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>
This commit is contained in:
parent
3282fa3c0a
commit
21be26fc67
@ -13,8 +13,8 @@ config AK8974
|
|||||||
select IIO_BUFFER
|
select IIO_BUFFER
|
||||||
select IIO_TRIGGERED_BUFFER
|
select IIO_TRIGGERED_BUFFER
|
||||||
help
|
help
|
||||||
Say yes here to build support for Asahi Kasei AK8974 or
|
Say yes here to build support for Asahi Kasei AK8974, AMI305 or
|
||||||
AMI305 I2C-based 3-axis magnetometer chips.
|
AMI306 I2C-based 3-axis magnetometer chips.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called ak8974.
|
will be called ak8974.
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
* and MSB is at the next higher address.
|
* and MSB is at the next higher address.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* These registers are common for AK8974 and AMI305 */
|
/* These registers are common for AK8974 and AMI30x */
|
||||||
#define AK8974_SELFTEST 0x0C
|
#define AK8974_SELFTEST 0x0C
|
||||||
#define AK8974_SELFTEST_IDLE 0x55
|
#define AK8974_SELFTEST_IDLE 0x55
|
||||||
#define AK8974_SELFTEST_OK 0xAA
|
#define AK8974_SELFTEST_OK 0xAA
|
||||||
@ -44,6 +44,7 @@
|
|||||||
#define AK8974_INFO 0x0D
|
#define AK8974_INFO 0x0D
|
||||||
|
|
||||||
#define AK8974_WHOAMI 0x0F
|
#define AK8974_WHOAMI 0x0F
|
||||||
|
#define AK8974_WHOAMI_VALUE_AMI306 0x46
|
||||||
#define AK8974_WHOAMI_VALUE_AMI305 0x47
|
#define AK8974_WHOAMI_VALUE_AMI305 0x47
|
||||||
#define AK8974_WHOAMI_VALUE_AK8974 0x48
|
#define AK8974_WHOAMI_VALUE_AK8974 0x48
|
||||||
|
|
||||||
@ -73,6 +74,35 @@
|
|||||||
#define AK8974_TEMP 0x31
|
#define AK8974_TEMP 0x31
|
||||||
#define AMI305_TEMP 0x60
|
#define AMI305_TEMP 0x60
|
||||||
|
|
||||||
|
/* AMI306-specific control register */
|
||||||
|
#define AMI306_CTRL4 0x5C
|
||||||
|
|
||||||
|
/* AMI306 factory calibration data */
|
||||||
|
|
||||||
|
/* fine axis sensitivity */
|
||||||
|
#define AMI306_FINEOUTPUT_X 0x90
|
||||||
|
#define AMI306_FINEOUTPUT_Y 0x92
|
||||||
|
#define AMI306_FINEOUTPUT_Z 0x94
|
||||||
|
|
||||||
|
/* axis sensitivity */
|
||||||
|
#define AMI306_SENS_X 0x96
|
||||||
|
#define AMI306_SENS_Y 0x98
|
||||||
|
#define AMI306_SENS_Z 0x9A
|
||||||
|
|
||||||
|
/* axis cross-interference */
|
||||||
|
#define AMI306_GAIN_PARA_XZ 0x9C
|
||||||
|
#define AMI306_GAIN_PARA_XY 0x9D
|
||||||
|
#define AMI306_GAIN_PARA_YZ 0x9E
|
||||||
|
#define AMI306_GAIN_PARA_YX 0x9F
|
||||||
|
#define AMI306_GAIN_PARA_ZY 0xA0
|
||||||
|
#define AMI306_GAIN_PARA_ZX 0xA1
|
||||||
|
|
||||||
|
/* offset at ZERO magnetic field */
|
||||||
|
#define AMI306_OFFZERO_X 0xF8
|
||||||
|
#define AMI306_OFFZERO_Y 0xFA
|
||||||
|
#define AMI306_OFFZERO_Z 0xFC
|
||||||
|
|
||||||
|
|
||||||
#define AK8974_INT_X_HIGH BIT(7) /* Axis over +threshold */
|
#define AK8974_INT_X_HIGH BIT(7) /* Axis over +threshold */
|
||||||
#define AK8974_INT_Y_HIGH BIT(6)
|
#define AK8974_INT_Y_HIGH BIT(6)
|
||||||
#define AK8974_INT_Z_HIGH BIT(5)
|
#define AK8974_INT_Z_HIGH BIT(5)
|
||||||
@ -158,6 +188,26 @@ struct ak8974 {
|
|||||||
static const char ak8974_reg_avdd[] = "avdd";
|
static const char ak8974_reg_avdd[] = "avdd";
|
||||||
static const char ak8974_reg_dvdd[] = "dvdd";
|
static const char ak8974_reg_dvdd[] = "dvdd";
|
||||||
|
|
||||||
|
static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
__le16 bulk;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
*val = le16_to_cpu(bulk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ak8974_set_u16_val(struct ak8974 *ak8974, u8 reg, u16 val)
|
||||||
|
{
|
||||||
|
__le16 bulk = cpu_to_le16(val);
|
||||||
|
|
||||||
|
return regmap_bulk_write(ak8974->map, reg, &bulk, 2);
|
||||||
|
}
|
||||||
|
|
||||||
static int ak8974_set_power(struct ak8974 *ak8974, bool mode)
|
static int ak8974_set_power(struct ak8974 *ak8974, bool mode)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -209,6 +259,12 @@ static int ak8974_configure(struct ak8974 *ak8974)
|
|||||||
ret = regmap_write(ak8974->map, AK8974_CTRL3, 0);
|
ret = regmap_write(ak8974->map, AK8974_CTRL3, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
if (ak8974->variant == AK8974_WHOAMI_VALUE_AMI306) {
|
||||||
|
/* magic from datasheet: set high-speed measurement mode */
|
||||||
|
ret = ak8974_set_u16_val(ak8974, AMI306_CTRL4, 0xA07E);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL);
|
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -388,19 +444,6 @@ static int ak8974_selftest(struct ak8974 *ak8974)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
__le16 bulk;
|
|
||||||
|
|
||||||
ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
*val = le16_to_cpu(bulk);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ak8974_detect(struct ak8974 *ak8974)
|
static int ak8974_detect(struct ak8974 *ak8974)
|
||||||
{
|
{
|
||||||
unsigned int whoami;
|
unsigned int whoami;
|
||||||
@ -413,9 +456,13 @@ static int ak8974_detect(struct ak8974 *ak8974)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
switch (whoami) {
|
|
||||||
case AK8974_WHOAMI_VALUE_AMI305:
|
|
||||||
name = "ami305";
|
name = "ami305";
|
||||||
|
|
||||||
|
switch (whoami) {
|
||||||
|
case AK8974_WHOAMI_VALUE_AMI306:
|
||||||
|
name = "ami306";
|
||||||
|
/* fall-through */
|
||||||
|
case AK8974_WHOAMI_VALUE_AMI305:
|
||||||
ret = regmap_read(ak8974->map, AMI305_VER, &fw);
|
ret = regmap_read(ak8974->map, AMI305_VER, &fw);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -602,9 +649,11 @@ static bool ak8974_writeable_reg(struct device *dev, unsigned int reg)
|
|||||||
case AMI305_OFFSET_Y + 1:
|
case AMI305_OFFSET_Y + 1:
|
||||||
case AMI305_OFFSET_Z:
|
case AMI305_OFFSET_Z:
|
||||||
case AMI305_OFFSET_Z + 1:
|
case AMI305_OFFSET_Z + 1:
|
||||||
if (ak8974->variant == AK8974_WHOAMI_VALUE_AMI305)
|
return ak8974->variant == AK8974_WHOAMI_VALUE_AMI305 ||
|
||||||
return true;
|
ak8974->variant == AK8974_WHOAMI_VALUE_AMI306;
|
||||||
return false;
|
case AMI306_CTRL4:
|
||||||
|
case AMI306_CTRL4 + 1:
|
||||||
|
return ak8974->variant == AK8974_WHOAMI_VALUE_AMI306;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -678,7 +727,7 @@ static int ak8974_probe(struct i2c_client *i2c,
|
|||||||
|
|
||||||
ret = ak8974_detect(ak8974);
|
ret = ak8974_detect(ak8974);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&i2c->dev, "neither AK8974 nor AMI305 found\n");
|
dev_err(&i2c->dev, "neither AK8974 nor AMI30x found\n");
|
||||||
goto power_off;
|
goto power_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,6 +876,7 @@ static const struct dev_pm_ops ak8974_dev_pm_ops = {
|
|||||||
|
|
||||||
static const struct i2c_device_id ak8974_id[] = {
|
static const struct i2c_device_id ak8974_id[] = {
|
||||||
{"ami305", 0 },
|
{"ami305", 0 },
|
||||||
|
{"ami306", 0 },
|
||||||
{"ak8974", 0 },
|
{"ak8974", 0 },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
@ -850,7 +900,7 @@ static struct i2c_driver ak8974_driver = {
|
|||||||
};
|
};
|
||||||
module_i2c_driver(ak8974_driver);
|
module_i2c_driver(ak8974_driver);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("AK8974 and AMI305 3-axis magnetometer driver");
|
MODULE_DESCRIPTION("AK8974 and AMI30x 3-axis magnetometer driver");
|
||||||
MODULE_AUTHOR("Samu Onkalo");
|
MODULE_AUTHOR("Samu Onkalo");
|
||||||
MODULE_AUTHOR("Linus Walleij");
|
MODULE_AUTHOR("Linus Walleij");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
Loading…
Reference in New Issue
Block a user