You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2455 lines
68 KiB
2455 lines
68 KiB
/* |
|
* Copyright (c) 2024 Meta Platforms |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/drivers/i3c.h> |
|
#include <zephyr/shell/shell.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <zephyr/sys/byteorder.h> |
|
#include <zephyr/sys/util.h> |
|
|
|
#include <zephyr/logging/log.h> |
|
LOG_MODULE_REGISTER(i3c_shell, CONFIG_LOG_DEFAULT_LEVEL); |
|
|
|
#define MAX_BYTES_FOR_REGISTER_INDEX 4 |
|
#define ARGV_DEV 1 |
|
#define ARGV_TDEV 2 |
|
#define ARGV_REG 3 |
|
|
|
/* Maximum bytes we can write or read at once */ |
|
#define MAX_I3C_BYTES 16 |
|
|
|
struct i3c_ctrl { |
|
const struct device *dev; |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
const union shell_cmd_entry *i3c_attached_dev_subcmd; |
|
const union shell_cmd_entry *i3c_list_dev_subcmd; |
|
#endif |
|
}; |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
#define I3C_ATTACHED_DEV_GET_FN(node_id) \ |
|
static void node_id##cmd_i3c_attached_get(size_t idx, struct shell_static_entry *entry); \ |
|
\ |
|
SHELL_DYNAMIC_CMD_CREATE(node_id##sub_i3c_attached, node_id##cmd_i3c_attached_get); \ |
|
\ |
|
static void node_id##cmd_i3c_attached_get(size_t idx, struct shell_static_entry *entry) \ |
|
{ \ |
|
const struct device *dev = DEVICE_DT_GET(node_id); \ |
|
struct i3c_device_desc *i3c_desc; \ |
|
size_t cnt = 0; \ |
|
\ |
|
entry->syntax = NULL; \ |
|
entry->handler = NULL; \ |
|
entry->subcmd = NULL; \ |
|
entry->help = NULL; \ |
|
\ |
|
I3C_BUS_FOR_EACH_I3CDEV(dev, i3c_desc) { \ |
|
if (cnt == idx) { \ |
|
entry->syntax = i3c_desc->dev->name; \ |
|
return; \ |
|
} \ |
|
cnt++; \ |
|
} \ |
|
} |
|
|
|
#define I3C_LIST_DEV_GET_FN(node_id) \ |
|
static void node_id##cmd_i3c_list_get(size_t idx, struct shell_static_entry *entry); \ |
|
\ |
|
SHELL_DYNAMIC_CMD_CREATE(node_id##sub_i3c_list, node_id##cmd_i3c_list_get); \ |
|
\ |
|
static void node_id##cmd_i3c_list_get(size_t idx, struct shell_static_entry *entry) \ |
|
{ \ |
|
const struct device *dev = DEVICE_DT_GET(node_id); \ |
|
struct i3c_driver_config *config; \ |
|
\ |
|
entry->syntax = NULL; \ |
|
entry->handler = NULL; \ |
|
entry->subcmd = NULL; \ |
|
entry->help = NULL; \ |
|
\ |
|
config = (struct i3c_driver_config *)dev->config; \ |
|
if (idx < config->dev_list.num_i3c) { \ |
|
entry->syntax = config->dev_list.i3c[idx].dev->name; \ |
|
} \ |
|
} |
|
|
|
#define I3C_CTRL_FN(node_id) \ |
|
I3C_ATTACHED_DEV_GET_FN(node_id) \ |
|
I3C_LIST_DEV_GET_FN(node_id) |
|
|
|
/* zephyr-keep-sorted-start */ |
|
DT_FOREACH_STATUS_OKAY(cdns_i3c, I3C_CTRL_FN) |
|
DT_FOREACH_STATUS_OKAY(ite_it51xxx_i3cm, I3C_CTRL_FN) |
|
DT_FOREACH_STATUS_OKAY(ite_it51xxx_i3cs, I3C_CTRL_FN) |
|
DT_FOREACH_STATUS_OKAY(nuvoton_npcx_i3c, I3C_CTRL_FN) |
|
DT_FOREACH_STATUS_OKAY(nxp_mcux_i3c, I3C_CTRL_FN) |
|
DT_FOREACH_STATUS_OKAY(renesas_ra_i3c, I3C_CTRL_FN) |
|
DT_FOREACH_STATUS_OKAY(snps_designware_i3c, I3C_CTRL_FN) |
|
DT_FOREACH_STATUS_OKAY(st_stm32_i3c, I3C_CTRL_FN) |
|
/* zephyr-keep-sorted-stop */ |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
#define I3C_CTRL_LIST_ENTRY(node_id) \ |
|
{ \ |
|
.dev = DEVICE_DT_GET(node_id), \ |
|
IF_ENABLED(CONFIG_I3C_CONTROLLER, \ |
|
(.i3c_attached_dev_subcmd = &node_id##sub_i3c_attached, \ |
|
.i3c_list_dev_subcmd = &node_id##sub_i3c_list,)) \ |
|
}, |
|
|
|
const struct i3c_ctrl i3c_list[] = { |
|
/* zephyr-keep-sorted-start */ |
|
DT_FOREACH_STATUS_OKAY(cdns_i3c, I3C_CTRL_LIST_ENTRY) |
|
DT_FOREACH_STATUS_OKAY(ite_it51xxx_i3cm, I3C_CTRL_LIST_ENTRY) |
|
DT_FOREACH_STATUS_OKAY(ite_it51xxx_i3cs, I3C_CTRL_LIST_ENTRY) |
|
DT_FOREACH_STATUS_OKAY(nuvoton_npcx_i3c, I3C_CTRL_LIST_ENTRY) |
|
DT_FOREACH_STATUS_OKAY(nxp_mcux_i3c, I3C_CTRL_LIST_ENTRY) |
|
DT_FOREACH_STATUS_OKAY(renesas_ra_i3c, I3C_CTRL_LIST_ENTRY) |
|
DT_FOREACH_STATUS_OKAY(snps_designware_i3c, I3C_CTRL_LIST_ENTRY) |
|
DT_FOREACH_STATUS_OKAY(st_stm32_i3c, I3C_CTRL_LIST_ENTRY) |
|
/* zephyr-keep-sorted-stop */ |
|
}; |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
static int get_bytes_count_for_hex(char *arg) |
|
{ |
|
int length = (strlen(arg) + 1) / 2; |
|
|
|
if (length > 1 && arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) { |
|
length -= 1; |
|
} |
|
|
|
return MIN(MAX_BYTES_FOR_REGISTER_INDEX, length); |
|
} |
|
|
|
static struct i3c_device_desc *get_i3c_list_desc_from_dev_name(const struct device *dev, |
|
const char *tdev_name) |
|
{ |
|
struct i3c_driver_config *config; |
|
uint8_t i; |
|
|
|
config = (struct i3c_driver_config *)dev->config; |
|
for (i = 0; i < config->dev_list.num_i3c; i++) { |
|
if (strcmp(config->dev_list.i3c[i].dev->name, tdev_name) == 0) { |
|
/* only look for a device with the same name */ |
|
return &config->dev_list.i3c[i]; |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
static struct i3c_device_desc *get_i3c_attached_desc_from_dev_name(const struct device *dev, |
|
const char *tdev_name) |
|
{ |
|
struct i3c_device_desc *i3c_desc; |
|
|
|
I3C_BUS_FOR_EACH_I3CDEV(dev, i3c_desc) { |
|
/* only look for a device with the same name */ |
|
if (strcmp(i3c_desc->dev->name, tdev_name) == 0) { |
|
return i3c_desc; |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
static int i3c_parse_args(const struct shell *sh, char **argv, const struct device **dev, |
|
const struct device **tdev, struct i3c_device_desc **desc) |
|
{ |
|
*dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!*dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
*tdev = shell_device_get_binding(argv[ARGV_TDEV]); |
|
if (!*tdev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); |
|
return -ENODEV; |
|
} |
|
*desc = get_i3c_attached_desc_from_dev_name(*dev, (*tdev)->name); |
|
if (!*desc) { |
|
shell_error(sh, "I3C: Device %s not attached to bus.", (*tdev)->name); |
|
return -ENODEV; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/* i3c info <device> [<target>] */ |
|
static int cmd_i3c_info(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_driver_data *data; |
|
struct i3c_device_desc *desc; |
|
struct i3c_i2c_device_desc *i2c_desc; |
|
bool found = false; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
|
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
data = (struct i3c_driver_data *)dev->data; |
|
|
|
if (argc == 3) { |
|
tdev = shell_device_get_binding(argv[ARGV_TDEV]); |
|
if (!tdev) { |
|
shell_error(sh, "I3C: Target Device driver %s not found.", argv[ARGV_TDEV]); |
|
return -ENODEV; |
|
} |
|
if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) { |
|
I3C_BUS_FOR_EACH_I3CDEV(dev, desc) { |
|
/* only look for a device with the same name */ |
|
if (strcmp(desc->dev->name, tdev->name) == 0) { |
|
shell_print(sh, |
|
"name: %s\n" |
|
"\tpid: 0x%012llx\n" |
|
"\tstatic_addr: 0x%02x\n" |
|
"\tdynamic_addr: 0x%02x\n" |
|
"\tbcr: 0x%02x\n" |
|
"\tdcr: 0x%02x\n" |
|
"\tmaxrd: 0x%02x\n" |
|
"\tmaxwr: 0x%02x\n" |
|
"\tmax_read_turnaround: 0x%06x\n" |
|
"\tmrl: 0x%04x\n" |
|
"\tmwl: 0x%04x\n" |
|
"\tmax_ibi: 0x%02x\n" |
|
"\tcrhdly1: 0x%02x\n" |
|
"\tgetcaps: 0x%02x; 0x%02x; 0x%02x; 0x%02x\n" |
|
"\tcrcaps: 0x%02x; 0x%02x", |
|
desc->dev->name, (uint64_t)desc->pid, |
|
desc->static_addr, desc->dynamic_addr, |
|
desc->bcr, desc->dcr, desc->data_speed.maxrd, |
|
desc->data_speed.maxwr, |
|
desc->data_speed.max_read_turnaround, |
|
desc->data_length.mrl, desc->data_length.mwl, |
|
desc->data_length.max_ibi, desc->crhdly1, |
|
desc->getcaps.getcap1, desc->getcaps.getcap2, |
|
desc->getcaps.getcap3, desc->getcaps.getcap4, |
|
desc->crcaps.crcaps1, desc->crcaps.crcaps2); |
|
found = true; |
|
break; |
|
} |
|
} |
|
} else { |
|
shell_print(sh, "I3C: No devices found."); |
|
return -ENODEV; |
|
} |
|
if (found == false) { |
|
shell_error(sh, "I3C: Target device not found."); |
|
return -ENODEV; |
|
} |
|
} else if (argc == 2) { |
|
/* This gets all "currently attached" I3C and I2C devices */ |
|
if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) { |
|
shell_print(sh, "I3C: Devices found:"); |
|
I3C_BUS_FOR_EACH_I3CDEV(dev, desc) { |
|
shell_print(sh, |
|
"name: %s\n" |
|
"\tpid: 0x%012llx\n" |
|
"\tstatic_addr: 0x%02x\n" |
|
"\tdynamic_addr: 0x%02x\n" |
|
"\tbcr: 0x%02x\n" |
|
"\tdcr: 0x%02x\n" |
|
"\tmaxrd: 0x%02x\n" |
|
"\tmaxwr: 0x%02x\n" |
|
"\tmax_read_turnaround: 0x%06x\n" |
|
"\tmrl: 0x%04x\n" |
|
"\tmwl: 0x%04x\n" |
|
"\tmax_ibi: 0x%02x\n" |
|
"\tcrhdly1: 0x%02x\n" |
|
"\tgetcaps: 0x%02x; 0x%02x; 0x%02x; 0x%02x\n" |
|
"\tcrcaps: 0x%02x; 0x%02x", |
|
desc->dev->name, (uint64_t)desc->pid, desc->static_addr, |
|
desc->dynamic_addr, |
|
desc->bcr, desc->dcr, desc->data_speed.maxrd, |
|
desc->data_speed.maxwr, |
|
desc->data_speed.max_read_turnaround, |
|
desc->data_length.mrl, desc->data_length.mwl, |
|
desc->data_length.max_ibi, desc->crhdly1, |
|
desc->getcaps.getcap1, desc->getcaps.getcap2, |
|
desc->getcaps.getcap3, desc->getcaps.getcap4, |
|
desc->crcaps.crcaps1, desc->crcaps.crcaps2); |
|
} |
|
} else { |
|
shell_print(sh, "I3C: No devices found."); |
|
} |
|
if (!sys_slist_is_empty(&data->attached_dev.devices.i2c)) { |
|
shell_print(sh, "I2C: Devices found:"); |
|
I3C_BUS_FOR_EACH_I2CDEV(dev, i2c_desc) { |
|
shell_print(sh, |
|
"addr: 0x%02x\n" |
|
"\tlvr: 0x%02x", |
|
i2c_desc->addr, i2c_desc->lvr); |
|
} |
|
} else { |
|
shell_print(sh, "I2C: No devices found."); |
|
} |
|
} else { |
|
shell_error(sh, "Invalid number of arguments."); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/* i3c speed <device> <speed> */ |
|
static int cmd_i3c_speed(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_config_controller config; |
|
uint32_t speed; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[1]); |
|
return -ENODEV; |
|
} |
|
|
|
speed = strtol(argv[ARGV_DEV + 1], NULL, 10); |
|
|
|
ret = i3c_config_get(dev, I3C_CONFIG_CONTROLLER, &config); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Failed to retrieve configuration"); |
|
return ret; |
|
} |
|
|
|
config.scl.i3c = speed; |
|
|
|
ret = i3c_configure(dev, I3C_CONFIG_CONTROLLER, &config); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Failed to configure device"); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c recover <device> */ |
|
static int cmd_i3c_recover(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
int err; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[1]); |
|
return -ENODEV; |
|
} |
|
|
|
err = i3c_recover_bus(dev); |
|
if (err) { |
|
shell_error(sh, "I3C: Bus recovery failed (err %d)", err); |
|
return err; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int i3c_write_from_buffer(const struct shell *sh, char *s_dev_name, char *s_tdev_name, |
|
char *s_reg_addr, char **data, uint8_t data_length) |
|
{ |
|
/* This buffer must preserve 4 bytes for register address, as it is |
|
* filled using put_be32 function and we don't want to lower available |
|
* space when using 1 byte address. |
|
*/ |
|
uint8_t buf[MAX_I3C_BYTES + MAX_BYTES_FOR_REGISTER_INDEX - 1]; |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int reg_addr_bytes; |
|
int reg_addr; |
|
int ret; |
|
int i; |
|
|
|
dev = shell_device_get_binding(s_dev_name); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", s_dev_name); |
|
return -ENODEV; |
|
} |
|
tdev = shell_device_get_binding(s_tdev_name); |
|
if (!tdev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", s_tdev_name); |
|
return -ENODEV; |
|
} |
|
desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); |
|
if (!desc) { |
|
shell_error(sh, "I3C: Device %s not attached to bus.", tdev->name); |
|
return -ENODEV; |
|
} |
|
|
|
reg_addr = strtol(s_reg_addr, NULL, 16); |
|
|
|
reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr); |
|
sys_put_be32(reg_addr, buf); |
|
|
|
if (data_length + reg_addr_bytes > MAX_I3C_BYTES) { |
|
data_length = MAX_I3C_BYTES - reg_addr_bytes; |
|
shell_info(sh, "Too many bytes provided, limit is %d", |
|
MAX_I3C_BYTES - reg_addr_bytes); |
|
} |
|
|
|
for (i = 0; i < data_length; i++) { |
|
buf[MAX_BYTES_FOR_REGISTER_INDEX + i] = (uint8_t)strtol(data[i], NULL, 16); |
|
} |
|
|
|
ret = i3c_write(desc, buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes, |
|
reg_addr_bytes + data_length); |
|
if (ret < 0) { |
|
shell_error(sh, "Failed to write to device: %s", tdev->name); |
|
return -EIO; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/* i3c write <device> <dev_addr> <reg_addr> [<byte1>, ...] */ |
|
static int cmd_i3c_write(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
return i3c_write_from_buffer(sh, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], &argv[4], |
|
argc - 4); |
|
} |
|
|
|
/* i3c write_byte <device> <dev_addr> <reg_addr> <value> */ |
|
static int cmd_i3c_write_byte(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
return i3c_write_from_buffer(sh, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], &argv[4], |
|
1); |
|
} |
|
|
|
static int i3c_read_to_buffer(const struct shell *sh, char *s_dev_name, char *s_tdev_name, |
|
char *s_reg_addr, uint8_t *buf, uint8_t buf_length) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
uint8_t reg_addr_buf[MAX_BYTES_FOR_REGISTER_INDEX]; |
|
int reg_addr_bytes; |
|
int reg_addr; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(s_dev_name); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", s_dev_name); |
|
return -ENODEV; |
|
} |
|
tdev = shell_device_get_binding(s_tdev_name); |
|
if (!tdev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", s_dev_name); |
|
return -ENODEV; |
|
} |
|
desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); |
|
if (!desc) { |
|
shell_error(sh, "I3C: Device %s not attached to bus.", tdev->name); |
|
return -ENODEV; |
|
} |
|
|
|
reg_addr = strtol(s_reg_addr, NULL, 16); |
|
|
|
reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr); |
|
sys_put_be32(reg_addr, reg_addr_buf); |
|
|
|
ret = i3c_write_read(desc, reg_addr_buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes, |
|
reg_addr_bytes, buf, buf_length); |
|
if (ret < 0) { |
|
shell_error(sh, "Failed to read from device: %s", tdev->name); |
|
return -EIO; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/* i3c read_byte <device> <target> <reg_addr> */ |
|
static int cmd_i3c_read_byte(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
uint8_t out; |
|
int ret; |
|
|
|
ret = i3c_read_to_buffer(sh, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], &out, 1); |
|
if (ret == 0) { |
|
shell_print(sh, "Output: 0x%x", out); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c read <device> <target> <reg_addr> [<numbytes>] */ |
|
static int cmd_i3c_read(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
uint8_t buf[MAX_I3C_BYTES]; |
|
int num_bytes; |
|
int ret; |
|
|
|
if (argc > 4) { |
|
num_bytes = strtol(argv[4], NULL, 16); |
|
if (num_bytes > MAX_I3C_BYTES) { |
|
num_bytes = MAX_I3C_BYTES; |
|
} |
|
} else { |
|
num_bytes = MAX_I3C_BYTES; |
|
} |
|
|
|
ret = i3c_read_to_buffer(sh, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], buf, |
|
num_bytes); |
|
if (ret == 0) { |
|
shell_hexdump(sh, buf, num_bytes); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c hdr ddr read <device> <target> <7b cmd> [<byte1>, ...] */ |
|
static int cmd_i3c_hdr_ddr_write(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
uint8_t buf[MAX_I3C_BYTES]; |
|
uint8_t cmd; |
|
uint8_t data_length; |
|
uint8_t i; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
cmd = strtol(argv[3], NULL, 16); |
|
|
|
data_length = argc - 4; |
|
if (data_length > MAX_I3C_BYTES) { |
|
shell_info(sh, "Too many bytes provided, limit is %d", MAX_I3C_BYTES); |
|
} |
|
|
|
for (i = 0; i < data_length; i++) { |
|
buf[i] = (uint8_t)strtol(argv[4 + i], NULL, 16); |
|
} |
|
|
|
ret = i3c_hdr_ddr_write(desc, cmd, buf, data_length); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: unable to perform HDR DDR write."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c hdr ddr read <device> <target> <7b cmd> [<numbytes>] */ |
|
static int cmd_i3c_hdr_ddr_read(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
uint8_t buf[MAX_I3C_BYTES]; |
|
int num_bytes; |
|
uint8_t cmd; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
cmd = strtol(argv[3], NULL, 16); |
|
|
|
if (argc > 4) { |
|
num_bytes = strtol(argv[4], NULL, 16); |
|
if (num_bytes > MAX_I3C_BYTES) { |
|
num_bytes = MAX_I3C_BYTES; |
|
} |
|
} else { |
|
num_bytes = MAX_I3C_BYTES; |
|
} |
|
|
|
ret = i3c_hdr_ddr_read(desc, cmd, buf, num_bytes); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: unable to perform HDR DDR read."); |
|
return ret; |
|
} |
|
|
|
shell_hexdump(sh, buf, num_bytes); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc rstdaa_dc <device> <target> */ |
|
static int cmd_i3c_ccc_rstdaa_dc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
if (!(desc->flags & I3C_V1P0_SUPPORT)) { |
|
shell_error(sh, "I3C: %s does not support RSTDAA_DC.", tdev->name); |
|
return -ENOTSUP; |
|
} |
|
|
|
ret = i3c_ccc_do_rstdaa(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC RSTDAA."); |
|
return ret; |
|
} |
|
|
|
/* reset device DA */ |
|
desc->dynamic_addr = 0; |
|
shell_print(sh, "Reset dynamic address for device %s", desc->dev->name); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc rstdaa <device> */ |
|
static int cmd_i3c_ccc_rstdaa(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
ret = i3c_bus_rstdaa_all(dev); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC RSTDAA."); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entdaa <device> */ |
|
static int cmd_i3c_ccc_entdaa(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
return i3c_do_daa(dev); |
|
} |
|
|
|
/* i3c ccc setaasa <device> */ |
|
static int cmd_i3c_ccc_setaasa(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
ret = i3c_bus_setaasa(dev); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETAASA."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setdasa <device> <target> <dynamic address> */ |
|
static int cmd_i3c_ccc_setdasa(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
struct i3c_driver_data *data; |
|
uint8_t dynamic_addr; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
data = (struct i3c_driver_data *)dev->data; |
|
dynamic_addr = strtol(argv[3], NULL, 16); |
|
|
|
ret = i3c_bus_setdasa(desc, dynamic_addr); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETDASA."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Dynamic address set to 0x%02x", desc->dynamic_addr); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setnewda <device> <target> <dynamic address> */ |
|
static int cmd_i3c_ccc_setnewda(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
struct i3c_driver_data *data; |
|
uint8_t dynamic_addr; |
|
uint8_t old_da; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
data = (struct i3c_driver_data *)dev->data; |
|
dynamic_addr = strtol(argv[3], NULL, 16); |
|
old_da = desc->dynamic_addr; |
|
|
|
ret = i3c_bus_setnewda(desc, dynamic_addr); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETNEWDA."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Dynamic address changed from 0x%02x to 0x%02x", old_da, |
|
desc->dynamic_addr); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getbcr <device> <target> */ |
|
static int cmd_i3c_ccc_getbcr(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_bus_getbcr(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETBCR."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: BCR: 0x%02x", desc->bcr); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getdcr <device> <target> */ |
|
static int cmd_i3c_ccc_getdcr(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_bus_getdcr(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETDCR."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: DCR: 0x%02x", desc->dcr); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getpid <device> <target> */ |
|
static int cmd_i3c_ccc_getpid(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_bus_getpid(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETPID."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: PID: 0x%012llx", desc->pid); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getmrl <device> <target> */ |
|
static int cmd_i3c_ccc_getmrl(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_bus_getmrl(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETMRL."); |
|
return ret; |
|
} |
|
|
|
if (desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) { |
|
shell_print(sh, "I3C: MRL: 0x%04x; IBI Length:0x%02x", desc->data_length.mrl, |
|
desc->data_length.max_ibi); |
|
} else { |
|
shell_print(sh, "I3C: MRL: 0x%04x", desc->data_length.mrl); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getmwl <device> <target> */ |
|
static int cmd_i3c_ccc_getmwl(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_bus_getmwl(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETMWL."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: MWL: 0x%04x", desc->data_length.mwl); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setmrl <device> <target> <max read length> [<max ibi length>] */ |
|
static int cmd_i3c_ccc_setmrl(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
uint16_t mrl; |
|
uint8_t ibi_len = 0; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
/* IBI length is required if the ibi payload bit is set */ |
|
if ((desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) && (argc < 5)) { |
|
shell_error(sh, "I3C: Missing IBI length."); |
|
return -EINVAL; |
|
} |
|
|
|
mrl = strtol(argv[3], NULL, 16); |
|
if (argc > 4) { |
|
ibi_len = strtol(argv[4], NULL, 16); |
|
} |
|
|
|
ret = i3c_bus_setmrl(desc, mrl, ibi_len); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETMRL."); |
|
} else { |
|
if (desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) { |
|
shell_print(sh, "I3C: MRL: 0x%04x; IBI Length:0x%02x", mrl, ibi_len); |
|
} else { |
|
shell_print(sh, "I3C: MRL: 0x%04x", mrl); |
|
} |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setmwl <device> <target> <max write length> */ |
|
static int cmd_i3c_ccc_setmwl(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
uint16_t mwl; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
mwl = strtol(argv[3], NULL, 16); |
|
|
|
ret = i3c_bus_setmwl(desc, mwl); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETMWL."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: SETMWL: 0x%04x", mwl); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setmrl_bc <device> <max read length> [<max ibi length>] */ |
|
static int cmd_i3c_ccc_setmrl_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
uint16_t mrl; |
|
uint8_t ibi_len = 0; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
mrl = strtol(argv[2], NULL, 16); |
|
if (argc > 3) { |
|
ibi_len = strtol(argv[3], NULL, 16); |
|
} |
|
|
|
ret = i3c_bus_setmrl_all(dev, mrl, ibi_len, argc > 3); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETMRL BC."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: SETMRL BC Sent"); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setmwl_bc <device> <max write length> */ |
|
static int cmd_i3c_ccc_setmwl_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
uint16_t mwl; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
mwl = strtol(argv[2], NULL, 16); |
|
|
|
ret = i3c_bus_setmwl_all(dev, mwl); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETMWL BC."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: SETMWL BC Sent"); |
|
|
|
return ret; |
|
} |
|
#ifdef CONFIG_I3C_TARGET |
|
/* i3c ccc deftgts <device> */ |
|
static int cmd_i3c_ccc_deftgts(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
if (!i3c_bus_has_sec_controller(dev)) { |
|
shell_error(sh, "I3C: No secondary controller on the bus"); |
|
return -ENXIO; |
|
} |
|
|
|
ret = i3c_bus_deftgts(dev); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC DEFTGTS."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: DEFTGTS sent"); |
|
|
|
return ret; |
|
} |
|
#endif /* CONFIG_I3C_TARGET */ |
|
/* i3c ccc enttm <device> <defining byte> */ |
|
static int cmd_i3c_ccc_enttm(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
enum i3c_ccc_enttm_defbyte defbyte; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
defbyte = strtol(argv[2], NULL, 16); |
|
|
|
ret = i3c_ccc_do_enttm(dev, defbyte); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTTM."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
#ifdef CONFIG_I3C_TARGET |
|
/* i3c ccc getacccr <device> <target> */ |
|
static int cmd_i3c_ccc_getacccr(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
if (!i3c_device_is_controller_capable(desc)) { |
|
shell_error(sh, "I3C: Not a Controller Capable Device"); |
|
return -EINVAL; |
|
} |
|
|
|
ret = i3c_bus_getacccr(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETACCCR."); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Controller Handoff successful"); |
|
|
|
return ret; |
|
} |
|
#endif /* CONFIG_I3C_TARGET */ |
|
/* i3c ccc rstact_bc <device> <defining byte> */ |
|
static int cmd_i3c_ccc_rstact_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
enum i3c_ccc_rstact_defining_byte action; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
action = strtol(argv[2], NULL, 16); |
|
|
|
ret = i3c_ccc_do_rstact_all(dev, action); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC RSTACT BC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc rstact <device> <target> <"set"/"get"> <defining byte> */ |
|
static int cmd_i3c_ccc_rstact(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
enum i3c_ccc_rstact_defining_byte action; |
|
int ret; |
|
uint8_t data; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
action = strtol(argv[4], NULL, 16); |
|
|
|
if (strcmp(argv[3], "get") == 0) { |
|
ret = i3c_ccc_do_rstact_fmt3(desc, action, &data); |
|
} else if (strcmp(argv[3], "set") == 0) { |
|
ret = i3c_ccc_do_rstact_fmt2(desc, action); |
|
} else { |
|
shell_error(sh, "I3C: invalid parameter"); |
|
return -EINVAL; |
|
} |
|
|
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC RSTACT."); |
|
return ret; |
|
} |
|
|
|
if (action >= 0x80) { |
|
shell_print(sh, "RSTACT Returned Data: 0x%02x", data); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc enec_bc <device> <defining byte> */ |
|
static int cmd_i3c_ccc_enec_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_ccc_events events; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
events.events = strtol(argv[2], NULL, 16); |
|
|
|
ret = i3c_ccc_do_events_all_set(dev, true, &events); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENEC BC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc disec_bc <device> <defining byte> */ |
|
static int cmd_i3c_ccc_disec_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_ccc_events events; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
events.events = strtol(argv[2], NULL, 16); |
|
|
|
ret = i3c_ccc_do_events_all_set(dev, false, &events); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC DISEC BC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc enec <device> <target> <defining byte> */ |
|
static int cmd_i3c_ccc_enec(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
struct i3c_ccc_events events; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
events.events = strtol(argv[3], NULL, 16); |
|
|
|
ret = i3c_ccc_do_events_set(desc, true, &events); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENEC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc disec <device> <target> <defining byte> */ |
|
static int cmd_i3c_ccc_disec(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
struct i3c_ccc_events events; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
events.events = strtol(argv[3], NULL, 16); |
|
|
|
ret = i3c_ccc_do_events_set(desc, false, &events); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC DISEC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas0_bc <device> */ |
|
static int cmd_i3c_ccc_entas0_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_driver_data *data; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
data = (struct i3c_driver_data *)dev->data; |
|
|
|
ret = i3c_ccc_do_entas0_all(dev); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS0 BC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas1_bc <device> */ |
|
static int cmd_i3c_ccc_entas1_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_driver_data *data; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
data = (struct i3c_driver_data *)dev->data; |
|
|
|
ret = i3c_ccc_do_entas1_all(dev); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS1 BC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas2_bc <device> */ |
|
static int cmd_i3c_ccc_entas2_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_driver_data *data; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
data = (struct i3c_driver_data *)dev->data; |
|
|
|
ret = i3c_ccc_do_entas2_all(dev); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS2 BC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas3_bc <device> */ |
|
static int cmd_i3c_ccc_entas3_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_driver_data *data; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
data = (struct i3c_driver_data *)dev->data; |
|
|
|
ret = i3c_ccc_do_entas3_all(dev); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS3 BC."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas0 <device> <target> */ |
|
static int cmd_i3c_ccc_entas0(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_ccc_do_entas0(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS0."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas1 <device> <target> */ |
|
static int cmd_i3c_ccc_entas1(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_ccc_do_entas1(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS1."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas2 <device> <target> */ |
|
static int cmd_i3c_ccc_entas2(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_ccc_do_entas2(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS2."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc entas3 <device> <target> */ |
|
static int cmd_i3c_ccc_entas3(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_ccc_do_entas3(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC ENTAS3."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getstatus <device> <target> [<defining byte>] */ |
|
static int cmd_i3c_ccc_getstatus(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
union i3c_ccc_getstatus status; |
|
enum i3c_ccc_getstatus_fmt fmt; |
|
enum i3c_ccc_getstatus_defbyte defbyte = GETSTATUS_FORMAT_2_INVALID; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
/* If there is a defining byte, then it is assumed to be Format 2*/ |
|
if (argc > 3) { |
|
fmt = GETSTATUS_FORMAT_2; |
|
defbyte = strtol(argv[3], NULL, 16); |
|
if (defbyte != GETSTATUS_FORMAT_2_TGTSTAT && defbyte != GETSTATUS_FORMAT_2_PRECR) { |
|
shell_error(sh, "Invalid defining byte."); |
|
return -EINVAL; |
|
} |
|
} else { |
|
fmt = GETSTATUS_FORMAT_1; |
|
} |
|
|
|
ret = i3c_ccc_do_getstatus(desc, &status, fmt, defbyte); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETSTATUS."); |
|
return ret; |
|
} |
|
|
|
if (fmt == GETSTATUS_FORMAT_2) { |
|
if (defbyte == GETSTATUS_FORMAT_2_TGTSTAT) { |
|
shell_print(sh, "TGTSTAT: 0x%04x", status.fmt2.tgtstat); |
|
} else if (defbyte == GETSTATUS_FORMAT_2_PRECR) { |
|
shell_print(sh, "PRECR: 0x%04x", status.fmt2.precr); |
|
} |
|
} else { |
|
shell_print(sh, "Status: 0x%04x", status.fmt1.status); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getcaps <device> <target> [<defining byte>] */ |
|
static int cmd_i3c_ccc_getcaps(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
union i3c_ccc_getcaps caps; |
|
enum i3c_ccc_getcaps_fmt fmt; |
|
enum i3c_ccc_getcaps_defbyte defbyte = GETCAPS_FORMAT_2_INVALID; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
/* If there is a defining byte, then it is assumed to be Format 2 */ |
|
if (argc > 3) { |
|
fmt = GETCAPS_FORMAT_2; |
|
defbyte = strtol(argv[3], NULL, 16); |
|
if (defbyte != GETCAPS_FORMAT_2_TGTCAPS && defbyte != GETCAPS_FORMAT_2_TESTPAT && |
|
defbyte != GETCAPS_FORMAT_2_CRCAPS && defbyte != GETCAPS_FORMAT_2_VTCAPS && |
|
defbyte != GETCAPS_FORMAT_2_DBGCAPS) { |
|
shell_error(sh, "Invalid defining byte."); |
|
return -EINVAL; |
|
} |
|
} else { |
|
fmt = GETCAPS_FORMAT_1; |
|
} |
|
|
|
ret = i3c_ccc_do_getcaps(desc, &caps, fmt, defbyte); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETCAPS."); |
|
return ret; |
|
} |
|
|
|
if (fmt == GETCAPS_FORMAT_2) { |
|
if (defbyte == GETCAPS_FORMAT_2_TGTCAPS) { |
|
shell_print(sh, "TGTCAPS: 0x%02x; 0x%02x; 0x%02x; 0x%02x", |
|
caps.fmt2.tgtcaps[0], caps.fmt2.tgtcaps[1], |
|
caps.fmt2.tgtcaps[2], caps.fmt2.tgtcaps[3]); |
|
} else if (defbyte == GETCAPS_FORMAT_2_TESTPAT) { |
|
shell_print(sh, "TESTPAT: 0x%08x", caps.fmt2.testpat); |
|
} else if (defbyte == GETCAPS_FORMAT_2_CRCAPS) { |
|
shell_print(sh, "CRCAPS: 0x%02x; 0x%02x", caps.fmt2.crcaps[0], |
|
caps.fmt2.crcaps[1]); |
|
memcpy(&desc->crcaps, &caps, sizeof(desc->crcaps)); |
|
} else if (defbyte == GETCAPS_FORMAT_2_VTCAPS) { |
|
shell_print(sh, "VTCAPS: 0x%02x; 0x%02x", caps.fmt2.vtcaps[0], |
|
caps.fmt2.vtcaps[1]); |
|
} |
|
} else { |
|
shell_print(sh, "GETCAPS: 0x%02x; 0x%02x; 0x%02x; 0x%02x", caps.fmt1.getcaps[0], |
|
caps.fmt1.getcaps[1], caps.fmt1.getcaps[2], caps.fmt1.getcaps[3]); |
|
memcpy(&desc->getcaps, &caps, sizeof(desc->getcaps)); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getvendor <device> <target> <id> [<defining byte>] */ |
|
static int cmd_i3c_ccc_getvendor(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
uint8_t buf[MAX_I3C_BYTES] = {0}; |
|
uint8_t defbyte; |
|
size_t num_xfer; |
|
uint8_t id; |
|
int err = 0; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
tdev = shell_device_get_binding(argv[ARGV_TDEV]); |
|
if (!tdev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); |
|
return -ENODEV; |
|
} |
|
desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); |
|
if (!desc) { |
|
shell_error(sh, "I3C: Device %s not attached to bus.", tdev->name); |
|
return -ENODEV; |
|
} |
|
|
|
id = (uint8_t)shell_strtoul(argv[3], 0, &err); |
|
if (err != 0) { |
|
shell_error(sh, "I3C: Invalid ID."); |
|
return -EINVAL; |
|
} |
|
|
|
if (argc > 4) { |
|
defbyte = strtol(argv[4], NULL, 16); |
|
ret = i3c_ccc_do_getvendor_defbyte(desc, id, defbyte, buf, MAX_I3C_BYTES, |
|
&num_xfer); |
|
} else { |
|
ret = i3c_ccc_do_getvendor(desc, id, buf, MAX_I3C_BYTES, &num_xfer); |
|
} |
|
|
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC VENDOR."); |
|
return ret; |
|
} |
|
|
|
shell_hexdump(sh, buf, num_xfer); |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setvendor <device> <target> <id> [<bytes>] */ |
|
static int cmd_i3c_ccc_setvendor(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
struct i3c_driver_data *data; |
|
uint8_t buf[MAX_I3C_BYTES] = {0}; |
|
uint8_t data_length; |
|
uint8_t id; |
|
int err = 0; |
|
int ret; |
|
int i; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
tdev = shell_device_get_binding(argv[ARGV_TDEV]); |
|
if (!tdev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); |
|
return -ENODEV; |
|
} |
|
desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); |
|
if (!desc) { |
|
shell_error(sh, "I3C: Device %s not attached to bus.", tdev->name); |
|
return -ENODEV; |
|
} |
|
data = (struct i3c_driver_data *)dev->data; |
|
|
|
id = (uint8_t)shell_strtoul(argv[3], 0, &err); |
|
if (err != 0) { |
|
shell_error(sh, "I3C: Invalid ID."); |
|
return -EINVAL; |
|
} |
|
|
|
data_length = argc - 4; |
|
for (i = 0; i < data_length; i++) { |
|
buf[i] = (uint8_t)strtol(argv[4 + i], NULL, 16); |
|
} |
|
|
|
ret = i3c_ccc_do_setvendor(desc, id, buf, data_length); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC VENDOR."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setvendor_bc <device> <id> [<bytes>] */ |
|
static int cmd_i3c_ccc_setvendor_bc(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
uint8_t buf[MAX_I3C_BYTES] = {0}; |
|
uint8_t data_length; |
|
uint8_t id; |
|
int err = 0; |
|
int ret; |
|
int i; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
id = (uint8_t)shell_strtoul(argv[2], 0, &err); |
|
if (err != 0) { |
|
shell_error(sh, "I3C: Invalid ID."); |
|
return -EINVAL; |
|
} |
|
|
|
data_length = argc - 3; |
|
for (i = 0; i < data_length; i++) { |
|
buf[i] = (uint8_t)strtol(argv[3 + i], NULL, 16); |
|
} |
|
|
|
ret = i3c_ccc_do_setvendor_all(dev, id, buf, data_length); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC VENDOR."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc setbuscon <device> <context> [<optional bytes>] */ |
|
static int cmd_i3c_ccc_setbuscon(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
uint8_t buf[MAX_I3C_BYTES] = {0}; |
|
uint8_t data_length; |
|
int ret; |
|
int i; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
data_length = argc - 2; |
|
for (i = 0; i < data_length; i++) { |
|
buf[i] = (uint8_t)strtol(argv[2 + i], NULL, 16); |
|
} |
|
|
|
ret = i3c_ccc_do_setbuscon(dev, buf, data_length); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC SETBUSCON."); |
|
return ret; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* i3c ccc getmxds <device> <target> [<defining byte>] */ |
|
static int cmd_i3c_ccc_getmxds(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
union i3c_ccc_getmxds mxds; |
|
enum i3c_ccc_getmxds_fmt fmt; |
|
enum i3c_ccc_getmxds_defbyte defbyte = GETMXDS_FORMAT_3_INVALID; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
if (!(desc->bcr & I3C_BCR_MAX_DATA_SPEED_LIMIT)) { |
|
shell_error(sh, "I3C: Device %s does not support max data speed limit", |
|
desc->dev->name); |
|
return -ENOTSUP; |
|
} |
|
|
|
/* If there is a defining byte, then it is assumed to be Format 3 */ |
|
if (argc > 3) { |
|
fmt = GETMXDS_FORMAT_3; |
|
defbyte = strtol(argv[3], NULL, 16); |
|
if (defbyte != GETMXDS_FORMAT_3_CRHDLY && defbyte != GETMXDS_FORMAT_3_WRRDTURN) { |
|
shell_error(sh, "Invalid defining byte."); |
|
return -EINVAL; |
|
} |
|
} else { |
|
fmt = GETMXDS_FORMAT_2; |
|
} |
|
|
|
ret = i3c_ccc_do_getmxds(desc, &mxds, fmt, defbyte); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to send CCC GETMXDS."); |
|
return ret; |
|
} |
|
|
|
if (fmt == GETMXDS_FORMAT_3) { |
|
if (defbyte == GETMXDS_FORMAT_3_WRRDTURN) { |
|
shell_print(sh, "WRRDTURN: maxwr 0x%02x; maxrd 0x%02x; maxrdturn 0x%06x", |
|
mxds.fmt3.wrrdturn[0], mxds.fmt3.wrrdturn[1], |
|
sys_get_le24(&mxds.fmt3.wrrdturn[2])); |
|
/* Update values in descriptor */ |
|
desc->data_speed.maxwr = mxds.fmt3.wrrdturn[0]; |
|
desc->data_speed.maxrd = mxds.fmt3.wrrdturn[1]; |
|
desc->data_speed.max_read_turnaround = sys_get_le24(&mxds.fmt3.wrrdturn[2]); |
|
} else if (defbyte == GETMXDS_FORMAT_3_CRHDLY) { |
|
shell_print(sh, "CRHDLY1: 0x%02x", mxds.fmt3.crhdly1); |
|
desc->crhdly1 = mxds.fmt3.crhdly1; |
|
} |
|
} else { |
|
shell_print(sh, "GETMXDS: maxwr 0x%02x; maxrd 0x%02x; maxrdturn 0x%06x", |
|
mxds.fmt2.maxwr, mxds.fmt2.maxrd, sys_get_le24(mxds.fmt2.maxrdturn)); |
|
/* Update values in descriptor */ |
|
desc->data_speed.maxwr = mxds.fmt2.maxwr; |
|
desc->data_speed.maxrd = mxds.fmt2.maxrd; |
|
desc->data_speed.max_read_turnaround = sys_get_le24(mxds.fmt2.maxrdturn); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int cmd_i3c_attach(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
tdev = shell_device_get_binding(argv[ARGV_TDEV]); |
|
if (!tdev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); |
|
return -ENODEV; |
|
} |
|
desc = get_i3c_list_desc_from_dev_name(dev, tdev->name); |
|
if (!desc) { |
|
shell_error(sh, "I3C: Device %s not attached to bus.", tdev->name); |
|
return -ENODEV; |
|
} |
|
|
|
ret = i3c_attach_i3c_device(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to attach device %s.", tdev->name); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int cmd_i3c_reattach(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
uint8_t old_dyn_addr = 0; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
if (argc > 2) { |
|
old_dyn_addr = strtol(argv[2], NULL, 16); |
|
} |
|
|
|
ret = i3c_reattach_i3c_device(desc, old_dyn_addr); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to reattach device %s.", tdev->name); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int cmd_i3c_detach(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_detach_i3c_device(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to detach device %s.", tdev->name); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int cmd_i3c_i2c_attach(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_i2c_device_desc *desc; |
|
uint16_t addr = 0; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
addr = strtol(argv[2], NULL, 16); |
|
desc = i3c_dev_list_i2c_addr_find(dev, addr); |
|
if (!desc) { |
|
shell_error(sh, "I3C: I2C addr 0x%02x not listed with the bus.", addr); |
|
return -ENODEV; |
|
} |
|
|
|
ret = i3c_attach_i2c_device(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to attach I2C addr 0x%02x.", addr); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int cmd_i3c_i2c_detach(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_i2c_device_desc *desc; |
|
uint16_t addr = 0; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
addr = strtol(argv[2], NULL, 16); |
|
desc = i3c_dev_list_i2c_addr_find(dev, addr); |
|
if (!desc) { |
|
shell_error(sh, "I3C: I2C addr 0x%02x not listed with the bus.", addr); |
|
return -ENODEV; |
|
} |
|
|
|
ret = i3c_detach_i2c_device(desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to detach I2C addr 0x%02x.", addr); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/* |
|
* This is a workaround command to perform an I2C Scan which is not as |
|
* simple on an I3C bus as it is with the I2C Shell. |
|
* |
|
* This will print "I3" if an address is already assigned for an I3C |
|
* device and it will print "I2" if an address is already assigned for |
|
* an I2C device. It will print RS, if the address is reserved according |
|
* to section 5.1.2.2.5 I3C Target Address Restrictions in I3C v1.1.1. |
|
* |
|
* This sends I2C messages without any data (i.e. stop condition after |
|
* sending just the address). If there is an ACK for the address, it |
|
* is assumed there is a device present. |
|
* |
|
* WARNING: As there is no standard I2C detection command, this code |
|
* uses arbitrary SMBus commands (namely SMBus quick write and SMBus |
|
* receive byte) to probe for devices. This operation can confuse |
|
* your I2C bus, cause data loss, and is known to corrupt the Atmel |
|
* AT24RF08 EEPROM found on many IBM Thinkpad laptops. |
|
* |
|
* https://manpages.debian.org/buster/i2c-tools/i2cdetect.8.en.html |
|
*/ |
|
/* i3c i2c_scan <device> */ |
|
static int cmd_i3c_i2c_scan(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_driver_data *data; |
|
enum i3c_addr_slot_status slot; |
|
uint8_t cnt = 0, first = 0x04, last = 0x77; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
|
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
data = (struct i3c_driver_data *)dev->data; |
|
|
|
shell_print(sh, " 0 1 2 3 4 5 6 7 8 9 a b c d e f"); |
|
for (uint8_t i = 0; i <= last; i += 16) { |
|
shell_fprintf_normal(sh, "%02x: ", i); |
|
for (uint8_t j = 0; j < 16; j++) { |
|
if (i + j < first || i + j > last) { |
|
shell_fprintf_normal(sh, " "); |
|
continue; |
|
} |
|
|
|
slot = i3c_addr_slots_status(&data->attached_dev.addr_slots, i + j); |
|
if (slot == I3C_ADDR_SLOT_STATUS_FREE) { |
|
struct i2c_msg msgs[1]; |
|
uint8_t dst; |
|
int ret; |
|
struct i3c_i2c_device_desc desc = { |
|
.bus = dev, |
|
.addr = i + j, |
|
.lvr = 0x00, |
|
}; |
|
|
|
ret = i3c_attach_i2c_device(&desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to attach I2C addr 0x%02x.", |
|
desc.addr); |
|
} |
|
|
|
/* Send the address to read from */ |
|
msgs[0].buf = &dst; |
|
msgs[0].len = 0U; |
|
msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP; |
|
if (i2c_transfer(dev, &msgs[0], 1, i + j) == 0) { |
|
shell_fprintf_normal(sh, "%02x ", i + j); |
|
++cnt; |
|
} else { |
|
shell_fprintf_normal(sh, "-- "); |
|
} |
|
|
|
ret = i3c_detach_i2c_device(&desc); |
|
if (ret < 0) { |
|
shell_error(sh, "I3C: unable to detach I2C addr 0x%02x.", |
|
desc.addr); |
|
} |
|
} else if (slot == I3C_ADDR_SLOT_STATUS_I3C_DEV) { |
|
shell_fprintf_normal(sh, "I3 "); |
|
} else if (slot == I3C_ADDR_SLOT_STATUS_I2C_DEV) { |
|
shell_fprintf_normal(sh, "I2 "); |
|
} else if (slot == I3C_ADDR_SLOT_STATUS_RSVD) { |
|
shell_fprintf_normal(sh, "RS "); |
|
} else { |
|
shell_fprintf_normal(sh, "-- "); |
|
} |
|
} |
|
shell_print(sh, ""); |
|
} |
|
|
|
shell_print(sh, "%u additional devices found on %s", cnt, argv[ARGV_DEV]); |
|
|
|
return 0; |
|
} |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
#ifdef CONFIG_I3C_USE_IBI |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
/* i3c ibi hj_response <device> <"ack"/"nack"> */ |
|
static int cmd_i3c_ibi_hj_response(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
bool ack; |
|
int ret; |
|
|
|
dev = device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
if (strcmp(argv[2], "ack") == 0) { |
|
ack = true; |
|
} else if (strcmp(argv[2], "nack") == 0) { |
|
ack = false; |
|
} else { |
|
shell_error(sh, "I3C: invalid parameter"); |
|
return -EINVAL; |
|
} |
|
|
|
ret = i3c_ibi_hj_response(dev, ack); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Unable to set IBI HJ Response"); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Set IBI HJ Response"); |
|
|
|
return 0; |
|
} |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
#ifdef CONFIG_I3C_TARGET |
|
/* i3c ibi hj <device> */ |
|
static int cmd_i3c_ibi_hj(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_ibi request; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
request.ibi_type = I3C_IBI_HOTJOIN; |
|
ret = i3c_ibi_raise(dev, &request); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Unable to issue IBI HJ"); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Issued IBI HJ"); |
|
|
|
return 0; |
|
} |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
/* i3c ibi cr <device> */ |
|
static int cmd_i3c_ibi_cr(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_ibi request; |
|
int ret; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
request.ibi_type = I3C_IBI_CONTROLLER_ROLE_REQUEST; |
|
ret = i3c_ibi_raise(dev, &request); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Unable to issue IBI CR"); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Issued IBI CR"); |
|
|
|
return 0; |
|
} |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
/* i3c ibi tir <device> [<bytes>]*/ |
|
static int cmd_i3c_ibi_tir(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev; |
|
struct i3c_ibi request; |
|
uint16_t data_length; |
|
uint8_t buf[MAX_I3C_BYTES]; |
|
int ret; |
|
uint8_t i; |
|
|
|
dev = shell_device_get_binding(argv[ARGV_DEV]); |
|
if (!dev) { |
|
shell_error(sh, "I3C: Device driver %s not found.", argv[ARGV_DEV]); |
|
return -ENODEV; |
|
} |
|
|
|
data_length = argc - 2; |
|
for (i = 0; i < data_length; i++) { |
|
buf[i] = (uint8_t)strtol(argv[2 + i], NULL, 16); |
|
} |
|
|
|
request.ibi_type = I3C_IBI_TARGET_INTR; |
|
request.payload = buf; |
|
request.payload_len = data_length; |
|
|
|
ret = i3c_ibi_raise(dev, &request); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Unable to issue IBI TIR"); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Issued IBI TIR"); |
|
|
|
return 0; |
|
} |
|
#endif /* CONFIG_I3C_TARGET */ |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
/* i3c ibi enable <device> <target> */ |
|
static int cmd_i3c_ibi_enable(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_ibi_enable(desc); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Unable to enable IBI"); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Enabled IBI"); |
|
|
|
return 0; |
|
} |
|
|
|
/* i3c ibi disable <device> <target> */ |
|
static int cmd_i3c_ibi_disable(const struct shell *sh, size_t argc, char **argv) |
|
{ |
|
const struct device *dev, *tdev; |
|
struct i3c_device_desc *desc; |
|
int ret; |
|
|
|
ret = i3c_parse_args(sh, argv, &dev, &tdev, &desc); |
|
if (ret != 0) { |
|
return ret; |
|
} |
|
|
|
ret = i3c_ibi_disable(desc); |
|
if (ret != 0) { |
|
shell_error(sh, "I3C: Unable to disable IBI"); |
|
return ret; |
|
} |
|
|
|
shell_print(sh, "I3C: Disabled IBI"); |
|
|
|
return 0; |
|
} |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
#endif /* CONFIG_I3C_USE_IBI */ |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
static void i3c_device_list_target_name_get(size_t idx, struct shell_static_entry *entry) |
|
{ |
|
if (idx < ARRAY_SIZE(i3c_list)) { |
|
entry->syntax = i3c_list[idx].dev->name; |
|
entry->handler = NULL; |
|
entry->help = NULL; |
|
entry->subcmd = i3c_list[idx].i3c_list_dev_subcmd; |
|
} else { |
|
entry->syntax = NULL; |
|
} |
|
} |
|
|
|
SHELL_DYNAMIC_CMD_CREATE(dsub_i3c_device_list_name, i3c_device_list_target_name_get); |
|
|
|
static void i3c_device_attached_target_name_get(size_t idx, struct shell_static_entry *entry) |
|
{ |
|
if (idx < ARRAY_SIZE(i3c_list)) { |
|
entry->syntax = i3c_list[idx].dev->name; |
|
entry->handler = NULL; |
|
entry->help = NULL; |
|
entry->subcmd = i3c_list[idx].i3c_attached_dev_subcmd; |
|
} else { |
|
entry->syntax = NULL; |
|
} |
|
} |
|
|
|
SHELL_DYNAMIC_CMD_CREATE(dsub_i3c_device_attached_name, i3c_device_attached_target_name_get); |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
|
|
static void i3c_device_name_get(size_t idx, struct shell_static_entry *entry) |
|
{ |
|
if (idx < ARRAY_SIZE(i3c_list)) { |
|
entry->syntax = i3c_list[idx].dev->name; |
|
entry->handler = NULL; |
|
entry->help = NULL; |
|
entry->subcmd = NULL; |
|
} else { |
|
entry->syntax = NULL; |
|
} |
|
} |
|
|
|
SHELL_DYNAMIC_CMD_CREATE(dsub_i3c_device_name, i3c_device_name_get); |
|
|
|
#ifdef CONFIG_I3C_USE_IBI |
|
/* L2 I3C IBI Shell Commands*/ |
|
SHELL_STATIC_SUBCMD_SET_CREATE( |
|
sub_i3c_ibi_cmds, |
|
#ifdef CONFIG_I3C_TARGET |
|
SHELL_CMD_ARG(hj, &dsub_i3c_device_name, |
|
"Send IBI HJ\n" |
|
"Usage: ibi hj <device>", |
|
cmd_i3c_ibi_hj, 2, 0), |
|
SHELL_CMD_ARG(tir, &dsub_i3c_device_name, |
|
"Send IBI TIR\n" |
|
"Usage: ibi tir <device> [<byte1>, ...]", |
|
cmd_i3c_ibi_tir, 2, MAX_I3C_BYTES), |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
SHELL_CMD_ARG(cr, &dsub_i3c_device_name, |
|
"Send IBI CR\n" |
|
"Usage: ibi cr <device>", |
|
cmd_i3c_ibi_cr, 2, 0), |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
#endif /* CONFIG_I3C_TARGET */ |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
SHELL_CMD_ARG(hj_response, &dsub_i3c_device_name, |
|
"Set IBI HJ Response\n" |
|
"Usage: ibi hj_response <device> <\"ack\"/\"nack\">", |
|
cmd_i3c_ibi_hj_response, 3, 0), |
|
SHELL_CMD_ARG(enable, &dsub_i3c_device_attached_name, |
|
"Enable receiving IBI from target\n" |
|
"Usage: ibi enable <device> <target>", |
|
cmd_i3c_ibi_enable, 3, 0), |
|
SHELL_CMD_ARG(disable, &dsub_i3c_device_attached_name, |
|
"Disable receiving IBI from target\n" |
|
"Usage: ibi disable <device> <target>", |
|
cmd_i3c_ibi_disable, 3, 0), |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
SHELL_SUBCMD_SET_END /* Array terminated. */ |
|
); |
|
#endif |
|
|
|
#ifdef CONFIG_I3C_CONTROLLER |
|
/* L3 I3C HDR DDR Shell Commands*/ |
|
SHELL_STATIC_SUBCMD_SET_CREATE( |
|
sub_i3c_hdr_ddr_cmds, |
|
SHELL_CMD_ARG(write, &dsub_i3c_device_attached_name, |
|
"Send HDR DDR Write\n" |
|
"Usage: hdr ddr write <device> <target> <7b cmd> [<byte1>, ...]", |
|
cmd_i3c_hdr_ddr_write, 4, MAX_I3C_BYTES), |
|
SHELL_CMD_ARG(read, &dsub_i3c_device_attached_name, |
|
"Send HDR DDR Read\n" |
|
"Usage: hdr ddr read <device> <target> <7b cmd> <bytes>", |
|
cmd_i3c_hdr_ddr_read, 5, 0), |
|
SHELL_SUBCMD_SET_END /* Array terminated. */ |
|
); |
|
|
|
/* L2 I3C HDR Shell Commands*/ |
|
SHELL_STATIC_SUBCMD_SET_CREATE( |
|
sub_i3c_hdr_cmds, |
|
SHELL_CMD_ARG(ddr, &sub_i3c_hdr_ddr_cmds, |
|
"Send HDR DDR\n" |
|
"Usage: hdr ddr <sub cmd>", |
|
NULL, 2, 0), |
|
SHELL_SUBCMD_SET_END /* Array terminated. */ |
|
); |
|
|
|
/* L2 I3C CCC Shell Commands*/ |
|
SHELL_STATIC_SUBCMD_SET_CREATE( |
|
sub_i3c_ccc_cmds, |
|
SHELL_CMD_ARG(rstdaa_dc, &dsub_i3c_device_attached_name, |
|
"Send CCC RSTDAA\n" |
|
"Usage: ccc rstdaa_dc <device> <target>", |
|
cmd_i3c_ccc_rstdaa_dc, 3, 0), |
|
SHELL_CMD_ARG(rstdaa, &dsub_i3c_device_name, |
|
"Send CCC RSTDAA\n" |
|
"Usage: ccc rstdaa <device>", |
|
cmd_i3c_ccc_rstdaa, 2, 0), |
|
SHELL_CMD_ARG(entdaa, &dsub_i3c_device_name, |
|
"Send CCC ENTDAA\n" |
|
"Usage: ccc entdaa <device>", |
|
cmd_i3c_ccc_entdaa, 2, 0), |
|
SHELL_CMD_ARG(setaasa, &dsub_i3c_device_name, |
|
"Send CCC SETAASA\n" |
|
"Usage: ccc setaasa <device>", |
|
cmd_i3c_ccc_setaasa, 2, 0), |
|
SHELL_CMD_ARG(setdasa, &dsub_i3c_device_attached_name, |
|
"Send CCC SETDASA\n" |
|
"Usage: ccc setdasa <device> <target> <dynamic address>", |
|
cmd_i3c_ccc_setdasa, 4, 0), |
|
SHELL_CMD_ARG(setnewda, &dsub_i3c_device_attached_name, |
|
"Send CCC SETNEWDA\n" |
|
"Usage: ccc setnewda <device> <target> <dynamic address>", |
|
cmd_i3c_ccc_setnewda, 4, 0), |
|
SHELL_CMD_ARG(getbcr, &dsub_i3c_device_attached_name, |
|
"Send CCC GETBCR\n" |
|
"Usage: ccc getbcr <device> <target>", |
|
cmd_i3c_ccc_getbcr, 3, 0), |
|
SHELL_CMD_ARG(getdcr, &dsub_i3c_device_attached_name, |
|
"Send CCC GETDCR\n" |
|
"Usage: ccc getdcr <device> <target>", |
|
cmd_i3c_ccc_getdcr, 3, 0), |
|
SHELL_CMD_ARG(getpid, &dsub_i3c_device_attached_name, |
|
"Send CCC GETPID\n" |
|
"Usage: ccc getpid <device> <target>", |
|
cmd_i3c_ccc_getpid, 3, 0), |
|
SHELL_CMD_ARG(getmrl, &dsub_i3c_device_attached_name, |
|
"Send CCC GETMRL\n" |
|
"Usage: ccc getmrl <device> <target>", |
|
cmd_i3c_ccc_getmrl, 3, 0), |
|
SHELL_CMD_ARG(getmwl, &dsub_i3c_device_attached_name, |
|
"Send CCC GETMWL\n" |
|
"Usage: ccc getmwl <device> <target>", |
|
cmd_i3c_ccc_getmwl, 3, 0), |
|
SHELL_CMD_ARG(setmrl, &dsub_i3c_device_attached_name, |
|
"Send CCC SETMRL\n" |
|
"Usage: ccc setmrl <device> <target> <max read length> [<max ibi length>]", |
|
cmd_i3c_ccc_setmrl, 4, 1), |
|
SHELL_CMD_ARG(setmwl, &dsub_i3c_device_attached_name, |
|
"Send CCC SETMWL\n" |
|
"Usage: ccc setmwl <device> <target> <max write length>", |
|
cmd_i3c_ccc_setmwl, 4, 0), |
|
SHELL_CMD_ARG(setmrl_bc, &dsub_i3c_device_name, |
|
"Send CCC SETMRL BC\n" |
|
"Usage: ccc setmrl_bc <device> <max read length> [<max ibi length>]", |
|
cmd_i3c_ccc_setmrl_bc, 3, 1), |
|
SHELL_CMD_ARG(setmwl_bc, &dsub_i3c_device_name, |
|
"Send CCC SETMWL BC\n" |
|
"Usage: ccc setmwl_bc <device> <max write length>", |
|
cmd_i3c_ccc_setmwl_bc, 3, 0), |
|
#ifdef CONFIG_I3C_TARGET |
|
SHELL_CMD_ARG(deftgts, &dsub_i3c_device_name, |
|
"Send CCC DEFTGTS\n" |
|
"Usage: ccc deftgts <device>", |
|
cmd_i3c_ccc_deftgts, 2, 0), |
|
#endif |
|
SHELL_CMD_ARG(enttm, &dsub_i3c_device_name, |
|
"Send CCC ENTTM\n" |
|
"Usage: ccc enttm <device> <defining byte>", |
|
cmd_i3c_ccc_enttm, 3, 0), |
|
SHELL_CMD_ARG(rstact, &dsub_i3c_device_attached_name, |
|
"Send CCC RSTACT\n" |
|
"Usage: ccc rstact <device> <target> <\"set\"/\"get\"> <defining byte>", |
|
cmd_i3c_ccc_rstact, 5, 0), |
|
#ifdef CONFIG_I3C_TARGET |
|
SHELL_CMD_ARG(getacccr, &dsub_i3c_device_attached_name, |
|
"Send CCC GETACCCR\n" |
|
"Usage: ccc getacccr <device> <target>", |
|
cmd_i3c_ccc_getacccr, 3, 0), |
|
#endif /* CONFIG_I3C_TARGET */ |
|
SHELL_CMD_ARG(rstact_bc, &dsub_i3c_device_name, |
|
"Send CCC RSTACT BC\n" |
|
"Usage: ccc rstact_bc <device> <defining byte>", |
|
cmd_i3c_ccc_rstact_bc, 3, 0), |
|
SHELL_CMD_ARG(enec_bc, &dsub_i3c_device_name, |
|
"Send CCC ENEC BC\n" |
|
"Usage: ccc enec_bc <device> <defining byte>", |
|
cmd_i3c_ccc_enec_bc, 3, 0), |
|
SHELL_CMD_ARG(disec_bc, &dsub_i3c_device_name, |
|
"Send CCC DISEC BC\n" |
|
"Usage: ccc disec_bc <device> <defining byte>", |
|
cmd_i3c_ccc_disec_bc, 3, 0), |
|
SHELL_CMD_ARG(enec, &dsub_i3c_device_attached_name, |
|
"Send CCC ENEC\n" |
|
"Usage: ccc enec <device> <target> <defining byte>", |
|
cmd_i3c_ccc_enec, 4, 0), |
|
SHELL_CMD_ARG(disec, &dsub_i3c_device_attached_name, |
|
"Send CCC DISEC\n" |
|
"Usage: ccc disec <device> <target> <defining byte>", |
|
cmd_i3c_ccc_disec, 4, 0), |
|
SHELL_CMD_ARG(entas0_bc, &dsub_i3c_device_name, |
|
"Send CCC ENTAS0 BC\n" |
|
"Usage: ccc entas0 <device>", |
|
cmd_i3c_ccc_entas0_bc, 2, 0), |
|
SHELL_CMD_ARG(entas1_bc, &dsub_i3c_device_name, |
|
"Send CCC ENTAS1 BC\n" |
|
"Usage: ccc entas1 <device>", |
|
cmd_i3c_ccc_entas1_bc, 2, 0), |
|
SHELL_CMD_ARG(entas2_bc, &dsub_i3c_device_name, |
|
"Send CCC ENTAS2 BC\n" |
|
"Usage: ccc entas2 <device>", |
|
cmd_i3c_ccc_entas2_bc, 2, 0), |
|
SHELL_CMD_ARG(entas3_bc, &dsub_i3c_device_name, |
|
"Send CCC ENTAS3 BC\n" |
|
"Usage: ccc entas3 <device>", |
|
cmd_i3c_ccc_entas3_bc, 2, 0), |
|
SHELL_CMD_ARG(entas0, &dsub_i3c_device_attached_name, |
|
"Send CCC ENTAS0\n" |
|
"Usage: ccc entas0 <device> <target>", |
|
cmd_i3c_ccc_entas0, 3, 0), |
|
SHELL_CMD_ARG(entas1, &dsub_i3c_device_attached_name, |
|
"Send CCC ENTAS1\n" |
|
"Usage: ccc entas1 <device> <target>", |
|
cmd_i3c_ccc_entas1, 3, 0), |
|
SHELL_CMD_ARG(entas2, &dsub_i3c_device_attached_name, |
|
"Send CCC ENTAS2\n" |
|
"Usage: ccc entas2 <device> <target>", |
|
cmd_i3c_ccc_entas2, 3, 0), |
|
SHELL_CMD_ARG(entas3, &dsub_i3c_device_attached_name, |
|
"Send CCC ENTAS3\n" |
|
"Usage: ccc entas3 <device> <target>", |
|
cmd_i3c_ccc_entas3, 3, 0), |
|
SHELL_CMD_ARG(getstatus, &dsub_i3c_device_attached_name, |
|
"Send CCC GETSTATUS\n" |
|
"Usage: ccc getstatus <device> <target> [<defining byte>]", |
|
cmd_i3c_ccc_getstatus, 3, 1), |
|
SHELL_CMD_ARG(getcaps, &dsub_i3c_device_attached_name, |
|
"Send CCC GETCAPS\n" |
|
"Usage: ccc getcaps <device> <target> [<defining byte>]", |
|
cmd_i3c_ccc_getcaps, 3, 1), |
|
SHELL_CMD_ARG(getmxds, &dsub_i3c_device_attached_name, |
|
"Send CCC GETMXDS\n" |
|
"Usage: ccc getmxds <device> <target> [<defining byte>]", |
|
cmd_i3c_ccc_getmxds, 3, 1), |
|
SHELL_CMD_ARG(setbuscon, &dsub_i3c_device_name, |
|
"Send CCC SETBUSCON\n" |
|
"Usage: ccc setbuscon <device> <context> [<optional bytes>]", |
|
cmd_i3c_ccc_setbuscon, 3, MAX_I3C_BYTES - 1), |
|
SHELL_CMD_ARG(getvendor, &dsub_i3c_device_attached_name, |
|
"Send CCC GETVENDOR\n" |
|
"Usage: ccc getvendor <device> <target> <id> [<defining byte>]", |
|
cmd_i3c_ccc_getvendor, 4, 1), |
|
SHELL_CMD_ARG(setvendor, &dsub_i3c_device_attached_name, |
|
"Send CCC SETVENDOR\n" |
|
"Usage: ccc setvendor <device> <target> <id> [<bytes>]", |
|
cmd_i3c_ccc_setvendor, 4, MAX_I3C_BYTES), |
|
SHELL_CMD_ARG(setvendor_bc, &dsub_i3c_device_name, |
|
"Send CCC SETVENDOR BC\n" |
|
"Usage: ccc setvendor_bc <device> <id> [<bytes>]", |
|
cmd_i3c_ccc_setvendor_bc, 3, MAX_I3C_BYTES), |
|
SHELL_SUBCMD_SET_END /* Array terminated. */ |
|
); |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
|
|
/* L1 I3C Shell Commands*/ |
|
SHELL_STATIC_SUBCMD_SET_CREATE( |
|
sub_i3c_cmds, |
|
#ifdef CONFIG_I3C_CONTROLLER |
|
SHELL_CMD_ARG(info, &dsub_i3c_device_attached_name, |
|
"Get I3C device info\n" |
|
"Usage: info <device> [<target>]", |
|
cmd_i3c_info, 2, 1), |
|
SHELL_CMD_ARG(speed, &dsub_i3c_device_name, |
|
"Set I3C device speed\n" |
|
"Usage: speed <device> <speed>", |
|
cmd_i3c_speed, 3, 0), |
|
SHELL_CMD_ARG(recover, &dsub_i3c_device_name, |
|
"Recover I3C bus\n" |
|
"Usage: recover <device>", |
|
cmd_i3c_recover, 2, 0), |
|
SHELL_CMD_ARG(read, &dsub_i3c_device_attached_name, |
|
"Read bytes from an I3C device\n" |
|
"Usage: read <device> <target> <reg> [<bytes>]", |
|
cmd_i3c_read, 4, 1), |
|
SHELL_CMD_ARG(read_byte, &dsub_i3c_device_attached_name, |
|
"Read a byte from an I3C device\n" |
|
"Usage: read_byte <device> <target> <reg>", |
|
cmd_i3c_read_byte, 4, 0), |
|
SHELL_CMD_ARG(write, &dsub_i3c_device_attached_name, |
|
"Write bytes to an I3C device\n" |
|
"Usage: write <device> <target> <reg> [<byte1>, ...]", |
|
cmd_i3c_write, 4, MAX_I3C_BYTES), |
|
SHELL_CMD_ARG(write_byte, &dsub_i3c_device_attached_name, |
|
"Write a byte to an I3C device\n" |
|
"Usage: write_byte <device> <target> <reg> <value>", |
|
cmd_i3c_write_byte, 5, 0), |
|
SHELL_CMD_ARG(i3c_attach, &dsub_i3c_device_list_name, |
|
"Attach I3C device from the bus\n" |
|
"Usage: i3c_attach <device> <target>", |
|
cmd_i3c_attach, 3, 0), |
|
SHELL_CMD_ARG(i3c_reattach, &dsub_i3c_device_attached_name, |
|
"Reattach I3C device from the bus\n" |
|
"Usage: i3c_reattach <device> <target> [<old dynamic address>]", |
|
cmd_i3c_reattach, 3, 1), |
|
SHELL_CMD_ARG(i3c_detach, &dsub_i3c_device_attached_name, |
|
"Detach I3C device from the bus\n" |
|
"Usage: i3c_detach <device> <target>", |
|
cmd_i3c_detach, 3, 0), |
|
SHELL_CMD_ARG(i2c_attach, &dsub_i3c_device_name, |
|
"Attach I2C device from the bus\n" |
|
"Usage: i2c_attach <device> <addr>", |
|
cmd_i3c_i2c_attach, 3, 0), |
|
SHELL_CMD_ARG(i2c_detach, &dsub_i3c_device_name, |
|
"Detach I2C device from the bus\n" |
|
"Usage: i2c_detach <device> <addr>", |
|
cmd_i3c_i2c_detach, 3, 0), |
|
SHELL_CMD_ARG(i2c_scan, &dsub_i3c_device_name, |
|
"Scan I2C devices\n" |
|
"Usage: i2c_scan <device>", |
|
cmd_i3c_i2c_scan, 2, 0), |
|
SHELL_CMD_ARG(ccc, &sub_i3c_ccc_cmds, |
|
"Send I3C CCC\n" |
|
"Usage: ccc <sub cmd>", |
|
NULL, 3, 0), |
|
SHELL_CMD_ARG(hdr, &sub_i3c_hdr_cmds, |
|
"Send I3C HDR\n" |
|
"Usage: hdr <sub cmd>", |
|
NULL, 3, 0), |
|
#endif /* CONFIG_I3C_CONTROLLER */ |
|
#ifdef CONFIG_I3C_USE_IBI |
|
SHELL_CMD_ARG(ibi, &sub_i3c_ibi_cmds, |
|
"Send I3C IBI\n" |
|
"Usage: ibi <sub cmd>", |
|
NULL, 3, 0), |
|
#endif /* CONFIG_I3C_USE_IBI */ |
|
SHELL_SUBCMD_SET_END /* Array terminated. */ |
|
); |
|
|
|
SHELL_CMD_REGISTER(i3c, &sub_i3c_cmds, "I3C commands", NULL);
|
|
|