aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/pwm/imx-pwm.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/mxs-pwm.txt2
-rw-r--r--Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt2
-rw-r--r--Documentation/driver-model/devres.txt4
-rw-r--r--Documentation/pwm.txt3
-rw-r--r--arch/mips/include/asm/mach-jz4740/platform.h1
-rw-r--r--arch/mips/include/asm/mach-jz4740/timer.h113
-rw-r--r--arch/mips/jz4740/Kconfig3
-rw-r--r--arch/mips/jz4740/Makefile2
-rw-r--r--arch/mips/jz4740/board-qi_lb60.c1
-rw-r--r--arch/mips/jz4740/platform.c6
-rw-r--r--arch/mips/jz4740/pwm.c177
-rw-r--r--arch/mips/jz4740/time.c2
-rw-r--r--arch/mips/jz4740/timer.c4
-rw-r--r--arch/mips/jz4740/timer.h136
-rw-r--r--arch/unicore32/Kconfig12
-rw-r--r--arch/unicore32/include/mach/regs-ost.h18
-rw-r--r--arch/unicore32/kernel/Makefile1
-rw-r--r--arch/unicore32/kernel/pwm.c263
-rw-r--r--drivers/misc/Kconfig10
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/pwm/Kconfig29
-rw-r--r--drivers/pwm/Makefile3
-rw-r--r--drivers/pwm/core.c82
-rw-r--r--drivers/pwm/pwm-ab8500.c (renamed from drivers/misc/ab8500-pwm.c)116
-rw-r--r--drivers/pwm/pwm-bfin.c3
-rw-r--r--drivers/pwm/pwm-imx.c278
-rw-r--r--drivers/pwm/pwm-jz4740.c221
-rw-r--r--drivers/pwm/pwm-puv3.c161
-rw-r--r--drivers/pwm/pwm-pxa.c3
-rw-r--r--drivers/pwm/pwm-samsung.c3
-rw-r--r--drivers/pwm/pwm-tiecap.c24
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c75
-rw-r--r--drivers/video/backlight/pwm_bl.c7
-rw-r--r--include/linux/pwm.h108
35 files changed, 1069 insertions, 822 deletions
diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
new file mode 100644
index 000000000000..8522bfbccfd7
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
@@ -0,0 +1,17 @@
1Freescale i.MX PWM controller
2
3Required properties:
4- compatible: should be "fsl,<soc>-pwm"
5- reg: physical base address and length of the controller's registers
6- #pwm-cells: should be 2. The first cell specifies the per-chip index
7 of the PWM to use and the second cell is the period in nanoseconds.
8- interrupts: The interrupt for the pwm controller
9
10Example:
11
12pwm1: pwm@53fb4000 {
13 #pwm-cells = <2>;
14 compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
15 reg = <0x53fb4000 0x4000>;
16 interrupts = <61>;
17};
diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
index 11963e4d6bc4..9e3f8f1d46a2 100644
--- a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
@@ -4,7 +4,7 @@ Required properties:
4- compatible: should be "fsl,imx23-pwm" 4- compatible: should be "fsl,imx23-pwm"
5- reg: physical base address and length of the controller's registers 5- reg: physical base address and length of the controller's registers
6- #pwm-cells: should be 2. The first cell specifies the per-chip index 6- #pwm-cells: should be 2. The first cell specifies the per-chip index
7 of the PWM to use and the second cell is the duty cycle in nanoseconds. 7 of the PWM to use and the second cell is the period in nanoseconds.
8- fsl,pwm-number: the number of PWM devices 8- fsl,pwm-number: the number of PWM devices
9 9
10Example: 10Example:
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
index bbbeedb4ec05..01438ecd6628 100644
--- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
@@ -7,7 +7,7 @@ Required properties:
7- reg: physical base address and length of the controller's registers 7- reg: physical base address and length of the controller's registers
8- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The 8- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The
9 first cell specifies the per-chip index of the PWM to use and the second 9 first cell specifies the per-chip index of the PWM to use and the second
10 cell is the duty cycle in nanoseconds. 10 cell is the period in nanoseconds.
11 11
12Example: 12Example:
13 13
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 950856bd2e39..43cff70465ab 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -284,3 +284,7 @@ CLOCK
284PINCTRL 284PINCTRL
285 devm_pinctrl_get() 285 devm_pinctrl_get()
286 devm_pinctrl_put() 286 devm_pinctrl_put()
287
288PWM
289 devm_pwm_get()
290 devm_pwm_put()
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
index 554290ebab94..7d2b4c9b544b 100644
--- a/Documentation/pwm.txt
+++ b/Documentation/pwm.txt
@@ -36,7 +36,8 @@ Legacy users can request a PWM device using pwm_request() and free it
36after usage with pwm_free(). 36after usage with pwm_free().
37 37
38New users should use the pwm_get() function and pass to it the consumer 38New users should use the pwm_get() function and pass to it the consumer
39device or a consumer name. pwm_put() is used to free the PWM device. 39device or a consumer name. pwm_put() is used to free the PWM device. Managed
40variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist.
40 41
41After being requested a PWM has to be configured using: 42After being requested a PWM has to be configured using:
42 43
diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h
index 564ab81d6cdc..163e81db880d 100644
--- a/arch/mips/include/asm/mach-jz4740/platform.h
+++ b/arch/mips/include/asm/mach-jz4740/platform.h
@@ -31,6 +31,7 @@ extern struct platform_device jz4740_pcm_device;
31extern struct platform_device jz4740_codec_device; 31extern struct platform_device jz4740_codec_device;
32extern struct platform_device jz4740_adc_device; 32extern struct platform_device jz4740_adc_device;
33extern struct platform_device jz4740_wdt_device; 33extern struct platform_device jz4740_wdt_device;
34extern struct platform_device jz4740_pwm_device;
34 35
35void jz4740_serial_device_register(void); 36void jz4740_serial_device_register(void);
36 37
diff --git a/arch/mips/include/asm/mach-jz4740/timer.h b/arch/mips/include/asm/mach-jz4740/timer.h
index 9baa03ce748c..a7759fb1f73d 100644
--- a/arch/mips/include/asm/mach-jz4740/timer.h
+++ b/arch/mips/include/asm/mach-jz4740/timer.h
@@ -16,7 +16,120 @@
16#ifndef __ASM_MACH_JZ4740_TIMER 16#ifndef __ASM_MACH_JZ4740_TIMER
17#define __ASM_MACH_JZ4740_TIMER 17#define __ASM_MACH_JZ4740_TIMER
18 18
19#define JZ_REG_TIMER_STOP 0x0C
20#define JZ_REG_TIMER_STOP_SET 0x1C
21#define JZ_REG_TIMER_STOP_CLEAR 0x2C
22#define JZ_REG_TIMER_ENABLE 0x00
23#define JZ_REG_TIMER_ENABLE_SET 0x04
24#define JZ_REG_TIMER_ENABLE_CLEAR 0x08
25#define JZ_REG_TIMER_FLAG 0x10
26#define JZ_REG_TIMER_FLAG_SET 0x14
27#define JZ_REG_TIMER_FLAG_CLEAR 0x18
28#define JZ_REG_TIMER_MASK 0x20
29#define JZ_REG_TIMER_MASK_SET 0x24
30#define JZ_REG_TIMER_MASK_CLEAR 0x28
31
32#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
33#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
34#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
35#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
36
37#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
38#define JZ_TIMER_IRQ_FULL(x) BIT(x)
39
40#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN BIT(9)
41#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW BIT(8)
42#define JZ_TIMER_CTRL_PWM_ENABLE BIT(7)
43#define JZ_TIMER_CTRL_PRESCALE_MASK 0x1c
44#define JZ_TIMER_CTRL_PRESCALE_OFFSET 0x3
45#define JZ_TIMER_CTRL_PRESCALE_1 (0 << 3)
46#define JZ_TIMER_CTRL_PRESCALE_4 (1 << 3)
47#define JZ_TIMER_CTRL_PRESCALE_16 (2 << 3)
48#define JZ_TIMER_CTRL_PRESCALE_64 (3 << 3)
49#define JZ_TIMER_CTRL_PRESCALE_256 (4 << 3)
50#define JZ_TIMER_CTRL_PRESCALE_1024 (5 << 3)
51
52#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
53
54#define JZ_TIMER_CTRL_SRC_EXT BIT(2)
55#define JZ_TIMER_CTRL_SRC_RTC BIT(1)
56#define JZ_TIMER_CTRL_SRC_PCLK BIT(0)
57
58extern void __iomem *jz4740_timer_base;
59void __init jz4740_timer_init(void);
60
19void jz4740_timer_enable_watchdog(void); 61void jz4740_timer_enable_watchdog(void);
20void jz4740_timer_disable_watchdog(void); 62void jz4740_timer_disable_watchdog(void);
21 63
64static inline void jz4740_timer_stop(unsigned int timer)
65{
66 writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
67}
68
69static inline void jz4740_timer_start(unsigned int timer)
70{
71 writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
72}
73
74static inline bool jz4740_timer_is_enabled(unsigned int timer)
75{
76 return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
77}
78
79static inline void jz4740_timer_enable(unsigned int timer)
80{
81 writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
82}
83
84static inline void jz4740_timer_disable(unsigned int timer)
85{
86 writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
87}
88
89static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
90{
91 writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
92}
93
94static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
95{
96 writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
97}
98
99static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
100{
101 writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
102}
103
104static inline uint16_t jz4740_timer_get_count(unsigned int timer)
105{
106 return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
107}
108
109static inline void jz4740_timer_ack_full(unsigned int timer)
110{
111 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
112}
113
114static inline void jz4740_timer_irq_full_enable(unsigned int timer)
115{
116 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
117 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
118}
119
120static inline void jz4740_timer_irq_full_disable(unsigned int timer)
121{
122 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
123}
124
125static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
126{
127 writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
128}
129
130static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
131{
132 return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
133}
134
22#endif 135#endif
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 3e7141f0746c..468903053883 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -7,6 +7,3 @@ config JZ4740_QI_LB60
7 bool "Qi Hardware Ben NanoNote" 7 bool "Qi Hardware Ben NanoNote"
8 8
9endchoice 9endchoice
10
11config HAVE_PWM
12 bool
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index e44abea9c209..63bad0e491d0 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
5# Object file lists. 5# Object file lists.
6 6
7obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ 7obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
8 gpio.o clock.o platform.o timer.o pwm.o serial.o 8 gpio.o clock.o platform.o timer.o serial.o
9 9
10obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o 10obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
11 11
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 9a3d9de4d04e..43d964d36288 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -437,6 +437,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
437 &jz4740_codec_device, 437 &jz4740_codec_device,
438 &jz4740_rtc_device, 438 &jz4740_rtc_device,
439 &jz4740_adc_device, 439 &jz4740_adc_device,
440 &jz4740_pwm_device,
440 &qi_lb60_gpio_keys, 441 &qi_lb60_gpio_keys,
441 &qi_lb60_pwm_beeper, 442 &qi_lb60_pwm_beeper,
442 &qi_lb60_charger_device, 443 &qi_lb60_charger_device,
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index e342ed4cbd43..6d14dcdbd908 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -323,3 +323,9 @@ struct platform_device jz4740_wdt_device = {
323 .num_resources = ARRAY_SIZE(jz4740_wdt_resources), 323 .num_resources = ARRAY_SIZE(jz4740_wdt_resources),
324 .resource = jz4740_wdt_resources, 324 .resource = jz4740_wdt_resources,
325}; 325};
326
327/* PWM */
328struct platform_device jz4740_pwm_device = {
329 .name = "jz4740-pwm",
330 .id = -1,
331};
diff --git a/arch/mips/jz4740/pwm.c b/arch/mips/jz4740/pwm.c
deleted file mode 100644
index a26a6faec9a6..000000000000
--- a/arch/mips/jz4740/pwm.c
+++ /dev/null
@@ -1,177 +0,0 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform PWM support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17
18#include <linux/clk.h>
19#include <linux/err.h>
20#include <linux/pwm.h>
21#include <linux/gpio.h>
22
23#include <asm/mach-jz4740/gpio.h>
24#include "timer.h"
25
26static struct clk *jz4740_pwm_clk;
27
28DEFINE_MUTEX(jz4740_pwm_mutex);
29
30struct pwm_device {
31 unsigned int id;
32 unsigned int gpio;
33 bool used;
34};
35
36static struct pwm_device jz4740_pwm_list[] = {
37 { 2, JZ_GPIO_PWM2, false },
38 { 3, JZ_GPIO_PWM3, false },
39 { 4, JZ_GPIO_PWM4, false },
40 { 5, JZ_GPIO_PWM5, false },
41 { 6, JZ_GPIO_PWM6, false },
42 { 7, JZ_GPIO_PWM7, false },
43};
44
45struct pwm_device *pwm_request(int id, const char *label)
46{
47 int ret = 0;
48 struct pwm_device *pwm;
49
50 if (id < 2 || id > 7 || !jz4740_pwm_clk)
51 return ERR_PTR(-ENODEV);
52
53 mutex_lock(&jz4740_pwm_mutex);
54
55 pwm = &jz4740_pwm_list[id - 2];
56 if (pwm->used)
57 ret = -EBUSY;
58 else
59 pwm->used = true;
60
61 mutex_unlock(&jz4740_pwm_mutex);
62
63 if (ret)
64 return ERR_PTR(ret);
65
66 ret = gpio_request(pwm->gpio, label);
67
68 if (ret) {
69 printk(KERN_ERR "Failed to request pwm gpio: %d\n", ret);
70 pwm->used = false;
71 return ERR_PTR(ret);
72 }
73
74 jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_PWM);
75
76 jz4740_timer_start(id);
77
78 return pwm;
79}
80
81void pwm_free(struct pwm_device *pwm)
82{
83 pwm_disable(pwm);
84 jz4740_timer_set_ctrl(pwm->id, 0);
85
86 jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_NONE);
87 gpio_free(pwm->gpio);
88
89 jz4740_timer_stop(pwm->id);
90
91 pwm->used = false;
92}
93
94int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
95{
96 unsigned long long tmp;
97 unsigned long period, duty;
98 unsigned int prescaler = 0;
99 unsigned int id = pwm->id;
100 uint16_t ctrl;
101 bool is_enabled;
102
103 if (duty_ns < 0 || duty_ns > period_ns)
104 return -EINVAL;
105
106 tmp = (unsigned long long)clk_get_rate(jz4740_pwm_clk) * period_ns;
107 do_div(tmp, 1000000000);
108 period = tmp;
109
110 while (period > 0xffff && prescaler < 6) {
111 period >>= 2;
112 ++prescaler;
113 }
114
115 if (prescaler == 6)
116 return -EINVAL;
117
118 tmp = (unsigned long long)period * duty_ns;
119 do_div(tmp, period_ns);
120 duty = period - tmp;
121
122 if (duty >= period)
123 duty = period - 1;
124
125 is_enabled = jz4740_timer_is_enabled(id);
126 if (is_enabled)
127 pwm_disable(pwm);
128
129 jz4740_timer_set_count(id, 0);
130 jz4740_timer_set_duty(id, duty);
131 jz4740_timer_set_period(id, period);
132
133 ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
134 JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
135
136 jz4740_timer_set_ctrl(id, ctrl);
137
138 if (is_enabled)
139 pwm_enable(pwm);
140
141 return 0;
142}
143
144int pwm_enable(struct pwm_device *pwm)
145{
146 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
147
148 ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
149 jz4740_timer_set_ctrl(pwm->id, ctrl);
150 jz4740_timer_enable(pwm->id);
151
152 return 0;
153}
154
155void pwm_disable(struct pwm_device *pwm)
156{
157 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
158
159 ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
160 jz4740_timer_disable(pwm->id);
161 jz4740_timer_set_ctrl(pwm->id, ctrl);
162}
163
164static int __init jz4740_pwm_init(void)
165{
166 int ret = 0;
167
168 jz4740_pwm_clk = clk_get(NULL, "ext");
169
170 if (IS_ERR(jz4740_pwm_clk)) {
171 ret = PTR_ERR(jz4740_pwm_clk);
172 jz4740_pwm_clk = NULL;
173 }
174
175 return ret;
176}
177subsys_initcall(jz4740_pwm_init);
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index f83c2dd07a27..39bb4bbf43e7 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -20,10 +20,10 @@
20#include <linux/clockchips.h> 20#include <linux/clockchips.h>
21 21
22#include <asm/mach-jz4740/irq.h> 22#include <asm/mach-jz4740/irq.h>
23#include <asm/mach-jz4740/timer.h>
23#include <asm/time.h> 24#include <asm/time.h>
24 25
25#include "clock.h" 26#include "clock.h"
26#include "timer.h"
27 27
28#define TIMER_CLOCKEVENT 0 28#define TIMER_CLOCKEVENT 0
29#define TIMER_CLOCKSOURCE 1 29#define TIMER_CLOCKSOURCE 1
diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c
index 654d5c3900b6..22f11d73a17d 100644
--- a/arch/mips/jz4740/timer.c
+++ b/arch/mips/jz4740/timer.c
@@ -17,11 +17,11 @@
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/module.h> 18#include <linux/module.h>
19 19
20#include "timer.h"
21
22#include <asm/mach-jz4740/base.h> 20#include <asm/mach-jz4740/base.h>
21#include <asm/mach-jz4740/timer.h>
23 22
24void __iomem *jz4740_timer_base; 23void __iomem *jz4740_timer_base;
24EXPORT_SYMBOL_GPL(jz4740_timer_base);
25 25
26void jz4740_timer_enable_watchdog(void) 26void jz4740_timer_enable_watchdog(void)
27{ 27{
diff --git a/arch/mips/jz4740/timer.h b/arch/mips/jz4740/timer.h
deleted file mode 100644
index fca3994f2e6d..000000000000
--- a/arch/mips/jz4740/timer.h
+++ /dev/null
@@ -1,136 +0,0 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform timer support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#ifndef __MIPS_JZ4740_TIMER_H__
17#define __MIPS_JZ4740_TIMER_H__
18
19#include <linux/module.h>
20#include <linux/io.h>
21
22#define JZ_REG_TIMER_STOP 0x0C
23#define JZ_REG_TIMER_STOP_SET 0x1C
24#define JZ_REG_TIMER_STOP_CLEAR 0x2C
25#define JZ_REG_TIMER_ENABLE 0x00
26#define JZ_REG_TIMER_ENABLE_SET 0x04
27#define JZ_REG_TIMER_ENABLE_CLEAR 0x08
28#define JZ_REG_TIMER_FLAG 0x10
29#define JZ_REG_TIMER_FLAG_SET 0x14
30#define JZ_REG_TIMER_FLAG_CLEAR 0x18
31#define JZ_REG_TIMER_MASK 0x20
32#define JZ_REG_TIMER_MASK_SET 0x24
33#define JZ_REG_TIMER_MASK_CLEAR 0x28
34
35#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
36#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
37#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
38#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
39
40#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
41#define JZ_TIMER_IRQ_FULL(x) BIT(x)
42
43#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN BIT(9)
44#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW BIT(8)
45#define JZ_TIMER_CTRL_PWM_ENABLE BIT(7)
46#define JZ_TIMER_CTRL_PRESCALE_MASK 0x1c
47#define JZ_TIMER_CTRL_PRESCALE_OFFSET 0x3
48#define JZ_TIMER_CTRL_PRESCALE_1 (0 << 3)
49#define JZ_TIMER_CTRL_PRESCALE_4 (1 << 3)
50#define JZ_TIMER_CTRL_PRESCALE_16 (2 << 3)
51#define JZ_TIMER_CTRL_PRESCALE_64 (3 << 3)
52#define JZ_TIMER_CTRL_PRESCALE_256 (4 << 3)
53#define JZ_TIMER_CTRL_PRESCALE_1024 (5 << 3)
54
55#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
56
57#define JZ_TIMER_CTRL_SRC_EXT BIT(2)
58#define JZ_TIMER_CTRL_SRC_RTC BIT(1)
59#define JZ_TIMER_CTRL_SRC_PCLK BIT(0)
60
61extern void __iomem *jz4740_timer_base;
62void __init jz4740_timer_init(void);
63
64static inline void jz4740_timer_stop(unsigned int timer)
65{
66 writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
67}
68
69static inline void jz4740_timer_start(unsigned int timer)
70{
71 writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
72}
73
74static inline bool jz4740_timer_is_enabled(unsigned int timer)
75{
76 return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
77}
78
79static inline void jz4740_timer_enable(unsigned int timer)
80{
81 writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
82}
83
84static inline void jz4740_timer_disable(unsigned int timer)
85{
86 writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
87}
88
89
90static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
91{
92 writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
93}
94
95static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
96{
97 writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
98}
99
100static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
101{
102 writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
103}
104
105static inline uint16_t jz4740_timer_get_count(unsigned int timer)
106{
107 return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
108}
109
110static inline void jz4740_timer_ack_full(unsigned int timer)
111{
112 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
113}
114
115static inline void jz4740_timer_irq_full_enable(unsigned int timer)
116{
117 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
118 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
119}
120
121static inline void jz4740_timer_irq_full_disable(unsigned int timer)
122{
123 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
124}
125
126static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
127{
128 writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
129}
130
131static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
132{
133 return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
134}
135
136#endif
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index 1e638e75a6b7..35ee2bf66354 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -21,9 +21,6 @@ config UNICORE32
21 designs licensed by PKUnity Ltd. 21 designs licensed by PKUnity Ltd.
22 Please see web page at <http://www.pkunity.com/>. 22 Please see web page at <http://www.pkunity.com/>.
23 23
24config HAVE_PWM
25 bool
26
27config GENERIC_GPIO 24config GENERIC_GPIO
28 def_bool y 25 def_bool y
29 26
@@ -106,7 +103,8 @@ config PUV3_DB0913
106 103
107config PUV3_NB0916 104config PUV3_NB0916
108 bool "NetBook board (0916)" 105 bool "NetBook board (0916)"
109 select HAVE_PWM 106 select PWM
107 select PWM_PUV3
110 108
111config PUV3_SMW0919 109config PUV3_SMW0919
112 bool "Security Mini-Workstation board (0919)" 110 bool "Security Mini-Workstation board (0919)"
@@ -220,12 +218,6 @@ config PUV3_GPIO
220 select GPIO_SYSFS if EXPERIMENTAL 218 select GPIO_SYSFS if EXPERIMENTAL
221 default y 219 default y
222 220
223config PUV3_PWM
224 tristate
225 default BACKLIGHT_PWM
226 help
227 Enable support for NB0916 PWM controllers
228
229if PUV3_NB0916 221if PUV3_NB0916
230 222
231menu "PKUnity NetBook-0916 Features" 223menu "PKUnity NetBook-0916 Features"
diff --git a/arch/unicore32/include/mach/regs-ost.h b/arch/unicore32/include/mach/regs-ost.h
index 7b91fe698eed..4a85fb463848 100644
--- a/arch/unicore32/include/mach/regs-ost.h
+++ b/arch/unicore32/include/mach/regs-ost.h
@@ -33,18 +33,16 @@
33 * Interrupt Enable Reg OST_OIER 33 * Interrupt Enable Reg OST_OIER
34 */ 34 */
35#define OST_OIER (PKUNITY_OST_BASE + 0x001C) 35#define OST_OIER (PKUNITY_OST_BASE + 0x001C)
36
36/* 37/*
37 * PWM Pulse Width Control Reg OST_PWMPWCR 38 * PWM Registers: IO base address: PKUNITY_OST_BASE + 0x80
38 */ 39 * PWCR: Pulse Width Control Reg
39#define OST_PWMPWCR (PKUNITY_OST_BASE + 0x0080) 40 * DCCR: Duty Cycle Control Reg
40/* 41 * PCR: Period Control Reg
41 * PWM Duty Cycle Control Reg OST_PWMDCCR
42 */
43#define OST_PWMDCCR (PKUNITY_OST_BASE + 0x0084)
44/*
45 * PWM Period Control Reg OST_PWMPCR
46 */ 42 */
47#define OST_PWMPCR (PKUNITY_OST_BASE + 0x0088) 43#define OST_PWM_PWCR (0x00)
44#define OST_PWM_DCCR (0x04)
45#define OST_PWM_PCR (0x08)
48 46
49/* 47/*
50 * Match detected 0 OST_OSSR_M0 48 * Match detected 0 OST_OSSR_M0
diff --git a/arch/unicore32/kernel/Makefile b/arch/unicore32/kernel/Makefile
index 324010156958..fa497e0efe5a 100644
--- a/arch/unicore32/kernel/Makefile
+++ b/arch/unicore32/kernel/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o
16obj-$(CONFIG_ARCH_PUV3) += clock.o irq.o time.o 16obj-$(CONFIG_ARCH_PUV3) += clock.o irq.o time.o
17 17
18obj-$(CONFIG_PUV3_GPIO) += gpio.o 18obj-$(CONFIG_PUV3_GPIO) += gpio.o
19obj-$(CONFIG_PUV3_PWM) += pwm.o
20obj-$(CONFIG_PUV3_PM) += pm.o sleep.o 19obj-$(CONFIG_PUV3_PM) += pm.o sleep.o
21obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o 20obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o
22 21
diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
deleted file mode 100644
index 4615d51e3ba6..000000000000
--- a/arch/unicore32/kernel/pwm.c
+++ /dev/null
@@ -1,263 +0,0 @@
1/*
2 * linux/arch/unicore32/kernel/pwm.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18#include <linux/err.h>
19#include <linux/clk.h>
20#include <linux/io.h>
21#include <linux/pwm.h>
22
23#include <asm/div64.h>
24#include <mach/hardware.h>
25
26struct pwm_device {
27 struct list_head node;
28 struct platform_device *pdev;
29
30 const char *label;
31 struct clk *clk;
32 int clk_enabled;
33
34 unsigned int use_count;
35 unsigned int pwm_id;
36};
37
38/*
39 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
40 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
41 */
42int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
43{
44 unsigned long long c;
45 unsigned long period_cycles, prescale, pv, dc;
46
47 if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
48 return -EINVAL;
49
50 c = clk_get_rate(pwm->clk);
51 c = c * period_ns;
52 do_div(c, 1000000000);
53 period_cycles = c;
54
55 if (period_cycles < 1)
56 period_cycles = 1;
57 prescale = (period_cycles - 1) / 1024;
58 pv = period_cycles / (prescale + 1) - 1;
59
60 if (prescale > 63)
61 return -EINVAL;
62
63 if (duty_ns == period_ns)
64 dc = OST_PWMDCCR_FDCYCLE;
65 else
66 dc = (pv + 1) * duty_ns / period_ns;
67
68 /* NOTE: the clock to PWM has to be enabled first
69 * before writing to the registers
70 */
71 clk_enable(pwm->clk);
72 OST_PWMPWCR = prescale;
73 OST_PWMDCCR = pv - dc;
74 OST_PWMPCR = pv;
75 clk_disable(pwm->clk);
76
77 return 0;
78}
79EXPORT_SYMBOL(pwm_config);
80
81int pwm_enable(struct pwm_device *pwm)
82{
83 int rc = 0;
84
85 if (!pwm->clk_enabled) {
86 rc = clk_enable(pwm->clk);
87 if (!rc)
88 pwm->clk_enabled = 1;
89 }
90 return rc;
91}
92EXPORT_SYMBOL(pwm_enable);
93
94void pwm_disable(struct pwm_device *pwm)
95{
96 if (pwm->clk_enabled) {
97 clk_disable(pwm->clk);
98 pwm->clk_enabled = 0;
99 }
100}
101EXPORT_SYMBOL(pwm_disable);
102
103static DEFINE_MUTEX(pwm_lock);
104static LIST_HEAD(pwm_list);
105
106struct pwm_device *pwm_request(int pwm_id, const char *label)
107{
108 struct pwm_device *pwm;
109 int found = 0;
110
111 mutex_lock(&pwm_lock);
112
113 list_for_each_entry(pwm, &pwm_list, node) {
114 if (pwm->pwm_id == pwm_id) {
115 found = 1;
116 break;
117 }
118 }
119
120 if (found) {
121 if (pwm->use_count == 0) {
122 pwm->use_count++;
123 pwm->label = label;
124 } else
125 pwm = ERR_PTR(-EBUSY);
126 } else
127 pwm = ERR_PTR(-ENOENT);
128
129 mutex_unlock(&pwm_lock);
130 return pwm;
131}
132EXPORT_SYMBOL(pwm_request);
133
134void pwm_free(struct pwm_device *pwm)
135{
136 mutex_lock(&pwm_lock);
137
138 if (pwm->use_count) {
139 pwm->use_count--;
140 pwm->label = NULL;
141 } else
142 pr_warning("PWM device already freed\n");
143
144 mutex_unlock(&pwm_lock);
145}
146EXPORT_SYMBOL(pwm_free);
147
148static inline void __add_pwm(struct pwm_device *pwm)
149{
150 mutex_lock(&pwm_lock);
151 list_add_tail(&pwm->node, &pwm_list);
152 mutex_unlock(&pwm_lock);
153}
154
155static struct pwm_device *pwm_probe(struct platform_device *pdev,
156 unsigned int pwm_id, struct pwm_device *parent_pwm)
157{
158 struct pwm_device *pwm;
159 struct resource *r;
160 int ret = 0;
161
162 pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
163 if (pwm == NULL) {
164 dev_err(&pdev->dev, "failed to allocate memory\n");
165 return ERR_PTR(-ENOMEM);
166 }
167
168 pwm->clk = clk_get(NULL, "OST_CLK");
169 if (IS_ERR(pwm->clk)) {
170 ret = PTR_ERR(pwm->clk);
171 goto err_free;
172 }
173 pwm->clk_enabled = 0;
174
175 pwm->use_count = 0;
176 pwm->pwm_id = pwm_id;
177 pwm->pdev = pdev;
178
179 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
180 if (r == NULL) {
181 dev_err(&pdev->dev, "no memory resource defined\n");
182 ret = -ENODEV;
183 goto err_free_clk;
184 }
185
186 r = request_mem_region(r->start, resource_size(r), pdev->name);
187 if (r == NULL) {
188 dev_err(&pdev->dev, "failed to request memory resource\n");
189 ret = -EBUSY;
190 goto err_free_clk;
191 }
192
193 __add_pwm(pwm);
194 platform_set_drvdata(pdev, pwm);
195 return pwm;
196
197err_free_clk:
198 clk_put(pwm->clk);
199err_free:
200 kfree(pwm);
201 return ERR_PTR(ret);
202}
203
204static int __devinit puv3_pwm_probe(struct platform_device *pdev)
205{
206 struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
207
208 if (IS_ERR(pwm))
209 return PTR_ERR(pwm);
210
211 return 0;
212}
213
214static int __devexit pwm_remove(struct platform_device *pdev)
215{
216 struct pwm_device *pwm;
217 struct resource *r;
218
219 pwm = platform_get_drvdata(pdev);
220 if (pwm == NULL)
221 return -ENODEV;
222
223 mutex_lock(&pwm_lock);
224 list_del(&pwm->node);
225 mutex_unlock(&pwm_lock);
226
227 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
228 release_mem_region(r->start, resource_size(r));
229
230 clk_put(pwm->clk);
231 kfree(pwm);
232 return 0;
233}
234
235static struct platform_driver puv3_pwm_driver = {
236 .driver = {
237 .name = "PKUnity-v3-PWM",
238 },
239 .probe = puv3_pwm_probe,
240 .remove = __devexit_p(pwm_remove),
241};
242
243static int __init pwm_init(void)
244{
245 int ret = 0;
246
247 ret = platform_driver_register(&puv3_pwm_driver);
248 if (ret) {
249 printk(KERN_ERR "failed to register puv3_pwm_driver\n");
250 return ret;
251 }
252
253 return ret;
254}
255arch_initcall(pwm_init);
256
257static void __exit pwm_exit(void)
258{
259 platform_driver_unregister(&puv3_pwm_driver);
260}
261module_exit(pwm_exit);
262
263MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 99c73352c430..b151b7c1bd59 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -60,16 +60,6 @@ config ATMEL_PWM
60 purposes including software controlled power-efficient backlights 60 purposes including software controlled power-efficient backlights
61 on LCD displays, motor control, and waveform generation. 61 on LCD displays, motor control, and waveform generation.
62 62
63config AB8500_PWM
64 bool "AB8500 PWM support"
65 depends on AB8500_CORE && ARCH_U8500
66 select HAVE_PWM
67 depends on !PWM
68 help
69 This driver exports functions to enable/disble/config/free Pulse
70 Width Modulation in the Analog Baseband Chip AB8500.
71 It is used by led and backlight driver to control the intensity.
72
73config ATMEL_TCLIB 63config ATMEL_TCLIB
74 bool "Atmel AT32/AT91 Timer/Counter Library" 64 bool "Atmel AT32/AT91 Timer/Counter Library"
75 depends on (AVR32 || ARCH_AT91) 65 depends on (AVR32 || ARCH_AT91)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b88df7a350b8..2129377c0de6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -44,7 +44,6 @@ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
44obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o 44obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
45obj-$(CONFIG_PCH_PHUB) += pch_phub.o 45obj-$(CONFIG_PCH_PHUB) += pch_phub.o
46obj-y += ti-st/ 46obj-y += ti-st/
47obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
48obj-y += lis3lv02d/ 47obj-y += lis3lv02d/
49obj-y += carma/ 48obj-y += carma/
50obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o 49obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index d7c6b83097c1..ed81720e7b2b 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -1,6 +1,5 @@
1menuconfig PWM 1menuconfig PWM
2 bool "Pulse-Width Modulation (PWM) Support" 2 bool "Pulse-Width Modulation (PWM) Support"
3 depends on !MACH_JZ4740 && !PUV3_PWM
4 help 3 help
5 Generic Pulse-Width Modulation (PWM) support. 4 Generic Pulse-Width Modulation (PWM) support.
6 5
@@ -29,6 +28,15 @@ menuconfig PWM
29 28
30if PWM 29if PWM
31 30
31config PWM_AB8500
32 tristate "AB8500 PWM support"
33 depends on AB8500_CORE && ARCH_U8500
34 help
35 Generic PWM framework driver for Analog Baseband AB8500.
36
37 To compile this driver as a module, choose M here: the module
38 will be called pwm-ab8500.
39
32config PWM_BFIN 40config PWM_BFIN
33 tristate "Blackfin PWM support" 41 tristate "Blackfin PWM support"
34 depends on BFIN_GPTIMERS 42 depends on BFIN_GPTIMERS
@@ -47,6 +55,16 @@ config PWM_IMX
47 To compile this driver as a module, choose M here: the module 55 To compile this driver as a module, choose M here: the module
48 will be called pwm-imx. 56 will be called pwm-imx.
49 57
58config PWM_JZ4740
59 tristate "Ingenic JZ4740 PWM support"
60 depends on MACH_JZ4740
61 help
62 Generic PWM framework driver for Ingenic JZ4740 based
63 machines.
64
65 To compile this driver as a module, choose M here: the module
66 will be called pwm-jz4740.
67
50config PWM_LPC32XX 68config PWM_LPC32XX
51 tristate "LPC32XX PWM support" 69 tristate "LPC32XX PWM support"
52 depends on ARCH_LPC32XX 70 depends on ARCH_LPC32XX
@@ -67,6 +85,15 @@ config PWM_MXS
67 To compile this driver as a module, choose M here: the module 85 To compile this driver as a module, choose M here: the module
68 will be called pwm-mxs. 86 will be called pwm-mxs.
69 87
88config PWM_PUV3
89 tristate "PKUnity NetBook-0916 PWM support"
90 depends on ARCH_PUV3
91 help
92 Generic PWM framework driver for PKUnity NetBook-0916.
93
94 To compile this driver as a module, choose M here: the module
95 will be called pwm-puv3.
96
70config PWM_PXA 97config PWM_PXA
71 tristate "PXA PWM support" 98 tristate "PXA PWM support"
72 depends on ARCH_PXA 99 depends on ARCH_PXA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 78f123dca30d..acfe4821c58b 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,8 +1,11 @@
1obj-$(CONFIG_PWM) += core.o 1obj-$(CONFIG_PWM) += core.o
2obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
2obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 3obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
3obj-$(CONFIG_PWM_IMX) += pwm-imx.o 4obj-$(CONFIG_PWM_IMX) += pwm-imx.o
5obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
4obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o 6obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
5obj-$(CONFIG_PWM_MXS) += pwm-mxs.o 7obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
8obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
6obj-$(CONFIG_PWM_PXA) += pwm-pxa.o 9obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
7obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o 10obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
8obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o 11obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c6e05078d3ad..f5acdaa52707 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -371,7 +371,7 @@ EXPORT_SYMBOL_GPL(pwm_free);
371 */ 371 */
372int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) 372int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
373{ 373{
374 if (!pwm || period_ns == 0 || duty_ns > period_ns) 374 if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
375 return -EINVAL; 375 return -EINVAL;
376 376
377 return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns); 377 return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
@@ -379,6 +379,28 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
379EXPORT_SYMBOL_GPL(pwm_config); 379EXPORT_SYMBOL_GPL(pwm_config);
380 380
381/** 381/**
382 * pwm_set_polarity() - configure the polarity of a PWM signal
383 * @pwm: PWM device
384 * @polarity: new polarity of the PWM signal
385 *
386 * Note that the polarity cannot be configured while the PWM device is enabled
387 */
388int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
389{
390 if (!pwm || !pwm->chip->ops)
391 return -EINVAL;
392
393 if (!pwm->chip->ops->set_polarity)
394 return -ENOSYS;
395
396 if (test_bit(PWMF_ENABLED, &pwm->flags))
397 return -EBUSY;
398
399 return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
400}
401EXPORT_SYMBOL_GPL(pwm_set_polarity);
402
403/**
382 * pwm_enable() - start a PWM output toggling 404 * pwm_enable() - start a PWM output toggling
383 * @pwm: PWM device 405 * @pwm: PWM device
384 */ 406 */
@@ -624,6 +646,64 @@ out:
624} 646}
625EXPORT_SYMBOL_GPL(pwm_put); 647EXPORT_SYMBOL_GPL(pwm_put);
626 648
649static void devm_pwm_release(struct device *dev, void *res)
650{
651 pwm_put(*(struct pwm_device **)res);
652}
653
654/**
655 * devm_pwm_get() - resource managed pwm_get()
656 * @dev: device for PWM consumer
657 * @con_id: consumer name
658 *
659 * This function performs like pwm_get() but the acquired PWM device will
660 * automatically be released on driver detach.
661 */
662struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
663{
664 struct pwm_device **ptr, *pwm;
665
666 ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL);
667 if (!ptr)
668 return ERR_PTR(-ENOMEM);
669
670 pwm = pwm_get(dev, con_id);
671 if (!IS_ERR(pwm)) {
672 *ptr = pwm;
673 devres_add(dev, ptr);
674 } else {
675 devres_free(ptr);
676 }
677
678 return pwm;
679}
680EXPORT_SYMBOL_GPL(devm_pwm_get);
681
682static int devm_pwm_match(struct device *dev, void *res, void *data)
683{
684 struct pwm_device **p = res;
685
686 if (WARN_ON(!p || !*p))
687 return 0;
688
689 return *p == data;
690}
691
692/**
693 * devm_pwm_put() - resource managed pwm_put()
694 * @dev: device for PWM consumer
695 * @pwm: PWM device
696 *
697 * Release a PWM previously allocated using devm_pwm_get(). Calling this
698 * function is usually not needed because devm-allocated resources are
699 * automatically released on driver detach.
700 */
701void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
702{
703 WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm));
704}
705EXPORT_SYMBOL_GPL(devm_pwm_put);
706
627#ifdef CONFIG_DEBUG_FS 707#ifdef CONFIG_DEBUG_FS
628static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) 708static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
629{ 709{
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/pwm/pwm-ab8500.c
index d7a9aa14e5d5..cfb72ca873d1 100644
--- a/drivers/misc/ab8500-pwm.c
+++ b/drivers/pwm/pwm-ab8500.c
@@ -24,16 +24,12 @@
24#define ENABLE_PWM 1 24#define ENABLE_PWM 1
25#define DISABLE_PWM 0 25#define DISABLE_PWM 0
26 26
27struct pwm_device { 27struct ab8500_pwm_chip {
28 struct device *dev; 28 struct pwm_chip chip;
29 struct list_head node;
30 const char *label;
31 unsigned int pwm_id;
32}; 29};
33 30
34static LIST_HEAD(pwm_list); 31static int ab8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
35 32 int duty_ns, int period_ns)
36int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
37{ 33{
38 int ret = 0; 34 int ret = 0;
39 unsigned int higher_val, lower_val; 35 unsigned int higher_val, lower_val;
@@ -50,95 +46,94 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
50 */ 46 */
51 higher_val = ((duty_ns & 0x0300) >> 8); 47 higher_val = ((duty_ns & 0x0300) >> 8);
52 48
53 reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2); 49 reg = AB8500_PWM_OUT_CTRL1_REG + ((chip->base - 1) * 2);
54 50
55 ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC, 51 ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
56 reg, (u8)lower_val); 52 reg, (u8)lower_val);
57 if (ret < 0) 53 if (ret < 0)
58 return ret; 54 return ret;
59 ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC, 55 ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
60 (reg + 1), (u8)higher_val); 56 (reg + 1), (u8)higher_val);
61 57
62 return ret; 58 return ret;
63} 59}
64EXPORT_SYMBOL(pwm_config);
65 60
66int pwm_enable(struct pwm_device *pwm) 61static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
67{ 62{
68 int ret; 63 int ret;
69 64
70 ret = abx500_mask_and_set_register_interruptible(pwm->dev, 65 ret = abx500_mask_and_set_register_interruptible(chip->dev,
71 AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, 66 AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
72 1 << (pwm->pwm_id-1), ENABLE_PWM); 67 1 << (chip->base - 1), ENABLE_PWM);
73 if (ret < 0) 68 if (ret < 0)
74 dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n", 69 dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
75 pwm->label, ret); 70 pwm->label, ret);
76 return ret; 71 return ret;
77} 72}
78EXPORT_SYMBOL(pwm_enable);
79 73
80void pwm_disable(struct pwm_device *pwm) 74static void ab8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
81{ 75{
82 int ret; 76 int ret;
83 77
84 ret = abx500_mask_and_set_register_interruptible(pwm->dev, 78 ret = abx500_mask_and_set_register_interruptible(chip->dev,
85 AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, 79 AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
86 1 << (pwm->pwm_id-1), DISABLE_PWM); 80 1 << (chip->base - 1), DISABLE_PWM);
87 if (ret < 0) 81 if (ret < 0)
88 dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n", 82 dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
89 pwm->label, ret); 83 pwm->label, ret);
90 return; 84 return;
91} 85}
92EXPORT_SYMBOL(pwm_disable);
93
94struct pwm_device *pwm_request(int pwm_id, const char *label)
95{
96 struct pwm_device *pwm;
97
98 list_for_each_entry(pwm, &pwm_list, node) {
99 if (pwm->pwm_id == pwm_id) {
100 pwm->label = label;
101 pwm->pwm_id = pwm_id;
102 return pwm;
103 }
104 }
105
106 return ERR_PTR(-ENOENT);
107}
108EXPORT_SYMBOL(pwm_request);
109 86
110void pwm_free(struct pwm_device *pwm) 87static const struct pwm_ops ab8500_pwm_ops = {
111{ 88 .config = ab8500_pwm_config,
112 pwm_disable(pwm); 89 .enable = ab8500_pwm_enable,
113} 90 .disable = ab8500_pwm_disable,
114EXPORT_SYMBOL(pwm_free); 91};
115 92
116static int __devinit ab8500_pwm_probe(struct platform_device *pdev) 93static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
117{ 94{
118 struct pwm_device *pwm; 95 struct ab8500_pwm_chip *ab8500;
96 int err;
97
119 /* 98 /*
120 * Nothing to be done in probe, this is required to get the 99 * Nothing to be done in probe, this is required to get the
121 * device which is required for ab8500 read and write 100 * device which is required for ab8500 read and write
122 */ 101 */
123 pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); 102 ab8500 = kzalloc(sizeof(*ab8500), GFP_KERNEL);
124 if (pwm == NULL) { 103 if (ab8500 == NULL) {
125 dev_err(&pdev->dev, "failed to allocate memory\n"); 104 dev_err(&pdev->dev, "failed to allocate memory\n");
126 return -ENOMEM; 105 return -ENOMEM;
127 } 106 }
128 pwm->dev = &pdev->dev; 107
129 pwm->pwm_id = pdev->id; 108 ab8500->chip.dev = &pdev->dev;
130 list_add_tail(&pwm->node, &pwm_list); 109 ab8500->chip.ops = &ab8500_pwm_ops;
131 platform_set_drvdata(pdev, pwm); 110 ab8500->chip.base = pdev->id;
132 dev_dbg(pwm->dev, "pwm probe successful\n"); 111 ab8500->chip.npwm = 1;
112
113 err = pwmchip_add(&ab8500->chip);
114 if (err < 0) {
115 kfree(ab8500);
116 return err;
117 }
118
119 dev_dbg(&pdev->dev, "pwm probe successful\n");
120 platform_set_drvdata(pdev, ab8500);
121
133 return 0; 122 return 0;
134} 123}
135 124
136static int __devexit ab8500_pwm_remove(struct platform_device *pdev) 125static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
137{ 126{
138 struct pwm_device *pwm = platform_get_drvdata(pdev); 127 struct ab8500_pwm_chip *ab8500 = platform_get_drvdata(pdev);
139 list_del(&pwm->node); 128 int err;
129
130 err = pwmchip_remove(&ab8500->chip);
131 if (err < 0)
132 return err;
133
140 dev_dbg(&pdev->dev, "pwm driver removed\n"); 134 dev_dbg(&pdev->dev, "pwm driver removed\n");
141 kfree(pwm); 135 kfree(ab8500);
136
142 return 0; 137 return 0;
143} 138}
144 139
@@ -150,19 +145,8 @@ static struct platform_driver ab8500_pwm_driver = {
150 .probe = ab8500_pwm_probe, 145 .probe = ab8500_pwm_probe,
151 .remove = __devexit_p(ab8500_pwm_remove), 146 .remove = __devexit_p(ab8500_pwm_remove),
152}; 147};
148module_platform_driver(ab8500_pwm_driver);
153 149
154static int __init ab8500_pwm_init(void)
155{
156 return platform_driver_register(&ab8500_pwm_driver);
157}
158
159static void __exit ab8500_pwm_exit(void)
160{
161 platform_driver_unregister(&ab8500_pwm_driver);
162}
163
164subsys_initcall(ab8500_pwm_init);
165module_exit(ab8500_pwm_exit);
166MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>"); 150MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>");
167MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver"); 151MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
168MODULE_ALIAS("platform:ab8500-pwm"); 152MODULE_ALIAS("platform:ab8500-pwm");
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c
index d53c4e7941ef..5da8e185e838 100644
--- a/drivers/pwm/pwm-bfin.c
+++ b/drivers/pwm/pwm-bfin.c
@@ -69,9 +69,6 @@ static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
69 unsigned long period, duty; 69 unsigned long period, duty;
70 unsigned long long val; 70 unsigned long long val;
71 71
72 if (duty_ns < 0 || duty_ns > period_ns)
73 return -EINVAL;
74
75 val = (unsigned long long)get_sclk() * period_ns; 72 val = (unsigned long long)get_sclk() * period_ns;
76 do_div(val, NSEC_PER_SEC); 73 do_div(val, NSEC_PER_SEC);
77 period = val; 74 period = val;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 2a0b35333972..8a5d3ae2946a 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -16,8 +16,7 @@
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/io.h> 17#include <linux/io.h>
18#include <linux/pwm.h> 18#include <linux/pwm.h>
19#include <mach/hardware.h> 19#include <linux/of_device.h>
20
21 20
22/* i.MX1 and i.MX21 share the same PWM function block: */ 21/* i.MX1 and i.MX21 share the same PWM function block: */
23 22
@@ -25,6 +24,7 @@
25#define MX1_PWMS 0x04 /* PWM Sample Register */ 24#define MX1_PWMS 0x04 /* PWM Sample Register */
26#define MX1_PWMP 0x08 /* PWM Period Register */ 25#define MX1_PWMP 0x08 /* PWM Period Register */
27 26
27#define MX1_PWMC_EN (1 << 4)
28 28
29/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ 29/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
30 30
@@ -40,110 +40,165 @@
40#define MX3_PWMCR_EN (1 << 0) 40#define MX3_PWMCR_EN (1 << 0)
41 41
42struct imx_chip { 42struct imx_chip {
43 struct clk *clk; 43 struct clk *clk_per;
44 struct clk *clk_ipg;
44 45
45 int clk_enabled; 46 int enabled;
46 void __iomem *mmio_base; 47 void __iomem *mmio_base;
47 48
48 struct pwm_chip chip; 49 struct pwm_chip chip;
50
51 int (*config)(struct pwm_chip *chip,
52 struct pwm_device *pwm, int duty_ns, int period_ns);
53 void (*set_enable)(struct pwm_chip *chip, bool enable);
49}; 54};
50 55
51#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) 56#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip)
52 57
53static int imx_pwm_config(struct pwm_chip *chip, 58static int imx_pwm_config_v1(struct pwm_chip *chip,
54 struct pwm_device *pwm, int duty_ns, int period_ns) 59 struct pwm_device *pwm, int duty_ns, int period_ns)
55{ 60{
56 struct imx_chip *imx = to_imx_chip(chip); 61 struct imx_chip *imx = to_imx_chip(chip);
57 62
58 if (!(cpu_is_mx1() || cpu_is_mx21())) { 63 /*
59 unsigned long long c; 64 * The PWM subsystem allows for exact frequencies. However,
60 unsigned long period_cycles, duty_cycles, prescale; 65 * I cannot connect a scope on my device to the PWM line and
61 u32 cr; 66 * thus cannot provide the program the PWM controller
62 67 * exactly. Instead, I'm relying on the fact that the
63 c = clk_get_rate(imx->clk); 68 * Bootloader (u-boot or WinCE+haret) has programmed the PWM
64 c = c * period_ns; 69 * function group already. So I'll just modify the PWM sample
65 do_div(c, 1000000000); 70 * register to follow the ratio of duty_ns vs. period_ns
66 period_cycles = c; 71 * accordingly.
67 72 *
68 prescale = period_cycles / 0x10000 + 1; 73 * This is good enough for programming the brightness of
69 74 * the LCD backlight.
70 period_cycles /= prescale; 75 *
71 c = (unsigned long long)period_cycles * duty_ns; 76 * The real implementation would divide PERCLK[0] first by
72 do_div(c, period_ns); 77 * both the prescaler (/1 .. /128) and then by CLKSEL
73 duty_cycles = c; 78 * (/2 .. /16).
74 79 */
75 /* 80 u32 max = readl(imx->mmio_base + MX1_PWMP);
76 * according to imx pwm RM, the real period value should be 81 u32 p = max * duty_ns / period_ns;
77 * PERIOD value in PWMPR plus 2. 82 writel(max - p, imx->mmio_base + MX1_PWMS);
78 */
79 if (period_cycles > 2)
80 period_cycles -= 2;
81 else
82 period_cycles = 0;
83
84 writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
85 writel(period_cycles, imx->mmio_base + MX3_PWMPR);
86
87 cr = MX3_PWMCR_PRESCALER(prescale) |
88 MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
89 MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
90
91 if (cpu_is_mx25())
92 cr |= MX3_PWMCR_CLKSRC_IPG;
93 else
94 cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
95
96 writel(cr, imx->mmio_base + MX3_PWMCR);
97 } else if (cpu_is_mx1() || cpu_is_mx21()) {
98 /* The PWM subsystem allows for exact frequencies. However,
99 * I cannot connect a scope on my device to the PWM line and
100 * thus cannot provide the program the PWM controller
101 * exactly. Instead, I'm relying on the fact that the
102 * Bootloader (u-boot or WinCE+haret) has programmed the PWM
103 * function group already. So I'll just modify the PWM sample
104 * register to follow the ratio of duty_ns vs. period_ns
105 * accordingly.
106 *
107 * This is good enough for programming the brightness of
108 * the LCD backlight.
109 *
110 * The real implementation would divide PERCLK[0] first by
111 * both the prescaler (/1 .. /128) and then by CLKSEL
112 * (/2 .. /16).
113 */
114 u32 max = readl(imx->mmio_base + MX1_PWMP);
115 u32 p = max * duty_ns / period_ns;
116 writel(max - p, imx->mmio_base + MX1_PWMS);
117 } else {
118 BUG();
119 }
120 83
121 return 0; 84 return 0;
122} 85}
123 86
87static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
88{
89 struct imx_chip *imx = to_imx_chip(chip);
90 u32 val;
91
92 val = readl(imx->mmio_base + MX1_PWMC);
93
94 if (enable)
95 val |= MX1_PWMC_EN;
96 else
97 val &= ~MX1_PWMC_EN;
98
99 writel(val, imx->mmio_base + MX1_PWMC);
100}
101
102static int imx_pwm_config_v2(struct pwm_chip *chip,
103 struct pwm_device *pwm, int duty_ns, int period_ns)
104{
105 struct imx_chip *imx = to_imx_chip(chip);
106 unsigned long long c;
107 unsigned long period_cycles, duty_cycles, prescale;
108 u32 cr;
109
110 c = clk_get_rate(imx->clk_per);
111 c = c * period_ns;
112 do_div(c, 1000000000);
113 period_cycles = c;
114
115 prescale = period_cycles / 0x10000 + 1;
116
117 period_cycles /= prescale;
118 c = (unsigned long long)period_cycles * duty_ns;
119 do_div(c, period_ns);
120 duty_cycles = c;
121
122 /*
123 * according to imx pwm RM, the real period value should be
124 * PERIOD value in PWMPR plus 2.
125 */
126 if (period_cycles > 2)
127 period_cycles -= 2;
128 else
129 period_cycles = 0;
130
131 writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
132 writel(period_cycles, imx->mmio_base + MX3_PWMPR);
133
134 cr = MX3_PWMCR_PRESCALER(prescale) |
135 MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
136 MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH;
137
138 if (imx->enabled)
139 cr |= MX3_PWMCR_EN;
140
141 writel(cr, imx->mmio_base + MX3_PWMCR);
142
143 return 0;
144}
145
146static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
147{
148 struct imx_chip *imx = to_imx_chip(chip);
149 u32 val;
150
151 val = readl(imx->mmio_base + MX3_PWMCR);
152
153 if (enable)
154 val |= MX3_PWMCR_EN;
155 else
156 val &= ~MX3_PWMCR_EN;
157
158 writel(val, imx->mmio_base + MX3_PWMCR);
159}
160
161static int imx_pwm_config(struct pwm_chip *chip,
162 struct pwm_device *pwm, int duty_ns, int period_ns)
163{
164 struct imx_chip *imx = to_imx_chip(chip);
165 int ret;
166
167 ret = clk_prepare_enable(imx->clk_ipg);
168 if (ret)
169 return ret;
170
171 ret = imx->config(chip, pwm, duty_ns, period_ns);
172
173 clk_disable_unprepare(imx->clk_ipg);
174
175 return ret;
176}
177
124static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 178static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
125{ 179{
126 struct imx_chip *imx = to_imx_chip(chip); 180 struct imx_chip *imx = to_imx_chip(chip);
127 int rc = 0; 181 int ret;
128 182
129 if (!imx->clk_enabled) { 183 ret = clk_prepare_enable(imx->clk_per);
130 rc = clk_prepare_enable(imx->clk); 184 if (ret)
131 if (!rc) 185 return ret;
132 imx->clk_enabled = 1; 186
133 } 187 imx->set_enable(chip, true);
134 return rc; 188
189 imx->enabled = 1;
190
191 return 0;
135} 192}
136 193
137static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 194static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
138{ 195{
139 struct imx_chip *imx = to_imx_chip(chip); 196 struct imx_chip *imx = to_imx_chip(chip);
140 197
141 writel(0, imx->mmio_base + MX3_PWMCR); 198 imx->set_enable(chip, false);
142 199
143 if (imx->clk_enabled) { 200 clk_disable_unprepare(imx->clk_per);
144 clk_disable_unprepare(imx->clk); 201 imx->enabled = 0;
145 imx->clk_enabled = 0;
146 }
147} 202}
148 203
149static struct pwm_ops imx_pwm_ops = { 204static struct pwm_ops imx_pwm_ops = {
@@ -153,30 +208,66 @@ static struct pwm_ops imx_pwm_ops = {
153 .owner = THIS_MODULE, 208 .owner = THIS_MODULE,
154}; 209};
155 210
211struct imx_pwm_data {
212 int (*config)(struct pwm_chip *chip,
213 struct pwm_device *pwm, int duty_ns, int period_ns);
214 void (*set_enable)(struct pwm_chip *chip, bool enable);
215};
216
217static struct imx_pwm_data imx_pwm_data_v1 = {
218 .config = imx_pwm_config_v1,
219 .set_enable = imx_pwm_set_enable_v1,
220};
221
222static struct imx_pwm_data imx_pwm_data_v2 = {
223 .config = imx_pwm_config_v2,
224 .set_enable = imx_pwm_set_enable_v2,
225};
226
227static const struct of_device_id imx_pwm_dt_ids[] = {
228 { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, },
229 { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, },
230 { /* sentinel */ }
231};
232MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids);
233
156static int __devinit imx_pwm_probe(struct platform_device *pdev) 234static int __devinit imx_pwm_probe(struct platform_device *pdev)
157{ 235{
236 const struct of_device_id *of_id =
237 of_match_device(imx_pwm_dt_ids, &pdev->dev);
238 struct imx_pwm_data *data;
158 struct imx_chip *imx; 239 struct imx_chip *imx;
159 struct resource *r; 240 struct resource *r;
160 int ret = 0; 241 int ret = 0;
161 242
243 if (!of_id)
244 return -ENODEV;
245
162 imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); 246 imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
163 if (imx == NULL) { 247 if (imx == NULL) {
164 dev_err(&pdev->dev, "failed to allocate memory\n"); 248 dev_err(&pdev->dev, "failed to allocate memory\n");
165 return -ENOMEM; 249 return -ENOMEM;
166 } 250 }
167 251
168 imx->clk = devm_clk_get(&pdev->dev, "pwm"); 252 imx->clk_per = devm_clk_get(&pdev->dev, "per");
253 if (IS_ERR(imx->clk_per)) {
254 dev_err(&pdev->dev, "getting per clock failed with %ld\n",
255 PTR_ERR(imx->clk_per));
256 return PTR_ERR(imx->clk_per);
257 }
169 258
170 if (IS_ERR(imx->clk)) 259 imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
171 return PTR_ERR(imx->clk); 260 if (IS_ERR(imx->clk_ipg)) {
261 dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
262 PTR_ERR(imx->clk_ipg));
263 return PTR_ERR(imx->clk_ipg);
264 }
172 265
173 imx->chip.ops = &imx_pwm_ops; 266 imx->chip.ops = &imx_pwm_ops;
174 imx->chip.dev = &pdev->dev; 267 imx->chip.dev = &pdev->dev;
175 imx->chip.base = -1; 268 imx->chip.base = -1;
176 imx->chip.npwm = 1; 269 imx->chip.npwm = 1;
177 270
178 imx->clk_enabled = 0;
179
180 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 271 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
181 if (r == NULL) { 272 if (r == NULL) {
182 dev_err(&pdev->dev, "no memory resource defined\n"); 273 dev_err(&pdev->dev, "no memory resource defined\n");
@@ -187,6 +278,10 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev)
187 if (imx->mmio_base == NULL) 278 if (imx->mmio_base == NULL)
188 return -EADDRNOTAVAIL; 279 return -EADDRNOTAVAIL;
189 280
281 data = of_id->data;
282 imx->config = data->config;
283 imx->set_enable = data->set_enable;
284
190 ret = pwmchip_add(&imx->chip); 285 ret = pwmchip_add(&imx->chip);
191 if (ret < 0) 286 if (ret < 0)
192 return ret; 287 return ret;
@@ -208,23 +303,14 @@ static int __devexit imx_pwm_remove(struct platform_device *pdev)
208 303
209static struct platform_driver imx_pwm_driver = { 304static struct platform_driver imx_pwm_driver = {
210 .driver = { 305 .driver = {
211 .name = "mxc_pwm", 306 .name = "imx-pwm",
307 .of_match_table = of_match_ptr(imx_pwm_dt_ids),
212 }, 308 },
213 .probe = imx_pwm_probe, 309 .probe = imx_pwm_probe,
214 .remove = __devexit_p(imx_pwm_remove), 310 .remove = __devexit_p(imx_pwm_remove),
215}; 311};
216 312
217static int __init imx_pwm_init(void) 313module_platform_driver(imx_pwm_driver);
218{
219 return platform_driver_register(&imx_pwm_driver);
220}
221arch_initcall(imx_pwm_init);
222
223static void __exit imx_pwm_exit(void)
224{
225 platform_driver_unregister(&imx_pwm_driver);
226}
227module_exit(imx_pwm_exit);
228 314
229MODULE_LICENSE("GPL v2"); 315MODULE_LICENSE("GPL v2");
230MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 316MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
new file mode 100644
index 000000000000..10250fcefb98
--- /dev/null
+++ b/drivers/pwm/pwm-jz4740.c
@@ -0,0 +1,221 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform PWM support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/clk.h>
17#include <linux/err.h>
18#include <linux/gpio.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/pwm.h>
23
24#include <asm/mach-jz4740/gpio.h>
25#include <asm/mach-jz4740/timer.h>
26
27#define NUM_PWM 8
28
29static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
30 JZ_GPIO_PWM0,
31 JZ_GPIO_PWM1,
32 JZ_GPIO_PWM2,
33 JZ_GPIO_PWM3,
34 JZ_GPIO_PWM4,
35 JZ_GPIO_PWM5,
36 JZ_GPIO_PWM6,
37 JZ_GPIO_PWM7,
38};
39
40struct jz4740_pwm_chip {
41 struct pwm_chip chip;
42 struct clk *clk;
43};
44
45static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
46{
47 return container_of(chip, struct jz4740_pwm_chip, chip);
48}
49
50static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
51{
52 unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
53 int ret;
54
55 /*
56 * Timers 0 and 1 are used for system tasks, so they are unavailable
57 * for use as PWMs.
58 */
59 if (pwm->hwpwm < 2)
60 return -EBUSY;
61
62 ret = gpio_request(gpio, pwm->label);
63 if (ret) {
64 dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
65 gpio, ret);
66 return ret;
67 }
68
69 jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
70
71 jz4740_timer_start(pwm->hwpwm);
72
73 return 0;
74}
75
76static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
77{
78 unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
79
80 jz4740_timer_set_ctrl(pwm->hwpwm, 0);
81
82 jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
83 gpio_free(gpio);
84
85 jz4740_timer_stop(pwm->hwpwm);
86}
87
88static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
89{
90 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
91
92 ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
93 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
94 jz4740_timer_enable(pwm->hwpwm);
95
96 return 0;
97}
98
99static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
100{
101 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
102
103 ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
104 jz4740_timer_disable(pwm->hwpwm);
105 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
106}
107
108static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
109 int duty_ns, int period_ns)
110{
111 struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
112 unsigned long long tmp;
113 unsigned long period, duty;
114 unsigned int prescaler = 0;
115 uint16_t ctrl;
116 bool is_enabled;
117
118 tmp = (unsigned long long)clk_get_rate(jz4740->clk) * period_ns;
119 do_div(tmp, 1000000000);
120 period = tmp;
121
122 while (period > 0xffff && prescaler < 6) {
123 period >>= 2;
124 ++prescaler;
125 }
126
127 if (prescaler == 6)
128 return -EINVAL;
129
130 tmp = (unsigned long long)period * duty_ns;
131 do_div(tmp, period_ns);
132 duty = period - tmp;
133
134 if (duty >= period)
135 duty = period - 1;
136
137 is_enabled = jz4740_timer_is_enabled(pwm->hwpwm);
138 if (is_enabled)
139 jz4740_pwm_disable(chip, pwm);
140
141 jz4740_timer_set_count(pwm->hwpwm, 0);
142 jz4740_timer_set_duty(pwm->hwpwm, duty);
143 jz4740_timer_set_period(pwm->hwpwm, period);
144
145 ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
146 JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
147
148 jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
149
150 if (is_enabled)
151 jz4740_pwm_enable(chip, pwm);
152
153 return 0;
154}
155
156static const struct pwm_ops jz4740_pwm_ops = {
157 .request = jz4740_pwm_request,
158 .free = jz4740_pwm_free,
159 .config = jz4740_pwm_config,
160 .enable = jz4740_pwm_enable,
161 .disable = jz4740_pwm_disable,
162 .owner = THIS_MODULE,
163};
164
165static int __devinit jz4740_pwm_probe(struct platform_device *pdev)
166{
167 struct jz4740_pwm_chip *jz4740;
168 int ret;
169
170 jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL);
171 if (!jz4740)
172 return -ENOMEM;
173
174 jz4740->clk = clk_get(NULL, "ext");
175 if (IS_ERR(jz4740->clk))
176 return PTR_ERR(jz4740->clk);
177
178 jz4740->chip.dev = &pdev->dev;
179 jz4740->chip.ops = &jz4740_pwm_ops;
180 jz4740->chip.npwm = NUM_PWM;
181 jz4740->chip.base = -1;
182
183 ret = pwmchip_add(&jz4740->chip);
184 if (ret < 0) {
185 clk_put(jz4740->clk);
186 return ret;
187 }
188
189 platform_set_drvdata(pdev, jz4740);
190
191 return 0;
192}
193
194static int __devexit jz4740_pwm_remove(struct platform_device *pdev)
195{
196 struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev);
197 int ret;
198
199 ret = pwmchip_remove(&jz4740->chip);
200 if (ret < 0)
201 return ret;
202
203 clk_put(jz4740->clk);
204
205 return 0;
206}
207
208static struct platform_driver jz4740_pwm_driver = {
209 .driver = {
210 .name = "jz4740-pwm",
211 .owner = THIS_MODULE,
212 },
213 .probe = jz4740_pwm_probe,
214 .remove = __devexit_p(jz4740_pwm_remove),
215};
216module_platform_driver(jz4740_pwm_driver);
217
218MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
219MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver");
220MODULE_ALIAS("platform:jz4740-pwm");
221MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
new file mode 100644
index 000000000000..2a93f37c46ad
--- /dev/null
+++ b/drivers/pwm/pwm-puv3.c
@@ -0,0 +1,161 @@
1/*
2 * linux/arch/unicore32/kernel/pwm.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18#include <linux/err.h>
19#include <linux/clk.h>
20#include <linux/io.h>
21#include <linux/pwm.h>
22
23#include <asm/div64.h>
24#include <mach/hardware.h>
25
26struct puv3_pwm_chip {
27 struct pwm_chip chip;
28 void __iomem *base;
29 struct clk *clk;
30 bool enabled;
31};
32
33static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip)
34{
35 return container_of(chip, struct puv3_pwm_chip, chip);
36}
37
38/*
39 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
40 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
41 */
42static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
43 int duty_ns, int period_ns)
44{
45 unsigned long period_cycles, prescale, pv, dc;
46 struct puv3_pwm_chip *puv3 = to_puv3(chip);
47 unsigned long long c;
48
49 c = clk_get_rate(puv3->clk);
50 c = c * period_ns;
51 do_div(c, 1000000000);
52 period_cycles = c;
53
54 if (period_cycles < 1)
55 period_cycles = 1;
56
57 prescale = (period_cycles - 1) / 1024;
58 pv = period_cycles / (prescale + 1) - 1;
59
60 if (prescale > 63)
61 return -EINVAL;
62
63 if (duty_ns == period_ns)
64 dc = OST_PWMDCCR_FDCYCLE;
65 else
66 dc = (pv + 1) * duty_ns / period_ns;
67
68 /*
69 * NOTE: the clock to PWM has to be enabled first
70 * before writing to the registers
71 */
72 clk_prepare_enable(puv3->clk);
73
74 writel(prescale, puv3->base + OST_PWM_PWCR);
75 writel(pv - dc, puv3->base + OST_PWM_DCCR);
76 writel(pv, puv3->base + OST_PWM_PCR);
77
78 clk_disable_unprepare(puv3->clk);
79
80 return 0;
81}
82
83static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
84{
85 struct puv3_pwm_chip *puv3 = to_puv3(chip);
86
87 return clk_prepare_enable(puv3->clk);
88}
89
90static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
91{
92 struct puv3_pwm_chip *puv3 = to_puv3(chip);
93
94 clk_disable_unprepare(puv3->clk);
95}
96
97static const struct pwm_ops puv3_pwm_ops = {
98 .config = puv3_pwm_config,
99 .enable = puv3_pwm_enable,
100 .disable = puv3_pwm_disable,
101 .owner = THIS_MODULE,
102};
103
104static int __devinit pwm_probe(struct platform_device *pdev)
105{
106 struct puv3_pwm_chip *puv3;
107 struct resource *r;
108 int ret;
109
110 puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL);
111 if (puv3 == NULL) {
112 dev_err(&pdev->dev, "failed to allocate memory\n");
113 return -ENOMEM;
114 }
115
116 puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK");
117 if (IS_ERR(puv3->clk))
118 return PTR_ERR(puv3->clk);
119
120 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
121 if (r == NULL) {
122 dev_err(&pdev->dev, "no memory resource defined\n");
123 return -ENODEV;
124 }
125
126 puv3->base = devm_request_and_ioremap(&pdev->dev, r);
127 if (puv3->base == NULL)
128 return -EADDRNOTAVAIL;
129
130 puv3->chip.dev = &pdev->dev;
131 puv3->chip.ops = &puv3_pwm_ops;
132 puv3->chip.base = -1;
133 puv3->chip.npwm = 1;
134
135 ret = pwmchip_add(&puv3->chip);
136 if (ret < 0) {
137 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
138 return ret;
139 }
140
141 platform_set_drvdata(pdev, puv3);
142 return 0;
143}
144
145static int __devexit pwm_remove(struct platform_device *pdev)
146{
147 struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev);
148
149 return pwmchip_remove(&puv3->chip);
150}
151
152static struct platform_driver puv3_pwm_driver = {
153 .driver = {
154 .name = "PKUnity-v3-PWM",
155 },
156 .probe = pwm_probe,
157 .remove = __devexit_p(pwm_remove),
158};
159module_platform_driver(puv3_pwm_driver);
160
161MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index bd5867a1c700..260c3a88564d 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -70,9 +70,6 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
70 unsigned long offset; 70 unsigned long offset;
71 int rc; 71 int rc;
72 72
73 if (period_ns == 0 || duty_ns > period_ns)
74 return -EINVAL;
75
76 offset = pwm->hwpwm ? 0x10 : 0; 73 offset = pwm->hwpwm ? 0x10 : 0;
77 74
78 c = clk_get_rate(pc->clk); 75 c = clk_get_rate(pc->clk);
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index e5187c0ade9f..023a3bee76e7 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -126,9 +126,6 @@ static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
126 if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) 126 if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ)
127 return -ERANGE; 127 return -ERANGE;
128 128
129 if (duty_ns > period_ns)
130 return -EINVAL;
131
132 if (period_ns == s3c->period_ns && 129 if (period_ns == s3c->period_ns &&
133 duty_ns == s3c->duty_ns) 130 duty_ns == s3c->duty_ns)
134 return 0; 131 return 0;
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 4b6688909fee..d6d4cf05565e 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -32,6 +32,7 @@
32#define CAP3 0x10 32#define CAP3 0x10
33#define CAP4 0x14 33#define CAP4 0x14
34#define ECCTL2 0x2A 34#define ECCTL2 0x2A
35#define ECCTL2_APWM_POL_LOW BIT(10)
35#define ECCTL2_APWM_MODE BIT(9) 36#define ECCTL2_APWM_MODE BIT(9)
36#define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) 37#define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6))
37#define ECCTL2_TSCTR_FREERUN BIT(4) 38#define ECCTL2_TSCTR_FREERUN BIT(4)
@@ -59,7 +60,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
59 unsigned long period_cycles, duty_cycles; 60 unsigned long period_cycles, duty_cycles;
60 unsigned int reg_val; 61 unsigned int reg_val;
61 62
62 if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) 63 if (period_ns > NSEC_PER_SEC)
63 return -ERANGE; 64 return -ERANGE;
64 65
65 c = pc->clk_rate; 66 c = pc->clk_rate;
@@ -111,6 +112,26 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
111 return 0; 112 return 0;
112} 113}
113 114
115static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
116 enum pwm_polarity polarity)
117{
118 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
119 unsigned short reg_val;
120
121 pm_runtime_get_sync(pc->chip.dev);
122 reg_val = readw(pc->mmio_base + ECCTL2);
123 if (polarity == PWM_POLARITY_INVERSED)
124 /* Duty cycle defines LOW period of PWM */
125 reg_val |= ECCTL2_APWM_POL_LOW;
126 else
127 /* Duty cycle defines HIGH period of PWM */
128 reg_val &= ~ECCTL2_APWM_POL_LOW;
129
130 writew(reg_val, pc->mmio_base + ECCTL2);
131 pm_runtime_put_sync(pc->chip.dev);
132 return 0;
133}
134
114static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 135static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
115{ 136{
116 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 137 struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
@@ -157,6 +178,7 @@ static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
157static const struct pwm_ops ecap_pwm_ops = { 178static const struct pwm_ops ecap_pwm_ops = {
158 .free = ecap_pwm_free, 179 .free = ecap_pwm_free,
159 .config = ecap_pwm_config, 180 .config = ecap_pwm_config,
181 .set_polarity = ecap_pwm_set_polarity,
160 .enable = ecap_pwm_enable, 182 .enable = ecap_pwm_enable,
161 .disable = ecap_pwm_disable, 183 .disable = ecap_pwm_disable,
162 .owner = THIS_MODULE, 184 .owner = THIS_MODULE,
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index b1996bcd5b78..d3c1dff0a0dc 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -81,6 +81,15 @@
81#define AQCTL_ZRO_FRCHIGH BIT(1) 81#define AQCTL_ZRO_FRCHIGH BIT(1)
82#define AQCTL_ZRO_FRCTOGGLE (BIT(1) | BIT(0)) 82#define AQCTL_ZRO_FRCTOGGLE (BIT(1) | BIT(0))
83 83
84#define AQCTL_CHANA_POLNORMAL (AQCTL_CAU_FRCLOW | AQCTL_PRD_FRCHIGH | \
85 AQCTL_ZRO_FRCHIGH)
86#define AQCTL_CHANA_POLINVERSED (AQCTL_CAU_FRCHIGH | AQCTL_PRD_FRCLOW | \
87 AQCTL_ZRO_FRCLOW)
88#define AQCTL_CHANB_POLNORMAL (AQCTL_CBU_FRCLOW | AQCTL_PRD_FRCHIGH | \
89 AQCTL_ZRO_FRCHIGH)
90#define AQCTL_CHANB_POLINVERSED (AQCTL_CBU_FRCHIGH | AQCTL_PRD_FRCLOW | \
91 AQCTL_ZRO_FRCLOW)
92
84#define AQSFRC_RLDCSF_MASK (BIT(7) | BIT(6)) 93#define AQSFRC_RLDCSF_MASK (BIT(7) | BIT(6))
85#define AQSFRC_RLDCSF_ZRO 0 94#define AQSFRC_RLDCSF_ZRO 0
86#define AQSFRC_RLDCSF_PRD BIT(6) 95#define AQSFRC_RLDCSF_PRD BIT(6)
@@ -105,6 +114,7 @@ struct ehrpwm_pwm_chip {
105 unsigned int clk_rate; 114 unsigned int clk_rate;
106 void __iomem *mmio_base; 115 void __iomem *mmio_base;
107 unsigned long period_cycles[NUM_PWM_CHANNEL]; 116 unsigned long period_cycles[NUM_PWM_CHANNEL];
117 enum pwm_polarity polarity[NUM_PWM_CHANNEL];
108}; 118};
109 119
110static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) 120static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -165,39 +175,37 @@ static int set_prescale_div(unsigned long rqst_prescaler,
165 return 1; 175 return 1;
166} 176}
167 177
168static void configure_chans(struct ehrpwm_pwm_chip *pc, int chan, 178static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan)
169 unsigned long duty_cycles)
170{ 179{
171 int cmp_reg, aqctl_reg; 180 int aqctl_reg;
172 unsigned short aqctl_val, aqctl_mask; 181 unsigned short aqctl_val, aqctl_mask;
173 182
174 /* 183 /*
175 * Channels can be configured from action qualifier module. 184 * Configure PWM output to HIGH/LOW level on counter
176 * Channel 0 configured with compare A register and for 185 * reaches compare register value and LOW/HIGH level
177 * up-counter mode. 186 * on counter value reaches period register value and
178 * Channel 1 configured with compare B register and for 187 * zero value on counter
179 * up-counter mode.
180 */ 188 */
181 if (chan == 1) { 189 if (chan == 1) {
182 aqctl_reg = AQCTLB; 190 aqctl_reg = AQCTLB;
183 cmp_reg = CMPB;
184 /* Configure PWM Low from compare B value */
185 aqctl_val = AQCTL_CBU_FRCLOW;
186 aqctl_mask = AQCTL_CBU_MASK; 191 aqctl_mask = AQCTL_CBU_MASK;
192
193 if (pc->polarity[chan] == PWM_POLARITY_INVERSED)
194 aqctl_val = AQCTL_CHANB_POLINVERSED;
195 else
196 aqctl_val = AQCTL_CHANB_POLNORMAL;
187 } else { 197 } else {
188 cmp_reg = CMPA;
189 aqctl_reg = AQCTLA; 198 aqctl_reg = AQCTLA;
190 /* Configure PWM Low from compare A value*/
191 aqctl_val = AQCTL_CAU_FRCLOW;
192 aqctl_mask = AQCTL_CAU_MASK; 199 aqctl_mask = AQCTL_CAU_MASK;
200
201 if (pc->polarity[chan] == PWM_POLARITY_INVERSED)
202 aqctl_val = AQCTL_CHANA_POLINVERSED;
203 else
204 aqctl_val = AQCTL_CHANA_POLNORMAL;
193 } 205 }
194 206
195 /* Configure PWM High from period value and zero value */
196 aqctl_val |= AQCTL_PRD_FRCHIGH | AQCTL_ZRO_FRCHIGH;
197 aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK; 207 aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK;
198 ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val); 208 ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val);
199
200 ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);
201} 209}
202 210
203/* 211/*
@@ -211,9 +219,9 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
211 unsigned long long c; 219 unsigned long long c;
212 unsigned long period_cycles, duty_cycles; 220 unsigned long period_cycles, duty_cycles;
213 unsigned short ps_divval, tb_divval; 221 unsigned short ps_divval, tb_divval;
214 int i; 222 int i, cmp_reg;
215 223
216 if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) 224 if (period_ns > NSEC_PER_SEC)
217 return -ERANGE; 225 return -ERANGE;
218 226
219 c = pc->clk_rate; 227 c = pc->clk_rate;
@@ -278,12 +286,29 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
278 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK, 286 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK,
279 TBCTL_CTRMODE_UP); 287 TBCTL_CTRMODE_UP);
280 288
281 /* Configure the channel for duty cycle */ 289 if (pwm->hwpwm == 1)
282 configure_chans(pc, pwm->hwpwm, duty_cycles); 290 /* Channel 1 configured with compare B register */
291 cmp_reg = CMPB;
292 else
293 /* Channel 0 configured with compare A register */
294 cmp_reg = CMPA;
295
296 ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);
297
283 pm_runtime_put_sync(chip->dev); 298 pm_runtime_put_sync(chip->dev);
284 return 0; 299 return 0;
285} 300}
286 301
302static int ehrpwm_pwm_set_polarity(struct pwm_chip *chip,
303 struct pwm_device *pwm, enum pwm_polarity polarity)
304{
305 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
306
307 /* Configuration of polarity in hardware delayed, do at enable */
308 pc->polarity[pwm->hwpwm] = polarity;
309 return 0;
310}
311
287static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 312static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
288{ 313{
289 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); 314 struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
@@ -307,6 +332,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
307 332
308 ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); 333 ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
309 334
335 /* Channels polarity can be configured from action qualifier module */
336 configure_polarity(pc, pwm->hwpwm);
337
310 /* Enable time counter for free_run */ 338 /* Enable time counter for free_run */
311 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); 339 ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
312 return 0; 340 return 0;
@@ -358,6 +386,7 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
358static const struct pwm_ops ehrpwm_pwm_ops = { 386static const struct pwm_ops ehrpwm_pwm_ops = {
359 .free = ehrpwm_pwm_free, 387 .free = ehrpwm_pwm_free,
360 .config = ehrpwm_pwm_config, 388 .config = ehrpwm_pwm_config,
389 .set_polarity = ehrpwm_pwm_set_polarity,
361 .enable = ehrpwm_pwm_enable, 390 .enable = ehrpwm_pwm_enable,
362 .disable = ehrpwm_pwm_disable, 391 .disable = ehrpwm_pwm_disable,
363 .owner = THIS_MODULE, 392 .owner = THIS_MODULE,
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 995f0164c9b0..069983ca49ff 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -213,7 +213,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
213 pb->exit = data->exit; 213 pb->exit = data->exit;
214 pb->dev = &pdev->dev; 214 pb->dev = &pdev->dev;
215 215
216 pb->pwm = pwm_get(&pdev->dev, NULL); 216 pb->pwm = devm_pwm_get(&pdev->dev, NULL);
217 if (IS_ERR(pb->pwm)) { 217 if (IS_ERR(pb->pwm)) {
218 dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); 218 dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
219 219
@@ -246,7 +246,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
246 if (IS_ERR(bl)) { 246 if (IS_ERR(bl)) {
247 dev_err(&pdev->dev, "failed to register backlight\n"); 247 dev_err(&pdev->dev, "failed to register backlight\n");
248 ret = PTR_ERR(bl); 248 ret = PTR_ERR(bl);
249 goto err_bl; 249 goto err_alloc;
250 } 250 }
251 251
252 bl->props.brightness = data->dft_brightness; 252 bl->props.brightness = data->dft_brightness;
@@ -255,8 +255,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
255 platform_set_drvdata(pdev, bl); 255 platform_set_drvdata(pdev, bl);
256 return 0; 256 return 0;
257 257
258err_bl:
259 pwm_put(pb->pwm);
260err_alloc: 258err_alloc:
261 if (data->exit) 259 if (data->exit)
262 data->exit(&pdev->dev); 260 data->exit(&pdev->dev);
@@ -271,7 +269,6 @@ static int pwm_backlight_remove(struct platform_device *pdev)
271 backlight_device_unregister(bl); 269 backlight_device_unregister(bl);
272 pwm_config(pb->pwm, 0, pb->period); 270 pwm_config(pb->pwm, 0, pb->period);
273 pwm_disable(pb->pwm); 271 pwm_disable(pb->pwm);
274 pwm_put(pb->pwm);
275 if (pb->exit) 272 if (pb->exit)
276 pb->exit(&pdev->dev); 273 pb->exit(&pdev->dev);
277 return 0; 274 return 0;
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 21d076c5089e..112b31436848 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -1,11 +1,13 @@
1#ifndef __LINUX_PWM_H 1#ifndef __LINUX_PWM_H
2#define __LINUX_PWM_H 2#define __LINUX_PWM_H
3 3
4#include <linux/err.h>
4#include <linux/of.h> 5#include <linux/of.h>
5 6
6struct pwm_device; 7struct pwm_device;
7struct seq_file; 8struct seq_file;
8 9
10#if IS_ENABLED(CONFIG_PWM) || IS_ENABLED(CONFIG_HAVE_PWM)
9/* 11/*
10 * pwm_request - request a PWM device 12 * pwm_request - request a PWM device
11 */ 13 */
@@ -30,10 +32,47 @@ int pwm_enable(struct pwm_device *pwm);
30 * pwm_disable - stop a PWM output toggling 32 * pwm_disable - stop a PWM output toggling
31 */ 33 */
32void pwm_disable(struct pwm_device *pwm); 34void pwm_disable(struct pwm_device *pwm);
35#else
36static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
37{
38 return ERR_PTR(-ENODEV);
39}
40
41static inline void pwm_free(struct pwm_device *pwm)
42{
43}
44
45static inline int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
46{
47 return -EINVAL;
48}
49
50static inline int pwm_enable(struct pwm_device *pwm)
51{
52 return -EINVAL;
53}
54
55static inline void pwm_disable(struct pwm_device *pwm)
56{
57}
58#endif
33 59
34#ifdef CONFIG_PWM
35struct pwm_chip; 60struct pwm_chip;
36 61
62/**
63 * enum pwm_polarity - polarity of a PWM signal
64 * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty-
65 * cycle, followed by a low signal for the remainder of the pulse
66 * period
67 * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty-
68 * cycle, followed by a high signal for the remainder of the pulse
69 * period
70 */
71enum pwm_polarity {
72 PWM_POLARITY_NORMAL,
73 PWM_POLARITY_INVERSED,
74};
75
37enum { 76enum {
38 PWMF_REQUESTED = 1 << 0, 77 PWMF_REQUESTED = 1 << 0,
39 PWMF_ENABLED = 1 << 1, 78 PWMF_ENABLED = 1 << 1,
@@ -61,11 +100,17 @@ static inline unsigned int pwm_get_period(struct pwm_device *pwm)
61 return pwm ? pwm->period : 0; 100 return pwm ? pwm->period : 0;
62} 101}
63 102
103/*
104 * pwm_set_polarity - configure the polarity of a PWM signal
105 */
106int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
107
64/** 108/**
65 * struct pwm_ops - PWM controller operations 109 * struct pwm_ops - PWM controller operations
66 * @request: optional hook for requesting a PWM 110 * @request: optional hook for requesting a PWM
67 * @free: optional hook for freeing a PWM 111 * @free: optional hook for freeing a PWM
68 * @config: configure duty cycles and period length for this PWM 112 * @config: configure duty cycles and period length for this PWM
113 * @set_polarity: configure the polarity of this PWM
69 * @enable: enable PWM output toggling 114 * @enable: enable PWM output toggling
70 * @disable: disable PWM output toggling 115 * @disable: disable PWM output toggling
71 * @dbg_show: optional routine to show contents in debugfs 116 * @dbg_show: optional routine to show contents in debugfs
@@ -79,6 +124,9 @@ struct pwm_ops {
79 int (*config)(struct pwm_chip *chip, 124 int (*config)(struct pwm_chip *chip,
80 struct pwm_device *pwm, 125 struct pwm_device *pwm,
81 int duty_ns, int period_ns); 126 int duty_ns, int period_ns);
127 int (*set_polarity)(struct pwm_chip *chip,
128 struct pwm_device *pwm,
129 enum pwm_polarity polarity);
82 int (*enable)(struct pwm_chip *chip, 130 int (*enable)(struct pwm_chip *chip,
83 struct pwm_device *pwm); 131 struct pwm_device *pwm);
84 void (*disable)(struct pwm_chip *chip, 132 void (*disable)(struct pwm_chip *chip,
@@ -113,6 +161,7 @@ struct pwm_chip {
113 unsigned int of_pwm_n_cells; 161 unsigned int of_pwm_n_cells;
114}; 162};
115 163
164#if IS_ENABLED(CONFIG_PWM)
116int pwm_set_chip_data(struct pwm_device *pwm, void *data); 165int pwm_set_chip_data(struct pwm_device *pwm, void *data);
117void *pwm_get_chip_data(struct pwm_device *pwm); 166void *pwm_get_chip_data(struct pwm_device *pwm);
118 167
@@ -125,6 +174,57 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
125struct pwm_device *pwm_get(struct device *dev, const char *consumer); 174struct pwm_device *pwm_get(struct device *dev, const char *consumer);
126void pwm_put(struct pwm_device *pwm); 175void pwm_put(struct pwm_device *pwm);
127 176
177struct pwm_device *devm_pwm_get(struct device *dev, const char *consumer);
178void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
179#else
180static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
181{
182 return -EINVAL;
183}
184
185static inline void *pwm_get_chip_data(struct pwm_device *pwm)
186{
187 return NULL;
188}
189
190static inline int pwmchip_add(struct pwm_chip *chip)
191{
192 return -EINVAL;
193}
194
195static inline int pwmchip_remove(struct pwm_chip *chip)
196{
197 return -EINVAL;
198}
199
200static inline struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
201 unsigned int index,
202 const char *label)
203{
204 return ERR_PTR(-ENODEV);
205}
206
207static inline struct pwm_device *pwm_get(struct device *dev,
208 const char *consumer)
209{
210 return ERR_PTR(-ENODEV);
211}
212
213static inline void pwm_put(struct pwm_device *pwm)
214{
215}
216
217static inline struct pwm_device *devm_pwm_get(struct device *dev,
218 const char *consumer)
219{
220 return ERR_PTR(-ENODEV);
221}
222
223static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
224{
225}
226#endif
227
128struct pwm_lookup { 228struct pwm_lookup {
129 struct list_head list; 229 struct list_head list;
130 const char *provider; 230 const char *provider;
@@ -141,8 +241,12 @@ struct pwm_lookup {
141 .con_id = _con_id, \ 241 .con_id = _con_id, \
142 } 242 }
143 243
244#if IS_ENABLED(CONFIG_PWM)
144void pwm_add_table(struct pwm_lookup *table, size_t num); 245void pwm_add_table(struct pwm_lookup *table, size_t num);
145 246#else
247static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
248{
249}
146#endif 250#endif
147 251
148#endif /* __LINUX_PWM_H */ 252#endif /* __LINUX_PWM_H */