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 <linux/printk.h> 12#include <power/regulator.h> 13 14#define LIMIT_DEVNAME 20 15#define LIMIT_OFNAME 32 16#define LIMIT_INFO 18 17 18static struct udevice *currdev; 19 20static int failure(int ret) 21{ 22 printf("Error: %d (%s)\n", ret, errno_str(ret)); 23 24 return CMD_RET_FAILURE; 25} 26 27static int do_dev(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 28{ 29 struct dm_regulator_uclass_plat *uc_pdata; 30 const char *name; 31 int ret = -ENXIO; 32 33 switch (argc) { 34 case 2: 35 name = argv[1]; 36 ret = regulator_get_by_platname(name, &currdev); 37 if (ret) { 38 printf("Can't get the regulator: %s!\n", name); 39 return failure(ret); 40 } 41 fallthrough; 42 case 1: 43 if (!currdev) { 44 printf("Regulator device is not set!\n\n"); 45 return CMD_RET_USAGE; 46 } 47 48 uc_pdata = dev_get_uclass_plat(currdev); 49 if (!uc_pdata) { 50 printf("%s: no regulator platform data!\n", currdev->name); 51 return failure(ret); 52 } 53 54 printf("dev: %s @ %s\n", uc_pdata->name, currdev->name); 55 } 56 57 return CMD_RET_SUCCESS; 58} 59 60static int curr_dev_and_plat(struct udevice **devp, 61 struct dm_regulator_uclass_plat **uc_pdata, 62 bool allow_type_fixed) 63{ 64 *devp = NULL; 65 *uc_pdata = NULL; 66 67 if (!currdev) { 68 printf("First, set the regulator device!\n"); 69 return CMD_RET_FAILURE; 70 } 71 72 *devp = currdev; 73 74 *uc_pdata = dev_get_uclass_plat(*devp); 75 if (!*uc_pdata) { 76 pr_err("Regulator: %s - missing platform data!\n", currdev->name); 77 return CMD_RET_FAILURE; 78 } 79 80 if (!allow_type_fixed && (*uc_pdata)->type == REGULATOR_TYPE_FIXED) { 81 printf("Operation not allowed for fixed regulator!\n"); 82 return CMD_RET_FAILURE; 83 } 84 85 return CMD_RET_SUCCESS; 86} 87 88static int do_list(struct cmd_tbl *cmdtp, int flag, int argc, 89 char *const argv[]) 90{ 91 struct dm_regulator_uclass_plat *uc_pdata; 92 struct udevice *dev; 93 int ret; 94 95 printf("| %-*.*s| %-*.*s| %s\n", 96 LIMIT_DEVNAME, LIMIT_DEVNAME, "Device", 97 LIMIT_OFNAME, LIMIT_OFNAME, "regulator-name", 98 "Parent"); 99 100 for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev; 101 ret = uclass_find_next_device(&dev)) { 102 if (ret) 103 continue; 104 105 uc_pdata = dev_get_uclass_plat(dev); 106 printf("| %-*.*s| %-*.*s| %s\n", 107 LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name, 108 LIMIT_OFNAME, LIMIT_OFNAME, uc_pdata->name, 109 dev->parent->name); 110 } 111 112 return ret; 113} 114 115static int constraint(const char *name, int val, const char *val_name) 116{ 117 printf("%-*s", LIMIT_INFO, name); 118 if (val < 0) { 119 printf(" %s (err: %d)\n", errno_str(val), val); 120 return val; 121 } 122 123 if (val_name) 124 printf(" %d (%s)\n", val, val_name); 125 else 126 printf(" %d\n", val); 127 128 return 0; 129} 130 131static const char *get_mode_name(struct dm_regulator_mode *mode, 132 int mode_count, 133 int mode_id) 134{ 135 while (mode_count--) { 136 if (mode->id == mode_id) 137 return mode->name; 138 mode++; 139 } 140 141 return NULL; 142} 143 144static int do_info(struct cmd_tbl *cmdtp, int flag, int argc, 145 char *const argv[]) 146{ 147 struct udevice *dev; 148 struct dm_regulator_uclass_plat *uc_pdata; 149 struct dm_regulator_mode *modes; 150 const char *parent_uc; 151 int mode_count; 152 int ret; 153 int i; 154 155 ret = curr_dev_and_plat(&dev, &uc_pdata, true); 156 if (ret) 157 return ret; 158 159 parent_uc = dev_get_uclass_name(dev->parent); 160 161 printf("%s\n%-*s %s\n%-*s %s\n%-*s %s\n%-*s %s\n%-*s\n", 162 "Regulator info:", 163 LIMIT_INFO, "* regulator-name:", uc_pdata->name, 164 LIMIT_INFO, "* device name:", dev->name, 165 LIMIT_INFO, "* parent name:", dev->parent->name, 166 LIMIT_INFO, "* parent uclass:", parent_uc, 167 LIMIT_INFO, "* constraints:"); 168 169 constraint(" - min uV:", uc_pdata->min_uV, NULL); 170 constraint(" - max uV:", uc_pdata->max_uV, NULL); 171 constraint(" - min uA:", uc_pdata->min_uA, NULL); 172 constraint(" - max uA:", uc_pdata->max_uA, NULL); 173 constraint(" - always on:", uc_pdata->always_on, 174 uc_pdata->always_on ? "true" : "false"); 175 constraint(" - boot on:", uc_pdata->boot_on, 176 uc_pdata->boot_on ? "true" : "false"); 177 178 mode_count = regulator_mode(dev, &modes); 179 constraint("* op modes:", mode_count, NULL); 180 181 for (i = 0; i < mode_count; i++, modes++) 182 constraint(" - mode id:", modes->id, modes->name); 183 184 return CMD_RET_SUCCESS; 185} 186 187static void do_status_detail(struct udevice *dev, 188 struct dm_regulator_uclass_plat *uc_pdata) 189{ 190 int current, value, mode; 191 const char *mode_name; 192 bool enabled; 193 194 printf("Regulator %s status:\n", uc_pdata->name); 195 196 enabled = regulator_get_enable(dev); 197 constraint(" * enable:", enabled, enabled ? "true" : "false"); 198 199 value = regulator_get_value(dev); 200 constraint(" * value uV:", value, NULL); 201 202 current = regulator_get_current(dev); 203 constraint(" * current uA:", current, NULL); 204 205 mode = regulator_get_mode(dev); 206 mode_name = get_mode_name(uc_pdata->mode, uc_pdata->mode_count, mode); 207 constraint(" * mode id:", mode, mode_name); 208} 209 210static void do_status_line(struct udevice *dev, int status) 211{ 212 struct dm_regulator_uclass_plat *pdata; 213 int current, value, mode; 214 const char *mode_name; 215 bool enabled; 216 217 pdata = dev_get_uclass_plat(dev); 218 enabled = regulator_get_enable(dev); 219 value = regulator_get_value(dev); 220 current = regulator_get_current(dev); 221 mode = regulator_get_mode(dev); 222 mode_name = get_mode_name(pdata->mode, pdata->mode_count, mode); 223 printf("%-20s %-10s ", pdata->name, enabled ? "enabled" : "disabled"); 224 if (value >= 0) 225 printf("%10d ", value); 226 else 227 printf("%10s ", "-"); 228 if (current >= 0) 229 printf("%10d ", current); 230 else 231 printf("%10s ", "-"); 232 if (mode >= 0) 233 printf("%-10s", mode_name); 234 else 235 printf("%-10s", "-"); 236 printf(" %i", status); 237 printf("\n"); 238} 239 240static int do_status(struct cmd_tbl *cmdtp, int flag, int argc, 241 char *const argv[]) 242{ 243 struct dm_regulator_uclass_plat *uc_pdata; 244 struct udevice *dev; 245 int ret; 246 247 if (currdev && (argc < 2 || strcmp(argv[1], "-a"))) { 248 ret = curr_dev_and_plat(&dev, &uc_pdata, true); 249 if (ret) 250 return CMD_RET_FAILURE; 251 do_status_detail(dev, uc_pdata); 252 return 0; 253 } 254 255 /* Show all of them in a list, probing them as needed */ 256 printf("%-20s %-10s %10s %10s %-10s %s\n", "Name", "Enabled", "uV", "mA", 257 "Mode", "Status"); 258 for (ret = uclass_first_device_check(UCLASS_REGULATOR, &dev); dev; 259 ret = uclass_next_device_check(&dev)) 260 do_status_line(dev, ret); 261 262 return CMD_RET_SUCCESS; 263} 264 265static int do_value(struct cmd_tbl *cmdtp, int flag, int argc, 266 char *const argv[]) 267{ 268 struct udevice *dev; 269 struct dm_regulator_uclass_plat *uc_pdata; 270 int value; 271 int force; 272 int ret; 273 274 ret = curr_dev_and_plat(&dev, &uc_pdata, argc == 1); 275 if (ret) 276 return ret; 277 278 if (argc == 1) { 279 ret = regulator_get_value(dev); 280 if (ret < 0) { 281 printf("Regulator: %s - can't get the Voltage!\n", 282 uc_pdata->name); 283 return failure(ret); 284 } 285 286 printf("%d uV\n", ret); 287 return CMD_RET_SUCCESS; 288 } 289 290 if (argc == 3) 291 force = !strcmp("-f", argv[2]); 292 else 293 force = 0; 294 295 value = simple_strtoul(argv[1], NULL, 0); 296 if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) && !force) { 297 printf("Value exceeds regulator constraint limits %d..%d uV\n", 298 uc_pdata->min_uV, uc_pdata->max_uV); 299 return CMD_RET_FAILURE; 300 } 301 302 if (!force) 303 ret = regulator_set_value(dev, value); 304 else 305 ret = regulator_set_value_force(dev, value); 306 if (ret) { 307 printf("Regulator: %s - can't set the Voltage!\n", 308 uc_pdata->name); 309 return failure(ret); 310 } 311 312 return CMD_RET_SUCCESS; 313} 314 315static int do_current(struct cmd_tbl *cmdtp, int flag, int argc, 316 char *const argv[]) 317{ 318 struct udevice *dev; 319 struct dm_regulator_uclass_plat *uc_pdata; 320 int current; 321 int ret; 322 323 ret = curr_dev_and_plat(&dev, &uc_pdata, argc == 1); 324 if (ret) 325 return ret; 326 327 if (argc == 1) { 328 ret = regulator_get_current(dev); 329 if (ret < 0) { 330 printf("Regulator: %s - can't get the Current!\n", 331 uc_pdata->name); 332 return failure(ret); 333 } 334 335 printf("%d uA\n", ret); 336 return CMD_RET_SUCCESS; 337 } 338 339 current = simple_strtoul(argv[1], NULL, 0); 340 if (current < uc_pdata->min_uA || current > uc_pdata->max_uA) { 341 printf("Current exceeds regulator constraint limits\n"); 342 return CMD_RET_FAILURE; 343 } 344 345 ret = regulator_set_current(dev, current); 346 if (ret) { 347 printf("Regulator: %s - can't set the Current!\n", 348 uc_pdata->name); 349 return failure(ret); 350 } 351 352 return CMD_RET_SUCCESS; 353} 354 355static int do_mode(struct cmd_tbl *cmdtp, int flag, int argc, 356 char *const argv[]) 357{ 358 struct udevice *dev; 359 struct dm_regulator_uclass_plat *uc_pdata; 360 int mode; 361 int ret; 362 363 ret = curr_dev_and_plat(&dev, &uc_pdata, false); 364 if (ret) 365 return ret; 366 367 if (argc == 1) { 368 ret = regulator_get_mode(dev); 369 if (ret < 0) { 370 printf("Regulator: %s - can't get the operation mode!\n", 371 uc_pdata->name); 372 return failure(ret); 373 } 374 375 printf("mode id: %d\n", ret); 376 return CMD_RET_SUCCESS; 377 } 378 379 mode = simple_strtoul(argv[1], NULL, 0); 380 381 ret = regulator_set_mode(dev, mode); 382 if (ret) { 383 printf("Regulator: %s - can't set the operation mode!\n", 384 uc_pdata->name); 385 return failure(ret); 386 } 387 388 return CMD_RET_SUCCESS; 389} 390 391static int do_enable(struct cmd_tbl *cmdtp, int flag, int argc, 392 char *const argv[]) 393{ 394 struct udevice *dev; 395 struct dm_regulator_uclass_plat *uc_pdata; 396 int ret; 397 398 ret = curr_dev_and_plat(&dev, &uc_pdata, true); 399 if (ret) 400 return ret; 401 402 ret = regulator_set_enable(dev, true); 403 if (ret) { 404 printf("Regulator: %s - can't enable!\n", uc_pdata->name); 405 return failure(ret); 406 } 407 408 return CMD_RET_SUCCESS; 409} 410 411static int do_disable(struct cmd_tbl *cmdtp, int flag, int argc, 412 char *const argv[]) 413{ 414 struct udevice *dev; 415 struct dm_regulator_uclass_plat *uc_pdata; 416 int ret; 417 418 ret = curr_dev_and_plat(&dev, &uc_pdata, true); 419 if (ret) 420 return ret; 421 422 ret = regulator_set_enable(dev, false); 423 if (ret) { 424 printf("Regulator: %s - can't disable!\n", uc_pdata->name); 425 return failure(ret); 426 } 427 428 return CMD_RET_SUCCESS; 429} 430 431static struct cmd_tbl subcmd[] = { 432 U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""), 433 U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""), 434 U_BOOT_CMD_MKENT(info, 2, 1, do_info, "", ""), 435 U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""), 436 U_BOOT_CMD_MKENT(value, 3, 1, do_value, "", ""), 437 U_BOOT_CMD_MKENT(current, 3, 1, do_current, "", ""), 438 U_BOOT_CMD_MKENT(mode, 2, 1, do_mode, "", ""), 439 U_BOOT_CMD_MKENT(enable, 1, 1, do_enable, "", ""), 440 U_BOOT_CMD_MKENT(disable, 1, 1, do_disable, "", ""), 441}; 442 443static int do_regulator(struct cmd_tbl *cmdtp, int flag, int argc, 444 char *const argv[]) 445{ 446 struct cmd_tbl *cmd; 447 448 argc--; 449 argv++; 450 451 cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd)); 452 if (cmd == NULL || argc > cmd->maxargs) 453 return CMD_RET_USAGE; 454 455 return cmd->cmd(cmdtp, flag, argc, argv); 456} 457 458U_BOOT_CMD(regulator, CONFIG_SYS_MAXARGS, 1, do_regulator, 459 "uclass operations", 460 "list - list UCLASS regulator devices\n" 461 "regulator dev [regulator-name] - show/[set] operating regulator device\n" 462 "regulator info - print constraints info\n" 463 "regulator status [-a] - print operating status [for all]\n" 464 "regulator value [val] [-f] - print/[set] voltage value [uV] (force)\n" 465 "regulator current [val] - print/[set] current value [uA]\n" 466 "regulator mode [id] - print/[set] operating mode id\n" 467 "regulator enable - enable the regulator output\n" 468 "regulator disable - disable the regulator output\n" 469); 470