diff --git a/arch/arm/boot/dts/ast2400.dtsi b/arch/arm/boot/dts/ast2400.dtsi index d924ac1e191a4d..1dd3f0892b5616 100644 --- a/arch/arm/boot/dts/ast2400.dtsi +++ b/arch/arm/boot/dts/ast2400.dtsi @@ -92,13 +92,17 @@ i2c: i2c@1e78a040 { #address-cells = <1>; #size-cells = <1>; - compatible = "aspeed,ast2400-i2c-common"; + #interrupt-cells = <1>; + + compatible = "aspeed,ast2400-i2c-controller"; reg = <0x1e78a000 0x40>; ranges = <0 0x1e78a000 0x1000>; interrupts = <12>; clocks = <&clk_apb>; + clock-ranges; + interrupt-controller; - i2c0: i2c-bus@0x40 { + i2c0: i2c-bus@40 { #address-cells = <1>; #size-cells = <0>; reg = <0x40 0x40>; @@ -106,19 +110,11 @@ bus = <0>; clock-frequency = <100000>; status = "okay"; - eeprom@50 { - compatible = "atmel,24c256"; - reg = <0x50>; - pagesize = <64>; - }; - rtc@68 { - compatible = "dallas,ds3231"; - reg = <0x68>; - // interrupts = - }; + interrupts = <0>; + interrupt-parent = <&i2c>; }; - i2c1: i2c-bus@0x80 { + i2c1: i2c-bus@80 { #address-cells = <1>; #size-cells = <0>; reg = <0x80 0x40>; @@ -126,9 +122,10 @@ bus = <1>; clock-frequency = <100000>; status = "okay"; + interrupts = <1>; }; - i2c2: i2c-bus@0xC0 { + i2c2: i2c-bus@c0 { #address-cells = <1>; #size-cells = <0>; reg = <0xC0 0x40>; @@ -136,13 +133,10 @@ bus = <2>; clock-frequency = <100000>; status = "okay"; - tmp423@4c { - compatible = "ti,tmp423"; - reg = <0x4c>; - }; + interrupts = <2>; }; - i2c3: i2c-bus@0x100 { + i2c3: i2c-bus@100 { #address-cells = <1>; #size-cells = <0>; reg = <0x100 0x40>; @@ -150,9 +144,10 @@ bus = <3>; clock-frequency = <100000>; status = "okay"; + interrupts = <3>; }; - i2c4: i2c-bus@0x140 { + i2c4: i2c-bus@140 { #address-cells = <1>; #size-cells = <0>; reg = <0x140 0x40>; @@ -160,6 +155,7 @@ bus = <4>; clock-frequency = <100000>; status = "okay"; + interrupts = <4>; }; i2c5: i2c-bus@0x180 { @@ -170,9 +166,10 @@ bus = <5>; clock-frequency = <100000>; status = "okay"; + interrupts = <5>; }; - i2c6: i2c-bus@0x1C0 { + i2c6: i2c-bus@1c0 { #address-cells = <1>; #size-cells = <0>; reg = <0x1C0 0x40>; @@ -180,9 +177,10 @@ bus = <6>; clock-frequency = <100000>; status = "okay"; + interrupts = <6>; }; - i2c7: i2c-bus@0x300 { + i2c7: i2c-bus@300 { #address-cells = <1>; #size-cells = <0>; reg = <0x300 0x40>; @@ -190,9 +188,10 @@ bus = <7>; clock-frequency = <100000>; status = "okay"; + interrupts = <7>; }; - i2c8: i2c-bus@0x340 { + i2c8: i2c-bus@340 { #address-cells = <1>; #size-cells = <0>; reg = <0x340 0x40>; @@ -200,9 +199,10 @@ bus = <8>; clock-frequency = <100000>; status = "okay"; + interrupts = <8>; }; - i2c9: i2c-bus@0x380 { + i2c9: i2c-bus@380 { #address-cells = <1>; #size-cells = <0>; reg = <0x380 0x40>; @@ -210,25 +210,28 @@ bus = <9>; clock-frequency = <100000>; status = "disabled"; + interrupts = <9>; }; - i2c10: i2c-bus@0x3C0 { + i2c10: i2c-bus@3c0 { reg = <0x380 0x40>; compatible = "aspeed,ast2400-i2c-bus"; bus = <10>; clock-frequency = <100000>; status = "disabled"; + interrupts = <10>; }; - i2c11: i2c-bus@0x400 { + i2c11: i2c-bus@400 { reg = <0x400 0x40>; compatible = "aspeed,ast2400-i2c-bus"; bus = <11>; clock-frequency = <100000>; status = "disabled"; + interrupts = <11>; }; - i2c12: i2c-bus@0x440 { + i2c12: i2c-bus@440 { #address-cells = <1>; #size-cells = <0>; reg = <0x400 0x40>; @@ -236,9 +239,10 @@ bus = <12>; clock-frequency = <100000>; status = "disabled"; + interrupts = <12>; }; - i2c13: i2c-bus@0x480 { + i2c13: i2c-bus@480 { #address-cells = <1>; #size-cells = <0>; reg = <0x480 0x40>; @@ -246,6 +250,7 @@ bus = <13>; clock-frequency = <100000>; status = "disabled"; + interrupts = <13>; }; }; diff --git a/arch/arm/mach-aspeed/Kconfig b/arch/arm/mach-aspeed/Kconfig index ea82c941b036c1..5ff74d7df1ef82 100644 --- a/arch/arm/mach-aspeed/Kconfig +++ b/arch/arm/mach-aspeed/Kconfig @@ -6,6 +6,7 @@ menuconfig ARCH_ASPEED select ARCH_REQUIRE_GPIOLIB select PINCTRL select PINCTRL_ASPEED + select I2C_ASPEED select PHYLIB if NETDEVICES select MFD_SYSCON select SRAM diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 08b86178e8fba9..c2800bf04773c7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -974,6 +974,17 @@ config I2C_RCAR This driver can also be built as a module. If so, the module will be called i2c-rcar. +config I2C_ASPEED + tristate "Aspeed AST2xxx SoC I2C Controller" + depends on ARCH_ASPEED + select I2C_SLAVE + help + If you say yes to this option, support will be included for the + Aspeed AST2xxx SoC I2C controller. + + This driver can also be built as a module. If so, the module + will be called i2c-aspeed. + comment "External I2C/SMBus adapter drivers" config I2C_DIOLAN_U2C diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 6df3b303bd092b..619c0f2bd353d9 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o +obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 89d253179ba467..ca17c7c191fbf5 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -1,9 +1,8 @@ /* - * i2c_adap_ast.c - * * I2C adapter for the ASPEED I2C bus access. * * Copyright (C) 2012-2020 ASPEED Technology Inc. + * Copyright 2015 IBM Corporation * * 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 @@ -12,9 +11,12 @@ * History: * 2012.07.26: Initial version [Ryan Chen] */ + #include #include #include +#include +#include #include #include #include @@ -22,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -88,21 +92,6 @@ /* Gloable Register Definition */ /* 0x00 : I2C Interrupt Status Register */ /* 0x08 : I2C Interrupt Target Assignment */ -//#if defined(AST_SOC_G4) || defined(AST_SOC_G5) -#define AST_I2CG_INTR14 (0x1 << 13) -#define AST_I2CG_INTR13 (0x1 << 12) -#define AST_I2CG_INTR12 (0x1 << 11) -#define AST_I2CG_INTR11 (0x1 << 10) -#define AST_I2CG_INTR10 (0x1 << 9) -#define AST_I2CG_INTR09 (0x1 << 8) -#define AST_I2CG_INTR08 (0x1 << 7) -#define AST_I2CG_INTR07 (0x1 << 6) -#define AST_I2CG_INTR06 (0x1 << 5) -#define AST_I2CG_INTR05 (0x1 << 4) -#define AST_I2CG_INTR04 (0x1 << 3) -#define AST_I2CG_INTR03 (0x1 << 2) -#define AST_I2CG_INTR02 (0x1 << 1) -#define AST_I2CG_INTR01 (0x1 ) /* Device Register Definition */ /* 0x00 : I2CD Function Control Register */ @@ -137,35 +126,27 @@ #define AST_NO_TIMEOUT_CTRL 0x0 -/* 0x0c : I2CD Interrupt Control Register */ -#define AST_I2CD_SDA_DL_TO_INTR_EN (0x1 << 14) -#define AST_I2CD_BUS_RECOVER_INTR_EN (0x1 << 13) -#define AST_I2CD_SMBUS_ALT_INTR_EN (0x1 << 12) -#define AST_I2CD_SLAVE_MATCH_INTR_EN (0x1 << 7) -#define AST_I2CD_SCL_TO_INTR_EN (0x1 << 6) -#define AST_I2CD_ABNORMAL_INTR_EN (0x1 << 5) -#define AST_I2CD_NORMAL_STOP_INTR_EN (0x1 << 4) -#define AST_I2CD_ARBIT_LOSS_INTR_EN (0x1 << 3) -#define AST_I2CD_RX_DOWN_INTR_EN (0x1 << 2) -#define AST_I2CD_TX_NAK_INTR_EN (0x1 << 1) -#define AST_I2CD_TX_ACK_INTR_EN (0x1 ) - -/* 0x10 : I2CD Interrupt Status Register : WC */ -#define AST_I2CD_INTR_STS_SDA_DL_TO (0x1 << 14) -#define AST_I2CD_INTR_STS_BUS_RECOVER (0x1 << 13) -#define AST_I2CD_INTR_STS_SMBUS_ALT (0x1 << 12) -#define AST_I2CD_INTR_STS_SMBUS_ARP_ADDR (0x1 << 11) -#define AST_I2CD_INTR_STS_SMBUS_DEV_ALT (0x1 << 10) -#define AST_I2CD_INTR_STS_SMBUS_DEF_ADDR (0x1 << 9) -#define AST_I2CD_INTR_STS_GCALL_ADDR (0x1 << 8) -#define AST_I2CD_INTR_STS_SLAVE_MATCH (0x1 << 7) -#define AST_I2CD_INTR_STS_SCL_TO (0x1 << 6) -#define AST_I2CD_INTR_STS_ABNORMAL (0x1 << 5) -#define AST_I2CD_INTR_STS_NORMAL_STOP (0x1 << 4) -#define AST_I2CD_INTR_STS_ARBIT_LOSS (0x1 << 3) -#define AST_I2CD_INTR_STS_RX_DOWN (0x1 << 2) -#define AST_I2CD_INTR_STS_TX_NAK (0x1 << 1) -#define AST_I2CD_INTR_STS_TX_ACK (0x1 ) +/* 0x0c : I2CD Interrupt Control Register & + * 0x10 : I2CD Interrupt Status Register + * + * These share bit definitions, so use the same values for the enable & + * status bits. + */ +#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) +#define AST_I2CD_INTR_NORMAL_STOP (0x1 << 4) +#define AST_I2CD_INTR_ARBIT_LOSS (0x1 << 3) +#define AST_I2CD_INTR_RX_DONE (0x1 << 2) +#define AST_I2CD_INTR_TX_NAK (0x1 << 1) +#define AST_I2CD_INTR_TX_ACK (0x1 << 0) /* 0x14 : I2CD Command/Status Register */ #define AST_I2CD_SDA_OE (0x1 << 28) @@ -230,139 +211,71 @@ #define AST_I2CD_RX_BYTE_BUFFER (0xff << 8) #define AST_I2CD_TX_BYTE_BUFFER (0xff ) -//I2C MEMORY Device state machine -typedef enum i2c_slave_stage { - INIT_STAGE, - CMD_STAGE, - CMD_DATA_STAGE, - DATA_STAGE -} stage; - -typedef enum i2c_xfer_mode { - BYTE_XFER, - BUFF_XFER, - DEC_DMA_XFER, - INC_DMA_XFER -} i2c_xfer_mode_t; - //1. usage flag , 2 size, 3. request address -struct buf_page -{ - u8 flag; //0:free to usage, 1: used - u8 page_no; //for AST2400 usage - u16 page_size; - u32 page_addr; - u32 page_addr_point; -}; - -typedef enum i2c_slave_event_e { - I2C_SLAVE_EVENT_START_READ, - I2C_SLAVE_EVENT_READ, - I2C_SLAVE_EVENT_START_WRITE, - I2C_SLAVE_EVENT_WRITE, - I2C_SLAVE_EVENT_NACK, - I2C_SLAVE_EVENT_STOP -} i2c_slave_event_t; - - - -//AST2400 buffer mode issue , force I2C slave write use byte mode , read use buffer mode /* Use platform_data instead of module parameters */ /* Fast Mode = 400 kHz, Standard = 100 kHz */ //static int clock = 100; /* Default: 100 kHz */ -struct ast_i2c_driver_data { - void __iomem *reg_gr; - u32 bus_clk; - u16 dma_size; - u8 master_dma; //0,byte mode 1,Buffer pool mode 256 , or 2048 , 2: DMA mode - u8 slave_dma; //0,byte mode 1,Buffer pool mode 256 , or 2048 , 2: DMA mode - u8 (*request_pool_buff_page)(struct buf_page **page); -// struct buf_page * (*request_pool_buff_page1)(u8 num); - void (*free_pool_buff_page)(struct buf_page *page); - unsigned char *buf_pool; - void (*slave_xfer)(i2c_slave_event_t event, struct i2c_msg **msgs); - void (*slave_init)(struct i2c_msg **msgs); - u32 (*get_i2c_clock)(void); -}; +#define AST_I2CD_CMDS (AST_I2CD_BUS_RECOVER_CMD_EN | \ + AST_I2CD_M_STOP_CMD | \ + AST_I2CD_M_S_RX_CMD_LAST | \ + AST_I2CD_M_RX_CMD | \ + AST_I2CD_M_TX_CMD | \ + AST_I2CD_M_START_CMD) +static const int ast_i2c_n_busses = 14; -/***************************************************************************/ -struct ast_i2c_dev { - struct ast_i2c_driver_data *ast_i2c_data; - struct device *dev; - void __iomem *reg_base; /* virtual */ - int irq; //I2C IRQ number - u32 bus_id; //for i2c dev# IRQ number check - u32 state; //I2C xfer mode state matchine - struct i2c_adapter adap; - struct buf_page *req_page; -//master dma or buff mode needed - unsigned char *dma_buf; - dma_addr_t dma_addr; -//master - int xfer_last; //cur xfer is last msgs for stop msgs - struct i2c_msg *master_msgs; //cur xfer msgs - int master_xfer_len; //cur xfer len - int master_xfer_cnt; //total xfer count - u32 master_xfer_mode; //cur xfer mode ... 0 : no_op , master: 1 byte , 2 : buffer , 3: dma , slave : xxxx - struct completion cmd_complete; - int cmd_err; - u8 blk_r_flag; //for smbus block read - void (*do_master_xfer)(struct ast_i2c_dev *i2c_dev); - void (*do_master_xfer_done)(struct ast_i2c_dev *i2c_dev); -//Slave structure - u8 slave_operation; - u8 slave_event; - struct i2c_msg *slave_msgs; //cur slave xfer msgs - int slave_xfer_len; - int slave_xfer_cnt; - u32 slave_xfer_mode; //cur xfer mode ... 0 : no_op , master: 1 byte , 2 : buffer , 3: dma , slave : xxxx - void (*do_slave_xfer)(struct ast_i2c_dev *i2c_dev); - void (*do_slave_xfer_done)(struct ast_i2c_dev *i2c_dev); +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; + 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; }; -#ifdef CONFIG_AST_I2C_SLAVE_RDWR -#define I2C_S_BUF_SIZE 64 -#define I2C_S_RX_BUF_NUM 4 -#define BUFF_FULL 0xff00 -#define BUFF_ONGOING 1 - -struct i2c_msg slave_rx_msg[I2C_S_RX_BUF_NUM + 1]; -struct i2c_msg slave_tx_msg; -#endif - +struct ast_i2c_controller { + struct device *dev; + void __iomem *base; + int irq; + struct irq_domain *irq_domain; +}; -static inline void -ast_i2c_write(struct ast_i2c_dev *i2c_dev, u32 val, u32 reg) +static inline void ast_i2c_write(struct ast_i2c_bus *bus, u32 val, u32 reg) { -// dev_dbg(i2c_dev->dev, "ast_i2c_write : val: %x , reg : %x \n",val,reg); - writel(val, i2c_dev->reg_base+ reg); + writel(val, bus->base + reg); } -static inline u32 -ast_i2c_read(struct ast_i2c_dev *i2c_dev, u32 reg) +static inline u32 ast_i2c_read(struct ast_i2c_bus *bus, u32 reg) { -#if 0 - u32 val = readl(i2c_dev->reg_base + reg); - printk("R : reg %x , val: %x \n",reg, val); - return val; -#else - return readl(i2c_dev->reg_base + reg); -#endif + return readl(bus->base + reg); } -static u32 select_i2c_clock(struct ast_i2c_dev *i2c_dev) +static u32 select_i2c_clock(struct ast_i2c_bus *bus) { - - unsigned int clk, inc = 0, div, divider_ratio; + unsigned int inc = 0, div, divider_ratio; u32 SCL_Low, SCL_High, data; - clk = i2c_dev->ast_i2c_data->get_i2c_clock(); -// printk("pclk = %d \n",clk); - divider_ratio = clk / i2c_dev->ast_i2c_data->bus_clk; - for (div = 0; divider_ratio >= 16; div++) - { + divider_ratio = clk_get_rate(bus->pclk) / bus->bus_clk; + for (div = 0; divider_ratio >= 16; div++) { inc |= (divider_ratio & 1); divider_ratio >>= 1; } @@ -370,322 +283,154 @@ static u32 select_i2c_clock(struct ast_i2c_dev *i2c_dev) SCL_Low = (divider_ratio >> 1) - 1; SCL_High = divider_ratio - SCL_Low - 2; data = 0x77700300 | (SCL_High << 16) | (SCL_Low << 12) | div; -// printk("I2CD04 for %d = %08X\n", target_speed, data); return data; } -#ifdef CONFIG_AST_I2C_SLAVE_MODE -/* AST I2C Slave mode */ -static void ast_slave_issue_alert(struct ast_i2c_dev *i2c_dev, u8 enable) -{ - //only support dev0~3 - if(i2c_dev->bus_id > 3) - return; - else { - if(enable) - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_CMD_REG) | AST_I2CD_S_ALT_EN, I2C_CMD_REG); - else - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_CMD_REG) & ~AST_I2CD_S_ALT_EN, I2C_CMD_REG); - } -} - -static void ast_slave_mode_enable(struct ast_i2c_dev *i2c_dev, struct i2c_msg *msgs) -{ - if(msgs->buf[0] == 1) { - ast_i2c_write(i2c_dev, msgs->addr, I2C_DEV_ADDR_REG); - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_FUN_CTRL_REG) | AST_I2CD_SLAVE_EN, I2C_FUN_CTRL_REG); - } else - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_FUN_CTRL_REG) & ~AST_I2CD_SLAVE_EN, I2C_FUN_CTRL_REG); -} - -#endif - -static void ast_i2c_dev_init(struct ast_i2c_dev *i2c_dev) +static void ast_i2c_dev_init(struct ast_i2c_bus *bus) { - //I2CG Reset - ast_i2c_write(i2c_dev, 0, I2C_FUN_CTRL_REG); - -#ifdef CONFIG_AST_I2C_SLAVE_EEPROM - i2c_dev->ast_i2c_data->slave_init(&(i2c_dev->slave_msgs)); - ast_slave_mode_enable(i2c_dev, i2c_dev->slave_msgs); -#endif - - //Enable Master Mode - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev, I2C_FUN_CTRL_REG) | AST_I2CD_MASTER_EN, I2C_FUN_CTRL_REG); + /* 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 defined(CONFIG_ARCH_AST2400) - if(i2c_dev->ast_i2c_data->bus_clk/1000 > 400) { - printk("high speed mode enable clk [%dkhz]\n",i2c_dev->ast_i2c_data->bus_clk/1000); - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev, 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); - - /* Set AC Timing */ - ast_i2c_write(i2c_dev, 0x3, I2C_AC_TIMING_REG2); - ast_i2c_write(i2c_dev, select_i2c_clock(i2c_dev), I2C_AC_TIMING_REG1); - }else { - /* target apeed is xxKhz*/ - ast_i2c_write(i2c_dev, select_i2c_clock(i2c_dev), I2C_AC_TIMING_REG1); - ast_i2c_write(i2c_dev, AST_NO_TIMEOUT_CTRL, I2C_AC_TIMING_REG2); + 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); } -#else - /* target apeed is xxKhz*/ - ast_i2c_write(i2c_dev, select_i2c_clock(i2c_dev), I2C_AC_TIMING_REG1); - ast_i2c_write(i2c_dev, AST_NO_TIMEOUT_CTRL, I2C_AC_TIMING_REG2); -#endif -// ast_i2c_write(i2c_dev, 0x77743335, I2C_AC_TIMING_REG1); -///// + 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); - //Clear Interrupt - ast_i2c_write(i2c_dev, 0xfffffff, I2C_INTR_STS_REG); - //TODO -// ast_i2c_write(i2c_dev, 0xAF, I2C_INTR_CTRL_REG); - //Enable Interrupt, STOP Interrupt has bug in AST2000 - /* Set interrupt generation of I2C controller */ - ast_i2c_write(i2c_dev, - AST_I2CD_SDA_DL_TO_INTR_EN | - AST_I2CD_BUS_RECOVER_INTR_EN | - AST_I2CD_SMBUS_ALT_INTR_EN | -// AST_I2CD_SLAVE_MATCH_INTR_EN | - AST_I2CD_SCL_TO_INTR_EN | - AST_I2CD_ABNORMAL_INTR_EN | - AST_I2CD_NORMAL_STOP_INTR_EN | - AST_I2CD_ARBIT_LOSS_INTR_EN | - AST_I2CD_RX_DOWN_INTR_EN | - AST_I2CD_TX_NAK_INTR_EN | - AST_I2CD_TX_ACK_INTR_EN, - I2C_INTR_CTRL_REG); + ast_i2c_write(bus, AST_I2CD_INTR_SDA_DL_TIMEOUT | + AST_I2CD_INTR_BUS_RECOVER_DONE | + AST_I2CD_INTR_SMBUS_ALERT | + 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); } -#ifdef CONFIG_AST_I2C_SLAVE_RDWR -//for memory buffer initial -static void ast_i2c_slave_buff_init(struct ast_i2c_dev *i2c_dev) +static void ast_i2c_issue_cmd(struct ast_i2c_bus *bus, u32 cmd) { - int i; - //Tx buf 1 - slave_tx_msg.len = I2C_S_BUF_SIZE; - slave_tx_msg.buf = kzalloc(I2C_S_BUF_SIZE, GFP_KERNEL); - //Rx buf 4 - for(i=0; idev, "issuing cmd: %x\n", cmd); + bus->cmd_err = 0; + bus->cmd_sent = bus->cmd_pending = cmd & AST_I2CD_CMDS; + ast_i2c_write(bus, cmd, I2C_CMD_REG); } -static void ast_i2c_slave_rdwr_xfer(struct ast_i2c_dev *i2c_dev) +static int ast_i2c_issue_oob_command(struct ast_i2c_bus *bus, u32 cmd) { - int i; - spinlock_t lock; - spin_lock(&lock); - - switch(i2c_dev->slave_event) { - case I2C_SLAVE_EVENT_START_WRITE: - for(i=0; islave_msgs = &slave_rx_msg[i]; - break; - case I2C_SLAVE_EVENT_START_READ: - printk("I2C_SLAVE_EVENT_START_READ ERROR .. not imple \n"); - i2c_dev->slave_msgs = &slave_tx_msg; - break; - case I2C_SLAVE_EVENT_WRITE: - printk("I2C_SLAVE_EVENT_WRITE next write ERROR ...\n"); - i2c_dev->slave_msgs = &slave_tx_msg; - break; - case I2C_SLAVE_EVENT_READ: - printk("I2C_SLAVE_EVENT_READ ERROR ... \n"); - i2c_dev->slave_msgs = &slave_tx_msg; - break; - case I2C_SLAVE_EVENT_NACK: - printk("I2C_SLAVE_EVENT_NACK ERROR ... \n"); - i2c_dev->slave_msgs = &slave_tx_msg; - break; - case I2C_SLAVE_EVENT_STOP: - printk("I2C_SLAVE_EVENT_STOP \n"); - for(i=0; islave_msgs = &slave_tx_msg; - break; - } - spin_unlock(&lock); - + 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 int ast_i2c_slave_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs) +static u8 ast_i2c_bus_error_recover(struct ast_i2c_bus *bus) { - struct ast_i2c_dev *i2c_dev = adap->algo_data; - int ret=0, i; - - switch(msgs->flags) { - case 0: -// printk("slave read \n"); - //cur_msg = get_free_msg; - for(i=0; ibuf, slave_rx_msg[i].buf, slave_rx_msg[i].len); - msgs->len = slave_rx_msg[i].len; - slave_rx_msg[i].flags = 0; - slave_rx_msg[i].len = 0; - break; - } - } - - if(i == I2C_S_RX_BUF_NUM) { - printk("No buffer ........ \n"); - msgs->len = 0; - ret = -1; - } - break; - case I2C_M_RD: //slave write -// printk("slave write \n"); - memcpy(msgs->buf, slave_tx_msg.buf, I2C_S_BUF_SIZE); - break; - case I2C_S_EN: - if((msgs->addr < 0x1) || (msgs->addr > 0xff)) { - ret = -1; - printk("addrsss not correct !! \n"); - return ret; - } - if(msgs->len != 1) printk("ERROR \n"); - ast_slave_mode_enable(i2c_dev, msgs); - break; - case I2C_S_ALT: -// printk("slave issue alt\n"); - if(msgs->len != 1) printk("ERROR \n"); - if(msgs->buf[0]==1) - ast_slave_issue_alert(i2c_dev, 1); - else - ast_slave_issue_alert(i2c_dev, 0); - break; - - default: - printk("slave xfer error \n"); - break; - - } - return ret; -} - - -#endif + u32 sts, i; + int r; -static u8 -ast_i2c_bus_error_recover(struct ast_i2c_dev *i2c_dev) -{ - u32 sts; - int r; - u32 i = 0; - //Check 0x14's SDA and SCL status - sts = ast_i2c_read(i2c_dev,I2C_CMD_REG); - + sts = ast_i2c_read(bus,I2C_CMD_REG); + if ((sts & AST_I2CD_SDA_LINE_STS) && (sts & AST_I2CD_SCL_LINE_STS)) { //Means bus is idle. - dev_dbg(i2c_dev->dev, "I2C bus (%d) is idle. I2C slave doesn't exist?!\n", i2c_dev->bus_id); + dev_dbg(bus->dev, + "I2C bus is idle. I2C slave doesn't exist?!\n"); return -1; } - dev_dbg(i2c_dev->dev, "ERROR!! I2C(%d) bus hanged, try to recovery it!\n", i2c_dev->bus_id); - - + dev_dbg(bus->dev, "I2C bus hung (status %x), attempting recovery\n", + sts); + 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(i2c_dev->dev, "I2C's master is locking the bus, try to stop it.\n"); -// - init_completion(&i2c_dev->cmd_complete); + //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(i2c_dev, AST_I2CD_M_STOP_CMD, I2C_CMD_REG); + ast_i2c_write(bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG); - r = wait_for_completion_interruptible_timeout(&i2c_dev->cmd_complete, - i2c_dev->adap.timeout*HZ); + r = wait_for_completion_interruptible_timeout(&bus->cmd_complete, + bus->adap.timeout*HZ); - if(i2c_dev->cmd_err) { - dev_dbg(i2c_dev->dev, "recovery error \n"); + if (bus->cmd_err) { + dev_dbg(bus->dev, "recovery error \n"); return -1; } - + if (r == 0) { - dev_dbg(i2c_dev->dev, "recovery timed out\n"); + dev_dbg(bus->dev, "recovery timed out\n"); return -1; } else { - dev_dbg(i2c_dev->dev, "Recovery successfully\n"); + dev_dbg(bus->dev, "Recovery successfully\n"); return 0; } - } 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(i2c_dev->dev, "I2C's slave is dead, try to recover it\n"); - //Let's retry 10 times - for (i = 0; i < 10; i++) { - ast_i2c_dev_init(i2c_dev); - //Do the recovery command BIT11 - init_completion(&i2c_dev->cmd_complete); - ast_i2c_write(i2c_dev, AST_I2CD_BUS_RECOVER_CMD_EN, I2C_CMD_REG); - - r = wait_for_completion_interruptible_timeout(&i2c_dev->cmd_complete, - i2c_dev->adap.timeout*HZ); - if (i2c_dev->cmd_err != 0) { - dev_dbg(i2c_dev->dev, "ERROR!! Failed to do recovery command(0x%08x)\n", i2c_dev->cmd_err); + 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(i2c_dev,I2C_CMD_REG); + sts = ast_i2c_read(bus,I2C_CMD_REG); if (sts & AST_I2CD_SDA_LINE_STS) //Recover OK break; } - if (i == 10) { - dev_dbg(i2c_dev->dev, "ERROR!! recover failed\n"); + if (i == 2) { + dev_dbg(bus->dev, "ERROR!! recover failed\n"); return -1; } } else { - dev_dbg(i2c_dev->dev, "Don't know how to handle this case?!\n"); + dev_dbg(bus->dev, "Don't know how to handle this case?!\n"); return -1; } - dev_dbg(i2c_dev->dev, "Recovery successfully\n"); + dev_dbg(bus->dev, "Recovery successfully\n"); return 0; } -static void ast_master_alert_recv(struct ast_i2c_dev *i2c_dev) +static int ast_i2c_wait_bus_not_busy(struct ast_i2c_bus *bus) { - printk("ast_master_alert_recv bus id %d, Disable Alt, Please Imple \n",i2c_dev->bus_id); -} + int timeout = 2; //TODO number -static int ast_i2c_wait_bus_not_busy(struct ast_i2c_dev *i2c_dev) -{ - int timeout = 32; //TODO number -// printk("ast_i2c_wait_bus_not_busy \n"); - while(ast_i2c_read(i2c_dev,I2C_CMD_REG) & AST_I2CD_BUS_BUSY_STS) { - ast_i2c_bus_error_recover(i2c_dev); - if(timeout<=0) + 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); @@ -694,1326 +439,230 @@ static int ast_i2c_wait_bus_not_busy(struct ast_i2c_dev *i2c_dev) return timeout <= 0 ? EAGAIN : 0; } -//ast1070, ast1010 dma -static void ast_i2c_do_dec_dma_xfer(struct ast_i2c_dev *i2c_dev) +static bool ast_i2c_do_byte_xfer(struct ast_i2c_bus *bus) { - u32 cmd = 0; - int i; - - i2c_dev->master_xfer_mode = DEC_DMA_XFER; - i2c_dev->slave_xfer_mode = DEC_DMA_XFER; - dev_dbg(i2c_dev->dev, "ast_i2c_do_dec_dma_xfer \n"); - if(i2c_dev->slave_operation == 1) { - if(i2c_dev->slave_msgs->flags & I2C_M_RD) { - //DMA tx mode - if(i2c_dev->slave_msgs->len > AST_I2C_DMA_SIZE) - i2c_dev->slave_xfer_len = AST_I2C_DMA_SIZE; - else - i2c_dev->slave_xfer_len = i2c_dev->slave_msgs->len; - - dev_dbg(i2c_dev->dev, "(<--) slave tx DMA \n"); - for(i=0; islave_xfer_len; i++) - i2c_dev->dma_buf[i] = i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt + i]; - - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (AST_I2C_DMA_SIZE-1), I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, AST_I2CD_TX_DMA_ENABLE | AST_I2CD_S_TX_CMD,I2C_CMD_REG); - } else { - //DMA prepare rx - dev_dbg(i2c_dev->dev, "(-->) slave rx DMA \n"); - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (AST_I2C_DMA_SIZE-1), I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, AST_I2CD_RX_DMA_ENABLE, I2C_CMD_REG); - } - } else { - dev_dbg(i2c_dev->dev,"M cnt %d, xf len %d \n",i2c_dev->master_xfer_cnt, i2c_dev->master_msgs->len); - if(i2c_dev->master_xfer_cnt == -1) { - //send start - dev_dbg(i2c_dev->dev, " %sing %d byte%s %s 0x%02x\n", - i2c_dev->master_msgs->flags & I2C_M_RD ? "read" : "write", - i2c_dev->master_msgs->len, i2c_dev->master_msgs->len > 1 ? "s" : "", - i2c_dev->master_msgs->flags & I2C_M_RD ? "from" : "to", i2c_dev->master_msgs->addr); - - if(i2c_dev->master_msgs->flags & I2C_M_RD) { - //workaround .. HW can;t send start read addr with buff mode - cmd = AST_I2CD_M_START_CMD | AST_I2CD_M_TX_CMD; - ast_i2c_write(i2c_dev, (i2c_dev->master_msgs->addr <<1) |0x1, I2C_BYTE_BUF_REG); -// tx_buf[0] = (i2c_dev->master_msgs->addr <<1); //+1 - i2c_dev->master_xfer_len = 1; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } else { - //tx - cmd = AST_I2CD_M_START_CMD | AST_I2CD_M_TX_CMD | AST_I2CD_TX_DMA_ENABLE; - - i2c_dev->dma_buf[0] = (i2c_dev->master_msgs->addr <<1); //+1 - //next data write - if((i2c_dev->master_msgs->len + 1) > AST_I2C_DMA_SIZE) - i2c_dev->master_xfer_len = AST_I2C_DMA_SIZE; - else - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len + 1; - - for(i = 1; i < i2c_dev->master_xfer_len; i++) - i2c_dev->dma_buf[i] = i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt+i]; - - if (i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (i2c_dev->master_xfer_len-1), I2C_DMA_LEN_REG); - } - ast_i2c_write(i2c_dev, cmd, I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "txfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - - } else if (i2c_dev->master_xfer_cnt < i2c_dev->master_msgs->len){ - //Next send - if(i2c_dev->master_msgs->flags & I2C_M_RD) { - //Rx data - cmd = AST_I2CD_M_RX_CMD | AST_I2CD_RX_DMA_ENABLE; - - if((i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt) > AST_I2C_DMA_SIZE) { - i2c_dev->master_xfer_len = AST_I2C_DMA_SIZE; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - - } else { - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt; - if((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->blk_r_flag == 0)) { - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN \n"); - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } else { -#ifdef CONFIG_AST1010 - //Workaround for ast1010 can't send NACK - if((i2c_dev->master_xfer_len == 1) && (i2c_dev->xfer_last == 1)) { - //change to byte mode - cmd |= AST_I2CD_M_STOP_CMD | AST_I2CD_M_S_RX_CMD_LAST; - cmd &= ~AST_I2CD_RX_DMA_ENABLE; - i2c_dev->master_xfer_mode = BYTE_XFER; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - - } else if (i2c_dev->master_xfer_len > 1) { - i2c_dev->master_xfer_len -=1; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } else { - printk(" Fix Me !! \n"); - } -#else - if(i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } - //TODO check.... - cmd |= AST_I2CD_M_S_RX_CMD_LAST; -#endif - } - - } - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (i2c_dev->master_xfer_len-1), I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, cmd, I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "rxfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - } else { - //Tx data - //next data write - cmd = AST_I2CD_M_TX_CMD | AST_I2CD_TX_DMA_ENABLE; - if((i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt) > AST_I2C_DMA_SIZE) { - i2c_dev->master_xfer_len = AST_I2C_DMA_SIZE; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - - } else { - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt; - if(i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } - } - - for(i = 0; i < i2c_dev->master_xfer_len; i++) - i2c_dev->dma_buf[i] = i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt + i]; - - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (i2c_dev->master_xfer_len-1), I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, cmd , I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "txfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - - } - }else { - //should send next msg - if(i2c_dev->master_xfer_cnt != i2c_dev->master_msgs->len) - printk("complete rx ... ERROR \n"); - - dev_dbg(i2c_dev->dev, "ast_i2c_do_byte_xfer complete \n"); - i2c_dev->cmd_err = 0; - complete(&i2c_dev->cmd_complete); - } - - } + u32 cmd, data; - -} - -//new generation dma -static void ast_i2c_do_inc_dma_xfer(struct ast_i2c_dev *i2c_dev) -{ - u32 cmd = 0; - int i; - - i2c_dev->master_xfer_mode = INC_DMA_XFER; - i2c_dev->slave_xfer_mode = INC_DMA_XFER; - dev_dbg(i2c_dev->dev, "ast_i2c_do_inc_dma_xfer \n"); - if(i2c_dev->slave_operation == 1) { - dev_dbg(i2c_dev->dev,"S cnt %d, xf len %d \n",i2c_dev->slave_xfer_cnt, i2c_dev->slave_msgs->len); - if(i2c_dev->slave_msgs->flags & I2C_M_RD) { - //DMA tx mode - if(i2c_dev->slave_msgs->len > AST_I2C_DMA_SIZE) - i2c_dev->slave_xfer_len = AST_I2C_DMA_SIZE; - else - i2c_dev->slave_xfer_len = i2c_dev->slave_msgs->len; - - dev_dbg(i2c_dev->dev, "(<--) slave tx DMA len %d \n",i2c_dev->slave_xfer_len); - for(i=0; islave_xfer_len; i++) - i2c_dev->dma_buf[i] = i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt + i]; - - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, i2c_dev->slave_xfer_len, I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, AST_I2CD_TX_DMA_ENABLE | AST_I2CD_S_TX_CMD,I2C_CMD_REG); - } else { - //DMA prepare rx - if(i2c_dev->slave_msgs->len > AST_I2C_DMA_SIZE) - i2c_dev->slave_xfer_len = AST_I2C_DMA_SIZE; - else - i2c_dev->slave_xfer_len = i2c_dev->slave_msgs->len; - - dev_dbg(i2c_dev->dev, "(-->) slave rx DMA len %d \n", i2c_dev->slave_xfer_len); - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, i2c_dev->slave_xfer_len, I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, AST_I2CD_RX_DMA_ENABLE, I2C_CMD_REG); - } - } else { - dev_dbg(i2c_dev->dev,"M cnt %d, xf len %d \n",i2c_dev->master_xfer_cnt, i2c_dev->master_msgs->len); - if(i2c_dev->master_xfer_cnt == -1) { - //send start - dev_dbg(i2c_dev->dev, " %sing %d byte%s %s 0x%02x\n", - i2c_dev->master_msgs->flags & I2C_M_RD ? "read" : "write", - i2c_dev->master_msgs->len, i2c_dev->master_msgs->len > 1 ? "s" : "", - i2c_dev->master_msgs->flags & I2C_M_RD ? "from" : "to", i2c_dev->master_msgs->addr); - - if(i2c_dev->master_msgs->flags & I2C_M_RD) { - //workaround .. HW can;t send start read addr with buff mode - cmd = AST_I2CD_M_START_CMD | AST_I2CD_M_TX_CMD; - ast_i2c_write(i2c_dev, (i2c_dev->master_msgs->addr <<1) |0x1, I2C_BYTE_BUF_REG); -// tx_buf[0] = (i2c_dev->master_msgs->addr <<1); //+1 - i2c_dev->master_xfer_len = 1; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } else { - //tx - cmd = AST_I2CD_M_START_CMD | AST_I2CD_M_TX_CMD | AST_I2CD_TX_DMA_ENABLE; - - i2c_dev->dma_buf[0] = (i2c_dev->master_msgs->addr <<1); //+1 - //next data write - if((i2c_dev->master_msgs->len + 1) > AST_I2C_DMA_SIZE) - i2c_dev->master_xfer_len = AST_I2C_DMA_SIZE; - else - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len + 1; - - for(i = 1; i < i2c_dev->master_xfer_len; i++) - i2c_dev->dma_buf[i] = i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt+i]; - - if (i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (i2c_dev->master_xfer_len), I2C_DMA_LEN_REG); - } - ast_i2c_write(i2c_dev, cmd, I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "txfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - - } else if (i2c_dev->master_xfer_cnt < i2c_dev->master_msgs->len) { - //Next send - if(i2c_dev->master_msgs->flags & I2C_M_RD) { - //Rx data - cmd = AST_I2CD_M_RX_CMD | AST_I2CD_RX_DMA_ENABLE; - - if((i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt) > AST_I2C_DMA_SIZE) { - i2c_dev->master_xfer_len = AST_I2C_DMA_SIZE; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - - } else { - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt; - if((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->blk_r_flag == 0)) { - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN \n"); - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } else { - if(i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } - //TODO check.... - cmd |= AST_I2CD_M_S_RX_CMD_LAST; - } - - } - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (i2c_dev->master_xfer_len), I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, cmd, I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "rxfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - } else { - //Tx data - //next data write - cmd = AST_I2CD_M_TX_CMD | AST_I2CD_TX_DMA_ENABLE; - if((i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt) > AST_I2C_DMA_SIZE) { - i2c_dev->master_xfer_len = AST_I2C_DMA_SIZE; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - - } else { - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt; - if(i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } - } - - for(i = 0; i < i2c_dev->master_xfer_len; i++) - i2c_dev->dma_buf[i] = i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt + i]; - - ast_i2c_write(i2c_dev, i2c_dev->dma_addr, I2C_DMA_BASE_REG); - ast_i2c_write(i2c_dev, (i2c_dev->master_xfer_len), I2C_DMA_LEN_REG); - ast_i2c_write(i2c_dev, cmd , I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "txfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - - } - }else { - //should send next msg - if(i2c_dev->master_xfer_cnt != i2c_dev->master_msgs->len) - printk("complete rx ... ERROR \n"); - - dev_dbg(i2c_dev->dev, "ast_i2c_do_byte_xfer complete \n"); - i2c_dev->cmd_err = 0; - complete(&i2c_dev->cmd_complete); - } - - } + 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; -static void ast_i2c_do_pool_xfer(struct ast_i2c_dev *i2c_dev) -{ - u32 cmd = 0; - int i; - u32 *tx_buf; - - i2c_dev->master_xfer_mode = BUFF_XFER; - i2c_dev->slave_xfer_mode = BUFF_XFER; - dev_dbg(i2c_dev->dev, "ast_i2c_do_pool_xfer \n"); -#if defined(AST_SOC_G4) - ast_i2c_write(i2c_dev, - (ast_i2c_read(i2c_dev, I2C_FUN_CTRL_REG) & - ~AST_I2CD_BUFF_SEL_MASK) | - AST_I2CD_BUFF_SEL(i2c_dev->req_page->page_no), - I2C_FUN_CTRL_REG); -#endif + 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; - tx_buf = (u32 *) i2c_dev->req_page->page_addr; + ast_i2c_write(bus, data, I2C_BYTE_BUF_REG); + ast_i2c_issue_cmd(bus, cmd); -#if defined(AST_SOC_G5) - dev_dbg(i2c_dev->dev, "offset buffer = %x \n",i2c_dev->bus_id * 0x10); + } else if (bus->msg_pos < bus->msg->len){ + bool is_last = bus->msg_pos + 1 == bus->msg->len; - tx_buf = (u32*)(i2c_dev->req_page->page_addr + i2c_dev->bus_id * 0x10); -#endif + 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) + cmd |= AST_I2CD_M_S_RX_CMD_LAST | + AST_I2CD_M_STOP_CMD; - if(i2c_dev->slave_operation == 1) { - if(i2c_dev->slave_msgs->flags & I2C_M_RD) { - dev_dbg(i2c_dev->dev, "(<--) slave tx buf \n"); - - if(i2c_dev->slave_msgs->len > i2c_dev->req_page->page_size) - i2c_dev->slave_xfer_len = i2c_dev->req_page->page_size; - else - i2c_dev->slave_xfer_len = i2c_dev->slave_msgs->len; - - for(i = 0; i< i2c_dev->slave_xfer_len; i++) { - if(i%4 == 0) - tx_buf[i/4] = 0; - tx_buf[i/4] |= (i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt + i] << ((i%4)*8)) ; - dev_dbg(i2c_dev->dev, "[%x] ",tx_buf[i/4]); - } - dev_dbg(i2c_dev->dev, "\n"); - - ast_i2c_write(i2c_dev, AST_I2CD_TX_DATA_BUF_END_SET((i2c_dev->slave_xfer_len-1)) | - AST_I2CD_BUF_BASE_ADDR_SET((i2c_dev->req_page->page_addr_point)), - I2C_BUF_CTRL_REG); - - ast_i2c_write(i2c_dev, AST_I2CD_TX_BUFF_ENABLE | AST_I2CD_S_TX_CMD, I2C_CMD_REG); - } else { - //prepare for new rx - if(i2c_dev->slave_msgs->len > i2c_dev->req_page->page_size) - i2c_dev->slave_xfer_len = i2c_dev->req_page->page_size; - else - i2c_dev->slave_xfer_len = i2c_dev->slave_msgs->len; - - ast_i2c_write(i2c_dev, - AST_I2CD_RX_BUF_END_ADDR_SET((i2c_dev->slave_msgs->len-1)) | - AST_I2CD_BUF_BASE_ADDR_SET((i2c_dev->req_page->page_addr_point)), - I2C_BUF_CTRL_REG); - - ast_i2c_write(i2c_dev, AST_I2CD_RX_BUFF_ENABLE, I2C_CMD_REG); - - } - } else { - dev_dbg(i2c_dev->dev,"M cnt %d, xf len %d \n",i2c_dev->master_xfer_cnt, i2c_dev->master_msgs->len); - if(i2c_dev->master_xfer_cnt == -1) { - //send start - dev_dbg(i2c_dev->dev, " %sing %d byte%s %s 0x%02x\n", - i2c_dev->master_msgs->flags & I2C_M_RD ? "read" : "write", - i2c_dev->master_msgs->len, i2c_dev->master_msgs->len > 1 ? "s" : "", - i2c_dev->master_msgs->flags & I2C_M_RD ? "from" : "to", i2c_dev->master_msgs->addr); - - if(i2c_dev->master_msgs->flags & I2C_M_RD) { -//workaround .. HW can;t send start read addr with buff mode - cmd = AST_I2CD_M_START_CMD | AST_I2CD_M_TX_CMD; - ast_i2c_write(i2c_dev, (i2c_dev->master_msgs->addr <<1) |0x1, I2C_BYTE_BUF_REG); - -// tx_buf[0] = (i2c_dev->master_msgs->addr <<1); //+1 - i2c_dev->master_xfer_len = 1; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } else { - cmd = AST_I2CD_M_START_CMD | AST_I2CD_M_TX_CMD | AST_I2CD_TX_BUFF_ENABLE; - tx_buf[0] = (i2c_dev->master_msgs->addr <<1); //+1 - //next data write - if((i2c_dev->master_msgs->len + 1) > i2c_dev->req_page->page_size) - i2c_dev->master_xfer_len = i2c_dev->req_page->page_size; - else - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len + 1; - - for(i = 1; i < i2c_dev->master_xfer_len; i++) { - if(i%4 == 0) - tx_buf[i/4] = 0; - tx_buf[i/4] |= (i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt + i] << ((i%4)*8)) ; - } - - if (i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } - ast_i2c_write(i2c_dev, - AST_I2CD_TX_DATA_BUF_END_SET((i2c_dev->master_xfer_len - 1)) | - AST_I2CD_BUF_BASE_ADDR_SET(i2c_dev->req_page->page_addr_point), - I2C_BUF_CTRL_REG); - } - ast_i2c_write(i2c_dev, cmd, I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "txfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - - } else if (i2c_dev->master_xfer_cnt < i2c_dev->master_msgs->len){ - //Next send - if(i2c_dev->master_msgs->flags & I2C_M_RD) { - //Rx data - cmd = AST_I2CD_M_RX_CMD | AST_I2CD_RX_BUFF_ENABLE; - - if((i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt) > i2c_dev->req_page->page_size) { - i2c_dev->master_xfer_len = i2c_dev->req_page->page_size; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } else { - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt; - if((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->blk_r_flag == 0)) { - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN \n"); - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } else { - if(i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } - cmd |= AST_I2CD_M_S_RX_CMD_LAST; - } - } - ast_i2c_write(i2c_dev, - AST_I2CD_RX_BUF_END_ADDR_SET((i2c_dev->master_xfer_len-1))| - AST_I2CD_BUF_BASE_ADDR_SET((i2c_dev->req_page->page_addr_point)), - I2C_BUF_CTRL_REG); - ast_i2c_write(i2c_dev, cmd, I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "rxfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - } else { - //Tx data - //next data write - cmd = AST_I2CD_M_TX_CMD | AST_I2CD_TX_BUFF_ENABLE; - if((i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt) > i2c_dev->req_page->page_size) { - i2c_dev->master_xfer_len = i2c_dev->req_page->page_size; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - - } else { - i2c_dev->master_xfer_len = i2c_dev->master_msgs->len - i2c_dev->master_xfer_cnt; - if(i2c_dev->xfer_last == 1) { - dev_dbg(i2c_dev->dev, "last stop \n"); - cmd |= AST_I2CD_M_STOP_CMD; - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - dev_dbg(i2c_dev->dev, "intr en %x \n",ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG)); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - } - } - - for(i = 0; i < i2c_dev->master_xfer_len; i++) { - if(i%4 == 0) - tx_buf[i/4] = 0; - tx_buf[i/4] |= (i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt + i] << ((i%4)*8)) ; - } -// printk("count %x \n",ast_i2c_read(i2c_dev,I2C_CMD_REG)); - ast_i2c_write(i2c_dev, - AST_I2CD_TX_DATA_BUF_END_SET((i2c_dev->master_xfer_len - 1)) | - AST_I2CD_BUF_BASE_ADDR_SET(i2c_dev->req_page->page_addr_point), - I2C_BUF_CTRL_REG); - - ast_i2c_write(i2c_dev, cmd , I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "txfer size %d , cmd = %x \n",i2c_dev->master_xfer_len, cmd); - } } else { - //should send next msg - if(i2c_dev->master_xfer_cnt != i2c_dev->master_msgs->len) - printk("complete rx ... ERROR \n"); - - dev_dbg(i2c_dev->dev, "ast_i2c_do_byte_xfer complete \n"); - i2c_dev->cmd_err = 0; - complete(&i2c_dev->cmd_complete); - } - - } -} - -static void ast_i2c_do_byte_xfer(struct ast_i2c_dev *i2c_dev) -{ - u8 *xfer_buf; - u32 cmd = 0; - - i2c_dev->master_xfer_mode = BYTE_XFER; - i2c_dev->master_xfer_len = 1; - - i2c_dev->slave_xfer_mode = BYTE_XFER; - i2c_dev->slave_xfer_len = 1; - dev_dbg(i2c_dev->dev, "ast_i2c_do_byte_xfer \n"); - if(i2c_dev->slave_operation == 1) { - dev_dbg(i2c_dev->dev,"S cnt %d, xf len %d \n",i2c_dev->slave_xfer_cnt, i2c_dev->slave_msgs->len); - if(i2c_dev->slave_msgs->flags & I2C_M_RD) { - //READ <-- TX - dev_dbg(i2c_dev->dev, "(<--) slave(tx) buf %d [%x]\n", i2c_dev->slave_xfer_cnt, i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt]); - ast_i2c_write(i2c_dev, i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt], I2C_BYTE_BUF_REG); - ast_i2c_write(i2c_dev, AST_I2CD_S_TX_CMD, I2C_CMD_REG); - } else { - // Write -->Rx - //no need to handle in byte mode - dev_dbg(i2c_dev->dev, "(-->) slave(rx) BYTE do nothing\n"); + 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; } - } else { - dev_dbg(i2c_dev->dev,"M cnt %d, xf len %d \n",i2c_dev->master_xfer_cnt, i2c_dev->master_msgs->len); - if(i2c_dev->master_xfer_cnt == -1) { - //first start - dev_dbg(i2c_dev->dev, " %sing %d byte%s %s 0x%02x\n", - i2c_dev->master_msgs->flags & I2C_M_RD ? "read" : "write", - i2c_dev->master_msgs->len, i2c_dev->master_msgs->len > 1 ? "s" : "", - i2c_dev->master_msgs->flags & I2C_M_RD ? "from" : "to", i2c_dev->master_msgs->addr); - - - if(i2c_dev->master_msgs->flags & I2C_M_RD) - ast_i2c_write(i2c_dev, (i2c_dev->master_msgs->addr <<1) |0x1, I2C_BYTE_BUF_REG); - else - ast_i2c_write(i2c_dev, (i2c_dev->master_msgs->addr <<1), I2C_BYTE_BUF_REG); - - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - - ast_i2c_write(i2c_dev, AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD, I2C_CMD_REG); - - - } else if (i2c_dev->master_xfer_cnt < i2c_dev->master_msgs->len){ - xfer_buf = i2c_dev->master_msgs->buf; - if(i2c_dev->master_msgs->flags & I2C_M_RD) { - //Rx data - cmd = AST_I2CD_M_RX_CMD; - if((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->master_xfer_cnt == 0)) { - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN \n"); - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - - } else if((i2c_dev->xfer_last == 1) && (i2c_dev->master_xfer_cnt + 1 == i2c_dev->master_msgs->len)) { - cmd |= AST_I2CD_M_S_RX_CMD_LAST | AST_I2CD_M_STOP_CMD; - // disable rx_dwn isr - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - } - - dev_dbg(i2c_dev->dev, "(<--) rx byte, cmd = %x \n",cmd); - - ast_i2c_write(i2c_dev, cmd, I2C_CMD_REG); - + ast_i2c_issue_cmd(bus, cmd); - } else { - //Tx data - dev_dbg(i2c_dev->dev, "(-->) xfer byte data index[%02x]:%02x \n",i2c_dev->master_xfer_cnt, *(xfer_buf + i2c_dev->master_xfer_cnt)); - ast_i2c_write(i2c_dev, *(xfer_buf + i2c_dev->master_xfer_cnt), I2C_BYTE_BUF_REG); - if((i2c_dev->xfer_last == 1) && (i2c_dev->master_xfer_cnt + 1 == i2c_dev->master_msgs->len)) { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) & - ~AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - ast_i2c_write(i2c_dev, AST_I2CD_M_TX_CMD | AST_I2CD_M_STOP_CMD, I2C_CMD_REG); - } else { - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - ast_i2c_write(i2c_dev, AST_I2CD_M_TX_CMD, I2C_CMD_REG); - } - } - - } else { - //should send next msg - if(i2c_dev->master_xfer_cnt != i2c_dev->master_msgs->len) - printk("CNT ERROR \n"); - - dev_dbg(i2c_dev->dev, "ast_i2c_do_byte_xfer complete \n"); - i2c_dev->cmd_err = 0; - complete(&i2c_dev->cmd_complete); - - } + } else { + return false; } - + + return true; } -static void ast_i2c_slave_xfer_done(struct ast_i2c_dev *i2c_dev) +//TX/Rx Done +static void ast_i2c_master_xfer_done(struct ast_i2c_bus *bus) { - u32 xfer_len = 0; - int i; - u8 *rx_buf; - - dev_dbg(i2c_dev->dev, "ast_i2c_slave_xfer_done [%d]\n",i2c_dev->slave_xfer_mode); - - if (i2c_dev->slave_msgs->flags & I2C_M_RD) { - //tx done , only check tx count ... - if(i2c_dev->slave_xfer_mode == BYTE_XFER) { - xfer_len = 1; - } else if (i2c_dev->slave_xfer_mode == BUFF_XFER) { - xfer_len = AST_I2CD_TX_DATA_BUF_GET(ast_i2c_read(i2c_dev, I2C_BUF_CTRL_REG)); - xfer_len++; - dev_dbg(i2c_dev->dev,"S tx buff done len %d \n",xfer_len); - } else if (i2c_dev->slave_xfer_mode == DEC_DMA_XFER) { - //DMA mode - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - if(xfer_len == 0) - xfer_len = i2c_dev->slave_xfer_len; - else - xfer_len = i2c_dev->slave_xfer_len - xfer_len - 1; - dev_dbg(i2c_dev->dev,"S tx tx dma done len %d \n",xfer_len); - } else if (i2c_dev->slave_xfer_mode == INC_DMA_XFER) { - //DMA mode - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - xfer_len = i2c_dev->slave_xfer_len - xfer_len; - dev_dbg(i2c_dev->dev,"S tx tx dma done len %d \n",xfer_len); + bool next_msg_queued; - } else { - printk("ERROR type !! \n"); - } + 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 { - //rx done - if(i2c_dev->slave_xfer_mode == BYTE_XFER) { - //TODO - xfer_len = 1; -#ifdef CONFIG_AST_I2C_SLAVE_RDWR - if(i2c_dev->slave_event == I2C_SLAVE_EVENT_STOP) { - i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt] = 0; - i2c_dev->slave_msgs->len = i2c_dev->slave_xfer_cnt; - } else { - i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt] = ast_i2c_read(i2c_dev,I2C_BYTE_BUF_REG) >> 8; - } -#else - if(i2c_dev->slave_event != I2C_SLAVE_EVENT_STOP) - i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt] = ast_i2c_read(i2c_dev,I2C_BYTE_BUF_REG) >> 8; -#endif - - dev_dbg(i2c_dev->dev,"rx buff %d, [%x] \n",i2c_dev->slave_xfer_cnt ,i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt]); - } else if (i2c_dev->slave_xfer_mode == BUFF_XFER) { - xfer_len = AST_I2CD_RX_BUF_ADDR_GET(ast_i2c_read(i2c_dev, I2C_BUF_CTRL_REG)); -#if defined(AST_SOC_G5) -#else - if(xfer_len == 0) - xfer_len = AST_I2C_PAGE_SIZE; -#endif - i2c_dev->slave_xfer_len = xfer_len; - dev_dbg(i2c_dev->dev,"rx buff done len %d \n",xfer_len); - - rx_buf = (u8 *)i2c_dev->req_page->page_addr; -#if defined(AST_SOC_G5) - dev_dbg(i2c_dev->dev, "offset buffer = %x \n",i2c_dev->bus_id * 0x10); - - rx_buf = (u8 *) (i2c_dev->req_page->page_addr + i2c_dev->bus_id * 0x10); -#endif - - if(xfer_len >i2c_dev->slave_msgs->len) - printk("big len \n"); - - for(i=0;islave_msgs->buf[i2c_dev->slave_xfer_cnt+i] = rx_buf[i]; - dev_dbg(i2c_dev->dev,"%d, [%x] \n",i2c_dev->slave_xfer_cnt+i ,i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt+i]); - } - - } else if (i2c_dev->slave_xfer_mode == DEC_DMA_XFER) { - //RX DMA DOWN - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - if(xfer_len == 0) - xfer_len = i2c_dev->slave_xfer_len; - else - xfer_len = i2c_dev->slave_xfer_len - xfer_len - 1; - dev_dbg(i2c_dev->dev, " S rx dma done len %d \n", xfer_len); - - for(i=0;islave_msgs->buf[i2c_dev->slave_xfer_cnt+i] = i2c_dev->dma_buf[i]; - dev_dbg(i2c_dev->dev,"%d, [%x] \n",i2c_dev->slave_xfer_cnt+i ,i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt+i]); - } - } else if (i2c_dev->slave_xfer_mode == INC_DMA_XFER) { - //RX DMA DOWN - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - if(xfer_len == 0) - xfer_len = i2c_dev->slave_xfer_len; - else - xfer_len = i2c_dev->slave_xfer_len - xfer_len; - - dev_dbg(i2c_dev->dev, " S rx dma done len %d \n", xfer_len); - for(i=0;islave_msgs->buf[i2c_dev->slave_xfer_cnt+i] = i2c_dev->dma_buf[i]; - dev_dbg(i2c_dev->dev,"%d, [%x] \n",i2c_dev->slave_xfer_cnt+i ,i2c_dev->slave_msgs->buf[i2c_dev->slave_xfer_cnt+i]); - } - } else { - printk("ERROR !! XFER Type \n"); - } - - } - - if(xfer_len != i2c_dev->slave_xfer_len) { - dev_dbg(i2c_dev->dev,"slave not xfer complete should goto stop\n"); - i2c_dev->slave_xfer_cnt += xfer_len; - } else - i2c_dev->slave_xfer_cnt += i2c_dev->slave_xfer_len; - - - if((i2c_dev->slave_event == I2C_SLAVE_EVENT_NACK) || (i2c_dev->slave_event == I2C_SLAVE_EVENT_STOP)) { -#ifdef CONFIG_AST_I2C_SLAVE_RDWR - ast_i2c_slave_rdwr_xfer(i2c_dev); -#else - i2c_dev->ast_i2c_data->slave_xfer(i2c_dev->slave_event, &(i2c_dev->slave_msgs)); -#endif - i2c_dev->slave_xfer_cnt = 0; - } else { - dev_dbg(i2c_dev->dev,"i2c_dev->slave_xfer_cnt %d , i2c_dev->slave_msgs->len = %d \n",i2c_dev->slave_xfer_cnt, i2c_dev->slave_msgs->len); - if(i2c_dev->slave_xfer_cnt == i2c_dev->slave_msgs->len) { - dev_dbg(i2c_dev->dev,"slave next msgs \n"); -#ifdef CONFIG_AST_I2C_SLAVE_RDWR - ast_i2c_slave_rdwr_xfer(i2c_dev); -#else - i2c_dev->ast_i2c_data->slave_xfer(i2c_dev->slave_event, &(i2c_dev->slave_msgs)); -#endif - - i2c_dev->slave_xfer_cnt = 0; - } - i2c_dev->do_slave_xfer(i2c_dev); - } - //Issue workaround - i2c_dev->state = (ast_i2c_read(i2c_dev,I2C_CMD_REG) >> 19) & 0xf; - - if(AST_I2CD_IDLE == i2c_dev->state) { - dev_dbg(i2c_dev->dev,"** Slave go IDLE **\n"); - i2c_dev->slave_operation = 0; - - if(i2c_dev->slave_xfer_mode == BUFF_XFER) { - i2c_dev->ast_i2c_data->free_pool_buff_page(i2c_dev->req_page); - } - - } - -} + if (bus->msg->flags & I2C_M_RD) { + uint8_t data; -//TX/Rx Done -static void ast_i2c_master_xfer_done(struct ast_i2c_dev *i2c_dev) -{ - u32 xfer_len = 0; - int i; - u8 *pool_buf; - - dev_dbg(i2c_dev->dev, "ast_i2c_master_xfer_done mode[%d] %s\n",i2c_dev->master_xfer_mode, i2c_dev->master_msgs->flags & I2C_M_RD ? "read" : "write"); - - if (i2c_dev->master_msgs->flags & I2C_M_RD) { - if(i2c_dev->master_xfer_cnt == -1) { - xfer_len = 1; - dev_dbg(i2c_dev->dev, "goto next_xfer \n"); - goto next_xfer; - } - if(i2c_dev->master_xfer_mode == BYTE_XFER) { - if ((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->blk_r_flag == 0)) { - i2c_dev->master_msgs->len += (ast_i2c_read(i2c_dev,I2C_BYTE_BUF_REG) & AST_I2CD_RX_BYTE_BUFFER) >> 8; - i2c_dev->blk_r_flag = 1; - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN %d \n", i2c_dev->master_msgs->len -1); - } - xfer_len = 1; - i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt] = (ast_i2c_read(i2c_dev,I2C_BYTE_BUF_REG) & AST_I2CD_RX_BYTE_BUFFER) >> 8; - } else if (i2c_dev->master_xfer_mode == BUFF_XFER) { - pool_buf = (u8 *)i2c_dev->req_page->page_addr; -#if defined(AST_SOC_G5) - dev_dbg(i2c_dev->dev, "offset buffer = %x \n",i2c_dev->bus_id * 0x10); - - pool_buf = (u8 *) (i2c_dev->req_page->page_addr + i2c_dev->bus_id * 0x10); -#endif - - xfer_len = AST_I2CD_RX_BUF_ADDR_GET(ast_i2c_read(i2c_dev, I2C_BUF_CTRL_REG)); -#if defined(AST_SOC_G5) -#else - if(xfer_len == 0) - xfer_len = AST_I2C_PAGE_SIZE; -#endif - for(i = 0; i< xfer_len; i++) { - i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt + i] = pool_buf[i]; - dev_dbg(i2c_dev->dev, "rx %d buff[%x]\n",i2c_dev->master_xfer_cnt+i, i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt+i]); - } + data = (ast_i2c_read(bus, I2C_BYTE_BUF_REG) & + AST_I2CD_RX_BYTE_BUFFER) >> 8; - if ((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->blk_r_flag == 0)) { - i2c_dev->master_msgs->len += pool_buf[0]; - i2c_dev->blk_r_flag = 1; - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN %d \n", i2c_dev->master_msgs->len -1); - } - } else if (i2c_dev->master_xfer_mode == DEC_DMA_XFER) { - //DMA Mode - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - if(xfer_len == 0) - xfer_len = i2c_dev->master_xfer_len; - else - xfer_len = i2c_dev->master_xfer_len - xfer_len - 1; - for(i = 0; i < xfer_len; i++) { - i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt + i] = i2c_dev->dma_buf[i]; - dev_dbg(i2c_dev->dev, "buf[%x] \n", i2c_dev->dma_buf[i]); - dev_dbg(i2c_dev->dev, "buf[%x] \n", i2c_dev->dma_buf[i+1]); - } - - if ((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->blk_r_flag == 0)) { - i2c_dev->master_msgs->len += i2c_dev->dma_buf[0]; - i2c_dev->blk_r_flag = 1; - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN %d \n", i2c_dev->master_msgs->len -1); - } - - } else if (i2c_dev->master_xfer_mode == INC_DMA_XFER) { - //DMA Mode - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - if(xfer_len == 0) - xfer_len = i2c_dev->master_xfer_len; - else - xfer_len = i2c_dev->master_xfer_len - xfer_len; - - for(i = 0; i < xfer_len; i++) { - i2c_dev->master_msgs->buf[i2c_dev->master_xfer_cnt + i] = i2c_dev->dma_buf[i]; - dev_dbg(i2c_dev->dev, "buf[%x] \n", i2c_dev->dma_buf[i]); - dev_dbg(i2c_dev->dev, "buf[%x] \n", i2c_dev->dma_buf[i+1]); - } - - if ((i2c_dev->master_msgs->flags & I2C_M_RECV_LEN) && (i2c_dev->blk_r_flag == 0)) { - i2c_dev->master_msgs->len += i2c_dev->dma_buf[0]; - i2c_dev->blk_r_flag = 1; - dev_dbg(i2c_dev->dev, "I2C_M_RECV_LEN %d \n", i2c_dev->master_msgs->len -1); + 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); } - - } else { - printk("ERROR xfer type \n"); - } - - - }else { - if(i2c_dev->master_xfer_mode == BYTE_XFER) { - xfer_len = 1; - } else if(i2c_dev->master_xfer_mode == BUFF_XFER) { - xfer_len = AST_I2CD_TX_DATA_BUF_GET(ast_i2c_read(i2c_dev, I2C_BUF_CTRL_REG)); - xfer_len++; - dev_dbg(i2c_dev->dev,"tx buff done len %d \n",xfer_len); - } else if(i2c_dev->master_xfer_mode == DEC_DMA_XFER) { - //DMA - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - if(xfer_len == 0) - xfer_len = i2c_dev->master_xfer_len; - else - xfer_len = i2c_dev->master_xfer_len - xfer_len - 1; - dev_dbg(i2c_dev->dev,"tx dma done len %d \n",xfer_len); - } else if(i2c_dev->master_xfer_mode == INC_DMA_XFER) { - //DMA - xfer_len = ast_i2c_read(i2c_dev, I2C_DMA_LEN_REG); - xfer_len = i2c_dev->master_xfer_len - xfer_len; - dev_dbg(i2c_dev->dev,"tx dma done len %d \n",xfer_len); - } else { - printk("ERROR xfer type \n"); + bus->msg->buf[bus->msg_pos] = data; } - + bus->msg_pos++; } -next_xfer: - - if(xfer_len != i2c_dev->master_xfer_len) { - //TODO.. - printk(" ** xfer_len = %d != master_xfer_len = %d \n", xfer_len, i2c_dev->master_xfer_len); - //should goto stop.... - i2c_dev->cmd_err = 1; - goto done_out; - } else - i2c_dev->master_xfer_cnt += i2c_dev->master_xfer_len; - - if(i2c_dev->master_xfer_cnt != i2c_dev->master_msgs->len) { - dev_dbg(i2c_dev->dev,"do next cnt \n"); - i2c_dev->do_master_xfer(i2c_dev); - } else { -#if 0 - int i; - printk(" ===== \n"); - for(i=0;imaster_msgs->len;i++) - printk("rx buf i,[%x]\n",i,i2c_dev->master_msgs->buf[i]); - printk(" ===== \n"); -#endif - i2c_dev->cmd_err = 0; - -done_out: - dev_dbg(i2c_dev->dev,"msgs complete \n"); - complete(&i2c_dev->cmd_complete); - } + /* 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); } -static void ast_i2c_slave_addr_match(struct ast_i2c_dev *i2c_dev) +static irqreturn_t ast_i2c_bus_irq(int irq, void *dev_id) { - u8 match; + struct ast_i2c_bus *bus = dev_id; - i2c_dev->slave_operation = 1; - i2c_dev->slave_xfer_cnt = 0; - match = ast_i2c_read(i2c_dev,I2C_BYTE_BUF_REG) >> 8; - i2c_dev->slave_msgs->buf[0] = match; - dev_dbg(i2c_dev->dev, "S Start Addr match [%x] \n",match); + const u32 errs = AST_I2CD_INTR_ARBIT_LOSS | + AST_I2CD_INTR_ABNORMAL | + AST_I2CD_INTR_SCL_TIMEOUT | + AST_I2CD_INTR_SDA_DL_TIMEOUT | + AST_I2CD_INTR_TX_NAK; + u32 sts, cmd; - - if(match & 1) { - i2c_dev->slave_event = I2C_SLAVE_EVENT_START_READ; - } else { - i2c_dev->slave_event = I2C_SLAVE_EVENT_START_WRITE; - } - -#ifdef CONFIG_AST_I2C_SLAVE_RDWR - ast_i2c_slave_rdwr_xfer(i2c_dev); - i2c_dev->slave_msgs->buf[0] = match; - i2c_dev->slave_xfer_cnt = 1; -#else - i2c_dev->ast_i2c_data->slave_xfer(i2c_dev->slave_event, &(i2c_dev->slave_msgs)); - i2c_dev->slave_xfer_cnt = 0; -#endif - - //request - if(i2c_dev->ast_i2c_data->slave_dma == BYTE_MODE) { - i2c_dev->do_slave_xfer = ast_i2c_do_byte_xfer; - i2c_dev->do_slave_xfer_done = ast_i2c_slave_xfer_done; - } else if (i2c_dev->ast_i2c_data->slave_dma == DEC_DMA_MODE) { - i2c_dev->do_slave_xfer = ast_i2c_do_dec_dma_xfer; - i2c_dev->do_slave_xfer_done = ast_i2c_slave_xfer_done; - } else if (i2c_dev->ast_i2c_data->slave_dma == INC_DMA_MODE) { - i2c_dev->do_slave_xfer = ast_i2c_do_inc_dma_xfer; - i2c_dev->do_slave_xfer_done = ast_i2c_slave_xfer_done; - } else { - if(i2c_dev->ast_i2c_data->request_pool_buff_page(&(i2c_dev->req_page)) == 0) - i2c_dev->do_slave_xfer = ast_i2c_do_pool_xfer; - else - i2c_dev->do_slave_xfer = ast_i2c_do_byte_xfer; - } + spin_lock(&bus->cmd_lock); - i2c_dev->do_slave_xfer(i2c_dev); + 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); -static irqreturn_t i2c_ast_handler(int this_irq, void *dev_id) -{ - u32 sts; + sts &= 0x7fff; + bus->state = cmd >> 19 & 0xf; - struct ast_i2c_dev *i2c_dev = dev_id; - u32 isr_sts = readl(i2c_dev->ast_i2c_data->reg_gr); + /* ack everything */ + ast_i2c_write(bus, sts, I2C_INTR_STS_REG); - if(!(isr_sts & (1<< i2c_dev->bus_id))) - return IRQ_NONE; + bus->cmd_err |= sts & errs; + bus->cmd_pending = cmd & AST_I2CD_CMDS; - i2c_dev->state = (ast_i2c_read(i2c_dev,I2C_CMD_REG) >> 19) & 0xf; - sts = ast_i2c_read(i2c_dev,I2C_INTR_STS_REG); + /* if we've seen an error, notify our waiter */ + if (bus->cmd_err) { + complete(&bus->cmd_complete); - //Ryan Fix for Issue No one care .. - sts &= 0xff; - dev_dbg(i2c_dev->dev,"ISR : %x \n",sts); + /* We have a transfer in progress */ + } else if (bus->msg && !bus->cmd_pending) { + ast_i2c_master_xfer_done(bus); -// dev_dbg(i2c_dev->dev,"sts machine %x, slave_op %d \n", xfer_sts,i2c_dev->slave_operation); + /* Other message queued: recovery, error stop. Notify waiters. */ + } else if (bus->cmd_sent && !bus->cmd_pending) { + complete(&bus->cmd_complete); - if(AST_I2CD_INTR_STS_SMBUS_ALT & sts) { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_SMBUS_ALT= %x\n",sts); - //Disable ALT INT - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev, I2C_INTR_CTRL_REG) & - ~AST_I2CD_SMBUS_ALT_INTR_EN, - I2C_INTR_CTRL_REG); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_SMBUS_ALT, I2C_INTR_STS_REG); - ast_master_alert_recv(i2c_dev); - sts &= ~AST_I2CD_SMBUS_ALT_INTR_EN; + } else { + dev_err(bus->dev, "Invalid state (msg %p, pending %x)?", + bus->msg, bus->cmd_pending); } - - switch(sts) { - case AST_I2CD_INTR_STS_TX_ACK: - if(i2c_dev->slave_operation == 1) { - i2c_dev->slave_event = I2C_SLAVE_EVENT_READ; - ast_i2c_slave_xfer_done(i2c_dev); - dev_dbg(i2c_dev->dev, "S clear isr: AST_I2CD_INTR_STS_TX_ACK = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_ACK, I2C_INTR_STS_REG); - } else { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_TX_ACK = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_ACK, I2C_INTR_STS_REG); - ast_i2c_master_xfer_done(i2c_dev); - } - break; - case AST_I2CD_INTR_STS_TX_ACK | AST_I2CD_INTR_STS_NORMAL_STOP: - if((i2c_dev->xfer_last == 1) && (i2c_dev->slave_operation == 0)) { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_TX_ACK | AST_I2CD_INTR_STS_NORMAL_STOP= %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_ACK | AST_I2CD_INTR_STS_NORMAL_STOP, I2C_INTR_STS_REG); - //take care - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_TX_ACK_INTR_EN, I2C_INTR_CTRL_REG); - ast_i2c_master_xfer_done(i2c_dev); - - } else { - printk("TODO ...\n"); - } - break; - case AST_I2CD_INTR_STS_TX_NAK: - if(i2c_dev->slave_operation == 1) { - i2c_dev->slave_event = I2C_SLAVE_EVENT_NACK; - ast_i2c_slave_xfer_done(i2c_dev); - dev_dbg(i2c_dev->dev, "S clear isr: AST_I2CD_INTR_STS_TX_NAK = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_NAK, I2C_INTR_STS_REG); - - } else { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_TX_NAK = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_NAK, I2C_INTR_STS_REG); - if(i2c_dev->master_msgs->flags == I2C_M_IGNORE_NAK) { - dev_dbg(i2c_dev->dev, "I2C_M_IGNORE_NAK next send\n"); - i2c_dev->cmd_err = 0; - } else { - dev_dbg(i2c_dev->dev, "NAK error\n"); - i2c_dev->cmd_err = AST_I2CD_INTR_STS_TX_NAK; - } - complete(&i2c_dev->cmd_complete); - } - break; - - case AST_I2CD_INTR_STS_TX_NAK | AST_I2CD_INTR_STS_NORMAL_STOP: - if(i2c_dev->slave_operation == 1) { - printk("SLAVE TODO .... \n"); - - } else { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_TX_NAK| AST_I2CD_INTR_STS_NORMAL_STOP = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_NAK | AST_I2CD_INTR_STS_NORMAL_STOP, I2C_INTR_STS_REG); - dev_dbg(i2c_dev->dev, "M TX NAK | NORMAL STOP \n"); - i2c_dev->cmd_err = AST_I2CD_INTR_STS_TX_NAK | AST_I2CD_INTR_STS_NORMAL_STOP; - complete(&i2c_dev->cmd_complete); - } - break; - - //Issue : Workaround for I2C slave mode - case AST_I2CD_INTR_STS_TX_NAK | AST_I2CD_INTR_STS_SLAVE_MATCH: - if(i2c_dev->slave_operation == 1) { - i2c_dev->slave_event = I2C_SLAVE_EVENT_NACK; - ast_i2c_slave_xfer_done(i2c_dev); - ast_i2c_slave_addr_match(i2c_dev); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_NAK | AST_I2CD_INTR_STS_SLAVE_MATCH , I2C_INTR_STS_REG); - } else { - printk("ERROR !!!!\n"); - } - break; - case AST_I2CD_INTR_STS_RX_DOWN | AST_I2CD_INTR_STS_SLAVE_MATCH: - ast_i2c_slave_addr_match(i2c_dev); - dev_dbg(i2c_dev->dev, "S clear isr: AST_I2CD_INTR_STS_RX_DOWN | AST_I2CD_INTR_STS_SLAVE_MATCH = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_RX_DOWN | AST_I2CD_INTR_STS_SLAVE_MATCH, I2C_INTR_STS_REG); - break; - - case AST_I2CD_INTR_STS_RX_DOWN: - if(i2c_dev->slave_operation == 1) { - i2c_dev->slave_event = I2C_SLAVE_EVENT_WRITE; - ast_i2c_slave_xfer_done(i2c_dev); - dev_dbg(i2c_dev->dev, "S clear isr: AST_I2CD_INTR_STS_RX_DOWN = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_RX_DOWN, I2C_INTR_STS_REG); - } else { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_RX_DOWN = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_RX_DOWN, I2C_INTR_STS_REG); - ast_i2c_master_xfer_done(i2c_dev); - - } - break; - - case AST_I2CD_INTR_STS_NORMAL_STOP: - if(i2c_dev->slave_operation == 1) { - i2c_dev->slave_event = I2C_SLAVE_EVENT_STOP; - ast_i2c_slave_xfer_done(i2c_dev); - dev_dbg(i2c_dev->dev, "S clear isr: AST_I2CD_INTR_STS_NORMAL_STOP = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_NORMAL_STOP, I2C_INTR_STS_REG); - dev_dbg(i2c_dev->dev, "state [%x] \n",i2c_dev->state); - } else { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_NORMAL_STOP = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_NORMAL_STOP, I2C_INTR_STS_REG); - i2c_dev->cmd_err = 0; - complete(&i2c_dev->cmd_complete); - } - break; -#if 0 - //Issue for slave S:Da:[[T:S:Da]]:T - case (AST_I2CD_INTR_STS_RX_DOWN | AST_I2CD_INTR_STS_NORMAL_STOP | AST_I2CD_INTR_STS_SLAVE_MATCH): - if(i2c_dev->slave_operation == 1) { - //STOP - i2c_dev->slave_event = I2C_SLAVE_EVENT_STOP; - ast_i2c_slave_xfer_done(i2c_dev); - dev_dbg(i2c_dev->dev, "S clear isr: AST_I2CD_INTR_STS_NORMAL_STOP = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_NORMAL_STOP, I2C_INTR_STS_REG); - dev_dbg(i2c_dev->dev, "state [%x] \n",i2c_dev->state); - //SLAVE MATCH - i2c_dev->slave_event = I2C_SLAVE_EVENT_NACK; - ast_i2c_slave_xfer_done(i2c_dev); - ast_i2c_slave_addr_match(i2c_dev); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_TX_NAK | AST_I2CD_INTR_STS_SLAVE_MATCH , I2C_INTR_STS_REG); - } else { - printk("TODO ERROR \n"); - } - break; -#endif - case (AST_I2CD_INTR_STS_RX_DOWN | AST_I2CD_INTR_STS_NORMAL_STOP): - if((i2c_dev->xfer_last == 1) && (i2c_dev->slave_operation == 0)) { - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_RX_DOWN | AST_I2CD_INTR_STS_NORMAL_STOP = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_RX_DOWN | AST_I2CD_INTR_STS_NORMAL_STOP, I2C_INTR_STS_REG); - //take care - ast_i2c_write(i2c_dev, ast_i2c_read(i2c_dev,I2C_INTR_CTRL_REG) | - AST_I2CD_RX_DOWN_INTR_EN, I2C_INTR_CTRL_REG); - ast_i2c_master_xfer_done(i2c_dev); - } else { - printk("TODO .. .. ..\n"); - } - break; - case AST_I2CD_INTR_STS_ARBIT_LOSS: - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_ARBIT_LOSS = %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_ARBIT_LOSS, I2C_INTR_STS_REG); - i2c_dev->cmd_err = AST_I2CD_INTR_STS_ARBIT_LOSS; - complete(&i2c_dev->cmd_complete); - break; - case AST_I2CD_INTR_STS_ABNORMAL: - i2c_dev->cmd_err = AST_I2CD_INTR_STS_ABNORMAL; - complete(&i2c_dev->cmd_complete); - break; - case AST_I2CD_INTR_STS_SCL_TO: - i2c_dev->cmd_err = AST_I2CD_INTR_STS_SCL_TO; - complete(&i2c_dev->cmd_complete); - - break; - case AST_I2CD_INTR_STS_GCALL_ADDR: - i2c_dev->cmd_err = AST_I2CD_INTR_STS_GCALL_ADDR; - complete(&i2c_dev->cmd_complete); - - break; - case AST_I2CD_INTR_STS_SMBUS_DEF_ADDR: - break; - case AST_I2CD_INTR_STS_SMBUS_DEV_ALT: - - break; - - case AST_I2CD_INTR_STS_SMBUS_ARP_ADDR: - break; - case AST_I2CD_INTR_STS_SDA_DL_TO: - break; - case AST_I2CD_INTR_STS_BUS_RECOVER: - dev_dbg(i2c_dev->dev, "M clear isr: AST_I2CD_INTR_STS_BUS_RECOVER= %x\n",sts); - ast_i2c_write(i2c_dev, AST_I2CD_INTR_STS_BUS_RECOVER, I2C_INTR_STS_REG); - i2c_dev->cmd_err = 0; - complete(&i2c_dev->cmd_complete); - break; - default: - if(sts) - printk("GR %x : No one care : %x, bus_id %d\n",(u32)i2c_dev->ast_i2c_data->reg_gr, sts, i2c_dev->bus_id); - return IRQ_NONE; - } + spin_unlock(&bus->cmd_lock); return IRQ_HANDLED; - } -static int ast_i2c_do_msgs_xfer(struct ast_i2c_dev *i2c_dev, struct i2c_msg *msgs, int num) +static int ast_i2c_do_msgs_xfer(struct ast_i2c_bus *bus, + struct i2c_msg *msgs, int num) { - int i; - int ret = 0; - - dev_dbg(i2c_dev->dev, "ast_i2c_do_msgs_xfer\n"); - //request - if(i2c_dev->ast_i2c_data->master_dma == BYTE_MODE) - i2c_dev->do_master_xfer = ast_i2c_do_byte_xfer; - else if (i2c_dev->ast_i2c_data->master_dma == DEC_DMA_MODE) - i2c_dev->do_master_xfer = ast_i2c_do_dec_dma_xfer; - else if (i2c_dev->ast_i2c_data->master_dma == INC_DMA_MODE) - i2c_dev->do_master_xfer = ast_i2c_do_inc_dma_xfer; - else { - if(i2c_dev->ast_i2c_data->request_pool_buff_page(&(i2c_dev->req_page)) == 0) - i2c_dev->do_master_xfer = ast_i2c_do_pool_xfer; - else - i2c_dev->do_master_xfer = ast_i2c_do_byte_xfer; - } - - for (i=0; i < num; i++) { - i2c_dev->blk_r_flag = 0; - i2c_dev->master_msgs = &msgs[i]; - if(num == i+1) - i2c_dev->xfer_last = 1; - else - i2c_dev->xfer_last = 0; - - i2c_dev->blk_r_flag = 0; - init_completion(&i2c_dev->cmd_complete); - - if(i2c_dev->master_msgs->flags & I2C_M_NOSTART) - i2c_dev->master_xfer_cnt = 0; - else - i2c_dev->master_xfer_cnt = -1; - - i2c_dev->do_master_xfer(i2c_dev); - - ret = wait_for_completion_interruptible_timeout(&i2c_dev->cmd_complete, - i2c_dev->adap.timeout*HZ); - - if (ret == 0) { - dev_dbg(i2c_dev->dev, "controller timed out\n"); - i2c_dev->state = (ast_i2c_read(i2c_dev,I2C_CMD_REG) >> 19) & 0xf; -// printk("sts [%x], isr sts [%x] \n",i2c_dev->state, ast_i2c_read(i2c_dev,I2C_INTR_STS_REG)); - ret = -ETIMEDOUT; - goto stop; + 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(i2c_dev->cmd_err != 0) { - if(i2c_dev->cmd_err == (AST_I2CD_INTR_STS_TX_NAK | AST_I2CD_INTR_STS_NORMAL_STOP)) { - dev_dbg(i2c_dev->dev, "go out \n"); - ret = -ETIMEDOUT; - goto out; + if (err != 0) { + if (cmd & AST_I2CD_M_STOP_CMD) { + return -ETIMEDOUT; } else { - dev_dbg(i2c_dev->dev, "send stop \n"); - ret = -EAGAIN; - goto stop; + dev_dbg(bus->dev, "send stop\n"); + ast_i2c_issue_oob_command(bus, + AST_I2CD_M_STOP_CMD); + return -EAGAIN; } } - ret++; } - if(i2c_dev->cmd_err == 0) - goto out; -stop: - init_completion(&i2c_dev->cmd_complete); - ast_i2c_write(i2c_dev, AST_I2CD_M_STOP_CMD, I2C_CMD_REG); - wait_for_completion_interruptible_timeout(&i2c_dev->cmd_complete, - i2c_dev->adap.timeout*HZ); - -out: - //Free .. - if(i2c_dev->master_xfer_mode == BUFF_XFER) { - i2c_dev->ast_i2c_data->free_pool_buff_page(i2c_dev->req_page); - - } - dev_dbg(i2c_dev->dev, "end xfer ret = %d, xfer mode[%d]\n",ret, i2c_dev->master_xfer_mode); - return ret; - + return num; } -static int ast_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +static int ast_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) { - struct ast_i2c_dev *i2c_dev = adap->algo_data; + struct ast_i2c_bus *bus = adap->algo_data; int ret, i; int sts; - sts = ast_i2c_read(i2c_dev,I2C_CMD_REG); - dev_dbg(i2c_dev->dev, "state[%x],SCL[%d],SDA[%d],BUS[%d]\n", (sts >> 19) & 0xf, (sts >> 18) & 0x1,(sts >> 17) & 0x1,(sts >> 16) & 1); + 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. */ - - ret = ast_i2c_wait_bus_not_busy(i2c_dev); + + ret = ast_i2c_wait_bus_not_busy(bus); if (ret) { - dev_err(&i2c_dev->adap.dev, "i2c_ast: timeout waiting for bus free\n"); + dev_err(&adap->dev, "i2c_ast: timeout waiting for bus free\n"); goto out; } for (i = adap->retries; i >= 0; i--) { - if(i != 0) + if (i != 0) dev_dbg(&adap->dev, "Do retrying transmission [%d]\n",i); - - ret = ast_i2c_do_msgs_xfer(i2c_dev, msgs, num); + + ret = ast_i2c_do_msgs_xfer(bus, msgs, num); if (ret != -EAGAIN) goto out; udelay(100); } - + ret = -EREMOTEIO; out: @@ -2027,234 +676,187 @@ static u32 ast_i2c_functionality(struct i2c_adapter *adap) static const struct i2c_algorithm i2c_ast_algorithm = { .master_xfer = ast_i2c_xfer, -#ifdef CONFIG_AST_I2C_SLAVE_RDWR - .slave_xfer = ast_i2c_slave_xfer, -#endif .functionality = ast_i2c_functionality, }; -static int ast_i2c_probe(struct platform_device *pdev) +static int ast_i2c_probe_bus(struct platform_device *pdev) { - struct ast_i2c_dev *i2c_dev; - struct resource *res; - int ret; + struct ast_i2c_bus *bus; + struct resource res; + int ret, bus_num; - dev_dbg(&pdev->dev, "ast_i2c_probe \n"); + bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); + if (!bus) + return -ENOMEM; - i2c_dev = kzalloc(sizeof(struct ast_i2c_dev), GFP_KERNEL); - if (!i2c_dev) { - ret = -ENOMEM; - goto err_no_mem; - } + ret = of_property_read_u32(pdev->dev.of_node, "bus", &bus_num); + if (ret) + return -ENXIO; - i2c_dev->ast_i2c_data = pdev->dev.platform_data; - //master xfer mode - if(i2c_dev->ast_i2c_data->master_dma == BUFF_MODE) { - dev_dbg(&pdev->dev, "use buffer pool mode\n"); - } else if ((i2c_dev->ast_i2c_data->master_dma >= DEC_DMA_MODE) || (i2c_dev->ast_i2c_data->slave_dma >= DEC_DMA_MODE)) { - dev_dbg(&pdev->dev, "use dma mode \n"); - if (!i2c_dev->dma_buf) { - i2c_dev->dma_buf = dma_alloc_coherent(NULL, AST_I2C_DMA_SIZE, &i2c_dev->dma_addr, GFP_KERNEL); - if (!i2c_dev->dma_buf) { - printk("unable to allocate tx Buffer memory\n"); - ret = -ENOMEM; - goto err_no_dma; - } - if(i2c_dev->dma_addr%4 !=0) { - printk("not 4 byte boundary \n"); - ret = -ENOMEM; - goto err_no_dma; - } - dev_dbg(&pdev->dev, "dma_buf = [0x%x] dma_addr = [0x%x], please check 4byte boundary \n",(u32)i2c_dev->dma_buf,i2c_dev->dma_addr); - memset (i2c_dev->dma_buf, 0, AST_I2C_DMA_SIZE); - } + ret = of_address_to_resource(pdev->dev.of_node, 0, &res); + if (ret < 0) + return -ENXIO; - } else { - //master_mode 0: use byte mode - dev_dbg(&pdev->dev, "use default byte mode \n"); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (NULL == res) { - dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); - ret = -ENOENT; - goto err_no_io_res; - } - if (!request_mem_region(res->start, resource_size(res), res->name)) { - dev_err(&pdev->dev, "cannot reserved region\n"); - ret = -ENXIO; - goto err_no_io_res; + bus->pclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(bus->pclk)) { + dev_dbg(&pdev->dev, "clk_get failed\n"); + return PTR_ERR(bus->pclk); } - i2c_dev->reg_base = ioremap(res->start, resource_size(res)); - if (!i2c_dev->reg_base) { - ret = -EIO; - goto release_mem; - } + bus->base = devm_ioremap_resource(&pdev->dev, &res); + if (IS_ERR(bus->base)) + return PTR_ERR(bus->base); - i2c_dev->irq = platform_get_irq(pdev, 0); - if (i2c_dev->irq < 0) { - dev_err(&pdev->dev, "no irq specified\n"); - ret = -ENOENT; - goto ereqirq; + bus->irq = platform_get_irq(pdev, 0); + if (bus->irq < 0) { + dev_err(&pdev->dev, "platform_get_irq failed\n"); + return -ENXIO; } - i2c_dev->dev = &pdev->dev; - -#if defined (CONFIG_ARCH_AST1070) - if(i2c_dev->irq == IRQ_C0_I2C) { - i2c_dev->bus_id = pdev->id - NUM_BUS; - dev_dbg(&pdev->dev, "C0 :: pdev->id %d , i2c_dev->bus_id = %d, i2c_dev->irq =%d\n",pdev->id, i2c_dev->bus_id,i2c_dev->irq); - } else if(i2c_dev->irq == IRQ_C1_I2C) { - i2c_dev->bus_id = pdev->id - (NUM_BUS + 8); - dev_dbg(&pdev->dev, "C1 :: pdev->id %d , i2c_dev->bus_id = %d, i2c_dev->irq =%d\n",pdev->id, i2c_dev->bus_id,i2c_dev->irq); - } else { - i2c_dev->bus_id = pdev->id; - dev_dbg(&pdev->dev, "AST pdev->id %d , i2c_dev->bus_id = %d, i2c_dev->irq =%d\n",pdev->id, i2c_dev->bus_id,i2c_dev->irq); + ret = devm_request_irq(&pdev->dev, bus->irq, ast_i2c_bus_irq, + 0, "ast-i2c-bus", bus); + if (ret) { + dev_err(&pdev->dev, "devm_request_irq failed\n"); + return -ENXIO; + } + + /* Initialize the I2C adapter */ + bus->adap.nr = bus_num; + bus->adap.owner = THIS_MODULE; + bus->adap.retries = 0; + bus->adap.timeout = 5; + bus->adap.algo = &i2c_ast_algorithm; + bus->adap.algo_data = bus; + bus->adap.dev.parent = &pdev->dev; + bus->adap.dev.of_node = pdev->dev.of_node; + snprintf(bus->adap.name, sizeof(bus->adap.name), "Aspeed i2c at %p", + bus->base); + + 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; } -#else - i2c_dev->bus_id = pdev->id; -#endif - /* Initialize the I2C adapter */ - i2c_dev->adap.owner = THIS_MODULE; -//TODO - i2c_dev->adap.retries = 0; + ast_i2c_dev_init(bus); -// i2c_dev->adap.retries = 3; + ret = i2c_add_numbered_adapter(&bus->adap); + if (ret < 0) + return -ENXIO; - i2c_dev->adap.timeout = 5; + dev_info(bus->dev, "i2c bus %d registered, irq %d\n", + bus->adap.nr, bus->irq); - i2c_dev->master_xfer_mode = BYTE_XFER; + return 0; +} - /* - * If "pdev->id" is negative we consider it as zero. - * The reason to do so is to avoid sysfs names that only make - * sense when there are multiple adapters. - */ - i2c_dev->adap.nr = pdev->id != -1 ? pdev->id : 0; - snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name), "ast_i2c.%u", - i2c_dev->adap.nr); +static void noop(struct irq_data *data) { } - i2c_dev->slave_operation = 0; - i2c_dev->blk_r_flag = 0; - i2c_dev->adap.algo = &i2c_ast_algorithm; +static struct irq_chip ast_i2c_irqchip = { + .name = "ast-i2c", + .irq_unmask = noop, + .irq_mask = noop, +}; - ret = request_irq(i2c_dev->irq, i2c_ast_handler, IRQF_SHARED, - i2c_dev->adap.name, i2c_dev); - if (ret) { - printk(KERN_INFO "I2C: Failed request irq %d\n", i2c_dev->irq); - goto ereqirq; +static void ast_i2c_controller_irq(struct irq_desc *desc) +{ + struct ast_i2c_controller *c = irq_desc_get_handler_data(desc); + unsigned long p, status; + unsigned int bus_irq; + + status = readl(c->base); + for_each_set_bit(p, &status, ast_i2c_n_busses) { + bus_irq = irq_find_mapping(c->irq_domain, p); + generic_handle_irq(bus_irq); } +} - ast_i2c_dev_init(i2c_dev); +static int ast_i2c_probe_controller(struct platform_device *pdev) +{ + struct ast_i2c_controller *controller; + struct device_node *np; + struct resource *res; + int i, irq; -#ifdef CONFIG_AST_I2C_SLAVE_RDWR - ast_i2c_slave_buff_init(i2c_dev); -#endif + controller = kzalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + return -ENOMEM; - i2c_dev->adap.algo_data = i2c_dev; - i2c_dev->adap.dev.parent = &pdev->dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + controller->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(controller->base)) + return PTR_ERR(controller->base); - ret = i2c_add_numbered_adapter(&i2c_dev->adap); - if (ret < 0) { - printk(KERN_INFO "I2C: Failed to add bus\n"); - goto eadapt; + controller->irq = platform_get_irq(pdev, 0); + if (controller->irq < 0) { + dev_err(&pdev->dev, "no platform IRQ\n"); + return -ENXIO; } -#if 0 - ret = sysfs_create_group(&pdev->dev.kobj, &ast_i2c_attr_groups); - if (ret) - goto ereqirq; -#endif - platform_set_drvdata(pdev, i2c_dev); - printk(KERN_INFO "I2C: %s: AST I2C adapter [%d khz]\n", - i2c_dev->adap.name,i2c_dev->ast_i2c_data->bus_clk/1000); + controller->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + ast_i2c_n_busses, &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"; - return 0; + for (i = 0; i < ast_i2c_n_busses; i++) { + irq = irq_create_mapping(controller->irq_domain, i); + irq_set_chip_data(irq, controller); + irq_set_chip_and_handler(irq, &ast_i2c_irqchip, + handle_simple_irq); + } -eadapt: - free_irq(i2c_dev->irq, i2c_dev); -ereqirq: - iounmap(i2c_dev->reg_base); -release_mem: - release_mem_region(res->start, resource_size(res)); -err_no_io_res: -err_no_dma: - kfree(i2c_dev); - -err_no_mem: - return ret; -} + irq_set_chained_handler_and_data(controller->irq, + ast_i2c_controller_irq, controller); -static int ast_i2c_remove(struct platform_device *pdev) -{ - struct ast_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - struct resource *res; + controller->dev = &pdev->dev; - platform_set_drvdata(pdev, NULL); - i2c_del_adapter(&i2c_dev->adap); - - free_irq(i2c_dev->irq, i2c_dev); + platform_set_drvdata(pdev, controller); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iounmap(i2c_dev->reg_base); - release_mem_region(res->start, res->end - res->start + 1); + dev_info(controller->dev, "i2c controller registered, irq %d\n", + controller->irq); - kfree(i2c_dev); + for_each_child_of_node(pdev->dev.of_node, np) + of_platform_device_create(np, NULL, &pdev->dev); return 0; } -#ifdef CONFIG_PM -static int ast_i2c_suspend(struct platform_device *pdev, pm_message_t state) -{ - //TODO -// struct ast_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - return 0; -} - -static int ast_i2c_resume(struct platform_device *pdev) +static int ast_i2c_probe(struct platform_device *pdev) { - //TODO -// struct ast_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - //Should reset i2c ??? - return 0; -} -#else -#define ast_i2c_suspend NULL -#define ast_i2c_resume NULL -#endif + if (of_device_is_compatible(pdev->dev.of_node, + "aspeed,ast2400-i2c-controller")) + return ast_i2c_probe_controller(pdev); -static struct platform_driver i2c_ast_driver = { - .probe = ast_i2c_probe, - .remove = ast_i2c_remove, - .suspend = ast_i2c_suspend, - .resume = ast_i2c_resume, - .driver = { - .name = "ast-i2c", - .owner = THIS_MODULE, - }, -}; + if (of_device_is_compatible(pdev->dev.of_node, + "aspeed,ast2400-i2c-bus")) + return ast_i2c_probe_bus(pdev); -static int __init ast_i2c_init(void) -{ - return platform_driver_register(&i2c_ast_driver); + return -ENODEV; } -static void __exit ast_i2c_exit(void) -{ - platform_driver_unregister(&i2c_ast_driver); -} -//TODO : check module init sequence +static const struct of_device_id ast_i2c_of_table[] = { + { .compatible = "aspeed,ast2400-i2c-controller", }, + { .compatible = "aspeed,ast2400-i2c-bus", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ast_i2c_of_table); -#if defined(CONFIG_VGA_DDC) -subsys_initcall(ast_i2c_init); -#else -module_init(ast_i2c_init); -#endif +static struct platform_driver i2c_ast_driver = { + .probe = ast_i2c_probe, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = ast_i2c_of_table, + }, +}; -module_exit(ast_i2c_exit); +module_platform_driver(i2c_ast_driver); MODULE_AUTHOR("Ryan Chen "); MODULE_DESCRIPTION("ASPEED AST I2C Bus Driver");