]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - cmd/smd-rpm.c
cmd: add command for accessing the RPM via SMD protocol
[karo-tx-uboot.git] / cmd / smd-rpm.c
1 /*
2  * (C) Copyright 2016 Lothar Waßmann <LW@KARO-electronics.de>
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <cli.h>
9 #include <command.h>
10 #include <console.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <malloc.h>
14 #include <power/pmic-qcom-smd-rpm.h>
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 static bool smd_inited;
19
20 static uint32_t smd_rpm_msg[] = {
21         LDOA_RES_TYPE, 0, KEY_SOFTWARE_ENABLE, 4, 0,
22         KEY_MICRO_VOLT, 4, 0,
23         KEY_CURRENT, 4, 0,
24 };
25
26 #define smd_param_ldo           smd_rpm_msg[1]
27 #define smd_param_enable        smd_rpm_msg[4]
28 #define smd_param_uV            smd_rpm_msg[7]
29 #define smd_param_uA            smd_rpm_msg[10]
30
31 static int do_smd_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
32 {
33         if (!smd_inited) {
34                 smd_rpm_init();
35                 smd_inited = true;
36         }
37         return CMD_RET_SUCCESS;
38 }
39
40 static int do_smd_uninit(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
41 {
42         if (smd_inited) {
43                 smd_rpm_uninit();
44                 smd_inited = false;
45         }
46         return CMD_RET_SUCCESS;
47 }
48
49 #ifdef DEBUG
50 static void dump_rpm_msg(void *_msg, size_t msglen)
51 {
52         uint32_t *msg = _msg;
53         size_t m;
54
55         printf("MSG:");
56         for (m = 0; m < msglen / 4; m++) {
57                 printf(" %08x", msg[m]);
58         }
59         printf("\n");
60 }
61 #else
62 static inline void dump_rpm_msg(void *_msg, size_t msglen)
63 {
64 }
65 #endif
66
67 static int do_raw_write(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
68 {
69         int ret;
70         size_t msglen = argc * sizeof(uint32_t);
71         static uint32_t *msg;
72         static size_t msgsize;
73         int i;
74
75         if (argc < 1)
76                 return CMD_RET_USAGE;
77
78         if (msg == NULL || msgsize < msglen) {
79                 free(msg);
80                 msg = malloc(msglen);
81                 if (msg == NULL) {
82                         msgsize = 0;
83                         return CMD_RET_FAILURE;
84                 }
85                 msgsize = msglen;
86         }
87
88         for (i = 0; i < argc; i++)
89                 msg[i] = strtoul(argv[i], NULL, 16);
90
91         dump_rpm_msg(msg, msglen);
92
93         if (!smd_inited)
94                 smd_rpm_init();
95
96         ret = rpm_send_data(msg, msglen, RPM_REQUEST_TYPE);
97         if (ret)
98                 printf("Failed to configure regulator LDO%u\n", smd_param_ldo);
99
100         if (!smd_inited)
101                 smd_rpm_uninit();
102
103         return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
104 }
105
106 static int do_smd_write(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
107 {
108         uint ldo, uV, uA;
109         int ret;
110         size_t msglen;
111
112         if (argv[0][0] == 'w')
113                 return do_raw_write(cmdtp, flag, argc - 1, &argv[1]);
114
115         if (argc < 2 || argc > 4)
116                 return cmd_usage(cmdtp);
117
118         msglen = 5 * sizeof(uint32_t);
119         smd_param_enable = argv[0][0] == 'e';
120
121         ldo = simple_strtoul(argv[1], NULL, 10);
122         if (ldo > 18)
123                 return CMD_RET_USAGE;
124
125         smd_param_ldo = ldo;
126
127         if (argc > 2) {
128                 if (ldo > 3) {
129                         uV = simple_strtoul(argv[2], NULL, 10);
130                         smd_param_uV = uV;
131                         msglen += 3 * sizeof(uint32_t);
132                 } else {
133                         printf("LDO%u has no voltage control\n", ldo);
134                 }
135         }
136         if (argc > 3) {
137                 uA = simple_strtoul(argv[3], NULL, 10);
138                 smd_param_uA = uA;
139                 msglen += 3 * sizeof(uint32_t);
140         }
141         printf("%sabling LDO%u", smd_param_enable == GENERIC_ENABLE ? "En" : "Dis",
142                 smd_param_ldo);
143         if (argc > 2)
144                 printf(": %u.%03uV", smd_param_uV / 1000000,
145                         smd_param_uV / 1000 % 1000);
146         if (argc > 3)
147                 printf(", %u.%03umA", smd_param_uA / 1000,
148                         smd_param_uA % 1000);
149         printf("\n");
150
151         if (!smd_inited)
152                 smd_rpm_init();
153
154         dump_rpm_msg(smd_rpm_msg, msglen);
155         ret = rpm_send_data(smd_rpm_msg, msglen, RPM_REQUEST_TYPE);
156         if (ret)
157                 printf("Failed to configure regulator LDO%u\n", smd_param_ldo);
158
159         if (!smd_inited)
160                 smd_rpm_uninit();
161
162         return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
163 }
164
165 static cmd_tbl_t cmd_smd_sub[] = {
166         U_BOOT_CMD_MKENT(init, 0, 1, do_smd_init, "", ""),
167         U_BOOT_CMD_MKENT(uninit, 0, 1, do_smd_uninit, "", ""),
168         U_BOOT_CMD_MKENT(enable, 4, 1, do_smd_write, "", ""),
169         U_BOOT_CMD_MKENT(disable, 5, 0, do_smd_write, "", ""),
170         U_BOOT_CMD_MKENT(write, 4, 1, do_smd_write, "", ""),
171 };
172
173 static inline void smd_reloc(void)
174 {
175         static int relocated;
176
177         if (!relocated) {
178                 fixup_cmdtable(cmd_smd_sub, ARRAY_SIZE(cmd_smd_sub));
179                 relocated = 1;
180         };
181 }
182
183 /**
184  * do_smd() - Handle the "smd" command-line command
185  * @cmdtp:      Command data struct pointer
186  * @flag:       Command flag
187  * @argc:       Command-line argument count
188  * @argv:       Array of command-line arguments
189  *
190  * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
191  * on error.
192  */
193 static int do_smd(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
194 {
195         cmd_tbl_t *c;
196
197 #ifdef CONFIG_NEEDS_MANUAL_RELOC
198         smd_reloc();
199 #endif
200
201         if (argc < 2)
202                 return CMD_RET_USAGE;
203
204         /* Strip off leading 'smd' command argument */
205         argc--;
206         argv++;
207
208         c = find_cmd_tbl(argv[0], cmd_smd_sub, ARRAY_SIZE(cmd_smd_sub));
209
210         if (c)
211                 return c->cmd(cmdtp, flag, argc, argv);
212         else
213                 printf("subcommand '%s' not found\n", argv[0]);
214         return CMD_RET_USAGE;
215 }
216
217 #ifdef CONFIG_SYS_LONGHELP
218 static char smd_help_text[] =
219         "\tsmd init\n"
220         "\tsmd uninit\n"
221         "\tsmd enable <ldo#> [<uV>] [<uA>]    - Enable LDO<ldo#> optionally setting voltage and current\n"
222         "\tsmd disable <ldo#> [<uV>] [<uA>]   - Disable LDO<ldö#>\n"
223         "\tsmd write <keycode> <key> [<param> <value>] [...]\n"
224         "\tsmd read <len>\n"
225         ;
226 #endif
227
228 U_BOOT_CMD(
229         smd, 16, 0, do_smd,
230         "Qualcomm SMD sub-system",
231         smd_help_text
232 );