diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-11 10:44:43 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-11 10:44:43 -0700 |
commit | 10fec20ef5eec1c91913baec1225400f0d02df40 (patch) | |
tree | 2e226afc846616f901998c956290813b814b6714 /drivers/mfd | |
parent | 29bb1bdb260cd504c6ec0f567cc0cba6a4cf40e7 (diff) | |
parent | 25d6cbd840d958aada29a342c9ee370590ff7b21 (diff) |
Merge branch 'for-linus' of git://git.o-hand.com/linux-mfd
* 'for-linus' of git://git.o-hand.com/linux-mfd:
mfd: tc6393 cleanup and update
mfd: have TMIO drivers and subdevices depend on ARM
mfd: TMIO MMC driver
mfd: driver for the TMIO NAND controller
mfd: t7l66 MMC platform data
mfd: tc6387 MMC platform data
mfd: Fix 7l66 and 6387 according to the new mfd-core API
mfd: Fix tc6393 according to the new tmio.h
mfd: driver for the TC6387XB TMIO controller.
mfd: driver for the T7L66XB TMIO SoC
mfd: TMIO MMC structures and accessors.
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 21 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 2 | ||||
-rw-r--r-- | drivers/mfd/t7l66xb.c | 419 | ||||
-rw-r--r-- | drivers/mfd/tc6387xb.c | 181 | ||||
-rw-r--r-- | drivers/mfd/tc6393xb.c | 159 |
5 files changed, 716 insertions, 66 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 883e7ea31de..10c44d3fe01 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -50,10 +50,31 @@ config HTC_PASIC3 HTC Magician devices, respectively. Actual functionality is handled by the leds-pasic3 and ds1wm drivers. +config MFD_TMIO + bool + default n + +config MFD_T7L66XB + bool "Support Toshiba T7L66XB" + depends on ARM + select MFD_CORE + select MFD_TMIO + help + Support for Toshiba Mobile IO Controller T7L66XB + +config MFD_TC6387XB + bool "Support Toshiba TC6387XB" + depends on ARM + select MFD_CORE + select MFD_TMIO + help + Support for Toshiba Mobile IO Controller TC6387XB + config MFD_TC6393XB bool "Support Toshiba TC6393XB" depends on GPIOLIB && ARM select MFD_CORE + select MFD_TMIO help Support for Toshiba Mobile IO Controller TC6393XB diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 33daa2f45dd..03ad239ecef 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -8,6 +8,8 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o +obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o +obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o obj-$(CONFIG_MFD_CORE) += mfd-core.o diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c new file mode 100644 index 00000000000..49a0fffc02a --- /dev/null +++ b/drivers/mfd/t7l66xb.c @@ -0,0 +1,419 @@ +/* + * + * Toshiba T7L66XB core mfd support + * + * Copyright (c) 2005, 2007, 2008 Ian Molton + * Copyright (c) 2008 Dmitry Baryshkov + * + * 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. + * + * T7L66 features: + * + * Supported in this driver: + * SD/MMC + * SM/NAND flash controller + * + * As yet not supported + * GPIO interface (on NAND pins) + * Serial interface + * TFT 'interface converter' + * PCMCIA interface logic + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> +#include <linux/mfd/t7l66xb.h> + +enum { + T7L66XB_CELL_NAND, + T7L66XB_CELL_MMC, +}; + +#define SCR_REVID 0x08 /* b Revision ID */ +#define SCR_IMR 0x42 /* b Interrupt Mask */ +#define SCR_DEV_CTL 0xe0 /* b Device control */ +#define SCR_ISR 0xe1 /* b Interrupt Status */ +#define SCR_GPO_OC 0xf0 /* b GPO output control */ +#define SCR_GPO_OS 0xf1 /* b GPO output enable */ +#define SCR_GPI_S 0xf2 /* w GPI status */ +#define SCR_APDC 0xf8 /* b Active pullup down ctrl */ + +#define SCR_DEV_CTL_USB BIT(0) /* USB enable */ +#define SCR_DEV_CTL_MMC BIT(1) /* MMC enable */ + +/*--------------------------------------------------------------------------*/ + +struct t7l66xb { + void __iomem *scr; + /* Lock to protect registers requiring read/modify/write ops. */ + spinlock_t lock; + + struct resource rscr; + int irq; + int irq_base; +}; + +/*--------------------------------------------------------------------------*/ + +static int t7l66xb_mmc_enable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned long flags; + u8 dev_ctl; + + if (pdata->enable_clk32k) + pdata->enable_clk32k(dev); + + spin_lock_irqsave(&t7l66xb->lock, flags); + + dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); + dev_ctl |= SCR_DEV_CTL_MMC; + tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); + + spin_unlock_irqrestore(&t7l66xb->lock, flags); + + return 0; +} + +static int t7l66xb_mmc_disable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned long flags; + u8 dev_ctl; + + spin_lock_irqsave(&t7l66xb->lock, flags); + + dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); + dev_ctl &= ~SCR_DEV_CTL_MMC; + tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); + + spin_unlock_irqrestore(&t7l66xb->lock, flags); + + if (pdata->disable_clk32k) + pdata->disable_clk32k(dev); + + return 0; +} + +/*--------------------------------------------------------------------------*/ + +const static struct resource t7l66xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x200, + .end = 0x2ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_T7L66XB_MMC, + .end = IRQ_T7L66XB_MMC, + .flags = IORESOURCE_IRQ, + }, +}; + +const static struct resource t7l66xb_nand_resources[] = { + { + .start = 0xc00, + .end = 0xc07, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x0100, + .end = 0x01ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_T7L66XB_NAND, + .end = IRQ_T7L66XB_NAND, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell t7l66xb_cells[] = { + [T7L66XB_CELL_MMC] = { + .name = "tmio-mmc", + .enable = t7l66xb_mmc_enable, + .disable = t7l66xb_mmc_disable, + .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), + .resources = t7l66xb_mmc_resources, + }, + [T7L66XB_CELL_NAND] = { + .name = "tmio-nand", + .num_resources = ARRAY_SIZE(t7l66xb_nand_resources), + .resources = t7l66xb_nand_resources, + }, +}; + +/*--------------------------------------------------------------------------*/ + +/* Handle the T7L66XB interrupt mux */ +static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) +{ + struct t7l66xb *t7l66xb = get_irq_data(irq); + unsigned int isr; + unsigned int i, irq_base; + + irq_base = t7l66xb->irq_base; + + while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) & + ~tmio_ioread8(t7l66xb->scr + SCR_IMR))) + for (i = 0; i < T7L66XB_NR_IRQS; i++) + if (isr & (1 << i)) + generic_handle_irq(irq_base + i); +} + +static void t7l66xb_irq_mask(unsigned int irq) +{ + struct t7l66xb *t7l66xb = get_irq_chip_data(irq); + unsigned long flags; + u8 imr; + + spin_lock_irqsave(&t7l66xb->lock, flags); + imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); + imr |= 1 << (irq - t7l66xb->irq_base); + tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); + spin_unlock_irqrestore(&t7l66xb->lock, flags); +} + +static void t7l66xb_irq_unmask(unsigned int irq) +{ + struct t7l66xb *t7l66xb = get_irq_chip_data(irq); + unsigned long flags; + u8 imr; + + spin_lock_irqsave(&t7l66xb->lock, flags); + imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); + imr &= ~(1 << (irq - t7l66xb->irq_base)); + tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); + spin_unlock_irqrestore(&t7l66xb->lock, flags); +} + +static struct irq_chip t7l66xb_chip = { + .name = "t7l66xb", + .ack = t7l66xb_irq_mask, + .mask = t7l66xb_irq_mask, + .unmask = t7l66xb_irq_unmask, +}; + +/*--------------------------------------------------------------------------*/ + +/* Install the IRQ handler */ +static void t7l66xb_attach_irq(struct platform_device *dev) +{ + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned int irq, irq_base; + + irq_base = t7l66xb->irq_base; + + for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { + set_irq_chip(irq, &t7l66xb_chip); + set_irq_chip_data(irq, t7l66xb); + set_irq_handler(irq, handle_level_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); +#endif + } + + set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); + set_irq_data(t7l66xb->irq, t7l66xb); + set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); +} + +static void t7l66xb_detach_irq(struct platform_device *dev) +{ + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + unsigned int irq, irq_base; + + irq_base = t7l66xb->irq_base; + + set_irq_chained_handler(t7l66xb->irq, NULL); + set_irq_data(t7l66xb->irq, NULL); + + for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { +#ifdef CONFIG_ARM + set_irq_flags(irq, 0); +#endif + set_irq_chip(irq, NULL); + set_irq_chip_data(irq, NULL); + } +} + +/*--------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM +static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + + if (pdata && pdata->suspend) + pdata->suspend(dev); + + return 0; +} + +static int t7l66xb_resume(struct platform_device *dev) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + + if (pdata && pdata->resume) + pdata->resume(dev); + + return 0; +} +#else +#define t7l66xb_suspend NULL +#define t7l66xb_resume NULL +#endif + +/*--------------------------------------------------------------------------*/ + +static int t7l66xb_probe(struct platform_device *dev) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb; + struct resource *iomem, *rscr; + int ret; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!iomem) + return -EINVAL; + + t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL); + if (!t7l66xb) + return -ENOMEM; + + spin_lock_init(&t7l66xb->lock); + + platform_set_drvdata(dev, t7l66xb); + + ret = platform_get_irq(dev, 0); + if (ret >= 0) + t7l66xb->irq = ret; + else + goto err_noirq; + + t7l66xb->irq_base = pdata->irq_base; + + rscr = &t7l66xb->rscr; + rscr->name = "t7l66xb-core"; + rscr->start = iomem->start; + rscr->end = iomem->start + 0xff; + rscr->flags = IORESOURCE_MEM; + + ret = request_resource(iomem, rscr); + if (ret) + goto err_request_scr; + + t7l66xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); + if (!t7l66xb->scr) { + ret = -ENOMEM; + goto err_ioremap; + } + + if (pdata && pdata->enable) + pdata->enable(dev); + + /* Mask all interrupts */ + tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR); + + printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n", + dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID), + (unsigned long)iomem->start, t7l66xb->irq); + + t7l66xb_attach_irq(dev); + + t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; + t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = + &t7l66xb_cells[T7L66XB_CELL_NAND]; + t7l66xb_cells[T7L66XB_CELL_NAND].data_size = + sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); + + t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = + &t7l66xb_cells[T7L66XB_CELL_MMC]; + t7l66xb_cells[T7L66XB_CELL_MMC].data_size = + sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); + + ret = mfd_add_devices(&dev->dev, dev->id, + t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), + iomem, t7l66xb->irq_base); + + if (!ret) + return 0; + + t7l66xb_detach_irq(dev); + iounmap(t7l66xb->scr); +err_ioremap: + release_resource(&t7l66xb->rscr); +err_noirq: +err_request_scr: + kfree(t7l66xb); + return ret; +} + +static int t7l66xb_remove(struct platform_device *dev) +{ + struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + int ret; + + ret = pdata->disable(dev); + + t7l66xb_detach_irq(dev); + iounmap(t7l66xb->scr); + release_resource(&t7l66xb->rscr); + mfd_remove_devices(&dev->dev); + platform_set_drvdata(dev, NULL); + kfree(t7l66xb); + + return ret; + +} + +static struct platform_driver t7l66xb_platform_driver = { + .driver = { + .name = "t7l66xb", + .owner = THIS_MODULE, + }, + .suspend = t7l66xb_suspend, + .resume = t7l66xb_resume, + .probe = t7l66xb_probe, + .remove = t7l66xb_remove, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init t7l66xb_init(void) +{ + int retval = 0; + + retval = platform_driver_register(&t7l66xb_platform_driver); + return retval; +} + +static void __exit t7l66xb_exit(void) +{ + platform_driver_unregister(&t7l66xb_platform_driver); +} + +module_init(t7l66xb_init); +module_exit(t7l66xb_exit); + +MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton"); +MODULE_ALIAS("platform:t7l66xb"); diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c new file mode 100644 index 00000000000..a22b21ac6cf --- /dev/null +++ b/drivers/mfd/tc6387xb.c @@ -0,0 +1,181 @@ +/* + * Toshiba TC6387XB support + * Copyright (c) 2005 Ian Molton + * + * 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. + * + * This file contains TC6387XB base support. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> +#include <linux/mfd/tc6387xb.h> + +enum { + TC6387XB_CELL_MMC, +}; + +#ifdef CONFIG_PM +static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) +{ + struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); + + if (pdata && pdata->suspend) + pdata->suspend(dev); + + return 0; +} + +static int tc6387xb_resume(struct platform_device *dev) +{ + struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); + + if (pdata && pdata->resume) + pdata->resume(dev); + + return 0; +} +#else +#define tc6387xb_suspend NULL +#define tc6387xb_resume NULL +#endif + +/*--------------------------------------------------------------------------*/ + +static int tc6387xb_mmc_enable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; + + if (tc6387xb->enable_clk32k) + tc6387xb->enable_clk32k(dev); + + return 0; +} + +static int tc6387xb_mmc_disable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; + + if (tc6387xb->disable_clk32k) + tc6387xb->disable_clk32k(dev); + + return 0; +} + +/*--------------------------------------------------------------------------*/ + +static struct resource tc6387xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x200, + .end = 0x2ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell tc6387xb_cells[] = { + [TC6387XB_CELL_MMC] = { + .name = "tmio-mmc", + .enable = tc6387xb_mmc_enable, + .disable = tc6387xb_mmc_disable, + .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), + .resources = tc6387xb_mmc_resources, + }, +}; + +static int tc6387xb_probe(struct platform_device *dev) +{ + struct tc6387xb_platform_data *data = platform_get_drvdata(dev); + struct resource *iomem; + int irq, ret; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!iomem) { + ret = -EINVAL; + goto err_resource; + } + + ret = platform_get_irq(dev, 0); + if (ret >= 0) + irq = ret; + else + goto err_resource; + + if (data && data->enable) + data->enable(dev); + + printk(KERN_INFO "Toshiba tc6387xb initialised\n"); + + tc6387xb_cells[TC6387XB_CELL_MMC].platform_data = + &tc6387xb_cells[TC6387XB_CELL_MMC]; + tc6387xb_cells[TC6387XB_CELL_MMC].data_size = + sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]); + + ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, + ARRAY_SIZE(tc6387xb_cells), iomem, irq); + + if (!ret) + return 0; + +err_resource: + return ret; +} + +static int tc6387xb_remove(struct platform_device *dev) +{ + struct tc6387xb_platform_data *data = platform_get_drvdata(dev); + + if (data && data->disable) + data->disable(dev); + + /* FIXME - free the resources! */ + + return 0; +} + + +static struct platform_driver tc6387xb_platform_driver = { + .driver = { + .name = "tc6387xb", + }, + .probe = tc6387xb_probe, + .remove = tc6387xb_remove, + .suspend = tc6387xb_suspend, + .resume = tc6387xb_resume, +}; + + +static int __init tc6387xb_init(void) +{ + return platform_driver_register(&tc6387xb_platform_driver); +} + +static void __exit tc6387xb_exit(void) +{ + platform_driver_unregister(&tc6387xb_platform_driver); +} + +module_init(tc6387xb_init); +module_exit(tc6387xb_exit); + +MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton"); +MODULE_ALIAS("platform:tc6387xb"); diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index f4fd797c159..e4c1c788b5f 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -19,8 +19,8 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/platform_device.h> -#include <linux/fb.h> #include <linux/clk.h> +#include <linux/err.h> #include <linux/mfd/core.h> #include <linux/mfd/tmio.h> #include <linux/mfd/tc6393xb.h> @@ -112,6 +112,7 @@ struct tc6393xb { enum { TC6393XB_CELL_NAND, + TC6393XB_CELL_MMC, }; /*--------------------------------------------------------------------------*/ @@ -126,7 +127,7 @@ static int tc6393xb_nand_enable(struct platform_device *nand) /* SMD buffer on */ dev_dbg(&dev->dev, "SMD buffer on\n"); - iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); + tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); spin_unlock_irqrestore(&tc6393xb->lock, flags); @@ -135,25 +136,40 @@ static int tc6393xb_nand_enable(struct platform_device *nand) static struct resource __devinitdata tc6393xb_nand_resources[] = { { - .name = TMIO_NAND_CONFIG, - .start = 0x0100, - .end = 0x01ff, + .start = 0x1000, + .end = 0x1007, .flags = IORESOURCE_MEM, }, { - .name = TMIO_NAND_CONTROL, - .start = 0x1000, - .end = 0x1007, + .start = 0x0100, + .end = 0x01ff, .flags = IORESOURCE_MEM, }, { - .name = TMIO_NAND_IRQ, .start = IRQ_TC6393_NAND, .end = IRQ_TC6393_NAND, .flags = IORESOURCE_IRQ, }, }; +static struct resource __devinitdata tc6393xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x200, + .end = 0x2ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_TC6393_MMC, + .end = IRQ_TC6393_MMC, + .flags = IORESOURCE_IRQ, + }, +}; + static struct mfd_cell __devinitdata tc6393xb_cells[] = { [TC6393XB_CELL_NAND] = { .name = "tmio-nand", @@ -161,6 +177,11 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), .resources = tc6393xb_nand_resources, }, + [TC6393XB_CELL_MMC] = { + .name = "tmio-mmc", + .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), + .resources = tc6393xb_mmc_resources, + }, }; /*--------------------------------------------------------------------------*/ @@ -171,7 +192,7 @@ static int tc6393xb_gpio_get(struct gpio_chip *chip, struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); /* XXX: does dsr also represent inputs? */ - return ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) + return tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) & TC_GPIO_BIT(offset); } @@ -181,13 +202,13 @@ static void __tc6393xb_gpio_set(struct gpio_chip *chip, struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio); u8 dsr; - dsr = ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); + dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); if (value) dsr |= TC_GPIO_BIT(offset); else dsr &= ~TC_GPIO_BIT(offset); - iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); + tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); } static void tc6393xb_gpio_set(struct gpio_chip *chip, @@ -212,9 +233,9 @@ static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, spin_lock_irqsave(&tc6393xb->lock, flags); - doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); doecr &= ~TC_GPIO_BIT(offset); - iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); spin_unlock_irqrestore(&tc6393xb->lock, flags); @@ -232,9 +253,9 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, __tc6393xb_gpio_set(chip, offset, value); - doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); doecr |= TC_GPIO_BIT(offset); - iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); + tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); spin_unlock_irqrestore(&tc6393xb->lock, flags); @@ -265,8 +286,8 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc) irq_base = tc6393xb->irq_base; - while ((isr = ioread8(tc6393xb->scr + SCR_ISR) & - ~ioread8(tc6393xb->scr + SCR_IMR))) + while ((isr = tmio_ioread8(tc6393xb->scr + SCR_ISR) & + ~tmio_ioread8(tc6393xb->scr + SCR_IMR))) for (i = 0; i < TC6393XB_NR_IRQS; i++) { if (isr & (1 << i)) generic_handle_irq(irq_base + i); @@ -284,9 +305,9 @@ static void tc6393xb_irq_mask(unsigned int irq) u8 imr; spin_lock_irqsave(&tc6393xb->lock, flags); - imr = ioread8(tc6393xb->scr + SCR_IMR); + imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); imr |= 1 << (irq - tc6393xb->irq_base); - iowrite8(imr, tc6393xb->scr + SCR_IMR); + tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); spin_unlock_irqrestore(&tc6393xb->lock, flags); } @@ -297,9 +318,9 @@ static void tc6393xb_irq_unmask(unsigned int irq) u8 imr; spin_lock_irqsave(&tc6393xb->lock, flags); - imr = ioread8(tc6393xb->scr + SCR_IMR); + imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); imr &= ~(1 << (irq - tc6393xb->irq_base)); - iowrite8(imr, tc6393xb->scr + SCR_IMR); + tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); spin_unlock_irqrestore(&tc6393xb->lock, flags); } @@ -380,9 +401,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; struct tc6393xb *tc6393xb; - struct resource *iomem; - struct resource *rscr; - int retval, temp; + struct resource *iomem, *rscr; + int ret, temp; int i; iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -391,20 +411,26 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); if (!tc6393xb) { - retval = -ENOMEM; + ret = -ENOMEM; goto err_kzalloc; } spin_lock_init(&tc6393xb->lock); platform_set_drvdata(dev, tc6393xb); + + ret = platform_get_irq(dev, 0); + if (ret >= 0) + tc6393xb->irq = ret; + else + goto err_noirq; + tc6393xb->iomem = iomem; - tc6393xb->irq = platform_get_irq(dev, 0); tc6393xb->irq_base = tcpd->irq_base; - tc6393xb->clk = clk_get(&dev->dev, "GPIO27_CLK" /* "CK3P6MI" */); + tc6393xb->clk = clk_get(&dev->dev, "CLK_CK3P6MI"); if (IS_ERR(tc6393xb->clk)) { - retval = PTR_ERR(tc6393xb->clk); + ret = PTR_ERR(tc6393xb->clk); goto err_clk_get; } @@ -414,71 +440,73 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) rscr->end = iomem->start + 0xff; rscr->flags = IORESOURCE_MEM; - retval = request_resource(iomem, rscr); - if (retval) + ret = request_resource(iomem, rscr); + if (ret) goto err_request_scr; tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); if (!tc6393xb->scr) { - retval = -ENOMEM; + ret = -ENOMEM; goto err_ioremap; } - retval = clk_enable(tc6393xb->clk); - if (retval) + ret = clk_enable(tc6393xb->clk); + if (ret) goto err_clk_enable; - retval = tcpd->enable(dev); - if (retval) + ret = tcpd->enable(dev); + if (ret) goto err_enable; tc6393xb->suspend_state.fer = 0; + for (i = 0; i < 3; i++) { tc6393xb->suspend_state.gpo_dsr[i] = (tcpd->scr_gpo_dsr >> (8 * i)) & 0xff; tc6393xb->suspend_state.gpo_doecr[i] = (tcpd->scr_gpo_doecr >> (8 * i)) & 0xff; } - /* - * It may be necessary to change this back to - * platform-dependant code - */ + tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 | SCR_CCR_HCLK_48; - retval = tc6393xb_hw_init(dev); - if (retval) + ret = tc6393xb_hw_init(dev); + if (ret) goto err_hw_init; printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", - ioread8(tc6393xb->scr + SCR_REVID), + tmio_ioread8(tc6393xb->scr + SCR_REVID), (unsigned long) iomem->start, tc6393xb->irq); tc6393xb->gpio.base = -1; if (tcpd->gpio_base >= 0) { - retval = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); - if (retval) + ret = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); + if (ret) goto err_gpio_add; } - if (tc6393xb->irq) - tc6393xb_attach_irq(dev); + tc6393xb_attach_irq(dev); tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = &tc6393xb_cells[TC6393XB_CELL_NAND]; tc6393xb_cells[TC6393XB_CELL_NAND].data_size = sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); + tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = + &tc6393xb_cells[TC6393XB_CELL_MMC]; + tc6393xb_cells[TC6393XB_CELL_MMC].data_size = + sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); + - retval = mfd_add_devices(&dev->dev, dev->id, + ret = mfd_add_devices(&dev->dev, dev->id, tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), iomem, tcpd->irq_base); - return 0; + if (!ret) + return 0; - if (tc6393xb->irq) - tc6393xb_detach_irq(dev); + tc6393xb_detach_irq(dev); err_gpio_add: if (tc6393xb->gpio.base != -1) @@ -493,10 +521,11 @@ err_ioremap: release_resource(&tc6393xb->rscr); err_request_scr: clk_put(tc6393xb->clk); +err_noirq: err_clk_get: kfree(tc6393xb); err_kzalloc: - return retval; + return ret; } static int __devexit tc6393xb_remove(struct platform_device *dev) @@ -506,9 +535,7 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) int ret; mfd_remove_devices(&dev->dev); - - if (tc6393xb->irq) - tc6393xb_detach_irq(dev); + tc6393xb_detach_irq(dev); if (tc6393xb->gpio.base != -1) { ret = gpiochip_remove(&tc6393xb->gpio); @@ -519,17 +546,11 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) } ret = tcpd->disable(dev); - clk_disable(tc6393xb->clk); - iounmap(tc6393xb->scr); - release_resource(&tc6393xb->rscr); - platform_set_drvdata(dev, NULL); - clk_put(tc6393xb->clk); - kfree(tc6393xb); return ret; @@ -540,8 +561,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - int i; - + int i, ret; tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); @@ -554,14 +574,21 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) tc6393xb->suspend_state.gpi_bcr[i] = ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); } + ret = tcpd->suspend(dev); + clk_disable(tc6393xb->clk); - return tcpd->suspend(dev); + return ret; } static int tc6393xb_resume(struct platform_device *dev) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; - int ret = tcpd->resume(dev); + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); + int ret; + + clk_enable(tc6393xb->clk); + + ret = tcpd->resume(dev); if (ret) return ret; @@ -598,7 +625,7 @@ static void __exit tc6393xb_exit(void) subsys_initcall(tc6393xb_init); module_exit(tc6393xb_exit); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); MODULE_ALIAS("platform:tc6393xb"); |