The document discusses Inter-Integrated Circuit (I2C) drivers in Linux. It provides an overview of I2C, describing its conditions, transactions and popular uses. It also describes the I2C subsystem in Linux, including I2C adapters, clients and drivers. It explains how to write an I2C client driver, covering initialization, cleanup and registration both with and without a device tree. The document aims to cover all aspects of developing I2C drivers and interfacing with I2C devices in Linux.
1_Introduction + EAM Vocabulary + how to navigate in EAM.pdf
I2c drivers
1. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Inter Integrated Circuit (I2C) Drivers
2. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
What to Expect
● I2C Overview
● I2C Conditions & Transactions
● I2C Subsystem in Linux – I2C Adapter & I2C
Client
● I2C Client Driver
● I2C Device Registration (Non DT and DT)
3. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Overview
● Originally developed by Phillips
● Suitable for small slow devices
● I2C is a 2-wire protocol
– One Serial Clock Line
– One Data Line
● Popular in Desktops & Embedded Systems
● Used for accessing
– EEPROMs
– RTCs
– ADCs
– ....
4. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Conditions
● Start Condition
– Master signals this condition to initiate the transfer
on the bus
● Stop Condition
– Master signals this condition to stop the transfer
● ACK Condition
– Master or Slave signals this to acknowledge the
succesful receipt of byte
5. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Transactions
● Master begins the communication by issuing
the start condition.
● Sends a 7/10 bit slave address followed by
read/write bit
● The addressed slave ACKs the transfer
● Transmitter transmits a byte of data and
receiver issues ACK on successful receipt
● Master issues a STOP condition to conclude
the transaction
6. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Transactions...
Start Data 1
SLA + W
Slave
ACK
Data 2 Data N
Slave
ACK
Slave
ACK
Stop
Master Write
Slave
ACK
Start Addr. 1
SLA +
W
Slave
ACK
Repeat
Start
Data
1
Slave
ACK
SLA +
R
Stop
Master
ACK
Data
N
Master
NACK
Master Read
7. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Character Driver Framework
User Space
i2c_app.c,
i2c_intr.c
Char Driver (i2c_char.c)
Low Level I2
C Driver
(low_level_driver.c)
App
open(), read(),
write()
/dev/i2c_drv0
my_open() my_read() my_write()
i2c_receive() i2c_transmit()
8. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
AM335X I2C Initialization
● Get the virtual address for the I2C-0 registers base address
● Set up the I2C speed
– Set the pre-scalar register to generate the I2C module
internal clock from the functional clock
– Set the scl low time & scl high time registers
● Enable the events
– Update the ‘Interrupt Enable Set’ register to enable various
events such as XRDY, RRDY and so on
9. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
AM335x I2C Registers
● I2C_SA_REGISTER (Slave Address Register)
● I2C_CON_REGISTER (Configuration Register)
– Bits for enabling / disabling the I2C module
– Selecting the Fast / Standard mode of operation
– Selecting the Master / Slave config
– Sending the Start / Stop conditions on the bus
● I2C_DATA (RX/TX Data Register)
● I2C_BUF (FIFO Thresholds, DMA configuration)
● I2C_CNT (Bytes in I2C data payload)
● I2C_IRQ_STATUS_REG
10. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
AM335X I2C APIs
● #include “i2c_char.h”
● u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int
reg)
● void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
int reg, u16 val)
● u16 wait_for_event(struct omap_i2c_dev *dev)
● void omap_i2c_ack_stat(struct omap_i2c_dev, u16 stat)
● val = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG)
● val |= OMAP_I2C_BUF_TXFIF
● omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, val)
11. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Accessing EEPROM
0XAA
0x0060
EEPROM
I2C Slave Address 0X50
12. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Writing to EEPROM
● For writing at EEPROM offset 0x0060
● Send the start condition
● Send the slave address of EEPROM (0X50), followed
by direction (Read/Write)
● Send the EEPROM offset higher byte, followed by
lower byte
● Send the actual data to be written
● Send the Stop condition
● START->0x50->0x00(offset high)->0x60 (offset low)-
>0X99(Data)->STOP
13. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Reading From EEPROM
● Write the EEPROM offset say 0x0060 (read offset)
– START->0x50->0x00(offset high)->0x60 (offset
low)->STOP
● Read the EEPROM data
– Send the start condition
– Send the slave address of EEPROM (0X50),
followed by direction (Read)
– Read the data
– Send the stop condition
– START->0x50->Data (RX)->Data (RX)->STOP
14. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Need for Linux Device Model
● Maximize the code re-usability across the platforms
– Same device drivers on different platforms
● To achieve this
– Decouple device drivers from controller drivers
– Decouple hardware description from the drivers
● In addition to above
– Information about how the system is put together
● Effective power management
– Communication with user space
– Hotpluggable devices
15. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Device Drivers in Linux
Application
System Call
Interface
Framework
Driver
Bus
Infrastructure
Hardware
16. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Device model data structures
● struct bus_type
– Represents the bus such as USB, PCI, I2C etc
● struct device_driver
– Represents the driver capable of handling certain
devices
● struct device
– Represents the device connected to the bus
17. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Linux I2C Subsystem
● I2C subsystem provides
– API to implement I2C controller driver
– API to implement I2C device driver in kernel space
– An abstraction to implement the client drivers
independent of adapter drivers
18. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Linux I2C Subsystem ...
User Space
Kernel Space
I2C Device
(i2c_client)
I2C Host
Controller
(i2c_adapter)
Hardware Space
/sys, /dev
User Applications
User Mode I2C
Device Driver
I2C Core
i2c-dev
Vertical: Character
I2C Client Driver
I2C Bus
I2C Adapter (platform_driver) / Algo Driver (i2c_algorithm)
19. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Subsystem Details
● i2c-adapter / i2c-algo
– Controller-specific I2C host controller / adapter
– Also called as the I2C bus drivers
● i2c-core
– Hides the adapter details from the layers above
– By providing the generic I2C APIs
● i2c-dev
– Provides device access in user space through /sys
– Enables implementation of User Mode Drivers
● i2c-client
– Driver specific to an I2C device
– Implemented using i2c-core APIs
20. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Client Driver
● Typically a character driver vertical - /dev or
/sys exposed
● But actually depends on the device category
● Registers with I2C Core (in the init function)
● Unregisters from I2C Core (in the cleanup
function)
● And uses the generic function from I2C Core for
data transfers
– int i2c_transfer(struct i2c_adapter *adap, struct
i2c_msg *msgs, int num)
21. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Client Driver init & cleanup
● Registering to the I2C Core using
– int i2c_add_driver(struct i2c_driver *)
– struct i2c_driver contains
● probe function – called on device detection
● remove function – called on device shutdown
● id_table – Table of device identifiers
● Unregistering from the I2C Core using
– void i2c_del_driver(struct i2c_driver *)
● Common bare-bone of init & cleanup
– Just use module_i2c_driver(struct i2c_driver)
23. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
I2C Adapter Driver (Un)Registeration
● Registering to the I2C Core using
– int i2c_add_numbered_adapter(struct i2c_adapter
*);
– Registered in the platform driver probe
● Unregistering from the I2C Core using
– void i2c_del_adapter(struct i2c_driver *);
– In platform driver remove functions
25. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Registering the I2C Client (Non DT)
● On non-DT platforms, the struct i2c_board_info
describes how device is connected to a board
● Defined with I2C_BOARD_INFO helper macro
– Takes as the arguments, the device name and the
slave address of the device on the bus
● An array of such structures is registered on per
bus basis using the i2c_register_board_info
during the platform initialization
27. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Registering an I2C Client (DT)
● In the device tree, the I2C devices on the bus
are described as children of the I2C controller
node
● reg property gives the I2C slave address on the
bus
28. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
Registering an I2C Client (DT) ...
● i2c@49607899 {
compatible = "dummy_adap";
clock-frequency = <0x186a0>;
#address-cells = <0x1>;
#size-cells = <0x0>;
my_dummy@0 {
compatible = "dummy_device";
reg = <0x40>;
};
};
● Registered internally by i2c_core based on info from DTB
● i2c_new_device(struct i2c_adapter *, struct i2c_board_info *)
29. @ 2021-22 Embitude Trainings <info@embitude.in>
All Rights Reserved
What all did we learn?
● I2C Overview
● I2C Conditions & Transactions
● I2C Subsystem in Linux – I2C Adapter & I2C
Client
● I2C Client Driver
● I2C Device Registration (Non DT and DT)