#define MAG3110_CTRL_AUTO_MRST_EN BIT(7) /* magnetic auto-reset */ #define MAG3110_CTRL_RAW BIT(5) /* measurements not user-offset corrected */
#define MAG3110_DEVICE_ID 0xc4
/* Each client has this additional data */ struct mag3110_data { struct i2c_client *client; struct mutex lock;
u8 ctrl_reg1; int sleep_val; struct regulator *vdd_reg; struct regulator *vddio_reg; /* Ensure natural alignment of timestamp */ struct {
__be16 channels[3];
u8 temperature;
aligned_s64 ts;
} scan;
};
staticint mag3110_request(struct mag3110_data *data)
{ int ret, tries = 150;
if ((data->ctrl_reg1 & MAG3110_CTRL_AC) == 0) { /* trigger measurement */
ret = i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1 | MAG3110_CTRL_TM); if (ret < 0) return ret;
}
while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, MAG3110_STATUS); if (ret < 0) return ret; /* wait for data ready */ if ((ret & MAG3110_STATUS_DRDY) == MAG3110_STATUS_DRDY) break;
if (tries < 0) {
dev_err(&data->client->dev, "data not ready\n"); return -EIO;
}
return 0;
}
staticint mag3110_read(struct mag3110_data *data, __be16 buf[3])
{ int ret;
guard(mutex)(&data->lock);
ret = mag3110_request(data); if (ret < 0) return ret; return i2c_smbus_read_i2c_block_data(data->client, MAG3110_OUT_X,
3 * sizeof(__be16), (u8 *) buf);
}
static ssize_t mag3110_show_int_plus_micros(char *buf, constint (*vals)[2], int n)
{
size_t len = 0;
while (n-- > 0)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", vals[n][0], vals[n][1]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
return len;
}
staticint mag3110_get_int_plus_micros_index(constint (*vals)[2], int n, int val, int val2)
{ while (n-- > 0) if (val == vals[n][0] && val2 == vals[n][1]) return n;
staticint mag3110_wait_standby(struct mag3110_data *data)
{ int ret, tries = 30;
/* * Takes up to 1/ODR to come out of active mode into stby * Longest expected period is 12.5seconds. * We'll sleep for 500ms between checks
*/ while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, MAG3110_SYSMOD); if (ret < 0) {
dev_err(&data->client->dev, "i2c error\n"); return ret;
} /* wait for standby */ if ((ret & MAG3110_SYSMOD_MODE_MASK) == 0) break;
msleep_interruptible(500);
}
if (tries < 0) {
dev_err(&data->client->dev, "device not entering standby mode\n"); return -EIO;
}
/* returns >0 if active, 0 if in standby and <0 on error */ staticint mag3110_is_active(struct mag3110_data *data)
{ int reg;
reg = i2c_smbus_read_byte_data(data->client, MAG3110_CTRL_REG1); if (reg < 0) return reg;
return reg & MAG3110_CTRL_AC;
}
staticint mag3110_change_config(struct mag3110_data *data, u8 reg, u8 val)
{ int ret; int is_active;
guard(mutex)(&data->lock);
is_active = mag3110_is_active(data); if (is_active < 0) return is_active;
/* config can only be changed when in standby */ if (is_active > 0) {
ret = mag3110_standby(data); if (ret < 0) return ret;
}
/* * After coming out of active we must wait for the part * to transition to STBY. This can take up to 1 /ODR to occur
*/
ret = mag3110_wait_standby(data); if (ret < 0) return ret;
ret = i2c_smbus_write_byte_data(data->client, reg, val); if (ret < 0) return ret;
if (is_active > 0) {
ret = mag3110_active(data); if (ret < 0) return ret;
}
return 0;
}
staticint __mag3110_read_info_raw(struct mag3110_data *data, struct iio_chan_spec const *chan, int *val)
{
__be16 buffer[3]; int ret;
switch (chan->type) { case IIO_MAGN: /* in 0.1 uT / LSB */
ret = mag3110_read(data, buffer); if (ret < 0) return ret;
*val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]),
chan->scan_type.realbits - 1); return IIO_VAL_INT;
case IIO_TEMP: { /* in 1 C / LSB */
guard(mutex)(&data->lock);
ret = mag3110_request(data); if (ret < 0) return ret;
ret = i2c_smbus_read_byte_data(data->client,
MAG3110_DIE_TEMP); if (ret < 0) return ret;
*val = sign_extend32(ret, chan->scan_type.realbits - 1); return IIO_VAL_INT;
} default: return -EINVAL;
}
}
staticint mag3110_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct mag3110_data *data = iio_priv(indio_dev); int i, ret;
switch (mask) { case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
ret = __mag3110_read_info_raw(data, chan, val);
iio_device_release_direct(indio_dev); return ret;
case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_MAGN:
*val = 0;
*val2 = 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_TEMP:
*val = 1000; return IIO_VAL_INT; default: return -EINVAL;
} case IIO_CHAN_INFO_SAMP_FREQ:
i = data->ctrl_reg1 >> MAG3110_CTRL_DR_SHIFT;
*val = mag3110_samp_freq[i][0];
*val2 = mag3110_samp_freq[i][1]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS:
ret = i2c_smbus_read_word_swapped(data->client,
MAG3110_OFF_X + 2 * chan->scan_index); if (ret < 0) return ret;
*val = sign_extend32(ret >> 1, 14); return IIO_VAL_INT;
} return -EINVAL;
}
staticint __mag3110_write_raw(struct mag3110_data *data, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ int rate;
switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ:
rate = mag3110_get_samp_freq_index(data, val, val2); if (rate < 0) return -EINVAL;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM;
data = iio_priv(indio_dev);
data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg), "failed to get VDD regulator!\n");
data->vddio_reg = devm_regulator_get(&client->dev, "vddio"); if (IS_ERR(data->vddio_reg)) return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg), "failed to get VDDIO regulator!\n");
ret = regulator_enable(data->vdd_reg); if (ret) {
dev_err(&client->dev, "failed to enable VDD regulator!\n"); return ret;
}
ret = regulator_enable(data->vddio_reg); if (ret) {
dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); goto disable_regulator_vdd;
}
ret = i2c_smbus_read_byte_data(client, MAG3110_WHO_AM_I); if (ret < 0) goto disable_regulators; if (ret != MAG3110_DEVICE_ID) {
ret = -ENODEV; goto disable_regulators;
}
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.