1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2014-2015 Samsung Electronics
4 * Przemyslaw Marczak <p.marczak@samsung.com>
5 */
6#include <common.h>
7#include <command.h>
8#include <errno.h>
9#include <dm.h>
10#include <dm/uclass-internal.h>
11#include <power/pmic.h>
12
13#define LIMIT_DEV	32
14#define LIMIT_PARENT	20
15
16static struct udevice *currdev;
17
18static int failure(int ret)
19{
20	printf("Error: %d (%s)\n", ret, errno_str(ret));
21
22	return CMD_RET_FAILURE;
23}
24
25static int do_dev(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
26{
27	char *name;
28	int ret = -ENODEV;
29
30	switch (argc) {
31	case 2:
32		name = argv[1];
33		ret = pmic_get(name, &currdev);
34		if (ret) {
35			printf("Can't get PMIC: %s!\n", name);
36			return failure(ret);
37		}
38	case 1:
39		if (!currdev) {
40			printf("PMIC device is not set!\n\n");
41			return CMD_RET_USAGE;
42		}
43
44		printf("dev: %d @ %s\n", dev_seq(currdev), currdev->name);
45	}
46
47	return CMD_RET_SUCCESS;
48}
49
50static int do_list(struct cmd_tbl *cmdtp, int flag, int argc,
51		   char *const argv[])
52{
53	struct udevice *dev;
54	int ret, err = 0;
55
56	printf("| %-*.*s| %-*.*s| %s @ %s\n",
57	       LIMIT_DEV, LIMIT_DEV, "Name",
58	       LIMIT_PARENT, LIMIT_PARENT, "Parent name",
59	       "Parent uclass", "seq");
60
61	for (ret = uclass_first_device_check(UCLASS_PMIC, &dev); dev;
62	     ret = uclass_next_device_check(&dev)) {
63		if (ret)
64			err = ret;
65
66		printf("| %-*.*s| %-*.*s| %s @ %d | status: %i\n",
67		       LIMIT_DEV, LIMIT_DEV, dev->name,
68		       LIMIT_PARENT, LIMIT_PARENT, dev->parent->name,
69		       dev_get_uclass_name(dev->parent), dev_seq(dev->parent),
70		       ret);
71	}
72
73	if (err)
74		return CMD_RET_FAILURE;
75
76	return CMD_RET_SUCCESS;
77}
78
79static int do_dump(struct cmd_tbl *cmdtp, int flag, int argc,
80		   char *const argv[])
81{
82	struct uc_pmic_priv *priv;
83	struct udevice *dev;
84	char fmt[16];
85	uint reg;
86	int ret;
87
88	if (!currdev) {
89		printf("First, set the PMIC device!\n");
90		return CMD_RET_USAGE;
91	}
92
93	dev = currdev;
94	priv = dev_get_uclass_priv(dev);
95	printf("Dump pmic: %s registers\n", dev->name);
96
97	sprintf(fmt, "%%%d.%dx ", priv->trans_len * 2,
98		priv->trans_len * 2);
99
100	for (reg = 0; reg < pmic_reg_count(dev); reg++) {
101		ret = pmic_reg_read(dev, reg);
102		if (ret < 0 && ret != -ENODATA) {
103			printf("Can't read register: %d\n", reg);
104			return failure(ret);
105		}
106
107		if (!(reg % 16))
108			printf("\n0x%02x: ", reg);
109
110		if (ret == -ENODATA) {
111			int i;
112
113			for (i = 0; i < priv->trans_len; i++)
114				puts("--");
115			puts(" ");
116		} else {
117			printf(fmt, ret);
118		}
119	}
120	printf("\n");
121
122	return CMD_RET_SUCCESS;
123}
124
125static int do_read(struct cmd_tbl *cmdtp, int flag, int argc,
126		   char *const argv[])
127{
128	struct uc_pmic_priv *priv;
129	struct udevice *dev;
130	int regs, ret;
131	char fmt[24];
132	uint reg;
133
134	if (!currdev) {
135		printf("First, set the PMIC device!\n");
136		return CMD_RET_USAGE;
137	}
138
139	dev = currdev;
140	priv = dev_get_uclass_priv(dev);
141
142	if (argc != 2)
143		return CMD_RET_USAGE;
144
145	reg = simple_strtoul(argv[1], NULL, 0);
146	regs = pmic_reg_count(dev);
147	if (reg > regs) {
148		printf("PMIC max reg: %d\n", regs);
149		return failure(-EFAULT);
150	}
151
152	ret = pmic_reg_read(dev, reg);
153	if (ret < 0) {
154		printf("Can't read PMIC register: %d!\n", reg);
155		return failure(ret);
156	}
157
158	sprintf(fmt, "0x%%02x: 0x%%%d.%dx\n", priv->trans_len * 2,
159		priv->trans_len * 2);
160	printf(fmt, reg, ret);
161
162	return CMD_RET_SUCCESS;
163}
164
165static int do_write(struct cmd_tbl *cmdtp, int flag, int argc,
166		    char *const argv[])
167{
168	struct udevice *dev;
169	uint reg, value;
170	int regs, ret;
171
172	if (!currdev) {
173		printf("First, set the PMIC device!\n");
174		return CMD_RET_USAGE;
175	}
176
177	dev = currdev;
178
179	if (argc != 3)
180		return CMD_RET_USAGE;
181
182	reg = simple_strtoul(argv[1], NULL, 0);
183	regs = pmic_reg_count(dev);
184	if (reg > regs) {
185		printf("PMIC max reg: %d\n", regs);
186		return failure(-EFAULT);
187	}
188
189	value = simple_strtoul(argv[2], NULL, 0);
190
191	ret = pmic_reg_write(dev, reg, value);
192	if (ret) {
193		printf("Can't write PMIC register: %d!\n", reg);
194		return failure(ret);
195	}
196
197	return CMD_RET_SUCCESS;
198}
199
200static struct cmd_tbl subcmd[] = {
201	U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
202	U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
203	U_BOOT_CMD_MKENT(dump, 1, 1, do_dump, "", ""),
204	U_BOOT_CMD_MKENT(read, 2, 1, do_read, "", ""),
205	U_BOOT_CMD_MKENT(write, 3, 1, do_write, "", ""),
206};
207
208static int do_pmic(struct cmd_tbl *cmdtp, int flag, int argc,
209		   char *const argv[])
210{
211	struct cmd_tbl *cmd;
212
213	argc--;
214	argv++;
215
216	cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd));
217	if (cmd == NULL || argc > cmd->maxargs)
218		return CMD_RET_USAGE;
219
220	return cmd->cmd(cmdtp, flag, argc, argv);
221}
222
223U_BOOT_CMD(pmic, CONFIG_SYS_MAXARGS, 1, do_pmic,
224	"PMIC sub-system",
225	"list          - list pmic devices\n"
226	"pmic dev [name]    - show or [set] operating PMIC device\n"
227	"pmic dump          - dump registers\n"
228	"pmic read <reg>    - read byte of 'reg' register\n"
229	"pmic write <reg> <byte> - write 'byte' byte to 'reg' register\n"
230);
231