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