blob: e06e78627861b5d15e60014545d5e2d015e6ff48 [file] [log] [blame]
/*
* 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;
}
}