diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2010-11-24 04:17:14 -0500 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2010-12-01 07:48:30 -0500 |
commit | d6ea3df0d470fb9260db93883f97764cf9f0e562 (patch) | |
tree | 277838ea93d6dc0c7d2a05be757dfa1b8bedb619 | |
parent | 8348c259dd6a6019a8fa01b0a3443409480f7b9d (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>
-rw-r--r-- | drivers/spi/Kconfig | 13 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/pxa2xx_spi.c | 1 | ||||
-rw-r--r-- | drivers/spi/pxa2xx_spi_pci.c | 201 | ||||
-rw-r--r-- | include/linux/spi/pxa2xx_spi.h | 105 |
5 files changed, 314 insertions, 7 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 | ||
268 | config SPI_PXA2XX | 268 | config 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 | |||
277 | config SPI_PXA2XX_PCI | ||
278 | def_bool SPI_PXA2XX && X86_32 && PCI | ||
276 | 279 | ||
277 | config SPI_S3C24XX | 280 | config 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 | |||
24 | obj-$(CONFIG_SPI_IMX) += spi_imx.o | 24 | obj-$(CONFIG_SPI_IMX) += spi_imx.o |
25 | obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o | 25 | obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o |
26 | obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o | 26 | obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o |
27 | obj-$(CONFIG_SPI_PXA2XX_PCI) += pxa2xx_spi_pci.o | ||
27 | obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o | 28 | obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o |
28 | obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o | 29 | obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o |
29 | obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o | 30 | obj-$(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 | |||
10 | struct awesome_struct { | ||
11 | struct ssp_device ssp; | ||
12 | struct platform_device spi_pdev; | ||
13 | struct pxa2xx_spi_master spi_pdata; | ||
14 | }; | ||
15 | |||
16 | static DEFINE_MUTEX(ssp_lock); | ||
17 | static LIST_HEAD(ssp_list); | ||
18 | |||
19 | struct 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 | } | ||
40 | EXPORT_SYMBOL_GPL(pxa_ssp_request); | ||
41 | |||
42 | void 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 | } | ||
52 | EXPORT_SYMBOL_GPL(pxa_ssp_free); | ||
53 | |||
54 | static 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 | |||
62 | static 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 | |||
131 | err_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 | |||
138 | err_remap: | ||
139 | kfree(spi_info); | ||
140 | |||
141 | err_kz: | ||
142 | release_mem_region(phys_beg, phys_len); | ||
143 | |||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | static 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 | |||
173 | static struct pci_device_id ce4100_spi_devices[] __devinitdata = { | ||
174 | |||
175 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) }, | ||
176 | { }, | ||
177 | }; | ||
178 | MODULE_DEVICE_TABLE(pci, ce4100_spi_devices); | ||
179 | |||
180 | static 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 | |||
187 | static int __init ce4100_spi_init(void) | ||
188 | { | ||
189 | return pci_register_driver(&ce4100_spi_driver); | ||
190 | } | ||
191 | module_init(ce4100_spi_init); | ||
192 | |||
193 | static void __exit ce4100_spi_exit(void) | ||
194 | { | ||
195 | pci_unregister_driver(&ce4100_spi_driver); | ||
196 | } | ||
197 | module_exit(ce4100_spi_exit); | ||
198 | |||
199 | MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver"); | ||
200 | MODULE_LICENSE("GPL v2"); | ||
201 | MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); | ||
diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index 471ed6889113..d3e1075f7b60 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h | |||
@@ -19,7 +19,6 @@ | |||
19 | #define __linux_pxa2xx_spi_h | 19 | #define __linux_pxa2xx_spi_h |
20 | 20 | ||
21 | #include <linux/pxa2xx_ssp.h> | 21 | #include <linux/pxa2xx_ssp.h> |
22 | #include <mach/dma.h> | ||
23 | 22 | ||
24 | #define PXA2XX_CS_ASSERT (0x01) | 23 | #define PXA2XX_CS_ASSERT (0x01) |
25 | #define PXA2XX_CS_DEASSERT (0x02) | 24 | #define PXA2XX_CS_DEASSERT (0x02) |
@@ -44,6 +43,110 @@ struct pxa2xx_spi_chip { | |||
44 | void (*cs_control)(u32 command); | 43 | void (*cs_control)(u32 command); |
45 | }; | 44 | }; |
46 | 45 | ||
46 | #ifdef CONFIG_ARCH_PXA | ||
47 | |||
48 | #include <linux/clk.h> | ||
49 | #include <mach/dma.h> | ||
50 | |||
47 | extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info); | 51 | extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info); |
48 | 52 | ||
53 | #else | ||
54 | /* | ||
55 | * This is the implemtation for CE4100 on x86. ARM defines them in mach/ or | ||
56 | * plat/ include path. | ||
57 | * The CE4100 does not provide DMA support. This bits are here to let the driver | ||
58 | * compile and will never be used. Maybe we get DMA support at a later point in | ||
59 | * time. | ||
60 | */ | ||
61 | |||
62 | #define DCSR(n) (n) | ||
63 | #define DSADR(n) (n) | ||
64 | #define DTADR(n) (n) | ||
65 | #define DCMD(n) (n) | ||
66 | #define DRCMR(n) (n) | ||
67 | |||
68 | #define DCSR_RUN (1 << 31) /* Run Bit */ | ||
69 | #define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch */ | ||
70 | #define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable */ | ||
71 | #define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */ | ||
72 | #define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */ | ||
73 | #define DCSR_ENDINTR (1 << 2) /* End Interrupt */ | ||
74 | #define DCSR_STARTINTR (1 << 1) /* Start Interrupt */ | ||
75 | #define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt */ | ||
76 | |||
77 | #define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable */ | ||
78 | #define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */ | ||
79 | #define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */ | ||
80 | #define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */ | ||
81 | #define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */ | ||
82 | #define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */ | ||
83 | #define DCSR_EORINTR (1 << 9) /* The end of Receive */ | ||
84 | |||
85 | #define DRCMR_MAPVLD (1 << 7) /* Map Valid */ | ||
86 | #define DRCMR_CHLNUM 0x1f /* mask for Channel Number */ | ||
87 | |||
88 | #define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor */ | ||
89 | #define DDADR_STOP (1 << 0) /* Stop */ | ||
90 | |||
91 | #define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */ | ||
92 | #define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */ | ||
93 | #define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */ | ||
94 | #define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */ | ||
95 | #define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */ | ||
96 | #define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */ | ||
97 | #define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */ | ||
98 | #define DCMD_BURST8 (1 << 16) /* 8 byte burst */ | ||
99 | #define DCMD_BURST16 (2 << 16) /* 16 byte burst */ | ||
100 | #define DCMD_BURST32 (3 << 16) /* 32 byte burst */ | ||
101 | #define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ | ||
102 | #define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ | ||
103 | #define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ | ||
104 | #define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ | ||
105 | |||
106 | /* | ||
107 | * Descriptor structure for PXA's DMA engine | ||
108 | * Note: this structure must always be aligned to a 16-byte boundary. | ||
109 | */ | ||
110 | |||
111 | typedef enum { | ||
112 | DMA_PRIO_HIGH = 0, | ||
113 | DMA_PRIO_MEDIUM = 1, | ||
114 | DMA_PRIO_LOW = 2 | ||
115 | } pxa_dma_prio; | ||
116 | |||
117 | /* | ||
118 | * DMA registration | ||
119 | */ | ||
120 | |||
121 | static inline int pxa_request_dma(char *name, | ||
122 | pxa_dma_prio prio, | ||
123 | void (*irq_handler)(int, void *), | ||
124 | void *data) | ||
125 | { | ||
126 | return -ENODEV; | ||
127 | } | ||
128 | |||
129 | static inline void pxa_free_dma(int dma_ch) | ||
130 | { | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * The CE4100 does not have the clk framework implemented and SPI clock can | ||
135 | * not be switched on/off or the divider changed. | ||
136 | */ | ||
137 | static inline void clk_disable(struct clk *clk) | ||
138 | { | ||
139 | } | ||
140 | |||
141 | static inline int clk_enable(struct clk *clk) | ||
142 | { | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static inline unsigned long clk_get_rate(struct clk *clk) | ||
147 | { | ||
148 | return 3686400; | ||
149 | } | ||
150 | |||
151 | #endif | ||
49 | #endif | 152 | #endif |