1bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding/* 2bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding * Copyright (C) 2012 Avionic Design GmbH 3bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding * 4bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding * This program is free software; you can redistribute it and/or modify 5bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding * it under the terms of the GNU General Public License version 2 as 6bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding * published by the Free Software Foundation. 7bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding */ 8bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 9bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#include <linux/err.h> 10bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#include <linux/i2c.h> 11bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#include <linux/module.h> 121f100e80bb27d9e7128a451324dc402ce524e9eaSachin Kamat#include <linux/of.h> 13bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 14bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#include <linux/iio/iio.h> 15bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#include <linux/regulator/consumer.h> 16bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 17bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstruct adc081c { 18bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct i2c_client *i2c; 19bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct regulator *ref; 20bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding}; 21bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 22bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#define REG_CONV_RES 0x00 23bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 24bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic int adc081c_read_raw(struct iio_dev *iio, 25bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct iio_chan_spec const *channel, int *value, 26bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding int *shift, long mask) 27bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding{ 28bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct adc081c *adc = iio_priv(iio); 29bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding int err; 30bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 31bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding switch (mask) { 32bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding case IIO_CHAN_INFO_RAW: 33bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES); 34bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding if (err < 0) 35bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return err; 36bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 37bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding *value = (err >> 4) & 0xff; 38bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return IIO_VAL_INT; 39bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 40bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding case IIO_CHAN_INFO_SCALE: 41bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding err = regulator_get_voltage(adc->ref); 42bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding if (err < 0) 43bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return err; 44bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 45bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding *value = err / 1000; 46bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding *shift = 8; 47bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 48bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return IIO_VAL_FRACTIONAL_LOG2; 49bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 50bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding default: 51bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding break; 52bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding } 53bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 54bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return -EINVAL; 55bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding} 56bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 57bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic const struct iio_chan_spec adc081c_channel = { 58bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .type = IIO_VOLTAGE, 59c8fe38a7dda0ff73ec5f9453fcefdd6ab84fcf71Jonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 60c8fe38a7dda0ff73ec5f9453fcefdd6ab84fcf71Jonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 61bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding}; 62bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 63bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic const struct iio_info adc081c_info = { 64bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .read_raw = adc081c_read_raw, 65bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .driver_module = THIS_MODULE, 66bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding}; 67bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 68bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic int adc081c_probe(struct i2c_client *client, 69bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding const struct i2c_device_id *id) 70bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding{ 71bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct iio_dev *iio; 72bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct adc081c *adc; 73bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding int err; 74bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 75bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) 76bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return -ENODEV; 77bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 7899e94b6d567188275b1269d4bd72d78cc10df8c3Sachin Kamat iio = devm_iio_device_alloc(&client->dev, sizeof(*adc)); 79bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding if (!iio) 80bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return -ENOMEM; 81bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 82bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding adc = iio_priv(iio); 83bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding adc->i2c = client; 84bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 8599e94b6d567188275b1269d4bd72d78cc10df8c3Sachin Kamat adc->ref = devm_regulator_get(&client->dev, "vref"); 8699e94b6d567188275b1269d4bd72d78cc10df8c3Sachin Kamat if (IS_ERR(adc->ref)) 8799e94b6d567188275b1269d4bd72d78cc10df8c3Sachin Kamat return PTR_ERR(adc->ref); 88bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 89bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding err = regulator_enable(adc->ref); 90bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding if (err < 0) 9199e94b6d567188275b1269d4bd72d78cc10df8c3Sachin Kamat return err; 92bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 93bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding iio->dev.parent = &client->dev; 94bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding iio->name = dev_name(&client->dev); 95bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding iio->modes = INDIO_DIRECT_MODE; 96bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding iio->info = &adc081c_info; 97bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 98bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding iio->channels = &adc081c_channel; 99bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding iio->num_channels = 1; 100bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 101bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding err = iio_device_register(iio); 102bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding if (err < 0) 103bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding goto regulator_disable; 104bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 105bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding i2c_set_clientdata(client, iio); 106bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 107bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return 0; 108bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 109bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingregulator_disable: 110bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding regulator_disable(adc->ref); 111bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 112bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return err; 113bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding} 114bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 115bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic int adc081c_remove(struct i2c_client *client) 116bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding{ 117bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct iio_dev *iio = i2c_get_clientdata(client); 118bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding struct adc081c *adc = iio_priv(iio); 119bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 120bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding iio_device_unregister(iio); 121bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding regulator_disable(adc->ref); 122bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 123bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding return 0; 124bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding} 125bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 126bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic const struct i2c_device_id adc081c_id[] = { 127bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding { "adc081c", 0 }, 128bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding { } 129bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding}; 130bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry RedingMODULE_DEVICE_TABLE(i2c, adc081c_id); 131bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 132bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#ifdef CONFIG_OF 133bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic const struct of_device_id adc081c_of_match[] = { 134bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding { .compatible = "ti,adc081c" }, 135bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding { } 136bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding}; 137bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry RedingMODULE_DEVICE_TABLE(of, adc081c_of_match); 138bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding#endif 139bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 140bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingstatic struct i2c_driver adc081c_driver = { 141bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .driver = { 142bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .name = "adc081c", 143bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .owner = THIS_MODULE, 144bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .of_match_table = of_match_ptr(adc081c_of_match), 145bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding }, 146bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .probe = adc081c_probe, 147bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .remove = adc081c_remove, 148bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding .id_table = adc081c_id, 149bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding}; 150bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Redingmodule_i2c_driver(adc081c_driver); 151bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry Reding 152bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry RedingMODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 153bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry RedingMODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver"); 154bc0a409c5ffd91b5403037ab2798b84dccee4f06Thierry RedingMODULE_LICENSE("GPL v2"); 155