/* * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved. */ #include #include #include #include struct i2c_init_desc { unsigned long ctrl_base; unsigned char flag; }; #define I2C_INIT_UNDO 0 #define I2C_INIT_DONE 1 #define i2c_desc(reg) {.ctrl_base = (reg), \ .flag = I2C_INIT_UNDO} #define I2C_BUS_CLOCK mhz(50) #define I2C_MAX_NUM 0 struct i2c_init_desc gk_i2c_init_desc[] = NULL; /* * I2C Registers offsets */ #define VENDOR_I2C_GLB 0x0 #define VENDOR_I2C_SCL_H 0x4 #define VENDOR_I2C_SCL_L 0x8 #define VENDOR_I2C_DATA1 0x10 #define VENDOR_I2C_TXF 0x20 #define VENDOR_I2C_RXF 0x24 #define VENDOR_I2C_CMD_BASE 0x30 #define VENDOR_I2C_LOOP1 0xb0 #define VENDOR_I2C_DST1 0xb4 #define VENDOR_I2C_TX_WATER 0xc8 #define VENDOR_I2C_RX_WATER 0xcc #define VENDOR_I2C_CTRL1 0xd0 #define VENDOR_I2C_CTRL2 0xd4 #define VENDOR_I2C_STAT 0xd8 #define VENDOR_I2C_INTR_RAW 0xe0 #define VENDOR_I2C_INTR_EN 0xe4 #define VENDOR_I2C_INTR_STAT 0xe8 /* * Create a contiguous bitmask starting at bit position @l and ending at * position @h. */ #define genmask(h, l) \ (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) /* * I2C Global Config Register -- VENDOR_I2C_GLB */ #define GLB_EN_MASK BIT(0) #define GLB_SDA_HOLD_MASK genmask(23, 8) #define GLB_SDA_HOLD_SHIFT 8 /* * I2C Timing CMD Register -- VENDOR_I2C_CMD_BASE + n * 4 (n = 0, 1, 2, ... 31) */ #define CMD_EXIT 0x0 #define CMD_TX_S 0x1 #define CMD_TX_D1_2 0x4 #define CMD_TX_D1_1 0x5 #define CMD_TX_FIFO 0x9 #define CMD_RX_FIFO 0x12 #define CMD_RX_ACK 0x13 #define CMD_IGN_ACK 0x15 #define CMD_TX_ACK 0x16 #define CMD_TX_NACK 0x17 #define CMD_JMP1 0x18 #define CMD_UP_TXF 0x1d #define CMD_TX_RS 0x1e #define CMD_TX_P 0x1f /* * I2C Control Register 1 -- VENDOR_I2C_CTRL1 */ #define CTRL1_CMD_START_MASK BIT(0) /* * I2C Status Register -- VENDOR_I2C_STAT */ #define STAT_RXF_NOE_MASK BIT(16) /* RX FIFO not empty flag */ #define STAT_TXF_NOF_MASK BIT(19) /* TX FIFO not full flag */ /* * I2C Interrupt status and mask Register -- * VENDOR_I2C_INTR_RAW, VENDOR_I2C_STAT, VENDOR_I2C_INTR_STAT */ #define INTR_ABORT_MASK (BIT(0) | BIT(11)) #define INTR_RX_MASK BIT(2) #define INTR_TX_MASK BIT(4) #define INTR_CMD_DONE_MASK BIT(12) #define INTR_USE_MASK (INTR_ABORT_MASK | \ INTR_RX_MASK | \ INTR_TX_MASK | \ INTR_CMD_DONE_MASK) #define INTR_ALL_MASK genmask(31, 0) #define I2C_DEFAULT_FREQUENCY 100000 #define I2C_TXF_DEPTH 64 #define I2C_RXF_DEPTH 64 #define I2C_TXF_WATER 32 #define I2C_RXF_WATER 32 #define I2C_WAIT_TIMEOUT 0x400 #define I2C_IRQ_TIMEOUT (msecs_to_jiffies(1000)) #define khz(clk) ((clk) * 1000) #define mhz(clk) ((clk) * 1000000) #define MAX_SPEED khz(400) unsigned int g_i2c_speed = I2C_DEFAULT_FREQUENCY; int g_i2c_num = -1; struct gk_i2c_msg { __u16 chip; /* slave address */ __u16 addr; /* reg address */ __u16 alen; /* reg width,1 or 2 */ __u16 flags; __u16 len; /* msg length,1 or 2 */ __u8 *buf; /* pointer to msg data */ #define I2C_M_RD 0x0001 /* read data, from slave to master */ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ #define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */ }; struct gk_i2c_dev { struct device *dev; void *base; unsigned int clk; unsigned int freq; struct gk_i2c_msg *msg; unsigned int msg_num; unsigned int msg_idx; unsigned int msg_buf_ptr; int status; }; struct gk_i2c_dev i2c_dev; static inline void gk_i2c_disable(struct gk_i2c_dev *i2c); static inline void gk_i2c_cfg_irq(struct gk_i2c_dev *i2c, unsigned int flag); static inline unsigned int gk_i2c_clr_irq(struct gk_i2c_dev *i2c); static inline void gk_i2c_enable(struct gk_i2c_dev *i2c); #define CHECK_SDA_IN_SHIFT 16 #define GPIO_MODE_SHIFT 8 #define FORCE_SCL_OEN_SHIFT 4 #define FORCE_SDA_OEN_SHIFT 0 static void gk_i2c_rescue(struct gk_i2c_dev *i2c) { unsigned int val; unsigned int time_cnt; int index; gk_i2c_disable(i2c); gk_i2c_cfg_irq(i2c, 0); gk_i2c_clr_irq(i2c); val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); writel(val, i2c->base + VENDOR_I2C_CTRL2); time_cnt = 0; do { for (index = 0; index < 9; index++) { /* 9: Cycle */ val = (0x1 << GPIO_MODE_SHIFT) | 0x1; writel(val, i2c->base + VENDOR_I2C_CTRL2); udelay(5); /* delay 5us */ val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); writel(val, i2c->base + VENDOR_I2C_CTRL2); udelay(5); /* delay 5us */ } time_cnt++; if (time_cnt > I2C_WAIT_TIMEOUT) { printf("wait Timeout!\n"); goto disable_rescue; } val = readl(i2c->base + VENDOR_I2C_CTRL2); } while (!(val & (0x1 << CHECK_SDA_IN_SHIFT))); val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); writel(val, i2c->base + VENDOR_I2C_CTRL2); val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT); writel(val, i2c->base + VENDOR_I2C_CTRL2); udelay(10); /* delay 10us */ val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); writel(val, i2c->base + VENDOR_I2C_CTRL2); disable_rescue: val = (0x1 << FORCE_SCL_OEN_SHIFT) | 0x1; writel(val, i2c->base + VENDOR_I2C_CTRL2); } static void gk_i2c_disable(struct gk_i2c_dev *i2c) { unsigned int val; val = readl(i2c->base + VENDOR_I2C_GLB); val &= ~GLB_EN_MASK; writel(val, i2c->base + VENDOR_I2C_GLB); } static void gk_i2c_enable(struct gk_i2c_dev *i2c) { unsigned int val; val = readl(i2c->base + VENDOR_I2C_GLB); val |= GLB_EN_MASK; writel(val, i2c->base + VENDOR_I2C_GLB); } static inline void gk_i2c_cfg_irq(struct gk_i2c_dev *i2c, unsigned int flag) { writel(flag, i2c->base + VENDOR_I2C_INTR_EN); } static void gk_i2c_disable_irq(struct gk_i2c_dev *i2c, unsigned int flag) { unsigned int val; val = readl(i2c->base + VENDOR_I2C_INTR_EN); val &= ~flag; writel(val, i2c->base + VENDOR_I2C_INTR_EN); } static unsigned int gk_i2c_clr_irq(struct gk_i2c_dev *i2c) { unsigned int val; val = readl(i2c->base + VENDOR_I2C_INTR_STAT); writel(INTR_ALL_MASK, i2c->base + VENDOR_I2C_INTR_RAW); return val; } static inline void gk_i2c_cmdreg_set(struct gk_i2c_dev *i2c, unsigned int cmd, unsigned int *offset) { /* the I2C_TIMING_CMD reg offset is (*offset * 4) */ writel(cmd, i2c->base + VENDOR_I2C_CMD_BASE + *offset * 4); (*offset)++; } /* * config i2c slave addr */ static void gk_i2c_set_addr(struct gk_i2c_dev *i2c) { struct gk_i2c_msg *msg = i2c->msg; u16 addr; if (msg->flags & I2C_M_TEN) { /* First byte is 11110XX0 where XX is upper 2 bits */ addr = ((msg->addr & 0x300) << 1) | 0xf000; if (msg->flags & I2C_M_RD) addr |= 1 << 8; /* Move Left 8bit */ /* Second byte is the remaining 8 bits */ addr |= msg->addr & 0xff; } else { addr = (msg->addr & 0x7f) << 1; if (msg->flags & I2C_M_RD) addr |= 1; } writel(addr, i2c->base + VENDOR_I2C_DATA1); } /* * Start command sequence */ static void gk_i2c_init_descart_cmd(struct gk_i2c_dev *i2c) { unsigned int val; val = readl(i2c->base + VENDOR_I2C_CTRL1); val |= CTRL1_CMD_START_MASK; writel(val, i2c->base + VENDOR_I2C_CTRL1); } static int gk_i2c_wait_rx_noempty(struct gk_i2c_dev *i2c) { unsigned int time_cnt = 0; unsigned int val; do { val = readl(i2c->base + VENDOR_I2C_STAT); if (val & STAT_RXF_NOE_MASK) return 0; udelay(50); /* delay 50us */ } while (time_cnt++ < I2C_WAIT_TIMEOUT); gk_i2c_rescue(i2c); printf("wait rx no empty timeout, RIS: 0x%x, SR: 0x%x\n", readl(i2c->base + VENDOR_I2C_INTR_RAW), val); return -EIO; } static int gk_i2c_wait_tx_nofull(struct gk_i2c_dev *i2c) { unsigned int time_cnt = 0; unsigned int val; do { val = readl(i2c->base + VENDOR_I2C_STAT); if (val & STAT_TXF_NOF_MASK) return 0; udelay(50); /* delay 50us */ } while (time_cnt++ < I2C_WAIT_TIMEOUT); gk_i2c_rescue(i2c); printf("wait tx no empty timeout, RIS: 0x%x, SR: 0x%x\n", readl(i2c->base + VENDOR_I2C_INTR_RAW), val); return -EIO; } static int gk_i2c_wait_idle(struct gk_i2c_dev *i2c) { unsigned int time_cnt = 0; unsigned int val; do { val = readl(i2c->base + VENDOR_I2C_INTR_RAW); if (val & (INTR_ABORT_MASK)) { printf("wait idle abort!, RIS: 0x%x\n", val); return -EIO; } if (val & INTR_CMD_DONE_MASK) return 0; udelay(50); /* delay 50us */ } while (time_cnt++ < I2C_WAIT_TIMEOUT); gk_i2c_rescue(i2c); printf("wait idle timeout, RIS: 0x%x, SR: 0x%x\n", val, readl(i2c->base + VENDOR_I2C_STAT)); return -EIO; } static void gk_i2c_set_freq(struct gk_i2c_dev *i2c) { unsigned int max_freq, freq; unsigned int clk_rate; unsigned int val; freq = i2c->freq; clk_rate = i2c->clk; max_freq = clk_rate >> 1; if (freq > max_freq) { i2c->freq = max_freq; freq = i2c->freq; } if (!freq) { printf("i2c_set_freq:freq can't be zero!"); return; } if (freq <= 100000) { /* 100000 : freq */ /* 1/2 of the SCL cycle in standard mode. */ val = clk_rate / (freq * 2); writel(val, i2c->base + VENDOR_I2C_SCL_H); writel(val, i2c->base + VENDOR_I2C_SCL_L); } else { /* 36/100 of the SCL cycle in fast mode. */ val = (clk_rate * 36) / (freq * 100); writel(val, i2c->base + VENDOR_I2C_SCL_H); /* 64/100 of the SCL cycle in fast mode. */ val = (clk_rate * 64) / (freq * 100); writel(val, i2c->base + VENDOR_I2C_SCL_L); } val = readl(i2c->base + VENDOR_I2C_GLB); val &= ~GLB_SDA_HOLD_MASK; val |= ((0xa << GLB_SDA_HOLD_SHIFT) & GLB_SDA_HOLD_MASK); writel(val, i2c->base + VENDOR_I2C_GLB); } /* * set i2c controller TX and RX FIFO water */ static inline void gk_i2c_set_water(struct gk_i2c_dev *i2c) { writel(I2C_TXF_WATER, i2c->base + VENDOR_I2C_TX_WATER); writel(I2C_RXF_WATER, i2c->base + VENDOR_I2C_RX_WATER); } /* * initialise the controller, set i2c bus interface freq */ static void gk_i2c_hw_init(struct gk_i2c_dev *i2c) { gk_i2c_disable(i2c); gk_i2c_disable_irq(i2c, INTR_ALL_MASK); gk_i2c_set_freq(i2c); gk_i2c_set_water(i2c); } /* * gk_i2c_cfg_cmd - config i2c controller command sequence * * After all the timing command is configured, * and then start the command, you can i2c communication, * and then only need to read and write i2c fifo. */ static void gk_i2c_cfg_cmd(struct gk_i2c_dev *i2c) { struct gk_i2c_msg *msg = i2c->msg; unsigned int offset = 0; if (i2c->msg_idx == 0) gk_i2c_cmdreg_set(i2c, CMD_TX_S, &offset); else gk_i2c_cmdreg_set(i2c, CMD_TX_RS, &offset); if (msg->flags & I2C_M_TEN) { if (i2c->msg_idx == 0) { gk_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset); gk_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset); } else { gk_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset); } } else { gk_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset); } if (msg->flags & I2C_M_IGNORE_NAK) gk_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset); else gk_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset); if (msg->flags & I2C_M_RD) { if (msg->len >= 2) { /* 2:len */ writel(offset, i2c->base + VENDOR_I2C_DST1); writel(msg->len - 2, i2c->base + VENDOR_I2C_LOOP1); /* 2: len */ gk_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset); gk_i2c_cmdreg_set(i2c, CMD_TX_ACK, &offset); gk_i2c_cmdreg_set(i2c, CMD_JMP1, &offset); } gk_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset); gk_i2c_cmdreg_set(i2c, CMD_TX_NACK, &offset); } else { writel(offset, i2c->base + VENDOR_I2C_DST1); writel(msg->len - 1, i2c->base + VENDOR_I2C_LOOP1); gk_i2c_cmdreg_set(i2c, CMD_UP_TXF, &offset); gk_i2c_cmdreg_set(i2c, CMD_TX_FIFO, &offset); if (msg->flags & I2C_M_IGNORE_NAK) gk_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset); else gk_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset); gk_i2c_cmdreg_set(i2c, CMD_JMP1, &offset); } if ((i2c->msg_idx == (i2c->msg_num - 1)) || (msg->flags & I2C_M_STOP)) gk_i2c_cmdreg_set(i2c, CMD_TX_P, &offset); gk_i2c_cmdreg_set(i2c, CMD_EXIT, &offset); } static int gk_i2c_polling_xfer_one_msg(struct gk_i2c_dev *i2c) { int status; unsigned int val; struct gk_i2c_msg *msg = i2c->msg; gk_i2c_enable(i2c); gk_i2c_clr_irq(i2c); gk_i2c_set_addr(i2c); gk_i2c_cfg_cmd(i2c); gk_i2c_init_descart_cmd(i2c); i2c->msg_buf_ptr = 0; if (msg->flags & I2C_M_RD) { while (i2c->msg_buf_ptr < msg->len) { status = gk_i2c_wait_rx_noempty(i2c); if (status) goto end; val = readl(i2c->base + VENDOR_I2C_RXF); msg->buf[i2c->msg_buf_ptr] = val; i2c->msg_buf_ptr++; } } else { while (i2c->msg_buf_ptr < msg->len) { status = gk_i2c_wait_tx_nofull(i2c); if (status) goto end; val = msg->buf[i2c->msg_buf_ptr]; writel(val, i2c->base + VENDOR_I2C_TXF); i2c->msg_buf_ptr++; } } status = gk_i2c_wait_idle(i2c); end: gk_i2c_disable(i2c); return status; } /* * Master transfer function */ static int gk_i2c_xfer(struct gk_i2c_msg *msgs, int num) { struct gk_i2c_dev *i2c = &i2c_dev; int status = -EINVAL; if (!msgs || (num <= 0)) { printf("msgs == NULL || num <= 0, Invalid argument!\n"); return -EINVAL; } i2c->msg = msgs; i2c->msg_num = num; i2c->msg_idx = 0; while (i2c->msg_idx < i2c->msg_num) { status = gk_i2c_polling_xfer_one_msg(i2c); if (status) break; i2c->msg++; i2c->msg_idx++; } if (!status || i2c->msg_idx > 0) status = i2c->msg_idx; return status; } void i2c_init(int speed, int i2c_num) { if (i2c_num < 0 || i2c_num >= I2C_MAX_NUM) { printf("Cannot found I2C[%d]!\n", i2c_num); return; } if (gk_i2c_init_desc[i2c_num].flag == I2C_INIT_UNDO) { struct gk_i2c_dev *i2c = &i2c_dev; i2c->base = (void *)(gk_i2c_init_desc[i2c_num].ctrl_base); i2c->clk = I2C_BUS_CLOCK; if (speed <= 0 || speed > MAX_SPEED) { printf("Error speed out of range:[0, %d]!\n", MAX_SPEED); } else { i2c->freq = speed; g_i2c_speed = i2c->freq; } gk_i2c_hw_init(i2c); gk_i2c_init_desc[i2c_num].flag = I2C_INIT_DONE; g_i2c_num = i2c_num; printf("I2C[%d] init OK!\n", i2c_num); } else { printf("I2C[%d] had init!\n", i2c_num); return; } } int i2c_probe(unsigned char i2c_num) { printf("init i2c [%d],speed:[%u]\n", i2c_num, g_i2c_speed); i2c_init(g_i2c_speed, i2c_num); return 0; } unsigned int i2c_set_bus_speed(unsigned int speed) { if (g_i2c_num < 0) { printf("please i2c probe [num] first!"); return 1; } if (g_i2c_speed != speed) { g_i2c_speed = speed; gk_i2c_init_desc[g_i2c_num].flag = I2C_INIT_UNDO; printf("Set the i2c speed to %u\n", g_i2c_speed); i2c_init(g_i2c_speed, g_i2c_num); } else { printf("The i2c speed has not changed!speed:%u\n", g_i2c_speed); } return 0; } unsigned int i2c_get_bus_speed(void) { return g_i2c_speed; } unsigned int i2c_set_bus_num(int bus_no) { struct gk_i2c_dev *i2c = &i2c_dev; if (bus_no < 0 || bus_no >= I2C_MAX_NUM) { printf("Error! out of range:[0, %d]!\n", I2C_MAX_NUM); return 0; } if (gk_i2c_init_desc[bus_no].flag == I2C_INIT_UNDO) { i2c_init(g_i2c_speed, bus_no); } else { g_i2c_num = bus_no; i2c->base = (void *)(gk_i2c_init_desc[g_i2c_num].ctrl_base); } return 0; } unsigned int i2c_get_bus_num(void) { if (g_i2c_num < 0) printf("Please set the I2C device number!\n"); return g_i2c_num; } int i2c_read(unsigned char chip, uint addr, int alen, unsigned char *buffer, int len) { struct gk_i2c_dev; struct gk_i2c_msg msg[2]; /* 2 bit array */ int num = (__u32)2; int len_idx = 1; unsigned int cur_addr; int ret; unsigned char buf[4]; /* 4 bit array */ memset(buf, 0x0, 4); /* memset the ength is 4 array. */ msg[0].addr = (chip >> 1); msg[0].len = alen; msg[0].buf = buf; msg[0].flags = 0; msg[1].addr = (chip >> 1); msg[1].len = len; msg[1].buf = buf; msg[1].flags = 0; msg[1].flags |= I2C_M_RD; for (cur_addr = addr; len_idx <= len; cur_addr += 1) { if (alen == 2) { /* 2:len */ buf[0] = (cur_addr >> 8) & 0xff; /* Move Right 8bit */ buf[1] = cur_addr & 0xff; } else { buf[0] = cur_addr & 0xff; } ret = gk_i2c_xfer(msg, num); if (ret != 2) { /* 2: Return Value */ printf("i2c read: failed %d\n", ret); return 0; } if (len == 2) /* 2:len */ *buffer = buf[0] | (buf[1] << 8); /* Move Left 8bit */ else *buffer = buf[0]; printf("0x%x:0x%x\n", cur_addr, buf[0]); len_idx++; } return 0; } int i2c_write(unsigned char chip, uint addr, int alen, const unsigned char *buffer, int len) { struct gk_i2c_msg msg = {0}; unsigned char buf[4]; /* 4 bit array */ int index = 0; int ret; msg.addr = (chip >> 1); msg.len = alen + len; msg.buf = buf; msg.flags = 0; if (alen == 2) { /* 2:len */ buf[index] = (addr >> 8) & 0xff; /* Move Right 8bit */ index++; buf[index] = addr & 0xff; index++; } else { buf[index] = addr & 0xff; index++; } if (len == 2) { /* 2:len */ buf[index] = *buffer & 0xff; index++; buf[index] = (*buffer >> 8) & 0xff; /* Move Right 8bit */ index++; } else { buf[index] = *buffer & 0xff; index++; } ret = gk_i2c_xfer(&msg, 1); if (ret != 1) { printf("I2c write: failed %d\n", ret); return 1; } return 0; }