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":