aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc/lp8788_adc.c
diff options
context:
space:
mode:
authorKim, Milo <Milo.Kim@ti.com>2012-09-17 05:35:00 -0400
committerJonathan Cameron <jic23@kernel.org>2012-09-22 05:29:19 -0400
commitf0347c36ccd7cfd31c8af10509d4110f0a769a85 (patch)
treef1f3b7763412ac0141b2eafe68bfe05bd9081289 /drivers/iio/adc/lp8788_adc.c
parent7aecec986e043f02738705328d85f97375ca6f41 (diff)
iio: adc: add new lp8788 adc driver
TI LP8788 PMU provides regulators, battery charger, ADC, RTC, backlight driver and current sinks. This patch enables the LP8788 ADC functions. The LP8788 ADC has several ADC input selection and supports 12bit resolution. Internal operation of getting ADC is access to registers of LP8788. The LP8788 ADC uses exported functions for accessing these registers. (exported by LP8788 MFD device driver) This driver supports IIO_CHAN_INFO_RAW and SCALE. So the IIO consumer can calculate the value with raw and scale. The unit of scale is micro. (ADC Input Selection) Voltage: battery voltage (MAX 5.0, 5.5 and 6.0V) charger input voltage four general ADC inputs coin cell voltage Current: battery charging current Temperature: IC temperature (The IIO map for the IIO consumer) The ADC input is configurable in the platform side. Even though this platform data is not defined, the default IIO map is created for supporting the power supply driver. The battery voltage and temperature are used inside this driver. (History) Patch v6. (a) Fix scale value for each ADC input selection Voltage and current type are mili unit and temperature is degree. To calculate the IC temperature, temp = raw * scaleint + (raw * scalepart)/ 1000000, scaleint is always 0. = raw * 0.061050, raw: 0 ~ 4095 Then range of IC temperature(ADC result) is 0 ~ 250'C (b) Reorganization of the IIO channel Spec Remove address, scan_type and scan_index and rollback the datasheet name. The reason why 'address' field is unnecessary is no relation with each channel. Moreover, to get the raw ADC value, the address info is not only one register but also several registers. Therefore specific function(lp8788_get_adc_result) is called rather than using one 'address' field. (c) Fix coding style Remove duplicated checking routine while unregistering the IIO map. Fix code for space and parenthesis. Patch v5. Fix default consumer name as 'lp8788-charger'. Add mutex for ADC read operation. Reorganization on lp8788_adc_read_raw(). Patch v4. Fix adc_raw function: support RAW and SCALE channel info. Change LP8788 ADC platform data - iio map. Enables the default IIO map. Patch v3. Fix wrong size of allocating iio private data. Fix coding styles. Patch v2. Support RAW and SCALE interface for IIO consumer. Clean up the iio channel spec macro. Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/adc/lp8788_adc.c')
-rw-r--r--drivers/iio/adc/lp8788_adc.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
new file mode 100644
index 000000000000..a93aaf0bb841
--- /dev/null
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -0,0 +1,264 @@
1/*
2 * TI LP8788 MFD - ADC driver
3 *
4 * Copyright 2012 Texas Instruments
5 *
6 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/delay.h>
14#include <linux/iio/iio.h>
15#include <linux/iio/driver.h>
16#include <linux/iio/machine.h>
17#include <linux/mfd/lp8788.h>
18#include <linux/module.h>
19#include <linux/mutex.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22
23/* register address */
24#define LP8788_ADC_CONF 0x60
25#define LP8788_ADC_RAW 0x61
26#define LP8788_ADC_DONE 0x63
27
28#define ADC_CONV_START 1
29
30struct lp8788_adc {
31 struct lp8788 *lp;
32 struct iio_map *map;
33 struct mutex lock;
34};
35
36static const int lp8788_scale[LPADC_MAX] = {
37 [LPADC_VBATT_5P5] = 1343101,
38 [LPADC_VIN_CHG] = 3052503,
39 [LPADC_IBATT] = 610500,
40 [LPADC_IC_TEMP] = 61050,
41 [LPADC_VBATT_6P0] = 1465201,
42 [LPADC_VBATT_5P0] = 1221001,
43 [LPADC_ADC1] = 610500,
44 [LPADC_ADC2] = 610500,
45 [LPADC_VDD] = 1025641,
46 [LPADC_VCOIN] = 757020,
47 [LPADC_ADC3] = 610500,
48 [LPADC_ADC4] = 610500,
49};
50
51static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id,
52 int *val)
53{
54 unsigned int msb;
55 unsigned int lsb;
56 unsigned int result;
57 u8 data;
58 u8 rawdata[2];
59 int size = ARRAY_SIZE(rawdata);
60 int retry = 5;
61 int ret;
62
63 data = (id << 1) | ADC_CONV_START;
64 ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data);
65 if (ret)
66 goto err_io;
67
68 /* retry until adc conversion is done */
69 data = 0;
70 while (retry--) {
71 usleep_range(100, 200);
72
73 ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data);
74 if (ret)
75 goto err_io;
76
77 /* conversion done */
78 if (data)
79 break;
80 }
81
82 ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size);
83 if (ret)
84 goto err_io;
85
86 msb = (rawdata[0] << 4) & 0x00000ff0;
87 lsb = (rawdata[1] >> 4) & 0x0000000f;
88 result = msb | lsb;
89 *val = result;
90
91 return 0;
92
93err_io:
94 return ret;
95}
96
97static int lp8788_adc_read_raw(struct iio_dev *indio_dev,
98 struct iio_chan_spec const *chan,
99 int *val, int *val2, long mask)
100{
101 struct lp8788_adc *adc = iio_priv(indio_dev);
102 enum lp8788_adc_id id = chan->channel;
103 int ret;
104
105 mutex_lock(&adc->lock);
106
107 switch (mask) {
108 case IIO_CHAN_INFO_RAW:
109 ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT;
110 break;
111 case IIO_CHAN_INFO_SCALE:
112 *val = lp8788_scale[id] / 1000000;
113 *val2 = lp8788_scale[id] % 1000000;
114 ret = IIO_VAL_INT_PLUS_MICRO;
115 break;
116 default:
117 ret = -EINVAL;
118 break;
119 }
120
121 mutex_unlock(&adc->lock);
122
123 return ret;
124}
125
126static const struct iio_info lp8788_adc_info = {
127 .read_raw = &lp8788_adc_read_raw,
128 .driver_module = THIS_MODULE,
129};
130
131#define LP8788_CHAN(_id, _type) { \
132 .type = _type, \
133 .indexed = 1, \
134 .channel = LPADC_##_id, \
135 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
136 IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
137 .datasheet_name = #_id, \
138}
139
140static const struct iio_chan_spec lp8788_adc_channels[] = {
141 [LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE),
142 [LPADC_VIN_CHG] = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE),
143 [LPADC_IBATT] = LP8788_CHAN(IBATT, IIO_CURRENT),
144 [LPADC_IC_TEMP] = LP8788_CHAN(IC_TEMP, IIO_TEMP),
145 [LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE),
146 [LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE),
147 [LPADC_ADC1] = LP8788_CHAN(ADC1, IIO_VOLTAGE),
148 [LPADC_ADC2] = LP8788_CHAN(ADC2, IIO_VOLTAGE),
149 [LPADC_VDD] = LP8788_CHAN(VDD, IIO_VOLTAGE),
150 [LPADC_VCOIN] = LP8788_CHAN(VCOIN, IIO_VOLTAGE),
151 [LPADC_ADC3] = LP8788_CHAN(ADC3, IIO_VOLTAGE),
152 [LPADC_ADC4] = LP8788_CHAN(ADC4, IIO_VOLTAGE),
153};
154
155/* default maps used by iio consumer (lp8788-charger driver) */
156static struct iio_map lp8788_default_iio_maps[] = {
157 {
158 .consumer_dev_name = "lp8788-charger",
159 .consumer_channel = "lp8788_vbatt_5p0",
160 .adc_channel_label = "VBATT_5P0",
161 },
162 {
163 .consumer_dev_name = "lp8788-charger",
164 .consumer_channel = "lp8788_adc1",
165 .adc_channel_label = "ADC1",
166 },
167 { }
168};
169
170static int lp8788_iio_map_register(struct iio_dev *indio_dev,
171 struct lp8788_platform_data *pdata,
172 struct lp8788_adc *adc)
173{
174 struct iio_map *map;
175 int ret;
176
177 map = (!pdata || !pdata->adc_pdata) ?
178 lp8788_default_iio_maps : pdata->adc_pdata;
179
180 ret = iio_map_array_register(indio_dev, map);
181 if (ret) {
182 dev_err(adc->lp->dev, "iio map err: %d\n", ret);
183 return ret;
184 }
185
186 adc->map = map;
187 return 0;
188}
189
190static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev,
191 struct lp8788_adc *adc)
192{
193 iio_map_array_unregister(indio_dev, adc->map);
194}
195
196static int __devinit lp8788_adc_probe(struct platform_device *pdev)
197{
198 struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
199 struct iio_dev *indio_dev;
200 struct lp8788_adc *adc;
201 int ret;
202
203 indio_dev = iio_device_alloc(sizeof(*adc));
204 if (!indio_dev)
205 return -ENOMEM;
206
207 adc = iio_priv(indio_dev);
208 adc->lp = lp;
209 platform_set_drvdata(pdev, indio_dev);
210
211 ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
212 if (ret)
213 goto err_iio_map;
214
215 mutex_init(&adc->lock);
216
217 indio_dev->dev.parent = lp->dev;
218 indio_dev->name = pdev->name;
219 indio_dev->modes = INDIO_DIRECT_MODE;
220 indio_dev->info = &lp8788_adc_info;
221 indio_dev->channels = lp8788_adc_channels;
222 indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels);
223
224 ret = iio_device_register(indio_dev);
225 if (ret) {
226 dev_err(lp->dev, "iio dev register err: %d\n", ret);
227 goto err_iio_device;
228 }
229
230 return 0;
231
232err_iio_device:
233 lp8788_iio_map_unregister(indio_dev, adc);
234err_iio_map:
235 iio_device_free(indio_dev);
236 return ret;
237}
238
239static int __devexit lp8788_adc_remove(struct platform_device *pdev)
240{
241 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
242 struct lp8788_adc *adc = iio_priv(indio_dev);
243
244 iio_device_unregister(indio_dev);
245 lp8788_iio_map_unregister(indio_dev, adc);
246 iio_device_free(indio_dev);
247
248 return 0;
249}
250
251static struct platform_driver lp8788_adc_driver = {
252 .probe = lp8788_adc_probe,
253 .remove = __devexit_p(lp8788_adc_remove),
254 .driver = {
255 .name = LP8788_DEV_ADC,
256 .owner = THIS_MODULE,
257 },
258};
259module_platform_driver(lp8788_adc_driver);
260
261MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver");
262MODULE_AUTHOR("Milo Kim");
263MODULE_LICENSE("GPL");
264MODULE_ALIAS("platform:lp8788-adc");