aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-19 11:19:07 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-19 11:19:07 -0500
commit74779e22261172ea728b989310f6ecc991b57d62 (patch)
treea6c71e02bf6cefc9e0d261dd1ab11f4a7433ed92
parent5031a2a7c12b837a0913c4139ebeb6bbff5e1aa5 (diff)
parent20e8ac3eea4dcfeea6ebeae57cd2c739fa48da11 (diff)
Merge tag 'for-3.8-rc1' of git://gitorious.org/linux-pwm/linux-pwm
Pull pwm changes from Thierry Reding: "A new driver has been added for the SPEAr platform and the TWL4030/6030 driver has been replaced by two drivers that control the regular PWMs and the PWM driven LEDs provided by the chips. The vt8500, tiecap, tiehrpwm, i.MX, LPC32xx and Samsung drivers have all been improved and the device tree bindings now support the PWM signal polarity." Fix up trivial conflicts due to __devinit/exit removal. * tag 'for-3.8-rc1' of git://gitorious.org/linux-pwm/linux-pwm: (21 commits) pwm: samsung: add missing s3c->pwm_id assignment pwm: lpc32xx: Set the chip base for dynamic allocation pwm: lpc32xx: Properly disable the clock on device removal pwm: lpc32xx: Fix the PWM polarity pwm: i.MX: eliminate build warning pwm: Export of_pwm_xlate_with_flags() pwm: Remove pwm-twl6030 driver pwm: New driver to support PWM driven LEDs on TWL4030/6030 series of PMICs pwm: New driver to support PWMs on TWL4030/6030 series of PMICs pwm: pwm-tiehrpwm: pinctrl support pwm: tiehrpwm: Add device-tree binding pwm: pwm-tiehrpwm: Adding TBCLK gating support. pwm: pwm-tiecap: pinctrl support pwm: tiecap: Add device-tree binding pwm: Add TI PWM subsystem driver pwm: Device tree support for PWM polarity pwm: vt8500: Ensure PWM clock is enabled during pwm_config pwm: vt8500: Fix build error pwm: spear: Staticize spear_pwm_config() pwm: Add SPEAr PWM chip driver support ...
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-tiecap.txt23
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt23
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt31
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/spear-pwm.txt18
-rw-r--r--Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/vt8500-pwm.txt17
-rw-r--r--drivers/pwm/Kconfig39
-rw-r--r--drivers/pwm/Makefile5
-rw-r--r--drivers/pwm/core.c29
-rw-r--r--drivers/pwm/pwm-imx.c2
-rw-r--r--drivers/pwm/pwm-lpc32xx.c23
-rw-r--r--drivers/pwm/pwm-samsung.c1
-rw-r--r--drivers/pwm/pwm-spear.c276
-rw-r--r--drivers/pwm/pwm-tiecap.c48
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c62
-rw-r--r--drivers/pwm/pwm-tipwmss.c139
-rw-r--r--drivers/pwm/pwm-tipwmss.h39
-rw-r--r--drivers/pwm/pwm-twl-led.c344
-rw-r--r--drivers/pwm/pwm-twl.c359
-rw-r--r--drivers/pwm/pwm-twl6030.c184
-rw-r--r--drivers/pwm/pwm-vt8500.c98
-rw-r--r--include/linux/pwm.h3
24 files changed, 1593 insertions, 221 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 @@
1TI SOC ECAP based APWM controller
2
3Required 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
12Optional 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
16Example:
17
18ecap0: ecap@0 {
19 compatible = "ti,am33xx-ecap";
20 #pwm-cells = <3>;
21 reg = <0x48300100 0x80>;
22 ti,hwmods = "ecap0";
23};
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
new file mode 100644
index 000000000000..4fc7079d822e
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
@@ -0,0 +1,23 @@
1TI SOC EHRPWM based PWM controller
2
3Required properties:
4- compatible : Must be "ti,am33xx-ehrpwm"
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
12Optional properties:
13- ti,hwmods: Name of the hwmod associated to the EHRPWM:
14 "ehrpwm<x>", <x> being the 0-based instance number from the HW spec
15
16Example:
17
18ehrpwm0: ehrpwm@0 {
19 compatible = "ti,am33xx-ehrpwm";
20 #pwm-cells = <3>;
21 reg = <0x48300200 0x100>;
22 ti,hwmods = "ehrpwm0";
23};
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
new file mode 100644
index 000000000000..f7eae77f8354
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
@@ -0,0 +1,31 @@
1TI SOC based PWM Subsystem
2
3Required properties:
4- compatible: Must be "ti,am33xx-pwmss";
5- reg: physical base address and size of the registers map.
6- address-cells: Specify the number of u32 entries needed in child nodes.
7 Should set to 1.
8- size-cells: specify number of u32 entries needed to specify child nodes size
9 in reg property. Should set to 1.
10- ranges: describes the address mapping of a memory-mapped bus. Should set to
11 physical address map of child's base address, physical address within
12 parent's address space and length of the address map. For am33xx,
13 3 set of child register maps present, ECAP register space, EQEP
14 register space, EHRPWM register space.
15
16Also child nodes should also populated under PWMSS DT node.
17
18Example:
19pwmss0: pwmss@48300000 {
20 compatible = "ti,am33xx-pwmss";
21 reg = <0x48300000 0x10>;
22 ti,hwmods = "epwmss0";
23 #address-cells = <1>;
24 #size-cells = <1>;
25 status = "disabled";
26 ranges = <0x48300100 0x48300100 0x80 /* ECAP */
27 0x48300180 0x48300180 0x80 /* EQEP */
28 0x48300200 0x48300200 0x80>; /* EHRPWM */
29
30 /* child nodes go here */
31};
diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt
index 73ec962bfe8c..06e67247859a 100644
--- a/Documentation/devicetree/bindings/pwm/pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm.txt
@@ -37,10 +37,21 @@ device:
37 pwm-names = "backlight"; 37 pwm-names = "backlight";
38 }; 38 };
39 39
40Note that in the example above, specifying the "pwm-names" is redundant
41because the name "backlight" would be used as fallback anyway.
42
40pwm-specifier typically encodes the chip-relative PWM number and the PWM 43pwm-specifier typically encodes the chip-relative PWM number and the PWM
41period in nanoseconds. Note that in the example above, specifying the 44period in nanoseconds.
42"pwm-names" is redundant because the name "backlight" would be used as 45
43fallback anyway. 46Optionally, the pwm-specifier can encode a number of flags in a third cell:
47- bit 0: PWM signal polarity (0: normal polarity, 1: inverse polarity)
48
49Example with optional PWM specifier for inverse polarity
50
51 bl: backlight {
52 pwms = <&pwm 0 5000000 1>;
53 pwm-names = "backlight";
54 };
44 55
452) PWM controller nodes 562) PWM controller nodes
46----------------------- 57-----------------------
diff --git a/Documentation/devicetree/bindings/pwm/spear-pwm.txt b/Documentation/devicetree/bindings/pwm/spear-pwm.txt
new file mode 100644
index 000000000000..3ac779d83386
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/spear-pwm.txt
@@ -0,0 +1,18 @@
1== ST SPEAr SoC PWM controller ==
2
3Required properties:
4- compatible: should be one of:
5 - "st,spear320-pwm"
6 - "st,spear1340-pwm"
7- reg: physical base address and length of the controller's registers
8- #pwm-cells: number of cells used to specify PWM which is fixed to 2 on
9 SPEAr. The first cell specifies the per-chip index of the PWM to use and
10 the second cell is the period in nanoseconds.
11
12Example:
13
14 pwm: pwm@a8000000 {
15 compatible ="st,spear320-pwm";
16 reg = <0xa8000000 0x1000>;
17 #pwm-cells = <2>;
18 };
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
new file mode 100644
index 000000000000..2943ee5fce00
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
@@ -0,0 +1,17 @@
1Texas Instruments TWL series PWM drivers
2
3Supported PWMs:
4On TWL4030 series: PWM1 and PWM2
5On TWL6030 series: PWM0 and PWM1
6
7Required properties:
8- compatible: "ti,twl4030-pwm" or "ti,twl6030-pwm"
9- #pwm-cells: should be 2. The first cell specifies the per-chip index
10 of the PWM to use and the second cell is the period in nanoseconds.
11
12Example:
13
14twl_pwm: pwm {
15 compatible = "ti,twl6030-pwm";
16 #pwm-cells = <2>;
17};
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
new file mode 100644
index 000000000000..cb64f3acc10f
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
@@ -0,0 +1,17 @@
1Texas Instruments TWL series PWM drivers connected to LED terminals
2
3Supported PWMs:
4On TWL4030 series: PWMA and PWMB (connected to LEDA and LEDB terminals)
5On TWL6030 series: LED PWM (mainly used as charging indicator LED)
6
7Required properties:
8- compatible: "ti,twl4030-pwmled" or "ti,twl6030-pwmled"
9- #pwm-cells: should be 2. The first cell specifies the per-chip index
10 of the PWM to use and the second cell is the period in nanoseconds.
11
12Example:
13
14twl_pwmled: pwmled {
15 compatible = "ti,twl6030-pwmled";
16 #pwm-cells = <2>;
17};
diff --git a/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
new file mode 100644
index 000000000000..bcc63678a9a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
@@ -0,0 +1,17 @@
1VIA/Wondermedia VT8500/WM8xxx series SoC PWM controller
2
3Required properties:
4- compatible: should be "via,vt8500-pwm"
5- reg: physical base address and length of the controller's registers
6- #pwm-cells: should be 2. The first cell specifies the per-chip index
7 of the PWM to use and the second cell is the period in nanoseconds.
8- clocks: phandle to the PWM source clock
9
10Example:
11
12pwm1: pwm@d8220000 {
13 #pwm-cells = <2>;
14 compatible = "via,vt8500-pwm";
15 reg = <0xd8220000 0x1000>;
16 clocks = <&clkpwm>;
17};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index ed81720e7b2b..e513cd998170 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -112,6 +112,17 @@ config PWM_SAMSUNG
112 To compile this driver as a module, choose M here: the module 112 To compile this driver as a module, choose M here: the module
113 will be called pwm-samsung. 113 will be called pwm-samsung.
114 114
115config PWM_SPEAR
116 tristate "STMicroelectronics SPEAr PWM support"
117 depends on PLAT_SPEAR
118 depends on OF
119 help
120 Generic PWM framework driver for the PWM controller on ST
121 SPEAr SoCs.
122
123 To compile this driver as a module, choose M here: the module
124 will be called pwm-spear.
125
115config PWM_TEGRA 126config PWM_TEGRA
116 tristate "NVIDIA Tegra PWM support" 127 tristate "NVIDIA Tegra PWM support"
117 depends on ARCH_TEGRA 128 depends on ARCH_TEGRA
@@ -125,6 +136,7 @@ config PWM_TEGRA
125config PWM_TIECAP 136config PWM_TIECAP
126 tristate "ECAP PWM support" 137 tristate "ECAP PWM support"
127 depends on SOC_AM33XX 138 depends on SOC_AM33XX
139 select PWM_TIPWMSS
128 help 140 help
129 PWM driver support for the ECAP APWM controller found on AM33XX 141 PWM driver support for the ECAP APWM controller found on AM33XX
130 TI SOC 142 TI SOC
@@ -135,6 +147,7 @@ config PWM_TIECAP
135config PWM_TIEHRPWM 147config PWM_TIEHRPWM
136 tristate "EHRPWM PWM support" 148 tristate "EHRPWM PWM support"
137 depends on SOC_AM33XX 149 depends on SOC_AM33XX
150 select PWM_TIPWMSS
138 help 151 help
139 PWM driver support for the EHRPWM controller found on AM33XX 152 PWM driver support for the EHRPWM controller found on AM33XX
140 TI SOC 153 TI SOC
@@ -142,14 +155,32 @@ config PWM_TIEHRPWM
142 To compile this driver as a module, choose M here: the module 155 To compile this driver as a module, choose M here: the module
143 will be called pwm-tiehrpwm. 156 will be called pwm-tiehrpwm.
144 157
145config PWM_TWL6030 158config PWM_TIPWMSS
146 tristate "TWL6030 PWM support" 159 bool
160 depends on SOC_AM33XX && (PWM_TIEHRPWM || PWM_TIECAP)
161 help
162 PWM Subsystem driver support for AM33xx SOC.
163
164 PWM submodules require PWM config space access from submodule
165 drivers and require common parent driver support.
166
167config PWM_TWL
168 tristate "TWL4030/6030 PWM support"
169 depends on TWL4030_CORE
170 help
171 Generic PWM framework driver for TWL4030/6030.
172
173 To compile this driver as a module, choose M here: the module
174 will be called pwm-twl.
175
176config PWM_TWL_LED
177 tristate "TWL4030/6030 PWM support for LED drivers"
147 depends on TWL4030_CORE 178 depends on TWL4030_CORE
148 help 179 help
149 Generic PWM framework driver for TWL6030. 180 Generic PWM framework driver for TWL4030/6030 LED terminals.
150 181
151 To compile this driver as a module, choose M here: the module 182 To compile this driver as a module, choose M here: the module
152 will be called pwm-twl6030. 183 will be called pwm-twl-led.
153 184
154config PWM_VT8500 185config PWM_VT8500
155 tristate "vt8500 pwm support" 186 tristate "vt8500 pwm support"
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index acfe4821c58b..62a2963cfe58 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -8,8 +8,11 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
8obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o 8obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
9obj-$(CONFIG_PWM_PXA) += pwm-pxa.o 9obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
10obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o 10obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
11obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
11obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o 12obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
12obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o 13obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
13obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o 14obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
14obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o 15obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o
16obj-$(CONFIG_PWM_TWL) += pwm-twl.o
17obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o
15obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o 18obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index f5acdaa52707..903138b18842 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -32,6 +32,9 @@
32 32
33#define MAX_PWMS 1024 33#define MAX_PWMS 1024
34 34
35/* flags in the third cell of the DT PWM specifier */
36#define PWM_SPEC_POLARITY (1 << 0)
37
35static DEFINE_MUTEX(pwm_lookup_lock); 38static DEFINE_MUTEX(pwm_lookup_lock);
36static LIST_HEAD(pwm_lookup_list); 39static LIST_HEAD(pwm_lookup_list);
37static DEFINE_MUTEX(pwm_lock); 40static DEFINE_MUTEX(pwm_lock);
@@ -129,6 +132,32 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
129 return 0; 132 return 0;
130} 133}
131 134
135struct pwm_device *
136of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
137{
138 struct pwm_device *pwm;
139
140 if (pc->of_pwm_n_cells < 3)
141 return ERR_PTR(-EINVAL);
142
143 if (args->args[0] >= pc->npwm)
144 return ERR_PTR(-EINVAL);
145
146 pwm = pwm_request_from_chip(pc, args->args[0], NULL);
147 if (IS_ERR(pwm))
148 return pwm;
149
150 pwm_set_period(pwm, args->args[1]);
151
152 if (args->args[2] & PWM_SPEC_POLARITY)
153 pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
154 else
155 pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
156
157 return pwm;
158}
159EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
160
132static struct pwm_device * 161static struct pwm_device *
133of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) 162of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
134{ 163{
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 8f26e9fcea97..65a86bdeabed 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -235,7 +235,7 @@ static int imx_pwm_probe(struct platform_device *pdev)
235{ 235{
236 const struct of_device_id *of_id = 236 const struct of_device_id *of_id =
237 of_match_device(imx_pwm_dt_ids, &pdev->dev); 237 of_match_device(imx_pwm_dt_ids, &pdev->dev);
238 struct imx_pwm_data *data; 238 const struct imx_pwm_data *data;
239 struct imx_chip *imx; 239 struct imx_chip *imx;
240 struct resource *r; 240 struct resource *r;
241 int ret = 0; 241 int ret = 0;
diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c
index 015a82235620..14106440294f 100644
--- a/drivers/pwm/pwm-lpc32xx.c
+++ b/drivers/pwm/pwm-lpc32xx.c
@@ -49,9 +49,24 @@ static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
49 c = 0; /* 0 set division by 256 */ 49 c = 0; /* 0 set division by 256 */
50 period_cycles = c; 50 period_cycles = c;
51 51
52 /* The duty-cycle value is as follows:
53 *
54 * DUTY-CYCLE HIGH LEVEL
55 * 1 99.9%
56 * 25 90.0%
57 * 128 50.0%
58 * 220 10.0%
59 * 255 0.1%
60 * 0 0.0%
61 *
62 * In other words, the register value is duty-cycle % 256 with
63 * duty-cycle in the range 1-256.
64 */
52 c = 256 * duty_ns; 65 c = 256 * duty_ns;
53 do_div(c, period_ns); 66 do_div(c, period_ns);
54 duty_cycles = c; 67 if (c > 255)
68 c = 255;
69 duty_cycles = 256 - c;
55 70
56 writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles), 71 writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles),
57 lpc32xx->base + (pwm->hwpwm << 2)); 72 lpc32xx->base + (pwm->hwpwm << 2));
@@ -106,6 +121,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
106 lpc32xx->chip.dev = &pdev->dev; 121 lpc32xx->chip.dev = &pdev->dev;
107 lpc32xx->chip.ops = &lpc32xx_pwm_ops; 122 lpc32xx->chip.ops = &lpc32xx_pwm_ops;
108 lpc32xx->chip.npwm = 2; 123 lpc32xx->chip.npwm = 2;
124 lpc32xx->chip.base = -1;
109 125
110 ret = pwmchip_add(&lpc32xx->chip); 126 ret = pwmchip_add(&lpc32xx->chip);
111 if (ret < 0) { 127 if (ret < 0) {
@@ -121,8 +137,11 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
121static int lpc32xx_pwm_remove(struct platform_device *pdev) 137static int lpc32xx_pwm_remove(struct platform_device *pdev)
122{ 138{
123 struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev); 139 struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev);
140 unsigned int i;
141
142 for (i = 0; i < lpc32xx->chip.npwm; i++)
143 pwm_disable(&lpc32xx->chip.pwms[i]);
124 144
125 clk_disable(lpc32xx->clk);
126 return pwmchip_remove(&lpc32xx->chip); 145 return pwmchip_remove(&lpc32xx->chip);
127} 146}
128 147
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index e9b15d099c03..5207e6cd8648 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -222,6 +222,7 @@ static int s3c_pwm_probe(struct platform_device *pdev)
222 222
223 /* calculate base of control bits in TCON */ 223 /* calculate base of control bits in TCON */
224 s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4; 224 s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4;
225 s3c->pwm_id = id;
225 s3c->chip.dev = &pdev->dev; 226 s3c->chip.dev = &pdev->dev;
226 s3c->chip.ops = &s3c_pwm_ops; 227 s3c->chip.ops = &s3c_pwm_ops;
227 s3c->chip.base = -1; 228 s3c->chip.base = -1;
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
new file mode 100644
index 000000000000..83b21d9d5cf9
--- /dev/null
+++ b/drivers/pwm/pwm-spear.c
@@ -0,0 +1,276 @@
1/*
2 * ST Microelectronics SPEAr Pulse Width Modulator driver
3 *
4 * Copyright (C) 2012 ST Microelectronics
5 * Shiraz Hashim <shiraz.hashim@st.com>
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include <linux/clk.h>
13#include <linux/err.h>
14#include <linux/io.h>
15#include <linux/ioport.h>
16#include <linux/kernel.h>
17#include <linux/math64.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/platform_device.h>
21#include <linux/pwm.h>
22#include <linux/slab.h>
23#include <linux/types.h>
24
25#define NUM_PWM 4
26
27/* PWM registers and bits definitions */
28#define PWMCR 0x00 /* Control Register */
29#define PWMCR_PWM_ENABLE 0x1
30#define PWMCR_PRESCALE_SHIFT 2
31#define PWMCR_MIN_PRESCALE 0x00
32#define PWMCR_MAX_PRESCALE 0x3FFF
33
34#define PWMDCR 0x04 /* Duty Cycle Register */
35#define PWMDCR_MIN_DUTY 0x0001
36#define PWMDCR_MAX_DUTY 0xFFFF
37
38#define PWMPCR 0x08 /* Period Register */
39#define PWMPCR_MIN_PERIOD 0x0001
40#define PWMPCR_MAX_PERIOD 0xFFFF
41
42/* Following only available on 13xx SoCs */
43#define PWMMCR 0x3C /* Master Control Register */
44#define PWMMCR_PWM_ENABLE 0x1
45
46/**
47 * struct spear_pwm_chip - struct representing pwm chip
48 *
49 * @mmio_base: base address of pwm chip
50 * @clk: pointer to clk structure of pwm chip
51 * @chip: linux pwm chip representation
52 * @dev: pointer to device structure of pwm chip
53 */
54struct spear_pwm_chip {
55 void __iomem *mmio_base;
56 struct clk *clk;
57 struct pwm_chip chip;
58 struct device *dev;
59};
60
61static inline struct spear_pwm_chip *to_spear_pwm_chip(struct pwm_chip *chip)
62{
63 return container_of(chip, struct spear_pwm_chip, chip);
64}
65
66static inline u32 spear_pwm_readl(struct spear_pwm_chip *chip, unsigned int num,
67 unsigned long offset)
68{
69 return readl_relaxed(chip->mmio_base + (num << 4) + offset);
70}
71
72static inline void spear_pwm_writel(struct spear_pwm_chip *chip,
73 unsigned int num, unsigned long offset,
74 unsigned long val)
75{
76 writel_relaxed(val, chip->mmio_base + (num << 4) + offset);
77}
78
79static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
80 int duty_ns, int period_ns)
81{
82 struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
83 u64 val, div, clk_rate;
84 unsigned long prescale = PWMCR_MIN_PRESCALE, pv, dc;
85 int ret;
86
87 /*
88 * Find pv, dc and prescale to suit duty_ns and period_ns. This is done
89 * according to formulas described below:
90 *
91 * period_ns = 10^9 * (PRESCALE + 1) * PV / PWM_CLK_RATE
92 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
93 *
94 * PV = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
95 * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
96 */
97 clk_rate = clk_get_rate(pc->clk);
98 while (1) {
99 div = 1000000000;
100 div *= 1 + prescale;
101 val = clk_rate * period_ns;
102 pv = div64_u64(val, div);
103 val = clk_rate * duty_ns;
104 dc = div64_u64(val, div);
105
106 /* if duty_ns and period_ns are not achievable then return */
107 if (pv < PWMPCR_MIN_PERIOD || dc < PWMDCR_MIN_DUTY)
108 return -EINVAL;
109
110 /*
111 * if pv and dc have crossed their upper limit, then increase
112 * prescale and recalculate pv and dc.
113 */
114 if (pv > PWMPCR_MAX_PERIOD || dc > PWMDCR_MAX_DUTY) {
115 if (++prescale > PWMCR_MAX_PRESCALE)
116 return -EINVAL;
117 continue;
118 }
119 break;
120 }
121
122 /*
123 * NOTE: the clock to PWM has to be enabled first before writing to the
124 * registers.
125 */
126 ret = clk_enable(pc->clk);
127 if (ret)
128 return ret;
129
130 spear_pwm_writel(pc, pwm->hwpwm, PWMCR,
131 prescale << PWMCR_PRESCALE_SHIFT);
132 spear_pwm_writel(pc, pwm->hwpwm, PWMDCR, dc);
133 spear_pwm_writel(pc, pwm->hwpwm, PWMPCR, pv);
134 clk_disable(pc->clk);
135
136 return 0;
137}
138
139static int spear_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
140{
141 struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
142 int rc = 0;
143 u32 val;
144
145 rc = clk_enable(pc->clk);
146 if (!rc)
147 return rc;
148
149 val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR);
150 val |= PWMCR_PWM_ENABLE;
151 spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val);
152
153 return 0;
154}
155
156static void spear_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
157{
158 struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
159 u32 val;
160
161 val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR);
162 val &= ~PWMCR_PWM_ENABLE;
163 spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val);
164
165 clk_disable(pc->clk);
166}
167
168static const struct pwm_ops spear_pwm_ops = {
169 .config = spear_pwm_config,
170 .enable = spear_pwm_enable,
171 .disable = spear_pwm_disable,
172 .owner = THIS_MODULE,
173};
174
175static int spear_pwm_probe(struct platform_device *pdev)
176{
177 struct device_node *np = pdev->dev.of_node;
178 struct spear_pwm_chip *pc;
179 struct resource *r;
180 int ret;
181 u32 val;
182
183 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
184 if (!r) {
185 dev_err(&pdev->dev, "no memory resources defined\n");
186 return -ENODEV;
187 }
188
189 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
190 if (!pc) {
191 dev_err(&pdev->dev, "failed to allocate memory\n");
192 return -ENOMEM;
193 }
194
195 pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
196 if (!pc->mmio_base)
197 return -EADDRNOTAVAIL;
198
199 pc->clk = devm_clk_get(&pdev->dev, NULL);
200 if (IS_ERR(pc->clk))
201 return PTR_ERR(pc->clk);
202
203 pc->dev = &pdev->dev;
204 platform_set_drvdata(pdev, pc);
205
206 pc->chip.dev = &pdev->dev;
207 pc->chip.ops = &spear_pwm_ops;
208 pc->chip.base = -1;
209 pc->chip.npwm = NUM_PWM;
210
211 ret = clk_prepare(pc->clk);
212 if (!ret)
213 return ret;
214
215 if (of_device_is_compatible(np, "st,spear1340-pwm")) {
216 ret = clk_enable(pc->clk);
217 if (!ret) {
218 clk_unprepare(pc->clk);
219 return ret;
220 }
221 /*
222 * Following enables PWM chip, channels would still be
223 * enabled individually through their control register
224 */
225 val = readl_relaxed(pc->mmio_base + PWMMCR);
226 val |= PWMMCR_PWM_ENABLE;
227 writel_relaxed(val, pc->mmio_base + PWMMCR);
228
229 clk_disable(pc->clk);
230 }
231
232 ret = pwmchip_add(&pc->chip);
233 if (!ret) {
234 clk_unprepare(pc->clk);
235 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
236 }
237
238 return ret;
239}
240
241static int spear_pwm_remove(struct platform_device *pdev)
242{
243 struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
244 int i;
245
246 for (i = 0; i < NUM_PWM; i++)
247 pwm_disable(&pc->chip.pwms[i]);
248
249 /* clk was prepared in probe, hence unprepare it here */
250 clk_unprepare(pc->clk);
251 return pwmchip_remove(&pc->chip);
252}
253
254static struct of_device_id spear_pwm_of_match[] = {
255 { .compatible = "st,spear320-pwm" },
256 { .compatible = "st,spear1340-pwm" },
257 { }
258};
259
260MODULE_DEVICE_TABLE(of, spear_pwm_of_match);
261
262static struct platform_driver spear_pwm_driver = {
263 .driver = {
264 .name = "spear-pwm",
265 .of_match_table = spear_pwm_of_match,
266 },
267 .probe = spear_pwm_probe,
268 .remove = spear_pwm_remove,
269};
270
271module_platform_driver(spear_pwm_driver);
272
273MODULE_LICENSE("GPL");
274MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>");
275MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.com>");
276MODULE_ALIAS("platform:spear-pwm");
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 87c091b245cc..5cf016dd9822 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -25,6 +25,10 @@
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#include <linux/pinctrl/consumer.h>
30
31#include "pwm-tipwmss.h"
28 32
29/* ECAP registers and bits definitions */ 33/* ECAP registers and bits definitions */
30#define CAP1 0x08 34#define CAP1 0x08
@@ -184,12 +188,24 @@ static const struct pwm_ops ecap_pwm_ops = {
184 .owner = THIS_MODULE, 188 .owner = THIS_MODULE,
185}; 189};
186 190
191static const struct of_device_id ecap_of_match[] = {
192 { .compatible = "ti,am33xx-ecap" },
193 {},
194};
195MODULE_DEVICE_TABLE(of, ecap_of_match);
196
187static int ecap_pwm_probe(struct platform_device *pdev) 197static int ecap_pwm_probe(struct platform_device *pdev)
188{ 198{
189 int ret; 199 int ret;
190 struct resource *r; 200 struct resource *r;
191 struct clk *clk; 201 struct clk *clk;
192 struct ecap_pwm_chip *pc; 202 struct ecap_pwm_chip *pc;
203 u16 status;
204 struct pinctrl *pinctrl;
205
206 pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
207 if (IS_ERR(pinctrl))
208 dev_warn(&pdev->dev, "unable to select pin group\n");
193 209
194 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 210 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
195 if (!pc) { 211 if (!pc) {
@@ -211,6 +227,8 @@ static int ecap_pwm_probe(struct platform_device *pdev)
211 227
212 pc->chip.dev = &pdev->dev; 228 pc->chip.dev = &pdev->dev;
213 pc->chip.ops = &ecap_pwm_ops; 229 pc->chip.ops = &ecap_pwm_ops;
230 pc->chip.of_xlate = of_pwm_xlate_with_flags;
231 pc->chip.of_pwm_n_cells = 3;
214 pc->chip.base = -1; 232 pc->chip.base = -1;
215 pc->chip.npwm = 1; 233 pc->chip.npwm = 1;
216 234
@@ -231,14 +249,40 @@ static int ecap_pwm_probe(struct platform_device *pdev)
231 } 249 }
232 250
233 pm_runtime_enable(&pdev->dev); 251 pm_runtime_enable(&pdev->dev);
252 pm_runtime_get_sync(&pdev->dev);
253
254 status = pwmss_submodule_state_change(pdev->dev.parent,
255 PWMSS_ECAPCLK_EN);
256 if (!(status & PWMSS_ECAPCLK_EN_ACK)) {
257 dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
258 ret = -EINVAL;
259 goto pwmss_clk_failure;
260 }
261
262 pm_runtime_put_sync(&pdev->dev);
263
234 platform_set_drvdata(pdev, pc); 264 platform_set_drvdata(pdev, pc);
235 return 0; 265 return 0;
266
267pwmss_clk_failure:
268 pm_runtime_put_sync(&pdev->dev);
269 pm_runtime_disable(&pdev->dev);
270 pwmchip_remove(&pc->chip);
271 return ret;
236} 272}
237 273
238static int ecap_pwm_remove(struct platform_device *pdev) 274static int ecap_pwm_remove(struct platform_device *pdev)
239{ 275{
240 struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); 276 struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);
241 277
278 pm_runtime_get_sync(&pdev->dev);
279 /*
280 * Due to hardware misbehaviour, acknowledge of the stop_req
281 * is missing. Hence checking of the status bit skipped.
282 */
283 pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ);
284 pm_runtime_put_sync(&pdev->dev);
285
242 pm_runtime_put_sync(&pdev->dev); 286 pm_runtime_put_sync(&pdev->dev);
243 pm_runtime_disable(&pdev->dev); 287 pm_runtime_disable(&pdev->dev);
244 return pwmchip_remove(&pc->chip); 288 return pwmchip_remove(&pc->chip);
@@ -246,7 +290,9 @@ static int ecap_pwm_remove(struct platform_device *pdev)
246 290
247static struct platform_driver ecap_pwm_driver = { 291static struct platform_driver ecap_pwm_driver = {
248 .driver = { 292 .driver = {
249 .name = "ecap", 293 .name = "ecap",
294 .owner = THIS_MODULE,
295 .of_match_table = ecap_of_match,
250 }, 296 },
251 .probe = ecap_pwm_probe, 297 .probe = ecap_pwm_probe,
252 .remove = ecap_pwm_remove, 298 .remove = ecap_pwm_remove,
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 9ffd389d0c8b..72a6dd40c9ec 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -25,6 +25,10 @@
25#include <linux/err.h> 25#include <linux/err.h>
26#include <linux/clk.h> 26#include <linux/clk.h>
27#include <linux/pm_runtime.h> 27#include <linux/pm_runtime.h>
28#include <linux/of_device.h>
29#include <linux/pinctrl/consumer.h>
30
31#include "pwm-tipwmss.h"
28 32
29/* EHRPWM registers and bits definitions */ 33/* EHRPWM registers and bits definitions */
30 34
@@ -115,6 +119,7 @@ struct ehrpwm_pwm_chip {
115 void __iomem *mmio_base; 119 void __iomem *mmio_base;
116 unsigned long period_cycles[NUM_PWM_CHANNEL]; 120 unsigned long period_cycles[NUM_PWM_CHANNEL];
117 enum pwm_polarity polarity[NUM_PWM_CHANNEL]; 121 enum pwm_polarity polarity[NUM_PWM_CHANNEL];
122 struct clk *tbclk;
118}; 123};
119 124
120static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) 125static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -335,6 +340,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
335 /* Channels polarity can be configured from action qualifier module */ 340 /* Channels polarity can be configured from action qualifier module */
336 configure_polarity(pc, pwm->hwpwm); 341 configure_polarity(pc, pwm->hwpwm);
337 342
343 /* Enable TBCLK before enabling PWM device */
344 clk_enable(pc->tbclk);
345
338 /* Enable time counter for free_run */ 346 /* Enable time counter for free_run */
339 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); 347 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
340 return 0; 348 return 0;
@@ -363,6 +371,9 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
363 371
364 ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); 372 ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
365 373
374 /* Disabling TBCLK on PWM disable */
375 clk_disable(pc->tbclk);
376
366 /* Stop Time base counter */ 377 /* Stop Time base counter */
367 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); 378 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
368 379
@@ -392,12 +403,24 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
392 .owner = THIS_MODULE, 403 .owner = THIS_MODULE,
393}; 404};
394 405
406static const struct of_device_id ehrpwm_of_match[] = {
407 { .compatible = "ti,am33xx-ehrpwm" },
408 {},
409};
410MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
411
395static int ehrpwm_pwm_probe(struct platform_device *pdev) 412static int ehrpwm_pwm_probe(struct platform_device *pdev)
396{ 413{
397 int ret; 414 int ret;
398 struct resource *r; 415 struct resource *r;
399 struct clk *clk; 416 struct clk *clk;
400 struct ehrpwm_pwm_chip *pc; 417 struct ehrpwm_pwm_chip *pc;
418 u16 status;
419 struct pinctrl *pinctrl;
420
421 pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
422 if (IS_ERR(pinctrl))
423 dev_warn(&pdev->dev, "unable to select pin group\n");
401 424
402 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 425 pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
403 if (!pc) { 426 if (!pc) {
@@ -419,6 +442,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
419 442
420 pc->chip.dev = &pdev->dev; 443 pc->chip.dev = &pdev->dev;
421 pc->chip.ops = &ehrpwm_pwm_ops; 444 pc->chip.ops = &ehrpwm_pwm_ops;
445 pc->chip.of_xlate = of_pwm_xlate_with_flags;
446 pc->chip.of_pwm_n_cells = 3;
422 pc->chip.base = -1; 447 pc->chip.base = -1;
423 pc->chip.npwm = NUM_PWM_CHANNEL; 448 pc->chip.npwm = NUM_PWM_CHANNEL;
424 449
@@ -432,6 +457,13 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
432 if (!pc->mmio_base) 457 if (!pc->mmio_base)
433 return -EADDRNOTAVAIL; 458 return -EADDRNOTAVAIL;
434 459
460 /* Acquire tbclk for Time Base EHRPWM submodule */
461 pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
462 if (IS_ERR(pc->tbclk)) {
463 dev_err(&pdev->dev, "Failed to get tbclk\n");
464 return PTR_ERR(pc->tbclk);
465 }
466
435 ret = pwmchip_add(&pc->chip); 467 ret = pwmchip_add(&pc->chip);
436 if (ret < 0) { 468 if (ret < 0) {
437 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 469 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
@@ -439,14 +471,40 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
439 } 471 }
440 472
441 pm_runtime_enable(&pdev->dev); 473 pm_runtime_enable(&pdev->dev);
474 pm_runtime_get_sync(&pdev->dev);
475
476 status = pwmss_submodule_state_change(pdev->dev.parent,
477 PWMSS_EPWMCLK_EN);
478 if (!(status & PWMSS_EPWMCLK_EN_ACK)) {
479 dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
480 ret = -EINVAL;
481 goto pwmss_clk_failure;
482 }
483
484 pm_runtime_put_sync(&pdev->dev);
485
442 platform_set_drvdata(pdev, pc); 486 platform_set_drvdata(pdev, pc);
443 return 0; 487 return 0;
488
489pwmss_clk_failure:
490 pm_runtime_put_sync(&pdev->dev);
491 pm_runtime_disable(&pdev->dev);
492 pwmchip_remove(&pc->chip);
493 return ret;
444} 494}
445 495
446static int ehrpwm_pwm_remove(struct platform_device *pdev) 496static int ehrpwm_pwm_remove(struct platform_device *pdev)
447{ 497{
448 struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); 498 struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
449 499
500 pm_runtime_get_sync(&pdev->dev);
501 /*
502 * Due to hardware misbehaviour, acknowledge of the stop_req
503 * is missing. Hence checking of the status bit skipped.
504 */
505 pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ);
506 pm_runtime_put_sync(&pdev->dev);
507
450 pm_runtime_put_sync(&pdev->dev); 508 pm_runtime_put_sync(&pdev->dev);
451 pm_runtime_disable(&pdev->dev); 509 pm_runtime_disable(&pdev->dev);
452 return pwmchip_remove(&pc->chip); 510 return pwmchip_remove(&pc->chip);
@@ -454,7 +512,9 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
454 512
455static struct platform_driver ehrpwm_pwm_driver = { 513static struct platform_driver ehrpwm_pwm_driver = {
456 .driver = { 514 .driver = {
457 .name = "ehrpwm", 515 .name = "ehrpwm",
516 .owner = THIS_MODULE,
517 .of_match_table = ehrpwm_of_match,
458 }, 518 },
459 .probe = ehrpwm_pwm_probe, 519 .probe = ehrpwm_pwm_probe,
460 .remove = ehrpwm_pwm_remove, 520 .remove = ehrpwm_pwm_remove,
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c
new file mode 100644
index 000000000000..3448a1c88590
--- /dev/null
+++ b/drivers/pwm/pwm-tipwmss.c
@@ -0,0 +1,139 @@
1/*
2 * TI PWM Subsystem driver
3 *
4 * Copyright (C) 2012 Texas Instruments Incorporated - 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 */
17
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/io.h>
21#include <linux/err.h>
22#include <linux/pm_runtime.h>
23#include <linux/of_device.h>
24
25#include "pwm-tipwmss.h"
26
27#define PWMSS_CLKCONFIG 0x8 /* Clock gating reg */
28#define PWMSS_CLKSTATUS 0xc /* Clock gating status reg */
29
30struct pwmss_info {
31 void __iomem *mmio_base;
32 struct mutex pwmss_lock;
33 u16 pwmss_clkconfig;
34};
35
36u16 pwmss_submodule_state_change(struct device *dev, int set)
37{
38 struct pwmss_info *info = dev_get_drvdata(dev);
39 u16 val;
40
41 mutex_lock(&info->pwmss_lock);
42 val = readw(info->mmio_base + PWMSS_CLKCONFIG);
43 val |= set;
44 writew(val , info->mmio_base + PWMSS_CLKCONFIG);
45 mutex_unlock(&info->pwmss_lock);
46
47 return readw(info->mmio_base + PWMSS_CLKSTATUS);
48}
49EXPORT_SYMBOL(pwmss_submodule_state_change);
50
51static const struct of_device_id pwmss_of_match[] = {
52 { .compatible = "ti,am33xx-pwmss" },
53 {},
54};
55MODULE_DEVICE_TABLE(of, pwmss_of_match);
56
57static int pwmss_probe(struct platform_device *pdev)
58{
59 int ret;
60 struct resource *r;
61 struct pwmss_info *info;
62 struct device_node *node = pdev->dev.of_node;
63
64 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
65 if (!info) {
66 dev_err(&pdev->dev, "failed to allocate memory\n");
67 return -ENOMEM;
68 }
69
70 mutex_init(&info->pwmss_lock);
71
72 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
73 if (!r) {
74 dev_err(&pdev->dev, "no memory resource defined\n");
75 return -ENODEV;
76 }
77
78 info->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
79 if (!info->mmio_base)
80 return -EADDRNOTAVAIL;
81
82 pm_runtime_enable(&pdev->dev);
83 pm_runtime_get_sync(&pdev->dev);
84 platform_set_drvdata(pdev, info);
85
86 /* Populate all the child nodes here... */
87 ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
88 if (ret)
89 dev_err(&pdev->dev, "no child node found\n");
90
91 return ret;
92}
93
94static int pwmss_remove(struct platform_device *pdev)
95{
96 struct pwmss_info *info = platform_get_drvdata(pdev);
97
98 pm_runtime_put_sync(&pdev->dev);
99 pm_runtime_disable(&pdev->dev);
100 mutex_destroy(&info->pwmss_lock);
101 return 0;
102}
103
104static int pwmss_suspend(struct device *dev)
105{
106 struct pwmss_info *info = dev_get_drvdata(dev);
107
108 info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG);
109 pm_runtime_put_sync(dev);
110 return 0;
111}
112
113static int pwmss_resume(struct device *dev)
114{
115 struct pwmss_info *info = dev_get_drvdata(dev);
116
117 pm_runtime_get_sync(dev);
118 writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG);
119 return 0;
120}
121
122static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume);
123
124static struct platform_driver pwmss_driver = {
125 .driver = {
126 .name = "pwmss",
127 .owner = THIS_MODULE,
128 .pm = &pwmss_pm_ops,
129 .of_match_table = pwmss_of_match,
130 },
131 .probe = pwmss_probe,
132 .remove = pwmss_remove,
133};
134
135module_platform_driver(pwmss_driver);
136
137MODULE_DESCRIPTION("PWM Subsystem driver");
138MODULE_AUTHOR("Texas Instruments");
139MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-tipwmss.h b/drivers/pwm/pwm-tipwmss.h
new file mode 100644
index 000000000000..11f76a1e266b
--- /dev/null
+++ b/drivers/pwm/pwm-tipwmss.h
@@ -0,0 +1,39 @@
1/*
2 * TI PWM Subsystem driver
3 *
4 * Copyright (C) 2012 Texas Instruments Incorporated - 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 */
17
18#ifndef __TIPWMSS_H
19#define __TIPWMSS_H
20
21#ifdef CONFIG_PWM_TIPWMSS
22/* PWM substem clock gating */
23#define PWMSS_ECAPCLK_EN BIT(0)
24#define PWMSS_ECAPCLK_STOP_REQ BIT(1)
25#define PWMSS_EPWMCLK_EN BIT(8)
26#define PWMSS_EPWMCLK_STOP_REQ BIT(9)
27
28#define PWMSS_ECAPCLK_EN_ACK BIT(0)
29#define PWMSS_EPWMCLK_EN_ACK BIT(8)
30
31extern u16 pwmss_submodule_state_change(struct device *dev, int set);
32#else
33static inline u16 pwmss_submodule_state_change(struct device *dev, int set)
34{
35 /* return success status value */
36 return 0xFFFF;
37}
38#endif
39#endif /* __TIPWMSS_H */
diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
new file mode 100644
index 000000000000..9dfa0f3eca30
--- /dev/null
+++ b/drivers/pwm/pwm-twl-led.c
@@ -0,0 +1,344 @@
1/*
2 * Driver for TWL4030/6030 Pulse Width Modulator used as LED driver
3 *
4 * Copyright (C) 2012 Texas Instruments
5 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
6 *
7 * This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
8 * Hemanth V <hemanthv@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/pwm.h>
26#include <linux/i2c/twl.h>
27#include <linux/slab.h>
28
29/*
30 * This driver handles the PWM driven LED terminals of TWL4030 and TWL6030.
31 * To generate the signal on TWL4030:
32 * - LEDA uses PWMA
33 * - LEDB uses PWMB
34 * TWL6030 has one LED pin with dedicated LEDPWM
35 */
36
37#define TWL4030_LED_MAX 0x7f
38#define TWL6030_LED_MAX 0xff
39
40/* Registers, bits and macro for TWL4030 */
41#define TWL4030_LEDEN_REG 0x00
42#define TWL4030_PWMA_REG 0x01
43
44#define TWL4030_LEDXON (1 << 0)
45#define TWL4030_LEDXPWM (1 << 4)
46#define TWL4030_LED_PINS (TWL4030_LEDXON | TWL4030_LEDXPWM)
47#define TWL4030_LED_TOGGLE(led, x) ((x) << (led))
48
49/* Register, bits and macro for TWL6030 */
50#define TWL6030_LED_PWM_CTRL1 0xf4
51#define TWL6030_LED_PWM_CTRL2 0xf5
52
53#define TWL6040_LED_MODE_HW 0x00
54#define TWL6040_LED_MODE_ON 0x01
55#define TWL6040_LED_MODE_OFF 0x02
56#define TWL6040_LED_MODE_MASK 0x03
57
58struct twl_pwmled_chip {
59 struct pwm_chip chip;
60 struct mutex mutex;
61};
62
63static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip)
64{
65 return container_of(chip, struct twl_pwmled_chip, chip);
66}
67
68static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
69 int duty_ns, int period_ns)
70{
71 int duty_cycle = DIV_ROUND_UP(duty_ns * TWL4030_LED_MAX, period_ns) + 1;
72 u8 pwm_config[2] = { 1, 0 };
73 int base, ret;
74
75 /*
76 * To configure the duty period:
77 * On-cycle is set to 1 (the minimum allowed value)
78 * The off time of 0 is not configurable, so the mapping is:
79 * 0 -> off cycle = 2,
80 * 1 -> off cycle = 2,
81 * 2 -> off cycle = 3,
82 * 126 - > off cycle 127,
83 * 127 - > off cycle 1
84 * When on cycle == off cycle the PWM will be always on
85 */
86 if (duty_cycle == 1)
87 duty_cycle = 2;
88 else if (duty_cycle > TWL4030_LED_MAX)
89 duty_cycle = 1;
90
91 base = pwm->hwpwm * 2 + TWL4030_PWMA_REG;
92
93 pwm_config[1] = duty_cycle;
94
95 ret = twl_i2c_write(TWL4030_MODULE_LED, pwm_config, base, 2);
96 if (ret < 0)
97 dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
98
99 return ret;
100}
101
102static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
103{
104 struct twl_pwmled_chip *twl = to_twl(chip);
105 int ret;
106 u8 val;
107
108 mutex_lock(&twl->mutex);
109 ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
110 if (ret < 0) {
111 dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
112 goto out;
113 }
114
115 val |= TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
116
117 ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
118 if (ret < 0)
119 dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
120
121out:
122 mutex_unlock(&twl->mutex);
123 return ret;
124}
125
126static void twl4030_pwmled_disable(struct pwm_chip *chip,
127 struct pwm_device *pwm)
128{
129 struct twl_pwmled_chip *twl = to_twl(chip);
130 int ret;
131 u8 val;
132
133 mutex_lock(&twl->mutex);
134 ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
135 if (ret < 0) {
136 dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
137 goto out;
138 }
139
140 val &= ~TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
141
142 ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
143 if (ret < 0)
144 dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
145
146out:
147 mutex_unlock(&twl->mutex);
148}
149
150static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
151 int duty_ns, int period_ns)
152{
153 int duty_cycle = (duty_ns * TWL6030_LED_MAX) / period_ns;
154 u8 on_time;
155 int ret;
156
157 on_time = duty_cycle & 0xff;
158
159 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, on_time,
160 TWL6030_LED_PWM_CTRL1);
161 if (ret < 0)
162 dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
163
164 return ret;
165}
166
167static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
168{
169 struct twl_pwmled_chip *twl = to_twl(chip);
170 int ret;
171 u8 val;
172
173 mutex_lock(&twl->mutex);
174 ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
175 if (ret < 0) {
176 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
177 pwm->label);
178 goto out;
179 }
180
181 val &= ~TWL6040_LED_MODE_MASK;
182 val |= TWL6040_LED_MODE_ON;
183
184 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
185 if (ret < 0)
186 dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
187
188out:
189 mutex_unlock(&twl->mutex);
190 return ret;
191}
192
193static void twl6030_pwmled_disable(struct pwm_chip *chip,
194 struct pwm_device *pwm)
195{
196 struct twl_pwmled_chip *twl = to_twl(chip);
197 int ret;
198 u8 val;
199
200 mutex_lock(&twl->mutex);
201 ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
202 if (ret < 0) {
203 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
204 pwm->label);
205 goto out;
206 }
207
208 val &= ~TWL6040_LED_MODE_MASK;
209 val |= TWL6040_LED_MODE_OFF;
210
211 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
212 if (ret < 0)
213 dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
214
215out:
216 mutex_unlock(&twl->mutex);
217}
218
219static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
220{
221 struct twl_pwmled_chip *twl = to_twl(chip);
222 int ret;
223 u8 val;
224
225 mutex_lock(&twl->mutex);
226 ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
227 if (ret < 0) {
228 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
229 pwm->label);
230 goto out;
231 }
232
233 val &= ~TWL6040_LED_MODE_MASK;
234 val |= TWL6040_LED_MODE_OFF;
235
236 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
237 if (ret < 0)
238 dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
239
240out:
241 mutex_unlock(&twl->mutex);
242 return ret;
243}
244
245static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
246{
247 struct twl_pwmled_chip *twl = to_twl(chip);
248 int ret;
249 u8 val;
250
251 mutex_lock(&twl->mutex);
252 ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
253 if (ret < 0) {
254 dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
255 pwm->label);
256 goto out;
257 }
258
259 val &= ~TWL6040_LED_MODE_MASK;
260 val |= TWL6040_LED_MODE_HW;
261
262 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
263 if (ret < 0)
264 dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
265
266out:
267 mutex_unlock(&twl->mutex);
268}
269
270static const struct pwm_ops twl4030_pwmled_ops = {
271 .enable = twl4030_pwmled_enable,
272 .disable = twl4030_pwmled_disable,
273 .config = twl4030_pwmled_config,
274};
275
276static const struct pwm_ops twl6030_pwmled_ops = {
277 .enable = twl6030_pwmled_enable,
278 .disable = twl6030_pwmled_disable,
279 .config = twl6030_pwmled_config,
280 .request = twl6030_pwmled_request,
281 .free = twl6030_pwmled_free,
282};
283
284static int twl_pwmled_probe(struct platform_device *pdev)
285{
286 struct twl_pwmled_chip *twl;
287 int ret;
288
289 twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
290 if (!twl)
291 return -ENOMEM;
292
293 if (twl_class_is_4030()) {
294 twl->chip.ops = &twl4030_pwmled_ops;
295 twl->chip.npwm = 2;
296 } else {
297 twl->chip.ops = &twl6030_pwmled_ops;
298 twl->chip.npwm = 1;
299 }
300
301 twl->chip.dev = &pdev->dev;
302 twl->chip.base = -1;
303
304 mutex_init(&twl->mutex);
305
306 ret = pwmchip_add(&twl->chip);
307 if (ret < 0)
308 return ret;
309
310 platform_set_drvdata(pdev, twl);
311
312 return 0;
313}
314
315static int twl_pwmled_remove(struct platform_device *pdev)
316{
317 struct twl_pwmled_chip *twl = platform_get_drvdata(pdev);
318
319 return pwmchip_remove(&twl->chip);
320}
321
322#ifdef CONFIG_OF
323static struct of_device_id twl_pwmled_of_match[] = {
324 { .compatible = "ti,twl4030-pwmled" },
325 { .compatible = "ti,twl6030-pwmled" },
326 { },
327};
328MODULE_DEVICE_TABLE(of, twl_pwmled_of_match);
329#endif
330
331static struct platform_driver twl_pwmled_driver = {
332 .driver = {
333 .name = "twl-pwmled",
334 .of_match_table = of_match_ptr(twl_pwmled_of_match),
335 },
336 .probe = twl_pwmled_probe,
337 .remove = twl_pwmled_remove,
338};
339module_platform_driver(twl_pwmled_driver);
340
341MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
342MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs");
343MODULE_ALIAS("platform:twl-pwmled");
344MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
new file mode 100644
index 000000000000..e65db95d5e59
--- /dev/null
+++ b/drivers/pwm/pwm-twl.c
@@ -0,0 +1,359 @@
1/*
2 * Driver for TWL4030/6030 Generic Pulse Width Modulator
3 *
4 * Copyright (C) 2012 Texas Instruments
5 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/pwm.h>
23#include <linux/i2c/twl.h>
24#include <linux/slab.h>
25
26/*
27 * This driver handles the PWMs of TWL4030 and TWL6030.
28 * The TRM names for the PWMs on TWL4030 are: PWM0, PWM1
29 * TWL6030 also have two PWMs named in the TRM as PWM1, PWM2
30 */
31
32#define TWL_PWM_MAX 0x7f
33
34/* Registers, bits and macro for TWL4030 */
35#define TWL4030_GPBR1_REG 0x0c
36#define TWL4030_PMBR1_REG 0x0d
37
38/* GPBR1 register bits */
39#define TWL4030_PWMXCLK_ENABLE (1 << 0)
40#define TWL4030_PWMX_ENABLE (1 << 2)
41#define TWL4030_PWMX_BITS (TWL4030_PWMX_ENABLE | TWL4030_PWMXCLK_ENABLE)
42#define TWL4030_PWM_TOGGLE(pwm, x) ((x) << (pwm))
43
44/* PMBR1 register bits */
45#define TWL4030_GPIO6_PWM0_MUTE_MASK (0x03 << 2)
46#define TWL4030_GPIO6_PWM0_MUTE_PWM0 (0x01 << 2)
47#define TWL4030_GPIO7_VIBRASYNC_PWM1_MASK (0x03 << 4)
48#define TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1 (0x03 << 4)
49
50/* Register, bits and macro for TWL6030 */
51#define TWL6030_TOGGLE3_REG 0x92
52
53#define TWL6030_PWMXR (1 << 0)
54#define TWL6030_PWMXS (1 << 1)
55#define TWL6030_PWMXEN (1 << 2)
56#define TWL6030_PWM_TOGGLE(pwm, x) ((x) << (pwm * 3))
57
58struct twl_pwm_chip {
59 struct pwm_chip chip;
60 struct mutex mutex;
61 u8 twl6030_toggle3;
62 u8 twl4030_pwm_mux;
63};
64
65static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
66{
67 return container_of(chip, struct twl_pwm_chip, chip);
68}
69
70static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
71 int duty_ns, int period_ns)
72{
73 int duty_cycle = DIV_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
74 u8 pwm_config[2] = { 1, 0 };
75 int base, ret;
76
77 /*
78 * To configure the duty period:
79 * On-cycle is set to 1 (the minimum allowed value)
80 * The off time of 0 is not configurable, so the mapping is:
81 * 0 -> off cycle = 2,
82 * 1 -> off cycle = 2,
83 * 2 -> off cycle = 3,
84 * 126 - > off cycle 127,
85 * 127 - > off cycle 1
86 * When on cycle == off cycle the PWM will be always on
87 */
88 if (duty_cycle == 1)
89 duty_cycle = 2;
90 else if (duty_cycle > TWL_PWM_MAX)
91 duty_cycle = 1;
92
93 base = pwm->hwpwm * 3;
94
95 pwm_config[1] = duty_cycle;
96
97 ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2);
98 if (ret < 0)
99 dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
100
101 return ret;
102}
103
104static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
105{
106 struct twl_pwm_chip *twl = to_twl(chip);
107 int ret;
108 u8 val;
109
110 mutex_lock(&twl->mutex);
111 ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
112 if (ret < 0) {
113 dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
114 goto out;
115 }
116
117 val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
118
119 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
120 if (ret < 0)
121 dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
122
123 val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
124
125 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
126 if (ret < 0)
127 dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
128
129out:
130 mutex_unlock(&twl->mutex);
131 return ret;
132}
133
134static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
135{
136 struct twl_pwm_chip *twl = to_twl(chip);
137 int ret;
138 u8 val;
139
140 mutex_lock(&twl->mutex);
141 ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
142 if (ret < 0) {
143 dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
144 goto out;
145 }
146
147 val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
148
149 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
150 if (ret < 0)
151 dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
152
153 val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
154
155 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
156 if (ret < 0)
157 dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
158
159out:
160 mutex_unlock(&twl->mutex);
161}
162
163static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
164{
165 struct twl_pwm_chip *twl = to_twl(chip);
166 int ret;
167 u8 val, mask, bits;
168
169 if (pwm->hwpwm == 1) {
170 mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
171 bits = TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1;
172 } else {
173 mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
174 bits = TWL4030_GPIO6_PWM0_MUTE_PWM0;
175 }
176
177 mutex_lock(&twl->mutex);
178 ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
179 if (ret < 0) {
180 dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
181 goto out;
182 }
183
184 /* Save the current MUX configuration for the PWM */
185 twl->twl4030_pwm_mux &= ~mask;
186 twl->twl4030_pwm_mux |= (val & mask);
187
188 /* Select PWM functionality */
189 val &= ~mask;
190 val |= bits;
191
192 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
193 if (ret < 0)
194 dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
195
196out:
197 mutex_unlock(&twl->mutex);
198 return ret;
199}
200
201static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
202{
203 struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
204 chip);
205 int ret;
206 u8 val, mask;
207
208 if (pwm->hwpwm == 1)
209 mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
210 else
211 mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
212
213 mutex_lock(&twl->mutex);
214 ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
215 if (ret < 0) {
216 dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
217 goto out;
218 }
219
220 /* Restore the MUX configuration for the PWM */
221 val &= ~mask;
222 val |= (twl->twl4030_pwm_mux & mask);
223
224 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
225 if (ret < 0)
226 dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
227
228out:
229 mutex_unlock(&twl->mutex);
230}
231
232static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
233{
234 struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
235 chip);
236 int ret;
237 u8 val;
238
239 mutex_lock(&twl->mutex);
240 val = twl->twl6030_toggle3;
241 val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
242 val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
243
244 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
245 if (ret < 0) {
246 dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
247 goto out;
248 }
249
250 twl->twl6030_toggle3 = val;
251out:
252 mutex_unlock(&twl->mutex);
253 return 0;
254}
255
256static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
257{
258 struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
259 chip);
260 int ret;
261 u8 val;
262
263 mutex_lock(&twl->mutex);
264 val = twl->twl6030_toggle3;
265 val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
266 val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
267
268 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
269 if (ret < 0) {
270 dev_err(chip->dev, "%s: Failed to read TOGGLE3\n", pwm->label);
271 goto out;
272 }
273
274 val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
275
276 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
277 if (ret < 0) {
278 dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
279 goto out;
280 }
281
282 twl->twl6030_toggle3 = val;
283out:
284 mutex_unlock(&twl->mutex);
285}
286
287static const struct pwm_ops twl4030_pwm_ops = {
288 .config = twl_pwm_config,
289 .enable = twl4030_pwm_enable,
290 .disable = twl4030_pwm_disable,
291 .request = twl4030_pwm_request,
292 .free = twl4030_pwm_free,
293};
294
295static const struct pwm_ops twl6030_pwm_ops = {
296 .config = twl_pwm_config,
297 .enable = twl6030_pwm_enable,
298 .disable = twl6030_pwm_disable,
299};
300
301static int twl_pwm_probe(struct platform_device *pdev)
302{
303 struct twl_pwm_chip *twl;
304 int ret;
305
306 twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
307 if (!twl)
308 return -ENOMEM;
309
310 if (twl_class_is_4030())
311 twl->chip.ops = &twl4030_pwm_ops;
312 else
313 twl->chip.ops = &twl6030_pwm_ops;
314
315 twl->chip.dev = &pdev->dev;
316 twl->chip.base = -1;
317 twl->chip.npwm = 2;
318
319 mutex_init(&twl->mutex);
320
321 ret = pwmchip_add(&twl->chip);
322 if (ret < 0)
323 return ret;
324
325 platform_set_drvdata(pdev, twl);
326
327 return 0;
328}
329
330static int twl_pwm_remove(struct platform_device *pdev)
331{
332 struct twl_pwm_chip *twl = platform_get_drvdata(pdev);
333
334 return pwmchip_remove(&twl->chip);
335}
336
337#ifdef CONFIG_OF
338static struct of_device_id twl_pwm_of_match[] = {
339 { .compatible = "ti,twl4030-pwm" },
340 { .compatible = "ti,twl6030-pwm" },
341 { },
342};
343MODULE_DEVICE_TABLE(of, twl_pwm_of_match);
344#endif
345
346static struct platform_driver twl_pwm_driver = {
347 .driver = {
348 .name = "twl-pwm",
349 .of_match_table = of_match_ptr(twl_pwm_of_match),
350 },
351 .probe = twl_pwm_probe,
352 .remove = twl_pwm_remove,
353};
354module_platform_driver(twl_pwm_driver);
355
356MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
357MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030");
358MODULE_ALIAS("platform:twl-pwm");
359MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-twl6030.c b/drivers/pwm/pwm-twl6030.c
deleted file mode 100644
index 378a7e286366..000000000000
--- a/drivers/pwm/pwm-twl6030.c
+++ /dev/null
@@ -1,184 +0,0 @@
1/*
2 * twl6030_pwm.c
3 * Driver for PHOENIX (TWL6030) Pulse Width Modulator
4 *
5 * Copyright (C) 2010 Texas Instruments
6 * Author: Hemanth V <hemanthv@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/pwm.h>
24#include <linux/i2c/twl.h>
25#include <linux/slab.h>
26
27#define LED_PWM_CTRL1 0xF4
28#define LED_PWM_CTRL2 0xF5
29
30/* Max value for CTRL1 register */
31#define PWM_CTRL1_MAX 255
32
33/* Pull down disable */
34#define PWM_CTRL2_DIS_PD (1 << 6)
35
36/* Current control 2.5 milli Amps */
37#define PWM_CTRL2_CURR_02 (2 << 4)
38
39/* LED supply source */
40#define PWM_CTRL2_SRC_VAC (1 << 2)
41
42/* LED modes */
43#define PWM_CTRL2_MODE_HW (0 << 0)
44#define PWM_CTRL2_MODE_SW (1 << 0)
45#define PWM_CTRL2_MODE_DIS (2 << 0)
46
47#define PWM_CTRL2_MODE_MASK 0x3
48
49struct twl6030_pwm_chip {
50 struct pwm_chip chip;
51};
52
53static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
54{
55 int ret;
56 u8 val;
57
58 /* Configure PWM */
59 val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
60 PWM_CTRL2_MODE_HW;
61
62 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
63 if (ret < 0) {
64 dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n",
65 pwm->label, ret);
66 return ret;
67 }
68
69 return 0;
70}
71
72static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
73 int duty_ns, int period_ns)
74{
75 u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
76 int ret;
77
78 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
79 if (ret < 0) {
80 pr_err("%s: Failed to configure PWM, Error %d\n",
81 pwm->label, ret);
82 return ret;
83 }
84
85 return 0;
86}
87
88static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
89{
90 int ret;
91 u8 val;
92
93 ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
94 if (ret < 0) {
95 dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
96 pwm->label, ret);
97 return ret;
98 }
99
100 /* Change mode to software control */
101 val &= ~PWM_CTRL2_MODE_MASK;
102 val |= PWM_CTRL2_MODE_SW;
103
104 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
105 if (ret < 0) {
106 dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
107 pwm->label, ret);
108 return ret;
109 }
110
111 twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
112 return 0;
113}
114
115static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
116{
117 int ret;
118 u8 val;
119
120 ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
121 if (ret < 0) {
122 dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
123 pwm->label, ret);
124 return;
125 }
126
127 val &= ~PWM_CTRL2_MODE_MASK;
128 val |= PWM_CTRL2_MODE_HW;
129
130 ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
131 if (ret < 0) {
132 dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
133 pwm->label, ret);
134 }
135}
136
137static const struct pwm_ops twl6030_pwm_ops = {
138 .request = twl6030_pwm_request,
139 .config = twl6030_pwm_config,
140 .enable = twl6030_pwm_enable,
141 .disable = twl6030_pwm_disable,
142};
143
144static int twl6030_pwm_probe(struct platform_device *pdev)
145{
146 struct twl6030_pwm_chip *twl6030;
147 int ret;
148
149 twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL);
150 if (!twl6030)
151 return -ENOMEM;
152
153 twl6030->chip.dev = &pdev->dev;
154 twl6030->chip.ops = &twl6030_pwm_ops;
155 twl6030->chip.base = -1;
156 twl6030->chip.npwm = 1;
157
158 ret = pwmchip_add(&twl6030->chip);
159 if (ret < 0)
160 return ret;
161
162 platform_set_drvdata(pdev, twl6030);
163
164 return 0;
165}
166
167static int twl6030_pwm_remove(struct platform_device *pdev)
168{
169 struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev);
170
171 return pwmchip_remove(&twl6030->chip);
172}
173
174static struct platform_driver twl6030_pwm_driver = {
175 .driver = {
176 .name = "twl6030-pwm",
177 },
178 .probe = twl6030_pwm_probe,
179 .remove = twl6030_pwm_remove,
180};
181module_platform_driver(twl6030_pwm_driver);
182
183MODULE_ALIAS("platform:twl6030-pwm");
184MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index ad14389b7144..b0ba2d403439 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * drivers/pwm/pwm-vt8500.c 2 * drivers/pwm/pwm-vt8500.c
3 * 3 *
4 * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> 4 * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
5 * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
5 * 6 *
6 * This software is licensed under the terms of the GNU General Public 7 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and 8 * License version 2, as published by the Free Software Foundation, and
@@ -21,14 +22,24 @@
21#include <linux/io.h> 22#include <linux/io.h>
22#include <linux/pwm.h> 23#include <linux/pwm.h>
23#include <linux/delay.h> 24#include <linux/delay.h>
25#include <linux/clk.h>
24 26
25#include <asm/div64.h> 27#include <asm/div64.h>
26 28
27#define VT8500_NR_PWMS 4 29#include <linux/of.h>
30#include <linux/of_device.h>
31#include <linux/of_address.h>
32
33/*
34 * SoC architecture allocates register space for 4 PWMs but only
35 * 2 are currently implemented.
36 */
37#define VT8500_NR_PWMS 2
28 38
29struct vt8500_chip { 39struct vt8500_chip {
30 struct pwm_chip chip; 40 struct pwm_chip chip;
31 void __iomem *base; 41 void __iomem *base;
42 struct clk *clk;
32}; 43};
33 44
34#define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip) 45#define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip)
@@ -51,8 +62,15 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
51 struct vt8500_chip *vt8500 = to_vt8500_chip(chip); 62 struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
52 unsigned long long c; 63 unsigned long long c;
53 unsigned long period_cycles, prescale, pv, dc; 64 unsigned long period_cycles, prescale, pv, dc;
65 int err;
54 66
55 c = 25000000/2; /* wild guess --- need to implement clocks */ 67 err = clk_enable(vt8500->clk);
68 if (err < 0) {
69 dev_err(chip->dev, "failed to enable clock\n");
70 return err;
71 }
72
73 c = clk_get_rate(vt8500->clk);
56 c = c * period_ns; 74 c = c * period_ns;
57 do_div(c, 1000000000); 75 do_div(c, 1000000000);
58 period_cycles = c; 76 period_cycles = c;
@@ -64,8 +82,10 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
64 if (pv > 4095) 82 if (pv > 4095)
65 pv = 4095; 83 pv = 4095;
66 84
67 if (prescale > 1023) 85 if (prescale > 1023) {
86 clk_disable(vt8500->clk);
68 return -EINVAL; 87 return -EINVAL;
88 }
69 89
70 c = (unsigned long long)pv * duty_ns; 90 c = (unsigned long long)pv * duty_ns;
71 do_div(c, period_ns); 91 do_div(c, period_ns);
@@ -80,13 +100,21 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
80 pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3)); 100 pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3));
81 writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4)); 101 writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4));
82 102
103 clk_disable(vt8500->clk);
83 return 0; 104 return 0;
84} 105}
85 106
86static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 107static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
87{ 108{
109 int err;
88 struct vt8500_chip *vt8500 = to_vt8500_chip(chip); 110 struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
89 111
112 err = clk_enable(vt8500->clk);
113 if (err < 0) {
114 dev_err(chip->dev, "failed to enable clock\n");
115 return err;
116 }
117
90 pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); 118 pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
91 writel(5, vt8500->base + (pwm->hwpwm << 4)); 119 writel(5, vt8500->base + (pwm->hwpwm << 4));
92 return 0; 120 return 0;
@@ -98,6 +126,8 @@ static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
98 126
99 pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); 127 pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
100 writel(0, vt8500->base + (pwm->hwpwm << 4)); 128 writel(0, vt8500->base + (pwm->hwpwm << 4));
129
130 clk_disable(vt8500->clk);
101} 131}
102 132
103static struct pwm_ops vt8500_pwm_ops = { 133static struct pwm_ops vt8500_pwm_ops = {
@@ -107,12 +137,24 @@ static struct pwm_ops vt8500_pwm_ops = {
107 .owner = THIS_MODULE, 137 .owner = THIS_MODULE,
108}; 138};
109 139
110static int __devinit pwm_probe(struct platform_device *pdev) 140static const struct of_device_id vt8500_pwm_dt_ids[] = {
141 { .compatible = "via,vt8500-pwm", },
142 { /* Sentinel */ }
143};
144MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids);
145
146static int vt8500_pwm_probe(struct platform_device *pdev)
111{ 147{
112 struct vt8500_chip *chip; 148 struct vt8500_chip *chip;
113 struct resource *r; 149 struct resource *r;
150 struct device_node *np = pdev->dev.of_node;
114 int ret; 151 int ret;
115 152
153 if (!np) {
154 dev_err(&pdev->dev, "invalid devicetree node\n");
155 return -EINVAL;
156 }
157
116 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); 158 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
117 if (chip == NULL) { 159 if (chip == NULL) {
118 dev_err(&pdev->dev, "failed to allocate memory\n"); 160 dev_err(&pdev->dev, "failed to allocate memory\n");
@@ -124,6 +166,12 @@ static int __devinit pwm_probe(struct platform_device *pdev)
124 chip->chip.base = -1; 166 chip->chip.base = -1;
125 chip->chip.npwm = VT8500_NR_PWMS; 167 chip->chip.npwm = VT8500_NR_PWMS;
126 168
169 chip->clk = devm_clk_get(&pdev->dev, NULL);
170 if (IS_ERR(chip->clk)) {
171 dev_err(&pdev->dev, "clock source not specified\n");
172 return PTR_ERR(chip->clk);
173 }
174
127 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 175 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
128 if (r == NULL) { 176 if (r == NULL) {
129 dev_err(&pdev->dev, "no memory resource defined\n"); 177 dev_err(&pdev->dev, "no memory resource defined\n");
@@ -131,18 +179,26 @@ static int __devinit pwm_probe(struct platform_device *pdev)
131 } 179 }
132 180
133 chip->base = devm_request_and_ioremap(&pdev->dev, r); 181 chip->base = devm_request_and_ioremap(&pdev->dev, r);
134 if (chip->base == NULL) 182 if (!chip->base)
135 return -EADDRNOTAVAIL; 183 return -EADDRNOTAVAIL;
136 184
185 ret = clk_prepare(chip->clk);
186 if (ret < 0) {
187 dev_err(&pdev->dev, "failed to prepare clock\n");
188 return ret;
189 }
190
137 ret = pwmchip_add(&chip->chip); 191 ret = pwmchip_add(&chip->chip);
138 if (ret < 0) 192 if (ret < 0) {
193 dev_err(&pdev->dev, "failed to add PWM chip\n");
139 return ret; 194 return ret;
195 }
140 196
141 platform_set_drvdata(pdev, chip); 197 platform_set_drvdata(pdev, chip);
142 return ret; 198 return ret;
143} 199}
144 200
145static int __devexit pwm_remove(struct platform_device *pdev) 201static int vt8500_pwm_remove(struct platform_device *pdev)
146{ 202{
147 struct vt8500_chip *chip; 203 struct vt8500_chip *chip;
148 204
@@ -150,28 +206,22 @@ static int __devexit pwm_remove(struct platform_device *pdev)
150 if (chip == NULL) 206 if (chip == NULL)
151 return -ENODEV; 207 return -ENODEV;
152 208
209 clk_unprepare(chip->clk);
210
153 return pwmchip_remove(&chip->chip); 211 return pwmchip_remove(&chip->chip);
154} 212}
155 213
156static struct platform_driver pwm_driver = { 214static struct platform_driver vt8500_pwm_driver = {
215 .probe = vt8500_pwm_probe,
216 .remove = vt8500_pwm_remove,
157 .driver = { 217 .driver = {
158 .name = "vt8500-pwm", 218 .name = "vt8500-pwm",
159 .owner = THIS_MODULE, 219 .owner = THIS_MODULE,
220 .of_match_table = vt8500_pwm_dt_ids,
160 }, 221 },
161 .probe = pwm_probe,
162 .remove = __devexit_p(pwm_remove),
163}; 222};
223module_platform_driver(vt8500_pwm_driver);
164 224
165static int __init pwm_init(void) 225MODULE_DESCRIPTION("VT8500 PWM Driver");
166{ 226MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
167 return platform_driver_register(&pwm_driver); 227MODULE_LICENSE("GPL v2");
168}
169arch_initcall(pwm_init);
170
171static void __exit pwm_exit(void)
172{
173 platform_driver_unregister(&pwm_driver);
174}
175module_exit(pwm_exit);
176
177MODULE_LICENSE("GPL");
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 112b31436848..6d661f32e0e4 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -171,6 +171,9 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
171 unsigned int index, 171 unsigned int index,
172 const char *label); 172 const char *label);
173 173
174struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc,
175 const struct of_phandle_args *args);
176
174struct pwm_device *pwm_get(struct device *dev, const char *consumer); 177struct pwm_device *pwm_get(struct device *dev, const char *consumer);
175void pwm_put(struct pwm_device *pwm); 178void pwm_put(struct pwm_device *pwm);
176 179