twl4030.c revision 1.3.2.2 1 /* $NetBSD: twl4030.c,v 1.3.2.2 2019/11/27 13:46:45 martin 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.3.2.2 2019/11/27 13:46:45 martin 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