Lines Matching +full:imx7ulp +full:- +full:tpm

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,
50 * together as a 2-bit field here.
58 #define PWM_IMX_TPM_MOD_MOD GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0)
92 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); in pwm_imx_tpm_round_state() local
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()
110 return -EINVAL; in pwm_imx_tpm_round_state()
111 p->mod = period_count - 1; in pwm_imx_tpm_round_state()
116 real_state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); in pwm_imx_tpm_round_state()
123 if (!state->enabled) in pwm_imx_tpm_round_state()
124 real_state->duty_cycle = 0; in pwm_imx_tpm_round_state()
126 real_state->duty_cycle = state->duty_cycle; in pwm_imx_tpm_round_state()
128 tmp = (u64)p->mod * real_state->duty_cycle; in pwm_imx_tpm_round_state()
129 p->val = DIV64_U64_ROUND_CLOSEST(tmp, real_state->period); in pwm_imx_tpm_round_state()
131 real_state->polarity = state->polarity; in pwm_imx_tpm_round_state()
132 real_state->enabled = state->enabled; in pwm_imx_tpm_round_state()
141 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); in pwm_imx_tpm_get_state() local
146 state->period = tpm->real_period; in pwm_imx_tpm_get_state()
149 rate = clk_get_rate(tpm->clk); in pwm_imx_tpm_get_state()
150 val = readl(tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_get_state()
152 tmp = readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); in pwm_imx_tpm_get_state()
154 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); in pwm_imx_tpm_get_state()
157 val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); in pwm_imx_tpm_get_state()
159 state->polarity = PWM_POLARITY_INVERSED; in pwm_imx_tpm_get_state()
165 state->polarity = PWM_POLARITY_NORMAL; in pwm_imx_tpm_get_state()
168 state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false; in pwm_imx_tpm_get_state()
179 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); in pwm_imx_tpm_apply_hw() local
186 if (state->period != tpm->real_period) { in pwm_imx_tpm_apply_hw()
188 * TPM counter is shared by multiple channels, so in pwm_imx_tpm_apply_hw()
193 if (tpm->user_count > 1) in pwm_imx_tpm_apply_hw()
194 return -EBUSY; in pwm_imx_tpm_apply_hw()
196 val = readl(tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
199 if (cmod && cur_prescale != p->prescale) in pwm_imx_tpm_apply_hw()
200 return -EBUSY; in pwm_imx_tpm_apply_hw()
202 /* set TPM counter prescale */ in pwm_imx_tpm_apply_hw()
204 val |= FIELD_PREP(PWM_IMX_TPM_SC_PS, p->prescale); in pwm_imx_tpm_apply_hw()
205 writel(val, tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
215 writel(p->mod, tpm->base + PWM_IMX_TPM_MOD); in pwm_imx_tpm_apply_hw()
216 tpm->real_period = state->period; in pwm_imx_tpm_apply_hw()
223 if (c.enabled && c.polarity != state->polarity) in pwm_imx_tpm_apply_hw()
224 return -EBUSY; in pwm_imx_tpm_apply_hw()
226 if (state->duty_cycle != c.duty_cycle) { in pwm_imx_tpm_apply_hw()
235 writel(p->val, tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)); in pwm_imx_tpm_apply_hw()
241 timeout = jiffies + msecs_to_jiffies(tpm->real_period / in pwm_imx_tpm_apply_hw()
243 while (readl(tpm->base + PWM_IMX_TPM_MOD) != p->mod in pwm_imx_tpm_apply_hw()
244 || readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm)) in pwm_imx_tpm_apply_hw()
245 != p->val) { in pwm_imx_tpm_apply_hw()
247 return -ETIME; in pwm_imx_tpm_apply_hw()
258 val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); in pwm_imx_tpm_apply_hw()
261 if (state->enabled) { in pwm_imx_tpm_apply_hw()
263 * set polarity (for edge-aligned PWM modes) in pwm_imx_tpm_apply_hw()
270 val |= (state->polarity == PWM_POLARITY_NORMAL) ? in pwm_imx_tpm_apply_hw()
274 writel(val, tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm)); in pwm_imx_tpm_apply_hw()
277 if (state->enabled != c.enabled) { in pwm_imx_tpm_apply_hw()
278 val = readl(tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
279 if (state->enabled) { in pwm_imx_tpm_apply_hw()
280 if (++tpm->enable_count == 1) in pwm_imx_tpm_apply_hw()
283 if (--tpm->enable_count == 0) in pwm_imx_tpm_apply_hw()
286 writel(val, tpm->base + PWM_IMX_TPM_SC); in pwm_imx_tpm_apply_hw()
296 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); in pwm_imx_tpm_apply() local
305 mutex_lock(&tpm->lock); in pwm_imx_tpm_apply()
307 mutex_unlock(&tpm->lock); in pwm_imx_tpm_apply()
314 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); in pwm_imx_tpm_request() local
316 mutex_lock(&tpm->lock); in pwm_imx_tpm_request()
317 tpm->user_count++; in pwm_imx_tpm_request()
318 mutex_unlock(&tpm->lock); in pwm_imx_tpm_request()
325 struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); in pwm_imx_tpm_free() local
327 mutex_lock(&tpm->lock); in pwm_imx_tpm_free()
328 tpm->user_count--; in pwm_imx_tpm_free()
329 mutex_unlock(&tpm->lock); in pwm_imx_tpm_free()
342 struct imx_tpm_pwm_chip *tpm; in pwm_imx_tpm_probe() local
353 clk = devm_clk_get_enabled(&pdev->dev, NULL); in pwm_imx_tpm_probe()
355 return dev_err_probe(&pdev->dev, PTR_ERR(clk), in pwm_imx_tpm_probe()
362 chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*tpm)); in pwm_imx_tpm_probe()
365 tpm = to_imx_tpm_pwm_chip(chip); in pwm_imx_tpm_probe()
367 platform_set_drvdata(pdev, tpm); in pwm_imx_tpm_probe()
369 tpm->base = base; in pwm_imx_tpm_probe()
370 tpm->clk = clk; in pwm_imx_tpm_probe()
372 chip->ops = &imx_tpm_pwm_ops; in pwm_imx_tpm_probe()
374 mutex_init(&tpm->lock); in pwm_imx_tpm_probe()
376 ret = devm_pwmchip_add(&pdev->dev, chip); in pwm_imx_tpm_probe()
378 return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); in pwm_imx_tpm_probe()
385 struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev); in pwm_imx_tpm_suspend() local
388 if (tpm->enable_count > 0) in pwm_imx_tpm_suspend()
389 return -EBUSY; in pwm_imx_tpm_suspend()
396 tpm->real_period = 0; in pwm_imx_tpm_suspend()
398 clk_disable_unprepare(tpm->clk); in pwm_imx_tpm_suspend()
402 clk_prepare_enable(tpm->clk); in pwm_imx_tpm_suspend()
409 struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev); in pwm_imx_tpm_resume() local
416 ret = clk_prepare_enable(tpm->clk); in pwm_imx_tpm_resume()
429 { .compatible = "fsl,imx7ulp-pwm", },
436 .name = "imx7ulp-tpm-pwm",
445 MODULE_DESCRIPTION("i.MX TPM PWM Driver");