diff options
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 @@ | |||
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/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 @@ | |||
1 | TI SOC EHRPWM based PWM controller | ||
2 | |||
3 | Required 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 | |||
12 | Optional 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 | |||
16 | Example: | ||
17 | |||
18 | ehrpwm0: 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 @@ | |||
1 | TI SOC based PWM Subsystem | ||
2 | |||
3 | Required 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 | |||
16 | Also child nodes should also populated under PWMSS DT node. | ||
17 | |||
18 | Example: | ||
19 | pwmss0: 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 | ||
40 | Note that in the example above, specifying the "pwm-names" is redundant | ||
41 | because the name "backlight" would be used as fallback anyway. | ||
42 | |||
40 | pwm-specifier typically encodes the chip-relative PWM number and the PWM | 43 | pwm-specifier typically encodes the chip-relative PWM number and the PWM |
41 | period in nanoseconds. Note that in the example above, specifying the | 44 | period in nanoseconds. |
42 | "pwm-names" is redundant because the name "backlight" would be used as | 45 | |
43 | fallback anyway. | 46 | Optionally, 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 | |||
49 | Example with optional PWM specifier for inverse polarity | ||
50 | |||
51 | bl: backlight { | ||
52 | pwms = <&pwm 0 5000000 1>; | ||
53 | pwm-names = "backlight"; | ||
54 | }; | ||
44 | 55 | ||
45 | 2) PWM controller nodes | 56 | 2) 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 | |||
3 | Required 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 | |||
12 | Example: | ||
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 @@ | |||
1 | Texas Instruments TWL series PWM drivers | ||
2 | |||
3 | Supported PWMs: | ||
4 | On TWL4030 series: PWM1 and PWM2 | ||
5 | On TWL6030 series: PWM0 and PWM1 | ||
6 | |||
7 | Required 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 | |||
12 | Example: | ||
13 | |||
14 | twl_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 @@ | |||
1 | Texas Instruments TWL series PWM drivers connected to LED terminals | ||
2 | |||
3 | Supported PWMs: | ||
4 | On TWL4030 series: PWMA and PWMB (connected to LEDA and LEDB terminals) | ||
5 | On TWL6030 series: LED PWM (mainly used as charging indicator LED) | ||
6 | |||
7 | Required 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 | |||
12 | Example: | ||
13 | |||
14 | twl_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 @@ | |||
1 | VIA/Wondermedia VT8500/WM8xxx series SoC PWM controller | ||
2 | |||
3 | Required 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 | |||
10 | Example: | ||
11 | |||
12 | pwm1: 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 | ||
115 | config 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 | |||
115 | config PWM_TEGRA | 126 | config 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 | |||
125 | config PWM_TIECAP | 136 | config 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 | |||
135 | config PWM_TIEHRPWM | 147 | config 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 | ||
145 | config PWM_TWL6030 | 158 | config 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 | |||
167 | config 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 | |||
176 | config 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 | ||
154 | config PWM_VT8500 | 185 | config 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 | |||
8 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o | 8 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o |
9 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o | 9 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o |
10 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o | 10 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o |
11 | obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o | ||
11 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o | 12 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o |
12 | obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o | 13 | obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o |
13 | obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o | 14 | obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o |
14 | obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o | 15 | obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o |
16 | obj-$(CONFIG_PWM_TWL) += pwm-twl.o | ||
17 | obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o | ||
15 | obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o | 18 | obj-$(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 | |||
35 | static DEFINE_MUTEX(pwm_lookup_lock); | 38 | static DEFINE_MUTEX(pwm_lookup_lock); |
36 | static LIST_HEAD(pwm_lookup_list); | 39 | static LIST_HEAD(pwm_lookup_list); |
37 | static DEFINE_MUTEX(pwm_lock); | 40 | static 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 | ||
135 | struct pwm_device * | ||
136 | of_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 | } | ||
159 | EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); | ||
160 | |||
132 | static struct pwm_device * | 161 | static struct pwm_device * |
133 | of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) | 162 | of_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) | |||
121 | static int lpc32xx_pwm_remove(struct platform_device *pdev) | 137 | static 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 | */ | ||
54 | struct spear_pwm_chip { | ||
55 | void __iomem *mmio_base; | ||
56 | struct clk *clk; | ||
57 | struct pwm_chip chip; | ||
58 | struct device *dev; | ||
59 | }; | ||
60 | |||
61 | static 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 | |||
66 | static 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 | |||
72 | static 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 | |||
79 | static 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 | |||
139 | static 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 | |||
156 | static 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 | |||
168 | static 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 | |||
175 | static 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 | |||
241 | static 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 | |||
254 | static struct of_device_id spear_pwm_of_match[] = { | ||
255 | { .compatible = "st,spear320-pwm" }, | ||
256 | { .compatible = "st,spear1340-pwm" }, | ||
257 | { } | ||
258 | }; | ||
259 | |||
260 | MODULE_DEVICE_TABLE(of, spear_pwm_of_match); | ||
261 | |||
262 | static 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 | |||
271 | module_platform_driver(spear_pwm_driver); | ||
272 | |||
273 | MODULE_LICENSE("GPL"); | ||
274 | MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>"); | ||
275 | MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.com>"); | ||
276 | MODULE_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 | ||
191 | static const struct of_device_id ecap_of_match[] = { | ||
192 | { .compatible = "ti,am33xx-ecap" }, | ||
193 | {}, | ||
194 | }; | ||
195 | MODULE_DEVICE_TABLE(of, ecap_of_match); | ||
196 | |||
187 | static int ecap_pwm_probe(struct platform_device *pdev) | 197 | static 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 | |||
267 | pwmss_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 | ||
238 | static int ecap_pwm_remove(struct platform_device *pdev) | 274 | static 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 | ||
247 | static struct platform_driver ecap_pwm_driver = { | 291 | static 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 | ||
120 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | 125 | static 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 | ||
406 | static const struct of_device_id ehrpwm_of_match[] = { | ||
407 | { .compatible = "ti,am33xx-ehrpwm" }, | ||
408 | {}, | ||
409 | }; | ||
410 | MODULE_DEVICE_TABLE(of, ehrpwm_of_match); | ||
411 | |||
395 | static int ehrpwm_pwm_probe(struct platform_device *pdev) | 412 | static 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 | |||
489 | pwmss_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 | ||
446 | static int ehrpwm_pwm_remove(struct platform_device *pdev) | 496 | static 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 | ||
455 | static struct platform_driver ehrpwm_pwm_driver = { | 513 | static 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 | |||
30 | struct pwmss_info { | ||
31 | void __iomem *mmio_base; | ||
32 | struct mutex pwmss_lock; | ||
33 | u16 pwmss_clkconfig; | ||
34 | }; | ||
35 | |||
36 | u16 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 | } | ||
49 | EXPORT_SYMBOL(pwmss_submodule_state_change); | ||
50 | |||
51 | static const struct of_device_id pwmss_of_match[] = { | ||
52 | { .compatible = "ti,am33xx-pwmss" }, | ||
53 | {}, | ||
54 | }; | ||
55 | MODULE_DEVICE_TABLE(of, pwmss_of_match); | ||
56 | |||
57 | static 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 | |||
94 | static 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 | |||
104 | static 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 | |||
113 | static 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 | |||
122 | static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume); | ||
123 | |||
124 | static 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 | |||
135 | module_platform_driver(pwmss_driver); | ||
136 | |||
137 | MODULE_DESCRIPTION("PWM Subsystem driver"); | ||
138 | MODULE_AUTHOR("Texas Instruments"); | ||
139 | MODULE_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 | |||
31 | extern u16 pwmss_submodule_state_change(struct device *dev, int set); | ||
32 | #else | ||
33 | static 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 | |||
58 | struct twl_pwmled_chip { | ||
59 | struct pwm_chip chip; | ||
60 | struct mutex mutex; | ||
61 | }; | ||
62 | |||
63 | static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip) | ||
64 | { | ||
65 | return container_of(chip, struct twl_pwmled_chip, chip); | ||
66 | } | ||
67 | |||
68 | static 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 | |||
102 | static 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 | |||
121 | out: | ||
122 | mutex_unlock(&twl->mutex); | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | static 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 | |||
146 | out: | ||
147 | mutex_unlock(&twl->mutex); | ||
148 | } | ||
149 | |||
150 | static 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 | |||
167 | static 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 | |||
188 | out: | ||
189 | mutex_unlock(&twl->mutex); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | static 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 | |||
215 | out: | ||
216 | mutex_unlock(&twl->mutex); | ||
217 | } | ||
218 | |||
219 | static 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 | |||
240 | out: | ||
241 | mutex_unlock(&twl->mutex); | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | static 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 | |||
266 | out: | ||
267 | mutex_unlock(&twl->mutex); | ||
268 | } | ||
269 | |||
270 | static const struct pwm_ops twl4030_pwmled_ops = { | ||
271 | .enable = twl4030_pwmled_enable, | ||
272 | .disable = twl4030_pwmled_disable, | ||
273 | .config = twl4030_pwmled_config, | ||
274 | }; | ||
275 | |||
276 | static 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 | |||
284 | static 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 | |||
315 | static 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 | ||
323 | static struct of_device_id twl_pwmled_of_match[] = { | ||
324 | { .compatible = "ti,twl4030-pwmled" }, | ||
325 | { .compatible = "ti,twl6030-pwmled" }, | ||
326 | { }, | ||
327 | }; | ||
328 | MODULE_DEVICE_TABLE(of, twl_pwmled_of_match); | ||
329 | #endif | ||
330 | |||
331 | static 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 | }; | ||
339 | module_platform_driver(twl_pwmled_driver); | ||
340 | |||
341 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); | ||
342 | MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs"); | ||
343 | MODULE_ALIAS("platform:twl-pwmled"); | ||
344 | MODULE_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 | |||
58 | struct twl_pwm_chip { | ||
59 | struct pwm_chip chip; | ||
60 | struct mutex mutex; | ||
61 | u8 twl6030_toggle3; | ||
62 | u8 twl4030_pwm_mux; | ||
63 | }; | ||
64 | |||
65 | static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip) | ||
66 | { | ||
67 | return container_of(chip, struct twl_pwm_chip, chip); | ||
68 | } | ||
69 | |||
70 | static 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 | |||
104 | static 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 | |||
129 | out: | ||
130 | mutex_unlock(&twl->mutex); | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static 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 | |||
159 | out: | ||
160 | mutex_unlock(&twl->mutex); | ||
161 | } | ||
162 | |||
163 | static 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 | |||
196 | out: | ||
197 | mutex_unlock(&twl->mutex); | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static 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 | |||
228 | out: | ||
229 | mutex_unlock(&twl->mutex); | ||
230 | } | ||
231 | |||
232 | static 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; | ||
251 | out: | ||
252 | mutex_unlock(&twl->mutex); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static 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; | ||
283 | out: | ||
284 | mutex_unlock(&twl->mutex); | ||
285 | } | ||
286 | |||
287 | static 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 | |||
295 | static const struct pwm_ops twl6030_pwm_ops = { | ||
296 | .config = twl_pwm_config, | ||
297 | .enable = twl6030_pwm_enable, | ||
298 | .disable = twl6030_pwm_disable, | ||
299 | }; | ||
300 | |||
301 | static 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 | |||
330 | static 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 | ||
338 | static struct of_device_id twl_pwm_of_match[] = { | ||
339 | { .compatible = "ti,twl4030-pwm" }, | ||
340 | { .compatible = "ti,twl6030-pwm" }, | ||
341 | { }, | ||
342 | }; | ||
343 | MODULE_DEVICE_TABLE(of, twl_pwm_of_match); | ||
344 | #endif | ||
345 | |||
346 | static 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 | }; | ||
354 | module_platform_driver(twl_pwm_driver); | ||
355 | |||
356 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); | ||
357 | MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030"); | ||
358 | MODULE_ALIAS("platform:twl-pwm"); | ||
359 | MODULE_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 | |||
49 | struct twl6030_pwm_chip { | ||
50 | struct pwm_chip chip; | ||
51 | }; | ||
52 | |||
53 | static 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 | |||
72 | static 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 | |||
88 | static 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 | |||
115 | static 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 | |||
137 | static 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 | |||
144 | static 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 | |||
167 | static 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 | |||
174 | static struct platform_driver twl6030_pwm_driver = { | ||
175 | .driver = { | ||
176 | .name = "twl6030-pwm", | ||
177 | }, | ||
178 | .probe = twl6030_pwm_probe, | ||
179 | .remove = twl6030_pwm_remove, | ||
180 | }; | ||
181 | module_platform_driver(twl6030_pwm_driver); | ||
182 | |||
183 | MODULE_ALIAS("platform:twl6030-pwm"); | ||
184 | MODULE_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 | ||
29 | struct vt8500_chip { | 39 | struct 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 | ||
86 | static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 107 | static 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 | ||
103 | static struct pwm_ops vt8500_pwm_ops = { | 133 | static 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 | ||
110 | static int __devinit pwm_probe(struct platform_device *pdev) | 140 | static const struct of_device_id vt8500_pwm_dt_ids[] = { |
141 | { .compatible = "via,vt8500-pwm", }, | ||
142 | { /* Sentinel */ } | ||
143 | }; | ||
144 | MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids); | ||
145 | |||
146 | static 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 | ||
145 | static int __devexit pwm_remove(struct platform_device *pdev) | 201 | static 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 | ||
156 | static struct platform_driver pwm_driver = { | 214 | static 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 | }; |
223 | module_platform_driver(vt8500_pwm_driver); | ||
164 | 224 | ||
165 | static int __init pwm_init(void) | 225 | MODULE_DESCRIPTION("VT8500 PWM Driver"); |
166 | { | 226 | MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); |
167 | return platform_driver_register(&pwm_driver); | 227 | MODULE_LICENSE("GPL v2"); |
168 | } | ||
169 | arch_initcall(pwm_init); | ||
170 | |||
171 | static void __exit pwm_exit(void) | ||
172 | { | ||
173 | platform_driver_unregister(&pwm_driver); | ||
174 | } | ||
175 | module_exit(pwm_exit); | ||
176 | |||
177 | MODULE_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 | ||
174 | struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc, | ||
175 | const struct of_phandle_args *args); | ||
176 | |||
174 | struct pwm_device *pwm_get(struct device *dev, const char *consumer); | 177 | struct pwm_device *pwm_get(struct device *dev, const char *consumer); |
175 | void pwm_put(struct pwm_device *pwm); | 178 | void pwm_put(struct pwm_device *pwm); |
176 | 179 | ||