summary refs log tree commit diff
path: root/drivers/iio/imu/inv_mpu6050
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-04-26 15:07:23 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-04-26 15:07:23 -0700
commit5a45e01d414636e144ab28b62089d0eb97f43ec2 (patch)
tree814ddaaceba0e759988c795a42728e91819af2c1 /drivers/iio/imu/inv_mpu6050
parent4145ba76b1f7f3296cc673c299084145e1267029 (diff)
parentfbced0e9465152d628ece5fd0d11de4e7a1f5ce5 (diff)
downloadlinux-5a45e01d414636e144ab28b62089d0eb97f43ec2.tar.gz
Merge tag 'iio-for-4.7b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-testing
Jonathan writes:

2nd set of new device support, features and cleanup for IIO in the 4.7 cycle.

Bit of a bumper set for new drivers but plenty of other stuff here as well!

New device support
* ad5592R ADC/DAC
  - new driver supporting ad5592r and ad5593r combined ADC/DAC and gpio chips.
* Aosong am2315 relative humidity
  - new driver with triggered buffer support in follow up patch.
* bmi160 imu
  - new driver
* bmp280
  - bmp180 support - note there is support in the misc/bmp085 driver. Intent
    is to remove that driver long term.
* invensense mpu6050
  - cleanup leading to explicit support of mpu9150 with a good few cleanups
    along the way.
* Hope RF hp03 pressure and temperature sensor.
  - new driver
* maxim DS1803 potentiometer
  - new driver
* maxim max44000 light and proximity sensor
  - new driver built in a series of steps to support pretty much everything.
* ROHM BH1780 light sensor
  - new driver. There is an existing driver in misc that this is pretty much
    intended to replace.  The discussion on whether to support the non standard
    interface of that driver is some way is continuing.
* st-gyro
  - lsm9ds0-gyro.  The accel/magn side of this will take a while longer as
    extensions to the st library are needed for cases where two types of sensor
    share a single i2c address.
* ti-adc081c
  - support the adc101c and adc121c
* Vishay VEML6070 UV sensor
  - new driver.

New features
* core
  - devm_ APIs for channel_get and channel_get_all.  The first user of these
    is the generic ADC based thermal driver.  As it is going through the
    thermal tree these will be picked up as a patch to that next cycle as that
    is how the author preferred to do it.
  - mounting matrix support.  This new core support allows devices to provide
    to userspace (typically from the device tree) allowing compensation for how
    the sensor is mounted on the device.  First examples are on UAVs but it
    has a more mundane use on typical phone where the chip may be on the front
    or the back of the circuit board and soldered at any angle. Includes
    support for this ABI in ak8975 (which has an older interface, now
    deprecated) and mpu6050.
* tools
  - add a -a option to enable all available channels in generic_buffer sample.
    Makes it somewhat easier to use.
* adis library and drivers
  - support manual self test flag clearing.  This has technically been broken
    for a very long time - result is an offset on readings as the applied field
    is on all the time.
* ak8975
  - triggered buffer support
* bmc150
  - spi support (including splitting the driver into core and i2c parts)
* bmp280
  - oversampling support.
* dht11
  - improved logging - useful to debug timing issues on this quirky device.
* st-sensors
  - read each channel invidivually as not all support the optimization of
  reading in bulk.  This is technically a fix, but will need to be backported
  if desired.
  - support open drain and shared interrupts.
* ti-adc081c
  - triggered buffer support.

Cleanups
* inkern
  - white space fix.
* ad7606
  - use the iio_device_claim_direct_mode call rather than open coding equiv.
* ad799x
  - white space fix.
* ad9523
  - unsigned -> unsigned int
* apds9660
  - brace location tidying up.
  - silence an uninitialized variable warning.
* ak8975
  - else and brace on same line fix.
* at91_adc
  - white space fixes.
* bmc150
  - use regmap stored copy of the device pointer rather than having an
    additional copy.
* bmg160
  - use regmap stored copy of the device pointer rather than having an
    additional copy.
