Blame view

drivers/pwm/pwm-imx27.c 9.7 KB
a99290c58   Fabio Estevam   pwm: imx: Switch ...
1
  // SPDX-License-Identifier: GPL-2.0
166091b18   Sascha Hauer   [ARM] MXC: add pw...
2
3
4
  /*
   * simple driver for PWM (Pulse Width Modulator) controller
   *
166091b18   Sascha Hauer   [ARM] MXC: add pw...
5
   * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
f6960976c   Uwe Kleine-König   pwm: imx: Documen...
6
7
8
9
   *
   * Limitations:
   * - When disabled the output is driven to 0 independent of the configured
   *   polarity.
166091b18   Sascha Hauer   [ARM] MXC: add pw...
10
   */
9f617ada9   Michal Vokáč   pwm: imx: Use bit...
11
12
  #include <linux/bitfield.h>
  #include <linux/bitops.h>
166091b18   Sascha Hauer   [ARM] MXC: add pw...
13
  #include <linux/clk.h>
137fd45ff   Liu Ying   pwm: imx: Avoid s...
14
  #include <linux/delay.h>
e3adc7efe   Michal Vokáč   pwm: imx: Sort in...
15
  #include <linux/err.h>
166091b18   Sascha Hauer   [ARM] MXC: add pw...
16
  #include <linux/io.h>
e3adc7efe   Michal Vokáč   pwm: imx: Sort in...
17
18
  #include <linux/kernel.h>
  #include <linux/module.h>
2a8876cfd   Sachin Kamat   pwm: imx: Include...
19
  #include <linux/of.h>
e3adc7efe   Michal Vokáč   pwm: imx: Sort in...
20
21
22
  #include <linux/platform_device.h>
  #include <linux/pwm.h>
  #include <linux/slab.h>
c010dba89   Holger Schurig   imx: re-work of P...
23

40f260c2c   Liu Ying   pwm: imx: Cleanup...
24
  #define MX3_PWMCR			0x00    /* PWM Control Register */
137fd45ff   Liu Ying   pwm: imx: Avoid s...
25
  #define MX3_PWMSR			0x04    /* PWM Status Register */
40f260c2c   Liu Ying   pwm: imx: Cleanup...
26
27
  #define MX3_PWMSAR			0x0C    /* PWM Sample Register */
  #define MX3_PWMPR			0x10    /* PWM Period Register */
9f617ada9   Michal Vokáč   pwm: imx: Use bit...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  
  #define MX3_PWMCR_FWM			GENMASK(27, 26)
  #define MX3_PWMCR_STOPEN		BIT(25)
  #define MX3_PWMCR_DOZEN			BIT(24)
  #define MX3_PWMCR_WAITEN		BIT(23)
  #define MX3_PWMCR_DBGEN			BIT(22)
  #define MX3_PWMCR_BCTR			BIT(21)
  #define MX3_PWMCR_HCTR			BIT(20)
  
  #define MX3_PWMCR_POUTC			GENMASK(19, 18)
  #define MX3_PWMCR_POUTC_NORMAL		0
  #define MX3_PWMCR_POUTC_INVERTED	1
  #define MX3_PWMCR_POUTC_OFF		2
  
  #define MX3_PWMCR_CLKSRC		GENMASK(17, 16)
  #define MX3_PWMCR_CLKSRC_OFF		0
  #define MX3_PWMCR_CLKSRC_IPG		1
  #define MX3_PWMCR_CLKSRC_IPG_HIGH	2
  #define MX3_PWMCR_CLKSRC_IPG_32K	3
  
  #define MX3_PWMCR_PRESCALER		GENMASK(15, 4)
  
  #define MX3_PWMCR_SWR			BIT(3)
  
  #define MX3_PWMCR_REPEAT		GENMASK(2, 1)
  #define MX3_PWMCR_REPEAT_1X		0
  #define MX3_PWMCR_REPEAT_2X		1
  #define MX3_PWMCR_REPEAT_4X		2
  #define MX3_PWMCR_REPEAT_8X		3
  
  #define MX3_PWMCR_EN			BIT(0)
  
  #define MX3_PWMSR_FWE			BIT(6)
  #define MX3_PWMSR_CMP			BIT(5)
  #define MX3_PWMSR_ROV			BIT(4)
  #define MX3_PWMSR_FE			BIT(3)
  
  #define MX3_PWMSR_FIFOAV		GENMASK(2, 0)
  #define MX3_PWMSR_FIFOAV_EMPTY		0
  #define MX3_PWMSR_FIFOAV_1WORD		1
  #define MX3_PWMSR_FIFOAV_2WORDS		2
  #define MX3_PWMSR_FIFOAV_3WORDS		3
  #define MX3_PWMSR_FIFOAV_4WORDS		4
  
  #define MX3_PWMCR_PRESCALER_SET(x)	FIELD_PREP(MX3_PWMCR_PRESCALER, (x) - 1)
  #define MX3_PWMCR_PRESCALER_GET(x)	(FIELD_GET(MX3_PWMCR_PRESCALER, \
  						   (x)) + 1)
