aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt16
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt35
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/mach-pxa/Kconfig14
-rw-r--r--drivers/input/misc/Kconfig4
-rw-r--r--drivers/pwm/Kconfig30
-rw-r--r--drivers/pwm/Makefile3
-rw-r--r--drivers/pwm/pwm-atmel.c9
-rw-r--r--drivers/pwm/pwm-clps711x.c176
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c495
-rw-r--r--drivers/pwm/pwm-lpss.c183
-rw-r--r--drivers/pwm/pwm-pxa.c4
-rw-r--r--drivers/pwm/pwm-samsung.c5
-rw-r--r--include/linux/pwm.h2
14 files changed, 952 insertions, 28 deletions
diff --git a/Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt b/Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt
new file mode 100644
index 000000000000..a183db48f910
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt
@@ -0,0 +1,16 @@
1* Cirris Logic CLPS711X PWM controller
2
3Required properties:
4- compatible: Shall contain "cirrus,clps711x-pwm".
5- reg: Physical base address and length of the controller's registers.
6- clocks: phandle + clock specifier pair of the PWM reference clock.
7- #pwm-cells: Should be 1. The cell specifies the index of the channel.
8
9Example:
10 pwm: pwm@80000400 {
11 compatible = "cirrus,ep7312-pwm",
12 "cirrus,clps711x-pwm";
13 reg = <0x80000400 0x4>;
14 clocks = <&clks 8>;
15 #pwm-cells = <1>;
16 };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt b/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt
new file mode 100644
index 000000000000..0bda229a6171
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt
@@ -0,0 +1,35 @@
1Freescale FlexTimer Module (FTM) PWM controller
2
3Required properties:
4- compatible: Should be "fsl,vf610-ftm-pwm".
5- reg: Physical base address and length of the controller's registers
6- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
7 the cells format.
8- clock-names: Should include the following module clock source entries:
9 "ftm_sys" (module clock, also can be used as counter clock),
10 "ftm_ext" (external counter clock),
11 "ftm_fix" (fixed counter clock),
12 "ftm_cnt_clk_en" (external and fixed counter clock enable/disable).
13- clocks: Must contain a phandle and clock specifier for each entry in
14 clock-names, please see clock/clock-bindings.txt for details of the property
15 values.
16- pinctrl-names: Must contain a "default" entry.
17- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
18 See pinctrl/pinctrl-bindings.txt for details of the property values.
19
20
21Example:
22
23pwm0: pwm@40038000 {
24 compatible = "fsl,vf610-ftm-pwm";
25 reg = <0x40038000 0x1000>;
26 #pwm-cells = <3>;
27 clock-names = "ftm_sys", "ftm_ext",
28 "ftm_fix", "ftm_cnt_clk_en";
29 clocks = <&clks VF610_CLK_FTM0>,
30 <&clks VF610_CLK_FTM0_EXT_SEL>,
31 <&clks VF610_CLK_FTM0_FIX_SEL>,
32 <&clks VF610_CLK_FTM0_EXT_FIX_EN>;
33 pinctrl-names = "default";
34 pinctrl-0 = <&pinctrl_pwm0_1>;
35};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b4935db86f37..d7a71e3ef55f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -113,9 +113,6 @@ config ARM_DMA_IOMMU_ALIGNMENT
113 113
114endif 114endif
115 115
116config HAVE_PWM
117 bool
118
119config MIGHT_HAVE_PCI 116config MIGHT_HAVE_PCI
120 bool 117 bool
121 118
@@ -633,7 +630,6 @@ config ARCH_LPC32XX
633 select CPU_ARM926T 630 select CPU_ARM926T
634 select GENERIC_CLOCKEVENTS 631 select GENERIC_CLOCKEVENTS
635 select HAVE_IDE 632 select HAVE_IDE
636 select HAVE_PWM
637 select USE_OF 633 select USE_OF
638 help 634 help
639 Support for the NXP LPC32XX family of processors 635 Support for the NXP LPC32XX family of processors
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index a280cc42636b..e6690a44917d 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -7,7 +7,6 @@ comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
7config MACH_PXA3XX_DT 7config MACH_PXA3XX_DT
8 bool "Support PXA3xx platforms from device tree" 8 bool "Support PXA3xx platforms from device tree"
9 select CPU_PXA300 9 select CPU_PXA300
10 select HAVE_PWM
11 select POWER_SUPPLY 10 select POWER_SUPPLY
12 select PXA3xx 11 select PXA3xx
13 select USE_OF 12 select USE_OF
@@ -23,12 +22,10 @@ config ARCH_LUBBOCK
23 22
24config MACH_MAINSTONE 23config MACH_MAINSTONE
25 bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)" 24 bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
26 select HAVE_PWM
27 select PXA27x 25 select PXA27x
28 26
29config MACH_ZYLONITE 27config MACH_ZYLONITE
30 bool 28 bool
31 select HAVE_PWM
32 select PXA3xx 29 select PXA3xx
33 30
34config MACH_ZYLONITE300 31config MACH_ZYLONITE300
@@ -123,7 +120,6 @@ config MACH_CM_X300
123 bool "CompuLab CM-X300 modules" 120 bool "CompuLab CM-X300 modules"
124 select CPU_PXA300 121 select CPU_PXA300
125 select CPU_PXA310 122 select CPU_PXA310
126 select HAVE_PWM
127 select PXA3xx 123 select PXA3xx
128 124
129config MACH_CAPC7117 125config MACH_CAPC7117
@@ -214,7 +210,6 @@ config TRIZEPS_PCMCIA
214 210
215config MACH_LOGICPD_PXA270 211config MACH_LOGICPD_PXA270
216 bool "LogicPD PXA270 Card Engine Development Platform" 212 bool "LogicPD PXA270 Card Engine Development Platform"
217 select HAVE_PWM
218 select PXA27x 213 select PXA27x
219 214
220config MACH_PCM027 215config MACH_PCM027
@@ -225,7 +220,6 @@ config MACH_PCM027
225config MACH_PCM990_BASEBOARD 220config MACH_PCM990_BASEBOARD
226 bool "PHYTEC PCM-990 development board" 221 bool "PHYTEC PCM-990 development board"
227 depends on MACH_PCM027 222 depends on MACH_PCM027
228 select HAVE_PWM
229 223
230choice 224choice
231 prompt "display on pcm990" 225 prompt "display on pcm990"
@@ -249,7 +243,6 @@ config MACH_COLIBRI
249config MACH_COLIBRI_PXA270_INCOME 243config MACH_COLIBRI_PXA270_INCOME
250 bool "Income s.r.o. PXA270 SBC" 244 bool "Income s.r.o. PXA270 SBC"
251 depends on MACH_COLIBRI 245 depends on MACH_COLIBRI
252 select HAVE_PWM
253 select PXA27x 246 select PXA27x
254 247
255config MACH_COLIBRI300 248config MACH_COLIBRI300
@@ -278,7 +271,6 @@ comment "End-user Products (sorted by vendor name)"
278 271
279config MACH_H4700 272config MACH_H4700
280 bool "HP iPAQ hx4700" 273 bool "HP iPAQ hx4700"
281 select HAVE_PWM
282 select IWMMXT 274 select IWMMXT
283 select PXA27x 275 select PXA27x
284 276
@@ -292,14 +284,12 @@ config MACH_HIMALAYA
292 284
293config MACH_MAGICIAN 285config MACH_MAGICIAN
294 bool "Enable HTC Magician Support" 286 bool "Enable HTC Magician Support"
295 select HAVE_PWM
296 select IWMMXT 287 select IWMMXT
297 select PXA27x 288 select PXA27x
298 289
299config MACH_MIOA701 290config MACH_MIOA701
300 bool "Mitac Mio A701 Support" 291 bool "Mitac Mio A701 Support"
301 select GPIO_SYSFS 292 select GPIO_SYSFS
302 select HAVE_PWM
303 select IWMMXT 293 select IWMMXT
304 select PXA27x 294 select PXA27x
305 help 295 help
@@ -309,7 +299,6 @@ config MACH_MIOA701
309 299
310config PXA_EZX 300config PXA_EZX
311 bool "Motorola EZX Platform" 301 bool "Motorola EZX Platform"
312 select HAVE_PWM
313 select IWMMXT 302 select IWMMXT
314 select PXA27x 303 select PXA27x
315 304
@@ -349,7 +338,6 @@ config MACH_MP900C
349 338
350config ARCH_PXA_PALM 339config ARCH_PXA_PALM
351 bool "PXA based Palm PDAs" 340 bool "PXA based Palm PDAs"
352 select HAVE_PWM
353 341
354config MACH_PALM27X 342config MACH_PALM27X
355 bool 343 bool
@@ -447,7 +435,6 @@ config MACH_TREO680
447config MACH_RAUMFELD_RC 435config MACH_RAUMFELD_RC
448 bool "Raumfeld Controller" 436 bool "Raumfeld Controller"
449 select CPU_PXA300 437 select CPU_PXA300
450 select HAVE_PWM
451 select POWER_SUPPLY 438 select POWER_SUPPLY
452 select PXA3xx 439 select PXA3xx
453 440
@@ -611,7 +598,6 @@ config MACH_E800
611 598
612config MACH_ZIPIT2 599config MACH_ZIPIT2
613 bool "Zipit Z2 Handheld" 600 bool "Zipit Z2 Handheld"
614 select HAVE_PWM
615 select PXA27x 601 select PXA27x
616endmenu 602endmenu
617 603
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index f772981bdcdb..5928ea71dd69 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -156,7 +156,7 @@ config INPUT_MAX8925_ONKEY
156 156
157config INPUT_MAX8997_HAPTIC 157config INPUT_MAX8997_HAPTIC
158 tristate "MAXIM MAX8997 haptic controller support" 158 tristate "MAXIM MAX8997 haptic controller support"
159 depends on PWM && HAVE_PWM && MFD_MAX8997 159 depends on PWM && MFD_MAX8997
160 select INPUT_FF_MEMLESS 160 select INPUT_FF_MEMLESS
161 help 161 help
162 This option enables device driver support for the haptic controller 162 This option enables device driver support for the haptic controller
@@ -470,7 +470,7 @@ config INPUT_PCF8574
470 470
471config INPUT_PWM_BEEPER 471config INPUT_PWM_BEEPER
472 tristate "PWM beeper support" 472 tristate "PWM beeper support"
473 depends on PWM && HAVE_PWM 473 depends on PWM
474 help 474 help
475 Say Y here to get support for PWM based beeper devices. 475 Say Y here to get support for PWM based beeper devices.
476 476
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 22f2f2857b82..5b34ff29ea38 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -71,6 +71,15 @@ config PWM_BFIN
71 To compile this driver as a module, choose M here: the module 71 To compile this driver as a module, choose M here: the module
72 will be called pwm-bfin. 72 will be called pwm-bfin.
73 73
74config PWM_CLPS711X
75 tristate "CLPS711X PWM support"
76 depends on ARCH_CLPS711X || COMPILE_TEST
77 help
78 Generic PWM framework driver for Cirrus Logic CLPS711X.
79
80 To compile this driver as a module, choose M here: the module
81 will be called pwm-clps711x.
82
74config PWM_EP93XX 83config PWM_EP93XX
75 tristate "Cirrus Logic EP93xx PWM support" 84 tristate "Cirrus Logic EP93xx PWM support"
76 depends on ARCH_EP93XX 85 depends on ARCH_EP93XX
@@ -80,6 +89,16 @@ config PWM_EP93XX
80 To compile this driver as a module, choose M here: the module 89 To compile this driver as a module, choose M here: the module
81 will be called pwm-ep93xx. 90 will be called pwm-ep93xx.
82 91
92config PWM_FSL_FTM
93 tristate "Freescale FlexTimer Module (FTM) PWM support"
94 depends on OF
95 help
96 Generic FTM PWM framework driver for Freescale VF610 and
97 Layerscape LS-1 SoCs.
98
99 To compile this driver as a module, choose M here: the module
100 will be called pwm-fsl-ftm.
101
83config PWM_IMX 102config PWM_IMX
84 tristate "i.MX PWM support" 103 tristate "i.MX PWM support"
85 depends on ARCH_MXC 104 depends on ARCH_MXC
@@ -119,6 +138,16 @@ config PWM_LPC32XX
119 To compile this driver as a module, choose M here: the module 138 To compile this driver as a module, choose M here: the module
120 will be called pwm-lpc32xx. 139 will be called pwm-lpc32xx.
121 140
141config PWM_LPSS
142 tristate "Intel LPSS PWM support"
143 depends on ACPI
144 help
145 Generic PWM framework driver for Intel Low Power Subsystem PWM
146 controller.
147
148 To compile this driver as a module, choose M here: the module
149 will be called pwm-lpss.
150
122config PWM_MXS 151config PWM_MXS
123 tristate "Freescale MXS PWM support" 152 tristate "Freescale MXS PWM support"
124 depends on ARCH_MXS && OF 153 depends on ARCH_MXS && OF
@@ -160,6 +189,7 @@ config PWM_PXA
160config PWM_RENESAS_TPU 189config PWM_RENESAS_TPU
161 tristate "Renesas TPU PWM support" 190 tristate "Renesas TPU PWM support"
162 depends on ARCH_SHMOBILE || COMPILE_TEST 191 depends on ARCH_SHMOBILE || COMPILE_TEST
192 depends on HAS_IOMEM
163 help 193 help
164 This driver exposes the Timer Pulse Unit (TPU) PWM controller found 194 This driver exposes the Timer Pulse Unit (TPU) PWM controller found
165 in Renesas chips through the PWM API. 195 in Renesas chips through the PWM API.
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index d8906ec69976..e57d2c38a794 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -4,11 +4,14 @@ obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
4obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o 4obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
5obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o 5obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
6obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 6obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
7obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
7obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o 8obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
9obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
8obj-$(CONFIG_PWM_IMX) += pwm-imx.o 10obj-$(CONFIG_PWM_IMX) += pwm-imx.o
9obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o 11obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
10obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o 12obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o
11obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o 13obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
14obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
12obj-$(CONFIG_PWM_MXS) += pwm-mxs.o 15obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
13obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o 16obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
14obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o 17obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index bf4144a14661..0adc952cc4ef 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -32,6 +32,7 @@
32/* Bit field in CMR */ 32/* Bit field in CMR */
33#define PWM_CMR_CPOL (1 << 9) 33#define PWM_CMR_CPOL (1 << 9)
34#define PWM_CMR_UPD_CDTY (1 << 10) 34#define PWM_CMR_UPD_CDTY (1 << 10)
35#define PWM_CMR_CPRE_MSK 0xF
35 36
36/* The following registers for PWM v1 */ 37/* The following registers for PWM v1 */
37#define PWMV1_CDTY 0x04 38#define PWMV1_CDTY 0x04
@@ -104,6 +105,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
104 unsigned long clk_rate, prd, dty; 105 unsigned long clk_rate, prd, dty;
105 unsigned long long div; 106 unsigned long long div;
106 unsigned int pres = 0; 107 unsigned int pres = 0;
108 u32 val;
107 int ret; 109 int ret;
108 110
109 if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) { 111 if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) {
@@ -131,7 +133,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
131 prd = div; 133 prd = div;
132 div *= duty_ns; 134 div *= duty_ns;
133 do_div(div, period_ns); 135 do_div(div, period_ns);
134 dty = div; 136 dty = prd - div;
135 137
136 ret = clk_enable(atmel_pwm->clk); 138 ret = clk_enable(atmel_pwm->clk);
137 if (ret) { 139 if (ret) {
@@ -139,7 +141,10 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
139 return ret; 141 return ret;
140 } 142 }
141 143
142 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, pres); 144 /* It is necessary to preserve CPOL, inside CMR */
145 val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
146 val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK);
147 atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
143 atmel_pwm->config(chip, pwm, dty, prd); 148 atmel_pwm->config(chip, pwm, dty, prd);
144 149
145 clk_disable(atmel_pwm->clk); 150 clk_disable(atmel_pwm->clk);
diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
new file mode 100644
index 000000000000..fafb6a0111b0
--- /dev/null
+++ b/drivers/pwm/pwm-clps711x.c
@@ -0,0 +1,176 @@
1/*
2 * Cirrus Logic CLPS711X PWM driver
3 *
4 * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/clk.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/pwm.h>
18
19struct clps711x_chip {
20 struct pwm_chip chip;
21 void __iomem *pmpcon;
22 struct clk *clk;
23 spinlock_t lock;
24};
25
26static inline struct clps711x_chip *to_clps711x_chip(struct pwm_chip *chip)
27{
28 return container_of(chip, struct clps711x_chip, chip);
29}
30
31static void clps711x_pwm_update_val(struct clps711x_chip *priv, u32 n, u32 v)
32{
33 /* PWM0 - bits 4..7, PWM1 - bits 8..11 */
34 u32 shift = (n + 1) * 4;
35 unsigned long flags;
36 u32 tmp;
37
38 spin_lock_irqsave(&priv->lock, flags);
39
40 tmp = readl(priv->pmpcon);
41 tmp &= ~(0xf << shift);
42 tmp |= v << shift;
43 writel(tmp, priv->pmpcon);
44
45 spin_unlock_irqrestore(&priv->lock, flags);
46}
47
48static unsigned int clps711x_get_duty(struct pwm_device *pwm, unsigned int v)
49{
50 /* Duty cycle 0..15 max */
51 return DIV_ROUND_CLOSEST(v * 0xf, pwm_get_period(pwm));
52}
53
54static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
55{
56 struct clps711x_chip *priv = to_clps711x_chip(chip);
57 unsigned int freq = clk_get_rate(priv->clk);
58
59 if (!freq)
60 return -EINVAL;
61
62 /* Store constant period value */
63 pwm_set_period(pwm, DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq));
64
65 return 0;
66}
67
68static int clps711x_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
69 int duty_ns, int period_ns)
70{
71 struct clps711x_chip *priv = to_clps711x_chip(chip);
72 unsigned int duty;
73
74 if (period_ns != pwm_get_period(pwm))
75 return -EINVAL;
76
77 duty = clps711x_get_duty(pwm, duty_ns);
78 clps711x_pwm_update_val(priv, pwm->hwpwm, duty);
79
80 return 0;
81}
82
83static int clps711x_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
84{
85 struct clps711x_chip *priv = to_clps711x_chip(chip);
86 unsigned int duty;
87
88 duty = clps711x_get_duty(pwm, pwm_get_duty_cycle(pwm));
89 clps711x_pwm_update_val(priv, pwm->hwpwm, duty);
90
91 return 0;
92}
93
94static void clps711x_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
95{
96 struct clps711x_chip *priv = to_clps711x_chip(chip);
97
98 clps711x_pwm_update_val(priv, pwm->hwpwm, 0);
99}
100
101static const struct pwm_ops clps711x_pwm_ops = {
102 .request = clps711x_pwm_request,
103 .config = clps711x_pwm_config,
104 .enable = clps711x_pwm_enable,
105 .disable = clps711x_pwm_disable,
106 .owner = THIS_MODULE,
107};
108
109static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip,
110 const struct of_phandle_args *args)
111{
112 if (args->args[0] >= chip->npwm)
113 return ERR_PTR(-EINVAL);
114
115 return pwm_request_from_chip(chip, args->args[0], NULL);
116}
117
118static int clps711x_pwm_probe(struct platform_device *pdev)
119{
120 struct clps711x_chip *priv;
121 struct resource *res;
122
123 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
124 if (!priv)
125 return -ENOMEM;
126
127 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
128 priv->pmpcon = devm_ioremap_resource(&pdev->dev, res);
129 if (IS_ERR(priv->pmpcon))
130 return PTR_ERR(priv->pmpcon);
131
132 priv->clk = devm_clk_get(&pdev->dev, NULL);
133 if (IS_ERR(priv->clk))
134 return PTR_ERR(priv->clk);
135
136 priv->chip.ops = &clps711x_pwm_ops;
137 priv->chip.dev = &pdev->dev;
138 priv->chip.base = -1;
139 priv->chip.npwm = 2;
140 priv->chip.of_xlate = clps711x_pwm_xlate;
141 priv->chip.of_pwm_n_cells = 1;
142
143 spin_lock_init(&priv->lock);
144
145 platform_set_drvdata(pdev, priv);
146
147 return pwmchip_add(&priv->chip);
148}
149
150static int clps711x_pwm_remove(struct platform_device *pdev)
151{
152 struct clps711x_chip *priv = platform_get_drvdata(pdev);
153
154 return pwmchip_remove(&priv->chip);
155}
156
157static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
158 { .compatible = "cirrus,clps711x-pwm", },
159 { }
160};
161MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids);
162
163static struct platform_driver clps711x_pwm_driver = {
164 .driver = {
165 .name = "clps711x-pwm",
166 .owner = THIS_MODULE,
167 .of_match_table = of_match_ptr(clps711x_pwm_dt_ids),
168 },
169 .probe = clps711x_pwm_probe,
170 .remove = clps711x_pwm_remove,
171};
172module_platform_driver(clps711x_pwm_driver);
173
174MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
175MODULE_DESCRIPTION("Cirrus Logic CLPS711X PWM driver");
176MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
new file mode 100644
index 000000000000..420169e96b5f
--- /dev/null
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -0,0 +1,495 @@
1/*
2 * Freescale FlexTimer Module (FTM) PWM Driver
3 *
4 * Copyright 2012-2013 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/clk.h>
13#include <linux/err.h>
14#include <linux/io.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/mutex.h>
18#include <linux/of_address.h>
19#include <linux/platform_device.h>
20#include <linux/pwm.h>
21#include <linux/slab.h>
22
23#define FTM_SC 0x00
24#define FTM_SC_CLK_MASK 0x3
25#define FTM_SC_CLK_SHIFT 3
26#define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_SHIFT)
27#define FTM_SC_PS_MASK 0x7
28#define FTM_SC_PS_SHIFT 0
29
30#define FTM_CNT 0x04
31#define FTM_MOD 0x08
32
33#define FTM_CSC_BASE 0x0C
34#define FTM_CSC_MSB BIT(5)
35#define FTM_CSC_MSA BIT(4)
36#define FTM_CSC_ELSB BIT(3)
37#define FTM_CSC_ELSA BIT(2)
38#define FTM_CSC(_channel) (FTM_CSC_BASE + ((_channel) * 8))
39
40#define FTM_CV_BASE 0x10
41#define FTM_CV(_channel) (FTM_CV_BASE + ((_channel) * 8))
42
43#define FTM_CNTIN 0x4C
44#define FTM_STATUS 0x50
45
46#define FTM_MODE 0x54
47#define FTM_MODE_FTMEN BIT(0)
48#define FTM_MODE_INIT BIT(2)
49#define FTM_MODE_PWMSYNC BIT(3)
50
51#define FTM_SYNC 0x58
52#define FTM_OUTINIT 0x5C
53#define FTM_OUTMASK 0x60
54#define FTM_COMBINE 0x64
55#define FTM_DEADTIME 0x68
56#define FTM_EXTTRIG 0x6C
57#define FTM_POL 0x70
58#define FTM_FMS 0x74
59#define FTM_FILTER 0x78
60#define FTM_FLTCTRL 0x7C
61#define FTM_QDCTRL 0x80
62#define FTM_CONF 0x84
63#define FTM_FLTPOL 0x88
64#define FTM_SYNCONF 0x8C
65#define FTM_INVCTRL 0x90
66#define FTM_SWOCTRL 0x94
67#define FTM_PWMLOAD 0x98
68
69enum fsl_pwm_clk {
70 FSL_PWM_CLK_SYS,
71 FSL_PWM_CLK_FIX,
72 FSL_PWM_CLK_EXT,
73 FSL_PWM_CLK_CNTEN,
74 FSL_PWM_CLK_MAX
75};
76
77struct fsl_pwm_chip {
78 struct pwm_chip chip;
79
80 struct mutex lock;
81
82 unsigned int use_count;
83 unsigned int cnt_select;
84 unsigned int clk_ps;
85
86 void __iomem *base;
87
88 int period_ns;
89
90 struct clk *clk[FSL_PWM_CLK_MAX];
91};
92
93static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
94{
95 return container_of(chip, struct fsl_pwm_chip, chip);
96}
97
98static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
99{
100 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
101
102 return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
103}
104
105static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
106{
107 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
108
109 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
110}
111
112static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc,
113 enum fsl_pwm_clk index)
114{
115 unsigned long sys_rate, cnt_rate;
116 unsigned long long ratio;
117
118 sys_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_SYS]);
119 if (!sys_rate)
120 return -EINVAL;
121
122 cnt_rate = clk_get_rate(fpc->clk[fpc->cnt_select]);
123 if (!cnt_rate)
124 return -EINVAL;
125
126 switch (index) {
127 case FSL_PWM_CLK_SYS:
128 fpc->clk_ps = 1;
129 break;
130 case FSL_PWM_CLK_FIX:
131 ratio = 2 * cnt_rate - 1;
132 do_div(ratio, sys_rate);
133 fpc->clk_ps = ratio;
134 break;
135 case FSL_PWM_CLK_EXT:
136 ratio = 4 * cnt_rate - 1;
137 do_div(ratio, sys_rate);
138 fpc->clk_ps = ratio;
139 break;
140 default:
141 return -EINVAL;
142 }
143
144 return 0;
145}
146
147static unsigned long fsl_pwm_calculate_cycles(struct fsl_pwm_chip *fpc,
148 unsigned long period_ns)
149{
150 unsigned long long c, c0;
151
152 c = clk_get_rate(fpc->clk[fpc->cnt_select]);
153 c = c * period_ns;
154 do_div(c, 1000000000UL);
155
156 do {
157 c0 = c;
158 do_div(c0, (1 << fpc->clk_ps));
159 if (c0 <= 0xFFFF)
160 return (unsigned long)c0;
161 } while (++fpc->clk_ps < 8);
162
163 return 0;
164}
165
166static unsigned long fsl_pwm_calculate_period_cycles(struct fsl_pwm_chip *fpc,
167 unsigned long period_ns,
168 enum fsl_pwm_clk index)
169{
170 int ret;
171
172 ret = fsl_pwm_calculate_default_ps(fpc, index);
173 if (ret) {
174 dev_err(fpc->chip.dev,
175 "failed to calculate default prescaler: %d\n",
176 ret);
177 return 0;
178 }
179
180 return fsl_pwm_calculate_cycles(fpc, period_ns);
181}
182
183static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
184 unsigned long period_ns)
185{
186 enum fsl_pwm_clk m0, m1;
187 unsigned long fix_rate, ext_rate, cycles;
188
189 cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns,
190 FSL_PWM_CLK_SYS);
191 if (cycles) {
192 fpc->cnt_select = FSL_PWM_CLK_SYS;
193 return cycles;
194 }
195
196 fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]);
197 ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]);
198
199 if (fix_rate > ext_rate) {
200 m0 = FSL_PWM_CLK_FIX;
201 m1 = FSL_PWM_CLK_EXT;
202 } else {
203 m0 = FSL_PWM_CLK_EXT;
204 m1 = FSL_PWM_CLK_FIX;
205 }
206
207 cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns, m0);
208 if (cycles) {
209 fpc->cnt_select = m0;
210 return cycles;
211 }
212
213 fpc->cnt_select = m1;
214
215 return fsl_pwm_calculate_period_cycles(fpc, period_ns, m1);
216}
217
218static unsigned long fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,
219 unsigned long period_ns,
220 unsigned long duty_ns)
221{
222 unsigned long long val, duty;
223
224 val = readl(fpc->base + FTM_MOD);
225 duty = duty_ns * (val + 1);
226 do_div(duty, period_ns);
227
228 return (unsigned long)duty;
229}
230
231static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
232 int duty_ns, int period_ns)
233{
234 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
235 u32 val, period, duty;
236
237 mutex_lock(&fpc->lock);
238
239 /*
240 * The Freescale FTM controller supports only a single period for
241 * all PWM channels, therefore incompatible changes need to be
242 * refused.
243 */
244 if (fpc->period_ns && fpc->period_ns != period_ns) {
245 dev_err(fpc->chip.dev,
246 "conflicting period requested for PWM %u\n",
247 pwm->hwpwm);
248 mutex_unlock(&fpc->lock);
249 return -EBUSY;
250 }
251
252 if (!fpc->period_ns && duty_ns) {
253 period = fsl_pwm_calculate_period(fpc, period_ns);
254 if (!period) {
255 dev_err(fpc->chip.dev, "failed to calculate period\n");
256 mutex_unlock(&fpc->lock);
257 return -EINVAL;
258 }
259
260 val = readl(fpc->base + FTM_SC);
261 val &= ~(FTM_SC_PS_MASK << FTM_SC_PS_SHIFT);
262 val |= fpc->clk_ps;
263 writel(val, fpc->base + FTM_SC);
264 writel(period - 1, fpc->base + FTM_MOD);
265
266 fpc->period_ns = period_ns;
267 }
268
269 mutex_unlock(&fpc->lock);
270
271 duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns);
272
273 writel(FTM_CSC_MSB | FTM_CSC_ELSB, fpc->base + FTM_CSC(pwm->hwpwm));
274 writel(duty, fpc->base + FTM_CV(pwm->hwpwm));
275
276 return 0;
277}
278
279static int fsl_pwm_set_polarity(struct pwm_chip *chip,
280 struct pwm_device *pwm,
281 enum pwm_polarity polarity)
282{
283 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
284 u32 val;
285
286 val = readl(fpc->base + FTM_POL);
287
288 if (polarity == PWM_POLARITY_INVERSED)
289 val |= BIT(pwm->hwpwm);
290 else
291 val &= ~BIT(pwm->hwpwm);
292
293 writel(val, fpc->base + FTM_POL);
294
295 return 0;
296}
297
298static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
299{
300 u32 val;
301 int ret;
302
303 if (fpc->use_count != 0)
304 return 0;
305
306 /* select counter clock source */
307 val = readl(fpc->base + FTM_SC);
308 val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT);
309 val |= FTM_SC_CLK(fpc->cnt_select);
310 writel(val, fpc->base + FTM_SC);
311
312 ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]);
313 if (ret)
314 return ret;
315
316 ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
317 if (ret) {
318 clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
319 return ret;
320 }
321
322 fpc->use_count++;
323
324 return 0;
325}
326
327static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
328{
329 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
330 u32 val;
331 int ret;
332
333 mutex_lock(&fpc->lock);
334 val = readl(fpc->base + FTM_OUTMASK);
335 val &= ~BIT(pwm->hwpwm);
336 writel(val, fpc->base + FTM_OUTMASK);
337
338 ret = fsl_counter_clock_enable(fpc);
339 mutex_unlock(&fpc->lock);
340
341 return ret;
342}
343
344static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc)
345{
346 u32 val;
347
348 /*
349 * already disabled, do nothing
350 */
351 if (fpc->use_count == 0)
352 return;
353
354 /* there are still users, so can't disable yet */
355 if (--fpc->use_count > 0)
356 return;
357
358 /* no users left, disable PWM counter clock */
359 val = readl(fpc->base + FTM_SC);
360 val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT);
361 writel(val, fpc->base + FTM_SC);
362
363 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
364 clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
365}
366
367static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
368{
369 struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
370 u32 val;
371
372 mutex_lock(&fpc->lock);
373 val = readl(fpc->base + FTM_OUTMASK);
374 val |= BIT(pwm->hwpwm);
375 writel(val, fpc->base + FTM_OUTMASK);
376
377 fsl_counter_clock_disable(fpc);
378
379 val = readl(fpc->base + FTM_OUTMASK);
380
381 if ((val & 0xFF) == 0xFF)
382 fpc->period_ns = 0;
383
384 mutex_unlock(&fpc->lock);
385}
386
387static const struct pwm_ops fsl_pwm_ops = {
388 .request = fsl_pwm_request,
389 .free = fsl_pwm_free,
390 .config = fsl_pwm_config,
391 .set_polarity = fsl_pwm_set_polarity,
392 .enable = fsl_pwm_enable,
393 .disable = fsl_pwm_disable,
394 .owner = THIS_MODULE,
395};
396
397static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
398{
399 int ret;
400
401 ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
402 if (ret)
403 return ret;
404
405 writel(0x00, fpc->base + FTM_CNTIN);
406 writel(0x00, fpc->base + FTM_OUTINIT);
407 writel(0xFF, fpc->base + FTM_OUTMASK);
408
409 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
410
411 return 0;
412}
413
414static int fsl_pwm_probe(struct platform_device *pdev)
415{
416 struct fsl_pwm_chip *fpc;
417 struct resource *res;
418 int ret;
419
420 fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL);
421 if (!fpc)
422 return -ENOMEM;
423
424 mutex_init(&fpc->lock);
425
426 fpc->chip.dev = &pdev->dev;
427
428 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
429 fpc->base = devm_ioremap_resource(&pdev->dev, res);
430 if (IS_ERR(fpc->base))
431 return PTR_ERR(fpc->base);
432
433 fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys");
434 if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) {
435 dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n");
436 return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);
437 }
438
439 fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(fpc->chip.dev, "ftm_fix");
440 if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX]))
441 return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]);
442
443 fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(fpc->chip.dev, "ftm_ext");
444 if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT]))
445 return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]);
446
447 fpc->clk[FSL_PWM_CLK_CNTEN] =
448 devm_clk_get(fpc->chip.dev, "ftm_cnt_clk_en");
449 if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))
450 return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);
451
452 fpc->chip.ops = &fsl_pwm_ops;
453 fpc->chip.of_xlate = of_pwm_xlate_with_flags;
454 fpc->chip.of_pwm_n_cells = 3;
455 fpc->chip.base = -1;
456 fpc->chip.npwm = 8;
457
458 ret = pwmchip_add(&fpc->chip);
459 if (ret < 0) {
460 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
461 return ret;
462 }
463
464 platform_set_drvdata(pdev, fpc);
465
466 return fsl_pwm_init(fpc);
467}
468
469static int fsl_pwm_remove(struct platform_device *pdev)
470{
471 struct fsl_pwm_chip *fpc = platform_get_drvdata(pdev);
472
473 return pwmchip_remove(&fpc->chip);
474}
475
476static const struct of_device_id fsl_pwm_dt_ids[] = {
477 { .compatible = "fsl,vf610-ftm-pwm", },
478 { /* sentinel */ }
479};
480MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids);
481
482static struct platform_driver fsl_pwm_driver = {
483 .driver = {
484 .name = "fsl-ftm-pwm",
485 .of_match_table = fsl_pwm_dt_ids,
486 },
487 .probe = fsl_pwm_probe,
488 .remove = fsl_pwm_remove,
489};
490module_platform_driver(fsl_pwm_driver);
491
492MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver");
493MODULE_AUTHOR("Xiubo Li <Li.Xiubo@freescale.com>");
494MODULE_ALIAS("platform:fsl-ftm-pwm");
495MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
new file mode 100644
index 000000000000..449e372050a0
--- /dev/null
+++ b/drivers/pwm/pwm-lpss.c
@@ -0,0 +1,183 @@
1/*
2 * Intel Low Power Subsystem PWM controller driver
3 *
4 * Copyright (C) 2014, Intel Corporation
5 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
6 * Author: Chew Kean Ho <kean.ho.chew@intel.com>
7 * Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
8 * Author: Chew Chiau Ee <chiau.ee.chew@intel.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/acpi.h>
16#include <linux/clk.h>
17#include <linux/device.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/pwm.h>
21#include <linux/platform_device.h>
22
23#define PWM 0x00000000
24#define PWM_ENABLE BIT(31)
25#define PWM_SW_UPDATE BIT(30)
26#define PWM_BASE_UNIT_SHIFT 8
27#define PWM_BASE_UNIT_MASK 0x00ffff00
28#define PWM_ON_TIME_DIV_MASK 0x000000ff
29#define PWM_DIVISION_CORRECTION 0x2
30#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION)
31#define NSECS_PER_SEC 1000000000UL
32
33struct pwm_lpss_chip {
34 struct pwm_chip chip;
35 void __iomem *regs;
36 struct clk *clk;
37};
38
39static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
40{
41 return container_of(chip, struct pwm_lpss_chip, chip);
42}
43
44static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
45 int duty_ns, int period_ns)
46{
47 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
48 u8 on_time_div;
49 unsigned long c;
50 unsigned long long base_unit, freq = NSECS_PER_SEC;
51 u32 ctrl;
52
53 do_div(freq, period_ns);
54
55 /* The equation is: base_unit = ((freq / c) * 65536) + correction */
56 base_unit = freq * 65536;
57
58 c = clk_get_rate(lpwm->clk);
59 if (!c)
60 return -EINVAL;
61
62 do_div(base_unit, c);
63 base_unit += PWM_DIVISION_CORRECTION;
64 if (base_unit > PWM_LIMIT)
65 return -EINVAL;
66
67 if (duty_ns <= 0)
68 duty_ns = 1;
69 on_time_div = 255 - (255 * duty_ns / period_ns);
70
71 ctrl = readl(lpwm->regs + PWM);
72 ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK);
73 ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT;
74 ctrl |= on_time_div;
75 /* request PWM to update on next cycle */
76 ctrl |= PWM_SW_UPDATE;
77 writel(ctrl, lpwm->regs + PWM);
78
79 return 0;
80}
81
82static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
83{
84 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
85 u32 ctrl;
86 int ret;
87
88 ret = clk_prepare_enable(lpwm->clk);
89 if (ret)
90 return ret;
91
92 ctrl = readl(lpwm->regs + PWM);
93 writel(ctrl | PWM_ENABLE, lpwm->regs + PWM);
94
95 return 0;
96}
97
98static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
99{
100 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
101 u32 ctrl;
102
103 ctrl = readl(lpwm->regs + PWM);
104 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
105
106 clk_disable_unprepare(lpwm->clk);
107}
108
109static const struct pwm_ops pwm_lpss_ops = {
110 .config = pwm_lpss_config,
111 .enable = pwm_lpss_enable,
112 .disable = pwm_lpss_disable,
113 .owner = THIS_MODULE,
114};
115
116static const struct acpi_device_id pwm_lpss_acpi_match[] = {
117 { "80860F09", 0 },
118 { },
119};
120MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
121
122static int pwm_lpss_probe(struct platform_device *pdev)
123{
124 struct pwm_lpss_chip *lpwm;
125 struct resource *r;
126 int ret;
127
128 lpwm = devm_kzalloc(&pdev->dev, sizeof(*lpwm), GFP_KERNEL);
129 if (!lpwm)
130 return -ENOMEM;
131
132 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
133
134 lpwm->regs = devm_ioremap_resource(&pdev->dev, r);
135 if (IS_ERR(lpwm->regs))
136 return PTR_ERR(lpwm->regs);
137
138 lpwm->clk = devm_clk_get(&pdev->dev, NULL);
139 if (IS_ERR(lpwm->clk)) {
140 dev_err(&pdev->dev, "failed to get PWM clock\n");
141 return PTR_ERR(lpwm->clk);
142 }
143
144 lpwm->chip.dev = &pdev->dev;
145 lpwm->chip.ops = &pwm_lpss_ops;
146 lpwm->chip.base = -1;
147 lpwm->chip.npwm = 1;
148
149 ret = pwmchip_add(&lpwm->chip);
150 if (ret) {
151 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
152 return ret;
153 }
154
155 platform_set_drvdata(pdev, lpwm);
156 return 0;
157}
158
159static int pwm_lpss_remove(struct platform_device *pdev)
160{
161 struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
162 u32 ctrl;
163
164 ctrl = readl(lpwm->regs + PWM);
165 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
166
167 return pwmchip_remove(&lpwm->chip);
168}
169
170static struct platform_driver pwm_lpss_driver = {
171 .driver = {
172 .name = "pwm-lpss",
173 .acpi_match_table = pwm_lpss_acpi_match,
174 },
175 .probe = pwm_lpss_probe,
176 .remove = pwm_lpss_remove,
177};
178module_platform_driver(pwm_lpss_driver);
179
180MODULE_DESCRIPTION("PWM driver for Intel LPSS");
181MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
182MODULE_LICENSE("GPL v2");
183MODULE_ALIAS("platform:pwm-lpss");
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index 8d995731cef8..cd356d870244 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -127,12 +127,12 @@ static struct pwm_ops pxa_pwm_ops = {
127 127
128#ifdef CONFIG_OF 128#ifdef CONFIG_OF
129/* 129/*
130 * Device tree users must create one device instance for each pwm channel. 130 * Device tree users must create one device instance for each PWM channel.
131 * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver 131 * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver
132 * code that this is a single channel pxa25x-pwm. Currently all devices are 132 * code that this is a single channel pxa25x-pwm. Currently all devices are
133 * supported identically. 133 * supported identically.
134 */ 134 */
135static struct of_device_id pwm_of_match[] = { 135static const struct of_device_id pwm_of_match[] = {
136 { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]}, 136 { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]},
137 { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]}, 137 { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]},
138 { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]}, 138 { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]},
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index b59639e0c029..d66529a995a1 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -598,9 +598,8 @@ static int pwm_samsung_resume(struct device *dev)
598} 598}
599#endif 599#endif
600 600
601static const struct dev_pm_ops pwm_samsung_pm_ops = { 601static SIMPLE_DEV_PM_OPS(pwm_samsung_pm_ops, pwm_samsung_suspend,
602 SET_SYSTEM_SLEEP_PM_OPS(pwm_samsung_suspend, pwm_samsung_resume) 602 pwm_samsung_resume);
603};
604 603
605static struct platform_driver pwm_samsung_driver = { 604static struct platform_driver pwm_samsung_driver = {
606 .driver = { 605 .driver = {
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index f0feafd184a0..4717f54051cb 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -7,7 +7,7 @@
7struct pwm_device; 7struct pwm_device;
8struct seq_file; 8struct seq_file;
9 9
10#if IS_ENABLED(CONFIG_PWM) || IS_ENABLED(CONFIG_HAVE_PWM) 10#if IS_ENABLED(CONFIG_PWM)
11/* 11/*
12 * pwm_request - request a PWM device 12 * pwm_request - request a PWM device
13 */ 13 */