diff options
author | root <root@dyn-67.arm.linux.org.uk> | 2009-03-24 18:04:25 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-03-24 18:04:25 -0400 |
commit | 9a38e989b8ce04923f919fc2a8a24eb07fb484e2 (patch) | |
tree | 6b99638dc32b99420ada46ca8d1373ad7aa5a208 /arch/arm/plat-pxa | |
parent | 7d83f8fca517b123cf0136503a9e50974f65ec49 (diff) | |
parent | 5fa82eb8ff06cd3ac4d64c6875922ae1dfa003c5 (diff) |
Merge branch 'devel' of git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6 into devel
Diffstat (limited to 'arch/arm/plat-pxa')
-rw-r--r-- | arch/arm/plat-pxa/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/plat-pxa/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/plat-pxa/dma.c | 144 | ||||
-rw-r--r-- | arch/arm/plat-pxa/gpio.c | 337 | ||||
-rw-r--r-- | arch/arm/plat-pxa/include/plat/dma.h | 85 | ||||
-rw-r--r-- | arch/arm/plat-pxa/include/plat/gpio.h | 62 | ||||
-rw-r--r-- | arch/arm/plat-pxa/include/plat/mfp.h | 399 | ||||
-rw-r--r-- | arch/arm/plat-pxa/mfp.c | 278 |
8 files changed, 1315 insertions, 0 deletions
diff --git a/arch/arm/plat-pxa/Kconfig b/arch/arm/plat-pxa/Kconfig new file mode 100644 index 000000000000..b158e98038ed --- /dev/null +++ b/arch/arm/plat-pxa/Kconfig | |||
@@ -0,0 +1,3 @@ | |||
1 | if PLAT_PXA | ||
2 | |||
3 | endif | ||
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile new file mode 100644 index 000000000000..4be37235f57b --- /dev/null +++ b/arch/arm/plat-pxa/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for code common across different PXA processor families | ||
3 | # | ||
4 | |||
5 | obj-y := dma.o mfp.o | ||
6 | |||
7 | obj-$(CONFIG_GENERIC_GPIO) += gpio.o | ||
diff --git a/arch/arm/plat-pxa/dma.c b/arch/arm/plat-pxa/dma.c new file mode 100644 index 000000000000..70aeee407f7d --- /dev/null +++ b/arch/arm/plat-pxa/dma.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-pxa/dma.c | ||
3 | * | ||
4 | * PXA DMA registration and IRQ dispatching | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Nov 15, 2001 | ||
8 | * Copyright: MontaVista Software Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/errno.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <mach/hardware.h> | ||
24 | #include <mach/dma.h> | ||
25 | |||
26 | struct dma_channel { | ||
27 | char *name; | ||
28 | pxa_dma_prio prio; | ||
29 | void (*irq_handler)(int, void *); | ||
30 | void *data; | ||
31 | }; | ||
32 | |||
33 | static struct dma_channel *dma_channels; | ||
34 | static int num_dma_channels; | ||
35 | |||
36 | int pxa_request_dma (char *name, pxa_dma_prio prio, | ||
37 | void (*irq_handler)(int, void *), | ||
38 | void *data) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | int i, found = 0; | ||
42 | |||
43 | /* basic sanity checks */ | ||
44 | if (!name || !irq_handler) | ||
45 | return -EINVAL; | ||
46 | |||
47 | local_irq_save(flags); | ||
48 | |||
49 | do { | ||
50 | /* try grabbing a DMA channel with the requested priority */ | ||
51 | for (i = 0; i < num_dma_channels; i++) { | ||
52 | if ((dma_channels[i].prio == prio) && | ||
53 | !dma_channels[i].name) { | ||
54 | found = 1; | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | /* if requested prio group is full, try a hier priority */ | ||
59 | } while (!found && prio--); | ||
60 | |||
61 | if (found) { | ||
62 | DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; | ||
63 | dma_channels[i].name = name; | ||
64 | dma_channels[i].irq_handler = irq_handler; | ||
65 | dma_channels[i].data = data; | ||
66 | } else { | ||
67 | printk (KERN_WARNING "No more available DMA channels for %s\n", name); | ||
68 | i = -ENODEV; | ||
69 | } | ||
70 | |||
71 | local_irq_restore(flags); | ||
72 | return i; | ||
73 | } | ||
74 | |||
75 | void pxa_free_dma (int dma_ch) | ||
76 | { | ||
77 | unsigned long flags; | ||
78 | |||
79 | if (!dma_channels[dma_ch].name) { | ||
80 | printk (KERN_CRIT | ||
81 | "%s: trying to free channel %d which is already freed\n", | ||
82 | __func__, dma_ch); | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | local_irq_save(flags); | ||
87 | DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; | ||
88 | dma_channels[dma_ch].name = NULL; | ||
89 | local_irq_restore(flags); | ||
90 | } | ||
91 | |||
92 | static irqreturn_t dma_irq_handler(int irq, void *dev_id) | ||
93 | { | ||
94 | int i, dint = DINT; | ||
95 | |||
96 | for (i = 0; i < num_dma_channels; i++) { | ||
97 | if (dint & (1 << i)) { | ||
98 | struct dma_channel *channel = &dma_channels[i]; | ||
99 | if (channel->name && channel->irq_handler) { | ||
100 | channel->irq_handler(i, channel->data); | ||
101 | } else { | ||
102 | /* | ||
103 | * IRQ for an unregistered DMA channel: | ||
104 | * let's clear the interrupts and disable it. | ||
105 | */ | ||
106 | printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i); | ||
107 | DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | return IRQ_HANDLED; | ||
112 | } | ||
113 | |||
114 | int __init pxa_init_dma(int irq, int num_ch) | ||
115 | { | ||
116 | int i, ret; | ||
117 | |||
118 | dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL); | ||
119 | if (dma_channels == NULL) | ||
120 | return -ENOMEM; | ||
121 | |||
122 | /* dma channel priorities on pxa2xx processors: | ||
123 | * ch 0 - 3, 16 - 19 <--> (0) DMA_PRIO_HIGH | ||
124 | * ch 4 - 7, 20 - 23 <--> (1) DMA_PRIO_MEDIUM | ||
125 | * ch 8 - 15, 24 - 31 <--> (2) DMA_PRIO_LOW | ||
126 | */ | ||
127 | for (i = 0; i < num_ch; i++) { | ||
128 | DCSR(i) = 0; | ||
129 | dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW); | ||
130 | } | ||
131 | |||
132 | ret = request_irq(irq, dma_irq_handler, IRQF_DISABLED, "DMA", NULL); | ||
133 | if (ret) { | ||
134 | printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); | ||
135 | kfree(dma_channels); | ||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | num_dma_channels = num_ch; | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | EXPORT_SYMBOL(pxa_request_dma); | ||
144 | EXPORT_SYMBOL(pxa_free_dma); | ||
diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c new file mode 100644 index 000000000000..af819bf21b63 --- /dev/null +++ b/arch/arm/plat-pxa/gpio.c | |||
@@ -0,0 +1,337 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-pxa/gpio.c | ||
3 | * | ||
4 | * Generic PXA GPIO handling | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Jun 15, 2001 | ||
8 | * Copyright: MontaVista Software Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/sysdev.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | |||
21 | #include <mach/gpio.h> | ||
22 | |||
23 | int pxa_last_gpio; | ||
24 | |||
25 | struct pxa_gpio_chip { | ||
26 | struct gpio_chip chip; | ||
27 | void __iomem *regbase; | ||
28 | char label[10]; | ||
29 | |||
30 | unsigned long irq_mask; | ||
31 | unsigned long irq_edge_rise; | ||
32 | unsigned long irq_edge_fall; | ||
33 | |||
34 | #ifdef CONFIG_PM | ||
35 | unsigned long saved_gplr; | ||
36 | unsigned long saved_gpdr; | ||
37 | unsigned long saved_grer; | ||
38 | unsigned long saved_gfer; | ||
39 | #endif | ||
40 | }; | ||
41 | |||
42 | static DEFINE_SPINLOCK(gpio_lock); | ||
43 | static struct pxa_gpio_chip *pxa_gpio_chips; | ||
44 | |||
45 | #define for_each_gpio_chip(i, c) \ | ||
46 | for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) | ||
47 | |||
48 | static inline void __iomem *gpio_chip_base(struct gpio_chip *c) | ||
49 | { | ||
50 | return container_of(c, struct pxa_gpio_chip, chip)->regbase; | ||
51 | } | ||
52 | |||
53 | static inline struct pxa_gpio_chip *gpio_to_chip(unsigned gpio) | ||
54 | { | ||
55 | return &pxa_gpio_chips[gpio_to_bank(gpio)]; | ||
56 | } | ||
57 | |||
58 | static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
59 | { | ||
60 | void __iomem *base = gpio_chip_base(chip); | ||
61 | uint32_t value, mask = 1 << offset; | ||
62 | unsigned long flags; | ||
63 | |||
64 | spin_lock_irqsave(&gpio_lock, flags); | ||
65 | |||
66 | value = __raw_readl(base + GPDR_OFFSET); | ||
67 | if (__gpio_is_inverted(chip->base + offset)) | ||
68 | value |= mask; | ||
69 | else | ||
70 | value &= ~mask; | ||
71 | __raw_writel(value, base + GPDR_OFFSET); | ||
72 | |||
73 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int pxa_gpio_direction_output(struct gpio_chip *chip, | ||
78 | unsigned offset, int value) | ||
79 | { | ||
80 | void __iomem *base = gpio_chip_base(chip); | ||
81 | uint32_t tmp, mask = 1 << offset; | ||
82 | unsigned long flags; | ||
83 | |||
84 | __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); | ||
85 | |||
86 | spin_lock_irqsave(&gpio_lock, flags); | ||
87 | |||
88 | tmp = __raw_readl(base + GPDR_OFFSET); | ||
89 | if (__gpio_is_inverted(chip->base + offset)) | ||
90 | tmp &= ~mask; | ||
91 | else | ||
92 | tmp |= mask; | ||
93 | __raw_writel(tmp, base + GPDR_OFFSET); | ||
94 | |||
95 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
100 | { | ||
101 | return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); | ||
102 | } | ||
103 | |||
104 | static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
105 | { | ||
106 | __raw_writel(1 << offset, gpio_chip_base(chip) + | ||
107 | (value ? GPSR_OFFSET : GPCR_OFFSET)); | ||
108 | } | ||
109 | |||
110 | static int __init pxa_init_gpio_chip(int gpio_end) | ||
111 | { | ||
112 | int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; | ||
113 | struct pxa_gpio_chip *chips; | ||
114 | |||
115 | /* this is early, we have to use bootmem allocator, and we really | ||
116 | * want this to be allocated dynamically for different 'gpio_end' | ||
117 | */ | ||
118 | chips = alloc_bootmem_low(nbanks * sizeof(struct pxa_gpio_chip)); | ||
119 | if (chips == NULL) { | ||
120 | pr_err("%s: failed to allocate GPIO chips\n", __func__); | ||
121 | return -ENOMEM; | ||
122 | } | ||
123 | |||
124 | for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { | ||
125 | struct gpio_chip *c = &chips[i].chip; | ||
126 | |||
127 | sprintf(chips[i].label, "gpio-%d", i); | ||
128 | chips[i].regbase = (void __iomem *)GPIO_BANK(i); | ||
129 | |||
130 | c->base = gpio; | ||
131 | c->label = chips[i].label; | ||
132 | |||
133 | c->direction_input = pxa_gpio_direction_input; | ||
134 | c->direction_output = pxa_gpio_direction_output; | ||
135 | c->get = pxa_gpio_get; | ||
136 | c->set = pxa_gpio_set; | ||
137 | |||
138 | /* number of GPIOs on last bank may be less than 32 */ | ||
139 | c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32; | ||
140 | gpiochip_add(c); | ||
141 | } | ||
142 | pxa_gpio_chips = chips; | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) | ||
147 | { | ||
148 | struct pxa_gpio_chip *c; | ||
149 | int gpio = irq_to_gpio(irq); | ||
150 | unsigned long gpdr, mask = GPIO_bit(gpio); | ||
151 | |||
152 | c = gpio_to_chip(gpio); | ||
153 | |||
154 | if (type == IRQ_TYPE_PROBE) { | ||
155 | /* Don't mess with enabled GPIOs using preconfigured edges or | ||
156 | * GPIOs set to alternate function or to output during probe | ||
157 | */ | ||
158 | if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio)) | ||
159 | return 0; | ||
160 | |||
161 | if (__gpio_is_occupied(gpio)) | ||
162 | return 0; | ||
163 | |||
164 | type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | ||
165 | } | ||
166 | |||
167 | gpdr = __raw_readl(c->regbase + GPDR_OFFSET); | ||
168 | |||
169 | if (__gpio_is_inverted(gpio)) | ||
170 | __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET); | ||
171 | else | ||
172 | __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET); | ||
173 | |||
174 | if (type & IRQ_TYPE_EDGE_RISING) | ||
175 | c->irq_edge_rise |= mask; | ||
176 | else | ||
177 | c->irq_edge_rise &= ~mask; | ||
178 | |||
179 | if (type & IRQ_TYPE_EDGE_FALLING) | ||
180 | c->irq_edge_fall |= mask; | ||
181 | else | ||
182 | c->irq_edge_fall &= ~mask; | ||
183 | |||
184 | __raw_writel(c->irq_edge_rise & c->irq_mask, c->regbase + GRER_OFFSET); | ||
185 | __raw_writel(c->irq_edge_fall & c->irq_mask, c->regbase + GFER_OFFSET); | ||
186 | |||
187 | pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, irq, gpio, | ||
188 | ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""), | ||
189 | ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : "")); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) | ||
194 | { | ||
195 | struct pxa_gpio_chip *c; | ||
196 | int loop, gpio, gpio_base, n; | ||
197 | unsigned long gedr; | ||
198 | |||
199 | do { | ||
200 | loop = 0; | ||
201 | for_each_gpio_chip(gpio, c) { | ||
202 | gpio_base = c->chip.base; | ||
203 | |||
204 | gedr = __raw_readl(c->regbase + GEDR_OFFSET); | ||
205 | gedr = gedr & c->irq_mask; | ||
206 | __raw_writel(gedr, c->regbase + GEDR_OFFSET); | ||
207 | |||
208 | n = find_first_bit(&gedr, BITS_PER_LONG); | ||
209 | while (n < BITS_PER_LONG) { | ||
210 | loop = 1; | ||
211 | |||
212 | generic_handle_irq(gpio_to_irq(gpio_base + n)); | ||
213 | n = find_next_bit(&gedr, BITS_PER_LONG, n + 1); | ||
214 | } | ||
215 | } | ||
216 | } while (loop); | ||
217 | } | ||
218 | |||
219 | static void pxa_ack_muxed_gpio(unsigned int irq) | ||
220 | { | ||
221 | int gpio = irq_to_gpio(irq); | ||
222 | struct pxa_gpio_chip *c = gpio_to_chip(gpio); | ||
223 | |||
224 | __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); | ||
225 | } | ||
226 | |||
227 | static void pxa_mask_muxed_gpio(unsigned int irq) | ||
228 | { | ||
229 | int gpio = irq_to_gpio(irq); | ||
230 | struct pxa_gpio_chip *c = gpio_to_chip(gpio); | ||
231 | uint32_t grer, gfer; | ||
232 | |||
233 | c->irq_mask &= ~GPIO_bit(gpio); | ||
234 | |||
235 | grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio); | ||
236 | gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio); | ||
237 | __raw_writel(grer, c->regbase + GRER_OFFSET); | ||
238 | __raw_writel(gfer, c->regbase + GFER_OFFSET); | ||
239 | } | ||
240 | |||
241 | static void pxa_unmask_muxed_gpio(unsigned int irq) | ||
242 | { | ||
243 | int gpio = irq_to_gpio(irq); | ||
244 | struct pxa_gpio_chip *c = gpio_to_chip(gpio); | ||
245 | |||
246 | c->irq_mask |= GPIO_bit(gpio); | ||
247 | __raw_writel(c->irq_edge_rise & c->irq_mask, c->regbase + GRER_OFFSET); | ||
248 | __raw_writel(c->irq_edge_fall & c->irq_mask, c->regbase + GFER_OFFSET); | ||
249 | } | ||
250 | |||
251 | static struct irq_chip pxa_muxed_gpio_chip = { | ||
252 | .name = "GPIO", | ||
253 | .ack = pxa_ack_muxed_gpio, | ||
254 | .mask = pxa_mask_muxed_gpio, | ||
255 | .unmask = pxa_unmask_muxed_gpio, | ||
256 | .set_type = pxa_gpio_irq_type, | ||
257 | }; | ||
258 | |||
259 | void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) | ||
260 | { | ||
261 | struct pxa_gpio_chip *c; | ||
262 | int gpio, irq; | ||
263 | |||
264 | pxa_last_gpio = end; | ||
265 | |||
266 | /* Initialize GPIO chips */ | ||
267 | pxa_init_gpio_chip(end); | ||
268 | |||
269 | /* clear all GPIO edge detects */ | ||
270 | for_each_gpio_chip(gpio, c) { | ||
271 | __raw_writel(0, c->regbase + GFER_OFFSET); | ||
272 | __raw_writel(0, c->regbase + GRER_OFFSET); | ||
273 | __raw_writel(~0,c->regbase + GEDR_OFFSET); | ||
274 | } | ||
275 | |||
276 | for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) { | ||
277 | set_irq_chip(irq, &pxa_muxed_gpio_chip); | ||
278 | set_irq_handler(irq, handle_edge_irq); | ||
279 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
280 | } | ||
281 | |||
282 | /* Install handler for GPIO>=2 edge detect interrupts */ | ||
283 | set_irq_chained_handler(mux_irq, pxa_gpio_demux_handler); | ||
284 | pxa_muxed_gpio_chip.set_wake = fn; | ||
285 | } | ||
286 | |||
287 | #ifdef CONFIG_PM | ||
288 | static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) | ||
289 | { | ||
290 | struct pxa_gpio_chip *c; | ||
291 | int gpio; | ||
292 | |||
293 | for_each_gpio_chip(gpio, c) { | ||
294 | c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET); | ||
295 | c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET); | ||
296 | c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET); | ||
297 | c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET); | ||
298 | |||
299 | /* Clear GPIO transition detect bits */ | ||
300 | __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET); | ||
301 | } | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int pxa_gpio_resume(struct sys_device *dev) | ||
306 | { | ||
307 | struct pxa_gpio_chip *c; | ||
308 | int gpio; | ||
309 | |||
310 | for_each_gpio_chip(gpio, c) { | ||
311 | /* restore level with set/clear */ | ||
312 | __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET); | ||
313 | __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET); | ||
314 | |||
315 | __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET); | ||
316 | __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); | ||
317 | __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); | ||
318 | } | ||
319 | return 0; | ||
320 | } | ||
321 | #else | ||
322 | #define pxa_gpio_suspend NULL | ||
323 | #define pxa_gpio_resume NULL | ||
324 | #endif | ||
325 | |||
326 | struct sysdev_class pxa_gpio_sysclass = { | ||
327 | .name = "gpio", | ||
328 | .suspend = pxa_gpio_suspend, | ||
329 | .resume = pxa_gpio_resume, | ||
330 | }; | ||
331 | |||
332 | static int __init pxa_gpio_init(void) | ||
333 | { | ||
334 | return sysdev_class_register(&pxa_gpio_sysclass); | ||
335 | } | ||
336 | |||
337 | core_initcall(pxa_gpio_init); | ||
diff --git a/arch/arm/plat-pxa/include/plat/dma.h b/arch/arm/plat-pxa/include/plat/dma.h new file mode 100644 index 000000000000..a7b91dc06852 --- /dev/null +++ b/arch/arm/plat-pxa/include/plat/dma.h | |||
@@ -0,0 +1,85 @@ | |||
1 | #ifndef __PLAT_DMA_H | ||
2 | #define __PLAT_DMA_H | ||
3 | |||
4 | #define DMAC_REG(x) (*((volatile u32 *)(DMAC_REGS_VIRT + (x)))) | ||
5 | |||
6 | #define DCSR(n) DMAC_REG((n) << 2) | ||
7 | #define DALGN DMAC_REG(0x00a0) /* DMA Alignment Register */ | ||
8 | #define DINT DMAC_REG(0x00f0) /* DMA Interrupt Register */ | ||
9 | #define DDADR(n) DMAC_REG(0x0200 + ((n) << 4)) | ||
10 | #define DSADR(n) DMAC_REG(0x0204 + ((n) << 4)) | ||
11 | #define DTADR(n) DMAC_REG(0x0208 + ((n) << 4)) | ||
12 | #define DCMD(n) DMAC_REG(0x020c + ((n) << 4)) | ||
13 | #define DRCMR(n) DMAC_REG((((n) < 64) ? 0x0100 : 0x1100) + \ | ||
14 | (((n) & 0x3f) << 2)) | ||
15 | |||
16 | #define DCSR_RUN (1 << 31) /* Run Bit (read / write) */ | ||
17 | #define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */ | ||
18 | #define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */ | ||
19 | #define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */ | ||
20 | #define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */ | ||
21 | #define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */ | ||
22 | #define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */ | ||
23 | #define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */ | ||
24 | |||
25 | #define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable (R/W) */ | ||
26 | #define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */ | ||
27 | #define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */ | ||
28 | #define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */ | ||
29 | #define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */ | ||
30 | #define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */ | ||
31 | #define DCSR_EORINTR (1 << 9) /* The end of Receive */ | ||
32 | |||
33 | #define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */ | ||
34 | #define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ | ||
35 | |||
36 | #define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ | ||
37 | #define DDADR_STOP (1 << 0) /* Stop (read / write) */ | ||
38 | |||
39 | #define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */ | ||
40 | #define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */ | ||
41 | #define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */ | ||
42 | #define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */ | ||
43 | #define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */ | ||
44 | #define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */ | ||
45 | #define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */ | ||
46 | #define DCMD_BURST8 (1 << 16) /* 8 byte burst */ | ||
47 | #define DCMD_BURST16 (2 << 16) /* 16 byte burst */ | ||
48 | #define DCMD_BURST32 (3 << 16) /* 32 byte burst */ | ||
49 | #define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ | ||
50 | #define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ | ||
51 | #define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ | ||
52 | #define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ | ||
53 | |||
54 | /* | ||
55 | * Descriptor structure for PXA's DMA engine | ||
56 | * Note: this structure must always be aligned to a 16-byte boundary. | ||
57 | */ | ||
58 | |||
59 | typedef struct pxa_dma_desc { | ||
60 | volatile u32 ddadr; /* Points to the next descriptor + flags */ | ||
61 | volatile u32 dsadr; /* DSADR value for the current transfer */ | ||
62 | volatile u32 dtadr; /* DTADR value for the current transfer */ | ||
63 | volatile u32 dcmd; /* DCMD value for the current transfer */ | ||
64 | } pxa_dma_desc; | ||
65 | |||
66 | typedef enum { | ||
67 | DMA_PRIO_HIGH = 0, | ||
68 | DMA_PRIO_MEDIUM = 1, | ||
69 | DMA_PRIO_LOW = 2 | ||
70 | } pxa_dma_prio; | ||
71 | |||
72 | /* | ||
73 | * DMA registration | ||
74 | */ | ||
75 | |||
76 | int __init pxa_init_dma(int irq, int num_ch); | ||
77 | |||
78 | int pxa_request_dma (char *name, | ||
79 | pxa_dma_prio prio, | ||
80 | void (*irq_handler)(int, void *), | ||
81 | void *data); | ||
82 | |||
83 | void pxa_free_dma (int dma_ch); | ||
84 | |||
85 | #endif /* __PLAT_DMA_H */ | ||
diff --git a/arch/arm/plat-pxa/include/plat/gpio.h b/arch/arm/plat-pxa/include/plat/gpio.h new file mode 100644 index 000000000000..44248cb926a5 --- /dev/null +++ b/arch/arm/plat-pxa/include/plat/gpio.h | |||
@@ -0,0 +1,62 @@ | |||
1 | #ifndef __PLAT_GPIO_H | ||
2 | #define __PLAT_GPIO_H | ||
3 | |||
4 | /* | ||
5 | * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with | ||
6 | * one set of registers. The register offsets are organized below: | ||
7 | * | ||
8 | * GPLR GPDR GPSR GPCR GRER GFER GEDR | ||
9 | * BANK 0 - 0x0000 0x000C 0x0018 0x0024 0x0030 0x003C 0x0048 | ||
10 | * BANK 1 - 0x0004 0x0010 0x001C 0x0028 0x0034 0x0040 0x004C | ||
11 | * BANK 2 - 0x0008 0x0014 0x0020 0x002C 0x0038 0x0044 0x0050 | ||
12 | * | ||
13 | * BANK 3 - 0x0100 0x010C 0x0118 0x0124 0x0130 0x013C 0x0148 | ||
14 | * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C | ||
15 | * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 | ||
16 | * | ||
17 | * NOTE: | ||
18 | * BANK 3 is only available on PXA27x and later processors. | ||
19 | * BANK 4 and 5 are only available on PXA935 | ||
20 | */ | ||
21 | |||
22 | #define GPIO_BANK(n) (GPIO_REGS_VIRT + BANK_OFF(n)) | ||
23 | |||
24 | #define GPLR_OFFSET 0x00 | ||
25 | #define GPDR_OFFSET 0x0C | ||
26 | #define GPSR_OFFSET 0x18 | ||
27 | #define GPCR_OFFSET 0x24 | ||
28 | #define GRER_OFFSET 0x30 | ||
29 | #define GFER_OFFSET 0x3C | ||
30 | #define GEDR_OFFSET 0x48 | ||
31 | |||
32 | static inline int gpio_get_value(unsigned gpio) | ||
33 | { | ||
34 | if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) | ||
35 | return GPLR(gpio) & GPIO_bit(gpio); | ||
36 | else | ||
37 | return __gpio_get_value(gpio); | ||
38 | } | ||
39 | |||
40 | static inline void gpio_set_value(unsigned gpio, int value) | ||
41 | { | ||
42 | if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) { | ||
43 | if (value) | ||
44 | GPSR(gpio) = GPIO_bit(gpio); | ||
45 | else | ||
46 | GPCR(gpio) = GPIO_bit(gpio); | ||
47 | } else | ||
48 | __gpio_set_value(gpio, value); | ||
49 | } | ||
50 | |||
51 | #define gpio_cansleep __gpio_cansleep | ||
52 | |||
53 | /* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85). | ||
54 | * Those cases currently cause holes in the GPIO number space, the | ||
55 | * actual number of the last GPIO is recorded by 'pxa_last_gpio'. | ||
56 | */ | ||
57 | extern int pxa_last_gpio; | ||
58 | |||
59 | typedef int (*set_wake_t)(unsigned int irq, unsigned int on); | ||
60 | |||
61 | extern void pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn); | ||
62 | #endif /* __PLAT_GPIO_H */ | ||
diff --git a/arch/arm/plat-pxa/include/plat/mfp.h b/arch/arm/plat-pxa/include/plat/mfp.h new file mode 100644 index 000000000000..64019464c8db --- /dev/null +++ b/arch/arm/plat-pxa/include/plat/mfp.h | |||
@@ -0,0 +1,399 @@ | |||
1 | /* | ||
2 | * arch/arm/plat-pxa/include/plat/mfp.h | ||
3 | * | ||
4 | * Common Multi-Function Pin Definitions | ||
5 | * | ||
6 | * Copyright (C) 2007 Marvell International Ltd. | ||
7 | * | ||
8 | * 2007-8-21: eric miao <eric.miao@marvell.com> | ||
9 | * initial version | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #ifndef __ASM_PLAT_MFP_H | ||
17 | #define __ASM_PLAT_MFP_H | ||
18 | |||
19 | #define mfp_to_gpio(m) ((m) % 128) | ||
20 | |||
21 | /* list of all the configurable MFP pins */ | ||
22 | enum { | ||
23 | MFP_PIN_INVALID = -1, | ||
24 | |||
25 | MFP_PIN_GPIO0 = 0, | ||
26 | MFP_PIN_GPIO1, | ||
27 | MFP_PIN_GPIO2, | ||
28 | MFP_PIN_GPIO3, | ||
29 | MFP_PIN_GPIO4, | ||
30 | MFP_PIN_GPIO5, | ||
31 | MFP_PIN_GPIO6, | ||
32 | MFP_PIN_GPIO7, | ||
33 | MFP_PIN_GPIO8, | ||
34 | MFP_PIN_GPIO9, | ||
35 | MFP_PIN_GPIO10, | ||
36 | MFP_PIN_GPIO11, | ||
37 | MFP_PIN_GPIO12, | ||
38 | MFP_PIN_GPIO13, | ||
39 | MFP_PIN_GPIO14, | ||
40 | MFP_PIN_GPIO15, | ||
41 | MFP_PIN_GPIO16, | ||
42 | MFP_PIN_GPIO17, | ||
43 | MFP_PIN_GPIO18, | ||
44 | MFP_PIN_GPIO19, | ||
45 | MFP_PIN_GPIO20, | ||
46 | MFP_PIN_GPIO21, | ||
47 | MFP_PIN_GPIO22, | ||
48 | MFP_PIN_GPIO23, | ||
49 | MFP_PIN_GPIO24, | ||
50 | MFP_PIN_GPIO25, | ||
51 | MFP_PIN_GPIO26, | ||
52 | MFP_PIN_GPIO27, | ||
53 | MFP_PIN_GPIO28, | ||
54 | MFP_PIN_GPIO29, | ||
55 | MFP_PIN_GPIO30, | ||
56 | MFP_PIN_GPIO31, | ||
57 | MFP_PIN_GPIO32, | ||
58 | MFP_PIN_GPIO33, | ||
59 | MFP_PIN_GPIO34, | ||
60 | MFP_PIN_GPIO35, | ||
61 | MFP_PIN_GPIO36, | ||
62 | MFP_PIN_GPIO37, | ||
63 | MFP_PIN_GPIO38, | ||
64 | MFP_PIN_GPIO39, | ||
65 | MFP_PIN_GPIO40, | ||
66 | MFP_PIN_GPIO41, | ||
67 | MFP_PIN_GPIO42, | ||
68 | MFP_PIN_GPIO43, | ||
69 | MFP_PIN_GPIO44, | ||
70 | MFP_PIN_GPIO45, | ||
71 | MFP_PIN_GPIO46, | ||
72 | MFP_PIN_GPIO47, | ||
73 | MFP_PIN_GPIO48, | ||
74 | MFP_PIN_GPIO49, | ||
75 | MFP_PIN_GPIO50, | ||
76 | MFP_PIN_GPIO51, | ||
77 | MFP_PIN_GPIO52, | ||
78 | MFP_PIN_GPIO53, | ||
79 | MFP_PIN_GPIO54, | ||
80 | MFP_PIN_GPIO55, | ||
81 | MFP_PIN_GPIO56, | ||
82 | MFP_PIN_GPIO57, | ||
83 | MFP_PIN_GPIO58, | ||
84 | MFP_PIN_GPIO59, | ||
85 | MFP_PIN_GPIO60, | ||
86 | MFP_PIN_GPIO61, | ||
87 | MFP_PIN_GPIO62, | ||
88 | MFP_PIN_GPIO63, | ||
89 | MFP_PIN_GPIO64, | ||
90 | MFP_PIN_GPIO65, | ||
91 | MFP_PIN_GPIO66, | ||
92 | MFP_PIN_GPIO67, | ||
93 | MFP_PIN_GPIO68, | ||
94 | MFP_PIN_GPIO69, | ||
95 | MFP_PIN_GPIO70, | ||
96 | MFP_PIN_GPIO71, | ||
97 | MFP_PIN_GPIO72, | ||
98 | MFP_PIN_GPIO73, | ||
99 | MFP_PIN_GPIO74, | ||
100 | MFP_PIN_GPIO75, | ||
101 | MFP_PIN_GPIO76, | ||
102 | MFP_PIN_GPIO77, | ||
103 | MFP_PIN_GPIO78, | ||
104 | MFP_PIN_GPIO79, | ||
105 | MFP_PIN_GPIO80, | ||
106 | MFP_PIN_GPIO81, | ||
107 | MFP_PIN_GPIO82, | ||
108 | MFP_PIN_GPIO83, | ||
109 | MFP_PIN_GPIO84, | ||
110 | MFP_PIN_GPIO85, | ||
111 | MFP_PIN_GPIO86, | ||
112 | MFP_PIN_GPIO87, | ||
113 | MFP_PIN_GPIO88, | ||
114 | MFP_PIN_GPIO89, | ||
115 | MFP_PIN_GPIO90, | ||
116 | MFP_PIN_GPIO91, | ||
117 | MFP_PIN_GPIO92, | ||
118 | MFP_PIN_GPIO93, | ||
119 | MFP_PIN_GPIO94, | ||
120 | MFP_PIN_GPIO95, | ||
121 | MFP_PIN_GPIO96, | ||
122 | MFP_PIN_GPIO97, | ||
123 | MFP_PIN_GPIO98, | ||
124 | MFP_PIN_GPIO99, | ||
125 | MFP_PIN_GPIO100, | ||
126 | MFP_PIN_GPIO101, | ||
127 | MFP_PIN_GPIO102, | ||
128 | MFP_PIN_GPIO103, | ||
129 | MFP_PIN_GPIO104, | ||
130 | MFP_PIN_GPIO105, | ||
131 | MFP_PIN_GPIO106, | ||
132 | MFP_PIN_GPIO107, | ||
133 | MFP_PIN_GPIO108, | ||
134 | MFP_PIN_GPIO109, | ||
135 | MFP_PIN_GPIO110, | ||
136 | MFP_PIN_GPIO111, | ||
137 | MFP_PIN_GPIO112, | ||
138 | MFP_PIN_GPIO113, | ||
139 | MFP_PIN_GPIO114, | ||
140 | MFP_PIN_GPIO115, | ||
141 | MFP_PIN_GPIO116, | ||
142 | MFP_PIN_GPIO117, | ||
143 | MFP_PIN_GPIO118, | ||
144 | MFP_PIN_GPIO119, | ||
145 | MFP_PIN_GPIO120, | ||
146 | MFP_PIN_GPIO121, | ||
147 | MFP_PIN_GPIO122, | ||
148 | MFP_PIN_GPIO123, | ||
149 | MFP_PIN_GPIO124, | ||
150 | MFP_PIN_GPIO125, | ||
151 | MFP_PIN_GPIO126, | ||
152 | MFP_PIN_GPIO127, | ||
153 | MFP_PIN_GPIO0_2, | ||
154 | MFP_PIN_GPIO1_2, | ||
155 | MFP_PIN_GPIO2_2, | ||
156 | MFP_PIN_GPIO3_2, | ||
157 | MFP_PIN_GPIO4_2, | ||
158 | MFP_PIN_GPIO5_2, | ||
159 | MFP_PIN_GPIO6_2, | ||
160 | MFP_PIN_GPIO7_2, | ||
161 | MFP_PIN_GPIO8_2, | ||
162 | MFP_PIN_GPIO9_2, | ||
163 | MFP_PIN_GPIO10_2, | ||
164 | MFP_PIN_GPIO11_2, | ||
165 | MFP_PIN_GPIO12_2, | ||
166 | MFP_PIN_GPIO13_2, | ||
167 | MFP_PIN_GPIO14_2, | ||
168 | MFP_PIN_GPIO15_2, | ||
169 | MFP_PIN_GPIO16_2, | ||
170 | MFP_PIN_GPIO17_2, | ||
171 | |||
172 | MFP_PIN_ULPI_STP, | ||
173 | MFP_PIN_ULPI_NXT, | ||
174 | MFP_PIN_ULPI_DIR, | ||
175 | |||
176 | MFP_PIN_nXCVREN, | ||
177 | MFP_PIN_DF_CLE_nOE, | ||
178 | MFP_PIN_DF_nADV1_ALE, | ||
179 | MFP_PIN_DF_SCLK_E, | ||
180 | MFP_PIN_DF_SCLK_S, | ||
181 | MFP_PIN_nBE0, | ||
182 | MFP_PIN_nBE1, | ||
183 | MFP_PIN_DF_nADV2_ALE, | ||
184 | MFP_PIN_DF_INT_RnB, | ||
185 | MFP_PIN_DF_nCS0, | ||
186 | MFP_PIN_DF_nCS1, | ||
187 | MFP_PIN_nLUA, | ||
188 | MFP_PIN_nLLA, | ||
189 | MFP_PIN_DF_nWE, | ||
190 | MFP_PIN_DF_ALE_nWE, | ||
191 | MFP_PIN_DF_nRE_nOE, | ||
192 | MFP_PIN_DF_ADDR0, | ||
193 | MFP_PIN_DF_ADDR1, | ||
194 | MFP_PIN_DF_ADDR2, | ||
195 | MFP_PIN_DF_ADDR3, | ||
196 | MFP_PIN_DF_IO0, | ||
197 | MFP_PIN_DF_IO1, | ||
198 | MFP_PIN_DF_IO2, | ||
199 | MFP_PIN_DF_IO3, | ||
200 | MFP_PIN_DF_IO4, | ||
201 | MFP_PIN_DF_IO5, | ||
202 | MFP_PIN_DF_IO6, | ||
203 | MFP_PIN_DF_IO7, | ||
204 | MFP_PIN_DF_IO8, | ||
205 | MFP_PIN_DF_IO9, | ||
206 | MFP_PIN_DF_IO10, | ||
207 | MFP_PIN_DF_IO11, | ||
208 | MFP_PIN_DF_IO12, | ||
209 | MFP_PIN_DF_IO13, | ||
210 | MFP_PIN_DF_IO14, | ||
211 | MFP_PIN_DF_IO15, | ||
212 | MFP_PIN_DF_nCS0_SM_nCS2, | ||
213 | MFP_PIN_DF_nCS1_SM_nCS3, | ||
214 | MFP_PIN_SM_nCS0, | ||
215 | MFP_PIN_SM_nCS1, | ||
216 | MFP_PIN_DF_WEn, | ||
217 | MFP_PIN_DF_REn, | ||
218 | MFP_PIN_DF_CLE_SM_OEn, | ||
219 | MFP_PIN_DF_ALE_SM_WEn, | ||
220 | MFP_PIN_DF_RDY0, | ||
221 | MFP_PIN_DF_RDY1, | ||
222 | |||
223 | MFP_PIN_SM_SCLK, | ||
224 | MFP_PIN_SM_BE0, | ||
225 | MFP_PIN_SM_BE1, | ||
226 | MFP_PIN_SM_ADV, | ||
227 | MFP_PIN_SM_ADVMUX, | ||
228 | MFP_PIN_SM_RDY, | ||
229 | |||
230 | MFP_PIN_MMC1_DAT7, | ||
231 | MFP_PIN_MMC1_DAT6, | ||
232 | MFP_PIN_MMC1_DAT5, | ||
233 | MFP_PIN_MMC1_DAT4, | ||
234 | MFP_PIN_MMC1_DAT3, | ||
235 | MFP_PIN_MMC1_DAT2, | ||
236 | MFP_PIN_MMC1_DAT1, | ||
237 | MFP_PIN_MMC1_DAT0, | ||
238 | MFP_PIN_MMC1_CMD, | ||
239 | MFP_PIN_MMC1_CLK, | ||
240 | MFP_PIN_MMC1_CD, | ||
241 | MFP_PIN_MMC1_WP, | ||
242 | |||
243 | /* additional pins on PXA930 */ | ||
244 | MFP_PIN_GSIM_UIO, | ||
245 | MFP_PIN_GSIM_UCLK, | ||
246 | MFP_PIN_GSIM_UDET, | ||
247 | MFP_PIN_GSIM_nURST, | ||
248 | MFP_PIN_PMIC_INT, | ||
249 | MFP_PIN_RDY, | ||
250 | |||
251 | MFP_PIN_MAX, | ||
252 | }; | ||
253 | |||
254 | /* | ||
255 | * a possible MFP configuration is represented by a 32-bit integer | ||
256 | * | ||
257 | * bit 0.. 9 - MFP Pin Number (1024 Pins Maximum) | ||
258 | * bit 10..12 - Alternate Function Selection | ||
259 | * bit 13..15 - Drive Strength | ||
260 | * bit 16..18 - Low Power Mode State | ||
261 | * bit 19..20 - Low Power Mode Edge Detection | ||
262 | * bit 21..22 - Run Mode Pull State | ||
263 | * | ||
264 | * to facilitate the definition, the following macros are provided | ||
265 | * | ||
266 | * MFP_CFG_DEFAULT - default MFP configuration value, with | ||
267 | * alternate function = 0, | ||
268 | * drive strength = fast 3mA (MFP_DS03X) | ||
269 | * low power mode = default | ||
270 | * edge detection = none | ||
271 | * | ||
272 | * MFP_CFG - default MFPR value with alternate function | ||
273 | * MFP_CFG_DRV - default MFPR value with alternate function and | ||
274 | * pin drive strength | ||
275 | * MFP_CFG_LPM - default MFPR value with alternate function and | ||
276 | * low power mode | ||
277 | * MFP_CFG_X - default MFPR value with alternate function, | ||
278 | * pin drive strength and low power mode | ||
279 | */ | ||
280 | |||
281 | typedef unsigned long mfp_cfg_t; | ||
282 | |||
283 | #define MFP_PIN(x) ((x) & 0x3ff) | ||
284 | |||
285 | #define MFP_AF0 (0x0 << 10) | ||
286 | #define MFP_AF1 (0x1 << 10) | ||
287 | #define MFP_AF2 (0x2 << 10) | ||
288 | #define MFP_AF3 (0x3 << 10) | ||
289 | #define MFP_AF4 (0x4 << 10) | ||
290 | #define MFP_AF5 (0x5 << 10) | ||
291 | #define MFP_AF6 (0x6 << 10) | ||
292 | #define MFP_AF7 (0x7 << 10) | ||
293 | #define MFP_AF_MASK (0x7 << 10) | ||
294 | #define MFP_AF(x) (((x) >> 10) & 0x7) | ||
295 | |||
296 | #define MFP_DS01X (0x0 << 13) | ||
297 | #define MFP_DS02X (0x1 << 13) | ||
298 | #define MFP_DS03X (0x2 << 13) | ||
299 | #define MFP_DS04X (0x3 << 13) | ||
300 | #define MFP_DS06X (0x4 << 13) | ||
301 | #define MFP_DS08X (0x5 << 13) | ||
302 | #define MFP_DS10X (0x6 << 13) | ||
303 | #define MFP_DS13X (0x7 << 13) | ||
304 | #define MFP_DS_MASK (0x7 << 13) | ||
305 | #define MFP_DS(x) (((x) >> 13) & 0x7) | ||
306 | |||
307 | #define MFP_LPM_DEFAULT (0x0 << 16) | ||
308 | #define MFP_LPM_DRIVE_LOW (0x1 << 16) | ||
309 | #define MFP_LPM_DRIVE_HIGH (0x2 << 16) | ||
310 | #define MFP_LPM_PULL_LOW (0x3 << 16) | ||
311 | #define MFP_LPM_PULL_HIGH (0x4 << 16) | ||
312 | #define MFP_LPM_FLOAT (0x5 << 16) | ||
313 | #define MFP_LPM_INPUT (0x6 << 16) | ||
314 | #define MFP_LPM_STATE_MASK (0x7 << 16) | ||
315 | #define MFP_LPM_STATE(x) (((x) >> 16) & 0x7) | ||
316 | |||
317 | #define MFP_LPM_EDGE_NONE (0x0 << 19) | ||
318 | #define MFP_LPM_EDGE_RISE (0x1 << 19) | ||
319 | #define MFP_LPM_EDGE_FALL (0x2 << 19) | ||
320 | #define MFP_LPM_EDGE_BOTH (0x3 << 19) | ||
321 | #define MFP_LPM_EDGE_MASK (0x3 << 19) | ||
322 | #define MFP_LPM_EDGE(x) (((x) >> 19) & 0x3) | ||
323 | |||
324 | #define MFP_PULL_NONE (0x0 << 21) | ||
325 | #define MFP_PULL_LOW (0x1 << 21) | ||
326 | #define MFP_PULL_HIGH (0x2 << 21) | ||
327 | #define MFP_PULL_BOTH (0x3 << 21) | ||
328 | #define MFP_PULL_MASK (0x3 << 21) | ||
329 | #define MFP_PULL(x) (((x) >> 21) & 0x3) | ||
330 | |||
331 | #define MFP_CFG_DEFAULT (MFP_AF0 | MFP_DS03X | MFP_LPM_DEFAULT |\ | ||
332 | MFP_LPM_EDGE_NONE | MFP_PULL_NONE) | ||
333 | |||
334 | #define MFP_CFG(pin, af) \ | ||
335 | ((MFP_CFG_DEFAULT & ~MFP_AF_MASK) |\ | ||
336 | (MFP_PIN(MFP_PIN_##pin) | MFP_##af)) | ||
337 | |||
338 | #define MFP_CFG_DRV(pin, af, drv) \ | ||
339 | ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK)) |\ | ||
340 | (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv)) | ||
341 | |||
342 | #define MFP_CFG_LPM(pin, af, lpm) \ | ||
343 | ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_LPM_STATE_MASK)) |\ | ||
344 | (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_LPM_##lpm)) | ||
345 | |||
346 | #define MFP_CFG_X(pin, af, drv, lpm) \ | ||
347 | ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK | MFP_LPM_STATE_MASK)) |\ | ||
348 | (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv | MFP_LPM_##lpm)) | ||
349 | |||
350 | #if defined(CONFIG_PXA3xx) || defined(CONFIG_ARCH_MMP) | ||
351 | /* | ||
352 | * each MFP pin will have a MFPR register, since the offset of the | ||
353 | * register varies between processors, the processor specific code | ||
354 | * should initialize the pin offsets by mfp_init() | ||
355 | * | ||
356 | * mfp_init_base() - accepts a virtual base for all MFPR registers and | ||
357 | * initialize the MFP table to a default state | ||
358 | * | ||
359 | * mfp_init_addr() - accepts a table of "mfp_addr_map" structure, which | ||
360 | * represents a range of MFP pins from "start" to "end", with the offset | ||
361 | * begining at "offset", to define a single pin, let "end" = -1. | ||
362 | * | ||
363 | * use | ||
364 | * | ||
365 | * MFP_ADDR_X() to define a range of pins | ||
366 | * MFP_ADDR() to define a single pin | ||
367 | * MFP_ADDR_END to signal the end of pin offset definitions | ||
368 | */ | ||
369 | struct mfp_addr_map { | ||
370 | unsigned int start; | ||
371 | unsigned int end; | ||
372 | unsigned long offset; | ||
373 | }; | ||
374 | |||
375 | #define MFP_ADDR_X(start, end, offset) \ | ||
376 | { MFP_PIN_##start, MFP_PIN_##end, offset } | ||
377 | |||
378 | #define MFP_ADDR(pin, offset) \ | ||
379 | { MFP_PIN_##pin, -1, offset } | ||
380 | |||
381 | #define MFP_ADDR_END { MFP_PIN_INVALID, 0 } | ||
382 | |||
383 | void __init mfp_init_base(unsigned long mfpr_base); | ||
384 | void __init mfp_init_addr(struct mfp_addr_map *map); | ||
385 | |||
386 | /* | ||
387 | * mfp_{read, write}() - for direct read/write access to the MFPR register | ||
388 | * mfp_config() - for configuring a group of MFPR registers | ||
389 | * mfp_config_lpm() - configuring all low power MFPR registers for suspend | ||
390 | * mfp_config_run() - configuring all run time MFPR registers after resume | ||
391 | */ | ||
392 | unsigned long mfp_read(int mfp); | ||
393 | void mfp_write(int mfp, unsigned long mfpr_val); | ||
394 | void mfp_config(unsigned long *mfp_cfgs, int num); | ||
395 | void mfp_config_run(void); | ||
396 | void mfp_config_lpm(void); | ||
397 | #endif /* CONFIG_PXA3xx || CONFIG_ARCH_MMP */ | ||
398 | |||
399 | #endif /* __ASM_PLAT_MFP_H */ | ||
diff --git a/arch/arm/plat-pxa/mfp.c b/arch/arm/plat-pxa/mfp.c new file mode 100644 index 000000000000..e716c622a17c --- /dev/null +++ b/arch/arm/plat-pxa/mfp.c | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-pxa/mfp.c | ||
3 | * | ||
4 | * Multi-Function Pin Support | ||
5 | * | ||
6 | * Copyright (C) 2007 Marvell Internation Ltd. | ||
7 | * | ||
8 | * 2007-08-21: eric miao <eric.miao@marvell.com> | ||
9 | * initial version | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/sysdev.h> | ||
21 | |||
22 | #include <plat/mfp.h> | ||
23 | |||
24 | #define MFPR_SIZE (PAGE_SIZE) | ||
25 | |||
26 | /* MFPR register bit definitions */ | ||
27 | #define MFPR_PULL_SEL (0x1 << 15) | ||
28 | #define MFPR_PULLUP_EN (0x1 << 14) | ||
29 | #define MFPR_PULLDOWN_EN (0x1 << 13) | ||
30 | #define MFPR_SLEEP_SEL (0x1 << 9) | ||
31 | #define MFPR_SLEEP_OE_N (0x1 << 7) | ||
32 | #define MFPR_EDGE_CLEAR (0x1 << 6) | ||
33 | #define MFPR_EDGE_FALL_EN (0x1 << 5) | ||
34 | #define MFPR_EDGE_RISE_EN (0x1 << 4) | ||
35 | |||
36 | #define MFPR_SLEEP_DATA(x) ((x) << 8) | ||
37 | #define MFPR_DRIVE(x) (((x) & 0x7) << 10) | ||
38 | #define MFPR_AF_SEL(x) (((x) & 0x7) << 0) | ||
39 | |||
40 | #define MFPR_EDGE_NONE (0) | ||
41 | #define MFPR_EDGE_RISE (MFPR_EDGE_RISE_EN) | ||
42 | #define MFPR_EDGE_FALL (MFPR_EDGE_FALL_EN) | ||
43 | #define MFPR_EDGE_BOTH (MFPR_EDGE_RISE | MFPR_EDGE_FALL) | ||
44 | |||
45 | /* | ||
46 | * Table that determines the low power modes outputs, with actual settings | ||
47 | * used in parentheses for don't-care values. Except for the float output, | ||
48 | * the configured driven and pulled levels match, so if there is a need for | ||
49 | * non-LPM pulled output, the same configuration could probably be used. | ||
50 | * | ||
51 | * Output value sleep_oe_n sleep_data pullup_en pulldown_en pull_sel | ||
52 | * (bit 7) (bit 8) (bit 14) (bit 13) (bit 15) | ||
53 | * | ||
54 | * Input 0 X(0) X(0) X(0) 0 | ||
55 | * Drive 0 0 0 0 X(1) 0 | ||
56 | * Drive 1 0 1 X(1) 0 0 | ||
57 | * Pull hi (1) 1 X(1) 1 0 0 | ||
58 | * Pull lo (0) 1 X(0) 0 1 0 | ||
59 | * Z (float) 1 X(0) 0 0 0 | ||
60 | */ | ||
61 | #define MFPR_LPM_INPUT (0) | ||
62 | #define MFPR_LPM_DRIVE_LOW (MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN) | ||
63 | #define MFPR_LPM_DRIVE_HIGH (MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN) | ||
64 | #define MFPR_LPM_PULL_LOW (MFPR_LPM_DRIVE_LOW | MFPR_SLEEP_OE_N) | ||
65 | #define MFPR_LPM_PULL_HIGH (MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N) | ||
66 | #define MFPR_LPM_FLOAT (MFPR_SLEEP_OE_N) | ||
67 | #define MFPR_LPM_MASK (0xe080) | ||
68 | |||
69 | /* | ||
70 | * The pullup and pulldown state of the MFP pin at run mode is by default | ||
71 | * determined by the selected alternate function. In case that some buggy | ||
72 | * devices need to override this default behavior, the definitions below | ||
73 | * indicates the setting of corresponding MFPR bits | ||
74 | * | ||
75 | * Definition pull_sel pullup_en pulldown_en | ||
76 | * MFPR_PULL_NONE 0 0 0 | ||
77 | * MFPR_PULL_LOW 1 0 1 | ||
78 | * MFPR_PULL_HIGH 1 1 0 | ||
79 | * MFPR_PULL_BOTH 1 1 1 | ||
80 | */ | ||
81 | #define MFPR_PULL_NONE (0) | ||
82 | #define MFPR_PULL_LOW (MFPR_PULL_SEL | MFPR_PULLDOWN_EN) | ||
83 | #define MFPR_PULL_BOTH (MFPR_PULL_LOW | MFPR_PULLUP_EN) | ||
84 | #define MFPR_PULL_HIGH (MFPR_PULL_SEL | MFPR_PULLUP_EN) | ||
85 | |||
86 | /* mfp_spin_lock is used to ensure that MFP register configuration | ||
87 | * (most likely a read-modify-write operation) is atomic, and that | ||
88 | * mfp_table[] is consistent | ||
89 | */ | ||
90 | static DEFINE_SPINLOCK(mfp_spin_lock); | ||
91 | |||
92 | static void __iomem *mfpr_mmio_base; | ||
93 | |||
94 | struct mfp_pin { | ||
95 | unsigned long config; /* -1 for not configured */ | ||
96 | unsigned long mfpr_off; /* MFPRxx Register offset */ | ||
97 | unsigned long mfpr_run; /* Run-Mode Register Value */ | ||
98 | unsigned long mfpr_lpm; /* Low Power Mode Register Value */ | ||
99 | }; | ||
100 | |||
101 | static struct mfp_pin mfp_table[MFP_PIN_MAX]; | ||
102 | |||
103 | /* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */ | ||
104 | static const unsigned long mfpr_lpm[] = { | ||
105 | MFPR_LPM_INPUT, | ||
106 | MFPR_LPM_DRIVE_LOW, | ||
107 | MFPR_LPM_DRIVE_HIGH, | ||
108 | MFPR_LPM_PULL_LOW, | ||
109 | MFPR_LPM_PULL_HIGH, | ||
110 | MFPR_LPM_FLOAT, | ||
111 | }; | ||
112 | |||
113 | /* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */ | ||
114 | static const unsigned long mfpr_pull[] = { | ||
115 | MFPR_PULL_NONE, | ||
116 | MFPR_PULL_LOW, | ||
117 | MFPR_PULL_HIGH, | ||
118 | MFPR_PULL_BOTH, | ||
119 | }; | ||
120 | |||
121 | /* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */ | ||
122 | static const unsigned long mfpr_edge[] = { | ||
123 | MFPR_EDGE_NONE, | ||
124 | MFPR_EDGE_RISE, | ||
125 | MFPR_EDGE_FALL, | ||
126 | MFPR_EDGE_BOTH, | ||
127 | }; | ||
128 | |||
129 | #define mfpr_readl(off) \ | ||
130 | __raw_readl(mfpr_mmio_base + (off)) | ||
131 | |||
132 | #define mfpr_writel(off, val) \ | ||
133 | __raw_writel(val, mfpr_mmio_base + (off)) | ||
134 | |||
135 | #define mfp_configured(p) ((p)->config != -1) | ||
136 | |||
137 | /* | ||
138 | * perform a read-back of any MFPR register to make sure the | ||
139 | * previous writings are finished | ||
140 | */ | ||
141 | #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) | ||
142 | |||
143 | static inline void __mfp_config_run(struct mfp_pin *p) | ||
144 | { | ||
145 | if (mfp_configured(p)) | ||
146 | mfpr_writel(p->mfpr_off, p->mfpr_run); | ||
147 | } | ||
148 | |||
149 | static inline void __mfp_config_lpm(struct mfp_pin *p) | ||
150 | { | ||
151 | if (mfp_configured(p)) { | ||
152 | unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR; | ||
153 | if (mfpr_clr != p->mfpr_run) | ||
154 | mfpr_writel(p->mfpr_off, mfpr_clr); | ||
155 | if (p->mfpr_lpm != mfpr_clr) | ||
156 | mfpr_writel(p->mfpr_off, p->mfpr_lpm); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void mfp_config(unsigned long *mfp_cfgs, int num) | ||
161 | { | ||
162 | unsigned long flags; | ||
163 | int i; | ||
164 | |||
165 | spin_lock_irqsave(&mfp_spin_lock, flags); | ||
166 | |||
167 | for (i = 0; i < num; i++, mfp_cfgs++) { | ||
168 | unsigned long tmp, c = *mfp_cfgs; | ||
169 | struct mfp_pin *p; | ||
170 | int pin, af, drv, lpm, edge, pull; | ||
171 | |||
172 | pin = MFP_PIN(c); | ||
173 | BUG_ON(pin >= MFP_PIN_MAX); | ||
174 | p = &mfp_table[pin]; | ||
175 | |||
176 | af = MFP_AF(c); | ||
177 | drv = MFP_DS(c); | ||
178 | lpm = MFP_LPM_STATE(c); | ||
179 | edge = MFP_LPM_EDGE(c); | ||
180 | pull = MFP_PULL(c); | ||
181 | |||
182 | /* run-mode pull settings will conflict with MFPR bits of | ||
183 | * low power mode state, calculate mfpr_run and mfpr_lpm | ||
184 | * individually if pull != MFP_PULL_NONE | ||
185 | */ | ||
186 | tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv); | ||
187 | |||
188 | if (likely(pull == MFP_PULL_NONE)) { | ||
189 | p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; | ||
190 | p->mfpr_lpm = p->mfpr_run; | ||
191 | } else { | ||
192 | p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; | ||
193 | p->mfpr_run = tmp | mfpr_pull[pull]; | ||
194 | } | ||
195 | |||
196 | p->config = c; __mfp_config_run(p); | ||
197 | } | ||
198 | |||
199 | mfpr_sync(); | ||
200 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | ||
201 | } | ||
202 | |||
203 | unsigned long mfp_read(int mfp) | ||
204 | { | ||
205 | unsigned long val, flags; | ||
206 | |||
207 | BUG_ON(mfp >= MFP_PIN_MAX); | ||
208 | |||
209 | spin_lock_irqsave(&mfp_spin_lock, flags); | ||
210 | val = mfpr_readl(mfp_table[mfp].mfpr_off); | ||
211 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | ||
212 | |||
213 | return val; | ||
214 | } | ||
215 | |||
216 | void mfp_write(int mfp, unsigned long val) | ||
217 | { | ||
218 | unsigned long flags; | ||
219 | |||
220 | BUG_ON(mfp >= MFP_PIN_MAX); | ||
221 | |||
222 | spin_lock_irqsave(&mfp_spin_lock, flags); | ||
223 | mfpr_writel(mfp_table[mfp].mfpr_off, val); | ||
224 | mfpr_sync(); | ||
225 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | ||
226 | } | ||
227 | |||
228 | void __init mfp_init_base(unsigned long mfpr_base) | ||
229 | { | ||
230 | int i; | ||
231 | |||
232 | /* initialize the table with default - unconfigured */ | ||
233 | for (i = 0; i < ARRAY_SIZE(mfp_table); i++) | ||
234 | mfp_table[i].config = -1; | ||
235 | |||
236 | mfpr_mmio_base = (void __iomem *)mfpr_base; | ||
237 | } | ||
238 | |||
239 | void __init mfp_init_addr(struct mfp_addr_map *map) | ||
240 | { | ||
241 | struct mfp_addr_map *p; | ||
242 | unsigned long offset, flags; | ||
243 | int i; | ||
244 | |||
245 | spin_lock_irqsave(&mfp_spin_lock, flags); | ||
246 | |||
247 | for (p = map; p->start != MFP_PIN_INVALID; p++) { | ||
248 | offset = p->offset; | ||
249 | i = p->start; | ||
250 | |||
251 | do { | ||
252 | mfp_table[i].mfpr_off = offset; | ||
253 | mfp_table[i].mfpr_run = 0; | ||
254 | mfp_table[i].mfpr_lpm = 0; | ||
255 | offset += 4; i++; | ||
256 | } while ((i <= p->end) && (p->end != -1)); | ||
257 | } | ||
258 | |||
259 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | ||
260 | } | ||
261 | |||
262 | void mfp_config_lpm(void) | ||
263 | { | ||
264 | struct mfp_pin *p = &mfp_table[0]; | ||
265 | int pin; | ||
266 | |||
267 | for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++) | ||
268 | __mfp_config_lpm(p); | ||
269 | } | ||
270 | |||
271 | void mfp_config_run(void) | ||
272 | { | ||
273 | struct mfp_pin *p = &mfp_table[0]; | ||
274 | int pin; | ||
275 | |||
276 | for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++) | ||
277 | __mfp_config_run(p); | ||
278 | } | ||