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