Blame view

drivers/pwm/pwm-rockchip.c 9.87 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
101353c82   Beniamino Galvani   pwm: add Rockchip...
2
3
4
5
  /*
   * PWM driver for Rockchip SoCs
   *
   * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
f63062990   Caesar Wang   pwm: rockchip: Ad...
6
   * Copyright (C) 2014 ROCKCHIP, Inc.
101353c82   Beniamino Galvani   pwm: add Rockchip...
7
8
9
10
11
12
   */
  
  #include <linux/clk.h>
  #include <linux/io.h>
  #include <linux/module.h>
  #include <linux/of.h>
f63062990   Caesar Wang   pwm: rockchip: Ad...
13
  #include <linux/of_device.h>
101353c82   Beniamino Galvani   pwm: add Rockchip...
14
15
16
  #include <linux/platform_device.h>
  #include <linux/pwm.h>
  #include <linux/time.h>
101353c82   Beniamino Galvani   pwm: add Rockchip...
17
18
  #define PWM_CTRL_TIMER_EN	(1 << 0)
  #define PWM_CTRL_OUTPUT_EN	(1 << 3)
f63062990   Caesar Wang   pwm: rockchip: Ad...
19
20
21
  #define PWM_ENABLE		(1 << 0)
  #define PWM_CONTINUOUS		(1 << 1)
  #define PWM_DUTY_POSITIVE	(1 << 3)
7264354c0   Doug Anderson   pwm: rockchip: Al...
22
  #define PWM_DUTY_NEGATIVE	(0 << 3)
f63062990   Caesar Wang   pwm: rockchip: Ad...
23
  #define PWM_INACTIVE_NEGATIVE	(0 << 4)
7264354c0   Doug Anderson   pwm: rockchip: Al...
24
  #define PWM_INACTIVE_POSITIVE	(1 << 4)
bc834d7b0   David Wu   pwm: rockchip: Mo...
25
  #define PWM_POLARITY_MASK	(PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE)
f63062990   Caesar Wang   pwm: rockchip: Ad...
26
  #define PWM_OUTPUT_LEFT		(0 << 5)
3f9a36313   David Wu   pwm: rockchip: Ad...
27
  #define PWM_LOCK_EN		(1 << 6)
f63062990   Caesar Wang   pwm: rockchip: Ad...
28
  #define PWM_LP_DISABLE		(0 << 8)
101353c82   Beniamino Galvani   pwm: add Rockchip...
29
30
31
32
  
  struct rockchip_pwm_chip {
  	struct pwm_chip chip;
  	struct clk *clk;
27922ff59   David Wu   pwm: rockchip: Ad...
33
  	struct clk *pclk;
f63062990   Caesar Wang   pwm: rockchip: Ad...
34
  	const struct rockchip_pwm_data *data;
101353c82   Beniamino Galvani   pwm: add Rockchip...
35
36
  	void __iomem *base;
  };
f63062990   Caesar Wang   pwm: rockchip: Ad...
37
38
39
40
41
42
43
44
45
46
  struct rockchip_pwm_regs {
  	unsigned long duty;
  	unsigned long period;
  	unsigned long cntr;
  	unsigned long ctrl;
  };
  
  struct rockchip_pwm_data {
  	struct rockchip_pwm_regs regs;
  	unsigned int prescaler;
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
47
  	bool supports_polarity;
3f9a36313   David Wu   pwm: rockchip: Ad...
48
  	bool supports_lock;
831b27905   David Wu   pwm: rockchip: Us...
49
  	u32 enable_conf;
f63062990   Caesar Wang   pwm: rockchip: Ad...
50
  };
