summaryrefslogtreecommitdiff
path: root/packages/linux/linux-rp-2.6.18/tmio-tc6393-r7.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-rp-2.6.18/tmio-tc6393-r7.patch')
-rw-r--r--packages/linux/linux-rp-2.6.18/tmio-tc6393-r7.patch793
1 files changed, 793 insertions, 0 deletions
diff --git a/packages/linux/linux-rp-2.6.18/tmio-tc6393-r7.patch b/packages/linux/linux-rp-2.6.18/tmio-tc6393-r7.patch
new file mode 100644
index 0000000000..844e3757a1
--- /dev/null
+++ b/packages/linux/linux-rp-2.6.18/tmio-tc6393-r7.patch
@@ -0,0 +1,793 @@
+Index: linux-2.6.18/arch/arm/common/tc6393xb.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.18/arch/arm/common/tc6393xb.c 2006-09-20 16:17:02.000000000 +0200
+@@ -0,0 +1,669 @@
++/*
++ * Toshiba TC6393XB SoC support
++ *
++ * Maintainer: Chris Humbert <mahadri-kernel@drigon.com>
++ *
++ * Copyright (c) 2005-2006 Chris Humbert
++ * Copyright (c) 2005 Dirk Opfer
++ *
++ * Based on code written by Sharp/Lineo for 2.4 kernels
++ * Based on locomo.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/fb.h>
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach/irq.h>
++#include <asm/arch/irqs.h>
++#include <asm/hardware/tmio.h>
++
++#ifndef TMIO_SOC_TC6393XB
++#error "TC6393XB SoC not configured"
++#endif
++
++/*--------------------------------------------------------------------------*/
++
++/* cell ids must be 0-based because they are used as array indexes. */
++#define TC6393_CELL_NAND 0
++#define TC6393_CELL_SD 1
++#define TC6393_CELL_OHCI 2
++#define TC6393_CELL_SERIAL 3
++#define TC6393_CELL_LCD 4
++#define TC6393_NUM_CELLS 5
++
++#define TC6393_RESOURCE(_name, _start, _end, _flags) \
++ { \
++ .name = _name, \
++ .start = _start, \
++ .end = _end, \
++ .flags = _flags, \
++ }
++
++#define TC6393_MEM(name, start, size) \
++ TC6393_RESOURCE(name, start, (start) + (size) - 1, IORESOURCE_MEM)
++
++#define TC6393_IRQ(name, irq) \
++ TC6393_RESOURCE(name, irq, irq, IORESOURCE_IRQ)
++
++const static struct resource tc6393_NAND_resource[] = {
++ TC6393_MEM (TMIO_NAME_NAND, 0x000100, 0x100),
++ TC6393_MEM (TMIO_NAME_NAND, 0x001000, 0x008),
++ TC6393_MEM (TMIO_NAME_NAND, 0, 0),
++ TC6393_IRQ (TMIO_NAME_NAND, IRQ_TC6393_NAND),
++};
++
++const static struct resource tc6393_SD_resource[] = {
++ TC6393_MEM (TMIO_NAME_SD, 0x000200, 0x100),
++ TC6393_MEM (TMIO_NAME_SD, 0x002000, 0x200),
++ TC6393_MEM (TMIO_NAME_SD, 0, 0),
++ TC6393_IRQ (TMIO_NAME_SD, IRQ_TC6393_SD),
++};
++
++const static struct resource tc6393_OHCI_resource[] = {
++ TC6393_MEM (TMIO_NAME_OHCI, 0x000300, 0x100),
++ TC6393_MEM (TMIO_NAME_OHCI, 0x003000, 0x100),
++ TC6393_MEM (TMIO_NAME_OHCI, 0x010000, 32 * 1024),
++ TC6393_IRQ (TMIO_NAME_OHCI, IRQ_TC6393_OHCI),
++};
++
++const static struct resource tc6393_SERIAL_resource[] = {
++ TC6393_MEM (TMIO_NAME_SERIAL, 0x000400, 0x100),
++ TC6393_MEM (TMIO_NAME_SERIAL, 0x004000, 0x100),
++ TC6393_MEM (TMIO_NAME_SERIAL, 0, 0),
++ TC6393_IRQ (TMIO_NAME_SERIAL, IRQ_TC6393_SERIAL),
++};
++
++const static struct resource tc6393_LCD_resource[] = {
++ TC6393_MEM (TMIO_NAME_LCD, 0x000500, 0x100),
++ TC6393_MEM (TMIO_NAME_LCD, 0x005000, 0x200),
++ TC6393_MEM (TMIO_NAME_LCD, 0x100000, 1024 * 1024),
++ TC6393_IRQ (TMIO_NAME_LCD, IRQ_TC6393_LCD),
++};
++
++#define TC6393_CELL(_NAME) \
++ [TC6393_CELL_##_NAME] = { \
++ .name = TMIO_NAME_##_NAME, \
++ .id = TC6393_CELL_##_NAME, \
++ .resource = tc6393_##_NAME##_resource, \
++ .num_resources = ARRAY_SIZE (tc6393_##_NAME##_resource), \
++ }
++
++struct tc6393_cell {
++ const char* name;
++ unsigned int id;
++ const struct resource* resource;
++ unsigned int num_resources;
++};
++
++const static struct tc6393_cell tc6393_cell [TC6393_NUM_CELLS] = {
++ TC6393_CELL (NAND ),
++ TC6393_CELL (SD ),
++ TC6393_CELL (OHCI ),
++ TC6393_CELL (SERIAL ),
++ TC6393_CELL (LCD ),
++};
++
++/*--------------------------------------------------------------------------*/
++
++/*
++ * TC6393 System Configuration Register
++ */
++struct tc6393_scr {
++ u8 x00[8];
++ u8 revid; /* 0x08 Revision ID */
++ u8 x01[0x47];
++ u8 isr; /* 0x50 Interrupt Status */
++ u8 x02;
++ u8 imr; /* 0x52 Interrupt Mask */
++ u8 x03;
++ u8 irr; /* 0x54 Interrupt Routing */
++ u8 x04[0x0b];
++ u16 gper; /* 0x60 GP Enable */
++ u8 x05[2];
++ u16 gpi_sr[2]; /* 0x64 GPI Status */
++ u16 gpi_imr[2]; /* 0x68 GPI INT Mask */
++ u16 gpi_eder[2]; /* 0x6c GPI Edge Detect Enable */
++ u16 gpi_lir[4]; /* 0x70 GPI Level Invert */
++ u16 gpo_dsr[2]; /* 0x78 GPO Data Set */
++ u16 gpo_doecr[2]; /* 0x7c GPO Data OE Control */
++ u16 gp_iarcr[2]; /* 0x80 GP Internal Active Reg Control */
++ u16 gp_iarlcr[2]; /* 0x84 GP Internal Active Reg Level Con*/
++ u8 gpi_bcr[4]; /* 0x88 GPI Buffer Control */
++ u16 gpa_iarcr; /* 0x8c GPa Internal Active Reg Control */
++ u8 x06[2];
++ u16 gpa_iarlcr; /* 0x90 GPa Internal Active Reg Level Co*/
++ u8 x07[2];
++ u16 gpa_bcr; /* 0x94 GPa Buffer Control */
++ u8 x08[2];
++ u16 ccr; /* 0x98 Clock Control */
++ u16 pll2cr; /* 0x9a PLL2 Control */
++ u16 pll1cr[2]; /* 0x9c PLL1 Control */
++ u8 diarcr; /* 0xa0 Device Internal Active Reg Contr*/
++ u8 dbocr; /* 0xa1 Device Buffer Off Control */
++ u8 x09[0x3e];
++ u8 fer; /* 0xe0 Function Enable */
++ u8 x10[3];
++ u16 mcr; /* 0xe4 Mode Control */
++ u8 x11[0x14];
++ u8 config; /* 0xfc Configuration Control */
++ u8 x12[2];
++ u8 debug; /* 0xff Debug */
++} __attribute__ ((packed));
++
++union tc6393_scr_fer {
++ u8 raw;
++struct {
++ unsigned usben:1; /* D0 USB enable */
++ unsigned lcdcven:1; /* D1 polysylicon TFT enable */
++ unsigned slcden:1; /* D2 SLCD enable */
++} __attribute__ ((packed));
++} __attribute__ ((packed));
++
++union tc6393_scr_ccr {
++ u16 raw;
++struct {
++ unsigned ck32ken:1; /* D0 SD host clock enable */
++ unsigned usbcken:1; /* D1 USB host clock enable */
++ unsigned x00:2;
++ unsigned sharp:1; /* D4 ??? set in Sharp's code */
++ unsigned x01:3;
++ enum { disable = 0,
++ m12MHz = 1,
++ m24MHz = 2,
++ m48MHz = 3,
++ } mclksel:3; /* D10-D8 LCD controller clock */
++ unsigned x02:1;
++ enum { h24MHz = 0,
++ h48MHz = 1,
++ } hclksel:2; /* D13-D12 host bus clock */
++ unsigned x03:2;
++} __attribute__ ((packed));
++} __attribute__ ((packed));
++
++/*--------------------------------------------------------------------------*/
++
++struct tc6393 {
++ spinlock_t lock; /* read-modify-write lock */
++ struct device* dev; /* TC6393 device */
++ struct tc6393_scr __iomem *scr; /* system configuration reg */
++
++ struct resource rscr; /* system config reg resource */
++ struct resource* iomem; /* entire TC6393 iomem resource */
++ unsigned int irq; /* hardware cascade irq */
++
++ struct tmio_device tdev [TC6393_NUM_CELLS];
++};
++
++/*--------------------------------------------------------------------------*/
++
++static u32 tc6393_ioread32 (const void __iomem *addr)
++{
++ return ((u32) ioread16 (addr)) | (((u32) ioread16 (addr + 2)) << 16);
++}
++
++static u32 tc6393_iowrite32 (u32 val, const void __iomem *addr)
++{
++ iowrite16 (val, addr);
++ iowrite16 (val >> 16, addr + 2);
++ return val;
++}
++
++u32 get_tc6393_gpio (struct device *dev)
++{
++ struct tc6393* tc6393 = dev_get_drvdata (dev);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++
++ return tc6393_ioread32 (scr->gpo_dsr);
++}
++EXPORT_SYMBOL (get_tc6393_gpio);
++
++u32 set_tc6393_gpio (struct device *dev, u32 bits)
++{
++ struct tc6393* tc6393 = dev_get_drvdata (dev);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ unsigned long flags;
++ u32 dsr;
++
++ spin_lock_irqsave (&tc6393->lock, flags);
++ dsr = tc6393_ioread32 (scr->gpo_dsr) | bits;
++ tc6393_iowrite32 (dsr, scr->gpo_dsr);
++ spin_unlock_irqrestore (&tc6393->lock, flags);
++
++ return dsr;
++}
++EXPORT_SYMBOL (set_tc6393_gpio);
++
++u32 reset_tc6393_gpio (struct device *dev, u32 bits)
++{
++ struct tc6393* tc6393 = dev_get_drvdata (dev);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ unsigned long flags;
++ u32 dsr;
++
++ spin_lock_irqsave (&tc6393->lock, flags);
++ dsr = tc6393_ioread32 (scr->gpo_dsr) & ~bits;
++ tc6393_iowrite32 (dsr, scr->gpo_dsr);
++ spin_unlock_irqrestore (&tc6393->lock, flags);
++
++ return dsr;
++}
++EXPORT_SYMBOL (reset_tc6393_gpio);
++
++/*--------------------------------------------------------------------------*/
++
++static void
++tc6393_irq (unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
++{
++ struct tc6393* tc6393 = get_irq_chipdata (irq);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ unsigned int isr;
++ unsigned int bit;
++ unsigned int i;
++
++ desc->chip->ack (irq);
++
++ while ((isr = ioread8(&scr->isr) & ~ioread8(&scr->imr)))
++ for (bit = 1, i = IRQ_TC6393_START; i <= IRQ_TC6393_LCD;
++ bit <<= 1, i++)
++ if (isr & bit)
++ desc_handle_irq (i, irq_desc + i, regs);
++}
++
++static void tc6393_irq_ack (unsigned int irq)
++{
++}
++
++static void tc6393_irq_mask (unsigned int irq)
++{
++ struct tc6393* tc6393 = get_irq_chipdata (irq);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ unsigned long flags;
++
++ spin_lock_irqsave (&tc6393->lock, flags);
++ iowrite8 (ioread8 (&scr->imr) | (1 << (irq - IRQ_TC6393_START)),
++ &scr->imr);
++ spin_unlock_irqrestore (&tc6393->lock, flags);
++}
++
++static void tc6393_irq_unmask (unsigned int irq)
++{
++ struct tc6393* tc6393 = get_irq_chipdata (irq);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ unsigned long flags;
++
++ spin_lock_irqsave (&tc6393->lock, flags);
++ iowrite8 (ioread8 (&scr->imr) & ~(1 << (irq - IRQ_TC6393_START)),
++ &scr->imr);
++ spin_unlock_irqrestore (&tc6393->lock, flags);
++}
++
++static struct irqchip tc6393_chip = {
++ .ack = tc6393_irq_ack,
++ .mask = tc6393_irq_mask,
++ .unmask = tc6393_irq_unmask,
++};
++
++static void tc6393_attach_irq (struct tc6393 *tc6393)
++{
++ unsigned int irq;
++
++ for (irq = IRQ_TC6393_START; irq <= IRQ_TC6393_LCD; irq++) {
++ set_irq_chip (irq, &tc6393_chip);
++ set_irq_chipdata(irq, tc6393);
++ set_irq_handler (irq, do_edge_IRQ);
++ set_irq_flags (irq, IRQF_VALID | IRQF_PROBE);
++ }
++
++ set_irq_type (tc6393->irq, IRQT_FALLING);
++ set_irq_chipdata (tc6393->irq, tc6393);
++ set_irq_chained_handler (tc6393->irq, tc6393_irq);
++}
++
++static void tc6393_detach_irq (struct tc6393 *tc6393)
++{
++ unsigned int irq;
++
++ set_irq_chained_handler (tc6393->irq, NULL);
++ set_irq_chipdata (tc6393->irq, NULL);
++
++ for (irq = IRQ_TC6393_START; irq <= IRQ_TC6393_LCD; irq++) {
++ set_irq_flags (irq, 0);
++ set_irq_chip (irq, NULL);
++ set_irq_chipdata(irq, NULL);
++ }
++}
++
++/*--------------------------------------------------------------------------*/
++
++static int tc6393_bus_match (struct device *dev, struct device_driver *drv)
++{
++ struct tmio_device* tdev = dev_to_tdev (dev);
++ const struct tc6393_cell* cell = tdev->soc_data;
++
++ return !strcmp (cell->name, drv->name);
++}
++
++static int tc6393_bus_suspend (struct device *dev, pm_message_t state)
++{
++ struct device_driver* drv = dev->driver;
++ return drv && drv->suspend ? drv->suspend (dev, state) : 0;
++}
++
++static int tc6393_bus_resume (struct device *dev)
++{
++ struct device_driver* drv = dev->driver;
++ return drv && drv->resume ? drv->resume (dev) : 0;
++}
++
++struct bus_type tc6393_bus_type = {
++ .name = TMIO_NAME_BUS,
++ .match = tc6393_bus_match,
++ .suspend = tc6393_bus_suspend,
++ .resume = tc6393_bus_resume,
++};
++EXPORT_SYMBOL (tc6393_bus_type);
++
++/*--------------------------------------------------------------------------*/
++
++static void tc6393_cell_clock (struct device *dev, int enable)
++{
++ struct tmio_device* tdev = dev_to_tdev (dev);
++ const struct tc6393_cell* cell = tdev->soc_data;
++ struct tc6393* tc6393 = dev_get_drvdata (dev->parent);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ union tc6393_scr_ccr ccr;
++ unsigned long flags;
++
++ spin_lock_irqsave (&tc6393->lock, flags);
++ ccr.raw = ioread16 (&scr->ccr);
++
++ switch (cell->id) {
++ case TC6393_CELL_SD: ccr.ck32ken = enable; break;
++ case TC6393_CELL_OHCI: ccr.usbcken = enable; break;
++ case TC6393_CELL_LCD:
++ ccr.mclksel = enable ? m48MHz : disable;
++ break;
++ }
++
++ printk (KERN_DEBUG TMIO_NAME_CORE ": scr->ccr = %04x\n", ccr.raw);
++
++ iowrite16(ccr.raw, &scr->ccr);
++ spin_unlock_irqrestore (&tc6393->lock, flags);
++}
++
++static void tc6393_cell_function (struct device *dev, int enable)
++{
++ struct tmio_device* tdev = dev_to_tdev (dev);
++ const struct tc6393_cell* cell = tdev->soc_data;
++ struct tc6393* tc6393 = dev_get_drvdata (dev->parent);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ union tc6393_scr_fer fer;
++ unsigned long flags;
++
++ if (cell->id == TC6393_CELL_NAND) {
++ if (enable) {
++ /* SMD buffer on */
++ printk (KERN_DEBUG TMIO_NAME_CORE ": SMD buffer on\n");
++ iowrite8 (0xff, scr->gpi_bcr + 1);
++ }
++ return;
++ }
++
++ spin_lock_irqsave (&tc6393->lock, flags);
++ fer.raw = ioread16 (&scr->fer);
++
++ switch (cell->id) {
++ case TC6393_CELL_OHCI: fer.usben = enable; break;
++ case TC6393_CELL_LCD: fer.slcden = enable; break;
++ }
++
++ printk (KERN_DEBUG TMIO_NAME_CORE ": scr->fer = %02x\n", fer.raw);
++
++ iowrite8 (fer.raw, &scr->fer);
++ spin_unlock_irqrestore (&tc6393->lock, flags);
++}
++
++static void
++tc6393_lcd_mode (struct device *dev, const struct fb_videomode *mode)
++{
++ struct tc6393* tc6393 = dev_get_drvdata (dev->parent);
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++
++ iowrite16 (mode->pixclock, scr->pll1cr + 0);
++ iowrite16 (mode->pixclock >> 16, scr->pll1cr + 1);
++}
++
++static struct tmio_cell_ops tc6393_cell_ops = {
++ .clock = tc6393_cell_clock,
++ .function = tc6393_cell_function,
++ .lcd_mode = tc6393_lcd_mode,
++};
++
++static void tc6393_device_release (struct device *dev)
++{
++}
++
++static int
++tc6393_device_register (struct tc6393 *tc6393, struct tmio_cell *tcell)
++{
++ const struct tc6393_cell* cell;
++ struct tmio_device* tdev;
++ struct device* dev;
++ int i;
++
++ for (i = 0; strcmp (tcell->name, tc6393_cell [i].name); )
++ if (++i >= ARRAY_SIZE(tc6393_cell))
++ return -EINVAL;
++
++ cell = tc6393_cell + i;
++ tdev = tc6393->tdev + i;
++ dev = &tdev->dev;
++
++ tdev->ops = &tc6393_cell_ops;
++ tdev->iomem = tc6393->iomem;
++ tdev->soc_data = (void*) cell;
++
++ dev->parent = tc6393->dev;
++ strncpy (dev->bus_id, cell->name, sizeof dev->bus_id);
++ dev->bus = &tc6393_bus_type;
++ dev->dma_mask = tc6393->dev->dma_mask;
++ dev->coherent_dma_mask = tc6393->dev->coherent_dma_mask;
++ dev->release = tc6393_device_release;
++ dev->platform_data = tcell->platform_data;
++
++ for (i=0; i < cell->num_resources; i++) {
++ const struct resource* cr = cell->resource + i;
++ struct resource* dr = tdev->resource + i;
++
++ dr->name = cr->name;
++ dr->start = cr->start;
++ dr->end = cr->end;
++ dr->flags = cr->flags;
++
++ /* convert memory offsets to absolutes */
++ if (cr->flags & IORESOURCE_MEM) {
++ dr->start += tc6393->iomem->start;
++ dr->end += tc6393->iomem->start;
++ }
++ }
++
++ return device_register (dev);
++}
++
++/*--------------------------------------------------------------------------*/
++
++static void tc6393_hw_init (struct tc6393 *tc6393)
++{
++ struct tc6393_scr __iomem * scr = tc6393->scr;
++ struct tc6393_platform_data* tcpd = tc6393->dev->platform_data;
++
++ tcpd->enable (tc6393->dev);
++
++ iowrite8 (0, &scr->fer);
++ iowrite16(tcpd->scr_pll2cr, &scr->pll2cr);
++ iowrite16(tcpd->scr_ccr, &scr->ccr);
++ iowrite16(tcpd->scr_mcr, &scr->mcr);
++ iowrite16(tcpd->scr_gper, &scr->gper);
++ iowrite8 (0, &scr->irr);
++ iowrite8 (0xbf, &scr->imr);
++ iowrite16(tcpd->scr_gpo_dsr, scr->gpo_dsr + 0);
++ iowrite16(tcpd->scr_gpo_dsr >> 16, scr->gpo_dsr + 1);
++ iowrite16(tcpd->scr_gpo_doecr, scr->gpo_doecr + 0);
++ iowrite16(tcpd->scr_gpo_doecr >> 16, scr->gpo_doecr + 1);
++}
++
++static int tc6393_probe (struct device *dev)
++{
++ struct platform_device* pdev = to_platform_device (dev);
++ struct tc6393_platform_data* tcpd = dev->platform_data;
++ struct tc6393* tc6393;
++ struct resource* iomem;
++ struct resource* rscr;
++ int retval;
++ int i;
++
++ iomem = platform_get_resource (pdev, IORESOURCE_MEM, 0);
++ if (!iomem)
++ return -EINVAL;
++
++ tc6393 = kzalloc (sizeof *tc6393, GFP_KERNEL);
++ if (!tc6393) {
++ retval = -ENOMEM;
++ goto err_kzalloc;
++ }
++
++ dev_set_drvdata (dev, tc6393);
++ spin_lock_init (&tc6393->lock);
++ tc6393->dev = dev;
++ tc6393->iomem = iomem;
++ tc6393->irq = platform_get_irq (pdev, 0);
++
++ rscr = &tc6393->rscr;
++ rscr->name = TMIO_NAME_CORE;
++ rscr->start = iomem->start;
++ rscr->end = iomem->start + 0xff;
++ rscr->flags = IORESOURCE_MEM;
++
++ retval = request_resource (iomem, rscr);
++ if (retval)
++ goto err_request_scr;
++
++ tc6393->scr = ioremap (rscr->start, rscr->end - rscr->start + 1);
++ if (!tc6393->scr) {
++ retval = -ENOMEM;
++ goto err_ioremap;
++ }
++
++ tc6393_hw_init (tc6393);
++
++ printk (KERN_INFO "Toshiba %s revision %d at 0x%08lx, irq %d\n",
++ TMIO_SOC_NAME, ioread8 (&tc6393->scr->revid),
++ iomem->start, tc6393->irq);
++
++ if (tc6393->irq)
++ tc6393_attach_irq (tc6393);
++
++ for (i = 0; i < tcpd->num_cells; i++)
++ tc6393_device_register (tc6393, tcpd->cell + i);
++
++ return 0;
++
++err_ioremap:
++ release_resource (rscr);
++err_request_scr:
++ kfree(tc6393);
++err_kzalloc:
++ release_resource (iomem);
++ return retval;
++}
++
++static int tc6393_dev_remove (struct device *dev, void *data)
++{
++ device_unregister (dev);
++ return 0;
++}
++
++static int tc6393_remove (struct device *dev)
++{
++ struct tc6393* tc6393 = dev_get_drvdata (dev);
++
++ device_for_each_child (dev, tc6393, tc6393_dev_remove);
++
++ if (tc6393->irq)
++ tc6393_detach_irq (tc6393);
++
++ iounmap (tc6393->scr);
++ release_resource (&tc6393->rscr);
++ release_resource (tc6393->iomem);
++ kfree (tc6393);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int tc6393_suspend (struct device *dev, pm_message_t state)
++{
++ struct tc6393_platform_data* tcpd = dev->platform_data;
++ tcpd->disable (dev);
++ return 0;
++}
++
++static int tc6393_resume (struct device *dev)
++{
++ struct tc6393* tc6393 = dev_get_drvdata (dev);
++ tc6393_hw_init (tc6393);
++ return 0;
++}
++#endif
++
++static struct device_driver tc6393_device_driver = {
++ .name = TMIO_SOC_NAME,
++ .bus = &platform_bus_type,
++ .probe = tc6393_probe,
++ .remove = tc6393_remove,
++#ifdef CONFIG_PM
++ .suspend = tc6393_suspend,
++ .resume = tc6393_resume,
++#endif
++};
++
++/*--------------------------------------------------------------------------*/
++
++static int __init tc6393_init (void)
++{
++ int retval = bus_register (&tc6393_bus_type);
++ if (retval)
++ return retval;
++
++ return driver_register (&tc6393_device_driver);
++}
++
++static void __exit tc6393_exit (void)
++{
++ driver_unregister (&tc6393_device_driver);
++ bus_unregister (&tc6393_bus_type);
++}
++
++module_init (tc6393_init);
++module_exit (tc6393_exit);
++
++MODULE_DESCRIPTION ("TC6393 SoC bus driver");
++MODULE_AUTHOR ("Chris Humbert, Dirk Opfer");
++MODULE_LICENSE ("GPL");
+Index: linux-2.6.18/arch/arm/common/Kconfig
+===================================================================
+--- linux-2.6.18.orig/arch/arm/common/Kconfig 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18/arch/arm/common/Kconfig 2006-09-20 16:17:02.000000000 +0200
+@@ -31,3 +31,6 @@
+
+ config SHARP_SCOOP
+ bool
++
++config TOSHIBA_TC6393XB
++ bool
+Index: linux-2.6.18/arch/arm/mach-pxa/Kconfig
+===================================================================
+--- linux-2.6.18.orig/arch/arm/mach-pxa/Kconfig 2006-09-20 16:16:58.000000000 +0200
++++ linux-2.6.18/arch/arm/mach-pxa/Kconfig 2006-09-20 16:17:02.000000000 +0200
+@@ -128,6 +128,7 @@
+ config MACH_TOSA
+ bool "Enable Sharp SL-6000x (Tosa) Support"
+ depends PXA_SHARPSL_25x
++ select TOSHIBA_TC6393XB
+
+ config PXA25x
+ bool
+Index: linux-2.6.18/arch/arm/common/Makefile
+===================================================================
+--- linux-2.6.18.orig/arch/arm/common/Makefile 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18/arch/arm/common/Makefile 2006-09-20 16:17:35.000000000 +0200
+@@ -17,3 +17,4 @@
+ obj-$(CONFIG_SHARP_SCOOP) += scoop.o
+ obj-$(CONFIG_ARCH_IXP2000) += uengine.o
+ obj-$(CONFIG_ARCH_IXP23XX) += uengine.o
++obj-$(CONFIG_TOSHIBA_TC6393XB) += tc6393xb.o
+Index: linux-2.6.18/include/asm-arm/hardware/tmio.h
+===================================================================
+--- linux-2.6.18.orig/include/asm-arm/hardware/tmio.h 2006-09-20 16:17:02.000000000 +0200
++++ linux-2.6.18/include/asm-arm/hardware/tmio.h 2006-09-20 16:17:02.000000000 +0200
+@@ -91,6 +91,50 @@
+
+ /*--------------------------------------------------------------------------*/
+
++/*
++ * TC6393XB SoC
++ */
++#ifdef CONFIG_TOSHIBA_TC6393XB
++#define TMIO_SOC_TC6393XB
++#define TMIO_SOC_NAME "TC6393XB"
++#define TMIO_NAME_BUS "tc6393-bus"
++#define TMIO_NAME_CORE "tc6393-core"
++#define TMIO_NAME_NAND "tc6393-nand"
++#define TMIO_NAME_SD "tc6393-sd"
++#define TMIO_NAME_OHCI "tc6393-ohci"
++#define TMIO_NAME_SERIAL "tc6393-serial"
++#define TMIO_NAME_LCD "tc6393-lcd"
++#define tmio_bus_type tc6393_bus_type
++
++#define TC6393_GPIO(x) (1 << (x))
++
++extern struct bus_type tc6393_bus_type;
++
++struct tc6393_platform_data {
++ u16 scr_pll2cr; /* PLL2 Control */
++ u16 scr_ccr; /* Clock Control */
++ u16 scr_mcr; /* Mode Control */
++ u16 scr_gper; /* GP Enable */
++ u32 scr_gpo_doecr; /* GPO Data OE Control */
++ u32 scr_gpo_dsr; /* GPO Data Set */
++
++ /* cells to register as devices */
++ struct tmio_cell* cell;
++ unsigned int num_cells;
++
++ /* callbacks to enable and disable the TC6393XB's power and clock */
++ void (*enable) (struct device *dev);
++ void (*disable) (struct device *dev);
++};
++
++u32 get_tc6393_gpio (struct device *dev);
++u32 set_tc6393_gpio (struct device *dev, u32 bits);
++u32 reset_tc6393_gpio (struct device *dev, u32 bits);
++
++/*--------------------------------------------------------------------------*/
++
++#else
+ #error "no TMIO SoC configured"
++#endif
+
+ #endif
+Index: linux-2.6.18/include/asm-arm/arch-pxa/irqs.h
+===================================================================
+--- linux-2.6.18.orig/include/asm-arm/arch-pxa/irqs.h 2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18/include/asm-arm/arch-pxa/irqs.h 2006-09-20 16:17:02.000000000 +0200
+@@ -163,17 +163,27 @@
+ #define IRQ_LOCOMO_SPI_OVRN (IRQ_BOARD_END + 20)
+ #define IRQ_LOCOMO_SPI_TEND (IRQ_BOARD_END + 21)
+
++#define IRQ_TC6393_START (IRQ_BOARD_END)
++#define IRQ_TC6393_NAND (IRQ_BOARD_END + 0)
++#define IRQ_TC6393_SD (IRQ_BOARD_END + 1)
++#define IRQ_TC6393_OHCI (IRQ_BOARD_END + 2)
++#define IRQ_TC6393_SERIAL (IRQ_BOARD_END + 3)
++#define IRQ_TC6393_LCD (IRQ_BOARD_END + 4)
++
+ /*
+ * Figure out the MAX IRQ number.
+ *
+ * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
+ * If we have an LoCoMo, the max IRQ is IRQ_LOCOMO_SPI_TEND+1
++ * If we have an TC6393XB, the max IRQ is IRQ_TC6393_LCD+1
+ * Otherwise, we have the standard IRQs only.
+ */
+ #ifdef CONFIG_SA1111
+ #define NR_IRQS (IRQ_S1_BVD1_STSCHG + 1)
+ #elif defined(CONFIG_SHARP_LOCOMO)
+ #define NR_IRQS (IRQ_LOCOMO_SPI_TEND + 1)
++#elif defined(CONFIG_TOSHIBA_TC6393XB)
++#define NR_IRQS (IRQ_TC6393_LCD + 1)
+ #elif defined(CONFIG_ARCH_LUBBOCK) || \
+ defined(CONFIG_MACH_LOGICPD_PXA270) || \
+ defined(CONFIG_MACH_MAINSTONE)