xref: /openbmc/u-boot/drivers/power/power_core.c (revision b46694df)
1 /*
2  * Copyright (C) 2011 Samsung Electronics
3  * Lukasz Majewski <l.majewski@samsung.com>
4  *
5  * (C) Copyright 2010
6  * Stefano Babic, DENX Software Engineering, sbabic@denx.de
7  *
8  * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
9  *
10  * See file CREDITS for list of people who contributed to this
11  * project.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation; either version 2 of
16  * the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26  * MA 02111-1307 USA
27  */
28 
29 #include <common.h>
30 #include <malloc.h>
31 #include <linux/types.h>
32 #include <linux/list.h>
33 #include <power/pmic.h>
34 
35 static LIST_HEAD(pmic_list);
36 
37 int check_reg(struct pmic *p, u32 reg)
38 {
39 	if (reg >= p->number_of_regs) {
40 		printf("<reg num> = %d is invalid. Should be less than %d\n",
41 		       reg, p->number_of_regs);
42 		return -1;
43 	}
44 
45 	return 0;
46 }
47 
48 int pmic_set_output(struct pmic *p, u32 reg, int out, int on)
49 {
50 	u32 val;
51 
52 	if (pmic_reg_read(p, reg, &val))
53 		return -1;
54 
55 	if (on)
56 		val |= out;
57 	else
58 		val &= ~out;
59 
60 	if (pmic_reg_write(p, reg, val))
61 		return -1;
62 
63 	return 0;
64 }
65 
66 static void pmic_show_info(struct pmic *p)
67 {
68 	printf("PMIC: %s\n", p->name);
69 }
70 
71 static int pmic_dump(struct pmic *p)
72 {
73 	int i, ret;
74 	u32 val;
75 
76 	if (!p) {
77 		puts("Wrong PMIC name!\n");
78 		return -1;
79 	}
80 
81 	pmic_show_info(p);
82 	for (i = 0; i < p->number_of_regs; i++) {
83 		ret = pmic_reg_read(p, i, &val);
84 		if (ret)
85 			puts("PMIC: Registers dump failed\n");
86 
87 		if (!(i % 8))
88 			printf("\n0x%02x: ", i);
89 
90 		printf("%08x ", val);
91 	}
92 	puts("\n");
93 	return 0;
94 }
95 
96 struct pmic *pmic_alloc(void)
97 {
98 	struct pmic *p;
99 
100 	p = calloc(sizeof(*p), 1);
101 	if (!p) {
102 		printf("%s: No available memory for allocation!\n", __func__);
103 		return NULL;
104 	}
105 
106 	list_add_tail(&p->list, &pmic_list);
107 
108 	debug("%s: new pmic struct: 0x%p\n", __func__, p);
109 
110 	return p;
111 }
112 
113 struct pmic *pmic_get(const char *s)
114 {
115 	struct pmic *p;
116 
117 	list_for_each_entry(p, &pmic_list, list) {
118 		if (strcmp(p->name, s) == 0) {
119 			debug("%s: pmic %s -> 0x%p\n", __func__, p->name, p);
120 			return p;
121 		}
122 	}
123 
124 	return NULL;
125 }
126 
127 const char *power_get_interface(int interface)
128 {
129 	const char *power_interface[] = {"I2C", "SPI", "|+|-|"};
130 	return power_interface[interface];
131 }
132 
133 static void pmic_list_names(void)
134 {
135 	struct pmic *p;
136 
137 	puts("PMIC devices:\n");
138 	list_for_each_entry(p, &pmic_list, list) {
139 		printf("name: %s bus: %s_%d\n", p->name,
140 		       power_get_interface(p->interface), p->bus);
141 	}
142 }
143 
144 int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
145 {
146 	u32 ret, reg, val;
147 	char *cmd, *name;
148 	struct pmic *p;
149 
150 	/* at least two arguments please */
151 	if (argc < 2)
152 		return CMD_RET_USAGE;
153 
154 	if (strcmp(argv[1], "list") == 0) {
155 		pmic_list_names();
156 		return CMD_RET_SUCCESS;
157 	}
158 
159 	name = argv[1];
160 	cmd = argv[2];
161 
162 	debug("%s: name: %s cmd: %s\n", __func__, name, cmd);
163 	p = pmic_get(name);
164 	if (!p)
165 		return CMD_RET_FAILURE;
166 
167 	if (strcmp(cmd, "dump") == 0) {
168 		if (pmic_dump(p))
169 			return CMD_RET_FAILURE;
170 		return CMD_RET_SUCCESS;
171 	}
172 
173 	if (strcmp(cmd, "read") == 0) {
174 		if (argc < 4)
175 			return CMD_RET_USAGE;
176 
177 		reg = simple_strtoul(argv[3], NULL, 16);
178 		ret = pmic_reg_read(p, reg, &val);
179 
180 		if (ret)
181 			puts("PMIC: Register read failed\n");
182 
183 		printf("\n0x%02x: 0x%08x\n", reg, val);
184 
185 		return CMD_RET_SUCCESS;
186 	}
187 
188 	if (strcmp(cmd, "write") == 0) {
189 		if (argc < 5)
190 			return CMD_RET_USAGE;
191 
192 		reg = simple_strtoul(argv[3], NULL, 16);
193 		val = simple_strtoul(argv[4], NULL, 16);
194 		pmic_reg_write(p, reg, val);
195 
196 		return CMD_RET_SUCCESS;
197 	}
198 
199 	if (strcmp(cmd, "bat") == 0) {
200 		if (argc < 4)
201 			return CMD_RET_USAGE;
202 
203 		if (strcmp(argv[3], "state") == 0)
204 			p->fg->fg_battery_check(p->pbat->fg, p);
205 
206 		if (strcmp(argv[3], "charge") == 0) {
207 			if (p->pbat) {
208 				printf("BAT: %s charging (ctrl+c to break)\n",
209 				       p->name);
210 				if (p->low_power_mode)
211 					p->low_power_mode();
212 				if (p->pbat->battery_charge)
213 					p->pbat->battery_charge(p);
214 			}
215 		}
216 
217 		return CMD_RET_SUCCESS;
218 	}
219 
220 	/* No subcommand found */
221 	return CMD_RET_SUCCESS;
222 }
223 
224 U_BOOT_CMD(
225 	pmic,	CONFIG_SYS_MAXARGS, 1, do_pmic,
226 	"PMIC",
227 	"list - list available PMICs\n"
228 	"pmic name dump - dump named PMIC registers\n"
229 	"pmic name read <reg> - read register\n"
230 	"pmic name write <reg> <value> - write register\n"
231 	"pmic name bat state - write register\n"
232 	"pmic name bat charge - write register\n"
233 );
234