xref: /netbsd-src/sys/dev/i2c/axppmic.c (revision 43133b5d4d6fd948fe14e269bf9378b9c9cff1a7)
1*43133b5dSskrll /* $NetBSD: axppmic.c,v 1.41 2025/01/05 19:24:04 skrll Exp $ */
271a82865Sjmcneill 
371a82865Sjmcneill /*-
471a82865Sjmcneill  * Copyright (c) 2014-2018 Jared McNeill <jmcneill@invisible.ca>
571a82865Sjmcneill  * All rights reserved.
671a82865Sjmcneill  *
771a82865Sjmcneill  * Redistribution and use in source and binary forms, with or without
871a82865Sjmcneill  * modification, are permitted provided that the following conditions
971a82865Sjmcneill  * are met:
1071a82865Sjmcneill  * 1. Redistributions of source code must retain the above copyright
1171a82865Sjmcneill  *    notice, this list of conditions and the following disclaimer.
1271a82865Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
1371a82865Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
1471a82865Sjmcneill  *    documentation and/or other materials provided with the distribution.
1571a82865Sjmcneill  *
1671a82865Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1771a82865Sjmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1871a82865Sjmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1971a82865Sjmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2071a82865Sjmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2171a82865Sjmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2271a82865Sjmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2371a82865Sjmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2471a82865Sjmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2571a82865Sjmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2671a82865Sjmcneill  * POSSIBILITY OF SUCH DAMAGE.
2771a82865Sjmcneill  */
2871a82865Sjmcneill 
2971a82865Sjmcneill #include <sys/cdefs.h>
30*43133b5dSskrll __KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 1.41 2025/01/05 19:24:04 skrll Exp $");
3171a82865Sjmcneill 
3271a82865Sjmcneill #include <sys/param.h>
3371a82865Sjmcneill #include <sys/systm.h>
3471a82865Sjmcneill #include <sys/kernel.h>
3571a82865Sjmcneill #include <sys/device.h>
3671a82865Sjmcneill #include <sys/conf.h>
3771a82865Sjmcneill #include <sys/bus.h>
3871a82865Sjmcneill #include <sys/kmem.h>
39d172e13fSthorpej #include <sys/workqueue.h>
4071a82865Sjmcneill 
4171a82865Sjmcneill #include <dev/i2c/i2cvar.h>
4271a82865Sjmcneill 
4371a82865Sjmcneill #include <dev/sysmon/sysmonvar.h>
4471a82865Sjmcneill #include <dev/sysmon/sysmon_taskq.h>
4571a82865Sjmcneill 
4671a82865Sjmcneill #include <dev/fdt/fdtvar.h>
4771a82865Sjmcneill 
48c2f11555Sjmcneill #define	AXP_POWER_SOURCE_REG	0x00
49c2f11555Sjmcneill #define	 AXP_POWER_SOURCE_ACIN_PRESENT	__BIT(7)
50c2f11555Sjmcneill #define	 AXP_POWER_SOURCE_VBUS_PRESENT	__BIT(5)
5186c215ccSjmcneill #define	 AXP_POWER_SOURCE_CHARGE_DIRECTION __BIT(2)
52c2f11555Sjmcneill 
53b4d62e18Sjmcneill #define	AXP_POWER_MODE_REG	0x01
54b4d62e18Sjmcneill #define	 AXP_POWER_MODE_BATT_VALID	__BIT(4)
55b4d62e18Sjmcneill #define	 AXP_POWER_MODE_BATT_PRESENT	__BIT(5)
56b4d62e18Sjmcneill #define	 AXP_POWER_MODE_BATT_CHARGING	__BIT(6)
57b4d62e18Sjmcneill 
58c9ef8419Sjmcneill #define	AXP_CHIP_ID_REG		0x03
59c9ef8419Sjmcneill 
6071a82865Sjmcneill #define AXP_POWER_DISABLE_REG	0x32
6171a82865Sjmcneill #define	 AXP_POWER_DISABLE_CTRL	__BIT(7)
6271a82865Sjmcneill 
6371a82865Sjmcneill #define AXP_IRQ_ENABLE_REG(n)	(0x40 + (n) - 1)
645a236e50Sjmcneill #define	 AXP_IRQ1_ACIN_RAISE	__BIT(6)
655a236e50Sjmcneill #define	 AXP_IRQ1_ACIN_LOWER	__BIT(5)
665a236e50Sjmcneill #define	 AXP_IRQ1_VBUS_RAISE	__BIT(3)
675a236e50Sjmcneill #define	 AXP_IRQ1_VBUS_LOWER	__BIT(2)
6871a82865Sjmcneill #define AXP_IRQ_STATUS_REG(n)	(0x48 + (n) - 1)
6971a82865Sjmcneill 
7086c215ccSjmcneill #define	AXP_BATSENSE_HI_REG	0x78
7186c215ccSjmcneill #define	AXP_BATSENSE_LO_REG	0x79
7286c215ccSjmcneill 
7386c215ccSjmcneill #define	AXP_BATTCHG_HI_REG	0x7a
7486c215ccSjmcneill #define	AXP_BATTCHG_LO_REG	0x7b
7586c215ccSjmcneill 
7686c215ccSjmcneill #define	AXP_BATTDISCHG_HI_REG	0x7c
7786c215ccSjmcneill #define	AXP_BATTDISCHG_LO_REG	0x7d
7886c215ccSjmcneill 
7986c215ccSjmcneill #define	AXP_ADC_RAW(_hi, _lo)	\
80eec37234Sjakllsch 	(((u_int)(_hi) << 4) | ((_lo) & 0xf))
8186c215ccSjmcneill 
82ee5caec1Sjmcneill #define	AXP_GPIO_CTRL_REG(pin)	(0x90 + (pin) * 2)
83ee5caec1Sjmcneill #define	 AXP_GPIO_CTRL_FUNC_MASK 	__BITS(2,0)
84ee5caec1Sjmcneill #define	 AXP_GPIO_CTRL_FUNC_LOW	 	0
85ee5caec1Sjmcneill #define	 AXP_GPIO_CTRL_FUNC_HIGH	1
86ee5caec1Sjmcneill #define	 AXP_GPIO_CTRL_FUNC_INPUT	2
87ee5caec1Sjmcneill #define	AXP_GPIO_SIGNAL_REG	0x94
88ee5caec1Sjmcneill 
89b4d62e18Sjmcneill #define	AXP_FUEL_GAUGE_CTRL_REG	0xb8
90b4d62e18Sjmcneill #define	 AXP_FUEL_GAUGE_CTRL_EN	__BIT(7)
9186c215ccSjmcneill 
92b4d62e18Sjmcneill #define	AXP_BATT_CAP_REG	0xb9
93b4d62e18Sjmcneill #define	 AXP_BATT_CAP_VALID	__BIT(7)
94b4d62e18Sjmcneill #define	 AXP_BATT_CAP_PERCENT	__BITS(6,0)
95b4d62e18Sjmcneill 
96a8e9e1a9Sjakllsch #define	AXP_BATT_MAX_CAP_HI_REG	0xe0
97a8e9e1a9Sjakllsch #define	 AXP_BATT_MAX_CAP_VALID	__BIT(7)
98a8e9e1a9Sjakllsch #define	AXP_BATT_MAX_CAP_LO_REG	0xe1
99a8e9e1a9Sjakllsch 
100a8e9e1a9Sjakllsch #define	AXP_BATT_COULOMB_HI_REG	0xe2
101a8e9e1a9Sjakllsch #define	 AXP_BATT_COULOMB_VALID	__BIT(7)
102a8e9e1a9Sjakllsch #define	AXP_BATT_COULOMB_LO_REG	0xe3
103a8e9e1a9Sjakllsch 
104a8e9e1a9Sjakllsch #define	AXP_COULOMB_RAW(_hi, _lo)	\
105a8e9e1a9Sjakllsch 	(((u_int)(_hi & ~__BIT(7)) << 8) | (_lo))
106a8e9e1a9Sjakllsch 
107b4d62e18Sjmcneill #define	AXP_BATT_CAP_WARN_REG	0xe6
108b4d62e18Sjmcneill #define	 AXP_BATT_CAP_WARN_LV1	__BITS(7,4)
109b4d62e18Sjmcneill #define	 AXP_BATT_CAP_WARN_LV2	__BITS(3,0)
110b4d62e18Sjmcneill 
111c9ef8419Sjmcneill #define	AXP_ADDR_EXT_REG	0xff	/* AXP806 */
112c9ef8419Sjmcneill #define	 AXP_ADDR_EXT_MASTER	0
113c9ef8419Sjmcneill #define	 AXP_ADDR_EXT_SLAVE	__BIT(4)
114c9ef8419Sjmcneill 
11571a82865Sjmcneill struct axppmic_ctrl {
11671a82865Sjmcneill 	device_t	c_dev;
11771a82865Sjmcneill 
11871a82865Sjmcneill 	const char *	c_name;
11971a82865Sjmcneill 	u_int		c_min;
12071a82865Sjmcneill 	u_int		c_max;
12171a82865Sjmcneill 	u_int		c_step1;
12271a82865Sjmcneill 	u_int		c_step1cnt;
12371a82865Sjmcneill 	u_int		c_step2;
12471a82865Sjmcneill 	u_int		c_step2cnt;
1252df3325bSjmcneill 	u_int		c_step2start;
12671a82865Sjmcneill 
12771a82865Sjmcneill 	uint8_t		c_enable_reg;
12871a82865Sjmcneill 	uint8_t		c_enable_mask;
129a1e24c6aSjmcneill 	uint8_t		c_enable_val;
130a1e24c6aSjmcneill 	uint8_t		c_disable_val;
13171a82865Sjmcneill 
13271a82865Sjmcneill 	uint8_t		c_voltage_reg;
13371a82865Sjmcneill 	uint8_t		c_voltage_mask;
13471a82865Sjmcneill };
13571a82865Sjmcneill 
13671a82865Sjmcneill #define AXP_CTRL(name, min, max, step, ereg, emask, vreg, vmask)	\
13771a82865Sjmcneill 	{ .c_name = (name), .c_min = (min), .c_max = (max),		\
13871a82865Sjmcneill 	  .c_step1 = (step), .c_step1cnt = (((max) - (min)) / (step)) + 1, \
13971a82865Sjmcneill 	  .c_step2 = 0, .c_step2cnt = 0,				\
14071a82865Sjmcneill 	  .c_enable_reg = (ereg), .c_enable_mask = (emask),		\
141a1e24c6aSjmcneill 	  .c_enable_val = (emask), .c_disable_val = 0,			\
14271a82865Sjmcneill 	  .c_voltage_reg = (vreg), .c_voltage_mask = (vmask) }
14371a82865Sjmcneill 
14471a82865Sjmcneill #define AXP_CTRL2(name, min, max, step1, step1cnt, step2, step2cnt, ereg, emask, vreg, vmask) \
14571a82865Sjmcneill 	{ .c_name = (name), .c_min = (min), .c_max = (max),		\
14671a82865Sjmcneill 	  .c_step1 = (step1), .c_step1cnt = (step1cnt),			\
14771a82865Sjmcneill 	  .c_step2 = (step2), .c_step2cnt = (step2cnt),			\
14871a82865Sjmcneill 	  .c_enable_reg = (ereg), .c_enable_mask = (emask),		\
149a1e24c6aSjmcneill 	  .c_enable_val = (emask), .c_disable_val = 0,			\
15071a82865Sjmcneill 	  .c_voltage_reg = (vreg), .c_voltage_mask = (vmask) }
15171a82865Sjmcneill 
1522df3325bSjmcneill #define AXP_CTRL2_RANGE(name, min, max, step1, step1cnt, step2start, step2, step2cnt, ereg, emask, vreg, vmask) \
1532df3325bSjmcneill 	{ .c_name = (name), .c_min = (min), .c_max = (max),		\
1542df3325bSjmcneill 	  .c_step1 = (step1), .c_step1cnt = (step1cnt),			\
1552df3325bSjmcneill 	  .c_step2start = (step2start),					\
1562df3325bSjmcneill 	  .c_step2 = (step2), .c_step2cnt = (step2cnt),			\
1572df3325bSjmcneill 	  .c_enable_reg = (ereg), .c_enable_mask = (emask),		\
1582df3325bSjmcneill 	  .c_enable_val = (emask), .c_disable_val = 0,			\
1592df3325bSjmcneill 	  .c_voltage_reg = (vreg), .c_voltage_mask = (vmask) }
1602df3325bSjmcneill 
161a1e24c6aSjmcneill #define AXP_CTRL_IO(name, min, max, step, ereg, emask, eval, dval, vreg, vmask)	\
162a1e24c6aSjmcneill 	{ .c_name = (name), .c_min = (min), .c_max = (max),		\
163a1e24c6aSjmcneill 	  .c_step1 = (step), .c_step1cnt = (((max) - (min)) / (step)) + 1, \
164a1e24c6aSjmcneill 	  .c_step2 = 0, .c_step2cnt = 0,				\
165a1e24c6aSjmcneill 	  .c_enable_reg = (ereg), .c_enable_mask = (emask),		\
166a1e24c6aSjmcneill 	  .c_enable_val = (eval), .c_disable_val = (dval),		\
167a1e24c6aSjmcneill 	  .c_voltage_reg = (vreg), .c_voltage_mask = (vmask) }
168a1e24c6aSjmcneill 
1692df3325bSjmcneill #define AXP_CTRL_SW(name, ereg, emask)					\
1702df3325bSjmcneill 	{ .c_name = (name), 						\
1712df3325bSjmcneill 	  .c_enable_reg = (ereg), .c_enable_mask = (emask),		\
1722df3325bSjmcneill 	  .c_enable_val = (emask), .c_disable_val = 0 }
173a1e24c6aSjmcneill 
17471a82865Sjmcneill static const struct axppmic_ctrl axp803_ctrls[] = {
17571a82865Sjmcneill 	AXP_CTRL("dldo1", 700, 3300, 100,
17671a82865Sjmcneill 		0x12, __BIT(3), 0x15, __BITS(4,0)),
17771a82865Sjmcneill 	AXP_CTRL2("dldo2", 700, 4200, 100, 28, 200, 4,
17871a82865Sjmcneill 		0x12, __BIT(4), 0x16, __BITS(4,0)),
17971a82865Sjmcneill 	AXP_CTRL("dldo3", 700, 3300, 100,
18071a82865Sjmcneill 	 	0x12, __BIT(5), 0x17, __BITS(4,0)),
18171a82865Sjmcneill 	AXP_CTRL("dldo4", 700, 3300, 100,
18271a82865Sjmcneill 		0x12, __BIT(6), 0x18, __BITS(4,0)),
18371a82865Sjmcneill 	AXP_CTRL("eldo1", 700, 1900, 50,
18471a82865Sjmcneill 		0x12, __BIT(0), 0x19, __BITS(4,0)),
18571a82865Sjmcneill 	AXP_CTRL("eldo2", 700, 1900, 50,
18671a82865Sjmcneill 		0x12, __BIT(1), 0x1a, __BITS(4,0)),
18771a82865Sjmcneill 	AXP_CTRL("eldo3", 700, 1900, 50,
18871a82865Sjmcneill 		0x12, __BIT(2), 0x1b, __BITS(4,0)),
18971a82865Sjmcneill 	AXP_CTRL("fldo1", 700, 1450, 50,
19071a82865Sjmcneill 		0x13, __BIT(2), 0x1c, __BITS(3,0)),
19171a82865Sjmcneill 	AXP_CTRL("fldo2", 700, 1450, 50,
19271a82865Sjmcneill 		0x13, __BIT(3), 0x1d, __BITS(3,0)),
19371a82865Sjmcneill 	AXP_CTRL("dcdc1", 1600, 3400, 100,
19471a82865Sjmcneill 		0x10, __BIT(0), 0x20, __BITS(4,0)),
195c917873fSjmcneill 	AXP_CTRL2("dcdc2", 500, 1300, 10, 70, 20, 5,
19671a82865Sjmcneill 		0x10, __BIT(1), 0x21, __BITS(6,0)),
197c917873fSjmcneill 	AXP_CTRL2("dcdc3", 500, 1300, 10, 70, 20, 5,
19871a82865Sjmcneill 		0x10, __BIT(2), 0x22, __BITS(6,0)),
199c917873fSjmcneill 	AXP_CTRL2("dcdc4", 500, 1300, 10, 70, 20, 5,
20071a82865Sjmcneill 		0x10, __BIT(3), 0x23, __BITS(6,0)),
20171a82865Sjmcneill 	AXP_CTRL2("dcdc5", 800, 1840, 10, 33, 20, 36,
20271a82865Sjmcneill 		0x10, __BIT(4), 0x24, __BITS(6,0)),
20371a82865Sjmcneill 	AXP_CTRL2("dcdc6", 600, 1520, 10, 51, 20, 21,
20471a82865Sjmcneill 		0x10, __BIT(5), 0x25, __BITS(6,0)),
20571a82865Sjmcneill 	AXP_CTRL("aldo1", 700, 3300, 100,
20671a82865Sjmcneill 		0x13, __BIT(5), 0x28, __BITS(4,0)),
20771a82865Sjmcneill 	AXP_CTRL("aldo2", 700, 3300, 100,
20871a82865Sjmcneill 		0x13, __BIT(6), 0x29, __BITS(4,0)),
20971a82865Sjmcneill 	AXP_CTRL("aldo3", 700, 3300, 100,
21071a82865Sjmcneill 		0x13, __BIT(7), 0x2a, __BITS(4,0)),
21171a82865Sjmcneill };
21271a82865Sjmcneill 
21371a82865Sjmcneill static const struct axppmic_ctrl axp805_ctrls[] = {
21471a82865Sjmcneill 	AXP_CTRL2("dcdca", 600, 1520, 10, 51, 20, 21,
21571a82865Sjmcneill 		0x10, __BIT(0), 0x12, __BITS(6,0)),
21671a82865Sjmcneill 	AXP_CTRL("dcdcb", 1000, 2550, 50,
21771a82865Sjmcneill 		0x10, __BIT(1), 0x13, __BITS(4,0)),
21871a82865Sjmcneill 	AXP_CTRL2("dcdcc", 600, 1520, 10, 51, 20, 21,
21971a82865Sjmcneill 		0x10, __BIT(2), 0x14, __BITS(6,0)),
22071a82865Sjmcneill 	AXP_CTRL2("dcdcd", 600, 3300, 20, 46, 100, 18,
22171a82865Sjmcneill 		0x10, __BIT(3), 0x15, __BITS(5,0)),
22271a82865Sjmcneill 	AXP_CTRL("dcdce", 1100, 3400, 100,
22371a82865Sjmcneill 		0x10, __BIT(4), 0x16, __BITS(4,0)),
22471a82865Sjmcneill 	AXP_CTRL("aldo1", 700, 3300, 100,
22571a82865Sjmcneill 		0x10, __BIT(5), 0x17, __BITS(4,0)),
22671a82865Sjmcneill 	AXP_CTRL("aldo2", 700, 3400, 100,
22771a82865Sjmcneill 		0x10, __BIT(6), 0x18, __BITS(4,0)),
22871a82865Sjmcneill 	AXP_CTRL("aldo3", 700, 3300, 100,
22971a82865Sjmcneill 		0x10, __BIT(7), 0x19, __BITS(4,0)),
23071a82865Sjmcneill 	AXP_CTRL("bldo1", 700, 1900, 100,
23171a82865Sjmcneill 		0x11, __BIT(0), 0x20, __BITS(3,0)),
23271a82865Sjmcneill 	AXP_CTRL("bldo2", 700, 1900, 100,
23371a82865Sjmcneill 		0x11, __BIT(1), 0x21, __BITS(3,0)),
23471a82865Sjmcneill 	AXP_CTRL("bldo3", 700, 1900, 100,
23571a82865Sjmcneill 		0x11, __BIT(2), 0x22, __BITS(3,0)),
23671a82865Sjmcneill 	AXP_CTRL("bldo4", 700, 1900, 100,
23771a82865Sjmcneill 		0x11, __BIT(3), 0x23, __BITS(3,0)),
23871a82865Sjmcneill 	AXP_CTRL("cldo1", 700, 3300, 100,
23971a82865Sjmcneill 		0x11, __BIT(4), 0x24, __BITS(4,0)),
24071a82865Sjmcneill 	AXP_CTRL2("cldo2", 700, 4200, 100, 28, 200, 4,
24171a82865Sjmcneill 		0x11, __BIT(5), 0x25, __BITS(4,0)),
24271a82865Sjmcneill 	AXP_CTRL("cldo3", 700, 3300, 100,
24371a82865Sjmcneill 		0x11, __BIT(6), 0x26, __BITS(4,0)),
24471a82865Sjmcneill };
24571a82865Sjmcneill 
246b42d70dbSjmcneill static const struct axppmic_ctrl axp809_ctrls[] = {
2472df3325bSjmcneill 	AXP_CTRL("dc5ldo", 700, 1400, 100,
2482df3325bSjmcneill 		0x10, __BIT(0), 0x1c, __BITS(2,0)),
2492df3325bSjmcneill 	AXP_CTRL("dcdc1", 1600, 3400, 100,
2502df3325bSjmcneill 		0x10, __BIT(1), 0x21, __BITS(4,0)),
2512df3325bSjmcneill 	AXP_CTRL("dcdc2", 600, 1540, 20,
2522df3325bSjmcneill 		0x10, __BIT(2), 0x22, __BITS(5,0)),
2532df3325bSjmcneill 	AXP_CTRL("dcdc3", 600, 1860, 20,
2542df3325bSjmcneill 		0x10, __BIT(3), 0x23, __BITS(5,0)),
2552df3325bSjmcneill 	AXP_CTRL2_RANGE("dcdc4", 600, 2600, 20, 47, 1800, 100, 9,
2562df3325bSjmcneill 		0x10, __BIT(4), 0x24, __BITS(5,0)),
2572df3325bSjmcneill 	AXP_CTRL("dcdc5", 1000, 2550, 50,
2582df3325bSjmcneill 		0x10, __BIT(5), 0x25, __BITS(4,0)),
2592df3325bSjmcneill 	AXP_CTRL("aldo1", 700, 3300, 100,
2602df3325bSjmcneill 		0x10, __BIT(6), 0x28, __BITS(4,0)),
2612df3325bSjmcneill 	AXP_CTRL("aldo2", 700, 3300, 100,
2622df3325bSjmcneill 		0x10, __BIT(7), 0x29, __BITS(4,0)),
2632df3325bSjmcneill 	AXP_CTRL("eldo1", 700, 3300, 100,
2642df3325bSjmcneill 		0x12, __BIT(0), 0x19, __BITS(4,0)),
2652df3325bSjmcneill 	AXP_CTRL("eldo2", 700, 3300, 100,
2662df3325bSjmcneill 		0x12, __BIT(1), 0x1a, __BITS(4,0)),
2672df3325bSjmcneill 	AXP_CTRL("eldo3", 700, 3300, 100,
2682df3325bSjmcneill 		0x12, __BIT(2), 0x1b, __BITS(4,0)),
2692df3325bSjmcneill 	AXP_CTRL2_RANGE("dldo1", 700, 4000, 100, 26, 3400, 200, 4,
2702df3325bSjmcneill 		0x12, __BIT(3), 0x15, __BITS(4,0)),
2712df3325bSjmcneill 	AXP_CTRL("dldo2", 700, 3300, 100,
2722df3325bSjmcneill 		0x12, __BIT(4), 0x16, __BITS(4,0)),
2732df3325bSjmcneill 	AXP_CTRL("aldo3", 700, 3300, 100,
2742df3325bSjmcneill 		0x12, __BIT(5), 0x2a, __BITS(4,0)),
2752df3325bSjmcneill 	AXP_CTRL_SW("sw",
2762df3325bSjmcneill 		0x12, __BIT(6)),
2772df3325bSjmcneill 	/* dc1sw is another switch for dcdc1 */
2782df3325bSjmcneill 	AXP_CTRL("dc1sw", 1600, 3400, 100,
2792df3325bSjmcneill 		0x12, __BIT(7), 0x21, __BITS(4,0)),
280a1e24c6aSjmcneill 	AXP_CTRL_IO("ldo_io0", 700, 3300, 100,
281a1e24c6aSjmcneill 		0x90, __BITS(3,0), 0x3, 0x7, 0x91, __BITS(4,0)),
282a1e24c6aSjmcneill 	AXP_CTRL_IO("ldo_io1", 700, 3300, 100,
283a1e24c6aSjmcneill 		0x92, __BITS(3,0), 0x3, 0x7, 0x93, __BITS(4,0)),
284b42d70dbSjmcneill };
285b42d70dbSjmcneill 
286efe109bdSjmcneill static const struct axppmic_ctrl axp813_ctrls[] = {
287efe109bdSjmcneill 	AXP_CTRL("dldo1", 700, 3300, 100,
288efe109bdSjmcneill 		0x12, __BIT(3), 0x15, __BITS(4,0)),
289efe109bdSjmcneill 	AXP_CTRL2("dldo2", 700, 4200, 100, 28, 200, 4,
290efe109bdSjmcneill 		0x12, __BIT(4), 0x16, __BITS(4,0)),
291efe109bdSjmcneill 	AXP_CTRL("dldo3", 700, 3300, 100,
292efe109bdSjmcneill 	 	0x12, __BIT(5), 0x17, __BITS(4,0)),
293efe109bdSjmcneill 	AXP_CTRL("dldo4", 700, 3300, 100,
294efe109bdSjmcneill 		0x12, __BIT(6), 0x18, __BITS(4,0)),
295efe109bdSjmcneill 	AXP_CTRL("eldo1", 700, 1900, 50,
296efe109bdSjmcneill 		0x12, __BIT(0), 0x19, __BITS(4,0)),
297efe109bdSjmcneill 	AXP_CTRL("eldo2", 700, 1900, 50,
298efe109bdSjmcneill 		0x12, __BIT(1), 0x1a, __BITS(4,0)),
299efe109bdSjmcneill 	AXP_CTRL("eldo3", 700, 1900, 50,
300efe109bdSjmcneill 		0x12, __BIT(2), 0x1b, __BITS(4,0)),
301efe109bdSjmcneill 	AXP_CTRL("fldo1", 700, 1450, 50,
302efe109bdSjmcneill 		0x13, __BIT(2), 0x1c, __BITS(3,0)),
303efe109bdSjmcneill 	AXP_CTRL("fldo2", 700, 1450, 50,
304efe109bdSjmcneill 		0x13, __BIT(3), 0x1d, __BITS(3,0)),
305efe109bdSjmcneill 	AXP_CTRL("dcdc1", 1600, 3400, 100,
306efe109bdSjmcneill 		0x10, __BIT(0), 0x20, __BITS(4,0)),
307efe109bdSjmcneill 	AXP_CTRL2("dcdc2", 500, 1300, 10, 70, 20, 5,
308efe109bdSjmcneill 		0x10, __BIT(1), 0x21, __BITS(6,0)),
309efe109bdSjmcneill 	AXP_CTRL2("dcdc3", 500, 1300, 10, 70, 20, 5,
310efe109bdSjmcneill 		0x10, __BIT(2), 0x22, __BITS(6,0)),
311efe109bdSjmcneill 	AXP_CTRL2("dcdc4", 500, 1300, 10, 70, 20, 5,
312efe109bdSjmcneill 		0x10, __BIT(3), 0x23, __BITS(6,0)),
313efe109bdSjmcneill 	AXP_CTRL2("dcdc5", 800, 1840, 10, 33, 20, 36,
314efe109bdSjmcneill 		0x10, __BIT(4), 0x24, __BITS(6,0)),
315efe109bdSjmcneill 	AXP_CTRL2("dcdc6", 600, 1520, 10, 51, 20, 21,
316efe109bdSjmcneill 		0x10, __BIT(5), 0x25, __BITS(6,0)),
317efe109bdSjmcneill 	AXP_CTRL2("dcdc7", 600, 1520, 10, 51, 20, 21,
318efe109bdSjmcneill 		0x10, __BIT(6), 0x26, __BITS(6,0)),
319efe109bdSjmcneill 	AXP_CTRL("aldo1", 700, 3300, 100,
320efe109bdSjmcneill 		0x13, __BIT(5), 0x28, __BITS(4,0)),
321efe109bdSjmcneill 	AXP_CTRL("aldo2", 700, 3300, 100,
322efe109bdSjmcneill 		0x13, __BIT(6), 0x29, __BITS(4,0)),
323efe109bdSjmcneill 	AXP_CTRL("aldo3", 700, 3300, 100,
324efe109bdSjmcneill 		0x13, __BIT(7), 0x2a, __BITS(4,0)),
325efe109bdSjmcneill };
326efe109bdSjmcneill 
3270f6eea99Sskrll static const struct axppmic_ctrl axp15060_ctrls[] = {
3280f6eea99Sskrll 	AXP_CTRL( "dcdc1",  1500, 3400, 100,
3290f6eea99Sskrll 		 0x13, __BITS(4, 0),
3300f6eea99Sskrll 		 0x10, __BIT(0)),
3310f6eea99Sskrll 	// DCDC2: 0.5~1.2V, 10mV/step, 1.22~1.54V, 20mV/step, IMAX=3.5A, DVM
3320f6eea99Sskrll 	AXP_CTRL2_RANGE("dcdc2",
3330f6eea99Sskrll 			500, 1540, 70, 10, 1220, 16 , 20,
3340f6eea99Sskrll 			0x14, __BITS(6, 0),
3350f6eea99Sskrll 			0x10, __BIT(1)),
3360f6eea99Sskrll 	// DCDC3: 0.5~1.2V, 10mV/step, 1.22~1.54V, 20mV/step, IMAX=3.5A, DVM
3370f6eea99Sskrll 	AXP_CTRL2_RANGE("dcdc3",
3380f6eea99Sskrll 			500, 1540, 70, 10, 1220, 16 , 20,
3390f6eea99Sskrll 			0x15, __BITS(6, 0),
3400f6eea99Sskrll 			0x10, __BIT(2)),
3410f6eea99Sskrll 	// DCDC4: 0.5~1.2V, 10mV/step, 1.22~1.54V, 20mV/step, IMAX=3.5A, DVM
3420f6eea99Sskrll 	AXP_CTRL2_RANGE("dcdc4",
3430f6eea99Sskrll 			500, 1540, 70, 10, 1220, 16 , 20,
3440f6eea99Sskrll 			0x16, __BITS(6, 0),
3450f6eea99Sskrll 			0x10, __BIT(3)),
3460f6eea99Sskrll 	// DCDC5: 0.8~1.12V, 10mV/step, 1.14~1.84V, 20mV/step, IMAX=2.5A, DVM
3470f6eea99Sskrll 	AXP_CTRL2_RANGE("dcdc5",
3480f6eea99Sskrll 			800, 1840,
3490f6eea99Sskrll 			32, 10,
3500f6eea99Sskrll 			1140, 35, 20,
3510f6eea99Sskrll 			0x17, __BITS(6, 0),
3520f6eea99Sskrll 			0x10, __BIT(4)),
3530f6eea99Sskrll 	AXP_CTRL("dcdc6", 500, 3400, 100,
3540f6eea99Sskrll 		 0x18, __BITS(4, 0),
3550f6eea99Sskrll 		 0x10, __BIT(5)),
3560f6eea99Sskrll 	AXP_CTRL("aldo1", 700, 3300, 100,
3570f6eea99Sskrll 		 0x19, __BITS(4, 0),
3580f6eea99Sskrll 		 0x11, __BIT(0)),
3590f6eea99Sskrll 	AXP_CTRL("aldo2", 700, 3300, 100,
3600f6eea99Sskrll 		 0x20, __BITS(4, 0),
3610f6eea99Sskrll 		 0x11, __BIT(1)),
3620f6eea99Sskrll 	AXP_CTRL("aldo3", 700, 3300, 100,
3630f6eea99Sskrll 		 0x21, __BITS(4, 0),
3640f6eea99Sskrll 		 0x11, __BIT(2)),
3650f6eea99Sskrll 	AXP_CTRL("aldo4", 700, 3300, 100,
3660f6eea99Sskrll 		 0x22, __BITS(4, 0),
3670f6eea99Sskrll 		 0x11, __BIT(3)),
3680f6eea99Sskrll 	AXP_CTRL("aldo5", 700, 3300, 100,
3690f6eea99Sskrll 		 0x23, __BITS(4, 0),
3700f6eea99Sskrll 		 0x11, __BIT(4)),
3710f6eea99Sskrll 	AXP_CTRL("bldo1", 700, 3300, 100,
3720f6eea99Sskrll 		 0x24, __BITS(4, 0),
3730f6eea99Sskrll 		 0x11, __BIT(5)),
3740f6eea99Sskrll 	AXP_CTRL("bldo2", 700, 3300, 100,
3750f6eea99Sskrll 		 0x25, __BITS(4, 0),
3760f6eea99Sskrll 		 0x11, __BIT(6)),
3770f6eea99Sskrll 	AXP_CTRL("bldo3", 700, 3300, 100,
3780f6eea99Sskrll 		 0x26, __BITS(4, 0),
3790f6eea99Sskrll 		 0x11, __BIT(7)),
3800f6eea99Sskrll 	AXP_CTRL("bldo4", 700, 3300, 100,
3810f6eea99Sskrll 		 0x27, __BITS(4, 0),
3820f6eea99Sskrll 		 0x12, __BIT(0)),
3830f6eea99Sskrll 	AXP_CTRL("bldo5", 700, 3300, 100,
3840f6eea99Sskrll 		 0x28, __BITS(4, 0),
3850f6eea99Sskrll 		 0x12, __BIT(1)),
3860f6eea99Sskrll 	AXP_CTRL("cldo1", 700, 3300, 100,
3870f6eea99Sskrll 		 0x29, __BITS(4, 0),
3880f6eea99Sskrll 		 0x12, __BIT(2)),
3890f6eea99Sskrll 	AXP_CTRL("cldo2", 700, 3300, 100,
3900f6eea99Sskrll 		 0x2a, __BITS(4, 0),
3910f6eea99Sskrll 		 0x12, __BIT(3)),
3920f6eea99Sskrll 	AXP_CTRL("cldo3", 700, 3300, 100,
3930f6eea99Sskrll 		 0x2b, __BITS(4, 0),
3940f6eea99Sskrll 		 0x12, __BIT(4)),
3950f6eea99Sskrll 	AXP_CTRL("cldo4", 700, 4200, 100,
3960f6eea99Sskrll 		 0x2d, __BITS(5, 0),
3970f6eea99Sskrll 		 0x12, __BIT(5)),
3980f6eea99Sskrll 	AXP_CTRL("cpusldo", 700, 1400, 50,
3990f6eea99Sskrll 		 0x2e, __BITS(3, 0),
4000f6eea99Sskrll 		 0x12, __BIT(6)),
4010f6eea99Sskrll };
4020f6eea99Sskrll 
4030f6eea99Sskrll 
404c6020708Sjmcneill struct axppmic_irq {
405c6020708Sjmcneill 	u_int reg;
406c6020708Sjmcneill 	uint8_t mask;
407c6020708Sjmcneill };
408c6020708Sjmcneill 
409c6020708Sjmcneill #define	AXPPMIC_IRQ(_reg, _mask)	\
410c6020708Sjmcneill 	{ .reg = (_reg), .mask = (_mask) }
411c6020708Sjmcneill 
41271a82865Sjmcneill struct axppmic_config {
41371a82865Sjmcneill 	const char *name;
414ee5caec1Sjmcneill 	const char *gpio_compat;
415ee5caec1Sjmcneill 	u_int gpio_npins;
41671a82865Sjmcneill 	const struct axppmic_ctrl *controls;
41771a82865Sjmcneill 	u_int ncontrols;
41871a82865Sjmcneill 	u_int irq_regs;
419b4d62e18Sjmcneill 	bool has_battery;
420b4d62e18Sjmcneill 	bool has_fuel_gauge;
421c9ef8419Sjmcneill 	bool has_mode_set;
422c6020708Sjmcneill 	struct axppmic_irq poklirq;
423c6020708Sjmcneill 	struct axppmic_irq acinirq;
424c6020708Sjmcneill 	struct axppmic_irq vbusirq;
425c6020708Sjmcneill 	struct axppmic_irq battirq;
426c6020708Sjmcneill 	struct axppmic_irq chargeirq;
427c6020708Sjmcneill 	struct axppmic_irq chargestirq;
42886c215ccSjmcneill 	u_int batsense_step;	/* uV */
42986c215ccSjmcneill 	u_int charge_step;	/* uA */
43086c215ccSjmcneill 	u_int discharge_step;	/* uA */
43186c215ccSjmcneill 	u_int maxcap_step;	/* uAh */
43286c215ccSjmcneill 	u_int coulomb_step;	/* uAh */
433b4d62e18Sjmcneill };
434b4d62e18Sjmcneill 
435b4d62e18Sjmcneill enum axppmic_sensor {
436c2f11555Sjmcneill 	AXP_SENSOR_ACIN_PRESENT,
437c2f11555Sjmcneill 	AXP_SENSOR_VBUS_PRESENT,
438b4d62e18Sjmcneill 	AXP_SENSOR_BATT_PRESENT,
439b4d62e18Sjmcneill 	AXP_SENSOR_BATT_CHARGING,
440b4d62e18Sjmcneill 	AXP_SENSOR_BATT_CHARGE_STATE,
44186c215ccSjmcneill 	AXP_SENSOR_BATT_VOLTAGE,
44286c215ccSjmcneill 	AXP_SENSOR_BATT_CHARGE_CURRENT,
44386c215ccSjmcneill 	AXP_SENSOR_BATT_DISCHARGE_CURRENT,
44486c215ccSjmcneill 	AXP_SENSOR_BATT_CAPACITY_PERCENT,
445a8e9e1a9Sjakllsch 	AXP_SENSOR_BATT_MAXIMUM_CAPACITY,
446a8e9e1a9Sjakllsch 	AXP_SENSOR_BATT_CURRENT_CAPACITY,
447b4d62e18Sjmcneill 	AXP_NSENSORS
44871a82865Sjmcneill };
44971a82865Sjmcneill 
45071a82865Sjmcneill struct axppmic_softc {
45171a82865Sjmcneill 	device_t	sc_dev;
45271a82865Sjmcneill 	i2c_tag_t	sc_i2c;
45371a82865Sjmcneill 	i2c_addr_t	sc_addr;
45471a82865Sjmcneill 	int		sc_phandle;
45571a82865Sjmcneill 
456d172e13fSthorpej 	void		*sc_ih;
457d172e13fSthorpej 	struct workqueue *sc_wq;
458d172e13fSthorpej 
459d172e13fSthorpej 	kmutex_t	sc_intr_lock;
460d172e13fSthorpej 	struct work	sc_work;
461d172e13fSthorpej 	bool		sc_work_scheduled;
462d172e13fSthorpej 
463c6020708Sjmcneill 	const struct axppmic_config *sc_conf;
464b4d62e18Sjmcneill 
46571a82865Sjmcneill 	struct sysmon_pswitch sc_smpsw;
46671a82865Sjmcneill 
467b4d62e18Sjmcneill 	struct sysmon_envsys *sc_sme;
468c2f11555Sjmcneill 
469b4d62e18Sjmcneill 	envsys_data_t	sc_sensor[AXP_NSENSORS];
47082e15d74Sjmcneill 
47182e15d74Sjmcneill 	u_int		sc_warn_thres;
47282e15d74Sjmcneill 	u_int		sc_shut_thres;
47371a82865Sjmcneill };
47471a82865Sjmcneill 
475ee5caec1Sjmcneill struct axppmic_gpio_pin {
476ee5caec1Sjmcneill 	struct axppmic_softc *pin_sc;
477ee5caec1Sjmcneill 	u_int pin_nr;
478ee5caec1Sjmcneill 	int pin_flags;
479ee5caec1Sjmcneill 	bool pin_actlo;
480ee5caec1Sjmcneill };
481ee5caec1Sjmcneill 
48271a82865Sjmcneill struct axpreg_softc {
48371a82865Sjmcneill 	device_t	sc_dev;
48471a82865Sjmcneill 	i2c_tag_t	sc_i2c;
48571a82865Sjmcneill 	i2c_addr_t	sc_addr;
48671a82865Sjmcneill 	const struct axppmic_ctrl *sc_ctrl;
48771a82865Sjmcneill };
48871a82865Sjmcneill 
48971a82865Sjmcneill struct axpreg_attach_args {
49071a82865Sjmcneill 	const struct axppmic_ctrl *reg_ctrl;
49171a82865Sjmcneill 	int		reg_phandle;
49271a82865Sjmcneill 	i2c_tag_t	reg_i2c;
49371a82865Sjmcneill 	i2c_addr_t	reg_addr;
49471a82865Sjmcneill };
49571a82865Sjmcneill 
49671a82865Sjmcneill static const struct axppmic_config axp803_config = {
49771a82865Sjmcneill 	.name = "AXP803",
498ee5caec1Sjmcneill 	.gpio_compat = "x-powers,axp803-gpio",
499ee5caec1Sjmcneill 	.gpio_npins = 2,
50071a82865Sjmcneill 	.controls = axp803_ctrls,
50171a82865Sjmcneill 	.ncontrols = __arraycount(axp803_ctrls),
50271a82865Sjmcneill 	.irq_regs = 6,
503b4d62e18Sjmcneill 	.has_battery = true,
504b4d62e18Sjmcneill 	.has_fuel_gauge = true,
50586c215ccSjmcneill 	.batsense_step = 1100,
50686c215ccSjmcneill 	.charge_step = 1000,
50786c215ccSjmcneill 	.discharge_step = 1000,
508a8e9e1a9Sjakllsch 	.maxcap_step = 1456,
509a8e9e1a9Sjakllsch 	.coulomb_step = 1456,
510c6020708Sjmcneill 	.poklirq = AXPPMIC_IRQ(5, __BIT(3)),
511c6020708Sjmcneill 	.acinirq = AXPPMIC_IRQ(1, __BITS(6,5)),
512c6020708Sjmcneill 	.vbusirq = AXPPMIC_IRQ(1, __BITS(3,2)),
513c6020708Sjmcneill 	.battirq = AXPPMIC_IRQ(2, __BITS(7,6)),
514c6020708Sjmcneill 	.chargeirq = AXPPMIC_IRQ(2, __BITS(3,2)),
515c6020708Sjmcneill 	.chargestirq = AXPPMIC_IRQ(4, __BITS(1,0)),
51671a82865Sjmcneill };
51771a82865Sjmcneill 
51871a82865Sjmcneill static const struct axppmic_config axp805_config = {
519c9ef8419Sjmcneill 	.name = "AXP805",
52071a82865Sjmcneill 	.controls = axp805_ctrls,
52171a82865Sjmcneill 	.ncontrols = __arraycount(axp805_ctrls),
52271a82865Sjmcneill 	.irq_regs = 2,
523c6020708Sjmcneill 	.poklirq = AXPPMIC_IRQ(2, __BIT(0)),
52471a82865Sjmcneill };
52571a82865Sjmcneill 
526c9ef8419Sjmcneill static const struct axppmic_config axp806_config = {
527c9ef8419Sjmcneill 	.name = "AXP806",
528c9ef8419Sjmcneill 	.controls = axp805_ctrls,
529c9ef8419Sjmcneill 	.ncontrols = __arraycount(axp805_ctrls),
530c9ef8419Sjmcneill #if notyet
531c9ef8419Sjmcneill 	.irq_regs = 2,
532c9ef8419Sjmcneill 	.poklirq = AXPPMIC_IRQ(2, __BIT(0)),
533c9ef8419Sjmcneill #endif
534c9ef8419Sjmcneill 	.has_mode_set = true,
535c9ef8419Sjmcneill };
536c9ef8419Sjmcneill 
537b42d70dbSjmcneill static const struct axppmic_config axp809_config = {
538b42d70dbSjmcneill 	.name = "AXP809",
539b42d70dbSjmcneill 	.controls = axp809_ctrls,
540b42d70dbSjmcneill 	.ncontrols = __arraycount(axp809_ctrls),
541b42d70dbSjmcneill };
542b42d70dbSjmcneill 
543efe109bdSjmcneill static const struct axppmic_config axp813_config = {
544efe109bdSjmcneill 	.name = "AXP813",
545ee5caec1Sjmcneill 	.gpio_compat = "x-powers,axp813-gpio",
546ee5caec1Sjmcneill 	.gpio_npins = 2,
547efe109bdSjmcneill 	.controls = axp813_ctrls,
548efe109bdSjmcneill 	.ncontrols = __arraycount(axp813_ctrls),
549efe109bdSjmcneill 	.irq_regs = 6,
550efe109bdSjmcneill 	.has_battery = true,
551efe109bdSjmcneill 	.has_fuel_gauge = true,
552efe109bdSjmcneill 	.batsense_step = 1100,
553efe109bdSjmcneill 	.charge_step = 1000,
554efe109bdSjmcneill 	.discharge_step = 1000,
555efe109bdSjmcneill 	.maxcap_step = 1456,
556efe109bdSjmcneill 	.coulomb_step = 1456,
557efe109bdSjmcneill 	.poklirq = AXPPMIC_IRQ(5, __BIT(3)),
558efe109bdSjmcneill 	.acinirq = AXPPMIC_IRQ(1, __BITS(6,5)),
559efe109bdSjmcneill 	.vbusirq = AXPPMIC_IRQ(1, __BITS(3,2)),
560efe109bdSjmcneill 	.battirq = AXPPMIC_IRQ(2, __BITS(7,6)),
561efe109bdSjmcneill 	.chargeirq = AXPPMIC_IRQ(2, __BITS(3,2)),
562efe109bdSjmcneill 	.chargestirq = AXPPMIC_IRQ(4, __BITS(1,0)),
563efe109bdSjmcneill };
564efe109bdSjmcneill 
5650f6eea99Sskrll static const struct axppmic_config axp15060_config = {
5660f6eea99Sskrll 	.name = "AXP15060",
5670f6eea99Sskrll 	.controls = axp15060_ctrls,
5680f6eea99Sskrll 	.ncontrols = __arraycount(axp15060_ctrls),
5690f6eea99Sskrll };
5700f6eea99Sskrll 
571feee3a19Sthorpej static const struct device_compatible_entry compat_data[] = {
57239983299Sthorpej 	{ .compat = "x-powers,axp803",		.data = &axp803_config },
57339983299Sthorpej 	{ .compat = "x-powers,axp805",		.data = &axp805_config },
57439983299Sthorpej 	{ .compat = "x-powers,axp806",		.data = &axp806_config },
57539983299Sthorpej 	{ .compat = "x-powers,axp809",		.data = &axp809_config },
57639983299Sthorpej 	{ .compat = "x-powers,axp813",		.data = &axp813_config },
5770f6eea99Sskrll 	{ .compat = "x-powers,axp15060",	.data = &axp15060_config },
57818f3098cSthorpej 	DEVICE_COMPAT_EOL
57971a82865Sjmcneill };
58071a82865Sjmcneill 
58171a82865Sjmcneill static int
58271a82865Sjmcneill axppmic_read(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t *val, int flags)
58371a82865Sjmcneill {
58471a82865Sjmcneill 	return iic_smbus_read_byte(tag, addr, reg, val, flags);
58571a82865Sjmcneill }
58671a82865Sjmcneill 
58771a82865Sjmcneill static int
58871a82865Sjmcneill axppmic_write(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t val, int flags)
58971a82865Sjmcneill {
59071a82865Sjmcneill 	return iic_smbus_write_byte(tag, addr, reg, val, flags);
59171a82865Sjmcneill }
59271a82865Sjmcneill 
59371a82865Sjmcneill static int
59471a82865Sjmcneill axppmic_set_voltage(i2c_tag_t tag, i2c_addr_t addr, const struct axppmic_ctrl *c, u_int min, u_int max)
59571a82865Sjmcneill {
59671a82865Sjmcneill 	u_int vol, reg_val;
59771a82865Sjmcneill 	int nstep, error;
59871a82865Sjmcneill 	uint8_t val;
59971a82865Sjmcneill 
60071a82865Sjmcneill 	if (!c->c_voltage_mask)
60171a82865Sjmcneill 		return EINVAL;
60271a82865Sjmcneill 
60371a82865Sjmcneill 	if (min < c->c_min || min > c->c_max)
60471a82865Sjmcneill 		return EINVAL;
60571a82865Sjmcneill 
60671a82865Sjmcneill 	reg_val = 0;
60771a82865Sjmcneill 	nstep = 1;
60871a82865Sjmcneill 	vol = c->c_min;
60971a82865Sjmcneill 
61071a82865Sjmcneill 	for (nstep = 0; nstep < c->c_step1cnt && vol < min; nstep++) {
61171a82865Sjmcneill 		++reg_val;
61271a82865Sjmcneill 		vol += c->c_step1;
61371a82865Sjmcneill 	}
6142df3325bSjmcneill 
6152df3325bSjmcneill 	if (c->c_step2start)
6162df3325bSjmcneill 		vol = c->c_step2start;
6172df3325bSjmcneill 
61871a82865Sjmcneill 	for (nstep = 0; nstep < c->c_step2cnt && vol < min; nstep++) {
61971a82865Sjmcneill 		++reg_val;
62071a82865Sjmcneill 		vol += c->c_step2;
62171a82865Sjmcneill 	}
62271a82865Sjmcneill 
62371a82865Sjmcneill 	if (vol > max)
62471a82865Sjmcneill 		return EINVAL;
62571a82865Sjmcneill 
626d172e13fSthorpej 	iic_acquire_bus(tag, 0);
627d172e13fSthorpej 	if ((error = axppmic_read(tag, addr, c->c_voltage_reg, &val, 0)) == 0) {
62871a82865Sjmcneill 		val &= ~c->c_voltage_mask;
62971a82865Sjmcneill 		val |= __SHIFTIN(reg_val, c->c_voltage_mask);
630d172e13fSthorpej 		error = axppmic_write(tag, addr, c->c_voltage_reg, val, 0);
63171a82865Sjmcneill 	}
632d172e13fSthorpej 	iic_release_bus(tag, 0);
63371a82865Sjmcneill 
63471a82865Sjmcneill 	return error;
63571a82865Sjmcneill }
63671a82865Sjmcneill 
63771a82865Sjmcneill static int
63871a82865Sjmcneill axppmic_get_voltage(i2c_tag_t tag, i2c_addr_t addr, const struct axppmic_ctrl *c, u_int *pvol)
63971a82865Sjmcneill {
64071a82865Sjmcneill 	int reg_val, error;
64171a82865Sjmcneill 	uint8_t val;
64271a82865Sjmcneill 
64371a82865Sjmcneill 	if (!c->c_voltage_mask)
64471a82865Sjmcneill 		return EINVAL;
64571a82865Sjmcneill 
646d172e13fSthorpej 	iic_acquire_bus(tag, 0);
647d172e13fSthorpej 	error = axppmic_read(tag, addr, c->c_voltage_reg, &val, 0);
648d172e13fSthorpej 	iic_release_bus(tag, 0);
64971a82865Sjmcneill 	if (error)
65071a82865Sjmcneill 		return error;
65171a82865Sjmcneill 
65271a82865Sjmcneill 	reg_val = __SHIFTOUT(val, c->c_voltage_mask);
65371a82865Sjmcneill 	if (reg_val < c->c_step1cnt) {
65471a82865Sjmcneill 		*pvol = c->c_min + reg_val * c->c_step1;
6552df3325bSjmcneill 	} else if (c->c_step2start) {
6562df3325bSjmcneill 		*pvol = c->c_step2start +
6572df3325bSjmcneill 		    ((reg_val - c->c_step1cnt) * c->c_step2);
65871a82865Sjmcneill 	} else {
65971a82865Sjmcneill 		*pvol = c->c_min + (c->c_step1cnt * c->c_step1) +
66071a82865Sjmcneill 		    ((reg_val - c->c_step1cnt) * c->c_step2);
66171a82865Sjmcneill 	}
66271a82865Sjmcneill 
66371a82865Sjmcneill 	return 0;
66471a82865Sjmcneill }
66571a82865Sjmcneill 
66671a82865Sjmcneill static void
66771a82865Sjmcneill axppmic_power_poweroff(device_t dev)
66871a82865Sjmcneill {
66971a82865Sjmcneill 	struct axppmic_softc *sc = device_private(dev);
6701104dc07Sthorpej 	int error;
67171a82865Sjmcneill 
67271a82865Sjmcneill 	delay(1000000);
67371a82865Sjmcneill 
674d172e13fSthorpej 	error = iic_acquire_bus(sc->sc_i2c, 0);
6751104dc07Sthorpej 	if (error == 0) {
6761104dc07Sthorpej 		error = axppmic_write(sc->sc_i2c, sc->sc_addr,
677d172e13fSthorpej 		    AXP_POWER_DISABLE_REG, AXP_POWER_DISABLE_CTRL, 0);
678d172e13fSthorpej 		iic_release_bus(sc->sc_i2c, 0);
67971a82865Sjmcneill 	}
6801104dc07Sthorpej 	if (error) {
6811104dc07Sthorpej 		device_printf(dev, "WARNING: unable to power off, error %d\n",
6821104dc07Sthorpej 		    error);
6831104dc07Sthorpej 	}
6841104dc07Sthorpej }
68571a82865Sjmcneill 
68671a82865Sjmcneill static struct fdtbus_power_controller_func axppmic_power_funcs = {
68771a82865Sjmcneill 	.poweroff = axppmic_power_poweroff,
68871a82865Sjmcneill };
68971a82865Sjmcneill 
690ee5caec1Sjmcneill static int
691ee5caec1Sjmcneill axppmic_gpio_ctl(struct axppmic_softc *sc, uint8_t pin, uint8_t func)
692ee5caec1Sjmcneill {
693ee5caec1Sjmcneill 	uint8_t val;
694ee5caec1Sjmcneill 	int error;
695ee5caec1Sjmcneill 
696ee5caec1Sjmcneill 	KASSERT(pin < sc->sc_conf->gpio_npins);
697ee5caec1Sjmcneill 	KASSERT((func & ~AXP_GPIO_CTRL_FUNC_MASK) == 0);
698ee5caec1Sjmcneill 
699ee5caec1Sjmcneill 	iic_acquire_bus(sc->sc_i2c, 0);
700ee5caec1Sjmcneill 	error = axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_GPIO_CTRL_REG(pin),
701ee5caec1Sjmcneill 	    &val, 0);
702ee5caec1Sjmcneill 	if (error == 0) {
703ee5caec1Sjmcneill 		val &= ~AXP_GPIO_CTRL_FUNC_MASK;
704ee5caec1Sjmcneill 		val |= func;
705ee5caec1Sjmcneill 		error = axppmic_write(sc->sc_i2c, sc->sc_addr,
706ee5caec1Sjmcneill 		    AXP_GPIO_CTRL_REG(pin), val, 0);
707ee5caec1Sjmcneill 	}
708ee5caec1Sjmcneill 	iic_release_bus(sc->sc_i2c, 0);
709ee5caec1Sjmcneill 
710ee5caec1Sjmcneill 	return error;
711ee5caec1Sjmcneill }
712ee5caec1Sjmcneill 
713ee5caec1Sjmcneill static void *
714ee5caec1Sjmcneill axppmic_gpio_acquire(device_t dev, const void *data, size_t len, int flags)
715ee5caec1Sjmcneill {
716ee5caec1Sjmcneill 	struct axppmic_softc *sc = device_private(dev);
717ee5caec1Sjmcneill 	struct axppmic_gpio_pin *gpin;
718ee5caec1Sjmcneill 	const u_int *gpio = data;
719ee5caec1Sjmcneill 	int error;
720ee5caec1Sjmcneill 
721ee5caec1Sjmcneill 	if (len != 12) {
722ee5caec1Sjmcneill 		return NULL;
723ee5caec1Sjmcneill 	}
724ee5caec1Sjmcneill 
725ee5caec1Sjmcneill 	const uint8_t pin = be32toh(gpio[1]) & 0xff;
726ee5caec1Sjmcneill 	const bool actlo = be32toh(gpio[2]) & 1;
727ee5caec1Sjmcneill 
728ee5caec1Sjmcneill 	if (pin >= sc->sc_conf->gpio_npins) {
729ee5caec1Sjmcneill 		return NULL;
730ee5caec1Sjmcneill 	}
731ee5caec1Sjmcneill 
732ee5caec1Sjmcneill 	if ((flags & GPIO_PIN_INPUT) != 0) {
733ee5caec1Sjmcneill 		error = axppmic_gpio_ctl(sc, pin, AXP_GPIO_CTRL_FUNC_INPUT);
734ee5caec1Sjmcneill 		if (error != 0) {
735ee5caec1Sjmcneill 			return NULL;
736ee5caec1Sjmcneill 		}
737ee5caec1Sjmcneill 	}
738ee5caec1Sjmcneill 
739ee5caec1Sjmcneill 	gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP);
740ee5caec1Sjmcneill 	gpin->pin_sc = sc;
741ee5caec1Sjmcneill 	gpin->pin_nr = pin;
742ee5caec1Sjmcneill 	gpin->pin_flags = flags;
743ee5caec1Sjmcneill 	gpin->pin_actlo = actlo;
744ee5caec1Sjmcneill 
745ee5caec1Sjmcneill 	return gpin;
746ee5caec1Sjmcneill }
747ee5caec1Sjmcneill 
748ee5caec1Sjmcneill static void
749ee5caec1Sjmcneill axppmic_gpio_release(device_t dev, void *priv)
750ee5caec1Sjmcneill {
751ee5caec1Sjmcneill 	struct axppmic_softc *sc = device_private(dev);
752ee5caec1Sjmcneill 	struct axppmic_gpio_pin *gpin = priv;
753ee5caec1Sjmcneill 
754ee5caec1Sjmcneill 	axppmic_gpio_ctl(sc, gpin->pin_nr, AXP_GPIO_CTRL_FUNC_INPUT);
755ee5caec1Sjmcneill 
756ee5caec1Sjmcneill 	kmem_free(gpin, sizeof(*gpin));
757ee5caec1Sjmcneill }
758ee5caec1Sjmcneill 
759ee5caec1Sjmcneill static int
760ee5caec1Sjmcneill axppmic_gpio_read(device_t dev, void *priv, bool raw)
761ee5caec1Sjmcneill {
762ee5caec1Sjmcneill 	struct axppmic_softc *sc = device_private(dev);
763ee5caec1Sjmcneill 	struct axppmic_gpio_pin *gpin = priv;
764ee5caec1Sjmcneill 	uint8_t data;
765ee5caec1Sjmcneill 	int error, val;
766ee5caec1Sjmcneill 
767ee5caec1Sjmcneill 	KASSERT(sc == gpin->pin_sc);
768ee5caec1Sjmcneill 
769ee5caec1Sjmcneill 	const uint8_t data_mask = __BIT(gpin->pin_nr);
770ee5caec1Sjmcneill 
771ee5caec1Sjmcneill 	iic_acquire_bus(sc->sc_i2c, 0);
772ee5caec1Sjmcneill 	error = axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_GPIO_SIGNAL_REG,
773ee5caec1Sjmcneill 	    &data, 0);
774ee5caec1Sjmcneill 	iic_release_bus(sc->sc_i2c, 0);
775ee5caec1Sjmcneill 
776ee5caec1Sjmcneill 	if (error != 0) {
777ee5caec1Sjmcneill 		device_printf(dev, "WARNING: failed to read pin %d: %d\n",
778ee5caec1Sjmcneill 		    gpin->pin_nr, error);
779ee5caec1Sjmcneill 		val = 0;
780ee5caec1Sjmcneill 	} else {
781ee5caec1Sjmcneill 		val = __SHIFTOUT(data, data_mask);
782ee5caec1Sjmcneill 	}
783ee5caec1Sjmcneill 	if (!raw && gpin->pin_actlo) {
784ee5caec1Sjmcneill 		val = !val;
785ee5caec1Sjmcneill 	}
786ee5caec1Sjmcneill 
787ee5caec1Sjmcneill 	return val;
788ee5caec1Sjmcneill }
789ee5caec1Sjmcneill 
790ee5caec1Sjmcneill static void
791ee5caec1Sjmcneill axppmic_gpio_write(device_t dev, void *priv, int val, bool raw)
792ee5caec1Sjmcneill {
793ee5caec1Sjmcneill 	struct axppmic_softc *sc = device_private(dev);
794ee5caec1Sjmcneill 	struct axppmic_gpio_pin *gpin = priv;
795ee5caec1Sjmcneill 	int error;
796ee5caec1Sjmcneill 
797ee5caec1Sjmcneill 	if (!raw && gpin->pin_actlo) {
798ee5caec1Sjmcneill 		val = !val;
799ee5caec1Sjmcneill 	}
800ee5caec1Sjmcneill 
801ee5caec1Sjmcneill 	error = axppmic_gpio_ctl(sc, gpin->pin_nr,
802ee5caec1Sjmcneill 	    val == 0 ? AXP_GPIO_CTRL_FUNC_LOW : AXP_GPIO_CTRL_FUNC_HIGH);
803ee5caec1Sjmcneill 	if (error != 0) {
804ee5caec1Sjmcneill 		device_printf(dev, "WARNING: failed to write pin %d: %d\n",
805ee5caec1Sjmcneill 		    gpin->pin_nr, error);
806ee5caec1Sjmcneill 	}
807ee5caec1Sjmcneill }
808ee5caec1Sjmcneill 
809ee5caec1Sjmcneill static struct fdtbus_gpio_controller_func axppmic_gpio_funcs = {
810ee5caec1Sjmcneill 	.acquire = axppmic_gpio_acquire,
811ee5caec1Sjmcneill 	.release = axppmic_gpio_release,
812ee5caec1Sjmcneill 	.read = axppmic_gpio_read,
813ee5caec1Sjmcneill 	.write = axppmic_gpio_write,
814ee5caec1Sjmcneill };
815ee5caec1Sjmcneill 
81671a82865Sjmcneill static void
81771a82865Sjmcneill axppmic_task_shut(void *priv)
81871a82865Sjmcneill {
81971a82865Sjmcneill 	struct axppmic_softc *sc = priv;
82071a82865Sjmcneill 
82171a82865Sjmcneill 	sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED);
82271a82865Sjmcneill }
82371a82865Sjmcneill 
824b4d62e18Sjmcneill static void
825c6020708Sjmcneill axppmic_sensor_update(struct sysmon_envsys *sme, envsys_data_t *e)
826b4d62e18Sjmcneill {
827b4d62e18Sjmcneill 	struct axppmic_softc *sc = sme->sme_cookie;
82886c215ccSjmcneill 	const struct axppmic_config *c = sc->sc_conf;
82986c215ccSjmcneill 	uint8_t val, lo, hi;
830b4d62e18Sjmcneill 
831b4d62e18Sjmcneill 	e->state = ENVSYS_SINVALID;
832b4d62e18Sjmcneill 
83386c215ccSjmcneill 	const bool battery_present =
83486c215ccSjmcneill 	    sc->sc_sensor[AXP_SENSOR_BATT_PRESENT].state == ENVSYS_SVALID &&
83586c215ccSjmcneill 	    sc->sc_sensor[AXP_SENSOR_BATT_PRESENT].value_cur == 1;
83686c215ccSjmcneill 
837b4d62e18Sjmcneill 	switch (e->private) {
838c2f11555Sjmcneill 	case AXP_SENSOR_ACIN_PRESENT:
839d172e13fSthorpej 		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0) {
840c2f11555Sjmcneill 			e->state = ENVSYS_SVALID;
841c2f11555Sjmcneill 			e->value_cur = !!(val & AXP_POWER_SOURCE_ACIN_PRESENT);
842c2f11555Sjmcneill 		}
843c2f11555Sjmcneill 		break;
844c2f11555Sjmcneill 	case AXP_SENSOR_VBUS_PRESENT:
845d172e13fSthorpej 		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0) {
846c2f11555Sjmcneill 			e->state = ENVSYS_SVALID;
847c2f11555Sjmcneill 			e->value_cur = !!(val & AXP_POWER_SOURCE_VBUS_PRESENT);
848c2f11555Sjmcneill 		}
849c2f11555Sjmcneill 		break;
850b4d62e18Sjmcneill 	case AXP_SENSOR_BATT_PRESENT:
851d172e13fSthorpej 		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, 0) == 0) {
852b4d62e18Sjmcneill 			if (val & AXP_POWER_MODE_BATT_VALID) {
853b4d62e18Sjmcneill 				e->state = ENVSYS_SVALID;
854b4d62e18Sjmcneill 				e->value_cur = !!(val & AXP_POWER_MODE_BATT_PRESENT);
855b4d62e18Sjmcneill 			}
856b4d62e18Sjmcneill 		}
857b4d62e18Sjmcneill 		break;
858b4d62e18Sjmcneill 	case AXP_SENSOR_BATT_CHARGING:
859d172e13fSthorpej 		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, 0) == 0) {
860b4d62e18Sjmcneill 			e->state = ENVSYS_SVALID;
861b4d62e18Sjmcneill 			e->value_cur = !!(val & AXP_POWER_MODE_BATT_CHARGING);
862b4d62e18Sjmcneill 		}
863b4d62e18Sjmcneill 		break;
864b4d62e18Sjmcneill 	case AXP_SENSOR_BATT_CHARGE_STATE:
86586c215ccSjmcneill 		if (battery_present &&
866d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, 0) == 0 &&
86782e15d74Sjmcneill 		    (val & AXP_BATT_CAP_VALID) != 0) {
868b4d62e18Sjmcneill 			const u_int batt_val = __SHIFTOUT(val, AXP_BATT_CAP_PERCENT);
86982e15d74Sjmcneill 			if (batt_val <= sc->sc_shut_thres) {
870b4d62e18Sjmcneill 				e->state = ENVSYS_SCRITICAL;
871b4d62e18Sjmcneill 				e->value_cur = ENVSYS_BATTERY_CAPACITY_CRITICAL;
87282e15d74Sjmcneill 			} else if (batt_val <= sc->sc_warn_thres) {
873b4d62e18Sjmcneill 				e->state = ENVSYS_SWARNUNDER;
874b4d62e18Sjmcneill 				e->value_cur = ENVSYS_BATTERY_CAPACITY_WARNING;
875b4d62e18Sjmcneill 			} else {
876b4d62e18Sjmcneill 				e->state = ENVSYS_SVALID;
877b4d62e18Sjmcneill 				e->value_cur = ENVSYS_BATTERY_CAPACITY_NORMAL;
878b4d62e18Sjmcneill 			}
879b4d62e18Sjmcneill 		}
880b4d62e18Sjmcneill 		break;
88186c215ccSjmcneill 	case AXP_SENSOR_BATT_CAPACITY_PERCENT:
88286c215ccSjmcneill 		if (battery_present &&
883d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, 0) == 0 &&
884b4d62e18Sjmcneill 		    (val & AXP_BATT_CAP_VALID) != 0) {
885b4d62e18Sjmcneill 			e->state = ENVSYS_SVALID;
886b4d62e18Sjmcneill 			e->value_cur = __SHIFTOUT(val, AXP_BATT_CAP_PERCENT);
887b4d62e18Sjmcneill 		}
888b4d62e18Sjmcneill 		break;
88986c215ccSjmcneill 	case AXP_SENSOR_BATT_VOLTAGE:
89086c215ccSjmcneill 		if (battery_present &&
891d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_HI_REG, &hi, 0) == 0 &&
892d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_LO_REG, &lo, 0) == 0) {
89386c215ccSjmcneill 			e->state = ENVSYS_SVALID;
89486c215ccSjmcneill 			e->value_cur = AXP_ADC_RAW(hi, lo) * c->batsense_step;
89586c215ccSjmcneill 		}
89686c215ccSjmcneill 		break;
89786c215ccSjmcneill 	case AXP_SENSOR_BATT_CHARGE_CURRENT:
89886c215ccSjmcneill 		if (battery_present &&
899d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0 &&
90086c215ccSjmcneill 		    (val & AXP_POWER_SOURCE_CHARGE_DIRECTION) != 0 &&
901d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_HI_REG, &hi, 0) == 0 &&
902d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_LO_REG, &lo, 0) == 0) {
90386c215ccSjmcneill 			e->state = ENVSYS_SVALID;
90486c215ccSjmcneill 			e->value_cur = AXP_ADC_RAW(hi, lo) * c->charge_step;
90586c215ccSjmcneill 		}
90686c215ccSjmcneill 		break;
90786c215ccSjmcneill 	case AXP_SENSOR_BATT_DISCHARGE_CURRENT:
90886c215ccSjmcneill 		if (battery_present &&
909d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0 &&
91086c215ccSjmcneill 		    (val & AXP_POWER_SOURCE_CHARGE_DIRECTION) == 0 &&
911d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_HI_REG, &hi, 0) == 0 &&
912d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_LO_REG, &lo, 0) == 0) {
91386c215ccSjmcneill 			e->state = ENVSYS_SVALID;
91486c215ccSjmcneill 			e->value_cur = AXP_ADC_RAW(hi, lo) * c->discharge_step;
91586c215ccSjmcneill 		}
91686c215ccSjmcneill 		break;
917a8e9e1a9Sjakllsch 	case AXP_SENSOR_BATT_MAXIMUM_CAPACITY:
918a8e9e1a9Sjakllsch 		if (battery_present &&
919d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_MAX_CAP_HI_REG, &hi, 0) == 0 &&
920d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_MAX_CAP_LO_REG, &lo, 0) == 0) {
921a8e9e1a9Sjakllsch 			e->state = (hi & AXP_BATT_MAX_CAP_VALID) ? ENVSYS_SVALID : ENVSYS_SINVALID;
922a8e9e1a9Sjakllsch 			e->value_cur = AXP_COULOMB_RAW(hi, lo) * c->maxcap_step;
923a8e9e1a9Sjakllsch 		}
924a8e9e1a9Sjakllsch 		break;
925a8e9e1a9Sjakllsch 	case AXP_SENSOR_BATT_CURRENT_CAPACITY:
926a8e9e1a9Sjakllsch 		if (battery_present &&
927d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_COULOMB_HI_REG, &hi, 0) == 0 &&
928d172e13fSthorpej 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_COULOMB_LO_REG, &lo, 0) == 0) {
929a8e9e1a9Sjakllsch 			e->state = (hi & AXP_BATT_COULOMB_VALID) ? ENVSYS_SVALID : ENVSYS_SINVALID;
930a8e9e1a9Sjakllsch 			e->value_cur = AXP_COULOMB_RAW(hi, lo) * c->coulomb_step;
931a8e9e1a9Sjakllsch 		}
932a8e9e1a9Sjakllsch 		break;
933b4d62e18Sjmcneill 	}
934c6020708Sjmcneill }
935c6020708Sjmcneill 
936c6020708Sjmcneill static void
937c6020708Sjmcneill axppmic_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *e)
938c6020708Sjmcneill {
939c6020708Sjmcneill 	struct axppmic_softc *sc = sme->sme_cookie;
940c6020708Sjmcneill 
941c6020708Sjmcneill 	switch (e->private) {
94286c215ccSjmcneill 	case AXP_SENSOR_BATT_CAPACITY_PERCENT:
94386c215ccSjmcneill 	case AXP_SENSOR_BATT_VOLTAGE:
94486c215ccSjmcneill 	case AXP_SENSOR_BATT_CHARGE_CURRENT:
94586c215ccSjmcneill 	case AXP_SENSOR_BATT_DISCHARGE_CURRENT:
94686c215ccSjmcneill 		/* Always update battery capacity and ADCs */
947d172e13fSthorpej 		iic_acquire_bus(sc->sc_i2c, 0);
948c6020708Sjmcneill 		axppmic_sensor_update(sme, e);
949d172e13fSthorpej 		iic_release_bus(sc->sc_i2c, 0);
950c6020708Sjmcneill 		break;
951c6020708Sjmcneill 	default:
952c6020708Sjmcneill 		/* Refresh if the sensor is not in valid state */
953c6020708Sjmcneill 		if (e->state != ENVSYS_SVALID) {
954d172e13fSthorpej 			iic_acquire_bus(sc->sc_i2c, 0);
955c6020708Sjmcneill 			axppmic_sensor_update(sme, e);
956d172e13fSthorpej 			iic_release_bus(sc->sc_i2c, 0);
957c6020708Sjmcneill 		}
958c6020708Sjmcneill 		break;
959c6020708Sjmcneill 	}
960c6020708Sjmcneill }
961c6020708Sjmcneill 
962c6020708Sjmcneill static int
963c6020708Sjmcneill axppmic_intr(void *priv)
964c6020708Sjmcneill {
965d172e13fSthorpej 	struct axppmic_softc * const sc = priv;
966d172e13fSthorpej 
967d172e13fSthorpej 	mutex_enter(&sc->sc_intr_lock);
968d172e13fSthorpej 
969d172e13fSthorpej 	fdtbus_intr_mask(sc->sc_phandle, sc->sc_ih);
970d172e13fSthorpej 
971d172e13fSthorpej 	/* Interrupt is always masked when work is scheduled! */
972d172e13fSthorpej 	KASSERT(!sc->sc_work_scheduled);
973d172e13fSthorpej 	sc->sc_work_scheduled = true;
974d172e13fSthorpej 	workqueue_enqueue(sc->sc_wq, &sc->sc_work, NULL);
975d172e13fSthorpej 
976d172e13fSthorpej 	mutex_exit(&sc->sc_intr_lock);
977d172e13fSthorpej 
978d172e13fSthorpej 	return 1;
979d172e13fSthorpej }
980d172e13fSthorpej 
981d172e13fSthorpej static void
982d172e13fSthorpej axppmic_work(struct work *work, void *arg)
983d172e13fSthorpej {
984d172e13fSthorpej 	struct axppmic_softc * const sc =
985d172e13fSthorpej 	    container_of(work, struct axppmic_softc, sc_work);
986d172e13fSthorpej 	const struct axppmic_config * const c = sc->sc_conf;
987d172e13fSthorpej 	const int flags = 0;
988c6020708Sjmcneill 	uint8_t stat;
989c6020708Sjmcneill 	u_int n;
990c6020708Sjmcneill 
991d172e13fSthorpej 	KASSERT(sc->sc_work_scheduled);
992d172e13fSthorpej 
993c6020708Sjmcneill 	iic_acquire_bus(sc->sc_i2c, flags);
994c6020708Sjmcneill 	for (n = 1; n <= c->irq_regs; n++) {
995c6020708Sjmcneill 		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_IRQ_STATUS_REG(n), &stat, flags) == 0) {
996d172e13fSthorpej 			if (stat != 0) {
997d172e13fSthorpej 				axppmic_write(sc->sc_i2c, sc->sc_addr,
998d172e13fSthorpej 				    AXP_IRQ_STATUS_REG(n), stat, flags);
999d172e13fSthorpej 			}
1000d172e13fSthorpej 
1001c6020708Sjmcneill 			if (n == c->poklirq.reg && (stat & c->poklirq.mask) != 0)
1002c6020708Sjmcneill 				sysmon_task_queue_sched(0, axppmic_task_shut, sc);
1003c6020708Sjmcneill 			if (n == c->acinirq.reg && (stat & c->acinirq.mask) != 0)
1004c6020708Sjmcneill 				axppmic_sensor_update(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACIN_PRESENT]);
1005c6020708Sjmcneill 			if (n == c->vbusirq.reg && (stat & c->vbusirq.mask) != 0)
1006c6020708Sjmcneill 				axppmic_sensor_update(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUS_PRESENT]);
1007c6020708Sjmcneill 			if (n == c->battirq.reg && (stat & c->battirq.mask) != 0)
1008c6020708Sjmcneill 				axppmic_sensor_update(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATT_PRESENT]);
1009c6020708Sjmcneill 			if (n == c->chargeirq.reg && (stat & c->chargeirq.mask) != 0)
1010c6020708Sjmcneill 				axppmic_sensor_update(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATT_CHARGING]);
1011c6020708Sjmcneill 			if (n == c->chargestirq.reg && (stat & c->chargestirq.mask) != 0)
1012c6020708Sjmcneill 				axppmic_sensor_update(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATT_CHARGE_STATE]);
1013c6020708Sjmcneill 		}
1014c6020708Sjmcneill 	}
1015c6020708Sjmcneill 	iic_release_bus(sc->sc_i2c, flags);
1016c6020708Sjmcneill 
1017d172e13fSthorpej 	mutex_enter(&sc->sc_intr_lock);
1018d172e13fSthorpej 	sc->sc_work_scheduled = false;
1019d172e13fSthorpej 	fdtbus_intr_unmask(sc->sc_phandle, sc->sc_ih);
1020d172e13fSthorpej 	mutex_exit(&sc->sc_intr_lock);
1021b4d62e18Sjmcneill }
1022b4d62e18Sjmcneill 
1023b4d62e18Sjmcneill static void
1024c2f11555Sjmcneill axppmic_attach_acadapter(struct axppmic_softc *sc)
1025c2f11555Sjmcneill {
1026c2f11555Sjmcneill 	envsys_data_t *e;
1027c2f11555Sjmcneill 
1028c2f11555Sjmcneill 	e = &sc->sc_sensor[AXP_SENSOR_ACIN_PRESENT];
1029c2f11555Sjmcneill 	e->private = AXP_SENSOR_ACIN_PRESENT;
1030c2f11555Sjmcneill 	e->units = ENVSYS_INDICATOR;
1031c2f11555Sjmcneill 	e->state = ENVSYS_SINVALID;
1032c2f11555Sjmcneill 	strlcpy(e->desc, "ACIN present", sizeof(e->desc));
1033c2f11555Sjmcneill 	sysmon_envsys_sensor_attach(sc->sc_sme, e);
1034c2f11555Sjmcneill 
1035c2f11555Sjmcneill 	e = &sc->sc_sensor[AXP_SENSOR_VBUS_PRESENT];
1036c2f11555Sjmcneill 	e->private = AXP_SENSOR_VBUS_PRESENT;
1037c2f11555Sjmcneill 	e->units = ENVSYS_INDICATOR;
1038c2f11555Sjmcneill 	e->state = ENVSYS_SINVALID;
1039c2f11555Sjmcneill 	strlcpy(e->desc, "VBUS present", sizeof(e->desc));
1040c2f11555Sjmcneill 	sysmon_envsys_sensor_attach(sc->sc_sme, e);
1041c2f11555Sjmcneill }
1042c2f11555Sjmcneill 
1043c2f11555Sjmcneill static void
1044b4d62e18Sjmcneill axppmic_attach_battery(struct axppmic_softc *sc)
1045b4d62e18Sjmcneill {
104686c215ccSjmcneill 	const struct axppmic_config *c = sc->sc_conf;
1047b4d62e18Sjmcneill 	envsys_data_t *e;
104882e15d74Sjmcneill 	uint8_t val;
104982e15d74Sjmcneill 
10500c3f7694Sthorpej 	iic_acquire_bus(sc->sc_i2c, 0);
1051d172e13fSthorpej 	if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_WARN_REG, &val, 0) == 0) {
105282e15d74Sjmcneill 		sc->sc_warn_thres = __SHIFTOUT(val, AXP_BATT_CAP_WARN_LV1) + 5;
105382e15d74Sjmcneill 		sc->sc_shut_thres = __SHIFTOUT(val, AXP_BATT_CAP_WARN_LV2);
105482e15d74Sjmcneill 	}
10550c3f7694Sthorpej 	iic_release_bus(sc->sc_i2c, 0);
1056b4d62e18Sjmcneill 
1057b4d62e18Sjmcneill 	e = &sc->sc_sensor[AXP_SENSOR_BATT_PRESENT];
1058b4d62e18Sjmcneill 	e->private = AXP_SENSOR_BATT_PRESENT;
1059b4d62e18Sjmcneill 	e->units = ENVSYS_INDICATOR;
1060b4d62e18Sjmcneill 	e->state = ENVSYS_SINVALID;
1061b4d62e18Sjmcneill 	strlcpy(e->desc, "battery present", sizeof(e->desc));
1062b4d62e18Sjmcneill 	sysmon_envsys_sensor_attach(sc->sc_sme, e);
1063b4d62e18Sjmcneill 
1064b4d62e18Sjmcneill 	e = &sc->sc_sensor[AXP_SENSOR_BATT_CHARGING];
1065b4d62e18Sjmcneill 	e->private = AXP_SENSOR_BATT_CHARGING;
1066b4d62e18Sjmcneill 	e->units = ENVSYS_BATTERY_CHARGE;
1067b4d62e18Sjmcneill 	e->state = ENVSYS_SINVALID;
1068b4d62e18Sjmcneill 	strlcpy(e->desc, "charging", sizeof(e->desc));
1069b4d62e18Sjmcneill 	sysmon_envsys_sensor_attach(sc->sc_sme, e);
1070b4d62e18Sjmcneill 
1071b4d62e18Sjmcneill 	e = &sc->sc_sensor[AXP_SENSOR_BATT_CHARGE_STATE];
1072b4d62e18Sjmcneill 	e->private = AXP_SENSOR_BATT_CHARGE_STATE;
1073b4d62e18Sjmcneill 	e->units = ENVSYS_BATTERY_CAPACITY;
1074b4d62e18Sjmcneill 	e->flags = ENVSYS_FMONSTCHANGED;
107521a656ecSjmcneill 	e->state = ENVSYS_SINVALID;
1076b4d62e18Sjmcneill 	e->value_cur = ENVSYS_BATTERY_CAPACITY_NORMAL;
1077b4d62e18Sjmcneill 	strlcpy(e->desc, "charge state", sizeof(e->desc));
1078b4d62e18Sjmcneill 	sysmon_envsys_sensor_attach(sc->sc_sme, e);
1079b4d62e18Sjmcneill 
108086c215ccSjmcneill 	if (c->batsense_step) {
108186c215ccSjmcneill 		e = &sc->sc_sensor[AXP_SENSOR_BATT_VOLTAGE];
108286c215ccSjmcneill 		e->private = AXP_SENSOR_BATT_VOLTAGE;
108386c215ccSjmcneill 		e->units = ENVSYS_SVOLTS_DC;
108486c215ccSjmcneill 		e->state = ENVSYS_SINVALID;
108586c215ccSjmcneill 		strlcpy(e->desc, "battery voltage", sizeof(e->desc));
108686c215ccSjmcneill 		sysmon_envsys_sensor_attach(sc->sc_sme, e);
108786c215ccSjmcneill 	}
108886c215ccSjmcneill 
108986c215ccSjmcneill 	if (c->charge_step) {
109086c215ccSjmcneill 		e = &sc->sc_sensor[AXP_SENSOR_BATT_CHARGE_CURRENT];
109186c215ccSjmcneill 		e->private = AXP_SENSOR_BATT_CHARGE_CURRENT;
109286c215ccSjmcneill 		e->units = ENVSYS_SAMPS;
109386c215ccSjmcneill 		e->state = ENVSYS_SINVALID;
109486c215ccSjmcneill 		strlcpy(e->desc, "battery charge current", sizeof(e->desc));
109586c215ccSjmcneill 		sysmon_envsys_sensor_attach(sc->sc_sme, e);
109686c215ccSjmcneill 	}
109786c215ccSjmcneill 
109886c215ccSjmcneill 	if (c->discharge_step) {
109986c215ccSjmcneill 		e = &sc->sc_sensor[AXP_SENSOR_BATT_DISCHARGE_CURRENT];
110086c215ccSjmcneill 		e->private = AXP_SENSOR_BATT_DISCHARGE_CURRENT;
110186c215ccSjmcneill 		e->units = ENVSYS_SAMPS;
110286c215ccSjmcneill 		e->state = ENVSYS_SINVALID;
110386c215ccSjmcneill 		strlcpy(e->desc, "battery discharge current", sizeof(e->desc));
110486c215ccSjmcneill 		sysmon_envsys_sensor_attach(sc->sc_sme, e);
110586c215ccSjmcneill 	}
110686c215ccSjmcneill 
110786c215ccSjmcneill 	if (c->has_fuel_gauge) {
110886c215ccSjmcneill 		e = &sc->sc_sensor[AXP_SENSOR_BATT_CAPACITY_PERCENT];
110986c215ccSjmcneill 		e->private = AXP_SENSOR_BATT_CAPACITY_PERCENT;
1110b4d62e18Sjmcneill 		e->units = ENVSYS_INTEGER;
1111b4d62e18Sjmcneill 		e->state = ENVSYS_SINVALID;
1112b4d62e18Sjmcneill 		e->flags = ENVSYS_FPERCENT;
1113b4d62e18Sjmcneill 		strlcpy(e->desc, "battery percent", sizeof(e->desc));
1114b4d62e18Sjmcneill 		sysmon_envsys_sensor_attach(sc->sc_sme, e);
1115b4d62e18Sjmcneill 	}
1116a8e9e1a9Sjakllsch 
1117a8e9e1a9Sjakllsch 	if (c->maxcap_step) {
1118a8e9e1a9Sjakllsch 		e = &sc->sc_sensor[AXP_SENSOR_BATT_MAXIMUM_CAPACITY];
1119a8e9e1a9Sjakllsch 		e->private = AXP_SENSOR_BATT_MAXIMUM_CAPACITY;
1120a8e9e1a9Sjakllsch 		e->units = ENVSYS_SAMPHOUR;
1121a8e9e1a9Sjakllsch 		e->state = ENVSYS_SINVALID;
1122a8e9e1a9Sjakllsch 		strlcpy(e->desc, "battery maximum capacity", sizeof(e->desc));
1123a8e9e1a9Sjakllsch 		sysmon_envsys_sensor_attach(sc->sc_sme, e);
1124a8e9e1a9Sjakllsch 	}
1125a8e9e1a9Sjakllsch 
1126a8e9e1a9Sjakllsch 	if (c->coulomb_step) {
1127a8e9e1a9Sjakllsch 		e = &sc->sc_sensor[AXP_SENSOR_BATT_CURRENT_CAPACITY];
1128a8e9e1a9Sjakllsch 		e->private = AXP_SENSOR_BATT_CURRENT_CAPACITY;
1129a8e9e1a9Sjakllsch 		e->units = ENVSYS_SAMPHOUR;
1130a8e9e1a9Sjakllsch 		e->state = ENVSYS_SINVALID;
1131a8e9e1a9Sjakllsch 		strlcpy(e->desc, "battery current capacity", sizeof(e->desc));
1132a8e9e1a9Sjakllsch 		sysmon_envsys_sensor_attach(sc->sc_sme, e);
1133a8e9e1a9Sjakllsch 	}
1134b4d62e18Sjmcneill }
1135b4d62e18Sjmcneill 
1136b4d62e18Sjmcneill static void
1137b4d62e18Sjmcneill axppmic_attach_sensors(struct axppmic_softc *sc)
1138b4d62e18Sjmcneill {
1139c6020708Sjmcneill 	if (sc->sc_conf->has_battery) {
1140b4d62e18Sjmcneill 		sc->sc_sme = sysmon_envsys_create();
1141b4d62e18Sjmcneill 		sc->sc_sme->sme_name = device_xname(sc->sc_dev);
1142b4d62e18Sjmcneill 		sc->sc_sme->sme_cookie = sc;
1143b4d62e18Sjmcneill 		sc->sc_sme->sme_refresh = axppmic_sensor_refresh;
1144b4d62e18Sjmcneill 		sc->sc_sme->sme_class = SME_CLASS_BATTERY;
11455a236e50Sjmcneill 		sc->sc_sme->sme_flags = SME_INIT_REFRESH;
1146b4d62e18Sjmcneill 
1147c2f11555Sjmcneill 		axppmic_attach_acadapter(sc);
1148b4d62e18Sjmcneill 		axppmic_attach_battery(sc);
1149b4d62e18Sjmcneill 
1150b4d62e18Sjmcneill 		sysmon_envsys_register(sc->sc_sme);
1151b4d62e18Sjmcneill 	}
1152b4d62e18Sjmcneill }
1153b4d62e18Sjmcneill 
1154b4d62e18Sjmcneill 
115571a82865Sjmcneill static int
115671a82865Sjmcneill axppmic_match(device_t parent, cfdata_t match, void *aux)
115771a82865Sjmcneill {
115871a82865Sjmcneill 	struct i2c_attach_args *ia = aux;
11594081e2beSthorpej 	int match_result;
116071a82865Sjmcneill 
1161feee3a19Sthorpej 	if (iic_use_direct_match(ia, match, compat_data, &match_result))
1162aa41e992Sthorpej 		return match_result;
116371a82865Sjmcneill 
1164aa41e992Sthorpej 	/* This device is direct-config only. */
1165aa41e992Sthorpej 
1166aa41e992Sthorpej 	return 0;
116771a82865Sjmcneill }
116871a82865Sjmcneill 
116971a82865Sjmcneill static void
117071a82865Sjmcneill axppmic_attach(device_t parent, device_t self, void *aux)
117171a82865Sjmcneill {
117271a82865Sjmcneill 	struct axppmic_softc *sc = device_private(self);
1173408f5aa5Sthorpej 	const struct device_compatible_entry *dce = NULL;
117471a82865Sjmcneill 	const struct axppmic_config *c;
117571a82865Sjmcneill 	struct axpreg_attach_args aaa;
117671a82865Sjmcneill 	struct i2c_attach_args *ia = aux;
117771a82865Sjmcneill 	int phandle, child, i;
1178c9ef8419Sjmcneill 	uint8_t irq_mask, val;
1179c9ef8419Sjmcneill 	int error;
118071a82865Sjmcneill 
11811f5ee023Sthorpej 	dce = iic_compatible_lookup(ia, compat_data);
11824081e2beSthorpej 	KASSERT(dce != NULL);
118339983299Sthorpej 	c = dce->data;
118471a82865Sjmcneill 
118571a82865Sjmcneill 	sc->sc_dev = self;
118671a82865Sjmcneill 	sc->sc_i2c = ia->ia_tag;
118771a82865Sjmcneill 	sc->sc_addr = ia->ia_addr;
118871a82865Sjmcneill 	sc->sc_phandle = ia->ia_cookie;
1189c6020708Sjmcneill 	sc->sc_conf = c;
119071a82865Sjmcneill 
119171a82865Sjmcneill 	aprint_naive("\n");
119271a82865Sjmcneill 	aprint_normal(": %s\n", c->name);
119371a82865Sjmcneill 
1194c9ef8419Sjmcneill 	if (c->has_mode_set) {
11952122d685Sskrll 		const bool master_mode =
11962122d685Sskrll 		    of_hasprop(sc->sc_phandle, "x-powers,self-working-mode") ||
1197c9ef8419Sjmcneill 		    of_hasprop(sc->sc_phandle, "x-powers,master-mode");
1198c9ef8419Sjmcneill 
11990c3f7694Sthorpej 		iic_acquire_bus(sc->sc_i2c, 0);
1200c9ef8419Sjmcneill 		axppmic_write(sc->sc_i2c, sc->sc_addr, AXP_ADDR_EXT_REG,
12010c3f7694Sthorpej 		    master_mode ? AXP_ADDR_EXT_MASTER : AXP_ADDR_EXT_SLAVE, 0);
12020c3f7694Sthorpej 		iic_release_bus(sc->sc_i2c, 0);
1203c9ef8419Sjmcneill 	}
1204c9ef8419Sjmcneill 
12050c3f7694Sthorpej 	iic_acquire_bus(sc->sc_i2c, 0);
12060c3f7694Sthorpej 	error = axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_CHIP_ID_REG, &val, 0);
12070c3f7694Sthorpej 	iic_release_bus(sc->sc_i2c, 0);
1208c9ef8419Sjmcneill 	if (error != 0) {
1209c9ef8419Sjmcneill 		aprint_error_dev(self, "couldn't read chipid\n");
1210c9ef8419Sjmcneill 		return;
1211c9ef8419Sjmcneill 	}
1212c9ef8419Sjmcneill 	aprint_debug_dev(self, "chipid %#x\n", val);
1213c9ef8419Sjmcneill 
121471a82865Sjmcneill 	sc->sc_smpsw.smpsw_name = device_xname(self);
121571a82865Sjmcneill 	sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_POWER;
121671a82865Sjmcneill 	sysmon_pswitch_register(&sc->sc_smpsw);
121771a82865Sjmcneill 
1218d172e13fSthorpej 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
1219d172e13fSthorpej 
1220c9ef8419Sjmcneill 	if (c->irq_regs > 0) {
1221d172e13fSthorpej 		char intrstr[128];
1222d172e13fSthorpej 
1223d172e13fSthorpej 		if (!fdtbus_intr_str(sc->sc_phandle, 0,
1224d172e13fSthorpej 				     intrstr, sizeof(intrstr))) {
1225d172e13fSthorpej 			aprint_error_dev(self,
1226d172e13fSthorpej 			    "WARNING: failed to decode interrupt\n");
1227d172e13fSthorpej 		}
1228d172e13fSthorpej 
1229d172e13fSthorpej 		sc->sc_ih = fdtbus_intr_establish(sc->sc_phandle, 0, IPL_VM,
1230d172e13fSthorpej 						  FDT_INTR_MPSAFE,
1231d172e13fSthorpej 						  axppmic_intr, sc);
1232d172e13fSthorpej 		if (sc->sc_ih == NULL) {
1233d172e13fSthorpej 			aprint_error_dev(self,
1234d172e13fSthorpej 			    "WARNING: couldn't establish interrupt handler\n");
1235d172e13fSthorpej 		}
1236d172e13fSthorpej 
1237d172e13fSthorpej 		error = workqueue_create(&sc->sc_wq, device_xname(self),
1238d172e13fSthorpej 					 axppmic_work, NULL,
1239d172e13fSthorpej 					 PRI_SOFTSERIAL, IPL_VM,
1240d172e13fSthorpej 					 WQ_MPSAFE);
1241d172e13fSthorpej 		if (error) {
1242d172e13fSthorpej 			sc->sc_wq = NULL;
1243d172e13fSthorpej 			aprint_error_dev(self,
1244d172e13fSthorpej 			    "WARNING: couldn't create work queue: error %d\n",
1245d172e13fSthorpej 			    error);
1246d172e13fSthorpej 		}
1247d172e13fSthorpej 
1248d172e13fSthorpej 		if (sc->sc_ih != NULL && sc->sc_wq != NULL) {
12490c3f7694Sthorpej 			iic_acquire_bus(sc->sc_i2c, 0);
1250b4d62e18Sjmcneill 			for (i = 1; i <= c->irq_regs; i++) {
125171a82865Sjmcneill 				irq_mask = 0;
1252c6020708Sjmcneill 				if (i == c->poklirq.reg)
1253c6020708Sjmcneill 					irq_mask |= c->poklirq.mask;
1254c6020708Sjmcneill 				if (i == c->acinirq.reg)
1255c6020708Sjmcneill 					irq_mask |= c->acinirq.mask;
1256c6020708Sjmcneill 				if (i == c->vbusirq.reg)
1257c6020708Sjmcneill 					irq_mask |= c->vbusirq.mask;
1258c6020708Sjmcneill 				if (i == c->battirq.reg)
1259c6020708Sjmcneill 					irq_mask |= c->battirq.mask;
1260c6020708Sjmcneill 				if (i == c->chargeirq.reg)
1261c6020708Sjmcneill 					irq_mask |= c->chargeirq.mask;
1262c6020708Sjmcneill 				if (i == c->chargestirq.reg)
1263c6020708Sjmcneill 					irq_mask |= c->chargestirq.mask;
1264d172e13fSthorpej 				axppmic_write(sc->sc_i2c, sc->sc_addr,
1265d172e13fSthorpej 					      AXP_IRQ_ENABLE_REG(i),
1266d172e13fSthorpej 					      irq_mask, 0);
126771a82865Sjmcneill 			}
12680c3f7694Sthorpej 			iic_release_bus(sc->sc_i2c, 0);
126971a82865Sjmcneill 		}
1270c9ef8419Sjmcneill 	}
127171a82865Sjmcneill 
127271a82865Sjmcneill 	fdtbus_register_power_controller(sc->sc_dev, sc->sc_phandle,
127371a82865Sjmcneill 	    &axppmic_power_funcs);
127471a82865Sjmcneill 
1275ee5caec1Sjmcneill 	if (c->gpio_compat != NULL) {
1276ee5caec1Sjmcneill 		phandle = of_find_bycompat(sc->sc_phandle, c->gpio_compat);
1277ee5caec1Sjmcneill 		if (phandle > 0) {
1278ee5caec1Sjmcneill 			fdtbus_register_gpio_controller(self, phandle,
1279ee5caec1Sjmcneill 			    &axppmic_gpio_funcs);
1280ee5caec1Sjmcneill 		}
1281ee5caec1Sjmcneill 	}
1282ee5caec1Sjmcneill 
128371a82865Sjmcneill 	phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators");
1284b4d62e18Sjmcneill 	if (phandle > 0) {
128571a82865Sjmcneill 		aaa.reg_i2c = sc->sc_i2c;
128671a82865Sjmcneill 		aaa.reg_addr = sc->sc_addr;
128771a82865Sjmcneill 		for (i = 0; i < c->ncontrols; i++) {
128871a82865Sjmcneill 			const struct axppmic_ctrl *ctrl = &c->controls[i];
128971a82865Sjmcneill 			child = of_find_firstchild_byname(phandle, ctrl->c_name);
129071a82865Sjmcneill 			if (child <= 0)
129171a82865Sjmcneill 				continue;
129271a82865Sjmcneill 			aaa.reg_ctrl = ctrl;
129371a82865Sjmcneill 			aaa.reg_phandle = child;
1294c7fb772bSthorpej 			config_found(sc->sc_dev, &aaa, NULL, CFARGS_NONE);
129571a82865Sjmcneill 		}
129671a82865Sjmcneill 	}
129771a82865Sjmcneill 
1298b4d62e18Sjmcneill 	if (c->has_battery)
1299b4d62e18Sjmcneill 		axppmic_attach_sensors(sc);
1300b4d62e18Sjmcneill }
1301b4d62e18Sjmcneill 
130271a82865Sjmcneill static int
130371a82865Sjmcneill axpreg_acquire(device_t dev)
130471a82865Sjmcneill {
130571a82865Sjmcneill 	return 0;
130671a82865Sjmcneill }
130771a82865Sjmcneill 
130871a82865Sjmcneill static void
130971a82865Sjmcneill axpreg_release(device_t dev)
131071a82865Sjmcneill {
131171a82865Sjmcneill }
131271a82865Sjmcneill 
131371a82865Sjmcneill static int
131471a82865Sjmcneill axpreg_enable(device_t dev, bool enable)
131571a82865Sjmcneill {
131671a82865Sjmcneill 	struct axpreg_softc *sc = device_private(dev);
131771a82865Sjmcneill 	const struct axppmic_ctrl *c = sc->sc_ctrl;
13184d2890e1Sthorpej 	const int flags = 0;
131971a82865Sjmcneill 	uint8_t val;
132071a82865Sjmcneill 	int error;
132171a82865Sjmcneill 
132271a82865Sjmcneill 	if (!c->c_enable_mask)
132371a82865Sjmcneill 		return EINVAL;
132471a82865Sjmcneill 
132571a82865Sjmcneill 	iic_acquire_bus(sc->sc_i2c, flags);
132671a82865Sjmcneill 	if ((error = axppmic_read(sc->sc_i2c, sc->sc_addr, c->c_enable_reg, &val, flags)) == 0) {
132771a82865Sjmcneill 		val &= ~c->c_enable_mask;
1328a1e24c6aSjmcneill 		if (enable)
1329a1e24c6aSjmcneill 			val |= c->c_enable_val;
1330a1e24c6aSjmcneill 		else
1331a1e24c6aSjmcneill 			val |= c->c_disable_val;
133271a82865Sjmcneill 		error = axppmic_write(sc->sc_i2c, sc->sc_addr, c->c_enable_reg, val, flags);
133371a82865Sjmcneill 	}
133471a82865Sjmcneill 	iic_release_bus(sc->sc_i2c, flags);
133571a82865Sjmcneill 
133671a82865Sjmcneill 	return error;
133771a82865Sjmcneill }
133871a82865Sjmcneill 
133971a82865Sjmcneill static int
134071a82865Sjmcneill axpreg_set_voltage(device_t dev, u_int min_uvol, u_int max_uvol)
134171a82865Sjmcneill {
134271a82865Sjmcneill 	struct axpreg_softc *sc = device_private(dev);
134371a82865Sjmcneill 	const struct axppmic_ctrl *c = sc->sc_ctrl;
134471a82865Sjmcneill 
134571a82865Sjmcneill 	return axppmic_set_voltage(sc->sc_i2c, sc->sc_addr, c,
134671a82865Sjmcneill 	    min_uvol / 1000, max_uvol / 1000);
134771a82865Sjmcneill }
134871a82865Sjmcneill 
134971a82865Sjmcneill static int
135071a82865Sjmcneill axpreg_get_voltage(device_t dev, u_int *puvol)
135171a82865Sjmcneill {
135271a82865Sjmcneill 	struct axpreg_softc *sc = device_private(dev);
135371a82865Sjmcneill 	const struct axppmic_ctrl *c = sc->sc_ctrl;
135471a82865Sjmcneill 	int error;
135571a82865Sjmcneill 	u_int vol;
135671a82865Sjmcneill 
135771a82865Sjmcneill 	error = axppmic_get_voltage(sc->sc_i2c, sc->sc_addr, c, &vol);
135871a82865Sjmcneill 	if (error)
135971a82865Sjmcneill 		return error;
136071a82865Sjmcneill 
136171a82865Sjmcneill 	*puvol = vol * 1000;
136271a82865Sjmcneill 	return 0;
136371a82865Sjmcneill }
136471a82865Sjmcneill 
136571a82865Sjmcneill static struct fdtbus_regulator_controller_func axpreg_funcs = {
136671a82865Sjmcneill 	.acquire = axpreg_acquire,
136771a82865Sjmcneill 	.release = axpreg_release,
136871a82865Sjmcneill 	.enable = axpreg_enable,
136971a82865Sjmcneill 	.set_voltage = axpreg_set_voltage,
137071a82865Sjmcneill 	.get_voltage = axpreg_get_voltage,
137171a82865Sjmcneill };
137271a82865Sjmcneill 
137371a82865Sjmcneill static int
137471a82865Sjmcneill axpreg_match(device_t parent, cfdata_t match, void *aux)
137571a82865Sjmcneill {
137671a82865Sjmcneill 	return 1;
137771a82865Sjmcneill }
137871a82865Sjmcneill 
137971a82865Sjmcneill static void
138071a82865Sjmcneill axpreg_attach(device_t parent, device_t self, void *aux)
138171a82865Sjmcneill {
138271a82865Sjmcneill 	struct axpreg_softc *sc = device_private(self);
138371a82865Sjmcneill 	struct axpreg_attach_args *aaa = aux;
138471a82865Sjmcneill 	const int phandle = aaa->reg_phandle;
138571a82865Sjmcneill 	const char *name;
1386bd1a7408Sjmcneill 	u_int uvol, min_uvol, max_uvol;
138771a82865Sjmcneill 
138871a82865Sjmcneill 	sc->sc_dev = self;
138971a82865Sjmcneill 	sc->sc_i2c = aaa->reg_i2c;
139071a82865Sjmcneill 	sc->sc_addr = aaa->reg_addr;
139171a82865Sjmcneill 	sc->sc_ctrl = aaa->reg_ctrl;
139271a82865Sjmcneill 
139371a82865Sjmcneill 	fdtbus_register_regulator_controller(self, phandle,
139471a82865Sjmcneill 	    &axpreg_funcs);
139571a82865Sjmcneill 
139671a82865Sjmcneill 	aprint_naive("\n");
139771a82865Sjmcneill 	name = fdtbus_get_string(phandle, "regulator-name");
139871a82865Sjmcneill 	if (name)
139971a82865Sjmcneill 		aprint_normal(": %s\n", name);
140071a82865Sjmcneill 	else
140171a82865Sjmcneill 		aprint_normal("\n");
1402bd1a7408Sjmcneill 
1403e1af7576Sskrll 	int error = axpreg_get_voltage(self, &uvol);
1404e1af7576Sskrll 	if (error)
1405e1af7576Sskrll 		return;
1406e1af7576Sskrll 
1407bd1a7408Sjmcneill 	if (of_getprop_uint32(phandle, "regulator-min-microvolt", &min_uvol) == 0 &&
1408bd1a7408Sjmcneill 	    of_getprop_uint32(phandle, "regulator-max-microvolt", &max_uvol) == 0) {
1409bd1a7408Sjmcneill 		if (uvol < min_uvol || uvol > max_uvol) {
1410fc5749c3Sjmcneill 			aprint_debug_dev(self, "fix voltage %u uV -> %u/%u uV\n",
1411fc5749c3Sjmcneill 			    uvol, min_uvol, max_uvol);
1412bd1a7408Sjmcneill 			axpreg_set_voltage(self, min_uvol, max_uvol);
1413bd1a7408Sjmcneill 		}
1414bd1a7408Sjmcneill 	}
1415fc5749c3Sjmcneill 
1416fc5749c3Sjmcneill 	if (of_hasprop(phandle, "regulator-always-on") ||
1417fc5749c3Sjmcneill 	    of_hasprop(phandle, "regulator-boot-on")) {
1418fc5749c3Sjmcneill 		axpreg_enable(self, true);
1419fc5749c3Sjmcneill 	}
142071a82865Sjmcneill }
142171a82865Sjmcneill 
142271a82865Sjmcneill CFATTACH_DECL_NEW(axppmic, sizeof(struct axppmic_softc),
142371a82865Sjmcneill     axppmic_match, axppmic_attach, NULL, NULL);
142471a82865Sjmcneill 
142571a82865Sjmcneill CFATTACH_DECL_NEW(axpreg, sizeof(struct axpreg_softc),
142671a82865Sjmcneill     axpreg_match, axpreg_attach, NULL, NULL);
1427