高通LK阶段使用模拟i2c--附i2c子协议smbus-protocol

在调试mipi转换芯片的时候总是需要使用i2c对其进行初始化,kernel阶段好办,一般高通平台提供较为完整的i2c操作方法,只需要配置一下i2c地址就可以建立相应的i2c设备。


但是lk阶段就不尽人意了。比如在此案例中,msm8937平台的lk阶段并没有配置i2c接口,只好使用模拟i2c一劳永逸。遂,写了一个简单的模拟i2c读写接口,代码如下,仅供参考学习。已测试可以使用。另外附录i2c子协议smbus-protocol(kernel/msm-3.18/Documentation/i2c/smbus-protocol)。


#include <platform/gpio.h>
#include <debug.h>
#include <string.h>
#include <smem.h>
#include <err.h>
#include <qtimer.h>//mdelay


#define SDA 6                         //定义SDA所对应的GPIO接口编号  
#define SCL 7                         //定义SCL所对应的GPIO接口编号  
#define OUTP 1                          //表示GPIO接口方向为输出  
#define INP 0                           //表示GPIO接口方向为输入  
//void gpio_tlmm_config(uint32_t gpio, uint8_t func,uint8_t dir, uint8_t pull,uint8_t drvstr, uint32_t enable)
#define  gpio_set_direction(fuck1,fuck2)  gpio_tlmm_config(fuck1, 0, 1, 0, 3, fuck2) //输出
#define  gpio_set_val(fuck1,fuck2) 		  gpio_set_dir(fuck1, 2*fuck2)
/* I2C起始条件 */  
int i2c_start()  
{  
	//初始化GPIO口  
	gpio_set_direction(SDA, OUTP);          //设置SDA方向为输出  
	gpio_set_direction (SCL, OUTP);         //设置SCL方向为输出  
	gpio_set_val(SCL, 1);                //设置SDA为高电平  
	udelay(10);
	gpio_set_val(SDA, 1);                 //设置SCL为高电平  
	udelay(10);                            //延时  
	//起始条件  
	gpio_set_val(SDA, 0);                 //SCL为高电平时,SDA由高变低  
	udelay(10);  
	gpio_set_val(SCL, 0); 
	udelay(10);
	return 0 ;
}  
/* I2C终止条件 */  
void i2c_stop()  
{  
	gpio_set_val(SCL, 0);  
	udelay(10);
	gpio_set_direction(SDA, OUTP);  
	gpio_set_val(SDA, 0);  
	udelay(10);  
	gpio_set_val(SCL, 1);             //SCL高电平时,SDA由低变高  
	udelay(10);
	gpio_set_val(SDA, 1);
	udelay(10);
}  
/*   
I2C读取ACK信号(写数据时使用)  
返回值 :0表示ACK信号有效;非0表示ACK信号无效  
*/  
unsigned char i2c_read_ack()  
{  
	unsigned char r;  
	gpio_set_direction(SDA, INP);           //设置SDA方向为输入  
	gpio_set_val(SCL,1);              // SCL变低
	udelay(10);	
	r = gpio_status(SDA);                //读取ACK信号  
	udelay(10);  
	gpio_set_val(SCL,0);              // SCL变高  
	udelay(10);  
	return r;  
}  
/* I2C发出ACK信号(读数据时使用) */  
int i2c_send_ack()  
{  
	gpio_set_direction(SDA, OUTP);          //设置SDA方向为输出  
	gpio_set_val(SDA, 0);             //发出ACK信号  
	udelay(10);  
	gpio_set_val(SCL,1);              // SCL变高  
	udelay(10);
	gpio_set_val(SCL,0); 
	udelay(10);  
	return 0 ;
} 
int i2c_send_noack()  
{  
	gpio_set_direction(SDA, OUTP);          //设置SDA方向为输出  
	gpio_set_val(SDA, 1);             //发出ACK信号  
	udelay(10);  
	gpio_set_val(SCL,1);              // SCL变高  
	udelay(10);
	gpio_set_val(SCL,0); 
	udelay(10);  
	return 0 ;
}  
/* I2C字节写 */  
void i2c_write_byte(unsigned char b)  
{  
	int i;  
	gpio_set_direction(SDA, OUTP);          //设置SDA方向为输出  
	for (i=7; i>=0; i--) {
	udelay(10);
	gpio_set_val(SDA, !!(b & (1<<i)));
	udelay(10);
	gpio_set_val(SCL, 1);             // SCL变低  
	udelay(10);  
	gpio_set_val(SCL, 0);             // SCL变高  
	} 
	udelay(10); 	
	//i2c_read_ack();                 //检查目标设备的ACK信号  
}  
/* I2C字节读 */  
unsigned char i2c_read_byte()  
{  
	int i;  
	unsigned char r = 0;  
	gpio_set_direction(SDA, INP);           //设置SDA方向为输入  
	for (i=7; i>=0; i--) {  
	gpio_set_val(SCL, 1);         // SCL变低  
	udelay(10);  
	r = (r <<1) | gpio_status(SDA);      //从高位到低位依次准备数据进行读取  
	gpio_set_val(SCL, 0);         // SCL变高  
	udelay(10);  
	}  
	//i2c_send_ack();                 //向目标设备发送ACK信号  
	return r;  
}  
/*  
I2C读操作  
addr:目标设备地址  
buf:读缓冲区  
len:读入字节的长度  
*/  
void i2c_read(unsigned char addr, unsigned char* buf, int len)  
{  
	int i;  
	unsigned char t;  
	i2c_start();                        //起始条件,开始数据通信  
	//发送地址和数据读写方向  
	t = (addr << 1) | 1;                    //低位为1,表示读数据  
	i2c_write_byte(t);  
	//读入数据  
	for (i=0; i<len; i++)  
	buf[i] = i2c_read_byte();  
	i2c_stop();                     //终止条件,结束数据通信  
}  
/*  
I2C写操作  
addr:目标设备地址  
buf:写缓冲区  
len:写入字节的长度  
*/  
void i2c_write (unsigned char addr, unsigned char* buf, int len)  
{  
	int i;  
	unsigned char t;  
	i2c_start();                        //起始条件,开始数据通信  
	//发送地址和数据读写方向  
	t = (addr << 1) | 0;                    //低位为0,表示写数据  
	i2c_write_byte(t);  
	//写入数据  
	for (i=0; i<len; i++)  
	i2c_write_byte(buf[i]);  
	i2c_stop();                     //终止条件,结束数据通信  
}  

