Commit | Line | Data |
---|---|---|
bc0a409c TR |
1 | /* |
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> | |
1f100e80 | 12 | #include <linux/of.h> |
bc0a409c TR |
13 | |
14 | #include <linux/iio/iio.h> | |
15 | #include <linux/regulator/consumer.h> | |
16 | ||
17 | struct adc081c { | |
18 | struct i2c_client *i2c; | |
19 | struct regulator *ref; | |
20 | }; | |
21 | ||
22 | #define REG_CONV_RES 0x00 | |
23 | ||
24 | static int adc081c_read_raw(struct iio_dev *iio, | |
25 | struct iio_chan_spec const *channel, int *value, | |
26 | int *shift, long mask) | |
27 | { | |
28 | struct adc081c *adc = iio_priv(iio); | |
29 | int err; | |
30 | ||
31 | switch (mask) { | |
32 | case IIO_CHAN_INFO_RAW: | |
33 | err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES); | |
34 | if (err < 0) | |
35 | return err; | |
36 | ||
37 | *value = (err >> 4) & 0xff; | |
38 | return IIO_VAL_INT; | |
39 | ||
40 | case IIO_CHAN_INFO_SCALE: | |
41 | err = regulator_get_voltage(adc->ref); | |
42 | if (err < 0) | |
43 | return err; | |
44 | ||
45 | *value = err / 1000; | |
46 | *shift = 8; | |
47 | ||
48 | return IIO_VAL_FRACTIONAL_LOG2; | |
49 | ||
50 | default: | |
51 | break; | |
52 | } | |
53 | ||
54 | return -EINVAL; | |
55 | } | |
56 | ||
57 | static const struct iio_chan_spec adc081c_channel = { | |
58 | .type = IIO_VOLTAGE, | |
c8fe38a7 JC |
59 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
60 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
bc0a409c TR |
61 | }; |
62 | ||
63 | static const struct iio_info adc081c_info = { | |
64 | .read_raw = adc081c_read_raw, | |
65 | .driver_module = THIS_MODULE, | |
66 | }; | |
67 | ||
68 | static int adc081c_probe(struct i2c_client *client, | |
69 | const struct i2c_device_id *id) | |
70 | { | |
71 | struct iio_dev *iio; | |
72 | struct adc081c *adc; | |
73 | int err; | |
74 | ||
75 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) | |
76 | return -ENODEV; | |
77 | ||
99e94b6d | 78 | iio = devm_iio_device_alloc(&client->dev, sizeof(*adc)); |
bc0a409c TR |
79 | if (!iio) |
80 | return -ENOMEM; | |
81 | ||
82 | adc = iio_priv(iio); | |
83 | adc->i2c = client; | |
84 | ||
99e94b6d SK |
85 | adc->ref = devm_regulator_get(&client->dev, "vref"); |
86 | if (IS_ERR(adc->ref)) | |
87 | return PTR_ERR(adc->ref); | |
bc0a409c TR |
88 | |
89 | err = regulator_enable(adc->ref); | |
90 | if (err < 0) | |
99e94b6d | 91 | return err; |
bc0a409c TR |
92 | |
93 | iio->dev.parent = &client->dev; | |
94 | iio->name = dev_name(&client->dev); | |
95 | iio->modes = INDIO_DIRECT_MODE; | |
96 | iio->info = &adc081c_info; | |
97 | ||
98 | iio->channels = &adc081c_channel; | |
99 | iio->num_channels = 1; | |
100 | ||
101 | err = iio_device_register(iio); | |
102 | if (err < 0) | |
103 | goto regulator_disable; | |
104 | ||
105 | i2c_set_clientdata(client, iio); | |
106 | ||
107 | return 0; | |
108 | ||
109 | regulator_disable: | |
110 | regulator_disable(adc->ref); | |
bc0a409c TR |
111 | |
112 | return err; | |
113 | } | |
114 | ||
115 | static int adc081c_remove(struct i2c_client *client) | |
116 | { | |
117 | struct iio_dev *iio = i2c_get_clientdata(client); | |
118 | struct adc081c *adc = iio_priv(iio); | |
119 | ||
120 | iio_device_unregister(iio); | |
121 | regulator_disable(adc->ref); | |
bc0a409c TR |
122 | |
123 | return 0; | |
124 | } | |
125 | ||
126 | static const struct i2c_device_id adc081c_id[] = { | |
127 | { "adc081c", 0 }, | |
128 | { } | |
129 | }; | |
130 | MODULE_DEVICE_TABLE(i2c, adc081c_id); | |
131 | ||
132 | #ifdef CONFIG_OF | |
133 | static const struct of_device_id adc081c_of_match[] = { | |
134 | { .compatible = "ti,adc081c" }, | |
135 | { } | |
136 | }; | |
137 | MODULE_DEVICE_TABLE(of, adc081c_of_match); | |
138 | #endif | |
139 | ||
140 | static struct i2c_driver adc081c_driver = { | |
141 | .driver = { | |
142 | .name = "adc081c", | |
bc0a409c TR |
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 | }; | |
149 | module_i2c_driver(adc081c_driver); | |
150 | ||
151 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | |
152 | MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver"); | |
153 | MODULE_LICENSE("GPL v2"); |