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(addr: 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, addr: spi->regs + reg); |
120 | } |
121 | |
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, val: 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, val: control); |
159 | |
160 | control |= CONTROL_ENABLE; |
161 | mchp_corespi_write(spi, REG_CONTROL, val: 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, val: control); |
173 | |
174 | control |= CONTROL_ENABLE; |
175 | mchp_corespi_write(spi, REG_CONTROL, val: 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, val: control); |
201 | |
202 | lenpart = len & 0xffff0000; |
203 | mchp_corespi_write(spi, REG_FRAMESUP, val: lenpart); |
204 | |
205 | control |= CONTROL_ENABLE; |
206 | mchp_corespi_write(spi, REG_CONTROL, val: 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, len: 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, val: 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, val: bt); |
238 | |
239 | control = mchp_corespi_read(spi, REG_CONTROL); |
240 | control |= CONTROL_ENABLE; |
241 | mchp_corespi_write(spi, REG_CONTROL, val: control); |
242 | } |
243 | |
244 | static void mchp_corespi_set_cs(struct spi_device *spi, bool disable) |
245 | { |
246 | u32 reg; |
247 | struct mchp_corespi *corespi = spi_controller_get_devdata(ctlr: spi->controller); |
248 | |
249 | reg = mchp_corespi_read(spi: corespi, REG_SLAVE_SELECT); |
250 | reg &= ~BIT(spi_get_chipselect(spi, 0)); |
251 | reg |= !disable << spi_get_chipselect(spi, idx: 0); |
252 | |
253 | mchp_corespi_write(spi: corespi, REG_SLAVE_SELECT, val: reg); |
254 | } |
255 | |
256 | static int mchp_corespi_setup(struct spi_device *spi) |
257 | { |
258 | struct mchp_corespi *corespi = spi_controller_get_devdata(ctlr: spi->controller); |
259 | u32 reg; |
260 | |
261 | /* |
262 | * Active high targets need to be specifically set to their inactive |
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(spi: corespi, REG_SLAVE_SELECT); |
268 | reg |= BIT(spi_get_chipselect(spi, 0)); |
269 | mchp_corespi_write(spi: corespi, REG_SLAVE_SELECT, val: reg); |
270 | } |
271 | return 0; |
272 | } |
273 | |
274 | static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *spi) |
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(clk: spi->clk); |
288 | host->max_speed_hz = clk_hz; |
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, val: 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 |
308 | * can deal with active high targets. |
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, val: 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, val: spi->clk_gen); |
333 | mchp_corespi_write(spi, REG_CONTROL, val: control); |
334 | mchp_corespi_write(spi, REG_CONTROL, val: 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, val: control); |
367 | |
368 | control |= CONTROL_ENABLE; |
369 | mchp_corespi_write(spi, REG_CONTROL, val: control); |
370 | } |
371 | |
372 | static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) |
373 | { |
374 | struct spi_controller *host = dev_id; |
375 | struct mchp_corespi *spi = spi_controller_get_devdata(ctlr: host); |
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; |
402 | dev_err(&host->dev, |
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; |
410 | dev_err(&host->dev, |
411 | "%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n" , __func__, |
412 | spi->rx_len, spi->tx_len); |
413 | } |
414 | |
415 | if (finalise) |
416 | spi_finalize_current_transfer(ctlr: host); |
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(clk: spi->clk); |
427 | if (!clk_hz) |
428 | return -EINVAL; |
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(x: 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 | |
458 | static int mchp_corespi_transfer_one(struct spi_controller *host, |
459 | struct spi_device *spi_dev, |
460 | struct spi_transfer *xfer) |
461 | { |
462 | struct mchp_corespi *spi = spi_controller_get_devdata(ctlr: host); |
463 | int ret; |
464 | |
465 | ret = mchp_corespi_calculate_clkgen(spi, target_hz: (unsigned long)xfer->speed_hz); |
466 | if (ret) { |
467 | dev_err(&host->dev, "failed to set clk_gen for target %u Hz\n" , xfer->speed_hz); |
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, len: (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 | |
487 | static int mchp_corespi_prepare_message(struct spi_controller *host, |
488 | struct spi_message *msg) |
489 | { |
490 | struct spi_device *spi_dev = msg->spi; |
491 | struct mchp_corespi *spi = spi_controller_get_devdata(ctlr: host); |
492 | |
493 | mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE); |
494 | mchp_corespi_set_mode(spi, mode: spi_dev->mode); |
495 | |
496 | return 0; |
497 | } |
498 | |
499 | static int mchp_corespi_probe(struct platform_device *pdev) |
500 | { |
501 | struct spi_controller *host; |
502 | struct mchp_corespi *spi; |
503 | struct resource *res; |
504 | u32 num_cs; |
505 | int ret = 0; |
506 | |
507 | host = devm_spi_alloc_host(dev: &pdev->dev, size: sizeof(*spi)); |
508 | if (!host) |
509 | return dev_err_probe(dev: &pdev->dev, err: -ENOMEM, |
510 | fmt: "unable to allocate host for SPI controller\n" ); |
511 | |
512 | platform_set_drvdata(pdev, data: host); |
513 | |
514 | if (of_property_read_u32(np: pdev->dev.of_node, propname: "num-cs" , out_value: &num_cs)) |
515 | num_cs = MAX_CS; |
516 | |
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; |
525 | |
526 | spi = spi_controller_get_devdata(ctlr: host); |
527 | |
528 | spi->regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
529 | if (IS_ERR(ptr: spi->regs)) |
530 | return PTR_ERR(ptr: spi->regs); |
531 | |
532 | spi->irq = platform_get_irq(pdev, 0); |
533 | if (spi->irq < 0) |
534 | return spi->irq; |
535 | |
536 | ret = devm_request_irq(dev: &pdev->dev, irq: spi->irq, handler: mchp_corespi_interrupt, |
537 | IRQF_SHARED, devname: dev_name(dev: &pdev->dev), dev_id: host); |
538 | if (ret) |
539 | return dev_err_probe(dev: &pdev->dev, err: ret, |
540 | fmt: "could not request irq\n" ); |
541 | |
542 | spi->clk = devm_clk_get_enabled(dev: &pdev->dev, NULL); |
543 | if (IS_ERR(ptr: spi->clk)) |
544 | return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: spi->clk), |
545 | fmt: "could not get clk\n" ); |
546 | |
547 | mchp_corespi_init(host, spi); |
548 | |
549 | ret = devm_spi_register_controller(dev: &pdev->dev, ctlr: host); |
550 | if (ret) { |
551 | mchp_corespi_disable(spi); |
552 | return dev_err_probe(dev: &pdev->dev, err: ret, |
553 | fmt: "unable to register host for SPI controller\n" ); |
554 | } |
555 | |
556 | dev_info(&pdev->dev, "Registered SPI controller %d\n" , host->bus_num); |
557 | |
558 | return 0; |
559 | } |
560 | |
561 | static void mchp_corespi_remove(struct platform_device *pdev) |
562 | { |
563 | struct spi_controller *host = platform_get_drvdata(pdev); |
564 | struct mchp_corespi *spi = spi_controller_get_devdata(ctlr: host); |
565 | |
566 | mchp_corespi_disable_ints(spi); |
567 | mchp_corespi_disable(spi); |
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), |
590 | }, |
591 | .remove_new = mchp_corespi_remove, |
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" ); |
598 | |