1 /* $NetBSD: exynos_i2c.c,v 1.25 2026/07/17 17:33:52 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Jared D. 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 30 #include "opt_exynos.h" 31 #include "opt_arm_debug.h" 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: exynos_i2c.c,v 1.25 2026/07/17 17:33:52 thorpej Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/bus.h> 38 #include <sys/device.h> 39 #include <sys/intr.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/kmem.h> 43 44 #include <arm/samsung/exynos_reg.h> 45 #include <arm/samsung/exynos_var.h> 46 #include <arm/samsung/exynos_intr.h> 47 48 #include <sys/gpio.h> 49 #include <dev/gpio/gpiovar.h> 50 51 #include <dev/i2c/i2cvar.h> 52 53 #include <dev/fdt/fdtvar.h> 54 55 struct exynos_i2c_softc { 56 device_t sc_dev; 57 bus_space_tag_t sc_bst; 58 bus_space_handle_t sc_bsh; 59 void * sc_ih; 60 struct clk * sc_clk; 61 62 struct fdtbus_pinctrl_pin *sc_sda; 63 struct fdtbus_pinctrl_pin *sc_scl; 64 bool sc_sda_is_output; 65 66 struct i2c_controller sc_ic; 67 kmutex_t sc_intr_lock; 68 kcondvar_t sc_intr_wait; 69 }; 70 71 static int exynos_i2c_intr(void *); 72 73 static int exynos_i2c_send_start(void *, int); 74 static int exynos_i2c_send_stop(void *, int); 75 static int exynos_i2c_initiate_xfer(void *, i2c_addr_t, int); 76 static int exynos_i2c_read_byte(void *, uint8_t *, int); 77 static int exynos_i2c_write_byte(void *, uint8_t , int); 78 79 static int exynos_i2c_wait(struct exynos_i2c_softc *, int); 80 81 82 static int exynos_i2c_match(device_t, cfdata_t, void *); 83 static void exynos_i2c_attach(device_t, device_t, void *); 84 85 CFATTACH_DECL_NEW(exynos_i2c, sizeof(struct exynos_i2c_softc), 86 exynos_i2c_match, exynos_i2c_attach, NULL, NULL); 87 88 #define I2C_WRITE(sc, reg, val) \ 89 bus_space_write_1((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 90 #define I2C_READ(sc, reg) \ 91 bus_space_read_1((sc)->sc_bst, (sc)->sc_bsh, (reg)) 92 93 #define IICCON 0x00 94 #define IICSTAT 0x04 95 #define IICADD 0x08 96 #define IICDS 0x0C 97 98 #define ACKENABLE (1<<7) 99 #define TXPRESCALE (1<<6) 100 #define INTENABLE (1<<5) 101 #define IRQPEND (1<<4) 102 #define PRESCALE (0x0f) 103 104 #define MODESELECT (3<<6) 105 #define BUSYSTART (1<<5) 106 #define BUSENABLE (1<<4) 107 #define ARBITRATION (1<<3) 108 #define SLAVESTATUS (1<<2) 109 #define ZEROSTATUS (1<<1) 110 #define LASTBIT (1<<0) 111 112 #define READBIT (1<<7) 113 114 static const struct device_compatible_entry compat_data[] = { 115 { .compat = "samsung,s3c2440-i2c" }, 116 DEVICE_COMPAT_EOL 117 }; 118 119 static int 120 exynos_i2c_match(device_t self, cfdata_t cf, void *aux) 121 { 122 struct fdt_attach_args * const faa = aux; 123 124 return of_compatible_match(faa->faa_phandle, compat_data); 125 } 126 127 static void 128 exynos_i2c_attach(device_t parent, device_t self, void *aux) 129 { 130 struct exynos_i2c_softc * const sc = device_private(self); 131 struct fdt_attach_args * const faa = aux; 132 const int phandle = faa->faa_phandle; 133 char intrstr[128]; 134 bus_addr_t addr; 135 bus_size_t size; 136 int error; 137 138 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 139 aprint_error(": couldn't get registers\n"); 140 return; 141 } 142 143 sc->sc_dev = self; 144 sc->sc_bst = faa->faa_bst; 145 error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 146 if (error) { 147 aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", addr, 148 error); 149 return; 150 } 151 152 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM); 153 cv_init(&sc->sc_intr_wait, device_xname(self)); 154 aprint_normal(" @ 0x%08x\n", (uint)addr); 155 156 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 157 aprint_error_dev(self, "failed to decode interrupt\n"); 158 return; 159 } 160 161 sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 162 FDT_INTR_MPSAFE, exynos_i2c_intr, sc, device_xname(self)); 163 if (sc->sc_ih == NULL) { 164 aprint_error_dev(self, "couldn't establish interrupt on %s\n", 165 intrstr); 166 return; 167 } 168 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 169 170 iic_tag_init(&sc->sc_ic); 171 sc->sc_ic.ic_cookie = sc; 172 sc->sc_ic.ic_send_start = exynos_i2c_send_start; 173 sc->sc_ic.ic_send_stop = exynos_i2c_send_stop; 174 sc->sc_ic.ic_initiate_xfer = exynos_i2c_initiate_xfer; 175 sc->sc_ic.ic_read_byte = exynos_i2c_read_byte; 176 sc->sc_ic.ic_write_byte = exynos_i2c_write_byte; 177 178 iicbus_attach(self, &sc->sc_ic); 179 } 180 181 static int 182 exynos_i2c_intr(void *priv) 183 { 184 struct exynos_i2c_softc * const sc = priv; 185 186 uint8_t istatus = I2C_READ(sc, IICCON); 187 if (!(istatus & IRQPEND)) 188 return 0; 189 istatus &= ~IRQPEND; 190 I2C_WRITE(sc, IICCON, istatus); 191 192 mutex_enter(&sc->sc_intr_lock); 193 cv_broadcast(&sc->sc_intr_wait); 194 mutex_exit(&sc->sc_intr_lock); 195 196 return 1; 197 } 198 199 static int 200 exynos_i2c_wait(struct exynos_i2c_softc *sc, int flags) 201 { 202 int error, retry; 203 uint8_t stat = 0; 204 205 retry = (flags & I2C_F_POLL) ? 100000 : 100; 206 207 while (--retry > 0) { 208 if ((flags & I2C_F_POLL) == 0) { 209 error = cv_timedwait_sig(&sc->sc_intr_wait, 210 &sc->sc_intr_lock, 211 uimax(mstohz(10), 1)); 212 if (error) { 213 return error; 214 } 215 } 216 stat = I2C_READ(sc, IICSTAT); 217 if (!(stat & BUSYSTART)) { 218 break; 219 } 220 if (flags & I2C_F_POLL) { 221 delay(10); 222 } 223 } 224 if (retry == 0) { 225 stat = I2C_READ(sc, IICSTAT); 226 device_printf(sc->sc_dev, "timed out, status = %#x\n", stat); 227 return ETIMEDOUT; 228 } 229 230 return 0; 231 } 232 233 234 static int 235 exynos_i2c_send_start_locked(struct exynos_i2c_softc *sc, int flags) 236 { 237 I2C_WRITE(sc, IICSTAT, 0xF0); 238 return 0; 239 } 240 241 static int 242 exynos_i2c_send_stop_locked(struct exynos_i2c_softc *sc, int flags) 243 { 244 I2C_WRITE(sc, IICSTAT, 0xD0); 245 return 0; 246 } 247 248 static int 249 exynos_i2c_write_byte_locked(struct exynos_i2c_softc *sc, uint8_t byte, 250 int flags) 251 { 252 int error = exynos_i2c_wait(sc, flags); 253 if (error) { 254 return error; 255 } 256 I2C_WRITE(sc, IICDS, byte); 257 return 0; 258 } 259 260 static int 261 exynos_i2c_send_start(void *cookie, int flags) 262 { 263 struct exynos_i2c_softc *sc = cookie; 264 265 mutex_enter(&sc->sc_intr_lock); 266 int error = exynos_i2c_send_start_locked(sc, flags); 267 mutex_exit(&sc->sc_intr_lock); 268 return error; 269 } 270 271 static int 272 exynos_i2c_send_stop(void *cookie, int flags) 273 { 274 struct exynos_i2c_softc *sc = cookie; 275 276 mutex_enter(&sc->sc_intr_lock); 277 int error = exynos_i2c_send_stop_locked(sc, flags); 278 mutex_exit(&sc->sc_intr_lock); 279 return error; 280 } 281 282 static int 283 exynos_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 284 { 285 struct exynos_i2c_softc *sc = cookie; 286 uint8_t byte = addr & 0x7f; 287 int error; 288 289 if (flags & I2C_F_READ) 290 byte |= READBIT; 291 else 292 byte &= ~READBIT; 293 294 mutex_enter(&sc->sc_intr_lock); 295 I2C_WRITE(sc, IICADD, addr); 296 exynos_i2c_send_start_locked(sc, flags); 297 exynos_i2c_write_byte_locked(sc, byte, flags); 298 error = exynos_i2c_wait(cookie, flags); 299 mutex_exit(&sc->sc_intr_lock); 300 301 return error; 302 } 303 304 static int 305 exynos_i2c_read_byte(void *cookie, uint8_t *bytep, int flags) 306 { 307 struct exynos_i2c_softc *sc = cookie; 308 309 mutex_enter(&sc->sc_intr_lock); 310 int error = exynos_i2c_wait(sc, flags); 311 if (error) { 312 mutex_exit(&sc->sc_intr_lock); 313 return error; 314 } 315 *bytep = I2C_READ(sc, IICDS) & 0xff; 316 if (flags & I2C_F_STOP) 317 exynos_i2c_send_stop_locked(sc, flags); 318 mutex_exit(&sc->sc_intr_lock); 319 return 0; 320 } 321 322 static int 323 exynos_i2c_write_byte(void *cookie, uint8_t byte, int flags) 324 { 325 struct exynos_i2c_softc *sc = cookie; 326 327 mutex_enter(&sc->sc_intr_lock); 328 int error = exynos_i2c_write_byte_locked(sc, byte, flags); 329 mutex_exit(&sc->sc_intr_lock); 330 return error; 331 } 332