All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1] iio: ak8975: Add AKM0991x support.
@ 2014-10-29 22:01 Gwendal Grignou
  2014-10-29 22:01 ` [PATCH] " Gwendal Grignou
  2014-10-31 15:21 ` [PATCH 0/1] " Srinivas Pandruvada
  0 siblings, 2 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-10-29 22:01 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23; +Cc: linux-iio

AK09912 is an accelerometer with the same register set as AK09911, but
same behavior as AK8973, so I was not sure where to add the support.
I decided to merge all AKM magnetometer support in the same file while
being as clean as I could.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH] iio: ak8975: Add AKM0991x support.
  2014-10-29 22:01 [PATCH 0/1] iio: ak8975: Add AKM0991x support Gwendal Grignou
@ 2014-10-29 22:01 ` Gwendal Grignou
  2014-11-03 22:22   ` Hartmut Knaack
  2014-10-31 15:21 ` [PATCH 0/1] " Srinivas Pandruvada
  1 sibling, 1 reply; 28+ messages in thread
From: Gwendal Grignou @ 2014-10-29 22:01 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23; +Cc: linux-iio, Gwendal Grignou

File and config id remains the same, but driver is now named akxxxx.
Move AKM09911 support in the same file.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---
 drivers/iio/magnetometer/Kconfig   |  19 +-
 drivers/iio/magnetometer/Makefile  |   1 -
 drivers/iio/magnetometer/ak09911.c | 326 -------------------
 drivers/iio/magnetometer/ak8975.c  | 627 ++++++++++++++++++++++++++-----------
 4 files changed, 448 insertions(+), 525 deletions(-)
 delete mode 100644 drivers/iio/magnetometer/ak09911.c

diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index b2dba9e..67f005d 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -6,26 +6,15 @@
 menu "Magnetometer sensors"
 
 config AK8975
-	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+	tristate "Asahi Kasei AK 3-Axis Magnetometer"
 	depends on I2C
 	depends on GPIOLIB
 	help
-	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
-	  Magnetometer. This driver can also support AK8963, if i2c
-	  device name is identified as ak8963.
+	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
+	  AK09911 or AK09912 3-Axis Magnetometer.
 
 	  To compile this driver as a module, choose M here: the module
-	  will be called ak8975.
-
-config AK09911
-	tristate "Asahi Kasei AK09911 3-axis Compass"
-	depends on I2C
-	help
-	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
-	  Magnetometer.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called ak09911.
+	  will be called akxxxx.
 
 config MAG3110
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b91315e..0f5d3c9 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,7 +3,6 @@
 #
 
 # When adding new entries keep the list in alphabetical order
-obj-$(CONFIG_AK09911)	+= ak09911.o
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
deleted file mode 100644
index b2bc942..0000000
--- a/drivers/iio/magnetometer/ak09911.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * AK09911 3-axis compass driver
- * Copyright (c) 2014, 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/iio/iio.h>
-
-#define AK09911_REG_WIA1		0x00
-#define AK09911_REG_WIA2		0x01
-#define AK09911_WIA1_VALUE		0x48
-#define AK09911_WIA2_VALUE		0x05
-
-#define AK09911_REG_ST1			0x10
-#define AK09911_REG_HXL			0x11
-#define AK09911_REG_HXH			0x12
-#define AK09911_REG_HYL			0x13
-#define AK09911_REG_HYH			0x14
-#define AK09911_REG_HZL			0x15
-#define AK09911_REG_HZH			0x16
-
-#define AK09911_REG_ASAX		0x60
-#define AK09911_REG_ASAY		0x61
-#define AK09911_REG_ASAZ		0x62
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_MODE_SNG_MEASURE	0x01
-#define AK09911_MODE_SELF_TEST		0x10
-#define AK09911_MODE_FUSE_ACCESS	0x1F
-#define AK09911_MODE_POWERDOWN		0x00
-#define AK09911_RESET_DATA		0x01
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
-
-#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
-#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
-
-struct ak09911_data {
-	struct i2c_client	*client;
-	struct mutex		lock;
-	u8			asa[3];
-	long			raw_to_gauss[3];
-};
-
-static const int ak09911_index_to_reg[] = {
-	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
-};
-
-static int ak09911_set_mode(struct i2c_client *client, u8 mode)
-{
-	int ret;
-
-	switch (mode) {
-	case AK09911_MODE_SNG_MEASURE:
-	case AK09911_MODE_SELF_TEST:
-	case AK09911_MODE_FUSE_ACCESS:
-	case AK09911_MODE_POWERDOWN:
-		ret = i2c_smbus_write_byte_data(client,
-						AK09911_REG_CNTL2, mode);
-		if (ret < 0) {
-			dev_err(&client->dev, "set_mode error\n");
-			return ret;
-		}
-		/* After mode change wait atleast 100us */
-		usleep_range(100, 500);
-		break;
-	default:
-		dev_err(&client->dev,
-			"%s: Unknown mode(%d).", __func__, mode);
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-/* Get Sensitivity Adjustment value */
-static int ak09911_get_asa(struct i2c_client *client)
-{
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak09911_data *data = iio_priv(indio_dev);
-	int ret;
-
-	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
-	if (ret < 0)
-		return ret;
-
-	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
-					    3, data->asa);
-	if (ret < 0) {
-		dev_err(&client->dev, "Not able to read asa data\n");
-		return ret;
-	}
-
-	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
-	if (ret < 0)
-		return ret;
-
-	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
-	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
-	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
-
-	return 0;
-}
-
-static int ak09911_verify_chip_id(struct i2c_client *client)
-{
-	u8 wia_val[2];
-	int ret;
-
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
-					    2, wia_val);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-
-	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
-
-	if (wia_val[0] != AK09911_WIA1_VALUE ||
-		wia_val[1] != AK09911_WIA2_VALUE) {
-		dev_err(&client->dev, "Device ak09911 not found\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int wait_conversion_complete_polled(struct ak09911_data *data)
-{
-	struct i2c_client *client = data->client;
-	u8 read_status;
-	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
-	int ret;
-
-	/* Wait for the conversion to complete. */
-	while (timeout_ms) {
-		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
-		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
-		if (ret < 0) {
-			dev_err(&client->dev, "Error in reading ST1\n");
-			return ret;
-		}
-		read_status = ret & 0x01;
-		if (read_status)
-			break;
-		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
-	}
-	if (!timeout_ms) {
-		dev_err(&client->dev, "Conversion timeout happened\n");
-		return -EIO;
-	}
-
-	return read_status;
-}
-
-static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	int ret;
-
-	mutex_lock(&data->lock);
-
-	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
-	if (ret < 0)
-		goto fn_exit;
-
-	ret = wait_conversion_complete_polled(data);
-	if (ret < 0)
-		goto fn_exit;
-
-	/* Read data */
-	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
-	if (ret < 0) {
-		dev_err(&client->dev, "Read axis data fails\n");
-		goto fn_exit;
-	}
-
-	mutex_unlock(&data->lock);
-
-	/* Clamp to valid range. */
-	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
-
-	return IIO_VAL_INT;
-
-fn_exit:
-	mutex_unlock(&data->lock);
-
-	return ret;
-}
-
-static int ak09911_read_raw(struct iio_dev *indio_dev,
-			    struct iio_chan_spec const *chan,
-			    int *val, int *val2,
-			    long mask)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		return ak09911_read_axis(indio_dev, chan->address, val);
-	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = data->raw_to_gauss[chan->address];
-		return IIO_VAL_INT_PLUS_MICRO;
-	}
-
-	return -EINVAL;
-}
-
-#define AK09911_CHANNEL(axis, index)					\
-	{								\
-		.type = IIO_MAGN,					\
-		.modified = 1,						\
-		.channel2 = IIO_MOD_##axis,				\
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
-			     BIT(IIO_CHAN_INFO_SCALE),			\
-		.address = index,					\
-	}
-
-static const struct iio_chan_spec ak09911_channels[] = {
-	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
-};
-
-static const struct iio_info ak09911_info = {
-	.read_raw = &ak09911_read_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct acpi_device_id ak_acpi_match[] = {
-	{"AK009911", 0},
-	{ },
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
-static int ak09911_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	struct iio_dev *indio_dev;
-	struct ak09911_data *data;
-	const char *name;
-	int ret;
-
-	ret = ak09911_verify_chip_id(client);
-	if (ret) {
-		dev_err(&client->dev, "AK00911 not detected\n");
-		return -ENODEV;
-	}
-
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
-	if (indio_dev == NULL)
-		return -ENOMEM;
-
-	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-
-	data->client = client;
-	mutex_init(&data->lock);
-
-	ret = ak09911_get_asa(client);
-	if (ret)
-		return ret;
-
-	if (id)
-		name = id->name;
-	else if (ACPI_HANDLE(&client->dev))
-		name = dev_name(&client->dev);
-	else
-		return -ENODEV;
-
-	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
-
-	indio_dev->dev.parent = &client->dev;
-	indio_dev->channels = ak09911_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
-	indio_dev->info = &ak09911_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->name = name;
-
-	return devm_iio_device_register(&client->dev, indio_dev);
-}
-
-static const struct i2c_device_id ak09911_id[] = {
-	{"ak09911", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, ak09911_id);
-
-static struct i2c_driver ak09911_driver = {
-	.driver = {
-		.name	= "ak09911",
-		.acpi_match_table = ACPI_PTR(ak_acpi_match),
-	},
-	.probe		= ak09911_probe,
-	.id_table	= ak09911_id,
-};
-module_i2c_driver(ak09911_driver);
-
-MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("AK09911 Compass driver");
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index bf5ef07..190c21c 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -35,9 +35,10 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+
 /*
- * Register definitions, as well as various shifts and masks to get at the
- * individual fields of the registers.
+ * AK_8975 Register definitions, as well as various shifts and masks to get
+ * at the individual fields of the registers.
  */
 #define AK8975_REG_WIA			0x00
 #define AK8975_DEVICE_ID		0x48
@@ -62,12 +63,12 @@
 #define AK8975_REG_ST2_HOFL_MASK	(1 << AK8975_REG_ST2_HOFL_SHIFT)
 
 #define AK8975_REG_CNTL			0x0A
+#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK8975_REG_CNTL_MODE_ONCE	0x01
+#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
+#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
 #define AK8975_REG_CNTL_MODE_SHIFT	0
 #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
-#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
-#define AK8975_REG_CNTL_MODE_ONCE	1
-#define AK8975_REG_CNTL_MODE_SELF_TEST	8
-#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
 
 #define AK8975_REG_RSVC			0x0B
 #define AK8975_REG_ASTC			0x0C
@@ -81,59 +82,369 @@
 #define AK8975_MAX_REGS			AK8975_REG_ASAZ
 
 /*
- * Miscellaneous values.
+ * AK09912 Register definitions
+ */
+#define AK09912_REG_WIA1		0x00
+#define AK09912_COMPANY_ID		0x48
+#define AK09912_REG_WIA2		0x01
+#define AK09912_DEVICE_ID		0x04
+#define AK09911_DEVICE_ID		0x05
+
+#define AK09912_REG_INFO1		0x02
+#define AK09912_REG_INFO2		0x03
+
+#define AK09912_REG_ST1			0x10
+
+#define AK09912_REG_ST1_DRDY_SHIFT	0
+#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
+
+#define AK09912_REG_HXL			0x11
+#define AK09912_REG_HXH			0x12
+#define AK09912_REG_HYL			0x13
+#define AK09912_REG_HYH			0x14
+#define AK09912_REG_HZL			0x15
+#define AK09912_REG_HZH			0x16
+#define AK09912_REG_TMPS		0x17
+
+#define AK09912_REG_ST2			0x18
+#define AK09912_REG_ST2_HOFL_SHIFT	3
+#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
+
+#define AK09912_REG_CNTL1		0x30
+
+
+#define AK09912_REG_CNTL2		0x31
+#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK09912_REG_CNTL_MODE_ONCE	0x01
+#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
+#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
+#define AK09912_REG_CNTL2_MODE_SHIFT	0
+#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
+
+#define AK09912_REG_CNTL3		0x32
+
+#define AK09912_REG_TS1			0x33
+#define AK09912_REG_TS2			0x34
+#define AK09912_REG_TS3			0x35
+#define AK09912_REG_I2CDIS		0x36
+#define AK09912_REG_TS4			0x37
+
+#define AK09912_REG_ASAX		0x60
+#define AK09912_REG_ASAY		0x61
+#define AK09912_REG_ASAZ		0x62
+
+#define AK09912_MAX_REGS		AK09912_REG_ASAZ
+
+
+/*
+ * Precalculate scale factor (in Gauss units) for each axis and
+ * store in the device data.
+ *
+ * This scale factor is axis-dependent, and is derived from 3 calibration
+ * factors ASA(x), ASA(y), and ASA(z).
+ *
+ * These ASA values are read from the sensor device at start of day, and
+ * cached in the device context struct.
+ *
+ * Adjusting the flux value with the sensitivity adjustment value should be
+ * done via the following formula:
+ *
+ * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
+ * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
+ * is the resultant adjusted value.
+ *
+ * We reduce the formula to:
+ *
+ * Hadj = H * (ASA + 128) / 256
+ *
+ * H is in the range of -4096 to 4095.  The magnetometer has a range of
+ * +-1229uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 1229/4096, or roughly, 3/10.
+ *
+ * Since 1uT = 0.01 gauss, our final scale factor becomes:
+ *
+ * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
+ * Hadj = H * ((ASA + 128) * 0.003) / 256
+ *
+ * Since ASA doesn't change, we cache the resultant scale factor into the
+ * device context in ak8975_setup().
+ */
+long ak8975_raw_to_gauss(uint16_t data)
+{
+	return (((long)data + 128) * 3000) / 256;
+}
+
+/*
+ * For AK8963, same calculation, except the device is less sensitive:
+ *
+ * H is in the range of +-8190.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
+ */
+long ak8963_09911_raw_to_gauss(uint16_t data)
+{
+	return (((long)data + 128) * 6000) / 256;
+}
+
+/*
+ * For AK09912, same calculation, except the device is more sensitive:
+ *
+ * H is in the range of -32752 to 32752.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
+ */
+long ak09912_raw_to_gauss(uint16_t data)
+{
+	return (((long)data + 128) * 1500) / 256;
+}
+
+/*
+ * Return 0 if the i2c device is supported,
+ * return a negative error number otherwise
  */
-#define AK8975_MAX_CONVERSION_TIMEOUT	500
-#define AK8975_CONVERSION_DONE_POLL_TIME 10
-#define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
-#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
-#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
-
-/* Compatible Asahi Kasei Compass parts */
-enum asahi_compass_chipset {
+int ak09912_who_i_am(struct i2c_client *client)
+{
+	u8 wia_val[2];
+	int ret;
+
+	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
+					    2, wia_val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return ret;
+	}
+
+	if (wia_val[0] != AK09912_COMPANY_ID ||
+		wia_val[1] != AK09912_DEVICE_ID) {
+		dev_err(&client->dev, "Device ak09912 not found\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+int ak09911_who_i_am(struct i2c_client *client)
+{
+	u8 wia_val[2];
+	int ret;
+
+	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
+					    2, wia_val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return ret;
+	}
+
+	if (wia_val[0] != AK09912_COMPANY_ID ||
+		wia_val[1] != AK09912_DEVICE_ID) {
+		dev_err(&client->dev, "Device ak09911 not found\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+int ak8975_8963_who_i_am(struct i2c_client *client)
+{
+	int device_id;
+	int ret;
+	/* Confirm that the device we're talking to is really an AK8975. */
+	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return ret;
+	}
+	device_id = ret;
+	if (device_id != AK8975_DEVICE_ID) {
+		dev_err(&client->dev, "Device ak8975 not found\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+enum ak_type {
 	AK8975,
 	AK8963,
+	AK09911,
+	AK09912,
+	AK_MAX_TYPE
+};
+
+enum ak_ctrl_reg_addr {
+	ST1,
+	ST2,
+	CNTL,
+	ASA_BASE,
+	MAX_REGS,
+	REGS_END,
+};
+
+enum ak_ctrl_reg_mask {
+	ST1_DRDY,
+	ST2_HOFL,
+	ST2_DERR,
+	CNTL_MODE,
+	MASK_END,
+};
+
+enum ak_ctrl_mode {
+	POWER_DOWN,
+	MODE_ONCE,
+	SELF_TEST,
+	FUSE_ROM,
+	MODE_END,
+};
+
+struct akxxxx_def {
+	int (*who_i_am)(struct i2c_client *client);
+	long (*raw_to_gauss)(uint16_t data);
+	uint8_t ctrl_regs[REGS_END];
+	uint8_t ctrl_masks[MASK_END];
+	uint8_t ctrl_modes[MODE_END];
+	uint8_t data_regs[3];
+} akxxxx_def_array[AK_MAX_TYPE] = {
+{
+	.who_i_am = ak8975_8963_who_i_am,
+	.raw_to_gauss = ak8975_raw_to_gauss,
+	.ctrl_regs = {
+		AK8975_REG_ST1,
+		AK8975_REG_ST2,
+		AK8975_REG_CNTL,
+		AK8975_REG_ASAX,
+		AK8975_MAX_REGS},
+	.ctrl_masks = {
+		AK8975_REG_ST1_DRDY_MASK,
+		AK8975_REG_ST2_HOFL_MASK,
+		AK8975_REG_ST2_DERR_MASK,
+		AK8975_REG_CNTL_MODE_MASK},
+	.ctrl_modes = {
+		AK8975_REG_CNTL_MODE_POWER_DOWN,
+		AK8975_REG_CNTL_MODE_ONCE,
+		AK8975_REG_CNTL_MODE_SELF_TEST,
+		AK8975_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK8975_REG_HXL,
+		AK8975_REG_HYL,
+		AK8975_REG_HZL},
+},
+{
+	.who_i_am = ak8975_8963_who_i_am,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
+	.ctrl_regs = {
+		AK8975_REG_ST1,
+		AK8975_REG_ST2,
+		AK8975_REG_CNTL,
+		AK8975_REG_ASAX,
+		AK8975_MAX_REGS},
+	.ctrl_masks = {
+		AK8975_REG_ST1_DRDY_MASK,
+		AK8975_REG_ST2_HOFL_MASK,
+		AK8975_REG_ST2_DERR_MASK,
+		AK8975_REG_CNTL_MODE_MASK},
+	.ctrl_modes = {
+		AK8975_REG_CNTL_MODE_POWER_DOWN,
+		AK8975_REG_CNTL_MODE_ONCE,
+		AK8975_REG_CNTL_MODE_SELF_TEST,
+		AK8975_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK8975_REG_HXL,
+		AK8975_REG_HYL,
+		AK8975_REG_HZL},
+},
+{
+	.who_i_am = ak09911_who_i_am,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+},
+{
+	.who_i_am = ak09912_who_i_am,
+	.raw_to_gauss = ak09912_raw_to_gauss,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+}
 };
 
 /*
+ * Miscellaneous values.
+ */
+#define AKXXXX_MAX_CONVERSION_TIMEOUT	500
+#define AKXXXX_CONVERSION_DONE_POLL_TIME 10
+#define AKXXXX_DATA_READY_TIMEOUT	((100*HZ)/1000)
+
+
+/*
  * Per-instance context data for the device.
  */
-struct ak8975_data {
+struct akxxxx_data {
 	struct i2c_client	*client;
+	struct akxxxx_def       *def;
 	struct attribute_group	attrs;
 	struct mutex		lock;
 	u8			asa[3];
 	long			raw_to_gauss[3];
-	u8			reg_cache[AK8975_MAX_REGS];
 	int			eoc_gpio;
 	int			eoc_irq;
 	wait_queue_head_t	data_ready_queue;
 	unsigned long		flags;
-	enum asahi_compass_chipset chipset;
-};
-
-static const int ak8975_index_to_reg[] = {
-	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
+	u8			cntl_cache;
 };
 
 /*
  * Helper function to write to the I2C device's registers.
  */
-static int ak8975_write_data(struct i2c_client *client,
-			     u8 reg, u8 val, u8 mask, u8 shift)
+static int akxxxx_set_mode(struct akxxxx_data *data, enum ak_ctrl_mode mode)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak8975_data *data = iio_priv(indio_dev);
 	u8 regval;
 	int ret;
 
-	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
-	ret = i2c_smbus_write_byte_data(client, reg, regval);
+	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
+		data->def->ctrl_modes[mode];
+	ret = i2c_smbus_write_byte_data(
+		data->client, data->def->ctrl_regs[CNTL], regval);
 	if (ret < 0) {
-		dev_err(&client->dev, "Write to device fails status %x\n", ret);
 		return ret;
 	}
-	data->reg_cache[reg] = regval;
+	data->cntl_cache = regval;
+	/* After mode change wait atleast 100us */
+	usleep_range(100, 500);
 
 	return 0;
 }
@@ -141,9 +452,9 @@ static int ak8975_write_data(struct i2c_client *client,
 /*
  * Handle data ready irq
  */
-static irqreturn_t ak8975_irq_handler(int irq, void *data)
+static irqreturn_t akxxxx_irq_handler(int irq, void *data)
 {
-	struct ak8975_data *ak8975 = data;
+	struct akxxxx_data *ak8975 = data;
 
 	set_bit(0, &ak8975->flags);
 	wake_up(&ak8975->data_ready_queue);
@@ -154,7 +465,7 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data)
 /*
  * Install data ready interrupt handler
  */
-static int ak8975_setup_irq(struct ak8975_data *data)
+static int akxxxx_setup_irq(struct akxxxx_data *data)
 {
 	struct i2c_client *client = data->client;
 	int rc;
@@ -165,7 +476,7 @@ static int ak8975_setup_irq(struct ak8975_data *data)
 	else
 		irq = gpio_to_irq(data->eoc_gpio);
 
-	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
+	rc = devm_request_irq(&client->dev, irq, akxxxx_irq_handler,
 			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 			 dev_name(&client->dev), data);
 	if (rc < 0) {
@@ -187,53 +498,31 @@ static int ak8975_setup_irq(struct ak8975_data *data)
  * Perform some start-of-day setup, including reading the asa calibration
  * values and caching them.
  */
-static int ak8975_setup(struct i2c_client *client)
+static int akxxxx_setup(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak8975_data *data = iio_priv(indio_dev);
-	u8 device_id;
+	struct akxxxx_data *data = iio_priv(indio_dev);
 	int ret;
 
-	/* Confirm that the device we're talking to is really an AK8975. */
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-	device_id = ret;
-	if (device_id != AK8975_DEVICE_ID) {
-		dev_err(&client->dev, "Device ak8975 not found\n");
-		return -ENODEV;
-	}
-
 	/* Write the fused rom access mode. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_FUSE_ROM,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = akxxxx_set_mode(data, FUSE_ROM);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting fuse access mode\n");
 		return ret;
 	}
 
 	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
-					    3, data->asa);
+	ret = i2c_smbus_read_i2c_block_data(client,
+			data->def->ctrl_regs[ASA_BASE], 3, data->asa);
 	if (ret < 0) {
 		dev_err(&client->dev, "Not able to read asa data\n");
 		return ret;
 	}
 
 	/* After reading fuse ROM data set power-down mode */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_POWER_DOWN,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
-
+	ret = akxxxx_set_mode(data, POWER_DOWN);
 	if (data->eoc_gpio > 0 || client->irq) {
-		ret = ak8975_setup_irq(data);
+		ret = akxxxx_setup_irq(data);
 		if (ret < 0) {
 			dev_err(&client->dev,
 				"Error setting data ready interrupt\n");
@@ -246,96 +535,50 @@ static int ak8975_setup(struct i2c_client *client)
 		return ret;
 	}
 
-/*
- * Precalculate scale factor (in Gauss units) for each axis and
- * store in the device data.
- *
- * This scale factor is axis-dependent, and is derived from 3 calibration
- * factors ASA(x), ASA(y), and ASA(z).
- *
- * These ASA values are read from the sensor device at start of day, and
- * cached in the device context struct.
- *
- * Adjusting the flux value with the sensitivity adjustment value should be
- * done via the following formula:
- *
- * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
- *
- * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
- * is the resultant adjusted value.
- *
- * We reduce the formula to:
- *
- * Hadj = H * (ASA + 128) / 256
- *
- * H is in the range of -4096 to 4095.  The magnetometer has a range of
- * +-1229uT.  To go from the raw value to uT is:
- *
- * HuT = H * 1229/4096, or roughly, 3/10.
- *
- * Since 1uT = 0.01 gauss, our final scale factor becomes:
- *
- * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
- * Hadj = H * ((ASA + 128) * 0.003) / 256
- *
- * Since ASA doesn't change, we cache the resultant scale factor into the
- * device context in ak8975_setup().
- */
-	if (data->chipset == AK8963) {
-		/*
-		 * H range is +-8190 and magnetometer range is +-4912.
-		 * So HuT using the above explanation for 8975,
-		 * 4912/8190 = ~ 6/10.
-		 * So the Hadj should use 6/10 instead of 3/10.
-		 */
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
-	} else {
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
-	}
+	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
+	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
+	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
 
 	return 0;
 }
 
-static int wait_conversion_complete_gpio(struct ak8975_data *data)
+static int wait_conversion_complete_gpio(struct akxxxx_data *data)
 {
 	struct i2c_client *client = data->client;
-	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
+	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
 	int ret;
 
 	/* Wait for the conversion to complete. */
 	while (timeout_ms) {
-		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
+		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
 		if (gpio_get_value(data->eoc_gpio))
 			break;
-		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
+		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
 	}
 	if (!timeout_ms) {
 		dev_err(&client->dev, "Conversion timeout happened\n");
 		return -EINVAL;
 	}
 
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
 	if (ret < 0)
 		dev_err(&client->dev, "Error in reading ST1\n");
 
 	return ret;
 }
 
-static int wait_conversion_complete_polled(struct ak8975_data *data)
+static int wait_conversion_complete_polled(struct akxxxx_data *data)
 {
 	struct i2c_client *client = data->client;
 	u8 read_status;
-	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
+	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
 	int ret;
 
 	/* Wait for the conversion to complete. */
 	while (timeout_ms) {
-		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
+		ret = i2c_smbus_read_byte_data(
+				client, data->def->ctrl_regs[ST1]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST1\n");
 			return ret;
@@ -343,7 +586,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
 		read_status = ret;
 		if (read_status)
 			break;
-		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
+		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
 	}
 	if (!timeout_ms) {
 		dev_err(&client->dev, "Conversion timeout happened\n");
@@ -354,13 +597,13 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
 }
 
 /* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
-static int wait_conversion_complete_interrupt(struct ak8975_data *data)
+static int wait_conversion_complete_interrupt(struct akxxxx_data *data)
 {
 	int ret;
 
 	ret = wait_event_timeout(data->data_ready_queue,
 				 test_bit(0, &data->flags),
-				 AK8975_DATA_READY_TIMEOUT);
+				 AKXXXX_DATA_READY_TIMEOUT);
 	clear_bit(0, &data->flags);
 
 	return ret > 0 ? 0 : -ETIME;
@@ -369,20 +612,16 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
 /*
  * Emits the raw flux value for the x, y, or z axis.
  */
-static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
+static int akxxxx_read_axis(struct iio_dev *indio_dev, int index, int *val)
 {
-	struct ak8975_data *data = iio_priv(indio_dev);
+	struct akxxxx_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
 	int ret;
 
 	mutex_lock(&data->lock);
 
 	/* Set up the device for taking a sample. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_ONCE,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = akxxxx_set_mode(data, MODE_ONCE);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting operating mode\n");
 		goto exit;
@@ -399,14 +638,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 		goto exit;
 
 	/* This will be executed only for non-interrupt based waiting case */
-	if (ret & AK8975_REG_ST1_DRDY_MASK) {
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
+	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
+		ret = i2c_smbus_read_byte_data(
+				client, data->def->ctrl_regs[ST2]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST2\n");
 			goto exit;
 		}
-		if (ret & (AK8975_REG_ST2_DERR_MASK |
-			   AK8975_REG_ST2_HOFL_MASK)) {
+		if (ret & (data->def->ctrl_masks[ST2_DERR] |
+			   data->def->ctrl_masks[ST2_HOFL])) {
 			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
 			ret = -EINVAL;
 			goto exit;
@@ -415,7 +655,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 
 	/* Read the flux value from the appropriate register
 	   (the register is specified in the iio device attributes). */
-	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
+	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
 	if (ret < 0) {
 		dev_err(&client->dev, "Read axis data fails\n");
 		goto exit;
@@ -432,16 +672,16 @@ exit:
 	return ret;
 }
 
-static int ak8975_read_raw(struct iio_dev *indio_dev,
+static int akxxxx_read_raw(struct iio_dev *indio_dev,
 			   struct iio_chan_spec const *chan,
 			   int *val, int *val2,
 			   long mask)
 {
-	struct ak8975_data *data = iio_priv(indio_dev);
+	struct akxxxx_data *data = iio_priv(indio_dev);
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		return ak8975_read_axis(indio_dev, chan->address, val);
+		return akxxxx_read_axis(indio_dev, chan->address, val);
 	case IIO_CHAN_INFO_SCALE:
 		*val = 0;
 		*val2 = data->raw_to_gauss[chan->address];
@@ -450,7 +690,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
 	return -EINVAL;
 }
 
-#define AK8975_CHANNEL(axis, index)					\
+#define AKXXXX_CHANNEL(axis, index)					\
 	{								\
 		.type = IIO_MAGN,					\
 		.modified = 1,						\
@@ -460,40 +700,41 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
 		.address = index,					\
 	}
 
-static const struct iio_chan_spec ak8975_channels[] = {
-	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
+static const struct iio_chan_spec akxxxx_channels[] = {
+	AKXXXX_CHANNEL(X, 0), AKXXXX_CHANNEL(Y, 1), AKXXXX_CHANNEL(Z, 2),
 };
 
-static const struct iio_info ak8975_info = {
-	.read_raw = &ak8975_read_raw,
+static const struct iio_info akxxxx_info = {
+	.read_raw = &akxxxx_read_raw,
 	.driver_module = THIS_MODULE,
 };
 
-static const struct acpi_device_id ak_acpi_match[] = {
-	{"AK8975", AK8975},
-	{"AK8963", AK8963},
-	{"INVN6500", AK8963},
+static const struct acpi_device_id akxxxx_acpi_match[] = {
+	{"AK8975", (uintptr_t)&akxxxx_def_array[AK8975]},
+	{"AK8963", (uintptr_t)&akxxxx_def_array[AK8963]},
+	{"AK09911", (uintptr_t)&akxxxx_def_array[AK09911]},
+	{"AK09912", (uintptr_t)&akxxxx_def_array[AK09912]},
 	{ },
 };
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
+MODULE_DEVICE_TABLE(acpi, akxxxx_acpi_match);
 
-static const char *ak8975_match_acpi_device(struct device *dev,
-					    enum asahi_compass_chipset *chipset)
+static const char *akxxxx_match_acpi_device(struct device *dev,
+					    struct akxxxx_def **def)
 {
 	const struct acpi_device_id *id;
 
 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 	if (!id)
 		return NULL;
-	*chipset = (int)id->driver_data;
+	*def = (struct akxxxx_def *)id->driver_data;
 
 	return dev_name(dev);
 }
 
-static int ak8975_probe(struct i2c_client *client,
+static int akxxxx_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	struct ak8975_data *data;
+	struct akxxxx_data *data;
 	struct iio_dev *indio_dev;
 	int eoc_gpio;
 	int err;
@@ -513,8 +754,8 @@ static int ak8975_probe(struct i2c_client *client,
 	/* We may not have a GPIO based IRQ to scan, that is fine, we will
 	   poll if so */
 	if (gpio_is_valid(eoc_gpio)) {
-		err = devm_gpio_request_one(&client->dev, eoc_gpio,
-							GPIOF_IN, "ak_8975");
+		err = devm_gpio_request_one(
+			&client->dev, eoc_gpio, GPIOF_IN, id->name);
 		if (err < 0) {
 			dev_err(&client->dev,
 				"failed to request GPIO %d, error %d\n",
@@ -534,23 +775,27 @@ static int ak8975_probe(struct i2c_client *client,
 	data->client = client;
 	data->eoc_gpio = eoc_gpio;
 	data->eoc_irq = 0;
-
 	/* id will be NULL when enumerated via ACPI */
 	if (id) {
-		data->chipset =
-			(enum asahi_compass_chipset)(id->driver_data);
+		data->def = (struct akxxxx_def *)id->driver_data;
 		name = id->name;
 	} else if (ACPI_HANDLE(&client->dev))
-		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
+		name = akxxxx_match_acpi_device(&client->dev, &data->def);
 	else
 		return -ENOSYS;
 
+	if (data->def->who_i_am(client) < 0) {
+		dev_err(&client->dev, "Unexpected device\n");
+		return -ENODEV;
+	}
+
+	/* id will be NULL when enumerated via ACPI */
 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 
 	/* Perform some basic start-of-day setup of the device. */
-	err = ak8975_setup(client);
+	err = akxxxx_setup(client);
 	if (err < 0) {
-		dev_err(&client->dev, "AK8975 initialization fails\n");
+		dev_err(&client->dev, "%s initialization fails\n", name);
 		return err;
 	}
 
@@ -558,9 +803,9 @@ static int ak8975_probe(struct i2c_client *client,
 	mutex_init(&data->lock);
 	data->eoc_gpio = eoc_gpio;
 	indio_dev->dev.parent = &client->dev;
-	indio_dev->channels = ak8975_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
-	indio_dev->info = &ak8975_info;
+	indio_dev->channels = akxxxx_channels;
+	indio_dev->num_channels = ARRAY_SIZE(akxxxx_channels);
+	indio_dev->info = &akxxxx_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = name;
 	err = devm_iio_device_register(&client->dev, indio_dev);
@@ -570,32 +815,48 @@ static int ak8975_probe(struct i2c_client *client,
 	return 0;
 }
 
-static const struct i2c_device_id ak8975_id[] = {
-	{"ak8975", AK8975},
-	{"ak8963", AK8963},
+static const struct i2c_device_id akxxxx_id[] = {
+	{"ak8975", (uintptr_t)&akxxxx_def_array[AK8975]},
+	{"ak8963", (uintptr_t)&akxxxx_def_array[AK8963]},
+	{"ak09911", (uintptr_t)&akxxxx_def_array[AK09911]},
+	{"ak09912", (uintptr_t)&akxxxx_def_array[AK09912]},
 	{}
 };
 
-MODULE_DEVICE_TABLE(i2c, ak8975_id);
-
-static const struct of_device_id ak8975_of_match[] = {
-	{ .compatible = "asahi-kasei,ak8975", },
-	{ .compatible = "ak8975", },
+MODULE_DEVICE_TABLE(i2c, akxxxx_id);
+
+static const struct of_device_id akxxxx_of_match[] = {
+	{ .compatible = "asahi-kasei,ak8975",
+	  .data = &akxxxx_def_array[AK8975]},
+	{ .compatible = "ak8975",
+	  .data = &akxxxx_def_array[AK8975]},
+	{ .compatible = "asahi-kasei,ak8963",
+	  .data = &akxxxx_def_array[AK8963]},
+	{ .compatible = "ak8963",
+	  .data = &akxxxx_def_array[AK8963]},
+	{ .compatible = "asahi-kasei,ak09911",
+	  .data = &akxxxx_def_array[AK09911]},
+	{ .compatible = "ak09911",
+	  .data = &akxxxx_def_array[AK09911]},
+	{ .compatible = "asahi-kasei,ak09912",
+	  .data = &akxxxx_def_array[AK09912]},
+	{ .compatible = "ak09912",
+	  .data = &akxxxx_def_array[AK09912]},
 	{ }
 };
-MODULE_DEVICE_TABLE(of, ak8975_of_match);
+MODULE_DEVICE_TABLE(of, akxxxx_of_match);
 
-static struct i2c_driver ak8975_driver = {
+static struct i2c_driver akxxxx_driver = {
 	.driver = {
-		.name	= "ak8975",
-		.of_match_table = ak8975_of_match,
-		.acpi_match_table = ACPI_PTR(ak_acpi_match),
+		.name	= "akxxxx",
+		.of_match_table = of_match_ptr(akxxxx_of_match),
+		.acpi_match_table = ACPI_PTR(akxxxx_acpi_match),
 	},
-	.probe		= ak8975_probe,
-	.id_table	= ak8975_id,
+	.probe		= akxxxx_probe,
+	.id_table	= akxxxx_id,
 };
-module_i2c_driver(ak8975_driver);
+module_i2c_driver(akxxxx_driver);
 
 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_DESCRIPTION("AK8975 magnetometer driver");
+MODULE_DESCRIPTION("ak8975 and ak09912 magnetometer driver");
 MODULE_LICENSE("GPL");
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 0/1] iio: ak8975: Add AKM0991x support.
  2014-10-29 22:01 [PATCH 0/1] iio: ak8975: Add AKM0991x support Gwendal Grignou
  2014-10-29 22:01 ` [PATCH] " Gwendal Grignou
@ 2014-10-31 15:21 ` Srinivas Pandruvada
  2014-11-01 21:03   ` Gwendal Grignou
  1 sibling, 1 reply; 28+ messages in thread
From: Srinivas Pandruvada @ 2014-10-31 15:21 UTC (permalink / raw)
  To: Gwendal Grignou; +Cc: jic23, linux-iio

On Wed, 2014-10-29 at 15:01 -0700, Gwendal Grignou wrote:
> AK09912 is an accelerometer with the same register set as AK09911, but
> same behavior as AK8973, so I was not sure where to add the support.
> I decided to merge all AKM magnetometer support in the same file while
> being as clean as I could.
> 
AK09911 is implemented as a separate driver to have a clean. 
- Register map is different and have different indexes
- AK09911 is a very compact interface with no DRDY pin. So no support
     of interrupt or GPIO poll
- Even for polled mode no mention on ST2 register, which is required in
    ak8975 driver
- mode values are different for fuse access

I didn't get chance to check your merged driver, IMO simple standalone
driver is better if there are two many difference like above, difference
between AK09911 and AK8973.

Thanks,
Srinivas

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 0/1] iio: ak8975: Add AKM0991x support.
  2014-10-31 15:21 ` [PATCH 0/1] " Srinivas Pandruvada
@ 2014-11-01 21:03   ` Gwendal Grignou
  0 siblings, 0 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-01 21:03 UTC (permalink / raw)
  To: Srinivas Pandruvada, jic23; +Cc: Gwendal Grignou, linux-iio

On Fri, Oct 31, 2014 at 8:21 AM, Srinivas Pandruvada
<srinivas.pandruvada@linux.intel.com> wrote:
> On Wed, 2014-10-29 at 15:01 -0700, Gwendal Grignou wrote:
>> AK09912 is an accelerometer with the same register set as AK09911, but
>> same behavior as AK8973, so I was not sure where to add the support.
>> I decided to merge all AKM magnetometer support in the same file while
>> being as clean as I could.
>>
> AK09911 is implemented as a separate driver to have a clean.
> - Register map is different and have different indexes
Please take a look at the code, I separated the registers definition
from the code itself.

> - AK09911 is a very compact interface with no DRDY pin. So no support
>      of interrupt or GPIO poll
Other AK can work the same way, use DRDY and interrupt is optional.
> - Even for polled mode no mention on ST2 register, which is required in
>     ak8975 driver
Not true: after polling the measurement, you have to look at ST2
register to ensure you don't have an overflow (HOFL bit).
> - mode values are different for fuse access
Taken care of.
>
> I didn't get chance to check your merged driver, IMO simple standalone
> driver is better if there are two many difference like above, difference
> between AK09911 and AK8973.
The problem I have is AK09912 has almost the same register set than
AK09911 but the same behavior as AK8973 (DRDY pin and interrupt).
So if we want to support it, we end up adding either the interrupt
code in ak09911.c or adding AK09912 register map into ak8973.c:
in the former case, we will end up with 2 very similar drivers, in the
later, ak8973.c driver would handle ak0911 without difficulty. That's
the latter approach I chose.

Gwendal.

>
> Thanks,
> Srinivas
>
>
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] iio: ak8975: Add AKM0991x support.
  2014-10-29 22:01 ` [PATCH] " Gwendal Grignou
@ 2014-11-03 22:22   ` Hartmut Knaack
  2014-11-04 19:41     ` [PATCHv2] " Gwendal Grignou
  0 siblings, 1 reply; 28+ messages in thread
From: Hartmut Knaack @ 2014-11-03 22:22 UTC (permalink / raw)
  To: Gwendal Grignou, srinivas.pandruvada, jic23; +Cc: linux-iio

Gwendal Grignou schrieb am 29.10.2014 23:01:
> File and config id remains the same, but driver is now named akxxxx.
> Move AKM09911 support in the same file.
> 
Find some comments inline.
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>  drivers/iio/magnetometer/Kconfig   |  19 +-
>  drivers/iio/magnetometer/Makefile  |   1 -
>  drivers/iio/magnetometer/ak09911.c | 326 -------------------
>  drivers/iio/magnetometer/ak8975.c  | 627 ++++++++++++++++++++++++++-----------
>  4 files changed, 448 insertions(+), 525 deletions(-)
>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
> 
> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> index b2dba9e..67f005d 100644
> --- a/drivers/iio/magnetometer/Kconfig
> +++ b/drivers/iio/magnetometer/Kconfig
> @@ -6,26 +6,15 @@
>  menu "Magnetometer sensors"
>  
>  config AK8975
> -	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> +	tristate "Asahi Kasei AK 3-Axis Magnetometer"
>  	depends on I2C
>  	depends on GPIOLIB
>  	help
> -	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
> -	  Magnetometer. This driver can also support AK8963, if i2c
> -	  device name is identified as ak8963.
> +	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
> +	  AK09911 or AK09912 3-Axis Magnetometer.
>  
>  	  To compile this driver as a module, choose M here: the module
> -	  will be called ak8975.
> -
> -config AK09911
> -	tristate "Asahi Kasei AK09911 3-axis Compass"
> -	depends on I2C
> -	help
> -	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
> -	  Magnetometer.
> -
> -	  To compile this driver as a module, choose M here: the module
> -	  will be called ak09911.
> +	  will be called akxxxx.
>  
>  config MAG3110
>  	tristate "Freescale MAG3110 3-Axis Magnetometer"
> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
> index b91315e..0f5d3c9 100644
> --- a/drivers/iio/magnetometer/Makefile
> +++ b/drivers/iio/magnetometer/Makefile
> @@ -3,7 +3,6 @@
>  #
>  
>  # When adding new entries keep the list in alphabetical order
> -obj-$(CONFIG_AK09911)	+= ak09911.o
>  obj-$(CONFIG_AK8975)	+= ak8975.o
>  obj-$(CONFIG_MAG3110)	+= mag3110.o
>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
> deleted file mode 100644
> index b2bc942..0000000
> --- a/drivers/iio/magnetometer/ak09911.c
> +++ /dev/null
> @@ -1,326 +0,0 @@
> -/*
> - * AK09911 3-axis compass driver
> - * Copyright (c) 2014, 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.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/types.h>
> -#include <linux/slab.h>
> -#include <linux/delay.h>
> -#include <linux/i2c.h>
> -#include <linux/acpi.h>
> -#include <linux/iio/iio.h>
> -
> -#define AK09911_REG_WIA1		0x00
> -#define AK09911_REG_WIA2		0x01
> -#define AK09911_WIA1_VALUE		0x48
> -#define AK09911_WIA2_VALUE		0x05
> -
> -#define AK09911_REG_ST1			0x10
> -#define AK09911_REG_HXL			0x11
> -#define AK09911_REG_HXH			0x12
> -#define AK09911_REG_HYL			0x13
> -#define AK09911_REG_HYH			0x14
> -#define AK09911_REG_HZL			0x15
> -#define AK09911_REG_HZH			0x16
> -
> -#define AK09911_REG_ASAX		0x60
> -#define AK09911_REG_ASAY		0x61
> -#define AK09911_REG_ASAZ		0x62
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_MODE_SNG_MEASURE	0x01
> -#define AK09911_MODE_SELF_TEST		0x10
> -#define AK09911_MODE_FUSE_ACCESS	0x1F
> -#define AK09911_MODE_POWERDOWN		0x00
> -#define AK09911_RESET_DATA		0x01
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
> -
> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
> -
> -struct ak09911_data {
> -	struct i2c_client	*client;
> -	struct mutex		lock;
> -	u8			asa[3];
> -	long			raw_to_gauss[3];
> -};
> -
> -static const int ak09911_index_to_reg[] = {
> -	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
> -};
> -
> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
> -{
> -	int ret;
> -
> -	switch (mode) {
> -	case AK09911_MODE_SNG_MEASURE:
> -	case AK09911_MODE_SELF_TEST:
> -	case AK09911_MODE_FUSE_ACCESS:
> -	case AK09911_MODE_POWERDOWN:
> -		ret = i2c_smbus_write_byte_data(client,
> -						AK09911_REG_CNTL2, mode);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "set_mode error\n");
> -			return ret;
> -		}
> -		/* After mode change wait atleast 100us */
> -		usleep_range(100, 500);
> -		break;
> -	default:
> -		dev_err(&client->dev,
> -			"%s: Unknown mode(%d).", __func__, mode);
> -		return -EINVAL;
> -	}
> -
> -	return ret;
> -}
> -
> -/* Get Sensitivity Adjustment value */
> -static int ak09911_get_asa(struct i2c_client *client)
> -{
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	int ret;
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
> -	if (ret < 0)
> -		return ret;
> -
> -	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
> -					    3, data->asa);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Not able to read asa data\n");
> -		return ret;
> -	}
> -
> -	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
> -	if (ret < 0)
> -		return ret;
> -
> -	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
> -	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
> -	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
> -
> -	return 0;
> -}
> -
> -static int ak09911_verify_chip_id(struct i2c_client *client)
> -{
> -	u8 wia_val[2];
> -	int ret;
> -
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
> -					    2, wia_val);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -
> -	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
> -
> -	if (wia_val[0] != AK09911_WIA1_VALUE ||
> -		wia_val[1] != AK09911_WIA2_VALUE) {
> -		dev_err(&client->dev, "Device ak09911 not found\n");
> -		return -ENODEV;
> -	}
> -
> -	return 0;
> -}
> -
> -static int wait_conversion_complete_polled(struct ak09911_data *data)
> -{
> -	struct i2c_client *client = data->client;
> -	u8 read_status;
> -	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
> -	int ret;
> -
> -	/* Wait for the conversion to complete. */
> -	while (timeout_ms) {
> -		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
> -		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "Error in reading ST1\n");
> -			return ret;
> -		}
> -		read_status = ret & 0x01;
> -		if (read_status)
> -			break;
> -		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
> -	}
> -	if (!timeout_ms) {
> -		dev_err(&client->dev, "Conversion timeout happened\n");
> -		return -EIO;
> -	}
> -
> -	return read_status;
> -}
> -
> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	struct i2c_client *client = data->client;
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	ret = wait_conversion_complete_polled(data);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	/* Read data */
> -	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Read axis data fails\n");
> -		goto fn_exit;
> -	}
> -
> -	mutex_unlock(&data->lock);
> -
> -	/* Clamp to valid range. */
> -	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
> -
> -	return IIO_VAL_INT;
> -
> -fn_exit:
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static int ak09911_read_raw(struct iio_dev *indio_dev,
> -			    struct iio_chan_spec const *chan,
> -			    int *val, int *val2,
> -			    long mask)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -
> -	switch (mask) {
> -	case IIO_CHAN_INFO_RAW:
> -		return ak09911_read_axis(indio_dev, chan->address, val);
> -	case IIO_CHAN_INFO_SCALE:
> -		*val = 0;
> -		*val2 = data->raw_to_gauss[chan->address];
> -		return IIO_VAL_INT_PLUS_MICRO;
> -	}
> -
> -	return -EINVAL;
> -}
> -
> -#define AK09911_CHANNEL(axis, index)					\
> -	{								\
> -		.type = IIO_MAGN,					\
> -		.modified = 1,						\
> -		.channel2 = IIO_MOD_##axis,				\
> -		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
> -			     BIT(IIO_CHAN_INFO_SCALE),			\
> -		.address = index,					\
> -	}
> -
> -static const struct iio_chan_spec ak09911_channels[] = {
> -	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
> -};
> -
> -static const struct iio_info ak09911_info = {
> -	.read_raw = &ak09911_read_raw,
> -	.driver_module = THIS_MODULE,
> -};
> -
> -static const struct acpi_device_id ak_acpi_match[] = {
> -	{"AK009911", 0},
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> -
> -static int ak09911_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> -{
> -	struct iio_dev *indio_dev;
> -	struct ak09911_data *data;
> -	const char *name;
> -	int ret;
> -
> -	ret = ak09911_verify_chip_id(client);
> -	if (ret) {
> -		dev_err(&client->dev, "AK00911 not detected\n");
> -		return -ENODEV;
> -	}
> -
> -	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> -	if (indio_dev == NULL)
> -		return -ENOMEM;
> -
> -	data = iio_priv(indio_dev);
> -	i2c_set_clientdata(client, indio_dev);
> -
> -	data->client = client;
> -	mutex_init(&data->lock);
> -
> -	ret = ak09911_get_asa(client);
> -	if (ret)
> -		return ret;
> -
> -	if (id)
> -		name = id->name;
> -	else if (ACPI_HANDLE(&client->dev))
> -		name = dev_name(&client->dev);
> -	else
> -		return -ENODEV;
> -
> -	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> -
> -	indio_dev->dev.parent = &client->dev;
> -	indio_dev->channels = ak09911_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
> -	indio_dev->info = &ak09911_info;
> -	indio_dev->modes = INDIO_DIRECT_MODE;
> -	indio_dev->name = name;
> -
> -	return devm_iio_device_register(&client->dev, indio_dev);
> -}
> -
> -static const struct i2c_device_id ak09911_id[] = {
> -	{"ak09911", 0},
> -	{}
> -};
> -
> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
> -
> -static struct i2c_driver ak09911_driver = {
> -	.driver = {
> -		.name	= "ak09911",
> -		.acpi_match_table = ACPI_PTR(ak_acpi_match),
> -	},
> -	.probe		= ak09911_probe,
> -	.id_table	= ak09911_id,
> -};
> -module_i2c_driver(ak09911_driver);
> -
> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
> -MODULE_LICENSE("GPL v2");
> -MODULE_DESCRIPTION("AK09911 Compass driver");
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index bf5ef07..190c21c 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -35,9 +35,10 @@
>  
>  #include <linux/iio/iio.h>
>  #include <linux/iio/sysfs.h>
> +
>  /*
> - * Register definitions, as well as various shifts and masks to get at the
> - * individual fields of the registers.
> + * AK_8975 Register definitions, as well as various shifts and masks to get
> + * at the individual fields of the registers.
>   */
>  #define AK8975_REG_WIA			0x00
>  #define AK8975_DEVICE_ID		0x48
> @@ -62,12 +63,12 @@
>  #define AK8975_REG_ST2_HOFL_MASK	(1 << AK8975_REG_ST2_HOFL_SHIFT)
>  
>  #define AK8975_REG_CNTL			0x0A
> +#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK8975_REG_CNTL_MODE_ONCE	0x01
> +#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
> +#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
>  #define AK8975_REG_CNTL_MODE_SHIFT	0
>  #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
> -#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
> -#define AK8975_REG_CNTL_MODE_ONCE	1
> -#define AK8975_REG_CNTL_MODE_SELF_TEST	8
> -#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
>  
>  #define AK8975_REG_RSVC			0x0B
>  #define AK8975_REG_ASTC			0x0C
> @@ -81,59 +82,369 @@
>  #define AK8975_MAX_REGS			AK8975_REG_ASAZ
>  
>  /*
> - * Miscellaneous values.
> + * AK09912 Register definitions
> + */
> +#define AK09912_REG_WIA1		0x00
> +#define AK09912_COMPANY_ID		0x48
> +#define AK09912_REG_WIA2		0x01
> +#define AK09912_DEVICE_ID		0x04
> +#define AK09911_DEVICE_ID		0x05
> +
> +#define AK09912_REG_INFO1		0x02
> +#define AK09912_REG_INFO2		0x03
These two registers only exist in AK09911.
> +
> +#define AK09912_REG_ST1			0x10
> +
> +#define AK09912_REG_ST1_DRDY_SHIFT	0
> +#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
> +
> +#define AK09912_REG_HXL			0x11
> +#define AK09912_REG_HXH			0x12
> +#define AK09912_REG_HYL			0x13
> +#define AK09912_REG_HYH			0x14
> +#define AK09912_REG_HZL			0x15
> +#define AK09912_REG_HZH			0x16
> +#define AK09912_REG_TMPS		0x17
> +
> +#define AK09912_REG_ST2			0x18
> +#define AK09912_REG_ST2_HOFL_SHIFT	3
> +#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
> +
> +#define AK09912_REG_CNTL1		0x30
> +
> +
> +#define AK09912_REG_CNTL2		0x31
> +#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK09912_REG_CNTL_MODE_ONCE	0x01
> +#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
> +#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
> +#define AK09912_REG_CNTL2_MODE_SHIFT	0
> +#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
> +
> +#define AK09912_REG_CNTL3		0x32
> +
> +#define AK09912_REG_TS1			0x33
> +#define AK09912_REG_TS2			0x34
> +#define AK09912_REG_TS3			0x35
> +#define AK09912_REG_I2CDIS		0x36
> +#define AK09912_REG_TS4			0x37
> +
> +#define AK09912_REG_ASAX		0x60
> +#define AK09912_REG_ASAY		0x61
> +#define AK09912_REG_ASAZ		0x62
> +
> +#define AK09912_MAX_REGS		AK09912_REG_ASAZ
> +
> +
> +/*
> + * Precalculate scale factor (in Gauss units) for each axis and
> + * store in the device data.
> + *
> + * This scale factor is axis-dependent, and is derived from 3 calibration
> + * factors ASA(x), ASA(y), and ASA(z).
> + *
> + * These ASA values are read from the sensor device at start of day, and
> + * cached in the device context struct.
> + *
> + * Adjusting the flux value with the sensitivity adjustment value should be
> + * done via the following formula:
> + *
> + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> + * is the resultant adjusted value.
> + *
> + * We reduce the formula to:
> + *
> + * Hadj = H * (ASA + 128) / 256
> + *
> + * H is in the range of -4096 to 4095.  The magnetometer has a range of
> + * +-1229uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 1229/4096, or roughly, 3/10.
> + *
> + * Since 1uT = 0.01 gauss, our final scale factor becomes:
> + *
> + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> + * Hadj = H * ((ASA + 128) * 0.003) / 256
> + *
> + * Since ASA doesn't change, we cache the resultant scale factor into the
> + * device context in ak8975_setup().
> + */
> +long ak8975_raw_to_gauss(uint16_t data)
You are using types like u16 later in your code as well, so just be consistent. u16 is commonly used and shorter/easier.
> +{
> +	return (((long)data + 128) * 3000) / 256;
I like the verbose explanation, but I somehow missed the part, where 0.003 turned into 3000.
> +}
> +
> +/*
> + * For AK8963, same calculation, except the device is less sensitive:
> + *
> + * H is in the range of +-8190.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
> + */
> +long ak8963_09911_raw_to_gauss(uint16_t data)
> +{
> +	return (((long)data + 128) * 6000) / 256;
> +}
> +
> +/*
> + * For AK09912, same calculation, except the device is more sensitive:
> + *
> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
> + */
> +long ak09912_raw_to_gauss(uint16_t data)
> +{
> +	return (((long)data + 128) * 1500) / 256;
> +}
> +
> +/*
> + * Return 0 if the i2c device is supported,
> + * return a negative error number otherwise
>   */
> -#define AK8975_MAX_CONVERSION_TIMEOUT	500
> -#define AK8975_CONVERSION_DONE_POLL_TIME 10
> -#define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
> -#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
> -#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
> -
> -/* Compatible Asahi Kasei Compass parts */
> -enum asahi_compass_chipset {
> +int ak09912_who_i_am(struct i2c_client *client)
> +{
> +	u8 wia_val[2];
> +	int ret;
> +
> +	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> +					    2, wia_val);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error reading WIA\n");
> +		return ret;
> +	}
> +
> +	if (wia_val[0] != AK09912_COMPANY_ID ||
> +		wia_val[1] != AK09912_DEVICE_ID) {
> +		dev_err(&client->dev, "Device ak09912 not found\n");
> +		return -ENODEV;
> +	}
> +	return 0;
> +}
> +
> +int ak09911_who_i_am(struct i2c_client *client)
> +{
> +	u8 wia_val[2];
> +	int ret;
> +
> +	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> +					    2, wia_val);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error reading WIA\n");
> +		return ret;
> +	}
> +
> +	if (wia_val[0] != AK09912_COMPANY_ID ||
> +		wia_val[1] != AK09912_DEVICE_ID) {
This needs to be compared against AK09911_DEVICE_ID.
> +		dev_err(&client->dev, "Device ak09911 not found\n");
> +		return -ENODEV;
> +	}
> +	return 0;
> +}
> +
> +int ak8975_8963_who_i_am(struct i2c_client *client)
> +{
> +	int device_id;
> +	int ret;
> +	/* Confirm that the device we're talking to is really an AK8975. */
> +	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error reading WIA\n");
> +		return ret;
> +	}
> +	device_id = ret;
> +	if (device_id != AK8975_DEVICE_ID) {
> +		dev_err(&client->dev, "Device ak8975 not found\n");
> +		return -ENODEV;
> +	}
> +	return 0;
> +}
> +
Why not have one generic function with second parameter ak_type? Thus commonly checking WIA for 0x48, and only for ak091x for a valid WIA2?
> +enum ak_type {
>  	AK8975,
>  	AK8963,
> +	AK09911,
> +	AK09912,
> +	AK_MAX_TYPE
> +};
> +
> +enum ak_ctrl_reg_addr {
> +	ST1,
> +	ST2,
> +	CNTL,
> +	ASA_BASE,
> +	MAX_REGS,
> +	REGS_END,
> +};
> +
> +enum ak_ctrl_reg_mask {
> +	ST1_DRDY,
> +	ST2_HOFL,
> +	ST2_DERR,
> +	CNTL_MODE,
> +	MASK_END,
> +};
> +
> +enum ak_ctrl_mode {
> +	POWER_DOWN,
> +	MODE_ONCE,
> +	SELF_TEST,
> +	FUSE_ROM,
> +	MODE_END,
> +};
> +
> +struct akxxxx_def {
> +	int (*who_i_am)(struct i2c_client *client);
> +	long (*raw_to_gauss)(uint16_t data);
> +	uint8_t ctrl_regs[REGS_END];
> +	uint8_t ctrl_masks[MASK_END];
> +	uint8_t ctrl_modes[MODE_END];
> +	uint8_t data_regs[3];
Just use u8 and u16.
> +} akxxxx_def_array[AK_MAX_TYPE] = {
> +{
> +	.who_i_am = ak8975_8963_who_i_am,
> +	.raw_to_gauss = ak8975_raw_to_gauss,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		AK8975_REG_ST2_DERR_MASK,
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
> +{
> +	.who_i_am = ak8975_8963_who_i_am,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		AK8975_REG_ST2_DERR_MASK,
This device doesn't have DERR.
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
> +{
> +	.who_i_am = ak09911_who_i_am,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +},
> +{
> +	.who_i_am = ak09912_who_i_am,
> +	.raw_to_gauss = ak09912_raw_to_gauss,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +}
>  };
>  
>  /*
> + * Miscellaneous values.
> + */
> +#define AKXXXX_MAX_CONVERSION_TIMEOUT	500
> +#define AKXXXX_CONVERSION_DONE_POLL_TIME 10
> +#define AKXXXX_DATA_READY_TIMEOUT	((100*HZ)/1000)
These definitions should be moved up to the other ones.
> +
> +
> +/*
>   * Per-instance context data for the device.
>   */
> -struct ak8975_data {
> +struct akxxxx_data {
>  	struct i2c_client	*client;
> +	struct akxxxx_def       *def;
>  	struct attribute_group	attrs;
>  	struct mutex		lock;
>  	u8			asa[3];
>  	long			raw_to_gauss[3];
> -	u8			reg_cache[AK8975_MAX_REGS];
>  	int			eoc_gpio;
>  	int			eoc_irq;
>  	wait_queue_head_t	data_ready_queue;
>  	unsigned long		flags;
> -	enum asahi_compass_chipset chipset;
> -};
> -
> -static const int ak8975_index_to_reg[] = {
> -	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
> +	u8			cntl_cache;
>  };
>  
>  /*
>   * Helper function to write to the I2C device's registers.
>   */
This comment should be updated or removed.
> -static int ak8975_write_data(struct i2c_client *client,
> -			     u8 reg, u8 val, u8 mask, u8 shift)
> +static int akxxxx_set_mode(struct akxxxx_data *data, enum ak_ctrl_mode mode)
>  {
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak8975_data *data = iio_priv(indio_dev);
>  	u8 regval;
>  	int ret;
>  
> -	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
> -	ret = i2c_smbus_write_byte_data(client, reg, regval);
> +	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
> +		data->def->ctrl_modes[mode];
> +	ret = i2c_smbus_write_byte_data(
> +		data->client, data->def->ctrl_regs[CNTL], regval);
Improve your indentation. Use checkpatch.pl with the strict switch to find these issues.
>  	if (ret < 0) {
> -		dev_err(&client->dev, "Write to device fails status %x\n", ret);
>  		return ret;
>  	}
> -	data->reg_cache[reg] = regval;
> +	data->cntl_cache = regval;
> +	/* After mode change wait atleast 100us */
> +	usleep_range(100, 500);
>  
>  	return 0;
>  }
> @@ -141,9 +452,9 @@ static int ak8975_write_data(struct i2c_client *client,
>  /*
>   * Handle data ready irq
>   */
> -static irqreturn_t ak8975_irq_handler(int irq, void *data)
> +static irqreturn_t akxxxx_irq_handler(int irq, void *data)
>  {
> -	struct ak8975_data *ak8975 = data;
> +	struct akxxxx_data *ak8975 = data;
>  
>  	set_bit(0, &ak8975->flags);
>  	wake_up(&ak8975->data_ready_queue);
> @@ -154,7 +465,7 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data)
>  /*
>   * Install data ready interrupt handler
>   */
> -static int ak8975_setup_irq(struct ak8975_data *data)
> +static int akxxxx_setup_irq(struct akxxxx_data *data)
>  {
>  	struct i2c_client *client = data->client;
>  	int rc;
> @@ -165,7 +476,7 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>  	else
>  		irq = gpio_to_irq(data->eoc_gpio);
>  
> -	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
> +	rc = devm_request_irq(&client->dev, irq, akxxxx_irq_handler,
>  			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
>  			 dev_name(&client->dev), data);
>  	if (rc < 0) {
> @@ -187,53 +498,31 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>   * Perform some start-of-day setup, including reading the asa calibration
>   * values and caching them.
>   */
> -static int ak8975_setup(struct i2c_client *client)
> +static int akxxxx_setup(struct i2c_client *client)
>  {
>  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak8975_data *data = iio_priv(indio_dev);
> -	u8 device_id;
> +	struct akxxxx_data *data = iio_priv(indio_dev);
>  	int ret;
>  
> -	/* Confirm that the device we're talking to is really an AK8975. */
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -	device_id = ret;
> -	if (device_id != AK8975_DEVICE_ID) {
> -		dev_err(&client->dev, "Device ak8975 not found\n");
> -		return -ENODEV;
> -	}
> -
>  	/* Write the fused rom access mode. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_FUSE_ROM,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = akxxxx_set_mode(data, FUSE_ROM);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting fuse access mode\n");
>  		return ret;
>  	}
>  
>  	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
> -					    3, data->asa);
> +	ret = i2c_smbus_read_i2c_block_data(client,
> +			data->def->ctrl_regs[ASA_BASE], 3, data->asa);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Not able to read asa data\n");
>  		return ret;
>  	}
>  
>  	/* After reading fuse ROM data set power-down mode */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_POWER_DOWN,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> -
> +	ret = akxxxx_set_mode(data, POWER_DOWN);
Although it is missing in the original driver: what about checking ret?
And according to the datasheet, you should wait at least 100 µs after setting POWER_DOWN before setting other modes.
>  	if (data->eoc_gpio > 0 || client->irq) {
> -		ret = ak8975_setup_irq(data);
> +		ret = akxxxx_setup_irq(data);
>  		if (ret < 0) {
>  			dev_err(&client->dev,
>  				"Error setting data ready interrupt\n");
> @@ -246,96 +535,50 @@ static int ak8975_setup(struct i2c_client *client)
>  		return ret;
This function is a mess. This check up here (in the original file) belongs below the POWER_DOWN setting! Please take care of it, while you are on it.
>  	}
>  
> -/*
> - * Precalculate scale factor (in Gauss units) for each axis and
> - * store in the device data.
> - *
> - * This scale factor is axis-dependent, and is derived from 3 calibration
> - * factors ASA(x), ASA(y), and ASA(z).
> - *
> - * These ASA values are read from the sensor device at start of day, and
> - * cached in the device context struct.
> - *
> - * Adjusting the flux value with the sensitivity adjustment value should be
> - * done via the following formula:
> - *
> - * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> - *
> - * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> - * is the resultant adjusted value.
> - *
> - * We reduce the formula to:
> - *
> - * Hadj = H * (ASA + 128) / 256
> - *
> - * H is in the range of -4096 to 4095.  The magnetometer has a range of
> - * +-1229uT.  To go from the raw value to uT is:
> - *
> - * HuT = H * 1229/4096, or roughly, 3/10.
> - *
> - * Since 1uT = 0.01 gauss, our final scale factor becomes:
> - *
> - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> - * Hadj = H * ((ASA + 128) * 0.003) / 256
> - *
> - * Since ASA doesn't change, we cache the resultant scale factor into the
> - * device context in ak8975_setup().
> - */
> -	if (data->chipset == AK8963) {
> -		/*
> -		 * H range is +-8190 and magnetometer range is +-4912.
> -		 * So HuT using the above explanation for 8975,
> -		 * 4912/8190 = ~ 6/10.
> -		 * So the Hadj should use 6/10 instead of 3/10.
> -		 */
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
> -	} else {
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
> -	}
> +	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
> +	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
> +	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
>  
>  	return 0;
>  }
>  
> -static int wait_conversion_complete_gpio(struct ak8975_data *data)
> +static int wait_conversion_complete_gpio(struct akxxxx_data *data)
>  {
>  	struct i2c_client *client = data->client;
> -	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
> +	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
>  	int ret;
>  
>  	/* Wait for the conversion to complete. */
>  	while (timeout_ms) {
> -		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> +		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
>  		if (gpio_get_value(data->eoc_gpio))
>  			break;
> -		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
> +		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
>  	}
>  	if (!timeout_ms) {
>  		dev_err(&client->dev, "Conversion timeout happened\n");
>  		return -EINVAL;
>  	}
>  
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
>  	if (ret < 0)
>  		dev_err(&client->dev, "Error in reading ST1\n");
>  
>  	return ret;
>  }
>  
> -static int wait_conversion_complete_polled(struct ak8975_data *data)
> +static int wait_conversion_complete_polled(struct akxxxx_data *data)
>  {
>  	struct i2c_client *client = data->client;
>  	u8 read_status;
> -	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
> +	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
>  	int ret;
>  
>  	/* Wait for the conversion to complete. */
>  	while (timeout_ms) {
> -		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST1]);
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST1\n");
>  			return ret;
> @@ -343,7 +586,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>  		read_status = ret;
>  		if (read_status)
>  			break;
> -		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
> +		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
>  	}
>  	if (!timeout_ms) {
>  		dev_err(&client->dev, "Conversion timeout happened\n");
> @@ -354,13 +597,13 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>  }
>  
>  /* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
> -static int wait_conversion_complete_interrupt(struct ak8975_data *data)
> +static int wait_conversion_complete_interrupt(struct akxxxx_data *data)
>  {
>  	int ret;
>  
>  	ret = wait_event_timeout(data->data_ready_queue,
>  				 test_bit(0, &data->flags),
> -				 AK8975_DATA_READY_TIMEOUT);
> +				 AKXXXX_DATA_READY_TIMEOUT);
>  	clear_bit(0, &data->flags);
>  
>  	return ret > 0 ? 0 : -ETIME;
> @@ -369,20 +612,16 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
>  /*
>   * Emits the raw flux value for the x, y, or z axis.
>   */
> -static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
> +static int akxxxx_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  {
> -	struct ak8975_data *data = iio_priv(indio_dev);
> +	struct akxxxx_data *data = iio_priv(indio_dev);
>  	struct i2c_client *client = data->client;
>  	int ret;
>  
>  	mutex_lock(&data->lock);
>  
>  	/* Set up the device for taking a sample. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_ONCE,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = akxxxx_set_mode(data, MODE_ONCE);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting operating mode\n");
>  		goto exit;
> @@ -399,14 +638,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  		goto exit;
>  
>  	/* This will be executed only for non-interrupt based waiting case */
> -	if (ret & AK8975_REG_ST1_DRDY_MASK) {
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
> +	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST2]);
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST2\n");
>  			goto exit;
>  		}
> -		if (ret & (AK8975_REG_ST2_DERR_MASK |
> -			   AK8975_REG_ST2_HOFL_MASK)) {
> +		if (ret & (data->def->ctrl_masks[ST2_DERR] |
> +			   data->def->ctrl_masks[ST2_HOFL])) {
>  			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
>  			ret = -EINVAL;
>  			goto exit;
> @@ -415,7 +655,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  
>  	/* Read the flux value from the appropriate register
>  	   (the register is specified in the iio device attributes). */
> -	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
> +	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Read axis data fails\n");
>  		goto exit;
The original driver does some value clamping in the following lines. Since the resolution on the new supported devices is different, you need to adjust the clamping.
> @@ -432,16 +672,16 @@ exit:
>  	return ret;
>  }
>  
> -static int ak8975_read_raw(struct iio_dev *indio_dev,
> +static int akxxxx_read_raw(struct iio_dev *indio_dev,
>  			   struct iio_chan_spec const *chan,
>  			   int *val, int *val2,
>  			   long mask)
>  {
> -	struct ak8975_data *data = iio_priv(indio_dev);
> +	struct akxxxx_data *data = iio_priv(indio_dev);
>  
>  	switch (mask) {
>  	case IIO_CHAN_INFO_RAW:
> -		return ak8975_read_axis(indio_dev, chan->address, val);
> +		return akxxxx_read_axis(indio_dev, chan->address, val);
>  	case IIO_CHAN_INFO_SCALE:
>  		*val = 0;
>  		*val2 = data->raw_to_gauss[chan->address];
> @@ -450,7 +690,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
>  	return -EINVAL;
>  }
>  
> -#define AK8975_CHANNEL(axis, index)					\
> +#define AKXXXX_CHANNEL(axis, index)					\
>  	{								\
>  		.type = IIO_MAGN,					\
>  		.modified = 1,						\
> @@ -460,40 +700,41 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
>  		.address = index,					\
>  	}
>  
> -static const struct iio_chan_spec ak8975_channels[] = {
> -	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
> +static const struct iio_chan_spec akxxxx_channels[] = {
> +	AKXXXX_CHANNEL(X, 0), AKXXXX_CHANNEL(Y, 1), AKXXXX_CHANNEL(Z, 2),
>  };
>  
> -static const struct iio_info ak8975_info = {
> -	.read_raw = &ak8975_read_raw,
> +static const struct iio_info akxxxx_info = {
> +	.read_raw = &akxxxx_read_raw,
>  	.driver_module = THIS_MODULE,
>  };
>  
> -static const struct acpi_device_id ak_acpi_match[] = {
> -	{"AK8975", AK8975},
> -	{"AK8963", AK8963},
> -	{"INVN6500", AK8963},
> +static const struct acpi_device_id akxxxx_acpi_match[] = {
> +	{"AK8975", (uintptr_t)&akxxxx_def_array[AK8975]},
> +	{"AK8963", (uintptr_t)&akxxxx_def_array[AK8963]},
> +	{"AK09911", (uintptr_t)&akxxxx_def_array[AK09911]},
> +	{"AK09912", (uintptr_t)&akxxxx_def_array[AK09912]},
>  	{ },
>  };
> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> +MODULE_DEVICE_TABLE(acpi, akxxxx_acpi_match);
>  
> -static const char *ak8975_match_acpi_device(struct device *dev,
> -					    enum asahi_compass_chipset *chipset)
> +static const char *akxxxx_match_acpi_device(struct device *dev,
> +					    struct akxxxx_def **def)
>  {
>  	const struct acpi_device_id *id;
>  
>  	id = acpi_match_device(dev->driver->acpi_match_table, dev);
>  	if (!id)
>  		return NULL;
> -	*chipset = (int)id->driver_data;
> +	*def = (struct akxxxx_def *)id->driver_data;
>  
>  	return dev_name(dev);
>  }
>  
> -static int ak8975_probe(struct i2c_client *client,
> +static int akxxxx_probe(struct i2c_client *client,
>  			const struct i2c_device_id *id)
>  {
> -	struct ak8975_data *data;
> +	struct akxxxx_data *data;
>  	struct iio_dev *indio_dev;
>  	int eoc_gpio;
>  	int err;
> @@ -513,8 +754,8 @@ static int ak8975_probe(struct i2c_client *client,
>  	/* We may not have a GPIO based IRQ to scan, that is fine, we will
>  	   poll if so */
>  	if (gpio_is_valid(eoc_gpio)) {
> -		err = devm_gpio_request_one(&client->dev, eoc_gpio,
> -							GPIOF_IN, "ak_8975");
> +		err = devm_gpio_request_one(
> +			&client->dev, eoc_gpio, GPIOF_IN, id->name);
>  		if (err < 0) {
>  			dev_err(&client->dev,
>  				"failed to request GPIO %d, error %d\n",
> @@ -534,23 +775,27 @@ static int ak8975_probe(struct i2c_client *client,
>  	data->client = client;
>  	data->eoc_gpio = eoc_gpio;
>  	data->eoc_irq = 0;
> -
>  	/* id will be NULL when enumerated via ACPI */
>  	if (id) {
> -		data->chipset =
> -			(enum asahi_compass_chipset)(id->driver_data);
> +		data->def = (struct akxxxx_def *)id->driver_data;
>  		name = id->name;
>  	} else if (ACPI_HANDLE(&client->dev))
> -		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
> +		name = akxxxx_match_acpi_device(&client->dev, &data->def);
>  	else
>  		return -ENOSYS;
>  
> +	if (data->def->who_i_am(client) < 0) {
> +		dev_err(&client->dev, "Unexpected device\n");
> +		return -ENODEV;
> +	}
> +
> +	/* id will be NULL when enumerated via ACPI */
Do we need this comment again?
>  	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>  
>  	/* Perform some basic start-of-day setup of the device. */
> -	err = ak8975_setup(client);
> +	err = akxxxx_setup(client);
>  	if (err < 0) {
> -		dev_err(&client->dev, "AK8975 initialization fails\n");
> +		dev_err(&client->dev, "%s initialization fails\n", name);
>  		return err;
>  	}
>  
> @@ -558,9 +803,9 @@ static int ak8975_probe(struct i2c_client *client,
>  	mutex_init(&data->lock);
>  	data->eoc_gpio = eoc_gpio;
>  	indio_dev->dev.parent = &client->dev;
> -	indio_dev->channels = ak8975_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
> -	indio_dev->info = &ak8975_info;
> +	indio_dev->channels = akxxxx_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(akxxxx_channels);
> +	indio_dev->info = &akxxxx_info;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  	indio_dev->name = name;
>  	err = devm_iio_device_register(&client->dev, indio_dev);
> @@ -570,32 +815,48 @@ static int ak8975_probe(struct i2c_client *client,
>  	return 0;
>  }
>  
> -static const struct i2c_device_id ak8975_id[] = {
> -	{"ak8975", AK8975},
> -	{"ak8963", AK8963},
> +static const struct i2c_device_id akxxxx_id[] = {
> +	{"ak8975", (uintptr_t)&akxxxx_def_array[AK8975]},
> +	{"ak8963", (uintptr_t)&akxxxx_def_array[AK8963]},
> +	{"ak09911", (uintptr_t)&akxxxx_def_array[AK09911]},
> +	{"ak09912", (uintptr_t)&akxxxx_def_array[AK09912]},
>  	{}
>  };
>  
> -MODULE_DEVICE_TABLE(i2c, ak8975_id);
> -
> -static const struct of_device_id ak8975_of_match[] = {
> -	{ .compatible = "asahi-kasei,ak8975", },
> -	{ .compatible = "ak8975", },
> +MODULE_DEVICE_TABLE(i2c, akxxxx_id);
> +
> +static const struct of_device_id akxxxx_of_match[] = {
> +	{ .compatible = "asahi-kasei,ak8975",
> +	  .data = &akxxxx_def_array[AK8975]},
> +	{ .compatible = "ak8975",
> +	  .data = &akxxxx_def_array[AK8975]},
> +	{ .compatible = "asahi-kasei,ak8963",
> +	  .data = &akxxxx_def_array[AK8963]},
> +	{ .compatible = "ak8963",
> +	  .data = &akxxxx_def_array[AK8963]},
> +	{ .compatible = "asahi-kasei,ak09911",
> +	  .data = &akxxxx_def_array[AK09911]},
> +	{ .compatible = "ak09911",
> +	  .data = &akxxxx_def_array[AK09911]},
> +	{ .compatible = "asahi-kasei,ak09912",
> +	  .data = &akxxxx_def_array[AK09912]},
> +	{ .compatible = "ak09912",
> +	  .data = &akxxxx_def_array[AK09912]},
>  	{ }
>  };
> -MODULE_DEVICE_TABLE(of, ak8975_of_match);
> +MODULE_DEVICE_TABLE(of, akxxxx_of_match);
>  
> -static struct i2c_driver ak8975_driver = {
> +static struct i2c_driver akxxxx_driver = {
>  	.driver = {
> -		.name	= "ak8975",
> -		.of_match_table = ak8975_of_match,
> -		.acpi_match_table = ACPI_PTR(ak_acpi_match),
> +		.name	= "akxxxx",
> +		.of_match_table = of_match_ptr(akxxxx_of_match),
> +		.acpi_match_table = ACPI_PTR(akxxxx_acpi_match),
>  	},
> -	.probe		= ak8975_probe,
> -	.id_table	= ak8975_id,
> +	.probe		= akxxxx_probe,
> +	.id_table	= akxxxx_id,
>  };
> -module_i2c_driver(ak8975_driver);
> +module_i2c_driver(akxxxx_driver);
>  
>  MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
> -MODULE_DESCRIPTION("AK8975 magnetometer driver");
> +MODULE_DESCRIPTION("ak8975 and ak09912 magnetometer driver");
>  MODULE_LICENSE("GPL");
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCHv2] iio: ak8975: Add AKM0991x support.
  2014-11-03 22:22   ` Hartmut Knaack
@ 2014-11-04 19:41     ` Gwendal Grignou
  2014-11-05 14:31       ` Jonathan Cameron
  0 siblings, 1 reply; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-04 19:41 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23, knaack.h; +Cc: linux-iio, Gwendal Grignou

File and config id remains the same, but driver is now named akxxxx.
Move AKM09911 support in the same file.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---

Addressed all comments from Hartmut.

 drivers/iio/magnetometer/Kconfig   |  19 +-
 drivers/iio/magnetometer/Makefile  |   1 -
 drivers/iio/magnetometer/ak09911.c | 326 -------------------
 drivers/iio/magnetometer/ak8975.c  | 629 ++++++++++++++++++++++++++-----------
 4 files changed, 444 insertions(+), 531 deletions(-)
 delete mode 100644 drivers/iio/magnetometer/ak09911.c

diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index b2dba9e..67f005d 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -6,26 +6,15 @@
 menu "Magnetometer sensors"
 
 config AK8975
-	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+	tristate "Asahi Kasei AK 3-Axis Magnetometer"
 	depends on I2C
 	depends on GPIOLIB
 	help
-	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
-	  Magnetometer. This driver can also support AK8963, if i2c
-	  device name is identified as ak8963.
+	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
+	  AK09911 or AK09912 3-Axis Magnetometer.
 
 	  To compile this driver as a module, choose M here: the module
-	  will be called ak8975.
-
-config AK09911
-	tristate "Asahi Kasei AK09911 3-axis Compass"
-	depends on I2C
-	help
-	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
-	  Magnetometer.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called ak09911.
+	  will be called akxxxx.
 
 config MAG3110
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b91315e..0f5d3c9 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,7 +3,6 @@
 #
 
 # When adding new entries keep the list in alphabetical order
-obj-$(CONFIG_AK09911)	+= ak09911.o
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
deleted file mode 100644
index b2bc942..0000000
--- a/drivers/iio/magnetometer/ak09911.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * AK09911 3-axis compass driver
- * Copyright (c) 2014, 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/iio/iio.h>
-
-#define AK09911_REG_WIA1		0x00
-#define AK09911_REG_WIA2		0x01
-#define AK09911_WIA1_VALUE		0x48
-#define AK09911_WIA2_VALUE		0x05
-
-#define AK09911_REG_ST1			0x10
-#define AK09911_REG_HXL			0x11
-#define AK09911_REG_HXH			0x12
-#define AK09911_REG_HYL			0x13
-#define AK09911_REG_HYH			0x14
-#define AK09911_REG_HZL			0x15
-#define AK09911_REG_HZH			0x16
-
-#define AK09911_REG_ASAX		0x60
-#define AK09911_REG_ASAY		0x61
-#define AK09911_REG_ASAZ		0x62
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_MODE_SNG_MEASURE	0x01
-#define AK09911_MODE_SELF_TEST		0x10
-#define AK09911_MODE_FUSE_ACCESS	0x1F
-#define AK09911_MODE_POWERDOWN		0x00
-#define AK09911_RESET_DATA		0x01
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
-
-#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
-#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
-
-struct ak09911_data {
-	struct i2c_client	*client;
-	struct mutex		lock;
-	u8			asa[3];
-	long			raw_to_gauss[3];
-};
-
-static const int ak09911_index_to_reg[] = {
-	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
-};
-
-static int ak09911_set_mode(struct i2c_client *client, u8 mode)
-{
-	int ret;
-
-	switch (mode) {
-	case AK09911_MODE_SNG_MEASURE:
-	case AK09911_MODE_SELF_TEST:
-	case AK09911_MODE_FUSE_ACCESS:
-	case AK09911_MODE_POWERDOWN:
-		ret = i2c_smbus_write_byte_data(client,
-						AK09911_REG_CNTL2, mode);
-		if (ret < 0) {
-			dev_err(&client->dev, "set_mode error\n");
-			return ret;
-		}
-		/* After mode change wait atleast 100us */
-		usleep_range(100, 500);
-		break;
-	default:
-		dev_err(&client->dev,
-			"%s: Unknown mode(%d).", __func__, mode);
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-/* Get Sensitivity Adjustment value */
-static int ak09911_get_asa(struct i2c_client *client)
-{
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak09911_data *data = iio_priv(indio_dev);
-	int ret;
-
-	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
-	if (ret < 0)
-		return ret;
-
-	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
-					    3, data->asa);
-	if (ret < 0) {
-		dev_err(&client->dev, "Not able to read asa data\n");
-		return ret;
-	}
-
-	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
-	if (ret < 0)
-		return ret;
-
-	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
-	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
-	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
-
-	return 0;
-}
-
-static int ak09911_verify_chip_id(struct i2c_client *client)
-{
-	u8 wia_val[2];
-	int ret;
-
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
-					    2, wia_val);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-
-	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
-
-	if (wia_val[0] != AK09911_WIA1_VALUE ||
-		wia_val[1] != AK09911_WIA2_VALUE) {
-		dev_err(&client->dev, "Device ak09911 not found\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int wait_conversion_complete_polled(struct ak09911_data *data)
-{
-	struct i2c_client *client = data->client;
-	u8 read_status;
-	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
-	int ret;
-
-	/* Wait for the conversion to complete. */
-	while (timeout_ms) {
-		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
-		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
-		if (ret < 0) {
-			dev_err(&client->dev, "Error in reading ST1\n");
-			return ret;
-		}
-		read_status = ret & 0x01;
-		if (read_status)
-			break;
-		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
-	}
-	if (!timeout_ms) {
-		dev_err(&client->dev, "Conversion timeout happened\n");
-		return -EIO;
-	}
-
-	return read_status;
-}
-
-static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	int ret;
-
-	mutex_lock(&data->lock);
-
-	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
-	if (ret < 0)
-		goto fn_exit;
-
-	ret = wait_conversion_complete_polled(data);
-	if (ret < 0)
-		goto fn_exit;
-
-	/* Read data */
-	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
-	if (ret < 0) {
-		dev_err(&client->dev, "Read axis data fails\n");
-		goto fn_exit;
-	}
-
-	mutex_unlock(&data->lock);
-
-	/* Clamp to valid range. */
-	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
-
-	return IIO_VAL_INT;
-
-fn_exit:
-	mutex_unlock(&data->lock);
-
-	return ret;
-}
-
-static int ak09911_read_raw(struct iio_dev *indio_dev,
-			    struct iio_chan_spec const *chan,
-			    int *val, int *val2,
-			    long mask)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		return ak09911_read_axis(indio_dev, chan->address, val);
-	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = data->raw_to_gauss[chan->address];
-		return IIO_VAL_INT_PLUS_MICRO;
-	}
-
-	return -EINVAL;
-}
-
-#define AK09911_CHANNEL(axis, index)					\
-	{								\
-		.type = IIO_MAGN,					\
-		.modified = 1,						\
-		.channel2 = IIO_MOD_##axis,				\
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
-			     BIT(IIO_CHAN_INFO_SCALE),			\
-		.address = index,					\
-	}
-
-static const struct iio_chan_spec ak09911_channels[] = {
-	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
-};
-
-static const struct iio_info ak09911_info = {
-	.read_raw = &ak09911_read_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct acpi_device_id ak_acpi_match[] = {
-	{"AK009911", 0},
-	{ },
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
-static int ak09911_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	struct iio_dev *indio_dev;
-	struct ak09911_data *data;
-	const char *name;
-	int ret;
-
-	ret = ak09911_verify_chip_id(client);
-	if (ret) {
-		dev_err(&client->dev, "AK00911 not detected\n");
-		return -ENODEV;
-	}
-
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
-	if (indio_dev == NULL)
-		return -ENOMEM;
-
-	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-
-	data->client = client;
-	mutex_init(&data->lock);
-
-	ret = ak09911_get_asa(client);
-	if (ret)
-		return ret;
-
-	if (id)
-		name = id->name;
-	else if (ACPI_HANDLE(&client->dev))
-		name = dev_name(&client->dev);
-	else
-		return -ENODEV;
-
-	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
-
-	indio_dev->dev.parent = &client->dev;
-	indio_dev->channels = ak09911_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
-	indio_dev->info = &ak09911_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->name = name;
-
-	return devm_iio_device_register(&client->dev, indio_dev);
-}
-
-static const struct i2c_device_id ak09911_id[] = {
-	{"ak09911", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, ak09911_id);
-
-static struct i2c_driver ak09911_driver = {
-	.driver = {
-		.name	= "ak09911",
-		.acpi_match_table = ACPI_PTR(ak_acpi_match),
-	},
-	.probe		= ak09911_probe,
-	.id_table	= ak09911_id,
-};
-module_i2c_driver(ak09911_driver);
-
-MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("AK09911 Compass driver");
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index bf5ef07..f2ec32f 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -35,12 +35,14 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+
+#define AKXXXX_COMPANY_ID		0x48
+
 /*
- * Register definitions, as well as various shifts and masks to get at the
- * individual fields of the registers.
+ * AK_8975 Register definitions, as well as various shifts and masks to get
+ * at the individual fields of the registers.
  */
 #define AK8975_REG_WIA			0x00
-#define AK8975_DEVICE_ID		0x48
 
 #define AK8975_REG_INFO			0x01
 
@@ -62,12 +64,12 @@
 #define AK8975_REG_ST2_HOFL_MASK	(1 << AK8975_REG_ST2_HOFL_SHIFT)
 
 #define AK8975_REG_CNTL			0x0A
+#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK8975_REG_CNTL_MODE_ONCE	0x01
+#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
+#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
 #define AK8975_REG_CNTL_MODE_SHIFT	0
 #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
-#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
-#define AK8975_REG_CNTL_MODE_ONCE	1
-#define AK8975_REG_CNTL_MODE_SELF_TEST	8
-#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
 
 #define AK8975_REG_RSVC			0x0B
 #define AK8975_REG_ASTC			0x0C
@@ -81,59 +83,359 @@
 #define AK8975_MAX_REGS			AK8975_REG_ASAZ
 
 /*
+ * AK09912 Register definitions
+ */
+#define AK09912_REG_WIA1		0x00
+#define AK09912_REG_WIA2		0x01
+#define AK09912_DEVICE_ID		0x04
+#define AK09911_DEVICE_ID		0x05
+
+#define AK09911_REG_INFO1		0x02
+#define AK09911_REG_INFO2		0x03
+
+#define AK09912_REG_ST1			0x10
+
+#define AK09912_REG_ST1_DRDY_SHIFT	0
+#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
+
+#define AK09912_REG_HXL			0x11
+#define AK09912_REG_HXH			0x12
+#define AK09912_REG_HYL			0x13
+#define AK09912_REG_HYH			0x14
+#define AK09912_REG_HZL			0x15
+#define AK09912_REG_HZH			0x16
+#define AK09912_REG_TMPS		0x17
+
+#define AK09912_REG_ST2			0x18
+#define AK09912_REG_ST2_HOFL_SHIFT	3
+#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
+
+#define AK09912_REG_CNTL1		0x30
+
+#define AK09912_REG_CNTL2		0x31
+#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK09912_REG_CNTL_MODE_ONCE	0x01
+#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
+#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
+#define AK09912_REG_CNTL2_MODE_SHIFT	0
+#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
+
+#define AK09912_REG_CNTL3		0x32
+
+#define AK09912_REG_TS1			0x33
+#define AK09912_REG_TS2			0x34
+#define AK09912_REG_TS3			0x35
+#define AK09912_REG_I2CDIS		0x36
+#define AK09912_REG_TS4			0x37
+
+#define AK09912_REG_ASAX		0x60
+#define AK09912_REG_ASAY		0x61
+#define AK09912_REG_ASAZ		0x62
+
+#define AK09912_MAX_REGS		AK09912_REG_ASAZ
+
+/*
  * Miscellaneous values.
  */
-#define AK8975_MAX_CONVERSION_TIMEOUT	500
-#define AK8975_CONVERSION_DONE_POLL_TIME 10
-#define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
-#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
-#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
-
-/* Compatible Asahi Kasei Compass parts */
-enum asahi_compass_chipset {
+#define AKXXXX_MAX_CONVERSION_TIMEOUT	500
+#define AKXXXX_CONVERSION_DONE_POLL_TIME 10
+#define AKXXXX_DATA_READY_TIMEOUT	((100*HZ)/1000)
+
+/*
+ * Precalculate scale factor (in Gauss units) for each axis and
+ * store in the device data.
+ *
+ * This scale factor is axis-dependent, and is derived from 3 calibration
+ * factors ASA(x), ASA(y), and ASA(z).
+ *
+ * These ASA values are read from the sensor device at start of day, and
+ * cached in the device context struct.
+ *
+ * Adjusting the flux value with the sensitivity adjustment value should be
+ * done via the following formula:
+ *
+ * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
+ * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
+ * is the resultant adjusted value.
+ *
+ * We reduce the formula to:
+ *
+ * Hadj = H * (ASA + 128) / 256
+ *
+ * H is in the range of -4096 to 4095.  The magnetometer has a range of
+ * +-1229uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 1229/4096, or roughly, 3/10.
+ *
+ * Since 1uT = 0.01 gauss, our final scale factor becomes:
+ *
+ * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
+ * Hadj = H * ((ASA + 128) * 0.003) / 256
+ *
+ * Since ASA doesn't change, we cache the resultant scale factor into the
+ * device context in akxxxx_setup().
+ *
+ * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
+ * multiply the stored scale value by 1e6.
+ */
+long ak8975_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 3000) / 256;
+}
+
+/*
+ * For AK8963 and AK09911, same calculation, but the device is less sensitive:
+ *
+ * H is in the range of +-8190.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
+ */
+long ak8963_09911_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 6000) / 256;
+}
+
+/*
+ * For AK09912, same calculation, except the device is more sensitive:
+ *
+ * H is in the range of -32752 to 32752.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
+ */
+long ak09912_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 1500) / 256;
+}
+
+enum ak_type {
 	AK8975,
 	AK8963,
+	AK09911,
+	AK09912,
+	AK_MAX_TYPE
+};
+
+enum ak_ctrl_reg_addr {
+	ST1,
+	ST2,
+	CNTL,
+	ASA_BASE,
+	MAX_REGS,
+	REGS_END,
+};
+
+enum ak_ctrl_reg_mask {
+	ST1_DRDY,
+	ST2_HOFL,
+	ST2_DERR,
+	CNTL_MODE,
+	MASK_END,
+};
+
+enum ak_ctrl_mode {
+	POWER_DOWN,
+	MODE_ONCE,
+	SELF_TEST,
+	FUSE_ROM,
+	MODE_END,
+};
+
+struct akxxxx_def {
+	enum ak_type type;
+	long (*raw_to_gauss)(u16 data);
+	u16 range;
+	u8 ctrl_regs[REGS_END];
+	u8 ctrl_masks[MASK_END];
+	u8 ctrl_modes[MODE_END];
+	u8 data_regs[3];
+} akxxxx_def_array[AK_MAX_TYPE] = {
+{
+	.type = AK8975,
+	.raw_to_gauss = ak8975_raw_to_gauss,
+	.range = 4096,
+	.ctrl_regs = {
+		AK8975_REG_ST1,
+		AK8975_REG_ST2,
+		AK8975_REG_CNTL,
+		AK8975_REG_ASAX,
+		AK8975_MAX_REGS},
+	.ctrl_masks = {
+		AK8975_REG_ST1_DRDY_MASK,
+		AK8975_REG_ST2_HOFL_MASK,
+		AK8975_REG_ST2_DERR_MASK,
+		AK8975_REG_CNTL_MODE_MASK},
+	.ctrl_modes = {
+		AK8975_REG_CNTL_MODE_POWER_DOWN,
+		AK8975_REG_CNTL_MODE_ONCE,
+		AK8975_REG_CNTL_MODE_SELF_TEST,
+		AK8975_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK8975_REG_HXL,
+		AK8975_REG_HYL,
+		AK8975_REG_HZL},
+},
+{
+	.type = AK8963,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
+	.range = 8190,
+	.ctrl_regs = {
+		AK8975_REG_ST1,
+		AK8975_REG_ST2,
+		AK8975_REG_CNTL,
+		AK8975_REG_ASAX,
+		AK8975_MAX_REGS},
+	.ctrl_masks = {
+		AK8975_REG_ST1_DRDY_MASK,
+		AK8975_REG_ST2_HOFL_MASK,
+		0,
+		AK8975_REG_CNTL_MODE_MASK},
+	.ctrl_modes = {
+		AK8975_REG_CNTL_MODE_POWER_DOWN,
+		AK8975_REG_CNTL_MODE_ONCE,
+		AK8975_REG_CNTL_MODE_SELF_TEST,
+		AK8975_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK8975_REG_HXL,
+		AK8975_REG_HYL,
+		AK8975_REG_HZL},
+},
+{
+	.type = AK09911,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
+	.range = 8192,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+},
+{
+	.type = AK09912,
+	.raw_to_gauss = ak09912_raw_to_gauss,
+	.range = 32752,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+}
 };
 
 /*
  * Per-instance context data for the device.
  */
-struct ak8975_data {
+struct akxxxx_data {
 	struct i2c_client	*client;
+	struct akxxxx_def       *def;
 	struct attribute_group	attrs;
 	struct mutex		lock;
 	u8			asa[3];
 	long			raw_to_gauss[3];
-	u8			reg_cache[AK8975_MAX_REGS];
 	int			eoc_gpio;
 	int			eoc_irq;
 	wait_queue_head_t	data_ready_queue;
 	unsigned long		flags;
-	enum asahi_compass_chipset chipset;
+	u8			cntl_cache;
 };
 
-static const int ak8975_index_to_reg[] = {
-	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
-};
+/*
+ * Return 0 if the i2c device is the one we expect.
+ * return a negative error number otherwise
+ */
+static int akxxxx_who_i_am(struct i2c_client *client, enum ak_type type)
+{
+	u8 wia_val[2];
+	int ret;
+
+	/*
+	 * Signature for each device:
+	 * Device   |  WIA1       |  WIA2
+	 * AK09912  |  COMPANY_ID |  AK09912_DEVICE_ID
+	 * AK09911  |  COMPANY_ID |  AK09911_DEVICE_ID
+	 * AK8975   |  COMPANY_ID |  NA
+	 * AK8963   |  COMPANY_ID |  NA
+	 */
+	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
+					    2, wia_val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return ret;
+	}
+
+	ret = -ENODEV;
+
+	if (wia_val[0] != AKXXXX_COMPANY_ID)
+		return ret;
+
+	switch (type) {
+	case AK8975:
+	case AK8963:
+		ret = 0;
+		break;
+	case AK09911:
+		if (wia_val[1] == AK09911_DEVICE_ID)
+			ret = 0;
+		break;
+	case AK09912:
+		if (wia_val[1] == AK09912_DEVICE_ID)
+			ret = 0;
+		break;
+	default:
+		dev_err(&client->dev, "Type %d unknown\n", type);
+	}
+	return ret;
+}
 
 /*
- * Helper function to write to the I2C device's registers.
+ * Helper function to write to CNTL register.
  */
-static int ak8975_write_data(struct i2c_client *client,
-			     u8 reg, u8 val, u8 mask, u8 shift)
+static int akxxxx_set_mode(struct akxxxx_data *data, enum ak_ctrl_mode mode)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak8975_data *data = iio_priv(indio_dev);
 	u8 regval;
 	int ret;
 
-	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
-	ret = i2c_smbus_write_byte_data(client, reg, regval);
+	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
+		data->def->ctrl_modes[mode];
+	ret = i2c_smbus_write_byte_data(
+		data->client, data->def->ctrl_regs[CNTL], regval);
 	if (ret < 0) {
-		dev_err(&client->dev, "Write to device fails status %x\n", ret);
 		return ret;
 	}
-	data->reg_cache[reg] = regval;
+	data->cntl_cache = regval;
+	/* After mode change wait atleast 100us */
+	usleep_range(100, 500);
 
 	return 0;
 }
@@ -141,9 +443,9 @@ static int ak8975_write_data(struct i2c_client *client,
 /*
  * Handle data ready irq
  */
-static irqreturn_t ak8975_irq_handler(int irq, void *data)
+static irqreturn_t akxxxx_irq_handler(int irq, void *data)
 {
-	struct ak8975_data *ak8975 = data;
+	struct akxxxx_data *ak8975 = data;
 
 	set_bit(0, &ak8975->flags);
 	wake_up(&ak8975->data_ready_queue);
@@ -154,7 +456,7 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data)
 /*
  * Install data ready interrupt handler
  */
-static int ak8975_setup_irq(struct ak8975_data *data)
+static int akxxxx_setup_irq(struct akxxxx_data *data)
 {
 	struct i2c_client *client = data->client;
 	int rc;
@@ -165,9 +467,9 @@ static int ak8975_setup_irq(struct ak8975_data *data)
 	else
 		irq = gpio_to_irq(data->eoc_gpio);
 
-	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
-			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-			 dev_name(&client->dev), data);
+	rc = devm_request_irq(&client->dev, irq, akxxxx_irq_handler,
+			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			      dev_name(&client->dev), data);
 	if (rc < 0) {
 		dev_err(&client->dev,
 			"irq %d request failed, (gpio %d): %d\n",
@@ -187,38 +489,22 @@ static int ak8975_setup_irq(struct ak8975_data *data)
  * Perform some start-of-day setup, including reading the asa calibration
  * values and caching them.
  */
-static int ak8975_setup(struct i2c_client *client)
+static int akxxxx_setup(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak8975_data *data = iio_priv(indio_dev);
-	u8 device_id;
+	struct akxxxx_data *data = iio_priv(indio_dev);
 	int ret;
 
-	/* Confirm that the device we're talking to is really an AK8975. */
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-	device_id = ret;
-	if (device_id != AK8975_DEVICE_ID) {
-		dev_err(&client->dev, "Device ak8975 not found\n");
-		return -ENODEV;
-	}
-
 	/* Write the fused rom access mode. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_FUSE_ROM,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = akxxxx_set_mode(data, FUSE_ROM);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting fuse access mode\n");
 		return ret;
 	}
 
 	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
+	ret = i2c_smbus_read_i2c_block_data(client,
+					    data->def->ctrl_regs[ASA_BASE],
 					    3, data->asa);
 	if (ret < 0) {
 		dev_err(&client->dev, "Not able to read asa data\n");
@@ -226,14 +512,14 @@ static int ak8975_setup(struct i2c_client *client)
 	}
 
 	/* After reading fuse ROM data set power-down mode */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_POWER_DOWN,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = akxxxx_set_mode(data, POWER_DOWN);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error in setting power-down mode\n");
+		return ret;
+	}
 
 	if (data->eoc_gpio > 0 || client->irq) {
-		ret = ak8975_setup_irq(data);
+		ret = akxxxx_setup_irq(data);
 		if (ret < 0) {
 			dev_err(&client->dev,
 				"Error setting data ready interrupt\n");
@@ -241,101 +527,50 @@ static int ak8975_setup(struct i2c_client *client)
 		}
 	}
 
-	if (ret < 0) {
-		dev_err(&client->dev, "Error in setting power-down mode\n");
-		return ret;
-	}
-
-/*
- * Precalculate scale factor (in Gauss units) for each axis and
- * store in the device data.
- *
- * This scale factor is axis-dependent, and is derived from 3 calibration
- * factors ASA(x), ASA(y), and ASA(z).
- *
- * These ASA values are read from the sensor device at start of day, and
- * cached in the device context struct.
- *
- * Adjusting the flux value with the sensitivity adjustment value should be
- * done via the following formula:
- *
- * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
- *
- * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
- * is the resultant adjusted value.
- *
- * We reduce the formula to:
- *
- * Hadj = H * (ASA + 128) / 256
- *
- * H is in the range of -4096 to 4095.  The magnetometer has a range of
- * +-1229uT.  To go from the raw value to uT is:
- *
- * HuT = H * 1229/4096, or roughly, 3/10.
- *
- * Since 1uT = 0.01 gauss, our final scale factor becomes:
- *
- * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
- * Hadj = H * ((ASA + 128) * 0.003) / 256
- *
- * Since ASA doesn't change, we cache the resultant scale factor into the
- * device context in ak8975_setup().
- */
-	if (data->chipset == AK8963) {
-		/*
-		 * H range is +-8190 and magnetometer range is +-4912.
-		 * So HuT using the above explanation for 8975,
-		 * 4912/8190 = ~ 6/10.
-		 * So the Hadj should use 6/10 instead of 3/10.
-		 */
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
-	} else {
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
-	}
+	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
+	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
+	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
 
 	return 0;
 }
 
-static int wait_conversion_complete_gpio(struct ak8975_data *data)
+static int wait_conversion_complete_gpio(struct akxxxx_data *data)
 {
 	struct i2c_client *client = data->client;
-	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
+	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
 	int ret;
 
 	/* Wait for the conversion to complete. */
 	while (timeout_ms) {
-		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
+		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
 		if (gpio_get_value(data->eoc_gpio))
 			break;
-		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
+		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
 	}
 	if (!timeout_ms) {
 		dev_err(&client->dev, "Conversion timeout happened\n");
 		return -EINVAL;
 	}
 
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
 	if (ret < 0)
 		dev_err(&client->dev, "Error in reading ST1\n");
 
 	return ret;
 }
 
-static int wait_conversion_complete_polled(struct ak8975_data *data)
+static int wait_conversion_complete_polled(struct akxxxx_data *data)
 {
 	struct i2c_client *client = data->client;
 	u8 read_status;
-	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
+	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
 	int ret;
 
 	/* Wait for the conversion to complete. */
 	while (timeout_ms) {
-		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
+		ret = i2c_smbus_read_byte_data(
+				client, data->def->ctrl_regs[ST1]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST1\n");
 			return ret;
@@ -343,7 +578,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
 		read_status = ret;
 		if (read_status)
 			break;
-		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
+		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
 	}
 	if (!timeout_ms) {
 		dev_err(&client->dev, "Conversion timeout happened\n");
@@ -354,13 +589,13 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
 }
 
 /* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
-static int wait_conversion_complete_interrupt(struct ak8975_data *data)
+static int wait_conversion_complete_interrupt(struct akxxxx_data *data)
 {
 	int ret;
 
 	ret = wait_event_timeout(data->data_ready_queue,
 				 test_bit(0, &data->flags),
-				 AK8975_DATA_READY_TIMEOUT);
+				 AKXXXX_DATA_READY_TIMEOUT);
 	clear_bit(0, &data->flags);
 
 	return ret > 0 ? 0 : -ETIME;
@@ -369,20 +604,16 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
 /*
  * Emits the raw flux value for the x, y, or z axis.
  */
-static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
+static int akxxxx_read_axis(struct iio_dev *indio_dev, int index, int *val)
 {
-	struct ak8975_data *data = iio_priv(indio_dev);
+	struct akxxxx_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
 	int ret;
 
 	mutex_lock(&data->lock);
 
 	/* Set up the device for taking a sample. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_ONCE,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = akxxxx_set_mode(data, MODE_ONCE);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting operating mode\n");
 		goto exit;
@@ -399,14 +630,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 		goto exit;
 
 	/* This will be executed only for non-interrupt based waiting case */
-	if (ret & AK8975_REG_ST1_DRDY_MASK) {
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
+	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
+		ret = i2c_smbus_read_byte_data(
+				client, data->def->ctrl_regs[ST2]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST2\n");
 			goto exit;
 		}
-		if (ret & (AK8975_REG_ST2_DERR_MASK |
-			   AK8975_REG_ST2_HOFL_MASK)) {
+		if (ret & (data->def->ctrl_masks[ST2_DERR] |
+			   data->def->ctrl_masks[ST2_HOFL])) {
 			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
 			ret = -EINVAL;
 			goto exit;
@@ -415,7 +647,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 
 	/* Read the flux value from the appropriate register
 	   (the register is specified in the iio device attributes). */
-	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
+	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
 	if (ret < 0) {
 		dev_err(&client->dev, "Read axis data fails\n");
 		goto exit;
@@ -424,7 +656,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 	mutex_unlock(&data->lock);
 
 	/* Clamp to valid range. */
-	*val = clamp_t(s16, ret, -4096, 4095);
+	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
 	return IIO_VAL_INT;
 
 exit:
@@ -432,16 +664,16 @@ exit:
 	return ret;
 }
 
-static int ak8975_read_raw(struct iio_dev *indio_dev,
+static int akxxxx_read_raw(struct iio_dev *indio_dev,
 			   struct iio_chan_spec const *chan,
 			   int *val, int *val2,
 			   long mask)
 {
-	struct ak8975_data *data = iio_priv(indio_dev);
+	struct akxxxx_data *data = iio_priv(indio_dev);
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		return ak8975_read_axis(indio_dev, chan->address, val);
+		return akxxxx_read_axis(indio_dev, chan->address, val);
 	case IIO_CHAN_INFO_SCALE:
 		*val = 0;
 		*val2 = data->raw_to_gauss[chan->address];
@@ -450,7 +682,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
 	return -EINVAL;
 }
 
-#define AK8975_CHANNEL(axis, index)					\
+#define AKXXXX_CHANNEL(axis, index)					\
 	{								\
 		.type = IIO_MAGN,					\
 		.modified = 1,						\
@@ -460,40 +692,41 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
 		.address = index,					\
 	}
 
-static const struct iio_chan_spec ak8975_channels[] = {
-	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
+static const struct iio_chan_spec akxxxx_channels[] = {
+	AKXXXX_CHANNEL(X, 0), AKXXXX_CHANNEL(Y, 1), AKXXXX_CHANNEL(Z, 2),
 };
 
-static const struct iio_info ak8975_info = {
-	.read_raw = &ak8975_read_raw,
+static const struct iio_info akxxxx_info = {
+	.read_raw = &akxxxx_read_raw,
 	.driver_module = THIS_MODULE,
 };
 
-static const struct acpi_device_id ak_acpi_match[] = {
-	{"AK8975", AK8975},
-	{"AK8963", AK8963},
-	{"INVN6500", AK8963},
+static const struct acpi_device_id akxxxx_acpi_match[] = {
+	{"AK8975", (uintptr_t)&akxxxx_def_array[AK8975]},
+	{"AK8963", (uintptr_t)&akxxxx_def_array[AK8963]},
+	{"AK09911", (uintptr_t)&akxxxx_def_array[AK09911]},
+	{"AK09912", (uintptr_t)&akxxxx_def_array[AK09912]},
 	{ },
 };
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
+MODULE_DEVICE_TABLE(acpi, akxxxx_acpi_match);
 
-static const char *ak8975_match_acpi_device(struct device *dev,
-					    enum asahi_compass_chipset *chipset)
+static const char *akxxxx_match_acpi_device(struct device *dev,
+					    struct akxxxx_def **def)
 {
 	const struct acpi_device_id *id;
 
 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 	if (!id)
 		return NULL;
-	*chipset = (int)id->driver_data;
+	*def = (struct akxxxx_def *)id->driver_data;
 
 	return dev_name(dev);
 }
 
-static int ak8975_probe(struct i2c_client *client,
+static int akxxxx_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	struct ak8975_data *data;
+	struct akxxxx_data *data;
 	struct iio_dev *indio_dev;
 	int eoc_gpio;
 	int err;
@@ -513,8 +746,8 @@ static int ak8975_probe(struct i2c_client *client,
 	/* We may not have a GPIO based IRQ to scan, that is fine, we will
 	   poll if so */
 	if (gpio_is_valid(eoc_gpio)) {
-		err = devm_gpio_request_one(&client->dev, eoc_gpio,
-							GPIOF_IN, "ak_8975");
+		err = devm_gpio_request_one(
+			&client->dev, eoc_gpio, GPIOF_IN, id->name);
 		if (err < 0) {
 			dev_err(&client->dev,
 				"failed to request GPIO %d, error %d\n",
@@ -534,23 +767,25 @@ static int ak8975_probe(struct i2c_client *client,
 	data->client = client;
 	data->eoc_gpio = eoc_gpio;
 	data->eoc_irq = 0;
-
 	/* id will be NULL when enumerated via ACPI */
 	if (id) {
-		data->chipset =
-			(enum asahi_compass_chipset)(id->driver_data);
+		data->def = (struct akxxxx_def *)id->driver_data;
 		name = id->name;
 	} else if (ACPI_HANDLE(&client->dev))
-		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
+		name = akxxxx_match_acpi_device(&client->dev, &data->def);
 	else
 		return -ENOSYS;
 
+	if (akxxxx_who_i_am(client, data->def->type) < 0) {
+		dev_err(&client->dev, "Unexpected device\n");
+		return -ENODEV;
+	}
 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 
 	/* Perform some basic start-of-day setup of the device. */
-	err = ak8975_setup(client);
+	err = akxxxx_setup(client);
 	if (err < 0) {
-		dev_err(&client->dev, "AK8975 initialization fails\n");
+		dev_err(&client->dev, "%s initialization fails\n", name);
 		return err;
 	}
 
@@ -558,9 +793,9 @@ static int ak8975_probe(struct i2c_client *client,
 	mutex_init(&data->lock);
 	data->eoc_gpio = eoc_gpio;
 	indio_dev->dev.parent = &client->dev;
-	indio_dev->channels = ak8975_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
-	indio_dev->info = &ak8975_info;
+	indio_dev->channels = akxxxx_channels;
+	indio_dev->num_channels = ARRAY_SIZE(akxxxx_channels);
+	indio_dev->info = &akxxxx_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = name;
 	err = devm_iio_device_register(&client->dev, indio_dev);
@@ -570,32 +805,48 @@ static int ak8975_probe(struct i2c_client *client,
 	return 0;
 }
 
-static const struct i2c_device_id ak8975_id[] = {
-	{"ak8975", AK8975},
-	{"ak8963", AK8963},
+static const struct i2c_device_id akxxxx_id[] = {
+	{"ak8975", (uintptr_t)&akxxxx_def_array[AK8975]},
+	{"ak8963", (uintptr_t)&akxxxx_def_array[AK8963]},
+	{"ak09911", (uintptr_t)&akxxxx_def_array[AK09911]},
+	{"ak09912", (uintptr_t)&akxxxx_def_array[AK09912]},
 	{}
 };
 
-MODULE_DEVICE_TABLE(i2c, ak8975_id);
-
-static const struct of_device_id ak8975_of_match[] = {
-	{ .compatible = "asahi-kasei,ak8975", },
-	{ .compatible = "ak8975", },
+MODULE_DEVICE_TABLE(i2c, akxxxx_id);
+
+static const struct of_device_id akxxxx_of_match[] = {
+	{ .compatible = "asahi-kasei,ak8975",
+	  .data = &akxxxx_def_array[AK8975]},
+	{ .compatible = "ak8975",
+	  .data = &akxxxx_def_array[AK8975]},
+	{ .compatible = "asahi-kasei,ak8963",
+	  .data = &akxxxx_def_array[AK8963]},
+	{ .compatible = "ak8963",
+	  .data = &akxxxx_def_array[AK8963]},
+	{ .compatible = "asahi-kasei,ak09911",
+	  .data = &akxxxx_def_array[AK09911]},
+	{ .compatible = "ak09911",
+	  .data = &akxxxx_def_array[AK09911]},
+	{ .compatible = "asahi-kasei,ak09912",
+	  .data = &akxxxx_def_array[AK09912]},
+	{ .compatible = "ak09912",
+	  .data = &akxxxx_def_array[AK09912]},
 	{ }
 };
-MODULE_DEVICE_TABLE(of, ak8975_of_match);
+MODULE_DEVICE_TABLE(of, akxxxx_of_match);
 
-static struct i2c_driver ak8975_driver = {
+static struct i2c_driver akxxxx_driver = {
 	.driver = {
-		.name	= "ak8975",
-		.of_match_table = ak8975_of_match,
-		.acpi_match_table = ACPI_PTR(ak_acpi_match),
+		.name	= "akxxxx",
+		.of_match_table = of_match_ptr(akxxxx_of_match),
+		.acpi_match_table = ACPI_PTR(akxxxx_acpi_match),
 	},
-	.probe		= ak8975_probe,
-	.id_table	= ak8975_id,
+	.probe		= akxxxx_probe,
+	.id_table	= akxxxx_id,
 };
-module_i2c_driver(ak8975_driver);
+module_i2c_driver(akxxxx_driver);
 
 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_DESCRIPTION("AK8975 magnetometer driver");
+MODULE_DESCRIPTION("ak8975 and ak09912 magnetometer driver");
 MODULE_LICENSE("GPL");
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCHv2] iio: ak8975: Add AKM0991x support.
  2014-11-04 19:41     ` [PATCHv2] " Gwendal Grignou
@ 2014-11-05 14:31       ` Jonathan Cameron
  2014-11-05 21:19         ` Gwendal Grignou
  0 siblings, 1 reply; 28+ messages in thread
From: Jonathan Cameron @ 2014-11-05 14:31 UTC (permalink / raw)
  To: Gwendal Grignou, srinivas.pandruvada, knaack.h; +Cc: linux-iio

On 04/11/14 19:41, Gwendal Grignou wrote:
> File and config id remains the same, but driver is now named akxxxx.

Don't do that.  Please name the driver after one supported part rather
than a general wild card.  Leaving it as ak8975 would be sensible.
Wild cards seem like a good idea until along comes a part that fits
in the naming scheme but is otherwise totally different.

Much cleaner to just pick a part to use in naming the driver and
make it clear what parts are supported in kconfig (see iio/adc/max1363 for
example).

I would have prefered this as a two patch series.  The first combining
the existing drivers, and the second (small one) adding the new part
support.

Would have broken it up into logical steps thus making it a little
easier to check for feature parity etc.

Once you've dropped the name change, this patch will contain less noise.
Also, there are a couple of sensible refactorings in there.  I would
have prefered these to be in precursor patches that made much smaller
changes.

This sort of merging of drivers is one of the hardest types of code to
review, so making it as easy as possible for reviewers by packaging
it up as baby steps is the way to go.

There is still some work to be done in convincing people that merging
the drivers is sensible (I'm pretty much convinced having waded through
this) but that is an easier job with a well split up series of steps!

Jonathan

> Move AKM09911 support in the same file.
>
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>
> Addressed all comments from Hartmut.
>
>  drivers/iio/magnetometer/Kconfig   |  19 +-
>  drivers/iio/magnetometer/Makefile  |   1 -
>  drivers/iio/magnetometer/ak09911.c | 326 -------------------
>  drivers/iio/magnetometer/ak8975.c  | 629 ++++++++++++++++++++++++++-----------
>  4 files changed, 444 insertions(+), 531 deletions(-)
>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
>
> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> index b2dba9e..67f005d 100644
> --- a/drivers/iio/magnetometer/Kconfig
> +++ b/drivers/iio/magnetometer/Kconfig
> @@ -6,26 +6,15 @@
>  menu "Magnetometer sensors"
>
>  config AK8975
> -	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> +	tristate "Asahi Kasei AK 3-Axis Magnetometer"
>  	depends on I2C
>  	depends on GPIOLIB
>  	help
> -	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
> -	  Magnetometer. This driver can also support AK8963, if i2c
> -	  device name is identified as ak8963.
> +	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
> +	  AK09911 or AK09912 3-Axis Magnetometer.
>
>  	  To compile this driver as a module, choose M here: the module
> -	  will be called ak8975.
> -
> -config AK09911
> -	tristate "Asahi Kasei AK09911 3-axis Compass"
> -	depends on I2C
> -	help
> -	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
> -	  Magnetometer.
> -
> -	  To compile this driver as a module, choose M here: the module
> -	  will be called ak09911.
> +	  will be called akxxxx.
>
>  config MAG3110
>  	tristate "Freescale MAG3110 3-Axis Magnetometer"
> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
> index b91315e..0f5d3c9 100644
> --- a/drivers/iio/magnetometer/Makefile
> +++ b/drivers/iio/magnetometer/Makefile
> @@ -3,7 +3,6 @@
>  #
>
>  # When adding new entries keep the list in alphabetical order
> -obj-$(CONFIG_AK09911)	+= ak09911.o
>  obj-$(CONFIG_AK8975)	+= ak8975.o
>  obj-$(CONFIG_MAG3110)	+= mag3110.o
>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
> deleted file mode 100644
> index b2bc942..0000000
> --- a/drivers/iio/magnetometer/ak09911.c
> +++ /dev/null
> @@ -1,326 +0,0 @@
> -/*
> - * AK09911 3-axis compass driver
> - * Copyright (c) 2014, 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.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/types.h>
> -#include <linux/slab.h>
> -#include <linux/delay.h>
> -#include <linux/i2c.h>
> -#include <linux/acpi.h>
> -#include <linux/iio/iio.h>
> -
> -#define AK09911_REG_WIA1		0x00
> -#define AK09911_REG_WIA2		0x01
> -#define AK09911_WIA1_VALUE		0x48
> -#define AK09911_WIA2_VALUE		0x05
> -
> -#define AK09911_REG_ST1			0x10
> -#define AK09911_REG_HXL			0x11
> -#define AK09911_REG_HXH			0x12
> -#define AK09911_REG_HYL			0x13
> -#define AK09911_REG_HYH			0x14
> -#define AK09911_REG_HZL			0x15
> -#define AK09911_REG_HZH			0x16
> -
> -#define AK09911_REG_ASAX		0x60
> -#define AK09911_REG_ASAY		0x61
> -#define AK09911_REG_ASAZ		0x62
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_MODE_SNG_MEASURE	0x01
> -#define AK09911_MODE_SELF_TEST		0x10
> -#define AK09911_MODE_FUSE_ACCESS	0x1F
> -#define AK09911_MODE_POWERDOWN		0x00
> -#define AK09911_RESET_DATA		0x01
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
> -
> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
> -
> -struct ak09911_data {
> -	struct i2c_client	*client;
> -	struct mutex		lock;
> -	u8			asa[3];
> -	long			raw_to_gauss[3];
> -};
> -
> -static const int ak09911_index_to_reg[] = {
> -	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
> -};
> -
> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
> -{
> -	int ret;
> -
> -	switch (mode) {
> -	case AK09911_MODE_SNG_MEASURE:
> -	case AK09911_MODE_SELF_TEST:
> -	case AK09911_MODE_FUSE_ACCESS:
> -	case AK09911_MODE_POWERDOWN:
> -		ret = i2c_smbus_write_byte_data(client,
> -						AK09911_REG_CNTL2, mode);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "set_mode error\n");
> -			return ret;
> -		}
> -		/* After mode change wait atleast 100us */
> -		usleep_range(100, 500);
> -		break;
> -	default:
> -		dev_err(&client->dev,
> -			"%s: Unknown mode(%d).", __func__, mode);
> -		return -EINVAL;
> -	}
> -
> -	return ret;
> -}
> -
> -/* Get Sensitivity Adjustment value */
> -static int ak09911_get_asa(struct i2c_client *client)
> -{
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	int ret;
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
> -	if (ret < 0)
> -		return ret;
> -
> -	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
> -					    3, data->asa);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Not able to read asa data\n");
> -		return ret;
> -	}
> -
> -	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
> -	if (ret < 0)
> -		return ret;
> -
> -	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
> -	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
> -	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
> -
> -	return 0;
> -}
> -
> -static int ak09911_verify_chip_id(struct i2c_client *client)
> -{
> -	u8 wia_val[2];
> -	int ret;
> -
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
> -					    2, wia_val);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -
> -	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
> -
> -	if (wia_val[0] != AK09911_WIA1_VALUE ||
> -		wia_val[1] != AK09911_WIA2_VALUE) {
> -		dev_err(&client->dev, "Device ak09911 not found\n");
> -		return -ENODEV;
> -	}
> -
> -	return 0;
> -}
> -
> -static int wait_conversion_complete_polled(struct ak09911_data *data)
> -{
> -	struct i2c_client *client = data->client;
> -	u8 read_status;
> -	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
> -	int ret;
> -
> -	/* Wait for the conversion to complete. */
> -	while (timeout_ms) {
> -		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
> -		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "Error in reading ST1\n");
> -			return ret;
> -		}
> -		read_status = ret & 0x01;
> -		if (read_status)
> -			break;
> -		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
> -	}
> -	if (!timeout_ms) {
> -		dev_err(&client->dev, "Conversion timeout happened\n");
> -		return -EIO;
> -	}
> -
> -	return read_status;
> -}
> -
> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	struct i2c_client *client = data->client;
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	ret = wait_conversion_complete_polled(data);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	/* Read data */
> -	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Read axis data fails\n");
> -		goto fn_exit;
> -	}
> -
> -	mutex_unlock(&data->lock);
> -
> -	/* Clamp to valid range. */
> -	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
> -
> -	return IIO_VAL_INT;
> -
> -fn_exit:
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static int ak09911_read_raw(struct iio_dev *indio_dev,
> -			    struct iio_chan_spec const *chan,
> -			    int *val, int *val2,
> -			    long mask)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -
> -	switch (mask) {
> -	case IIO_CHAN_INFO_RAW:
> -		return ak09911_read_axis(indio_dev, chan->address, val);
> -	case IIO_CHAN_INFO_SCALE:
> -		*val = 0;
> -		*val2 = data->raw_to_gauss[chan->address];
> -		return IIO_VAL_INT_PLUS_MICRO;
> -	}
> -
> -	return -EINVAL;
> -}
> -
> -#define AK09911_CHANNEL(axis, index)					\
> -	{								\
> -		.type = IIO_MAGN,					\
> -		.modified = 1,						\
> -		.channel2 = IIO_MOD_##axis,				\
> -		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
> -			     BIT(IIO_CHAN_INFO_SCALE),			\
> -		.address = index,					\
> -	}
> -
> -static const struct iio_chan_spec ak09911_channels[] = {
> -	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
> -};
> -
> -static const struct iio_info ak09911_info = {
> -	.read_raw = &ak09911_read_raw,
> -	.driver_module = THIS_MODULE,
> -};
> -
> -static const struct acpi_device_id ak_acpi_match[] = {
> -	{"AK009911", 0},
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> -
> -static int ak09911_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> -{
> -	struct iio_dev *indio_dev;
> -	struct ak09911_data *data;
> -	const char *name;
> -	int ret;
> -
> -	ret = ak09911_verify_chip_id(client);
> -	if (ret) {
> -		dev_err(&client->dev, "AK00911 not detected\n");
> -		return -ENODEV;
> -	}
> -
> -	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> -	if (indio_dev == NULL)
> -		return -ENOMEM;
> -
> -	data = iio_priv(indio_dev);
> -	i2c_set_clientdata(client, indio_dev);
> -
> -	data->client = client;
> -	mutex_init(&data->lock);
> -
> -	ret = ak09911_get_asa(client);
> -	if (ret)
> -		return ret;
> -
> -	if (id)
> -		name = id->name;
> -	else if (ACPI_HANDLE(&client->dev))
> -		name = dev_name(&client->dev);
> -	else
> -		return -ENODEV;
> -
> -	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> -
> -	indio_dev->dev.parent = &client->dev;
> -	indio_dev->channels = ak09911_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
> -	indio_dev->info = &ak09911_info;
> -	indio_dev->modes = INDIO_DIRECT_MODE;
> -	indio_dev->name = name;
> -
> -	return devm_iio_device_register(&client->dev, indio_dev);
> -}
> -
> -static const struct i2c_device_id ak09911_id[] = {
> -	{"ak09911", 0},
> -	{}
> -};
> -
> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
> -
> -static struct i2c_driver ak09911_driver = {
> -	.driver = {
> -		.name	= "ak09911",
> -		.acpi_match_table = ACPI_PTR(ak_acpi_match),
> -	},
> -	.probe		= ak09911_probe,
> -	.id_table	= ak09911_id,
> -};
> -module_i2c_driver(ak09911_driver);
> -
> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
> -MODULE_LICENSE("GPL v2");
> -MODULE_DESCRIPTION("AK09911 Compass driver");
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index bf5ef07..f2ec32f 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -35,12 +35,14 @@
>
>  #include <linux/iio/iio.h>
>  #include <linux/iio/sysfs.h>
> +
> +#define AKXXXX_COMPANY_ID		0x48
> +
>  /*
> - * Register definitions, as well as various shifts and masks to get at the
> - * individual fields of the registers.
> + * AK_8975 Register definitions, as well as various shifts and masks to get
> + * at the individual fields of the registers.
>   */
>  #define AK8975_REG_WIA			0x00
> -#define AK8975_DEVICE_ID		0x48
>
>  #define AK8975_REG_INFO			0x01
>
> @@ -62,12 +64,12 @@
>  #define AK8975_REG_ST2_HOFL_MASK	(1 << AK8975_REG_ST2_HOFL_SHIFT)
>
>  #define AK8975_REG_CNTL			0x0A
> +#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK8975_REG_CNTL_MODE_ONCE	0x01
> +#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
> +#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
>  #define AK8975_REG_CNTL_MODE_SHIFT	0
>  #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
> -#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
> -#define AK8975_REG_CNTL_MODE_ONCE	1
> -#define AK8975_REG_CNTL_MODE_SELF_TEST	8
> -#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
>
>  #define AK8975_REG_RSVC			0x0B
>  #define AK8975_REG_ASTC			0x0C
> @@ -81,59 +83,359 @@
>  #define AK8975_MAX_REGS			AK8975_REG_ASAZ
>
>  /*
> + * AK09912 Register definitions
> + */
> +#define AK09912_REG_WIA1		0x00
> +#define AK09912_REG_WIA2		0x01
> +#define AK09912_DEVICE_ID		0x04
> +#define AK09911_DEVICE_ID		0x05
> +
> +#define AK09911_REG_INFO1		0x02
> +#define AK09911_REG_INFO2		0x03
> +
> +#define AK09912_REG_ST1			0x10
> +
> +#define AK09912_REG_ST1_DRDY_SHIFT	0
> +#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
> +
> +#define AK09912_REG_HXL			0x11
> +#define AK09912_REG_HXH			0x12
> +#define AK09912_REG_HYL			0x13
> +#define AK09912_REG_HYH			0x14
> +#define AK09912_REG_HZL			0x15
> +#define AK09912_REG_HZH			0x16
> +#define AK09912_REG_TMPS		0x17
> +
> +#define AK09912_REG_ST2			0x18
> +#define AK09912_REG_ST2_HOFL_SHIFT	3
> +#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
> +
> +#define AK09912_REG_CNTL1		0x30
> +
> +#define AK09912_REG_CNTL2		0x31
> +#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK09912_REG_CNTL_MODE_ONCE	0x01
> +#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
> +#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
> +#define AK09912_REG_CNTL2_MODE_SHIFT	0
> +#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
> +
> +#define AK09912_REG_CNTL3		0x32
> +
> +#define AK09912_REG_TS1			0x33
> +#define AK09912_REG_TS2			0x34
> +#define AK09912_REG_TS3			0x35
> +#define AK09912_REG_I2CDIS		0x36
> +#define AK09912_REG_TS4			0x37
> +
> +#define AK09912_REG_ASAX		0x60
> +#define AK09912_REG_ASAY		0x61
> +#define AK09912_REG_ASAZ		0x62
> +
> +#define AK09912_MAX_REGS		AK09912_REG_ASAZ
> +
> +/*
>   * Miscellaneous values.
>   */
> -#define AK8975_MAX_CONVERSION_TIMEOUT	500
> -#define AK8975_CONVERSION_DONE_POLL_TIME 10
> -#define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
> -#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
> -#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
> -
> -/* Compatible Asahi Kasei Compass parts */
> -enum asahi_compass_chipset {
> +#define AKXXXX_MAX_CONVERSION_TIMEOUT	500
> +#define AKXXXX_CONVERSION_DONE_POLL_TIME 10
> +#define AKXXXX_DATA_READY_TIMEOUT	((100*HZ)/1000)
> +
> +/*
> + * Precalculate scale factor (in Gauss units) for each axis and
> + * store in the device data.
> + *
> + * This scale factor is axis-dependent, and is derived from 3 calibration
> + * factors ASA(x), ASA(y), and ASA(z).
> + *
> + * These ASA values are read from the sensor device at start of day, and
> + * cached in the device context struct.
> + *
> + * Adjusting the flux value with the sensitivity adjustment value should be
> + * done via the following formula:
> + *
> + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> + * is the resultant adjusted value.
> + *
> + * We reduce the formula to:
> + *
> + * Hadj = H * (ASA + 128) / 256
> + *
> + * H is in the range of -4096 to 4095.  The magnetometer has a range of
> + * +-1229uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 1229/4096, or roughly, 3/10.
> + *
> + * Since 1uT = 0.01 gauss, our final scale factor becomes:
> + *
> + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> + * Hadj = H * ((ASA + 128) * 0.003) / 256
> + *
> + * Since ASA doesn't change, we cache the resultant scale factor into the
> + * device context in akxxxx_setup().
> + *
> + * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
> + * multiply the stored scale value by 1e6.
> + */
> +long ak8975_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 3000) / 256;
> +}
> +
> +/*
> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
> + *
> + * H is in the range of +-8190.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
> + */
> +long ak8963_09911_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 6000) / 256;
> +}
> +
> +/*
> + * For AK09912, same calculation, except the device is more sensitive:
> + *
> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
> + */
> +long ak09912_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 1500) / 256;
> +}
> +
> +enum ak_type {
>  	AK8975,
>  	AK8963,
> +	AK09911,
> +	AK09912,
> +	AK_MAX_TYPE
> +};
> +
> +enum ak_ctrl_reg_addr {
> +	ST1,
> +	ST2,
> +	CNTL,
> +	ASA_BASE,
> +	MAX_REGS,
> +	REGS_END,
> +};
> +
> +enum ak_ctrl_reg_mask {
> +	ST1_DRDY,
> +	ST2_HOFL,
> +	ST2_DERR,
> +	CNTL_MODE,
> +	MASK_END,
> +};
> +
> +enum ak_ctrl_mode {
> +	POWER_DOWN,
> +	MODE_ONCE,
> +	SELF_TEST,
> +	FUSE_ROM,
> +	MODE_END,
> +};
> +
> +struct akxxxx_def {
> +	enum ak_type type;
> +	long (*raw_to_gauss)(u16 data);
> +	u16 range;
> +	u8 ctrl_regs[REGS_END];
> +	u8 ctrl_masks[MASK_END];
> +	u8 ctrl_modes[MODE_END];
> +	u8 data_regs[3];
> +} akxxxx_def_array[AK_MAX_TYPE] = {
> +{
> +	.type = AK8975,
> +	.raw_to_gauss = ak8975_raw_to_gauss,
> +	.range = 4096,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		AK8975_REG_ST2_DERR_MASK,
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
> +{
> +	.type = AK8963,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
> +	.range = 8190,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		0,
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
> +{
> +	.type = AK09911,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
> +	.range = 8192,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +},
> +{
> +	.type = AK09912,
> +	.raw_to_gauss = ak09912_raw_to_gauss,
> +	.range = 32752,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +}
>  };
>
>  /*
>   * Per-instance context data for the device.
>   */
> -struct ak8975_data {
> +struct akxxxx_data {
>  	struct i2c_client	*client;
> +	struct akxxxx_def       *def;
>  	struct attribute_group	attrs;
>  	struct mutex		lock;
>  	u8			asa[3];
>  	long			raw_to_gauss[3];
> -	u8			reg_cache[AK8975_MAX_REGS];
Justify dropping this register cache...

>  	int			eoc_gpio;
>  	int			eoc_irq;
>  	wait_queue_head_t	data_ready_queue;
>  	unsigned long		flags;
> -	enum asahi_compass_chipset chipset;
> +	u8			cntl_cache;
>  };
>
> -static const int ak8975_index_to_reg[] = {
> -	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
> -};
> +/*
> + * Return 0 if the i2c device is the one we expect.
> + * return a negative error number otherwise
> + */
> +static int akxxxx_who_i_am(struct i2c_client *client, enum ak_type type)
> +{
> +	u8 wia_val[2];
> +	int ret;
> +
> +	/*
> +	 * Signature for each device:
> +	 * Device   |  WIA1       |  WIA2
> +	 * AK09912  |  COMPANY_ID |  AK09912_DEVICE_ID
> +	 * AK09911  |  COMPANY_ID |  AK09911_DEVICE_ID
> +	 * AK8975   |  COMPANY_ID |  NA
> +	 * AK8963   |  COMPANY_ID |  NA
> +	 */
> +	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> +					    2, wia_val);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error reading WIA\n");
> +		return ret;
> +	}
> +
> +	ret = -ENODEV;
> +
> +	if (wia_val[0] != AKXXXX_COMPANY_ID)
> +		return ret;
> +
> +	switch (type) {
> +	case AK8975:
> +	case AK8963:
> +		ret = 0;
> +		break;
> +	case AK09911:
> +		if (wia_val[1] == AK09911_DEVICE_ID)
> +			ret = 0;
> +		break;
> +	case AK09912:
> +		if (wia_val[1] == AK09912_DEVICE_ID)
> +			ret = 0;
> +		break;
> +	default:
> +		dev_err(&client->dev, "Type %d unknown\n", type);
> +	}
> +	return ret;
> +}
>
>  /*
> - * Helper function to write to the I2C device's registers.
> + * Helper function to write to CNTL register.
>   */
> -static int ak8975_write_data(struct i2c_client *client,
> -			     u8 reg, u8 val, u8 mask, u8 shift)
> +static int akxxxx_set_mode(struct akxxxx_data *data, enum ak_ctrl_mode mode)
>  {
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak8975_data *data = iio_priv(indio_dev);
>  	u8 regval;
>  	int ret;
>
> -	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
> -	ret = i2c_smbus_write_byte_data(client, reg, regval);
> +	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
> +		data->def->ctrl_modes[mode];
> +	ret = i2c_smbus_write_byte_data(
> +		data->client, data->def->ctrl_regs[CNTL], regval);
>  	if (ret < 0) {
> -		dev_err(&client->dev, "Write to device fails status %x\n", ret);
>  		return ret;
>  	}
> -	data->reg_cache[reg] = regval;
> +	data->cntl_cache = regval;
> +	/* After mode change wait atleast 100us */
> +	usleep_range(100, 500);
>
>  	return 0;
>  }
> @@ -141,9 +443,9 @@ static int ak8975_write_data(struct i2c_client *client,
>  /*
>   * Handle data ready irq
>   */
> -static irqreturn_t ak8975_irq_handler(int irq, void *data)
> +static irqreturn_t akxxxx_irq_handler(int irq, void *data)
>  {
> -	struct ak8975_data *ak8975 = data;
> +	struct akxxxx_data *ak8975 = data;
>
>  	set_bit(0, &ak8975->flags);
>  	wake_up(&ak8975->data_ready_queue);
> @@ -154,7 +456,7 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data)
>  /*
>   * Install data ready interrupt handler
>   */
> -static int ak8975_setup_irq(struct ak8975_data *data)
> +static int akxxxx_setup_irq(struct akxxxx_data *data)
>  {
>  	struct i2c_client *client = data->client;
>  	int rc;
> @@ -165,9 +467,9 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>  	else
>  		irq = gpio_to_irq(data->eoc_gpio);
>
> -	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
> -			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> -			 dev_name(&client->dev), data);
> +	rc = devm_request_irq(&client->dev, irq, akxxxx_irq_handler,
> +			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +			      dev_name(&client->dev), data);
>  	if (rc < 0) {
>  		dev_err(&client->dev,
>  			"irq %d request failed, (gpio %d): %d\n",
> @@ -187,38 +489,22 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>   * Perform some start-of-day setup, including reading the asa calibration
>   * values and caching them.
>   */
> -static int ak8975_setup(struct i2c_client *client)
> +static int akxxxx_setup(struct i2c_client *client)
>  {
>  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak8975_data *data = iio_priv(indio_dev);
> -	u8 device_id;
> +	struct akxxxx_data *data = iio_priv(indio_dev);
>  	int ret;
>
> -	/* Confirm that the device we're talking to is really an AK8975. */
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -	device_id = ret;
> -	if (device_id != AK8975_DEVICE_ID) {
> -		dev_err(&client->dev, "Device ak8975 not found\n");
> -		return -ENODEV;
> -	}
> -
>  	/* Write the fused rom access mode. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_FUSE_ROM,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = akxxxx_set_mode(data, FUSE_ROM);
The factoring out of set_mode makes sense, but should probably have
been a separate precursor patch to the main series.
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting fuse access mode\n");
>  		return ret;
>  	}
>
>  	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
> +	ret = i2c_smbus_read_i2c_block_data(client,
> +					    data->def->ctrl_regs[ASA_BASE],
>  					    3, data->asa);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Not able to read asa data\n");
> @@ -226,14 +512,14 @@ static int ak8975_setup(struct i2c_client *client)
>  	}
>
>  	/* After reading fuse ROM data set power-down mode */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_POWER_DOWN,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = akxxxx_set_mode(data, POWER_DOWN);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error in setting power-down mode\n");
> +		return ret;
> +	}
>
>  	if (data->eoc_gpio > 0 || client->irq) {
> -		ret = ak8975_setup_irq(data);
> +		ret = akxxxx_setup_irq(data);
>  		if (ret < 0) {
>  			dev_err(&client->dev,
>  				"Error setting data ready interrupt\n");
> @@ -241,101 +527,50 @@ static int ak8975_setup(struct i2c_client *client)
>  		}
>  	}
>
Why has this disappeared?
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error in setting power-down mode\n");
> -		return ret;
> -	}
> -
> -/*
> - * Precalculate scale factor (in Gauss units) for each axis and
> - * store in the device data.
> - *
> - * This scale factor is axis-dependent, and is derived from 3 calibration
> - * factors ASA(x), ASA(y), and ASA(z).
> - *
> - * These ASA values are read from the sensor device at start of day, and
> - * cached in the device context struct.
> - *
> - * Adjusting the flux value with the sensitivity adjustment value should be
> - * done via the following formula:
> - *
> - * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> - *
> - * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> - * is the resultant adjusted value.
> - *
> - * We reduce the formula to:
> - *
> - * Hadj = H * (ASA + 128) / 256
> - *
> - * H is in the range of -4096 to 4095.  The magnetometer has a range of
> - * +-1229uT.  To go from the raw value to uT is:
> - *
> - * HuT = H * 1229/4096, or roughly, 3/10.
> - *
> - * Since 1uT = 0.01 gauss, our final scale factor becomes:
> - *
> - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> - * Hadj = H * ((ASA + 128) * 0.003) / 256
> - *
> - * Since ASA doesn't change, we cache the resultant scale factor into the
> - * device context in ak8975_setup().
> - */

> -	if (data->chipset == AK8963) {
> -		/*
> -		 * H range is +-8190 and magnetometer range is +-4912.
> -		 * So HuT using the above explanation for 8975,
> -		 * 4912/8190 = ~ 6/10.
> -		 * So the Hadj should use 6/10 instead of 3/10.
> -		 */
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
> -	} else {
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
> -	}
> +	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
> +	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
> +	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
>
>  	return 0;
>  }
>
> -static int wait_conversion_complete_gpio(struct ak8975_data *data)
> +static int wait_conversion_complete_gpio(struct akxxxx_data *data)
>  {
>  	struct i2c_client *client = data->client;
> -	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
> +	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
>  	int ret;
>
>  	/* Wait for the conversion to complete. */
>  	while (timeout_ms) {
> -		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> +		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
>  		if (gpio_get_value(data->eoc_gpio))
>  			break;
> -		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
> +		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
>  	}
>  	if (!timeout_ms) {
>  		dev_err(&client->dev, "Conversion timeout happened\n");
>  		return -EINVAL;
>  	}
>
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
>  	if (ret < 0)
>  		dev_err(&client->dev, "Error in reading ST1\n");
>
>  	return ret;
>  }
>
> -static int wait_conversion_complete_polled(struct ak8975_data *data)
> +static int wait_conversion_complete_polled(struct akxxxx_data *data)
>  {
>  	struct i2c_client *client = data->client;
>  	u8 read_status;
> -	u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
> +	u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
>  	int ret;
>
>  	/* Wait for the conversion to complete. */
>  	while (timeout_ms) {
> -		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +		msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST1]);
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST1\n");
>  			return ret;
> @@ -343,7 +578,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>  		read_status = ret;
>  		if (read_status)
>  			break;
> -		timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
> +		timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
>  	}
>  	if (!timeout_ms) {
>  		dev_err(&client->dev, "Conversion timeout happened\n");
> @@ -354,13 +589,13 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>  }
>
>  /* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
> -static int wait_conversion_complete_interrupt(struct ak8975_data *data)
> +static int wait_conversion_complete_interrupt(struct akxxxx_data *data)
>  {
>  	int ret;
>
>  	ret = wait_event_timeout(data->data_ready_queue,
>  				 test_bit(0, &data->flags),
> -				 AK8975_DATA_READY_TIMEOUT);
> +				 AKXXXX_DATA_READY_TIMEOUT);
>  	clear_bit(0, &data->flags);
>
>  	return ret > 0 ? 0 : -ETIME;
> @@ -369,20 +604,16 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
>  /*
>   * Emits the raw flux value for the x, y, or z axis.
>   */
> -static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
> +static int akxxxx_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  {
> -	struct ak8975_data *data = iio_priv(indio_dev);
> +	struct akxxxx_data *data = iio_priv(indio_dev);
>  	struct i2c_client *client = data->client;
>  	int ret;
>
>  	mutex_lock(&data->lock);
>
>  	/* Set up the device for taking a sample. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_ONCE,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = akxxxx_set_mode(data, MODE_ONCE);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting operating mode\n");
>  		goto exit;
> @@ -399,14 +630,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  		goto exit;
>
>  	/* This will be executed only for non-interrupt based waiting case */
> -	if (ret & AK8975_REG_ST1_DRDY_MASK) {
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
> +	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST2]);
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST2\n");
>  			goto exit;
>  		}
> -		if (ret & (AK8975_REG_ST2_DERR_MASK |
> -			   AK8975_REG_ST2_HOFL_MASK)) {
> +		if (ret & (data->def->ctrl_masks[ST2_DERR] |
> +			   data->def->ctrl_masks[ST2_HOFL])) {
>  			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
>  			ret = -EINVAL;
>  			goto exit;
> @@ -415,7 +647,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>
>  	/* Read the flux value from the appropriate register
>  	   (the register is specified in the iio device attributes). */
> -	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
> +	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Read axis data fails\n");
>  		goto exit;
> @@ -424,7 +656,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  	mutex_unlock(&data->lock);
>
>  	/* Clamp to valid range. */
> -	*val = clamp_t(s16, ret, -4096, 4095);
> +	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
Well that isn't going to be the same as before...  I think you need a
- 1
>  	return IIO_VAL_INT;
>
>  exit:
> @@ -432,16 +664,16 @@ exit:
>  	return ret;
>  }
>
> -static int ak8975_read_raw(struct iio_dev *indio_dev,
> +static int akxxxx_read_raw(struct iio_dev *indio_dev,
>  			   struct iio_chan_spec const *chan,
>  			   int *val, int *val2,
>  			   long mask)
>  {
> -	struct ak8975_data *data = iio_priv(indio_dev);
> +	struct akxxxx_data *data = iio_priv(indio_dev);
>
>  	switch (mask) {
>  	case IIO_CHAN_INFO_RAW:
> -		return ak8975_read_axis(indio_dev, chan->address, val);
> +		return akxxxx_read_axis(indio_dev, chan->address, val);
>  	case IIO_CHAN_INFO_SCALE:
>  		*val = 0;
>  		*val2 = data->raw_to_gauss[chan->address];
> @@ -450,7 +682,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
>  	return -EINVAL;
>  }
>
> -#define AK8975_CHANNEL(axis, index)					\
> +#define AKXXXX_CHANNEL(axis, index)					\
>  	{								\
>  		.type = IIO_MAGN,					\
>  		.modified = 1,						\
> @@ -460,40 +692,41 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
>  		.address = index,					\
>  	}
>
> -static const struct iio_chan_spec ak8975_channels[] = {
> -	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
> +static const struct iio_chan_spec akxxxx_channels[] = {
> +	AKXXXX_CHANNEL(X, 0), AKXXXX_CHANNEL(Y, 1), AKXXXX_CHANNEL(Z, 2),
>  };
>
> -static const struct iio_info ak8975_info = {
> -	.read_raw = &ak8975_read_raw,
> +static const struct iio_info akxxxx_info = {
> +	.read_raw = &akxxxx_read_raw,
>  	.driver_module = THIS_MODULE,
>  };
>
> -static const struct acpi_device_id ak_acpi_match[] = {
> -	{"AK8975", AK8975},
> -	{"AK8963", AK8963},
> -	{"INVN6500", AK8963},
> +static const struct acpi_device_id akxxxx_acpi_match[] = {
> +	{"AK8975", (uintptr_t)&akxxxx_def_array[AK8975]},
> +	{"AK8963", (uintptr_t)&akxxxx_def_array[AK8963]},
> +	{"AK09911", (uintptr_t)&akxxxx_def_array[AK09911]},
> +	{"AK09912", (uintptr_t)&akxxxx_def_array[AK09912]},
Again, I'm lost as to why you have changed form an index....
>  	{ },
>  };
> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> +MODULE_DEVICE_TABLE(acpi, akxxxx_acpi_match);
>
> -static const char *ak8975_match_acpi_device(struct device *dev,
> -					    enum asahi_compass_chipset *chipset)
> +static const char *akxxxx_match_acpi_device(struct device *dev,
> +					    struct akxxxx_def **def)
>  {
>  	const struct acpi_device_id *id;
>
>  	id = acpi_match_device(dev->driver->acpi_match_table, dev);
>  	if (!id)
>  		return NULL;
> -	*chipset = (int)id->driver_data;
> +	*def = (struct akxxxx_def *)id->driver_data;
>
>  	return dev_name(dev);
>  }
>
> -static int ak8975_probe(struct i2c_client *client,
> +static int akxxxx_probe(struct i2c_client *client,
>  			const struct i2c_device_id *id)
>  {
> -	struct ak8975_data *data;
> +	struct akxxxx_data *data;
>  	struct iio_dev *indio_dev;
>  	int eoc_gpio;
>  	int err;
> @@ -513,8 +746,8 @@ static int ak8975_probe(struct i2c_client *client,
>  	/* We may not have a GPIO based IRQ to scan, that is fine, we will
>  	   poll if so */
>  	if (gpio_is_valid(eoc_gpio)) {
> -		err = devm_gpio_request_one(&client->dev, eoc_gpio,
> -							GPIOF_IN, "ak_8975");
> +		err = devm_gpio_request_one(
> +			&client->dev, eoc_gpio, GPIOF_IN, id->name);
>  		if (err < 0) {
>  			dev_err(&client->dev,
>  				"failed to request GPIO %d, error %d\n",
> @@ -534,23 +767,25 @@ static int ak8975_probe(struct i2c_client *client,
>  	data->client = client;
>  	data->eoc_gpio = eoc_gpio;
Rather curriously data->eoc_gpio is set to the same value twice...

>  	data->eoc_irq = 0;
> -
>  	/* id will be NULL when enumerated via ACPI */
>  	if (id) {
> -		data->chipset =
> -			(enum asahi_compass_chipset)(id->driver_data);
> +		data->def = (struct akxxxx_def *)id->driver_data;
>  		name = id->name;
>  	} else if (ACPI_HANDLE(&client->dev))
> -		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
> +		name = akxxxx_match_acpi_device(&client->dev, &data->def);
>  	else
>  		return -ENOSYS;
>
> +	if (akxxxx_who_i_am(client, data->def->type) < 0) {
> +		dev_err(&client->dev, "Unexpected device\n");
> +		return -ENODEV;
> +	}
>  	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>
>  	/* Perform some basic start-of-day setup of the device. */
> -	err = ak8975_setup(client);
> +	err = akxxxx_setup(client);
>  	if (err < 0) {
> -		dev_err(&client->dev, "AK8975 initialization fails\n");
> +		dev_err(&client->dev, "%s initialization fails\n", name);
>  		return err;
>  	}
>
> @@ -558,9 +793,9 @@ static int ak8975_probe(struct i2c_client *client,
>  	mutex_init(&data->lock);
>  	data->eoc_gpio = eoc_gpio;
>  	indio_dev->dev.parent = &client->dev;
> -	indio_dev->channels = ak8975_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
> -	indio_dev->info = &ak8975_info;
> +	indio_dev->channels = akxxxx_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(akxxxx_channels);
> +	indio_dev->info = &akxxxx_info;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  	indio_dev->name = name;
>  	err = devm_iio_device_register(&client->dev, indio_dev);
> @@ -570,32 +805,48 @@ static int ak8975_probe(struct i2c_client *client,
>  	return 0;
Not your fault, but this function could just end
return devm_iio_device_register(...) which would be cleaner.
(in case you haven't guessed I'm looking at the result rather than the
patch ;)
>  }
>
> -static const struct i2c_device_id ak8975_id[] = {
> -	{"ak8975", AK8975},
> -	{"ak8963", AK8963},
> +static const struct i2c_device_id akxxxx_id[] = {
> +	{"ak8975", (uintptr_t)&akxxxx_def_array[AK8975]},
> +	{"ak8963", (uintptr_t)&akxxxx_def_array[AK8963]},
> +	{"ak09911", (uintptr_t)&akxxxx_def_array[AK09911]},
> +	{"ak09912", (uintptr_t)&akxxxx_def_array[AK09912]},
Why not use an index instead as per the original driver?
Same result, less type casting mess ;)
>  	{}
>  };
>
> -MODULE_DEVICE_TABLE(i2c, ak8975_id);
> -
> -static const struct of_device_id ak8975_of_match[] = {
> -	{ .compatible = "asahi-kasei,ak8975", },
> -	{ .compatible = "ak8975", },
> +MODULE_DEVICE_TABLE(i2c, akxxxx_id);
> +
> +static const struct of_device_id akxxxx_of_match[] = {
> +	{ .compatible = "asahi-kasei,ak8975",
> +	  .data = &akxxxx_def_array[AK8975]},
> +	{ .compatible = "ak8975",
> +	  .data = &akxxxx_def_array[AK8975]},
> +	{ .compatible = "asahi-kasei,ak8963",
> +	  .data = &akxxxx_def_array[AK8963]},
> +	{ .compatible = "ak8963",
> +	  .data = &akxxxx_def_array[AK8963]},
> +	{ .compatible = "asahi-kasei,ak09911",
> +	  .data = &akxxxx_def_array[AK09911]},
> +	{ .compatible = "ak09911",
> +	  .data = &akxxxx_def_array[AK09911]},
> +	{ .compatible = "asahi-kasei,ak09912",
> +	  .data = &akxxxx_def_array[AK09912]},
> +	{ .compatible = "ak09912",
> +	  .data = &akxxxx_def_array[AK09912]},
>  	{ }
>  };
> -MODULE_DEVICE_TABLE(of, ak8975_of_match);
> +MODULE_DEVICE_TABLE(of, akxxxx_of_match);
>
> -static struct i2c_driver ak8975_driver = {
> +static struct i2c_driver akxxxx_driver = {
>  	.driver = {
> -		.name	= "ak8975",
> -		.of_match_table = ak8975_of_match,
> -		.acpi_match_table = ACPI_PTR(ak_acpi_match),
> +		.name	= "akxxxx",
> +		.of_match_table = of_match_ptr(akxxxx_of_match),
> +		.acpi_match_table = ACPI_PTR(akxxxx_acpi_match),
>  	},
> -	.probe		= ak8975_probe,
> -	.id_table	= ak8975_id,
> +	.probe		= akxxxx_probe,
> +	.id_table	= akxxxx_id,
>  };
> -module_i2c_driver(ak8975_driver);
> +module_i2c_driver(akxxxx_driver);
>
>  MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
> -MODULE_DESCRIPTION("AK8975 magnetometer driver");
> +MODULE_DESCRIPTION("ak8975 and ak09912 magnetometer driver");
>  MODULE_LICENSE("GPL");
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCHv2] iio: ak8975: Add AKM0991x support.
  2014-11-05 14:31       ` Jonathan Cameron
@ 2014-11-05 21:19         ` Gwendal Grignou
  2014-11-05 22:10           ` [PATCH 0/3] Support all AKM compass in a single driver Gwendal Grignou
  2014-11-06 14:32           ` [PATCHv2] iio: ak8975: Add AKM0991x support Srinivas Pandruvada
  0 siblings, 2 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-05 21:19 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Gwendal Grignou, Srinivas Pandruvada, knaack.h, linux-iio

On Wed, Nov 5, 2014 at 6:31 AM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 04/11/14 19:41, Gwendal Grignou wrote:
>> File and config id remains the same, but driver is now named akxxxx.
>
> Don't do that.  Please name the driver after one supported part rather
> than a general wild card.  Leaving it as ak8975 would be sensible.
> Wild cards seem like a good idea until along comes a part that fits
> in the naming scheme but is otherwise totally different.
>
> Much cleaner to just pick a part to use in naming the driver and
> make it clear what parts are supported in kconfig (see iio/adc/max1363 for
> example).
Will do. It is cleaner indeed.
>
> I would have prefered this as a two patch series.  The first combining
> the existing drivers, and the second (small one) adding the new part
> support.
I will submit 3 patches soon:
- minor fixes in the driver first,
- one that refactor the current driver to introduce a definition data structure
- the next one that remove ak9911.c and add support for ak09911 and
ak9912 into ak8975.c
>
> Would have broken it up into logical steps thus making it a little
> easier to check for feature parity etc.
>
> Once you've dropped the name change, this patch will contain less noise.
> Also, there are a couple of sensible refactorings in there.  I would
> have prefered these to be in precursor patches that made much smaller
> changes.
The re-factoring became obvious after I introduce the definition data structure.
>
> This sort of merging of drivers is one of the hardest types of code to
> review, so making it as easy as possible for reviewers by packaging
> it up as baby steps is the way to go.
>
> There is still some work to be done in convincing people that merging
> the drivers is sensible (I'm pretty much convinced having waded through
> this) but that is an easier job with a well split up series of steps!
>
> Jonathan
>
>> Move AKM09911 support in the same file.
>>
>> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
>> ---
>>
>> Addressed all comments from Hartmut.
>>
>>  drivers/iio/magnetometer/Kconfig   |  19 +-
>>  drivers/iio/magnetometer/Makefile  |   1 -
>>  drivers/iio/magnetometer/ak09911.c | 326 -------------------
>>  drivers/iio/magnetometer/ak8975.c  | 629 ++++++++++++++++++++++++++-----------
>>  4 files changed, 444 insertions(+), 531 deletions(-)
>>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
>>
>> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
>> index b2dba9e..67f005d 100644
>> --- a/drivers/iio/magnetometer/Kconfig
>> +++ b/drivers/iio/magnetometer/Kconfig
>> @@ -6,26 +6,15 @@
>>  menu "Magnetometer sensors"
>>
>>  config AK8975
>> -     tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
>> +     tristate "Asahi Kasei AK 3-Axis Magnetometer"
>>       depends on I2C
>>       depends on GPIOLIB
>>       help
>> -       Say yes here to build support for Asahi Kasei AK8975 3-Axis
>> -       Magnetometer. This driver can also support AK8963, if i2c
>> -       device name is identified as ak8963.
>> +       Say yes here to build support for Asahi Kasei AK8975, AK8963,
>> +       AK09911 or AK09912 3-Axis Magnetometer.
>>
>>         To compile this driver as a module, choose M here: the module
>> -       will be called ak8975.
>> -
>> -config AK09911
>> -     tristate "Asahi Kasei AK09911 3-axis Compass"
>> -     depends on I2C
>> -     help
>> -       Say yes here to build support for Asahi Kasei AK09911 3-Axis
>> -       Magnetometer.
>> -
>> -       To compile this driver as a module, choose M here: the module
>> -       will be called ak09911.
>> +       will be called akxxxx.
>>
>>  config MAG3110
>>       tristate "Freescale MAG3110 3-Axis Magnetometer"
>> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
>> index b91315e..0f5d3c9 100644
>> --- a/drivers/iio/magnetometer/Makefile
>> +++ b/drivers/iio/magnetometer/Makefile
>> @@ -3,7 +3,6 @@
>>  #
>>
>>  # When adding new entries keep the list in alphabetical order
>> -obj-$(CONFIG_AK09911)        += ak09911.o
>>  obj-$(CONFIG_AK8975) += ak8975.o
>>  obj-$(CONFIG_MAG3110)        += mag3110.o
>>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
>> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
>> deleted file mode 100644
>> index b2bc942..0000000
>> --- a/drivers/iio/magnetometer/ak09911.c
>> +++ /dev/null
>> @@ -1,326 +0,0 @@
>> -/*
>> - * AK09911 3-axis compass driver
>> - * Copyright (c) 2014, 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.
>> - */
>> -
>> -#include <linux/kernel.h>
>> -#include <linux/module.h>
>> -#include <linux/init.h>
>> -#include <linux/types.h>
>> -#include <linux/slab.h>
>> -#include <linux/delay.h>
>> -#include <linux/i2c.h>
>> -#include <linux/acpi.h>
>> -#include <linux/iio/iio.h>
>> -
>> -#define AK09911_REG_WIA1             0x00
>> -#define AK09911_REG_WIA2             0x01
>> -#define AK09911_WIA1_VALUE           0x48
>> -#define AK09911_WIA2_VALUE           0x05
>> -
>> -#define AK09911_REG_ST1                      0x10
>> -#define AK09911_REG_HXL                      0x11
>> -#define AK09911_REG_HXH                      0x12
>> -#define AK09911_REG_HYL                      0x13
>> -#define AK09911_REG_HYH                      0x14
>> -#define AK09911_REG_HZL                      0x15
>> -#define AK09911_REG_HZH                      0x16
>> -
>> -#define AK09911_REG_ASAX             0x60
>> -#define AK09911_REG_ASAY             0x61
>> -#define AK09911_REG_ASAZ             0x62
>> -
>> -#define AK09911_REG_CNTL1            0x30
>> -#define AK09911_REG_CNTL2            0x31
>> -#define AK09911_REG_CNTL3            0x32
>> -
>> -#define AK09911_MODE_SNG_MEASURE     0x01
>> -#define AK09911_MODE_SELF_TEST               0x10
>> -#define AK09911_MODE_FUSE_ACCESS     0x1F
>> -#define AK09911_MODE_POWERDOWN               0x00
>> -#define AK09911_RESET_DATA           0x01
>> -
>> -#define AK09911_REG_CNTL1            0x30
>> -#define AK09911_REG_CNTL2            0x31
>> -#define AK09911_REG_CNTL3            0x32
>> -
>> -#define AK09911_RAW_TO_GAUSS(asa)    ((((asa) + 128) * 6000) / 256)
>> -
>> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS    500
>> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
>> -
>> -struct ak09911_data {
>> -     struct i2c_client       *client;
>> -     struct mutex            lock;
>> -     u8                      asa[3];
>> -     long                    raw_to_gauss[3];
>> -};
>> -
>> -static const int ak09911_index_to_reg[] = {
>> -     AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
>> -};
>> -
>> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
>> -{
>> -     int ret;
>> -
>> -     switch (mode) {
>> -     case AK09911_MODE_SNG_MEASURE:
>> -     case AK09911_MODE_SELF_TEST:
>> -     case AK09911_MODE_FUSE_ACCESS:
>> -     case AK09911_MODE_POWERDOWN:
>> -             ret = i2c_smbus_write_byte_data(client,
>> -                                             AK09911_REG_CNTL2, mode);
>> -             if (ret < 0) {
>> -                     dev_err(&client->dev, "set_mode error\n");
>> -                     return ret;
>> -             }
>> -             /* After mode change wait atleast 100us */
>> -             usleep_range(100, 500);
>> -             break;
>> -     default:
>> -             dev_err(&client->dev,
>> -                     "%s: Unknown mode(%d).", __func__, mode);
>> -             return -EINVAL;
>> -     }
>> -
>> -     return ret;
>> -}
>> -
>> -/* Get Sensitivity Adjustment value */
>> -static int ak09911_get_asa(struct i2c_client *client)
>> -{
>> -     struct iio_dev *indio_dev = i2c_get_clientdata(client);
>> -     struct ak09911_data *data = iio_priv(indio_dev);
>> -     int ret;
>> -
>> -     ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
>> -     if (ret < 0)
>> -             return ret;
>> -
>> -     /* Get asa data and store in the device data. */
>> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
>> -                                         3, data->asa);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Not able to read asa data\n");
>> -             return ret;
>> -     }
>> -
>> -     ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
>> -     if (ret < 0)
>> -             return ret;
>> -
>> -     data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
>> -     data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
>> -     data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
>> -
>> -     return 0;
>> -}
>> -
>> -static int ak09911_verify_chip_id(struct i2c_client *client)
>> -{
>> -     u8 wia_val[2];
>> -     int ret;
>> -
>> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
>> -                                         2, wia_val);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Error reading WIA\n");
>> -             return ret;
>> -     }
>> -
>> -     dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
>> -
>> -     if (wia_val[0] != AK09911_WIA1_VALUE ||
>> -             wia_val[1] != AK09911_WIA2_VALUE) {
>> -             dev_err(&client->dev, "Device ak09911 not found\n");
>> -             return -ENODEV;
>> -     }
>> -
>> -     return 0;
>> -}
>> -
>> -static int wait_conversion_complete_polled(struct ak09911_data *data)
>> -{
>> -     struct i2c_client *client = data->client;
>> -     u8 read_status;
>> -     u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
>> -     int ret;
>> -
>> -     /* Wait for the conversion to complete. */
>> -     while (timeout_ms) {
>> -             msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
>> -             ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
>> -             if (ret < 0) {
>> -                     dev_err(&client->dev, "Error in reading ST1\n");
>> -                     return ret;
>> -             }
>> -             read_status = ret & 0x01;
>> -             if (read_status)
>> -                     break;
>> -             timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
>> -     }
>> -     if (!timeout_ms) {
>> -             dev_err(&client->dev, "Conversion timeout happened\n");
>> -             return -EIO;
>> -     }
>> -
>> -     return read_status;
>> -}
>> -
>> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
>> -{
>> -     struct ak09911_data *data = iio_priv(indio_dev);
>> -     struct i2c_client *client = data->client;
>> -     int ret;
>> -
>> -     mutex_lock(&data->lock);
>> -
>> -     ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
>> -     if (ret < 0)
>> -             goto fn_exit;
>> -
>> -     ret = wait_conversion_complete_polled(data);
>> -     if (ret < 0)
>> -             goto fn_exit;
>> -
>> -     /* Read data */
>> -     ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Read axis data fails\n");
>> -             goto fn_exit;
>> -     }
>> -
>> -     mutex_unlock(&data->lock);
>> -
>> -     /* Clamp to valid range. */
>> -     *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
>> -
>> -     return IIO_VAL_INT;
>> -
>> -fn_exit:
>> -     mutex_unlock(&data->lock);
>> -
>> -     return ret;
>> -}
>> -
>> -static int ak09911_read_raw(struct iio_dev *indio_dev,
>> -                         struct iio_chan_spec const *chan,
>> -                         int *val, int *val2,
>> -                         long mask)
>> -{
>> -     struct ak09911_data *data = iio_priv(indio_dev);
>> -
>> -     switch (mask) {
>> -     case IIO_CHAN_INFO_RAW:
>> -             return ak09911_read_axis(indio_dev, chan->address, val);
>> -     case IIO_CHAN_INFO_SCALE:
>> -             *val = 0;
>> -             *val2 = data->raw_to_gauss[chan->address];
>> -             return IIO_VAL_INT_PLUS_MICRO;
>> -     }
>> -
>> -     return -EINVAL;
>> -}
>> -
>> -#define AK09911_CHANNEL(axis, index)                                 \
>> -     {                                                               \
>> -             .type = IIO_MAGN,                                       \
>> -             .modified = 1,                                          \
>> -             .channel2 = IIO_MOD_##axis,                             \
>> -             .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
>> -                          BIT(IIO_CHAN_INFO_SCALE),                  \
>> -             .address = index,                                       \
>> -     }
>> -
>> -static const struct iio_chan_spec ak09911_channels[] = {
>> -     AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
>> -};
>> -
>> -static const struct iio_info ak09911_info = {
>> -     .read_raw = &ak09911_read_raw,
>> -     .driver_module = THIS_MODULE,
>> -};
>> -
>> -static const struct acpi_device_id ak_acpi_match[] = {
>> -     {"AK009911", 0},
>> -     { },
>> -};
>> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
>> -
>> -static int ak09911_probe(struct i2c_client *client,
>> -                      const struct i2c_device_id *id)
>> -{
>> -     struct iio_dev *indio_dev;
>> -     struct ak09911_data *data;
>> -     const char *name;
>> -     int ret;
>> -
>> -     ret = ak09911_verify_chip_id(client);
>> -     if (ret) {
>> -             dev_err(&client->dev, "AK00911 not detected\n");
>> -             return -ENODEV;
>> -     }
>> -
>> -     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
>> -     if (indio_dev == NULL)
>> -             return -ENOMEM;
>> -
>> -     data = iio_priv(indio_dev);
>> -     i2c_set_clientdata(client, indio_dev);
>> -
>> -     data->client = client;
>> -     mutex_init(&data->lock);
>> -
>> -     ret = ak09911_get_asa(client);
>> -     if (ret)
>> -             return ret;
>> -
>> -     if (id)
>> -             name = id->name;
>> -     else if (ACPI_HANDLE(&client->dev))
>> -             name = dev_name(&client->dev);
>> -     else
>> -             return -ENODEV;
>> -
>> -     dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>> -
>> -     indio_dev->dev.parent = &client->dev;
>> -     indio_dev->channels = ak09911_channels;
>> -     indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
>> -     indio_dev->info = &ak09911_info;
>> -     indio_dev->modes = INDIO_DIRECT_MODE;
>> -     indio_dev->name = name;
>> -
>> -     return devm_iio_device_register(&client->dev, indio_dev);
>> -}
>> -
>> -static const struct i2c_device_id ak09911_id[] = {
>> -     {"ak09911", 0},
>> -     {}
>> -};
>> -
>> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
>> -
>> -static struct i2c_driver ak09911_driver = {
>> -     .driver = {
>> -             .name   = "ak09911",
>> -             .acpi_match_table = ACPI_PTR(ak_acpi_match),
>> -     },
>> -     .probe          = ak09911_probe,
>> -     .id_table       = ak09911_id,
>> -};
>> -module_i2c_driver(ak09911_driver);
>> -
>> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
>> -MODULE_LICENSE("GPL v2");
>> -MODULE_DESCRIPTION("AK09911 Compass driver");
>> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
>> index bf5ef07..f2ec32f 100644
>> --- a/drivers/iio/magnetometer/ak8975.c
>> +++ b/drivers/iio/magnetometer/ak8975.c
>> @@ -35,12 +35,14 @@
>>
>>  #include <linux/iio/iio.h>
>>  #include <linux/iio/sysfs.h>
>> +
>> +#define AKXXXX_COMPANY_ID            0x48
>> +
>>  /*
>> - * Register definitions, as well as various shifts and masks to get at the
>> - * individual fields of the registers.
>> + * AK_8975 Register definitions, as well as various shifts and masks to get
>> + * at the individual fields of the registers.
>>   */
>>  #define AK8975_REG_WIA                       0x00
>> -#define AK8975_DEVICE_ID             0x48
>>
>>  #define AK8975_REG_INFO                      0x01
>>
>> @@ -62,12 +64,12 @@
>>  #define AK8975_REG_ST2_HOFL_MASK     (1 << AK8975_REG_ST2_HOFL_SHIFT)
>>
>>  #define AK8975_REG_CNTL                      0x0A
>> +#define AK8975_REG_CNTL_MODE_POWER_DOWN      0x00
>> +#define AK8975_REG_CNTL_MODE_ONCE    0x01
>> +#define AK8975_REG_CNTL_MODE_SELF_TEST       0x08
>> +#define AK8975_REG_CNTL_MODE_FUSE_ROM        0x0F
>>  #define AK8975_REG_CNTL_MODE_SHIFT   0
>>  #define AK8975_REG_CNTL_MODE_MASK    (0xF << AK8975_REG_CNTL_MODE_SHIFT)
>> -#define AK8975_REG_CNTL_MODE_POWER_DOWN      0
>> -#define AK8975_REG_CNTL_MODE_ONCE    1
>> -#define AK8975_REG_CNTL_MODE_SELF_TEST       8
>> -#define AK8975_REG_CNTL_MODE_FUSE_ROM        0xF
>>
>>  #define AK8975_REG_RSVC                      0x0B
>>  #define AK8975_REG_ASTC                      0x0C
>> @@ -81,59 +83,359 @@
>>  #define AK8975_MAX_REGS                      AK8975_REG_ASAZ
>>
>>  /*
>> + * AK09912 Register definitions
>> + */
>> +#define AK09912_REG_WIA1             0x00
>> +#define AK09912_REG_WIA2             0x01
>> +#define AK09912_DEVICE_ID            0x04
>> +#define AK09911_DEVICE_ID            0x05
>> +
>> +#define AK09911_REG_INFO1            0x02
>> +#define AK09911_REG_INFO2            0x03
>> +
>> +#define AK09912_REG_ST1                      0x10
>> +
>> +#define AK09912_REG_ST1_DRDY_SHIFT   0
>> +#define AK09912_REG_ST1_DRDY_MASK    (1 << AK09912_REG_ST1_DRDY_SHIFT)
>> +
>> +#define AK09912_REG_HXL                      0x11
>> +#define AK09912_REG_HXH                      0x12
>> +#define AK09912_REG_HYL                      0x13
>> +#define AK09912_REG_HYH                      0x14
>> +#define AK09912_REG_HZL                      0x15
>> +#define AK09912_REG_HZH                      0x16
>> +#define AK09912_REG_TMPS             0x17
>> +
>> +#define AK09912_REG_ST2                      0x18
>> +#define AK09912_REG_ST2_HOFL_SHIFT   3
>> +#define AK09912_REG_ST2_HOFL_MASK    (1 << AK09912_REG_ST2_HOFL_SHIFT)
>> +
>> +#define AK09912_REG_CNTL1            0x30
>> +
>> +#define AK09912_REG_CNTL2            0x31
>> +#define AK09912_REG_CNTL_MODE_POWER_DOWN     0x00
>> +#define AK09912_REG_CNTL_MODE_ONCE   0x01
>> +#define AK09912_REG_CNTL_MODE_SELF_TEST      0x10
>> +#define AK09912_REG_CNTL_MODE_FUSE_ROM       0x1F
>> +#define AK09912_REG_CNTL2_MODE_SHIFT 0
>> +#define AK09912_REG_CNTL2_MODE_MASK  (0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
>> +
>> +#define AK09912_REG_CNTL3            0x32
>> +
>> +#define AK09912_REG_TS1                      0x33
>> +#define AK09912_REG_TS2                      0x34
>> +#define AK09912_REG_TS3                      0x35
>> +#define AK09912_REG_I2CDIS           0x36
>> +#define AK09912_REG_TS4                      0x37
>> +
>> +#define AK09912_REG_ASAX             0x60
>> +#define AK09912_REG_ASAY             0x61
>> +#define AK09912_REG_ASAZ             0x62
>> +
>> +#define AK09912_MAX_REGS             AK09912_REG_ASAZ
>> +
>> +/*
>>   * Miscellaneous values.
>>   */
>> -#define AK8975_MAX_CONVERSION_TIMEOUT        500
>> -#define AK8975_CONVERSION_DONE_POLL_TIME 10
>> -#define AK8975_DATA_READY_TIMEOUT    ((100*HZ)/1000)
>> -#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
>> -#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
>> -
>> -/* Compatible Asahi Kasei Compass parts */
>> -enum asahi_compass_chipset {
>> +#define AKXXXX_MAX_CONVERSION_TIMEOUT        500
>> +#define AKXXXX_CONVERSION_DONE_POLL_TIME 10
>> +#define AKXXXX_DATA_READY_TIMEOUT    ((100*HZ)/1000)
>> +
>> +/*
>> + * Precalculate scale factor (in Gauss units) for each axis and
>> + * store in the device data.
>> + *
>> + * This scale factor is axis-dependent, and is derived from 3 calibration
>> + * factors ASA(x), ASA(y), and ASA(z).
>> + *
>> + * These ASA values are read from the sensor device at start of day, and
>> + * cached in the device context struct.
>> + *
>> + * Adjusting the flux value with the sensitivity adjustment value should be
>> + * done via the following formula:
>> + *
>> + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
>> + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
>> + * is the resultant adjusted value.
>> + *
>> + * We reduce the formula to:
>> + *
>> + * Hadj = H * (ASA + 128) / 256
>> + *
>> + * H is in the range of -4096 to 4095.  The magnetometer has a range of
>> + * +-1229uT.  To go from the raw value to uT is:
>> + *
>> + * HuT = H * 1229/4096, or roughly, 3/10.
>> + *
>> + * Since 1uT = 0.01 gauss, our final scale factor becomes:
>> + *
>> + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
>> + * Hadj = H * ((ASA + 128) * 0.003) / 256
>> + *
>> + * Since ASA doesn't change, we cache the resultant scale factor into the
>> + * device context in akxxxx_setup().
>> + *
>> + * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
>> + * multiply the stored scale value by 1e6.
>> + */
>> +long ak8975_raw_to_gauss(u16 data)
>> +{
>> +     return (((long)data + 128) * 3000) / 256;
>> +}
>> +
>> +/*
>> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
>> + *
>> + * H is in the range of +-8190.  The magnetometer has a range of
>> + * +-4912uT.  To go from the raw value to uT is:
>> + *
>> + * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
>> + */
>> +long ak8963_09911_raw_to_gauss(u16 data)
>> +{
>> +     return (((long)data + 128) * 6000) / 256;
>> +}
>> +
>> +/*
>> + * For AK09912, same calculation, except the device is more sensitive:
>> + *
>> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
>> + * +-4912uT.  To go from the raw value to uT is:
>> + *
>> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
>> + */
>> +long ak09912_raw_to_gauss(u16 data)
>> +{
>> +     return (((long)data + 128) * 1500) / 256;
>> +}
>> +
>> +enum ak_type {
>>       AK8975,
>>       AK8963,
>> +     AK09911,
>> +     AK09912,
>> +     AK_MAX_TYPE
>> +};
>> +
>> +enum ak_ctrl_reg_addr {
>> +     ST1,
>> +     ST2,
>> +     CNTL,
>> +     ASA_BASE,
>> +     MAX_REGS,
>> +     REGS_END,
>> +};
>> +
>> +enum ak_ctrl_reg_mask {
>> +     ST1_DRDY,
>> +     ST2_HOFL,
>> +     ST2_DERR,
>> +     CNTL_MODE,
>> +     MASK_END,
>> +};
>> +
>> +enum ak_ctrl_mode {
>> +     POWER_DOWN,
>> +     MODE_ONCE,
>> +     SELF_TEST,
>> +     FUSE_ROM,
>> +     MODE_END,
>> +};
>> +
>> +struct akxxxx_def {
>> +     enum ak_type type;
>> +     long (*raw_to_gauss)(u16 data);
>> +     u16 range;
>> +     u8 ctrl_regs[REGS_END];
>> +     u8 ctrl_masks[MASK_END];
>> +     u8 ctrl_modes[MODE_END];
>> +     u8 data_regs[3];
>> +} akxxxx_def_array[AK_MAX_TYPE] = {
>> +{
>> +     .type = AK8975,
>> +     .raw_to_gauss = ak8975_raw_to_gauss,
>> +     .range = 4096,
>> +     .ctrl_regs = {
>> +             AK8975_REG_ST1,
>> +             AK8975_REG_ST2,
>> +             AK8975_REG_CNTL,
>> +             AK8975_REG_ASAX,
>> +             AK8975_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK8975_REG_ST1_DRDY_MASK,
>> +             AK8975_REG_ST2_HOFL_MASK,
>> +             AK8975_REG_ST2_DERR_MASK,
>> +             AK8975_REG_CNTL_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK8975_REG_CNTL_MODE_POWER_DOWN,
>> +             AK8975_REG_CNTL_MODE_ONCE,
>> +             AK8975_REG_CNTL_MODE_SELF_TEST,
>> +             AK8975_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK8975_REG_HXL,
>> +             AK8975_REG_HYL,
>> +             AK8975_REG_HZL},
>> +},
>> +{
>> +     .type = AK8963,
>> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
>> +     .range = 8190,
>> +     .ctrl_regs = {
>> +             AK8975_REG_ST1,
>> +             AK8975_REG_ST2,
>> +             AK8975_REG_CNTL,
>> +             AK8975_REG_ASAX,
>> +             AK8975_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK8975_REG_ST1_DRDY_MASK,
>> +             AK8975_REG_ST2_HOFL_MASK,
>> +             0,
>> +             AK8975_REG_CNTL_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK8975_REG_CNTL_MODE_POWER_DOWN,
>> +             AK8975_REG_CNTL_MODE_ONCE,
>> +             AK8975_REG_CNTL_MODE_SELF_TEST,
>> +             AK8975_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK8975_REG_HXL,
>> +             AK8975_REG_HYL,
>> +             AK8975_REG_HZL},
>> +},
>> +{
>> +     .type = AK09911,
>> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
>> +     .range = 8192,
>> +     .ctrl_regs = {
>> +             AK09912_REG_ST1,
>> +             AK09912_REG_ST2,
>> +             AK09912_REG_CNTL2,
>> +             AK09912_REG_ASAX,
>> +             AK09912_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK09912_REG_ST1_DRDY_MASK,
>> +             AK09912_REG_ST2_HOFL_MASK,
>> +             0,
>> +             AK09912_REG_CNTL2_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
>> +             AK09912_REG_CNTL_MODE_ONCE,
>> +             AK09912_REG_CNTL_MODE_SELF_TEST,
>> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK09912_REG_HXL,
>> +             AK09912_REG_HYL,
>> +             AK09912_REG_HZL},
>> +},
>> +{
>> +     .type = AK09912,
>> +     .raw_to_gauss = ak09912_raw_to_gauss,
>> +     .range = 32752,
>> +     .ctrl_regs = {
>> +             AK09912_REG_ST1,
>> +             AK09912_REG_ST2,
>> +             AK09912_REG_CNTL2,
>> +             AK09912_REG_ASAX,
>> +             AK09912_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK09912_REG_ST1_DRDY_MASK,
>> +             AK09912_REG_ST2_HOFL_MASK,
>> +             0,
>> +             AK09912_REG_CNTL2_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
>> +             AK09912_REG_CNTL_MODE_ONCE,
>> +             AK09912_REG_CNTL_MODE_SELF_TEST,
>> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK09912_REG_HXL,
>> +             AK09912_REG_HYL,
>> +             AK09912_REG_HZL},
>> +}
>>  };
>>
>>  /*
>>   * Per-instance context data for the device.
>>   */
>> -struct ak8975_data {
>> +struct akxxxx_data {
>>       struct i2c_client       *client;
>> +     struct akxxxx_def       *def;
>>       struct attribute_group  attrs;
>>       struct mutex            lock;
>>       u8                      asa[3];
>>       long                    raw_to_gauss[3];
>> -     u8                      reg_cache[AK8975_MAX_REGS];
> Justify dropping this register cache...
reg_cache was only needed in ak8975_write_data, which was only used to write the
CNTL register. It is needed for this register to preserve the bits
outside the mode mask.
>
>>       int                     eoc_gpio;
>>       int                     eoc_irq;
>>       wait_queue_head_t       data_ready_queue;
>>       unsigned long           flags;
>> -     enum asahi_compass_chipset chipset;
>> +     u8                      cntl_cache;
>>  };
>>
>> -static const int ak8975_index_to_reg[] = {
>> -     AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
>> -};
>> +/*
>> + * Return 0 if the i2c device is the one we expect.
>> + * return a negative error number otherwise
>> + */
>> +static int akxxxx_who_i_am(struct i2c_client *client, enum ak_type type)
>> +{
>> +     u8 wia_val[2];
>> +     int ret;
>> +
>> +     /*
>> +      * Signature for each device:
>> +      * Device   |  WIA1       |  WIA2
>> +      * AK09912  |  COMPANY_ID |  AK09912_DEVICE_ID
>> +      * AK09911  |  COMPANY_ID |  AK09911_DEVICE_ID
>> +      * AK8975   |  COMPANY_ID |  NA
>> +      * AK8963   |  COMPANY_ID |  NA
>> +      */
>> +     ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
>> +                                         2, wia_val);
>> +     if (ret < 0) {
>> +             dev_err(&client->dev, "Error reading WIA\n");
>> +             return ret;
>> +     }
>> +
>> +     ret = -ENODEV;
>> +
>> +     if (wia_val[0] != AKXXXX_COMPANY_ID)
>> +             return ret;
>> +
>> +     switch (type) {
>> +     case AK8975:
>> +     case AK8963:
>> +             ret = 0;
>> +             break;
>> +     case AK09911:
>> +             if (wia_val[1] == AK09911_DEVICE_ID)
>> +                     ret = 0;
>> +             break;
>> +     case AK09912:
>> +             if (wia_val[1] == AK09912_DEVICE_ID)
>> +                     ret = 0;
>> +             break;
>> +     default:
>> +             dev_err(&client->dev, "Type %d unknown\n", type);
>> +     }
>> +     return ret;
>> +}
>>
>>  /*
>> - * Helper function to write to the I2C device's registers.
>> + * Helper function to write to CNTL register.
>>   */
>> -static int ak8975_write_data(struct i2c_client *client,
>> -                          u8 reg, u8 val, u8 mask, u8 shift)
>> +static int akxxxx_set_mode(struct akxxxx_data *data, enum ak_ctrl_mode mode)
>>  {
>> -     struct iio_dev *indio_dev = i2c_get_clientdata(client);
>> -     struct ak8975_data *data = iio_priv(indio_dev);
>>       u8 regval;
>>       int ret;
>>
>> -     regval = (data->reg_cache[reg] & ~mask) | (val << shift);
>> -     ret = i2c_smbus_write_byte_data(client, reg, regval);
>> +     regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
>> +             data->def->ctrl_modes[mode];
>> +     ret = i2c_smbus_write_byte_data(
>> +             data->client, data->def->ctrl_regs[CNTL], regval);
>>       if (ret < 0) {
>> -             dev_err(&client->dev, "Write to device fails status %x\n", ret);
>>               return ret;
>>       }
>> -     data->reg_cache[reg] = regval;
>> +     data->cntl_cache = regval;
>> +     /* After mode change wait atleast 100us */
>> +     usleep_range(100, 500);
>>
>>       return 0;
>>  }
>> @@ -141,9 +443,9 @@ static int ak8975_write_data(struct i2c_client *client,
>>  /*
>>   * Handle data ready irq
>>   */
>> -static irqreturn_t ak8975_irq_handler(int irq, void *data)
>> +static irqreturn_t akxxxx_irq_handler(int irq, void *data)
>>  {
>> -     struct ak8975_data *ak8975 = data;
>> +     struct akxxxx_data *ak8975 = data;
>>
>>       set_bit(0, &ak8975->flags);
>>       wake_up(&ak8975->data_ready_queue);
>> @@ -154,7 +456,7 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data)
>>  /*
>>   * Install data ready interrupt handler
>>   */
>> -static int ak8975_setup_irq(struct ak8975_data *data)
>> +static int akxxxx_setup_irq(struct akxxxx_data *data)
>>  {
>>       struct i2c_client *client = data->client;
>>       int rc;
>> @@ -165,9 +467,9 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>>       else
>>               irq = gpio_to_irq(data->eoc_gpio);
>>
>> -     rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
>> -                      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
>> -                      dev_name(&client->dev), data);
>> +     rc = devm_request_irq(&client->dev, irq, akxxxx_irq_handler,
>> +                           IRQF_TRIGGER_RISING | IRQF_ONESHOT,
>> +                           dev_name(&client->dev), data);
>>       if (rc < 0) {
>>               dev_err(&client->dev,
>>                       "irq %d request failed, (gpio %d): %d\n",
>> @@ -187,38 +489,22 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>>   * Perform some start-of-day setup, including reading the asa calibration
>>   * values and caching them.
>>   */
>> -static int ak8975_setup(struct i2c_client *client)
>> +static int akxxxx_setup(struct i2c_client *client)
>>  {
>>       struct iio_dev *indio_dev = i2c_get_clientdata(client);
>> -     struct ak8975_data *data = iio_priv(indio_dev);
>> -     u8 device_id;
>> +     struct akxxxx_data *data = iio_priv(indio_dev);
>>       int ret;
>>
>> -     /* Confirm that the device we're talking to is really an AK8975. */
>> -     ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Error reading WIA\n");
>> -             return ret;
>> -     }
>> -     device_id = ret;
>> -     if (device_id != AK8975_DEVICE_ID) {
>> -             dev_err(&client->dev, "Device ak8975 not found\n");
>> -             return -ENODEV;
>> -     }
>> -
>>       /* Write the fused rom access mode. */
>> -     ret = ak8975_write_data(client,
>> -                             AK8975_REG_CNTL,
>> -                             AK8975_REG_CNTL_MODE_FUSE_ROM,
>> -                             AK8975_REG_CNTL_MODE_MASK,
>> -                             AK8975_REG_CNTL_MODE_SHIFT);
>> +     ret = akxxxx_set_mode(data, FUSE_ROM);
> The factoring out of set_mode makes sense, but should probably have
> been a separate precursor patch to the main series.
Done
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Error in setting fuse access mode\n");
>>               return ret;
>>       }
>>
>>       /* Get asa data and store in the device data. */
>> -     ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
>> +     ret = i2c_smbus_read_i2c_block_data(client,
>> +                                         data->def->ctrl_regs[ASA_BASE],
>>                                           3, data->asa);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Not able to read asa data\n");
>> @@ -226,14 +512,14 @@ static int ak8975_setup(struct i2c_client *client)
>>       }
>>
>>       /* After reading fuse ROM data set power-down mode */
>> -     ret = ak8975_write_data(client,
>> -                             AK8975_REG_CNTL,
>> -                             AK8975_REG_CNTL_MODE_POWER_DOWN,
>> -                             AK8975_REG_CNTL_MODE_MASK,
>> -                             AK8975_REG_CNTL_MODE_SHIFT);
>> +     ret = akxxxx_set_mode(data, POWER_DOWN);
>> +     if (ret < 0) {
>> +             dev_err(&client->dev, "Error in setting power-down mode\n");
>> +             return ret;
>> +     }
>>
>>       if (data->eoc_gpio > 0 || client->irq) {
>> -             ret = ak8975_setup_irq(data);
>> +             ret = akxxxx_setup_irq(data);
>>               if (ret < 0) {
>>                       dev_err(&client->dev,
>>                               "Error setting data ready interrupt\n");
>> @@ -241,101 +527,50 @@ static int ak8975_setup(struct i2c_client *client)
>>               }
>>       }
>>
> Why has this disappeared?
I move it just below setting mode to POWER_DOWN, where it belongs, as
Hartmut pointed out.
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Error in setting power-down mode\n");
>> -             return ret;
>> -     }
>> -
>> -/*
>> - * Precalculate scale factor (in Gauss units) for each axis and
>> - * store in the device data.
>> - *
>> - * This scale factor is axis-dependent, and is derived from 3 calibration
>> - * factors ASA(x), ASA(y), and ASA(z).
>> - *
>> - * These ASA values are read from the sensor device at start of day, and
>> - * cached in the device context struct.
>> - *
>> - * Adjusting the flux value with the sensitivity adjustment value should be
>> - * done via the following formula:
>> - *
>> - * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
>> - *
>> - * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
>> - * is the resultant adjusted value.
>> - *
>> - * We reduce the formula to:
>> - *
>> - * Hadj = H * (ASA + 128) / 256
>> - *
>> - * H is in the range of -4096 to 4095.  The magnetometer has a range of
>> - * +-1229uT.  To go from the raw value to uT is:
>> - *
>> - * HuT = H * 1229/4096, or roughly, 3/10.
>> - *
>> - * Since 1uT = 0.01 gauss, our final scale factor becomes:
>> - *
>> - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
>> - * Hadj = H * ((ASA + 128) * 0.003) / 256
>> - *
>> - * Since ASA doesn't change, we cache the resultant scale factor into the
>> - * device context in ak8975_setup().
>> - */
>
>> -     if (data->chipset == AK8963) {
>> -             /*
>> -              * H range is +-8190 and magnetometer range is +-4912.
>> -              * So HuT using the above explanation for 8975,
>> -              * 4912/8190 = ~ 6/10.
>> -              * So the Hadj should use 6/10 instead of 3/10.
>> -              */
>> -             data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
>> -             data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
>> -             data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
>> -     } else {
>> -             data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
>> -             data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
>> -             data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
>> -     }
>> +     data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
>> +     data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
>> +     data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
>>
>>       return 0;
>>  }
>>
>> -static int wait_conversion_complete_gpio(struct ak8975_data *data)
>> +static int wait_conversion_complete_gpio(struct akxxxx_data *data)
>>  {
>>       struct i2c_client *client = data->client;
>> -     u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
>> +     u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
>>       int ret;
>>
>>       /* Wait for the conversion to complete. */
>>       while (timeout_ms) {
>> -             msleep(AK8975_CONVERSION_DONE_POLL_TIME);
>> +             msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
>>               if (gpio_get_value(data->eoc_gpio))
>>                       break;
>> -             timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
>> +             timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
>>       }
>>       if (!timeout_ms) {
>>               dev_err(&client->dev, "Conversion timeout happened\n");
>>               return -EINVAL;
>>       }
>>
>> -     ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
>> +     ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
>>       if (ret < 0)
>>               dev_err(&client->dev, "Error in reading ST1\n");
>>
>>       return ret;
>>  }
>>
>> -static int wait_conversion_complete_polled(struct ak8975_data *data)
>> +static int wait_conversion_complete_polled(struct akxxxx_data *data)
>>  {
>>       struct i2c_client *client = data->client;
>>       u8 read_status;
>> -     u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
>> +     u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
>>       int ret;
>>
>>       /* Wait for the conversion to complete. */
>>       while (timeout_ms) {
>> -             msleep(AK8975_CONVERSION_DONE_POLL_TIME);
>> -             ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
>> +             msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
>> +             ret = i2c_smbus_read_byte_data(
>> +                             client, data->def->ctrl_regs[ST1]);
>>               if (ret < 0) {
>>                       dev_err(&client->dev, "Error in reading ST1\n");
>>                       return ret;
>> @@ -343,7 +578,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>>               read_status = ret;
>>               if (read_status)
>>                       break;
>> -             timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
>> +             timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
>>       }
>>       if (!timeout_ms) {
>>               dev_err(&client->dev, "Conversion timeout happened\n");
>> @@ -354,13 +589,13 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>>  }
>>
>>  /* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
>> -static int wait_conversion_complete_interrupt(struct ak8975_data *data)
>> +static int wait_conversion_complete_interrupt(struct akxxxx_data *data)
>>  {
>>       int ret;
>>
>>       ret = wait_event_timeout(data->data_ready_queue,
>>                                test_bit(0, &data->flags),
>> -                              AK8975_DATA_READY_TIMEOUT);
>> +                              AKXXXX_DATA_READY_TIMEOUT);
>>       clear_bit(0, &data->flags);
>>
>>       return ret > 0 ? 0 : -ETIME;
>> @@ -369,20 +604,16 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
>>  /*
>>   * Emits the raw flux value for the x, y, or z axis.
>>   */
>> -static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>> +static int akxxxx_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>  {
>> -     struct ak8975_data *data = iio_priv(indio_dev);
>> +     struct akxxxx_data *data = iio_priv(indio_dev);
>>       struct i2c_client *client = data->client;
>>       int ret;
>>
>>       mutex_lock(&data->lock);
>>
>>       /* Set up the device for taking a sample. */
>> -     ret = ak8975_write_data(client,
>> -                             AK8975_REG_CNTL,
>> -                             AK8975_REG_CNTL_MODE_ONCE,
>> -                             AK8975_REG_CNTL_MODE_MASK,
>> -                             AK8975_REG_CNTL_MODE_SHIFT);
>> +     ret = akxxxx_set_mode(data, MODE_ONCE);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Error in setting operating mode\n");
>>               goto exit;
>> @@ -399,14 +630,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>               goto exit;
>>
>>       /* This will be executed only for non-interrupt based waiting case */
>> -     if (ret & AK8975_REG_ST1_DRDY_MASK) {
>> -             ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
>> +     if (ret & data->def->ctrl_masks[ST1_DRDY]) {
>> +             ret = i2c_smbus_read_byte_data(
>> +                             client, data->def->ctrl_regs[ST2]);
>>               if (ret < 0) {
>>                       dev_err(&client->dev, "Error in reading ST2\n");
>>                       goto exit;
>>               }
>> -             if (ret & (AK8975_REG_ST2_DERR_MASK |
>> -                        AK8975_REG_ST2_HOFL_MASK)) {
>> +             if (ret & (data->def->ctrl_masks[ST2_DERR] |
>> +                        data->def->ctrl_masks[ST2_HOFL])) {
>>                       dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
>>                       ret = -EINVAL;
>>                       goto exit;
>> @@ -415,7 +647,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>
>>       /* Read the flux value from the appropriate register
>>          (the register is specified in the iio device attributes). */
>> -     ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
>> +     ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Read axis data fails\n");
>>               goto exit;
>> @@ -424,7 +656,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>       mutex_unlock(&data->lock);
>>
>>       /* Clamp to valid range. */
>> -     *val = clamp_t(s16, ret, -4096, 4095);
>> +     *val = clamp_t(s16, ret, -data->def->range, data->def->range);
> Well that isn't going to be the same as before...  I think you need a
> - 1
-1 is needed only for ak8975: the others are +-8190 or +-32752. I drop
the -1, allowing ak8957 values to be +- 4096.
>>       return IIO_VAL_INT;
>>
>>  exit:
>> @@ -432,16 +664,16 @@ exit:
>>       return ret;
>>  }
>>
>> -static int ak8975_read_raw(struct iio_dev *indio_dev,
>> +static int akxxxx_read_raw(struct iio_dev *indio_dev,
>>                          struct iio_chan_spec const *chan,
>>                          int *val, int *val2,
>>                          long mask)
>>  {
>> -     struct ak8975_data *data = iio_priv(indio_dev);
>> +     struct akxxxx_data *data = iio_priv(indio_dev);
>>
>>       switch (mask) {
>>       case IIO_CHAN_INFO_RAW:
>> -             return ak8975_read_axis(indio_dev, chan->address, val);
>> +             return akxxxx_read_axis(indio_dev, chan->address, val);
>>       case IIO_CHAN_INFO_SCALE:
>>               *val = 0;
>>               *val2 = data->raw_to_gauss[chan->address];
>> @@ -450,7 +682,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
>>       return -EINVAL;
>>  }
>>
>> -#define AK8975_CHANNEL(axis, index)                                  \
>> +#define AKXXXX_CHANNEL(axis, index)                                  \
>>       {                                                               \
>>               .type = IIO_MAGN,                                       \
>>               .modified = 1,                                          \
>> @@ -460,40 +692,41 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
>>               .address = index,                                       \
>>       }
>>
>> -static const struct iio_chan_spec ak8975_channels[] = {
>> -     AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
>> +static const struct iio_chan_spec akxxxx_channels[] = {
>> +     AKXXXX_CHANNEL(X, 0), AKXXXX_CHANNEL(Y, 1), AKXXXX_CHANNEL(Z, 2),
>>  };
>>
>> -static const struct iio_info ak8975_info = {
>> -     .read_raw = &ak8975_read_raw,
>> +static const struct iio_info akxxxx_info = {
>> +     .read_raw = &akxxxx_read_raw,
>>       .driver_module = THIS_MODULE,
>>  };
>>
>> -static const struct acpi_device_id ak_acpi_match[] = {
>> -     {"AK8975", AK8975},
>> -     {"AK8963", AK8963},
>> -     {"INVN6500", AK8963},
>> +static const struct acpi_device_id akxxxx_acpi_match[] = {
>> +     {"AK8975", (uintptr_t)&akxxxx_def_array[AK8975]},
>> +     {"AK8963", (uintptr_t)&akxxxx_def_array[AK8963]},
>> +     {"AK09911", (uintptr_t)&akxxxx_def_array[AK09911]},
>> +     {"AK09912", (uintptr_t)&akxxxx_def_array[AK09912]},
> Again, I'm lost as to why you have changed form an index....
>>       { },
>>  };
>> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
>> +MODULE_DEVICE_TABLE(acpi, akxxxx_acpi_match);
>>
>> -static const char *ak8975_match_acpi_device(struct device *dev,
>> -                                         enum asahi_compass_chipset *chipset)
>> +static const char *akxxxx_match_acpi_device(struct device *dev,
>> +                                         struct akxxxx_def **def)
>>  {
>>       const struct acpi_device_id *id;
>>
>>       id = acpi_match_device(dev->driver->acpi_match_table, dev);
>>       if (!id)
>>               return NULL;
>> -     *chipset = (int)id->driver_data;
>> +     *def = (struct akxxxx_def *)id->driver_data;
>>
>>       return dev_name(dev);
>>  }
>>
>> -static int ak8975_probe(struct i2c_client *client,
>> +static int akxxxx_probe(struct i2c_client *client,
>>                       const struct i2c_device_id *id)
>>  {
>> -     struct ak8975_data *data;
>> +     struct akxxxx_data *data;
>>       struct iio_dev *indio_dev;
>>       int eoc_gpio;
>>       int err;
>> @@ -513,8 +746,8 @@ static int ak8975_probe(struct i2c_client *client,
>>       /* We may not have a GPIO based IRQ to scan, that is fine, we will
>>          poll if so */
>>       if (gpio_is_valid(eoc_gpio)) {
>> -             err = devm_gpio_request_one(&client->dev, eoc_gpio,
>> -                                                     GPIOF_IN, "ak_8975");
>> +             err = devm_gpio_request_one(
>> +                     &client->dev, eoc_gpio, GPIOF_IN, id->name);
>>               if (err < 0) {
>>                       dev_err(&client->dev,
>>                               "failed to request GPIO %d, error %d\n",
>> @@ -534,23 +767,25 @@ static int ak8975_probe(struct i2c_client *client,
>>       data->client = client;
>>       data->eoc_gpio = eoc_gpio;
> Rather curriously data->eoc_gpio is set to the same value twice...
I made a copy&paste mistake, will be fixed.
>
>>       data->eoc_irq = 0;
>> -
>>       /* id will be NULL when enumerated via ACPI */
>>       if (id) {
>> -             data->chipset =
>> -                     (enum asahi_compass_chipset)(id->driver_data);
>> +             data->def = (struct akxxxx_def *)id->driver_data;
>>               name = id->name;
>>       } else if (ACPI_HANDLE(&client->dev))
>> -             name = ak8975_match_acpi_device(&client->dev, &data->chipset);
>> +             name = akxxxx_match_acpi_device(&client->dev, &data->def);
>>       else
>>               return -ENOSYS;
>>
>> +     if (akxxxx_who_i_am(client, data->def->type) < 0) {
>> +             dev_err(&client->dev, "Unexpected device\n");
>> +             return -ENODEV;
>> +     }
>>       dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>>
>>       /* Perform some basic start-of-day setup of the device. */
>> -     err = ak8975_setup(client);
>> +     err = akxxxx_setup(client);
>>       if (err < 0) {
>> -             dev_err(&client->dev, "AK8975 initialization fails\n");
>> +             dev_err(&client->dev, "%s initialization fails\n", name);
>>               return err;
>>       }
>>
>> @@ -558,9 +793,9 @@ static int ak8975_probe(struct i2c_client *client,
>>       mutex_init(&data->lock);
>>       data->eoc_gpio = eoc_gpio;
>>       indio_dev->dev.parent = &client->dev;
>> -     indio_dev->channels = ak8975_channels;
>> -     indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
>> -     indio_dev->info = &ak8975_info;
>> +     indio_dev->channels = akxxxx_channels;
>> +     indio_dev->num_channels = ARRAY_SIZE(akxxxx_channels);
>> +     indio_dev->info = &akxxxx_info;
>>       indio_dev->modes = INDIO_DIRECT_MODE;
>>       indio_dev->name = name;
>>       err = devm_iio_device_register(&client->dev, indio_dev);
>> @@ -570,32 +805,48 @@ static int ak8975_probe(struct i2c_client *client,
>>       return 0;
> Not your fault, but this function could just end
> return devm_iio_device_register(...) which would be cleaner.
> (in case you haven't guessed I'm looking at the result rather than the
> patch ;)
>>  }
>>
>> -static const struct i2c_device_id ak8975_id[] = {
>> -     {"ak8975", AK8975},
>> -     {"ak8963", AK8963},
>> +static const struct i2c_device_id akxxxx_id[] = {
>> +     {"ak8975", (uintptr_t)&akxxxx_def_array[AK8975]},
>> +     {"ak8963", (uintptr_t)&akxxxx_def_array[AK8963]},
>> +     {"ak09911", (uintptr_t)&akxxxx_def_array[AK09911]},
>> +     {"ak09912", (uintptr_t)&akxxxx_def_array[AK09912]},
> Why not use an index instead as per the original driver?
> Same result, less type casting mess ;)
>>       {}
>>  };
>>
>> -MODULE_DEVICE_TABLE(i2c, ak8975_id);
>> -
>> -static const struct of_device_id ak8975_of_match[] = {
>> -     { .compatible = "asahi-kasei,ak8975", },
>> -     { .compatible = "ak8975", },
>> +MODULE_DEVICE_TABLE(i2c, akxxxx_id);
>> +
>> +static const struct of_device_id akxxxx_of_match[] = {
>> +     { .compatible = "asahi-kasei,ak8975",
>> +       .data = &akxxxx_def_array[AK8975]},
>> +     { .compatible = "ak8975",
>> +       .data = &akxxxx_def_array[AK8975]},
>> +     { .compatible = "asahi-kasei,ak8963",
>> +       .data = &akxxxx_def_array[AK8963]},
>> +     { .compatible = "ak8963",
>> +       .data = &akxxxx_def_array[AK8963]},
>> +     { .compatible = "asahi-kasei,ak09911",
>> +       .data = &akxxxx_def_array[AK09911]},
>> +     { .compatible = "ak09911",
>> +       .data = &akxxxx_def_array[AK09911]},
>> +     { .compatible = "asahi-kasei,ak09912",
>> +       .data = &akxxxx_def_array[AK09912]},
>> +     { .compatible = "ak09912",
>> +       .data = &akxxxx_def_array[AK09912]},
>>       { }
>>  };
>> -MODULE_DEVICE_TABLE(of, ak8975_of_match);
>> +MODULE_DEVICE_TABLE(of, akxxxx_of_match);
>>
>> -static struct i2c_driver ak8975_driver = {
>> +static struct i2c_driver akxxxx_driver = {
>>       .driver = {
>> -             .name   = "ak8975",
>> -             .of_match_table = ak8975_of_match,
>> -             .acpi_match_table = ACPI_PTR(ak_acpi_match),
>> +             .name   = "akxxxx",
>> +             .of_match_table = of_match_ptr(akxxxx_of_match),
>> +             .acpi_match_table = ACPI_PTR(akxxxx_acpi_match),
>>       },
>> -     .probe          = ak8975_probe,
>> -     .id_table       = ak8975_id,
>> +     .probe          = akxxxx_probe,
>> +     .id_table       = akxxxx_id,
>>  };
>> -module_i2c_driver(ak8975_driver);
>> +module_i2c_driver(akxxxx_driver);
>>
>>  MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
>> -MODULE_DESCRIPTION("AK8975 magnetometer driver");
>> +MODULE_DESCRIPTION("ak8975 and ak09912 magnetometer driver");
>>  MODULE_LICENSE("GPL");
>>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/3] Support all AKM compass in a single driver
  2014-11-05 21:19         ` Gwendal Grignou
@ 2014-11-05 22:10           ` Gwendal Grignou
  2014-11-05 22:10             ` [PATCH 1/3] iio: ak8975: minor fixes Gwendal Grignou
                               ` (2 more replies)
  2014-11-06 14:32           ` [PATCHv2] iio: ak8975: Add AKM0991x support Srinivas Pandruvada
  1 sibling, 3 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-05 22:10 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23, knaack.h; +Cc: linux-iio, Gwendal Grignou

Currently, 2 drivers are used for supporting AKM compasses:
- ak8975 and ak8963 in ak875.c: these compasses support DRDY line and interrupt.
- ak09911 in ak0911.c: this compass has a new register map and does not support DRDY line.

A newer compass, ak09912 has the same register map as ak09911 but the same functionality as
ak8975. By adding support to ak09912 into ak8975, we can remove the driver specific to ak09911.

Gwendal Grignou (3):
  iio: ak8975: minor fixes
  iio: ak8975: add definition structure per compass type
  iio: ak8975: add ak09911 and ak09912 support

 drivers/iio/magnetometer/Kconfig   |  17 +-
 drivers/iio/magnetometer/Makefile  |   1 -
 drivers/iio/magnetometer/ak09911.c | 326 ------------------------
 drivers/iio/magnetometer/ak8975.c  | 501 +++++++++++++++++++++++++++----------
 4 files changed, 377 insertions(+), 468 deletions(-)
 delete mode 100644 drivers/iio/magnetometer/ak09911.c

-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/3] iio: ak8975: minor fixes
  2014-11-05 22:10           ` [PATCH 0/3] Support all AKM compass in a single driver Gwendal Grignou
@ 2014-11-05 22:10             ` Gwendal Grignou
  2014-11-06 15:00               ` Srinivas Pandruvada
  2014-11-17 20:13               ` [PATCH v2 " Gwendal Grignou
  2014-11-05 22:10             ` [PATCH 2/3] iio: ak8975: add definition structure per compass type Gwendal Grignou
  2014-11-05 22:10             ` [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support Gwendal Grignou
  2 siblings, 2 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-05 22:10 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23, knaack.h; +Cc: linux-iio, Gwendal Grignou

Fixes code duplication, return of function.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---
 drivers/iio/magnetometer/ak8975.c | 33 +++++++++++++--------------------
 1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index bf5ef07..12f0b00 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -64,10 +64,10 @@
 #define AK8975_REG_CNTL			0x0A
 #define AK8975_REG_CNTL_MODE_SHIFT	0
 #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
-#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
-#define AK8975_REG_CNTL_MODE_ONCE	1
-#define AK8975_REG_CNTL_MODE_SELF_TEST	8
-#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
+#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK8975_REG_CNTL_MODE_ONCE	0x01
+#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
+#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
 
 #define AK8975_REG_RSVC			0x0B
 #define AK8975_REG_ASTC			0x0C
@@ -166,8 +166,8 @@ static int ak8975_setup_irq(struct ak8975_data *data)
 		irq = gpio_to_irq(data->eoc_gpio);
 
 	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
-			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-			 dev_name(&client->dev), data);
+			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			      dev_name(&client->dev), data);
 	if (rc < 0) {
 		dev_err(&client->dev,
 			"irq %d request failed, (gpio %d): %d\n",
@@ -231,6 +231,10 @@ static int ak8975_setup(struct i2c_client *client)
 				AK8975_REG_CNTL_MODE_POWER_DOWN,
 				AK8975_REG_CNTL_MODE_MASK,
 				AK8975_REG_CNTL_MODE_SHIFT);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error in setting power-down mode\n");
+		return ret;
+	}
 
 	if (data->eoc_gpio > 0 || client->irq) {
 		ret = ak8975_setup_irq(data);
@@ -241,11 +245,6 @@ static int ak8975_setup(struct i2c_client *client)
 		}
 	}
 
-	if (ret < 0) {
-		dev_err(&client->dev, "Error in setting power-down mode\n");
-		return ret;
-	}
-
 /*
  * Precalculate scale factor (in Gauss units) for each axis and
  * store in the device data.
@@ -550,24 +549,18 @@ static int ak8975_probe(struct i2c_client *client,
 	/* Perform some basic start-of-day setup of the device. */
 	err = ak8975_setup(client);
 	if (err < 0) {
-		dev_err(&client->dev, "AK8975 initialization fails\n");
+		dev_err(&client->dev, "%s initialization fails\n", name);
 		return err;
 	}
 
-	data->client = client;
 	mutex_init(&data->lock);
-	data->eoc_gpio = eoc_gpio;
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->channels = ak8975_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
 	indio_dev->info = &ak8975_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = name;
-	err = devm_iio_device_register(&client->dev, indio_dev);
-	if (err < 0)
-		return err;
-
-	return 0;
+	return devm_iio_device_register(&client->dev, indio_dev);
 }
 
 static const struct i2c_device_id ak8975_id[] = {
@@ -588,7 +581,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match);
 static struct i2c_driver ak8975_driver = {
 	.driver = {
 		.name	= "ak8975",
-		.of_match_table = ak8975_of_match,
+		.of_match_table = of_match_ptr(ak8975_of_match),
 		.acpi_match_table = ACPI_PTR(ak_acpi_match),
 	},
 	.probe		= ak8975_probe,
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 2/3] iio: ak8975: add definition structure per compass type
  2014-11-05 22:10           ` [PATCH 0/3] Support all AKM compass in a single driver Gwendal Grignou
  2014-11-05 22:10             ` [PATCH 1/3] iio: ak8975: minor fixes Gwendal Grignou
@ 2014-11-05 22:10             ` Gwendal Grignou
  2014-11-06 15:02               ` Srinivas Pandruvada
  2014-11-19 11:25               ` Hartmut Knaack
  2014-11-05 22:10             ` [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support Gwendal Grignou
  2 siblings, 2 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-05 22:10 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23, knaack.h; +Cc: linux-iio, Gwendal Grignou

For each type of compass supported (AK8975 and AK8963),
add a definition structure for register masks, important registers,
raw data interpretation.
This change will make integrating new type of devices easier.

Remove i2c register cache. It is only used for one single register.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---
 drivers/iio/magnetometer/ak8975.c | 279 +++++++++++++++++++++++++-------------
 1 file changed, 184 insertions(+), 95 deletions(-)

diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index 12f0b00..b170654 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -86,13 +86,153 @@
 #define AK8975_MAX_CONVERSION_TIMEOUT	500
 #define AK8975_CONVERSION_DONE_POLL_TIME 10
 #define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
-#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
-#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
+
+/*
+ * Precalculate scale factor (in Gauss units) for each axis and
+ * store in the device data.
+ *
+ * This scale factor is axis-dependent, and is derived from 3 calibration
+ * factors ASA(x), ASA(y), and ASA(z).
+ *
+ * These ASA values are read from the sensor device at start of day, and
+ * cached in the device context struct.
+ *
+ * Adjusting the flux value with the sensitivity adjustment value should be
+ * done via the following formula:
+ *
+ * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
+ * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
+ * is the resultant adjusted value.
+ *
+ * We reduce the formula to:
+ *
+ * Hadj = H * (ASA + 128) / 256
+ *
+ * H is in the range of -4096 to 4095.  The magnetometer has a range of
+ * +-1229uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 1229/4096, or roughly, 3/10.
+ *
+ * Since 1uT = 0.01 gauss, our final scale factor becomes:
+ *
+ * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
+ * Hadj = H * ((ASA + 128) * 0.003) / 256
+ *
+ * Since ASA doesn't change, we cache the resultant scale factor into the
+ * device context in ak8975_setup().
+ *
+ * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
+ * multiply the stored scale value by 1e6.
+ */
+long ak8975_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 3000) / 256;
+}
+
+/*
+ * For AK8963, same calculation, but the device is less sensitive:
+ *
+ * H is in the range of +-8190.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
+ */
+long ak8963_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 6000) / 256;
+}
 
 /* Compatible Asahi Kasei Compass parts */
 enum asahi_compass_chipset {
 	AK8975,
 	AK8963,
+	AK_MAX_TYPE
+};
+
+enum ak_ctrl_reg_addr {
+	ST1,
+	ST2,
+	CNTL,
+	ASA_BASE,
+	MAX_REGS,
+	REGS_END,
+};
+
+enum ak_ctrl_reg_mask {
+	ST1_DRDY,
+	ST2_HOFL,
+	ST2_DERR,
+	CNTL_MODE,
+	MASK_END,
+};
+
+enum ak_ctrl_mode {
+	POWER_DOWN,
+	MODE_ONCE,
+	SELF_TEST,
+	FUSE_ROM,
+	MODE_END,
+};
+
+struct ak_def {
+	enum asahi_compass_chipset type;
+	long (*raw_to_gauss)(u16 data);
+	u16 range;
+	u8 ctrl_regs[REGS_END];
+	u8 ctrl_masks[MASK_END];
+	u8 ctrl_modes[MODE_END];
+	u8 data_regs[3];
+} ak_def_array[AK_MAX_TYPE] = {
+{
+	.type = AK8975,
+	.raw_to_gauss = ak8975_raw_to_gauss,
+	.range = 4096,
+	.ctrl_regs = {
+		AK8975_REG_ST1,
+		AK8975_REG_ST2,
+		AK8975_REG_CNTL,
+		AK8975_REG_ASAX,
+		AK8975_MAX_REGS},
+	.ctrl_masks = {
+		AK8975_REG_ST1_DRDY_MASK,
+		AK8975_REG_ST2_HOFL_MASK,
+		AK8975_REG_ST2_DERR_MASK,
+		AK8975_REG_CNTL_MODE_MASK},
+	.ctrl_modes = {
+		AK8975_REG_CNTL_MODE_POWER_DOWN,
+		AK8975_REG_CNTL_MODE_ONCE,
+		AK8975_REG_CNTL_MODE_SELF_TEST,
+		AK8975_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK8975_REG_HXL,
+		AK8975_REG_HYL,
+		AK8975_REG_HZL},
+},
+{
+	.type = AK8963,
+	.raw_to_gauss = ak8963_raw_to_gauss,
+	.range = 8190,
+	.ctrl_regs = {
+		AK8975_REG_ST1,
+		AK8975_REG_ST2,
+		AK8975_REG_CNTL,
+		AK8975_REG_ASAX,
+		AK8975_MAX_REGS},
+	.ctrl_masks = {
+		AK8975_REG_ST1_DRDY_MASK,
+		AK8975_REG_ST2_HOFL_MASK,
+		0,
+		AK8975_REG_CNTL_MODE_MASK},
+	.ctrl_modes = {
+		AK8975_REG_CNTL_MODE_POWER_DOWN,
+		AK8975_REG_CNTL_MODE_ONCE,
+		AK8975_REG_CNTL_MODE_SELF_TEST,
+		AK8975_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK8975_REG_HXL,
+		AK8975_REG_HYL,
+		AK8975_REG_HZL},
+},
 };
 
 /*
@@ -100,40 +240,36 @@ enum asahi_compass_chipset {
  */
 struct ak8975_data {
 	struct i2c_client	*client;
+	struct ak_def		*def;
 	struct attribute_group	attrs;
 	struct mutex		lock;
 	u8			asa[3];
 	long			raw_to_gauss[3];
-	u8			reg_cache[AK8975_MAX_REGS];
 	int			eoc_gpio;
 	int			eoc_irq;
 	wait_queue_head_t	data_ready_queue;
 	unsigned long		flags;
-	enum asahi_compass_chipset chipset;
-};
-
-static const int ak8975_index_to_reg[] = {
-	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
+	u8			cntl_cache;
 };
 
 /*
- * Helper function to write to the I2C device's registers.
+ * Helper function to write to CNTL register.
  */
-static int ak8975_write_data(struct i2c_client *client,
-			     u8 reg, u8 val, u8 mask, u8 shift)
+static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak8975_data *data = iio_priv(indio_dev);
 	u8 regval;
 	int ret;
 
-	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
-	ret = i2c_smbus_write_byte_data(client, reg, regval);
+	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
+		data->def->ctrl_modes[mode];
+	ret = i2c_smbus_write_byte_data(
+		data->client, data->def->ctrl_regs[CNTL], regval);
 	if (ret < 0) {
-		dev_err(&client->dev, "Write to device fails status %x\n", ret);
 		return ret;
 	}
-	data->reg_cache[reg] = regval;
+	data->cntl_cache = regval;
+	/* After mode change wait atleast 100us */
+	usleep_range(100, 500);
 
 	return 0;
 }
@@ -207,18 +343,15 @@ static int ak8975_setup(struct i2c_client *client)
 	}
 
 	/* Write the fused rom access mode. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_FUSE_ROM,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = ak8975_set_mode(data, FUSE_ROM);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting fuse access mode\n");
 		return ret;
 	}
 
 	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
+	ret = i2c_smbus_read_i2c_block_data(client,
+					    data->def->ctrl_regs[ASA_BASE],
 					    3, data->asa);
 	if (ret < 0) {
 		dev_err(&client->dev, "Not able to read asa data\n");
@@ -226,11 +359,7 @@ static int ak8975_setup(struct i2c_client *client)
 	}
 
 	/* After reading fuse ROM data set power-down mode */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_POWER_DOWN,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = ak8975_set_mode(data, POWER_DOWN);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting power-down mode\n");
 		return ret;
@@ -245,56 +374,9 @@ static int ak8975_setup(struct i2c_client *client)
 		}
 	}
 
-/*
- * Precalculate scale factor (in Gauss units) for each axis and
- * store in the device data.
- *
- * This scale factor is axis-dependent, and is derived from 3 calibration
- * factors ASA(x), ASA(y), and ASA(z).
- *
- * These ASA values are read from the sensor device at start of day, and
- * cached in the device context struct.
- *
- * Adjusting the flux value with the sensitivity adjustment value should be
- * done via the following formula:
- *
- * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
- *
- * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
- * is the resultant adjusted value.
- *
- * We reduce the formula to:
- *
- * Hadj = H * (ASA + 128) / 256
- *
- * H is in the range of -4096 to 4095.  The magnetometer has a range of
- * +-1229uT.  To go from the raw value to uT is:
- *
- * HuT = H * 1229/4096, or roughly, 3/10.
- *
- * Since 1uT = 0.01 gauss, our final scale factor becomes:
- *
- * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
- * Hadj = H * ((ASA + 128) * 0.003) / 256
- *
- * Since ASA doesn't change, we cache the resultant scale factor into the
- * device context in ak8975_setup().
- */
-	if (data->chipset == AK8963) {
-		/*
-		 * H range is +-8190 and magnetometer range is +-4912.
-		 * So HuT using the above explanation for 8975,
-		 * 4912/8190 = ~ 6/10.
-		 * So the Hadj should use 6/10 instead of 3/10.
-		 */
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
-	} else {
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
-	}
+	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
+	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
+	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
 
 	return 0;
 }
@@ -317,7 +399,7 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
 		return -EINVAL;
 	}
 
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
 	if (ret < 0)
 		dev_err(&client->dev, "Error in reading ST1\n");
 
@@ -334,7 +416,8 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
 	/* Wait for the conversion to complete. */
 	while (timeout_ms) {
 		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+		ret = i2c_smbus_read_byte_data(
+				client, data->def->ctrl_regs[ST1]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST1\n");
 			return ret;
@@ -377,11 +460,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 	mutex_lock(&data->lock);
 
 	/* Set up the device for taking a sample. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_ONCE,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = ak8975_set_mode(data, MODE_ONCE);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting operating mode\n");
 		goto exit;
@@ -398,14 +477,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 		goto exit;
 
 	/* This will be executed only for non-interrupt based waiting case */
-	if (ret & AK8975_REG_ST1_DRDY_MASK) {
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
+	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
+		ret = i2c_smbus_read_byte_data(
+				client, data->def->ctrl_regs[ST2]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST2\n");
 			goto exit;
 		}
-		if (ret & (AK8975_REG_ST2_DERR_MASK |
-			   AK8975_REG_ST2_HOFL_MASK)) {
+		if (ret & (data->def->ctrl_masks[ST2_DERR] |
+			   data->def->ctrl_masks[ST2_HOFL])) {
 			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
 			ret = -EINVAL;
 			goto exit;
@@ -414,7 +494,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 
 	/* Read the flux value from the appropriate register
 	   (the register is specified in the iio device attributes). */
-	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
+	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
 	if (ret < 0) {
 		dev_err(&client->dev, "Read axis data fails\n");
 		goto exit;
@@ -423,7 +503,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 	mutex_unlock(&data->lock);
 
 	/* Clamp to valid range. */
-	*val = clamp_t(s16, ret, -4096, 4095);
+	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
 	return IIO_VAL_INT;
 
 exit:
@@ -497,6 +577,7 @@ static int ak8975_probe(struct i2c_client *client,
 	int eoc_gpio;
 	int err;
 	const char *name = NULL;
+	enum asahi_compass_chipset chipset;
 
 	/* Grab and set up the supplied GPIO. */
 	if (client->dev.platform_data)
@@ -536,14 +617,20 @@ static int ak8975_probe(struct i2c_client *client,
 
 	/* id will be NULL when enumerated via ACPI */
 	if (id) {
-		data->chipset =
-			(enum asahi_compass_chipset)(id->driver_data);
+		chipset = (enum asahi_compass_chipset)(id->driver_data);
 		name = id->name;
 	} else if (ACPI_HANDLE(&client->dev))
-		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
+		name = ak8975_match_acpi_device(&client->dev, &chipset);
 	else
 		return -ENOSYS;
 
+	if (chipset >= AK_MAX_TYPE) {
+		dev_err(&client->dev, "AKM device type unsupported: %d\n",
+			chipset);
+		return -ENODEV;
+	}
+
+	data->def = &ak_def_array[chipset];
 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 
 	/* Perform some basic start-of-day setup of the device. */
@@ -574,7 +661,9 @@ MODULE_DEVICE_TABLE(i2c, ak8975_id);
 static const struct of_device_id ak8975_of_match[] = {
 	{ .compatible = "asahi-kasei,ak8975", },
 	{ .compatible = "ak8975", },
-	{ }
+	{ .compatible = "asahi-kasei,ak8963", },
+	{ .compatible = "ak8963", },
+	{}
 };
 MODULE_DEVICE_TABLE(of, ak8975_of_match);
 
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-05 22:10           ` [PATCH 0/3] Support all AKM compass in a single driver Gwendal Grignou
  2014-11-05 22:10             ` [PATCH 1/3] iio: ak8975: minor fixes Gwendal Grignou
  2014-11-05 22:10             ` [PATCH 2/3] iio: ak8975: add definition structure per compass type Gwendal Grignou
@ 2014-11-05 22:10             ` Gwendal Grignou
  2014-11-06 15:05               ` Srinivas Pandruvada
  2 siblings, 1 reply; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-05 22:10 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23, knaack.h; +Cc: linux-iio, Gwendal Grignou

Add 2 new definition entries to support ak0991x compass.
Add a more advanced function to check we are dealy with the
expected device.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---
 drivers/iio/magnetometer/Kconfig   |  17 +-
 drivers/iio/magnetometer/Makefile  |   1 -
 drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
 drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
 4 files changed, 184 insertions(+), 357 deletions(-)
 delete mode 100644 drivers/iio/magnetometer/ak09911.c

diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index b2dba9e..cd8750b 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -6,27 +6,16 @@
 menu "Magnetometer sensors"
 
 config AK8975
-	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+	tristate "Asahi Kasei AK 3-Axis Magnetometer"
 	depends on I2C
 	depends on GPIOLIB
 	help
-	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
-	  Magnetometer. This driver can also support AK8963, if i2c
-	  device name is identified as ak8963.
+	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
+	  AK09911 or AK09912 3-Axis Magnetometer.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called ak8975.
 
-config AK09911
-	tristate "Asahi Kasei AK09911 3-axis Compass"
-	depends on I2C
-	help
-	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
-	  Magnetometer.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called ak09911.
-
 config MAG3110
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
 	depends on I2C
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b91315e..0f5d3c9 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,7 +3,6 @@
 #
 
 # When adding new entries keep the list in alphabetical order
-obj-$(CONFIG_AK09911)	+= ak09911.o
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
deleted file mode 100644
index b2bc942..0000000
--- a/drivers/iio/magnetometer/ak09911.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * AK09911 3-axis compass driver
- * Copyright (c) 2014, 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/iio/iio.h>
-
-#define AK09911_REG_WIA1		0x00
-#define AK09911_REG_WIA2		0x01
-#define AK09911_WIA1_VALUE		0x48
-#define AK09911_WIA2_VALUE		0x05
-
-#define AK09911_REG_ST1			0x10
-#define AK09911_REG_HXL			0x11
-#define AK09911_REG_HXH			0x12
-#define AK09911_REG_HYL			0x13
-#define AK09911_REG_HYH			0x14
-#define AK09911_REG_HZL			0x15
-#define AK09911_REG_HZH			0x16
-
-#define AK09911_REG_ASAX		0x60
-#define AK09911_REG_ASAY		0x61
-#define AK09911_REG_ASAZ		0x62
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_MODE_SNG_MEASURE	0x01
-#define AK09911_MODE_SELF_TEST		0x10
-#define AK09911_MODE_FUSE_ACCESS	0x1F
-#define AK09911_MODE_POWERDOWN		0x00
-#define AK09911_RESET_DATA		0x01
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
-
-#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
-#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
-
-struct ak09911_data {
-	struct i2c_client	*client;
-	struct mutex		lock;
-	u8			asa[3];
-	long			raw_to_gauss[3];
-};
-
-static const int ak09911_index_to_reg[] = {
-	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
-};
-
-static int ak09911_set_mode(struct i2c_client *client, u8 mode)
-{
-	int ret;
-
-	switch (mode) {
-	case AK09911_MODE_SNG_MEASURE:
-	case AK09911_MODE_SELF_TEST:
-	case AK09911_MODE_FUSE_ACCESS:
-	case AK09911_MODE_POWERDOWN:
-		ret = i2c_smbus_write_byte_data(client,
-						AK09911_REG_CNTL2, mode);
-		if (ret < 0) {
-			dev_err(&client->dev, "set_mode error\n");
-			return ret;
-		}
-		/* After mode change wait atleast 100us */
-		usleep_range(100, 500);
-		break;
-	default:
-		dev_err(&client->dev,
-			"%s: Unknown mode(%d).", __func__, mode);
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-/* Get Sensitivity Adjustment value */
-static int ak09911_get_asa(struct i2c_client *client)
-{
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak09911_data *data = iio_priv(indio_dev);
-	int ret;
-
-	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
-	if (ret < 0)
-		return ret;
-
-	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
-					    3, data->asa);
-	if (ret < 0) {
-		dev_err(&client->dev, "Not able to read asa data\n");
-		return ret;
-	}
-
-	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
-	if (ret < 0)
-		return ret;
-
-	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
-	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
-	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
-
-	return 0;
-}
-
-static int ak09911_verify_chip_id(struct i2c_client *client)
-{
-	u8 wia_val[2];
-	int ret;
-
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
-					    2, wia_val);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-
-	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
-
-	if (wia_val[0] != AK09911_WIA1_VALUE ||
-		wia_val[1] != AK09911_WIA2_VALUE) {
-		dev_err(&client->dev, "Device ak09911 not found\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int wait_conversion_complete_polled(struct ak09911_data *data)
-{
-	struct i2c_client *client = data->client;
-	u8 read_status;
-	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
-	int ret;
-
-	/* Wait for the conversion to complete. */
-	while (timeout_ms) {
-		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
-		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
-		if (ret < 0) {
-			dev_err(&client->dev, "Error in reading ST1\n");
-			return ret;
-		}
-		read_status = ret & 0x01;
-		if (read_status)
-			break;
-		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
-	}
-	if (!timeout_ms) {
-		dev_err(&client->dev, "Conversion timeout happened\n");
-		return -EIO;
-	}
-
-	return read_status;
-}
-
-static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	int ret;
-
-	mutex_lock(&data->lock);
-
-	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
-	if (ret < 0)
-		goto fn_exit;
-
-	ret = wait_conversion_complete_polled(data);
-	if (ret < 0)
-		goto fn_exit;
-
-	/* Read data */
-	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
-	if (ret < 0) {
-		dev_err(&client->dev, "Read axis data fails\n");
-		goto fn_exit;
-	}
-
-	mutex_unlock(&data->lock);
-
-	/* Clamp to valid range. */
-	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
-
-	return IIO_VAL_INT;
-
-fn_exit:
-	mutex_unlock(&data->lock);
-
-	return ret;
-}
-
-static int ak09911_read_raw(struct iio_dev *indio_dev,
-			    struct iio_chan_spec const *chan,
-			    int *val, int *val2,
-			    long mask)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		return ak09911_read_axis(indio_dev, chan->address, val);
-	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = data->raw_to_gauss[chan->address];
-		return IIO_VAL_INT_PLUS_MICRO;
-	}
-
-	return -EINVAL;
-}
-
-#define AK09911_CHANNEL(axis, index)					\
-	{								\
-		.type = IIO_MAGN,					\
-		.modified = 1,						\
-		.channel2 = IIO_MOD_##axis,				\
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
-			     BIT(IIO_CHAN_INFO_SCALE),			\
-		.address = index,					\
-	}
-
-static const struct iio_chan_spec ak09911_channels[] = {
-	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
-};
-
-static const struct iio_info ak09911_info = {
-	.read_raw = &ak09911_read_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct acpi_device_id ak_acpi_match[] = {
-	{"AK009911", 0},
-	{ },
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
-static int ak09911_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	struct iio_dev *indio_dev;
-	struct ak09911_data *data;
-	const char *name;
-	int ret;
-
-	ret = ak09911_verify_chip_id(client);
-	if (ret) {
-		dev_err(&client->dev, "AK00911 not detected\n");
-		return -ENODEV;
-	}
-
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
-	if (indio_dev == NULL)
-		return -ENOMEM;
-
-	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-
-	data->client = client;
-	mutex_init(&data->lock);
-
-	ret = ak09911_get_asa(client);
-	if (ret)
-		return ret;
-
-	if (id)
-		name = id->name;
-	else if (ACPI_HANDLE(&client->dev))
-		name = dev_name(&client->dev);
-	else
-		return -ENODEV;
-
-	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
-
-	indio_dev->dev.parent = &client->dev;
-	indio_dev->channels = ak09911_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
-	indio_dev->info = &ak09911_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->name = name;
-
-	return devm_iio_device_register(&client->dev, indio_dev);
-}
-
-static const struct i2c_device_id ak09911_id[] = {
-	{"ak09911", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, ak09911_id);
-
-static struct i2c_driver ak09911_driver = {
-	.driver = {
-		.name	= "ak09911",
-		.acpi_match_table = ACPI_PTR(ak_acpi_match),
-	},
-	.probe		= ak09911_probe,
-	.id_table	= ak09911_id,
-};
-module_i2c_driver(ak09911_driver);
-
-MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("AK09911 Compass driver");
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index b170654..f8c7046 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -81,6 +81,58 @@
 #define AK8975_MAX_REGS			AK8975_REG_ASAZ
 
 /*
+ * AK09912 Register definitions
+ */
+#define AK09912_REG_WIA1		0x00
+#define AK09912_REG_WIA2		0x01
+#define AK09912_DEVICE_ID		0x04
+#define AK09911_DEVICE_ID		0x05
+
+#define AK09911_REG_INFO1		0x02
+#define AK09911_REG_INFO2		0x03
+
+#define AK09912_REG_ST1			0x10
+
+#define AK09912_REG_ST1_DRDY_SHIFT	0
+#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
+
+#define AK09912_REG_HXL			0x11
+#define AK09912_REG_HXH			0x12
+#define AK09912_REG_HYL			0x13
+#define AK09912_REG_HYH			0x14
+#define AK09912_REG_HZL			0x15
+#define AK09912_REG_HZH			0x16
+#define AK09912_REG_TMPS		0x17
+
+#define AK09912_REG_ST2			0x18
+#define AK09912_REG_ST2_HOFL_SHIFT	3
+#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
+
+#define AK09912_REG_CNTL1		0x30
+
+#define AK09912_REG_CNTL2		0x31
+#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK09912_REG_CNTL_MODE_ONCE	0x01
+#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
+#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
+#define AK09912_REG_CNTL2_MODE_SHIFT	0
+#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
+
+#define AK09912_REG_CNTL3		0x32
+
+#define AK09912_REG_TS1			0x33
+#define AK09912_REG_TS2			0x34
+#define AK09912_REG_TS3			0x35
+#define AK09912_REG_I2CDIS		0x36
+#define AK09912_REG_TS4			0x37
+
+#define AK09912_REG_ASAX		0x60
+#define AK09912_REG_ASAY		0x61
+#define AK09912_REG_ASAZ		0x62
+
+#define AK09912_MAX_REGS		AK09912_REG_ASAZ
+
+/*
  * Miscellaneous values.
  */
 #define AK8975_MAX_CONVERSION_TIMEOUT	500
@@ -130,22 +182,37 @@ long ak8975_raw_to_gauss(u16 data)
 }
 
 /*
- * For AK8963, same calculation, but the device is less sensitive:
+ * For AK8963 and AK09911, same calculation, but the device is less sensitive:
  *
  * H is in the range of +-8190.  The magnetometer has a range of
  * +-4912uT.  To go from the raw value to uT is:
  *
  * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
  */
-long ak8963_raw_to_gauss(u16 data)
+long ak8963_09911_raw_to_gauss(u16 data)
 {
 	return (((long)data + 128) * 6000) / 256;
 }
 
+/*
+ * For AK09912, same calculation, except the device is more sensitive:
+ *
+ * H is in the range of -32752 to 32752.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
+ */
+long ak09912_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 1500) / 256;
+}
+
 /* Compatible Asahi Kasei Compass parts */
 enum asahi_compass_chipset {
 	AK8975,
 	AK8963,
+	AK09911,
+	AK09912,
 	AK_MAX_TYPE
 };
 
@@ -210,7 +277,7 @@ struct ak_def {
 },
 {
 	.type = AK8963,
-	.raw_to_gauss = ak8963_raw_to_gauss,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
 	.range = 8190,
 	.ctrl_regs = {
 		AK8975_REG_ST1,
@@ -233,6 +300,56 @@ struct ak_def {
 		AK8975_REG_HYL,
 		AK8975_REG_HZL},
 },
+{
+	.type = AK09911,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
+	.range = 8192,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+},
+{
+	.type = AK09912,
+	.raw_to_gauss = ak09912_raw_to_gauss,
+	.range = 32752,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+}
 };
 
 /*
@@ -253,6 +370,55 @@ struct ak8975_data {
 };
 
 /*
+ * Return 0 if the i2c device is the one we expect.
+ * return a negative error number otherwise
+ */
+static int ak8975_who_i_am(struct i2c_client *client,
+			   enum asahi_compass_chipset type)
+{
+	u8 wia_val[2];
+	int ret;
+
+	/*
+	 * Signature for each device:
+	 * Device   |  WIA1      |  WIA2
+	 * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
+	 * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
+	 * AK8975   |  DEVICE_ID |  NA
+	 * AK8963   |  DEVICE_ID |  NA
+	 */
+	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
+					    2, wia_val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return ret;
+	}
+
+	ret = -ENODEV;
+
+	if (wia_val[0] != AK8975_DEVICE_ID)
+		return ret;
+
+	switch (type) {
+	case AK8975:
+	case AK8963:
+		ret = 0;
+		break;
+	case AK09911:
+		if (wia_val[1] == AK09911_DEVICE_ID)
+			ret = 0;
+		break;
+	case AK09912:
+		if (wia_val[1] == AK09912_DEVICE_ID)
+			ret = 0;
+		break;
+	default:
+		dev_err(&client->dev, "Type %d unknown\n", type);
+	}
+	return ret;
+}
+
+/*
  * Helper function to write to CNTL register.
  */
 static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
@@ -327,21 +493,8 @@ static int ak8975_setup(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct ak8975_data *data = iio_priv(indio_dev);
-	u8 device_id;
 	int ret;
 
-	/* Confirm that the device we're talking to is really an AK8975. */
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-	device_id = ret;
-	if (device_id != AK8975_DEVICE_ID) {
-		dev_err(&client->dev, "Device ak8975 not found\n");
-		return -ENODEV;
-	}
-
 	/* Write the fused rom access mode. */
 	ret = ak8975_set_mode(data, FUSE_ROM);
 	if (ret < 0) {
@@ -552,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
 	{"AK8975", AK8975},
 	{"AK8963", AK8963},
 	{"INVN6500", AK8963},
+	{"AK09911", AK09911},
+	{"AK09912", AK09912},
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
@@ -631,6 +786,10 @@ static int ak8975_probe(struct i2c_client *client,
 	}
 
 	data->def = &ak_def_array[chipset];
+	if (ak8975_who_i_am(client, data->def->type) < 0) {
+		dev_err(&client->dev, "Unexpected device\n");
+		return -ENODEV;
+	}
 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 
 	/* Perform some basic start-of-day setup of the device. */
@@ -653,6 +812,8 @@ static int ak8975_probe(struct i2c_client *client,
 static const struct i2c_device_id ak8975_id[] = {
 	{"ak8975", AK8975},
 	{"ak8963", AK8963},
+	{"ak09911", AK09911},
+	{"ak09912", AK09912},
 	{}
 };
 
@@ -663,6 +824,10 @@ static const struct of_device_id ak8975_of_match[] = {
 	{ .compatible = "ak8975", },
 	{ .compatible = "asahi-kasei,ak8963", },
 	{ .compatible = "ak8963", },
+	{ .compatible = "asahi-kasei,ak09911", },
+	{ .compatible = "ak09911", },
+	{ .compatible = "asahi-kasei,ak09912", },
+	{ .compatible = "ak09912", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, ak8975_of_match);
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCHv2] iio: ak8975: Add AKM0991x support.
  2014-11-05 21:19         ` Gwendal Grignou
  2014-11-05 22:10           ` [PATCH 0/3] Support all AKM compass in a single driver Gwendal Grignou
@ 2014-11-06 14:32           ` Srinivas Pandruvada
  2014-11-08 12:17             ` Jonathan Cameron
  1 sibling, 1 reply; 28+ messages in thread
From: Srinivas Pandruvada @ 2014-11-06 14:32 UTC (permalink / raw)
  To: Gwendal Grignou; +Cc: Jonathan Cameron, Gwendal Grignou, knaack.h, linux-iio

On Wed, 2014-11-05 at 13:19 -0800, Gwendal Grignou wrote:
> On Wed, Nov 5, 2014 at 6:31 AM, Jonathan Cameron <jic23@kernel.org> wrote:
> > On 04/11/14 19:41, Gwendal Grignou wrote:
> >> File and config id remains the same, but driver is now named akxxxx.
> >
> > Don't do that.  Please name the driver after one supported part rather
> > than a general wild card.  Leaving it as ak8975 would be sensible.
> > Wild cards seem like a good idea until along comes a part that fits
> > in the naming scheme but is otherwise totally different.
> >
> > Much cleaner to just pick a part to use in naming the driver and
> > make it clear what parts are supported in kconfig (see iio/adc/max1363 for
> > example).
> Will do. It is cleaner indeed.
> >
> > I would have prefered this as a two patch series.  The first combining
> > the existing drivers, and the second (small one) adding the new part
> > support.
> I will submit 3 patches soon:
> - minor fixes in the driver first,
> - one that refactor the current driver to introduce a definition data structure
> - the next one that remove ak9911.c and add support for ak09911 and
> ak9912 into ak8975.c
> >
> > Would have broken it up into logical steps thus making it a little
> > easier to check for feature parity etc.
> >
> > Once you've dropped the name change, this patch will contain less noise.
> > Also, there are a couple of sensible refactorings in there.  I would
> > have prefered these to be in precursor patches that made much smaller
> > changes.
> The re-factoring became obvious after I introduce the definition data structure.
> >
> > This sort of merging of drivers is one of the hardest types of code to
> > review, so making it as easy as possible for reviewers by packaging
> > it up as baby steps is the way to go.
> >
> > There is still some work to be done in convincing people that merging
> > the drivers is sensible (I'm pretty much convinced having waded through
> > this) but that is an easier job with a well split up series of steps!
> >
> > Jonathan
> >
> >> Move AKM09911 support in the same file.
> >>
> >> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> >> ---
> >>
> >> Addressed all comments from Hartmut.
> >>
> >>  drivers/iio/magnetometer/Kconfig   |  19 +-
> >>  drivers/iio/magnetometer/Makefile  |   1 -
> >>  drivers/iio/magnetometer/ak09911.c | 326 -------------------
> >>  drivers/iio/magnetometer/ak8975.c  | 629 ++++++++++++++++++++++++++-----------
> >>  4 files changed, 444 insertions(+), 531 deletions(-)
> >>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
> >>
> >> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> >> index b2dba9e..67f005d 100644
> >> --- a/drivers/iio/magnetometer/Kconfig
> >> +++ b/drivers/iio/magnetometer/Kconfig
> >> @@ -6,26 +6,15 @@
> >>  menu "Magnetometer sensors"
> >>
> >>  config AK8975
> >> -     tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> >> +     tristate "Asahi Kasei AK 3-Axis Magnetometer"
> >>       depends on I2C
> >>       depends on GPIOLIB
> >>       help
> >> -       Say yes here to build support for Asahi Kasei AK8975 3-Axis
> >> -       Magnetometer. This driver can also support AK8963, if i2c
> >> -       device name is identified as ak8963.
> >> +       Say yes here to build support for Asahi Kasei AK8975, AK8963,
> >> +       AK09911 or AK09912 3-Axis Magnetometer.
> >>
> >>         To compile this driver as a module, choose M here: the module
> >> -       will be called ak8975.
> >> -
> >> -config AK09911
> >> -     tristate "Asahi Kasei AK09911 3-axis Compass"
> >> -     depends on I2C
> >> -     help
> >> -       Say yes here to build support for Asahi Kasei AK09911 3-Axis
> >> -       Magnetometer.
> >> -
> >> -       To compile this driver as a module, choose M here: the module
> >> -       will be called ak09911.
> >> +       will be called akxxxx.
> >>
We already have released products with CONFIG_AK09911, so will next
kernel upgrade will break them. Customers don't allow config changes.
So we can't remove this config.
Merging of drivers is fine. At the least we should keep the config and
select the AK8975 when defined in the config if we remove AK09911.

Jonathan,
What do you think? This driver is part of a commercial released product.
As you know customers are very sensitive about .config changes.

Thanks,
Srinivas

> >>  config MAG3110
> >>       tristate "Freescale MAG3110 3-Axis Magnetometer"
> >> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
> >> index b91315e..0f5d3c9 100644
> >> --- a/drivers/iio/magnetometer/Makefile
> >> +++ b/drivers/iio/magnetometer/Makefile
> >> @@ -3,7 +3,6 @@
> >>  #
> >>
> >>  # When adding new entries keep the list in alphabetical order
> >> -obj-$(CONFIG_AK09911)        += ak09911.o
> >>  obj-$(CONFIG_AK8975) += ak8975.o
> >>  obj-$(CONFIG_MAG3110)        += mag3110.o
> >>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
> >> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
> >> deleted file mode 100644
> >> index b2bc942..0000000
> >> --- a/drivers/iio/magnetometer/ak09911.c
> >> +++ /dev/null
> >> @@ -1,326 +0,0 @@
> >> -/*
> >> - * AK09911 3-axis compass driver
> >> - * Copyright (c) 2014, 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.
> >> - */
> >> -
> >> -#include <linux/kernel.h>
> >> -#include <linux/module.h>
> >> -#include <linux/init.h>
> >> -#include <linux/types.h>
> >> -#include <linux/slab.h>
> >> -#include <linux/delay.h>
> >> -#include <linux/i2c.h>
> >> -#include <linux/acpi.h>
> >> -#include <linux/iio/iio.h>
> >> -
> >> -#define AK09911_REG_WIA1             0x00
> >> -#define AK09911_REG_WIA2             0x01
> >> -#define AK09911_WIA1_VALUE           0x48
> >> -#define AK09911_WIA2_VALUE           0x05
> >> -
> >> -#define AK09911_REG_ST1                      0x10
> >> -#define AK09911_REG_HXL                      0x11
> >> -#define AK09911_REG_HXH                      0x12
> >> -#define AK09911_REG_HYL                      0x13
> >> -#define AK09911_REG_HYH                      0x14
> >> -#define AK09911_REG_HZL                      0x15
> >> -#define AK09911_REG_HZH                      0x16
> >> -
> >> -#define AK09911_REG_ASAX             0x60
> >> -#define AK09911_REG_ASAY             0x61
> >> -#define AK09911_REG_ASAZ             0x62
> >> -
> >> -#define AK09911_REG_CNTL1            0x30
> >> -#define AK09911_REG_CNTL2            0x31
> >> -#define AK09911_REG_CNTL3            0x32
> >> -
> >> -#define AK09911_MODE_SNG_MEASURE     0x01
> >> -#define AK09911_MODE_SELF_TEST               0x10
> >> -#define AK09911_MODE_FUSE_ACCESS     0x1F
> >> -#define AK09911_MODE_POWERDOWN               0x00
> >> -#define AK09911_RESET_DATA           0x01
> >> -
> >> -#define AK09911_REG_CNTL1            0x30
> >> -#define AK09911_REG_CNTL2            0x31
> >> -#define AK09911_REG_CNTL3            0x32
> >> -
> >> -#define AK09911_RAW_TO_GAUSS(asa)    ((((asa) + 128) * 6000) / 256)
> >> -
> >> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS    500
> >> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
> >> -
> >> -struct ak09911_data {
> >> -     struct i2c_client       *client;
> >> -     struct mutex            lock;
> >> -     u8                      asa[3];
> >> -     long                    raw_to_gauss[3];
> >> -};
> >> -
> >> -static const int ak09911_index_to_reg[] = {
> >> -     AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
> >> -};
> >> -
> >> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
> >> -{
> >> -     int ret;
> >> -
> >> -     switch (mode) {
> >> -     case AK09911_MODE_SNG_MEASURE:
> >> -     case AK09911_MODE_SELF_TEST:
> >> -     case AK09911_MODE_FUSE_ACCESS:
> >> -     case AK09911_MODE_POWERDOWN:
> >> -             ret = i2c_smbus_write_byte_data(client,
> >> -                                             AK09911_REG_CNTL2, mode);
> >> -             if (ret < 0) {
> >> -                     dev_err(&client->dev, "set_mode error\n");
> >> -                     return ret;
> >> -             }
> >> -             /* After mode change wait atleast 100us */
> >> -             usleep_range(100, 500);
> >> -             break;
> >> -     default:
> >> -             dev_err(&client->dev,
> >> -                     "%s: Unknown mode(%d).", __func__, mode);
> >> -             return -EINVAL;
> >> -     }
> >> -
> >> -     return ret;
> >> -}
> >> -
> >> -/* Get Sensitivity Adjustment value */
> >> -static int ak09911_get_asa(struct i2c_client *client)
> >> -{
> >> -     struct iio_dev *indio_dev = i2c_get_clientdata(client);
> >> -     struct ak09911_data *data = iio_priv(indio_dev);
> >> -     int ret;
> >> -
> >> -     ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
> >> -     if (ret < 0)
> >> -             return ret;
> >> -
> >> -     /* Get asa data and store in the device data. */
> >> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
> >> -                                         3, data->asa);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Not able to read asa data\n");
> >> -             return ret;
> >> -     }
> >> -
> >> -     ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
> >> -     if (ret < 0)
> >> -             return ret;
> >> -
> >> -     data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
> >> -     data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
> >> -     data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
> >> -
> >> -     return 0;
> >> -}
> >> -
> >> -static int ak09911_verify_chip_id(struct i2c_client *client)
> >> -{
> >> -     u8 wia_val[2];
> >> -     int ret;
> >> -
> >> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
> >> -                                         2, wia_val);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Error reading WIA\n");
> >> -             return ret;
> >> -     }
> >> -
> >> -     dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
> >> -
> >> -     if (wia_val[0] != AK09911_WIA1_VALUE ||
> >> -             wia_val[1] != AK09911_WIA2_VALUE) {
> >> -             dev_err(&client->dev, "Device ak09911 not found\n");
> >> -             return -ENODEV;
> >> -     }
> >> -
> >> -     return 0;
> >> -}
> >> -
> >> -static int wait_conversion_complete_polled(struct ak09911_data *data)
> >> -{
> >> -     struct i2c_client *client = data->client;
> >> -     u8 read_status;
> >> -     u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
> >> -     int ret;
> >> -
> >> -     /* Wait for the conversion to complete. */
> >> -     while (timeout_ms) {
> >> -             msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
> >> -             ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
> >> -             if (ret < 0) {
> >> -                     dev_err(&client->dev, "Error in reading ST1\n");
> >> -                     return ret;
> >> -             }
> >> -             read_status = ret & 0x01;
> >> -             if (read_status)
> >> -                     break;
> >> -             timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
> >> -     }
> >> -     if (!timeout_ms) {
> >> -             dev_err(&client->dev, "Conversion timeout happened\n");
> >> -             return -EIO;
> >> -     }
> >> -
> >> -     return read_status;
> >> -}
> >> -
> >> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
> >> -{
> >> -     struct ak09911_data *data = iio_priv(indio_dev);
> >> -     struct i2c_client *client = data->client;
> >> -     int ret;
> >> -
> >> -     mutex_lock(&data->lock);
> >> -
> >> -     ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
> >> -     if (ret < 0)
> >> -             goto fn_exit;
> >> -
> >> -     ret = wait_conversion_complete_polled(data);
> >> -     if (ret < 0)
> >> -             goto fn_exit;
> >> -
> >> -     /* Read data */
> >> -     ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Read axis data fails\n");
> >> -             goto fn_exit;
> >> -     }
> >> -
> >> -     mutex_unlock(&data->lock);
> >> -
> >> -     /* Clamp to valid range. */
> >> -     *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
> >> -
> >> -     return IIO_VAL_INT;
> >> -
> >> -fn_exit:
> >> -     mutex_unlock(&data->lock);
> >> -
> >> -     return ret;
> >> -}
> >> -
> >> -static int ak09911_read_raw(struct iio_dev *indio_dev,
> >> -                         struct iio_chan_spec const *chan,
> >> -                         int *val, int *val2,
> >> -                         long mask)
> >> -{
> >> -     struct ak09911_data *data = iio_priv(indio_dev);
> >> -
> >> -     switch (mask) {
> >> -     case IIO_CHAN_INFO_RAW:
> >> -             return ak09911_read_axis(indio_dev, chan->address, val);
> >> -     case IIO_CHAN_INFO_SCALE:
> >> -             *val = 0;
> >> -             *val2 = data->raw_to_gauss[chan->address];
> >> -             return IIO_VAL_INT_PLUS_MICRO;
> >> -     }
> >> -
> >> -     return -EINVAL;
> >> -}
> >> -
> >> -#define AK09911_CHANNEL(axis, index)                                 \
> >> -     {                                                               \
> >> -             .type = IIO_MAGN,                                       \
> >> -             .modified = 1,                                          \
> >> -             .channel2 = IIO_MOD_##axis,                             \
> >> -             .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
> >> -                          BIT(IIO_CHAN_INFO_SCALE),                  \
> >> -             .address = index,                                       \
> >> -     }
> >> -
> >> -static const struct iio_chan_spec ak09911_channels[] = {
> >> -     AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
> >> -};
> >> -
> >> -static const struct iio_info ak09911_info = {
> >> -     .read_raw = &ak09911_read_raw,
> >> -     .driver_module = THIS_MODULE,
> >> -};
> >> -
> >> -static const struct acpi_device_id ak_acpi_match[] = {
> >> -     {"AK009911", 0},
> >> -     { },
> >> -};
> >> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> >> -
> >> -static int ak09911_probe(struct i2c_client *client,
> >> -                      const struct i2c_device_id *id)
> >> -{
> >> -     struct iio_dev *indio_dev;
> >> -     struct ak09911_data *data;
> >> -     const char *name;
> >> -     int ret;
> >> -
> >> -     ret = ak09911_verify_chip_id(client);
> >> -     if (ret) {
> >> -             dev_err(&client->dev, "AK00911 not detected\n");
> >> -             return -ENODEV;
> >> -     }
> >> -
> >> -     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> >> -     if (indio_dev == NULL)
> >> -             return -ENOMEM;
> >> -
> >> -     data = iio_priv(indio_dev);
> >> -     i2c_set_clientdata(client, indio_dev);
> >> -
> >> -     data->client = client;
> >> -     mutex_init(&data->lock);
> >> -
> >> -     ret = ak09911_get_asa(client);
> >> -     if (ret)
> >> -             return ret;
> >> -
> >> -     if (id)
> >> -             name = id->name;
> >> -     else if (ACPI_HANDLE(&client->dev))
> >> -             name = dev_name(&client->dev);
> >> -     else
> >> -             return -ENODEV;
> >> -
> >> -     dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> >> -
> >> -     indio_dev->dev.parent = &client->dev;
> >> -     indio_dev->channels = ak09911_channels;
> >> -     indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
> >> -     indio_dev->info = &ak09911_info;
> >> -     indio_dev->modes = INDIO_DIRECT_MODE;
> >> -     indio_dev->name = name;
> >> -
> >> -     return devm_iio_device_register(&client->dev, indio_dev);
> >> -}
> >> -
> >> -static const struct i2c_device_id ak09911_id[] = {
> >> -     {"ak09911", 0},
> >> -     {}
> >> -};
> >> -
> >> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
> >> -
> >> -static struct i2c_driver ak09911_driver = {
> >> -     .driver = {
> >> -             .name   = "ak09911",
> >> -             .acpi_match_table = ACPI_PTR(ak_acpi_match),
> >> -     },
> >> -     .probe          = ak09911_probe,
> >> -     .id_table       = ak09911_id,
> >> -};
> >> -module_i2c_driver(ak09911_driver);
> >> -
> >> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
> >> -MODULE_LICENSE("GPL v2");
> >> -MODULE_DESCRIPTION("AK09911 Compass driver");
> >> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> >> index bf5ef07..f2ec32f 100644
> >> --- a/drivers/iio/magnetometer/ak8975.c
> >> +++ b/drivers/iio/magnetometer/ak8975.c
> >> @@ -35,12 +35,14 @@
> >>
> >>  #include <linux/iio/iio.h>
> >>  #include <linux/iio/sysfs.h>
> >> +
> >> +#define AKXXXX_COMPANY_ID            0x48
> >> +
> >>  /*
> >> - * Register definitions, as well as various shifts and masks to get at the
> >> - * individual fields of the registers.
> >> + * AK_8975 Register definitions, as well as various shifts and masks to get
> >> + * at the individual fields of the registers.
> >>   */
> >>  #define AK8975_REG_WIA                       0x00
> >> -#define AK8975_DEVICE_ID             0x48
> >>
> >>  #define AK8975_REG_INFO                      0x01
> >>
> >> @@ -62,12 +64,12 @@
> >>  #define AK8975_REG_ST2_HOFL_MASK     (1 << AK8975_REG_ST2_HOFL_SHIFT)
> >>
> >>  #define AK8975_REG_CNTL                      0x0A
> >> +#define AK8975_REG_CNTL_MODE_POWER_DOWN      0x00
> >> +#define AK8975_REG_CNTL_MODE_ONCE    0x01
> >> +#define AK8975_REG_CNTL_MODE_SELF_TEST       0x08
> >> +#define AK8975_REG_CNTL_MODE_FUSE_ROM        0x0F
> >>  #define AK8975_REG_CNTL_MODE_SHIFT   0
> >>  #define AK8975_REG_CNTL_MODE_MASK    (0xF << AK8975_REG_CNTL_MODE_SHIFT)
> >> -#define AK8975_REG_CNTL_MODE_POWER_DOWN      0
> >> -#define AK8975_REG_CNTL_MODE_ONCE    1
> >> -#define AK8975_REG_CNTL_MODE_SELF_TEST       8
> >> -#define AK8975_REG_CNTL_MODE_FUSE_ROM        0xF
> >>
> >>  #define AK8975_REG_RSVC                      0x0B
> >>  #define AK8975_REG_ASTC                      0x0C
> >> @@ -81,59 +83,359 @@
> >>  #define AK8975_MAX_REGS                      AK8975_REG_ASAZ
> >>
> >>  /*
> >> + * AK09912 Register definitions
> >> + */
> >> +#define AK09912_REG_WIA1             0x00
> >> +#define AK09912_REG_WIA2             0x01
> >> +#define AK09912_DEVICE_ID            0x04
> >> +#define AK09911_DEVICE_ID            0x05
> >> +
> >> +#define AK09911_REG_INFO1            0x02
> >> +#define AK09911_REG_INFO2            0x03
> >> +
> >> +#define AK09912_REG_ST1                      0x10
> >> +
> >> +#define AK09912_REG_ST1_DRDY_SHIFT   0
> >> +#define AK09912_REG_ST1_DRDY_MASK    (1 << AK09912_REG_ST1_DRDY_SHIFT)
> >> +
> >> +#define AK09912_REG_HXL                      0x11
> >> +#define AK09912_REG_HXH                      0x12
> >> +#define AK09912_REG_HYL                      0x13
> >> +#define AK09912_REG_HYH                      0x14
> >> +#define AK09912_REG_HZL                      0x15
> >> +#define AK09912_REG_HZH                      0x16
> >> +#define AK09912_REG_TMPS             0x17
> >> +
> >> +#define AK09912_REG_ST2                      0x18
> >> +#define AK09912_REG_ST2_HOFL_SHIFT   3
> >> +#define AK09912_REG_ST2_HOFL_MASK    (1 << AK09912_REG_ST2_HOFL_SHIFT)
> >> +
> >> +#define AK09912_REG_CNTL1            0x30
> >> +
> >> +#define AK09912_REG_CNTL2            0x31
> >> +#define AK09912_REG_CNTL_MODE_POWER_DOWN     0x00
> >> +#define AK09912_REG_CNTL_MODE_ONCE   0x01
> >> +#define AK09912_REG_CNTL_MODE_SELF_TEST      0x10
> >> +#define AK09912_REG_CNTL_MODE_FUSE_ROM       0x1F
> >> +#define AK09912_REG_CNTL2_MODE_SHIFT 0
> >> +#define AK09912_REG_CNTL2_MODE_MASK  (0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
> >> +
> >> +#define AK09912_REG_CNTL3            0x32
> >> +
> >> +#define AK09912_REG_TS1                      0x33
> >> +#define AK09912_REG_TS2                      0x34
> >> +#define AK09912_REG_TS3                      0x35
> >> +#define AK09912_REG_I2CDIS           0x36
> >> +#define AK09912_REG_TS4                      0x37
> >> +
> >> +#define AK09912_REG_ASAX             0x60
> >> +#define AK09912_REG_ASAY             0x61
> >> +#define AK09912_REG_ASAZ             0x62
> >> +
> >> +#define AK09912_MAX_REGS             AK09912_REG_ASAZ
> >> +
> >> +/*
> >>   * Miscellaneous values.
> >>   */
> >> -#define AK8975_MAX_CONVERSION_TIMEOUT        500
> >> -#define AK8975_CONVERSION_DONE_POLL_TIME 10
> >> -#define AK8975_DATA_READY_TIMEOUT    ((100*HZ)/1000)
> >> -#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
> >> -#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
> >> -
> >> -/* Compatible Asahi Kasei Compass parts */
> >> -enum asahi_compass_chipset {
> >> +#define AKXXXX_MAX_CONVERSION_TIMEOUT        500
> >> +#define AKXXXX_CONVERSION_DONE_POLL_TIME 10
> >> +#define AKXXXX_DATA_READY_TIMEOUT    ((100*HZ)/1000)
> >> +
> >> +/*
> >> + * Precalculate scale factor (in Gauss units) for each axis and
> >> + * store in the device data.
> >> + *
> >> + * This scale factor is axis-dependent, and is derived from 3 calibration
> >> + * factors ASA(x), ASA(y), and ASA(z).
> >> + *
> >> + * These ASA values are read from the sensor device at start of day, and
> >> + * cached in the device context struct.
> >> + *
> >> + * Adjusting the flux value with the sensitivity adjustment value should be
> >> + * done via the following formula:
> >> + *
> >> + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> >> + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> >> + * is the resultant adjusted value.
> >> + *
> >> + * We reduce the formula to:
> >> + *
> >> + * Hadj = H * (ASA + 128) / 256
> >> + *
> >> + * H is in the range of -4096 to 4095.  The magnetometer has a range of
> >> + * +-1229uT.  To go from the raw value to uT is:
> >> + *
> >> + * HuT = H * 1229/4096, or roughly, 3/10.
> >> + *
> >> + * Since 1uT = 0.01 gauss, our final scale factor becomes:
> >> + *
> >> + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> >> + * Hadj = H * ((ASA + 128) * 0.003) / 256
> >> + *
> >> + * Since ASA doesn't change, we cache the resultant scale factor into the
> >> + * device context in akxxxx_setup().
> >> + *
> >> + * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
> >> + * multiply the stored scale value by 1e6.
> >> + */
> >> +long ak8975_raw_to_gauss(u16 data)
> >> +{
> >> +     return (((long)data + 128) * 3000) / 256;
> >> +}
> >> +
> >> +/*
> >> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
> >> + *
> >> + * H is in the range of +-8190.  The magnetometer has a range of
> >> + * +-4912uT.  To go from the raw value to uT is:
> >> + *
> >> + * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
> >> + */
> >> +long ak8963_09911_raw_to_gauss(u16 data)
> >> +{
> >> +     return (((long)data + 128) * 6000) / 256;
> >> +}
> >> +
> >> +/*
> >> + * For AK09912, same calculation, except the device is more sensitive:
> >> + *
> >> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
> >> + * +-4912uT.  To go from the raw value to uT is:
> >> + *
> >> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
> >> + */
> >> +long ak09912_raw_to_gauss(u16 data)
> >> +{
> >> +     return (((long)data + 128) * 1500) / 256;
> >> +}
> >> +
> >> +enum ak_type {
> >>       AK8975,
> >>       AK8963,
> >> +     AK09911,
> >> +     AK09912,
> >> +     AK_MAX_TYPE
> >> +};
> >> +
> >> +enum ak_ctrl_reg_addr {
> >> +     ST1,
> >> +     ST2,
> >> +     CNTL,
> >> +     ASA_BASE,
> >> +     MAX_REGS,
> >> +     REGS_END,
> >> +};
> >> +
> >> +enum ak_ctrl_reg_mask {
> >> +     ST1_DRDY,
> >> +     ST2_HOFL,
> >> +     ST2_DERR,
> >> +     CNTL_MODE,
> >> +     MASK_END,
> >> +};
> >> +
> >> +enum ak_ctrl_mode {
> >> +     POWER_DOWN,
> >> +     MODE_ONCE,
> >> +     SELF_TEST,
> >> +     FUSE_ROM,
> >> +     MODE_END,
> >> +};
> >> +
> >> +struct akxxxx_def {
> >> +     enum ak_type type;
> >> +     long (*raw_to_gauss)(u16 data);
> >> +     u16 range;
> >> +     u8 ctrl_regs[REGS_END];
> >> +     u8 ctrl_masks[MASK_END];
> >> +     u8 ctrl_modes[MODE_END];
> >> +     u8 data_regs[3];
> >> +} akxxxx_def_array[AK_MAX_TYPE] = {
> >> +{
> >> +     .type = AK8975,
> >> +     .raw_to_gauss = ak8975_raw_to_gauss,
> >> +     .range = 4096,
> >> +     .ctrl_regs = {
> >> +             AK8975_REG_ST1,
> >> +             AK8975_REG_ST2,
> >> +             AK8975_REG_CNTL,
> >> +             AK8975_REG_ASAX,
> >> +             AK8975_MAX_REGS},
> >> +     .ctrl_masks = {
> >> +             AK8975_REG_ST1_DRDY_MASK,
> >> +             AK8975_REG_ST2_HOFL_MASK,
> >> +             AK8975_REG_ST2_DERR_MASK,
> >> +             AK8975_REG_CNTL_MODE_MASK},
> >> +     .ctrl_modes = {
> >> +             AK8975_REG_CNTL_MODE_POWER_DOWN,
> >> +             AK8975_REG_CNTL_MODE_ONCE,
> >> +             AK8975_REG_CNTL_MODE_SELF_TEST,
> >> +             AK8975_REG_CNTL_MODE_FUSE_ROM},
> >> +     .data_regs = {
> >> +             AK8975_REG_HXL,
> >> +             AK8975_REG_HYL,
> >> +             AK8975_REG_HZL},
> >> +},
> >> +{
> >> +     .type = AK8963,
> >> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
> >> +     .range = 8190,
> >> +     .ctrl_regs = {
> >> +             AK8975_REG_ST1,
> >> +             AK8975_REG_ST2,
> >> +             AK8975_REG_CNTL,
> >> +             AK8975_REG_ASAX,
> >> +             AK8975_MAX_REGS},
> >> +     .ctrl_masks = {
> >> +             AK8975_REG_ST1_DRDY_MASK,
> >> +             AK8975_REG_ST2_HOFL_MASK,
> >> +             0,
> >> +             AK8975_REG_CNTL_MODE_MASK},
> >> +     .ctrl_modes = {
> >> +             AK8975_REG_CNTL_MODE_POWER_DOWN,
> >> +             AK8975_REG_CNTL_MODE_ONCE,
> >> +             AK8975_REG_CNTL_MODE_SELF_TEST,
> >> +             AK8975_REG_CNTL_MODE_FUSE_ROM},
> >> +     .data_regs = {
> >> +             AK8975_REG_HXL,
> >> +             AK8975_REG_HYL,
> >> +             AK8975_REG_HZL},
> >> +},
> >> +{
> >> +     .type = AK09911,
> >> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
> >> +     .range = 8192,
> >> +     .ctrl_regs = {
> >> +             AK09912_REG_ST1,
> >> +             AK09912_REG_ST2,
> >> +             AK09912_REG_CNTL2,
> >> +             AK09912_REG_ASAX,
> >> +             AK09912_MAX_REGS},
> >> +     .ctrl_masks = {
> >> +             AK09912_REG_ST1_DRDY_MASK,
> >> +             AK09912_REG_ST2_HOFL_MASK,
> >> +             0,
> >> +             AK09912_REG_CNTL2_MODE_MASK},
> >> +     .ctrl_modes = {
> >> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
> >> +             AK09912_REG_CNTL_MODE_ONCE,
> >> +             AK09912_REG_CNTL_MODE_SELF_TEST,
> >> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
> >> +     .data_regs = {
> >> +             AK09912_REG_HXL,
> >> +             AK09912_REG_HYL,
> >> +             AK09912_REG_HZL},
> >> +},
> >> +{
> >> +     .type = AK09912,
> >> +     .raw_to_gauss = ak09912_raw_to_gauss,
> >> +     .range = 32752,
> >> +     .ctrl_regs = {
> >> +             AK09912_REG_ST1,
> >> +             AK09912_REG_ST2,
> >> +             AK09912_REG_CNTL2,
> >> +             AK09912_REG_ASAX,
> >> +             AK09912_MAX_REGS},
> >> +     .ctrl_masks = {
> >> +             AK09912_REG_ST1_DRDY_MASK,
> >> +             AK09912_REG_ST2_HOFL_MASK,
> >> +             0,
> >> +             AK09912_REG_CNTL2_MODE_MASK},
> >> +     .ctrl_modes = {
> >> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
> >> +             AK09912_REG_CNTL_MODE_ONCE,
> >> +             AK09912_REG_CNTL_MODE_SELF_TEST,
> >> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
> >> +     .data_regs = {
> >> +             AK09912_REG_HXL,
> >> +             AK09912_REG_HYL,
> >> +             AK09912_REG_HZL},
> >> +}
> >>  };
> >>
> >>  /*
> >>   * Per-instance context data for the device.
> >>   */
> >> -struct ak8975_data {
> >> +struct akxxxx_data {
> >>       struct i2c_client       *client;
> >> +     struct akxxxx_def       *def;
> >>       struct attribute_group  attrs;
> >>       struct mutex            lock;
> >>       u8                      asa[3];
> >>       long                    raw_to_gauss[3];
> >> -     u8                      reg_cache[AK8975_MAX_REGS];
> > Justify dropping this register cache...
> reg_cache was only needed in ak8975_write_data, which was only used to write the
> CNTL register. It is needed for this register to preserve the bits
> outside the mode mask.
> >
> >>       int                     eoc_gpio;
> >>       int                     eoc_irq;
> >>       wait_queue_head_t       data_ready_queue;
> >>       unsigned long           flags;
> >> -     enum asahi_compass_chipset chipset;
> >> +     u8                      cntl_cache;
> >>  };
> >>
> >> -static const int ak8975_index_to_reg[] = {
> >> -     AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
> >> -};
> >> +/*
> >> + * Return 0 if the i2c device is the one we expect.
> >> + * return a negative error number otherwise
> >> + */
> >> +static int akxxxx_who_i_am(struct i2c_client *client, enum ak_type type)
> >> +{
> >> +     u8 wia_val[2];
> >> +     int ret;
> >> +
> >> +     /*
> >> +      * Signature for each device:
> >> +      * Device   |  WIA1       |  WIA2
> >> +      * AK09912  |  COMPANY_ID |  AK09912_DEVICE_ID
> >> +      * AK09911  |  COMPANY_ID |  AK09911_DEVICE_ID
> >> +      * AK8975   |  COMPANY_ID |  NA
> >> +      * AK8963   |  COMPANY_ID |  NA
> >> +      */
> >> +     ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> >> +                                         2, wia_val);
> >> +     if (ret < 0) {
> >> +             dev_err(&client->dev, "Error reading WIA\n");
> >> +             return ret;
> >> +     }
> >> +
> >> +     ret = -ENODEV;
> >> +
> >> +     if (wia_val[0] != AKXXXX_COMPANY_ID)
> >> +             return ret;
> >> +
> >> +     switch (type) {
> >> +     case AK8975:
> >> +     case AK8963:
> >> +             ret = 0;
> >> +             break;
> >> +     case AK09911:
> >> +             if (wia_val[1] == AK09911_DEVICE_ID)
> >> +                     ret = 0;
> >> +             break;
> >> +     case AK09912:
> >> +             if (wia_val[1] == AK09912_DEVICE_ID)
> >> +                     ret = 0;
> >> +             break;
> >> +     default:
> >> +             dev_err(&client->dev, "Type %d unknown\n", type);
> >> +     }
> >> +     return ret;
> >> +}
> >>
> >>  /*
> >> - * Helper function to write to the I2C device's registers.
> >> + * Helper function to write to CNTL register.
> >>   */
> >> -static int ak8975_write_data(struct i2c_client *client,
> >> -                          u8 reg, u8 val, u8 mask, u8 shift)
> >> +static int akxxxx_set_mode(struct akxxxx_data *data, enum ak_ctrl_mode mode)
> >>  {
> >> -     struct iio_dev *indio_dev = i2c_get_clientdata(client);
> >> -     struct ak8975_data *data = iio_priv(indio_dev);
> >>       u8 regval;
> >>       int ret;
> >>
> >> -     regval = (data->reg_cache[reg] & ~mask) | (val << shift);
> >> -     ret = i2c_smbus_write_byte_data(client, reg, regval);
> >> +     regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
> >> +             data->def->ctrl_modes[mode];
> >> +     ret = i2c_smbus_write_byte_data(
> >> +             data->client, data->def->ctrl_regs[CNTL], regval);
> >>       if (ret < 0) {
> >> -             dev_err(&client->dev, "Write to device fails status %x\n", ret);
> >>               return ret;
> >>       }
> >> -     data->reg_cache[reg] = regval;
> >> +     data->cntl_cache = regval;
> >> +     /* After mode change wait atleast 100us */
> >> +     usleep_range(100, 500);
> >>
> >>       return 0;
> >>  }
> >> @@ -141,9 +443,9 @@ static int ak8975_write_data(struct i2c_client *client,
> >>  /*
> >>   * Handle data ready irq
> >>   */
> >> -static irqreturn_t ak8975_irq_handler(int irq, void *data)
> >> +static irqreturn_t akxxxx_irq_handler(int irq, void *data)
> >>  {
> >> -     struct ak8975_data *ak8975 = data;
> >> +     struct akxxxx_data *ak8975 = data;
> >>
> >>       set_bit(0, &ak8975->flags);
> >>       wake_up(&ak8975->data_ready_queue);
> >> @@ -154,7 +456,7 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data)
> >>  /*
> >>   * Install data ready interrupt handler
> >>   */
> >> -static int ak8975_setup_irq(struct ak8975_data *data)
> >> +static int akxxxx_setup_irq(struct akxxxx_data *data)
> >>  {
> >>       struct i2c_client *client = data->client;
> >>       int rc;
> >> @@ -165,9 +467,9 @@ static int ak8975_setup_irq(struct ak8975_data *data)
> >>       else
> >>               irq = gpio_to_irq(data->eoc_gpio);
> >>
> >> -     rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
> >> -                      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> >> -                      dev_name(&client->dev), data);
> >> +     rc = devm_request_irq(&client->dev, irq, akxxxx_irq_handler,
> >> +                           IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> >> +                           dev_name(&client->dev), data);
> >>       if (rc < 0) {
> >>               dev_err(&client->dev,
> >>                       "irq %d request failed, (gpio %d): %d\n",
> >> @@ -187,38 +489,22 @@ static int ak8975_setup_irq(struct ak8975_data *data)
> >>   * Perform some start-of-day setup, including reading the asa calibration
> >>   * values and caching them.
> >>   */
> >> -static int ak8975_setup(struct i2c_client *client)
> >> +static int akxxxx_setup(struct i2c_client *client)
> >>  {
> >>       struct iio_dev *indio_dev = i2c_get_clientdata(client);
> >> -     struct ak8975_data *data = iio_priv(indio_dev);
> >> -     u8 device_id;
> >> +     struct akxxxx_data *data = iio_priv(indio_dev);
> >>       int ret;
> >>
> >> -     /* Confirm that the device we're talking to is really an AK8975. */
> >> -     ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Error reading WIA\n");
> >> -             return ret;
> >> -     }
> >> -     device_id = ret;
> >> -     if (device_id != AK8975_DEVICE_ID) {
> >> -             dev_err(&client->dev, "Device ak8975 not found\n");
> >> -             return -ENODEV;
> >> -     }
> >> -
> >>       /* Write the fused rom access mode. */
> >> -     ret = ak8975_write_data(client,
> >> -                             AK8975_REG_CNTL,
> >> -                             AK8975_REG_CNTL_MODE_FUSE_ROM,
> >> -                             AK8975_REG_CNTL_MODE_MASK,
> >> -                             AK8975_REG_CNTL_MODE_SHIFT);
> >> +     ret = akxxxx_set_mode(data, FUSE_ROM);
> > The factoring out of set_mode makes sense, but should probably have
> > been a separate precursor patch to the main series.
> Done
> >>       if (ret < 0) {
> >>               dev_err(&client->dev, "Error in setting fuse access mode\n");
> >>               return ret;
> >>       }
> >>
> >>       /* Get asa data and store in the device data. */
> >> -     ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
> >> +     ret = i2c_smbus_read_i2c_block_data(client,
> >> +                                         data->def->ctrl_regs[ASA_BASE],
> >>                                           3, data->asa);
> >>       if (ret < 0) {
> >>               dev_err(&client->dev, "Not able to read asa data\n");
> >> @@ -226,14 +512,14 @@ static int ak8975_setup(struct i2c_client *client)
> >>       }
> >>
> >>       /* After reading fuse ROM data set power-down mode */
> >> -     ret = ak8975_write_data(client,
> >> -                             AK8975_REG_CNTL,
> >> -                             AK8975_REG_CNTL_MODE_POWER_DOWN,
> >> -                             AK8975_REG_CNTL_MODE_MASK,
> >> -                             AK8975_REG_CNTL_MODE_SHIFT);
> >> +     ret = akxxxx_set_mode(data, POWER_DOWN);
> >> +     if (ret < 0) {
> >> +             dev_err(&client->dev, "Error in setting power-down mode\n");
> >> +             return ret;
> >> +     }
> >>
> >>       if (data->eoc_gpio > 0 || client->irq) {
> >> -             ret = ak8975_setup_irq(data);
> >> +             ret = akxxxx_setup_irq(data);
> >>               if (ret < 0) {
> >>                       dev_err(&client->dev,
> >>                               "Error setting data ready interrupt\n");
> >> @@ -241,101 +527,50 @@ static int ak8975_setup(struct i2c_client *client)
> >>               }
> >>       }
> >>
> > Why has this disappeared?
> I move it just below setting mode to POWER_DOWN, where it belongs, as
> Hartmut pointed out.
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Error in setting power-down mode\n");
> >> -             return ret;
> >> -     }
> >> -
> >> -/*
> >> - * Precalculate scale factor (in Gauss units) for each axis and
> >> - * store in the device data.
> >> - *
> >> - * This scale factor is axis-dependent, and is derived from 3 calibration
> >> - * factors ASA(x), ASA(y), and ASA(z).
> >> - *
> >> - * These ASA values are read from the sensor device at start of day, and
> >> - * cached in the device context struct.
> >> - *
> >> - * Adjusting the flux value with the sensitivity adjustment value should be
> >> - * done via the following formula:
> >> - *
> >> - * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> >> - *
> >> - * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> >> - * is the resultant adjusted value.
> >> - *
> >> - * We reduce the formula to:
> >> - *
> >> - * Hadj = H * (ASA + 128) / 256
> >> - *
> >> - * H is in the range of -4096 to 4095.  The magnetometer has a range of
> >> - * +-1229uT.  To go from the raw value to uT is:
> >> - *
> >> - * HuT = H * 1229/4096, or roughly, 3/10.
> >> - *
> >> - * Since 1uT = 0.01 gauss, our final scale factor becomes:
> >> - *
> >> - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> >> - * Hadj = H * ((ASA + 128) * 0.003) / 256
> >> - *
> >> - * Since ASA doesn't change, we cache the resultant scale factor into the
> >> - * device context in ak8975_setup().
> >> - */
> >
> >> -     if (data->chipset == AK8963) {
> >> -             /*
> >> -              * H range is +-8190 and magnetometer range is +-4912.
> >> -              * So HuT using the above explanation for 8975,
> >> -              * 4912/8190 = ~ 6/10.
> >> -              * So the Hadj should use 6/10 instead of 3/10.
> >> -              */
> >> -             data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
> >> -             data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
> >> -             data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
> >> -     } else {
> >> -             data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
> >> -             data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
> >> -             data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
> >> -     }
> >> +     data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
> >> +     data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
> >> +     data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
> >>
> >>       return 0;
> >>  }
> >>
> >> -static int wait_conversion_complete_gpio(struct ak8975_data *data)
> >> +static int wait_conversion_complete_gpio(struct akxxxx_data *data)
> >>  {
> >>       struct i2c_client *client = data->client;
> >> -     u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
> >> +     u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
> >>       int ret;
> >>
> >>       /* Wait for the conversion to complete. */
> >>       while (timeout_ms) {
> >> -             msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> >> +             msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
> >>               if (gpio_get_value(data->eoc_gpio))
> >>                       break;
> >> -             timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
> >> +             timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
> >>       }
> >>       if (!timeout_ms) {
> >>               dev_err(&client->dev, "Conversion timeout happened\n");
> >>               return -EINVAL;
> >>       }
> >>
> >> -     ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> >> +     ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
> >>       if (ret < 0)
> >>               dev_err(&client->dev, "Error in reading ST1\n");
> >>
> >>       return ret;
> >>  }
> >>
> >> -static int wait_conversion_complete_polled(struct ak8975_data *data)
> >> +static int wait_conversion_complete_polled(struct akxxxx_data *data)
> >>  {
> >>       struct i2c_client *client = data->client;
> >>       u8 read_status;
> >> -     u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
> >> +     u32 timeout_ms = AKXXXX_MAX_CONVERSION_TIMEOUT;
> >>       int ret;
> >>
> >>       /* Wait for the conversion to complete. */
> >>       while (timeout_ms) {
> >> -             msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> >> -             ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> >> +             msleep(AKXXXX_CONVERSION_DONE_POLL_TIME);
> >> +             ret = i2c_smbus_read_byte_data(
> >> +                             client, data->def->ctrl_regs[ST1]);
> >>               if (ret < 0) {
> >>                       dev_err(&client->dev, "Error in reading ST1\n");
> >>                       return ret;
> >> @@ -343,7 +578,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
> >>               read_status = ret;
> >>               if (read_status)
> >>                       break;
> >> -             timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
> >> +             timeout_ms -= AKXXXX_CONVERSION_DONE_POLL_TIME;
> >>       }
> >>       if (!timeout_ms) {
> >>               dev_err(&client->dev, "Conversion timeout happened\n");
> >> @@ -354,13 +589,13 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
> >>  }
> >>
> >>  /* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
> >> -static int wait_conversion_complete_interrupt(struct ak8975_data *data)
> >> +static int wait_conversion_complete_interrupt(struct akxxxx_data *data)
> >>  {
> >>       int ret;
> >>
> >>       ret = wait_event_timeout(data->data_ready_queue,
> >>                                test_bit(0, &data->flags),
> >> -                              AK8975_DATA_READY_TIMEOUT);
> >> +                              AKXXXX_DATA_READY_TIMEOUT);
> >>       clear_bit(0, &data->flags);
> >>
> >>       return ret > 0 ? 0 : -ETIME;
> >> @@ -369,20 +604,16 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
> >>  /*
> >>   * Emits the raw flux value for the x, y, or z axis.
> >>   */
> >> -static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
> >> +static int akxxxx_read_axis(struct iio_dev *indio_dev, int index, int *val)
> >>  {
> >> -     struct ak8975_data *data = iio_priv(indio_dev);
> >> +     struct akxxxx_data *data = iio_priv(indio_dev);
> >>       struct i2c_client *client = data->client;
> >>       int ret;
> >>
> >>       mutex_lock(&data->lock);
> >>
> >>       /* Set up the device for taking a sample. */
> >> -     ret = ak8975_write_data(client,
> >> -                             AK8975_REG_CNTL,
> >> -                             AK8975_REG_CNTL_MODE_ONCE,
> >> -                             AK8975_REG_CNTL_MODE_MASK,
> >> -                             AK8975_REG_CNTL_MODE_SHIFT);
> >> +     ret = akxxxx_set_mode(data, MODE_ONCE);
> >>       if (ret < 0) {
> >>               dev_err(&client->dev, "Error in setting operating mode\n");
> >>               goto exit;
> >> @@ -399,14 +630,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
> >>               goto exit;
> >>
> >>       /* This will be executed only for non-interrupt based waiting case */
> >> -     if (ret & AK8975_REG_ST1_DRDY_MASK) {
> >> -             ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
> >> +     if (ret & data->def->ctrl_masks[ST1_DRDY]) {
> >> +             ret = i2c_smbus_read_byte_data(
> >> +                             client, data->def->ctrl_regs[ST2]);
> >>               if (ret < 0) {
> >>                       dev_err(&client->dev, "Error in reading ST2\n");
> >>                       goto exit;
> >>               }
> >> -             if (ret & (AK8975_REG_ST2_DERR_MASK |
> >> -                        AK8975_REG_ST2_HOFL_MASK)) {
> >> +             if (ret & (data->def->ctrl_masks[ST2_DERR] |
> >> +                        data->def->ctrl_masks[ST2_HOFL])) {
> >>                       dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
> >>                       ret = -EINVAL;
> >>                       goto exit;
> >> @@ -415,7 +647,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
> >>
> >>       /* Read the flux value from the appropriate register
> >>          (the register is specified in the iio device attributes). */
> >> -     ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
> >> +     ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
> >>       if (ret < 0) {
> >>               dev_err(&client->dev, "Read axis data fails\n");
> >>               goto exit;
> >> @@ -424,7 +656,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
> >>       mutex_unlock(&data->lock);
> >>
> >>       /* Clamp to valid range. */
> >> -     *val = clamp_t(s16, ret, -4096, 4095);
> >> +     *val = clamp_t(s16, ret, -data->def->range, data->def->range);
> > Well that isn't going to be the same as before...  I think you need a
> > - 1
> -1 is needed only for ak8975: the others are +-8190 or +-32752. I drop
> the -1, allowing ak8957 values to be +- 4096.
> >>       return IIO_VAL_INT;
> >>
> >>  exit:
> >> @@ -432,16 +664,16 @@ exit:
> >>       return ret;
> >>  }
> >>
> >> -static int ak8975_read_raw(struct iio_dev *indio_dev,
> >> +static int akxxxx_read_raw(struct iio_dev *indio_dev,
> >>                          struct iio_chan_spec const *chan,
> >>                          int *val, int *val2,
> >>                          long mask)
> >>  {
> >> -     struct ak8975_data *data = iio_priv(indio_dev);
> >> +     struct akxxxx_data *data = iio_priv(indio_dev);
> >>
> >>       switch (mask) {
> >>       case IIO_CHAN_INFO_RAW:
> >> -             return ak8975_read_axis(indio_dev, chan->address, val);
> >> +             return akxxxx_read_axis(indio_dev, chan->address, val);
> >>       case IIO_CHAN_INFO_SCALE:
> >>               *val = 0;
> >>               *val2 = data->raw_to_gauss[chan->address];
> >> @@ -450,7 +682,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
> >>       return -EINVAL;
> >>  }
> >>
> >> -#define AK8975_CHANNEL(axis, index)                                  \
> >> +#define AKXXXX_CHANNEL(axis, index)                                  \
> >>       {                                                               \
> >>               .type = IIO_MAGN,                                       \
> >>               .modified = 1,                                          \
> >> @@ -460,40 +692,41 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
> >>               .address = index,                                       \
> >>       }
> >>
> >> -static const struct iio_chan_spec ak8975_channels[] = {
> >> -     AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
> >> +static const struct iio_chan_spec akxxxx_channels[] = {
> >> +     AKXXXX_CHANNEL(X, 0), AKXXXX_CHANNEL(Y, 1), AKXXXX_CHANNEL(Z, 2),
> >>  };
> >>
> >> -static const struct iio_info ak8975_info = {
> >> -     .read_raw = &ak8975_read_raw,
> >> +static const struct iio_info akxxxx_info = {
> >> +     .read_raw = &akxxxx_read_raw,
> >>       .driver_module = THIS_MODULE,
> >>  };
> >>
> >> -static const struct acpi_device_id ak_acpi_match[] = {
> >> -     {"AK8975", AK8975},
> >> -     {"AK8963", AK8963},
> >> -     {"INVN6500", AK8963},
> >> +static const struct acpi_device_id akxxxx_acpi_match[] = {
> >> +     {"AK8975", (uintptr_t)&akxxxx_def_array[AK8975]},
> >> +     {"AK8963", (uintptr_t)&akxxxx_def_array[AK8963]},
> >> +     {"AK09911", (uintptr_t)&akxxxx_def_array[AK09911]},
> >> +     {"AK09912", (uintptr_t)&akxxxx_def_array[AK09912]},
> > Again, I'm lost as to why you have changed form an index....
> >>       { },
> >>  };
> >> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> >> +MODULE_DEVICE_TABLE(acpi, akxxxx_acpi_match);
> >>
> >> -static const char *ak8975_match_acpi_device(struct device *dev,
> >> -                                         enum asahi_compass_chipset *chipset)
> >> +static const char *akxxxx_match_acpi_device(struct device *dev,
> >> +                                         struct akxxxx_def **def)
> >>  {
> >>       const struct acpi_device_id *id;
> >>
> >>       id = acpi_match_device(dev->driver->acpi_match_table, dev);
> >>       if (!id)
> >>               return NULL;
> >> -     *chipset = (int)id->driver_data;
> >> +     *def = (struct akxxxx_def *)id->driver_data;
> >>
> >>       return dev_name(dev);
> >>  }
> >>
> >> -static int ak8975_probe(struct i2c_client *client,
> >> +static int akxxxx_probe(struct i2c_client *client,
> >>                       const struct i2c_device_id *id)
> >>  {
> >> -     struct ak8975_data *data;
> >> +     struct akxxxx_data *data;
> >>       struct iio_dev *indio_dev;
> >>       int eoc_gpio;
> >>       int err;
> >> @@ -513,8 +746,8 @@ static int ak8975_probe(struct i2c_client *client,
> >>       /* We may not have a GPIO based IRQ to scan, that is fine, we will
> >>          poll if so */
> >>       if (gpio_is_valid(eoc_gpio)) {
> >> -             err = devm_gpio_request_one(&client->dev, eoc_gpio,
> >> -                                                     GPIOF_IN, "ak_8975");
> >> +             err = devm_gpio_request_one(
> >> +                     &client->dev, eoc_gpio, GPIOF_IN, id->name);
> >>               if (err < 0) {
> >>                       dev_err(&client->dev,
> >>                               "failed to request GPIO %d, error %d\n",
> >> @@ -534,23 +767,25 @@ static int ak8975_probe(struct i2c_client *client,
> >>       data->client = client;
> >>       data->eoc_gpio = eoc_gpio;
> > Rather curriously data->eoc_gpio is set to the same value twice...
> I made a copy&paste mistake, will be fixed.
> >
> >>       data->eoc_irq = 0;
> >> -
> >>       /* id will be NULL when enumerated via ACPI */
> >>       if (id) {
> >> -             data->chipset =
> >> -                     (enum asahi_compass_chipset)(id->driver_data);
> >> +             data->def = (struct akxxxx_def *)id->driver_data;
> >>               name = id->name;
> >>       } else if (ACPI_HANDLE(&client->dev))
> >> -             name = ak8975_match_acpi_device(&client->dev, &data->chipset);
> >> +             name = akxxxx_match_acpi_device(&client->dev, &data->def);
> >>       else
> >>               return -ENOSYS;
> >>
> >> +     if (akxxxx_who_i_am(client, data->def->type) < 0) {
> >> +             dev_err(&client->dev, "Unexpected device\n");
> >> +             return -ENODEV;
> >> +     }
> >>       dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> >>
> >>       /* Perform some basic start-of-day setup of the device. */
> >> -     err = ak8975_setup(client);
> >> +     err = akxxxx_setup(client);
> >>       if (err < 0) {
> >> -             dev_err(&client->dev, "AK8975 initialization fails\n");
> >> +             dev_err(&client->dev, "%s initialization fails\n", name);
> >>               return err;
> >>       }
> >>
> >> @@ -558,9 +793,9 @@ static int ak8975_probe(struct i2c_client *client,
> >>       mutex_init(&data->lock);
> >>       data->eoc_gpio = eoc_gpio;
> >>       indio_dev->dev.parent = &client->dev;
> >> -     indio_dev->channels = ak8975_channels;
> >> -     indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
> >> -     indio_dev->info = &ak8975_info;
> >> +     indio_dev->channels = akxxxx_channels;
> >> +     indio_dev->num_channels = ARRAY_SIZE(akxxxx_channels);
> >> +     indio_dev->info = &akxxxx_info;
> >>       indio_dev->modes = INDIO_DIRECT_MODE;
> >>       indio_dev->name = name;
> >>       err = devm_iio_device_register(&client->dev, indio_dev);
> >> @@ -570,32 +805,48 @@ static int ak8975_probe(struct i2c_client *client,
> >>       return 0;
> > Not your fault, but this function could just end
> > return devm_iio_device_register(...) which would be cleaner.
> > (in case you haven't guessed I'm looking at the result rather than the
> > patch ;)
> >>  }
> >>
> >> -static const struct i2c_device_id ak8975_id[] = {
> >> -     {"ak8975", AK8975},
> >> -     {"ak8963", AK8963},
> >> +static const struct i2c_device_id akxxxx_id[] = {
> >> +     {"ak8975", (uintptr_t)&akxxxx_def_array[AK8975]},
> >> +     {"ak8963", (uintptr_t)&akxxxx_def_array[AK8963]},
> >> +     {"ak09911", (uintptr_t)&akxxxx_def_array[AK09911]},
> >> +     {"ak09912", (uintptr_t)&akxxxx_def_array[AK09912]},
> > Why not use an index instead as per the original driver?
> > Same result, less type casting mess ;)
> >>       {}
> >>  };
> >>
> >> -MODULE_DEVICE_TABLE(i2c, ak8975_id);
> >> -
> >> -static const struct of_device_id ak8975_of_match[] = {
> >> -     { .compatible = "asahi-kasei,ak8975", },
> >> -     { .compatible = "ak8975", },
> >> +MODULE_DEVICE_TABLE(i2c, akxxxx_id);
> >> +
> >> +static const struct of_device_id akxxxx_of_match[] = {
> >> +     { .compatible = "asahi-kasei,ak8975",
> >> +       .data = &akxxxx_def_array[AK8975]},
> >> +     { .compatible = "ak8975",
> >> +       .data = &akxxxx_def_array[AK8975]},
> >> +     { .compatible = "asahi-kasei,ak8963",
> >> +       .data = &akxxxx_def_array[AK8963]},
> >> +     { .compatible = "ak8963",
> >> +       .data = &akxxxx_def_array[AK8963]},
> >> +     { .compatible = "asahi-kasei,ak09911",
> >> +       .data = &akxxxx_def_array[AK09911]},
> >> +     { .compatible = "ak09911",
> >> +       .data = &akxxxx_def_array[AK09911]},
> >> +     { .compatible = "asahi-kasei,ak09912",
> >> +       .data = &akxxxx_def_array[AK09912]},
> >> +     { .compatible = "ak09912",
> >> +       .data = &akxxxx_def_array[AK09912]},
> >>       { }
> >>  };
> >> -MODULE_DEVICE_TABLE(of, ak8975_of_match);
> >> +MODULE_DEVICE_TABLE(of, akxxxx_of_match);
> >>
> >> -static struct i2c_driver ak8975_driver = {
> >> +static struct i2c_driver akxxxx_driver = {
> >>       .driver = {
> >> -             .name   = "ak8975",
> >> -             .of_match_table = ak8975_of_match,
> >> -             .acpi_match_table = ACPI_PTR(ak_acpi_match),
> >> +             .name   = "akxxxx",
> >> +             .of_match_table = of_match_ptr(akxxxx_of_match),
> >> +             .acpi_match_table = ACPI_PTR(akxxxx_acpi_match),
> >>       },
> >> -     .probe          = ak8975_probe,
> >> -     .id_table       = ak8975_id,
> >> +     .probe          = akxxxx_probe,
> >> +     .id_table       = akxxxx_id,
> >>  };
> >> -module_i2c_driver(ak8975_driver);
> >> +module_i2c_driver(akxxxx_driver);
> >>
> >>  MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
> >> -MODULE_DESCRIPTION("AK8975 magnetometer driver");
> >> +MODULE_DESCRIPTION("ak8975 and ak09912 magnetometer driver");
> >>  MODULE_LICENSE("GPL");
> >>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] iio: ak8975: minor fixes
  2014-11-05 22:10             ` [PATCH 1/3] iio: ak8975: minor fixes Gwendal Grignou
@ 2014-11-06 15:00               ` Srinivas Pandruvada
  2014-11-17 20:13               ` [PATCH v2 " Gwendal Grignou
  1 sibling, 0 replies; 28+ messages in thread
From: Srinivas Pandruvada @ 2014-11-06 15:00 UTC (permalink / raw)
  To: Gwendal Grignou; +Cc: jic23, knaack.h, linux-iio

On Wed, 2014-11-05 at 14:10 -0800, Gwendal Grignou wrote:
> Fixes code duplication, return of function.
> 
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>  drivers/iio/magnetometer/ak8975.c | 33 +++++++++++++--------------------
>  1 file changed, 13 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index bf5ef07..12f0b00 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -64,10 +64,10 @@
>  #define AK8975_REG_CNTL			0x0A
>  #define AK8975_REG_CNTL_MODE_SHIFT	0
>  #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
> -#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
> -#define AK8975_REG_CNTL_MODE_ONCE	1
> -#define AK8975_REG_CNTL_MODE_SELF_TEST	8
> -#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
> +#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK8975_REG_CNTL_MODE_ONCE	0x01
> +#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
> +#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
>  
>  #define AK8975_REG_RSVC			0x0B
>  #define AK8975_REG_ASTC			0x0C
> @@ -166,8 +166,8 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>  		irq = gpio_to_irq(data->eoc_gpio);
>  
>  	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
> -			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> -			 dev_name(&client->dev), data);
> +			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +			      dev_name(&client->dev), data);
>  	if (rc < 0) {
>  		dev_err(&client->dev,
>  			"irq %d request failed, (gpio %d): %d\n",
> @@ -231,6 +231,10 @@ static int ak8975_setup(struct i2c_client *client)
>  				AK8975_REG_CNTL_MODE_POWER_DOWN,
>  				AK8975_REG_CNTL_MODE_MASK,
>  				AK8975_REG_CNTL_MODE_SHIFT);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error in setting power-down mode\n");
> +		return ret;
> +	}
>  
>  	if (data->eoc_gpio > 0 || client->irq) {
>  		ret = ak8975_setup_irq(data);
> @@ -241,11 +245,6 @@ static int ak8975_setup(struct i2c_client *client)
>  		}
>  	}
>  
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error in setting power-down mode\n");
> -		return ret;
> -	}
> -
>  /*
>   * Precalculate scale factor (in Gauss units) for each axis and
>   * store in the device data.
> @@ -550,24 +549,18 @@ static int ak8975_probe(struct i2c_client *client,
>  	/* Perform some basic start-of-day setup of the device. */
>  	err = ak8975_setup(client);
>  	if (err < 0) {
> -		dev_err(&client->dev, "AK8975 initialization fails\n");
> +		dev_err(&client->dev, "%s initialization fails\n", name);
>  		return err;
>  	}
>  
> -	data->client = client;
>  	mutex_init(&data->lock);
> -	data->eoc_gpio = eoc_gpio;
>  	indio_dev->dev.parent = &client->dev;
>  	indio_dev->channels = ak8975_channels;
>  	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
>  	indio_dev->info = &ak8975_info;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  	indio_dev->name = name;
> -	err = devm_iio_device_register(&client->dev, indio_dev);
> -	if (err < 0)
> -		return err;
> -
> -	return 0;
> +	return devm_iio_device_register(&client->dev, indio_dev);
>  }
>  
>  static const struct i2c_device_id ak8975_id[] = {
> @@ -588,7 +581,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match);
>  static struct i2c_driver ak8975_driver = {
>  	.driver = {
>  		.name	= "ak8975",
> -		.of_match_table = ak8975_of_match,
> +		.of_match_table = of_match_ptr(ak8975_of_match),
>  		.acpi_match_table = ACPI_PTR(ak_acpi_match),
>  	},
>  	.probe		= ak8975_probe,
Looks OK to me.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/3] iio: ak8975: add definition structure per compass type
  2014-11-05 22:10             ` [PATCH 2/3] iio: ak8975: add definition structure per compass type Gwendal Grignou
@ 2014-11-06 15:02               ` Srinivas Pandruvada
  2014-11-06 21:16                 ` Gwendal Grignou
  2014-11-19 11:25               ` Hartmut Knaack
  1 sibling, 1 reply; 28+ messages in thread
From: Srinivas Pandruvada @ 2014-11-06 15:02 UTC (permalink / raw)
  To: Gwendal Grignou; +Cc: jic23, knaack.h, linux-iio

On Wed, 2014-11-05 at 14:10 -0800, Gwendal Grignou wrote:
> For each type of compass supported (AK8975 and AK8963),
> add a definition structure for register masks, important registers,
> raw data interpretation.
> This change will make integrating new type of devices easier.
> 
> Remove i2c register cache. It is only used for one single register.
> 
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>  drivers/iio/magnetometer/ak8975.c | 279 +++++++++++++++++++++++++-------------
>  1 file changed, 184 insertions(+), 95 deletions(-)
> 
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index 12f0b00..b170654 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -86,13 +86,153 @@
>  #define AK8975_MAX_CONVERSION_TIMEOUT	500
>  #define AK8975_CONVERSION_DONE_POLL_TIME 10
>  #define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
> -#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
> -#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
> +
> +/*
> + * Precalculate scale factor (in Gauss units) for each axis and
> + * store in the device data.
> + *
> + * This scale factor is axis-dependent, and is derived from 3 calibration
> + * factors ASA(x), ASA(y), and ASA(z).
> + *
> + * These ASA values are read from the sensor device at start of day, and
> + * cached in the device context struct.
> + *
> + * Adjusting the flux value with the sensitivity adjustment value should be
> + * done via the following formula:
> + *
> + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> + * is the resultant adjusted value.
> + *
> + * We reduce the formula to:
> + *
> + * Hadj = H * (ASA + 128) / 256
> + *
> + * H is in the range of -4096 to 4095.  The magnetometer has a range of
> + * +-1229uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 1229/4096, or roughly, 3/10.
> + *
> + * Since 1uT = 0.01 gauss, our final scale factor becomes:
> + *
> + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> + * Hadj = H * ((ASA + 128) * 0.003) / 256
> + *
> + * Since ASA doesn't change, we cache the resultant scale factor into the
> + * device context in ak8975_setup().
> + *
> + * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
> + * multiply the stored scale value by 1e6.
> + */
> +long ak8975_raw_to_gauss(u16 data)
What about inline?
> +{
> +	return (((long)data + 128) * 3000) / 256;
> +}
> +
> +/*
> + * For AK8963, same calculation, but the device is less sensitive:
> + *
> + * H is in the range of +-8190.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
> + */
> +long ak8963_raw_to_gauss(u16 data)
What about inline?
> +{
> +	return (((long)data + 128) * 6000) / 256;
> +}
>  
>  /* Compatible Asahi Kasei Compass parts */
>  enum asahi_compass_chipset {
>  	AK8975,
>  	AK8963,
> +	AK_MAX_TYPE
> +};
> +
> +enum ak_ctrl_reg_addr {
> +	ST1,
> +	ST2,
> +	CNTL,
> +	ASA_BASE,
> +	MAX_REGS,
> +	REGS_END,
> +};
> +
> +enum ak_ctrl_reg_mask {
> +	ST1_DRDY,
> +	ST2_HOFL,
> +	ST2_DERR,
> +	CNTL_MODE,
> +	MASK_END,
> +};
> +
> +enum ak_ctrl_mode {
> +	POWER_DOWN,
> +	MODE_ONCE,
> +	SELF_TEST,
> +	FUSE_ROM,
> +	MODE_END,
> +};
> +
> +struct ak_def {
> +	enum asahi_compass_chipset type;
> +	long (*raw_to_gauss)(u16 data);
> +	u16 range;
> +	u8 ctrl_regs[REGS_END];
> +	u8 ctrl_masks[MASK_END];
> +	u8 ctrl_modes[MODE_END];
> +	u8 data_regs[3];
> +} ak_def_array[AK_MAX_TYPE] = {
> +{
> +	.type = AK8975,
> +	.raw_to_gauss = ak8975_raw_to_gauss,
> +	.range = 4096,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		AK8975_REG_ST2_DERR_MASK,
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
> +{
> +	.type = AK8963,
> +	.raw_to_gauss = ak8963_raw_to_gauss,
> +	.range = 8190,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		0,
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
>  };
>  
>  /*
> @@ -100,40 +240,36 @@ enum asahi_compass_chipset {
>   */
>  struct ak8975_data {
>  	struct i2c_client	*client;
> +	struct ak_def		*def;
>  	struct attribute_group	attrs;
>  	struct mutex		lock;
>  	u8			asa[3];
>  	long			raw_to_gauss[3];
> -	u8			reg_cache[AK8975_MAX_REGS];
>  	int			eoc_gpio;
>  	int			eoc_irq;
>  	wait_queue_head_t	data_ready_queue;
>  	unsigned long		flags;
> -	enum asahi_compass_chipset chipset;
> -};
> -
> -static const int ak8975_index_to_reg[] = {
> -	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
> +	u8			cntl_cache;
>  };
>  
>  /*
> - * Helper function to write to the I2C device's registers.
> + * Helper function to write to CNTL register.
>   */
> -static int ak8975_write_data(struct i2c_client *client,
> -			     u8 reg, u8 val, u8 mask, u8 shift)
> +static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
>  {
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak8975_data *data = iio_priv(indio_dev);
>  	u8 regval;
>  	int ret;
>  
> -	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
> -	ret = i2c_smbus_write_byte_data(client, reg, regval);
> +	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
> +		data->def->ctrl_modes[mode];
> +	ret = i2c_smbus_write_byte_data(
> +		data->client, data->def->ctrl_regs[CNTL], regval);
>  	if (ret < 0) {
> -		dev_err(&client->dev, "Write to device fails status %x\n", ret);
>  		return ret;
>  	}
> -	data->reg_cache[reg] = regval;
> +	data->cntl_cache = regval;
> +	/* After mode change wait atleast 100us */
> +	usleep_range(100, 500);
>  
>  	return 0;
>  }
> @@ -207,18 +343,15 @@ static int ak8975_setup(struct i2c_client *client)
>  	}
>  
>  	/* Write the fused rom access mode. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_FUSE_ROM,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = ak8975_set_mode(data, FUSE_ROM);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting fuse access mode\n");
>  		return ret;
>  	}
>  
>  	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
> +	ret = i2c_smbus_read_i2c_block_data(client,
> +					    data->def->ctrl_regs[ASA_BASE],
>  					    3, data->asa);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Not able to read asa data\n");
> @@ -226,11 +359,7 @@ static int ak8975_setup(struct i2c_client *client)
>  	}
>  
>  	/* After reading fuse ROM data set power-down mode */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_POWER_DOWN,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = ak8975_set_mode(data, POWER_DOWN);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting power-down mode\n");
>  		return ret;
> @@ -245,56 +374,9 @@ static int ak8975_setup(struct i2c_client *client)
>  		}
>  	}
>  
> -/*
> - * Precalculate scale factor (in Gauss units) for each axis and
> - * store in the device data.
> - *
> - * This scale factor is axis-dependent, and is derived from 3 calibration
> - * factors ASA(x), ASA(y), and ASA(z).
> - *
> - * These ASA values are read from the sensor device at start of day, and
> - * cached in the device context struct.
> - *
> - * Adjusting the flux value with the sensitivity adjustment value should be
> - * done via the following formula:
> - *
> - * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> - *
> - * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> - * is the resultant adjusted value.
> - *
> - * We reduce the formula to:
> - *
> - * Hadj = H * (ASA + 128) / 256
> - *
> - * H is in the range of -4096 to 4095.  The magnetometer has a range of
> - * +-1229uT.  To go from the raw value to uT is:
> - *
> - * HuT = H * 1229/4096, or roughly, 3/10.
> - *
> - * Since 1uT = 0.01 gauss, our final scale factor becomes:
> - *
> - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> - * Hadj = H * ((ASA + 128) * 0.003) / 256
> - *
> - * Since ASA doesn't change, we cache the resultant scale factor into the
> - * device context in ak8975_setup().
> - */
> -	if (data->chipset == AK8963) {
> -		/*
> -		 * H range is +-8190 and magnetometer range is +-4912.
> -		 * So HuT using the above explanation for 8975,
> -		 * 4912/8190 = ~ 6/10.
> -		 * So the Hadj should use 6/10 instead of 3/10.
> -		 */
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
> -	} else {
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
> -	}
> +	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
> +	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
> +	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
>  
>  	return 0;
>  }
> @@ -317,7 +399,7 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
>  		return -EINVAL;
>  	}
>  
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
>  	if (ret < 0)
>  		dev_err(&client->dev, "Error in reading ST1\n");
>  
> @@ -334,7 +416,8 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>  	/* Wait for the conversion to complete. */
>  	while (timeout_ms) {
>  		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST1]);
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST1\n");
>  			return ret;
> @@ -377,11 +460,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  	mutex_lock(&data->lock);
>  
>  	/* Set up the device for taking a sample. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_ONCE,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = ak8975_set_mode(data, MODE_ONCE);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting operating mode\n");
>  		goto exit;
> @@ -398,14 +477,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  		goto exit;
>  
>  	/* This will be executed only for non-interrupt based waiting case */
> -	if (ret & AK8975_REG_ST1_DRDY_MASK) {
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
> +	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST2]);
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST2\n");
>  			goto exit;
>  		}
> -		if (ret & (AK8975_REG_ST2_DERR_MASK |
> -			   AK8975_REG_ST2_HOFL_MASK)) {
> +		if (ret & (data->def->ctrl_masks[ST2_DERR] |
> +			   data->def->ctrl_masks[ST2_HOFL])) {
>  			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
>  			ret = -EINVAL;
>  			goto exit;
> @@ -414,7 +494,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  
>  	/* Read the flux value from the appropriate register
>  	   (the register is specified in the iio device attributes). */
> -	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
> +	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Read axis data fails\n");
>  		goto exit;
> @@ -423,7 +503,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  	mutex_unlock(&data->lock);
>  
>  	/* Clamp to valid range. */
> -	*val = clamp_t(s16, ret, -4096, 4095);
> +	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
>  	return IIO_VAL_INT;
>  
>  exit:
> @@ -497,6 +577,7 @@ static int ak8975_probe(struct i2c_client *client,
>  	int eoc_gpio;
>  	int err;
>  	const char *name = NULL;
> +	enum asahi_compass_chipset chipset;
>  
>  	/* Grab and set up the supplied GPIO. */
>  	if (client->dev.platform_data)
> @@ -536,14 +617,20 @@ static int ak8975_probe(struct i2c_client *client,
>  
>  	/* id will be NULL when enumerated via ACPI */
>  	if (id) {
> -		data->chipset =
> -			(enum asahi_compass_chipset)(id->driver_data);
> +		chipset = (enum asahi_compass_chipset)(id->driver_data);
>  		name = id->name;
>  	} else if (ACPI_HANDLE(&client->dev))
> -		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
> +		name = ak8975_match_acpi_device(&client->dev, &chipset);
>  	else
>  		return -ENOSYS;
>  
> +	if (chipset >= AK_MAX_TYPE) {
> +		dev_err(&client->dev, "AKM device type unsupported: %d\n",
> +			chipset);
> +		return -ENODEV;
> +	}
> +
> +	data->def = &ak_def_array[chipset];
>  	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>  
>  	/* Perform some basic start-of-day setup of the device. */
> @@ -574,7 +661,9 @@ MODULE_DEVICE_TABLE(i2c, ak8975_id);
>  static const struct of_device_id ak8975_of_match[] = {
>  	{ .compatible = "asahi-kasei,ak8975", },
>  	{ .compatible = "ak8975", },
> -	{ }
> +	{ .compatible = "asahi-kasei,ak8963", },
> +	{ .compatible = "ak8963", },
> +	{}
>  };
>  MODULE_DEVICE_TABLE(of, ak8975_of_match);
>  

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-05 22:10             ` [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support Gwendal Grignou
@ 2014-11-06 15:05               ` Srinivas Pandruvada
  2014-11-06 21:25                 ` Gwendal Grignou
  2014-11-08 12:16                 ` Jonathan Cameron
  0 siblings, 2 replies; 28+ messages in thread
From: Srinivas Pandruvada @ 2014-11-06 15:05 UTC (permalink / raw)
  To: Gwendal Grignou; +Cc: jic23, knaack.h, linux-iio

On Wed, 2014-11-05 at 14:10 -0800, Gwendal Grignou wrote:
> Add 2 new definition entries to support ak0991x compass.
> Add a more advanced function to check we are dealy with the
> expected device.
This commit message doesn't state that you are removing ak09911 driver.
Although you added in cover letter, but that will not be present in the
history.

> 
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>  drivers/iio/magnetometer/Kconfig   |  17 +-
>  drivers/iio/magnetometer/Makefile  |   1 -
>  drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
>  drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
>  4 files changed, 184 insertions(+), 357 deletions(-)
>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
> 
> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> index b2dba9e..cd8750b 100644
> --- a/drivers/iio/magnetometer/Kconfig
> +++ b/drivers/iio/magnetometer/Kconfig
> @@ -6,27 +6,16 @@
>  menu "Magnetometer sensors"
>  
>  config AK8975
> -	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> +	tristate "Asahi Kasei AK 3-Axis Magnetometer"
>  	depends on I2C
>  	depends on GPIOLIB
>  	help
> -	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
> -	  Magnetometer. This driver can also support AK8963, if i2c
> -	  device name is identified as ak8963.
> +	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
> +	  AK09911 or AK09912 3-Axis Magnetometer.
>  
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called ak8975.
>  
> -config AK09911
Instead
config AK09911
	select AK8975

I stated my reason below.
> -	tristate "Asahi Kasei AK09911 3-axis Compass"
> -	depends on I2C
> -	help
> -	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
> -	  Magnetometer.
> -
> -	  To compile this driver as a module, choose M here: the module
> -	  will be called ak09911.
> -
>  config MAG3110
>  	tristate "Freescale MAG3110 3-Axis Magnetometer"
>  	depends on I2C
> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
> index b91315e..0f5d3c9 100644
> --- a/drivers/iio/magnetometer/Makefile
> +++ b/drivers/iio/magnetometer/Makefile
> @@ -3,7 +3,6 @@
>  #
>  
>  # When adding new entries keep the list in alphabetical order
> -obj-$(CONFIG_AK09911)	+= ak09911.o
>  obj-$(CONFIG_AK8975)	+= ak8975.o
>  obj-$(CONFIG_MAG3110)	+= mag3110.o
>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
> deleted file mode 100644
> index b2bc942..0000000
> --- a/drivers/iio/magnetometer/ak09911.c
> +++ /dev/null
> @@ -1,326 +0,0 @@
> -/*
> - * AK09911 3-axis compass driver
> - * Copyright (c) 2014, 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.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/types.h>
> -#include <linux/slab.h>
> -#include <linux/delay.h>
> -#include <linux/i2c.h>
> -#include <linux/acpi.h>
> -#include <linux/iio/iio.h>
> -
> -#define AK09911_REG_WIA1		0x00
> -#define AK09911_REG_WIA2		0x01
> -#define AK09911_WIA1_VALUE		0x48
> -#define AK09911_WIA2_VALUE		0x05
> -
> -#define AK09911_REG_ST1			0x10
> -#define AK09911_REG_HXL			0x11
> -#define AK09911_REG_HXH			0x12
> -#define AK09911_REG_HYL			0x13
> -#define AK09911_REG_HYH			0x14
> -#define AK09911_REG_HZL			0x15
> -#define AK09911_REG_HZH			0x16
> -
> -#define AK09911_REG_ASAX		0x60
> -#define AK09911_REG_ASAY		0x61
> -#define AK09911_REG_ASAZ		0x62
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_MODE_SNG_MEASURE	0x01
> -#define AK09911_MODE_SELF_TEST		0x10
> -#define AK09911_MODE_FUSE_ACCESS	0x1F
> -#define AK09911_MODE_POWERDOWN		0x00
> -#define AK09911_RESET_DATA		0x01
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
> -
> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
> -
> -struct ak09911_data {
> -	struct i2c_client	*client;
> -	struct mutex		lock;
> -	u8			asa[3];
> -	long			raw_to_gauss[3];
> -};
> -
> -static const int ak09911_index_to_reg[] = {
> -	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
> -};
> -
> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
> -{
> -	int ret;
> -
> -	switch (mode) {
> -	case AK09911_MODE_SNG_MEASURE:
> -	case AK09911_MODE_SELF_TEST:
> -	case AK09911_MODE_FUSE_ACCESS:
> -	case AK09911_MODE_POWERDOWN:
> -		ret = i2c_smbus_write_byte_data(client,
> -						AK09911_REG_CNTL2, mode);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "set_mode error\n");
> -			return ret;
> -		}
> -		/* After mode change wait atleast 100us */
> -		usleep_range(100, 500);
> -		break;
> -	default:
> -		dev_err(&client->dev,
> -			"%s: Unknown mode(%d).", __func__, mode);
> -		return -EINVAL;
> -	}
> -
> -	return ret;
> -}
> -
> -/* Get Sensitivity Adjustment value */
> -static int ak09911_get_asa(struct i2c_client *client)
> -{
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	int ret;
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
> -	if (ret < 0)
> -		return ret;
> -
> -	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
> -					    3, data->asa);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Not able to read asa data\n");
> -		return ret;
> -	}
> -
> -	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
> -	if (ret < 0)
> -		return ret;
> -
> -	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
> -	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
> -	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
> -
> -	return 0;
> -}
> -
> -static int ak09911_verify_chip_id(struct i2c_client *client)
> -{
> -	u8 wia_val[2];
> -	int ret;
> -
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
> -					    2, wia_val);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -
> -	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
> -
> -	if (wia_val[0] != AK09911_WIA1_VALUE ||
> -		wia_val[1] != AK09911_WIA2_VALUE) {
> -		dev_err(&client->dev, "Device ak09911 not found\n");
> -		return -ENODEV;
> -	}
> -
> -	return 0;
> -}
> -
> -static int wait_conversion_complete_polled(struct ak09911_data *data)
> -{
> -	struct i2c_client *client = data->client;
> -	u8 read_status;
> -	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
> -	int ret;
> -
> -	/* Wait for the conversion to complete. */
> -	while (timeout_ms) {
> -		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
> -		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "Error in reading ST1\n");
> -			return ret;
> -		}
> -		read_status = ret & 0x01;
> -		if (read_status)
> -			break;
> -		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
> -	}
> -	if (!timeout_ms) {
> -		dev_err(&client->dev, "Conversion timeout happened\n");
> -		return -EIO;
> -	}
> -
> -	return read_status;
> -}
> -
> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	struct i2c_client *client = data->client;
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	ret = wait_conversion_complete_polled(data);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	/* Read data */
> -	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Read axis data fails\n");
> -		goto fn_exit;
> -	}
> -
> -	mutex_unlock(&data->lock);
> -
> -	/* Clamp to valid range. */
> -	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
> -
> -	return IIO_VAL_INT;
> -
> -fn_exit:
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static int ak09911_read_raw(struct iio_dev *indio_dev,
> -			    struct iio_chan_spec const *chan,
> -			    int *val, int *val2,
> -			    long mask)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -
> -	switch (mask) {
> -	case IIO_CHAN_INFO_RAW:
> -		return ak09911_read_axis(indio_dev, chan->address, val);
> -	case IIO_CHAN_INFO_SCALE:
> -		*val = 0;
> -		*val2 = data->raw_to_gauss[chan->address];
> -		return IIO_VAL_INT_PLUS_MICRO;
> -	}
> -
> -	return -EINVAL;
> -}
> -
> -#define AK09911_CHANNEL(axis, index)					\
> -	{								\
> -		.type = IIO_MAGN,					\
> -		.modified = 1,						\
> -		.channel2 = IIO_MOD_##axis,				\
> -		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
> -			     BIT(IIO_CHAN_INFO_SCALE),			\
> -		.address = index,					\
> -	}
> -
> -static const struct iio_chan_spec ak09911_channels[] = {
> -	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
> -};
> -
> -static const struct iio_info ak09911_info = {
> -	.read_raw = &ak09911_read_raw,
> -	.driver_module = THIS_MODULE,
> -};
> -
> -static const struct acpi_device_id ak_acpi_match[] = {
> -	{"AK009911", 0},
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> -
> -static int ak09911_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> -{
> -	struct iio_dev *indio_dev;
> -	struct ak09911_data *data;
> -	const char *name;
> -	int ret;
> -
> -	ret = ak09911_verify_chip_id(client);
> -	if (ret) {
> -		dev_err(&client->dev, "AK00911 not detected\n");
> -		return -ENODEV;
> -	}
> -
> -	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> -	if (indio_dev == NULL)
> -		return -ENOMEM;
> -
> -	data = iio_priv(indio_dev);
> -	i2c_set_clientdata(client, indio_dev);
> -
> -	data->client = client;
> -	mutex_init(&data->lock);
> -
> -	ret = ak09911_get_asa(client);
> -	if (ret)
> -		return ret;
> -
> -	if (id)
> -		name = id->name;
> -	else if (ACPI_HANDLE(&client->dev))
> -		name = dev_name(&client->dev);
> -	else
> -		return -ENODEV;
> -
> -	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> -
> -	indio_dev->dev.parent = &client->dev;
> -	indio_dev->channels = ak09911_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
> -	indio_dev->info = &ak09911_info;
> -	indio_dev->modes = INDIO_DIRECT_MODE;
> -	indio_dev->name = name;
> -
> -	return devm_iio_device_register(&client->dev, indio_dev);
> -}
> -
> -static const struct i2c_device_id ak09911_id[] = {
> -	{"ak09911", 0},
> -	{}
> -};
> -
> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
> -
> -static struct i2c_driver ak09911_driver = {
> -	.driver = {
> -		.name	= "ak09911",
> -		.acpi_match_table = ACPI_PTR(ak_acpi_match),
> -	},
> -	.probe		= ak09911_probe,
> -	.id_table	= ak09911_id,
> -};
> -module_i2c_driver(ak09911_driver);
> -
> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
> -MODULE_LICENSE("GPL v2");
> -MODULE_DESCRIPTION("AK09911 Compass driver");
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index b170654..f8c7046 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -81,6 +81,58 @@
>  #define AK8975_MAX_REGS			AK8975_REG_ASAZ
>  
>  /*
> + * AK09912 Register definitions
> + */
> +#define AK09912_REG_WIA1		0x00
> +#define AK09912_REG_WIA2		0x01
> +#define AK09912_DEVICE_ID		0x04
> +#define AK09911_DEVICE_ID		0x05
> +
> +#define AK09911_REG_INFO1		0x02
> +#define AK09911_REG_INFO2		0x03
> +
> +#define AK09912_REG_ST1			0x10
> +
> +#define AK09912_REG_ST1_DRDY_SHIFT	0
> +#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
> +
> +#define AK09912_REG_HXL			0x11
> +#define AK09912_REG_HXH			0x12
> +#define AK09912_REG_HYL			0x13
> +#define AK09912_REG_HYH			0x14
> +#define AK09912_REG_HZL			0x15
> +#define AK09912_REG_HZH			0x16
> +#define AK09912_REG_TMPS		0x17
> +
> +#define AK09912_REG_ST2			0x18
> +#define AK09912_REG_ST2_HOFL_SHIFT	3
> +#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
> +
> +#define AK09912_REG_CNTL1		0x30
> +
> +#define AK09912_REG_CNTL2		0x31
> +#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK09912_REG_CNTL_MODE_ONCE	0x01
> +#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
> +#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
> +#define AK09912_REG_CNTL2_MODE_SHIFT	0
> +#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
> +
> +#define AK09912_REG_CNTL3		0x32
> +
> +#define AK09912_REG_TS1			0x33
> +#define AK09912_REG_TS2			0x34
> +#define AK09912_REG_TS3			0x35
> +#define AK09912_REG_I2CDIS		0x36
> +#define AK09912_REG_TS4			0x37
> +
> +#define AK09912_REG_ASAX		0x60
> +#define AK09912_REG_ASAY		0x61
> +#define AK09912_REG_ASAZ		0x62
> +
> +#define AK09912_MAX_REGS		AK09912_REG_ASAZ
> +
> +/*
>   * Miscellaneous values.
>   */
>  #define AK8975_MAX_CONVERSION_TIMEOUT	500
> @@ -130,22 +182,37 @@ long ak8975_raw_to_gauss(u16 data)
>  }
>  
>  /*
> - * For AK8963, same calculation, but the device is less sensitive:
> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
>   *
>   * H is in the range of +-8190.  The magnetometer has a range of
>   * +-4912uT.  To go from the raw value to uT is:
>   *
>   * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
>   */
> -long ak8963_raw_to_gauss(u16 data)
> +long ak8963_09911_raw_to_gauss(u16 data)
>  {
>  	return (((long)data + 128) * 6000) / 256;
>  }
>  
> +/*
> + * For AK09912, same calculation, except the device is more sensitive:
> + *
> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
> + */
> +long ak09912_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 1500) / 256;
> +}
> +
>  /* Compatible Asahi Kasei Compass parts */
>  enum asahi_compass_chipset {
>  	AK8975,
>  	AK8963,
> +	AK09911,
> +	AK09912,
>  	AK_MAX_TYPE
>  };
>  
> @@ -210,7 +277,7 @@ struct ak_def {
>  },
>  {
>  	.type = AK8963,
> -	.raw_to_gauss = ak8963_raw_to_gauss,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
>  	.range = 8190,
>  	.ctrl_regs = {
>  		AK8975_REG_ST1,
> @@ -233,6 +300,56 @@ struct ak_def {
>  		AK8975_REG_HYL,
>  		AK8975_REG_HZL},
>  },
> +{
> +	.type = AK09911,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
> +	.range = 8192,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +},
> +{
> +	.type = AK09912,
> +	.raw_to_gauss = ak09912_raw_to_gauss,
> +	.range = 32752,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +}
>  };
>  
>  /*
> @@ -253,6 +370,55 @@ struct ak8975_data {
>  };
>  
>  /*
> + * Return 0 if the i2c device is the one we expect.
> + * return a negative error number otherwise
> + */
> +static int ak8975_who_i_am(struct i2c_client *client,
> +			   enum asahi_compass_chipset type)
> +{
> +	u8 wia_val[2];
> +	int ret;
> +
> +	/*
> +	 * Signature for each device:
> +	 * Device   |  WIA1      |  WIA2
> +	 * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
> +	 * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
> +	 * AK8975   |  DEVICE_ID |  NA
> +	 * AK8963   |  DEVICE_ID |  NA
> +	 */
> +	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> +					    2, wia_val);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error reading WIA\n");
> +		return ret;
> +	}
> +
> +	ret = -ENODEV;
> +
> +	if (wia_val[0] != AK8975_DEVICE_ID)
> +		return ret;
> +
> +	switch (type) {
> +	case AK8975:
> +	case AK8963:
> +		ret = 0;
> +		break;
> +	case AK09911:
> +		if (wia_val[1] == AK09911_DEVICE_ID)
> +			ret = 0;
> +		break;
> +	case AK09912:
> +		if (wia_val[1] == AK09912_DEVICE_ID)
> +			ret = 0;
> +		break;
> +	default:
> +		dev_err(&client->dev, "Type %d unknown\n", type);
> +	}
> +	return ret;
> +}
> +
> +/*
>   * Helper function to write to CNTL register.
>   */
>  static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
> @@ -327,21 +493,8 @@ static int ak8975_setup(struct i2c_client *client)
>  {
>  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
>  	struct ak8975_data *data = iio_priv(indio_dev);
> -	u8 device_id;
>  	int ret;
>  
> -	/* Confirm that the device we're talking to is really an AK8975. */
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -	device_id = ret;
> -	if (device_id != AK8975_DEVICE_ID) {
> -		dev_err(&client->dev, "Device ak8975 not found\n");
> -		return -ENODEV;
> -	}
> -
>  	/* Write the fused rom access mode. */
>  	ret = ak8975_set_mode(data, FUSE_ROM);
>  	if (ret < 0) {
> @@ -552,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
>  	{"AK8975", AK8975},
>  	{"AK8963", AK8963},
>  	{"INVN6500", AK8963},
> +	{"AK09911", AK09911},
> +	{"AK09912", AK09912},
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> @@ -631,6 +786,10 @@ static int ak8975_probe(struct i2c_client *client,
>  	}
>  
>  	data->def = &ak_def_array[chipset];
> +	if (ak8975_who_i_am(client, data->def->type) < 0) {
> +		dev_err(&client->dev, "Unexpected device\n");
> +		return -ENODEV;
> +	}
>  	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>  
>  	/* Perform some basic start-of-day setup of the device. */
> @@ -653,6 +812,8 @@ static int ak8975_probe(struct i2c_client *client,
>  static const struct i2c_device_id ak8975_id[] = {
>  	{"ak8975", AK8975},
>  	{"ak8963", AK8963},
> +	{"ak09911", AK09911},
> +	{"ak09912", AK09912},
>  	{}
>  };
>  
> @@ -663,6 +824,10 @@ static const struct of_device_id ak8975_of_match[] = {
>  	{ .compatible = "ak8975", },
>  	{ .compatible = "asahi-kasei,ak8963", },
>  	{ .compatible = "ak8963", },
> +	{ .compatible = "asahi-kasei,ak09911", },
> +	{ .compatible = "ak09911", },
> +	{ .compatible = "asahi-kasei,ak09912", },
> +	{ .compatible = "ak09912", },
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, ak8975_of_match);

I need to test this driver.
Jonathan,
If possible, wait for Tested by tag from me or someone else.

Thanks,
Srinivas


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/3] iio: ak8975: add definition structure per compass type
  2014-11-06 15:02               ` Srinivas Pandruvada
@ 2014-11-06 21:16                 ` Gwendal Grignou
  0 siblings, 0 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-06 21:16 UTC (permalink / raw)
  To: Srinivas Pandruvada
  Cc: Gwendal Grignou, Jonathan Cameron, knaack.h, linux-iio

On Thu, Nov 6, 2014 at 7:02 AM, Srinivas Pandruvada
<srinivas.pandruvada@linux.intel.com> wrote:
> On Wed, 2014-11-05 at 14:10 -0800, Gwendal Grignou wrote:
>> For each type of compass supported (AK8975 and AK8963),
>> add a definition structure for register masks, important registers,
>> raw data interpretation.
>> This change will make integrating new type of devices easier.
>>
>> Remove i2c register cache. It is only used for one single register.
>>
>> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
>> ---
>>  drivers/iio/magnetometer/ak8975.c | 279 +++++++++++++++++++++++++-------------
>>  1 file changed, 184 insertions(+), 95 deletions(-)
>>
>> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
>> index 12f0b00..b170654 100644
>> --- a/drivers/iio/magnetometer/ak8975.c
>> +++ b/drivers/iio/magnetometer/ak8975.c
>> @@ -86,13 +86,153 @@
>>  #define AK8975_MAX_CONVERSION_TIMEOUT        500
>>  #define AK8975_CONVERSION_DONE_POLL_TIME 10
>>  #define AK8975_DATA_READY_TIMEOUT    ((100*HZ)/1000)
>> -#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
>> -#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
>> +
>> +/*
>> + * Precalculate scale factor (in Gauss units) for each axis and
>> + * store in the device data.
>> + *
>> + * This scale factor is axis-dependent, and is derived from 3 calibration
>> + * factors ASA(x), ASA(y), and ASA(z).
>> + *
>> + * These ASA values are read from the sensor device at start of day, and
>> + * cached in the device context struct.
>> + *
>> + * Adjusting the flux value with the sensitivity adjustment value should be
>> + * done via the following formula:
>> + *
>> + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
>> + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
>> + * is the resultant adjusted value.
>> + *
>> + * We reduce the formula to:
>> + *
>> + * Hadj = H * (ASA + 128) / 256
>> + *
>> + * H is in the range of -4096 to 4095.  The magnetometer has a range of
>> + * +-1229uT.  To go from the raw value to uT is:
>> + *
>> + * HuT = H * 1229/4096, or roughly, 3/10.
>> + *
>> + * Since 1uT = 0.01 gauss, our final scale factor becomes:
>> + *
>> + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
>> + * Hadj = H * ((ASA + 128) * 0.003) / 256
>> + *
>> + * Since ASA doesn't change, we cache the resultant scale factor into the
>> + * device context in ak8975_setup().
>> + *
>> + * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
>> + * multiply the stored scale value by 1e6.
>> + */
>> +long ak8975_raw_to_gauss(u16 data)
> What about inline?
>> +{
>> +     return (((long)data + 128) * 3000) / 256;
>> +}
>> +
>> +/*
>> + * For AK8963, same calculation, but the device is less sensitive:
>> + *
>> + * H is in the range of +-8190.  The magnetometer has a range of
>> + * +-4912uT.  To go from the raw value to uT is:
>> + *
>> + * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
>> + */
>> +long ak8963_raw_to_gauss(u16 data)
> What about inline?
1 - This function is only used at setup time, so we don't have to inline them.
2 - Given the functions are use through pointer, in-lining does not
bring any performance improvement anyway.
>> +{
>> +     return (((long)data + 128) * 6000) / 256;
>> +}
>>
>>  /* Compatible Asahi Kasei Compass parts */
>>  enum asahi_compass_chipset {
>>       AK8975,
>>       AK8963,
>> +     AK_MAX_TYPE
>> +};
>> +
>> +enum ak_ctrl_reg_addr {
>> +     ST1,
>> +     ST2,
>> +     CNTL,
>> +     ASA_BASE,
>> +     MAX_REGS,
>> +     REGS_END,
>> +};
>> +
>> +enum ak_ctrl_reg_mask {
>> +     ST1_DRDY,
>> +     ST2_HOFL,
>> +     ST2_DERR,
>> +     CNTL_MODE,
>> +     MASK_END,
>> +};
>> +
>> +enum ak_ctrl_mode {
>> +     POWER_DOWN,
>> +     MODE_ONCE,
>> +     SELF_TEST,
>> +     FUSE_ROM,
>> +     MODE_END,
>> +};
>> +
>> +struct ak_def {
>> +     enum asahi_compass_chipset type;
>> +     long (*raw_to_gauss)(u16 data);
>> +     u16 range;
>> +     u8 ctrl_regs[REGS_END];
>> +     u8 ctrl_masks[MASK_END];
>> +     u8 ctrl_modes[MODE_END];
>> +     u8 data_regs[3];
>> +} ak_def_array[AK_MAX_TYPE] = {
>> +{
>> +     .type = AK8975,
>> +     .raw_to_gauss = ak8975_raw_to_gauss,
>> +     .range = 4096,
>> +     .ctrl_regs = {
>> +             AK8975_REG_ST1,
>> +             AK8975_REG_ST2,
>> +             AK8975_REG_CNTL,
>> +             AK8975_REG_ASAX,
>> +             AK8975_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK8975_REG_ST1_DRDY_MASK,
>> +             AK8975_REG_ST2_HOFL_MASK,
>> +             AK8975_REG_ST2_DERR_MASK,
>> +             AK8975_REG_CNTL_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK8975_REG_CNTL_MODE_POWER_DOWN,
>> +             AK8975_REG_CNTL_MODE_ONCE,
>> +             AK8975_REG_CNTL_MODE_SELF_TEST,
>> +             AK8975_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK8975_REG_HXL,
>> +             AK8975_REG_HYL,
>> +             AK8975_REG_HZL},
>> +},
>> +{
>> +     .type = AK8963,
>> +     .raw_to_gauss = ak8963_raw_to_gauss,
>> +     .range = 8190,
>> +     .ctrl_regs = {
>> +             AK8975_REG_ST1,
>> +             AK8975_REG_ST2,
>> +             AK8975_REG_CNTL,
>> +             AK8975_REG_ASAX,
>> +             AK8975_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK8975_REG_ST1_DRDY_MASK,
>> +             AK8975_REG_ST2_HOFL_MASK,
>> +             0,
>> +             AK8975_REG_CNTL_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK8975_REG_CNTL_MODE_POWER_DOWN,
>> +             AK8975_REG_CNTL_MODE_ONCE,
>> +             AK8975_REG_CNTL_MODE_SELF_TEST,
>> +             AK8975_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK8975_REG_HXL,
>> +             AK8975_REG_HYL,
>> +             AK8975_REG_HZL},
>> +},
>>  };
>>
>>  /*
>> @@ -100,40 +240,36 @@ enum asahi_compass_chipset {
>>   */
>>  struct ak8975_data {
>>       struct i2c_client       *client;
>> +     struct ak_def           *def;
>>       struct attribute_group  attrs;
>>       struct mutex            lock;
>>       u8                      asa[3];
>>       long                    raw_to_gauss[3];
>> -     u8                      reg_cache[AK8975_MAX_REGS];
>>       int                     eoc_gpio;
>>       int                     eoc_irq;
>>       wait_queue_head_t       data_ready_queue;
>>       unsigned long           flags;
>> -     enum asahi_compass_chipset chipset;
>> -};
>> -
>> -static const int ak8975_index_to_reg[] = {
>> -     AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
>> +     u8                      cntl_cache;
>>  };
>>
>>  /*
>> - * Helper function to write to the I2C device's registers.
>> + * Helper function to write to CNTL register.
>>   */
>> -static int ak8975_write_data(struct i2c_client *client,
>> -                          u8 reg, u8 val, u8 mask, u8 shift)
>> +static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
>>  {
>> -     struct iio_dev *indio_dev = i2c_get_clientdata(client);
>> -     struct ak8975_data *data = iio_priv(indio_dev);
>>       u8 regval;
>>       int ret;
>>
>> -     regval = (data->reg_cache[reg] & ~mask) | (val << shift);
>> -     ret = i2c_smbus_write_byte_data(client, reg, regval);
>> +     regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
>> +             data->def->ctrl_modes[mode];
>> +     ret = i2c_smbus_write_byte_data(
>> +             data->client, data->def->ctrl_regs[CNTL], regval);
>>       if (ret < 0) {
>> -             dev_err(&client->dev, "Write to device fails status %x\n", ret);
>>               return ret;
>>       }
>> -     data->reg_cache[reg] = regval;
>> +     data->cntl_cache = regval;
>> +     /* After mode change wait atleast 100us */
>> +     usleep_range(100, 500);
>>
>>       return 0;
>>  }
>> @@ -207,18 +343,15 @@ static int ak8975_setup(struct i2c_client *client)
>>       }
>>
>>       /* Write the fused rom access mode. */
>> -     ret = ak8975_write_data(client,
>> -                             AK8975_REG_CNTL,
>> -                             AK8975_REG_CNTL_MODE_FUSE_ROM,
>> -                             AK8975_REG_CNTL_MODE_MASK,
>> -                             AK8975_REG_CNTL_MODE_SHIFT);
>> +     ret = ak8975_set_mode(data, FUSE_ROM);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Error in setting fuse access mode\n");
>>               return ret;
>>       }
>>
>>       /* Get asa data and store in the device data. */
>> -     ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
>> +     ret = i2c_smbus_read_i2c_block_data(client,
>> +                                         data->def->ctrl_regs[ASA_BASE],
>>                                           3, data->asa);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Not able to read asa data\n");
>> @@ -226,11 +359,7 @@ static int ak8975_setup(struct i2c_client *client)
>>       }
>>
>>       /* After reading fuse ROM data set power-down mode */
>> -     ret = ak8975_write_data(client,
>> -                             AK8975_REG_CNTL,
>> -                             AK8975_REG_CNTL_MODE_POWER_DOWN,
>> -                             AK8975_REG_CNTL_MODE_MASK,
>> -                             AK8975_REG_CNTL_MODE_SHIFT);
>> +     ret = ak8975_set_mode(data, POWER_DOWN);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Error in setting power-down mode\n");
>>               return ret;
>> @@ -245,56 +374,9 @@ static int ak8975_setup(struct i2c_client *client)
>>               }
>>       }
>>
>> -/*
>> - * Precalculate scale factor (in Gauss units) for each axis and
>> - * store in the device data.
>> - *
>> - * This scale factor is axis-dependent, and is derived from 3 calibration
>> - * factors ASA(x), ASA(y), and ASA(z).
>> - *
>> - * These ASA values are read from the sensor device at start of day, and
>> - * cached in the device context struct.
>> - *
>> - * Adjusting the flux value with the sensitivity adjustment value should be
>> - * done via the following formula:
>> - *
>> - * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
>> - *
>> - * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
>> - * is the resultant adjusted value.
>> - *
>> - * We reduce the formula to:
>> - *
>> - * Hadj = H * (ASA + 128) / 256
>> - *
>> - * H is in the range of -4096 to 4095.  The magnetometer has a range of
>> - * +-1229uT.  To go from the raw value to uT is:
>> - *
>> - * HuT = H * 1229/4096, or roughly, 3/10.
>> - *
>> - * Since 1uT = 0.01 gauss, our final scale factor becomes:
>> - *
>> - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
>> - * Hadj = H * ((ASA + 128) * 0.003) / 256
>> - *
>> - * Since ASA doesn't change, we cache the resultant scale factor into the
>> - * device context in ak8975_setup().
>> - */
>> -     if (data->chipset == AK8963) {
>> -             /*
>> -              * H range is +-8190 and magnetometer range is +-4912.
>> -              * So HuT using the above explanation for 8975,
>> -              * 4912/8190 = ~ 6/10.
>> -              * So the Hadj should use 6/10 instead of 3/10.
>> -              */
>> -             data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
>> -             data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
>> -             data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
>> -     } else {
>> -             data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
>> -             data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
>> -             data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
>> -     }
>> +     data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
>> +     data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
>> +     data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
>>
>>       return 0;
>>  }
>> @@ -317,7 +399,7 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
>>               return -EINVAL;
>>       }
>>
>> -     ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
>> +     ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
>>       if (ret < 0)
>>               dev_err(&client->dev, "Error in reading ST1\n");
>>
>> @@ -334,7 +416,8 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>>       /* Wait for the conversion to complete. */
>>       while (timeout_ms) {
>>               msleep(AK8975_CONVERSION_DONE_POLL_TIME);
>> -             ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
>> +             ret = i2c_smbus_read_byte_data(
>> +                             client, data->def->ctrl_regs[ST1]);
>>               if (ret < 0) {
>>                       dev_err(&client->dev, "Error in reading ST1\n");
>>                       return ret;
>> @@ -377,11 +460,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>       mutex_lock(&data->lock);
>>
>>       /* Set up the device for taking a sample. */
>> -     ret = ak8975_write_data(client,
>> -                             AK8975_REG_CNTL,
>> -                             AK8975_REG_CNTL_MODE_ONCE,
>> -                             AK8975_REG_CNTL_MODE_MASK,
>> -                             AK8975_REG_CNTL_MODE_SHIFT);
>> +     ret = ak8975_set_mode(data, MODE_ONCE);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Error in setting operating mode\n");
>>               goto exit;
>> @@ -398,14 +477,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>               goto exit;
>>
>>       /* This will be executed only for non-interrupt based waiting case */
>> -     if (ret & AK8975_REG_ST1_DRDY_MASK) {
>> -             ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
>> +     if (ret & data->def->ctrl_masks[ST1_DRDY]) {
>> +             ret = i2c_smbus_read_byte_data(
>> +                             client, data->def->ctrl_regs[ST2]);
>>               if (ret < 0) {
>>                       dev_err(&client->dev, "Error in reading ST2\n");
>>                       goto exit;
>>               }
>> -             if (ret & (AK8975_REG_ST2_DERR_MASK |
>> -                        AK8975_REG_ST2_HOFL_MASK)) {
>> +             if (ret & (data->def->ctrl_masks[ST2_DERR] |
>> +                        data->def->ctrl_masks[ST2_HOFL])) {
>>                       dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
>>                       ret = -EINVAL;
>>                       goto exit;
>> @@ -414,7 +494,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>
>>       /* Read the flux value from the appropriate register
>>          (the register is specified in the iio device attributes). */
>> -     ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
>> +     ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
>>       if (ret < 0) {
>>               dev_err(&client->dev, "Read axis data fails\n");
>>               goto exit;
>> @@ -423,7 +503,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>>       mutex_unlock(&data->lock);
>>
>>       /* Clamp to valid range. */
>> -     *val = clamp_t(s16, ret, -4096, 4095);
>> +     *val = clamp_t(s16, ret, -data->def->range, data->def->range);
>>       return IIO_VAL_INT;
>>
>>  exit:
>> @@ -497,6 +577,7 @@ static int ak8975_probe(struct i2c_client *client,
>>       int eoc_gpio;
>>       int err;
>>       const char *name = NULL;
>> +     enum asahi_compass_chipset chipset;
>>
>>       /* Grab and set up the supplied GPIO. */
>>       if (client->dev.platform_data)
>> @@ -536,14 +617,20 @@ static int ak8975_probe(struct i2c_client *client,
>>
>>       /* id will be NULL when enumerated via ACPI */
>>       if (id) {
>> -             data->chipset =
>> -                     (enum asahi_compass_chipset)(id->driver_data);
>> +             chipset = (enum asahi_compass_chipset)(id->driver_data);
>>               name = id->name;
>>       } else if (ACPI_HANDLE(&client->dev))
>> -             name = ak8975_match_acpi_device(&client->dev, &data->chipset);
>> +             name = ak8975_match_acpi_device(&client->dev, &chipset);
>>       else
>>               return -ENOSYS;
>>
>> +     if (chipset >= AK_MAX_TYPE) {
>> +             dev_err(&client->dev, "AKM device type unsupported: %d\n",
>> +                     chipset);
>> +             return -ENODEV;
>> +     }
>> +
>> +     data->def = &ak_def_array[chipset];
>>       dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>>
>>       /* Perform some basic start-of-day setup of the device. */
>> @@ -574,7 +661,9 @@ MODULE_DEVICE_TABLE(i2c, ak8975_id);
>>  static const struct of_device_id ak8975_of_match[] = {
>>       { .compatible = "asahi-kasei,ak8975", },
>>       { .compatible = "ak8975", },
>> -     { }
>> +     { .compatible = "asahi-kasei,ak8963", },
>> +     { .compatible = "ak8963", },
>> +     {}
>>  };
>>  MODULE_DEVICE_TABLE(of, ak8975_of_match);
>>
>
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-06 15:05               ` Srinivas Pandruvada
@ 2014-11-06 21:25                 ` Gwendal Grignou
  2014-11-17 18:02                   ` Srinivas Pandruvada
  2014-11-19 11:39                   ` Hartmut Knaack
  2014-11-08 12:16                 ` Jonathan Cameron
  1 sibling, 2 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-06 21:25 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23, knaack.h; +Cc: linux-iio, Gwendal Grignou

Add 2 new definition entries to support ak0991x compass.
Add a more advanced function to check we are dealing with the
expected device.
Remove standalone driver for ak09911.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---
 Readded CONFIG_AK09911 to ease transition from standalone driver.

 drivers/iio/magnetometer/Kconfig   |  15 +-
 drivers/iio/magnetometer/Makefile  |   1 -
 drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
 drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
 4 files changed, 186 insertions(+), 353 deletions(-)
 delete mode 100644 drivers/iio/magnetometer/ak09911.c

diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index b2dba9e..4c7a4c5 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -6,26 +6,21 @@
 menu "Magnetometer sensors"
 
 config AK8975
-	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+	tristate "Asahi Kasei AK 3-Axis Magnetometer"
 	depends on I2C
 	depends on GPIOLIB
 	help
-	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
-	  Magnetometer. This driver can also support AK8963, if i2c
-	  device name is identified as ak8963.
+	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
+	  AK09911 or AK09912 3-Axis Magnetometer.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called ak8975.
 
 config AK09911
 	tristate "Asahi Kasei AK09911 3-axis Compass"
-	depends on I2C
+	select AK8975
 	help
-	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
-	  Magnetometer.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called ak09911.
+	  Deprecated: AK09911 is now supported by AK8975 driver.
 
 config MAG3110
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b91315e..0f5d3c9 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,7 +3,6 @@
 #
 
 # When adding new entries keep the list in alphabetical order
-obj-$(CONFIG_AK09911)	+= ak09911.o
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
deleted file mode 100644
index b2bc942..0000000
--- a/drivers/iio/magnetometer/ak09911.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * AK09911 3-axis compass driver
- * Copyright (c) 2014, 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/iio/iio.h>
-
-#define AK09911_REG_WIA1		0x00
-#define AK09911_REG_WIA2		0x01
-#define AK09911_WIA1_VALUE		0x48
-#define AK09911_WIA2_VALUE		0x05
-
-#define AK09911_REG_ST1			0x10
-#define AK09911_REG_HXL			0x11
-#define AK09911_REG_HXH			0x12
-#define AK09911_REG_HYL			0x13
-#define AK09911_REG_HYH			0x14
-#define AK09911_REG_HZL			0x15
-#define AK09911_REG_HZH			0x16
-
-#define AK09911_REG_ASAX		0x60
-#define AK09911_REG_ASAY		0x61
-#define AK09911_REG_ASAZ		0x62
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_MODE_SNG_MEASURE	0x01
-#define AK09911_MODE_SELF_TEST		0x10
-#define AK09911_MODE_FUSE_ACCESS	0x1F
-#define AK09911_MODE_POWERDOWN		0x00
-#define AK09911_RESET_DATA		0x01
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
-
-#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
-#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
-
-struct ak09911_data {
-	struct i2c_client	*client;
-	struct mutex		lock;
-	u8			asa[3];
-	long			raw_to_gauss[3];
-};
-
-static const int ak09911_index_to_reg[] = {
-	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
-};
-
-static int ak09911_set_mode(struct i2c_client *client, u8 mode)
-{
-	int ret;
-
-	switch (mode) {
-	case AK09911_MODE_SNG_MEASURE:
-	case AK09911_MODE_SELF_TEST:
-	case AK09911_MODE_FUSE_ACCESS:
-	case AK09911_MODE_POWERDOWN:
-		ret = i2c_smbus_write_byte_data(client,
-						AK09911_REG_CNTL2, mode);
-		if (ret < 0) {
-			dev_err(&client->dev, "set_mode error\n");
-			return ret;
-		}
-		/* After mode change wait atleast 100us */
-		usleep_range(100, 500);
-		break;
-	default:
-		dev_err(&client->dev,
-			"%s: Unknown mode(%d).", __func__, mode);
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-/* Get Sensitivity Adjustment value */
-static int ak09911_get_asa(struct i2c_client *client)
-{
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak09911_data *data = iio_priv(indio_dev);
-	int ret;
-
-	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
-	if (ret < 0)
-		return ret;
-
-	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
-					    3, data->asa);
-	if (ret < 0) {
-		dev_err(&client->dev, "Not able to read asa data\n");
-		return ret;
-	}
-
-	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
-	if (ret < 0)
-		return ret;
-
-	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
-	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
-	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
-
-	return 0;
-}
-
-static int ak09911_verify_chip_id(struct i2c_client *client)
-{
-	u8 wia_val[2];
-	int ret;
-
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
-					    2, wia_val);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-
-	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
-
-	if (wia_val[0] != AK09911_WIA1_VALUE ||
-		wia_val[1] != AK09911_WIA2_VALUE) {
-		dev_err(&client->dev, "Device ak09911 not found\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int wait_conversion_complete_polled(struct ak09911_data *data)
-{
-	struct i2c_client *client = data->client;
-	u8 read_status;
-	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
-	int ret;
-
-	/* Wait for the conversion to complete. */
-	while (timeout_ms) {
-		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
-		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
-		if (ret < 0) {
-			dev_err(&client->dev, "Error in reading ST1\n");
-			return ret;
-		}
-		read_status = ret & 0x01;
-		if (read_status)
-			break;
-		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
-	}
-	if (!timeout_ms) {
-		dev_err(&client->dev, "Conversion timeout happened\n");
-		return -EIO;
-	}
-
-	return read_status;
-}
-
-static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	int ret;
-
-	mutex_lock(&data->lock);
-
-	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
-	if (ret < 0)
-		goto fn_exit;
-
-	ret = wait_conversion_complete_polled(data);
-	if (ret < 0)
-		goto fn_exit;
-
-	/* Read data */
-	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
-	if (ret < 0) {
-		dev_err(&client->dev, "Read axis data fails\n");
-		goto fn_exit;
-	}
-
-	mutex_unlock(&data->lock);
-
-	/* Clamp to valid range. */
-	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
-
-	return IIO_VAL_INT;
-
-fn_exit:
-	mutex_unlock(&data->lock);
-
-	return ret;
-}
-
-static int ak09911_read_raw(struct iio_dev *indio_dev,
-			    struct iio_chan_spec const *chan,
-			    int *val, int *val2,
-			    long mask)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		return ak09911_read_axis(indio_dev, chan->address, val);
-	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = data->raw_to_gauss[chan->address];
-		return IIO_VAL_INT_PLUS_MICRO;
-	}
-
-	return -EINVAL;
-}
-
-#define AK09911_CHANNEL(axis, index)					\
-	{								\
-		.type = IIO_MAGN,					\
-		.modified = 1,						\
-		.channel2 = IIO_MOD_##axis,				\
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
-			     BIT(IIO_CHAN_INFO_SCALE),			\
-		.address = index,					\
-	}
-
-static const struct iio_chan_spec ak09911_channels[] = {
-	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
-};
-
-static const struct iio_info ak09911_info = {
-	.read_raw = &ak09911_read_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct acpi_device_id ak_acpi_match[] = {
-	{"AK009911", 0},
-	{ },
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
-static int ak09911_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	struct iio_dev *indio_dev;
-	struct ak09911_data *data;
-	const char *name;
-	int ret;
-
-	ret = ak09911_verify_chip_id(client);
-	if (ret) {
-		dev_err(&client->dev, "AK00911 not detected\n");
-		return -ENODEV;
-	}
-
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
-	if (indio_dev == NULL)
-		return -ENOMEM;
-
-	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-
-	data->client = client;
-	mutex_init(&data->lock);
-
-	ret = ak09911_get_asa(client);
-	if (ret)
-		return ret;
-
-	if (id)
-		name = id->name;
-	else if (ACPI_HANDLE(&client->dev))
-		name = dev_name(&client->dev);
-	else
-		return -ENODEV;
-
-	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
-
-	indio_dev->dev.parent = &client->dev;
-	indio_dev->channels = ak09911_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
-	indio_dev->info = &ak09911_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->name = name;
-
-	return devm_iio_device_register(&client->dev, indio_dev);
-}
-
-static const struct i2c_device_id ak09911_id[] = {
-	{"ak09911", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, ak09911_id);
-
-static struct i2c_driver ak09911_driver = {
-	.driver = {
-		.name	= "ak09911",
-		.acpi_match_table = ACPI_PTR(ak_acpi_match),
-	},
-	.probe		= ak09911_probe,
-	.id_table	= ak09911_id,
-};
-module_i2c_driver(ak09911_driver);
-
-MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("AK09911 Compass driver");
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index b170654..f8c7046 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -81,6 +81,58 @@
 #define AK8975_MAX_REGS			AK8975_REG_ASAZ
 
 /*
+ * AK09912 Register definitions
+ */
+#define AK09912_REG_WIA1		0x00
+#define AK09912_REG_WIA2		0x01
+#define AK09912_DEVICE_ID		0x04
+#define AK09911_DEVICE_ID		0x05
+
+#define AK09911_REG_INFO1		0x02
+#define AK09911_REG_INFO2		0x03
+
+#define AK09912_REG_ST1			0x10
+
+#define AK09912_REG_ST1_DRDY_SHIFT	0
+#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
+
+#define AK09912_REG_HXL			0x11
+#define AK09912_REG_HXH			0x12
+#define AK09912_REG_HYL			0x13
+#define AK09912_REG_HYH			0x14
+#define AK09912_REG_HZL			0x15
+#define AK09912_REG_HZH			0x16
+#define AK09912_REG_TMPS		0x17
+
+#define AK09912_REG_ST2			0x18
+#define AK09912_REG_ST2_HOFL_SHIFT	3
+#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
+
+#define AK09912_REG_CNTL1		0x30
+
+#define AK09912_REG_CNTL2		0x31
+#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK09912_REG_CNTL_MODE_ONCE	0x01
+#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
+#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
+#define AK09912_REG_CNTL2_MODE_SHIFT	0
+#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
+
+#define AK09912_REG_CNTL3		0x32
+
+#define AK09912_REG_TS1			0x33
+#define AK09912_REG_TS2			0x34
+#define AK09912_REG_TS3			0x35
+#define AK09912_REG_I2CDIS		0x36
+#define AK09912_REG_TS4			0x37
+
+#define AK09912_REG_ASAX		0x60
+#define AK09912_REG_ASAY		0x61
+#define AK09912_REG_ASAZ		0x62
+
+#define AK09912_MAX_REGS		AK09912_REG_ASAZ
+
+/*
  * Miscellaneous values.
  */
 #define AK8975_MAX_CONVERSION_TIMEOUT	500
@@ -130,22 +182,37 @@ long ak8975_raw_to_gauss(u16 data)
 }
 
 /*
- * For AK8963, same calculation, but the device is less sensitive:
+ * For AK8963 and AK09911, same calculation, but the device is less sensitive:
  *
  * H is in the range of +-8190.  The magnetometer has a range of
  * +-4912uT.  To go from the raw value to uT is:
  *
  * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
  */
-long ak8963_raw_to_gauss(u16 data)
+long ak8963_09911_raw_to_gauss(u16 data)
 {
 	return (((long)data + 128) * 6000) / 256;
 }
 
+/*
+ * For AK09912, same calculation, except the device is more sensitive:
+ *
+ * H is in the range of -32752 to 32752.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
+ */
+long ak09912_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 1500) / 256;
+}
+
 /* Compatible Asahi Kasei Compass parts */
 enum asahi_compass_chipset {
 	AK8975,
 	AK8963,
+	AK09911,
+	AK09912,
 	AK_MAX_TYPE
 };
 
@@ -210,7 +277,7 @@ struct ak_def {
 },
 {
 	.type = AK8963,
-	.raw_to_gauss = ak8963_raw_to_gauss,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
 	.range = 8190,
 	.ctrl_regs = {
 		AK8975_REG_ST1,
@@ -233,6 +300,56 @@ struct ak_def {
 		AK8975_REG_HYL,
 		AK8975_REG_HZL},
 },
+{
+	.type = AK09911,
+	.raw_to_gauss = ak8963_09911_raw_to_gauss,
+	.range = 8192,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+},
+{
+	.type = AK09912,
+	.raw_to_gauss = ak09912_raw_to_gauss,
+	.range = 32752,
+	.ctrl_regs = {
+		AK09912_REG_ST1,
+		AK09912_REG_ST2,
+		AK09912_REG_CNTL2,
+		AK09912_REG_ASAX,
+		AK09912_MAX_REGS},
+	.ctrl_masks = {
+		AK09912_REG_ST1_DRDY_MASK,
+		AK09912_REG_ST2_HOFL_MASK,
+		0,
+		AK09912_REG_CNTL2_MODE_MASK},
+	.ctrl_modes = {
+		AK09912_REG_CNTL_MODE_POWER_DOWN,
+		AK09912_REG_CNTL_MODE_ONCE,
+		AK09912_REG_CNTL_MODE_SELF_TEST,
+		AK09912_REG_CNTL_MODE_FUSE_ROM},
+	.data_regs = {
+		AK09912_REG_HXL,
+		AK09912_REG_HYL,
+		AK09912_REG_HZL},
+}
 };
 
 /*
@@ -253,6 +370,55 @@ struct ak8975_data {
 };
 
 /*
+ * Return 0 if the i2c device is the one we expect.
+ * return a negative error number otherwise
+ */
+static int ak8975_who_i_am(struct i2c_client *client,
+			   enum asahi_compass_chipset type)
+{
+	u8 wia_val[2];
+	int ret;
+
+	/*
+	 * Signature for each device:
+	 * Device   |  WIA1      |  WIA2
+	 * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
+	 * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
+	 * AK8975   |  DEVICE_ID |  NA
+	 * AK8963   |  DEVICE_ID |  NA
+	 */
+	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
+					    2, wia_val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return ret;
+	}
+
+	ret = -ENODEV;
+
+	if (wia_val[0] != AK8975_DEVICE_ID)
+		return ret;
+
+	switch (type) {
+	case AK8975:
+	case AK8963:
+		ret = 0;
+		break;
+	case AK09911:
+		if (wia_val[1] == AK09911_DEVICE_ID)
+			ret = 0;
+		break;
+	case AK09912:
+		if (wia_val[1] == AK09912_DEVICE_ID)
+			ret = 0;
+		break;
+	default:
+		dev_err(&client->dev, "Type %d unknown\n", type);
+	}
+	return ret;
+}
+
+/*
  * Helper function to write to CNTL register.
  */
 static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
@@ -327,21 +493,8 @@ static int ak8975_setup(struct i2c_client *client)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct ak8975_data *data = iio_priv(indio_dev);
-	u8 device_id;
 	int ret;
 
-	/* Confirm that the device we're talking to is really an AK8975. */
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-	device_id = ret;
-	if (device_id != AK8975_DEVICE_ID) {
-		dev_err(&client->dev, "Device ak8975 not found\n");
-		return -ENODEV;
-	}
-
 	/* Write the fused rom access mode. */
 	ret = ak8975_set_mode(data, FUSE_ROM);
 	if (ret < 0) {
@@ -552,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
 	{"AK8975", AK8975},
 	{"AK8963", AK8963},
 	{"INVN6500", AK8963},
+	{"AK09911", AK09911},
+	{"AK09912", AK09912},
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
@@ -631,6 +786,10 @@ static int ak8975_probe(struct i2c_client *client,
 	}
 
 	data->def = &ak_def_array[chipset];
+	if (ak8975_who_i_am(client, data->def->type) < 0) {
+		dev_err(&client->dev, "Unexpected device\n");
+		return -ENODEV;
+	}
 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 
 	/* Perform some basic start-of-day setup of the device. */
@@ -653,6 +812,8 @@ static int ak8975_probe(struct i2c_client *client,
 static const struct i2c_device_id ak8975_id[] = {
 	{"ak8975", AK8975},
 	{"ak8963", AK8963},
+	{"ak09911", AK09911},
+	{"ak09912", AK09912},
 	{}
 };
 
@@ -663,6 +824,10 @@ static const struct of_device_id ak8975_of_match[] = {
 	{ .compatible = "ak8975", },
 	{ .compatible = "asahi-kasei,ak8963", },
 	{ .compatible = "ak8963", },
+	{ .compatible = "asahi-kasei,ak09911", },
+	{ .compatible = "ak09911", },
+	{ .compatible = "asahi-kasei,ak09912", },
+	{ .compatible = "ak09912", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, ak8975_of_match);
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-06 15:05               ` Srinivas Pandruvada
  2014-11-06 21:25                 ` Gwendal Grignou
@ 2014-11-08 12:16                 ` Jonathan Cameron
  2014-11-14  9:01                   ` Gwendal Grignou
  1 sibling, 1 reply; 28+ messages in thread
From: Jonathan Cameron @ 2014-11-08 12:16 UTC (permalink / raw)
  To: Srinivas Pandruvada, Gwendal Grignou; +Cc: knaack.h, linux-iio

On 06/11/14 15:05, Srinivas Pandruvada wrote:
> On Wed, 2014-11-05 at 14:10 -0800, Gwendal Grignou wrote:
>> Add 2 new definition entries to support ak0991x compass.
>> Add a more advanced function to check we are dealy with the
>> expected device.
> This commit message doesn't state that you are removing ak09911 driver.
> Although you added in cover letter, but that will not be present in the
> history.
> 
>>
>> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
>> ---
>>  drivers/iio/magnetometer/Kconfig   |  17 +-
>>  drivers/iio/magnetometer/Makefile  |   1 -
>>  drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
>>  drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
>>  4 files changed, 184 insertions(+), 357 deletions(-)
>>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
>>
>> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
>> index b2dba9e..cd8750b 100644
>> --- a/drivers/iio/magnetometer/Kconfig
>> +++ b/drivers/iio/magnetometer/Kconfig
>> @@ -6,27 +6,16 @@
>>  menu "Magnetometer sensors"
>>  
>>  config AK8975
>> -	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
>> +	tristate "Asahi Kasei AK 3-Axis Magnetometer"
>>  	depends on I2C
>>  	depends on GPIOLIB
>>  	help
>> -	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
>> -	  Magnetometer. This driver can also support AK8963, if i2c
>> -	  device name is identified as ak8963.
>> +	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
>> +	  AK09911 or AK09912 3-Axis Magnetometer.
>>  
>>  	  To compile this driver as a module, choose M here: the module
>>  	  will be called ak8975.
>>  
>> -config AK09911
> Instead
> config AK09911
> 	select AK8975
> 
> I stated my reason below.
Agreed.  This will reduce breakage and is common when merging drivers.

>> -	tristate "Asahi Kasei AK09911 3-axis Compass"
>> -	depends on I2C
>> -	help
>> -	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
>> -	  Magnetometer.
>> -
>> -	  To compile this driver as a module, choose M here: the module
>> -	  will be called ak09911.
>> -

> 
> I need to test this driver.
> Jonathan,
> If possible, wait for Tested by tag from me or someone else.
Will do.
> 
> Thanks,
> Srinivas
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCHv2] iio: ak8975: Add AKM0991x support.
  2014-11-06 14:32           ` [PATCHv2] iio: ak8975: Add AKM0991x support Srinivas Pandruvada
@ 2014-11-08 12:17             ` Jonathan Cameron
  0 siblings, 0 replies; 28+ messages in thread
From: Jonathan Cameron @ 2014-11-08 12:17 UTC (permalink / raw)
  To: Srinivas Pandruvada, Gwendal Grignou; +Cc: Gwendal Grignou, knaack.h, linux-iio

On 06/11/14 14:32, Srinivas Pandruvada wrote:
> On Wed, 2014-11-05 at 13:19 -0800, Gwendal Grignou wrote:
>> On Wed, Nov 5, 2014 at 6:31 AM, Jonathan Cameron <jic23@kernel.org> wrote:
>>> On 04/11/14 19:41, Gwendal Grignou wrote:
>>>> File and config id remains the same, but driver is now named akxxxx.
>>>
>>> Don't do that.  Please name the driver after one supported part rather
>>> than a general wild card.  Leaving it as ak8975 would be sensible.
>>> Wild cards seem like a good idea until along comes a part that fits
>>> in the naming scheme but is otherwise totally different.
>>>
>>> Much cleaner to just pick a part to use in naming the driver and
>>> make it clear what parts are supported in kconfig (see iio/adc/max1363 for
>>> example).
>> Will do. It is cleaner indeed.
>>>
>>> I would have prefered this as a two patch series.  The first combining
>>> the existing drivers, and the second (small one) adding the new part
>>> support.
>> I will submit 3 patches soon:
>> - minor fixes in the driver first,
>> - one that refactor the current driver to introduce a definition data structure
>> - the next one that remove ak9911.c and add support for ak09911 and
>> ak9912 into ak8975.c
>>>
>>> Would have broken it up into logical steps thus making it a little
>>> easier to check for feature parity etc.
>>>
>>> Once you've dropped the name change, this patch will contain less noise.
>>> Also, there are a couple of sensible refactorings in there.  I would
>>> have prefered these to be in precursor patches that made much smaller
>>> changes.
>> The re-factoring became obvious after I introduce the definition data structure.
>>>
>>> This sort of merging of drivers is one of the hardest types of code to
>>> review, so making it as easy as possible for reviewers by packaging
>>> it up as baby steps is the way to go.
>>>
>>> There is still some work to be done in convincing people that merging
>>> the drivers is sensible (I'm pretty much convinced having waded through
>>> this) but that is an easier job with a well split up series of steps!
>>>
>>> Jonathan
>>>
>>>> Move AKM09911 support in the same file.
>>>>
>>>> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
>>>> ---
>>>>
>>>> Addressed all comments from Hartmut.
>>>>
>>>>  drivers/iio/magnetometer/Kconfig   |  19 +-
>>>>  drivers/iio/magnetometer/Makefile  |   1 -
>>>>  drivers/iio/magnetometer/ak09911.c | 326 -------------------
>>>>  drivers/iio/magnetometer/ak8975.c  | 629 ++++++++++++++++++++++++++-----------
>>>>  4 files changed, 444 insertions(+), 531 deletions(-)
>>>>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
>>>>
>>>> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
>>>> index b2dba9e..67f005d 100644
>>>> --- a/drivers/iio/magnetometer/Kconfig
>>>> +++ b/drivers/iio/magnetometer/Kconfig
>>>> @@ -6,26 +6,15 @@
>>>>  menu "Magnetometer sensors"
>>>>
>>>>  config AK8975
>>>> -     tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
>>>> +     tristate "Asahi Kasei AK 3-Axis Magnetometer"
>>>>       depends on I2C
>>>>       depends on GPIOLIB
>>>>       help
>>>> -       Say yes here to build support for Asahi Kasei AK8975 3-Axis
>>>> -       Magnetometer. This driver can also support AK8963, if i2c
>>>> -       device name is identified as ak8963.
>>>> +       Say yes here to build support for Asahi Kasei AK8975, AK8963,
>>>> +       AK09911 or AK09912 3-Axis Magnetometer.
>>>>
>>>>         To compile this driver as a module, choose M here: the module
>>>> -       will be called ak8975.
>>>> -
>>>> -config AK09911
>>>> -     tristate "Asahi Kasei AK09911 3-axis Compass"
>>>> -     depends on I2C
>>>> -     help
>>>> -       Say yes here to build support for Asahi Kasei AK09911 3-Axis
>>>> -       Magnetometer.
>>>> -
>>>> -       To compile this driver as a module, choose M here: the module
>>>> -       will be called ak09911.
>>>> +       will be called akxxxx.
>>>>
> We already have released products with CONFIG_AK09911, so will next
> kernel upgrade will break them. Customers don't allow config changes.
> So we can't remove this config.
> Merging of drivers is fine. At the least we should keep the config and
> select the AK8975 when defined in the config if we remove AK09911.
> 
> Jonathan,
> What do you think? This driver is part of a commercial released product.
> As you know customers are very sensitive about .config changes.
Absolutely.  When merging drivers putting in some config magic
to select the new driver is a common solution.

> 
> Thanks,
> Srinivas
> 



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-08 12:16                 ` Jonathan Cameron
@ 2014-11-14  9:01                   ` Gwendal Grignou
  0 siblings, 0 replies; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-14  9:01 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Srinivas Pandruvada, Gwendal Grignou, knaack.h, linux-iio

On Sat, Nov 8, 2014 at 4:16 AM, Jonathan Cameron <jic23@kernel.org> wrote:
>
> On 06/11/14 15:05, Srinivas Pandruvada wrote:
> > On Wed, 2014-11-05 at 14:10 -0800, Gwendal Grignou wrote:
> >> Add 2 new definition entries to support ak0991x compass.
> >> Add a more advanced function to check we are dealy with the
> >> expected device.
> > This commit message doesn't state that you are removing ak09911 driver.
> > Although you added in cover letter, but that will not be present in the
> > history.
> >
> >>
> >> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> >> ---
> >>  drivers/iio/magnetometer/Kconfig   |  17 +-
> >>  drivers/iio/magnetometer/Makefile  |   1 -
> >>  drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
> >>  drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
> >>  4 files changed, 184 insertions(+), 357 deletions(-)
> >>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
> >>
> >> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> >> index b2dba9e..cd8750b 100644
> >> --- a/drivers/iio/magnetometer/Kconfig
> >> +++ b/drivers/iio/magnetometer/Kconfig
> >> @@ -6,27 +6,16 @@
> >>  menu "Magnetometer sensors"
> >>
> >>  config AK8975
> >> -    tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> >> +    tristate "Asahi Kasei AK 3-Axis Magnetometer"
> >>      depends on I2C
> >>      depends on GPIOLIB
> >>      help
> >> -      Say yes here to build support for Asahi Kasei AK8975 3-Axis
> >> -      Magnetometer. This driver can also support AK8963, if i2c
> >> -      device name is identified as ak8963.
> >> +      Say yes here to build support for Asahi Kasei AK8975, AK8963,
> >> +      AK09911 or AK09912 3-Axis Magnetometer.
> >>
> >>        To compile this driver as a module, choose M here: the module
> >>        will be called ak8975.
> >>
> >> -config AK09911
> > Instead
> > config AK09911
> >       select AK8975
> >
> > I stated my reason below.
> Agreed.  This will reduce breakage and is common when merging drivers.
>
> >> -    tristate "Asahi Kasei AK09911 3-axis Compass"
> >> -    depends on I2C
> >> -    help
> >> -      Say yes here to build support for Asahi Kasei AK09911 3-Axis
> >> -      Magnetometer.
> >> -
> >> -      To compile this driver as a module, choose M here: the module
> >> -      will be called ak09911.
> >> -
>
> >
> > I need to test this driver.
> > Jonathan,
> > If possible, wait for Tested by tag from me or someone else.
> Will do.
Srinivas,

Did you have a chance to test these CLs? Let me know if you find any problem.
On my side, the changes work fine with an ak09912.
Thanks,

Gwendal.
> >
> > Thanks,
> > Srinivas
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-06 21:25                 ` Gwendal Grignou
@ 2014-11-17 18:02                   ` Srinivas Pandruvada
  2014-11-17 20:15                     ` Gwendal Grignou
  2014-11-19 11:39                   ` Hartmut Knaack
  1 sibling, 1 reply; 28+ messages in thread
From: Srinivas Pandruvada @ 2014-11-17 18:02 UTC (permalink / raw)
  To: Gwendal Grignou; +Cc: jic23, knaack.h, linux-iio

On Thu, 2014-11-06 at 13:25 -0800, Gwendal Grignou wrote: 
> Add 2 new definition entries to support ak0991x compass.
> Add a more advanced function to check we are dealing with the
> expected device.
> Remove standalone driver for ak09911.
> 

Since there is no interrupt for AK09911, the client->irq is initialized
to -1 by acpi-i2c.
static int ak8975_setup(struct i2c_client *client)
{
..
if (data->eoc_gpio > 0 || client->irq) {

change to

if (data->eoc_gpio > 0 || client->irq > 0) {

If you do this change, the modified driver works fine.

Thanks,
Srinivas



> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>  Readded CONFIG_AK09911 to ease transition from standalone driver.
> 
>  drivers/iio/magnetometer/Kconfig   |  15 +-
>  drivers/iio/magnetometer/Makefile  |   1 -
>  drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
>  drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
>  4 files changed, 186 insertions(+), 353 deletions(-)
>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
> 
> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> index b2dba9e..4c7a4c5 100644
> --- a/drivers/iio/magnetometer/Kconfig
> +++ b/drivers/iio/magnetometer/Kconfig
> @@ -6,26 +6,21 @@
>  menu "Magnetometer sensors"
>  
>  config AK8975
> -	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> +	tristate "Asahi Kasei AK 3-Axis Magnetometer"
>  	depends on I2C
>  	depends on GPIOLIB
>  	help
> -	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
> -	  Magnetometer. This driver can also support AK8963, if i2c
> -	  device name is identified as ak8963.
> +	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
> +	  AK09911 or AK09912 3-Axis Magnetometer.
>  
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called ak8975.
>  
>  config AK09911
>  	tristate "Asahi Kasei AK09911 3-axis Compass"
> -	depends on I2C
> +	select AK8975
>  	help
> -	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
> -	  Magnetometer.
> -
> -	  To compile this driver as a module, choose M here: the module
> -	  will be called ak09911.
> +	  Deprecated: AK09911 is now supported by AK8975 driver.
>  
>  config MAG3110
>  	tristate "Freescale MAG3110 3-Axis Magnetometer"
> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
> index b91315e..0f5d3c9 100644
> --- a/drivers/iio/magnetometer/Makefile
> +++ b/drivers/iio/magnetometer/Makefile
> @@ -3,7 +3,6 @@
>  #
>  
>  # When adding new entries keep the list in alphabetical order
> -obj-$(CONFIG_AK09911)	+= ak09911.o
>  obj-$(CONFIG_AK8975)	+= ak8975.o
>  obj-$(CONFIG_MAG3110)	+= mag3110.o
>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
> deleted file mode 100644
> index b2bc942..0000000
> --- a/drivers/iio/magnetometer/ak09911.c
> +++ /dev/null
> @@ -1,326 +0,0 @@
> -/*
> - * AK09911 3-axis compass driver
> - * Copyright (c) 2014, 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.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/types.h>
> -#include <linux/slab.h>
> -#include <linux/delay.h>
> -#include <linux/i2c.h>
> -#include <linux/acpi.h>
> -#include <linux/iio/iio.h>
> -
> -#define AK09911_REG_WIA1		0x00
> -#define AK09911_REG_WIA2		0x01
> -#define AK09911_WIA1_VALUE		0x48
> -#define AK09911_WIA2_VALUE		0x05
> -
> -#define AK09911_REG_ST1			0x10
> -#define AK09911_REG_HXL			0x11
> -#define AK09911_REG_HXH			0x12
> -#define AK09911_REG_HYL			0x13
> -#define AK09911_REG_HYH			0x14
> -#define AK09911_REG_HZL			0x15
> -#define AK09911_REG_HZH			0x16
> -
> -#define AK09911_REG_ASAX		0x60
> -#define AK09911_REG_ASAY		0x61
> -#define AK09911_REG_ASAZ		0x62
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_MODE_SNG_MEASURE	0x01
> -#define AK09911_MODE_SELF_TEST		0x10
> -#define AK09911_MODE_FUSE_ACCESS	0x1F
> -#define AK09911_MODE_POWERDOWN		0x00
> -#define AK09911_RESET_DATA		0x01
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
> -
> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
> -
> -struct ak09911_data {
> -	struct i2c_client	*client;
> -	struct mutex		lock;
> -	u8			asa[3];
> -	long			raw_to_gauss[3];
> -};
> -
> -static const int ak09911_index_to_reg[] = {
> -	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
> -};
> -
> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
> -{
> -	int ret;
> -
> -	switch (mode) {
> -	case AK09911_MODE_SNG_MEASURE:
> -	case AK09911_MODE_SELF_TEST:
> -	case AK09911_MODE_FUSE_ACCESS:
> -	case AK09911_MODE_POWERDOWN:
> -		ret = i2c_smbus_write_byte_data(client,
> -						AK09911_REG_CNTL2, mode);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "set_mode error\n");
> -			return ret;
> -		}
> -		/* After mode change wait atleast 100us */
> -		usleep_range(100, 500);
> -		break;
> -	default:
> -		dev_err(&client->dev,
> -			"%s: Unknown mode(%d).", __func__, mode);
> -		return -EINVAL;
> -	}
> -
> -	return ret;
> -}
> -
> -/* Get Sensitivity Adjustment value */
> -static int ak09911_get_asa(struct i2c_client *client)
> -{
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	int ret;
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
> -	if (ret < 0)
> -		return ret;
> -
> -	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
> -					    3, data->asa);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Not able to read asa data\n");
> -		return ret;
> -	}
> -
> -	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
> -	if (ret < 0)
> -		return ret;
> -
> -	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
> -	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
> -	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
> -
> -	return 0;
> -}
> -
> -static int ak09911_verify_chip_id(struct i2c_client *client)
> -{
> -	u8 wia_val[2];
> -	int ret;
> -
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
> -					    2, wia_val);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -
> -	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
> -
> -	if (wia_val[0] != AK09911_WIA1_VALUE ||
> -		wia_val[1] != AK09911_WIA2_VALUE) {
> -		dev_err(&client->dev, "Device ak09911 not found\n");
> -		return -ENODEV;
> -	}
> -
> -	return 0;
> -}
> -
> -static int wait_conversion_complete_polled(struct ak09911_data *data)
> -{
> -	struct i2c_client *client = data->client;
> -	u8 read_status;
> -	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
> -	int ret;
> -
> -	/* Wait for the conversion to complete. */
> -	while (timeout_ms) {
> -		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
> -		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "Error in reading ST1\n");
> -			return ret;
> -		}
> -		read_status = ret & 0x01;
> -		if (read_status)
> -			break;
> -		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
> -	}
> -	if (!timeout_ms) {
> -		dev_err(&client->dev, "Conversion timeout happened\n");
> -		return -EIO;
> -	}
> -
> -	return read_status;
> -}
> -
> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	struct i2c_client *client = data->client;
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	ret = wait_conversion_complete_polled(data);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	/* Read data */
> -	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Read axis data fails\n");
> -		goto fn_exit;
> -	}
> -
> -	mutex_unlock(&data->lock);
> -
> -	/* Clamp to valid range. */
> -	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
> -
> -	return IIO_VAL_INT;
> -
> -fn_exit:
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static int ak09911_read_raw(struct iio_dev *indio_dev,
> -			    struct iio_chan_spec const *chan,
> -			    int *val, int *val2,
> -			    long mask)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -
> -	switch (mask) {
> -	case IIO_CHAN_INFO_RAW:
> -		return ak09911_read_axis(indio_dev, chan->address, val);
> -	case IIO_CHAN_INFO_SCALE:
> -		*val = 0;
> -		*val2 = data->raw_to_gauss[chan->address];
> -		return IIO_VAL_INT_PLUS_MICRO;
> -	}
> -
> -	return -EINVAL;
> -}
> -
> -#define AK09911_CHANNEL(axis, index)					\
> -	{								\
> -		.type = IIO_MAGN,					\
> -		.modified = 1,						\
> -		.channel2 = IIO_MOD_##axis,				\
> -		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
> -			     BIT(IIO_CHAN_INFO_SCALE),			\
> -		.address = index,					\
> -	}
> -
> -static const struct iio_chan_spec ak09911_channels[] = {
> -	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
> -};
> -
> -static const struct iio_info ak09911_info = {
> -	.read_raw = &ak09911_read_raw,
> -	.driver_module = THIS_MODULE,
> -};
> -
> -static const struct acpi_device_id ak_acpi_match[] = {
> -	{"AK009911", 0},
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> -
> -static int ak09911_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> -{
> -	struct iio_dev *indio_dev;
> -	struct ak09911_data *data;
> -	const char *name;
> -	int ret;
> -
> -	ret = ak09911_verify_chip_id(client);
> -	if (ret) {
> -		dev_err(&client->dev, "AK00911 not detected\n");
> -		return -ENODEV;
> -	}
> -
> -	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> -	if (indio_dev == NULL)
> -		return -ENOMEM;
> -
> -	data = iio_priv(indio_dev);
> -	i2c_set_clientdata(client, indio_dev);
> -
> -	data->client = client;
> -	mutex_init(&data->lock);
> -
> -	ret = ak09911_get_asa(client);
> -	if (ret)
> -		return ret;
> -
> -	if (id)
> -		name = id->name;
> -	else if (ACPI_HANDLE(&client->dev))
> -		name = dev_name(&client->dev);
> -	else
> -		return -ENODEV;
> -
> -	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> -
> -	indio_dev->dev.parent = &client->dev;
> -	indio_dev->channels = ak09911_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
> -	indio_dev->info = &ak09911_info;
> -	indio_dev->modes = INDIO_DIRECT_MODE;
> -	indio_dev->name = name;
> -
> -	return devm_iio_device_register(&client->dev, indio_dev);
> -}
> -
> -static const struct i2c_device_id ak09911_id[] = {
> -	{"ak09911", 0},
> -	{}
> -};
> -
> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
> -
> -static struct i2c_driver ak09911_driver = {
> -	.driver = {
> -		.name	= "ak09911",
> -		.acpi_match_table = ACPI_PTR(ak_acpi_match),
> -	},
> -	.probe		= ak09911_probe,
> -	.id_table	= ak09911_id,
> -};
> -module_i2c_driver(ak09911_driver);
> -
> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
> -MODULE_LICENSE("GPL v2");
> -MODULE_DESCRIPTION("AK09911 Compass driver");
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index b170654..f8c7046 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -81,6 +81,58 @@
>  #define AK8975_MAX_REGS			AK8975_REG_ASAZ
>  
>  /*
> + * AK09912 Register definitions
> + */
> +#define AK09912_REG_WIA1		0x00
> +#define AK09912_REG_WIA2		0x01
> +#define AK09912_DEVICE_ID		0x04
> +#define AK09911_DEVICE_ID		0x05
> +
> +#define AK09911_REG_INFO1		0x02
> +#define AK09911_REG_INFO2		0x03
> +
> +#define AK09912_REG_ST1			0x10
> +
> +#define AK09912_REG_ST1_DRDY_SHIFT	0
> +#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
> +
> +#define AK09912_REG_HXL			0x11
> +#define AK09912_REG_HXH			0x12
> +#define AK09912_REG_HYL			0x13
> +#define AK09912_REG_HYH			0x14
> +#define AK09912_REG_HZL			0x15
> +#define AK09912_REG_HZH			0x16
> +#define AK09912_REG_TMPS		0x17
> +
> +#define AK09912_REG_ST2			0x18
> +#define AK09912_REG_ST2_HOFL_SHIFT	3
> +#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
> +
> +#define AK09912_REG_CNTL1		0x30
> +
> +#define AK09912_REG_CNTL2		0x31
> +#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK09912_REG_CNTL_MODE_ONCE	0x01
> +#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
> +#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
> +#define AK09912_REG_CNTL2_MODE_SHIFT	0
> +#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
> +
> +#define AK09912_REG_CNTL3		0x32
> +
> +#define AK09912_REG_TS1			0x33
> +#define AK09912_REG_TS2			0x34
> +#define AK09912_REG_TS3			0x35
> +#define AK09912_REG_I2CDIS		0x36
> +#define AK09912_REG_TS4			0x37
> +
> +#define AK09912_REG_ASAX		0x60
> +#define AK09912_REG_ASAY		0x61
> +#define AK09912_REG_ASAZ		0x62
> +
> +#define AK09912_MAX_REGS		AK09912_REG_ASAZ
> +
> +/*
>   * Miscellaneous values.
>   */
>  #define AK8975_MAX_CONVERSION_TIMEOUT	500
> @@ -130,22 +182,37 @@ long ak8975_raw_to_gauss(u16 data)
>  }
>  
>  /*
> - * For AK8963, same calculation, but the device is less sensitive:
> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
>   *
>   * H is in the range of +-8190.  The magnetometer has a range of
>   * +-4912uT.  To go from the raw value to uT is:
>   *
>   * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
>   */
> -long ak8963_raw_to_gauss(u16 data)
> +long ak8963_09911_raw_to_gauss(u16 data)
>  {
>  	return (((long)data + 128) * 6000) / 256;
>  }
>  
> +/*
> + * For AK09912, same calculation, except the device is more sensitive:
> + *
> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
> + */
> +long ak09912_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 1500) / 256;
> +}
> +
>  /* Compatible Asahi Kasei Compass parts */
>  enum asahi_compass_chipset {
>  	AK8975,
>  	AK8963,
> +	AK09911,
> +	AK09912,
>  	AK_MAX_TYPE
>  };
>  
> @@ -210,7 +277,7 @@ struct ak_def {
>  },
>  {
>  	.type = AK8963,
> -	.raw_to_gauss = ak8963_raw_to_gauss,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
>  	.range = 8190,
>  	.ctrl_regs = {
>  		AK8975_REG_ST1,
> @@ -233,6 +300,56 @@ struct ak_def {
>  		AK8975_REG_HYL,
>  		AK8975_REG_HZL},
>  },
> +{
> +	.type = AK09911,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
> +	.range = 8192,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +},
> +{
> +	.type = AK09912,
> +	.raw_to_gauss = ak09912_raw_to_gauss,
> +	.range = 32752,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +}
>  };
>  
>  /*
> @@ -253,6 +370,55 @@ struct ak8975_data {
>  };
>  
>  /*
> + * Return 0 if the i2c device is the one we expect.
> + * return a negative error number otherwise
> + */
> +static int ak8975_who_i_am(struct i2c_client *client,
> +			   enum asahi_compass_chipset type)
> +{
> +	u8 wia_val[2];
> +	int ret;
> +
> +	/*
> +	 * Signature for each device:
> +	 * Device   |  WIA1      |  WIA2
> +	 * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
> +	 * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
> +	 * AK8975   |  DEVICE_ID |  NA
> +	 * AK8963   |  DEVICE_ID |  NA
> +	 */
> +	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> +					    2, wia_val);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error reading WIA\n");
> +		return ret;
> +	}
> +
> +	ret = -ENODEV;
> +
> +	if (wia_val[0] != AK8975_DEVICE_ID)
> +		return ret;
> +
> +	switch (type) {
> +	case AK8975:
> +	case AK8963:
> +		ret = 0;
> +		break;
> +	case AK09911:
> +		if (wia_val[1] == AK09911_DEVICE_ID)
> +			ret = 0;
> +		break;
> +	case AK09912:
> +		if (wia_val[1] == AK09912_DEVICE_ID)
> +			ret = 0;
> +		break;
> +	default:
> +		dev_err(&client->dev, "Type %d unknown\n", type);
> +	}
> +	return ret;
> +}
> +
> +/*
>   * Helper function to write to CNTL register.
>   */
>  static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
> @@ -327,21 +493,8 @@ static int ak8975_setup(struct i2c_client *client)
>  {
>  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
>  	struct ak8975_data *data = iio_priv(indio_dev);
> -	u8 device_id;
>  	int ret;
>  
> -	/* Confirm that the device we're talking to is really an AK8975. */
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -	device_id = ret;
> -	if (device_id != AK8975_DEVICE_ID) {
> -		dev_err(&client->dev, "Device ak8975 not found\n");
> -		return -ENODEV;
> -	}
> -
>  	/* Write the fused rom access mode. */
>  	ret = ak8975_set_mode(data, FUSE_ROM);
>  	if (ret < 0) {
> @@ -552,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
>  	{"AK8975", AK8975},
>  	{"AK8963", AK8963},
>  	{"INVN6500", AK8963},
> +	{"AK09911", AK09911},
> +	{"AK09912", AK09912},
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> @@ -631,6 +786,10 @@ static int ak8975_probe(struct i2c_client *client,
>  	}
>  
>  	data->def = &ak_def_array[chipset];
> +	if (ak8975_who_i_am(client, data->def->type) < 0) {
> +		dev_err(&client->dev, "Unexpected device\n");
> +		return -ENODEV;
> +	}
>  	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>  
>  	/* Perform some basic start-of-day setup of the device. */
> @@ -653,6 +812,8 @@ static int ak8975_probe(struct i2c_client *client,
>  static const struct i2c_device_id ak8975_id[] = {
>  	{"ak8975", AK8975},
>  	{"ak8963", AK8963},
> +	{"ak09911", AK09911},
> +	{"ak09912", AK09912},
>  	{}
>  };
>  
> @@ -663,6 +824,10 @@ static const struct of_device_id ak8975_of_match[] = {
>  	{ .compatible = "ak8975", },
>  	{ .compatible = "asahi-kasei,ak8963", },
>  	{ .compatible = "ak8963", },
> +	{ .compatible = "asahi-kasei,ak09911", },
> +	{ .compatible = "ak09911", },
> +	{ .compatible = "asahi-kasei,ak09912", },
> +	{ .compatible = "ak09912", },
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, ak8975_of_match);

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v2 1/3] iio: ak8975: minor fixes
  2014-11-05 22:10             ` [PATCH 1/3] iio: ak8975: minor fixes Gwendal Grignou
  2014-11-06 15:00               ` Srinivas Pandruvada
@ 2014-11-17 20:13               ` Gwendal Grignou
  2014-11-19 11:16                 ` Hartmut Knaack
  1 sibling, 1 reply; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-17 20:13 UTC (permalink / raw)
  To: srinivas.pandruvada, jic23, knaack.h; +Cc: linux-iio, Gwendal Grignou

Fixes code duplication, return of function.
Check client->irq properly when setting up optional irq handler.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---
 Fix client->irq checking, Srinivas found it was not correct on ACPI based
 machine.
 drivers/iio/magnetometer/ak8975.c | 35 ++++++++++++++---------------------
 1 file changed, 14 insertions(+), 21 deletions(-)

diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index bf5ef07..4e69480 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -64,10 +64,10 @@
 #define AK8975_REG_CNTL			0x0A
 #define AK8975_REG_CNTL_MODE_SHIFT	0
 #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
-#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
-#define AK8975_REG_CNTL_MODE_ONCE	1
-#define AK8975_REG_CNTL_MODE_SELF_TEST	8
-#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
+#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK8975_REG_CNTL_MODE_ONCE	0x01
+#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
+#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
 
 #define AK8975_REG_RSVC			0x0B
 #define AK8975_REG_ASTC			0x0C
@@ -166,8 +166,8 @@ static int ak8975_setup_irq(struct ak8975_data *data)
 		irq = gpio_to_irq(data->eoc_gpio);
 
 	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
-			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-			 dev_name(&client->dev), data);
+			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			      dev_name(&client->dev), data);
 	if (rc < 0) {
 		dev_err(&client->dev,
 			"irq %d request failed, (gpio %d): %d\n",
@@ -231,8 +231,12 @@ static int ak8975_setup(struct i2c_client *client)
 				AK8975_REG_CNTL_MODE_POWER_DOWN,
 				AK8975_REG_CNTL_MODE_MASK,
 				AK8975_REG_CNTL_MODE_SHIFT);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error in setting power-down mode\n");
+		return ret;
+	}
 
-	if (data->eoc_gpio > 0 || client->irq) {
+	if (data->eoc_gpio > 0 || client->irq > 0) {
 		ret = ak8975_setup_irq(data);
 		if (ret < 0) {
 			dev_err(&client->dev,
@@ -241,11 +245,6 @@ static int ak8975_setup(struct i2c_client *client)
 		}
 	}
 
-	if (ret < 0) {
-		dev_err(&client->dev, "Error in setting power-down mode\n");
-		return ret;
-	}
-
 /*
  * Precalculate scale factor (in Gauss units) for each axis and
  * store in the device data.
@@ -550,24 +549,18 @@ static int ak8975_probe(struct i2c_client *client,
 	/* Perform some basic start-of-day setup of the device. */
 	err = ak8975_setup(client);
 	if (err < 0) {
-		dev_err(&client->dev, "AK8975 initialization fails\n");
+		dev_err(&client->dev, "%s initialization fails\n", name);
 		return err;
 	}
 
-	data->client = client;
 	mutex_init(&data->lock);
-	data->eoc_gpio = eoc_gpio;
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->channels = ak8975_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
 	indio_dev->info = &ak8975_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = name;
-	err = devm_iio_device_register(&client->dev, indio_dev);
-	if (err < 0)
-		return err;
-
-	return 0;
+	return devm_iio_device_register(&client->dev, indio_dev);
 }
 
 static const struct i2c_device_id ak8975_id[] = {
@@ -588,7 +581,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match);
 static struct i2c_driver ak8975_driver = {
 	.driver = {
 		.name	= "ak8975",
-		.of_match_table = ak8975_of_match,
+		.of_match_table = of_match_ptr(ak8975_of_match),
 		.acpi_match_table = ACPI_PTR(ak_acpi_match),
 	},
 	.probe		= ak8975_probe,
-- 
2.1.0.rc2.206.gedb03e5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-17 18:02                   ` Srinivas Pandruvada
@ 2014-11-17 20:15                     ` Gwendal Grignou
  2014-11-17 20:36                       ` Srinivas Pandruvada
  0 siblings, 1 reply; 28+ messages in thread
From: Gwendal Grignou @ 2014-11-17 20:15 UTC (permalink / raw)
  To: Srinivas Pandruvada; +Cc: Gwendal Grignou, jic23, knaack.h, linux-iio

Thanks Srinivas. I fixed the issue in the first patch, called "[PATCH
v2 1/3] iio: ak8975: minor fixes".

Gwendal.

On Mon, Nov 17, 2014 at 10:02 AM, Srinivas Pandruvada
<srinivas.pandruvada@linux.intel.com> wrote:
> On Thu, 2014-11-06 at 13:25 -0800, Gwendal Grignou wrote:
>> Add 2 new definition entries to support ak0991x compass.
>> Add a more advanced function to check we are dealing with the
>> expected device.
>> Remove standalone driver for ak09911.
>>
>
> Since there is no interrupt for AK09911, the client->irq is initialized
> to -1 by acpi-i2c.
> static int ak8975_setup(struct i2c_client *client)
> {
> ..
> if (data->eoc_gpio > 0 || client->irq) {
>
> change to
>
> if (data->eoc_gpio > 0 || client->irq > 0) {
>
> If you do this change, the modified driver works fine.
>
> Thanks,
> Srinivas
>
>
>
>> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
>> ---
>>  Readded CONFIG_AK09911 to ease transition from standalone driver.
>>
>>  drivers/iio/magnetometer/Kconfig   |  15 +-
>>  drivers/iio/magnetometer/Makefile  |   1 -
>>  drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
>>  drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
>>  4 files changed, 186 insertions(+), 353 deletions(-)
>>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
>>
>> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
>> index b2dba9e..4c7a4c5 100644
>> --- a/drivers/iio/magnetometer/Kconfig
>> +++ b/drivers/iio/magnetometer/Kconfig
>> @@ -6,26 +6,21 @@
>>  menu "Magnetometer sensors"
>>
>>  config AK8975
>> -     tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
>> +     tristate "Asahi Kasei AK 3-Axis Magnetometer"
>>       depends on I2C
>>       depends on GPIOLIB
>>       help
>> -       Say yes here to build support for Asahi Kasei AK8975 3-Axis
>> -       Magnetometer. This driver can also support AK8963, if i2c
>> -       device name is identified as ak8963.
>> +       Say yes here to build support for Asahi Kasei AK8975, AK8963,
>> +       AK09911 or AK09912 3-Axis Magnetometer.
>>
>>         To compile this driver as a module, choose M here: the module
>>         will be called ak8975.
>>
>>  config AK09911
>>       tristate "Asahi Kasei AK09911 3-axis Compass"
>> -     depends on I2C
>> +     select AK8975
>>       help
>> -       Say yes here to build support for Asahi Kasei AK09911 3-Axis
>> -       Magnetometer.
>> -
>> -       To compile this driver as a module, choose M here: the module
>> -       will be called ak09911.
>> +       Deprecated: AK09911 is now supported by AK8975 driver.
>>
>>  config MAG3110
>>       tristate "Freescale MAG3110 3-Axis Magnetometer"
>> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
>> index b91315e..0f5d3c9 100644
>> --- a/drivers/iio/magnetometer/Makefile
>> +++ b/drivers/iio/magnetometer/Makefile
>> @@ -3,7 +3,6 @@
>>  #
>>
>>  # When adding new entries keep the list in alphabetical order
>> -obj-$(CONFIG_AK09911)        += ak09911.o
>>  obj-$(CONFIG_AK8975) += ak8975.o
>>  obj-$(CONFIG_MAG3110)        += mag3110.o
>>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
>> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
>> deleted file mode 100644
>> index b2bc942..0000000
>> --- a/drivers/iio/magnetometer/ak09911.c
>> +++ /dev/null
>> @@ -1,326 +0,0 @@
>> -/*
>> - * AK09911 3-axis compass driver
>> - * Copyright (c) 2014, 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.
>> - */
>> -
>> -#include <linux/kernel.h>
>> -#include <linux/module.h>
>> -#include <linux/init.h>
>> -#include <linux/types.h>
>> -#include <linux/slab.h>
>> -#include <linux/delay.h>
>> -#include <linux/i2c.h>
>> -#include <linux/acpi.h>
>> -#include <linux/iio/iio.h>
>> -
>> -#define AK09911_REG_WIA1             0x00
>> -#define AK09911_REG_WIA2             0x01
>> -#define AK09911_WIA1_VALUE           0x48
>> -#define AK09911_WIA2_VALUE           0x05
>> -
>> -#define AK09911_REG_ST1                      0x10
>> -#define AK09911_REG_HXL                      0x11
>> -#define AK09911_REG_HXH                      0x12
>> -#define AK09911_REG_HYL                      0x13
>> -#define AK09911_REG_HYH                      0x14
>> -#define AK09911_REG_HZL                      0x15
>> -#define AK09911_REG_HZH                      0x16
>> -
>> -#define AK09911_REG_ASAX             0x60
>> -#define AK09911_REG_ASAY             0x61
>> -#define AK09911_REG_ASAZ             0x62
>> -
>> -#define AK09911_REG_CNTL1            0x30
>> -#define AK09911_REG_CNTL2            0x31
>> -#define AK09911_REG_CNTL3            0x32
>> -
>> -#define AK09911_MODE_SNG_MEASURE     0x01
>> -#define AK09911_MODE_SELF_TEST               0x10
>> -#define AK09911_MODE_FUSE_ACCESS     0x1F
>> -#define AK09911_MODE_POWERDOWN               0x00
>> -#define AK09911_RESET_DATA           0x01
>> -
>> -#define AK09911_REG_CNTL1            0x30
>> -#define AK09911_REG_CNTL2            0x31
>> -#define AK09911_REG_CNTL3            0x32
>> -
>> -#define AK09911_RAW_TO_GAUSS(asa)    ((((asa) + 128) * 6000) / 256)
>> -
>> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS    500
>> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
>> -
>> -struct ak09911_data {
>> -     struct i2c_client       *client;
>> -     struct mutex            lock;
>> -     u8                      asa[3];
>> -     long                    raw_to_gauss[3];
>> -};
>> -
>> -static const int ak09911_index_to_reg[] = {
>> -     AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
>> -};
>> -
>> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
>> -{
>> -     int ret;
>> -
>> -     switch (mode) {
>> -     case AK09911_MODE_SNG_MEASURE:
>> -     case AK09911_MODE_SELF_TEST:
>> -     case AK09911_MODE_FUSE_ACCESS:
>> -     case AK09911_MODE_POWERDOWN:
>> -             ret = i2c_smbus_write_byte_data(client,
>> -                                             AK09911_REG_CNTL2, mode);
>> -             if (ret < 0) {
>> -                     dev_err(&client->dev, "set_mode error\n");
>> -                     return ret;
>> -             }
>> -             /* After mode change wait atleast 100us */
>> -             usleep_range(100, 500);
>> -             break;
>> -     default:
>> -             dev_err(&client->dev,
>> -                     "%s: Unknown mode(%d).", __func__, mode);
>> -             return -EINVAL;
>> -     }
>> -
>> -     return ret;
>> -}
>> -
>> -/* Get Sensitivity Adjustment value */
>> -static int ak09911_get_asa(struct i2c_client *client)
>> -{
>> -     struct iio_dev *indio_dev = i2c_get_clientdata(client);
>> -     struct ak09911_data *data = iio_priv(indio_dev);
>> -     int ret;
>> -
>> -     ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
>> -     if (ret < 0)
>> -             return ret;
>> -
>> -     /* Get asa data and store in the device data. */
>> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
>> -                                         3, data->asa);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Not able to read asa data\n");
>> -             return ret;
>> -     }
>> -
>> -     ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
>> -     if (ret < 0)
>> -             return ret;
>> -
>> -     data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
>> -     data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
>> -     data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
>> -
>> -     return 0;
>> -}
>> -
>> -static int ak09911_verify_chip_id(struct i2c_client *client)
>> -{
>> -     u8 wia_val[2];
>> -     int ret;
>> -
>> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
>> -                                         2, wia_val);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Error reading WIA\n");
>> -             return ret;
>> -     }
>> -
>> -     dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
>> -
>> -     if (wia_val[0] != AK09911_WIA1_VALUE ||
>> -             wia_val[1] != AK09911_WIA2_VALUE) {
>> -             dev_err(&client->dev, "Device ak09911 not found\n");
>> -             return -ENODEV;
>> -     }
>> -
>> -     return 0;
>> -}
>> -
>> -static int wait_conversion_complete_polled(struct ak09911_data *data)
>> -{
>> -     struct i2c_client *client = data->client;
>> -     u8 read_status;
>> -     u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
>> -     int ret;
>> -
>> -     /* Wait for the conversion to complete. */
>> -     while (timeout_ms) {
>> -             msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
>> -             ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
>> -             if (ret < 0) {
>> -                     dev_err(&client->dev, "Error in reading ST1\n");
>> -                     return ret;
>> -             }
>> -             read_status = ret & 0x01;
>> -             if (read_status)
>> -                     break;
>> -             timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
>> -     }
>> -     if (!timeout_ms) {
>> -             dev_err(&client->dev, "Conversion timeout happened\n");
>> -             return -EIO;
>> -     }
>> -
>> -     return read_status;
>> -}
>> -
>> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
>> -{
>> -     struct ak09911_data *data = iio_priv(indio_dev);
>> -     struct i2c_client *client = data->client;
>> -     int ret;
>> -
>> -     mutex_lock(&data->lock);
>> -
>> -     ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
>> -     if (ret < 0)
>> -             goto fn_exit;
>> -
>> -     ret = wait_conversion_complete_polled(data);
>> -     if (ret < 0)
>> -             goto fn_exit;
>> -
>> -     /* Read data */
>> -     ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Read axis data fails\n");
>> -             goto fn_exit;
>> -     }
>> -
>> -     mutex_unlock(&data->lock);
>> -
>> -     /* Clamp to valid range. */
>> -     *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
>> -
>> -     return IIO_VAL_INT;
>> -
>> -fn_exit:
>> -     mutex_unlock(&data->lock);
>> -
>> -     return ret;
>> -}
>> -
>> -static int ak09911_read_raw(struct iio_dev *indio_dev,
>> -                         struct iio_chan_spec const *chan,
>> -                         int *val, int *val2,
>> -                         long mask)
>> -{
>> -     struct ak09911_data *data = iio_priv(indio_dev);
>> -
>> -     switch (mask) {
>> -     case IIO_CHAN_INFO_RAW:
>> -             return ak09911_read_axis(indio_dev, chan->address, val);
>> -     case IIO_CHAN_INFO_SCALE:
>> -             *val = 0;
>> -             *val2 = data->raw_to_gauss[chan->address];
>> -             return IIO_VAL_INT_PLUS_MICRO;
>> -     }
>> -
>> -     return -EINVAL;
>> -}
>> -
>> -#define AK09911_CHANNEL(axis, index)                                 \
>> -     {                                                               \
>> -             .type = IIO_MAGN,                                       \
>> -             .modified = 1,                                          \
>> -             .channel2 = IIO_MOD_##axis,                             \
>> -             .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
>> -                          BIT(IIO_CHAN_INFO_SCALE),                  \
>> -             .address = index,                                       \
>> -     }
>> -
>> -static const struct iio_chan_spec ak09911_channels[] = {
>> -     AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
>> -};
>> -
>> -static const struct iio_info ak09911_info = {
>> -     .read_raw = &ak09911_read_raw,
>> -     .driver_module = THIS_MODULE,
>> -};
>> -
>> -static const struct acpi_device_id ak_acpi_match[] = {
>> -     {"AK009911", 0},
>> -     { },
>> -};
>> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
>> -
>> -static int ak09911_probe(struct i2c_client *client,
>> -                      const struct i2c_device_id *id)
>> -{
>> -     struct iio_dev *indio_dev;
>> -     struct ak09911_data *data;
>> -     const char *name;
>> -     int ret;
>> -
>> -     ret = ak09911_verify_chip_id(client);
>> -     if (ret) {
>> -             dev_err(&client->dev, "AK00911 not detected\n");
>> -             return -ENODEV;
>> -     }
>> -
>> -     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
>> -     if (indio_dev == NULL)
>> -             return -ENOMEM;
>> -
>> -     data = iio_priv(indio_dev);
>> -     i2c_set_clientdata(client, indio_dev);
>> -
>> -     data->client = client;
>> -     mutex_init(&data->lock);
>> -
>> -     ret = ak09911_get_asa(client);
>> -     if (ret)
>> -             return ret;
>> -
>> -     if (id)
>> -             name = id->name;
>> -     else if (ACPI_HANDLE(&client->dev))
>> -             name = dev_name(&client->dev);
>> -     else
>> -             return -ENODEV;
>> -
>> -     dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>> -
>> -     indio_dev->dev.parent = &client->dev;
>> -     indio_dev->channels = ak09911_channels;
>> -     indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
>> -     indio_dev->info = &ak09911_info;
>> -     indio_dev->modes = INDIO_DIRECT_MODE;
>> -     indio_dev->name = name;
>> -
>> -     return devm_iio_device_register(&client->dev, indio_dev);
>> -}
>> -
>> -static const struct i2c_device_id ak09911_id[] = {
>> -     {"ak09911", 0},
>> -     {}
>> -};
>> -
>> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
>> -
>> -static struct i2c_driver ak09911_driver = {
>> -     .driver = {
>> -             .name   = "ak09911",
>> -             .acpi_match_table = ACPI_PTR(ak_acpi_match),
>> -     },
>> -     .probe          = ak09911_probe,
>> -     .id_table       = ak09911_id,
>> -};
>> -module_i2c_driver(ak09911_driver);
>> -
>> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
>> -MODULE_LICENSE("GPL v2");
>> -MODULE_DESCRIPTION("AK09911 Compass driver");
>> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
>> index b170654..f8c7046 100644
>> --- a/drivers/iio/magnetometer/ak8975.c
>> +++ b/drivers/iio/magnetometer/ak8975.c
>> @@ -81,6 +81,58 @@
>>  #define AK8975_MAX_REGS                      AK8975_REG_ASAZ
>>
>>  /*
>> + * AK09912 Register definitions
>> + */
>> +#define AK09912_REG_WIA1             0x00
>> +#define AK09912_REG_WIA2             0x01
>> +#define AK09912_DEVICE_ID            0x04
>> +#define AK09911_DEVICE_ID            0x05
>> +
>> +#define AK09911_REG_INFO1            0x02
>> +#define AK09911_REG_INFO2            0x03
>> +
>> +#define AK09912_REG_ST1                      0x10
>> +
>> +#define AK09912_REG_ST1_DRDY_SHIFT   0
>> +#define AK09912_REG_ST1_DRDY_MASK    (1 << AK09912_REG_ST1_DRDY_SHIFT)
>> +
>> +#define AK09912_REG_HXL                      0x11
>> +#define AK09912_REG_HXH                      0x12
>> +#define AK09912_REG_HYL                      0x13
>> +#define AK09912_REG_HYH                      0x14
>> +#define AK09912_REG_HZL                      0x15
>> +#define AK09912_REG_HZH                      0x16
>> +#define AK09912_REG_TMPS             0x17
>> +
>> +#define AK09912_REG_ST2                      0x18
>> +#define AK09912_REG_ST2_HOFL_SHIFT   3
>> +#define AK09912_REG_ST2_HOFL_MASK    (1 << AK09912_REG_ST2_HOFL_SHIFT)
>> +
>> +#define AK09912_REG_CNTL1            0x30
>> +
>> +#define AK09912_REG_CNTL2            0x31
>> +#define AK09912_REG_CNTL_MODE_POWER_DOWN     0x00
>> +#define AK09912_REG_CNTL_MODE_ONCE   0x01
>> +#define AK09912_REG_CNTL_MODE_SELF_TEST      0x10
>> +#define AK09912_REG_CNTL_MODE_FUSE_ROM       0x1F
>> +#define AK09912_REG_CNTL2_MODE_SHIFT 0
>> +#define AK09912_REG_CNTL2_MODE_MASK  (0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
>> +
>> +#define AK09912_REG_CNTL3            0x32
>> +
>> +#define AK09912_REG_TS1                      0x33
>> +#define AK09912_REG_TS2                      0x34
>> +#define AK09912_REG_TS3                      0x35
>> +#define AK09912_REG_I2CDIS           0x36
>> +#define AK09912_REG_TS4                      0x37
>> +
>> +#define AK09912_REG_ASAX             0x60
>> +#define AK09912_REG_ASAY             0x61
>> +#define AK09912_REG_ASAZ             0x62
>> +
>> +#define AK09912_MAX_REGS             AK09912_REG_ASAZ
>> +
>> +/*
>>   * Miscellaneous values.
>>   */
>>  #define AK8975_MAX_CONVERSION_TIMEOUT        500
>> @@ -130,22 +182,37 @@ long ak8975_raw_to_gauss(u16 data)
>>  }
>>
>>  /*
>> - * For AK8963, same calculation, but the device is less sensitive:
>> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
>>   *
>>   * H is in the range of +-8190.  The magnetometer has a range of
>>   * +-4912uT.  To go from the raw value to uT is:
>>   *
>>   * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
>>   */
>> -long ak8963_raw_to_gauss(u16 data)
>> +long ak8963_09911_raw_to_gauss(u16 data)
>>  {
>>       return (((long)data + 128) * 6000) / 256;
>>  }
>>
>> +/*
>> + * For AK09912, same calculation, except the device is more sensitive:
>> + *
>> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
>> + * +-4912uT.  To go from the raw value to uT is:
>> + *
>> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
>> + */
>> +long ak09912_raw_to_gauss(u16 data)
>> +{
>> +     return (((long)data + 128) * 1500) / 256;
>> +}
>> +
>>  /* Compatible Asahi Kasei Compass parts */
>>  enum asahi_compass_chipset {
>>       AK8975,
>>       AK8963,
>> +     AK09911,
>> +     AK09912,
>>       AK_MAX_TYPE
>>  };
>>
>> @@ -210,7 +277,7 @@ struct ak_def {
>>  },
>>  {
>>       .type = AK8963,
>> -     .raw_to_gauss = ak8963_raw_to_gauss,
>> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
>>       .range = 8190,
>>       .ctrl_regs = {
>>               AK8975_REG_ST1,
>> @@ -233,6 +300,56 @@ struct ak_def {
>>               AK8975_REG_HYL,
>>               AK8975_REG_HZL},
>>  },
>> +{
>> +     .type = AK09911,
>> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
>> +     .range = 8192,
>> +     .ctrl_regs = {
>> +             AK09912_REG_ST1,
>> +             AK09912_REG_ST2,
>> +             AK09912_REG_CNTL2,
>> +             AK09912_REG_ASAX,
>> +             AK09912_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK09912_REG_ST1_DRDY_MASK,
>> +             AK09912_REG_ST2_HOFL_MASK,
>> +             0,
>> +             AK09912_REG_CNTL2_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
>> +             AK09912_REG_CNTL_MODE_ONCE,
>> +             AK09912_REG_CNTL_MODE_SELF_TEST,
>> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK09912_REG_HXL,
>> +             AK09912_REG_HYL,
>> +             AK09912_REG_HZL},
>> +},
>> +{
>> +     .type = AK09912,
>> +     .raw_to_gauss = ak09912_raw_to_gauss,
>> +     .range = 32752,
>> +     .ctrl_regs = {
>> +             AK09912_REG_ST1,
>> +             AK09912_REG_ST2,
>> +             AK09912_REG_CNTL2,
>> +             AK09912_REG_ASAX,
>> +             AK09912_MAX_REGS},
>> +     .ctrl_masks = {
>> +             AK09912_REG_ST1_DRDY_MASK,
>> +             AK09912_REG_ST2_HOFL_MASK,
>> +             0,
>> +             AK09912_REG_CNTL2_MODE_MASK},
>> +     .ctrl_modes = {
>> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
>> +             AK09912_REG_CNTL_MODE_ONCE,
>> +             AK09912_REG_CNTL_MODE_SELF_TEST,
>> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
>> +     .data_regs = {
>> +             AK09912_REG_HXL,
>> +             AK09912_REG_HYL,
>> +             AK09912_REG_HZL},
>> +}
>>  };
>>
>>  /*
>> @@ -253,6 +370,55 @@ struct ak8975_data {
>>  };
>>
>>  /*
>> + * Return 0 if the i2c device is the one we expect.
>> + * return a negative error number otherwise
>> + */
>> +static int ak8975_who_i_am(struct i2c_client *client,
>> +                        enum asahi_compass_chipset type)
>> +{
>> +     u8 wia_val[2];
>> +     int ret;
>> +
>> +     /*
>> +      * Signature for each device:
>> +      * Device   |  WIA1      |  WIA2
>> +      * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
>> +      * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
>> +      * AK8975   |  DEVICE_ID |  NA
>> +      * AK8963   |  DEVICE_ID |  NA
>> +      */
>> +     ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
>> +                                         2, wia_val);
>> +     if (ret < 0) {
>> +             dev_err(&client->dev, "Error reading WIA\n");
>> +             return ret;
>> +     }
>> +
>> +     ret = -ENODEV;
>> +
>> +     if (wia_val[0] != AK8975_DEVICE_ID)
>> +             return ret;
>> +
>> +     switch (type) {
>> +     case AK8975:
>> +     case AK8963:
>> +             ret = 0;
>> +             break;
>> +     case AK09911:
>> +             if (wia_val[1] == AK09911_DEVICE_ID)
>> +                     ret = 0;
>> +             break;
>> +     case AK09912:
>> +             if (wia_val[1] == AK09912_DEVICE_ID)
>> +                     ret = 0;
>> +             break;
>> +     default:
>> +             dev_err(&client->dev, "Type %d unknown\n", type);
>> +     }
>> +     return ret;
>> +}
>> +
>> +/*
>>   * Helper function to write to CNTL register.
>>   */
>>  static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
>> @@ -327,21 +493,8 @@ static int ak8975_setup(struct i2c_client *client)
>>  {
>>       struct iio_dev *indio_dev = i2c_get_clientdata(client);
>>       struct ak8975_data *data = iio_priv(indio_dev);
>> -     u8 device_id;
>>       int ret;
>>
>> -     /* Confirm that the device we're talking to is really an AK8975. */
>> -     ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
>> -     if (ret < 0) {
>> -             dev_err(&client->dev, "Error reading WIA\n");
>> -             return ret;
>> -     }
>> -     device_id = ret;
>> -     if (device_id != AK8975_DEVICE_ID) {
>> -             dev_err(&client->dev, "Device ak8975 not found\n");
>> -             return -ENODEV;
>> -     }
>> -
>>       /* Write the fused rom access mode. */
>>       ret = ak8975_set_mode(data, FUSE_ROM);
>>       if (ret < 0) {
>> @@ -552,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
>>       {"AK8975", AK8975},
>>       {"AK8963", AK8963},
>>       {"INVN6500", AK8963},
>> +     {"AK09911", AK09911},
>> +     {"AK09912", AK09912},
>>       { },
>>  };
>>  MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
>> @@ -631,6 +786,10 @@ static int ak8975_probe(struct i2c_client *client,
>>       }
>>
>>       data->def = &ak_def_array[chipset];
>> +     if (ak8975_who_i_am(client, data->def->type) < 0) {
>> +             dev_err(&client->dev, "Unexpected device\n");
>> +             return -ENODEV;
>> +     }
>>       dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>>
>>       /* Perform some basic start-of-day setup of the device. */
>> @@ -653,6 +812,8 @@ static int ak8975_probe(struct i2c_client *client,
>>  static const struct i2c_device_id ak8975_id[] = {
>>       {"ak8975", AK8975},
>>       {"ak8963", AK8963},
>> +     {"ak09911", AK09911},
>> +     {"ak09912", AK09912},
>>       {}
>>  };
>>
>> @@ -663,6 +824,10 @@ static const struct of_device_id ak8975_of_match[] = {
>>       { .compatible = "ak8975", },
>>       { .compatible = "asahi-kasei,ak8963", },
>>       { .compatible = "ak8963", },
>> +     { .compatible = "asahi-kasei,ak09911", },
>> +     { .compatible = "ak09911", },
>> +     { .compatible = "asahi-kasei,ak09912", },
>> +     { .compatible = "ak09912", },
>>       {}
>>  };
>>  MODULE_DEVICE_TABLE(of, ak8975_of_match);
>
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-17 20:15                     ` Gwendal Grignou
@ 2014-11-17 20:36                       ` Srinivas Pandruvada
  0 siblings, 0 replies; 28+ messages in thread
From: Srinivas Pandruvada @ 2014-11-17 20:36 UTC (permalink / raw)
  To: Gwendal Grignou; +Cc: jic23, knaack.h, linux-iio

On Mon, 2014-11-17 at 12:15 -0800, Gwendal Grignou wrote: 
> Thanks Srinivas. I fixed the issue in the first patch, called "[PATCH
> v2 1/3] iio: ak8975: minor fixes".

Great. You can add my "tested-by" with that change.

> Gwendal.
> 
> On Mon, Nov 17, 2014 at 10:02 AM, Srinivas Pandruvada
> <srinivas.pandruvada@linux.intel.com> wrote:
> > On Thu, 2014-11-06 at 13:25 -0800, Gwendal Grignou wrote:
> >> Add 2 new definition entries to support ak0991x compass.
> >> Add a more advanced function to check we are dealing with the
> >> expected device.
> >> Remove standalone driver for ak09911.
> >>
> >
> > Since there is no interrupt for AK09911, the client->irq is initialized
> > to -1 by acpi-i2c.
> > static int ak8975_setup(struct i2c_client *client)
> > {
> > ..
> > if (data->eoc_gpio > 0 || client->irq) {
> >
> > change to
> >
> > if (data->eoc_gpio > 0 || client->irq > 0) {
> >
> > If you do this change, the modified driver works fine.
> >
> > Thanks,
> > Srinivas
> >
> >
> >
> >> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> >> ---
> >>  Readded CONFIG_AK09911 to ease transition from standalone driver.
> >>
> >>  drivers/iio/magnetometer/Kconfig   |  15 +-
> >>  drivers/iio/magnetometer/Makefile  |   1 -
> >>  drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
> >>  drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
> >>  4 files changed, 186 insertions(+), 353 deletions(-)
> >>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
> >>
> >> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> >> index b2dba9e..4c7a4c5 100644
> >> --- a/drivers/iio/magnetometer/Kconfig
> >> +++ b/drivers/iio/magnetometer/Kconfig
> >> @@ -6,26 +6,21 @@
> >>  menu "Magnetometer sensors"
> >>
> >>  config AK8975
> >> -     tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> >> +     tristate "Asahi Kasei AK 3-Axis Magnetometer"
> >>       depends on I2C
> >>       depends on GPIOLIB
> >>       help
> >> -       Say yes here to build support for Asahi Kasei AK8975 3-Axis
> >> -       Magnetometer. This driver can also support AK8963, if i2c
> >> -       device name is identified as ak8963.
> >> +       Say yes here to build support for Asahi Kasei AK8975, AK8963,
> >> +       AK09911 or AK09912 3-Axis Magnetometer.
> >>
> >>         To compile this driver as a module, choose M here: the module
> >>         will be called ak8975.
> >>
> >>  config AK09911
> >>       tristate "Asahi Kasei AK09911 3-axis Compass"
> >> -     depends on I2C
> >> +     select AK8975
> >>       help
> >> -       Say yes here to build support for Asahi Kasei AK09911 3-Axis
> >> -       Magnetometer.
> >> -
> >> -       To compile this driver as a module, choose M here: the module
> >> -       will be called ak09911.
> >> +       Deprecated: AK09911 is now supported by AK8975 driver.
> >>
> >>  config MAG3110
> >>       tristate "Freescale MAG3110 3-Axis Magnetometer"
> >> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
> >> index b91315e..0f5d3c9 100644
> >> --- a/drivers/iio/magnetometer/Makefile
> >> +++ b/drivers/iio/magnetometer/Makefile
> >> @@ -3,7 +3,6 @@
> >>  #
> >>
> >>  # When adding new entries keep the list in alphabetical order
> >> -obj-$(CONFIG_AK09911)        += ak09911.o
> >>  obj-$(CONFIG_AK8975) += ak8975.o
> >>  obj-$(CONFIG_MAG3110)        += mag3110.o
> >>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
> >> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
> >> deleted file mode 100644
> >> index b2bc942..0000000
> >> --- a/drivers/iio/magnetometer/ak09911.c
> >> +++ /dev/null
> >> @@ -1,326 +0,0 @@
> >> -/*
> >> - * AK09911 3-axis compass driver
> >> - * Copyright (c) 2014, 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.
> >> - */
> >> -
> >> -#include <linux/kernel.h>
> >> -#include <linux/module.h>
> >> -#include <linux/init.h>
> >> -#include <linux/types.h>
> >> -#include <linux/slab.h>
> >> -#include <linux/delay.h>
> >> -#include <linux/i2c.h>
> >> -#include <linux/acpi.h>
> >> -#include <linux/iio/iio.h>
> >> -
> >> -#define AK09911_REG_WIA1             0x00
> >> -#define AK09911_REG_WIA2             0x01
> >> -#define AK09911_WIA1_VALUE           0x48
> >> -#define AK09911_WIA2_VALUE           0x05
> >> -
> >> -#define AK09911_REG_ST1                      0x10
> >> -#define AK09911_REG_HXL                      0x11
> >> -#define AK09911_REG_HXH                      0x12
> >> -#define AK09911_REG_HYL                      0x13
> >> -#define AK09911_REG_HYH                      0x14
> >> -#define AK09911_REG_HZL                      0x15
> >> -#define AK09911_REG_HZH                      0x16
> >> -
> >> -#define AK09911_REG_ASAX             0x60
> >> -#define AK09911_REG_ASAY             0x61
> >> -#define AK09911_REG_ASAZ             0x62
> >> -
> >> -#define AK09911_REG_CNTL1            0x30
> >> -#define AK09911_REG_CNTL2            0x31
> >> -#define AK09911_REG_CNTL3            0x32
> >> -
> >> -#define AK09911_MODE_SNG_MEASURE     0x01
> >> -#define AK09911_MODE_SELF_TEST               0x10
> >> -#define AK09911_MODE_FUSE_ACCESS     0x1F
> >> -#define AK09911_MODE_POWERDOWN               0x00
> >> -#define AK09911_RESET_DATA           0x01
> >> -
> >> -#define AK09911_REG_CNTL1            0x30
> >> -#define AK09911_REG_CNTL2            0x31
> >> -#define AK09911_REG_CNTL3            0x32
> >> -
> >> -#define AK09911_RAW_TO_GAUSS(asa)    ((((asa) + 128) * 6000) / 256)
> >> -
> >> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS    500
> >> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
> >> -
> >> -struct ak09911_data {
> >> -     struct i2c_client       *client;
> >> -     struct mutex            lock;
> >> -     u8                      asa[3];
> >> -     long                    raw_to_gauss[3];
> >> -};
> >> -
> >> -static const int ak09911_index_to_reg[] = {
> >> -     AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
> >> -};
> >> -
> >> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
> >> -{
> >> -     int ret;
> >> -
> >> -     switch (mode) {
> >> -     case AK09911_MODE_SNG_MEASURE:
> >> -     case AK09911_MODE_SELF_TEST:
> >> -     case AK09911_MODE_FUSE_ACCESS:
> >> -     case AK09911_MODE_POWERDOWN:
> >> -             ret = i2c_smbus_write_byte_data(client,
> >> -                                             AK09911_REG_CNTL2, mode);
> >> -             if (ret < 0) {
> >> -                     dev_err(&client->dev, "set_mode error\n");
> >> -                     return ret;
> >> -             }
> >> -             /* After mode change wait atleast 100us */
> >> -             usleep_range(100, 500);
> >> -             break;
> >> -     default:
> >> -             dev_err(&client->dev,
> >> -                     "%s: Unknown mode(%d).", __func__, mode);
> >> -             return -EINVAL;
> >> -     }
> >> -
> >> -     return ret;
> >> -}
> >> -
> >> -/* Get Sensitivity Adjustment value */
> >> -static int ak09911_get_asa(struct i2c_client *client)
> >> -{
> >> -     struct iio_dev *indio_dev = i2c_get_clientdata(client);
> >> -     struct ak09911_data *data = iio_priv(indio_dev);
> >> -     int ret;
> >> -
> >> -     ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
> >> -     if (ret < 0)
> >> -             return ret;
> >> -
> >> -     /* Get asa data and store in the device data. */
> >> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
> >> -                                         3, data->asa);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Not able to read asa data\n");
> >> -             return ret;
> >> -     }
> >> -
> >> -     ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
> >> -     if (ret < 0)
> >> -             return ret;
> >> -
> >> -     data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
> >> -     data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
> >> -     data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
> >> -
> >> -     return 0;
> >> -}
> >> -
> >> -static int ak09911_verify_chip_id(struct i2c_client *client)
> >> -{
> >> -     u8 wia_val[2];
> >> -     int ret;
> >> -
> >> -     ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
> >> -                                         2, wia_val);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Error reading WIA\n");
> >> -             return ret;
> >> -     }
> >> -
> >> -     dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
> >> -
> >> -     if (wia_val[0] != AK09911_WIA1_VALUE ||
> >> -             wia_val[1] != AK09911_WIA2_VALUE) {
> >> -             dev_err(&client->dev, "Device ak09911 not found\n");
> >> -             return -ENODEV;
> >> -     }
> >> -
> >> -     return 0;
> >> -}
> >> -
> >> -static int wait_conversion_complete_polled(struct ak09911_data *data)
> >> -{
> >> -     struct i2c_client *client = data->client;
> >> -     u8 read_status;
> >> -     u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
> >> -     int ret;
> >> -
> >> -     /* Wait for the conversion to complete. */
> >> -     while (timeout_ms) {
> >> -             msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
> >> -             ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
> >> -             if (ret < 0) {
> >> -                     dev_err(&client->dev, "Error in reading ST1\n");
> >> -                     return ret;
> >> -             }
> >> -             read_status = ret & 0x01;
> >> -             if (read_status)
> >> -                     break;
> >> -             timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
> >> -     }
> >> -     if (!timeout_ms) {
> >> -             dev_err(&client->dev, "Conversion timeout happened\n");
> >> -             return -EIO;
> >> -     }
> >> -
> >> -     return read_status;
> >> -}
> >> -
> >> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
> >> -{
> >> -     struct ak09911_data *data = iio_priv(indio_dev);
> >> -     struct i2c_client *client = data->client;
> >> -     int ret;
> >> -
> >> -     mutex_lock(&data->lock);
> >> -
> >> -     ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
> >> -     if (ret < 0)
> >> -             goto fn_exit;
> >> -
> >> -     ret = wait_conversion_complete_polled(data);
> >> -     if (ret < 0)
> >> -             goto fn_exit;
> >> -
> >> -     /* Read data */
> >> -     ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Read axis data fails\n");
> >> -             goto fn_exit;
> >> -     }
> >> -
> >> -     mutex_unlock(&data->lock);
> >> -
> >> -     /* Clamp to valid range. */
> >> -     *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
> >> -
> >> -     return IIO_VAL_INT;
> >> -
> >> -fn_exit:
> >> -     mutex_unlock(&data->lock);
> >> -
> >> -     return ret;
> >> -}
> >> -
> >> -static int ak09911_read_raw(struct iio_dev *indio_dev,
> >> -                         struct iio_chan_spec const *chan,
> >> -                         int *val, int *val2,
> >> -                         long mask)
> >> -{
> >> -     struct ak09911_data *data = iio_priv(indio_dev);
> >> -
> >> -     switch (mask) {
> >> -     case IIO_CHAN_INFO_RAW:
> >> -             return ak09911_read_axis(indio_dev, chan->address, val);
> >> -     case IIO_CHAN_INFO_SCALE:
> >> -             *val = 0;
> >> -             *val2 = data->raw_to_gauss[chan->address];
> >> -             return IIO_VAL_INT_PLUS_MICRO;
> >> -     }
> >> -
> >> -     return -EINVAL;
> >> -}
> >> -
> >> -#define AK09911_CHANNEL(axis, index)                                 \
> >> -     {                                                               \
> >> -             .type = IIO_MAGN,                                       \
> >> -             .modified = 1,                                          \
> >> -             .channel2 = IIO_MOD_##axis,                             \
> >> -             .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
> >> -                          BIT(IIO_CHAN_INFO_SCALE),                  \
> >> -             .address = index,                                       \
> >> -     }
> >> -
> >> -static const struct iio_chan_spec ak09911_channels[] = {
> >> -     AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
> >> -};
> >> -
> >> -static const struct iio_info ak09911_info = {
> >> -     .read_raw = &ak09911_read_raw,
> >> -     .driver_module = THIS_MODULE,
> >> -};
> >> -
> >> -static const struct acpi_device_id ak_acpi_match[] = {
> >> -     {"AK009911", 0},
> >> -     { },
> >> -};
> >> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> >> -
> >> -static int ak09911_probe(struct i2c_client *client,
> >> -                      const struct i2c_device_id *id)
> >> -{
> >> -     struct iio_dev *indio_dev;
> >> -     struct ak09911_data *data;
> >> -     const char *name;
> >> -     int ret;
> >> -
> >> -     ret = ak09911_verify_chip_id(client);
> >> -     if (ret) {
> >> -             dev_err(&client->dev, "AK00911 not detected\n");
> >> -             return -ENODEV;
> >> -     }
> >> -
> >> -     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> >> -     if (indio_dev == NULL)
> >> -             return -ENOMEM;
> >> -
> >> -     data = iio_priv(indio_dev);
> >> -     i2c_set_clientdata(client, indio_dev);
> >> -
> >> -     data->client = client;
> >> -     mutex_init(&data->lock);
> >> -
> >> -     ret = ak09911_get_asa(client);
> >> -     if (ret)
> >> -             return ret;
> >> -
> >> -     if (id)
> >> -             name = id->name;
> >> -     else if (ACPI_HANDLE(&client->dev))
> >> -             name = dev_name(&client->dev);
> >> -     else
> >> -             return -ENODEV;
> >> -
> >> -     dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> >> -
> >> -     indio_dev->dev.parent = &client->dev;
> >> -     indio_dev->channels = ak09911_channels;
> >> -     indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
> >> -     indio_dev->info = &ak09911_info;
> >> -     indio_dev->modes = INDIO_DIRECT_MODE;
> >> -     indio_dev->name = name;
> >> -
> >> -     return devm_iio_device_register(&client->dev, indio_dev);
> >> -}
> >> -
> >> -static const struct i2c_device_id ak09911_id[] = {
> >> -     {"ak09911", 0},
> >> -     {}
> >> -};
> >> -
> >> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
> >> -
> >> -static struct i2c_driver ak09911_driver = {
> >> -     .driver = {
> >> -             .name   = "ak09911",
> >> -             .acpi_match_table = ACPI_PTR(ak_acpi_match),
> >> -     },
> >> -     .probe          = ak09911_probe,
> >> -     .id_table       = ak09911_id,
> >> -};
> >> -module_i2c_driver(ak09911_driver);
> >> -
> >> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
> >> -MODULE_LICENSE("GPL v2");
> >> -MODULE_DESCRIPTION("AK09911 Compass driver");
> >> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> >> index b170654..f8c7046 100644
> >> --- a/drivers/iio/magnetometer/ak8975.c
> >> +++ b/drivers/iio/magnetometer/ak8975.c
> >> @@ -81,6 +81,58 @@
> >>  #define AK8975_MAX_REGS                      AK8975_REG_ASAZ
> >>
> >>  /*
> >> + * AK09912 Register definitions
> >> + */
> >> +#define AK09912_REG_WIA1             0x00
> >> +#define AK09912_REG_WIA2             0x01
> >> +#define AK09912_DEVICE_ID            0x04
> >> +#define AK09911_DEVICE_ID            0x05
> >> +
> >> +#define AK09911_REG_INFO1            0x02
> >> +#define AK09911_REG_INFO2            0x03
> >> +
> >> +#define AK09912_REG_ST1                      0x10
> >> +
> >> +#define AK09912_REG_ST1_DRDY_SHIFT   0
> >> +#define AK09912_REG_ST1_DRDY_MASK    (1 << AK09912_REG_ST1_DRDY_SHIFT)
> >> +
> >> +#define AK09912_REG_HXL                      0x11
> >> +#define AK09912_REG_HXH                      0x12
> >> +#define AK09912_REG_HYL                      0x13
> >> +#define AK09912_REG_HYH                      0x14
> >> +#define AK09912_REG_HZL                      0x15
> >> +#define AK09912_REG_HZH                      0x16
> >> +#define AK09912_REG_TMPS             0x17
> >> +
> >> +#define AK09912_REG_ST2                      0x18
> >> +#define AK09912_REG_ST2_HOFL_SHIFT   3
> >> +#define AK09912_REG_ST2_HOFL_MASK    (1 << AK09912_REG_ST2_HOFL_SHIFT)
> >> +
> >> +#define AK09912_REG_CNTL1            0x30
> >> +
> >> +#define AK09912_REG_CNTL2            0x31
> >> +#define AK09912_REG_CNTL_MODE_POWER_DOWN     0x00
> >> +#define AK09912_REG_CNTL_MODE_ONCE   0x01
> >> +#define AK09912_REG_CNTL_MODE_SELF_TEST      0x10
> >> +#define AK09912_REG_CNTL_MODE_FUSE_ROM       0x1F
> >> +#define AK09912_REG_CNTL2_MODE_SHIFT 0
> >> +#define AK09912_REG_CNTL2_MODE_MASK  (0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
> >> +
> >> +#define AK09912_REG_CNTL3            0x32
> >> +
> >> +#define AK09912_REG_TS1                      0x33
> >> +#define AK09912_REG_TS2                      0x34
> >> +#define AK09912_REG_TS3                      0x35
> >> +#define AK09912_REG_I2CDIS           0x36
> >> +#define AK09912_REG_TS4                      0x37
> >> +
> >> +#define AK09912_REG_ASAX             0x60
> >> +#define AK09912_REG_ASAY             0x61
> >> +#define AK09912_REG_ASAZ             0x62
> >> +
> >> +#define AK09912_MAX_REGS             AK09912_REG_ASAZ
> >> +
> >> +/*
> >>   * Miscellaneous values.
> >>   */
> >>  #define AK8975_MAX_CONVERSION_TIMEOUT        500
> >> @@ -130,22 +182,37 @@ long ak8975_raw_to_gauss(u16 data)
> >>  }
> >>
> >>  /*
> >> - * For AK8963, same calculation, but the device is less sensitive:
> >> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
> >>   *
> >>   * H is in the range of +-8190.  The magnetometer has a range of
> >>   * +-4912uT.  To go from the raw value to uT is:
> >>   *
> >>   * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
> >>   */
> >> -long ak8963_raw_to_gauss(u16 data)
> >> +long ak8963_09911_raw_to_gauss(u16 data)
> >>  {
> >>       return (((long)data + 128) * 6000) / 256;
> >>  }
> >>
> >> +/*
> >> + * For AK09912, same calculation, except the device is more sensitive:
> >> + *
> >> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
> >> + * +-4912uT.  To go from the raw value to uT is:
> >> + *
> >> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
> >> + */
> >> +long ak09912_raw_to_gauss(u16 data)
> >> +{
> >> +     return (((long)data + 128) * 1500) / 256;
> >> +}
> >> +
> >>  /* Compatible Asahi Kasei Compass parts */
> >>  enum asahi_compass_chipset {
> >>       AK8975,
> >>       AK8963,
> >> +     AK09911,
> >> +     AK09912,
> >>       AK_MAX_TYPE
> >>  };
> >>
> >> @@ -210,7 +277,7 @@ struct ak_def {
> >>  },
> >>  {
> >>       .type = AK8963,
> >> -     .raw_to_gauss = ak8963_raw_to_gauss,
> >> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
> >>       .range = 8190,
> >>       .ctrl_regs = {
> >>               AK8975_REG_ST1,
> >> @@ -233,6 +300,56 @@ struct ak_def {
> >>               AK8975_REG_HYL,
> >>               AK8975_REG_HZL},
> >>  },
> >> +{
> >> +     .type = AK09911,
> >> +     .raw_to_gauss = ak8963_09911_raw_to_gauss,
> >> +     .range = 8192,
> >> +     .ctrl_regs = {
> >> +             AK09912_REG_ST1,
> >> +             AK09912_REG_ST2,
> >> +             AK09912_REG_CNTL2,
> >> +             AK09912_REG_ASAX,
> >> +             AK09912_MAX_REGS},
> >> +     .ctrl_masks = {
> >> +             AK09912_REG_ST1_DRDY_MASK,
> >> +             AK09912_REG_ST2_HOFL_MASK,
> >> +             0,
> >> +             AK09912_REG_CNTL2_MODE_MASK},
> >> +     .ctrl_modes = {
> >> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
> >> +             AK09912_REG_CNTL_MODE_ONCE,
> >> +             AK09912_REG_CNTL_MODE_SELF_TEST,
> >> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
> >> +     .data_regs = {
> >> +             AK09912_REG_HXL,
> >> +             AK09912_REG_HYL,
> >> +             AK09912_REG_HZL},
> >> +},
> >> +{
> >> +     .type = AK09912,
> >> +     .raw_to_gauss = ak09912_raw_to_gauss,
> >> +     .range = 32752,
> >> +     .ctrl_regs = {
> >> +             AK09912_REG_ST1,
> >> +             AK09912_REG_ST2,
> >> +             AK09912_REG_CNTL2,
> >> +             AK09912_REG_ASAX,
> >> +             AK09912_MAX_REGS},
> >> +     .ctrl_masks = {
> >> +             AK09912_REG_ST1_DRDY_MASK,
> >> +             AK09912_REG_ST2_HOFL_MASK,
> >> +             0,
> >> +             AK09912_REG_CNTL2_MODE_MASK},
> >> +     .ctrl_modes = {
> >> +             AK09912_REG_CNTL_MODE_POWER_DOWN,
> >> +             AK09912_REG_CNTL_MODE_ONCE,
> >> +             AK09912_REG_CNTL_MODE_SELF_TEST,
> >> +             AK09912_REG_CNTL_MODE_FUSE_ROM},
> >> +     .data_regs = {
> >> +             AK09912_REG_HXL,
> >> +             AK09912_REG_HYL,
> >> +             AK09912_REG_HZL},
> >> +}
> >>  };
> >>
> >>  /*
> >> @@ -253,6 +370,55 @@ struct ak8975_data {
> >>  };
> >>
> >>  /*
> >> + * Return 0 if the i2c device is the one we expect.
> >> + * return a negative error number otherwise
> >> + */
> >> +static int ak8975_who_i_am(struct i2c_client *client,
> >> +                        enum asahi_compass_chipset type)
> >> +{
> >> +     u8 wia_val[2];
> >> +     int ret;
> >> +
> >> +     /*
> >> +      * Signature for each device:
> >> +      * Device   |  WIA1      |  WIA2
> >> +      * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
> >> +      * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
> >> +      * AK8975   |  DEVICE_ID |  NA
> >> +      * AK8963   |  DEVICE_ID |  NA
> >> +      */
> >> +     ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> >> +                                         2, wia_val);
> >> +     if (ret < 0) {
> >> +             dev_err(&client->dev, "Error reading WIA\n");
> >> +             return ret;
> >> +     }
> >> +
> >> +     ret = -ENODEV;
> >> +
> >> +     if (wia_val[0] != AK8975_DEVICE_ID)
> >> +             return ret;
> >> +
> >> +     switch (type) {
> >> +     case AK8975:
> >> +     case AK8963:
> >> +             ret = 0;
> >> +             break;
> >> +     case AK09911:
> >> +             if (wia_val[1] == AK09911_DEVICE_ID)
> >> +                     ret = 0;
> >> +             break;
> >> +     case AK09912:
> >> +             if (wia_val[1] == AK09912_DEVICE_ID)
> >> +                     ret = 0;
> >> +             break;
> >> +     default:
> >> +             dev_err(&client->dev, "Type %d unknown\n", type);
> >> +     }
> >> +     return ret;
> >> +}
> >> +
> >> +/*
> >>   * Helper function to write to CNTL register.
> >>   */
> >>  static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
> >> @@ -327,21 +493,8 @@ static int ak8975_setup(struct i2c_client *client)
> >>  {
> >>       struct iio_dev *indio_dev = i2c_get_clientdata(client);
> >>       struct ak8975_data *data = iio_priv(indio_dev);
> >> -     u8 device_id;
> >>       int ret;
> >>
> >> -     /* Confirm that the device we're talking to is really an AK8975. */
> >> -     ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> >> -     if (ret < 0) {
> >> -             dev_err(&client->dev, "Error reading WIA\n");
> >> -             return ret;
> >> -     }
> >> -     device_id = ret;
> >> -     if (device_id != AK8975_DEVICE_ID) {
> >> -             dev_err(&client->dev, "Device ak8975 not found\n");
> >> -             return -ENODEV;
> >> -     }
> >> -
> >>       /* Write the fused rom access mode. */
> >>       ret = ak8975_set_mode(data, FUSE_ROM);
> >>       if (ret < 0) {
> >> @@ -552,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
> >>       {"AK8975", AK8975},
> >>       {"AK8963", AK8963},
> >>       {"INVN6500", AK8963},
> >> +     {"AK09911", AK09911},
> >> +     {"AK09912", AK09912},
> >>       { },
> >>  };
> >>  MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> >> @@ -631,6 +786,10 @@ static int ak8975_probe(struct i2c_client *client,
> >>       }
> >>
> >>       data->def = &ak_def_array[chipset];
> >> +     if (ak8975_who_i_am(client, data->def->type) < 0) {
> >> +             dev_err(&client->dev, "Unexpected device\n");
> >> +             return -ENODEV;
> >> +     }
> >>       dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> >>
> >>       /* Perform some basic start-of-day setup of the device. */
> >> @@ -653,6 +812,8 @@ static int ak8975_probe(struct i2c_client *client,
> >>  static const struct i2c_device_id ak8975_id[] = {
> >>       {"ak8975", AK8975},
> >>       {"ak8963", AK8963},
> >> +     {"ak09911", AK09911},
> >> +     {"ak09912", AK09912},
> >>       {}
> >>  };
> >>
> >> @@ -663,6 +824,10 @@ static const struct of_device_id ak8975_of_match[] = {
> >>       { .compatible = "ak8975", },
> >>       { .compatible = "asahi-kasei,ak8963", },
> >>       { .compatible = "ak8963", },
> >> +     { .compatible = "asahi-kasei,ak09911", },
> >> +     { .compatible = "ak09911", },
> >> +     { .compatible = "asahi-kasei,ak09912", },
> >> +     { .compatible = "ak09912", },
> >>       {}
> >>  };
> >>  MODULE_DEVICE_TABLE(of, ak8975_of_match);
> >
> >



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2 1/3] iio: ak8975: minor fixes
  2014-11-17 20:13               ` [PATCH v2 " Gwendal Grignou
@ 2014-11-19 11:16                 ` Hartmut Knaack
  0 siblings, 0 replies; 28+ messages in thread
From: Hartmut Knaack @ 2014-11-19 11:16 UTC (permalink / raw)
  To: Gwendal Grignou, srinivas.pandruvada, jic23; +Cc: linux-iio

Gwendal Grignou schrieb am 17.11.2014 21:13:
> Fixes code duplication, return of function.
> Check client->irq properly when setting up optional irq handler.
> 
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  Fix client->irq checking, Srinivas found it was not correct on ACPI based
>  machine.
>  drivers/iio/magnetometer/ak8975.c | 35 ++++++++++++++---------------------
>  1 file changed, 14 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index bf5ef07..4e69480 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -64,10 +64,10 @@
>  #define AK8975_REG_CNTL			0x0A
>  #define AK8975_REG_CNTL_MODE_SHIFT	0
>  #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
> -#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
> -#define AK8975_REG_CNTL_MODE_ONCE	1
> -#define AK8975_REG_CNTL_MODE_SELF_TEST	8
> -#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
> +#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK8975_REG_CNTL_MODE_ONCE	0x01
> +#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
> +#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
>  
>  #define AK8975_REG_RSVC			0x0B
>  #define AK8975_REG_ASTC			0x0C
> @@ -166,8 +166,8 @@ static int ak8975_setup_irq(struct ak8975_data *data)
>  		irq = gpio_to_irq(data->eoc_gpio);
>  
>  	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
> -			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> -			 dev_name(&client->dev), data);
> +			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +			      dev_name(&client->dev), data);
>  	if (rc < 0) {
>  		dev_err(&client->dev,
>  			"irq %d request failed, (gpio %d): %d\n",
> @@ -231,8 +231,12 @@ static int ak8975_setup(struct i2c_client *client)
>  				AK8975_REG_CNTL_MODE_POWER_DOWN,
>  				AK8975_REG_CNTL_MODE_MASK,
>  				AK8975_REG_CNTL_MODE_SHIFT);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error in setting power-down mode\n");
> +		return ret;
> +	}
>  
> -	if (data->eoc_gpio > 0 || client->irq) {
> +	if (data->eoc_gpio > 0 || client->irq > 0) {
>  		ret = ak8975_setup_irq(data);
>  		if (ret < 0) {
>  			dev_err(&client->dev,
> @@ -241,11 +245,6 @@ static int ak8975_setup(struct i2c_client *client)
>  		}
>  	}
>  
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error in setting power-down mode\n");
> -		return ret;
> -	}
> -
>  /*
>   * Precalculate scale factor (in Gauss units) for each axis and
>   * store in the device data.
> @@ -550,24 +549,18 @@ static int ak8975_probe(struct i2c_client *client,
>  	/* Perform some basic start-of-day setup of the device. */
>  	err = ak8975_setup(client);
>  	if (err < 0) {
> -		dev_err(&client->dev, "AK8975 initialization fails\n");
> +		dev_err(&client->dev, "%s initialization fails\n", name);
>  		return err;
>  	}
>  
> -	data->client = client;
>  	mutex_init(&data->lock);
> -	data->eoc_gpio = eoc_gpio;
>  	indio_dev->dev.parent = &client->dev;
>  	indio_dev->channels = ak8975_channels;
>  	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
>  	indio_dev->info = &ak8975_info;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  	indio_dev->name = name;
> -	err = devm_iio_device_register(&client->dev, indio_dev);
> -	if (err < 0)
> -		return err;
> -
> -	return 0;
> +	return devm_iio_device_register(&client->dev, indio_dev);
>  }
>  
>  static const struct i2c_device_id ak8975_id[] = {
> @@ -588,7 +581,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match);
>  static struct i2c_driver ak8975_driver = {
>  	.driver = {
>  		.name	= "ak8975",
> -		.of_match_table = ak8975_of_match,
> +		.of_match_table = of_match_ptr(ak8975_of_match),
>  		.acpi_match_table = ACPI_PTR(ak_acpi_match),
>  	},
>  	.probe		= ak8975_probe,
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/3] iio: ak8975: add definition structure per compass type
  2014-11-05 22:10             ` [PATCH 2/3] iio: ak8975: add definition structure per compass type Gwendal Grignou
  2014-11-06 15:02               ` Srinivas Pandruvada
@ 2014-11-19 11:25               ` Hartmut Knaack
  1 sibling, 0 replies; 28+ messages in thread
From: Hartmut Knaack @ 2014-11-19 11:25 UTC (permalink / raw)
  To: Gwendal Grignou, srinivas.pandruvada, jic23; +Cc: linux-iio

Gwendal Grignou schrieb am 05.11.2014 23:10:
> For each type of compass supported (AK8975 and AK8963),
> add a definition structure for register masks, important registers,
> raw data interpretation.
> This change will make integrating new type of devices easier.
> 
> Remove i2c register cache. It is only used for one single register.
Looks basically good to me, I just put some thoughts about tweaking indentations inline.
> 
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>  drivers/iio/magnetometer/ak8975.c | 279 +++++++++++++++++++++++++-------------
>  1 file changed, 184 insertions(+), 95 deletions(-)
> 
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index 12f0b00..b170654 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -86,13 +86,153 @@
>  #define AK8975_MAX_CONVERSION_TIMEOUT	500
>  #define AK8975_CONVERSION_DONE_POLL_TIME 10
>  #define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
> -#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
> -#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
> +
> +/*
> + * Precalculate scale factor (in Gauss units) for each axis and
> + * store in the device data.
> + *
> + * This scale factor is axis-dependent, and is derived from 3 calibration
> + * factors ASA(x), ASA(y), and ASA(z).
> + *
> + * These ASA values are read from the sensor device at start of day, and
> + * cached in the device context struct.
> + *
> + * Adjusting the flux value with the sensitivity adjustment value should be
> + * done via the following formula:
> + *
> + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> + * is the resultant adjusted value.
> + *
> + * We reduce the formula to:
> + *
> + * Hadj = H * (ASA + 128) / 256
> + *
> + * H is in the range of -4096 to 4095.  The magnetometer has a range of
> + * +-1229uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 1229/4096, or roughly, 3/10.
> + *
> + * Since 1uT = 0.01 gauss, our final scale factor becomes:
> + *
> + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> + * Hadj = H * ((ASA + 128) * 0.003) / 256
> + *
> + * Since ASA doesn't change, we cache the resultant scale factor into the
> + * device context in ak8975_setup().
> + *
> + * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
> + * multiply the stored scale value by 1e6.
> + */
> +long ak8975_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 3000) / 256;
> +}
> +
> +/*
> + * For AK8963, same calculation, but the device is less sensitive:
> + *
> + * H is in the range of +-8190.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
> + */
> +long ak8963_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 6000) / 256;
> +}
>  
>  /* Compatible Asahi Kasei Compass parts */
>  enum asahi_compass_chipset {
>  	AK8975,
>  	AK8963,
> +	AK_MAX_TYPE
> +};
> +
> +enum ak_ctrl_reg_addr {
> +	ST1,
> +	ST2,
> +	CNTL,
> +	ASA_BASE,
> +	MAX_REGS,
> +	REGS_END,
> +};
> +
> +enum ak_ctrl_reg_mask {
> +	ST1_DRDY,
> +	ST2_HOFL,
> +	ST2_DERR,
> +	CNTL_MODE,
> +	MASK_END,
> +};
> +
> +enum ak_ctrl_mode {
> +	POWER_DOWN,
> +	MODE_ONCE,
> +	SELF_TEST,
> +	FUSE_ROM,
> +	MODE_END,
> +};
> +
> +struct ak_def {
> +	enum asahi_compass_chipset type;
> +	long (*raw_to_gauss)(u16 data);
> +	u16 range;
> +	u8 ctrl_regs[REGS_END];
> +	u8 ctrl_masks[MASK_END];
> +	u8 ctrl_modes[MODE_END];
> +	u8 data_regs[3];
> +} ak_def_array[AK_MAX_TYPE] = {
> +{
Shouldn't this be indented one level more?
> +	.type = AK8975,
> +	.raw_to_gauss = ak8975_raw_to_gauss,
> +	.range = 4096,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		AK8975_REG_ST2_DERR_MASK,
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
> +{
> +	.type = AK8963,
> +	.raw_to_gauss = ak8963_raw_to_gauss,
> +	.range = 8190,
> +	.ctrl_regs = {
> +		AK8975_REG_ST1,
> +		AK8975_REG_ST2,
> +		AK8975_REG_CNTL,
> +		AK8975_REG_ASAX,
> +		AK8975_MAX_REGS},
> +	.ctrl_masks = {
> +		AK8975_REG_ST1_DRDY_MASK,
> +		AK8975_REG_ST2_HOFL_MASK,
> +		0,
> +		AK8975_REG_CNTL_MODE_MASK},
> +	.ctrl_modes = {
> +		AK8975_REG_CNTL_MODE_POWER_DOWN,
> +		AK8975_REG_CNTL_MODE_ONCE,
> +		AK8975_REG_CNTL_MODE_SELF_TEST,
> +		AK8975_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK8975_REG_HXL,
> +		AK8975_REG_HYL,
> +		AK8975_REG_HZL},
> +},
>  };
>  
>  /*
> @@ -100,40 +240,36 @@ enum asahi_compass_chipset {
>   */
>  struct ak8975_data {
>  	struct i2c_client	*client;
> +	struct ak_def		*def;
>  	struct attribute_group	attrs;
>  	struct mutex		lock;
>  	u8			asa[3];
>  	long			raw_to_gauss[3];
> -	u8			reg_cache[AK8975_MAX_REGS];
>  	int			eoc_gpio;
>  	int			eoc_irq;
>  	wait_queue_head_t	data_ready_queue;
>  	unsigned long		flags;
> -	enum asahi_compass_chipset chipset;
> -};
> -
> -static const int ak8975_index_to_reg[] = {
> -	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
> +	u8			cntl_cache;
>  };
>  
>  /*
> - * Helper function to write to the I2C device's registers.
> + * Helper function to write to CNTL register.
>   */
> -static int ak8975_write_data(struct i2c_client *client,
> -			     u8 reg, u8 val, u8 mask, u8 shift)
> +static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
>  {
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak8975_data *data = iio_priv(indio_dev);
>  	u8 regval;
>  	int ret;
>  
> -	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
> -	ret = i2c_smbus_write_byte_data(client, reg, regval);
> +	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
> +		data->def->ctrl_modes[mode];
This could be indented by one more space.
> +	ret = i2c_smbus_write_byte_data(
> +		data->client, data->def->ctrl_regs[CNTL], regval);
This could be indented like this:
	ret = i2c_smbus_write_byte_data(data->client,
					data->def->ctrl_regs[CNTL], regval);
>  	if (ret < 0) {
> -		dev_err(&client->dev, "Write to device fails status %x\n", ret);
>  		return ret;
>  	}
> -	data->reg_cache[reg] = regval;
> +	data->cntl_cache = regval;
> +	/* After mode change wait atleast 100us */
> +	usleep_range(100, 500);
>  
>  	return 0;
>  }
> @@ -207,18 +343,15 @@ static int ak8975_setup(struct i2c_client *client)
>  	}
>  
>  	/* Write the fused rom access mode. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_FUSE_ROM,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = ak8975_set_mode(data, FUSE_ROM);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting fuse access mode\n");
>  		return ret;
>  	}
>  
>  	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
> +	ret = i2c_smbus_read_i2c_block_data(client,
> +					    data->def->ctrl_regs[ASA_BASE],
>  					    3, data->asa);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Not able to read asa data\n");
> @@ -226,11 +359,7 @@ static int ak8975_setup(struct i2c_client *client)
>  	}
>  
>  	/* After reading fuse ROM data set power-down mode */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_POWER_DOWN,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = ak8975_set_mode(data, POWER_DOWN);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting power-down mode\n");
>  		return ret;
> @@ -245,56 +374,9 @@ static int ak8975_setup(struct i2c_client *client)
>  		}
>  	}
>  
> -/*
> - * Precalculate scale factor (in Gauss units) for each axis and
> - * store in the device data.
> - *
> - * This scale factor is axis-dependent, and is derived from 3 calibration
> - * factors ASA(x), ASA(y), and ASA(z).
> - *
> - * These ASA values are read from the sensor device at start of day, and
> - * cached in the device context struct.
> - *
> - * Adjusting the flux value with the sensitivity adjustment value should be
> - * done via the following formula:
> - *
> - * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
> - *
> - * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
> - * is the resultant adjusted value.
> - *
> - * We reduce the formula to:
> - *
> - * Hadj = H * (ASA + 128) / 256
> - *
> - * H is in the range of -4096 to 4095.  The magnetometer has a range of
> - * +-1229uT.  To go from the raw value to uT is:
> - *
> - * HuT = H * 1229/4096, or roughly, 3/10.
> - *
> - * Since 1uT = 0.01 gauss, our final scale factor becomes:
> - *
> - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
> - * Hadj = H * ((ASA + 128) * 0.003) / 256
> - *
> - * Since ASA doesn't change, we cache the resultant scale factor into the
> - * device context in ak8975_setup().
> - */
> -	if (data->chipset == AK8963) {
> -		/*
> -		 * H range is +-8190 and magnetometer range is +-4912.
> -		 * So HuT using the above explanation for 8975,
> -		 * 4912/8190 = ~ 6/10.
> -		 * So the Hadj should use 6/10 instead of 3/10.
> -		 */
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
> -	} else {
> -		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
> -		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
> -		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
> -	}
> +	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
> +	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
> +	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
>  
>  	return 0;
>  }
> @@ -317,7 +399,7 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
>  		return -EINVAL;
>  	}
>  
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
>  	if (ret < 0)
>  		dev_err(&client->dev, "Error in reading ST1\n");
>  
> @@ -334,7 +416,8 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
>  	/* Wait for the conversion to complete. */
>  	while (timeout_ms) {
>  		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST1]);
Same as mentioned above.
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST1\n");
>  			return ret;
> @@ -377,11 +460,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  	mutex_lock(&data->lock);
>  
>  	/* Set up the device for taking a sample. */
> -	ret = ak8975_write_data(client,
> -				AK8975_REG_CNTL,
> -				AK8975_REG_CNTL_MODE_ONCE,
> -				AK8975_REG_CNTL_MODE_MASK,
> -				AK8975_REG_CNTL_MODE_SHIFT);
> +	ret = ak8975_set_mode(data, MODE_ONCE);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Error in setting operating mode\n");
>  		goto exit;
> @@ -398,14 +477,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  		goto exit;
>  
>  	/* This will be executed only for non-interrupt based waiting case */
> -	if (ret & AK8975_REG_ST1_DRDY_MASK) {
> -		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
> +	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
> +		ret = i2c_smbus_read_byte_data(
> +				client, data->def->ctrl_regs[ST2]);
And here as well.
>  		if (ret < 0) {
>  			dev_err(&client->dev, "Error in reading ST2\n");
>  			goto exit;
>  		}
> -		if (ret & (AK8975_REG_ST2_DERR_MASK |
> -			   AK8975_REG_ST2_HOFL_MASK)) {
> +		if (ret & (data->def->ctrl_masks[ST2_DERR] |
> +			   data->def->ctrl_masks[ST2_HOFL])) {
>  			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
>  			ret = -EINVAL;
>  			goto exit;
> @@ -414,7 +494,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  
>  	/* Read the flux value from the appropriate register
>  	   (the register is specified in the iio device attributes). */
> -	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
> +	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "Read axis data fails\n");
>  		goto exit;
> @@ -423,7 +503,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
>  	mutex_unlock(&data->lock);
>  
>  	/* Clamp to valid range. */
> -	*val = clamp_t(s16, ret, -4096, 4095);
> +	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
>  	return IIO_VAL_INT;
>  
>  exit:
> @@ -497,6 +577,7 @@ static int ak8975_probe(struct i2c_client *client,
>  	int eoc_gpio;
>  	int err;
>  	const char *name = NULL;
> +	enum asahi_compass_chipset chipset;
>  
>  	/* Grab and set up the supplied GPIO. */
>  	if (client->dev.platform_data)
> @@ -536,14 +617,20 @@ static int ak8975_probe(struct i2c_client *client,
>  
>  	/* id will be NULL when enumerated via ACPI */
>  	if (id) {
> -		data->chipset =
> -			(enum asahi_compass_chipset)(id->driver_data);
> +		chipset = (enum asahi_compass_chipset)(id->driver_data);
>  		name = id->name;
>  	} else if (ACPI_HANDLE(&client->dev))
> -		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
> +		name = ak8975_match_acpi_device(&client->dev, &chipset);
>  	else
>  		return -ENOSYS;
>  
> +	if (chipset >= AK_MAX_TYPE) {
> +		dev_err(&client->dev, "AKM device type unsupported: %d\n",
> +			chipset);
> +		return -ENODEV;
> +	}
> +
> +	data->def = &ak_def_array[chipset];
>  	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>  
>  	/* Perform some basic start-of-day setup of the device. */
> @@ -574,7 +661,9 @@ MODULE_DEVICE_TABLE(i2c, ak8975_id);
>  static const struct of_device_id ak8975_of_match[] = {
>  	{ .compatible = "asahi-kasei,ak8975", },
>  	{ .compatible = "ak8975", },
> -	{ }
> +	{ .compatible = "asahi-kasei,ak8963", },
> +	{ .compatible = "ak8963", },
> +	{}
>  };
>  MODULE_DEVICE_TABLE(of, ak8975_of_match);
>  
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support
  2014-11-06 21:25                 ` Gwendal Grignou
  2014-11-17 18:02                   ` Srinivas Pandruvada
@ 2014-11-19 11:39                   ` Hartmut Knaack
  1 sibling, 0 replies; 28+ messages in thread
From: Hartmut Knaack @ 2014-11-19 11:39 UTC (permalink / raw)
  To: Gwendal Grignou, srinivas.pandruvada, jic23; +Cc: linux-iio

Gwendal Grignou schrieb am 06.11.2014 22:25:
> Add 2 new definition entries to support ak0991x compass.
> Add a more advanced function to check we are dealing with the
> expected device.
> Remove standalone driver for ak09911.
> 
Looks mostly good to me. Find some comments inline about what could be improved.
> Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
> ---
>  Readded CONFIG_AK09911 to ease transition from standalone driver.
> 
>  drivers/iio/magnetometer/Kconfig   |  15 +-
>  drivers/iio/magnetometer/Makefile  |   1 -
>  drivers/iio/magnetometer/ak09911.c | 326 -------------------------------------
>  drivers/iio/magnetometer/ak8975.c  | 197 ++++++++++++++++++++--
>  4 files changed, 186 insertions(+), 353 deletions(-)
>  delete mode 100644 drivers/iio/magnetometer/ak09911.c
> 
> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
> index b2dba9e..4c7a4c5 100644
> --- a/drivers/iio/magnetometer/Kconfig
> +++ b/drivers/iio/magnetometer/Kconfig
> @@ -6,26 +6,21 @@
>  menu "Magnetometer sensors"
>  
>  config AK8975
> -	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
> +	tristate "Asahi Kasei AK 3-Axis Magnetometer"
>  	depends on I2C
>  	depends on GPIOLIB
>  	help
> -	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
> -	  Magnetometer. This driver can also support AK8963, if i2c
> -	  device name is identified as ak8963.
> +	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
> +	  AK09911 or AK09912 3-Axis Magnetometer.
>  
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called ak8975.
>  
>  config AK09911
>  	tristate "Asahi Kasei AK09911 3-axis Compass"
> -	depends on I2C
> +	select AK8975
>  	help
> -	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
> -	  Magnetometer.
> -
> -	  To compile this driver as a module, choose M here: the module
> -	  will be called ak09911.
> +	  Deprecated: AK09911 is now supported by AK8975 driver.
>  
>  config MAG3110
>  	tristate "Freescale MAG3110 3-Axis Magnetometer"
> diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
> index b91315e..0f5d3c9 100644
> --- a/drivers/iio/magnetometer/Makefile
> +++ b/drivers/iio/magnetometer/Makefile
> @@ -3,7 +3,6 @@
>  #
>  
>  # When adding new entries keep the list in alphabetical order
> -obj-$(CONFIG_AK09911)	+= ak09911.o
>  obj-$(CONFIG_AK8975)	+= ak8975.o
>  obj-$(CONFIG_MAG3110)	+= mag3110.o
>  obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
> diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
> deleted file mode 100644
> index b2bc942..0000000
> --- a/drivers/iio/magnetometer/ak09911.c
> +++ /dev/null
> @@ -1,326 +0,0 @@
> -/*
> - * AK09911 3-axis compass driver
> - * Copyright (c) 2014, 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.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/types.h>
> -#include <linux/slab.h>
> -#include <linux/delay.h>
> -#include <linux/i2c.h>
> -#include <linux/acpi.h>
> -#include <linux/iio/iio.h>
> -
> -#define AK09911_REG_WIA1		0x00
> -#define AK09911_REG_WIA2		0x01
> -#define AK09911_WIA1_VALUE		0x48
> -#define AK09911_WIA2_VALUE		0x05
> -
> -#define AK09911_REG_ST1			0x10
> -#define AK09911_REG_HXL			0x11
> -#define AK09911_REG_HXH			0x12
> -#define AK09911_REG_HYL			0x13
> -#define AK09911_REG_HYH			0x14
> -#define AK09911_REG_HZL			0x15
> -#define AK09911_REG_HZH			0x16
> -
> -#define AK09911_REG_ASAX		0x60
> -#define AK09911_REG_ASAY		0x61
> -#define AK09911_REG_ASAZ		0x62
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_MODE_SNG_MEASURE	0x01
> -#define AK09911_MODE_SELF_TEST		0x10
> -#define AK09911_MODE_FUSE_ACCESS	0x1F
> -#define AK09911_MODE_POWERDOWN		0x00
> -#define AK09911_RESET_DATA		0x01
> -
> -#define AK09911_REG_CNTL1		0x30
> -#define AK09911_REG_CNTL2		0x31
> -#define AK09911_REG_CNTL3		0x32
> -
> -#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
> -
> -#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
> -#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
> -
> -struct ak09911_data {
> -	struct i2c_client	*client;
> -	struct mutex		lock;
> -	u8			asa[3];
> -	long			raw_to_gauss[3];
> -};
> -
> -static const int ak09911_index_to_reg[] = {
> -	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
> -};
> -
> -static int ak09911_set_mode(struct i2c_client *client, u8 mode)
> -{
> -	int ret;
> -
> -	switch (mode) {
> -	case AK09911_MODE_SNG_MEASURE:
> -	case AK09911_MODE_SELF_TEST:
> -	case AK09911_MODE_FUSE_ACCESS:
> -	case AK09911_MODE_POWERDOWN:
> -		ret = i2c_smbus_write_byte_data(client,
> -						AK09911_REG_CNTL2, mode);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "set_mode error\n");
> -			return ret;
> -		}
> -		/* After mode change wait atleast 100us */
> -		usleep_range(100, 500);
> -		break;
> -	default:
> -		dev_err(&client->dev,
> -			"%s: Unknown mode(%d).", __func__, mode);
> -		return -EINVAL;
> -	}
> -
> -	return ret;
> -}
> -
> -/* Get Sensitivity Adjustment value */
> -static int ak09911_get_asa(struct i2c_client *client)
> -{
> -	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	int ret;
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
> -	if (ret < 0)
> -		return ret;
> -
> -	/* Get asa data and store in the device data. */
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
> -					    3, data->asa);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Not able to read asa data\n");
> -		return ret;
> -	}
> -
> -	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
> -	if (ret < 0)
> -		return ret;
> -
> -	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
> -	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
> -	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
> -
> -	return 0;
> -}
> -
> -static int ak09911_verify_chip_id(struct i2c_client *client)
> -{
> -	u8 wia_val[2];
> -	int ret;
> -
> -	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
> -					    2, wia_val);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -
> -	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
> -
> -	if (wia_val[0] != AK09911_WIA1_VALUE ||
> -		wia_val[1] != AK09911_WIA2_VALUE) {
> -		dev_err(&client->dev, "Device ak09911 not found\n");
> -		return -ENODEV;
> -	}
> -
> -	return 0;
> -}
> -
> -static int wait_conversion_complete_polled(struct ak09911_data *data)
> -{
> -	struct i2c_client *client = data->client;
> -	u8 read_status;
> -	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
> -	int ret;
> -
> -	/* Wait for the conversion to complete. */
> -	while (timeout_ms) {
> -		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
> -		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "Error in reading ST1\n");
> -			return ret;
> -		}
> -		read_status = ret & 0x01;
> -		if (read_status)
> -			break;
> -		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
> -	}
> -	if (!timeout_ms) {
> -		dev_err(&client->dev, "Conversion timeout happened\n");
> -		return -EIO;
> -	}
> -
> -	return read_status;
> -}
> -
> -static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -	struct i2c_client *client = data->client;
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -
> -	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	ret = wait_conversion_complete_polled(data);
> -	if (ret < 0)
> -		goto fn_exit;
> -
> -	/* Read data */
> -	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Read axis data fails\n");
> -		goto fn_exit;
> -	}
> -
> -	mutex_unlock(&data->lock);
> -
> -	/* Clamp to valid range. */
> -	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
> -
> -	return IIO_VAL_INT;
> -
> -fn_exit:
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static int ak09911_read_raw(struct iio_dev *indio_dev,
> -			    struct iio_chan_spec const *chan,
> -			    int *val, int *val2,
> -			    long mask)
> -{
> -	struct ak09911_data *data = iio_priv(indio_dev);
> -
> -	switch (mask) {
> -	case IIO_CHAN_INFO_RAW:
> -		return ak09911_read_axis(indio_dev, chan->address, val);
> -	case IIO_CHAN_INFO_SCALE:
> -		*val = 0;
> -		*val2 = data->raw_to_gauss[chan->address];
> -		return IIO_VAL_INT_PLUS_MICRO;
> -	}
> -
> -	return -EINVAL;
> -}
> -
> -#define AK09911_CHANNEL(axis, index)					\
> -	{								\
> -		.type = IIO_MAGN,					\
> -		.modified = 1,						\
> -		.channel2 = IIO_MOD_##axis,				\
> -		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
> -			     BIT(IIO_CHAN_INFO_SCALE),			\
> -		.address = index,					\
> -	}
> -
> -static const struct iio_chan_spec ak09911_channels[] = {
> -	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
> -};
> -
> -static const struct iio_info ak09911_info = {
> -	.read_raw = &ak09911_read_raw,
> -	.driver_module = THIS_MODULE,
> -};
> -
> -static const struct acpi_device_id ak_acpi_match[] = {
> -	{"AK009911", 0},
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> -
> -static int ak09911_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> -{
> -	struct iio_dev *indio_dev;
> -	struct ak09911_data *data;
> -	const char *name;
> -	int ret;
> -
> -	ret = ak09911_verify_chip_id(client);
> -	if (ret) {
> -		dev_err(&client->dev, "AK00911 not detected\n");
> -		return -ENODEV;
> -	}
> -
> -	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> -	if (indio_dev == NULL)
> -		return -ENOMEM;
> -
> -	data = iio_priv(indio_dev);
> -	i2c_set_clientdata(client, indio_dev);
> -
> -	data->client = client;
> -	mutex_init(&data->lock);
> -
> -	ret = ak09911_get_asa(client);
> -	if (ret)
> -		return ret;
> -
> -	if (id)
> -		name = id->name;
> -	else if (ACPI_HANDLE(&client->dev))
> -		name = dev_name(&client->dev);
> -	else
> -		return -ENODEV;
> -
> -	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
> -
> -	indio_dev->dev.parent = &client->dev;
> -	indio_dev->channels = ak09911_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
> -	indio_dev->info = &ak09911_info;
> -	indio_dev->modes = INDIO_DIRECT_MODE;
> -	indio_dev->name = name;
> -
> -	return devm_iio_device_register(&client->dev, indio_dev);
> -}
> -
> -static const struct i2c_device_id ak09911_id[] = {
> -	{"ak09911", 0},
> -	{}
> -};
> -
> -MODULE_DEVICE_TABLE(i2c, ak09911_id);
> -
> -static struct i2c_driver ak09911_driver = {
> -	.driver = {
> -		.name	= "ak09911",
> -		.acpi_match_table = ACPI_PTR(ak_acpi_match),
> -	},
> -	.probe		= ak09911_probe,
> -	.id_table	= ak09911_id,
> -};
> -module_i2c_driver(ak09911_driver);
> -
> -MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
> -MODULE_LICENSE("GPL v2");
> -MODULE_DESCRIPTION("AK09911 Compass driver");
> diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
> index b170654..f8c7046 100644
> --- a/drivers/iio/magnetometer/ak8975.c
> +++ b/drivers/iio/magnetometer/ak8975.c
> @@ -81,6 +81,58 @@
>  #define AK8975_MAX_REGS			AK8975_REG_ASAZ
>  
>  /*
> + * AK09912 Register definitions
> + */
> +#define AK09912_REG_WIA1		0x00
> +#define AK09912_REG_WIA2		0x01
> +#define AK09912_DEVICE_ID		0x04
> +#define AK09911_DEVICE_ID		0x05
> +
> +#define AK09911_REG_INFO1		0x02
> +#define AK09911_REG_INFO2		0x03
> +
> +#define AK09912_REG_ST1			0x10
> +
> +#define AK09912_REG_ST1_DRDY_SHIFT	0
> +#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
> +
> +#define AK09912_REG_HXL			0x11
> +#define AK09912_REG_HXH			0x12
> +#define AK09912_REG_HYL			0x13
> +#define AK09912_REG_HYH			0x14
> +#define AK09912_REG_HZL			0x15
> +#define AK09912_REG_HZH			0x16
> +#define AK09912_REG_TMPS		0x17
> +
> +#define AK09912_REG_ST2			0x18
> +#define AK09912_REG_ST2_HOFL_SHIFT	3
> +#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
> +
> +#define AK09912_REG_CNTL1		0x30
> +
> +#define AK09912_REG_CNTL2		0x31
> +#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
> +#define AK09912_REG_CNTL_MODE_ONCE	0x01
> +#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
> +#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
> +#define AK09912_REG_CNTL2_MODE_SHIFT	0
> +#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
> +
> +#define AK09912_REG_CNTL3		0x32
> +
> +#define AK09912_REG_TS1			0x33
> +#define AK09912_REG_TS2			0x34
> +#define AK09912_REG_TS3			0x35
> +#define AK09912_REG_I2CDIS		0x36
> +#define AK09912_REG_TS4			0x37
> +
> +#define AK09912_REG_ASAX		0x60
> +#define AK09912_REG_ASAY		0x61
> +#define AK09912_REG_ASAZ		0x62
> +
> +#define AK09912_MAX_REGS		AK09912_REG_ASAZ
> +
> +/*
>   * Miscellaneous values.
>   */
>  #define AK8975_MAX_CONVERSION_TIMEOUT	500
> @@ -130,22 +182,37 @@ long ak8975_raw_to_gauss(u16 data)
>  }
>  
>  /*
> - * For AK8963, same calculation, but the device is less sensitive:
> + * For AK8963 and AK09911, same calculation, but the device is less sensitive:
>   *
>   * H is in the range of +-8190.  The magnetometer has a range of
>   * +-4912uT.  To go from the raw value to uT is:
>   *
>   * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
>   */
> -long ak8963_raw_to_gauss(u16 data)
> +long ak8963_09911_raw_to_gauss(u16 data)
>  {
>  	return (((long)data + 128) * 6000) / 256;
>  }
>  
> +/*
> + * For AK09912, same calculation, except the device is more sensitive:
> + *
> + * H is in the range of -32752 to 32752.  The magnetometer has a range of
> + * +-4912uT.  To go from the raw value to uT is:
> + *
> + * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
> + */
> +long ak09912_raw_to_gauss(u16 data)
> +{
> +	return (((long)data + 128) * 1500) / 256;
> +}
> +
>  /* Compatible Asahi Kasei Compass parts */
>  enum asahi_compass_chipset {
>  	AK8975,
>  	AK8963,
> +	AK09911,
> +	AK09912,
>  	AK_MAX_TYPE
>  };
>  
> @@ -210,7 +277,7 @@ struct ak_def {
>  },
>  {
>  	.type = AK8963,
> -	.raw_to_gauss = ak8963_raw_to_gauss,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
>  	.range = 8190,
>  	.ctrl_regs = {
>  		AK8975_REG_ST1,
> @@ -233,6 +300,56 @@ struct ak_def {
>  		AK8975_REG_HYL,
>  		AK8975_REG_HZL},
>  },
> +{
> +	.type = AK09911,
> +	.raw_to_gauss = ak8963_09911_raw_to_gauss,
> +	.range = 8192,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +},
> +{
> +	.type = AK09912,
> +	.raw_to_gauss = ak09912_raw_to_gauss,
> +	.range = 32752,
> +	.ctrl_regs = {
> +		AK09912_REG_ST1,
> +		AK09912_REG_ST2,
> +		AK09912_REG_CNTL2,
> +		AK09912_REG_ASAX,
> +		AK09912_MAX_REGS},
> +	.ctrl_masks = {
> +		AK09912_REG_ST1_DRDY_MASK,
> +		AK09912_REG_ST2_HOFL_MASK,
> +		0,
> +		AK09912_REG_CNTL2_MODE_MASK},
> +	.ctrl_modes = {
> +		AK09912_REG_CNTL_MODE_POWER_DOWN,
> +		AK09912_REG_CNTL_MODE_ONCE,
> +		AK09912_REG_CNTL_MODE_SELF_TEST,
> +		AK09912_REG_CNTL_MODE_FUSE_ROM},
> +	.data_regs = {
> +		AK09912_REG_HXL,
> +		AK09912_REG_HYL,
> +		AK09912_REG_HZL},
> +}
>  };
>  
>  /*
> @@ -253,6 +370,55 @@ struct ak8975_data {
>  };
>  
>  /*
> + * Return 0 if the i2c device is the one we expect.
> + * return a negative error number otherwise
> + */
> +static int ak8975_who_i_am(struct i2c_client *client,
> +			   enum asahi_compass_chipset type)
> +{
> +	u8 wia_val[2];
> +	int ret;
> +
> +	/*
> +	 * Signature for each device:
> +	 * Device   |  WIA1      |  WIA2
> +	 * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
> +	 * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
> +	 * AK8975   |  DEVICE_ID |  NA
> +	 * AK8963   |  DEVICE_ID |  NA
> +	 */
> +	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
> +					    2, wia_val);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Error reading WIA\n");
> +		return ret;
> +	}
> +
> +	ret = -ENODEV;
I regard it more obvious to directly return values, instead of using variables in the following cases.
> +
> +	if (wia_val[0] != AK8975_DEVICE_ID)
> +		return ret;
return -ENODEV;
> +
> +	switch (type) {
> +	case AK8975:
> +	case AK8963:
> +		ret = 0;
> +		break;
return 0;
> +	case AK09911:
> +		if (wia_val[1] == AK09911_DEVICE_ID)
> +			ret = 0;
return 0;
> +		break;
> +	case AK09912:
> +		if (wia_val[1] == AK09912_DEVICE_ID)
> +			ret = 0;
return 0;
> +		break;
> +	default:
> +		dev_err(&client->dev, "Type %d unknown\n", type);
> +	}
> +	return ret;
return -ENODEV;
> +}
> +
> +/*
>   * Helper function to write to CNTL register.
>   */
>  static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
> @@ -327,21 +493,8 @@ static int ak8975_setup(struct i2c_client *client)
>  {
>  	struct iio_dev *indio_dev = i2c_get_clientdata(client);
>  	struct ak8975_data *data = iio_priv(indio_dev);
> -	u8 device_id;
>  	int ret;
>  
> -	/* Confirm that the device we're talking to is really an AK8975. */
> -	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "Error reading WIA\n");
> -		return ret;
> -	}
> -	device_id = ret;
> -	if (device_id != AK8975_DEVICE_ID) {
> -		dev_err(&client->dev, "Device ak8975 not found\n");
> -		return -ENODEV;
> -	}
> -
>  	/* Write the fused rom access mode. */
>  	ret = ak8975_set_mode(data, FUSE_ROM);
>  	if (ret < 0) {
> @@ -552,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
>  	{"AK8975", AK8975},
>  	{"AK8963", AK8963},
>  	{"INVN6500", AK8963},
> +	{"AK09911", AK09911},
> +	{"AK09912", AK09912},
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
> @@ -631,6 +786,10 @@ static int ak8975_probe(struct i2c_client *client,
>  	}
>  
>  	data->def = &ak_def_array[chipset];
> +	if (ak8975_who_i_am(client, data->def->type) < 0) {
> +		dev_err(&client->dev, "Unexpected device\n");
> +		return -ENODEV;
> +	}
I would prefer to pass up the error code from ak8975_who_am_i().
>  	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
>  
>  	/* Perform some basic start-of-day setup of the device. */
> @@ -653,6 +812,8 @@ static int ak8975_probe(struct i2c_client *client,
>  static const struct i2c_device_id ak8975_id[] = {
>  	{"ak8975", AK8975},
>  	{"ak8963", AK8963},
> +	{"ak09911", AK09911},
> +	{"ak09912", AK09912},
>  	{}
>  };
>  
> @@ -663,6 +824,10 @@ static const struct of_device_id ak8975_of_match[] = {
>  	{ .compatible = "ak8975", },
>  	{ .compatible = "asahi-kasei,ak8963", },
>  	{ .compatible = "ak8963", },
> +	{ .compatible = "asahi-kasei,ak09911", },
> +	{ .compatible = "ak09911", },
> +	{ .compatible = "asahi-kasei,ak09912", },
> +	{ .compatible = "ak09912", },
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, ak8975_of_match);
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2014-11-19 11:39 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-29 22:01 [PATCH 0/1] iio: ak8975: Add AKM0991x support Gwendal Grignou
2014-10-29 22:01 ` [PATCH] " Gwendal Grignou
2014-11-03 22:22   ` Hartmut Knaack
2014-11-04 19:41     ` [PATCHv2] " Gwendal Grignou
2014-11-05 14:31       ` Jonathan Cameron
2014-11-05 21:19         ` Gwendal Grignou
2014-11-05 22:10           ` [PATCH 0/3] Support all AKM compass in a single driver Gwendal Grignou
2014-11-05 22:10             ` [PATCH 1/3] iio: ak8975: minor fixes Gwendal Grignou
2014-11-06 15:00               ` Srinivas Pandruvada
2014-11-17 20:13               ` [PATCH v2 " Gwendal Grignou
2014-11-19 11:16                 ` Hartmut Knaack
2014-11-05 22:10             ` [PATCH 2/3] iio: ak8975: add definition structure per compass type Gwendal Grignou
2014-11-06 15:02               ` Srinivas Pandruvada
2014-11-06 21:16                 ` Gwendal Grignou
2014-11-19 11:25               ` Hartmut Knaack
2014-11-05 22:10             ` [PATCH 3/3] iio: ak8975: add ak09911 and ak09912 support Gwendal Grignou
2014-11-06 15:05               ` Srinivas Pandruvada
2014-11-06 21:25                 ` Gwendal Grignou
2014-11-17 18:02                   ` Srinivas Pandruvada
2014-11-17 20:15                     ` Gwendal Grignou
2014-11-17 20:36                       ` Srinivas Pandruvada
2014-11-19 11:39                   ` Hartmut Knaack
2014-11-08 12:16                 ` Jonathan Cameron
2014-11-14  9:01                   ` Gwendal Grignou
2014-11-06 14:32           ` [PATCHv2] iio: ak8975: Add AKM0991x support Srinivas Pandruvada
2014-11-08 12:17             ` Jonathan Cameron
2014-10-31 15:21 ` [PATCH 0/1] " Srinivas Pandruvada
2014-11-01 21:03   ` Gwendal Grignou

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.