Linux Device Driver Tutorial Part 40 – I2C Bus Linux Device Driver using I2C-GPIO

This is the Series on Linux Device Driver. The aim of this series is to provide easy and practical examples that anyone can understand. This is the Linux Device Driver Tutorial Part 40 – I2C Bus Linux Device Driver using I2C-GPIO using Raspberry PI.

We are using the Raspberry PI 4 Model B for this demonstration.

I2C Bus Linux Device Driver using I2C-GPIO

Prerequisites

Hardware Required

Bring up Raspberry PI

  1. Install Raspberry Pi OS (32-bit) with desktop in the SD card.
  2. Then install the kernel header using sudo apt install raspberrypi-kernel-headers

For your information, In our Raspberry PI 4 board, kernel 5.4.51-v7l+ is installed.

Please enable the I2C in the Raspberry Pi.

Introduction

In our last tutorial,  we have implemented everything using Bit banging right from the START condition, STOP condition, Read ACK/NACK, etc. But we have not taken care of advanced I2C operations like arbitration, clock stretching, etc. So even if we implement that we have to test it fully. Maybe our approach will take more time than normal.

So in this tutorial, we are going to use i2c-gpio driver where all the START condition, STOP condition, ACK/NACK, Arbitration, clock stretching, etc are implemented (bit banging) and it has been tested fully as it is part of the Linux kernel. So we will see how to use that. Let’s get started.

APIs used for the I2C bus driver

struct i2c_algo_bit_data

If you see the structure, setscl, getscl, setsda, getsda are present. We have to give our callback function to these members. For example, If the i2c-gpio driver wants to send the START condition, it needs to set the SCL/SDA GPIO to High/Low. But it doesn’t know which GPIO we are using. That’s why they have made this as a callback. See the example code given below to understand more.

data – private data (Optional)

pre_xfer – Function that will be called before i2C-gpio starts the I2C transfer  (Optional)

post_xfer – Function that will be called after i2C-gpio finishes the I2C transfer (Optional)

delay – delay in uS

timout – Timout in jiffies

can_do_atomic – This will tells callback can sleep or not (Optional)

 Note : When you are using this method, you have to add this structure to the i2c_adapter structure’s algo_data member. Make sure that you have requested the GPIO before accessing.

Example

i2c_bit_add_bus

This API is used to register the adapter to the subsystem. But this will assign the dynamic bus number.

int i2c_bit_add_bus (struct i2c_adapter * adapter);

where,
adapter – the adapter to add

It returns zero when a new bus number was allocated and stored in adap->nr, and the specified adapter became available for clients. Otherwise, a negative errno value is returned

i2c_bit_add_numbered_bus

This API is used to register the adapter to the subsystem. But it assigns the number that we asked for if only it is available. We have to initialize the member called nr in the i2c_adapter structure before calling this.

int i2c_bit_add_numbered_bus ( struct i2c_adapter * adap);

Where,
adap – the adapter to register (with adap->nr initialized)

This returns zero when the specified adapter is available for clients using the bus number provided in adap->nr. Otherwise, negative errno value is returned.

I think we have discussed other APIs in our previous tutorials. So we can jump into the programming now.

Example Programming

In this tutorial, we will demonstrate the same example (last tutorial’s) which fills data in the display while loading the module and clears the display while unloading the module. The only difference from the last tutorial is the code that we are using in the bus driver.

Connection Diagram

  • SCL – GPIO 20
  • SDA – GPIO 21

I2C-bus-driver-ssd1306-interface-with-raspberry-pi

I2C Bus Driver Source Code

[Get the source code form the GitHub]

Makefile

2C Client Device Driver Source code

There is no modifications in the client driver from the last tutorial.

[Get the source code form the GitHub]

Makefile

Testing the Device Driver

  • Build the driver by using Makefile (sudo make) in both bus and client driver directories.
  • Before loading the bus driver, we should load the i2c-gpio driver. Use sudo modprobe i2c-gpio to load the i2c-gpio driver.
  • Load the bus driver using sudo insmod driver_bus.ko
  • Load the client driver using sudo insmod driver_client.ko
  • See the Display is filled.
  • Unload the driver using sudo rmmod driver_client
  • See the Display has been cleared.
  • Unload the driver using sudo rmmod driver_bus
  • Unload the i2c-gpio using sudo modprobe -r i2c-gpio

Output Video

Click here if you don’t see the output video

5 2 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x
%d bloggers like this: