blob: 4865fd91f8c008231d16af686547dcbc73b67262 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +02002/*
3 * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de>
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +02004 */
5
6#include <common.h>
Peng Fanea0bce62017-08-09 13:09:33 +08007#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Haavard Skinnemoend74084a2008-05-16 11:10:31 +02009#include <malloc.h>
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +020010#include <spi.h>
Simon Glass9bc15642020-02-03 07:36:16 -070011#include <dm/device_compat.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090012#include <linux/errno.h>
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +020013#include <asm/io.h>
Stefano Babic7faee912011-08-21 10:45:44 +020014#include <asm/gpio.h>
Stefano Babic78129d92011-03-14 15:43:56 +010015#include <asm/arch/imx-regs.h>
16#include <asm/arch/clock.h>
Stefano Babic33731bc2017-06-29 10:16:06 +020017#include <asm/mach-imx/spi.h>
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +020018
Peng Fanea0bce62017-08-09 13:09:33 +080019DECLARE_GLOBAL_DATA_PTR;
20
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +020021#ifdef CONFIG_MX27
22/* i.MX27 has a completely wrong register layout and register definitions in the
23 * datasheet, the correct one is in the Freescale's Linux driver */
24
Helmut Raiger785efc92011-06-15 01:45:45 +000025#error "i.MX27 CSPI not supported due to drastic differences in register definitions" \
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +020026"See linux mxc_spi driver from Freescale for details."
Eric Nelsonfe1e7612012-01-31 07:52:03 +000027#endif
Stefano Babicdcd73cd2011-01-19 22:46:30 +000028
Nikita Kiryanov00cd7382014-08-20 15:08:50 +030029__weak int board_spi_cs_gpio(unsigned bus, unsigned cs)
30{
31 return -1;
32}
33
Stefano Babicd77fe992010-07-06 17:05:06 +020034#define OUT MXC_GPIO_DIRECTION_OUT
35
Stefano Babic28580452011-01-19 22:46:33 +000036#define reg_read readl
37#define reg_write(a, v) writel(v, a)
38
Heiko Schocherb77c8882014-07-14 10:22:11 +020039#if !defined(CONFIG_SYS_SPI_MXC_WAIT)
40#define CONFIG_SYS_SPI_MXC_WAIT (CONFIG_SYS_HZ/100) /* 10 ms */
41#endif
42
Heiko Schocher053c2442019-05-26 12:15:47 +020043#define MAX_CS_COUNT 4
44
Haavard Skinnemoend74084a2008-05-16 11:10:31 +020045struct mxc_spi_slave {
46 struct spi_slave slave;
47 unsigned long base;
48 u32 ctrl_reg;
Eric Nelsonfe1e7612012-01-31 07:52:03 +000049#if defined(MXC_ECSPI)
Stefano Babic6e6f4552010-04-04 22:43:38 +020050 u32 cfg_reg;
51#endif
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +010052 int gpio;
Stefano Babicd77fe992010-07-06 17:05:06 +020053 int ss_pol;
Markus Niebel8f769cf2014-10-23 16:09:39 +020054 unsigned int max_hz;
55 unsigned int mode;
Peng Fanea0bce62017-08-09 13:09:33 +080056 struct gpio_desc ss;
Heiko Schocher053c2442019-05-26 12:15:47 +020057 struct gpio_desc cs_gpios[MAX_CS_COUNT];
58 struct udevice *dev;
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +020059};
Haavard Skinnemoend74084a2008-05-16 11:10:31 +020060
61static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave)
62{
63 return container_of(slave, struct mxc_spi_slave, slave);
64}
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +020065
Peng Fanea0bce62017-08-09 13:09:33 +080066static void mxc_spi_cs_activate(struct mxc_spi_slave *mxcs)
Stefano Babic6e6f4552010-04-04 22:43:38 +020067{
Heiko Schocher053c2442019-05-26 12:15:47 +020068#if defined(CONFIG_DM_SPI)
69 struct udevice *dev = mxcs->dev;
70 struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
71
72 u32 cs = slave_plat->cs;
73
74 if (!dm_gpio_is_valid(&mxcs->cs_gpios[cs]))
75 return;
76
77 dm_gpio_set_value(&mxcs->cs_gpios[cs], 1);
78#else
79 if (mxcs->gpio > 0)
80 gpio_set_value(mxcs->gpio, mxcs->ss_pol);
81#endif
Stefano Babic6e6f4552010-04-04 22:43:38 +020082}
83
Peng Fanea0bce62017-08-09 13:09:33 +080084static void mxc_spi_cs_deactivate(struct mxc_spi_slave *mxcs)
Stefano Babic6e6f4552010-04-04 22:43:38 +020085{
Heiko Schocher053c2442019-05-26 12:15:47 +020086#if defined(CONFIG_DM_SPI)
87 struct udevice *dev = mxcs->dev;
88 struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
89
90 u32 cs = slave_plat->cs;
91
92 if (!dm_gpio_is_valid(&mxcs->cs_gpios[cs]))
93 return;
94
95 dm_gpio_set_value(&mxcs->cs_gpios[cs], 0);
96#else
97 if (mxcs->gpio > 0)
98 gpio_set_value(mxcs->gpio, !(mxcs->ss_pol));
99#endif
Stefano Babic6e6f4552010-04-04 22:43:38 +0200100}
101
Anatolij Gustschin0aa35fd2011-01-19 22:46:32 +0000102u32 get_cspi_div(u32 div)
103{
104 int i;
105
106 for (i = 0; i < 8; i++) {
107 if (div <= (4 << i))
108 return i;
109 }
110 return i;
111}
112
Eric Nelsonfe1e7612012-01-31 07:52:03 +0000113#ifdef MXC_CSPI
Markus Niebel8f769cf2014-10-23 16:09:39 +0200114static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs)
Stefano Babicdcd73cd2011-01-19 22:46:30 +0000115{
116 unsigned int ctrl_reg;
Anatolij Gustschin0aa35fd2011-01-19 22:46:32 +0000117 u32 clk_src;
118 u32 div;
Markus Niebel8f769cf2014-10-23 16:09:39 +0200119 unsigned int max_hz = mxcs->max_hz;
120 unsigned int mode = mxcs->mode;
Anatolij Gustschin0aa35fd2011-01-19 22:46:32 +0000121
122 clk_src = mxc_get_clock(MXC_CSPI_CLK);
123
Benoît Thébaudeau884622b2012-08-10 08:51:50 +0000124 div = DIV_ROUND_UP(clk_src, max_hz);
Anatolij Gustschin0aa35fd2011-01-19 22:46:32 +0000125 div = get_cspi_div(div);
126
127 debug("clk %d Hz, div %d, real clk %d Hz\n",
128 max_hz, div, clk_src / (4 << div));
Stefano Babicdcd73cd2011-01-19 22:46:30 +0000129
130 ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) |
131 MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS) |
Anatolij Gustschin0aa35fd2011-01-19 22:46:32 +0000132 MXC_CSPICTRL_DATARATE(div) |
Stefano Babicdcd73cd2011-01-19 22:46:30 +0000133 MXC_CSPICTRL_EN |
134#ifdef CONFIG_MX35
135 MXC_CSPICTRL_SSCTL |
136#endif
137 MXC_CSPICTRL_MODE;
138
139 if (mode & SPI_CPHA)
140 ctrl_reg |= MXC_CSPICTRL_PHA;
141 if (mode & SPI_CPOL)
142 ctrl_reg |= MXC_CSPICTRL_POL;
143 if (mode & SPI_CS_HIGH)
144 ctrl_reg |= MXC_CSPICTRL_SSPOL;
145 mxcs->ctrl_reg = ctrl_reg;
146
147 return 0;
148}
149#endif
150
Eric Nelsonfe1e7612012-01-31 07:52:03 +0000151#ifdef MXC_ECSPI
Markus Niebel8f769cf2014-10-23 16:09:39 +0200152static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs)
Stefano Babic6e6f4552010-04-04 22:43:38 +0200153{
154 u32 clk_src = mxc_get_clock(MXC_CSPI_CLK);
Dirk Behmeb177b712013-05-11 07:25:54 +0200155 s32 reg_ctrl, reg_config;
Markus Niebel6683e622014-02-17 17:33:17 +0100156 u32 ss_pol = 0, sclkpol = 0, sclkpha = 0, sclkctl = 0;
157 u32 pre_div = 0, post_div = 0;
Stefano Babic28580452011-01-19 22:46:33 +0000158 struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
Markus Niebel8f769cf2014-10-23 16:09:39 +0200159 unsigned int max_hz = mxcs->max_hz;
160 unsigned int mode = mxcs->mode;
Stefano Babic6e6f4552010-04-04 22:43:38 +0200161
Fabio Estevam833fb552013-04-09 13:06:25 +0000162 /*
163 * Reset SPI and set all CSs to master mode, if toggling
164 * between slave and master mode we might see a glitch
165 * on the clock line
166 */
167 reg_ctrl = MXC_CSPICTRL_MODE_MASK;
168 reg_write(&regs->ctrl, reg_ctrl);
169 reg_ctrl |= MXC_CSPICTRL_EN;
170 reg_write(&regs->ctrl, reg_ctrl);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200171
Stefano Babic6e6f4552010-04-04 22:43:38 +0200172 if (clk_src > max_hz) {
Dirk Behmeb177b712013-05-11 07:25:54 +0200173 pre_div = (clk_src - 1) / max_hz;
174 /* fls(1) = 1, fls(0x80000000) = 32, fls(16) = 5 */
175 post_div = fls(pre_div);
176 if (post_div > 4) {
177 post_div -= 4;
178 if (post_div >= 16) {
Stefano Babic6e6f4552010-04-04 22:43:38 +0200179 printf("Error: no divider for the freq: %d\n",
180 max_hz);
181 return -1;
182 }
Dirk Behmeb177b712013-05-11 07:25:54 +0200183 pre_div >>= post_div;
184 } else {
185 post_div = 0;
Stefano Babic6e6f4552010-04-04 22:43:38 +0200186 }
187 }
188
189 debug("pre_div = %d, post_div=%d\n", pre_div, post_div);
190 reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_SELCHAN(3)) |
191 MXC_CSPICTRL_SELCHAN(cs);
192 reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_PREDIV(0x0F)) |
193 MXC_CSPICTRL_PREDIV(pre_div);
194 reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_POSTDIV(0x0F)) |
195 MXC_CSPICTRL_POSTDIV(post_div);
196
Stefano Babic6e6f4552010-04-04 22:43:38 +0200197 if (mode & SPI_CS_HIGH)
198 ss_pol = 1;
199
Markus Niebel6683e622014-02-17 17:33:17 +0100200 if (mode & SPI_CPOL) {
Stefano Babic6e6f4552010-04-04 22:43:38 +0200201 sclkpol = 1;
Markus Niebel6683e622014-02-17 17:33:17 +0100202 sclkctl = 1;
203 }
Stefano Babic6e6f4552010-04-04 22:43:38 +0200204
205 if (mode & SPI_CPHA)
206 sclkpha = 1;
207
Stefano Babic28580452011-01-19 22:46:33 +0000208 reg_config = reg_read(&regs->cfg);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200209
210 /*
211 * Configuration register setup
Stefano Babicdcd73cd2011-01-19 22:46:30 +0000212 * The MX51 supports different setup for each SS
Stefano Babic6e6f4552010-04-04 22:43:38 +0200213 */
214 reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_SSPOL))) |
215 (ss_pol << (cs + MXC_CSPICON_SSPOL));
216 reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_POL))) |
217 (sclkpol << (cs + MXC_CSPICON_POL));
Markus Niebel6683e622014-02-17 17:33:17 +0100218 reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_CTL))) |
219 (sclkctl << (cs + MXC_CSPICON_CTL));
Stefano Babic6e6f4552010-04-04 22:43:38 +0200220 reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_PHA))) |
221 (sclkpha << (cs + MXC_CSPICON_PHA));
222
223 debug("reg_ctrl = 0x%x\n", reg_ctrl);
Stefano Babic28580452011-01-19 22:46:33 +0000224 reg_write(&regs->ctrl, reg_ctrl);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200225 debug("reg_config = 0x%x\n", reg_config);
Stefano Babic28580452011-01-19 22:46:33 +0000226 reg_write(&regs->cfg, reg_config);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200227
228 /* save config register and control register */
229 mxcs->ctrl_reg = reg_ctrl;
230 mxcs->cfg_reg = reg_config;
231
232 /* clear interrupt reg */
Stefano Babic28580452011-01-19 22:46:33 +0000233 reg_write(&regs->intr, 0);
234 reg_write(&regs->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200235
236 return 0;
237}
238#endif
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200239
Peng Fanea0bce62017-08-09 13:09:33 +0800240int spi_xchg_single(struct mxc_spi_slave *mxcs, unsigned int bitlen,
Stefano Babic125f82a2010-08-20 12:05:03 +0200241 const u8 *dout, u8 *din, unsigned long flags)
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200242{
Axel Linfb7def92013-06-14 21:13:32 +0800243 int nbytes = DIV_ROUND_UP(bitlen, 8);
Stefano Babic125f82a2010-08-20 12:05:03 +0200244 u32 data, cnt, i;
Stefano Babic28580452011-01-19 22:46:33 +0000245 struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
Heiko Schocherb77c8882014-07-14 10:22:11 +0200246 u32 ts;
247 int status;
Stefano Babic6e6f4552010-04-04 22:43:38 +0200248
Ye Li07955fb2019-01-04 09:26:00 +0000249 debug("%s: bitlen %d dout 0x%lx din 0x%lx\n",
250 __func__, bitlen, (ulong)dout, (ulong)din);
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200251
Stefano Babic6e6f4552010-04-04 22:43:38 +0200252 mxcs->ctrl_reg = (mxcs->ctrl_reg &
253 ~MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS)) |
Guennadi Liakhovetskid3380132009-02-07 00:09:12 +0100254 MXC_CSPICTRL_BITCOUNT(bitlen - 1);
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200255
Stefano Babic28580452011-01-19 22:46:33 +0000256 reg_write(&regs->ctrl, mxcs->ctrl_reg | MXC_CSPICTRL_EN);
Eric Nelsonfe1e7612012-01-31 07:52:03 +0000257#ifdef MXC_ECSPI
Stefano Babic28580452011-01-19 22:46:33 +0000258 reg_write(&regs->cfg, mxcs->cfg_reg);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200259#endif
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200260
Stefano Babic6e6f4552010-04-04 22:43:38 +0200261 /* Clear interrupt register */
Stefano Babic28580452011-01-19 22:46:33 +0000262 reg_write(&regs->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100263
Stefano Babic125f82a2010-08-20 12:05:03 +0200264 /*
265 * The SPI controller works only with words,
266 * check if less than a word is sent.
267 * Access to the FIFO is only 32 bit
268 */
269 if (bitlen % 32) {
270 data = 0;
271 cnt = (bitlen % 32) / 8;
272 if (dout) {
273 for (i = 0; i < cnt; i++) {
274 data = (data << 8) | (*dout++ & 0xFF);
275 }
276 }
277 debug("Sending SPI 0x%x\n", data);
278
Stefano Babic28580452011-01-19 22:46:33 +0000279 reg_write(&regs->txdata, data);
Stefano Babic125f82a2010-08-20 12:05:03 +0200280 nbytes -= cnt;
281 }
282
283 data = 0;
284
285 while (nbytes > 0) {
286 data = 0;
287 if (dout) {
288 /* Buffer is not 32-bit aligned */
289 if ((unsigned long)dout & 0x03) {
290 data = 0;
Anatolij Gustschin089ebe02011-01-20 07:53:06 +0000291 for (i = 0; i < 4; i++)
Stefano Babic125f82a2010-08-20 12:05:03 +0200292 data = (data << 8) | (*dout++ & 0xFF);
Stefano Babic125f82a2010-08-20 12:05:03 +0200293 } else {
294 data = *(u32 *)dout;
295 data = cpu_to_be32(data);
Timo Herbrecher64203202013-10-16 00:05:09 +0530296 dout += 4;
Stefano Babic125f82a2010-08-20 12:05:03 +0200297 }
Stefano Babic125f82a2010-08-20 12:05:03 +0200298 }
299 debug("Sending SPI 0x%x\n", data);
Stefano Babic28580452011-01-19 22:46:33 +0000300 reg_write(&regs->txdata, data);
Stefano Babic125f82a2010-08-20 12:05:03 +0200301 nbytes -= 4;
302 }
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200303
Stefano Babic6e6f4552010-04-04 22:43:38 +0200304 /* FIFO is written, now starts the transfer setting the XCH bit */
Stefano Babic28580452011-01-19 22:46:33 +0000305 reg_write(&regs->ctrl, mxcs->ctrl_reg |
Stefano Babic6e6f4552010-04-04 22:43:38 +0200306 MXC_CSPICTRL_EN | MXC_CSPICTRL_XCH);
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200307
Heiko Schocherb77c8882014-07-14 10:22:11 +0200308 ts = get_timer(0);
309 status = reg_read(&regs->stat);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200310 /* Wait until the TC (Transfer completed) bit is set */
Heiko Schocherb77c8882014-07-14 10:22:11 +0200311 while ((status & MXC_CSPICTRL_TC) == 0) {
312 if (get_timer(ts) > CONFIG_SYS_SPI_MXC_WAIT) {
313 printf("spi_xchg_single: Timeout!\n");
314 return -1;
315 }
316 status = reg_read(&regs->stat);
317 }
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200318
Stefano Babic6e6f4552010-04-04 22:43:38 +0200319 /* Transfer completed, clear any pending request */
Stefano Babic28580452011-01-19 22:46:33 +0000320 reg_write(&regs->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200321
Axel Linfb7def92013-06-14 21:13:32 +0800322 nbytes = DIV_ROUND_UP(bitlen, 8);
Stefano Babic6e6f4552010-04-04 22:43:38 +0200323
Stefano Babic125f82a2010-08-20 12:05:03 +0200324 cnt = nbytes % 32;
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100325
Stefano Babic125f82a2010-08-20 12:05:03 +0200326 if (bitlen % 32) {
Stefano Babic28580452011-01-19 22:46:33 +0000327 data = reg_read(&regs->rxdata);
Stefano Babic125f82a2010-08-20 12:05:03 +0200328 cnt = (bitlen % 32) / 8;
Anatolij Gustschin089ebe02011-01-20 07:53:06 +0000329 data = cpu_to_be32(data) >> ((sizeof(data) - cnt) * 8);
Stefano Babic125f82a2010-08-20 12:05:03 +0200330 debug("SPI Rx unaligned: 0x%x\n", data);
331 if (din) {
Anatolij Gustschin089ebe02011-01-20 07:53:06 +0000332 memcpy(din, &data, cnt);
333 din += cnt;
Stefano Babic125f82a2010-08-20 12:05:03 +0200334 }
335 nbytes -= cnt;
336 }
337
338 while (nbytes > 0) {
339 u32 tmp;
Stefano Babic28580452011-01-19 22:46:33 +0000340 tmp = reg_read(&regs->rxdata);
Stefano Babic125f82a2010-08-20 12:05:03 +0200341 data = cpu_to_be32(tmp);
342 debug("SPI Rx: 0x%x 0x%x\n", tmp, data);
Masahiro Yamadadb204642014-11-07 03:03:31 +0900343 cnt = min_t(u32, nbytes, sizeof(data));
Stefano Babic125f82a2010-08-20 12:05:03 +0200344 if (din) {
345 memcpy(din, &data, cnt);
346 din += cnt;
347 }
348 nbytes -= cnt;
349 }
350
351 return 0;
Stefano Babic6e6f4552010-04-04 22:43:38 +0200352
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200353}
354
Peng Fanea0bce62017-08-09 13:09:33 +0800355static int mxc_spi_xfer_internal(struct mxc_spi_slave *mxcs,
356 unsigned int bitlen, const void *dout,
357 void *din, unsigned long flags)
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200358{
Axel Linfb7def92013-06-14 21:13:32 +0800359 int n_bytes = DIV_ROUND_UP(bitlen, 8);
Stefano Babic125f82a2010-08-20 12:05:03 +0200360 int n_bits;
361 int ret;
362 u32 blk_size;
363 u8 *p_outbuf = (u8 *)dout;
364 u8 *p_inbuf = (u8 *)din;
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200365
Peng Fanea0bce62017-08-09 13:09:33 +0800366 if (!mxcs)
367 return -EINVAL;
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200368
Stefano Babic125f82a2010-08-20 12:05:03 +0200369 if (flags & SPI_XFER_BEGIN)
Peng Fanea0bce62017-08-09 13:09:33 +0800370 mxc_spi_cs_activate(mxcs);
Magnus Lilja1858a9a2010-02-09 22:05:39 +0100371
Stefano Babic125f82a2010-08-20 12:05:03 +0200372 while (n_bytes > 0) {
Stefano Babic125f82a2010-08-20 12:05:03 +0200373 if (n_bytes < MAX_SPI_BYTES)
374 blk_size = n_bytes;
375 else
376 blk_size = MAX_SPI_BYTES;
377
378 n_bits = blk_size * 8;
379
Peng Fanea0bce62017-08-09 13:09:33 +0800380 ret = spi_xchg_single(mxcs, n_bits, p_outbuf, p_inbuf, 0);
Stefano Babic125f82a2010-08-20 12:05:03 +0200381
382 if (ret)
383 return ret;
384 if (dout)
385 p_outbuf += blk_size;
386 if (din)
387 p_inbuf += blk_size;
388 n_bytes -= blk_size;
Guennadi Liakhovetskid3380132009-02-07 00:09:12 +0100389 }
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200390
Stefano Babic125f82a2010-08-20 12:05:03 +0200391 if (flags & SPI_XFER_END) {
Peng Fanea0bce62017-08-09 13:09:33 +0800392 mxc_spi_cs_deactivate(mxcs);
Stefano Babic125f82a2010-08-20 12:05:03 +0200393 }
394
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200395 return 0;
396}
397
Peng Fanea0bce62017-08-09 13:09:33 +0800398static int mxc_spi_claim_bus_internal(struct mxc_spi_slave *mxcs, int cs)
399{
400 struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
401 int ret;
402
403 reg_write(&regs->rxdata, 1);
404 udelay(1);
405 ret = spi_cfg_mxc(mxcs, cs);
406 if (ret) {
407 printf("mxc_spi: cannot setup SPI controller\n");
408 return ret;
409 }
410 reg_write(&regs->period, MXC_CSPIPERIOD_32KHZ);
411 reg_write(&regs->intr, 0);
412
413 return 0;
414}
415
416#ifndef CONFIG_DM_SPI
417int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
418 void *din, unsigned long flags)
419{
420 struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
421
422 return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags);
423}
424
Nikita Kiryanov00cd7382014-08-20 15:08:50 +0300425/*
426 * Some SPI devices require active chip-select over multiple
427 * transactions, we achieve this using a GPIO. Still, the SPI
428 * controller has to be configured to use one of its own chipselects.
429 * To use this feature you have to implement board_spi_cs_gpio() to assign
430 * a gpio value for each cs (-1 if cs doesn't need to use gpio).
431 * You must use some unused on this SPI controller cs between 0 and 3.
432 */
433static int setup_cs_gpio(struct mxc_spi_slave *mxcs,
434 unsigned int bus, unsigned int cs)
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100435{
436 int ret;
437
Nikita Kiryanov00cd7382014-08-20 15:08:50 +0300438 mxcs->gpio = board_spi_cs_gpio(bus, cs);
439 if (mxcs->gpio == -1)
440 return 0;
441
Peng Fanea0bce62017-08-09 13:09:33 +0800442 gpio_request(mxcs->gpio, "spi-cs");
Nikita Kiryanov00cd7382014-08-20 15:08:50 +0300443 ret = gpio_direction_output(mxcs->gpio, !(mxcs->ss_pol));
444 if (ret) {
445 printf("mxc_spi: cannot setup gpio %d\n", mxcs->gpio);
446 return -EINVAL;
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100447 }
448
Nikita Kiryanov00cd7382014-08-20 15:08:50 +0300449 return 0;
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200450}
451
Peng Fanea0bce62017-08-09 13:09:33 +0800452static unsigned long spi_bases[] = {
453 MXC_SPI_BASE_ADDRESSES
454};
455
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200456struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
457 unsigned int max_hz, unsigned int mode)
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200458{
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200459 struct mxc_spi_slave *mxcs;
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100460 int ret;
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200461
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100462 if (bus >= ARRAY_SIZE(spi_bases))
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200463 return NULL;
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200464
Markus Niebel8f769cf2014-10-23 16:09:39 +0200465 if (max_hz == 0) {
466 printf("Error: desired clock is 0\n");
467 return NULL;
468 }
469
Simon Glassd034a952013-03-18 19:23:40 +0000470 mxcs = spi_alloc_slave(struct mxc_spi_slave, bus, cs);
Stefano Babic125f82a2010-08-20 12:05:03 +0200471 if (!mxcs) {
472 puts("mxc_spi: SPI Slave not allocated !\n");
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100473 return NULL;
Stefano Babic125f82a2010-08-20 12:05:03 +0200474 }
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100475
Fabio Estevam17cd2a82012-11-15 11:23:23 +0000476 mxcs->ss_pol = (mode & SPI_CS_HIGH) ? 1 : 0;
477
Nikita Kiryanov00cd7382014-08-20 15:08:50 +0300478 ret = setup_cs_gpio(mxcs, bus, cs);
Guennadi Liakhovetski9a88d702009-02-13 09:26:40 +0100479 if (ret < 0) {
480 free(mxcs);
481 return NULL;
482 }
483
Stefano Babic6e6f4552010-04-04 22:43:38 +0200484 mxcs->base = spi_bases[bus];
Markus Niebel8f769cf2014-10-23 16:09:39 +0200485 mxcs->max_hz = max_hz;
486 mxcs->mode = mode;
Stefano Babic6e6f4552010-04-04 22:43:38 +0200487
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200488 return &mxcs->slave;
489}
490
491void spi_free_slave(struct spi_slave *slave)
492{
Guennadi Liakhovetskid3380132009-02-07 00:09:12 +0100493 struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
494
495 free(mxcs);
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200496}
497
498int spi_claim_bus(struct spi_slave *slave)
499{
500 struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
501
Peng Fanea0bce62017-08-09 13:09:33 +0800502 return mxc_spi_claim_bus_internal(mxcs, slave->cs);
503}
504
505void spi_release_bus(struct spi_slave *slave)
506{
507 /* TODO: Shut the controller down */
508}
509#else
510
511static int mxc_spi_probe(struct udevice *bus)
512{
Peng Fanea0bce62017-08-09 13:09:33 +0800513 struct mxc_spi_slave *mxcs = dev_get_platdata(bus);
514 int node = dev_of_offset(bus);
515 const void *blob = gd->fdt_blob;
516 int ret;
Heiko Schocher053c2442019-05-26 12:15:47 +0200517 int i;
Peng Fanea0bce62017-08-09 13:09:33 +0800518
Heiko Schocher053c2442019-05-26 12:15:47 +0200519 ret = gpio_request_list_by_name(bus, "cs-gpios", mxcs->cs_gpios,
520 ARRAY_SIZE(mxcs->cs_gpios), 0);
521 if (ret < 0) {
522 pr_err("Can't get %s gpios! Error: %d", bus->name, ret);
523 return ret;
524 }
525
526 for (i = 0; i < ARRAY_SIZE(mxcs->cs_gpios); i++) {
527 if (!dm_gpio_is_valid(&mxcs->cs_gpios[i]))
528 continue;
529
530 ret = dm_gpio_set_dir_flags(&mxcs->cs_gpios[i],
531 GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
532 if (ret) {
533 dev_err(bus, "Setting cs %d error\n", i);
534 return ret;
535 }
Peng Fanea0bce62017-08-09 13:09:33 +0800536 }
537
Heiko Schocher6d49b4e2019-05-26 12:15:46 +0200538 mxcs->base = devfdt_get_addr(bus);
539 if (mxcs->base == FDT_ADDR_T_NONE)
Peng Fanea0bce62017-08-09 13:09:33 +0800540 return -ENODEV;
541
Peng Fanea0bce62017-08-09 13:09:33 +0800542 mxcs->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
543 20000000);
Guennadi Liakhovetski07327a52008-04-15 14:14:25 +0200544
545 return 0;
546}
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200547
Peng Fanea0bce62017-08-09 13:09:33 +0800548static int mxc_spi_xfer(struct udevice *dev, unsigned int bitlen,
549 const void *dout, void *din, unsigned long flags)
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200550{
Peng Fanea0bce62017-08-09 13:09:33 +0800551 struct mxc_spi_slave *mxcs = dev_get_platdata(dev->parent);
552
553
554 return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags);
555}
556
557static int mxc_spi_claim_bus(struct udevice *dev)
558{
559 struct mxc_spi_slave *mxcs = dev_get_platdata(dev->parent);
560 struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
561
Heiko Schocher053c2442019-05-26 12:15:47 +0200562 mxcs->dev = dev;
563
Peng Fanea0bce62017-08-09 13:09:33 +0800564 return mxc_spi_claim_bus_internal(mxcs, slave_plat->cs);
Haavard Skinnemoend74084a2008-05-16 11:10:31 +0200565}
Peng Fanea0bce62017-08-09 13:09:33 +0800566
567static int mxc_spi_release_bus(struct udevice *dev)
568{
569 return 0;
570}
571
572static int mxc_spi_set_speed(struct udevice *bus, uint speed)
573{
574 /* Nothing to do */
575 return 0;
576}
577
578static int mxc_spi_set_mode(struct udevice *bus, uint mode)
579{
580 struct mxc_spi_slave *mxcs = dev_get_platdata(bus);
581
582 mxcs->mode = mode;
583 mxcs->ss_pol = (mode & SPI_CS_HIGH) ? 1 : 0;
584
585 return 0;
586}
587
588static const struct dm_spi_ops mxc_spi_ops = {
589 .claim_bus = mxc_spi_claim_bus,
590 .release_bus = mxc_spi_release_bus,
591 .xfer = mxc_spi_xfer,
592 .set_speed = mxc_spi_set_speed,
593 .set_mode = mxc_spi_set_mode,
594};
595
596static const struct udevice_id mxc_spi_ids[] = {
597 { .compatible = "fsl,imx51-ecspi" },
598 { }
599};
600
601U_BOOT_DRIVER(mxc_spi) = {
602 .name = "mxc_spi",
603 .id = UCLASS_SPI,
604 .of_match = mxc_spi_ids,
605 .ops = &mxc_spi_ops,
606 .platdata_auto_alloc_size = sizeof(struct mxc_spi_slave),
607 .probe = mxc_spi_probe,
608};
609#endif