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