Lines Matching +full:imx27 +full:- +full:pwm
1 // SPDX-License-Identifier: GPL-2.0
3 * simple driver for PWM (Pulse Width Modulator) controller
5 * Derived from pxa PWM driver by eric miao <[email protected]>
8 * - When disabled the output is driven to 0 independent of the configured
22 #include <linux/pwm.h>
25 #define MX3_PWMCR 0x00 /* PWM Control Register */
26 #define MX3_PWMSR 0x04 /* PWM Status Register */
27 #define MX3_PWMSAR 0x0C /* PWM Sample Register */
28 #define MX3_PWMPR 0x10 /* PWM Period Register */
29 #define MX3_PWMCNR 0x14 /* PWM Counter Register */
74 #define MX3_PWMCR_PRESCALER_SET(x) FIELD_PREP(MX3_PWMCR_PRESCALER, (x) - 1)
105 struct pwm_device *pwm, struct pwm_state *state) in pwm_imx27_get_state() argument
112 ret = clk_bulk_prepare_enable(imx->clks_cnt, imx->clks); in pwm_imx27_get_state()
116 val = readl(imx->mmio_base + MX3_PWMCR); in pwm_imx27_get_state()
119 state->enabled = true; in pwm_imx27_get_state()
121 state->enabled = false; in pwm_imx27_get_state()
125 state->polarity = PWM_POLARITY_NORMAL; in pwm_imx27_get_state()
128 state->polarity = PWM_POLARITY_INVERSED; in pwm_imx27_get_state()
135 pwm_clk = clk_get_rate(imx->clks[PWM_IMX27_PER].clk); in pwm_imx27_get_state()
136 val = readl(imx->mmio_base + MX3_PWMPR); in pwm_imx27_get_state()
141 state->period = DIV_ROUND_UP_ULL(tmp, pwm_clk); in pwm_imx27_get_state()
144 * PWMSAR can be read only if PWM is enabled. If the PWM is disabled, in pwm_imx27_get_state()
147 if (state->enabled) in pwm_imx27_get_state()
148 val = readl(imx->mmio_base + MX3_PWMSAR); in pwm_imx27_get_state()
150 val = imx->duty_cycle; in pwm_imx27_get_state()
153 state->duty_cycle = DIV_ROUND_UP_ULL(tmp, pwm_clk); in pwm_imx27_get_state()
155 clk_bulk_disable_unprepare(imx->clks_cnt, imx->clks); in pwm_imx27_get_state()
167 writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); in pwm_imx27_sw_reset()
170 cr = readl(imx->mmio_base + MX3_PWMCR); in pwm_imx27_sw_reset()
179 struct pwm_device *pwm) in pwm_imx27_wait_fifo_slot() argument
187 sr = readl(imx->mmio_base + MX3_PWMSR); in pwm_imx27_wait_fifo_slot()
190 period_ms = DIV_ROUND_UP_ULL(pwm->state.period, in pwm_imx27_wait_fifo_slot()
194 sr = readl(imx->mmio_base + MX3_PWMSR); in pwm_imx27_wait_fifo_slot()
200 static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, in pwm_imx27_apply() argument
212 clkrate = clk_get_rate(imx->clks[PWM_IMX27_PER].clk); in pwm_imx27_apply()
213 c = clkrate * state->period; in pwm_imx27_apply()
221 c = clkrate * state->duty_cycle; in pwm_imx27_apply()
227 * according to imx pwm RM, the real period value should be PERIOD in pwm_imx27_apply()
231 period_cycles -= 2; in pwm_imx27_apply()
236 * Wait for a free FIFO slot if the PWM is already enabled, and flush in pwm_imx27_apply()
237 * the FIFO if the PWM was disabled and is about to be enabled. in pwm_imx27_apply()
239 if (pwm->state.enabled) { in pwm_imx27_apply()
240 pwm_imx27_wait_fifo_slot(chip, pwm); in pwm_imx27_apply()
242 ret = clk_bulk_prepare_enable(imx->clks_cnt, imx->clks); in pwm_imx27_apply()
249 val = readl(imx->mmio_base + MX3_PWMPR); in pwm_imx27_apply()
251 cr = readl(imx->mmio_base + MX3_PWMCR); in pwm_imx27_apply()
258 * PWM: PWM output may not function correctly if the FIFO is empty when in pwm_imx27_apply()
262 * When the PWM FIFO is empty, a new value programmed to the PWM Sample in pwm_imx27_apply()
267 * less than the previous value, and the PWM counter register in pwm_imx27_apply()
287 * |<-- old SAR -->| |<-- new SAR -->| in pwm_imx27_apply()
302 * in PWM will be out of data and take wrong action. in pwm_imx27_apply()
308 * the SAR register to increase the fastest PWM frequency supported. in pwm_imx27_apply()
310 * When the PWM period is longer than 2us(or <500kHz), this workaround in pwm_imx27_apply()
311 * can solve this problem. No software workaround is available if PWM in pwm_imx27_apply()
319 val = FIELD_GET(MX3_PWMSR_FIFOAV, readl_relaxed(imx->mmio_base + MX3_PWMSR)); in pwm_imx27_apply()
321 if (duty_cycles < imx->duty_cycle && (cr & MX3_PWMCR_EN)) { in pwm_imx27_apply()
325 writel_relaxed(imx->duty_cycle, imx->mmio_base + MX3_PWMSAR); in pwm_imx27_apply()
326 writel_relaxed(imx->duty_cycle, imx->mmio_base + MX3_PWMSAR); in pwm_imx27_apply()
328 val = readl_relaxed(imx->mmio_base + MX3_PWMCNR); in pwm_imx27_apply()
333 if ((val + c >= duty_cycles && val < imx->duty_cycle) || in pwm_imx27_apply()
335 writel_relaxed(imx->duty_cycle, imx->mmio_base + MX3_PWMSAR); in pwm_imx27_apply()
338 writel_relaxed(duty_cycles, imx->mmio_base + MX3_PWMSAR); in pwm_imx27_apply()
341 writel(period_cycles, imx->mmio_base + MX3_PWMPR); in pwm_imx27_apply()
345 * MX3_PWMSAR register can't be read (i.e. when the PWM is disabled). in pwm_imx27_apply()
347 imx->duty_cycle = duty_cycles; in pwm_imx27_apply()
354 if (state->polarity == PWM_POLARITY_INVERSED) in pwm_imx27_apply()
358 if (state->enabled) in pwm_imx27_apply()
361 writel(cr, imx->mmio_base + MX3_PWMCR); in pwm_imx27_apply()
363 if (!state->enabled) in pwm_imx27_apply()
364 clk_bulk_disable_unprepare(imx->clks_cnt, imx->clks); in pwm_imx27_apply()
375 { .compatible = "fsl,imx27-pwm", },
388 chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*imx)); in pwm_imx27_probe()
393 imx->clks_cnt = ARRAY_SIZE(pwm_imx27_clks); in pwm_imx27_probe()
394 for (i = 0; i < imx->clks_cnt; ++i) in pwm_imx27_probe()
395 imx->clks[i].id = pwm_imx27_clks[i]; in pwm_imx27_probe()
397 ret = devm_clk_bulk_get(&pdev->dev, imx->clks_cnt, imx->clks); in pwm_imx27_probe()
400 return dev_err_probe(&pdev->dev, ret, in pwm_imx27_probe()
403 chip->ops = &pwm_imx27_ops; in pwm_imx27_probe()
405 imx->mmio_base = devm_platform_ioremap_resource(pdev, 0); in pwm_imx27_probe()
406 if (IS_ERR(imx->mmio_base)) in pwm_imx27_probe()
407 return PTR_ERR(imx->mmio_base); in pwm_imx27_probe()
409 ret = clk_bulk_prepare_enable(imx->clks_cnt, imx->clks); in pwm_imx27_probe()
413 /* keep clks on if pwm is running */ in pwm_imx27_probe()
414 pwmcr = readl(imx->mmio_base + MX3_PWMCR); in pwm_imx27_probe()
416 clk_bulk_disable_unprepare(imx->clks_cnt, imx->clks); in pwm_imx27_probe()
418 return devm_pwmchip_add(&pdev->dev, chip); in pwm_imx27_probe()
423 .name = "pwm-imx27",