]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/spi/dw_spi_mmio.c
NFSv4.1 reclaim complete must wait for completion
[mv-sheeva.git] / drivers / spi / dw_spi_mmio.c
1 /*
2  * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core
3  *
4  * Copyright (c) 2010, Octasic semiconductor.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  */
10
11 #include <linux/clk.h>
12 #include <linux/err.h>
13 #include <linux/interrupt.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/spi/dw_spi.h>
17 #include <linux/spi/spi.h>
18
19 #define DRIVER_NAME "dw_spi_mmio"
20
21 struct dw_spi_mmio {
22         struct dw_spi  dws;
23         struct clk     *clk;
24 };
25
26 static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
27 {
28         struct dw_spi_mmio *dwsmmio;
29         struct dw_spi *dws;
30         struct resource *mem, *ioarea;
31         int ret;
32
33         dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL);
34         if (!dwsmmio) {
35                 ret = -ENOMEM;
36                 goto err_end;
37         }
38
39         dws = &dwsmmio->dws;
40
41         /* Get basic io resource and map it */
42         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
43         if (!mem) {
44                 dev_err(&pdev->dev, "no mem resource?\n");
45                 ret = -EINVAL;
46                 goto err_kfree;
47         }
48
49         ioarea = request_mem_region(mem->start, resource_size(mem),
50                         pdev->name);
51         if (!ioarea) {
52                 dev_err(&pdev->dev, "SPI region already claimed\n");
53                 ret = -EBUSY;
54                 goto err_kfree;
55         }
56
57         dws->regs = ioremap_nocache(mem->start, resource_size(mem));
58         if (!dws->regs) {
59                 dev_err(&pdev->dev, "SPI region already mapped\n");
60                 ret = -ENOMEM;
61                 goto err_release_reg;
62         }
63
64         dws->irq = platform_get_irq(pdev, 0);
65         if (dws->irq < 0) {
66                 dev_err(&pdev->dev, "no irq resource?\n");
67                 ret = dws->irq; /* -ENXIO */
68                 goto err_unmap;
69         }
70
71         dwsmmio->clk = clk_get(&pdev->dev, NULL);
72         if (IS_ERR(dwsmmio->clk)) {
73                 ret = PTR_ERR(dwsmmio->clk);
74                 goto err_irq;
75         }
76         clk_enable(dwsmmio->clk);
77
78         dws->parent_dev = &pdev->dev;
79         dws->bus_num = 0;
80         dws->num_cs = 4;
81         dws->max_freq = clk_get_rate(dwsmmio->clk);
82
83         ret = dw_spi_add_host(dws);
84         if (ret)
85                 goto err_clk;
86
87         platform_set_drvdata(pdev, dwsmmio);
88         return 0;
89
90 err_clk:
91         clk_disable(dwsmmio->clk);
92         clk_put(dwsmmio->clk);
93         dwsmmio->clk = NULL;
94 err_irq:
95         free_irq(dws->irq, dws);
96 err_unmap:
97         iounmap(dws->regs);
98 err_release_reg:
99         release_mem_region(mem->start, resource_size(mem));
100 err_kfree:
101         kfree(dwsmmio);
102 err_end:
103         return ret;
104 }
105
106 static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
107 {
108         struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
109         struct resource *mem;
110
111         platform_set_drvdata(pdev, NULL);
112
113         clk_disable(dwsmmio->clk);
114         clk_put(dwsmmio->clk);
115         dwsmmio->clk = NULL;
116
117         free_irq(dwsmmio->dws.irq, &dwsmmio->dws);
118         dw_spi_remove_host(&dwsmmio->dws);
119         iounmap(dwsmmio->dws.regs);
120         kfree(dwsmmio);
121
122         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
123         release_mem_region(mem->start, resource_size(mem));
124         return 0;
125 }
126
127 static struct platform_driver dw_spi_mmio_driver = {
128         .remove         = __devexit_p(dw_spi_mmio_remove),
129         .driver         = {
130                 .name   = DRIVER_NAME,
131                 .owner  = THIS_MODULE,
132         },
133 };
134
135 static int __init dw_spi_mmio_init(void)
136 {
137         return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe);
138 }
139 module_init(dw_spi_mmio_init);
140
141 static void __exit dw_spi_mmio_exit(void)
142 {
143         platform_driver_unregister(&dw_spi_mmio_driver);
144 }
145 module_exit(dw_spi_mmio_exit);
146
147 MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
148 MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
149 MODULE_LICENSE("GPL v2");