Commit | Line | Data |
---|---|---|
81c9859b | 1 | // SPDX-License-Identifier: GPL-2.0-only |
d8c80d49 KP |
2 | /* |
3 | * Copyright (C) 2003-2015 Broadcom Corporation | |
4 | * All Rights Reserved | |
d8c80d49 | 5 | */ |
097d0619 | 6 | #include <linux/acpi.h> |
d8c80d49 KP |
7 | #include <linux/clk.h> |
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/platform_device.h> | |
11 | #include <linux/spi/spi.h> | |
12 | #include <linux/of.h> | |
13 | #include <linux/interrupt.h> | |
14 | ||
15 | /* SPI Configuration Register */ | |
16 | #define XLP_SPI_CONFIG 0x00 | |
17 | #define XLP_SPI_CPHA BIT(0) | |
18 | #define XLP_SPI_CPOL BIT(1) | |
19 | #define XLP_SPI_CS_POL BIT(2) | |
20 | #define XLP_SPI_TXMISO_EN BIT(3) | |
21 | #define XLP_SPI_TXMOSI_EN BIT(4) | |
22 | #define XLP_SPI_RXMISO_EN BIT(5) | |
23 | #define XLP_SPI_CS_LSBFE BIT(10) | |
24 | #define XLP_SPI_RXCAP_EN BIT(11) | |
25 | ||
26 | /* SPI Frequency Divider Register */ | |
27 | #define XLP_SPI_FDIV 0x04 | |
28 | ||
29 | /* SPI Command Register */ | |
30 | #define XLP_SPI_CMD 0x08 | |
31 | #define XLP_SPI_CMD_IDLE_MASK 0x0 | |
32 | #define XLP_SPI_CMD_TX_MASK 0x1 | |
33 | #define XLP_SPI_CMD_RX_MASK 0x2 | |
34 | #define XLP_SPI_CMD_TXRX_MASK 0x3 | |
35 | #define XLP_SPI_CMD_CONT BIT(4) | |
36 | #define XLP_SPI_XFR_BITCNT_SHIFT 16 | |
37 | ||
38 | /* SPI Status Register */ | |
39 | #define XLP_SPI_STATUS 0x0c | |
40 | #define XLP_SPI_XFR_PENDING BIT(0) | |
41 | #define XLP_SPI_XFR_DONE BIT(1) | |
42 | #define XLP_SPI_TX_INT BIT(2) | |
43 | #define XLP_SPI_RX_INT BIT(3) | |
44 | #define XLP_SPI_TX_UF BIT(4) | |
45 | #define XLP_SPI_RX_OF BIT(5) | |
46 | #define XLP_SPI_STAT_MASK 0x3f | |
47 | ||
48 | /* SPI Interrupt Enable Register */ | |
49 | #define XLP_SPI_INTR_EN 0x10 | |
50 | #define XLP_SPI_INTR_DONE BIT(0) | |
51 | #define XLP_SPI_INTR_TXTH BIT(1) | |
52 | #define XLP_SPI_INTR_RXTH BIT(2) | |
53 | #define XLP_SPI_INTR_TXUF BIT(3) | |
54 | #define XLP_SPI_INTR_RXOF BIT(4) | |
55 | ||
56 | /* SPI FIFO Threshold Register */ | |
57 | #define XLP_SPI_FIFO_THRESH 0x14 | |
58 | ||
59 | /* SPI FIFO Word Count Register */ | |
60 | #define XLP_SPI_FIFO_WCNT 0x18 | |
61 | #define XLP_SPI_RXFIFO_WCNT_MASK 0xf | |
62 | #define XLP_SPI_TXFIFO_WCNT_MASK 0xf0 | |
63 | #define XLP_SPI_TXFIFO_WCNT_SHIFT 4 | |
64 | ||
65 | /* SPI Transmit Data FIFO Register */ | |
66 | #define XLP_SPI_TXDATA_FIFO 0x1c | |
67 | ||
68 | /* SPI Receive Data FIFO Register */ | |
69 | #define XLP_SPI_RXDATA_FIFO 0x20 | |
70 | ||
71 | /* SPI System Control Register */ | |
72 | #define XLP_SPI_SYSCTRL 0x100 | |
73 | #define XLP_SPI_SYS_RESET BIT(0) | |
74 | #define XLP_SPI_SYS_CLKDIS BIT(1) | |
75 | #define XLP_SPI_SYS_PMEN BIT(8) | |
76 | ||
77 | #define SPI_CS_OFFSET 0x40 | |
78 | #define XLP_SPI_TXRXTH 0x80 | |
79 | #define XLP_SPI_FIFO_SIZE 8 | |
80 | #define XLP_SPI_MAX_CS 4 | |
81 | #define XLP_SPI_DEFAULT_FREQ 133333333 | |
82 | #define XLP_SPI_FDIV_MIN 4 | |
83 | #define XLP_SPI_FDIV_MAX 65535 | |
84 | /* | |
85 | * SPI can transfer only 28 bytes properly at a time. So split the | |
86 | * transfer into 28 bytes size. | |
87 | */ | |
88 | #define XLP_SPI_XFER_SIZE 28 | |
89 | ||
90 | struct xlp_spi_priv { | |
91 | struct device dev; /* device structure */ | |
92 | void __iomem *base; /* spi registers base address */ | |
93 | const u8 *tx_buf; /* tx data buffer */ | |
94 | u8 *rx_buf; /* rx data buffer */ | |
95 | int tx_len; /* tx xfer length */ | |
96 | int rx_len; /* rx xfer length */ | |
97 | int txerrors; /* TXFIFO underflow count */ | |
98 | int rxerrors; /* RXFIFO overflow count */ | |
99 | int cs; /* slave device chip select */ | |
100 | u32 spi_clk; /* spi clock frequency */ | |
101 | bool cmd_cont; /* cs active */ | |
102 | struct completion done; /* completion notification */ | |
103 | }; | |
104 | ||
105 | static inline u32 xlp_spi_reg_read(struct xlp_spi_priv *priv, | |
106 | int cs, int regoff) | |
107 | { | |
108 | return readl(priv->base + regoff + cs * SPI_CS_OFFSET); | |
109 | } | |
110 | ||
111 | static inline void xlp_spi_reg_write(struct xlp_spi_priv *priv, int cs, | |
112 | int regoff, u32 val) | |
113 | { | |
114 | writel(val, priv->base + regoff + cs * SPI_CS_OFFSET); | |
115 | } | |
116 | ||
117 | static inline void xlp_spi_sysctl_write(struct xlp_spi_priv *priv, | |
118 | int regoff, u32 val) | |
119 | { | |
120 | writel(val, priv->base + regoff); | |
121 | } | |
122 | ||
123 | /* | |
124 | * Setup global SPI_SYSCTRL register for all SPI channels. | |
125 | */ | |
126 | static void xlp_spi_sysctl_setup(struct xlp_spi_priv *xspi) | |
127 | { | |
128 | int cs; | |
129 | ||
130 | for (cs = 0; cs < XLP_SPI_MAX_CS; cs++) | |
131 | xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL, | |
132 | XLP_SPI_SYS_RESET << cs); | |
133 | xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL, XLP_SPI_SYS_PMEN); | |
134 | } | |
135 | ||
136 | static int xlp_spi_setup(struct spi_device *spi) | |
137 | { | |
138 | struct xlp_spi_priv *xspi; | |
139 | u32 fdiv, cfg; | |
140 | int cs; | |
141 | ||
142 | xspi = spi_master_get_devdata(spi->master); | |
143 | cs = spi->chip_select; | |
144 | /* | |
145 | * The value of fdiv must be between 4 and 65535. | |
146 | */ | |
147 | fdiv = DIV_ROUND_UP(xspi->spi_clk, spi->max_speed_hz); | |
148 | if (fdiv > XLP_SPI_FDIV_MAX) | |
149 | fdiv = XLP_SPI_FDIV_MAX; | |
150 | else if (fdiv < XLP_SPI_FDIV_MIN) | |
151 | fdiv = XLP_SPI_FDIV_MIN; | |
152 | ||
153 | xlp_spi_reg_write(xspi, cs, XLP_SPI_FDIV, fdiv); | |
154 | xlp_spi_reg_write(xspi, cs, XLP_SPI_FIFO_THRESH, XLP_SPI_TXRXTH); | |
155 | cfg = xlp_spi_reg_read(xspi, cs, XLP_SPI_CONFIG); | |
156 | if (spi->mode & SPI_CPHA) | |
157 | cfg |= XLP_SPI_CPHA; | |
158 | else | |
159 | cfg &= ~XLP_SPI_CPHA; | |
160 | if (spi->mode & SPI_CPOL) | |
161 | cfg |= XLP_SPI_CPOL; | |
162 | else | |
163 | cfg &= ~XLP_SPI_CPOL; | |
164 | if (!(spi->mode & SPI_CS_HIGH)) | |
165 | cfg |= XLP_SPI_CS_POL; | |
166 | else | |
167 | cfg &= ~XLP_SPI_CS_POL; | |
168 | if (spi->mode & SPI_LSB_FIRST) | |
169 | cfg |= XLP_SPI_CS_LSBFE; | |
170 | else | |
171 | cfg &= ~XLP_SPI_CS_LSBFE; | |
172 | ||
173 | cfg |= XLP_SPI_TXMOSI_EN | XLP_SPI_RXMISO_EN; | |
174 | if (fdiv == 4) | |
175 | cfg |= XLP_SPI_RXCAP_EN; | |
176 | xlp_spi_reg_write(xspi, cs, XLP_SPI_CONFIG, cfg); | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
181 | static void xlp_spi_read_rxfifo(struct xlp_spi_priv *xspi) | |
182 | { | |
183 | u32 rx_data, rxfifo_cnt; | |
184 | int i, j, nbytes; | |
185 | ||
186 | rxfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT); | |
187 | rxfifo_cnt &= XLP_SPI_RXFIFO_WCNT_MASK; | |
188 | while (rxfifo_cnt) { | |
189 | rx_data = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_RXDATA_FIFO); | |
190 | j = 0; | |
191 | nbytes = min(xspi->rx_len, 4); | |
192 | for (i = nbytes - 1; i >= 0; i--, j++) | |
193 | xspi->rx_buf[i] = (rx_data >> (j * 8)) & 0xff; | |
194 | ||
195 | xspi->rx_len -= nbytes; | |
196 | xspi->rx_buf += nbytes; | |
197 | rxfifo_cnt--; | |
198 | } | |
199 | } | |
200 | ||
201 | static void xlp_spi_fill_txfifo(struct xlp_spi_priv *xspi) | |
202 | { | |
203 | u32 tx_data, txfifo_cnt; | |
204 | int i, j, nbytes; | |
205 | ||
206 | txfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT); | |
207 | txfifo_cnt &= XLP_SPI_TXFIFO_WCNT_MASK; | |
208 | txfifo_cnt >>= XLP_SPI_TXFIFO_WCNT_SHIFT; | |
209 | while (xspi->tx_len && (txfifo_cnt < XLP_SPI_FIFO_SIZE)) { | |
210 | j = 0; | |
211 | tx_data = 0; | |
212 | nbytes = min(xspi->tx_len, 4); | |
213 | for (i = nbytes - 1; i >= 0; i--, j++) | |
214 | tx_data |= xspi->tx_buf[i] << (j * 8); | |
215 | ||
216 | xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_TXDATA_FIFO, tx_data); | |
217 | xspi->tx_len -= nbytes; | |
218 | xspi->tx_buf += nbytes; | |
219 | txfifo_cnt++; | |
220 | } | |
221 | } | |
222 | ||
223 | static irqreturn_t xlp_spi_interrupt(int irq, void *dev_id) | |
224 | { | |
225 | struct xlp_spi_priv *xspi = dev_id; | |
226 | u32 stat; | |
227 | ||
228 | stat = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_STATUS) & | |
229 | XLP_SPI_STAT_MASK; | |
230 | if (!stat) | |
231 | return IRQ_NONE; | |
232 | ||
233 | if (stat & XLP_SPI_TX_INT) { | |
234 | if (xspi->tx_len) | |
235 | xlp_spi_fill_txfifo(xspi); | |
236 | if (stat & XLP_SPI_TX_UF) | |
237 | xspi->txerrors++; | |
238 | } | |
239 | ||
240 | if (stat & XLP_SPI_RX_INT) { | |
241 | if (xspi->rx_len) | |
242 | xlp_spi_read_rxfifo(xspi); | |
243 | if (stat & XLP_SPI_RX_OF) | |
244 | xspi->rxerrors++; | |
245 | } | |
246 | ||
247 | /* write status back to clear interrupts */ | |
248 | xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_STATUS, stat); | |
249 | if (stat & XLP_SPI_XFR_DONE) | |
250 | complete(&xspi->done); | |
251 | ||
252 | return IRQ_HANDLED; | |
253 | } | |
254 | ||
255 | static void xlp_spi_send_cmd(struct xlp_spi_priv *xspi, int xfer_len, | |
256 | int cmd_cont) | |
257 | { | |
258 | u32 cmd = 0; | |
259 | ||
260 | if (xspi->tx_buf) | |
261 | cmd |= XLP_SPI_CMD_TX_MASK; | |
262 | if (xspi->rx_buf) | |
263 | cmd |= XLP_SPI_CMD_RX_MASK; | |
264 | if (cmd_cont) | |
265 | cmd |= XLP_SPI_CMD_CONT; | |
266 | cmd |= ((xfer_len * 8 - 1) << XLP_SPI_XFR_BITCNT_SHIFT); | |
267 | xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_CMD, cmd); | |
268 | } | |
269 | ||
270 | static int xlp_spi_xfer_block(struct xlp_spi_priv *xs, | |
271 | const unsigned char *tx_buf, | |
272 | unsigned char *rx_buf, int xfer_len, int cmd_cont) | |
273 | { | |
274 | int timeout; | |
275 | u32 intr_mask = 0; | |
276 | ||
277 | xs->tx_buf = tx_buf; | |
278 | xs->rx_buf = rx_buf; | |
279 | xs->tx_len = (xs->tx_buf == NULL) ? 0 : xfer_len; | |
280 | xs->rx_len = (xs->rx_buf == NULL) ? 0 : xfer_len; | |
281 | xs->txerrors = xs->rxerrors = 0; | |
282 | ||
283 | /* fill TXDATA_FIFO, then send the CMD */ | |
284 | if (xs->tx_len) | |
285 | xlp_spi_fill_txfifo(xs); | |
286 | ||
287 | xlp_spi_send_cmd(xs, xfer_len, cmd_cont); | |
288 | ||
289 | /* | |
290 | * We are getting some spurious tx interrupts, so avoid enabling | |
291 | * tx interrupts when only rx is in process. | |
292 | * Enable all the interrupts in tx case. | |
293 | */ | |
294 | if (xs->tx_len) | |
295 | intr_mask |= XLP_SPI_INTR_TXTH | XLP_SPI_INTR_TXUF | | |
296 | XLP_SPI_INTR_RXTH | XLP_SPI_INTR_RXOF; | |
297 | else | |
298 | intr_mask |= XLP_SPI_INTR_RXTH | XLP_SPI_INTR_RXOF; | |
299 | ||
300 | intr_mask |= XLP_SPI_INTR_DONE; | |
301 | xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, intr_mask); | |
302 | ||
303 | timeout = wait_for_completion_timeout(&xs->done, | |
304 | msecs_to_jiffies(1000)); | |
305 | /* Disable interrupts */ | |
306 | xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, 0x0); | |
307 | if (!timeout) { | |
308 | dev_err(&xs->dev, "xfer timedout!\n"); | |
309 | goto out; | |
310 | } | |
311 | if (xs->txerrors || xs->rxerrors) | |
312 | dev_err(&xs->dev, "Over/Underflow rx %d tx %d xfer %d!\n", | |
313 | xs->rxerrors, xs->txerrors, xfer_len); | |
314 | ||
315 | return xfer_len; | |
316 | out: | |
317 | return -ETIMEDOUT; | |
318 | } | |
319 | ||
320 | static int xlp_spi_txrx_bufs(struct xlp_spi_priv *xs, struct spi_transfer *t) | |
321 | { | |
322 | int bytesleft, sz; | |
323 | unsigned char *rx_buf; | |
324 | const unsigned char *tx_buf; | |
325 | ||
326 | tx_buf = t->tx_buf; | |
327 | rx_buf = t->rx_buf; | |
328 | bytesleft = t->len; | |
329 | while (bytesleft) { | |
330 | if (bytesleft > XLP_SPI_XFER_SIZE) | |
331 | sz = xlp_spi_xfer_block(xs, tx_buf, rx_buf, | |
332 | XLP_SPI_XFER_SIZE, 1); | |
333 | else | |
334 | sz = xlp_spi_xfer_block(xs, tx_buf, rx_buf, | |
335 | bytesleft, xs->cmd_cont); | |
336 | if (sz < 0) | |
337 | return sz; | |
338 | bytesleft -= sz; | |
339 | if (tx_buf) | |
340 | tx_buf += sz; | |
341 | if (rx_buf) | |
342 | rx_buf += sz; | |
343 | } | |
344 | return bytesleft; | |
345 | } | |
346 | ||
347 | static int xlp_spi_transfer_one(struct spi_master *master, | |
348 | struct spi_device *spi, | |
349 | struct spi_transfer *t) | |
350 | { | |
351 | struct xlp_spi_priv *xspi = spi_master_get_devdata(master); | |
352 | int ret = 0; | |
353 | ||
354 | xspi->cs = spi->chip_select; | |
355 | xspi->dev = spi->dev; | |
356 | ||
357 | if (spi_transfer_is_last(master, t)) | |
358 | xspi->cmd_cont = 0; | |
359 | else | |
360 | xspi->cmd_cont = 1; | |
361 | ||
362 | if (xlp_spi_txrx_bufs(xspi, t)) | |
363 | ret = -EIO; | |
364 | ||
365 | spi_finalize_current_transfer(master); | |
366 | return ret; | |
367 | } | |
368 | ||
369 | static int xlp_spi_probe(struct platform_device *pdev) | |
370 | { | |
371 | struct spi_master *master; | |
372 | struct xlp_spi_priv *xspi; | |
373 | struct resource *res; | |
374 | struct clk *clk; | |
375 | int irq, err; | |
376 | ||
377 | xspi = devm_kzalloc(&pdev->dev, sizeof(*xspi), GFP_KERNEL); | |
378 | if (!xspi) | |
379 | return -ENOMEM; | |
380 | ||
381 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
382 | xspi->base = devm_ioremap_resource(&pdev->dev, res); | |
383 | if (IS_ERR(xspi->base)) | |
384 | return PTR_ERR(xspi->base); | |
385 | ||
386 | irq = platform_get_irq(pdev, 0); | |
387 | if (irq < 0) { | |
9a6b9479 GS |
388 | dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq); |
389 | return irq; | |
d8c80d49 KP |
390 | } |
391 | err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0, | |
392 | pdev->name, xspi); | |
393 | if (err) { | |
394 | dev_err(&pdev->dev, "unable to request irq %d\n", irq); | |
395 | return err; | |
396 | } | |
397 | ||
398 | clk = devm_clk_get(&pdev->dev, NULL); | |
399 | if (IS_ERR(clk)) { | |
400 | dev_err(&pdev->dev, "could not get spi clock\n"); | |
097d0619 | 401 | return PTR_ERR(clk); |
d8c80d49 | 402 | } |
097d0619 | 403 | |
d8c80d49 KP |
404 | xspi->spi_clk = clk_get_rate(clk); |
405 | ||
406 | master = spi_alloc_master(&pdev->dev, 0); | |
407 | if (!master) { | |
408 | dev_err(&pdev->dev, "could not alloc master\n"); | |
409 | return -ENOMEM; | |
410 | } | |
411 | ||
412 | master->bus_num = 0; | |
413 | master->num_chipselect = XLP_SPI_MAX_CS; | |
414 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; | |
415 | master->setup = xlp_spi_setup; | |
416 | master->transfer_one = xlp_spi_transfer_one; | |
417 | master->dev.of_node = pdev->dev.of_node; | |
418 | ||
419 | init_completion(&xspi->done); | |
420 | spi_master_set_devdata(master, xspi); | |
421 | xlp_spi_sysctl_setup(xspi); | |
422 | ||
423 | /* register spi controller */ | |
424 | err = devm_spi_register_master(&pdev->dev, master); | |
425 | if (err) { | |
426 | dev_err(&pdev->dev, "spi register master failed!\n"); | |
427 | spi_master_put(master); | |
428 | return err; | |
429 | } | |
430 | ||
431 | return 0; | |
432 | } | |
433 | ||
097d0619 KP |
434 | #ifdef CONFIG_ACPI |
435 | static const struct acpi_device_id xlp_spi_acpi_match[] = { | |
436 | { "BRCM900D", 0 }, | |
251831bd | 437 | { "CAV900D", 0 }, |
097d0619 KP |
438 | { }, |
439 | }; | |
440 | MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match); | |
441 | #endif | |
442 | ||
d8c80d49 KP |
443 | static const struct of_device_id xlp_spi_dt_id[] = { |
444 | { .compatible = "netlogic,xlp832-spi" }, | |
445 | { }, | |
446 | }; | |
b87c701b | 447 | MODULE_DEVICE_TABLE(of, xlp_spi_dt_id); |
d8c80d49 KP |
448 | |
449 | static struct platform_driver xlp_spi_driver = { | |
450 | .probe = xlp_spi_probe, | |
451 | .driver = { | |
452 | .name = "xlp-spi", | |
453 | .of_match_table = xlp_spi_dt_id, | |
097d0619 | 454 | .acpi_match_table = ACPI_PTR(xlp_spi_acpi_match), |
d8c80d49 KP |
455 | }, |
456 | }; | |
457 | module_platform_driver(xlp_spi_driver); | |
458 | ||
459 | MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>"); | |
460 | MODULE_DESCRIPTION("Netlogic XLP SPI controller driver"); | |
461 | MODULE_LICENSE("GPL v2"); |