// SPDX-License-Identifier: GPL-2.0-only /* * iio/adc/ad799x.c * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. * * based on iio/adc/max1363 * Copyright (C) 2008-2010 Jonathan Cameron * * based on linux/drivers/i2c/chips/max123x * Copyright (C) 2002-2004 Stefan Eletzhofer * * based on linux/drivers/acron/char/pcf8583.c * Copyright (C) 2000 Russell King * * ad799x.c * * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, * ad7998 and similar chips.
*/
/** * struct ad799x_chip_info - chip specific information * @num_channels: number of channels * @noirq_config: device configuration w/o IRQ * @irq_config: device configuration w/IRQ
*/ struct ad799x_chip_info { int num_channels; conststruct ad799x_chip_config noirq_config; conststruct ad799x_chip_config irq_config;
};
struct ad799x_state { struct i2c_client *client; conststruct ad799x_chip_config *chip_config; struct regulator *reg; struct regulator *vref; /* lock to protect against multiple access to the device */ struct mutex lock; unsignedint id;
u16 config;
u8 *rx_buf; unsignedint transfer_size;
};
staticint ad799x_write_config(struct ad799x_state *st, u16 val)
{ switch (st->id) { case ad7997: case ad7998: return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG,
val); case ad7992: case ad7993: case ad7994: return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG,
val); default: /* Will be written when doing a conversion */
st->config = val; return 0;
}
}
staticint ad799x_read_config(struct ad799x_state *st)
{ switch (st->id) { case ad7997: case ad7998: return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG); case ad7992: case ad7993: case ad7994: return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG); default: /* No readback support */ return st->config;
}
}
staticint ad799x_update_config(struct ad799x_state *st, u16 config)
{ int ret;
ret = ad799x_write_config(st, config); if (ret < 0) return ret;
ret = ad799x_read_config(st); if (ret < 0) return ret;
st->config = ret;
staticint ad799x_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m)
{ int ret; struct ad799x_state *st = iio_priv(indio_dev);
switch (m) { case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
mutex_lock(&st->lock);
ret = ad799x_scan_direct(st, chan->scan_index);
mutex_unlock(&st->lock);
iio_device_release_direct(indio_dev);
if (ret < 0) return ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (st->vref)
ret = regulator_get_voltage(st->vref); else
ret = regulator_get_voltage(st->reg);
ret = kstrtol(buf, 10, &val); if (ret) return ret;
mutex_lock(&st->lock);
ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG); if (ret < 0) goto error_ret_mutex; /* Wipe the bits clean */
ret &= ~AD7998_CYC_MASK;
for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++) if (val == ad7998_frequencies[i]) break; if (i == ARRAY_SIZE(ad7998_frequencies)) {
ret = -EINVAL; goto error_ret_mutex;
}
ret = i2c_smbus_write_byte_data(st->client, AD7998_CYCLE_TMR_REG,
ret | i); if (ret < 0) goto error_ret_mutex;
ret = len;
static irqreturn_t ad799x_event_handler(int irq, void *private)
{ struct iio_dev *indio_dev = private; struct ad799x_state *st = iio_priv(private); int i, ret;
ret = i2c_smbus_read_byte_data(st->client, AD7998_ALERT_STAT_REG); if (ret <= 0) goto done;
if (i2c_smbus_write_byte_data(st->client, AD7998_ALERT_STAT_REG,
AD7998_ALERT_STAT_CLEAR) < 0) goto done;
for (i = 0; i < 8; i++) { if (ret & BIT(i))
iio_push_event(indio_dev,
i & 0x1 ?
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
(i >> 1),
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING) :
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
(i >> 1),
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns(indio_dev));
}
/* TODO: Add pdata options for filtering and bit delay */
st->reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg);
ret = regulator_enable(st->reg); if (ret) return ret;
/* check if an external reference is supplied */
st->vref = devm_regulator_get_optional(&client->dev, "vref");
if (IS_ERR(st->vref)) { if (PTR_ERR(st->vref) == -ENODEV) {
st->vref = NULL;
dev_info(&client->dev, "Using VCC reference voltage\n");
} else {
ret = PTR_ERR(st->vref); goto error_disable_reg;
}
}
if (st->vref) { /* * Use external reference voltage if supported by hardware. * This is optional if voltage / regulator present, use VCC otherwise.
*/ if ((st->id == ad7991) || (st->id == ad7995) || (st->id == ad7999)) {
dev_info(&client->dev, "Using external reference voltage\n");
extra_config |= AD7991_REF_SEL;
ret = regulator_enable(st->vref); if (ret) goto error_disable_reg;
} else {
st->vref = NULL;
dev_warn(&client->dev, "Supplied reference not supported\n");
}
}
ret = regulator_enable(st->reg); if (ret) {
dev_err(dev, "Unable to enable vcc regulator\n"); return ret;
}
if (st->vref) {
ret = regulator_enable(st->vref); if (ret) {
regulator_disable(st->reg);
dev_err(dev, "Unable to enable vref regulator\n"); return ret;
}
}
/* resync config */
ret = ad799x_update_config(st, st->config); if (ret) { if (st->vref)
regulator_disable(st->vref);
regulator_disable(st->reg); return ret;
}
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.