From: Henrik Nordstrom <hen...@henriknordstrom.net>

Based linux-sunxi#sunxi commit d854c4de2f57 "arm: Handle .gnu.hash section in
ldscripts" vs v2014.01.

As well as the following signed-off-by the sunxi branch shows commits to
the sunxi_i2c.c file by:

Stefan Roese <s...@denx.de>

Signed-off-by: Henrik Nordstrom <hen...@henriknordstrom.net>
Signed-off-by: Oliver Schinagl <oli...@schinagl.nl>
Signed-off-by: Hans de Goede <hdego...@redhat.com>
---
 arch/arm/cpu/armv7/sunxi/board.c      |   6 +
 arch/arm/include/asm/arch-sunxi/i2c.h | 169 ++++++++++++++++++++++
 drivers/i2c/Makefile                  |   1 +
 drivers/i2c/sunxi_i2c.c               | 260 ++++++++++++++++++++++++++++++++++
 include/configs/sunxi-common.h        |   8 ++
 5 files changed, 444 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-sunxi/i2c.h
 create 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 72eed16..b00bf89 100644
--- a/arch/arm/cpu/armv7/sunxi/board.c
+++ b/arch/arm/cpu/armv7/sunxi/board.c
@@ -11,6 +11,7 @@
  */
 
 #include <common.h>
+#include <i2c.h>
 #include <serial.h>
 #ifdef CONFIG_SPL_BUILD
 #include <spl.h>
@@ -94,6 +95,11 @@ void s_init(void)
        gd = &gdata;
        preloader_console_init();
 
+#ifdef CONFIG_SPL_I2C_SUPPORT
+       /* Needed early by sunxi_board_init if PMU is enabled */
+       i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+
        sunxi_board_init();
 #endif
 }
diff --git a/arch/arm/include/asm/arch-sunxi/i2c.h 
b/arch/arm/include/asm/arch-sunxi/i2c.h
new file mode 100644
index 0000000..74c2d18
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/i2c.h
@@ -0,0 +1,169 @@
+/*
+ * (C) Copyright 2012 Henrik Nordstrom <hen...@henriknordstrom.net>
+ *
+ * Based on sun4i linux kernle i2c.h
+ * (C) Copyright 2007-2012
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Tom Cubie <tangla...@allwinnertech.com>
+ * Victor Wei <weizih...@allwinnertech.com>
+ *
+ * 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
+
+/* No relevant status infomation,INT_FLAG = 0 */
+#define TWI_STAT_IDLE          0xf8
+
+#endif
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index fa3a875..2a44db4 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -15,6 +15,7 @@ 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
diff --git a/drivers/i2c/sunxi_i2c.c b/drivers/i2c/sunxi_i2c.c
new file mode 100644
index 0000000..9a542f6
--- /dev/null
+++ b/drivers/i2c/sunxi_i2c.c
@@ -0,0 +1,260 @@
+/*
+ * (C) Copyright 2012 Henrik Nordstrom <hen...@henriknordstrom.net>
+ *
+ * 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 *)0x1c2ac00;
+
+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 fe41b89..1f2bcb5 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -176,6 +176,14 @@
 #undef CONFIG_CMD_NET
 #undef CONFIG_CMD_NFS
 
+/* I2C */
+#define CONFIG_SPL_I2C_SUPPORT
+#define CONFIG_SYS_I2C_SPEED           400000
+#define CONFIG_HARD_I2C
+#define CONFIG_SUNXI_I2C
+#define CONFIG_SYS_I2C_SLAVE           0x7f
+#define CONFIG_CMD_I2C
+
 #ifndef CONFIG_CONS_INDEX
 #define CONFIG_CONS_INDEX              1       /* UART0 */
 #endif
-- 
1.9.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to