exynos_i2c.c revision 1.8 1 1.8 marty /* $NetBSD: exynos_i2c.c,v 1.8 2015/12/24 21:30:05 marty Exp $ */
2 1.1 reinoud
3 1.1 reinoud /*
4 1.1 reinoud * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 1.1 reinoud * All rights reserved.
6 1.1 reinoud *
7 1.1 reinoud * This code is derived from software contributed to The NetBSD Foundation
8 1.1 reinoud * by Reinoud Zandijk.
9 1.1 reinoud *
10 1.1 reinoud * Redistribution and use in source and binary forms, with or without
11 1.1 reinoud * modification, are permitted provided that the following conditions
12 1.1 reinoud * are met:
13 1.1 reinoud * 1. Redistributions of source code must retain the above copyright
14 1.1 reinoud * notice, this list of conditions and the following disclaimer.
15 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 reinoud * notice, this list of conditions and the following disclaimer in the
17 1.1 reinoud * documentation and/or other materials provided with the distribution.
18 1.1 reinoud *
19 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 reinoud * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 reinoud * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 reinoud * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 reinoud * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 reinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 reinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 reinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 reinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 reinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 reinoud * POSSIBILITY OF SUCH DAMAGE.
30 1.1 reinoud *
31 1.1 reinoud */
32 1.1 reinoud
33 1.1 reinoud #include "opt_exynos.h"
34 1.1 reinoud #include "opt_arm_debug.h"
35 1.1 reinoud
36 1.1 reinoud #include <sys/cdefs.h>
37 1.8 marty __KERNEL_RCSID(0, "$NetBSD: exynos_i2c.c,v 1.8 2015/12/24 21:30:05 marty Exp $");
38 1.1 reinoud
39 1.1 reinoud #include <sys/param.h>
40 1.1 reinoud #include <sys/bus.h>
41 1.1 reinoud #include <sys/device.h>
42 1.1 reinoud #include <sys/intr.h>
43 1.1 reinoud #include <sys/systm.h>
44 1.1 reinoud #include <sys/kmem.h>
45 1.1 reinoud
46 1.1 reinoud #include <arm/samsung/exynos_reg.h>
47 1.1 reinoud #include <arm/samsung/exynos_intr.h>
48 1.1 reinoud
49 1.1 reinoud #include <sys/gpio.h>
50 1.1 reinoud #include <dev/gpio/gpiovar.h>
51 1.1 reinoud
52 1.1 reinoud #include <dev/i2c/i2cvar.h>
53 1.1 reinoud #include <dev/i2c/i2c_bitbang.h>
54 1.1 reinoud
55 1.5 marty #include <dev/fdt/fdtvar.h>
56 1.1 reinoud
57 1.5 marty struct exynos_i2c_softc {
58 1.5 marty device_t sc_dev;
59 1.5 marty bus_space_tag_t sc_bst;
60 1.5 marty bus_space_handle_t sc_bsh;
61 1.5 marty void * sc_ih;
62 1.5 marty u_int sc_port;
63 1.5 marty
64 1.8 marty struct fdtbus_gpio_pin *sc_sda;
65 1.8 marty struct fdtbus_gpio_pin *sc_scl;
66 1.5 marty bool sc_sda_is_output;
67 1.5 marty struct i2c_controller sc_ic;
68 1.5 marty kmutex_t sc_lock;
69 1.5 marty kcondvar_t sc_cv;
70 1.5 marty device_t sc_i2cdev;
71 1.1 reinoud };
72 1.1 reinoud
73 1.5 marty static u_int i2c_port;
74 1.1 reinoud
75 1.5 marty static int exynos_i2c_intr(void *);
76 1.1 reinoud
77 1.5 marty static int exynos_i2c_acquire_bus(void *, int);
78 1.5 marty static void exynos_i2c_release_bus(void *, int);
79 1.1 reinoud
80 1.5 marty static int exynos_i2c_send_start(void *, int);
81 1.5 marty static int exynos_i2c_send_stop(void *, int);
82 1.5 marty static int exynos_i2c_initiate_xfer(void *, i2c_addr_t, int);
83 1.5 marty static int exynos_i2c_read_byte(void *, uint8_t *, int);
84 1.5 marty static int exynos_i2c_write_byte(void *, uint8_t , int);
85 1.1 reinoud
86 1.5 marty static bool exynos_i2c_attach_i2cbus(struct exynos_i2c_softc *,
87 1.5 marty struct i2c_controller *);
88 1.1 reinoud
89 1.5 marty static int exynos_i2c_match(device_t, cfdata_t, void *);
90 1.5 marty static void exynos_i2c_attach(device_t, device_t, void *);
91 1.1 reinoud
92 1.5 marty CFATTACH_DECL_NEW(exynos_i2c, sizeof(struct exynos_i2c_softc),
93 1.5 marty exynos_i2c_match, exynos_i2c_attach, NULL, NULL);
94 1.1 reinoud
95 1.8 marty #define I2C_WRITE(sc, reg, val) \
96 1.8 marty bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
97 1.8 marty #define I2C_READ(sc, reg) \
98 1.8 marty bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
99 1.8 marty
100 1.8 marty #define IICON 0
101 1.8 marty #define IRQPEND (1<<4)
102 1.8 marty
103 1.1 reinoud static int
104 1.5 marty exynos_i2c_match(device_t self, cfdata_t cf, void *aux)
105 1.1 reinoud {
106 1.5 marty const char * const compatible[] = { "samsung,s3c2440-i2c", NULL };
107 1.5 marty struct fdt_attach_args * const faa = aux;
108 1.1 reinoud
109 1.5 marty return of_match_compatible(faa->faa_phandle, compatible);
110 1.1 reinoud }
111 1.1 reinoud
112 1.1 reinoud static void
113 1.5 marty exynos_i2c_attach(device_t parent, device_t self, void *aux)
114 1.1 reinoud {
115 1.5 marty struct exynos_i2c_softc * const sc = device_private(self);
116 1.5 marty struct fdt_attach_args * const faa = aux;
117 1.5 marty const int phandle = faa->faa_phandle;
118 1.1 reinoud struct i2cbus_attach_args iba;
119 1.5 marty
120 1.5 marty char intrstr[128];
121 1.5 marty bus_addr_t addr;
122 1.5 marty bus_size_t size;
123 1.5 marty int error;
124 1.5 marty
125 1.8 marty char result[64];
126 1.8 marty int i2c_handle;
127 1.8 marty int len;
128 1.8 marty int handle;
129 1.8 marty int func /*, pud, drv */;
130 1.8 marty
131 1.5 marty if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
132 1.5 marty aprint_error(": couldn't get registers\n");
133 1.5 marty return;
134 1.5 marty }
135 1.5 marty
136 1.1 reinoud
137 1.1 reinoud sc->sc_dev = self;
138 1.5 marty sc->sc_bst = faa->faa_bst;
139 1.5 marty error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
140 1.5 marty if (error) {
141 1.5 marty aprint_error(": couldn't map %#llx: %d", (uint64_t)addr,
142 1.5 marty error);
143 1.1 reinoud return;
144 1.1 reinoud }
145 1.1 reinoud
146 1.5 marty sc->sc_port = i2c_port++;
147 1.5 marty mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
148 1.5 marty cv_init(&sc->sc_cv, device_xname(self));
149 1.8 marty aprint_normal(" @ 0x%08x\n", (uint)addr);
150 1.1 reinoud
151 1.5 marty if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
152 1.5 marty aprint_error_dev(self, "failed to decode interrupt\n");
153 1.5 marty return;
154 1.1 reinoud }
155 1.5 marty
156 1.5 marty sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM,
157 1.5 marty FDT_INTR_MPSAFE, exynos_i2c_intr, sc);
158 1.5 marty if (sc->sc_ih == NULL) {
159 1.5 marty aprint_error_dev(self, "couldn't establish interrupt on %s\n",
160 1.5 marty intrstr);
161 1.5 marty return;
162 1.5 marty }
163 1.5 marty aprint_normal_dev(self, "interrupting on %s\n", intrstr);
164 1.5 marty
165 1.8 marty len = OF_getprop(phandle, "pinctrl-0", (char *)&handle,
166 1.8 marty sizeof(handle));
167 1.8 marty if (len != sizeof(int)) {
168 1.8 marty aprint_error_dev(self, "couldn't get pinctrl-0.\n");
169 1.8 marty return;
170 1.8 marty }
171 1.8 marty
172 1.8 marty i2c_handle = fdtbus_get_phandle_from_native(be32toh(handle));
173 1.8 marty len = OF_getprop(i2c_handle, "samsung,pins", result, sizeof(result));
174 1.8 marty if (len <= 0) {
175 1.8 marty aprint_error_dev(self, "couldn't get pins.\n");
176 1.8 marty return;
177 1.8 marty }
178 1.8 marty
179 1.8 marty len = OF_getprop(i2c_handle, "samsung,pin-function",
180 1.8 marty &handle, sizeof(handle));
181 1.8 marty if (len <= 0) {
182 1.8 marty aprint_error_dev(self, "couldn't get pin-function.\n");
183 1.8 marty return;
184 1.8 marty } else
185 1.8 marty func = be32toh(handle);
186 1.8 marty
187 1.8 marty sc->sc_sda = fdtbus_gpio_acquire(phandle, &result[0], func);
188 1.8 marty sc->sc_scl = fdtbus_gpio_acquire(phandle, &result[7], func);
189 1.8 marty
190 1.8 marty /* MJF: Need fdtbus_gpio_configure */
191 1.8 marty #if 0
192 1.8 marty len = OF_getprop(i2c_handle, "samsung,pin-pud", &handle,
193 1.8 marty sizeof(&handle));
194 1.8 marty if (len <= 0) {
195 1.8 marty aprint_error_dev(self, "couldn't get pin-pud.\n");
196 1.8 marty return;
197 1.8 marty } else
198 1.8 marty pud = be32toh(handle);
199 1.8 marty
200 1.8 marty len = OF_getprop(i2c_handle, "samsung,pin-drv", &handle,
201 1.8 marty sizeof(&handle));
202 1.8 marty if (len <= 0) {
203 1.8 marty aprint_error_dev(self, "couldn't get pin-drv.\n");
204 1.8 marty return;
205 1.8 marty } else
206 1.8 marty drv = be32toh(handle);
207 1.8 marty
208 1.8 marty #endif
209 1.5 marty if (!exynos_i2c_attach_i2cbus(sc, &sc->sc_ic))
210 1.5 marty return;
211 1.5 marty
212 1.5 marty sc->sc_i2cdev = config_found_ia(self, "i2cbus", &iba, iicbus_print);
213 1.5 marty
214 1.1 reinoud }
215 1.1 reinoud
216 1.1 reinoud static bool
217 1.5 marty exynos_i2c_attach_i2cbus(struct exynos_i2c_softc *i2c_sc,
218 1.5 marty struct i2c_controller *i2c_cntr)
219 1.1 reinoud {
220 1.5 marty i2c_cntr->ic_cookie = i2c_sc;
221 1.5 marty i2c_cntr->ic_acquire_bus = exynos_i2c_acquire_bus;
222 1.5 marty i2c_cntr->ic_release_bus = exynos_i2c_release_bus;
223 1.5 marty i2c_cntr->ic_send_start = exynos_i2c_send_start;
224 1.5 marty i2c_cntr->ic_send_stop = exynos_i2c_send_stop;
225 1.5 marty i2c_cntr->ic_initiate_xfer = exynos_i2c_initiate_xfer;
226 1.5 marty i2c_cntr->ic_read_byte = exynos_i2c_read_byte;
227 1.5 marty i2c_cntr->ic_write_byte = exynos_i2c_write_byte;
228 1.3 skrll
229 1.5 marty return 1;
230 1.1 reinoud }
231 1.1 reinoud
232 1.5 marty #define EXYNOS_I2C_BB_SDA __BIT(1)
233 1.5 marty #define EXYNOS_I2C_BB_SCL __BIT(2)
234 1.5 marty #define EXYNOS_I2C_BB_SDA_OUT __BIT(3)
235 1.5 marty #define EXYNOS_I2C_BB_SDA_IN 0
236 1.1 reinoud
237 1.1 reinoud static void
238 1.5 marty exynos_i2c_bb_set_bits(void *cookie, uint32_t bits)
239 1.1 reinoud {
240 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
241 1.8 marty int sda, scl;
242 1.1 reinoud
243 1.5 marty sda = (bits & EXYNOS_I2C_BB_SDA) ? true : false;
244 1.8 marty scl = (bits & EXYNOS_I2C_BB_SCL) ? true : false;
245 1.1 reinoud
246 1.5 marty if (i2c_sc->sc_sda_is_output)
247 1.8 marty fdtbus_gpio_write(i2c_sc->sc_sda, sda);
248 1.8 marty fdtbus_gpio_write(i2c_sc->sc_scl, scl);
249 1.1 reinoud }
250 1.1 reinoud
251 1.1 reinoud static uint32_t
252 1.5 marty exynos_i2c_bb_read_bits(void *cookie)
253 1.1 reinoud {
254 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
255 1.8 marty int sda, scl;
256 1.1 reinoud
257 1.1 reinoud sda = 0;
258 1.5 marty if (!i2c_sc->sc_sda_is_output)
259 1.8 marty sda = fdtbus_gpio_read(i2c_sc->sc_sda);
260 1.8 marty scl = fdtbus_gpio_read(i2c_sc->sc_scl);
261 1.1 reinoud
262 1.8 marty return (sda ? EXYNOS_I2C_BB_SDA : 0) | (scl ? EXYNOS_I2C_BB_SCL : 0);
263 1.1 reinoud }
264 1.1 reinoud
265 1.1 reinoud static void
266 1.5 marty exynos_i2c_bb_set_dir(void *cookie, uint32_t bits)
267 1.1 reinoud {
268 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
269 1.1 reinoud int flags;
270 1.1 reinoud
271 1.1 reinoud flags = GPIO_PIN_INPUT | GPIO_PIN_TRISTATE;
272 1.5 marty i2c_sc->sc_sda_is_output = ((bits & EXYNOS_I2C_BB_SDA_OUT) != 0);
273 1.5 marty if (i2c_sc->sc_sda_is_output)
274 1.1 reinoud flags = GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE;
275 1.1 reinoud
276 1.5 marty /* MJF: This is wrong but fdtbus has no ctrl operation */
277 1.8 marty fdtbus_gpio_write(i2c_sc->sc_sda, flags);
278 1.1 reinoud }
279 1.1 reinoud
280 1.5 marty static const struct i2c_bitbang_ops exynos_i2c_bbops = {
281 1.5 marty exynos_i2c_bb_set_bits,
282 1.5 marty exynos_i2c_bb_set_dir,
283 1.5 marty exynos_i2c_bb_read_bits,
284 1.1 reinoud {
285 1.5 marty EXYNOS_I2C_BB_SDA,
286 1.5 marty EXYNOS_I2C_BB_SCL,
287 1.5 marty EXYNOS_I2C_BB_SDA_OUT,
288 1.5 marty EXYNOS_I2C_BB_SDA_IN,
289 1.1 reinoud }
290 1.1 reinoud };
291 1.1 reinoud
292 1.5 marty static int
293 1.5 marty exynos_i2c_intr(void *priv)
294 1.5 marty {
295 1.5 marty struct exynos_i2c_softc * const sc = priv;
296 1.5 marty
297 1.8 marty uint32_t istatus = I2C_READ(sc, IICON);
298 1.8 marty if (!(istatus & IRQPEND))
299 1.8 marty return 0;
300 1.8 marty istatus &= ~IRQPEND;
301 1.8 marty I2C_WRITE(sc, IICON, istatus);
302 1.5 marty
303 1.5 marty mutex_enter(&sc->sc_lock);
304 1.5 marty cv_broadcast(&sc->sc_cv);
305 1.5 marty mutex_exit(&sc->sc_lock);
306 1.5 marty
307 1.5 marty return 1;
308 1.5 marty }
309 1.1 reinoud
310 1.1 reinoud static int
311 1.5 marty exynos_i2c_acquire_bus(void *cookie, int flags)
312 1.1 reinoud {
313 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
314 1.1 reinoud
315 1.1 reinoud /* XXX what to do in polling case? could another cpu help */
316 1.1 reinoud if (flags & I2C_F_POLL)
317 1.1 reinoud return 0;
318 1.5 marty mutex_enter(&i2c_sc->sc_lock);
319 1.1 reinoud return 0;
320 1.1 reinoud }
321 1.1 reinoud
322 1.1 reinoud static void
323 1.5 marty exynos_i2c_release_bus(void *cookie, int flags)
324 1.1 reinoud {
325 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
326 1.1 reinoud
327 1.1 reinoud /* XXX what to do in polling case? could another cpu help */
328 1.1 reinoud if (flags & I2C_F_POLL)
329 1.1 reinoud return;
330 1.5 marty mutex_exit(&i2c_sc->sc_lock);
331 1.1 reinoud }
332 1.1 reinoud
333 1.1 reinoud static int
334 1.5 marty exynos_i2c_send_start(void *cookie, int flags)
335 1.1 reinoud {
336 1.5 marty return i2c_bitbang_send_start(cookie, flags, &exynos_i2c_bbops);
337 1.1 reinoud }
338 1.1 reinoud
339 1.3 skrll static int
340 1.5 marty exynos_i2c_send_stop(void *cookie, int flags)
341 1.1 reinoud {
342 1.5 marty return i2c_bitbang_send_stop(cookie, flags, &exynos_i2c_bbops);
343 1.1 reinoud }
344 1.1 reinoud
345 1.3 skrll static int
346 1.5 marty exynos_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
347 1.1 reinoud {
348 1.5 marty return i2c_bitbang_initiate_xfer(cookie, addr, flags,
349 1.5 marty &exynos_i2c_bbops);
350 1.1 reinoud }
351 1.1 reinoud
352 1.1 reinoud static int
353 1.5 marty exynos_i2c_read_byte(void *cookie, uint8_t *bytep, int flags)
354 1.1 reinoud {
355 1.5 marty return i2c_bitbang_read_byte(cookie, bytep, flags,
356 1.5 marty &exynos_i2c_bbops);
357 1.1 reinoud }
358 1.1 reinoud
359 1.3 skrll static int
360 1.5 marty exynos_i2c_write_byte(void *cookie, uint8_t byte, int flags)
361 1.1 reinoud {
362 1.5 marty return i2c_bitbang_write_byte(cookie, byte, flags,
363 1.5 marty &exynos_i2c_bbops);
364 1.1 reinoud }
365