diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2012-03-15 05:04:37 -0400 |
---|---|---|
committer | Thierry Reding <thierry.reding@avionic-design.de> | 2012-07-02 16:06:33 -0400 |
commit | a245ccebb4aad9fae60597d5cbad158c0de4483e (patch) | |
tree | 99f2cecbbacfb6c06d803b4e5e0e5cba16bf5d2d | |
parent | 215c29d3d0e925189ade522d1ea6052a320d7692 (diff) |
ARM vt8500: Move vt8500 pwm driver to pwm framework
Move the driver to drivers/pwm/ and convert it to use the framework.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Alexey Charkov <alchark@gmail.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-vt8500/Makefile | 2 | ||||
-rw-r--r-- | drivers/pwm/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 1 | ||||
-rw-r--r-- | drivers/pwm/pwm-vt8500.c (renamed from arch/arm/mach-vt8500/pwm.c) | 169 |
5 files changed, 66 insertions, 116 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 84449dd8f031..8da8f82f6fe3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -962,7 +962,6 @@ config ARCH_VT8500 | |||
962 | select ARCH_HAS_CPUFREQ | 962 | select ARCH_HAS_CPUFREQ |
963 | select GENERIC_CLOCKEVENTS | 963 | select GENERIC_CLOCKEVENTS |
964 | select ARCH_REQUIRE_GPIOLIB | 964 | select ARCH_REQUIRE_GPIOLIB |
965 | select HAVE_PWM | ||
966 | help | 965 | help |
967 | Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. | 966 | Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. |
968 | 967 | ||
diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile index 81aedb7c893c..8df9e4abab6d 100644 --- a/arch/arm/mach-vt8500/Makefile +++ b/arch/arm/mach-vt8500/Makefile | |||
@@ -5,5 +5,3 @@ obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o | |||
5 | 5 | ||
6 | obj-$(CONFIG_MACH_BV07) += bv07.o | 6 | obj-$(CONFIG_MACH_BV07) += bv07.o |
7 | obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o | 7 | obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o |
8 | |||
9 | obj-$(CONFIG_HAVE_PWM) += pwm.o | ||
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 0d9aa92636c3..a93feffbc36a 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig | |||
@@ -55,4 +55,13 @@ config PWM_TEGRA | |||
55 | 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 |
56 | will be called pwm-tegra. | 56 | will be called pwm-tegra. |
57 | 57 | ||
58 | config PWM_VT8500 | ||
59 | tristate "vt8500 pwm support" | ||
60 | depends on ARCH_VT8500 | ||
61 | help | ||
62 | Generic PWM framework driver for vt8500. | ||
63 | |||
64 | To compile this driver as a module, choose M here: the module | ||
65 | will be called pwm-vt8500. | ||
66 | |||
58 | endif | 67 | endif |
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index a1d87b173312..b7c0fcf4de16 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile | |||
@@ -4,3 +4,4 @@ obj-$(CONFIG_PWM_IMX) += pwm-imx.o | |||
4 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o | 4 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o |
5 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o | 5 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o |
6 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o | 6 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o |
7 | obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o | ||
diff --git a/arch/arm/mach-vt8500/pwm.c b/drivers/pwm/pwm-vt8500.c index 8ad825e93592..3db0746f7200 100644 --- a/arch/arm/mach-vt8500/pwm.c +++ b/drivers/pwm/pwm-vt8500.c | |||
@@ -26,21 +26,13 @@ | |||
26 | 26 | ||
27 | #define VT8500_NR_PWMS 4 | 27 | #define VT8500_NR_PWMS 4 |
28 | 28 | ||
29 | static DEFINE_MUTEX(pwm_lock); | 29 | struct vt8500_chip { |
30 | static LIST_HEAD(pwm_list); | 30 | struct pwm_chip chip; |
31 | 31 | void __iomem *base; | |
32 | struct pwm_device { | ||
33 | struct list_head node; | ||
34 | struct platform_device *pdev; | ||
35 | |||
36 | const char *label; | ||
37 | |||
38 | void __iomem *regbase; | ||
39 | |||
40 | unsigned int use_count; | ||
41 | unsigned int pwm_id; | ||
42 | }; | 32 | }; |
43 | 33 | ||
34 | #define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip) | ||
35 | |||
44 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | 36 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) |
45 | static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) | 37 | static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) |
46 | { | 38 | { |
@@ -53,14 +45,13 @@ static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) | |||
53 | bitmask); | 45 | bitmask); |
54 | } | 46 | } |
55 | 47 | ||
56 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | 48 | static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
49 | int duty_ns, int period_ns) | ||
57 | { | 50 | { |
51 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); | ||
58 | unsigned long long c; | 52 | unsigned long long c; |
59 | unsigned long period_cycles, prescale, pv, dc; | 53 | unsigned long period_cycles, prescale, pv, dc; |
60 | 54 | ||
61 | if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) | ||
62 | return -EINVAL; | ||
63 | |||
64 | c = 25000000/2; /* wild guess --- need to implement clocks */ | 55 | c = 25000000/2; /* wild guess --- need to implement clocks */ |
65 | c = c * period_ns; | 56 | c = c * period_ns; |
66 | do_div(c, 1000000000); | 57 | do_div(c, 1000000000); |
@@ -80,104 +71,58 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
80 | do_div(c, period_ns); | 71 | do_div(c, period_ns); |
81 | dc = c; | 72 | dc = c; |
82 | 73 | ||
83 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 1)); | 74 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 1)); |
84 | writel(prescale, pwm->regbase + 0x4 + (pwm->pwm_id << 4)); | 75 | writel(prescale, vt8500->base + 0x4 + (pwm->hwpwm << 4)); |
85 | 76 | ||
86 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 2)); | 77 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 2)); |
87 | writel(pv, pwm->regbase + 0x8 + (pwm->pwm_id << 4)); | 78 | writel(pv, vt8500->base + 0x8 + (pwm->hwpwm << 4)); |
88 | 79 | ||
89 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 3)); | 80 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3)); |
90 | writel(dc, pwm->regbase + 0xc + (pwm->pwm_id << 4)); | 81 | writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4)); |
91 | 82 | ||
92 | return 0; | 83 | return 0; |
93 | } | 84 | } |
94 | EXPORT_SYMBOL(pwm_config); | ||
95 | 85 | ||
96 | int pwm_enable(struct pwm_device *pwm) | 86 | static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
97 | { | 87 | { |
98 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); | 88 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); |
99 | writel(5, pwm->regbase + (pwm->pwm_id << 4)); | ||
100 | return 0; | ||
101 | } | ||
102 | EXPORT_SYMBOL(pwm_enable); | ||
103 | |||
104 | void pwm_disable(struct pwm_device *pwm) | ||
105 | { | ||
106 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); | ||
107 | writel(0, pwm->regbase + (pwm->pwm_id << 4)); | ||
108 | } | ||
109 | EXPORT_SYMBOL(pwm_disable); | ||
110 | |||
111 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
112 | { | ||
113 | struct pwm_device *pwm; | ||
114 | int found = 0; | ||
115 | |||
116 | mutex_lock(&pwm_lock); | ||
117 | 89 | ||
118 | list_for_each_entry(pwm, &pwm_list, node) { | 90 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); |
119 | if (pwm->pwm_id == pwm_id) { | 91 | writel(5, vt8500->base + (pwm->hwpwm << 4)); |
120 | found = 1; | 92 | return 0; |
121 | break; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | if (found) { | ||
126 | if (pwm->use_count == 0) { | ||
127 | pwm->use_count++; | ||
128 | pwm->label = label; | ||
129 | } else { | ||
130 | pwm = ERR_PTR(-EBUSY); | ||
131 | } | ||
132 | } else { | ||
133 | pwm = ERR_PTR(-ENOENT); | ||
134 | } | ||
135 | |||
136 | mutex_unlock(&pwm_lock); | ||
137 | return pwm; | ||
138 | } | 93 | } |
139 | EXPORT_SYMBOL(pwm_request); | ||
140 | 94 | ||
141 | void pwm_free(struct pwm_device *pwm) | 95 | static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
142 | { | 96 | { |
143 | mutex_lock(&pwm_lock); | 97 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); |
144 | |||
145 | if (pwm->use_count) { | ||
146 | pwm->use_count--; | ||
147 | pwm->label = NULL; | ||
148 | } else { | ||
149 | pr_warning("PWM device already freed\n"); | ||
150 | } | ||
151 | 98 | ||
152 | mutex_unlock(&pwm_lock); | 99 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); |
100 | writel(0, vt8500->base + (pwm->hwpwm << 4)); | ||
153 | } | 101 | } |
154 | EXPORT_SYMBOL(pwm_free); | ||
155 | 102 | ||
156 | static inline void __add_pwm(struct pwm_device *pwm) | 103 | static struct pwm_ops vt8500_pwm_ops = { |
157 | { | 104 | .enable = vt8500_pwm_enable, |
158 | mutex_lock(&pwm_lock); | 105 | .disable = vt8500_pwm_disable, |
159 | list_add_tail(&pwm->node, &pwm_list); | 106 | .config = vt8500_pwm_config, |
160 | mutex_unlock(&pwm_lock); | 107 | .owner = THIS_MODULE, |
161 | } | 108 | }; |
162 | 109 | ||
163 | static int __devinit pwm_probe(struct platform_device *pdev) | 110 | static int __devinit pwm_probe(struct platform_device *pdev) |
164 | { | 111 | { |
165 | struct pwm_device *pwms; | 112 | struct vt8500_chip *chip; |
166 | struct resource *r; | 113 | struct resource *r; |
167 | int ret = 0; | 114 | int ret; |
168 | int i; | ||
169 | 115 | ||
170 | pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL); | 116 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
171 | if (pwms == NULL) { | 117 | if (chip == NULL) { |
172 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 118 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
173 | return -ENOMEM; | 119 | return -ENOMEM; |
174 | } | 120 | } |
175 | 121 | ||
176 | for (i = 0; i < VT8500_NR_PWMS; i++) { | 122 | chip->chip.dev = &pdev->dev; |
177 | pwms[i].use_count = 0; | 123 | chip->chip.ops = &vt8500_pwm_ops; |
178 | pwms[i].pwm_id = i; | 124 | chip->chip.base = -1; |
179 | pwms[i].pdev = pdev; | 125 | chip->chip.npwm = VT8500_NR_PWMS; |
180 | } | ||
181 | 126 | ||
182 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 127 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
183 | if (r == NULL) { | 128 | if (r == NULL) { |
@@ -193,51 +138,49 @@ static int __devinit pwm_probe(struct platform_device *pdev) | |||
193 | goto err_free; | 138 | goto err_free; |
194 | } | 139 | } |
195 | 140 | ||
196 | pwms[0].regbase = ioremap(r->start, resource_size(r)); | 141 | chip->base = ioremap(r->start, resource_size(r)); |
197 | if (pwms[0].regbase == NULL) { | 142 | if (chip->base == NULL) { |
198 | dev_err(&pdev->dev, "failed to ioremap() registers\n"); | 143 | dev_err(&pdev->dev, "failed to ioremap() registers\n"); |
199 | ret = -ENODEV; | 144 | ret = -ENODEV; |
200 | goto err_free_mem; | 145 | goto err_free_mem; |
201 | } | 146 | } |
202 | 147 | ||
203 | for (i = 1; i < VT8500_NR_PWMS; i++) | 148 | ret = pwmchip_add(&chip->chip); |
204 | pwms[i].regbase = pwms[0].regbase; | 149 | if (ret < 0) |
205 | 150 | goto err_unmap; | |
206 | for (i = 0; i < VT8500_NR_PWMS; i++) | ||
207 | __add_pwm(&pwms[i]); | ||
208 | 151 | ||
209 | platform_set_drvdata(pdev, pwms); | 152 | platform_set_drvdata(pdev, chip); |
210 | return 0; | 153 | return ret; |
211 | 154 | ||
155 | err_unmap: | ||
156 | iounmap(chip->base); | ||
212 | err_free_mem: | 157 | err_free_mem: |
213 | release_mem_region(r->start, resource_size(r)); | 158 | release_mem_region(r->start, resource_size(r)); |
214 | err_free: | 159 | err_free: |
215 | kfree(pwms); | 160 | kfree(chip); |
216 | return ret; | 161 | return ret; |
217 | } | 162 | } |
218 | 163 | ||
219 | static int __devexit pwm_remove(struct platform_device *pdev) | 164 | static int __devexit pwm_remove(struct platform_device *pdev) |
220 | { | 165 | { |
221 | struct pwm_device *pwms; | 166 | struct vt8500_chip *chip; |
222 | struct resource *r; | 167 | struct resource *r; |
223 | int i; | 168 | int err; |
224 | 169 | ||
225 | pwms = platform_get_drvdata(pdev); | 170 | chip = platform_get_drvdata(pdev); |
226 | if (pwms == NULL) | 171 | if (chip == NULL) |
227 | return -ENODEV; | 172 | return -ENODEV; |
228 | 173 | ||
229 | mutex_lock(&pwm_lock); | 174 | err = pwmchip_remove(&chip->chip); |
230 | 175 | if (err < 0) | |
231 | for (i = 0; i < VT8500_NR_PWMS; i++) | 176 | return err; |
232 | list_del(&pwms[i].node); | ||
233 | mutex_unlock(&pwm_lock); | ||
234 | 177 | ||
235 | iounmap(pwms[0].regbase); | 178 | iounmap(chip->base); |
236 | 179 | ||
237 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 180 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
238 | release_mem_region(r->start, resource_size(r)); | 181 | release_mem_region(r->start, resource_size(r)); |
239 | 182 | ||
240 | kfree(pwms); | 183 | kfree(chip); |
241 | return 0; | 184 | return 0; |
242 | } | 185 | } |
243 | 186 | ||