• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
22 #include <clk.h>
23 #include <dm.h>
24 #include <spi.h>
25 #include <errno.h>
26 #include <fdt_support.h>
27 #include <reset.h>
28 #include <wait_bit.h>
29 
30 #include <asm/bitops.h>
31 #include <asm/gpio.h>
32 #include <asm/io.h>
33 
34 #include <linux/iopoll.h>
35 
36 DECLARE_GLOBAL_DATA_PTR;
37 
38 /* sun4i spi registers */
39 #define SUN4I_RXDATA_REG		0x00
40 #define SUN4I_TXDATA_REG		0x04
41 #define SUN4I_CTL_REG			0x08
42 #define SUN4I_CLK_CTL_REG		0x1c
43 #define SUN4I_BURST_CNT_REG		0x20
44 #define SUN4I_XMIT_CNT_REG		0x24
45 #define SUN4I_FIFO_STA_REG		0x28
46 
47 /* sun6i spi registers */
48 #define SUN6I_GBL_CTL_REG		0x04
49 #define SUN6I_TFR_CTL_REG		0x08
50 #define SUN6I_FIFO_CTL_REG		0x18
51 #define SUN6I_FIFO_STA_REG		0x1c
52 #define SUN6I_CLK_CTL_REG		0x24
53 #define SUN6I_BURST_CNT_REG		0x30
54 #define SUN6I_XMIT_CNT_REG		0x34
55 #define SUN6I_BURST_CTL_REG		0x38
56 #define SUN6I_TXDATA_REG		0x200
57 #define SUN6I_RXDATA_REG		0x300
58 
59 /* sun spi bits */
60 #define SUN4I_CTL_ENABLE		BIT(0)
61 #define SUN4I_CTL_MASTER		BIT(1)
62 #define SUN4I_CLK_CTL_CDR2_MASK		0xff
63 #define SUN4I_CLK_CTL_CDR2(div)		((div) & SUN4I_CLK_CTL_CDR2_MASK)
64 #define SUN4I_CLK_CTL_CDR1_MASK		0xf
65 #define SUN4I_CLK_CTL_CDR1(div)		(((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
66 #define SUN4I_CLK_CTL_DRS		BIT(12)
67 #define SUN4I_MAX_XFER_SIZE		0xffffff
68 #define SUN4I_BURST_CNT(cnt)		((cnt) & SUN4I_MAX_XFER_SIZE)
69 #define SUN4I_XMIT_CNT(cnt)		((cnt) & SUN4I_MAX_XFER_SIZE)
70 #define SUN4I_FIFO_STA_RF_CNT_BITS	0
71 
72 #define SUN4I_SPI_MAX_RATE		24000000
73 #define SUN4I_SPI_MIN_RATE		3000
74 #define SUN4I_SPI_DEFAULT_RATE		1000000
75 #define SUN4I_SPI_TIMEOUT_US		1000000
76 
77 #define SPI_REG(priv, reg)		((priv)->base + \
78 					(priv)->variant->regs[reg])
79 #define SPI_BIT(priv, bit)		((priv)->variant->bits[bit])
80 #define SPI_CS(priv, cs)		(((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \
81 					SPI_BIT(priv, SPI_TCR_CS_MASK))
82 
83 /* sun spi register set */
84 enum sun4i_spi_regs {
85 	SPI_GCR,
86 	SPI_TCR,
87 	SPI_FCR,
88 	SPI_FSR,
89 	SPI_CCR,
90 	SPI_BC,
91 	SPI_TC,
92 	SPI_BCTL,
93 	SPI_TXD,
94 	SPI_RXD,
95 };
96 
97 /* sun spi register bits */
98 enum sun4i_spi_bits {
99 	SPI_GCR_TP,
100 	SPI_GCR_SRST,
101 	SPI_TCR_CPHA,
102 	SPI_TCR_CPOL,
103 	SPI_TCR_CS_ACTIVE_LOW,
104 	SPI_TCR_CS_SEL,
105 	SPI_TCR_CS_MASK,
106 	SPI_TCR_XCH,
107 	SPI_TCR_CS_MANUAL,
108 	SPI_TCR_CS_LEVEL,
109 	SPI_FCR_TF_RST,
110 	SPI_FCR_RF_RST,
111 	SPI_FSR_RF_CNT_MASK,
112 };
113 
114 struct sun4i_spi_variant {
115 	const unsigned long *regs;
116 	const u32 *bits;
117 	u32 fifo_depth;
118 	bool has_soft_reset;
119 	bool has_burst_ctl;
120 };
121 
122 struct sun4i_spi_platdata {
123 	struct sun4i_spi_variant *variant;
124 	u32 base;
125 	u32 max_hz;
126 };
127 
128 struct sun4i_spi_priv {
129 	struct sun4i_spi_variant *variant;
130 	struct clk clk_ahb, clk_mod;
131 	struct reset_ctl reset;
132 	u32 base;
133 	u32 freq;
134 	u32 mode;
135 
136 	const u8 *tx_buf;
137 	u8 *rx_buf;
138 };
139 
sun4i_spi_drain_fifo(struct sun4i_spi_priv * priv,int len)140 static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len)
141 {
142 	u8 byte;
143 
144 	while (len--) {
145 		byte = readb(SPI_REG(priv, SPI_RXD));
146 		if (priv->rx_buf)
147 			*priv->rx_buf++ = byte;
148 	}
149 }
150 
sun4i_spi_fill_fifo(struct sun4i_spi_priv * priv,int len)151 static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len)
152 {
153 	u8 byte;
154 
155 	while (len--) {
156 		byte = priv->tx_buf ? *priv->tx_buf++ : 0;
157 		writeb(byte, SPI_REG(priv, SPI_TXD));
158 	}
159 }
160 
sun4i_spi_set_cs(struct udevice * bus,u8 cs,bool enable)161 static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
162 {
163 	struct sun4i_spi_priv *priv = dev_get_priv(bus);
164 	u32 reg;
165 
166 	reg = readl(SPI_REG(priv, SPI_TCR));
167 
168 	reg &= ~SPI_BIT(priv, SPI_TCR_CS_MASK);
169 	reg |= SPI_CS(priv, cs);
170 
171 	if (enable)
172 		reg &= ~SPI_BIT(priv, SPI_TCR_CS_LEVEL);
173 	else
174 		reg |= SPI_BIT(priv, SPI_TCR_CS_LEVEL);
175 
176 	writel(reg, SPI_REG(priv, SPI_TCR));
177 }
178 
sun4i_spi_parse_pins(struct udevice * dev)179 static int sun4i_spi_parse_pins(struct udevice *dev)
180 {
181 	const void *fdt = gd->fdt_blob;
182 	const char *pin_name;
183 	const fdt32_t *list;
184 	u32 phandle;
185 	int drive, pull = 0, pin, i;
186 	int offset;
187 	int size;
188 
189 	list = fdt_getprop(fdt, dev_of_offset(dev), "pinctrl-0", &size);
190 	if (!list) {
191 		printf("WARNING: sun4i_spi: cannot find pinctrl-0 node\n");
192 		return -EINVAL;
193 	}
194 
195 	while (size) {
196 		phandle = fdt32_to_cpu(*list++);
197 		size -= sizeof(*list);
198 
199 		offset = fdt_node_offset_by_phandle(fdt, phandle);
200 		if (offset < 0)
201 			return offset;
202 
203 		drive = fdt_getprop_u32_default_node(fdt, offset, 0,
204 						     "drive-strength", 0);
205 		if (drive) {
206 			if (drive <= 10)
207 				drive = 0;
208 			else if (drive <= 20)
209 				drive = 1;
210 			else if (drive <= 30)
211 				drive = 2;
212 			else
213 				drive = 3;
214 		} else {
215 			drive = fdt_getprop_u32_default_node(fdt, offset, 0,
216 							     "allwinner,drive",
217 							      0);
218 			drive = min(drive, 3);
219 		}
220 
221 		if (fdt_get_property(fdt, offset, "bias-disable", NULL))
222 			pull = 0;
223 		else if (fdt_get_property(fdt, offset, "bias-pull-up", NULL))
224 			pull = 1;
225 		else if (fdt_get_property(fdt, offset, "bias-pull-down", NULL))
226 			pull = 2;
227 		else
228 			pull = fdt_getprop_u32_default_node(fdt, offset, 0,
229 							    "allwinner,pull",
230 							     0);
231 		pull = min(pull, 2);
232 
233 		for (i = 0; ; i++) {
234 			pin_name = fdt_stringlist_get(fdt, offset,
235 						      "pins", i, NULL);
236 			if (!pin_name) {
237 				pin_name = fdt_stringlist_get(fdt, offset,
238 							      "allwinner,pins",
239 							       i, NULL);
240 				if (!pin_name)
241 					break;
242 			}
243 
244 			pin = name_to_gpio(pin_name);
245 			if (pin < 0)
246 				break;
247 
248 			if (IS_ENABLED(CONFIG_MACH_SUN50I))
249 				sunxi_gpio_set_cfgpin(pin, SUN50I_GPC_SPI0);
250 			else
251 				sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0);
252 			sunxi_gpio_set_drv(pin, drive);
253 			sunxi_gpio_set_pull(pin, pull);
254 		}
255 	}
256 	return 0;
257 }
258 
sun4i_spi_set_clock(struct udevice * dev,bool enable)259 static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable)
260 {
261 	struct sun4i_spi_priv *priv = dev_get_priv(dev);
262 	int ret;
263 
264 	if (!enable) {
265 		clk_disable(&priv->clk_ahb);
266 		clk_disable(&priv->clk_mod);
267 		if (reset_valid(&priv->reset))
268 			reset_assert(&priv->reset);
269 		return 0;
270 	}
271 
272 	ret = clk_enable(&priv->clk_ahb);
273 	if (ret) {
274 		dev_err(dev, "failed to enable ahb clock (ret=%d)\n", ret);
275 		return ret;
276 	}
277 
278 	ret = clk_enable(&priv->clk_mod);
279 	if (ret) {
280 		dev_err(dev, "failed to enable mod clock (ret=%d)\n", ret);
281 		goto err_ahb;
282 	}
283 
284 	if (reset_valid(&priv->reset)) {
285 		ret = reset_deassert(&priv->reset);
286 		if (ret) {
287 			dev_err(dev, "failed to deassert reset\n");
288 			goto err_mod;
289 		}
290 	}
291 
292 	return 0;
293 
294 err_mod:
295 	clk_disable(&priv->clk_mod);
296 err_ahb:
297 	clk_disable(&priv->clk_ahb);
298 	return ret;
299 }
300 
sun4i_spi_claim_bus(struct udevice * dev)301 static int sun4i_spi_claim_bus(struct udevice *dev)
302 {
303 	struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
304 	int ret;
305 
306 	ret = sun4i_spi_set_clock(dev->parent, true);
307 	if (ret)
308 		return ret;
309 
310 	setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE |
311 		     SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP));
312 
313 	if (priv->variant->has_soft_reset)
314 		setbits_le32(SPI_REG(priv, SPI_GCR),
315 			     SPI_BIT(priv, SPI_GCR_SRST));
316 
317 	setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
318 		     SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
319 
320 	return 0;
321 }
322 
sun4i_spi_release_bus(struct udevice * dev)323 static int sun4i_spi_release_bus(struct udevice *dev)
324 {
325 	struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
326 
327 	clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE);
328 
329 	sun4i_spi_set_clock(dev->parent, false);
330 
331 	return 0;
332 }
333 
sun4i_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)334 static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
335 			  const void *dout, void *din, unsigned long flags)
336 {
337 	struct udevice *bus = dev->parent;
338 	struct sun4i_spi_priv *priv = dev_get_priv(bus);
339 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
340 
341 	u32 len = bitlen / 8;
342 	u32 rx_fifocnt;
343 	u8 nbytes;
344 	int ret;
345 
346 	priv->tx_buf = dout;
347 	priv->rx_buf = din;
348 
349 	if (bitlen % 8) {
350 		debug("%s: non byte-aligned SPI transfer.\n", __func__);
351 		return -ENAVAIL;
352 	}
353 
354 	if (flags & SPI_XFER_BEGIN)
355 		sun4i_spi_set_cs(bus, slave_plat->cs, true);
356 
357 	/* Reset FIFOs */
358 	setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
359 		     SPI_BIT(priv, SPI_FCR_TF_RST));
360 
361 	while (len) {
362 		/* Setup the transfer now... */
363 		nbytes = min(len, (priv->variant->fifo_depth - 1));
364 
365 		/* Setup the counters */
366 		writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC));
367 		writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC));
368 
369 		if (priv->variant->has_burst_ctl)
370 			writel(SUN4I_BURST_CNT(nbytes),
371 			       SPI_REG(priv, SPI_BCTL));
372 
373 		/* Fill the TX FIFO */
374 		sun4i_spi_fill_fifo(priv, nbytes);
375 
376 		/* Start the transfer */
377 		setbits_le32(SPI_REG(priv, SPI_TCR),
378 			     SPI_BIT(priv, SPI_TCR_XCH));
379 
380 		/* Wait till RX FIFO to be empty */
381 		ret = readl_poll_timeout(SPI_REG(priv, SPI_FSR),
382 					 rx_fifocnt,
383 					 (((rx_fifocnt &
384 					 SPI_BIT(priv, SPI_FSR_RF_CNT_MASK)) >>
385 					 SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes),
386 					 SUN4I_SPI_TIMEOUT_US);
387 		if (ret < 0) {
388 			printf("ERROR: sun4i_spi: Timeout transferring data\n");
389 			sun4i_spi_set_cs(bus, slave_plat->cs, false);
390 			return ret;
391 		}
392 
393 		/* Drain the RX FIFO */
394 		sun4i_spi_drain_fifo(priv, nbytes);
395 
396 		len -= nbytes;
397 	}
398 
399 	if (flags & SPI_XFER_END)
400 		sun4i_spi_set_cs(bus, slave_plat->cs, false);
401 
402 	return 0;
403 }
404 
sun4i_spi_set_speed(struct udevice * dev,uint speed)405 static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
406 {
407 	struct sun4i_spi_platdata *plat = dev_get_platdata(dev);
408 	struct sun4i_spi_priv *priv = dev_get_priv(dev);
409 	unsigned int div;
410 	u32 reg;
411 
412 	if (speed > plat->max_hz)
413 		speed = plat->max_hz;
414 
415 	if (speed < SUN4I_SPI_MIN_RATE)
416 		speed = SUN4I_SPI_MIN_RATE;
417 	/*
418 	 * Setup clock divider.
419 	 *
420 	 * We have two choices there. Either we can use the clock
421 	 * divide rate 1, which is calculated thanks to this formula:
422 	 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
423 	 * Or we can use CDR2, which is calculated with the formula:
424 	 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
425 	 * Whether we use the former or the latter is set through the
426 	 * DRS bit.
427 	 *
428 	 * First try CDR2, and if we can't reach the expected
429 	 * frequency, fall back to CDR1.
430 	 */
431 
432 	div = SUN4I_SPI_MAX_RATE / (2 * speed);
433 	reg = readl(SPI_REG(priv, SPI_CCR));
434 
435 	if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
436 		if (div > 0)
437 			div--;
438 
439 		reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
440 		reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
441 	} else {
442 		div = __ilog2(SUN4I_SPI_MAX_RATE) - __ilog2(speed);
443 		reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
444 		reg |= SUN4I_CLK_CTL_CDR1(div);
445 	}
446 
447 	priv->freq = speed;
448 	writel(reg, SPI_REG(priv, SPI_CCR));
449 
450 	return 0;
451 }
452 
sun4i_spi_set_mode(struct udevice * dev,uint mode)453 static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
454 {
455 	struct sun4i_spi_priv *priv = dev_get_priv(dev);
456 	u32 reg;
457 
458 	reg = readl(SPI_REG(priv, SPI_TCR));
459 	reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
460 
461 	if (mode & SPI_CPOL)
462 		reg |= SPI_BIT(priv, SPI_TCR_CPOL);
463 
464 	if (mode & SPI_CPHA)
465 		reg |= SPI_BIT(priv, SPI_TCR_CPHA);
466 
467 	priv->mode = mode;
468 	writel(reg, SPI_REG(priv, SPI_TCR));
469 
470 	return 0;
471 }
472 
473 static const struct dm_spi_ops sun4i_spi_ops = {
474 	.claim_bus		= sun4i_spi_claim_bus,
475 	.release_bus		= sun4i_spi_release_bus,
476 	.xfer			= sun4i_spi_xfer,
477 	.set_speed		= sun4i_spi_set_speed,
478 	.set_mode		= sun4i_spi_set_mode,
479 };
480 
sun4i_spi_probe(struct udevice * bus)481 static int sun4i_spi_probe(struct udevice *bus)
482 {
483 	struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
484 	struct sun4i_spi_priv *priv = dev_get_priv(bus);
485 	int ret;
486 
487 	ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb);
488 	if (ret) {
489 		dev_err(dev, "failed to get ahb clock\n");
490 		return ret;
491 	}
492 
493 	ret = clk_get_by_name(bus, "mod", &priv->clk_mod);
494 	if (ret) {
495 		dev_err(dev, "failed to get mod clock\n");
496 		return ret;
497 	}
498 
499 	ret = reset_get_by_index(bus, 0, &priv->reset);
500 	if (ret && ret != -ENOENT) {
501 		dev_err(dev, "failed to get reset\n");
502 		return ret;
503 	}
504 
505 	sun4i_spi_parse_pins(bus);
506 
507 	priv->variant = plat->variant;
508 	priv->base = plat->base;
509 	priv->freq = plat->max_hz;
510 
511 	return 0;
512 }
513 
sun4i_spi_ofdata_to_platdata(struct udevice * bus)514 static int sun4i_spi_ofdata_to_platdata(struct udevice *bus)
515 {
516 	struct sun4i_spi_platdata *plat = dev_get_platdata(bus);
517 	int node = dev_of_offset(bus);
518 
519 	plat->base = devfdt_get_addr(bus);
520 	plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus);
521 	plat->max_hz = fdtdec_get_int(gd->fdt_blob, node,
522 				      "spi-max-frequency",
523 				      SUN4I_SPI_DEFAULT_RATE);
524 
525 	if (plat->max_hz > SUN4I_SPI_MAX_RATE)
526 		plat->max_hz = SUN4I_SPI_MAX_RATE;
527 
528 	return 0;
529 }
530 
531 static const unsigned long sun4i_spi_regs[] = {
532 	[SPI_GCR]		= SUN4I_CTL_REG,
533 	[SPI_TCR]		= SUN4I_CTL_REG,
534 	[SPI_FCR]		= SUN4I_CTL_REG,
535 	[SPI_FSR]		= SUN4I_FIFO_STA_REG,
536 	[SPI_CCR]		= SUN4I_CLK_CTL_REG,
537 	[SPI_BC]		= SUN4I_BURST_CNT_REG,
538 	[SPI_TC]		= SUN4I_XMIT_CNT_REG,
539 	[SPI_TXD]		= SUN4I_TXDATA_REG,
540 	[SPI_RXD]		= SUN4I_RXDATA_REG,
541 };
542 
543 static const u32 sun4i_spi_bits[] = {
544 	[SPI_GCR_TP]		= BIT(18),
545 	[SPI_TCR_CPHA]		= BIT(2),
546 	[SPI_TCR_CPOL]		= BIT(3),
547 	[SPI_TCR_CS_ACTIVE_LOW] = BIT(4),
548 	[SPI_TCR_XCH]		= BIT(10),
549 	[SPI_TCR_CS_SEL]	= 12,
550 	[SPI_TCR_CS_MASK]	= 0x3000,
551 	[SPI_TCR_CS_MANUAL]	= BIT(16),
552 	[SPI_TCR_CS_LEVEL]	= BIT(17),
553 	[SPI_FCR_TF_RST]	= BIT(8),
554 	[SPI_FCR_RF_RST]	= BIT(9),
555 	[SPI_FSR_RF_CNT_MASK]	= GENMASK(6, 0),
556 };
557 
558 static const unsigned long sun6i_spi_regs[] = {
559 	[SPI_GCR]		= SUN6I_GBL_CTL_REG,
560 	[SPI_TCR]		= SUN6I_TFR_CTL_REG,
561 	[SPI_FCR]		= SUN6I_FIFO_CTL_REG,
562 	[SPI_FSR]		= SUN6I_FIFO_STA_REG,
563 	[SPI_CCR]		= SUN6I_CLK_CTL_REG,
564 	[SPI_BC]		= SUN6I_BURST_CNT_REG,
565 	[SPI_TC]		= SUN6I_XMIT_CNT_REG,
566 	[SPI_BCTL]		= SUN6I_BURST_CTL_REG,
567 	[SPI_TXD]		= SUN6I_TXDATA_REG,
568 	[SPI_RXD]		= SUN6I_RXDATA_REG,
569 };
570 
571 static const u32 sun6i_spi_bits[] = {
572 	[SPI_GCR_TP]		= BIT(7),
573 	[SPI_GCR_SRST]		= BIT(31),
574 	[SPI_TCR_CPHA]		= BIT(0),
575 	[SPI_TCR_CPOL]		= BIT(1),
576 	[SPI_TCR_CS_ACTIVE_LOW] = BIT(2),
577 	[SPI_TCR_CS_SEL]	= 4,
578 	[SPI_TCR_CS_MASK]	= 0x30,
579 	[SPI_TCR_CS_MANUAL]	= BIT(6),
580 	[SPI_TCR_CS_LEVEL]	= BIT(7),
581 	[SPI_TCR_XCH]		= BIT(31),
582 	[SPI_FCR_RF_RST]	= BIT(15),
583 	[SPI_FCR_TF_RST]	= BIT(31),
584 	[SPI_FSR_RF_CNT_MASK]	= GENMASK(7, 0),
585 };
586 
587 static const struct sun4i_spi_variant sun4i_a10_spi_variant = {
588 	.regs			= sun4i_spi_regs,
589 	.bits			= sun4i_spi_bits,
590 	.fifo_depth		= 64,
591 };
592 
593 static const struct sun4i_spi_variant sun6i_a31_spi_variant = {
594 	.regs			= sun6i_spi_regs,
595 	.bits			= sun6i_spi_bits,
596 	.fifo_depth		= 128,
597 	.has_soft_reset		= true,
598 	.has_burst_ctl		= true,
599 };
600 
601 static const struct sun4i_spi_variant sun8i_h3_spi_variant = {
602 	.regs			= sun6i_spi_regs,
603 	.bits			= sun6i_spi_bits,
604 	.fifo_depth		= 64,
605 	.has_soft_reset		= true,
606 	.has_burst_ctl		= true,
607 };
608 
609 static const struct udevice_id sun4i_spi_ids[] = {
610 	{
611 	  .compatible = "allwinner,sun4i-a10-spi",
612 	  .data = (ulong)&sun4i_a10_spi_variant,
613 	},
614 	{
615 	  .compatible = "allwinner,sun6i-a31-spi",
616 	  .data = (ulong)&sun6i_a31_spi_variant,
617 	},
618 	{
619 	  .compatible = "allwinner,sun8i-h3-spi",
620 	  .data = (ulong)&sun8i_h3_spi_variant,
621 	},
622 	{ /* sentinel */ }
623 };
624 
625 U_BOOT_DRIVER(sun4i_spi) = {
626 	.name	= "sun4i_spi",
627 	.id	= UCLASS_SPI,
628 	.of_match	= sun4i_spi_ids,
629 	.ops	= &sun4i_spi_ops,
630 	.ofdata_to_platdata	= sun4i_spi_ofdata_to_platdata,
631 	.platdata_auto_alloc_size	= sizeof(struct sun4i_spi_platdata),
632 	.priv_auto_alloc_size	= sizeof(struct sun4i_spi_priv),
633 	.probe	= sun4i_spi_probe,
634 };
635