aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/magnetometer
diff options
context:
space:
mode:
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>2014-11-06 18:06:00 -0500
committerJonathan Cameron <jic23@kernel.org>2014-06-16 15:55:24 -0400
commitd14c0f10e71c174cc312fb77832450bd02171be5 (patch)
tree38372546dc76d1ed16a5c3d932485bd6cfd2d175 /drivers/iio/magnetometer
parent1a4fbf6a9286a6e3db497bc7bbae2024f0f1ad90 (diff)
iio: AK09911 : 3 axis compass support
Added IIO magnetometer driver for AK09911. In functionality is resembles AK8975 or AK8963. But there are several differences, so instead of modifying existing AK8975 driver and keep it clean, implemented as a separate driver. The key differences are: - 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 Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/magnetometer')
-rw-r--r--drivers/iio/magnetometer/Kconfig10
-rw-r--r--drivers/iio/magnetometer/Makefile1
-rw-r--r--drivers/iio/magnetometer/ak09911.c326
3 files changed, 337 insertions, 0 deletions
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index 05a364c543f8..b2dba9e506ab 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -17,6 +17,16 @@ config AK8975
17 To compile this driver as a module, choose M here: the module 17 To compile this driver as a module, choose M here: the module
18 will be called ak8975. 18 will be called ak8975.
19 19
20config AK09911
21 tristate "Asahi Kasei AK09911 3-axis Compass"
22 depends on I2C
23 help
24 Say yes here to build support for Asahi Kasei AK09911 3-Axis
25 Magnetometer.
26
27 To compile this driver as a module, choose M here: the module
28 will be called ak09911.
29
20config MAG3110 30config MAG3110
21 tristate "Freescale MAG3110 3-Axis Magnetometer" 31 tristate "Freescale MAG3110 3-Axis Magnetometer"
22 depends on I2C 32 depends on I2C
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 0f5d3c985799..b91315e0b826 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5# When adding new entries keep the list in alphabetical order 5# When adding new entries keep the list in alphabetical order
6obj-$(CONFIG_AK09911) += ak09911.o
6obj-$(CONFIG_AK8975) += ak8975.o 7obj-$(CONFIG_AK8975) += ak8975.o
7obj-$(CONFIG_MAG3110) += mag3110.o 8obj-$(CONFIG_MAG3110) += mag3110.o
8obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o 9obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
new file mode 100644
index 000000000000..b2bc942ff6b8
--- /dev/null
+++ b/drivers/iio/magnetometer/ak09911.c
@@ -0,0 +1,326 @@
1/*
2 * AK09911 3-axis compass driver
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/types.h>
19#include <linux/slab.h>
20#include <linux/delay.h>
21#include <linux/i2c.h>
22#include <linux/acpi.h>
23#include <linux/iio/iio.h>
24
25#define AK09911_REG_WIA1 0x00
26#define AK09911_REG_WIA2 0x01
27#define AK09911_WIA1_VALUE 0x48
28#define AK09911_WIA2_VALUE 0x05
29
30#define AK09911_REG_ST1 0x10
31#define AK09911_REG_HXL 0x11
32#define AK09911_REG_HXH 0x12
33#define AK09911_REG_HYL 0x13
34#define AK09911_REG_HYH 0x14
35#define AK09911_REG_HZL 0x15
36#define AK09911_REG_HZH 0x16
37
38#define AK09911_REG_ASAX 0x60
39#define AK09911_REG_ASAY 0x61
40#define AK09911_REG_ASAZ 0x62
41
42#define AK09911_REG_CNTL1 0x30
43#define AK09911_REG_CNTL2 0x31
44#define AK09911_REG_CNTL3 0x32
45
46#define AK09911_MODE_SNG_MEASURE 0x01
47#define AK09911_MODE_SELF_TEST 0x10
48#define AK09911_MODE_FUSE_ACCESS 0x1F
49#define AK09911_MODE_POWERDOWN 0x00
50#define AK09911_RESET_DATA 0x01
51
52#define AK09911_REG_CNTL1 0x30
53#define AK09911_REG_CNTL2 0x31
54#define AK09911_REG_CNTL3 0x32
55
56#define AK09911_RAW_TO_GAUSS(asa) ((((asa) + 128) * 6000) / 256)
57
58#define AK09911_MAX_CONVERSION_TIMEOUT_MS 500
59#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
60
61struct ak09911_data {
62 struct i2c_client *client;
63 struct mutex lock;
64 u8 asa[3];
65 long raw_to_gauss[3];
66};
67
68static const int ak09911_index_to_reg[] = {
69 AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
70};
71
72static int ak09911_set_mode(struct i2c_client *client, u8 mode)
73{
74 int ret;
75
76 switch (mode) {
77 case AK09911_MODE_SNG_MEASURE:
78 case AK09911_MODE_SELF_TEST:
79 case AK09911_MODE_FUSE_ACCESS:
80 case AK09911_MODE_POWERDOWN:
81 ret = i2c_smbus_write_byte_data(client,
82 AK09911_REG_CNTL2, mode);
83 if (ret < 0) {
84 dev_err(&client->dev, "set_mode error\n");
85 return ret;
86 }
87 /* After mode change wait atleast 100us */
88 usleep_range(100, 500);
89 break;
90 default:
91 dev_err(&client->dev,
92 "%s: Unknown mode(%d).", __func__, mode);
93 return -EINVAL;
94 }
95
96 return ret;
97}
98
99/* Get Sensitivity Adjustment value */
100static int ak09911_get_asa(struct i2c_client *client)
101{
102 struct iio_dev *indio_dev = i2c_get_clientdata(client);
103 struct ak09911_data *data = iio_priv(indio_dev);
104 int ret;
105
106 ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
107 if (ret < 0)
108 return ret;
109
110 /* Get asa data and store in the device data. */
111 ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
112 3, data->asa);
113 if (ret < 0) {
114 dev_err(&client->dev, "Not able to read asa data\n");
115 return ret;
116 }
117
118 ret = ak09911_set_mode(client, AK09911_MODE_POWERDOWN);
119 if (ret < 0)
120 return ret;
121
122 data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
123 data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
124 data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
125
126 return 0;
127}
128
129static int ak09911_verify_chip_id(struct i2c_client *client)
130{
131 u8 wia_val[2];
132 int ret;
133
134 ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
135 2, wia_val);
136 if (ret < 0) {
137 dev_err(&client->dev, "Error reading WIA\n");
138 return ret;
139 }
140
141 dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
142
143 if (wia_val[0] != AK09911_WIA1_VALUE ||
144 wia_val[1] != AK09911_WIA2_VALUE) {
145 dev_err(&client->dev, "Device ak09911 not found\n");
146 return -ENODEV;
147 }
148
149 return 0;
150}
151
152static int wait_conversion_complete_polled(struct ak09911_data *data)
153{
154 struct i2c_client *client = data->client;
155 u8 read_status;
156 u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
157 int ret;
158
159 /* Wait for the conversion to complete. */
160 while (timeout_ms) {
161 msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
162 ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
163 if (ret < 0) {
164 dev_err(&client->dev, "Error in reading ST1\n");
165 return ret;
166 }
167 read_status = ret & 0x01;
168 if (read_status)
169 break;
170 timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
171 }
172 if (!timeout_ms) {
173 dev_err(&client->dev, "Conversion timeout happened\n");
174 return -EIO;
175 }
176
177 return read_status;
178}
179
180static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
181{
182 struct ak09911_data *data = iio_priv(indio_dev);
183 struct i2c_client *client = data->client;
184 int ret;
185
186 mutex_lock(&data->lock);
187
188 ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
189 if (ret < 0)
190 goto fn_exit;
191
192 ret = wait_conversion_complete_polled(data);
193 if (ret < 0)
194 goto fn_exit;
195
196 /* Read data */
197 ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
198 if (ret < 0) {
199 dev_err(&client->dev, "Read axis data fails\n");
200 goto fn_exit;
201 }
202
203 mutex_unlock(&data->lock);
204
205 /* Clamp to valid range. */
206 *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
207
208 return IIO_VAL_INT;
209
210fn_exit:
211 mutex_unlock(&data->lock);
212
213 return ret;
214}
215
216static int ak09911_read_raw(struct iio_dev *indio_dev,
217 struct iio_chan_spec const *chan,
218 int *val, int *val2,
219 long mask)
220{
221 struct ak09911_data *data = iio_priv(indio_dev);
222
223 switch (mask) {
224 case IIO_CHAN_INFO_RAW:
225 return ak09911_read_axis(indio_dev, chan->address, val);
226 case IIO_CHAN_INFO_SCALE:
227 *val = 0;
228 *val2 = data->raw_to_gauss[chan->address];
229 return IIO_VAL_INT_PLUS_MICRO;
230 }
231
232 return -EINVAL;
233}
234
235#define AK09911_CHANNEL(axis, index) \
236 { \
237 .type = IIO_MAGN, \
238 .modified = 1, \
239 .channel2 = IIO_MOD_##axis, \
240 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
241 BIT(IIO_CHAN_INFO_SCALE), \
242 .address = index, \
243 }
244
245static const struct iio_chan_spec ak09911_channels[] = {
246 AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
247};
248
249static const struct iio_info ak09911_info = {
250 .read_raw = &ak09911_read_raw,
251 .driver_module = THIS_MODULE,
252};
253
254static const struct acpi_device_id ak_acpi_match[] = {
255 {"AK009911", 0},
256 { },
257};
258MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
259
260static int ak09911_probe(struct i2c_client *client,
261 const struct i2c_device_id *id)
262{
263 struct iio_dev *indio_dev;
264 struct ak09911_data *data;
265 const char *name;
266 int ret;
267
268 ret = ak09911_verify_chip_id(client);
269 if (ret) {
270 dev_err(&client->dev, "AK00911 not detected\n");
271 return -ENODEV;
272 }
273
274 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
275 if (indio_dev == NULL)
276 return -ENOMEM;
277
278 data = iio_priv(indio_dev);
279 i2c_set_clientdata(client, indio_dev);
280
281 data->client = client;
282 mutex_init(&data->lock);
283
284 ret = ak09911_get_asa(client);
285 if (ret)
286 return ret;
287
288 if (id)
289 name = id->name;
290 else if (ACPI_HANDLE(&client->dev))
291 name = dev_name(&client->dev);
292 else
293 return -ENODEV;
294
295 dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
296
297 indio_dev->dev.parent = &client->dev;
298 indio_dev->channels = ak09911_channels;
299 indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
300 indio_dev->info = &ak09911_info;
301 indio_dev->modes = INDIO_DIRECT_MODE;
302 indio_dev->name = name;
303
304 return devm_iio_device_register(&client->dev, indio_dev);
305}
306
307static const struct i2c_device_id ak09911_id[] = {
308 {"ak09911", 0},
309 {}
310};
311
312MODULE_DEVICE_TABLE(i2c, ak09911_id);
313
314static struct i2c_driver ak09911_driver = {
315 .driver = {
316 .name = "ak09911",
317 .acpi_match_table = ACPI_PTR(ak_acpi_match),
318 },
319 .probe = ak09911_probe,
320 .id_table = ak09911_id,
321};
322module_i2c_driver(ak09911_driver);
323
324MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
325MODULE_LICENSE("GPL v2");
326MODULE_DESCRIPTION("AK09911 Compass driver");