sync hh.org
[hh.org.git] / drivers / soc / tc6393xb.c
blob3ca1d4dc2c2a86da235f979cab3dd3c7423549f1
1 /*
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
9 * Based on locomo.c
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>
37 #include <asm/io.h>
38 #include <asm/arch/pxa-regs.h>
40 #include <soc/tc6393.h>
41 #include "soc-core.h"
43 #define platform_get_platdata(_dev) ((_dev)->dev.platform_data)
45 struct tc6393xb_data
47 int irq_base, irq_nr;
48 void *mapbase;
49 struct platform_device *devices;
50 int ndevices;
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);
58 /* Sequence:
59 * SMD Buffer ON (gpio related)
60 * Enable the clock (SCRUNEN)
61 * Set the ctl reg base address
62 * Enable the ctl reg
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);
69 // return 0;
72 static void tc6393xb_nand_suspend(struct platform_device *sdev) {
73 printk("nand_suspend()\n");
74 // return 0;
77 static void tc6393xb_nand_resume(struct platform_device *sdev) {
78 printk("nand_resume()\n");
79 // return 0;
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);
90 unsigned char tmp;
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,
104 #if 0
105 static void tc6393xb_ohci_hwinit(struct platform_device *sdev) {
106 struct tc6393xb_data *chip = platform_get_drvdata(sdev);
107 unsigned char tmp;
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,
120 #endif
122 static struct resource tc6393xb_mmc_resources[] = {
124 .name = "control",
125 .start = TC6393XB_MMC_CTL_BASE,
126 .end = TC6393XB_MMC_CTL_BASE + 0x1ff,
127 .flags = IORESOURCE_MEM,
130 .name = "config",
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[] = {
144 .name = "control",
145 .start = TC6393XB_NAND_CTL_BASE,
146 .end = TC6393XB_NAND_CTL_BASE + 0x1ff,
147 .flags = IORESOURCE_MEM,
150 .name = "config",
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[] = {
159 .name = "tmio_mmc",
160 .res = tc6393xb_mmc_resources,
161 .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
162 .hwconfig = &tc6393xb_mmc_hwconfig,
165 .name = "tmio-nand",
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)
183 int req, i;
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)
226 int i;
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");
248 return;
251 if (pdata->hw_init)
252 pdata->hw_init();
254 writew(0, tchip->mapbase + TC6393_SYS_FER);
256 /* Clock setting */
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);
261 /* GPIO */
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);
268 #ifdef CONFIG_PM
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)
275 pdata->suspend();
277 return 0;
280 static int tc6393xb_resume(struct platform_device *dev)
282 struct tc6393xb_platform_data *pdata = platform_get_platdata(dev);
284 if (pdata && pdata->resume)
285 pdata->resume();
287 tc6393xb_hwinit(dev);
289 return 0;
292 #else
293 #define tc6393xb_suspend NULL
294 #define tc6393xb_resume NULL
295 #endif
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;
301 int err = -ENOMEM;
302 struct tc6393xb_data *data;
304 data = kmalloc (sizeof (struct tc6393xb_data), GFP_KERNEL);
305 if (!data)
306 goto out;
308 data->irq_base = alloc_irq_space (TC6393XB_NR_IRQS);
309 data->irq_nr = dev->resource[1].start;
311 if (data->irq_base == -1)
312 goto out_free_data;
314 data->mapbase = ioremap(pbase, plen);
315 if(!data->mapbase)
316 goto out_free_irqs;
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);
335 if(!data->devices) {
336 printk(KERN_INFO "%s: Failed to allocate devices!\n",
337 dev->name);
338 goto out_free_devices;
341 return 0;
343 out_free_devices:
344 //FIXME tc6393xb_remove_devices(data);
345 out_free_irqs:
346 free_irq_space(data->irq_base, TC6393XB_NR_IRQS);
347 out_free_data:
348 kfree(data);
349 out:
350 return err;
353 static int tc6393xb_remove(struct platform_device *dev)
355 struct tc6393xb_data *tchip = platform_get_drvdata(dev);
356 int i;
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);
373 // Free IRQ ?
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);
381 kfree (tchip);
383 return 0;
387 static struct platform_driver tc6393xb_device_driver = {
388 .driver = {
389 .name = "tc6393xb",
391 .probe = tc6393xb_probe,
392 .remove = tc6393xb_remove,
393 #ifdef CONFIG_PM
394 .suspend = tc6393xb_suspend,
395 .resume = tc6393xb_resume,
396 #endif
400 static int __init tc6393xb_init(void)
402 int retval = 0;
403 retval = platform_driver_register (&tc6393xb_device_driver);
404 return retval;
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");