1166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer/*
2166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * simple driver for PWM (Pulse Width Modulator) controller
3166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer *
4166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * This program is free software; you can redistribute it and/or modify
5166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * it under the terms of the GNU General Public License version 2 as
6166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * published by the Free Software Foundation.
7166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer *
8166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
9166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer */
10166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
11166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/module.h>
12166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/kernel.h>
13166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/platform_device.h>
145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
15166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/err.h>
16166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/clk.h>
17137fd45ffec15db14034990ceac890975cae7a32Liu Ying#include <linux/delay.h>
18166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/io.h>
19166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/pwm.h>
202a8876cfdf14de557705e2559df99f40058a3b3bSachin Kamat#include <linux/of.h>
21479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel#include <linux/of_device.h>
22c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig
23c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig/* i.MX1 and i.MX21 share the same PWM function block: */
24c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig
2540f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMC			0x00   /* PWM Control Register */
2640f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMS			0x04   /* PWM Sample Register */
2740f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMP			0x08   /* PWM Period Register */
28c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig
2940f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMC_EN			(1 << 4)
30c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig
31c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
32c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig
3340f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR			0x00    /* PWM Control Register */
34137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMSR			0x04    /* PWM Status Register */
3540f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMSAR			0x0C    /* PWM Sample Register */
3640f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMPR			0x10    /* PWM Period Register */
3740f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_PRESCALER(x)		((((x) - 1) & 0xFFF) << 4)
3840f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_DOZEEN		(1 << 24)
3940f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_WAITEN		(1 << 23)
40c0d96aed8c6dd925afe9ea35491a0cd458642a86Jason Chen#define MX3_PWMCR_DBGEN			(1 << 22)
4140f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_CLKSRC_IPG_HIGH	(2 << 16)
4240f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_CLKSRC_IPG		(1 << 16)
43137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMCR_SWR			(1 << 3)
4440f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_EN			(1 << 0)
45137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMSR_FIFOAV_4WORDS		0x4
46137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMSR_FIFOAV_MASK		0x7
47137fd45ffec15db14034990ceac890975cae7a32Liu Ying
48137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWM_SWR_LOOP		5
49c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig
5029693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstruct imx_chip {
517b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	struct clk	*clk_per;
527b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	struct clk	*clk_ipg;
53166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
54166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	void __iomem	*mmio_base;
55166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
5629693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	struct pwm_chip	chip;
5719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
5819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	int (*config)(struct pwm_chip *chip,
5919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer		struct pwm_device *pwm, int duty_ns, int period_ns);
6066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	void (*set_enable)(struct pwm_chip *chip, bool enable);
61166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer};
62166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
6329693248edf10830db2ef82b36806e378ff75c67Sascha Hauer#define to_imx_chip(chip)	container_of(chip, struct imx_chip, chip)
6429693248edf10830db2ef82b36806e378ff75c67Sascha Hauer
6519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauerstatic int imx_pwm_config_v1(struct pwm_chip *chip,
6629693248edf10830db2ef82b36806e378ff75c67Sascha Hauer		struct pwm_device *pwm, int duty_ns, int period_ns)
67166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{
6829693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	struct imx_chip *imx = to_imx_chip(chip);
69166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
7019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	/*
7119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * The PWM subsystem allows for exact frequencies. However,
7219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * I cannot connect a scope on my device to the PWM line and
7319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * thus cannot provide the program the PWM controller
7419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * exactly. Instead, I'm relying on the fact that the
7519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * Bootloader (u-boot or WinCE+haret) has programmed the PWM
7619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * function group already. So I'll just modify the PWM sample
7719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * register to follow the ratio of duty_ns vs. period_ns
7819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * accordingly.
7919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 *
8019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * This is good enough for programming the brightness of
8119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * the LCD backlight.
8219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 *
8319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * The real implementation would divide PERCLK[0] first by
8419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * both the prescaler (/1 .. /128) and then by CLKSEL
8519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * (/2 .. /16).
8619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 */
8719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	u32 max = readl(imx->mmio_base + MX1_PWMP);
8819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	u32 p = max * duty_ns / period_ns;
8919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	writel(max - p, imx->mmio_base + MX1_PWMS);
9019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
9119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	return 0;
9219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer}
9319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
9466ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauerstatic void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
9566ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer{
9666ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	struct imx_chip *imx = to_imx_chip(chip);
9766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	u32 val;
9866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
9966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	val = readl(imx->mmio_base + MX1_PWMC);
10066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
10166ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	if (enable)
10266ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer		val |= MX1_PWMC_EN;
10366ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	else
10466ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer		val &= ~MX1_PWMC_EN;
10566ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
10666ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	writel(val, imx->mmio_base + MX1_PWMC);
10766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer}
10866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
10919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauerstatic int imx_pwm_config_v2(struct pwm_chip *chip,
11019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer		struct pwm_device *pwm, int duty_ns, int period_ns)
11119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer{
11219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	struct imx_chip *imx = to_imx_chip(chip);
113137fd45ffec15db14034990ceac890975cae7a32Liu Ying	struct device *dev = chip->dev;
11419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	unsigned long long c;
11519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	unsigned long period_cycles, duty_cycles, prescale;
116137fd45ffec15db14034990ceac890975cae7a32Liu Ying	unsigned int period_ms;
117137fd45ffec15db14034990ceac890975cae7a32Liu Ying	bool enable = test_bit(PWMF_ENABLED, &pwm->flags);
118137fd45ffec15db14034990ceac890975cae7a32Liu Ying	int wait_count = 0, fifoav;
119137fd45ffec15db14034990ceac890975cae7a32Liu Ying	u32 cr, sr;
120137fd45ffec15db14034990ceac890975cae7a32Liu Ying
121137fd45ffec15db14034990ceac890975cae7a32Liu Ying	/*
122137fd45ffec15db14034990ceac890975cae7a32Liu Ying	 * i.MX PWMv2 has a 4-word sample FIFO.
123137fd45ffec15db14034990ceac890975cae7a32Liu Ying	 * In order to avoid FIFO overflow issue, we do software reset
124137fd45ffec15db14034990ceac890975cae7a32Liu Ying	 * to clear all sample FIFO if the controller is disabled or
125137fd45ffec15db14034990ceac890975cae7a32Liu Ying	 * wait for a full PWM cycle to get a relinquished FIFO slot
126137fd45ffec15db14034990ceac890975cae7a32Liu Ying	 * when the controller is enabled and the FIFO is fully loaded.
127137fd45ffec15db14034990ceac890975cae7a32Liu Ying	 */
128137fd45ffec15db14034990ceac890975cae7a32Liu Ying	if (enable) {
129137fd45ffec15db14034990ceac890975cae7a32Liu Ying		sr = readl(imx->mmio_base + MX3_PWMSR);
130137fd45ffec15db14034990ceac890975cae7a32Liu Ying		fifoav = sr & MX3_PWMSR_FIFOAV_MASK;
131137fd45ffec15db14034990ceac890975cae7a32Liu Ying		if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
132137fd45ffec15db14034990ceac890975cae7a32Liu Ying			period_ms = DIV_ROUND_UP(pwm->period, NSEC_PER_MSEC);
133137fd45ffec15db14034990ceac890975cae7a32Liu Ying			msleep(period_ms);
134137fd45ffec15db14034990ceac890975cae7a32Liu Ying
135137fd45ffec15db14034990ceac890975cae7a32Liu Ying			sr = readl(imx->mmio_base + MX3_PWMSR);
136137fd45ffec15db14034990ceac890975cae7a32Liu Ying			if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK))
137137fd45ffec15db14034990ceac890975cae7a32Liu Ying				dev_warn(dev, "there is no free FIFO slot\n");
138137fd45ffec15db14034990ceac890975cae7a32Liu Ying		}
139137fd45ffec15db14034990ceac890975cae7a32Liu Ying	} else {
140137fd45ffec15db14034990ceac890975cae7a32Liu Ying		writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR);
141137fd45ffec15db14034990ceac890975cae7a32Liu Ying		do {
142137fd45ffec15db14034990ceac890975cae7a32Liu Ying			usleep_range(200, 1000);
143137fd45ffec15db14034990ceac890975cae7a32Liu Ying			cr = readl(imx->mmio_base + MX3_PWMCR);
144137fd45ffec15db14034990ceac890975cae7a32Liu Ying		} while ((cr & MX3_PWMCR_SWR) &&
145137fd45ffec15db14034990ceac890975cae7a32Liu Ying			 (wait_count++ < MX3_PWM_SWR_LOOP));
146137fd45ffec15db14034990ceac890975cae7a32Liu Ying
147137fd45ffec15db14034990ceac890975cae7a32Liu Ying		if (cr & MX3_PWMCR_SWR)
148137fd45ffec15db14034990ceac890975cae7a32Liu Ying			dev_warn(dev, "software reset timeout\n");
149137fd45ffec15db14034990ceac890975cae7a32Liu Ying	}
15019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
1517b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	c = clk_get_rate(imx->clk_per);
15219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	c = c * period_ns;
15319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	do_div(c, 1000000000);
15419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	period_cycles = c;
15519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
15619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	prescale = period_cycles / 0x10000 + 1;
15719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
15819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	period_cycles /= prescale;
15919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	c = (unsigned long long)period_cycles * duty_ns;
16019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	do_div(c, period_ns);
16119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	duty_cycles = c;
16219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
16319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	/*
16419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * according to imx pwm RM, the real period value should be
16519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 * PERIOD value in PWMPR plus 2.
16619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	 */
16719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	if (period_cycles > 2)
16819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer		period_cycles -= 2;
16919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	else
17019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer		period_cycles = 0;
17119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
17219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
17319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	writel(period_cycles, imx->mmio_base + MX3_PWMPR);
17419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
17519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	cr = MX3_PWMCR_PRESCALER(prescale) |
17619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer		MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
1778d1c24bfd20829f5943c76b85c4973db264dd666Sascha Hauer		MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH;
17866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
179137fd45ffec15db14034990ceac890975cae7a32Liu Ying	if (enable)
18066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer		cr |= MX3_PWMCR_EN;
18119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
18219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	writel(cr, imx->mmio_base + MX3_PWMCR);
183166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
184166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	return 0;
185166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer}
186166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
18766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauerstatic void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
18866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer{
18966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	struct imx_chip *imx = to_imx_chip(chip);
19066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	u32 val;
19166ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
19266ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	val = readl(imx->mmio_base + MX3_PWMCR);
19366ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
19466ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	if (enable)
19566ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer		val |= MX3_PWMCR_EN;
19666ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	else
19766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer		val &= ~MX3_PWMCR_EN;
19866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
19966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	writel(val, imx->mmio_base + MX3_PWMCR);
20066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer}
20166ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
20219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauerstatic int imx_pwm_config(struct pwm_chip *chip,
20319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer		struct pwm_device *pwm, int duty_ns, int period_ns)
20419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer{
20519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer	struct imx_chip *imx = to_imx_chip(chip);
2067b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	int ret;
2077b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel
2087b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	ret = clk_prepare_enable(imx->clk_ipg);
2097b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	if (ret)
2107b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel		return ret;
21119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
2127b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	ret = imx->config(chip, pwm, duty_ns, period_ns);
2137b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel
2147b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	clk_disable_unprepare(imx->clk_ipg);
2157b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel
2167b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	return ret;
21719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer}
21819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
21929693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
220166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{
22129693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	struct imx_chip *imx = to_imx_chip(chip);
222140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer	int ret;
223166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
2247b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	ret = clk_prepare_enable(imx->clk_per);
225140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer	if (ret)
226140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer		return ret;
227140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer
22866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	imx->set_enable(chip, true);
22966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer
230140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer	return 0;
231166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer}
232166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
23329693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
234166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{
23529693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	struct imx_chip *imx = to_imx_chip(chip);
236166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
23766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer	imx->set_enable(chip, false);
238166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
2397b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	clk_disable_unprepare(imx->clk_per);
240166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer}
241166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
24229693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic struct pwm_ops imx_pwm_ops = {
24329693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	.enable = imx_pwm_enable,
24429693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	.disable = imx_pwm_disable,
24529693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	.config = imx_pwm_config,
24629693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	.owner = THIS_MODULE,
24729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer};
248166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
249479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstruct imx_pwm_data {
250479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	int (*config)(struct pwm_chip *chip,
251479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel		struct pwm_device *pwm, int duty_ns, int period_ns);
252479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	void (*set_enable)(struct pwm_chip *chip, bool enable);
253479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel};
254479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel
255479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstatic struct imx_pwm_data imx_pwm_data_v1 = {
256479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	.config = imx_pwm_config_v1,
257479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	.set_enable = imx_pwm_set_enable_v1,
258479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel};
259479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel
260479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstatic struct imx_pwm_data imx_pwm_data_v2 = {
261479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	.config = imx_pwm_config_v2,
262479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	.set_enable = imx_pwm_set_enable_v2,
263479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel};
264479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel
265479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstatic const struct of_device_id imx_pwm_dt_ids[] = {
266479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	{ .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, },
267479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	{ .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, },
268479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	{ /* sentinel */ }
269479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel};
270479e2e301c626cc64fb27b6b1938655eaba8b036Philipp ZabelMODULE_DEVICE_TABLE(of, imx_pwm_dt_ids);
271479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel
2723e9fe83d278cce6974f0a4d1870c0ff4a0b74ba5Bill Pembertonstatic int imx_pwm_probe(struct platform_device *pdev)
273166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{
274479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	const struct of_device_id *of_id =
275479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel			of_match_device(imx_pwm_dt_ids, &pdev->dev);
276983290b0625628448ea8907243e3cbceda0a8d74Lothar Waßmann	const struct imx_pwm_data *data;
27729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	struct imx_chip *imx;
278166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	struct resource *r;
279166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	int ret = 0;
280166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
281479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	if (!of_id)
282479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel		return -ENODEV;
283479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel
284a9970e3becbbb095296afdf0bcaa1ce2b819360fAxel Lin	imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
2851cbec749bf5a7d9259ce0650e2287cf95e65225dJingoo Han	if (imx == NULL)
286166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer		return -ENOMEM;
287166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
2887b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	imx->clk_per = devm_clk_get(&pdev->dev, "per");
2897b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	if (IS_ERR(imx->clk_per)) {
2907b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel		dev_err(&pdev->dev, "getting per clock failed with %ld\n",
2917b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel				PTR_ERR(imx->clk_per));
2927b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel		return PTR_ERR(imx->clk_per);
2937b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	}
294166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
2957b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
2967b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	if (IS_ERR(imx->clk_ipg)) {
2977b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel		dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
2987b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel				PTR_ERR(imx->clk_ipg));
2997b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel		return PTR_ERR(imx->clk_ipg);
3007b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel	}
301166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
30229693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	imx->chip.ops = &imx_pwm_ops;
30329693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	imx->chip.dev = &pdev->dev;
30429693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	imx->chip.base = -1;
30529693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	imx->chip.npwm = 1;
30631c4fa3442570d001f58303dea36d81693bc199cShawn Guo	imx->chip.can_sleep = true;
307166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
308166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3096d4294d1634543853febc4287ecf02998fd234e1Thierry Reding	imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
3106d4294d1634543853febc4287ecf02998fd234e1Thierry Reding	if (IS_ERR(imx->mmio_base))
3116d4294d1634543853febc4287ecf02998fd234e1Thierry Reding		return PTR_ERR(imx->mmio_base);
312166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
313479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	data = of_id->data;
314479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	imx->config = data->config;
315479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel	imx->set_enable = data->set_enable;
31619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer
31729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	ret = pwmchip_add(&imx->chip);
31829693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	if (ret < 0)
319a9970e3becbbb095296afdf0bcaa1ce2b819360fAxel Lin		return ret;
320166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
32129693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	platform_set_drvdata(pdev, imx);
322166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	return 0;
323166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer}
324166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
32577f37917a6f2bd8635b553178bb34bdd80f08e40Bill Pembertonstatic int imx_pwm_remove(struct platform_device *pdev)
326166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{
32729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	struct imx_chip *imx;
328166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
32929693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	imx = platform_get_drvdata(pdev);
33029693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	if (imx == NULL)
331166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer		return -ENODEV;
332166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
333a9970e3becbbb095296afdf0bcaa1ce2b819360fAxel Lin	return pwmchip_remove(&imx->chip);
334166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer}
335166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
33629693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic struct platform_driver imx_pwm_driver = {
337166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	.driver		= {
338479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel		.name	= "imx-pwm",
3393dd0a909479c1d372341d749b4ff94cd638b57daThierry Reding		.owner = THIS_MODULE,
340becbca1390a5147b363a34e238e74cffe65eecc3Sachin Kamat		.of_match_table = imx_pwm_dt_ids,
341166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer	},
34229693248edf10830db2ef82b36806e378ff75c67Sascha Hauer	.probe		= imx_pwm_probe,
343fd1091125a1d11fcc635749d0d3dec36904a7a48Bill Pemberton	.remove		= imx_pwm_remove,
344166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer};
345166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
346208d038f4792b5ca0dc76deebbc0ae13b4f1a744Sascha Hauermodule_platform_driver(imx_pwm_driver);
347166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer
348166091b1894df3de736f43c649f2e6639f4a31acSascha HauerMODULE_LICENSE("GPL v2");
349166091b1894df3de736f43c649f2e6639f4a31acSascha HauerMODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
350