137fd45ff   Liu Ying   pwm: imx: Avoid s...
75
76
  
  #define MX3_PWM_SWR_LOOP		5
c010dba89   Holger Schurig   imx: re-work of P...
77

bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
78
79
  /* PWMPR register value of 0xffff has the same effect as 0xfffe */
  #define MX3_PWMPR_MAX			0xfffe
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
80
  struct pwm_imx27_chip {
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
81
  	struct clk	*clk_ipg;
7b27c160c   Philipp Zabel   pwm: i.MX: fix cl...
82
  	struct clk	*clk_per;
4cbdea0ba   Liu Ying   pwm: imx27: Use 3...
83
  	struct clk	*clk_32k;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
84
  	void __iomem	*mmio_base;
29693248e   Sascha Hauer   ARM i.MX: Move i....
85
  	struct pwm_chip	chip;
a3597d6c8   Thierry Reding   pwm: imx27: Cache...
86
87
88
89
90
91
92
  
  	/*
  	 * The driver cannot read the current duty cycle from the hardware if
  	 * the hardware is disabled. Cache the last programmed duty cycle
  	 * value to return in that case.
  	 */
  	unsigned int duty_cycle;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
93
  };
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
94
  #define to_pwm_imx27_chip(chip)	container_of(chip, struct pwm_imx27_chip, chip)
29693248e   Sascha Hauer   ARM i.MX: Move i....
95

aad4e530c   Uwe Kleine-König   pwm: imx27: Simpl...
96
  static int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx)
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
97
  {
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
98
  	int ret;
4cbdea0ba   Liu Ying   pwm: imx27: Use 3...
99
100
101
102
103
  	if (imx->clk_32k) {
  		ret = clk_prepare_enable(imx->clk_32k);
  		if (ret)
  			goto err1;
  	}
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
104
105
  	ret = clk_prepare_enable(imx->clk_ipg);
  	if (ret)
4cbdea0ba   Liu Ying   pwm: imx27: Use 3...
106
  		goto err2;
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
107
108
  
  	ret = clk_prepare_enable(imx->clk_per);
4cbdea0ba   Liu Ying   pwm: imx27: Use 3...
109
110
  	if (ret)
  		goto err3;
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
111
112
  
  	return 0;
4cbdea0ba   Liu Ying   pwm: imx27: Use 3...
113
114
115
116
117
118
119
  err3:
  	clk_disable_unprepare(imx->clk_ipg);
  err2:
  	if (imx->clk_32k)
  		clk_disable_unprepare(imx->clk_32k);
  err1:
  	return ret;
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
120
  }
