Skip to content

Commit 8fe24b8

Browse files
committed
spi: shell: rework command to use SPI devices
Rework the shell interface to work on SPI devices. This will create a build-time list of all spi device nodes based on the devicetree. At runtime, the shell will autocomplete device names and use spi_transceive_dt() to leverage the devicetree configuration of each node. This removes the need for a conf command, and will ensure that all chip select modes are properly supported (i.e. cs-gpios). Signed-off-by: Liam Beguin <[email protected]>
1 parent b7b4de8 commit 8fe24b8

File tree

1 file changed

+47
-100
lines changed

1 file changed

+47
-100
lines changed

drivers/spi/spi_shell.c

Lines changed: 47 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -12,42 +12,60 @@
1212
#include <zephyr/shell/shell.h>
1313
#include <zephyr/sys/util.h>
1414

15-
#define TXRX_ARGV_BYTES (1)
16-
#define CONF_ARGV_DEV (1)
17-
#define CONF_ARGV_FREQUENCY (2)
18-
#define CONF_ARGV_SETTINGS (3)
15+
#define TXRX_ARGV_DEV (1)
16+
#define TXRX_ARGV_BYTES (2)
1917

2018
/* Maximum bytes we can write and read at once */
2119
#define MAX_SPI_BYTES MIN((CONFIG_SHELL_ARGC_MAX - TXRX_ARGV_BYTES), 32)
2220

23-
static struct device *spi_device;
24-
static struct spi_config config = {.frequency = 1000000,
25-
.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8)};
21+
#define SPIDEV_INST(node_id) \
22+
{ \
23+
.dev = DEVICE_DT_GET(node_id), \
24+
.spi = SPI_DT_SPEC_GET(node_id, SPI_WORD_SET(8) | SPI_OP_MODE_MASTER, 0), \
25+
},
2626

