1// SPDX-License-Identifier: GPL-2.0+
2
3#include <common.h>
4#include <command.h>
5#include <display_options.h>
6#include <dm.h>
7#include <hexdump.h>
8#include <i2c.h>
9#include <mapmem.h>
10#include <rtc.h>
11
12#define MAX_RTC_BYTES 32
13
14static int do_rtc_read(struct udevice *dev, int argc, char * const argv[])
15{
16	u8 buf[MAX_RTC_BYTES];
17	int reg, len, ret, r;
18
19	if (argc < 2 || argc > 3)
20		return CMD_RET_USAGE;
21
22	reg = hextoul(argv[0], NULL);
23	len = hextoul(argv[1], NULL);
24
25	if (argc == 3) {
26		u8 *addr;
27
28		addr = map_sysmem(hextoul(argv[2], NULL), len);
29		ret = dm_rtc_read(dev, reg, addr, len);
30		unmap_sysmem(addr);
31		if (ret) {
32			printf("dm_rtc_read() failed: %d\n", ret);
33			return CMD_RET_FAILURE;
34		}
35		return CMD_RET_SUCCESS;
36	}
37
38	while (len) {
39		r = min_t(int, len, sizeof(buf));
40		ret = dm_rtc_read(dev, reg, buf, r);
41		if (ret) {
42			printf("dm_rtc_read() failed: %d\n", ret);
43			return CMD_RET_FAILURE;
44		}
45		print_buffer(reg, buf, 1, r, 0);
46		len -= r;
47		reg += r;
48	}
49
50	return CMD_RET_SUCCESS;
51}
52
53static int do_rtc_write(struct udevice *dev, int argc, char * const argv[])
54{
55	u8 buf[MAX_RTC_BYTES];
56	int reg, len, ret;
57	const char *s;
58	int slen;
59
60	if (argc < 2 || argc > 3)
61		return CMD_RET_USAGE;
62
63	reg = hextoul(argv[0], NULL);
64
65	if (argc == 3) {
66		u8 *addr;
67
68		len = hextoul(argv[1], NULL);
69		addr = map_sysmem(hextoul(argv[2], NULL), len);
70		ret = dm_rtc_write(dev, reg, addr, len);
71		unmap_sysmem(addr);
72		if (ret) {
73			printf("dm_rtc_write() failed: %d\n", ret);
74			return CMD_RET_FAILURE;
75		}
76		return CMD_RET_SUCCESS;
77	}
78
79	s = argv[1];
80	slen = strlen(s);
81
82	if (slen % 2) {
83		printf("invalid hex string\n");
84		return CMD_RET_FAILURE;
85	}
86
87	while (slen) {
88		len = min_t(int, slen / 2, sizeof(buf));
89		if (hex2bin(buf, s, len)) {
90			printf("invalid hex string\n");
91			return CMD_RET_FAILURE;
92		}
93
94		ret = dm_rtc_write(dev, reg, buf, len);
95		if (ret) {
96			printf("dm_rtc_write() failed: %d\n", ret);
97			return CMD_RET_FAILURE;
98		}
99		s += 2 * len;
100		slen -= 2 * len;
101	}
102
103	return CMD_RET_SUCCESS;
104}
105
106int do_rtc(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
107{
108	static int curr_rtc;
109	struct udevice *dev;
110	int ret, idx;
111
112	if (argc < 2)
113		return CMD_RET_USAGE;
114
115	argc--;
116	argv++;
117
118	if (!strcmp(argv[0], "list")) {
119		struct uclass *uc;
120
121		idx = 0;
122		uclass_id_foreach_dev(UCLASS_RTC, dev, uc) {
123			printf("RTC #%d - %s\n", idx++, dev->name);
124		}
125		if (!idx) {
126			printf("*** no RTC devices available ***\n");
127			return CMD_RET_FAILURE;
128		}
129		return CMD_RET_SUCCESS;
130	}
131
132	idx = curr_rtc;
133	if (!strcmp(argv[0], "dev") && argc >= 2)
134		idx = dectoul(argv[1], NULL);
135
136	ret = uclass_get_device(UCLASS_RTC, idx, &dev);
137	if (ret) {
138		printf("Cannot find RTC #%d: err=%d\n", idx, ret);
139		return CMD_RET_FAILURE;
140	}
141
142	if (!strcmp(argv[0], "dev")) {
143		/* Show the existing or newly selected RTC */
144		if (argc >= 2)
145			curr_rtc = idx;
146		printf("RTC #%d - %s\n", idx, dev->name);
147		return CMD_RET_SUCCESS;
148	}
149
150	if (!strcmp(argv[0], "read"))
151		return do_rtc_read(dev, argc - 1, argv + 1);
152
153	if (!strcmp(argv[0], "write"))
154		return do_rtc_write(dev, argc - 1, argv + 1);
155
156	return CMD_RET_USAGE;
157}
158
159U_BOOT_CMD(
160	rtc,	5,	0,	do_rtc,
161	"RTC subsystem",
162	"list                        - show available rtc devices\n"
163	"rtc dev [n]                     - show or set current rtc device\n"
164	"rtc read <reg> <count>          - read and display 8-bit registers starting at <reg>\n"
165	"rtc read <reg> <count> <addr>   - read 8-bit registers starting at <reg> to memory <addr>\n"
166	"rtc write <reg> <hexstring>     - write 8-bit registers starting at <reg>\n"
167	"rtc write <reg> <count> <addr>  - write from memory <addr> to 8-bit registers starting at <reg>\n"
168);
169