blob: 4f7ba099cd917baf8c2bb4a4846f6e15c7eb3c6c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Łukasz Majewski16db0622011-10-06 02:37:34 +00002/*
3 * Copyright (C) 2011 Samsung Electronics
4 * Lukasz Majewski <l.majewski@samsung.com>
5 *
6 * (C) Copyright 2010
7 * Stefano Babic, DENX Software Engineering, sbabic@denx.de
8 *
9 * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
Łukasz Majewski16db0622011-10-06 02:37:34 +000010 */
11
12#include <common.h>
Simon Glassed38aef2020-05-10 11:40:03 -060013#include <command.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000015#include <malloc.h>
Łukasz Majewski16db0622011-10-06 02:37:34 +000016#include <linux/types.h>
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000017#include <linux/list.h>
18#include <power/pmic.h>
Łukasz Majewski16db0622011-10-06 02:37:34 +000019
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000020static LIST_HEAD(pmic_list);
Łukasz Majewski16db0622011-10-06 02:37:34 +000021
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000022int check_reg(struct pmic *p, u32 reg)
Łukasz Majewski16db0622011-10-06 02:37:34 +000023{
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000024 if (reg >= p->number_of_regs) {
Łukasz Majewski16db0622011-10-06 02:37:34 +000025 printf("<reg num> = %d is invalid. Should be less than %d\n",
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000026 reg, p->number_of_regs);
Jaehoon Chung10e80f32016-12-15 20:49:50 +090027 return -EINVAL;
Łukasz Majewski16db0622011-10-06 02:37:34 +000028 }
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000029
Łukasz Majewski16db0622011-10-06 02:37:34 +000030 return 0;
31}
32
33int pmic_set_output(struct pmic *p, u32 reg, int out, int on)
34{
35 u32 val;
36
37 if (pmic_reg_read(p, reg, &val))
Jaehoon Chung10e80f32016-12-15 20:49:50 +090038 return -ENOTSUPP;
Łukasz Majewski16db0622011-10-06 02:37:34 +000039
40 if (on)
41 val |= out;
42 else
43 val &= ~out;
44
45 if (pmic_reg_write(p, reg, val))
Jaehoon Chung10e80f32016-12-15 20:49:50 +090046 return -ENOTSUPP;
Łukasz Majewski16db0622011-10-06 02:37:34 +000047
48 return 0;
49}
50
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000051struct pmic *pmic_alloc(void)
52{
53 struct pmic *p;
54
55 p = calloc(sizeof(*p), 1);
56 if (!p) {
57 printf("%s: No available memory for allocation!\n", __func__);
58 return NULL;
59 }
60
61 list_add_tail(&p->list, &pmic_list);
62
63 debug("%s: new pmic struct: 0x%p\n", __func__, p);
64
65 return p;
66}
67
68struct pmic *pmic_get(const char *s)
69{
70 struct pmic *p;
71
72 list_for_each_entry(p, &pmic_list, list) {
73 if (strcmp(p->name, s) == 0) {
74 debug("%s: pmic %s -> 0x%p\n", __func__, p->name, p);
75 return p;
76 }
77 }
78
79 return NULL;
Łukasz Majewski16db0622011-10-06 02:37:34 +000080}
81
Tom Riniec896572017-12-22 12:27:14 -050082#ifndef CONFIG_SPL_BUILD
83static int pmic_dump(struct pmic *p)
84{
85 int i, ret;
86 u32 val;
87
88 if (!p) {
89 puts("Wrong PMIC name!\n");
90 return -ENODEV;
91 }
92
93 printf("PMIC: %s\n", p->name);
94 for (i = 0; i < p->number_of_regs; i++) {
95 ret = pmic_reg_read(p, i, &val);
96 if (ret)
97 puts("PMIC: Registers dump failed\n");
98
99 if (!(i % 8))
100 printf("\n0x%02x: ", i);
101
102 printf("%08x ", val);
103 }
104 puts("\n");
105 return 0;
106}
107
108static const char *power_get_interface(int interface)
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000109{
110 const char *power_interface[] = {"I2C", "SPI", "|+|-|"};
111 return power_interface[interface];
112}
113
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000114static void pmic_list_names(void)
Łukasz Majewski16db0622011-10-06 02:37:34 +0000115{
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000116 struct pmic *p;
117
118 puts("PMIC devices:\n");
119 list_for_each_entry(p, &pmic_list, list) {
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000120 printf("name: %s bus: %s_%d\n", p->name,
121 power_get_interface(p->interface), p->bus);
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000122 }
Łukasz Majewski16db0622011-10-06 02:37:34 +0000123}
124
Simon Glassed38aef2020-05-10 11:40:03 -0600125static int do_pmic(struct cmd_tbl *cmdtp, int flag, int argc,
126 char *const argv[])
Łukasz Majewski16db0622011-10-06 02:37:34 +0000127{
128 u32 ret, reg, val;
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000129 char *cmd, *name;
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000130 struct pmic *p;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000131
Łukasz Majewski16db0622011-10-06 02:37:34 +0000132 /* at least two arguments please */
133 if (argc < 2)
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000134 return CMD_RET_USAGE;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000135
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000136 if (strcmp(argv[1], "list") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000137 pmic_list_names();
138 return CMD_RET_SUCCESS;
139 }
140
Łukasz Majewski25719232014-02-24 13:33:08 +0100141 if (argc < 3)
142 return CMD_RET_USAGE;
143
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000144 name = argv[1];
145 cmd = argv[2];
146
147 debug("%s: name: %s cmd: %s\n", __func__, name, cmd);
148 p = pmic_get(name);
149 if (!p)
150 return CMD_RET_FAILURE;
151
Łukasz Majewski16db0622011-10-06 02:37:34 +0000152 if (strcmp(cmd, "dump") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000153 if (pmic_dump(p))
154 return CMD_RET_FAILURE;
155 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000156 }
157
158 if (strcmp(cmd, "read") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000159 if (argc < 4)
160 return CMD_RET_USAGE;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000161
Simon Glass3ff49ec2021-07-24 09:03:29 -0600162 reg = hextoul(argv[3], NULL);
Łukasz Majewski16db0622011-10-06 02:37:34 +0000163 ret = pmic_reg_read(p, reg, &val);
164
165 if (ret)
166 puts("PMIC: Register read failed\n");
167
168 printf("\n0x%02x: 0x%08x\n", reg, val);
169
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000170 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000171 }
172
173 if (strcmp(cmd, "write") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000174 if (argc < 5)
175 return CMD_RET_USAGE;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000176
Simon Glass3ff49ec2021-07-24 09:03:29 -0600177 reg = hextoul(argv[3], NULL);
178 val = hextoul(argv[4], NULL);
Łukasz Majewski16db0622011-10-06 02:37:34 +0000179 pmic_reg_write(p, reg, val);
180
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000181 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000182 }
183
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000184 if (strcmp(cmd, "bat") == 0) {
185 if (argc < 4)
186 return CMD_RET_USAGE;
187
Piotr Wilczekdfb100d2013-09-26 14:43:35 +0200188 if (!p->pbat) {
189 printf("%s is not a battery\n", p->name);
190 return CMD_RET_FAILURE;
191 }
192
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000193 if (strcmp(argv[3], "state") == 0)
194 p->fg->fg_battery_check(p->pbat->fg, p);
195
196 if (strcmp(argv[3], "charge") == 0) {
Piotr Wilczekdfb100d2013-09-26 14:43:35 +0200197 printf("BAT: %s charging (ctrl+c to break)\n",
198 p->name);
199 if (p->low_power_mode)
200 p->low_power_mode();
201 if (p->pbat->battery_charge)
202 p->pbat->battery_charge(p);
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000203 }
204
205 return CMD_RET_SUCCESS;
206 }
207
Łukasz Majewski16db0622011-10-06 02:37:34 +0000208 /* No subcommand found */
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000209 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000210}
211
212U_BOOT_CMD(
213 pmic, CONFIG_SYS_MAXARGS, 1, do_pmic,
214 "PMIC",
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000215 "list - list available PMICs\n"
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000216 "pmic name dump - dump named PMIC registers\n"
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000217 "pmic name read <reg> - read register\n"
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000218 "pmic name write <reg> <value> - write register\n"
219 "pmic name bat state - write register\n"
220 "pmic name bat charge - write register\n"
Łukasz Majewski16db0622011-10-06 02:37:34 +0000221);
Tom Riniec896572017-12-22 12:27:14 -0500222#endif