//S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P

unsigned char i2c_read_one(unsigned char Slave_addr, unsigned char addr)  
{  
	unsigned char t,val;  
	i2c_start();                        //起始条件,开始数据通信 
	//发送地址和数据读写方向  
	t = (Slave_addr << 1) | 0;                    //低位为0,表示写数据  
	//dprintf(CRITICAL, "eliot:!!!! Slave_addr w = 0x%x\n",t);
	i2c_write_byte(t); 
	i2c_read_ack();
	//dprintf(CRITICAL, "eliot:!!!! ack1= %d\n",i2c_read_ack());	
	//写入数据   
	i2c_write_byte(addr); 
	i2c_read_ack();
	//dprintf(CRITICAL, "eliot:!!!! ack2= %d\n",i2c_read_ack());
	//i2c_stop(); 
	
	i2c_start(); 
	//发送地址和数据读写方向  
	t = (Slave_addr << 1) | 1;                    //低位为1,表示读数据 
	//dprintf(CRITICAL, "eliot:!!!! Slave_addr r = 0x%x\n",t);	
	i2c_write_byte(t); 
	i2c_read_ack();
	//dprintf(CRITICAL, "eliot:!!!! ack3= %d\n",i2c_read_ack());	
	//读入数据   
	val = i2c_read_byte();  
	i2c_send_noack() ;
	i2c_stop();                     //终止条件,结束数据通信  
	
	return val ;
}  