* hid-sensors
  - white space fixes.
* mcp3422
  - white space fix.
* mma7455
  - use regmap to retrieve the device struct rather than carrying another copy
    in the private data.
* ms_sensors
  - white space fix.
* mxs-lradc
  - move current bindings out of staging - some will be shortly deprecated but
    the reality is that we have device trees out there using them so they will
    need to be supported for some time.  They accidentally got left behind
    when the driver graduated from staging.
  - white space cleanup.
  - set INPUT_PROP_DIRECT.
  - move ts config into a better function.
  - move the STMP reset out of the ADC init.
* vf610_adc
  - case label indenting fix.
Diffstat (limited to 'drivers/iio/imu/inv_mpu6050')
-rw-r--r--drivers/iio/imu/inv_mpu6050/Kconfig10
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c73
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c3
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h16
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c20
5 files changed, 102 insertions, 20 deletions
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
index 847455a2d6bb..f756feecfa4c 100644
--- a/drivers/iio/imu/inv_mpu6050/Kconfig
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -13,10 +13,8 @@ config INV_MPU6050_I2C
 	select INV_MPU6050_IIO
 	select REGMAP_I2C
 	help
-	  This driver supports the Invensense MPU6050 devices.
-	  This driver can also support MPU6500 in MPU6050 compatibility mode
-	  and also in MPU6500 mode with some limitations.
-	  It is a gyroscope/accelerometer combo device.
+	  This driver supports the Invensense MPU6050/6500/9150 motion tracking
+	  devices over I2C.
 	  This driver can be built as a module. The module will be called
 	  inv-mpu6050-i2c.
 
@@ -26,7 +24,7 @@ config INV_MPU6050_SPI
 	select INV_MPU6050_IIO
 	select REGMAP_SPI
 	help
-	  This driver supports the Invensense MPU6050 devices.
-	  It is a gyroscope/accelerometer combo device.
+	  This driver supports the Invensense MPU6000/6500/9150 motion tracking
+	  devices over SPI.
 	  This driver can be built as a module. The module will be called
 	  inv-mpu6050-spi.
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index d192953e9a38..b269b375ca34 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -88,16 +88,29 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
 	.accl_fs = INV_MPU6050_FS_02G,
 };
 
+/* Indexed by enum inv_devices */
 static const struct inv_mpu6050_hw hw_info[] = {
 	{
-		.num_reg = 117,
+		.whoami = INV_MPU6050_WHOAMI_VALUE,
+		.name = "MPU6050",
+		.reg = &reg_set_6050,
+		.config = &chip_config_6050,
+	},
+	{
+		.whoami = INV_MPU6500_WHOAMI_VALUE,
 		.name = "MPU6500",
 		.reg = &reg_set_6500,
 		.config = &chip_config_6050,
 	},
 	{
-		.num_reg = 117,
-		.name = "MPU6050",
+		.whoami = INV_MPU6000_WHOAMI_VALUE,
+		.name = "MPU6000",
+		.reg = &reg_set_6050,
+		.config = &chip_config_6050,
+	},
+	{
+		.whoami = INV_MPU9150_WHOAMI_VALUE,
+		.name = "MPU9150",
 		.reg = &reg_set_6050,
 		.config = &chip_config_6050,
 	},
@@ -600,6 +613,10 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr,
 /**
  * inv_attr_show() - calling this function will show current
  *                    parameters.
+ *
+ * Deprecated in favor of IIO mounting matrix API.
+ *
+ * See inv_get_mount_matrix()
  */
 static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
@@ -644,6 +661,18 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
 	return 0;
 }
 
+static const struct iio_mount_matrix *
+inv_get_mount_matrix(const struct iio_dev *indio_dev,
+		     const struct iio_chan_spec *chan)
+{
+	return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation;
+}
+
+static const struct iio_chan_spec_ext_info inv_ext_info[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix),
+	{ },
+};
+
 #define INV_MPU6050_CHAN(_type, _channel2, _index)                    \
 	{                                                             \
 		.type = _type,                                        \
@@ -660,6 +689,7 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
 				.shift = 0,                           \
 				.endianness = IIO_BE,                 \
 			     },                                       \