101353c82   Beniamino Galvani   pwm: add Rockchip...
51
52
53
54
  static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
  {
  	return container_of(c, struct rockchip_pwm_chip, chip);
  }
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
55
56
57
58
59
  static void rockchip_pwm_get_state(struct pwm_chip *chip,
  				   struct pwm_device *pwm,
  				   struct pwm_state *state)
  {
  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
831b27905   David Wu   pwm: rockchip: Us...
60
  	u32 enable_conf = pc->data->enable_conf;
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
61
62
  	unsigned long clk_rate;
  	u64 tmp;
831b27905   David Wu   pwm: rockchip: Us...
63
  	u32 val;
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
64
  	int ret;
27922ff59   David Wu   pwm: rockchip: Ad...
65
  	ret = clk_enable(pc->pclk);
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
66
67
68
69
70
71
72
73
74
75
76
  	if (ret)
  		return;
  
  	clk_rate = clk_get_rate(pc->clk);
  
  	tmp = readl_relaxed(pc->base + pc->data->regs.period);
  	tmp *= pc->data->prescaler * NSEC_PER_SEC;
  	state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
  
  	tmp = readl_relaxed(pc->base + pc->data->regs.duty);
  	tmp *= pc->data->prescaler * NSEC_PER_SEC;
831b27905   David Wu   pwm: rockchip: Us...
77
  	state->duty_cycle =  DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
78

831b27905   David Wu   pwm: rockchip: Us...
79
  	val = readl_relaxed(pc->base + pc->data->regs.ctrl);
cad0f2960   Rasmus Villemoes   pwm: rockchip: Si...
80
  	state->enabled = (val & enable_conf) == enable_conf;
831b27905   David Wu   pwm: rockchip: Us...
81

ba73deb16   Uwe Kleine-König   pwm: rockchip: Se...
82
83
84
85
  	if (pc->data->supports_polarity && !(val & PWM_DUTY_POSITIVE))
  		state->polarity = PWM_POLARITY_INVERSED;
  	else
  		state->polarity = PWM_POLARITY_NORMAL;
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
86

27922ff59   David Wu   pwm: rockchip: Ad...
87
  	clk_disable(pc->pclk);
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
88
  }
f90df9cda   David Wu   pwm: rockchip: Re...
89
  static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
71523d181   Uwe Kleine-König   pwm: Ensure pwm_a...
90
  			       const struct pwm_state *state)
101353c82   Beniamino Galvani   pwm: add Rockchip...
91
92
93
94
  {
  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
  	unsigned long period, duty;
  	u64 clk_rate, div;
bc834d7b0   David Wu   pwm: rockchip: Mo...
95
  	u32 ctrl;
101353c82   Beniamino Galvani   pwm: add Rockchip...
96
97
98
99
100
101
102
103
  
  	clk_rate = clk_get_rate(pc->clk);
  
  	/*
  	 * Since period and duty cycle registers have a width of 32
  	 * bits, every possible input period can be obtained using the
  	 * default prescaler value for all practical clock rate values.
  	 */
bc834d7b0   David Wu   pwm: rockchip: Mo...
104
  	div = clk_rate * state->period;
12f9ce4a5   Boris Brezillon   pwm: rockchip: Fi...
105
106
  	period = DIV_ROUND_CLOSEST_ULL(div,
  				       pc->data->prescaler * NSEC_PER_SEC);
101353c82   Beniamino Galvani   pwm: add Rockchip...
107

bc834d7b0   David Wu   pwm: rockchip: Mo...
108
  	div = clk_rate * state->duty_cycle;
12f9ce4a5   Boris Brezillon   pwm: rockchip: Fi...
109
  	duty = DIV_ROUND_CLOSEST_ULL(div, pc->data->prescaler * NSEC_PER_SEC);
101353c82   Beniamino Galvani   pwm: add Rockchip...
110

3f9a36313   David Wu   pwm: rockchip: Ad...
111
112
113
114
115
116
117
118
119
  	/*
  	 * Lock the period and duty of previous configuration, then
  	 * change the duty and period, that would not be effective.
  	 */
  	ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
  	if (pc->data->supports_lock) {
  		ctrl |= PWM_LOCK_EN;
  		writel_relaxed(ctrl, pc->base + pc->data->regs.ctrl);
  	}
f63062990   Caesar Wang   pwm: rockchip: Ad...
120
121
  	writel(period, pc->base + pc->data->regs.period);
  	writel(duty, pc->base + pc->data->regs.duty);
bc834d7b0   David Wu   pwm: rockchip: Mo...
122

bc834d7b0   David Wu   pwm: rockchip: Mo...
123
124
125
126
127
128
129
  	if (pc->data->supports_polarity) {
  		ctrl &= ~PWM_POLARITY_MASK;
  		if (state->polarity == PWM_POLARITY_INVERSED)
  			ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
  		else
  			ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
  	}
3f9a36313   David Wu   pwm: rockchip: Ad...
130
131
132
133
134
135
136
137
  
  	/*
  	 * Unlock and set polarity at the same time,
  	 * the configuration of duty, period and polarity
  	 * would be effective together at next period.
  	 */
  	if (pc->data->supports_lock)
  		ctrl &= ~PWM_LOCK_EN;
bc834d7b0   David Wu   pwm: rockchip: Mo...
138
  	writel(ctrl, pc->base + pc->data->regs.ctrl);
7264354c0   Doug Anderson   pwm: rockchip: Al...
139
  }
