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