📄 i2c-samsung.c
字号:
/* Send byte address: LSB */
IICBUF = iic_txmit.BYTE_ADDR_LSB;
iic_txmit.FLAG |= (U32)iic_byte_addr_lsb;
}
else if(iic_txmit.BuffByteCnt < iic_txmit.WriteDataSize) {
IICBUF = iic_txmit.PAGE_BUFFER[iic_txmit.BuffByteCnt++];
}
else {
/* STOP IIC Controller */
IICCON = STOP;
/* byte data or page data transmit done */
iic_txmit.FLAG |= (U32)iic_page_tx_done;
}
}
else{
if(!(iic_recv.FLAG & (U32)iic_byte_addr_msb)) {
//else if(!(iic_recv.FLAG & (U32)iic_byte_addr_msb)) {
/* Send byte address: MSB */
IICBUF = iic_recv.BYTE_ADDR_MSB;
iic_recv.FLAG |= (U32)iic_byte_addr_msb; /* send msb byte addr */
}
else if(!(iic_recv.FLAG & (U32)iic_byte_addr_lsb)) {
/* Send byte address: LSB */
IICBUF = iic_recv.BYTE_ADDR_LSB;
iic_recv.FLAG |= (U32)iic_byte_addr_lsb; /* send lsb byte addr */
}
else if(!(iic_recv.FLAG & (U32)iic_repeat_start)) {
/* Repeat Start */
IICCON = RESTART;
IICCON = START|ACK|IEN;
IICBUF = iic_recv.SLAVE_ADDR|S_READ;
iic_recv.FLAG |= (U32)iic_repeat_start;
}
else if(!(iic_recv.FLAG & (U32)iic_multi_recv)) {
/* Receive multiple data */
IICCON = ACK|IEN;
iic_recv.FLAG |= (U32)iic_multi_recv;
}
else if(iic_recv.ByteReadCnt < iic_recv.ReadDataSize) {
*(iic_recv.RCV_BUFFER)++ = IICBUF;
iic_recv.ByteReadCnt++;
}
else if(!(iic_recv.FLAG & (U32)iic_no_more_recv)) {
/* Now,no more received data is required from slave */
IICCON = NOACK|IEN;
iic_recv.FLAG |= (U32)iic_no_more_recv;
}
else { /* Receive last data and STOP */
*(iic_recv.RCV_BUFFER)++ = IICBUF;
/* STOP IIC Controller */
IICCON = STOP;
/* byte data receive done */
iic_recv.FLAG |= (U32)iic_byte_rx_done;
}
}
spin_unlock(&i2c_priv.lock);
}
#ifdef MODULE
/*===============================================*/
/* install module */
/*===============================================*/
int init_module(void)
{
return i2c_samsung_init();
}
/*================================================*/
/* uninstall module */
/*================================================*/
void cleanup_module( void )
{
free_irq(INT_IIC, NULL);
devfs_unregister_chrdev( I2C_MAJOR, DEVICE_NAME );
devfs_unregister( dev_handle );
DBG( "s34510: unload i2c device ......\n");
}
#endif
int __init i2c_samsung_init( void )
{
int result;
DBG( "s34510: install hardware I2C device ......\n" );
disable_irq(INT_IIC);
// register i2c isr
if(request_irq(INT_IIC, &s3c4510_i2c, SA_INTERRUPT, "i2c isr", NULL)
) {
printk(KERN_ERR DEVICE_NAME " s34510: can't get irq %d\n", INT_IIC );
return -EAGAIN;
}
else DBG(KERN_ERR DEVICE_NAME " s34510: get i2c irq %d\n", INT_IIC );
result = devfs_register_chrdev(I2C_MAJOR, DEVICE_NAME, &i2c_ops);
if( result < 0 ){
printk (KERN_ERR DEVICE_NAME " s34510: init_module failed with %d\n", result);
return result;
}
printk (KERN_INFO "Samsung S3C4510 I2c hardware driver version 0.3 with mutex (2003.11.16 ) <honeyandy@thunis.com>\n");
// dev_handle = devfs_register( NULL, DEVICE_NAME, DEVFS_FL_DEFAULT,
// I2C_MAJOR, 0, S_IFCHR, &i2c_ops, NULL);
// if( i2c_major == 0)
// i2c_major = result;
iic_priv.i2c_speed = CFG_I2C_SPEED;
iic_priv.i2c_slave = CFG_I2C_SLAVE;
iic_priv.i2c_addrlen = IICADDR2;
iic_priv.i2c_operate = IICREAD;
iic_priv.i2c_pagesize = 0;
i2c_init( iic_priv.i2c_speed);
DBG( "OK\n" );
spin_lock_init(&i2c_priv.lock);
sema_init(&i2c_samsung_sem, 1);
return 0;
}
/*================================================================*/
/* SETUP IIC PRESCALER VALUE FROM SERIAL CLOCK FREQUENCY */
/*================================================================*/
static int SetSpeed(int sclk)
{
volatile U32 value ;
DBG("s34510: set i2c IICPS slck %d Hz\n",(U32)sclk);
value = ( U32 ) (fMCLK_MHz)/sclk; /** fMCLK in MHz, fMCLK_MHz in Hz, this is uClinux defined */
value = value-3;
value = value/16;
value = value - 1; //support upto 100KHz
DBG("s34510: set i2c IICPS want set %08x\n",(U32)value );
IICPS = value&0xFFFF; //LSB 16bit valuable
DBG("s34510: set i2c IICPS %08x\n",(U32)IICPS);
}
/*=====================================================================*/
/* `speed' and `slaveaddr' not implemented */
/*=====================================================================*/
static void i2c_init (int speed)
{
IICCON = IICRESET;
SetSpeed(speed);
}
/* --------------------------------------------------------------
* bellow is I2C operation functions body
*
* --------------------------------------------------------------
*
*---------------------------------------------------------------
* Definitions
*/
/*-----------------------------------------------------------------------
*
* W/RAddr: Array of address bytes; for instance, to read from
* EEPROM with 8 bit page addresses you have to write 2
* address bytes: the block number, and the block
* offset.
* AddrLen: Number of address bytes in "addr"
* data: where to store the read data in
* SizeOfData: number of bytes to read
* Warning: it is expected that the device is really
* capable of reading `len' sequential bytes; no
* checking is done here
*/
static void i2c_chain_write (U32 WriteAddr, U8 *data, int SizeOfData )
{
int page,j;
int no_of_page; /* Number of page */
int remain_byte;
U32 PageAccessAddr;
PageAccessAddr = WriteAddr;
iic_txmit.SLAVE_ADDR = iic_priv.i2c_slave;
no_of_page = (int)(SizeOfData/(U32)iic_priv.i2c_pagesize);
remain_byte = (int)(SizeOfData%(U32)iic_priv.i2c_pagesize);
for(page=0; page <= no_of_page;page++)
{
if(SizeOfData < iic_priv.i2c_pagesize) {
for(j=0; j < SizeOfData; j++)
iic_txmit.PAGE_BUFFER[j] = *data++;
iic_txmit.WriteDataSize = SizeOfData;
}
else {
if(page == no_of_page) {
for(j=0; j < remain_byte; j++)
iic_txmit.PAGE_BUFFER[j] = *data++;
iic_txmit.WriteDataSize = remain_byte;
}
else {
for(j=0; j < iic_priv.i2c_pagesize; j++)
iic_txmit.PAGE_BUFFER[j] = *data++;
iic_txmit.WriteDataSize = iic_priv.i2c_pagesize;
}
}
i2c_init( iic_priv.i2c_speed);
iic_priv.i2c_operate = IICWRITE;
enable_irq(INT_IIC) ;
iic_txmit.FLAG = 0x0;
if(iic_priv.i2c_addrlen == IICADDR1)
iic_txmit.FLAG |= (U32)iic_byte_addr_msb;
iic_txmit.BuffByteCnt = 0x0;
iic_txmit.BYTE_ADDR_MSB = (U8)((PageAccessAddr>>8) & 0xff);
iic_txmit.BYTE_ADDR_LSB = (U8)(PageAccessAddr & 0xff);
/* Step 1: Setup IICON register for transmit start */
while(IICCON & BUSY); /* Wait! the iic bus is busy */
IICCON = START|ACK|IEN; /* Now, Start to transmit */
/* Send Slave Address and Write command */
IICBUF = iic_txmit.SLAVE_ADDR|S_WRITE;
while(!(iic_txmit.FLAG & iic_page_tx_done));
PageAccessAddr += iic_priv.i2c_pagesize;
udelay(7000); /* for 5ms write cycle */
}
disable_irq(INT_IIC) ;
}
static void i2c_chain_read (U32 ReadAddr , U8 *data , int SizeOfData)
{
i2c_init( iic_priv.i2c_speed);
iic_priv.i2c_operate = IICREAD;
enable_irq(INT_IIC) ;
/*Memory alloc for receive data */
iic_recv.RCV_BUFFER = data;
iic_recv.FLAG = 0x0;
if(iic_priv.i2c_addrlen == IICADDR1)
iic_txmit.FLAG |= (U32)iic_byte_addr_msb;
iic_recv.ByteReadCnt = 0x0;
iic_recv.ReadDataSize = SizeOfData;
iic_recv.SLAVE_ADDR = iic_priv.i2c_slave;
iic_recv.BYTE_ADDR_MSB = (U8)((ReadAddr>>8) & 0xff);
iic_recv.BYTE_ADDR_LSB = (U8)(ReadAddr & 0xff);
/* Step 1: Setup IICON register for receive start */
while(IICCON & BUSY); /* Wait! the iic bus is busy */
IICCON = START|ACK|IEN;
/* Send Slave Address and Write command */
IICBUF = iic_recv.SLAVE_ADDR|S_WRITE;
while(!(iic_recv.FLAG & iic_byte_rx_done));
disable_irq(INT_IIC) ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -