1bc0a409cSThierry Reding /* 2a6b5ec88SCrestez Dan Leonard * TI ADC081C/ADC101C/ADC121C 8/10/12-bit ADC driver 3a6b5ec88SCrestez Dan Leonard * 4bc0a409cSThierry Reding * Copyright (C) 2012 Avionic Design GmbH 5a6b5ec88SCrestez Dan Leonard * Copyright (C) 2016 Intel 6bc0a409cSThierry Reding * 7bc0a409cSThierry Reding * This program is free software; you can redistribute it and/or modify 8bc0a409cSThierry Reding * it under the terms of the GNU General Public License version 2 as 9bc0a409cSThierry Reding * published by the Free Software Foundation. 10a6b5ec88SCrestez Dan Leonard * 11a6b5ec88SCrestez Dan Leonard * Datasheets: 12a6b5ec88SCrestez Dan Leonard * http://www.ti.com/lit/ds/symlink/adc081c021.pdf 13a6b5ec88SCrestez Dan Leonard * http://www.ti.com/lit/ds/symlink/adc101c021.pdf 14a6b5ec88SCrestez Dan Leonard * http://www.ti.com/lit/ds/symlink/adc121c021.pdf 15a6b5ec88SCrestez Dan Leonard * 16a6b5ec88SCrestez Dan Leonard * The devices have a very similar interface and differ mostly in the number of 17a6b5ec88SCrestez Dan Leonard * bits handled. For the 8-bit and 10-bit models the least-significant 4 or 2 18a6b5ec88SCrestez Dan Leonard * bits of value registers are reserved. 19bc0a409cSThierry Reding */ 20bc0a409cSThierry Reding 21bc0a409cSThierry Reding #include <linux/err.h> 22bc0a409cSThierry Reding #include <linux/i2c.h> 23bc0a409cSThierry Reding #include <linux/module.h> 241f100e80SSachin Kamat #include <linux/of.h> 25*7feae871SDan O'Donovan #include <linux/acpi.h> 26bc0a409cSThierry Reding 27bc0a409cSThierry Reding #include <linux/iio/iio.h> 2808e05d1fSCrestez Dan Leonard #include <linux/iio/buffer.h> 2908e05d1fSCrestez Dan Leonard #include <linux/iio/trigger_consumer.h> 3008e05d1fSCrestez Dan Leonard #include <linux/iio/triggered_buffer.h> 31bc0a409cSThierry Reding #include <linux/regulator/consumer.h> 32bc0a409cSThierry Reding 33bc0a409cSThierry Reding struct adc081c { 34bc0a409cSThierry Reding struct i2c_client *i2c; 35bc0a409cSThierry Reding struct regulator *ref; 36a6b5ec88SCrestez Dan Leonard 37a6b5ec88SCrestez Dan Leonard /* 8, 10 or 12 */ 38a6b5ec88SCrestez Dan Leonard int bits; 39bc0a409cSThierry Reding }; 40bc0a409cSThierry Reding 41bc0a409cSThierry Reding #define REG_CONV_RES 0x00 42bc0a409cSThierry Reding 43bc0a409cSThierry Reding static int adc081c_read_raw(struct iio_dev *iio, 44bc0a409cSThierry Reding struct iio_chan_spec const *channel, int *value, 45bc0a409cSThierry Reding int *shift, long mask) 46bc0a409cSThierry Reding { 47bc0a409cSThierry Reding struct adc081c *adc = iio_priv(iio); 48bc0a409cSThierry Reding int err; 49bc0a409cSThierry Reding 50bc0a409cSThierry Reding switch (mask) { 51bc0a409cSThierry Reding case IIO_CHAN_INFO_RAW: 52bc0a409cSThierry Reding err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES); 53bc0a409cSThierry Reding if (err < 0) 54bc0a409cSThierry Reding return err; 55bc0a409cSThierry Reding 56a6b5ec88SCrestez Dan Leonard *value = (err & 0xFFF) >> (12 - adc->bits); 57bc0a409cSThierry Reding return IIO_VAL_INT; 58bc0a409cSThierry Reding 59bc0a409cSThierry Reding case IIO_CHAN_INFO_SCALE: 60bc0a409cSThierry Reding err = regulator_get_voltage(adc->ref); 61bc0a409cSThierry Reding if (err < 0) 62bc0a409cSThierry Reding return err; 63bc0a409cSThierry Reding 64bc0a409cSThierry Reding *value = err / 1000; 65a6b5ec88SCrestez Dan Leonard *shift = adc->bits; 66bc0a409cSThierry Reding 67bc0a409cSThierry Reding return IIO_VAL_FRACTIONAL_LOG2; 68bc0a409cSThierry Reding 69bc0a409cSThierry Reding default: 70bc0a409cSThierry Reding break; 71bc0a409cSThierry Reding } 72bc0a409cSThierry Reding 73bc0a409cSThierry Reding return -EINVAL; 74bc0a409cSThierry Reding } 75bc0a409cSThierry Reding 7608e05d1fSCrestez Dan Leonard #define ADCxx1C_CHAN(_bits) { \ 7708e05d1fSCrestez Dan Leonard .type = IIO_VOLTAGE, \ 7808e05d1fSCrestez Dan Leonard .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 7908e05d1fSCrestez Dan Leonard .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 8008e05d1fSCrestez Dan Leonard .scan_type = { \ 8108e05d1fSCrestez Dan Leonard .sign = 'u', \ 8208e05d1fSCrestez Dan Leonard .realbits = (_bits), \ 8308e05d1fSCrestez Dan Leonard .storagebits = 16, \ 8408e05d1fSCrestez Dan Leonard .shift = 12 - (_bits), \ 8508e05d1fSCrestez Dan Leonard .endianness = IIO_CPU, \ 8608e05d1fSCrestez Dan Leonard }, \ 8708e05d1fSCrestez Dan Leonard } 8808e05d1fSCrestez Dan Leonard 8908e05d1fSCrestez Dan Leonard #define DEFINE_ADCxx1C_CHANNELS(_name, _bits) \ 9008e05d1fSCrestez Dan Leonard static const struct iio_chan_spec _name ## _channels[] = { \ 9108e05d1fSCrestez Dan Leonard ADCxx1C_CHAN((_bits)), \ 9208e05d1fSCrestez Dan Leonard IIO_CHAN_SOFT_TIMESTAMP(1), \ 9308e05d1fSCrestez Dan Leonard }; \ 9408e05d1fSCrestez Dan Leonard 9508e05d1fSCrestez Dan Leonard #define ADC081C_NUM_CHANNELS 2 96bc0a409cSThierry Reding 97a6b5ec88SCrestez Dan Leonard struct adcxx1c_model { 9808e05d1fSCrestez Dan Leonard const struct iio_chan_spec* channels; 99a6b5ec88SCrestez Dan Leonard int bits; 100a6b5ec88SCrestez Dan Leonard }; 101a6b5ec88SCrestez Dan Leonard 10208e05d1fSCrestez Dan Leonard #define ADCxx1C_MODEL(_name, _bits) \ 103a6b5ec88SCrestez Dan Leonard { \ 10408e05d1fSCrestez Dan Leonard .channels = _name ## _channels, \ 105a6b5ec88SCrestez Dan Leonard .bits = (_bits), \ 106a6b5ec88SCrestez Dan Leonard } 107a6b5ec88SCrestez Dan Leonard 10808e05d1fSCrestez Dan Leonard DEFINE_ADCxx1C_CHANNELS(adc081c, 8); 10908e05d1fSCrestez Dan Leonard DEFINE_ADCxx1C_CHANNELS(adc101c, 10); 11008e05d1fSCrestez Dan Leonard DEFINE_ADCxx1C_CHANNELS(adc121c, 12); 11108e05d1fSCrestez Dan Leonard 112a6b5ec88SCrestez Dan Leonard /* Model ids are indexes in _models array */ 113a6b5ec88SCrestez Dan Leonard enum adcxx1c_model_id { 114a6b5ec88SCrestez Dan Leonard ADC081C = 0, 115a6b5ec88SCrestez Dan Leonard ADC101C = 1, 116a6b5ec88SCrestez Dan Leonard ADC121C = 2, 117a6b5ec88SCrestez Dan Leonard }; 118a6b5ec88SCrestez Dan Leonard 119a6b5ec88SCrestez Dan Leonard static struct adcxx1c_model adcxx1c_models[] = { 12008e05d1fSCrestez Dan Leonard ADCxx1C_MODEL(adc081c, 8), 12108e05d1fSCrestez Dan Leonard ADCxx1C_MODEL(adc101c, 10), 12208e05d1fSCrestez Dan Leonard ADCxx1C_MODEL(adc121c, 12), 123a6b5ec88SCrestez Dan Leonard }; 124a6b5ec88SCrestez Dan Leonard 125bc0a409cSThierry Reding static const struct iio_info adc081c_info = { 126bc0a409cSThierry Reding .read_raw = adc081c_read_raw, 127bc0a409cSThierry Reding .driver_module = THIS_MODULE, 128bc0a409cSThierry Reding }; 129bc0a409cSThierry Reding 13008e05d1fSCrestez Dan Leonard static irqreturn_t adc081c_trigger_handler(int irq, void *p) 13108e05d1fSCrestez Dan Leonard { 13208e05d1fSCrestez Dan Leonard struct iio_poll_func *pf = p; 13308e05d1fSCrestez Dan Leonard struct iio_dev *indio_dev = pf->indio_dev; 13408e05d1fSCrestez Dan Leonard struct adc081c *data = iio_priv(indio_dev); 13508e05d1fSCrestez Dan Leonard u16 buf[8]; /* 2 bytes data + 6 bytes padding + 8 bytes timestamp */ 13608e05d1fSCrestez Dan Leonard int ret; 13708e05d1fSCrestez Dan Leonard 13808e05d1fSCrestez Dan Leonard ret = i2c_smbus_read_word_swapped(data->i2c, REG_CONV_RES); 13908e05d1fSCrestez Dan Leonard if (ret < 0) 14008e05d1fSCrestez Dan Leonard goto out; 14108e05d1fSCrestez Dan Leonard buf[0] = ret; 14208e05d1fSCrestez Dan Leonard iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); 14308e05d1fSCrestez Dan Leonard out: 14408e05d1fSCrestez Dan Leonard iio_trigger_notify_done(indio_dev->trig); 14508e05d1fSCrestez Dan Leonard return IRQ_HANDLED; 14608e05d1fSCrestez Dan Leonard } 14708e05d1fSCrestez Dan Leonard 148bc0a409cSThierry Reding static int adc081c_probe(struct i2c_client *client, 149bc0a409cSThierry Reding const struct i2c_device_id *id) 150bc0a409cSThierry Reding { 151bc0a409cSThierry Reding struct iio_dev *iio; 152bc0a409cSThierry Reding struct adc081c *adc; 153*7feae871SDan O'Donovan struct adcxx1c_model *model; 154bc0a409cSThierry Reding int err; 155bc0a409cSThierry Reding 156bc0a409cSThierry Reding if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) 157f8d9d3b4SMatt Ranostay return -EOPNOTSUPP; 158bc0a409cSThierry Reding 159*7feae871SDan O'Donovan if (ACPI_COMPANION(&client->dev)) { 160*7feae871SDan O'Donovan const struct acpi_device_id *ad_id; 161*7feae871SDan O'Donovan 162*7feae871SDan O'Donovan ad_id = acpi_match_device(client->dev.driver->acpi_match_table, 163*7feae871SDan O'Donovan &client->dev); 164*7feae871SDan O'Donovan if (!ad_id) 165*7feae871SDan O'Donovan return -ENODEV; 166*7feae871SDan O'Donovan model = &adcxx1c_models[ad_id->driver_data]; 167*7feae871SDan O'Donovan } else { 168*7feae871SDan O'Donovan model = &adcxx1c_models[id->driver_data]; 169*7feae871SDan O'Donovan } 170*7feae871SDan O'Donovan 17199e94b6dSSachin Kamat iio = devm_iio_device_alloc(&client->dev, sizeof(*adc)); 172bc0a409cSThierry Reding if (!iio) 173bc0a409cSThierry Reding return -ENOMEM; 174bc0a409cSThierry Reding 175bc0a409cSThierry Reding adc = iio_priv(iio); 176bc0a409cSThierry Reding adc->i2c = client; 177a6b5ec88SCrestez Dan Leonard adc->bits = model->bits; 178bc0a409cSThierry Reding 17999e94b6dSSachin Kamat adc->ref = devm_regulator_get(&client->dev, "vref"); 18099e94b6dSSachin Kamat if (IS_ERR(adc->ref)) 18199e94b6dSSachin Kamat return PTR_ERR(adc->ref); 182bc0a409cSThierry Reding 183bc0a409cSThierry Reding err = regulator_enable(adc->ref); 184bc0a409cSThierry Reding if (err < 0) 18599e94b6dSSachin Kamat return err; 186bc0a409cSThierry Reding 187bc0a409cSThierry Reding iio->dev.parent = &client->dev; 188bc0a409cSThierry Reding iio->name = dev_name(&client->dev); 189bc0a409cSThierry Reding iio->modes = INDIO_DIRECT_MODE; 190bc0a409cSThierry Reding iio->info = &adc081c_info; 191bc0a409cSThierry Reding 19208e05d1fSCrestez Dan Leonard iio->channels = model->channels; 19308e05d1fSCrestez Dan Leonard iio->num_channels = ADC081C_NUM_CHANNELS; 19408e05d1fSCrestez Dan Leonard 19508e05d1fSCrestez Dan Leonard err = iio_triggered_buffer_setup(iio, NULL, adc081c_trigger_handler, NULL); 19608e05d1fSCrestez Dan Leonard if (err < 0) { 19708e05d1fSCrestez Dan Leonard dev_err(&client->dev, "iio triggered buffer setup failed\n"); 19808e05d1fSCrestez Dan Leonard goto err_regulator_disable; 19908e05d1fSCrestez Dan Leonard } 200bc0a409cSThierry Reding 201bc0a409cSThierry Reding err = iio_device_register(iio); 202bc0a409cSThierry Reding if (err < 0) 20308e05d1fSCrestez Dan Leonard goto err_buffer_cleanup; 204bc0a409cSThierry Reding 205bc0a409cSThierry Reding i2c_set_clientdata(client, iio); 206bc0a409cSThierry Reding 207bc0a409cSThierry Reding return 0; 208bc0a409cSThierry Reding 20908e05d1fSCrestez Dan Leonard err_buffer_cleanup: 21008e05d1fSCrestez Dan Leonard iio_triggered_buffer_cleanup(iio); 21108e05d1fSCrestez Dan Leonard err_regulator_disable: 212bc0a409cSThierry Reding regulator_disable(adc->ref); 213bc0a409cSThierry Reding 214bc0a409cSThierry Reding return err; 215bc0a409cSThierry Reding } 216bc0a409cSThierry Reding 217bc0a409cSThierry Reding static int adc081c_remove(struct i2c_client *client) 218bc0a409cSThierry Reding { 219bc0a409cSThierry Reding struct iio_dev *iio = i2c_get_clientdata(client); 220bc0a409cSThierry Reding struct adc081c *adc = iio_priv(iio); 221bc0a409cSThierry Reding 222bc0a409cSThierry Reding iio_device_unregister(iio); 22308e05d1fSCrestez Dan Leonard iio_triggered_buffer_cleanup(iio); 224bc0a409cSThierry Reding regulator_disable(adc->ref); 225bc0a409cSThierry Reding 226bc0a409cSThierry Reding return 0; 227bc0a409cSThierry Reding } 228bc0a409cSThierry Reding 229bc0a409cSThierry Reding static const struct i2c_device_id adc081c_id[] = { 230a6b5ec88SCrestez Dan Leonard { "adc081c", ADC081C }, 231a6b5ec88SCrestez Dan Leonard { "adc101c", ADC101C }, 232a6b5ec88SCrestez Dan Leonard { "adc121c", ADC121C }, 233bc0a409cSThierry Reding { } 234bc0a409cSThierry Reding }; 235bc0a409cSThierry Reding MODULE_DEVICE_TABLE(i2c, adc081c_id); 236bc0a409cSThierry Reding 237bc0a409cSThierry Reding #ifdef CONFIG_OF 238bc0a409cSThierry Reding static const struct of_device_id adc081c_of_match[] = { 239bc0a409cSThierry Reding { .compatible = "ti,adc081c" }, 240a6b5ec88SCrestez Dan Leonard { .compatible = "ti,adc101c" }, 241a6b5ec88SCrestez Dan Leonard { .compatible = "ti,adc121c" }, 242bc0a409cSThierry Reding { } 243bc0a409cSThierry Reding }; 244bc0a409cSThierry Reding MODULE_DEVICE_TABLE(of, adc081c_of_match); 245bc0a409cSThierry Reding #endif 246bc0a409cSThierry Reding 247*7feae871SDan O'Donovan #ifdef CONFIG_ACPI 248*7feae871SDan O'Donovan static const struct acpi_device_id adc081c_acpi_match[] = { 249*7feae871SDan O'Donovan { "ADC081C", ADC081C }, 250*7feae871SDan O'Donovan { "ADC101C", ADC101C }, 251*7feae871SDan O'Donovan { "ADC121C", ADC121C }, 252*7feae871SDan O'Donovan { } 253*7feae871SDan O'Donovan }; 254*7feae871SDan O'Donovan MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match); 255*7feae871SDan O'Donovan #endif 256*7feae871SDan O'Donovan 257bc0a409cSThierry Reding static struct i2c_driver adc081c_driver = { 258bc0a409cSThierry Reding .driver = { 259bc0a409cSThierry Reding .name = "adc081c", 260bc0a409cSThierry Reding .of_match_table = of_match_ptr(adc081c_of_match), 261*7feae871SDan O'Donovan .acpi_match_table = ACPI_PTR(adc081c_acpi_match), 262bc0a409cSThierry Reding }, 263bc0a409cSThierry Reding .probe = adc081c_probe, 264bc0a409cSThierry Reding .remove = adc081c_remove, 265bc0a409cSThierry Reding .id_table = adc081c_id, 266bc0a409cSThierry Reding }; 267bc0a409cSThierry Reding module_i2c_driver(adc081c_driver); 268bc0a409cSThierry Reding 269bc0a409cSThierry Reding MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 270a6b5ec88SCrestez Dan Leonard MODULE_DESCRIPTION("Texas Instruments ADC081C/ADC101C/ADC121C driver"); 271bc0a409cSThierry Reding MODULE_LICENSE("GPL v2"); 272