diff options
author | Michał Mirosław <mirq-linux@rere.qmqm.pl> | 2017-08-17 09:56:10 -0400 |
---|---|---|
committer | Jonathan Cameron <Jonathan.Cameron@huawei.com> | 2017-08-20 06:18:33 -0400 |
commit | 21be26fc6786a674b7b10f50ba29e4459cbd1aa8 (patch) | |
tree | 49c20ff44b6f9b17cbcc5898075829eac4808d15 | |
parent | 3282fa3c0a108ac21b4c5a4818e70f510d582676 (diff) |
iio: magnetometer: ak8974: support AMI306 variant
Add support for AMI306 magnetometer - very similar to AMI305.
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
-rw-r--r-- | drivers/iio/magnetometer/Kconfig | 4 | ||||
-rw-r--r-- | drivers/iio/magnetometer/ak8974.c | 90 |
2 files changed, 72 insertions, 22 deletions
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 421ad90a5fbe..ed9d776d01af 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig | |||
@@ -13,8 +13,8 @@ config AK8974 | |||
13 | select IIO_BUFFER | 13 | select IIO_BUFFER |
14 | select IIO_TRIGGERED_BUFFER | 14 | select IIO_TRIGGERED_BUFFER |
15 | help | 15 | help |
16 | Say yes here to build support for Asahi Kasei AK8974 or | 16 | Say yes here to build support for Asahi Kasei AK8974, AMI305 or |
17 | AMI305 I2C-based 3-axis magnetometer chips. | 17 | AMI306 I2C-based 3-axis magnetometer chips. |
18 | 18 | ||
19 | To compile this driver as a module, choose M here: the module | 19 | To compile this driver as a module, choose M here: the module |
20 | will be called ak8974. | 20 | will be called ak8974. |
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index e13370dc9b1c..76091da20a0c 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c | |||
@@ -36,7 +36,7 @@ | |||
36 | * and MSB is at the next higher address. | 36 | * and MSB is at the next higher address. |
37 | */ | 37 | */ |
38 | 38 | ||
39 | /* These registers are common for AK8974 and AMI305 */ | 39 | /* These registers are common for AK8974 and AMI30x */ |
40 | #define AK8974_SELFTEST 0x0C | 40 | #define AK8974_SELFTEST 0x0C |
41 | #define AK8974_SELFTEST_IDLE 0x55 | 41 | #define AK8974_SELFTEST_IDLE 0x55 |
42 | #define AK8974_SELFTEST_OK 0xAA | 42 | #define AK8974_SELFTEST_OK 0xAA |
@@ -44,6 +44,7 @@ | |||
44 | #define AK8974_INFO 0x0D | 44 | #define AK8974_INFO 0x0D |
45 | 45 | ||
46 | #define AK8974_WHOAMI 0x0F | 46 | #define AK8974_WHOAMI 0x0F |
47 | #define AK8974_WHOAMI_VALUE_AMI306 0x46 | ||
47 | #define AK8974_WHOAMI_VALUE_AMI305 0x47 | 48 | #define AK8974_WHOAMI_VALUE_AMI305 0x47 |
48 | #define AK8974_WHOAMI_VALUE_AK8974 0x48 | 49 | #define AK8974_WHOAMI_VALUE_AK8974 0x48 |
49 | 50 | ||
@@ -73,6 +74,35 @@ | |||
73 | #define AK8974_TEMP 0x31 | 74 | #define AK8974_TEMP 0x31 |
74 | #define AMI305_TEMP 0x60 | 75 | #define AMI305_TEMP 0x60 |
75 | 76 | ||
77 | /* AMI306-specific control register */ | ||
78 | #define AMI306_CTRL4 0x5C | ||
79 | |||
80 | /* AMI306 factory calibration data */ | ||
81 | |||
82 | /* fine axis sensitivity */ | ||
83 | #define AMI306_FINEOUTPUT_X 0x90 | ||
84 | #define AMI306_FINEOUTPUT_Y 0x92 | ||
85 | #define AMI306_FINEOUTPUT_Z 0x94 | ||
86 | |||
87 | /* axis sensitivity */ | ||
88 | #define AMI306_SENS_X 0x96 | ||
89 | #define AMI306_SENS_Y 0x98 | ||
90 | #define AMI306_SENS_Z 0x9A | ||
91 | |||
92 | /* axis cross-interference */ | ||
93 | #define AMI306_GAIN_PARA_XZ 0x9C | ||
94 | #define AMI306_GAIN_PARA_XY 0x9D | ||
95 | #define AMI306_GAIN_PARA_YZ 0x9E | ||
96 | #define AMI306_GAIN_PARA_YX 0x9F | ||
97 | #define AMI306_GAIN_PARA_ZY 0xA0 | ||
98 | #define AMI306_GAIN_PARA_ZX 0xA1 | ||
99 | |||
100 | /* offset at ZERO magnetic field */ | ||
101 | #define AMI306_OFFZERO_X 0xF8 | ||
102 | #define AMI306_OFFZERO_Y 0xFA | ||
103 | #define AMI306_OFFZERO_Z 0xFC | ||
104 | |||
105 | |||
76 | #define AK8974_INT_X_HIGH BIT(7) /* Axis over +threshold */ | 106 | #define AK8974_INT_X_HIGH BIT(7) /* Axis over +threshold */ |
77 | #define AK8974_INT_Y_HIGH BIT(6) | 107 | #define AK8974_INT_Y_HIGH BIT(6) |
78 | #define AK8974_INT_Z_HIGH BIT(5) | 108 | #define AK8974_INT_Z_HIGH BIT(5) |
@@ -158,6 +188,26 @@ struct ak8974 { | |||
158 | static const char ak8974_reg_avdd[] = "avdd"; | 188 | static const char ak8974_reg_avdd[] = "avdd"; |
159 | static const char ak8974_reg_dvdd[] = "dvdd"; | 189 | static const char ak8974_reg_dvdd[] = "dvdd"; |
160 | 190 | ||
191 | static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val) | ||
192 | { | ||
193 | int ret; | ||
194 | __le16 bulk; | ||
195 | |||
196 | ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2); | ||
197 | if (ret) | ||
198 | return ret; | ||
199 | *val = le16_to_cpu(bulk); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int ak8974_set_u16_val(struct ak8974 *ak8974, u8 reg, u16 val) | ||
205 | { | ||
206 | __le16 bulk = cpu_to_le16(val); | ||
207 | |||
208 | return regmap_bulk_write(ak8974->map, reg, &bulk, 2); | ||
209 | } | ||
210 | |||
161 | static int ak8974_set_power(struct ak8974 *ak8974, bool mode) | 211 | static int ak8974_set_power(struct ak8974 *ak8974, bool mode) |
162 | { | 212 | { |
163 | int ret; | 213 | int ret; |
@@ -209,6 +259,12 @@ static int ak8974_configure(struct ak8974 *ak8974) | |||
209 | ret = regmap_write(ak8974->map, AK8974_CTRL3, 0); | 259 | ret = regmap_write(ak8974->map, AK8974_CTRL3, 0); |
210 | if (ret) | 260 | if (ret) |
211 | return ret; | 261 | return ret; |
262 | if (ak8974->variant == AK8974_WHOAMI_VALUE_AMI306) { | ||
263 | /* magic from datasheet: set high-speed measurement mode */ | ||
264 | ret = ak8974_set_u16_val(ak8974, AMI306_CTRL4, 0xA07E); | ||
265 | if (ret) | ||
266 | return ret; | ||
267 | } | ||
212 | ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL); | 268 | ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL); |
213 | if (ret) | 269 | if (ret) |
214 | return ret; | 270 | return ret; |
@@ -388,19 +444,6 @@ static int ak8974_selftest(struct ak8974 *ak8974) | |||
388 | return 0; | 444 | return 0; |
389 | } | 445 | } |
390 | 446 | ||
391 | static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val) | ||
392 | { | ||
393 | int ret; | ||
394 | __le16 bulk; | ||
395 | |||
396 | ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2); | ||
397 | if (ret) | ||
398 | return ret; | ||
399 | *val = le16_to_cpu(bulk); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int ak8974_detect(struct ak8974 *ak8974) | 447 | static int ak8974_detect(struct ak8974 *ak8974) |
405 | { | 448 | { |
406 | unsigned int whoami; | 449 | unsigned int whoami; |
@@ -413,9 +456,13 @@ static int ak8974_detect(struct ak8974 *ak8974) | |||
413 | if (ret) | 456 | if (ret) |
414 | return ret; | 457 | return ret; |
415 | 458 | ||
459 | name = "ami305"; | ||
460 | |||
416 | switch (whoami) { | 461 | switch (whoami) { |
462 | case AK8974_WHOAMI_VALUE_AMI306: | ||
463 | name = "ami306"; | ||
464 | /* fall-through */ | ||
417 | case AK8974_WHOAMI_VALUE_AMI305: | 465 | case AK8974_WHOAMI_VALUE_AMI305: |
418 | name = "ami305"; | ||
419 | ret = regmap_read(ak8974->map, AMI305_VER, &fw); | 466 | ret = regmap_read(ak8974->map, AMI305_VER, &fw); |
420 | if (ret) | 467 | if (ret) |
421 | return ret; | 468 | return ret; |
@@ -602,9 +649,11 @@ static bool ak8974_writeable_reg(struct device *dev, unsigned int reg) | |||
602 | case AMI305_OFFSET_Y + 1: | 649 | case AMI305_OFFSET_Y + 1: |
603 | case AMI305_OFFSET_Z: | 650 | case AMI305_OFFSET_Z: |
604 | case AMI305_OFFSET_Z + 1: | 651 | case AMI305_OFFSET_Z + 1: |
605 | if (ak8974->variant == AK8974_WHOAMI_VALUE_AMI305) | 652 | return ak8974->variant == AK8974_WHOAMI_VALUE_AMI305 || |
606 | return true; | 653 | ak8974->variant == AK8974_WHOAMI_VALUE_AMI306; |
607 | return false; | 654 | case AMI306_CTRL4: |
655 | case AMI306_CTRL4 + 1: | ||
656 | return ak8974->variant == AK8974_WHOAMI_VALUE_AMI306; | ||
608 | default: | 657 | default: |
609 | return false; | 658 | return false; |
610 | } | 659 | } |
@@ -678,7 +727,7 @@ static int ak8974_probe(struct i2c_client *i2c, | |||
678 | 727 | ||
679 | ret = ak8974_detect(ak8974); | 728 | ret = ak8974_detect(ak8974); |
680 | if (ret) { | 729 | if (ret) { |
681 | dev_err(&i2c->dev, "neither AK8974 nor AMI305 found\n"); | 730 | dev_err(&i2c->dev, "neither AK8974 nor AMI30x found\n"); |
682 | goto power_off; | 731 | goto power_off; |
683 | } | 732 | } |
684 | 733 | ||
@@ -827,6 +876,7 @@ static const struct dev_pm_ops ak8974_dev_pm_ops = { | |||
827 | 876 | ||
828 | static const struct i2c_device_id ak8974_id[] = { | 877 | static const struct i2c_device_id ak8974_id[] = { |
829 | {"ami305", 0 }, | 878 | {"ami305", 0 }, |
879 | {"ami306", 0 }, | ||
830 | {"ak8974", 0 }, | 880 | {"ak8974", 0 }, |
831 | {} | 881 | {} |
832 | }; | 882 | }; |
@@ -850,7 +900,7 @@ static struct i2c_driver ak8974_driver = { | |||
850 | }; | 900 | }; |
851 | module_i2c_driver(ak8974_driver); | 901 | module_i2c_driver(ak8974_driver); |
852 | 902 | ||
853 | MODULE_DESCRIPTION("AK8974 and AMI305 3-axis magnetometer driver"); | 903 | MODULE_DESCRIPTION("AK8974 and AMI30x 3-axis magnetometer driver"); |
854 | MODULE_AUTHOR("Samu Onkalo"); | 904 | MODULE_AUTHOR("Samu Onkalo"); |
855 | MODULE_AUTHOR("Linus Walleij"); | 905 | MODULE_AUTHOR("Linus Walleij"); |
856 | MODULE_LICENSE("GPL v2"); | 906 | MODULE_LICENSE("GPL v2"); |