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
  18#define SDHCI_CLK_DELAY_SETTING 0x4C
  19#define SDHCI_SIRF_8BITBUS BIT(3)
  20#define SIRF_TUNING_COUNT 16384
  21
  22struct sdhci_sirf_priv {
  23        int gpio_cd;
  24};
  25
  26static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
  27{
  28        u8 ctrl;
  29
  30        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
  31        ctrl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_SIRF_8BITBUS);
  32
  33        /*
  34         * CSR atlas7 and prima2 SD host version is not 3.0
  35         * 8bit-width enable bit of CSR SD hosts is 3,
  36         * while stardard hosts use bit 5
  37         */
  38        if (width == MMC_BUS_WIDTH_8)
  39                ctrl |= SDHCI_SIRF_8BITBUS;
  40        else if (width == MMC_BUS_WIDTH_4)
  41                ctrl |= SDHCI_CTRL_4BITBUS;
  42
  43        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
  44}
  45
  46static u32 sdhci_sirf_readl_le(struct sdhci_host *host, int reg)
  47{
  48        u32 val = readl(host->ioaddr + reg);
  49
  50        if (unlikely((reg == SDHCI_CAPABILITIES_1) &&
  51                        (host->mmc->caps & MMC_CAP_UHS_SDR50))) {
  52                /* fake CAP_1 register */
  53                val = SDHCI_SUPPORT_DDR50 |
  54                        SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING;
  55        }
  56
  57        if (unlikely(reg == SDHCI_SLOT_INT_STATUS)) {
  58                u32 prss = val;
  59                /* fake chips as V3.0 host conreoller */
  60                prss &= ~(0xFF << 16);
  61                val = prss | (SDHCI_SPEC_300 << 16);
  62        }
  63        return val;
  64}
  65
  66static u16 sdhci_sirf_readw_le(struct sdhci_host *host, int reg)
  67{
  68        u16 ret = 0;
  69
  70        ret = readw(host->ioaddr + reg);
  71
  72        if (unlikely(reg == SDHCI_HOST_VERSION)) {
  73                ret = readw(host->ioaddr + SDHCI_HOST_VERSION);
  74                ret |= SDHCI_SPEC_300;
  75        }
  76
  77        return ret;
  78}
  79
  80static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
  81{
  82        int tuning_seq_cnt = 3;
  83        int phase;
  84        u8 tuned_phase_cnt = 0;
  85        int rc = 0, longest_range = 0;
  86        int start = -1, end = 0, tuning_value = -1, range = 0;
  87        u16 clock_setting;
  88        struct mmc_host *mmc = host->mmc;
  89
  90        clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING);
  91        clock_setting &= ~0x3fff;
  92
  93retry:
  94        phase = 0;
  95        tuned_phase_cnt = 0;
  96        do {
  97                sdhci_writel(host,
  98                        clock_setting | phase,
  99                        SDHCI_CLK_DELAY_SETTING);
 100
 101                if (!mmc_send_tuning(mmc, opcode, NULL)) {
 102                        /* Tuning is successful at this tuning point */
 103                        tuned_phase_cnt++;
 104                        dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
 105                                 mmc_hostname(mmc), phase);
 106                        if (start == -1)
 107                                start = phase;
 108                        end = phase;
 109                        range++;
 110                        if (phase == (SIRF_TUNING_COUNT - 1)
 111                                && range > longest_range)
 112                                tuning_value = (start + end) / 2;
 113                } else {
 114                        dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n",
 115                                 mmc_hostname(mmc), phase);
 116                        if (range > longest_range) {
 117                                tuning_value = (start + end) / 2;
 118                                longest_range = range;
 119                        }
 120                        start = -1;
 121                        end = range = 0;
 122                }
 123        } while (++phase < SIRF_TUNING_COUNT);
 124
 125        if (tuned_phase_cnt && tuning_value > 0) {
 126                /*
 127                 * Finally set the selected phase in delay
 128                 * line hw block.
 129                 */
 130                phase = tuning_value;
 131                sdhci_writel(host,
 132                        clock_setting | phase,
 133                        SDHCI_CLK_DELAY_SETTING);
 134
 135                dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
 136                         mmc_hostname(mmc), phase);
 137        } else {
 138                if (--tuning_seq_cnt)
 139                        goto retry;
 140                /* Tuning failed */
 141                dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
 142                       mmc_hostname(mmc));
 143                rc = -EIO;
 144        }
 145
 146        return rc;
 147}
 148
 149static const struct sdhci_ops sdhci_sirf_ops = {
 150        .read_l = sdhci_sirf_readl_le,
 151        .read_w = sdhci_sirf_readw_le,
 152        .platform_execute_tuning = sdhci_sirf_execute_tuning,
 153        .set_clock = sdhci_set_clock,
 154        .get_max_clock  = sdhci_pltfm_clk_get_max_clock,
 155        .set_bus_width = sdhci_sirf_set_bus_width,
 156        .reset = sdhci_reset,
 157        .set_uhs_signaling = sdhci_set_uhs_signaling,
 158};
 159
 160static const struct sdhci_pltfm_data sdhci_sirf_pdata = {
 161        .ops = &sdhci_sirf_ops,
 162        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
 163                SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
 164                SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
 165                SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
 166        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 167};
 168
 169static int sdhci_sirf_probe(struct platform_device *pdev)
 170{
 171        struct sdhci_host *host;
 172        struct sdhci_pltfm_host *pltfm_host;
 173        struct sdhci_sirf_priv *priv;
 174        struct clk *clk;
 175        int gpio_cd;
 176        int ret;
 177
 178        clk = devm_clk_get(&pdev->dev, NULL);
 179        if (IS_ERR(clk)) {
 180                dev_err(&pdev->dev, "unable to get clock");
 181                return PTR_ERR(clk);
 182        }
 183
 184        if (pdev->dev.of_node)
 185                gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
 186        else
 187                gpio_cd = -EINVAL;
 188
 189        host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
 190        if (IS_ERR(host))
 191                return PTR_ERR(host);
 192
 193        pltfm_host = sdhci_priv(host);
 194        pltfm_host->clk = clk;
 195        priv = sdhci_pltfm_priv(pltfm_host);
 196        priv->gpio_cd = gpio_cd;
 197
 198        sdhci_get_of_property(pdev);
 199
 200        ret = clk_prepare_enable(pltfm_host->clk);
 201        if (ret)
 202                goto err_clk_prepare;
 203
 204        ret = sdhci_add_host(host);
 205        if (ret)
 206                goto err_sdhci_add;
 207
 208        /*
 209         * We must request the IRQ after sdhci_add_host(), as the tasklet only
 210         * gets setup in sdhci_add_host() and we oops.
 211         */
 212        if (gpio_is_valid(priv->gpio_cd)) {
 213                ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0);
 214                if (ret) {
 215                        dev_err(&pdev->dev, "card detect irq request failed: %d\n",
 216                                ret);
 217                        goto err_request_cd;
 218                }
 219                mmc_gpiod_request_cd_irq(host->mmc);
 220        }
 221
 222        return 0;
 223
 224err_request_cd:
 225        sdhci_remove_host(host, 0);
 226err_sdhci_add:
 227        clk_disable_unprepare(pltfm_host->clk);
 228err_clk_prepare:
 229        sdhci_pltfm_free(pdev);
 230        return ret;
 231}
 232
 233static const struct of_device_id sdhci_sirf_of_match[] = {
 234        { .compatible = "sirf,prima2-sdhc" },
 235        { }
 236};
 237MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
 238
 239static struct platform_driver sdhci_sirf_driver = {
 240        .driver         = {
 241                .name   = "sdhci-sirf",
 242                .of_match_table = sdhci_sirf_of_match,
 243                .pm     = &sdhci_pltfm_pmops,
 244        },
 245        .probe          = sdhci_sirf_probe,
 246        .remove         = sdhci_pltfm_unregister,
 247};
 248
 249module_platform_driver(sdhci_sirf_driver);
 250
 251MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco");
 252MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
 253MODULE_LICENSE("GPL v2");
 254