1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* NXP PCF50633 ADC Driver
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) 2006-2008 by Openmoko, Inc.
5*4882a593Smuzhiyun * Author: Balaji Rao <balajirrao@openmoko.org>
6*4882a593Smuzhiyun * All rights reserved.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Broken down from monstrous PCF50633 driver mainly by
9*4882a593Smuzhiyun * Harald Welte, Andy Green and Werner Almesberger
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * NOTE: This driver does not yet support subtractive ADC mode, which means
12*4882a593Smuzhiyun * you can do only one measurement per read request.
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/device.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/completion.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <linux/mfd/pcf50633/core.h>
23*4882a593Smuzhiyun #include <linux/mfd/pcf50633/adc.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun struct pcf50633_adc_request {
26*4882a593Smuzhiyun int mux;
27*4882a593Smuzhiyun int avg;
28*4882a593Smuzhiyun void (*callback)(struct pcf50633 *, void *, int);
29*4882a593Smuzhiyun void *callback_param;
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun struct pcf50633_adc_sync_request {
33*4882a593Smuzhiyun int result;
34*4882a593Smuzhiyun struct completion completion;
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define PCF50633_MAX_ADC_FIFO_DEPTH 8
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun struct pcf50633_adc {
40*4882a593Smuzhiyun struct pcf50633 *pcf;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* Private stuff */
43*4882a593Smuzhiyun struct pcf50633_adc_request *queue[PCF50633_MAX_ADC_FIFO_DEPTH];
44*4882a593Smuzhiyun int queue_head;
45*4882a593Smuzhiyun int queue_tail;
46*4882a593Smuzhiyun struct mutex queue_mutex;
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
__to_adc(struct pcf50633 * pcf)49*4882a593Smuzhiyun static inline struct pcf50633_adc *__to_adc(struct pcf50633 *pcf)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun return platform_get_drvdata(pcf->adc_pdev);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
adc_setup(struct pcf50633 * pcf,int channel,int avg)54*4882a593Smuzhiyun static void adc_setup(struct pcf50633 *pcf, int channel, int avg)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun channel &= PCF50633_ADCC1_ADCMUX_MASK;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /* kill ratiometric, but enable ACCSW biasing */
59*4882a593Smuzhiyun pcf50633_reg_write(pcf, PCF50633_REG_ADCC2, 0x00);
60*4882a593Smuzhiyun pcf50633_reg_write(pcf, PCF50633_REG_ADCC3, 0x01);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* start ADC conversion on selected channel */
63*4882a593Smuzhiyun pcf50633_reg_write(pcf, PCF50633_REG_ADCC1, channel | avg |
64*4882a593Smuzhiyun PCF50633_ADCC1_ADCSTART | PCF50633_ADCC1_RES_10BIT);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
trigger_next_adc_job_if_any(struct pcf50633 * pcf)67*4882a593Smuzhiyun static void trigger_next_adc_job_if_any(struct pcf50633 *pcf)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun struct pcf50633_adc *adc = __to_adc(pcf);
70*4882a593Smuzhiyun int head;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun head = adc->queue_head;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (!adc->queue[head])
75*4882a593Smuzhiyun return;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun static int
adc_enqueue_request(struct pcf50633 * pcf,struct pcf50633_adc_request * req)81*4882a593Smuzhiyun adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun struct pcf50633_adc *adc = __to_adc(pcf);
84*4882a593Smuzhiyun int head, tail;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun mutex_lock(&adc->queue_mutex);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun head = adc->queue_head;
89*4882a593Smuzhiyun tail = adc->queue_tail;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (adc->queue[tail]) {
92*4882a593Smuzhiyun mutex_unlock(&adc->queue_mutex);
93*4882a593Smuzhiyun dev_err(pcf->dev, "ADC queue is full, dropping request\n");
94*4882a593Smuzhiyun return -EBUSY;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun adc->queue[tail] = req;
98*4882a593Smuzhiyun if (head == tail)
99*4882a593Smuzhiyun trigger_next_adc_job_if_any(pcf);
100*4882a593Smuzhiyun adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun mutex_unlock(&adc->queue_mutex);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun return 0;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
pcf50633_adc_sync_read_callback(struct pcf50633 * pcf,void * param,int result)107*4882a593Smuzhiyun static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param,
108*4882a593Smuzhiyun int result)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun struct pcf50633_adc_sync_request *req = param;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun req->result = result;
113*4882a593Smuzhiyun complete(&req->completion);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
pcf50633_adc_sync_read(struct pcf50633 * pcf,int mux,int avg)116*4882a593Smuzhiyun int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun struct pcf50633_adc_sync_request req;
119*4882a593Smuzhiyun int ret;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun init_completion(&req.completion);
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun ret = pcf50633_adc_async_read(pcf, mux, avg,
124*4882a593Smuzhiyun pcf50633_adc_sync_read_callback, &req);
125*4882a593Smuzhiyun if (ret)
126*4882a593Smuzhiyun return ret;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun wait_for_completion(&req.completion);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun return req.result;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read);
133*4882a593Smuzhiyun
pcf50633_adc_async_read(struct pcf50633 * pcf,int mux,int avg,void (* callback)(struct pcf50633 *,void *,int),void * callback_param)134*4882a593Smuzhiyun int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
135*4882a593Smuzhiyun void (*callback)(struct pcf50633 *, void *, int),
136*4882a593Smuzhiyun void *callback_param)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct pcf50633_adc_request *req;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* req is freed when the result is ready, in interrupt handler */
141*4882a593Smuzhiyun req = kmalloc(sizeof(*req), GFP_KERNEL);
142*4882a593Smuzhiyun if (!req)
143*4882a593Smuzhiyun return -ENOMEM;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun req->mux = mux;
146*4882a593Smuzhiyun req->avg = avg;
147*4882a593Smuzhiyun req->callback = callback;
148*4882a593Smuzhiyun req->callback_param = callback_param;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return adc_enqueue_request(pcf, req);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
153*4882a593Smuzhiyun
adc_result(struct pcf50633 * pcf)154*4882a593Smuzhiyun static int adc_result(struct pcf50633 *pcf)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun u8 adcs1, adcs3;
157*4882a593Smuzhiyun u16 result;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun adcs1 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS1);
160*4882a593Smuzhiyun adcs3 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS3);
161*4882a593Smuzhiyun result = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun dev_dbg(pcf->dev, "adc result = %d\n", result);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun return result;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
pcf50633_adc_irq(int irq,void * data)168*4882a593Smuzhiyun static void pcf50633_adc_irq(int irq, void *data)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun struct pcf50633_adc *adc = data;
171*4882a593Smuzhiyun struct pcf50633 *pcf = adc->pcf;
172*4882a593Smuzhiyun struct pcf50633_adc_request *req;
173*4882a593Smuzhiyun int head, res;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun mutex_lock(&adc->queue_mutex);
176*4882a593Smuzhiyun head = adc->queue_head;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun req = adc->queue[head];
179*4882a593Smuzhiyun if (WARN_ON(!req)) {
180*4882a593Smuzhiyun dev_err(pcf->dev, "pcf50633-adc irq: ADC queue empty!\n");
181*4882a593Smuzhiyun mutex_unlock(&adc->queue_mutex);
182*4882a593Smuzhiyun return;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun adc->queue[head] = NULL;
185*4882a593Smuzhiyun adc->queue_head = (head + 1) &
186*4882a593Smuzhiyun (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun res = adc_result(pcf);
189*4882a593Smuzhiyun trigger_next_adc_job_if_any(pcf);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun mutex_unlock(&adc->queue_mutex);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun req->callback(pcf, req->callback_param, res);
194*4882a593Smuzhiyun kfree(req);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
pcf50633_adc_probe(struct platform_device * pdev)197*4882a593Smuzhiyun static int pcf50633_adc_probe(struct platform_device *pdev)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun struct pcf50633_adc *adc;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL);
202*4882a593Smuzhiyun if (!adc)
203*4882a593Smuzhiyun return -ENOMEM;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun adc->pcf = dev_to_pcf50633(pdev->dev.parent);
206*4882a593Smuzhiyun platform_set_drvdata(pdev, adc);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY,
209*4882a593Smuzhiyun pcf50633_adc_irq, adc);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun mutex_init(&adc->queue_mutex);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
pcf50633_adc_remove(struct platform_device * pdev)216*4882a593Smuzhiyun static int pcf50633_adc_remove(struct platform_device *pdev)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun struct pcf50633_adc *adc = platform_get_drvdata(pdev);
219*4882a593Smuzhiyun int i, head;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun pcf50633_free_irq(adc->pcf, PCF50633_IRQ_ADCRDY);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun mutex_lock(&adc->queue_mutex);
224*4882a593Smuzhiyun head = adc->queue_head;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (WARN_ON(adc->queue[head]))
227*4882a593Smuzhiyun dev_err(adc->pcf->dev,
228*4882a593Smuzhiyun "adc driver removed with request pending\n");
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun for (i = 0; i < PCF50633_MAX_ADC_FIFO_DEPTH; i++)
231*4882a593Smuzhiyun kfree(adc->queue[i]);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun mutex_unlock(&adc->queue_mutex);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun static struct platform_driver pcf50633_adc_driver = {
239*4882a593Smuzhiyun .driver = {
240*4882a593Smuzhiyun .name = "pcf50633-adc",
241*4882a593Smuzhiyun },
242*4882a593Smuzhiyun .probe = pcf50633_adc_probe,
243*4882a593Smuzhiyun .remove = pcf50633_adc_remove,
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun module_platform_driver(pcf50633_adc_driver);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
249*4882a593Smuzhiyun MODULE_DESCRIPTION("PCF50633 adc driver");
250*4882a593Smuzhiyun MODULE_LICENSE("GPL");
251*4882a593Smuzhiyun MODULE_ALIAS("platform:pcf50633-adc");
252*4882a593Smuzhiyun
253