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 128 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 int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) 47{ 48 int tuning_seq_cnt = 3; 49 u8 phase, tuned_phases[SIRF_TUNING_COUNT]; 50 u8 tuned_phase_cnt = 0; 51 int rc = 0, longest_range = 0; 52 int start = -1, end = 0, tuning_value = -1, range = 0; 53 u16 clock_setting; 54 struct mmc_host *mmc = host->mmc; 55 56 clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING); 57 clock_setting &= ~0x3fff; 58 59retry: 60 phase = 0; 61 do { 62 sdhci_writel(host, 63 clock_setting | phase, 64 SDHCI_CLK_DELAY_SETTING); 65 66 if (!mmc_send_tuning(mmc)) { 67 /* Tuning is successful at this tuning point */ 68 tuned_phases[tuned_phase_cnt++] = phase; 69 dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", 70 mmc_hostname(mmc), phase); 71 if (start == -1) 72 start = phase; 73 end = phase; 74 range++; 75 if (phase == (SIRF_TUNING_COUNT - 1) 76 && range > longest_range) 77 tuning_value = (start + end) / 2; 78 } else { 79 dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n", 80 mmc_hostname(mmc), phase); 81 if (range > longest_range) { 82 tuning_value = (start + end) / 2; 83 longest_range = range; 84 } 85 start = -1; 86 end = range = 0; 87 } 88 } while (++phase < ARRAY_SIZE(tuned_phases)); 89 90 if (tuned_phase_cnt && tuning_value > 0) { 91 /* 92 * Finally set the selected phase in delay 93 * line hw block. 94 */ 95 phase = tuning_value; 96 sdhci_writel(host, 97 clock_setting | phase, 98 SDHCI_CLK_DELAY_SETTING); 99 100 dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", 101 mmc_hostname(mmc), phase); 102 } else { 103 if (--tuning_seq_cnt) 104 goto retry; 105 /* Tuning failed */ 106 dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", 107 mmc_hostname(mmc)); 108 rc = -EIO; 109 } 110 111 return rc; 112} 113 114static struct sdhci_ops sdhci_sirf_ops = { 115 .platform_execute_tuning = sdhci_sirf_execute_tuning, 116 .set_clock = sdhci_set_clock, 117 .get_max_clock = sdhci_pltfm_clk_get_max_clock, 118 .set_bus_width = sdhci_sirf_set_bus_width, 119 .reset = sdhci_reset, 120 .set_uhs_signaling = sdhci_set_uhs_signaling, 121}; 122 123static struct sdhci_pltfm_data sdhci_sirf_pdata = { 124 .ops = &sdhci_sirf_ops, 125 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 126 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 127 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 128 SDHCI_QUIRK_INVERTED_WRITE_PROTECT | 129 SDHCI_QUIRK_DELAY_AFTER_POWER, 130}; 131 132static int sdhci_sirf_probe(struct platform_device *pdev) 133{ 134 struct sdhci_host *host; 135 struct sdhci_pltfm_host *pltfm_host; 136 struct sdhci_sirf_priv *priv; 137 struct clk *clk; 138 int gpio_cd; 139 int ret; 140 141 clk = devm_clk_get(&pdev->dev, NULL); 142 if (IS_ERR(clk)) { 143 dev_err(&pdev->dev, "unable to get clock"); 144 return PTR_ERR(clk); 145 } 146 147 if (pdev->dev.of_node) 148 gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0); 149 else 150 gpio_cd = -EINVAL; 151 152 host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv)); 153 if (IS_ERR(host)) 154 return PTR_ERR(host); 155 156 pltfm_host = sdhci_priv(host); 157 pltfm_host->clk = clk; 158 priv = sdhci_pltfm_priv(pltfm_host); 159 priv->gpio_cd = gpio_cd; 160 161 sdhci_get_of_property(pdev); 162 163 ret = clk_prepare_enable(pltfm_host->clk); 164 if (ret) 165 goto err_clk_prepare; 166 167 ret = sdhci_add_host(host); 168 if (ret) 169 goto err_sdhci_add; 170 171 /* 172 * We must request the IRQ after sdhci_add_host(), as the tasklet only 173 * gets setup in sdhci_add_host() and we oops. 174 */ 175 if (gpio_is_valid(priv->gpio_cd)) { 176 ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0); 177 if (ret) { 178 dev_err(&pdev->dev, "card detect irq request failed: %d\n", 179 ret); 180 goto err_request_cd; 181 } 182 mmc_gpiod_request_cd_irq(host->mmc); 183 } 184 185 return 0; 186 187err_request_cd: 188 sdhci_remove_host(host, 0); 189err_sdhci_add: 190 clk_disable_unprepare(pltfm_host->clk); 191err_clk_prepare: 192 sdhci_pltfm_free(pdev); 193 return ret; 194} 195 196#ifdef CONFIG_PM_SLEEP 197static int sdhci_sirf_suspend(struct device *dev) 198{ 199 struct sdhci_host *host = dev_get_drvdata(dev); 200 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 201 int ret; 202 203 ret = sdhci_suspend_host(host); 204 if (ret) 205 return ret; 206 207 clk_disable(pltfm_host->clk); 208 209 return 0; 210} 211 212static int sdhci_sirf_resume(struct device *dev) 213{ 214 struct sdhci_host *host = dev_get_drvdata(dev); 215 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 216 int ret; 217 218 ret = clk_enable(pltfm_host->clk); 219 if (ret) { 220 dev_dbg(dev, "Resume: Error enabling clock\n"); 221 return ret; 222 } 223 224 return sdhci_resume_host(host); 225} 226 227static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume); 228#endif 229 230static const struct of_device_id sdhci_sirf_of_match[] = { 231 { .compatible = "sirf,prima2-sdhc" }, 232 { } 233}; 234MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match); 235 236static struct platform_driver sdhci_sirf_driver = { 237 .driver = { 238 .name = "sdhci-sirf", 239 .of_match_table = sdhci_sirf_of_match, 240#ifdef CONFIG_PM_SLEEP 241 .pm = &sdhci_sirf_pm_ops, 242#endif 243 }, 244 .probe = sdhci_sirf_probe, 245 .remove = sdhci_pltfm_unregister, 246}; 247 248module_platform_driver(sdhci_sirf_driver); 249 250MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco"); 251MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); 252MODULE_LICENSE("GPL v2"); 253