From: prabhu annabathula Date: Thu, 27 Jan 2011 02:56:13 +0000 (-0600) Subject: misc: gps_brcm4750: Adding wake up timer support for Brcm gps v17 library X-Git-Tag: firefly_0821_release~9834^2~119 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=919c384106ac107da3812ca1657421c4499b95bb;p=firefly-linux-kernel-4.4.55.git misc: gps_brcm4750: Adding wake up timer support for Brcm gps v17 library broadcom gps library will schedule the wake up timer in two cases - when a fix interval longer than 5 seconds is requested - when integrating long for very weak gps signals In these two cases brcm library will release the wakelock and schedule timer to wake up if the system goes in to deep sleep. Signed-off-by: prabhu annabathula Signed-off-by: Mike Lockwood --- diff --git a/drivers/misc/gps-gpio-brcm4750.c b/drivers/misc/gps-gpio-brcm4750.c index 0706e1cc73ac..ad05d709cf60 100755 --- a/drivers/misc/gps-gpio-brcm4750.c +++ b/drivers/misc/gps-gpio-brcm4750.c @@ -22,14 +22,104 @@ #include #include #include +#include #include #include #include +#include +#include #include #include +#include struct gps_gpio_brcm4750_platform_data *gps_gpio_data; +/* Wakeup timer state definition */ + +enum timer_state { + /* Timer is inactive */ + TIMER_INACTIVE = 0, + /* Timer is active, waitting for timeout */ + TIMER_ACTIVE, + /* Timer has timeout, has wokenup process, waiting for next poll */ + TIMER_EXPIRED, + /* Timer is unused. */ + TIMER_INVALID +}; + +static int gps_start_wakeup_timer( struct file *filp, unsigned long timer_val_msecs) +{ + ktime_t low_interval = ktime_set(timer_val_msecs/MSEC_PER_SEC, + (timer_val_msecs%MSEC_PER_SEC)*NSEC_PER_MSEC); + /* set the alarm expiry window to 500 msecs */ + ktime_t slack = ktime_set(0, 500*NSEC_PER_MSEC); + ktime_t next = ktime_add(alarm_get_elapsed_realtime(), low_interval); + /* set filp structure if it is first time timer is scheduled */ + if (filp->private_data == NULL) + { + filp->private_data = (void *)gps_gpio_data; + } + alarm_cancel(&gps_gpio_data->alarm); + gps_gpio_data->timer_status = TIMER_ACTIVE; + alarm_start_range(&gps_gpio_data->alarm, next, ktime_add(next, slack)); + return 0; +} + +static int gps_stop_wakeup_timer( struct file *filp) +{ + if (filp->private_data == NULL) + return 0; + + alarm_cancel(&gps_gpio_data->alarm); + gps_gpio_data->timer_status = TIMER_INACTIVE; + return 0; +} + +static void gps_brcm4750_alarm(struct alarm* alarm) +{ + + struct gps_gpio_brcm4750_platform_data *gps_gpio_data = + container_of(alarm, struct gps_gpio_brcm4750_platform_data, alarm); + gps_gpio_data->timer_status = TIMER_EXPIRED; + wake_lock_timeout(&gps_gpio_data->gps_brcm4750_wake, 5* HZ); + /* trigger poll wait */ + wake_up_interruptible(&(gps_gpio_data->gps_brcm4750_wq)); +} + + +static unsigned int gps_brcm_4750_poll(struct file *filp, poll_table *wait) +{ + unsigned int ret = 0; + struct gps_gpio_brcm4750_platform_data *gps_gpio_data; + /* If the timer is not present, do not permit this operation */ + if (filp->private_data == NULL) + { + return -EPERM; + } + + gps_gpio_data = (struct gps_gpio_brcm4750_platform_data *)filp->private_data; + if (gps_gpio_data->timer_status == TIMER_INVALID || + gps_gpio_data->timer_status == TIMER_INACTIVE) + { + return -EPERM; + } + + /* Check whether the timer has already expired */ + if (gps_gpio_data->timer_status == TIMER_EXPIRED) { + gps_gpio_data->timer_status = TIMER_INACTIVE; + return POLLIN; + } + /* release wake lock before poll wait */ + + wake_unlock(&gps_gpio_data->gps_brcm4750_wake); + poll_wait(filp, &(gps_gpio_data->gps_brcm4750_wq), wait); + + if (gps_gpio_data->timer_status == TIMER_EXPIRED) { + gps_gpio_data->timer_status = TIMER_INACTIVE; + ret = POLLIN; + } + return ret; +} static long gps_brcm4750_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -38,26 +128,35 @@ static long gps_brcm4750_ioctl(struct file *filp, if (cmd <= 0) return -EINVAL; - if (copy_from_user((void *) &gpio_val, (void *) arg, - sizeof(int))) - return -EFAULT; - - if (!(gpio_val == 0 || gpio_val == 1)) - return -EINVAL; - switch (cmd) { case IOC_GPS_GPIO_RESET: + if (copy_from_user((void *) &gpio_val, (void *) arg, + sizeof(int))) + return -EFAULT; + if (!(gpio_val == 0 || gpio_val == 1)) + return -EINVAL; pr_info("%s: Setting gps gpio reset pin: %d\n", - __func__, gpio_val); + __func__, gpio_val); if (gps_gpio_data->set_reset_gpio) gps_gpio_data->set_reset_gpio(gpio_val); break; case IOC_GPS_GPIO_STANDBY: + if (copy_from_user((void *) &gpio_val, (void *) arg, + sizeof(int))) + return -EFAULT; + if (!(gpio_val == 0 || gpio_val == 1)) + return -EINVAL; pr_info("%s: Setting gps gpio standby pin to: %d\n", __func__, gpio_val); if (gps_gpio_data->set_standby_gpio) gps_gpio_data->set_standby_gpio(gpio_val); break; + case IOC_GPS_START_TIMER: + gps_start_wakeup_timer(filp, (unsigned long)arg); + break; + case IOC_GPS_STOP_TIMER: + gps_stop_wakeup_timer(filp); + break; default: pr_info("%s: Invalid GPS GPIO IOCTL command\n", __func__); return -EINVAL; @@ -67,8 +166,9 @@ static long gps_brcm4750_ioctl(struct file *filp, } static const struct file_operations gps_brcm4750_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = gps_brcm4750_ioctl, + .owner = THIS_MODULE, + .unlocked_ioctl = gps_brcm4750_ioctl, + .poll = gps_brcm_4750_poll, }; static struct miscdevice gps_gpio_miscdev = { @@ -80,6 +180,12 @@ static struct miscdevice gps_gpio_miscdev = { static int gps_gpio_brcm4750_probe(struct platform_device *pdev) { gps_gpio_data = pdev->dev.platform_data; + wake_lock_init(&gps_gpio_data->gps_brcm4750_wake, WAKE_LOCK_SUSPEND, + "gps-brcm4750"); + alarm_init(&gps_gpio_data->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + gps_brcm4750_alarm); + init_waitqueue_head(&(gps_gpio_data->gps_brcm4750_wq)); + gps_gpio_data->timer_status = TIMER_INVALID; if (misc_register(&gps_gpio_miscdev)) { pr_info("%s: gps_brcm4750 misc_register failed\n", __func__); return -1; @@ -117,5 +223,5 @@ module_init(gps_gpio_brcm4750_init); module_exit(gps_gpio_brcm4750_exit); MODULE_AUTHOR("Motorola"); -MODULE_DESCRIPTION("GPS GPIO Controller for BRCM 4750"); +MODULE_DESCRIPTION("GPS GPIO Controller and wake up timer for BRCM 4750"); MODULE_LICENSE("GPL"); diff --git a/include/linux/gps-gpio-brcm4750.h b/include/linux/gps-gpio-brcm4750.h index d534ab7afe12..8b30cd7622eb 100755 --- a/include/linux/gps-gpio-brcm4750.h +++ b/include/linux/gps-gpio-brcm4750.h @@ -19,7 +19,11 @@ #ifndef _GPS_GPIO_BRCM4750_H_ #define _GPS_GPIO_BRCM4750_H_ +#include #include +#include +#include +#include #define GPS_GPIO_DRIVER_NAME "gps_brcm4750" @@ -27,12 +31,20 @@ #define IOC_GPS_GPIO_RESET _IOW(GPS_GPIO_IOCTL_BASE, 0x0, int) #define IOC_GPS_GPIO_STANDBY _IOW(GPS_GPIO_IOCTL_BASE, 0x1, int) +/* start single shot wake up timer, set the value in msecs */ +#define IOC_GPS_START_TIMER _IOW(GPS_GPIO_IOCTL_BASE, 0x2, int) +/* stop wake up timer */ +#define IOC_GPS_STOP_TIMER _IOW(GPS_GPIO_IOCTL_BASE, 0x3, int) #ifdef __KERNEL__ struct gps_gpio_brcm4750_platform_data { void (*set_reset_gpio)(unsigned int gpio_val); void (*set_standby_gpio)(unsigned int gpio_val); void (*free_gpio)(void); + struct alarm alarm; + struct wake_lock gps_brcm4750_wake; + wait_queue_head_t gps_brcm4750_wq; + int timer_status; } __attribute__ ((packed)); #endif /* __KERNEL__ */