diff options
Diffstat (limited to 'arch/arm/mach-lh7a40x')
-rw-r--r-- | arch/arm/mach-lh7a40x/Kconfig | 5 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/Makefile | 19 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/arch-lpd7a40x.c | 200 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/clcd.c | 241 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/clocks.c | 199 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/irq-lh7a404.c | 17 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/lcd-panel.h | 346 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/ssp-cpld.c | 343 | ||||
-rw-r--r-- | arch/arm/mach-lh7a40x/time.c | 4 |
10 files changed, 1303 insertions, 72 deletions
diff --git a/arch/arm/mach-lh7a40x/Kconfig b/arch/arm/mach-lh7a40x/Kconfig index 8a17867a6a24..558a34f53b1c 100644 --- a/arch/arm/mach-lh7a40x/Kconfig +++ b/arch/arm/mach-lh7a40x/Kconfig | |||
@@ -14,6 +14,7 @@ config MACH_LPD7A400 | |||
14 | bool "LPD7A400 Card Engine" | 14 | bool "LPD7A400 Card Engine" |
15 | select ARCH_LH7A400 | 15 | select ARCH_LH7A400 |
16 | # select IDE_POLL | 16 | # select IDE_POLL |
17 | select HAS_TOUCHSCREEN_ADS7843_LH7 | ||
17 | help | 18 | help |
18 | Say Y here if you are using Logic Product Development's | 19 | Say Y here if you are using Logic Product Development's |
19 | LPD7A400 CardEngine. For the time being, the LPD7A400 and | 20 | LPD7A400 CardEngine. For the time being, the LPD7A400 and |
@@ -23,6 +24,7 @@ config MACH_LPD7A404 | |||
23 | bool "LPD7A404 Card Engine" | 24 | bool "LPD7A404 Card Engine" |
24 | select ARCH_LH7A404 | 25 | select ARCH_LH7A404 |
25 | # select IDE_POLL | 26 | # select IDE_POLL |
27 | select HAS_TOUCHSCREEN_ADC_LH7 | ||
26 | help | 28 | help |
27 | Say Y here if you are using Logic Product Development's | 29 | Say Y here if you are using Logic Product Development's |
28 | LPD7A404 CardEngine. For the time being, the LPD7A400 and | 30 | LPD7A404 CardEngine. For the time being, the LPD7A400 and |
@@ -34,6 +36,9 @@ config ARCH_LH7A400 | |||
34 | config ARCH_LH7A404 | 36 | config ARCH_LH7A404 |
35 | bool | 37 | bool |
36 | 38 | ||
39 | config LPD7A40X_CPLD_SSP | ||
40 | bool | ||
41 | |||
37 | config LH7A40X_CONTIGMEM | 42 | config LH7A40X_CONTIGMEM |
38 | bool "Disable NUMA Support" | 43 | bool "Disable NUMA Support" |
39 | depends on ARCH_LH7A40X | 44 | depends on ARCH_LH7A40X |
diff --git a/arch/arm/mach-lh7a40x/Makefile b/arch/arm/mach-lh7a40x/Makefile index e90512dbc2d6..94b8615fb3c3 100644 --- a/arch/arm/mach-lh7a40x/Makefile +++ b/arch/arm/mach-lh7a40x/Makefile | |||
@@ -4,11 +4,14 @@ | |||
4 | 4 | ||
5 | # Object file lists. | 5 | # Object file lists. |
6 | 6 | ||
7 | obj-y := time.o | 7 | obj-y := time.o clocks.o |
8 | obj-$(CONFIG_MACH_KEV7A400) += arch-kev7a400.o irq-lh7a400.o | 8 | obj-m := |
9 | obj-$(CONFIG_MACH_LPD7A400) += arch-lpd7a40x.o irq-lh7a400.o | 9 | obj-n := |
10 | obj-$(CONFIG_MACH_LPD7A404) += arch-lpd7a40x.o irq-lh7a404.o | 10 | obj- := |
11 | 11 | ||
12 | obj-m := | 12 | obj-$(CONFIG_MACH_KEV7A400) += arch-kev7a400.o irq-lh7a400.o |
13 | obj-n := | 13 | obj-$(CONFIG_MACH_LPD7A400) += arch-lpd7a40x.o irq-lh7a400.o |
14 | obj- := | 14 | obj-$(CONFIG_MACH_LPD7A404) += arch-lpd7a40x.o irq-lh7a404.o |
15 | obj-$(CONFIG_LPD7A40X_CPLD_SSP) += ssp-cpld.o | ||
16 | obj-$(CONFIG_FB_ARMCLCD) += clcd.o | ||
17 | |||
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index 12e23277c5ea..c0e6854289f1 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c | |||
@@ -23,6 +23,28 @@ | |||
23 | 23 | ||
24 | #include "common.h" | 24 | #include "common.h" |
25 | 25 | ||
26 | #define CPLD_INT_NETHERNET (1<<0) | ||
27 | #define CPLD_INTMASK_ETHERNET (1<<2) | ||
28 | #if defined (CONFIG_MACH_LPD7A400) | ||
29 | # define CPLD_INT_NTOUCH (1<<1) | ||
30 | # define CPLD_INTMASK_TOUCH (1<<3) | ||
31 | # define CPLD_INT_PEN (1<<4) | ||
32 | # define CPLD_INTMASK_PEN (1<<4) | ||
33 | # define CPLD_INT_PIRQ (1<<4) | ||
34 | #endif | ||
35 | #define CPLD_INTMASK_CPLD (1<<7) | ||
36 | #define CPLD_INT_CPLD (1<<6) | ||
37 | |||
38 | #define CPLD_CONTROL_SWINT (1<<7) /* Disable all CPLD IRQs */ | ||
39 | #define CPLD_CONTROL_OCMSK (1<<6) /* Mask USB1 connect IRQ */ | ||
40 | #define CPLD_CONTROL_PDRV (1<<5) /* PCC_nDRV high */ | ||
41 | #define CPLD_CONTROL_USB1C (1<<4) /* USB1 connect IRQ active */ | ||
42 | #define CPLD_CONTROL_USB1P (1<<3) /* USB1 power disable */ | ||
43 | #define CPLD_CONTROL_AWKP (1<<2) /* Auto-wakeup disabled */ | ||
44 | #define CPLD_CONTROL_LCD_ENABLE (1<<1) /* LCD Vee enable */ | ||
45 | #define CPLD_CONTROL_WRLAN_NENABLE (1<<0) /* SMC91x power disable */ | ||
46 | |||
47 | |||
26 | static struct resource smc91x_resources[] = { | 48 | static struct resource smc91x_resources[] = { |
27 | [0] = { | 49 | [0] = { |
28 | .start = CPLD00_PHYS, | 50 | .start = CPLD00_PHYS, |
@@ -48,12 +70,12 @@ static struct platform_device smc91x_device = { | |||
48 | static struct resource lh7a40x_usbclient_resources[] = { | 70 | static struct resource lh7a40x_usbclient_resources[] = { |
49 | [0] = { | 71 | [0] = { |
50 | .start = USB_PHYS, | 72 | .start = USB_PHYS, |
51 | .end = (USB_PHYS + 0xFF), | 73 | .end = (USB_PHYS + PAGE_SIZE), |
52 | .flags = IORESOURCE_MEM, | 74 | .flags = IORESOURCE_MEM, |
53 | }, | 75 | }, |
54 | [1] = { | 76 | [1] = { |
55 | .start = IRQ_USBINTR, | 77 | .start = IRQ_USB, |
56 | .end = IRQ_USBINTR, | 78 | .end = IRQ_USB, |
57 | .flags = IORESOURCE_IRQ, | 79 | .flags = IORESOURCE_IRQ, |
58 | }, | 80 | }, |
59 | }; | 81 | }; |
@@ -61,7 +83,8 @@ static struct resource lh7a40x_usbclient_resources[] = { | |||
61 | static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL; | 83 | static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL; |
62 | 84 | ||
63 | static struct platform_device lh7a40x_usbclient_device = { | 85 | static struct platform_device lh7a40x_usbclient_device = { |
64 | .name = "lh7a40x_udc", | 86 | // .name = "lh7a40x_udc", |
87 | .name = "lh7-udc", | ||
65 | .id = 0, | 88 | .id = 0, |
66 | .dev = { | 89 | .dev = { |
67 | .dma_mask = &lh7a40x_usbclient_dma_mask, | 90 | .dma_mask = &lh7a40x_usbclient_dma_mask, |
@@ -101,7 +124,7 @@ static struct platform_device lh7a404_usbhost_device = { | |||
101 | 124 | ||
102 | #endif | 125 | #endif |
103 | 126 | ||
104 | static struct platform_device *lpd7a40x_devs[] __initdata = { | 127 | static struct platform_device* lpd7a40x_devs[] __initdata = { |
105 | &smc91x_device, | 128 | &smc91x_device, |
106 | &lh7a40x_usbclient_device, | 129 | &lh7a40x_usbclient_device, |
107 | #if defined (CONFIG_ARCH_LH7A404) | 130 | #if defined (CONFIG_ARCH_LH7A404) |
@@ -113,29 +136,52 @@ extern void lpd7a400_map_io (void); | |||
113 | 136 | ||
114 | static void __init lpd7a40x_init (void) | 137 | static void __init lpd7a40x_init (void) |
115 | { | 138 | { |
116 | CPLD_CONTROL |= (1<<6); /* Mask USB1 connection IRQ */ | 139 | #if defined (CONFIG_MACH_LPD7A400) |
140 | CPLD_CONTROL |= 0 | ||
141 | | CPLD_CONTROL_SWINT /* Disable software interrupt */ | ||
142 | | CPLD_CONTROL_OCMSK; /* Mask USB1 connection IRQ */ | ||
117 | CPLD_CONTROL &= ~(0 | 143 | CPLD_CONTROL &= ~(0 |
118 | | (1<<1) /* Disable LCD */ | 144 | | CPLD_CONTROL_LCD_ENABLE /* Disable LCD */ |
119 | | (1<<0) /* Enable WLAN */ | 145 | | CPLD_CONTROL_WRLAN_NENABLE /* Enable SMC91x */ |
120 | ); | 146 | ); |
147 | #endif | ||
148 | |||
149 | #if defined (CONFIG_MACH_LPD7A404) | ||
150 | CPLD_CONTROL &= ~(0 | ||
151 | | CPLD_CONTROL_WRLAN_NENABLE /* Enable SMC91x */ | ||
152 | ); | ||
153 | #endif | ||
121 | 154 | ||
122 | platform_add_devices (lpd7a40x_devs, ARRAY_SIZE (lpd7a40x_devs)); | 155 | platform_add_devices (lpd7a40x_devs, ARRAY_SIZE (lpd7a40x_devs)); |
156 | #if defined (CONFIG_FB_ARMCLCD) | ||
157 | lh7a40x_clcd_init (); | ||
158 | #endif | ||
123 | } | 159 | } |
124 | 160 | ||
125 | static void lh7a40x_ack_cpld_irq (u32 irq) | 161 | static void lh7a40x_ack_cpld_irq (u32 irq) |
126 | { | 162 | { |
127 | /* CPLD doesn't have ack capability */ | 163 | /* CPLD doesn't have ack capability, but some devices may */ |
164 | |||
165 | #if defined (CPLD_INTMASK_TOUCH) | ||
166 | /* The touch control *must* mask the the interrupt because the | ||
167 | * interrupt bit is read by the driver to determine if the pen | ||
168 | * is still down. */ | ||
169 | if (irq == IRQ_TOUCH) | ||
170 | CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH; | ||
171 | #endif | ||
128 | } | 172 | } |
129 | 173 | ||
130 | static void lh7a40x_mask_cpld_irq (u32 irq) | 174 | static void lh7a40x_mask_cpld_irq (u32 irq) |
131 | { | 175 | { |
132 | switch (irq) { | 176 | switch (irq) { |
133 | case IRQ_LPD7A40X_ETH_INT: | 177 | case IRQ_LPD7A40X_ETH_INT: |
134 | CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x4; | 178 | CPLD_INTERRUPTS |= CPLD_INTMASK_ETHERNET; |
135 | break; | 179 | break; |
136 | case IRQ_LPD7A400_TS: | 180 | #if defined (IRQ_TOUCH) |
137 | CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x8; | 181 | case IRQ_TOUCH: |
182 | CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH; | ||
138 | break; | 183 | break; |
184 | #endif | ||
139 | } | 185 | } |
140 | } | 186 | } |
141 | 187 | ||
@@ -143,11 +189,13 @@ static void lh7a40x_unmask_cpld_irq (u32 irq) | |||
143 | { | 189 | { |
144 | switch (irq) { | 190 | switch (irq) { |
145 | case IRQ_LPD7A40X_ETH_INT: | 191 | case IRQ_LPD7A40X_ETH_INT: |
146 | CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x4; | 192 | CPLD_INTERRUPTS &= ~CPLD_INTMASK_ETHERNET; |
147 | break; | 193 | break; |
148 | case IRQ_LPD7A400_TS: | 194 | #if defined (IRQ_TOUCH) |
149 | CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x8; | 195 | case IRQ_TOUCH: |
196 | CPLD_INTERRUPTS &= ~CPLD_INTMASK_TOUCH; | ||
150 | break; | 197 | break; |
198 | #endif | ||
151 | } | 199 | } |
152 | } | 200 | } |
153 | 201 | ||
@@ -164,11 +212,13 @@ static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc, | |||
164 | 212 | ||
165 | desc->chip->ack (irq); | 213 | desc->chip->ack (irq); |
166 | 214 | ||
167 | if ((mask & 0x1) == 0) /* WLAN */ | 215 | if ((mask & (1<<0)) == 0) /* WLAN */ |
168 | IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT); | 216 | IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT); |
169 | 217 | ||
170 | if ((mask & 0x2) == 0) /* Touch */ | 218 | #if defined (IRQ_TOUCH) |
171 | IRQ_DISPATCH (IRQ_LPD7A400_TS); | 219 | if ((mask & (1<<1)) == 0) /* Touch */ |
220 | IRQ_DISPATCH (IRQ_TOUCH); | ||
221 | #endif | ||
172 | 222 | ||
173 | desc->chip->unmask (irq); /* Level-triggered need this */ | 223 | desc->chip->unmask (irq); /* Level-triggered need this */ |
174 | } | 224 | } |
@@ -204,9 +254,21 @@ void __init lh7a40x_init_board_irq (void) | |||
204 | 254 | ||
205 | /* Then, configure CPLD interrupt */ | 255 | /* Then, configure CPLD interrupt */ |
206 | 256 | ||
207 | CPLD_INTERRUPTS = 0x9c; /* Disable all CPLD interrupts */ | 257 | /* Disable all CPLD interrupts */ |
258 | #if defined (CONFIG_MACH_LPD7A400) | ||
259 | CPLD_INTERRUPTS = CPLD_INTMASK_TOUCH | CPLD_INTMASK_PEN | ||
260 | | CPLD_INTMASK_ETHERNET; | ||
261 | /* *** FIXME: don't know why we need 7 and 4. 7 is way wrong | ||
262 | and 4 is uncefined. */ | ||
263 | // (1<<7)|(1<<4)|(1<<3)|(1<<2); | ||
264 | #endif | ||
265 | #if defined (CONFIG_MACH_LPD7A404) | ||
266 | CPLD_INTERRUPTS = CPLD_INTMASK_ETHERNET; | ||
267 | /* *** FIXME: don't know why we need 6 and 5, neither is defined. */ | ||
268 | // (1<<6)|(1<<5)|(1<<3); | ||
269 | #endif | ||
208 | GPIO_PFDD &= ~(1 << pinCPLD); /* Make input */ | 270 | GPIO_PFDD &= ~(1 << pinCPLD); /* Make input */ |
209 | GPIO_INTTYPE1 |= (1 << pinCPLD); /* Edge triggered */ | 271 | GPIO_INTTYPE1 &= ~(1 << pinCPLD); /* Level triggered */ |
210 | GPIO_INTTYPE2 &= ~(1 << pinCPLD); /* Active low */ | 272 | GPIO_INTTYPE2 &= ~(1 << pinCPLD); /* Active low */ |
211 | barrier (); | 273 | barrier (); |
212 | GPIO_GPIOFINTEN |= (1 << pinCPLD); /* Enable */ | 274 | GPIO_GPIOFINTEN |= (1 << pinCPLD); /* Enable */ |
@@ -216,7 +278,7 @@ void __init lh7a40x_init_board_irq (void) | |||
216 | for (irq = IRQ_BOARD_START; | 278 | for (irq = IRQ_BOARD_START; |
217 | irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) { | 279 | irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) { |
218 | set_irq_chip (irq, &lpd7a40x_cpld_chip); | 280 | set_irq_chip (irq, &lpd7a40x_cpld_chip); |
219 | set_irq_handler (irq, do_edge_IRQ); | 281 | set_irq_handler (irq, do_level_IRQ); |
220 | set_irq_flags (irq, IRQF_VALID); | 282 | set_irq_flags (irq, IRQF_VALID); |
221 | } | 283 | } |
222 | 284 | ||
@@ -226,91 +288,109 @@ void __init lh7a40x_init_board_irq (void) | |||
226 | lpd7a40x_cpld_handler); | 288 | lpd7a40x_cpld_handler); |
227 | } | 289 | } |
228 | 290 | ||
229 | static struct map_desc lpd7a400_io_desc[] __initdata = { | 291 | static struct map_desc lpd7a40x_io_desc[] __initdata = { |
230 | { | 292 | { |
231 | .virtual = IO_VIRT, | 293 | .virtual = IO_VIRT, |
232 | .pfn = __phys_to_pfn(IO_PHYS), | 294 | .pfn = __phys_to_pfn(IO_PHYS), |
233 | .length = IO_SIZE, | 295 | .length = IO_SIZE, |
234 | .type = MT_DEVICE | 296 | .type = MT_DEVICE |
235 | }, { /* Mapping added to work around chip select problems */ | 297 | }, |
298 | { /* Mapping added to work around chip select problems */ | ||
236 | .virtual = IOBARRIER_VIRT, | 299 | .virtual = IOBARRIER_VIRT, |
237 | .pfn = __phys_to_pfn(IOBARRIER_PHYS), | 300 | .pfn = __phys_to_pfn(IOBARRIER_PHYS), |
238 | .length = IOBARRIER_SIZE, | 301 | .length = IOBARRIER_SIZE, |
239 | .type = MT_DEVICE | 302 | .type = MT_DEVICE |
240 | }, { | 303 | }, |
304 | { | ||
241 | .virtual = CF_VIRT, | 305 | .virtual = CF_VIRT, |
242 | .pfn = __phys_to_pfn(CF_PHYS), | 306 | .pfn = __phys_to_pfn(CF_PHYS), |
243 | .length = CF_SIZE, | 307 | .length = CF_SIZE, |
244 | .type = MT_DEVICE | 308 | .type = MT_DEVICE |
245 | }, { | 309 | }, |
310 | { | ||
246 | .virtual = CPLD02_VIRT, | 311 | .virtual = CPLD02_VIRT, |
247 | .pfn = __phys_to_pfn(CPLD02_PHYS), | 312 | .pfn = __phys_to_pfn(CPLD02_PHYS), |
248 | .length = CPLD02_SIZE, | 313 | .length = CPLD02_SIZE, |
249 | .type = MT_DEVICE | 314 | .type = MT_DEVICE |
250 | }, { | 315 | }, |
316 | { | ||
251 | .virtual = CPLD06_VIRT, | 317 | .virtual = CPLD06_VIRT, |
252 | .pfn = __phys_to_pfn(CPLD06_PHYS), | 318 | .pfn = __phys_to_pfn(CPLD06_PHYS), |
253 | .length = CPLD06_SIZE, | 319 | .length = CPLD06_SIZE, |
320 | .type = MT_DEVICE | ||
321 | }, | ||
322 | { | ||
323 | .virtual = CPLD08_VIRT, | ||
324 | .pfn = __phys_to_pfn(CPLD08_PHYS), | ||
325 | .length = CPLD08_SIZE, | ||
254 | .type = MT_DEVICE | 326 | .type = MT_DEVICE |
255 | }, { | 327 | }, |
328 | { | ||
256 | .virtual = CPLD08_VIRT, | 329 | .virtual = CPLD08_VIRT, |
257 | .pfn = __phys_to_pfn(CPLD08_PHYS), | 330 | .pfn = __phys_to_pfn(CPLD08_PHYS), |
258 | .length = CPLD08_SIZE, | 331 | .length = CPLD08_SIZE, |
259 | .type = MT_DEVICE | 332 | .type = MT_DEVICE |
260 | }, { | 333 | }, |
334 | { | ||
335 | .virtual = CPLD0A_VIRT, | ||
336 | .pfn = __phys_to_pfn(CPLD0A_PHYS), | ||
337 | .length = CPLD0A_SIZE, | ||
338 | .type = MT_DEVICE | ||
339 | }, | ||
340 | { | ||
261 | .virtual = CPLD0C_VIRT, | 341 | .virtual = CPLD0C_VIRT, |
262 | .pfn = __phys_to_pfn(CPLD0C_PHYS), | 342 | .pfn = __phys_to_pfn(CPLD0C_PHYS), |
263 | .length = CPLD0C_SIZE, | 343 | .length = CPLD0C_SIZE, |
264 | .type = MT_DEVICE | 344 | .type = MT_DEVICE |
265 | }, { | 345 | }, |
346 | { | ||
266 | .virtual = CPLD0E_VIRT, | 347 | .virtual = CPLD0E_VIRT, |
267 | .pfn = __phys_to_pfn(CPLD0E_PHYS), | 348 | .pfn = __phys_to_pfn(CPLD0E_PHYS), |
268 | .length = CPLD0E_SIZE, | 349 | .length = CPLD0E_SIZE, |
269 | .type = MT_DEVICE | 350 | .type = MT_DEVICE |
270 | }, { | 351 | }, |
352 | { | ||
271 | .virtual = CPLD10_VIRT, | 353 | .virtual = CPLD10_VIRT, |
272 | .pfn = __phys_to_pfn(CPLD10_PHYS), | 354 | .pfn = __phys_to_pfn(CPLD10_PHYS), |
273 | .length = CPLD10_SIZE, | 355 | .length = CPLD10_SIZE, |
274 | .type = MT_DEVICE | 356 | .type = MT_DEVICE |
275 | }, { | 357 | }, |
358 | { | ||
276 | .virtual = CPLD12_VIRT, | 359 | .virtual = CPLD12_VIRT, |
277 | .pfn = __phys_to_pfn(CPLD12_PHYS), | 360 | .pfn = __phys_to_pfn(CPLD12_PHYS), |
278 | .length = CPLD12_SIZE, | 361 | .length = CPLD12_SIZE, |
279 | .type = MT_DEVICE | 362 | .type = MT_DEVICE |
280 | }, { | 363 | }, |
364 | { | ||
281 | .virtual = CPLD14_VIRT, | 365 | .virtual = CPLD14_VIRT, |
282 | .pfn = __phys_to_pfn(CPLD14_PHYS), | 366 | .pfn = __phys_to_pfn(CPLD14_PHYS), |
283 | .length = CPLD14_SIZE, | 367 | .length = CPLD14_SIZE, |
284 | .type = MT_DEVICE | 368 | .type = MT_DEVICE |
285 | }, { | 369 | }, |
370 | { | ||
286 | .virtual = CPLD16_VIRT, | 371 | .virtual = CPLD16_VIRT, |
287 | .pfn = __phys_to_pfn(CPLD16_PHYS), | 372 | .pfn = __phys_to_pfn(CPLD16_PHYS), |
288 | .length = CPLD16_SIZE, | 373 | .length = CPLD16_SIZE, |
289 | .type = MT_DEVICE | 374 | .type = MT_DEVICE |
290 | }, { | 375 | }, |
376 | { | ||
291 | .virtual = CPLD18_VIRT, | 377 | .virtual = CPLD18_VIRT, |
292 | .pfn = __phys_to_pfn(CPLD18_PHYS), | 378 | .pfn = __phys_to_pfn(CPLD18_PHYS), |
293 | .length = CPLD18_SIZE, | 379 | .length = CPLD18_SIZE, |
294 | .type = MT_DEVICE | 380 | .type = MT_DEVICE |
295 | }, { | 381 | }, |
382 | { | ||
296 | .virtual = CPLD1A_VIRT, | 383 | .virtual = CPLD1A_VIRT, |
297 | .pfn = __phys_to_pfn(CPLD1A_PHYS), | 384 | .pfn = __phys_to_pfn(CPLD1A_PHYS), |
298 | .length = CPLD1A_SIZE, | 385 | .length = CPLD1A_SIZE, |
299 | .type = MT_DEVICE | 386 | .type = MT_DEVICE |
300 | }, | 387 | }, |
301 | /* This mapping is redundant since the smc driver performs another. */ | ||
302 | /* { CPLD00_VIRT, CPLD00_PHYS, CPLD00_SIZE, MT_DEVICE }, */ | ||
303 | }; | 388 | }; |
304 | 389 | ||
305 | void __init | 390 | void __init |
306 | lpd7a400_map_io(void) | 391 | lpd7a40x_map_io(void) |
307 | { | 392 | { |
308 | iotable_init (lpd7a400_io_desc, ARRAY_SIZE (lpd7a400_io_desc)); | 393 | iotable_init (lpd7a40x_io_desc, ARRAY_SIZE (lpd7a40x_io_desc)); |
309 | |||
310 | /* Fixup (improve) Static Memory Controller settings */ | ||
311 | SMC_BCR0 = 0x200039af; /* Boot Flash */ | ||
312 | SMC_BCR6 = 0x1000fbe0; /* CPLD */ | ||
313 | SMC_BCR7 = 0x1000b2c2; /* Compact Flash */ | ||
314 | } | 394 | } |
315 | 395 | ||
316 | #ifdef CONFIG_MACH_LPD7A400 | 396 | #ifdef CONFIG_MACH_LPD7A400 |
@@ -320,7 +400,7 @@ MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10") | |||
320 | .phys_io = 0x80000000, | 400 | .phys_io = 0x80000000, |
321 | .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc, | 401 | .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc, |
322 | .boot_params = 0xc0000100, | 402 | .boot_params = 0xc0000100, |
323 | .map_io = lpd7a400_map_io, | 403 | .map_io = lpd7a40x_map_io, |
324 | .init_irq = lh7a400_init_irq, | 404 | .init_irq = lh7a400_init_irq, |
325 | .timer = &lh7a40x_timer, | 405 | .timer = &lh7a40x_timer, |
326 | .init_machine = lpd7a40x_init, | 406 | .init_machine = lpd7a40x_init, |
@@ -335,7 +415,7 @@ MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10") | |||
335 | .phys_io = 0x80000000, | 415 | .phys_io = 0x80000000, |
336 | .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc, | 416 | .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc, |
337 | .boot_params = 0xc0000100, | 417 | .boot_params = 0xc0000100, |
338 | .map_io = lpd7a400_map_io, | 418 | .map_io = lpd7a40x_map_io, |
339 | .init_irq = lh7a404_init_irq, | 419 | .init_irq = lh7a404_init_irq, |
340 | .timer = &lh7a40x_timer, | 420 | .timer = &lh7a40x_timer, |
341 | .init_machine = lpd7a40x_init, | 421 | .init_machine = lpd7a40x_init, |
diff --git a/arch/arm/mach-lh7a40x/clcd.c b/arch/arm/mach-lh7a40x/clcd.c new file mode 100644 index 000000000000..93751fee793d --- /dev/null +++ b/arch/arm/mach-lh7a40x/clcd.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-lh7a40x/clcd.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Marc Singer | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/sysdev.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | |||
18 | //#include <linux/module.h> | ||
19 | //#include <linux/time.h> | ||
20 | //#include <asm/hardware.h> | ||
21 | |||
22 | //#include <asm/mach/time.h> | ||
23 | #include <asm/irq.h> | ||
24 | #include <asm/mach/irq.h> | ||
25 | |||
26 | #include <asm/system.h> | ||
27 | #include <asm/hardware.h> | ||
28 | #include <linux/amba/bus.h> | ||
29 | #include <linux/amba/clcd.h> | ||
30 | |||
31 | #define HRTFTC_HRSETUP __REG(HRTFTC_PHYS + 0x00) | ||
32 | #define HRTFTC_HRCON __REG(HRTFTC_PHYS + 0x04) | ||
33 | #define HRTFTC_HRTIMING1 __REG(HRTFTC_PHYS + 0x08) | ||
34 | #define HRTFTC_HRTIMING2 __REG(HRTFTC_PHYS + 0x0c) | ||
35 | |||
36 | #define ALI_SETUP __REG(ALI_PHYS + 0x00) | ||
37 | #define ALI_CONTROL __REG(ALI_PHYS + 0x04) | ||
38 | #define ALI_TIMING1 __REG(ALI_PHYS + 0x08) | ||
39 | #define ALI_TIMING2 __REG(ALI_PHYS + 0x0c) | ||
40 | |||
41 | #include "lcd-panel.h" | ||
42 | |||
43 | static void lh7a40x_clcd_disable (struct clcd_fb *fb) | ||
44 | { | ||
45 | #if defined (CONFIG_MACH_LPD7A400) | ||
46 | CPLD_CONTROL &= ~(1<<1); /* Disable LCD Vee */ | ||
47 | #endif | ||
48 | |||
49 | #if defined (CONFIG_MACH_LPD7A404) | ||
50 | GPIO_PCD &= ~(1<<3); /* Disable LCD Vee */ | ||
51 | #endif | ||
52 | |||
53 | #if defined (CONFIG_ARCH_LH7A400) | ||
54 | HRTFTC_HRSETUP &= ~(1<<13); /* Disable HRTFT controller */ | ||
55 | #endif | ||
56 | |||
57 | #if defined (CONFIG_ARCH_LH7A404) | ||
58 | ALI_SETUP &= ~(1<<13); /* Disable ALI */ | ||
59 | #endif | ||
60 | } | ||
61 | |||
62 | static void lh7a40x_clcd_enable (struct clcd_fb *fb) | ||
63 | { | ||
64 | struct clcd_panel_extra* extra | ||
65 | = (struct clcd_panel_extra*) fb->board_data; | ||
66 | |||
67 | #if defined (CONFIG_MACH_LPD7A400) | ||
68 | CPLD_CONTROL |= (1<<1); /* Enable LCD Vee */ | ||
69 | #endif | ||
70 | |||
71 | #if defined (CONFIG_MACH_LPD7A404) | ||
72 | GPIO_PCDD &= ~(1<<3); /* Enable LCD Vee */ | ||
73 | GPIO_PCD |= (1<<3); | ||
74 | #endif | ||
75 | |||
76 | #if defined (CONFIG_ARCH_LH7A400) | ||
77 | |||
78 | if (extra) { | ||
79 | HRTFTC_HRSETUP | ||
80 | = (1 << 13) | ||
81 | | ((fb->fb.var.xres - 1) << 4) | ||
82 | | 0xc | ||
83 | | (extra->hrmode ? 1 : 0); | ||
84 | HRTFTC_HRCON | ||
85 | = ((extra->clsen ? 1 : 0) << 1) | ||
86 | | ((extra->spsen ? 1 : 0) << 0); | ||
87 | HRTFTC_HRTIMING1 | ||
88 | = (extra->pcdel << 8) | ||
89 | | (extra->revdel << 4) | ||
90 | | (extra->lpdel << 0); | ||
91 | HRTFTC_HRTIMING2 | ||
92 | = (extra->spldel << 9) | ||
93 | | (extra->pc2del << 0); | ||
94 | } | ||
95 | else | ||
96 | HRTFTC_HRSETUP | ||
97 | = (1 << 13) | ||
98 | | 0xc; | ||
99 | #endif | ||
100 | |||
101 | #if defined (CONFIG_ARCH_LH7A404) | ||
102 | |||
103 | if (extra) { | ||
104 | ALI_SETUP | ||
105 | = (1 << 13) | ||
106 | | ((fb->fb.var.xres - 1) << 4) | ||
107 | | 0xc | ||
108 | | (extra->hrmode ? 1 : 0); | ||
109 | ALI_CONTROL | ||
110 | = ((extra->clsen ? 1 : 0) << 1) | ||
111 | | ((extra->spsen ? 1 : 0) << 0); | ||
112 | ALI_TIMING1 | ||
113 | = (extra->pcdel << 8) | ||
114 | | (extra->revdel << 4) | ||
115 | | (extra->lpdel << 0); | ||
116 | ALI_TIMING2 | ||
117 | = (extra->spldel << 9) | ||
118 | | (extra->pc2del << 0); | ||
119 | } | ||
120 | else | ||
121 | ALI_SETUP | ||
122 | = (1 << 13) | ||
123 | | 0xc; | ||
124 | #endif | ||
125 | |||
126 | } | ||
127 | |||
128 | #define FRAMESIZE(s) (((s) + PAGE_SIZE - 1)&PAGE_MASK) | ||
129 | |||
130 | static int lh7a40x_clcd_setup (struct clcd_fb *fb) | ||
131 | { | ||
132 | dma_addr_t dma; | ||
133 | u32 len = FRAMESIZE (lcd_panel.mode.xres*lcd_panel.mode.yres | ||
134 | *(lcd_panel.bpp/8)); | ||
135 | |||
136 | fb->panel = &lcd_panel; | ||
137 | |||
138 | /* Enforce the sync polarity defaults */ | ||
139 | if (!(fb->panel->tim2 & TIM2_IHS)) | ||
140 | fb->fb.var.sync |= FB_SYNC_HOR_HIGH_ACT; | ||
141 | if (!(fb->panel->tim2 & TIM2_IVS)) | ||
142 | fb->fb.var.sync |= FB_SYNC_VERT_HIGH_ACT; | ||
143 | |||
144 | #if defined (HAS_LCD_PANEL_EXTRA) | ||
145 | fb->board_data = &lcd_panel_extra; | ||
146 | #endif | ||
147 | |||
148 | fb->fb.screen_base | ||
149 | = dma_alloc_writecombine (&fb->dev->dev, len, | ||
150 | &dma, GFP_KERNEL); | ||
151 | printk ("CLCD: LCD setup fb virt 0x%p phys 0x%p l %x io 0x%p \n", | ||
152 | fb->fb.screen_base, (void*) dma, len, | ||
153 | (void*) io_p2v (CLCDC_PHYS)); | ||
154 | printk ("CLCD: pixclock %d\n", lcd_panel.mode.pixclock); | ||
155 | |||
156 | if (!fb->fb.screen_base) { | ||
157 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | ||
158 | return -ENOMEM; | ||
159 | } | ||
160 | |||
161 | #if defined (USE_RGB555) | ||
162 | fb->fb.var.green.length = 5; /* Panel uses RGB 5:5:5 */ | ||
163 | #endif | ||
164 | |||
165 | fb->fb.fix.smem_start = dma; | ||
166 | fb->fb.fix.smem_len = len; | ||
167 | |||
168 | /* Drive PE4 high to prevent CPLD crash */ | ||
169 | GPIO_PEDD |= (1<<4); | ||
170 | GPIO_PED |= (1<<4); | ||
171 | |||
172 | GPIO_PINMUX |= (1<<1) | (1<<0); /* LCDVD[15:4] */ | ||
173 | |||
174 | // fb->fb.fbops->fb_check_var (&fb->fb.var, &fb->fb); | ||
175 | // fb->fb.fbops->fb_set_par (&fb->fb); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int lh7a40x_clcd_mmap (struct clcd_fb *fb, struct vm_area_struct *vma) | ||
181 | { | ||
182 | return dma_mmap_writecombine(&fb->dev->dev, vma, | ||
183 | fb->fb.screen_base, | ||
184 | fb->fb.fix.smem_start, | ||
185 | fb->fb.fix.smem_len); | ||
186 | } | ||
187 | |||
188 | static void lh7a40x_clcd_remove (struct clcd_fb *fb) | ||
189 | { | ||
190 | dma_free_writecombine (&fb->dev->dev, fb->fb.fix.smem_len, | ||
191 | fb->fb.screen_base, fb->fb.fix.smem_start); | ||
192 | } | ||
193 | |||
194 | static struct clcd_board clcd_platform_data = { | ||
195 | .name = "lh7a40x FB", | ||
196 | .check = clcdfb_check, | ||
197 | .decode = clcdfb_decode, | ||
198 | .enable = lh7a40x_clcd_enable, | ||
199 | .setup = lh7a40x_clcd_setup, | ||
200 | .mmap = lh7a40x_clcd_mmap, | ||
201 | .remove = lh7a40x_clcd_remove, | ||
202 | .disable = lh7a40x_clcd_disable, | ||
203 | }; | ||
204 | |||
205 | #define IRQ_CLCDC (IRQ_LCDINTR) | ||
206 | |||
207 | #define AMBA_DEVICE(name,busid,base,plat,pid) \ | ||
208 | static struct amba_device name##_device = { \ | ||
209 | .dev = { \ | ||
210 | .coherent_dma_mask = ~0, \ | ||
211 | .bus_id = busid, \ | ||
212 | .platform_data = plat, \ | ||
213 | }, \ | ||
214 | .res = { \ | ||
215 | .start = base##_PHYS, \ | ||
216 | .end = (base##_PHYS) + (4*1024) - 1, \ | ||
217 | .flags = IORESOURCE_MEM, \ | ||
218 | }, \ | ||
219 | .dma_mask = ~0, \ | ||
220 | .irq = { IRQ_##base, }, \ | ||
221 | /* .dma = base##_DMA,*/ \ | ||
222 | .periphid = pid, \ | ||
223 | } | ||
224 | |||
225 | AMBA_DEVICE(clcd, "cldc-lh7a40x", CLCDC, &clcd_platform_data, 0x41110); | ||
226 | |||
227 | static struct amba_device *amba_devs[] __initdata = { | ||
228 | &clcd_device, | ||
229 | }; | ||
230 | |||
231 | void __init lh7a40x_clcd_init (void) | ||
232 | { | ||
233 | int i; | ||
234 | int result; | ||
235 | printk ("CLCD: registering amba devices\n"); | ||
236 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | ||
237 | struct amba_device *d = amba_devs[i]; | ||
238 | result = amba_device_register(d, &iomem_resource); | ||
239 | printk (" %d -> %d\n", i ,result); | ||
240 | } | ||
241 | } | ||
diff --git a/arch/arm/mach-lh7a40x/clocks.c b/arch/arm/mach-lh7a40x/clocks.c new file mode 100644 index 000000000000..2291afe9f23e --- /dev/null +++ b/arch/arm/mach-lh7a40x/clocks.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* arch/arm/mach-lh7a40x/clocks.c | ||
2 | * | ||
3 | * Copyright (C) 2004 Marc Singer | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/cpufreq.h> | ||
13 | #include <asm/hardware.h> | ||
14 | #include <asm/arch/clocks.h> | ||
15 | #include <linux/err.h> | ||
16 | |||
17 | struct module; | ||
18 | struct icst525_params; | ||
19 | |||
20 | struct clk { | ||
21 | struct list_head node; | ||
22 | unsigned long rate; | ||
23 | struct module *owner; | ||
24 | const char *name; | ||
25 | // void *data; | ||
26 | // const struct icst525_params *params; | ||
27 | // void (*setvco)(struct clk *, struct icst525_vco vco); | ||
28 | }; | ||
29 | |||
30 | int clk_register(struct clk *clk); | ||
31 | void clk_unregister(struct clk *clk); | ||
32 | |||
33 | /* ----- */ | ||
34 | |||
35 | #define MAINDIV1(c) (((c) >> 7) & 0x0f) | ||
36 | #define MAINDIV2(c) (((c) >> 11) & 0x1f) | ||
37 | #define PS(c) (((c) >> 18) & 0x03) | ||
38 | #define PREDIV(c) (((c) >> 2) & 0x1f) | ||
39 | #define HCLKDIV(c) (((c) >> 0) & 0x02) | ||
40 | #define PCLKDIV(c) (((c) >> 16) & 0x03) | ||
41 | |||
42 | unsigned int cpufreq_get (unsigned int cpu) /* in kHz */ | ||
43 | { | ||
44 | return fclkfreq_get ()/1000; | ||
45 | } | ||
46 | EXPORT_SYMBOL(cpufreq_get); | ||
47 | |||
48 | unsigned int fclkfreq_get (void) | ||
49 | { | ||
50 | unsigned int clkset = CSC_CLKSET; | ||
51 | unsigned int gclk | ||
52 | = XTAL_IN | ||
53 | / (1 << PS(clkset)) | ||
54 | * (MAINDIV1(clkset) + 2) | ||
55 | / (PREDIV(clkset) + 2) | ||
56 | * (MAINDIV2(clkset) + 2) | ||
57 | ; | ||
58 | return gclk; | ||
59 | } | ||
60 | |||
61 | unsigned int hclkfreq_get (void) | ||
62 | { | ||
63 | unsigned int clkset = CSC_CLKSET; | ||
64 | unsigned int hclk = fclkfreq_get () / (HCLKDIV(clkset) + 1); | ||
65 | |||
66 | return hclk; | ||
67 | } | ||
68 | |||
69 | unsigned int pclkfreq_get (void) | ||
70 | { | ||
71 | unsigned int clkset = CSC_CLKSET; | ||
72 | int pclkdiv = PCLKDIV(clkset); | ||
73 | unsigned int pclk; | ||
74 | if (pclkdiv == 0x3) | ||
75 | pclkdiv = 0x2; | ||
76 | pclk = hclkfreq_get () / (1 << pclkdiv); | ||
77 | |||
78 | return pclk; | ||
79 | } | ||
80 | |||
81 | /* ----- */ | ||
82 | |||
83 | static LIST_HEAD(clocks); | ||
84 | static DECLARE_MUTEX(clocks_sem); | ||
85 | |||
86 | struct clk *clk_get (struct device *dev, const char *id) | ||
87 | { | ||
88 | struct clk *p; | ||
89 | struct clk *clk = ERR_PTR(-ENOENT); | ||
90 | |||
91 | down (&clocks_sem); | ||
92 | list_for_each_entry (p, &clocks, node) { | ||
93 | if (strcmp (id, p->name) == 0 | ||
94 | && try_module_get(p->owner)) { | ||
95 | clk = p; | ||
96 | break; | ||
97 | } | ||
98 | } | ||
99 | up (&clocks_sem); | ||
100 | |||
101 | return clk; | ||
102 | } | ||
103 | EXPORT_SYMBOL(clk_get); | ||
104 | |||
105 | void clk_put (struct clk *clk) | ||
106 | { | ||
107 | module_put(clk->owner); | ||
108 | } | ||
109 | EXPORT_SYMBOL(clk_put); | ||
110 | |||
111 | int clk_enable (struct clk *clk) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | EXPORT_SYMBOL(clk_enable); | ||
116 | |||
117 | void clk_disable (struct clk *clk) | ||
118 | { | ||
119 | } | ||
120 | EXPORT_SYMBOL(clk_disable); | ||
121 | |||
122 | int clk_use (struct clk *clk) | ||
123 | { | ||
124 | return 0; | ||
125 | } | ||
126 | EXPORT_SYMBOL(clk_use); | ||
127 | |||
128 | void clk_unuse (struct clk *clk) | ||
129 | { | ||
130 | } | ||
131 | EXPORT_SYMBOL(clk_unuse); | ||
132 | |||
133 | unsigned long clk_get_rate (struct clk *clk) | ||
134 | { | ||
135 | return clk->rate; | ||
136 | } | ||
137 | EXPORT_SYMBOL(clk_get_rate); | ||
138 | |||
139 | long clk_round_rate (struct clk *clk, unsigned long rate) | ||
140 | { | ||
141 | return rate; | ||
142 | } | ||
143 | EXPORT_SYMBOL(clk_round_rate); | ||
144 | |||
145 | int clk_set_rate (struct clk *clk, unsigned long rate) | ||
146 | { | ||
147 | int ret = -EIO; | ||
148 | return ret; | ||
149 | } | ||
150 | EXPORT_SYMBOL(clk_set_rate); | ||
151 | |||
152 | #if 0 | ||
153 | /* | ||
154 | * These are fixed clocks. | ||
155 | */ | ||
156 | static struct clk kmi_clk = { | ||
157 | .name = "KMIREFCLK", | ||
158 | .rate = 24000000, | ||
159 | }; | ||
160 | |||
161 | static struct clk uart_clk = { | ||
162 | .name = "UARTCLK", | ||
163 | .rate = 24000000, | ||
164 | }; | ||
165 | |||
166 | static struct clk mmci_clk = { | ||
167 | .name = "MCLK", | ||
168 | .rate = 33000000, | ||
169 | }; | ||
170 | #endif | ||
171 | |||
172 | static struct clk clcd_clk = { | ||
173 | .name = "CLCDCLK", | ||
174 | .rate = 0, | ||
175 | }; | ||
176 | |||
177 | int clk_register (struct clk *clk) | ||
178 | { | ||
179 | down (&clocks_sem); | ||
180 | list_add (&clk->node, &clocks); | ||
181 | up (&clocks_sem); | ||
182 | return 0; | ||
183 | } | ||
184 | EXPORT_SYMBOL(clk_register); | ||
185 | |||
186 | void clk_unregister (struct clk *clk) | ||
187 | { | ||
188 | down (&clocks_sem); | ||
189 | list_del (&clk->node); | ||
190 | up (&clocks_sem); | ||
191 | } | ||
192 | EXPORT_SYMBOL(clk_unregister); | ||
193 | |||
194 | static int __init clk_init (void) | ||
195 | { | ||
196 | clk_register(&clcd_clk); | ||
197 | return 0; | ||
198 | } | ||
199 | arch_initcall(clk_init); | ||
diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h index ea8de7e3ab1b..18e8bb4eb202 100644 --- a/arch/arm/mach-lh7a40x/common.h +++ b/arch/arm/mach-lh7a40x/common.h | |||
@@ -12,6 +12,7 @@ extern struct sys_timer lh7a40x_timer; | |||
12 | 12 | ||
13 | extern void lh7a400_init_irq (void); | 13 | extern void lh7a400_init_irq (void); |
14 | extern void lh7a404_init_irq (void); | 14 | extern void lh7a404_init_irq (void); |
15 | extern void lh7a40x_clcd_init (void); | ||
15 | extern void lh7a40x_init_board_irq (void); | 16 | extern void lh7a40x_init_board_irq (void); |
16 | 17 | ||
17 | #define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs) | 18 | #define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs) |
diff --git a/arch/arm/mach-lh7a40x/irq-lh7a404.c b/arch/arm/mach-lh7a40x/irq-lh7a404.c index e902e3d87da4..2685a81454d2 100644 --- a/arch/arm/mach-lh7a40x/irq-lh7a404.c +++ b/arch/arm/mach-lh7a40x/irq-lh7a404.c | |||
@@ -28,13 +28,17 @@ | |||
28 | 28 | ||
29 | static unsigned char irq_pri_vic1[] = { | 29 | static unsigned char irq_pri_vic1[] = { |
30 | #if defined (USE_PRIORITIES) | 30 | #if defined (USE_PRIORITIES) |
31 | IRQ_GPIO3INTR, | 31 | IRQ_GPIO3INTR, /* CPLD */ |
32 | IRQ_DMAM2P4, IRQ_DMAM2P5, /* AC97 */ | ||
32 | #endif | 33 | #endif |
33 | }; | 34 | }; |
34 | static unsigned char irq_pri_vic2[] = { | 35 | static unsigned char irq_pri_vic2[] = { |
35 | #if defined (USE_PRIORITIES) | 36 | #if defined (USE_PRIORITIES) |
36 | IRQ_T3UI, IRQ_GPIO7INTR, | 37 | IRQ_T3UI, /* Timer */ |
38 | IRQ_GPIO7INTR, /* CPLD */ | ||
37 | IRQ_UART1INTR, IRQ_UART2INTR, IRQ_UART3INTR, | 39 | IRQ_UART1INTR, IRQ_UART2INTR, IRQ_UART3INTR, |
40 | IRQ_LCDINTR, /* LCD */ | ||
41 | IRQ_TSCINTR, /* ADC/Touchscreen */ | ||
38 | #endif | 42 | #endif |
39 | }; | 43 | }; |
40 | 44 | ||
@@ -98,10 +102,19 @@ static struct irqchip lh7a404_gpio_vic2_chip = { | |||
98 | 102 | ||
99 | /* IRQ initialization */ | 103 | /* IRQ initialization */ |
100 | 104 | ||
105 | #if defined (CONFIG_ARCH_LH7A400) && defined (CONFIG_ARCH_LH7A404) | ||
106 | extern void* branch_irq_lh7a400; | ||
107 | #endif | ||
108 | |||
101 | void __init lh7a404_init_irq (void) | 109 | void __init lh7a404_init_irq (void) |
102 | { | 110 | { |
103 | int irq; | 111 | int irq; |
104 | 112 | ||
113 | #if defined (CONFIG_ARCH_LH7A400) && defined (CONFIG_ARCH_LH7A404) | ||
114 | #define NOP 0xe1a00000 /* mov r0, r0 */ | ||
115 | branch_irq_lh7a400 = NOP; | ||
116 | #endif | ||
117 | |||
105 | VIC1_INTENCLR = 0xffffffff; | 118 | VIC1_INTENCLR = 0xffffffff; |
106 | VIC2_INTENCLR = 0xffffffff; | 119 | VIC2_INTENCLR = 0xffffffff; |
107 | VIC1_INTSEL = 0; /* All IRQs */ | 120 | VIC1_INTSEL = 0; /* All IRQs */ |
diff --git a/arch/arm/mach-lh7a40x/lcd-panel.h b/arch/arm/mach-lh7a40x/lcd-panel.h new file mode 100644 index 000000000000..4fb2efc4950f --- /dev/null +++ b/arch/arm/mach-lh7a40x/lcd-panel.h | |||
@@ -0,0 +1,346 @@ | |||
1 | /* lcd-panel.h | ||
2 | $Id$ | ||
3 | |||
4 | written by Marc Singer | ||
5 | 18 Jul 2005 | ||
6 | |||
7 | Copyright (C) 2005 Marc Singer | ||
8 | |||
9 | ----------- | ||
10 | DESCRIPTION | ||
11 | ----------- | ||
12 | |||
13 | Only one panel may be defined at a time. | ||
14 | |||
15 | The pixel clock is calculated to be no greater than the target. | ||
16 | |||
17 | Each timing value is accompanied by a specification comment. | ||
18 | |||
19 | UNITS/MIN/TYP/MAX | ||
20 | |||
21 | Most of the units will be in clocks. | ||
22 | |||
23 | USE_RGB555 | ||
24 | |||
25 | Define this macro to configure the AMBA LCD controller to use an | ||
26 | RGB555 encoding for the pels instead of the normal RGB565. | ||
27 | |||
28 | LPD9520, LPD79524, LPD7A400, LPD7A404-10, LPD7A404-11 | ||
29 | |||
30 | These boards are best approximated by 555 for all panels. Some | ||
31 | can use an extra low-order bit of blue in bit 16 of the color | ||
32 | value, but we don't have a way to communicate this non-linear | ||
33 | mapping to the kernel. | ||
34 | |||
35 | */ | ||
36 | |||
37 | #if !defined (__LCD_PANEL_H__) | ||
38 | # define __LCD_PANEL_H__ | ||
39 | |||
40 | #if defined (MACH_LPD79520)\ | ||
41 | || defined (MACH_LPD79524)\ | ||
42 | || defined (MACH_LPD7A400)\ | ||
43 | || defined (MACH_LPD7A404) | ||
44 | # define USE_RGB555 | ||
45 | #endif | ||
46 | |||
47 | struct clcd_panel_extra { | ||
48 | unsigned int hrmode; | ||
49 | unsigned int clsen; | ||
50 | unsigned int spsen; | ||
51 | unsigned int pcdel; | ||
52 | unsigned int revdel; | ||
53 | unsigned int lpdel; | ||
54 | unsigned int spldel; | ||
55 | unsigned int pc2del; | ||
56 | }; | ||
57 | |||
58 | #define NS_TO_CLOCK(ns,c) ((((ns)*((c)/1000) + (1000000 - 1))/1000000)) | ||
59 | #define CLOCK_TO_DIV(e,c) (((c) + (e) - 1)/(e)) | ||
60 | |||
61 | #if defined CONFIG_FB_ARMCLCD_SHARP_LQ035Q7DB02_HRTFT | ||
62 | |||
63 | /* Logic Product Development LCD 3.5" QVGA HRTFT -10 */ | ||
64 | /* Sharp PN LQ035Q7DB02 w/HRTFT controller chip */ | ||
65 | |||
66 | #define PIX_CLOCK_TARGET (6800000) | ||
67 | #define PIX_CLOCK_DIVIDER CLOCK_TO_DIV (PIX_CLOCK_TARGET, HCLK) | ||
68 | #define PIX_CLOCK (HCLK/PIX_CLOCK_DIVIDER) | ||
69 | |||
70 | static struct clcd_panel lcd_panel = { | ||
71 | .mode = { | ||
72 | .name = "3.5in QVGA (LQ035Q7DB02)", | ||
73 | .xres = 240, | ||
74 | .yres = 320, | ||
75 | .pixclock = PIX_CLOCK, | ||
76 | .left_margin = 16, | ||
77 | .right_margin = 21, | ||
78 | .upper_margin = 8, // line/8/8/8 | ||
79 | .lower_margin = 5, | ||
80 | .hsync_len = 61, | ||
81 | .vsync_len = NS_TO_CLOCK (60, PIX_CLOCK), | ||
82 | .vmode = FB_VMODE_NONINTERLACED, | ||
83 | }, | ||
84 | .width = -1, | ||
85 | .height = -1, | ||
86 | .tim2 = TIM2_IPC | (PIX_CLOCK_DIVIDER - 2), | ||
87 | .cntl = CNTL_LCDTFT | CNTL_WATERMARK, | ||
88 | .bpp = 16, | ||
89 | }; | ||
90 | |||
91 | #define HAS_LCD_PANEL_EXTRA | ||
92 | |||
93 | static struct clcd_panel_extra lcd_panel_extra = { | ||
94 | .hrmode = 1, | ||
95 | .clsen = 1, | ||
96 | .spsen = 1, | ||
97 | .pcdel = 8, | ||
98 | .revdel = 7, | ||
99 | .lpdel = 13, | ||
100 | .spldel = 77, | ||
101 | .pc2del = 208, | ||
102 | }; | ||
103 | |||
104 | #endif | ||
105 | |||
106 | #if defined CONFIG_FB_ARMCLCD_SHARP_LQ057Q3DC02 | ||
107 | |||
108 | /* Logic Product Development LCD 5.7" QVGA -10 */ | ||
109 | /* Sharp PN LQ057Q3DC02 */ | ||
110 | /* QVGA mode, V/Q=LOW */ | ||
111 | |||
112 | /* From Sharp on 2006.1.3. I believe some of the values are incorrect | ||
113 | * based on the datasheet. | ||
114 | |||
115 | Timing0 TIMING1 TIMING2 CONTROL | ||
116 | 0x140A0C4C 0x080504EF 0x013F380D 0x00000829 | ||
117 | HBP= 20 VBP= 8 BCD= 0 | ||
118 | HFP= 10 VFP= 5 CPL=319 | ||
119 | HSW= 12 VSW= 1 IOE= 0 | ||
120 | PPL= 19 LPP=239 IPC= 1 | ||
121 | IHS= 1 | ||
122 | IVS= 1 | ||
123 | ACB= 0 | ||
124 | CSEL= 0 | ||
125 | PCD= 13 | ||
126 | |||
127 | */ | ||
128 | |||
129 | /* The full horozontal cycle (Th) is clock/360/400/450. */ | ||
130 | /* The full vertical cycle (Tv) is line/251/262/280. */ | ||
131 | |||
132 | #define PIX_CLOCK_TARGET (6300000) /* -/6.3/7 MHz */ | ||
133 | #define PIX_CLOCK_DIVIDER CLOCK_TO_DIV (PIX_CLOCK_TARGET, HCLK) | ||
134 | #define PIX_CLOCK (HCLK/PIX_CLOCK_DIVIDER) | ||
135 | |||
136 | static struct clcd_panel lcd_panel = { | ||
137 | .mode = { | ||
138 | .name = "5.7in QVGA (LQ057Q3DC02)", | ||
139 | .xres = 320, | ||
140 | .yres = 240, | ||
141 | .pixclock = PIX_CLOCK, | ||
142 | .left_margin = 11, | ||
143 | .right_margin = 400-11-320-2, | ||
144 | .upper_margin = 7, // line/7/7/7 | ||
145 | .lower_margin = 262-7-240-2, | ||
146 | .hsync_len = 2, // clk/2/96/200 | ||
147 | .vsync_len = 2, // line/2/-/34 | ||
148 | .vmode = FB_VMODE_NONINTERLACED, | ||
149 | }, | ||
150 | .width = -1, | ||
151 | .height = -1, | ||
152 | .tim2 = TIM2_IHS | TIM2_IVS | ||
153 | | (PIX_CLOCK_DIVIDER - 2), | ||
154 | .cntl = CNTL_LCDTFT | CNTL_WATERMARK, | ||
155 | .bpp = 16, | ||
156 | }; | ||
157 | |||
158 | #endif | ||
159 | |||
160 | #if defined CONFIG_FB_ARMCLCD_SHARP_LQ64D343 | ||
161 | |||
162 | /* Logic Product Development LCD 6.4" VGA -10 */ | ||
163 | /* Sharp PN LQ64D343 */ | ||
164 | |||
165 | /* The full horozontal cycle (Th) is clock/750/800/900. */ | ||
166 | /* The full vertical cycle (Tv) is line/515/525/560. */ | ||
167 | |||
168 | #define PIX_CLOCK_TARGET (28330000) | ||
169 | #define PIX_CLOCK_DIVIDER CLOCK_TO_DIV (PIX_CLOCK_TARGET, HCLK) | ||
170 | #define PIX_CLOCK (HCLK/PIX_CLOCK_DIVIDER) | ||
171 | |||
172 | static struct clcd_panel lcd_panel = { | ||
173 | .mode = { | ||
174 | .name = "6.4in QVGA (LQ64D343)", | ||
175 | .xres = 640, | ||
176 | .yres = 480, | ||
177 | .pixclock = PIX_CLOCK, | ||
178 | .left_margin = 32, | ||
179 | .right_margin = 800-32-640-96, | ||
180 | .upper_margin = 32, // line/34/34/34 | ||
181 | .lower_margin = 540-32-480-2, | ||
182 | .hsync_len = 96, // clk/2/96/200 | ||
183 | .vsync_len = 2, // line/2/-/34 | ||
184 | .vmode = FB_VMODE_NONINTERLACED, | ||
185 | }, | ||
186 | .width = -1, | ||
187 | .height = -1, | ||
188 | .tim2 = TIM2_IHS | TIM2_IVS | ||
189 | | (PIX_CLOCK_DIVIDER - 2), | ||
190 | .cntl = CNTL_LCDTFT | CNTL_WATERMARK, | ||
191 | .bpp = 16, | ||
192 | }; | ||
193 | |||
194 | #endif | ||
195 | |||
196 | #if defined CONFIG_FB_ARMCLCD_SHARP_LQ10D368 | ||
197 | |||
198 | /* Logic Product Development LCD 10.4" VGA -10 */ | ||
199 | /* Sharp PN LQ10D368 */ | ||
200 | |||
201 | #define PIX_CLOCK_TARGET (28330000) | ||
202 | #define PIX_CLOCK_DIVIDER CLOCK_TO_DIV (PIX_CLOCK_TARGET, HCLK) | ||
203 | #define PIX_CLOCK (HCLK/PIX_CLOCK_DIVIDER) | ||
204 | |||
205 | static struct clcd_panel lcd_panel = { | ||
206 | .mode = { | ||
207 | .name = "10.4in VGA (LQ10D368)", | ||
208 | .xres = 640, | ||
209 | .yres = 480, | ||
210 | .pixclock = PIX_CLOCK, | ||
211 | .left_margin = 21, | ||
212 | .right_margin = 15, | ||
213 | .upper_margin = 34, | ||
214 | .lower_margin = 5, | ||
215 | .hsync_len = 96, | ||
216 | .vsync_len = 16, | ||
217 | .vmode = FB_VMODE_NONINTERLACED, | ||
218 | }, | ||
219 | .width = -1, | ||
220 | .height = -1, | ||
221 | .tim2 = TIM2_IHS | TIM2_IVS | ||
222 | | (PIX_CLOCK_DIVIDER - 2), | ||
223 | .cntl = CNTL_LCDTFT | CNTL_WATERMARK, | ||
224 | .bpp = 16, | ||
225 | }; | ||
226 | |||
227 | #endif | ||
228 | |||
229 | #if defined CONFIG_FB_ARMCLCD_SHARP_LQ121S1DG41 | ||
230 | |||
231 | /* Logic Product Development LCD 12.1" SVGA -10 */ | ||
232 | /* Sharp PN LQ121S1DG41, was LQ121S1DG31 */ | ||
233 | |||
234 | /* Note that with a 99993900 Hz HCLK, it is not possible to hit the | ||
235 | * target clock frequency range of 35MHz to 42MHz. */ | ||
236 | |||
237 | /* If the target pixel clock is substantially lower than the panel | ||
238 | * spec, this is done to prevent the LCD display from glitching when | ||
239 | * the CPU is under load. A pixel clock higher than 25MHz | ||
240 | * (empirically determined) will compete with the CPU for bus cycles | ||
241 | * for the Ethernet chip. However, even a pixel clock of 10MHz | ||
242 | * competes with Compact Flash interface during some operations | ||
243 | * (fdisk, e2fsck). And, at that speed the display may have a visible | ||
244 | * flicker. */ | ||
245 | |||
246 | /* The full horozontal cycle (Th) is clock/832/1056/1395. */ | ||
247 | |||
248 | #define PIX_CLOCK_TARGET (20000000) | ||
249 | #define PIX_CLOCK_DIVIDER CLOCK_TO_DIV (PIX_CLOCK_TARGET, HCLK) | ||
250 | #define PIX_CLOCK (HCLK/PIX_CLOCK_DIVIDER) | ||
251 | |||
252 | static struct clcd_panel lcd_panel = { | ||
253 | .mode = { | ||
254 | .name = "12.1in SVGA (LQ121S1DG41)", | ||
255 | .xres = 800, | ||
256 | .yres = 600, | ||
257 | .pixclock = PIX_CLOCK, | ||
258 | .left_margin = 89, // ns/5/-/(1/PIX_CLOCK)-10 | ||
259 | .right_margin = 1056-800-89-128, | ||
260 | .upper_margin = 23, // line/23/23/23 | ||
261 | .lower_margin = 44, | ||
262 | .hsync_len = 128, // clk/2/128/200 | ||
263 | .vsync_len = 4, // line/2/4/6 | ||
264 | .vmode = FB_VMODE_NONINTERLACED, | ||
265 | }, | ||
266 | .width = -1, | ||
267 | .height = -1, | ||
268 | .tim2 = TIM2_IHS | TIM2_IVS | ||
269 | | (PIX_CLOCK_DIVIDER - 2), | ||
270 | .cntl = CNTL_LCDTFT | CNTL_WATERMARK, | ||
271 | .bpp = 16, | ||
272 | }; | ||
273 | |||
274 | #endif | ||
275 | |||
276 | #if defined CONFIG_FB_ARMCLCD_HITACHI | ||
277 | |||
278 | /* Hitachi*/ | ||
279 | /* Submitted by Michele Da Rold <michele.darold@ecsproject.com> */ | ||
280 | |||
281 | #define PIX_CLOCK_TARGET (49000000) | ||
282 | #define PIX_CLOCK_DIVIDER CLOCK_TO_DIV (PIX_CLOCK_TARGET, HCLK) | ||
283 | #define PIX_CLOCK (HCLK/PIX_CLOCK_DIVIDER) | ||
284 | |||
285 | static struct clcd_panel lcd_panel = { | ||
286 | .mode = { | ||
287 | .name = "Hitachi 800x480", | ||
288 | .xres = 800, | ||
289 | .yres = 480, | ||
290 | .pixclock = PIX_CLOCK, | ||
291 | .left_margin = 88, | ||
292 | .right_margin = 40, | ||
293 | .upper_margin = 32, | ||
294 | .lower_margin = 11, | ||
295 | .hsync_len = 128, | ||
296 | .vsync_len = 2, | ||
297 | .vmode = FB_VMODE_NONINTERLACED, | ||
298 | }, | ||
299 | .width = -1, | ||
300 | .height = -1, | ||
301 | .tim2 = TIM2_IPC | TIM2_IHS | TIM2_IVS | ||
302 | | (PIX_CLOCK_DIVIDER - 2), | ||
303 | .cntl = CNTL_LCDTFT | CNTL_WATERMARK, | ||
304 | .bpp = 16, | ||
305 | }; | ||
306 | |||
307 | #endif | ||
308 | |||
309 | |||
310 | #if defined CONFIG_FB_ARMCLCD_AUO_A070VW01_WIDE | ||
311 | |||
312 | /* AU Optotronics A070VW01 7.0 Wide Screen color Display*/ | ||
313 | /* Submitted by Michele Da Rold <michele.darold@ecsproject.com> */ | ||
314 | |||
315 | #define PIX_CLOCK_TARGET (10000000) | ||
316 | #define PIX_CLOCK_DIVIDER CLOCK_TO_DIV (PIX_CLOCK_TARGET, HCLK) | ||
317 | #define PIX_CLOCK (HCLK/PIX_CLOCK_DIVIDER) | ||
318 | |||
319 | static struct clcd_panel lcd_panel = { | ||
320 | .mode = { | ||
321 | .name = "7.0in Wide (A070VW01)", | ||
322 | .xres = 480, | ||
323 | .yres = 234, | ||
324 | .pixclock = PIX_CLOCK, | ||
325 | .left_margin = 30, | ||
326 | .right_margin = 25, | ||
327 | .upper_margin = 14, | ||
328 | .lower_margin = 12, | ||
329 | .hsync_len = 100, | ||
330 | .vsync_len = 1, | ||
331 | .vmode = FB_VMODE_NONINTERLACED, | ||
332 | }, | ||
333 | .width = -1, | ||
334 | .height = -1, | ||
335 | .tim2 = TIM2_IPC | TIM2_IHS | TIM2_IVS | ||
336 | | (PIX_CLOCK_DIVIDER - 2), | ||
337 | .cntl = CNTL_LCDTFT | CNTL_WATERMARK, | ||
338 | .bpp = 16, | ||
339 | }; | ||
340 | |||
341 | #endif | ||
342 | |||
343 | #undef NS_TO_CLOCK | ||
344 | #undef CLOCK_TO_DIV | ||
345 | |||
346 | #endif /* __LCD_PANEL_H__ */ | ||
diff --git a/arch/arm/mach-lh7a40x/ssp-cpld.c b/arch/arm/mach-lh7a40x/ssp-cpld.c new file mode 100644 index 000000000000..a10830186dac --- /dev/null +++ b/arch/arm/mach-lh7a40x/ssp-cpld.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* arch/arm/mach-lh7a40x/ssp-cpld.c | ||
2 | * | ||
3 | * Copyright (C) 2004,2005 Marc Singer | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * SSP/SPI driver for the CardEngine CPLD. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* NOTES | ||
14 | ----- | ||
15 | |||
16 | o *** This driver is cribbed from the 7952x implementation. | ||
17 | Some comments may not apply. | ||
18 | |||
19 | o This driver contains sufficient logic to control either the | ||
20 | serial EEPROMs or the audio codec. It is included in the kernel | ||
21 | to support the codec. The EEPROMs are really the responsibility | ||
22 | of the boot loader and should probably be left alone. | ||
23 | |||
24 | o The code must be augmented to cope with multiple, simultaneous | ||
25 | clients. | ||
26 | o The audio codec writes to the codec chip whenever playback | ||
27 | starts. | ||
28 | o The touchscreen driver writes to the ads chip every time it | ||
29 | samples. | ||
30 | o The audio codec must write 16 bits, but the touch chip writes | ||
31 | are 8 bits long. | ||
32 | o We need to be able to keep these configurations separate while | ||
33 | simultaneously active. | ||
34 | |||
35 | */ | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/kernel.h> | ||
39 | //#include <linux/sched.h> | ||
40 | #include <linux/errno.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | //#include <linux/ioport.h> | ||
43 | #include <linux/init.h> | ||
44 | #include <linux/delay.h> | ||
45 | #include <linux/spinlock.h> | ||
46 | |||
47 | #include <asm/io.h> | ||
48 | #include <asm/irq.h> | ||
49 | #include <asm/hardware.h> | ||
50 | |||
51 | #include <asm/arch/ssp.h> | ||
52 | |||
53 | //#define TALK | ||
54 | |||
55 | #if defined (TALK) | ||
56 | #define PRINTK(f...) printk (f) | ||
57 | #else | ||
58 | #define PRINTK(f...) do {} while (0) | ||
59 | #endif | ||
60 | |||
61 | #if defined (CONFIG_ARCH_LH7A400) | ||
62 | # define CPLD_SPID __REGP16(CPLD06_VIRT) /* SPI data */ | ||
63 | # define CPLD_SPIC __REGP16(CPLD08_VIRT) /* SPI control */ | ||
64 | # define CPLD_SPIC_CS_CODEC (1<<0) | ||
65 | # define CPLD_SPIC_CS_TOUCH (1<<1) | ||
66 | # define CPLD_SPIC_WRITE (0<<2) | ||
67 | # define CPLD_SPIC_READ (1<<2) | ||
68 | # define CPLD_SPIC_DONE (1<<3) /* r/o */ | ||
69 | # define CPLD_SPIC_LOAD (1<<4) | ||
70 | # define CPLD_SPIC_START (1<<4) | ||
71 | # define CPLD_SPIC_LOADED (1<<5) /* r/o */ | ||
72 | #endif | ||
73 | |||
74 | #define CPLD_SPI __REGP16(CPLD0A_VIRT) /* SPI operation */ | ||
75 | #define CPLD_SPI_CS_EEPROM (1<<3) | ||
76 | #define CPLD_SPI_SCLK (1<<2) | ||
77 | #define CPLD_SPI_TX_SHIFT (1) | ||
78 | #define CPLD_SPI_TX (1<<CPLD_SPI_TX_SHIFT) | ||
79 | #define CPLD_SPI_RX_SHIFT (0) | ||
80 | #define CPLD_SPI_RX (1<<CPLD_SPI_RX_SHIFT) | ||
81 | |||
82 | /* *** FIXME: these timing values are substantially larger than the | ||
83 | *** chip requires. We may implement an nsleep () function. */ | ||
84 | #define T_SKH 1 /* Clock time high (us) */ | ||
85 | #define T_SKL 1 /* Clock time low (us) */ | ||
86 | #define T_CS 1 /* Minimum chip select low time (us) */ | ||
87 | #define T_CSS 1 /* Minimum chip select setup time (us) */ | ||
88 | #define T_DIS 1 /* Data setup time (us) */ | ||
89 | |||
90 | /* EEPROM SPI bits */ | ||
91 | #define P_START (1<<9) | ||
92 | #define P_WRITE (1<<7) | ||
93 | #define P_READ (2<<7) | ||
94 | #define P_ERASE (3<<7) | ||
95 | #define P_EWDS (0<<7) | ||
96 | #define P_WRAL (0<<7) | ||
97 | #define P_ERAL (0<<7) | ||
98 | #define P_EWEN (0<<7) | ||
99 | #define P_A_EWDS (0<<5) | ||
100 | #define P_A_WRAL (1<<5) | ||
101 | #define P_A_ERAL (2<<5) | ||
102 | #define P_A_EWEN (3<<5) | ||
103 | |||
104 | struct ssp_configuration { | ||
105 | int device; | ||
106 | int mode; | ||
107 | int speed; | ||
108 | int frame_size_write; | ||
109 | int frame_size_read; | ||
110 | }; | ||
111 | |||
112 | static struct ssp_configuration ssp_configuration; | ||
113 | static spinlock_t ssp_lock; | ||
114 | |||
115 | static void enable_cs (void) | ||
116 | { | ||
117 | switch (ssp_configuration.device) { | ||
118 | case DEVICE_EEPROM: | ||
119 | CPLD_SPI |= CPLD_SPI_CS_EEPROM; | ||
120 | break; | ||
121 | } | ||
122 | udelay (T_CSS); | ||
123 | } | ||
124 | |||
125 | static void disable_cs (void) | ||
126 | { | ||
127 | switch (ssp_configuration.device) { | ||
128 | case DEVICE_EEPROM: | ||
129 | CPLD_SPI &= ~CPLD_SPI_CS_EEPROM; | ||
130 | break; | ||
131 | } | ||
132 | udelay (T_CS); | ||
133 | } | ||
134 | |||
135 | static void pulse_clock (void) | ||
136 | { | ||
137 | CPLD_SPI |= CPLD_SPI_SCLK; | ||
138 | udelay (T_SKH); | ||
139 | CPLD_SPI &= ~CPLD_SPI_SCLK; | ||
140 | udelay (T_SKL); | ||
141 | } | ||
142 | |||
143 | |||
144 | /* execute_spi_command | ||
145 | |||
146 | sends an spi command to a device. It first sends cwrite bits from | ||
147 | v. If cread is greater than zero it will read cread bits | ||
148 | (discarding the leading 0 bit) and return them. If cread is less | ||
149 | than zero it will check for completetion status and return 0 on | ||
150 | success or -1 on timeout. If cread is zero it does nothing other | ||
151 | than sending the command. | ||
152 | |||
153 | On the LPD7A400, we can only read or write multiples of 8 bits on | ||
154 | the codec and the touch screen device. Here, we round up. | ||
155 | |||
156 | */ | ||
157 | |||
158 | static int execute_spi_command (int v, int cwrite, int cread) | ||
159 | { | ||
160 | unsigned long l = 0; | ||
161 | |||
162 | #if defined (CONFIG_MACH_LPD7A400) | ||
163 | /* The codec and touch devices cannot be bit-banged. Instead, | ||
164 | * the CPLD provides an eight-bit shift register and a crude | ||
165 | * interface. */ | ||
166 | if ( ssp_configuration.device == DEVICE_CODEC | ||
167 | || ssp_configuration.device == DEVICE_TOUCH) { | ||
168 | int select = 0; | ||
169 | |||
170 | PRINTK ("spi(%d %d.%d) 0x%04x", | ||
171 | ssp_configuration.device, cwrite, cread, | ||
172 | v); | ||
173 | #if defined (TALK) | ||
174 | if (ssp_configuration.device == DEVICE_CODEC) | ||
175 | PRINTK (" 0x%03x -> %2d", v & 0x1ff, (v >> 9) & 0x7f); | ||
176 | #endif | ||
177 | PRINTK ("\n"); | ||
178 | |||
179 | if (ssp_configuration.device == DEVICE_CODEC) | ||
180 | select = CPLD_SPIC_CS_CODEC; | ||
181 | if (ssp_configuration.device == DEVICE_TOUCH) | ||
182 | select = CPLD_SPIC_CS_TOUCH; | ||
183 | if (cwrite) { | ||
184 | for (cwrite = (cwrite + 7)/8; cwrite-- > 0; ) { | ||
185 | CPLD_SPID = (v >> (8*cwrite)) & 0xff; | ||
186 | CPLD_SPIC = select | CPLD_SPIC_LOAD; | ||
187 | while (!(CPLD_SPIC & CPLD_SPIC_LOADED)) | ||
188 | ; | ||
189 | CPLD_SPIC = select; | ||
190 | while (!(CPLD_SPIC & CPLD_SPIC_DONE)) | ||
191 | ; | ||
192 | } | ||
193 | v = 0; | ||
194 | } | ||
195 | if (cread) { | ||
196 | mdelay (2); /* *** FIXME: required by ads7843? */ | ||
197 | v = 0; | ||
198 | for (cread = (cread + 7)/8; cread-- > 0;) { | ||
199 | CPLD_SPID = 0; | ||
200 | CPLD_SPIC = select | CPLD_SPIC_READ | ||
201 | | CPLD_SPIC_START; | ||
202 | while (!(CPLD_SPIC & CPLD_SPIC_LOADED)) | ||
203 | ; | ||
204 | CPLD_SPIC = select | CPLD_SPIC_READ; | ||
205 | while (!(CPLD_SPIC & CPLD_SPIC_DONE)) | ||
206 | ; | ||
207 | v = (v << 8) | CPLD_SPID; | ||
208 | } | ||
209 | } | ||
210 | return v; | ||
211 | } | ||
212 | #endif | ||
213 | |||
214 | PRINTK ("spi(%d) 0x%04x -> 0x%x\r\n", ssp_configuration.device, | ||
215 | v & 0x1ff, (v >> 9) & 0x7f); | ||
216 | |||
217 | enable_cs (); | ||
218 | |||
219 | v <<= CPLD_SPI_TX_SHIFT; /* Correction for position of SPI_TX bit */ | ||
220 | while (cwrite--) { | ||
221 | CPLD_SPI | ||
222 | = (CPLD_SPI & ~CPLD_SPI_TX) | ||
223 | | ((v >> cwrite) & CPLD_SPI_TX); | ||
224 | udelay (T_DIS); | ||
225 | pulse_clock (); | ||
226 | } | ||
227 | |||
228 | if (cread < 0) { | ||
229 | int delay = 10; | ||
230 | disable_cs (); | ||
231 | udelay (1); | ||
232 | enable_cs (); | ||
233 | |||
234 | l = -1; | ||
235 | do { | ||
236 | if (CPLD_SPI & CPLD_SPI_RX) { | ||
237 | l = 0; | ||
238 | break; | ||
239 | } | ||
240 | } while (udelay (1), --delay); | ||
241 | } | ||
242 | else | ||
243 | /* We pulse the clock before the data to skip the leading zero. */ | ||
244 | while (cread-- > 0) { | ||
245 | pulse_clock (); | ||
246 | l = (l<<1) | ||
247 | | (((CPLD_SPI & CPLD_SPI_RX) | ||
248 | >> CPLD_SPI_RX_SHIFT) & 0x1); | ||
249 | } | ||
250 | |||
251 | disable_cs (); | ||
252 | return l; | ||
253 | } | ||
254 | |||
255 | static int ssp_init (void) | ||
256 | { | ||
257 | spin_lock_init (&ssp_lock); | ||
258 | memset (&ssp_configuration, 0, sizeof (ssp_configuration)); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | |||
263 | /* ssp_chip_select | ||
264 | |||
265 | drops the chip select line for the CPLD shift-register controlled | ||
266 | devices. It doesn't enable chip | ||
267 | |||
268 | */ | ||
269 | |||
270 | static void ssp_chip_select (int enable) | ||
271 | { | ||
272 | #if defined (CONFIG_MACH_LPD7A400) | ||
273 | int select; | ||
274 | |||
275 | if (ssp_configuration.device == DEVICE_CODEC) | ||
276 | select = CPLD_SPIC_CS_CODEC; | ||
277 | else if (ssp_configuration.device == DEVICE_TOUCH) | ||
278 | select = CPLD_SPIC_CS_TOUCH; | ||
279 | else | ||
280 | return; | ||
281 | |||
282 | if (enable) | ||
283 | CPLD_SPIC = select; | ||
284 | else | ||
285 | CPLD_SPIC = 0; | ||
286 | #endif | ||
287 | } | ||
288 | |||
289 | static void ssp_acquire (void) | ||
290 | { | ||
291 | spin_lock (&ssp_lock); | ||
292 | } | ||
293 | |||
294 | static void ssp_release (void) | ||
295 | { | ||
296 | ssp_chip_select (0); /* just in case */ | ||
297 | spin_unlock (&ssp_lock); | ||
298 | } | ||
299 | |||
300 | static int ssp_configure (int device, int mode, int speed, | ||
301 | int frame_size_write, int frame_size_read) | ||
302 | { | ||
303 | ssp_configuration.device = device; | ||
304 | ssp_configuration.mode = mode; | ||
305 | ssp_configuration.speed = speed; | ||
306 | ssp_configuration.frame_size_write = frame_size_write; | ||
307 | ssp_configuration.frame_size_read = frame_size_read; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int ssp_read (void) | ||
313 | { | ||
314 | return execute_spi_command (0, 0, ssp_configuration.frame_size_read); | ||
315 | } | ||
316 | |||
317 | static int ssp_write (u16 data) | ||
318 | { | ||
319 | execute_spi_command (data, ssp_configuration.frame_size_write, 0); | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int ssp_write_read (u16 data) | ||
324 | { | ||
325 | return execute_spi_command (data, ssp_configuration.frame_size_write, | ||
326 | ssp_configuration.frame_size_read); | ||
327 | } | ||
328 | |||
329 | struct ssp_driver lh7a40x_cpld_ssp_driver = { | ||
330 | .init = ssp_init, | ||
331 | .acquire = ssp_acquire, | ||
332 | .release = ssp_release, | ||
333 | .configure = ssp_configure, | ||
334 | .chip_select = ssp_chip_select, | ||
335 | .read = ssp_read, | ||
336 | .write = ssp_write, | ||
337 | .write_read = ssp_write_read, | ||
338 | }; | ||
339 | |||
340 | |||
341 | MODULE_AUTHOR("Marc Singer"); | ||
342 | MODULE_DESCRIPTION("LPD7A40X CPLD SPI driver"); | ||
343 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c index be377e331f25..ef9af375fcc4 100644 --- a/arch/arm/mach-lh7a40x/time.c +++ b/arch/arm/mach-lh7a40x/time.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/mach-lh7a40x/time.c | 2 | * arch/arm/mach-lh7a40x/time.c |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Logic Product Development | 4 | * Copyright (C) 2004 Logic Product Development |
@@ -57,7 +57,7 @@ static struct irqaction lh7a40x_timer_irq = { | |||
57 | .handler = lh7a40x_timer_interrupt, | 57 | .handler = lh7a40x_timer_interrupt, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static void __init lh7a40x_timer_init(void) | 60 | static void __init lh7a40x_timer_init (void) |
61 | { | 61 | { |
62 | /* Stop/disable all timers */ | 62 | /* Stop/disable all timers */ |
63 | TIMER_CONTROL1 = 0; | 63 | TIMER_CONTROL1 = 0; |