1 /* 2 * drivers/mmc/host/sdhci-spear.c 3 * 4 * Support of SDHCI platform devices for spear soc family 5 * 6 * Copyright (C) 2010 ST Microelectronics 7 * Viresh Kumar <viresh.linux@gmail.com> 8 * 9 * Inspired by sdhci-pltfm.c 10 * 11 * This file is licensed under the terms of the GNU General Public 12 * License version 2. This program is licensed "as is" without any 13 * warranty of any kind, whether express or implied. 14 */ 15 16 #include <linux/clk.h> 17 #include <linux/delay.h> 18 #include <linux/gpio.h> 19 #include <linux/highmem.h> 20 #include <linux/module.h> 21 #include <linux/interrupt.h> 22 #include <linux/irq.h> 23 #include <linux/of.h> 24 #include <linux/of_gpio.h> 25 #include <linux/platform_device.h> 26 #include <linux/pm.h> 27 #include <linux/slab.h> 28 #include <linux/mmc/host.h> 29 #include <linux/mmc/sdhci-spear.h> 30 #include <linux/io.h> 31 #include "sdhci.h" 32 33 struct spear_sdhci { 34 struct clk *clk; 35 struct sdhci_plat_data *data; 36 }; 37 38 /* sdhci ops */ 39 static const struct sdhci_ops sdhci_pltfm_ops = { 40 /* Nothing to do for now. */ 41 }; 42 43 /* gpio card detection interrupt handler */ 44 static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) 45 { 46 struct platform_device *pdev = dev_id; 47 struct sdhci_host *host = platform_get_drvdata(pdev); 48 struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); 49 unsigned long gpio_irq_type; 50 int val; 51 52 val = gpio_get_value(sdhci->data->card_int_gpio); 53 54 /* val == 1 -> card removed, val == 0 -> card inserted */ 55 /* if card removed - set irq for low level, else vice versa */ 56 gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; 57 irq_set_irq_type(irq, gpio_irq_type); 58 59 if (sdhci->data->card_power_gpio >= 0) { 60 if (!sdhci->data->power_always_enb) { 61 /* if card inserted, give power, otherwise remove it */ 62 val = sdhci->data->power_active_high ? !val : val ; 63 gpio_set_value(sdhci->data->card_power_gpio, val); 64 } 65 } 66 67 /* inform sdhci driver about card insertion/removal */ 68 tasklet_schedule(&host->card_tasklet); 69 70 return IRQ_HANDLED; 71 } 72 73 #ifdef CONFIG_OF 74 static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) 75 { 76 struct device_node *np = pdev->dev.of_node; 77 struct sdhci_plat_data *pdata = NULL; 78 int cd_gpio; 79 80 cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); 81 if (!gpio_is_valid(cd_gpio)) 82 cd_gpio = -1; 83 84 /* If pdata is required */ 85 if (cd_gpio != -1) { 86 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 87 if (!pdata) 88 dev_err(&pdev->dev, "DT: kzalloc failed\n"); 89 else 90 pdata->card_int_gpio = cd_gpio; 91 } 92 93 return pdata; 94 } 95 #else 96 static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) 97 { 98 return ERR_PTR(-ENOSYS); 99 } 100 #endif 101 102 static int sdhci_probe(struct platform_device *pdev) 103 { 104 struct device_node *np = pdev->dev.of_node; 105 struct sdhci_host *host; 106 struct resource *iomem; 107 struct spear_sdhci *sdhci; 108 int ret; 109 110 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 111 if (!iomem) { 112 ret = -ENOMEM; 113 dev_dbg(&pdev->dev, "memory resource not defined\n"); 114 goto err; 115 } 116 117 if (!devm_request_mem_region(&pdev->dev, iomem->start, 118 resource_size(iomem), "spear-sdhci")) { 119 ret = -EBUSY; 120 dev_dbg(&pdev->dev, "cannot request region\n"); 121 goto err; 122 } 123 124 sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL); 125 if (!sdhci) { 126 ret = -ENOMEM; 127 dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); 128 goto err; 129 } 130 131 /* clk enable */ 132 sdhci->clk = clk_get(&pdev->dev, NULL); 133 if (IS_ERR(sdhci->clk)) { 134 ret = PTR_ERR(sdhci->clk); 135 dev_dbg(&pdev->dev, "Error getting clock\n"); 136 goto err; 137 } 138 139 ret = clk_prepare_enable(sdhci->clk); 140 if (ret) { 141 dev_dbg(&pdev->dev, "Error enabling clock\n"); 142 goto put_clk; 143 } 144 145 ret = clk_set_rate(sdhci->clk, 50000000); 146 if (ret) 147 dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n", 148 clk_get_rate(sdhci->clk)); 149 150 if (np) { 151 sdhci->data = sdhci_probe_config_dt(pdev); 152 if (IS_ERR(sdhci->data)) { 153 dev_err(&pdev->dev, "DT: Failed to get pdata\n"); 154 return -ENODEV; 155 } 156 } else { 157 sdhci->data = dev_get_platdata(&pdev->dev); 158 } 159 160 pdev->dev.platform_data = sdhci; 161 162 if (pdev->dev.parent) 163 host = sdhci_alloc_host(pdev->dev.parent, 0); 164 else 165 host = sdhci_alloc_host(&pdev->dev, 0); 166 167 if (IS_ERR(host)) { 168 ret = PTR_ERR(host); 169 dev_dbg(&pdev->dev, "error allocating host\n"); 170 goto disable_clk; 171 } 172 173 host->hw_name = "sdhci"; 174 host->ops = &sdhci_pltfm_ops; 175 host->irq = platform_get_irq(pdev, 0); 176 host->quirks = SDHCI_QUIRK_BROKEN_ADMA; 177 178 host->ioaddr = devm_ioremap(&pdev->dev, iomem->start, 179 resource_size(iomem)); 180 if (!host->ioaddr) { 181 ret = -ENOMEM; 182 dev_dbg(&pdev->dev, "failed to remap registers\n"); 183 goto free_host; 184 } 185 186 ret = sdhci_add_host(host); 187 if (ret) { 188 dev_dbg(&pdev->dev, "error adding host\n"); 189 goto free_host; 190 } 191 192 platform_set_drvdata(pdev, host); 193 194 /* 195 * It is optional to use GPIOs for sdhci Power control & sdhci card 196 * interrupt detection. If sdhci->data is NULL, then use original sdhci 197 * lines otherwise GPIO lines. 198 * If GPIO is selected for power control, then power should be disabled 199 * after card removal and should be enabled when card insertion 200 * interrupt occurs 201 */ 202 if (!sdhci->data) 203 return 0; 204 205 if (sdhci->data->card_power_gpio >= 0) { 206 int val = 0; 207 208 ret = devm_gpio_request(&pdev->dev, 209 sdhci->data->card_power_gpio, "sdhci"); 210 if (ret < 0) { 211 dev_dbg(&pdev->dev, "gpio request fail: %d\n", 212 sdhci->data->card_power_gpio); 213 goto set_drvdata; 214 } 215 216 if (sdhci->data->power_always_enb) 217 val = sdhci->data->power_active_high; 218 else 219 val = !sdhci->data->power_active_high; 220 221 ret = gpio_direction_output(sdhci->data->card_power_gpio, val); 222 if (ret) { 223 dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", 224 sdhci->data->card_power_gpio); 225 goto set_drvdata; 226 } 227 } 228 229 if (sdhci->data->card_int_gpio >= 0) { 230 ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio, 231 "sdhci"); 232 if (ret < 0) { 233 dev_dbg(&pdev->dev, "gpio request fail: %d\n", 234 sdhci->data->card_int_gpio); 235 goto set_drvdata; 236 } 237 238 ret = gpio_direction_input(sdhci->data->card_int_gpio); 239 if (ret) { 240 dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", 241 sdhci->data->card_int_gpio); 242 goto set_drvdata; 243 } 244 ret = devm_request_irq(&pdev->dev, 245 gpio_to_irq(sdhci->data->card_int_gpio), 246 sdhci_gpio_irq, IRQF_TRIGGER_LOW, 247 mmc_hostname(host->mmc), pdev); 248 if (ret) { 249 dev_dbg(&pdev->dev, "gpio request irq fail: %d\n", 250 sdhci->data->card_int_gpio); 251 goto set_drvdata; 252 } 253 254 } 255 256 return 0; 257 258 set_drvdata: 259 sdhci_remove_host(host, 1); 260 free_host: 261 sdhci_free_host(host); 262 disable_clk: 263 clk_disable_unprepare(sdhci->clk); 264 put_clk: 265 clk_put(sdhci->clk); 266 err: 267 dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); 268 return ret; 269 } 270 271 static int sdhci_remove(struct platform_device *pdev) 272 { 273 struct sdhci_host *host = platform_get_drvdata(pdev); 274 struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); 275 int dead = 0; 276 u32 scratch; 277 278 scratch = readl(host->ioaddr + SDHCI_INT_STATUS); 279 if (scratch == (u32)-1) 280 dead = 1; 281 282 sdhci_remove_host(host, dead); 283 sdhci_free_host(host); 284 clk_disable_unprepare(sdhci->clk); 285 clk_put(sdhci->clk); 286 287 return 0; 288 } 289 290 #ifdef CONFIG_PM_SLEEP 291 static int sdhci_suspend(struct device *dev) 292 { 293 struct sdhci_host *host = dev_get_drvdata(dev); 294 struct spear_sdhci *sdhci = dev_get_platdata(dev); 295 int ret; 296 297 ret = sdhci_suspend_host(host); 298 if (!ret) 299 clk_disable(sdhci->clk); 300 301 return ret; 302 } 303 304 static int sdhci_resume(struct device *dev) 305 { 306 struct sdhci_host *host = dev_get_drvdata(dev); 307 struct spear_sdhci *sdhci = dev_get_platdata(dev); 308 int ret; 309 310 ret = clk_enable(sdhci->clk); 311 if (ret) { 312 dev_dbg(dev, "Resume: Error enabling clock\n"); 313 return ret; 314 } 315 316 return sdhci_resume_host(host); 317 } 318 #endif 319 320 static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume); 321 322 #ifdef CONFIG_OF 323 static const struct of_device_id sdhci_spear_id_table[] = { 324 { .compatible = "st,spear300-sdhci" }, 325 {} 326 }; 327 MODULE_DEVICE_TABLE(of, sdhci_spear_id_table); 328 #endif 329 330 static struct platform_driver sdhci_driver = { 331 .driver = { 332 .name = "sdhci", 333 .owner = THIS_MODULE, 334 .pm = &sdhci_pm_ops, 335 .of_match_table = of_match_ptr(sdhci_spear_id_table), 336 }, 337 .probe = sdhci_probe, 338 .remove = sdhci_remove, 339 }; 340 341 module_platform_driver(sdhci_driver); 342 343 MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); 344 MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>"); 345 MODULE_LICENSE("GPL v2"); 346