summaryrefslogtreecommitdiffstats
path: root/drivers/iio/imu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/imu')
-rw-r--r--drivers/iio/imu/inv_mpu6050/Makefile2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c211
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c7
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h3
-rw-r--r--drivers/iio/imu/kmx61.c70
5 files changed, 249 insertions, 44 deletions
diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
index 3a677c7..f566f6a 100644
--- a/drivers/iio/imu/inv_mpu6050/Makefile
+++ b/drivers/iio/imu/inv_mpu6050/Makefile
@@ -3,4 +3,4 @@
#
obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
-inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
+inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o inv_mpu_acpi.o
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
new file mode 100644
index 0000000..1c982a5
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
@@ -0,0 +1,211 @@
+/*
+ * inv_mpu_acpi: ACPI processing for creating client devices
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#ifdef CONFIG_ACPI
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include "inv_mpu_iio.h"
+
+enum inv_mpu_product_name {
+ INV_MPU_NOT_MATCHED,
+ INV_MPU_ASUS_T100TA,
+};
+
+static enum inv_mpu_product_name matched_product_name;
+
+static int __init asus_t100_matched(const struct dmi_system_id *d)
+{
+ matched_product_name = INV_MPU_ASUS_T100TA;
+
+ return 0;
+}
+
+static const struct dmi_system_id inv_mpu_dev_list[] = {
+ {
+ .callback = asus_t100_matched,
+ .ident = "Asus Transformer Book T100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
+ },
+ },
+ /* Add more matching tables here..*/
+ {}
+};
+
+static int asus_acpi_get_sensor_info(struct acpi_device *adev,
+ struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ int i;
+ acpi_status status;
+ union acpi_object *cpm;
+
+ status = acpi_evaluate_object(adev->handle, "CNF0", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ cpm = buffer.pointer;
+ for (i = 0; i < cpm->package.count; ++i) {
+ union acpi_object *elem;
+ int j;
+
+ elem = &(cpm->package.elements[i]);
+ for (j = 0; j < elem->package.count; ++j) {
+ union acpi_object *sub_elem;
+
+ sub_elem = &(elem->package.elements[j]);
+ if (sub_elem->type == ACPI_TYPE_STRING)
+ strlcpy(info->type, sub_elem->string.pointer,
+ sizeof(info->type));
+ else if (sub_elem->type == ACPI_TYPE_INTEGER) {
+ if (sub_elem->integer.value != client->addr) {
+ info->addr = sub_elem->integer.value;
+ break; /* Not a MPU6500 primary */
+ }
+ }
+ }
+ }
+
+ kfree(buffer.pointer);
+
+ return cpm->package.count;
+}
+
+static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data)
+{
+ u32 *addr = data;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
+ struct acpi_resource_i2c_serialbus *sb;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+ if (*addr)
+ *addr |= (sb->slave_address << 16);
+ else
+ *addr = sb->slave_address;
+ }
+ }
+
+ /* Tell the ACPI core that we already copied this address */
+ return 1;
+}
+
+static int inv_mpu_process_acpi_config(struct i2c_client *client,
+ unsigned short *primary_addr,
+ unsigned short *secondary_addr)
+{
+ const struct acpi_device_id *id;
+ struct acpi_device *adev;
+ u32 i2c_addr = 0;
+ LIST_HEAD(resources);
+ int ret;
+
+ id = acpi_match_device(client->dev.driver->acpi_match_table,
+ &client->dev);
+ if (!id)
+ return -ENODEV;
+
+ adev = ACPI_COMPANION(&client->dev);
+ if (!adev)
+ return -ENODEV;
+
+ ret = acpi_dev_get_resources(adev, &resources,
+ acpi_i2c_check_resource, &i2c_addr);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resources);
+ *primary_addr = i2c_addr & 0x0000ffff;
+ *secondary_addr = (i2c_addr & 0xffff0000) >> 16;
+
+ return 0;
+}
+
+int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
+{
+
+ st->mux_client = NULL;
+ if (ACPI_HANDLE(&st->client->dev)) {
+ struct i2c_board_info info;
+ struct acpi_device *adev;
+ int ret = -1;
+
+ adev = ACPI_COMPANION(&st->client->dev);
+ memset(&info, 0, sizeof(info));
+
+ dmi_check_system(inv_mpu_dev_list);
+ switch (matched_product_name) {
+ case INV_MPU_ASUS_T100TA:
+ ret = asus_acpi_get_sensor_info(adev, st->client,
+ &info);
+ break;
+ /* Add more matched product processing here */
+ default:
+ break;
+ }
+
+ if (ret < 0) {
+ /* No matching DMI, so create device on INV6XX type */
+ unsigned short primary, secondary;
+
+ ret = inv_mpu_process_acpi_config(st->client, &primary,
+ &secondary);
+ if (!ret && secondary) {
+ char *name;
+
+ info.addr = secondary;
+ strlcpy(info.type, dev_name(&adev->dev),
+ sizeof(info.type));
+ name = strchr(info.type, ':');
+ if (name)
+ *name = '\0';
+ strlcat(info.type, "-client",
+ sizeof(info.type));
+ } else
+ return 0; /* no secondary addr, which is OK */
+ }
+ st->mux_client = i2c_new_device(st->mux_adapter, &info);
+ if (!st->mux_client)
+ return -ENODEV;
+
+ }
+
+ return 0;
+}
+
+void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st)
+{
+ if (st->mux_client)
+ i2c_unregister_device(st->mux_client);
+}
+#else
+
+#include "inv_mpu_iio.h"
+
+int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
+{
+ return 0;
+}
+
+void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st)
+{
+}
+#endif
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index ef76afe..17d4bb1 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -829,8 +829,14 @@ static int inv_mpu_probe(struct i2c_client *client,
goto out_unreg_device;
}
+ result = inv_mpu_acpi_create_mux_client(st);
+ if (result)
+ goto out_del_mux;
+
return 0;
+out_del_mux:
+ i2c_del_mux_adapter(st->mux_adapter);
out_unreg_device:
iio_device_unregister(indio_dev);
out_remove_trigger:
@@ -845,6 +851,7 @@ 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(st);
i2c_del_mux_adapter(st->mux_adapter);
iio_device_unregister(indio_dev);
inv_mpu6050_remove_trigger(st);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index aa837de..db0a4a2 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -121,6 +121,7 @@ struct inv_mpu6050_state {
spinlock_t time_stamp_lock;
struct i2c_client *client;
struct i2c_adapter *mux_adapter;
+ struct i2c_client *mux_client;
unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
@@ -251,3 +252,5 @@ int inv_reset_fifo(struct iio_dev *indio_dev);
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
+int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st);
+void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st);
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index b3a3637..462a010 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -169,19 +169,18 @@ static const u16 kmx61_uscale_table[] = {9582, 19163, 38326};
static const struct {
int val;
int val2;
- u8 odr_bits;
-} kmx61_samp_freq_table[] = { {12, 500000, 0x00},
- {25, 0, 0x01},
- {50, 0, 0x02},
- {100, 0, 0x03},
- {200, 0, 0x04},
- {400, 0, 0x05},
- {800, 0, 0x06},
- {1600, 0, 0x07},
- {0, 781000, 0x08},
- {1, 563000, 0x09},
- {3, 125000, 0x0A},
- {6, 250000, 0x0B} };
+} kmx61_samp_freq_table[] = { {12, 500000},
+ {25, 0},
+ {50, 0},
+ {100, 0},
+ {200, 0},
+ {400, 0},
+ {800, 0},
+ {1600, 0},
+ {0, 781000},
+ {1, 563000},
+ {3, 125000},
+ {6, 250000} };
static const struct {
int val;
@@ -302,24 +301,10 @@ static int kmx61_convert_freq_to_bit(int val, int val2)
for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
if (val == kmx61_samp_freq_table[i].val &&
val2 == kmx61_samp_freq_table[i].val2)
- return kmx61_samp_freq_table[i].odr_bits;
+ return i;
return -EINVAL;
}
-static int kmx61_convert_bit_to_freq(u8 odr_bits, int *val, int *val2)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
- if (odr_bits == kmx61_samp_freq_table[i].odr_bits) {
- *val = kmx61_samp_freq_table[i].val;
- *val2 = kmx61_samp_freq_table[i].val2;
- return 0;
- }
- return -EINVAL;
-}
-
-
static int kmx61_convert_wake_up_odr_to_bit(int val, int val2)
{
int i;
@@ -478,7 +463,7 @@ static int kmx61_set_odr(struct kmx61_data *data, int val, int val2, u8 device)
static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2,
u8 device)
-{ int i;
+{
u8 lodr_bits;
if (device & KMX61_ACC)
@@ -490,13 +475,13 @@ static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2,
else
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
- if (lodr_bits == kmx61_samp_freq_table[i].odr_bits) {
- *val = kmx61_samp_freq_table[i].val;
- *val2 = kmx61_samp_freq_table[i].val2;
- return 0;
- }
- return -EINVAL;
+ if (lodr_bits >= ARRAY_SIZE(kmx61_samp_freq_table))
+ return -EINVAL;
+
+ *val = kmx61_samp_freq_table[lodr_bits].val;
+ *val2 = kmx61_samp_freq_table[lodr_bits].val2;
+
+ return 0;
}
static int kmx61_set_range(struct kmx61_data *data, u8 range)
@@ -580,8 +565,11 @@ static int kmx61_chip_init(struct kmx61_data *data)
}
data->odr_bits = ret;
- /* set output data rate for wake up (motion detection) function */
- ret = kmx61_convert_bit_to_freq(data->odr_bits, &val, &val2);
+ /*
+ * set output data rate for wake up (motion detection) function
+ * to match data rate for accelerometer sampling
+ */
+ ret = kmx61_get_odr(data, &val, &val2, KMX61_ACC);
if (ret < 0)
return ret;
@@ -1267,16 +1255,12 @@ static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data)
dev = &client->dev;
/* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0);
+ gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
- ret = gpiod_direction_input(gpio);
- if (ret)
- return ret;
-
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
OpenPOWER on IntegriCloud