aad4e530c   Uwe Kleine-König   pwm: imx27: Simpl...
121
  static void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx)
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
122
  {
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
123
124
  	clk_disable_unprepare(imx->clk_per);
  	clk_disable_unprepare(imx->clk_ipg);
4cbdea0ba   Liu Ying   pwm: imx27: Use 3...
125
126
  	if (imx->clk_32k)
  		clk_disable_unprepare(imx->clk_32k);
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
127
  }
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
128
129
  static void pwm_imx27_get_state(struct pwm_chip *chip,
  				struct pwm_device *pwm, struct pwm_state *state)
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
130
  {
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
131
  	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
7ca17b207   Dan Carpenter   pwm: imx: Signedn...
132
  	u32 period, prescaler, pwm_clk, val;
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
133
  	u64 tmp;
7ca17b207   Dan Carpenter   pwm: imx: Signedn...
134
  	int ret;
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
135

aad4e530c   Uwe Kleine-König   pwm: imx27: Simpl...
136
  	ret = pwm_imx27_clk_prepare_enable(imx);
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
137
138
  	if (ret < 0)
  		return;
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
139
  	val = readl(imx->mmio_base + MX3_PWMCR);
519ef9b5f   Uwe Kleine-König   pwm: imx27: Only ...
140
  	if (val & MX3_PWMCR_EN)
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
141
  		state->enabled = true;
519ef9b5f   Uwe Kleine-König   pwm: imx27: Only ...
142
  	else
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
143
  		state->enabled = false;
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  
  	switch (FIELD_GET(MX3_PWMCR_POUTC, val)) {
  	case MX3_PWMCR_POUTC_NORMAL:
  		state->polarity = PWM_POLARITY_NORMAL;
  		break;
  	case MX3_PWMCR_POUTC_INVERTED:
  		state->polarity = PWM_POLARITY_INVERSED;
  		break;
  	default:
  		dev_warn(chip->dev, "can't set polarity, output disconnected");
  	}
  
  	prescaler = MX3_PWMCR_PRESCALER_GET(val);
  	pwm_clk = clk_get_rate(imx->clk_per);
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
158
159
160
161
  	val = readl(imx->mmio_base + MX3_PWMPR);
  	period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val;
  
  	/* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */
aef1a3799   Uwe Kleine-König   pwm: imx27: Fix r...
162
163
  	tmp = NSEC_PER_SEC * (u64)(period + 2) * prescaler;
  	state->period = DIV_ROUND_UP_ULL(tmp, pwm_clk);
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
164

a3597d6c8   Thierry Reding   pwm: imx27: Cache...
165
166
167
168
169
  	/*
  	 * PWMSAR can be read only if PWM is enabled. If the PWM is disabled,
  	 * use the cached value.
  	 */
  	if (state->enabled)
bf9b0b1b0   Michal Vokáč   pwm: imx: Impleme...
170
  		val = readl(imx->mmio_base + MX3_PWMSAR);
a3597d6c8   Thierry Reding   pwm: imx27: Cache...
171
172
  	else
  		val = imx->duty_cycle;
aef1a3799   Uwe Kleine-König   pwm: imx27: Fix r...
173
174
  	tmp = NSEC_PER_SEC * (u64)(val) * prescaler;
  	state->duty_cycle = DIV_ROUND_UP_ULL(tmp, pwm_clk);
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
175

2cb5cd90f   Uwe Kleine-König   pwm: imx27: Ensur...
176
  	pwm_imx27_clk_disable_unprepare(imx);
66ad6a613   Sascha Hauer   pwm: i.MX: add fu...
177
  }
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
178
  static void pwm_imx27_sw_reset(struct pwm_chip *chip)
19e733332   Sascha Hauer   pwm: i.MX: factor...
179
  {
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
180
  	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
970247a48   Lukasz Majewski   pwm: imx: Move PW...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  	struct device *dev = chip->dev;
  	int wait_count = 0;
  	u32 cr;
  
  	writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR);
  	do {
  		usleep_range(200, 1000);
  		cr = readl(imx->mmio_base + MX3_PWMCR);
  	} while ((cr & MX3_PWMCR_SWR) &&
  		 (wait_count++ < MX3_PWM_SWR_LOOP));
  
  	if (cr & MX3_PWMCR_SWR)
  		dev_warn(dev, "software reset timeout
  ");
  }
19e733332   Sascha Hauer   pwm: i.MX: factor...
196

d80f82069   Uwe Kleine-König   pwm: imx: Split i...
197
198
  static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip,
  				     struct pwm_device *pwm)
