blob: 2a0be3ce9ada406e10cf269e1d01bccc9b2aa487 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001 /*
2 * Copyright (C) 2011-2014 MediaTek Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 * See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17/******************************************************************************
18 * Dependency
19 ******************************************************************************/
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/types.h>
24#include <linux/wait.h>
25#include <linux/slab.h>
26#include <linux/fs.h>
27#include <linux/sched/signal.h>
28#include <linux/poll.h>
29#include <linux/device.h>
30#include <linux/interrupt.h>
31#include <linux/of.h>
32#include <linux/delay.h>
33#include <linux/platform_device.h>
34#include <linux/cdev.h>
35#include <linux/errno.h>
36#include <linux/io.h>
37#include <linux/uaccess.h>
38/* #include <linux/xlog.h> */
39#include <linux/printk.h>
40#include <linux/semaphore.h>
41#include <linux/version.h>
42#include <linux/regulator/consumer.h>
43
44static int antSwitchFlag;
45static struct regulator *vmch_reg;
46
47#ifdef pr_fmt
48#undef pr_fmt
49#endif
50#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt
51
52/******************************************************************************
53 * Function Configuration
54 ******************************************************************************/
55/* #define FAKE_DATA */
56#define GPS_SUSPEND_RESUME
57#define GPS_CONFIGURABLE_RESET_DELAY
58/******************************************************************************
59 * Definition
60 ******************************************************************************/
61/* device name and major number */
62#define GPS_DEVNAME "gps"
63/******************************************************************************
64 * structure & enumeration
65 ******************************************************************************/
66enum {
67 GPS_PWRCTL_UNSUPPORTED = 0xFF,
68 GPS_PWRCTL_OFF = 0x00,
69 GPS_PWRCTL_ON = 0x01,
70 GPS_PWRCTL_RST = 0x02,
71 GPS_PWRCTL_OFF_FORCE = 0x03,
72 GPS_PWRCTL_RST_FORCE = 0x04,
73 GPS_PWRCTL_MAX = 0x05,
74};
75enum {
76 GPS_PWR_UNSUPPORTED = 0xFF,
77 GPS_PWR_RESUME = 0x00,
78 GPS_PWR_SUSPEND = 0x01,
79 GPS_PWR_MAX = 0x02,
80};
81enum {
82 GPS_STATE_UNSUPPORTED = 0xFF,
83 GPS_STATE_OFF = 0x00, /*cleanup/power off, default state */
84 GPS_STATE_INIT = 0x01, /*init */
85 GPS_STATE_START = 0x02, /*start navigating */
86 GPS_STATE_STOP = 0x03, /*stop navigating */
87 GPS_STATE_DEC_FREQ = 0x04,
88 GPS_STATE_SLEEP = 0x05,
89 GPS_STATE_MAX = 0x06,
90};
91enum {
92 GPS_PWRSAVE_UNSUPPORTED = 0xFF,
93 GPS_PWRSAVE_DEC_FREQ = 0x00,
94 GPS_PWRSAVE_SLEEP = 0x01,
95 GPS_PWRSAVE_OFF = 0x02,
96 GPS_PWRSAVE_MAX = 0x03,
97};
98/*---------------------------------------------------------------------------*/
99struct gps_data {
100 int dat_len;
101 int dat_pos;
102 char dat_buf[4096];
103 spinlock_t lock;
104 wait_queue_head_t read_wait;
105 struct semaphore sem;
106};
107/*---------------------------------------------------------------------------*/
108struct gps_sta_itm { /*gps status record */
109 unsigned char year; /*current year - 1900 */
110 unsigned char month; /*1~12 */
111 unsigned char day; /*1~31 */
112 unsigned char hour; /*0~23 */
113
114 unsigned char minute; /*0~59 */
115 unsigned char sec; /*0~59 */
116 unsigned char count; /*reborn count */
117 unsigned char reason; /*reason: 0: timeout; 1: force */
118};
119/*---------------------------------------------------------------------------*/
120struct gps_sta_obj {
121 int index;
122 struct gps_sta_itm items[32];
123};
124/*---------------------------------------------------------------------------*/
125struct gps_drv_obj {
126 unsigned char pwrctl;
127 unsigned char suspend;
128 unsigned char state;
129 unsigned char pwrsave;
130 int rdelay; /*power reset delay */
131 struct kobject *kobj;
132 struct mutex sem;
133 struct gps_sta_obj status;
134 struct mt3326_gps_hardware *hw;
135};
136/*---------------------------------------------------------------------------*/
137struct gps_dev_obj {
138 struct class *cls;
139 struct device *dev;
140 dev_t devno;
141 struct cdev chdev;
142 struct mt3326_gps_hardware *hw;
143};
144/******************************************************************************
145 * GPS driver
146 ******************************************************************************/
147#ifdef CONFIG_OF
148static void mt3303_gps_get_dts_data(void);
149#endif
150static int mt3303_power_on(struct regulator *, int state);
151static int mt3303_power_off(struct regulator *, int state);
152
153struct mt3326_gps_hardware {
154 int (*ext_power_on)(struct regulator *, int);
155 int (*ext_power_off)(struct regulator *, int);
156 struct regulator *reg_id;
157};
158
159static struct mt3326_gps_hardware mt3326_gps_hw = {
160 .ext_power_on = mt3303_power_on,
161 .ext_power_off = mt3303_power_off,
162};
163
164#define min_uV 3300000
165#define max_uV 3500000
166/******************************************************************************
167 * local variables
168 ******************************************************************************/
169static struct gps_data gps_private = { 0 };
170
171#if defined(FAKE_DATA)
172static char fake_data[] = {
173"$GPGGA,135036.000,2446.3713,N,12101.3605,E,1,5,1.61,191.1,M,15.1,M,,*51\r\n"
174"$GPGSA,A,3,22,18,14,30,31,,,,,,,,1.88,1.61,0.98*09\r\n"
175"$GPGSV,2,1,6,18,83,106,32,22,58,324,35,30,45,157,35,14,28,308,32*44\r\n"
176"$GPGSV,2,2,6,40,21,254,,31,17,237,29*42\r\n"
177"$GPRMC,135036.000,A,2446.37125,N,12101.36054,E,0.243,56.48,140109,,A*46\r\n"
178"$GPVTG,56.48,T,,M,0.243,N,0.451,K,A*07\r\n"
179};
180#endif /* FAKE_DATA */
181
182/*
183 * this should be synchronous with mnld.c
184 * enum {
185 * MNL_RESTART_NONE = 0x00, //recording the 1st of mnld
186 * MNL_RESTART_TIMEOUT_INIT = 0x01, //restart due to timeout
187 * MNL_RESTART_TIMEOUT_MONITOR = 0x02, //restart due to timeout
188 * MNL_RESTART_TIMEOUT_WAKEUP = 0x03, //restart due to timeout
189 * MNL_RESTART_TIMEOUT_TTFF = 0x04, //restart due to TTFF timeout
190 * MNL_RESTART_FORCE = 0x04, //restart due to external command
191 * };
192 */
193/*---------------------------------------------------------------------------*/
194static char *str_reason[] = {
195 "none",
196 "init",
197 "monitor",
198 "wakeup",
199 "TTFF",
200 "force",
201 "unknown"
202};
203
204/******************************************************************************
205 * Functions
206 ******************************************************************************/
207static inline void mt3326_gps_power(struct mt3326_gps_hardware *hw,
208 unsigned int on, unsigned int force)
209{
210 /*FIX ME: PM_api should provide a function to get current status */
211 static unsigned int power_on = 1;
212 int err;
213
214 pr_info("Switching GPS device %s\n", (on != 0U) ? "on" : "off");
215
216 if (hw == NULL) {
217 pr_debug("null pointer!!\n");
218 return;
219 }
220
221 if (power_on == on) {
222 pr_info("ignore power control: %d\n", on);
223 } else if (on != 0U) {
224 (void)pr_info("power on: %d\n", on);
225 /*power on */
226 if (hw->ext_power_on != NULL) {
227 err = hw->ext_power_on(hw->reg_id, 0);
228 if (err != 0)
229 (void)pr_info("ext_power_on fail\n");
230 }
231 if (hw->ext_power_on != NULL) {
232 err = hw->ext_power_on(hw->reg_id, 1);
233 if (err != 0)
234 (void)pr_info("ext_power_on fail\n");
235 }
236 mdelay(120UL);
237 } else {
238 pr_info("power off: %d\n", on);
239 if (hw->ext_power_off != NULL) {
240 err = hw->ext_power_off(hw->reg_id, force);
241 if (err != 0)
242 (void)pr_info("ext_power_off fail\n");
243 }
244 pr_info("power off ok: %d\n", on);
245 }
246 power_on = on;
247}
248
249/*****************************************************************************/
250static inline void mt3326_gps_reset(struct mt3326_gps_hardware *hw,
251 int delay, int force)
252{
253 mt3326_gps_power(hw, 1, 0);
254 mdelay((unsigned long)delay);
255 mt3326_gps_power(hw, 0, (unsigned int)force);
256 mdelay((unsigned long)delay);
257 mt3326_gps_power(hw, 1, 0);
258}
259
260/******************************************************************************/
261static inline int mt3326_gps_set_suspend(struct gps_drv_obj *obj,
262 unsigned char suspend)
263{
264 if (obj == NULL)
265 return -1;
266 mutex_lock(&obj->sem);
267 if (obj->suspend != suspend) {
268 pr_debug("issue sysfs_notify : %p\n", obj->kobj->sd);
269 sysfs_notify(obj->kobj, NULL, "suspend");
270 }
271 obj->suspend = suspend;
272 mutex_unlock(&obj->sem);
273 return 0;
274}
275
276/******************************************************************************/
277static inline int mt3326_gps_set_pwrctl(struct gps_drv_obj *obj,
278 unsigned char pwrctl)
279{
280 int err = 0;
281
282 if (obj == NULL)
283 return -1;
284 mutex_lock(&obj->sem);
285
286 if ((pwrctl == (unsigned char)GPS_PWRCTL_ON) ||
287 (pwrctl == (unsigned char)GPS_PWRCTL_OFF)) {
288 obj->pwrctl = pwrctl;
289 mt3326_gps_power(obj->hw, pwrctl, 0);
290 } else if (pwrctl == (unsigned char)GPS_PWRCTL_OFF_FORCE) {
291 obj->pwrctl = pwrctl;
292 mt3326_gps_power(obj->hw, pwrctl, 1);
293 } else if (pwrctl == (unsigned char)GPS_PWRCTL_RST) {
294 mt3326_gps_reset(obj->hw, obj->rdelay, 0);
295 obj->pwrctl = (unsigned char)GPS_PWRCTL_ON;
296 } else if (pwrctl == (unsigned char)GPS_PWRCTL_RST_FORCE) {
297 mt3326_gps_reset(obj->hw, obj->rdelay, 1);
298 obj->pwrctl = (unsigned char)GPS_PWRCTL_ON;
299 } else {
300 err = -1;
301 }
302 mutex_unlock(&obj->sem);
303 return err;
304}
305
306/******************************************************************************/
307static inline int mt3326_gps_set_status(struct gps_drv_obj *obj,
308 const char *buf, size_t count)
309{
310 int err = 0;
311 int year, mon, day, hour, minute, sec, cnt, reason, idx;
312
313 if (obj == NULL)
314 return -1;
315
316 mutex_lock(&obj->sem);
317 if (sscanf(buf, "(%d/%d/%d %d:%d:%d) - %d/%d", &year, &mon, &day,
318 &hour, &minute, &sec, &cnt, &reason) == 8) {
319 int number = (int)ARRAY_SIZE(obj->status.items);
320
321 idx = obj->status.index % number;
322 obj->status.items[idx].year = (unsigned char)year;
323 obj->status.items[idx].month = (unsigned char)mon;
324 obj->status.items[idx].day = (unsigned char)day;
325 obj->status.items[idx].hour = (unsigned char)hour;
326 obj->status.items[idx].minute = (unsigned char)minute;
327 obj->status.items[idx].sec = (unsigned char)sec;
328 obj->status.items[idx].count = (unsigned char)cnt;
329 obj->status.items[idx].reason = (unsigned char)reason;
330 obj->status.index++;
331 } else {
332 err = -1;
333 }
334 mutex_unlock(&obj->sem);
335 return err;
336}
337
338/******************************************************************************/
339static inline int mt3326_gps_set_state(struct gps_drv_obj *obj,
340 unsigned char state)
341{
342 int err = 0;
343
344 if (obj == NULL)
345 return -1;
346 mutex_lock(&obj->sem);
347 if (state < (unsigned char)GPS_STATE_MAX)
348 obj->state = state;
349 else
350 err = -1;
351 mutex_unlock(&obj->sem);
352 return err;
353}
354
355/******************************************************************************/
356static inline int mt3326_gps_set_pwrsave(struct gps_drv_obj *obj,
357 unsigned char pwrsave)
358{
359 int err = 0;
360
361 if (obj == NULL)
362 return -1;
363 mutex_lock(&obj->sem);
364 if (pwrsave < (unsigned char)GPS_PWRSAVE_MAX)
365 obj->pwrsave = pwrsave;
366 else
367 err = -1;
368 mutex_unlock(&obj->sem);
369 return err;
370}
371
372/******************************************************************************/
373static inline int mt3326_gps_dev_suspend(struct gps_drv_obj *obj)
374{
375#if defined(GPS_SUSPEND_RESUME)
376 int err;
377
378 err = mt3326_gps_set_suspend(obj, GPS_PWR_SUSPEND);
379 if (err != 0)
380 pr_debug("set suspend fail: %d\n", err);
381 err = mt3326_gps_set_pwrctl(obj, GPS_PWRCTL_OFF);
382 if (err != 0)
383 pr_debug("set pwrctl fail: %d\n", err);
384 return err;
385#endif
386}
387
388/******************************************************************************/
389static inline int mt3326_gps_dev_resume(struct gps_drv_obj *obj)
390{
391#if defined(GPS_SUSPEND_RESUME)
392 int err;
393
394 err = mt3326_gps_set_suspend(obj, GPS_PWR_RESUME);
395 if (err != 0)
396 pr_debug("set suspend fail: %d\n", err);
397 /*don't power on device automatically */
398 return err;
399#endif
400}
401
402/******************************************************************************/
403static ssize_t mt3326_show_pwrctl(struct device *dev,
404 struct device_attribute *attr, char *buf)
405{
406 struct gps_drv_obj *obj;
407 ssize_t res;
408
409 if (dev == NULL) {
410 pr_debug("dev is null!!\n");
411 return 0;
412 }
413 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
414 if (obj == NULL) {
415 pr_debug("drv data is null!!\n");
416 return 0;
417 }
418 mutex_lock(&obj->sem);
419 res = snprintf(buf, PAGE_SIZE, "%d\n", obj->pwrctl);
420 mutex_unlock(&obj->sem);
421 return res;
422}
423
424/******************************************************************************/
425static ssize_t mt3326_store_pwrctl(struct device *dev,
426 struct device_attribute *attr, const char *buf, size_t count)
427{
428 struct gps_drv_obj *obj;
429
430 if (dev == NULL) {
431 pr_debug("dev is null!!\n");
432 return 0;
433 }
434 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
435 if (obj == NULL) {
436 pr_debug("drv data is null!!\n");
437 return 0;
438 }
439 if ((count == (size_t)1) || ((count == (size_t)2)
440 && (buf[1] == '\n'))) {
441 unsigned char pwrctl = (unsigned char)(buf[0] - '0');
442
443 if (mt3326_gps_set_pwrctl(obj, pwrctl) == 0)
444 return (ssize_t)count;
445 }
446 return (ssize_t)count;
447}
448
449/******************************************************************************/
450static ssize_t mt3326_show_suspend(struct device *dev,
451 struct device_attribute *attr, char *buf)
452{
453 struct gps_drv_obj *obj;
454 ssize_t res;
455
456 if (dev == NULL) {
457 pr_debug("dev is null!!\n");
458 return 0;
459 }
460 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
461 if (obj == NULL) {
462 pr_debug("drv data is null!!\n");
463 return 0;
464 }
465 mutex_lock(&obj->sem);
466 res = snprintf(buf, PAGE_SIZE, "%d\n", obj->suspend);
467 mutex_unlock(&obj->sem);
468 return res;
469}
470
471/******************************************************************************/
472static ssize_t mt3326_store_suspend(struct device *dev,
473 struct device_attribute *attr, const char *buf, size_t count)
474{
475 struct gps_drv_obj *obj;
476
477 if (dev == NULL) {
478 pr_debug("dev is null!!\n");
479 return 0;
480 }
481 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
482 if (obj == NULL) {
483 pr_debug("drv data is null!!\n");
484 return 0;
485 }
486 if ((count == (size_t)1) || ((count == (size_t)2)
487 && (buf[1] == '\n'))) {
488 int suspend = buf[0] - '0';
489
490 if (suspend == GPS_PWR_SUSPEND) {
491 if (mt3326_gps_dev_suspend(obj) == 0)
492 return (ssize_t)count;
493 } else if (suspend == GPS_PWR_RESUME) {
494 if (mt3326_gps_dev_resume(obj) == 0)
495 return (ssize_t)count;
496 } else {
497 pr_debug("suspend value error: %d!!\n", suspend);
498 return 0;
499 }
500 }
501 return (ssize_t)count;
502}
503
504/******************************************************************************/
505static ssize_t mt3326_show_status(struct device *dev,
506 struct device_attribute *attr, char *buf)
507{
508 int res, idx, num, left, cnt, len;
509 struct gps_drv_obj *obj;
510 char *reason = NULL;
511 int reason_max = (int)ARRAY_SIZE(str_reason);
512
513 if (dev == NULL) {
514 pr_debug("dev is null!!\n");
515 return 0;
516 }
517 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
518 if (obj == NULL) {
519 pr_debug("drv data is null!!\n");
520 return 0;
521 }
522 mutex_lock(&obj->sem);
523 num = (int)ARRAY_SIZE(obj->status.items);
524 left = (int)PAGE_SIZE;
525 cnt = 0;
526 len = 0;
527 for (idx = 0; idx < num; idx++) {
528 if (obj->status.items[idx].month == 0)
529 continue;
530 if (obj->status.items[idx].reason >= reason_max)
531 reason = str_reason[reason_max - 1];
532 else
533 reason = str_reason[obj->status.items[idx].reason];
534 cnt = snprintf(&buf[len], left,
535 "[%d] %.4d/%.2d/%.2d %.2d:%.2d:%.2d - %d, %s\n",
536 idx, obj->status.items[idx].year + 1900,
537 obj->status.items[idx].month,
538 obj->status.items[idx].day,
539 obj->status.items[idx].hour,
540 obj->status.items[idx].minute,
541 obj->status.items[idx].sec,
542 obj->status.items[idx].count, reason);
543 left -= cnt;
544 len += cnt;
545 }
546 res = PAGE_SIZE - left;
547 mutex_unlock(&obj->sem);
548 return res;
549}
550
551/******************************************************************************/
552static ssize_t mt3326_store_status(struct device *dev,
553 struct device_attribute *attr, const char *buf, size_t count)
554{
555 int res = 0;
556 struct gps_drv_obj *obj;
557
558 if (dev == NULL) {
559 pr_debug("dev is null!!\n");
560 return 0;
561 }
562 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
563 if (obj == NULL) {
564 pr_debug("drv data is null!!\n");
565 return 0;
566 }
567 res = mt3326_gps_set_status(obj, buf, count);
568 if (res == 0)
569 return (ssize_t)count;
570
571 pr_debug("invalid content: '%p', length = %zu\n", buf, count);
572 return (ssize_t)count;
573}
574
575/******************************************************************************/
576static ssize_t mt3326_show_state(struct device *dev,
577 struct device_attribute *attr, char *buf)
578{
579 ssize_t res;
580 struct gps_drv_obj *obj;
581
582 if (dev == NULL) {
583 pr_debug("dev is null!!\n");
584 return 0;
585 }
586 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
587 if (obj == NULL) {
588 pr_debug("drv data is null!!\n");
589 return 0;
590 }
591 mutex_lock(&obj->sem);
592 res = snprintf(buf, PAGE_SIZE, "%d\n", obj->state);
593 mutex_unlock(&obj->sem);
594 return res;
595}
596
597/******************************************************************************/
598static ssize_t mt3326_store_state(struct device *dev,
599 struct device_attribute *attr, const char *buf, size_t count)
600{
601 struct gps_drv_obj *obj;
602
603 if (dev == NULL) {
604 pr_debug("dev is null!!\n");
605 return 0;
606 }
607 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
608 if (obj == NULL) {
609 pr_debug("drv data is null!!\n");
610 return 0;
611 }
612 if ((count == (size_t)1) || ((count == (size_t)2) &&
613 (buf[1] == '\n'))) {
614 /*To Do: dynamic change according to input */
615 unsigned char state = (unsigned char)(buf[0] - '0');
616
617 if (mt3326_gps_set_state(obj, state) == 0)
618 return (ssize_t)count;
619 }
620 pr_debug("invalid content: '%p', length = %zu\n", buf, count);
621 return (ssize_t)count;
622}
623
624/******************************************************************************/
625static ssize_t mt3326_show_pwrsave(struct device *dev,
626 struct device_attribute *attr, char *buf)
627{
628 ssize_t res;
629 struct gps_drv_obj *obj;
630
631 if (dev == NULL) {
632 pr_debug("dev is null!!\n");
633 return 0;
634 }
635 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
636 if (obj == NULL) {
637 pr_debug("drv data is null!!\n");
638 return 0;
639 }
640 mutex_lock(&obj->sem);
641 res = snprintf(buf, PAGE_SIZE, "%d\n", obj->pwrsave);
642 mutex_unlock(&obj->sem);
643 return res;
644}
645
646/******************************************************************************/
647static ssize_t mt3326_store_pwrsave(struct device *dev,
648 struct device_attribute *attr, const char *buf, size_t count)
649{
650 struct gps_drv_obj *obj;
651
652 if (dev == NULL) {
653 pr_debug("dev is null!!\n");
654 return 0;
655 }
656 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
657 if (obj == NULL) {
658 pr_debug("drv data is null!!\n");
659 return 0;
660 }
661 if ((count == (size_t)1) || ((count == (size_t)2) &&
662 (buf[1] == '\n'))) {
663 unsigned char pwrsave = (unsigned char)(buf[0] - '0');
664
665 if (mt3326_gps_set_pwrsave(obj, pwrsave) == 0)
666 return (ssize_t)count;
667 }
668 pr_debug("invalid content: '%p', length = %zu\n", buf, count);
669 return (ssize_t)count;
670}
671
672/******************************************************************************/
673#if defined(GPS_CONFIGURABLE_RESET_DELAY)
674/******************************************************************************/
675static ssize_t mt3326_show_rdelay(struct device *dev,
676 struct device_attribute *attr, char *buf)
677{
678 ssize_t res;
679 struct gps_drv_obj *obj;
680
681 if (dev == NULL) {
682 pr_debug("dev is null!!\n");
683 return 0;
684 }
685 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
686 if (obj == NULL) {
687 pr_debug("drv data is null!!\n");
688 return 0;
689 }
690 mutex_lock(&obj->sem);
691 res = snprintf(buf, PAGE_SIZE, "%d\n", obj->rdelay);
692 mutex_unlock(&obj->sem);
693 return res;
694}
695
696/******************************************************************************/
697static ssize_t mt3326_store_rdelay(struct device *dev,
698 struct device_attribute *attr, const char *buf, size_t count)
699{
700 struct gps_drv_obj *obj;
701 int rdelay;
702 unsigned long val = 0;
703
704 if (dev == NULL) {
705 pr_debug("dev is null!!\n");
706 return 0;
707 }
708 obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
709 if (obj == NULL) {
710 pr_debug("drv data is null!!\n");
711 return 0;
712 }
713 rdelay = (int)kstrtol(buf, 10, &val);
714 if (rdelay == 0 && val <= 2000) {
715 mutex_lock(&obj->sem);
716 obj->rdelay = val;
717 mutex_unlock(&obj->sem);
718 return (ssize_t)count;
719 }
720 pr_debug("invalid content: '%p', length = %zu\n", buf, count);
721 return (ssize_t)count;
722}
723
724/******************************************************************************/
725#endif
726/******************************************************************************/
727DEVICE_ATTR(pwrctl, 0664, mt3326_show_pwrctl, mt3326_store_pwrctl);
728DEVICE_ATTR(suspend, 0664, mt3326_show_suspend, mt3326_store_suspend);
729DEVICE_ATTR(status, 0664, mt3326_show_status, mt3326_store_status);
730DEVICE_ATTR(state, 0664, mt3326_show_state, mt3326_store_state);
731DEVICE_ATTR(pwrsave, 0664, mt3326_show_pwrsave, mt3326_store_pwrsave);
732#if defined(GPS_CONFIGURABLE_RESET_DELAY)
733DEVICE_ATTR(rdelay, 0664, mt3326_show_rdelay, mt3326_store_rdelay);
734#endif
735static struct device_attribute *gps_attr_list[] = {
736 &dev_attr_pwrctl,
737 &dev_attr_suspend,
738 &dev_attr_status,
739 &dev_attr_state,
740 &dev_attr_pwrsave,
741#if defined(GPS_CONFIGURABLE_RESET_DELAY)
742 &dev_attr_rdelay,
743#endif
744};
745
746/******************************************************************************/
747static int mt3326_gps_create_attr(struct device *dev)
748{
749 int idx, err = 0;
750 int num = (int)ARRAY_SIZE(gps_attr_list);
751
752 if (dev == NULL)
753 return -EINVAL;
754
755 for (idx = 0; idx < num; idx++) {
756 err = device_create_file(dev, gps_attr_list[idx]);
757 if (err != 0) {
758 pr_debug("device_create_file (%s) = %d\n",
759 gps_attr_list[idx]->attr.name, err);
760 break;
761 }
762 }
763
764 return err;
765}
766
767/******************************************************************************/
768static int mt3326_gps_delete_attr(struct device *dev)
769{
770 int idx, err = 0;
771 int num = (int)ARRAY_SIZE(gps_attr_list);
772
773 if (dev == NULL)
774 return -EINVAL;
775
776 for (idx = 0; idx < num; idx++)
777 device_remove_file(dev, gps_attr_list[idx]);
778
779 return err;
780}
781
782/******************************************************************************/
783static long mt3326_gps_unlocked_ioctl(struct file *file, unsigned int cmd,
784 unsigned long arg)
785{
786 pr_debug("%s!!\n", __func__);
787 return -ENOIOCTLCMD;
788}
789
790/******************************************************************************/
791static long mt3326_gps_compat_ioctl(struct file *file, unsigned int cmd,
792 unsigned long arg)
793{
794 long ret;
795
796 pr_debug("%s!!\n", __func__);
797 ret = mt3326_gps_unlocked_ioctl(file, cmd, arg);
798 return ret;
799}
800
801/*****************************************************************************/
802static int mt3326_gps_open(struct inode *inode, struct file *file)
803{
804 /* all files share the same buffer */
805 file->private_data = &gps_private;
806 return nonseekable_open(inode, file);
807}
808
809/*****************************************************************************/
810static int mt3326_gps_release(struct inode *inode, struct file *file)
811{
812 struct gps_data *dev = file->private_data;
813
814 if (dev != NULL)
815 file->private_data = NULL;
816
817 return 0;
818}
819
820/******************************************************************************/
821static ssize_t mt3326_gps_read(struct file *file, char __user *buf,
822 size_t count, loff_t *ppos)
823{
824 struct gps_data *dev = file->private_data;
825 ssize_t ret = 0;
826 int copy_len = 0;
827
828 if (dev == NULL)
829 return -EINVAL;
830
831 if (signal_pending(current) != 0)
832 return -ERESTARTSYS;
833
834 if (down_interruptible(&dev->sem) != 0)
835 return -ERESTARTSYS;
836
837 if (dev->dat_len == 0) { /*no data to be read */
838 up(&dev->sem);
839 /*non-block mode */
840 if ((file->f_flags &
841 (unsigned int)O_NONBLOCK) == (unsigned int)O_NONBLOCK)
842 return -EAGAIN;
843 do { /*block mode */
844 ret = wait_event_interruptible
845 (dev->read_wait, (dev->dat_len > 0));
846 if (ret == -ERESTARTSYS)
847 return -ERESTARTSYS;
848 } while (ret == 0);
849 if (down_interruptible(&dev->sem) != 0)
850 return -ERESTARTSYS;
851 }
852
853 /*data is available */
854 copy_len = (dev->dat_len < (int)count) ? (dev->dat_len) : (int)(count);
855 if (copy_to_user(buf, (dev->dat_buf + dev->dat_pos),
856 (unsigned long)copy_len) != 0UL) {
857 ret = -EFAULT;
858 } else {
859 /*pr_debug("mt3326_gps_read(%ld,%d,%d) = %d\n",
860 *count, dev->dat_pos, dev->dat_len, copy_len);
861 */
862 if (dev->dat_len > (copy_len + dev->dat_pos)) {
863 dev->dat_pos += copy_len;
864 } else {
865 dev->dat_len = 0;
866 dev->dat_pos = 0;
867 }
868 ret = copy_len;
869 }
870
871 up(&dev->sem);
872 /* pr_debug("%s return %ld bytes\n", __func__, ret); */
873 return ret;
874}
875
876/******************************************************************************/
877static ssize_t mt3326_gps_write(struct file *file, const char __user *buf,
878 size_t count, loff_t *ppos)
879{
880 struct gps_data *dev = file->private_data;
881 ssize_t ret = 0;
882 size_t copy_size = 0;
883
884 if (dev == NULL)
885 return -EINVAL;
886
887 if (count == 0UL) /*no data written */
888 return 0;
889
890 if (signal_pending(current) != 0)
891 return -ERESTARTSYS;
892
893 if (down_interruptible(&dev->sem) != 0)
894 return -ERESTARTSYS;
895
896 copy_size = (count < (size_t)4096) ? count : (size_t)4096;
897 if (copy_from_user(dev->dat_buf, buf, copy_size) != 0UL) {
898 pr_debug("copy_from_user error");
899 ret = -EFAULT;
900 } else {
901 dev->dat_len = (int)count;
902 dev->dat_pos = 0;
903 ret = (ssize_t)count;
904 }
905 up(&dev->sem);
906 wake_up_interruptible(&dev->read_wait);
907 pr_debug("%s: write %d bytes\n", __func__, dev->dat_len);
908 return ret;
909}
910
911/******************************************************************************/
912static unsigned int mt3326_gps_poll(struct file *file, poll_table *wait)
913{
914 struct gps_data *dev = file->private_data;
915 unsigned int mask = 0;
916
917 if (dev == NULL)
918 return 0;
919
920 down(&dev->sem);
921 poll_wait(file, &dev->read_wait, wait);
922 if (dev->dat_len != 0) /*readable if data is available */
923 mask = (((unsigned int)POLLIN | (unsigned int)POLLRDNORM)
924 | ((unsigned int)POLLOUT | (unsigned int)POLLWRNORM));
925 else /*always writable */
926 mask = ((unsigned int)POLLOUT | (unsigned int)POLLWRNORM);
927 up(&dev->sem);
928 pr_debug("%s: mask : 0x%X\n", __func__, mask);
929 return mask;
930}
931
932/*****************************************************************************/
933/* Kernel interface */
934static const struct file_operations mt3326_gps_fops = {
935 .owner = THIS_MODULE,
936 .unlocked_ioctl = mt3326_gps_unlocked_ioctl,
937 .compat_ioctl = mt3326_gps_compat_ioctl,
938 .open = mt3326_gps_open,
939 .read = mt3326_gps_read,
940 .write = mt3326_gps_write,
941 .release = mt3326_gps_release,
942 .poll = mt3326_gps_poll,
943};
944
945/*****************************************************************************/
946static void mt3326_gps_hw_init(struct mt3326_gps_hardware *hw)
947{
948 mt3326_gps_power(hw, 1, 0);
949}
950
951/*****************************************************************************/
952static void mt3326_gps_hw_exit(struct mt3326_gps_hardware *hw)
953{
954 mt3326_gps_power(hw, 0, 0);
955}
956
957/*****************************************************************************/
958static int mt3326_gps_probe(struct platform_device *dev)
959{
960 int ret = 0;
961 int err = 0;
962 struct gps_drv_obj *drvobj = NULL;
963 /*struct mt3326_gps_hardware *hw =
964 *(struct mt3326_gps_hardware *)dev->dev.platform_data;
965 */
966 struct mt3326_gps_hardware *hw = &mt3326_gps_hw;
967 struct gps_dev_obj *devobj = NULL;
968
969#ifdef CONFIG_OF
970 mt3303_gps_get_dts_data();
971#endif
972
973 devobj = kzalloc(sizeof(*devobj), GFP_KERNEL);
974 if (devobj == NULL) {
975 /*(void)pr_err("kzalloc fail\n");*/
976 err = -ENOMEM;
977 return -1;
978 }
979
980 pr_info("get regulator");
981#ifdef CONFIG_MTK_PMIC_CHIP_MT6356
982 hw->reg_id = regulator_get(&dev->dev, "vcn33_wifi");
983#else
984 hw->reg_id = regulator_get(&dev->dev, "vcn33");
985#endif
986 if (!hw->reg_id) {
987 pr_info("regulator_get reg_id failed.\n");
988 return -1;
989 }
990
991 pr_info("regulator_get_voltage reg_id = %d uV\n",
992 regulator_get_voltage(hw->reg_id));
993
994 /*set voltage*/
995 if (regulator_set_voltage(hw->reg_id, min_uV, max_uV)) {
996 pr_info("regulator_set_voltage reg_id failed.\n");
997 };
998
999 mt3326_gps_hw_init(hw);
1000 ret = alloc_chrdev_region(&devobj->devno, 0, 1, GPS_DEVNAME);
1001 if (ret != 0) {
1002 (void)pr_err("alloc_chrdev_region fail: %d\n", ret);
1003 goto error;
1004 } else {
1005 pr_debug("major: %d, minor: %d\n", MAJOR(devobj->devno),
1006 MINOR(devobj->devno));
1007 }
1008 cdev_init(&devobj->chdev, &mt3326_gps_fops);
1009 devobj->chdev.owner = THIS_MODULE;
1010 err = cdev_add(&devobj->chdev, devobj->devno, 1);
1011 if (err != 0) {
1012 (void)pr_err("cdev_add fail: %d\n", err);
1013 goto error;
1014 }
1015 drvobj = kmalloc(sizeof(*drvobj), GFP_KERNEL);
1016 if (drvobj == NULL) {
1017 err = -ENOMEM;
1018 goto error;
1019 }
1020 memset(drvobj, 0, sizeof(*drvobj));
1021
1022 devobj->cls = class_create(THIS_MODULE, "gpsdrv");
1023 if (IS_ERR(devobj->cls)) {
1024 (void)pr_err("Unable to create class, err = %d\n",
1025 (int)PTR_ERR(devobj->cls));
1026 goto error;
1027 }
1028 devobj->dev = device_create(devobj->cls, NULL,
1029 devobj->devno, drvobj, "gps");
1030 drvobj->hw = hw;
1031 drvobj->pwrctl = 0;
1032 drvobj->suspend = 0;
1033 drvobj->state = GPS_STATE_UNSUPPORTED;
1034 drvobj->pwrsave = GPS_PWRSAVE_UNSUPPORTED;
1035 drvobj->rdelay = 50;
1036 drvobj->kobj = &devobj->dev->kobj;
1037 mutex_init(&drvobj->sem);
1038
1039 err = mt3326_gps_create_attr(devobj->dev);
1040 if (err != 0)
1041 goto error;
1042
1043 /* initialize members */
1044 spin_lock_init(&gps_private.lock);
1045 init_waitqueue_head(&gps_private.read_wait);
1046 sema_init(&gps_private.sem, 1);
1047
1048 gps_private.dat_len = 0;
1049 gps_private.dat_pos = 0;
1050 (void)memset(gps_private.dat_buf, 0x00, sizeof(gps_private.dat_buf));
1051
1052 /* set platform data: a new device created for gps */
1053 platform_set_drvdata(dev, devobj);
1054
1055 if (antSwitchFlag) {
1056 pr_info("mt3303 get regulator");
1057 vmch_reg = regulator_get(devobj->dev, "vmch");
1058 if (!vmch_reg) {
1059 pr_info("mt3303 regulator_get vmch failed.\n");
1060 return -1;
1061 }
1062
1063 pr_info("mt3303 regulator_get_voltage reg_id = %d uV\n",
1064 regulator_get_voltage(vmch_reg));
1065 }
1066 pr_debug("Done\n");
1067
1068 return 0;
1069
1070error:
1071 if (err == 0)
1072 cdev_del(&devobj->chdev);
1073 if (ret == 0)
1074 unregister_chrdev_region(devobj->devno, 1);
1075 kfree(devobj);
1076 kfree(drvobj);
1077
1078 return -1;
1079}
1080
1081/*****************************************************************************/
1082static int mt3326_gps_remove(struct platform_device *dev)
1083{
1084 int err;
1085 struct gps_dev_obj *devobj =
1086 (struct gps_dev_obj *)platform_get_drvdata(dev);
1087 struct gps_drv_obj *drvobj;
1088
1089 if (devobj == NULL) {
1090 (void)pr_err("null pointer: %p\n", devobj);
1091 return -1;
1092 }
1093
1094 drvobj = (struct gps_drv_obj *)dev_get_drvdata(devobj->dev);
1095 if (drvobj == NULL) {
1096 (void)pr_err("null pointer: %p\n", drvobj);
1097 return -1;
1098 }
1099 pr_debug("Unregistering chardev\n");
1100
1101 cdev_del(&devobj->chdev);
1102 unregister_chrdev_region(devobj->devno, 1);
1103
1104 mt3326_gps_hw_exit(devobj->hw);
1105 err = mt3326_gps_delete_attr(devobj->dev);
1106 if (err != 0)
1107 pr_debug("delete attr fails: %d\n", err);
1108 device_destroy(devobj->cls, devobj->devno);
1109 class_destroy(devobj->cls);
1110
1111 kfree(devobj);
1112 pr_debug("Done\n");
1113 return 0;
1114}
1115
1116/*****************************************************************************/
1117static void mt3326_gps_shutdown(struct platform_device *dev)
1118{
1119 struct gps_dev_obj *devobj =
1120 (struct gps_dev_obj *)platform_get_drvdata(dev);
1121
1122 pr_debug("Shutting down\n");
1123 mt3326_gps_hw_exit(devobj->hw);
1124}
1125
1126/*****************************************************************************/
1127#ifdef CONFIG_PM
1128/*****************************************************************************/
1129static int mt3326_gps_suspend(struct platform_device *dev,
1130 pm_message_t state)
1131{
1132 int err = 0;
1133 struct gps_dev_obj *devobj =
1134 (struct gps_dev_obj *)platform_get_drvdata(dev);
1135 struct gps_drv_obj *drvobj;
1136
1137 if (devobj == NULL) {
1138 (void)pr_err("null pointer: %p\n", devobj);
1139 return -1;
1140 }
1141
1142 drvobj = (struct gps_drv_obj *)dev_get_drvdata(devobj->dev);
1143 if (drvobj == NULL) {
1144 (void)pr_err("null pointer: %p\n", drvobj);
1145 return -1;
1146 }
1147
1148 pr_debug("dev = %p, event = %u,", dev, state.event);
1149 if (state.event == PM_EVENT_SUSPEND)
1150 err = mt3326_gps_dev_suspend(drvobj);
1151 return err;
1152}
1153
1154/*****************************************************************************/
1155static int mt3326_gps_resume(struct platform_device *dev)
1156{
1157 struct gps_dev_obj *devobj =
1158 (struct gps_dev_obj *)platform_get_drvdata(dev);
1159 struct gps_drv_obj *drvobj =
1160 (struct gps_drv_obj *)dev_get_drvdata(devobj->dev);
1161
1162 return mt3326_gps_dev_resume(drvobj);
1163}
1164
1165/*****************************************************************************/
1166#endif /* CONFIG_PM */
1167/*****************************************************************************/
1168#ifdef CONFIG_OF
1169static const struct of_device_id apgps_of_ids[] = {
1170 {.compatible = "mediatek,mt3303",},
1171 {}
1172};
1173#endif
1174static struct platform_driver mt3326_gps_driver = {
1175 .probe = mt3326_gps_probe,
1176 .remove = mt3326_gps_remove,
1177 .shutdown = mt3326_gps_shutdown,
1178#if defined(CONFIG_PM)
1179 .suspend = mt3326_gps_suspend,
1180 .resume = mt3326_gps_resume,
1181#endif
1182 .driver = {
1183 .name = GPS_DEVNAME,
1184 .bus = &platform_bus_type,
1185#ifdef CONFIG_OF
1186 .of_match_table = apgps_of_ids,
1187#endif
1188 },
1189};
1190
1191#ifdef CONFIG_OF
1192static void mt3303_gps_get_dts_data(void)
1193{
1194 struct device_node *node = NULL;
1195
1196 pr_info("mt3303 before: %d", antSwitchFlag);
1197 node = of_find_matching_node(node, apgps_of_ids);
1198 if (node) {
1199 pr_info("of_property_read_u32");
1200 of_property_read_u32(node, "antSwitchFlag", &antSwitchFlag);
1201 }
1202 pr_info("mt3303 after: %d", antSwitchFlag);
1203}
1204#endif
1205
1206/*****************************************************************************/
1207static int __init mt3326_gps_mod_init(void)
1208{
1209 int ret = 0;
1210 (void)pr_info("%s", __func__);
1211 /* ret = driver_register(&mt3326_gps_driver); */
1212 ret = platform_driver_register(&mt3326_gps_driver);
1213
1214 return ret;
1215}
1216
1217/*****************************************************************************/
1218static void __exit mt3326_gps_mod_exit(void)
1219{
1220 platform_driver_unregister(&mt3326_gps_driver);
1221}
1222
1223static int mt3303_power_on(struct regulator *reg_id, int state)
1224{
1225 int ret;
1226
1227 if (antSwitchFlag && vmch_reg) {
1228 if (!regulator_is_enabled(vmch_reg)) {
1229 if (regulator_enable(vmch_reg)) {
1230 pr_info("mt3303 regulator_enable vmch failed\n");
1231 return 1;
1232 }
1233 }
1234 pr_info("mt3303 regulator_enabled vmch is %s\n",
1235 regulator_is_enabled(vmch_reg)?"enable":"non-enable");
1236 }
1237
1238 if (reg_id) {
1239 if (!regulator_is_enabled(reg_id)) {
1240 ret = regulator_enable(reg_id);
1241 if (ret) {
1242 pr_info("mt3303 regulator_enable failed\n");
1243 return 1;
1244 }
1245 }
1246 pr_info("mt3303 regulator_enabled is %s\n",
1247 regulator_is_enabled(reg_id)?"enable":"non-enable");
1248 return 0;
1249 }
1250
1251 return 1;
1252}
1253
1254static int mt3303_power_off(struct regulator *reg_id, int state)
1255{
1256 int ret;
1257
1258 if (antSwitchFlag && vmch_reg) {
1259 if (regulator_is_enabled(vmch_reg)) {
1260 if (regulator_disable(vmch_reg)) {
1261 pr_info("mt3303 regulator_disable vmch failed\n");
1262 return 1;
1263 }
1264 }
1265 pr_info("mt3303 regulator_disable vmch is %s\n",
1266 regulator_is_enabled(vmch_reg)?"enable":"non-enable");
1267 }
1268
1269 if (reg_id) {
1270 if (regulator_is_enabled(reg_id)) {
1271 ret = regulator_disable(reg_id);
1272 if (ret) {
1273 pr_info("mt3303 regulator_disable failed\n");
1274 return 1;
1275 }
1276 }
1277 pr_info("mt3303 regulator_disable is %s\n",
1278 regulator_is_enabled(reg_id)?"enable":"non-enable");
1279 return 0;
1280 }
1281
1282 return 1;
1283}
1284
1285/*****************************************************************************/
1286module_init(mt3326_gps_mod_init);
1287module_exit(mt3326_gps_mod_exit);
1288/*****************************************************************************/
1289MODULE_AUTHOR("MingHsien Hsieh <MingHsien.Hsieh@mediatek.com>");
1290MODULE_DESCRIPTION("MT3326 GPS Driver");
1291MODULE_LICENSE("GPL");