162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * simple driver for PWM (Pulse Width Modulator) controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Limitations:
862306a36Sopenharmony_ci * - When disabled the output is driven to 0 independent of the configured
962306a36Sopenharmony_ci *   polarity.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/bitfield.h>
1362306a36Sopenharmony_ci#include <linux/bitops.h>
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/io.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/of.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/pwm.h>
2362306a36Sopenharmony_ci#include <linux/slab.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define MX3_PWMCR			0x00    /* PWM Control Register */
2662306a36Sopenharmony_ci#define MX3_PWMSR			0x04    /* PWM Status Register */
2762306a36Sopenharmony_ci#define MX3_PWMSAR			0x0C    /* PWM Sample Register */
2862306a36Sopenharmony_ci#define MX3_PWMPR			0x10    /* PWM Period Register */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define MX3_PWMCR_FWM			GENMASK(27, 26)
3162306a36Sopenharmony_ci#define MX3_PWMCR_STOPEN		BIT(25)
3262306a36Sopenharmony_ci#define MX3_PWMCR_DOZEN			BIT(24)
3362306a36Sopenharmony_ci#define MX3_PWMCR_WAITEN		BIT(23)
3462306a36Sopenharmony_ci#define MX3_PWMCR_DBGEN			BIT(22)
3562306a36Sopenharmony_ci#define MX3_PWMCR_BCTR			BIT(21)
3662306a36Sopenharmony_ci#define MX3_PWMCR_HCTR			BIT(20)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define MX3_PWMCR_POUTC			GENMASK(19, 18)
3962306a36Sopenharmony_ci#define MX3_PWMCR_POUTC_NORMAL		0
4062306a36Sopenharmony_ci#define MX3_PWMCR_POUTC_INVERTED	1
4162306a36Sopenharmony_ci#define MX3_PWMCR_POUTC_OFF		2
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define MX3_PWMCR_CLKSRC		GENMASK(17, 16)
4462306a36Sopenharmony_ci#define MX3_PWMCR_CLKSRC_OFF		0
4562306a36Sopenharmony_ci#define MX3_PWMCR_CLKSRC_IPG		1
4662306a36Sopenharmony_ci#define MX3_PWMCR_CLKSRC_IPG_HIGH	2
4762306a36Sopenharmony_ci#define MX3_PWMCR_CLKSRC_IPG_32K	3
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define MX3_PWMCR_PRESCALER		GENMASK(15, 4)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define MX3_PWMCR_SWR			BIT(3)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define MX3_PWMCR_REPEAT		GENMASK(2, 1)
5462306a36Sopenharmony_ci#define MX3_PWMCR_REPEAT_1X		0
5562306a36Sopenharmony_ci#define MX3_PWMCR_REPEAT_2X		1
5662306a36Sopenharmony_ci#define MX3_PWMCR_REPEAT_4X		2
5762306a36Sopenharmony_ci#define MX3_PWMCR_REPEAT_8X		3
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define MX3_PWMCR_EN			BIT(0)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define MX3_PWMSR_FWE			BIT(6)
6262306a36Sopenharmony_ci#define MX3_PWMSR_CMP			BIT(5)
6362306a36Sopenharmony_ci#define MX3_PWMSR_ROV			BIT(4)
6462306a36Sopenharmony_ci#define MX3_PWMSR_FE			BIT(3)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define MX3_PWMSR_FIFOAV		GENMASK(2, 0)
6762306a36Sopenharmony_ci#define MX3_PWMSR_FIFOAV_EMPTY		0
6862306a36Sopenharmony_ci#define MX3_PWMSR_FIFOAV_1WORD		1
6962306a36Sopenharmony_ci#define MX3_PWMSR_FIFOAV_2WORDS		2
7062306a36Sopenharmony_ci#define MX3_PWMSR_FIFOAV_3WORDS		3
7162306a36Sopenharmony_ci#define MX3_PWMSR_FIFOAV_4WORDS		4
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define MX3_PWMCR_PRESCALER_SET(x)	FIELD_PREP(MX3_PWMCR_PRESCALER, (x) - 1)
7462306a36Sopenharmony_ci#define MX3_PWMCR_PRESCALER_GET(x)	(FIELD_GET(MX3_PWMCR_PRESCALER, \
7562306a36Sopenharmony_ci						   (x)) + 1)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define MX3_PWM_SWR_LOOP		5
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* PWMPR register value of 0xffff has the same effect as 0xfffe */
8062306a36Sopenharmony_ci#define MX3_PWMPR_MAX			0xfffe
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct pwm_imx27_chip {
8362306a36Sopenharmony_ci	struct clk	*clk_ipg;
8462306a36Sopenharmony_ci	struct clk	*clk_per;
8562306a36Sopenharmony_ci	void __iomem	*mmio_base;
8662306a36Sopenharmony_ci	struct pwm_chip	chip;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/*
8962306a36Sopenharmony_ci	 * The driver cannot read the current duty cycle from the hardware if
9062306a36Sopenharmony_ci	 * the hardware is disabled. Cache the last programmed duty cycle
9162306a36Sopenharmony_ci	 * value to return in that case.
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	unsigned int duty_cycle;
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define to_pwm_imx27_chip(chip)	container_of(chip, struct pwm_imx27_chip, chip)
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	int ret;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	ret = clk_prepare_enable(imx->clk_ipg);
10362306a36Sopenharmony_ci	if (ret)
10462306a36Sopenharmony_ci		return ret;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	ret = clk_prepare_enable(imx->clk_per);
10762306a36Sopenharmony_ci	if (ret) {
10862306a36Sopenharmony_ci		clk_disable_unprepare(imx->clk_ipg);
10962306a36Sopenharmony_ci		return ret;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return 0;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	clk_disable_unprepare(imx->clk_per);
11862306a36Sopenharmony_ci	clk_disable_unprepare(imx->clk_ipg);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int pwm_imx27_get_state(struct pwm_chip *chip,
12262306a36Sopenharmony_ci			       struct pwm_device *pwm, struct pwm_state *state)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
12562306a36Sopenharmony_ci	u32 period, prescaler, pwm_clk, val;
12662306a36Sopenharmony_ci	u64 tmp;
12762306a36Sopenharmony_ci	int ret;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	ret = pwm_imx27_clk_prepare_enable(imx);
13062306a36Sopenharmony_ci	if (ret < 0)
13162306a36Sopenharmony_ci		return ret;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	val = readl(imx->mmio_base + MX3_PWMCR);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (val & MX3_PWMCR_EN)
13662306a36Sopenharmony_ci		state->enabled = true;
13762306a36Sopenharmony_ci	else
13862306a36Sopenharmony_ci		state->enabled = false;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	switch (FIELD_GET(MX3_PWMCR_POUTC, val)) {
14162306a36Sopenharmony_ci	case MX3_PWMCR_POUTC_NORMAL:
14262306a36Sopenharmony_ci		state->polarity = PWM_POLARITY_NORMAL;
14362306a36Sopenharmony_ci		break;
14462306a36Sopenharmony_ci	case MX3_PWMCR_POUTC_INVERTED:
14562306a36Sopenharmony_ci		state->polarity = PWM_POLARITY_INVERSED;
14662306a36Sopenharmony_ci		break;
14762306a36Sopenharmony_ci	default:
14862306a36Sopenharmony_ci		dev_warn(chip->dev, "can't set polarity, output disconnected");
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	prescaler = MX3_PWMCR_PRESCALER_GET(val);
15262306a36Sopenharmony_ci	pwm_clk = clk_get_rate(imx->clk_per);
15362306a36Sopenharmony_ci	val = readl(imx->mmio_base + MX3_PWMPR);
15462306a36Sopenharmony_ci	period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */
15762306a36Sopenharmony_ci	tmp = NSEC_PER_SEC * (u64)(period + 2) * prescaler;
15862306a36Sopenharmony_ci	state->period = DIV_ROUND_UP_ULL(tmp, pwm_clk);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/*
16162306a36Sopenharmony_ci	 * PWMSAR can be read only if PWM is enabled. If the PWM is disabled,
16262306a36Sopenharmony_ci	 * use the cached value.
16362306a36Sopenharmony_ci	 */
16462306a36Sopenharmony_ci	if (state->enabled)
16562306a36Sopenharmony_ci		val = readl(imx->mmio_base + MX3_PWMSAR);
16662306a36Sopenharmony_ci	else
16762306a36Sopenharmony_ci		val = imx->duty_cycle;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	tmp = NSEC_PER_SEC * (u64)(val) * prescaler;
17062306a36Sopenharmony_ci	state->duty_cycle = DIV_ROUND_UP_ULL(tmp, pwm_clk);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	pwm_imx27_clk_disable_unprepare(imx);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return 0;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void pwm_imx27_sw_reset(struct pwm_chip *chip)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
18062306a36Sopenharmony_ci	struct device *dev = chip->dev;
18162306a36Sopenharmony_ci	int wait_count = 0;
18262306a36Sopenharmony_ci	u32 cr;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR);
18562306a36Sopenharmony_ci	do {
18662306a36Sopenharmony_ci		usleep_range(200, 1000);
18762306a36Sopenharmony_ci		cr = readl(imx->mmio_base + MX3_PWMCR);
18862306a36Sopenharmony_ci	} while ((cr & MX3_PWMCR_SWR) &&
18962306a36Sopenharmony_ci		 (wait_count++ < MX3_PWM_SWR_LOOP));
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (cr & MX3_PWMCR_SWR)
19262306a36Sopenharmony_ci		dev_warn(dev, "software reset timeout\n");
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip,
19662306a36Sopenharmony_ci				     struct pwm_device *pwm)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
19962306a36Sopenharmony_ci	struct device *dev = chip->dev;
20062306a36Sopenharmony_ci	unsigned int period_ms;
20162306a36Sopenharmony_ci	int fifoav;
20262306a36Sopenharmony_ci	u32 sr;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	sr = readl(imx->mmio_base + MX3_PWMSR);
20562306a36Sopenharmony_ci	fifoav = FIELD_GET(MX3_PWMSR_FIFOAV, sr);
20662306a36Sopenharmony_ci	if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
20762306a36Sopenharmony_ci		period_ms = DIV_ROUND_UP_ULL(pwm_get_period(pwm),
20862306a36Sopenharmony_ci					 NSEC_PER_MSEC);
20962306a36Sopenharmony_ci		msleep(period_ms);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		sr = readl(imx->mmio_base + MX3_PWMSR);
21262306a36Sopenharmony_ci		if (fifoav == FIELD_GET(MX3_PWMSR_FIFOAV, sr))
21362306a36Sopenharmony_ci			dev_warn(dev, "there is no free FIFO slot\n");
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
21862306a36Sopenharmony_ci			   const struct pwm_state *state)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	unsigned long period_cycles, duty_cycles, prescale;
22162306a36Sopenharmony_ci	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
22262306a36Sopenharmony_ci	struct pwm_state cstate;
22362306a36Sopenharmony_ci	unsigned long long c;
22462306a36Sopenharmony_ci	unsigned long long clkrate;
22562306a36Sopenharmony_ci	int ret;
22662306a36Sopenharmony_ci	u32 cr;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	pwm_get_state(pwm, &cstate);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	clkrate = clk_get_rate(imx->clk_per);
23162306a36Sopenharmony_ci	c = clkrate * state->period;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	do_div(c, NSEC_PER_SEC);
23462306a36Sopenharmony_ci	period_cycles = c;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	prescale = period_cycles / 0x10000 + 1;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	period_cycles /= prescale;
23962306a36Sopenharmony_ci	c = clkrate * state->duty_cycle;
24062306a36Sopenharmony_ci	do_div(c, NSEC_PER_SEC);
24162306a36Sopenharmony_ci	duty_cycles = c;
24262306a36Sopenharmony_ci	duty_cycles /= prescale;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/*
24562306a36Sopenharmony_ci	 * according to imx pwm RM, the real period value should be PERIOD
24662306a36Sopenharmony_ci	 * value in PWMPR plus 2.
24762306a36Sopenharmony_ci	 */
24862306a36Sopenharmony_ci	if (period_cycles > 2)
24962306a36Sopenharmony_ci		period_cycles -= 2;
25062306a36Sopenharmony_ci	else
25162306a36Sopenharmony_ci		period_cycles = 0;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/*
25462306a36Sopenharmony_ci	 * Wait for a free FIFO slot if the PWM is already enabled, and flush
25562306a36Sopenharmony_ci	 * the FIFO if the PWM was disabled and is about to be enabled.
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	if (cstate.enabled) {
25862306a36Sopenharmony_ci		pwm_imx27_wait_fifo_slot(chip, pwm);
25962306a36Sopenharmony_ci	} else {
26062306a36Sopenharmony_ci		ret = pwm_imx27_clk_prepare_enable(imx);
26162306a36Sopenharmony_ci		if (ret)
26262306a36Sopenharmony_ci			return ret;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		pwm_imx27_sw_reset(chip);
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
26862306a36Sopenharmony_ci	writel(period_cycles, imx->mmio_base + MX3_PWMPR);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/*
27162306a36Sopenharmony_ci	 * Store the duty cycle for future reference in cases where the
27262306a36Sopenharmony_ci	 * MX3_PWMSAR register can't be read (i.e. when the PWM is disabled).
27362306a36Sopenharmony_ci	 */
27462306a36Sopenharmony_ci	imx->duty_cycle = duty_cycles;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	cr = MX3_PWMCR_PRESCALER_SET(prescale) |
27762306a36Sopenharmony_ci	     MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN |
27862306a36Sopenharmony_ci	     FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) |
27962306a36Sopenharmony_ci	     MX3_PWMCR_DBGEN;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (state->polarity == PWM_POLARITY_INVERSED)
28262306a36Sopenharmony_ci		cr |= FIELD_PREP(MX3_PWMCR_POUTC,
28362306a36Sopenharmony_ci				MX3_PWMCR_POUTC_INVERTED);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (state->enabled)
28662306a36Sopenharmony_ci		cr |= MX3_PWMCR_EN;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	writel(cr, imx->mmio_base + MX3_PWMCR);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (!state->enabled)
29162306a36Sopenharmony_ci		pwm_imx27_clk_disable_unprepare(imx);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return 0;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic const struct pwm_ops pwm_imx27_ops = {
29762306a36Sopenharmony_ci	.apply = pwm_imx27_apply,
29862306a36Sopenharmony_ci	.get_state = pwm_imx27_get_state,
29962306a36Sopenharmony_ci	.owner = THIS_MODULE,
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic const struct of_device_id pwm_imx27_dt_ids[] = {
30362306a36Sopenharmony_ci	{ .compatible = "fsl,imx27-pwm", },
30462306a36Sopenharmony_ci	{ /* sentinel */ }
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int pwm_imx27_probe(struct platform_device *pdev)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct pwm_imx27_chip *imx;
31162306a36Sopenharmony_ci	int ret;
31262306a36Sopenharmony_ci	u32 pwmcr;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
31562306a36Sopenharmony_ci	if (imx == NULL)
31662306a36Sopenharmony_ci		return -ENOMEM;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
31962306a36Sopenharmony_ci	if (IS_ERR(imx->clk_ipg))
32062306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg),
32162306a36Sopenharmony_ci				     "getting ipg clock failed\n");
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	imx->clk_per = devm_clk_get(&pdev->dev, "per");
32462306a36Sopenharmony_ci	if (IS_ERR(imx->clk_per))
32562306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per),
32662306a36Sopenharmony_ci				     "failed to get peripheral clock\n");
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	imx->chip.ops = &pwm_imx27_ops;
32962306a36Sopenharmony_ci	imx->chip.dev = &pdev->dev;
33062306a36Sopenharmony_ci	imx->chip.npwm = 1;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
33362306a36Sopenharmony_ci	if (IS_ERR(imx->mmio_base))
33462306a36Sopenharmony_ci		return PTR_ERR(imx->mmio_base);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	ret = pwm_imx27_clk_prepare_enable(imx);
33762306a36Sopenharmony_ci	if (ret)
33862306a36Sopenharmony_ci		return ret;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* keep clks on if pwm is running */
34162306a36Sopenharmony_ci	pwmcr = readl(imx->mmio_base + MX3_PWMCR);
34262306a36Sopenharmony_ci	if (!(pwmcr & MX3_PWMCR_EN))
34362306a36Sopenharmony_ci		pwm_imx27_clk_disable_unprepare(imx);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return devm_pwmchip_add(&pdev->dev, &imx->chip);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic struct platform_driver imx_pwm_driver = {
34962306a36Sopenharmony_ci	.driver = {
35062306a36Sopenharmony_ci		.name = "pwm-imx27",
35162306a36Sopenharmony_ci		.of_match_table = pwm_imx27_dt_ids,
35262306a36Sopenharmony_ci	},
35362306a36Sopenharmony_ci	.probe = pwm_imx27_probe,
35462306a36Sopenharmony_ci};
35562306a36Sopenharmony_cimodule_platform_driver(imx_pwm_driver);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
35862306a36Sopenharmony_ciMODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
359