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