aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2010-11-24 04:17:14 -0500
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2010-12-01 07:48:30 -0500
commitd6ea3df0d470fb9260db93883f97764cf9f0e562 (patch)
tree277838ea93d6dc0c7d2a05be757dfa1b8bedb619 /drivers
parent8348c259dd6a6019a8fa01b0a3443409480f7b9d (diff)
spi/pxa2xx: Add CE4100 support
Sodaville's SPI controller is very much the same as in PXA25x. The difference: - The RX/TX FIFO is only 4 words deep instead of 16 - No DMA support - The SPI controller offers a CS functionality Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/Kconfig13
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/pxa2xx_spi.c1
-rw-r--r--drivers/spi/pxa2xx_spi_pci.c201
4 files changed, 210 insertions, 6 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 78f9fd02c1b2..537759011d1d 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -267,12 +267,15 @@ config SPI_PPC4xx
267 267
268config SPI_PXA2XX 268config SPI_PXA2XX
269 tristate "PXA2xx SSP SPI master" 269 tristate "PXA2xx SSP SPI master"
270 depends on ARCH_PXA && EXPERIMENTAL 270 depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
271 select PXA_SSP 271 select PXA_SSP if ARCH_PXA
272 help 272 help
273 This enables using a PXA2xx SSP port as a SPI master controller. 273 This enables using a PXA2xx or Sodaville SSP port as a SPI master
274 The driver can be configured to use any SSP port and additional 274 controller. The driver can be configured to use any SSP port and
275 documentation can be found a Documentation/spi/pxa2xx. 275 additional documentation can be found a Documentation/spi/pxa2xx.
276
277config SPI_PXA2XX_PCI
278 def_bool SPI_PXA2XX && X86_32 && PCI
276 279
277config SPI_S3C24XX 280config SPI_S3C24XX
278 tristate "Samsung S3C24XX series SPI" 281 tristate "Samsung S3C24XX series SPI"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8bc1a5abac1f..bdc4c400fd71 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
24obj-$(CONFIG_SPI_IMX) += spi_imx.o 24obj-$(CONFIG_SPI_IMX) += spi_imx.o
25obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o 25obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
26obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o 26obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
27obj-$(CONFIG_SPI_PXA2XX_PCI) += pxa2xx_spi_pci.o
27obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o 28obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
28obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o 29obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
29obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o 30obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 98d9c8b09182..ed212c2583ab 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -28,7 +28,6 @@
28#include <linux/spi/spi.h> 28#include <linux/spi/spi.h>
29#include <linux/workqueue.h> 29#include <linux/workqueue.h>
30#include <linux/delay.h> 30#include <linux/delay.h>
31#include <linux/clk.h>
32#include <linux/gpio.h> 31#include <linux/gpio.h>
33#include <linux/slab.h> 32#include <linux/slab.h>
34 33
diff --git a/drivers/spi/pxa2xx_spi_pci.c b/drivers/spi/pxa2xx_spi_pci.c
new file mode 100644
index 000000000000..351d8a375b57
--- /dev/null
+++ b/drivers/spi/pxa2xx_spi_pci.c
@@ -0,0 +1,201 @@
1/*
2 * CE4100's SPI device is more or less the same one as found on PXA
3 *
4 */
5#include <linux/pci.h>
6#include <linux/platform_device.h>
7#include <linux/of_device.h>
8#include <linux/spi/pxa2xx_spi.h>
9
10struct awesome_struct {
11 struct ssp_device ssp;
12 struct platform_device spi_pdev;
13 struct pxa2xx_spi_master spi_pdata;
14};
15
16static DEFINE_MUTEX(ssp_lock);
17static LIST_HEAD(ssp_list);
18
19struct ssp_device *pxa_ssp_request(int port, const char *label)
20{
21 struct ssp_device *ssp = NULL;
22
23 mutex_lock(&ssp_lock);
24
25 list_for_each_entry(ssp, &ssp_list, node) {
26 if (ssp->port_id == port && ssp->use_count == 0) {
27 ssp->use_count++;
28 ssp->label = label;
29 break;
30 }
31 }
32
33 mutex_unlock(&ssp_lock);
34
35 if (&ssp->node == &ssp_list)
36 return NULL;
37
38 return ssp;
39}
40EXPORT_SYMBOL_GPL(pxa_ssp_request);
41
42void pxa_ssp_free(struct ssp_device *ssp)
43{
44 mutex_lock(&ssp_lock);
45 if (ssp->use_count) {
46 ssp->use_count--;
47 ssp->label = NULL;
48 } else
49 dev_err(&ssp->pdev->dev, "device already free\n");
50 mutex_unlock(&ssp_lock);
51}
52EXPORT_SYMBOL_GPL(pxa_ssp_free);
53
54static void plat_dev_release(struct device *dev)
55{
56 struct awesome_struct *as = container_of(dev,
57 struct awesome_struct, spi_pdev.dev);
58
59 of_device_node_put(&as->spi_pdev.dev);
60}
61
62static int __devinit ce4100_spi_probe(struct pci_dev *dev,
63 const struct pci_device_id *ent)
64{
65 int ret;
66 resource_size_t phys_beg;
67 resource_size_t phys_len;
68 struct awesome_struct *spi_info;
69 struct platform_device *pdev;
70 struct pxa2xx_spi_master *spi_pdata;
71 struct ssp_device *ssp;
72
73 ret = pci_enable_device(dev);
74 if (ret)
75 return ret;
76
77 phys_beg = pci_resource_start(dev, 0);
78 phys_len = pci_resource_len(dev, 0);
79
80 if (!request_mem_region(phys_beg, phys_len,
81 "CE4100 SPI")) {
82 dev_err(&dev->dev, "Can't request register space.\n");
83 ret = -EBUSY;
84 return ret;
85 }
86
87 spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
88 if (!spi_info) {
89 ret = -ENOMEM;
90 goto err_kz;
91 }
92 ssp = &spi_info->ssp;
93 pdev = &spi_info->spi_pdev;
94 spi_pdata = &spi_info->spi_pdata;
95
96 pdev->name = "pxa2xx-spi";
97 pdev->id = dev->devfn;
98 pdev->dev.parent = &dev->dev;
99 pdev->dev.platform_data = &spi_info->spi_pdata;
100
101#ifdef CONFIG_OF
102 pdev->dev.of_node = dev->dev.of_node;
103#endif
104 pdev->dev.release = plat_dev_release;
105
106 spi_pdata->num_chipselect = dev->devfn;
107
108 ssp->phys_base = pci_resource_start(dev, 0);
109 ssp->mmio_base = ioremap(phys_beg, phys_len);
110 if (!ssp->mmio_base) {
111 dev_err(&pdev->dev, "failed to ioremap() registers\n");
112 ret = -EIO;
113 goto err_remap;
114 }
115 ssp->irq = dev->irq;
116 ssp->port_id = pdev->id;
117 ssp->type = PXA25x_SSP;
118
119 mutex_lock(&ssp_lock);
120 list_add(&ssp->node, &ssp_list);
121 mutex_unlock(&ssp_lock);
122
123 pci_set_drvdata(dev, spi_info);
124
125 ret = platform_device_register(pdev);
126 if (ret)
127 goto err_dev_add;
128
129 return ret;
130
131err_dev_add:
132 pci_set_drvdata(dev, NULL);
133 mutex_lock(&ssp_lock);
134 list_del(&ssp->node);
135 mutex_unlock(&ssp_lock);
136 iounmap(ssp->mmio_base);
137
138err_remap:
139 kfree(spi_info);
140
141err_kz:
142 release_mem_region(phys_beg, phys_len);
143
144 return ret;
145}
146
147static void __devexit ce4100_spi_remove(struct pci_dev *dev)
148{
149 struct awesome_struct *spi_info;
150 struct platform_device *pdev;
151 struct ssp_device *ssp;
152
153 spi_info = pci_get_drvdata(dev);
154
155 ssp = &spi_info->ssp;
156 pdev = &spi_info->spi_pdev;
157
158 platform_device_unregister(pdev);
159
160 iounmap(ssp->mmio_base);
161 release_mem_region(pci_resource_start(dev, 0),
162 pci_resource_len(dev, 0));
163
164 mutex_lock(&ssp_lock);
165 list_del(&ssp->node);
166 mutex_unlock(&ssp_lock);
167
168 pci_set_drvdata(dev, NULL);
169 pci_disable_device(dev);
170 kfree(spi_info);
171}
172
173static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
174
175 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
176 { },
177};
178MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);
179
180static struct pci_driver ce4100_spi_driver = {
181 .name = "ce4100_spi",
182 .id_table = ce4100_spi_devices,
183 .probe = ce4100_spi_probe,
184 .remove = __devexit_p(ce4100_spi_remove),
185};
186
187static int __init ce4100_spi_init(void)
188{
189 return pci_register_driver(&ce4100_spi_driver);
190}
191module_init(ce4100_spi_init);
192
193static void __exit ce4100_spi_exit(void)
194{
195 pci_unregister_driver(&ce4100_spi_driver);
196}
197module_exit(ce4100_spi_exit);
198
199MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver");
200MODULE_LICENSE("GPL v2");
201MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");