Merge "drivers: gnss: Add SiRFStart GNSS chip power controls"

This commit is contained in:
qctecmdr 2021-05-03 18:42:37 -07:00 • committed by Gerrit - the friendly Code Review server
commit b52ffb09f0
6 changed files with 392 additions and 0 deletions

View file

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

View file

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

View file

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

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# SIRF GNSS driver makefile.
obj-$(CONFIG_GNSS_SIRF) += gnss_sirf.o

View file

@ -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 <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 <soc/qcom/boot_stats.h>
#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");

View file

@ -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 <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)
#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_