Home | History | Annotate | Line # | Download | only in i2c
act8846.c revision 1.5
      1 /* $NetBSD: act8846.c,v 1.5 2018/06/16 21:22:13 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 //#define ACT_DEBUG
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: act8846.c,v 1.5 2018/06/16 21:22:13 thorpej Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/systm.h>
     36 #include <sys/kernel.h>
     37 #include <sys/device.h>
     38 #include <sys/conf.h>
     39 #include <sys/bus.h>
     40 #include <sys/kmem.h>
     41 
     42 #include <dev/i2c/i2cvar.h>
     43 #include <dev/i2c/act8846.h>
     44 
     45 #define ACT_BATTVOL_STATUS_REG		0x00
     46 #define ACT_THERMAL_CTRL_REG		0x01
     47 #define ACT_DCDC1_BASE_REG		0x10
     48 #define ACT_DCDC2_BASE_REG		0x20
     49 #define ACT_DCDC3_BASE_REG		0x30
     50 #define ACT_DCDC4_BASE_REG		0x40
     51 #define ACT_LDO1_BASE_REG		0x50
     52 #define ACT_LDO2_BASE_REG		0x58
     53 #define ACT_LDO3_BASE_REG		0x60
     54 #define ACT_LDO4_BASE_REG		0x68
     55 #define ACT_LDO5_BASE_REG		0x70
     56 #define ACT_LDO6_BASE_REG		0x80
     57 #define ACT_LDO7_BASE_REG		0x90
     58 #define ACT_LDO8_BASE_REG		0xa0
     59 #define ACT_LDO9_BASE_REG		0xb0
     60 
     61 #define ACT_VSET0_OFFSET		0
     62 #define ACT_VSET1_OFFSET		1
     63 #define ACT_DCDC_CTRL_OFFSET		2
     64 #define ACT_LDO_CTRL_OFFSET		1
     65 
     66 #define ACT_VSET_VSET			__BITS(5,0)
     67 
     68 #define ACT_DCDC_CTRL_ON		__BIT(7)
     69 
     70 #define ACT_LDO_CTRL_ON			__BIT(7)
     71 
     72 enum act8846_ctrl_type {
     73 	ACT_CTRL_DCDC,
     74 	ACT_CTRL_LDO,
     75 };
     76 
     77 #define ACT_VOLTAGE_MIN			600
     78 #define ACT_VOLTAGE_MAX			3900
     79 
     80 struct act8846_ctrl {
     81 	device_t	c_dev;
     82 
     83 	const char *	c_name;
     84 	u_int		c_min;
     85 	u_int		c_max;
     86 	uint8_t		c_base;
     87 	enum act8846_ctrl_type c_type;
     88 };
     89 
     90 #define ACT_CTRL(name, base, type)				\
     91 	{ .c_name = (name),					\
     92 	  .c_min = ACT_VOLTAGE_MIN, .c_max = ACT_VOLTAGE_MAX,	\
     93 	  .c_base = ACT_ ## base ## _BASE_REG, .c_type = (type) }
     94 
     95 #define ACT_DCDC(name, base)	ACT_CTRL(name, base, ACT_CTRL_DCDC)
     96 #define ACT_LDO(name, base)	ACT_CTRL(name, base, ACT_CTRL_LDO)
     97 
     98 static const struct act8846_ctrl act8846_ctrls[] = {
     99 	ACT_DCDC("DCDC1", DCDC1),	/* VCC_DDR */
    100 	ACT_DCDC("DCDC2", DCDC2),	/* VDD_LOG */
    101 	ACT_DCDC("DCDC3", DCDC3),	/* VDD_ARM */
    102 	ACT_DCDC("DCDC4", DCDC4),	/* VCC_IO */
    103 	ACT_LDO("LDO1", LDO1),		/* VDD_10 */
    104 	ACT_LDO("LDO2", LDO2),		/* VCC_25 */
    105 	ACT_LDO("LDO3", LDO3),		/* VCC18_CIF */
    106 	ACT_LDO("LDO4", LDO4),		/* VCCA_33 */
    107 	ACT_LDO("LDO5", LDO5),		/* VCC_TOUCH */
    108 	ACT_LDO("LDO6", LDO6),		/* VCC33 */
    109 	ACT_LDO("LDO7", LDO7),		/* VCC18_IO */
    110 	ACT_LDO("LDO8", LDO8),		/* VCC28_CIF */
    111 #if 0
    112 	ACT_LDO("LDO9", LDO9),		/* VDD_RTC (Always-ON) */
    113 #endif
    114 };
    115 
    116 /* From datasheet, Table 5: REGx/VSET[] Output Voltage Setting */
    117 static const u_int act8846_vset[] = {
    118 	600, 625, 650, 675, 700, 725, 750, 775,
    119 	800, 825, 850, 875, 900, 925, 950, 975,
    120 	1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
    121 	1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
    122 	1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
    123 	2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
    124 	2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
    125 	3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900
    126 };
    127 
    128 struct act8846_softc {
    129 	device_t	sc_dev;
    130 	i2c_tag_t	sc_i2c;
    131 	i2c_addr_t	sc_addr;
    132 
    133 	u_int		sc_nctrl;
    134 	struct act8846_ctrl *sc_ctrl;
    135 };
    136 
    137 static int	act8846_match(device_t, cfdata_t, void *);
    138 static void	act8846_attach(device_t, device_t, void *);
    139 
    140 static int	act8846_read(struct act8846_softc *, uint8_t, uint8_t *);
    141 static int	act8846_write(struct act8846_softc *, uint8_t, uint8_t);
    142 
    143 static void	act8846_print(struct act8846_ctrl *c);
    144 
    145 CFATTACH_DECL_NEW(act8846pm, sizeof(struct act8846_softc),
    146     act8846_match, act8846_attach, NULL, NULL);
    147 
    148 static int
    149 act8846_match(device_t parent, cfdata_t match, void *aux)
    150 {
    151 	struct i2c_attach_args *ia = aux;
    152 
    153 	if (ia->ia_addr == 0x5a)
    154 		return I2C_MATCH_ADDRESS_ONLY;
    155 
    156 	return 0;
    157 }
    158 
    159 static void
    160 act8846_attach(device_t parent, device_t self, void *aux)
    161 {
    162 	struct act8846_softc *sc = device_private(self);
    163 	struct i2c_attach_args *ia = aux;
    164 	u_int n;
    165 
    166 	sc->sc_dev = self;
    167 	sc->sc_i2c = ia->ia_tag;
    168 	sc->sc_addr = ia->ia_addr;
    169 
    170 	aprint_naive("\n");
    171 	aprint_normal("\n");
    172 
    173 	sc->sc_nctrl = __arraycount(act8846_ctrls);
    174 	sc->sc_ctrl = kmem_alloc(sizeof(act8846_ctrls), KM_SLEEP);
    175 	memcpy(sc->sc_ctrl, act8846_ctrls, sizeof(act8846_ctrls));
    176 	for (n = 0; n < sc->sc_nctrl; n++) {
    177 		sc->sc_ctrl[n].c_dev = self;
    178 	}
    179 
    180 	for (n = 0; n < sc->sc_nctrl; n++) {
    181 		act8846_print(&sc->sc_ctrl[n]);
    182 	}
    183 }
    184 
    185 static int
    186 act8846_read(struct act8846_softc *sc, uint8_t reg, uint8_t *val)
    187 {
    188 	return iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr, reg, val,
    189 	    cold ? I2C_F_POLL : 0);
    190 }
    191 
    192 static int
    193 act8846_write(struct act8846_softc *sc, uint8_t reg, uint8_t val)
    194 {
    195 	return iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr, reg, val,
    196 	    cold ? I2C_F_POLL : 0);
    197 }
    198 
    199 static void
    200 act8846_print(struct act8846_ctrl *c)
    201 {
    202 	struct act8846_softc *sc = device_private(c->c_dev);
    203 	u_int voltage;
    204 	bool enabled;
    205 
    206 	device_printf(sc->sc_dev, "%s:", c->c_name);
    207 	if (act8846_get_voltage(c, &voltage)) {
    208 		printf(" [??? V]");
    209 	} else {
    210 		printf(" [%d.%03dV]", voltage / 1000,
    211 		    voltage % 1000);
    212 	}
    213 	if (act8846_is_enabled(c, &enabled)) {
    214 		printf(" [unknown state]");
    215 	} else {
    216 		printf(" [%s]", enabled ? "ON" : "OFF");
    217 	}
    218 	printf("\n");
    219 }
    220 
    221 struct act8846_ctrl *
    222 act8846_lookup(device_t dev, const char *name)
    223 {
    224 	struct act8846_softc *sc = device_private(dev);
    225 	struct act8846_ctrl *c;
    226 	u_int n;
    227 
    228 	for (n = 0; n < sc->sc_nctrl; n++) {
    229 		c = &sc->sc_ctrl[n];
    230 		if (strcmp(c->c_name, name) == 0) {
    231 			return c;
    232 		}
    233 	}
    234 
    235 	return NULL;
    236 }
    237 
    238 int
    239 act8846_set_voltage(struct act8846_ctrl *c, u_int min, u_int max)
    240 {
    241 	struct act8846_softc *sc = device_private(c->c_dev);
    242 	uint8_t val;
    243 	int error, n;
    244 
    245 	if (min < c->c_min || min > c->c_max || (min % 25) != 0)
    246 		return EINVAL;
    247 
    248 	for (n = 0; n < __arraycount(act8846_vset); n++) {
    249 		if (min >= act8846_vset[n] && max <= act8846_vset[n]) {
    250 			break;
    251 		}
    252 	}
    253 	if (n == __arraycount(act8846_vset))
    254 		return EINVAL;
    255 
    256 	val = __SHIFTIN(n, ACT_VSET_VSET);
    257 
    258 	iic_acquire_bus(sc->sc_i2c, 0);
    259 	error = act8846_write(sc, c->c_base + ACT_VSET0_OFFSET, val);
    260 	iic_release_bus(sc->sc_i2c, 0);
    261 #ifdef ACT_DEBUG
    262 	if (error == 0)
    263 		act8846_print(c);
    264 #endif
    265 	return error;
    266 }
    267 
    268 int
    269 act8846_get_voltage(struct act8846_ctrl *c, u_int *pvol)
    270 {
    271 	struct act8846_softc *sc = device_private(c->c_dev);
    272 	uint8_t val;
    273 	int error;
    274 
    275 	iic_acquire_bus(sc->sc_i2c, 0);
    276 	error = act8846_read(sc, c->c_base + ACT_VSET0_OFFSET, &val);
    277 	iic_release_bus(sc->sc_i2c, 0);
    278 	if (error)
    279 		return error;
    280 
    281 	*pvol = act8846_vset[__SHIFTOUT(val, ACT_VSET_VSET)];
    282 
    283 	return 0;
    284 }
    285 
    286 int
    287 act8846_is_enabled(struct act8846_ctrl *c, bool *penabled)
    288 {
    289 	struct act8846_softc *sc = device_private(c->c_dev);
    290 	uint8_t val, regoff, regmask;
    291 	int error;
    292 
    293 	if (c->c_type == ACT_CTRL_DCDC) {
    294 		regoff = ACT_DCDC_CTRL_OFFSET;
    295 		regmask = ACT_DCDC_CTRL_ON;
    296 	} else {
    297 		regoff = ACT_LDO_CTRL_OFFSET;
    298 		regmask = ACT_LDO_CTRL_ON;
    299 	}
    300 
    301 	iic_acquire_bus(sc->sc_i2c, 0);
    302 	error = act8846_read(sc, c->c_base + regoff, &val);
    303 	iic_release_bus(sc->sc_i2c, 0);
    304 	if (error)
    305 		return error;
    306 
    307 	*penabled = !!(val & regmask);
    308 	return 0;
    309 }
    310 
    311 int
    312 act8846_enable(struct act8846_ctrl *c)
    313 {
    314 	struct act8846_softc *sc = device_private(c->c_dev);
    315 	uint8_t val, regoff, regmask;
    316 	int error;
    317 
    318 	if (c->c_type == ACT_CTRL_DCDC) {
    319 		regoff = ACT_DCDC_CTRL_OFFSET;
    320 		regmask = ACT_DCDC_CTRL_ON;
    321 	} else {
    322 		regoff = ACT_LDO_CTRL_OFFSET;
    323 		regmask = ACT_LDO_CTRL_ON;
    324 	}
    325 
    326 	iic_acquire_bus(sc->sc_i2c, 0);
    327 	if ((error = act8846_read(sc, c->c_base + regoff, &val)) != 0)
    328 		goto done;
    329 	val |= regmask;
    330 	error = act8846_write(sc, c->c_base + regoff, val);
    331 done:
    332 	iic_release_bus(sc->sc_i2c, 0);
    333 #ifdef ACT_DEBUG
    334 	if (error == 0)
    335 		act8846_print(c);
    336 #endif
    337 
    338 	return error;
    339 }
    340 
    341 int
    342 act8846_disable(struct act8846_ctrl *c)
    343 {
    344 	struct act8846_softc *sc = device_private(c->c_dev);
    345 	uint8_t val, regoff, regmask;
    346 	int error;
    347 
    348 	if (c->c_type == ACT_CTRL_DCDC) {
    349 		regoff = ACT_DCDC_CTRL_OFFSET;
    350 		regmask = ACT_DCDC_CTRL_ON;
    351 	} else {
    352 		regoff = ACT_LDO_CTRL_OFFSET;
    353 		regmask = ACT_LDO_CTRL_ON;
    354 	}
    355 
    356 	iic_acquire_bus(sc->sc_i2c, 0);
    357 	if ((error = act8846_read(sc, c->c_base + regoff, &val)) != 0)
    358 		goto done;
    359 	val &= ~regmask;
    360 	error = act8846_write(sc, c->c_base + regoff, val);
    361 done:
    362 	iic_release_bus(sc->sc_i2c, 0);
    363 #ifdef ACT_DEBUG
    364 	if (error == 0)
    365 		act8846_print(c);
    366 #endif
    367 
    368 	return error;
    369 }
    370