Merge remote-tracking branch 'origin/upstream/linux-linaro-lsk-v3.10-android' into...
[firefly-linux-kernel-4.4.55.git] / drivers / adc / plat / rk30_adc.c
1 /* drivers/adc/chips/rk30_adc.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/adc.h>\r
8 \r
9 #include "../adc_priv.h"\r
10 #include "rk30_adc.h"\r
11 \r
12 //#define ADC_TEST\r
13 #define SAMPLE_COUNT            10\r
14 #define MIN_SAMPLE_VALUE        310\r
15 struct rk30_adc_device {\r
16         int                      irq;\r
17         void __iomem            *regs;\r
18         struct clk              *clk;\r
19         struct clk              *pclk;\r
20         struct resource         *ioarea;\r
21         struct adc_host         *adc;\r
22 };\r
23 static void rk30_adc_dump(struct adc_host *adc)\r
24 {\r
25         struct rk30_adc_device *dev  = adc_priv(adc);\r
26 \r
27         dev_info(adc->dev, "[0x00-0x0c]: 0x%08x 0x%08x 0x%08x 0x%08x\n",\r
28                         adc_readl(dev->regs + 0x00),\r
29                         adc_readl(dev->regs + 0x04),\r
30                         adc_readl(dev->regs + 0x08),\r
31                         adc_readl(dev->regs + 0x0c));\r
32 }\r
33 static void rk30_adc_start(struct adc_host *adc)\r
34 {\r
35         struct rk30_adc_device *dev  = adc_priv(adc);\r
36         int chn = adc->chn;\r
37 \r
38         //adc_writel(0, dev->regs + ADC_CTRL);\r
39         adc_writel(0x08, dev->regs + ADC_DELAY_PU_SOC);\r
40         adc_writel(ADC_CTRL_POWER_UP|ADC_CTRL_CH(chn)|ADC_CTRL_IRQ_ENABLE, dev->regs + ADC_CTRL);\r
41 \r
42         return;\r
43 }\r
44 static void rk30_adc_stop(struct adc_host *adc)\r
45 {\r
46         struct rk30_adc_device *dev  = adc_priv(adc);\r
47         \r
48         adc_writel(0, dev->regs + ADC_CTRL);\r
49 }\r
50 static int rk30_adc_read(struct adc_host *adc)\r
51 {\r
52         struct rk30_adc_device *dev  = adc_priv(adc);\r
53 \r
54         return adc_readl(dev->regs + ADC_DATA) & ADC_DATA_MASK;\r
55 }\r
56 static irqreturn_t rk30_adc_irq(int irq, void *data)\r
57 {\r
58         struct rk30_adc_device *dev = data;\r
59 \r
60         adc_core_irq_handle(dev->adc);\r
61         return IRQ_HANDLED;\r
62 }\r
63 static const struct adc_ops rk30_adc_ops = {\r
64         .start          = rk30_adc_start,\r
65         .stop           = rk30_adc_stop,\r
66         .read           = rk30_adc_read,\r
67         .dump           = rk30_adc_dump,\r
68 };\r
69 #ifdef ADC_TEST\r
70 #define CHN_NR  3\r
71 struct workqueue_struct *adc_wq;\r
72 struct adc_test_data {\r
73         struct adc_client *client;\r
74         struct timer_list timer;\r
75         struct work_struct      timer_work;\r
76 };\r
77 static void callback(struct adc_client *client, void *param, int result)\r
78 {\r
79         dev_dbg(client->adc->dev, "[chn%d] async_read = %d\n", client->chn, result);\r
80         return;\r
81 }\r
82 static void adc_timer(unsigned long data)\r
83 {\r
84          struct adc_test_data *test=(struct adc_test_data *)data;\r
85         \r
86         queue_work(adc_wq, &test->timer_work);\r
87         mod_timer(&test->timer, jiffies+msecs_to_jiffies(20));\r
88 }\r
89 static void adc_timer_work(struct work_struct *work)\r
90 {       \r
91         int sync_read = 0;\r
92         struct adc_test_data *test = container_of(work, struct adc_test_data,\r
93                                                 timer_work);\r
94         adc_async_read(test->client);\r
95         sync_read = adc_sync_read(test->client);\r
96         dev_dbg(test->client->adc->dev, "[chn%d] sync_read = %d\n", test->client->chn, sync_read);\r
97 }\r
98 \r
99 static int rk30_adc_test(void)\r
100 {\r
101         int i;\r
102         struct adc_test_data *test[CHN_NR];\r
103 \r
104         adc_wq = create_singlethread_workqueue("adc_test");\r
105         for(i = 0; i < CHN_NR; i++){\r
106                 test[i] = kzalloc(sizeof(struct adc_test_data), GFP_KERNEL);\r
107                 test[i]->client = adc_register(i, callback, NULL);\r
108                 INIT_WORK(&test[i]->timer_work, adc_timer_work);\r
109                 setup_timer(&test[i]->timer, adc_timer, (unsigned long)test[i]);\r
110                 mod_timer(&test[i]->timer, jiffies+msecs_to_jiffies(20));\r
111         }\r
112         \r
113         return 0;\r
114 \r
115 }\r
116 #endif\r
117 \r
118 static int rk30_adc_probe(struct platform_device *pdev)\r
119 {\r
120         struct adc_platform_data *pdata = pdev->dev.platform_data;\r
121         struct adc_host *adc = NULL;\r
122         struct rk30_adc_device *dev;\r
123         struct resource *res;\r
124         int ret = 0, i, v;\r
125 \r
126         if(!pdata)\r
127                 return -EINVAL;\r
128 \r
129         adc = adc_alloc_host(&pdev->dev, sizeof(struct rk30_adc_device), SARADC_CHN_MASK);\r
130         if (!adc)\r
131                 return -ENOMEM;\r
132         adc->ops = &rk30_adc_ops;\r
133         adc->pdata = pdata;\r
134         dev = adc_priv(adc);\r
135         dev->adc = adc;\r
136         dev->irq = platform_get_irq(pdev, 0);\r
137         if (dev->irq <= 0) {\r
138                 dev_err(&pdev->dev, "failed to get adc irq\n");\r
139                 ret = -ENOENT;\r
140                 goto err_alloc;\r
141         }\r
142 \r
143         ret = request_threaded_irq(dev->irq, NULL, rk30_adc_irq, IRQF_ONESHOT, pdev->name, dev);\r
144         if (ret < 0) {\r
145                 dev_err(&pdev->dev, "failed to attach adc irq\n");\r
146                 goto err_alloc;\r
147         }\r
148 \r
149         dev->pclk = clk_get(&pdev->dev, "pclk_saradc");\r
150         if (IS_ERR(dev->pclk)) {\r
151                 dev_err(&pdev->dev, "failed to get adc pclk\n");\r
152                 ret = PTR_ERR(dev->pclk);\r
153                 goto err_irq;\r
154         }\r
155         clk_enable(dev->pclk);\r
156 \r
157         dev->clk = clk_get(&pdev->dev, "saradc");\r
158         if (IS_ERR(dev->clk)) {\r
159                 dev_err(&pdev->dev, "failed to get adc clock\n");\r
160                 ret = PTR_ERR(dev->clk);\r
161                 goto err_pclk;\r
162         }\r
163 \r
164         ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);\r
165         if(ret < 0) {\r
166                 dev_err(&pdev->dev, "failed to set adc clk\n");\r
167                 goto err_clk2;\r
168         }\r
169         clk_enable(dev->clk);\r
170 \r
171         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
172         if (!res) {\r
173                 dev_err(&pdev->dev, "cannot find IO resource\n");\r
174                 ret = -ENOENT;\r
175                 goto err_clk;\r
176         }\r
177         dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1, \r
178                                                                         pdev->name);\r
179         if(dev->ioarea == NULL) {\r
180                 dev_err(&pdev->dev, "cannot request IO\n");\r
181                 ret = -ENXIO;\r
182                 goto err_clk;\r
183         }\r
184         dev->regs = ioremap(res->start, (res->end - res->start) + 1);\r
185         if (!dev->regs) {\r
186                 dev_err(&pdev->dev, "cannot map IO\n");\r
187                 ret = -ENXIO;\r
188                 goto err_ioarea;\r
189         }\r
190         g_adc = adc;\r
191         platform_set_drvdata(pdev, dev);\r
192 \r
193         if(adc->pdata->base_chn > 0){\r
194                 adc->base_client = adc_register(adc->pdata->base_chn, NULL, NULL);\r
195                 if(!adc->base_client){\r
196                         dev_err(&pdev->dev, "adc_register(base_chn: %d) failed\n", adc->pdata->base_chn);\r
197                         ret = -ENOMEM;\r
198                         goto err_adc_register;\r
199                 }\r
200                 for(i = 0; i < SAMPLE_COUNT; i++){\r
201                         v = adc_sync_read(adc->base_client);\r
202                         if(v < 0){\r
203                                 dev_err(&pdev->dev, "adc_register(base_chn: %d) failed\n", adc->pdata->base_chn);\r
204                                 ret = v;\r
205                                 goto err_adc_sync_read;\r
206                         }else if(v < MIN_SAMPLE_VALUE){\r
207                                 dev_info(&pdev->dev, "chn[%d]: adc value(%d) is invalide\n", adc->pdata->base_chn, v);\r
208                                 adc_unregister(adc->base_client);\r
209                                 adc->base_client = NULL;\r
210                                 break;\r
211                         }\r
212                         adc_dbg(&pdev->dev, "read ref_adc: %d\n", v);\r
213                         mdelay(1);\r
214                 }\r
215         }\r
216         dev_info(&pdev->dev, "rk30 adc: driver initialized\n");\r
217         return 0;\r
218 err_adc_sync_read:\r
219         adc_unregister(adc->base_client);\r
220         adc->base_client = NULL;\r
221 err_adc_register:\r
222         iounmap(dev->regs);\r
223 err_ioarea:\r
224         release_resource(dev->ioarea);\r
225         kfree(dev->ioarea);\r
226 \r
227 err_clk:\r
228         clk_disable(dev->clk);\r
229 \r
230 err_pclk:\r
231         clk_disable(dev->pclk);\r
232         clk_put(dev->pclk);\r
233 \r
234 err_clk2:\r
235         clk_put(dev->clk);\r
236 \r
237 err_irq:\r
238         free_irq(dev->irq, dev);\r
239 \r
240 err_alloc:\r
241         adc_free_host(dev->adc);\r
242         return ret;\r
243 }\r
244 \r
245 static int rk30_adc_remove(struct platform_device *pdev)\r
246 {\r
247         struct rk30_adc_device *dev = platform_get_drvdata(pdev);\r
248 \r
249         if(dev->adc->base_client){\r
250                 adc_unregister(dev->adc->base_client);\r
251                 dev->adc->base_client = NULL;\r
252         }\r
253         iounmap(dev->regs);\r
254         release_resource(dev->ioarea);\r
255         kfree(dev->ioarea);\r
256         free_irq(dev->irq, dev);\r
257         clk_disable(dev->clk);\r
258         clk_put(dev->clk);\r
259         clk_disable(dev->pclk);\r
260         clk_put(dev->pclk);\r
261         adc_free_host(dev->adc);\r
262 \r
263         return 0;\r
264 }\r
265 \r
266 #ifdef CONFIG_PM\r
267 static int rk30_adc_suspend(struct platform_device *pdev, pm_message_t state)\r
268 {\r
269         struct rk30_adc_device *dev = platform_get_drvdata(pdev);\r
270 \r
271         dev->adc->is_suspended = 1;\r
272         return 0;\r
273 }\r
274 \r
275 static int rk30_adc_resume(struct platform_device *pdev)\r
276 {\r
277         struct rk30_adc_device *dev = platform_get_drvdata(pdev);\r
278 \r
279         dev->adc->is_suspended = 0;\r
280         return 0;\r
281 }\r
282 \r
283 #else\r
284 #define rk30_adc_suspend NULL\r
285 #define rk30_adc_resume NULL\r
286 #endif\r
287 \r
288 static struct platform_driver rk30_adc_driver = {\r
289         .driver         = {\r
290                 .name   = "rk30-adc",\r
291                 .owner  = THIS_MODULE,\r
292         },\r
293         .probe          = rk30_adc_probe,\r
294         .remove         = __devexit_p(rk30_adc_remove),\r
295         .suspend        = rk30_adc_suspend,\r
296         .resume         = rk30_adc_resume,\r
297 };\r
298 \r
299 static int __init rk30_adc_init(void)\r
300 {\r
301         return platform_driver_register(&rk30_adc_driver);\r
302 }\r
303 subsys_initcall(rk30_adc_init);\r
304 \r
305 static void __exit rk30_adc_exit(void)\r
306 {\r
307         platform_driver_unregister(&rk30_adc_driver);\r
308 }\r
309 module_exit(rk30_adc_exit);\r
310 \r
311 MODULE_DESCRIPTION("Driver for ADC");\r
312 MODULE_AUTHOR("kfx, kfx@rock-chips.com");\r
313 MODULE_LICENSE("GPL");\r
314 \r
315 static int __init adc_test_init(void)\r
316 {\r
317         printk("def_ref_volt: %dmV, curr_ref_volt: %dmV\n", \r
318                         adc_get_def_ref_volt(), adc_get_curr_ref_volt());\r
319 #ifdef ADC_TEST \r
320         rk30_adc_test();\r
321 #endif\r
322         return 0;\r
323 \r
324 }\r
325 module_init(adc_test_init);\r