brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 6c2cb3d Raw
242 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI ADC081C/ADC101C/ADC121C 8/10/12-bit ADC driver4 *5 * Copyright (C) 2012 Avionic Design GmbH6 * Copyright (C) 2016 Intel7 *8 * Datasheets:9 *	https://www.ti.com/lit/ds/symlink/adc081c021.pdf10 *	https://www.ti.com/lit/ds/symlink/adc101c021.pdf11 *	https://www.ti.com/lit/ds/symlink/adc121c021.pdf12 *13 * The devices have a very similar interface and differ mostly in the number of14 * bits handled. For the 8-bit and 10-bit models the least-significant 4 or 215 * bits of value registers are reserved.16 */17 18#include <linux/err.h>19#include <linux/i2c.h>20#include <linux/module.h>21#include <linux/mod_devicetable.h>22#include <linux/property.h>23 24#include <linux/iio/iio.h>25#include <linux/iio/buffer.h>26#include <linux/iio/trigger_consumer.h>27#include <linux/iio/triggered_buffer.h>28#include <linux/regulator/consumer.h>29 30struct adc081c {31	struct i2c_client *i2c;32	struct regulator *ref;33 34	/* 8, 10 or 12 */35	int bits;36 37	/* Ensure natural alignment of buffer elements */38	struct {39		u16 channel;40		s64 ts __aligned(8);41	} scan;42};43 44#define REG_CONV_RES 0x0045 46static int adc081c_read_raw(struct iio_dev *iio,47			    struct iio_chan_spec const *channel, int *value,48			    int *shift, long mask)49{50	struct adc081c *adc = iio_priv(iio);51	int err;52 53	switch (mask) {54	case IIO_CHAN_INFO_RAW:55		err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES);56		if (err < 0)57			return err;58 59		*value = (err & 0xFFF) >> (12 - adc->bits);60		return IIO_VAL_INT;61 62	case IIO_CHAN_INFO_SCALE:63		err = regulator_get_voltage(adc->ref);64		if (err < 0)65			return err;66 67		*value = err / 1000;68		*shift = adc->bits;69 70		return IIO_VAL_FRACTIONAL_LOG2;71 72	default:73		break;74	}75 76	return -EINVAL;77}78 79#define ADCxx1C_CHAN(_bits) {					\80	.type = IIO_VOLTAGE,					\81	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\82	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\83	.scan_type = {						\84		.sign = 'u',					\85		.realbits = (_bits),				\86		.storagebits = 16,				\87		.shift = 12 - (_bits),				\88		.endianness = IIO_CPU,				\89	},							\90}91 92#define DEFINE_ADCxx1C_CHANNELS(_name, _bits)				\93	static const struct iio_chan_spec _name ## _channels[] = {	\94		ADCxx1C_CHAN((_bits)),					\95		IIO_CHAN_SOFT_TIMESTAMP(1),				\96	};								\97 98#define ADC081C_NUM_CHANNELS 299 100struct adcxx1c_model {101	const struct iio_chan_spec* channels;102	int bits;103};104 105#define ADCxx1C_MODEL(_name, _bits)					\106	{								\107		.channels = _name ## _channels,				\108		.bits = (_bits),					\109	}110 111DEFINE_ADCxx1C_CHANNELS(adc081c,  8);112DEFINE_ADCxx1C_CHANNELS(adc101c, 10);113DEFINE_ADCxx1C_CHANNELS(adc121c, 12);114 115/* Model ids are indexes in _models array */116enum adcxx1c_model_id {117	ADC081C = 0,118	ADC101C = 1,119	ADC121C = 2,120};121 122static struct adcxx1c_model adcxx1c_models[] = {123	ADCxx1C_MODEL(adc081c,  8),124	ADCxx1C_MODEL(adc101c, 10),125	ADCxx1C_MODEL(adc121c, 12),126};127 128static const struct iio_info adc081c_info = {129	.read_raw = adc081c_read_raw,130};131 132static irqreturn_t adc081c_trigger_handler(int irq, void *p)133{134	struct iio_poll_func *pf = p;135	struct iio_dev *indio_dev = pf->indio_dev;136	struct adc081c *data = iio_priv(indio_dev);137	int ret;138 139	ret = i2c_smbus_read_word_swapped(data->i2c, REG_CONV_RES);140	if (ret < 0)141		goto out;142	data->scan.channel = ret;143	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,144					   iio_get_time_ns(indio_dev));145out:146	iio_trigger_notify_done(indio_dev->trig);147	return IRQ_HANDLED;148}149 150static void adc081c_reg_disable(void *reg)151{152	regulator_disable(reg);153}154 155static int adc081c_probe(struct i2c_client *client)156{157	struct iio_dev *iio;158	struct adc081c *adc;159	const struct adcxx1c_model *model;160	int err;161 162	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))163		return -EOPNOTSUPP;164 165	model = i2c_get_match_data(client);166 167	iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));168	if (!iio)169		return -ENOMEM;170 171	adc = iio_priv(iio);172	adc->i2c = client;173	adc->bits = model->bits;174 175	adc->ref = devm_regulator_get(&client->dev, "vref");176	if (IS_ERR(adc->ref))177		return PTR_ERR(adc->ref);178 179	err = regulator_enable(adc->ref);180	if (err < 0)181		return err;182 183	err = devm_add_action_or_reset(&client->dev, adc081c_reg_disable,184				       adc->ref);185	if (err)186		return err;187 188	iio->name = dev_name(&client->dev);189	iio->modes = INDIO_DIRECT_MODE;190	iio->info = &adc081c_info;191 192	iio->channels = model->channels;193	iio->num_channels = ADC081C_NUM_CHANNELS;194 195	err = devm_iio_triggered_buffer_setup(&client->dev, iio, NULL,196					      adc081c_trigger_handler, NULL);197	if (err < 0) {198		dev_err(&client->dev, "iio triggered buffer setup failed\n");199		return err;200	}201 202	return devm_iio_device_register(&client->dev, iio);203}204 205static const struct i2c_device_id adc081c_id[] = {206	{ "adc081c", (kernel_ulong_t)&adcxx1c_models[ADC081C] },207	{ "adc101c", (kernel_ulong_t)&adcxx1c_models[ADC101C] },208	{ "adc121c", (kernel_ulong_t)&adcxx1c_models[ADC121C] },209	{ }210};211MODULE_DEVICE_TABLE(i2c, adc081c_id);212 213static const struct acpi_device_id adc081c_acpi_match[] = {214	/* Used on some AAEON boards */215	{ "ADC081C", (kernel_ulong_t)&adcxx1c_models[ADC081C] },216	{ }217};218MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match);219 220static const struct of_device_id adc081c_of_match[] = {221	{ .compatible = "ti,adc081c", .data = &adcxx1c_models[ADC081C] },222	{ .compatible = "ti,adc101c", .data = &adcxx1c_models[ADC101C] },223	{ .compatible = "ti,adc121c", .data = &adcxx1c_models[ADC121C] },224	{ }225};226MODULE_DEVICE_TABLE(of, adc081c_of_match);227 228static struct i2c_driver adc081c_driver = {229	.driver = {230		.name = "adc081c",231		.of_match_table = adc081c_of_match,232		.acpi_match_table = adc081c_acpi_match,233	},234	.probe = adc081c_probe,235	.id_table = adc081c_id,236};237module_i2c_driver(adc081c_driver);238 239MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");240MODULE_DESCRIPTION("Texas Instruments ADC081C/ADC101C/ADC121C driver");241MODULE_LICENSE("GPL v2");242