73b1ff1f3   Lukasz Majewski   pwm: imx: Move PW...
199
  {
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
200
  	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
73b1ff1f3   Lukasz Majewski   pwm: imx: Move PW...
201
202
203
204
  	struct device *dev = chip->dev;
  	unsigned int period_ms;
  	int fifoav;
  	u32 sr;
7b27c160c   Philipp Zabel   pwm: i.MX: fix cl...
205

73b1ff1f3   Lukasz Majewski   pwm: imx: Move PW...
206
  	sr = readl(imx->mmio_base + MX3_PWMSR);
9f617ada9   Michal Vokáč   pwm: imx: Use bit...
207
  	fifoav = FIELD_GET(MX3_PWMSR_FIFOAV, sr);
73b1ff1f3   Lukasz Majewski   pwm: imx: Move PW...
208
  	if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
1689dcd43   Guru Das Srinagesh   pwm: imx27: Use 6...
209
  		period_ms = DIV_ROUND_UP_ULL(pwm_get_period(pwm),
73b1ff1f3   Lukasz Majewski   pwm: imx: Move PW...
210
211
  					 NSEC_PER_MSEC);
  		msleep(period_ms);
7b27c160c   Philipp Zabel   pwm: i.MX: fix cl...
212

73b1ff1f3   Lukasz Majewski   pwm: imx: Move PW...
213
  		sr = readl(imx->mmio_base + MX3_PWMSR);
9f617ada9   Michal Vokáč   pwm: imx: Use bit...
214
  		if (fifoav == FIELD_GET(MX3_PWMSR_FIFOAV, sr))
73b1ff1f3   Lukasz Majewski   pwm: imx: Move PW...
215
216
217
  			dev_warn(dev, "there is no free FIFO slot
  ");
  	}
19e733332   Sascha Hauer   pwm: i.MX: factor...
218
  }
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
219
  static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
71523d181   Uwe Kleine-König   pwm: Ensure pwm_a...
220
  			   const struct pwm_state *state)
166091b18   Sascha Hauer   [ARM] MXC: add pw...
221
  {
0ca1a11a1   Lukasz Majewski   pwm: imx: Provide...
222
  	unsigned long period_cycles, duty_cycles, prescale;
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
223
  	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
0ca1a11a1   Lukasz Majewski   pwm: imx: Provide...
224
225
  	struct pwm_state cstate;
  	unsigned long long c;
aef1a3799   Uwe Kleine-König   pwm: imx27: Fix r...
226
  	unsigned long long clkrate;
140827c14   Sascha Hauer   pwm: i.MX: remove...
227
  	int ret;
326ed314f   Lukasz Majewski   pwm: imx: Add pol...
228
  	u32 cr;
0ca1a11a1   Lukasz Majewski   pwm: imx: Provide...
229
230
  
  	pwm_get_state(pwm, &cstate);
aef1a3799   Uwe Kleine-König   pwm: imx27: Fix r...
231
232
  	clkrate = clk_get_rate(imx->clk_per);
  	c = clkrate * state->period;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
233

aef1a3799   Uwe Kleine-König   pwm: imx27: Fix r...
234
  	do_div(c, NSEC_PER_SEC);
bd88d319a   Thierry Reding   pwm: imx27: Uncon...
235
236
237
238
239
  	period_cycles = c;
  
  	prescale = period_cycles / 0x10000 + 1;
  
  	period_cycles /= prescale;
aef1a3799   Uwe Kleine-König   pwm: imx27: Fix r...
240
  	c = clkrate * state->duty_cycle;
7c4544a21   Uwe Kleine-König   pwm: imx27: Fix o...
241
  	do_div(c, NSEC_PER_SEC);
bd88d319a   Thierry Reding   pwm: imx27: Uncon...
242
  	duty_cycles = c;
7c4544a21   Uwe Kleine-König   pwm: imx27: Fix o...
243
  	duty_cycles /= prescale;
bd88d319a   Thierry Reding   pwm: imx27: Uncon...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  
  	/*
  	 * according to imx pwm RM, the real period value should be PERIOD
  	 * value in PWMPR plus 2.
  	 */
  	if (period_cycles > 2)
  		period_cycles -= 2;
  	else
  		period_cycles = 0;
  
  	/*
  	 * Wait for a free FIFO slot if the PWM is already enabled, and flush
  	 * the FIFO if the PWM was disabled and is about to be enabled.
  	 */
  	if (cstate.enabled) {
  		pwm_imx27_wait_fifo_slot(chip, pwm);
  	} else {
aad4e530c   Uwe Kleine-König   pwm: imx27: Simpl...
261
  		ret = pwm_imx27_clk_prepare_enable(imx);
bd88d319a   Thierry Reding   pwm: imx27: Uncon...
262
263
264
265
  		if (ret)
  			return ret;
  
  		pwm_imx27_sw_reset(chip);
0ca1a11a1   Lukasz Majewski   pwm: imx: Provide...
266
  	}
166091b18   Sascha Hauer   [ARM] MXC: add pw...
267

bd88d319a   Thierry Reding   pwm: imx27: Uncon...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  	writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
  	writel(period_cycles, imx->mmio_base + MX3_PWMPR);
  
  	/*
  	 * Store the duty cycle for future reference in cases where the
  	 * MX3_PWMSAR register can't be read (i.e. when the PWM is disabled).
  	 */
  	imx->duty_cycle = duty_cycles;
  
  	cr = MX3_PWMCR_PRESCALER_SET(prescale) |
  	     MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN |
  	     FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) |
  	     MX3_PWMCR_DBGEN;
  
  	if (state->polarity == PWM_POLARITY_INVERSED)
  		cr |= FIELD_PREP(MX3_PWMCR_POUTC,
  				MX3_PWMCR_POUTC_INVERTED);
  
  	if (state->enabled)
  		cr |= MX3_PWMCR_EN;
  
  	writel(cr, imx->mmio_base + MX3_PWMCR);
