From 275162fd52392b1561952b05c24226ea16cb938e Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Fri, 20 Sep 2024 19:54:02 +0900 Subject: [PATCH] drivers: pwm: rpi_pico: Configuring the divide ratio adaptively If the `divider-int-0` or variations of these for each channel properties are not specified, or if these is 0, the driver dynamically configures the division ratio by specified cycles. The driver will operate at the specified division ratio if a non-zero value is specified for `divider-int-0`. This is unchanged from previous behavior. Please specify ``divider-int-0`` explicitly to make the same behavior as before. In addition, the default device tree properties related to the division ratio have been removed. Signed-off-by: TOKITA Hiroshi --- .../raspberrypi/rpi_pico/rpi_pico-common.dtsi | 1 - doc/releases/migration-guide-4.0.rst | 13 ++++ doc/releases/release-notes-4.0.rst | 2 + drivers/pwm/pwm_rpi_pico.c | 59 ++++++++++++++----- dts/bindings/pwm/raspberrypi,pico-pwm.yaml | 27 +++------ 5 files changed, 67 insertions(+), 35 deletions(-) diff --git a/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi b/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi index 36058ef6483..2b40cf3540b 100644 --- a/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi +++ b/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi @@ -152,7 +152,6 @@ zephyr_udc0: &usbd { &pwm { pinctrl-0 = <&pwm_ch4b_default>; pinctrl-names = "default"; - divider-int-0 = <255>; }; &vreg { diff --git a/doc/releases/migration-guide-4.0.rst b/doc/releases/migration-guide-4.0.rst index a401dacbfc6..0c3c1cb9835 100644 --- a/doc/releases/migration-guide-4.0.rst +++ b/doc/releases/migration-guide-4.0.rst @@ -213,6 +213,19 @@ Interrupt Controller LED Strip ========= +PWM +=== + +* The Raspberry Pi Pico PWM driver now configures frequency adaptively. + This has resulted in a change in how device tree parameters are handled. + If the :dtcompatible:`raspberry,pico-pwm`'s ``divider-int-0`` or variations + for each channel are specified, or if these are set to 0, + the driver dynamically configures the division ratio by specified cycles. + The driver will operate at the specified division ratio if a non-zero value is + specified for ``divider-int-0``. + This is unchanged from previous behavior. + Please specify ``divider-int-0`` explicitly to make the same behavior as before. + SDHC ==== diff --git a/doc/releases/release-notes-4.0.rst b/doc/releases/release-notes-4.0.rst index 75b44df3fd1..38953b1b30e 100644 --- a/doc/releases/release-notes-4.0.rst +++ b/doc/releases/release-notes-4.0.rst @@ -234,6 +234,8 @@ Drivers and Sensors * PWM + * rpi_pico: The driver now configures the divide ratio adaptively. + * Regulators * Reset diff --git a/drivers/pwm/pwm_rpi_pico.c b/drivers/pwm/pwm_rpi_pico.c index 2050ca27a2e..d277cddaf15 100644 --- a/drivers/pwm/pwm_rpi_pico.c +++ b/drivers/pwm/pwm_rpi_pico.c @@ -73,10 +73,15 @@ static int pwm_rpi_get_cycles_per_sec(const struct device *dev, uint32_t ch, uin return -EINVAL; } - /* No need to check for divide by 0 since the minimum value of - * pwm_rpi_get_clkdiv is 1 - */ - *cycles = (uint64_t)((float)pclk / pwm_rpi_get_clkdiv(dev, slice)); + if (cfg->slice_configs[slice].integral == 0) { + *cycles = pclk; + } else { + /* No need to check for divide by 0 since the minimum value of + * pwm_rpi_get_clkdiv is 1 + */ + *cycles = (uint64_t)((float)pclk / pwm_rpi_get_clkdiv(dev, slice)); + } + return 0; } @@ -104,24 +109,46 @@ static void pwm_rpi_set_channel_polarity(const struct device *dev, int slice, static int pwm_rpi_set_cycles(const struct device *dev, uint32_t ch, uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags) { + const struct pwm_rpi_config *cfg = dev->config; + int slice = pwm_rpi_channel_to_slice(ch); + + /* this is the channel within a pwm slice */ + int pico_channel = pwm_rpi_channel_to_pico_channel(ch); + int div_int; + int div_frac; + if (ch >= PWM_RPI_NUM_CHANNELS) { return -EINVAL; } + div_int = cfg->slice_configs[slice].integral; + div_frac = cfg->slice_configs[slice].frac; + + if (div_int == 0) { + div_int = 1; + div_frac = 0; + while ((period_cycles / div_int - 1) > PWM_RPI_PICO_COUNTER_TOP_MAX) { + div_int *= 2; + } + + if (div_int > (UINT8_MAX + 1)) { + return -EINVAL; + } + + period_cycles /= div_int; + pulse_cycles /= div_int; + } + if (period_cycles - 1 > PWM_RPI_PICO_COUNTER_TOP_MAX || pulse_cycles > PWM_RPI_PICO_COUNTER_TOP_MAX) { return -EINVAL; } - int slice = pwm_rpi_channel_to_slice(ch); - - /* this is the channel within a pwm slice */ - int pico_channel = pwm_rpi_channel_to_pico_channel(ch); - pwm_rpi_set_channel_polarity(dev, slice, pico_channel, (flags & PWM_POLARITY_MASK) == PWM_POLARITY_INVERTED); pwm_set_wrap(slice, period_cycles - 1); pwm_set_chan_level(slice, pico_channel, pulse_cycles); + pwm_set_clkdiv_int_frac(slice, div_int, div_frac); return 0; }; @@ -160,9 +187,13 @@ static int pwm_rpi_init(const struct device *dev) pwm_init(slice_idx, &slice_cfg, false); - pwm_set_clkdiv_int_frac(slice_idx, - cfg->slice_configs[slice_idx].integral, - cfg->slice_configs[slice_idx].frac); + if (cfg->slice_configs[slice_idx].integral == 0) { + pwm_set_clkdiv_int_frac(slice_idx, 1, 0); + } else { + pwm_set_clkdiv_int_frac(slice_idx, + cfg->slice_configs[slice_idx].integral, + cfg->slice_configs[slice_idx].frac); + } pwm_set_enabled(slice_idx, true); } @@ -171,8 +202,8 @@ static int pwm_rpi_init(const struct device *dev) #define PWM_INST_RPI_SLICE_DIVIDER(idx, n) \ { \ - .integral = DT_INST_PROP(idx, UTIL_CAT(divider_int_, n)), \ - .frac = DT_INST_PROP(idx, UTIL_CAT(divider_frac_, n)), \ + .integral = DT_INST_PROP_OR(idx, UTIL_CAT(divider_int_, n), 0), \ + .frac = DT_INST_PROP_OR(idx, UTIL_CAT(divider_frac_, n), 0), \ } #define PWM_RPI_INIT(idx) \ diff --git a/dts/bindings/pwm/raspberrypi,pico-pwm.yaml b/dts/bindings/pwm/raspberrypi,pico-pwm.yaml index b8ac90eacc5..6e29eb132ee 100644 --- a/dts/bindings/pwm/raspberrypi,pico-pwm.yaml +++ b/dts/bindings/pwm/raspberrypi,pico-pwm.yaml @@ -16,88 +16,75 @@ properties: divider-int-0: type: int - default: 1 description: | The integral part of the divider for pwm slice 0. - This number should be in the range 1 - 255. Defaults - to 1, the same as the RESET value. + If a value between 1 and 255 is set, it will be set to the register + as the integer part of the divider. + If the value is set to 0 or this property is not defined when setting + the number of cycles to PWM, a division ratio appropriate to that value is set. divider-frac-0: type: int - default: 0 description: | The fractional part of the divider for pwm slice 0. - This number should be in the range 0 - 15. Defaults - to 0, the same as the RESET value. + This number should be in the range 0 - 15. + When the "divider-int-0" is set to 0 or is not defined, this property will be + ignored. divider-int-1: type: int - default: 1 description: See divider-int-0 for help divider-frac-1: type: int - default: 0 description: See divider-frac-0 for help divider-int-2: type: int - default: 1 description: See divider-int-0 for help divider-frac-2: type: int - default: 0 description: See divider-frac-0 for help divider-int-3: type: int - default: 1 description: See divider-int-0 for help divider-frac-3: type: int - default: 0 description: See divider-frac-0 for help divider-int-4: type: int - default: 1 description: See divider-int-0 for help divider-frac-4: type: int - default: 0 description: See divider-frac-0 for help divider-int-5: type: int - default: 1 description: See divider-int-0 for help divider-frac-5: type: int - default: 0 description: See divider-frac-0 for help divider-int-6: type: int - default: 1 description: See divider-int-0 for help divider-frac-6: type: int - default: 0 description: See divider-frac-0 for help divider-int-7: type: int - default: 1 description: See divider-int-0 for help divider-frac-7: type: int - default: 0 description: See divider-frac-0 for help "#pwm-cells":