]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/spi/mt7621_spi.c
Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
[thirdparty/u-boot.git] / drivers / spi / mt7621_spi.c
CommitLineData
5eee9dee
SR
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Stefan Roese <sr@denx.de>
4 *
5 * Derived from the Linux driver version drivers/spi/spi-mt7621.c
6 * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
7 * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
8 * Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
9 */
10
d678a59d 11#include <common.h>
f0997856 12#include <clk.h>
5eee9dee 13#include <dm.h>
f7ae49fc 14#include <log.h>
5eee9dee
SR
15#include <spi.h>
16#include <wait_bit.h>
cd93d625 17#include <linux/bitops.h>
5eee9dee 18#include <linux/io.h>
1e94b46f 19#include <linux/printk.h>
5eee9dee 20
54a6b8e7
WG
21#define MT7621_RX_FIFO_LEN 32
22#define MT7621_TX_FIFO_LEN 36
5eee9dee
SR
23
24#define MT7621_SPI_TRANS 0x00
25#define MT7621_SPI_TRANS_START BIT(8)
26#define MT7621_SPI_TRANS_BUSY BIT(16)
43405e00
WG
27#define TRANS_ADDR_SZ GENMASK(20, 19)
28#define TRANS_ADDR_SZ_SHIFT 19
29#define TRANS_MOSI_BCNT GENMASK(3, 0)
30#define TRANS_MOSI_BCNT_SHIFT 0
5eee9dee
SR
31
32#define MT7621_SPI_OPCODE 0x04
33#define MT7621_SPI_DATA0 0x08
34#define MT7621_SPI_DATA4 0x18
35#define MT7621_SPI_MASTER 0x28
36#define MT7621_SPI_MOREBUF 0x2c
37#define MT7621_SPI_POLAR 0x38
38
39#define MT7621_LSB_FIRST BIT(3)
40#define MT7621_CPOL BIT(4)
41#define MT7621_CPHA BIT(5)
42
43#define MASTER_MORE_BUFMODE BIT(2)
44#define MASTER_RS_CLK_SEL GENMASK(27, 16)
45#define MASTER_RS_CLK_SEL_SHIFT 16
46#define MASTER_RS_SLAVE_SEL GENMASK(31, 29)
47
54a6b8e7
WG
48#define MOREBUF_CMD_CNT GENMASK(29, 24)
49#define MOREBUF_CMD_CNT_SHIFT 24
50#define MOREBUF_MISO_CNT GENMASK(20, 12)
51#define MOREBUF_MISO_CNT_SHIFT 12
52#define MOREBUF_MOSI_CNT GENMASK(8, 0)
53#define MOREBUF_MOSI_CNT_SHIFT 0
54
5eee9dee
SR
55struct mt7621_spi {
56 void __iomem *base;
57 unsigned int sys_freq;
5eee9dee
SR
58};
59
5eee9dee
SR
60static void mt7621_spi_set_cs(struct mt7621_spi *rs, int cs, int enable)
61{
5eee9dee 62 debug("%s: cs#%d -> %s\n", __func__, cs, enable ? "enable" : "disable");
43405e00
WG
63
64 if (enable) {
65 setbits_le32(rs->base + MT7621_SPI_MASTER,
66 MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE);
67 iowrite32(BIT(cs), rs->base + MT7621_SPI_POLAR);
68 } else {
69 iowrite32(0, rs->base + MT7621_SPI_POLAR);
70 iowrite32((2 << TRANS_ADDR_SZ_SHIFT) |
71 (1 << TRANS_MOSI_BCNT_SHIFT),
72 rs->base + MT7621_SPI_TRANS);
73 clrbits_le32(rs->base + MT7621_SPI_MASTER,
74 MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE);
75 }
5eee9dee
SR
76}
77
78static int mt7621_spi_set_mode(struct udevice *bus, uint mode)
79{
80 struct mt7621_spi *rs = dev_get_priv(bus);
81 u32 reg;
82
83 debug("%s: mode=0x%08x\n", __func__, mode);
84 reg = ioread32(rs->base + MT7621_SPI_MASTER);
85
86 reg &= ~MT7621_LSB_FIRST;
87 if (mode & SPI_LSB_FIRST)
88 reg |= MT7621_LSB_FIRST;
89
90 reg &= ~(MT7621_CPHA | MT7621_CPOL);
91 switch (mode & (SPI_CPOL | SPI_CPHA)) {
92 case SPI_MODE_0:
93 break;
94 case SPI_MODE_1:
95 reg |= MT7621_CPHA;
96 break;
97 case SPI_MODE_2:
98 reg |= MT7621_CPOL;
99 break;
100 case SPI_MODE_3:
101 reg |= MT7621_CPOL | MT7621_CPHA;
102 break;
103 }
104 iowrite32(reg, rs->base + MT7621_SPI_MASTER);
105
106 return 0;
107}
108
109static int mt7621_spi_set_speed(struct udevice *bus, uint speed)
110{
111 struct mt7621_spi *rs = dev_get_priv(bus);
112 u32 rate;
113 u32 reg;
114
115 debug("%s: speed=%d\n", __func__, speed);
116 rate = DIV_ROUND_UP(rs->sys_freq, speed);
117 debug("rate:%u\n", rate);
118
119 if (rate > 4097)
120 return -EINVAL;
121
122 if (rate < 2)
123 rate = 2;
124
125 reg = ioread32(rs->base + MT7621_SPI_MASTER);
126 reg &= ~MASTER_RS_CLK_SEL;
127 reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT;
128 iowrite32(reg, rs->base + MT7621_SPI_MASTER);
129
130 return 0;
131}
132
133static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
134{
135 int ret;
136
137 ret = wait_for_bit_le32(rs->base + MT7621_SPI_TRANS,
138 MT7621_SPI_TRANS_BUSY, 0, 10, 0);
139 if (ret)
140 pr_err("Timeout in %s!\n", __func__);
141
142 return ret;
143}
144
54a6b8e7
WG
145static int mt7621_spi_read(struct mt7621_spi *rs, u8 *buf, size_t len)
146{
147 size_t rx_len;
148 int i, ret;
149 u32 val = 0;
150
151 while (len) {
152 rx_len = min_t(size_t, len, MT7621_RX_FIFO_LEN);
153
154 iowrite32((rx_len * 8) << MOREBUF_MISO_CNT_SHIFT,
155 rs->base + MT7621_SPI_MOREBUF);
156 iowrite32(MT7621_SPI_TRANS_START, rs->base + MT7621_SPI_TRANS);
157
158 ret = mt7621_spi_wait_till_ready(rs);
159 if (ret)
160 return ret;
161
162 for (i = 0; i < rx_len; i++) {
163 if ((i % 4) == 0)
164 val = ioread32(rs->base + MT7621_SPI_DATA0 + i);
165 *buf++ = val & 0xff;
166 val >>= 8;
167 }
168
169 len -= rx_len;
170 }
171
172 return ret;
173}
174
175static int mt7621_spi_write(struct mt7621_spi *rs, const u8 *buf, size_t len)
176{
177 size_t tx_len, opcode_len, dido_len;
178 int i, ret;
179 u32 val;
180
181 while (len) {
182 tx_len = min_t(size_t, len, MT7621_TX_FIFO_LEN);
183
184 opcode_len = min_t(size_t, tx_len, 4);
185 dido_len = tx_len - opcode_len;
186
187 val = 0;
188 for (i = 0; i < opcode_len; i++) {
189 val <<= 8;
190 val |= *buf++;
191 }
192
193 iowrite32(val, rs->base + MT7621_SPI_OPCODE);
194
195 val = 0;
196 for (i = 0; i < dido_len; i++) {
197 val |= (*buf++) << ((i % 4) * 8);
198
199 if ((i % 4 == 3) || (i == dido_len - 1)) {
200 iowrite32(val, rs->base + MT7621_SPI_DATA0 +
201 (i & ~3));
202 val = 0;
203 }
204 }
205
206 iowrite32(((opcode_len * 8) << MOREBUF_CMD_CNT_SHIFT) |
207 ((dido_len * 8) << MOREBUF_MOSI_CNT_SHIFT),
208 rs->base + MT7621_SPI_MOREBUF);
209 iowrite32(MT7621_SPI_TRANS_START, rs->base + MT7621_SPI_TRANS);
210
211 ret = mt7621_spi_wait_till_ready(rs);
212 if (ret)
213 return ret;
214
215 len -= tx_len;
216 }
217
218 return 0;
219}
220
5eee9dee
SR
221static int mt7621_spi_xfer(struct udevice *dev, unsigned int bitlen,
222 const void *dout, void *din, unsigned long flags)
223{
224 struct udevice *bus = dev->parent;
225 struct mt7621_spi *rs = dev_get_priv(bus);
5eee9dee 226 int total_size = bitlen >> 3;
54a6b8e7 227 int ret = 0;
5eee9dee
SR
228
229 debug("%s: dout=%p, din=%p, len=%x, flags=%lx\n", __func__, dout, din,
230 total_size, flags);
231
232 /*
233 * This driver only supports half-duplex, so complain and bail out
234 * upon full-duplex messages
235 */
236 if (dout && din) {
237 printf("Only half-duplex SPI transfer supported\n");
238 return -EIO;
239 }
240
5eee9dee
SR
241 mt7621_spi_wait_till_ready(rs);
242
243 /*
244 * Set CS active upon start of SPI message. This message can
245 * be split upon multiple calls to this xfer function
246 */
247 if (flags & SPI_XFER_BEGIN)
248 mt7621_spi_set_cs(rs, spi_chip_select(dev), 1);
249
54a6b8e7
WG
250 if (din)
251 ret = mt7621_spi_read(rs, din, total_size);
252 else if (dout)
253 ret = mt7621_spi_write(rs, dout, total_size);
5eee9dee 254
5eee9dee
SR
255 if (flags & SPI_XFER_END)
256 mt7621_spi_set_cs(rs, spi_chip_select(dev), 0);
257
54a6b8e7 258 return ret;
5eee9dee
SR
259}
260
261static int mt7621_spi_probe(struct udevice *dev)
262{
263 struct mt7621_spi *rs = dev_get_priv(dev);
f0997856
WG
264 struct clk clk;
265 int ret;
5eee9dee
SR
266
267 rs->base = dev_remap_addr(dev);
268 if (!rs->base)
269 return -EINVAL;
270
f0997856
WG
271 ret = clk_get_by_index(dev, 0, &clk);
272 if (ret < 0) {
273 printf("Please provide a clock!\n");
274 return ret;
275 }
276
277 clk_enable(&clk);
278
279 rs->sys_freq = clk_get_rate(&clk);
5eee9dee 280 if (!rs->sys_freq) {
f0997856 281 printf("Please provide a valid clock!\n");
5eee9dee
SR
282 return -EINVAL;
283 }
284
5eee9dee
SR
285 return 0;
286}
287
288static const struct dm_spi_ops mt7621_spi_ops = {
289 .set_mode = mt7621_spi_set_mode,
290 .set_speed = mt7621_spi_set_speed,
291 .xfer = mt7621_spi_xfer,
292 /*
293 * cs_info is not needed, since we require all chip selects to be
294 * in the device tree explicitly
295 */
296};
297
298static const struct udevice_id mt7621_spi_ids[] = {
299 { .compatible = "ralink,mt7621-spi" },
300 { }
301};
302
303U_BOOT_DRIVER(mt7621_spi) = {
304 .name = "mt7621_spi",
305 .id = UCLASS_SPI,
306 .of_match = mt7621_spi_ids,
307 .ops = &mt7621_spi_ops,
41575d8e 308 .priv_auto = sizeof(struct mt7621_spi),
5eee9dee
SR
309 .probe = mt7621_spi_probe,
310};