15d4dbd60   Uwe Kleine-König   pwm: imx27: Fix c...
290
  	if (!state->enabled)
aad4e530c   Uwe Kleine-König   pwm: imx27: Simpl...
291
  		pwm_imx27_clk_disable_unprepare(imx);
bd88d319a   Thierry Reding   pwm: imx27: Uncon...
292

0ca1a11a1   Lukasz Majewski   pwm: imx: Provide...
293
  	return 0;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
294
  }
166091b18   Sascha Hauer   [ARM] MXC: add pw...
295

d80f82069   Uwe Kleine-König   pwm: imx: Split i...
296
297
298
  static const struct pwm_ops pwm_imx27_ops = {
  	.apply = pwm_imx27_apply,
  	.get_state = pwm_imx27_get_state,
29693248e   Sascha Hauer   ARM i.MX: Move i....
299
300
  	.owner = THIS_MODULE,
  };
166091b18   Sascha Hauer   [ARM] MXC: add pw...
301

d80f82069   Uwe Kleine-König   pwm: imx: Split i...
302
303
  static const struct of_device_id pwm_imx27_dt_ids[] = {
  	{ .compatible = "fsl,imx27-pwm", },
479e2e301   Philipp Zabel   pwm: i.MX: add de...
304
305
  	{ /* sentinel */ }
  };
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
306
  MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
479e2e301   Philipp Zabel   pwm: i.MX: add de...
307

d80f82069   Uwe Kleine-König   pwm: imx: Split i...
308
  static int pwm_imx27_probe(struct platform_device *pdev)
