Sunxi uses the same i2c controller, so re-use the existing code instead of having our own duplicate code.
Signed-off-by: Hans de Goede <[email protected]> --- arch/arm/cpu/armv7/sunxi/board.c | 1 + arch/arm/include/asm/arch-sunxi/i2c.h | 164 +-------------------- board/sunxi/board.c | 7 + drivers/i2c/Makefile | 2 +- drivers/i2c/mvtwsi.c | 18 +++ drivers/i2c/sunxi_i2c.c | 260 ---------------------------------- include/configs/sunxi-common.h | 7 +- 7 files changed, 36 insertions(+), 423 deletions(-) delete mode 100644 drivers/i2c/sunxi_i2c.c diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 8147a99..9e5aec2 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -106,6 +106,7 @@ void s_init(void) clock_init(); timer_init(); gpio_init(); + i2c_init_board(); #ifdef CONFIG_SPL_BUILD gd = &gdata; diff --git a/arch/arm/include/asm/arch-sunxi/i2c.h b/arch/arm/include/asm/arch-sunxi/i2c.h index 74c2d18..dc5406b 100644 --- a/arch/arm/include/asm/arch-sunxi/i2c.h +++ b/arch/arm/include/asm/arch-sunxi/i2c.h @@ -1,169 +1,15 @@ /* - * (C) Copyright 2012 Henrik Nordstrom <[email protected]> - * - * Based on sun4i linux kernle i2c.h - * (C) Copyright 2007-2012 - * Allwinner Technology Co., Ltd. <www.allwinnertech.com> - * Tom Cubie <[email protected]> - * Victor Wei <[email protected]> + * Copyright 2014 - Hans de Goede <[email protected]> * * SPDX-License-Identifier: GPL-2.0+ */ #ifndef _SUNXI_I2C_H_ #define _SUNXI_I2C_H_ -struct i2c { - u32 saddr; /* 31:8bit res,7-1bit for slave addr,0 bit for GCE */ - u32 xsaddr; /* 31:8bit res,7-0bit for second addr in 10bit addr */ - u32 data; /* 31:8bit res, 7-0bit send or receive data byte */ - u32 ctl; /* INT_EN,BUS_EN,M_STA,INT_FLAG,A_ACK */ - u32 status; /* 28 interrupt types + 0xf8 normal type = 29 */ - u32 clkr; /* 31:7bit res,6-3bit,CLK_M,2-0bit CLK_N */ - u32 reset; /* 31:1bit res;0bit,write 1 to clear 0. */ - u32 efr; /* 31:2bit res,1:0 bit data byte follow read comand */ - u32 lctl; /* 31:6bits res 5:0bit for sda&scl control */ -}; - -/* TWI address register */ -#define TWI_GCE_EN (0x1 << 0) /* gen call addr enable slave mode */ -#define TWI_ADDR_MASK (0x7f << 1) /* 7:1bits */ -#define TWI_XADDR_MASK 0xff /* 7:0bits for extend slave address */ - -#define TWI_DATA_MASK 0xff /* 7:0bits for send or received */ - -/* TWI Control Register Bit Fields */ -/* 1:0 bits reserved */ -/* set 1 to send A_ACK,then low level on SDA */ -#define TWI_CTL_ACK (0x1 << 2) -/* INT_FLAG,interrupt status flag: set '1' when interrupt coming */ -#define TWI_CTL_INTFLG (0x1 << 3) -#define TWI_CTL_STP (0x1 << 4) /* M_STP,Automatic clear 0 */ -#define TWI_CTL_STA (0x1 << 5) /* M_STA,atutomatic clear 0 */ -#define TWI_CTL_BUSEN (0x1 << 6) /* BUS_EN, mastr mode should be set 1 */ -#define TWI_CTL_INTEN (0x1 << 7) /* INT_EN */ -/* 31:8 bit reserved */ - -/* - * TWI Clock Register Bit Fields & Masks,default value:0x0000_0000 - * Fin is APB CLOCK INPUT; - * Fsample = F0 = Fin/2^CLK_N; - * F1 = F0/(CLK_M+1); - * - * Foscl = F1/10 = Fin/(2^CLK_N * (CLK_M+1)*10); - * Foscl is clock SCL;standard mode:100KHz or fast mode:400KHz - */ - -#define TWI_CLK_DIV_M (0xf << 3) /* 6:3bit */ -#define TWI_CLK_DIV_N (0x7 << 0) /* 2:0bit */ -#define TWI_CLK_DIV(N, M) ((((N) & 0xf) << 3) | (((M) & 0x7) << 0)) - -/* TWI Soft Reset Register Bit Fields & Masks */ -/* write 1 to clear 0, when complete soft reset clear 0 */ -#define TWI_SRST_SRST (0x1 << 0) - -/* TWI Enhance Feature Register Bit Fields & Masks */ -/* default -- 0x0 */ -/* 00:no,01: 1byte, 10:2 bytes, 11: 3bytes */ -#define TWI_EFR_MASK (0x3 << 0) -#define TWI_EFR_WARC_0 (0x0 << 0) -#define TWI_EFR_WARC_1 (0x1 << 0) -#define TWI_EFR_WARC_2 (0x2 << 0) -#define TWI_EFR_WARC_3 (0x3 << 0) - -/* twi line control register -default value: 0x0000_003a */ -/* SDA line state control enable ,1:enable;0:disable */ -#define TWI_LCR_SDA_EN (0x01 << 0) -/* SDA line state control bit, 1:high level;0:low level */ -#define TWI_LCR_SDA_CTL (0x01 << 1) -/* SCL line state control enable ,1:enable;0:disable */ -#define TWI_LCR_SCL_EN (0x01 << 2) -/* SCL line state control bit, 1:high level;0:low level */ -#define TWI_LCR_SCL_CTL (0x01 << 3) -/* current state of SDA,readonly bit */ -#define TWI_LCR_SDA_STATE_MASK (0x01 << 4) -/* current state of SCL,readonly bit */ -#define TWI_LCR_SCL_STATE_MASK (0x01 << 5) -/* 31:6bits reserved */ -#define TWI_LCR_IDLE_STATUS 0x3a - -/* TWI Status Register Bit Fields & Masks */ -#define TWI_STAT_MASK 0xff -/* 7:0 bits use only,default is 0xf8 */ -#define TWI_STAT_BUS_ERR 0x00 /* BUS ERROR */ - -/* Master mode use only */ -#define TWI_STAT_TX_STA 0x08 /* START condition transmitted */ -/* Repeated START condition transmitted */ -#define TWI_STAT_TX_RESTA 0x10 -/* Address+Write bit transmitted, ACK received */ -#define TWI_STAT_TX_AW_ACK 0x18 -/* Address+Write bit transmitted, ACK not received */ -#define TWI_STAT_TX_AW_NAK 0x20 -/* data byte transmitted in master mode,ack received */ -#define TWI_STAT_TXD_ACK 0x28 -/* data byte transmitted in master mode ,ack not received */ -#define TWI_STAT_TXD_NAK 0x30 -/* arbitration lost in address or data byte */ -#define TWI_STAT_ARBLOST 0x38 -/* Address+Read bit transmitted, ACK received */ -#define TWI_STAT_TX_AR_ACK 0x40 -/* Address+Read bit transmitted, ACK not received */ -#define TWI_STAT_TX_AR_NAK 0x48 -/* Second Address byte + Write bit transmitted, ACK received */ -#define TWI_STAT_TX_2AW_ACK 0xd0 -/* Second Address byte + Write bit transmitted, ACK received */ -#define TWI_STAT_TX_2AW_NAK 0xd8 -/* data byte received in master mode ,ack transmitted */ -#define TWI_STAT_RXD_ACK 0x50 -/* date byte received in master mode,not ack transmitted */ -#define TWI_STAT_RXD_NAK 0x58 - -/* Slave mode use only */ -/* Slave address+Write bit received, ACK transmitted */ -#define TWI_STAT_RXWS_ACK 0x60 -/* - * Arbitration lost in address as master, slave address + Write bit received, - * ACK transmitted - */ -#define TWI_STAT_ARBLOST_RXWS_ACK 0x68 -/* General Call address received, ACK transmitted */ -#define TWI_STAT_RXGCAS_ACK 0x70 -/* - * Arbitration lost in address as master, General Call address received, - * ACK transmitted - */ -#define TWI_STAT_ARBLOST_RXGCAS_ACK 0x78 -/* Data byte received after slave address received, ACK transmitted */ -#define TWI_STAT_RXDS_ACK 0x80 -/* Data byte received after slave address received, not ACK transmitted */ -#define TWI_STAT_RXDS_NAK 0x88 -/* Data byte received after General Call received, ACK transmitted */ -#define TWI_STAT_RXDGCAS_ACK 0x90 -/* Data byte received after General Call received, not ACK transmitted */ -#define TWI_STAT_RXDGCAS_NAK 0x98 -/* STOP or repeated START condition received in slave */ -#define TWI_STAT_RXSTPS_RXRESTAS 0xa0 -/* Slave address + Read bit received, ACK transmitted */ -#define TWI_STAT_RXRS_ACK 0xa8 -/* - * Arbitration lost in address as master, slave address + Read bit received, - * ACK transmitted - */ -#define TWI_STAT_ARBLOST_SLAR_ACK 0xb0 -/* Data byte transmitted in slave mode, ACK received */ -#define TWI_STAT_TXDS_ACK 0xb8 -/* Data byte transmitted in slave mode, ACK not received */ -#define TWI_STAT_TXDS_NAK 0xc0 -/* Last byte transmitted in slave mode, ACK received */ -#define TWI_STAT_TXDSL_ACK 0xc8 - -/* 10bit Address, second part of address */ -/* Second Address byte+Write bit transmitted,ACK received */ -#define TWI_STAT_TX_SAW_ACK 0xd0 -/* Second Address byte+Write bit transmitted,ACK not received */ -#define TWI_STAT_TX_SAW_NAK 0xd8 +#include <asm/arch/cpu.h> -/* No relevant status infomation,INT_FLAG = 0 */ -#define TWI_STAT_IDLE 0xf8 +#define CONFIG_I2C_MVTWSI_BASE SUNXI_TWI0_BASE +/* This is abp0-clk on sun4i/5i/7i / abp1-clk on sun6i/sun8i which is 24MHz */ +#define CONFIG_SYS_TCLK 24000000 #endif diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 27feecc..c5487c7 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -136,6 +136,13 @@ int board_mmc_init(bd_t *bis) } #endif +void i2c_init_board(void) +{ + sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUNXI_GPB0_TWI0); + sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUNXI_GPB0_TWI0); + clock_twi_onoff(0, 1); +} + #if defined(CONFIG_SPL_BUILD) || defined(CONFIG_SUN6I) || defined(CONFIG_SUN8I) void sunxi_board_init(void) { diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index ca89ac7..a8ccb52 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o obj-$(CONFIG_U8500_I2C) += u8500_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o -obj-$(CONFIG_SUNXI_I2C) += sunxi_i2c.o obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o @@ -28,5 +27,6 @@ obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o +obj-$(CONFIG_SYS_I2C_SUNXI) += mvtwsi.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c index 5ba0e03..e670515 100644 --- a/drivers/i2c/mvtwsi.c +++ b/drivers/i2c/mvtwsi.c @@ -22,6 +22,8 @@ #include <asm/arch/orion5x.h> #elif defined(CONFIG_KIRKWOOD) #include <asm/arch/kirkwood.h> +#elif defined(CONFIG_SUNXI) +#include <asm/arch/i2c.h> #else #error Driver mvtwsi not supported by SoC or board #endif @@ -30,6 +32,20 @@ * TWSI register structure */ +#ifdef CONFIG_SUNXI + +struct mvtwsi_registers { + u32 slave_address; + u32 xtnd_slave_addr; + u32 data; + u32 control; + u32 status; + u32 baudrate; + u32 soft_reset; +}; + +#else + struct mvtwsi_registers { u32 slave_address; u32 data; @@ -43,6 +59,8 @@ struct mvtwsi_registers { u32 soft_reset; }; +#endif + /* * Control register fields */ diff --git a/drivers/i2c/sunxi_i2c.c b/drivers/i2c/sunxi_i2c.c deleted file mode 100644 index 43a19c4..0000000 --- a/drivers/i2c/sunxi_i2c.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * (C) Copyright 2012 Henrik Nordstrom <[email protected]> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <i2c.h> -#include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cpu.h> -#include <asm/arch/gpio.h> -#include <asm/arch/i2c.h> - -static struct i2c __attribute__ ((section(".data"))) *i2c_base = - (struct i2c *)SUNXI_TWI0_BASE; - -void i2c_init(int speed, int slaveaddr) -{ - int timeout = 0x2ff; - - sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUNXI_GPB0_TWI0); - sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUNXI_GPB0_TWI0); - clock_twi_onoff(0, 1); - - /* Enable the i2c bus */ - writel(TWI_CTL_BUSEN, &i2c_base->ctl); - - /* 400KHz operation M=2, N=1, 24MHz APB clock */ - writel(TWI_CLK_DIV(2, 1), &i2c_base->clkr); - writel(TWI_SRST_SRST, &i2c_base->reset); - - while ((readl(&i2c_base->reset) & TWI_SRST_SRST) && timeout--); -} - -int i2c_probe(uchar chip) -{ - return -1; -} - -static int i2c_wait_ctl(int mask, int state) -{ - int timeout = 0x2ff; - int value = state ? mask : 0; - - debug("i2c_wait_ctl(%x == %x), ctl=%x, status=%x\n", mask, value, - i2c_base->ctl, i2c_base->status); - - while (((readl(&i2c_base->ctl) & mask) != value) && timeout-- > 0); - - debug("i2c_wait_ctl(), timeout=%d, ctl=%x, status=%x\n", timeout, - i2c_base->ctl, i2c_base->status); - - if (timeout != 0) - return 0; - else - return -1; -} - -static void i2c_clear_irq(void) -{ - writel(readl(&i2c_base->ctl) & ~TWI_CTL_INTFLG, &i2c_base->ctl); -} - -static int i2c_wait_irq(void) -{ - return i2c_wait_ctl(TWI_CTL_INTFLG, 1); -} - -static int i2c_wait_status(int status) -{ - int timeout = 0x2ff; - - while (readl(&i2c_base->status) != status && timeout-- > 0); - - if (timeout != 0) - return 0; - else - return -1; -} - -static int i2c_wait_irq_status(int status) -{ - if (i2c_wait_irq() != 0) - return -1; - - if (readl(&i2c_base->status) != status) - return -1; - - return 0; -} - -static int i2c_wait_bus_idle(void) -{ - int timeout = 0x2ff; - - while (readl(&i2c_base->lctl) != 0x3a && timeout-- > 0); - - if (timeout != 0) - return 0; - else - return -1; -} - -static int i2c_stop(void) -{ - u32 ctl; - - ctl = readl(&i2c_base->ctl) & 0xc0; - ctl |= TWI_CTL_STP; - - writel(ctl, &i2c_base->ctl); - - /* dummy to delay one I/O operation to make sure it's started */ - (void)readl(&i2c_base->ctl); - - if (i2c_wait_ctl(TWI_CTL_STP, 0) != 0) - return -1; - if (i2c_wait_status(TWI_STAT_IDLE)) - return -1; - if (i2c_wait_bus_idle() != 0) - return -1; - - return 0; -} - -static int i2c_send_data(u8 data, u8 status) -{ - debug("i2c_write(%02x, %x), ctl=%x, status=%x\n", data, status, - i2c_base->ctl, i2c_base->status); - - writel(data, &i2c_base->data); - i2c_clear_irq(); - - if (i2c_wait_irq_status(status) != 0) - return -1; - - return 0; -} - -static int i2c_start(int status) -{ - u32 ctl; - - debug("i2c_start(%x), ctl=%x, status=%x\n", status, i2c_base->ctl, - i2c_base->status); - /* Check that the controller is idle */ - if (status == TWI_STAT_TX_STA && - readl(&i2c_base->status) != TWI_STAT_IDLE) { - return -1; - } - - writel(0, &i2c_base->efr); - - /* Send start */ - ctl = readl(&i2c_base->ctl); - ctl |= TWI_CTL_STA; /* Set start bit */ - ctl &= ~TWI_CTL_INTFLG; /* Clear int flag */ - writel(ctl, &i2c_base->ctl); - - if (i2c_wait_ctl(TWI_CTL_STA, 0) != 0) - return -1; - if (i2c_wait_irq_status(status) != 0) - return -1; - - return 0; -} - -int i2c_do_read(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - u32 status; - u32 ctl; - - if (i2c_start(TWI_STAT_TX_STA) != 0) - return -1; - - /* Send chip address */ - if (i2c_send_data(chip << 1 | 0, TWI_STAT_TX_AW_ACK) != 0) - return -1; - - /* Send data address */ - if (i2c_send_data(addr, TWI_STAT_TXD_ACK) != 0) - return -1; - - /* Send restart for read */ - if (i2c_start(TWI_STAT_TX_RESTA) != 0) - return -1; - - /* Send chip address */ - if (i2c_send_data(chip << 1 | 1, TWI_STAT_TX_AR_ACK) != 0) - return -1; - - /* Set ACK mode */ - ctl = readl(&i2c_base->ctl); - ctl |= TWI_CTL_ACK; - writel(ctl, &i2c_base->ctl); - status = TWI_STAT_RXD_ACK; - - /* Read data */ - while (len > 0) { - if (len == 1) { - /* Set NACK mode (last byte) */ - ctl = readl(&i2c_base->ctl); - ctl &= ~TWI_CTL_ACK; - writel(ctl, &i2c_base->ctl); - status = TWI_STAT_RXD_NAK; - } - - i2c_clear_irq(); - if (i2c_wait_irq_status(status) != 0) - return -1; - - *buffer++ = readl(&i2c_base->data); - len--; - } - - return 0; -} - -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - int rc = i2c_do_read(chip, addr, alen, buffer, len); - - i2c_stop(); - - return rc; -} - -static int i2c_do_write(uchar chip, uint addr, int alen, uchar *buffer, - int len) -{ - if (i2c_start(TWI_STAT_TX_STA) != 0) - return -1; - - /* Send chip address */ - if (i2c_send_data(chip << 1 | 0, TWI_STAT_TX_AW_ACK) != 0) - return -1; - - /* Send data address */ - if (i2c_send_data(addr, TWI_STAT_TXD_ACK) != 0) - return -1; - - /* Send data */ - while (len > 0) { - if (i2c_send_data(*buffer++, TWI_STAT_TXD_ACK) != 0) - return -1; - len--; - } - - return 0; -} - -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - int rc = i2c_do_write(chip, addr, alen, buffer, len); - - i2c_stop(); - - return rc; -} diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 035bc60..e11c4ee 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -314,12 +314,13 @@ #undef CONFIG_CMD_NFS /* I2C */ -#ifndef CONFIG_SUN6I +#if !defined CONFIG_SUN6I && !defined CONFIG_SUN8I #define CONFIG_SPL_I2C_SUPPORT #endif -#define CONFIG_SYS_I2C_SPEED 400000 +/* No CONFIG_SYS_I2C as we use the non converted mvtwsi driver */ #define CONFIG_HARD_I2C -#define CONFIG_SUNXI_I2C +#define CONFIG_SYS_I2C_SUNXI +#define CONFIG_SYS_I2C_SPEED 400000 #define CONFIG_SYS_I2C_SLAVE 0x7f #define CONFIG_CMD_I2C -- 1.9.0 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
