Lines Matching +full:lpc1850 +full:- +full:sct +full:- +full:pwm

1 // SPDX-License-Identifier: GPL-2.0-only
3 * NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver
9 * NXP LPC18xx provides a State Configurable Timer (SCT) which can be configured
12 * SCT supports 16 outputs, 16 events and 16 registers. Each event will be
13 * triggered when its related register matches the SCT counter value, and it
18 * global to all the channels, thus PWM driver will refuse setting different
28 #include <linux/pwm.h>
30 /* LPC18xx SCT registers */
73 /* LPC18xx SCT unified counter */
76 /* LPC18xx SCT events */
82 /* SCT conflict resolution */
115 writel(val, lpc18xx_pwm->base + reg); in lpc18xx_pwm_writel()
121 return readl(lpc18xx_pwm->base + reg); in lpc18xx_pwm_readl()
125 struct pwm_device *pwm, in lpc18xx_pwm_set_conflict_res() argument
132 * when duty_ns == period_ns. LPC18xx SCT allows to set a conflict in lpc18xx_pwm_set_conflict_res()
136 val &= ~LPC18XX_PWM_RES_MASK(pwm->hwpwm); in lpc18xx_pwm_set_conflict_res()
137 val |= LPC18XX_PWM_RES(pwm->hwpwm, action); in lpc18xx_pwm_set_conflict_res()
149 * As period_ns >= min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, lpc18xx_pwm->clk_rate); in lpc18xx_pwm_config_period()
152 val = mul_u64_u64_div_u64(period_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC); in lpc18xx_pwm_config_period()
155 LPC18XX_PWM_MATCH(lpc18xx_pwm->period_event), in lpc18xx_pwm_config_period()
156 val - 1); in lpc18xx_pwm_config_period()
159 LPC18XX_PWM_MATCHREL(lpc18xx_pwm->period_event), in lpc18xx_pwm_config_period()
160 val - 1); in lpc18xx_pwm_config_period()
164 struct pwm_device *pwm, u64 duty_ns) in lpc18xx_pwm_config_duty() argument
167 struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; in lpc18xx_pwm_config_duty()
174 val = mul_u64_u64_div_u64(duty_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC); in lpc18xx_pwm_config_duty()
177 LPC18XX_PWM_MATCH(lpc18xx_data->duty_event), in lpc18xx_pwm_config_duty()
181 LPC18XX_PWM_MATCHREL(lpc18xx_data->duty_event), in lpc18xx_pwm_config_duty()
185 static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, in lpc18xx_pwm_config() argument
191 if (period_ns < lpc18xx_pwm->min_period_ns || in lpc18xx_pwm_config()
192 period_ns > lpc18xx_pwm->max_period_ns) { in lpc18xx_pwm_config()
194 return -ERANGE; in lpc18xx_pwm_config()
197 requested_events = bitmap_weight(&lpc18xx_pwm->event_map, in lpc18xx_pwm_config()
201 * The PWM supports only a single period for all PWM channels. in lpc18xx_pwm_config()
205 if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns && in lpc18xx_pwm_config()
206 lpc18xx_pwm->period_ns) { in lpc18xx_pwm_config()
207 dev_err(pwmchip_parent(chip), "conflicting period requested for PWM %u\n", in lpc18xx_pwm_config()
208 pwm->hwpwm); in lpc18xx_pwm_config()
209 return -EBUSY; in lpc18xx_pwm_config()
212 if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) || in lpc18xx_pwm_config()
213 !lpc18xx_pwm->period_ns) { in lpc18xx_pwm_config()
214 lpc18xx_pwm->period_ns = period_ns; in lpc18xx_pwm_config()
218 lpc18xx_pwm_config_duty(chip, pwm, duty_ns); in lpc18xx_pwm_config()
223 static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity pola… in lpc18xx_pwm_enable() argument
226 struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; in lpc18xx_pwm_enable()
231 LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), in lpc18xx_pwm_enable()
232 LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_data->duty_event) | in lpc18xx_pwm_enable()
236 LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event), in lpc18xx_pwm_enable()
240 set_event = lpc18xx_pwm->period_event; in lpc18xx_pwm_enable()
241 clear_event = lpc18xx_data->duty_event; in lpc18xx_pwm_enable()
244 set_event = lpc18xx_data->duty_event; in lpc18xx_pwm_enable()
245 clear_event = lpc18xx_pwm->period_event; in lpc18xx_pwm_enable()
249 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), in lpc18xx_pwm_enable()
251 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), in lpc18xx_pwm_enable()
253 lpc18xx_pwm_set_conflict_res(lpc18xx_pwm, pwm, res_action); in lpc18xx_pwm_enable()
258 static void lpc18xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) in lpc18xx_pwm_disable() argument
261 struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; in lpc18xx_pwm_disable()
264 LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), 0); in lpc18xx_pwm_disable()
265 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), 0); in lpc18xx_pwm_disable()
266 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), 0); in lpc18xx_pwm_disable()
269 static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) in lpc18xx_pwm_request() argument
272 struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; in lpc18xx_pwm_request()
275 event = find_first_zero_bit(&lpc18xx_pwm->event_map, in lpc18xx_pwm_request()
281 return -EBUSY; in lpc18xx_pwm_request()
284 set_bit(event, &lpc18xx_pwm->event_map); in lpc18xx_pwm_request()
285 lpc18xx_data->duty_event = event; in lpc18xx_pwm_request()
290 static void lpc18xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) in lpc18xx_pwm_free() argument
293 struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; in lpc18xx_pwm_free()
295 clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map); in lpc18xx_pwm_free()
298 static int lpc18xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, in lpc18xx_pwm_apply() argument
302 bool enabled = pwm->state.enabled; in lpc18xx_pwm_apply()
304 if (state->polarity != pwm->state.polarity && pwm->state.enabled) { in lpc18xx_pwm_apply()
305 lpc18xx_pwm_disable(chip, pwm); in lpc18xx_pwm_apply()
309 if (!state->enabled) { in lpc18xx_pwm_apply()
311 lpc18xx_pwm_disable(chip, pwm); in lpc18xx_pwm_apply()
316 err = lpc18xx_pwm_config(chip, pwm, state->duty_cycle, state->period); in lpc18xx_pwm_apply()
321 err = lpc18xx_pwm_enable(chip, pwm, state->polarity); in lpc18xx_pwm_apply()
332 { .compatible = "nxp,lpc1850-sct-pwm" },
344 chip = devm_pwmchip_alloc(&pdev->dev, LPC18XX_NUM_PWMS, sizeof(*lpc18xx_pwm)); in lpc18xx_pwm_probe()
349 lpc18xx_pwm->base = devm_platform_ioremap_resource(pdev, 0); in lpc18xx_pwm_probe()
350 if (IS_ERR(lpc18xx_pwm->base)) in lpc18xx_pwm_probe()
351 return PTR_ERR(lpc18xx_pwm->base); in lpc18xx_pwm_probe()
353 lpc18xx_pwm->pwm_clk = devm_clk_get_enabled(&pdev->dev, "pwm"); in lpc18xx_pwm_probe()
354 if (IS_ERR(lpc18xx_pwm->pwm_clk)) in lpc18xx_pwm_probe()
355 return dev_err_probe(&pdev->dev, PTR_ERR(lpc18xx_pwm->pwm_clk), in lpc18xx_pwm_probe()
356 "failed to get pwm clock\n"); in lpc18xx_pwm_probe()
358 lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk); in lpc18xx_pwm_probe()
359 if (!lpc18xx_pwm->clk_rate) in lpc18xx_pwm_probe()
360 return dev_err_probe(&pdev->dev, in lpc18xx_pwm_probe()
361 -EINVAL, "pwm clock has no frequency\n"); in lpc18xx_pwm_probe()
366 if (lpc18xx_pwm->clk_rate > NSEC_PER_SEC) in lpc18xx_pwm_probe()
367 return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock to fast\n"); in lpc18xx_pwm_probe()
369 lpc18xx_pwm->max_period_ns = in lpc18xx_pwm_probe()
370 mul_u64_u64_div_u64(NSEC_PER_SEC, LPC18XX_PWM_TIMER_MAX, lpc18xx_pwm->clk_rate); in lpc18xx_pwm_probe()
372 lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, in lpc18xx_pwm_probe()
373 lpc18xx_pwm->clk_rate); in lpc18xx_pwm_probe()
375 chip->ops = &lpc18xx_pwm_ops; in lpc18xx_pwm_probe()
377 /* SCT counter must be in unify (32 bit) mode */ in lpc18xx_pwm_probe()
385 set_bit(LPC18XX_PWM_EVENT_PERIOD, &lpc18xx_pwm->event_map); in lpc18xx_pwm_probe()
386 lpc18xx_pwm->period_event = LPC18XX_PWM_EVENT_PERIOD; in lpc18xx_pwm_probe()
389 LPC18XX_PWM_EVSTATEMSK(lpc18xx_pwm->period_event), in lpc18xx_pwm_probe()
392 val = LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_pwm->period_event) | in lpc18xx_pwm_probe()
395 LPC18XX_PWM_EVCTRL(lpc18xx_pwm->period_event), val); in lpc18xx_pwm_probe()
398 BIT(lpc18xx_pwm->period_event)); in lpc18xx_pwm_probe()
409 return dev_err_probe(&pdev->dev, ret, "pwmchip_add failed\n"); in lpc18xx_pwm_probe()
431 .name = "lpc18xx-sct-pwm",
440 MODULE_DESCRIPTION("NXP LPC18xx PWM driver");