Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Zynq linux's I2C-driven Learning Notes (1)

2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/02 Report--

Recently, I have been doing a small project with Mill's Z-TURN BOARD veneer. By the way, also strengthen the study of I2C driver, write down a note.

I2C bus knowledge is very simple, SDA,SCL, their timing rules are: I2C bus is a serial bus composed of data line SDA and clock SCL, which can send and receive data. Bi-directional transmission is carried out between the CPU and the controlled IC, and between the IC and the IC, with the highest transmission rate 100kbps. All kinds of controlled circuits are connected in parallel on this bus, but just like telephones, they can only work by dialing their respective numbers, so each circuit and module has a unique address. In the process of information transmission, each module circuit connected to the I2C bus is not only the main controller (or controlled), but also the transmitter (or receiver), depending on the function it wants to complete. The control signal sent by CPU is divided into two parts: the address code and the control quantity. The address code is used to select the address, that is, to turn on the circuit to be controlled and to determine the type of control; the control quantity determines the type of adjustment (such as contrast, brightness, etc.) and the amount to be adjusted. In this way, although the control circuits are hung on the same bus, they are independent and independent of each other.

There are three types of signals in the process of data transmission in I2C bus, which are: start signal, end signal and reply signal.

Start signal: SCL is a high level, SDA jumps from high level to low level, and begins to transmit data.

End signal: SCL is a high level, SDA jumps from low level to high level, ending data transmission.

Reply signal: after receiving the 8bit data, the IC that receives the data sends a specific low-level pulse to the IC that sends the data, indicating that the data has been received. After CPU sends a signal to the controlled unit, it waits for the controlled unit to send a reply signal. After receiving the reply signal, CPU makes a judgment on whether to continue to transmit the signal according to the actual situation. If the response signal is not received, it is judged that the controlled unit is faulty.

In the process of initialization of the LINUX system, the required I2C slave devices are added to a two-way cyclic list called _ i2c_board_list through i2c_register_board_info. After successfully loading the I2C master device adapt, the system will complete the i2c_client registration of all the I2C slave devices in this list one by one.

In other words, both i2c_client and i2c_adapter are maintained by i2c_core.

In xilinx-linux, i2c slave devices are passed to the kernel through the dts file, and the kernel registers all i2c slave devices through the zynq_init_machine function, i2c_client.

The linux of I2C must know four structures: i2cworkshop adaptor, i2cvendor adaptor, i2cvendor client, i2cvendor driver.

Struct i2c_adapter {

Struct module owner

Unsigned int class; / classes to allow probing for /

Const struct i2c_algorithm algo; / the algorithm to access the bus /

Void * algo_data

/ data fields that are valid for all devices /

Struct rt_mutex bus_lock

Int timeout; / in jIFfies /

Int retries

Struct device dev; / the adapter device /

Int nr

Char name [48]

Struct completion dev_released

Struct mutex userspace_clients_lock

Struct list_head userspace_clients

Struct i2c_bus_recovery_info * bus_recovery_info

}

I2C bus controller data is attached to algo_data, such as xi2cps,s3c24xx_i2c.

Struct device dev; members indicate that i2c_adapter is a hardware that corresponds to the I2C controller on SoC. I2c_algorithm is the underlying driver of this I2C controller.

By the same token:

Struct i2c_client {

Unsigned short flags; / div., see below /

Unsigned short addr; / chip address-NOTE: 7bit /

/ addresses are stored in the /

/ LOWER 7 bits /

Char name[I2C _ NAME_SIZE]

Struct i2c_adapter adapter; / the adapter we sit on /

Struct i2c_driver driver; / and our access routines /

Struct device dev; / the device structure /

Int irq; / irq issued by device /

Struct list_head detected

}

Struct i2c_client represents an i2C slave device mounted to the i2C bus, the data structure required by the device, including

The i2c master device struct i2c_adapter adapter to which the i2c slave device is attached

The i2c slave device driver struct i2c_driver driver

As a common member variable for i2c slave devices, such as addr, name, etc.

The i2c slave device driver-specific data is attached to dev- > driver_data, and the structure member is set in the probe function in i2c_driver. Such as eeprom's eeprom_data.

Bi-directional linked list of all i2c slave devices: detected

Struct device dev indicates that struct i2c_client represents a piece of hardware, such as an eeprom chip, or a rtc chip, which is connected to i2c_adapter hardware through an i2C bus.

I2c_driver is the driver of the i2c_client chip hardware.

We generally define a private information structure for each I2C character device, and i2c_client is generally included in this private information structure. Hacker that has seen the LDR3 source code should be clear.

I2c_client is attached to i2c_adapter, that is, the corresponding relationship between I2C devices and I2C bus controllers. The struct list_head userspace_clients; structure members of an i2c_adapter that can connect more than one i2c client adapter is a linked list of all client.

