| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Aspeed 24XX/25XX I2C Controller. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2012-2017 ASPEED Technology Inc. |
|---|
| 5 | 6 | * Copyright 2017 IBM Corporation |
|---|
| 6 | 7 | * Copyright 2017 Google, Inc. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 10 | | - * published by the Free Software Foundation. |
|---|
| 11 | 8 | */ |
|---|
| 12 | 9 | |
|---|
| 13 | 10 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 72 | 69 | * These share bit definitions, so use the same values for the enable & |
|---|
| 73 | 70 | * status bits. |
|---|
| 74 | 71 | */ |
|---|
| 72 | +#define ASPEED_I2CD_INTR_RECV_MASK 0xf000ffff |
|---|
| 75 | 73 | #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) |
|---|
| 76 | 74 | #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) |
|---|
| 77 | 75 | #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) |
|---|
| .. | .. |
|---|
| 82 | 80 | #define ASPEED_I2CD_INTR_RX_DONE BIT(2) |
|---|
| 83 | 81 | #define ASPEED_I2CD_INTR_TX_NAK BIT(1) |
|---|
| 84 | 82 | #define ASPEED_I2CD_INTR_TX_ACK BIT(0) |
|---|
| 83 | +#define ASPEED_I2CD_INTR_MASTER_ERRORS \ |
|---|
| 84 | + (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \ |
|---|
| 85 | + ASPEED_I2CD_INTR_SCL_TIMEOUT | \ |
|---|
| 86 | + ASPEED_I2CD_INTR_ABNORMAL | \ |
|---|
| 87 | + ASPEED_I2CD_INTR_ARBIT_LOSS) |
|---|
| 85 | 88 | #define ASPEED_I2CD_INTR_ALL \ |
|---|
| 86 | 89 | (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \ |
|---|
| 87 | 90 | ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \ |
|---|
| .. | .. |
|---|
| 106 | 109 | #define ASPEED_I2CD_S_TX_CMD BIT(2) |
|---|
| 107 | 110 | #define ASPEED_I2CD_M_TX_CMD BIT(1) |
|---|
| 108 | 111 | #define ASPEED_I2CD_M_START_CMD BIT(0) |
|---|
| 112 | +#define ASPEED_I2CD_MASTER_CMDS_MASK \ |
|---|
| 113 | + (ASPEED_I2CD_M_STOP_CMD | \ |
|---|
| 114 | + ASPEED_I2CD_M_S_RX_CMD_LAST | \ |
|---|
| 115 | + ASPEED_I2CD_M_RX_CMD | \ |
|---|
| 116 | + ASPEED_I2CD_M_TX_CMD | \ |
|---|
| 117 | + ASPEED_I2CD_M_START_CMD) |
|---|
| 109 | 118 | |
|---|
| 110 | 119 | /* 0x18 : I2CD Slave Device Address Register */ |
|---|
| 111 | 120 | #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) |
|---|
| 112 | 121 | |
|---|
| 113 | 122 | enum aspeed_i2c_master_state { |
|---|
| 114 | 123 | ASPEED_I2C_MASTER_INACTIVE, |
|---|
| 124 | + ASPEED_I2C_MASTER_PENDING, |
|---|
| 115 | 125 | ASPEED_I2C_MASTER_START, |
|---|
| 116 | 126 | ASPEED_I2C_MASTER_TX_FIRST, |
|---|
| 117 | 127 | ASPEED_I2C_MASTER_TX, |
|---|
| .. | .. |
|---|
| 121 | 131 | }; |
|---|
| 122 | 132 | |
|---|
| 123 | 133 | enum aspeed_i2c_slave_state { |
|---|
| 124 | | - ASPEED_I2C_SLAVE_STOP, |
|---|
| 134 | + ASPEED_I2C_SLAVE_INACTIVE, |
|---|
| 125 | 135 | ASPEED_I2C_SLAVE_START, |
|---|
| 126 | 136 | ASPEED_I2C_SLAVE_READ_REQUESTED, |
|---|
| 127 | 137 | ASPEED_I2C_SLAVE_READ_PROCESSED, |
|---|
| 128 | 138 | ASPEED_I2C_SLAVE_WRITE_REQUESTED, |
|---|
| 129 | 139 | ASPEED_I2C_SLAVE_WRITE_RECEIVED, |
|---|
| 140 | + ASPEED_I2C_SLAVE_STOP, |
|---|
| 130 | 141 | }; |
|---|
| 131 | 142 | |
|---|
| 132 | 143 | struct aspeed_i2c_bus { |
|---|
| .. | .. |
|---|
| 151 | 162 | int cmd_err; |
|---|
| 152 | 163 | /* Protected only by i2c_lock_bus */ |
|---|
| 153 | 164 | int master_xfer_result; |
|---|
| 165 | + /* Multi-master */ |
|---|
| 166 | + bool multi_master; |
|---|
| 154 | 167 | #if IS_ENABLED(CONFIG_I2C_SLAVE) |
|---|
| 155 | 168 | struct i2c_client *slave; |
|---|
| 156 | 169 | enum aspeed_i2c_slave_state slave_state; |
|---|
| .. | .. |
|---|
| 228 | 241 | } |
|---|
| 229 | 242 | |
|---|
| 230 | 243 | #if IS_ENABLED(CONFIG_I2C_SLAVE) |
|---|
| 231 | | -static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus) |
|---|
| 244 | +static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) |
|---|
| 232 | 245 | { |
|---|
| 233 | | - u32 command, irq_status, status_ack = 0; |
|---|
| 246 | + u32 command, irq_handled = 0; |
|---|
| 234 | 247 | struct i2c_client *slave = bus->slave; |
|---|
| 235 | | - bool irq_handled = true; |
|---|
| 236 | 248 | u8 value; |
|---|
| 237 | 249 | |
|---|
| 238 | | - if (!slave) { |
|---|
| 239 | | - irq_handled = false; |
|---|
| 240 | | - goto out; |
|---|
| 241 | | - } |
|---|
| 250 | + if (!slave) |
|---|
| 251 | + return 0; |
|---|
| 242 | 252 | |
|---|
| 243 | 253 | command = readl(bus->base + ASPEED_I2C_CMD_REG); |
|---|
| 244 | | - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 245 | 254 | |
|---|
| 246 | 255 | /* Slave was requested, restart state machine. */ |
|---|
| 247 | 256 | if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) { |
|---|
| 248 | | - status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH; |
|---|
| 257 | + irq_handled |= ASPEED_I2CD_INTR_SLAVE_MATCH; |
|---|
| 249 | 258 | bus->slave_state = ASPEED_I2C_SLAVE_START; |
|---|
| 250 | 259 | } |
|---|
| 251 | 260 | |
|---|
| 252 | 261 | /* Slave is not currently active, irq was for someone else. */ |
|---|
| 253 | | - if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) { |
|---|
| 254 | | - irq_handled = false; |
|---|
| 255 | | - goto out; |
|---|
| 256 | | - } |
|---|
| 262 | + if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) |
|---|
| 263 | + return irq_handled; |
|---|
| 257 | 264 | |
|---|
| 258 | 265 | dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n", |
|---|
| 259 | 266 | irq_status, command); |
|---|
| .. | .. |
|---|
| 270 | 277 | bus->slave_state = |
|---|
| 271 | 278 | ASPEED_I2C_SLAVE_WRITE_REQUESTED; |
|---|
| 272 | 279 | } |
|---|
| 273 | | - status_ack |= ASPEED_I2CD_INTR_RX_DONE; |
|---|
| 280 | + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; |
|---|
| 274 | 281 | } |
|---|
| 275 | 282 | |
|---|
| 276 | 283 | /* Slave was asked to stop. */ |
|---|
| 277 | 284 | if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { |
|---|
| 278 | | - status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP; |
|---|
| 285 | + irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; |
|---|
| 279 | 286 | bus->slave_state = ASPEED_I2C_SLAVE_STOP; |
|---|
| 280 | 287 | } |
|---|
| 281 | | - if (irq_status & ASPEED_I2CD_INTR_TX_NAK) { |
|---|
| 282 | | - status_ack |= ASPEED_I2CD_INTR_TX_NAK; |
|---|
| 288 | + if (irq_status & ASPEED_I2CD_INTR_TX_NAK && |
|---|
| 289 | + bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) { |
|---|
| 290 | + irq_handled |= ASPEED_I2CD_INTR_TX_NAK; |
|---|
| 283 | 291 | bus->slave_state = ASPEED_I2C_SLAVE_STOP; |
|---|
| 284 | 292 | } |
|---|
| 285 | 293 | |
|---|
| 286 | 294 | switch (bus->slave_state) { |
|---|
| 287 | 295 | case ASPEED_I2C_SLAVE_READ_REQUESTED: |
|---|
| 288 | | - if (irq_status & ASPEED_I2CD_INTR_TX_ACK) |
|---|
| 296 | + if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK)) |
|---|
| 289 | 297 | dev_err(bus->dev, "Unexpected ACK on read request.\n"); |
|---|
| 290 | 298 | bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED; |
|---|
| 291 | | - |
|---|
| 292 | 299 | i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); |
|---|
| 293 | 300 | writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG); |
|---|
| 294 | 301 | writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG); |
|---|
| 295 | 302 | break; |
|---|
| 296 | 303 | case ASPEED_I2C_SLAVE_READ_PROCESSED: |
|---|
| 297 | | - status_ack |= ASPEED_I2CD_INTR_TX_ACK; |
|---|
| 298 | | - if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK)) |
|---|
| 304 | + if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { |
|---|
| 299 | 305 | dev_err(bus->dev, |
|---|
| 300 | 306 | "Expected ACK after processed read.\n"); |
|---|
| 307 | + break; |
|---|
| 308 | + } |
|---|
| 309 | + irq_handled |= ASPEED_I2CD_INTR_TX_ACK; |
|---|
| 301 | 310 | i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value); |
|---|
| 302 | 311 | writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG); |
|---|
| 303 | 312 | writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG); |
|---|
| .. | .. |
|---|
| 311 | 320 | break; |
|---|
| 312 | 321 | case ASPEED_I2C_SLAVE_STOP: |
|---|
| 313 | 322 | i2c_slave_event(slave, I2C_SLAVE_STOP, &value); |
|---|
| 323 | + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; |
|---|
| 324 | + break; |
|---|
| 325 | + case ASPEED_I2C_SLAVE_START: |
|---|
| 326 | + /* Slave was just started. Waiting for the next event. */; |
|---|
| 314 | 327 | break; |
|---|
| 315 | 328 | default: |
|---|
| 316 | | - dev_err(bus->dev, "unhandled slave_state: %d\n", |
|---|
| 329 | + dev_err(bus->dev, "unknown slave_state: %d\n", |
|---|
| 317 | 330 | bus->slave_state); |
|---|
| 331 | + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; |
|---|
| 318 | 332 | break; |
|---|
| 319 | 333 | } |
|---|
| 320 | 334 | |
|---|
| 321 | | - if (status_ack != irq_status) |
|---|
| 322 | | - dev_err(bus->dev, |
|---|
| 323 | | - "irq handled != irq. expected %x, but was %x\n", |
|---|
| 324 | | - irq_status, status_ack); |
|---|
| 325 | | - writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 326 | | - |
|---|
| 327 | | -out: |
|---|
| 328 | 335 | return irq_handled; |
|---|
| 329 | 336 | } |
|---|
| 330 | 337 | #endif /* CONFIG_I2C_SLAVE */ |
|---|
| .. | .. |
|---|
| 335 | 342 | u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD; |
|---|
| 336 | 343 | struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; |
|---|
| 337 | 344 | u8 slave_addr = i2c_8bit_addr_from_msg(msg); |
|---|
| 345 | + |
|---|
| 346 | +#if IS_ENABLED(CONFIG_I2C_SLAVE) |
|---|
| 347 | + /* |
|---|
| 348 | + * If it's requested in the middle of a slave session, set the master |
|---|
| 349 | + * state to 'pending' then H/W will continue handling this master |
|---|
| 350 | + * command when the bus comes back to the idle state. |
|---|
| 351 | + */ |
|---|
| 352 | + if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) { |
|---|
| 353 | + bus->master_state = ASPEED_I2C_MASTER_PENDING; |
|---|
| 354 | + return; |
|---|
| 355 | + } |
|---|
| 356 | +#endif /* CONFIG_I2C_SLAVE */ |
|---|
| 338 | 357 | |
|---|
| 339 | 358 | bus->master_state = ASPEED_I2C_MASTER_START; |
|---|
| 340 | 359 | bus->buf_index = 0; |
|---|
| .. | .. |
|---|
| 381 | 400 | return 0; |
|---|
| 382 | 401 | } |
|---|
| 383 | 402 | |
|---|
| 384 | | -static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) |
|---|
| 403 | +static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) |
|---|
| 385 | 404 | { |
|---|
| 386 | | - u32 irq_status, status_ack = 0, command = 0; |
|---|
| 405 | + u32 irq_handled = 0, command = 0; |
|---|
| 387 | 406 | struct i2c_msg *msg; |
|---|
| 388 | 407 | u8 recv_byte; |
|---|
| 389 | 408 | int ret; |
|---|
| 390 | 409 | |
|---|
| 391 | | - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 392 | | - /* Ack all interrupt bits. */ |
|---|
| 393 | | - writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 394 | | - |
|---|
| 395 | 410 | if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) { |
|---|
| 396 | 411 | bus->master_state = ASPEED_I2C_MASTER_INACTIVE; |
|---|
| 397 | | - status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE; |
|---|
| 412 | + irq_handled |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE; |
|---|
| 398 | 413 | goto out_complete; |
|---|
| 399 | 414 | } |
|---|
| 400 | 415 | |
|---|
| .. | .. |
|---|
| 404 | 419 | * INACTIVE state. |
|---|
| 405 | 420 | */ |
|---|
| 406 | 421 | ret = aspeed_i2c_is_irq_error(irq_status); |
|---|
| 407 | | - if (ret < 0) { |
|---|
| 422 | + if (ret) { |
|---|
| 408 | 423 | dev_dbg(bus->dev, "received error interrupt: 0x%08x\n", |
|---|
| 409 | 424 | irq_status); |
|---|
| 410 | | - bus->cmd_err = ret; |
|---|
| 411 | | - bus->master_state = ASPEED_I2C_MASTER_INACTIVE; |
|---|
| 412 | | - goto out_complete; |
|---|
| 425 | + irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS); |
|---|
| 426 | + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) { |
|---|
| 427 | + bus->cmd_err = ret; |
|---|
| 428 | + bus->master_state = ASPEED_I2C_MASTER_INACTIVE; |
|---|
| 429 | + goto out_complete; |
|---|
| 430 | + } |
|---|
| 413 | 431 | } |
|---|
| 432 | + |
|---|
| 433 | + /* Master is not currently active, irq was for someone else. */ |
|---|
| 434 | + if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE || |
|---|
| 435 | + bus->master_state == ASPEED_I2C_MASTER_PENDING) |
|---|
| 436 | + goto out_no_complete; |
|---|
| 414 | 437 | |
|---|
| 415 | 438 | /* We are in an invalid state; reset bus to a known state. */ |
|---|
| 416 | 439 | if (!bus->msgs) { |
|---|
| 417 | | - dev_err(bus->dev, "bus in unknown state\n"); |
|---|
| 440 | + dev_err(bus->dev, "bus in unknown state. irq_status: 0x%x\n", |
|---|
| 441 | + irq_status); |
|---|
| 418 | 442 | bus->cmd_err = -EIO; |
|---|
| 419 | | - if (bus->master_state != ASPEED_I2C_MASTER_STOP) |
|---|
| 443 | + if (bus->master_state != ASPEED_I2C_MASTER_STOP && |
|---|
| 444 | + bus->master_state != ASPEED_I2C_MASTER_INACTIVE) |
|---|
| 420 | 445 | aspeed_i2c_do_stop(bus); |
|---|
| 421 | 446 | goto out_no_complete; |
|---|
| 422 | 447 | } |
|---|
| .. | .. |
|---|
| 428 | 453 | * then update the state and handle the new state below. |
|---|
| 429 | 454 | */ |
|---|
| 430 | 455 | if (bus->master_state == ASPEED_I2C_MASTER_START) { |
|---|
| 456 | +#if IS_ENABLED(CONFIG_I2C_SLAVE) |
|---|
| 457 | + /* |
|---|
| 458 | + * If a peer master starts a xfer immediately after it queues a |
|---|
| 459 | + * master command, clear the queued master command and change |
|---|
| 460 | + * its state to 'pending'. To simplify handling of pending |
|---|
| 461 | + * cases, it uses S/W solution instead of H/W command queue |
|---|
| 462 | + * handling. |
|---|
| 463 | + */ |
|---|
| 464 | + if (unlikely(irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH)) { |
|---|
| 465 | + writel(readl(bus->base + ASPEED_I2C_CMD_REG) & |
|---|
| 466 | + ~ASPEED_I2CD_MASTER_CMDS_MASK, |
|---|
| 467 | + bus->base + ASPEED_I2C_CMD_REG); |
|---|
| 468 | + bus->master_state = ASPEED_I2C_MASTER_PENDING; |
|---|
| 469 | + dev_dbg(bus->dev, |
|---|
| 470 | + "master goes pending due to a slave start\n"); |
|---|
| 471 | + goto out_no_complete; |
|---|
| 472 | + } |
|---|
| 473 | +#endif /* CONFIG_I2C_SLAVE */ |
|---|
| 431 | 474 | if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { |
|---|
| 475 | + if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_NAK))) { |
|---|
| 476 | + bus->cmd_err = -ENXIO; |
|---|
| 477 | + bus->master_state = ASPEED_I2C_MASTER_INACTIVE; |
|---|
| 478 | + goto out_complete; |
|---|
| 479 | + } |
|---|
| 432 | 480 | pr_devel("no slave present at %02x\n", msg->addr); |
|---|
| 433 | | - status_ack |= ASPEED_I2CD_INTR_TX_NAK; |
|---|
| 481 | + irq_handled |= ASPEED_I2CD_INTR_TX_NAK; |
|---|
| 434 | 482 | bus->cmd_err = -ENXIO; |
|---|
| 435 | 483 | aspeed_i2c_do_stop(bus); |
|---|
| 436 | 484 | goto out_no_complete; |
|---|
| 437 | 485 | } |
|---|
| 438 | | - status_ack |= ASPEED_I2CD_INTR_TX_ACK; |
|---|
| 486 | + irq_handled |= ASPEED_I2CD_INTR_TX_ACK; |
|---|
| 439 | 487 | if (msg->len == 0) { /* SMBUS_QUICK */ |
|---|
| 440 | 488 | aspeed_i2c_do_stop(bus); |
|---|
| 441 | 489 | goto out_no_complete; |
|---|
| .. | .. |
|---|
| 450 | 498 | case ASPEED_I2C_MASTER_TX: |
|---|
| 451 | 499 | if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) { |
|---|
| 452 | 500 | dev_dbg(bus->dev, "slave NACKed TX\n"); |
|---|
| 453 | | - status_ack |= ASPEED_I2CD_INTR_TX_NAK; |
|---|
| 501 | + irq_handled |= ASPEED_I2CD_INTR_TX_NAK; |
|---|
| 454 | 502 | goto error_and_stop; |
|---|
| 455 | 503 | } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { |
|---|
| 456 | 504 | dev_err(bus->dev, "slave failed to ACK TX\n"); |
|---|
| 457 | 505 | goto error_and_stop; |
|---|
| 458 | 506 | } |
|---|
| 459 | | - status_ack |= ASPEED_I2CD_INTR_TX_ACK; |
|---|
| 460 | | - /* fallthrough intended */ |
|---|
| 507 | + irq_handled |= ASPEED_I2CD_INTR_TX_ACK; |
|---|
| 508 | + fallthrough; |
|---|
| 461 | 509 | case ASPEED_I2C_MASTER_TX_FIRST: |
|---|
| 462 | 510 | if (bus->buf_index < msg->len) { |
|---|
| 463 | 511 | bus->master_state = ASPEED_I2C_MASTER_TX; |
|---|
| .. | .. |
|---|
| 473 | 521 | /* RX may not have completed yet (only address cycle) */ |
|---|
| 474 | 522 | if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE)) |
|---|
| 475 | 523 | goto out_no_complete; |
|---|
| 476 | | - /* fallthrough intended */ |
|---|
| 524 | + fallthrough; |
|---|
| 477 | 525 | case ASPEED_I2C_MASTER_RX: |
|---|
| 478 | 526 | if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) { |
|---|
| 479 | 527 | dev_err(bus->dev, "master failed to RX\n"); |
|---|
| 480 | 528 | goto error_and_stop; |
|---|
| 481 | 529 | } |
|---|
| 482 | | - status_ack |= ASPEED_I2CD_INTR_RX_DONE; |
|---|
| 530 | + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; |
|---|
| 483 | 531 | |
|---|
| 484 | 532 | recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; |
|---|
| 485 | 533 | msg->buf[bus->buf_index++] = recv_byte; |
|---|
| .. | .. |
|---|
| 507 | 555 | goto out_no_complete; |
|---|
| 508 | 556 | case ASPEED_I2C_MASTER_STOP: |
|---|
| 509 | 557 | if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) { |
|---|
| 510 | | - dev_err(bus->dev, "master failed to STOP\n"); |
|---|
| 558 | + dev_err(bus->dev, |
|---|
| 559 | + "master failed to STOP. irq_status:0x%x\n", |
|---|
| 560 | + irq_status); |
|---|
| 511 | 561 | bus->cmd_err = -EIO; |
|---|
| 512 | 562 | /* Do not STOP as we have already tried. */ |
|---|
| 513 | 563 | } else { |
|---|
| 514 | | - status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP; |
|---|
| 564 | + irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; |
|---|
| 515 | 565 | } |
|---|
| 516 | 566 | |
|---|
| 517 | 567 | bus->master_state = ASPEED_I2C_MASTER_INACTIVE; |
|---|
| .. | .. |
|---|
| 541 | 591 | bus->master_xfer_result = bus->msgs_index + 1; |
|---|
| 542 | 592 | complete(&bus->cmd_complete); |
|---|
| 543 | 593 | out_no_complete: |
|---|
| 544 | | - if (irq_status != status_ack) |
|---|
| 545 | | - dev_err(bus->dev, |
|---|
| 546 | | - "irq handled != irq. expected 0x%08x, but was 0x%08x\n", |
|---|
| 547 | | - irq_status, status_ack); |
|---|
| 548 | | - return !!irq_status; |
|---|
| 594 | + return irq_handled; |
|---|
| 549 | 595 | } |
|---|
| 550 | 596 | |
|---|
| 551 | 597 | static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) |
|---|
| 552 | 598 | { |
|---|
| 553 | 599 | struct aspeed_i2c_bus *bus = dev_id; |
|---|
| 554 | | - bool ret; |
|---|
| 600 | + u32 irq_received, irq_remaining, irq_handled; |
|---|
| 555 | 601 | |
|---|
| 556 | 602 | spin_lock(&bus->lock); |
|---|
| 603 | + irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 604 | + /* Ack all interrupts except for Rx done */ |
|---|
| 605 | + writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, |
|---|
| 606 | + bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 607 | + readl(bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 608 | + irq_received &= ASPEED_I2CD_INTR_RECV_MASK; |
|---|
| 609 | + irq_remaining = irq_received; |
|---|
| 557 | 610 | |
|---|
| 558 | 611 | #if IS_ENABLED(CONFIG_I2C_SLAVE) |
|---|
| 559 | | - if (IS_ENABLED(CONFIG_I2C_SLAVE) && aspeed_i2c_slave_irq(bus)) { |
|---|
| 560 | | - dev_dbg(bus->dev, "irq handled by slave.\n"); |
|---|
| 561 | | - ret = true; |
|---|
| 562 | | - goto out; |
|---|
| 612 | + /* |
|---|
| 613 | + * In most cases, interrupt bits will be set one by one, although |
|---|
| 614 | + * multiple interrupt bits could be set at the same time. It's also |
|---|
| 615 | + * possible that master interrupt bits could be set along with slave |
|---|
| 616 | + * interrupt bits. Each case needs to be handled using corresponding |
|---|
| 617 | + * handlers depending on the current state. |
|---|
| 618 | + */ |
|---|
| 619 | + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE && |
|---|
| 620 | + bus->master_state != ASPEED_I2C_MASTER_PENDING) { |
|---|
| 621 | + irq_handled = aspeed_i2c_master_irq(bus, irq_remaining); |
|---|
| 622 | + irq_remaining &= ~irq_handled; |
|---|
| 623 | + if (irq_remaining) |
|---|
| 624 | + irq_handled |= aspeed_i2c_slave_irq(bus, irq_remaining); |
|---|
| 625 | + } else { |
|---|
| 626 | + irq_handled = aspeed_i2c_slave_irq(bus, irq_remaining); |
|---|
| 627 | + irq_remaining &= ~irq_handled; |
|---|
| 628 | + if (irq_remaining) |
|---|
| 629 | + irq_handled |= aspeed_i2c_master_irq(bus, |
|---|
| 630 | + irq_remaining); |
|---|
| 563 | 631 | } |
|---|
| 632 | + |
|---|
| 633 | + /* |
|---|
| 634 | + * Start a pending master command at here if a slave operation is |
|---|
| 635 | + * completed. |
|---|
| 636 | + */ |
|---|
| 637 | + if (bus->master_state == ASPEED_I2C_MASTER_PENDING && |
|---|
| 638 | + bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) |
|---|
| 639 | + aspeed_i2c_do_start(bus); |
|---|
| 640 | +#else |
|---|
| 641 | + irq_handled = aspeed_i2c_master_irq(bus, irq_remaining); |
|---|
| 564 | 642 | #endif /* CONFIG_I2C_SLAVE */ |
|---|
| 565 | 643 | |
|---|
| 566 | | - ret = aspeed_i2c_master_irq(bus); |
|---|
| 644 | + irq_remaining &= ~irq_handled; |
|---|
| 645 | + if (irq_remaining) |
|---|
| 646 | + dev_err(bus->dev, |
|---|
| 647 | + "irq handled != irq. expected 0x%08x, but was 0x%08x\n", |
|---|
| 648 | + irq_received, irq_handled); |
|---|
| 567 | 649 | |
|---|
| 568 | | -#if IS_ENABLED(CONFIG_I2C_SLAVE) |
|---|
| 569 | | -out: |
|---|
| 570 | | -#endif |
|---|
| 650 | + /* Ack Rx done */ |
|---|
| 651 | + if (irq_received & ASPEED_I2CD_INTR_RX_DONE) { |
|---|
| 652 | + writel(ASPEED_I2CD_INTR_RX_DONE, |
|---|
| 653 | + bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 654 | + readl(bus->base + ASPEED_I2C_INTR_STS_REG); |
|---|
| 655 | + } |
|---|
| 571 | 656 | spin_unlock(&bus->lock); |
|---|
| 572 | | - return ret ? IRQ_HANDLED : IRQ_NONE; |
|---|
| 657 | + return irq_remaining ? IRQ_NONE : IRQ_HANDLED; |
|---|
| 573 | 658 | } |
|---|
| 574 | 659 | |
|---|
| 575 | 660 | static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, |
|---|
| .. | .. |
|---|
| 577 | 662 | { |
|---|
| 578 | 663 | struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap); |
|---|
| 579 | 664 | unsigned long time_left, flags; |
|---|
| 580 | | - int ret = 0; |
|---|
| 581 | 665 | |
|---|
| 582 | 666 | spin_lock_irqsave(&bus->lock, flags); |
|---|
| 583 | 667 | bus->cmd_err = 0; |
|---|
| 584 | 668 | |
|---|
| 585 | | - /* If bus is busy, attempt recovery. We assume a single master |
|---|
| 586 | | - * environment. |
|---|
| 587 | | - */ |
|---|
| 588 | | - if (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS) { |
|---|
| 669 | + /* If bus is busy in a single master environment, attempt recovery. */ |
|---|
| 670 | + if (!bus->multi_master && |
|---|
| 671 | + (readl(bus->base + ASPEED_I2C_CMD_REG) & |
|---|
| 672 | + ASPEED_I2CD_BUS_BUSY_STS)) { |
|---|
| 673 | + int ret; |
|---|
| 674 | + |
|---|
| 589 | 675 | spin_unlock_irqrestore(&bus->lock, flags); |
|---|
| 590 | 676 | ret = aspeed_i2c_recover_bus(bus); |
|---|
| 591 | 677 | if (ret) |
|---|
| .. | .. |
|---|
| 605 | 691 | time_left = wait_for_completion_timeout(&bus->cmd_complete, |
|---|
| 606 | 692 | bus->adap.timeout); |
|---|
| 607 | 693 | |
|---|
| 608 | | - if (time_left == 0) |
|---|
| 694 | + if (time_left == 0) { |
|---|
| 695 | + /* |
|---|
| 696 | + * In a multi-master setup, if a timeout occurs, attempt |
|---|
| 697 | + * recovery. But if the bus is idle, we still need to reset the |
|---|
| 698 | + * i2c controller to clear the remaining interrupts. |
|---|
| 699 | + */ |
|---|
| 700 | + if (bus->multi_master && |
|---|
| 701 | + (readl(bus->base + ASPEED_I2C_CMD_REG) & |
|---|
| 702 | + ASPEED_I2CD_BUS_BUSY_STS)) |
|---|
| 703 | + aspeed_i2c_recover_bus(bus); |
|---|
| 704 | + else |
|---|
| 705 | + aspeed_i2c_reset(bus); |
|---|
| 706 | + |
|---|
| 707 | + /* |
|---|
| 708 | + * If timed out and the state is still pending, drop the pending |
|---|
| 709 | + * master command. |
|---|
| 710 | + */ |
|---|
| 711 | + spin_lock_irqsave(&bus->lock, flags); |
|---|
| 712 | + if (bus->master_state == ASPEED_I2C_MASTER_PENDING) |
|---|
| 713 | + bus->master_state = ASPEED_I2C_MASTER_INACTIVE; |
|---|
| 714 | + spin_unlock_irqrestore(&bus->lock, flags); |
|---|
| 715 | + |
|---|
| 609 | 716 | return -ETIMEDOUT; |
|---|
| 610 | | - else |
|---|
| 611 | | - return bus->master_xfer_result; |
|---|
| 717 | + } |
|---|
| 718 | + |
|---|
| 719 | + return bus->master_xfer_result; |
|---|
| 612 | 720 | } |
|---|
| 613 | 721 | |
|---|
| 614 | 722 | static u32 aspeed_i2c_functionality(struct i2c_adapter *adap) |
|---|
| .. | .. |
|---|
| 648 | 756 | __aspeed_i2c_reg_slave(bus, client->addr); |
|---|
| 649 | 757 | |
|---|
| 650 | 758 | bus->slave = client; |
|---|
| 651 | | - bus->slave_state = ASPEED_I2C_SLAVE_STOP; |
|---|
| 759 | + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; |
|---|
| 652 | 760 | spin_unlock_irqrestore(&bus->lock, flags); |
|---|
| 653 | 761 | |
|---|
| 654 | 762 | return 0; |
|---|
| .. | .. |
|---|
| 803 | 911 | if (ret < 0) |
|---|
| 804 | 912 | return ret; |
|---|
| 805 | 913 | |
|---|
| 806 | | - if (!of_property_read_bool(pdev->dev.of_node, "multi-master")) |
|---|
| 914 | + if (of_property_read_bool(pdev->dev.of_node, "multi-master")) |
|---|
| 915 | + bus->multi_master = true; |
|---|
| 916 | + else |
|---|
| 807 | 917 | fun_ctrl_reg |= ASPEED_I2CD_MULTI_MASTER_DIS; |
|---|
| 808 | 918 | |
|---|
| 809 | 919 | /* Enable Master Mode */ |
|---|
| .. | .. |
|---|
| 850 | 960 | .compatible = "aspeed,ast2500-i2c-bus", |
|---|
| 851 | 961 | .data = aspeed_i2c_25xx_get_clk_reg_val, |
|---|
| 852 | 962 | }, |
|---|
| 963 | + { |
|---|
| 964 | + .compatible = "aspeed,ast2600-i2c-bus", |
|---|
| 965 | + .data = aspeed_i2c_25xx_get_clk_reg_val, |
|---|
| 966 | + }, |
|---|
| 853 | 967 | { }, |
|---|
| 854 | 968 | }; |
|---|
| 855 | 969 | MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table); |
|---|
| .. | .. |
|---|
| 891 | 1005 | if (ret < 0) { |
|---|
| 892 | 1006 | dev_err(&pdev->dev, |
|---|
| 893 | 1007 | "Could not read bus-frequency property\n"); |
|---|
| 894 | | - bus->bus_frequency = 100000; |
|---|
| 1008 | + bus->bus_frequency = I2C_MAX_STANDARD_MODE_FREQ; |
|---|
| 895 | 1009 | } |
|---|
| 896 | 1010 | |
|---|
| 897 | 1011 | match = of_match_node(aspeed_i2c_bus_of_table, pdev->dev.of_node); |
|---|
| .. | .. |
|---|
| 906 | 1020 | init_completion(&bus->cmd_complete); |
|---|
| 907 | 1021 | bus->adap.owner = THIS_MODULE; |
|---|
| 908 | 1022 | bus->adap.retries = 0; |
|---|
| 909 | | - bus->adap.timeout = 5 * HZ; |
|---|
| 910 | 1023 | bus->adap.algo = &aspeed_i2c_algo; |
|---|
| 911 | 1024 | bus->adap.dev.parent = &pdev->dev; |
|---|
| 912 | 1025 | bus->adap.dev.of_node = pdev->dev.of_node; |
|---|