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 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 * __devinit 75 sdhci_probe_config_dt(struct platform_device *pdev) 76 { 77 struct device_node *np = pdev->dev.of_node; 78 struct sdhci_plat_data *pdata = NULL; 79 int cd_gpio; 80 81 cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); 82 if (!gpio_is_valid(cd_gpio)) 83 cd_gpio = -1; 84 85 /* If pdata is required */ 86 if (cd_gpio != -1) { 87 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 88 if (!pdata) { 89 dev_err(&pdev->dev, "DT: kzalloc failed\n"); 90 return ERR_PTR(-ENOMEM); 91 } 92 } 93 94 pdata->card_int_gpio = cd_gpio; 95 96 return pdata; 97 } 98 #else 99 static struct sdhci_plat_data * __devinit 100 sdhci_probe_config_dt(struct platform_device *pdev) 101 { 102 return ERR_PTR(-ENOSYS); 103 } 104 #endif 105 106 static int __devinit sdhci_probe(struct platform_device *pdev) 107 { 108 struct device_node *np = pdev->dev.of_node; 109 struct sdhci_host *host; 110 struct resource *iomem; 111 struct spear_sdhci *sdhci; 112 int ret; 113 114 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 115 if (!iomem) { 116 ret = -ENOMEM; 117 dev_dbg(&pdev->dev, "memory resource not defined\n"); 118 goto err; 119 } 120 121 if (!devm_request_mem_region(&pdev->dev, iomem->start, 122 resource_size(iomem), "spear-sdhci")) { 123 ret = -EBUSY; 124 dev_dbg(&pdev->dev, "cannot request region\n"); 125 goto err; 126 } 127 128 sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL); 129 if (!sdhci) { 130 ret = -ENOMEM; 131 dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); 132 goto err; 133 } 134 135 /* clk enable */ 136 sdhci->clk = clk_get(&pdev->dev, NULL); 137 if (IS_ERR(sdhci->clk)) { 138 ret = PTR_ERR(sdhci->clk); 139 dev_dbg(&pdev->dev, "Error getting clock\n"); 140 goto err; 141 } 142 143 ret = clk_prepare_enable(sdhci->clk); 144 if (ret) { 145 dev_dbg(&pdev->dev, "Error enabling clock\n"); 146 goto put_clk; 147 } 148 149 if (np) { 150 sdhci->data = sdhci_probe_config_dt(pdev); 151 if (IS_ERR(sdhci->data)) { 152 dev_err(&pdev->dev, "DT: Failed to get pdata\n"); 153 return -ENODEV; 154 } 155 } else { 156 sdhci->data = dev_get_platdata(&pdev->dev); 157 } 158 159 pdev->dev.platform_data = sdhci; 160 161 if (pdev->dev.parent) 162 host = sdhci_alloc_host(pdev->dev.parent, 0); 163 else 164 host = sdhci_alloc_host(&pdev->dev, 0); 165 166 if (IS_ERR(host)) { 167 ret = PTR_ERR(host); 168 dev_dbg(&pdev->dev, "error allocating host\n"); 169 goto disable_clk; 170 } 171 172 host->hw_name = "sdhci"; 173 host->ops = &sdhci_pltfm_ops; 174 host->irq = platform_get_irq(pdev, 0); 175 host->quirks = SDHCI_QUIRK_BROKEN_ADMA; 176 177 host->ioaddr = devm_ioremap(&pdev->dev, iomem->start, 178 resource_size(iomem)); 179 if (!host->ioaddr) { 180 ret = -ENOMEM; 181 dev_dbg(&pdev->dev, "failed to remap registers\n"); 182 goto free_host; 183 } 184 185 ret = sdhci_add_host(host); 186 if (ret) { 187 dev_dbg(&pdev->dev, "error adding host\n"); 188 goto free_host; 189 } 190 191 platform_set_drvdata(pdev, host); 192 193 /* 194 * It is optional to use GPIOs for sdhci Power control & sdhci card 195 * interrupt detection. If sdhci->data is NULL, then use original sdhci 196 * lines otherwise GPIO lines. 197 * If GPIO is selected for power control, then power should be disabled 198 * after card removal and should be enabled when card insertion 199 * interrupt occurs 200 */ 201 if (!sdhci->data) 202 return 0; 203 204 if (sdhci->data->card_power_gpio >= 0) { 205 int val = 0; 206 207 ret = devm_gpio_request(&pdev->dev, 208 sdhci->data->card_power_gpio, "sdhci"); 209 if (ret < 0) { 210 dev_dbg(&pdev->dev, "gpio request fail: %d\n", 211 sdhci->data->card_power_gpio); 212 goto set_drvdata; 213 } 214 215 if (sdhci->data->power_always_enb) 216 val = sdhci->data->power_active_high; 217 else 218 val = !sdhci->data->power_active_high; 219 220 ret = gpio_direction_output(sdhci->data->card_power_gpio, val); 221 if (ret) { 222 dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", 223 sdhci->data->card_power_gpio); 224 goto set_drvdata; 225 } 226 } 227 228 if (sdhci->data->card_int_gpio >= 0) { 229 ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio, 230 "sdhci"); 231 if (ret < 0) { 232 dev_dbg(&pdev->dev, "gpio request fail: %d\n", 233 sdhci->data->card_int_gpio); 234 goto set_drvdata; 235 } 236 237 ret = gpio_direction_input(sdhci->data->card_int_gpio); 238 if (ret) { 239 dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", 240 sdhci->data->card_int_gpio); 241 goto set_drvdata; 242 } 243 ret = devm_request_irq(&pdev->dev, 244 gpio_to_irq(sdhci->data->card_int_gpio), 245 sdhci_gpio_irq, IRQF_TRIGGER_LOW, 246 mmc_hostname(host->mmc), pdev); 247 if (ret) { 248 dev_dbg(&pdev->dev, "gpio request irq fail: %d\n", 249 sdhci->data->card_int_gpio); 250 goto set_drvdata; 251 } 252 253 } 254 255 return 0; 256 257 set_drvdata: 258 platform_set_drvdata(pdev, NULL); 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 __devexit 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 platform_set_drvdata(pdev, NULL); 279 scratch = readl(host->ioaddr + SDHCI_INT_STATUS); 280 if (scratch == (u32)-1) 281 dead = 1; 282 283 sdhci_remove_host(host, dead); 284 sdhci_free_host(host); 285 clk_disable_unprepare(sdhci->clk); 286 clk_put(sdhci->clk); 287 288 return 0; 289 } 290 291 #ifdef CONFIG_PM 292 static int sdhci_suspend(struct device *dev) 293 { 294 struct sdhci_host *host = dev_get_drvdata(dev); 295 struct spear_sdhci *sdhci = dev_get_platdata(dev); 296 int ret; 297 298 ret = sdhci_suspend_host(host); 299 if (!ret) 300 clk_disable_unprepare(sdhci->clk); 301 302 return ret; 303 } 304 305 static int sdhci_resume(struct device *dev) 306 { 307 struct sdhci_host *host = dev_get_drvdata(dev); 308 struct spear_sdhci *sdhci = dev_get_platdata(dev); 309 int ret; 310 311 ret = clk_prepare_enable(sdhci->clk); 312 if (ret) { 313 dev_dbg(dev, "Resume: Error enabling clock\n"); 314 return ret; 315 } 316 317 return sdhci_resume_host(host); 318 } 319 #endif 320 321 static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume); 322 323 #ifdef CONFIG_OF 324 static const struct of_device_id sdhci_spear_id_table[] = { 325 { .compatible = "st,spear300-sdhci" }, 326 {} 327 }; 328 MODULE_DEVICE_TABLE(of, sdhci_spear_id_table); 329 #endif 330 331 static struct platform_driver sdhci_driver = { 332 .driver = { 333 .name = "sdhci", 334 .owner = THIS_MODULE, 335 .pm = &sdhci_pm_ops, 336 .of_match_table = of_match_ptr(sdhci_spear_id_table), 337 }, 338 .probe = sdhci_probe, 339 .remove = __devexit_p(sdhci_remove), 340 }; 341 342 module_platform_driver(sdhci_driver); 343 344 MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); 345 MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>"); 346 MODULE_LICENSE("GPL v2"); 347