diff options
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt | 42 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 7 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-dspi.c | 557 |
4 files changed, 607 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt new file mode 100644 index 000000000000..a1fb3035a42b --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt | |||
@@ -0,0 +1,42 @@ | |||
1 | ARM Freescale DSPI controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "fsl,vf610-dspi" | ||
5 | - reg : Offset and length of the register set for the device | ||
6 | - interrupts : Should contain SPI controller interrupt | ||
7 | - clocks: from common clock binding: handle to dspi clock. | ||
8 | - clock-names: from common clock binding: Shall be "dspi". | ||
9 | - pinctrl-0: pin control group to be used for this controller. | ||
10 | - pinctrl-names: must contain a "default" entry. | ||
11 | - spi-num-chipselects : the number of the chipselect signals. | ||
12 | - bus-num : the slave chip chipselect signal number. | ||
13 | Example: | ||
14 | |||
15 | dspi0@4002c000 { | ||
16 | #address-cells = <1>; | ||
17 | #size-cells = <0>; | ||
18 | compatible = "fsl,vf610-dspi"; | ||
19 | reg = <0x4002c000 0x1000>; | ||
20 | interrupts = <0 67 0x04>; | ||
21 | clocks = <&clks VF610_CLK_DSPI0>; | ||
22 | clock-names = "dspi"; | ||
23 | spi-num-chipselects = <5>; | ||
24 | bus-num = <0>; | ||
25 | pinctrl-names = "default"; | ||
26 | pinctrl-0 = <&pinctrl_dspi0_1>; | ||
27 | status = "okay"; | ||
28 | |||
29 | sflash: at26df081a@0 { | ||
30 | #address-cells = <1>; | ||
31 | #size-cells = <1>; | ||
32 | compatible = "atmel,at26df081a"; | ||
33 | spi-max-frequency = <16000000>; | ||
34 | spi-cpol; | ||
35 | spi-cpha; | ||
36 | reg = <0>; | ||
37 | linux,modalias = "m25p80"; | ||
38 | modal = "at26df081a"; | ||
39 | }; | ||
40 | }; | ||
41 | |||
42 | |||
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 2f6f42a4f805..718d08205bd3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -255,6 +255,13 @@ config SPI_FSL_SPI | |||
255 | This also enables using the Aeroflex Gaisler GRLIB SPI controller in | 255 | This also enables using the Aeroflex Gaisler GRLIB SPI controller in |
256 | master mode. | 256 | master mode. |
257 | 257 | ||
258 | config SPI_FSL_DSPI | ||
259 | tristate "Freescale DSPI controller" | ||
260 | select SPI_BITBANG | ||
261 | help | ||
262 | This enables support for the Freescale DSPI controller in master | ||
263 | mode. VF610 platform uses the controller. | ||
264 | |||
258 | config SPI_FSL_ESPI | 265 | config SPI_FSL_ESPI |
259 | bool "Freescale eSPI controller" | 266 | bool "Freescale eSPI controller" |
260 | depends on FSL_SOC | 267 | depends on FSL_SOC |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7c4170263cd8..aaacc93c40f4 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -31,6 +31,7 @@ spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o | |||
31 | obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o | 31 | obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o |
32 | obj-$(CONFIG_SPI_FALCON) += spi-falcon.o | 32 | obj-$(CONFIG_SPI_FALCON) += spi-falcon.o |
33 | obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o | 33 | obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o |
34 | obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o | ||
34 | obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o | 35 | obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o |
35 | obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o | 36 | obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o |
36 | obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o | 37 | obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o |
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c new file mode 100644 index 000000000000..6cd07d13ecab --- /dev/null +++ b/drivers/spi/spi-fsl-dspi.c | |||
@@ -0,0 +1,557 @@ | |||
1 | /* | ||
2 | * drivers/spi/spi-fsl-dspi.c | ||
3 | * | ||
4 | * Copyright 2013 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Freescale DSPI driver | ||
7 | * This file contains a driver for the Freescale DSPI | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/spi/spi.h> | ||
27 | #include <linux/spi/spi_bitbang.h> | ||
28 | #include <linux/pm_runtime.h> | ||
29 | #include <linux/of.h> | ||
30 | #include <linux/of_device.h> | ||
31 | |||
32 | #define DRIVER_NAME "fsl-dspi" | ||
33 | |||
34 | #define TRAN_STATE_RX_VOID 0x01 | ||
35 | #define TRAN_STATE_TX_VOID 0x02 | ||
36 | #define TRAN_STATE_WORD_ODD_NUM 0x04 | ||
37 | |||
38 | #define DSPI_FIFO_SIZE 4 | ||
39 | |||
40 | #define SPI_MCR 0x00 | ||
41 | #define SPI_MCR_MASTER (1 << 31) | ||
42 | #define SPI_MCR_PCSIS (0x3F << 16) | ||
43 | #define SPI_MCR_CLR_TXF (1 << 11) | ||
44 | #define SPI_MCR_CLR_RXF (1 << 10) | ||
45 | |||
46 | #define SPI_TCR 0x08 | ||
47 | |||
48 | #define SPI_CTAR(x) (0x0c + (x * 4)) | ||
49 | #define SPI_CTAR_FMSZ(x) (((x) & 0x0000000f) << 27) | ||
50 | #define SPI_CTAR_CPOL(x) ((x) << 26) | ||
51 | #define SPI_CTAR_CPHA(x) ((x) << 25) | ||
52 | #define SPI_CTAR_LSBFE(x) ((x) << 24) | ||
53 | #define SPI_CTAR_PCSSCR(x) (((x) & 0x00000003) << 22) | ||
54 | #define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20) | ||
55 | #define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18) | ||
56 | #define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16) | ||
57 | #define SPI_CTAR_CSSCK(x) (((x) & 0x0000000f) << 12) | ||
58 | #define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8) | ||
59 | #define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4) | ||
60 | #define SPI_CTAR_BR(x) ((x) & 0x0000000f) | ||
61 | |||
62 | #define SPI_CTAR0_SLAVE 0x0c | ||
63 | |||
64 | #define SPI_SR 0x2c | ||
65 | #define SPI_SR_EOQF 0x10000000 | ||
66 | |||
67 | #define SPI_RSER 0x30 | ||
68 | #define SPI_RSER_EOQFE 0x10000000 | ||
69 | |||
70 | #define SPI_PUSHR 0x34 | ||
71 | #define SPI_PUSHR_CONT (1 << 31) | ||
72 | #define SPI_PUSHR_CTAS(x) (((x) & 0x00000007) << 28) | ||
73 | #define SPI_PUSHR_EOQ (1 << 27) | ||
74 | #define SPI_PUSHR_CTCNT (1 << 26) | ||
75 | #define SPI_PUSHR_PCS(x) (((1 << x) & 0x0000003f) << 16) | ||
76 | #define SPI_PUSHR_TXDATA(x) ((x) & 0x0000ffff) | ||
77 | |||
78 | #define SPI_PUSHR_SLAVE 0x34 | ||
79 | |||
80 | #define SPI_POPR 0x38 | ||
81 | #define SPI_POPR_RXDATA(x) ((x) & 0x0000ffff) | ||
82 | |||
83 | #define SPI_TXFR0 0x3c | ||
84 | #define SPI_TXFR1 0x40 | ||
85 | #define SPI_TXFR2 0x44 | ||
86 | #define SPI_TXFR3 0x48 | ||
87 | #define SPI_RXFR0 0x7c | ||
88 | #define SPI_RXFR1 0x80 | ||
89 | #define SPI_RXFR2 0x84 | ||
90 | #define SPI_RXFR3 0x88 | ||
91 | |||
92 | #define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1) | ||
93 | #define SPI_FRAME_BITS_MASK SPI_CTAR_FMSZ(0xf) | ||
94 | #define SPI_FRAME_BITS_16 SPI_CTAR_FMSZ(0xf) | ||
95 | #define SPI_FRAME_BITS_8 SPI_CTAR_FMSZ(0x7) | ||
96 | |||
97 | #define SPI_CS_INIT 0x01 | ||
98 | #define SPI_CS_ASSERT 0x02 | ||
99 | #define SPI_CS_DROP 0x04 | ||
100 | |||
101 | struct chip_data { | ||
102 | u32 mcr_val; | ||
103 | u32 ctar_val; | ||
104 | u16 void_write_data; | ||
105 | }; | ||
106 | |||
107 | struct fsl_dspi { | ||
108 | struct spi_bitbang bitbang; | ||
109 | struct platform_device *pdev; | ||
110 | |||
111 | void *base; | ||
112 | int irq; | ||
113 | struct clk *clk; | ||
114 | |||
115 | struct spi_transfer *cur_transfer; | ||
116 | struct chip_data *cur_chip; | ||
117 | size_t len; | ||
118 | void *tx; | ||
119 | void *tx_end; | ||
120 | void *rx; | ||
121 | void *rx_end; | ||
122 | char dataflags; | ||
123 | u8 cs; | ||
124 | u16 void_write_data; | ||
125 | |||
126 | wait_queue_head_t waitq; | ||
127 | u32 waitflags; | ||
128 | }; | ||
129 | |||
130 | static inline int is_double_byte_mode(struct fsl_dspi *dspi) | ||
131 | { | ||
132 | return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK) | ||
133 | == SPI_FRAME_BITS(8)) ? 0 : 1; | ||
134 | } | ||
135 | |||
136 | static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits) | ||
137 | { | ||
138 | u32 temp; | ||
139 | |||
140 | temp = readl(dspi->base + SPI_CTAR(dspi->cs)); | ||
141 | temp &= ~SPI_FRAME_BITS_MASK; | ||
142 | temp |= SPI_FRAME_BITS(bits); | ||
143 | writel(temp, dspi->base + SPI_CTAR(dspi->cs)); | ||
144 | } | ||
145 | |||
146 | static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, | ||
147 | unsigned long clkrate) | ||
148 | { | ||
149 | /* Valid baud rate pre-scaler values */ | ||
150 | int pbr_tbl[4] = {2, 3, 5, 7}; | ||
151 | int brs[16] = { 2, 4, 6, 8, | ||
152 | 16, 32, 64, 128, | ||
153 | 256, 512, 1024, 2048, | ||
154 | 4096, 8192, 16384, 32768 }; | ||
155 | int temp, i = 0, j = 0; | ||
156 | |||
157 | temp = clkrate / 2 / speed_hz; | ||
158 | |||
159 | for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++) | ||
160 | for (j = 0; j < ARRAY_SIZE(brs); j++) { | ||
161 | if (pbr_tbl[i] * brs[j] >= temp) { | ||
162 | *pbr = i; | ||
163 | *br = j; | ||
164 | return; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | pr_warn("Can not find valid buad rate,speed_hz is %d,clkrate is %ld\ | ||
169 | ,we use the max prescaler value.\n", speed_hz, clkrate); | ||
170 | *pbr = ARRAY_SIZE(pbr_tbl) - 1; | ||
171 | *br = ARRAY_SIZE(brs) - 1; | ||
172 | } | ||
173 | |||
174 | static int dspi_transfer_write(struct fsl_dspi *dspi) | ||
175 | { | ||
176 | int tx_count = 0; | ||
177 | int tx_word; | ||
178 | u16 d16; | ||
179 | u8 d8; | ||
180 | u32 dspi_pushr = 0; | ||
181 | int first = 1; | ||
182 | |||
183 | tx_word = is_double_byte_mode(dspi); | ||
184 | |||
185 | /* If we are in word mode, but only have a single byte to transfer | ||
186 | * then switch to byte mode temporarily. Will switch back at the | ||
187 | * end of the transfer. | ||
188 | */ | ||
189 | if (tx_word && (dspi->len == 1)) { | ||
190 | dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; | ||
191 | set_bit_mode(dspi, 8); | ||
192 | tx_word = 0; | ||
193 | } | ||
194 | |||
195 | while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) { | ||
196 | if (tx_word) { | ||
197 | if (dspi->len == 1) | ||
198 | break; | ||
199 | |||
200 | if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { | ||
201 | d16 = *(u16 *)dspi->tx; | ||
202 | dspi->tx += 2; | ||
203 | } else { | ||
204 | d16 = dspi->void_write_data; | ||
205 | } | ||
206 | |||
207 | dspi_pushr = SPI_PUSHR_TXDATA(d16) | | ||
208 | SPI_PUSHR_PCS(dspi->cs) | | ||
209 | SPI_PUSHR_CTAS(dspi->cs) | | ||
210 | SPI_PUSHR_CONT; | ||
211 | |||
212 | dspi->len -= 2; | ||
213 | } else { | ||
214 | if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { | ||
215 | |||
216 | d8 = *(u8 *)dspi->tx; | ||
217 | dspi->tx++; | ||
218 | } else { | ||
219 | d8 = (u8)dspi->void_write_data; | ||
220 | } | ||
221 | |||
222 | dspi_pushr = SPI_PUSHR_TXDATA(d8) | | ||
223 | SPI_PUSHR_PCS(dspi->cs) | | ||
224 | SPI_PUSHR_CTAS(dspi->cs) | | ||
225 | SPI_PUSHR_CONT; | ||
226 | |||
227 | dspi->len--; | ||
228 | } | ||
229 | |||
230 | if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) { | ||
231 | /* last transfer in the transfer */ | ||
232 | dspi_pushr |= SPI_PUSHR_EOQ; | ||
233 | } else if (tx_word && (dspi->len == 1)) | ||
234 | dspi_pushr |= SPI_PUSHR_EOQ; | ||
235 | |||
236 | if (first) { | ||
237 | first = 0; | ||
238 | dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */ | ||
239 | } | ||
240 | |||
241 | writel(dspi_pushr, dspi->base + SPI_PUSHR); | ||
242 | tx_count++; | ||
243 | } | ||
244 | |||
245 | return tx_count * (tx_word + 1); | ||
246 | } | ||
247 | |||
248 | static int dspi_transfer_read(struct fsl_dspi *dspi) | ||
249 | { | ||
250 | int rx_count = 0; | ||
251 | int rx_word = is_double_byte_mode(dspi); | ||
252 | u16 d; | ||
253 | while ((dspi->rx < dspi->rx_end) | ||
254 | && (rx_count < DSPI_FIFO_SIZE)) { | ||
255 | if (rx_word) { | ||
256 | if ((dspi->rx_end - dspi->rx) == 1) | ||
257 | break; | ||
258 | |||
259 | d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); | ||
260 | |||
261 | if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) | ||
262 | *(u16 *)dspi->rx = d; | ||
263 | dspi->rx += 2; | ||
264 | |||
265 | } else { | ||
266 | d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); | ||
267 | if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) | ||
268 | *(u8 *)dspi->rx = d; | ||
269 | dspi->rx++; | ||
270 | } | ||
271 | rx_count++; | ||
272 | } | ||
273 | |||
274 | return rx_count; | ||
275 | } | ||
276 | |||
277 | static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t) | ||
278 | { | ||
279 | struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); | ||
280 | dspi->cur_transfer = t; | ||
281 | dspi->cur_chip = spi_get_ctldata(spi); | ||
282 | dspi->cs = spi->chip_select; | ||
283 | dspi->void_write_data = dspi->cur_chip->void_write_data; | ||
284 | |||
285 | dspi->dataflags = 0; | ||
286 | dspi->tx = (void *)t->tx_buf; | ||
287 | dspi->tx_end = dspi->tx + t->len; | ||
288 | dspi->rx = t->rx_buf; | ||
289 | dspi->rx_end = dspi->rx + t->len; | ||
290 | dspi->len = t->len; | ||
291 | |||
292 | if (!dspi->rx) | ||
293 | dspi->dataflags |= TRAN_STATE_RX_VOID; | ||
294 | |||
295 | if (!dspi->tx) | ||
296 | dspi->dataflags |= TRAN_STATE_TX_VOID; | ||
297 | |||
298 | writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR); | ||
299 | writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs)); | ||
300 | writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER); | ||
301 | |||
302 | if (t->speed_hz) | ||
303 | writel(dspi->cur_chip->ctar_val, | ||
304 | dspi->base + SPI_CTAR(dspi->cs)); | ||
305 | |||
306 | dspi_transfer_write(dspi); | ||
307 | |||
308 | if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) | ||
309 | dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); | ||
310 | dspi->waitflags = 0; | ||
311 | |||
312 | return t->len - dspi->len; | ||
313 | } | ||
314 | |||
315 | static void dspi_chipselect(struct spi_device *spi, int value) | ||
316 | { | ||
317 | struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); | ||
318 | u32 pushr = readl(dspi->base + SPI_PUSHR); | ||
319 | |||
320 | switch (value) { | ||
321 | case BITBANG_CS_ACTIVE: | ||
322 | pushr |= SPI_PUSHR_CONT; | ||
323 | case BITBANG_CS_INACTIVE: | ||
324 | pushr &= ~SPI_PUSHR_CONT; | ||
325 | } | ||
326 | |||
327 | writel(pushr, dspi->base + SPI_PUSHR); | ||
328 | } | ||
329 | |||
330 | static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) | ||
331 | { | ||
332 | struct chip_data *chip; | ||
333 | struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); | ||
334 | unsigned char br = 0, pbr = 0, fmsz = 0; | ||
335 | |||
336 | /* Only alloc on first setup */ | ||
337 | chip = spi_get_ctldata(spi); | ||
338 | if (chip == NULL) { | ||
339 | chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL); | ||
340 | if (!chip) | ||
341 | return -ENOMEM; | ||
342 | } | ||
343 | |||
344 | chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS | | ||
345 | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; | ||
346 | if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) { | ||
347 | fmsz = spi->bits_per_word - 1; | ||
348 | } else { | ||
349 | pr_err("Invalid wordsize\n"); | ||
350 | kfree(chip); | ||
351 | return -ENODEV; | ||
352 | } | ||
353 | |||
354 | chip->void_write_data = 0; | ||
355 | |||
356 | hz_to_spi_baud(&pbr, &br, | ||
357 | spi->max_speed_hz, clk_get_rate(dspi->clk)); | ||
358 | |||
359 | chip->ctar_val = SPI_CTAR_FMSZ(fmsz) | ||
360 | | SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0) | ||
361 | | SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0) | ||
362 | | SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0) | ||
363 | | SPI_CTAR_PBR(pbr) | ||
364 | | SPI_CTAR_BR(br); | ||
365 | |||
366 | spi_set_ctldata(spi, chip); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int dspi_setup(struct spi_device *spi) | ||
372 | { | ||
373 | if (!spi->max_speed_hz) | ||
374 | return -EINVAL; | ||
375 | |||
376 | if (!spi->bits_per_word) | ||
377 | spi->bits_per_word = 8; | ||
378 | |||
379 | return dspi_setup_transfer(spi, NULL); | ||
380 | } | ||
381 | |||
382 | static irqreturn_t dspi_interrupt(int irq, void *dev_id) | ||
383 | { | ||
384 | struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; | ||
385 | |||
386 | writel(SPI_SR_EOQF, dspi->base + SPI_SR); | ||
387 | |||
388 | dspi_transfer_read(dspi); | ||
389 | |||
390 | if (!dspi->len) { | ||
391 | if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) | ||
392 | set_bit_mode(dspi, 16); | ||
393 | dspi->waitflags = 1; | ||
394 | wake_up_interruptible(&dspi->waitq); | ||
395 | } else { | ||
396 | dspi_transfer_write(dspi); | ||
397 | |||
398 | return IRQ_HANDLED; | ||
399 | } | ||
400 | |||
401 | return IRQ_HANDLED; | ||
402 | } | ||
403 | |||
404 | static struct of_device_id fsl_dspi_dt_ids[] = { | ||
405 | { .compatible = "fsl,vf610-dspi", .data = NULL, }, | ||
406 | { /* sentinel */ } | ||
407 | }; | ||
408 | MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids); | ||
409 | |||
410 | #ifdef CONFIG_PM_SLEEP | ||
411 | static int dspi_suspend(struct device *dev) | ||
412 | { | ||
413 | struct spi_master *master = dev_get_drvdata(dev); | ||
414 | struct fsl_dspi *dspi = spi_master_get_devdata(master); | ||
415 | |||
416 | spi_master_suspend(master); | ||
417 | clk_disable_unprepare(dspi->clk); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int dspi_resume(struct device *dev) | ||
423 | { | ||
424 | |||
425 | struct spi_master *master = dev_get_drvdata(dev); | ||
426 | struct fsl_dspi *dspi = spi_master_get_devdata(master); | ||
427 | |||
428 | clk_prepare_enable(dspi->clk); | ||
429 | spi_master_resume(master); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | #endif /* CONFIG_PM_SLEEP */ | ||
434 | |||
435 | static const struct dev_pm_ops dspi_pm = { | ||
436 | SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume) | ||
437 | }; | ||
438 | |||
439 | static int dspi_probe(struct platform_device *pdev) | ||
440 | { | ||
441 | struct device_node *np = pdev->dev.of_node; | ||
442 | struct spi_master *master; | ||
443 | struct fsl_dspi *dspi; | ||
444 | struct resource *res; | ||
445 | int ret = 0, cs_num, bus_num; | ||
446 | |||
447 | master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); | ||
448 | if (!master) | ||
449 | return -ENOMEM; | ||
450 | |||
451 | dspi = spi_master_get_devdata(master); | ||
452 | dspi->pdev = pdev; | ||
453 | dspi->bitbang.master = spi_master_get(master); | ||
454 | dspi->bitbang.chipselect = dspi_chipselect; | ||
455 | dspi->bitbang.setup_transfer = dspi_setup_transfer; | ||
456 | dspi->bitbang.txrx_bufs = dspi_txrx_transfer; | ||
457 | dspi->bitbang.master->setup = dspi_setup; | ||
458 | dspi->bitbang.master->dev.of_node = pdev->dev.of_node; | ||
459 | |||
460 | master->mode_bits = SPI_CPOL | SPI_CPHA; | ||
461 | master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) | | ||
462 | SPI_BPW_MASK(16); | ||
463 | |||
464 | ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num); | ||
465 | if (ret < 0) { | ||
466 | dev_err(&pdev->dev, "can't get spi-num-chipselects\n"); | ||
467 | goto out_master_put; | ||
468 | } | ||
469 | master->num_chipselect = cs_num; | ||
470 | |||
471 | ret = of_property_read_u32(np, "bus-num", &bus_num); | ||
472 | if (ret < 0) { | ||
473 | dev_err(&pdev->dev, "can't get bus-num\n"); | ||
474 | goto out_master_put; | ||
475 | } | ||
476 | master->bus_num = bus_num; | ||
477 | |||
478 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
479 | if (!res) { | ||
480 | dev_err(&pdev->dev, "can't get platform resource\n"); | ||
481 | ret = -EINVAL; | ||
482 | goto out_master_put; | ||
483 | } | ||
484 | |||
485 | dspi->base = devm_ioremap_resource(&pdev->dev, res); | ||
486 | if (!dspi->base) { | ||
487 | ret = -EINVAL; | ||
488 | goto out_master_put; | ||
489 | } | ||
490 | |||
491 | dspi->irq = platform_get_irq(pdev, 0); | ||
492 | if (dspi->irq < 0) { | ||
493 | dev_err(&pdev->dev, "can't get platform irq\n"); | ||
494 | ret = dspi->irq; | ||
495 | goto out_master_put; | ||
496 | } | ||
497 | |||
498 | ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, 0, | ||
499 | pdev->name, dspi); | ||
500 | if (ret < 0) { | ||
501 | dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n"); | ||
502 | goto out_master_put; | ||
503 | } | ||
504 | |||
505 | dspi->clk = devm_clk_get(&pdev->dev, "dspi"); | ||
506 | if (IS_ERR(dspi->clk)) { | ||
507 | ret = PTR_ERR(dspi->clk); | ||
508 | dev_err(&pdev->dev, "unable to get clock\n"); | ||
509 | goto out_master_put; | ||
510 | } | ||
511 | clk_prepare_enable(dspi->clk); | ||
512 | |||
513 | init_waitqueue_head(&dspi->waitq); | ||
514 | platform_set_drvdata(pdev, dspi); | ||
515 | |||
516 | ret = spi_bitbang_start(&dspi->bitbang); | ||
517 | if (ret != 0) { | ||
518 | dev_err(&pdev->dev, "Problem registering DSPI master\n"); | ||
519 | goto out_clk_put; | ||
520 | } | ||
521 | |||
522 | pr_info(KERN_INFO "Freescale DSPI master initialized\n"); | ||
523 | return ret; | ||
524 | |||
525 | out_clk_put: | ||
526 | clk_disable_unprepare(dspi->clk); | ||
527 | out_master_put: | ||
528 | spi_master_put(master); | ||
529 | platform_set_drvdata(pdev, NULL); | ||
530 | |||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | static int dspi_remove(struct platform_device *pdev) | ||
535 | { | ||
536 | struct fsl_dspi *dspi = platform_get_drvdata(pdev); | ||
537 | |||
538 | /* Disconnect from the SPI framework */ | ||
539 | spi_bitbang_stop(&dspi->bitbang); | ||
540 | spi_master_put(dspi->bitbang.master); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static struct platform_driver fsl_dspi_driver = { | ||
546 | .driver.name = DRIVER_NAME, | ||
547 | .driver.of_match_table = fsl_dspi_dt_ids, | ||
548 | .driver.owner = THIS_MODULE, | ||
549 | .driver.pm = &dspi_pm, | ||
550 | .probe = dspi_probe, | ||
551 | .remove = dspi_remove, | ||
552 | }; | ||
553 | module_platform_driver(fsl_dspi_driver); | ||
554 | |||
555 | MODULE_DESCRIPTION("Freescale DSPI Controller Driver"); | ||
556 | MODULE_LICENSE("GPL v2"); | ||
557 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||