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 <tokita.hiroshi@gmail.com>
This commit is contained in:
TOKITA Hiroshi 2024-09-20 19:54:02 +09:00 committed by Carles Cufí
parent 5c9c95b593
commit 275162fd52
5 changed files with 67 additions and 35 deletions

View File

@ -152,7 +152,6 @@ zephyr_udc0: &usbd {
&pwm {
pinctrl-0 = <&pwm_ch4b_default>;
pinctrl-names = "default";
divider-int-0 = <255>;
};
&vreg {

View File

@ -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
====

View File

@ -234,6 +234,8 @@ Drivers and Sensors
* PWM
* rpi_pico: The driver now configures the divide ratio adaptively.
* Regulators
* Reset

View File

@ -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) \

View File

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