a900152b5   David Wu   pwm: rockchip: St...
140
  static int rockchip_pwm_enable(struct pwm_chip *chip,
bc834d7b0   David Wu   pwm: rockchip: Mo...
141
  			       struct pwm_device *pwm,
831b27905   David Wu   pwm: rockchip: Us...
142
  			       bool enable)
a900152b5   David Wu   pwm: rockchip: St...
143
144
  {
  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
831b27905   David Wu   pwm: rockchip: Us...
145
  	u32 enable_conf = pc->data->enable_conf;
a900152b5   David Wu   pwm: rockchip: St...
146
  	int ret;
ed054693d   David Wu   pwm: rockchip: Us...
147
  	u32 val;
a900152b5   David Wu   pwm: rockchip: St...
148
149
150
151
152
153
  
  	if (enable) {
  		ret = clk_enable(pc->clk);
  		if (ret)
  			return ret;
  	}
ed054693d   David Wu   pwm: rockchip: Us...
154
155
156
157
158
159
160
161
  	val = readl_relaxed(pc->base + pc->data->regs.ctrl);
  
  	if (enable)
  		val |= enable_conf;
  	else
  		val &= ~enable_conf;
  
  	writel_relaxed(val, pc->base + pc->data->regs.ctrl);
a900152b5   David Wu   pwm: rockchip: St...
162
163
164
165
166
167
  
  	if (!enable)
  		clk_disable(pc->clk);
  
  	return 0;
  }
831b27905   David Wu   pwm: rockchip: Us...
168
  static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
71523d181   Uwe Kleine-König   pwm: Ensure pwm_a...
169
  			      const struct pwm_state *state)
