Root/
1 | /* |
2 | * ECAP PWM driver |
3 | * |
4 | * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.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, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ |
20 | |
21 | #include <linux/module.h> |
22 | #include <linux/platform_device.h> |
23 | #include <linux/io.h> |
24 | #include <linux/err.h> |
25 | #include <linux/clk.h> |
26 | #include <linux/pm_runtime.h> |
27 | #include <linux/pwm.h> |
28 | #include <linux/of_device.h> |
29 | #include <linux/pinctrl/consumer.h> |
30 | |
31 | #include "pwm-tipwmss.h" |
32 | |
33 | /* ECAP registers and bits definitions */ |
34 | #define CAP1 0x08 |
35 | #define CAP2 0x0C |
36 | #define CAP3 0x10 |
37 | #define CAP4 0x14 |
38 | #define ECCTL2 0x2A |
39 | #define ECCTL2_APWM_POL_LOW BIT(10) |
40 | #define ECCTL2_APWM_MODE BIT(9) |
41 | #define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) |
42 | #define ECCTL2_TSCTR_FREERUN BIT(4) |
43 | |
44 | struct ecap_context { |
45 | u32 cap3; |
46 | u32 cap4; |
47 | u16 ecctl2; |
48 | }; |
49 | |
50 | struct ecap_pwm_chip { |
51 | struct pwm_chip chip; |
52 | unsigned int clk_rate; |
53 | void __iomem *mmio_base; |
54 | struct ecap_context ctx; |
55 | }; |
56 | |
57 | static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip) |
58 | { |
59 | return container_of(chip, struct ecap_pwm_chip, chip); |
60 | } |
61 | |
62 | /* |
63 | * period_ns = 10^9 * period_cycles / PWM_CLK_RATE |
64 | * duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE |
65 | */ |
66 | static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
67 | int duty_ns, int period_ns) |
68 | { |
69 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); |
70 | unsigned long long c; |
71 | unsigned long period_cycles, duty_cycles; |
72 | unsigned int reg_val; |
73 | |
74 | if (period_ns > NSEC_PER_SEC) |
75 | return -ERANGE; |
76 | |
77 | c = pc->clk_rate; |
78 | c = c * period_ns; |
79 | do_div(c, NSEC_PER_SEC); |
80 | period_cycles = (unsigned long)c; |
81 | |
82 | if (period_cycles < 1) { |
83 | period_cycles = 1; |
84 | duty_cycles = 1; |
85 | } else { |
86 | c = pc->clk_rate; |
87 | c = c * duty_ns; |
88 | do_div(c, NSEC_PER_SEC); |
89 | duty_cycles = (unsigned long)c; |
90 | } |
91 | |
92 | pm_runtime_get_sync(pc->chip.dev); |
93 | |
94 | reg_val = readw(pc->mmio_base + ECCTL2); |
95 | |
96 | /* Configure APWM mode & disable sync option */ |
97 | reg_val |= ECCTL2_APWM_MODE | ECCTL2_SYNC_SEL_DISA; |
98 | |
99 | writew(reg_val, pc->mmio_base + ECCTL2); |
100 | |
101 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) { |
102 | /* Update active registers if not running */ |
103 | writel(duty_cycles, pc->mmio_base + CAP2); |
104 | writel(period_cycles, pc->mmio_base + CAP1); |
105 | } else { |
106 | /* |
107 | * Update shadow registers to configure period and |
108 | * compare values. This helps current PWM period to |
109 | * complete on reconfiguring |
110 | */ |
111 | writel(duty_cycles, pc->mmio_base + CAP4); |
112 | writel(period_cycles, pc->mmio_base + CAP3); |
113 | } |
114 | |
115 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) { |
116 | reg_val = readw(pc->mmio_base + ECCTL2); |
117 | /* Disable APWM mode to put APWM output Low */ |
118 | reg_val &= ~ECCTL2_APWM_MODE; |
119 | writew(reg_val, pc->mmio_base + ECCTL2); |
120 | } |
121 | |
122 | pm_runtime_put_sync(pc->chip.dev); |
123 | return 0; |
124 | } |
125 | |
126 | static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, |
127 | enum pwm_polarity polarity) |
128 | { |
129 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); |
130 | unsigned short reg_val; |
131 | |
132 | pm_runtime_get_sync(pc->chip.dev); |
133 | reg_val = readw(pc->mmio_base + ECCTL2); |
134 | if (polarity == PWM_POLARITY_INVERSED) |
135 | /* Duty cycle defines LOW period of PWM */ |
136 | reg_val |= ECCTL2_APWM_POL_LOW; |
137 | else |
138 | /* Duty cycle defines HIGH period of PWM */ |
139 | reg_val &= ~ECCTL2_APWM_POL_LOW; |
140 | |
141 | writew(reg_val, pc->mmio_base + ECCTL2); |
142 | pm_runtime_put_sync(pc->chip.dev); |
143 | return 0; |
144 | } |
145 | |
146 | static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
147 | { |
148 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); |
149 | unsigned int reg_val; |
150 | |
151 | /* Leave clock enabled on enabling PWM */ |
152 | pm_runtime_get_sync(pc->chip.dev); |
153 | |
154 | /* |
155 | * Enable 'Free run Time stamp counter mode' to start counter |
156 | * and 'APWM mode' to enable APWM output |
157 | */ |
158 | reg_val = readw(pc->mmio_base + ECCTL2); |
159 | reg_val |= ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE; |
160 | writew(reg_val, pc->mmio_base + ECCTL2); |
161 | return 0; |
162 | } |
163 | |
164 | static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
165 | { |
166 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); |
167 | unsigned int reg_val; |
168 | |
169 | /* |
170 | * Disable 'Free run Time stamp counter mode' to stop counter |
171 | * and 'APWM mode' to put APWM output to low |
172 | */ |
173 | reg_val = readw(pc->mmio_base + ECCTL2); |
174 | reg_val &= ~(ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE); |
175 | writew(reg_val, pc->mmio_base + ECCTL2); |
176 | |
177 | /* Disable clock on PWM disable */ |
178 | pm_runtime_put_sync(pc->chip.dev); |
179 | } |
180 | |
181 | static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) |
182 | { |
183 | if (test_bit(PWMF_ENABLED, &pwm->flags)) { |
184 | dev_warn(chip->dev, "Removing PWM device without disabling\n"); |
185 | pm_runtime_put_sync(chip->dev); |
186 | } |
187 | } |
188 | |
189 | static const struct pwm_ops ecap_pwm_ops = { |
190 | .free = ecap_pwm_free, |
191 | .config = ecap_pwm_config, |
192 | .set_polarity = ecap_pwm_set_polarity, |
193 | .enable = ecap_pwm_enable, |
194 | .disable = ecap_pwm_disable, |
195 | .owner = THIS_MODULE, |
196 | }; |
197 | |
198 | static const struct of_device_id ecap_of_match[] = { |
199 | { .compatible = "ti,am33xx-ecap" }, |
200 | {}, |
201 | }; |
202 | MODULE_DEVICE_TABLE(of, ecap_of_match); |
203 | |
204 | static int ecap_pwm_probe(struct platform_device *pdev) |
205 | { |
206 | int ret; |
207 | struct resource *r; |
208 | struct clk *clk; |
209 | struct ecap_pwm_chip *pc; |
210 | u16 status; |
211 | struct pinctrl *pinctrl; |
212 | |
213 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); |
214 | if (IS_ERR(pinctrl)) |
215 | dev_warn(&pdev->dev, "unable to select pin group\n"); |
216 | |
217 | pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); |
218 | if (!pc) { |
219 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
220 | return -ENOMEM; |
221 | } |
222 | |
223 | clk = devm_clk_get(&pdev->dev, "fck"); |
224 | if (IS_ERR(clk)) { |
225 | dev_err(&pdev->dev, "failed to get clock\n"); |
226 | return PTR_ERR(clk); |
227 | } |
228 | |
229 | pc->clk_rate = clk_get_rate(clk); |
230 | if (!pc->clk_rate) { |
231 | dev_err(&pdev->dev, "failed to get clock rate\n"); |
232 | return -EINVAL; |
233 | } |
234 | |
235 | pc->chip.dev = &pdev->dev; |
236 | pc->chip.ops = &ecap_pwm_ops; |
237 | pc->chip.of_xlate = of_pwm_xlate_with_flags; |
238 | pc->chip.of_pwm_n_cells = 3; |
239 | pc->chip.base = -1; |
240 | pc->chip.npwm = 1; |
241 | |
242 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
243 | if (!r) { |
244 | dev_err(&pdev->dev, "no memory resource defined\n"); |
245 | return -ENODEV; |
246 | } |
247 | |
248 | pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); |
249 | if (IS_ERR(pc->mmio_base)) |
250 | return PTR_ERR(pc->mmio_base); |
251 | |
252 | ret = pwmchip_add(&pc->chip); |
253 | if (ret < 0) { |
254 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); |
255 | return ret; |
256 | } |
257 | |
258 | pm_runtime_enable(&pdev->dev); |
259 | pm_runtime_get_sync(&pdev->dev); |
260 | |
261 | status = pwmss_submodule_state_change(pdev->dev.parent, |
262 | PWMSS_ECAPCLK_EN); |
263 | if (!(status & PWMSS_ECAPCLK_EN_ACK)) { |
264 | dev_err(&pdev->dev, "PWMSS config space clock enable failed\n"); |
265 | ret = -EINVAL; |
266 | goto pwmss_clk_failure; |
267 | } |
268 | |
269 | pm_runtime_put_sync(&pdev->dev); |
270 | |
271 | platform_set_drvdata(pdev, pc); |
272 | return 0; |
273 | |
274 | pwmss_clk_failure: |
275 | pm_runtime_put_sync(&pdev->dev); |
276 | pm_runtime_disable(&pdev->dev); |
277 | pwmchip_remove(&pc->chip); |
278 | return ret; |
279 | } |
280 | |
281 | static int ecap_pwm_remove(struct platform_device *pdev) |
282 | { |
283 | struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); |
284 | |
285 | pm_runtime_get_sync(&pdev->dev); |
286 | /* |
287 | * Due to hardware misbehaviour, acknowledge of the stop_req |
288 | * is missing. Hence checking of the status bit skipped. |
289 | */ |
290 | pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ); |
291 | pm_runtime_put_sync(&pdev->dev); |
292 | |
293 | pm_runtime_put_sync(&pdev->dev); |
294 | pm_runtime_disable(&pdev->dev); |
295 | return pwmchip_remove(&pc->chip); |
296 | } |
297 | |
298 | void ecap_pwm_save_context(struct ecap_pwm_chip *pc) |
299 | { |
300 | pm_runtime_get_sync(pc->chip.dev); |
301 | pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2); |
302 | pc->ctx.cap4 = readl(pc->mmio_base + CAP4); |
303 | pc->ctx.cap3 = readl(pc->mmio_base + CAP3); |
304 | pm_runtime_put_sync(pc->chip.dev); |
305 | } |
306 | |
307 | void ecap_pwm_restore_context(struct ecap_pwm_chip *pc) |
308 | { |
309 | writel(pc->ctx.cap3, pc->mmio_base + CAP3); |
310 | writel(pc->ctx.cap4, pc->mmio_base + CAP4); |
311 | writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2); |
312 | } |
313 | |
314 | static int ecap_pwm_suspend(struct device *dev) |
315 | { |
316 | struct ecap_pwm_chip *pc = dev_get_drvdata(dev); |
317 | struct pwm_device *pwm = pc->chip.pwms; |
318 | |
319 | ecap_pwm_save_context(pc); |
320 | |
321 | /* Disable explicitly if PWM is running */ |
322 | if (test_bit(PWMF_ENABLED, &pwm->flags)) |
323 | pm_runtime_put_sync(dev); |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | static int ecap_pwm_resume(struct device *dev) |
329 | { |
330 | struct ecap_pwm_chip *pc = dev_get_drvdata(dev); |
331 | struct pwm_device *pwm = pc->chip.pwms; |
332 | |
333 | /* Enable explicitly if PWM was running */ |
334 | if (test_bit(PWMF_ENABLED, &pwm->flags)) |
335 | pm_runtime_get_sync(dev); |
336 | |
337 | ecap_pwm_restore_context(pc); |
338 | return 0; |
339 | } |
340 | |
341 | static SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume); |
342 | |
343 | static struct platform_driver ecap_pwm_driver = { |
344 | .driver = { |
345 | .name = "ecap", |
346 | .owner = THIS_MODULE, |
347 | .of_match_table = ecap_of_match, |
348 | .pm = &ecap_pwm_pm_ops, |
349 | }, |
350 | .probe = ecap_pwm_probe, |
351 | .remove = ecap_pwm_remove, |
352 | }; |
353 | |
354 | module_platform_driver(ecap_pwm_driver); |
355 | |
356 | MODULE_DESCRIPTION("ECAP PWM driver"); |
357 | MODULE_AUTHOR("Texas Instruments"); |
358 | MODULE_LICENSE("GPL"); |
359 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9