SmartAudio/lichee/linux-4.9/drivers/soc/sunxi/pm/standby/standby_twi.c

288 lines
7.4 KiB
C
Executable File
Raw Blame History

/*
*********************************************************************************************************
* LINUX-KERNEL
* AllWinner Linux Platform Develop Kits
* Kernel Module
*
* (c) Copyright 2006-2011, kevin.z China
* All Rights Reserved
*
* File : standby_twi.c
* By : kevin.z
* Version : v1.0
* Date : 2011-5-31 15:22
* Descript:
* Update : date auther ver notes
*********************************************************************************************************
*/
#include "standby_i.h"
#define TWI_CHECK_TIMEOUT (0x2ff)
static __twic_reg_t* TWI_REG_BASE[3] = {
(__twic_reg_t*)IO_ADDRESS(AW_TWI0_BASE),
(__twic_reg_t*)IO_ADDRESS(AW_TWI1_BASE),
(__twic_reg_t*)IO_ADDRESS(AW_TWI2_BASE)
};
static __u32 TwiClkRegBak = 0;
static __u32 TwiCtlRegBak = 0;
static __twic_reg_t *twi_reg = (__twic_reg_t *)(0);
/*
*********************************************************************************************************
* standby_twi_init
*
*Description: init twi transfer.
*
*Arguments :
*
*Return :
*
*********************************************************************************************************
*/
__s32 standby_twi_init(int group)
{
twi_reg = TWI_REG_BASE[group];
TwiClkRegBak = twi_reg->reg_clkr;
TwiCtlRegBak = 0x80&twi_reg->reg_ctl;/* backup INT_EN;no need for BUS_EN(0xc0) */
//twi_reg->reg_clkr = (2<<3)|3; //100k
twi_reg->reg_clkr = (5<<3)|0; //400k, M = 5, N=0;
twi_reg->reg_reset |= 0x1;
while(twi_reg->reg_reset&0x1);
return 0;
}
/*
*********************************************************************************************************
* standby_twi_exit
*
*Description: exit twi transfer.
*
*Arguments :
*
*Return :
*
*********************************************************************************************************
*/
__s32 standby_twi_exit(void)
{
/* softreset twi module */
twi_reg->reg_reset |= 0x1;
/* delay */
//change_runtime_env();
//delay_ms(10);
/* restore clock division */
twi_reg->reg_clkr = TwiClkRegBak;
/* restore INT_EN */
twi_reg->reg_ctl |= TwiCtlRegBak;
return 0;
}
/*
*********************************************************************************************************
* _standby_twi_stop
*
*Description: stop current twi transfer.
*
*Arguments :
*
*Return :
*
*********************************************************************************************************
*/
static int _standby_twi_stop(void)
{
unsigned int nop_read;
unsigned int timeout = TWI_CHECK_TIMEOUT;
twi_reg->reg_ctl = (twi_reg->reg_ctl & 0xc0) | 0x10 | 0x08;/* set stop+clear int flag */
nop_read = twi_reg->reg_ctl;
nop_read = nop_read;
// 1. stop bit is zero.
while((twi_reg->reg_ctl & 0x10)&&(timeout--));
if(timeout == 0)
{
return -1;
}
// 2. twi fsm is idle(0xf8).
timeout = TWI_CHECK_TIMEOUT;
while((0xf8 != twi_reg->reg_status)&&(timeout--));
if(timeout == 0)
{
return -1;
}
// 3. twi scl & sda must high level.
timeout = TWI_CHECK_TIMEOUT;
while((0x3a != twi_reg->reg_lctl)&&(timeout--));
if(timeout == 0)
{
return -1;
}
return 0;
}
/*
*********************************************************************************************************
* twi_byte_rw
*
*Description: twi byte read and write.
*
*Arguments : op operation read or write;
* saddr slave address;
* baddr byte address;
* data pointer to the data to be read or write;
*
*Return : result;
* = EPDK_OK, byte read or write successed;
* = EPDK_FAIL, btye read or write failed!
*********************************************************************************************************
*/
__s32 twi_byte_rw(enum twi_op_type_e op, __u8 saddr, __u8 baddr, __u8 *data)
{
unsigned char state_tmp;
unsigned int timeout;
int ret = -1;
twi_reg->reg_efr = 0;/* <20><>׼<EFBFBD><D7BC>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0 */
state_tmp = twi_reg->reg_status;
if(state_tmp != 0xf8)
{
goto stop_out;
}
/* control registser bitmap
7 6 5 4 3 2 1 0
INT_EN BUS_EN START STOP INT_FLAG ACK NOT NOT
*/
//1.Send Start
twi_reg->reg_ctl |= 0x20;
timeout = TWI_CHECK_TIMEOUT;
while((!(twi_reg->reg_ctl & 0x08))&&(timeout--));
if(timeout == 0)
{
goto stop_out;
}
state_tmp = twi_reg->reg_status;
if(state_tmp != 0x08)
{
goto stop_out;
}
//2.Send Slave Address
twi_reg->reg_data = ((saddr<<1)&0xfe) | 0; /* slave address + write */
twi_reg->reg_ctl &= 0xCF;
timeout = TWI_CHECK_TIMEOUT;
while((!(twi_reg->reg_ctl & 0x08))&&(timeout--));
if(timeout == 0)
{
goto stop_out;
}
state_tmp = twi_reg->reg_status;
if(state_tmp != 0x18)
{
goto stop_out;
}
//3.Send Byte Address
twi_reg->reg_data = baddr;
twi_reg->reg_ctl &= 0xCF;
timeout = TWI_CHECK_TIMEOUT;
while((!(twi_reg->reg_ctl & 0x08))&&(timeout--));
if(timeout == 0)
{
goto stop_out;
}
state_tmp = twi_reg->reg_status;
if(state_tmp != 0x28)
{
goto stop_out;
}
if(op == TWI_OP_WR)
{
//4.Send Data to be write
twi_reg->reg_data = *data;
twi_reg->reg_ctl &= 0xCF;
timeout = TWI_CHECK_TIMEOUT;
while((!(twi_reg->reg_ctl & 0x08))&&(timeout--));
if(timeout == 0)
{
goto stop_out;
}
state_tmp = twi_reg->reg_status;
if(state_tmp != 0x28)
{
goto stop_out;
}
}
else
{
//4. Send restart for read
twi_reg->reg_ctl = (twi_reg->reg_ctl & 0xc0) | 0x20 | 0x08; /* set start+clear int flag */
timeout = TWI_CHECK_TIMEOUT;
while((!(twi_reg->reg_ctl & 0x08))&&(timeout--));
if(timeout == 0)
{
goto stop_out;
}
state_tmp = twi_reg->reg_status;
if(state_tmp != 0x10)
{
goto stop_out;
}
//5.Send Slave Address
twi_reg->reg_data = (saddr<<1) | 1;/* slave address+ read */
twi_reg->reg_ctl &= 0xCF; /* clear int flag then 0x40 come in */
timeout = TWI_CHECK_TIMEOUT;
while((!(twi_reg->reg_ctl & 0x08))&&(timeout--));
if(timeout == 0)
{
goto stop_out;
}
state_tmp = twi_reg->reg_status;
if(state_tmp != 0x40)
{
goto stop_out;
}
//6.Get data
twi_reg->reg_ctl &= 0xCF; /* clear int flag then data come in */
timeout = TWI_CHECK_TIMEOUT;
while((!(twi_reg->reg_ctl & 0x08))&&(timeout--));
if(timeout == 0)
{
goto stop_out;
}
*data = twi_reg->reg_data;
state_tmp = twi_reg->reg_status;
if(state_tmp != 0x58)
{
goto stop_out;
}
}
ret = 0;
stop_out:
//WRITE: step 5; READ: step 7
//Send Stop
_standby_twi_stop();
return ret;
}