Lines Matching +full:imx7ulp +full:- +full:pwm

1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2018-2019 NXP.
6 * - The TPM counter and period counter are shared between
9 * - Changes to polarity cannot be latched at the time of the
11 * - Changing period and duty cycle together isn't atomic,
24 #include <linux/pwm.h>
49 * together as a 2-bit field here.
57 #define PWM_IMX_TPM_MOD_MOD GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0)
96 rate = clk_get_rate(tpm->clk); in pwm_imx_tpm_round_state()
97 tmp = (u64)state->period * rate; in pwm_imx_tpm_round_state()
102 prescale = ilog2(clock_unit) + 1 - PWM_IMX_TPM_MOD_WIDTH; in pwm_imx_tpm_round_state()
105 return -ERANGE; in pwm_imx_tpm_round_state()
106 p->prescale = prescale; in pwm_imx_tpm_round_state()
109 p->mod = period_count; in pwm_imx_tpm_round_state()
114 real_state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); in pwm_imx_tpm_round_state()
117 * if eventually the PWM output is inactive, either in pwm_imx_tpm_round_state()
121 if (!state->enabled) in pwm_imx_tpm_round_state()
122 real_state->duty_cycle = 0; in pwm_imx_tpm_round_state()
124 real_state->duty_cycle = state->duty_cycle; in pwm_imx_tpm_round_state()
126 tmp = (u64)p->mod * real_state->duty_cycle; in pwm_imx_tpm_round_state()
127 p->val = DIV64_U64_ROUND_CLOSEST(tmp, real_state->period); in pwm_imx_tpm_round_state()
129 real_state->polarity = state->polarity; in pwm_imx_tpm_round_state()
130 real_state->enabled = state->enabled; in pwm_imx_tpm_round_state()
136 struct pwm_device *pwm, in pwm_imx_tpm_get_state() argument
144 state->period = tpm->real_period; in pwm_imx_tpm_get_state()
147 rate = clk_get_rate(tpm->clk); in pwm_imx_tpm_get_state()
148 val = readl(tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_get_state()
150 tmp = readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); in pwm_imx_tpm_get_state()
152 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); in pwm_imx_tpm_get_state()
155 val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); in pwm_imx_tpm_get_state()
157 state->polarity = PWM_POLARITY_INVERSED; in pwm_imx_tpm_get_state()
163 state->polarity = PWM_POLARITY_NORMAL; in pwm_imx_tpm_get_state()
166 state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false; in pwm_imx_tpm_get_state()
175 struct pwm_device *pwm) in pwm_imx_tpm_apply_hw() argument
184 if (state->period != tpm->real_period) { in pwm_imx_tpm_apply_hw()
191 if (tpm->user_count > 1) in pwm_imx_tpm_apply_hw()
192 return -EBUSY; in pwm_imx_tpm_apply_hw()
194 val = readl(tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
197 if (cmod && cur_prescale != p->prescale) in pwm_imx_tpm_apply_hw()
198 return -EBUSY; in pwm_imx_tpm_apply_hw()
202 val |= FIELD_PREP(PWM_IMX_TPM_SC_PS, p->prescale); in pwm_imx_tpm_apply_hw()
203 writel(val, tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
207 * if the PWM is disabled (CMOD[1:0] = 2b00), then MOD register in pwm_imx_tpm_apply_hw()
210 * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the period length in pwm_imx_tpm_apply_hw()
213 writel(p->mod, tpm->base + PWM_IMX_TPM_MOD); in pwm_imx_tpm_apply_hw()
214 tpm->real_period = state->period; in pwm_imx_tpm_apply_hw()
218 pwm_imx_tpm_get_state(chip, pwm, &c); in pwm_imx_tpm_apply_hw()
220 /* polarity is NOT allowed to be changed if PWM is active */ in pwm_imx_tpm_apply_hw()
221 if (c.enabled && c.polarity != state->polarity) in pwm_imx_tpm_apply_hw()
222 return -EBUSY; in pwm_imx_tpm_apply_hw()
224 if (state->duty_cycle != c.duty_cycle) { in pwm_imx_tpm_apply_hw()
227 * if the PWM is disabled (CMOD[1:0] = 2b00), then CnV register in pwm_imx_tpm_apply_hw()
230 * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the duty length in pwm_imx_tpm_apply_hw()
233 writel(p->val, tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); in pwm_imx_tpm_apply_hw()
239 timeout = jiffies + msecs_to_jiffies(tpm->real_period / in pwm_imx_tpm_apply_hw()
241 while (readl(tpm->base + PWM_IMX_TPM_MOD) != p->mod in pwm_imx_tpm_apply_hw()
242 || readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)) in pwm_imx_tpm_apply_hw()
243 != p->val) { in pwm_imx_tpm_apply_hw()
245 return -ETIME; in pwm_imx_tpm_apply_hw()
256 val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); in pwm_imx_tpm_apply_hw()
259 if (state->enabled) { in pwm_imx_tpm_apply_hw()
261 * set polarity (for edge-aligned PWM modes) in pwm_imx_tpm_apply_hw()
268 val |= (state->polarity == PWM_POLARITY_NORMAL) ? in pwm_imx_tpm_apply_hw()
272 writel(val, tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); in pwm_imx_tpm_apply_hw()
275 if (state->enabled != c.enabled) { in pwm_imx_tpm_apply_hw()
276 val = readl(tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
277 if (state->enabled) { in pwm_imx_tpm_apply_hw()
278 if (++tpm->enable_count == 1) in pwm_imx_tpm_apply_hw()
281 if (--tpm->enable_count == 0) in pwm_imx_tpm_apply_hw()
284 writel(val, tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
291 struct pwm_device *pwm, in pwm_imx_tpm_apply() argument
303 mutex_lock(&tpm->lock); in pwm_imx_tpm_apply()
304 ret = pwm_imx_tpm_apply_hw(chip, &param, &real_state, pwm); in pwm_imx_tpm_apply()
305 mutex_unlock(&tpm->lock); in pwm_imx_tpm_apply()
310 static int pwm_imx_tpm_request(struct pwm_chip *chip, struct pwm_device *pwm) in pwm_imx_tpm_request() argument
314 mutex_lock(&tpm->lock); in pwm_imx_tpm_request()
315 tpm->user_count++; in pwm_imx_tpm_request()
316 mutex_unlock(&tpm->lock); in pwm_imx_tpm_request()
321 static void pwm_imx_tpm_free(struct pwm_chip *chip, struct pwm_device *pwm) in pwm_imx_tpm_free() argument
325 mutex_lock(&tpm->lock); in pwm_imx_tpm_free()
326 tpm->user_count--; in pwm_imx_tpm_free()
327 mutex_unlock(&tpm->lock); in pwm_imx_tpm_free()
343 tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL); in pwm_imx_tpm_probe()
345 return -ENOMEM; in pwm_imx_tpm_probe()
349 tpm->base = devm_platform_ioremap_resource(pdev, 0); in pwm_imx_tpm_probe()
350 if (IS_ERR(tpm->base)) in pwm_imx_tpm_probe()
351 return PTR_ERR(tpm->base); in pwm_imx_tpm_probe()
353 tpm->clk = devm_clk_get_enabled(&pdev->dev, NULL); in pwm_imx_tpm_probe()
354 if (IS_ERR(tpm->clk)) in pwm_imx_tpm_probe()
355 return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk), in pwm_imx_tpm_probe()
356 "failed to get PWM clock\n"); in pwm_imx_tpm_probe()
358 tpm->chip.dev = &pdev->dev; in pwm_imx_tpm_probe()
359 tpm->chip.ops = &imx_tpm_pwm_ops; in pwm_imx_tpm_probe()
362 val = readl(tpm->base + PWM_IMX_TPM_PARAM); in pwm_imx_tpm_probe()
363 tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val); in pwm_imx_tpm_probe()
365 mutex_init(&tpm->lock); in pwm_imx_tpm_probe()
367 ret = devm_pwmchip_add(&pdev->dev, &tpm->chip); in pwm_imx_tpm_probe()
369 return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); in pwm_imx_tpm_probe()
378 if (tpm->enable_count > 0) in pwm_imx_tpm_suspend()
379 return -EBUSY; in pwm_imx_tpm_suspend()
386 tpm->real_period = 0; in pwm_imx_tpm_suspend()
388 clk_disable_unprepare(tpm->clk); in pwm_imx_tpm_suspend()
398 ret = clk_prepare_enable(tpm->clk); in pwm_imx_tpm_resume()
409 { .compatible = "fsl,imx7ulp-pwm", },
416 .name = "imx7ulp-tpm-pwm",
425 MODULE_DESCRIPTION("i.MX TPM PWM Driver");