14388c70cSMichal Meloun /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
34388c70cSMichal Meloun  *
44388c70cSMichal Meloun  * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
54388c70cSMichal Meloun  *
64388c70cSMichal Meloun  * Redistribution and use in source and binary forms, with or without
74388c70cSMichal Meloun  * modification, are permitted provided that the following conditions
84388c70cSMichal Meloun  * are met:
94388c70cSMichal Meloun  * 1. Redistributions of source code must retain the above copyright
104388c70cSMichal Meloun  *    notice, this list of conditions and the following disclaimer.
114388c70cSMichal Meloun  * 2. Redistributions in binary form must reproduce the above copyright
124388c70cSMichal Meloun  *    notice, this list of conditions and the following disclaimer in the
134388c70cSMichal Meloun  *    documentation and/or other materials provided with the distribution.
144388c70cSMichal Meloun  *
154388c70cSMichal Meloun  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
164388c70cSMichal Meloun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
174388c70cSMichal Meloun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184388c70cSMichal Meloun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
194388c70cSMichal Meloun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204388c70cSMichal Meloun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214388c70cSMichal Meloun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224388c70cSMichal Meloun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234388c70cSMichal Meloun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244388c70cSMichal Meloun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254388c70cSMichal Meloun  * SUCH DAMAGE.
264388c70cSMichal Meloun  */
274388c70cSMichal Meloun 
284388c70cSMichal Meloun #include <sys/param.h>
294388c70cSMichal Meloun #include <sys/systm.h>
304388c70cSMichal Meloun #include <sys/bus.h>
314388c70cSMichal Meloun #include <sys/kernel.h>
324388c70cSMichal Meloun #include <sys/module.h>
334388c70cSMichal Meloun #include <sys/mutex.h>
344388c70cSMichal Meloun #include <sys/rman.h>
354388c70cSMichal Meloun #include <machine/bus.h>
364388c70cSMichal Meloun 
374388c70cSMichal Meloun #include <dev/iicbus/iiconf.h>
384388c70cSMichal Meloun #include <dev/iicbus/iicbus.h>
394388c70cSMichal Meloun 
404388c70cSMichal Meloun #include <dev/ofw/ofw_bus.h>
414388c70cSMichal Meloun #include <dev/ofw/ofw_bus_subr.h>
424388c70cSMichal Meloun 
43b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h>
444388c70cSMichal Meloun 
454388c70cSMichal Meloun #include <dev/iicbus/pmic/act8846.h>
464388c70cSMichal Meloun 
474388c70cSMichal Meloun #include "regdev_if.h"
484388c70cSMichal Meloun 
494388c70cSMichal Meloun MALLOC_DEFINE(M_ACT8846_REG, "ACT8846 regulator", "ACT8846 power regulator");
504388c70cSMichal Meloun 
514388c70cSMichal Meloun #if 0
524388c70cSMichal Meloun #define	dprintf(sc, format, arg...)
534388c70cSMichal Meloun 	device_printf(sc->base_sc->dev, "%s: " format, __func__, arg) */
544388c70cSMichal Meloun #else
554388c70cSMichal Meloun #define	dprintf(sc, format, arg...)
564388c70cSMichal Meloun #endif
574388c70cSMichal Meloun 
584388c70cSMichal Meloun enum act8846_reg_id {
594388c70cSMichal Meloun 	ACT8846_REG_ID_REG1,
604388c70cSMichal Meloun 	ACT8846_REG_ID_REG2,
614388c70cSMichal Meloun 	ACT8846_REG_ID_REG3,
624388c70cSMichal Meloun 	ACT8846_REG_ID_REG4,
634388c70cSMichal Meloun 	ACT8846_REG_ID_REG5,
644388c70cSMichal Meloun 	ACT8846_REG_ID_REG6,
654388c70cSMichal Meloun 	ACT8846_REG_ID_REG7,
664388c70cSMichal Meloun 	ACT8846_REG_ID_REG8,
674388c70cSMichal Meloun 	ACT8846_REG_ID_REG9,
684388c70cSMichal Meloun 	ACT8846_REG_ID_REG10,
694388c70cSMichal Meloun 	ACT8846_REG_ID_REG11,
704388c70cSMichal Meloun 	ACT8846_REG_ID_REG12,
714388c70cSMichal Meloun 	ACT8846_REG_ID_REG13,
724388c70cSMichal Meloun };
734388c70cSMichal Meloun 
744388c70cSMichal Meloun struct act8846_regdef {
754388c70cSMichal Meloun 	intptr_t		id;		/* ID */
764388c70cSMichal Meloun 	char			*name;		/* Regulator name */
774388c70cSMichal Meloun 	char			*supply_name;	/* Source property name */
784388c70cSMichal Meloun 	uint8_t			enable_reg;
794388c70cSMichal Meloun 	uint8_t			enable_mask;
804388c70cSMichal Meloun 	uint8_t			voltage_reg;
814388c70cSMichal Meloun 	uint8_t			voltage_mask;
824388c70cSMichal Meloun 	struct regulator_range	*ranges;
834388c70cSMichal Meloun 	int			nranges;
844388c70cSMichal Meloun };
854388c70cSMichal Meloun struct act8846_softc;
864388c70cSMichal Meloun 
874388c70cSMichal Meloun struct act8846_reg_sc {
884388c70cSMichal Meloun 	struct regnode		*regnode;
894388c70cSMichal Meloun 	struct act8846_softc	*base_sc;
904388c70cSMichal Meloun 	struct act8846_regdef	*def;
914388c70cSMichal Meloun 	phandle_t		xref;
924388c70cSMichal Meloun 	struct regnode_std_param *param;
934388c70cSMichal Meloun };
944388c70cSMichal Meloun 
954388c70cSMichal Meloun 
964388c70cSMichal Meloun static struct regulator_range act8846_ranges[] = {
974388c70cSMichal Meloun 	REG_RANGE_INIT(  0, 23,  600000, 25000),
984388c70cSMichal Meloun 	REG_RANGE_INIT( 24, 47, 1200000, 50000),
994388c70cSMichal Meloun 	REG_RANGE_INIT( 48, 64, 2400000, 100000),
1004388c70cSMichal Meloun };
1014388c70cSMichal Meloun 
1024388c70cSMichal Meloun static struct act8846_regdef act8846_regdefs[] = {
1034388c70cSMichal Meloun 	{
1044388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG1,
1054388c70cSMichal Meloun 		.name = "REG1",
1064388c70cSMichal Meloun 		.supply_name = "vp1",
1074388c70cSMichal Meloun 		.enable_reg = ACT8846_REG1_CTRL,
1084388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1094388c70cSMichal Meloun 	},
1104388c70cSMichal Meloun 	{
1114388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG2,
1124388c70cSMichal Meloun 		.name = "REG2",
1134388c70cSMichal Meloun 		.supply_name = "vp2",
1144388c70cSMichal Meloun 		.enable_reg = ACT8846_REG2_CTRL,
1154388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1164388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG2_VSET0,
1174388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1184388c70cSMichal Meloun 		.ranges = act8846_ranges,
1194388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1204388c70cSMichal Meloun 	},
1214388c70cSMichal Meloun 	{
1224388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG3,
1234388c70cSMichal Meloun 		.name = "REG3",
1244388c70cSMichal Meloun 		.supply_name = "vp3",
1254388c70cSMichal Meloun 		.enable_reg = ACT8846_REG3_CTRL,
1264388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1274388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG3_VSET0,
1284388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1294388c70cSMichal Meloun 		.ranges = act8846_ranges,
1304388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1314388c70cSMichal Meloun 	},
1324388c70cSMichal Meloun 	{
1334388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG4,
1344388c70cSMichal Meloun 		.name = "REG4",
1354388c70cSMichal Meloun 		.supply_name = "vp4",
1364388c70cSMichal Meloun 		.enable_reg = ACT8846_REG4_CTRL,
1374388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1384388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG4_VSET0,
1394388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1404388c70cSMichal Meloun 		.ranges = act8846_ranges,
1414388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1424388c70cSMichal Meloun 	},
1434388c70cSMichal Meloun 	{
1444388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG5,
1454388c70cSMichal Meloun 		.name = "REG5",
1464388c70cSMichal Meloun 		.supply_name = "inl1",
1474388c70cSMichal Meloun 		.enable_reg = ACT8846_REG5_CTRL,
1484388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1494388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG5_VSET,
1504388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1514388c70cSMichal Meloun 		.ranges = act8846_ranges,
1524388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1534388c70cSMichal Meloun 	},
1544388c70cSMichal Meloun 	{
1554388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG6,
1564388c70cSMichal Meloun 		.name = "REG6",
1574388c70cSMichal Meloun 		.supply_name = "inl1",
1584388c70cSMichal Meloun 		.enable_reg = ACT8846_REG6_CTRL,
1594388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1604388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG6_VSET,
1614388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1624388c70cSMichal Meloun 		.ranges = act8846_ranges,
1634388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1644388c70cSMichal Meloun 	},
1654388c70cSMichal Meloun 	{
1664388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG7,
1674388c70cSMichal Meloun 		.name = "REG7",
1684388c70cSMichal Meloun 		.supply_name = "inl1",
1694388c70cSMichal Meloun 		.enable_reg = ACT8846_REG7_CTRL,
1704388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1714388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG7_VSET,
1724388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1734388c70cSMichal Meloun 		.ranges = act8846_ranges,
1744388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1754388c70cSMichal Meloun 	},
1764388c70cSMichal Meloun 	{
1774388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG8,
1784388c70cSMichal Meloun 		.name = "REG8",
1794388c70cSMichal Meloun 		.supply_name = "inl2",
1804388c70cSMichal Meloun 		.enable_reg = ACT8846_REG8_CTRL,
1814388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1824388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG8_VSET,
1834388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1844388c70cSMichal Meloun 		.ranges = act8846_ranges,
1854388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1864388c70cSMichal Meloun 	},
1874388c70cSMichal Meloun 	{
1884388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG9,
1894388c70cSMichal Meloun 		.name = "REG9",
1904388c70cSMichal Meloun 		.supply_name = "inl2",
1914388c70cSMichal Meloun 		.enable_reg = ACT8846_REG9_CTRL,
1924388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
1934388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG9_VSET,
1944388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
1954388c70cSMichal Meloun 		.ranges = act8846_ranges,
1964388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
1974388c70cSMichal Meloun 	},
1984388c70cSMichal Meloun 	{
1994388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG10,
2004388c70cSMichal Meloun 		.name = "REG10",
2014388c70cSMichal Meloun 		.supply_name = "inl3",
2024388c70cSMichal Meloun 		.enable_reg = ACT8846_REG10_CTRL,
2034388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
2044388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG10_VSET,
2054388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
2064388c70cSMichal Meloun 		.ranges = act8846_ranges,
2074388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
2084388c70cSMichal Meloun 	},
2094388c70cSMichal Meloun 	{
2104388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG11,
2114388c70cSMichal Meloun 		.name = "REG11",
2124388c70cSMichal Meloun 		.supply_name = "inl3",
2134388c70cSMichal Meloun 		.enable_reg = ACT8846_REG11_CTRL,
2144388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
2154388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG11_VSET,
2164388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
2174388c70cSMichal Meloun 		.ranges = act8846_ranges,
2184388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
2194388c70cSMichal Meloun 	},
2204388c70cSMichal Meloun 	{
2214388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG12,
2224388c70cSMichal Meloun 		.name = "REG12",
2234388c70cSMichal Meloun 		.supply_name = "inl3",
2244388c70cSMichal Meloun 		.enable_reg = ACT8846_REG12_CTRL,
2254388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
2264388c70cSMichal Meloun 		.voltage_reg = ACT8846_REG12_VSET,
2274388c70cSMichal Meloun 		.voltage_mask = ACT8846_VSEL_MASK,
2284388c70cSMichal Meloun 		.ranges = act8846_ranges,
2294388c70cSMichal Meloun 		.nranges = nitems(act8846_ranges),
2304388c70cSMichal Meloun 	},
2314388c70cSMichal Meloun 	{
2324388c70cSMichal Meloun 		.id = ACT8846_REG_ID_REG13,
2334388c70cSMichal Meloun 		.name = "REG13",
2344388c70cSMichal Meloun 		.supply_name = "inl1",
2354388c70cSMichal Meloun 		.enable_reg = ACT8846_REG13_CTRL,
2364388c70cSMichal Meloun 		.enable_mask = ACT8846_CTRL_ENA,
2374388c70cSMichal Meloun 	},
2384388c70cSMichal Meloun };
2394388c70cSMichal Meloun 
2404388c70cSMichal Meloun static int
act8846_read_sel(struct act8846_reg_sc * sc,uint8_t * sel)2414388c70cSMichal Meloun act8846_read_sel(struct act8846_reg_sc *sc, uint8_t *sel)
2424388c70cSMichal Meloun {
2434388c70cSMichal Meloun 	int rv;
2444388c70cSMichal Meloun 
2454388c70cSMichal Meloun 	rv = RD1(sc->base_sc, sc->def->voltage_reg, sel);
2464388c70cSMichal Meloun 	if (rv != 0)
2474388c70cSMichal Meloun 		return (rv);
2484388c70cSMichal Meloun 	*sel &= sc->def->voltage_mask;
2494388c70cSMichal Meloun 	*sel >>= ffs(sc->def->voltage_mask) - 1;
2504388c70cSMichal Meloun 	return (0);
2514388c70cSMichal Meloun }
2524388c70cSMichal Meloun 
2534388c70cSMichal Meloun static int
act8846_write_sel(struct act8846_reg_sc * sc,uint8_t sel)2544388c70cSMichal Meloun act8846_write_sel(struct act8846_reg_sc *sc, uint8_t sel)
2554388c70cSMichal Meloun {
2564388c70cSMichal Meloun 	int rv;
2574388c70cSMichal Meloun 
2584388c70cSMichal Meloun 	sel <<= ffs(sc->def->voltage_mask) - 1;
2594388c70cSMichal Meloun 	sel &= sc->def->voltage_mask;
2604388c70cSMichal Meloun 
2614388c70cSMichal Meloun 	rv = RM1(sc->base_sc, sc->def->voltage_reg,
2624388c70cSMichal Meloun 	    sc->def->voltage_mask, sel);
2634388c70cSMichal Meloun 	if (rv != 0)
2644388c70cSMichal Meloun 		return (rv);
2654388c70cSMichal Meloun 	return (rv);
2664388c70cSMichal Meloun }
2674388c70cSMichal Meloun 
2684388c70cSMichal Meloun static int
act8846_regnode_init(struct regnode * regnode)2694388c70cSMichal Meloun act8846_regnode_init(struct regnode *regnode)
2704388c70cSMichal Meloun {
2714388c70cSMichal Meloun 	return (0);
2724388c70cSMichal Meloun }
2734388c70cSMichal Meloun 
2744388c70cSMichal Meloun static int
act8846_regnode_enable(struct regnode * regnode,bool enable,int * udelay)2754388c70cSMichal Meloun act8846_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
2764388c70cSMichal Meloun {
2774388c70cSMichal Meloun 	struct act8846_reg_sc *sc;
2784388c70cSMichal Meloun 	int rv;
2794388c70cSMichal Meloun 
2804388c70cSMichal Meloun 	sc = regnode_get_softc(regnode);
2814388c70cSMichal Meloun 
2824388c70cSMichal Meloun 	dprintf(sc, "%sabling regulator %s\n",
2834388c70cSMichal Meloun 	    enable ? "En" : "Dis",
2844388c70cSMichal Meloun 	    sc->def->name);
2854388c70cSMichal Meloun 	rv = RM1(sc->base_sc, sc->def->enable_reg,
2864388c70cSMichal Meloun 	    sc->def->enable_mask, enable ? sc->def->enable_mask: 0);
2874388c70cSMichal Meloun 	*udelay = sc->param->enable_delay;
2884388c70cSMichal Meloun 
2894388c70cSMichal Meloun 	return (rv);
2904388c70cSMichal Meloun }
2914388c70cSMichal Meloun 
2924388c70cSMichal Meloun static int
act8846_regnode_set_voltage(struct regnode * regnode,int min_uvolt,int max_uvolt,int * udelay)2934388c70cSMichal Meloun act8846_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
2944388c70cSMichal Meloun     int max_uvolt, int *udelay)
2954388c70cSMichal Meloun {
2964388c70cSMichal Meloun 	struct act8846_reg_sc *sc;
2974388c70cSMichal Meloun 	uint8_t sel;
2984388c70cSMichal Meloun 	int uvolt, rv;
2994388c70cSMichal Meloun 
3004388c70cSMichal Meloun 	sc = regnode_get_softc(regnode);
3014388c70cSMichal Meloun 
3024388c70cSMichal Meloun 	if (sc->def->ranges == NULL)
3034388c70cSMichal Meloun 		return (ENXIO);
3044388c70cSMichal Meloun 
3054388c70cSMichal Meloun 	dprintf(sc, "Setting %s to %d<->%d uvolts\n",
3064388c70cSMichal Meloun 	    sc->def->name,
3074388c70cSMichal Meloun 	    min_uvolt,
3084388c70cSMichal Meloun 	    max_uvolt);
3094388c70cSMichal Meloun 	rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges,
3104388c70cSMichal Meloun 	    min_uvolt, max_uvolt, &sel);
3114388c70cSMichal Meloun 	if (rv != 0)
3124388c70cSMichal Meloun 		return (rv);
3134388c70cSMichal Meloun 	*udelay = sc->param->ramp_delay;
3144388c70cSMichal Meloun 	rv = act8846_write_sel(sc, sel);
3154388c70cSMichal Meloun 
3164388c70cSMichal Meloun 	act8846_read_sel(sc, &sel);
3174388c70cSMichal Meloun 	regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,
3184388c70cSMichal Meloun 	    sel, &uvolt);
3194388c70cSMichal Meloun 	dprintf(sc, "Regulator %s set to %d uvolt\n", sc->def->name,
3204388c70cSMichal Meloun 	    uvolt);
3214388c70cSMichal Meloun 
3224388c70cSMichal Meloun 	return (rv);
3234388c70cSMichal Meloun }
3244388c70cSMichal Meloun 
3254388c70cSMichal Meloun static int
act8846_regnode_get_voltage(struct regnode * regnode,int * uvolt)3264388c70cSMichal Meloun act8846_regnode_get_voltage(struct regnode *regnode, int *uvolt)
3274388c70cSMichal Meloun {
3284388c70cSMichal Meloun 	struct act8846_reg_sc *sc;
3294388c70cSMichal Meloun 	uint8_t sel;
3304388c70cSMichal Meloun 	int rv;
3314388c70cSMichal Meloun 
3324388c70cSMichal Meloun 	sc = regnode_get_softc(regnode);
3334388c70cSMichal Meloun 
3344388c70cSMichal Meloun 	if (sc->def->ranges == NULL) {
3354388c70cSMichal Meloun 		if (sc->def->id == ACT8846_REG_ID_REG13) {
3364388c70cSMichal Meloun 			*uvolt = 1800000;
3374388c70cSMichal Meloun 			return (0);
3384388c70cSMichal Meloun 		}
3394388c70cSMichal Meloun 		return (ENXIO);
3404388c70cSMichal Meloun 	}
3414388c70cSMichal Meloun 
3424388c70cSMichal Meloun 	rv = act8846_read_sel(sc, &sel);
3434388c70cSMichal Meloun 	if (rv != 0)
3444388c70cSMichal Meloun 		return (rv);
3454388c70cSMichal Meloun 	rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,
3464388c70cSMichal Meloun 	    sel, uvolt);
3474388c70cSMichal Meloun 	dprintf(sc, "Regulator %s is at %d uvolt\n", sc->def->name,
3484388c70cSMichal Meloun 	    *uvolt);
3494388c70cSMichal Meloun 
3504388c70cSMichal Meloun 	return (rv);
3514388c70cSMichal Meloun }
3524388c70cSMichal Meloun 
3534388c70cSMichal Meloun static regnode_method_t act8846_regnode_methods[] = {
3544388c70cSMichal Meloun 	/* Regulator interface */
3554388c70cSMichal Meloun 	REGNODEMETHOD(regnode_init,		act8846_regnode_init),
3564388c70cSMichal Meloun 	REGNODEMETHOD(regnode_enable,		act8846_regnode_enable),
3574388c70cSMichal Meloun 	REGNODEMETHOD(regnode_set_voltage,	act8846_regnode_set_voltage),
3584388c70cSMichal Meloun 	REGNODEMETHOD(regnode_get_voltage,	act8846_regnode_get_voltage),
3594388c70cSMichal Meloun 	REGNODEMETHOD_END
3604388c70cSMichal Meloun };
3614388c70cSMichal Meloun DEFINE_CLASS_1(act8846_regnode, act8846_regnode_class, act8846_regnode_methods,
3624388c70cSMichal Meloun     sizeof(struct act8846_reg_sc), regnode_class);
3634388c70cSMichal Meloun 
3644388c70cSMichal Meloun static int
act8846_fdt_parse(struct act8846_softc * sc,phandle_t pnode,phandle_t node,struct act8846_regdef * def,struct regnode_init_def * init_def)3654388c70cSMichal Meloun act8846_fdt_parse(struct act8846_softc *sc, phandle_t pnode, phandle_t node,
3664388c70cSMichal Meloun     struct act8846_regdef *def, struct regnode_init_def *init_def)
3674388c70cSMichal Meloun {
3684388c70cSMichal Meloun 	int rv;
3694388c70cSMichal Meloun 	phandle_t supply_node;
3704388c70cSMichal Meloun 	char prop_name[64]; /* Maximum OFW property name length. */
3714388c70cSMichal Meloun 
3724388c70cSMichal Meloun 	rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def);
3734388c70cSMichal Meloun 
3744388c70cSMichal Meloun 	/* Get parent supply. */
3754388c70cSMichal Meloun 	if (def->supply_name == NULL)
3764388c70cSMichal Meloun 		 return (0);
3774388c70cSMichal Meloun 
3784388c70cSMichal Meloun 	snprintf(prop_name, sizeof(prop_name), "%s-supply",
3794388c70cSMichal Meloun 	    def->supply_name);
3804388c70cSMichal Meloun 	rv = OF_getencprop(pnode, prop_name, &supply_node,
3814388c70cSMichal Meloun 	    sizeof(supply_node));
3824388c70cSMichal Meloun 	if (rv <= 0)
3834388c70cSMichal Meloun 		return (rv);
3844388c70cSMichal Meloun 	supply_node = OF_node_from_xref(supply_node);
3854388c70cSMichal Meloun 	rv = OF_getprop_alloc(supply_node, "regulator-name",
3864388c70cSMichal Meloun 	    (void **)&init_def->parent_name);
3874388c70cSMichal Meloun 	if (rv <= 0)
3884388c70cSMichal Meloun 		init_def->parent_name = NULL;
3894388c70cSMichal Meloun 	return (0);
3904388c70cSMichal Meloun }
3914388c70cSMichal Meloun 
3924388c70cSMichal Meloun static struct act8846_reg_sc *
act8846_attach(struct act8846_softc * sc,phandle_t pnode,phandle_t node,struct act8846_regdef * def)3934388c70cSMichal Meloun act8846_attach(struct act8846_softc *sc, phandle_t pnode, phandle_t node,
3944388c70cSMichal Meloun     struct act8846_regdef *def)
3954388c70cSMichal Meloun {
3964388c70cSMichal Meloun 	struct act8846_reg_sc *reg_sc;
3974388c70cSMichal Meloun 	struct regnode_init_def initdef;
3984388c70cSMichal Meloun 	struct regnode *regnode;
3994388c70cSMichal Meloun 
4004388c70cSMichal Meloun 	memset(&initdef, 0, sizeof(initdef));
4014388c70cSMichal Meloun 	if (act8846_fdt_parse(sc, pnode, node, def, &initdef) != 0) {
4024388c70cSMichal Meloun 		device_printf(sc->dev, "cannot parse FDT data for regulator\n");
4034388c70cSMichal Meloun 		return (NULL);
4044388c70cSMichal Meloun 	}
4054388c70cSMichal Meloun 	initdef.id = def->id;
4064388c70cSMichal Meloun 	initdef.ofw_node = node;
4074388c70cSMichal Meloun 
4084388c70cSMichal Meloun 	regnode = regnode_create(sc->dev, &act8846_regnode_class, &initdef);
4094388c70cSMichal Meloun 	if (regnode == NULL) {
4104388c70cSMichal Meloun 		device_printf(sc->dev, "cannot create regulator\n");
4114388c70cSMichal Meloun 		return (NULL);
4124388c70cSMichal Meloun 	}
4134388c70cSMichal Meloun 
4144388c70cSMichal Meloun 	reg_sc = regnode_get_softc(regnode);
4154388c70cSMichal Meloun 	reg_sc->base_sc = sc;
4164388c70cSMichal Meloun 	reg_sc->def = def;
4174388c70cSMichal Meloun 	reg_sc->xref = OF_xref_from_node(node);
4184388c70cSMichal Meloun 	reg_sc->param = regnode_get_stdparam(regnode);
4194388c70cSMichal Meloun 
4204388c70cSMichal Meloun 	regnode_register(regnode);
4214388c70cSMichal Meloun 
4224388c70cSMichal Meloun 	if (bootverbose) {
4234388c70cSMichal Meloun 		int volt, rv;
4244388c70cSMichal Meloun 		regnode_topo_slock();
4254388c70cSMichal Meloun 		rv = regnode_get_voltage(regnode, &volt);
4264388c70cSMichal Meloun 		if (rv == ENODEV) {
4274388c70cSMichal Meloun 			device_printf(sc->dev,
4284388c70cSMichal Meloun 			   " Regulator %s: parent doesn't exist yet.\n",
4294388c70cSMichal Meloun 			   regnode_get_name(regnode));
4304388c70cSMichal Meloun 		} else if (rv != 0) {
4314388c70cSMichal Meloun 			device_printf(sc->dev,
4324388c70cSMichal Meloun 			   " Regulator %s: voltage: INVALID!!!\n",
4334388c70cSMichal Meloun 			   regnode_get_name(regnode));
4344388c70cSMichal Meloun 		} else {
4354388c70cSMichal Meloun 			device_printf(sc->dev,
4364388c70cSMichal Meloun 			    " Regulator %s: voltage: %d uV\n",
4374388c70cSMichal Meloun 			    regnode_get_name(regnode), volt);
4384388c70cSMichal Meloun 		}
4394388c70cSMichal Meloun 		regnode_topo_unlock();
4404388c70cSMichal Meloun 	}
4414388c70cSMichal Meloun 
4424388c70cSMichal Meloun 	return (reg_sc);
4434388c70cSMichal Meloun }
4444388c70cSMichal Meloun 
4454388c70cSMichal Meloun 
4464388c70cSMichal Meloun int
act8846_regulator_attach(struct act8846_softc * sc,phandle_t node)4474388c70cSMichal Meloun act8846_regulator_attach(struct act8846_softc *sc, phandle_t node)
4484388c70cSMichal Meloun {
4494388c70cSMichal Meloun 	struct act8846_reg_sc *reg;
4504388c70cSMichal Meloun 	phandle_t child, rnode;
4514388c70cSMichal Meloun 	int i;
4524388c70cSMichal Meloun 
4534388c70cSMichal Meloun 	rnode = ofw_bus_find_child(node, "regulators");
4544388c70cSMichal Meloun 	if (rnode <= 0) {
4554388c70cSMichal Meloun 		device_printf(sc->dev, " Cannot find regulators subnode\n");
4564388c70cSMichal Meloun 		return (ENXIO);
4574388c70cSMichal Meloun 	}
4584388c70cSMichal Meloun 
4594388c70cSMichal Meloun 	/* ACT8846 specific definitio. */
4604388c70cSMichal Meloun 	sc->nregs = nitems(act8846_regdefs);
4614388c70cSMichal Meloun 	sc->regs = malloc(sizeof(struct act8846_reg_sc *) * sc->nregs,
4624388c70cSMichal Meloun 	    M_ACT8846_REG, M_WAITOK | M_ZERO);
4634388c70cSMichal Meloun 
4644388c70cSMichal Meloun 
4654388c70cSMichal Meloun 	/* Attach all known regulators if exist in DT. */
4664388c70cSMichal Meloun 	for (i = 0; i < sc->nregs; i++) {
4674388c70cSMichal Meloun 		child = ofw_bus_find_child(rnode, act8846_regdefs[i].name);
4684388c70cSMichal Meloun 		if (child == 0) {
4694388c70cSMichal Meloun 			if (bootverbose)
4704388c70cSMichal Meloun 				device_printf(sc->dev,
4714388c70cSMichal Meloun 				    "Regulator %s missing in DT\n",
4724388c70cSMichal Meloun 				    act8846_regdefs[i].name);
4734388c70cSMichal Meloun 			continue;
4744388c70cSMichal Meloun 		}
4754388c70cSMichal Meloun 		reg = act8846_attach(sc, node, child, act8846_regdefs + i);
4764388c70cSMichal Meloun 		if (reg == NULL) {
4774388c70cSMichal Meloun 			device_printf(sc->dev, "Cannot attach regulator: %s\n",
4784388c70cSMichal Meloun 			    act8846_regdefs[i].name);
4794388c70cSMichal Meloun 			return (ENXIO);
4804388c70cSMichal Meloun 		}
4814388c70cSMichal Meloun 		sc->regs[i] = reg;
4824388c70cSMichal Meloun 	}
4834388c70cSMichal Meloun 	return (0);
4844388c70cSMichal Meloun }
4854388c70cSMichal Meloun 
4864388c70cSMichal Meloun int
act8846_regulator_map(device_t dev,phandle_t xref,int ncells,pcell_t * cells,int * num)4874388c70cSMichal Meloun act8846_regulator_map(device_t dev, phandle_t xref, int ncells,
4884388c70cSMichal Meloun     pcell_t *cells, int *num)
4894388c70cSMichal Meloun {
4904388c70cSMichal Meloun 	struct act8846_softc *sc;
4914388c70cSMichal Meloun 	int i;
4924388c70cSMichal Meloun 
4934388c70cSMichal Meloun 	sc = device_get_softc(dev);
4944388c70cSMichal Meloun 	for (i = 0; i < sc->nregs; i++) {
4954388c70cSMichal Meloun 		if (sc->regs[i] == NULL)
4964388c70cSMichal Meloun 			continue;
4974388c70cSMichal Meloun 		if (sc->regs[i]->xref == xref) {
4984388c70cSMichal Meloun 			*num = sc->regs[i]->def->id;
4994388c70cSMichal Meloun 			return (0);
5004388c70cSMichal Meloun 		}
5014388c70cSMichal Meloun 	}
5024388c70cSMichal Meloun 	return (ENXIO);
5034388c70cSMichal Meloun }
504