9ad1dae2e6ff192024b00a66f3322ba91345c1b1
[firefly-linux-kernel-4.4.55.git] / drivers / adc / core.c
1 /* drivers/adc/core.c
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License.
6 */
7
8 #include <linux/kernel.h>
9 #include <linux/device.h>
10 #include <linux/completion.h>
11 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/adc.h>
14
15
16 static struct adc_host *g_adc = NULL;
17
18 struct adc_host *adc_alloc_host(int extra, struct device *dev)
19 {
20         struct adc_host *adc;
21         
22         adc = kzalloc(sizeof(struct adc_host) + extra, GFP_KERNEL);
23         if (!adc)
24                 return NULL;
25         adc->dev = dev;
26         g_adc = adc;
27         return adc;
28 }
29 EXPORT_SYMBOL(adc_alloc_host);
30 void adc_free_host(struct adc_host *adc)
31 {
32         kfree(adc);
33         adc = NULL;
34         return;
35 }
36 EXPORT_SYMBOL(adc_free_host);
37
38
39 struct adc_client *adc_register(int chn,
40                                 void (*callback)(struct adc_client *, void *, int), 
41                                 void *callback_param)
42 {
43         struct adc_client *client;
44         if(!g_adc)
45         {
46                 printk(KERN_ERR "adc host has not initialized\n");
47                 return NULL;
48         }
49         if(chn >= MAX_ADC_CHN)
50         {
51                 dev_err(g_adc->dev, "channel[%d] is greater than the maximum[%d]\n", chn, MAX_ADC_CHN);
52                 return NULL;
53         }
54         client = kzalloc(sizeof(struct adc_client), GFP_KERNEL);
55         if(!client)
56         {
57                 dev_err(g_adc->dev, "no memory for adc client\n");
58                 return NULL;
59         }
60         client->callback = callback;
61         client->callback_param = callback_param;
62         client->chn = chn;
63
64         client->adc = g_adc;
65
66         return client;
67 }
68 EXPORT_SYMBOL(adc_register);
69
70 void adc_unregister(struct adc_client *client)
71 {
72         kfree(client);
73         client = NULL;
74         return;
75 }
76 EXPORT_SYMBOL(adc_unregister);
77
78
79 static void trigger_next_adc_job_if_any(struct adc_host *adc)
80 {
81         int head = adc->queue_head;
82
83         if (!adc->queue[head])
84                 return;
85         adc->cur = adc->queue[head]->client;
86         adc->ops->start(adc);
87         return;
88 }
89
90 static int
91 adc_enqueue_request(struct adc_host *adc, struct adc_request *req)
92 {
93         int head, tail;
94
95         mutex_lock(&adc->queue_mutex);
96
97         head = adc->queue_head;
98         tail = adc->queue_tail;
99
100         if (adc->queue[tail]) {
101                 mutex_unlock(&adc->queue_mutex);
102                 dev_err(adc->dev, "ADC queue is full, dropping request\n");
103                 return -EBUSY;
104         }
105
106         adc->queue[tail] = req;
107         if (head == tail)
108                 trigger_next_adc_job_if_any(adc);
109         adc->queue_tail = (tail + 1) & (MAX_ADC_FIFO_DEPTH - 1);
110
111         mutex_unlock(&adc->queue_mutex);
112
113         return 0;
114 }
115
116 static void
117 adc_sync_read_callback(struct adc_client *client, void *param, int result)
118 {
119         struct adc_request *req = param;
120
121         client->result = result;
122         complete(&req->completion);
123 }
124
125 int adc_sync_read(struct adc_client *client)
126 {
127         struct adc_request *req = NULL;
128         int err, tmo;
129
130         if(client == NULL) {
131                 printk(KERN_ERR "client point is NULL");
132                 return -EINVAL;
133         }
134         if(client->adc->is_suspended == 1) {
135                 dev_dbg(client->adc->dev, "system enter sleep\n");
136                 return -1;
137         }
138         req = kzalloc(sizeof(*req), GFP_KERNEL);
139         if (!req){
140                 dev_err(client->adc->dev, "no memory for adc request\n");
141                 return -ENOMEM;
142         }
143         req->chn = client->chn;
144         req->callback =  adc_sync_read_callback;
145         req->callback_param = req;
146         req->client = client;
147
148         init_completion(&req->completion);
149         err = adc_enqueue_request(client->adc, req);
150         if (err)
151         {
152                 dev_err(client->adc->dev, "fail to enqueue request\n");
153                 kfree(req);
154                 return err;
155         }
156         tmo = wait_for_completion_timeout(&req->completion,msecs_to_jiffies(100));
157         if(tmo == 0)
158                 return -ETIMEDOUT;
159         return client->result;
160 }
161 EXPORT_SYMBOL(adc_sync_read);
162
163 int adc_async_read(struct adc_client *client)
164 {
165         struct adc_request *req = NULL;
166         
167         if(client == NULL) {
168                 printk(KERN_ERR "client point is NULL");
169                 return -EINVAL;
170         }
171         if(client->adc->is_suspended == 1) {
172                 dev_dbg(client->adc->dev, "system enter sleep\n");
173                 return -1;
174         }
175         req = kzalloc(sizeof(*req), GFP_KERNEL);
176         if (!req) {
177                 dev_err(client->adc->dev, "no memory for adc request\n");
178                 return -ENOMEM;
179         }
180         req->chn = client->chn;
181         req->callback = client->callback;
182         req->callback_param = client->callback_param;
183         req->client = client;
184
185         return adc_enqueue_request(client->adc, req);
186 }
187 EXPORT_SYMBOL(adc_async_read);
188
189 void adc_core_irq_handle(struct adc_host *adc)
190 {
191         struct adc_request *req;
192         int head, res;
193
194         head = adc->queue_head;
195
196         req = adc->queue[head];
197         if (WARN_ON(!req)) {
198                 dev_err(adc->dev, "adc irq: ADC queue empty!\n");
199                 return;
200         }
201         adc->queue[head] = NULL;
202         adc->queue_head = (head + 1) & (MAX_ADC_FIFO_DEPTH - 1);
203         
204         res = adc->ops->read(adc);
205         adc->ops->stop(adc);
206         trigger_next_adc_job_if_any(adc);
207
208         req->callback(adc->cur, req->callback_param, res);
209         kfree(req);
210 }
211 EXPORT_SYMBOL(adc_core_irq_handle);
212
213