[PATCH 2/2] i2c: aspeed: cleanup driver
Brendan Higgins
brendanhiggins at google.com
Sun Aug 21 11:34:18 AEST 2016
Rewrote most of master IRQ handler, xfer functions, and error recovery.
Minor refactor of probing functions. Added remove functions.
---
drivers/i2c/busses/i2c-aspeed.c | 932 ++++++++++++++--------------------------
1 file changed, 318 insertions(+), 614 deletions(-)
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index ece5aa3..542ddef 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -1,5 +1,5 @@
/*
- * I2C adapter for the ASPEED I2C bus access.
+ * I2C adapter for the ASPEED I2C bus.
*
* Copyright (C) 2012-2020 ASPEED Technology Inc.
* Copyright 2015 IBM Corporation
@@ -7,9 +7,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * History:
- * 2012.07.26: Initial version [Ryan Chen]
*/
#include <linux/kernel.h>
@@ -18,76 +15,29 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
-
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/irq.h>
#include <asm/io.h>
-#if defined(CONFIG_COLDFIRE)
-#include <asm/arch/regs-iic.h>
-#include <asm/arch/ast_i2c.h>
-#else
-//#include <plat/regs-iic.h>
-//#include <plat/ast_i2c.h>
-#endif
-
-#define BYTE_MODE 0
-#define BUFF_MODE 1
-#define DEC_DMA_MODE 2
-#define INC_DMA_MODE 3
-
/* I2C Register */
#define I2C_FUN_CTRL_REG 0x00
-#define I2C_AC_TIMING_REG1 0x04
-#define I2C_AC_TIMING_REG2 0x08
-#define I2C_INTR_CTRL_REG 0x0c
-#define I2C_INTR_STS_REG 0x10
-#define I2C_CMD_REG 0x14
-#define I2C_DEV_ADDR_REG 0x18
-#define I2C_BUF_CTRL_REG 0x1c
-#define I2C_BYTE_BUF_REG 0x20
-#define I2C_DMA_BASE_REG 0x24
-#define I2C_DMA_LEN_REG 0x28
-
-#define AST_I2C_DMA_SIZE 0
-#define AST_I2C_PAGE_SIZE 256
-#define MASTER_XFER_MODE BUFF_MODE
-#define SLAVE_XFER_MODE BYTE_MODE
-#define NUM_BUS 14
-
-/*AST I2C Register Definition */
-// if defined(AST_SOC_G4)
-#define AST_I2C_POOL_BUFF_2048
-#define AST_I2C_GLOBAL_REG 0x00
-#define AST_I2C_DEVICE1 0x40
-#define AST_I2C_DEVICE2 0x80
-#define AST_I2C_DEVICE3 0xc0
-#define AST_I2C_DEVICE4 0x100
-#define AST_I2C_DEVICE5 0x140
-#define AST_I2C_DEVICE6 0x180
-#define AST_I2C_DEVICE7 0x1c0
-#define AST_I2C_BUFFER_POOL2 0x200
-#define AST_I2C_DEVICE8 0x300
-#define AST_I2C_DEVICE9 0x340
-#define AST_I2C_DEVICE10 0x380
-#define AST_I2C_DEVICE11 0x3c0
-#define AST_I2C_DEVICE12 0x400
-#define AST_I2C_DEVICE13 0x440
-#define AST_I2C_DEVICE14 0x480
-#define AST_I2C_BUFFER_POOL1 0x800
+#define I2C_AC_TIMING_REG1 0x04
+#define I2C_AC_TIMING_REG2 0x08
+#define I2C_INTR_CTRL_REG 0x0c
+#define I2C_INTR_STS_REG 0x10
+#define I2C_CMD_REG 0x14
+#define I2C_DEV_ADDR_REG 0x18
+#define I2C_BYTE_BUF_REG 0x20
+
+#define AST_I2C_NUM_BUS 14
/* Gloable Register Definition */
/* 0x00 : I2C Interrupt Status Register */
@@ -95,35 +45,15 @@
/* Device Register Definition */
/* 0x00 : I2CD Function Control Register */
-#define AST_I2CD_BUFF_SEL_MASK (0x7 << 20)
-#define AST_I2CD_BUFF_SEL(x) (x << 20) // page 0 ~ 7
-#define AST_I2CD_M_SDA_LOCK_EN (0x1 << 16)
#define AST_I2CD_MULTI_MASTER_DIS (0x1 << 15)
-#define AST_I2CD_M_SCL_DRIVE_EN (0x1 << 14)
-#define AST_I2CD_MSB_STS (0x1 << 9)
#define AST_I2CD_SDA_DRIVE_1T_EN (0x1 << 8)
-#define AST_I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7)
-#define AST_I2CD_M_HIGH_SPEED_EN (0x1 << 6)
-#define AST_I2CD_DEF_ADDR_EN (0x1 << 5)
-#define AST_I2CD_DEF_ALERT_EN (0x1 << 4)
-#define AST_I2CD_DEF_ARP_EN (0x1 << 3)
-#define AST_I2CD_DEF_GCALL_EN (0x1 << 2)
-#define AST_I2CD_SLAVE_EN (0x1 << 1)
-#define AST_I2CD_MASTER_EN (0x1 )
-
-/* 0x04 : I2CD Clock and AC Timing Control Register #1 */
-#define AST_I2CD_tBUF (0x1 << 28) // 0~7
-#define AST_I2CD_tHDSTA (0x1 << 24) // 0~7
-#define AST_I2CD_tACST (0x1 << 20) // 0~7
-#define AST_I2CD_tCKHIGH (0x1 << 16) // 0~7
-#define AST_I2CD_tCKLOW (0x1 << 12) // 0~7
-#define AST_I2CD_tHDDAT (0x1 << 10) // 0~7
-#define AST_I2CD_CLK_TO_BASE_DIV (0x1 << 8) // 0~3
-#define AST_I2CD_CLK_BASE_DIV (0x1 ) // 0~0xf
+#define AST_I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7)
+#define AST_I2CD_M_HIGH_SPEED_EN (0x1 << 6)
+#define AST_I2CD_SLAVE_EN (0x1 << 1)
+#define AST_I2CD_MASTER_EN (0x1)
/* 0x08 : I2CD Clock and AC Timing Control Register #2 */
-#define AST_I2CD_tTIMEOUT (0x1 ) // 0~7
-#define AST_NO_TIMEOUT_CTRL 0x0
+#define AST_NO_TIMEOUT_CTRL 0x0
/* 0x0c : I2CD Interrupt Control Register &
@@ -134,11 +64,6 @@
*/
#define AST_I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14)
#define AST_I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13)
-#define AST_I2CD_INTR_SMBUS_ALERT (0x1 << 12)
-#define AST_I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11)
-#define AST_I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10)
-#define AST_I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9)
-#define AST_I2CD_INTR_GCALL_ADDR (0x1 << 8)
#define AST_I2CD_INTR_SLAVE_MATCH (0x1 << 7)
#define AST_I2CD_INTR_SCL_TIMEOUT (0x1 << 6)
#define AST_I2CD_INTR_ABNORMAL (0x1 << 5)
@@ -149,82 +74,22 @@
#define AST_I2CD_INTR_TX_ACK (0x1 << 0)
/* 0x14 : I2CD Command/Status Register */
-#define AST_I2CD_SDA_OE (0x1 << 28)
-#define AST_I2CD_SDA_O (0x1 << 27)
-#define AST_I2CD_SCL_OE (0x1 << 26)
-#define AST_I2CD_SCL_O (0x1 << 25)
-#define AST_I2CD_TX_TIMING (0x1 << 24) // 0 ~3
-#define AST_I2CD_TX_STATUS (0x1 << 23)
-// Tx State Machine
-#define AST_I2CD_IDLE 0x0
-#define AST_I2CD_MACTIVE 0x8
-#define AST_I2CD_MSTART 0x9
-#define AST_I2CD_MSTARTR 0xa
-#define AST_I2CD_MSTOP 0xb
-#define AST_I2CD_MTXD 0xc
-#define AST_I2CD_MRXACK 0xd
-#define AST_I2CD_MRXD 0xe
-#define AST_I2CD_MTXACK 0xf
-#define AST_I2CD_SWAIT 0x1
-#define AST_I2CD_SRXD 0x4
-#define AST_I2CD_STXACK 0x5
-#define AST_I2CD_STXD 0x6
-#define AST_I2CD_SRXACK 0x7
-#define AST_I2CD_RECOVER 0x3
-
-#define AST_I2CD_SCL_LINE_STS (0x1 << 18)
-#define AST_I2CD_SDA_LINE_STS (0x1 << 17)
-#define AST_I2CD_BUS_BUSY_STS (0x1 << 16)
-#define AST_I2CD_SDA_OE_OUT_DIR (0x1 << 15)
-#define AST_I2CD_SDA_O_OUT_DIR (0x1 << 14)
-#define AST_I2CD_SCL_OE_OUT_DIR (0x1 << 13)
-#define AST_I2CD_SCL_O_OUT_DIR (0x1 << 12)
-#define AST_I2CD_BUS_RECOVER_CMD_EN (0x1 << 11)
-#define AST_I2CD_S_ALT_EN (0x1 << 10)
-// 0 : DMA Buffer, 1: Pool Buffer
-//AST1070 DMA register
-#define AST_I2CD_RX_DMA_ENABLE (0x1 << 9)
-#define AST_I2CD_TX_DMA_ENABLE (0x1 << 8)
+#define AST_I2CD_SCL_LINE_STS (0x1 << 18)
+#define AST_I2CD_SDA_LINE_STS (0x1 << 17)
+#define AST_I2CD_BUS_BUSY_STS (0x1 << 16)
+#define AST_I2CD_BUS_RECOVER_CMD (0x1 << 11)
/* Command Bit */
-#define AST_I2CD_RX_BUFF_ENABLE (0x1 << 7)
-#define AST_I2CD_TX_BUFF_ENABLE (0x1 << 6)
-#define AST_I2CD_M_STOP_CMD (0x1 << 5)
-#define AST_I2CD_M_S_RX_CMD_LAST (0x1 << 4)
-#define AST_I2CD_M_RX_CMD (0x1 << 3)
-#define AST_I2CD_S_TX_CMD (0x1 << 2)
-#define AST_I2CD_M_TX_CMD (0x1 << 1)
-#define AST_I2CD_M_START_CMD (0x1 )
+#define AST_I2CD_M_STOP_CMD (0x1 << 5)
+#define AST_I2CD_M_S_RX_CMD_LAST (0x1 << 4)
+#define AST_I2CD_M_RX_CMD (0x1 << 3)
+#define AST_I2CD_S_TX_CMD (0x1 << 2)
+#define AST_I2CD_M_TX_CMD (0x1 << 1)
+#define AST_I2CD_M_START_CMD (0x1)
/* 0x18 : I2CD Slave Device Address Register */
#define AST_I2CD_DEV_ADDR_MASK ((0x1 << 7) - 1)
-/* 0x1C : I2CD Pool Buffer Control Register */
-#define AST_I2CD_RX_BUF_ADDR_GET(x) ((x>> 24)& 0xff)
-#define AST_I2CD_RX_BUF_END_ADDR_SET(x) (x << 16)
-#define AST_I2CD_TX_DATA_BUF_END_SET(x) ((x&0xff) << 8)
-#define AST_I2CD_TX_DATA_BUF_GET(x) ((x >>8) & 0xff)
-#define AST_I2CD_BUF_BASE_ADDR_SET(x) (x & 0x3f)
-
-/* 0x20 : I2CD Transmit/Receive Byte Buffer Register */
-#define AST_I2CD_GET_MODE(x) ((x >> 8) & 0x1)
-
-#define AST_I2CD_RX_BYTE_BUFFER (0xff << 8)
-#define AST_I2CD_TX_BYTE_BUFFER (0xff )
-
-//1. usage flag , 2 size, 3. request address
-/* Use platform_data instead of module parameters */
-/* Fast Mode = 400 kHz, Standard = 100 kHz */
-//static int clock = 100; /* Default: 100 kHz */
-
-/* bitmask of commands that we wait for, in the cmd_pending mask */
-#define AST_I2CD_CMDS (AST_I2CD_BUS_RECOVER_CMD_EN | \
- AST_I2CD_M_STOP_CMD | \
- AST_I2CD_M_RX_CMD | \
- AST_I2CD_M_TX_CMD)
-
-static const int ast_i2c_n_busses = 14;
-
#if IS_ENABLED(CONFIG_I2C_SLAVE)
enum ast_i2c_slave_state {
AST_I2C_SLAVE_START,
@@ -238,33 +103,20 @@ enum ast_i2c_slave_state {
struct ast_i2c_bus {
/* TODO: find a better way to do this */
- struct ast_i2c_dev *i2c_dev;
- struct device *dev;
-
- void __iomem *base; /* virtual */
- u32 state; //I2C xfer mode state matchine
- struct i2c_adapter adap;
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ spinlock_t lock;
+ struct completion cmd_complete;
+ int irq;
+ /* Transaction state. */
+ struct i2c_msg *msg;
+ int msg_pos;
+ u32 cmd_err;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
- struct i2c_client *slave;
- enum ast_i2c_slave_state slave_state;
+ struct i2c_client *slave;
+ enum ast_i2c_slave_state slave_state;
#endif
- u32 bus_clk;
- struct clk *pclk;
- int irq;
-
- /* i2c transfer state. this is accessed from both process and IRQ
- * context, so is protected by cmd_lock */
- spinlock_t cmd_lock;
- bool send_start;
- bool send_stop; /* last message of an xfer? */
- bool query_len;
- struct i2c_msg *msg; /* current tx/rx message */
- int msg_pos; /* current byte position in message */
-
- struct completion cmd_complete;
- u32 cmd_sent;
- u32 cmd_pending;
- u32 cmd_err;
};
struct ast_i2c_controller {
@@ -284,263 +136,57 @@ static inline u32 ast_i2c_read(struct ast_i2c_bus *bus, u32 reg)
return readl(bus->base + reg);
}
-static u32 select_i2c_clock(struct ast_i2c_bus *bus)
-{
- unsigned int inc = 0, div, divider_ratio;
- u32 SCL_Low, SCL_High, data;
-
- divider_ratio = clk_get_rate(bus->pclk) / bus->bus_clk;
- for (div = 0; divider_ratio >= 16; div++) {
- inc |= (divider_ratio & 1);
- divider_ratio >>= 1;
- }
- divider_ratio += inc;
- SCL_Low = (divider_ratio >> 1) - 1;
- SCL_High = divider_ratio - SCL_Low - 2;
- data = 0x77700300 | (SCL_High << 16) | (SCL_Low << 12) | div;
- return data;
-}
-
-static void ast_i2c_dev_init(struct ast_i2c_bus *bus)
-{
- /* reset device: disable master & slave functions */
- ast_i2c_write(bus, 0, I2C_FUN_CTRL_REG);
-
- dev_dbg(bus->dev, "bus_clk %u, pclk %lu\n",
- bus->bus_clk, clk_get_rate(bus->pclk));
-
- /* Set AC Timing */
- if(bus->bus_clk / 1000 > 400) {
- ast_i2c_write(bus, ast_i2c_read(bus, I2C_FUN_CTRL_REG) |
- AST_I2CD_M_HIGH_SPEED_EN |
- AST_I2CD_M_SDA_DRIVE_1T_EN |
- AST_I2CD_SDA_DRIVE_1T_EN,
- I2C_FUN_CTRL_REG);
-
- ast_i2c_write(bus, 0x3, I2C_AC_TIMING_REG2);
- ast_i2c_write(bus, select_i2c_clock(bus), I2C_AC_TIMING_REG1);
- } else {
- ast_i2c_write(bus, select_i2c_clock(bus), I2C_AC_TIMING_REG1);
- ast_i2c_write(bus, AST_NO_TIMEOUT_CTRL, I2C_AC_TIMING_REG2);
- }
-
- dev_dbg(bus->dev, "reg1: %x, reg2: %x, fun_ctrl: %x\n",
- ast_i2c_read(bus, I2C_AC_TIMING_REG1),
- ast_i2c_read(bus, I2C_AC_TIMING_REG2),
- ast_i2c_read(bus, I2C_FUN_CTRL_REG));
-
- /* Enable Master Mode */
- ast_i2c_write(bus, ast_i2c_read(bus, I2C_FUN_CTRL_REG)
- | AST_I2CD_MASTER_EN, I2C_FUN_CTRL_REG);
-
- /* Set interrupt generation of I2C controller */
- ast_i2c_write(bus, AST_I2CD_INTR_SDA_DL_TIMEOUT |
- AST_I2CD_INTR_BUS_RECOVER_DONE |
- AST_I2CD_INTR_SCL_TIMEOUT |
- AST_I2CD_INTR_ABNORMAL |
- AST_I2CD_INTR_NORMAL_STOP |
- AST_I2CD_INTR_ARBIT_LOSS |
- AST_I2CD_INTR_RX_DONE |
- AST_I2CD_INTR_TX_NAK |
- AST_I2CD_INTR_TX_ACK,
- I2C_INTR_CTRL_REG);
-
-}
-
-static void ast_i2c_issue_cmd(struct ast_i2c_bus *bus, u32 cmd)
-{
- dev_dbg(bus->dev, "issuing cmd: %x\n", cmd);
- bus->cmd_err = 0;
- bus->cmd_sent = cmd;
- bus->cmd_pending = cmd & AST_I2CD_CMDS;
- ast_i2c_write(bus, cmd, I2C_CMD_REG);
-}
-
-static int ast_i2c_issue_oob_command(struct ast_i2c_bus *bus, u32 cmd)
-{
- spin_lock_irq(&bus->cmd_lock);
- init_completion(&bus->cmd_complete);
- ast_i2c_issue_cmd(bus, cmd);
- spin_unlock_irq(&bus->cmd_lock);
- return wait_for_completion_interruptible_timeout(&bus->cmd_complete,
- bus->adap.timeout*HZ);
-}
-
-static u8 ast_i2c_bus_error_recover(struct ast_i2c_bus *bus)
+static u8 ast_i2c_recover_bus(struct ast_i2c_bus *bus)
{
- u32 sts, i;
- int r;
+ u32 sts;
+ unsigned long time_left;
+ unsigned long flags;
+ int ret = 0;
- //Check 0x14's SDA and SCL status
+ spin_lock_irqsave(&bus->lock, flags);
sts = ast_i2c_read(bus,I2C_CMD_REG);
-
+ /* Bus is idle: no recovery needed. */
if ((sts & AST_I2CD_SDA_LINE_STS) && (sts & AST_I2CD_SCL_LINE_STS)) {
- //Means bus is idle.
- dev_dbg(bus->dev,
- "I2C bus is idle. I2C slave doesn't exist?!\n");
- return -1;
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return 0;
}
+ dev_dbg(bus->dev, "bus hung (status %x), attempting recovery\n", sts);
- dev_dbg(bus->dev, "I2C bus hung (status %x), attempting recovery\n",
- sts);
-
+ /* Bus held: put bus in stop state. */
if ((sts & AST_I2CD_SDA_LINE_STS) && !(sts & AST_I2CD_SCL_LINE_STS)) {
- //if SDA == 1 and SCL == 0, it means the master is locking the bus.
- //Send a stop command to unlock the bus.
- dev_dbg(bus->dev, "I2C's master is locking the bus, try to stop it.\n");
-
- init_completion(&bus->cmd_complete);
-
ast_i2c_write(bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG);
-
- r = wait_for_completion_interruptible_timeout(&bus->cmd_complete,
- bus->adap.timeout*HZ);
-
- if (bus->cmd_err) {
- dev_dbg(bus->dev, "recovery error \n");
- return -1;
- }
-
- if (r == 0) {
- dev_dbg(bus->dev, "recovery timed out\n");
- return -1;
- } else {
- dev_dbg(bus->dev, "Recovery successfully\n");
- return 0;
- }
-
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ);
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (time_left == 0)
+ ret = -ETIMEDOUT;
+ else if (bus->cmd_err)
+ ret = -EIO;
+ /* Bus error. */
} else if (!(sts & AST_I2CD_SDA_LINE_STS)) {
- //else if SDA == 0, the device is dead. We need to reset the bus
- //And do the recovery command.
- dev_dbg(bus->dev, "I2C's slave is dead, try to recover it\n");
- for (i = 0; i < 2; i++) {
- ast_i2c_dev_init(bus);
- ast_i2c_issue_oob_command(bus,
- AST_I2CD_BUS_RECOVER_CMD_EN);
- if (bus->cmd_err != 0) {
- dev_dbg(bus->dev, "ERROR!! Failed to do recovery command(0x%08x)\n", bus->cmd_err);
- return -1;
- }
- //Check 0x14's SDA and SCL status
- sts = ast_i2c_read(bus,I2C_CMD_REG);
- if (sts & AST_I2CD_SDA_LINE_STS) //Recover OK
- break;
- }
- if (i == 2) {
- dev_dbg(bus->dev, "ERROR!! recover failed\n");
- return -1;
- }
- } else {
- dev_dbg(bus->dev, "Don't know how to handle this case?!\n");
- return -1;
+ ast_i2c_write(bus, AST_I2CD_BUS_RECOVER_CMD, I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ);
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (time_left == 0)
+ ret = -ETIMEDOUT;
+ else if (bus->cmd_err)
+ ret = -EIO;
+ /* Recovery failed. */
+ else if (!(ast_i2c_read(bus,I2C_CMD_REG) &
+ AST_I2CD_SDA_LINE_STS))
+ ret = -EIO;
}
- dev_dbg(bus->dev, "Recovery successfully\n");
- return 0;
-}
-
-static int ast_i2c_wait_bus_not_busy(struct ast_i2c_bus *bus)
-{
- int timeout = 2; //TODO number
-
- while (ast_i2c_read(bus, I2C_CMD_REG) & AST_I2CD_BUS_BUSY_STS) {
- ast_i2c_bus_error_recover(bus);
- if(timeout <= 0)
- break;
- timeout--;
- msleep(2);
- }
-
- return timeout <= 0 ? EAGAIN : 0;
-}
-
-static bool ast_i2c_do_byte_xfer(struct ast_i2c_bus *bus)
-{
- u32 cmd, data;
-
- if (bus->send_start) {
- dev_dbg(bus->dev, "%s %c: addr %x start, len %d\n", __func__,
- bus->msg->flags & I2C_M_RD ? 'R' : 'W',
- bus->msg->addr, bus->msg->len);
-
- data = bus->msg->addr << 1;
- if (bus->msg->flags & I2C_M_RD)
- data |= 0x1;
-
- cmd = AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD;
- if (bus->send_stop && bus->msg->len == 0)
- cmd |= AST_I2CD_M_STOP_CMD;
-
- ast_i2c_write(bus, data, I2C_BYTE_BUF_REG);
- ast_i2c_issue_cmd(bus, cmd);
-
- } else if (bus->msg_pos < bus->msg->len){
- bool is_last = bus->msg_pos + 1 == bus->msg->len;
-
- dev_dbg(bus->dev, "%s %c%c: addr %x xfer %d, len %d\n",
- __func__,
- bus->msg->flags & I2C_M_RD ? 'R' : 'W',
- bus->send_stop && is_last ? 'T' : '-',
- bus->msg->addr,
- bus->msg_pos, bus->msg->len);
-
- if (bus->msg->flags & I2C_M_RD) {
- cmd = AST_I2CD_M_RX_CMD;
- if (bus->send_stop && is_last && !bus->query_len)
- cmd |= AST_I2CD_M_S_RX_CMD_LAST |
- AST_I2CD_M_STOP_CMD;
-
- } else {
- cmd = AST_I2CD_M_TX_CMD;
- ast_i2c_write(bus, bus->msg->buf[bus->msg_pos],
- I2C_BYTE_BUF_REG);
-
- if (bus->send_stop && is_last)
- cmd |= AST_I2CD_M_STOP_CMD;
- }
- ast_i2c_issue_cmd(bus, cmd);
-
- } else {
- return false;
- }
-
- return true;
-}
-
-//TX/Rx Done
-static void ast_i2c_master_xfer_done(struct ast_i2c_bus *bus)
-{
- bool next_msg_queued;
-
- dev_dbg(bus->dev, "%s xfer %d%c\n", __func__,
- bus->msg_pos,
- bus->send_start ? 'S' : ' ');
-
- if (bus->send_start) {
- bus->send_start = false;
- } else {
-
- if (bus->msg->flags & I2C_M_RD) {
- uint8_t data;
-
- data = (ast_i2c_read(bus, I2C_BYTE_BUF_REG) &
- AST_I2CD_RX_BYTE_BUFFER) >> 8;
-
- if (bus->query_len) {
- bus->msg->len += data;
- bus->query_len = false;
- dev_dbg(bus->dev, "got rx len: %d\n",
- bus->msg->len -1);
- }
- bus->msg->buf[bus->msg_pos] = data;
- }
- bus->msg_pos++;
- }
-
- /* queue the next message. If there's none left, we notify the
- * waiter */
- next_msg_queued = ast_i2c_do_byte_xfer(bus);
- if (!next_msg_queued)
- complete(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return ret;
}
#if IS_ENABLED(CONFIG_I2C_SLAVE)
@@ -554,7 +200,7 @@ static bool ast_i2c_slave_irq(struct ast_i2c_bus *bus)
enum i2c_slave_event event;
struct i2c_client *slave = bus->slave;
- spin_lock(&bus->cmd_lock);
+ spin_lock(&bus->lock);
if (!slave) {
irq_handled = false;
goto out;
@@ -635,7 +281,7 @@ static bool ast_i2c_slave_irq(struct ast_i2c_bus *bus)
ast_i2c_write(bus, status_ack, I2C_INTR_STS_REG);
out:
- spin_unlock(&bus->cmd_lock);
+ spin_unlock(&bus->lock);
return irq_handled;
}
#endif
@@ -647,69 +293,43 @@ static bool ast_i2c_master_irq(struct ast_i2c_bus *bus)
AST_I2CD_INTR_SCL_TIMEOUT |
AST_I2CD_INTR_SDA_DL_TIMEOUT |
AST_I2CD_INTR_TX_NAK;
- u32 sts, cmd;
-
- spin_lock(&bus->cmd_lock);
-
- cmd = ast_i2c_read(bus, I2C_CMD_REG);
- sts = ast_i2c_read(bus, I2C_INTR_STS_REG);
-
- dev_dbg(bus->dev, "irq! status 0x%08x, cmd 0x%08x\n", sts, cmd);
-
- sts &= 0xffff;
- bus->state = cmd >> 19 & 0xf;
-
- /*
- * ack everything - this is safe because this driver makes master mode
- * and slave mode mutually exclusive on a single bus; thus, it is not
- * possible for a master to steal a slave IRQ in this way.
- */
- ast_i2c_write(bus, sts, I2C_INTR_STS_REG);
-
- bus->cmd_err |= sts & errs;
-
- /**
- * Mask-out pending commands that this interrupt has indicated are
- * complete. These checks need to cover all of the possible bits set
- * in the AST_I2CD_CMDS bitmask.
- */
- if (sts & AST_I2CD_INTR_TX_ACK)
- bus->cmd_pending &= ~AST_I2CD_M_TX_CMD;
-
- if (sts & AST_I2CD_INTR_RX_DONE)
- bus->cmd_pending &= ~AST_I2CD_M_RX_CMD;
-
- if (sts & AST_I2CD_INTR_NORMAL_STOP)
- bus->cmd_pending &= ~AST_I2CD_M_STOP_CMD;
-
- if (sts & AST_I2CD_INTR_BUS_RECOVER_DONE)
- bus->cmd_pending &= ~AST_I2CD_BUS_RECOVER_CMD_EN;
-
- /* if we've seen an error, notify our waiter */
- if (bus->cmd_err) {
- complete(&bus->cmd_complete);
+ u32 irq_status;
- /* still have work to do? We'll wait for the corresponding IRQ(s) for
- * that to complete. */
- } else if (bus->cmd_pending) {
- dev_dbg(bus->dev, "cmds pending: 0x%x\n", bus->cmd_pending);
+ spin_lock(&bus->lock);
+ irq_status = ast_i2c_read(bus, I2C_INTR_STS_REG);
+ bus->cmd_err |= irq_status & errs;
- /* message transfer complete */
- } else if (bus->msg) {
- ast_i2c_master_xfer_done(bus);
+ dev_dbg(bus->dev, "master irq status 0x%08x\n", irq_status);
- /* other (non-message) command complete: recovery, error stop. Notify
- * waiters. */
- } else if (bus->cmd_sent) {
+ /* No message to transfer. */
+ if (bus->cmd_err ||
+ (irq_status & AST_I2CD_INTR_NORMAL_STOP) ||
+ (irq_status & AST_I2CD_INTR_BUS_RECOVER_DONE)) {
complete(&bus->cmd_complete);
+ goto out;
+ } else if (!bus->msg || bus->msg_pos >= bus->msg->len)
+ goto out;
- } else {
- dev_err(bus->dev, "Invalid state (msg %p, pending %x)?",
- bus->msg, bus->cmd_pending);
+ if ((bus->msg->flags & I2C_M_RD) && (irq_status & AST_I2CD_INTR_RX_DONE)) {
+ bus->msg->buf[bus->msg_pos++] =
+ ast_i2c_read(bus, I2C_BYTE_BUF_REG) >> 8;
+ if (bus->msg_pos + 1 < bus->msg->len)
+ ast_i2c_write(bus, AST_I2CD_M_RX_CMD, I2C_CMD_REG);
+ else if (bus->msg_pos < bus->msg->len)
+ ast_i2c_write(bus, AST_I2CD_M_RX_CMD |
+ AST_I2CD_M_S_RX_CMD_LAST, I2C_CMD_REG);
+ } else if (!(bus->msg->flags & I2C_M_RD) && (irq_status & AST_I2CD_INTR_TX_ACK)) {
+ ast_i2c_write(bus, bus->msg->buf[bus->msg_pos++],
+ I2C_BYTE_BUF_REG);
+ ast_i2c_write(bus, AST_I2CD_M_TX_CMD, I2C_CMD_REG);
}
- spin_unlock(&bus->cmd_lock);
-
+ /* Transmission complete: notify caller. */
+ if (bus->msg_pos >= bus->msg->len)
+ complete(&bus->cmd_complete);
+out:
+ ast_i2c_write(bus, irq_status, I2C_INTR_STS_REG);
+ spin_unlock(&bus->lock);
return true;
}
@@ -731,95 +351,94 @@ static irqreturn_t ast_i2c_bus_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int ast_i2c_do_msgs_xfer(struct ast_i2c_bus *bus,
- struct i2c_msg *msgs, int num)
+static int ast_i2c_master_single_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
{
+ struct ast_i2c_bus *bus = adap->algo_data;
unsigned long flags;
- int i, ret = 0;
- u32 err, cmd;
-
- for (i = 0; i < num; i++) {
-
- spin_lock_irqsave(&bus->cmd_lock, flags);
- bus->msg = &msgs[i];
- bus->msg_pos = 0;
- bus->query_len = bus->msg->flags & I2C_M_RECV_LEN;
- bus->send_start = !(bus->msg->flags & I2C_M_NOSTART);
- bus->send_stop = !!(num == i+1);
- init_completion(&bus->cmd_complete);
-
- ast_i2c_do_byte_xfer(bus);
- spin_unlock_irqrestore(&bus->cmd_lock, flags);
-
- ret = wait_for_completion_interruptible_timeout(
- &bus->cmd_complete,
- bus->adap.timeout * HZ);
-
- spin_lock_irqsave(&bus->cmd_lock, flags);
- err = bus->cmd_err;
- cmd = bus->cmd_sent;
- bus->cmd_sent = 0;
- bus->msg = NULL;
- spin_unlock_irqrestore(&bus->cmd_lock, flags);
-
- if (!ret) {
- dev_dbg(bus->dev, "controller timed out\n");
- return -EIO;
- }
-
- if (err != 0) {
- if (cmd & AST_I2CD_M_STOP_CMD) {
- return -ETIMEDOUT;
- } else {
- dev_dbg(bus->dev, "send stop\n");
- ast_i2c_issue_oob_command(bus,
- AST_I2CD_M_STOP_CMD);
- return -EAGAIN;
- }
- }
+ u8 slave_addr;
+ u32 command = AST_I2CD_M_START_CMD | AST_I2CD_M_TX_CMD;
+ int ret = msg->len;
+ unsigned long time_left;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ bus->msg = msg;
+ bus->msg_pos = 0;
+ slave_addr = msg->addr << 1;
+ if (msg->flags & I2C_M_RD) {
+ slave_addr |= 1;
+ command |= AST_I2CD_M_RX_CMD;
}
+ ast_i2c_write(bus, slave_addr, I2C_BYTE_BUF_REG);
+ ast_i2c_write(bus, command, I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ * msg->len);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (bus->cmd_err)
+ ret = -EIO;
+ bus->msg = NULL;
+ spin_unlock_irqrestore(&bus->lock, flags);
- return num;
+ return ret;
}
-static int ast_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg *msgs, int num)
+static int ast_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
{
struct ast_i2c_bus *bus = adap->algo_data;
- int ret, i;
- int sts;
-
- sts = ast_i2c_read(bus, I2C_CMD_REG);
- dev_dbg(bus->dev, "state[%x], SCL[%d], SDA[%d], BUS[%d]\n",
- (sts >> 19) & 0xf,
- (sts >> 18) & 0x1,
- (sts >> 17) & 0x1,
- (sts >> 16) & 1);
- /*
- * Wait for the bus to become free.
- */
+ int ret;
+ int i;
+ unsigned long flags;
+ unsigned long time_left;
- ret = ast_i2c_wait_bus_not_busy(bus);
- if (ret) {
- dev_err(&adap->dev, "i2c_ast: timeout waiting for bus free\n");
- goto out;
+ /* If bus is busy, attempt recovery. We assume a single master
+ * environment.
+ */
+ if (ast_i2c_read(bus, I2C_CMD_REG) & AST_I2CD_BUS_BUSY_STS) {
+ ret = ast_i2c_recover_bus(bus);
+ if (ret)
+ return ret;
}
- for (i = adap->retries; i >= 0; i--) {
- if (i != 0)
- dev_dbg(&adap->dev, "Do retrying transmission [%d]\n",i);
-
- ret = ast_i2c_do_msgs_xfer(bus, msgs, num);
- if (ret != -EAGAIN)
- goto out;
-
- udelay(100);
+ for (i = 0; i < num; i++) {
+ ret = ast_i2c_master_single_xfer(adap, &msgs[i]);
+ if (ret < 0)
+ break;
+ /* TODO: Support other forms of I2C protocol mangling. */
+ if (msgs[i].flags & I2C_M_STOP) {
+ spin_lock_irqsave(&bus->lock, flags);
+ ast_i2c_write(bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete,
+ bus->adap.timeout * HZ);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+ }
}
- ret = -EREMOTEIO;
-out:
+ spin_lock_irqsave(&bus->lock, flags);
+ ast_i2c_write(bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
- return ret;
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ /* If nothing went wrong, return number of messages transferred. */
+ if (ret < 0)
+ return ret;
+ else
+ return i;
}
static u32 ast_i2c_functionality(struct i2c_adapter *adap)
@@ -836,9 +455,9 @@ static int ast_i2c_reg_slave(struct i2c_client *client)
u32 func_ctrl_reg_val;
bus = client->adapter->algo_data;
- spin_lock_irqsave(&bus->cmd_lock, flags);
+ spin_lock_irqsave(&bus->lock, flags);
if (bus->slave) {
- spin_unlock_irqrestore(&bus->cmd_lock, flags);
+ spin_unlock_irqrestore(&bus->lock, flags);
return -EINVAL;
}
@@ -856,7 +475,7 @@ static int ast_i2c_reg_slave(struct i2c_client *client)
bus->slave = client;
bus->slave_state = AST_I2C_SLAVE_STOP;
- spin_unlock_irqrestore(&bus->cmd_lock, flags);
+ spin_unlock_irqrestore(&bus->lock, flags);
return 0;
}
@@ -864,12 +483,11 @@ static int ast_i2c_unreg_slave(struct i2c_client *client)
{
struct ast_i2c_bus *bus = client->adapter->algo_data;
unsigned long flags;
- u32 addr_reg_val;
u32 func_ctrl_reg_val;
- spin_lock_irqsave(&bus->cmd_lock, flags);
+ spin_lock_irqsave(&bus->lock, flags);
if (!bus->slave) {
- spin_unlock_irqrestore(&bus->cmd_lock, flags);
+ spin_unlock_irqrestore(&bus->lock, flags);
return -EINVAL;
}
@@ -880,13 +498,13 @@ static int ast_i2c_unreg_slave(struct i2c_client *client)
ast_i2c_write(bus, func_ctrl_reg_val, I2C_FUN_CTRL_REG);
bus->slave = NULL;
- spin_unlock_irqrestore(&bus->cmd_lock, flags);
+ spin_unlock_irqrestore(&bus->lock, flags);
return 0;
}
#endif
static const struct i2c_algorithm i2c_ast_algorithm = {
- .master_xfer = ast_i2c_xfer,
+ .master_xfer = ast_i2c_master_xfer,
.functionality = ast_i2c_functionality,
#if IS_ENABLED(CONFIG_I2C_SLAVE)
.reg_slave = ast_i2c_reg_slave,
@@ -894,6 +512,65 @@ static const struct i2c_algorithm i2c_ast_algorithm = {
#endif
};
+static u32 get_clk_reg_val(u32 divider_ratio)
+{
+ unsigned int inc = 0, div;
+ u32 scl_low, scl_high, data;
+
+ for (div = 0; divider_ratio >= 16; div++) {
+ inc |= (divider_ratio & 1);
+ divider_ratio >>= 1;
+ }
+ divider_ratio += inc;
+ scl_low = (divider_ratio >> 1) - 1;
+ scl_high = divider_ratio - scl_low - 2;
+ data = 0x77700300 | (scl_high << 16) | (scl_low << 12) | div;
+ return data;
+}
+
+static int init_clk(struct ast_i2c_bus *bus, struct platform_device *pdev)
+{
+ struct clk *pclk;
+ u32 clk_freq;
+ u32 divider_ratio;
+ int ret;
+
+ pclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pclk)) {
+ dev_err(&pdev->dev, "clk_get failed\n");
+ return PTR_ERR(pclk);
+ }
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &clk_freq);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Could not read clock-frequency property\n");
+ clk_freq = 100000;
+ }
+ divider_ratio = clk_get_rate(pclk) / clk_freq;
+ /* We just need the clock rate, we don't actually use the clk object. */
+ devm_clk_put(&pdev->dev, pclk);
+
+ /* Set AC Timing */
+ if(clk_freq / 1000 > 400) {
+ ast_i2c_write(bus, ast_i2c_read(bus, I2C_FUN_CTRL_REG) |
+ AST_I2CD_M_HIGH_SPEED_EN |
+ AST_I2CD_M_SDA_DRIVE_1T_EN |
+ AST_I2CD_SDA_DRIVE_1T_EN,
+ I2C_FUN_CTRL_REG);
+
+ ast_i2c_write(bus, 0x3, I2C_AC_TIMING_REG2);
+ ast_i2c_write(bus, get_clk_reg_val(divider_ratio),
+ I2C_AC_TIMING_REG1);
+ } else {
+ ast_i2c_write(bus, get_clk_reg_val(divider_ratio),
+ I2C_AC_TIMING_REG1);
+ ast_i2c_write(bus, AST_NO_TIMEOUT_CTRL, I2C_AC_TIMING_REG2);
+ }
+
+ return 0;
+}
+
static int ast_i2c_probe_bus(struct platform_device *pdev)
{
struct ast_i2c_bus *bus;
@@ -908,12 +585,6 @@ static int ast_i2c_probe_bus(struct platform_device *pdev)
if (ret)
return -ENXIO;
- bus->pclk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(bus->pclk)) {
- dev_err(&pdev->dev, "clk_get failed\n");
- return PTR_ERR(bus->pclk);
- }
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bus->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(bus->base))
@@ -933,7 +604,8 @@ static int ast_i2c_probe_bus(struct platform_device *pdev)
}
/* Initialize the I2C adapter */
- spin_lock_init(&bus->cmd_lock);
+ spin_lock_init(&bus->lock);
+ init_completion(&bus->cmd_complete);
bus->adap.nr = bus_num;
bus->adap.owner = THIS_MODULE;
bus->adap.retries = 0;
@@ -947,26 +619,67 @@ static int ast_i2c_probe_bus(struct platform_device *pdev)
bus->dev = &pdev->dev;
- ret = of_property_read_u32(pdev->dev.of_node,
- "clock-frequency", &bus->bus_clk);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "Could not read clock-frequency property\n");
- bus->bus_clk = 100000;
- }
+ /* reset device: disable master & slave functions */
+ ast_i2c_write(bus, 0, I2C_FUN_CTRL_REG);
+
+ ret = init_clk(bus, pdev);
+ if (ret < 0)
+ return ret;
- ast_i2c_dev_init(bus);
+ /* Enable Master Mode */
+ ast_i2c_write(bus, ast_i2c_read(bus, I2C_FUN_CTRL_REG) |
+ AST_I2CD_MASTER_EN |
+ AST_I2CD_MULTI_MASTER_DIS, I2C_FUN_CTRL_REG);
+
+ /* Set interrupt generation of I2C controller */
+ ast_i2c_write(bus, AST_I2CD_INTR_SDA_DL_TIMEOUT |
+ AST_I2CD_INTR_BUS_RECOVER_DONE |
+ AST_I2CD_INTR_SCL_TIMEOUT |
+ AST_I2CD_INTR_ABNORMAL |
+ AST_I2CD_INTR_NORMAL_STOP |
+ AST_I2CD_INTR_ARBIT_LOSS |
+ AST_I2CD_INTR_RX_DONE |
+ AST_I2CD_INTR_TX_NAK |
+ AST_I2CD_INTR_TX_ACK,
+ I2C_INTR_CTRL_REG);
ret = i2c_add_numbered_adapter(&bus->adap);
if (ret < 0)
return -ENXIO;
+ platform_set_drvdata(pdev, bus);
+
dev_info(bus->dev, "i2c bus %d registered, irq %d\n",
bus->adap.nr, bus->irq);
return 0;
}
+static int ast_i2c_remove_bus(struct platform_device *pdev)
+{
+ struct ast_i2c_bus *bus = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&bus->adap);
+ return 0;
+}
+
+static const struct of_device_id ast_i2c_bus_of_table[] = {
+ { .compatible = "aspeed,ast2400-i2c-bus", },
+ { .compatible = "aspeed,ast2500-i2c-bus", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ast_i2c_of_table);
+
+static struct platform_driver ast_i2c_bus_driver = {
+ .probe = ast_i2c_probe_bus,
+ .remove = ast_i2c_remove_bus,
+ .driver = {
+ .name = "ast-i2c-bus",
+ .of_match_table = ast_i2c_bus_of_table,
+ },
+};
+module_platform_driver(ast_i2c_bus_driver);
+
static void noop(struct irq_data *data) { }
static struct irq_chip ast_i2c_irqchip = {
@@ -982,7 +695,7 @@ static void ast_i2c_controller_irq(struct irq_desc *desc)
unsigned int bus_irq;
status = readl(c->base);
- for_each_set_bit(p, &status, ast_i2c_n_busses) {
+ for_each_set_bit(p, &status, AST_I2C_NUM_BUS) {
bus_irq = irq_find_mapping(c->irq_domain, p);
generic_handle_irq(bus_irq);
}
@@ -1011,14 +724,14 @@ static int ast_i2c_probe_controller(struct platform_device *pdev)
}
controller->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
- ast_i2c_n_busses, &irq_domain_simple_ops, NULL);
+ AST_I2C_NUM_BUS, &irq_domain_simple_ops, NULL);
if (!controller->irq_domain) {
dev_err(&pdev->dev, "no IRQ domain\n");
return -ENXIO;
}
controller->irq_domain->name = "ast-i2c-domain";
- for (i = 0; i < ast_i2c_n_busses; i++) {
+ for (i = 0; i < AST_I2C_NUM_BUS; i++) {
irq = irq_create_mapping(controller->irq_domain, i);
irq_set_chip_data(irq, controller);
irq_set_chip_and_handler(irq, &ast_i2c_irqchip,
@@ -1062,43 +775,34 @@ static int ast_i2c_probe_controller(struct platform_device *pdev)
return 0;
}
-static int ast_i2c_probe(struct platform_device *pdev)
+static int ast_i2c_remove_controller(struct platform_device *pdev)
{
- if (of_device_is_compatible(pdev->dev.of_node,
- "aspeed,ast2400-i2c-controller") ||
- of_device_is_compatible(pdev->dev.of_node,
- "aspeed,ast2500-i2c-controller"))
- return ast_i2c_probe_controller(pdev);
-
- if (of_device_is_compatible(pdev->dev.of_node,
- "aspeed,ast2400-i2c-bus") ||
- of_device_is_compatible(pdev->dev.of_node,
- "aspeed,ast2500-i2c-bus"))
- return ast_i2c_probe_bus(pdev);
-
- return -ENODEV;
+ struct ast_i2c_controller *controller = platform_get_drvdata(pdev);
+
+ irq_domain_remove(controller->irq_domain);
+ return 0;
}
-static const struct of_device_id ast_i2c_of_table[] = {
- { .compatible = "aspeed,ast2500-i2c-controller", },
- { .compatible = "aspeed,ast2500-i2c-bus", },
+static const struct of_device_id ast_i2c_controller_of_table[] = {
{ .compatible = "aspeed,ast2400-i2c-controller", },
- { .compatible = "aspeed,ast2400-i2c-bus", },
+ { .compatible = "aspeed,ast2500-i2c-controller", },
{ },
};
MODULE_DEVICE_TABLE(of, ast_i2c_of_table);
-static struct platform_driver i2c_ast_driver = {
- .probe = ast_i2c_probe,
+static struct platform_driver ast_i2c_controller_driver = {
+ .probe = ast_i2c_probe_controller,
+ .remove = ast_i2c_remove_controller,
.driver = {
- .name = KBUILD_MODNAME,
- .of_match_table = ast_i2c_of_table,
+ .name = "ast-i2c-controller",
+ .of_match_table = ast_i2c_controller_of_table,
},
};
-module_platform_driver(i2c_ast_driver);
+module_platform_driver(ast_i2c_controller_driver);
MODULE_AUTHOR("Ryan Chen <ryan_chen at aspeedtech.com>");
+MODULE_AUTHOR("Brendan Higgins <brendanhiggins at google.com>");
MODULE_DESCRIPTION("ASPEED AST I2C Bus Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ast_i2c");
--
2.8.0.rc3.226.g39d4020
More information about the openbmc
mailing list