| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * Copyright (c) 2020 Wind River Systems, Inc. | |
| * | |
| * Author: | |
| * Bin Meng <bin.meng@windriver.com> | |
| * | |
| * A command interface to access misc devices with MISC uclass driver APIs. | |
| */ | |
| #include <common.h> | |
| #include <command.h> | |
| #include <dm.h> | |
| #include <errno.h> | |
| #include <misc.h> | |
| enum misc_op { | |
| MISC_OP_READ, | |
| MISC_OP_WRITE | |
| }; | |
| static char *misc_op_str[] = { | |
| "read", | |
| "write" | |
| }; | |
| static int do_misc_list(struct cmd_tbl *cmdtp, int flag, | |
| int argc, char *const argv[]) | |
| { | |
| struct udevice *dev; | |
| printf("Device Index Driver\n"); | |
| printf("-------------------------------------\n"); | |
| for (uclass_first_device(UCLASS_MISC, &dev); | |
| dev; | |
| uclass_next_device(&dev)) { | |
| printf("%-20s %5d %10s\n", dev->name, dev_seq(dev), | |
| dev->driver->name); | |
| } | |
| return 0; | |
| } | |
| static int do_misc_op(struct cmd_tbl *cmdtp, int flag, | |
| int argc, char *const argv[], enum misc_op op) | |
| { | |
| int (*misc_op)(struct udevice *, int, void *, int); | |
| struct udevice *dev; | |
| int offset; | |
| void *buf; | |
| int size; | |
| int ret; | |
| ret = uclass_get_device_by_name(UCLASS_MISC, argv[0], &dev); | |
| if (ret) { | |
| printf("Unable to find device %s\n", argv[0]); | |
| return ret; | |
| } | |
| offset = hextoul(argv[1], NULL); | |
| buf = (void *)hextoul(argv[2], NULL); | |
| size = hextoul(argv[3], NULL); | |
| if (op == MISC_OP_READ) | |
| misc_op = misc_read; | |
| else | |
| misc_op = misc_write; | |
| ret = misc_op(dev, offset, buf, size); | |
| if (ret < 0) { | |
| if (ret == -ENOSYS) { | |
| printf("The device does not support %s\n", | |
| misc_op_str[op]); | |
| ret = 0; | |
| } | |
| } else { | |
| if (ret == size) | |
| ret = 0; | |
| else | |
| printf("Partially %s %d bytes\n", misc_op_str[op], ret); | |
| } | |
| return ret; | |
| } | |
| static int do_misc_read(struct cmd_tbl *cmdtp, int flag, | |
| int argc, char *const argv[]) | |
| { | |
| return do_misc_op(cmdtp, flag, argc, argv, MISC_OP_READ); | |
| } | |
| static int do_misc_write(struct cmd_tbl *cmdtp, int flag, | |
| int argc, char *const argv[]) | |
| { | |
| return do_misc_op(cmdtp, flag, argc, argv, MISC_OP_WRITE); | |
| } | |
| static struct cmd_tbl misc_commands[] = { | |
| U_BOOT_CMD_MKENT(list, 0, 1, do_misc_list, "", ""), | |
| U_BOOT_CMD_MKENT(read, 4, 1, do_misc_read, "", ""), | |
| U_BOOT_CMD_MKENT(write, 4, 1, do_misc_write, "", ""), | |
| }; | |
| static int do_misc(struct cmd_tbl *cmdtp, int flag, | |
| int argc, char *const argv[]) | |
| { | |
| struct cmd_tbl *misc_cmd; | |
| int ret; | |
| if (argc < 2) | |
| return CMD_RET_USAGE; | |
| misc_cmd = find_cmd_tbl(argv[1], misc_commands, | |
| ARRAY_SIZE(misc_commands)); | |
| argc -= 2; | |
| argv += 2; | |
| if (!misc_cmd || argc != misc_cmd->maxargs) | |
| return CMD_RET_USAGE; | |
| ret = misc_cmd->cmd(misc_cmd, flag, argc, argv); | |
| return cmd_process_error(misc_cmd, ret); | |
| } | |
| U_BOOT_CMD( | |
| misc, 6, 1, do_misc, | |
| "Access miscellaneous devices with MISC uclass driver APIs", | |
| "list - list all miscellaneous devices\n" | |
| "misc read name offset addr len - read `len' bytes starting at\n" | |
| " `offset' of device `name'\n" | |
| " to memory at `addr'\n" | |
| "misc write name offset addr len - write `len' bytes starting at\n" | |
| " `offset' of device `name'\n" | |
| " from memory at `addr'" | |
| ); |