27-
static void device_name_get(size_t idx, struct shell_static_entry *entry)
28-
{
29-
const struct device *dev = shell_device_lookup(idx, "spi");
27+
#define IS_SPIDEV_NODE(node_id) \
28+
COND_CODE_1(DT_NODE_HAS_PROP(node_id, spi_max_frequency), (SPIDEV_INST(node_id)), ())
29+
30+
static struct spidev {
31+
const struct device *dev;
32+
const struct spi_dt_spec spi;
3033

31-
entry->syntax = (dev != NULL) ? dev->name : NULL;
32-
entry->handler = NULL;
33-
entry->help = NULL;
34-
entry->subcmd = NULL;
34+
} spidev_list[] = {DT_FOREACH_STATUS_OKAY_NODE(IS_SPIDEV_NODE)};
35+
36+
static void get_spidev_comp(size_t idx, struct shell_static_entry *entry)
37+
{
38+
if (idx < ARRAY_SIZE(spidev_list)) {
39+
entry->syntax = spidev_list[idx].dev->name;
40+
entry->handler = NULL;
41+
entry->subcmd = NULL;
42+
entry->help = "Select spi device.";
43+
} else {
44+
entry->syntax = NULL;
45+
}
3546
}
47+
SHELL_DYNAMIC_CMD_CREATE(dsub_spidev, get_spidev_comp);
3648

37-
SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
49+
static struct spidev *get_spidev(const char *device_label)
50+
{
51+
for (int i = 0; i < ARRAY_SIZE(spidev_list); i++) {
52+
if (!strcmp(device_label, spidev_list[i].dev->name)) {
53+
return &spidev_list[i];
54+
}
55+
}
3856

39-
static int cmd_spi_transceive(const struct shell *ctx, size_t argc, char **argv)
57+
/* This will never happen because was prompted by shell */
58+
__ASSERT_NO_MSG(false);
59+
return NULL;
60+
}
61+
static int cmd_spi_transceive_dt(const struct shell *ctx, size_t argc, char **argv)
4062
{
4163
uint8_t rx_buffer[MAX_SPI_BYTES] = {0};
4264
uint8_t tx_buffer[MAX_SPI_BYTES] = {0};
4365

44-
if (spi_device == NULL) {
45-
shell_error(ctx, "SPI device isn't configured. Use `spi conf`");
46-
return -ENODEV;
47-
}
66+
struct spidev *spidev = get_spidev(argv[TXRX_ARGV_DEV]);
4867

4968
int bytes_to_send = argc - TXRX_ARGV_BYTES;
50-
5169
for (int i = 0; i < bytes_to_send; i++) {
5270
tx_buffer[i] = strtol(argv[TXRX_ARGV_BYTES + i], NULL, 16);
5371
}
@@ -58,8 +76,7 @@ static int cmd_spi_transceive(const struct shell *ctx, size_t argc, char **argv)
5876
const struct spi_buf_set tx_buf_set = {.buffers = &tx_buffers, .count = 1};
5977
const struct spi_buf_set rx_buf_set = {.buffers = &rx_buffers, .count = 1};
6078

61-
int ret = spi_transceive(spi_device, &config, &tx_buf_set, &rx_buf_set);
62-
79+
int ret = spi_transceive_dt(&spidev->spi, &tx_buf_set, &rx_buf_set);
6380
if (ret < 0) {
6481
shell_error(ctx, "spi_transceive returned %d", ret);
6582
return ret;
@@ -74,82 +91,12 @@ static int cmd_spi_transceive(const struct shell *ctx, size_t argc, char **argv)
7491
return ret;
7592
}
7693

77-
static int cmd_spi_conf(const struct shell *ctx, size_t argc, char **argv)
78-
{
79-
spi_operation_t operation = SPI_WORD_SET(8) | SPI_OP_MODE_MASTER;
80-
81-
/* warning: initialization discards 'const' qualifier from pointer */
82-
/* target type */
83-
struct device *dev = (struct device *)device_get_binding(argv[CONF_ARGV_DEV]);
84-
85-
if (dev == NULL) {
86-
shell_error(ctx, "device %s not found.", argv[CONF_ARGV_DEV]);
87-
return -ENODEV;
88-
}
89-
90-
uint32_t frequency = strtol(argv[CONF_ARGV_FREQUENCY], NULL, 10);
91-
92-
if (!IN_RANGE(frequency, 100 * 1000, 80 * 1000 * 1000)) {
93-
shell_error(ctx, "frequency must be between 100000 and 80000000");
94-
return -EINVAL;
95-
}
96-
97-
/* no settings */
98-
if (argc == (CONF_ARGV_FREQUENCY + 1)) {
99-
goto out;
100-
}
101-
102-
char *opts = argv[CONF_ARGV_SETTINGS];
103-
bool all_opts_is_valid = true;
104-
105-
while (*opts != '\0') {
106-
switch (*opts) {
107-
case 'o':
108-
operation |= SPI_MODE_CPOL;
109-
break;
110-
case 'h':
111-
operation |= SPI_MODE_CPHA;
112-
break;
113-
case 'l':
114-
operation |= SPI_TRANSFER_LSB;
115-
break;
116-
case 'T':
117-
operation |= SPI_FRAME_FORMAT_TI;
118-
break;
119-
default:
120-
all_opts_is_valid = false;
121-
shell_error(ctx, "invalid setting %c", *opts);
122-
}
123-
opts++;
124-
}
125-
126-
if (!all_opts_is_valid) {
127-
return -EINVAL;
128-
}
129-
130-
out:
131-
config.frequency = frequency;
132-
config.operation = operation;
133-
spi_device = dev;
134-
135-
return 0;
136-
}
137-
138-
SHELL_STATIC_SUBCMD_SET_CREATE(sub_spi_cmds,
139-
SHELL_CMD_ARG(conf, &dsub_device_name,
140-
"Configure SPI\n"
141-
"Usage: spi conf <device> <frequency> [<settings>]\n"
142-
"<settings> - any sequence of letters:\n"
143-
"o - SPI_MODE_CPOL\n"
144-
"h - SPI_MODE_CPHA\n"
145-
"l - SPI_TRANSFER_LSB\n"
146-
"T - SPI_FRAME_FORMAT_TI\n"
147-
"example: spi conf spi1 1000000 ol",
148-
cmd_spi_conf, 3, 1),
149-
SHELL_CMD_ARG(transceive, NULL,
150-
"Transceive data to and from an SPI device\n"
151-
"Usage: spi transceive <TX byte 1> [<TX byte 2> ...]",
152-
cmd_spi_transceive, 2, MAX_SPI_BYTES - 1),
153-
SHELL_SUBCMD_SET_END);
94+
SHELL_STATIC_SUBCMD_SET_CREATE(
95+
sub_spi_cmds,
96+
SHELL_CMD_ARG(transceive, &dsub_spidev,
97+
"Transceive data to and from an SPI device\n"
98+
"Usage: spi transceive <node> <TX byte 1> [<TX byte 2> ...]",
99+
cmd_spi_transceive_dt, 3, MAX_SPI_BYTES - 1),
100+
SHELL_SUBCMD_SET_END);
154101

155102
SHELL_CMD_REGISTER(spi, &sub_spi_cmds, "SPI commands", NULL);

0 commit comments

Comments
 (0)