1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019 TDK-InvenSense, Inc. 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/device.h> 8 #include <linux/regmap.h> 9 #include <linux/delay.h> 10 11 #include "inv_mpu_aux.h" 12 #include "inv_mpu_iio.h" 13 14 /* 15 * i2c master auxiliary bus transfer function. 16 * Requires the i2c operations to be correctly setup before. 17 * Disables SLV0 and checks for NACK status internally. 18 * Assumes that only SLV0 is used for transfers. 19 */ 20 static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st) 21 { 22 /* use 50hz frequency for xfer */ 23 const unsigned int freq = 50; 24 const unsigned int period_ms = 1000 / freq; 25 uint8_t d; 26 unsigned int user_ctrl; 27 int ret; 28 unsigned int status; 29 30 /* set sample rate */ 31 d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq); 32 ret = regmap_write(st->map, st->reg->sample_rate_div, d); 33 if (ret) 34 return ret; 35 36 /* start i2c master */ 37 user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN; 38 ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); 39 if (ret) 40 goto error_restore_rate; 41 42 /* wait for xfer: 1 period + half-period margin */ 43 msleep(period_ms + period_ms / 2); 44 45 /* stop i2c master */ 46 user_ctrl = st->chip_config.user_ctrl; 47 ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); 48 if (ret) 49 goto error_stop_i2c; 50 51 /* restore sample rate */ 52 d = st->chip_config.divider; 53 ret = regmap_write(st->map, st->reg->sample_rate_div, d); 54 if (ret) 55 goto error_restore_rate; 56 57 /* disable i2c slave */ 58 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); 59 if (ret) 60 goto error_disable_i2c; 61 62 /* check i2c status */ 63 ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status); 64 if (ret) 65 return ret; 66 67 if (status & INV_MPU6050_BIT_I2C_SLV0_NACK) 68 return -EIO; 69 70 return 0; 71 72 error_stop_i2c: 73 regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl); 74 error_restore_rate: 75 regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider); 76 error_disable_i2c: 77 regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); 78 return ret; 79 } 80 81 /** 82 * inv_mpu_aux_init() - init i2c auxiliary bus 83 * @st: driver internal state 84 * 85 * Returns 0 on success, a negative error code otherwise. 86 */ 87 int inv_mpu_aux_init(const struct inv_mpu6050_state *st) 88 { 89 unsigned int val; 90 int ret; 91 92 /* 93 * Code based on the vendor Linux kernel v3.0, 94 * the exact meaning is unknown. 95 */ 96 if (st->chip_type == INV_MPU9150) { 97 unsigned int mask = BIT(7); 98 99 val = st->level_shifter ? mask : 0; 100 ret = regmap_update_bits(st->map, 0x1, mask, val); 101 if (ret) 102 return ret; 103 } 104 105 /* configure i2c master */ 106 val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ | 107 INV_MPU6050_BIT_WAIT_FOR_ES; 108 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_CTRL, val); 109 if (ret) 110 return ret; 111 112 /* configure i2c master delay */ 113 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, 0); 114 if (ret) 115 return ret; 116 117 val = INV_MPU6050_BIT_I2C_SLV0_DLY_EN | 118 INV_MPU6050_BIT_I2C_SLV1_DLY_EN | 119 INV_MPU6050_BIT_I2C_SLV2_DLY_EN | 120 INV_MPU6050_BIT_I2C_SLV3_DLY_EN | 121 INV_MPU6050_BIT_DELAY_ES_SHADOW; 122 return regmap_write(st->map, INV_MPU6050_REG_I2C_MST_DELAY_CTRL, val); 123 } 124 125 /** 126 * inv_mpu_aux_read() - read register function for i2c auxiliary bus 127 * @st: driver internal state. 128 * @addr: chip i2c Address 129 * @reg: chip register address 130 * @val: buffer for storing read bytes 131 * @size: number of bytes to read 132 * 133 * Returns 0 on success, a negative error code otherwise. 134 */ 135 int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr, 136 uint8_t reg, uint8_t *val, size_t size) 137 { 138 int ret; 139 140 if (size > 0x0F) 141 return -EINVAL; 142 143 /* setup i2c SLV0 control: i2c addr, register, enable + size */ 144 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), 145 INV_MPU6050_BIT_I2C_SLV_RNW | addr); 146 if (ret) 147 return ret; 148 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg); 149 if (ret) 150 return ret; 151 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 152 INV_MPU6050_BIT_SLV_EN | size); 153 if (ret) 154 return ret; 155 156 /* do i2c xfer, disable i2c slave and check status*/ 157 ret = inv_mpu_i2c_master_xfer(st); 158 if (ret) 159 return ret; 160 161 /* read data in registers */ 162 return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA, 163 val, size); 164 } 165 166 /** 167 * inv_mpu_aux_write() - write register function for i2c auxiliary bus 168 * @st: driver internal state. 169 * @addr: chip i2c Address 170 * @reg: chip register address 171 * @val: 1 byte value to write 172 * 173 * Returns 0 on success, a negative error code otherwise. 174 */ 175 int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr, 176 uint8_t reg, uint8_t val) 177 { 178 int ret; 179 180 /* setup i2c SLV0 control: i2c addr, register, value, enable + size */ 181 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), addr); 182 if (ret) 183 return ret; 184 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg); 185 if (ret) 186 return ret; 187 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(0), val); 188 if (ret) 189 return ret; 190 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 191 INV_MPU6050_BIT_SLV_EN | 1); 192 if (ret) 193 return ret; 194 195 /* do i2c xfer, disable i2c slave and check status*/ 196 ret = inv_mpu_i2c_master_xfer(st); 197 if (ret) 198 return ret; 199 200 return 0; 201 } 202