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