diff options
-rw-r--r-- | Documentation/devicetree/bindings/pwm/cirrus,clps711x-pwm.txt | 16 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt | 35 | ||||
-rw-r--r-- | arch/arm/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Kconfig | 14 | ||||
-rw-r--r-- | drivers/input/misc/Kconfig | 4 | ||||
-rw-r--r-- | drivers/pwm/Kconfig | 30 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 3 | ||||
-rw-r--r-- | drivers/pwm/pwm-atmel.c | 9 | ||||
-rw-r--r-- | drivers/pwm/pwm-clps711x.c | 176 | ||||
-rw-r--r-- | drivers/pwm/pwm-fsl-ftm.c | 495 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss.c | 183 | ||||
-rw-r--r-- | drivers/pwm/pwm-pxa.c | 4 | ||||
-rw-r--r-- | drivers/pwm/pwm-samsung.c | 5 | ||||
-rw-r--r-- | include/linux/pwm.h | 2 |
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 | |||
3 | Required 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 | |||
9 | Example: | ||
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 @@ | |||
1 | Freescale FlexTimer Module (FTM) PWM controller | ||
2 | |||
3 | Required 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 | |||
21 | Example: | ||
22 | |||
23 | pwm0: 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 | ||
114 | endif | 114 | endif |
115 | 115 | ||
116 | config HAVE_PWM | ||
117 | bool | ||
118 | |||
119 | config MIGHT_HAVE_PCI | 116 | config 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)" | |||
7 | config MACH_PXA3XX_DT | 7 | config 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 | ||
24 | config MACH_MAINSTONE | 23 | config 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 | ||
29 | config MACH_ZYLONITE | 27 | config MACH_ZYLONITE |
30 | bool | 28 | bool |
31 | select HAVE_PWM | ||
32 | select PXA3xx | 29 | select PXA3xx |
33 | 30 | ||
34 | config MACH_ZYLONITE300 | 31 | config 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 | ||
129 | config MACH_CAPC7117 | 125 | config MACH_CAPC7117 |
@@ -214,7 +210,6 @@ config TRIZEPS_PCMCIA | |||
214 | 210 | ||
215 | config MACH_LOGICPD_PXA270 | 211 | config 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 | ||
220 | config MACH_PCM027 | 215 | config MACH_PCM027 |
@@ -225,7 +220,6 @@ config MACH_PCM027 | |||
225 | config MACH_PCM990_BASEBOARD | 220 | config 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 | ||
230 | choice | 224 | choice |
231 | prompt "display on pcm990" | 225 | prompt "display on pcm990" |
@@ -249,7 +243,6 @@ config MACH_COLIBRI | |||
249 | config MACH_COLIBRI_PXA270_INCOME | 243 | config 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 | ||
255 | config MACH_COLIBRI300 | 248 | config MACH_COLIBRI300 |
@@ -278,7 +271,6 @@ comment "End-user Products (sorted by vendor name)" | |||
278 | 271 | ||
279 | config MACH_H4700 | 272 | config 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 | ||
293 | config MACH_MAGICIAN | 285 | config 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 | ||
299 | config MACH_MIOA701 | 290 | config 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 | ||
310 | config PXA_EZX | 300 | config 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 | ||
350 | config ARCH_PXA_PALM | 339 | config ARCH_PXA_PALM |
351 | bool "PXA based Palm PDAs" | 340 | bool "PXA based Palm PDAs" |
352 | select HAVE_PWM | ||
353 | 341 | ||
354 | config MACH_PALM27X | 342 | config MACH_PALM27X |
355 | bool | 343 | bool |
@@ -447,7 +435,6 @@ config MACH_TREO680 | |||
447 | config MACH_RAUMFELD_RC | 435 | config 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 | ||
612 | config MACH_ZIPIT2 | 599 | config MACH_ZIPIT2 |
613 | bool "Zipit Z2 Handheld" | 600 | bool "Zipit Z2 Handheld" |
614 | select HAVE_PWM | ||
615 | select PXA27x | 601 | select PXA27x |
616 | endmenu | 602 | endmenu |
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 | ||
157 | config INPUT_MAX8997_HAPTIC | 157 | config 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 | ||
471 | config INPUT_PWM_BEEPER | 471 | config 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 | ||
74 | config 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 | |||
74 | config PWM_EP93XX | 83 | config 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 | ||
92 | config 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 | |||
83 | config PWM_IMX | 102 | config 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 | ||
141 | config 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 | |||
122 | config PWM_MXS | 151 | config 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 | |||
160 | config PWM_RENESAS_TPU | 189 | config 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 | |||
4 | obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o | 4 | obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o |
5 | obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o | 5 | obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o |
6 | obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o | 6 | obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o |
7 | obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o | ||
7 | obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o | 8 | obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o |
9 | obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o | ||
8 | obj-$(CONFIG_PWM_IMX) += pwm-imx.o | 10 | obj-$(CONFIG_PWM_IMX) += pwm-imx.o |
9 | obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o | 11 | obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o |
10 | obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o | 12 | obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o |
11 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o | 13 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o |
14 | obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o | ||
12 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o | 15 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o |
13 | obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o | 16 | obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o |
14 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o | 17 | obj-$(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 | |||
19 | struct clps711x_chip { | ||
20 | struct pwm_chip chip; | ||
21 | void __iomem *pmpcon; | ||
22 | struct clk *clk; | ||
23 | spinlock_t lock; | ||
24 | }; | ||
25 | |||
26 | static inline struct clps711x_chip *to_clps711x_chip(struct pwm_chip *chip) | ||
27 | { | ||
28 | return container_of(chip, struct clps711x_chip, chip); | ||
29 | } | ||
30 | |||
31 | static 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 | |||
48 | static 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 | |||
54 | static 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 | |||
68 | static 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 | |||
83 | static 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 | |||
94 | static 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 | |||
101 | static 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 | |||
109 | static 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 | |||
118 | static 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 | |||
150 | static 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 | |||
157 | static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = { | ||
158 | { .compatible = "cirrus,clps711x-pwm", }, | ||
159 | { } | ||
160 | }; | ||
161 | MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids); | ||
162 | |||
163 | static 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 | }; | ||
172 | module_platform_driver(clps711x_pwm_driver); | ||
173 | |||
174 | MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); | ||
175 | MODULE_DESCRIPTION("Cirrus Logic CLPS711X PWM driver"); | ||
176 | MODULE_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 | |||
69 | enum 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 | |||
77 | struct 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 | |||
93 | static 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 | |||
98 | static 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 | |||
105 | static 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 | |||
112 | static 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 | |||
147 | static 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 | |||
166 | static 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 | |||
183 | static 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 | |||
218 | static 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 | |||
231 | static 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 | |||
279 | static 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 | |||
298 | static 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 | |||
327 | static 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 | |||
344 | static 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 | |||
367 | static 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 | |||
387 | static 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 | |||
397 | static 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 | |||
414 | static 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 | |||
469 | static 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 | |||
476 | static const struct of_device_id fsl_pwm_dt_ids[] = { | ||
477 | { .compatible = "fsl,vf610-ftm-pwm", }, | ||
478 | { /* sentinel */ } | ||
479 | }; | ||
480 | MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids); | ||
481 | |||
482 | static 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 | }; | ||
490 | module_platform_driver(fsl_pwm_driver); | ||
491 | |||
492 | MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver"); | ||
493 | MODULE_AUTHOR("Xiubo Li <Li.Xiubo@freescale.com>"); | ||
494 | MODULE_ALIAS("platform:fsl-ftm-pwm"); | ||
495 | MODULE_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 | |||
33 | struct pwm_lpss_chip { | ||
34 | struct pwm_chip chip; | ||
35 | void __iomem *regs; | ||
36 | struct clk *clk; | ||
37 | }; | ||
38 | |||
39 | static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) | ||
40 | { | ||
41 | return container_of(chip, struct pwm_lpss_chip, chip); | ||
42 | } | ||
43 | |||
44 | static 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 | |||
82 | static 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 | |||
98 | static 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 | |||
109 | static 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 | |||
116 | static const struct acpi_device_id pwm_lpss_acpi_match[] = { | ||
117 | { "80860F09", 0 }, | ||
118 | { }, | ||
119 | }; | ||
120 | MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); | ||
121 | |||
122 | static 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 | |||
159 | static 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 | |||
170 | static 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 | }; | ||
178 | module_platform_driver(pwm_lpss_driver); | ||
179 | |||
180 | MODULE_DESCRIPTION("PWM driver for Intel LPSS"); | ||
181 | MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); | ||
182 | MODULE_LICENSE("GPL v2"); | ||
183 | MODULE_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 | */ |
135 | static struct of_device_id pwm_of_match[] = { | 135 | static 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 | ||
601 | static const struct dev_pm_ops pwm_samsung_pm_ops = { | 601 | static 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 | ||
605 | static struct platform_driver pwm_samsung_driver = { | 604 | static 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 @@ | |||
7 | struct pwm_device; | 7 | struct pwm_device; |
8 | struct seq_file; | 8 | struct 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 | */ |