FreeBSD kernel IICBUS device code
fan53555.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
5 * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
6 * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include <sys/param.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/mutex.h>
38#include <sys/rman.h>
39#include <machine/bus.h>
40
41#include <dev/iicbus/iiconf.h>
42#include <dev/iicbus/iicbus.h>
43
44#include <dev/ofw/ofw_bus.h>
45#include <dev/ofw/ofw_bus_subr.h>
46
47#include <dev/extres/regulator/regulator.h>
48
49#include "regdev_if.h"
50
51/* Registers */
52#define FAN53555_VSEL0 0x00
53#define FAN53555_VSEL1 0x01
54#define FAN53555_VSEL_ENA (1 << 7)
55#define FAN53555_VSEL_MODE (1 << 6)
56#define FAN53555_VSEL_MASK 0x3f
57#define FAN53555_CTRL 0x02
58#define FAN53555_ID1 0x03
59#define FAN53555_ID1_DIE_ID(x) (((x) >> 4) & 0x0F)
60#define FAN53555_ID2 0x04
61#define FAN53555_ID2_DIE_REV(x) (((x) >> 4) & 0x0F)
62#define FAN53555_MON 0x05
63
64
65#if 0
66#define dprintf(sc, format, arg...) \
67 device_printf(sc->base_dev, "%s: " format, __func__, arg)
68#else
69#define dprintf(sc, format, arg...)
70#endif
71
76};
77
78static struct ofw_compat_data compat_data[] = {
79 {"fcs,fan53555", FAN53555},
80 {"silergy,syr827", SYR827},
81 {"silergy,syr828", SYR828},
82 {NULL, 0}
83};
84
87 char *name;
88 device_t base_dev;
89 uint8_t live_reg;
90 uint8_t sleep_reg;
91 struct regulator_range *range;
92 struct regnode_std_param *param;
93};
94
96 device_t dev;
97 uint8_t live_reg;
98 uint8_t sleep_reg;
99};
100
101static struct regulator_range syr_8_range =
102 REG_RANGE_INIT( 0, 0x3F, 712500, 12500);
103
104static struct regulator_range fan_0_0_range =
105 REG_RANGE_INIT( 0, 0x3F, 600000, 10000);
106static struct regulator_range fan_0_13_range =
107 REG_RANGE_INIT( 0, 0x3F, 800000, 10000);
108static struct regulator_range fan_1_range =
109 REG_RANGE_INIT( 0, 0x3F, 600000, 10000);
110static struct regulator_range fan_4_range =
111 REG_RANGE_INIT( 0, 0x3F, 603000, 12826);
112
113
114static int
115fan53555_read(device_t dev, uint8_t reg, uint8_t *val)
116{
117 uint8_t addr;
118 int rv;
119 struct iic_msg msgs[2] = {
120 {0, IIC_M_WR | IIC_M_NOSTOP, 1, &addr},
121 {0, IIC_M_RD, 1, val},
122 };
123
124 msgs[0].slave = iicbus_get_addr(dev);
125 msgs[1].slave = iicbus_get_addr(dev);
126 addr = reg;
127
129 if (rv != 0) {
130 device_printf(dev, "Error when reading reg 0x%02X, rv: %d\n",
131 reg, rv);
132 return (EIO);
133 }
134
135 return (0);
136}
137
138static int
139fan53555_write(device_t dev, uint8_t reg, uint8_t val)
140{
141 uint8_t data[2];
142 int rv;
143
144 struct iic_msg msgs[1] = {
145 {0, IIC_M_WR, 2, data},
146 };
147
148 msgs[0].slave = iicbus_get_addr(dev);
149 data[0] = reg;
150 data[1] = val;
151
153 if (rv != 0) {
154 device_printf(dev,
155 "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
156 return (EIO);
157 }
158 return (0);
159}
160
161static int
162fan53555_read_sel(struct fan53555_reg_sc *sc, uint8_t *sel)
163{
164 int rv;
165
166 rv = fan53555_read(sc->base_dev, sc->live_reg, sel);
167 if (rv != 0)
168 return (rv);
169 *sel &= FAN53555_VSEL_MASK;
170 return (0);
171}
172
173static int
174fan53555_write_sel(struct fan53555_reg_sc *sc, uint8_t sel)
175{
176 int rv;
177 uint8_t reg;
178
179 rv = fan53555_read(sc->base_dev, sc->live_reg, &reg);
180 if (rv != 0)
181 return (rv);
182 reg &= ~FAN53555_VSEL_MASK;
183 reg |= sel;
184
185 rv = fan53555_write(sc->base_dev, sc->live_reg, reg);
186 if (rv != 0)
187 return (rv);
188 return (rv);
189}
190
191static int
192fan53555_regnode_init(struct regnode *regnode)
193{
194 return (0);
195}
196
197static int
198fan53555_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
199{
200 struct fan53555_reg_sc *sc;
201 uint8_t val;
202
203 sc = regnode_get_softc(regnode);
204
205 dprintf(sc, "%sabling regulator %s\n", enable ? "En" : "Dis",
206 sc->name);
208 if (enable)
210 else
211 val &= ~FAN53555_VSEL_ENA;
213
214 *udelay = sc->param->enable_delay;
215 return (0);
216}
217
218
219static int
221 int max_uvolt, int *udelay)
222{
223 struct fan53555_reg_sc *sc;
224 uint8_t sel;
225 int uvolt, rv;
226
227 sc = regnode_get_softc(regnode);
228
229 dprintf(sc, "Setting %s to %d<->%d uvolts\n", sc->name, min_uvolt,
230 max_uvolt);
231 rv = regulator_range_volt_to_sel8(sc->range, 1, min_uvolt, max_uvolt,
232 &sel);
233 if (rv != 0)
234 return (rv);
235 *udelay = sc->param->ramp_delay;
236 rv = fan53555_write_sel(sc, sel);
237 dprintf(sc, "Regulator %s writing sel: 0x%02X\n", sc->name, sel);
238
239 fan53555_read_sel(sc, &sel);
240 regulator_range_sel8_to_volt(sc->range, 1, sel, &uvolt);
241 dprintf(sc, "Regulator %s set to %d uvolt (sel: 0x%02X)\n", sc->name,
242 uvolt, sel);
243
244 return (rv);
245}
246
247static int
249{
250 struct fan53555_reg_sc *sc;
251 uint8_t sel;
252 int rv;
253
254 sc = regnode_get_softc(regnode);
255
256 rv = fan53555_read_sel(sc, &sel);
257 if (rv != 0)
258 return (rv);
259 rv = regulator_range_sel8_to_volt(sc->range, 1, sel, uvolt);
260 dprintf(sc, "Regulator %s is at %d uvolt ((sel: 0x%02X)\n", sc->name,
261 *uvolt, sel);
262
263 return (rv);
264}
265
266static regnode_method_t fan53555_regnode_methods[] = {
267 /* Regulator interface */
268 REGNODEMETHOD(regnode_init, fan53555_regnode_init),
269 REGNODEMETHOD(regnode_enable, fan53555_regnode_enable),
270 REGNODEMETHOD(regnode_set_voltage, fan53555_regnode_set_voltage),
271 REGNODEMETHOD(regnode_get_voltage, fan53555_regnode_get_voltage),
272 REGNODEMETHOD_END
273};
274DEFINE_CLASS_1(fan53555_regnode, fan53555_regnode_class,
275 fan53555_regnode_methods, sizeof(struct fan53555_reg_sc), regnode_class);
276
277static struct regulator_range *
278fan53555_get_range(struct fan53555_softc *sc, int type, uint8_t id,
279 uint8_t rev)
280{
281 if (type == SYR827 || type == SYR828) {
282 switch (id) {
283 case 8:
284 return (&syr_8_range);
285 default:
286 return (NULL);
287 }
288 }
289
290 if (type == FAN53555) {
291 switch (id) {
292 case 0:
293 if (rev == 0)
294 return (&fan_0_0_range);
295 else if (rev == 13)
296 return (&fan_0_13_range);
297 else
298 return (NULL);
299 case 1:
300 case 3:
301 case 5:
302 case 8:
303 return (&fan_1_range);
304 case 4:
305 return (&fan_4_range);
306 default:
307 return (NULL);
308 }
309 }
310
311 return (NULL);
312}
313
314static struct fan53555_reg_sc *
315fan53555_reg_attach(struct fan53555_softc *sc, phandle_t node, int type)
316{
317 struct fan53555_reg_sc *reg_sc;
318 struct regnode_init_def initdef;
319 struct regnode *regnode;
320 static struct regulator_range *range;
321 uint8_t id1, id2;
322
323 memset(&initdef, 0, sizeof(initdef));
324 if (regulator_parse_ofw_stdparam(sc->dev, node, &initdef) != 0) {
325 device_printf(sc->dev, "cannot parse regulator FDT data\n");
326 return (NULL);
327 }
328
329 if (fan53555_read(sc->dev, FAN53555_ID1, &id1) != 0) {
330 device_printf(sc->dev, "cannot read ID1\n");
331 return (NULL);
332 }
333
334 if (fan53555_read(sc->dev, FAN53555_ID2, &id2) != 0) {
335 device_printf(sc->dev, "cannot read ID2\n");
336 return (NULL);
337 }
338 dprintf(sc, "Device ID1: 0x%02X, ID2: 0x%02X\n", id1, id2);
339
340 range = fan53555_get_range(sc, type, FAN53555_ID1_DIE_ID(id1),
342 if (range == NULL) {
343 device_printf(sc->dev,
344 "cannot determine chip type (ID1: 0x%02X, ID2: 0x%02X)\n",
345 id1, id2);
346 return (NULL);
347 }
348
349 initdef.id = 1;
350 initdef.ofw_node = node;
351
352 regnode = regnode_create(sc->dev, &fan53555_regnode_class, &initdef);
353 if (regnode == NULL) {
354 device_printf(sc->dev, "cannot create regulator\n");
355 return (NULL);
356 }
357
358 reg_sc = regnode_get_softc(regnode);
359 reg_sc->name = "fan53555";
360 reg_sc->regnode = regnode;
361 reg_sc->base_dev = sc->dev;
362 reg_sc->param = regnode_get_stdparam(regnode);
363 reg_sc->range = range;
364 reg_sc->live_reg = sc->live_reg;
365 reg_sc->sleep_reg = sc->sleep_reg;
366
367 dprintf(sc->dev, "live_reg: %d, sleep_reg: %d\n", reg_sc->live_reg,
368 reg_sc->sleep_reg);
369
370 regnode_register(regnode);
371
372 if (bootverbose) {
373 int volt, rv;
374 regnode_topo_slock();
375 rv = regnode_get_voltage(regnode, &volt);
376 if (rv == ENODEV) {
377 device_printf(sc->dev,
378 " Regulator %s: parent doesn't exist yet.\n",
379 regnode_get_name(regnode));
380 } else if (rv != 0) {
381 device_printf(sc->dev,
382 " Regulator %s: voltage: INVALID!!!\n",
383 regnode_get_name(regnode));
384 } else {
385 device_printf(sc->dev,
386 " Regulator %s: voltage: %d uV\n",
387 regnode_get_name(regnode), volt);
388 }
389 regnode_topo_unlock();
390 }
391
392 return (reg_sc);
393}
394
395static int
397{
398 int type;
399
400 if (!ofw_bus_status_okay(dev))
401 return (ENXIO);
402
403 type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
404 switch (type) {
405 case FAN53555:
406 device_set_desc(dev, "FAN53555 PMIC");
407 break;
408 case SYR827:
409 device_set_desc(dev, "SYR827 PMIC");
410 break;
411 case SYR828:
412 device_set_desc(dev, "SYR828 PMIC");
413 break;
414 default:
415 return (ENXIO);
416 }
417
418 return (BUS_PROBE_DEFAULT);
419}
420
421static int
423{
424 struct fan53555_softc *sc;
425 phandle_t node;
426 int type, susp_sel, rv;
427
428 sc = device_get_softc(dev);
429 sc->dev = dev;
430 node = ofw_bus_get_node(dev);
431 type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
432
433 rv = OF_getencprop(node, "fcs,suspend-voltage-selector", &susp_sel,
434 sizeof(susp_sel));
435 if (rv <= 0)
436 susp_sel = 1;
437 if (susp_sel == 1) {
440 } else {
443 }
444 if (fan53555_reg_attach(sc, node, type) == NULL)
445 device_printf(dev, "cannot attach regulator.\n");
446
447 return (0);
448}
449
450static int
452{
453
454 /* We cannot detach regulators */
455 return (EBUSY);
456}
457
458static device_method_t fan53555_methods[] = {
459 DEVMETHOD(device_probe, fan53555_probe),
460 DEVMETHOD(device_attach, fan53555_attach),
461 DEVMETHOD(device_detach, fan53555_detach),
462
463 /* Regdev interface */
464 DEVMETHOD(regdev_map, regdev_default_ofw_map),
465
466 DEVMETHOD_END
467};
468
469static devclass_t fan53555_devclass;
470static DEFINE_CLASS_0(fan53555_pmic, fan53555_driver, fan53555_methods,
471 sizeof(struct fan53555_softc));
472
473EARLY_DRIVER_MODULE(fan53555, iicbus, fan53555_driver, fan53555_devclass, 0, 0,
474 BUS_PASS_RESOURCE);
475MODULE_VERSION(fan53555, 1);
#define IIC_M_WR
Definition: ad7418.c:45
static int fan53555_detach(device_t dev)
Definition: fan53555.c:451
static int fan53555_probe(device_t dev)
Definition: fan53555.c:396
#define FAN53555_VSEL1
Definition: fan53555.c:53
#define FAN53555_ID2
Definition: fan53555.c:60
fan53555_pmic_type
Definition: fan53555.c:72
@ FAN53555
Definition: fan53555.c:73
@ SYR827
Definition: fan53555.c:74
@ SYR828
Definition: fan53555.c:75
#define FAN53555_VSEL_ENA
Definition: fan53555.c:54
static struct regulator_range syr_8_range
Definition: fan53555.c:101
static devclass_t fan53555_devclass
Definition: fan53555.c:469
static int fan53555_write_sel(struct fan53555_reg_sc *sc, uint8_t sel)
Definition: fan53555.c:174
static struct regulator_range fan_1_range
Definition: fan53555.c:108
#define dprintf(sc, format, arg...)
Definition: fan53555.c:69
MODULE_VERSION(fan53555, 1)
DEFINE_CLASS_1(fan53555_regnode, fan53555_regnode_class, fan53555_regnode_methods, sizeof(struct fan53555_reg_sc), regnode_class)
static int fan53555_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
Definition: fan53555.c:198
static DEFINE_CLASS_0(fan53555_pmic, fan53555_driver, fan53555_methods, sizeof(struct fan53555_softc))
static struct regulator_range * fan53555_get_range(struct fan53555_softc *sc, int type, uint8_t id, uint8_t rev)
Definition: fan53555.c:278
static struct regulator_range fan_0_13_range
Definition: fan53555.c:106
static int fan53555_write(device_t dev, uint8_t reg, uint8_t val)
Definition: fan53555.c:139
#define FAN53555_VSEL_MASK
Definition: fan53555.c:56
EARLY_DRIVER_MODULE(fan53555, iicbus, fan53555_driver, fan53555_devclass, 0, 0, BUS_PASS_RESOURCE)
__FBSDID("$FreeBSD$")
static device_method_t fan53555_methods[]
Definition: fan53555.c:458
MODULE_DEPEND(fan53555, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER)
static int fan53555_regnode_init(struct regnode *regnode)
Definition: fan53555.c:192
#define FAN53555_ID2_DIE_REV(x)
Definition: fan53555.c:61
static int fan53555_regnode_get_voltage(struct regnode *regnode, int *uvolt)
Definition: fan53555.c:248
static regnode_method_t fan53555_regnode_methods[]
Definition: fan53555.c:266
IICBUS_FDT_PNP_INFO(compat_data)
static struct ofw_compat_data compat_data[]
Definition: fan53555.c:78
static int fan53555_read(device_t dev, uint8_t reg, uint8_t *val)
Definition: fan53555.c:115
#define FAN53555_VSEL0
Definition: fan53555.c:52
static int fan53555_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay)
Definition: fan53555.c:220
#define FAN53555_ID1_DIE_ID(x)
Definition: fan53555.c:59
static int fan53555_attach(device_t dev)
Definition: fan53555.c:422
static struct regulator_range fan_0_0_range
Definition: fan53555.c:104
static struct regulator_range fan_4_range
Definition: fan53555.c:110
static int fan53555_read_sel(struct fan53555_reg_sc *sc, uint8_t *sel)
Definition: fan53555.c:162
#define FAN53555_ID1
Definition: fan53555.c:58
static struct fan53555_reg_sc * fan53555_reg_attach(struct fan53555_softc *sc, phandle_t node, int type)
Definition: fan53555.c:315
#define IIC_M_RD
Definition: iic.h:42
#define IIC_M_NOSTOP
Definition: iic.h:43
caddr_t data
Definition: iicbb_if.m:61
int val
Definition: iicbb_if.m:83
u_char addr
Definition: iicbb_if.m:116
struct iic_msg * msgs
Definition: iicbus_if.m:134
INTERFACE iicbus
Definition: iicbus_if.m:32
int iicbus_transfer_excl(device_t dev, struct iic_msg *msgs, uint32_t nmsgs, int how)
Definition: iiconf.c:449
#define IICBUS_MINVER
Definition: iiconf.h:171
#define IIC_INTRWAIT
Definition: iiconf.h:48
#define IICBUS_MAXVER
Definition: iiconf.h:172
#define IICBUS_PREFVER
Definition: iiconf.h:173
device_t dev
Definition: ofw_iicbus_if.m:38
struct regulator_range * range
Definition: fan53555.c:91
struct regnode * regnode
Definition: fan53555.c:86
device_t base_dev
Definition: fan53555.c:88
char * name
Definition: fan53555.c:87
uint8_t sleep_reg
Definition: fan53555.c:90
uint8_t live_reg
Definition: fan53555.c:89
struct regnode_std_param * param
Definition: fan53555.c:92
uint8_t live_reg
Definition: fan53555.c:97
uint8_t sleep_reg
Definition: fan53555.c:98
device_t dev
Definition: fan53555.c:96
Definition: iic.h:38
uint16_t slave
Definition: iic.h:39