Merge remote-tracking branch 'linux-2.6.32.y/master' into develop
[firefly-linux-kernel-4.4.55.git] / drivers / adc / plat / rk28_adc.c
1 /* drivers/adc/chips/rk28_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 \r
19 \r
20 #include "rk28_adc.h"\r
21 \r
22 //#define ADC_TEST\r
23 \r
24 struct rk28_adc_device {\r
25         int                                     irq;\r
26         void __iomem            *regs;\r
27         struct clk *            clk;\r
28         struct resource         *ioarea;\r
29         struct adc_host         *adc;\r
30 };\r
31 static void rk28_adc_start(struct adc_host *adc)\r
32 {\r
33         struct rk28_adc_device *dev  = adc_priv(adc);\r
34         int chn = adc->cur->chn;\r
35         \r
36         writel(ADC_CTRL_IRQ_ENABLE|ADC_CTRL_POWER_UP|ADC_CTRL_START|ADC_CTRL_CH(chn),\r
37                 dev->regs + ADC_CTRL);\r
38 }\r
39 static void rk28_adc_stop(struct adc_host *adc)\r
40 {\r
41         struct rk28_adc_device *dev  = adc_priv(adc);\r
42         \r
43         writel(ADC_CTRL_IRQ_STATUS, dev->regs + ADC_CTRL);\r
44 }\r
45 static int rk28_adc_read(struct adc_host *adc)\r
46 {\r
47         struct rk28_adc_device *dev  = adc_priv(adc);\r
48 \r
49         udelay(SAMPLE_RATE);\r
50         return readl(dev->regs + ADC_DATA) & ADC_DATA_MASK;\r
51 }\r
52 static irqreturn_t rk28_adc_irq(int irq, void *data)\r
53 {\r
54         struct rk28_adc_device *dev = data;\r
55         adc_core_irq_handle(dev->adc);\r
56         return IRQ_HANDLED;\r
57 }\r
58 static const struct adc_ops rk28_adc_ops = {\r
59         .start          = rk28_adc_start,\r
60         .stop           = rk28_adc_stop,\r
61         .read           = rk28_adc_read,\r
62 };\r
63 #ifdef ADC_TEST\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 int rk28_adc_test(void)\r
70 {\r
71         int sync_read = 0;\r
72         struct adc_client *client = adc_register(1, callback, NULL);\r
73 \r
74         while(1)\r
75         {\r
76                 adc_async_read(client);\r
77                 udelay(20);\r
78                 sync_read = adc_sync_read(client);\r
79                 dev_info(client->adc->dev, "[chn%d] sync_read = %d\n", client->chn, sync_read);\r
80                 udelay(20);\r
81         }\r
82         adc_unregister(client);\r
83         return 0;\r
84 }\r
85 #endif\r
86 \r
87 static int rk28_adc_probe(struct platform_device *pdev)\r
88 {\r
89         struct adc_host *adc = NULL;\r
90         struct rk28_adc_device *dev;\r
91         struct resource *res;\r
92         int ret;\r
93 \r
94         adc = adc_alloc_host(sizeof(struct rk28_adc_device), &pdev->dev);\r
95         if (!adc)\r
96                 return -ENOMEM;\r
97         mutex_init(&adc->queue_mutex);\r
98         adc->dev = &pdev->dev;\r
99         adc->is_suspended = 0;\r
100         adc->ops = &rk28_adc_ops;\r
101         dev = adc_priv(adc);\r
102         dev->adc = adc;\r
103         dev->irq = platform_get_irq(pdev, 0);\r
104         if (dev->irq <= 0) {\r
105                 dev_err(&pdev->dev, "failed to get adc irq\n");\r
106                 ret = -ENOENT;\r
107                 goto err_alloc;\r
108         }\r
109 \r
110         ret = request_irq(dev->irq, rk28_adc_irq, 0, pdev->name, dev);\r
111         if (ret < 0) {\r
112                 dev_err(&pdev->dev, "failed to attach adc irq\n");\r
113                 goto err_alloc;\r
114         }\r
115         dev->clk = clk_get(&pdev->dev, "saradc");\r
116         if (IS_ERR(dev->clk)) {\r
117                 dev_err(&pdev->dev, "failed to get adc clock\n");\r
118                 ret = PTR_ERR(dev->clk);\r
119                 goto err_irq;\r
120         }\r
121 \r
122         ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);\r
123         if(ret < 0) {\r
124                 dev_err(&pdev->dev, "failed to set adc clk\n");\r
125                 goto err_clk;\r
126         }\r
127         clk_enable(dev->clk);\r
128 \r
129         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
130         if (!res) {\r
131                 dev_err(&pdev->dev, "cannot find IO resource\n");\r
132                 ret = -ENOENT;\r
133                 goto err_clk;\r
134         }\r
135         dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1, \r
136                                                                         pdev->name);\r
137         if(dev->ioarea == NULL) {\r
138                 dev_err(&pdev->dev, "cannot request IO\n");\r
139                 ret = -ENXIO;\r
140                 goto err_clk;\r
141         }\r
142         dev->regs = ioremap(res->start, (res->end - res->start) + 1);\r
143         if (!dev->regs) {\r
144                 dev_err(&pdev->dev, "cannot map IO\n");\r
145                 ret = -ENXIO;\r
146                 goto err_ioarea;\r
147         }\r
148         platform_set_drvdata(pdev, dev);\r
149         dev_info(&pdev->dev, "rk28 adc: driver initialized\n");\r
150 #ifdef ADC_TEST \r
151         rk28_adc_test();\r
152 #endif\r
153         return 0;\r
154 // err_iomap:\r
155 //      iounmap(dev->regs);\r
156 \r
157  err_ioarea:\r
158         release_resource(dev->ioarea);\r
159         kfree(dev->ioarea);\r
160         clk_disable(dev->clk);\r
161 \r
162  err_clk:\r
163         clk_put(dev->clk);\r
164 \r
165  err_irq:\r
166         free_irq(dev->irq, dev);\r
167 \r
168  err_alloc:\r
169         adc_free_host(dev->adc);\r
170         return ret;\r
171 }\r
172 \r
173 static int rk28_adc_remove(struct platform_device *pdev)\r
174 {\r
175         struct rk28_adc_device *dev = platform_get_drvdata(pdev);\r
176 \r
177         iounmap(dev->regs);\r
178         release_resource(dev->ioarea);\r
179         kfree(dev->ioarea);\r
180         free_irq(dev->irq, dev);\r
181         clk_disable(dev->clk);\r
182         clk_put(dev->clk);\r
183         adc_free_host(dev->adc);\r
184 \r
185         return 0;\r
186 }\r
187 \r
188 #ifdef CONFIG_PM\r
189 static int rk28_adc_suspend(struct platform_device *pdev, pm_message_t state)\r
190 {\r
191         struct rk28_adc_device *dev = platform_get_drvdata(pdev);\r
192 \r
193         dev->adc->is_suspended = 1;\r
194         return 0;\r
195 }\r
196 \r
197 static int rk28_adc_resume(struct platform_device *pdev)\r
198 {\r
199         struct rk28_adc_device *dev = platform_get_drvdata(pdev);\r
200 \r
201         dev->adc->is_suspended = 0;\r
202         return 0;\r
203 }\r
204 \r
205 #else\r
206 #define rk28_adc_suspend NULL\r
207 #define rk28_adc_resume NULL\r
208 #endif\r
209 \r
210 static struct platform_driver rk28_adc_driver = {\r
211         .driver         = {\r
212                 .name   = "rk28-adc",\r
213                 .owner  = THIS_MODULE,\r
214         },\r
215         .probe          = rk28_adc_probe,\r
216         .remove         = __devexit_p(rk28_adc_remove),\r
217         .suspend        = rk28_adc_suspend,\r
218         .resume         = rk28_adc_resume,\r
219 };\r
220 \r
221 static int __init rk28_adc_init(void)\r
222 {\r
223         return platform_driver_register(&rk28_adc_driver);\r
224 }\r
225 subsys_initcall(rk28_adc_init);\r
226 \r
227 static void __exit rk28_adc_exit(void)\r
228 {\r
229         platform_driver_unregister(&rk28_adc_driver);\r
230 }\r
231 module_exit(rk28_adc_exit);\r
232 \r
233 MODULE_DESCRIPTION("Driver for ADC");\r
234 MODULE_AUTHOR("kfx, kfx@rock-chips.com");\r
235 MODULE_LICENSE("GPL");\r
236 \r