diff options
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-meson.txt | 23 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt | 3 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-st.txt | 8 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-sun4i.txt | 1 | ||||
-rw-r--r-- | drivers/pwm/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 1 | ||||
-rw-r--r-- | drivers/pwm/core.c | 2 | ||||
-rw-r--r-- | drivers/pwm/pwm-berlin.c | 84 | ||||
-rw-r--r-- | drivers/pwm/pwm-cros-ec.c | 4 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpc18xx-sct.c | 12 | ||||
-rw-r--r-- | drivers/pwm/pwm-meson.c | 529 | ||||
-rw-r--r-- | drivers/pwm/pwm-mtk-disp.c | 87 | ||||
-rw-r--r-- | drivers/pwm/pwm-samsung.c | 15 | ||||
-rw-r--r-- | drivers/pwm/pwm-sti.c | 483 | ||||
-rw-r--r-- | drivers/pwm/pwm-sun4i.c | 9 | ||||
-rw-r--r-- | drivers/pwm/pwm-tipwmss.c | 19 | ||||
-rw-r--r-- | drivers/pwm/pwm-twl.c | 16 | ||||
-rw-r--r-- | drivers/pwm/sysfs.c | 18 | ||||
-rw-r--r-- | include/linux/pwm.h | 5 |
19 files changed, 1183 insertions, 145 deletions
diff --git a/Documentation/devicetree/bindings/pwm/pwm-meson.txt b/Documentation/devicetree/bindings/pwm/pwm-meson.txt new file mode 100644 index 000000000000..5376a4468cb6 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-meson.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | Amlogic Meson PWM Controller | ||
2 | ============================ | ||
3 | |||
4 | Required properties: | ||
5 | - compatible: Shall contain "amlogic,meson8b-pwm" or "amlogic,meson-gxbb-pwm". | ||
6 | - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of | ||
7 | the cells format. | ||
8 | |||
9 | Optional properties: | ||
10 | - clocks: Could contain one or two parents clocks phandle for each of the two | ||
11 | PWM channels. | ||
12 | - clock-names: Could contain at least the "clkin0" and/or "clkin1" names. | ||
13 | |||
14 | Example: | ||
15 | |||
16 | pwm_ab: pwm@8550 { | ||
17 | compatible = "amlogic,meson-gxbb-pwm"; | ||
18 | reg = <0x0 0x08550 0x0 0x10>; | ||
19 | #pwm-cells = <3>; | ||
20 | status = "disabled"; | ||
21 | clocks = <&xtal>, <&xtal>; | ||
22 | clock-names = "clkin0", "clkin1"; | ||
23 | } | ||
diff --git a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt index f8f59baf6b67..6f8af2bcc7b7 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt | |||
@@ -2,8 +2,9 @@ MediaTek display PWM controller | |||
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: should be "mediatek,<name>-disp-pwm": | 4 | - compatible: should be "mediatek,<name>-disp-pwm": |
5 | - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. | 5 | - "mediatek,mt2701-disp-pwm": found on mt2701 SoC. |
6 | - "mediatek,mt6595-disp-pwm": found on mt6595 SoC. | 6 | - "mediatek,mt6595-disp-pwm": found on mt6595 SoC. |
7 | - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. | ||
7 | - reg: physical base address and length of the controller's registers. | 8 | - reg: physical base address and length of the controller's registers. |
8 | - #pwm-cells: must be 2. See pwm.txt in this directory for a description of | 9 | - #pwm-cells: must be 2. See pwm.txt in this directory for a description of |
9 | the cell format. | 10 | the cell format. |
diff --git a/Documentation/devicetree/bindings/pwm/pwm-st.txt b/Documentation/devicetree/bindings/pwm/pwm-st.txt index 84d2fb807d3c..19fce774cafa 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-st.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-st.txt | |||
@@ -13,13 +13,14 @@ Required parameters: | |||
13 | - pinctrl-0: List of phandles pointing to pin configuration nodes | 13 | - pinctrl-0: List of phandles pointing to pin configuration nodes |
14 | for PWM module. | 14 | for PWM module. |
15 | For Pinctrl properties, please refer to [1]. | 15 | For Pinctrl properties, please refer to [1]. |
16 | - clock-names: Set to "pwm". | 16 | - clock-names: Valid entries are "pwm" and/or "capture". |
17 | - clocks: phandle of the clock used by the PWM module. | 17 | - clocks: phandle of the clock used by the PWM module. |
18 | For Clk properties, please refer to [2]. | 18 | For Clk properties, please refer to [2]. |
19 | - interrupts: IRQ for the Capture device | ||
19 | 20 | ||
20 | Optional properties: | 21 | Optional properties: |
21 | - st,pwm-num-chan: Number of available channels. If not passed, the driver | 22 | - st,pwm-num-chan: Number of available PWM channels. Default is 0. |
22 | will consider single channel by default. | 23 | - st,capture-num-chan: Number of available Capture channels. Default is 0. |
23 | 24 | ||
24 | [1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 25 | [1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt |
25 | [2] Documentation/devicetree/bindings/clock/clock-bindings.txt | 26 | [2] Documentation/devicetree/bindings/clock/clock-bindings.txt |
@@ -38,4 +39,5 @@ pwm1: pwm@fe510000 { | |||
38 | clocks = <&clk_sysin>; | 39 | clocks = <&clk_sysin>; |
39 | clock-names = "pwm"; | 40 | clock-names = "pwm"; |
40 | st,pwm-num-chan = <4>; | 41 | st,pwm-num-chan = <4>; |
42 | st,capture-num-chan = <2>; | ||
41 | }; | 43 | }; |
diff --git a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt index cf6068b8e974..f1cbeefb3087 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt | |||
@@ -6,6 +6,7 @@ Required properties: | |||
6 | - "allwinner,sun5i-a10s-pwm" | 6 | - "allwinner,sun5i-a10s-pwm" |
7 | - "allwinner,sun5i-a13-pwm" | 7 | - "allwinner,sun5i-a13-pwm" |
8 | - "allwinner,sun7i-a20-pwm" | 8 | - "allwinner,sun7i-a20-pwm" |
9 | - "allwinner,sun8i-h3-pwm" | ||
9 | - reg: physical base address and length of the controller's registers | 10 | - reg: physical base address and length of the controller's registers |
10 | - #pwm-cells: should be 3. See pwm.txt in this directory for a description of | 11 | - #pwm-cells: should be 3. See pwm.txt in this directory for a description of |
11 | the cells format. | 12 | the cells format. |
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 80a566a00d04..bf0128899c09 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig | |||
@@ -262,6 +262,15 @@ config PWM_LPSS_PLATFORM | |||
262 | To compile this driver as a module, choose M here: the module | 262 | To compile this driver as a module, choose M here: the module |
263 | will be called pwm-lpss-platform. | 263 | will be called pwm-lpss-platform. |
264 | 264 | ||
265 | config PWM_MESON | ||
266 | tristate "Amlogic Meson PWM driver" | ||
267 | depends on ARCH_MESON | ||
268 | help | ||
269 | The platform driver for Amlogic Meson PWM controller. | ||
270 | |||
271 | To compile this driver as a module, choose M here: the module | ||
272 | will be called pwm-meson. | ||
273 | |||
265 | config PWM_MTK_DISP | 274 | config PWM_MTK_DISP |
266 | tristate "MediaTek display PWM driver" | 275 | tristate "MediaTek display PWM driver" |
267 | depends on ARCH_MEDIATEK || COMPILE_TEST | 276 | depends on ARCH_MEDIATEK || COMPILE_TEST |
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index feef1dd29f73..1194c54efcc2 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile | |||
@@ -24,6 +24,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o | |||
24 | obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o | 24 | obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o |
25 | obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o | 25 | obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o |
26 | obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o | 26 | obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o |
27 | obj-$(CONFIG_PWM_MESON) += pwm-meson.o | ||
27 | obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o | 28 | obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o |
28 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o | 29 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o |
29 | obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o | 30 | obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o |
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 0dbd29e287db..172ef8245811 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c | |||
@@ -339,6 +339,8 @@ int pwmchip_remove(struct pwm_chip *chip) | |||
339 | unsigned int i; | 339 | unsigned int i; |
340 | int ret = 0; | 340 | int ret = 0; |
341 | 341 | ||
342 | pwmchip_sysfs_unexport_children(chip); | ||
343 | |||
342 | mutex_lock(&pwm_lock); | 344 | mutex_lock(&pwm_lock); |
343 | 345 | ||
344 | for (i = 0; i < chip->npwm; i++) { | 346 | for (i = 0; i < chip->npwm; i++) { |
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 65108129d505..01339c152ab0 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/pwm.h> | 18 | #include <linux/pwm.h> |
19 | #include <linux/slab.h> | ||
19 | 20 | ||
20 | #define BERLIN_PWM_EN 0x0 | 21 | #define BERLIN_PWM_EN 0x0 |
21 | #define BERLIN_PWM_ENABLE BIT(0) | 22 | #define BERLIN_PWM_ENABLE BIT(0) |
@@ -27,6 +28,13 @@ | |||
27 | #define BERLIN_PWM_TCNT 0xc | 28 | #define BERLIN_PWM_TCNT 0xc |
28 | #define BERLIN_PWM_MAX_TCNT 65535 | 29 | #define BERLIN_PWM_MAX_TCNT 65535 |
29 | 30 | ||
31 | struct berlin_pwm_channel { | ||
32 | u32 enable; | ||
33 | u32 ctrl; | ||
34 | u32 duty; | ||
35 | u32 tcnt; | ||
36 | }; | ||
37 | |||
30 | struct berlin_pwm_chip { | 38 | struct berlin_pwm_chip { |
31 | struct pwm_chip chip; | 39 | struct pwm_chip chip; |
32 | struct clk *clk; | 40 | struct clk *clk; |
@@ -55,6 +63,25 @@ static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip, | |||
55 | writel_relaxed(value, chip->base + channel * 0x10 + offset); | 63 | writel_relaxed(value, chip->base + channel * 0x10 + offset); |
56 | } | 64 | } |
57 | 65 | ||
66 | static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) | ||
67 | { | ||
68 | struct berlin_pwm_channel *channel; | ||
69 | |||
70 | channel = kzalloc(sizeof(*channel), GFP_KERNEL); | ||
71 | if (!channel) | ||
72 | return -ENOMEM; | ||
73 | |||
74 | return pwm_set_chip_data(pwm, channel); | ||
75 | } | ||
76 | |||
77 | static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | ||
78 | { | ||
79 | struct berlin_pwm_channel *channel = pwm_get_chip_data(pwm); | ||
80 | |||
81 | pwm_set_chip_data(pwm, NULL); | ||
82 | kfree(channel); | ||
83 | } | ||
84 | |||
58 | static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, | 85 | static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, |
59 | int duty_ns, int period_ns) | 86 | int duty_ns, int period_ns) |
60 | { | 87 | { |
@@ -137,6 +164,8 @@ static void berlin_pwm_disable(struct pwm_chip *chip, | |||
137 | } | 164 | } |
138 | 165 | ||
139 | static const struct pwm_ops berlin_pwm_ops = { | 166 | static const struct pwm_ops berlin_pwm_ops = { |
167 | .request = berlin_pwm_request, | ||
168 | .free = berlin_pwm_free, | ||
140 | .config = berlin_pwm_config, | 169 | .config = berlin_pwm_config, |
141 | .set_polarity = berlin_pwm_set_polarity, | 170 | .set_polarity = berlin_pwm_set_polarity, |
142 | .enable = berlin_pwm_enable, | 171 | .enable = berlin_pwm_enable, |
@@ -204,12 +233,67 @@ static int berlin_pwm_remove(struct platform_device *pdev) | |||
204 | return ret; | 233 | return ret; |
205 | } | 234 | } |
206 | 235 | ||
236 | #ifdef CONFIG_PM_SLEEP | ||
237 | static int berlin_pwm_suspend(struct device *dev) | ||
238 | { | ||
239 | struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); | ||
240 | unsigned int i; | ||
241 | |||
242 | for (i = 0; i < pwm->chip.npwm; i++) { | ||
243 | struct berlin_pwm_channel *channel; | ||
244 | |||
245 | channel = pwm_get_chip_data(&pwm->chip.pwms[i]); | ||
246 | if (!channel) | ||
247 | continue; | ||
248 | |||
249 | channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE); | ||
250 | channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL); | ||
251 | channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY); | ||
252 | channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT); | ||
253 | } | ||
254 | |||
255 | clk_disable_unprepare(pwm->clk); | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int berlin_pwm_resume(struct device *dev) | ||
261 | { | ||
262 | struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); | ||
263 | unsigned int i; | ||
264 | int ret; | ||
265 | |||
266 | ret = clk_prepare_enable(pwm->clk); | ||
267 | if (ret) | ||
268 | return ret; | ||
269 | |||
270 | for (i = 0; i < pwm->chip.npwm; i++) { | ||
271 | struct berlin_pwm_channel *channel; | ||
272 | |||
273 | channel = pwm_get_chip_data(&pwm->chip.pwms[i]); | ||
274 | if (!channel) | ||
275 | continue; | ||
276 | |||
277 | berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL); | ||
278 | berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY); | ||
279 | berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT); | ||
280 | berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE); | ||
281 | } | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | #endif | ||
286 | |||
287 | static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend, | ||
288 | berlin_pwm_resume); | ||
289 | |||
207 | static struct platform_driver berlin_pwm_driver = { | 290 | static struct platform_driver berlin_pwm_driver = { |
208 | .probe = berlin_pwm_probe, | 291 | .probe = berlin_pwm_probe, |
209 | .remove = berlin_pwm_remove, | 292 | .remove = berlin_pwm_remove, |
210 | .driver = { | 293 | .driver = { |
211 | .name = "berlin-pwm", | 294 | .name = "berlin-pwm", |
212 | .of_match_table = berlin_pwm_match, | 295 | .of_match_table = berlin_pwm_match, |
296 | .pm = &berlin_pwm_pm_ops, | ||
213 | }, | 297 | }, |
214 | }; | 298 | }; |
215 | module_platform_driver(berlin_pwm_driver); | 299 | module_platform_driver(berlin_pwm_driver); |
diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 99b9acc1a420..f6ca4e8c6253 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c | |||
@@ -38,7 +38,7 @@ static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty) | |||
38 | struct { | 38 | struct { |
39 | struct cros_ec_command msg; | 39 | struct cros_ec_command msg; |
40 | struct ec_params_pwm_set_duty params; | 40 | struct ec_params_pwm_set_duty params; |
41 | } buf; | 41 | } __packed buf; |
42 | struct ec_params_pwm_set_duty *params = &buf.params; | 42 | struct ec_params_pwm_set_duty *params = &buf.params; |
43 | struct cros_ec_command *msg = &buf.msg; | 43 | struct cros_ec_command *msg = &buf.msg; |
44 | 44 | ||
@@ -65,7 +65,7 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index, | |||
65 | struct ec_params_pwm_get_duty params; | 65 | struct ec_params_pwm_get_duty params; |
66 | struct ec_response_pwm_get_duty resp; | 66 | struct ec_response_pwm_get_duty resp; |
67 | }; | 67 | }; |
68 | } buf; | 68 | } __packed buf; |
69 | struct ec_params_pwm_get_duty *params = &buf.params; | 69 | struct ec_params_pwm_get_duty *params = &buf.params; |
70 | struct ec_response_pwm_get_duty *resp = &buf.resp; | 70 | struct ec_response_pwm_get_duty *resp = &buf.resp; |
71 | struct cros_ec_command *msg = &buf.msg; | 71 | struct cros_ec_command *msg = &buf.msg; |
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 19dc64cab2f0..d7f5f7de030d 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c | |||
@@ -413,14 +413,18 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) | |||
413 | } | 413 | } |
414 | 414 | ||
415 | for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) { | 415 | for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) { |
416 | struct lpc18xx_pwm_data *data; | ||
417 | |||
416 | pwm = &lpc18xx_pwm->chip.pwms[i]; | 418 | pwm = &lpc18xx_pwm->chip.pwms[i]; |
417 | pwm->chip_data = devm_kzalloc(lpc18xx_pwm->dev, | 419 | |
418 | sizeof(struct lpc18xx_pwm_data), | 420 | data = devm_kzalloc(lpc18xx_pwm->dev, sizeof(*data), |
419 | GFP_KERNEL); | 421 | GFP_KERNEL); |
420 | if (!pwm->chip_data) { | 422 | if (!data) { |
421 | ret = -ENOMEM; | 423 | ret = -ENOMEM; |
422 | goto remove_pwmchip; | 424 | goto remove_pwmchip; |
423 | } | 425 | } |
426 | |||
427 | pwm_set_chip_data(pwm, data); | ||
424 | } | 428 | } |
425 | 429 | ||
426 | platform_set_drvdata(pdev, lpc18xx_pwm); | 430 | platform_set_drvdata(pdev, lpc18xx_pwm); |
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c new file mode 100644 index 000000000000..381871b2bb46 --- /dev/null +++ b/drivers/pwm/pwm-meson.c | |||
@@ -0,0 +1,529 @@ | |||
1 | /* | ||
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
3 | * redistributing this file, you may do so under either license. | ||
4 | * | ||
5 | * GPL LICENSE SUMMARY | ||
6 | * | ||
7 | * Copyright (c) 2016 BayLibre, SAS. | ||
8 | * Author: Neil Armstrong <narmstrong@baylibre.com> | ||
9 | * Copyright (C) 2014 Amlogic, Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of version 2 of the GNU General Public License as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
22 | * The full GNU General Public License is included in this distribution | ||
23 | * in the file called COPYING. | ||
24 | * | ||
25 | * BSD LICENSE | ||
26 | * | ||
27 | * Copyright (c) 2016 BayLibre, SAS. | ||
28 | * Author: Neil Armstrong <narmstrong@baylibre.com> | ||
29 | * Copyright (C) 2014 Amlogic, Inc. | ||
30 | * | ||
31 | * Redistribution and use in source and binary forms, with or without | ||
32 | * modification, are permitted provided that the following conditions | ||
33 | * are met: | ||
34 | * | ||
35 | * * Redistributions of source code must retain the above copyright | ||
36 | * notice, this list of conditions and the following disclaimer. | ||
37 | * * Redistributions in binary form must reproduce the above copyright | ||
38 | * notice, this list of conditions and the following disclaimer in | ||
39 | * the documentation and/or other materials provided with the | ||
40 | * distribution. | ||
41 | * * Neither the name of Intel Corporation nor the names of its | ||
42 | * contributors may be used to endorse or promote products derived | ||
43 | * from this software without specific prior written permission. | ||
44 | * | ||
45 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
46 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
47 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
48 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
49 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
50 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
51 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
52 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
53 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
54 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
55 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
56 | */ | ||
57 | |||
58 | #include <linux/clk.h> | ||
59 | #include <linux/clk-provider.h> | ||
60 | #include <linux/err.h> | ||
61 | #include <linux/io.h> | ||
62 | #include <linux/kernel.h> | ||
63 | #include <linux/module.h> | ||
64 | #include <linux/of.h> | ||
65 | #include <linux/of_device.h> | ||
66 | #include <linux/platform_device.h> | ||
67 | #include <linux/pwm.h> | ||
68 | #include <linux/slab.h> | ||
69 | #include <linux/spinlock.h> | ||
70 | |||
71 | #define REG_PWM_A 0x0 | ||
72 | #define REG_PWM_B 0x4 | ||
73 | #define PWM_HIGH_SHIFT 16 | ||
74 | |||
75 | #define REG_MISC_AB 0x8 | ||
76 | #define MISC_B_CLK_EN BIT(23) | ||
77 | #define MISC_A_CLK_EN BIT(15) | ||
78 | #define MISC_CLK_DIV_MASK 0x7f | ||
79 | #define MISC_B_CLK_DIV_SHIFT 16 | ||
80 | #define MISC_A_CLK_DIV_SHIFT 8 | ||
81 | #define MISC_B_CLK_SEL_SHIFT 6 | ||
82 | #define MISC_A_CLK_SEL_SHIFT 4 | ||
83 | #define MISC_CLK_SEL_WIDTH 2 | ||
84 | #define MISC_B_EN BIT(1) | ||
85 | #define MISC_A_EN BIT(0) | ||
86 | |||
87 | static const unsigned int mux_reg_shifts[] = { | ||
88 | MISC_A_CLK_SEL_SHIFT, | ||
89 | MISC_B_CLK_SEL_SHIFT | ||
90 | }; | ||
91 | |||
92 | struct meson_pwm_channel { | ||
93 | unsigned int hi; | ||
94 | unsigned int lo; | ||
95 | u8 pre_div; | ||
96 | |||
97 | struct pwm_state state; | ||
98 | |||
99 | struct clk *clk_parent; | ||
100 | struct clk_mux mux; | ||
101 | struct clk *clk; | ||
102 | }; | ||
103 | |||
104 | struct meson_pwm_data { | ||
105 | const char * const *parent_names; | ||
106 | }; | ||
107 | |||
108 | struct meson_pwm { | ||
109 | struct pwm_chip chip; | ||
110 | const struct meson_pwm_data *data; | ||
111 | void __iomem *base; | ||
112 | u8 inverter_mask; | ||
113 | spinlock_t lock; | ||
114 | }; | ||
115 | |||
116 | static inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip) | ||
117 | { | ||
118 | return container_of(chip, struct meson_pwm, chip); | ||
119 | } | ||
120 | |||
121 | static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) | ||
122 | { | ||
123 | struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); | ||
124 | struct device *dev = chip->dev; | ||
125 | int err; | ||
126 | |||
127 | if (!channel) | ||
128 | return -ENODEV; | ||
129 | |||
130 | if (channel->clk_parent) { | ||
131 | err = clk_set_parent(channel->clk, channel->clk_parent); | ||
132 | if (err < 0) { | ||
133 | dev_err(dev, "failed to set parent %s for %s: %d\n", | ||
134 | __clk_get_name(channel->clk_parent), | ||
135 | __clk_get_name(channel->clk), err); | ||
136 | return err; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | err = clk_prepare_enable(channel->clk); | ||
141 | if (err < 0) { | ||
142 | dev_err(dev, "failed to enable clock %s: %d\n", | ||
143 | __clk_get_name(channel->clk), err); | ||
144 | return err; | ||
145 | } | ||
146 | |||
147 | chip->ops->get_state(chip, pwm, &channel->state); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | ||
153 | { | ||
154 | struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); | ||
155 | |||
156 | if (channel) | ||
157 | clk_disable_unprepare(channel->clk); | ||
158 | } | ||
159 | |||
160 | static int meson_pwm_calc(struct meson_pwm *meson, | ||
161 | struct meson_pwm_channel *channel, unsigned int id, | ||
162 | unsigned int duty, unsigned int period) | ||
163 | { | ||
164 | unsigned int pre_div, cnt, duty_cnt; | ||
165 | unsigned long fin_freq = -1, fin_ns; | ||
166 | |||
167 | if (~(meson->inverter_mask >> id) & 0x1) | ||
168 | duty = period - duty; | ||
169 | |||
170 | if (period == channel->state.period && | ||
171 | duty == channel->state.duty_cycle) | ||
172 | return 0; | ||
173 | |||
174 | fin_freq = clk_get_rate(channel->clk); | ||
175 | if (fin_freq == 0) { | ||
176 | dev_err(meson->chip.dev, "invalid source clock frequency\n"); | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | |||
180 | dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); | ||
181 | fin_ns = NSEC_PER_SEC / fin_freq; | ||
182 | |||
183 | /* Calc pre_div with the period */ | ||
184 | for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { | ||
185 | cnt = DIV_ROUND_CLOSEST(period, fin_ns * (pre_div + 1)); | ||
186 | dev_dbg(meson->chip.dev, "fin_ns=%lu pre_div=%u cnt=%u\n", | ||
187 | fin_ns, pre_div, cnt); | ||
188 | if (cnt <= 0xffff) | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | if (pre_div == MISC_CLK_DIV_MASK) { | ||
193 | dev_err(meson->chip.dev, "unable to get period pre_div\n"); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period, | ||
198 | pre_div, cnt); | ||
199 | |||
200 | if (duty == period) { | ||
201 | channel->pre_div = pre_div; | ||
202 | channel->hi = cnt; | ||
203 | channel->lo = 0; | ||
204 | } else if (duty == 0) { | ||
205 | channel->pre_div = pre_div; | ||
206 | channel->hi = 0; | ||
207 | channel->lo = cnt; | ||
208 | } else { | ||
209 | /* Then check is we can have the duty with the same pre_div */ | ||
210 | duty_cnt = DIV_ROUND_CLOSEST(duty, fin_ns * (pre_div + 1)); | ||
211 | if (duty_cnt > 0xffff) { | ||
212 | dev_err(meson->chip.dev, "unable to get duty cycle\n"); | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | |||
216 | dev_dbg(meson->chip.dev, "duty=%u pre_div=%u duty_cnt=%u\n", | ||
217 | duty, pre_div, duty_cnt); | ||
218 | |||
219 | channel->pre_div = pre_div; | ||
220 | channel->hi = duty_cnt; | ||
221 | channel->lo = cnt - duty_cnt; | ||
222 | } | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static void meson_pwm_enable(struct meson_pwm *meson, | ||
228 | struct meson_pwm_channel *channel, | ||
229 | unsigned int id) | ||
230 | { | ||
231 | u32 value, clk_shift, clk_enable, enable; | ||
232 | unsigned int offset; | ||
233 | |||
234 | switch (id) { | ||
235 | case 0: | ||
236 | clk_shift = MISC_A_CLK_DIV_SHIFT; | ||
237 | clk_enable = MISC_A_CLK_EN; | ||
238 | enable = MISC_A_EN; | ||
239 | offset = REG_PWM_A; | ||
240 | break; | ||
241 | |||
242 | case 1: | ||
243 | clk_shift = MISC_B_CLK_DIV_SHIFT; | ||
244 | clk_enable = MISC_B_CLK_EN; | ||
245 | enable = MISC_B_EN; | ||
246 | offset = REG_PWM_B; | ||
247 | break; | ||
248 | |||
249 | default: | ||
250 | return; | ||
251 | } | ||
252 | |||
253 | value = readl(meson->base + REG_MISC_AB); | ||
254 | value &= ~(MISC_CLK_DIV_MASK << clk_shift); | ||
255 | value |= channel->pre_div << clk_shift; | ||
256 | value |= clk_enable; | ||
257 | writel(value, meson->base + REG_MISC_AB); | ||
258 | |||
259 | value = (channel->hi << PWM_HIGH_SHIFT) | channel->lo; | ||
260 | writel(value, meson->base + offset); | ||
261 | |||
262 | value = readl(meson->base + REG_MISC_AB); | ||
263 | value |= enable; | ||
264 | writel(value, meson->base + REG_MISC_AB); | ||
265 | } | ||
266 | |||
267 | static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) | ||
268 | { | ||
269 | u32 value, enable; | ||
270 | |||
271 | switch (id) { | ||
272 | case 0: | ||
273 | enable = MISC_A_EN; | ||
274 | break; | ||
275 | |||
276 | case 1: | ||
277 | enable = MISC_B_EN; | ||
278 | break; | ||
279 | |||
280 | default: | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | value = readl(meson->base + REG_MISC_AB); | ||
285 | value &= ~enable; | ||
286 | writel(value, meson->base + REG_MISC_AB); | ||
287 | } | ||
288 | |||
289 | static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | ||
290 | struct pwm_state *state) | ||
291 | { | ||
292 | struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); | ||
293 | struct meson_pwm *meson = to_meson_pwm(chip); | ||
294 | unsigned long flags; | ||
295 | int err = 0; | ||
296 | |||
297 | if (!state) | ||
298 | return -EINVAL; | ||
299 | |||
300 | spin_lock_irqsave(&meson->lock, flags); | ||
301 | |||
302 | if (!state->enabled) { | ||
303 | meson_pwm_disable(meson, pwm->hwpwm); | ||
304 | channel->state.enabled = false; | ||
305 | |||
306 | goto unlock; | ||
307 | } | ||
308 | |||
309 | if (state->period != channel->state.period || | ||
310 | state->duty_cycle != channel->state.duty_cycle || | ||
311 | state->polarity != channel->state.polarity) { | ||
312 | if (channel->state.enabled) { | ||
313 | meson_pwm_disable(meson, pwm->hwpwm); | ||
314 | channel->state.enabled = false; | ||
315 | } | ||
316 | |||
317 | if (state->polarity != channel->state.polarity) { | ||
318 | if (state->polarity == PWM_POLARITY_NORMAL) | ||
319 | meson->inverter_mask |= BIT(pwm->hwpwm); | ||
320 | else | ||
321 | meson->inverter_mask &= ~BIT(pwm->hwpwm); | ||
322 | } | ||
323 | |||
324 | err = meson_pwm_calc(meson, channel, pwm->hwpwm, | ||
325 | state->duty_cycle, state->period); | ||
326 | if (err < 0) | ||
327 | goto unlock; | ||
328 | |||
329 | channel->state.polarity = state->polarity; | ||
330 | channel->state.period = state->period; | ||
331 | channel->state.duty_cycle = state->duty_cycle; | ||
332 | } | ||
333 | |||
334 | if (state->enabled && !channel->state.enabled) { | ||
335 | meson_pwm_enable(meson, channel, pwm->hwpwm); | ||
336 | channel->state.enabled = true; | ||
337 | } | ||
338 | |||
339 | unlock: | ||
340 | spin_unlock_irqrestore(&meson->lock, flags); | ||
341 | return err; | ||
342 | } | ||
343 | |||
344 | static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, | ||
345 | struct pwm_state *state) | ||
346 | { | ||
347 | struct meson_pwm *meson = to_meson_pwm(chip); | ||
348 | u32 value, mask; | ||
349 | |||
350 | if (!state) | ||
351 | return; | ||
352 | |||
353 | switch (pwm->hwpwm) { | ||
354 | case 0: | ||
355 | mask = MISC_A_EN; | ||
356 | break; | ||
357 | |||
358 | case 1: | ||
359 | mask = MISC_B_EN; | ||
360 | break; | ||
361 | |||
362 | default: | ||
363 | return; | ||
364 | } | ||
365 | |||
366 | value = readl(meson->base + REG_MISC_AB); | ||
367 | state->enabled = (value & mask) != 0; | ||
368 | } | ||
369 | |||
370 | static const struct pwm_ops meson_pwm_ops = { | ||
371 | .request = meson_pwm_request, | ||
372 | .free = meson_pwm_free, | ||
373 | .apply = meson_pwm_apply, | ||
374 | .get_state = meson_pwm_get_state, | ||
375 | .owner = THIS_MODULE, | ||
376 | }; | ||
377 | |||
378 | static const char * const pwm_meson8b_parent_names[] = { | ||
379 | "xtal", "vid_pll", "fclk_div4", "fclk_div3" | ||
380 | }; | ||
381 | |||
382 | static const struct meson_pwm_data pwm_meson8b_data = { | ||
383 | .parent_names = pwm_meson8b_parent_names, | ||
384 | }; | ||
385 | |||
386 | static const char * const pwm_gxbb_parent_names[] = { | ||
387 | "xtal", "hdmi_pll", "fclk_div4", "fclk_div3" | ||
388 | }; | ||
389 | |||
390 | static const struct meson_pwm_data pwm_gxbb_data = { | ||
391 | .parent_names = pwm_gxbb_parent_names, | ||
392 | }; | ||
393 | |||
394 | static const struct of_device_id meson_pwm_matches[] = { | ||
395 | { .compatible = "amlogic,meson8b-pwm", .data = &pwm_meson8b_data }, | ||
396 | { .compatible = "amlogic,meson-gxbb-pwm", .data = &pwm_gxbb_data }, | ||
397 | {}, | ||
398 | }; | ||
399 | MODULE_DEVICE_TABLE(of, meson_pwm_matches); | ||
400 | |||
401 | static int meson_pwm_init_channels(struct meson_pwm *meson, | ||
402 | struct meson_pwm_channel *channels) | ||
403 | { | ||
404 | struct device *dev = meson->chip.dev; | ||
405 | struct device_node *np = dev->of_node; | ||
406 | struct clk_init_data init; | ||
407 | unsigned int i; | ||
408 | char name[255]; | ||
409 | int err; | ||
410 | |||
411 | for (i = 0; i < meson->chip.npwm; i++) { | ||
412 | struct meson_pwm_channel *channel = &channels[i]; | ||
413 | |||
414 | snprintf(name, sizeof(name), "%s#mux%u", np->full_name, i); | ||
415 | |||
416 | init.name = name; | ||
417 | init.ops = &clk_mux_ops; | ||
418 | init.flags = CLK_IS_BASIC; | ||
419 | init.parent_names = meson->data->parent_names; | ||
420 | init.num_parents = 1 << MISC_CLK_SEL_WIDTH; | ||
421 | |||
422 | channel->mux.reg = meson->base + REG_MISC_AB; | ||
423 | channel->mux.shift = mux_reg_shifts[i]; | ||
424 | channel->mux.mask = BIT(MISC_CLK_SEL_WIDTH) - 1; | ||
425 | channel->mux.flags = 0; | ||
426 | channel->mux.lock = &meson->lock; | ||
427 | channel->mux.table = NULL; | ||
428 | channel->mux.hw.init = &init; | ||
429 | |||
430 | channel->clk = devm_clk_register(dev, &channel->mux.hw); | ||
431 | if (IS_ERR(channel->clk)) { | ||
432 | err = PTR_ERR(channel->clk); | ||
433 | dev_err(dev, "failed to register %s: %d\n", name, err); | ||
434 | return err; | ||
435 | } | ||
436 | |||
437 | snprintf(name, sizeof(name), "clkin%u", i); | ||
438 | |||
439 | channel->clk_parent = devm_clk_get(dev, name); | ||
440 | if (IS_ERR(channel->clk_parent)) { | ||
441 | err = PTR_ERR(channel->clk_parent); | ||
442 | if (err == -EPROBE_DEFER) | ||
443 | return err; | ||
444 | |||
445 | channel->clk_parent = NULL; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static void meson_pwm_add_channels(struct meson_pwm *meson, | ||
453 | struct meson_pwm_channel *channels) | ||
454 | { | ||
455 | unsigned int i; | ||
456 | |||
457 | for (i = 0; i < meson->chip.npwm; i++) | ||
458 | pwm_set_chip_data(&meson->chip.pwms[i], &channels[i]); | ||
459 | } | ||
460 | |||
461 | static int meson_pwm_probe(struct platform_device *pdev) | ||
462 | { | ||
463 | struct meson_pwm_channel *channels; | ||
464 | struct meson_pwm *meson; | ||
465 | struct resource *regs; | ||
466 | int err; | ||
467 | |||
468 | meson = devm_kzalloc(&pdev->dev, sizeof(*meson), GFP_KERNEL); | ||
469 | if (!meson) | ||
470 | return -ENOMEM; | ||
471 | |||
472 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
473 | meson->base = devm_ioremap_resource(&pdev->dev, regs); | ||
474 | if (IS_ERR(meson->base)) | ||
475 | return PTR_ERR(meson->base); | ||
476 | |||
477 | meson->chip.dev = &pdev->dev; | ||
478 | meson->chip.ops = &meson_pwm_ops; | ||
479 | meson->chip.base = -1; | ||
480 | meson->chip.npwm = 2; | ||
481 | meson->chip.of_xlate = of_pwm_xlate_with_flags; | ||
482 | meson->chip.of_pwm_n_cells = 3; | ||
483 | |||
484 | meson->data = of_device_get_match_data(&pdev->dev); | ||
485 | meson->inverter_mask = BIT(meson->chip.npwm) - 1; | ||
486 | |||
487 | channels = devm_kcalloc(&pdev->dev, meson->chip.npwm, sizeof(*meson), | ||
488 | GFP_KERNEL); | ||
489 | if (!channels) | ||
490 | return -ENOMEM; | ||
491 | |||
492 | err = meson_pwm_init_channels(meson, channels); | ||
493 | if (err < 0) | ||
494 | return err; | ||
495 | |||
496 | err = pwmchip_add(&meson->chip); | ||
497 | if (err < 0) { | ||
498 | dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err); | ||
499 | return err; | ||
500 | } | ||
501 | |||
502 | meson_pwm_add_channels(meson, channels); | ||
503 | |||
504 | platform_set_drvdata(pdev, meson); | ||
505 | |||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static int meson_pwm_remove(struct platform_device *pdev) | ||
510 | { | ||
511 | struct meson_pwm *meson = platform_get_drvdata(pdev); | ||
512 | |||
513 | return pwmchip_remove(&meson->chip); | ||
514 | } | ||
515 | |||
516 | static struct platform_driver meson_pwm_driver = { | ||
517 | .driver = { | ||
518 | .name = "meson-pwm", | ||
519 | .of_match_table = meson_pwm_matches, | ||
520 | }, | ||
521 | .probe = meson_pwm_probe, | ||
522 | .remove = meson_pwm_remove, | ||
523 | }; | ||
524 | module_platform_driver(meson_pwm_driver); | ||
525 | |||
526 | MODULE_ALIAS("platform:meson-pwm"); | ||
527 | MODULE_DESCRIPTION("Amlogic Meson PWM Generator driver"); | ||
528 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); | ||
529 | MODULE_LICENSE("Dual BSD/GPL"); | ||
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index 0ad3385298c0..893940d45f0d 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c | |||
@@ -18,30 +18,40 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/of.h> | 20 | #include <linux/of.h> |
21 | #include <linux/of_device.h> | ||
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
22 | #include <linux/pwm.h> | 23 | #include <linux/pwm.h> |
23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
24 | 25 | ||
25 | #define DISP_PWM_EN 0x00 | 26 | #define DISP_PWM_EN 0x00 |
26 | #define PWM_ENABLE_MASK BIT(0) | ||
27 | 27 | ||
28 | #define DISP_PWM_COMMIT 0x08 | ||
29 | #define PWM_COMMIT_MASK BIT(0) | ||
30 | |||
31 | #define DISP_PWM_CON_0 0x10 | ||
32 | #define PWM_CLKDIV_SHIFT 16 | 28 | #define PWM_CLKDIV_SHIFT 16 |
33 | #define PWM_CLKDIV_MAX 0x3ff | 29 | #define PWM_CLKDIV_MAX 0x3ff |
34 | #define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT) | 30 | #define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT) |
35 | 31 | ||
36 | #define DISP_PWM_CON_1 0x14 | ||
37 | #define PWM_PERIOD_BIT_WIDTH 12 | 32 | #define PWM_PERIOD_BIT_WIDTH 12 |
38 | #define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1) | 33 | #define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1) |
39 | 34 | ||
40 | #define PWM_HIGH_WIDTH_SHIFT 16 | 35 | #define PWM_HIGH_WIDTH_SHIFT 16 |
41 | #define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT) | 36 | #define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT) |
42 | 37 | ||
38 | struct mtk_pwm_data { | ||
39 | u32 enable_mask; | ||
40 | unsigned int con0; | ||
41 | u32 con0_sel; | ||
42 | unsigned int con1; | ||
43 | |||
44 | bool has_commit; | ||
45 | unsigned int commit; | ||
46 | unsigned int commit_mask; | ||
47 | |||
48 | unsigned int bls_debug; | ||
49 | u32 bls_debug_mask; | ||
50 | }; | ||
51 | |||
43 | struct mtk_disp_pwm { | 52 | struct mtk_disp_pwm { |
44 | struct pwm_chip chip; | 53 | struct pwm_chip chip; |
54 | const struct mtk_pwm_data *data; | ||
45 | struct clk *clk_main; | 55 | struct clk *clk_main; |
46 | struct clk *clk_mm; | 56 | struct clk *clk_mm; |
47 | void __iomem *base; | 57 | void __iomem *base; |
@@ -106,12 +116,21 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
106 | return err; | 116 | return err; |
107 | } | 117 | } |
108 | 118 | ||
109 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK, | 119 | mtk_disp_pwm_update_bits(mdp, mdp->data->con0, |
120 | PWM_CLKDIV_MASK, | ||
110 | clk_div << PWM_CLKDIV_SHIFT); | 121 | clk_div << PWM_CLKDIV_SHIFT); |
111 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1, | 122 | mtk_disp_pwm_update_bits(mdp, mdp->data->con1, |
112 | PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value); | 123 | PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, |
113 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1); | 124 | value); |
114 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0); | 125 | |
126 | if (mdp->data->has_commit) { | ||
127 | mtk_disp_pwm_update_bits(mdp, mdp->data->commit, | ||
128 | mdp->data->commit_mask, | ||
129 | mdp->data->commit_mask); | ||
130 | mtk_disp_pwm_update_bits(mdp, mdp->data->commit, | ||
131 | mdp->data->commit_mask, | ||
132 | 0x0); | ||
133 | } | ||
115 | 134 | ||
116 | clk_disable(mdp->clk_mm); | 135 | clk_disable(mdp->clk_mm); |
117 | clk_disable(mdp->clk_main); | 136 | clk_disable(mdp->clk_main); |
@@ -134,7 +153,8 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
134 | return err; | 153 | return err; |
135 | } | 154 | } |
136 | 155 | ||
137 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1); | 156 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, |
157 | mdp->data->enable_mask); | ||
138 | 158 | ||
139 | return 0; | 159 | return 0; |
140 | } | 160 | } |
@@ -143,7 +163,8 @@ static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
143 | { | 163 | { |
144 | struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); | 164 | struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); |
145 | 165 | ||
146 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0); | 166 | mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, |
167 | 0x0); | ||
147 | 168 | ||
148 | clk_disable(mdp->clk_mm); | 169 | clk_disable(mdp->clk_mm); |
149 | clk_disable(mdp->clk_main); | 170 | clk_disable(mdp->clk_main); |
@@ -166,6 +187,8 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev) | |||
166 | if (!mdp) | 187 | if (!mdp) |
167 | return -ENOMEM; | 188 | return -ENOMEM; |
168 | 189 | ||
190 | mdp->data = of_device_get_match_data(&pdev->dev); | ||
191 | |||
169 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 192 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
170 | mdp->base = devm_ioremap_resource(&pdev->dev, r); | 193 | mdp->base = devm_ioremap_resource(&pdev->dev, r); |
171 | if (IS_ERR(mdp->base)) | 194 | if (IS_ERR(mdp->base)) |
@@ -200,6 +223,19 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev) | |||
200 | 223 | ||
201 | platform_set_drvdata(pdev, mdp); | 224 | platform_set_drvdata(pdev, mdp); |
202 | 225 | ||
226 | /* | ||
227 | * For MT2701, disable double buffer before writing register | ||
228 | * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH. | ||
229 | */ | ||
230 | if (!mdp->data->has_commit) { | ||
231 | mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug, | ||
232 | mdp->data->bls_debug_mask, | ||
233 | mdp->data->bls_debug_mask); | ||
234 | mtk_disp_pwm_update_bits(mdp, mdp->data->con0, | ||
235 | mdp->data->con0_sel, | ||
236 | mdp->data->con0_sel); | ||
237 | } | ||
238 | |||
203 | return 0; | 239 | return 0; |
204 | 240 | ||
205 | disable_clk_mm: | 241 | disable_clk_mm: |
@@ -221,9 +257,30 @@ static int mtk_disp_pwm_remove(struct platform_device *pdev) | |||
221 | return ret; | 257 | return ret; |
222 | } | 258 | } |
223 | 259 | ||
260 | static const struct mtk_pwm_data mt2701_pwm_data = { | ||
261 | .enable_mask = BIT(16), | ||
262 | .con0 = 0xa8, | ||
263 | .con0_sel = 0x2, | ||
264 | .con1 = 0xac, | ||
265 | .has_commit = false, | ||
266 | .bls_debug = 0xb0, | ||
267 | .bls_debug_mask = 0x3, | ||
268 | }; | ||
269 | |||
270 | static const struct mtk_pwm_data mt8173_pwm_data = { | ||
271 | .enable_mask = BIT(0), | ||
272 | .con0 = 0x10, | ||
273 | .con0_sel = 0x0, | ||
274 | .con1 = 0x14, | ||
275 | .has_commit = true, | ||
276 | .commit = 0x8, | ||
277 | .commit_mask = 0x1, | ||
278 | }; | ||
279 | |||
224 | static const struct of_device_id mtk_disp_pwm_of_match[] = { | 280 | static const struct of_device_id mtk_disp_pwm_of_match[] = { |
225 | { .compatible = "mediatek,mt8173-disp-pwm" }, | 281 | { .compatible = "mediatek,mt2701-disp-pwm", .data = &mt2701_pwm_data}, |
226 | { .compatible = "mediatek,mt6595-disp-pwm" }, | 282 | { .compatible = "mediatek,mt6595-disp-pwm", .data = &mt8173_pwm_data}, |
283 | { .compatible = "mediatek,mt8173-disp-pwm", .data = &mt8173_pwm_data}, | ||
227 | { } | 284 | { } |
228 | }; | 285 | }; |
229 | MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match); | 286 | MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match); |
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index ada2d326dc3e..f113cda47032 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c | |||
@@ -193,9 +193,18 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip, | |||
193 | * divider settings and choose the lowest divisor that can generate | 193 | * divider settings and choose the lowest divisor that can generate |
194 | * frequencies lower than requested. | 194 | * frequencies lower than requested. |
195 | */ | 195 | */ |
196 | for (div = variant->div_base; div < 4; ++div) | 196 | if (variant->bits < 32) { |
197 | if ((rate >> (variant->bits + div)) < freq) | 197 | /* Only for s3c24xx */ |
198 | break; | 198 | for (div = variant->div_base; div < 4; ++div) |
199 | if ((rate >> (variant->bits + div)) < freq) | ||
200 | break; | ||
201 | } else { | ||
202 | /* | ||
203 | * Other variants have enough counter bits to generate any | ||
204 | * requested rate, so no need to check higher divisors. | ||
205 | */ | ||
206 | div = variant->div_base; | ||
207 | } | ||
199 | 208 | ||
200 | pwm_samsung_set_divisor(chip, chan, BIT(div)); | 209 | pwm_samsung_set_divisor(chip, chan, BIT(div)); |
201 | 210 | ||
diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 92abbd56b9f7..dd82dc840af9 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c | |||
@@ -1,8 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * PWM device driver for ST SoCs. | 2 | * PWM device driver for ST SoCs |
3 | * Author: Ajit Pal Singh <ajitpal.singh@st.com> | 3 | * |
4 | * Copyright (C) 2013-2016 STMicroelectronics (R&D) Limited | ||
4 | * | 5 | * |
5 | * Copyright (C) 2013-2014 STMicroelectronics (R&D) Limited | 6 | * Author: Ajit Pal Singh <ajitpal.singh@st.com> |
7 | * Lee Jones <lee.jones@linaro.org> | ||
6 | * | 8 | * |
7 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
@@ -11,6 +13,7 @@ | |||
11 | */ | 13 | */ |
12 | 14 | ||
13 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/interrupt.h> | ||
14 | #include <linux/math64.h> | 17 | #include <linux/math64.h> |
15 | #include <linux/mfd/syscon.h> | 18 | #include <linux/mfd/syscon.h> |
16 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -18,43 +21,82 @@ | |||
18 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
19 | #include <linux/pwm.h> | 22 | #include <linux/pwm.h> |
20 | #include <linux/regmap.h> | 23 | #include <linux/regmap.h> |
24 | #include <linux/sched.h> | ||
21 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
22 | #include <linux/time.h> | 26 | #include <linux/time.h> |
27 | #include <linux/wait.h> | ||
28 | |||
29 | #define PWM_OUT_VAL(x) (0x00 + (4 * (x))) /* Device's Duty Cycle register */ | ||
30 | #define PWM_CPT_VAL(x) (0x10 + (4 * (x))) /* Capture value */ | ||
31 | #define PWM_CPT_EDGE(x) (0x30 + (4 * (x))) /* Edge to capture on */ | ||
23 | 32 | ||
24 | #define STI_DS_REG(ch) (4 * (ch)) /* Channel's Duty Cycle register */ | 33 | #define STI_PWM_CTRL 0x50 /* Control/Config register */ |
25 | #define STI_PWMCR 0x50 /* Control/Config register */ | 34 | #define STI_INT_EN 0x54 /* Interrupt Enable/Disable register */ |
26 | #define STI_INTEN 0x54 /* Interrupt Enable/Disable register */ | 35 | #define STI_INT_STA 0x58 /* Interrupt Status register */ |
27 | #define PWM_PRESCALE_LOW_MASK 0x0f | 36 | #define PWM_INT_ACK 0x5c |
28 | #define PWM_PRESCALE_HIGH_MASK 0xf0 | 37 | #define PWM_PRESCALE_LOW_MASK 0x0f |
38 | #define PWM_PRESCALE_HIGH_MASK 0xf0 | ||
39 | #define PWM_CPT_EDGE_MASK 0x03 | ||
40 | #define PWM_INT_ACK_MASK 0x1ff | ||
41 | |||
42 | #define STI_MAX_CPT_DEVS 4 | ||
43 | #define CPT_DC_MAX 0xff | ||
29 | 44 | ||
30 | /* Regfield IDs */ | 45 | /* Regfield IDs */ |
31 | enum { | 46 | enum { |
47 | /* Bits in PWM_CTRL*/ | ||
32 | PWMCLK_PRESCALE_LOW, | 48 | PWMCLK_PRESCALE_LOW, |
33 | PWMCLK_PRESCALE_HIGH, | 49 | PWMCLK_PRESCALE_HIGH, |
34 | PWM_EN, | 50 | CPTCLK_PRESCALE, |
35 | PWM_INT_EN, | 51 | |
52 | PWM_OUT_EN, | ||
53 | PWM_CPT_EN, | ||
54 | |||
55 | PWM_CPT_INT_EN, | ||
56 | PWM_CPT_INT_STAT, | ||
36 | 57 | ||
37 | /* Keep last */ | 58 | /* Keep last */ |
38 | MAX_REGFIELDS | 59 | MAX_REGFIELDS |
39 | }; | 60 | }; |
40 | 61 | ||
62 | /* | ||
63 | * Each capture input can be programmed to detect rising-edge, falling-edge, | ||
64 | * either edge or neither egde. | ||
65 | */ | ||
66 | enum sti_cpt_edge { | ||
67 | CPT_EDGE_DISABLED, | ||
68 | CPT_EDGE_RISING, | ||
69 | CPT_EDGE_FALLING, | ||
70 | CPT_EDGE_BOTH, | ||
71 | }; | ||
72 | |||
73 | struct sti_cpt_ddata { | ||
74 | u32 snapshot[3]; | ||
75 | unsigned int index; | ||
76 | struct mutex lock; | ||
77 | wait_queue_head_t wait; | ||
78 | }; | ||
79 | |||
41 | struct sti_pwm_compat_data { | 80 | struct sti_pwm_compat_data { |
42 | const struct reg_field *reg_fields; | 81 | const struct reg_field *reg_fields; |
43 | unsigned int num_chan; | 82 | unsigned int pwm_num_devs; |
83 | unsigned int cpt_num_devs; | ||
44 | unsigned int max_pwm_cnt; | 84 | unsigned int max_pwm_cnt; |
45 | unsigned int max_prescale; | 85 | unsigned int max_prescale; |
46 | }; | 86 | }; |
47 | 87 | ||
48 | struct sti_pwm_chip { | 88 | struct sti_pwm_chip { |
49 | struct device *dev; | 89 | struct device *dev; |
50 | struct clk *clk; | 90 | struct clk *pwm_clk; |
51 | unsigned long clk_rate; | 91 | struct clk *cpt_clk; |
52 | struct regmap *regmap; | 92 | struct regmap *regmap; |
53 | struct sti_pwm_compat_data *cdata; | 93 | struct sti_pwm_compat_data *cdata; |
54 | struct regmap_field *prescale_low; | 94 | struct regmap_field *prescale_low; |
55 | struct regmap_field *prescale_high; | 95 | struct regmap_field *prescale_high; |
56 | struct regmap_field *pwm_en; | 96 | struct regmap_field *pwm_out_en; |
57 | struct regmap_field *pwm_int_en; | 97 | struct regmap_field *pwm_cpt_en; |
98 | struct regmap_field *pwm_cpt_int_en; | ||
99 | struct regmap_field *pwm_cpt_int_stat; | ||
58 | struct pwm_chip chip; | 100 | struct pwm_chip chip; |
59 | struct pwm_device *cur; | 101 | struct pwm_device *cur; |
60 | unsigned long configured; | 102 | unsigned long configured; |
@@ -64,10 +106,13 @@ struct sti_pwm_chip { | |||
64 | }; | 106 | }; |
65 | 107 | ||
66 | static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = { | 108 | static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = { |
67 | [PWMCLK_PRESCALE_LOW] = REG_FIELD(STI_PWMCR, 0, 3), | 109 | [PWMCLK_PRESCALE_LOW] = REG_FIELD(STI_PWM_CTRL, 0, 3), |
68 | [PWMCLK_PRESCALE_HIGH] = REG_FIELD(STI_PWMCR, 11, 14), | 110 | [PWMCLK_PRESCALE_HIGH] = REG_FIELD(STI_PWM_CTRL, 11, 14), |
69 | [PWM_EN] = REG_FIELD(STI_PWMCR, 9, 9), | 111 | [CPTCLK_PRESCALE] = REG_FIELD(STI_PWM_CTRL, 4, 8), |
70 | [PWM_INT_EN] = REG_FIELD(STI_INTEN, 0, 0), | 112 | [PWM_OUT_EN] = REG_FIELD(STI_PWM_CTRL, 9, 9), |
113 | [PWM_CPT_EN] = REG_FIELD(STI_PWM_CTRL, 10, 10), | ||
114 | [PWM_CPT_INT_EN] = REG_FIELD(STI_INT_EN, 1, 4), | ||
115 | [PWM_CPT_INT_STAT] = REG_FIELD(STI_INT_STA, 1, 4), | ||
71 | }; | 116 | }; |
72 | 117 | ||
73 | static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip) | 118 | static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip) |
@@ -82,61 +127,68 @@ static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period, | |||
82 | unsigned int *prescale) | 127 | unsigned int *prescale) |
83 | { | 128 | { |
84 | struct sti_pwm_compat_data *cdata = pc->cdata; | 129 | struct sti_pwm_compat_data *cdata = pc->cdata; |
85 | unsigned long val; | 130 | unsigned long clk_rate; |
131 | unsigned long value; | ||
86 | unsigned int ps; | 132 | unsigned int ps; |
87 | 133 | ||
134 | clk_rate = clk_get_rate(pc->pwm_clk); | ||
135 | if (!clk_rate) { | ||
136 | dev_err(pc->dev, "failed to get clock rate\n"); | ||
137 | return -EINVAL; | ||
138 | } | ||
139 | |||
88 | /* | 140 | /* |
89 | * prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_count + 1)) - 1 | 141 | * prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_cnt + 1)) - 1 |
90 | */ | 142 | */ |
91 | val = NSEC_PER_SEC / pc->clk_rate; | 143 | value = NSEC_PER_SEC / clk_rate; |
92 | val *= cdata->max_pwm_cnt + 1; | 144 | value *= cdata->max_pwm_cnt + 1; |
93 | 145 | ||
94 | if (period % val) { | 146 | if (period % value) |
95 | return -EINVAL; | 147 | return -EINVAL; |
96 | } else { | 148 | |
97 | ps = period / val - 1; | 149 | ps = period / value - 1; |
98 | if (ps > cdata->max_prescale) | 150 | if (ps > cdata->max_prescale) |
99 | return -EINVAL; | 151 | return -EINVAL; |
100 | } | 152 | |
101 | *prescale = ps; | 153 | *prescale = ps; |
102 | 154 | ||
103 | return 0; | 155 | return 0; |
104 | } | 156 | } |
105 | 157 | ||
106 | /* | 158 | /* |
107 | * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles. | 159 | * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles. The |
108 | * The only way to change the period (apart from changing the PWM input clock) | 160 | * only way to change the period (apart from changing the PWM input clock) is |
109 | * is to change the PWM clock prescaler. | 161 | * to change the PWM clock prescaler. |
110 | * The prescaler is of 8 bits, so 256 prescaler values and hence | 162 | * |
111 | * 256 possible period values are supported (for a particular clock rate). | 163 | * The prescaler is of 8 bits, so 256 prescaler values and hence 256 possible |
112 | * The requested period will be applied only if it matches one of these | 164 | * period values are supported (for a particular clock rate). The requested |
113 | * 256 values. | 165 | * period will be applied only if it matches one of these 256 values. |
114 | */ | 166 | */ |
115 | static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | 167 | static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
116 | int duty_ns, int period_ns) | 168 | int duty_ns, int period_ns) |
117 | { | 169 | { |
118 | struct sti_pwm_chip *pc = to_sti_pwmchip(chip); | 170 | struct sti_pwm_chip *pc = to_sti_pwmchip(chip); |
119 | struct sti_pwm_compat_data *cdata = pc->cdata; | 171 | struct sti_pwm_compat_data *cdata = pc->cdata; |
172 | unsigned int ncfg, value, prescale = 0; | ||
120 | struct pwm_device *cur = pc->cur; | 173 | struct pwm_device *cur = pc->cur; |
121 | struct device *dev = pc->dev; | 174 | struct device *dev = pc->dev; |
122 | unsigned int prescale = 0, pwmvalx; | ||
123 | int ret; | ||
124 | unsigned int ncfg; | ||
125 | bool period_same = false; | 175 | bool period_same = false; |
176 | int ret; | ||
126 | 177 | ||
127 | ncfg = hweight_long(pc->configured); | 178 | ncfg = hweight_long(pc->configured); |
128 | if (ncfg) | 179 | if (ncfg) |
129 | period_same = (period_ns == pwm_get_period(cur)); | 180 | period_same = (period_ns == pwm_get_period(cur)); |
130 | 181 | ||
131 | /* Allow configuration changes if one of the | 182 | /* |
132 | * following conditions satisfy. | 183 | * Allow configuration changes if one of the following conditions |
133 | * 1. No channels have been configured. | 184 | * satisfy. |
134 | * 2. Only one channel has been configured and the new request | 185 | * 1. No devices have been configured. |
135 | * is for the same channel. | 186 | * 2. Only one device has been configured and the new request is for |
136 | * 3. Only one channel has been configured and the new request is | 187 | * the same device. |
137 | * for a new channel and period of the new channel is same as | 188 | * 3. Only one device has been configured and the new request is for |
138 | * the current configured period. | 189 | * a new device and period of the new device is same as the current |
139 | * 4. More than one channels are configured and period of the new | 190 | * configured period. |
191 | * 4. More than one devices are configured and period of the new | ||
140 | * requestis the same as the current period. | 192 | * requestis the same as the current period. |
141 | */ | 193 | */ |
142 | if (!ncfg || | 194 | if (!ncfg || |
@@ -144,7 +196,11 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
144 | ((ncfg == 1) && (pwm->hwpwm != cur->hwpwm) && period_same) || | 196 | ((ncfg == 1) && (pwm->hwpwm != cur->hwpwm) && period_same) || |
145 | ((ncfg > 1) && period_same)) { | 197 | ((ncfg > 1) && period_same)) { |
146 | /* Enable clock before writing to PWM registers. */ | 198 | /* Enable clock before writing to PWM registers. */ |
147 | ret = clk_enable(pc->clk); | 199 | ret = clk_enable(pc->pwm_clk); |
200 | if (ret) | ||
201 | return ret; | ||
202 | |||
203 | ret = clk_enable(pc->cpt_clk); | ||
148 | if (ret) | 204 | if (ret) |
149 | return ret; | 205 | return ret; |
150 | 206 | ||
@@ -153,15 +209,15 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
153 | if (ret) | 209 | if (ret) |
154 | goto clk_dis; | 210 | goto clk_dis; |
155 | 211 | ||
156 | ret = | 212 | value = prescale & PWM_PRESCALE_LOW_MASK; |
157 | regmap_field_write(pc->prescale_low, | 213 | |
158 | prescale & PWM_PRESCALE_LOW_MASK); | 214 | ret = regmap_field_write(pc->prescale_low, value); |
159 | if (ret) | 215 | if (ret) |
160 | goto clk_dis; | 216 | goto clk_dis; |
161 | 217 | ||
162 | ret = | 218 | value = (prescale & PWM_PRESCALE_HIGH_MASK) >> 4; |
163 | regmap_field_write(pc->prescale_high, | 219 | |
164 | (prescale & PWM_PRESCALE_HIGH_MASK) >> 4); | 220 | ret = regmap_field_write(pc->prescale_high, value); |
165 | if (ret) | 221 | if (ret) |
166 | goto clk_dis; | 222 | goto clk_dis; |
167 | } | 223 | } |
@@ -172,25 +228,26 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
172 | * PWM pulse = (max_pwm_count + 1) local cycles, | 228 | * PWM pulse = (max_pwm_count + 1) local cycles, |
173 | * that is continuous pulse: signal never goes low. | 229 | * that is continuous pulse: signal never goes low. |
174 | */ | 230 | */ |
175 | pwmvalx = cdata->max_pwm_cnt * duty_ns / period_ns; | 231 | value = cdata->max_pwm_cnt * duty_ns / period_ns; |
176 | 232 | ||
177 | ret = regmap_write(pc->regmap, STI_DS_REG(pwm->hwpwm), pwmvalx); | 233 | ret = regmap_write(pc->regmap, PWM_OUT_VAL(pwm->hwpwm), value); |
178 | if (ret) | 234 | if (ret) |
179 | goto clk_dis; | 235 | goto clk_dis; |
180 | 236 | ||
181 | ret = regmap_field_write(pc->pwm_int_en, 0); | 237 | ret = regmap_field_write(pc->pwm_cpt_int_en, 0); |
182 | 238 | ||
183 | set_bit(pwm->hwpwm, &pc->configured); | 239 | set_bit(pwm->hwpwm, &pc->configured); |
184 | pc->cur = pwm; | 240 | pc->cur = pwm; |
185 | 241 | ||
186 | dev_dbg(dev, "prescale:%u, period:%i, duty:%i, pwmvalx:%u\n", | 242 | dev_dbg(dev, "prescale:%u, period:%i, duty:%i, value:%u\n", |
187 | prescale, period_ns, duty_ns, pwmvalx); | 243 | prescale, period_ns, duty_ns, value); |
188 | } else { | 244 | } else { |
189 | return -EINVAL; | 245 | return -EINVAL; |
190 | } | 246 | } |
191 | 247 | ||
192 | clk_dis: | 248 | clk_dis: |
193 | clk_disable(pc->clk); | 249 | clk_disable(pc->pwm_clk); |
250 | clk_disable(pc->cpt_clk); | ||
194 | return ret; | 251 | return ret; |
195 | } | 252 | } |
196 | 253 | ||
@@ -201,23 +258,30 @@ static int sti_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
201 | int ret = 0; | 258 | int ret = 0; |
202 | 259 | ||
203 | /* | 260 | /* |
204 | * Since we have a common enable for all PWM channels, | 261 | * Since we have a common enable for all PWM devices, do not enable if |
205 | * do not enable if already enabled. | 262 | * already enabled. |
206 | */ | 263 | */ |
207 | mutex_lock(&pc->sti_pwm_lock); | 264 | mutex_lock(&pc->sti_pwm_lock); |
265 | |||
208 | if (!pc->en_count) { | 266 | if (!pc->en_count) { |
209 | ret = clk_enable(pc->clk); | 267 | ret = clk_enable(pc->pwm_clk); |
268 | if (ret) | ||
269 | goto out; | ||
270 | |||
271 | ret = clk_enable(pc->cpt_clk); | ||
210 | if (ret) | 272 | if (ret) |
211 | goto out; | 273 | goto out; |
212 | 274 | ||
213 | ret = regmap_field_write(pc->pwm_en, 1); | 275 | ret = regmap_field_write(pc->pwm_out_en, 1); |
214 | if (ret) { | 276 | if (ret) { |
215 | dev_err(dev, "failed to enable PWM device:%d\n", | 277 | dev_err(dev, "failed to enable PWM device %u: %d\n", |
216 | pwm->hwpwm); | 278 | pwm->hwpwm, ret); |
217 | goto out; | 279 | goto out; |
218 | } | 280 | } |
219 | } | 281 | } |
282 | |||
220 | pc->en_count++; | 283 | pc->en_count++; |
284 | |||
221 | out: | 285 | out: |
222 | mutex_unlock(&pc->sti_pwm_lock); | 286 | mutex_unlock(&pc->sti_pwm_lock); |
223 | return ret; | 287 | return ret; |
@@ -228,13 +292,17 @@ static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
228 | struct sti_pwm_chip *pc = to_sti_pwmchip(chip); | 292 | struct sti_pwm_chip *pc = to_sti_pwmchip(chip); |
229 | 293 | ||
230 | mutex_lock(&pc->sti_pwm_lock); | 294 | mutex_lock(&pc->sti_pwm_lock); |
295 | |||
231 | if (--pc->en_count) { | 296 | if (--pc->en_count) { |
232 | mutex_unlock(&pc->sti_pwm_lock); | 297 | mutex_unlock(&pc->sti_pwm_lock); |
233 | return; | 298 | return; |
234 | } | 299 | } |
235 | regmap_field_write(pc->pwm_en, 0); | ||
236 | 300 | ||
237 | clk_disable(pc->clk); | 301 | regmap_field_write(pc->pwm_out_en, 0); |
302 | |||
303 | clk_disable(pc->pwm_clk); | ||
304 | clk_disable(pc->cpt_clk); | ||
305 | |||
238 | mutex_unlock(&pc->sti_pwm_lock); | 306 | mutex_unlock(&pc->sti_pwm_lock); |
239 | } | 307 | } |
240 | 308 | ||
@@ -245,7 +313,90 @@ static void sti_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | |||
245 | clear_bit(pwm->hwpwm, &pc->configured); | 313 | clear_bit(pwm->hwpwm, &pc->configured); |
246 | } | 314 | } |
247 | 315 | ||
316 | static int sti_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, | ||
317 | struct pwm_capture *result, unsigned long timeout) | ||
318 | { | ||
319 | struct sti_pwm_chip *pc = to_sti_pwmchip(chip); | ||
320 | struct sti_pwm_compat_data *cdata = pc->cdata; | ||
321 | struct sti_cpt_ddata *ddata = pwm_get_chip_data(pwm); | ||
322 | struct device *dev = pc->dev; | ||
323 | unsigned int effective_ticks; | ||
324 | unsigned long long high, low; | ||
325 | int ret; | ||
326 | |||
327 | if (pwm->hwpwm >= cdata->cpt_num_devs) { | ||
328 | dev_err(dev, "device %u is not valid\n", pwm->hwpwm); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | mutex_lock(&ddata->lock); | ||
333 | ddata->index = 0; | ||
334 | |||
335 | /* Prepare capture measurement */ | ||
336 | regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_RISING); | ||
337 | regmap_field_write(pc->pwm_cpt_int_en, BIT(pwm->hwpwm)); | ||
338 | |||
339 | /* Enable capture */ | ||
340 | ret = regmap_field_write(pc->pwm_cpt_en, 1); | ||
341 | if (ret) { | ||
342 | dev_err(dev, "failed to enable PWM capture %u: %d\n", | ||
343 | pwm->hwpwm, ret); | ||
344 | goto out; | ||
345 | } | ||
346 | |||
347 | ret = wait_event_interruptible_timeout(ddata->wait, ddata->index > 1, | ||
348 | msecs_to_jiffies(timeout)); | ||
349 | |||
350 | regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_DISABLED); | ||
351 | |||
352 | if (ret == -ERESTARTSYS) | ||
353 | goto out; | ||
354 | |||
355 | switch (ddata->index) { | ||
356 | case 0: | ||
357 | case 1: | ||
358 | /* | ||
359 | * Getting here could mean: | ||
360 | * - input signal is constant of less than 1 Hz | ||
361 | * - there is no input signal at all | ||
362 | * | ||
363 | * In such case the frequency is rounded down to 0 | ||
364 | */ | ||
365 | result->period = 0; | ||
366 | result->duty_cycle = 0; | ||
367 | |||
368 | break; | ||
369 | |||
370 | case 2: | ||
371 | /* We have everying we need */ | ||
372 | high = ddata->snapshot[1] - ddata->snapshot[0]; | ||
373 | low = ddata->snapshot[2] - ddata->snapshot[1]; | ||
374 | |||
375 | effective_ticks = clk_get_rate(pc->cpt_clk); | ||
376 | |||
377 | result->period = (high + low) * NSEC_PER_SEC; | ||
378 | result->period /= effective_ticks; | ||
379 | |||
380 | result->duty_cycle = high * NSEC_PER_SEC; | ||
381 | result->duty_cycle /= effective_ticks; | ||
382 | |||
383 | break; | ||
384 | |||
385 | default: | ||
386 | dev_err(dev, "internal error\n"); | ||
387 | break; | ||
388 | } | ||
389 | |||
390 | out: | ||
391 | /* Disable capture */ | ||
392 | regmap_field_write(pc->pwm_cpt_en, 0); | ||
393 | |||
394 | mutex_unlock(&ddata->lock); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
248 | static const struct pwm_ops sti_pwm_ops = { | 398 | static const struct pwm_ops sti_pwm_ops = { |
399 | .capture = sti_pwm_capture, | ||
249 | .config = sti_pwm_config, | 400 | .config = sti_pwm_config, |
250 | .enable = sti_pwm_enable, | 401 | .enable = sti_pwm_enable, |
251 | .disable = sti_pwm_disable, | 402 | .disable = sti_pwm_disable, |
@@ -253,17 +404,98 @@ static const struct pwm_ops sti_pwm_ops = { | |||
253 | .owner = THIS_MODULE, | 404 | .owner = THIS_MODULE, |
254 | }; | 405 | }; |
255 | 406 | ||
407 | static irqreturn_t sti_pwm_interrupt(int irq, void *data) | ||
408 | { | ||
409 | struct sti_pwm_chip *pc = data; | ||
410 | struct device *dev = pc->dev; | ||
411 | struct sti_cpt_ddata *ddata; | ||
412 | int devicenum; | ||
413 | unsigned int cpt_int_stat; | ||
414 | unsigned int reg; | ||
415 | int ret = IRQ_NONE; | ||
416 | |||
417 | ret = regmap_field_read(pc->pwm_cpt_int_stat, &cpt_int_stat); | ||
418 | if (ret) | ||
419 | return ret; | ||
420 | |||
421 | while (cpt_int_stat) { | ||
422 | devicenum = ffs(cpt_int_stat) - 1; | ||
423 | |||
424 | ddata = pwm_get_chip_data(&pc->chip.pwms[devicenum]); | ||
425 | |||
426 | /* | ||
427 | * Capture input: | ||
428 | * _______ _______ | ||
429 | * | | | | | ||
430 | * __| |_________________| |________ | ||
431 | * ^0 ^1 ^2 | ||
432 | * | ||
433 | * Capture start by the first available rising edge. When a | ||
434 | * capture event occurs, capture value (CPT_VALx) is stored, | ||
435 | * index incremented, capture edge changed. | ||
436 | * | ||
437 | * After the capture, if the index > 1, we have collected the | ||
438 | * necessary data so we signal the thread waiting for it and | ||
439 | * disable the capture by setting capture edge to none | ||
440 | */ | ||
441 | |||
442 | regmap_read(pc->regmap, | ||
443 | PWM_CPT_VAL(devicenum), | ||
444 | &ddata->snapshot[ddata->index]); | ||
445 | |||
446 | switch (ddata->index) { | ||
447 | case 0: | ||
448 | case 1: | ||
449 | regmap_read(pc->regmap, PWM_CPT_EDGE(devicenum), ®); | ||
450 | reg ^= PWM_CPT_EDGE_MASK; | ||
451 | regmap_write(pc->regmap, PWM_CPT_EDGE(devicenum), reg); | ||
452 | |||
453 | ddata->index++; | ||
454 | break; | ||
455 | |||
456 | case 2: | ||
457 | regmap_write(pc->regmap, | ||
458 | PWM_CPT_EDGE(devicenum), | ||
459 | CPT_EDGE_DISABLED); | ||
460 | wake_up(&ddata->wait); | ||
461 | break; | ||
462 | |||
463 | default: | ||
464 | dev_err(dev, "Internal error\n"); | ||
465 | } | ||
466 | |||
467 | cpt_int_stat &= ~BIT_MASK(devicenum); | ||
468 | |||
469 | ret = IRQ_HANDLED; | ||
470 | } | ||
471 | |||
472 | /* Just ACK everything */ | ||
473 | regmap_write(pc->regmap, PWM_INT_ACK, PWM_INT_ACK_MASK); | ||
474 | |||
475 | return ret; | ||
476 | } | ||
477 | |||
256 | static int sti_pwm_probe_dt(struct sti_pwm_chip *pc) | 478 | static int sti_pwm_probe_dt(struct sti_pwm_chip *pc) |
257 | { | 479 | { |
258 | struct device *dev = pc->dev; | 480 | struct device *dev = pc->dev; |
259 | const struct reg_field *reg_fields; | 481 | const struct reg_field *reg_fields; |
260 | struct device_node *np = dev->of_node; | 482 | struct device_node *np = dev->of_node; |
261 | struct sti_pwm_compat_data *cdata = pc->cdata; | 483 | struct sti_pwm_compat_data *cdata = pc->cdata; |
262 | u32 num_chan; | 484 | u32 num_devs; |
485 | int ret; | ||
486 | |||
487 | ret = of_property_read_u32(np, "st,pwm-num-chan", &num_devs); | ||
488 | if (!ret) | ||
489 | cdata->pwm_num_devs = num_devs; | ||
490 | |||
491 | ret = of_property_read_u32(np, "st,capture-num-chan", &num_devs); | ||
492 | if (!ret) | ||
493 | cdata->cpt_num_devs = num_devs; | ||
263 | 494 | ||
264 | of_property_read_u32(np, "st,pwm-num-chan", &num_chan); | 495 | if (!cdata->pwm_num_devs && !cdata->cpt_num_devs) { |
265 | if (num_chan) | 496 | dev_err(dev, "No channels configured\n"); |
266 | cdata->num_chan = num_chan; | 497 | return -EINVAL; |
498 | } | ||
267 | 499 | ||
268 | reg_fields = cdata->reg_fields; | 500 | reg_fields = cdata->reg_fields; |
269 | 501 | ||
@@ -277,15 +509,26 @@ static int sti_pwm_probe_dt(struct sti_pwm_chip *pc) | |||
277 | if (IS_ERR(pc->prescale_high)) | 509 | if (IS_ERR(pc->prescale_high)) |
278 | return PTR_ERR(pc->prescale_high); | 510 | return PTR_ERR(pc->prescale_high); |
279 | 511 | ||
280 | pc->pwm_en = devm_regmap_field_alloc(dev, pc->regmap, | ||
281 | reg_fields[PWM_EN]); | ||
282 | if (IS_ERR(pc->pwm_en)) | ||
283 | return PTR_ERR(pc->pwm_en); | ||
284 | 512 | ||
285 | pc->pwm_int_en = devm_regmap_field_alloc(dev, pc->regmap, | 513 | pc->pwm_out_en = devm_regmap_field_alloc(dev, pc->regmap, |
286 | reg_fields[PWM_INT_EN]); | 514 | reg_fields[PWM_OUT_EN]); |
287 | if (IS_ERR(pc->pwm_int_en)) | 515 | if (IS_ERR(pc->pwm_out_en)) |
288 | return PTR_ERR(pc->pwm_int_en); | 516 | return PTR_ERR(pc->pwm_out_en); |
517 | |||
518 | pc->pwm_cpt_en = devm_regmap_field_alloc(dev, pc->regmap, | ||
519 | reg_fields[PWM_CPT_EN]); | ||
520 | if (IS_ERR(pc->pwm_cpt_en)) | ||
521 | return PTR_ERR(pc->pwm_cpt_en); | ||
522 | |||
523 | pc->pwm_cpt_int_en = devm_regmap_field_alloc(dev, pc->regmap, | ||
524 | reg_fields[PWM_CPT_INT_EN]); | ||
525 | if (IS_ERR(pc->pwm_cpt_int_en)) | ||
526 | return PTR_ERR(pc->pwm_cpt_int_en); | ||
527 | |||
528 | pc->pwm_cpt_int_stat = devm_regmap_field_alloc(dev, pc->regmap, | ||
529 | reg_fields[PWM_CPT_INT_STAT]); | ||
530 | if (PTR_ERR_OR_ZERO(pc->pwm_cpt_int_stat)) | ||
531 | return PTR_ERR(pc->pwm_cpt_int_stat); | ||
289 | 532 | ||
290 | return 0; | 533 | return 0; |
291 | } | 534 | } |
@@ -302,7 +545,8 @@ static int sti_pwm_probe(struct platform_device *pdev) | |||
302 | struct sti_pwm_compat_data *cdata; | 545 | struct sti_pwm_compat_data *cdata; |
303 | struct sti_pwm_chip *pc; | 546 | struct sti_pwm_chip *pc; |
304 | struct resource *res; | 547 | struct resource *res; |
305 | int ret; | 548 | unsigned int i; |
549 | int irq, ret; | ||
306 | 550 | ||
307 | pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); | 551 | pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); |
308 | if (!pc) | 552 | if (!pc) |
@@ -323,14 +567,28 @@ static int sti_pwm_probe(struct platform_device *pdev) | |||
323 | if (IS_ERR(pc->regmap)) | 567 | if (IS_ERR(pc->regmap)) |
324 | return PTR_ERR(pc->regmap); | 568 | return PTR_ERR(pc->regmap); |
325 | 569 | ||
570 | irq = platform_get_irq(pdev, 0); | ||
571 | if (irq < 0) { | ||
572 | dev_err(&pdev->dev, "Failed to obtain IRQ\n"); | ||
573 | return irq; | ||
574 | } | ||
575 | |||
576 | ret = devm_request_irq(&pdev->dev, irq, sti_pwm_interrupt, 0, | ||
577 | pdev->name, pc); | ||
578 | if (ret < 0) { | ||
579 | dev_err(&pdev->dev, "Failed to request IRQ\n"); | ||
580 | return ret; | ||
581 | } | ||
582 | |||
326 | /* | 583 | /* |
327 | * Setup PWM data with default values: some values could be replaced | 584 | * Setup PWM data with default values: some values could be replaced |
328 | * with specific ones provided from Device Tree. | 585 | * with specific ones provided from Device Tree. |
329 | */ | 586 | */ |
330 | cdata->reg_fields = &sti_pwm_regfields[0]; | 587 | cdata->reg_fields = sti_pwm_regfields; |
331 | cdata->max_prescale = 0xff; | 588 | cdata->max_prescale = 0xff; |
332 | cdata->max_pwm_cnt = 255; | 589 | cdata->max_pwm_cnt = 255; |
333 | cdata->num_chan = 1; | 590 | cdata->pwm_num_devs = 0; |
591 | cdata->cpt_num_devs = 0; | ||
334 | 592 | ||
335 | pc->cdata = cdata; | 593 | pc->cdata = cdata; |
336 | pc->dev = dev; | 594 | pc->dev = dev; |
@@ -341,36 +599,64 @@ static int sti_pwm_probe(struct platform_device *pdev) | |||
341 | if (ret) | 599 | if (ret) |
342 | return ret; | 600 | return ret; |
343 | 601 | ||
344 | pc->clk = of_clk_get_by_name(dev->of_node, "pwm"); | 602 | if (!cdata->pwm_num_devs) |
345 | if (IS_ERR(pc->clk)) { | 603 | goto skip_pwm; |
604 | |||
605 | pc->pwm_clk = of_clk_get_by_name(dev->of_node, "pwm"); | ||
606 | if (IS_ERR(pc->pwm_clk)) { | ||
346 | dev_err(dev, "failed to get PWM clock\n"); | 607 | dev_err(dev, "failed to get PWM clock\n"); |
347 | return PTR_ERR(pc->clk); | 608 | return PTR_ERR(pc->pwm_clk); |
348 | } | 609 | } |
349 | 610 | ||
350 | pc->clk_rate = clk_get_rate(pc->clk); | 611 | ret = clk_prepare(pc->pwm_clk); |
351 | if (!pc->clk_rate) { | 612 | if (ret) { |
352 | dev_err(dev, "failed to get clock rate\n"); | 613 | dev_err(dev, "failed to prepare clock\n"); |
353 | return -EINVAL; | 614 | return ret; |
354 | } | 615 | } |
355 | 616 | ||
356 | ret = clk_prepare(pc->clk); | 617 | skip_pwm: |
618 | if (!cdata->cpt_num_devs) | ||
619 | goto skip_cpt; | ||
620 | |||
621 | pc->cpt_clk = of_clk_get_by_name(dev->of_node, "capture"); | ||
622 | if (IS_ERR(pc->cpt_clk)) { | ||
623 | dev_err(dev, "failed to get PWM capture clock\n"); | ||
624 | return PTR_ERR(pc->cpt_clk); | ||
625 | } | ||
626 | |||
627 | ret = clk_prepare(pc->cpt_clk); | ||
357 | if (ret) { | 628 | if (ret) { |
358 | dev_err(dev, "failed to prepare clock\n"); | 629 | dev_err(dev, "failed to prepare clock\n"); |
359 | return ret; | 630 | return ret; |
360 | } | 631 | } |
361 | 632 | ||
633 | skip_cpt: | ||
362 | pc->chip.dev = dev; | 634 | pc->chip.dev = dev; |
363 | pc->chip.ops = &sti_pwm_ops; | 635 | pc->chip.ops = &sti_pwm_ops; |
364 | pc->chip.base = -1; | 636 | pc->chip.base = -1; |
365 | pc->chip.npwm = pc->cdata->num_chan; | 637 | pc->chip.npwm = pc->cdata->pwm_num_devs; |
366 | pc->chip.can_sleep = true; | 638 | pc->chip.can_sleep = true; |
367 | 639 | ||
368 | ret = pwmchip_add(&pc->chip); | 640 | ret = pwmchip_add(&pc->chip); |
369 | if (ret < 0) { | 641 | if (ret < 0) { |
370 | clk_unprepare(pc->clk); | 642 | clk_unprepare(pc->pwm_clk); |
643 | clk_unprepare(pc->cpt_clk); | ||
371 | return ret; | 644 | return ret; |
372 | } | 645 | } |
373 | 646 | ||
647 | for (i = 0; i < cdata->cpt_num_devs; i++) { | ||
648 | struct sti_cpt_ddata *ddata; | ||
649 | |||
650 | ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); | ||
651 | if (!ddata) | ||
652 | return -ENOMEM; | ||
653 | |||
654 | init_waitqueue_head(&ddata->wait); | ||
655 | mutex_init(&ddata->lock); | ||
656 | |||
657 | pwm_set_chip_data(&pc->chip.pwms[i], ddata); | ||
658 | } | ||
659 | |||
374 | platform_set_drvdata(pdev, pc); | 660 | platform_set_drvdata(pdev, pc); |
375 | 661 | ||
376 | return 0; | 662 | return 0; |
@@ -381,10 +667,11 @@ static int sti_pwm_remove(struct platform_device *pdev) | |||
381 | struct sti_pwm_chip *pc = platform_get_drvdata(pdev); | 667 | struct sti_pwm_chip *pc = platform_get_drvdata(pdev); |
382 | unsigned int i; | 668 | unsigned int i; |
383 | 669 | ||
384 | for (i = 0; i < pc->cdata->num_chan; i++) | 670 | for (i = 0; i < pc->cdata->pwm_num_devs; i++) |
385 | pwm_disable(&pc->chip.pwms[i]); | 671 | pwm_disable(&pc->chip.pwms[i]); |
386 | 672 | ||
387 | clk_unprepare(pc->clk); | 673 | clk_unprepare(pc->pwm_clk); |
674 | clk_unprepare(pc->cpt_clk); | ||
388 | 675 | ||
389 | return pwmchip_remove(&pc->chip); | 676 | return pwmchip_remove(&pc->chip); |
390 | } | 677 | } |
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 03a99a53c39e..b0803f6c64d9 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c | |||
@@ -284,6 +284,12 @@ static const struct sun4i_pwm_data sun4i_pwm_data_a20 = { | |||
284 | .npwm = 2, | 284 | .npwm = 2, |
285 | }; | 285 | }; |
286 | 286 | ||
287 | static const struct sun4i_pwm_data sun4i_pwm_data_h3 = { | ||
288 | .has_prescaler_bypass = true, | ||
289 | .has_rdy = true, | ||
290 | .npwm = 1, | ||
291 | }; | ||
292 | |||
287 | static const struct of_device_id sun4i_pwm_dt_ids[] = { | 293 | static const struct of_device_id sun4i_pwm_dt_ids[] = { |
288 | { | 294 | { |
289 | .compatible = "allwinner,sun4i-a10-pwm", | 295 | .compatible = "allwinner,sun4i-a10-pwm", |
@@ -298,6 +304,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { | |||
298 | .compatible = "allwinner,sun7i-a20-pwm", | 304 | .compatible = "allwinner,sun7i-a20-pwm", |
299 | .data = &sun4i_pwm_data_a20, | 305 | .data = &sun4i_pwm_data_a20, |
300 | }, { | 306 | }, { |
307 | .compatible = "allwinner,sun8i-h3-pwm", | ||
308 | .data = &sun4i_pwm_data_h3, | ||
309 | }, { | ||
301 | /* sentinel */ | 310 | /* sentinel */ |
302 | }, | 311 | }, |
303 | }; | 312 | }; |
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c index 829f4991c96f..7fa85a1604da 100644 --- a/drivers/pwm/pwm-tipwmss.c +++ b/drivers/pwm/pwm-tipwmss.c | |||
@@ -34,7 +34,6 @@ static int pwmss_probe(struct platform_device *pdev) | |||
34 | struct device_node *node = pdev->dev.of_node; | 34 | struct device_node *node = pdev->dev.of_node; |
35 | 35 | ||
36 | pm_runtime_enable(&pdev->dev); | 36 | pm_runtime_enable(&pdev->dev); |
37 | pm_runtime_get_sync(&pdev->dev); | ||
38 | 37 | ||
39 | /* Populate all the child nodes here... */ | 38 | /* Populate all the child nodes here... */ |
40 | ret = of_platform_populate(node, NULL, NULL, &pdev->dev); | 39 | ret = of_platform_populate(node, NULL, NULL, &pdev->dev); |
@@ -46,31 +45,13 @@ static int pwmss_probe(struct platform_device *pdev) | |||
46 | 45 | ||
47 | static int pwmss_remove(struct platform_device *pdev) | 46 | static int pwmss_remove(struct platform_device *pdev) |
48 | { | 47 | { |
49 | pm_runtime_put_sync(&pdev->dev); | ||
50 | pm_runtime_disable(&pdev->dev); | 48 | pm_runtime_disable(&pdev->dev); |
51 | return 0; | 49 | return 0; |
52 | } | 50 | } |
53 | 51 | ||
54 | #ifdef CONFIG_PM_SLEEP | ||
55 | static int pwmss_suspend(struct device *dev) | ||
56 | { | ||
57 | pm_runtime_put_sync(dev); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int pwmss_resume(struct device *dev) | ||
62 | { | ||
63 | pm_runtime_get_sync(dev); | ||
64 | return 0; | ||
65 | } | ||
66 | #endif | ||
67 | |||
68 | static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume); | ||
69 | |||
70 | static struct platform_driver pwmss_driver = { | 52 | static struct platform_driver pwmss_driver = { |
71 | .driver = { | 53 | .driver = { |
72 | .name = "pwmss", | 54 | .name = "pwmss", |
73 | .pm = &pwmss_pm_ops, | ||
74 | .of_match_table = pwmss_of_match, | 55 | .of_match_table = pwmss_of_match, |
75 | }, | 56 | }, |
76 | .probe = pwmss_probe, | 57 | .probe = pwmss_probe, |
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index 04f76725d591..7a993b056638 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c | |||
@@ -269,6 +269,22 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
269 | goto out; | 269 | goto out; |
270 | } | 270 | } |
271 | 271 | ||
272 | val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN); | ||
273 | |||
274 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); | ||
275 | if (ret < 0) { | ||
276 | dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); | ||
277 | goto out; | ||
278 | } | ||
279 | |||
280 | val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN); | ||
281 | |||
282 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); | ||
283 | if (ret < 0) { | ||
284 | dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); | ||
285 | goto out; | ||
286 | } | ||
287 | |||
272 | twl->twl6030_toggle3 = val; | 288 | twl->twl6030_toggle3 = val; |
273 | out: | 289 | out: |
274 | mutex_unlock(&twl->mutex); | 290 | mutex_unlock(&twl->mutex); |
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 18ed725594c3..0296d8178ae2 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c | |||
@@ -409,6 +409,24 @@ void pwmchip_sysfs_unexport(struct pwm_chip *chip) | |||
409 | } | 409 | } |
410 | } | 410 | } |
411 | 411 | ||
412 | void pwmchip_sysfs_unexport_children(struct pwm_chip *chip) | ||
413 | { | ||
414 | struct device *parent; | ||
415 | unsigned int i; | ||
416 | |||
417 | parent = class_find_device(&pwm_class, NULL, chip, | ||
418 | pwmchip_sysfs_match); | ||
419 | if (!parent) | ||
420 | return; | ||
421 | |||
422 | for (i = 0; i < chip->npwm; i++) { | ||
423 | struct pwm_device *pwm = &chip->pwms[i]; | ||
424 | |||
425 | if (test_bit(PWMF_EXPORTED, &pwm->flags)) | ||
426 | pwm_unexport_child(parent, pwm); | ||
427 | } | ||
428 | } | ||
429 | |||
412 | static int __init pwm_sysfs_init(void) | 430 | static int __init pwm_sysfs_init(void) |
413 | { | 431 | { |
414 | return class_register(&pwm_class); | 432 | return class_register(&pwm_class); |
diff --git a/include/linux/pwm.h b/include/linux/pwm.h index f1bbae014889..2c6c5114c089 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h | |||
@@ -641,6 +641,7 @@ static inline void pwm_remove_table(struct pwm_lookup *table, size_t num) | |||
641 | #ifdef CONFIG_PWM_SYSFS | 641 | #ifdef CONFIG_PWM_SYSFS |
642 | void pwmchip_sysfs_export(struct pwm_chip *chip); | 642 | void pwmchip_sysfs_export(struct pwm_chip *chip); |
643 | void pwmchip_sysfs_unexport(struct pwm_chip *chip); | 643 | void pwmchip_sysfs_unexport(struct pwm_chip *chip); |
644 | void pwmchip_sysfs_unexport_children(struct pwm_chip *chip); | ||
644 | #else | 645 | #else |
645 | static inline void pwmchip_sysfs_export(struct pwm_chip *chip) | 646 | static inline void pwmchip_sysfs_export(struct pwm_chip *chip) |
646 | { | 647 | { |
@@ -649,6 +650,10 @@ static inline void pwmchip_sysfs_export(struct pwm_chip *chip) | |||
649 | static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip) | 650 | static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip) |
650 | { | 651 | { |
651 | } | 652 | } |
653 | |||
654 | static inline void pwmchip_sysfs_unexport_children(struct pwm_chip *chip) | ||
655 | { | ||
656 | } | ||
652 | #endif /* CONFIG_PWM_SYSFS */ | 657 | #endif /* CONFIG_PWM_SYSFS */ |
653 | 658 | ||
654 | #endif /* __LINUX_PWM_H */ | 659 | #endif /* __LINUX_PWM_H */ |