upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / gsd4t.c
1 /*
2  *  gsd4t.c (SiRFstarIV)
3  *  GPS driver for SiRFstar based chip.
4  *
5  *  Copyright (C) 2011 Samsung Electronics
6  *  Minho Ban <mhban@samsung.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/platform_device.h>
16 #include <linux/regulator/consumer.h>
17 #include <linux/mutex.h>
18 #include <linux/err.h>
19 #include <linux/slab.h>
20 #include <linux/delay.h>
21 #include <linux/rfkill.h>
22 #include <asm/mach-types.h>
23 #include <mach/gpio.h>
24 #include <plat/gpio-cfg.h>
25
26 #include "gsd4t.h"
27
28 struct gsd4t_data {
29         struct gsd4t_platform_data      *pdata;
30         struct rfkill                   *rfk;
31         bool                            in_use;
32         /* No need below if constraints is always_on */
33         struct regulator                *vdd_18;
34         struct regulator                *rtc_xi;
35 };
36
37 static int gsd4t_set_block(void *data, bool blocked)
38 {
39         struct gsd4t_data *bd = data;
40         struct gsd4t_platform_data *pdata = bd->pdata;
41
42         if (!blocked) {
43                 if (bd->in_use)
44                         return 0;
45
46                 pr_info("gsd4t on\n");
47
48                 regulator_enable(bd->vdd_18);
49                 regulator_enable(bd->rtc_xi);
50
51                 /* 
52                  * CSR(SiRF) recommends,
53                  *
54                  *  _|^^^|_100ms_|^^^^^^^^^^^^^^^ nrst
55                  *  _____________,___200ms___|^^^ onoff
56                  *
57                  */
58
59                 gpio_set_value(pdata->nrst, 1);
60                 gpio_set_value(pdata->onoff, 0);
61                 /* 
62                  * But real boot sequence should be handled by user layer
63                  * (including download firmware) so we don't need control pins
64                  * here actually.
65                  *
66                 msleep(50);
67                 gpio_set_value(pdata->nrst, 0);
68                 msleep(100);
69                 gpio_set_value(pdata->nrst, 1);
70                 msleep(200);
71                 gpio_set_value(pdata->onoff, 1);
72                  */
73
74                 bd->in_use = true;
75         } else {
76                 if (!bd->in_use)
77                         return 0;
78
79                 pr_info("gsd4t off\n");
80
81                 gpio_set_value(pdata->nrst, 0);
82
83                 regulator_disable(bd->vdd_18);
84                 regulator_disable(bd->rtc_xi);
85
86                 bd->in_use = false;
87         }
88         return 0;
89 }
90
91 static const struct rfkill_ops gsd4t_rfkill_ops = {
92         .set_block = gsd4t_set_block,
93 };
94
95 static int __devinit gsd4t_probe(struct platform_device *dev)
96 {
97         struct gsd4t_platform_data *pdata;
98         struct gsd4t_data *bd;
99         unsigned int gpio;
100         int ret = 0;
101
102         pdata = dev->dev.platform_data;
103         if (!pdata) {
104                 dev_err(&dev->dev, "No platform data.\n");
105                 return -EINVAL;
106         }
107
108         bd = kzalloc(sizeof(struct gsd4t_data), GFP_KERNEL);
109         if (!bd)
110                 return -ENOMEM;
111
112         bd->pdata = pdata;
113
114         if (gpio_is_valid(pdata->nrst)) {
115                 gpio = pdata->nrst;
116                 /* GPS_nRST is high */
117                 gpio_request(gpio, "GPS_nRST");
118                 s3c_gpio_cfgpin(gpio, S3C_GPIO_OUTPUT);
119                 gpio_direction_output(gpio, 0);
120
121                 gpio_export(gpio, 1);
122                 gpio_export_link(&dev->dev, "reset", gpio);
123         } else {
124                 dev_err(&dev->dev, "Invalid nRST pin\n");
125                 ret = -EINVAL;
126                 goto err_invalid_pin1;
127         }
128
129
130         if (gpio_is_valid(pdata->onoff)) {
131                 gpio = pdata->onoff;
132                 /* GPS_EN is low */
133                 gpio_request(gpio, "GPS_EN");
134                 s3c_gpio_cfgpin(gpio, S3C_GPIO_OUTPUT);
135                 gpio_direction_output(gpio, 0);
136
137                 gpio_export(gpio, 1);
138                 gpio_export_link(&dev->dev, "onoff", gpio);
139         } else {
140                 dev_err(&dev->dev, "Invalid GPS_EN pin\n");
141                 ret = -EINVAL;
142                 goto err_invalid_pin2;
143         }
144
145         /* Optional aiding pin */
146         if (gpio_is_valid(pdata->tsync)) {
147                 gpio = pdata->tsync;
148                 /* AP_AGPS_TSYNC is low */
149                 gpio_request(gpio, "AP_AGPS_TSYNC");
150                 s3c_gpio_cfgpin(gpio, S3C_GPIO_OUTPUT);
151                 gpio_direction_output(gpio, 0);
152
153                 gpio_export(gpio, 1);
154                 gpio_export_link(&dev->dev, "tsync", gpio);
155         } 
156
157         /* input UART pin need to set pull-up to prevent floating */
158         if (gpio_is_valid(pdata->uart_rxd))
159                 s3c_gpio_setpull(pdata->uart_rxd, S3C_GPIO_PULL_UP);
160
161         /* 
162          * Get regulators. 
163          * If always_on power, can remove below.
164          */
165         bd->rtc_xi = regulator_get(&dev->dev, "gps_clk");
166         if (IS_ERR_OR_NULL(bd->rtc_xi)) {
167                 dev_err(&dev->dev, "gps_clk regulator_get error\n");
168                 ret = -EINVAL;
169                 goto err_regulator_1;
170         }
171
172         bd->vdd_18 = regulator_get(&dev->dev, "v_gps_1.8v");
173         if (IS_ERR_OR_NULL(bd->vdd_18)) {
174                 dev_err(&dev->dev, "vdd_18 regulator_get error\n");
175                 ret = -EINVAL;
176                 goto err_regulator_2;
177         }
178
179         /* 
180          * Actually, we don't need rfkill becasue most of power sequences to be
181          * done by user level. Just leave this to know user trggers onoff so we
182          * can set pins PDN mode at suspend/resume.
183          */
184         bd->rfk = rfkill_alloc("gsd4t", &dev->dev, RFKILL_TYPE_GPS,
185                         &gsd4t_rfkill_ops, bd);
186         if (!bd->rfk) {
187                 ret = -ENOMEM;
188                 goto err_rfk_alloc;
189         }
190
191         /*
192          * rfkill.h
193          * block true   : off
194          * block false  : on
195          */
196         rfkill_init_sw_state(bd->rfk, true);
197         bd->in_use = false;
198
199         ret = rfkill_register(bd->rfk);
200         if (ret)
201                 goto err_rfkill;
202
203         platform_set_drvdata(dev, bd);
204
205         dev_info(&dev->dev, "ready\n");
206
207         return 0;
208
209 err_rfkill:
210         rfkill_destroy(bd->rfk);
211 err_rfk_alloc:
212         regulator_put(bd->vdd_18);
213 err_regulator_2:
214         regulator_put(bd->rtc_xi);
215 err_regulator_1:
216         gpio_unexport(pdata->tsync);
217         gpio_unexport(pdata->onoff);
218 err_invalid_pin2:
219         gpio_unexport(pdata->nrst);
220 err_invalid_pin1:
221         kfree(bd);
222         return ret;
223 }
224
225 static int __devexit gsd4t_remove(struct platform_device *dev)
226 {
227         struct gsd4t_data *bd = platform_get_drvdata(dev);
228         struct gsd4t_platform_data *pdata = bd->pdata;
229
230         if (bd->in_use)
231                 rfkill_init_sw_state(bd->rfk, true);
232
233         rfkill_unregister(bd->rfk);
234         rfkill_destroy(bd->rfk);
235         gpio_unexport(pdata->onoff);
236         gpio_unexport(pdata->nrst);
237         gpio_unexport(pdata->tsync);
238         gpio_free(pdata->onoff);
239         gpio_free(pdata->nrst);
240
241         regulator_put(bd->vdd_18);
242         regulator_put(bd->rtc_xi);
243
244         kfree(bd);
245         platform_set_drvdata(dev, NULL);
246
247         return 0;
248 }
249
250 #ifdef CONFIG_PM
251 static int gsd4t_suspend(struct platform_device *dev, pm_message_t stata)
252 {
253         struct gsd4t_data *bd = platform_get_drvdata(dev);
254         struct gsd4t_platform_data *pdata = bd->pdata;
255
256         if (bd->in_use)
257                 s5p_gpio_set_pdn_config(pdata->nrst, S3C_GPIO_PDNCFG_OUTPUT1);
258         else
259                 s5p_gpio_set_pdn_config(pdata->nrst, S3C_GPIO_PDNCFG_OUTPUT0);
260
261         return 0;
262 }
263
264 static int gsd4t_resume(struct platform_device *dev)
265 {
266         return 0;
267 }
268 #else
269 #define gsd4t_suspend           NULL
270 #define gsd4t_resume            NULL
271 #endif
272
273 static struct platform_driver gsd4t_driver = {
274         .probe          = gsd4t_probe,
275         .remove         = __devexit_p(gsd4t_remove),
276         .suspend        = gsd4t_suspend,
277         .resume         = gsd4t_resume,
278         .driver = {
279                 .name   = "gsd4t",
280         },
281 };
282
283 static int __init gsd4t_init(void)
284 {
285         return platform_driver_register(&gsd4t_driver);
286 }
287
288 static void __exit gsd4t_exit(void)
289 {
290         platform_driver_unregister(&gsd4t_driver);
291 }
292
293 module_init(gsd4t_init);
294 module_exit(gsd4t_exit);
295
296 MODULE_AUTHOR("Minho Ban <mhban@samsung.com>");
297 MODULE_DESCRIPTION("GSD4T GPS driver");
298 MODULE_LICENSE("GPL");