The latest version of linux basically supports all current I2C adapter hardware and I2C slave devices, but engineers may face a variety of situations: writing drivers for i2c_adapter and i2c_client.

II. I2C core

The I2C core is that the source code is located in drivers/i2c/i2c-core.c, which does not depend on the interface function of the hardware platform and is the link between the I2C bus driver and the device driver.

Add / remove i2c_adapter

Int i2c_add_adapter (struct i2c_adapter adapter) / / call i2c_register_adapter ()

Int i2c_del_adapter (struct i2c_adapter adapter)

Add / remove i2c_driver

Int i2c_register_driver (struct module owner, struct i2c_driver driver)

Int i2c_add_driver (struct i2c_driver driver) / / call i2c_register_driver

Void i2c_del_driver (struct i2c_driver driver)

Add / remove i2c_client

Struct i2c_client i2c_new_device (struct i2c_adapter adap, struct i2c_board_info const info)

Void i2c_unregister_device (struct i2c_client client)

Note: before version 2.6.30, the i2c_attach_client () and i2c_detach_client () functions were used. Attach is then added to i2c_new_device by merge, while detach is directly replaced by unregister. In fact, device_register () and device_unregister () are called inside both functions.

I2C transmission, sending and receiving

Int i2c_transfer (struct i2c_adapter adap, struct i2c_msg msgs, int num)

Int i2c_master_send (struct i2c_client client,const char buf, int count)

Int i2c_master_recv (struct i2c_client client, char buf, int count)

The i2c_transfer () function is used for a set of message interactions between the I2C adapter and the I2C device. The i2c_master_send () function and the i2c_master_recv () function call the i2c_transfer () function to complete a write message and a read message, respectively.

I2c_transfer () itself can not complete message interaction with the hardware, it looks for the corresponding i2c_algorithm of i2c_adapter. To achieve data transfer, it is necessary to implement i2c_algorithm 's master_xfer (). This function is related to the specific hardware and is completed by the manufacturer most of the time.

I2c_transfer () completes I2C communication by calling _ _ i2c_transfer ():

Int _ _ i2c_transfer (struct i2c_adapter adap, struct i2c_msg msgs, int num)

{

Unsigned long orig_jiffies

Int ret, try

/ Retry automatically on arbitration loss /

Orig_jiffies = jiffies

For (ret = 0, try = 0; try retries; try++) {

Ret = adap- > algo- > master_xfer (adap, msgs, num)

If (ret! =-EAGAIN)

Break

If (time_after (jiffies, orig_jiffies + adap- > timeout))

Break

}

Return ret

}

It can be seen that retries is the number of retransmission attempts and timeout is the timeout.

Third, Linux I2C bus driver

1. Loading and removing of I2C Adapter

Load: apply for hardware resources, such as IO address, interrupt number, call i2c_add_adapter load adapter

The i2c_register_adapter function is called in i2c_add_adapter

Static int i2c_register_adapter (struct i2c_adapter * adap)

{

Device_register (& adap- > dev); / / complete the registration of I2C master device adapter, that is, register object and send uevent, etc.

I2c_scan_static_board_info (adap); / / Register i2c_clienlt

}

Static void i2c_scan_static_board_info (struct i2c_adapter adapter)

{

Struct i2c_devinfo devinfo

Down_read (& _ _ i2c_board_lock)

List_for_each_entry (devinfo, & i2c_board_list, list) {

If (devinfo- > busnum = = adapter- > nr

&! i2c_new_device (adapter

& devinfo- > board_info))

Dev_err (& adapter- > dev

"Can't create device at 0xx\ n"

Devinfo- > board_info.addr)

}

Up_read & i2c_board_lock)

}

I2c_new_device calls device_register to register the i2c slave device.

So, when and how did this two-way circular list of I2C slave devices be established?

Take / arch/ARM/mach-pxa/saar.c as an example

Static void _ init saar_init (void)

{

Saar_init_i2c ()

}

Static void _ init saar_init_i2c (void)

{

Pxa_set_i2c_info (NULL)

I2c_register_board_info (0, ARRAY_AND_SIZE (saar_i2c_info))

}

Static struct i2c_board_info saar_i2c_info [] = {

[0] = {

.type = "da9034"

.addr = 0x34

.platform _ data = & saar_da9034_info

.irq = PXA_GPIO_TO_IRQ (mfp_to_gpio (MFP_PIN_GPIO83))

}

}

/ drivers/i2c/i2c-boardinfo.c /

Int _ _ init i2c_register_board_info (int busnum, structi2c_board_info const info, unsigned len)

{

Struct i2c_devinfo devinfo

Devinfo- > board_info = * info

List_add_tail (& devinfo- > list, & _ i2c_board_list); / / add I2C slave devices to the linked list

}

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report