Merge remote-tracking branch 'common/android-3.0' into develop-3.0-jb
[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 #include <linux/adc.h>
8 #include "adc_priv.h"
9
10 struct list_head adc_host_head;
11
12 static void adc_host_work(struct work_struct *work);
13 struct adc_host *adc_alloc_host(struct device *dev, int extra, enum host_chn_mask mask)
14 {
15         struct adc_host *adc;
16         
17         adc = kzalloc(sizeof(struct adc_host) + extra, GFP_KERNEL);
18         if (!adc)
19                 return NULL;
20         adc->mask = mask;
21         adc->dev = dev;
22         adc->chn = -1;
23         spin_lock_init(&adc->lock);
24         INIT_LIST_HEAD(&adc->req_head);
25         INIT_WORK(&adc->work, adc_host_work);
26
27         list_add_tail(&adc->entry, &adc_host_head);
28
29         return adc;
30 }
31
32 void adc_free_host(struct adc_host *adc)
33 {
34         list_del(&adc->entry);
35         kfree(adc);
36         adc = NULL;
37         return;
38 }
39
40 struct adc_client *adc_register(int chn,
41                                 void (*callback)(struct adc_client *, void *, int), 
42                                 void *callback_param)
43
44 {
45         struct adc_client *client = NULL;
46         struct adc_host *adc = NULL;
47
48         list_for_each_entry(adc, &adc_host_head, entry) {
49                 if((chn == 0 && adc->mask == SARADC_CHN_MASK) ||
50                 (chn & adc->mask)){
51                         client = kzalloc(sizeof(struct adc_client), GFP_KERNEL);
52                         if(!client)
53                                 return NULL;
54                         client->callback = callback;
55                         client->callback_param = callback_param;
56                         client->chn = chn;
57                         client->adc = adc;
58                         client->index = adc->client_count;
59                         init_waitqueue_head(&client->wait);
60                         adc->client_count++;
61
62                         return client;
63                 }
64         }
65         dev_err(adc->dev, "chn(%d) is not support\n", chn);
66         return NULL;
67 }
68
69 void adc_unregister(struct adc_client *client)
70 {
71         struct adc_host *adc = client->adc;
72
73         adc->client_count--;
74         kfree(client);
75         client = NULL;
76         return;
77 }
78
79 static inline void trigger_next_adc_job_if_any(struct adc_host *adc)
80 {
81         struct adc_request *req = NULL;
82
83         if(adc->chn != -1)
84                 return;
85         req = list_first_entry(&adc->req_head, struct adc_request, entry);
86         if(req){
87                 adc->chn = req->client->chn;
88                 adc->ops->start(adc);
89         }
90
91         return;
92 }
93 static void adc_host_work(struct work_struct *work)
94 {
95         unsigned long flags;
96         struct adc_host *adc =
97                 container_of(work, struct adc_host, work);
98
99         spin_lock_irqsave(&adc->lock, flags);
100         trigger_next_adc_job_if_any(adc);
101         spin_unlock_irqrestore(&adc->lock, flags);
102 }
103 static int adc_request_add(struct adc_host *adc, struct adc_client *client)
104 {
105         struct adc_request *req = NULL;
106
107         req = kzalloc(sizeof(struct adc_request), GFP_ATOMIC);
108
109         if(!req)
110                 return -ENOMEM;
111         INIT_LIST_HEAD(&req->entry);
112         req->client = client;
113         list_add_tail(&req->entry, &adc->req_head);
114         trigger_next_adc_job_if_any(adc);
115         return 0;
116 }
117 static void
118 adc_sync_read_callback(struct adc_client *client, void *param, int result)
119 {
120         client->result = result;
121 }
122 static void adc_finished(struct adc_host *adc, int result)
123 {
124         struct adc_request *req = NULL, *n = NULL;
125
126         adc_dbg(adc->dev, "chn[%d] read value: %d\n", adc->chn, result);
127         adc->ops->stop(adc);
128         list_for_each_entry_safe(req, n, &adc->req_head, entry) {
129                 if(req->client->chn == adc->chn){
130                         if(req->client->flags & (1<<ADC_ASYNC_READ)){
131                                 req->client->callback(req->client, req->client->callback_param, result);
132                         }
133                         if(req->client->flags & (1<<ADC_SYNC_READ)){
134                                 adc_sync_read_callback(req->client, NULL, result);
135                                 req->client->is_finished = 1;
136                                 wake_up(&req->client->wait);
137                         }
138                         req->client->result = result;
139                         req->client->flags = 0;
140                         list_del_init(&req->entry);
141                         kfree(req);
142                 }
143         }
144         adc->chn = -1;
145 }
146 void adc_core_irq_handle(struct adc_host *adc)
147 {
148         int result = 0;
149
150         spin_lock(&adc->lock);
151         result = adc->ops->read(adc);
152
153         adc_finished(adc, result);
154
155         if(!list_empty(&adc->req_head))
156                 schedule_work(&adc->work);
157         spin_unlock(&adc->lock);
158 }
159
160 int adc_host_read(struct adc_client *client, enum read_type type)
161 {
162         int tmo, ret = 0;
163         unsigned long flags;
164         struct adc_host *adc = NULL;
165
166         if(client == NULL) {
167                 printk(KERN_ERR "client is NULL");
168                 return -EINVAL;
169         }
170         adc = client->adc;
171         if(adc->is_suspended == 1) {
172                 dev_err(adc->dev, "adc is in suspend state\n");
173                 return -EIO;
174         }
175
176         spin_lock_irqsave(&adc->lock, flags);
177         if(client->flags & (1<<type)){
178                 spin_unlock_irqrestore(&adc->lock, flags);
179                 adc_dbg(adc->dev, "req is exist: %s, client->index: %d\n", 
180                                 (type == ADC_ASYNC_READ)?"async_read":"sync_read", client->index);
181                 return -EEXIST;
182         }else if(client->flags != 0){
183                 client->flags |= 1<<type;
184         }else{
185                 client->flags = 1<<type;
186                 ret = adc_request_add(adc, client);
187                 if(ret < 0){
188                         spin_unlock_irqrestore(&adc->lock, flags);
189                         dev_err(adc->dev, "fail to add request\n");
190                         return ret;
191                 }
192         }
193         if(type == ADC_ASYNC_READ){
194                 spin_unlock_irqrestore(&adc->lock, flags);
195                 return 0;
196         }
197         client->is_finished = 0;
198         spin_unlock_irqrestore(&adc->lock, flags);
199
200         tmo = wait_event_timeout(client->wait, ( client->is_finished == 1 ), msecs_to_jiffies(ADC_READ_TMO));
201         spin_lock_irqsave(&adc->lock, flags);
202         if(unlikely((tmo <= 0) && (client->is_finished == 0))) {
203                 if(adc->ops->dump)
204                         adc->ops->dump(adc);
205                 dev_err(adc->dev, "get adc value timeout.................................\n");
206                 adc_finished(adc, -1);
207                 spin_unlock_irqrestore(&adc->lock, flags);
208                 return -ETIMEDOUT;
209         } 
210         spin_unlock_irqrestore(&adc->lock, flags);
211
212         return client->result;
213 }
214
215 int adc_sync_read(struct adc_client *client)
216 {
217         return adc_host_read(client, ADC_SYNC_READ);
218 }
219
220 int adc_async_read(struct adc_client *client)
221 {
222         return adc_host_read(client, ADC_ASYNC_READ);
223 }
224
225
226 static int __init adc_core_init(void)
227 {
228         INIT_LIST_HEAD(&adc_host_head);
229         return 0;
230 }
231 subsys_initcall(adc_core_init);
232
233 static void __exit adc_core_exit(void)
234 {
235         return;
236 }
237 module_exit(adc_core_exit);  
238
239