aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorThierry Reding <thierry.reding@avionic-design.de>2012-08-22 04:01:24 -0400
committerThierry Reding <thierry.reding@avionic-design.de>2012-10-05 14:56:42 -0400
commitf6b8a5700057cc1b531c2f9b7806428a6f83b467 (patch)
treebf019c60548d37c21c8f1ca00a7968a425ea53da /arch/mips
parent46a98765133bd880916415d431698797010d4ba8 (diff)
pwm: Add Ingenic JZ4740 support
This commit moves the driver to drivers/pwm and converts it to the new PWM framework. Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de> Acked-by: Lars-Peter Clausen <lars@metafoo.de> Tested-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/include/asm/mach-jz4740/platform.h1
-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
6 files changed, 9 insertions, 181 deletions
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/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);