#include #include #include #include "board.h" #include "drv_clock.h" #include "drv_gpio.h" #define I2C_DEBUG 0 #if I2C_DEBUG #define I2C_DBG(...) rt_kprintf("[I2C]"),rt_kprintf(__VA_ARGS__) #else #define I2C_DBG(...) #endif #define I2C_CTRL (0x00) #define I2C_TAR (0x04) #define I2C_SAR (0x08) #define I2C_DC (0x10) #define I2C_SHCNT (0x14) #define I2C_SLCNT (0x18) #define I2C_FHCNT (0x1C) #define I2C_FLCNT (0x20) #define I2C_INTST (0x2C) #define I2C_INTM (0x30) #define I2C_RXTL (0x38) #define I2C_TXTL (0x3c) #define I2C_CINTR (0x40) #define I2C_CRXUF (0x44) #define I2C_CRXOF (0x48) #define I2C_CTXOF (0x4C) #define I2C_CRXREQ (0x50) #define I2C_CTXABRT (0x54) #define I2C_CRXDONE (0x58) #define I2C_CACT (0x5C) #define I2C_CSTP (0x60) #define I2C_CSTT (0x64) #define I2C_CGC (0x68) #define I2C_ENB (0x6C) #define I2C_STA (0x70) #define I2C_TXFLR (0x74) #define I2C_RXFLR (0x78) #define I2C_SDAHD (0x7C) #define I2C_TXABRT (0x80) #define I2C_DMACR (0x88) #define I2C_DMATDLR (0x8c) #define I2C_DMARDLR (0x90) #define I2C_SDASU (0x94) #define I2C_ACKGC (0x98) #define I2C_ENSTA (0x9C) #define I2C_FLT (0xA0) /* I2C Control Register (I2C_CTRL) */ #define I2C_CTRL_SLVDIS (1 << 6) /* after reset slave is disabled */ #define I2C_CTRL_REST (1 << 5) #define I2C_CTRL_MATP (1 << 4) /* 1: 10bit address 0: 7bit addressing */ #define I2C_CTRL_SATP (1 << 3) /* 1: 10bit address 0: 7bit address */ #define I2C_CTRL_SPDF (2 << 1) /* fast mode 400kbps */ #define I2C_CTRL_SPDS (1 << 1) /* standard mode 100kbps */ #define I2C_CTRL_MD (1 << 0) /* master enabled */ /* I2C Status Register (I2C_STA) */ #define I2C_STA_SLVACT (1 << 6) /* Slave FSM is not in IDLE state */ #define I2C_STA_MSTACT (1 << 5) /* Master FSM is not in IDLE state */ #define I2C_STA_RFF (1 << 4) /* RFIFO if full */ #define I2C_STA_RFNE (1 << 3) /* RFIFO is not empty */ #define I2C_STA_TFE (1 << 2) /* TFIFO is empty */ #define I2C_STA_TFNF (1 << 1) /* TFIFO is not full */ #define I2C_STA_ACT (1 << 0) /* I2C Activity Status */ /* i2c interrupt status (I2C_INTST) */ #define I2C_INTST_IGC (1 << 11) #define I2C_INTST_ISTT (1 << 10) #define I2C_INTST_ISTP (1 << 9) #define I2C_INTST_IACT (1 << 8) #define I2C_INTST_RXDN (1 << 7) #define I2C_INTST_TXABT (1 << 6) #define I2C_INTST_RDREQ (1 << 5) #define I2C_INTST_TXEMP (1 << 4) #define I2C_INTST_TXOF (1 << 3) #define I2C_INTST_RXFL (1 << 2) #define I2C_INTST_RXOF (1 << 1) #define I2C_INTST_RXUF (1 << 0) /* i2c interrupt mask status (I2C_INTM) */ #define I2C_INTM_MIGC (1 << 11) #define I2C_INTM_MISTT (1 << 10) #define I2C_INTM_MISTP (1 << 9) #define I2C_INTM_MIACT (1 << 8) #define I2C_INTM_MRXDN (1 << 7) #define I2C_INTM_MTXABT (1 << 6) #define I2C_INTM_MRDREQ (1 << 5) #define I2C_INTM_MTXEMP (1 << 4) #define I2C_INTM_MTXOF (1 << 3) #define I2C_INTM_MRXFL (1 << 2) #define I2C_INTM_MRXOF (1 << 1) #define I2C_INTM_MRXUF (1 << 0) #define I2C_DC_REST (1 << 10) #define I2C_DC_STP (1 << 9) #define I2C_DC_READ (1 << 8) #define I2C_ENB_I2CENB (1 << 0) /* Enable the i2c */ #define CONFIG_I2C_FIFO_LEN 64 #define I2C_FIFO_LEN (CONFIG_I2C_FIFO_LEN) #define TX_LEVEL (I2C_FIFO_LEN / 2) #define RX_LEVEL (I2C_FIFO_LEN / 2 - 1) #define TIMEOUT 0xff /* * msg_end_type: The bus control which need to be send at end of transfer. * @MSG_END_STOP: Send stop pulse at end of transfer. * @MSG_END_REPEAT_START: Send repeat start at end of transfer. */ enum msg_end_type { MSG_END_STOP, MSG_END_CONTINUE, MSG_END_REPEAT_START, }; /* I2C standard mode high count register(I2CSHCNT) */ #define I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) /* I2C standard mode low count register(I2CSLCNT) */ #define I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) /* I2C fast mode high count register(I2CFHCNT) */ #define I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) /* I2C fast mode low count register(I2CFLCNT) */ #define I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) /* I2C Transmit Abort Status Register (I2C_TXABRT) */ static const char *abrt_src[] = { "I2C_TXABRT_ABRT_7B_ADDR_NOACK", "I2C_TXABRT_ABRT_10ADDR1_NOACK", "I2C_TXABRT_ABRT_10ADDR2_NOACK", "I2C_TXABRT_ABRT_XDATA_NOACK", "I2C_TXABRT_ABRT_GCALL_NOACK", "I2C_TXABRT_ABRT_GCALL_READ", "I2C_TXABRT_ABRT_HS_ACKD", "I2C_TXABRT_SBYTE_ACKDET", "I2C_TXABRT_ABRT_HS_NORSTRT", "I2C_TXABRT_SBYTE_NORSTRT", "I2C_TXABRT_ABRT_10B_RD_NORSTRT", "I2C_TXABRT_ABRT_MASTER_DIS", "I2C_TXABRT_ARB_LOST", "I2C_TXABRT_SLVFLUSH_TXFIFO", "I2C_TXABRT_SLV_ARBLOST", "I2C_TXABRT_SLVRD_INTX", }; struct ingenic_i2c_bus { struct rt_i2c_bus_device parent; rt_uint32_t hwaddr; rt_uint32_t irqno; struct clk *clk; enum msg_end_type w_end_type; enum msg_end_type r_end_type; unsigned char *rbuf; unsigned char *wbuf; unsigned int rd_len; int len; unsigned int rate; struct rt_completion completion; }; #ifdef RT_USING_I2C0 static struct ingenic_i2c_bus ingenic_i2c0; #endif #ifdef RT_USING_I2C1 static struct ingenic_i2c_bus ingenic_i2c1; #endif #ifdef RT_USING_I2C2 static struct ingenic_i2c_bus ingenic_i2c2; #endif static inline unsigned short i2c_readl(struct ingenic_i2c_bus *i2c, unsigned short offset) { return readl(i2c->hwaddr + offset); } static inline void i2c_writel(struct ingenic_i2c_bus *i2c, unsigned short offset, unsigned short value) { writel(value, i2c->hwaddr + offset); } static int ingenic_i2c_disable(struct ingenic_i2c_bus *i2c) { int timeout = TIMEOUT; i2c_writel(i2c, I2C_ENB, 0); while ((i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) && (--timeout > 0)) rt_thread_delay(1); if (timeout) return 0; I2C_DBG("disable i2c failed!\n"); return -RT_ETIMEOUT; } static int ingenic_i2c_enable(struct ingenic_i2c_bus *i2c) { int timeout = TIMEOUT; i2c_writel(i2c, I2C_ENB, 1); while (!(i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) && (--timeout > 0)) rt_thread_delay(1); if (timeout) return 0; I2C_DBG("enable i2c failed\n"); return -RT_ETIMEOUT; } static void ingenic_i2c_reset(struct ingenic_i2c_bus *i2c) { i2c_readl(i2c, I2C_CTXABRT); i2c_readl(i2c, I2C_INTST); ingenic_i2c_disable(i2c); rt_thread_delay(1); ingenic_i2c_enable(i2c); } static int ingenic_i2c_set_speed(struct ingenic_i2c_bus *i2c, int rate) { /*ns */ long dev_clk = clk_get_rate(i2c->clk); long cnt_high = 0; /* HIGH period count of the SCL clock */ long cnt_low = 0; /* LOW period count of the SCL clock */ long setup_time = 0; long hold_time = 0; unsigned short tmp; i2c->rate = rate; if (ingenic_i2c_disable(i2c))I2C_DBG("i2c not disable\n"); if (rate <= 100000) { tmp = 0x43 | (1 << 5); /* standard speed mode */ i2c_writel(i2c, I2C_CTRL, tmp); } else { tmp = 0x45 | (1 << 5); /* fast speed mode */ i2c_writel(i2c, I2C_CTRL, tmp); } /* high * ____ ____ ____ ____ * clk __| | |___| |____| |____| |___ * | | | * | | | * |_|_| _________ ____ * data __/ | |\___/ \____/ \____ * setup->| |<| * ->| |<-hold */ //setup_time = (10 000 000/(rate*4)) + 1; setup_time = (dev_clk / (rate * 4)); if (setup_time > 1) setup_time -= 1; //hold_time = (10000000/(rate*4)) - 1; hold_time = (dev_clk / (rate * 4)); /* high * ____ ____ * clk __| |___| |____ * low * |<--period--->| * */ cnt_high = dev_clk / (rate * 2); cnt_low = dev_clk / (rate * 2); if (setup_time > 255) setup_time = 255; if (setup_time <= 0) setup_time = 1; if (hold_time > 0xFFFF) hold_time = 0xFFFF; if (rate <= 100000) { i2c_writel(i2c, I2C_SHCNT, I2CSHCNT_ADJUST(cnt_high)); i2c_writel(i2c, I2C_SLCNT, I2CSLCNT_ADJUST(cnt_low)); } else { i2c_writel(i2c, I2C_FHCNT, I2CFHCNT_ADJUST(cnt_high)); i2c_writel(i2c, I2C_FLCNT, I2CFLCNT_ADJUST(cnt_low)); } i2c_writel(i2c, I2C_SDASU, setup_time & 0xff); i2c_writel(i2c, I2C_SDAHD, hold_time); return 0; } /* function: send read command * return: 0, successful * 1, txfifo valid entry is more than receive fifo, before send read command, * must be read. * 2, txfifo count is 0 or rxfifo count is 0. * */ static inline unsigned int i2c_send_rcmd(struct ingenic_i2c_bus *i2c) { unsigned int tx_count, rx_count, count, tx_valid, rx_valid; tx_valid = i2c_readl(i2c, I2C_TXFLR); rx_valid = i2c_readl(i2c, I2C_RXFLR); tx_count = I2C_FIFO_LEN - tx_valid; rx_count = I2C_FIFO_LEN - rx_valid; if (tx_valid > rx_count) { I2C_DBG("###Warning: I2C transfer fifo valid entry is more receive fifo, " "before send read cmd, please read data from " "the read fifo.\n"); return 1; } if (!tx_count || !rx_count) { I2C_DBG("###Warning: I2C receive fifo or transfer fifo is full, " "before send read cmd, please read data from " "the read fifo or wait some time.\n\n"); return 2; } count = (i2c->rd_len < tx_count)? i2c->rd_len : tx_count; count = (count < rx_count)? count : rx_count; i2c->rd_len -= count; if (!i2c->rd_len) { while (count > 1) { i2c_writel(i2c, I2C_DC, I2C_DC_READ); count--; } if (i2c->r_end_type == MSG_END_STOP) { i2c_writel(i2c, I2C_DC, I2C_DC_READ | I2C_DC_STP); } else { i2c_writel(i2c, I2C_DC, I2C_DC_READ); } } else { while (count > 0) { i2c_writel(i2c, I2C_DC, I2C_DC_READ); count--; } } return 0; } static void txabrt(struct ingenic_i2c_bus *i2c, int src) { int i; I2C_DBG("--I2C txabrt:\n"); for (i = 0; i < 16; i++) { if (src & (0x1 << i)) I2C_DBG("--I2C TXABRT[%d]=%s\n", i, abrt_src[i]); } } static int i2c_disable_clk(struct ingenic_i2c_bus *i2c) { int timeout = 10; int tmp = i2c_readl(i2c, I2C_STA); while ((tmp & I2C_STA_MSTACT) && (--timeout > 0)) { rt_thread_delay(2); tmp = i2c_readl(i2c, I2C_STA); } if (timeout > 0) { clk_disable(i2c->clk); return 0; } else { I2C_DBG("--I2C disable clk timeout, I2C_STA = 0x%x\n", tmp); ingenic_i2c_reset(i2c); clk_disable(i2c->clk); return -RT_ETIMEOUT; } } static inline int xfer_read(struct ingenic_i2c_bus *i2c, unsigned char *buf, int len, enum msg_end_type end_type) { int ret = 0; long timeout; unsigned short tmp; rt_memset(buf, 0, len); i2c->rd_len = len; i2c->len = len; i2c->rbuf = buf; i2c->r_end_type = end_type; i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ I2C_DBG("i2c: read %d len data\n", len); if (len <= I2C_FIFO_LEN) { i2c_writel(i2c, I2C_RXTL, len - 1); } else { i2c_writel(i2c, I2C_RXTL, RX_LEVEL); } // I2C_DBG("RXTL: %x\n", i2c_readl(i2c, I2C_RXTL)); I2C_DBG("read len: %d\n", i2c_readl(i2c, I2C_RXFLR)); while (i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) { i2c_readl(i2c, I2C_DC); } if (i2c_send_rcmd(i2c)) { I2C_DBG("i2c: send read command failed!\n"); } else { I2C_DBG("i2c: send read command OK!\n"); } tmp = I2C_INTM_MRXFL | I2C_INTM_MTXABT; if (end_type == MSG_END_STOP) tmp |= I2C_INTM_MISTP; i2c_writel(i2c, I2C_INTM, tmp); /* wait for finish */ while(rt_completion_wait(&(i2c->completion), RT_TICK_PER_SECOND) == -RT_ETIMEOUT) I2C_DBG("fifo len: %d\n", i2c_readl(i2c, I2C_RXFLR)); tmp = i2c_readl(i2c, I2C_TXABRT); if (tmp) { txabrt(i2c, tmp); if (tmp > 0x1 && tmp < 0x10) ret = -RT_EIO; else ret = -RT_EIO; /* abort read */ if (tmp & (1 << 5)) { ret = -RT_ERROR; } i2c_readl(i2c, I2C_CTXABRT); } if (ret < 0) ingenic_i2c_reset(i2c); return ret; } static inline int xfer_write(struct ingenic_i2c_bus *i2c, unsigned char *buf, int len, enum msg_end_type end_type) { int ret = 0; long timeout = TIMEOUT; unsigned short reg_tmp; i2c->wbuf = buf; i2c->len = len; i2c_writel(i2c, I2C_TXTL, TX_LEVEL); i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ I2C_DBG("i2c: write %d len data\n", len); i2c->w_end_type = end_type; while ((i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF) && (i2c->len > 0)) { reg_tmp = *i2c->wbuf++; if (i2c->len == 1) { if (end_type == MSG_END_STOP) { reg_tmp |= I2C_DC_STP; } } i2c_writel(i2c, I2C_DC, reg_tmp); i2c->len -= 1; } if (i2c->len == 0) { i2c_writel(i2c, I2C_TXTL, 0); } reg_tmp = I2C_INTM_MTXEMP | I2C_INTM_MTXABT | I2C_INTM_MTXOF; if (end_type == MSG_END_STOP) reg_tmp |= I2C_INTM_MISTP; i2c_writel(i2c, I2C_INTM, reg_tmp); /* wait for finish */ rt_completion_wait(&(i2c->completion), rt_tick_from_millisecond(2000)); reg_tmp = i2c_readl(i2c, I2C_TXABRT); if (reg_tmp) { txabrt(i2c, reg_tmp); if (reg_tmp > 0x1 && reg_tmp < 0x10) ret = -RT_EIO; else ret = -RT_EIO; //after I2C_TXABRT_ABRT_XDATA_NOACK error,this required core to resend if (reg_tmp & 8) { ret = -RT_ERROR; } i2c_readl(i2c, I2C_CTXABRT); } if (ret < 0) ingenic_i2c_reset(i2c); return ret; } static rt_size_t ingenic_i2c_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num) { int i; int ret = RT_EOK; struct ingenic_i2c_bus *i2c; i2c = (struct ingenic_i2c_bus*)bus; clk_enable(i2c->clk); i2c_writel(i2c, I2C_TAR, msgs[0].addr); for (i = 0; i < num; i++) { enum msg_end_type end_type = MSG_END_STOP; if (i < (num - 1)) { if (msgs[i + 1].flags & RT_I2C_NO_START) { end_type = MSG_END_CONTINUE; /* have no STOP and START */ } else { end_type = MSG_END_REPEAT_START; /* have no STOP but have RESTART */ } } /* initialize completion */ rt_completion_init(&(i2c->completion)); if (msgs[i].flags & RT_I2C_RD) { ret = xfer_read(i2c, msgs[i].buf, msgs[i].len, end_type); } else { ret = xfer_write(i2c, msgs[i].buf, msgs[i].len, end_type); } if (ret < 0) { clk_disable(i2c->clk); goto _ERR; } } ret = i2c_disable_clk(i2c); _ERR: return ret < 0? ret : i; } static const struct rt_i2c_bus_device_ops i2c_ops = { ingenic_i2c_xfer, RT_NULL, RT_NULL }; static void i2c_irq_handler(int irqno, void *param) { unsigned short tmp, intst, intmsk; struct ingenic_i2c_bus *i2c; i2c = (struct ingenic_i2c_bus*)param; intst = i2c_readl(i2c, I2C_INTST); intmsk = i2c_readl(i2c, I2C_INTM); I2C_DBG("i2c irq!!\n"); if ((intst & I2C_INTST_TXABT) && (intmsk & I2C_INTM_MTXABT)) { I2C_DBG("%s %d, I2C transfer error, ABORT interrupt\n", __func__, __LINE__); goto END_TRSF_IRQ_HND; } if ((intst & I2C_INTST_ISTP) && (intmsk & I2C_INTM_MISTP)) { i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ if (i2c->len == 0) goto END_TRSF_IRQ_HND; } if ((intmsk & I2C_INTM_MTXEMP) && (intst & I2C_INTST_TXEMP)) { if (!i2c->len) { if (i2c->w_end_type == MSG_END_REPEAT_START) { goto END_TRSF_IRQ_HND; } else { tmp = i2c_readl(i2c, I2C_INTM); tmp &= ~I2C_INTM_MTXEMP; i2c_writel(i2c, I2C_INTM, tmp); } } else { while ((i2c->len > 0) && (i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF)) { tmp = *i2c->wbuf++; if (i2c->len == 1) { if (i2c->w_end_type == MSG_END_STOP) tmp |= I2C_DC_STP; } i2c_writel(i2c, I2C_DC, tmp); i2c->len -= 1; } if (i2c->len == 0) { i2c_writel(i2c, I2C_TXTL, 0); } } } if ((intst & I2C_INTST_RXFL) && (intmsk & I2C_INTM_MRXFL)) { I2C_DBG("I2C RXFL\n"); while ((i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) && (i2c->len > 0)) { tmp = i2c_readl(i2c, I2C_DC) & 0xff; *i2c->rbuf++ = tmp; i2c->len--; } if (i2c->len == 0) { goto END_RECE_IRQ_HND; } if (i2c->len <= I2C_FIFO_LEN) { i2c_writel(i2c, I2C_RXTL, i2c->len - 1); } if (i2c_send_rcmd(i2c)) { I2C_DBG("%s %d, I2C controller has BUG, RXFLR or TXFLR can not clear\n", __func__, __LINE__); } } if ((intst & I2C_INTST_RXOF) && (intmsk & I2C_INTM_MRXOF)) { I2C_DBG("%s %d, I2C transfer error, RXFIFO over full\n", __func__, __LINE__); i2c_readl(i2c, I2C_CRXOF); /* clear RXOF bit */ } if ((intst & I2C_INTST_TXOF) && (intmsk & I2C_INTM_MTXOF)) { I2C_DBG("%s %d, I2C transfer error, TXFIFO over full\n", __func__, __LINE__); i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ goto END_TRSF_IRQ_HND; } return ; END_RECE_IRQ_HND: END_TRSF_IRQ_HND: i2c_writel(i2c, I2C_INTM, 0); rt_completion_done(&i2c->completion); } int rt_hw_i2c_init(void) { struct ingenic_i2c_bus *i2c; struct rt_i2c_bus_device *i2c_bus; #ifdef RT_USING_I2C0 { i2c = &ingenic_i2c0; rt_memset((void *)i2c, 0, sizeof(struct ingenic_i2c_bus)); i2c->hwaddr = I2C0_BASE; i2c->irqno = IRQ_I2C0; /* Set PB23 PB24 in func0 (I2C0) */ gpio_set_func(GPIO_PORT_B, GPIO_Pin_24, GPIO_FUNC_0); gpio_set_func(GPIO_PORT_B, GPIO_Pin_23, GPIO_FUNC_0); /* enable clock */ i2c->clk = clk_get("i2c0"); clk_enable(i2c->clk); i2c_bus = &i2c->parent; i2c_bus->ops = &i2c_ops; rt_i2c_bus_device_register(i2c_bus, "i2c0"); ingenic_i2c_set_speed(i2c, 400 * 1000); /* reset I2C */ i2c_writel(i2c, I2C_CTRL, i2c_readl(i2c, I2C_CTRL) | I2C_CTRL_REST); i2c_writel(i2c, I2C_INTM, 0x0); ingenic_i2c_enable(i2c); clk_disable(i2c->clk); /* install interrupt */ rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c0"); rt_hw_interrupt_umask(i2c->irqno); } #endif #ifdef RT_USING_I2C1 { i2c = &ingenic_i2c1; rt_memset((void *)i2c, 0, sizeof(struct ingenic_i2c_bus)); i2c->hwaddr = I2C1_BASE; i2c->irqno = IRQ_I2C1; /* Set PC26 PC27 in func0 (I2C1) */ gpio_set_func(GPIO_PORT_C, GPIO_Pin_26, GPIO_FUNC_0); gpio_set_func(GPIO_PORT_C, GPIO_Pin_27, GPIO_FUNC_0); /* enable clock */ i2c->clk = clk_get("i2c1"); clk_enable(i2c->clk); i2c_bus = &i2c->parent; i2c_bus->ops = &i2c_ops; rt_i2c_bus_device_register(i2c_bus, "i2c1"); ingenic_i2c_set_speed(i2c, 400 * 1000); /* reset I2C */ i2c_writel(i2c, I2C_CTRL, i2c_readl(i2c, I2C_CTRL) | I2C_CTRL_REST); i2c_writel(i2c, I2C_INTM, 0x0); ingenic_i2c_enable(i2c); clk_disable(i2c->clk); /* install interrupt */ rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c1"); rt_hw_interrupt_umask(i2c->irqno); } #endif #ifdef RT_USING_I2C2 { i2c = &ingenic_i2c2; rt_memset((void *)i2c, 0, sizeof(struct ingenic_i2c_bus)); i2c->hwaddr = I2C2_BASE; i2c->irqno = IRQ_I2C2; /* Set PC26 PC27 in func0 (I2C1) */ gpio_set_func(GPIO_PORT_D, GPIO_Pin_0, GPIO_FUNC_1); gpio_set_func(GPIO_PORT_D, GPIO_Pin_1, GPIO_FUNC_1); /* enable clock */ i2c->clk = clk_get("i2c2"); clk_enable(i2c->clk); i2c_bus = &i2c->parent; i2c_bus->ops = &i2c_ops; rt_i2c_bus_device_register(i2c_bus, "i2c2"); ingenic_i2c_set_speed(i2c, 400 * 1000); /* reset I2C */ i2c_writel(i2c, I2C_CTRL, i2c_readl(i2c, I2C_CTRL) | I2C_CTRL_REST); i2c_writel(i2c, I2C_INTM, 0x0); ingenic_i2c_enable(i2c); clk_disable(i2c->clk); /* install interrupt */ rt_hw_interrupt_install(i2c->irqno, i2c_irq_handler, i2c, "i2c2"); rt_hw_interrupt_umask(i2c->irqno); } #endif return 0; } INIT_BOARD_EXPORT(rt_hw_i2c_init);