101353c82   Beniamino Galvani   pwm: add Rockchip...
170
  {
831b27905   David Wu   pwm: rockchip: Us...
171
  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
172
173
  	struct pwm_state curstate;
  	bool enabled;
ed054693d   David Wu   pwm: rockchip: Us...
174
  	int ret = 0;
101353c82   Beniamino Galvani   pwm: add Rockchip...
175

831b27905   David Wu   pwm: rockchip: Us...
176
177
178
  	ret = clk_enable(pc->pclk);
  	if (ret)
  		return ret;
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
179
180
  	pwm_get_state(pwm, &curstate);
  	enabled = curstate.enabled;
3f9a36313   David Wu   pwm: rockchip: Ad...
181
182
  	if (state->polarity != curstate.polarity && enabled &&
  	    !pc->data->supports_lock) {
831b27905   David Wu   pwm: rockchip: Us...
183
  		ret = rockchip_pwm_enable(chip, pwm, false);
a900152b5   David Wu   pwm: rockchip: St...
184
  		if (ret)
831b27905   David Wu   pwm: rockchip: Us...
185
  			goto out;
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
186
187
  		enabled = false;
  	}
101353c82   Beniamino Galvani   pwm: add Rockchip...
188

bc834d7b0   David Wu   pwm: rockchip: Mo...
189
  	rockchip_pwm_config(chip, pwm, state);
831b27905   David Wu   pwm: rockchip: Us...
190
191
  	if (state->enabled != enabled) {
  		ret = rockchip_pwm_enable(chip, pwm, state->enabled);
a900152b5   David Wu   pwm: rockchip: St...
192
  		if (ret)
831b27905   David Wu   pwm: rockchip: Us...
193
  			goto out;
a900152b5   David Wu   pwm: rockchip: St...
194
  	}
101353c82   Beniamino Galvani   pwm: add Rockchip...
195

2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
196
  out:
27922ff59   David Wu   pwm: rockchip: Ad...
197
  	clk_disable(pc->pclk);
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
198
199
  
  	return ret;
101353c82   Beniamino Galvani   pwm: add Rockchip...
200
  }
831b27905   David Wu   pwm: rockchip: Us...
201
  static const struct pwm_ops rockchip_pwm_ops = {
1ebb74cf3   Boris Brezillon   pwm: rockchip: Ad...
202
  	.get_state = rockchip_pwm_get_state,
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
203
  	.apply = rockchip_pwm_apply,
7264354c0   Doug Anderson   pwm: rockchip: Al...
204
205
  	.owner = THIS_MODULE,
  };
