summaryrefslogtreecommitdiffstats
path: root/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-14 11:10:38 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-14 11:10:38 -0800
commitd9750a2f9eea15377924dac96dd129af7edcbede (patch)
tree4582584dfb0f22f1b9f5727bf60abb80a2fbec37 /drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
parent2cdb82c7ffd27f3f574e0bb80e97024a4f65c26b (diff)
parentecc24e72f43735cceab06f4e69aa6ce075a3ae46 (diff)
downloadtalos-obmc-linux-d9750a2f9eea15377924dac96dd129af7edcbede.tar.gz
talos-obmc-linux-d9750a2f9eea15377924dac96dd129af7edcbede.zip
Merge tag 'iio-for-4.6b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes: 2nd round of new IIO device support, features and cleanups for the 4.6 cycle. New Device Support * Apex stx104 DAC - new driver for this PC104 board. Right now DAC support only. * ADI ad5064 - Add support for ad5625, ad5627, ad5645, ad5665, ad5667 DACs. - Add support for Linear Technology ltc2606, ltc2607, ltc2609, ltc2616, ltc2617, ltc2619, ltc2626, ltc2627 and ltc2629. * ADI ad7192 - add support for the ad7193 * Invensense mpu6050 - substantial rework of driver to use regmap allowing SPI support extending the now split driver to cover the MPU6000. * TI adc0832 - new driver supporting ADC0831, ADC0832, ADC0834 and ADC0838 ADCs. * TI ads1015 - new driver, note that there is an existing hwmon driver. The long term intention is to probably remove the hwmon driver but for now we just have guards in place to ensure this driver is not built if that one is enabled. * TI afe4403 - new driver for this heart rate monitor / pulse oximeter front end chip. * TI afe4404 - new driver for this heart rate monitor / pulse oximeter front end chip. Staging Graduations * mxs-lradc - A combined general purpose and touch screen (input) device driver. Originally held in staging to allow reworking into and MFD but as that wasn't happening and isn't an absolute requirement we are moving it out of staging. Driver new features * ms5611 - triggered buffer support - IIO_CHAN_INFO_SCALE to aid the triggered buffer support. Driver cleanups / reworks / fixes * ad5064 - Use an enum for the register map layout to allow support of additional chips (precursor to the new support listed above). - Structural driver changes to allow support of the slightly different handling for the ltc parts above. * ad5933 - drop an exceptional & unnecessary for a function pointer. * ad7606 - Cleanup the repeated copies of pm ops. - consolidate the various channels specs via a sport of rearranging so only one version is needed. * atlas ph sensor - add select IRQ_WORK * hmc8543 (soon to move out of staging) - Comment style fixes - functionality of suspend and resume was swapped. * spear-adc - use devm_clk_dev instead of managing the clk lifetime by hand. Core * Use new dmaengine_terminate_sync call to avoid a theoretical race. * Fix docs for mlock in struct iio_dev as it is correctly taken in some drivers (docs used to say for core only). * Add a helper function for calculating the scan index storage size within the core cutting out some cut and paste versions of the same code.
Diffstat (limited to 'drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c')
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
new file mode 100644
index 000000000000..af400dd892a9
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -0,0 +1,206 @@
+/*
+* Copyright (C) 2012 Invensense, Inc.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include "inv_mpu_iio.h"
+
+static const struct regmap_config inv_mpu_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+/*
+ * The i2c read/write needs to happen in unlocked mode. As the parent
+ * adapter is common. If we use locked versions, it will fail as
+ * the mux adapter will lock the parent i2c adapter, while calling
+ * select/deselect functions.
+ */
+static int inv_mpu6050_write_reg_unlocked(struct i2c_client *client,
+ u8 reg, u8 d)
+{
+ int ret;
+ u8 buf[2] = {reg, d};
+ struct i2c_msg msg[1] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = __i2c_transfer(client->adapter, msg, 1);
+ if (ret != 1)
+ return ret;
+
+ return 0;
+}
+
+static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
+ u32 chan_id)
+{
+ struct i2c_client *client = mux_priv;
+ struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ int ret = 0;
+
+ /* Use the same mutex which was used everywhere to protect power-op */
+ mutex_lock(&indio_dev->mlock);
+ if (!st->powerup_count) {
+ ret = inv_mpu6050_write_reg_unlocked(client,
+ st->reg->pwr_mgmt_1, 0);
+ if (ret)
+ goto write_error;
+
+ msleep(INV_MPU6050_REG_UP_TIME);
+ }
+ if (!ret) {
+ st->powerup_count++;
+ ret = inv_mpu6050_write_reg_unlocked(client,
+ st->reg->int_pin_cfg,
+ INV_MPU6050_INT_PIN_CFG |
+ INV_MPU6050_BIT_BYPASS_EN);
+ }
+write_error:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
+ void *mux_priv, u32 chan_id)
+{
+ struct i2c_client *client = mux_priv;
+ struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ mutex_lock(&indio_dev->mlock);
+ /* It doesn't really mattter, if any of the calls fails */
+ inv_mpu6050_write_reg_unlocked(client, st->reg->int_pin_cfg,
+ INV_MPU6050_INT_PIN_CFG);
+ st->powerup_count--;
+ if (!st->powerup_count)
+ inv_mpu6050_write_reg_unlocked(client, st->reg->pwr_mgmt_1,
+ INV_MPU6050_BIT_SLEEP);
+ mutex_unlock(&indio_dev->mlock);
+
+ return 0;
+}
+
+/**
+ * inv_mpu_probe() - probe function.
+ * @client: i2c client.
+ * @id: i2c device id.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int inv_mpu_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct inv_mpu6050_state *st;
+ int result;
+ const char *name = id ? id->name : NULL;
+ struct regmap *regmap;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -ENOSYS;
+
+ regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to register i2c regmap %d\n",
+ (int)PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ result = inv_mpu_core_probe(regmap, client->irq, name, NULL);
+ if (result < 0)
+ return result;
+
+ st = iio_priv(dev_get_drvdata(&client->dev));
+ st->mux_adapter = i2c_add_mux_adapter(client->adapter,
+ &client->dev,
+ client,
+ 0, 0, 0,
+ inv_mpu6050_select_bypass,
+ inv_mpu6050_deselect_bypass);
+ if (!st->mux_adapter) {
+ result = -ENODEV;
+ goto out_unreg_device;
+ }
+
+ result = inv_mpu_acpi_create_mux_client(client);
+ if (result)
+ goto out_del_mux;
+
+ return 0;
+
+out_del_mux:
+ i2c_del_mux_adapter(st->mux_adapter);
+out_unreg_device:
+ inv_mpu_core_remove(&client->dev);
+ return result;
+}
+
+static int inv_mpu_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ inv_mpu_acpi_delete_mux_client(client);
+ i2c_del_mux_adapter(st->mux_adapter);
+
+ return inv_mpu_core_remove(&client->dev);
+}
+
+/*
+ * device id table is used to identify what device can be
+ * supported by this driver
+ */
+static const struct i2c_device_id inv_mpu_id[] = {
+ {"mpu6050", INV_MPU6050},
+ {"mpu6500", INV_MPU6500},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
+
+static const struct acpi_device_id inv_acpi_match[] = {
+ {"INVN6500", 0},
+ { },
+};
+
+MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
+
+static struct i2c_driver inv_mpu_driver = {
+ .probe = inv_mpu_probe,
+ .remove = inv_mpu_remove,
+ .id_table = inv_mpu_id,
+ .driver = {
+ .acpi_match_table = ACPI_PTR(inv_acpi_match),
+ .name = "inv-mpu6050-i2c",
+ .pm = &inv_mpu_pmops,
+ },
+};
+
+module_i2c_driver(inv_mpu_driver);
+
+MODULE_AUTHOR("Invensense Corporation");
+MODULE_DESCRIPTION("Invensense device MPU6050 driver");
+MODULE_LICENSE("GPL");
OpenPOWER on IntegriCloud