aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAriel D'Alessandro <ariel@vanguardiasur.com.ar>2015-08-05 22:31:46 -0400
committerThierry Reding <thierry.reding@gmail.com>2015-09-09 09:00:33 -0400
commit841e6f90bb789a1372087b22c39f3a9ef2e02758 (patch)
treef1c95b80f47c307f4263aa79c9578a3ea449231e
parent01ec8472009c973413d4dc6fb198f0cc40abb9b4 (diff)
pwm: NXP LPC18xx PWM/SCT driver
This commit adds support for NXP LPC18xx PWM/SCT. NXP LPC SoCs family, which includes LPC18xx/LPC43xx, provides a State Configurable Timer (SCT) which can be configured as a Pulse Width Modulator. Other SoCs in that family may share the same hardware. The PWM supports a total of 16 channels, but only 15 can be simultaneously requested. There's only one period, global to all the channels, thus PWM driver will refuse setting different values to it, unless there's only one channel requested. Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> [thierry.reding@gmail.com: remove excessive padding of fields] Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
-rw-r--r--drivers/pwm/Kconfig12
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/pwm-lpc18xx-sct.c465
3 files changed, 478 insertions, 0 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index b1541f40fd8d..ac8b0e968b6b 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -173,6 +173,18 @@ config PWM_LP3943
173 To compile this driver as a module, choose M here: the module 173 To compile this driver as a module, choose M here: the module
174 will be called pwm-lp3943. 174 will be called pwm-lp3943.
175 175
176config PWM_LPC18XX_SCT
177 tristate "LPC18xx/43xx PWM/SCT support"
178 depends on ARCH_LPC18XX
179 help
180 Generic PWM framework driver for NXP LPC18xx PWM/SCT which
181 supports 16 channels.
182 A maximum of 15 channels can be requested simultaneously and
183 must have the same period.
184
185 To compile this driver as a module, choose M here: the module
186 will be called pwm-lpc18xx-sct.
187
176config PWM_LPC32XX 188config PWM_LPC32XX
177 tristate "LPC32XX PWM support" 189 tristate "LPC32XX PWM support"
178 depends on ARCH_LPC32XX 190 depends on ARCH_LPC32XX
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index ec50eb5b5a8f..cd9abef2d5b1 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_PWM_IMG) += pwm-img.o
14obj-$(CONFIG_PWM_IMX) += pwm-imx.o 14obj-$(CONFIG_PWM_IMX) += pwm-imx.o
15obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o 15obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
16obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o 16obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o
17obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o
17obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o 18obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
18obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o 19obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
19obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o 20obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
new file mode 100644
index 000000000000..9163085101bc
--- /dev/null
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -0,0 +1,465 @@
1/*
2 * NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver
3 *
4 * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License.
9 *
10 * Notes
11 * =====
12 * NXP LPC18xx provides a State Configurable Timer (SCT) which can be configured
13 * as a Pulse Width Modulator.
14 *
15 * SCT supports 16 outputs, 16 events and 16 registers. Each event will be
16 * triggered when its related register matches the SCT counter value, and it
17 * will set or clear a selected output.
18 *
19 * One of the events is preselected to generate the period, thus the maximum
20 * number of simultaneous channels is limited to 15. Notice that period is
21 * global to all the channels, thus PWM driver will refuse setting different
22 * values to it, unless there's only one channel requested.
23 */
24
25#include <linux/clk.h>
26#include <linux/err.h>
27#include <linux/io.h>
28#include <linux/module.h>
29#include <linux/platform_device.h>
30#include <linux/pwm.h>
31
32/* LPC18xx SCT registers */
33#define LPC18XX_PWM_CONFIG 0x000
34#define LPC18XX_PWM_CONFIG_UNIFY BIT(0)
35#define LPC18XX_PWM_CONFIG_NORELOAD BIT(7)
36
37#define LPC18XX_PWM_CTRL 0x004
38#define LPC18XX_PWM_CTRL_HALT BIT(2)
39#define LPC18XX_PWM_BIDIR BIT(4)
40#define LPC18XX_PWM_PRE_SHIFT 5
41#define LPC18XX_PWM_PRE_MASK (0xff << LPC18XX_PWM_PRE_SHIFT)
42#define LPC18XX_PWM_PRE(x) (x << LPC18XX_PWM_PRE_SHIFT)
43
44#define LPC18XX_PWM_LIMIT 0x008
45
46#define LPC18XX_PWM_RES_BASE 0x058
47#define LPC18XX_PWM_RES_SHIFT(_ch) (_ch * 2)
48#define LPC18XX_PWM_RES(_ch, _action) (_action << LPC18XX_PWM_RES_SHIFT(_ch))
49#define LPC18XX_PWM_RES_MASK(_ch) (0x3 << LPC18XX_PWM_RES_SHIFT(_ch))
50
51#define LPC18XX_PWM_MATCH_BASE 0x100
52#define LPC18XX_PWM_MATCH(_ch) (LPC18XX_PWM_MATCH_BASE + _ch * 4)
53
54#define LPC18XX_PWM_MATCHREL_BASE 0x200
55#define LPC18XX_PWM_MATCHREL(_ch) (LPC18XX_PWM_MATCHREL_BASE + _ch * 4)
56
57#define LPC18XX_PWM_EVSTATEMSK_BASE 0x300
58#define LPC18XX_PWM_EVSTATEMSK(_ch) (LPC18XX_PWM_EVSTATEMSK_BASE + _ch * 8)
59#define LPC18XX_PWM_EVSTATEMSK_ALL 0xffffffff
60
61#define LPC18XX_PWM_EVCTRL_BASE 0x304
62#define LPC18XX_PWM_EVCTRL(_ev) (LPC18XX_PWM_EVCTRL_BASE + _ev * 8)
63
64#define LPC18XX_PWM_EVCTRL_MATCH(_ch) _ch
65
66#define LPC18XX_PWM_EVCTRL_COMB_SHIFT 12
67#define LPC18XX_PWM_EVCTRL_COMB_MATCH (0x1 << LPC18XX_PWM_EVCTRL_COMB_SHIFT)
68
69#define LPC18XX_PWM_OUTPUTSET_BASE 0x500
70#define LPC18XX_PWM_OUTPUTSET(_ch) (LPC18XX_PWM_OUTPUTSET_BASE + _ch * 8)
71
72#define LPC18XX_PWM_OUTPUTCL_BASE 0x504
73#define LPC18XX_PWM_OUTPUTCL(_ch) (LPC18XX_PWM_OUTPUTCL_BASE + _ch * 8)
74
75/* LPC18xx SCT unified counter */
76#define LPC18XX_PWM_TIMER_MAX 0xffffffff
77
78/* LPC18xx SCT events */
79#define LPC18XX_PWM_EVENT_PERIOD 0
80#define LPC18XX_PWM_EVENT_MAX 16
81
82/* SCT conflict resolution */
83enum lpc18xx_pwm_res_action {
84 LPC18XX_PWM_RES_NONE,
85 LPC18XX_PWM_RES_SET,
86 LPC18XX_PWM_RES_CLEAR,
87 LPC18XX_PWM_RES_TOGGLE,
88};
89
90struct lpc18xx_pwm_data {
91 unsigned int duty_event;
92};
93
94struct lpc18xx_pwm_chip {
95 struct device *dev;
96 struct pwm_chip chip;
97 void __iomem *base;
98 struct clk *pwm_clk;
99 unsigned long clk_rate;
100 unsigned int period_ns;
101 unsigned int min_period_ns;
102 unsigned int max_period_ns;
103 unsigned int period_event;
104 unsigned long event_map;
105 struct mutex res_lock;
106 struct mutex period_lock;
107};
108
109static inline struct lpc18xx_pwm_chip *
110to_lpc18xx_pwm_chip(struct pwm_chip *chip)
111{
112 return container_of(chip, struct lpc18xx_pwm_chip, chip);
113}
114
115static inline void lpc18xx_pwm_writel(struct lpc18xx_pwm_chip *lpc18xx_pwm,
116 u32 reg, u32 val)
117{
118 writel(val, lpc18xx_pwm->base + reg);
119}
120
121static inline u32 lpc18xx_pwm_readl(struct lpc18xx_pwm_chip *lpc18xx_pwm,
122 u32 reg)
123{
124 return readl(lpc18xx_pwm->base + reg);
125}
126
127static void lpc18xx_pwm_set_conflict_res(struct lpc18xx_pwm_chip *lpc18xx_pwm,
128 struct pwm_device *pwm,
129 enum lpc18xx_pwm_res_action action)
130{
131 u32 val;
132
133 mutex_lock(&lpc18xx_pwm->res_lock);
134
135 /*
136 * Simultaneous set and clear may happen on an output, that is the case
137 * when duty_ns == period_ns. LPC18xx SCT allows to set a conflict
138 * resolution action to be taken in such a case.
139 */
140 val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_RES_BASE);
141 val &= ~LPC18XX_PWM_RES_MASK(pwm->hwpwm);
142 val |= LPC18XX_PWM_RES(pwm->hwpwm, action);
143 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_RES_BASE, val);
144
145 mutex_unlock(&lpc18xx_pwm->res_lock);
146}
147
148static void lpc18xx_pwm_config_period(struct pwm_chip *chip, int period_ns)
149{
150 struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
151 u64 val;
152
153 val = (u64)period_ns * lpc18xx_pwm->clk_rate;
154 do_div(val, NSEC_PER_SEC);
155
156 lpc18xx_pwm_writel(lpc18xx_pwm,
157 LPC18XX_PWM_MATCH(lpc18xx_pwm->period_event),
158 (u32)val - 1);
159
160 lpc18xx_pwm_writel(lpc18xx_pwm,
161 LPC18XX_PWM_MATCHREL(lpc18xx_pwm->period_event),
162 (u32)val - 1);
163}
164
165static void lpc18xx_pwm_config_duty(struct pwm_chip *chip,
166 struct pwm_device *pwm, int duty_ns)
167{
168 struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
169 struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
170 u64 val;
171
172 val = (u64)duty_ns * lpc18xx_pwm->clk_rate;
173 do_div(val, NSEC_PER_SEC);
174
175 lpc18xx_pwm_writel(lpc18xx_pwm,
176 LPC18XX_PWM_MATCH(lpc18xx_data->duty_event),
177 (u32)val);
178
179 lpc18xx_pwm_writel(lpc18xx_pwm,
180 LPC18XX_PWM_MATCHREL(lpc18xx_data->duty_event),
181 (u32)val);
182}
183
184static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
185 int duty_ns, int period_ns)
186{
187 struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
188 int requested_events, i;
189
190 if (period_ns < lpc18xx_pwm->min_period_ns ||
191 period_ns > lpc18xx_pwm->max_period_ns) {
192 dev_err(chip->dev, "period %d not in range\n", period_ns);
193 return -ERANGE;
194 }
195
196 mutex_lock(&lpc18xx_pwm->period_lock);
197
198 requested_events = bitmap_weight(&lpc18xx_pwm->event_map,
199 LPC18XX_PWM_EVENT_MAX);
200
201 /*
202 * The PWM supports only a single period for all PWM channels.
203 * Once the period is set, it can only be changed if no more than one
204 * channel is requested at that moment.
205 */
206 if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns &&
207 lpc18xx_pwm->period_ns) {
208 dev_err(chip->dev, "conflicting period requested for PWM %u\n",
209 pwm->hwpwm);
210 mutex_unlock(&lpc18xx_pwm->period_lock);
211 return -EBUSY;
212 }
213
214 if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) ||
215 !lpc18xx_pwm->period_ns) {
216 lpc18xx_pwm->period_ns = period_ns;
217 for (i = 0; i < chip->npwm; i++)
218 pwm_set_period(&chip->pwms[i], period_ns);
219 lpc18xx_pwm_config_period(chip, period_ns);
220 }
221
222 mutex_unlock(&lpc18xx_pwm->period_lock);
223
224 lpc18xx_pwm_config_duty(chip, pwm, duty_ns);
225
226 return 0;
227}
228
229static int lpc18xx_pwm_set_polarity(struct pwm_chip *chip,
230 struct pwm_device *pwm,
231 enum pwm_polarity polarity)
232{
233 return 0;
234}
235
236static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
237{
238 struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
239 struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
240 enum lpc18xx_pwm_res_action res_action;
241 unsigned int set_event, clear_event;
242
243 lpc18xx_pwm_writel(lpc18xx_pwm,
244 LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event),
245 LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_data->duty_event) |
246 LPC18XX_PWM_EVCTRL_COMB_MATCH);
247
248 lpc18xx_pwm_writel(lpc18xx_pwm,
249 LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event),
250 LPC18XX_PWM_EVSTATEMSK_ALL);
251
252 if (pwm->polarity == PWM_POLARITY_NORMAL) {
253 set_event = lpc18xx_pwm->period_event;
254 clear_event = lpc18xx_data->duty_event;
255 res_action = LPC18XX_PWM_RES_SET;
256 } else {
257 set_event = lpc18xx_data->duty_event;
258 clear_event = lpc18xx_pwm->period_event;
259 res_action = LPC18XX_PWM_RES_CLEAR;
260 }
261
262 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm),
263 BIT(set_event));
264 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm),
265 BIT(clear_event));
266 lpc18xx_pwm_set_conflict_res(lpc18xx_pwm, pwm, res_action);
267
268 return 0;
269}
270
271static void lpc18xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
272{
273 struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
274 struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
275
276 lpc18xx_pwm_writel(lpc18xx_pwm,
277 LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), 0);
278 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), 0);
279 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), 0);
280}
281
282static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
283{
284 struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
285 struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
286 unsigned long event;
287
288 event = find_first_zero_bit(&lpc18xx_pwm->event_map,
289 LPC18XX_PWM_EVENT_MAX);
290
291 if (event >= LPC18XX_PWM_EVENT_MAX) {
292 dev_err(lpc18xx_pwm->dev,
293 "maximum number of simultaneous channels reached\n");
294 return -EBUSY;
295 };
296
297 set_bit(event, &lpc18xx_pwm->event_map);
298 lpc18xx_data->duty_event = event;
299 lpc18xx_pwm_config_duty(chip, pwm, pwm_get_duty_cycle(pwm));
300
301 return 0;
302}
303
304static void lpc18xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
305{
306 struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
307 struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm);
308
309 pwm_disable(pwm);
310 pwm_set_duty_cycle(pwm, 0);
311 clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map);
312}
313
314static const struct pwm_ops lpc18xx_pwm_ops = {
315 .config = lpc18xx_pwm_config,
316 .set_polarity = lpc18xx_pwm_set_polarity,
317 .enable = lpc18xx_pwm_enable,
318 .disable = lpc18xx_pwm_disable,
319 .request = lpc18xx_pwm_request,
320 .free = lpc18xx_pwm_free,
321 .owner = THIS_MODULE,
322};
323
324static const struct of_device_id lpc18xx_pwm_of_match[] = {
325 { .compatible = "nxp,lpc1850-sct-pwm" },
326 {}
327};
328MODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match);
329
330static int lpc18xx_pwm_probe(struct platform_device *pdev)
331{
332 struct lpc18xx_pwm_chip *lpc18xx_pwm;
333 struct pwm_device *pwm;
334 struct resource *res;
335 int ret, i;
336 u64 val;
337
338 lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm),
339 GFP_KERNEL);
340 if (!lpc18xx_pwm)
341 return -ENOMEM;
342
343 lpc18xx_pwm->dev = &pdev->dev;
344
345 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
346 lpc18xx_pwm->base = devm_ioremap_resource(&pdev->dev, res);
347 if (IS_ERR(lpc18xx_pwm->base))
348 return PTR_ERR(lpc18xx_pwm->base);
349
350 lpc18xx_pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm");
351 if (IS_ERR(lpc18xx_pwm->pwm_clk)) {
352 dev_err(&pdev->dev, "failed to get pwm clock\n");
353 return PTR_ERR(lpc18xx_pwm->pwm_clk);
354 }
355
356 ret = clk_prepare_enable(lpc18xx_pwm->pwm_clk);
357 if (ret < 0) {
358 dev_err(&pdev->dev, "could not prepare or enable pwm clock\n");
359 return ret;
360 }
361
362 lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk);
363
364 mutex_init(&lpc18xx_pwm->res_lock);
365 mutex_init(&lpc18xx_pwm->period_lock);
366
367 val = (u64)NSEC_PER_SEC * LPC18XX_PWM_TIMER_MAX;
368 do_div(val, lpc18xx_pwm->clk_rate);
369 lpc18xx_pwm->max_period_ns = val;
370
371 lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC,
372 lpc18xx_pwm->clk_rate);
373
374 lpc18xx_pwm->chip.dev = &pdev->dev;
375 lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
376 lpc18xx_pwm->chip.base = -1;
377 lpc18xx_pwm->chip.npwm = 16;
378 lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
379 lpc18xx_pwm->chip.of_pwm_n_cells = 3;
380
381 /* SCT counter must be in unify (32 bit) mode */
382 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
383 LPC18XX_PWM_CONFIG_UNIFY);
384
385 /*
386 * Everytime the timer counter reaches the period value, the related
387 * event will be triggered and the counter reset to 0.
388 */
389 set_bit(LPC18XX_PWM_EVENT_PERIOD, &lpc18xx_pwm->event_map);
390 lpc18xx_pwm->period_event = LPC18XX_PWM_EVENT_PERIOD;
391
392 lpc18xx_pwm_writel(lpc18xx_pwm,
393 LPC18XX_PWM_EVSTATEMSK(lpc18xx_pwm->period_event),
394 LPC18XX_PWM_EVSTATEMSK_ALL);
395
396 val = LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_pwm->period_event) |
397 LPC18XX_PWM_EVCTRL_COMB_MATCH;
398 lpc18xx_pwm_writel(lpc18xx_pwm,
399 LPC18XX_PWM_EVCTRL(lpc18xx_pwm->period_event), val);
400
401 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT,
402 BIT(lpc18xx_pwm->period_event));
403
404 ret = pwmchip_add(&lpc18xx_pwm->chip);
405 if (ret < 0) {
406 dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
407 goto disable_pwmclk;
408 }
409
410 for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) {
411 pwm = &lpc18xx_pwm->chip.pwms[i];
412 pwm->chip_data = devm_kzalloc(lpc18xx_pwm->dev,
413 sizeof(struct lpc18xx_pwm_data),
414 GFP_KERNEL);
415 if (!pwm->chip_data) {
416 ret = -ENOMEM;
417 goto remove_pwmchip;
418 }
419 }
420
421 platform_set_drvdata(pdev, lpc18xx_pwm);
422
423 val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
424 val &= ~LPC18XX_PWM_BIDIR;
425 val &= ~LPC18XX_PWM_CTRL_HALT;
426 val &= ~LPC18XX_PWM_PRE_MASK;
427 val |= LPC18XX_PWM_PRE(0);
428 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val);
429
430 return 0;
431
432remove_pwmchip:
433 pwmchip_remove(&lpc18xx_pwm->chip);
434disable_pwmclk:
435 clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
436 return ret;
437}
438
439static int lpc18xx_pwm_remove(struct platform_device *pdev)
440{
441 struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
442 u32 val;
443
444 val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
445 lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL,
446 val | LPC18XX_PWM_CTRL_HALT);
447
448 clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
449
450 return pwmchip_remove(&lpc18xx_pwm->chip);
451}
452
453static struct platform_driver lpc18xx_pwm_driver = {
454 .driver = {
455 .name = "lpc18xx-sct-pwm",
456 .of_match_table = lpc18xx_pwm_of_match,
457 },
458 .probe = lpc18xx_pwm_probe,
459 .remove = lpc18xx_pwm_remove,
460};
461module_platform_driver(lpc18xx_pwm_driver);
462
463MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>");
464MODULE_DESCRIPTION("NXP LPC18xx PWM driver");
465MODULE_LICENSE("GPL v2");