blob: 509baed7eca3f3a935aa6c2cd87b4161263a9387 [file] [log] [blame]
Tom Rini8b0c8a12018-05-06 18:27:01 -04001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
Patrick Delaunay3cba4512018-03-12 10:46:12 +01002/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
Patrick Delaunay3cba4512018-03-12 10:46:12 +01004 */
5
6#include <common.h>
7#include <dm.h>
8#include <errno.h>
9#include <i2c.h>
Patrick Delaunayc9a5d392019-08-02 13:08:03 +020010#include <misc.h>
Patrick Delaunay537581d2019-02-04 11:26:19 +010011#include <sysreset.h>
12#include <dm/device.h>
13#include <dm/lists.h>
Patrick Delaunay3cba4512018-03-12 10:46:12 +010014#include <power/pmic.h>
Patrick Delaunay91be5942019-02-04 11:26:16 +010015#include <power/stpmic1.h>
Patrick Delaunay3cba4512018-03-12 10:46:12 +010016
Patrick Delaunayd79218f2019-02-04 11:26:17 +010017#define STPMIC1_NUM_OF_REGS 0x100
Patrick Delaunay3cba4512018-03-12 10:46:12 +010018
Patrick Delaunayd592d132019-02-04 11:26:22 +010019#define STPMIC1_NVM_SIZE 8
20#define STPMIC1_NVM_POLL_TIMEOUT 100000
21#define STPMIC1_NVM_START_ADDRESS 0xf8
22
23enum pmic_nvm_op {
24 SHADOW_READ,
25 SHADOW_WRITE,
26 NVM_READ,
27 NVM_WRITE,
28};
29
Patrick Delaunayd79218f2019-02-04 11:26:17 +010030#if CONFIG_IS_ENABLED(DM_REGULATOR)
31static const struct pmic_child_info stpmic1_children_info[] = {
32 { .prefix = "ldo", .driver = "stpmic1_ldo" },
33 { .prefix = "buck", .driver = "stpmic1_buck" },
34 { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" },
35 { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" },
36 { .prefix = "boost", .driver = "stpmic1_boost" },
Patrice Chotard0de05412018-04-26 17:13:10 +020037 { },
38};
Patrick Delaunayd79218f2019-02-04 11:26:17 +010039#endif /* DM_REGULATOR */
Patrice Chotard0de05412018-04-26 17:13:10 +020040
Patrick Delaunayd79218f2019-02-04 11:26:17 +010041static int stpmic1_reg_count(struct udevice *dev)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010042{
Patrick Delaunayd79218f2019-02-04 11:26:17 +010043 return STPMIC1_NUM_OF_REGS;
Patrick Delaunay3cba4512018-03-12 10:46:12 +010044}
45
Patrick Delaunayd79218f2019-02-04 11:26:17 +010046static int stpmic1_write(struct udevice *dev, uint reg, const uint8_t *buff,
47 int len)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010048{
49 int ret;
50
51 ret = dm_i2c_write(dev, reg, buff, len);
52 if (ret)
53 dev_err(dev, "%s: failed to write register %#x :%d",
54 __func__, reg, ret);
55
56 return ret;
57}
58
Patrick Delaunayd79218f2019-02-04 11:26:17 +010059static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010060{
61 int ret;
62
63 ret = dm_i2c_read(dev, reg, buff, len);
64 if (ret)
65 dev_err(dev, "%s: failed to read register %#x : %d",
66 __func__, reg, ret);
67
68 return ret;
69}
70
Patrick Delaunayd79218f2019-02-04 11:26:17 +010071static int stpmic1_bind(struct udevice *dev)
Patrice Chotard0de05412018-04-26 17:13:10 +020072{
Patrick Delaunayc9a5d392019-08-02 13:08:03 +020073 int ret;
Patrick Delaunayd79218f2019-02-04 11:26:17 +010074#if CONFIG_IS_ENABLED(DM_REGULATOR)
Patrice Chotard0de05412018-04-26 17:13:10 +020075 ofnode regulators_node;
76 int children;
77
78 regulators_node = dev_read_subnode(dev, "regulators");
79 if (!ofnode_valid(regulators_node)) {
Patrick Delaunayd79218f2019-02-04 11:26:17 +010080 dev_dbg(dev, "regulators subnode not found!");
Patrice Chotard0de05412018-04-26 17:13:10 +020081 return -ENXIO;
82 }
83 dev_dbg(dev, "found regulators subnode\n");
84
85 children = pmic_bind_children(dev, regulators_node,
Patrick Delaunayd79218f2019-02-04 11:26:17 +010086 stpmic1_children_info);
Patrice Chotard0de05412018-04-26 17:13:10 +020087 if (!children)
88 dev_dbg(dev, "no child found\n");
Patrick Delaunayd79218f2019-02-04 11:26:17 +010089#endif /* DM_REGULATOR */
Patrice Chotard0de05412018-04-26 17:13:10 +020090
Patrick Delaunayc9a5d392019-08-02 13:08:03 +020091 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
92 ret = device_bind_driver(dev, "stpmic1-nvm",
93 "stpmic1-nvm", NULL);
94 if (ret)
95 return ret;
96 }
97
Patrick Delaunay537581d2019-02-04 11:26:19 +010098 if (CONFIG_IS_ENABLED(SYSRESET))
99 return device_bind_driver(dev, "stpmic1-sysreset",
100 "stpmic1-sysreset", NULL);
101
Patrice Chotard0de05412018-04-26 17:13:10 +0200102 return 0;
103}
104
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100105static struct dm_pmic_ops stpmic1_ops = {
106 .reg_count = stpmic1_reg_count,
107 .read = stpmic1_read,
108 .write = stpmic1_write,
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100109};
110
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100111static const struct udevice_id stpmic1_ids[] = {
112 { .compatible = "st,stpmic1" },
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100113 { }
114};
115
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100116U_BOOT_DRIVER(pmic_stpmic1) = {
117 .name = "stpmic1_pmic",
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100118 .id = UCLASS_PMIC,
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100119 .of_match = stpmic1_ids,
120 .bind = stpmic1_bind,
121 .ops = &stpmic1_ops,
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100122};
Patrick Delaunay537581d2019-02-04 11:26:19 +0100123
Patrick Delaunayd592d132019-02-04 11:26:22 +0100124#ifndef CONFIG_SPL_BUILD
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200125static int stpmic1_nvm_rw(struct udevice *dev, u8 addr, u8 *buf, int buf_len,
126 enum pmic_nvm_op op)
Patrick Delaunayd592d132019-02-04 11:26:22 +0100127{
Patrick Delaunayd592d132019-02-04 11:26:22 +0100128 unsigned long timeout;
129 u8 cmd = STPMIC1_NVM_CMD_READ;
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200130 int ret, len = buf_len;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100131
132 if (addr < STPMIC1_NVM_START_ADDRESS)
133 return -EACCES;
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200134 if (addr + buf_len > STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE)
135 len = STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE - addr;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100136
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200137 if (op == SHADOW_READ) {
138 ret = pmic_read(dev, addr, buf, len);
139 if (ret < 0)
140 return ret;
141 else
142 return len;
143 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100144
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200145 if (op == SHADOW_WRITE) {
146 ret = pmic_write(dev, addr, buf, len);
147 if (ret < 0)
148 return ret;
149 else
150 return len;
151 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100152
153 if (op == NVM_WRITE) {
154 cmd = STPMIC1_NVM_CMD_PROGRAM;
155
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200156 ret = pmic_write(dev, addr, buf, len);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100157 if (ret < 0)
158 return ret;
159 }
160
161 ret = pmic_reg_read(dev, STPMIC1_NVM_CR);
162 if (ret < 0)
163 return ret;
164
165 ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd);
166 if (ret < 0)
167 return ret;
168
169 timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT;
170 for (;;) {
171 ret = pmic_reg_read(dev, STPMIC1_NVM_SR);
172 if (ret < 0)
173 return ret;
174
175 if (!(ret & STPMIC1_NVM_BUSY))
176 break;
177
178 if (time_after(timer_get_us(), timeout))
179 break;
180 }
181
182 if (ret & STPMIC1_NVM_BUSY)
183 return -ETIMEDOUT;
184
185 if (op == NVM_READ) {
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200186 ret = pmic_read(dev, addr, buf, len);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100187 if (ret < 0)
188 return ret;
189 }
190
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200191 return len;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100192}
193
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200194static int stpmic1_nvm_read(struct udevice *dev, int offset,
195 void *buf, int size)
Patrick Delaunayd592d132019-02-04 11:26:22 +0100196{
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200197 enum pmic_nvm_op op = NVM_READ;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100198
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200199 if (offset < 0) {
200 op = SHADOW_READ;
201 offset = -offset;
202 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100203
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200204 return stpmic1_nvm_rw(dev->parent, offset, buf, size, op);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100205}
206
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200207static int stpmic1_nvm_write(struct udevice *dev, int offset,
208 const void *buf, int size)
Patrick Delaunayd592d132019-02-04 11:26:22 +0100209{
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200210 enum pmic_nvm_op op = NVM_WRITE;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100211
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200212 if (offset < 0) {
213 op = SHADOW_WRITE;
214 offset = -offset;
215 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100216
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200217 return stpmic1_nvm_rw(dev->parent, offset, (void *)buf, size, op);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100218}
219
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200220static const struct misc_ops stpmic1_nvm_ops = {
221 .read = stpmic1_nvm_read,
222 .write = stpmic1_nvm_write,
223};
Patrick Delaunayd592d132019-02-04 11:26:22 +0100224
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200225U_BOOT_DRIVER(stpmic1_nvm) = {
226 .name = "stpmic1-nvm",
227 .id = UCLASS_MISC,
228 .ops = &stpmic1_nvm_ops,
229};
Patrick Delaunayd592d132019-02-04 11:26:22 +0100230#endif /* CONFIG_SPL_BUILD */
231
Patrick Delaunay537581d2019-02-04 11:26:19 +0100232#ifdef CONFIG_SYSRESET
233static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type)
234{
235 struct udevice *pmic_dev;
236 int ret;
237
Patrick Delaunayf6d02202019-05-20 09:47:07 +0200238 if (type != SYSRESET_POWER && type != SYSRESET_POWER_OFF)
Patrick Delaunay537581d2019-02-04 11:26:19 +0100239 return -EPROTONOSUPPORT;
240
241 ret = uclass_get_device_by_driver(UCLASS_PMIC,
242 DM_GET_DRIVER(pmic_stpmic1),
243 &pmic_dev);
244
245 if (ret)
246 return -EOPNOTSUPP;
247
248 ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR);
249 if (ret < 0)
250 return ret;
251
Patrick Delaunayf6d02202019-05-20 09:47:07 +0200252 ret |= STPMIC1_SWOFF;
253 ret &= ~STPMIC1_RREQ_EN;
254 /* request Power Cycle */
255 if (type == SYSRESET_POWER)
256 ret |= STPMIC1_RREQ_EN;
257
258 ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, ret);
Patrick Delaunay537581d2019-02-04 11:26:19 +0100259 if (ret < 0)
260 return ret;
261
262 return -EINPROGRESS;
263}
264
265static struct sysreset_ops stpmic1_sysreset_ops = {
266 .request = stpmic1_sysreset_request,
267};
268
269U_BOOT_DRIVER(stpmic1_sysreset) = {
270 .name = "stpmic1-sysreset",
271 .id = UCLASS_SYSRESET,
272 .ops = &stpmic1_sysreset_ops,
273};
274#endif