val = mode ? AK8974_CTRL1_POWER : 0;
val |= AK8974_CTRL1_FORCE_EN;
ret = regmap_write(ak8974->map, AK8974_CTRL1, val); if (ret < 0) return ret;
if (mode)
msleep(AK8974_ACTIVATE_DELAY);
return0;
}
staticint ak8974_reset(struct ak8974 *ak8974)
{ int ret;
/* Power on to get register access. Sets CTRL1 reg to reset state */
ret = ak8974_set_power(ak8974, AK8974_PWR_ON); if (ret) return ret;
ret = regmap_write(ak8974->map, AK8974_CTRL2, AK8974_CTRL2_RESDEF); if (ret) return ret;
ret = regmap_write(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_RESDEF); if (ret) return ret; if (ak8974->variant != AK8974_WHOAMI_VALUE_HSCDTD008A) {
ret = regmap_write(ak8974->map, AK8974_INT_CTRL,
AK8974_INT_CTRL_RESDEF); if (ret) return ret;
} else {
ret = regmap_write(ak8974->map, HSCDTD008A_CTRL4,
HSCDTD008A_CTRL4_RESDEF); if (ret) return ret;
}
/* After reset, power off is default state */ return ak8974_set_power(ak8974, AK8974_PWR_OFF);
}
staticint ak8974_configure(struct ak8974 *ak8974)
{ int ret;
ret = regmap_write(ak8974->map, AK8974_CTRL2, AK8974_CTRL2_DRDY_EN |
AK8974_CTRL2_INT_EN); if (ret) return ret;
ret = regmap_write(ak8974->map, AK8974_CTRL3, 0); if (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;
} if (ak8974->variant == AK8974_WHOAMI_VALUE_HSCDTD008A) return0;
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL); if (ret) return ret;
/* Clear any previous measurement overflow status */
ret = regmap_read(ak8974->map, AK8974_INT_CLEAR, &clear); if (ret) return ret;
/* If we have a DRDY IRQ line, use it */ if (ak8974->drdy_irq) {
mask = AK8974_CTRL2_INT_EN |
AK8974_CTRL2_DRDY_EN |
AK8974_CTRL2_DRDY_POL;
val = AK8974_CTRL2_DRDY_EN;
if (!ak8974->drdy_active_low)
val |= AK8974_CTRL2_DRDY_POL;
init_completion(&ak8974->drdy_complete);
ret = regmap_update_bits(ak8974->map, AK8974_CTRL2,
mask, val); if (ret) return ret;
}
/* Force a measurement */ return regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_FORCE);
}
staticint ak8974_await_drdy(struct ak8974 *ak8974)
{ int timeout = 2; unsignedint val; int ret;
if (ak8974->drdy_irq) {
ret = wait_for_completion_timeout(&ak8974->drdy_complete, 1 + msecs_to_jiffies(1000)); if (!ret) {
dev_err(&ak8974->i2c->dev, "timeout waiting for DRDY IRQ\n"); return -ETIMEDOUT;
} return0;
}
/* Default delay-based poll loop */ do {
msleep(AK8974_MEASTIME);
ret = regmap_read(ak8974->map, AK8974_STATUS, &val); if (ret < 0) return ret; if (val & AK8974_STATUS_DRDY) return0;
} while (--timeout);
dev_err(&ak8974->i2c->dev, "timeout waiting for DRDY\n"); return -ETIMEDOUT;
}
ret = ak8974_await_drdy(ak8974); if (ret) return ret;
ret = regmap_read(ak8974->map, AK8974_INT_SRC, &src); if (ret < 0) return ret;
/* Out of range overflow! Strong magnet close? */ if (src & AK8974_INT_RANGE) {
dev_err(&ak8974->i2c->dev, "range overflow in sensor\n"); return -ERANGE;
}
ret = regmap_bulk_read(ak8974->map, AK8974_DATA_X, result, 6); if (ret) return ret;
/* Check if this was a DRDY from us */
ret = regmap_read(ak8974->map, AK8974_STATUS, &val); if (ret < 0) {
dev_err(&ak8974->i2c->dev, "error reading DRDY status\n"); return IRQ_HANDLED;
} if (val & AK8974_STATUS_DRDY) { /* Yes this was our IRQ */
complete(&ak8974->drdy_complete); return IRQ_HANDLED;
}
/* We may be on a shared IRQ, let the next client check */ return IRQ_NONE;
}
ret = regmap_read(ak8974->map, AK8974_SELFTEST, &val); if (ret) return ret; if (val != AK8974_SELFTEST_IDLE) {
dev_err(dev, "selftest not idle before test\n"); return -EIO;
}
/* Trigger self-test */
ret = regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_SELFTEST); if (ret) {
dev_err(dev, "could not write CTRL3\n"); return ret;
}
msleep(AK8974_SELFTEST_DELAY);
ret = regmap_read(ak8974->map, AK8974_SELFTEST, &val); if (ret) return ret; if (val != AK8974_SELFTEST_OK) {
dev_err(dev, "selftest result NOT OK (%02x)\n", val); return -EIO;
}
ret = regmap_read(ak8974->map, AK8974_SELFTEST, &val); if (ret) return ret; if (val != AK8974_SELFTEST_IDLE) {
dev_err(dev, "selftest not idle after test (%02x)\n", val); return -EIO;
}
dev_dbg(dev, "passed self-test\n");
switch (reg) { case AK8974_CTRL1: case AK8974_CTRL2: case AK8974_CTRL3: case AK8974_INT_CTRL: case AK8974_INT_THRES: case AK8974_INT_THRES + 1: returntrue; case AK8974_PRESET: case AK8974_PRESET + 1: return ak8974->variant != AK8974_WHOAMI_VALUE_HSCDTD008A; case AK8974_OFFSET_X: case AK8974_OFFSET_X + 1: case AK8974_OFFSET_Y: case AK8974_OFFSET_Y + 1: case AK8974_OFFSET_Z: case AK8974_OFFSET_Z + 1: return ak8974->variant == AK8974_WHOAMI_VALUE_AK8974 ||
ak8974->variant == AK8974_WHOAMI_VALUE_HSCDTD008A; case AMI305_OFFSET_X: case AMI305_OFFSET_X + 1: case AMI305_OFFSET_Y: case AMI305_OFFSET_Y + 1: case AMI305_OFFSET_Z: case AMI305_OFFSET_Z + 1: return ak8974->variant == AK8974_WHOAMI_VALUE_AMI305 ||
ak8974->variant == AK8974_WHOAMI_VALUE_AMI306; case AMI306_CTRL4: case AMI306_CTRL4 + 1: return ak8974->variant == AK8974_WHOAMI_VALUE_AMI306; default: returnfalse;
}
}
ret = devm_regulator_bulk_get(&i2c->dev,
ARRAY_SIZE(ak8974->regs),
ak8974->regs); if (ret < 0) return dev_err_probe(&i2c->dev, ret, "cannot get regulators\n");
ret = regulator_bulk_enable(ARRAY_SIZE(ak8974->regs), ak8974->regs); if (ret < 0) {
dev_err(&i2c->dev, "cannot enable regulators\n"); return ret;
}
/* Take runtime PM online */
pm_runtime_get_noresume(&i2c->dev);
pm_runtime_set_active(&i2c->dev);
pm_runtime_enable(&i2c->dev);
ak8974->map = devm_regmap_init_i2c(i2c, &ak8974_regmap_config); if (IS_ERR(ak8974->map)) {
dev_err(&i2c->dev, "failed to allocate register map\n");
pm_runtime_put_noidle(&i2c->dev);
pm_runtime_disable(&i2c->dev); return PTR_ERR(ak8974->map);
}
ret = ak8974_set_power(ak8974, AK8974_PWR_ON); if (ret) {
dev_err(&i2c->dev, "could not power on\n"); goto disable_pm;
}
ret = ak8974_detect(ak8974); if (ret) {
dev_err(&i2c->dev, "neither AK8974 nor AMI30x found\n"); goto disable_pm;
}
ret = ak8974_selftest(ak8974); if (ret)
dev_err(&i2c->dev, "selftest failed (continuing anyway)\n");
ret = ak8974_reset(ak8974); if (ret) {
dev_err(&i2c->dev, "AK8974 reset failed\n"); goto disable_pm;
}
ret = regulator_bulk_enable(ARRAY_SIZE(ak8974->regs), ak8974->regs); if (ret) return ret;
msleep(AK8974_POWERON_DELAY);
ret = ak8974_set_power(ak8974, AK8974_PWR_ON); if (ret) goto out_regulator_disable;
ret = ak8974_configure(ak8974); if (ret) goto out_disable_power;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.11Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-01)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.