diff options
author | Philip, Avinash <avinashphilip@ti.com> | 2012-11-27 03:48:09 -0500 |
---|---|---|
committer | Thierry Reding <thierry.reding@avionic-design.de> | 2012-11-28 09:16:15 -0500 |
commit | 333b08ee8c6e120d67118e4eb71c45f5c369c8a4 (patch) | |
tree | a2626907a8e7d59010c64f0fb632ec1a428fcf8b | |
parent | af0ba001d208e117b5f4e4f504672b42a664a7f7 (diff) |
pwm: tiecap: Add device-tree binding
This patch
1. Add support for device-tree binding for ECAP APWM driver.
2. Set size of pwm-cells set to 3 to support PWM channel number, PWM
period & polarity configuration from device tree.
3. Add enable/disable clock gating in PWM subsystem common config space.
4. When here set .owner member in platform_driver structure to
THIS_MODULE.
Signed-off-by: Philip, Avinash <avinashphilip@ti.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Rob Landley <rob@landley.net>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-tiecap.txt | 23 | ||||
-rw-r--r-- | drivers/pwm/pwm-tiecap.c | 42 |
2 files changed, 64 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt new file mode 100644 index 000000000000..131e8c11d26f --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | TI SOC ECAP based APWM controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: Must be "ti,am33xx-ecap" | ||
5 | - #pwm-cells: Should be 3. Number of cells being used to specify PWM property. | ||
6 | First cell specifies the per-chip index of the PWM to use, the second | ||
7 | cell is the period in nanoseconds and bit 0 in the third cell is used to | ||
8 | encode the polarity of PWM output. Set bit 0 of the third in PWM specifier | ||
9 | to 1 for inverse polarity & set to 0 for normal polarity. | ||
10 | - reg: physical base address and size of the registers map. | ||
11 | |||
12 | Optional properties: | ||
13 | - ti,hwmods: Name of the hwmod associated to the ECAP: | ||
14 | "ecap<x>", <x> being the 0-based instance number from the HW spec | ||
15 | |||
16 | Example: | ||
17 | |||
18 | ecap0: ecap@0 { | ||
19 | compatible = "ti,am33xx-ecap"; | ||
20 | #pwm-cells = <3>; | ||
21 | reg = <0x48300100 0x80>; | ||
22 | ti,hwmods = "ecap0"; | ||
23 | }; | ||
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index d6d4cf05565e..0f541c5cbe98 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c | |||
@@ -25,6 +25,9 @@ | |||
25 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
26 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
27 | #include <linux/pwm.h> | 27 | #include <linux/pwm.h> |
28 | #include <linux/of_device.h> | ||
29 | |||
30 | #include "pwm-tipwmss.h" | ||
28 | 31 | ||
29 | /* ECAP registers and bits definitions */ | 32 | /* ECAP registers and bits definitions */ |
30 | #define CAP1 0x08 | 33 | #define CAP1 0x08 |
@@ -184,12 +187,19 @@ static const struct pwm_ops ecap_pwm_ops = { | |||
184 | .owner = THIS_MODULE, | 187 | .owner = THIS_MODULE, |
185 | }; | 188 | }; |
186 | 189 | ||
190 | static const struct of_device_id ecap_of_match[] = { | ||
191 | { .compatible = "ti,am33xx-ecap" }, | ||
192 | {}, | ||
193 | }; | ||
194 | MODULE_DEVICE_TABLE(of, ecap_of_match); | ||
195 | |||
187 | static int __devinit ecap_pwm_probe(struct platform_device *pdev) | 196 | static int __devinit ecap_pwm_probe(struct platform_device *pdev) |
188 | { | 197 | { |
189 | int ret; | 198 | int ret; |
190 | struct resource *r; | 199 | struct resource *r; |
191 | struct clk *clk; | 200 | struct clk *clk; |
192 | struct ecap_pwm_chip *pc; | 201 | struct ecap_pwm_chip *pc; |
202 | u16 status; | ||
193 | 203 | ||
194 | pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); | 204 | pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); |
195 | if (!pc) { | 205 | if (!pc) { |
@@ -211,6 +221,8 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) | |||
211 | 221 | ||
212 | pc->chip.dev = &pdev->dev; | 222 | pc->chip.dev = &pdev->dev; |
213 | pc->chip.ops = &ecap_pwm_ops; | 223 | pc->chip.ops = &ecap_pwm_ops; |
224 | pc->chip.of_xlate = of_pwm_xlate_with_flags; | ||
225 | pc->chip.of_pwm_n_cells = 3; | ||
214 | pc->chip.base = -1; | 226 | pc->chip.base = -1; |
215 | pc->chip.npwm = 1; | 227 | pc->chip.npwm = 1; |
216 | 228 | ||
@@ -231,14 +243,40 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) | |||
231 | } | 243 | } |
232 | 244 | ||
233 | pm_runtime_enable(&pdev->dev); | 245 | pm_runtime_enable(&pdev->dev); |
246 | pm_runtime_get_sync(&pdev->dev); | ||
247 | |||
248 | status = pwmss_submodule_state_change(pdev->dev.parent, | ||
249 | PWMSS_ECAPCLK_EN); | ||
250 | if (!(status & PWMSS_ECAPCLK_EN_ACK)) { | ||
251 | dev_err(&pdev->dev, "PWMSS config space clock enable failed\n"); | ||
252 | ret = -EINVAL; | ||
253 | goto pwmss_clk_failure; | ||
254 | } | ||
255 | |||
256 | pm_runtime_put_sync(&pdev->dev); | ||
257 | |||
234 | platform_set_drvdata(pdev, pc); | 258 | platform_set_drvdata(pdev, pc); |
235 | return 0; | 259 | return 0; |
260 | |||
261 | pwmss_clk_failure: | ||
262 | pm_runtime_put_sync(&pdev->dev); | ||
263 | pm_runtime_disable(&pdev->dev); | ||
264 | pwmchip_remove(&pc->chip); | ||
265 | return ret; | ||
236 | } | 266 | } |
237 | 267 | ||
238 | static int __devexit ecap_pwm_remove(struct platform_device *pdev) | 268 | static int __devexit ecap_pwm_remove(struct platform_device *pdev) |
239 | { | 269 | { |
240 | struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); | 270 | struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); |
241 | 271 | ||
272 | pm_runtime_get_sync(&pdev->dev); | ||
273 | /* | ||
274 | * Due to hardware misbehaviour, acknowledge of the stop_req | ||
275 | * is missing. Hence checking of the status bit skipped. | ||
276 | */ | ||
277 | pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ); | ||
278 | pm_runtime_put_sync(&pdev->dev); | ||
279 | |||
242 | pm_runtime_put_sync(&pdev->dev); | 280 | pm_runtime_put_sync(&pdev->dev); |
243 | pm_runtime_disable(&pdev->dev); | 281 | pm_runtime_disable(&pdev->dev); |
244 | return pwmchip_remove(&pc->chip); | 282 | return pwmchip_remove(&pc->chip); |
@@ -246,7 +284,9 @@ static int __devexit ecap_pwm_remove(struct platform_device *pdev) | |||
246 | 284 | ||
247 | static struct platform_driver ecap_pwm_driver = { | 285 | static struct platform_driver ecap_pwm_driver = { |
248 | .driver = { | 286 | .driver = { |
249 | .name = "ecap", | 287 | .name = "ecap", |
288 | .owner = THIS_MODULE, | ||
289 | .of_match_table = ecap_of_match, | ||
250 | }, | 290 | }, |
251 | .probe = ecap_pwm_probe, | 291 | .probe = ecap_pwm_probe, |
252 | .remove = __devexit_p(ecap_pwm_remove), | 292 | .remove = __devexit_p(ecap_pwm_remove), |