I2C driver Programming Interface I2c_master_send and I2C_MASTER_RECV, i2c_transfer__ programming

Source: Internet
Author: User
1. Communication interface
I2C send or receive data in packets struct I2C_MSG encapsulation
[CPP]
struct I2C_MSG {
__u16 addr; From machine address
__U16 flags; Sign
#define I2c_m_ten 0x0010//10-bit address flag
#define I2C_M_RD 0x0001//Receive data markers
__u16 Len; Data length
__u8 *buf; Data pointers
};
Where addr is the address of the machine; flags are the sign of this communication, sending the data as 0, and receiving the data as the number of bytes I2c_m_rd;len for this communication; buf a pointer to send or receive data. In device drivers we typically call I2c-core-defined interfaces I2c_master_send and I2C_MASTER_RECV to send or receive data.
[CPP]
int i2c_master_send (struct i2c_client *client,const char *buf, int count)
{
int ret;
struct I2c_adapter *adap=client->adapter; Get Adapter Information
struct i2c_msg msg; To define a temporary packet

MSG.ADDR = client->addr; Write the address from the machine to the packet
Msg.flags = client->flags & I2c_m_ten; Merging from machine flags into packets
Msg.len = count; Writes the number of bytes sent to the data packet
MSG.BUF = (char *) buf; Writes the sending data pointer to a packet

ret = I2c_transfer (ADAP, &msg, 1); Calling the platform interface to send data

/* If everything went ok (i.e 1 MSG transmitted), return #bytes
Transmitted, else error code. */
return (ret = 1)?           Count:ret; Returns the number of bytes if sent successfully
}
Export_symbol (I2c_master_send);
The three parameters of the I2c_master_send interface: Client for this host communication from the machine, buf for the sent data pointer, count is the number of bytes sent data.
[CPP]
int i2c_master_recv (struct i2c_client *client, char *buf, int count)
{
struct I2c_adapter *adap=client->adapter; Get Adapter Information
struct i2c_msg msg; To define a temporary packet
int ret;

MSG.ADDR = client->addr; Write the address from the machine to the packet
Msg.flags = client->flags & I2c_m_ten; Merging from machine flags into packets
Msg.flags |= i2c_m_rd; Incorporate the logo of this communication into the packet
Msg.len = count; Writes the number of bytes received for this data packet
Msg.buf = BUF;

ret = I2c_transfer (ADAP, &msg, 1); Calling the platform interface to receive data

/* If everything went ok (i.e 1 MSG transmitted), return #bytes
Transmitted, else error code. */
return (ret = 1)?           Count:ret; Returns the number of bytes if received successfully
}
Export_symbol (I2C_MASTER_RECV);
The three parameters of the I2C_MASTER_RECV interface: Client for this host communication from the machine, buf for the received data pointer, count is the number of bytes received data. Let's take a look at the parameter descriptions for the I2c_transfer interface:
[CPP
int I2c_transfer (struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
Where ADAP is the adapter that the host communicates with the machine; msgs is a packet of traffic, which can be single or multiple packets; num is used to specify the number of packets, and if greater than 1 indicates that more than one communication will be performed. Once a communication needs to be addressed once, multiple addresses are required if multiple communications are required, the first 2 interfaces are all for one communication, so num is 1; In some cases we want to read the value of a register, we need to send a register address from the machine and then receive data, so if you want to encapsulate an interface, you need to Num is set to 2. The return value of the interface is negative if it fails, and returns the number of packets transmitted if successful. For example, an interface that reads a register can be encapsulated as follows:
[CPP]
static int Read_reg (struct i2c_client *client, unsigned char reg, unsigned char *data)
{
int ret;

struct I2c_msg msgs[] = {
{
. addr = Client->addr,
. Flags = 0,
. Len = 1,
. BUF = &reg,//register address
},
{
. addr = Client->addr,
. Flags = I2C_M_RD,
. Len = 1,
. BUF = data,//Register value
},
};

ret = I2c_transfer (Client->adapter, msgs, 2); Here num = 2, communication success RET = 2
if (Ret < 0)
Tp_err ("%s Error:%d\n", __func__, ret);

return ret;
}
You can also invoke the interface encapsulation described earlier:
[CPP]
static unsigned char read_reg (struct i2c_client *client, unsigned char reg)
{
unsigned char buf;

I2c_master_send (client, &reg, 1); Send Register Address
I2C_MASTER_RECV (client, &AMP;BUF, 1); Value of Receive Register

return buf;
}
2, Reset interface
Recently because the platform of the I2C bus often deadlock, with the logic Analyzer detection found that usually SDA and SCL are pulled down, so in I2c-core added the reset mechanism, the overall idea is as follows:
(1) In the structure of i2c.driver and i2c.adapter add reset interface, that is, each I2C device can register reset function, each I2C bus has the corresponding reset interface
(2) When a deadlock occurs, first get the device address and bus number of the current communication according to the I2c-timeout information, then execute the reset function of all the I2C devices under the current bus, and then try to send it successfully. If the bus is still in a deadlock state, perform the reset function of I2c.adapter, or reboot the machine if the bus is still in a deadlock state; a total of 3 layers reset mechanism
(3) I2c.driver reset function general operating equipment reset PIN or power supply (need to be based on the hardware design of the corresponding operation)
(4) The Reset function of I2c.adapter is preferred to simulate the SCL, and then it is the power to operate the equipment on the whole bus (it needs to be operated according to the hardware design).
(5) Reboot is the last layer of mechanism, at this time can not restore the normal use of equipment can only be restarted
Because of the need of the I2c.adapter layer, an interface i2c_reset_device that traverses all devices in the current bus and performs the reset function of the device is added in I2c-core:
[CPP]
/**
* I2c_reset_device-reset I2C device when bus dead
* @adapter: The adapter being reset
* @addr: The device Address
*/
static int __i2c_reset_device (struct device *dev, void *ADDRP)
{
struct I2c_client *client = to_i2c_client (dev);
int addr = * (int *) ADDRP;

if (client && client->driver && client->driver->reset)
return Client->driver->reset ();

return 0;
}

int I2c_reset_device (struct i2c_adapter *adapter, int addr)
{
Return Device_for_each_child (&adapter->dev, &addr, __i2c_reset_device);
}
Export_symbol (I2c_reset_device);
Note that the reset function of I2c.driver is required to return a value of 0, or Device_for_each_child will not continue the subsequent traversal. The reference code to simulate SCL unlocking with Gpio is as follows:
[CPP]
static int i2c_reset_adapter (void)
{
int counter = 0;

Gpio_request (I2c_bus_data, "Gpioxx");
Gpio_request (I2C_BUS_CLK, "Gpioxx");
* Try to recover I2C bus * *
Gpio_direction_input (I2c_bus_data);

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.