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