aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Mirosław <mirq-linux@rere.qmqm.pl>2017-08-17 09:56:10 -0400
committerJonathan Cameron <Jonathan.Cameron@huawei.com>2017-08-20 06:18:33 -0400
commit21be26fc6786a674b7b10f50ba29e4459cbd1aa8 (patch)
tree49c20ff44b6f9b17cbcc5898075829eac4808d15
parent3282fa3c0a108ac21b4c5a4818e70f510d582676 (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/Kconfig4
-rw-r--r--drivers/iio/magnetometer/ak8974.c90
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 {
158static const char ak8974_reg_avdd[] = "avdd"; 188static const char ak8974_reg_avdd[] = "avdd";
159static const char ak8974_reg_dvdd[] = "dvdd"; 189static const char ak8974_reg_dvdd[] = "dvdd";
160 190
191static 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
204static 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
161static int ak8974_set_power(struct ak8974 *ak8974, bool mode) 211static 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
391static 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
404static int ak8974_detect(struct ak8974 *ak8974) 447static 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
828static const struct i2c_device_id ak8974_id[] = { 877static 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};
851module_i2c_driver(ak8974_driver); 901module_i2c_driver(ak8974_driver);
852 902
853MODULE_DESCRIPTION("AK8974 and AMI305 3-axis magnetometer driver"); 903MODULE_DESCRIPTION("AK8974 and AMI30x 3-axis magnetometer driver");
854MODULE_AUTHOR("Samu Onkalo"); 904MODULE_AUTHOR("Samu Onkalo");
855MODULE_AUTHOR("Linus Walleij"); 905MODULE_AUTHOR("Linus Walleij");
856MODULE_LICENSE("GPL v2"); 906MODULE_LICENSE("GPL v2");