diff options
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/Kconfig | 1 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 115 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 6 |
3 files changed, 116 insertions, 6 deletions
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 2d0608ba88d7..48fbc0bc7e2a 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig | |||
@@ -7,6 +7,7 @@ config INV_MPU6050_IIO | |||
7 | depends on I2C && SYSFS | 7 | depends on I2C && SYSFS |
8 | select IIO_BUFFER | 8 | select IIO_BUFFER |
9 | select IIO_TRIGGERED_BUFFER | 9 | select IIO_TRIGGERED_BUFFER |
10 | select I2C_MUX | ||
10 | help | 11 | help |
11 | This driver supports the Invensense MPU6050 devices. | 12 | This driver supports the Invensense MPU6050 devices. |
12 | This driver can also support MPU6500 in MPU6050 compatibility mode | 13 | This driver can also support MPU6500 in MPU6050 compatibility mode |
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index b75519deac1a..6d2c115f39b4 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kfifo.h> | 23 | #include <linux/kfifo.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/iio/iio.h> | 25 | #include <linux/iio/iio.h> |
26 | #include <linux/i2c-mux.h> | ||
26 | #include "inv_mpu_iio.h" | 27 | #include "inv_mpu_iio.h" |
27 | 28 | ||
28 | /* | 29 | /* |
@@ -52,6 +53,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = { | |||
52 | .int_enable = INV_MPU6050_REG_INT_ENABLE, | 53 | .int_enable = INV_MPU6050_REG_INT_ENABLE, |
53 | .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, | 54 | .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, |
54 | .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, | 55 | .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, |
56 | .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG, | ||
55 | }; | 57 | }; |
56 | 58 | ||
57 | static const struct inv_mpu6050_chip_config chip_config_6050 = { | 59 | static const struct inv_mpu6050_chip_config chip_config_6050 = { |
@@ -77,6 +79,83 @@ int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d) | |||
77 | return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d); | 79 | return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d); |
78 | } | 80 | } |
79 | 81 | ||
82 | /* | ||
83 | * The i2c read/write needs to happen in unlocked mode. As the parent | ||
84 | * adapter is common. If we use locked versions, it will fail as | ||
85 | * the mux adapter will lock the parent i2c adapter, while calling | ||
86 | * select/deselect functions. | ||
87 | */ | ||
88 | static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st, | ||
89 | u8 reg, u8 d) | ||
90 | { | ||
91 | int ret; | ||
92 | u8 buf[2]; | ||
93 | struct i2c_msg msg[1] = { | ||
94 | { | ||
95 | .addr = st->client->addr, | ||
96 | .flags = 0, | ||
97 | .len = sizeof(buf), | ||
98 | .buf = buf, | ||
99 | } | ||
100 | }; | ||
101 | |||
102 | buf[0] = reg; | ||
103 | buf[1] = d; | ||
104 | ret = __i2c_transfer(st->client->adapter, msg, 1); | ||
105 | if (ret != 1) | ||
106 | return ret; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv, | ||
112 | u32 chan_id) | ||
113 | { | ||
114 | struct iio_dev *indio_dev = mux_priv; | ||
115 | struct inv_mpu6050_state *st = iio_priv(indio_dev); | ||
116 | int ret = 0; | ||
117 | |||
118 | /* Use the same mutex which was used everywhere to protect power-op */ | ||
119 | mutex_lock(&indio_dev->mlock); | ||
120 | if (!st->powerup_count) { | ||
121 | ret = inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1, | ||
122 | 0); | ||
123 | if (ret) | ||
124 | goto write_error; | ||
125 | |||
126 | msleep(INV_MPU6050_REG_UP_TIME); | ||
127 | } | ||
128 | if (!ret) { | ||
129 | st->powerup_count++; | ||
130 | ret = inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg, | ||
131 | st->client->irq | | ||
132 | INV_MPU6050_BIT_BYPASS_EN); | ||
133 | } | ||
134 | write_error: | ||
135 | mutex_unlock(&indio_dev->mlock); | ||
136 | |||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap, | ||
141 | void *mux_priv, u32 chan_id) | ||
142 | { | ||
143 | struct iio_dev *indio_dev = mux_priv; | ||
144 | struct inv_mpu6050_state *st = iio_priv(indio_dev); | ||
145 | |||
146 | mutex_lock(&indio_dev->mlock); | ||
147 | /* It doesn't really mattter, if any of the calls fails */ | ||
148 | inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg, | ||
149 | st->client->irq); | ||
150 | st->powerup_count--; | ||
151 | if (!st->powerup_count) | ||
152 | inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1, | ||
153 | INV_MPU6050_BIT_SLEEP); | ||
154 | mutex_unlock(&indio_dev->mlock); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
80 | int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) | 159 | int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) |
81 | { | 160 | { |
82 | u8 d, mgmt_1; | 161 | u8 d, mgmt_1; |
@@ -133,13 +212,22 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) | |||
133 | 212 | ||
134 | int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) | 213 | int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) |
135 | { | 214 | { |
136 | int result; | 215 | int result = 0; |
216 | |||
217 | if (power_on) { | ||
218 | /* Already under indio-dev->mlock mutex */ | ||
219 | if (!st->powerup_count) | ||
220 | result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, | ||
221 | 0); | ||
222 | if (!result) | ||
223 | st->powerup_count++; | ||
224 | } else { | ||
225 | st->powerup_count--; | ||
226 | if (!st->powerup_count) | ||
227 | result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, | ||
228 | INV_MPU6050_BIT_SLEEP); | ||
229 | } | ||
137 | 230 | ||
138 | if (power_on) | ||
139 | result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0); | ||
140 | else | ||
141 | result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, | ||
142 | INV_MPU6050_BIT_SLEEP); | ||
143 | if (result) | 231 | if (result) |
144 | return result; | 232 | return result; |
145 | 233 | ||
@@ -673,6 +761,7 @@ static int inv_mpu_probe(struct i2c_client *client, | |||
673 | 761 | ||
674 | st = iio_priv(indio_dev); | 762 | st = iio_priv(indio_dev); |
675 | st->client = client; | 763 | st->client = client; |
764 | st->powerup_count = 0; | ||
676 | pdata = dev_get_platdata(&client->dev); | 765 | pdata = dev_get_platdata(&client->dev); |
677 | if (pdata) | 766 | if (pdata) |
678 | st->plat_data = *pdata; | 767 | st->plat_data = *pdata; |
@@ -720,8 +809,21 @@ static int inv_mpu_probe(struct i2c_client *client, | |||
720 | goto out_remove_trigger; | 809 | goto out_remove_trigger; |
721 | } | 810 | } |
722 | 811 | ||
812 | st->mux_adapter = i2c_add_mux_adapter(client->adapter, | ||
813 | &client->dev, | ||
814 | indio_dev, | ||
815 | 0, 0, 0, | ||
816 | inv_mpu6050_select_bypass, | ||
817 | inv_mpu6050_deselect_bypass); | ||
818 | if (!st->mux_adapter) { | ||
819 | result = -ENODEV; | ||
820 | goto out_unreg_device; | ||
821 | } | ||
822 | |||
723 | return 0; | 823 | return 0; |
724 | 824 | ||
825 | out_unreg_device: | ||
826 | iio_device_unregister(indio_dev); | ||
725 | out_remove_trigger: | 827 | out_remove_trigger: |
726 | inv_mpu6050_remove_trigger(st); | 828 | inv_mpu6050_remove_trigger(st); |
727 | out_unreg_ring: | 829 | out_unreg_ring: |
@@ -734,6 +836,7 @@ static int inv_mpu_remove(struct i2c_client *client) | |||
734 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | 836 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
735 | struct inv_mpu6050_state *st = iio_priv(indio_dev); | 837 | struct inv_mpu6050_state *st = iio_priv(indio_dev); |
736 | 838 | ||
839 | i2c_del_mux_adapter(st->mux_adapter); | ||
737 | iio_device_unregister(indio_dev); | 840 | iio_device_unregister(indio_dev); |
738 | inv_mpu6050_remove_trigger(st); | 841 | inv_mpu6050_remove_trigger(st); |
739 | iio_triggered_buffer_cleanup(indio_dev); | 842 | iio_triggered_buffer_cleanup(indio_dev); |
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index e7799315d4dc..aa837de57079 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | |||
@@ -54,6 +54,7 @@ struct inv_mpu6050_reg_map { | |||
54 | u8 int_enable; | 54 | u8 int_enable; |
55 | u8 pwr_mgmt_1; | 55 | u8 pwr_mgmt_1; |
56 | u8 pwr_mgmt_2; | 56 | u8 pwr_mgmt_2; |
57 | u8 int_pin_cfg; | ||
57 | }; | 58 | }; |
58 | 59 | ||
59 | /*device enum */ | 60 | /*device enum */ |
@@ -119,6 +120,8 @@ struct inv_mpu6050_state { | |||
119 | enum inv_devices chip_type; | 120 | enum inv_devices chip_type; |
120 | spinlock_t time_stamp_lock; | 121 | spinlock_t time_stamp_lock; |
121 | struct i2c_client *client; | 122 | struct i2c_client *client; |
123 | struct i2c_adapter *mux_adapter; | ||
124 | unsigned int powerup_count; | ||
122 | struct inv_mpu6050_platform_data plat_data; | 125 | struct inv_mpu6050_platform_data plat_data; |
123 | DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); | 126 | DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); |
124 | }; | 127 | }; |
@@ -179,6 +182,9 @@ struct inv_mpu6050_state { | |||
179 | /* 6 + 6 round up and plus 8 */ | 182 | /* 6 + 6 round up and plus 8 */ |
180 | #define INV_MPU6050_OUTPUT_DATA_SIZE 24 | 183 | #define INV_MPU6050_OUTPUT_DATA_SIZE 24 |
181 | 184 | ||
185 | #define INV_MPU6050_REG_INT_PIN_CFG 0x37 | ||
186 | #define INV_MPU6050_BIT_BYPASS_EN 0x2 | ||
187 | |||
182 | /* init parameters */ | 188 | /* init parameters */ |
183 | #define INV_MPU6050_INIT_FIFO_RATE 50 | 189 | #define INV_MPU6050_INIT_FIFO_RATE 50 |
184 | #define INV_MPU6050_TIME_STAMP_TOR 5 | 190 | #define INV_MPU6050_TIME_STAMP_TOR 5 |