ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[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_platform_data *pdata = pdev->dev.platform_data;\r
109         struct adc_host *adc = NULL;\r
110         struct rk29_adc_device *dev;\r
111         struct resource *res;\r
112         int ret;\r
113 \r
114         if(!pdata)\r
115                 return -EINVAL;\r
116 \r
117         adc = adc_alloc_host(&pdev->dev, sizeof(struct rk29_adc_device), SARADC_CHN_MASK);\r
118         if (!adc)\r
119                 return -ENOMEM;\r
120         adc->ops = &rk29_adc_ops;\r
121         adc->pdata = pdata;\r
122         dev = adc_priv(adc);\r
123         dev->adc = adc;\r
124         dev->irq = platform_get_irq(pdev, 0);\r
125         if (dev->irq <= 0) {\r
126                 dev_err(&pdev->dev, "failed to get adc irq\n");\r
127                 ret = -ENOENT;\r
128                 goto err_alloc;\r
129         }\r
130 \r
131         ret = request_threaded_irq(dev->irq, NULL, rk29_adc_irq, IRQF_ONESHOT, pdev->name, dev);\r
132         if (ret < 0) {\r
133                 dev_err(&pdev->dev, "failed to attach adc irq\n");\r
134                 goto err_alloc;\r
135         }\r
136         dev->clk = clk_get(&pdev->dev, "saradc");\r
137         if (IS_ERR(dev->clk)) {\r
138                 dev_err(&pdev->dev, "failed to get adc clock\n");\r
139                 ret = PTR_ERR(dev->clk);\r
140                 goto err_irq;\r
141         }\r
142 \r
143         ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);\r
144         if(ret < 0) {\r
145                 dev_err(&pdev->dev, "failed to set adc clk\n");\r
146                 goto err_clk;\r
147         }\r
148         clk_enable(dev->clk);\r
149 \r
150         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
151         if (!res) {\r
152                 dev_err(&pdev->dev, "cannot find IO resource\n");\r
153                 ret = -ENOENT;\r
154                 goto err_clk;\r
155         }\r
156         dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1, \r
157                                                                         pdev->name);\r
158         if(dev->ioarea == NULL) {\r
159                 dev_err(&pdev->dev, "cannot request IO\n");\r
160                 ret = -ENXIO;\r
161                 goto err_clk;\r
162         }\r
163         dev->regs = ioremap(res->start, (res->end - res->start) + 1);\r
164         if (!dev->regs) {\r
165                 dev_err(&pdev->dev, "cannot map IO\n");\r
166                 ret = -ENXIO;\r
167                 goto err_ioarea;\r
168         }\r
169         g_adc = adc;\r
170         platform_set_drvdata(pdev, dev);\r
171         dev_info(&pdev->dev, "rk29 adc: driver initialized\n");\r
172         return 0;\r
173 \r
174  err_ioarea:\r
175         release_resource(dev->ioarea);\r
176         kfree(dev->ioarea);\r
177         clk_disable(dev->clk);\r
178 \r
179  err_clk:\r
180         clk_put(dev->clk);\r
181 \r
182  err_irq:\r
183         free_irq(dev->irq, dev);\r
184 \r
185  err_alloc:\r
186         adc_free_host(dev->adc);\r
187         return ret;\r
188 }\r
189 \r
190 static int rk29_adc_remove(struct platform_device *pdev)\r
191 {\r
192         struct rk29_adc_device *dev = platform_get_drvdata(pdev);\r
193 \r
194         iounmap(dev->regs);\r
195         release_resource(dev->ioarea);\r
196         kfree(dev->ioarea);\r
197         free_irq(dev->irq, dev);\r
198         clk_disable(dev->clk);\r
199         clk_put(dev->clk);\r
200         adc_free_host(dev->adc);\r
201 \r
202         return 0;\r
203 }\r
204 \r
205 #ifdef CONFIG_PM\r
206 static int rk29_adc_suspend(struct platform_device *pdev, pm_message_t state)\r
207 {\r
208         struct rk29_adc_device *dev = platform_get_drvdata(pdev);\r
209 \r
210         dev->adc->is_suspended = 1;\r
211         return 0;\r
212 }\r
213 \r
214 static int rk29_adc_resume(struct platform_device *pdev)\r
215 {\r
216         struct rk29_adc_device *dev = platform_get_drvdata(pdev);\r
217 \r
218         dev->adc->is_suspended = 0;\r
219         return 0;\r
220 }\r
221 \r
222 #else\r
223 #define rk29_adc_suspend NULL\r
224 #define rk29_adc_resume NULL\r
225 #endif\r
226 \r
227 static struct platform_driver rk29_adc_driver = {\r
228         .driver         = {\r
229                 .name   = "rk29-adc",\r
230                 .owner  = THIS_MODULE,\r
231         },\r
232         .probe          = rk29_adc_probe,\r
233         .remove         = __devexit_p(rk29_adc_remove),\r
234         .suspend        = rk29_adc_suspend,\r
235         .resume         = rk29_adc_resume,\r
236 };\r
237 \r
238 static int __init rk29_adc_init(void)\r
239 {\r
240         return platform_driver_register(&rk29_adc_driver);\r
241 }\r
242 subsys_initcall(rk29_adc_init);\r
243 \r
244 static void __exit rk29_adc_exit(void)\r
245 {\r
246         platform_driver_unregister(&rk29_adc_driver);\r
247 }\r
248 module_exit(rk29_adc_exit);\r
249 \r
250 MODULE_DESCRIPTION("Driver for ADC");\r
251 MODULE_AUTHOR("kfx, kfx@rock-chips.com");\r
252 MODULE_LICENSE("GPL");\r
253 static int __init adc_test_init(void)\r
254 {\r
255 #ifdef ADC_TEST \r
256                 rk29_adc_test();\r
257 #endif\r
258         return 0;\r
259 \r
260 }\r
261 module_init(adc_test_init);\r