当前位置: 首页 > news >正文

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 = <1>; /* 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 <dt-bindings/pinctrl/qcom,pmic-gpio.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>#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 <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <log_util.h>#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

http://www.taodudu.cc/news/show-7669554.html

相关文章:

  • 【高通平台电源管理汇总】PMIC基础知识简介
  • 高通Pmic闪光灯代码架构
  • 功率管理集成电路(PMIC):优化电源管理的关键技术
  • Qcom 平台 pmic adc读取代码实现
  • Regulator 框架(一): PMIC /生产者 驱动接口
  • 最小相位系统与全通系统
  • winfrom界面库(CSkin)
  • VisualStudio2022添加CSkin和SunnyUI控件
  • 史上最全SpringMVC教程,从零开始带你深入♂学习(一)——SpringMVC快速入门、注解开发
  • SpringMVC教程来喽!
  • Spring 最全入门教程详解
  • uniapp 下载文件和保存到本地
  • 【HTML】点击直接下载文件
  • 前端下载文件之http链接地址
  • 【基础知识】---概率密度函数和似然函数的区别
  • 概率论考点之多维随机变量及密度函数
  • 矩阵分析与应用-06-概率密度函数01
  • 概论_第3章_二维随机变量_已知概念密度函数求分布函数
  • 机器学习|点估计-极大似然估计法(以联合密度、联合概率函数为例)| 20mins入门|概统学习笔记(二十六)
  • ppp协议总结
  • PPP协议讲解(PPP连接状态、CHAP/PAP认证、PPP报文)
  • 数据结构-二叉搜索树
  • 二叉搜索树的应用
  • Java二叉搜索树
  • 数据结构——二叉搜索树详解
  • 二叉搜索树--BinarySerachTree(BSTree)
  • LruCache和DiskLruCache
  • android 日历控件_UI界面开发工具Calendar日历插件示例合集
  • 【模式匹配】之 —— BM算法
  • 学习笔记0714----NOSQL之redis