Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pwm: bcm-kona: Implement .apply() callback

To eventually get rid of all legacy drivers convert this driver to the
modern world implementing .apply().

The conversion wasn't quite straight forward because .config() and
.enable() were special to effectively swap their usual order. This resulted
in calculating the required values twice in some cases when
pwm_apply_state() was called. This is optimized en passant, and the order
of the callbacks is preserved without special jumping through hoops.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>

authored by

Uwe Kleine-König and committed by
Thierry Reding
1c1283db 5f027d9b

+58 -32
+58 -32
drivers/pwm/pwm-bcm-kona.c
··· 109 109 } 110 110 111 111 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, 112 - int duty_ns, int period_ns) 112 + u64 duty_ns, u64 period_ns) 113 113 { 114 114 struct kona_pwmc *kp = to_kona_pwmc(chip); 115 - u64 val, div, rate; 115 + u64 div, rate; 116 116 unsigned long prescale = PRESCALE_MIN, pc, dc; 117 117 unsigned int value, chan = pwm->hwpwm; 118 118 ··· 132 132 while (1) { 133 133 div = 1000000000; 134 134 div *= 1 + prescale; 135 - val = rate * period_ns; 136 - pc = div64_u64(val, div); 137 - val = rate * duty_ns; 138 - dc = div64_u64(val, div); 135 + pc = mul_u64_u64_div_u64(rate, period_ns, div); 136 + dc = mul_u64_u64_div_u64(rate, duty_ns, div); 139 137 140 138 /* If duty_ns or period_ns are not achievable then return */ 141 139 if (pc < PERIOD_COUNT_MIN) ··· 148 150 return -EINVAL; 149 151 } 150 152 151 - /* 152 - * Don't apply settings if disabled. The period and duty cycle are 153 - * always calculated above to ensure the new values are 154 - * validated immediately instead of on enable. 155 - */ 156 - if (pwm_is_enabled(pwm)) { 157 - kona_pwmc_prepare_for_settings(kp, chan); 153 + kona_pwmc_prepare_for_settings(kp, chan); 158 154 159 - value = readl(kp->base + PRESCALE_OFFSET); 160 - value &= ~PRESCALE_MASK(chan); 161 - value |= prescale << PRESCALE_SHIFT(chan); 162 - writel(value, kp->base + PRESCALE_OFFSET); 155 + value = readl(kp->base + PRESCALE_OFFSET); 156 + value &= ~PRESCALE_MASK(chan); 157 + value |= prescale << PRESCALE_SHIFT(chan); 158 + writel(value, kp->base + PRESCALE_OFFSET); 163 159 164 - writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan)); 160 + writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan)); 165 161 166 - writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); 162 + writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); 167 163 168 - kona_pwmc_apply_settings(kp, chan); 169 - } 164 + kona_pwmc_apply_settings(kp, chan); 170 165 171 166 return 0; 172 167 } ··· 207 216 return ret; 208 217 } 209 218 210 - ret = kona_pwmc_config(chip, pwm, pwm_get_duty_cycle(pwm), 211 - pwm_get_period(pwm)); 212 - if (ret < 0) { 213 - clk_disable_unprepare(kp->clk); 214 - return ret; 215 - } 216 - 217 219 return 0; 218 220 } 219 221 ··· 232 248 clk_disable_unprepare(kp->clk); 233 249 } 234 250 251 + static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm, 252 + const struct pwm_state *state) 253 + { 254 + int err; 255 + struct kona_pwmc *kp = to_kona_pwmc(chip); 256 + bool enabled = pwm->state.enabled; 257 + 258 + if (state->polarity != pwm->state.polarity) { 259 + if (enabled) { 260 + kona_pwmc_disable(chip, pwm); 261 + enabled = false; 262 + } 263 + 264 + err = kona_pwmc_set_polarity(chip, pwm, state->polarity); 265 + if (err) 266 + return err; 267 + 268 + pwm->state.polarity = state->polarity; 269 + } 270 + 271 + if (!state->enabled) { 272 + if (enabled) 273 + kona_pwmc_disable(chip, pwm); 274 + return 0; 275 + } else if (!enabled) { 276 + /* 277 + * This is a bit special here, usually the PWM should only be 278 + * enabled when duty and period are setup. But before this 279 + * driver was converted to .apply it was done the other way 280 + * around and so this behaviour was kept even though this might 281 + * result in a glitch. This might be improvable by someone with 282 + * hardware and/or documentation. 283 + */ 284 + err = kona_pwmc_enable(chip, pwm); 285 + if (err) 286 + return err; 287 + } 288 + 289 + err = kona_pwmc_config(pwm->chip, pwm, state->duty_cycle, state->period); 290 + if (err && !pwm->state.enabled) 291 + clk_disable_unprepare(kp->clk); 292 + 293 + return err; 294 + } 295 + 235 296 static const struct pwm_ops kona_pwm_ops = { 236 - .config = kona_pwmc_config, 237 - .set_polarity = kona_pwmc_set_polarity, 238 - .enable = kona_pwmc_enable, 239 - .disable = kona_pwmc_disable, 297 + .apply = kona_pwmc_apply, 240 298 .owner = THIS_MODULE, 241 299 }; 242 300