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