blob: 867977f698418e62783dcbf40e7197a60301b7f1 [file] [log] [blame]
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +05301/*
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/interrupt.h>
14#include <linux/module.h>
15#include <linux/io.h>
16#include <linux/irq.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <linux/mmc/host.h>
20#include <linux/mmc/mmc.h>
21#include <linux/mmc/dw_mmc.h>
Thomas Abrahamc91eab42012-09-17 18:16:40 +000022#include <linux/of.h>
23
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053024#include "dw_mmc.h"
25
Thomas Abraham800d78b2012-09-17 18:16:42 +000026int dw_mci_pltfm_register(struct platform_device *pdev,
Arnd Bergmann8e2b36e2012-11-06 22:55:31 +010027 const struct dw_mci_drv_data *drv_data)
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053028{
29 struct dw_mci *host;
30 struct resource *regs;
31 int ret;
32
Thomas Abrahambb8bdc72012-09-17 18:16:36 +000033 host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053034 if (!host)
35 return -ENOMEM;
36
37 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Thomas Abrahambb8bdc72012-09-17 18:16:36 +000038 if (!regs)
39 return -ENXIO;
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053040
41 host->irq = platform_get_irq(pdev, 0);
Thomas Abrahambb8bdc72012-09-17 18:16:36 +000042 if (host->irq < 0)
43 return host->irq;
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053044
Thomas Abraham800d78b2012-09-17 18:16:42 +000045 host->drv_data = drv_data;
Thomas Abraham4a909202012-09-17 18:16:35 +000046 host->dev = &pdev->dev;
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053047 host->irq_flags = 0;
48 host->pdata = pdev->dev.platform_data;
Thomas Abrahambb8bdc72012-09-17 18:16:36 +000049 host->regs = devm_request_and_ioremap(&pdev->dev, regs);
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053050 if (!host->regs)
Thomas Abrahambb8bdc72012-09-17 18:16:36 +000051 return -ENOMEM;
52
James Hogancb27a842012-10-16 09:43:08 +010053 if (drv_data && drv_data->init) {
54 ret = drv_data->init(host);
Thomas Abraham800d78b2012-09-17 18:16:42 +000055 if (ret)
56 return ret;
57 }
58
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053059 platform_set_drvdata(pdev, host);
60 ret = dw_mci_probe(host);
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053061 return ret;
62}
Thomas Abraham17403f22012-09-17 18:16:41 +000063EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
64
Bill Pembertonc3be1ef2012-11-19 13:23:06 -050065static int dw_mci_pltfm_probe(struct platform_device *pdev)
Thomas Abraham17403f22012-09-17 18:16:41 +000066{
Thomas Abraham800d78b2012-09-17 18:16:42 +000067 return dw_mci_pltfm_register(pdev, NULL);
Thomas Abraham17403f22012-09-17 18:16:41 +000068}
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053069
Jaehoon Chung36c179a2012-08-23 20:31:48 +090070static int __devexit dw_mci_pltfm_remove(struct platform_device *pdev)
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053071{
72 struct dw_mci *host = platform_get_drvdata(pdev);
73
74 platform_set_drvdata(pdev, NULL);
75 dw_mci_remove(host);
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053076 return 0;
77}
Thomas Abraham17403f22012-09-17 18:16:41 +000078EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +053079
80#ifdef CONFIG_PM_SLEEP
81/*
82 * TODO: we should probably disable the clock to the card in the suspend path.
83 */
84static int dw_mci_pltfm_suspend(struct device *dev)
85{
86 int ret;
87 struct dw_mci *host = dev_get_drvdata(dev);
88
89 ret = dw_mci_suspend(host);
90 if (ret)
91 return ret;
92
93 return 0;
94}
95
96static int dw_mci_pltfm_resume(struct device *dev)
97{
98 int ret;
99 struct dw_mci *host = dev_get_drvdata(dev);
100
101 ret = dw_mci_resume(host);
102 if (ret)
103 return ret;
104
105 return 0;
106}
107#else
108#define dw_mci_pltfm_suspend NULL
109#define dw_mci_pltfm_resume NULL
110#endif /* CONFIG_PM_SLEEP */
111
Thomas Abraham17403f22012-09-17 18:16:41 +0000112SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
113EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +0530114
Thomas Abrahamc91eab42012-09-17 18:16:40 +0000115static const struct of_device_id dw_mci_pltfm_match[] = {
116 { .compatible = "snps,dw-mshc", },
117 {},
118};
119MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
120
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +0530121static struct platform_driver dw_mci_pltfm_driver = {
122 .remove = __exit_p(dw_mci_pltfm_remove),
123 .driver = {
124 .name = "dw_mmc",
Thomas Abrahamc91eab42012-09-17 18:16:40 +0000125 .of_match_table = of_match_ptr(dw_mci_pltfm_match),
Shashidhar Hiremath62ca8032012-01-13 16:04:57 +0530126 .pm = &dw_mci_pltfm_pmops,
127 },
128};
129
130static int __init dw_mci_init(void)
131{
132 return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
133}
134
135static void __exit dw_mci_exit(void)
136{
137 platform_driver_unregister(&dw_mci_pltfm_driver);
138}
139
140module_init(dw_mci_init);
141module_exit(dw_mci_exit);
142
143MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
144MODULE_AUTHOR("NXP Semiconductor VietNam");
145MODULE_AUTHOR("Imagination Technologies Ltd");
146MODULE_LICENSE("GPL v2");