1 /* 2 * Synopsys DesignWare Multimedia Card Interface driver 3 * 4 * Copyright (C) 2009 NXP Semiconductors 5 * Copyright (C) 2009, 2010 Imagination Technologies Ltd. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 */ 12 13 #include <linux/err.h> 14 #include <linux/interrupt.h> 15 #include <linux/module.h> 16 #include <linux/io.h> 17 #include <linux/irq.h> 18 #include <linux/platform_device.h> 19 #include <linux/slab.h> 20 #include <linux/mmc/host.h> 21 #include <linux/mmc/mmc.h> 22 #include <linux/mmc/dw_mmc.h> 23 #include <linux/of.h> 24 25 #include "dw_mmc.h" 26 27 int dw_mci_pltfm_register(struct platform_device *pdev, 28 const struct dw_mci_drv_data *drv_data) 29 { 30 struct dw_mci *host; 31 struct resource *regs; 32 int ret; 33 34 host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL); 35 if (!host) 36 return -ENOMEM; 37 38 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 39 if (!regs) 40 return -ENXIO; 41 42 host->irq = platform_get_irq(pdev, 0); 43 if (host->irq < 0) 44 return host->irq; 45 46 host->drv_data = drv_data; 47 host->dev = &pdev->dev; 48 host->irq_flags = 0; 49 host->pdata = pdev->dev.platform_data; 50 host->regs = devm_ioremap_resource(&pdev->dev, regs); 51 if (IS_ERR(host->regs)) 52 return PTR_ERR(host->regs); 53 54 if (drv_data && drv_data->init) { 55 ret = drv_data->init(host); 56 if (ret) 57 return ret; 58 } 59 60 platform_set_drvdata(pdev, host); 61 ret = dw_mci_probe(host); 62 return ret; 63 } 64 EXPORT_SYMBOL_GPL(dw_mci_pltfm_register); 65 66 static int dw_mci_pltfm_probe(struct platform_device *pdev) 67 { 68 return dw_mci_pltfm_register(pdev, NULL); 69 } 70 71 static int dw_mci_pltfm_remove(struct platform_device *pdev) 72 { 73 struct dw_mci *host = platform_get_drvdata(pdev); 74 75 platform_set_drvdata(pdev, NULL); 76 dw_mci_remove(host); 77 return 0; 78 } 79 EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove); 80 81 #ifdef CONFIG_PM_SLEEP 82 /* 83 * TODO: we should probably disable the clock to the card in the suspend path. 84 */ 85 static int dw_mci_pltfm_suspend(struct device *dev) 86 { 87 int ret; 88 struct dw_mci *host = dev_get_drvdata(dev); 89 90 ret = dw_mci_suspend(host); 91 if (ret) 92 return ret; 93 94 return 0; 95 } 96 97 static int dw_mci_pltfm_resume(struct device *dev) 98 { 99 int ret; 100 struct dw_mci *host = dev_get_drvdata(dev); 101 102 ret = dw_mci_resume(host); 103 if (ret) 104 return ret; 105 106 return 0; 107 } 108 #else 109 #define dw_mci_pltfm_suspend NULL 110 #define dw_mci_pltfm_resume NULL 111 #endif /* CONFIG_PM_SLEEP */ 112 113 SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume); 114 EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops); 115 116 static const struct of_device_id dw_mci_pltfm_match[] = { 117 { .compatible = "snps,dw-mshc", }, 118 {}, 119 }; 120 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); 121 122 static struct platform_driver dw_mci_pltfm_driver = { 123 .probe = dw_mci_pltfm_probe, 124 .remove = dw_mci_pltfm_remove, 125 .driver = { 126 .name = "dw_mmc", 127 .of_match_table = of_match_ptr(dw_mci_pltfm_match), 128 .pm = &dw_mci_pltfm_pmops, 129 }, 130 }; 131 132 module_platform_driver(dw_mci_pltfm_driver); 133 134 MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 135 MODULE_AUTHOR("NXP Semiconductor VietNam"); 136 MODULE_AUTHOR("Imagination Technologies Ltd"); 137 MODULE_LICENSE("GPL v2"); 138