mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Refactors inv_mpu_aux_read() and inv_mpu_aux_write() to extract the common I2C transfer sequence into inv_mpu_i2c_master_xfer(), which now handles starting and stopping the I2C master, waiting for completion, disabling SLV0, and checking for NACK errors. This refactoring removes code duplication and improves maintainability. No functional changes are intended. Signed-off-by: Isabella Caselli <bellacaselli20@gmail.com> Co-developed-by: Rodrigo Michelassi <rodrigo.michelassi@usp.br> Signed-off-by: Rodrigo Michelassi <rodrigo.michelassi@usp.br> Acked-by: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com> Link: https://patch.msgid.link/20250507184539.54658-1-bellacaselli20@gmail.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
201 lines
5.1 KiB
C
201 lines
5.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2019 TDK-InvenSense, Inc.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/device.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include "inv_mpu_aux.h"
|
|
#include "inv_mpu_iio.h"
|
|
|
|
/*
|
|
* i2c master auxiliary bus transfer function.
|
|
* Requires the i2c operations to be correctly setup before.
|
|
* Disables SLV0 and checks for NACK status internally.
|
|
* Assumes that only SLV0 is used for transfers.
|
|
*/
|
|
static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st)
|
|
{
|
|
/* use 50hz frequency for xfer */
|
|
const unsigned int freq = 50;
|
|
const unsigned int period_ms = 1000 / freq;
|
|
uint8_t d;
|
|
unsigned int user_ctrl;
|
|
int ret;
|
|
unsigned int status;
|
|
|
|
/* set sample rate */
|
|
d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq);
|
|
ret = regmap_write(st->map, st->reg->sample_rate_div, d);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* start i2c master */
|
|
user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
|
|
ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
|
|
if (ret)
|
|
goto error_restore_rate;
|
|
|
|
/* wait for xfer: 1 period + half-period margin */
|
|
msleep(period_ms + period_ms / 2);
|
|
|
|
/* stop i2c master */
|
|
user_ctrl = st->chip_config.user_ctrl;
|
|
ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
|
|
if (ret)
|
|
goto error_stop_i2c;
|
|
|
|
/* restore sample rate */
|
|
d = st->chip_config.divider;
|
|
ret = regmap_write(st->map, st->reg->sample_rate_div, d);
|
|
if (ret)
|
|
goto error_restore_rate;
|
|
|
|
/* 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;
|
|
|
|
return 0;
|
|
|
|
error_stop_i2c:
|
|
regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
|
|
error_restore_rate:
|
|
regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider);
|
|
error_disable_i2c:
|
|
regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* inv_mpu_aux_init() - init i2c auxiliary bus
|
|
* @st: driver internal state
|
|
*
|
|
* Returns 0 on success, a negative error code otherwise.
|
|
*/
|
|
int inv_mpu_aux_init(const struct inv_mpu6050_state *st)
|
|
{
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
/*
|
|
* Code based on the vendor Linux kernel v3.0,
|
|
* the exact meaning is unknown.
|
|
*/
|
|
if (st->chip_type == INV_MPU9150) {
|
|
unsigned int mask = BIT(7);
|
|
|
|
val = st->level_shifter ? mask : 0;
|
|
ret = regmap_update_bits(st->map, 0x1, mask, val);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
/* configure i2c master */
|
|
val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ |
|
|
INV_MPU6050_BIT_WAIT_FOR_ES;
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_CTRL, val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* configure i2c master delay */
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, 0);
|
|
if (ret)
|
|
return ret;
|
|
|
|
val = INV_MPU6050_BIT_I2C_SLV0_DLY_EN |
|
|
INV_MPU6050_BIT_I2C_SLV1_DLY_EN |
|
|
INV_MPU6050_BIT_I2C_SLV2_DLY_EN |
|
|
INV_MPU6050_BIT_I2C_SLV3_DLY_EN |
|
|
INV_MPU6050_BIT_DELAY_ES_SHADOW;
|
|
return regmap_write(st->map, INV_MPU6050_REG_I2C_MST_DELAY_CTRL, val);
|
|
}
|
|
|
|
/**
|
|
* inv_mpu_aux_read() - read register function for i2c auxiliary bus
|
|
* @st: driver internal state.
|
|
* @addr: chip i2c Address
|
|
* @reg: chip register address
|
|
* @val: buffer for storing read bytes
|
|
* @size: number of bytes to read
|
|
*
|
|
* Returns 0 on success, a negative error code otherwise.
|
|
*/
|
|
int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
|
|
uint8_t reg, uint8_t *val, size_t size)
|
|
{
|
|
int ret;
|
|
|
|
if (size > 0x0F)
|
|
return -EINVAL;
|
|
|
|
/* setup i2c SLV0 control: i2c addr, register, enable + size */
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
|
|
INV_MPU6050_BIT_I2C_SLV_RNW | addr);
|
|
if (ret)
|
|
return ret;
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
|
|
if (ret)
|
|
return ret;
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
|
|
INV_MPU6050_BIT_SLV_EN | size);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* do i2c xfer, disable i2c slave and check status*/
|
|
ret = inv_mpu_i2c_master_xfer(st);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* read data in registers */
|
|
return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
|
|
val, size);
|
|
}
|
|
|
|
/**
|
|
* inv_mpu_aux_write() - write register function for i2c auxiliary bus
|
|
* @st: driver internal state.
|
|
* @addr: chip i2c Address
|
|
* @reg: chip register address
|
|
* @val: 1 byte value to write
|
|
*
|
|
* Returns 0 on success, a negative error code otherwise.
|
|
*/
|
|
int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
|
|
uint8_t reg, uint8_t val)
|
|
{
|
|
int ret;
|
|
|
|
/* setup i2c SLV0 control: i2c addr, register, value, enable + size */
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), addr);
|
|
if (ret)
|
|
return ret;
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
|
|
if (ret)
|
|
return ret;
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(0), val);
|
|
if (ret)
|
|
return ret;
|
|
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
|
|
INV_MPU6050_BIT_SLV_EN | 1);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* do i2c xfer, disable i2c slave and check status*/
|
|
ret = inv_mpu_i2c_master_xfer(st);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|