Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Mike Looijmans | 1873 | 99.89% | 1 | 33.33% |
Dan Carpenter | 1 | 0.05% | 1 | 33.33% |
Uwe Kleine-König | 1 | 0.05% | 1 | 33.33% |
Total | 1875 | 3 |
// SPDX-License-Identifier: GPL-2.0-only /* * ADS1100 - Texas Instruments Analog-to-Digital Converter * * Copyright (c) 2023, Topic Embedded Products * * Datasheet: https://www.ti.com/lit/gpn/ads1100 * IIO driver for ADS1100 and ADS1000 ADC 16-bit I2C */ #include <linux/bitfield.h> #include <linux/bits.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/units.h> #include <linux/iio/iio.h> #include <linux/iio/types.h> /* The ADS1100 has a single byte config register */ /* Conversion in progress bit */ #define ADS1100_CFG_ST_BSY BIT(7) /* Single conversion bit */ #define ADS1100_CFG_SC BIT(4) /* Data rate */ #define ADS1100_DR_MASK GENMASK(3, 2) /* Gain */ #define ADS1100_PGA_MASK GENMASK(1, 0) #define ADS1100_CONTINUOUS 0 #define ADS1100_SINGLESHOT ADS1100_CFG_SC #define ADS1100_SLEEP_DELAY_MS 2000 static const int ads1100_data_rate[] = { 128, 32, 16, 8 }; static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 }; struct ads1100_data { struct i2c_client *client; struct regulator *reg_vdd; struct mutex lock; int scale_avail[2 * 4]; /* 4 gain settings */ u8 config; bool supports_data_rate; /* Only the ADS1100 can select the rate */ }; static const struct iio_chan_spec ads1100_channel = { .type = IIO_VOLTAGE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_all = 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_type = { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_CPU, }, .datasheet_name = "AIN", }; static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value) { int ret; u8 config = (data->config & ~mask) | (value & mask); if (data->config == config) return 0; /* Already done */ ret = i2c_master_send(data->client, &config, 1); if (ret < 0) return ret; data->config = config; return 0; }; static int ads1100_data_bits(struct ads1100_data *data) { return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)]; } static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val) { int ret; __be16 buffer; s16 value; if (chan != 0) return -EINVAL; ret = pm_runtime_resume_and_get(&data->client->dev); if (ret < 0) return ret; ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); pm_runtime_mark_last_busy(&data->client->dev); pm_runtime_put_autosuspend(&data->client->dev); if (ret < 0) { dev_err(&data->client->dev, "I2C read fail: %d\n", ret); return ret; } /* Value is always 16-bit 2's complement */ value = be16_to_cpu(buffer); /* Shift result to compensate for bit resolution vs. sample rate */ value <<= 16 - ads1100_data_bits(data); *val = sign_extend32(value, 15); return 0; } static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) { int microvolts; int gain; /* With Vdd between 2.7 and 5V, the scale is always below 1 */ if (val) return -EINVAL; if (!val2) return -EINVAL; microvolts = regulator_get_voltage(data->reg_vdd); /* * val2 is in 'micro' units, n = val2 / 1000000 * result must be millivolts, d = microvolts / 1000 * the full-scale value is d/n, corresponds to 2^15, * hence the gain = (d / n) >> 15, factoring out the 1000 and moving the * bitshift so everything fits in 32-bits yields this formula. */ gain = DIV_ROUND_CLOSEST(microvolts, BIT(15)) * MILLI / val2; if (gain < BIT(0) || gain > BIT(3)) return -EINVAL; ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1); return 0; } static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate) { unsigned int i; unsigned int size; size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1; for (i = 0; i < size; i++) { if (ads1100_data_rate[i] == rate) return ads1100_set_config_bits(data, ADS1100_DR_MASK, FIELD_PREP(ADS1100_DR_MASK, i)); } return -EINVAL; } static int ads1100_get_vdd_millivolts(struct ads1100_data *data) { return regulator_get_voltage(data->reg_vdd) / (MICRO / MILLI); } static void ads1100_calc_scale_avail(struct ads1100_data *data) { int millivolts = ads1100_get_vdd_millivolts(data); unsigned int i; for (i = 0; i < ARRAY_SIZE(data->scale_avail) / 2; i++) { data->scale_avail[i * 2 + 0] = millivolts; data->scale_avail[i * 2 + 1] = 15 + i; } } static int ads1100_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask) { struct ads1100_data *data = iio_priv(indio_dev); if (chan->type != IIO_VOLTAGE) return -EINVAL; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: *type = IIO_VAL_INT; *vals = ads1100_data_rate; if (data->supports_data_rate) *length = ARRAY_SIZE(ads1100_data_rate); else *length = 1; return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SCALE: *type = IIO_VAL_FRACTIONAL_LOG2; *vals = data->scale_avail; *length = ARRAY_SIZE(data->scale_avail); return IIO_AVAIL_LIST; default: return -EINVAL; } } static int ads1100_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { int ret; struct ads1100_data *data = iio_priv(indio_dev); mutex_lock(&data->lock); switch (mask) { case IIO_CHAN_INFO_RAW: ret = iio_device_claim_direct_mode(indio_dev); if (ret) break; ret = ads1100_get_adc_result(data, chan->address, val); if (ret >= 0) ret = IIO_VAL_INT; iio_device_release_direct_mode(indio_dev); break; case IIO_CHAN_INFO_SCALE: /* full-scale is the supply voltage in millivolts */ *val = ads1100_get_vdd_millivolts(data); *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config); ret = IIO_VAL_FRACTIONAL_LOG2; break; case IIO_CHAN_INFO_SAMP_FREQ: *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)]; ret = IIO_VAL_INT; break; default: ret = -EINVAL; break; } mutex_unlock(&data->lock); return ret; } static int ads1100_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct ads1100_data *data = iio_priv(indio_dev); int ret; mutex_lock(&data->lock); switch (mask) { case IIO_CHAN_INFO_SCALE: ret = ads1100_set_scale(data, val, val2); break; case IIO_CHAN_INFO_SAMP_FREQ: ret = ads1100_set_data_rate(data, chan->address, val); break; default: ret = -EINVAL; break; } mutex_unlock(&data->lock); return ret; } static const struct iio_info ads1100_info = { .read_avail = ads1100_read_avail, .read_raw = ads1100_read_raw, .write_raw = ads1100_write_raw, }; static int ads1100_setup(struct ads1100_data *data) { int ret; u8 buffer[3]; /* Setup continuous sampling mode at 8sps */ buffer[0] = ADS1100_DR_MASK | ADS1100_CONTINUOUS; ret = i2c_master_send(data->client, buffer, 1); if (ret < 0) return ret; ret = i2c_master_recv(data->client, buffer, sizeof(buffer)); if (ret < 0) return ret; /* Config register returned in third byte, strip away the busy status */ data->config = buffer[2] & ~ADS1100_CFG_ST_BSY; /* Detect the sample rate capability by checking the DR bits */ data->supports_data_rate = FIELD_GET(ADS1100_DR_MASK, buffer[2]) != 0; return 0; } static void ads1100_reg_disable(void *reg) { regulator_disable(reg); } static void ads1100_disable_continuous(void *data) { ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_SINGLESHOT); } static int ads1100_probe(struct i2c_client *client) { struct iio_dev *indio_dev; struct ads1100_data *data; struct device *dev = &client->dev; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); dev_set_drvdata(dev, data); data->client = client; mutex_init(&data->lock); indio_dev->name = "ads1100"; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = &ads1100_channel; indio_dev->num_channels = 1; indio_dev->info = &ads1100_info; data->reg_vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(data->reg_vdd)) return dev_err_probe(dev, PTR_ERR(data->reg_vdd), "Failed to get vdd regulator\n"); ret = regulator_enable(data->reg_vdd); if (ret < 0) return dev_err_probe(dev, ret, "Failed to enable vdd regulator\n"); ret = devm_add_action_or_reset(dev, ads1100_reg_disable, data->reg_vdd); if (ret) return ret; ret = ads1100_setup(data); if (ret) return dev_err_probe(dev, ret, "Failed to communicate with device\n"); ret = devm_add_action_or_reset(dev, ads1100_disable_continuous, data); if (ret) return ret; ads1100_calc_scale_avail(data); pm_runtime_set_autosuspend_delay(dev, ADS1100_SLEEP_DELAY_MS); pm_runtime_use_autosuspend(dev); pm_runtime_set_active(dev); ret = devm_pm_runtime_enable(dev); if (ret) return dev_err_probe(dev, ret, "Failed to enable pm_runtime\n"); ret = devm_iio_device_register(dev, indio_dev); if (ret) return dev_err_probe(dev, ret, "Failed to register IIO device\n"); return 0; } static int ads1100_runtime_suspend(struct device *dev) { struct ads1100_data *data = dev_get_drvdata(dev); ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_SINGLESHOT); regulator_disable(data->reg_vdd); return 0; } static int ads1100_runtime_resume(struct device *dev) { struct ads1100_data *data = dev_get_drvdata(dev); int ret; ret = regulator_enable(data->reg_vdd); if (ret) { dev_err(&data->client->dev, "Failed to enable Vdd\n"); return ret; } /* * We'll always change the mode bit in the config register, so there is * no need here to "force" a write to the config register. If the device * has been power-cycled, we'll re-write its config register now. */ return ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_CONTINUOUS); } static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops, ads1100_runtime_suspend, ads1100_runtime_resume, NULL); static const struct i2c_device_id ads1100_id[] = { { "ads1100" }, { "ads1000" }, { } }; MODULE_DEVICE_TABLE(i2c, ads1100_id); static const struct of_device_id ads1100_of_match[] = { {.compatible = "ti,ads1100" }, {.compatible = "ti,ads1000" }, { } }; MODULE_DEVICE_TABLE(of, ads1100_of_match); static struct i2c_driver ads1100_driver = { .driver = { .name = "ads1100", .of_match_table = ads1100_of_match, .pm = pm_ptr(&ads1100_pm_ops), }, .probe = ads1100_probe, .id_table = ads1100_id, }; module_i2c_driver(ads1100_driver); MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); MODULE_DESCRIPTION("Texas Instruments ADS1100 ADC driver"); MODULE_LICENSE("GPL");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1