1 /* $NetBSD: act8846.c,v 1.4 2018/04/30 20:26:09 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@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.4 2018/04/30 20:26:09 jmcneill 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 1; 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