Android实现在用户空间拉高拉低PMIC GPIO

0、需求:

基于高通SM8550,在GNSS定位过程中,将PM8550 GPIO9管脚拉高至1.8V(用于驱动有源天线),定位结束后拉低。

PM8550相关文档可以参考高通的“80-35348-100 SM8550 PMIC Software User Guide”。

1、debug

在实现前,下面的手段是可以实现拉高pm8550 gpio9至1.8V的。拉高后可以搜到卫星,有源天线进入工作状态。

adb root
adb shell
cd d/regmap/0-01
echo 1 > count
echo 0x9040 > address
echo 0x01 > data
echo 0x9041 > address
echo 0x01 > data
echo 0x9042 > address
echo 0x05 > data
echo 0x9044 > address
# 00 output low, 0x80 output high
echo 0x80 > data
echo 0x9046 > address
echo 0x80 > data
exit

下面从软件层面去实现。

1、配置device tree

首先按照高通文档(8.3.5#Configuration examples),配置如下的dts。

在kernel_platform/qcom/proprietary/devicetree/qcom下找到该机型的dtsi。

&soc {
// ......gnss_ant_en {compatible = "qcom,gpio-en";pinctrl-names = "default";pinctrl-0 = <&gnss_ant_default>;ant-gpios = <&pm8550_gpios 9 GPIO_ACTIVE_LOW>;};
};&pm8550_gpios {gnss_ant {gnss_ant_default: gnss_ant_default {pins = "gpio9"; /* GPIO 9 */function = "normal"; /* normal output */power-source = 

; /* VIN1 */output-low; /* digital output, no invert */input-disable; /* prevent GPIO from being set to DIO */};}; };

配置后效果如何呢?

在/sys/firmware/devicetree/base/soc树节点下,可以查找到gnss_ant_en节点。

cat name
#gnss_ant_encat cat pinctrl-names
#default

2、新增驱动

新增一个驱动,用于控制该gpio的高低。由于与gnss功能相关,我们将它放在kernel_platform/msm-kernel/drivers/gnss下。

新增一个文件pm8550_gpio9_out.c,用于实现驱动。

2.1 Makefile改动

修改Makefile,新增如下,模块名为:gnss-qcom-pm8550-gpio9-out,依赖pm8550_gpio9_out.o。

obj-$(CONFIG_GNSS_QCOM_PM8550_GPIO9_OUT)			+= gnss-qcom-pm8550-gpio9-out.o
gnss-qcom-pm8550-gpio9-out-y := pm8550_gpio9_out.o

2.2 Kconfig改动

在Kconfig中增加该config说明。

config GNSS_QCOM_PM8550_GPIO9_OUTtristate "GNSS QCOM PM8550 GPIO9 OUT"helpSay Y here if you need to config pm8550 gpio9 as driver-controllabledigital output HIGH or LOW.To compile this driver as a module, choose M here: the module willbe called.If unsure or no need, say N.

2.3 加入编译

为了能够在所有的版本中都能有该可加载模块,在kernel_platform/msm-kernel/arch/arm64/configs/vendor/xxx_GKI.config中配置该CONFIG。

CONFIG_GNSS_QCOM_PM8550_GPIO9_OUT=m

2.4 驱动实现

本方案中使用字符设备的ioctl来实现gpio的驱动。

// SPDX-License-Identifier: GPL-2.0#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include #define DEV_NAME "gnss_ant_en"static dev_t dev_id;
static struct cdev *gnss_ant_dev;
static struct class *gnss_ant_class;static int gnss_ant_open(struct inode *inode, struct file *file)
{printk("%s enter\n", __func__);// TODOreturn 0;
}static int gnss_ant_release(struct inode *inode, struct file *file)
{printk("%s enter\n", __func__);// TODOreturn 0;
}static void setGpio9Output(int val) {int gpio9_out;struct device_node *node;printk("%s enter. val=%d\n", __func__, val);/* 获取设备树节点的引用 */node = of_find_node_opts_by_path("/soc/gnss_ant_en", NULL);if (node == NULL) {printk("%s, Failed to find device tree node\n", __func__);return;}gpio9_out = of_get_named_gpio(node, "ant-gpios", 0);gpio_request(gpio9_out, "GPIO9");gpio_direction_output(gpio9_out, val); //1:Output HIGH;0:Output LOW
}static long gnss_ant_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{printk("%s enter\n", __func__);switch (cmd) {case _IOW('k', 0, int):setGpio9Output(0);break;case _IOW('k', 1, int):setGpio9Output(1);break;default:break;}return 0;
}static const struct file_operations gnss_ant_fops = {.owner		= THIS_MODULE,.open		= gnss_ant_open,.release	= gnss_ant_release,.unlocked_ioctl = gnss_ant_ioctl,
};static int __init gnss_ant_init(void)
{printk("%s enter\n", __func__);/* 申请设备号 */alloc_chrdev_region(&dev_id, 1, 1, DEV_NAME);/* 分配字符设备 */gnss_ant_dev = cdev_alloc();/* 设置字符设备 */cdev_init(gnss_ant_dev, &gnss_ant_fops);/* 注册字符设备 */cdev_add(gnss_ant_dev, dev_id, 1);/* 打印申请到的主次设备号 */printk("major:%d; minor:%d\n", MAJOR(dev_id), MINOR(dev_id));gnss_ant_class = class_create(THIS_MODULE, DEV_NAME);device_create(gnss_ant_class, NULL, dev_id, NULL, DEV_NAME);return 0;
}
module_init(gnss_ant_init);static void __exit gnss_ant_exit(void)
{printk("gnss_ant_exit\n");device_destroy(gnss_ant_class, dev_id);class_destroy(gnss_ant_class);cdev_del(gnss_ant_dev);kfree(gnss_ant_dev);unregister_chrdev_region(dev_id, 1);
}
module_exit(gnss_ant_exit);MODULE_AUTHOR("阅后即奋");
MODULE_DESCRIPTION("QCOM GNSS PM8550 GPIO9 Enabler");
MODULE_LICENSE("GPL v2");

ioctl的参数cmd,魔数就选定'k',基数0表示拉低,基数1表示拉高。setGpio9Output函数也没有去润色,只是先实现个功能,可自行补充其他的check。

一开始使用of_find_node_by_name(NULL, "gnss_ant_en")函数去获取device_node,返回的是NULL,所以改成了node = of_find_node_opts_by_path("/soc/gnss_ant_en", NULL)去获取设备树节点的引用。

设备开机后,可加载模块被modprobe自动加载,字符设备创建成功。由于是动态创建的,所以主设备号可能每次开机后都不一样。

[    8.740527] gnss_ant_init
[    8.740559] major:488; minor:1

adb shell cat /proc/devices后,可以在看到:

Character devices:

......

488 gnss_ant_en

......

在/dev/下也能看到字符设备gnss_ant_en

crw------- 1 root root 488,   1 1970-01-02 22:59 gnss_ant_en

3、用户空间控制字符设备

编译部分就不写了。下面给出在用户空间控制字符设备"/dev/gnss_ant_en"的sample code。

#include 
#include 
#include  
#include 
#include 
#include 
#include #ifdef LOG_NDEBUG
#undef LOG_NDEBUG
#endif
#define LOG_NDEBUG 0
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "PM8550_GPIO9_EN"
#ifdef LOGD
#undef LOGD
#endif
#define LOGI(...) ALOGI(__VA_ARGS__)
#define LOGE(...) ALOGE(__VA_ARGS__)#define DEV_NAME "/dev/gnss_ant_en"int pm8550_gpio9_ioctl(int cmd) {int fd;int ret;fd = open(DEV_NAME, O_RDWR);if (fd < 0) {LOGE("open device %s failed, return %d", DEV_NAME, fd);return -1;}ret = ioctl(fd, _IOW('k', cmd, int));LOGI("ioctl %s, return %d", DEV_NAME, ret);close(fd);return ret;
}

然后在开始定位的函数LocApiV02::startTimeBasedTracking中调用pm8550_gpio9_ioctl(1),在结束定位的函数LocApiV02::stopTimeBasedTracking中调用pm8550_gpio9_ioctl(0)即可。

日志打印如下:

开始定位:

[  710.940557] gnss_ant_open enter
[  710.940576] gnss_ant_ioctl enter
[  710.940578] setGpio9Output enter. val=1
[  710.941423] gnss_ant_release enter

结束定位:

[  726.021958] gnss_ant_open enter
[  726.021980] gnss_ant_ioctl enter
[  726.021982] setGpio9Output enter. val=0
[  726.022581] gnss_ant_release enter

验证:

adb root
adb shell
cd /d/regmap/0-01
# 开始定位
echo 0x9044 > address
cat data
# 打印9044: 80# 结束定位
cat data
# 打印9044: 00


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部