1 /* $NetBSD: twl4030.c,v 1.3 2019/11/03 09:34:09 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2019 Jared 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 #include "opt_fdt.h" 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: twl4030.c,v 1.3 2019/11/03 09:34: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 #include <sys/gpio.h> 42 43 #include <dev/i2c/i2cvar.h> 44 45 #include <dev/fdt/fdtvar.h> 46 47 #define TWL_PIN_COUNT 16 48 49 /* TWL4030 is a multi-function IC. Each module is at a separate I2C address */ 50 #define ADDR_USB 0x00 51 #define ADDR_INT 0x01 52 #define ADDR_AUX 0x02 53 #define ADDR_POWER 0x03 54 55 /* INTBR registers */ 56 #define IDCODE_7_0 0x85 57 #define IDCODE_15_8 0x86 58 #define IDCODE_23_16 0x87 59 #define IDCODE_31_24 0x88 60 61 /* GPIO registers */ 62 #define GPIOBASE 0x98 63 #define GPIODATAIN(pin) (GPIOBASE + 0x00 + (pin) / 8) 64 #define GPIODATADIR(pin) (GPIOBASE + 0x03 + (pin) / 8) 65 #define CLEARGPIODATAOUT(pin) (GPIOBASE + 0x09 + (pin) / 8) 66 #define SETGPIODATAOUT(pin) (GPIOBASE + 0x0c + (pin) / 8) 67 #define PIN_BIT(pin) __BIT((pin) % 8) 68 #define GPIOPUPDCTR(pin) (GPIOBASE + 0x13 + (n) / 4) 69 #define PUPD_BITS(pin) __BITS((pin) % 4 + 1, (pin) % 4) 70 71 /* POWER registers */ 72 #define SECONDS_REG 0x1c 73 #define MINUTES_REG 0x1d 74 #define HOURS_REG 0x1e 75 #define DAYS_REG 0x1f 76 #define MONTHS_REG 0x20 77 #define YEARS_REG 0x21 78 #define WEEKS_REG 0x22 79 #define RTC_CTRL_REG 0x29 80 #define GET_TIME __BIT(6) 81 #define STOP_RTC __BIT(0) 82 83 struct twl_softc { 84 device_t sc_dev; 85 i2c_tag_t sc_i2c; 86 i2c_addr_t sc_addr; 87 int sc_phandle; 88 89 int sc_npins; 90 91 struct todr_chip_handle sc_todr; 92 }; 93 94 struct twl_pin { 95 struct twl_softc *pin_sc; 96 int pin_num; 97 int pin_flags; 98 bool pin_actlo; 99 }; 100 101 static const struct device_compatible_entry compat_data[] = { 102 { "ti,twl4030", 0 }, 103 { NULL, 0 } 104 }; 105 106 #ifdef FDT 107 static const char * const rtc_compatible[] = { "ti,twl4030-rtc", NULL }; 108 static const char * const gpio_compatible[] = { "ti,twl4030-gpio", NULL }; 109 #endif 110 111 static uint8_t 112 twl_read(struct twl_softc *sc, uint8_t mod, uint8_t reg, int flags) 113 { 114 uint8_t val = 0; 115 int error; 116 117 error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr + mod, 118 ®, 1, &val, 1, flags); 119 if (error != 0) 120 aprint_error_dev(sc->sc_dev, "error reading reg %#x: %d\n", reg, error); 121 122 return val; 123 } 124 125 static void 126 twl_write(struct twl_softc *sc, uint8_t mod, uint8_t reg, uint8_t val, int flags) 127 { 128 uint8_t buf[2]; 129 int error; 130 131 buf[0] = reg; 132 buf[1] = val; 133 134 error = iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, sc->sc_addr + mod, 135 NULL, 0, buf, 2, flags); 136 if (error != 0) 137 aprint_error_dev(sc->sc_dev, "error writing reg %#x: %d\n", reg, error); 138 } 139 140 #define I2C_LOCK(sc) iic_acquire_bus((sc)->sc_i2c, I2C_F_POLL) 141 #define I2C_UNLOCK(sc) iic_release_bus((sc)->sc_i2c, I2C_F_POLL) 142 143 #define INT_READ(sc, reg) twl_read((sc), ADDR_INT, (reg), I2C_F_POLL) 144 #define INT_WRITE(sc, reg, val) twl_write((sc), ADDR_INT, (reg), (val), I2C_F_POLL) 145 146 #define POWER_READ(sc, reg) twl_read((sc), ADDR_POWER, (reg), I2C_F_POLL) 147 #define POWER_WRITE(sc, reg, val) twl_write((sc), ADDR_POWER, (reg), (val), I2C_F_POLL) 148 149 static void 150 twl_rtc_enable(struct twl_softc *sc, bool onoff) 151 { 152 uint8_t rtc_ctrl; 153 154 rtc_ctrl = POWER_READ(sc, RTC_CTRL_REG); 155 if (onoff) 156 rtc_ctrl |= STOP_RTC; /* 1: RTC is running */ 157 else 158 rtc_ctrl &= ~STOP_RTC; /* 0: RTC is frozen */ 159 POWER_WRITE(sc, RTC_CTRL_REG, rtc_ctrl); 160 } 161 162 static int 163 twl_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) 164 { 165 struct twl_softc *sc = tch->cookie; 166 uint8_t seconds_reg, minutes_reg, hours_reg, 167 days_reg, months_reg, years_reg, weeks_reg; 168 169 iic_acquire_bus(sc->sc_i2c, I2C_F_POLL); 170 seconds_reg = POWER_READ(sc, SECONDS_REG); 171 minutes_reg = POWER_READ(sc, MINUTES_REG); 172 hours_reg = POWER_READ(sc, HOURS_REG); 173 days_reg = POWER_READ(sc, DAYS_REG); 174 months_reg = POWER_READ(sc, MONTHS_REG); 175 years_reg = POWER_READ(sc, YEARS_REG); 176 weeks_reg = POWER_READ(sc, WEEKS_REG); 177 iic_release_bus(sc->sc_i2c, I2C_F_POLL); 178 179 dt->dt_sec = bcdtobin(seconds_reg); 180 dt->dt_min = bcdtobin(minutes_reg); 181 dt->dt_hour = bcdtobin(hours_reg); 182 dt->dt_day = bcdtobin(days_reg); 183 dt->dt_mon = bcdtobin(months_reg); 184 dt->dt_year = bcdtobin(years_reg) + 2000; 185 dt->dt_wday = bcdtobin(weeks_reg); 186 187 return 0; 188 } 189 190 static int 191 twl_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) 192 { 193 struct twl_softc *sc = tch->cookie; 194 195 iic_acquire_bus(sc->sc_i2c, I2C_F_POLL); 196 twl_rtc_enable(sc, false); 197 POWER_WRITE(sc, SECONDS_REG, bintobcd(dt->dt_sec)); 198 POWER_WRITE(sc, MINUTES_REG, bintobcd(dt->dt_min)); 199 POWER_WRITE(sc, HOURS_REG, bintobcd(dt->dt_hour)); 200 POWER_WRITE(sc, DAYS_REG, bintobcd(dt->dt_day)); 201 POWER_WRITE(sc, MONTHS_REG, bintobcd(dt->dt_mon)); 202 POWER_WRITE(sc, YEARS_REG, bintobcd(dt->dt_year % 100)); 203 POWER_WRITE(sc, WEEKS_REG, bintobcd(dt->dt_wday)); 204 twl_rtc_enable(sc, true); 205 iic_release_bus(sc->sc_i2c, I2C_F_POLL); 206 207 return 0; 208 } 209 210 #ifdef FDT 211 static int 212 twl_gpio_config(struct twl_softc *sc, int pin, int flags) 213 { 214 uint8_t dir; 215 216 KASSERT(pin >= 0 && pin < sc->sc_npins); 217 218 dir = INT_READ(sc, GPIODATADIR(pin)); 219 220 switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 221 case GPIO_PIN_INPUT: 222 dir &= ~PIN_BIT(pin); 223 break; 224 case GPIO_PIN_OUTPUT: 225 dir |= PIN_BIT(pin); 226 break; 227 default: 228 return EINVAL; 229 } 230 231 INT_WRITE(sc, GPIODATADIR(pin), dir); 232 233 return 0; 234 } 235 236 static void * 237 twl_gpio_acquire(device_t dev, const void *data, size_t len, int flags) 238 { 239 struct twl_softc * const sc = device_private(dev); 240 struct twl_pin *gpin; 241 const u_int *gpio = data; 242 int error; 243 244 if (len != 12) 245 return NULL; 246 247 const uint8_t pin = be32toh(gpio[1]) & 0xff; 248 const bool actlo = (be32toh(gpio[2]) & __BIT(0)) != 0; 249 250 if (pin >= sc->sc_npins) 251 return NULL; 252 253 I2C_LOCK(sc); 254 error = twl_gpio_config(sc, pin, flags); 255 I2C_UNLOCK(sc); 256 257 if (error != 0) { 258 device_printf(dev, "bad pin %d config %#x\n", pin, flags); 259 return NULL; 260 } 261 262 gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP); 263 gpin->pin_sc = sc; 264 gpin->pin_num = pin; 265 gpin->pin_flags = flags; 266 gpin->pin_actlo = actlo; 267 268 return gpin; 269 } 270 271 static void 272 twl_gpio_release(device_t dev, void *priv) 273 { 274 struct twl_softc * const sc = device_private(dev); 275 struct twl_pin *gpin = priv; 276 277 I2C_LOCK(sc); 278 twl_gpio_config(sc, gpin->pin_num, GPIO_PIN_INPUT); 279 I2C_UNLOCK(sc); 280 281 kmem_free(gpin, sizeof(*gpin)); 282 } 283 284 static int 285 twl_gpio_read(device_t dev, void *priv, bool raw) 286 { 287 struct twl_softc * const sc = device_private(dev); 288 struct twl_pin *gpin = priv; 289 uint8_t gpio; 290 int val; 291 292 I2C_LOCK(sc); 293 gpio = INT_READ(sc, GPIODATAIN(gpin->pin_num)); 294 I2C_UNLOCK(sc); 295 296 val = __SHIFTOUT(gpio, PIN_BIT(gpin->pin_num)); 297 if (!raw && gpin->pin_actlo) 298 val = !val; 299 300 return val; 301 } 302 303 static void 304 twl_gpio_write(device_t dev, void *priv, int val, bool raw) 305 { 306 struct twl_softc * const sc = device_private(dev); 307 struct twl_pin *gpin = priv; 308 309 if (!raw && gpin->pin_actlo) 310 val = !val; 311 312 I2C_LOCK(sc); 313 if (val) 314 INT_WRITE(sc, SETGPIODATAOUT(gpin->pin_num), PIN_BIT(gpin->pin_num)); 315 else 316 INT_WRITE(sc, CLEARGPIODATAOUT(gpin->pin_num), PIN_BIT(gpin->pin_num)); 317 I2C_UNLOCK(sc); 318 } 319 320 static struct fdtbus_gpio_controller_func twl_gpio_funcs = { 321 .acquire = twl_gpio_acquire, 322 .release = twl_gpio_release, 323 .read = twl_gpio_read, 324 .write = twl_gpio_write, 325 }; 326 #endif /* !FDT */ 327 328 static void 329 twl_rtc_attach(struct twl_softc *sc, const int phandle) 330 { 331 iic_acquire_bus(sc->sc_i2c, I2C_F_POLL); 332 twl_rtc_enable(sc, true); 333 iic_release_bus(sc->sc_i2c, I2C_F_POLL); 334 335 sc->sc_todr.todr_gettime_ymdhms = twl_rtc_gettime; 336 sc->sc_todr.todr_settime_ymdhms = twl_rtc_settime; 337 sc->sc_todr.cookie = sc; 338 #ifdef FDT 339 fdtbus_todr_attach(sc->sc_dev, phandle, &sc->sc_todr); 340 #else 341 todr_attach(&sc->sc_todr); 342 #endif 343 } 344 345 static void 346 twl_gpio_attach(struct twl_softc *sc, const int phandle) 347 { 348 #ifdef FDT 349 fdtbus_register_gpio_controller(sc->sc_dev, phandle, &twl_gpio_funcs); 350 #endif 351 } 352 353 static int 354 twl_match(device_t parent, cfdata_t match, void *aux) 355 { 356 struct i2c_attach_args *ia = aux; 357 int match_result; 358 359 if (iic_use_direct_match(ia, match, compat_data, &match_result)) 360 return match_result; 361 362 if (ia->ia_addr == 0x48) 363 return I2C_MATCH_ADDRESS_ONLY; 364 365 return 0; 366 } 367 368 static void 369 twl_attach(device_t parent, device_t self, void *aux) 370 { 371 struct twl_softc * const sc = device_private(self); 372 struct i2c_attach_args *ia = aux; 373 uint32_t idcode; 374 375 sc->sc_dev = self; 376 sc->sc_i2c = ia->ia_tag; 377 sc->sc_addr = ia->ia_addr; 378 sc->sc_phandle = ia->ia_cookie; 379 sc->sc_npins = TWL_PIN_COUNT; 380 381 aprint_naive("\n"); 382 aprint_normal(": TWL4030"); 383 384 #ifdef FDT 385 for (int child = OF_child(sc->sc_phandle); child; child = OF_peer(child)) { 386 if (of_match_compatible(child, gpio_compatible)) { 387 aprint_normal(", GPIO"); 388 twl_gpio_attach(sc, child); 389 } else if (of_match_compatible(child, rtc_compatible)) { 390 aprint_normal(", RTC"); 391 twl_rtc_attach(sc, child); 392 } 393 } 394 #else 395 aprint_normal("\n"); 396 twl_gpio_attach(sc, -1); 397 twl_rtc_attach(sc, -1); 398 #endif 399 400 I2C_LOCK(sc); 401 idcode = INT_READ(sc, IDCODE_7_0); 402 idcode |= (uint32_t)INT_READ(sc, IDCODE_15_8) << 8; 403 idcode |= (uint32_t)INT_READ(sc, IDCODE_23_16) << 16; 404 idcode |= (uint32_t)INT_READ(sc, IDCODE_31_24) << 24; 405 I2C_UNLOCK(sc); 406 407 aprint_normal(", IDCODE 0x%08x\n", idcode); 408 } 409 410 CFATTACH_DECL_NEW(twl, sizeof(struct twl_softc), 411 twl_match, twl_attach, NULL, NULL); 412