blob: c99a0c27b3360ad5f13655f99380f56c660cf0f4 [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
Patrick Delaunay3cba4512018-03-12 10:46:12 +01006#include <dm.h>
7#include <errno.h>
8#include <i2c.h>
Patrick Delaunayc9a5d392019-08-02 13:08:03 +02009#include <misc.h>
Patrick Delaunay537581d2019-02-04 11:26:19 +010010#include <sysreset.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070011#include <time.h>
Patrick Delaunay537581d2019-02-04 11:26:19 +010012#include <dm/device.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <dm/device_compat.h>
Patrick Delaunay537581d2019-02-04 11:26:19 +010014#include <dm/lists.h>
Patrick Delaunay3cba4512018-03-12 10:46:12 +010015#include <power/pmic.h>
Patrick Delaunay91be5942019-02-04 11:26:16 +010016#include <power/stpmic1.h>
Patrick Delaunay3cba4512018-03-12 10:46:12 +010017
Patrick Delaunayd79218f2019-02-04 11:26:17 +010018#define STPMIC1_NUM_OF_REGS 0x100
Patrick Delaunay3cba4512018-03-12 10:46:12 +010019
Patrick Delaunayd592d132019-02-04 11:26:22 +010020#define STPMIC1_NVM_SIZE 8
21#define STPMIC1_NVM_POLL_TIMEOUT 100000
22#define STPMIC1_NVM_START_ADDRESS 0xf8
23
24enum pmic_nvm_op {
25 SHADOW_READ,
26 SHADOW_WRITE,
27 NVM_READ,
28 NVM_WRITE,
29};
30
Patrick Delaunayd79218f2019-02-04 11:26:17 +010031#if CONFIG_IS_ENABLED(DM_REGULATOR)
32static const struct pmic_child_info stpmic1_children_info[] = {
33 { .prefix = "ldo", .driver = "stpmic1_ldo" },
34 { .prefix = "buck", .driver = "stpmic1_buck" },
35 { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" },
Patrick Delaunay7d129dc2023-04-27 15:36:38 +020036 { .prefix = "vref-ddr", .driver = "stpmic1_vref_ddr" },
Patrick Delaunayd79218f2019-02-04 11:26:17 +010037 { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" },
Patrick Delaunay7d129dc2023-04-27 15:36:38 +020038 { .prefix = "pwr-sw", .driver = "stpmic1_pwr_sw" },
Patrick Delaunayd79218f2019-02-04 11:26:17 +010039 { .prefix = "boost", .driver = "stpmic1_boost" },
Patrice Chotard0de05412018-04-26 17:13:10 +020040 { },
41};
Patrick Delaunayd79218f2019-02-04 11:26:17 +010042#endif /* DM_REGULATOR */
Patrice Chotard0de05412018-04-26 17:13:10 +020043
Patrick Delaunayd79218f2019-02-04 11:26:17 +010044static int stpmic1_reg_count(struct udevice *dev)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010045{
Patrick Delaunayd79218f2019-02-04 11:26:17 +010046 return STPMIC1_NUM_OF_REGS;
Patrick Delaunay3cba4512018-03-12 10:46:12 +010047}
48
Patrick Delaunayd79218f2019-02-04 11:26:17 +010049static int stpmic1_write(struct udevice *dev, uint reg, const uint8_t *buff,
50 int len)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010051{
52 int ret;
53
54 ret = dm_i2c_write(dev, reg, buff, len);
55 if (ret)
56 dev_err(dev, "%s: failed to write register %#x :%d",
57 __func__, reg, ret);
58
59 return ret;
60}
61
Patrick Delaunayd79218f2019-02-04 11:26:17 +010062static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010063{
64 int ret;
65
66 ret = dm_i2c_read(dev, reg, buff, len);
67 if (ret)
68 dev_err(dev, "%s: failed to read register %#x : %d",
69 __func__, reg, ret);
70
71 return ret;
72}
73
Patrick Delaunayd79218f2019-02-04 11:26:17 +010074static int stpmic1_bind(struct udevice *dev)
Patrice Chotard0de05412018-04-26 17:13:10 +020075{
Patrick Delaunayc9a5d392019-08-02 13:08:03 +020076 int ret;
Patrick Delaunayd79218f2019-02-04 11:26:17 +010077#if CONFIG_IS_ENABLED(DM_REGULATOR)
Patrice Chotard0de05412018-04-26 17:13:10 +020078 ofnode regulators_node;
79 int children;
80
81 regulators_node = dev_read_subnode(dev, "regulators");
82 if (!ofnode_valid(regulators_node)) {
Patrick Delaunayd79218f2019-02-04 11:26:17 +010083 dev_dbg(dev, "regulators subnode not found!");
Patrice Chotard0de05412018-04-26 17:13:10 +020084 return -ENXIO;
85 }
86 dev_dbg(dev, "found regulators subnode\n");
87
88 children = pmic_bind_children(dev, regulators_node,
Patrick Delaunayd79218f2019-02-04 11:26:17 +010089 stpmic1_children_info);
Patrice Chotard0de05412018-04-26 17:13:10 +020090 if (!children)
91 dev_dbg(dev, "no child found\n");
Patrick Delaunayd79218f2019-02-04 11:26:17 +010092#endif /* DM_REGULATOR */
Patrice Chotard0de05412018-04-26 17:13:10 +020093
Patrick Delaunayc9a5d392019-08-02 13:08:03 +020094 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
95 ret = device_bind_driver(dev, "stpmic1-nvm",
96 "stpmic1-nvm", NULL);
97 if (ret)
98 return ret;
99 }
100
Patrick Delaunay537581d2019-02-04 11:26:19 +0100101 if (CONFIG_IS_ENABLED(SYSRESET))
102 return device_bind_driver(dev, "stpmic1-sysreset",
103 "stpmic1-sysreset", NULL);
104
Patrice Chotard0de05412018-04-26 17:13:10 +0200105 return 0;
106}
107
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100108static struct dm_pmic_ops stpmic1_ops = {
109 .reg_count = stpmic1_reg_count,
110 .read = stpmic1_read,
111 .write = stpmic1_write,
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100112};
113
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100114static const struct udevice_id stpmic1_ids[] = {
115 { .compatible = "st,stpmic1" },
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100116 { }
117};
118
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100119U_BOOT_DRIVER(pmic_stpmic1) = {
120 .name = "stpmic1_pmic",
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100121 .id = UCLASS_PMIC,
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100122 .of_match = stpmic1_ids,
123 .bind = stpmic1_bind,
124 .ops = &stpmic1_ops,
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100125};
Patrick Delaunay537581d2019-02-04 11:26:19 +0100126
Patrick Delaunayd592d132019-02-04 11:26:22 +0100127#ifndef CONFIG_SPL_BUILD
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200128static int stpmic1_nvm_rw(struct udevice *dev, u8 addr, u8 *buf, int buf_len,
129 enum pmic_nvm_op op)
Patrick Delaunayd592d132019-02-04 11:26:22 +0100130{
Patrick Delaunayd592d132019-02-04 11:26:22 +0100131 unsigned long timeout;
132 u8 cmd = STPMIC1_NVM_CMD_READ;
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200133 int ret, len = buf_len;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100134
135 if (addr < STPMIC1_NVM_START_ADDRESS)
136 return -EACCES;
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200137 if (addr + buf_len > STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE)
138 len = STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE - addr;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100139
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200140 if (op == SHADOW_READ) {
141 ret = pmic_read(dev, addr, buf, len);
142 if (ret < 0)
143 return ret;
144 else
145 return len;
146 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100147
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200148 if (op == SHADOW_WRITE) {
149 ret = pmic_write(dev, addr, buf, len);
150 if (ret < 0)
151 return ret;
152 else
153 return len;
154 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100155
156 if (op == NVM_WRITE) {
157 cmd = STPMIC1_NVM_CMD_PROGRAM;
158
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200159 ret = pmic_write(dev, addr, buf, len);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100160 if (ret < 0)
161 return ret;
162 }
163
164 ret = pmic_reg_read(dev, STPMIC1_NVM_CR);
165 if (ret < 0)
166 return ret;
167
168 ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd);
169 if (ret < 0)
170 return ret;
171
172 timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT;
173 for (;;) {
174 ret = pmic_reg_read(dev, STPMIC1_NVM_SR);
175 if (ret < 0)
176 return ret;
177
178 if (!(ret & STPMIC1_NVM_BUSY))
179 break;
180
181 if (time_after(timer_get_us(), timeout))
182 break;
183 }
184
185 if (ret & STPMIC1_NVM_BUSY)
186 return -ETIMEDOUT;
187
188 if (op == NVM_READ) {
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200189 ret = pmic_read(dev, addr, buf, len);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100190 if (ret < 0)
191 return ret;
192 }
193
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200194 return len;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100195}
196
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200197static int stpmic1_nvm_read(struct udevice *dev, int offset,
198 void *buf, int size)
Patrick Delaunayd592d132019-02-04 11:26:22 +0100199{
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200200 enum pmic_nvm_op op = NVM_READ;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100201
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200202 if (offset < 0) {
203 op = SHADOW_READ;
204 offset = -offset;
205 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100206
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200207 return stpmic1_nvm_rw(dev->parent, offset, buf, size, op);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100208}
209
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200210static int stpmic1_nvm_write(struct udevice *dev, int offset,
211 const void *buf, int size)
Patrick Delaunayd592d132019-02-04 11:26:22 +0100212{
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200213 enum pmic_nvm_op op = NVM_WRITE;
Patrick Delaunayd592d132019-02-04 11:26:22 +0100214
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200215 if (offset < 0) {
216 op = SHADOW_WRITE;
217 offset = -offset;
218 }
Patrick Delaunayd592d132019-02-04 11:26:22 +0100219
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200220 return stpmic1_nvm_rw(dev->parent, offset, (void *)buf, size, op);
Patrick Delaunayd592d132019-02-04 11:26:22 +0100221}
222
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200223static const struct misc_ops stpmic1_nvm_ops = {
224 .read = stpmic1_nvm_read,
225 .write = stpmic1_nvm_write,
226};
Patrick Delaunayd592d132019-02-04 11:26:22 +0100227
Patrick Delaunayc9a5d392019-08-02 13:08:03 +0200228U_BOOT_DRIVER(stpmic1_nvm) = {
229 .name = "stpmic1-nvm",
230 .id = UCLASS_MISC,
231 .ops = &stpmic1_nvm_ops,
232};
Patrick Delaunayd592d132019-02-04 11:26:22 +0100233#endif /* CONFIG_SPL_BUILD */
234
Patrick Delaunay537581d2019-02-04 11:26:19 +0100235#ifdef CONFIG_SYSRESET
236static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type)
237{
Patrick Delaunay8844c4a2019-08-02 13:08:04 +0200238 struct udevice *pmic_dev = dev->parent;
Patrick Delaunay537581d2019-02-04 11:26:19 +0100239 int ret;
240
Patrick Delaunayf6d02202019-05-20 09:47:07 +0200241 if (type != SYSRESET_POWER && type != SYSRESET_POWER_OFF)
Patrick Delaunay537581d2019-02-04 11:26:19 +0100242 return -EPROTONOSUPPORT;
243
Patrick Delaunay537581d2019-02-04 11:26:19 +0100244 ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR);
245 if (ret < 0)
246 return ret;
247
Patrick Delaunayf6d02202019-05-20 09:47:07 +0200248 ret |= STPMIC1_SWOFF;
249 ret &= ~STPMIC1_RREQ_EN;
250 /* request Power Cycle */
251 if (type == SYSRESET_POWER)
252 ret |= STPMIC1_RREQ_EN;
253
254 ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, ret);
Patrick Delaunay537581d2019-02-04 11:26:19 +0100255 if (ret < 0)
256 return ret;
257
258 return -EINPROGRESS;
259}
260
261static struct sysreset_ops stpmic1_sysreset_ops = {
262 .request = stpmic1_sysreset_request,
263};
264
265U_BOOT_DRIVER(stpmic1_sysreset) = {
266 .name = "stpmic1-sysreset",
267 .id = UCLASS_SYSRESET,
268 .ops = &stpmic1_sysreset_ops,
269};
270#endif