blob: 65296c5fc3a0dc26c334910e169e4f2431c44c4e [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 Delaunay537581d2019-02-04 11:26:19 +010010#include <sysreset.h>
11#include <dm/device.h>
12#include <dm/lists.h>
Patrick Delaunay3cba4512018-03-12 10:46:12 +010013#include <power/pmic.h>
Patrick Delaunay91be5942019-02-04 11:26:16 +010014#include <power/stpmic1.h>
Patrick Delaunay3cba4512018-03-12 10:46:12 +010015
Patrick Delaunayd79218f2019-02-04 11:26:17 +010016#define STPMIC1_NUM_OF_REGS 0x100
Patrick Delaunay3cba4512018-03-12 10:46:12 +010017
Patrick Delaunayd592d132019-02-04 11:26:22 +010018#define STPMIC1_NVM_SIZE 8
19#define STPMIC1_NVM_POLL_TIMEOUT 100000
20#define STPMIC1_NVM_START_ADDRESS 0xf8
21
22enum pmic_nvm_op {
23 SHADOW_READ,
24 SHADOW_WRITE,
25 NVM_READ,
26 NVM_WRITE,
27};
28
Patrick Delaunayd79218f2019-02-04 11:26:17 +010029#if CONFIG_IS_ENABLED(DM_REGULATOR)
30static const struct pmic_child_info stpmic1_children_info[] = {
31 { .prefix = "ldo", .driver = "stpmic1_ldo" },
32 { .prefix = "buck", .driver = "stpmic1_buck" },
33 { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" },
34 { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" },
35 { .prefix = "boost", .driver = "stpmic1_boost" },
Patrice Chotard0de05412018-04-26 17:13:10 +020036 { },
37};
Patrick Delaunayd79218f2019-02-04 11:26:17 +010038#endif /* DM_REGULATOR */
Patrice Chotard0de05412018-04-26 17:13:10 +020039
Patrick Delaunayd79218f2019-02-04 11:26:17 +010040static int stpmic1_reg_count(struct udevice *dev)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010041{
Patrick Delaunayd79218f2019-02-04 11:26:17 +010042 return STPMIC1_NUM_OF_REGS;
Patrick Delaunay3cba4512018-03-12 10:46:12 +010043}
44
Patrick Delaunayd79218f2019-02-04 11:26:17 +010045static int stpmic1_write(struct udevice *dev, uint reg, const uint8_t *buff,
46 int len)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010047{
48 int ret;
49
50 ret = dm_i2c_write(dev, reg, buff, len);
51 if (ret)
52 dev_err(dev, "%s: failed to write register %#x :%d",
53 __func__, reg, ret);
54
55 return ret;
56}
57
Patrick Delaunayd79218f2019-02-04 11:26:17 +010058static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
Patrick Delaunay3cba4512018-03-12 10:46:12 +010059{
60 int ret;
61
62 ret = dm_i2c_read(dev, reg, buff, len);
63 if (ret)
64 dev_err(dev, "%s: failed to read register %#x : %d",
65 __func__, reg, ret);
66
67 return ret;
68}
69
Patrick Delaunayd79218f2019-02-04 11:26:17 +010070static int stpmic1_bind(struct udevice *dev)
Patrice Chotard0de05412018-04-26 17:13:10 +020071{
Patrick Delaunayd79218f2019-02-04 11:26:17 +010072#if CONFIG_IS_ENABLED(DM_REGULATOR)
Patrice Chotard0de05412018-04-26 17:13:10 +020073 ofnode regulators_node;
74 int children;
75
76 regulators_node = dev_read_subnode(dev, "regulators");
77 if (!ofnode_valid(regulators_node)) {
Patrick Delaunayd79218f2019-02-04 11:26:17 +010078 dev_dbg(dev, "regulators subnode not found!");
Patrice Chotard0de05412018-04-26 17:13:10 +020079 return -ENXIO;
80 }
81 dev_dbg(dev, "found regulators subnode\n");
82
83 children = pmic_bind_children(dev, regulators_node,
Patrick Delaunayd79218f2019-02-04 11:26:17 +010084 stpmic1_children_info);
Patrice Chotard0de05412018-04-26 17:13:10 +020085 if (!children)
86 dev_dbg(dev, "no child found\n");
Patrick Delaunayd79218f2019-02-04 11:26:17 +010087#endif /* DM_REGULATOR */
Patrice Chotard0de05412018-04-26 17:13:10 +020088
Patrick Delaunay537581d2019-02-04 11:26:19 +010089 if (CONFIG_IS_ENABLED(SYSRESET))
90 return device_bind_driver(dev, "stpmic1-sysreset",
91 "stpmic1-sysreset", NULL);
92
Patrice Chotard0de05412018-04-26 17:13:10 +020093 return 0;
94}
95
Patrick Delaunayd79218f2019-02-04 11:26:17 +010096static struct dm_pmic_ops stpmic1_ops = {
97 .reg_count = stpmic1_reg_count,
98 .read = stpmic1_read,
99 .write = stpmic1_write,
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100100};
101
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100102static const struct udevice_id stpmic1_ids[] = {
103 { .compatible = "st,stpmic1" },
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100104 { }
105};
106
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100107U_BOOT_DRIVER(pmic_stpmic1) = {
108 .name = "stpmic1_pmic",
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100109 .id = UCLASS_PMIC,
Patrick Delaunayd79218f2019-02-04 11:26:17 +0100110 .of_match = stpmic1_ids,
111 .bind = stpmic1_bind,
112 .ops = &stpmic1_ops,
Patrick Delaunay3cba4512018-03-12 10:46:12 +0100113};
Patrick Delaunay537581d2019-02-04 11:26:19 +0100114
Patrick Delaunayd592d132019-02-04 11:26:22 +0100115#ifndef CONFIG_SPL_BUILD
116static int stpmic1_nvm_rw(u8 addr, u8 *buf, int buf_len, enum pmic_nvm_op op)
117{
118 struct udevice *dev;
119 unsigned long timeout;
120 u8 cmd = STPMIC1_NVM_CMD_READ;
121 int ret;
122
123 ret = uclass_get_device_by_driver(UCLASS_PMIC,
124 DM_GET_DRIVER(pmic_stpmic1), &dev);
125 if (ret)
126 /* No PMIC on power discrete board */
127 return -EOPNOTSUPP;
128
129 if (addr < STPMIC1_NVM_START_ADDRESS)
130 return -EACCES;
131
132 if (op == SHADOW_READ)
133 return pmic_read(dev, addr, buf, buf_len);
134
135 if (op == SHADOW_WRITE)
136 return pmic_write(dev, addr, buf, buf_len);
137
138 if (op == NVM_WRITE) {
139 cmd = STPMIC1_NVM_CMD_PROGRAM;
140
141 ret = pmic_write(dev, addr, buf, buf_len);
142 if (ret < 0)
143 return ret;
144 }
145
146 ret = pmic_reg_read(dev, STPMIC1_NVM_CR);
147 if (ret < 0)
148 return ret;
149
150 ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd);
151 if (ret < 0)
152 return ret;
153
154 timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT;
155 for (;;) {
156 ret = pmic_reg_read(dev, STPMIC1_NVM_SR);
157 if (ret < 0)
158 return ret;
159
160 if (!(ret & STPMIC1_NVM_BUSY))
161 break;
162
163 if (time_after(timer_get_us(), timeout))
164 break;
165 }
166
167 if (ret & STPMIC1_NVM_BUSY)
168 return -ETIMEDOUT;
169
170 if (op == NVM_READ) {
171 ret = pmic_read(dev, addr, buf, buf_len);
172 if (ret < 0)
173 return ret;
174 }
175
176 return 0;
177}
178
179int stpmic1_shadow_read_byte(u8 addr, u8 *buf)
180{
181 return stpmic1_nvm_rw(addr, buf, 1, SHADOW_READ);
182}
183
184int stpmic1_shadow_write_byte(u8 addr, u8 *buf)
185{
186 return stpmic1_nvm_rw(addr, buf, 1, SHADOW_WRITE);
187}
188
189int stpmic1_nvm_read_byte(u8 addr, u8 *buf)
190{
191 return stpmic1_nvm_rw(addr, buf, 1, NVM_READ);
192}
193
194int stpmic1_nvm_write_byte(u8 addr, u8 *buf)
195{
196 return stpmic1_nvm_rw(addr, buf, 1, NVM_WRITE);
197}
198
199int stpmic1_nvm_read_all(u8 *buf, int buf_len)
200{
201 if (buf_len != STPMIC1_NVM_SIZE)
202 return -EINVAL;
203
204 return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS,
205 buf, buf_len, NVM_READ);
206}
207
208int stpmic1_nvm_write_all(u8 *buf, int buf_len)
209{
210 if (buf_len != STPMIC1_NVM_SIZE)
211 return -EINVAL;
212
213 return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS,
214 buf, buf_len, NVM_WRITE);
215}
216#endif /* CONFIG_SPL_BUILD */
217
Patrick Delaunay537581d2019-02-04 11:26:19 +0100218#ifdef CONFIG_SYSRESET
219static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type)
220{
221 struct udevice *pmic_dev;
222 int ret;
223
224 if (type != SYSRESET_POWER)
225 return -EPROTONOSUPPORT;
226
227 ret = uclass_get_device_by_driver(UCLASS_PMIC,
228 DM_GET_DRIVER(pmic_stpmic1),
229 &pmic_dev);
230
231 if (ret)
232 return -EOPNOTSUPP;
233
234 ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR);
235 if (ret < 0)
236 return ret;
237
238 ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR,
239 ret | STPMIC1_SWOFF | STPMIC1_RREQ_EN);
240 if (ret < 0)
241 return ret;
242
243 return -EINPROGRESS;
244}
245
246static struct sysreset_ops stpmic1_sysreset_ops = {
247 .request = stpmic1_sysreset_request,
248};
249
250U_BOOT_DRIVER(stpmic1_sysreset) = {
251 .name = "stpmic1-sysreset",
252 .id = UCLASS_SYSRESET,
253 .ops = &stpmic1_sysreset_ops,
254};
255#endif