1 | /* |
2 | * Driver for Amlogic Meson SPI communication controller (SPICC) |
3 | * |
4 | * Copyright (C) BayLibre, SAS |
5 | * Author: Neil Armstrong <narmstrong@baylibre.com> |
6 | * |
7 | * SPDX-License-Identifier: GPL-2.0+ |
8 | */ |
9 | |
10 | #include <linux/bitfield.h> |
11 | #include <linux/clk.h> |
12 | #include <linux/clk-provider.h> |
13 | #include <linux/device.h> |
14 | #include <linux/io.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/spi/spi.h> |
20 | #include <linux/types.h> |
21 | #include <linux/interrupt.h> |
22 | #include <linux/reset.h> |
23 | #include <linux/pinctrl/consumer.h> |
24 | |
25 | /* |
26 | * The Meson SPICC controller could support DMA based transfers, but is not |
27 | * implemented by the vendor code, and while having the registers documentation |
28 | * it has never worked on the GXL Hardware. |
29 | * The PIO mode is the only mode implemented, and due to badly designed HW : |
30 | * - all transfers are cutted in 16 words burst because the FIFO hangs on |
31 | * TX underflow, and there is no TX "Half-Empty" interrupt, so we go by |
32 | * FIFO max size chunk only |
33 | * - CS management is dumb, and goes UP between every burst, so is really a |
34 | * "Data Valid" signal than a Chip Select, GPIO link should be used instead |
35 | * to have a CS go down over the full transfer |
36 | */ |
37 | |
38 | #define SPICC_MAX_BURST 128 |
39 | |
40 | /* Register Map */ |
41 | #define SPICC_RXDATA 0x00 |
42 | |
43 | #define SPICC_TXDATA 0x04 |
44 | |
45 | #define SPICC_CONREG 0x08 |
46 | #define SPICC_ENABLE BIT(0) |
47 | #define SPICC_MODE_MASTER BIT(1) |
48 | #define SPICC_XCH BIT(2) |
49 | #define SPICC_SMC BIT(3) |
50 | #define SPICC_POL BIT(4) |
51 | #define SPICC_PHA BIT(5) |
52 | #define SPICC_SSCTL BIT(6) |
53 | #define SPICC_SSPOL BIT(7) |
54 | #define SPICC_DRCTL_MASK GENMASK(9, 8) |
55 | #define SPICC_DRCTL_IGNORE 0 |
56 | #define SPICC_DRCTL_FALLING 1 |
57 | #define SPICC_DRCTL_LOWLEVEL 2 |
58 | #define SPICC_CS_MASK GENMASK(13, 12) |
59 | #define SPICC_DATARATE_MASK GENMASK(18, 16) |
60 | #define SPICC_DATARATE_DIV4 0 |
61 | #define SPICC_DATARATE_DIV8 1 |
62 | #define SPICC_DATARATE_DIV16 2 |
63 | #define SPICC_DATARATE_DIV32 3 |
64 | #define SPICC_BITLENGTH_MASK GENMASK(24, 19) |
65 | #define SPICC_BURSTLENGTH_MASK GENMASK(31, 25) |
66 | |
67 | #define SPICC_INTREG 0x0c |
68 | #define SPICC_TE_EN BIT(0) /* TX FIFO Empty Interrupt */ |
69 | #define SPICC_TH_EN BIT(1) /* TX FIFO Half-Full Interrupt */ |
70 | #define SPICC_TF_EN BIT(2) /* TX FIFO Full Interrupt */ |
71 | #define SPICC_RR_EN BIT(3) /* RX FIFO Ready Interrupt */ |
72 | #define SPICC_RH_EN BIT(4) /* RX FIFO Half-Full Interrupt */ |
73 | #define SPICC_RF_EN BIT(5) /* RX FIFO Full Interrupt */ |
74 | #define SPICC_RO_EN BIT(6) /* RX FIFO Overflow Interrupt */ |
75 | #define SPICC_TC_EN BIT(7) /* Transfert Complete Interrupt */ |
76 | |
77 | #define SPICC_DMAREG 0x10 |
78 | #define SPICC_DMA_ENABLE BIT(0) |
79 | #define SPICC_TXFIFO_THRESHOLD_MASK GENMASK(5, 1) |
80 | #define SPICC_RXFIFO_THRESHOLD_MASK GENMASK(10, 6) |
81 | #define SPICC_READ_BURST_MASK GENMASK(14, 11) |
82 | #define SPICC_WRITE_BURST_MASK GENMASK(18, 15) |
83 | #define SPICC_DMA_URGENT BIT(19) |
84 | #define SPICC_DMA_THREADID_MASK GENMASK(25, 20) |
85 | #define SPICC_DMA_BURSTNUM_MASK GENMASK(31, 26) |
86 | |
87 | #define SPICC_STATREG 0x14 |
88 | #define SPICC_TE BIT(0) /* TX FIFO Empty Interrupt */ |
89 | #define SPICC_TH BIT(1) /* TX FIFO Half-Full Interrupt */ |
90 | #define SPICC_TF BIT(2) /* TX FIFO Full Interrupt */ |
91 | #define SPICC_RR BIT(3) /* RX FIFO Ready Interrupt */ |
92 | #define SPICC_RH BIT(4) /* RX FIFO Half-Full Interrupt */ |
93 | #define SPICC_RF BIT(5) /* RX FIFO Full Interrupt */ |
94 | #define SPICC_RO BIT(6) /* RX FIFO Overflow Interrupt */ |
95 | #define SPICC_TC BIT(7) /* Transfert Complete Interrupt */ |
96 | |
97 | #define SPICC_PERIODREG 0x18 |
98 | #define SPICC_PERIOD GENMASK(14, 0) /* Wait cycles */ |
99 | |
100 | #define SPICC_TESTREG 0x1c |
101 | #define SPICC_TXCNT_MASK GENMASK(4, 0) /* TX FIFO Counter */ |
102 | #define SPICC_RXCNT_MASK GENMASK(9, 5) /* RX FIFO Counter */ |
103 | #define SPICC_SMSTATUS_MASK GENMASK(12, 10) /* State Machine Status */ |
104 | #define SPICC_LBC_RO BIT(13) /* Loop Back Control Read-Only */ |
105 | #define SPICC_LBC_W1 BIT(14) /* Loop Back Control Write-Only */ |
106 | #define SPICC_SWAP_RO BIT(14) /* RX FIFO Data Swap Read-Only */ |
107 | #define SPICC_SWAP_W1 BIT(15) /* RX FIFO Data Swap Write-Only */ |
108 | #define SPICC_DLYCTL_RO_MASK GENMASK(20, 15) /* Delay Control Read-Only */ |
109 | #define SPICC_MO_DELAY_MASK GENMASK(17, 16) /* Master Output Delay */ |
110 | #define SPICC_MO_NO_DELAY 0 |
111 | #define SPICC_MO_DELAY_1_CYCLE 1 |
112 | #define SPICC_MO_DELAY_2_CYCLE 2 |
113 | #define SPICC_MO_DELAY_3_CYCLE 3 |
114 | #define SPICC_MI_DELAY_MASK GENMASK(19, 18) /* Master Input Delay */ |
115 | #define SPICC_MI_NO_DELAY 0 |
116 | #define SPICC_MI_DELAY_1_CYCLE 1 |
117 | #define SPICC_MI_DELAY_2_CYCLE 2 |
118 | #define SPICC_MI_DELAY_3_CYCLE 3 |
119 | #define SPICC_MI_CAP_DELAY_MASK GENMASK(21, 20) /* Master Capture Delay */ |
120 | #define SPICC_CAP_AHEAD_2_CYCLE 0 |
121 | #define SPICC_CAP_AHEAD_1_CYCLE 1 |
122 | #define SPICC_CAP_NO_DELAY 2 |
123 | #define SPICC_CAP_DELAY_1_CYCLE 3 |
124 | #define SPICC_FIFORST_RO_MASK GENMASK(22, 21) /* FIFO Softreset Read-Only */ |
125 | #define SPICC_FIFORST_W1_MASK GENMASK(23, 22) /* FIFO Softreset Write-Only */ |
126 | |
127 | #define SPICC_DRADDR 0x20 /* Read Address of DMA */ |
128 | |
129 | #define SPICC_DWADDR 0x24 /* Write Address of DMA */ |
130 | |
131 | #define SPICC_ENH_CTL0 0x38 /* Enhanced Feature */ |
132 | #define SPICC_ENH_CLK_CS_DELAY_MASK GENMASK(15, 0) |
133 | #define SPICC_ENH_DATARATE_MASK GENMASK(23, 16) |
134 | #define SPICC_ENH_DATARATE_EN BIT(24) |
135 | #define SPICC_ENH_MOSI_OEN BIT(25) |
136 | #define SPICC_ENH_CLK_OEN BIT(26) |
137 | #define SPICC_ENH_CS_OEN BIT(27) |
138 | #define SPICC_ENH_CLK_CS_DELAY_EN BIT(28) |
139 | #define SPICC_ENH_MAIN_CLK_AO BIT(29) |
140 | |
141 | #define writel_bits_relaxed(mask, val, addr) \ |
142 | writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) |
143 | |
144 | struct meson_spicc_data { |
145 | unsigned int max_speed_hz; |
146 | unsigned int min_speed_hz; |
147 | unsigned int fifo_size; |
148 | bool has_oen; |
149 | bool has_enhance_clk_div; |
150 | bool has_pclk; |
151 | }; |
152 | |
153 | struct meson_spicc_device { |
154 | struct spi_controller *host; |
155 | struct platform_device *pdev; |
156 | void __iomem *base; |
157 | struct clk *core; |
158 | struct clk *pclk; |
159 | struct clk_divider pow2_div; |
160 | struct clk *clk; |
161 | struct spi_message *message; |
162 | struct spi_transfer *xfer; |
163 | struct completion done; |
164 | const struct meson_spicc_data *data; |
165 | u8 *tx_buf; |
166 | u8 *rx_buf; |
167 | unsigned int bytes_per_word; |
168 | unsigned long tx_remain; |
169 | unsigned long rx_remain; |
170 | unsigned long xfer_remain; |
171 | struct pinctrl *pinctrl; |
172 | struct pinctrl_state *pins_idle_high; |
173 | struct pinctrl_state *pins_idle_low; |
174 | }; |
175 | |
176 | #define pow2_clk_to_spicc(_div) container_of(_div, struct meson_spicc_device, pow2_div) |
177 | |
178 | static void meson_spicc_oen_enable(struct meson_spicc_device *spicc) |
179 | { |
180 | u32 conf; |
181 | |
182 | if (!spicc->data->has_oen) { |
183 | /* Try to get pinctrl states for idle high/low */ |
184 | spicc->pins_idle_high = pinctrl_lookup_state(p: spicc->pinctrl, |
185 | name: "idle-high" ); |
186 | if (IS_ERR(ptr: spicc->pins_idle_high)) { |
187 | dev_warn(&spicc->pdev->dev, "can't get idle-high pinctrl\n" ); |
188 | spicc->pins_idle_high = NULL; |
189 | } |
190 | spicc->pins_idle_low = pinctrl_lookup_state(p: spicc->pinctrl, |
191 | name: "idle-low" ); |
192 | if (IS_ERR(ptr: spicc->pins_idle_low)) { |
193 | dev_warn(&spicc->pdev->dev, "can't get idle-low pinctrl\n" ); |
194 | spicc->pins_idle_low = NULL; |
195 | } |
196 | return; |
197 | } |
198 | |
199 | conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) | |
200 | SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN; |
201 | |
202 | writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0); |
203 | } |
204 | |
205 | static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc) |
206 | { |
207 | return !!FIELD_GET(SPICC_TF, |
208 | readl_relaxed(spicc->base + SPICC_STATREG)); |
209 | } |
210 | |
211 | static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc) |
212 | { |
213 | return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF, |
214 | readl_relaxed(spicc->base + SPICC_STATREG)); |
215 | } |
216 | |
217 | static inline u32 meson_spicc_pull_data(struct meson_spicc_device *spicc) |
218 | { |
219 | unsigned int bytes = spicc->bytes_per_word; |
220 | unsigned int byte_shift = 0; |
221 | u32 data = 0; |
222 | u8 byte; |
223 | |
224 | while (bytes--) { |
225 | byte = *spicc->tx_buf++; |
226 | data |= (byte & 0xff) << byte_shift; |
227 | byte_shift += 8; |
228 | } |
229 | |
230 | spicc->tx_remain--; |
231 | return data; |
232 | } |
233 | |
234 | static inline void meson_spicc_push_data(struct meson_spicc_device *spicc, |
235 | u32 data) |
236 | { |
237 | unsigned int bytes = spicc->bytes_per_word; |
238 | unsigned int byte_shift = 0; |
239 | u8 byte; |
240 | |
241 | while (bytes--) { |
242 | byte = (data >> byte_shift) & 0xff; |
243 | *spicc->rx_buf++ = byte; |
244 | byte_shift += 8; |
245 | } |
246 | |
247 | spicc->rx_remain--; |
248 | } |
249 | |
250 | static inline void meson_spicc_rx(struct meson_spicc_device *spicc) |
251 | { |
252 | /* Empty RX FIFO */ |
253 | while (spicc->rx_remain && |
254 | meson_spicc_rxready(spicc)) |
255 | meson_spicc_push_data(spicc, |
256 | readl_relaxed(spicc->base + SPICC_RXDATA)); |
257 | } |
258 | |
259 | static inline void meson_spicc_tx(struct meson_spicc_device *spicc) |
260 | { |
261 | /* Fill Up TX FIFO */ |
262 | while (spicc->tx_remain && |
263 | !meson_spicc_txfull(spicc)) |
264 | writel_relaxed(meson_spicc_pull_data(spicc), |
265 | spicc->base + SPICC_TXDATA); |
266 | } |
267 | |
268 | static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc) |
269 | { |
270 | |
271 | unsigned int burst_len = min_t(unsigned int, |
272 | spicc->xfer_remain / |
273 | spicc->bytes_per_word, |
274 | spicc->data->fifo_size); |
275 | /* Setup Xfer variables */ |
276 | spicc->tx_remain = burst_len; |
277 | spicc->rx_remain = burst_len; |
278 | spicc->xfer_remain -= burst_len * spicc->bytes_per_word; |
279 | |
280 | /* Setup burst length */ |
281 | writel_bits_relaxed(SPICC_BURSTLENGTH_MASK, |
282 | FIELD_PREP(SPICC_BURSTLENGTH_MASK, |
283 | burst_len - 1), |
284 | spicc->base + SPICC_CONREG); |
285 | |
286 | /* Fill TX FIFO */ |
287 | meson_spicc_tx(spicc); |
288 | } |
289 | |
290 | static irqreturn_t meson_spicc_irq(int irq, void *data) |
291 | { |
292 | struct meson_spicc_device *spicc = (void *) data; |
293 | |
294 | writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG); |
295 | |
296 | /* Empty RX FIFO */ |
297 | meson_spicc_rx(spicc); |
298 | |
299 | if (!spicc->xfer_remain) { |
300 | /* Disable all IRQs */ |
301 | writel(val: 0, addr: spicc->base + SPICC_INTREG); |
302 | |
303 | complete(&spicc->done); |
304 | |
305 | return IRQ_HANDLED; |
306 | } |
307 | |
308 | /* Setup burst */ |
309 | meson_spicc_setup_burst(spicc); |
310 | |
311 | /* Start burst */ |
312 | writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); |
313 | |
314 | return IRQ_HANDLED; |
315 | } |
316 | |
317 | static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc) |
318 | { |
319 | u32 div, hz; |
320 | u32 mi_delay, cap_delay; |
321 | u32 conf; |
322 | |
323 | if (spicc->data->has_enhance_clk_div) { |
324 | div = FIELD_GET(SPICC_ENH_DATARATE_MASK, |
325 | readl_relaxed(spicc->base + SPICC_ENH_CTL0)); |
326 | div++; |
327 | div <<= 1; |
328 | } else { |
329 | div = FIELD_GET(SPICC_DATARATE_MASK, |
330 | readl_relaxed(spicc->base + SPICC_CONREG)); |
331 | div += 2; |
332 | div = 1 << div; |
333 | } |
334 | |
335 | mi_delay = SPICC_MI_NO_DELAY; |
336 | cap_delay = SPICC_CAP_AHEAD_2_CYCLE; |
337 | hz = clk_get_rate(clk: spicc->clk); |
338 | |
339 | if (hz >= 100000000) |
340 | cap_delay = SPICC_CAP_DELAY_1_CYCLE; |
341 | else if (hz >= 80000000) |
342 | cap_delay = SPICC_CAP_NO_DELAY; |
343 | else if (hz >= 40000000) |
344 | cap_delay = SPICC_CAP_AHEAD_1_CYCLE; |
345 | else if (div >= 16) |
346 | mi_delay = SPICC_MI_DELAY_3_CYCLE; |
347 | else if (div >= 8) |
348 | mi_delay = SPICC_MI_DELAY_2_CYCLE; |
349 | else if (div >= 6) |
350 | mi_delay = SPICC_MI_DELAY_1_CYCLE; |
351 | |
352 | conf = readl_relaxed(spicc->base + SPICC_TESTREG); |
353 | conf &= ~(SPICC_MO_DELAY_MASK | SPICC_MI_DELAY_MASK |
354 | | SPICC_MI_CAP_DELAY_MASK); |
355 | conf |= FIELD_PREP(SPICC_MI_DELAY_MASK, mi_delay); |
356 | conf |= FIELD_PREP(SPICC_MI_CAP_DELAY_MASK, cap_delay); |
357 | writel_relaxed(conf, spicc->base + SPICC_TESTREG); |
358 | } |
359 | |
360 | static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, |
361 | struct spi_transfer *xfer) |
362 | { |
363 | u32 conf, conf_orig; |
364 | |
365 | /* Read original configuration */ |
366 | conf = conf_orig = readl_relaxed(spicc->base + SPICC_CONREG); |
367 | |
368 | /* Setup word width */ |
369 | conf &= ~SPICC_BITLENGTH_MASK; |
370 | conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, |
371 | (spicc->bytes_per_word << 3) - 1); |
372 | |
373 | /* Ignore if unchanged */ |
374 | if (conf != conf_orig) |
375 | writel_relaxed(conf, spicc->base + SPICC_CONREG); |
376 | |
377 | clk_set_rate(clk: spicc->clk, rate: xfer->speed_hz); |
378 | |
379 | meson_spicc_auto_io_delay(spicc); |
380 | |
381 | writel_relaxed(0, spicc->base + SPICC_DMAREG); |
382 | } |
383 | |
384 | static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc) |
385 | { |
386 | if (spicc->data->has_oen) |
387 | writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, |
388 | SPICC_ENH_MAIN_CLK_AO, |
389 | spicc->base + SPICC_ENH_CTL0); |
390 | |
391 | writel_bits_relaxed(SPICC_FIFORST_W1_MASK, SPICC_FIFORST_W1_MASK, |
392 | spicc->base + SPICC_TESTREG); |
393 | |
394 | while (meson_spicc_rxready(spicc)) |
395 | readl_relaxed(spicc->base + SPICC_RXDATA); |
396 | |
397 | if (spicc->data->has_oen) |
398 | writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0, |
399 | spicc->base + SPICC_ENH_CTL0); |
400 | } |
401 | |
402 | static int meson_spicc_transfer_one(struct spi_controller *host, |
403 | struct spi_device *spi, |
404 | struct spi_transfer *xfer) |
405 | { |
406 | struct meson_spicc_device *spicc = spi_controller_get_devdata(ctlr: host); |
407 | uint64_t timeout; |
408 | |
409 | /* Store current transfer */ |
410 | spicc->xfer = xfer; |
411 | |
412 | /* Setup transfer parameters */ |
413 | spicc->tx_buf = (u8 *)xfer->tx_buf; |
414 | spicc->rx_buf = (u8 *)xfer->rx_buf; |
415 | spicc->xfer_remain = xfer->len; |
416 | |
417 | /* Pre-calculate word size */ |
418 | spicc->bytes_per_word = |
419 | DIV_ROUND_UP(spicc->xfer->bits_per_word, 8); |
420 | |
421 | if (xfer->len % spicc->bytes_per_word) |
422 | return -EINVAL; |
423 | |
424 | /* Setup transfer parameters */ |
425 | meson_spicc_setup_xfer(spicc, xfer); |
426 | |
427 | meson_spicc_reset_fifo(spicc); |
428 | |
429 | /* Setup burst */ |
430 | meson_spicc_setup_burst(spicc); |
431 | |
432 | /* Setup wait for completion */ |
433 | reinit_completion(x: &spicc->done); |
434 | |
435 | /* For each byte we wait for 8 cycles of the SPI clock */ |
436 | timeout = 8LL * MSEC_PER_SEC * xfer->len; |
437 | do_div(timeout, xfer->speed_hz); |
438 | |
439 | /* Add 10us delay between each fifo bursts */ |
440 | timeout += ((xfer->len >> 4) * 10) / MSEC_PER_SEC; |
441 | |
442 | /* Increase it twice and add 200 ms tolerance */ |
443 | timeout += timeout + 200; |
444 | |
445 | /* Start burst */ |
446 | writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); |
447 | |
448 | /* Enable interrupts */ |
449 | writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG); |
450 | |
451 | if (!wait_for_completion_timeout(x: &spicc->done, timeout: msecs_to_jiffies(m: timeout))) |
452 | return -ETIMEDOUT; |
453 | |
454 | return 0; |
455 | } |
456 | |
457 | static int meson_spicc_prepare_message(struct spi_controller *host, |
458 | struct spi_message *message) |
459 | { |
460 | struct meson_spicc_device *spicc = spi_controller_get_devdata(ctlr: host); |
461 | struct spi_device *spi = message->spi; |
462 | u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK; |
463 | |
464 | /* Store current message */ |
465 | spicc->message = message; |
466 | |
467 | /* Enable Master */ |
468 | conf |= SPICC_ENABLE; |
469 | conf |= SPICC_MODE_MASTER; |
470 | |
471 | /* SMC = 0 */ |
472 | |
473 | /* Setup transfer mode */ |
474 | if (spi->mode & SPI_CPOL) |
475 | conf |= SPICC_POL; |
476 | else |
477 | conf &= ~SPICC_POL; |
478 | |
479 | if (!spicc->data->has_oen) { |
480 | if (spi->mode & SPI_CPOL) { |
481 | if (spicc->pins_idle_high) |
482 | pinctrl_select_state(p: spicc->pinctrl, s: spicc->pins_idle_high); |
483 | } else { |
484 | if (spicc->pins_idle_low) |
485 | pinctrl_select_state(p: spicc->pinctrl, s: spicc->pins_idle_low); |
486 | } |
487 | } |
488 | |
489 | if (spi->mode & SPI_CPHA) |
490 | conf |= SPICC_PHA; |
491 | else |
492 | conf &= ~SPICC_PHA; |
493 | |
494 | /* SSCTL = 0 */ |
495 | |
496 | if (spi->mode & SPI_CS_HIGH) |
497 | conf |= SPICC_SSPOL; |
498 | else |
499 | conf &= ~SPICC_SSPOL; |
500 | |
501 | if (spi->mode & SPI_READY) |
502 | conf |= FIELD_PREP(SPICC_DRCTL_MASK, SPICC_DRCTL_LOWLEVEL); |
503 | else |
504 | conf |= FIELD_PREP(SPICC_DRCTL_MASK, SPICC_DRCTL_IGNORE); |
505 | |
506 | /* Select CS */ |
507 | conf |= FIELD_PREP(SPICC_CS_MASK, spi_get_chipselect(spi, 0)); |
508 | |
509 | /* Default 8bit word */ |
510 | conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, 8 - 1); |
511 | |
512 | writel_relaxed(conf, spicc->base + SPICC_CONREG); |
513 | |
514 | /* Setup no wait cycles by default */ |
515 | writel_relaxed(0, spicc->base + SPICC_PERIODREG); |
516 | |
517 | writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG); |
518 | |
519 | return 0; |
520 | } |
521 | |
522 | static int meson_spicc_unprepare_transfer(struct spi_controller *host) |
523 | { |
524 | struct meson_spicc_device *spicc = spi_controller_get_devdata(ctlr: host); |
525 | u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK; |
526 | |
527 | /* Disable all IRQs */ |
528 | writel(val: 0, addr: spicc->base + SPICC_INTREG); |
529 | |
530 | device_reset_optional(dev: &spicc->pdev->dev); |
531 | |
532 | /* Set default configuration, keeping datarate field */ |
533 | writel_relaxed(conf, spicc->base + SPICC_CONREG); |
534 | |
535 | if (!spicc->data->has_oen) |
536 | pinctrl_select_default_state(dev: &spicc->pdev->dev); |
537 | |
538 | return 0; |
539 | } |
540 | |
541 | static int meson_spicc_setup(struct spi_device *spi) |
542 | { |
543 | if (!spi->controller_state) |
544 | spi->controller_state = spi_controller_get_devdata(ctlr: spi->controller); |
545 | |
546 | return 0; |
547 | } |
548 | |
549 | static void meson_spicc_cleanup(struct spi_device *spi) |
550 | { |
551 | spi->controller_state = NULL; |
552 | } |
553 | |
554 | /* |
555 | * The Clock Mux |
556 | * x-----------------x x------------x x------\ |
557 | * |---| pow2 fixed div |---| pow2 div |----| | |
558 | * | x-----------------x x------------x | | |
559 | * src ---| | mux |-- out |
560 | * | x-----------------x x------------x | | |
561 | * |---| enh fixed div |---| enh div |0---| | |
562 | * x-----------------x x------------x x------/ |
563 | * |
564 | * Clk path for GX series: |
565 | * src -> pow2 fixed div -> pow2 div -> out |
566 | * |
567 | * Clk path for AXG series: |
568 | * src -> pow2 fixed div -> pow2 div -> mux -> out |
569 | * src -> enh fixed div -> enh div -> mux -> out |
570 | * |
571 | * Clk path for G12A series: |
572 | * pclk -> pow2 fixed div -> pow2 div -> mux -> out |
573 | * pclk -> enh fixed div -> enh div -> mux -> out |
574 | * |
575 | * The pow2 divider is tied to the controller HW state, and the |
576 | * divider is only valid when the controller is initialized. |
577 | * |
578 | * A set of clock ops is added to make sure we don't read/set this |
579 | * clock rate while the controller is in an unknown state. |
580 | */ |
581 | |
582 | static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw, |
583 | unsigned long parent_rate) |
584 | { |
585 | struct clk_divider *divider = to_clk_divider(hw); |
586 | struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); |
587 | |
588 | if (!spicc->host->cur_msg) |
589 | return 0; |
590 | |
591 | return clk_divider_ops.recalc_rate(hw, parent_rate); |
592 | } |
593 | |
594 | static int meson_spicc_pow2_determine_rate(struct clk_hw *hw, |
595 | struct clk_rate_request *req) |
596 | { |
597 | struct clk_divider *divider = to_clk_divider(hw); |
598 | struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); |
599 | |
600 | if (!spicc->host->cur_msg) |
601 | return -EINVAL; |
602 | |
603 | return clk_divider_ops.determine_rate(hw, req); |
604 | } |
605 | |
606 | static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate, |
607 | unsigned long parent_rate) |
608 | { |
609 | struct clk_divider *divider = to_clk_divider(hw); |
610 | struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); |
611 | |
612 | if (!spicc->host->cur_msg) |
613 | return -EINVAL; |
614 | |
615 | return clk_divider_ops.set_rate(hw, rate, parent_rate); |
616 | } |
617 | |
618 | static const struct clk_ops meson_spicc_pow2_clk_ops = { |
619 | .recalc_rate = meson_spicc_pow2_recalc_rate, |
620 | .determine_rate = meson_spicc_pow2_determine_rate, |
621 | .set_rate = meson_spicc_pow2_set_rate, |
622 | }; |
623 | |
624 | static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc) |
625 | { |
626 | struct device *dev = &spicc->pdev->dev; |
627 | struct clk_fixed_factor *pow2_fixed_div; |
628 | struct clk_init_data init; |
629 | struct clk *clk; |
630 | struct clk_parent_data parent_data[2]; |
631 | char name[64]; |
632 | |
633 | memset(&init, 0, sizeof(init)); |
634 | memset(&parent_data, 0, sizeof(parent_data)); |
635 | |
636 | init.parent_data = parent_data; |
637 | |
638 | /* algorithm for pow2 div: rate = freq / 4 / (2 ^ N) */ |
639 | |
640 | pow2_fixed_div = devm_kzalloc(dev, size: sizeof(*pow2_fixed_div), GFP_KERNEL); |
641 | if (!pow2_fixed_div) |
642 | return -ENOMEM; |
643 | |
644 | snprintf(buf: name, size: sizeof(name), fmt: "%s#pow2_fixed_div" , dev_name(dev)); |
645 | init.name = name; |
646 | init.ops = &clk_fixed_factor_ops; |
647 | init.flags = 0; |
648 | if (spicc->data->has_pclk) |
649 | parent_data[0].hw = __clk_get_hw(clk: spicc->pclk); |
650 | else |
651 | parent_data[0].hw = __clk_get_hw(clk: spicc->core); |
652 | init.num_parents = 1; |
653 | |
654 | pow2_fixed_div->mult = 1, |
655 | pow2_fixed_div->div = 4, |
656 | pow2_fixed_div->hw.init = &init; |
657 | |
658 | clk = devm_clk_register(dev, hw: &pow2_fixed_div->hw); |
659 | if (WARN_ON(IS_ERR(clk))) |
660 | return PTR_ERR(ptr: clk); |
661 | |
662 | snprintf(buf: name, size: sizeof(name), fmt: "%s#pow2_div" , dev_name(dev)); |
663 | init.name = name; |
664 | init.ops = &meson_spicc_pow2_clk_ops; |
665 | /* |
666 | * Set NOCACHE here to make sure we read the actual HW value |
667 | * since we reset the HW after each transfer. |
668 | */ |
669 | init.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE; |
670 | parent_data[0].hw = &pow2_fixed_div->hw; |
671 | init.num_parents = 1; |
672 | |
673 | spicc->pow2_div.shift = 16, |
674 | spicc->pow2_div.width = 3, |
675 | spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO, |
676 | spicc->pow2_div.reg = spicc->base + SPICC_CONREG; |
677 | spicc->pow2_div.hw.init = &init; |
678 | |
679 | spicc->clk = devm_clk_register(dev, hw: &spicc->pow2_div.hw); |
680 | if (WARN_ON(IS_ERR(spicc->clk))) |
681 | return PTR_ERR(ptr: spicc->clk); |
682 | |
683 | return 0; |
684 | } |
685 | |
686 | static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) |
687 | { |
688 | struct device *dev = &spicc->pdev->dev; |
689 | struct clk_fixed_factor *enh_fixed_div; |
690 | struct clk_divider *enh_div; |
691 | struct clk_mux *mux; |
692 | struct clk_init_data init; |
693 | struct clk *clk; |
694 | struct clk_parent_data parent_data[2]; |
695 | char name[64]; |
696 | |
697 | memset(&init, 0, sizeof(init)); |
698 | memset(&parent_data, 0, sizeof(parent_data)); |
699 | |
700 | init.parent_data = parent_data; |
701 | |
702 | /* algorithm for enh div: rate = freq / 2 / (N + 1) */ |
703 | |
704 | enh_fixed_div = devm_kzalloc(dev, size: sizeof(*enh_fixed_div), GFP_KERNEL); |
705 | if (!enh_fixed_div) |
706 | return -ENOMEM; |
707 | |
708 | snprintf(buf: name, size: sizeof(name), fmt: "%s#enh_fixed_div" , dev_name(dev)); |
709 | init.name = name; |
710 | init.ops = &clk_fixed_factor_ops; |
711 | init.flags = 0; |
712 | if (spicc->data->has_pclk) |
713 | parent_data[0].hw = __clk_get_hw(clk: spicc->pclk); |
714 | else |
715 | parent_data[0].hw = __clk_get_hw(clk: spicc->core); |
716 | init.num_parents = 1; |
717 | |
718 | enh_fixed_div->mult = 1, |
719 | enh_fixed_div->div = 2, |
720 | enh_fixed_div->hw.init = &init; |
721 | |
722 | clk = devm_clk_register(dev, hw: &enh_fixed_div->hw); |
723 | if (WARN_ON(IS_ERR(clk))) |
724 | return PTR_ERR(ptr: clk); |
725 | |
726 | enh_div = devm_kzalloc(dev, size: sizeof(*enh_div), GFP_KERNEL); |
727 | if (!enh_div) |
728 | return -ENOMEM; |
729 | |
730 | snprintf(buf: name, size: sizeof(name), fmt: "%s#enh_div" , dev_name(dev)); |
731 | init.name = name; |
732 | init.ops = &clk_divider_ops; |
733 | init.flags = CLK_SET_RATE_PARENT; |
734 | parent_data[0].hw = &enh_fixed_div->hw; |
735 | init.num_parents = 1; |
736 | |
737 | enh_div->shift = 16, |
738 | enh_div->width = 8, |
739 | enh_div->reg = spicc->base + SPICC_ENH_CTL0; |
740 | enh_div->hw.init = &init; |
741 | |
742 | clk = devm_clk_register(dev, hw: &enh_div->hw); |
743 | if (WARN_ON(IS_ERR(clk))) |
744 | return PTR_ERR(ptr: clk); |
745 | |
746 | mux = devm_kzalloc(dev, size: sizeof(*mux), GFP_KERNEL); |
747 | if (!mux) |
748 | return -ENOMEM; |
749 | |
750 | snprintf(buf: name, size: sizeof(name), fmt: "%s#sel" , dev_name(dev)); |
751 | init.name = name; |
752 | init.ops = &clk_mux_ops; |
753 | parent_data[0].hw = &spicc->pow2_div.hw; |
754 | parent_data[1].hw = &enh_div->hw; |
755 | init.num_parents = 2; |
756 | init.flags = CLK_SET_RATE_PARENT; |
757 | |
758 | mux->mask = 0x1, |
759 | mux->shift = 24, |
760 | mux->reg = spicc->base + SPICC_ENH_CTL0; |
761 | mux->hw.init = &init; |
762 | |
763 | spicc->clk = devm_clk_register(dev, hw: &mux->hw); |
764 | if (WARN_ON(IS_ERR(spicc->clk))) |
765 | return PTR_ERR(ptr: spicc->clk); |
766 | |
767 | return 0; |
768 | } |
769 | |
770 | static int meson_spicc_probe(struct platform_device *pdev) |
771 | { |
772 | struct spi_controller *host; |
773 | struct meson_spicc_device *spicc; |
774 | int ret, irq; |
775 | |
776 | host = spi_alloc_host(dev: &pdev->dev, size: sizeof(*spicc)); |
777 | if (!host) { |
778 | dev_err(&pdev->dev, "host allocation failed\n" ); |
779 | return -ENOMEM; |
780 | } |
781 | spicc = spi_controller_get_devdata(ctlr: host); |
782 | spicc->host = host; |
783 | |
784 | spicc->data = of_device_get_match_data(dev: &pdev->dev); |
785 | if (!spicc->data) { |
786 | dev_err(&pdev->dev, "failed to get match data\n" ); |
787 | ret = -EINVAL; |
788 | goto out_host; |
789 | } |
790 | |
791 | spicc->pdev = pdev; |
792 | platform_set_drvdata(pdev, data: spicc); |
793 | |
794 | init_completion(x: &spicc->done); |
795 | |
796 | spicc->base = devm_platform_ioremap_resource(pdev, index: 0); |
797 | if (IS_ERR(ptr: spicc->base)) { |
798 | dev_err(&pdev->dev, "io resource mapping failed\n" ); |
799 | ret = PTR_ERR(ptr: spicc->base); |
800 | goto out_host; |
801 | } |
802 | |
803 | /* Set master mode and enable controller */ |
804 | writel_relaxed(SPICC_ENABLE | SPICC_MODE_MASTER, |
805 | spicc->base + SPICC_CONREG); |
806 | |
807 | /* Disable all IRQs */ |
808 | writel_relaxed(0, spicc->base + SPICC_INTREG); |
809 | |
810 | irq = platform_get_irq(pdev, 0); |
811 | if (irq < 0) { |
812 | ret = irq; |
813 | goto out_host; |
814 | } |
815 | |
816 | ret = devm_request_irq(dev: &pdev->dev, irq, handler: meson_spicc_irq, |
817 | irqflags: 0, NULL, dev_id: spicc); |
818 | if (ret) { |
819 | dev_err(&pdev->dev, "irq request failed\n" ); |
820 | goto out_host; |
821 | } |
822 | |
823 | spicc->core = devm_clk_get_enabled(dev: &pdev->dev, id: "core" ); |
824 | if (IS_ERR(ptr: spicc->core)) { |
825 | dev_err(&pdev->dev, "core clock request failed\n" ); |
826 | ret = PTR_ERR(ptr: spicc->core); |
827 | goto out_host; |
828 | } |
829 | |
830 | if (spicc->data->has_pclk) { |
831 | spicc->pclk = devm_clk_get_enabled(dev: &pdev->dev, id: "pclk" ); |
832 | if (IS_ERR(ptr: spicc->pclk)) { |
833 | dev_err(&pdev->dev, "pclk clock request failed\n" ); |
834 | ret = PTR_ERR(ptr: spicc->pclk); |
835 | goto out_host; |
836 | } |
837 | } |
838 | |
839 | spicc->pinctrl = devm_pinctrl_get(dev: &pdev->dev); |
840 | if (IS_ERR(ptr: spicc->pinctrl)) { |
841 | ret = PTR_ERR(ptr: spicc->pinctrl); |
842 | goto out_host; |
843 | } |
844 | |
845 | device_reset_optional(dev: &pdev->dev); |
846 | |
847 | host->num_chipselect = 4; |
848 | host->dev.of_node = pdev->dev.of_node; |
849 | host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH; |
850 | host->bits_per_word_mask = SPI_BPW_MASK(32) | |
851 | SPI_BPW_MASK(24) | |
852 | SPI_BPW_MASK(16) | |
853 | SPI_BPW_MASK(8); |
854 | host->flags = (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX); |
855 | host->min_speed_hz = spicc->data->min_speed_hz; |
856 | host->max_speed_hz = spicc->data->max_speed_hz; |
857 | host->setup = meson_spicc_setup; |
858 | host->cleanup = meson_spicc_cleanup; |
859 | host->prepare_message = meson_spicc_prepare_message; |
860 | host->unprepare_transfer_hardware = meson_spicc_unprepare_transfer; |
861 | host->transfer_one = meson_spicc_transfer_one; |
862 | host->use_gpio_descriptors = true; |
863 | |
864 | meson_spicc_oen_enable(spicc); |
865 | |
866 | ret = meson_spicc_pow2_clk_init(spicc); |
867 | if (ret) { |
868 | dev_err(&pdev->dev, "pow2 clock registration failed\n" ); |
869 | goto out_host; |
870 | } |
871 | |
872 | if (spicc->data->has_enhance_clk_div) { |
873 | ret = meson_spicc_enh_clk_init(spicc); |
874 | if (ret) { |
875 | dev_err(&pdev->dev, "clock registration failed\n" ); |
876 | goto out_host; |
877 | } |
878 | } |
879 | |
880 | ret = devm_spi_register_controller(dev: &pdev->dev, ctlr: host); |
881 | if (ret) { |
882 | dev_err(&pdev->dev, "spi registration failed\n" ); |
883 | goto out_host; |
884 | } |
885 | |
886 | return 0; |
887 | |
888 | out_host: |
889 | spi_controller_put(ctlr: host); |
890 | |
891 | return ret; |
892 | } |
893 | |
894 | static void meson_spicc_remove(struct platform_device *pdev) |
895 | { |
896 | struct meson_spicc_device *spicc = platform_get_drvdata(pdev); |
897 | |
898 | /* Disable SPI */ |
899 | writel(val: 0, addr: spicc->base + SPICC_CONREG); |
900 | |
901 | spi_controller_put(ctlr: spicc->host); |
902 | } |
903 | |
904 | static const struct meson_spicc_data meson_spicc_gx_data = { |
905 | .max_speed_hz = 30000000, |
906 | .min_speed_hz = 325000, |
907 | .fifo_size = 16, |
908 | }; |
909 | |
910 | static const struct meson_spicc_data meson_spicc_axg_data = { |
911 | .max_speed_hz = 80000000, |
912 | .min_speed_hz = 325000, |
913 | .fifo_size = 16, |
914 | .has_oen = true, |
915 | .has_enhance_clk_div = true, |
916 | }; |
917 | |
918 | static const struct meson_spicc_data meson_spicc_g12a_data = { |
919 | .max_speed_hz = 166666666, |
920 | .min_speed_hz = 50000, |
921 | .fifo_size = 15, |
922 | .has_oen = true, |
923 | .has_enhance_clk_div = true, |
924 | .has_pclk = true, |
925 | }; |
926 | |
927 | static const struct of_device_id meson_spicc_of_match[] = { |
928 | { |
929 | .compatible = "amlogic,meson-gx-spicc" , |
930 | .data = &meson_spicc_gx_data, |
931 | }, |
932 | { |
933 | .compatible = "amlogic,meson-axg-spicc" , |
934 | .data = &meson_spicc_axg_data, |
935 | }, |
936 | { |
937 | .compatible = "amlogic,meson-g12a-spicc" , |
938 | .data = &meson_spicc_g12a_data, |
939 | }, |
940 | { /* sentinel */ } |
941 | }; |
942 | MODULE_DEVICE_TABLE(of, meson_spicc_of_match); |
943 | |
944 | static struct platform_driver meson_spicc_driver = { |
945 | .probe = meson_spicc_probe, |
946 | .remove_new = meson_spicc_remove, |
947 | .driver = { |
948 | .name = "meson-spicc" , |
949 | .of_match_table = of_match_ptr(meson_spicc_of_match), |
950 | }, |
951 | }; |
952 | |
953 | module_platform_driver(meson_spicc_driver); |
954 | |
955 | MODULE_DESCRIPTION("Meson SPI Communication Controller driver" ); |
956 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>" ); |
957 | MODULE_LICENSE("GPL" ); |
958 | |