Commit b5f3294f0be5496aec01e5aa709a5fab8bb2f225
Committed by
Linus Torvalds
1 parent
f33b29ee33
Exists in
master
and in
7 other branches
spi: add SPI driver for most known i.MX SoCs
This driver has been tested on i.MX1/i.MX27/i.MX35 with an AT25 type EEPROM and on i.MX27/i.MX31 with a Freescale MC13783 PMIC. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: David Brownell <david-b@pacbell.net> Cc: Andrea Paterniani <a.paterniani@swapp-eng.it> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 4 changed files with 721 additions and 0 deletions Side-by-side Diff
arch/arm/plat-mxc/include/mach/spi.h
1 | + | |
2 | +#ifndef __MACH_SPI_H_ | |
3 | +#define __MACH_SPI_H_ | |
4 | + | |
5 | +/* | |
6 | + * struct spi_imx_master - device.platform_data for SPI controller devices. | |
7 | + * @chipselect: Array of chipselects for this master. Numbers >= 0 mean gpio | |
8 | + * pins, numbers < 0 mean internal CSPI chipselects according | |
9 | + * to MXC_SPI_CS(). Normally you want to use gpio based chip | |
10 | + * selects as the CSPI module tries to be intelligent about | |
11 | + * when to assert the chipselect: The CSPI module deasserts the | |
12 | + * chipselect once it runs out of input data. The other problem | |
13 | + * is that it is not possible to mix between high active and low | |
14 | + * active chipselects on one single bus using the internal | |
15 | + * chipselects. Unfortunately Freescale decided to put some | |
16 | + * chipselects on dedicated pins which are not usable as gpios, | |
17 | + * so we have to support the internal chipselects. | |
18 | + * @num_chipselect: ARRAY_SIZE(chipselect) | |
19 | + */ | |
20 | +struct spi_imx_master { | |
21 | + int *chipselect; | |
22 | + int num_chipselect; | |
23 | +}; | |
24 | + | |
25 | +#define MXC_SPI_CS(no) ((no) - 32) | |
26 | + | |
27 | +#endif /* __MACH_SPI_H_*/ |
drivers/spi/Kconfig
... | ... | @@ -116,6 +116,14 @@ |
116 | 116 | GPIO operations, you should be able to leverage that for better |
117 | 117 | speed with a custom version of this driver; see the source code. |
118 | 118 | |
119 | +config SPI_IMX | |
120 | + tristate "Freescale i.MX SPI controllers" | |
121 | + depends on ARCH_MXC | |
122 | + select SPI_BITBANG | |
123 | + help | |
124 | + This enables using the Freescale i.MX SPI controllers in master | |
125 | + mode. | |
126 | + | |
119 | 127 | config SPI_LM70_LLP |
120 | 128 | tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" |
121 | 129 | depends on PARPORT && EXPERIMENTAL |
drivers/spi/Makefile
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | obj-$(CONFIG_SPI_AU1550) += au1550_spi.o |
18 | 18 | obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o |
19 | 19 | obj-$(CONFIG_SPI_GPIO) += spi_gpio.o |
20 | +obj-$(CONFIG_SPI_IMX) += mxc_spi.o | |
20 | 21 | obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o |
21 | 22 | obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o |
22 | 23 | obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o |
drivers/spi/mxc_spi.c
1 | +/* | |
2 | + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. | |
3 | + * Copyright (C) 2008 Juergen Beisert | |
4 | + * | |
5 | + * This program is free software; you can redistribute it and/or | |
6 | + * modify it under the terms of the GNU General Public License | |
7 | + * as published by the Free Software Foundation; either version 2 | |
8 | + * of the License, or (at your option) any later version. | |
9 | + * This program is distributed in the hope that it will be useful, | |
10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | + * GNU General Public License for more details. | |
13 | + * | |
14 | + * You should have received a copy of the GNU General Public License | |
15 | + * along with this program; if not, write to the | |
16 | + * Free Software Foundation | |
17 | + * 51 Franklin Street, Fifth Floor | |
18 | + * Boston, MA 02110-1301, USA. | |
19 | + */ | |
20 | + | |
21 | +#include <linux/clk.h> | |
22 | +#include <linux/completion.h> | |
23 | +#include <linux/delay.h> | |
24 | +#include <linux/err.h> | |
25 | +#include <linux/gpio.h> | |
26 | +#include <linux/init.h> | |
27 | +#include <linux/interrupt.h> | |
28 | +#include <linux/io.h> | |
29 | +#include <linux/irq.h> | |
30 | +#include <linux/kernel.h> | |
31 | +#include <linux/module.h> | |
32 | +#include <linux/platform_device.h> | |
33 | +#include <linux/spi/spi.h> | |
34 | +#include <linux/spi/spi_bitbang.h> | |
35 | +#include <linux/types.h> | |
36 | + | |
37 | +#include <mach/spi.h> | |
38 | + | |
39 | +#define DRIVER_NAME "spi_imx" | |
40 | + | |
41 | +#define MXC_CSPIRXDATA 0x00 | |
42 | +#define MXC_CSPITXDATA 0x04 | |
43 | +#define MXC_CSPICTRL 0x08 | |
44 | +#define MXC_CSPIINT 0x0c | |
45 | +#define MXC_RESET 0x1c | |
46 | + | |
47 | +/* generic defines to abstract from the different register layouts */ | |
48 | +#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */ | |
49 | +#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */ | |
50 | + | |
51 | +struct mxc_spi_config { | |
52 | + unsigned int speed_hz; | |
53 | + unsigned int bpw; | |
54 | + unsigned int mode; | |
55 | + int cs; | |
56 | +}; | |
57 | + | |
58 | +struct mxc_spi_data { | |
59 | + struct spi_bitbang bitbang; | |
60 | + | |
61 | + struct completion xfer_done; | |
62 | + void *base; | |
63 | + int irq; | |
64 | + struct clk *clk; | |
65 | + unsigned long spi_clk; | |
66 | + int *chipselect; | |
67 | + | |
68 | + unsigned int count; | |
69 | + void (*tx)(struct mxc_spi_data *); | |
70 | + void (*rx)(struct mxc_spi_data *); | |
71 | + void *rx_buf; | |
72 | + const void *tx_buf; | |
73 | + unsigned int txfifo; /* number of words pushed in tx FIFO */ | |
74 | + | |
75 | + /* SoC specific functions */ | |
76 | + void (*intctrl)(struct mxc_spi_data *, int); | |
77 | + int (*config)(struct mxc_spi_data *, struct mxc_spi_config *); | |
78 | + void (*trigger)(struct mxc_spi_data *); | |
79 | + int (*rx_available)(struct mxc_spi_data *); | |
80 | +}; | |
81 | + | |
82 | +#define MXC_SPI_BUF_RX(type) \ | |
83 | +static void mxc_spi_buf_rx_##type(struct mxc_spi_data *mxc_spi) \ | |
84 | +{ \ | |
85 | + unsigned int val = readl(mxc_spi->base + MXC_CSPIRXDATA); \ | |
86 | + \ | |
87 | + if (mxc_spi->rx_buf) { \ | |
88 | + *(type *)mxc_spi->rx_buf = val; \ | |
89 | + mxc_spi->rx_buf += sizeof(type); \ | |
90 | + } \ | |
91 | +} | |
92 | + | |
93 | +#define MXC_SPI_BUF_TX(type) \ | |
94 | +static void mxc_spi_buf_tx_##type(struct mxc_spi_data *mxc_spi) \ | |
95 | +{ \ | |
96 | + type val = 0; \ | |
97 | + \ | |
98 | + if (mxc_spi->tx_buf) { \ | |
99 | + val = *(type *)mxc_spi->tx_buf; \ | |
100 | + mxc_spi->tx_buf += sizeof(type); \ | |
101 | + } \ | |
102 | + \ | |
103 | + mxc_spi->count -= sizeof(type); \ | |
104 | + \ | |
105 | + writel(val, mxc_spi->base + MXC_CSPITXDATA); \ | |
106 | +} | |
107 | + | |
108 | +MXC_SPI_BUF_RX(u8) | |
109 | +MXC_SPI_BUF_TX(u8) | |
110 | +MXC_SPI_BUF_RX(u16) | |
111 | +MXC_SPI_BUF_TX(u16) | |
112 | +MXC_SPI_BUF_RX(u32) | |
113 | +MXC_SPI_BUF_TX(u32) | |
114 | + | |
115 | +/* First entry is reserved, second entry is valid only if SDHC_SPIEN is set | |
116 | + * (which is currently not the case in this driver) | |
117 | + */ | |
118 | +static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, | |
119 | + 256, 384, 512, 768, 1024}; | |
120 | + | |
121 | +/* MX21, MX27 */ | |
122 | +static unsigned int mxc_spi_clkdiv_1(unsigned int fin, | |
123 | + unsigned int fspi) | |
124 | +{ | |
125 | + int i, max; | |
126 | + | |
127 | + if (cpu_is_mx21()) | |
128 | + max = 18; | |
129 | + else | |
130 | + max = 16; | |
131 | + | |
132 | + for (i = 2; i < max; i++) | |
133 | + if (fspi * mxc_clkdivs[i] >= fin) | |
134 | + return i; | |
135 | + | |
136 | + return max; | |
137 | +} | |
138 | + | |
139 | +/* MX1, MX31, MX35 */ | |
140 | +static unsigned int mxc_spi_clkdiv_2(unsigned int fin, | |
141 | + unsigned int fspi) | |
142 | +{ | |
143 | + int i, div = 4; | |
144 | + | |
145 | + for (i = 0; i < 7; i++) { | |
146 | + if (fspi * div >= fin) | |
147 | + return i; | |
148 | + div <<= 1; | |
149 | + } | |
150 | + | |
151 | + return 7; | |
152 | +} | |
153 | + | |
154 | +#define MX31_INTREG_TEEN (1 << 0) | |
155 | +#define MX31_INTREG_RREN (1 << 3) | |
156 | + | |
157 | +#define MX31_CSPICTRL_ENABLE (1 << 0) | |
158 | +#define MX31_CSPICTRL_MASTER (1 << 1) | |
159 | +#define MX31_CSPICTRL_XCH (1 << 2) | |
160 | +#define MX31_CSPICTRL_POL (1 << 4) | |
161 | +#define MX31_CSPICTRL_PHA (1 << 5) | |
162 | +#define MX31_CSPICTRL_SSCTL (1 << 6) | |
163 | +#define MX31_CSPICTRL_SSPOL (1 << 7) | |
164 | +#define MX31_CSPICTRL_BC_SHIFT 8 | |
165 | +#define MX35_CSPICTRL_BL_SHIFT 20 | |
166 | +#define MX31_CSPICTRL_CS_SHIFT 24 | |
167 | +#define MX35_CSPICTRL_CS_SHIFT 12 | |
168 | +#define MX31_CSPICTRL_DR_SHIFT 16 | |
169 | + | |
170 | +#define MX31_CSPISTATUS 0x14 | |
171 | +#define MX31_STATUS_RR (1 << 3) | |
172 | + | |
173 | +/* These functions also work for the i.MX35, but be aware that | |
174 | + * the i.MX35 has a slightly different register layout for bits | |
175 | + * we do not use here. | |
176 | + */ | |
177 | +static void mx31_intctrl(struct mxc_spi_data *mxc_spi, int enable) | |
178 | +{ | |
179 | + unsigned int val = 0; | |
180 | + | |
181 | + if (enable & MXC_INT_TE) | |
182 | + val |= MX31_INTREG_TEEN; | |
183 | + if (enable & MXC_INT_RR) | |
184 | + val |= MX31_INTREG_RREN; | |
185 | + | |
186 | + writel(val, mxc_spi->base + MXC_CSPIINT); | |
187 | +} | |
188 | + | |
189 | +static void mx31_trigger(struct mxc_spi_data *mxc_spi) | |
190 | +{ | |
191 | + unsigned int reg; | |
192 | + | |
193 | + reg = readl(mxc_spi->base + MXC_CSPICTRL); | |
194 | + reg |= MX31_CSPICTRL_XCH; | |
195 | + writel(reg, mxc_spi->base + MXC_CSPICTRL); | |
196 | +} | |
197 | + | |
198 | +static int mx31_config(struct mxc_spi_data *mxc_spi, | |
199 | + struct mxc_spi_config *config) | |
200 | +{ | |
201 | + unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; | |
202 | + | |
203 | + reg |= mxc_spi_clkdiv_2(mxc_spi->spi_clk, config->speed_hz) << | |
204 | + MX31_CSPICTRL_DR_SHIFT; | |
205 | + | |
206 | + if (cpu_is_mx31()) | |
207 | + reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT; | |
208 | + else if (cpu_is_mx35()) { | |
209 | + reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT; | |
210 | + reg |= MX31_CSPICTRL_SSCTL; | |
211 | + } | |
212 | + | |
213 | + if (config->mode & SPI_CPHA) | |
214 | + reg |= MX31_CSPICTRL_PHA; | |
215 | + if (config->mode & SPI_CPOL) | |
216 | + reg |= MX31_CSPICTRL_POL; | |
217 | + if (config->mode & SPI_CS_HIGH) | |
218 | + reg |= MX31_CSPICTRL_SSPOL; | |
219 | + if (config->cs < 0) { | |
220 | + if (cpu_is_mx31()) | |
221 | + reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT; | |
222 | + else if (cpu_is_mx35()) | |
223 | + reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT; | |
224 | + } | |
225 | + | |
226 | + writel(reg, mxc_spi->base + MXC_CSPICTRL); | |
227 | + | |
228 | + return 0; | |
229 | +} | |
230 | + | |
231 | +static int mx31_rx_available(struct mxc_spi_data *mxc_spi) | |
232 | +{ | |
233 | + return readl(mxc_spi->base + MX31_CSPISTATUS) & MX31_STATUS_RR; | |
234 | +} | |
235 | + | |
236 | +#define MX27_INTREG_RR (1 << 4) | |
237 | +#define MX27_INTREG_TEEN (1 << 9) | |
238 | +#define MX27_INTREG_RREN (1 << 13) | |
239 | + | |
240 | +#define MX27_CSPICTRL_POL (1 << 5) | |
241 | +#define MX27_CSPICTRL_PHA (1 << 6) | |
242 | +#define MX27_CSPICTRL_SSPOL (1 << 8) | |
243 | +#define MX27_CSPICTRL_XCH (1 << 9) | |
244 | +#define MX27_CSPICTRL_ENABLE (1 << 10) | |
245 | +#define MX27_CSPICTRL_MASTER (1 << 11) | |
246 | +#define MX27_CSPICTRL_DR_SHIFT 14 | |
247 | +#define MX27_CSPICTRL_CS_SHIFT 19 | |
248 | + | |
249 | +static void mx27_intctrl(struct mxc_spi_data *mxc_spi, int enable) | |
250 | +{ | |
251 | + unsigned int val = 0; | |
252 | + | |
253 | + if (enable & MXC_INT_TE) | |
254 | + val |= MX27_INTREG_TEEN; | |
255 | + if (enable & MXC_INT_RR) | |
256 | + val |= MX27_INTREG_RREN; | |
257 | + | |
258 | + writel(val, mxc_spi->base + MXC_CSPIINT); | |
259 | +} | |
260 | + | |
261 | +static void mx27_trigger(struct mxc_spi_data *mxc_spi) | |
262 | +{ | |
263 | + unsigned int reg; | |
264 | + | |
265 | + reg = readl(mxc_spi->base + MXC_CSPICTRL); | |
266 | + reg |= MX27_CSPICTRL_XCH; | |
267 | + writel(reg, mxc_spi->base + MXC_CSPICTRL); | |
268 | +} | |
269 | + | |
270 | +static int mx27_config(struct mxc_spi_data *mxc_spi, | |
271 | + struct mxc_spi_config *config) | |
272 | +{ | |
273 | + unsigned int reg = MX27_CSPICTRL_ENABLE | MX27_CSPICTRL_MASTER; | |
274 | + | |
275 | + reg |= mxc_spi_clkdiv_1(mxc_spi->spi_clk, config->speed_hz) << | |
276 | + MX27_CSPICTRL_DR_SHIFT; | |
277 | + reg |= config->bpw - 1; | |
278 | + | |
279 | + if (config->mode & SPI_CPHA) | |
280 | + reg |= MX27_CSPICTRL_PHA; | |
281 | + if (config->mode & SPI_CPOL) | |
282 | + reg |= MX27_CSPICTRL_POL; | |
283 | + if (config->mode & SPI_CS_HIGH) | |
284 | + reg |= MX27_CSPICTRL_SSPOL; | |
285 | + if (config->cs < 0) | |
286 | + reg |= (config->cs + 32) << MX27_CSPICTRL_CS_SHIFT; | |
287 | + | |
288 | + writel(reg, mxc_spi->base + MXC_CSPICTRL); | |
289 | + | |
290 | + return 0; | |
291 | +} | |
292 | + | |
293 | +static int mx27_rx_available(struct mxc_spi_data *mxc_spi) | |
294 | +{ | |
295 | + return readl(mxc_spi->base + MXC_CSPIINT) & MX27_INTREG_RR; | |
296 | +} | |
297 | + | |
298 | +#define MX1_INTREG_RR (1 << 3) | |
299 | +#define MX1_INTREG_TEEN (1 << 8) | |
300 | +#define MX1_INTREG_RREN (1 << 11) | |
301 | + | |
302 | +#define MX1_CSPICTRL_POL (1 << 4) | |
303 | +#define MX1_CSPICTRL_PHA (1 << 5) | |
304 | +#define MX1_CSPICTRL_XCH (1 << 8) | |
305 | +#define MX1_CSPICTRL_ENABLE (1 << 9) | |
306 | +#define MX1_CSPICTRL_MASTER (1 << 10) | |
307 | +#define MX1_CSPICTRL_DR_SHIFT 13 | |
308 | + | |
309 | +static void mx1_intctrl(struct mxc_spi_data *mxc_spi, int enable) | |
310 | +{ | |
311 | + unsigned int val = 0; | |
312 | + | |
313 | + if (enable & MXC_INT_TE) | |
314 | + val |= MX1_INTREG_TEEN; | |
315 | + if (enable & MXC_INT_RR) | |
316 | + val |= MX1_INTREG_RREN; | |
317 | + | |
318 | + writel(val, mxc_spi->base + MXC_CSPIINT); | |
319 | +} | |
320 | + | |
321 | +static void mx1_trigger(struct mxc_spi_data *mxc_spi) | |
322 | +{ | |
323 | + unsigned int reg; | |
324 | + | |
325 | + reg = readl(mxc_spi->base + MXC_CSPICTRL); | |
326 | + reg |= MX1_CSPICTRL_XCH; | |
327 | + writel(reg, mxc_spi->base + MXC_CSPICTRL); | |
328 | +} | |
329 | + | |
330 | +static int mx1_config(struct mxc_spi_data *mxc_spi, | |
331 | + struct mxc_spi_config *config) | |
332 | +{ | |
333 | + unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER; | |
334 | + | |
335 | + reg |= mxc_spi_clkdiv_2(mxc_spi->spi_clk, config->speed_hz) << | |
336 | + MX1_CSPICTRL_DR_SHIFT; | |
337 | + reg |= config->bpw - 1; | |
338 | + | |
339 | + if (config->mode & SPI_CPHA) | |
340 | + reg |= MX1_CSPICTRL_PHA; | |
341 | + if (config->mode & SPI_CPOL) | |
342 | + reg |= MX1_CSPICTRL_POL; | |
343 | + | |
344 | + writel(reg, mxc_spi->base + MXC_CSPICTRL); | |
345 | + | |
346 | + return 0; | |
347 | +} | |
348 | + | |
349 | +static int mx1_rx_available(struct mxc_spi_data *mxc_spi) | |
350 | +{ | |
351 | + return readl(mxc_spi->base + MXC_CSPIINT) & MX1_INTREG_RR; | |
352 | +} | |
353 | + | |
354 | +static void mxc_spi_chipselect(struct spi_device *spi, int is_active) | |
355 | +{ | |
356 | + struct mxc_spi_data *mxc_spi = spi_master_get_devdata(spi->master); | |
357 | + unsigned int cs = 0; | |
358 | + int gpio = mxc_spi->chipselect[spi->chip_select]; | |
359 | + struct mxc_spi_config config; | |
360 | + | |
361 | + if (spi->mode & SPI_CS_HIGH) | |
362 | + cs = 1; | |
363 | + | |
364 | + if (is_active == BITBANG_CS_INACTIVE) { | |
365 | + if (gpio >= 0) | |
366 | + gpio_set_value(gpio, !cs); | |
367 | + return; | |
368 | + } | |
369 | + | |
370 | + config.bpw = spi->bits_per_word; | |
371 | + config.speed_hz = spi->max_speed_hz; | |
372 | + config.mode = spi->mode; | |
373 | + config.cs = mxc_spi->chipselect[spi->chip_select]; | |
374 | + | |
375 | + mxc_spi->config(mxc_spi, &config); | |
376 | + | |
377 | + /* Initialize the functions for transfer */ | |
378 | + if (config.bpw <= 8) { | |
379 | + mxc_spi->rx = mxc_spi_buf_rx_u8; | |
380 | + mxc_spi->tx = mxc_spi_buf_tx_u8; | |
381 | + } else if (config.bpw <= 16) { | |
382 | + mxc_spi->rx = mxc_spi_buf_rx_u16; | |
383 | + mxc_spi->tx = mxc_spi_buf_tx_u16; | |
384 | + } else if (config.bpw <= 32) { | |
385 | + mxc_spi->rx = mxc_spi_buf_rx_u32; | |
386 | + mxc_spi->tx = mxc_spi_buf_tx_u32; | |
387 | + } else | |
388 | + BUG(); | |
389 | + | |
390 | + if (gpio >= 0) | |
391 | + gpio_set_value(gpio, cs); | |
392 | + | |
393 | + return; | |
394 | +} | |
395 | + | |
396 | +static void mxc_spi_push(struct mxc_spi_data *mxc_spi) | |
397 | +{ | |
398 | + while (mxc_spi->txfifo < 8) { | |
399 | + if (!mxc_spi->count) | |
400 | + break; | |
401 | + mxc_spi->tx(mxc_spi); | |
402 | + mxc_spi->txfifo++; | |
403 | + } | |
404 | + | |
405 | + mxc_spi->trigger(mxc_spi); | |
406 | +} | |
407 | + | |
408 | +static irqreturn_t mxc_spi_isr(int irq, void *dev_id) | |
409 | +{ | |
410 | + struct mxc_spi_data *mxc_spi = dev_id; | |
411 | + | |
412 | + while (mxc_spi->rx_available(mxc_spi)) { | |
413 | + mxc_spi->rx(mxc_spi); | |
414 | + mxc_spi->txfifo--; | |
415 | + } | |
416 | + | |
417 | + if (mxc_spi->count) { | |
418 | + mxc_spi_push(mxc_spi); | |
419 | + return IRQ_HANDLED; | |
420 | + } | |
421 | + | |
422 | + if (mxc_spi->txfifo) { | |
423 | + /* No data left to push, but still waiting for rx data, | |
424 | + * enable receive data available interrupt. | |
425 | + */ | |
426 | + mxc_spi->intctrl(mxc_spi, MXC_INT_RR); | |
427 | + return IRQ_HANDLED; | |
428 | + } | |
429 | + | |
430 | + mxc_spi->intctrl(mxc_spi, 0); | |
431 | + complete(&mxc_spi->xfer_done); | |
432 | + | |
433 | + return IRQ_HANDLED; | |
434 | +} | |
435 | + | |
436 | +static int mxc_spi_setupxfer(struct spi_device *spi, | |
437 | + struct spi_transfer *t) | |
438 | +{ | |
439 | + struct mxc_spi_data *mxc_spi = spi_master_get_devdata(spi->master); | |
440 | + struct mxc_spi_config config; | |
441 | + | |
442 | + config.bpw = t ? t->bits_per_word : spi->bits_per_word; | |
443 | + config.speed_hz = t ? t->speed_hz : spi->max_speed_hz; | |
444 | + config.mode = spi->mode; | |
445 | + | |
446 | + mxc_spi->config(mxc_spi, &config); | |
447 | + | |
448 | + return 0; | |
449 | +} | |
450 | + | |
451 | +static int mxc_spi_transfer(struct spi_device *spi, | |
452 | + struct spi_transfer *transfer) | |
453 | +{ | |
454 | + struct mxc_spi_data *mxc_spi = spi_master_get_devdata(spi->master); | |
455 | + | |
456 | + mxc_spi->tx_buf = transfer->tx_buf; | |
457 | + mxc_spi->rx_buf = transfer->rx_buf; | |
458 | + mxc_spi->count = transfer->len; | |
459 | + mxc_spi->txfifo = 0; | |
460 | + | |
461 | + init_completion(&mxc_spi->xfer_done); | |
462 | + | |
463 | + mxc_spi_push(mxc_spi); | |
464 | + | |
465 | + mxc_spi->intctrl(mxc_spi, MXC_INT_TE); | |
466 | + | |
467 | + wait_for_completion(&mxc_spi->xfer_done); | |
468 | + | |
469 | + return transfer->len; | |
470 | +} | |
471 | + | |
472 | +static int mxc_spi_setup(struct spi_device *spi) | |
473 | +{ | |
474 | + if (!spi->bits_per_word) | |
475 | + spi->bits_per_word = 8; | |
476 | + | |
477 | + pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__, | |
478 | + spi->mode, spi->bits_per_word, spi->max_speed_hz); | |
479 | + | |
480 | + mxc_spi_chipselect(spi, BITBANG_CS_INACTIVE); | |
481 | + | |
482 | + return 0; | |
483 | +} | |
484 | + | |
485 | +static void mxc_spi_cleanup(struct spi_device *spi) | |
486 | +{ | |
487 | +} | |
488 | + | |
489 | +static int __init mxc_spi_probe(struct platform_device *pdev) | |
490 | +{ | |
491 | + struct spi_imx_master *mxc_platform_info; | |
492 | + struct spi_master *master; | |
493 | + struct mxc_spi_data *mxc_spi; | |
494 | + struct resource *res; | |
495 | + int i, ret; | |
496 | + | |
497 | + mxc_platform_info = (struct spi_imx_master *)pdev->dev.platform_data; | |
498 | + if (!mxc_platform_info) { | |
499 | + dev_err(&pdev->dev, "can't get the platform data\n"); | |
500 | + return -EINVAL; | |
501 | + } | |
502 | + | |
503 | + master = spi_alloc_master(&pdev->dev, sizeof(struct mxc_spi_data)); | |
504 | + if (!master) | |
505 | + return -ENOMEM; | |
506 | + | |
507 | + platform_set_drvdata(pdev, master); | |
508 | + | |
509 | + master->bus_num = pdev->id; | |
510 | + master->num_chipselect = mxc_platform_info->num_chipselect; | |
511 | + | |
512 | + mxc_spi = spi_master_get_devdata(master); | |
513 | + mxc_spi->bitbang.master = spi_master_get(master); | |
514 | + mxc_spi->chipselect = mxc_platform_info->chipselect; | |
515 | + | |
516 | + for (i = 0; i < master->num_chipselect; i++) { | |
517 | + if (mxc_spi->chipselect[i] < 0) | |
518 | + continue; | |
519 | + ret = gpio_request(mxc_spi->chipselect[i], DRIVER_NAME); | |
520 | + if (ret) { | |
521 | + i--; | |
522 | + while (i > 0) | |
523 | + if (mxc_spi->chipselect[i] >= 0) | |
524 | + gpio_free(mxc_spi->chipselect[i--]); | |
525 | + dev_err(&pdev->dev, "can't get cs gpios"); | |
526 | + goto out_master_put; | |
527 | + } | |
528 | + gpio_direction_output(mxc_spi->chipselect[i], 1); | |
529 | + } | |
530 | + | |
531 | + mxc_spi->bitbang.chipselect = mxc_spi_chipselect; | |
532 | + mxc_spi->bitbang.setup_transfer = mxc_spi_setupxfer; | |
533 | + mxc_spi->bitbang.txrx_bufs = mxc_spi_transfer; | |
534 | + mxc_spi->bitbang.master->setup = mxc_spi_setup; | |
535 | + mxc_spi->bitbang.master->cleanup = mxc_spi_cleanup; | |
536 | + | |
537 | + init_completion(&mxc_spi->xfer_done); | |
538 | + | |
539 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
540 | + if (!res) { | |
541 | + dev_err(&pdev->dev, "can't get platform resource\n"); | |
542 | + ret = -ENOMEM; | |
543 | + goto out_gpio_free; | |
544 | + } | |
545 | + | |
546 | + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | |
547 | + dev_err(&pdev->dev, "request_mem_region failed\n"); | |
548 | + ret = -EBUSY; | |
549 | + goto out_gpio_free; | |
550 | + } | |
551 | + | |
552 | + mxc_spi->base = ioremap(res->start, resource_size(res)); | |
553 | + if (!mxc_spi->base) { | |
554 | + ret = -EINVAL; | |
555 | + goto out_release_mem; | |
556 | + } | |
557 | + | |
558 | + mxc_spi->irq = platform_get_irq(pdev, 0); | |
559 | + if (!mxc_spi->irq) { | |
560 | + ret = -EINVAL; | |
561 | + goto out_iounmap; | |
562 | + } | |
563 | + | |
564 | + ret = request_irq(mxc_spi->irq, mxc_spi_isr, 0, DRIVER_NAME, mxc_spi); | |
565 | + if (ret) { | |
566 | + dev_err(&pdev->dev, "can't get irq%d: %d\n", mxc_spi->irq, ret); | |
567 | + goto out_iounmap; | |
568 | + } | |
569 | + | |
570 | + if (cpu_is_mx31() || cpu_is_mx35()) { | |
571 | + mxc_spi->intctrl = mx31_intctrl; | |
572 | + mxc_spi->config = mx31_config; | |
573 | + mxc_spi->trigger = mx31_trigger; | |
574 | + mxc_spi->rx_available = mx31_rx_available; | |
575 | + } else if (cpu_is_mx27() || cpu_is_mx21()) { | |
576 | + mxc_spi->intctrl = mx27_intctrl; | |
577 | + mxc_spi->config = mx27_config; | |
578 | + mxc_spi->trigger = mx27_trigger; | |
579 | + mxc_spi->rx_available = mx27_rx_available; | |
580 | + } else if (cpu_is_mx1()) { | |
581 | + mxc_spi->intctrl = mx1_intctrl; | |
582 | + mxc_spi->config = mx1_config; | |
583 | + mxc_spi->trigger = mx1_trigger; | |
584 | + mxc_spi->rx_available = mx1_rx_available; | |
585 | + } else | |
586 | + BUG(); | |
587 | + | |
588 | + mxc_spi->clk = clk_get(&pdev->dev, NULL); | |
589 | + if (IS_ERR(mxc_spi->clk)) { | |
590 | + dev_err(&pdev->dev, "unable to get clock\n"); | |
591 | + ret = PTR_ERR(mxc_spi->clk); | |
592 | + goto out_free_irq; | |
593 | + } | |
594 | + | |
595 | + clk_enable(mxc_spi->clk); | |
596 | + mxc_spi->spi_clk = clk_get_rate(mxc_spi->clk); | |
597 | + | |
598 | + if (!cpu_is_mx31() || !cpu_is_mx35()) | |
599 | + writel(1, mxc_spi->base + MXC_RESET); | |
600 | + | |
601 | + mxc_spi->intctrl(mxc_spi, 0); | |
602 | + | |
603 | + ret = spi_bitbang_start(&mxc_spi->bitbang); | |
604 | + if (ret) { | |
605 | + dev_err(&pdev->dev, "bitbang start failed with %d\n", ret); | |
606 | + goto out_clk_put; | |
607 | + } | |
608 | + | |
609 | + dev_info(&pdev->dev, "probed\n"); | |
610 | + | |
611 | + return ret; | |
612 | + | |
613 | +out_clk_put: | |
614 | + clk_disable(mxc_spi->clk); | |
615 | + clk_put(mxc_spi->clk); | |
616 | +out_free_irq: | |
617 | + free_irq(mxc_spi->irq, mxc_spi); | |
618 | +out_iounmap: | |
619 | + iounmap(mxc_spi->base); | |
620 | +out_release_mem: | |
621 | + release_mem_region(res->start, resource_size(res)); | |
622 | +out_gpio_free: | |
623 | + for (i = 0; i < master->num_chipselect; i++) | |
624 | + if (mxc_spi->chipselect[i] >= 0) | |
625 | + gpio_free(mxc_spi->chipselect[i]); | |
626 | +out_master_put: | |
627 | + spi_master_put(master); | |
628 | + kfree(master); | |
629 | + platform_set_drvdata(pdev, NULL); | |
630 | + return ret; | |
631 | +} | |
632 | + | |
633 | +static int __exit mxc_spi_remove(struct platform_device *pdev) | |
634 | +{ | |
635 | + struct spi_master *master = platform_get_drvdata(pdev); | |
636 | + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
637 | + struct mxc_spi_data *mxc_spi = spi_master_get_devdata(master); | |
638 | + int i; | |
639 | + | |
640 | + spi_bitbang_stop(&mxc_spi->bitbang); | |
641 | + | |
642 | + writel(0, mxc_spi->base + MXC_CSPICTRL); | |
643 | + clk_disable(mxc_spi->clk); | |
644 | + clk_put(mxc_spi->clk); | |
645 | + free_irq(mxc_spi->irq, mxc_spi); | |
646 | + iounmap(mxc_spi->base); | |
647 | + | |
648 | + for (i = 0; i < master->num_chipselect; i++) | |
649 | + if (mxc_spi->chipselect[i] >= 0) | |
650 | + gpio_free(mxc_spi->chipselect[i]); | |
651 | + | |
652 | + spi_master_put(master); | |
653 | + | |
654 | + release_mem_region(res->start, resource_size(res)); | |
655 | + | |
656 | + platform_set_drvdata(pdev, NULL); | |
657 | + | |
658 | + return 0; | |
659 | +} | |
660 | + | |
661 | +static struct platform_driver mxc_spi_driver = { | |
662 | + .driver = { | |
663 | + .name = DRIVER_NAME, | |
664 | + .owner = THIS_MODULE, | |
665 | + }, | |
666 | + .probe = mxc_spi_probe, | |
667 | + .remove = __exit_p(mxc_spi_remove), | |
668 | +}; | |
669 | + | |
670 | +static int __init mxc_spi_init(void) | |
671 | +{ | |
672 | + return platform_driver_register(&mxc_spi_driver); | |
673 | +} | |
674 | + | |
675 | +static void __exit mxc_spi_exit(void) | |
676 | +{ | |
677 | + platform_driver_unregister(&mxc_spi_driver); | |
678 | +} | |
679 | + | |
680 | +module_init(mxc_spi_init); | |
681 | +module_exit(mxc_spi_exit); | |
682 | + | |
683 | +MODULE_DESCRIPTION("SPI Master Controller driver"); | |
684 | +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); | |
685 | +MODULE_LICENSE("GPL"); |