summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-11 12:16:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-11 12:16:10 -0500
commitc8fff3ed321abf11bea7464884b0876c46ff2491 (patch)
tree0275ed769371ba07451b14c41d4c0760efa1b8e1
parentbaf51c43926ec9aa42ef9d33ca6ee9e3e043aebe (diff)
parent5dcd7b42f1d06c62b5589441e69cc77c26c8b725 (diff)
Merge tag 'pwm/for-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding: "This round contains a couple of new drivers for the Marvell Berlin family of SoCs, various SoCs from Renesas and Broadcom as well as the backlight PWM present on MediaTek SoCs. Further existing drivers are extended to support a wider range of hardware. The remaining patches are minor fixes and cleanups across the board. Note that one of the patches included in this pull request is against arch/unicore32. I've included it here because I couldn't get a response from Guan Xuetao and I consider the change low-risk. Equivalent patches have been merged and tested in Samsung and PXA trees. The goal is to finally get rid of legacy code paths that have repeatedly been causing headaches" * tag 'pwm/for-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (24 commits) pwm: sunxi: Fix whitespace issue pwm: sysfs: Make use of the DEVICE_ATTR_[RW][WO] macro's pwm: sysfs: Remove unnecessary temporary variable unicore32: nb0916: Use PWM lookup table pwm: pwm-rcar: Revise the device tree binding document about compatible pwm: Return -ENODEV if no PWM lookup match is found pwm: sun4i: Add support for PWM controller on sun5i SoCs pwm: Set enable state properly on failed call to enable pwm: lpss: Add support for runtime PM pwm: lpss: Add more Intel Broxton IDs pwm: lpss: Support all four PWMs on Intel Broxton pwm: lpss: Add support for multiple PWMs pwm-pca9685: enable ACPI device found on Galileo Gen2 pwm: Add MediaTek display PWM driver support dt-bindings: pwm: Add MediaTek display PWM bindings pwm: tipwmss: Enable on TI DRA7x and AM437x pwm: atmel-hlcdc: add sama5d2 SoC support. pwm: Add Broadcom BCM7038 PWM controller support Documentation: dt: add Broadcom BCM7038 PWM controller binding pwm: Add support for R-Car PWM Timer ...
-rw-r--r--Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt20
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-berlin.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt42
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-sun4i.txt2
-rw-r--r--Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt26
-rw-r--r--arch/unicore32/kernel/puv3-nb0916.c10
-rw-r--r--drivers/pwm/Kconfig49
-rw-r--r--drivers/pwm/Makefile4
-rw-r--r--drivers/pwm/core.c37
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c4
-rw-r--r--drivers/pwm/pwm-berlin.c219
-rw-r--r--drivers/pwm/pwm-brcmstb.c343
-rw-r--r--drivers/pwm/pwm-lpss-pci.c37
-rw-r--r--drivers/pwm/pwm-lpss-platform.c7
-rw-r--r--drivers/pwm/pwm-lpss.c62
-rw-r--r--drivers/pwm/pwm-lpss.h2
-rw-r--r--drivers/pwm/pwm-mtk-disp.c243
-rw-r--r--drivers/pwm/pwm-pca9685.c20
-rw-r--r--drivers/pwm/pwm-rcar.c274
-rw-r--r--drivers/pwm/pwm-sun4i.c27
-rw-r--r--drivers/pwm/sysfs.c75
-rw-r--r--include/linux/pwm.h3
22 files changed, 1441 insertions, 82 deletions
diff --git a/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt b/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt
new file mode 100644
index 000000000000..d9254a6da5ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt
@@ -0,0 +1,20 @@
1Broadcom BCM7038 PWM controller (BCM7xxx Set Top Box PWM controller)
2
3Required properties:
4
5- compatible: must be "brcm,bcm7038-pwm"
6- reg: physical base address and length for this controller
7- #pwm-cells: should be 2. See pwm.txt in this directory for a description
8 of the cells format
9- clocks: a phandle to the reference clock for this block which is fed through
10 its internal variable clock frequency generator
11
12
13Example:
14
15 pwm: pwm@f0408000 {
16 compatible = "brcm,bcm7038-pwm";
17 reg = <0xf0408000 0x28>;
18 #pwm-cells = <2>;
19 clocks = <&upg_fixed>;
20 };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-berlin.txt b/Documentation/devicetree/bindings/pwm/pwm-berlin.txt
new file mode 100644
index 000000000000..82cbe16fcbbc
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-berlin.txt
@@ -0,0 +1,17 @@
1Berlin PWM controller
2
3Required properties:
4- compatible: should be "marvell,berlin-pwm"
5- reg: physical base address and length of the controller's registers
6- clocks: phandle to the input clock
7- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
8 the cells format.
9
10Example:
11
12pwm: pwm@f7f20000 {
13 compatible = "marvell,berlin-pwm";
14 reg = <0xf7f20000 0x40>;
15 clocks = <&chip_clk CLKID_CFG>;
16 #pwm-cells = <3>;
17}
diff --git a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
new file mode 100644
index 000000000000..f8f59baf6b67
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
@@ -0,0 +1,42 @@
1MediaTek display PWM controller
2
3Required properties:
4 - compatible: should be "mediatek,<name>-disp-pwm":
5 - "mediatek,mt8173-disp-pwm": found on mt8173 SoC.
6 - "mediatek,mt6595-disp-pwm": found on mt6595 SoC.
7 - 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 the cell format.
10 - clocks: phandle and clock specifier of the PWM reference clock.
11 - clock-names: must contain the following:
12 - "main": clock used to generate PWM signals.
13 - "mm": sync signals from the modules of mmsys.
14 - pinctrl-names: Must contain a "default" entry.
15 - pinctrl-0: One property must exist for each entry in pinctrl-names.
16 See pinctrl/pinctrl-bindings.txt for details of the property values.
17
18Example:
19 pwm0: pwm@1401e000 {
20 compatible = "mediatek,mt8173-disp-pwm",
21 "mediatek,mt6595-disp-pwm";
22 reg = <0 0x1401e000 0 0x1000>;
23 #pwm-cells = <2>;
24 clocks = <&mmsys CLK_MM_DISP_PWM026M>,
25 <&mmsys CLK_MM_DISP_PWM0MM>;
26 clock-names = "main", "mm";
27 pinctrl-names = "default";
28 pinctrl-0 = <&disp_pwm0_pins>;
29 };
30
31 backlight_lcd: backlight_lcd {
32 compatible = "pwm-backlight";
33 pwms = <&pwm0 0 1000000>;
34 brightness-levels = <
35 0 16 32 48 64 80 96 112
36 128 144 160 176 192 208 224 240
37 255
38 >;
39 default-brightness-level = <9>;
40 power-supply = <&mt6397_vio18_reg>;
41 enable-gpios = <&pio 95 GPIO_ACTIVE_HIGH>;
42 };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
index ae0273e19506..cf6068b8e974 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
@@ -3,6 +3,8 @@ Allwinner sun4i and sun7i SoC PWM controller
3Required properties: 3Required properties:
4 - compatible: should be one of: 4 - compatible: should be one of:
5 - "allwinner,sun4i-a10-pwm" 5 - "allwinner,sun4i-a10-pwm"
6 - "allwinner,sun5i-a10s-pwm"
7 - "allwinner,sun5i-a13-pwm"
6 - "allwinner,sun7i-a20-pwm" 8 - "allwinner,sun7i-a20-pwm"
7 - reg: physical base address and length of the controller's registers 9 - reg: physical base address and length of the controller's registers
8 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of 10 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
new file mode 100644
index 000000000000..0822a083fc57
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
@@ -0,0 +1,26 @@
1* Renesas R-Car PWM Timer Controller
2
3Required Properties:
4- compatible: should be "renesas,pwm-rcar" and one of the following.
5 - "renesas,pwm-r8a7778": for R-Car M1A
6 - "renesas,pwm-r8a7779": for R-Car H1
7 - "renesas,pwm-r8a7790": for R-Car H2
8 - "renesas,pwm-r8a7791": for R-Car M2-W
9 - "renesas,pwm-r8a7794": for R-Car E2
10- reg: base address and length of the registers block for the PWM.
11- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
12 the cells format.
13- clocks: clock phandle and specifier pair.
14- pinctrl-0: phandle, referring to a default pin configuration node.
15- pinctrl-names: Set to "default".
16
17Example: R8A7790 (R-Car H2) PWM Timer node
18
19 pwm0: pwm@e6e30000 {
20 compatible = "renesas,pwm-r8a7790", "renesas,pwm-rcar";
21 reg = <0 0xe6e30000 0 0x8>;
22 #pwm-cells = <2>;
23 clocks = <&mstp5_clks R8A7790_CLK_PWM>;
24 pinctrl-0 = <&pwm0_pins>;
25 pinctrl-names = "default";
26 };
diff --git a/arch/unicore32/kernel/puv3-nb0916.c b/arch/unicore32/kernel/puv3-nb0916.c
index 46ebfdccbc31..aab5f341dec0 100644
--- a/arch/unicore32/kernel/puv3-nb0916.c
+++ b/arch/unicore32/kernel/puv3-nb0916.c
@@ -19,6 +19,7 @@
19#include <linux/reboot.h> 19#include <linux/reboot.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/i2c.h> 21#include <linux/i2c.h>
22#include <linux/pwm.h>
22#include <linux/pwm_backlight.h> 23#include <linux/pwm_backlight.h>
23#include <linux/gpio.h> 24#include <linux/gpio.h>
24#include <linux/gpio_keys.h> 25#include <linux/gpio_keys.h>
@@ -49,11 +50,14 @@ static struct resource puv3_i2c_resources[] = {
49 } 50 }
50}; 51};
51 52
53static struct pwm_lookup nb0916_pwm_lookup[] = {
54 PWM_LOOKUP("PKUnity-v3-PWM", 0, "pwm-backlight", NULL, 70 * 1024,
55 PWM_POLARITY_NORMAL),
56};
57
52static struct platform_pwm_backlight_data nb0916_backlight_data = { 58static struct platform_pwm_backlight_data nb0916_backlight_data = {
53 .pwm_id = 0,
54 .max_brightness = 100, 59 .max_brightness = 100,
55 .dft_brightness = 100, 60 .dft_brightness = 100,
56 .pwm_period_ns = 70 * 1024,
57 .enable_gpio = -1, 61 .enable_gpio = -1,
58}; 62};
59 63
@@ -112,6 +116,8 @@ int __init mach_nb0916_init(void)
112 platform_device_register_simple("PKUnity-v3-I2C", -1, 116 platform_device_register_simple("PKUnity-v3-I2C", -1,
113 puv3_i2c_resources, ARRAY_SIZE(puv3_i2c_resources)); 117 puv3_i2c_resources, ARRAY_SIZE(puv3_i2c_resources));
114 118
119 pwm_add_table(nb0916_pwm_lookup, ARRAY_SIZE(nb0916_pwm_lookup));
120
115 platform_device_register_data(NULL, "pwm-backlight", -1, 121 platform_device_register_data(NULL, "pwm-backlight", -1,
116 &nb0916_backlight_data, sizeof(nb0916_backlight_data)); 122 &nb0916_backlight_data, sizeof(nb0916_backlight_data));
117 123
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 062630ab7424..2f4641a0e88b 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -92,6 +92,15 @@ config PWM_BCM2835
92 To compile this driver as a module, choose M here: the module 92 To compile this driver as a module, choose M here: the module
93 will be called pwm-bcm2835. 93 will be called pwm-bcm2835.
94 94
95config PWM_BERLIN
96 tristate "Marvell Berlin PWM support"
97 depends on ARCH_BERLIN
98 help
99 PWM framework driver for Marvell Berlin SoCs.
100
101 To compile this driver as a module, choose M here: the module
102 will be called pwm-berlin.
103
95config PWM_BFIN 104config PWM_BFIN
96 tristate "Blackfin PWM support" 105 tristate "Blackfin PWM support"
97 depends on BFIN_GPTIMERS 106 depends on BFIN_GPTIMERS
@@ -101,6 +110,16 @@ config PWM_BFIN
101 To compile this driver as a module, choose M here: the module 110 To compile this driver as a module, choose M here: the module
102 will be called pwm-bfin. 111 will be called pwm-bfin.
103 112
113config PWM_BRCMSTB
114 tristate "Broadcom STB PWM support"
115 depends on ARCH_BRCMSTB || BMIPS_GENERIC
116 help
117 Generic PWM framework driver for the Broadcom Set-top-Box
118 SoCs (BCM7xxx).
119
120 To compile this driver as a module, choose M Here: the module
121 will be called pwm-brcmstb.c.
122
104config PWM_CLPS711X 123config PWM_CLPS711X
105 tristate "CLPS711X PWM support" 124 tristate "CLPS711X PWM support"
106 depends on ARCH_CLPS711X || COMPILE_TEST 125 depends on ARCH_CLPS711X || COMPILE_TEST
@@ -230,6 +249,17 @@ config PWM_LPSS_PLATFORM
230 To compile this driver as a module, choose M here: the module 249 To compile this driver as a module, choose M here: the module
231 will be called pwm-lpss-platform. 250 will be called pwm-lpss-platform.
232 251
252config PWM_MTK_DISP
253 tristate "MediaTek display PWM driver"
254 depends on ARCH_MEDIATEK || COMPILE_TEST
255 depends on HAS_IOMEM
256 help
257 Generic PWM framework driver for MediaTek disp-pwm device.
258 The PWM is used to control the backlight brightness for display.
259
260 To compile this driver as a module, choose M here: the module
261 will be called pwm-mtk-disp.
262
233config PWM_MXS 263config PWM_MXS
234 tristate "Freescale MXS PWM support" 264 tristate "Freescale MXS PWM support"
235 depends on ARCH_MXS && OF 265 depends on ARCH_MXS && OF
@@ -242,7 +272,7 @@ config PWM_MXS
242 272
243config PWM_PCA9685 273config PWM_PCA9685
244 tristate "NXP PCA9685 PWM driver" 274 tristate "NXP PCA9685 PWM driver"
245 depends on OF && I2C 275 depends on I2C
246 select REGMAP_I2C 276 select REGMAP_I2C
247 help 277 help
248 Generic PWM framework driver for NXP PCA9685 LED controller. 278 Generic PWM framework driver for NXP PCA9685 LED controller.
@@ -268,6 +298,17 @@ config PWM_PXA
268 To compile this driver as a module, choose M here: the module 298 To compile this driver as a module, choose M here: the module
269 will be called pwm-pxa. 299 will be called pwm-pxa.
270 300
301config PWM_RCAR
302 tristate "Renesas R-Car PWM support"
303 depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || COMPILE_TEST
304 depends on HAS_IOMEM
305 help
306 This driver exposes the PWM Timer controller found in Renesas
307 R-Car chips through the PWM API.
308
309 To compile this driver as a module, choose M here: the module
310 will be called pwm-rcar.
311
271config PWM_RENESAS_TPU 312config PWM_RENESAS_TPU
272 tristate "Renesas TPU PWM support" 313 tristate "Renesas TPU PWM support"
273 depends on ARCH_SHMOBILE || COMPILE_TEST 314 depends on ARCH_SHMOBILE || COMPILE_TEST
@@ -338,7 +379,7 @@ config PWM_TEGRA
338 379
339config PWM_TIECAP 380config PWM_TIECAP
340 tristate "ECAP PWM support" 381 tristate "ECAP PWM support"
341 depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX 382 depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX
342 help 383 help
343 PWM driver support for the ECAP APWM controller found on AM33XX 384 PWM driver support for the ECAP APWM controller found on AM33XX
344 TI SOC 385 TI SOC
@@ -348,7 +389,7 @@ config PWM_TIECAP
348 389
349config PWM_TIEHRPWM 390config PWM_TIEHRPWM
350 tristate "EHRPWM PWM support" 391 tristate "EHRPWM PWM support"
351 depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX 392 depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX
352 help 393 help
353 PWM driver support for the EHRPWM controller found on AM33XX 394 PWM driver support for the EHRPWM controller found on AM33XX
354 TI SOC 395 TI SOC
@@ -358,7 +399,7 @@ config PWM_TIEHRPWM
358 399
359config PWM_TIPWMSS 400config PWM_TIPWMSS
360 bool 401 bool
361 default y if SOC_AM33XX && (PWM_TIECAP || PWM_TIEHRPWM) 402 default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM)
362 help 403 help
363 PWM Subsystem driver support for AM33xx SOC. 404 PWM Subsystem driver support for AM33xx SOC.
364 405
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index a0e00c09ead3..69b8275f3c08 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -6,7 +6,9 @@ obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o
6obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o 6obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
7obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o 7obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o
8obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o 8obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o
9obj-$(CONFIG_PWM_BERLIN) += pwm-berlin.o
9obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 10obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
11obj-$(CONFIG_PWM_BRCMSTB) += pwm-brcmstb.o
10obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o 12obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
11obj-$(CONFIG_PWM_CRC) += pwm-crc.o 13obj-$(CONFIG_PWM_CRC) += pwm-crc.o
12obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o 14obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
@@ -20,10 +22,12 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
20obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o 22obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
21obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o 23obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o
22obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o 24obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
25obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
23obj-$(CONFIG_PWM_MXS) += pwm-mxs.o 26obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
24obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o 27obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
25obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o 28obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
26obj-$(CONFIG_PWM_PXA) += pwm-pxa.o 29obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
30obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o
27obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o 31obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
28obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o 32obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
29obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o 33obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 3f9df3ea3350..d24ca5f281b4 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -269,6 +269,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
269 pwm->pwm = chip->base + i; 269 pwm->pwm = chip->base + i;
270 pwm->hwpwm = i; 270 pwm->hwpwm = i;
271 pwm->polarity = polarity; 271 pwm->polarity = polarity;
272 mutex_init(&pwm->lock);
272 273
273 radix_tree_insert(&pwm_tree, pwm->pwm, pwm); 274 radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
274 } 275 }
@@ -473,16 +474,22 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
473 if (!pwm->chip->ops->set_polarity) 474 if (!pwm->chip->ops->set_polarity)
474 return -ENOSYS; 475 return -ENOSYS;
475 476
476 if (pwm_is_enabled(pwm)) 477 mutex_lock(&pwm->lock);
477 return -EBUSY; 478
479 if (pwm_is_enabled(pwm)) {
480 err = -EBUSY;
481 goto unlock;
482 }
478 483
479 err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); 484 err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
480 if (err) 485 if (err)
481 return err; 486 goto unlock;
482 487
483 pwm->polarity = polarity; 488 pwm->polarity = polarity;
484 489
485 return 0; 490unlock:
491 mutex_unlock(&pwm->lock);
492 return err;
486} 493}
487EXPORT_SYMBOL_GPL(pwm_set_polarity); 494EXPORT_SYMBOL_GPL(pwm_set_polarity);
488 495
@@ -494,10 +501,22 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
494 */ 501 */
495int pwm_enable(struct pwm_device *pwm) 502int pwm_enable(struct pwm_device *pwm)
496{ 503{
497 if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) 504 int err = 0;
498 return pwm->chip->ops->enable(pwm->chip, pwm);
499 505
500 return pwm ? 0 : -EINVAL; 506 if (!pwm)
507 return -EINVAL;
508
509 mutex_lock(&pwm->lock);
510
511 if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
512 err = pwm->chip->ops->enable(pwm->chip, pwm);
513 if (err)
514 clear_bit(PWMF_ENABLED, &pwm->flags);
515 }
516
517 mutex_unlock(&pwm->lock);
518
519 return err;
501} 520}
502EXPORT_SYMBOL_GPL(pwm_enable); 521EXPORT_SYMBOL_GPL(pwm_enable);
503 522
@@ -719,8 +738,10 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
719 } 738 }
720 } 739 }
721 740
722 if (!chosen) 741 if (!chosen) {
742 pwm = ERR_PTR(-ENODEV);
723 goto out; 743 goto out;
744 }
724 745
725 chip = pwmchip_find_by_name(chosen->provider); 746 chip = pwmchip_find_by_name(chosen->provider);
726 if (!chip) 747 if (!chip)
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 5df1db40fc07..f994c7eaf41c 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -227,6 +227,9 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = {
227 .data = &atmel_hlcdc_pwm_at91sam9x5_errata, 227 .data = &atmel_hlcdc_pwm_at91sam9x5_errata,
228 }, 228 },
229 { 229 {
230 .compatible = "atmel,sama5d2-hlcdc",
231 },
232 {
230 .compatible = "atmel,sama5d3-hlcdc", 233 .compatible = "atmel,sama5d3-hlcdc",
231 .data = &atmel_hlcdc_pwm_sama5d3_errata, 234 .data = &atmel_hlcdc_pwm_sama5d3_errata,
232 }, 235 },
@@ -236,6 +239,7 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = {
236 }, 239 },
237 { /* sentinel */ }, 240 { /* sentinel */ },
238}; 241};
242MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids);
239 243
240static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) 244static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
241{ 245{
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
new file mode 100644
index 000000000000..65108129d505
--- /dev/null
+++ b/drivers/pwm/pwm-berlin.c
@@ -0,0 +1,219 @@
1/*
2 * Marvell Berlin PWM driver
3 *
4 * Copyright (C) 2015 Marvell Technology Group Ltd.
5 *
6 * Author: Antoine Tenart <antoine.tenart@free-electrons.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/clk.h>
14#include <linux/io.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/pwm.h>
19
20#define BERLIN_PWM_EN 0x0
21#define BERLIN_PWM_ENABLE BIT(0)
22#define BERLIN_PWM_CONTROL 0x4
23#define BERLIN_PWM_PRESCALE_MASK 0x7
24#define BERLIN_PWM_PRESCALE_MAX 4096
25#define BERLIN_PWM_INVERT_POLARITY BIT(3)
26#define BERLIN_PWM_DUTY 0x8
27#define BERLIN_PWM_TCNT 0xc
28#define BERLIN_PWM_MAX_TCNT 65535
29
30struct berlin_pwm_chip {
31 struct pwm_chip chip;
32 struct clk *clk;
33 void __iomem *base;
34};
35
36static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
37{
38 return container_of(chip, struct berlin_pwm_chip, chip);
39}
40
41static const u32 prescaler_table[] = {
42 1, 4, 8, 16, 64, 256, 1024, 4096
43};
44
45static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
46 unsigned int channel, unsigned long offset)
47{
48 return readl_relaxed(chip->base + channel * 0x10 + offset);
49}
50
51static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip,
52 unsigned int channel, u32 value,
53 unsigned long offset)
54{
55 writel_relaxed(value, chip->base + channel * 0x10 + offset);
56}
57
58static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
59 int duty_ns, int period_ns)
60{
61 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
62 unsigned int prescale;
63 u32 value, duty, period;
64 u64 cycles, tmp;
65
66 cycles = clk_get_rate(pwm->clk);
67 cycles *= period_ns;
68 do_div(cycles, NSEC_PER_SEC);
69
70 for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) {
71 tmp = cycles;
72 do_div(tmp, prescaler_table[prescale]);
73
74 if (tmp <= BERLIN_PWM_MAX_TCNT)
75 break;
76 }
77
78 if (tmp > BERLIN_PWM_MAX_TCNT)
79 return -ERANGE;
80
81 period = tmp;
82 cycles = tmp * duty_ns;
83 do_div(cycles, period_ns);
84 duty = cycles;
85
86 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
87 value &= ~BERLIN_PWM_PRESCALE_MASK;
88 value |= prescale;
89 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
90
91 berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);
92 berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT);
93
94 return 0;
95}
96
97static int berlin_pwm_set_polarity(struct pwm_chip *chip,
98 struct pwm_device *pwm_dev,
99 enum pwm_polarity polarity)
100{
101 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
102 u32 value;
103
104 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
105
106 if (polarity == PWM_POLARITY_NORMAL)
107 value &= ~BERLIN_PWM_INVERT_POLARITY;
108 else
109 value |= BERLIN_PWM_INVERT_POLARITY;
110
111 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
112
113 return 0;
114}
115
116static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
117{
118 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
119 u32 value;
120
121 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
122 value |= BERLIN_PWM_ENABLE;
123 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
124
125 return 0;
126}
127
128static void berlin_pwm_disable(struct pwm_chip *chip,
129 struct pwm_device *pwm_dev)
130{
131 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
132 u32 value;
133
134 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
135 value &= ~BERLIN_PWM_ENABLE;
136 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
137}
138
139static const struct pwm_ops berlin_pwm_ops = {
140 .config = berlin_pwm_config,
141 .set_polarity = berlin_pwm_set_polarity,
142 .enable = berlin_pwm_enable,
143 .disable = berlin_pwm_disable,
144 .owner = THIS_MODULE,
145};
146
147static const struct of_device_id berlin_pwm_match[] = {
148 { .compatible = "marvell,berlin-pwm" },
149 { },
150};
151MODULE_DEVICE_TABLE(of, berlin_pwm_match);
152
153static int berlin_pwm_probe(struct platform_device *pdev)
154{
155 struct berlin_pwm_chip *pwm;
156 struct resource *res;
157 int ret;
158
159 pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
160 if (!pwm)
161 return -ENOMEM;
162
163 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
164 pwm->base = devm_ioremap_resource(&pdev->dev, res);
165 if (IS_ERR(pwm->base))
166 return PTR_ERR(pwm->base);
167
168 pwm->clk = devm_clk_get(&pdev->dev, NULL);
169 if (IS_ERR(pwm->clk))
170 return PTR_ERR(pwm->clk);
171
172 ret = clk_prepare_enable(pwm->clk);
173 if (ret)
174 return ret;
175
176 pwm->chip.dev = &pdev->dev;
177 pwm->chip.ops = &berlin_pwm_ops;
178 pwm->chip.base = -1;
179 pwm->chip.npwm = 4;
180 pwm->chip.can_sleep = true;
181 pwm->chip.of_xlate = of_pwm_xlate_with_flags;
182 pwm->chip.of_pwm_n_cells = 3;
183
184 ret = pwmchip_add(&pwm->chip);
185 if (ret < 0) {
186 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
187 clk_disable_unprepare(pwm->clk);
188 return ret;
189 }
190
191 platform_set_drvdata(pdev, pwm);
192
193 return 0;
194}
195
196static int berlin_pwm_remove(struct platform_device *pdev)
197{
198 struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev);
199 int ret;
200
201 ret = pwmchip_remove(&pwm->chip);
202 clk_disable_unprepare(pwm->clk);
203
204 return ret;
205}
206
207static struct platform_driver berlin_pwm_driver = {
208 .probe = berlin_pwm_probe,
209 .remove = berlin_pwm_remove,
210 .driver = {
211 .name = "berlin-pwm",
212 .of_match_table = berlin_pwm_match,
213 },
214};
215module_platform_driver(berlin_pwm_driver);
216
217MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
218MODULE_DESCRIPTION("Marvell Berlin PWM driver");
219MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
new file mode 100644
index 000000000000..423ce087cd9c
--- /dev/null
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -0,0 +1,343 @@
1/*
2 * Broadcom BCM7038 PWM driver
3 * Author: Florian Fainelli
4 *
5 * Copyright (C) 2015 Broadcom Corporation
6 *
7 * 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
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/clk.h>
21#include <linux/export.h>
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/of.h>
27#include <linux/platform_device.h>
28#include <linux/pwm.h>
29#include <linux/spinlock.h>
30
31#define PWM_CTRL 0x00
32#define CTRL_START BIT(0)
33#define CTRL_OEB BIT(1)
34#define CTRL_FORCE_HIGH BIT(2)
35#define CTRL_OPENDRAIN BIT(3)
36#define CTRL_CHAN_OFFS 4
37
38#define PWM_CTRL2 0x04
39#define CTRL2_OUT_SELECT BIT(0)
40
41#define PWM_CH_SIZE 0x8
42
43#define PWM_CWORD_MSB(ch) (0x08 + ((ch) * PWM_CH_SIZE))
44#define PWM_CWORD_LSB(ch) (0x0c + ((ch) * PWM_CH_SIZE))
45
46/* Number of bits for the CWORD value */
47#define CWORD_BIT_SIZE 16
48
49/*
50 * Maximum control word value allowed when variable-frequency PWM is used as a
51 * clock for the constant-frequency PMW.
52 */
53#define CONST_VAR_F_MAX 32768
54#define CONST_VAR_F_MIN 1
55
56#define PWM_ON(ch) (0x18 + ((ch) * PWM_CH_SIZE))
57#define PWM_ON_MIN 1
58#define PWM_PERIOD(ch) (0x1c + ((ch) * PWM_CH_SIZE))
59#define PWM_PERIOD_MIN 0
60
61#define PWM_ON_PERIOD_MAX 0xff
62
63struct brcmstb_pwm {
64 void __iomem *base;
65 spinlock_t lock;
66 struct clk *clk;
67 struct pwm_chip chip;
68};
69
70static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
71 unsigned int offset)
72{
73 if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
74 return __raw_readl(p->base + offset);
75 else
76 return readl_relaxed(p->base + offset);
77}
78
79static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value,
80 unsigned int offset)
81{
82 if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
83 __raw_writel(value, p->base + offset);
84 else
85 writel_relaxed(value, p->base + offset);
86}
87
88static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
89{
90 return container_of(chip, struct brcmstb_pwm, chip);
91}
92
93/*
94 * Fv is derived from the variable frequency output. The variable frequency
95 * output is configured using this formula:
96 *
97 * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword
98 *
99 * Fv = W x 2 ^ -16 x 27Mhz (reference clock)
100 *
101 * The period is: (period + 1) / Fv and "on" time is on / (period + 1)
102 *
103 * The PWM core framework specifies that the "duty_ns" parameter is in fact the
104 * "on" time, so this translates directly into our HW programming here.
105 */
106static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
107 int duty_ns, int period_ns)
108{
109 struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
110 unsigned long pc, dc, cword = CONST_VAR_F_MAX;
111 unsigned int channel = pwm->hwpwm;
112 u32 value;
113
114 /*
115 * If asking for a duty_ns equal to period_ns, we need to substract
116 * the period value by 1 to make it shorter than the "on" time and
117 * produce a flat 100% duty cycle signal, and max out the "on" time
118 */
119 if (duty_ns == period_ns) {
120 dc = PWM_ON_PERIOD_MAX;
121 pc = PWM_ON_PERIOD_MAX - 1;
122 goto done;
123 }
124
125 while (1) {
126 u64 rate, tmp;
127
128 /*
129 * Calculate the base rate from base frequency and current
130 * cword
131 */
132 rate = (u64)clk_get_rate(p->clk) * (u64)cword;
133 do_div(rate, 1 << CWORD_BIT_SIZE);
134
135 tmp = period_ns * rate;
136 do_div(tmp, NSEC_PER_SEC);
137 pc = tmp;
138
139 tmp = (duty_ns + 1) * rate;
140 do_div(tmp, NSEC_PER_SEC);
141 dc = tmp;
142
143 /*
144 * We can be called with separate duty and period updates,
145 * so do not reject dc == 0 right away
146 */
147 if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns))
148 return -EINVAL;
149
150 /* We converged on a calculation */
151 if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX)
152 break;
153
154 /*
155 * The cword needs to be a power of 2 for the variable
156 * frequency generator to output a 50% duty cycle variable
157 * frequency which is used as input clock to the fixed
158 * frequency generator.
159 */
160 cword >>= 1;
161
162 /*
163 * Desired periods are too large, we do not have a divider
164 * for them
165 */
166 if (cword < CONST_VAR_F_MIN)
167 return -EINVAL;
168 }
169
170done:
171 /*
172 * Configure the defined "cword" value to have the variable frequency
173 * generator output a base frequency for the constant frequency
174 * generator to derive from.
175 */
176 spin_lock(&p->lock);
177 brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel));
178 brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel));
179
180 /* Select constant frequency signal output */
181 value = brcmstb_pwm_readl(p, PWM_CTRL2);
182 value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS);
183 brcmstb_pwm_writel(p, value, PWM_CTRL2);
184
185 /* Configure on and period value */
186 brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel));
187 brcmstb_pwm_writel(p, dc, PWM_ON(channel));
188 spin_unlock(&p->lock);
189
190 return 0;
191}
192
193static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p,
194 unsigned int channel, bool enable)
195{
196 unsigned int shift = channel * CTRL_CHAN_OFFS;
197 u32 value;
198
199 spin_lock(&p->lock);
200 value = brcmstb_pwm_readl(p, PWM_CTRL);
201
202 if (enable) {
203 value &= ~(CTRL_OEB << shift);
204 value |= (CTRL_START | CTRL_OPENDRAIN) << shift;
205 } else {
206 value &= ~((CTRL_START | CTRL_OPENDRAIN) << shift);
207 value |= CTRL_OEB << shift;
208 }
209
210 brcmstb_pwm_writel(p, value, PWM_CTRL);
211 spin_unlock(&p->lock);
212}
213
214static int brcmstb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
215{
216 struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
217
218 brcmstb_pwm_enable_set(p, pwm->hwpwm, true);
219
220 return 0;
221}
222
223static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
224{
225 struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
226
227 brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
228}
229
230static const struct pwm_ops brcmstb_pwm_ops = {
231 .config = brcmstb_pwm_config,
232 .enable = brcmstb_pwm_enable,
233 .disable = brcmstb_pwm_disable,
234 .owner = THIS_MODULE,
235};
236
237static const struct of_device_id brcmstb_pwm_of_match[] = {
238 { .compatible = "brcm,bcm7038-pwm", },
239 { /* sentinel */ }
240};
241MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match);
242
243static int brcmstb_pwm_probe(struct platform_device *pdev)
244{
245 struct brcmstb_pwm *p;
246 struct resource *res;
247 int ret;
248
249 p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
250 if (!p)
251 return -ENOMEM;
252
253 spin_lock_init(&p->lock);
254
255 p->clk = devm_clk_get(&pdev->dev, NULL);
256 if (IS_ERR(p->clk)) {
257 dev_err(&pdev->dev, "failed to obtain clock\n");
258 return PTR_ERR(p->clk);
259 }
260
261 ret = clk_prepare_enable(p->clk);
262 if (ret < 0) {
263 dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
264 return ret;
265 }
266
267 platform_set_drvdata(pdev, p);
268
269 p->chip.dev = &pdev->dev;
270 p->chip.ops = &brcmstb_pwm_ops;
271 p->chip.base = -1;
272 p->chip.npwm = 2;
273 p->chip.can_sleep = true;
274
275 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
276 p->base = devm_ioremap_resource(&pdev->dev, res);
277 if (!p->base) {
278 ret = -ENOMEM;
279 goto out_clk;
280 }
281
282 ret = pwmchip_add(&p->chip);
283 if (ret) {
284 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
285 goto out_clk;
286 }
287
288 return 0;
289
290out_clk:
291 clk_disable_unprepare(p->clk);
292 return ret;
293}
294
295static int brcmstb_pwm_remove(struct platform_device *pdev)
296{
297 struct brcmstb_pwm *p = platform_get_drvdata(pdev);
298 int ret;
299
300 ret = pwmchip_remove(&p->chip);
301 clk_disable_unprepare(p->clk);
302
303 return ret;
304}
305
306#ifdef CONFIG_PM_SLEEP
307static int brcmstb_pwm_suspend(struct device *dev)
308{
309 struct brcmstb_pwm *p = dev_get_drvdata(dev);
310
311 clk_disable(p->clk);
312
313 return 0;
314}
315
316static int brcmstb_pwm_resume(struct device *dev)
317{
318 struct brcmstb_pwm *p = dev_get_drvdata(dev);
319
320 clk_enable(p->clk);
321
322 return 0;
323}
324#endif
325
326static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
327 brcmstb_pwm_resume);
328
329static struct platform_driver brcmstb_pwm_driver = {
330 .probe = brcmstb_pwm_probe,
331 .remove = brcmstb_pwm_remove,
332 .driver = {
333 .name = "pwm-brcmstb",
334 .of_match_table = brcmstb_pwm_of_match,
335 .pm = &brcmstb_pwm_pm_ops,
336 },
337};
338module_platform_driver(brcmstb_pwm_driver);
339
340MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
341MODULE_DESCRIPTION("Broadcom STB PWM driver");
342MODULE_ALIAS("platform:pwm-brcmstb");
343MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c
index 45042c1b2046..7160e8ab38a4 100644
--- a/drivers/pwm/pwm-lpss-pci.c
+++ b/drivers/pwm/pwm-lpss-pci.c
@@ -13,6 +13,7 @@
13#include <linux/kernel.h> 13#include <linux/kernel.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/pci.h> 15#include <linux/pci.h>
16#include <linux/pm_runtime.h>
16 17
17#include "pwm-lpss.h" 18#include "pwm-lpss.h"
18 19
@@ -33,6 +34,10 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev,
33 return PTR_ERR(lpwm); 34 return PTR_ERR(lpwm);
34 35
35 pci_set_drvdata(pdev, lpwm); 36 pci_set_drvdata(pdev, lpwm);
37
38 pm_runtime_put(&pdev->dev);
39 pm_runtime_allow(&pdev->dev);
40
36 return 0; 41 return 0;
37} 42}
38 43
@@ -40,16 +45,41 @@ static void pwm_lpss_remove_pci(struct pci_dev *pdev)
40{ 45{
41 struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); 46 struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
42 47
48 pm_runtime_forbid(&pdev->dev);
49 pm_runtime_get_sync(&pdev->dev);
50
43 pwm_lpss_remove(lpwm); 51 pwm_lpss_remove(lpwm);
44} 52}
45 53
54#ifdef CONFIG_PM
55static int pwm_lpss_runtime_suspend_pci(struct device *dev)
56{
57 /*
58 * The PCI core will handle transition to D3 automatically. We only
59 * need to provide runtime PM hooks for that to happen.
60 */
61 return 0;
62}
63
64static int pwm_lpss_runtime_resume_pci(struct device *dev)
65{
66 return 0;
67}
68#endif
69
70static const struct dev_pm_ops pwm_lpss_pci_pm = {
71 SET_RUNTIME_PM_OPS(pwm_lpss_runtime_suspend_pci,
72 pwm_lpss_runtime_resume_pci, NULL)
73};
74
46static const struct pci_device_id pwm_lpss_pci_ids[] = { 75static const struct pci_device_id pwm_lpss_pci_ids[] = {
47 { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bsw_info}, 76 { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bxt_info},
48 { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info}, 77 { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info},
49 { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info}, 78 { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info},
50 { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bsw_info}, 79 { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info},
51 { PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info}, 80 { PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info},
52 { PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info}, 81 { PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info},
82 { PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info},
53 { }, 83 { },
54}; 84};
55MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids); 85MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids);
@@ -59,6 +89,9 @@ static struct pci_driver pwm_lpss_driver_pci = {
59 .id_table = pwm_lpss_pci_ids, 89 .id_table = pwm_lpss_pci_ids,
60 .probe = pwm_lpss_probe_pci, 90 .probe = pwm_lpss_probe_pci,
61 .remove = pwm_lpss_remove_pci, 91 .remove = pwm_lpss_remove_pci,
92 .driver = {
93 .pm = &pwm_lpss_pci_pm,
94 },
62}; 95};
63module_pci_driver(pwm_lpss_driver_pci); 96module_pci_driver(pwm_lpss_driver_pci);
64 97
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 18a9c880a76d..54433fc6d1a4 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -14,6 +14,7 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/platform_device.h> 16#include <linux/platform_device.h>
17#include <linux/pm_runtime.h>
17 18
18#include "pwm-lpss.h" 19#include "pwm-lpss.h"
19 20
@@ -36,6 +37,10 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
36 return PTR_ERR(lpwm); 37 return PTR_ERR(lpwm);
37 38
38 platform_set_drvdata(pdev, lpwm); 39 platform_set_drvdata(pdev, lpwm);
40
41 pm_runtime_set_active(&pdev->dev);
42 pm_runtime_enable(&pdev->dev);
43
39 return 0; 44 return 0;
40} 45}
41 46
@@ -43,12 +48,14 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev)
43{ 48{
44 struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); 49 struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
45 50
51 pm_runtime_disable(&pdev->dev);
46 return pwm_lpss_remove(lpwm); 52 return pwm_lpss_remove(lpwm);
47} 53}
48 54
49static const struct acpi_device_id pwm_lpss_acpi_match[] = { 55static const struct acpi_device_id pwm_lpss_acpi_match[] = {
50 { "80860F09", (unsigned long)&pwm_lpss_byt_info }, 56 { "80860F09", (unsigned long)&pwm_lpss_byt_info },
51 { "80862288", (unsigned long)&pwm_lpss_bsw_info }, 57 { "80862288", (unsigned long)&pwm_lpss_bsw_info },
58 { "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
52 { }, 59 { },
53}; 60};
54MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); 61MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index e9798253a16f..25044104003b 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -16,6 +16,7 @@
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/pm_runtime.h>
19 20
20#include "pwm-lpss.h" 21#include "pwm-lpss.h"
21 22
@@ -29,6 +30,9 @@
29#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION) 30#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION)
30#define NSECS_PER_SEC 1000000000UL 31#define NSECS_PER_SEC 1000000000UL
31 32
33/* Size of each PWM register space if multiple */
34#define PWM_SIZE 0x400
35
32struct pwm_lpss_chip { 36struct pwm_lpss_chip {
33 struct pwm_chip chip; 37 struct pwm_chip chip;
34 void __iomem *regs; 38 void __iomem *regs;
@@ -37,21 +41,44 @@ struct pwm_lpss_chip {
37 41
38/* BayTrail */ 42/* BayTrail */
39const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { 43const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
40 .clk_rate = 25000000 44 .clk_rate = 25000000,
45 .npwm = 1,
41}; 46};
42EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); 47EXPORT_SYMBOL_GPL(pwm_lpss_byt_info);
43 48
44/* Braswell */ 49/* Braswell */
45const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { 50const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
46 .clk_rate = 19200000 51 .clk_rate = 19200000,
52 .npwm = 1,
47}; 53};
48EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); 54EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info);
49 55
56/* Broxton */
57const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
58 .clk_rate = 19200000,
59 .npwm = 4,
60};
61EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info);
62
50static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) 63static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
51{ 64{
52 return container_of(chip, struct pwm_lpss_chip, chip); 65 return container_of(chip, struct pwm_lpss_chip, chip);
53} 66}
54 67
68static inline u32 pwm_lpss_read(const struct pwm_device *pwm)
69{
70 struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
71
72 return readl(lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
73}
74
75static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
76{
77 struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
78
79 writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
80}
81
55static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, 82static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
56 int duty_ns, int period_ns) 83 int duty_ns, int period_ns)
57{ 84{
@@ -79,38 +106,36 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
79 duty_ns = 1; 106 duty_ns = 1;
80 on_time_div = 255 - (255 * duty_ns / period_ns); 107 on_time_div = 255 - (255 * duty_ns / period_ns);
81 108
82 ctrl = readl(lpwm->regs + PWM); 109 pm_runtime_get_sync(chip->dev);
110
111 ctrl = pwm_lpss_read(pwm);
83 ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK); 112 ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK);
84 ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT; 113 ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT;
85 ctrl |= on_time_div; 114 ctrl |= on_time_div;
86 /* request PWM to update on next cycle */ 115 /* request PWM to update on next cycle */
87 ctrl |= PWM_SW_UPDATE; 116 ctrl |= PWM_SW_UPDATE;
88 writel(ctrl, lpwm->regs + PWM); 117 pwm_lpss_write(pwm, ctrl);
118
119 pm_runtime_put(chip->dev);
89 120
90 return 0; 121 return 0;
91} 122}
92 123
93static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) 124static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
94{ 125{
95 struct pwm_lpss_chip *lpwm = to_lpwm(chip); 126 pm_runtime_get_sync(chip->dev);
96 u32 ctrl; 127 pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
97
98 ctrl = readl(lpwm->regs + PWM);
99 writel(ctrl | PWM_ENABLE, lpwm->regs + PWM);
100
101 return 0; 128 return 0;
102} 129}
103 130
104static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) 131static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
105{ 132{
106 struct pwm_lpss_chip *lpwm = to_lpwm(chip); 133 pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
107 u32 ctrl; 134 pm_runtime_put(chip->dev);
108
109 ctrl = readl(lpwm->regs + PWM);
110 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
111} 135}
112 136
113static const struct pwm_ops pwm_lpss_ops = { 137static const struct pwm_ops pwm_lpss_ops = {
138 .free = pwm_lpss_disable,
114 .config = pwm_lpss_config, 139 .config = pwm_lpss_config,
115 .enable = pwm_lpss_enable, 140 .enable = pwm_lpss_enable,
116 .disable = pwm_lpss_disable, 141 .disable = pwm_lpss_disable,
@@ -135,7 +160,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
135 lpwm->chip.dev = dev; 160 lpwm->chip.dev = dev;
136 lpwm->chip.ops = &pwm_lpss_ops; 161 lpwm->chip.ops = &pwm_lpss_ops;
137 lpwm->chip.base = -1; 162 lpwm->chip.base = -1;
138 lpwm->chip.npwm = 1; 163 lpwm->chip.npwm = info->npwm;
139 164
140 ret = pwmchip_add(&lpwm->chip); 165 ret = pwmchip_add(&lpwm->chip);
141 if (ret) { 166 if (ret) {
@@ -149,11 +174,6 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
149 174
150int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) 175int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
151{ 176{
152 u32 ctrl;
153
154 ctrl = readl(lpwm->regs + PWM);
155 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
156
157 return pwmchip_remove(&lpwm->chip); 177 return pwmchip_remove(&lpwm->chip);
158} 178}
159EXPORT_SYMBOL_GPL(pwm_lpss_remove); 179EXPORT_SYMBOL_GPL(pwm_lpss_remove);
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index aa041bb1b67d..e8cf337ae1d1 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -20,10 +20,12 @@ struct pwm_lpss_chip;
20 20
21struct pwm_lpss_boardinfo { 21struct pwm_lpss_boardinfo {
22 unsigned long clk_rate; 22 unsigned long clk_rate;
23 unsigned int npwm;
23}; 24};
24 25
25extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info; 26extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info;
26extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info; 27extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info;
28extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info;
27 29
28struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, 30struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
29 const struct pwm_lpss_boardinfo *info); 31 const struct pwm_lpss_boardinfo *info);
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
new file mode 100644
index 000000000000..0ad3385298c0
--- /dev/null
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -0,0 +1,243 @@
1/*
2 * MediaTek display pulse-width-modulation controller driver.
3 * Copyright (c) 2015 MediaTek Inc.
4 * Author: YH Huang <yh.huang@mediatek.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 version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/clk.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/platform_device.h>
22#include <linux/pwm.h>
23#include <linux/slab.h>
24
25#define DISP_PWM_EN 0x00
26#define PWM_ENABLE_MASK BIT(0)
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
33#define PWM_CLKDIV_MAX 0x3ff
34#define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT)
35
36#define DISP_PWM_CON_1 0x14
37#define PWM_PERIOD_BIT_WIDTH 12
38#define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1)
39
40#define PWM_HIGH_WIDTH_SHIFT 16
41#define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT)
42
43struct mtk_disp_pwm {
44 struct pwm_chip chip;
45 struct clk *clk_main;
46 struct clk *clk_mm;
47 void __iomem *base;
48};
49
50static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
51{
52 return container_of(chip, struct mtk_disp_pwm, chip);
53}
54
55static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
56 u32 mask, u32 data)
57{
58 void __iomem *address = mdp->base + offset;
59 u32 value;
60
61 value = readl(address);
62 value &= ~mask;
63 value |= data;
64 writel(value, address);
65}
66
67static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
68 int duty_ns, int period_ns)
69{
70 struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
71 u32 clk_div, period, high_width, value;
72 u64 div, rate;
73 int err;
74
75 /*
76 * Find period, high_width and clk_div to suit duty_ns and period_ns.
77 * Calculate proper div value to keep period value in the bound.
78 *
79 * period_ns = 10^9 * (clk_div + 1) * (period + 1) / PWM_CLK_RATE
80 * duty_ns = 10^9 * (clk_div + 1) * high_width / PWM_CLK_RATE
81 *
82 * period = (PWM_CLK_RATE * period_ns) / (10^9 * (clk_div + 1)) - 1
83 * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))
84 */
85 rate = clk_get_rate(mdp->clk_main);
86 clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
87 PWM_PERIOD_BIT_WIDTH;
88 if (clk_div > PWM_CLKDIV_MAX)
89 return -EINVAL;
90
91 div = NSEC_PER_SEC * (clk_div + 1);
92 period = div64_u64(rate * period_ns, div);
93 if (period > 0)
94 period--;
95
96 high_width = div64_u64(rate * duty_ns, div);
97 value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);
98
99 err = clk_enable(mdp->clk_main);
100 if (err < 0)
101 return err;
102
103 err = clk_enable(mdp->clk_mm);
104 if (err < 0) {
105 clk_disable(mdp->clk_main);
106 return err;
107 }
108
109 mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK,
110 clk_div << PWM_CLKDIV_SHIFT);
111 mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1,
112 PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value);
113 mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1);
114 mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0);
115
116 clk_disable(mdp->clk_mm);
117 clk_disable(mdp->clk_main);
118
119 return 0;
120}
121
122static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
123{
124 struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
125 int err;
126
127 err = clk_enable(mdp->clk_main);
128 if (err < 0)
129 return err;
130
131 err = clk_enable(mdp->clk_mm);
132 if (err < 0) {
133 clk_disable(mdp->clk_main);
134 return err;
135 }
136
137 mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1);
138
139 return 0;
140}
141
142static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
143{
144 struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
145
146 mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0);
147
148 clk_disable(mdp->clk_mm);
149 clk_disable(mdp->clk_main);
150}
151
152static const struct pwm_ops mtk_disp_pwm_ops = {
153 .config = mtk_disp_pwm_config,
154 .enable = mtk_disp_pwm_enable,
155 .disable = mtk_disp_pwm_disable,
156 .owner = THIS_MODULE,
157};
158
159static int mtk_disp_pwm_probe(struct platform_device *pdev)
160{
161 struct mtk_disp_pwm *mdp;
162 struct resource *r;
163 int ret;
164
165 mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL);
166 if (!mdp)
167 return -ENOMEM;
168
169 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
170 mdp->base = devm_ioremap_resource(&pdev->dev, r);
171 if (IS_ERR(mdp->base))
172 return PTR_ERR(mdp->base);
173
174 mdp->clk_main = devm_clk_get(&pdev->dev, "main");
175 if (IS_ERR(mdp->clk_main))
176 return PTR_ERR(mdp->clk_main);
177
178 mdp->clk_mm = devm_clk_get(&pdev->dev, "mm");
179 if (IS_ERR(mdp->clk_mm))
180 return PTR_ERR(mdp->clk_mm);
181
182 ret = clk_prepare(mdp->clk_main);
183 if (ret < 0)
184 return ret;
185
186 ret = clk_prepare(mdp->clk_mm);
187 if (ret < 0)
188 goto disable_clk_main;
189
190 mdp->chip.dev = &pdev->dev;
191 mdp->chip.ops = &mtk_disp_pwm_ops;
192 mdp->chip.base = -1;
193 mdp->chip.npwm = 1;
194
195 ret = pwmchip_add(&mdp->chip);
196 if (ret < 0) {
197 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
198 goto disable_clk_mm;
199 }
200
201 platform_set_drvdata(pdev, mdp);
202
203 return 0;
204
205disable_clk_mm:
206 clk_unprepare(mdp->clk_mm);
207disable_clk_main:
208 clk_unprepare(mdp->clk_main);
209 return ret;
210}
211
212static int mtk_disp_pwm_remove(struct platform_device *pdev)
213{
214 struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev);
215 int ret;
216
217 ret = pwmchip_remove(&mdp->chip);
218 clk_unprepare(mdp->clk_mm);
219 clk_unprepare(mdp->clk_main);
220
221 return ret;
222}
223
224static const struct of_device_id mtk_disp_pwm_of_match[] = {
225 { .compatible = "mediatek,mt8173-disp-pwm" },
226 { .compatible = "mediatek,mt6595-disp-pwm" },
227 { }
228};
229MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match);
230
231static struct platform_driver mtk_disp_pwm_driver = {
232 .driver = {
233 .name = "mediatek-disp-pwm",
234 .of_match_table = mtk_disp_pwm_of_match,
235 },
236 .probe = mtk_disp_pwm_probe,
237 .remove = mtk_disp_pwm_remove,
238};
239module_platform_driver(mtk_disp_pwm_driver);
240
241MODULE_AUTHOR("YH Huang <yh.huang@mediatek.com>");
242MODULE_DESCRIPTION("MediaTek SoC display PWM driver");
243MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 70448a6079b0..117fccf7934a 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -19,9 +19,11 @@
19 * this program. If not, see <http://www.gnu.org/licenses/>. 19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */ 20 */
21 21
22#include <linux/acpi.h>
22#include <linux/i2c.h> 23#include <linux/i2c.h>
23#include <linux/module.h> 24#include <linux/module.h>
24#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/property.h>
25#include <linux/pwm.h> 27#include <linux/pwm.h>
26#include <linux/regmap.h> 28#include <linux/regmap.h>
27#include <linux/slab.h> 29#include <linux/slab.h>
@@ -297,7 +299,6 @@ static const struct regmap_config pca9685_regmap_i2c_config = {
297static int pca9685_pwm_probe(struct i2c_client *client, 299static int pca9685_pwm_probe(struct i2c_client *client,
298 const struct i2c_device_id *id) 300 const struct i2c_device_id *id)
299{ 301{
300 struct device_node *np = client->dev.of_node;
301 struct pca9685 *pca; 302 struct pca9685 *pca;
302 int ret; 303 int ret;
303 int mode2; 304 int mode2;
@@ -320,12 +321,12 @@ static int pca9685_pwm_probe(struct i2c_client *client,
320 321
321 regmap_read(pca->regmap, PCA9685_MODE2, &mode2); 322 regmap_read(pca->regmap, PCA9685_MODE2, &mode2);
322 323
323 if (of_property_read_bool(np, "invert")) 324 if (device_property_read_bool(&client->dev, "invert"))
324 mode2 |= MODE2_INVRT; 325 mode2 |= MODE2_INVRT;
325 else 326 else
326 mode2 &= ~MODE2_INVRT; 327 mode2 &= ~MODE2_INVRT;
327 328
328 if (of_property_read_bool(np, "open-drain")) 329 if (device_property_read_bool(&client->dev, "open-drain"))
329 mode2 &= ~MODE2_OUTDRV; 330 mode2 &= ~MODE2_OUTDRV;
330 else 331 else
331 mode2 |= MODE2_OUTDRV; 332 mode2 |= MODE2_OUTDRV;
@@ -363,16 +364,27 @@ static const struct i2c_device_id pca9685_id[] = {
363}; 364};
364MODULE_DEVICE_TABLE(i2c, pca9685_id); 365MODULE_DEVICE_TABLE(i2c, pca9685_id);
365 366
367#ifdef CONFIG_ACPI
368static const struct acpi_device_id pca9685_acpi_ids[] = {
369 { "INT3492", 0 },
370 { /* sentinel */ },
371};
372MODULE_DEVICE_TABLE(acpi, pca9685_acpi_ids);
373#endif
374
375#ifdef CONFIG_OF
366static const struct of_device_id pca9685_dt_ids[] = { 376static const struct of_device_id pca9685_dt_ids[] = {
367 { .compatible = "nxp,pca9685-pwm", }, 377 { .compatible = "nxp,pca9685-pwm", },
368 { /* sentinel */ } 378 { /* sentinel */ }
369}; 379};
370MODULE_DEVICE_TABLE(of, pca9685_dt_ids); 380MODULE_DEVICE_TABLE(of, pca9685_dt_ids);
381#endif
371 382
372static struct i2c_driver pca9685_i2c_driver = { 383static struct i2c_driver pca9685_i2c_driver = {
373 .driver = { 384 .driver = {
374 .name = "pca9685-pwm", 385 .name = "pca9685-pwm",
375 .of_match_table = pca9685_dt_ids, 386 .acpi_match_table = ACPI_PTR(pca9685_acpi_ids),
387 .of_match_table = of_match_ptr(pca9685_dt_ids),
376 }, 388 },
377 .probe = pca9685_pwm_probe, 389 .probe = pca9685_pwm_probe,
378 .remove = pca9685_pwm_remove, 390 .remove = pca9685_pwm_remove,
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
new file mode 100644
index 000000000000..6e99a63ffa29
--- /dev/null
+++ b/drivers/pwm/pwm-rcar.c
@@ -0,0 +1,274 @@
1/*
2 * R-Car PWM Timer driver
3 *
4 * Copyright (C) 2015 Renesas Electronics Corporation
5 *
6 * This is free software; you can redistribute it and/or modify
7 * it under the terms of version 2 of the GNU General Public License as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/clk.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/platform_device.h>
17#include <linux/pm_runtime.h>
18#include <linux/pwm.h>
19#include <linux/slab.h>
20
21#define RCAR_PWM_MAX_DIVISION 24
22#define RCAR_PWM_MAX_CYCLE 1023
23
24#define RCAR_PWMCR 0x00
25#define RCAR_PWMCR_CC0_MASK 0x000f0000
26#define RCAR_PWMCR_CC0_SHIFT 16
27#define RCAR_PWMCR_CCMD BIT(15)
28#define RCAR_PWMCR_SYNC BIT(11)
29#define RCAR_PWMCR_SS0 BIT(4)
30#define RCAR_PWMCR_EN0 BIT(0)
31
32#define RCAR_PWMCNT 0x04
33#define RCAR_PWMCNT_CYC0_MASK 0x03ff0000
34#define RCAR_PWMCNT_CYC0_SHIFT 16
35#define RCAR_PWMCNT_PH0_MASK 0x000003ff
36#define RCAR_PWMCNT_PH0_SHIFT 0
37
38struct rcar_pwm_chip {
39 struct pwm_chip chip;
40 void __iomem *base;
41 struct clk *clk;
42};
43
44static inline struct rcar_pwm_chip *to_rcar_pwm_chip(struct pwm_chip *chip)
45{
46 return container_of(chip, struct rcar_pwm_chip, chip);
47}
48
49static void rcar_pwm_write(struct rcar_pwm_chip *rp, u32 data,
50 unsigned int offset)
51{
52 writel(data, rp->base + offset);
53}
54
55static u32 rcar_pwm_read(struct rcar_pwm_chip *rp, unsigned int offset)
56{
57 return readl(rp->base + offset);
58}
59
60static void rcar_pwm_update(struct rcar_pwm_chip *rp, u32 mask, u32 data,
61 unsigned int offset)
62{
63 u32 value;
64
65 value = rcar_pwm_read(rp, offset);
66 value &= ~mask;
67 value |= data & mask;
68 rcar_pwm_write(rp, value, offset);
69}
70
71static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns)
72{
73 unsigned long clk_rate = clk_get_rate(rp->clk);
74 unsigned long long max; /* max cycle / nanoseconds */
75 unsigned int div;
76
77 if (clk_rate == 0)
78 return -EINVAL;
79
80 for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) {
81 max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE *
82 (1 << div);
83 do_div(max, clk_rate);
84 if (period_ns < max)
85 break;
86 }
87
88 return (div <= RCAR_PWM_MAX_DIVISION) ? div : -ERANGE;
89}
90
91static void rcar_pwm_set_clock_control(struct rcar_pwm_chip *rp,
92 unsigned int div)
93{
94 u32 value;
95
96 value = rcar_pwm_read(rp, RCAR_PWMCR);
97 value &= ~(RCAR_PWMCR_CCMD | RCAR_PWMCR_CC0_MASK);
98
99 if (div & 1)
100 value |= RCAR_PWMCR_CCMD;
101
102 div >>= 1;
103
104 value |= div << RCAR_PWMCR_CC0_SHIFT;
105 rcar_pwm_write(rp, value, RCAR_PWMCR);
106}
107
108static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns,
109 int period_ns)
110{
111 unsigned long long one_cycle, tmp; /* 0.01 nanoseconds */
112 unsigned long clk_rate = clk_get_rate(rp->clk);
113 u32 cyc, ph;
114
115 one_cycle = (unsigned long long)NSEC_PER_SEC * 100ULL * (1 << div);
116 do_div(one_cycle, clk_rate);
117
118 tmp = period_ns * 100ULL;
119 do_div(tmp, one_cycle);
120 cyc = (tmp << RCAR_PWMCNT_CYC0_SHIFT) & RCAR_PWMCNT_CYC0_MASK;
121
122 tmp = duty_ns * 100ULL;
123 do_div(tmp, one_cycle);
124 ph = tmp & RCAR_PWMCNT_PH0_MASK;
125
126 /* Avoid prohibited setting */
127 if (cyc == 0 || ph == 0)
128 return -EINVAL;
129
130 rcar_pwm_write(rp, cyc | ph, RCAR_PWMCNT);
131
132 return 0;
133}
134
135static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
136{
137 struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
138
139 return clk_prepare_enable(rp->clk);
140}
141
142static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
143{
144 struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
145
146 clk_disable_unprepare(rp->clk);
147}
148
149static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
150 int duty_ns, int period_ns)
151{
152 struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
153 int div, ret;
154
155 div = rcar_pwm_get_clock_division(rp, period_ns);
156 if (div < 0)
157 return div;
158
159 /* Let the core driver set pwm->period if disabled and duty_ns == 0 */
160 if (!test_bit(PWMF_ENABLED, &pwm->flags) && !duty_ns)
161 return 0;
162
163 rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
164
165 ret = rcar_pwm_set_counter(rp, div, duty_ns, period_ns);
166 if (!ret)
167 rcar_pwm_set_clock_control(rp, div);
168
169 /* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */
170 rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR);
171
172 return ret;
173}
174
175static int rcar_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
176{
177 struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
178 u32 value;
179
180 /* Don't enable the PWM device if CYC0 or PH0 is 0 */
181 value = rcar_pwm_read(rp, RCAR_PWMCNT);
182 if ((value & RCAR_PWMCNT_CYC0_MASK) == 0 ||
183 (value & RCAR_PWMCNT_PH0_MASK) == 0)
184 return -EINVAL;
185
186 rcar_pwm_update(rp, RCAR_PWMCR_EN0, RCAR_PWMCR_EN0, RCAR_PWMCR);
187
188 return 0;
189}
190
191static void rcar_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
192{
193 struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
194
195 rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR);
196}
197
198static const struct pwm_ops rcar_pwm_ops = {
199 .request = rcar_pwm_request,
200 .free = rcar_pwm_free,
201 .config = rcar_pwm_config,
202 .enable = rcar_pwm_enable,
203 .disable = rcar_pwm_disable,
204 .owner = THIS_MODULE,
205};
206
207static int rcar_pwm_probe(struct platform_device *pdev)
208{
209 struct rcar_pwm_chip *rcar_pwm;
210 struct resource *res;
211 int ret;
212
213 rcar_pwm = devm_kzalloc(&pdev->dev, sizeof(*rcar_pwm), GFP_KERNEL);
214 if (rcar_pwm == NULL)
215 return -ENOMEM;
216
217 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
218 rcar_pwm->base = devm_ioremap_resource(&pdev->dev, res);
219 if (IS_ERR(rcar_pwm->base))
220 return PTR_ERR(rcar_pwm->base);
221
222 rcar_pwm->clk = devm_clk_get(&pdev->dev, NULL);
223 if (IS_ERR(rcar_pwm->clk)) {
224 dev_err(&pdev->dev, "cannot get clock\n");
225 return PTR_ERR(rcar_pwm->clk);
226 }
227
228 platform_set_drvdata(pdev, rcar_pwm);
229
230 rcar_pwm->chip.dev = &pdev->dev;
231 rcar_pwm->chip.ops = &rcar_pwm_ops;
232 rcar_pwm->chip.base = -1;
233 rcar_pwm->chip.npwm = 1;
234
235 ret = pwmchip_add(&rcar_pwm->chip);
236 if (ret < 0) {
237 dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret);
238 return ret;
239 }
240
241 pm_runtime_enable(&pdev->dev);
242
243 return 0;
244}
245
246static int rcar_pwm_remove(struct platform_device *pdev)
247{
248 struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
249
250 pm_runtime_disable(&pdev->dev);
251
252 return pwmchip_remove(&rcar_pwm->chip);
253}
254
255static const struct of_device_id rcar_pwm_of_table[] = {
256 { .compatible = "renesas,pwm-rcar", },
257 { },
258};
259MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
260
261static struct platform_driver rcar_pwm_driver = {
262 .probe = rcar_pwm_probe,
263 .remove = rcar_pwm_remove,
264 .driver = {
265 .name = "pwm-rcar",
266 .of_match_table = of_match_ptr(rcar_pwm_of_table),
267 }
268};
269module_platform_driver(rcar_pwm_driver);
270
271MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");
272MODULE_DESCRIPTION("Renesas PWM Timer Driver");
273MODULE_LICENSE("GPL v2");
274MODULE_ALIAS("platform:pwm-rcar");
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index cd9dde563018..67af9f62361f 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -68,6 +68,7 @@ static const u32 prescaler_table[] = {
68struct sun4i_pwm_data { 68struct sun4i_pwm_data {
69 bool has_prescaler_bypass; 69 bool has_prescaler_bypass;
70 bool has_rdy; 70 bool has_rdy;
71 unsigned int npwm;
71}; 72};
72 73
73struct sun4i_pwm_chip { 74struct sun4i_pwm_chip {
@@ -114,7 +115,7 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
114 * is not an integer so round it half up instead of 115 * is not an integer so round it half up instead of
115 * truncating to get less surprising values. 116 * truncating to get less surprising values.
116 */ 117 */
117 div = clk_rate * period_ns + NSEC_PER_SEC/2; 118 div = clk_rate * period_ns + NSEC_PER_SEC / 2;
118 do_div(div, NSEC_PER_SEC); 119 do_div(div, NSEC_PER_SEC);
119 if (div - 1 > PWM_PRD_MASK) 120 if (div - 1 > PWM_PRD_MASK)
120 prescaler = 0; 121 prescaler = 0;
@@ -262,11 +263,25 @@ static const struct pwm_ops sun4i_pwm_ops = {
262static const struct sun4i_pwm_data sun4i_pwm_data_a10 = { 263static const struct sun4i_pwm_data sun4i_pwm_data_a10 = {
263 .has_prescaler_bypass = false, 264 .has_prescaler_bypass = false,
264 .has_rdy = false, 265 .has_rdy = false,
266 .npwm = 2,
267};
268
269static const struct sun4i_pwm_data sun4i_pwm_data_a10s = {
270 .has_prescaler_bypass = true,
271 .has_rdy = true,
272 .npwm = 2,
273};
274
275static const struct sun4i_pwm_data sun4i_pwm_data_a13 = {
276 .has_prescaler_bypass = true,
277 .has_rdy = true,
278 .npwm = 1,
265}; 279};
266 280
267static const struct sun4i_pwm_data sun4i_pwm_data_a20 = { 281static const struct sun4i_pwm_data sun4i_pwm_data_a20 = {
268 .has_prescaler_bypass = true, 282 .has_prescaler_bypass = true,
269 .has_rdy = true, 283 .has_rdy = true,
284 .npwm = 2,
270}; 285};
271 286
272static const struct of_device_id sun4i_pwm_dt_ids[] = { 287static const struct of_device_id sun4i_pwm_dt_ids[] = {
@@ -274,6 +289,12 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = {
274 .compatible = "allwinner,sun4i-a10-pwm", 289 .compatible = "allwinner,sun4i-a10-pwm",
275 .data = &sun4i_pwm_data_a10, 290 .data = &sun4i_pwm_data_a10,
276 }, { 291 }, {
292 .compatible = "allwinner,sun5i-a10s-pwm",
293 .data = &sun4i_pwm_data_a10s,
294 }, {
295 .compatible = "allwinner,sun5i-a13-pwm",
296 .data = &sun4i_pwm_data_a13,
297 }, {
277 .compatible = "allwinner,sun7i-a20-pwm", 298 .compatible = "allwinner,sun7i-a20-pwm",
278 .data = &sun4i_pwm_data_a20, 299 .data = &sun4i_pwm_data_a20,
279 }, { 300 }, {
@@ -305,14 +326,14 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
305 if (IS_ERR(pwm->clk)) 326 if (IS_ERR(pwm->clk))
306 return PTR_ERR(pwm->clk); 327 return PTR_ERR(pwm->clk);
307 328
329 pwm->data = match->data;
308 pwm->chip.dev = &pdev->dev; 330 pwm->chip.dev = &pdev->dev;
309 pwm->chip.ops = &sun4i_pwm_ops; 331 pwm->chip.ops = &sun4i_pwm_ops;
310 pwm->chip.base = -1; 332 pwm->chip.base = -1;
311 pwm->chip.npwm = 2; 333 pwm->chip.npwm = pwm->data->npwm;
312 pwm->chip.can_sleep = true; 334 pwm->chip.can_sleep = true;
313 pwm->chip.of_xlate = of_pwm_xlate_with_flags; 335 pwm->chip.of_xlate = of_pwm_xlate_with_flags;
314 pwm->chip.of_pwm_n_cells = 3; 336 pwm->chip.of_pwm_n_cells = 3;
315 pwm->data = match->data;
316 337
317 spin_lock_init(&pwm->ctrl_lock); 338 spin_lock_init(&pwm->ctrl_lock);
318 339
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index c472772f00a7..9c90886f4123 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -40,18 +40,18 @@ static struct pwm_device *child_to_pwm_device(struct device *child)
40 return export->pwm; 40 return export->pwm;
41} 41}
42 42
43static ssize_t pwm_period_show(struct device *child, 43static ssize_t period_show(struct device *child,
44 struct device_attribute *attr, 44 struct device_attribute *attr,
45 char *buf) 45 char *buf)
46{ 46{
47 const struct pwm_device *pwm = child_to_pwm_device(child); 47 const struct pwm_device *pwm = child_to_pwm_device(child);
48 48
49 return sprintf(buf, "%u\n", pwm_get_period(pwm)); 49 return sprintf(buf, "%u\n", pwm_get_period(pwm));
50} 50}
51 51
52static ssize_t pwm_period_store(struct device *child, 52static ssize_t period_store(struct device *child,
53 struct device_attribute *attr, 53 struct device_attribute *attr,
54 const char *buf, size_t size) 54 const char *buf, size_t size)
55{ 55{
56 struct pwm_device *pwm = child_to_pwm_device(child); 56 struct pwm_device *pwm = child_to_pwm_device(child);
57 unsigned int val; 57 unsigned int val;
@@ -66,18 +66,18 @@ static ssize_t pwm_period_store(struct device *child,
66 return ret ? : size; 66 return ret ? : size;
67} 67}
68 68
69static ssize_t pwm_duty_cycle_show(struct device *child, 69static ssize_t duty_cycle_show(struct device *child,
70 struct device_attribute *attr, 70 struct device_attribute *attr,
71 char *buf) 71 char *buf)
72{ 72{
73 const struct pwm_device *pwm = child_to_pwm_device(child); 73 const struct pwm_device *pwm = child_to_pwm_device(child);
74 74
75 return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm)); 75 return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm));
76} 76}
77 77
78static ssize_t pwm_duty_cycle_store(struct device *child, 78static ssize_t duty_cycle_store(struct device *child,
79 struct device_attribute *attr, 79 struct device_attribute *attr,
80 const char *buf, size_t size) 80 const char *buf, size_t size)
81{ 81{
82 struct pwm_device *pwm = child_to_pwm_device(child); 82 struct pwm_device *pwm = child_to_pwm_device(child);
83 unsigned int val; 83 unsigned int val;
@@ -92,19 +92,18 @@ static ssize_t pwm_duty_cycle_store(struct device *child,
92 return ret ? : size; 92 return ret ? : size;
93} 93}
94 94
95static ssize_t pwm_enable_show(struct device *child, 95static ssize_t enable_show(struct device *child,
96 struct device_attribute *attr, 96 struct device_attribute *attr,
97 char *buf) 97 char *buf)
98{ 98{
99 const struct pwm_device *pwm = child_to_pwm_device(child); 99 const struct pwm_device *pwm = child_to_pwm_device(child);
100 int enabled = pwm_is_enabled(pwm);
101 100
102 return sprintf(buf, "%d\n", enabled); 101 return sprintf(buf, "%d\n", pwm_is_enabled(pwm));
103} 102}
104 103
105static ssize_t pwm_enable_store(struct device *child, 104static ssize_t enable_store(struct device *child,
106 struct device_attribute *attr, 105 struct device_attribute *attr,
107 const char *buf, size_t size) 106 const char *buf, size_t size)
108{ 107{
109 struct pwm_device *pwm = child_to_pwm_device(child); 108 struct pwm_device *pwm = child_to_pwm_device(child);
110 int val, ret; 109 int val, ret;
@@ -128,9 +127,9 @@ static ssize_t pwm_enable_store(struct device *child,
128 return ret ? : size; 127 return ret ? : size;
129} 128}
130 129
131static ssize_t pwm_polarity_show(struct device *child, 130static ssize_t polarity_show(struct device *child,
132 struct device_attribute *attr, 131 struct device_attribute *attr,
133 char *buf) 132 char *buf)
134{ 133{
135 const struct pwm_device *pwm = child_to_pwm_device(child); 134 const struct pwm_device *pwm = child_to_pwm_device(child);
136 const char *polarity = "unknown"; 135 const char *polarity = "unknown";
@@ -148,9 +147,9 @@ static ssize_t pwm_polarity_show(struct device *child,
148 return sprintf(buf, "%s\n", polarity); 147 return sprintf(buf, "%s\n", polarity);
149} 148}
150 149
151static ssize_t pwm_polarity_store(struct device *child, 150static ssize_t polarity_store(struct device *child,
152 struct device_attribute *attr, 151 struct device_attribute *attr,
153 const char *buf, size_t size) 152 const char *buf, size_t size)
154{ 153{
155 struct pwm_device *pwm = child_to_pwm_device(child); 154 struct pwm_device *pwm = child_to_pwm_device(child);
156 enum pwm_polarity polarity; 155 enum pwm_polarity polarity;
@@ -168,10 +167,10 @@ static ssize_t pwm_polarity_store(struct device *child,
168 return ret ? : size; 167 return ret ? : size;
169} 168}
170 169
171static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store); 170static DEVICE_ATTR_RW(period);
172static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store); 171static DEVICE_ATTR_RW(duty_cycle);
173static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store); 172static DEVICE_ATTR_RW(enable);
174static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store); 173static DEVICE_ATTR_RW(polarity);
175 174
176static struct attribute *pwm_attrs[] = { 175static struct attribute *pwm_attrs[] = {
177 &dev_attr_period.attr, 176 &dev_attr_period.attr,
@@ -245,9 +244,9 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
245 return 0; 244 return 0;
246} 245}
247 246
248static ssize_t pwm_export_store(struct device *parent, 247static ssize_t export_store(struct device *parent,
249 struct device_attribute *attr, 248 struct device_attribute *attr,
250 const char *buf, size_t len) 249 const char *buf, size_t len)
251{ 250{
252 struct pwm_chip *chip = dev_get_drvdata(parent); 251 struct pwm_chip *chip = dev_get_drvdata(parent);
253 struct pwm_device *pwm; 252 struct pwm_device *pwm;
@@ -271,11 +270,11 @@ static ssize_t pwm_export_store(struct device *parent,
271 270
272 return ret ? : len; 271 return ret ? : len;
273} 272}
274static DEVICE_ATTR(export, 0200, NULL, pwm_export_store); 273static DEVICE_ATTR_WO(export);
275 274
276static ssize_t pwm_unexport_store(struct device *parent, 275static ssize_t unexport_store(struct device *parent,
277 struct device_attribute *attr, 276 struct device_attribute *attr,
278 const char *buf, size_t len) 277 const char *buf, size_t len)
279{ 278{
280 struct pwm_chip *chip = dev_get_drvdata(parent); 279 struct pwm_chip *chip = dev_get_drvdata(parent);
281 unsigned int hwpwm; 280 unsigned int hwpwm;
@@ -292,7 +291,7 @@ static ssize_t pwm_unexport_store(struct device *parent,
292 291
293 return ret ? : len; 292 return ret ? : len;
294} 293}
295static DEVICE_ATTR(unexport, 0200, NULL, pwm_unexport_store); 294static DEVICE_ATTR_WO(unexport);
296 295
297static ssize_t npwm_show(struct device *parent, struct device_attribute *attr, 296static ssize_t npwm_show(struct device *parent, struct device_attribute *attr,
298 char *buf) 297 char *buf)
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index d681f6875aef..cfc3ed46cad2 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -2,6 +2,7 @@
2#define __LINUX_PWM_H 2#define __LINUX_PWM_H
3 3
4#include <linux/err.h> 4#include <linux/err.h>
5#include <linux/mutex.h>
5#include <linux/of.h> 6#include <linux/of.h>
6 7
7struct pwm_device; 8struct pwm_device;
@@ -87,6 +88,7 @@ enum {
87 * @pwm: global index of the PWM device 88 * @pwm: global index of the PWM device
88 * @chip: PWM chip providing this PWM device 89 * @chip: PWM chip providing this PWM device
89 * @chip_data: chip-private data associated with the PWM device 90 * @chip_data: chip-private data associated with the PWM device
91 * @lock: used to serialize accesses to the PWM device where necessary
90 * @period: period of the PWM signal (in nanoseconds) 92 * @period: period of the PWM signal (in nanoseconds)
91 * @duty_cycle: duty cycle of the PWM signal (in nanoseconds) 93 * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
92 * @polarity: polarity of the PWM signal 94 * @polarity: polarity of the PWM signal
@@ -98,6 +100,7 @@ struct pwm_device {
98 unsigned int pwm; 100 unsigned int pwm;
99 struct pwm_chip *chip; 101 struct pwm_chip *chip;
100 void *chip_data; 102 void *chip_data;
103 struct mutex lock;
101 104
102 unsigned int period; 105 unsigned int period;
103 unsigned int duty_cycle; 106 unsigned int duty_cycle;