exynos_i2c.c revision 1.5 1 1.5 marty /* $NetBSD: exynos_i2c.c,v 1.5 2015/12/21 00:52:50 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 #include "exynos_iic.h"
36 1.1 reinoud
37 1.1 reinoud #include <sys/cdefs.h>
38 1.5 marty __KERNEL_RCSID(0, "$NetBSD: exynos_i2c.c,v 1.5 2015/12/21 00:52:50 marty Exp $");
39 1.1 reinoud
40 1.1 reinoud #include <sys/param.h>
41 1.1 reinoud #include <sys/bus.h>
42 1.1 reinoud #include <sys/device.h>
43 1.1 reinoud #include <sys/intr.h>
44 1.1 reinoud #include <sys/systm.h>
45 1.1 reinoud #include <sys/kmem.h>
46 1.1 reinoud
47 1.1 reinoud #include <arm/samsung/exynos_reg.h>
48 1.1 reinoud #include <arm/samsung/exynos_io.h>
49 1.1 reinoud #include <arm/samsung/exynos_intr.h>
50 1.1 reinoud
51 1.1 reinoud #include <sys/gpio.h>
52 1.1 reinoud #include <dev/gpio/gpiovar.h>
53 1.1 reinoud
54 1.1 reinoud #include <dev/i2c/i2cvar.h>
55 1.1 reinoud #include <dev/i2c/i2c_bitbang.h>
56 1.1 reinoud
57 1.5 marty #include <dev/fdt/fdtvar.h>
58 1.1 reinoud
59 1.5 marty struct exynos_i2c_softc {
60 1.5 marty device_t sc_dev;
61 1.5 marty bus_space_tag_t sc_bst;
62 1.5 marty bus_space_handle_t sc_bsh;
63 1.5 marty void * sc_ih;
64 1.5 marty u_int sc_port;
65 1.5 marty
66 1.5 marty struct fdtbus_gpio_pin sc_sda;
67 1.5 marty struct fdtbus_gpio_pin sc_slc;
68 1.5 marty bool sc_sda_is_output;
69 1.5 marty struct i2c_controller sc_ic;
70 1.5 marty kmutex_t sc_lock;
71 1.5 marty kcondvar_t sc_cv;
72 1.5 marty device_t sc_i2cdev;
73 1.1 reinoud };
74 1.1 reinoud
75 1.5 marty static u_int i2c_port;
76 1.1 reinoud
77 1.5 marty static int exynos_i2c_intr(void *);
78 1.1 reinoud
79 1.5 marty static int exynos_i2c_acquire_bus(void *, int);
80 1.5 marty static void exynos_i2c_release_bus(void *, int);
81 1.1 reinoud
82 1.5 marty static int exynos_i2c_send_start(void *, int);
83 1.5 marty static int exynos_i2c_send_stop(void *, int);
84 1.5 marty static int exynos_i2c_initiate_xfer(void *, i2c_addr_t, int);
85 1.5 marty static int exynos_i2c_read_byte(void *, uint8_t *, int);
86 1.5 marty static int exynos_i2c_write_byte(void *, uint8_t , int);
87 1.1 reinoud
88 1.5 marty static bool exynos_i2c_attach_i2cbus(struct exynos_i2c_softc *,
89 1.5 marty struct i2c_controller *);
90 1.1 reinoud
91 1.5 marty static int exynos_i2c_match(device_t, cfdata_t, void *);
92 1.5 marty static void exynos_i2c_attach(device_t, device_t, void *);
93 1.1 reinoud
94 1.5 marty CFATTACH_DECL_NEW(exynos_i2c, sizeof(struct exynos_i2c_softc),
95 1.5 marty exynos_i2c_match, exynos_i2c_attach, NULL, NULL);
96 1.1 reinoud
97 1.1 reinoud static int
98 1.5 marty exynos_i2c_match(device_t self, cfdata_t cf, void *aux)
99 1.1 reinoud {
100 1.5 marty const char * const compatible[] = { "samsung,s3c2440-i2c", NULL };
101 1.5 marty struct fdt_attach_args * const faa = aux;
102 1.1 reinoud
103 1.5 marty return of_match_compatible(faa->faa_phandle, compatible);
104 1.1 reinoud }
105 1.1 reinoud
106 1.1 reinoud static void
107 1.5 marty exynos_i2c_attach(device_t parent, device_t self, void *aux)
108 1.1 reinoud {
109 1.5 marty struct exynos_i2c_softc * const sc = device_private(self);
110 1.5 marty struct fdt_attach_args * const faa = aux;
111 1.5 marty const int phandle = faa->faa_phandle;
112 1.1 reinoud struct i2cbus_attach_args iba;
113 1.5 marty
114 1.5 marty char intrstr[128];
115 1.5 marty bus_addr_t addr;
116 1.5 marty bus_size_t size;
117 1.5 marty int error;
118 1.5 marty
119 1.5 marty if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
120 1.5 marty aprint_error(": couldn't get registers\n");
121 1.5 marty return;
122 1.5 marty }
123 1.5 marty
124 1.1 reinoud
125 1.1 reinoud sc->sc_dev = self;
126 1.5 marty sc->sc_bst = faa->faa_bst;
127 1.5 marty error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
128 1.5 marty if (error) {
129 1.5 marty aprint_error(": couldn't map %#llx: %d", (uint64_t)addr,
130 1.5 marty error);
131 1.1 reinoud return;
132 1.1 reinoud }
133 1.1 reinoud
134 1.5 marty sc->sc_port = i2c_port++;
135 1.5 marty mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
136 1.5 marty cv_init(&sc->sc_cv, device_xname(self));
137 1.5 marty aprint_normal(" @ 0x%08x", (uint)addr);
138 1.1 reinoud
139 1.5 marty if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
140 1.5 marty aprint_error_dev(self, "failed to decode interrupt\n");
141 1.5 marty return;
142 1.1 reinoud }
143 1.5 marty
144 1.5 marty sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM,
145 1.5 marty FDT_INTR_MPSAFE, exynos_i2c_intr, sc);
146 1.5 marty if (sc->sc_ih == NULL) {
147 1.5 marty aprint_error_dev(self, "couldn't establish interrupt on %s\n",
148 1.5 marty intrstr);
149 1.5 marty return;
150 1.5 marty }
151 1.5 marty aprint_normal_dev(self, "interrupting on %s\n", intrstr);
152 1.5 marty
153 1.5 marty if (!exynos_i2c_attach_i2cbus(sc, &sc->sc_ic))
154 1.5 marty return;
155 1.5 marty
156 1.5 marty sc->sc_i2cdev = config_found_ia(self, "i2cbus", &iba, iicbus_print);
157 1.5 marty
158 1.1 reinoud }
159 1.1 reinoud
160 1.1 reinoud static bool
161 1.5 marty exynos_i2c_attach_i2cbus(struct exynos_i2c_softc *i2c_sc,
162 1.5 marty struct i2c_controller *i2c_cntr)
163 1.1 reinoud {
164 1.5 marty i2c_cntr->ic_cookie = i2c_sc;
165 1.5 marty i2c_cntr->ic_acquire_bus = exynos_i2c_acquire_bus;
166 1.5 marty i2c_cntr->ic_release_bus = exynos_i2c_release_bus;
167 1.5 marty i2c_cntr->ic_send_start = exynos_i2c_send_start;
168 1.5 marty i2c_cntr->ic_send_stop = exynos_i2c_send_stop;
169 1.5 marty i2c_cntr->ic_initiate_xfer = exynos_i2c_initiate_xfer;
170 1.5 marty i2c_cntr->ic_read_byte = exynos_i2c_read_byte;
171 1.5 marty i2c_cntr->ic_write_byte = exynos_i2c_write_byte;
172 1.3 skrll
173 1.5 marty /*MJF: FIX ME needs gpio pins */
174 1.4 marty // exynos_gpio_pinset_acquire(pinset);
175 1.5 marty return 1;
176 1.1 reinoud }
177 1.1 reinoud
178 1.5 marty #define EXYNOS_I2C_BB_SDA __BIT(1)
179 1.5 marty #define EXYNOS_I2C_BB_SCL __BIT(2)
180 1.5 marty #define EXYNOS_I2C_BB_SDA_OUT __BIT(3)
181 1.5 marty #define EXYNOS_I2C_BB_SDA_IN 0
182 1.1 reinoud
183 1.1 reinoud static void
184 1.5 marty exynos_i2c_bb_set_bits(void *cookie, uint32_t bits)
185 1.1 reinoud {
186 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
187 1.1 reinoud int sda, slc;
188 1.1 reinoud
189 1.5 marty sda = (bits & EXYNOS_I2C_BB_SDA) ? true : false;
190 1.5 marty slc = (bits & EXYNOS_I2C_BB_SCL) ? true : false;
191 1.1 reinoud
192 1.5 marty if (i2c_sc->sc_sda_is_output)
193 1.5 marty fdtbus_gpio_write(&i2c_sc->sc_sda, sda);
194 1.5 marty fdtbus_gpio_write(&i2c_sc->sc_slc, slc);
195 1.1 reinoud }
196 1.1 reinoud
197 1.1 reinoud static uint32_t
198 1.5 marty exynos_i2c_bb_read_bits(void *cookie)
199 1.1 reinoud {
200 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
201 1.1 reinoud int sda, slc;
202 1.1 reinoud
203 1.1 reinoud sda = 0;
204 1.5 marty if (!i2c_sc->sc_sda_is_output)
205 1.5 marty sda = fdtbus_gpio_read(&i2c_sc->sc_sda);
206 1.5 marty slc = fdtbus_gpio_read(&i2c_sc->sc_slc);
207 1.1 reinoud
208 1.5 marty return (sda ? EXYNOS_I2C_BB_SDA : 0) | (slc ? EXYNOS_I2C_BB_SCL : 0);
209 1.1 reinoud }
210 1.1 reinoud
211 1.1 reinoud static void
212 1.5 marty exynos_i2c_bb_set_dir(void *cookie, uint32_t bits)
213 1.1 reinoud {
214 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
215 1.1 reinoud int flags;
216 1.1 reinoud
217 1.1 reinoud flags = GPIO_PIN_INPUT | GPIO_PIN_TRISTATE;
218 1.5 marty i2c_sc->sc_sda_is_output = ((bits & EXYNOS_I2C_BB_SDA_OUT) != 0);
219 1.5 marty if (i2c_sc->sc_sda_is_output)
220 1.1 reinoud flags = GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE;
221 1.1 reinoud
222 1.5 marty /* MJF: This is wrong but fdtbus has no ctrl operation */
223 1.5 marty fdtbus_gpio_write(&i2c_sc->sc_sda, flags);
224 1.1 reinoud }
225 1.1 reinoud
226 1.5 marty static const struct i2c_bitbang_ops exynos_i2c_bbops = {
227 1.5 marty exynos_i2c_bb_set_bits,
228 1.5 marty exynos_i2c_bb_set_dir,
229 1.5 marty exynos_i2c_bb_read_bits,
230 1.1 reinoud {
231 1.5 marty EXYNOS_I2C_BB_SDA,
232 1.5 marty EXYNOS_I2C_BB_SCL,
233 1.5 marty EXYNOS_I2C_BB_SDA_OUT,
234 1.5 marty EXYNOS_I2C_BB_SDA_IN,
235 1.1 reinoud }
236 1.1 reinoud };
237 1.1 reinoud
238 1.5 marty static int
239 1.5 marty exynos_i2c_intr(void *priv)
240 1.5 marty {
241 1.5 marty struct exynos_i2c_softc * const sc = priv;
242 1.5 marty
243 1.5 marty // const uint32_t istatus = I2C_READ(sc, I2C_INTERRUPT_STATUS_REG);
244 1.5 marty // if (istatus == 0)
245 1.5 marty // return 0;
246 1.5 marty // I2C_WRITE(sc, I2C_INTERRUPT_STATUS_REG, istatus);
247 1.5 marty
248 1.5 marty mutex_enter(&sc->sc_lock);
249 1.5 marty cv_broadcast(&sc->sc_cv);
250 1.5 marty mutex_exit(&sc->sc_lock);
251 1.5 marty
252 1.5 marty return 1;
253 1.5 marty }
254 1.1 reinoud
255 1.1 reinoud static int
256 1.5 marty exynos_i2c_acquire_bus(void *cookie, int flags)
257 1.1 reinoud {
258 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
259 1.1 reinoud
260 1.1 reinoud /* XXX what to do in polling case? could another cpu help */
261 1.1 reinoud if (flags & I2C_F_POLL)
262 1.1 reinoud return 0;
263 1.5 marty mutex_enter(&i2c_sc->sc_lock);
264 1.1 reinoud return 0;
265 1.1 reinoud }
266 1.1 reinoud
267 1.1 reinoud static void
268 1.5 marty exynos_i2c_release_bus(void *cookie, int flags)
269 1.1 reinoud {
270 1.5 marty struct exynos_i2c_softc *i2c_sc = cookie;
271 1.1 reinoud
272 1.1 reinoud /* XXX what to do in polling case? could another cpu help */
273 1.1 reinoud if (flags & I2C_F_POLL)
274 1.1 reinoud return;
275 1.5 marty mutex_exit(&i2c_sc->sc_lock);
276 1.1 reinoud }
277 1.1 reinoud
278 1.1 reinoud static int
279 1.5 marty exynos_i2c_send_start(void *cookie, int flags)
280 1.1 reinoud {
281 1.5 marty return i2c_bitbang_send_start(cookie, flags, &exynos_i2c_bbops);
282 1.1 reinoud }
283 1.1 reinoud
284 1.3 skrll static int
285 1.5 marty exynos_i2c_send_stop(void *cookie, int flags)
286 1.1 reinoud {
287 1.5 marty return i2c_bitbang_send_stop(cookie, flags, &exynos_i2c_bbops);
288 1.1 reinoud }
289 1.1 reinoud
290 1.3 skrll static int
291 1.5 marty exynos_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
292 1.1 reinoud {
293 1.5 marty return i2c_bitbang_initiate_xfer(cookie, addr, flags,
294 1.5 marty &exynos_i2c_bbops);
295 1.1 reinoud }
296 1.1 reinoud
297 1.1 reinoud static int
298 1.5 marty exynos_i2c_read_byte(void *cookie, uint8_t *bytep, int flags)
299 1.1 reinoud {
300 1.5 marty return i2c_bitbang_read_byte(cookie, bytep, flags,
301 1.5 marty &exynos_i2c_bbops);
302 1.1 reinoud }
303 1.1 reinoud
304 1.3 skrll static int
305 1.5 marty exynos_i2c_write_byte(void *cookie, uint8_t byte, int flags)
306 1.1 reinoud {
307 1.5 marty return i2c_bitbang_write_byte(cookie, byte, flags,
308 1.5 marty &exynos_i2c_bbops);
309 1.1 reinoud }
310