166091b18   Sascha Hauer   [ARM] MXC: add pw...
309
  {
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
310
  	struct pwm_imx27_chip *imx;
2cb5cd90f   Uwe Kleine-König   pwm: imx27: Ensur...
311
312
  	int ret;
  	u32 pwmcr;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
313

a9970e3be   Axel Lin   pwm: Convert pwm-...
314
  	imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
1cbec749b   Jingoo Han   pwm: i.MX: Remove...
315
  	if (imx == NULL)
166091b18   Sascha Hauer   [ARM] MXC: add pw...
316
  		return -ENOMEM;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
317

f20b187e3   Uwe Kleine-König   pwm: imx: Set dri...
318
  	platform_set_drvdata(pdev, imx);
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
319
320
  	imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
  	if (IS_ERR(imx->clk_ipg)) {
a368c3434   Anson Huang   pwm: imx27: Elimi...
321
322
323
324
325
326
327
328
  		int ret = PTR_ERR(imx->clk_ipg);
  
  		if (ret != -EPROBE_DEFER)
  			dev_err(&pdev->dev,
  				"getting ipg clock failed with %d
  ",
  				ret);
  		return ret;
9f4c8f960   Anson Huang   pwm: imx: Add ipg...
329
  	}
7b27c160c   Philipp Zabel   pwm: i.MX: fix cl...
330
331
  	imx->clk_per = devm_clk_get(&pdev->dev, "per");
  	if (IS_ERR(imx->clk_per)) {
b9a5c60bc   Uwe Kleine-König   pwm: imx: Don't p...
332
333
334
335
336
337
338
339
340
  		int ret = PTR_ERR(imx->clk_per);
  
  		if (ret != -EPROBE_DEFER)
  			dev_err(&pdev->dev,
  				"failed to get peripheral clock: %d
  ",
  				ret);
  
  		return ret;
7b27c160c   Philipp Zabel   pwm: i.MX: fix cl...
341
  	}
166091b18   Sascha Hauer   [ARM] MXC: add pw...
342

4cbdea0ba   Liu Ying   pwm: imx27: Use 3...
343
344
345
346
347
348
349
  	imx->clk_32k = devm_clk_get_optional(&pdev->dev, "32k");
  	if (IS_ERR(imx->clk_32k)) {
  		dev_err(&pdev->dev, "getting 32k clock failed with %ld
  ",
  				PTR_ERR(imx->clk_32k));
  		return PTR_ERR(imx->clk_32k);
  	}
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
350
  	imx->chip.ops = &pwm_imx27_ops;
29693248e   Sascha Hauer   ARM i.MX: Move i....
351
352
353
  	imx->chip.dev = &pdev->dev;
  	imx->chip.base = -1;
  	imx->chip.npwm = 1;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
354

d80f82069   Uwe Kleine-König   pwm: imx: Split i...
355
356
  	imx->chip.of_xlate = of_pwm_xlate_with_flags;
  	imx->chip.of_pwm_n_cells = 3;
326ed314f   Lukasz Majewski   pwm: imx: Add pol...
357

1347c94f7   Anson Huang   pwm: imx27: Use d...
358
  	imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
6d4294d16   Thierry Reding   pwm: Convert to d...
359
360
  	if (IS_ERR(imx->mmio_base))
  		return PTR_ERR(imx->mmio_base);
166091b18   Sascha Hauer   [ARM] MXC: add pw...
361

2cb5cd90f   Uwe Kleine-König   pwm: imx27: Ensur...
362
363
364
365
366
367
368
369
  	ret = pwm_imx27_clk_prepare_enable(imx);
  	if (ret)
  		return ret;
  
  	/* keep clks on if pwm is running */
  	pwmcr = readl(imx->mmio_base + MX3_PWMCR);
  	if (!(pwmcr & MX3_PWMCR_EN))
  		pwm_imx27_clk_disable_unprepare(imx);
f20b187e3   Uwe Kleine-König   pwm: imx: Set dri...
370
  	return pwmchip_add(&imx->chip);
166091b18   Sascha Hauer   [ARM] MXC: add pw...
371
  }
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
372
  static int pwm_imx27_remove(struct platform_device *pdev)
166091b18   Sascha Hauer   [ARM] MXC: add pw...
373
  {
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
374
  	struct pwm_imx27_chip *imx;
166091b18   Sascha Hauer   [ARM] MXC: add pw...
375

29693248e   Sascha Hauer   ARM i.MX: Move i....
376
  	imx = platform_get_drvdata(pdev);
166091b18   Sascha Hauer   [ARM] MXC: add pw...
377

a9970e3be   Axel Lin   pwm: Convert pwm-...
378
  	return pwmchip_remove(&imx->chip);
166091b18   Sascha Hauer   [ARM] MXC: add pw...
379
  }
29693248e   Sascha Hauer   ARM i.MX: Move i....
380
  static struct platform_driver imx_pwm_driver = {
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
381
382
383
  	.driver = {
  		.name = "pwm-imx27",
  		.of_match_table = pwm_imx27_dt_ids,
166091b18   Sascha Hauer   [ARM] MXC: add pw...
384
  	},
d80f82069   Uwe Kleine-König   pwm: imx: Split i...
385
386
  	.probe = pwm_imx27_probe,
  	.remove = pwm_imx27_remove,
166091b18   Sascha Hauer   [ARM] MXC: add pw...
387
  };
208d038f4   Sascha Hauer   pwm: i.MX: Use mo...
388
  module_platform_driver(imx_pwm_driver);
166091b18   Sascha Hauer   [ARM] MXC: add pw...
389
390
391
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");