//S Addr Wr [A] Comm [A] Data [A] P
void i2c_write_one(unsigned char addr, unsigned char val)  
{  
	unsigned char t;  
	unsigned char Slave_addr = 0x2c;
	i2c_start();                        //起始条件,开始数据通信 
	//发送地址和数据读写方向  
	t = (Slave_addr << 1) | 0;                    //低位为0,表示写数据  
	//dprintf(CRITICAL, "eliot:!!!! Slave_addr w = 0x%x\n",t);
	i2c_write_byte(t);  
	i2c_read_ack();
	//dprintf(CRITICAL, "eliot:!!!! ack= %d\n",i2c_read_ack());
	//写入数据   
	i2c_write_byte(addr); 
	i2c_read_ack();
	//dprintf(CRITICAL, "eliot:!!!! ack= %d\n",i2c_read_ack());
	
	i2c_write_byte(val);  
	i2c_read_ack();
	//dprintf(CRITICAL, "eliot:!!!! ack= %d\n",i2c_read_ack());
	

	i2c_stop();                     //终止条件,结束数据通信  
}  

smbus-protocol

SMBus Protocol Summary
======================

The following is a summary of the SMBus protocol. It applies to
all revisions of the protocol (1.0, 1.1, and 2.0).
Certain protocol features which are not supported by
this package are briefly described at the end of this document.

Some adapters understand only the SMBus (System Management Bus) protocol,
which is a subset from the I2C protocol. Fortunately, many devices use
only the same subset, which makes it possible to put them on an SMBus.

If you write a driver for some I2C device, please try to use the SMBus
commands if at all possible (if the device uses only that subset of the
I2C protocol). This makes it possible to use the device driver on both
SMBus adapters and I2C adapters (the SMBus command set is automatically
translated to I2C on I2C adapters, but plain I2C commands can not be
handled at all on most pure SMBus adapters).

Below is a list of SMBus protocol operations, and the functions executing
them.  Note that the names used in the SMBus protocol specifications usually
don't match these function names.  For some of the operations which pass a
single data byte, the functions using SMBus protocol operation names execute
a different protocol operation entirely.

Each transaction type corresponds to a functionality flag. Before calling a
transaction function, a device driver should always check (just once) for
the corresponding functionality flag to ensure that the underlying I2C
adapter supports the transaction in question. See
<file:Documentation/i2c/functionality> for the details.


Key to symbols
==============

S     (1 bit) : Start bit
P     (1 bit) : Stop bit
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
A, NA (1 bit) : Accept and reverse accept bit. 
Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to 
                get a 10 bit I2C address.
Comm  (8 bits): Command byte, a data byte which often selects a register on
                the device.
