From 64e8867ba8098b69889c1af94997a5ba2348fb26 Mon Sep 17 00:00:00 2001 From: Ian Molton Date: Wed, 6 Jan 2010 13:51:48 +0100 Subject: mfd: tmio_mmc hardware abstraction for CNF area This patch abstracts out the CNF area code from tmio_mmc which is not present in all hardware that can use this driver. This is required so that we can support non-toshiba based hardware. ASIC3 support by Philipp Zabel Signed-off-by: Ian Molton Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz --- drivers/mfd/Makefile | 6 +-- drivers/mfd/asic3.c | 40 ++++++++++++---- drivers/mfd/t7l66xb.c | 55 ++++++++++++++-------- drivers/mfd/tc6387xb.c | 119 +++++++++++++++++++++++++++++++++++------------- drivers/mfd/tc6393xb.c | 56 +++++++++++++++++++---- drivers/mfd/tmio_core.c | 52 +++++++++++++++++++++ 6 files changed, 259 insertions(+), 69 deletions(-) create mode 100644 drivers/mfd/tmio_core.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ca2f2c4ff05..8f0d18409ed 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -11,9 +11,9 @@ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o -obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o -obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o -obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o +obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o +obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o +obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o obj-$(CONFIG_MFD_WM8400) += wm8400-core.o wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index e22128c3e9a..95c1e6bd172 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -80,6 +80,7 @@ struct asic3 { u16 irq_bothedge[4]; struct gpio_chip gpio; struct device *dev; + void __iomem *tmio_cnf; struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)]; }; @@ -685,8 +686,24 @@ static struct mfd_cell asic3_cell_ds1wm = { .resources = ds1wm_resources, }; +static void asic3_mmc_pwr(struct platform_device *pdev, int state) +{ + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state); +} + +static void asic3_mmc_clk_div(struct platform_device *pdev, int state) +{ + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state); +} + static struct tmio_mmc_data asic3_mmc_data = { - .hclk = 24576000, + .hclk = 24576000, + .set_pwr = asic3_mmc_pwr, + .set_clk_div = asic3_mmc_clk_div, }; static struct resource asic3_mmc_resources[] = { @@ -695,11 +712,6 @@ static struct resource asic3_mmc_resources[] = { .end = ASIC3_SD_CTRL_BASE + 0x3ff, .flags = IORESOURCE_MEM, }, - { - .start = ASIC3_SD_CONFIG_BASE, - .end = ASIC3_SD_CONFIG_BASE + 0x1ff, - .flags = IORESOURCE_MEM, - }, { .start = 0, .end = 0, @@ -743,6 +755,10 @@ static int asic3_mmc_enable(struct platform_device *pdev) asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), ASIC3_SDHWCTRL_SDPWR, 1); + /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */ + tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift, + ASIC3_SD_CTRL_BASE >> 1); + return 0; } @@ -797,10 +813,15 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); /* MMC */ + asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + + mem_sdio->start, 0x400 >> asic->bus_shift); + if (!asic->tmio_cnf) { + ret = -ENOMEM; + dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n"); + goto out; + } asic3_mmc_resources[0].start >>= asic->bus_shift; asic3_mmc_resources[0].end >>= asic->bus_shift; - asic3_mmc_resources[1].start >>= asic->bus_shift; - asic3_mmc_resources[1].end >>= asic->bus_shift; asic3_cell_mmc.platform_data = &asic3_cell_mmc; asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); @@ -820,7 +841,10 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, static void asic3_mfd_remove(struct platform_device *pdev) { + struct asic3 *asic = platform_get_drvdata(pdev); + mfd_remove_devices(&pdev->dev); + iounmap(asic->tmio_cnf); } /* Core */ diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 0a255c1f1ce..bcf4687d4af 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -38,6 +38,19 @@ enum { T7L66XB_CELL_MMC, }; +static const struct resource t7l66xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_T7L66XB_MMC, + .end = IRQ_T7L66XB_MMC, + .flags = IORESOURCE_IRQ, + }, +}; + #define SCR_REVID 0x08 /* b Revision ID */ #define SCR_IMR 0x42 /* b Interrupt Mask */ #define SCR_DEV_CTL 0xe0 /* b Device control */ @@ -83,6 +96,9 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc) spin_unlock_irqrestore(&t7l66xb->lock, flags); + tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, + t7l66xb_mmc_resources[0].start & 0xfffe); + return 0; } @@ -106,28 +122,28 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc) return 0; } +static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + + tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state); +} + +static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); + + tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state); +} + /*--------------------------------------------------------------------------*/ static struct tmio_mmc_data t7166xb_mmc_data = { .hclk = 24000000, -}; - -static const 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, - }, + .set_pwr = t7l66xb_mmc_pwr, + .set_clk_div = t7l66xb_mmc_clk_div, }; static const struct resource t7l66xb_nand_resources[] = { @@ -282,6 +298,9 @@ static int t7l66xb_resume(struct platform_device *dev) if (pdata && pdata->resume) pdata->resume(dev); + tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, + t7l66xb_mmc_resources[0].start & 0xfffe); + return 0; } #else diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 3280ab33f88..5c7f04343d5 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -22,28 +22,52 @@ enum { TC6387XB_CELL_MMC, }; +struct tc6387xb { + void __iomem *scr; + struct clk *clk32k; + struct resource rscr; +}; + +static struct resource tc6387xb_mmc_resources[] = { + { + .start = 0x800, + .end = 0x9ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +/*--------------------------------------------------------------------------*/ + #ifdef CONFIG_PM static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) { - struct clk *clk32k = platform_get_drvdata(dev); + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); struct tc6387xb_platform_data *pdata = dev->dev.platform_data; if (pdata && pdata->suspend) pdata->suspend(dev); - clk_disable(clk32k); + clk_disable(tc6387xb->clk32k); return 0; } static int tc6387xb_resume(struct platform_device *dev) { - struct clk *clk32k = platform_get_drvdata(dev); + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); struct tc6387xb_platform_data *pdata = dev->dev.platform_data; - clk_enable(clk32k); + clk_enable(tc6387xb->clk32k); if (pdata && pdata->resume) pdata->resume(dev); + tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0, + tc6387xb_mmc_resources[0].start & 0xfffe); + return 0; } #else @@ -53,12 +77,32 @@ static int tc6387xb_resume(struct platform_device *dev) /*--------------------------------------------------------------------------*/ +static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); + + tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state); +} + +static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); + + tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state); +} + + static int tc6387xb_mmc_enable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); - struct clk *clk32k = platform_get_drvdata(dev); + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - clk_enable(clk32k); + clk_enable(tc6387xb->clk32k); + + tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0, + tc6387xb_mmc_resources[0].start & 0xfffe); return 0; } @@ -66,36 +110,20 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc) static int tc6387xb_mmc_disable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); - struct clk *clk32k = platform_get_drvdata(dev); + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - clk_disable(clk32k); + clk_disable(tc6387xb->clk32k); return 0; } -/*--------------------------------------------------------------------------*/ - static struct tmio_mmc_data tc6387xb_mmc_data = { .hclk = 24000000, + .set_pwr = tc6387xb_mmc_pwr, + .set_clk_div = tc6387xb_mmc_clk_div, }; -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] = { @@ -111,8 +139,9 @@ static struct mfd_cell tc6387xb_cells[] = { static int tc6387xb_probe(struct platform_device *dev) { struct tc6387xb_platform_data *pdata = dev->dev.platform_data; - struct resource *iomem; + struct resource *iomem, *rscr; struct clk *clk32k; + struct tc6387xb *tc6387xb; int irq, ret; iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -120,18 +149,40 @@ static int tc6387xb_probe(struct platform_device *dev) return -EINVAL; } + tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL); + if (!tc6387xb) + return -ENOMEM; + ret = platform_get_irq(dev, 0); if (ret >= 0) irq = ret; else - goto err_resource; + goto err_no_irq; clk32k = clk_get(&dev->dev, "CLK_CK32K"); if (IS_ERR(clk32k)) { ret = PTR_ERR(clk32k); + goto err_no_clk; + } + + rscr = &tc6387xb->rscr; + rscr->name = "tc6387xb-core"; + rscr->start = iomem->start; + rscr->end = iomem->start + 0xff; + rscr->flags = IORESOURCE_MEM; + + ret = request_resource(iomem, rscr); + if (ret) goto err_resource; + + tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); + if (!tc6387xb->scr) { + ret = -ENOMEM; + goto err_ioremap; } - platform_set_drvdata(dev, clk32k); + + tc6387xb->clk32k = clk32k; + platform_set_drvdata(dev, tc6387xb); if (pdata && pdata->enable) pdata->enable(dev); @@ -149,8 +200,13 @@ static int tc6387xb_probe(struct platform_device *dev) if (!ret) return 0; - clk_put(clk32k); +err_ioremap: + release_resource(&tc6387xb->rscr); err_resource: + clk_put(clk32k); +err_no_clk: +err_no_irq: + kfree(tc6387xb); return ret; } @@ -195,3 +251,4 @@ 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 1429a7341a9..4bc5a08a2b0 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -136,10 +136,6 @@ static int tc6393xb_nand_enable(struct platform_device *nand) return 0; } -static struct tmio_mmc_data tc6393xb_mmc_data = { - .hclk = 24000000, -}; - static struct resource __devinitdata tc6393xb_nand_resources[] = { { .start = 0x1000, @@ -164,11 +160,6 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = { .end = 0x9ff, .flags = IORESOURCE_MEM, }, - { - .start = 0x200, - .end = 0x2ff, - .flags = IORESOURCE_MEM, - }, { .start = IRQ_TC6393_MMC, .end = IRQ_TC6393_MMC, @@ -346,6 +337,50 @@ int tc6393xb_lcd_mode(struct platform_device *fb, } EXPORT_SYMBOL(tc6393xb_lcd_mode); +static int tc6393xb_mmc_enable(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); + + tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0, + tc6393xb_mmc_resources[0].start & 0xfffe); + + return 0; +} + +static int tc6393xb_mmc_resume(struct platform_device *mmc) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); + + tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0, + tc6393xb_mmc_resources[0].start & 0xfffe); + + return 0; +} + +static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); + + tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state); +} + +static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state) +{ + struct platform_device *dev = to_platform_device(mmc->dev.parent); + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); + + tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state); +} + +static struct tmio_mmc_data tc6393xb_mmc_data = { + .hclk = 24000000, + .set_pwr = tc6393xb_mmc_pwr, + .set_clk_div = tc6393xb_mmc_clk_div, +}; + static struct mfd_cell __devinitdata tc6393xb_cells[] = { [TC6393XB_CELL_NAND] = { .name = "tmio-nand", @@ -355,6 +390,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { }, [TC6393XB_CELL_MMC] = { .name = "tmio-mmc", + .enable = tc6393xb_mmc_enable, + .resume = tc6393xb_mmc_resume, .driver_data = &tc6393xb_mmc_data, .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), .resources = tc6393xb_mmc_resources, @@ -836,3 +873,4 @@ MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); MODULE_ALIAS("platform:tc6393xb"); + diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c new file mode 100644 index 00000000000..eddc19ae464 --- /dev/null +++ b/drivers/mfd/tmio_core.c @@ -0,0 +1,52 @@ +/* + * Copyright(c) 2009 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. + */ + +#include + +int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base) +{ + /* Enable the MMC/SD Control registers */ + sd_config_write16(cnf, shift, CNF_CMD, SDCREN); + sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); + + /* Disable SD power during suspend */ + sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01); + + /* The below is required but why? FIXME */ + sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f); + + /* Power down SD bus */ + sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00); + + return 0; +} +EXPORT_SYMBOL(tmio_core_mmc_enable); + +int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base) +{ + + /* Enable the MMC/SD Control registers */ + sd_config_write16(cnf, shift, CNF_CMD, SDCREN); + sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); + + return 0; +} +EXPORT_SYMBOL(tmio_core_mmc_resume); + +void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state) +{ + sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00); +} +EXPORT_SYMBOL(tmio_core_mmc_pwr); + +void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state) +{ + sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0); +} +EXPORT_SYMBOL(tmio_core_mmc_clk_div); + -- cgit v1.2.3