aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-pxa/ssp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-pxa/ssp.c')
-rw-r--r--arch/arm/plat-pxa/ssp.c171
1 files changed, 114 insertions, 57 deletions
diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c
index 8e11e96eab5e..c83f27b6bdda 100644
--- a/arch/arm/plat-pxa/ssp.c
+++ b/arch/arm/plat-pxa/ssp.c
@@ -30,6 +30,8 @@
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <linux/spi/pxa2xx_spi.h> 31#include <linux/spi/pxa2xx_spi.h>
32#include <linux/io.h> 32#include <linux/io.h>
33#include <linux/of.h>
34#include <linux/of_device.h>
33 35
34#include <asm/irq.h> 36#include <asm/irq.h>
35#include <mach/hardware.h> 37#include <mach/hardware.h>
@@ -60,6 +62,30 @@ struct ssp_device *pxa_ssp_request(int port, const char *label)
60} 62}
61EXPORT_SYMBOL(pxa_ssp_request); 63EXPORT_SYMBOL(pxa_ssp_request);
62 64
65struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
66 const char *label)
67{
68 struct ssp_device *ssp = NULL;
69
70 mutex_lock(&ssp_lock);
71
72 list_for_each_entry(ssp, &ssp_list, node) {
73 if (ssp->of_node == of_node && ssp->use_count == 0) {
74 ssp->use_count++;
75 ssp->label = label;
76 break;
77 }
78 }
79
80 mutex_unlock(&ssp_lock);
81
82 if (&ssp->node == &ssp_list)
83 return NULL;
84
85 return ssp;
86}
87EXPORT_SYMBOL(pxa_ssp_request_of);
88
63void pxa_ssp_free(struct ssp_device *ssp) 89void pxa_ssp_free(struct ssp_device *ssp)
64{ 90{
65 mutex_lock(&ssp_lock); 91 mutex_lock(&ssp_lock);
@@ -72,96 +98,126 @@ void pxa_ssp_free(struct ssp_device *ssp)
72} 98}
73EXPORT_SYMBOL(pxa_ssp_free); 99EXPORT_SYMBOL(pxa_ssp_free);
74 100
101#ifdef CONFIG_OF
102static const struct of_device_id pxa_ssp_of_ids[] = {
103 { .compatible = "mrvl,pxa25x-ssp", .data = (void *) PXA25x_SSP },
104 { .compatible = "mvrl,pxa25x-nssp", .data = (void *) PXA25x_NSSP },
105 { .compatible = "mrvl,pxa27x-ssp", .data = (void *) PXA27x_SSP },
106 { .compatible = "mrvl,pxa3xx-ssp", .data = (void *) PXA3xx_SSP },
107 { .compatible = "mvrl,pxa168-ssp", .data = (void *) PXA168_SSP },
108 { .compatible = "mrvl,pxa910-ssp", .data = (void *) PXA910_SSP },
109 { .compatible = "mrvl,ce4100-ssp", .data = (void *) CE4100_SSP },
110 { .compatible = "mrvl,lpss-ssp", .data = (void *) LPSS_SSP },
111 { },
112};
113MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
114#endif
115
75static int pxa_ssp_probe(struct platform_device *pdev) 116static int pxa_ssp_probe(struct platform_device *pdev)
76{ 117{
77 const struct platform_device_id *id = platform_get_device_id(pdev);
78 struct resource *res; 118 struct resource *res;
79 struct ssp_device *ssp; 119 struct ssp_device *ssp;
80 int ret = 0; 120 struct device *dev = &pdev->dev;
81 121
82 ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL); 122 ssp = devm_kzalloc(dev, sizeof(struct ssp_device), GFP_KERNEL);
83 if (ssp == NULL) { 123 if (ssp == NULL)
84 dev_err(&pdev->dev, "failed to allocate memory");
85 return -ENOMEM; 124 return -ENOMEM;
86 }
87 ssp->pdev = pdev;
88 125
89 ssp->clk = clk_get(&pdev->dev, NULL); 126 ssp->pdev = pdev;
90 if (IS_ERR(ssp->clk)) {
91 ret = PTR_ERR(ssp->clk);
92 goto err_free;
93 }
94 127
95 res = platform_get_resource(pdev, IORESOURCE_DMA, 0); 128 ssp->clk = devm_clk_get(dev, NULL);
96 if (res == NULL) { 129 if (IS_ERR(ssp->clk))
97 dev_err(&pdev->dev, "no SSP RX DRCMR defined\n"); 130 return PTR_ERR(ssp->clk);
98 ret = -ENODEV; 131
99 goto err_free_clk; 132 if (dev->of_node) {
100 } 133 struct of_phandle_args dma_spec;
101 ssp->drcmr_rx = res->start; 134 struct device_node *np = dev->of_node;
135
136 /*
137 * FIXME: we should allocate the DMA channel from this
138 * context and pass the channel down to the ssp users.
139 * For now, we lookup the rx and tx indices manually
140 */
141
142 /* rx */
143 of_parse_phandle_with_args(np, "dmas", "#dma-cells",
144 0, &dma_spec);
145 ssp->drcmr_rx = dma_spec.args[0];
146 of_node_put(dma_spec.np);
147
148 /* tx */
149 of_parse_phandle_with_args(np, "dmas", "#dma-cells",
150 1, &dma_spec);
151 ssp->drcmr_tx = dma_spec.args[0];
152 of_node_put(dma_spec.np);
153 } else {
154 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
155 if (res == NULL) {
156 dev_err(dev, "no SSP RX DRCMR defined\n");
157 return -ENODEV;
158 }
159 ssp->drcmr_rx = res->start;
102 160
103 res = platform_get_resource(pdev, IORESOURCE_DMA, 1); 161 res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
104 if (res == NULL) { 162 if (res == NULL) {
105 dev_err(&pdev->dev, "no SSP TX DRCMR defined\n"); 163 dev_err(dev, "no SSP TX DRCMR defined\n");
106 ret = -ENODEV; 164 return -ENODEV;
107 goto err_free_clk; 165 }
166 ssp->drcmr_tx = res->start;
108 } 167 }
109 ssp->drcmr_tx = res->start;
110 168
111 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 169 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
112 if (res == NULL) { 170 if (res == NULL) {
113 dev_err(&pdev->dev, "no memory resource defined\n"); 171 dev_err(dev, "no memory resource defined\n");
114 ret = -ENODEV; 172 return -ENODEV;
115 goto err_free_clk;
116 } 173 }
117 174
118 res = request_mem_region(res->start, resource_size(res), 175 res = devm_request_mem_region(dev, res->start, resource_size(res),
119 pdev->name); 176 pdev->name);
120 if (res == NULL) { 177 if (res == NULL) {
121 dev_err(&pdev->dev, "failed to request memory resource\n"); 178 dev_err(dev, "failed to request memory resource\n");
122 ret = -EBUSY; 179 return -EBUSY;
123 goto err_free_clk;
124 } 180 }
125 181
126 ssp->phys_base = res->start; 182 ssp->phys_base = res->start;
127 183
128 ssp->mmio_base = ioremap(res->start, resource_size(res)); 184 ssp->mmio_base = devm_ioremap(dev, res->start, resource_size(res));
129 if (ssp->mmio_base == NULL) { 185 if (ssp->mmio_base == NULL) {
130 dev_err(&pdev->dev, "failed to ioremap() registers\n"); 186 dev_err(dev, "failed to ioremap() registers\n");
131 ret = -ENODEV; 187 return -ENODEV;
132 goto err_free_mem;
133 } 188 }
134 189
135 ssp->irq = platform_get_irq(pdev, 0); 190 ssp->irq = platform_get_irq(pdev, 0);
136 if (ssp->irq < 0) { 191 if (ssp->irq < 0) {
137 dev_err(&pdev->dev, "no IRQ resource defined\n"); 192 dev_err(dev, "no IRQ resource defined\n");
138 ret = -ENODEV; 193 return -ENODEV;
139 goto err_free_io; 194 }
195
196 if (dev->of_node) {
197 const struct of_device_id *id =
198 of_match_device(of_match_ptr(pxa_ssp_of_ids), dev);
199 ssp->type = (int) id->data;
200 } else {
201 const struct platform_device_id *id =
202 platform_get_device_id(pdev);
203 ssp->type = (int) id->driver_data;
204
205 /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
206 * starts from 0, do a translation here
207 */
208 ssp->port_id = pdev->id + 1;
140 } 209 }
141 210
142 /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
143 * starts from 0, do a translation here
144 */
145 ssp->port_id = pdev->id + 1;
146 ssp->use_count = 0; 211 ssp->use_count = 0;
147 ssp->type = (int)id->driver_data; 212 ssp->of_node = dev->of_node;
148 213
149 mutex_lock(&ssp_lock); 214 mutex_lock(&ssp_lock);
150 list_add(&ssp->node, &ssp_list); 215 list_add(&ssp->node, &ssp_list);
151 mutex_unlock(&ssp_lock); 216 mutex_unlock(&ssp_lock);
152 217
153 platform_set_drvdata(pdev, ssp); 218 platform_set_drvdata(pdev, ssp);
154 return 0;
155 219
156err_free_io: 220 return 0;
157 iounmap(ssp->mmio_base);
158err_free_mem:
159 release_mem_region(res->start, resource_size(res));
160err_free_clk:
161 clk_put(ssp->clk);
162err_free:
163 kfree(ssp);
164 return ret;
165} 221}
166 222
167static int pxa_ssp_remove(struct platform_device *pdev) 223static int pxa_ssp_remove(struct platform_device *pdev)
@@ -201,8 +257,9 @@ static struct platform_driver pxa_ssp_driver = {
201 .probe = pxa_ssp_probe, 257 .probe = pxa_ssp_probe,
202 .remove = pxa_ssp_remove, 258 .remove = pxa_ssp_remove,
203 .driver = { 259 .driver = {
204 .owner = THIS_MODULE, 260 .owner = THIS_MODULE,
205 .name = "pxa2xx-ssp", 261 .name = "pxa2xx-ssp",
262 .of_match_table = of_match_ptr(pxa_ssp_of_ids),
206 }, 263 },
207 .id_table = ssp_id_table, 264 .id_table = ssp_id_table,
208}; 265};