f63062990   Caesar Wang   pwm: rockchip: Ad...
206
207
208
209
210
211
212
213
  static const struct rockchip_pwm_data pwm_data_v1 = {
  	.regs = {
  		.duty = 0x04,
  		.period = 0x08,
  		.cntr = 0x00,
  		.ctrl = 0x0c,
  	},
  	.prescaler = 2,
831b27905   David Wu   pwm: rockchip: Us...
214
  	.supports_polarity = false,
3f9a36313   David Wu   pwm: rockchip: Ad...
215
  	.supports_lock = false,
831b27905   David Wu   pwm: rockchip: Us...
216
  	.enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
f63062990   Caesar Wang   pwm: rockchip: Ad...
217
218
219
220
221
222
223
224
225
226
  };
  
  static const struct rockchip_pwm_data pwm_data_v2 = {
  	.regs = {
  		.duty = 0x08,
  		.period = 0x04,
  		.cntr = 0x00,
  		.ctrl = 0x0c,
  	},
  	.prescaler = 1,
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
227
  	.supports_polarity = true,
3f9a36313   David Wu   pwm: rockchip: Ad...
228
  	.supports_lock = false,
831b27905   David Wu   pwm: rockchip: Us...
229
230
  	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
  		       PWM_CONTINUOUS,
f63062990   Caesar Wang   pwm: rockchip: Ad...
231
232
233
234
235
236
237
238
239
240
  };
  
  static const struct rockchip_pwm_data pwm_data_vop = {
  	.regs = {
  		.duty = 0x08,
  		.period = 0x04,
  		.cntr = 0x0c,
  		.ctrl = 0x00,
  	},
  	.prescaler = 1,
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
241
  	.supports_polarity = true,
3f9a36313   David Wu   pwm: rockchip: Ad...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  	.supports_lock = false,
  	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
  		       PWM_CONTINUOUS,
  };
  
  static const struct rockchip_pwm_data pwm_data_v3 = {
  	.regs = {
  		.duty = 0x08,
  		.period = 0x04,
  		.cntr = 0x00,
  		.ctrl = 0x0c,
  	},
  	.prescaler = 1,
  	.supports_polarity = true,
  	.supports_lock = true,
831b27905   David Wu   pwm: rockchip: Us...
257
258
  	.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
  		       PWM_CONTINUOUS,
f63062990   Caesar Wang   pwm: rockchip: Ad...
259
260
261
262
263
264
  };
  
  static const struct of_device_id rockchip_pwm_dt_ids[] = {
  	{ .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
  	{ .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
  	{ .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
3f9a36313   David Wu   pwm: rockchip: Ad...
265
  	{ .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3},
f63062990   Caesar Wang   pwm: rockchip: Ad...
266
267
268
  	{ /* sentinel */ }
  };
  MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
101353c82   Beniamino Galvani   pwm: add Rockchip...
269
270
  static int rockchip_pwm_probe(struct platform_device *pdev)
  {
f63062990   Caesar Wang   pwm: rockchip: Ad...
271
  	const struct of_device_id *id;
101353c82   Beniamino Galvani   pwm: add Rockchip...
272
273
  	struct rockchip_pwm_chip *pc;
  	struct resource *r;
457f74abb   Simon South   pwm: rockchip: Ke...
274
  	u32 enable_conf, ctrl;
27922ff59   David Wu   pwm: rockchip: Ad...
275
  	int ret, count;
101353c82   Beniamino Galvani   pwm: add Rockchip...
276

f63062990   Caesar Wang   pwm: rockchip: Ad...
277
278
279
  	id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
  	if (!id)
  		return -EINVAL;
101353c82   Beniamino Galvani   pwm: add Rockchip...
280
281
282
283
284
285
286
287
  	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
  	if (!pc)
  		return -ENOMEM;
  
  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	pc->base = devm_ioremap_resource(&pdev->dev, r);
  	if (IS_ERR(pc->base))
  		return PTR_ERR(pc->base);
27922ff59   David Wu   pwm: rockchip: Ad...
288
289
290
  	pc->clk = devm_clk_get(&pdev->dev, "pwm");
  	if (IS_ERR(pc->clk)) {
  		pc->clk = devm_clk_get(&pdev->dev, NULL);
836719f89   Krzysztof Kozlowski   pwm: rockchip: Si...
291
292
293
294
  		if (IS_ERR(pc->clk))
  			return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
  					     "Can't get bus clk
  ");
27922ff59   David Wu   pwm: rockchip: Ad...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  	}
  
  	count = of_count_phandle_with_args(pdev->dev.of_node,
  					   "clocks", "#clock-cells");
  	if (count == 2)
  		pc->pclk = devm_clk_get(&pdev->dev, "pclk");
  	else
  		pc->pclk = pc->clk;
  
  	if (IS_ERR(pc->pclk)) {
  		ret = PTR_ERR(pc->pclk);
  		if (ret != -EPROBE_DEFER)
  			dev_err(&pdev->dev, "Can't get APB clk: %d
  ", ret);
  		return ret;
  	}
101353c82   Beniamino Galvani   pwm: add Rockchip...
311

48cf973ca   Boris Brezillon   pwm: rockchip: Av...
312
  	ret = clk_prepare_enable(pc->clk);
27922ff59   David Wu   pwm: rockchip: Ad...
313
314
315
  	if (ret) {
  		dev_err(&pdev->dev, "Can't prepare enable bus clk: %d
  ", ret);
101353c82   Beniamino Galvani   pwm: add Rockchip...
316
  		return ret;
27922ff59   David Wu   pwm: rockchip: Ad...
317
318
319
320
321
322
323
324
  	}
  
  	ret = clk_prepare(pc->pclk);
  	if (ret) {
  		dev_err(&pdev->dev, "Can't prepare APB clk: %d
  ", ret);
  		goto err_clk;
  	}
101353c82   Beniamino Galvani   pwm: add Rockchip...
325
326
  
  	platform_set_drvdata(pdev, pc);
f63062990   Caesar Wang   pwm: rockchip: Ad...
327
  	pc->data = id->data;
101353c82   Beniamino Galvani   pwm: add Rockchip...
328
  	pc->chip.dev = &pdev->dev;
831b27905   David Wu   pwm: rockchip: Us...
329
  	pc->chip.ops = &rockchip_pwm_ops;
101353c82   Beniamino Galvani   pwm: add Rockchip...
330
331
  	pc->chip.base = -1;
  	pc->chip.npwm = 1;
2bf1c98aa   Boris Brezillon   pwm: rockchip: Ad...
332
  	if (pc->data->supports_polarity) {
7264354c0   Doug Anderson   pwm: rockchip: Al...
333
334
335
  		pc->chip.of_xlate = of_pwm_xlate_with_flags;
  		pc->chip.of_pwm_n_cells = 3;
  	}
101353c82   Beniamino Galvani   pwm: add Rockchip...
336
337
338
339
340
  	ret = pwmchip_add(&pc->chip);
  	if (ret < 0) {
  		clk_unprepare(pc->clk);
  		dev_err(&pdev->dev, "pwmchip_add() failed: %d
  ", ret);
27922ff59   David Wu   pwm: rockchip: Ad...
341
  		goto err_pclk;
101353c82   Beniamino Galvani   pwm: add Rockchip...
342
  	}
48cf973ca   Boris Brezillon   pwm: rockchip: Av...
343
  	/* Keep the PWM clk enabled if the PWM appears to be up and running. */
457f74abb   Simon South   pwm: rockchip: Ke...
344
345
346
  	enable_conf = pc->data->enable_conf;
  	ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
  	if ((ctrl & enable_conf) != enable_conf)
48cf973ca   Boris Brezillon   pwm: rockchip: Av...
347
  		clk_disable(pc->clk);
27922ff59   David Wu   pwm: rockchip: Ad...
348
349
350
351
352
353
  	return 0;
  
  err_pclk:
  	clk_unprepare(pc->pclk);
  err_clk:
  	clk_disable_unprepare(pc->clk);
101353c82   Beniamino Galvani   pwm: add Rockchip...
354
355
356
357
358
359
  	return ret;
  }
  
  static int rockchip_pwm_remove(struct platform_device *pdev)
  {
  	struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
48cf973ca   Boris Brezillon   pwm: rockchip: Av...
360
361
362
363
364
365
366
367
368
369
370
371
372
  	/*
  	 * Disable the PWM clk before unpreparing it if the PWM device is still
  	 * running. This should only happen when the last PWM user left it
  	 * enabled, or when nobody requested a PWM that was previously enabled
  	 * by the bootloader.
  	 *
  	 * FIXME: Maybe the core should disable all PWM devices in
  	 * pwmchip_remove(). In this case we'd only have to call
  	 * clk_unprepare() after pwmchip_remove().
  	 *
  	 */
  	if (pwm_is_enabled(pc->chip.pwms))
  		clk_disable(pc->clk);
27922ff59   David Wu   pwm: rockchip: Ad...
373
  	clk_unprepare(pc->pclk);
101353c82   Beniamino Galvani   pwm: add Rockchip...
374
375
376
377
  	clk_unprepare(pc->clk);
  
  	return pwmchip_remove(&pc->chip);
  }
101353c82   Beniamino Galvani   pwm: add Rockchip...
378
379
380
381
382
383
384
385
386
387
388
389
390
  static struct platform_driver rockchip_pwm_driver = {
  	.driver = {
  		.name = "rockchip-pwm",
  		.of_match_table = rockchip_pwm_dt_ids,
  	},
  	.probe = rockchip_pwm_probe,
  	.remove = rockchip_pwm_remove,
  };
  module_platform_driver(rockchip_pwm_driver);
  
  MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
  MODULE_DESCRIPTION("Rockchip SoC PWM driver");
  MODULE_LICENSE("GPL v2");