1 // SPDX-License-Identifier: GPL-2.0+
2 /*
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.
10 */
11
12 #include <common.h>
13 #include <malloc.h>
14 #include <linux/types.h>
15 #include <linux/list.h>
16 #include <power/pmic.h>
17
18 static LIST_HEAD(pmic_list);
19
check_reg(struct pmic * p,u32 reg)20 int check_reg(struct pmic *p, u32 reg)
21 {
22 if (reg >= p->number_of_regs) {
23 printf("<reg num> = %d is invalid. Should be less than %d\n",
24 reg, p->number_of_regs);
25 return -EINVAL;
26 }
27
28 return 0;
29 }
30
pmic_set_output(struct pmic * p,u32 reg,int out,int on)31 int pmic_set_output(struct pmic *p, u32 reg, int out, int on)
32 {
33 u32 val;
34
35 if (pmic_reg_read(p, reg, &val))
36 return -ENOTSUPP;
37
38 if (on)
39 val |= out;
40 else
41 val &= ~out;
42
43 if (pmic_reg_write(p, reg, val))
44 return -ENOTSUPP;
45
46 return 0;
47 }
48
pmic_alloc(void)49 struct pmic *pmic_alloc(void)
50 {
51 struct pmic *p;
52
53 p = calloc(sizeof(*p), 1);
54 if (!p) {
55 printf("%s: No available memory for allocation!\n", __func__);
56 return NULL;
57 }
58
59 list_add_tail(&p->list, &pmic_list);
60
61 debug("%s: new pmic struct: 0x%p\n", __func__, p);
62
63 return p;
64 }
65
pmic_get(const char * s)66 struct pmic *pmic_get(const char *s)
67 {
68 struct pmic *p;
69
70 list_for_each_entry(p, &pmic_list, list) {
71 if (strcmp(p->name, s) == 0) {
72 debug("%s: pmic %s -> 0x%p\n", __func__, p->name, p);
73 return p;
74 }
75 }
76
77 return NULL;
78 }
79
80 #ifndef CONFIG_SPL_BUILD
pmic_dump(struct pmic * p)81 static int pmic_dump(struct pmic *p)
82 {
83 int i, ret;
84 u32 val;
85
86 if (!p) {
87 puts("Wrong PMIC name!\n");
88 return -ENODEV;
89 }
90
91 printf("PMIC: %s\n", p->name);
92 for (i = 0; i < p->number_of_regs; i++) {
93 ret = pmic_reg_read(p, i, &val);
94 if (ret)
95 puts("PMIC: Registers dump failed\n");
96
97 if (!(i % 8))
98 printf("\n0x%02x: ", i);
99
100 printf("%08x ", val);
101 }
102 puts("\n");
103 return 0;
104 }
105
power_get_interface(int interface)106 static const char *power_get_interface(int interface)
107 {
108 const char *power_interface[] = {"I2C", "SPI", "|+|-|"};
109 return power_interface[interface];
110 }
111
pmic_list_names(void)112 static void pmic_list_names(void)
113 {
114 struct pmic *p;
115
116 puts("PMIC devices:\n");
117 list_for_each_entry(p, &pmic_list, list) {
118 printf("name: %s bus: %s_%d\n", p->name,
119 power_get_interface(p->interface), p->bus);
120 }
121 }
122
do_pmic(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])123 static int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
124 {
125 u32 ret, reg, val;
126 char *cmd, *name;
127 struct pmic *p;
128
129 /* at least two arguments please */
130 if (argc < 2)
131 return CMD_RET_USAGE;
132
133 if (strcmp(argv[1], "list") == 0) {
134 pmic_list_names();
135 return CMD_RET_SUCCESS;
136 }
137
138 if (argc < 3)
139 return CMD_RET_USAGE;
140
141 name = argv[1];
142 cmd = argv[2];
143
144 debug("%s: name: %s cmd: %s\n", __func__, name, cmd);
145 p = pmic_get(name);
146 if (!p)
147 return CMD_RET_FAILURE;
148
149 if (strcmp(cmd, "dump") == 0) {
150 if (pmic_dump(p))
151 return CMD_RET_FAILURE;
152 return CMD_RET_SUCCESS;
153 }
154
155 if (strcmp(cmd, "read") == 0) {
156 if (argc < 4)
157 return CMD_RET_USAGE;
158
159 reg = simple_strtoul(argv[3], NULL, 16);
160 ret = pmic_reg_read(p, reg, &val);
161
162 if (ret)
163 puts("PMIC: Register read failed\n");
164
165 printf("\n0x%02x: 0x%08x\n", reg, val);
166
167 return CMD_RET_SUCCESS;
168 }
169
170 if (strcmp(cmd, "write") == 0) {
171 if (argc < 5)
172 return CMD_RET_USAGE;
173
174 reg = simple_strtoul(argv[3], NULL, 16);
175 val = simple_strtoul(argv[4], NULL, 16);
176 pmic_reg_write(p, reg, val);
177
178 return CMD_RET_SUCCESS;
179 }
180
181 if (strcmp(cmd, "bat") == 0) {
182 if (argc < 4)
183 return CMD_RET_USAGE;
184
185 if (!p->pbat) {
186 printf("%s is not a battery\n", p->name);
187 return CMD_RET_FAILURE;
188 }
189
190 if (strcmp(argv[3], "state") == 0)
191 p->fg->fg_battery_check(p->pbat->fg, p);
192
193 if (strcmp(argv[3], "charge") == 0) {
194 printf("BAT: %s charging (ctrl+c to break)\n",
195 p->name);
196 if (p->low_power_mode)
197 p->low_power_mode();
198 if (p->pbat->battery_charge)
199 p->pbat->battery_charge(p);
200 }
201
202 return CMD_RET_SUCCESS;
203 }
204
205 /* No subcommand found */
206 return CMD_RET_SUCCESS;
207 }
208
209 U_BOOT_CMD(
210 pmic, CONFIG_SYS_MAXARGS, 1, do_pmic,
211 "PMIC",
212 "list - list available PMICs\n"
213 "pmic name dump - dump named PMIC registers\n"
214 "pmic name read <reg> - read register\n"
215 "pmic name write <reg> <value> - write register\n"
216 "pmic name bat state - write register\n"
217 "pmic name bat charge - write register\n"
218 );
219 #endif
220