linux/drivers/mmc/host/sdhci-sirf.c
<<
>>
Prefs
   1/*
   2 * SDHCI support for SiRF primaII and marco SoCs
   3 *
   4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
   5 *
   6 * Licensed under GPLv2 or later.
   7 */
   8
   9#include <linux/delay.h>
  10#include <linux/device.h>
  11#include <linux/mmc/host.h>
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/of_gpio.h>
  15#include <linux/mmc/slot-gpio.h>
  16#include "sdhci-pltfm.h"
  17
  18struct sdhci_sirf_priv {
  19        struct clk *clk;
  20        int gpio_cd;
  21};
  22
  23static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
  24{
  25        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
  26        struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
  27        return clk_get_rate(priv->clk);
  28}
  29
  30static struct sdhci_ops sdhci_sirf_ops = {
  31        .get_max_clock  = sdhci_sirf_get_max_clk,
  32};
  33
  34static struct sdhci_pltfm_data sdhci_sirf_pdata = {
  35        .ops = &sdhci_sirf_ops,
  36        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
  37                SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
  38                SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
  39                SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
  40                SDHCI_QUIRK_DELAY_AFTER_POWER,
  41};
  42
  43static int sdhci_sirf_probe(struct platform_device *pdev)
  44{
  45        struct sdhci_host *host;
  46        struct sdhci_pltfm_host *pltfm_host;
  47        struct sdhci_sirf_priv *priv;
  48        struct clk *clk;
  49        int gpio_cd;
  50        int ret;
  51
  52        clk = devm_clk_get(&pdev->dev, NULL);
  53        if (IS_ERR(clk)) {
  54                dev_err(&pdev->dev, "unable to get clock");
  55                return PTR_ERR(clk);
  56        }
  57
  58        if (pdev->dev.of_node)
  59                gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
  60        else
  61                gpio_cd = -EINVAL;
  62
  63        host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
  64        if (IS_ERR(host))
  65                return PTR_ERR(host);
  66
  67        pltfm_host = sdhci_priv(host);
  68        priv = sdhci_pltfm_priv(pltfm_host);
  69        priv->clk = clk;
  70        priv->gpio_cd = gpio_cd;
  71
  72        sdhci_get_of_property(pdev);
  73
  74        ret = clk_prepare_enable(priv->clk);
  75        if (ret)
  76                goto err_clk_prepare;
  77
  78        ret = sdhci_add_host(host);
  79        if (ret)
  80                goto err_sdhci_add;
  81
  82        /*
  83         * We must request the IRQ after sdhci_add_host(), as the tasklet only
  84         * gets setup in sdhci_add_host() and we oops.
  85         */
  86        if (gpio_is_valid(priv->gpio_cd)) {
  87                ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd);
  88                if (ret) {
  89                        dev_err(&pdev->dev, "card detect irq request failed: %d\n",
  90                                ret);
  91                        goto err_request_cd;
  92                }
  93        }
  94
  95        return 0;
  96
  97err_request_cd:
  98        sdhci_remove_host(host, 0);
  99err_sdhci_add:
 100        clk_disable_unprepare(priv->clk);
 101err_clk_prepare:
 102        sdhci_pltfm_free(pdev);
 103        return ret;
 104}
 105
 106static int sdhci_sirf_remove(struct platform_device *pdev)
 107{
 108        struct sdhci_host *host = platform_get_drvdata(pdev);
 109        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 110        struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
 111
 112        sdhci_pltfm_unregister(pdev);
 113
 114        if (gpio_is_valid(priv->gpio_cd))
 115                mmc_gpio_free_cd(host->mmc);
 116
 117        clk_disable_unprepare(priv->clk);
 118        return 0;
 119}
 120
 121#ifdef CONFIG_PM_SLEEP
 122static int sdhci_sirf_suspend(struct device *dev)
 123{
 124        struct sdhci_host *host = dev_get_drvdata(dev);
 125        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 126        struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
 127        int ret;
 128
 129        ret = sdhci_suspend_host(host);
 130        if (ret)
 131                return ret;
 132
 133        clk_disable(priv->clk);
 134
 135        return 0;
 136}
 137
 138static int sdhci_sirf_resume(struct device *dev)
 139{
 140        struct sdhci_host *host = dev_get_drvdata(dev);
 141        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 142        struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
 143        int ret;
 144
 145        ret = clk_enable(priv->clk);
 146        if (ret) {
 147                dev_dbg(dev, "Resume: Error enabling clock\n");
 148                return ret;
 149        }
 150
 151        return sdhci_resume_host(host);
 152}
 153
 154static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
 155#endif
 156
 157static const struct of_device_id sdhci_sirf_of_match[] = {
 158        { .compatible = "sirf,prima2-sdhc" },
 159        { }
 160};
 161MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
 162
 163static struct platform_driver sdhci_sirf_driver = {
 164        .driver         = {
 165                .name   = "sdhci-sirf",
 166                .owner  = THIS_MODULE,
 167                .of_match_table = sdhci_sirf_of_match,
 168#ifdef CONFIG_PM_SLEEP
 169                .pm     = &sdhci_sirf_pm_ops,
 170#endif
 171        },
 172        .probe          = sdhci_sirf_probe,
 173        .remove         = sdhci_sirf_remove,
 174};
 175
 176module_platform_driver(sdhci_sirf_driver);
 177
 178MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco");
 179MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
 180MODULE_LICENSE("GPL v2");
 181