From 72dffdb9d1851b5513f435b302b7fee62a15f329 Mon Sep 17 00:00:00 2001 From: Vijayakumar Badiger Date: Thu, 4 Feb 2021 12:04:50 -0800 Subject: [PATCH] drivers: gnss: Add SiRFStart GNSS chip power controls This is a driver to handle SiRFStar GNSS chip power controls, a device node is created to interact with driver power controls and exposes set of IOCTLs. These IOCTLs provide mechanisms to transition of GNSS receiver power state. Change-Id: Idf8ff2553736221930f4f032455692e3752176ce Signed-off-by: Vijayakumar Badiger Signed-off-by: Santoshkumar Zalake --- drivers/soc/qcom/Kconfig | 2 + drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/gnsssirf/Kconfig | 19 ++ drivers/soc/qcom/gnsssirf/Makefile | 5 + drivers/soc/qcom/gnsssirf/gnss_sirf.c | 341 ++++++++++++++++++++++++++ drivers/soc/qcom/gnsssirf/gnss_sirf.h | 23 ++ 6 files changed, 392 insertions(+) create mode 100644 drivers/soc/qcom/gnsssirf/Kconfig create mode 100644 drivers/soc/qcom/gnsssirf/Makefile create mode 100644 drivers/soc/qcom/gnsssirf/gnss_sirf.c create mode 100644 drivers/soc/qcom/gnsssirf/gnss_sirf.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 4ffdc2ad6e6b..1cb9868653d6 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -1311,4 +1311,6 @@ config DUMP_XBL_LOG cat /sys/module/xbl_log/xbl_log source "drivers/soc/qcom/icnss2/Kconfig" + +source "drivers/soc/qcom/gnsssirf/Kconfig" endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index a9f32608c1fc..9d7c22883458 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -120,3 +120,5 @@ obj-$(CONFIG_MSM_SLATECOM_INTERFACE) += slatecom_interface.o obj-$(CONFIG_QCOM_AOP_SET_DDR) += aop-set-ddr.o obj-$(CONFIG_CPU_V7) += idle-v7.o obj-$(CONFIG_DUMP_XBL_LOG) += dump_boot_log.o +# GNSS driver +obj-$(CONFIG_GNSS_SIRF) += gnsssirf/ diff --git a/drivers/soc/qcom/gnsssirf/Kconfig b/drivers/soc/qcom/gnsssirf/Kconfig new file mode 100644 index 000000000000..898dadcd837d --- /dev/null +++ b/drivers/soc/qcom/gnsssirf/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# SIRF GNSS receiver configuration +# + +menu "GNSS SIRF controls" + +config GNSS_SIRF + tristate "GNSS SIRF" + help + The GNSS SIRF driver enables SiRFStarV GNSS chipset. + + The purpose of the driver to provide location information over UART. + The location information contains position reports and Satellite info. + The Chipset is interface over UART and controlled using Power enable + and reset GPIO. To compile this driver as a module, choose M here: + the module will be called GNSS SIRF. + +endmenu diff --git a/drivers/soc/qcom/gnsssirf/Makefile b/drivers/soc/qcom/gnsssirf/Makefile new file mode 100644 index 000000000000..9bd62d802c98 --- /dev/null +++ b/drivers/soc/qcom/gnsssirf/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# SIRF GNSS driver makefile. + +obj-$(CONFIG_GNSS_SIRF) += gnss_sirf.o diff --git a/drivers/soc/qcom/gnsssirf/gnss_sirf.c b/drivers/soc/qcom/gnsssirf/gnss_sirf.c new file mode 100644 index 000000000000..1547b01a3bed --- /dev/null +++ b/drivers/soc/qcom/gnsssirf/gnss_sirf.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. +/* + * + * SiRF GNSS Driver + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "gnss_sirf.h" + +static int resetPin; +static int onOffPin; +static int bootPin; + +static dev_t gnssDev; +static struct cdev c_dev; +static struct class *devClass; + +static int configurePins(struct platform_device *pdev); + +static const struct of_device_id gnss_sirf_match_table[] = { + { .compatible = "qcom,gnss_sirf" }, + { } +}; + +static int gnss_sirf_driver_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static ssize_t gnss_sirf_driver_read(struct file *filp, + char *buf, + size_t count, + loff_t *f_pos) +{ + return 0; +} + +static ssize_t gnss_sirf_driver_write(struct file *filp, + const char *buf, + size_t count, + loff_t *f_pos) +{ + return count; +} + +static int gnss_sirf_driver_release(struct inode *inode, + struct file *filp) +{ + return 0; +} + +static long gnss_sirf_driver_ioctl(struct file *file, + unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case IO_CONTROL_SIRF_RESET_CLEAR: + gpio_direction_output(resetPin, 0); + break; + case IO_CONTROL_SIRF_RESET_SET: + gpio_direction_output(resetPin, 1); + break; + case IO_CONTROL_SIRF_ON_OFF_CLEAR: + gpio_direction_output(onOffPin, 0); + break; + case IO_CONTROL_SIRF_ON_OFF_SET: + gpio_direction_output(onOffPin, 1); + break; + case IO_CONTROL_SIRF_BOOT_CLEAR: + gpio_direction_output(bootPin, 0); + break; + case IO_CONTROL_SIRF_BOOT_SET: + gpio_direction_output(bootPin, 1); + break; + default: + break; + } + return 0; +} + +static const struct file_operations gnss_sirf_fops = { + .open = gnss_sirf_driver_open, + .read = gnss_sirf_driver_read, + .write = gnss_sirf_driver_write, + .release = gnss_sirf_driver_release, + .unlocked_ioctl = gnss_sirf_driver_ioctl, +}; + +static int gnss_sirf_init_ports(void) +{ + gpio_direction_output(resetPin, 0); + gpio_direction_output(onOffPin, 0); + gpio_direction_output(bootPin, 0); + return 0; +} + +static int gnss_sirf_deInit_sirf_ports(void) +{ + gpio_direction_output(resetPin, 0); + gpio_direction_output(onOffPin, 0); + gpio_direction_output(bootPin, 0); + return 0; +} + +static int gnss_sirf_probe(struct platform_device *pdev) +{ + int ret = -ENODEV; + struct device *dev; + char boot_marker[40]; + + dev = &pdev->dev; + if (pdev != NULL) { + if (pdev->name) { + resetPin = of_get_named_gpio(pdev->dev.of_node, + "ssVreset-gpio", 0); + onOffPin = of_get_named_gpio(pdev->dev.of_node, + "ssVonoff-gpio", 0); + bootPin = of_get_named_gpio(pdev->dev.of_node, + "ssVboot-gpio", 0); + ret = configurePins(pdev); + if (ret == 0) { + snprintf(boot_marker, sizeof(boot_marker), + "M - DRIVER GNSS Ready"); + place_marker(boot_marker); + } + } + } + dev_info(dev, "reset:%d onoff:%d boot:%d\n", + resetPin, onOffPin, bootPin); + return ret; +} + +static int gnss_sirf_delete_device(void) +{ + /* Remove Char device */ + cdev_del(&c_dev); + device_destroy(devClass, gnssDev); + class_destroy(devClass); + unregister_chrdev_region(gnssDev, 1); + return 0; +} + +static int gnss_sirf_remove(struct platform_device *pdev) +{ + struct device *dev; + + dev = &pdev->dev; + gnss_sirf_delete_device(); + + if (gnss_sirf_deInit_sirf_ports() < 0) { + pr_err("gnss_sirf_deInit_sirf_ports failed\n"); + return -ENODEV; + } + return 0; +} + +static int gnss_sirf_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct device *dev; + int ret = -ENODEV; + + dev = &pdev->dev; + gpio_free(resetPin); + ret = gpio_request_one(resetPin, 1, "ssVreset-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + resetPin, ret); + return ret; + } + gpio_direction_input(resetPin); + gpio_free(resetPin); + + gpio_free(onOffPin); + ret = gpio_request(onOffPin, "ssVonoff-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + onOffPin, ret); + return ret; + } + gpio_direction_input(onOffPin); + gpio_free(onOffPin); + + gpio_free(bootPin); + ret = gpio_request(bootPin, "ssVboot-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + bootPin, ret); + return ret; + } + gpio_direction_input(bootPin); + gpio_free(bootPin); + + return 0; +} + +static int gnss_sirf_resume(struct platform_device *pdev) +{ + struct device *dev; + + dev = &pdev->dev; + configurePins(pdev); + return 0; +} + +static struct platform_driver gnss_sirf_drv = { + .driver = { + .name = "gnss_sirf", + .of_match_table = gnss_sirf_match_table, + }, + .probe = gnss_sirf_probe, + .remove = gnss_sirf_remove, + .suspend = gnss_sirf_suspend, + .resume = gnss_sirf_resume, +}; + +static int gnss_sirf_cteate_device(void) +{ + if (alloc_chrdev_region(&gnssDev, 0, 1, "gnss_sirf") < 0) + return -ENODEV; + + devClass = class_create(THIS_MODULE, "gnssdevClass"); + if (devClass == NULL) { + unregister_chrdev_region(gnssDev, 1); + return -ENODEV; + } + + if (device_create(devClass, NULL, gnssDev, NULL, "gnss_sirf") == NULL) { + class_destroy(devClass); + unregister_chrdev_region(gnssDev, 1); + return -ENODEV; + } + + cdev_init(&c_dev, &gnss_sirf_fops); + if (cdev_add(&c_dev, gnssDev, 1) == -1) { + device_destroy(devClass, gnssDev); + class_destroy(devClass); + unregister_chrdev_region(gnssDev, 1); + return -ENODEV; + } + return 0; +} + +static int configurePins(struct platform_device *pdev) +{ + int ret = -ENODEV; + struct device *dev; + + dev = &pdev->dev; + + if (gpio_is_valid(resetPin)) { + ret = gpio_request(resetPin, "ssVreset-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + resetPin, ret); + return ret; + } + } else { + dev_info(dev, "%s resetPin not valid\n", __func__); + } + + if (gpio_is_valid(onOffPin)) { + ret = gpio_request(onOffPin, "ssVonoff-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + onOffPin, ret); + return ret; + } + } else { + dev_info(dev, "%s onOffPin not valid\n", __func__); + } + + if (gpio_is_valid(bootPin)) { + ret = gpio_request(bootPin, "ssVboot-gpio"); + if (ret < 0) { + pr_err("failed to request gpio %d: error:%d\n", + bootPin, ret); + return ret; + } + } else { + dev_info(dev, "%s bootPin not valid\n", __func__); + } + + if (gnss_sirf_init_ports() < 0) + pr_err("gnss_sirf_init_ports failed\n"); + else + ret = 0; + return ret; +} + +static int __init gnss_sirf_init(void) +{ + int retVal; + + retVal = platform_driver_register(&gnss_sirf_drv); + if (retVal) { + pr_err("GNSS platform driver registration Failed !!!!\n"); + return retVal; + } + + retVal = gnss_sirf_cteate_device(); + return retVal; +} + + +static void __exit gnss_sirf_exit(void) +{ + platform_driver_unregister(&gnss_sirf_drv); +} + + +module_init(gnss_sirf_init); +module_exit(gnss_sirf_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SIRF GNSS receiver control driver"); diff --git a/drivers/soc/qcom/gnsssirf/gnss_sirf.h b/drivers/soc/qcom/gnsssirf/gnss_sirf.h new file mode 100644 index 000000000000..8f5aac372f95 --- /dev/null +++ b/drivers/soc/qcom/gnsssirf/gnss_sirf.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. +/* + * + * SiRF GNSS Driver + * + */ + +#ifndef _GNSS_SIRF_H_ +#define _GNSS_SIRF_H_ + +#include + +/* IO Control used to interface with SiRF GNSS receiver */ +#define IO_CONTROL_SIRF_MAGIC_CODE 'Q' +#define IO_CONTROL_SIRF_RESET_CLEAR _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 0, int) +#define IO_CONTROL_SIRF_RESET_SET _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 1, int) +#define IO_CONTROL_SIRF_ON_OFF_CLEAR _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 2, int) +#define IO_CONTROL_SIRF_ON_OFF_SET _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 3, int) +#define IO_CONTROL_SIRF_BOOT_CLEAR _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 4, int) +#define IO_CONTROL_SIRF_BOOT_SET _IOW(IO_CONTROL_SIRF_MAGIC_CODE, 5, int) + +#endif //_GNSS_SIRF_H_