forked from Minki/linux
iio: imu: st_lsm6dsx: enable sensor-hub support for lsm6dsm
Enabled i2c master controller support for LSM6DSM sensor. Enable ext_sensor0 for lsm6dsm. This series has been tested using LIS2MDL as slave device connected to the i2c controller of the LSM6DSM Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
111b087577
commit
e485e2a2cf
@ -176,11 +176,13 @@ struct st_lsm6dsx_hw_ts_settings {
|
||||
* @pullup_en: i2c controller pull-up register info (addr + mask).
|
||||
* @aux_sens: aux sensor register info (addr + mask).
|
||||
* @wr_once: write_once register info (addr + mask).
|
||||
* @emb_func: embedded function register info (addr + mask).
|
||||
* @num_ext_dev: max number of slave devices.
|
||||
* @shub_out: sensor hub first output register info.
|
||||
* @slv0_addr: slave0 address in secondary page.
|
||||
* @dw_slv0_addr: slave0 write register address in secondary page.
|
||||
* @batch_en: Enable/disable FIFO batching.
|
||||
* @pause: controller pause value.
|
||||
*/
|
||||
struct st_lsm6dsx_shub_settings {
|
||||
struct st_lsm6dsx_reg page_mux;
|
||||
@ -196,6 +198,7 @@ struct st_lsm6dsx_shub_settings {
|
||||
} pullup_en;
|
||||
struct st_lsm6dsx_reg aux_sens;
|
||||
struct st_lsm6dsx_reg wr_once;
|
||||
struct st_lsm6dsx_reg emb_func;
|
||||
u8 num_ext_dev;
|
||||
struct {
|
||||
bool sec_page;
|
||||
@ -204,6 +207,7 @@ struct st_lsm6dsx_shub_settings {
|
||||
u8 slv0_addr;
|
||||
u8 dw_slv0_addr;
|
||||
u8 batch_en;
|
||||
u8 pause;
|
||||
};
|
||||
|
||||
struct st_lsm6dsx_event_settings {
|
||||
|
@ -332,12 +332,13 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
|
||||
*/
|
||||
int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
||||
{
|
||||
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor, *ext_sensor = NULL;
|
||||
int err, acc_sip, gyro_sip, ts_sip, ext_sip, read_len, offset;
|
||||
u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
|
||||
u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
|
||||
int err, acc_sip, gyro_sip, ts_sip, read_len, offset;
|
||||
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
|
||||
u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
|
||||
u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
|
||||
u8 ext_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
|
||||
bool reset_ts = false;
|
||||
__le16 fifo_status;
|
||||
s64 ts = 0;
|
||||
@ -360,6 +361,8 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
||||
|
||||
acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
|
||||
gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
|
||||
if (hw->iio_devs[ST_LSM6DSX_ID_EXT0])
|
||||
ext_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_EXT0]);
|
||||
|
||||
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
|
||||
err = st_lsm6dsx_read_block(hw, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
|
||||
@ -387,12 +390,13 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
||||
* following pattern is repeated every 9 samples:
|
||||
* - Gx, Gy, Gz, Ax, Ay, Az, Ts, Gx, Gy, Gz, Ts, Gx, ..
|
||||
*/
|
||||
ext_sip = ext_sensor ? ext_sensor->sip : 0;
|
||||
gyro_sip = gyro_sensor->sip;
|
||||
acc_sip = acc_sensor->sip;
|
||||
ts_sip = hw->ts_sip;
|
||||
offset = 0;
|
||||
|
||||
while (acc_sip > 0 || gyro_sip > 0) {
|
||||
while (acc_sip > 0 || gyro_sip > 0 || ext_sip > 0) {
|
||||
if (gyro_sip > 0) {
|
||||
memcpy(gyro_buff, &hw->buff[offset],
|
||||
ST_LSM6DSX_SAMPLE_SIZE);
|
||||
@ -403,6 +407,11 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
||||
ST_LSM6DSX_SAMPLE_SIZE);
|
||||
offset += ST_LSM6DSX_SAMPLE_SIZE;
|
||||
}
|
||||
if (ext_sip > 0) {
|
||||
memcpy(ext_buff, &hw->buff[offset],
|
||||
ST_LSM6DSX_SAMPLE_SIZE);
|
||||
offset += ST_LSM6DSX_SAMPLE_SIZE;
|
||||
}
|
||||
|
||||
if (ts_sip-- > 0) {
|
||||
u8 data[ST_LSM6DSX_SAMPLE_SIZE];
|
||||
@ -436,6 +445,10 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
||||
iio_push_to_buffers_with_timestamp(
|
||||
hw->iio_devs[ST_LSM6DSX_ID_ACC],
|
||||
acc_buff, acc_sensor->ts_ref + ts);
|
||||
if (ext_sip-- > 0)
|
||||
iio_push_to_buffers_with_timestamp(
|
||||
hw->iio_devs[ST_LSM6DSX_ID_EXT0],
|
||||
ext_buff, ext_sensor->ts_ref + ts);
|
||||
}
|
||||
}
|
||||
|
||||
@ -628,11 +641,11 @@ int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
|
||||
err = st_lsm6dsx_sensor_set_enable(sensor, enable);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = st_lsm6dsx_update_decimators(hw);
|
||||
if (err < 0)
|
||||
|
@ -656,6 +656,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.addr = 0x08,
|
||||
.mask = GENMASK(5, 3),
|
||||
},
|
||||
[ST_LSM6DSX_ID_EXT0] = {
|
||||
.addr = 0x09,
|
||||
.mask = GENMASK(2, 0),
|
||||
},
|
||||
},
|
||||
.fifo_ops = {
|
||||
.update_fifo = st_lsm6dsx_update_fifo,
|
||||
@ -688,6 +692,39 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
|
||||
.mask = GENMASK(5, 3),
|
||||
},
|
||||
},
|
||||
.shub_settings = {
|
||||
.page_mux = {
|
||||
.addr = 0x01,
|
||||
.mask = BIT(7),
|
||||
},
|
||||
.master_en = {
|
||||
.addr = 0x1a,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
.pullup_en = {
|
||||
.addr = 0x1a,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.aux_sens = {
|
||||
.addr = 0x04,
|
||||
.mask = GENMASK(5, 4),
|
||||
},
|
||||
.wr_once = {
|
||||
.addr = 0x07,
|
||||
.mask = BIT(5),
|
||||
},
|
||||
.emb_func = {
|
||||
.addr = 0x19,
|
||||
.mask = BIT(2),
|
||||
},
|
||||
.num_ext_dev = 1,
|
||||
.shub_out = {
|
||||
.addr = 0x2e,
|
||||
},
|
||||
.slv0_addr = 0x02,
|
||||
.dw_slv0_addr = 0x0e,
|
||||
.pause = 0x7,
|
||||
},
|
||||
.event_settings = {
|
||||
.enable_reg = {
|
||||
.addr = 0x58,
|
||||
@ -1902,6 +1939,16 @@ static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
|
||||
hub_settings->aux_sens.mask, data);
|
||||
|
||||
st_lsm6dsx_set_page(hw, false);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (hub_settings->emb_func.addr) {
|
||||
data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->emb_func.mask);
|
||||
err = regmap_update_bits(hw->regmap,
|
||||
hub_settings->emb_func.addr,
|
||||
hub_settings->emb_func.mask, data);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -221,16 +221,21 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr,
|
||||
u8 *data, int len)
|
||||
{
|
||||
const struct st_lsm6dsx_shub_settings *hub_settings;
|
||||
u8 config[3], slv_addr, slv_config = 0;
|
||||
struct st_lsm6dsx_hw *hw = sensor->hw;
|
||||
u8 config[3], slv_addr;
|
||||
const struct st_lsm6dsx_reg *aux_sens;
|
||||
int err;
|
||||
|
||||
hub_settings = &hw->settings->shub_settings;
|
||||
slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
|
||||
aux_sens = &hw->settings->shub_settings.aux_sens;
|
||||
/* do not overwrite aux_sens */
|
||||
if (slv_addr + 2 == aux_sens->addr)
|
||||
slv_config = ST_LSM6DSX_SHIFT_VAL(3, aux_sens->mask);
|
||||
|
||||
config[0] = (sensor->ext_info.addr << 1) | 1;
|
||||
config[1] = addr;
|
||||
config[2] = len & ST_LS6DSX_READ_OP_MASK;
|
||||
config[2] = (len & ST_LS6DSX_READ_OP_MASK) | slv_config;
|
||||
|
||||
err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
|
||||
sizeof(config));
|
||||
@ -248,7 +253,9 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr,
|
||||
|
||||
st_lsm6dsx_shub_master_enable(sensor, false);
|
||||
|
||||
memset(config, 0, sizeof(config));
|
||||
config[0] = hub_settings->pause;
|
||||
config[1] = 0;
|
||||
config[2] = slv_config;
|
||||
return st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
|
||||
sizeof(config));
|
||||
}
|
||||
@ -305,7 +312,8 @@ st_lsm6dsx_shub_write(struct st_lsm6dsx_sensor *sensor, u8 addr,
|
||||
st_lsm6dsx_shub_master_enable(sensor, false);
|
||||
}
|
||||
|
||||
memset(config, 0, sizeof(config));
|
||||
config[0] = hub_settings->pause;
|
||||
config[1] = 0;
|
||||
return st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config));
|
||||
}
|
||||
|
||||
@ -697,14 +705,19 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
|
||||
const struct st_lsm6dsx_ext_dev_settings *settings)
|
||||
{
|
||||
const struct st_lsm6dsx_shub_settings *hub_settings;
|
||||
u8 config[3], data, slv_addr, slv_config = 0;
|
||||
const struct st_lsm6dsx_reg *aux_sens;
|
||||
struct st_lsm6dsx_sensor *sensor;
|
||||
u8 config[3], data, slv_addr;
|
||||
bool found = false;
|
||||
int i, err;
|
||||
|
||||
hub_settings = &hw->settings->shub_settings;
|
||||
slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
|
||||
sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
|
||||
hub_settings = &hw->settings->shub_settings;
|
||||
aux_sens = &hw->settings->shub_settings.aux_sens;
|
||||
slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
|
||||
/* do not overwrite aux_sens */
|
||||
if (slv_addr + 2 == aux_sens->addr)
|
||||
slv_config = ST_LSM6DSX_SHIFT_VAL(3, aux_sens->mask);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(settings->i2c_addr); i++) {
|
||||
if (!settings->i2c_addr[i])
|
||||
@ -713,7 +726,7 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
|
||||
/* read wai slave register */
|
||||
config[0] = (settings->i2c_addr[i] << 1) | 0x1;
|
||||
config[1] = settings->wai.addr;
|
||||
config[2] = 0x1;
|
||||
config[2] = 0x1 | slv_config;
|
||||
|
||||
err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
|
||||
sizeof(config));
|
||||
@ -742,7 +755,9 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
|
||||
}
|
||||
|
||||
/* reset SLV0 channel */
|
||||
memset(config, 0, sizeof(config));
|
||||
config[0] = hub_settings->pause;
|
||||
config[1] = 0;
|
||||
config[2] = slv_config;
|
||||
err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
|
||||
sizeof(config));
|
||||
if (err < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user