blob: 7a22ad2efed64120a3d952ae4f24c4a43a1d9368 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenke3093092002-10-01 01:07:28 +00002/*
3 * (C) Copyright 2002
4 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
wdenke3093092002-10-01 01:07:28 +00005 */
6
7/*
8 * SPI Read/Write Utilities
9 */
10
11#include <common.h>
12#include <command.h>
Simon Glass1157a162014-10-13 23:41:56 -060013#include <dm.h>
Simon Glassdf3b23a2014-09-15 06:33:22 -060014#include <errno.h>
wdenke3093092002-10-01 01:07:28 +000015#include <spi.h>
wdenke3093092002-10-01 01:07:28 +000016
Feng Chen28748192023-04-19 14:48:09 +080017#if CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
18#include <linux/compat.h>
19#endif
wdenkeb9401e2002-11-11 02:11:37 +000020/*-----------------------------------------------------------------------
21 * Definitions
22 */
23
24#ifndef MAX_SPI_BYTES
25# define MAX_SPI_BYTES 32 /* Maximum number of bytes we can handle */
26#endif
wdenke3093092002-10-01 01:07:28 +000027
Feng Chen28748192023-04-19 14:48:09 +080028#if CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
29#ifndef CONFIG_DEFAULT_SPI_BUS
30# define CONFIG_DEFAULT_SPI_BUS 0
31#endif
32#ifndef CONFIG_DEFAULT_SPI_MODE
33# define CONFIG_DEFAULT_SPI_MODE SPI_MODE_0
34#endif
35#endif
36
wdenke3093092002-10-01 01:07:28 +000037/*
38 * Values from last command.
39 */
Reinhard Meyer21032b32010-08-26 10:57:27 +020040static unsigned int bus;
41static unsigned int cs;
42static unsigned int mode;
Marek Vasut69547562019-12-20 12:44:57 +010043static unsigned int freq;
Wolfgang Denk0cf207e2021-09-27 17:42:39 +020044static int bitlen;
Feng Chen28748192023-04-19 14:48:09 +080045
46#if !CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
Wolfgang Denk0cf207e2021-09-27 17:42:39 +020047static uchar dout[MAX_SPI_BYTES];
48static uchar din[MAX_SPI_BYTES];
Feng Chen28748192023-04-19 14:48:09 +080049#else
50static int wordlen = 8;
51static unsigned int xfer_flags;
52struct spi_slave *g_slave;
53#define XFERS_MAX 8
54static uchar *buf_list[XFERS_MAX];
55static int buf_cnt;
56static uchar *dout;
57static uchar *din;
58#endif
wdenke3093092002-10-01 01:07:28 +000059
Simon Glassdf3b23a2014-09-15 06:33:22 -060060static int do_spi_xfer(int bus, int cs)
61{
62 struct spi_slave *slave;
Simon Glass1157a162014-10-13 23:41:56 -060063 int ret = 0;
Feng Chen28748192023-04-19 14:48:09 +080064#if CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
65 if (g_slave && !(xfer_flags & SPI_XFER_BEGIN)) {
66 slave = g_slave;
67 goto next_xfer;
68 }
69#endif
Lukasz Majewski56c40462020-06-04 23:11:53 +080070#if CONFIG_IS_ENABLED(DM_SPI)
Simon Glass1157a162014-10-13 23:41:56 -060071 char name[30], *str;
72 struct udevice *dev;
73
74 snprintf(name, sizeof(name), "generic_%d:%d", bus, cs);
75 str = strdup(name);
Peng Fan9caeb262016-03-20 21:21:36 +080076 if (!str)
77 return -ENOMEM;
Patrice Chotard61708bb2022-03-30 09:33:13 +020078 ret = _spi_get_bus_and_cs(bus, cs, freq, mode, "spi_generic_drv",
79 str, &dev, &slave);
Simon Glass1157a162014-10-13 23:41:56 -060080 if (ret)
81 return ret;
82#else
Marek Vasut69547562019-12-20 12:44:57 +010083 slave = spi_setup_slave(bus, cs, freq, mode);
Simon Glassdf3b23a2014-09-15 06:33:22 -060084 if (!slave) {
85 printf("Invalid device %d:%d\n", bus, cs);
86 return -EINVAL;
87 }
Simon Glass1157a162014-10-13 23:41:56 -060088#endif
Simon Glassdf3b23a2014-09-15 06:33:22 -060089
Feng Chen28748192023-04-19 14:48:09 +080090#if CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
91 g_slave = slave;
92 slave->wordlen = wordlen;
93#endif
Simon Glass1157a162014-10-13 23:41:56 -060094 ret = spi_claim_bus(slave);
95 if (ret)
96 goto done;
Feng Chen28748192023-04-19 14:48:09 +080097#if !CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
Simon Glass1157a162014-10-13 23:41:56 -060098 ret = spi_xfer(slave, bitlen, dout, din,
Feng Chen28748192023-04-19 14:48:09 +080099 SPI_XFER_BEGIN | SPI_XFER_END);
100#else
101next_xfer:
102 ret = spi_xfer(slave, bitlen, dout, din, xfer_flags);
103 if (ret > 0)
104 return 0;
105#endif
Lukasz Majewski56c40462020-06-04 23:11:53 +0800106#if !CONFIG_IS_ENABLED(DM_SPI)
Simon Glass1157a162014-10-13 23:41:56 -0600107 /* We don't get an error code in this case */
108 if (ret)
109 ret = -EIO;
110#endif
111 if (ret) {
112 printf("Error %d during SPI transaction\n", ret);
Simon Glassdf3b23a2014-09-15 06:33:22 -0600113 } else {
114 int j;
115
116 for (j = 0; j < ((bitlen + 7) / 8); j++)
117 printf("%02X", din[j]);
118 printf("\n");
119 }
Simon Glass1157a162014-10-13 23:41:56 -0600120done:
Feng Chen28748192023-04-19 14:48:09 +0800121#if CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
122 g_slave = 0;
123 for (int i = 0; i < buf_cnt; i++)
124 kfree(buf_list[i]);
125 buf_cnt = 0;
126#endif
Simon Glassdf3b23a2014-09-15 06:33:22 -0600127 spi_release_bus(slave);
Lukasz Majewski56c40462020-06-04 23:11:53 +0800128#if !CONFIG_IS_ENABLED(DM_SPI)
Simon Glassdf3b23a2014-09-15 06:33:22 -0600129 spi_free_slave(slave);
Simon Glass1157a162014-10-13 23:41:56 -0600130#endif
Simon Glassdf3b23a2014-09-15 06:33:22 -0600131
Simon Glass1157a162014-10-13 23:41:56 -0600132 return ret;
Simon Glassdf3b23a2014-09-15 06:33:22 -0600133}
134
wdenke3093092002-10-01 01:07:28 +0000135/*
136 * SPI read/write
137 *
138 * Syntax:
139 * spi {dev} {num_bits} {dout}
140 * {dev} is the device number for controlling chip select (see TBD)
141 * {num_bits} is the number of bits to send & receive (base 10)
142 * {dout} is a hexadecimal string of data to send
143 * The command prints out the hexadecimal string received via SPI.
144 */
145
Simon Glass09140112020-05-10 11:40:03 -0600146int do_spi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
wdenke3093092002-10-01 01:07:28 +0000147{
148 char *cp = 0;
149 uchar tmp;
150 int j;
wdenke3093092002-10-01 01:07:28 +0000151
152 /*
153 * We use the last specified parameters, unless new ones are
154 * entered.
155 */
Marek Vasut69547562019-12-20 12:44:57 +0100156 if (freq == 0)
157 freq = 1000000;
wdenke3093092002-10-01 01:07:28 +0000158
159 if ((flag & CMD_FLAG_REPEAT) == 0)
160 {
Reinhard Meyer21032b32010-08-26 10:57:27 +0200161 if (argc >= 2) {
162 mode = CONFIG_DEFAULT_SPI_MODE;
Simon Glass0b1284e2021-07-24 09:03:30 -0600163 bus = dectoul(argv[1], &cp);
Reinhard Meyer21032b32010-08-26 10:57:27 +0200164 if (*cp == ':') {
Simon Glass0b1284e2021-07-24 09:03:30 -0600165 cs = dectoul(cp + 1, &cp);
Reinhard Meyer21032b32010-08-26 10:57:27 +0200166 } else {
167 cs = bus;
168 bus = CONFIG_DEFAULT_SPI_BUS;
169 }
Marek Vasut2d5e7c72012-08-01 15:12:15 +0200170 if (*cp == '.')
Simon Glass0b1284e2021-07-24 09:03:30 -0600171 mode = dectoul(cp + 1, &cp);
Marek Vasut69547562019-12-20 12:44:57 +0100172 if (*cp == '@')
Simon Glass0b1284e2021-07-24 09:03:30 -0600173 freq = dectoul(cp + 1, &cp);
Feng Chen28748192023-04-19 14:48:09 +0800174#if CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
175 if (*cp == '.')
176 wordlen = simple_strtoul(cp + 1, &cp, 10);
177 if (*cp == '.')
178 xfer_flags = simple_strtoul(cp + 1, &cp, 16);
179 else
180 xfer_flags = SPI_XFER_BEGIN | SPI_XFER_END;
181#endif
Reinhard Meyer21032b32010-08-26 10:57:27 +0200182 }
Feng Chen28748192023-04-19 14:48:09 +0800183#if !CONFIG_IS_ENABLED(AMLOGIC_MODIFY)
wdenke3093092002-10-01 01:07:28 +0000184 if (argc >= 3)
Simon Glass0b1284e2021-07-24 09:03:30 -0600185 bitlen = dectoul(argv[2], NULL);
Feng Chen28748192023-04-19 14:48:09 +0800186#else
187 if (argc >= 3) {
188 bitlen = dectoul(argv[2], NULL);
189 dout = kcalloc(ALIGN(bitlen / 8, 8), 2, GFP_KERNEL);
190 if (!dout)
191 return -ENOMEM;
192 din = dout + ALIGN(bitlen / 8, 8);
193 buf_list[buf_cnt] = dout;
194 if (++buf_cnt >= XFERS_MAX)
195 xfer_flags |= SPI_XFER_END;
196 }
197#endif
wdenkeb9401e2002-11-11 02:11:37 +0000198 if (argc >= 4) {
199 cp = argv[3];
200 for(j = 0; *cp; j++, cp++) {
201 tmp = *cp - '0';
202 if(tmp > 9)
203 tmp -= ('A' - '0') - 10;
204 if(tmp > 15)
205 tmp -= ('a' - 'A');
206 if(tmp > 15) {
Reinhard Meyer21032b32010-08-26 10:57:27 +0200207 printf("Hex conversion error on %c\n", *cp);
wdenkeb9401e2002-11-11 02:11:37 +0000208 return 1;
209 }
210 if((j % 2) == 0)
211 dout[j / 2] = (tmp << 4);
212 else
213 dout[j / 2] |= tmp;
wdenke3093092002-10-01 01:07:28 +0000214 }
wdenke3093092002-10-01 01:07:28 +0000215 }
216 }
217
wdenkeb9401e2002-11-11 02:11:37 +0000218 if ((bitlen < 0) || (bitlen > (MAX_SPI_BYTES * 8))) {
Reinhard Meyer21032b32010-08-26 10:57:27 +0200219 printf("Invalid bitlen %d\n", bitlen);
wdenkeb9401e2002-11-11 02:11:37 +0000220 return 1;
wdenk8bde7f72003-06-27 21:31:46 +0000221 }
wdenkeb9401e2002-11-11 02:11:37 +0000222
Simon Glassdf3b23a2014-09-15 06:33:22 -0600223 if (do_spi_xfer(bus, cs))
Haavard Skinnemoend255bb02008-05-16 11:10:31 +0200224 return 1;
wdenkeb9401e2002-11-11 02:11:37 +0000225
Simon Glassdf3b23a2014-09-15 06:33:22 -0600226 return 0;
wdenke3093092002-10-01 01:07:28 +0000227}
228
wdenk8bde7f72003-06-27 21:31:46 +0000229/***************************************************/
230
wdenk0d498392003-07-01 21:06:45 +0000231U_BOOT_CMD(
232 sspi, 5, 1, do_spi,
Reinhard Meyer21032b32010-08-26 10:57:27 +0200233 "SPI utility command",
Marek Vasut69547562019-12-20 12:44:57 +0100234 "[<bus>:]<cs>[.<mode>][@<freq>] <bit_len> <dout> - Send and receive bits\n"
Reinhard Meyer21032b32010-08-26 10:57:27 +0200235 "<bus> - Identifies the SPI bus\n"
236 "<cs> - Identifies the chip select\n"
237 "<mode> - Identifies the SPI mode to use\n"
Marek Vasut69547562019-12-20 12:44:57 +0100238 "<freq> - Identifies the SPI bus frequency in Hz\n"
wdenk8bde7f72003-06-27 21:31:46 +0000239 "<bit_len> - Number of bits to send (base 10)\n"
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200240 "<dout> - Hexadecimal string that gets sent"
wdenk8bde7f72003-06-27 21:31:46 +0000241);