mx6sabresd: convert to DM_VIDEO
[oweals/u-boot.git] / drivers / spi / spi-sunxi.c
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
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
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
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
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
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
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
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
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
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
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
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
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 };