Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/ti/am335x/am335x_pmic.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2012 Damjan Marion <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/cdefs.h>
30
/*
31
* TI TPS65217 PMIC companion chip for AM335x SoC sitting on I2C bus
32
*/
33
#include <sys/param.h>
34
#include <sys/systm.h>
35
#include <sys/eventhandler.h>
36
#include <sys/kernel.h>
37
#include <sys/module.h>
38
#include <sys/clock.h>
39
#include <sys/time.h>
40
#include <sys/bus.h>
41
#include <sys/proc.h>
42
#include <sys/reboot.h>
43
#include <sys/resource.h>
44
#include <sys/rman.h>
45
46
#include <dev/iicbus/iicbus.h>
47
#include <dev/iicbus/iiconf.h>
48
49
#include <dev/ofw/openfirm.h>
50
#include <dev/ofw/ofw_bus.h>
51
#include <dev/ofw/ofw_bus_subr.h>
52
53
#include <arm/ti/am335x/am335x_rtcvar.h>
54
#include <arm/ti/am335x/tps65217x.h>
55
56
#include "iicbus_if.h"
57
58
struct am335x_pmic_softc {
59
device_t sc_dev;
60
uint32_t sc_addr;
61
struct resource *sc_irq_res;
62
void *sc_intrhand;
63
};
64
65
static const char *tps65217_voreg_c[4] = {"4.10V", "4.15V", "4.20V", "4.25V"};
66
67
static int am335x_pmic_bootverbose = 0;
68
TUNABLE_INT("hw.am335x_pmic.bootverbose", &am335x_pmic_bootverbose);
69
static char am335x_pmic_vo[6];
70
TUNABLE_STR("hw.am335x_pmic.vo", am335x_pmic_vo, sizeof(am335x_pmic_vo));
71
72
static void am335x_pmic_shutdown(void *, int);
73
74
static int
75
am335x_pmic_read(device_t dev, uint8_t addr, uint8_t *data, uint8_t size)
76
{
77
return (iicdev_readfrom(dev, addr, data, size, IIC_INTRWAIT));
78
}
79
80
static int
81
am335x_pmic_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size)
82
{
83
return (iicdev_writeto(dev, address, data, size, IIC_INTRWAIT));
84
}
85
86
static void
87
am335x_pmic_intr(void *arg)
88
{
89
struct am335x_pmic_softc *sc = (struct am335x_pmic_softc *)arg;
90
struct tps65217_status_reg status_reg;
91
struct tps65217_int_reg int_reg;
92
int rv;
93
char notify_buf[16];
94
95
THREAD_SLEEPING_OK();
96
rv = am335x_pmic_read(sc->sc_dev, TPS65217_INT_REG, (uint8_t *)&int_reg, 1);
97
if (rv != 0) {
98
device_printf(sc->sc_dev, "Cannot read interrupt register\n");
99
THREAD_NO_SLEEPING();
100
return;
101
}
102
rv = am335x_pmic_read(sc->sc_dev, TPS65217_STATUS_REG, (uint8_t *)&status_reg, 1);
103
if (rv != 0) {
104
device_printf(sc->sc_dev, "Cannot read status register\n");
105
THREAD_NO_SLEEPING();
106
return;
107
}
108
THREAD_NO_SLEEPING();
109
110
if (int_reg.pbi && status_reg.pb)
111
shutdown_nice(RB_POWEROFF);
112
if (int_reg.aci) {
113
snprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x",
114
status_reg.acpwr);
115
devctl_notify("ACPI", "ACAD", "power", notify_buf);
116
}
117
}
118
119
static int
120
am335x_pmic_probe(device_t dev)
121
{
122
struct am335x_pmic_softc *sc;
123
124
if (!ofw_bus_is_compatible(dev, "ti,tps65217"))
125
return (ENXIO);
126
127
sc = device_get_softc(dev);
128
sc->sc_dev = dev;
129
/* Convert to 8-bit addressing */
130
sc->sc_addr = iicbus_get_addr(dev);
131
132
device_set_desc(dev, "TI TPS65217 Power Management IC");
133
134
return (0);
135
}
136
137
static void
138
am335x_pmic_dump_chgconfig(device_t dev)
139
{
140
struct tps65217_chgconfig0_reg reg0;
141
struct tps65217_chgconfig1_reg reg1;
142
struct tps65217_chgconfig2_reg reg2;
143
struct tps65217_chgconfig3_reg reg3;
144
const char *e_d[] = {"enabled", "disabled"};
145
const char *d_e[] = {"disabled", "enabled"};
146
const char *i_a[] = {"inactive", "active"};
147
const char *f_t[] = {"false", "true"};
148
const char *timer_c[] = {"4h", "5h", "6h", "8h"};
149
const char *ntc_type_c[] = {"100k", "10k"};
150
const char *vprechg_c[] = {"2.9V", "2.5V"};
151
const char *trange_c[] = {"0-45 C", "0-60 C"};
152
const char *termif_c[] = {"2.5%", "7.5%", "15%", "18%"};
153
const char *pchrgt_c[] = {"30 min", "60 min"};
154
const char *dppmth_c[] = {"3.50V", "3.75V", "4.00V", "4.25V"};
155
const char *ichrg_c[] = {"300mA", "400mA", "500mA", "700mA"};
156
157
am335x_pmic_read(dev, TPS65217_CHGCONFIG0_REG, (uint8_t *)&reg0, 1);
158
device_printf(dev, " BAT TEMP/NTC ERROR: %s\n", f_t[reg0.battemp]);
159
device_printf(dev, " Pre-charge timer time-out: %s\n", f_t[reg0.pchgtout]);
160
device_printf(dev, " Charge timer time-out: %s\n", f_t[reg0.chgtout]);
161
device_printf(dev, " Charger active: %s\n", f_t[reg0.active]);
162
device_printf(dev, " Termination current detected: %s\n", f_t[reg0.termi]);
163
device_printf(dev, " Thermal suspend: %s\n", f_t[reg0.tsusp]);
164
device_printf(dev, " DPPM active: %s\n", f_t[reg0.dppm]);
165
device_printf(dev, " Thermal regulation: %s\n", i_a[reg0.treg]);
166
167
am335x_pmic_read(dev, TPS65217_CHGCONFIG1_REG, (uint8_t *)&reg1, 1);
168
device_printf(dev, " Charger: %s\n", d_e[reg1.chg_en]);
169
device_printf(dev, " Suspend charge: %s\n", i_a[reg1.susp]);
170
device_printf(dev, " Charge termination: %s\n", e_d[reg1.term]);
171
device_printf(dev, " Charger reset: %s\n", i_a[reg1.reset]);
172
device_printf(dev, " NTC TYPE: %s\n", ntc_type_c[reg1.ntc_type]);
173
device_printf(dev, " Safety timer: %s\n", d_e[reg1.tmr_en]);
174
device_printf(dev, " Charge safety timer: %s\n", timer_c[reg1.timer]);
175
176
am335x_pmic_read(dev, TPS65217_CHGCONFIG2_REG, (uint8_t *)&reg2, 1);
177
device_printf(dev, " Charge voltage: %s\n", tps65217_voreg_c[reg2.voreg]);
178
device_printf(dev, " Pre-charge to fast charge transition voltage: %s\n",
179
vprechg_c[reg2.vprechg]);
180
device_printf(dev, " Dynamic timer function: %s\n", d_e[reg2.dyntmr]);
181
182
am335x_pmic_read(dev, TPS65217_CHGCONFIG3_REG, (uint8_t *)&reg3, 1);
183
device_printf(dev, " Temperature range for charging: %s\n", trange_c[reg3.trange]);
184
device_printf(dev, " Termination current factor: %s\n", termif_c[reg3.termif]);
185
device_printf(dev, " Pre-charge time: %s\n", pchrgt_c[reg3.pchrgt]);
186
device_printf(dev, " Power path DPPM threshold: %s\n", dppmth_c[reg3.dppmth]);
187
device_printf(dev, " Charge current: %s\n", ichrg_c[reg3.ichrg]);
188
}
189
190
static void
191
am335x_pmic_setvo(device_t dev, uint8_t vo)
192
{
193
struct tps65217_chgconfig2_reg reg2;
194
195
am335x_pmic_read(dev, TPS65217_CHGCONFIG2_REG, (uint8_t *)&reg2, 1);
196
reg2.voreg = vo;
197
am335x_pmic_write(dev, TPS65217_CHGCONFIG2_REG, (uint8_t *)&reg2, 1);
198
}
199
200
static void
201
am335x_pmic_start(struct am335x_pmic_softc *sc)
202
{
203
device_t dev;
204
struct tps65217_status_reg status_reg;
205
struct tps65217_chipid_reg chipid_reg;
206
uint8_t reg, vo;
207
char name[20];
208
char pwr[4][11] = {"Battery", "USB", "AC", "USB and AC"};
209
int rv;
210
phandle_t node;
211
212
dev = sc->sc_dev;
213
am335x_pmic_read(dev, TPS65217_CHIPID_REG, (uint8_t *)&chipid_reg, 1);
214
switch (chipid_reg.chip) {
215
case TPS65217A:
216
sprintf(name, "TPS65217A ver 1.%u", chipid_reg.rev);
217
break;
218
case TPS65217B:
219
sprintf(name, "TPS65217B ver 1.%u", chipid_reg.rev);
220
break;
221
case TPS65217C:
222
sprintf(name, "TPS65217C ver 1.%u", chipid_reg.rev);
223
break;
224
case TPS65217D:
225
sprintf(name, "TPS65217D ver 1.%u", chipid_reg.rev);
226
break;
227
default:
228
sprintf(name, "Unknown PMIC");
229
}
230
231
am335x_pmic_read(dev, TPS65217_STATUS_REG, (uint8_t *)&status_reg, 1);
232
device_printf(dev, "%s powered by %s\n", name,
233
pwr[status_reg.usbpwr | (status_reg.acpwr << 1)]);
234
235
/* Check devicetree for ti,pmic-shutdown-controller
236
* if present; PMIC will go to shutdown state on PWR_EN toggle
237
* if not present; PMIC will enter sleep state on PWR_EN toggle (default on reset)
238
*/
239
node = ofw_bus_get_node(dev);
240
if (OF_hasprop(node, "ti,pmic-shutdown-controller")) {
241
status_reg.off = 1;
242
am335x_pmic_write(dev, TPS65217_STATUS_REG, (uint8_t *)&status_reg, 1);
243
}
244
245
if (am335x_pmic_vo[0] != '\0') {
246
for (vo = 0; vo < 4; vo++) {
247
if (strcmp(tps65217_voreg_c[vo], am335x_pmic_vo) == 0)
248
break;
249
}
250
if (vo == 4) {
251
device_printf(dev, "WARNING: hw.am335x_pmic.vo=\"%s\""
252
": unsupported value\n", am335x_pmic_vo);
253
} else {
254
am335x_pmic_setvo(dev, vo);
255
}
256
}
257
258
if (bootverbose || am335x_pmic_bootverbose) {
259
am335x_pmic_dump_chgconfig(dev);
260
}
261
262
EVENTHANDLER_REGISTER(shutdown_final, am335x_pmic_shutdown, dev,
263
SHUTDOWN_PRI_LAST);
264
265
/* Unmask all interrupts and clear pending status */
266
reg = 0;
267
am335x_pmic_write(dev, TPS65217_INT_REG, &reg, 1);
268
am335x_pmic_read(dev, TPS65217_INT_REG, &reg, 1);
269
270
if (sc->sc_irq_res != NULL) {
271
rv = bus_setup_intr(dev, sc->sc_irq_res,
272
INTR_TYPE_MISC | INTR_MPSAFE, NULL, am335x_pmic_intr,
273
sc, &sc->sc_intrhand);
274
if (rv != 0)
275
device_printf(dev,
276
"Unable to setup the irq handler.\n");
277
}
278
}
279
280
static int
281
am335x_pmic_attach(device_t dev)
282
{
283
struct am335x_pmic_softc *sc;
284
int rid;
285
286
sc = device_get_softc(dev);
287
288
rid = 0;
289
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
290
RF_ACTIVE);
291
if (!sc->sc_irq_res) {
292
device_printf(dev, "cannot allocate interrupt\n");
293
/* return (ENXIO); */
294
}
295
296
am335x_pmic_start(sc);
297
298
return (0);
299
}
300
301
static void
302
am335x_pmic_shutdown(void *xdev, int howto)
303
{
304
if (!(howto & RB_POWEROFF))
305
return;
306
307
/* Toggle pmic_pwr_enable to shutdown the PMIC. */
308
am335x_rtc_pmic_pwr_toggle();
309
}
310
311
static device_method_t am335x_pmic_methods[] = {
312
DEVMETHOD(device_probe, am335x_pmic_probe),
313
DEVMETHOD(device_attach, am335x_pmic_attach),
314
{0, 0},
315
};
316
317
static driver_t am335x_pmic_driver = {
318
"am335x_pmic",
319
am335x_pmic_methods,
320
sizeof(struct am335x_pmic_softc),
321
};
322
323
DRIVER_MODULE(am335x_pmic, iicbus, am335x_pmic_driver, 0, 0);
324
MODULE_VERSION(am335x_pmic, 1);
325
MODULE_DEPEND(am335x_pmic, iicbus, 1, 1, 1);
326
327