diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-21 03:13:37 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-21 03:13:37 +0100 |
commit | 6e49557b316e8db983a6d40d18e88ab0ba8571ef (patch) | |
tree | ded6ad6cdaace89769d7a3464fd0170f4d4471b8 /drivers/iio/magnetometer/ak8975.c | |
parent | staging: fbtft: remove ARCH_BCM2708 optimization (diff) | |
parent | iio kmx61 / PM: Replace CONFIG_PM_RUNTIME with CONFIG_PM (diff) | |
download | linux-6e49557b316e8db983a6d40d18e88ab0ba8571ef.tar.xz linux-6e49557b316e8db983a6d40d18e88ab0ba8571ef.zip |
Merge tag 'iio-for-3.20a_take2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-testing
Jonathan writes:
First round of IIO new drivers, cleanups and functionality for the 3.20 cycle take 2
Updated pull request with Daniel's fix on top for the power management
Kconfig changes that had snuck in since last update of the IIO tree
worked it's way through from mainline.
Original pull message
New device support
* jsa1212 proxmity / ambient light sensor
* SM08500 supported added to the kxcjk-1013 accelerometer driver
* KMX61 Accelerometer/Magnetometer. This took a somewhat rocky path
being first merged, then reverted for a rewrite after a discussion of
how to support additional functionality and finally being merged prior
to some last reviews coming in, with resultant follow up patches.
* Freescale mma9551l driver (minor follow up warning supression patch).
* Semtech SX9500 proximity device driver.
* ak8975 gains support for ak09911 and ak09912 and drop the standalone driver
for the ak09911.
New functionality
* Dummy driver gains some virtual registers making it more flexible.
* IIO_ACTIVITY channel types, with modifiers running, walking etc. This is
to support on chip motion clasifiers. As such it is in the form of a
confidence percentage. The only devices so far only do binary decisions
but this gives us room when other devices give more nuanced clasification.
* IIO_EV_DIR_NONE type for events where there is no obvious direction.
First case is step detection.
* IIO_STEPS channel type for pedometers.
* ENABLE mask element used to control turning on counting types such as
the pedometer that need a 'start point'.
* INSTANCE event type to support things that happen once.
* info element for height calibration (used in various motion estimation
algorithms). Note heigh tof use
* dummy driver demonstration of the use of all the new bits above.
* event monitor support for the new events.
* inv_mpu6050 gains an i2c mux to allow bypassing the device to access
additional devices connected on the other side of it. Note that in
Windows these are handled by firmware on the device and not exposed
directly.
* inv_mpu6050 gains ACPI enumeration.
* inkern interface gains iio_write_channel_raw to allow in kernel users
of DAC functionality via a simple wrapper.
* Document input current readings in the ABI docs.
* Add an error message when we get an out of range error in device tree
processing for the in kernel interfaces. Basically a device tree debugging
aid.
* Add a sanity check that a scan index for a channel is unique during
registration. There to help catch bugs as this should never happen
in a bug free driver.
Cleanups and fixlets
A rework of buffer registration from Lars - a precursor to some other
upcoming new stuff (a few patches from others rolled in here as well).
* Ensure all drivers register the same channels for the device and buffer.
* Move buffer registration into the core rather than using the old
two step approach. Now we have simple ways of using a unified set channels
for both without requiring channels be exposed by both interface, this
removes a fair bit of boilerplate.
* Stop sca3000 and ad5933 (both in staging) enabling buffer channels by
default. It has long be convention in IIO to startup with no channels
enabled and leave it up to userspace to say what goes in the buffer.
Getting rid of these allows us to drop export of iio_scan_mask_set.
* Drop get_bytes_per_datum from iio_buffer_access_funcs as not been used
for a while.
* Allocate standard buffer attributes in the core rather than in every
driver with a buffer.
* Make the length attribute read only when a driver is not able to set
the length.
* Drop the get_length callback for buffers as it is already available in
struct iio_buffer.
* Drop an unused arguement form iio_kfifo_allocate and add devm allocator
for it.
* some kconfig entries gain anotation with the resulting module name.
* Fix a resulting compile issue in dummy driver due to a stub taking
wrong parameters as a result of the above rework.
* Fix an off by 2 error in copying the core assigned buffer attributes.
Other cleanups,
* Trivial space before comma fixups.
* ak8975 fixlets - none critical. Rework to allow more device support.
* Drop unnecessary sizeof(u8) calls.
* bmp280 - refactor the compensation code to reduce copy operations and
code length. A second patch futher optimized this and performed some
other minor cleanups.
* kxcjk-1013 - various power control cleanups to avoid unnecessary enable
/ disable of device. Make sure it is only controlled at all if CONFIG_PM
is enabled. Also som cleanups of error paths.
* Small cleanups in adf4530 driver - pointless message and unnecessary braces.
* Clarifiy the proximity ABI docs to make it clear it should get bigger
as we move futher away.
* Drop a misleading comment form industrialio-core.c
* Trivial white space cleanups.
* sca3000 looses an unused debug function.
* Fix char unsigned ordering in ad8366
* Increase the sleep time in ad9523 to make it predictable (value didn't
really matter so make it more than 20 msecs)
* mxs-lradc touchscreen property cleanups in device tree are fixed to ensure
the meet all the 'interesting' documentation.
* A couple of cleanups for the staging ad5933 driver to avoid unnecessary
conversion to a processed temperature vlaue in kernel and remove
platform data form the state structure as not needed after probe.
* Fix a wrong scale factor in the docs.
Misc
* Add IIO include files to the maintainers entry.
Diffstat (limited to 'drivers/iio/magnetometer/ak8975.c')
-rw-r--r-- | drivers/iio/magnetometer/ak8975.c | 504 |
1 files changed, 376 insertions, 128 deletions
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index bf5ef077e791..0d10a4baceb6 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 @@ -81,18 +81,278 @@ #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) + +/* + * 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. + */ +static 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. + */ + +static 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. + */ +static 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 +}; + +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]; +}; + +static struct ak_def 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_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}, + } }; /* @@ -100,40 +360,82 @@ 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; + 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 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; + } + + if (wia_val[0] != AK8975_DEVICE_ID) + return -ENODEV; + + switch (type) { + case AK8975: + case AK8963: + return 0; + case AK09911: + if (wia_val[1] == AK09911_DEVICE_ID) + return 0; + break; + case AK09912: + if (wia_val[1] == AK09912_DEVICE_ID) + return 0; + break; + default: + dev_err(&client->dev, "Type %d unknown\n", type); + } + return -ENODEV; +} /* - * 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; } @@ -166,8 +468,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", @@ -191,34 +493,18 @@ 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_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,13 +512,13 @@ 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; + } - 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,61 +527,9 @@ 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; } @@ -318,7 +552,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"); @@ -335,7 +569,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; @@ -378,11 +613,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; @@ -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: @@ -473,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); @@ -498,6 +732,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) @@ -537,42 +772,49 @@ 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]; + err = ak8975_who_i_am(client, data->def->type); + if (err < 0) { + dev_err(&client->dev, "Unexpected device\n"); + return err; + } dev_dbg(&client->dev, "Asahi compass chip %s\n", name); /* 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[] = { {"ak8975", AK8975}, {"ak8963", AK8963}, + {"ak09911", AK09911}, + {"ak09912", AK09912}, {} }; @@ -581,14 +823,20 @@ 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", }, + { .compatible = "asahi-kasei,ak09911", }, + { .compatible = "ak09911", }, + { .compatible = "asahi-kasei,ak09912", }, + { .compatible = "ak09912", }, + {} }; 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, |