blob: dbfeac77eecf1f2fd7f09c3c2e31bc14365140b2 [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>
Jagan Teki853f4512019-02-27 20:02:11 +053027#include <reset.h>
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020028#include <wait_bit.h>
29
30#include <asm/bitops.h>
31#include <asm/gpio.h>
32#include <asm/io.h>
33
Jagan Teki6cb6aa62019-02-27 20:02:05 +053034#include <linux/iopoll.h>
35
Jagan Teki903e7cf2019-02-27 20:02:12 +053036DECLARE_GLOBAL_DATA_PTR;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020037
Jagan Teki903e7cf2019-02-27 20:02:12 +053038/* 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
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020046
Jagan Teki853f4512019-02-27 20:02:11 +053047/* 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
Jagan Teki903e7cf2019-02-27 20:02:12 +053059/* 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
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020071
Jagan Teki903e7cf2019-02-27 20:02:12 +053072#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 + \
Jagan Teki8d9bf462019-02-27 20:02:08 +053078 (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 */
84enum 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 */
98enum sun4i_spi_bits {
99 SPI_GCR_TP,
Jagan Teki853f4512019-02-27 20:02:11 +0530100 SPI_GCR_SRST,
Jagan Teki8d9bf462019-02-27 20:02:08 +0530101 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
114struct sun4i_spi_variant {
115 const unsigned long *regs;
116 const u32 *bits;
Jagan Teki178fbd22019-02-27 20:02:09 +0530117 u32 fifo_depth;
Jagan Teki853f4512019-02-27 20:02:11 +0530118 bool has_soft_reset;
119 bool has_burst_ctl;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200120};
121
122struct sun4i_spi_platdata {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530123 struct sun4i_spi_variant *variant;
Jagan Teki903e7cf2019-02-27 20:02:12 +0530124 u32 base;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200125 u32 max_hz;
126};
127
128struct sun4i_spi_priv {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530129 struct sun4i_spi_variant *variant;
Jagan Teki8d71a192019-02-27 20:02:10 +0530130 struct clk clk_ahb, clk_mod;
Jagan Teki853f4512019-02-27 20:02:11 +0530131 struct reset_ctl reset;
Jagan Teki903e7cf2019-02-27 20:02:12 +0530132 u32 base;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200133 u32 freq;
134 u32 mode;
135
136 const u8 *tx_buf;
137 u8 *rx_buf;
138};
139
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200140static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len)
141{
142 u8 byte;
143
144 while (len--) {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530145 byte = readb(SPI_REG(priv, SPI_RXD));
Stefan Mavrodiev5c1a87d2018-12-05 14:27:57 +0200146 if (priv->rx_buf)
147 *priv->rx_buf++ = byte;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200148 }
149}
150
151static 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;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530157 writeb(byte, SPI_REG(priv, SPI_TXD));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200158 }
159}
160
161static 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
Jagan Teki8d9bf462019-02-27 20:02:08 +0530166 reg = readl(SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200167
Jagan Teki8d9bf462019-02-27 20:02:08 +0530168 reg &= ~SPI_BIT(priv, SPI_TCR_CS_MASK);
169 reg |= SPI_CS(priv, cs);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200170
171 if (enable)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530172 reg &= ~SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200173 else
Jagan Teki8d9bf462019-02-27 20:02:08 +0530174 reg |= SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200175
Jagan Teki8d9bf462019-02-27 20:02:08 +0530176 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200177}
178
179static 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
Jagan Teki853f4512019-02-27 20:02:11 +0530248 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);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200252 sunxi_gpio_set_drv(pin, drive);
253 sunxi_gpio_set_pull(pin, pull);
254 }
255 }
256 return 0;
257}
258
Jagan Teki8d71a192019-02-27 20:02:10 +0530259static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable)
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200260{
Jagan Teki8d71a192019-02-27 20:02:10 +0530261 struct sun4i_spi_priv *priv = dev_get_priv(dev);
262 int ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200263
Jagan Teki8d71a192019-02-27 20:02:10 +0530264 if (!enable) {
265 clk_disable(&priv->clk_ahb);
266 clk_disable(&priv->clk_mod);
Jagan Teki853f4512019-02-27 20:02:11 +0530267 if (reset_valid(&priv->reset))
268 reset_assert(&priv->reset);
Jagan Teki8d71a192019-02-27 20:02:10 +0530269 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
Jagan Teki853f4512019-02-27 20:02:11 +0530284 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
Jagan Teki8d71a192019-02-27 20:02:10 +0530292 return 0;
293
Jagan Teki853f4512019-02-27 20:02:11 +0530294err_mod:
295 clk_disable(&priv->clk_mod);
Jagan Teki8d71a192019-02-27 20:02:10 +0530296err_ahb:
297 clk_disable(&priv->clk_ahb);
298 return ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200299}
300
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200301static int sun4i_spi_claim_bus(struct udevice *dev)
302{
303 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Jagan Teki8d71a192019-02-27 20:02:10 +0530304 int ret;
305
306 ret = sun4i_spi_set_clock(dev->parent, true);
307 if (ret)
308 return ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200309
Jagan Teki8d9bf462019-02-27 20:02:08 +0530310 setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE |
311 SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP));
312
Jagan Teki853f4512019-02-27 20:02:11 +0530313 if (priv->variant->has_soft_reset)
314 setbits_le32(SPI_REG(priv, SPI_GCR),
315 SPI_BIT(priv, SPI_GCR_SRST));
316
Jagan Teki8d9bf462019-02-27 20:02:08 +0530317 setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
318 SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
Jagan Teki8cbf09b2019-02-27 20:02:07 +0530319
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200320 return 0;
321}
322
323static int sun4i_spi_release_bus(struct udevice *dev)
324{
325 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200326
Jagan Teki8d9bf462019-02-27 20:02:08 +0530327 clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200328
Jagan Teki8d71a192019-02-27 20:02:10 +0530329 sun4i_spi_set_clock(dev->parent, false);
330
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200331 return 0;
332}
333
334static 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;
Jagan Teki8cbf09b2019-02-27 20:02:07 +0530342 u32 rx_fifocnt;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200343 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
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200357 /* Reset FIFOs */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530358 setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
359 SPI_BIT(priv, SPI_FCR_TF_RST));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200360
361 while (len) {
362 /* Setup the transfer now... */
Jagan Teki178fbd22019-02-27 20:02:09 +0530363 nbytes = min(len, (priv->variant->fifo_depth - 1));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200364
365 /* Setup the counters */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530366 writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC));
367 writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200368
Jagan Teki853f4512019-02-27 20:02:11 +0530369 if (priv->variant->has_burst_ctl)
370 writel(SUN4I_BURST_CNT(nbytes),
371 SPI_REG(priv, SPI_BCTL));
372
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200373 /* Fill the TX FIFO */
374 sun4i_spi_fill_fifo(priv, nbytes);
375
376 /* Start the transfer */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530377 setbits_le32(SPI_REG(priv, SPI_TCR),
378 SPI_BIT(priv, SPI_TCR_XCH));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200379
Jagan Teki6cb6aa62019-02-27 20:02:05 +0530380 /* Wait till RX FIFO to be empty */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530381 ret = readl_poll_timeout(SPI_REG(priv, SPI_FSR),
382 rx_fifocnt,
383 (((rx_fifocnt &
384 SPI_BIT(priv, SPI_FSR_RF_CNT_MASK)) >>
Jagan Teki6cb6aa62019-02-27 20:02:05 +0530385 SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes),
386 SUN4I_SPI_TIMEOUT_US);
387 if (ret < 0) {
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200388 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
405static 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);
Jagan Teki8d9bf462019-02-27 20:02:08 +0530433 reg = readl(SPI_REG(priv, SPI_CCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200434
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;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530448 writel(reg, SPI_REG(priv, SPI_CCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200449
450 return 0;
451}
452
453static 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
Jagan Teki8d9bf462019-02-27 20:02:08 +0530458 reg = readl(SPI_REG(priv, SPI_TCR));
459 reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200460
461 if (mode & SPI_CPOL)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530462 reg |= SPI_BIT(priv, SPI_TCR_CPOL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200463
464 if (mode & SPI_CPHA)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530465 reg |= SPI_BIT(priv, SPI_TCR_CPHA);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200466
467 priv->mode = mode;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530468 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200469
470 return 0;
471}
472
473static 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
Jagan Teki903e7cf2019-02-27 20:02:12 +0530481static 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
514static 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
Jagan Teki8d9bf462019-02-27 20:02:08 +0530531static 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
543static 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
Jagan Teki853f4512019-02-27 20:02:11 +0530558static 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
571static 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
Jagan Teki8d9bf462019-02-27 20:02:08 +0530587static const struct sun4i_spi_variant sun4i_a10_spi_variant = {
588 .regs = sun4i_spi_regs,
589 .bits = sun4i_spi_bits,
Jagan Teki178fbd22019-02-27 20:02:09 +0530590 .fifo_depth = 64,
Jagan Teki8d9bf462019-02-27 20:02:08 +0530591};
592
Jagan Teki853f4512019-02-27 20:02:11 +0530593static 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
601static 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
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200609static const struct udevice_id sun4i_spi_ids[] = {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530610 {
611 .compatible = "allwinner,sun4i-a10-spi",
612 .data = (ulong)&sun4i_a10_spi_variant,
613 },
Jagan Teki853f4512019-02-27 20:02:11 +0530614 {
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 },
Jagan Teki903e7cf2019-02-27 20:02:12 +0530622 { /* sentinel */ }
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200623};
624
625U_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};