blob: e00532a371b420d0fe88b337b0fd68ac71ef5bba [file] [log] [blame]
Stefan Mavrodiev5d716042018-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
Jagan Teki97b3d5a2019-02-27 20:02:10 +053021#include <clk.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020022#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060023#include <log.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020024#include <spi.h>
25#include <errno.h>
26#include <fdt_support.h>
Jagan Tekif69b4252019-02-27 20:02:11 +053027#include <reset.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020028#include <wait_bit.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060029#include <asm/global_data.h>
Simon Glass9bc15642020-02-03 07:36:16 -070030#include <dm/device_compat.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060031#include <linux/bitops.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020032
33#include <asm/bitops.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020034#include <asm/io.h>
35
Jagan Teki66220da2019-02-27 20:02:05 +053036#include <linux/iopoll.h>
37
Jagan Teki3f53a582019-02-27 20:02:12 +053038DECLARE_GLOBAL_DATA_PTR;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020039
Jagan Teki3f53a582019-02-27 20:02:12 +053040/* sun4i spi registers */
41#define SUN4I_RXDATA_REG 0x00
42#define SUN4I_TXDATA_REG 0x04
43#define SUN4I_CTL_REG 0x08
44#define SUN4I_CLK_CTL_REG 0x1c
45#define SUN4I_BURST_CNT_REG 0x20
46#define SUN4I_XMIT_CNT_REG 0x24
47#define SUN4I_FIFO_STA_REG 0x28
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020048
Jagan Tekif69b4252019-02-27 20:02:11 +053049/* sun6i spi registers */
50#define SUN6I_GBL_CTL_REG 0x04
51#define SUN6I_TFR_CTL_REG 0x08
52#define SUN6I_FIFO_CTL_REG 0x18
53#define SUN6I_FIFO_STA_REG 0x1c
54#define SUN6I_CLK_CTL_REG 0x24
55#define SUN6I_BURST_CNT_REG 0x30
56#define SUN6I_XMIT_CNT_REG 0x34
57#define SUN6I_BURST_CTL_REG 0x38
58#define SUN6I_TXDATA_REG 0x200
59#define SUN6I_RXDATA_REG 0x300
60
Jagan Teki3f53a582019-02-27 20:02:12 +053061/* sun spi bits */
62#define SUN4I_CTL_ENABLE BIT(0)
63#define SUN4I_CTL_MASTER BIT(1)
64#define SUN4I_CLK_CTL_CDR2_MASK 0xff
65#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
66#define SUN4I_CLK_CTL_CDR1_MASK 0xf
67#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
68#define SUN4I_CLK_CTL_DRS BIT(12)
69#define SUN4I_MAX_XFER_SIZE 0xffffff
70#define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
71#define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
72#define SUN4I_FIFO_STA_RF_CNT_BITS 0
73
Andre Przywara4d3521ce2022-04-26 23:58:53 +010074#ifdef CONFIG_MACH_SUNIV
75/* the AHB clock, which we programmed to be 1/3 of PLL_PERIPH@600MHz */
76#define SUNXI_INPUT_CLOCK 200000000 /* 200 MHz */
77#define SUN4I_SPI_MAX_RATE (SUNXI_INPUT_CLOCK / 2)
78#else
Andre Przywara27835682022-05-03 02:06:37 +010079/* the SPI mod clock, defaulting to be 1/1 of the HOSC@24MHz */
80#define SUNXI_INPUT_CLOCK 24000000 /* 24 MHz */
81#define SUN4I_SPI_MAX_RATE SUNXI_INPUT_CLOCK
Andre Przywara4d3521ce2022-04-26 23:58:53 +010082#endif
Jagan Teki3f53a582019-02-27 20:02:12 +053083#define SUN4I_SPI_MIN_RATE 3000
84#define SUN4I_SPI_DEFAULT_RATE 1000000
Icenowy Zhenga244be62022-06-28 14:49:24 +080085#define SUN4I_SPI_TIMEOUT_MS 1000
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020086
Jagan Teki3f53a582019-02-27 20:02:12 +053087#define SPI_REG(priv, reg) ((priv)->base + \
Jagan Tekic25058c2019-02-27 20:02:08 +053088 (priv)->variant->regs[reg])
89#define SPI_BIT(priv, bit) ((priv)->variant->bits[bit])
90#define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \
91 SPI_BIT(priv, SPI_TCR_CS_MASK))
92
93/* sun spi register set */
94enum sun4i_spi_regs {
95 SPI_GCR,
96 SPI_TCR,
97 SPI_FCR,
98 SPI_FSR,
99 SPI_CCR,
100 SPI_BC,
101 SPI_TC,
102 SPI_BCTL,
103 SPI_TXD,
104 SPI_RXD,
105};
106
107/* sun spi register bits */
108enum sun4i_spi_bits {
109 SPI_GCR_TP,
Jagan Tekif69b4252019-02-27 20:02:11 +0530110 SPI_GCR_SRST,
Jagan Tekic25058c2019-02-27 20:02:08 +0530111 SPI_TCR_CPHA,
112 SPI_TCR_CPOL,
113 SPI_TCR_CS_ACTIVE_LOW,
114 SPI_TCR_CS_SEL,
115 SPI_TCR_CS_MASK,
116 SPI_TCR_XCH,
117 SPI_TCR_CS_MANUAL,
118 SPI_TCR_CS_LEVEL,
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300119 SPI_TCR_SDC,
120 SPI_TCR_SDM,
Jagan Tekic25058c2019-02-27 20:02:08 +0530121 SPI_FCR_TF_RST,
122 SPI_FCR_RF_RST,
123 SPI_FSR_RF_CNT_MASK,
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200124};
125
Jagan Tekic25058c2019-02-27 20:02:08 +0530126struct sun4i_spi_variant {
127 const unsigned long *regs;
128 const u32 *bits;
Jagan Tekic12eb6a2019-02-27 20:02:09 +0530129 u32 fifo_depth;
Jagan Tekif69b4252019-02-27 20:02:11 +0530130 bool has_soft_reset;
131 bool has_burst_ctl;
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300132 bool has_clk_ctl;
Jagan Tekic25058c2019-02-27 20:02:08 +0530133};
134
Simon Glassb75b15b2020-12-03 16:55:23 -0700135struct sun4i_spi_plat {
Jagan Tekic25058c2019-02-27 20:02:08 +0530136 struct sun4i_spi_variant *variant;
Jagan Teki3f53a582019-02-27 20:02:12 +0530137 u32 base;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200138};
139
140struct sun4i_spi_priv {
Jagan Tekic25058c2019-02-27 20:02:08 +0530141 struct sun4i_spi_variant *variant;
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530142 struct clk clk_ahb, clk_mod;
Jagan Tekif69b4252019-02-27 20:02:11 +0530143 struct reset_ctl reset;
Jagan Teki3f53a582019-02-27 20:02:12 +0530144 u32 base;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200145 u32 freq;
146 u32 mode;
147
148 const u8 *tx_buf;
149 u8 *rx_buf;
150};
151
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200152static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len)
153{
154 u8 byte;
155
156 while (len--) {
Jagan Tekic25058c2019-02-27 20:02:08 +0530157 byte = readb(SPI_REG(priv, SPI_RXD));
Stefan Mavrodiev165db622018-12-05 14:27:57 +0200158 if (priv->rx_buf)
159 *priv->rx_buf++ = byte;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200160 }
161}
162
163static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len)
164{
165 u8 byte;
166
167 while (len--) {
168 byte = priv->tx_buf ? *priv->tx_buf++ : 0;
Jagan Tekic25058c2019-02-27 20:02:08 +0530169 writeb(byte, SPI_REG(priv, SPI_TXD));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200170 }
171}
172
173static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
174{
175 struct sun4i_spi_priv *priv = dev_get_priv(bus);
176 u32 reg;
177
Jagan Tekic25058c2019-02-27 20:02:08 +0530178 reg = readl(SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200179
Jagan Tekic25058c2019-02-27 20:02:08 +0530180 reg &= ~SPI_BIT(priv, SPI_TCR_CS_MASK);
181 reg |= SPI_CS(priv, cs);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200182
183 if (enable)
Jagan Tekic25058c2019-02-27 20:02:08 +0530184 reg &= ~SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200185 else
Jagan Tekic25058c2019-02-27 20:02:08 +0530186 reg |= SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200187
Jagan Tekic25058c2019-02-27 20:02:08 +0530188 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200189}
190
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530191static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable)
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200192{
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530193 struct sun4i_spi_priv *priv = dev_get_priv(dev);
194 int ret;
195
196 if (!enable) {
197 clk_disable(&priv->clk_ahb);
198 clk_disable(&priv->clk_mod);
Jagan Tekif69b4252019-02-27 20:02:11 +0530199 if (reset_valid(&priv->reset))
200 reset_assert(&priv->reset);
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530201 return 0;
202 }
203
204 ret = clk_enable(&priv->clk_ahb);
205 if (ret) {
206 dev_err(dev, "failed to enable ahb clock (ret=%d)\n", ret);
207 return ret;
208 }
209
210 ret = clk_enable(&priv->clk_mod);
211 if (ret) {
212 dev_err(dev, "failed to enable mod clock (ret=%d)\n", ret);
213 goto err_ahb;
214 }
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200215
Jagan Tekif69b4252019-02-27 20:02:11 +0530216 if (reset_valid(&priv->reset)) {
217 ret = reset_deassert(&priv->reset);
218 if (ret) {
219 dev_err(dev, "failed to deassert reset\n");
220 goto err_mod;
221 }
222 }
223
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530224 return 0;
225
Jagan Tekif69b4252019-02-27 20:02:11 +0530226err_mod:
227 clk_disable(&priv->clk_mod);
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530228err_ahb:
229 clk_disable(&priv->clk_ahb);
230 return ret;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200231}
232
Andre Przywara62a24e12022-05-03 00:07:16 +0100233static void sun4i_spi_set_speed_mode(struct udevice *dev)
234{
235 struct sun4i_spi_priv *priv = dev_get_priv(dev);
Michael Walle8ca7b0c2024-07-18 22:42:52 +0200236 unsigned int div, div_cdr2;
Andre Przywara62a24e12022-05-03 00:07:16 +0100237 u32 reg;
238
239 /*
Michael Wallecece6822024-07-12 19:14:56 +0200240 * The uclass should take care that this won't happen. But anyway,
241 * avoid a div-by-zero exception.
242 */
243 if (!priv->freq)
244 return;
245
246 /*
Andre Przywara62a24e12022-05-03 00:07:16 +0100247 * Setup clock divider.
248 *
249 * We have two choices there. Either we can use the clock
250 * divide rate 1, which is calculated thanks to this formula:
251 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
Michael Walle3a169172024-07-18 22:42:53 +0200252 * Or for sun6i/sun8i variants:
253 * SPI_CLK = MOD_CLK / (2 ^ cdr)
Andre Przywara62a24e12022-05-03 00:07:16 +0100254 * Or we can use CDR2, which is calculated with the formula:
255 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
256 * Whether we use the former or the latter is set through the
257 * DRS bit.
258 *
259 * First try CDR2, and if we can't reach the expected
260 * frequency, fall back to CDR1.
Michael Walle3a169172024-07-18 22:42:53 +0200261 * There is one exception if the requested clock is the input
262 * clock. In that case we always use CDR1 because we'll get a
263 * 1:1 ration for sun6i/sun8i variants.
Andre Przywara62a24e12022-05-03 00:07:16 +0100264 */
265
Andre Przywara27835682022-05-03 02:06:37 +0100266 div = DIV_ROUND_UP(SUNXI_INPUT_CLOCK, priv->freq);
Michael Walle8ca7b0c2024-07-18 22:42:52 +0200267 div_cdr2 = DIV_ROUND_UP(div, 2);
Andre Przywara62a24e12022-05-03 00:07:16 +0100268 reg = readl(SPI_REG(priv, SPI_CCR));
269
Michael Walle3a169172024-07-18 22:42:53 +0200270 if (div != 1 && (div_cdr2 <= (SUN4I_CLK_CTL_CDR2_MASK + 1))) {
Andre Przywara62a24e12022-05-03 00:07:16 +0100271 reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
Michael Walle8ca7b0c2024-07-18 22:42:52 +0200272 reg |= SUN4I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN4I_CLK_CTL_DRS;
Andre Przywara62a24e12022-05-03 00:07:16 +0100273 } else {
Andre Przywara27835682022-05-03 02:06:37 +0100274 div = fls(div - 1);
Andre Przywara4d3521ce2022-04-26 23:58:53 +0100275 /* The F1C100s encodes the divider as 2^(n+1) */
276 if (IS_ENABLED(CONFIG_MACH_SUNIV))
277 div--;
Andre Przywara62a24e12022-05-03 00:07:16 +0100278 reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
279 reg |= SUN4I_CLK_CTL_CDR1(div);
280 }
281
282 writel(reg, SPI_REG(priv, SPI_CCR));
283
284 reg = readl(SPI_REG(priv, SPI_TCR));
285 reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
286
287 if (priv->mode & SPI_CPOL)
288 reg |= SPI_BIT(priv, SPI_TCR_CPOL);
289
290 if (priv->mode & SPI_CPHA)
291 reg |= SPI_BIT(priv, SPI_TCR_CPHA);
292
293 writel(reg, SPI_REG(priv, SPI_TCR));
294}
295
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200296static int sun4i_spi_claim_bus(struct udevice *dev)
297{
298 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530299 int ret;
300
301 ret = sun4i_spi_set_clock(dev->parent, true);
302 if (ret)
303 return ret;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200304
Jagan Tekic25058c2019-02-27 20:02:08 +0530305 setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE |
306 SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP));
307
Jagan Tekif69b4252019-02-27 20:02:11 +0530308 if (priv->variant->has_soft_reset)
309 setbits_le32(SPI_REG(priv, SPI_GCR),
310 SPI_BIT(priv, SPI_GCR_SRST));
311
Jagan Tekic25058c2019-02-27 20:02:08 +0530312 setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
313 SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
Jagan Tekif9b70122019-02-27 20:02:07 +0530314
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300315 if (priv->variant->has_clk_ctl) {
316 sun4i_spi_set_speed_mode(dev->parent);
317 } else {
318 /*
319 * At this moment there is no ability to change input clock.
320 * Therefore, we can only use default HOSC@24MHz clock and
321 * set SPI sampling mode to normal
322 */
323 clrsetbits_le32(SPI_REG(priv, SPI_TCR),
324 SPI_BIT(priv, SPI_TCR_SDC) |
325 SPI_BIT(priv, SPI_TCR_SDM),
326 SPI_BIT(priv, SPI_TCR_SDM));
327 }
Andre Przywara62a24e12022-05-03 00:07:16 +0100328
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200329 return 0;
330}
331
332static int sun4i_spi_release_bus(struct udevice *dev)
333{
334 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200335
Jagan Tekic25058c2019-02-27 20:02:08 +0530336 clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200337
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530338 sun4i_spi_set_clock(dev->parent, false);
339
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200340 return 0;
341}
342
343static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
344 const void *dout, void *din, unsigned long flags)
345{
346 struct udevice *bus = dev->parent;
347 struct sun4i_spi_priv *priv = dev_get_priv(bus);
Simon Glassb75b15b2020-12-03 16:55:23 -0700348 struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200349
350 u32 len = bitlen / 8;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200351 u8 nbytes;
352 int ret;
353
354 priv->tx_buf = dout;
355 priv->rx_buf = din;
356
357 if (bitlen % 8) {
358 debug("%s: non byte-aligned SPI transfer.\n", __func__);
359 return -ENAVAIL;
360 }
361
362 if (flags & SPI_XFER_BEGIN)
Venkatesh Yadav Abbarapu91b9e372024-09-26 10:25:05 +0530363 sun4i_spi_set_cs(bus, slave_plat->cs[0], true);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200364
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200365 /* Reset FIFOs */
Jagan Tekic25058c2019-02-27 20:02:08 +0530366 setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
367 SPI_BIT(priv, SPI_FCR_TF_RST));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200368
369 while (len) {
370 /* Setup the transfer now... */
Jagan Tekic12eb6a2019-02-27 20:02:09 +0530371 nbytes = min(len, (priv->variant->fifo_depth - 1));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200372
373 /* Setup the counters */
Jagan Tekic25058c2019-02-27 20:02:08 +0530374 writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC));
375 writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200376
Jagan Tekif69b4252019-02-27 20:02:11 +0530377 if (priv->variant->has_burst_ctl)
378 writel(SUN4I_BURST_CNT(nbytes),
379 SPI_REG(priv, SPI_BCTL));
380
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200381 /* Fill the TX FIFO */
382 sun4i_spi_fill_fifo(priv, nbytes);
383
384 /* Start the transfer */
Jagan Tekic25058c2019-02-27 20:02:08 +0530385 setbits_le32(SPI_REG(priv, SPI_TCR),
386 SPI_BIT(priv, SPI_TCR_XCH));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200387
Icenowy Zhenga244be62022-06-28 14:49:24 +0800388 /* Wait for the transfer to be done */
389 ret = wait_for_bit_le32((const void *)SPI_REG(priv, SPI_TCR),
390 SPI_BIT(priv, SPI_TCR_XCH),
391 false, SUN4I_SPI_TIMEOUT_MS, false);
Jagan Teki66220da2019-02-27 20:02:05 +0530392 if (ret < 0) {
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200393 printf("ERROR: sun4i_spi: Timeout transferring data\n");
Venkatesh Yadav Abbarapu91b9e372024-09-26 10:25:05 +0530394 sun4i_spi_set_cs(bus, slave_plat->cs[0], false);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200395 return ret;
396 }
397
398 /* Drain the RX FIFO */
399 sun4i_spi_drain_fifo(priv, nbytes);
400
401 len -= nbytes;
402 }
403
404 if (flags & SPI_XFER_END)
Venkatesh Yadav Abbarapu91b9e372024-09-26 10:25:05 +0530405 sun4i_spi_set_cs(bus, slave_plat->cs[0], false);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200406
407 return 0;
408}
409
410static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
411{
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200412 struct sun4i_spi_priv *priv = dev_get_priv(dev);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200413
Michael Wallecece6822024-07-12 19:14:56 +0200414 if (speed > SUN4I_SPI_MAX_RATE)
415 speed = SUN4I_SPI_MAX_RATE;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200416
417 if (speed < SUN4I_SPI_MIN_RATE)
418 speed = SUN4I_SPI_MIN_RATE;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200419
420 priv->freq = speed;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200421
422 return 0;
423}
424
425static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
426{
427 struct sun4i_spi_priv *priv = dev_get_priv(dev);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200428
429 priv->mode = mode;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200430
431 return 0;
432}
433
434static const struct dm_spi_ops sun4i_spi_ops = {
435 .claim_bus = sun4i_spi_claim_bus,
436 .release_bus = sun4i_spi_release_bus,
437 .xfer = sun4i_spi_xfer,
438 .set_speed = sun4i_spi_set_speed,
439 .set_mode = sun4i_spi_set_mode,
440};
441
Jagan Teki3f53a582019-02-27 20:02:12 +0530442static int sun4i_spi_probe(struct udevice *bus)
443{
Simon Glassb75b15b2020-12-03 16:55:23 -0700444 struct sun4i_spi_plat *plat = dev_get_plat(bus);
Jagan Teki3f53a582019-02-27 20:02:12 +0530445 struct sun4i_spi_priv *priv = dev_get_priv(bus);
446 int ret;
447
448 ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb);
449 if (ret) {
Sean Anderson64474dd2020-09-15 10:45:11 -0400450 dev_err(bus, "failed to get ahb clock\n");
Jagan Teki3f53a582019-02-27 20:02:12 +0530451 return ret;
452 }
453
454 ret = clk_get_by_name(bus, "mod", &priv->clk_mod);
455 if (ret) {
Sean Anderson64474dd2020-09-15 10:45:11 -0400456 dev_err(bus, "failed to get mod clock\n");
Jagan Teki3f53a582019-02-27 20:02:12 +0530457 return ret;
458 }
459
460 ret = reset_get_by_index(bus, 0, &priv->reset);
461 if (ret && ret != -ENOENT) {
Sean Anderson64474dd2020-09-15 10:45:11 -0400462 dev_err(bus, "failed to get reset\n");
Jagan Teki3f53a582019-02-27 20:02:12 +0530463 return ret;
464 }
465
Jagan Teki3f53a582019-02-27 20:02:12 +0530466 priv->variant = plat->variant;
467 priv->base = plat->base;
Jagan Teki3f53a582019-02-27 20:02:12 +0530468
469 return 0;
470}
471
Simon Glassaad29ae2020-12-03 16:55:21 -0700472static int sun4i_spi_of_to_plat(struct udevice *bus)
Jagan Teki3f53a582019-02-27 20:02:12 +0530473{
Simon Glassb75b15b2020-12-03 16:55:23 -0700474 struct sun4i_spi_plat *plat = dev_get_plat(bus);
Jagan Teki3f53a582019-02-27 20:02:12 +0530475
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900476 plat->base = dev_read_addr(bus);
Jagan Teki3f53a582019-02-27 20:02:12 +0530477 plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus);
Jagan Teki3f53a582019-02-27 20:02:12 +0530478
479 return 0;
480}
481
Jagan Tekic25058c2019-02-27 20:02:08 +0530482static const unsigned long sun4i_spi_regs[] = {
483 [SPI_GCR] = SUN4I_CTL_REG,
484 [SPI_TCR] = SUN4I_CTL_REG,
485 [SPI_FCR] = SUN4I_CTL_REG,
486 [SPI_FSR] = SUN4I_FIFO_STA_REG,
487 [SPI_CCR] = SUN4I_CLK_CTL_REG,
488 [SPI_BC] = SUN4I_BURST_CNT_REG,
489 [SPI_TC] = SUN4I_XMIT_CNT_REG,
490 [SPI_TXD] = SUN4I_TXDATA_REG,
491 [SPI_RXD] = SUN4I_RXDATA_REG,
492};
493
494static const u32 sun4i_spi_bits[] = {
495 [SPI_GCR_TP] = BIT(18),
496 [SPI_TCR_CPHA] = BIT(2),
497 [SPI_TCR_CPOL] = BIT(3),
498 [SPI_TCR_CS_ACTIVE_LOW] = BIT(4),
499 [SPI_TCR_XCH] = BIT(10),
500 [SPI_TCR_CS_SEL] = 12,
501 [SPI_TCR_CS_MASK] = 0x3000,
502 [SPI_TCR_CS_MANUAL] = BIT(16),
503 [SPI_TCR_CS_LEVEL] = BIT(17),
504 [SPI_FCR_TF_RST] = BIT(8),
505 [SPI_FCR_RF_RST] = BIT(9),
506 [SPI_FSR_RF_CNT_MASK] = GENMASK(6, 0),
507};
508
Jagan Tekif69b4252019-02-27 20:02:11 +0530509static const unsigned long sun6i_spi_regs[] = {
510 [SPI_GCR] = SUN6I_GBL_CTL_REG,
511 [SPI_TCR] = SUN6I_TFR_CTL_REG,
512 [SPI_FCR] = SUN6I_FIFO_CTL_REG,
513 [SPI_FSR] = SUN6I_FIFO_STA_REG,
514 [SPI_CCR] = SUN6I_CLK_CTL_REG,
515 [SPI_BC] = SUN6I_BURST_CNT_REG,
516 [SPI_TC] = SUN6I_XMIT_CNT_REG,
517 [SPI_BCTL] = SUN6I_BURST_CTL_REG,
518 [SPI_TXD] = SUN6I_TXDATA_REG,
519 [SPI_RXD] = SUN6I_RXDATA_REG,
520};
521
522static const u32 sun6i_spi_bits[] = {
523 [SPI_GCR_TP] = BIT(7),
524 [SPI_GCR_SRST] = BIT(31),
525 [SPI_TCR_CPHA] = BIT(0),
526 [SPI_TCR_CPOL] = BIT(1),
527 [SPI_TCR_CS_ACTIVE_LOW] = BIT(2),
528 [SPI_TCR_CS_SEL] = 4,
529 [SPI_TCR_CS_MASK] = 0x30,
530 [SPI_TCR_CS_MANUAL] = BIT(6),
531 [SPI_TCR_CS_LEVEL] = BIT(7),
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300532 [SPI_TCR_SDC] = BIT(11),
533 [SPI_TCR_SDM] = BIT(13),
Jagan Tekif69b4252019-02-27 20:02:11 +0530534 [SPI_TCR_XCH] = BIT(31),
535 [SPI_FCR_RF_RST] = BIT(15),
536 [SPI_FCR_TF_RST] = BIT(31),
537 [SPI_FSR_RF_CNT_MASK] = GENMASK(7, 0),
538};
539
Jagan Tekic25058c2019-02-27 20:02:08 +0530540static const struct sun4i_spi_variant sun4i_a10_spi_variant = {
541 .regs = sun4i_spi_regs,
542 .bits = sun4i_spi_bits,
Jagan Tekic12eb6a2019-02-27 20:02:09 +0530543 .fifo_depth = 64,
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300544 .has_clk_ctl = true,
Jagan Tekif69b4252019-02-27 20:02:11 +0530545};
546
547static const struct sun4i_spi_variant sun6i_a31_spi_variant = {
548 .regs = sun6i_spi_regs,
549 .bits = sun6i_spi_bits,
550 .fifo_depth = 128,
551 .has_soft_reset = true,
552 .has_burst_ctl = true,
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300553 .has_clk_ctl = true,
Jagan Tekif69b4252019-02-27 20:02:11 +0530554};
555
556static const struct sun4i_spi_variant sun8i_h3_spi_variant = {
557 .regs = sun6i_spi_regs,
558 .bits = sun6i_spi_bits,
559 .fifo_depth = 64,
560 .has_soft_reset = true,
561 .has_burst_ctl = true,
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300562 .has_clk_ctl = true,
Jagan Tekic25058c2019-02-27 20:02:08 +0530563};
564
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300565static const struct sun4i_spi_variant sun50i_r329_spi_variant = {
566 .regs = sun6i_spi_regs,
567 .bits = sun6i_spi_bits,
568 .fifo_depth = 64,
569 .has_soft_reset = true,
570 .has_burst_ctl = true,
571};
572
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200573static const struct udevice_id sun4i_spi_ids[] = {
Jagan Tekic25058c2019-02-27 20:02:08 +0530574 {
575 .compatible = "allwinner,sun4i-a10-spi",
576 .data = (ulong)&sun4i_a10_spi_variant,
577 },
Jagan Tekif69b4252019-02-27 20:02:11 +0530578 {
579 .compatible = "allwinner,sun6i-a31-spi",
580 .data = (ulong)&sun6i_a31_spi_variant,
581 },
582 {
583 .compatible = "allwinner,sun8i-h3-spi",
584 .data = (ulong)&sun8i_h3_spi_variant,
585 },
Maksim Kiselev4d9267e2023-11-11 16:33:08 +0300586 {
587 .compatible = "allwinner,sun50i-r329-spi",
588 .data = (ulong)&sun50i_r329_spi_variant,
589 },
Jagan Teki3f53a582019-02-27 20:02:12 +0530590 { /* sentinel */ }
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200591};
592
593U_BOOT_DRIVER(sun4i_spi) = {
594 .name = "sun4i_spi",
595 .id = UCLASS_SPI,
596 .of_match = sun4i_spi_ids,
597 .ops = &sun4i_spi_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700598 .of_to_plat = sun4i_spi_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700599 .plat_auto = sizeof(struct sun4i_spi_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700600 .priv_auto = sizeof(struct sun4i_spi_priv),
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200601 .probe = sun4i_spi_probe,
602};