diff --git a/Documentation/devicetree/bindings/gnsssirf/gnss_sirf.txt b/Documentation/devicetree/bindings/gnsssirf/gnss_sirf.txt new file mode 100644 index 000000000000..18e8b251d9c5 --- /dev/null +++ b/Documentation/devicetree/bindings/gnsssirf/gnss_sirf.txt @@ -0,0 +1,47 @@ +Binding for SIRF GNSS receiver control driver +GPIO pins are toggled to control GNSS receiver power states either to +wake it from sleep or put receiver into sleep mode + +Required properties: +- compatible: must be "gnss_sirf" +- #gpio-pins: + 0: GPIO 18 + 1: GPIO 87 + +Example: + ss5_pwr_ctrl0 { + compatible = "gnss_sirf"; + pinctrl-0 = <&ss5_pwr_ctrl_rst_on>; + ssVreset-gpio = <&tlmm 87 1>; + ssVonoff-gpio = <&tlmm 18 1>; + }; + + ss5_pwr_ctrl_pins: ss5_pwr_ctrl_pins { + ss5_pwr_ctrl_rst_on: ss5_pwr_ctrl_rst_on { + mux { + pins = "gpio87", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-pull-up; + output-high; + }; + }; + + ss5_pwr_ctrl_rst_off: ss5_pwr_ctrl_off { + mux { + pins = "gpio87", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-pull-up; + output-high; + }; + }; + }; diff --git a/Documentation/gnsssirf/gnss_sirf.txt b/Documentation/gnsssirf/gnss_sirf.txt new file mode 100644 index 000000000000..77cc06a07374 --- /dev/null +++ b/Documentation/gnsssirf/gnss_sirf.txt @@ -0,0 +1,17 @@ +GNSS Driver for SiRFStar Chip +============================= + +Description: +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. + +GPIO Usage: + probe will provide GPIO pins information to driver to control GNSS power + +Device Node Creation: + A device node is will be created as /dev/gnss_sirf + +Device Node Usage: + Device node /dev/gnss_sirf can be used to control ON_OFF & RESET pins of + SiRFStar GNSS receiver using exposed IOCTLS diff --git a/drivers/Kconfig b/drivers/Kconfig index 29096a4caa44..ed96eb7d8ba2 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -71,6 +71,8 @@ source "drivers/pinctrl/Kconfig" source "drivers/gpio/Kconfig" +source "drivers/gnsssirf/Kconfig" + source "drivers/w1/Kconfig" source "drivers/power/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index f409e6ddf143..cef0160448bc 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -188,3 +188,5 @@ obj-$(CONFIG_TEE) += tee/ obj-$(CONFIG_MULTIPLEXER) += mux/ obj-$(CONFIG_SENSORS_SSC) += sensors/ obj-$(CONFIG_ESOC) += esoc/ +# GNSS driver +obj-$(CONFIG_GNSS_SIRF) += gnsssirf/ diff --git a/drivers/gnsssirf/Kconfig b/drivers/gnsssirf/Kconfig new file mode 100644 index 000000000000..559a6b62f815 --- /dev/null +++ b/drivers/gnsssirf/Kconfig @@ -0,0 +1,11 @@ +# +# SIRF GNSS receiver configuration +# + +menu "GNSS SIRF controls" +config GNSS_SIRF + bool "GNSS SIRF" + help + Driver for ports of GNSS SIRF functionality + +endmenu diff --git a/drivers/gnsssirf/Makefile b/drivers/gnsssirf/Makefile new file mode 100644 index 000000000000..e8400ec13ea2 --- /dev/null +++ b/drivers/gnsssirf/Makefile @@ -0,0 +1,3 @@ +# SIRF GNSS driver makefile. + +obj-$(CONFIG_GNSS_SIRF) += gnss_sirf.o \ No newline at end of file diff --git a/drivers/gnsssirf/gnss_sirf.c b/drivers/gnsssirf/gnss_sirf.c new file mode 100644 index 000000000000..5281cecb6f15 --- /dev/null +++ b/drivers/gnsssirf/gnss_sirf.c @@ -0,0 +1,267 @@ +/* + * + * SiRF GNSS Driver + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#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 dev_t gnssDev; +static struct cdev c_dev; +static struct class *devClass; + +static int gnss_sirf_driver_open(struct inode *inode, struct file *filp); +static ssize_t gnss_sirf_driver_read(struct file *filp, char *buf, + size_t count, loff_t *f_pos); +static ssize_t gnss_sirf_driver_write(struct file *filp, const char *buf, + size_t count, loff_t *f_pos); +static int gnss_sirf_driver_release(struct inode *inode, struct file *filp); +static long gnss_sirf_driver_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + +static int gnss_sirf_probe(struct platform_device *pdev); +static int gnss_sirf_remove(struct platform_device *pdev); + + +static const struct of_device_id gnss_sirf_match_table[] = { + { .compatible = "gnss_sirf" }, + { } +}; + +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, + .owner = THIS_MODULE +}; + +static struct platform_driver gnss_sirf_drv = { + .driver = { + .name = "gnss_sirf", + .of_match_table = gnss_sirf_match_table, + .owner = THIS_MODULE, + }, + .probe = gnss_sirf_probe, + .remove = gnss_sirf_remove, +}; + +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; + default: + break; + } + return 0; +} + + +static int gnss_sirf_init_ports(void) +{ + gpio_direction_output(resetPin, 1); + gpio_direction_output(onOffPin, 1); + return 0; +} + +static int gnss_sirf_deInit_sirf_ports(void) +{ + gpio_direction_output(resetPin, 0); + gpio_direction_output(onOffPin, 0); + return 0; +} + + +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 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_probe(struct platform_device *pdev) +{ + int ret = -ENODEV; + struct device *dev; + + dev = &pdev->dev; + dev_info(dev, "%s", __func__); + 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); + 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; + } + } + 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; + } + } + gpio_direction_output(resetPin, 1); + gpio_direction_output(onOffPin, 1); + if (gnss_sirf_init_ports() < 0) + pr_err("gnss_sirf_init_ports failed\n"); + else + ret = 0; + } + } + return ret; +} + + +static int gnss_sirf_remove(struct platform_device *pdev) +{ + 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 __init gnss_sirf_init(void) +{ + int retVal; + + retVal = platform_driver_register(&gnss_sirf_drv); + if (retVal) { + pr_err("GNSS platform driver registation 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 reciver control driver"); diff --git a/drivers/gnsssirf/gnss_sirf.h b/drivers/gnsssirf/gnss_sirf.h new file mode 100644 index 000000000000..ad87709f65d2 --- /dev/null +++ b/drivers/gnsssirf/gnss_sirf.h @@ -0,0 +1,31 @@ +/* + * + * SiRF GNSS Driver + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#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) + +#endif //_GNSS_SIRF_H_