Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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