rk30: enable 'adc drivers' and 'adc keys'
[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/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_adc.h"\r
22 \r
23 //#define ADC_TEST\r
24 \r
25 struct rk30_adc_device {\r
26         int                                     irq;\r
27         void __iomem            *regs;\r
28         struct clk *            clk;\r
29         struct resource         *ioarea;\r
30         struct adc_host         *adc;\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->cur->chn;\r
36 \r
37         writel(0, dev->regs + ADC_CTRL);\r
38         writel(0x08, dev->regs + ADC_DELAY_PU_SOC);\r
39         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         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         udelay(SAMPLE_RATE);\r
54         return 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 };\r
68 #ifdef ADC_TEST\r
69 struct adc_test_data {\r
70         struct adc_client *client;\r
71         struct timer_list timer;\r
72         struct work_struct      timer_work;\r
73 };\r
74 static void callback(struct adc_client *client, void *param, int result)\r
75 {\r
76         dev_info(client->adc->dev, "[chn%d] async_read = %d\n", client->chn, result);\r
77         return;\r
78 }\r
79 static void adc_timer(unsigned long data)\r
80 {\r
81         //int sync_read = 0;\r
82          struct adc_test_data *test=(struct adc_test_data *)data;\r
83         \r
84         //sync_read = adc_sync_read(test->client);\r
85         //dev_info(test->client->adc->dev, "[chn%d] sync_read = %d\n", 0, sync_read);\r
86         schedule_work(&test->timer_work);\r
87         add_timer(&test->timer);\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_info(test->client->adc->dev, "[chn%d] sync_read = %d\n", 0, sync_read);\r
97 }\r
98 \r
99 static int rk30_adc_test(void)\r
100 {\r
101         struct adc_test_data *test = NULL;\r
102 \r
103         test = kzalloc(sizeof(struct adc_test_data), GFP_KERNEL);\r
104         \r
105         test->client = adc_register(0, callback, NULL);\r
106         INIT_WORK(&test->timer_work, adc_timer_work);\r
107         setup_timer(&test->timer, adc_timer, (unsigned long)test);\r
108         test->timer.expires  = jiffies + 100;\r
109         add_timer(&test->timer);\r
110         \r
111         return 0;\r
112 \r
113 }\r
114 #endif\r
115 \r
116 static int rk30_adc_probe(struct platform_device *pdev)\r
117 {\r
118         struct adc_host *adc = NULL;\r
119         struct rk30_adc_device *dev;\r
120         struct resource *res;\r
121         int ret;\r
122 \r
123         adc = adc_alloc_host(sizeof(struct rk30_adc_device), &pdev->dev);\r
124         if (!adc)\r
125                 return -ENOMEM;\r
126         spin_lock_init(&adc->lock);\r
127         adc->dev = &pdev->dev;\r
128         adc->is_suspended = 0;\r
129         adc->ops = &rk30_adc_ops;\r
130         dev = adc_priv(adc);\r
131         dev->adc = adc;\r
132         dev->irq = platform_get_irq(pdev, 0);\r
133         if (dev->irq <= 0) {\r
134                 dev_err(&pdev->dev, "failed to get adc irq\n");\r
135                 ret = -ENOENT;\r
136                 goto err_alloc;\r
137         }\r
138 \r
139         ret = request_irq(dev->irq, rk30_adc_irq, 0, pdev->name, dev);\r
140         if (ret < 0) {\r
141                 dev_err(&pdev->dev, "failed to attach adc irq\n");\r
142                 goto err_alloc;\r
143         }\r
144         dev->clk = clk_get(&pdev->dev, "saradc");\r
145         if (IS_ERR(dev->clk)) {\r
146                 dev_err(&pdev->dev, "failed to get adc clock\n");\r
147                 ret = PTR_ERR(dev->clk);\r
148                 goto err_irq;\r
149         }\r
150 \r
151         ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);\r
152         if(ret < 0) {\r
153                 dev_err(&pdev->dev, "failed to set adc clk\n");\r
154                 goto err_clk;\r
155         }\r
156         clk_enable(dev->clk);\r
157 \r
158         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
159         if (!res) {\r
160                 dev_err(&pdev->dev, "cannot find IO resource\n");\r
161                 ret = -ENOENT;\r
162                 goto err_clk;\r
163         }\r
164         dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1, \r
165                                                                         pdev->name);\r
166         if(dev->ioarea == NULL) {\r
167                 dev_err(&pdev->dev, "cannot request IO\n");\r
168                 ret = -ENXIO;\r
169                 goto err_clk;\r
170         }\r
171         dev->regs = ioremap(res->start, (res->end - res->start) + 1);\r
172         if (!dev->regs) {\r
173                 dev_err(&pdev->dev, "cannot map IO\n");\r
174                 ret = -ENXIO;\r
175                 goto err_ioarea;\r
176         }\r
177         platform_set_drvdata(pdev, dev);\r
178         dev_info(&pdev->dev, "rk30 adc: driver initialized\n");\r
179         return 0;\r
180 // err_iomap:\r
181 //      iounmap(dev->regs);\r
182 \r
183  err_ioarea:\r
184         release_resource(dev->ioarea);\r
185         kfree(dev->ioarea);\r
186         clk_disable(dev->clk);\r
187 \r
188  err_clk:\r
189         clk_put(dev->clk);\r
190 \r
191  err_irq:\r
192         free_irq(dev->irq, dev);\r
193 \r
194  err_alloc:\r
195         adc_free_host(dev->adc);\r
196         return ret;\r
197 }\r
198 \r
199 static int rk30_adc_remove(struct platform_device *pdev)\r
200 {\r
201         struct rk30_adc_device *dev = platform_get_drvdata(pdev);\r
202 \r
203         iounmap(dev->regs);\r
204         release_resource(dev->ioarea);\r
205         kfree(dev->ioarea);\r
206         free_irq(dev->irq, dev);\r
207         clk_disable(dev->clk);\r
208         clk_put(dev->clk);\r
209         adc_free_host(dev->adc);\r
210 \r
211         return 0;\r
212 }\r
213 \r
214 #ifdef CONFIG_PM\r
215 static int rk30_adc_suspend(struct platform_device *pdev, pm_message_t state)\r
216 {\r
217         struct rk30_adc_device *dev = platform_get_drvdata(pdev);\r
218 \r
219         dev->adc->is_suspended = 1;\r
220         return 0;\r
221 }\r
222 \r
223 static int rk30_adc_resume(struct platform_device *pdev)\r
224 {\r
225         struct rk30_adc_device *dev = platform_get_drvdata(pdev);\r
226 \r
227         dev->adc->is_suspended = 0;\r
228         return 0;\r
229 }\r
230 \r
231 #else\r
232 #define rk30_adc_suspend NULL\r
233 #define rk30_adc_resume NULL\r
234 #endif\r
235 \r
236 static struct platform_driver rk30_adc_driver = {\r
237         .driver         = {\r
238                 .name   = "rk30-adc",\r
239                 .owner  = THIS_MODULE,\r
240         },\r
241         .probe          = rk30_adc_probe,\r
242         .remove         = __devexit_p(rk30_adc_remove),\r
243         .suspend        = rk30_adc_suspend,\r
244         .resume         = rk30_adc_resume,\r
245 };\r
246 \r
247 static int __init rk30_adc_init(void)\r
248 {\r
249         return platform_driver_register(&rk30_adc_driver);\r
250 }\r
251 subsys_initcall(rk30_adc_init);\r
252 \r
253 static void __exit rk30_adc_exit(void)\r
254 {\r
255         platform_driver_unregister(&rk30_adc_driver);\r
256 }\r
257 module_exit(rk30_adc_exit);\r
258 \r
259 MODULE_DESCRIPTION("Driver for ADC");\r
260 MODULE_AUTHOR("kfx, kfx@rock-chips.com");\r
261 MODULE_LICENSE("GPL");\r
262 static int __init adc_test_init(void)\r
263 {\r
264 #ifdef ADC_TEST \r
265                 rk30_adc_test();\r
266 #endif\r
267         return 0;\r
268 \r
269 }\r
270 module_init(adc_test_init);\r