2 * linux/arch/arm/common/tc6393xb_soc.c
4 * Toshiba TC6393 support
5 * Copyright (c) 2005 Dirk Opfer
6 * Copyright (c) 2005 Ian Molton <spyro@f2s.com>
8 * Based on code written by Sharp/Lineo for 2.4 kernels
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.
15 * This file contains all generic TC6393 support.
17 * 19/03/2005 IM Fixed IRQ code
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/kernel.h>
24 #include <linux/delay.h>
25 #include <linux/errno.h>
26 #include <linux/ioport.h>
27 #include <linux/irq.h>
28 #include <linux/device.h>
29 #include <linux/slab.h>
30 #include <linux/spinlock.h>
31 #include <linux/soc/tmio_mmc.h>
32 #include <linux/soc/tmio_nand.h>
33 #include <linux/soc/tmio_ohci.h>
35 #include <asm/hardware.h>
36 #include <asm/mach-types.h>
38 #include <asm/arch/pxa-regs.h>
40 #include <soc/tc6393.h>
43 #define platform_get_platdata(_dev) ((_dev)->dev.platform_data)
49 struct platform_device
*devices
;
53 /* Setup the TC6393XB NAND flash controllers configuration registers */
54 static void tc6393xb_nand_hwinit(struct platform_device
*sdev
) {
56 struct tc6393xb_data
*chip
= platform_get_drvdata(sdev
);
59 * SMD Buffer ON (gpio related)
60 * Enable the clock (SCRUNEN)
61 * Set the ctl reg base address
63 * Configure power control (control bt PCNT[1,0] 4ms startup delay)
65 printk("nand_hwinit(0x%08lx)\n", (unsigned long)chip
->mapbase
);
66 /* (89h) SMD Buffer ON By TC6393XB SystemConfig gpibfc1*/
67 writew(0xff, chip
->mapbase
+ TC6393_SYS_GPIBCR1
);
72 static void tc6393xb_nand_suspend(struct platform_device
*sdev
) {
73 printk("nand_suspend()\n");
77 static void tc6393xb_nand_resume(struct platform_device
*sdev
) {
78 printk("nand_resume()\n");
82 static struct tmio_nand_hwconfig tc6393xb_nand_hwconfig
= {
83 .hwinit
= tc6393xb_nand_hwinit
,
84 .suspend
= tc6393xb_nand_suspend
,
85 .resume
= tc6393xb_nand_resume
,
88 static void tc6393xb_mmc_set_clock(struct platform_device
*sdev
, int state
) {
89 struct tc6393xb_data
*chip
= platform_get_drvdata(sdev
);
92 printk("mmc_set_clock(0x%08lx)\n", (unsigned long)chip
->mapbase
);
93 if(state
== MMC_CLOCK_ENABLED
){
94 tmp
= readw(chip
->mapbase
+ TC6393_SYS_GPIBCR1
);
95 writew(tmp
| CK32KEN
, chip
->mapbase
+ TC6393_SYS_GPIBCR1
);
96 //FIXME - need to disable too...
100 static struct tmio_mmc_hwconfig tc6393xb_mmc_hwconfig
= {
101 .set_mmc_clock
= tc6393xb_mmc_set_clock
,
105 static void tc6393xb_ohci_hwinit(struct platform_device
*sdev
) {
106 struct tc6393xb_data
*chip
= platform_get_drvdata(sdev
);
109 // enable usb clock - sysconf + 0x98, halfword, bit D1 (0x2)
110 // FIXME - setting this reg could use some locking...
111 tmp
= readw(chip
->mapbase
+ TC6393_SYS_GPIBCR1
);
112 writew(tmp
| USBCLK
, chip
->mapbase
+ TC6393_SYS_GPIBCR1
);
113 // enable usb function - sysconf + 0xe0 bit D0 (0x1)
114 writeb(0x1, chip
->mapbase
+ 0xe0);
117 static struct tmio_ohci_hwconfig tc6393xb_ohci_hwconfig
= {
118 .hwinit
= tc6393xb_ohci_hwinit
,
122 static struct resource tc6393xb_mmc_resources
[] = {
125 .start
= TC6393XB_MMC_CTL_BASE
,
126 .end
= TC6393XB_MMC_CTL_BASE
+ 0x1ff,
127 .flags
= IORESOURCE_MEM
,
131 .start
= TC6393XB_MMC_CNF_BASE
,
132 .end
= TC6393XB_MMC_CNF_BASE
+ 0xff,
133 .flags
= IORESOURCE_MEM
,
136 .start
= TC6393XB_MMC_IRQ
,
137 .end
= TC6393XB_MMC_IRQ
,
138 .flags
= IORESOURCE_IRQ
| IORESOURCE_IRQ_SOC_SUBDEVICE
,
142 static struct resource tc6393xb_nand_resources
[] = {
145 .start
= TC6393XB_NAND_CTL_BASE
,
146 .end
= TC6393XB_NAND_CTL_BASE
+ 0x1ff,
147 .flags
= IORESOURCE_MEM
,
151 .start
= TC6393XB_NAND_CNF_BASE
,
152 .end
= TC6393XB_NAND_CNF_BASE
+ 0xff,
153 .flags
= IORESOURCE_MEM
,
157 static struct soc_device_data tc6393xb_devices
[] = {
160 .res
= tc6393xb_mmc_resources
,
161 .num_resources
= ARRAY_SIZE(tc6393xb_mmc_resources
),
162 .hwconfig
= &tc6393xb_mmc_hwconfig
,
166 .res
= tc6393xb_nand_resources
,
167 .num_resources
= ARRAY_SIZE(tc6393xb_nand_resources
),
168 .hwconfig
= &tc6393xb_nand_hwconfig
,
172 /** TC6393 interrupt handling stuff.
173 * NOTE: TC6393 has a 1 to many mapping on all of its IRQs.
174 * that is, there is only one real hardware interrupt
175 * we determine which interrupt it is by reading some IO memory.
176 * We have two levels of expansion, first in the handler for the
177 * hardware interrupt we generate an interrupt
178 * IRQ_TC6393_*_BASE and those handlers generate more interrupts
181 static void tc6393xb_irq_handler(unsigned int irq
, struct irq_desc
*desc
)
184 struct tc6393xb_data
*data
= get_irq_data(irq
);
186 /* Acknowledge the parent IRQ */
187 desc
->chip
->ack(irq
);
189 while ( (req
= (readb(data
->mapbase
+ TC6393_SYS_ISR
)
190 & ~(readb(data
->mapbase
+ TC6393_SYS_IMR
)))) ) {
191 for (i
= 0; i
<= 7; i
++) {
192 int dev_irq
= data
->irq_base
+ i
;
193 struct irq_desc
*d
= NULL
;
194 if ((req
& (1<<i
))) {
195 if(i
!= 1) printk("IRQ! from %d\n", i
);
196 d
= irq_desc
+ dev_irq
;
197 d
->handle_irq(dev_irq
, d
);
203 static void tc6393xb_mask_irq(unsigned int irq
)
205 struct tc6393xb_data
*tc6393
= get_irq_chipdata(irq
);
207 writeb(readb(tc6393
->mapbase
+ TC6393_SYS_IMR
) | 1 << (irq
- tc6393
->irq_base
),tc6393
->mapbase
+ TC6393_SYS_IMR
);
210 static void tc6393xb_unmask_irq(unsigned int irq
)
212 struct tc6393xb_data
*tc6393
= get_irq_chipdata(irq
);
214 writeb(readb(tc6393
->mapbase
+ TC6393_SYS_IMR
) & ~( 1 << (irq
- tc6393
->irq_base
)),tc6393
->mapbase
+ TC6393_SYS_IMR
);
217 static struct irqchip tc6393xb_chip
= {
218 .ack
= tc6393xb_mask_irq
,
219 .mask
= tc6393xb_mask_irq
,
220 .unmask
= tc6393xb_unmask_irq
,
224 static void tc6393xb_setup_irq(struct tc6393xb_data
*tchip
)
228 for (i
= 0; i
< TC6393XB_NR_IRQS
; i
++) {
229 int irq
= tchip
->irq_base
+ i
;
230 set_irq_chip (irq
, &tc6393xb_chip
);
231 set_irq_chip_data (irq
, tchip
);
232 set_irq_handler (irq
, do_level_IRQ
);
233 set_irq_flags(irq
, IRQF_VALID
| IRQF_PROBE
);
236 set_irq_data (tchip
->irq_nr
, tchip
);
237 set_irq_chained_handler (tchip
->irq_nr
, tc6393xb_irq_handler
);
238 set_irq_type (tchip
->irq_nr
, IRQT_FALLING
);
241 void tc6393xb_hwinit(struct platform_device
*dev
)
243 struct tc6393xb_platform_data
*pdata
= platform_get_platdata(dev
);
244 struct tc6393xb_data
*tchip
= platform_get_drvdata(dev
);
246 if(!pdata
|| !tchip
){
247 BUG_ON("no driver data!\n");
254 writew(0, tchip
->mapbase
+ TC6393_SYS_FER
);
257 writew(pdata
->sys_pll2cr
, tchip
->mapbase
+ TC6393_SYS_PLL2CR
);
258 writew(pdata
->sys_ccr
, tchip
->mapbase
+ TC6393_SYS_CCR
);
259 writew(pdata
->sys_mcr
, tchip
->mapbase
+ TC6393_SYS_MCR
);
262 writew(pdata
->sys_gper
, tchip
->mapbase
+ TC6393_SYS_GPER
);
263 writew(pdata
->sys_gpodsr1
, tchip
->mapbase
+ TC6393_SYS_GPODSR1
);
264 writew(pdata
->sys_gpooecr1
, tchip
->mapbase
+ TC6393_SYS_GPOOECR1
);
270 static int tc6393xb_suspend(struct platform_device
*dev
, pm_message_t state
)
272 struct tc6393xb_platform_data
*pdata
= platform_get_platdata(dev
);
274 if (pdata
&& pdata
->suspend
)
280 static int tc6393xb_resume(struct platform_device
*dev
)
282 struct tc6393xb_platform_data
*pdata
= platform_get_platdata(dev
);
284 if (pdata
&& pdata
->resume
)
287 tc6393xb_hwinit(dev
);
293 #define tc6393xb_suspend NULL
294 #define tc6393xb_resume NULL
297 static int tc6393xb_probe(struct platform_device
*dev
)
299 unsigned long pbase
= (unsigned long)dev
->resource
[0].start
;
300 unsigned long plen
= dev
->resource
[0].end
- dev
->resource
[0].start
;
302 struct tc6393xb_data
*data
;
304 data
= kmalloc (sizeof (struct tc6393xb_data
), GFP_KERNEL
);
308 data
->irq_base
= alloc_irq_space (TC6393XB_NR_IRQS
);
309 data
->irq_nr
= dev
->resource
[1].start
;
311 if (data
->irq_base
== -1)
314 data
->mapbase
= ioremap(pbase
, plen
);
318 platform_set_drvdata(dev
, data
);
319 tc6393xb_setup_irq (data
);
320 tc6393xb_hwinit(dev
);
322 /* Enable (but mask!) our IRQs */
323 writew(0, data
->mapbase
+ TC6393_SYS_IRR
);
324 writew(0xbf, data
->mapbase
+ TC6393_SYS_IMR
);
326 printk(KERN_INFO
"%s rev %d @ 0x%08lx using irq %d-%d on irq %d\n",
327 dev
->name
, readw(data
->mapbase
+ TC6393_SYS_RIDR
),
328 (unsigned long)data
->mapbase
, data
->irq_base
,
329 data
->irq_base
+ TC6393XB_NR_IRQS
- 1, data
->irq_nr
);
331 data
->devices
= soc_add_devices(dev
, tc6393xb_devices
,
332 ARRAY_SIZE(tc6393xb_devices
),
333 &dev
->resource
[0], data
->irq_base
);
336 printk(KERN_INFO
"%s: Failed to allocate devices!\n",
338 goto out_free_devices
;
344 //FIXME tc6393xb_remove_devices(data);
346 free_irq_space(data
->irq_base
, TC6393XB_NR_IRQS
);
353 static int tc6393xb_remove(struct platform_device
*dev
)
355 struct tc6393xb_data
*tchip
= platform_get_drvdata(dev
);
358 /* Free the subdevice resources */
359 for (i
= 0; i
< tchip
->ndevices
; i
++) {
360 platform_device_unregister (&tchip
->devices
[i
]);
361 kfree (tchip
->devices
[i
].resource
);
364 /* Take down IRQ handling */
365 for (i
= 0; i
< TC6393XB_NR_IRQS
; i
++) {
366 int irq
= i
+ tchip
->irq_base
;
367 set_irq_handler (irq
, NULL
);
368 set_irq_chip (irq
, NULL
);
369 set_irq_chip_data (irq
, NULL
);
372 set_irq_chained_handler (tchip
->irq_nr
, NULL
);
375 //FIXME - put chip to sleep?
377 /* Free core resources */
378 iounmap (tchip
->mapbase
);
379 //FIXME tc6393xb_remove_devices(tchip);
380 free_irq_space (tchip
->irq_base
, TC6393XB_NR_IRQS
);
387 static struct platform_driver tc6393xb_device_driver
= {
391 .probe
= tc6393xb_probe
,
392 .remove
= tc6393xb_remove
,
394 .suspend
= tc6393xb_suspend
,
395 .resume
= tc6393xb_resume
,
400 static int __init
tc6393xb_init(void)
403 retval
= platform_driver_register (&tc6393xb_device_driver
);
407 static void __exit
tc6393xb_exit(void)
409 platform_driver_unregister(&tc6393xb_device_driver
);
412 module_init(tc6393xb_init
);
413 module_exit(tc6393xb_exit
);
415 MODULE_DESCRIPTION("Toshiba TC6393 core driver");
416 MODULE_LICENSE("GPL");
417 MODULE_AUTHOR("Dirk Opfer and Ian Molton");