1 1.11 thorpej /* $NetBSD: dwiic.c,v 1.11 2025/09/15 15:18:42 thorpej Exp $ */ 2 1.1 bouyer 3 1.4 jakllsch /* $OpenBSD: dwiic.c,v 1.4 2018/05/23 22:08:00 kettenis Exp $ */ 4 1.1 bouyer 5 1.1 bouyer /*- 6 1.1 bouyer * Copyright (c) 2017 The NetBSD Foundation, Inc. 7 1.1 bouyer * All rights reserved. 8 1.1 bouyer * 9 1.1 bouyer * This code is derived from software contributed to The NetBSD Foundation 10 1.1 bouyer * by Manuel Bouyer. 11 1.1 bouyer * 12 1.1 bouyer * Redistribution and use in source and binary forms, with or without 13 1.1 bouyer * modification, are permitted provided that the following conditions 14 1.1 bouyer * are met: 15 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 16 1.1 bouyer * notice, this list of conditions and the following disclaimer. 17 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 19 1.1 bouyer * documentation and/or other materials provided with the distribution. 20 1.1 bouyer * 21 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 1.1 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 1.1 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 bouyer * POSSIBILITY OF SUCH DAMAGE. 32 1.1 bouyer */ 33 1.1 bouyer /* 34 1.1 bouyer * Synopsys DesignWare I2C controller 35 1.1 bouyer * 36 1.1 bouyer * Copyright (c) 2015, 2016 joshua stein <jcs (at) openbsd.org> 37 1.1 bouyer * 38 1.1 bouyer * Permission to use, copy, modify, and/or distribute this software for any 39 1.1 bouyer * purpose with or without fee is hereby granted, provided that the above 40 1.1 bouyer * copyright notice and this permission notice appear in all copies. 41 1.1 bouyer * 42 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 43 1.1 bouyer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 44 1.1 bouyer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 45 1.1 bouyer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 46 1.1 bouyer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 47 1.1 bouyer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 48 1.1 bouyer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49 1.1 bouyer */ 50 1.1 bouyer 51 1.1 bouyer #include <sys/cdefs.h> 52 1.11 thorpej __KERNEL_RCSID(0, "$NetBSD: dwiic.c,v 1.11 2025/09/15 15:18:42 thorpej Exp $"); 53 1.1 bouyer 54 1.1 bouyer #include <sys/param.h> 55 1.9 riastrad 56 1.9 riastrad #include <sys/atomic.h> 57 1.1 bouyer #include <sys/bus.h> 58 1.1 bouyer #include <sys/device.h> 59 1.1 bouyer #include <sys/kernel.h> 60 1.1 bouyer #include <sys/systm.h> 61 1.1 bouyer 62 1.1 bouyer #include <dev/ic/dwiic_var.h> 63 1.1 bouyer 64 1.1 bouyer //#define DWIIC_DEBUG 65 1.1 bouyer 66 1.1 bouyer #ifdef DWIIC_DEBUG 67 1.1 bouyer #define DPRINTF(x) printf x 68 1.1 bouyer #else 69 1.1 bouyer #define DPRINTF(x) 70 1.1 bouyer #endif 71 1.1 bouyer 72 1.1 bouyer /* register offsets */ 73 1.1 bouyer #define DW_IC_CON 0x0 74 1.1 bouyer #define DW_IC_TAR 0x4 75 1.1 bouyer #define DW_IC_DATA_CMD 0x10 76 1.1 bouyer #define DW_IC_SS_SCL_HCNT 0x14 77 1.1 bouyer #define DW_IC_SS_SCL_LCNT 0x18 78 1.1 bouyer #define DW_IC_FS_SCL_HCNT 0x1c 79 1.1 bouyer #define DW_IC_FS_SCL_LCNT 0x20 80 1.1 bouyer #define DW_IC_INTR_STAT 0x2c 81 1.1 bouyer #define DW_IC_INTR_MASK 0x30 82 1.1 bouyer #define DW_IC_RAW_INTR_STAT 0x34 83 1.1 bouyer #define DW_IC_RX_TL 0x38 84 1.1 bouyer #define DW_IC_TX_TL 0x3c 85 1.1 bouyer #define DW_IC_CLR_INTR 0x40 86 1.1 bouyer #define DW_IC_CLR_RX_UNDER 0x44 87 1.1 bouyer #define DW_IC_CLR_RX_OVER 0x48 88 1.1 bouyer #define DW_IC_CLR_TX_OVER 0x4c 89 1.1 bouyer #define DW_IC_CLR_RD_REQ 0x50 90 1.1 bouyer #define DW_IC_CLR_TX_ABRT 0x54 91 1.1 bouyer #define DW_IC_CLR_RX_DONE 0x58 92 1.1 bouyer #define DW_IC_CLR_ACTIVITY 0x5c 93 1.1 bouyer #define DW_IC_CLR_STOP_DET 0x60 94 1.1 bouyer #define DW_IC_CLR_START_DET 0x64 95 1.1 bouyer #define DW_IC_CLR_GEN_CALL 0x68 96 1.1 bouyer #define DW_IC_ENABLE 0x6c 97 1.1 bouyer #define DW_IC_STATUS 0x70 98 1.1 bouyer #define DW_IC_TXFLR 0x74 99 1.1 bouyer #define DW_IC_RXFLR 0x78 100 1.1 bouyer #define DW_IC_SDA_HOLD 0x7c 101 1.1 bouyer #define DW_IC_TX_ABRT_SOURCE 0x80 102 1.1 bouyer #define DW_IC_ENABLE_STATUS 0x9c 103 1.1 bouyer #define DW_IC_COMP_PARAM_1 0xf4 104 1.1 bouyer #define DW_IC_COMP_VERSION 0xf8 105 1.1 bouyer #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A 106 1.1 bouyer #define DW_IC_COMP_TYPE 0xfc 107 1.1 bouyer #define DW_IC_COMP_TYPE_VALUE 0x44570140 108 1.1 bouyer 109 1.1 bouyer #define DW_IC_CON_MASTER 0x1 110 1.1 bouyer #define DW_IC_CON_SPEED_STD 0x2 111 1.1 bouyer #define DW_IC_CON_SPEED_FAST 0x4 112 1.1 bouyer #define DW_IC_CON_10BITADDR_MASTER 0x10 113 1.1 bouyer #define DW_IC_CON_RESTART_EN 0x20 114 1.1 bouyer #define DW_IC_CON_SLAVE_DISABLE 0x40 115 1.1 bouyer 116 1.1 bouyer #define DW_IC_DATA_CMD_READ 0x100 117 1.1 bouyer #define DW_IC_DATA_CMD_STOP 0x200 118 1.1 bouyer #define DW_IC_DATA_CMD_RESTART 0x400 119 1.1 bouyer 120 1.1 bouyer #define DW_IC_INTR_RX_UNDER 0x001 121 1.1 bouyer #define DW_IC_INTR_RX_OVER 0x002 122 1.1 bouyer #define DW_IC_INTR_RX_FULL 0x004 123 1.1 bouyer #define DW_IC_INTR_TX_OVER 0x008 124 1.1 bouyer #define DW_IC_INTR_TX_EMPTY 0x010 125 1.1 bouyer #define DW_IC_INTR_RD_REQ 0x020 126 1.1 bouyer #define DW_IC_INTR_TX_ABRT 0x040 127 1.1 bouyer #define DW_IC_INTR_RX_DONE 0x080 128 1.1 bouyer #define DW_IC_INTR_ACTIVITY 0x100 129 1.1 bouyer #define DW_IC_INTR_STOP_DET 0x200 130 1.1 bouyer #define DW_IC_INTR_START_DET 0x400 131 1.1 bouyer #define DW_IC_INTR_GEN_CALL 0x800 132 1.1 bouyer 133 1.1 bouyer #define DW_IC_STATUS_ACTIVITY 0x1 134 1.1 bouyer 135 1.1 bouyer /* hardware abort codes from the DW_IC_TX_ABRT_SOURCE register */ 136 1.1 bouyer #define ABRT_7B_ADDR_NOACK 0 137 1.1 bouyer #define ABRT_10ADDR1_NOACK 1 138 1.1 bouyer #define ABRT_10ADDR2_NOACK 2 139 1.1 bouyer #define ABRT_TXDATA_NOACK 3 140 1.1 bouyer #define ABRT_GCALL_NOACK 4 141 1.1 bouyer #define ABRT_GCALL_READ 5 142 1.1 bouyer #define ABRT_SBYTE_ACKDET 7 143 1.1 bouyer #define ABRT_SBYTE_NORSTRT 9 144 1.1 bouyer #define ABRT_10B_RD_NORSTRT 10 145 1.1 bouyer #define ABRT_MASTER_DIS 11 146 1.1 bouyer #define ARB_LOST 12 147 1.1 bouyer 148 1.1 bouyer static int dwiic_init(struct dwiic_softc *); 149 1.1 bouyer static void dwiic_enable(struct dwiic_softc *, bool); 150 1.1 bouyer static uint32_t dwiic_read(struct dwiic_softc *, int); 151 1.1 bouyer static void dwiic_write(struct dwiic_softc *, int, uint32_t); 152 1.1 bouyer static int dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, 153 1.1 bouyer size_t, void *, size_t, int); 154 1.1 bouyer 155 1.1 bouyer bool 156 1.1 bouyer dwiic_attach(struct dwiic_softc *sc) 157 1.1 bouyer { 158 1.1 bouyer if (sc->sc_power != NULL) { 159 1.1 bouyer if (!sc->sc_power(sc, 1)) { 160 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed to power up\n"); 161 1.1 bouyer return 0; 162 1.1 bouyer } 163 1.1 bouyer } 164 1.1 bouyer 165 1.1 bouyer /* fetch timing parameters */ 166 1.10 skrll if (sc->ss_hcnt == 0) 167 1.1 bouyer sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT); 168 1.1 bouyer if (sc->ss_lcnt == 0) 169 1.1 bouyer sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT); 170 1.1 bouyer if (sc->fs_hcnt == 0) 171 1.1 bouyer sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT); 172 1.1 bouyer if (sc->fs_lcnt == 0) 173 1.1 bouyer sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT); 174 1.1 bouyer if (sc->sda_hold_time == 0) 175 1.1 bouyer sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD); 176 1.1 bouyer 177 1.1 bouyer if (dwiic_init(sc)) { 178 1.1 bouyer aprint_error_dev(sc->sc_dev, "failed initializing\n"); 179 1.1 bouyer return 0; 180 1.1 bouyer } 181 1.1 bouyer 182 1.1 bouyer /* leave the controller disabled */ 183 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 0); 184 1.1 bouyer dwiic_enable(sc, 0); 185 1.1 bouyer dwiic_read(sc, DW_IC_CLR_INTR); 186 1.1 bouyer 187 1.1 bouyer mutex_init(&sc->sc_int_lock, MUTEX_DEFAULT, IPL_VM); 188 1.1 bouyer cv_init(&sc->sc_int_readwait, "dwiicr"); 189 1.1 bouyer cv_init(&sc->sc_int_writewait, "dwiicw"); 190 1.4 jakllsch cv_init(&sc->sc_int_stopwait, "dwiics"); 191 1.1 bouyer 192 1.1 bouyer /* setup and attach iic bus */ 193 1.6 thorpej iic_tag_init(&sc->sc_i2c_tag); 194 1.1 bouyer sc->sc_i2c_tag.ic_cookie = sc; 195 1.1 bouyer sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec; 196 1.1 bouyer 197 1.11 thorpej /* config_found for "i2cbus" is done in the bus-attachment glue */ 198 1.5 jakllsch 199 1.9 riastrad atomic_store_release(&sc->sc_attached, true); 200 1.9 riastrad 201 1.1 bouyer return 1; 202 1.1 bouyer } 203 1.1 bouyer 204 1.1 bouyer int 205 1.1 bouyer dwiic_detach(device_t self, int flags) 206 1.1 bouyer { 207 1.1 bouyer struct dwiic_softc *sc = device_private(self); 208 1.1 bouyer 209 1.1 bouyer dwiic_enable(sc, 0); 210 1.1 bouyer if (sc->sc_ih != NULL) { 211 1.1 bouyer intr_disestablish(sc->sc_ih); 212 1.1 bouyer sc->sc_ih = NULL; 213 1.1 bouyer } 214 1.1 bouyer 215 1.1 bouyer return 0; 216 1.1 bouyer } 217 1.1 bouyer 218 1.1 bouyer bool 219 1.1 bouyer dwiic_suspend(device_t self, const pmf_qual_t *qual) 220 1.1 bouyer { 221 1.1 bouyer struct dwiic_softc *sc = device_private(self); 222 1.1 bouyer 223 1.1 bouyer /* disable controller */ 224 1.1 bouyer dwiic_enable(sc, 0); 225 1.1 bouyer 226 1.1 bouyer /* disable interrupts */ 227 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 0); 228 1.1 bouyer dwiic_read(sc, DW_IC_CLR_INTR); 229 1.1 bouyer if (sc->sc_power != NULL) { 230 1.1 bouyer if (!sc->sc_power(sc, 0)) { 231 1.3 jakllsch device_printf(sc->sc_dev, "failed to power off\n"); 232 1.1 bouyer } 233 1.1 bouyer } 234 1.1 bouyer return true; 235 1.1 bouyer } 236 1.1 bouyer 237 1.1 bouyer bool 238 1.1 bouyer dwiic_resume(device_t self, const pmf_qual_t *qual) 239 1.1 bouyer { 240 1.1 bouyer struct dwiic_softc *sc = device_private(self); 241 1.1 bouyer if (sc->sc_power != NULL) { 242 1.1 bouyer if (!sc->sc_power(sc, 1)) { 243 1.3 jakllsch device_printf(sc->sc_dev, "failed to power up\n"); 244 1.1 bouyer return false; 245 1.1 bouyer } 246 1.1 bouyer } 247 1.1 bouyer dwiic_init(sc); 248 1.1 bouyer return true; 249 1.1 bouyer } 250 1.1 bouyer 251 1.1 bouyer static uint32_t 252 1.1 bouyer dwiic_read(struct dwiic_softc *sc, int offset) 253 1.1 bouyer { 254 1.1 bouyer u_int32_t b = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset); 255 1.1 bouyer 256 1.1 bouyer DPRINTF(("%s: read at 0x%x = 0x%x\n", device_xname(sc->sc_dev), offset, b)); 257 1.1 bouyer 258 1.1 bouyer return b; 259 1.1 bouyer } 260 1.1 bouyer 261 1.1 bouyer static void 262 1.1 bouyer dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val) 263 1.1 bouyer { 264 1.1 bouyer bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val); 265 1.1 bouyer 266 1.1 bouyer DPRINTF(("%s: write at 0x%x: 0x%x\n", device_xname(sc->sc_dev), offset, 267 1.1 bouyer val)); 268 1.1 bouyer } 269 1.1 bouyer 270 1.1 bouyer static int 271 1.1 bouyer dwiic_init(struct dwiic_softc *sc) 272 1.1 bouyer { 273 1.1 bouyer uint32_t reg; 274 1.1 bouyer 275 1.1 bouyer /* make sure we're talking to a device we know */ 276 1.1 bouyer reg = dwiic_read(sc, DW_IC_COMP_TYPE); 277 1.1 bouyer if (reg != DW_IC_COMP_TYPE_VALUE) { 278 1.1 bouyer DPRINTF(("%s: invalid component type 0x%x\n", 279 1.1 bouyer device_xname(sc->sc_dev), reg)); 280 1.1 bouyer return 1; 281 1.1 bouyer } 282 1.1 bouyer 283 1.1 bouyer /* disable the adapter */ 284 1.1 bouyer dwiic_enable(sc, 0); 285 1.1 bouyer 286 1.1 bouyer /* write standard-mode SCL timing parameters */ 287 1.1 bouyer dwiic_write(sc, DW_IC_SS_SCL_HCNT, sc->ss_hcnt); 288 1.1 bouyer dwiic_write(sc, DW_IC_SS_SCL_LCNT, sc->ss_lcnt); 289 1.1 bouyer 290 1.1 bouyer /* and fast-mode SCL timing parameters */ 291 1.1 bouyer dwiic_write(sc, DW_IC_FS_SCL_HCNT, sc->fs_hcnt); 292 1.1 bouyer dwiic_write(sc, DW_IC_FS_SCL_LCNT, sc->fs_lcnt); 293 1.1 bouyer 294 1.1 bouyer /* SDA hold time */ 295 1.1 bouyer reg = dwiic_read(sc, DW_IC_COMP_VERSION); 296 1.1 bouyer if (reg >= DW_IC_SDA_HOLD_MIN_VERS) 297 1.1 bouyer dwiic_write(sc, DW_IC_SDA_HOLD, sc->sda_hold_time); 298 1.1 bouyer 299 1.1 bouyer /* FIFO threshold levels */ 300 1.1 bouyer sc->tx_fifo_depth = 32; 301 1.1 bouyer sc->rx_fifo_depth = 32; 302 1.1 bouyer dwiic_write(sc, DW_IC_TX_TL, sc->tx_fifo_depth / 2); 303 1.1 bouyer dwiic_write(sc, DW_IC_RX_TL, 0); 304 1.1 bouyer 305 1.1 bouyer /* configure as i2c master with fast speed */ 306 1.1 bouyer sc->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | 307 1.1 bouyer DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; 308 1.1 bouyer dwiic_write(sc, DW_IC_CON, sc->master_cfg); 309 1.1 bouyer 310 1.1 bouyer return 0; 311 1.1 bouyer } 312 1.1 bouyer 313 1.1 bouyer static void 314 1.1 bouyer dwiic_enable(struct dwiic_softc *sc, bool enable) 315 1.1 bouyer { 316 1.1 bouyer int retries; 317 1.1 bouyer 318 1.1 bouyer for (retries = 100; retries > 0; retries--) { 319 1.1 bouyer dwiic_write(sc, DW_IC_ENABLE, enable); 320 1.1 bouyer if ((dwiic_read(sc, DW_IC_ENABLE_STATUS) & 1) == enable) 321 1.1 bouyer return; 322 1.1 bouyer 323 1.1 bouyer DELAY(25); 324 1.1 bouyer } 325 1.1 bouyer 326 1.3 jakllsch device_printf(sc->sc_dev, "failed to %sable\n", 327 1.1 bouyer (enable ? "en" : "dis")); 328 1.1 bouyer } 329 1.1 bouyer 330 1.1 bouyer static int 331 1.1 bouyer dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, 332 1.1 bouyer size_t cmdlen, void *buf, size_t len, int flags) 333 1.1 bouyer { 334 1.1 bouyer struct dwiic_softc *sc = cookie; 335 1.1 bouyer u_int32_t ic_con, st, cmd, resp; 336 1.1 bouyer int retries, tx_limit, rx_avail, x, readpos; 337 1.1 bouyer const uint8_t *bcmd; 338 1.1 bouyer uint8_t *bdata; 339 1.1 bouyer 340 1.7 thorpej if (sc->sc_poll) 341 1.1 bouyer flags |= I2C_F_POLL; 342 1.1 bouyer 343 1.1 bouyer DPRINTF(("%s: %s: op %d, addr 0x%02x, cmdlen %zu, len %zu, " 344 1.1 bouyer "flags 0x%02x\n", device_xname(sc->sc_dev), __func__, op, addr, cmdlen, 345 1.1 bouyer len, flags)); 346 1.1 bouyer 347 1.1 bouyer /* setup transfer */ 348 1.1 bouyer sc->sc_i2c_xfer.op = op; 349 1.1 bouyer sc->sc_i2c_xfer.buf = buf; 350 1.1 bouyer sc->sc_i2c_xfer.len = len; 351 1.1 bouyer sc->sc_i2c_xfer.flags = flags; 352 1.1 bouyer sc->sc_i2c_xfer.error = 0; 353 1.1 bouyer 354 1.1 bouyer /* wait for bus to be idle */ 355 1.1 bouyer for (retries = 100; retries > 0; retries--) { 356 1.1 bouyer st = dwiic_read(sc, DW_IC_STATUS); 357 1.1 bouyer if (!(st & DW_IC_STATUS_ACTIVITY)) 358 1.1 bouyer break; 359 1.1 bouyer DELAY(1000); 360 1.1 bouyer } 361 1.1 bouyer DPRINTF(("%s: %s: status 0x%x\n", device_xname(sc->sc_dev), __func__, st)); 362 1.1 bouyer if (st & DW_IC_STATUS_ACTIVITY) { 363 1.1 bouyer return (1); 364 1.1 bouyer } 365 1.1 bouyer 366 1.1 bouyer /* disable controller */ 367 1.1 bouyer dwiic_enable(sc, 0); 368 1.1 bouyer 369 1.1 bouyer /* set slave address */ 370 1.1 bouyer ic_con = dwiic_read(sc, DW_IC_CON); 371 1.1 bouyer ic_con &= ~DW_IC_CON_10BITADDR_MASTER; 372 1.1 bouyer dwiic_write(sc, DW_IC_CON, ic_con); 373 1.1 bouyer dwiic_write(sc, DW_IC_TAR, addr); 374 1.1 bouyer 375 1.1 bouyer /* disable interrupts */ 376 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 0); 377 1.1 bouyer dwiic_read(sc, DW_IC_CLR_INTR); 378 1.1 bouyer 379 1.1 bouyer /* enable controller */ 380 1.1 bouyer dwiic_enable(sc, 1); 381 1.1 bouyer 382 1.1 bouyer /* wait until the controller is ready for commands */ 383 1.1 bouyer if (flags & I2C_F_POLL) 384 1.1 bouyer DELAY(200); 385 1.1 bouyer else { 386 1.1 bouyer mutex_enter(&sc->sc_int_lock); 387 1.1 bouyer dwiic_read(sc, DW_IC_CLR_INTR); 388 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY); 389 1.1 bouyer 390 1.1 bouyer if (cv_timedwait(&sc->sc_int_writewait, 391 1.1 bouyer &sc->sc_int_lock, hz / 2) != 0) 392 1.3 jakllsch device_printf(sc->sc_dev, 393 1.1 bouyer "timed out waiting for tx_empty intr\n"); 394 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 0); 395 1.1 bouyer dwiic_read(sc, DW_IC_CLR_INTR); 396 1.1 bouyer mutex_exit(&sc->sc_int_lock); 397 1.1 bouyer } 398 1.1 bouyer 399 1.1 bouyer /* send our command, one byte at a time */ 400 1.1 bouyer if (cmdlen > 0) { 401 1.1 bouyer bcmd = (const void *)cmdbuf; 402 1.1 bouyer 403 1.1 bouyer DPRINTF(("%s: %s: sending cmd (len %zu):", device_xname(sc->sc_dev), 404 1.1 bouyer __func__, cmdlen)); 405 1.1 bouyer for (x = 0; x < cmdlen; x++) 406 1.1 bouyer DPRINTF((" %02x", bcmd[x])); 407 1.1 bouyer DPRINTF(("\n")); 408 1.1 bouyer 409 1.1 bouyer tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR); 410 1.1 bouyer if (cmdlen > tx_limit) { 411 1.1 bouyer /* TODO */ 412 1.3 jakllsch device_printf(sc->sc_dev, "can't write %zu (> %d)\n", 413 1.1 bouyer cmdlen, tx_limit); 414 1.1 bouyer sc->sc_i2c_xfer.error = 1; 415 1.1 bouyer return (1); 416 1.1 bouyer } 417 1.1 bouyer 418 1.1 bouyer for (x = 0; x < cmdlen; x++) { 419 1.1 bouyer cmd = bcmd[x]; 420 1.1 bouyer /* 421 1.1 bouyer * Generate STOP condition if this is the last 422 1.1 bouyer * byte of the transfer. 423 1.1 bouyer */ 424 1.1 bouyer if (x == (cmdlen - 1) && len == 0 && I2C_OP_STOP_P(op)) 425 1.1 bouyer cmd |= DW_IC_DATA_CMD_STOP; 426 1.1 bouyer dwiic_write(sc, DW_IC_DATA_CMD, cmd); 427 1.1 bouyer } 428 1.1 bouyer } 429 1.1 bouyer 430 1.1 bouyer bdata = (void *)buf; 431 1.1 bouyer x = readpos = 0; 432 1.1 bouyer tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR); 433 1.1 bouyer 434 1.1 bouyer DPRINTF(("%s: %s: need to read %zu bytes, can send %d read reqs\n", 435 1.1 bouyer device_xname(sc->sc_dev), __func__, len, tx_limit)); 436 1.1 bouyer 437 1.1 bouyer while (x < len) { 438 1.1 bouyer if (I2C_OP_WRITE_P(op)) 439 1.1 bouyer cmd = bdata[x]; 440 1.1 bouyer else 441 1.1 bouyer cmd = DW_IC_DATA_CMD_READ; 442 1.1 bouyer 443 1.1 bouyer /* 444 1.1 bouyer * Generate RESTART condition if we're reversing 445 1.1 bouyer * direction. 446 1.1 bouyer */ 447 1.1 bouyer if (x == 0 && cmdlen > 0 && I2C_OP_READ_P(op)) 448 1.1 bouyer cmd |= DW_IC_DATA_CMD_RESTART; 449 1.1 bouyer /* 450 1.8 andvar * Generate STOP condition on the last byte of the 451 1.1 bouyer * transfer. 452 1.1 bouyer */ 453 1.1 bouyer if (x == (len - 1) && I2C_OP_STOP_P(op)) 454 1.1 bouyer cmd |= DW_IC_DATA_CMD_STOP; 455 1.1 bouyer 456 1.1 bouyer dwiic_write(sc, DW_IC_DATA_CMD, cmd); 457 1.1 bouyer 458 1.1 bouyer tx_limit--; 459 1.1 bouyer x++; 460 1.1 bouyer 461 1.1 bouyer /* 462 1.1 bouyer * As TXFLR fills up, we need to clear it out by reading all 463 1.1 bouyer * available data. 464 1.1 bouyer */ 465 1.4 jakllsch while (I2C_OP_READ_P(op) && (tx_limit == 0 || x == len)) { 466 1.1 bouyer DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n", 467 1.1 bouyer device_xname(sc->sc_dev), __func__, tx_limit, x)); 468 1.1 bouyer 469 1.1 bouyer if (flags & I2C_F_POLL) { 470 1.1 bouyer for (retries = 100; retries > 0; retries--) { 471 1.1 bouyer rx_avail = dwiic_read(sc, DW_IC_RXFLR); 472 1.1 bouyer if (rx_avail > 0) 473 1.1 bouyer break; 474 1.1 bouyer DELAY(50); 475 1.1 bouyer } 476 1.1 bouyer } else { 477 1.1 bouyer mutex_enter(&sc->sc_int_lock); 478 1.1 bouyer dwiic_read(sc, DW_IC_CLR_INTR); 479 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 480 1.1 bouyer DW_IC_INTR_RX_FULL); 481 1.1 bouyer 482 1.1 bouyer if (cv_timedwait(&sc->sc_int_readwait, 483 1.1 bouyer &sc->sc_int_lock, hz / 2) != 0) 484 1.3 jakllsch device_printf(sc->sc_dev, 485 1.1 bouyer "timed out waiting for " 486 1.1 bouyer "rx_full intr\n"); 487 1.1 bouyer 488 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 0); 489 1.1 bouyer dwiic_read(sc, DW_IC_CLR_INTR); 490 1.1 bouyer mutex_exit(&sc->sc_int_lock); 491 1.1 bouyer rx_avail = dwiic_read(sc, DW_IC_RXFLR); 492 1.1 bouyer } 493 1.1 bouyer 494 1.1 bouyer if (rx_avail == 0) { 495 1.3 jakllsch device_printf(sc->sc_dev, 496 1.1 bouyer "timed out reading remaining %d\n", 497 1.1 bouyer (int)(len - 1 - readpos)); 498 1.1 bouyer sc->sc_i2c_xfer.error = 1; 499 1.1 bouyer return (1); 500 1.1 bouyer } 501 1.1 bouyer 502 1.1 bouyer DPRINTF(("%s: %s: %d avail to read (%zu remaining)\n", 503 1.1 bouyer device_xname(sc->sc_dev), __func__, rx_avail, 504 1.1 bouyer len - readpos)); 505 1.1 bouyer 506 1.1 bouyer while (rx_avail > 0) { 507 1.1 bouyer resp = dwiic_read(sc, DW_IC_DATA_CMD); 508 1.1 bouyer if (readpos < len) { 509 1.1 bouyer bdata[readpos] = resp; 510 1.1 bouyer readpos++; 511 1.1 bouyer } 512 1.1 bouyer rx_avail--; 513 1.1 bouyer } 514 1.1 bouyer 515 1.1 bouyer if (readpos >= len) 516 1.1 bouyer break; 517 1.1 bouyer 518 1.1 bouyer DPRINTF(("%s: still need to read %d bytes\n", 519 1.1 bouyer device_xname(sc->sc_dev), (int)(len - readpos))); 520 1.1 bouyer tx_limit = sc->tx_fifo_depth - 521 1.1 bouyer dwiic_read(sc, DW_IC_TXFLR); 522 1.1 bouyer } 523 1.1 bouyer } 524 1.1 bouyer 525 1.4 jakllsch if (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) { 526 1.4 jakllsch if (flags & I2C_F_POLL) { 527 1.4 jakllsch /* wait for bus to be idle */ 528 1.4 jakllsch for (retries = 100; retries > 0; retries--) { 529 1.4 jakllsch st = dwiic_read(sc, DW_IC_STATUS); 530 1.4 jakllsch if (!(st & DW_IC_STATUS_ACTIVITY)) 531 1.4 jakllsch break; 532 1.4 jakllsch DELAY(1000); 533 1.4 jakllsch } 534 1.4 jakllsch if (st & DW_IC_STATUS_ACTIVITY) 535 1.4 jakllsch device_printf(sc->sc_dev, "timed out waiting " 536 1.4 jakllsch "for bus idle\n"); 537 1.4 jakllsch } else { 538 1.4 jakllsch mutex_enter(&sc->sc_int_lock); 539 1.4 jakllsch dwiic_read(sc, DW_IC_CLR_INTR); 540 1.4 jakllsch dwiic_write(sc, DW_IC_INTR_MASK, 541 1.4 jakllsch DW_IC_INTR_STOP_DET); 542 1.4 jakllsch if (cv_timedwait(&sc->sc_int_stopwait, 543 1.4 jakllsch &sc->sc_int_lock, hz / 2) != 0) 544 1.4 jakllsch device_printf(sc->sc_dev, "timed out waiting " 545 1.4 jakllsch "for stop intr\n"); 546 1.4 jakllsch dwiic_write(sc, DW_IC_INTR_MASK, 0); 547 1.4 jakllsch dwiic_read(sc, DW_IC_CLR_INTR); 548 1.4 jakllsch mutex_exit(&sc->sc_int_lock); 549 1.4 jakllsch } 550 1.4 jakllsch } 551 1.4 jakllsch 552 1.1 bouyer return 0; 553 1.1 bouyer } 554 1.1 bouyer 555 1.1 bouyer static uint32_t 556 1.1 bouyer dwiic_read_clear_intrbits(struct dwiic_softc *sc) 557 1.1 bouyer { 558 1.1 bouyer uint32_t stat; 559 1.1 bouyer 560 1.1 bouyer stat = dwiic_read(sc, DW_IC_INTR_STAT); 561 1.1 bouyer 562 1.1 bouyer if (stat & DW_IC_INTR_RX_UNDER) 563 1.1 bouyer dwiic_read(sc, DW_IC_CLR_RX_UNDER); 564 1.1 bouyer if (stat & DW_IC_INTR_RX_OVER) 565 1.1 bouyer dwiic_read(sc, DW_IC_CLR_RX_OVER); 566 1.1 bouyer if (stat & DW_IC_INTR_TX_OVER) 567 1.1 bouyer dwiic_read(sc, DW_IC_CLR_TX_OVER); 568 1.1 bouyer if (stat & DW_IC_INTR_RD_REQ) 569 1.1 bouyer dwiic_read(sc, DW_IC_CLR_RD_REQ); 570 1.1 bouyer if (stat & DW_IC_INTR_TX_ABRT) 571 1.1 bouyer dwiic_read(sc, DW_IC_CLR_TX_ABRT); 572 1.1 bouyer if (stat & DW_IC_INTR_RX_DONE) 573 1.1 bouyer dwiic_read(sc, DW_IC_CLR_RX_DONE); 574 1.1 bouyer if (stat & DW_IC_INTR_ACTIVITY) 575 1.1 bouyer dwiic_read(sc, DW_IC_CLR_ACTIVITY); 576 1.1 bouyer if (stat & DW_IC_INTR_STOP_DET) 577 1.1 bouyer dwiic_read(sc, DW_IC_CLR_STOP_DET); 578 1.1 bouyer if (stat & DW_IC_INTR_START_DET) 579 1.1 bouyer dwiic_read(sc, DW_IC_CLR_START_DET); 580 1.1 bouyer if (stat & DW_IC_INTR_GEN_CALL) 581 1.1 bouyer dwiic_read(sc, DW_IC_CLR_GEN_CALL); 582 1.1 bouyer 583 1.1 bouyer return stat; 584 1.1 bouyer } 585 1.1 bouyer 586 1.1 bouyer int 587 1.1 bouyer dwiic_intr(void *arg) 588 1.1 bouyer { 589 1.1 bouyer struct dwiic_softc *sc = arg; 590 1.1 bouyer uint32_t en, stat; 591 1.1 bouyer 592 1.9 riastrad /* 593 1.9 riastrad * Give up if attach hasn't succeeded. If it failed, nothing 594 1.9 riastrad * to do here. If it is still ongoing and simply hasn't yet 595 1.9 riastrad * succeeded, interrupts from the device are masked -- so this 596 1.9 riastrad * interrupt must be shared with another driver -- and any 597 1.9 riastrad * interrupts applicable to us will be delivered once 598 1.9 riastrad * interrupts from the device are unmasked in dwiic_i2c_exec. 599 1.9 riastrad */ 600 1.9 riastrad if (!atomic_load_acquire(&sc->sc_attached)) 601 1.9 riastrad return 0; 602 1.9 riastrad 603 1.1 bouyer en = dwiic_read(sc, DW_IC_ENABLE); 604 1.1 bouyer /* probably for the other controller */ 605 1.1 bouyer if (!en) 606 1.1 bouyer return 0; 607 1.1 bouyer 608 1.1 bouyer stat = dwiic_read_clear_intrbits(sc); 609 1.1 bouyer DPRINTF(("%s: %s: enabled=0x%x stat=0x%x\n", device_xname(sc->sc_dev), 610 1.1 bouyer __func__, en, stat)); 611 1.1 bouyer if (!(stat & ~DW_IC_INTR_ACTIVITY)) 612 1.1 bouyer return 1; 613 1.1 bouyer 614 1.1 bouyer if (stat & DW_IC_INTR_TX_ABRT) 615 1.1 bouyer sc->sc_i2c_xfer.error = 1; 616 1.1 bouyer 617 1.1 bouyer if (sc->sc_i2c_xfer.flags & I2C_F_POLL) 618 1.1 bouyer DPRINTF(("%s: %s: intr in poll mode?\n", device_xname(sc->sc_dev), 619 1.1 bouyer __func__)); 620 1.1 bouyer else { 621 1.1 bouyer mutex_enter(&sc->sc_int_lock); 622 1.1 bouyer if (stat & DW_IC_INTR_RX_FULL) { 623 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 0); 624 1.1 bouyer DPRINTF(("%s: %s: waking up reader\n", 625 1.1 bouyer device_xname(sc->sc_dev), __func__)); 626 1.1 bouyer cv_signal(&sc->sc_int_readwait); 627 1.1 bouyer } 628 1.1 bouyer if (stat & DW_IC_INTR_TX_EMPTY) { 629 1.1 bouyer dwiic_write(sc, DW_IC_INTR_MASK, 0); 630 1.1 bouyer DPRINTF(("%s: %s: waking up writer\n", 631 1.1 bouyer device_xname(sc->sc_dev), __func__)); 632 1.1 bouyer cv_signal(&sc->sc_int_writewait); 633 1.1 bouyer } 634 1.4 jakllsch if (stat & DW_IC_INTR_STOP_DET) { 635 1.4 jakllsch dwiic_write(sc, DW_IC_INTR_MASK, 0); 636 1.4 jakllsch DPRINTF(("%s: %s: waking up stopper\n", 637 1.4 jakllsch device_xname(sc->sc_dev), __func__)); 638 1.4 jakllsch cv_signal(&sc->sc_int_stopwait); 639 1.4 jakllsch } 640 1.1 bouyer mutex_exit(&sc->sc_int_lock); 641 1.1 bouyer } 642 1.1 bouyer 643 1.1 bouyer return 1; 644 1.1 bouyer } 645