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: I96056fc860c5be66e4b5bbdfecf6b572eaae971f
Signed-off-by: Naresh Munagala <nareshm@codeaurora.org>
This commit is contained in:
Naresh Munagala 2019-06-11 16:16:24 +05:30
parent 4c16f4bdc0
commit cf8207dc2f
8 changed files with 380 additions and 0 deletions

View File

@ -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;
};
};
};

View File

@ -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

View File

@ -71,6 +71,8 @@ source "drivers/pinctrl/Kconfig"
source "drivers/gpio/Kconfig" source "drivers/gpio/Kconfig"
source "drivers/gnsssirf/Kconfig"
source "drivers/w1/Kconfig" source "drivers/w1/Kconfig"
source "drivers/power/Kconfig" source "drivers/power/Kconfig"

View File

@ -188,3 +188,5 @@ obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_MULTIPLEXER) += mux/ obj-$(CONFIG_MULTIPLEXER) += mux/
obj-$(CONFIG_SENSORS_SSC) += sensors/ obj-$(CONFIG_SENSORS_SSC) += sensors/
obj-$(CONFIG_ESOC) += esoc/ obj-$(CONFIG_ESOC) += esoc/
# GNSS driver
obj-$(CONFIG_GNSS_SIRF) += gnsssirf/

11
drivers/gnsssirf/Kconfig Normal file
View File

@ -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

View File

@ -0,0 +1,3 @@
# SIRF GNSS driver makefile.
obj-$(CONFIG_GNSS_SIRF) += gnss_sirf.o

View File

@ -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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/aio.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#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");

View File

@ -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 <linux/ioctl.h>
/* 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_