camera: rockchip: camsys version 0.0x21.0xb
[firefly-linux-kernel-4.4.55.git] / drivers / misc / gps / rk29_gps.c
1 #include <linux/input.h>\r
2 #include <linux/module.h>\r
3 #include <linux/init.h>\r
4 #include <linux/interrupt.h>\r
5 #include <linux/kernel.h>\r
6 #include <linux/fcntl.h>\r
7 #include <linux/delay.h>\r
8 #include <linux/device.h>\r
9 #include <linux/miscdevice.h>\r
10 #include <asm/types.h>\r
11 #include <mach/gpio.h>\r
12 #include <mach/iomux.h>\r
13 #include <linux/platform_device.h>\r
14 #include <asm/uaccess.h>\r
15 #include <linux/wait.h>\r
16 #include "rk29_gps.h"\r
17 #if 0\r
18 #define DBG(x...)       printk(KERN_INFO x)\r
19 #else\r
20 #define DBG(x...)\r
21 #endif\r
22 \r
23 #define ENABLE  1\r
24 #define DISABLE 0\r
25 \r
26 static struct rk29_gps_data *pgps;\r
27 \r
28 static int rk29_gps_uart_to_gpio(int uart_id)\r
29 {\r
30         if(uart_id == 3) {\r
31                 rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_GPIO2B3);                       \r
32                 rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_GPIO2B2);                \r
33 \r
34                 gpio_request(RK29_PIN2_PB3, NULL);\r
35                 gpio_request(RK29_PIN2_PB2, NULL);\r
36 \r
37                 gpio_pull_updown(RK29_PIN2_PB3, PullDisable);\r
38                 gpio_pull_updown(RK29_PIN2_PB2, PullDisable);\r
39 \r
40                 gpio_direction_output(RK29_PIN2_PB3, GPIO_LOW);\r
41                 gpio_direction_output(RK29_PIN2_PB2, GPIO_LOW);\r
42 \r
43                 gpio_free(RK29_PIN2_PB3);\r
44                 gpio_free(RK29_PIN2_PB2);\r
45         }\r
46         else if(uart_id == 2) {\r
47                 rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_GPIO2B1);                       \r
48                 rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_GPIO2B0);                \r
49 \r
50                 gpio_request(RK29_PIN2_PB1, NULL);\r
51                 gpio_request(RK29_PIN2_PB0, NULL);\r
52 \r
53                 gpio_direction_output(RK29_PIN2_PB1, GPIO_LOW);\r
54                 gpio_direction_output(RK29_PIN2_PB0, GPIO_LOW);\r
55         }\r
56         else if(uart_id == 1) {\r
57                 rk29_mux_api_set(GPIO2A5_UART1SOUT_NAME, GPIO2L_GPIO2A5);                       \r
58                 rk29_mux_api_set(GPIO2A4_UART1SIN_NAME, GPIO2L_GPIO2A4);                \r
59 \r
60                 gpio_request(RK29_PIN2_PA5, NULL);\r
61                 gpio_request(RK29_PIN2_PA4, NULL);\r
62 \r
63                 gpio_direction_output(RK29_PIN2_PA5, GPIO_LOW);\r
64                 gpio_direction_output(RK29_PIN2_PA4, GPIO_LOW);\r
65         }\r
66         else {\r
67                 //to do\r
68         }\r
69 \r
70         return 0;\r
71 }\r
72 \r
73 static int rk29_gps_gpio_to_uart(int uart_id)\r
74 {\r
75         if(uart_id == 3) {\r
76                 rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_UART3_SOUT);\r
77                 rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_UART3_SIN); \r
78 \r
79                 gpio_request(RK29_PIN2_PB3, NULL);\r
80                 gpio_request(RK29_PIN2_PB2, NULL);\r
81 \r
82                 gpio_direction_output(RK29_PIN2_PB3, GPIO_HIGH);\r
83                 gpio_direction_output(RK29_PIN2_PB2, GPIO_HIGH);\r
84         }\r
85         else if(uart_id == 2) {\r
86                 rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_UART2_SOUT);                    \r
87                 rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_UART2_SIN);              \r
88 \r
89                 gpio_request(RK29_PIN2_PB1, NULL);\r
90                 gpio_request(RK29_PIN2_PB0, NULL);\r
91 \r
92                 gpio_direction_output(RK29_PIN2_PB1, GPIO_HIGH);\r
93                 gpio_direction_output(RK29_PIN2_PB0, GPIO_HIGH);\r
94         }\r
95         else if(uart_id == 1) {\r
96                 rk29_mux_api_set(GPIO2A5_UART1SOUT_NAME, GPIO2L_UART1_SOUT);                    \r
97                 rk29_mux_api_set(GPIO2A4_UART1SIN_NAME, GPIO2L_UART1_SIN);              \r
98 \r
99                 gpio_request(RK29_PIN2_PA5, NULL);\r
100                 gpio_request(RK29_PIN2_PA4, NULL);\r
101 \r
102                 gpio_direction_output(RK29_PIN2_PA5, GPIO_HIGH);\r
103                 gpio_direction_output(RK29_PIN2_PA4, GPIO_HIGH);\r
104         }\r
105         else {\r
106                 //to do\r
107         }\r
108 \r
109         return 0;\r
110 \r
111 }\r
112 \r
113 static int rk29_gps_suspend(struct platform_device *pdev,  pm_message_t state)\r
114 {\r
115         struct rk29_gps_data *pdata = pdev->dev.platform_data;\r
116 \r
117         if(!pdata) {\r
118                 printk("%s: pdata = NULL ...... \n", __func__);\r
119                 return -1;\r
120         }\r
121                 \r
122         if(pdata->power_flag == 1)\r
123         {\r
124                 rk29_gps_uart_to_gpio(pdata->uart_id);\r
125                 pdata->power_down();    \r
126                 pdata->reset(GPIO_LOW);\r
127         }\r
128         \r
129         printk("%s\n",__FUNCTION__);\r
130         return 0;       \r
131 }\r
132 \r
133 static int rk29_gps_resume(struct platform_device *pdev)\r
134 {\r
135         struct rk29_gps_data *pdata = pdev->dev.platform_data;\r
136 \r
137         if(!pdata) {\r
138                 printk("%s: pdata = NULL ...... \n", __func__);\r
139                 return -1;\r
140         }\r
141         \r
142         if(pdata->power_flag == 1)\r
143         {\r
144                 queue_work(pdata->wq, &pdata->work);\r
145         }\r
146         \r
147         printk("%s\n",__FUNCTION__);\r
148         return 0;\r
149 }\r
150 \r
151 static void rk29_gps_delay_power_downup(struct work_struct *work)\r
152 {\r
153         struct rk29_gps_data *pdata = container_of(work, struct rk29_gps_data, work);\r
154         if (pdata == NULL) {\r
155                 printk("%s: pdata = NULL\n", __func__);\r
156                 return;\r
157         }\r
158 \r
159         //DBG("%s: suspend=%d\n", __func__, pdata->suspend);\r
160 \r
161         down(&pdata->power_sem);\r
162         \r
163         pdata->reset(GPIO_LOW);\r
164         mdelay(5);\r
165         pdata->power_up();\r
166         msleep(500);\r
167         pdata->reset(GPIO_HIGH);\r
168         rk29_gps_gpio_to_uart(pdata->uart_id);\r
169 \r
170         up(&pdata->power_sem);\r
171 }\r
172 \r
173 static int rk29_gps_open(struct inode *inode, struct file *filp)\r
174 {\r
175     DBG("rk29_gps_open\n");\r
176 \r
177         return 0;\r
178 }\r
179 \r
180 static ssize_t rk29_gps_read(struct file *filp, char __user *ptr, size_t size, loff_t *pos)\r
181 {\r
182         if (ptr == NULL)\r
183                 printk("%s: user space address is NULL\n", __func__);\r
184 \r
185         if (pgps == NULL) {\r
186                 printk("%s: pgps addr is NULL\n", __func__);\r
187                 return -1;\r
188         }\r
189 \r
190         put_user(pgps->uart_id, ptr);\r
191         \r
192         return sizeof(int);\r
193 }\r
194 \r
195 static long rk29_gps_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)\r
196 {\r
197         long ret = 0;\r
198         struct rk29_gps_data *pdata = pgps;\r
199 \r
200         DBG("rk29_gps_ioctl: cmd = %d arg = %ld\n",cmd, arg);\r
201 \r
202         ret = down_interruptible(&pdata->power_sem);\r
203         if (ret < 0) {\r
204                 printk("%s: down power_sem error ret = %ld\n", __func__, ret);\r
205                 return ret;\r
206         }\r
207 \r
208         switch (cmd){\r
209                 case ENABLE:\r
210                         pdata->reset(GPIO_LOW);\r
211                         mdelay(5);\r
212                         pdata->power_up();\r
213                         mdelay(5);\r
214                         rk29_gps_gpio_to_uart(pdata->uart_id);\r
215                         mdelay(500);\r
216                         pdata->reset(GPIO_HIGH);\r
217                         pdata->power_flag = 1;\r
218                         break;\r
219                         \r
220                 case DISABLE:\r
221                         rk29_gps_uart_to_gpio(pdata->uart_id);\r
222                         pdata->power_down();\r
223                         pdata->reset(GPIO_LOW);\r
224                         pdata->power_flag = 0;\r
225                         break;\r
226 \r
227                 default:\r
228                         printk("unknown ioctl cmd!\n");\r
229                         up(&pdata->power_sem);\r
230                         ret = -EINVAL;\r
231                         break;\r
232         }\r
233 \r
234         up(&pdata->power_sem);\r
235 \r
236         return ret;\r
237 }\r
238 \r
239 \r
240 static int rk29_gps_release(struct inode *inode, struct file *filp)\r
241 {\r
242     DBG("rk29_gps_release\n");\r
243     \r
244         return 0;\r
245 }\r
246 \r
247 static struct file_operations rk29_gps_fops = {\r
248         .owner   = THIS_MODULE,\r
249         .open    = rk29_gps_open,\r
250         .read    = rk29_gps_read,\r
251         .unlocked_ioctl   = rk29_gps_ioctl,\r
252         .release = rk29_gps_release,\r
253 };\r
254 \r
255 static struct miscdevice rk29_gps_dev = \r
256 {\r
257     .minor = MISC_DYNAMIC_MINOR,\r
258     .name = "rk29_gps",\r
259     .fops = &rk29_gps_fops,\r
260 };\r
261 \r
262 static int rk29_gps_probe(struct platform_device *pdev)\r
263 {\r
264         int ret = 0;\r
265         struct rk29_gps_data *pdata = pdev->dev.platform_data;\r
266         if(!pdata)\r
267                 return -1;\r
268                 \r
269         ret = misc_register(&rk29_gps_dev);\r
270         if (ret < 0){\r
271                 printk("rk29 gps register err!\n");\r
272                 return ret;\r
273         }\r
274         \r
275         sema_init(&pdata->power_sem,1);\r
276         pdata->wq = create_freezable_workqueue("rk29_gps");\r
277         INIT_WORK(&pdata->work, rk29_gps_delay_power_downup);\r
278         pdata->power_flag = 0;\r
279 \r
280         //gps power down\r
281         rk29_gps_uart_to_gpio(pdata->uart_id);\r
282         if (pdata->power_down)\r
283                 pdata->power_down();\r
284         if (pdata->reset)\r
285                 pdata->reset(GPIO_LOW);\r
286 \r
287         pgps = pdata;\r
288 \r
289 \r
290         printk("%s:rk29 GPS initialized\n",__FUNCTION__);\r
291 \r
292         return ret;\r
293 }\r
294 \r
295 static int rk29_gps_remove(struct platform_device *pdev)\r
296 {\r
297         struct rk29_gps_data *pdata = pdev->dev.platform_data;\r
298         if(!pdata)\r
299                 return -1;\r
300 \r
301         misc_deregister(&rk29_gps_dev);\r
302         destroy_workqueue(pdata->wq);\r
303 \r
304         return 0;\r
305 }\r
306 \r
307 static struct platform_driver rk29_gps_driver = {\r
308         .probe  = rk29_gps_probe,\r
309         .remove = rk29_gps_remove,\r
310         .suspend        = rk29_gps_suspend,\r
311         .resume         = rk29_gps_resume,\r
312         .driver = {\r
313                 .name   = "rk29_gps",\r
314                 .owner  = THIS_MODULE,\r
315         },\r
316 };\r
317 \r
318 static int __init rk29_gps_init(void)\r
319 {\r
320         return platform_driver_register(&rk29_gps_driver);\r
321 }\r
322 \r
323 static void __exit rk29_gps_exit(void)\r
324 {\r
325         platform_driver_unregister(&rk29_gps_driver);\r
326 }\r
327 \r
328 module_init(rk29_gps_init);\r
329 module_exit(rk29_gps_exit);\r
330 MODULE_DESCRIPTION ("rk29 gps driver");\r
331 MODULE_LICENSE("GPL");\r
332 \r