1 /* $NetBSD: act8846.c,v 1.3 2015/01/02 21:55:31 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.3 2015/01/02 21:55:31 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 return 1; 152 } 153 154 static void 155 act8846_attach(device_t parent, device_t self, void *aux) 156 { 157 struct act8846_softc *sc = device_private(self); 158 struct i2c_attach_args *ia = aux; 159 u_int n; 160 161 sc->sc_dev = self; 162 sc->sc_i2c = ia->ia_tag; 163 sc->sc_addr = ia->ia_addr; 164 165 aprint_naive("\n"); 166 aprint_normal("\n"); 167 168 sc->sc_nctrl = __arraycount(act8846_ctrls); 169 sc->sc_ctrl = kmem_alloc(sizeof(act8846_ctrls), KM_SLEEP); 170 memcpy(sc->sc_ctrl, act8846_ctrls, sizeof(act8846_ctrls)); 171 for (n = 0; n < sc->sc_nctrl; n++) { 172 sc->sc_ctrl[n].c_dev = self; 173 } 174 175 for (n = 0; n < sc->sc_nctrl; n++) { 176 act8846_print(&sc->sc_ctrl[n]); 177 } 178 } 179 180 static int 181 act8846_read(struct act8846_softc *sc, uint8_t reg, uint8_t *val) 182 { 183 return iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr, reg, val, 184 cold ? I2C_F_POLL : 0); 185 } 186 187 static int 188 act8846_write(struct act8846_softc *sc, uint8_t reg, uint8_t val) 189 { 190 return iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr, reg, val, 191 cold ? I2C_F_POLL : 0); 192 } 193 194 static void 195 act8846_print(struct act8846_ctrl *c) 196 { 197 struct act8846_softc *sc = device_private(c->c_dev); 198 u_int voltage; 199 bool enabled; 200 201 device_printf(sc->sc_dev, "%s:", c->c_name); 202 if (act8846_get_voltage(c, &voltage)) { 203 printf(" [??? V]"); 204 } else { 205 printf(" [%d.%03dV]", voltage / 1000, 206 voltage % 1000); 207 } 208 if (act8846_is_enabled(c, &enabled)) { 209 printf(" [unknown state]"); 210 } else { 211 printf(" [%s]", enabled ? "ON" : "OFF"); 212 } 213 printf("\n"); 214 } 215 216 struct act8846_ctrl * 217 act8846_lookup(device_t dev, const char *name) 218 { 219 struct act8846_softc *sc = device_private(dev); 220 struct act8846_ctrl *c; 221 u_int n; 222 223 for (n = 0; n < sc->sc_nctrl; n++) { 224 c = &sc->sc_ctrl[n]; 225 if (strcmp(c->c_name, name) == 0) { 226 return c; 227 } 228 } 229 230 return NULL; 231 } 232 233 int 234 act8846_set_voltage(struct act8846_ctrl *c, u_int min, u_int max) 235 { 236 struct act8846_softc *sc = device_private(c->c_dev); 237 uint8_t val; 238 int error, n; 239 240 if (min < c->c_min || min > c->c_max || (min % 25) != 0) 241 return EINVAL; 242 243 for (n = 0; n < __arraycount(act8846_vset); n++) { 244 if (min >= act8846_vset[n] && max <= act8846_vset[n]) { 245 break; 246 } 247 } 248 if (n == __arraycount(act8846_vset)) 249 return EINVAL; 250 251 val = __SHIFTIN(n, ACT_VSET_VSET); 252 253 iic_acquire_bus(sc->sc_i2c, 0); 254 error = act8846_write(sc, c->c_base + ACT_VSET0_OFFSET, val); 255 iic_release_bus(sc->sc_i2c, 0); 256 #ifdef ACT_DEBUG 257 if (error == 0) 258 act8846_print(c); 259 #endif 260 return error; 261 } 262 263 int 264 act8846_get_voltage(struct act8846_ctrl *c, u_int *pvol) 265 { 266 struct act8846_softc *sc = device_private(c->c_dev); 267 uint8_t val; 268 int error; 269 270 iic_acquire_bus(sc->sc_i2c, 0); 271 error = act8846_read(sc, c->c_base + ACT_VSET0_OFFSET, &val); 272 iic_release_bus(sc->sc_i2c, 0); 273 if (error) 274 return error; 275 276 *pvol = act8846_vset[__SHIFTOUT(val, ACT_VSET_VSET)]; 277 278 return 0; 279 } 280 281 int 282 act8846_is_enabled(struct act8846_ctrl *c, bool *penabled) 283 { 284 struct act8846_softc *sc = device_private(c->c_dev); 285 uint8_t val, regoff, regmask; 286 int error; 287 288 if (c->c_type == ACT_CTRL_DCDC) { 289 regoff = ACT_DCDC_CTRL_OFFSET; 290 regmask = ACT_DCDC_CTRL_ON; 291 } else { 292 regoff = ACT_LDO_CTRL_OFFSET; 293 regmask = ACT_LDO_CTRL_ON; 294 } 295 296 iic_acquire_bus(sc->sc_i2c, 0); 297 error = act8846_read(sc, c->c_base + regoff, &val); 298 iic_release_bus(sc->sc_i2c, 0); 299 if (error) 300 return error; 301 302 *penabled = !!(val & regmask); 303 return 0; 304 } 305 306 int 307 act8846_enable(struct act8846_ctrl *c) 308 { 309 struct act8846_softc *sc = device_private(c->c_dev); 310 uint8_t val, regoff, regmask; 311 int error; 312 313 if (c->c_type == ACT_CTRL_DCDC) { 314 regoff = ACT_DCDC_CTRL_OFFSET; 315 regmask = ACT_DCDC_CTRL_ON; 316 } else { 317 regoff = ACT_LDO_CTRL_OFFSET; 318 regmask = ACT_LDO_CTRL_ON; 319 } 320 321 iic_acquire_bus(sc->sc_i2c, 0); 322 if ((error = act8846_read(sc, c->c_base + regoff, &val)) != 0) 323 goto done; 324 val |= regmask; 325 error = act8846_write(sc, c->c_base + regoff, val); 326 done: 327 iic_release_bus(sc->sc_i2c, 0); 328 #ifdef ACT_DEBUG 329 if (error == 0) 330 act8846_print(c); 331 #endif 332 333 return error; 334 } 335 336 int 337 act8846_disable(struct act8846_ctrl *c) 338 { 339 struct act8846_softc *sc = device_private(c->c_dev); 340 uint8_t val, regoff, regmask; 341 int error; 342 343 if (c->c_type == ACT_CTRL_DCDC) { 344 regoff = ACT_DCDC_CTRL_OFFSET; 345 regmask = ACT_DCDC_CTRL_ON; 346 } else { 347 regoff = ACT_LDO_CTRL_OFFSET; 348 regmask = ACT_LDO_CTRL_ON; 349 } 350 351 iic_acquire_bus(sc->sc_i2c, 0); 352 if ((error = act8846_read(sc, c->c_base + regoff, &val)) != 0) 353 goto done; 354 val &= ~regmask; 355 error = act8846_write(sc, c->c_base + regoff, val); 356 done: 357 iic_release_bus(sc->sc_i2c, 0); 358 #ifdef ACT_DEBUG 359 if (error == 0) 360 act8846_print(c); 361 #endif 362 363 return error; 364 } 365