2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform PWM support
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.
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.
16 #include <linux/kernel.h>
18 #include <linux/clk.h>
19 #include <linux/err.h>
20 #include <linux/pwm.h>
21 #include <linux/gpio.h>
23 #include <asm/mach-jz4740/gpio.h>
26 static struct clk
*jz4740_pwm_clk
;
28 DEFINE_MUTEX(jz4740_pwm_mutex
);
36 static 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 },
45 struct pwm_device
*pwm_request(int id
, const char *label
)
48 struct pwm_device
*pwm
;
50 if (id
< 2 || id
> 7 || !jz4740_pwm_clk
)
51 return ERR_PTR(-ENODEV
);
53 mutex_lock(&jz4740_pwm_mutex
);
55 pwm
= &jz4740_pwm_list
[id
- 2];
61 mutex_unlock(&jz4740_pwm_mutex
);
66 ret
= gpio_request(pwm
->gpio
, label
);
69 printk(KERN_ERR
"Failed to request pwm gpio: %d\n", ret
);
74 jz_gpio_set_function(pwm
->gpio
, JZ_GPIO_FUNC_PWM
);
76 jz4740_timer_start(id
);
81 void pwm_free(struct pwm_device
*pwm
)
84 jz4740_timer_set_ctrl(pwm
->id
, 0);
86 jz_gpio_set_function(pwm
->gpio
, JZ_GPIO_FUNC_NONE
);
89 jz4740_timer_stop(pwm
->id
);
94 int pwm_config(struct pwm_device
*pwm
, int duty_ns
, int period_ns
)
96 unsigned long long tmp
;
97 unsigned long period
, duty
;
98 unsigned int prescaler
= 0;
99 unsigned int id
= pwm
->id
;
103 if (duty_ns
< 0 || duty_ns
> period_ns
)
106 tmp
= (unsigned long long)clk_get_rate(jz4740_pwm_clk
) * period_ns
;
107 do_div(tmp
, 1000000000);
110 while (period
> 0xffff && prescaler
< 6) {
118 tmp
= (unsigned long long)period
* duty_ns
;
119 do_div(tmp
, period_ns
);
125 is_enabled
= jz4740_timer_is_enabled(id
);
129 jz4740_timer_set_count(id
, 0);
130 jz4740_timer_set_duty(id
, duty
);
131 jz4740_timer_set_period(id
, period
);
133 ctrl
= JZ_TIMER_CTRL_PRESCALER(prescaler
) | JZ_TIMER_CTRL_SRC_EXT
|
134 JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN
;
136 jz4740_timer_set_ctrl(id
, ctrl
);
144 int pwm_enable(struct pwm_device
*pwm
)
146 uint32_t ctrl
= jz4740_timer_get_ctrl(pwm
->id
);
148 ctrl
|= JZ_TIMER_CTRL_PWM_ENABLE
;
149 jz4740_timer_set_ctrl(pwm
->id
, ctrl
);
150 jz4740_timer_enable(pwm
->id
);
155 void pwm_disable(struct pwm_device
*pwm
)
157 uint32_t ctrl
= jz4740_timer_get_ctrl(pwm
->id
);
159 ctrl
&= ~JZ_TIMER_CTRL_PWM_ENABLE
;
160 jz4740_timer_disable(pwm
->id
);
161 jz4740_timer_set_ctrl(pwm
->id
, ctrl
);
164 static int __init
jz4740_pwm_init(void)
168 jz4740_pwm_clk
= clk_get(NULL
, "ext");
170 if (IS_ERR(jz4740_pwm_clk
)) {
171 ret
= PTR_ERR(jz4740_pwm_clk
);
172 jz4740_pwm_clk
= NULL
;
177 subsys_initcall(jz4740_pwm_init
);