Post

Refactoring Auxiliary I2C Transfers in the MPU6050 Driver

My first patch submission to the Linux kernel, refactoring auxiliary I2C transfers in the MPU6050 IMU driver, as part of the Free and Open Source Software Development course at USP.

Refactoring Auxiliary I2C Transfers in the MPU6050 Driver

Working with Rodrigo, I’ve submitted my first contribution to the Linux kernel! Our patch focuses on improving the MPU6050 IMU driver, which handles an accelerometer and gyroscope via the I2C protocol. This device lives in the IIO (Industrial I/O) subsystem, under drivers/iio/imu/inv_mpu6050/.

What We Changed

Based on the sugestions of last class, we chose the one with two functions inv_mpu_aux_read and inv_mpu_aux_write sharing the same sequence of I2C transfer steps. This sequence involved:

  • Starting an I2C transfer.
  • Disabling the slave device.
  • Checking for transfer errors.
  • Handling errors and cleanup if something went wrong.

This block of code appeared almost identically in both functions, which we saw as an opportunity to refactor.

We introduced a helper function, inv_mpu_aux_exec_xfer, to encapsulate this repeated logic. This function:

  • Initiates the I2C transfer.
  • Disables the slave after the transfer.
  • Checks for any transfer errors and returns an appropriate status.

With that in place, the read and write functions became simpler and easier to maintain:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
                     uint8_t reg, uint8_t *val, size_t size)
{
    /* [...] previous code */
    ret = inv_mpu_aux_exec_xfer(st);
    if (ret)
        return ret;

    /* read data in registers */
    return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
                            val, size);
}

int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
                      uint8_t reg, uint8_t val)
{
    /* [...] previous code */
    ret = inv_mpu_aux_exec_xfer(st);
    if (ret)
        return ret;

    return 0;
}

With the function that we created, we got the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 /**
  * inv_mpu_aux_exec_xfer() - executes i2c auxiliary transfer and checks status
  * @st: driver internal state.
  *
  *  Returns 0 on success, a negative error code otherwise.
  */
int inv_mpu_aux_exec_xfer(const struct inv_mpu6050_state *st)
 {
	 int ret;
	 unsigned int status;
	 
	 /* do i2c xfer */
	 ret = inv_mpu_i2c_master_xfer(st);
	 if (ret)
		 goto error_disable_i2c;
 
	 /* disable i2c slave */
	 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
	 if (ret)
		 goto error_disable_i2c;
 
	 /* check i2c status */
	 ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
	 if (ret)
		 return ret;
	 if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
		 return -EIO;
 
 error_disable_i2c:
	 regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
	 return ret;
 }
 
int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
                     uint8_t reg, uint8_t *val, size_t size)
{
    /* [...] previous code */
    ret = inv_mpu_aux_exec_xfer(st);
    if(ret)
        return ret;

    /* read data in registers */
    return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
                            val, size);
}

int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
                      uint8_t reg, uint8_t val)
{
    /* [...] previous code */
    ret = inv_mpu_aux_exec_xfer(st);
    if(ret)
        return ret;

    return 0;
}

Submitting the Patch

Besides working on the code itself, I also experienced how to submit a patch to the Linux kernel via email. This is a crucial part of the contribution process, and even though our patch was small, learning this workflow was important.

During this process, I ran into an issue with my university email address, which caused some trouble sending emails in the proper format. Thankfully, with help from one of the TAs, I was able to use my personal email to send the patch instead.

We also received feedback from the course TA after sending the patch for initial review. Some improvements were suggested before we submit it officially to the kernel mailing list, and working on these adjustments will be the next step in this process.

This post is licensed under CC BY 4.0 by the author.