GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / iio / adc / intel_mrfld_adc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ADC driver for Basin Cove PMIC
4  *
5  * Copyright (C) 2012 Intel Corporation
6  * Author: Bin Yang <bin.yang@intel.com>
7  *
8  * Rewritten for upstream by:
9  *       Vincent Pelletier <plr.vincent@gmail.com>
10  *       Andy Shevchenko <andriy.shevchenko@linux.intel.com>
11  */
12
13 #include <linux/bitops.h>
14 #include <linux/completion.h>
15 #include <linux/interrupt.h>
16 #include <linux/mfd/intel_soc_pmic.h>
17 #include <linux/mfd/intel_soc_pmic_mrfld.h>
18 #include <linux/mod_devicetable.h>
19 #include <linux/module.h>
20 #include <linux/mutex.h>
21 #include <linux/platform_device.h>
22 #include <linux/regmap.h>
23
24 #include <linux/iio/driver.h>
25 #include <linux/iio/iio.h>
26 #include <linux/iio/machine.h>
27
28 #include <asm/unaligned.h>
29
30 #define BCOVE_GPADCREQ                  0xDC
31 #define BCOVE_GPADCREQ_BUSY             BIT(0)
32 #define BCOVE_GPADCREQ_IRQEN            BIT(1)
33
34 #define BCOVE_ADCIRQ_ALL (              \
35         BCOVE_ADCIRQ_BATTEMP |          \
36         BCOVE_ADCIRQ_SYSTEMP |          \
37         BCOVE_ADCIRQ_BATTID |           \
38         BCOVE_ADCIRQ_VIBATT |           \
39         BCOVE_ADCIRQ_CCTICK)
40
41 #define BCOVE_ADC_TIMEOUT               msecs_to_jiffies(1000)
42
43 static const u8 mrfld_adc_requests[] = {
44         BCOVE_ADCIRQ_VIBATT,
45         BCOVE_ADCIRQ_BATTID,
46         BCOVE_ADCIRQ_VIBATT,
47         BCOVE_ADCIRQ_SYSTEMP,
48         BCOVE_ADCIRQ_BATTEMP,
49         BCOVE_ADCIRQ_BATTEMP,
50         BCOVE_ADCIRQ_SYSTEMP,
51         BCOVE_ADCIRQ_SYSTEMP,
52         BCOVE_ADCIRQ_SYSTEMP,
53 };
54
55 struct mrfld_adc {
56         struct regmap *regmap;
57         struct completion completion;
58         /* Lock to protect the IPC transfers */
59         struct mutex lock;
60 };
61
62 static irqreturn_t mrfld_adc_thread_isr(int irq, void *data)
63 {
64         struct iio_dev *indio_dev = data;
65         struct mrfld_adc *adc = iio_priv(indio_dev);
66
67         complete(&adc->completion);
68         return IRQ_HANDLED;
69 }
70
71 static int mrfld_adc_single_conv(struct iio_dev *indio_dev,
72                                  struct iio_chan_spec const *chan,
73                                  int *result)
74 {
75         struct mrfld_adc *adc = iio_priv(indio_dev);
76         struct regmap *regmap = adc->regmap;
77         unsigned int req;
78         long timeout;
79         __be16 value;
80         int ret;
81
82         reinit_completion(&adc->completion);
83
84         regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0);
85         regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0);
86
87         ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req,
88                                        !(req & BCOVE_GPADCREQ_BUSY),
89                                        2000, 1000000);
90         if (ret)
91                 goto done;
92
93         req = mrfld_adc_requests[chan->channel];
94         ret = regmap_write(regmap, BCOVE_GPADCREQ, BCOVE_GPADCREQ_IRQEN | req);
95         if (ret)
96                 goto done;
97
98         timeout = wait_for_completion_interruptible_timeout(&adc->completion,
99                                                             BCOVE_ADC_TIMEOUT);
100         if (timeout < 0) {
101                 ret = timeout;
102                 goto done;
103         }
104         if (timeout == 0) {
105                 ret = -ETIMEDOUT;
106                 goto done;
107         }
108
109         ret = regmap_bulk_read(regmap, chan->address, &value, sizeof(value));
110         if (ret)
111                 goto done;
112
113         *result = be16_to_cpu(value);
114         ret = IIO_VAL_INT;
115
116 done:
117         regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0xff);
118         regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0xff);
119
120         return ret;
121 }
122
123 static int mrfld_adc_read_raw(struct iio_dev *indio_dev,
124                               struct iio_chan_spec const *chan,
125                               int *val, int *val2, long mask)
126 {
127         struct mrfld_adc *adc = iio_priv(indio_dev);
128         int ret;
129
130         switch (mask) {
131         case IIO_CHAN_INFO_RAW:
132                 mutex_lock(&adc->lock);
133                 ret = mrfld_adc_single_conv(indio_dev, chan, val);
134                 mutex_unlock(&adc->lock);
135                 return ret;
136         default:
137                 return -EINVAL;
138         }
139 }
140
141 static const struct iio_info mrfld_adc_iio_info = {
142         .read_raw = &mrfld_adc_read_raw,
143 };
144
145 #define BCOVE_ADC_CHANNEL(_type, _channel, _datasheet_name, _address)   \
146         {                                                               \
147                 .indexed = 1,                                           \
148                 .type = _type,                                          \
149                 .channel = _channel,                                    \
150                 .address = _address,                                    \
151                 .datasheet_name = _datasheet_name,                      \
152                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
153         }
154
155 static const struct iio_chan_spec mrfld_adc_channels[] = {
156         BCOVE_ADC_CHANNEL(IIO_VOLTAGE,    0, "CH0", 0xE9),
157         BCOVE_ADC_CHANNEL(IIO_RESISTANCE, 1, "CH1", 0xEB),
158         BCOVE_ADC_CHANNEL(IIO_CURRENT,    2, "CH2", 0xED),
159         BCOVE_ADC_CHANNEL(IIO_TEMP,       3, "CH3", 0xCC),
160         BCOVE_ADC_CHANNEL(IIO_TEMP,       4, "CH4", 0xC8),
161         BCOVE_ADC_CHANNEL(IIO_TEMP,       5, "CH5", 0xCA),
162         BCOVE_ADC_CHANNEL(IIO_TEMP,       6, "CH6", 0xC2),
163         BCOVE_ADC_CHANNEL(IIO_TEMP,       7, "CH7", 0xC4),
164         BCOVE_ADC_CHANNEL(IIO_TEMP,       8, "CH8", 0xC6),
165 };
166
167 static struct iio_map iio_maps[] = {
168         IIO_MAP("CH0", "bcove-battery", "VBATRSLT"),
169         IIO_MAP("CH1", "bcove-battery", "BATTID"),
170         IIO_MAP("CH2", "bcove-battery", "IBATRSLT"),
171         IIO_MAP("CH3", "bcove-temp",    "PMICTEMP"),
172         IIO_MAP("CH4", "bcove-temp",    "BATTEMP0"),
173         IIO_MAP("CH5", "bcove-temp",    "BATTEMP1"),
174         IIO_MAP("CH6", "bcove-temp",    "SYSTEMP0"),
175         IIO_MAP("CH7", "bcove-temp",    "SYSTEMP1"),
176         IIO_MAP("CH8", "bcove-temp",    "SYSTEMP2"),
177         {}
178 };
179
180 static int mrfld_adc_probe(struct platform_device *pdev)
181 {
182         struct device *dev = &pdev->dev;
183         struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
184         struct iio_dev *indio_dev;
185         struct mrfld_adc *adc;
186         int irq;
187         int ret;
188
189         indio_dev = devm_iio_device_alloc(dev, sizeof(struct mrfld_adc));
190         if (!indio_dev)
191                 return -ENOMEM;
192
193         adc = iio_priv(indio_dev);
194
195         mutex_init(&adc->lock);
196         init_completion(&adc->completion);
197         adc->regmap = pmic->regmap;
198
199         irq = platform_get_irq(pdev, 0);
200         if (irq < 0)
201                 return irq;
202
203         ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_adc_thread_isr,
204                                         IRQF_ONESHOT | IRQF_SHARED, pdev->name,
205                                         indio_dev);
206         if (ret)
207                 return ret;
208
209         indio_dev->name = pdev->name;
210
211         indio_dev->channels = mrfld_adc_channels;
212         indio_dev->num_channels = ARRAY_SIZE(mrfld_adc_channels);
213         indio_dev->info = &mrfld_adc_iio_info;
214         indio_dev->modes = INDIO_DIRECT_MODE;
215
216         ret = devm_iio_map_array_register(dev, indio_dev, iio_maps);
217         if (ret)
218                 return ret;
219
220         return devm_iio_device_register(dev, indio_dev);
221 }
222
223 static const struct platform_device_id mrfld_adc_id_table[] = {
224         { .name = "mrfld_bcove_adc" },
225         {}
226 };
227 MODULE_DEVICE_TABLE(platform, mrfld_adc_id_table);
228
229 static struct platform_driver mrfld_adc_driver = {
230         .driver = {
231                 .name = "mrfld_bcove_adc",
232         },
233         .probe = mrfld_adc_probe,
234         .id_table = mrfld_adc_id_table,
235 };
236 module_platform_driver(mrfld_adc_driver);
237
238 MODULE_AUTHOR("Bin Yang <bin.yang@intel.com>");
239 MODULE_AUTHOR("Vincent Pelletier <plr.vincent@gmail.com>");
240 MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
241 MODULE_DESCRIPTION("ADC driver for Basin Cove PMIC");
242 MODULE_LICENSE("GPL v2");