| /* |
| * Copyright (C) 2018 Synaptics Incorporated. All rights reserved. |
| * |
| * 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 |
| * published by the Free Software Foundation. |
| * |
| * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND |
| * SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, |
| * INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY |
| * INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR |
| * CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE |
| * OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND |
| * BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF |
| * COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT |
| * DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY |
| * TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS. |
| */ |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////I2C API/////////////////////////////////////////////// |
| ////////////////////////////////////////////////////////////////////////////////////////////// |
| #include "util.h" |
| #include "i2c_driver.h" |
| #include "apbRegBase.h" |
| |
| // number of I2C masters in system |
| #define I2C_MASTER_NUM 3 |
| |
| // I2C master system clock |
| // minimum sysmte clock are required |
| // Standard Mode: 2 MHz |
| // Fast Mode: 10 MHz |
| // High-Speed Mode: 100 MHz |
| //#ifdef BG2_DV_BOARD |
| |
| #define I2C_SDA_HOLD_TIME 2 // Range: [2, SCL_LCNT -2] |
| |
| // I2C master TX/RX fifo size |
| #define I2C_RX_FIFO_SIZE 64 |
| #define I2C_TX_FIFO_SIZE 64 |
| |
| // register definitions of I2C master |
| #define I2C_REG_CON 0x00 |
| #define I2C_REG_TAR 0x04 |
| #define I2C_REG_SAR 0x08 |
| #define I2C_REG_HS_MADDR 0x0C |
| #define I2C_REG_DATA_CMD 0x10 |
| #define I2C_REG_SS_SCL_HCNT 0x14 |
| #define I2C_REG_SS_SCL_LCNT 0x18 |
| #define I2C_REG_FS_SCL_HCNT 0x1C |
| #define I2C_REG_FS_SCL_LCNT 0x20 |
| #define I2C_REG_HS_SCL_HCNT 0x24 |
| #define I2C_REG_HS_SCL_LCNT 0x28 |
| #define I2C_REG_INTR_STAT 0x2C |
| #define I2C_REG_INTR_MASK 0x30 |
| #define I2C_REG_RINTR_STAT 0x34 |
| #define I2C_REG_RX_TL 0x38 |
| #define I2C_REG_TX_TL 0x3C |
| #define I2C_REG_CLR_INTR 0x40 |
| #define I2C_REG_CLR_RX_UNDER 0x44 |
| #define I2C_REG_CLR_RX_OVER 0x48 |
| #define I2C_REG_CLR_TX_OVER 0x4C |
| #define I2C_REG_CLR_RD_REQ 0x50 |
| #define I2C_REG_CLR_TX_ABRT 0x54 |
| #define I2C_REG_CLR_RX_DONE 0x58 |
| #define I2C_REG_CLR_ACTIVITY 0x5C |
| #define I2C_REG_CLR_STOP_DET 0x60 |
| #define I2C_REG_CLR_START_DET 0x64 |
| #define I2C_REG_CLR_GEN_CALL 0x68 |
| #define I2C_REG_ENABLE 0x6C |
| #define I2C_REG_STATUS 0x70 |
| #define I2C_REG_TXFLR 0x74 |
| #define I2C_REG_RXFLR 0x78 |
| #define I2C_REG_SDA_HOLD 0x7C //for SDA_HOLD |
| #define I2C_REG_TX_ABRT_STAT 0x80 |
| #define I2C_REG_DMA_CR 0x88 |
| #define I2C_REG_DMA_TDLR 0x8C |
| #define I2C_REG_DMA_RDLR 0x90 |
| #define I2C_REG_SDA_SETUP 0x94 //for SDA_SETUP |
| #define I2C_REG_COMP_PARAM 0xF4 |
| #define I2C_REG_COMP_VERSION 0xF8 |
| #define I2C_REG_COMP_TYPE 0xFC // reset value: 0x44570140 |
| |
| // Macros of I2C_REG_CON bit offset |
| #define CON_SLAVE_DISABLE 6 |
| #define CON_RESTART_EN 5 |
| #define CON_10BITADDR 4 |
| #define CON_SPEED 1 |
| #define CON_MASTER_ENABLE 0 |
| |
| // Macros of I2C_REG_TAR bit offset |
| #define TAR_10BITADDR 12 |
| #define TAR_SPECIAL 11 |
| #define TAR_GC_OR_START 10 |
| |
| // Macros of I2C_REG_INTR_* bit definition |
| #define INTR_GEN_CALL 0x800 |
| #define INTR_START_DET 0x400 |
| #define INTR_STOP_DET 0x200 |
| #define INTR_ACTIVITY 0x100 |
| #define INTR_RX_DONE 0x080 |
| #define INTR_TX_ABRT 0x040 |
| #define INTR_RD_REQ 0x020 |
| #define INTR_TX_EMPTY 0x010 |
| #define INTR_TX_OVER 0x008 |
| #define INTR_RX_FULL 0x004 |
| #define INTR_RX_OVER 0x002 |
| #define INTR_RX_UNDER 0x001 |
| |
| // Macros of I2C_REG_ENABLE bit definition |
| #define EN_ENABLE 0x01 |
| |
| // Macros of read-command |
| #define READ_CMD 0x100 |
| |
| // Macros to interrupt mask flag |
| #define MASK 0 |
| #define UNMASK 1 |
| |
| // Macros of read/write I2C master registers |
| //#define I2C_RegRead(a, pv) (*(volatile int *)(base_addr+(a))) |
| //#define I2C_RegWrite(a, v) *(volatile int *)(base_addr+(a)) = (v) |
| #define I2C_REG_READ(base, reg) (*(volatile unsigned int*)(unsigned long)((base)+(reg))) |
| #define I2C_REG_WRITE(base, reg, v) (*(volatile unsigned int*)(unsigned long)((base)+(reg)) = (v)) |
| #define REG_READ(addr) (*(volatile unsigned int*)(addr)) |
| #define REG_WRITE(addr, v) *(volatile unsigned int*)(addr) = (v) |
| |
| #define ARRAY_NUM(a) (sizeof(a)/sizeof(a[0])) |
| #define DIAG_ASSERT(cond) {if (!(cond)) { \ |
| dbg_printf(PRN_RES, "Assert fail, condition:%s, file:%s, line:%d\n", #cond, __FILE__, __LINE__); \ |
| while(1); \ |
| }} |
| // apb core clock for soc timer, spi, i2c, ... |
| #define CONFIG_CLOCK_KHZ (200*1000) |
| #define SOC_I2C_CLOCK CONFIG_CLOCK_KHZ // KHz |
| #define I2C_MAX_BUF_SIZE 128 |
| #define I2C_FIFO_DEPTH 256 |
| #define I2C_FIFO_DEPTH_TH (I2C_FIFO_DEPTH/2) |
| |
| |
| // I2C master's transfer buffer, shared by TX and RX |
| static int i2c_master_buffer[I2C_MASTER_NUM][256+4]; |
| // number of command which have been written to TX fifo so far, |
| // this will equal bytes_of_write_cmd + bytes_of_read_cmd at the end of transaction |
| static int bytes_written_to_txfifo[I2C_MASTER_NUM]; |
| // number of bytes read out from RX fifo so far, |
| static int bytes_read_from_rxfifo[I2C_MASTER_NUM]; |
| // number of write-command which need to be written to TX fifo |
| static int bytes_of_write_cmd[I2C_MASTER_NUM]; |
| // number of read-command which need to be written to TX fifo |
| static int bytes_of_read_cmd[I2C_MASTER_NUM]; |
| // variable indicating transaction finishing or not |
| static volatile int transaction_done[I2C_MASTER_NUM]; |
| |
| |
| // I2C master's base-address vector |
| static const unsigned int I2C_MASTER_BASEADDR[I2C_MASTER_NUM] = {APB_I2C0_BASE, APB_I2C1_BASE, APB_I2C2_BASE}; |
| |
| //static const unsigned char* wbuf= (unsigned char*)0xF7A47F00; |
| |
| const unsigned int i2c_bases[] = |
| { |
| APB_I2C0_BASE, |
| APB_I2C1_BASE, |
| APB_I2C2_BASE |
| }; |
| |
| static unsigned int i_i2c_get_base_addr(int id) |
| { |
| if (id < 0 || id >= (int)ARRAY_NUM(i2c_bases)) |
| { |
| return 0; |
| } |
| |
| return i2c_bases[id]; |
| } |
| |
| int i2c_master_init(int id, int speed, int b_10bit_addr) |
| { |
| unsigned int base_addr; |
| int base_clock; |
| int high_count; |
| int low_count; |
| int b_use_fast = 0; |
| unsigned int control_value; |
| |
| base_addr = i_i2c_get_base_addr(id); |
| if (base_addr == 0) |
| { |
| return -1; |
| } |
| |
| control_value = (1<<6) | (1<<5) | (1<<0); // slave disabled, re-start en, master enbled |
| |
| I2C_REG_WRITE(base_addr, 0x6C, 0); // disable |
| I2C_REG_WRITE(base_addr, 0x30, 0); // interrupt mask all |
| |
| // try to find the max fifo depth and set threshold to half |
| I2C_REG_WRITE(base_addr, 0x38, I2C_FIFO_DEPTH-1); // rx fifo threshold |
| I2C_REG_WRITE(base_addr, 0x3C, I2C_FIFO_DEPTH-1); // tx fifo threshold |
| //DIAG_ASSERT(I2C_REG_READ(base_addr, 0x38) == I2C_FIFO_DEPTH-1); |
| //DIAG_ASSERT(I2C_REG_READ(base_addr, 0x3C) == I2C_FIFO_DEPTH-1); |
| |
| I2C_REG_WRITE(base_addr, 0x3C, I2C_FIFO_DEPTH_TH-1); // tx fifo threshold |
| |
| base_clock = SOC_I2C_CLOCK; |
| |
| if (speed > 100) |
| { |
| b_use_fast = 1; |
| } |
| |
| if (b_use_fast) |
| { |
| // default clock |
| high_count = base_clock/speed*40/100; // high:40% |
| low_count = base_clock/speed - high_count; |
| |
| I2C_REG_WRITE(base_addr, 0x1C, high_count); // IC_FS_SCL_HCNT |
| I2C_REG_WRITE(base_addr, 0x20, low_count); // IC_FS_SCL_LCNT |
| |
| control_value |= 2<<1; |
| |
| I2C_REG_WRITE(base_addr, 0x7C, 30); // SDA hold time BG4CDp hold time ne |
| } |
| else |
| { |
| high_count = base_clock/speed*40/100; // high:40% |
| low_count = base_clock/speed - high_count; |
| |
| I2C_REG_WRITE(base_addr, 0x14, high_count); // IC_SS_SCL_HCNT |
| I2C_REG_WRITE(base_addr, 0x18, low_count); // IC_SS_SCL_LCNT |
| |
| control_value |= 1<<1; |
| |
| I2C_REG_WRITE(base_addr, 0x7C, 30); // SDA hold time BG4CDp hold time ne |
| } |
| |
| if (b_10bit_addr) |
| { |
| control_value |= (1<<4); // enable 10 bit mode for master |
| } |
| |
| // enable master mode |
| I2C_REG_WRITE(base_addr, 0x00, control_value); |
| |
| //dbg_printf(PRN_INFO, "I2C_%d, HCNT:%d, LCNT:%d, control:0x%02x\n", id, high_count, low_count, control_value); |
| return 0; |
| } |
| |
| /***************************************************** |
| * set I2C master TX FIFO underflow threshold |
| * thrld: 0 - 255 |
| * |
| *****************************************************/ |
| #if 0 |
| static void set_txfifo_threshold(int master_id, int thrld) |
| { |
| unsigned int base_addr; |
| |
| if (thrld<0 || thrld>255) return; |
| |
| base_addr = i_i2c_get_base_addr(master_id); |
| I2C_REG_WRITE(base_addr, I2C_REG_TX_TL, thrld); |
| return; |
| } |
| #endif |
| /***************************************************** |
| * set I2C master RX FIFO overflow threshold |
| * thrld: 1 - 256 |
| * |
| *****************************************************/ |
| #if 0 |
| static void set_rxfifo_threshold(int master_id, int thrld) |
| { |
| unsigned int base_addr; |
| |
| if (thrld<1 || thrld>256) return; |
| |
| base_addr = i_i2c_get_base_addr(master_id); |
| I2C_REG_WRITE(base_addr, I2C_REG_RX_TL, thrld-1); |
| |
| return; |
| } |
| #endif |
| /*********************************************************************** |
| * FUNCTION: read bytes from slave device |
| * PARAMS: master_id - id of I2C master to operate |
| * slave_addr - address of slave device |
| * pwbuf - pointer of write buffer |
| * wnum - number of bytes to write |
| * RETURN: I2C_OK - succeed |
| * I2C_ERROR - I2C module is enabled, or read failed |
| * NOTE: maximum write bytes is 260, maximum read bytes is 256 in a single |
| * transaction |
| ***********************************************************************/ |
| int diag_i2c_master_write_bytes(int master_id, int slave_addr, char *pwbuf, int wnum) |
| { |
| unsigned int base_addr; |
| int i, j; |
| int timeout=1000000; |
| |
| if ((master_id < 0) || (master_id > I2C_MASTER_NUM-1)) |
| { |
| return -1; |
| } |
| |
| if (wnum>260) |
| { |
| return -1; |
| } |
| |
| base_addr = i_i2c_get_base_addr(master_id); |
| |
| // check whether I2C module is disabled |
| i = I2C_REG_READ(base_addr, I2C_REG_ENABLE); |
| if (i & EN_ENABLE) |
| { |
| return -1; |
| } |
| |
| i = I2C_REG_READ(base_addr, I2C_REG_CON); |
| |
| { // 7-bit slave address |
| // set 7-bit target address, normal transfer mode |
| i = I2C_REG_READ(base_addr, I2C_REG_TAR); |
| i &= ~((1<<TAR_10BITADDR) | (1<<TAR_SPECIAL) | 0x3ff); |
| i |= slave_addr; |
| I2C_REG_WRITE(base_addr, I2C_REG_TAR, i); |
| |
| // for SM_TW1, the dynamic address change is 0, |
| // so we have to set 7-bit address type here |
| i = I2C_REG_READ(base_addr, I2C_REG_CON); |
| i &= ~(1<<CON_10BITADDR); |
| I2C_REG_WRITE(base_addr, I2C_REG_CON, i); |
| } |
| |
| // initiate transaction status flag |
| transaction_done[master_id] = 0; |
| |
| // set TX fifo threshold to make sure TXE interrupt will be triggered |
| // as soon as we unmask the TXE interupt, we will start transaction by writing CMD_DATA register then. |
| //set_txfifo_threshold(master_id, I2C_TX_FIFO_SIZE/2); |
| |
| // clear TX_ABRT_SOURCE by reading |
| i = I2C_REG_READ(base_addr, I2C_REG_CLR_INTR); |
| |
| |
| { // write-only transaction |
| // initiate number of write commands which are going to be written to TX fifo |
| bytes_written_to_txfifo[master_id] = 0; |
| bytes_read_from_rxfifo[master_id] = 0; |
| bytes_of_write_cmd[master_id] = wnum; |
| bytes_of_read_cmd[master_id] = 0; |
| |
| // write-command need to be copy to buffer first, |
| for (i=0; i<wnum; i++) |
| i2c_master_buffer[master_id][i] = (int)pwbuf[i]; |
| |
| // enable I2C master |
| I2C_REG_WRITE(base_addr, I2C_REG_ENABLE, EN_ENABLE); |
| |
| // issue write commands to TX fifo |
| for (i=0; i<wnum; i++) |
| { |
| |
| #if 0 //original way to check TX fifo when write |
| if(!(--timeout)) break; |
| j = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| while (!(j&0x02)) /* TX fifo is full */ |
| { |
| if (!(j&0x01)) /* but I2C master is idle */ |
| { |
| // disable I2C master |
| I2C_REG_WRITE(base_addr, I2C_REG_ENABLE, ~EN_ENABLE); |
| /* somehow error happen !!! */ |
| //dbg_printf( "I2C write failed\n"); |
| return -1; |
| } |
| j = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| } |
| #else |
| timeout=10000; |
| j = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| while (!(j&0x02)) /* TX fifo is full, so wait, but if it take too long, timeout*/ |
| { |
| if(!(timeout--)) |
| { |
| // disable I2C master |
| I2C_REG_WRITE(base_addr, I2C_REG_ENABLE, ~EN_ENABLE); |
| /* somehow error happen !!! */ |
| //dbg_printf( "I2C write failed\n"); |
| //REG_WRITE(0xB00000, 0x1); |
| return -1; |
| } |
| j = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| } |
| |
| #endif |
| I2C_REG_WRITE(base_addr, I2C_REG_DATA_CMD, i2c_master_buffer[master_id][i]); |
| } |
| |
| //add some delay, otherwise, the next error condition will get hit on fast cpu |
| //fifo not empty and master is idle |
| //{ |
| // int delay=10000; |
| // while(delay--); |
| //} |
| berlin_delay_us(10000); |
| |
| j = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| while (!(j&0x04)){ /* TX fifo is not empty */ |
| if(!(j&0x01)) /* but I2C master is idle */ |
| { |
| // disable I2C master |
| I2C_REG_WRITE(base_addr, I2C_REG_ENABLE, ~EN_ENABLE); |
| /* somehow error happen !!! */ |
| //dbg_printf( "I2C write failed\n"); |
| //REG_WRITE(0xB00000, j); |
| return -1; |
| } |
| j = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| } |
| |
| do{ |
| i = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| }while (i&0x01); /* wait until transfer finish */ |
| |
| //for write only transaction, need to check TX_ABRT_SOURCE to know if tx failed |
| i = I2C_REG_READ(base_addr, I2C_REG_TX_ABRT_STAT); |
| if(i) |
| { |
| // disable I2C master |
| I2C_REG_WRITE(base_addr, I2C_REG_ENABLE, ~EN_ENABLE); |
| /* somehow error happen !!! */ |
| //dbg_printf( "I2C tx aborted! I2C_REG_TX_ABRT_STAT = 0x%x\n", i); |
| //REG_WRITE(0xB00000, 0x3); |
| return -1; |
| } |
| |
| transaction_done[master_id] = 1; |
| } |
| // if it is a write only transaction, wait until transfer finish |
| do{ |
| i = I2C_REG_READ(base_addr, I2C_REG_STATUS); |
| }while (i&0x01); /* wait until transfer finish */ |
| |
| |
| // disable I2C master |
| I2C_REG_WRITE(base_addr, I2C_REG_ENABLE, ~EN_ENABLE); |
| |
| if(!timeout) |
| { |
| //REG_WRITE(0xB00000, 0x4); |
| return -1; |
| } |
| //REG_WRITE(0xB00000, 0xBEEFBEEF); |
| return 0; |
| } |
| |
| |
| int i2c_vcore(int master_id, int slave_addr, int voltage) |
| { |
| int result=0; |
| char wbuf[2]; |
| |
| // I2C init |
| result = i2c_master_init(master_id, 100, 0); // init I2C master to 100K |
| if (result != 0) |
| { |
| return result; |
| } |
| else |
| { |
| wbuf[0]=0x24; |
| wbuf[1]=2+(voltage-775)/25; |
| //dbg |
| //REG_WRITE(0xA00000,index); |
| result=diag_i2c_master_write_bytes(master_id, slave_addr, wbuf, 2); |
| berlin_delay_us(1000); |
| return result; |
| } |
| } |