1 From 5cd5a44b94b451ecaf593bb49919cfbb51ccb622 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sat, 17 Jul 2010 11:12:20 +0000
4 Subject: [PATCH] MIPS: JZ4740: Add PWM support
6 Add support for the PWM part of the timer unit on a JZ4740 SoC.
8 Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
9 Cc: linux-mips@linux-mips.org
10 Cc: linux-kernel@vger.kernel.org
11 Patchwork: https://patchwork.linux-mips.org/patch/1468/
12 Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
14 arch/mips/jz4740/pwm.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++
15 1 files changed, 177 insertions(+), 0 deletions(-)
16 create mode 100644 arch/mips/jz4740/pwm.c
19 +++ b/arch/mips/jz4740/pwm.c
22 + * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
23 + * JZ4740 platform PWM support
25 + * This program is free software; you can redistribute it and/or modify it
26 + * under the terms of the GNU General Public License as published by the
27 + * Free Software Foundation; either version 2 of the License, or (at your
28 + * option) any later version.
30 + * You should have received a copy of the GNU General Public License along
31 + * with this program; if not, write to the Free Software Foundation, Inc.,
32 + * 675 Mass Ave, Cambridge, MA 02139, USA.
36 +#include <linux/kernel.h>
38 +#include <linux/clk.h>
39 +#include <linux/err.h>
40 +#include <linux/pwm.h>
41 +#include <linux/gpio.h>
43 +#include <asm/mach-jz4740/gpio.h>
46 +static struct clk *jz4740_pwm_clk;
48 +DEFINE_MUTEX(jz4740_pwm_mutex);
56 +static struct pwm_device jz4740_pwm_list[] = {
57 + { 2, JZ_GPIO_PWM2, false },
58 + { 3, JZ_GPIO_PWM3, false },
59 + { 4, JZ_GPIO_PWM4, false },
60 + { 5, JZ_GPIO_PWM5, false },
61 + { 6, JZ_GPIO_PWM6, false },
62 + { 7, JZ_GPIO_PWM7, false },
65 +struct pwm_device *pwm_request(int id, const char *label)
68 + struct pwm_device *pwm;
70 + if (id < 2 || id > 7 || !jz4740_pwm_clk)
71 + return ERR_PTR(-ENODEV);
73 + mutex_lock(&jz4740_pwm_mutex);
75 + pwm = &jz4740_pwm_list[id - 2];
81 + mutex_unlock(&jz4740_pwm_mutex);
84 + return ERR_PTR(ret);
86 + ret = gpio_request(pwm->gpio, label);
89 + printk(KERN_ERR "Failed to request pwm gpio: %d\n", ret);
91 + return ERR_PTR(ret);
94 + jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_PWM);
96 + jz4740_timer_start(id);
101 +void pwm_free(struct pwm_device *pwm)
104 + jz4740_timer_set_ctrl(pwm->id, 0);
106 + jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_NONE);
107 + gpio_free(pwm->gpio);
109 + jz4740_timer_stop(pwm->id);
114 +int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
116 + unsigned long long tmp;
117 + unsigned long period, duty;
118 + unsigned int prescaler = 0;
119 + unsigned int id = pwm->id;
123 + if (duty_ns < 0 || duty_ns > period_ns)
126 + tmp = (unsigned long long)clk_get_rate(jz4740_pwm_clk) * period_ns;
127 + do_div(tmp, 1000000000);
130 + while (period > 0xffff && prescaler < 6) {
135 + if (prescaler == 6)
138 + tmp = (unsigned long long)period * duty_ns;
139 + do_div(tmp, period_ns);
140 + duty = period - tmp;
142 + if (duty >= period)
145 + is_enabled = jz4740_timer_is_enabled(id);
149 + jz4740_timer_set_count(id, 0);
150 + jz4740_timer_set_duty(id, duty);
151 + jz4740_timer_set_period(id, period);
153 + ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
154 + JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
156 + jz4740_timer_set_ctrl(id, ctrl);
164 +int pwm_enable(struct pwm_device *pwm)
166 + uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
168 + ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
169 + jz4740_timer_set_ctrl(pwm->id, ctrl);
170 + jz4740_timer_enable(pwm->id);
175 +void pwm_disable(struct pwm_device *pwm)
177 + uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
179 + ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
180 + jz4740_timer_disable(pwm->id);
181 + jz4740_timer_set_ctrl(pwm->id, ctrl);
184 +static int __init jz4740_pwm_init(void)
188 + jz4740_pwm_clk = clk_get(NULL, "ext");
190 + if (IS_ERR(jz4740_pwm_clk)) {
191 + ret = PTR_ERR(jz4740_pwm_clk);
192 + jz4740_pwm_clk = NULL;
197 +subsys_initcall(jz4740_pwm_init);