Commit | Line | Data |
---|---|---|
9e37a53e YS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2017-2018 SiFive | |
4 | * For SiFive's PWM IP block documentation please refer Chapter 14 of | |
5 | * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf | |
6 | * | |
7 | * Limitations: | |
8 | * - When changing both duty cycle and period, we cannot prevent in | |
9 | * software that the output might produce a period with mixed | |
10 | * settings (new period length and old duty cycle). | |
11 | * - The hardware cannot generate a 100% duty cycle. | |
12 | * - The hardware generates only inverted output. | |
13 | */ | |
14 | #include <linux/clk.h> | |
15 | #include <linux/io.h> | |
16 | #include <linux/module.h> | |
17 | #include <linux/platform_device.h> | |
18 | #include <linux/pwm.h> | |
19 | #include <linux/slab.h> | |
20 | #include <linux/bitfield.h> | |
21 | ||
22 | /* Register offsets */ | |
23 | #define PWM_SIFIVE_PWMCFG 0x0 | |
24 | #define PWM_SIFIVE_PWMCOUNT 0x8 | |
25 | #define PWM_SIFIVE_PWMS 0x10 | |
26 | #define PWM_SIFIVE_PWMCMP0 0x20 | |
27 | ||
28 | /* PWMCFG fields */ | |
29 | #define PWM_SIFIVE_PWMCFG_SCALE GENMASK(3, 0) | |
30 | #define PWM_SIFIVE_PWMCFG_STICKY BIT(8) | |
31 | #define PWM_SIFIVE_PWMCFG_ZERO_CMP BIT(9) | |
32 | #define PWM_SIFIVE_PWMCFG_DEGLITCH BIT(10) | |
33 | #define PWM_SIFIVE_PWMCFG_EN_ALWAYS BIT(12) | |
34 | #define PWM_SIFIVE_PWMCFG_EN_ONCE BIT(13) | |
35 | #define PWM_SIFIVE_PWMCFG_CENTER BIT(16) | |
36 | #define PWM_SIFIVE_PWMCFG_GANG BIT(24) | |
37 | #define PWM_SIFIVE_PWMCFG_IP BIT(28) | |
38 | ||
39 | /* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */ | |
40 | #define PWM_SIFIVE_SIZE_PWMCMP 4 | |
41 | #define PWM_SIFIVE_CMPWIDTH 16 | |
42 | #define PWM_SIFIVE_DEFAULT_PERIOD 10000000 | |
43 | ||
44 | struct pwm_sifive_ddata { | |
45 | struct pwm_chip chip; | |
46 | struct mutex lock; /* lock to protect user_count */ | |
47 | struct notifier_block notifier; | |
48 | struct clk *clk; | |
49 | void __iomem *regs; | |
50 | unsigned int real_period; | |
51 | unsigned int approx_period; | |
52 | int user_count; | |
53 | }; | |
54 | ||
55 | static inline | |
56 | struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *c) | |
57 | { | |
58 | return container_of(c, struct pwm_sifive_ddata, chip); | |
59 | } | |
60 | ||
61 | static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm) | |
62 | { | |
63 | struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); | |
64 | ||
65 | mutex_lock(&ddata->lock); | |
66 | ddata->user_count++; | |
67 | mutex_unlock(&ddata->lock); | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm) | |
73 | { | |
74 | struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); | |
75 | ||
76 | mutex_lock(&ddata->lock); | |
77 | ddata->user_count--; | |
78 | mutex_unlock(&ddata->lock); | |
79 | } | |
80 | ||
81 | static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata, | |
82 | unsigned long rate) | |
83 | { | |
84 | unsigned long long num; | |
85 | unsigned long scale_pow; | |
86 | int scale; | |
87 | u32 val; | |
88 | /* | |
89 | * The PWM unit is used with pwmzerocmp=0, so the only way to modify the | |
90 | * period length is using pwmscale which provides the number of bits the | |
91 | * counter is shifted before being feed to the comparators. A period | |
92 | * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks. | |
93 | * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period | |
94 | */ | |
95 | scale_pow = div64_ul(ddata->approx_period * (u64)rate, NSEC_PER_SEC); | |
96 | scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf); | |
97 | ||
98 | val = PWM_SIFIVE_PWMCFG_EN_ALWAYS | | |
99 | FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale); | |
100 | writel(val, ddata->regs + PWM_SIFIVE_PWMCFG); | |
101 | ||
102 | /* As scale <= 15 the shift operation cannot overflow. */ | |
103 | num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale); | |
104 | ddata->real_period = div64_ul(num, rate); | |
105 | dev_dbg(ddata->chip.dev, | |
106 | "New real_period = %u ns\n", ddata->real_period); | |
107 | } | |
108 | ||
109 | static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, | |
110 | struct pwm_state *state) | |
111 | { | |
112 | struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); | |
113 | u32 duty, val; | |
114 | ||
115 | duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP0 + | |
116 | pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP); | |
117 | ||
118 | state->enabled = duty > 0; | |
119 | ||
120 | val = readl(ddata->regs + PWM_SIFIVE_PWMCFG); | |
121 | if (!(val & PWM_SIFIVE_PWMCFG_EN_ALWAYS)) | |
122 | state->enabled = false; | |
123 | ||
124 | state->period = ddata->real_period; | |
125 | state->duty_cycle = | |
126 | (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH; | |
127 | state->polarity = PWM_POLARITY_INVERSED; | |
128 | } | |
129 | ||
130 | static int pwm_sifive_enable(struct pwm_chip *chip, bool enable) | |
131 | { | |
132 | struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); | |
133 | int ret; | |
134 | ||
135 | if (enable) { | |
136 | ret = clk_enable(ddata->clk); | |
137 | if (ret) { | |
138 | dev_err(ddata->chip.dev, "Enable clk failed\n"); | |
139 | return ret; | |
140 | } | |
141 | } | |
142 | ||
143 | if (!enable) | |
144 | clk_disable(ddata->clk); | |
145 | ||
146 | return 0; | |
147 | } | |
148 | ||
149 | static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, | |
150 | struct pwm_state *state) | |
151 | { | |
152 | struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); | |
153 | struct pwm_state cur_state; | |
154 | unsigned int duty_cycle; | |
155 | unsigned long long num; | |
156 | bool enabled; | |
157 | int ret = 0; | |
158 | u32 frac; | |
159 | ||
160 | if (state->polarity != PWM_POLARITY_INVERSED) | |
161 | return -EINVAL; | |
162 | ||
163 | ret = clk_enable(ddata->clk); | |
164 | if (ret) { | |
165 | dev_err(ddata->chip.dev, "Enable clk failed\n"); | |
166 | return ret; | |
167 | } | |
168 | ||
169 | mutex_lock(&ddata->lock); | |
170 | cur_state = pwm->state; | |
171 | enabled = cur_state.enabled; | |
172 | ||
173 | duty_cycle = state->duty_cycle; | |
174 | if (!state->enabled) | |
175 | duty_cycle = 0; | |
176 | ||
177 | /* | |
178 | * The problem of output producing mixed setting as mentioned at top, | |
179 | * occurs here. To minimize the window for this problem, we are | |
180 | * calculating the register values first and then writing them | |
181 | * consecutively | |
182 | */ | |
183 | num = (u64)duty_cycle * (1U << PWM_SIFIVE_CMPWIDTH); | |
184 | frac = DIV_ROUND_CLOSEST_ULL(num, state->period); | |
185 | /* The hardware cannot generate a 100% duty cycle */ | |
186 | frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1); | |
187 | ||
188 | if (state->period != ddata->approx_period) { | |
189 | if (ddata->user_count != 1) { | |
190 | ret = -EBUSY; | |
191 | goto exit; | |
192 | } | |
193 | ddata->approx_period = state->period; | |
194 | pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk)); | |
195 | } | |
196 | ||
197 | writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 + | |
198 | pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP); | |
199 | ||
200 | if (state->enabled != enabled) | |
201 | pwm_sifive_enable(chip, state->enabled); | |
202 | ||
203 | exit: | |
204 | clk_disable(ddata->clk); | |
205 | mutex_unlock(&ddata->lock); | |
206 | return ret; | |
207 | } | |
208 | ||
209 | static const struct pwm_ops pwm_sifive_ops = { | |
210 | .request = pwm_sifive_request, | |
211 | .free = pwm_sifive_free, | |
212 | .get_state = pwm_sifive_get_state, | |
213 | .apply = pwm_sifive_apply, | |
214 | .owner = THIS_MODULE, | |
215 | }; | |
216 | ||
217 | static int pwm_sifive_clock_notifier(struct notifier_block *nb, | |
218 | unsigned long event, void *data) | |
219 | { | |
220 | struct clk_notifier_data *ndata = data; | |
221 | struct pwm_sifive_ddata *ddata = | |
222 | container_of(nb, struct pwm_sifive_ddata, notifier); | |
223 | ||
224 | if (event == POST_RATE_CHANGE) | |
225 | pwm_sifive_update_clock(ddata, ndata->new_rate); | |
226 | ||
227 | return NOTIFY_OK; | |
228 | } | |
229 | ||
230 | static int pwm_sifive_probe(struct platform_device *pdev) | |
231 | { | |
232 | struct device *dev = &pdev->dev; | |
233 | struct pwm_sifive_ddata *ddata; | |
234 | struct pwm_chip *chip; | |
235 | struct resource *res; | |
236 | int ret; | |
237 | ||
238 | ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); | |
239 | if (!ddata) | |
240 | return -ENOMEM; | |
241 | ||
242 | mutex_init(&ddata->lock); | |
243 | chip = &ddata->chip; | |
244 | chip->dev = dev; | |
245 | chip->ops = &pwm_sifive_ops; | |
246 | chip->of_xlate = of_pwm_xlate_with_flags; | |
247 | chip->of_pwm_n_cells = 3; | |
248 | chip->base = -1; | |
249 | chip->npwm = 4; | |
250 | ||
251 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
252 | ddata->regs = devm_ioremap_resource(dev, res); | |
253 | if (IS_ERR(ddata->regs)) { | |
254 | dev_err(dev, "Unable to map IO resources\n"); | |
255 | return PTR_ERR(ddata->regs); | |
256 | } | |
257 | ||
258 | ddata->clk = devm_clk_get(dev, NULL); | |
259 | if (IS_ERR(ddata->clk)) { | |
260 | if (PTR_ERR(ddata->clk) != -EPROBE_DEFER) | |
261 | dev_err(dev, "Unable to find controller clock\n"); | |
262 | return PTR_ERR(ddata->clk); | |
263 | } | |
264 | ||
265 | ret = clk_prepare_enable(ddata->clk); | |
266 | if (ret) { | |
267 | dev_err(dev, "failed to enable clock for pwm: %d\n", ret); | |
268 | return ret; | |
269 | } | |
270 | ||
271 | /* Watch for changes to underlying clock frequency */ | |
272 | ddata->notifier.notifier_call = pwm_sifive_clock_notifier; | |
273 | ret = clk_notifier_register(ddata->clk, &ddata->notifier); | |
274 | if (ret) { | |
275 | dev_err(dev, "failed to register clock notifier: %d\n", ret); | |
276 | goto disable_clk; | |
277 | } | |
278 | ||
279 | ret = pwmchip_add(chip); | |
280 | if (ret < 0) { | |
281 | dev_err(dev, "cannot register PWM: %d\n", ret); | |
282 | goto unregister_clk; | |
283 | } | |
284 | ||
285 | platform_set_drvdata(pdev, ddata); | |
286 | dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm); | |
287 | ||
288 | return 0; | |
289 | ||
290 | unregister_clk: | |
291 | clk_notifier_unregister(ddata->clk, &ddata->notifier); | |
292 | disable_clk: | |
293 | clk_disable_unprepare(ddata->clk); | |
294 | ||
295 | return ret; | |
296 | } | |
297 | ||
298 | static int pwm_sifive_remove(struct platform_device *dev) | |
299 | { | |
300 | struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev); | |
301 | bool is_enabled = false; | |
302 | struct pwm_device *pwm; | |
303 | int ret, ch; | |
304 | ||
305 | for (ch = 0; ch < ddata->chip.npwm; ch++) { | |
306 | pwm = &ddata->chip.pwms[ch]; | |
307 | if (pwm->state.enabled) { | |
308 | is_enabled = true; | |
309 | break; | |
310 | } | |
311 | } | |
312 | if (is_enabled) | |
313 | clk_disable(ddata->clk); | |
314 | ||
315 | clk_disable_unprepare(ddata->clk); | |
316 | ret = pwmchip_remove(&ddata->chip); | |
317 | clk_notifier_unregister(ddata->clk, &ddata->notifier); | |
318 | ||
319 | return ret; | |
320 | } | |
321 | ||
322 | static const struct of_device_id pwm_sifive_of_match[] = { | |
323 | { .compatible = "sifive,pwm0" }, | |
324 | {}, | |
325 | }; | |
326 | MODULE_DEVICE_TABLE(of, pwm_sifive_of_match); | |
327 | ||
328 | static struct platform_driver pwm_sifive_driver = { | |
329 | .probe = pwm_sifive_probe, | |
330 | .remove = pwm_sifive_remove, | |
331 | .driver = { | |
332 | .name = "pwm-sifive", | |
333 | .of_match_table = pwm_sifive_of_match, | |
334 | }, | |
335 | }; | |
336 | module_platform_driver(pwm_sifive_driver); | |
337 | ||
338 | MODULE_DESCRIPTION("SiFive PWM driver"); | |
339 | MODULE_LICENSE("GPL v2"); |