forked from Minki/linux
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 <ian@mnementh.co.uk> Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
6f2af72a24
commit
64e8867ba8
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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_resource;
|
||||
goto err_no_clk;
|
||||
}
|
||||
platform_set_drvdata(dev, clk32k);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
52
drivers/mfd/tmio_core.c
Normal file
52
drivers/mfd/tmio_core.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright(c) 2009 Ian Molton <spyro@f2s.com>
|
||||
*
|
||||
* 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/mfd/tmio.h>
|
||||
|
||||
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);
|
||||
|
@ -46,7 +46,9 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
|
||||
clk |= 0x100;
|
||||
}
|
||||
|
||||
sd_config_write8(host, CNF_SD_CLK_MODE, clk >> 22);
|
||||
if (host->set_clk_div)
|
||||
host->set_clk_div(host->pdev, (clk>>22) & 1);
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
|
||||
}
|
||||
|
||||
@ -427,12 +429,13 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
/* Power sequence - OFF -> ON -> UP */
|
||||
switch (ios->power_mode) {
|
||||
case MMC_POWER_OFF: /* power down SD bus */
|
||||
sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
|
||||
if (host->set_pwr)
|
||||
host->set_pwr(host->pdev, 0);
|
||||
tmio_mmc_clk_stop(host);
|
||||
break;
|
||||
case MMC_POWER_ON: /* power up SD bus */
|
||||
|
||||
sd_config_write8(host, CNF_PWR_CTL_2, 0x02);
|
||||
if (host->set_pwr)
|
||||
host->set_pwr(host->pdev, 1);
|
||||
break;
|
||||
case MMC_POWER_UP: /* start bus clock */
|
||||
tmio_mmc_clk_start(host);
|
||||
@ -485,21 +488,15 @@ static int tmio_mmc_resume(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
|
||||
struct mmc_host *mmc = platform_get_drvdata(dev);
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
int ret = 0;
|
||||
|
||||
/* Tell the MFD core we are ready to be enabled */
|
||||
if (cell->enable) {
|
||||
ret = cell->enable(dev);
|
||||
if (cell->resume) {
|
||||
ret = cell->resume(dev);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Enable the MMC/SD Control registers */
|
||||
sd_config_write16(host, CNF_CMD, SDCREN);
|
||||
sd_config_write32(host, CNF_CTL_BASE,
|
||||
(dev->resource[0].start >> host->bus_shift) & 0xfffe);
|
||||
|
||||
mmc_resume_host(mmc);
|
||||
|
||||
out:
|
||||
@ -514,17 +511,16 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata;
|
||||
struct resource *res_ctl, *res_cnf;
|
||||
struct resource *res_ctl;
|
||||
struct tmio_mmc_host *host;
|
||||
struct mmc_host *mmc;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (dev->num_resources != 3)
|
||||
if (dev->num_resources != 2)
|
||||
goto out;
|
||||
|
||||
res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1);
|
||||
if (!res_ctl || !res_cnf)
|
||||
if (!res_ctl)
|
||||
goto out;
|
||||
|
||||
pdata = cell->driver_data;
|
||||
@ -539,8 +535,12 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
host->mmc = mmc;
|
||||
host->pdev = dev;
|
||||
platform_set_drvdata(dev, mmc);
|
||||
|
||||
host->set_pwr = pdata->set_pwr;
|
||||
host->set_clk_div = pdata->set_clk_div;
|
||||
|
||||
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
|
||||
host->bus_shift = resource_size(res_ctl) >> 10;
|
||||
|
||||
@ -548,10 +548,6 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
if (!host->ctl)
|
||||
goto host_free;
|
||||
|
||||
host->cnf = ioremap(res_cnf->start, resource_size(res_cnf));
|
||||
if (!host->cnf)
|
||||
goto unmap_ctl;
|
||||
|
||||
mmc->ops = &tmio_mmc_ops;
|
||||
mmc->caps = MMC_CAP_4_BIT_DATA;
|
||||
mmc->f_max = pdata->hclk;
|
||||
@ -562,23 +558,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
if (cell->enable) {
|
||||
ret = cell->enable(dev);
|
||||
if (ret)
|
||||
goto unmap_cnf;
|
||||
goto unmap_ctl;
|
||||
}
|
||||
|
||||
/* Enable the MMC/SD Control registers */
|
||||
sd_config_write16(host, CNF_CMD, SDCREN);
|
||||
sd_config_write32(host, CNF_CTL_BASE,
|
||||
(dev->resource[0].start >> host->bus_shift) & 0xfffe);
|
||||
|
||||
/* Disable SD power during suspend */
|
||||
sd_config_write8(host, CNF_PWR_CTL_3, 0x01);
|
||||
|
||||
/* The below is required but why? FIXME */
|
||||
sd_config_write8(host, CNF_STOP_CLK_CTL, 0x1f);
|
||||
|
||||
/* Power down SD bus*/
|
||||
sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
|
||||
|
||||
tmio_mmc_clk_stop(host);
|
||||
reset(host);
|
||||
|
||||
@ -586,14 +568,14 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
if (ret >= 0)
|
||||
host->irq = ret;
|
||||
else
|
||||
goto unmap_cnf;
|
||||
goto unmap_ctl;
|
||||
|
||||
disable_mmc_irqs(host, TMIO_MASK_ALL);
|
||||
|
||||
ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED |
|
||||
IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host);
|
||||
if (ret)
|
||||
goto unmap_cnf;
|
||||
goto unmap_ctl;
|
||||
|
||||
mmc_add_host(mmc);
|
||||
|
||||
@ -605,8 +587,6 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
|
||||
return 0;
|
||||
|
||||
unmap_cnf:
|
||||
iounmap(host->cnf);
|
||||
unmap_ctl:
|
||||
iounmap(host->ctl);
|
||||
host_free:
|
||||
@ -626,7 +606,6 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev)
|
||||
mmc_remove_host(mmc);
|
||||
free_irq(host->irq, host);
|
||||
iounmap(host->ctl);
|
||||
iounmap(host->cnf);
|
||||
mmc_free_host(mmc);
|
||||
}
|
||||
|
||||
|
@ -11,26 +11,6 @@
|
||||
|
||||
#include <linux/highmem.h>
|
||||
|
||||
#define CNF_CMD 0x04
|
||||
#define CNF_CTL_BASE 0x10
|
||||
#define CNF_INT_PIN 0x3d
|
||||
#define CNF_STOP_CLK_CTL 0x40
|
||||
#define CNF_GCLK_CTL 0x41
|
||||
#define CNF_SD_CLK_MODE 0x42
|
||||
#define CNF_PIN_STATUS 0x44
|
||||
#define CNF_PWR_CTL_1 0x48
|
||||
#define CNF_PWR_CTL_2 0x49
|
||||
#define CNF_PWR_CTL_3 0x4a
|
||||
#define CNF_CARD_DETECT_MODE 0x4c
|
||||
#define CNF_SD_SLOT 0x50
|
||||
#define CNF_EXT_GCLK_CTL_1 0xf0
|
||||
#define CNF_EXT_GCLK_CTL_2 0xf1
|
||||
#define CNF_EXT_GCLK_CTL_3 0xf9
|
||||
#define CNF_SD_LED_EN_1 0xfa
|
||||
#define CNF_SD_LED_EN_2 0xfe
|
||||
|
||||
#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/
|
||||
|
||||
#define CTL_SD_CMD 0x00
|
||||
#define CTL_ARG_REG 0x04
|
||||
#define CTL_STOP_INTERNAL_ACTION 0x08
|
||||
@ -110,7 +90,6 @@
|
||||
|
||||
|
||||
struct tmio_mmc_host {
|
||||
void __iomem *cnf;
|
||||
void __iomem *ctl;
|
||||
unsigned long bus_shift;
|
||||
struct mmc_command *cmd;
|
||||
@ -119,10 +98,16 @@ struct tmio_mmc_host {
|
||||
struct mmc_host *mmc;
|
||||
int irq;
|
||||
|
||||
/* Callbacks for clock / power control */
|
||||
void (*set_pwr)(struct platform_device *host, int state);
|
||||
void (*set_clk_div)(struct platform_device *host, int state);
|
||||
|
||||
/* pio related stuff */
|
||||
struct scatterlist *sg_ptr;
|
||||
unsigned int sg_len;
|
||||
unsigned int sg_off;
|
||||
|
||||
struct platform_device *pdev;
|
||||
};
|
||||
|
||||
#include <linux/io.h>
|
||||
@ -163,25 +148,6 @@ static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr,
|
||||
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
|
||||
}
|
||||
|
||||
static inline void sd_config_write8(struct tmio_mmc_host *host, int addr,
|
||||
u8 val)
|
||||
{
|
||||
writeb(val, host->cnf + (addr << host->bus_shift));
|
||||
}
|
||||
|
||||
static inline void sd_config_write16(struct tmio_mmc_host *host, int addr,
|
||||
u16 val)
|
||||
{
|
||||
writew(val, host->cnf + (addr << host->bus_shift));
|
||||
}
|
||||
|
||||
static inline void sd_config_write32(struct tmio_mmc_host *host, int addr,
|
||||
u32 val)
|
||||
{
|
||||
writew(val, host->cnf + (addr << host->bus_shift));
|
||||
writew(val >> 16, host->cnf + ((addr + 2) << host->bus_shift));
|
||||
}
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define MFD_TMIO_H
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define tmio_ioread8(addr) readb(addr)
|
||||
#define tmio_ioread16(addr) readw(addr)
|
||||
@ -18,11 +20,48 @@
|
||||
writew((val) >> 16, (addr) + 2); \
|
||||
} while (0)
|
||||
|
||||
#define CNF_CMD 0x04
|
||||
#define CNF_CTL_BASE 0x10
|
||||
#define CNF_INT_PIN 0x3d
|
||||
#define CNF_STOP_CLK_CTL 0x40
|
||||
#define CNF_GCLK_CTL 0x41
|
||||
#define CNF_SD_CLK_MODE 0x42
|
||||
#define CNF_PIN_STATUS 0x44
|
||||
#define CNF_PWR_CTL_1 0x48
|
||||
#define CNF_PWR_CTL_2 0x49
|
||||
#define CNF_PWR_CTL_3 0x4a
|
||||
#define CNF_CARD_DETECT_MODE 0x4c
|
||||
#define CNF_SD_SLOT 0x50
|
||||
#define CNF_EXT_GCLK_CTL_1 0xf0
|
||||
#define CNF_EXT_GCLK_CTL_2 0xf1
|
||||
#define CNF_EXT_GCLK_CTL_3 0xf9
|
||||
#define CNF_SD_LED_EN_1 0xfa
|
||||
#define CNF_SD_LED_EN_2 0xfe
|
||||
|
||||
#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/
|
||||
|
||||
#define sd_config_write8(base, shift, reg, val) \
|
||||
tmio_iowrite8((val), (base) + ((reg) << (shift)))
|
||||
#define sd_config_write16(base, shift, reg, val) \
|
||||
tmio_iowrite16((val), (base) + ((reg) << (shift)))
|
||||
#define sd_config_write32(base, shift, reg, val) \
|
||||
do { \
|
||||
tmio_iowrite16((val), (base) + ((reg) << (shift))); \
|
||||
tmio_iowrite16((val) >> 16, (base) + ((reg + 2) << (shift))); \
|
||||
} while (0)
|
||||
|
||||
int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
|
||||
int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
|
||||
void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
|
||||
void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state);
|
||||
|
||||
/*
|
||||
* data for the MMC controller
|
||||
*/
|
||||
struct tmio_mmc_data {
|
||||
const unsigned int hclk;
|
||||
void (*set_pwr)(struct platform_device *host, int state);
|
||||
void (*set_clk_div)(struct platform_device *host, int state);
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user