blob: 095d8a51bef062c76712c96e5df574a422110a47 [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>
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000013#include <malloc.h>
Łukasz Majewski16db0622011-10-06 02:37:34 +000014#include <linux/types.h>
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000015#include <linux/list.h>
16#include <power/pmic.h>
Łukasz Majewski16db0622011-10-06 02:37:34 +000017
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000018static LIST_HEAD(pmic_list);
Łukasz Majewski16db0622011-10-06 02:37:34 +000019
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000020int check_reg(struct pmic *p, u32 reg)
Łukasz Majewski16db0622011-10-06 02:37:34 +000021{
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000022 if (reg >= p->number_of_regs) {
Łukasz Majewski16db0622011-10-06 02:37:34 +000023 printf("<reg num> = %d is invalid. Should be less than %d\n",
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000024 reg, p->number_of_regs);
Jaehoon Chung10e80f32016-12-15 20:49:50 +090025 return -EINVAL;
Łukasz Majewski16db0622011-10-06 02:37:34 +000026 }
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000027
Łukasz Majewski16db0622011-10-06 02:37:34 +000028 return 0;
29}
30
31int 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))
Jaehoon Chung10e80f32016-12-15 20:49:50 +090036 return -ENOTSUPP;
Łukasz Majewski16db0622011-10-06 02:37:34 +000037
38 if (on)
39 val |= out;
40 else
41 val &= ~out;
42
43 if (pmic_reg_write(p, reg, val))
Jaehoon Chung10e80f32016-12-15 20:49:50 +090044 return -ENOTSUPP;
Łukasz Majewski16db0622011-10-06 02:37:34 +000045
46 return 0;
47}
48
Łukasz Majewski1c6dba12012-11-13 03:21:55 +000049struct 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
66struct 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;
Łukasz Majewski16db0622011-10-06 02:37:34 +000078}
79
Tom Riniec896572017-12-22 12:27:14 -050080#ifndef CONFIG_SPL_BUILD
81static 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
106static const char *power_get_interface(int interface)
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000107{
108 const char *power_interface[] = {"I2C", "SPI", "|+|-|"};
109 return power_interface[interface];
110}
111
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000112static void pmic_list_names(void)
Łukasz Majewski16db0622011-10-06 02:37:34 +0000113{
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000114 struct pmic *p;
115
116 puts("PMIC devices:\n");
117 list_for_each_entry(p, &pmic_list, list) {
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000118 printf("name: %s bus: %s_%d\n", p->name,
119 power_get_interface(p->interface), p->bus);
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000120 }
Łukasz Majewski16db0622011-10-06 02:37:34 +0000121}
122
Tom Riniec896572017-12-22 12:27:14 -0500123static int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Łukasz Majewski16db0622011-10-06 02:37:34 +0000124{
125 u32 ret, reg, val;
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000126 char *cmd, *name;
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000127 struct pmic *p;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000128
Łukasz Majewski16db0622011-10-06 02:37:34 +0000129 /* at least two arguments please */
130 if (argc < 2)
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000131 return CMD_RET_USAGE;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000132
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000133 if (strcmp(argv[1], "list") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000134 pmic_list_names();
135 return CMD_RET_SUCCESS;
136 }
137
Łukasz Majewski25719232014-02-24 13:33:08 +0100138 if (argc < 3)
139 return CMD_RET_USAGE;
140
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000141 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
Łukasz Majewski16db0622011-10-06 02:37:34 +0000149 if (strcmp(cmd, "dump") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000150 if (pmic_dump(p))
151 return CMD_RET_FAILURE;
152 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000153 }
154
155 if (strcmp(cmd, "read") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000156 if (argc < 4)
157 return CMD_RET_USAGE;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000158
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000159 reg = simple_strtoul(argv[3], NULL, 16);
Łukasz Majewski16db0622011-10-06 02:37:34 +0000160 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
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000167 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000168 }
169
170 if (strcmp(cmd, "write") == 0) {
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000171 if (argc < 5)
172 return CMD_RET_USAGE;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000173
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000174 reg = simple_strtoul(argv[3], NULL, 16);
175 val = simple_strtoul(argv[4], NULL, 16);
Łukasz Majewski16db0622011-10-06 02:37:34 +0000176 pmic_reg_write(p, reg, val);
177
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000178 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000179 }
180
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000181 if (strcmp(cmd, "bat") == 0) {
182 if (argc < 4)
183 return CMD_RET_USAGE;
184
Piotr Wilczekdfb100d2013-09-26 14:43:35 +0200185 if (!p->pbat) {
186 printf("%s is not a battery\n", p->name);
187 return CMD_RET_FAILURE;
188 }
189
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000190 if (strcmp(argv[3], "state") == 0)
191 p->fg->fg_battery_check(p->pbat->fg, p);
192
193 if (strcmp(argv[3], "charge") == 0) {
Piotr Wilczekdfb100d2013-09-26 14:43:35 +0200194 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);
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000200 }
201
202 return CMD_RET_SUCCESS;
203 }
204
Łukasz Majewski16db0622011-10-06 02:37:34 +0000205 /* No subcommand found */
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000206 return CMD_RET_SUCCESS;
Łukasz Majewski16db0622011-10-06 02:37:34 +0000207}
208
209U_BOOT_CMD(
210 pmic, CONFIG_SYS_MAXARGS, 1, do_pmic,
211 "PMIC",
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000212 "list - list available PMICs\n"
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000213 "pmic name dump - dump named PMIC registers\n"
Łukasz Majewski1c6dba12012-11-13 03:21:55 +0000214 "pmic name read <reg> - read register\n"
Łukasz Majewski6328caf2012-11-13 03:22:12 +0000215 "pmic name write <reg> <value> - write register\n"
216 "pmic name bat state - write register\n"
217 "pmic name bat charge - write register\n"
Łukasz Majewski16db0622011-10-06 02:37:34 +0000218);
Tom Riniec896572017-12-22 12:27:14 -0500219#endif