rk2928: 'adc&keypad support' and 'lvds' and 'lcd'
[firefly-linux-kernel-4.4.55.git] / drivers / adc / plat / rk29_adc.c
1 /* drivers/adc/chips/rk29_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 "rk29_adc.h"\r
11 \r
12 //#define ADC_TEST\r
13 \r
14 struct rk29_adc_device {\r
15         int                                     irq;\r
16         void __iomem            *regs;\r
17         struct clk *            clk;\r
18         struct resource         *ioarea;\r
19         struct adc_host         *adc;\r
20 };\r
21 static void rk29_adc_start(struct adc_host *adc)\r
22 {\r
23         struct rk29_adc_device *dev  = adc_priv(adc);\r
24         int chn = adc->chn;\r
25 \r
26         writel(0, dev->regs + ADC_CTRL);\r
27         writel(ADC_CTRL_POWER_UP|ADC_CTRL_CH(chn), dev->regs + ADC_CTRL);\r
28         udelay(SAMPLE_RATE);\r
29 \r
30         writel(readl(dev->regs + ADC_CTRL)|ADC_CTRL_IRQ_ENABLE|ADC_CTRL_START, \r
31                 dev->regs + ADC_CTRL);\r
32         return;\r
33 }\r
34 static void rk29_adc_stop(struct adc_host *adc)\r
35 {\r
36         struct rk29_adc_device *dev  = adc_priv(adc);\r
37         \r
38         writel(0, dev->regs + ADC_CTRL);\r
39 }\r
40 static int rk29_adc_read(struct adc_host *adc)\r
41 {\r
42         struct rk29_adc_device *dev  = adc_priv(adc);\r
43 \r
44         udelay(SAMPLE_RATE);\r
45         return readl(dev->regs + ADC_DATA) & ADC_DATA_MASK;\r
46 }\r
47 static irqreturn_t rk29_adc_irq(int irq, void *data)\r
48 {\r
49         struct rk29_adc_device *dev = data;\r
50         adc_core_irq_handle(dev->adc);\r
51         return IRQ_HANDLED;\r
52 }\r
53 static const struct adc_ops rk29_adc_ops = {\r
54         .start          = rk29_adc_start,\r
55         .stop           = rk29_adc_stop,\r
56         .read           = rk29_adc_read,\r
57 };\r
58 #ifdef ADC_TEST\r
59 struct adc_test_data {\r
60         struct adc_client *client;\r
61         struct timer_list timer;\r
62         struct work_struct      timer_work;\r
63 };\r
64 static void callback(struct adc_client *client, void *param, int result)\r
65 {\r
66         dev_info(client->adc->dev, "[chn%d] async_read = %d\n", client->chn, result);\r
67         return;\r
68 }\r
69 static void adc_timer(unsigned long data)\r
70 {\r
71         //int sync_read = 0;\r
72          struct adc_test_data *test=(struct adc_test_data *)data;\r
73         \r
74         //sync_read = adc_sync_read(test->client);\r
75         //dev_info(test->client->adc->dev, "[chn%d] sync_read = %d\n", 0, sync_read);\r
76         schedule_work(&test->timer_work);\r
77         add_timer(&test->timer);\r
78 }\r
79 static void adc_timer_work(struct work_struct *work)\r
80 {       \r
81         int sync_read = 0;\r
82         struct adc_test_data *test = container_of(work, struct adc_test_data,\r
83                                                 timer_work);\r
84         adc_async_read(test->client);\r
85         sync_read = adc_sync_read(test->client);\r
86         dev_info(test->client->adc->dev, "[chn%d] sync_read = %d\n", 0, sync_read);\r
87 }\r
88 \r
89 static int rk29_adc_test(void)\r
90 {\r
91         struct adc_test_data *test = NULL;\r
92 \r
93         test = kzalloc(sizeof(struct adc_test_data), GFP_KERNEL);\r
94         \r
95         test->client = adc_register(0, callback, NULL);\r
96         INIT_WORK(&test->timer_work, adc_timer_work);\r
97         setup_timer(&test->timer, adc_timer, (unsigned long)test);\r
98         test->timer.expires  = jiffies + 100;\r
99         add_timer(&test->timer);\r
100         \r
101         return 0;\r
102 \r
103 }\r
104 #endif\r
105 \r
106 static int rk29_adc_probe(struct platform_device *pdev)\r
107 {\r
108         struct adc_host *adc = NULL;\r
109         struct rk29_adc_device *dev;\r
110         struct resource *res;\r
111         int ret;\r
112 \r
113         adc = adc_alloc_host(&pdev->dev, sizeof(struct rk29_adc_device), SARADC_CHN_MASK);\r
114         if (!adc)\r
115                 return -ENOMEM;\r
116         adc->ops = &rk29_adc_ops;\r
117         dev = adc_priv(adc);\r
118         dev->adc = adc;\r
119         dev->irq = platform_get_irq(pdev, 0);\r
120         if (dev->irq <= 0) {\r
121                 dev_err(&pdev->dev, "failed to get adc irq\n");\r
122                 ret = -ENOENT;\r
123                 goto err_alloc;\r
124         }\r
125 \r
126         ret = request_irq(dev->irq, rk29_adc_irq, 0, pdev->name, dev);\r
127         if (ret < 0) {\r
128                 dev_err(&pdev->dev, "failed to attach adc irq\n");\r
129                 goto err_alloc;\r
130         }\r
131         dev->clk = clk_get(&pdev->dev, "saradc");\r
132         if (IS_ERR(dev->clk)) {\r
133                 dev_err(&pdev->dev, "failed to get adc clock\n");\r
134                 ret = PTR_ERR(dev->clk);\r
135                 goto err_irq;\r
136         }\r
137 \r
138         ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);\r
139         if(ret < 0) {\r
140                 dev_err(&pdev->dev, "failed to set adc clk\n");\r
141                 goto err_clk;\r
142         }\r
143         clk_enable(dev->clk);\r
144 \r
145         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
146         if (!res) {\r
147                 dev_err(&pdev->dev, "cannot find IO resource\n");\r
148                 ret = -ENOENT;\r
149                 goto err_clk;\r
150         }\r
151         dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1, \r
152                                                                         pdev->name);\r
153         if(dev->ioarea == NULL) {\r
154                 dev_err(&pdev->dev, "cannot request IO\n");\r
155                 ret = -ENXIO;\r
156                 goto err_clk;\r
157         }\r
158         dev->regs = ioremap(res->start, (res->end - res->start) + 1);\r
159         if (!dev->regs) {\r
160                 dev_err(&pdev->dev, "cannot map IO\n");\r
161                 ret = -ENXIO;\r
162                 goto err_ioarea;\r
163         }\r
164         platform_set_drvdata(pdev, dev);\r
165         dev_info(&pdev->dev, "rk29 adc: driver initialized\n");\r
166         return 0;\r
167 \r
168  err_ioarea:\r
169         release_resource(dev->ioarea);\r
170         kfree(dev->ioarea);\r
171         clk_disable(dev->clk);\r
172 \r
173  err_clk:\r
174         clk_put(dev->clk);\r
175 \r
176  err_irq:\r
177         free_irq(dev->irq, dev);\r
178 \r
179  err_alloc:\r
180         adc_free_host(dev->adc);\r
181         return ret;\r
182 }\r
183 \r
184 static int rk29_adc_remove(struct platform_device *pdev)\r
185 {\r
186         struct rk29_adc_device *dev = platform_get_drvdata(pdev);\r
187 \r
188         iounmap(dev->regs);\r
189         release_resource(dev->ioarea);\r
190         kfree(dev->ioarea);\r
191         free_irq(dev->irq, dev);\r
192         clk_disable(dev->clk);\r
193         clk_put(dev->clk);\r
194         adc_free_host(dev->adc);\r
195 \r
196         return 0;\r
197 }\r
198 \r
199 #ifdef CONFIG_PM\r
200 static int rk29_adc_suspend(struct platform_device *pdev, pm_message_t state)\r
201 {\r
202         struct rk29_adc_device *dev = platform_get_drvdata(pdev);\r
203 \r
204         dev->adc->is_suspended = 1;\r
205         return 0;\r
206 }\r
207 \r
208 static int rk29_adc_resume(struct platform_device *pdev)\r
209 {\r
210         struct rk29_adc_device *dev = platform_get_drvdata(pdev);\r
211 \r
212         dev->adc->is_suspended = 0;\r
213         return 0;\r
214 }\r
215 \r
216 #else\r
217 #define rk29_adc_suspend NULL\r
218 #define rk29_adc_resume NULL\r
219 #endif\r
220 \r
221 static struct platform_driver rk29_adc_driver = {\r
222         .driver         = {\r
223                 .name   = "rk29-adc",\r
224                 .owner  = THIS_MODULE,\r
225         },\r
226         .probe          = rk29_adc_probe,\r
227         .remove         = __devexit_p(rk29_adc_remove),\r
228         .suspend        = rk29_adc_suspend,\r
229         .resume         = rk29_adc_resume,\r
230 };\r
231 \r
232 static int __init rk29_adc_init(void)\r
233 {\r
234         return platform_driver_register(&rk29_adc_driver);\r
235 }\r
236 subsys_initcall(rk29_adc_init);\r
237 \r
238 static void __exit rk29_adc_exit(void)\r
239 {\r
240         platform_driver_unregister(&rk29_adc_driver);\r
241 }\r
242 module_exit(rk29_adc_exit);\r
243 \r
244 MODULE_DESCRIPTION("Driver for ADC");\r
245 MODULE_AUTHOR("kfx, kfx@rock-chips.com");\r
246 MODULE_LICENSE("GPL");\r
247 static int __init adc_test_init(void)\r
248 {\r
249 #ifdef ADC_TEST \r
250                 rk29_adc_test();\r
251 #endif\r
252         return 0;\r
253 \r
254 }\r
255 module_init(adc_test_init);\r