android_kernel_motorola_sm6225/drivers/mmc/host/tmio_mmc.c
Guennadi Liakhovetski e6ee7182c3 mmc: Add runtime and system-wide PM to the TMIO MMC driver
Add runtime and system-wide power management to the TMIO MMC driver
in PIO and DMA modes, allowing it to properly save and restore its
state during system suspend. Runtime PM is very crude ATM, because
the controller has to be powered on all the time to detect card
hotplug events.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
2011-05-24 23:53:51 -04:00

145 lines
3.1 KiB
C

/*
* linux/drivers/mmc/host/tmio_mmc.c
*
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 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.
*
* Driver for the MMC / SD / SDIO cell found in:
*
* TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
*/
#include <linux/device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include "tmio_mmc.h"
#ifdef CONFIG_PM
static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
{
const struct mfd_cell *cell = mfd_get_cell(dev);
struct mmc_host *mmc = platform_get_drvdata(dev);
int ret;
ret = tmio_mmc_host_suspend(&dev->dev);
/* Tell MFD core it can disable us now.*/
if (!ret && cell->disable)
cell->disable(dev);
return ret;
}
static int tmio_mmc_resume(struct platform_device *dev)
{
const struct mfd_cell *cell = mfd_get_cell(dev);
struct mmc_host *mmc = platform_get_drvdata(dev);
int ret = 0;
/* Tell the MFD core we are ready to be enabled */
if (cell->resume)
ret = cell->resume(dev);
if (!ret)
ret = tmio_mmc_host_resume(&dev->dev);
return ret;
}
#else
#define tmio_mmc_suspend NULL
#define tmio_mmc_resume NULL
#endif
static int __devinit tmio_mmc_probe(struct platform_device *pdev)
{
const struct mfd_cell *cell = mfd_get_cell(pdev);
struct tmio_mmc_data *pdata;
struct tmio_mmc_host *host;
int ret = -EINVAL;
if (pdev->num_resources != 2)
goto out;
pdata = mfd_get_data(pdev);
if (!pdata || !pdata->hclk)
goto out;
/* Tell the MFD core we are ready to be enabled */
if (cell->enable) {
ret = cell->enable(pdev);
if (ret)
goto out;
}
ret = tmio_mmc_host_probe(&host, pdev, pdata);
if (ret)
goto cell_disable;
pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
(unsigned long)host->ctl, host->irq);
return 0;
cell_disable:
if (cell->disable)
cell->disable(pdev);
out:
return ret;
}
static int __devexit tmio_mmc_remove(struct platform_device *pdev)
{
const struct mfd_cell *cell = mfd_get_cell(pdev);
struct mmc_host *mmc = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
if (mmc) {
tmio_mmc_host_remove(mmc_priv(mmc));
if (cell->disable)
cell->disable(pdev);
}
return 0;
}
/* ------------------- device registration ----------------------- */
static struct platform_driver tmio_mmc_driver = {
.driver = {
.name = "tmio-mmc",
.owner = THIS_MODULE,
},
.probe = tmio_mmc_probe,
.remove = __devexit_p(tmio_mmc_remove),
.suspend = tmio_mmc_suspend,
.resume = tmio_mmc_resume,
};
static int __init tmio_mmc_init(void)
{
return platform_driver_register(&tmio_mmc_driver);
}
static void __exit tmio_mmc_exit(void)
{
platform_driver_unregister(&tmio_mmc_driver);
}
module_init(tmio_mmc_init);
module_exit(tmio_mmc_exit);
MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:tmio-mmc");