Data  (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
                for 16 bit data.
Count (8 bits): A data byte containing the length of a block operation.

[..]: Data sent by I2C device, as opposed to data sent by the host adapter.


SMBus Quick Command
===================

This sends a single bit to the device, at the place of the Rd/Wr bit.

A Addr Rd/Wr [A] P

Functionality flag: I2C_FUNC_SMBUS_QUICK


SMBus Receive Byte:  i2c_smbus_read_byte()
==========================================

This reads a single byte from a device, without specifying a device
register. Some devices are so simple that this interface is enough; for
others, it is a shorthand if you want to read the same register as in
the previous SMBus command.

S Addr Rd [A] [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_BYTE


SMBus Send Byte:  i2c_smbus_write_byte()
========================================

This operation is the reverse of Receive Byte: it sends a single byte
to a device.  See Receive Byte for more information.

S Addr Wr [A] Data [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE


SMBus Read Byte:  i2c_smbus_read_byte_data()
============================================

This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte.

S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_BYTE_DATA


SMBus Read Word:  i2c_smbus_read_word_data()
============================================

This operation is very like Read Byte; again, data is read from a
device, from a designated register that is specified through the Comm
byte. But this time, the data is a complete word (16 bits).

S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_WORD_DATA

Note the convenience function i2c_smbus_read_word_swapped is
available for reads where the two data bytes are the other way
around (not SMBus compliant, but very popular.)


SMBus Write Byte:  i2c_smbus_write_byte_data()
==============================================

This writes a single byte to a device, to a designated register. The
register is specified through the Comm byte. This is the opposite of
the Read Byte operation.

S Addr Wr [A] Comm [A] Data [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE_DATA


SMBus Write Word:  i2c_smbus_write_word_data()
==============================================

This is the opposite of the Read Word operation. 16 bits
of data is written to a device, to the designated register that is
specified through the Comm byte. 

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_WORD_DATA

Note the convenience function i2c_smbus_write_word_swapped is
available for writes where the two data bytes are the other way
around (not SMBus compliant, but very popular.)


SMBus Process Call:
===================

This command selects a device register (through the Comm byte), sends
16 bits of data to it, and reads 16 bits of data in return.

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] 
                             S Addr Rd [A] [DataLow] A [DataHigh] NA P

Functionality flag: I2C_FUNC_SMBUS_PROC_CALL


SMBus Block Read:  i2c_smbus_read_block_data()
==============================================

This command reads a block of up to 32 bytes from a device, from a 
designated register that is specified through the Comm byte. The amount
of data is specified by the device in the Count byte.

S Addr Wr [A] Comm [A] 
           S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_BLOCK_DATA


SMBus Block Write:  i2c_smbus_write_block_data()
================================================

The opposite of the Block Read command, this writes up to 32 bytes to 
a device, to a designated register that is specified through the
Comm byte. The amount of data is specified in the Count byte.

S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_BLOCK_DATA


SMBus Block Write - Block Read Process Call
===========================================

SMBus Block Write - Block Read Process Call was introduced in
Revision 2.0 of the specification.

This command selects a device register (through the Comm byte), sends
1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return.

S Addr Wr [A] Comm [A] Count [A] Data [A] ...
                             S Addr Rd [A] [Count] A [Data] ... A P

Functionality flag: I2C_FUNC_SMBUS_BLOCK_PROC_CALL


SMBus Host Notify
=================

This command is sent from a SMBus device acting as a master to the
SMBus host acting as a slave.
It is the same form as Write Word, with the command code replaced by the
alerting device's address.

[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P]


Packet Error Checking (PEC)
===========================

Packet Error Checking was introduced in Revision 1.1 of the specification.

PEC adds a CRC-8 error-checking byte to transfers using it, immediately
before the terminating STOP.


Address Resolution Protocol (ARP)
=================================

The Address Resolution Protocol was introduced in Revision 2.0 of
the specification. It is a higher-layer protocol which uses the
messages above.

ARP adds device enumeration and dynamic address assignment to
the protocol. All ARP communications use slave address 0x61 and
require PEC checksums.


SMBus Alert
===========

SMBus Alert was introduced in Revision 1.0 of the specification.

The SMBus alert protocol allows several SMBus slave devices to share a
single interrupt pin on the SMBus master, while still allowing the master
to know which slave triggered the interrupt.

This is implemented the following way in the Linux kernel:
* I2C bus drivers which support SMBus alert should call
  i2c_setup_smbus_alert() to setup SMBus alert support.
* I2C drivers for devices which can trigger SMBus alerts should implement
  the optional alert() callback.


I2C Block Transactions
======================

The following I2C block transactions are supported by the
SMBus layer and are described here for completeness.
They are *NOT* defined by the SMBus specification.

I2C block transactions do not limit the number of bytes transferred
but the SMBus layer places a limit of 32 bytes.


I2C Block Read:  i2c_smbus_read_i2c_block_data()
================================================

This command reads a block of bytes from a device, from a 
designated register that is specified through the Comm byte.

S Addr Wr [A] Comm [A] 
           S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_I2C_BLOCK


I2C Block Write:  i2c_smbus_write_i2c_block_data()
==================================================

The opposite of the Block Read command, this writes bytes to 
a device, to a designated register that is specified through the
Comm byte. Note that command lengths of 0, 2, or more bytes are
supported as they are indistinguishable from data.

S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值