Commit | Line | Data |
---|---|---|
9ac8d176 CD |
1 | // SPDX-License-Identifier: (GPL-2.0) |
2 | /* | |
3 | * Microchip CoreSPI SPI controller driver | |
4 | * | |
5 | * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries | |
6 | * | |
7 | * Author: Daire McNamara <daire.mcnamara@microchip.com> | |
8 | * Author: Conor Dooley <conor.dooley@microchip.com> | |
9 | * | |
10 | */ | |
11 | ||
12 | #include <linux/clk.h> | |
13 | #include <linux/delay.h> | |
14 | #include <linux/err.h> | |
15 | #include <linux/init.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/io.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/of.h> | |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/spi/spi.h> | |
22 | ||
23 | #define MAX_LEN (0xffff) | |
24 | #define MAX_CS (8) | |
25 | #define DEFAULT_FRAMESIZE (8) | |
26 | #define FIFO_DEPTH (32) | |
27 | #define CLK_GEN_MODE1_MAX (255) | |
28 | #define CLK_GEN_MODE0_MAX (15) | |
29 | #define CLK_GEN_MIN (0) | |
30 | #define MODE_X_MASK_SHIFT (24) | |
31 | ||
32 | #define CONTROL_ENABLE BIT(0) | |
33 | #define CONTROL_MASTER BIT(1) | |
34 | #define CONTROL_RX_DATA_INT BIT(4) | |
35 | #define CONTROL_TX_DATA_INT BIT(5) | |
36 | #define CONTROL_RX_OVER_INT BIT(6) | |
37 | #define CONTROL_TX_UNDER_INT BIT(7) | |
38 | #define CONTROL_SPO BIT(24) | |
39 | #define CONTROL_SPH BIT(25) | |
40 | #define CONTROL_SPS BIT(26) | |
41 | #define CONTROL_FRAMEURUN BIT(27) | |
42 | #define CONTROL_CLKMODE BIT(28) | |
43 | #define CONTROL_BIGFIFO BIT(29) | |
44 | #define CONTROL_OENOFF BIT(30) | |
45 | #define CONTROL_RESET BIT(31) | |
46 | ||
47 | #define CONTROL_MODE_MASK GENMASK(3, 2) | |
48 | #define MOTOROLA_MODE (0) | |
49 | #define CONTROL_FRAMECNT_MASK GENMASK(23, 8) | |
50 | #define CONTROL_FRAMECNT_SHIFT (8) | |
51 | ||
52 | #define STATUS_ACTIVE BIT(14) | |
53 | #define STATUS_SSEL BIT(13) | |
54 | #define STATUS_FRAMESTART BIT(12) | |
55 | #define STATUS_TXFIFO_EMPTY_NEXT_READ BIT(11) | |
56 | #define STATUS_TXFIFO_EMPTY BIT(10) | |
57 | #define STATUS_TXFIFO_FULL_NEXT_WRITE BIT(9) | |
58 | #define STATUS_TXFIFO_FULL BIT(8) | |
59 | #define STATUS_RXFIFO_EMPTY_NEXT_READ BIT(7) | |
60 | #define STATUS_RXFIFO_EMPTY BIT(6) | |
61 | #define STATUS_RXFIFO_FULL_NEXT_WRITE BIT(5) | |
62 | #define STATUS_RXFIFO_FULL BIT(4) | |
63 | #define STATUS_TX_UNDERRUN BIT(3) | |
64 | #define STATUS_RX_OVERFLOW BIT(2) | |
65 | #define STATUS_RXDAT_RXED BIT(1) | |
66 | #define STATUS_TXDAT_SENT BIT(0) | |
67 | ||
68 | #define INT_TXDONE BIT(0) | |
69 | #define INT_RXRDY BIT(1) | |
70 | #define INT_RX_CHANNEL_OVERFLOW BIT(2) | |
71 | #define INT_TX_CHANNEL_UNDERRUN BIT(3) | |
72 | ||
73 | #define INT_ENABLE_MASK (CONTROL_RX_DATA_INT | CONTROL_TX_DATA_INT | \ | |
74 | CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT) | |
75 | ||
76 | #define REG_CONTROL (0x00) | |
77 | #define REG_FRAME_SIZE (0x04) | |
78 | #define REG_STATUS (0x08) | |
79 | #define REG_INT_CLEAR (0x0c) | |
80 | #define REG_RX_DATA (0x10) | |
81 | #define REG_TX_DATA (0x14) | |
82 | #define REG_CLK_GEN (0x18) | |
83 | #define REG_SLAVE_SELECT (0x1c) | |
84 | #define SSEL_MASK GENMASK(7, 0) | |
85 | #define SSEL_DIRECT BIT(8) | |
86 | #define SSELOUT_SHIFT 9 | |
87 | #define SSELOUT BIT(SSELOUT_SHIFT) | |
88 | #define REG_MIS (0x20) | |
89 | #define REG_RIS (0x24) | |
90 | #define REG_CONTROL2 (0x28) | |
91 | #define REG_COMMAND (0x2c) | |
92 | #define REG_PKTSIZE (0x30) | |
93 | #define REG_CMD_SIZE (0x34) | |
94 | #define REG_HWSTATUS (0x38) | |
95 | #define REG_STAT8 (0x3c) | |
96 | #define REG_CTRL2 (0x48) | |
97 | #define REG_FRAMESUP (0x50) | |
98 | ||
99 | struct mchp_corespi { | |
100 | void __iomem *regs; | |
101 | struct clk *clk; | |
102 | const u8 *tx_buf; | |
103 | u8 *rx_buf; | |
104 | u32 clk_gen; /* divider for spi output clock generated by the controller */ | |
105 | u32 clk_mode; | |
106 | int irq; | |
107 | int tx_len; | |
108 | int rx_len; | |
109 | int pending; | |
110 | }; | |
111 | ||
112 | static inline u32 mchp_corespi_read(struct mchp_corespi *spi, unsigned int reg) | |
113 | { | |
114 | return readl(spi->regs + reg); | |
115 | } | |
116 | ||
117 | static inline void mchp_corespi_write(struct mchp_corespi *spi, unsigned int reg, u32 val) | |
118 | { | |
119 | writel(val, spi->regs + reg); | |
120 | } | |
121 | ||
9ac8d176 CD |
122 | static inline void mchp_corespi_disable(struct mchp_corespi *spi) |
123 | { | |
124 | u32 control = mchp_corespi_read(spi, REG_CONTROL); | |
125 | ||
126 | control &= ~CONTROL_ENABLE; | |
127 | ||
128 | mchp_corespi_write(spi, REG_CONTROL, control); | |
129 | } | |
130 | ||
131 | static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi) | |
132 | { | |
133 | u8 data; | |
134 | int fifo_max, i = 0; | |
135 | ||
136 | fifo_max = min(spi->rx_len, FIFO_DEPTH); | |
137 | ||
138 | while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)) { | |
139 | data = mchp_corespi_read(spi, REG_RX_DATA); | |
140 | ||
141 | if (spi->rx_buf) | |
142 | *spi->rx_buf++ = data; | |
143 | i++; | |
144 | } | |
145 | spi->rx_len -= i; | |
146 | spi->pending -= i; | |
147 | } | |
148 | ||
149 | static void mchp_corespi_enable_ints(struct mchp_corespi *spi) | |
150 | { | |
151 | u32 control, mask = INT_ENABLE_MASK; | |
152 | ||
153 | mchp_corespi_disable(spi); | |
154 | ||
155 | control = mchp_corespi_read(spi, REG_CONTROL); | |
156 | ||
157 | control |= mask; | |
158 | mchp_corespi_write(spi, REG_CONTROL, control); | |
159 | ||
160 | control |= CONTROL_ENABLE; | |
161 | mchp_corespi_write(spi, REG_CONTROL, control); | |
162 | } | |
163 | ||
164 | static void mchp_corespi_disable_ints(struct mchp_corespi *spi) | |
165 | { | |
166 | u32 control, mask = INT_ENABLE_MASK; | |
167 | ||
168 | mchp_corespi_disable(spi); | |
169 | ||
170 | control = mchp_corespi_read(spi, REG_CONTROL); | |
171 | control &= ~mask; | |
172 | mchp_corespi_write(spi, REG_CONTROL, control); | |
173 | ||
174 | control |= CONTROL_ENABLE; | |
175 | mchp_corespi_write(spi, REG_CONTROL, control); | |
176 | } | |
177 | ||
178 | static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len) | |
179 | { | |
180 | u32 control; | |
181 | u16 lenpart; | |
182 | ||
183 | /* | |
184 | * Disable the SPI controller. Writes to transfer length have | |
185 | * no effect when the controller is enabled. | |
186 | */ | |
187 | mchp_corespi_disable(spi); | |
188 | ||
189 | /* | |
190 | * The lower 16 bits of the frame count are stored in the control reg | |
191 | * for legacy reasons, but the upper 16 written to a different register: | |
192 | * FRAMESUP. While both the upper and lower bits can be *READ* from the | |
193 | * FRAMESUP register, writing to the lower 16 bits is a NOP | |
194 | */ | |
195 | lenpart = len & 0xffff; | |
196 | ||
197 | control = mchp_corespi_read(spi, REG_CONTROL); | |
198 | control &= ~CONTROL_FRAMECNT_MASK; | |
199 | control |= lenpart << CONTROL_FRAMECNT_SHIFT; | |
200 | mchp_corespi_write(spi, REG_CONTROL, control); | |
201 | ||
202 | lenpart = len & 0xffff0000; | |
203 | mchp_corespi_write(spi, REG_FRAMESUP, lenpart); | |
204 | ||
205 | control |= CONTROL_ENABLE; | |
206 | mchp_corespi_write(spi, REG_CONTROL, control); | |
207 | } | |
208 | ||
209 | static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi) | |
210 | { | |
211 | u8 byte; | |
212 | int fifo_max, i = 0; | |
213 | ||
214 | fifo_max = min(spi->tx_len, FIFO_DEPTH); | |
215 | mchp_corespi_set_xfer_size(spi, fifo_max); | |
216 | ||
217 | while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) { | |
218 | byte = spi->tx_buf ? *spi->tx_buf++ : 0xaa; | |
219 | mchp_corespi_write(spi, REG_TX_DATA, byte); | |
220 | i++; | |
221 | } | |
222 | ||
223 | spi->tx_len -= i; | |
224 | spi->pending += i; | |
225 | } | |
226 | ||
227 | static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt) | |
228 | { | |
229 | u32 control; | |
230 | ||
231 | /* | |
232 | * Disable the SPI controller. Writes to the frame size have | |
233 | * no effect when the controller is enabled. | |
234 | */ | |
235 | mchp_corespi_disable(spi); | |
236 | ||
237 | mchp_corespi_write(spi, REG_FRAME_SIZE, bt); | |
238 | ||
239 | control = mchp_corespi_read(spi, REG_CONTROL); | |
240 | control |= CONTROL_ENABLE; | |
241 | mchp_corespi_write(spi, REG_CONTROL, control); | |
242 | } | |
243 | ||
244 | static void mchp_corespi_set_cs(struct spi_device *spi, bool disable) | |
245 | { | |
246 | u32 reg; | |
8f8bf52e | 247 | struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); |
9ac8d176 CD |
248 | |
249 | reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT); | |
9e264f3f AKMA |
250 | reg &= ~BIT(spi_get_chipselect(spi, 0)); |
251 | reg |= !disable << spi_get_chipselect(spi, 0); | |
9ac8d176 CD |
252 | |
253 | mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg); | |
254 | } | |
255 | ||
256 | static int mchp_corespi_setup(struct spi_device *spi) | |
257 | { | |
8f8bf52e | 258 | struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); |
9ac8d176 CD |
259 | u32 reg; |
260 | ||
261 | /* | |
8f8bf52e | 262 | * Active high targets need to be specifically set to their inactive |
9ac8d176 CD |
263 | * states during probe by adding them to the "control group" & thus |
264 | * driving their select line low. | |
265 | */ | |
266 | if (spi->mode & SPI_CS_HIGH) { | |
267 | reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT); | |
9e264f3f | 268 | reg |= BIT(spi_get_chipselect(spi, 0)); |
9ac8d176 CD |
269 | mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg); |
270 | } | |
271 | return 0; | |
272 | } | |
273 | ||
8f8bf52e | 274 | static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *spi) |
9ac8d176 CD |
275 | { |
276 | unsigned long clk_hz; | |
277 | u32 control = mchp_corespi_read(spi, REG_CONTROL); | |
278 | ||
279 | control |= CONTROL_MASTER; | |
280 | ||
281 | control &= ~CONTROL_MODE_MASK; | |
282 | control |= MOTOROLA_MODE; | |
283 | ||
284 | mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE); | |
285 | ||
286 | /* max. possible spi clock rate is the apb clock rate */ | |
287 | clk_hz = clk_get_rate(spi->clk); | |
8f8bf52e | 288 | host->max_speed_hz = clk_hz; |
9ac8d176 CD |
289 | |
290 | /* | |
291 | * The controller must be configured so that it doesn't remove Chip | |
292 | * Select until the entire message has been transferred, even if at | |
293 | * some points TX FIFO becomes empty. | |
294 | * | |
295 | * BIGFIFO mode is also enabled, which sets the fifo depth to 32 frames | |
296 | * for the 8 bit transfers that this driver uses. | |
297 | */ | |
298 | control = mchp_corespi_read(spi, REG_CONTROL); | |
299 | control |= CONTROL_SPS | CONTROL_BIGFIFO; | |
300 | ||
301 | mchp_corespi_write(spi, REG_CONTROL, control); | |
302 | ||
303 | mchp_corespi_enable_ints(spi); | |
304 | ||
305 | /* | |
306 | * It is required to enable direct mode, otherwise control over the chip | |
307 | * select is relinquished to the hardware. SSELOUT is enabled too so we | |
8f8bf52e | 308 | * can deal with active high targets. |
9ac8d176 CD |
309 | */ |
310 | mchp_corespi_write(spi, REG_SLAVE_SELECT, SSELOUT | SSEL_DIRECT); | |
311 | ||
312 | control = mchp_corespi_read(spi, REG_CONTROL); | |
313 | ||
314 | control &= ~CONTROL_RESET; | |
315 | control |= CONTROL_ENABLE; | |
316 | ||
317 | mchp_corespi_write(spi, REG_CONTROL, control); | |
318 | } | |
319 | ||
320 | static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi) | |
321 | { | |
322 | u32 control; | |
323 | ||
324 | mchp_corespi_disable(spi); | |
325 | ||
326 | control = mchp_corespi_read(spi, REG_CONTROL); | |
327 | if (spi->clk_mode) | |
328 | control |= CONTROL_CLKMODE; | |
329 | else | |
330 | control &= ~CONTROL_CLKMODE; | |
331 | ||
332 | mchp_corespi_write(spi, REG_CLK_GEN, spi->clk_gen); | |
333 | mchp_corespi_write(spi, REG_CONTROL, control); | |
334 | mchp_corespi_write(spi, REG_CONTROL, control | CONTROL_ENABLE); | |
335 | } | |
336 | ||
337 | static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int mode) | |
338 | { | |
339 | u32 control, mode_val; | |
340 | ||
341 | switch (mode & SPI_MODE_X_MASK) { | |
342 | case SPI_MODE_0: | |
343 | mode_val = 0; | |
344 | break; | |
345 | case SPI_MODE_1: | |
346 | mode_val = CONTROL_SPH; | |
347 | break; | |
348 | case SPI_MODE_2: | |
349 | mode_val = CONTROL_SPO; | |
350 | break; | |
351 | case SPI_MODE_3: | |
352 | mode_val = CONTROL_SPH | CONTROL_SPO; | |
353 | break; | |
354 | } | |
355 | ||
356 | /* | |
357 | * Disable the SPI controller. Writes to the frame size have | |
358 | * no effect when the controller is enabled. | |
359 | */ | |
360 | mchp_corespi_disable(spi); | |
361 | ||
362 | control = mchp_corespi_read(spi, REG_CONTROL); | |
363 | control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT); | |
364 | control |= mode_val; | |
365 | ||
366 | mchp_corespi_write(spi, REG_CONTROL, control); | |
367 | ||
368 | control |= CONTROL_ENABLE; | |
369 | mchp_corespi_write(spi, REG_CONTROL, control); | |
370 | } | |
371 | ||
372 | static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) | |
373 | { | |
8f8bf52e YY |
374 | struct spi_controller *host = dev_id; |
375 | struct mchp_corespi *spi = spi_controller_get_devdata(host); | |
9ac8d176 CD |
376 | u32 intfield = mchp_corespi_read(spi, REG_MIS) & 0xf; |
377 | bool finalise = false; | |
378 | ||
379 | /* Interrupt line may be shared and not for us at all */ | |
380 | if (intfield == 0) | |
381 | return IRQ_NONE; | |
382 | ||
383 | if (intfield & INT_TXDONE) { | |
384 | mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE); | |
385 | ||
386 | if (spi->rx_len) | |
387 | mchp_corespi_read_fifo(spi); | |
388 | ||
389 | if (spi->tx_len) | |
390 | mchp_corespi_write_fifo(spi); | |
391 | ||
392 | if (!spi->rx_len) | |
393 | finalise = true; | |
394 | } | |
395 | ||
396 | if (intfield & INT_RXRDY) | |
397 | mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY); | |
398 | ||
399 | if (intfield & INT_RX_CHANNEL_OVERFLOW) { | |
400 | mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW); | |
401 | finalise = true; | |
8f8bf52e | 402 | dev_err(&host->dev, |
9ac8d176 CD |
403 | "%s: RX OVERFLOW: rxlen: %d, txlen: %d\n", __func__, |
404 | spi->rx_len, spi->tx_len); | |
405 | } | |
406 | ||
407 | if (intfield & INT_TX_CHANNEL_UNDERRUN) { | |
408 | mchp_corespi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN); | |
409 | finalise = true; | |
8f8bf52e | 410 | dev_err(&host->dev, |
9ac8d176 CD |
411 | "%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n", __func__, |
412 | spi->rx_len, spi->tx_len); | |
413 | } | |
414 | ||
415 | if (finalise) | |
8f8bf52e | 416 | spi_finalize_current_transfer(host); |
9ac8d176 CD |
417 | |
418 | return IRQ_HANDLED; | |
419 | } | |
420 | ||
421 | static int mchp_corespi_calculate_clkgen(struct mchp_corespi *spi, | |
422 | unsigned long target_hz) | |
423 | { | |
424 | unsigned long clk_hz, spi_hz, clk_gen; | |
425 | ||
426 | clk_hz = clk_get_rate(spi->clk); | |
2081ad14 CD |
427 | if (!clk_hz) |
428 | return -EINVAL; | |
9ac8d176 CD |
429 | spi_hz = min(target_hz, clk_hz); |
430 | ||
431 | /* | |
432 | * There are two possible clock modes for the controller generated | |
433 | * clock's division ratio: | |
434 | * CLK_MODE = 0: 1 / (2^(CLK_GEN + 1)) where CLK_GEN = 0 to 15. | |
435 | * CLK_MODE = 1: 1 / (2 * CLK_GEN + 1) where CLK_GEN = 0 to 255. | |
436 | * First try mode 1, fall back to 0 and if we have tried both modes and | |
437 | * we /still/ can't get a good setting, we then throw the toys out of | |
438 | * the pram and give up | |
439 | * clk_gen is the register name for the clock divider on MPFS. | |
440 | */ | |
441 | clk_gen = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1; | |
442 | if (clk_gen > CLK_GEN_MODE1_MAX || clk_gen <= CLK_GEN_MIN) { | |
443 | clk_gen = DIV_ROUND_UP(clk_hz, spi_hz); | |
444 | clk_gen = fls(clk_gen) - 1; | |
445 | ||
446 | if (clk_gen > CLK_GEN_MODE0_MAX) | |
447 | return -EINVAL; | |
448 | ||
449 | spi->clk_mode = 0; | |
450 | } else { | |
451 | spi->clk_mode = 1; | |
452 | } | |
453 | ||
454 | spi->clk_gen = clk_gen; | |
455 | return 0; | |
456 | } | |
457 | ||
8f8bf52e | 458 | static int mchp_corespi_transfer_one(struct spi_controller *host, |
9ac8d176 CD |
459 | struct spi_device *spi_dev, |
460 | struct spi_transfer *xfer) | |
461 | { | |
8f8bf52e | 462 | struct mchp_corespi *spi = spi_controller_get_devdata(host); |
9ac8d176 CD |
463 | int ret; |
464 | ||
465 | ret = mchp_corespi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz); | |
466 | if (ret) { | |
8f8bf52e | 467 | dev_err(&host->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz); |
9ac8d176 CD |
468 | return ret; |
469 | } | |
470 | ||
471 | mchp_corespi_set_clk_gen(spi); | |
472 | ||
473 | spi->tx_buf = xfer->tx_buf; | |
474 | spi->rx_buf = xfer->rx_buf; | |
475 | spi->tx_len = xfer->len; | |
476 | spi->rx_len = xfer->len; | |
477 | spi->pending = 0; | |
478 | ||
479 | mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH) | |
480 | ? FIFO_DEPTH : spi->tx_len); | |
481 | ||
482 | if (spi->tx_len) | |
483 | mchp_corespi_write_fifo(spi); | |
484 | return 1; | |
485 | } | |
486 | ||
8f8bf52e | 487 | static int mchp_corespi_prepare_message(struct spi_controller *host, |
9ac8d176 CD |
488 | struct spi_message *msg) |
489 | { | |
490 | struct spi_device *spi_dev = msg->spi; | |
8f8bf52e | 491 | struct mchp_corespi *spi = spi_controller_get_devdata(host); |
9ac8d176 CD |
492 | |
493 | mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE); | |
494 | mchp_corespi_set_mode(spi, spi_dev->mode); | |
495 | ||
496 | return 0; | |
497 | } | |
498 | ||
499 | static int mchp_corespi_probe(struct platform_device *pdev) | |
500 | { | |
8f8bf52e | 501 | struct spi_controller *host; |
9ac8d176 CD |
502 | struct mchp_corespi *spi; |
503 | struct resource *res; | |
504 | u32 num_cs; | |
505 | int ret = 0; | |
506 | ||
8f8bf52e YY |
507 | host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi)); |
508 | if (!host) | |
9ac8d176 | 509 | return dev_err_probe(&pdev->dev, -ENOMEM, |
8f8bf52e | 510 | "unable to allocate host for SPI controller\n"); |
9ac8d176 | 511 | |
8f8bf52e | 512 | platform_set_drvdata(pdev, host); |
9ac8d176 CD |
513 | |
514 | if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs)) | |
515 | num_cs = MAX_CS; | |
516 | ||
8f8bf52e YY |
517 | host->num_chipselect = num_cs; |
518 | host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; | |
519 | host->setup = mchp_corespi_setup; | |
520 | host->bits_per_word_mask = SPI_BPW_MASK(8); | |
521 | host->transfer_one = mchp_corespi_transfer_one; | |
522 | host->prepare_message = mchp_corespi_prepare_message; | |
523 | host->set_cs = mchp_corespi_set_cs; | |
524 | host->dev.of_node = pdev->dev.of_node; | |
9ac8d176 | 525 | |
8f8bf52e | 526 | spi = spi_controller_get_devdata(host); |
9ac8d176 CD |
527 | |
528 | spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); | |
5d56d897 YY |
529 | if (IS_ERR(spi->regs)) |
530 | return PTR_ERR(spi->regs); | |
9ac8d176 CD |
531 | |
532 | spi->irq = platform_get_irq(pdev, 0); | |
71ee2a4f CJ |
533 | if (spi->irq < 0) |
534 | return spi->irq; | |
9ac8d176 CD |
535 | |
536 | ret = devm_request_irq(&pdev->dev, spi->irq, mchp_corespi_interrupt, | |
8f8bf52e | 537 | IRQF_SHARED, dev_name(&pdev->dev), host); |
cdeaf3a9 YY |
538 | if (ret) |
539 | return dev_err_probe(&pdev->dev, ret, | |
7964e817 | 540 | "could not request irq\n"); |
9ac8d176 | 541 | |
605204fc | 542 | spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); |
cdeaf3a9 YY |
543 | if (IS_ERR(spi->clk)) |
544 | return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), | |
7964e817 | 545 | "could not get clk\n"); |
9ac8d176 | 546 | |
8f8bf52e | 547 | mchp_corespi_init(host, spi); |
9ac8d176 | 548 | |
8f8bf52e | 549 | ret = devm_spi_register_controller(&pdev->dev, host); |
9ac8d176 | 550 | if (ret) { |
cdeaf3a9 | 551 | mchp_corespi_disable(spi); |
cdeaf3a9 | 552 | return dev_err_probe(&pdev->dev, ret, |
8f8bf52e | 553 | "unable to register host for SPI controller\n"); |
9ac8d176 CD |
554 | } |
555 | ||
8f8bf52e | 556 | dev_info(&pdev->dev, "Registered SPI controller %d\n", host->bus_num); |
9ac8d176 CD |
557 | |
558 | return 0; | |
9ac8d176 CD |
559 | } |
560 | ||
beb6ed0f | 561 | static void mchp_corespi_remove(struct platform_device *pdev) |
9ac8d176 | 562 | { |
8f8bf52e YY |
563 | struct spi_controller *host = platform_get_drvdata(pdev); |
564 | struct mchp_corespi *spi = spi_controller_get_devdata(host); | |
9ac8d176 CD |
565 | |
566 | mchp_corespi_disable_ints(spi); | |
9ac8d176 | 567 | mchp_corespi_disable(spi); |
9ac8d176 CD |
568 | } |
569 | ||
570 | #define MICROCHIP_SPI_PM_OPS (NULL) | |
571 | ||
572 | /* | |
573 | * Platform driver data structure | |
574 | */ | |
575 | ||
576 | #if defined(CONFIG_OF) | |
577 | static const struct of_device_id mchp_corespi_dt_ids[] = { | |
578 | { .compatible = "microchip,mpfs-spi" }, | |
579 | { /* sentinel */ } | |
580 | }; | |
581 | MODULE_DEVICE_TABLE(of, mchp_corespi_dt_ids); | |
582 | #endif | |
583 | ||
584 | static struct platform_driver mchp_corespi_driver = { | |
585 | .probe = mchp_corespi_probe, | |
586 | .driver = { | |
587 | .name = "microchip-corespi", | |
588 | .pm = MICROCHIP_SPI_PM_OPS, | |
589 | .of_match_table = of_match_ptr(mchp_corespi_dt_ids), | |
9ac8d176 | 590 | }, |
beb6ed0f | 591 | .remove_new = mchp_corespi_remove, |
9ac8d176 CD |
592 | }; |
593 | module_platform_driver(mchp_corespi_driver); | |
594 | MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver"); | |
595 | MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>"); | |
596 | MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>"); | |
597 | MODULE_LICENSE("GPL"); |