xref: /openbmc/linux/drivers/pwm/pwm-lpc18xx-sct.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
184a14ae8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2841e6f90SAriel D'Alessandro /*
3841e6f90SAriel D'Alessandro  * NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver
4841e6f90SAriel D'Alessandro  *
5841e6f90SAriel D'Alessandro  * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
6841e6f90SAriel D'Alessandro  *
7841e6f90SAriel D'Alessandro  * Notes
8841e6f90SAriel D'Alessandro  * =====
9841e6f90SAriel D'Alessandro  * NXP LPC18xx provides a State Configurable Timer (SCT) which can be configured
10841e6f90SAriel D'Alessandro  * as a Pulse Width Modulator.
11841e6f90SAriel D'Alessandro  *
12841e6f90SAriel D'Alessandro  * SCT supports 16 outputs, 16 events and 16 registers. Each event will be
13841e6f90SAriel D'Alessandro  * triggered when its related register matches the SCT counter value, and it
14841e6f90SAriel D'Alessandro  * will set or clear a selected output.
15841e6f90SAriel D'Alessandro  *
16841e6f90SAriel D'Alessandro  * One of the events is preselected to generate the period, thus the maximum
17841e6f90SAriel D'Alessandro  * number of simultaneous channels is limited to 15. Notice that period is
18841e6f90SAriel D'Alessandro  * global to all the channels, thus PWM driver will refuse setting different
19841e6f90SAriel D'Alessandro  * values to it, unless there's only one channel requested.
20841e6f90SAriel D'Alessandro  */
21841e6f90SAriel D'Alessandro 
22841e6f90SAriel D'Alessandro #include <linux/clk.h>
23841e6f90SAriel D'Alessandro #include <linux/err.h>
24841e6f90SAriel D'Alessandro #include <linux/io.h>
250a41b0c5SRob Herring #include <linux/mod_devicetable.h>
26841e6f90SAriel D'Alessandro #include <linux/module.h>
27841e6f90SAriel D'Alessandro #include <linux/platform_device.h>
28841e6f90SAriel D'Alessandro #include <linux/pwm.h>
29841e6f90SAriel D'Alessandro 
30841e6f90SAriel D'Alessandro /* LPC18xx SCT registers */
31841e6f90SAriel D'Alessandro #define LPC18XX_PWM_CONFIG		0x000
32841e6f90SAriel D'Alessandro #define LPC18XX_PWM_CONFIG_UNIFY	BIT(0)
33841e6f90SAriel D'Alessandro #define LPC18XX_PWM_CONFIG_NORELOAD	BIT(7)
34841e6f90SAriel D'Alessandro 
35841e6f90SAriel D'Alessandro #define LPC18XX_PWM_CTRL		0x004
36841e6f90SAriel D'Alessandro #define LPC18XX_PWM_CTRL_HALT		BIT(2)
37841e6f90SAriel D'Alessandro #define LPC18XX_PWM_BIDIR		BIT(4)
38841e6f90SAriel D'Alessandro #define LPC18XX_PWM_PRE_SHIFT		5
39841e6f90SAriel D'Alessandro #define LPC18XX_PWM_PRE_MASK		(0xff << LPC18XX_PWM_PRE_SHIFT)
40841e6f90SAriel D'Alessandro #define LPC18XX_PWM_PRE(x)		(x << LPC18XX_PWM_PRE_SHIFT)
41841e6f90SAriel D'Alessandro 
42841e6f90SAriel D'Alessandro #define LPC18XX_PWM_LIMIT		0x008
43841e6f90SAriel D'Alessandro 
44841e6f90SAriel D'Alessandro #define LPC18XX_PWM_RES_BASE		0x058
45841e6f90SAriel D'Alessandro #define LPC18XX_PWM_RES_SHIFT(_ch)	(_ch * 2)
46841e6f90SAriel D'Alessandro #define LPC18XX_PWM_RES(_ch, _action)	(_action << LPC18XX_PWM_RES_SHIFT(_ch))
47841e6f90SAriel D'Alessandro #define LPC18XX_PWM_RES_MASK(_ch)	(0x3 << LPC18XX_PWM_RES_SHIFT(_ch))
48841e6f90SAriel D'Alessandro 
49841e6f90SAriel D'Alessandro #define LPC18XX_PWM_MATCH_BASE		0x100
50841e6f90SAriel D'Alessandro #define LPC18XX_PWM_MATCH(_ch)		(LPC18XX_PWM_MATCH_BASE + _ch * 4)
51841e6f90SAriel D'Alessandro 
52841e6f90SAriel D'Alessandro #define LPC18XX_PWM_MATCHREL_BASE	0x200
53841e6f90SAriel D'Alessandro #define LPC18XX_PWM_MATCHREL(_ch)	(LPC18XX_PWM_MATCHREL_BASE + _ch * 4)
54841e6f90SAriel D'Alessandro 
55841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVSTATEMSK_BASE	0x300
56841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVSTATEMSK(_ch)	(LPC18XX_PWM_EVSTATEMSK_BASE + _ch * 8)
57841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVSTATEMSK_ALL	0xffffffff
58841e6f90SAriel D'Alessandro 
59841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVCTRL_BASE		0x304
60841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVCTRL(_ev)		(LPC18XX_PWM_EVCTRL_BASE + _ev * 8)
61841e6f90SAriel D'Alessandro 
62841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVCTRL_MATCH(_ch)	_ch
63841e6f90SAriel D'Alessandro 
64841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVCTRL_COMB_SHIFT	12
65841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVCTRL_COMB_MATCH	(0x1 << LPC18XX_PWM_EVCTRL_COMB_SHIFT)
66841e6f90SAriel D'Alessandro 
67841e6f90SAriel D'Alessandro #define LPC18XX_PWM_OUTPUTSET_BASE	0x500
68841e6f90SAriel D'Alessandro #define LPC18XX_PWM_OUTPUTSET(_ch)	(LPC18XX_PWM_OUTPUTSET_BASE + _ch * 8)
69841e6f90SAriel D'Alessandro 
70841e6f90SAriel D'Alessandro #define LPC18XX_PWM_OUTPUTCL_BASE	0x504
71841e6f90SAriel D'Alessandro #define LPC18XX_PWM_OUTPUTCL(_ch)	(LPC18XX_PWM_OUTPUTCL_BASE + _ch * 8)
72841e6f90SAriel D'Alessandro 
73841e6f90SAriel D'Alessandro /* LPC18xx SCT unified counter */
74841e6f90SAriel D'Alessandro #define LPC18XX_PWM_TIMER_MAX		0xffffffff
75841e6f90SAriel D'Alessandro 
76841e6f90SAriel D'Alessandro /* LPC18xx SCT events */
77841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVENT_PERIOD	0
78841e6f90SAriel D'Alessandro #define LPC18XX_PWM_EVENT_MAX		16
79841e6f90SAriel D'Alessandro 
8020d9de9cSUwe Kleine-König #define LPC18XX_NUM_PWMS		16
8120d9de9cSUwe Kleine-König 
82841e6f90SAriel D'Alessandro /* SCT conflict resolution */
83841e6f90SAriel D'Alessandro enum lpc18xx_pwm_res_action {
84841e6f90SAriel D'Alessandro 	LPC18XX_PWM_RES_NONE,
85841e6f90SAriel D'Alessandro 	LPC18XX_PWM_RES_SET,
86841e6f90SAriel D'Alessandro 	LPC18XX_PWM_RES_CLEAR,
87841e6f90SAriel D'Alessandro 	LPC18XX_PWM_RES_TOGGLE,
88841e6f90SAriel D'Alessandro };
89841e6f90SAriel D'Alessandro 
90841e6f90SAriel D'Alessandro struct lpc18xx_pwm_data {
91841e6f90SAriel D'Alessandro 	unsigned int duty_event;
92841e6f90SAriel D'Alessandro };
93841e6f90SAriel D'Alessandro 
94841e6f90SAriel D'Alessandro struct lpc18xx_pwm_chip {
95841e6f90SAriel D'Alessandro 	struct device *dev;
96841e6f90SAriel D'Alessandro 	struct pwm_chip chip;
97841e6f90SAriel D'Alessandro 	void __iomem *base;
98841e6f90SAriel D'Alessandro 	struct clk *pwm_clk;
99841e6f90SAriel D'Alessandro 	unsigned long clk_rate;
100841e6f90SAriel D'Alessandro 	unsigned int period_ns;
101841e6f90SAriel D'Alessandro 	unsigned int min_period_ns;
1028933d30cSUwe Kleine-König 	u64 max_period_ns;
103841e6f90SAriel D'Alessandro 	unsigned int period_event;
104841e6f90SAriel D'Alessandro 	unsigned long event_map;
105841e6f90SAriel D'Alessandro 	struct mutex res_lock;
106841e6f90SAriel D'Alessandro 	struct mutex period_lock;
10720d9de9cSUwe Kleine-König 	struct lpc18xx_pwm_data channeldata[LPC18XX_NUM_PWMS];
108841e6f90SAriel D'Alessandro };
109841e6f90SAriel D'Alessandro 
110841e6f90SAriel D'Alessandro static inline struct lpc18xx_pwm_chip *
to_lpc18xx_pwm_chip(struct pwm_chip * chip)111841e6f90SAriel D'Alessandro to_lpc18xx_pwm_chip(struct pwm_chip *chip)
112841e6f90SAriel D'Alessandro {
113841e6f90SAriel D'Alessandro 	return container_of(chip, struct lpc18xx_pwm_chip, chip);
114841e6f90SAriel D'Alessandro }
115841e6f90SAriel D'Alessandro 
lpc18xx_pwm_writel(struct lpc18xx_pwm_chip * lpc18xx_pwm,u32 reg,u32 val)116841e6f90SAriel D'Alessandro static inline void lpc18xx_pwm_writel(struct lpc18xx_pwm_chip *lpc18xx_pwm,
117841e6f90SAriel D'Alessandro 				      u32 reg, u32 val)
118841e6f90SAriel D'Alessandro {
119841e6f90SAriel D'Alessandro 	writel(val, lpc18xx_pwm->base + reg);
120841e6f90SAriel D'Alessandro }
121841e6f90SAriel D'Alessandro 
lpc18xx_pwm_readl(struct lpc18xx_pwm_chip * lpc18xx_pwm,u32 reg)122841e6f90SAriel D'Alessandro static inline u32 lpc18xx_pwm_readl(struct lpc18xx_pwm_chip *lpc18xx_pwm,
123841e6f90SAriel D'Alessandro 				    u32 reg)
124841e6f90SAriel D'Alessandro {
125841e6f90SAriel D'Alessandro 	return readl(lpc18xx_pwm->base + reg);
126841e6f90SAriel D'Alessandro }
127841e6f90SAriel D'Alessandro 
lpc18xx_pwm_set_conflict_res(struct lpc18xx_pwm_chip * lpc18xx_pwm,struct pwm_device * pwm,enum lpc18xx_pwm_res_action action)128841e6f90SAriel D'Alessandro static void lpc18xx_pwm_set_conflict_res(struct lpc18xx_pwm_chip *lpc18xx_pwm,
129841e6f90SAriel D'Alessandro 					 struct pwm_device *pwm,
130841e6f90SAriel D'Alessandro 					 enum lpc18xx_pwm_res_action action)
131841e6f90SAriel D'Alessandro {
132841e6f90SAriel D'Alessandro 	u32 val;
133841e6f90SAriel D'Alessandro 
134841e6f90SAriel D'Alessandro 	mutex_lock(&lpc18xx_pwm->res_lock);
135841e6f90SAriel D'Alessandro 
136841e6f90SAriel D'Alessandro 	/*
137841e6f90SAriel D'Alessandro 	 * Simultaneous set and clear may happen on an output, that is the case
138841e6f90SAriel D'Alessandro 	 * when duty_ns == period_ns. LPC18xx SCT allows to set a conflict
139841e6f90SAriel D'Alessandro 	 * resolution action to be taken in such a case.
140841e6f90SAriel D'Alessandro 	 */
141841e6f90SAriel D'Alessandro 	val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_RES_BASE);
142841e6f90SAriel D'Alessandro 	val &= ~LPC18XX_PWM_RES_MASK(pwm->hwpwm);
143841e6f90SAriel D'Alessandro 	val |= LPC18XX_PWM_RES(pwm->hwpwm, action);
144841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_RES_BASE, val);
145841e6f90SAriel D'Alessandro 
146841e6f90SAriel D'Alessandro 	mutex_unlock(&lpc18xx_pwm->res_lock);
147841e6f90SAriel D'Alessandro }
148841e6f90SAriel D'Alessandro 
lpc18xx_pwm_config_period(struct pwm_chip * chip,u64 period_ns)1498933d30cSUwe Kleine-König static void lpc18xx_pwm_config_period(struct pwm_chip *chip, u64 period_ns)
150841e6f90SAriel D'Alessandro {
151841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
1528933d30cSUwe Kleine-König 	u32 val;
153841e6f90SAriel D'Alessandro 
1548933d30cSUwe Kleine-König 	/*
1558933d30cSUwe Kleine-König 	 * With clk_rate < NSEC_PER_SEC this cannot overflow.
1568933d30cSUwe Kleine-König 	 * With period_ns < max_period_ns this also fits into an u32.
1578933d30cSUwe Kleine-König 	 * As period_ns >= min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, lpc18xx_pwm->clk_rate);
1588933d30cSUwe Kleine-König 	 * we have val >= 1.
1598933d30cSUwe Kleine-König 	 */
1608933d30cSUwe Kleine-König 	val = mul_u64_u64_div_u64(period_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC);
161841e6f90SAriel D'Alessandro 
162841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
163841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_MATCH(lpc18xx_pwm->period_event),
1648933d30cSUwe Kleine-König 			   val - 1);
165841e6f90SAriel D'Alessandro 
166841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
167841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_MATCHREL(lpc18xx_pwm->period_event),
1688933d30cSUwe Kleine-König 			   val - 1);
169841e6f90SAriel D'Alessandro }
170841e6f90SAriel D'Alessandro 
lpc18xx_pwm_config_duty(struct pwm_chip * chip,struct pwm_device * pwm,u64 duty_ns)171841e6f90SAriel D'Alessandro static void lpc18xx_pwm_config_duty(struct pwm_chip *chip,
1728933d30cSUwe Kleine-König 				    struct pwm_device *pwm, u64 duty_ns)
173841e6f90SAriel D'Alessandro {
174841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
1759136a39eSUwe Kleine-König 	struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm];
1768933d30cSUwe Kleine-König 	u32 val;
177841e6f90SAriel D'Alessandro 
1788933d30cSUwe Kleine-König 	/*
17907d8d8d2SUwe Kleine-König 	 * With clk_rate <= NSEC_PER_SEC this cannot overflow.
1808933d30cSUwe Kleine-König 	 * With duty_ns <= period_ns < max_period_ns this also fits into an u32.
1818933d30cSUwe Kleine-König 	 */
1828933d30cSUwe Kleine-König 	val = mul_u64_u64_div_u64(duty_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC);
183841e6f90SAriel D'Alessandro 
184841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
185841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_MATCH(lpc18xx_data->duty_event),
1868933d30cSUwe Kleine-König 			   val);
187841e6f90SAriel D'Alessandro 
188841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
189841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_MATCHREL(lpc18xx_data->duty_event),
1908933d30cSUwe Kleine-König 			   val);
191841e6f90SAriel D'Alessandro }
192841e6f90SAriel D'Alessandro 
lpc18xx_pwm_config(struct pwm_chip * chip,struct pwm_device * pwm,int duty_ns,int period_ns)193841e6f90SAriel D'Alessandro static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
194841e6f90SAriel D'Alessandro 			      int duty_ns, int period_ns)
195841e6f90SAriel D'Alessandro {
196841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
197841e6f90SAriel D'Alessandro 	int requested_events, i;
198841e6f90SAriel D'Alessandro 
199841e6f90SAriel D'Alessandro 	if (period_ns < lpc18xx_pwm->min_period_ns ||
200841e6f90SAriel D'Alessandro 	    period_ns > lpc18xx_pwm->max_period_ns) {
201841e6f90SAriel D'Alessandro 		dev_err(chip->dev, "period %d not in range\n", period_ns);
202841e6f90SAriel D'Alessandro 		return -ERANGE;
203841e6f90SAriel D'Alessandro 	}
204841e6f90SAriel D'Alessandro 
205841e6f90SAriel D'Alessandro 	mutex_lock(&lpc18xx_pwm->period_lock);
206841e6f90SAriel D'Alessandro 
207841e6f90SAriel D'Alessandro 	requested_events = bitmap_weight(&lpc18xx_pwm->event_map,
208841e6f90SAriel D'Alessandro 					 LPC18XX_PWM_EVENT_MAX);
209841e6f90SAriel D'Alessandro 
210841e6f90SAriel D'Alessandro 	/*
211841e6f90SAriel D'Alessandro 	 * The PWM supports only a single period for all PWM channels.
212841e6f90SAriel D'Alessandro 	 * Once the period is set, it can only be changed if no more than one
213841e6f90SAriel D'Alessandro 	 * channel is requested at that moment.
214841e6f90SAriel D'Alessandro 	 */
215841e6f90SAriel D'Alessandro 	if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns &&
216841e6f90SAriel D'Alessandro 	    lpc18xx_pwm->period_ns) {
217841e6f90SAriel D'Alessandro 		dev_err(chip->dev, "conflicting period requested for PWM %u\n",
218841e6f90SAriel D'Alessandro 			pwm->hwpwm);
219841e6f90SAriel D'Alessandro 		mutex_unlock(&lpc18xx_pwm->period_lock);
220841e6f90SAriel D'Alessandro 		return -EBUSY;
221841e6f90SAriel D'Alessandro 	}
222841e6f90SAriel D'Alessandro 
223841e6f90SAriel D'Alessandro 	if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) ||
224841e6f90SAriel D'Alessandro 	    !lpc18xx_pwm->period_ns) {
225841e6f90SAriel D'Alessandro 		lpc18xx_pwm->period_ns = period_ns;
226841e6f90SAriel D'Alessandro 		for (i = 0; i < chip->npwm; i++)
227841e6f90SAriel D'Alessandro 			pwm_set_period(&chip->pwms[i], period_ns);
228841e6f90SAriel D'Alessandro 		lpc18xx_pwm_config_period(chip, period_ns);
229841e6f90SAriel D'Alessandro 	}
230841e6f90SAriel D'Alessandro 
231841e6f90SAriel D'Alessandro 	mutex_unlock(&lpc18xx_pwm->period_lock);
232841e6f90SAriel D'Alessandro 
233841e6f90SAriel D'Alessandro 	lpc18xx_pwm_config_duty(chip, pwm, duty_ns);
234841e6f90SAriel D'Alessandro 
235841e6f90SAriel D'Alessandro 	return 0;
236841e6f90SAriel D'Alessandro }
237841e6f90SAriel D'Alessandro 
lpc18xx_pwm_enable(struct pwm_chip * chip,struct pwm_device * pwm,enum pwm_polarity polarity)238c449a8caSUwe Kleine-König static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity)
239841e6f90SAriel D'Alessandro {
240841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
2419136a39eSUwe Kleine-König 	struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm];
242841e6f90SAriel D'Alessandro 	enum lpc18xx_pwm_res_action res_action;
243841e6f90SAriel D'Alessandro 	unsigned int set_event, clear_event;
244841e6f90SAriel D'Alessandro 
245841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
246841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event),
247841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_data->duty_event) |
248841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVCTRL_COMB_MATCH);
249841e6f90SAriel D'Alessandro 
250841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
251841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event),
252841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVSTATEMSK_ALL);
253841e6f90SAriel D'Alessandro 
254c449a8caSUwe Kleine-König 	if (polarity == PWM_POLARITY_NORMAL) {
255841e6f90SAriel D'Alessandro 		set_event = lpc18xx_pwm->period_event;
256841e6f90SAriel D'Alessandro 		clear_event = lpc18xx_data->duty_event;
257841e6f90SAriel D'Alessandro 		res_action = LPC18XX_PWM_RES_SET;
258841e6f90SAriel D'Alessandro 	} else {
259841e6f90SAriel D'Alessandro 		set_event = lpc18xx_data->duty_event;
260841e6f90SAriel D'Alessandro 		clear_event = lpc18xx_pwm->period_event;
261841e6f90SAriel D'Alessandro 		res_action = LPC18XX_PWM_RES_CLEAR;
262841e6f90SAriel D'Alessandro 	}
263841e6f90SAriel D'Alessandro 
264841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm),
265841e6f90SAriel D'Alessandro 			   BIT(set_event));
266841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm),
267841e6f90SAriel D'Alessandro 			   BIT(clear_event));
268841e6f90SAriel D'Alessandro 	lpc18xx_pwm_set_conflict_res(lpc18xx_pwm, pwm, res_action);
269841e6f90SAriel D'Alessandro 
270841e6f90SAriel D'Alessandro 	return 0;
271841e6f90SAriel D'Alessandro }
272841e6f90SAriel D'Alessandro 
lpc18xx_pwm_disable(struct pwm_chip * chip,struct pwm_device * pwm)273841e6f90SAriel D'Alessandro static void lpc18xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
274841e6f90SAriel D'Alessandro {
275841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
2769136a39eSUwe Kleine-König 	struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm];
277841e6f90SAriel D'Alessandro 
278841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
279841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), 0);
280841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), 0);
281841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), 0);
282841e6f90SAriel D'Alessandro }
283841e6f90SAriel D'Alessandro 
lpc18xx_pwm_request(struct pwm_chip * chip,struct pwm_device * pwm)284841e6f90SAriel D'Alessandro static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
285841e6f90SAriel D'Alessandro {
286841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
2879136a39eSUwe Kleine-König 	struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm];
288841e6f90SAriel D'Alessandro 	unsigned long event;
289841e6f90SAriel D'Alessandro 
290841e6f90SAriel D'Alessandro 	event = find_first_zero_bit(&lpc18xx_pwm->event_map,
291841e6f90SAriel D'Alessandro 				    LPC18XX_PWM_EVENT_MAX);
292841e6f90SAriel D'Alessandro 
293841e6f90SAriel D'Alessandro 	if (event >= LPC18XX_PWM_EVENT_MAX) {
294841e6f90SAriel D'Alessandro 		dev_err(lpc18xx_pwm->dev,
295841e6f90SAriel D'Alessandro 			"maximum number of simultaneous channels reached\n");
296841e6f90SAriel D'Alessandro 		return -EBUSY;
2979a9dd7e4SYang Li 	}
298841e6f90SAriel D'Alessandro 
299841e6f90SAriel D'Alessandro 	set_bit(event, &lpc18xx_pwm->event_map);
300841e6f90SAriel D'Alessandro 	lpc18xx_data->duty_event = event;
301841e6f90SAriel D'Alessandro 
302841e6f90SAriel D'Alessandro 	return 0;
303841e6f90SAriel D'Alessandro }
304841e6f90SAriel D'Alessandro 
lpc18xx_pwm_free(struct pwm_chip * chip,struct pwm_device * pwm)305841e6f90SAriel D'Alessandro static void lpc18xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
306841e6f90SAriel D'Alessandro {
307841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
3089136a39eSUwe Kleine-König 	struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm];
309841e6f90SAriel D'Alessandro 
310841e6f90SAriel D'Alessandro 	clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map);
311841e6f90SAriel D'Alessandro }
312841e6f90SAriel D'Alessandro 
lpc18xx_pwm_apply(struct pwm_chip * chip,struct pwm_device * pwm,const struct pwm_state * state)313c449a8caSUwe Kleine-König static int lpc18xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
314c449a8caSUwe Kleine-König 			     const struct pwm_state *state)
315c449a8caSUwe Kleine-König {
316c449a8caSUwe Kleine-König 	int err;
317c449a8caSUwe Kleine-König 	bool enabled = pwm->state.enabled;
318c449a8caSUwe Kleine-König 
319c449a8caSUwe Kleine-König 	if (state->polarity != pwm->state.polarity && pwm->state.enabled) {
320c449a8caSUwe Kleine-König 		lpc18xx_pwm_disable(chip, pwm);
321c449a8caSUwe Kleine-König 		enabled = false;
322c449a8caSUwe Kleine-König 	}
323c449a8caSUwe Kleine-König 
324c449a8caSUwe Kleine-König 	if (!state->enabled) {
325c449a8caSUwe Kleine-König 		if (enabled)
326c449a8caSUwe Kleine-König 			lpc18xx_pwm_disable(chip, pwm);
327c449a8caSUwe Kleine-König 
328c449a8caSUwe Kleine-König 		return 0;
329c449a8caSUwe Kleine-König 	}
330c449a8caSUwe Kleine-König 
331c449a8caSUwe Kleine-König 	err = lpc18xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
332c449a8caSUwe Kleine-König 	if (err)
333c449a8caSUwe Kleine-König 		return err;
334c449a8caSUwe Kleine-König 
335c449a8caSUwe Kleine-König 	if (!enabled)
336c449a8caSUwe Kleine-König 		err = lpc18xx_pwm_enable(chip, pwm, state->polarity);
337c449a8caSUwe Kleine-König 
338c449a8caSUwe Kleine-König 	return err;
339c449a8caSUwe Kleine-König }
340841e6f90SAriel D'Alessandro static const struct pwm_ops lpc18xx_pwm_ops = {
341c449a8caSUwe Kleine-König 	.apply = lpc18xx_pwm_apply,
342841e6f90SAriel D'Alessandro 	.request = lpc18xx_pwm_request,
343841e6f90SAriel D'Alessandro 	.free = lpc18xx_pwm_free,
344841e6f90SAriel D'Alessandro 	.owner = THIS_MODULE,
345841e6f90SAriel D'Alessandro };
346841e6f90SAriel D'Alessandro 
347841e6f90SAriel D'Alessandro static const struct of_device_id lpc18xx_pwm_of_match[] = {
348841e6f90SAriel D'Alessandro 	{ .compatible = "nxp,lpc1850-sct-pwm" },
349841e6f90SAriel D'Alessandro 	{}
350841e6f90SAriel D'Alessandro };
351841e6f90SAriel D'Alessandro MODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match);
352841e6f90SAriel D'Alessandro 
lpc18xx_pwm_probe(struct platform_device * pdev)353841e6f90SAriel D'Alessandro static int lpc18xx_pwm_probe(struct platform_device *pdev)
354841e6f90SAriel D'Alessandro {
355841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm;
3569136a39eSUwe Kleine-König 	int ret;
357841e6f90SAriel D'Alessandro 	u64 val;
358841e6f90SAriel D'Alessandro 
359841e6f90SAriel D'Alessandro 	lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm),
360841e6f90SAriel D'Alessandro 				   GFP_KERNEL);
361841e6f90SAriel D'Alessandro 	if (!lpc18xx_pwm)
362841e6f90SAriel D'Alessandro 		return -ENOMEM;
363841e6f90SAriel D'Alessandro 
364841e6f90SAriel D'Alessandro 	lpc18xx_pwm->dev = &pdev->dev;
365841e6f90SAriel D'Alessandro 
36674ec20a4SYangtao Li 	lpc18xx_pwm->base = devm_platform_ioremap_resource(pdev, 0);
367841e6f90SAriel D'Alessandro 	if (IS_ERR(lpc18xx_pwm->base))
368841e6f90SAriel D'Alessandro 		return PTR_ERR(lpc18xx_pwm->base);
369841e6f90SAriel D'Alessandro 
370*4aed0ccdSUwe Kleine-König 	lpc18xx_pwm->pwm_clk = devm_clk_get_enabled(&pdev->dev, "pwm");
3712ba1aedeSUwe Kleine-König 	if (IS_ERR(lpc18xx_pwm->pwm_clk))
3722ba1aedeSUwe Kleine-König 		return dev_err_probe(&pdev->dev, PTR_ERR(lpc18xx_pwm->pwm_clk),
3732ba1aedeSUwe Kleine-König 				     "failed to get pwm clock\n");
374841e6f90SAriel D'Alessandro 
375841e6f90SAriel D'Alessandro 	lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk);
376*4aed0ccdSUwe Kleine-König 	if (!lpc18xx_pwm->clk_rate)
377*4aed0ccdSUwe Kleine-König 		return dev_err_probe(&pdev->dev,
3782ba1aedeSUwe Kleine-König 				     -EINVAL, "pwm clock has no frequency\n");
379841e6f90SAriel D'Alessandro 
3808933d30cSUwe Kleine-König 	/*
3818933d30cSUwe Kleine-König 	 * If clkrate is too fast, the calculations in .apply() might overflow.
3828933d30cSUwe Kleine-König 	 */
383*4aed0ccdSUwe Kleine-König 	if (lpc18xx_pwm->clk_rate > NSEC_PER_SEC)
384*4aed0ccdSUwe Kleine-König 		return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock to fast\n");
3858933d30cSUwe Kleine-König 
386841e6f90SAriel D'Alessandro 	mutex_init(&lpc18xx_pwm->res_lock);
387841e6f90SAriel D'Alessandro 	mutex_init(&lpc18xx_pwm->period_lock);
388841e6f90SAriel D'Alessandro 
3898933d30cSUwe Kleine-König 	lpc18xx_pwm->max_period_ns =
3908933d30cSUwe Kleine-König 		mul_u64_u64_div_u64(NSEC_PER_SEC, LPC18XX_PWM_TIMER_MAX, lpc18xx_pwm->clk_rate);
391841e6f90SAriel D'Alessandro 
392841e6f90SAriel D'Alessandro 	lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC,
393841e6f90SAriel D'Alessandro 						  lpc18xx_pwm->clk_rate);
394841e6f90SAriel D'Alessandro 
395841e6f90SAriel D'Alessandro 	lpc18xx_pwm->chip.dev = &pdev->dev;
396841e6f90SAriel D'Alessandro 	lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
39720d9de9cSUwe Kleine-König 	lpc18xx_pwm->chip.npwm = LPC18XX_NUM_PWMS;
398841e6f90SAriel D'Alessandro 
399841e6f90SAriel D'Alessandro 	/* SCT counter must be in unify (32 bit) mode */
400841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
401841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_CONFIG_UNIFY);
402841e6f90SAriel D'Alessandro 
403841e6f90SAriel D'Alessandro 	/*
404841e6f90SAriel D'Alessandro 	 * Everytime the timer counter reaches the period value, the related
405841e6f90SAriel D'Alessandro 	 * event will be triggered and the counter reset to 0.
406841e6f90SAriel D'Alessandro 	 */
407841e6f90SAriel D'Alessandro 	set_bit(LPC18XX_PWM_EVENT_PERIOD, &lpc18xx_pwm->event_map);
408841e6f90SAriel D'Alessandro 	lpc18xx_pwm->period_event = LPC18XX_PWM_EVENT_PERIOD;
409841e6f90SAriel D'Alessandro 
410841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
411841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVSTATEMSK(lpc18xx_pwm->period_event),
412841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVSTATEMSK_ALL);
413841e6f90SAriel D'Alessandro 
414841e6f90SAriel D'Alessandro 	val = LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_pwm->period_event) |
415841e6f90SAriel D'Alessandro 	      LPC18XX_PWM_EVCTRL_COMB_MATCH;
416841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm,
417841e6f90SAriel D'Alessandro 			   LPC18XX_PWM_EVCTRL(lpc18xx_pwm->period_event), val);
418841e6f90SAriel D'Alessandro 
419841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT,
420841e6f90SAriel D'Alessandro 			   BIT(lpc18xx_pwm->period_event));
421841e6f90SAriel D'Alessandro 
422841e6f90SAriel D'Alessandro 	val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
423841e6f90SAriel D'Alessandro 	val &= ~LPC18XX_PWM_BIDIR;
424841e6f90SAriel D'Alessandro 	val &= ~LPC18XX_PWM_CTRL_HALT;
425841e6f90SAriel D'Alessandro 	val &= ~LPC18XX_PWM_PRE_MASK;
426841e6f90SAriel D'Alessandro 	val |= LPC18XX_PWM_PRE(0);
427841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val);
428841e6f90SAriel D'Alessandro 
4290401f24cSUwe Kleine-König 	ret = pwmchip_add(&lpc18xx_pwm->chip);
430*4aed0ccdSUwe Kleine-König 	if (ret < 0)
431*4aed0ccdSUwe Kleine-König 		return dev_err_probe(&pdev->dev, ret, "pwmchip_add failed\n");
4320401f24cSUwe Kleine-König 
4330401f24cSUwe Kleine-König 	platform_set_drvdata(pdev, lpc18xx_pwm);
4340401f24cSUwe Kleine-König 
435841e6f90SAriel D'Alessandro 	return 0;
436841e6f90SAriel D'Alessandro }
437841e6f90SAriel D'Alessandro 
lpc18xx_pwm_remove(struct platform_device * pdev)438fbd2d733SUwe Kleine-König static void lpc18xx_pwm_remove(struct platform_device *pdev)
439841e6f90SAriel D'Alessandro {
440841e6f90SAriel D'Alessandro 	struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
441841e6f90SAriel D'Alessandro 	u32 val;
442841e6f90SAriel D'Alessandro 
443d58a484eSUwe Kleine-König 	pwmchip_remove(&lpc18xx_pwm->chip);
444d58a484eSUwe Kleine-König 
445841e6f90SAriel D'Alessandro 	val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
446841e6f90SAriel D'Alessandro 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL,
447841e6f90SAriel D'Alessandro 			   val | LPC18XX_PWM_CTRL_HALT);
448841e6f90SAriel D'Alessandro }
449841e6f90SAriel D'Alessandro 
450841e6f90SAriel D'Alessandro static struct platform_driver lpc18xx_pwm_driver = {
451841e6f90SAriel D'Alessandro 	.driver = {
452841e6f90SAriel D'Alessandro 		.name = "lpc18xx-sct-pwm",
453841e6f90SAriel D'Alessandro 		.of_match_table = lpc18xx_pwm_of_match,
454841e6f90SAriel D'Alessandro 	},
455841e6f90SAriel D'Alessandro 	.probe = lpc18xx_pwm_probe,
456fbd2d733SUwe Kleine-König 	.remove_new = lpc18xx_pwm_remove,
457841e6f90SAriel D'Alessandro };
458841e6f90SAriel D'Alessandro module_platform_driver(lpc18xx_pwm_driver);
459841e6f90SAriel D'Alessandro 
460841e6f90SAriel D'Alessandro MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>");
461841e6f90SAriel D'Alessandro MODULE_DESCRIPTION("NXP LPC18xx PWM driver");
462841e6f90SAriel D'Alessandro MODULE_LICENSE("GPL v2");
463