rk30:add tsadc support
[firefly-linux-kernel-4.4.55.git] / drivers / adc / plat / rk30_tsadc.c
1 /* drivers/adc/chips/rk30_tadc.c\r
2  *\r
3  * This program is free software; you can redistribute it and/or modify\r
4  * it under the terms of the GNU General Public License as published by\r
5  * the Free Software Foundation; either version 2 of the License.\r
6 */\r
7 #include <linux/kernel.h>\r
8 #include <linux/module.h>\r
9 #include <linux/init.h>\r
10 #include <linux/device.h>\r
11 #include <linux/platform_device.h>\r
12 #include <linux/err.h>\r
13 #include <linux/clk.h>\r
14 #include <linux/interrupt.h>\r
15 #include <linux/io.h>\r
16 #include <linux/adc.h>\r
17 #include <linux/delay.h>\r
18 #include <linux/slab.h>\r
19 \r
20 \r
21 #include "rk30_tsadc.h"\r
22 \r
23 //#define ADC_TEST\r
24 #define ADC_POLL        1       //if no tsadc intterupt\r
25 \r
26 struct rk30_tsadc_device {\r
27         int                      irq;\r
28         void __iomem            *regs;\r
29         struct clk *            clk;\r
30         struct resource         *ioarea;\r
31         struct adc_host         *adc;\r
32 };\r
33 static void rk30_tsadc_start(struct adc_host *adc)\r
34 {\r
35         struct rk30_tsadc_device *dev  = adc_priv(adc); \r
36         int chn = adc->cur->chn;\r
37         \r
38         writel(0, dev->regs + ADC_CTRL);\r
39         writel(ADC_CTRL_POWER_UP|ADC_CTRL_CH(chn), dev->regs + ADC_CTRL);\r
40         udelay(SAMPLE_RATE);\r
41 \r
42         writel(readl(dev->regs + ADC_CTRL)|ADC_CTRL_IRQ_ENABLE|ADC_CTRL_START, \r
43                 dev->regs + ADC_CTRL);\r
44         return;\r
45 }\r
46 \r
47 static void rk30_tsadc_start_poll(struct adc_host *adc)\r
48 {\r
49         struct rk30_tsadc_device *dev  = adc_priv(adc); \r
50         int chn = adc->cur->chn;\r
51         \r
52         writel(0, dev->regs + ADC_CTRL);\r
53         writel(ADC_CTRL_POWER_UP|ADC_CTRL_CH(chn), dev->regs + ADC_CTRL);\r
54         udelay(SAMPLE_RATE);\r
55 \r
56         writel(readl(dev->regs + ADC_CTRL)|ADC_CTRL_START, \r
57                 dev->regs + ADC_CTRL);\r
58         return;\r
59 }\r
60 \r
61 static void rk30_tsadc_stop(struct adc_host *adc)\r
62 {\r
63         struct rk30_tsadc_device *dev  = adc_priv(adc);\r
64         \r
65         writel(0, dev->regs + ADC_CTRL);\r
66 }\r
67 static int rk30_tsadc_read(struct adc_host *adc)\r
68 {\r
69         struct rk30_tsadc_device *dev  = adc_priv(adc);\r
70 \r
71         udelay(SAMPLE_RATE);\r
72         return readl(dev->regs + ADC_DATA) & ADC_DATA_MASK;\r
73 }\r
74 static irqreturn_t rk30_tsadc_irq(int irq, void *data)\r
75 {\r
76         struct rk30_tsadc_device *dev = data;\r
77         adc_core_irq_handle(dev->adc);\r
78         return IRQ_HANDLED;\r
79 }\r
80 static const struct adc_ops rk30_tsadc_ops = {\r
81         .start          = rk30_tsadc_start,\r
82         .stop           = rk30_tsadc_stop,\r
83         .read           = rk30_tsadc_read,\r
84 };\r
85 \r
86 \r
87 #ifdef ADC_TEST\r
88 struct adc_test_data {\r
89         struct adc_client client[2];\r
90         struct timer_list timer;\r
91         struct work_struct      timer_work;\r
92 };\r
93 static void callback_test(struct adc_client *client, void *param, int result)\r
94 {\r
95         int i = 0;\r
96         for(i=0;i<2;i++)\r
97         dev_info(client[i].adc->dev, "[chn=%d] async_read = %d\n", client[i].chn, result);\r
98         return;\r
99 }\r
100 static void adc_timer(unsigned long data)\r
101 {\r
102         //int sync_read = 0;\r
103          struct adc_test_data *test=(struct adc_test_data *)data;\r
104         \r
105         //sync_read = adc_sync_read(test->client);\r
106         //dev_info(test->client->adc->dev, "[chn%d] sync_read = %d\n", 0, sync_read);\r
107         schedule_work(&test->timer_work);\r
108         add_timer(&test->timer);\r
109 }\r
110 \r
111 static void adc_timer_work(struct work_struct *work)\r
112 {       \r
113         struct adc_test_data *test = container_of(work, struct adc_test_data,\r
114                                                 timer_work);\r
115         int i = 0;\r
116 #if ADC_POLL\r
117         int ret = 0, count = 0;\r
118         struct adc_host *adc = test->client[i].adc;\r
119         struct rk30_tsadc_device *dev  = adc_priv(adc);\r
120         adc->cur = &test->client[i];\r
121         rk30_tsadc_start(adc);\r
122         while(1)\r
123         {       \r
124                 udelay(SAMPLE_RATE);\r
125                 ret = readl(dev->regs + ADC_STAS);\r
126                 if(!(ret & ADC_STAS_BUSY))\r
127                 {       \r
128                         rk30_tsadc_stop(adc);\r
129                         break;\r
130                 }\r
131                 if(count++ > 10)\r
132                 {\r
133                         rk30_tsadc_stop(adc);\r
134                         printk("%s:timeout\n",__func__);\r
135                         break;\r
136                 }\r
137         }\r
138         \r
139         sync_read = readl(dev->regs + ADC_DATA);\r
140         dev_info(test->client[i].adc->dev, "[chn=%d] sync_read = %d\n", i, sync_read);\r
141 #else   \r
142         int sync_read = 0;\r
143         for(i=0;i<2;i++)\r
144         {       \r
145                 adc_async_read(&test->client[i]);       \r
146                 sync_read = adc_sync_read(&test->client[i]);            \r
147                 dev_info(test->client[i].adc->dev, "[chn=%d] sync_read = %d\n", i, sync_read);\r
148         }\r
149 #endif\r
150 }\r
151 \r
152 static int rk30_tsadc_test(void)\r
153 {\r
154         struct adc_test_data *test = NULL;\r
155         int i = 0;\r
156         test = kzalloc(sizeof(struct adc_test_data), GFP_KERNEL);\r
157         for(i=0;i<2;i++)\r
158         test->client[i] = *adc_register(i, callback_test, NULL);\r
159 \r
160         INIT_WORK(&test->timer_work, adc_timer_work);\r
161         setup_timer(&test->timer, adc_timer, (unsigned long)test);\r
162         test->timer.expires  = jiffies + 200;\r
163         add_timer(&test->timer);\r
164         \r
165         return 0;\r
166 }\r
167 #endif\r
168 \r
169 #if 1\r
170 struct temp_sample_data {\r
171         struct adc_client client[2];\r
172         struct timer_list timer;\r
173         struct work_struct      timer_work;\r
174 };\r
175 static struct temp_sample_data *gtemp;\r
176 static void callback(struct adc_client *client, void *param, int result)\r
177 {\r
178         int i = 0;\r
179         for(i=0; i<2; i++)\r
180         dev_info(client[i].adc->dev, "[chn=%d] async_read = %d\n", client[i].chn, result);\r
181         return;\r
182 }\r
183 \r
184 static int rk30_temp_sample_init(void)\r
185 {\r
186         struct temp_sample_data *temp = NULL;   \r
187         int i = 0;\r
188         temp = kzalloc(sizeof(struct temp_sample_data), GFP_KERNEL);\r
189         if (!temp){\r
190                 printk("%s:no memory for adc request\n",__func__);\r
191                 return -ENOMEM;
192         }\r
193         \r
194         for(i=0; i<2; i++)\r
195         temp->client[i] = *adc_register(i, callback, NULL);\r
196         gtemp = temp;\r
197         return 0;\r
198 \r
199 }\r
200 \r
201 \r
202 int rk30_temp_sample(int chn, int *result)\r
203 {\r
204         int sync_read = 0;\r
205         int i = 0, num = 0;\r
206 #if ADC_POLL\r
207         int ret = 0, count = 0; \r
208         struct temp_sample_data *temp = gtemp;  \r
209         struct adc_host *adc;\r
210         struct rk30_tsadc_device *dev;\r
211         chn &= 0x01;    //0 or 1\r
212         adc = temp->client[chn].adc;\r
213         dev = adc_priv(adc);\r
214         adc->cur = &temp->client[chn];\r
215         rk30_tsadc_start_poll(adc);\r
216         while(1)\r
217         {       \r
218                 udelay(SAMPLE_RATE);\r
219                 ret = readl(dev->regs + ADC_STAS);\r
220                 if(!(ret & ADC_STAS_BUSY))\r
221                 {       \r
222                         rk30_tsadc_stop(adc);\r
223                         break;\r
224                 }\r
225                 if(count++ > 20)\r
226                 {\r
227                         rk30_tsadc_stop(adc);\r
228                         printk("%s:timeout\n",__func__);\r
229                         break;\r
230                 }\r
231         }\r
232         \r
233         sync_read = readl(dev->regs + ADC_DATA);\r
234         //dev_info(temp->client[chn].adc->dev, "[chn=%d] sync_read = %d\n", chn, sync_read);\r
235 #else\r
236         adc_async_read(&gtemp->client[chn]);\r
237         sync_read = adc_sync_read(&gtemp->client[chn]);\r
238         dev_info(gtemp->client[chn].adc->dev, "[chn=%d] sync_read = %d\n", chn, sync_read);\r
239 #endif\r
240         //get temperature according to ADC value\r
241         num = sizeof(table_code_to_temp)/sizeof(struct tsadc_table);    \r
242         for(i=0; i<num-1;i++)\r
243         {\r
244                 if((sync_read >= table_code_to_temp[i+1].code) && (sync_read < table_code_to_temp[i].code))\r
245                 {\r
246                         *result = table_code_to_temp[i+1].temp;\r
247                         return 0;\r
248                 }\r
249         }\r
250 \r
251         if(sync_read <= table_code_to_temp[num-1].code)\r
252         {\r
253                 *result = table_code_to_temp[num-1].temp;               \r
254                 printk("%s:temperature is out of table\n",__func__);\r
255                 return -1;\r
256         }\r
257         else if(sync_read >= table_code_to_temp[0].code)\r
258         {\r
259                 *result = table_code_to_temp[0].temp;\r
260                 printk("%s:temperature is out of table\n",__func__);\r
261                 return -1;\r
262         }\r
263 \r
264         return -1;\r
265                 \r
266 }\r
267 \r
268 EXPORT_SYMBOL(rk30_temp_sample);\r
269 \r
270 #endif\r
271 \r
272 static int rk30_tsadc_probe(struct platform_device *pdev)\r
273 {\r
274         struct adc_host *adc = NULL;\r
275         struct rk30_tsadc_device *dev;\r
276         struct resource *res;\r
277         int ret;\r
278 \r
279         adc = adc_alloc_host(sizeof(struct rk30_tsadc_device), &pdev->dev);\r
280         if (!adc)\r
281                 return -ENOMEM;\r
282         spin_lock_init(&adc->lock);\r
283         adc->dev = &pdev->dev;\r
284         adc->is_suspended = 0;\r
285         adc->ops = &rk30_tsadc_ops;\r
286         dev = adc_priv(adc);\r
287         dev->adc = adc;\r
288         dev->irq = platform_get_irq(pdev, 0);\r
289         if (dev->irq <= 0) {\r
290                 dev_err(&pdev->dev, "failed to get adc irq\n");\r
291                 ret = -ENOENT;\r
292                 goto err_alloc;\r
293         }\r
294 \r
295         ret = request_irq(dev->irq, rk30_tsadc_irq, 0, pdev->name, dev);\r
296         if (ret < 0) {\r
297                 dev_err(&pdev->dev, "failed to attach adc irq\n");\r
298                 goto err_alloc;\r
299         }\r
300 \r
301         dev->clk = clk_get(&pdev->dev, "saradc");\r
302         if (IS_ERR(dev->clk)) {\r
303                 dev_err(&pdev->dev, "failed to get adc clock\n");\r
304                 ret = PTR_ERR(dev->clk);\r
305                 //goto err_irq;\r
306         }\r
307 \r
308         //ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);\r
309         //if(ret < 0) {\r
310         //      dev_err(&pdev->dev, "failed to set adc clk\n");\r
311                 //goto err_clk;\r
312         //}\r
313         clk_enable(dev->clk);\r
314 \r
315         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
316         if (!res) {\r
317                 dev_err(&pdev->dev, "cannot find IO resource\n");\r
318                 ret = -ENOENT;\r
319                 goto err_clk;\r
320         }\r
321         dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1, \r
322                                                                         pdev->name);\r
323         if(dev->ioarea == NULL) {\r
324                 dev_err(&pdev->dev, "cannot request IO\n");\r
325                 ret = -ENXIO;\r
326                 goto err_clk;\r
327         }\r
328         dev->regs = ioremap(res->start, (res->end - res->start) + 1);\r
329         if (!dev->regs) {\r
330                 dev_err(&pdev->dev, "cannot map IO\n");\r
331                 ret = -ENXIO;\r
332                 goto err_ioarea;\r
333         }\r
334         platform_set_drvdata(pdev, dev);\r
335         dev_info(&pdev->dev, "rk30 adc: driver initialized\n");\r
336         return 0;\r
337 // err_iomap:\r
338 //      iounmap(dev->regs);\r
339 \r
340  err_ioarea:\r
341         release_resource(dev->ioarea);\r
342         kfree(dev->ioarea);\r
343         clk_disable(dev->clk);\r
344 \r
345  err_clk:\r
346         clk_put(dev->clk);\r
347 \r
348  err_irq:\r
349         free_irq(dev->irq, dev);\r
350 \r
351  err_alloc:\r
352         adc_free_host(dev->adc);\r
353         return ret;\r
354 }\r
355 \r
356 static int rk30_tsadc_remove(struct platform_device *pdev)\r
357 {\r
358         struct rk30_tsadc_device *dev = platform_get_drvdata(pdev);\r
359 \r
360         iounmap(dev->regs);\r
361         release_resource(dev->ioarea);\r
362         kfree(dev->ioarea);\r
363         free_irq(dev->irq, dev);\r
364         clk_disable(dev->clk);\r
365         clk_put(dev->clk);\r
366         adc_free_host(dev->adc);\r
367 \r
368         return 0;\r
369 }\r
370 \r
371 #ifdef CONFIG_PM\r
372 static int rk30_tsadc_suspend(struct platform_device *pdev, pm_message_t state)\r
373 {\r
374         struct rk30_tsadc_device *dev = platform_get_drvdata(pdev);\r
375 \r
376         dev->adc->is_suspended = 1;\r
377         return 0;\r
378 }\r
379 \r
380 static int rk30_tsadc_resume(struct platform_device *pdev)\r
381 {\r
382         struct rk30_tsadc_device *dev = platform_get_drvdata(pdev);\r
383 \r
384         dev->adc->is_suspended = 0;\r
385         return 0;\r
386 }\r
387 \r
388 #else\r
389 #define rk30_tsadc_suspend NULL\r
390 #define rk30_tsadc_resume NULL\r
391 #endif\r
392 \r
393 static struct platform_driver rk30_tsadc_driver = {\r
394         .driver         = {\r
395                 .name   = "rk30-tsadc",\r
396                 .owner  = THIS_MODULE,\r
397         },\r
398         .probe          = rk30_tsadc_probe,\r
399         .remove         = __devexit_p(rk30_tsadc_remove),\r
400         .suspend        = rk30_tsadc_suspend,\r
401         .resume         = rk30_tsadc_resume,\r
402 };\r
403 \r
404 static int __init rk30_tsadc_init(void)\r
405 {\r
406         return platform_driver_register(&rk30_tsadc_driver);\r
407 }\r
408 subsys_initcall(rk30_tsadc_init);\r
409 \r
410 static void __exit rk30_tsadc_exit(void)\r
411 {\r
412         platform_driver_unregister(&rk30_tsadc_driver);\r
413 }\r
414 module_exit(rk30_tsadc_exit);\r
415 \r
416 MODULE_DESCRIPTION("Driver for TSADC");\r
417 MODULE_AUTHOR("lw, lw@rock-chips.com");\r
418 MODULE_LICENSE("GPL");\r
419 \r
420 static int __init rk30_temp_init(void)\r
421 {\r
422         int ret = 0;\r
423         ret = rk30_temp_sample_init();\r
424 #ifdef ADC_TEST \r
425         rk30_tsadc_test();\r
426 #endif  \r
427         printk("%s:initialized\n",__func__);\r
428         return ret;\r
429 }\r
430 \r
431 static void __exit rk30_temp_exit(void)\r
432 {\r
433         int i = 0;\r
434         struct temp_sample_data *temp = gtemp;\r
435         for(i=0; i<2; i++)\r
436         adc_unregister(&temp->client[i]);\r
437         kfree(temp);\r
438 }\r
439 \r
440 module_init(rk30_temp_init);\r
441 module_exit(rk30_temp_exit);\r
442 \r