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