diff options
Diffstat (limited to 'arch/arm/mach-davinci')
-rw-r--r-- | arch/arm/mach-davinci/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-davinci/board-evm.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-davinci/clock.c | 323 | ||||
-rw-r--r-- | arch/arm/mach-davinci/clock.h | 33 | ||||
-rw-r--r-- | arch/arm/mach-davinci/gpio.c | 286 | ||||
-rw-r--r-- | arch/arm/mach-davinci/io.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-davinci/mux.c | 41 | ||||
-rw-r--r-- | arch/arm/mach-davinci/psc.c | 87 |
8 files changed, 750 insertions, 31 deletions
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index a8f88cd29905..99ac2e55774d 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile | |||
@@ -4,7 +4,8 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | # Common objects | 6 | # Common objects |
7 | obj-y := time.o irq.o serial.o io.o id.o psc.o | 7 | obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \ |
8 | gpio.o mux.o | ||
8 | 9 | ||
9 | # Board specific | 10 | # Board specific |
10 | obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o | 11 | obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o |
diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c index 633c12e43044..9e4024c4965f 100644 --- a/arch/arm/mach-davinci/board-evm.c +++ b/arch/arm/mach-davinci/board-evm.c | |||
@@ -32,6 +32,7 @@ | |||
32 | void __init davinci_psc_init(void); | 32 | void __init davinci_psc_init(void); |
33 | void __init davinci_irq_init(void); | 33 | void __init davinci_irq_init(void); |
34 | void __init davinci_map_common_io(void); | 34 | void __init davinci_map_common_io(void); |
35 | void __init davinci_init_common_hw(void); | ||
35 | 36 | ||
36 | /* NOR Flash base address set to CS0 by default */ | 37 | /* NOR Flash base address set to CS0 by default */ |
37 | #define NOR_FLASH_PHYS 0x02000000 | 38 | #define NOR_FLASH_PHYS 0x02000000 |
@@ -116,6 +117,7 @@ static __init void davinci_evm_init(void) | |||
116 | 117 | ||
117 | static __init void davinci_evm_irq_init(void) | 118 | static __init void davinci_evm_irq_init(void) |
118 | { | 119 | { |
120 | davinci_init_common_hw(); | ||
119 | davinci_irq_init(); | 121 | davinci_irq_init(); |
120 | } | 122 | } |
121 | 123 | ||
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c new file mode 100644 index 000000000000..139ceaa35e24 --- /dev/null +++ b/arch/arm/mach-davinci/clock.c | |||
@@ -0,0 +1,323 @@ | |||
1 | /* | ||
2 | * TI DaVinci clock config file | ||
3 | * | ||
4 | * Copyright (C) 2006 Texas Instruments. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | |||
20 | #include <asm/hardware.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | #include <asm/arch/psc.h> | ||
24 | #include "clock.h" | ||
25 | |||
26 | /* PLL/Reset register offsets */ | ||
27 | #define PLLM 0x110 | ||
28 | |||
29 | static LIST_HEAD(clocks); | ||
30 | static DEFINE_MUTEX(clocks_mutex); | ||
31 | static DEFINE_SPINLOCK(clockfw_lock); | ||
32 | |||
33 | static unsigned int commonrate; | ||
34 | static unsigned int armrate; | ||
35 | static unsigned int fixedrate = 27000000; /* 27 MHZ */ | ||
36 | |||
37 | extern void davinci_psc_config(unsigned int domain, unsigned int id, char enable); | ||
38 | |||
39 | /* | ||
40 | * Returns a clock. Note that we first try to use device id on the bus | ||
41 | * and clock name. If this fails, we try to use clock name only. | ||
42 | */ | ||
43 | struct clk *clk_get(struct device *dev, const char *id) | ||
44 | { | ||
45 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
46 | int idno; | ||
47 | |||
48 | if (dev == NULL || dev->bus != &platform_bus_type) | ||
49 | idno = -1; | ||
50 | else | ||
51 | idno = to_platform_device(dev)->id; | ||
52 | |||
53 | mutex_lock(&clocks_mutex); | ||
54 | |||
55 | list_for_each_entry(p, &clocks, node) { | ||
56 | if (p->id == idno && | ||
57 | strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
58 | clk = p; | ||
59 | goto found; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | list_for_each_entry(p, &clocks, node) { | ||
64 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
65 | clk = p; | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | found: | ||
71 | mutex_unlock(&clocks_mutex); | ||
72 | |||
73 | return clk; | ||
74 | } | ||
75 | EXPORT_SYMBOL(clk_get); | ||
76 | |||
77 | void clk_put(struct clk *clk) | ||
78 | { | ||
79 | if (clk && !IS_ERR(clk)) | ||
80 | module_put(clk->owner); | ||
81 | } | ||
82 | EXPORT_SYMBOL(clk_put); | ||
83 | |||
84 | static int __clk_enable(struct clk *clk) | ||
85 | { | ||
86 | if (clk->flags & ALWAYS_ENABLED) | ||
87 | return 0; | ||
88 | |||
89 | davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 1); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static void __clk_disable(struct clk *clk) | ||
94 | { | ||
95 | if (clk->usecount) | ||
96 | return; | ||
97 | |||
98 | davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 0); | ||
99 | } | ||
100 | |||
101 | int clk_enable(struct clk *clk) | ||
102 | { | ||
103 | unsigned long flags; | ||
104 | int ret = 0; | ||
105 | |||
106 | if (clk == NULL || IS_ERR(clk)) | ||
107 | return -EINVAL; | ||
108 | |||
109 | if (clk->usecount++ == 0) { | ||
110 | spin_lock_irqsave(&clockfw_lock, flags); | ||
111 | ret = __clk_enable(clk); | ||
112 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
113 | } | ||
114 | |||
115 | return ret; | ||
116 | } | ||
117 | EXPORT_SYMBOL(clk_enable); | ||
118 | |||
119 | void clk_disable(struct clk *clk) | ||
120 | { | ||
121 | unsigned long flags; | ||
122 | |||
123 | if (clk == NULL || IS_ERR(clk)) | ||
124 | return; | ||
125 | |||
126 | if (clk->usecount > 0 && !(--clk->usecount)) { | ||
127 | spin_lock_irqsave(&clockfw_lock, flags); | ||
128 | __clk_disable(clk); | ||
129 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
130 | } | ||
131 | } | ||
132 | EXPORT_SYMBOL(clk_disable); | ||
133 | |||
134 | unsigned long clk_get_rate(struct clk *clk) | ||
135 | { | ||
136 | if (clk == NULL || IS_ERR(clk)) | ||
137 | return -EINVAL; | ||
138 | |||
139 | return *(clk->rate); | ||
140 | } | ||
141 | EXPORT_SYMBOL(clk_get_rate); | ||
142 | |||
143 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
144 | { | ||
145 | if (clk == NULL || IS_ERR(clk)) | ||
146 | return -EINVAL; | ||
147 | |||
148 | return *(clk->rate); | ||
149 | } | ||
150 | EXPORT_SYMBOL(clk_round_rate); | ||
151 | |||
152 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
153 | { | ||
154 | if (clk == NULL || IS_ERR(clk)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | /* changing the clk rate is not supported */ | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | EXPORT_SYMBOL(clk_set_rate); | ||
161 | |||
162 | int clk_register(struct clk *clk) | ||
163 | { | ||
164 | if (clk == NULL || IS_ERR(clk)) | ||
165 | return -EINVAL; | ||
166 | |||
167 | mutex_lock(&clocks_mutex); | ||
168 | list_add(&clk->node, &clocks); | ||
169 | mutex_unlock(&clocks_mutex); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | EXPORT_SYMBOL(clk_register); | ||
174 | |||
175 | void clk_unregister(struct clk *clk) | ||
176 | { | ||
177 | if (clk == NULL || IS_ERR(clk)) | ||
178 | return; | ||
179 | |||
180 | mutex_lock(&clocks_mutex); | ||
181 | list_del(&clk->node); | ||
182 | mutex_unlock(&clocks_mutex); | ||
183 | } | ||
184 | EXPORT_SYMBOL(clk_unregister); | ||
185 | |||
186 | static struct clk davinci_clks[] = { | ||
187 | { | ||
188 | .name = "ARMCLK", | ||
189 | .rate = &armrate, | ||
190 | .lpsc = -1, | ||
191 | .flags = ALWAYS_ENABLED, | ||
192 | }, | ||
193 | { | ||
194 | .name = "UART", | ||
195 | .rate = &fixedrate, | ||
196 | .lpsc = DAVINCI_LPSC_UART0, | ||
197 | }, | ||
198 | { | ||
199 | .name = "EMACCLK", | ||
200 | .rate = &commonrate, | ||
201 | .lpsc = DAVINCI_LPSC_EMAC_WRAPPER, | ||
202 | }, | ||
203 | { | ||
204 | .name = "I2CCLK", | ||
205 | .rate = &fixedrate, | ||
206 | .lpsc = DAVINCI_LPSC_I2C, | ||
207 | }, | ||
208 | { | ||
209 | .name = "IDECLK", | ||
210 | .rate = &commonrate, | ||
211 | .lpsc = DAVINCI_LPSC_ATA, | ||
212 | }, | ||
213 | { | ||
214 | .name = "McBSPCLK", | ||
215 | .rate = &commonrate, | ||
216 | .lpsc = DAVINCI_LPSC_McBSP, | ||
217 | }, | ||
218 | { | ||
219 | .name = "MMCSDCLK", | ||
220 | .rate = &commonrate, | ||
221 | .lpsc = DAVINCI_LPSC_MMC_SD, | ||
222 | }, | ||
223 | { | ||
224 | .name = "SPICLK", | ||
225 | .rate = &commonrate, | ||
226 | .lpsc = DAVINCI_LPSC_SPI, | ||
227 | }, | ||
228 | { | ||
229 | .name = "gpio", | ||
230 | .rate = &commonrate, | ||
231 | .lpsc = DAVINCI_LPSC_GPIO, | ||
232 | }, | ||
233 | { | ||
234 | .name = "AEMIFCLK", | ||
235 | .rate = &commonrate, | ||
236 | .lpsc = DAVINCI_LPSC_AEMIF, | ||
237 | .usecount = 1, | ||
238 | } | ||
239 | }; | ||
240 | |||
241 | int __init davinci_clk_init(void) | ||
242 | { | ||
243 | struct clk *clkp; | ||
244 | int count = 0; | ||
245 | u32 pll_mult; | ||
246 | |||
247 | pll_mult = davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLM); | ||
248 | commonrate = ((pll_mult + 1) * 27000000) / 6; | ||
249 | armrate = ((pll_mult + 1) * 27000000) / 2; | ||
250 | |||
251 | for (clkp = davinci_clks; count < ARRAY_SIZE(davinci_clks); | ||
252 | count++, clkp++) { | ||
253 | clk_register(clkp); | ||
254 | |||
255 | /* Turn on clocks that have been enabled in the | ||
256 | * table above */ | ||
257 | if (clkp->usecount) | ||
258 | clk_enable(clkp); | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | #ifdef CONFIG_PROC_FS | ||
265 | #include <linux/proc_fs.h> | ||
266 | #include <linux/seq_file.h> | ||
267 | |||
268 | static void *davinci_ck_start(struct seq_file *m, loff_t *pos) | ||
269 | { | ||
270 | return *pos < 1 ? (void *)1 : NULL; | ||
271 | } | ||
272 | |||
273 | static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos) | ||
274 | { | ||
275 | ++*pos; | ||
276 | return NULL; | ||
277 | } | ||
278 | |||
279 | static void davinci_ck_stop(struct seq_file *m, void *v) | ||
280 | { | ||
281 | } | ||
282 | |||
283 | static int davinci_ck_show(struct seq_file *m, void *v) | ||
284 | { | ||
285 | struct clk *cp; | ||
286 | |||
287 | list_for_each_entry(cp, &clocks, node) | ||
288 | seq_printf(m,"%s %d %d\n", cp->name, *(cp->rate), cp->usecount); | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static struct seq_operations davinci_ck_op = { | ||
294 | .start = davinci_ck_start, | ||
295 | .next = davinci_ck_next, | ||
296 | .stop = davinci_ck_stop, | ||
297 | .show = davinci_ck_show | ||
298 | }; | ||
299 | |||
300 | static int davinci_ck_open(struct inode *inode, struct file *file) | ||
301 | { | ||
302 | return seq_open(file, &davinci_ck_op); | ||
303 | } | ||
304 | |||
305 | static struct file_operations proc_davinci_ck_operations = { | ||
306 | .open = davinci_ck_open, | ||
307 | .read = seq_read, | ||
308 | .llseek = seq_lseek, | ||
309 | .release = seq_release, | ||
310 | }; | ||
311 | |||
312 | static int __init davinci_ck_proc_init(void) | ||
313 | { | ||
314 | struct proc_dir_entry *entry; | ||
315 | |||
316 | entry = create_proc_entry("davinci_clocks", 0, NULL); | ||
317 | if (entry) | ||
318 | entry->proc_fops = &proc_davinci_ck_operations; | ||
319 | return 0; | ||
320 | |||
321 | } | ||
322 | __initcall(davinci_ck_proc_init); | ||
323 | #endif /* CONFIG_DEBUG_PROC_FS */ | ||
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h new file mode 100644 index 000000000000..ed47079a52e4 --- /dev/null +++ b/arch/arm/mach-davinci/clock.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * TI DaVinci clock definitions | ||
3 | * | ||
4 | * Copyright (C) 2006 Texas Instruments. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __ARCH_ARM_DAVINCI_CLOCK_H | ||
12 | #define __ARCH_ARM_DAVINCI_CLOCK_H | ||
13 | |||
14 | struct clk { | ||
15 | struct list_head node; | ||
16 | struct module *owner; | ||
17 | const char *name; | ||
18 | unsigned int *rate; | ||
19 | int id; | ||
20 | __s8 usecount; | ||
21 | __u8 flags; | ||
22 | __u8 lpsc; | ||
23 | }; | ||
24 | |||
25 | /* Clock flags */ | ||
26 | #define RATE_CKCTL 1 | ||
27 | #define RATE_FIXED 2 | ||
28 | #define RATE_PROPAGATES 4 | ||
29 | #define VIRTUAL_CLOCK 8 | ||
30 | #define ALWAYS_ENABLED 16 | ||
31 | #define ENABLE_REG_32BIT 32 | ||
32 | |||
33 | #endif | ||
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c new file mode 100644 index 000000000000..9c67886e7189 --- /dev/null +++ b/arch/arm/mach-davinci/gpio.c | |||
@@ -0,0 +1,286 @@ | |||
1 | /* | ||
2 | * TI DaVinci GPIO Support | ||
3 | * | ||
4 | * Copyright (c) 2006 David Brownell | ||
5 | * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/bitops.h> | ||
22 | |||
23 | #include <asm/arch/irqs.h> | ||
24 | #include <asm/arch/hardware.h> | ||
25 | #include <asm/arch/gpio.h> | ||
26 | |||
27 | #include <asm/mach/irq.h> | ||
28 | |||
29 | static DEFINE_SPINLOCK(gpio_lock); | ||
30 | static DECLARE_BITMAP(gpio_in_use, DAVINCI_N_GPIO); | ||
31 | |||
32 | int gpio_request(unsigned gpio, const char *tag) | ||
33 | { | ||
34 | if (gpio >= DAVINCI_N_GPIO) | ||
35 | return -EINVAL; | ||
36 | |||
37 | if (test_and_set_bit(gpio, gpio_in_use)) | ||
38 | return -EBUSY; | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | EXPORT_SYMBOL(gpio_request); | ||
43 | |||
44 | void gpio_free(unsigned gpio) | ||
45 | { | ||
46 | if (gpio >= DAVINCI_N_GPIO) | ||
47 | return; | ||
48 | |||
49 | clear_bit(gpio, gpio_in_use); | ||
50 | } | ||
51 | EXPORT_SYMBOL(gpio_free); | ||
52 | |||
53 | /* create a non-inlined version */ | ||
54 | static struct gpio_controller *__iomem gpio2controller(unsigned gpio) | ||
55 | { | ||
56 | return __gpio_to_controller(gpio); | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Assuming the pin is muxed as a gpio output, set its output value. | ||
61 | */ | ||
62 | void __gpio_set(unsigned gpio, int value) | ||
63 | { | ||
64 | struct gpio_controller *__iomem g = gpio2controller(gpio); | ||
65 | |||
66 | __raw_writel(__gpio_mask(gpio), value ? &g->set_data : &g->clr_data); | ||
67 | } | ||
68 | EXPORT_SYMBOL(__gpio_set); | ||
69 | |||
70 | |||
71 | /* | ||
72 | * Read the pin's value (works even if it's set up as output); | ||
73 | * returns zero/nonzero. | ||
74 | * | ||
75 | * Note that changes are synched to the GPIO clock, so reading values back | ||
76 | * right after you've set them may give old values. | ||
77 | */ | ||
78 | int __gpio_get(unsigned gpio) | ||
79 | { | ||
80 | struct gpio_controller *__iomem g = gpio2controller(gpio); | ||
81 | |||
82 | return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data)); | ||
83 | } | ||
84 | EXPORT_SYMBOL(__gpio_get); | ||
85 | |||
86 | |||
87 | /*--------------------------------------------------------------------------*/ | ||
88 | |||
89 | /* | ||
90 | * board setup code *MUST* set PINMUX0 and PINMUX1 as | ||
91 | * needed, and enable the GPIO clock. | ||
92 | */ | ||
93 | |||
94 | int gpio_direction_input(unsigned gpio) | ||
95 | { | ||
96 | struct gpio_controller *__iomem g = gpio2controller(gpio); | ||
97 | u32 temp; | ||
98 | u32 mask; | ||
99 | |||
100 | if (!g) | ||
101 | return -EINVAL; | ||
102 | |||
103 | spin_lock(&gpio_lock); | ||
104 | mask = __gpio_mask(gpio); | ||
105 | temp = __raw_readl(&g->dir); | ||
106 | temp |= mask; | ||
107 | __raw_writel(temp, &g->dir); | ||
108 | spin_unlock(&gpio_lock); | ||
109 | return 0; | ||
110 | } | ||
111 | EXPORT_SYMBOL(gpio_direction_input); | ||
112 | |||
113 | int gpio_direction_output(unsigned gpio, int value) | ||
114 | { | ||
115 | struct gpio_controller *__iomem g = gpio2controller(gpio); | ||
116 | u32 temp; | ||
117 | u32 mask; | ||
118 | |||
119 | if (!g) | ||
120 | return -EINVAL; | ||
121 | |||
122 | spin_lock(&gpio_lock); | ||
123 | mask = __gpio_mask(gpio); | ||
124 | temp = __raw_readl(&g->dir); | ||
125 | temp &= ~mask; | ||
126 | __raw_writel(mask, value ? &g->set_data : &g->clr_data); | ||
127 | __raw_writel(temp, &g->dir); | ||
128 | spin_unlock(&gpio_lock); | ||
129 | return 0; | ||
130 | } | ||
131 | EXPORT_SYMBOL(gpio_direction_output); | ||
132 | |||
133 | /* | ||
134 | * We expect irqs will normally be set up as input pins, but they can also be | ||
135 | * used as output pins ... which is convenient for testing. | ||
136 | * | ||
137 | * NOTE: GPIO0..GPIO7 also have direct INTC hookups, which work in addition | ||
138 | * to their GPIOBNK0 irq (but with a bit less overhead). But we don't have | ||
139 | * a good way to hook those up ... | ||
140 | * | ||
141 | * All those INTC hookups (GPIO0..GPIO7 plus five IRQ banks) can also | ||
142 | * serve as EDMA event triggers. | ||
143 | */ | ||
144 | |||
145 | static void gpio_irq_disable(unsigned irq) | ||
146 | { | ||
147 | struct gpio_controller *__iomem g = get_irq_chip_data(irq); | ||
148 | u32 mask = __gpio_mask(irq_to_gpio(irq)); | ||
149 | |||
150 | __raw_writel(mask, &g->clr_falling); | ||
151 | __raw_writel(mask, &g->clr_rising); | ||
152 | } | ||
153 | |||
154 | static void gpio_irq_enable(unsigned irq) | ||
155 | { | ||
156 | struct gpio_controller *__iomem g = get_irq_chip_data(irq); | ||
157 | u32 mask = __gpio_mask(irq_to_gpio(irq)); | ||
158 | |||
159 | if (irq_desc[irq].status & IRQ_TYPE_EDGE_FALLING) | ||
160 | __raw_writel(mask, &g->set_falling); | ||
161 | if (irq_desc[irq].status & IRQ_TYPE_EDGE_RISING) | ||
162 | __raw_writel(mask, &g->set_rising); | ||
163 | } | ||
164 | |||
165 | static int gpio_irq_type(unsigned irq, unsigned trigger) | ||
166 | { | ||
167 | struct gpio_controller *__iomem g = get_irq_chip_data(irq); | ||
168 | u32 mask = __gpio_mask(irq_to_gpio(irq)); | ||
169 | |||
170 | if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | ||
171 | return -EINVAL; | ||
172 | |||
173 | irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; | ||
174 | irq_desc[irq].status |= trigger; | ||
175 | |||
176 | __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING) | ||
177 | ? &g->set_falling : &g->clr_falling); | ||
178 | __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING) | ||
179 | ? &g->set_rising : &g->clr_rising); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static struct irq_chip gpio_irqchip = { | ||
184 | .name = "GPIO", | ||
185 | .enable = gpio_irq_enable, | ||
186 | .disable = gpio_irq_disable, | ||
187 | .set_type = gpio_irq_type, | ||
188 | }; | ||
189 | |||
190 | static void | ||
191 | gpio_irq_handler(unsigned irq, struct irq_desc *desc) | ||
192 | { | ||
193 | struct gpio_controller *__iomem g = get_irq_chip_data(irq); | ||
194 | u32 mask = 0xffff; | ||
195 | |||
196 | /* we only care about one bank */ | ||
197 | if (irq & 1) | ||
198 | mask <<= 16; | ||
199 | |||
200 | /* temporarily mask (level sensitive) parent IRQ */ | ||
201 | desc->chip->ack(irq); | ||
202 | while (1) { | ||
203 | u32 status; | ||
204 | struct irq_desc *gpio; | ||
205 | int n; | ||
206 | int res; | ||
207 | |||
208 | /* ack any irqs */ | ||
209 | status = __raw_readl(&g->intstat) & mask; | ||
210 | if (!status) | ||
211 | break; | ||
212 | __raw_writel(status, &g->intstat); | ||
213 | if (irq & 1) | ||
214 | status >>= 16; | ||
215 | |||
216 | /* now demux them to the right lowlevel handler */ | ||
217 | n = (int)get_irq_data(irq); | ||
218 | gpio = &irq_desc[n]; | ||
219 | while (status) { | ||
220 | res = ffs(status); | ||
221 | n += res; | ||
222 | gpio += res; | ||
223 | desc_handle_irq(n - 1, gpio - 1); | ||
224 | status >>= res; | ||
225 | } | ||
226 | } | ||
227 | desc->chip->unmask(irq); | ||
228 | /* now it may re-trigger */ | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * NOTE: for suspend/resume, probably best to make a sysdev (and class) | ||
233 | * with its suspend/resume calls hooking into the results of the set_wake() | ||
234 | * calls ... so if no gpios are wakeup events the clock can be disabled, | ||
235 | * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0 | ||
236 | * can be set appropriately for GPIOV33 pins. | ||
237 | */ | ||
238 | |||
239 | static int __init davinci_gpio_irq_setup(void) | ||
240 | { | ||
241 | unsigned gpio, irq, bank; | ||
242 | struct clk *clk; | ||
243 | |||
244 | clk = clk_get(NULL, "gpio"); | ||
245 | if (IS_ERR(clk)) { | ||
246 | printk(KERN_ERR "Error %ld getting gpio clock?\n", | ||
247 | PTR_ERR(clk)); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | clk_enable(clk); | ||
252 | |||
253 | for (gpio = 0, irq = gpio_to_irq(0), bank = IRQ_GPIOBNK0; | ||
254 | gpio < DAVINCI_N_GPIO; bank++) { | ||
255 | struct gpio_controller *__iomem g = gpio2controller(gpio); | ||
256 | unsigned i; | ||
257 | |||
258 | __raw_writel(~0, &g->clr_falling); | ||
259 | __raw_writel(~0, &g->clr_rising); | ||
260 | |||
261 | /* set up all irqs in this bank */ | ||
262 | set_irq_chained_handler(bank, gpio_irq_handler); | ||
263 | set_irq_chip_data(bank, g); | ||
264 | set_irq_data(bank, (void *)irq); | ||
265 | |||
266 | for (i = 0; i < 16 && gpio < DAVINCI_N_GPIO; | ||
267 | i++, irq++, gpio++) { | ||
268 | set_irq_chip(irq, &gpio_irqchip); | ||
269 | set_irq_chip_data(irq, g); | ||
270 | set_irq_handler(irq, handle_simple_irq); | ||
271 | set_irq_flags(irq, IRQF_VALID); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* BINTEN -- per-bank interrupt enable. genirq would also let these | ||
276 | * bits be set/cleared dynamically. | ||
277 | */ | ||
278 | __raw_writel(0x1f, (void *__iomem) | ||
279 | IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08)); | ||
280 | |||
281 | printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0)); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | arch_initcall(davinci_gpio_irq_setup); | ||
diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c index 87fae6fb6ecf..47787ff84a6a 100644 --- a/arch/arm/mach-davinci/io.c +++ b/arch/arm/mach-davinci/io.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/memory.h> | 17 | #include <asm/memory.h> |
18 | 18 | ||
19 | #include <asm/mach/map.h> | 19 | #include <asm/mach/map.h> |
20 | #include <asm/arch/clock.h> | ||
20 | 21 | ||
21 | extern void davinci_check_revision(void); | 22 | extern void davinci_check_revision(void); |
22 | 23 | ||
@@ -49,3 +50,8 @@ void __init davinci_map_common_io(void) | |||
49 | */ | 50 | */ |
50 | davinci_check_revision(); | 51 | davinci_check_revision(); |
51 | } | 52 | } |
53 | |||
54 | void __init davinci_init_common_hw(void) | ||
55 | { | ||
56 | davinci_clk_init(); | ||
57 | } | ||
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c new file mode 100644 index 000000000000..92d26bd305b7 --- /dev/null +++ b/arch/arm/mach-davinci/mux.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * DaVinci pin multiplexing configurations | ||
3 | * | ||
4 | * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com> | ||
5 | * | ||
6 | * 2007 (c) MontaVista Software, Inc. This file is licensed under | ||
7 | * the terms of the GNU General Public License version 2. This program | ||
8 | * is licensed "as is" without any warranty of any kind, whether express | ||
9 | * or implied. | ||
10 | */ | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | |||
14 | #include <asm/hardware.h> | ||
15 | |||
16 | #include <asm/arch/mux.h> | ||
17 | |||
18 | /* System control register offsets */ | ||
19 | #define PINMUX0 0x00 | ||
20 | #define PINMUX1 0x04 | ||
21 | |||
22 | static DEFINE_SPINLOCK(mux_lock); | ||
23 | |||
24 | void davinci_mux_peripheral(unsigned int mux, unsigned int enable) | ||
25 | { | ||
26 | u32 pinmux, muxreg = PINMUX0; | ||
27 | |||
28 | if (mux >= DAVINCI_MUX_LEVEL2) { | ||
29 | muxreg = PINMUX1; | ||
30 | mux -= DAVINCI_MUX_LEVEL2; | ||
31 | } | ||
32 | |||
33 | spin_lock(&mux_lock); | ||
34 | pinmux = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + muxreg); | ||
35 | if (enable) | ||
36 | pinmux |= (1 << mux); | ||
37 | else | ||
38 | pinmux &= ~(1 << mux); | ||
39 | davinci_writel(pinmux, DAVINCI_SYSTEM_MODULE_BASE + muxreg); | ||
40 | spin_unlock(&mux_lock); | ||
41 | } | ||
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index e1b0050283a6..1334416559ad 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c | |||
@@ -25,39 +25,40 @@ | |||
25 | #include <asm/io.h> | 25 | #include <asm/io.h> |
26 | #include <asm/hardware.h> | 26 | #include <asm/hardware.h> |
27 | #include <asm/arch/psc.h> | 27 | #include <asm/arch/psc.h> |
28 | #include <asm/arch/mux.h> | ||
28 | 29 | ||
29 | #define PTCMD __REG(0x01C41120) | 30 | /* PSC register offsets */ |
30 | #define PDSTAT __REG(0x01C41200) | 31 | #define EPCPR 0x070 |
31 | #define PDCTL1 __REG(0x01C41304) | 32 | #define PTCMD 0x120 |
32 | #define EPCPR __REG(0x01C41070) | 33 | #define PTSTAT 0x128 |
33 | #define PTSTAT __REG(0x01C41128) | 34 | #define PDSTAT 0x200 |
35 | #define PDCTL1 0x304 | ||
36 | #define MDSTAT 0x800 | ||
37 | #define MDCTL 0xA00 | ||
34 | 38 | ||
35 | #define MDSTAT IO_ADDRESS(0x01C41800) | 39 | /* System control register offsets */ |
36 | #define MDCTL IO_ADDRESS(0x01C41A00) | 40 | #define VDD3P3V_PWDN 0x48 |
37 | |||
38 | #define PINMUX0 __REG(0x01c40000) | ||
39 | #define PINMUX1 __REG(0x01c40004) | ||
40 | #define VDD3P3V_PWDN __REG(0x01C40048) | ||
41 | 41 | ||
42 | static void davinci_psc_mux(unsigned int id) | 42 | static void davinci_psc_mux(unsigned int id) |
43 | { | 43 | { |
44 | switch (id) { | 44 | switch (id) { |
45 | case DAVINCI_LPSC_ATA: | 45 | case DAVINCI_LPSC_ATA: |
46 | PINMUX0 |= (1 << 17) | (1 << 16); | 46 | davinci_mux_peripheral(DAVINCI_MUX_HDIREN, 1); |
47 | davinci_mux_peripheral(DAVINCI_MUX_ATAEN, 1); | ||
47 | break; | 48 | break; |
48 | case DAVINCI_LPSC_MMC_SD: | 49 | case DAVINCI_LPSC_MMC_SD: |
49 | /* VDD power manupulations are done in U-Boot for CPMAC | 50 | /* VDD power manupulations are done in U-Boot for CPMAC |
50 | * so applies to MMC as well | 51 | * so applies to MMC as well |
51 | */ | 52 | */ |
52 | /*Set up the pull regiter for MMC */ | 53 | /*Set up the pull regiter for MMC */ |
53 | VDD3P3V_PWDN = 0x0; | 54 | davinci_writel(0, DAVINCI_SYSTEM_MODULE_BASE + VDD3P3V_PWDN); |
54 | PINMUX1 &= (~(1 << 9)); | 55 | davinci_mux_peripheral(DAVINCI_MUX_MSTK, 0); |
55 | break; | 56 | break; |
56 | case DAVINCI_LPSC_I2C: | 57 | case DAVINCI_LPSC_I2C: |
57 | PINMUX1 |= (1 << 7); | 58 | davinci_mux_peripheral(DAVINCI_MUX_I2C, 1); |
58 | break; | 59 | break; |
59 | case DAVINCI_LPSC_McBSP: | 60 | case DAVINCI_LPSC_McBSP: |
60 | PINMUX1 |= (1 << 10); | 61 | davinci_mux_peripheral(DAVINCI_MUX_ASP, 1); |
61 | break; | 62 | break; |
62 | default: | 63 | default: |
63 | break; | 64 | break; |
@@ -67,33 +68,59 @@ static void davinci_psc_mux(unsigned int id) | |||
67 | /* Enable or disable a PSC domain */ | 68 | /* Enable or disable a PSC domain */ |
68 | void davinci_psc_config(unsigned int domain, unsigned int id, char enable) | 69 | void davinci_psc_config(unsigned int domain, unsigned int id, char enable) |
69 | { | 70 | { |
70 | volatile unsigned int *mdstat = (unsigned int *)((int)MDSTAT + 4 * id); | 71 | u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl, mdstat_mask; |
71 | volatile unsigned int *mdctl = (unsigned int *)((int)MDCTL + 4 * id); | ||
72 | 72 | ||
73 | if (id < 0) | 73 | if (id < 0) |
74 | return; | 74 | return; |
75 | 75 | ||
76 | mdctl = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id); | ||
76 | if (enable) | 77 | if (enable) |
77 | *mdctl |= 0x00000003; /* Enable Module */ | 78 | mdctl |= 0x00000003; /* Enable Module */ |
78 | else | 79 | else |
79 | *mdctl &= 0xFFFFFFF2; /* Disable Module */ | 80 | mdctl &= 0xFFFFFFF2; /* Disable Module */ |
81 | davinci_writel(mdctl, DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id); | ||
82 | |||
83 | pdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDSTAT); | ||
84 | if ((pdstat & 0x00000001) == 0) { | ||
85 | pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); | ||
86 | pdctl1 |= 0x1; | ||
87 | davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); | ||
88 | |||
89 | ptcmd = 1 << domain; | ||
90 | davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD); | ||
80 | 91 | ||
81 | if ((PDSTAT & 0x00000001) == 0) { | 92 | do { |
82 | PDCTL1 |= 0x1; | 93 | epcpr = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + |
83 | PTCMD = (1 << domain); | 94 | EPCPR); |
84 | while ((((EPCPR >> domain) & 1) == 0)); | 95 | } while ((((epcpr >> domain) & 1) == 0)); |
85 | 96 | ||
86 | PDCTL1 |= 0x100; | 97 | pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); |
87 | while (!(((PTSTAT >> domain) & 1) == 0)); | 98 | pdctl1 |= 0x100; |
99 | davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); | ||
100 | |||
101 | do { | ||
102 | ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + | ||
103 | PTSTAT); | ||
104 | } while (!(((ptstat >> domain) & 1) == 0)); | ||
88 | } else { | 105 | } else { |
89 | PTCMD = (1 << domain); | 106 | ptcmd = 1 << domain; |
90 | while (!(((PTSTAT >> domain) & 1) == 0)); | 107 | davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD); |
108 | |||
109 | do { | ||
110 | ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + | ||
111 | PTSTAT); | ||
112 | } while (!(((ptstat >> domain) & 1) == 0)); | ||
91 | } | 113 | } |
92 | 114 | ||
93 | if (enable) | 115 | if (enable) |
94 | while (!((*mdstat & 0x0000001F) == 0x3)); | 116 | mdstat_mask = 0x3; |
95 | else | 117 | else |
96 | while (!((*mdstat & 0x0000001F) == 0x2)); | 118 | mdstat_mask = 0x2; |
119 | |||
120 | do { | ||
121 | mdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + | ||
122 | MDSTAT + 4 * id); | ||
123 | } while (!((mdstat & 0x0000001F) == mdstat_mask)); | ||
97 | 124 | ||
98 | if (enable) | 125 | if (enable) |
99 | davinci_psc_mux(id); | 126 | davinci_psc_mux(id); |