summaryrefslogtreecommitdiff
path: root/drivers/iio/adc/ti-ads1015.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/ti-ads1015.c')
-rw-r--r--drivers/iio/adc/ti-ads1015.c636
1 files changed, 333 insertions, 303 deletions
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 5ea4f45d6bad..f2a93c63ca14 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -12,6 +12,7 @@
*/
#include <linux/module.h>
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/i2c.h>
@@ -76,10 +77,15 @@
#define ADS1015_DEFAULT_DATA_RATE 4
#define ADS1015_DEFAULT_CHAN 0
-enum chip_ids {
- ADSXXXX = 0,
- ADS1015,
- ADS1115,
+struct ads1015_chip_data {
+ struct iio_chan_spec const *channels;
+ int num_channels;
+ const struct iio_info *info;
+ const int *data_rate;
+ const int data_rate_len;
+ const int *scale;
+ const int scale_len;
+ bool has_comparator;
};
enum ads1015_channels {
@@ -94,11 +100,11 @@ enum ads1015_channels {
ADS1015_TIMESTAMP,
};
-static const unsigned int ads1015_data_rate[] = {
+static const int ads1015_data_rate[] = {
128, 250, 490, 920, 1600, 2400, 3300, 3300
};
-static const unsigned int ads1115_data_rate[] = {
+static const int ads1115_data_rate[] = {
8, 16, 32, 64, 128, 250, 475, 860
};
@@ -106,10 +112,28 @@ static const unsigned int ads1115_data_rate[] = {
* Translation from PGA bits to full-scale positive and negative input voltage
* range in mV
*/
-static int ads1015_fullscale_range[] = {
+static const int ads1015_fullscale_range[] = {
6144, 4096, 2048, 1024, 512, 256, 256, 256
};
+static const int ads1015_scale[] = { /* 12bit ADC */
+ 256, 11,
+ 512, 11,
+ 1024, 11,
+ 2048, 11,
+ 4096, 11,
+ 6144, 11
+};
+
+static const int ads1115_scale[] = { /* 16bit ADC */
+ 256, 15,
+ 512, 15,
+ 1024, 15,
+ 2048, 15,
+ 4096, 15,
+ 6144, 15
+};
+
/*
* Translation from COMP_QUE field value to the number of successive readings
* exceed the threshold values before an interrupt is generated
@@ -134,7 +158,29 @@ static const struct iio_event_spec ads1015_events[] = {
},
};
-#define ADS1015_V_CHAN(_chan, _addr) { \
+/*
+ * Compile-time check whether _fitbits can accommodate up to _testbits
+ * bits. Returns _fitbits on success, fails to compile otherwise.
+ *
+ * The test works such that it multiplies constant _fitbits by constant
+ * double-negation of size of a non-empty structure, i.e. it multiplies
+ * constant _fitbits by constant 1 in each successful compilation case.
+ * The non-empty structure may contain C11 _Static_assert(), make use of
+ * this and place the kernel variant of static assert in there, so that
+ * it performs the compile-time check for _testbits <= _fitbits. Note
+ * that it is not possible to directly use static_assert in compound
+ * statements, hence this convoluted construct.
+ */
+#define FIT_CHECK(_testbits, _fitbits) \
+ ( \
+ (_fitbits) * \
+ !!sizeof(struct { \
+ static_assert((_testbits) <= (_fitbits)); \
+ int pad; \
+ }) \
+ )
+
+#define ADS1015_V_CHAN(_chan, _addr, _realbits, _shift, _event_spec, _num_event_specs) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.address = _addr, \
@@ -142,63 +188,23 @@ static const struct iio_event_spec ads1015_events[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
- .scan_index = _addr, \
- .scan_type = { \
- .sign = 's', \
- .realbits = 12, \
- .storagebits = 16, \
- .shift = 4, \
- .endianness = IIO_CPU, \
- }, \
- .event_spec = ads1015_events, \
- .num_event_specs = ARRAY_SIZE(ads1015_events), \
- .datasheet_name = "AIN"#_chan, \
-}
-
-#define ADS1015_V_DIFF_CHAN(_chan, _chan2, _addr) { \
- .type = IIO_VOLTAGE, \
- .differential = 1, \
- .indexed = 1, \
- .address = _addr, \
- .channel = _chan, \
- .channel2 = _chan2, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ .info_mask_shared_by_all_available = \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = _addr, \
.scan_type = { \
.sign = 's', \
- .realbits = 12, \
- .storagebits = 16, \
- .shift = 4, \
+ .realbits = (_realbits), \
+ .storagebits = FIT_CHECK((_realbits) + (_shift), 16), \
+ .shift = (_shift), \
.endianness = IIO_CPU, \
}, \
- .event_spec = ads1015_events, \
- .num_event_specs = ARRAY_SIZE(ads1015_events), \
- .datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
-}
-
-#define ADS1115_V_CHAN(_chan, _addr) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .address = _addr, \
- .channel = _chan, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_SAMP_FREQ), \
- .scan_index = _addr, \
- .scan_type = { \
- .sign = 's', \
- .realbits = 16, \
- .storagebits = 16, \
- .endianness = IIO_CPU, \
- }, \
- .event_spec = ads1015_events, \
- .num_event_specs = ARRAY_SIZE(ads1015_events), \
+ .event_spec = (_event_spec), \
+ .num_event_specs = (_num_event_specs), \
.datasheet_name = "AIN"#_chan, \
}
-#define ADS1115_V_DIFF_CHAN(_chan, _chan2, _addr) { \
+#define ADS1015_V_DIFF_CHAN(_chan, _chan2, _addr, _realbits, _shift, _event_spec, _num_event_specs) { \
.type = IIO_VOLTAGE, \
.differential = 1, \
.indexed = 1, \
@@ -208,15 +214,19 @@ static const struct iio_event_spec ads1015_events[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = _addr, \
.scan_type = { \
.sign = 's', \
- .realbits = 16, \
- .storagebits = 16, \
+ .realbits = (_realbits), \
+ .storagebits = FIT_CHECK((_realbits) + (_shift), 16), \
+ .shift = (_shift), \
.endianness = IIO_CPU, \
}, \
- .event_spec = ads1015_events, \
- .num_event_specs = ARRAY_SIZE(ads1015_events), \
+ .event_spec = (_event_spec), \
+ .num_event_specs = (_num_event_specs), \
.datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
}
@@ -245,7 +255,7 @@ struct ads1015_data {
unsigned int comp_mode;
struct ads1015_thresh_data thresh_data[ADS1015_CHANNELS];
- unsigned int *data_rate;
+ const struct ads1015_chip_data *chip;
/*
* Set to true when the ADC is switched to the continuous-conversion
* mode and exits from a power-down state. This flag is used to avoid
@@ -273,69 +283,118 @@ static void ads1015_event_channel_disable(struct ads1015_data *data, int chan)
data->event_channel = ADS1015_CHANNELS;
}
-static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case ADS1015_CFG_REG:
- case ADS1015_LO_THRESH_REG:
- case ADS1015_HI_THRESH_REG:
- return true;
- default:
- return false;
- }
-}
+static const struct regmap_range ads1015_writeable_ranges[] = {
+ regmap_reg_range(ADS1015_CFG_REG, ADS1015_HI_THRESH_REG),
+};
+
+static const struct regmap_access_table ads1015_writeable_table = {
+ .yes_ranges = ads1015_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ads1015_writeable_ranges),
+};
static const struct regmap_config ads1015_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.max_register = ADS1015_HI_THRESH_REG,
- .writeable_reg = ads1015_is_writeable_reg,
+ .wr_table = &ads1015_writeable_table,
+};
+
+static const struct regmap_range tla2024_writeable_ranges[] = {
+ regmap_reg_range(ADS1015_CFG_REG, ADS1015_CFG_REG),
+};
+
+static const struct regmap_access_table tla2024_writeable_table = {
+ .yes_ranges = tla2024_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(tla2024_writeable_ranges),
+};
+
+static const struct regmap_config tla2024_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = ADS1015_CFG_REG,
+ .wr_table = &tla2024_writeable_table,
};
static const struct iio_chan_spec ads1015_channels[] = {
- ADS1015_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1),
- ADS1015_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3),
- ADS1015_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3),
- ADS1015_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3),
- ADS1015_V_CHAN(0, ADS1015_AIN0),
- ADS1015_V_CHAN(1, ADS1015_AIN1),
- ADS1015_V_CHAN(2, ADS1015_AIN2),
- ADS1015_V_CHAN(3, ADS1015_AIN3),
+ ADS1015_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(0, ADS1015_AIN0, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(1, ADS1015_AIN1, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(2, ADS1015_AIN2, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(3, ADS1015_AIN3, 12, 4,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
};
static const struct iio_chan_spec ads1115_channels[] = {
- ADS1115_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1),
- ADS1115_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3),
- ADS1115_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3),
- ADS1115_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3),
- ADS1115_V_CHAN(0, ADS1015_AIN0),
- ADS1115_V_CHAN(1, ADS1015_AIN1),
- ADS1115_V_CHAN(2, ADS1015_AIN2),
- ADS1115_V_CHAN(3, ADS1015_AIN3),
+ ADS1015_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(0, ADS1015_AIN0, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(1, ADS1015_AIN1, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(2, ADS1015_AIN2, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
+ ADS1015_V_CHAN(3, ADS1015_AIN3, 16, 0,
+ ads1015_events, ARRAY_SIZE(ads1015_events)),
IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
};
+static const struct iio_chan_spec tla2024_channels[] = {
+ ADS1015_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1, 12, 4, NULL, 0),
+ ADS1015_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3, 12, 4, NULL, 0),
+ ADS1015_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3, 12, 4, NULL, 0),
+ ADS1015_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3, 12, 4, NULL, 0),
+ ADS1015_V_CHAN(0, ADS1015_AIN0, 12, 4, NULL, 0),
+ ADS1015_V_CHAN(1, ADS1015_AIN1, 12, 4, NULL, 0),
+ ADS1015_V_CHAN(2, ADS1015_AIN2, 12, 4, NULL, 0),
+ ADS1015_V_CHAN(3, ADS1015_AIN3, 12, 4, NULL, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
+};
+
+
+#ifdef CONFIG_PM
static int ads1015_set_power_state(struct ads1015_data *data, bool on)
{
int ret;
struct device *dev = regmap_get_device(data->regmap);
- if (on) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- pm_runtime_put_noidle(dev);
- } else {
- pm_runtime_mark_last_busy(dev);
+ if (on)
+ ret = pm_runtime_resume_and_get(dev);
+ else
ret = pm_runtime_put_autosuspend(dev);
- }
return ret < 0 ? ret : 0;
}
+#else /* !CONFIG_PM */
+
+static int ads1015_set_power_state(struct ads1015_data *data, bool on)
+{
+ return 0;
+}
+
+#endif /* !CONFIG_PM */
+
static
int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
{
+ const int *data_rate = data->chip->data_rate;
int ret, pga, dr, dr_old, conv_time;
unsigned int old, mask, cfg;
@@ -370,8 +429,8 @@ int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
}
if (data->conv_invalid) {
dr_old = (old & ADS1015_CFG_DR_MASK) >> ADS1015_CFG_DR_SHIFT;
- conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr_old]);
- conv_time += DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
+ conv_time = DIV_ROUND_UP(USEC_PER_SEC, data_rate[dr_old]);
+ conv_time += DIV_ROUND_UP(USEC_PER_SEC, data_rate[dr]);
conv_time += conv_time / 10; /* 10% internal clock inaccuracy */
usleep_range(conv_time, conv_time + 1);
data->conv_invalid = false;
@@ -385,25 +444,27 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ads1015_data *data = iio_priv(indio_dev);
- s16 buf[8]; /* 1x s16 ADC val + 3x s16 padding + 4x s16 timestamp */
+ /* Ensure natural alignment of timestamp */
+ struct {
+ s16 chan;
+ aligned_s64 timestamp;
+ } scan = { };
int chan, ret, res;
- memset(buf, 0, sizeof(buf));
-
mutex_lock(&data->lock);
chan = find_first_bit(indio_dev->active_scan_mask,
- indio_dev->masklength);
+ iio_get_masklength(indio_dev));
ret = ads1015_get_adc_result(data, chan, &res);
if (ret < 0) {
mutex_unlock(&data->lock);
goto err;
}
- buf[0] = res;
+ scan.chan = res;
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, buf,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -433,8 +494,8 @@ static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
{
int i;
- for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++) {
- if (data->data_rate[i] == rate) {
+ for (i = 0; i < data->chip->data_rate_len; i++) {
+ if (data->chip->data_rate[i] == rate) {
data->channel_data[chan].data_rate = i;
return 0;
}
@@ -443,67 +504,87 @@ static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
return -EINVAL;
}
-static int ads1015_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int *val,
- int *val2, long mask)
+static int ads1015_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
{
- int ret, idx;
struct ads1015_data *data = iio_priv(indio_dev);
- mutex_lock(&data->lock);
+ if (chan->type != IIO_VOLTAGE)
+ return -EINVAL;
+
switch (mask) {
- case IIO_CHAN_INFO_RAW: {
- int shift = chan->scan_type.shift;
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_FRACTIONAL_LOG2;
+ *vals = data->chip->scale;
+ *length = data->chip->scale_len;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *type = IIO_VAL_INT;
+ *vals = data->chip->data_rate;
+ *length = data->chip->data_rate_len;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- break;
+static int __ads1015_read_info_raw(struct ads1015_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ int ret;
- if (ads1015_event_channel_enabled(data) &&
- data->event_channel != chan->address) {
- ret = -EBUSY;
- goto release_direct;
- }
+ if (ads1015_event_channel_enabled(data) &&
+ data->event_channel != chan->address)
+ return -EBUSY;
- ret = ads1015_set_power_state(data, true);
- if (ret < 0)
- goto release_direct;
+ ret = ads1015_set_power_state(data, true);
+ if (ret < 0)
+ return ret;
- ret = ads1015_get_adc_result(data, chan->address, val);
- if (ret < 0) {
- ads1015_set_power_state(data, false);
- goto release_direct;
- }
+ ret = ads1015_get_adc_result(data, chan->address, val);
+ if (ret < 0) {
+ ads1015_set_power_state(data, false);
+ return ret;
+ }
- *val = sign_extend32(*val >> shift, 15 - shift);
+ *val = sign_extend32(*val >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
- ret = ads1015_set_power_state(data, false);
- if (ret < 0)
- goto release_direct;
+ return ads1015_set_power_state(data, false);
+}
- ret = IIO_VAL_INT;
-release_direct:
- iio_device_release_direct_mode(indio_dev);
- break;
- }
+static int ads1015_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ int ret, idx;
+ struct ads1015_data *data = iio_priv(indio_dev);
+
+ guard(mutex)(&data->lock);
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = __ads1015_read_info_raw(data, chan, val);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
idx = data->channel_data[chan->address].pga;
*val = ads1015_fullscale_range[idx];
*val2 = chan->scan_type.realbits - 1;
- ret = IIO_VAL_FRACTIONAL_LOG2;
- break;
+ return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
idx = data->channel_data[chan->address].data_rate;
- *val = data->data_rate[idx];
- ret = IIO_VAL_INT;
- break;
+ *val = data->chip->data_rate[idx];
+ return IIO_VAL_INT;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_write_raw(struct iio_dev *indio_dev,
@@ -511,23 +592,16 @@ static int ads1015_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct ads1015_data *data = iio_priv(indio_dev);
- int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- ret = ads1015_set_scale(data, chan, val, val2);
- break;
+ return ads1015_set_scale(data, chan, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
- ret = ads1015_set_data_rate(data, chan->address, val);
- break;
+ return ads1015_set_data_rate(data, chan->address, val);
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_read_event(struct iio_dev *indio_dev,
@@ -536,38 +610,30 @@ static int ads1015_read_event(struct iio_dev *indio_dev,
int *val2)
{
struct ads1015_data *data = iio_priv(indio_dev);
- int ret;
unsigned int comp_queue;
int period;
int dr;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (info) {
case IIO_EV_INFO_VALUE:
*val = (dir == IIO_EV_DIR_RISING) ?
data->thresh_data[chan->address].high_thresh :
data->thresh_data[chan->address].low_thresh;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
dr = data->channel_data[chan->address].data_rate;
comp_queue = data->thresh_data[chan->address].comp_queue;
period = ads1015_comp_queue[comp_queue] *
- USEC_PER_SEC / data->data_rate[dr];
+ USEC_PER_SEC / data->chip->data_rate[dr];
*val = period / USEC_PER_SEC;
*val2 = period % USEC_PER_SEC;
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_write_event(struct iio_dev *indio_dev,
@@ -576,44 +642,38 @@ static int ads1015_write_event(struct iio_dev *indio_dev,
int val2)
{
struct ads1015_data *data = iio_priv(indio_dev);
+ const int *data_rate = data->chip->data_rate;
int realbits = chan->scan_type.realbits;
- int ret = 0;
long long period;
int i;
int dr;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (info) {
case IIO_EV_INFO_VALUE:
- if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1)) {
- ret = -EINVAL;
- break;
- }
+ if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1))
+ return -EINVAL;
+
if (dir == IIO_EV_DIR_RISING)
data->thresh_data[chan->address].high_thresh = val;
else
data->thresh_data[chan->address].low_thresh = val;
- break;
+ return 0;
case IIO_EV_INFO_PERIOD:
dr = data->channel_data[chan->address].data_rate;
period = val * USEC_PER_SEC + val2;
for (i = 0; i < ARRAY_SIZE(ads1015_comp_queue) - 1; i++) {
if (period <= ads1015_comp_queue[i] *
- USEC_PER_SEC / data->data_rate[dr])
+ USEC_PER_SEC / data_rate[dr])
break;
}
data->thresh_data[chan->address].comp_queue = i;
- break;
+ return 0;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_read_event_config(struct iio_dev *indio_dev,
@@ -621,25 +681,19 @@ static int ads1015_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
struct ads1015_data *data = iio_priv(indio_dev);
- int ret = 0;
- mutex_lock(&data->lock);
- if (data->event_channel == chan->address) {
- switch (dir) {
- case IIO_EV_DIR_RISING:
- ret = 1;
- break;
- case IIO_EV_DIR_EITHER:
- ret = (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- }
- mutex_unlock(&data->lock);
+ guard(mutex)(&data->lock);
+ if (data->event_channel != chan->address)
+ return 0;
- return ret;
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return 1;
+ case IIO_EV_DIR_EITHER:
+ return (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW);
+ default:
+ return -EINVAL;
+ }
}
static int ads1015_enable_event_config(struct ads1015_data *data,
@@ -717,30 +771,25 @@ static int ads1015_disable_event_config(struct ads1015_data *data,
static int ads1015_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir, bool state)
{
struct ads1015_data *data = iio_priv(indio_dev);
int ret;
int comp_mode = (dir == IIO_EV_DIR_EITHER) ?
ADS1015_CFG_COMP_MODE_WINDOW : ADS1015_CFG_COMP_MODE_TRAD;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
/* Prevent from enabling both buffer and event at a time */
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret) {
- mutex_unlock(&data->lock);
- return ret;
- }
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
if (state)
ret = ads1015_enable_event_config(data, chan, comp_mode);
else
ret = ads1015_disable_event_config(data, chan, comp_mode);
- iio_device_release_direct_mode(indio_dev);
- mutex_unlock(&data->lock);
-
+ iio_device_release_direct(indio_dev);
return ret;
}
@@ -788,60 +837,24 @@ static int ads1015_buffer_postdisable(struct iio_dev *indio_dev)
static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
.preenable = ads1015_buffer_preenable,
- .postenable = iio_triggered_buffer_postenable,
- .predisable = iio_triggered_buffer_predisable,
.postdisable = ads1015_buffer_postdisable,
.validate_scan_mask = &iio_validate_scan_mask_onehot,
};
-static IIO_CONST_ATTR_NAMED(ads1015_scale_available, scale_available,
- "3 2 1 0.5 0.25 0.125");
-static IIO_CONST_ATTR_NAMED(ads1115_scale_available, scale_available,
- "0.1875 0.125 0.0625 0.03125 0.015625 0.007813");
-
-static IIO_CONST_ATTR_NAMED(ads1015_sampling_frequency_available,
- sampling_frequency_available, "128 250 490 920 1600 2400 3300");
-static IIO_CONST_ATTR_NAMED(ads1115_sampling_frequency_available,
- sampling_frequency_available, "8 16 32 64 128 250 475 860");
-
-static struct attribute *ads1015_attributes[] = {
- &iio_const_attr_ads1015_scale_available.dev_attr.attr,
- &iio_const_attr_ads1015_sampling_frequency_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ads1015_attribute_group = {
- .attrs = ads1015_attributes,
-};
-
-static struct attribute *ads1115_attributes[] = {
- &iio_const_attr_ads1115_scale_available.dev_attr.attr,
- &iio_const_attr_ads1115_sampling_frequency_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ads1115_attribute_group = {
- .attrs = ads1115_attributes,
-};
-
static const struct iio_info ads1015_info = {
+ .read_avail = ads1015_read_avail,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
.read_event_value = ads1015_read_event,
.write_event_value = ads1015_write_event,
.read_event_config = ads1015_read_event_config,
.write_event_config = ads1015_write_event_config,
- .attrs = &ads1015_attribute_group,
};
-static const struct iio_info ads1115_info = {
+static const struct iio_info tla2024_info = {
+ .read_avail = ads1015_read_avail,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
- .read_event_value = ads1015_read_event,
- .write_event_value = ads1015_write_event,
- .read_event_config = ads1015_read_event_config,
- .write_event_config = ads1015_write_event_config,
- .attrs = &ads1115_attribute_group,
};
static int ads1015_client_get_channels_config(struct i2c_client *client)
@@ -849,10 +862,9 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
struct device *dev = &client->dev;
- struct fwnode_handle *node;
int i = -1;
- device_for_each_child_node(dev, node) {
+ device_for_each_child_node_scoped(dev, node) {
u32 pval;
unsigned int channel;
unsigned int pga = ADS1015_DEFAULT_PGA;
@@ -872,9 +884,8 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
if (!fwnode_property_read_u32(node, "ti,gain", &pval)) {
pga = pval;
- if (pga > 6) {
+ if (pga > 5) {
dev_err(dev, "invalid gain on %pfw\n", node);
- fwnode_handle_put(node);
return -EINVAL;
}
}
@@ -883,7 +894,6 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
data_rate = pval;
if (data_rate > 7) {
dev_err(dev, "invalid data_rate on %pfw\n", node);
- fwnode_handle_put(node);
return -EINVAL;
}
}
@@ -921,15 +931,18 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
mode << ADS1015_CFG_MOD_SHIFT);
}
-static int ads1015_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ads1015_probe(struct i2c_client *client)
{
+ const struct ads1015_chip_data *chip;
struct iio_dev *indio_dev;
struct ads1015_data *data;
int ret;
- enum chip_ids chip;
int i;
+ chip = i2c_get_match_data(client);
+ if (!chip)
+ return dev_err_probe(&client->dev, -EINVAL, "Unknown chip\n");
+
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@@ -939,33 +952,15 @@ static int ads1015_probe(struct i2c_client *client,
mutex_init(&data->lock);
- indio_dev->dev.parent = &client->dev;
- indio_dev->dev.of_node = client->dev.of_node;
indio_dev->name = ADS1015_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
- chip = (enum chip_ids)device_get_match_data(&client->dev);
- if (chip == ADSXXXX)
- chip = id->driver_data;
- switch (chip) {
- case ADS1015:
- indio_dev->channels = ads1015_channels;
- indio_dev->num_channels = ARRAY_SIZE(ads1015_channels);
- indio_dev->info = &ads1015_info;
- data->data_rate = (unsigned int *) &ads1015_data_rate;
- break;
- case ADS1115:
- indio_dev->channels = ads1115_channels;
- indio_dev->num_channels = ARRAY_SIZE(ads1115_channels);
- indio_dev->info = &ads1115_info;
- data->data_rate = (unsigned int *) &ads1115_data_rate;
- break;
- default:
- dev_err(&client->dev, "Unknown chip %d\n", chip);
- return -EINVAL;
- }
-
+ indio_dev->channels = chip->channels;
+ indio_dev->num_channels = chip->num_channels;
+ indio_dev->info = chip->info;
+ data->chip = chip;
data->event_channel = ADS1015_CHANNELS;
+
/*
* Set default lower and upper threshold to min and max value
* respectively.
@@ -980,7 +975,9 @@ static int ads1015_probe(struct i2c_client *client,
/* we need to keep this ABI the same as used by hwmon ADS1015 driver */
ads1015_get_channels_config(client);
- data->regmap = devm_regmap_init_i2c(client, &ads1015_regmap_config);
+ data->regmap = devm_regmap_init_i2c(client, chip->has_comparator ?
+ &ads1015_regmap_config :
+ &tla2024_regmap_config);
if (IS_ERR(data->regmap)) {
dev_err(&client->dev, "Failed to allocate register map\n");
return PTR_ERR(data->regmap);
@@ -994,9 +991,8 @@ static int ads1015_probe(struct i2c_client *client,
return ret;
}
- if (client->irq) {
- unsigned long irq_trig =
- irqd_get_trigger_type(irq_get_irq_data(client->irq));
+ if (client->irq && chip->has_comparator) {
+ unsigned long irq_trig = irq_get_trigger_type(client->irq);
unsigned int cfg_comp_mask = ADS1015_CFG_COMP_QUE_MASK |
ADS1015_CFG_COMP_LAT_MASK | ADS1015_CFG_COMP_POL_MASK;
unsigned int cfg_comp =
@@ -1004,11 +1000,13 @@ static int ads1015_probe(struct i2c_client *client,
1 << ADS1015_CFG_COMP_LAT_SHIFT;
switch (irq_trig) {
+ case IRQF_TRIGGER_FALLING:
case IRQF_TRIGGER_LOW:
cfg_comp |= ADS1015_CFG_COMP_POL_LOW <<
ADS1015_CFG_COMP_POL_SHIFT;
break;
case IRQF_TRIGGER_HIGH:
+ case IRQF_TRIGGER_RISING:
cfg_comp |= ADS1015_CFG_COMP_POL_HIGH <<
ADS1015_CFG_COMP_POL_SHIFT;
break;
@@ -1051,19 +1049,22 @@ static int ads1015_probe(struct i2c_client *client,
return 0;
}
-static int ads1015_remove(struct i2c_client *client)
+static void ads1015_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
+ int ret;
iio_device_unregister(indio_dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
/* power down single shot mode */
- return ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
+ ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
+ if (ret)
+ dev_warn(&client->dev, "Failed to power down (%pe)\n",
+ ERR_PTR(ret));
}
#ifdef CONFIG_PM
@@ -1094,23 +1095,52 @@ static const struct dev_pm_ops ads1015_pm_ops = {
ads1015_runtime_resume, NULL)
};
+static const struct ads1015_chip_data ads1015_data = {
+ .channels = ads1015_channels,
+ .num_channels = ARRAY_SIZE(ads1015_channels),
+ .info = &ads1015_info,
+ .data_rate = ads1015_data_rate,
+ .data_rate_len = ARRAY_SIZE(ads1015_data_rate),
+ .scale = ads1015_scale,
+ .scale_len = ARRAY_SIZE(ads1015_scale),
+ .has_comparator = true,
+};
+
+static const struct ads1015_chip_data ads1115_data = {
+ .channels = ads1115_channels,
+ .num_channels = ARRAY_SIZE(ads1115_channels),
+ .info = &ads1015_info,
+ .data_rate = ads1115_data_rate,
+ .data_rate_len = ARRAY_SIZE(ads1115_data_rate),
+ .scale = ads1115_scale,
+ .scale_len = ARRAY_SIZE(ads1115_scale),
+ .has_comparator = true,
+};
+
+static const struct ads1015_chip_data tla2024_data = {
+ .channels = tla2024_channels,
+ .num_channels = ARRAY_SIZE(tla2024_channels),
+ .info = &tla2024_info,
+ .data_rate = ads1015_data_rate,
+ .data_rate_len = ARRAY_SIZE(ads1015_data_rate),
+ .scale = ads1015_scale,
+ .scale_len = ARRAY_SIZE(ads1015_scale),
+ .has_comparator = false,
+};
+
static const struct i2c_device_id ads1015_id[] = {
- {"ads1015", ADS1015},
- {"ads1115", ADS1115},
- {}
+ { "ads1015", (kernel_ulong_t)&ads1015_data },
+ { "ads1115", (kernel_ulong_t)&ads1115_data },
+ { "tla2024", (kernel_ulong_t)&tla2024_data },
+ { }
};
MODULE_DEVICE_TABLE(i2c, ads1015_id);
static const struct of_device_id ads1015_of_match[] = {
- {
- .compatible = "ti,ads1015",
- .data = (void *)ADS1015
- },
- {
- .compatible = "ti,ads1115",
- .data = (void *)ADS1115
- },
- {}
+ { .compatible = "ti,ads1015", .data = &ads1015_data },
+ { .compatible = "ti,ads1115", .data = &ads1115_data },
+ { .compatible = "ti,tla2024", .data = &tla2024_data },
+ { }
};
MODULE_DEVICE_TABLE(of, ads1015_of_match);