+		.ext_info = inv_ext_info,                             \
 	}
 
 static const struct iio_chan_spec inv_mpu_channels[] = {
@@ -692,14 +722,16 @@ static IIO_CONST_ATTR(in_accel_scale_available,
 					  "0.000598 0.001196 0.002392 0.004785");
 static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
 	inv_mpu6050_fifo_rate_store);
+
+/* Deprecated: kept for userspace backward compatibility. */
 static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL,
 	ATTR_GYRO_MATRIX);
 static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL,
 	ATTR_ACCL_MATRIX);
 
 static struct attribute *inv_attributes[] = {
-	&iio_dev_attr_in_gyro_matrix.dev_attr.attr,
-	&iio_dev_attr_in_accel_matrix.dev_attr.attr,
+	&iio_dev_attr_in_gyro_matrix.dev_attr.attr,  /* deprecated */
+	&iio_dev_attr_in_accel_matrix.dev_attr.attr, /* deprecated */
 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
 	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
@@ -726,6 +758,7 @@ static const struct iio_info mpu_info = {
 static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
 {
 	int result;
+	unsigned int regval;
 
 	st->hw  = &hw_info[st->chip_type];
 	st->reg = hw_info[st->chip_type].reg;
@@ -736,6 +769,17 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
 	if (result)
 		return result;
 	msleep(INV_MPU6050_POWER_UP_TIME);
+
+	/* check chip self-identification */
+	result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, &regval);
+	if (result)
+		return result;
+	if (regval != st->hw->whoami) {
+		dev_warn(regmap_get_device(st->map),
+				"whoami mismatch got %#02x expected %#02hhx for %s\n",
+				regval, st->hw->whoami, st->hw->name);
+	}
+
 	/*
 	 * toggle power state. After reset, the sleep bit could be on
 	 * or off depending on the OTP settings. Toggling power would
@@ -774,14 +818,31 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
 	if (!indio_dev)
 		return -ENOMEM;
 
+	BUILD_BUG_ON(ARRAY_SIZE(hw_info) != INV_NUM_PARTS);
+	if (chip_type < 0 || chip_type >= INV_NUM_PARTS) {
+		dev_err(dev, "Bad invensense chip_type=%d name=%s\n",
+				chip_type, name);
+		return -ENODEV;
+	}
 	st = iio_priv(indio_dev);
 	st->chip_type = chip_type;
 	st->powerup_count = 0;
 	st->irq = irq;
 	st->map = regmap;
+
 	pdata = dev_get_platdata(dev);
-	if (pdata)
+	if (!pdata) {
+		result = of_iio_read_mount_matrix(dev, "mount-matrix",
+						  &st->orientation);
+		if (result) {
+			dev_err(dev, "Failed to retrieve mounting matrix %d\n",
+				result);
+			return result;
+		}
+	} else {
 		st->plat_data = *pdata;
+	}
+
 	/* power is turned on inside check chip type*/
 	result = inv_check_and_setup_chip(st);
 	if (result)
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index 5ee4e0dc093e..1a424a6561de 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -202,13 +202,14 @@ static int inv_mpu_remove(struct i2c_client *client)
 static const struct i2c_device_id inv_mpu_id[] = {
 	{"mpu6050", INV_MPU6050},
 	{"mpu6500", INV_MPU6500},
+	{"mpu9150", INV_MPU9150},
 	{}
 };
 
 MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
 
 static const struct acpi_device_id inv_acpi_match[] = {
-	{"INVN6500", 0},
+	{"INVN6500", INV_MPU6500},
 	{ },
 };
 
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index e302a49703bf..47ca25b94a73 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -68,6 +68,7 @@ enum inv_devices {
 	INV_MPU6050,
 	INV_MPU6500,
 	INV_MPU6000,
+	INV_MPU9150,
 	INV_NUM_PARTS
 };
 
@@ -93,13 +94,13 @@ struct inv_mpu6050_chip_config {
 
 /**
  *  struct inv_mpu6050_hw - Other important hardware information.
- *  @num_reg:	Number of registers on device.
+ *  @whoami:	Self identification byte from WHO_AM_I register
  *  @name:      name of the chip.
  *  @reg:   register map of the chip.
  *  @config:    configuration of the chip.
  */
 struct inv_mpu6050_hw {
-	u8 num_reg;
+	u8 whoami;
 	u8 *name;
 	const struct inv_mpu6050_reg_map *reg;
 	const struct inv_mpu6050_chip_config *config;
@@ -114,7 +115,8 @@ struct inv_mpu6050_hw {
  *  @hw:		Other hardware-specific information.
  *  @chip_type:		chip type.
  *  @time_stamp_lock:	spin lock to time stamp.
- *  @plat_data:		platform data.
+ *  @plat_data:		platform data (deprecated in favor of @orientation).
+ *  @orientation:	sensor chip orientation relative to main hardware.
  *  @timestamps:        kfifo queue to store time stamp.
  *  @map		regmap pointer.
  *  @irq		interrupt number.
@@ -131,6 +133,7 @@ struct inv_mpu6050_state {
 	struct i2c_client *mux_client;
 	unsigned int powerup_count;
 	struct inv_mpu6050_platform_data plat_data;
+	struct iio_mount_matrix orientation;
 	DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
 	struct regmap *map;
 	int irq;
@@ -215,6 +218,13 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_MIN_FIFO_RATE            4
 #define INV_MPU6050_ONE_K_HZ                 1000
 
+#define INV_MPU6050_REG_WHOAMI			117
+
+#define INV_MPU6000_WHOAMI_VALUE		0x68
+#define INV_MPU6050_WHOAMI_VALUE		0x68
+#define INV_MPU6500_WHOAMI_VALUE		0x70
+#define INV_MPU9150_WHOAMI_VALUE		0x68
+
 /* scan element definition */
 enum inv_mpu6050_scan {
 	INV_MPU6050_SCAN_ACCL_X,
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
index 7bcb8d839f05..190a4a51c830 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
@@ -44,9 +44,19 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
 static int inv_mpu_probe(struct spi_device *spi)
 {
 	struct regmap *regmap;
-	const struct spi_device_id *id = spi_get_device_id(spi);
-	const char *name = id ? id->name : NULL;
-	const int chip_type = id ? id->driver_data : 0;
+	const struct spi_device_id *spi_id;
+	const struct acpi_device_id *acpi_id;
+	const char *name = NULL;
+	enum inv_devices chip_type;
+
+	if ((spi_id = spi_get_device_id(spi))) {
+		chip_type = (enum inv_devices)spi_id->driver_data;
+		name = spi_id->name;
+	} else if ((acpi_id = acpi_match_device(spi->dev.driver->acpi_match_table, &spi->dev))) {
+		chip_type = (enum inv_devices)acpi_id->driver_data;
+	} else {
+		return -ENODEV;
+	}
 
 	regmap = devm_regmap_init_spi(spi, &inv_mpu_regmap_config);
 	if (IS_ERR(regmap)) {
@@ -70,13 +80,15 @@ static int inv_mpu_remove(struct spi_device *spi)
  */
 static const struct spi_device_id inv_mpu_id[] = {
 	{"mpu6000", INV_MPU6000},
+	{"mpu6500", INV_MPU6500},
+	{"mpu9150", INV_MPU9150},
 	{}
 };
 
 MODULE_DEVICE_TABLE(spi, inv_mpu_id);
 
 static const struct acpi_device_id inv_acpi_match[] = {
-	{"INVN6000", 0},
+	{"INVN6000", INV_MPU6000},
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, inv_acpi_match);