blob: 4324d686eb20d8f35f140b3d07559cf197345070 [file] [log] [blame]
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +02001/*
2 * (C) Copyright 2017 Whitebox Systems / Northend Systems B.V.
3 * S.J.R. van Schaik <stephan@whiteboxsystems.nl>
4 * M.B.W. Wajer <merlijn@whiteboxsystems.nl>
5 *
6 * (C) Copyright 2017 Olimex Ltd..
7 * Stefan Mavrodiev <stefan@olimex.com>
8 *
9 * Based on linux spi driver. Original copyright follows:
10 * linux/drivers/spi/spi-sun4i.c
11 *
12 * Copyright (C) 2012 - 2014 Allwinner Tech
13 * Pan Nan <pannan@allwinnertech.com>
14 *
15 * Copyright (C) 2014 Maxime Ripard
16 * Maxime Ripard <maxime.ripard@free-electrons.com>
17 *
18 * SPDX-License-Identifier: GPL-2.0+
19 */
20
21#include <common.h>
Jagan Teki8d71a192019-02-27 20:02:10 +053022#include <clk.h>
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020023#include <dm.h>
24#include <spi.h>
25#include <errno.h>
26#include <fdt_support.h>
27#include <wait_bit.h>
28
29#include <asm/bitops.h>
30#include <asm/gpio.h>
31#include <asm/io.h>
32
Jagan Teki6cb6aa62019-02-27 20:02:05 +053033#include <linux/iopoll.h>
34
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020035#define SUN4I_RXDATA_REG 0x00
36
37#define SUN4I_TXDATA_REG 0x04
38
39#define SUN4I_CTL_REG 0x08
40#define SUN4I_CTL_ENABLE BIT(0)
41#define SUN4I_CTL_MASTER BIT(1)
42#define SUN4I_CTL_CPHA BIT(2)
43#define SUN4I_CTL_CPOL BIT(3)
44#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4)
45#define SUN4I_CTL_LMTF BIT(6)
46#define SUN4I_CTL_TF_RST BIT(8)
47#define SUN4I_CTL_RF_RST BIT(9)
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020048#define SUN4I_CTL_XCH BIT(10)
49#define SUN4I_CTL_CS_MASK 0x3000
50#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK)
51#define SUN4I_CTL_DHB BIT(15)
52#define SUN4I_CTL_CS_MANUAL BIT(16)
53#define SUN4I_CTL_CS_LEVEL BIT(17)
54#define SUN4I_CTL_TP BIT(18)
55
56#define SUN4I_INT_CTL_REG 0x0c
57#define SUN4I_INT_CTL_RF_F34 BIT(4)
58#define SUN4I_INT_CTL_TF_E34 BIT(12)
59#define SUN4I_INT_CTL_TC BIT(16)
60
61#define SUN4I_INT_STA_REG 0x10
62
63#define SUN4I_DMA_CTL_REG 0x14
64
65#define SUN4I_WAIT_REG 0x18
66
67#define SUN4I_CLK_CTL_REG 0x1c
68#define SUN4I_CLK_CTL_CDR2_MASK 0xff
69#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
70#define SUN4I_CLK_CTL_CDR1_MASK 0xf
71#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
72#define SUN4I_CLK_CTL_DRS BIT(12)
73
74#define SUN4I_MAX_XFER_SIZE 0xffffff
75
76#define SUN4I_BURST_CNT_REG 0x20
77#define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
78
79#define SUN4I_XMIT_CNT_REG 0x24
80#define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
81
82#define SUN4I_FIFO_STA_REG 0x28
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020083#define SUN4I_FIFO_STA_RF_CNT_BITS 0
84#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
85#define SUN4I_FIFO_STA_TF_CNT_BITS 16
86
87#define SUN4I_SPI_MAX_RATE 24000000
88#define SUN4I_SPI_MIN_RATE 3000
89#define SUN4I_SPI_DEFAULT_RATE 1000000
90#define SUN4I_SPI_TIMEOUT_US 1000000
91
Jagan Teki8d9bf462019-02-27 20:02:08 +053092#define SPI_REG(priv, reg) ((priv)->base_addr + \
93 (priv)->variant->regs[reg])
94#define SPI_BIT(priv, bit) ((priv)->variant->bits[bit])
95#define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \
96 SPI_BIT(priv, SPI_TCR_CS_MASK))
97
98/* sun spi register set */
99enum sun4i_spi_regs {
100 SPI_GCR,
101 SPI_TCR,
102 SPI_FCR,
103 SPI_FSR,
104 SPI_CCR,
105 SPI_BC,
106 SPI_TC,
107 SPI_BCTL,
108 SPI_TXD,
109 SPI_RXD,
110};
111
112/* sun spi register bits */
113enum sun4i_spi_bits {
114 SPI_GCR_TP,
115 SPI_TCR_CPHA,
116 SPI_TCR_CPOL,
117 SPI_TCR_CS_ACTIVE_LOW,
118 SPI_TCR_CS_SEL,
119 SPI_TCR_CS_MASK,
120 SPI_TCR_XCH,
121 SPI_TCR_CS_MANUAL,
122 SPI_TCR_CS_LEVEL,
123 SPI_FCR_TF_RST,
124 SPI_FCR_RF_RST,
125 SPI_FSR_RF_CNT_MASK,
126};
127
128struct sun4i_spi_variant {
129 const unsigned long *regs;
130 const u32 *bits;
Jagan Teki178fbd22019-02-27 20:02:09 +0530131 u32 fifo_depth;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200132};
133
134struct sun4i_spi_platdata {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530135 struct sun4i_spi_variant *variant;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200136 u32 base_addr;
137 u32 max_hz;
138};
139
140struct sun4i_spi_priv {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530141 struct sun4i_spi_variant *variant;
Jagan Teki8d71a192019-02-27 20:02:10 +0530142 struct clk clk_ahb, clk_mod;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530143 u32 base_addr;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200144 u32 freq;
145 u32 mode;
146
147 const u8 *tx_buf;
148 u8 *rx_buf;
149};
150
151DECLARE_GLOBAL_DATA_PTR;
152
153static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len)
154{
155 u8 byte;
156
157 while (len--) {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530158 byte = readb(SPI_REG(priv, SPI_RXD));
Stefan Mavrodiev5c1a87d2018-12-05 14:27:57 +0200159 if (priv->rx_buf)
160 *priv->rx_buf++ = byte;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200161 }
162}
163
164static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len)
165{
166 u8 byte;
167
168 while (len--) {
169 byte = priv->tx_buf ? *priv->tx_buf++ : 0;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530170 writeb(byte, SPI_REG(priv, SPI_TXD));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200171 }
172}
173
174static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
175{
176 struct sun4i_spi_priv *priv = dev_get_priv(bus);
177 u32 reg;
178
Jagan Teki8d9bf462019-02-27 20:02:08 +0530179 reg = readl(SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200180
Jagan Teki8d9bf462019-02-27 20:02:08 +0530181 reg &= ~SPI_BIT(priv, SPI_TCR_CS_MASK);
182 reg |= SPI_CS(priv, cs);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200183
184 if (enable)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530185 reg &= ~SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200186 else
Jagan Teki8d9bf462019-02-27 20:02:08 +0530187 reg |= SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200188
Jagan Teki8d9bf462019-02-27 20:02:08 +0530189 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200190}
191
192static int sun4i_spi_parse_pins(struct udevice *dev)
193{
194 const void *fdt = gd->fdt_blob;
195 const char *pin_name;
196 const fdt32_t *list;
197 u32 phandle;
198 int drive, pull = 0, pin, i;
199 int offset;
200 int size;
201
202 list = fdt_getprop(fdt, dev_of_offset(dev), "pinctrl-0", &size);
203 if (!list) {
204 printf("WARNING: sun4i_spi: cannot find pinctrl-0 node\n");
205 return -EINVAL;
206 }
207
208 while (size) {
209 phandle = fdt32_to_cpu(*list++);
210 size -= sizeof(*list);
211
212 offset = fdt_node_offset_by_phandle(fdt, phandle);
213 if (offset < 0)
214 return offset;
215
216 drive = fdt_getprop_u32_default_node(fdt, offset, 0,
217 "drive-strength", 0);
218 if (drive) {
219 if (drive <= 10)
220 drive = 0;
221 else if (drive <= 20)
222 drive = 1;
223 else if (drive <= 30)
224 drive = 2;
225 else
226 drive = 3;
227 } else {
228 drive = fdt_getprop_u32_default_node(fdt, offset, 0,
229 "allwinner,drive",
230 0);
231 drive = min(drive, 3);
232 }
233
234 if (fdt_get_property(fdt, offset, "bias-disable", NULL))
235 pull = 0;
236 else if (fdt_get_property(fdt, offset, "bias-pull-up", NULL))
237 pull = 1;
238 else if (fdt_get_property(fdt, offset, "bias-pull-down", NULL))
239 pull = 2;
240 else
241 pull = fdt_getprop_u32_default_node(fdt, offset, 0,
242 "allwinner,pull",
243 0);
244 pull = min(pull, 2);
245
246 for (i = 0; ; i++) {
247 pin_name = fdt_stringlist_get(fdt, offset,
248 "pins", i, NULL);
249 if (!pin_name) {
250 pin_name = fdt_stringlist_get(fdt, offset,
251 "allwinner,pins",
252 i, NULL);
253 if (!pin_name)
254 break;
255 }
256
257 pin = name_to_gpio(pin_name);
258 if (pin < 0)
259 break;
260
261 sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0);
262 sunxi_gpio_set_drv(pin, drive);
263 sunxi_gpio_set_pull(pin, pull);
264 }
265 }
266 return 0;
267}
268
Jagan Teki8d71a192019-02-27 20:02:10 +0530269static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable)
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200270{
Jagan Teki8d71a192019-02-27 20:02:10 +0530271 struct sun4i_spi_priv *priv = dev_get_priv(dev);
272 int ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200273
Jagan Teki8d71a192019-02-27 20:02:10 +0530274 if (!enable) {
275 clk_disable(&priv->clk_ahb);
276 clk_disable(&priv->clk_mod);
277 return 0;
278 }
279
280 ret = clk_enable(&priv->clk_ahb);
281 if (ret) {
282 dev_err(dev, "failed to enable ahb clock (ret=%d)\n", ret);
283 return ret;
284 }
285
286 ret = clk_enable(&priv->clk_mod);
287 if (ret) {
288 dev_err(dev, "failed to enable mod clock (ret=%d)\n", ret);
289 goto err_ahb;
290 }
291
292 return 0;
293
294err_ahb:
295 clk_disable(&priv->clk_ahb);
296 return ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200297}
298
299static int sun4i_spi_ofdata_to_platdata(struct udevice *bus)
300{
301 struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
302 int node = dev_of_offset(bus);
303
304 plat->base_addr = devfdt_get_addr(bus);
Jagan Teki8d9bf462019-02-27 20:02:08 +0530305 plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200306 plat->max_hz = fdtdec_get_int(gd->fdt_blob, node,
307 "spi-max-frequency",
308 SUN4I_SPI_DEFAULT_RATE);
309
310 if (plat->max_hz > SUN4I_SPI_MAX_RATE)
311 plat->max_hz = SUN4I_SPI_MAX_RATE;
312
313 return 0;
314}
315
316static int sun4i_spi_probe(struct udevice *bus)
317{
318 struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
319 struct sun4i_spi_priv *priv = dev_get_priv(bus);
Jagan Teki8d71a192019-02-27 20:02:10 +0530320 int ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200321
Jagan Teki8d71a192019-02-27 20:02:10 +0530322 ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb);
323 if (ret) {
324 dev_err(dev, "failed to get ahb clock\n");
325 return ret;
326 }
327
328 ret = clk_get_by_name(bus, "mod", &priv->clk_mod);
329 if (ret) {
330 dev_err(dev, "failed to get mod clock\n");
331 return ret;
332 }
333
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200334 sun4i_spi_parse_pins(bus);
335
Jagan Teki8d9bf462019-02-27 20:02:08 +0530336 priv->variant = plat->variant;
337 priv->base_addr = plat->base_addr;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200338 priv->freq = plat->max_hz;
339
340 return 0;
341}
342
343static int sun4i_spi_claim_bus(struct udevice *dev)
344{
345 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Jagan Teki8d71a192019-02-27 20:02:10 +0530346 int ret;
347
348 ret = sun4i_spi_set_clock(dev->parent, true);
349 if (ret)
350 return ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200351
Jagan Teki8d9bf462019-02-27 20:02:08 +0530352 setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE |
353 SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP));
354
355 setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
356 SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
Jagan Teki8cbf09b2019-02-27 20:02:07 +0530357
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200358 return 0;
359}
360
361static int sun4i_spi_release_bus(struct udevice *dev)
362{
363 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200364
Jagan Teki8d9bf462019-02-27 20:02:08 +0530365 clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200366
Jagan Teki8d71a192019-02-27 20:02:10 +0530367 sun4i_spi_set_clock(dev->parent, false);
368
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200369 return 0;
370}
371
372static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
373 const void *dout, void *din, unsigned long flags)
374{
375 struct udevice *bus = dev->parent;
376 struct sun4i_spi_priv *priv = dev_get_priv(bus);
377 struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
378
379 u32 len = bitlen / 8;
Jagan Teki8cbf09b2019-02-27 20:02:07 +0530380 u32 rx_fifocnt;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200381 u8 nbytes;
382 int ret;
383
384 priv->tx_buf = dout;
385 priv->rx_buf = din;
386
387 if (bitlen % 8) {
388 debug("%s: non byte-aligned SPI transfer.\n", __func__);
389 return -ENAVAIL;
390 }
391
392 if (flags & SPI_XFER_BEGIN)
393 sun4i_spi_set_cs(bus, slave_plat->cs, true);
394
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200395 /* Reset FIFOs */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530396 setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
397 SPI_BIT(priv, SPI_FCR_TF_RST));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200398
399 while (len) {
400 /* Setup the transfer now... */
Jagan Teki178fbd22019-02-27 20:02:09 +0530401 nbytes = min(len, (priv->variant->fifo_depth - 1));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200402
403 /* Setup the counters */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530404 writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC));
405 writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200406
407 /* Fill the TX FIFO */
408 sun4i_spi_fill_fifo(priv, nbytes);
409
410 /* Start the transfer */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530411 setbits_le32(SPI_REG(priv, SPI_TCR),
412 SPI_BIT(priv, SPI_TCR_XCH));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200413
Jagan Teki6cb6aa62019-02-27 20:02:05 +0530414 /* Wait till RX FIFO to be empty */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530415 ret = readl_poll_timeout(SPI_REG(priv, SPI_FSR),
416 rx_fifocnt,
417 (((rx_fifocnt &
418 SPI_BIT(priv, SPI_FSR_RF_CNT_MASK)) >>
Jagan Teki6cb6aa62019-02-27 20:02:05 +0530419 SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes),
420 SUN4I_SPI_TIMEOUT_US);
421 if (ret < 0) {
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200422 printf("ERROR: sun4i_spi: Timeout transferring data\n");
423 sun4i_spi_set_cs(bus, slave_plat->cs, false);
424 return ret;
425 }
426
427 /* Drain the RX FIFO */
428 sun4i_spi_drain_fifo(priv, nbytes);
429
430 len -= nbytes;
431 }
432
433 if (flags & SPI_XFER_END)
434 sun4i_spi_set_cs(bus, slave_plat->cs, false);
435
436 return 0;
437}
438
439static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
440{
441 struct sun4i_spi_platdata *plat = dev_get_platdata(dev);
442 struct sun4i_spi_priv *priv = dev_get_priv(dev);
443 unsigned int div;
444 u32 reg;
445
446 if (speed > plat->max_hz)
447 speed = plat->max_hz;
448
449 if (speed < SUN4I_SPI_MIN_RATE)
450 speed = SUN4I_SPI_MIN_RATE;
451 /*
452 * Setup clock divider.
453 *
454 * We have two choices there. Either we can use the clock
455 * divide rate 1, which is calculated thanks to this formula:
456 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
457 * Or we can use CDR2, which is calculated with the formula:
458 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
459 * Whether we use the former or the latter is set through the
460 * DRS bit.
461 *
462 * First try CDR2, and if we can't reach the expected
463 * frequency, fall back to CDR1.
464 */
465
466 div = SUN4I_SPI_MAX_RATE / (2 * speed);
Jagan Teki8d9bf462019-02-27 20:02:08 +0530467 reg = readl(SPI_REG(priv, SPI_CCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200468
469 if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
470 if (div > 0)
471 div--;
472
473 reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
474 reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
475 } else {
476 div = __ilog2(SUN4I_SPI_MAX_RATE) - __ilog2(speed);
477 reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
478 reg |= SUN4I_CLK_CTL_CDR1(div);
479 }
480
481 priv->freq = speed;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530482 writel(reg, SPI_REG(priv, SPI_CCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200483
484 return 0;
485}
486
487static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
488{
489 struct sun4i_spi_priv *priv = dev_get_priv(dev);
490 u32 reg;
491
Jagan Teki8d9bf462019-02-27 20:02:08 +0530492 reg = readl(SPI_REG(priv, SPI_TCR));
493 reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200494
495 if (mode & SPI_CPOL)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530496 reg |= SPI_BIT(priv, SPI_TCR_CPOL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200497
498 if (mode & SPI_CPHA)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530499 reg |= SPI_BIT(priv, SPI_TCR_CPHA);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200500
501 priv->mode = mode;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530502 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200503
504 return 0;
505}
506
507static const struct dm_spi_ops sun4i_spi_ops = {
508 .claim_bus = sun4i_spi_claim_bus,
509 .release_bus = sun4i_spi_release_bus,
510 .xfer = sun4i_spi_xfer,
511 .set_speed = sun4i_spi_set_speed,
512 .set_mode = sun4i_spi_set_mode,
513};
514
Jagan Teki8d9bf462019-02-27 20:02:08 +0530515static const unsigned long sun4i_spi_regs[] = {
516 [SPI_GCR] = SUN4I_CTL_REG,
517 [SPI_TCR] = SUN4I_CTL_REG,
518 [SPI_FCR] = SUN4I_CTL_REG,
519 [SPI_FSR] = SUN4I_FIFO_STA_REG,
520 [SPI_CCR] = SUN4I_CLK_CTL_REG,
521 [SPI_BC] = SUN4I_BURST_CNT_REG,
522 [SPI_TC] = SUN4I_XMIT_CNT_REG,
523 [SPI_TXD] = SUN4I_TXDATA_REG,
524 [SPI_RXD] = SUN4I_RXDATA_REG,
525};
526
527static const u32 sun4i_spi_bits[] = {
528 [SPI_GCR_TP] = BIT(18),
529 [SPI_TCR_CPHA] = BIT(2),
530 [SPI_TCR_CPOL] = BIT(3),
531 [SPI_TCR_CS_ACTIVE_LOW] = BIT(4),
532 [SPI_TCR_XCH] = BIT(10),
533 [SPI_TCR_CS_SEL] = 12,
534 [SPI_TCR_CS_MASK] = 0x3000,
535 [SPI_TCR_CS_MANUAL] = BIT(16),
536 [SPI_TCR_CS_LEVEL] = BIT(17),
537 [SPI_FCR_TF_RST] = BIT(8),
538 [SPI_FCR_RF_RST] = BIT(9),
539 [SPI_FSR_RF_CNT_MASK] = GENMASK(6, 0),
540};
541
542static const struct sun4i_spi_variant sun4i_a10_spi_variant = {
543 .regs = sun4i_spi_regs,
544 .bits = sun4i_spi_bits,
Jagan Teki178fbd22019-02-27 20:02:09 +0530545 .fifo_depth = 64,
Jagan Teki8d9bf462019-02-27 20:02:08 +0530546};
547
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200548static const struct udevice_id sun4i_spi_ids[] = {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530549 {
550 .compatible = "allwinner,sun4i-a10-spi",
551 .data = (ulong)&sun4i_a10_spi_variant,
552 },
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200553 { }
554};
555
556U_BOOT_DRIVER(sun4i_spi) = {
557 .name = "sun4i_spi",
558 .id = UCLASS_SPI,
559 .of_match = sun4i_spi_ids,
560 .ops = &sun4i_spi_ops,
561 .ofdata_to_platdata = sun4i_spi_ofdata_to_platdata,
562 .platdata_auto_alloc_size = sizeof(struct sun4i_spi_platdata),
563 .priv_auto_alloc_size = sizeof(struct sun4i_spi_priv),
564 .probe = sun4i_spi_probe,
565};