技术标签: # GPIO mtk android linux 嵌入式 gpio
MTK平台的GPIO配置,通过“DrvGen”工具和“codegen.dws”文件实现,在“preloader”,“lk”,“kernel”里面,都有对应的“DrvGen”工具和“codegen.dws”文件。具体每个部分编译的时候使用的工具和文件的目录,可以参考每一个部分的编译脚本“drvgen.mk”:
DRVGEN_TOOL := $(PWD)/tools/dct/DrvGen
DRVGEN_PATH := drivers/misc/mediatek/mach/$(MTK_PLATFORM)/$(MTK_PROJECT)/dct/$(PRIVATE_CUSTOM_KERNEL_DCT)
DWS_FILE := $(PWD)/$(DRVGEN_PATH)/codegen.dws
以“kernel”为例,
“DrvGen”工具在目录:kernel-3.10\tools\dct
“codegen.dws”文件在目录:kernel-3.10\drivers\misc\mediatek\mach\platform\project\dct\dct
使用“DrvGen”打开“codegen.dws”进行编辑,会出现如下图界面:
在上面界面可以做各种GPIO的配置,比如是否是中断管脚“EintMode”;对应管脚的功能“M0~M7”,默认“M0”是GPIO功能;管脚方向,是否上拉等。最后有一个“VarName1”,这实际是给GPIO命了一个名字,这里有下拉框,可以选择不同的名字,如下图:
可以根据管脚的功能,选择对应的名字,如果需要自定义名字,可以修改“DrvGen”工具目录下的“GPIO_YuSu.cmp”文件,新增自定义名字进去,然后在上图的下拉框就可以找到新增的名字了。
这个名字,在编译的时候,解析完“codegen.dws”文件之后,会在“cust_gpio_usage.h”文件生成用这个名字命名的一系列宏,如下:
#define GPIO_CTP_EINT_PIN (GPIO4 | 0x80000000)
#define GPIO_CTP_EINT_PIN_M_EINT GPIO_MODE_00
#define GPIO_CTP_EINT_PIN_M_GPIO GPIO_MODE_00
#define GPIO_CTP_EINT_PIN_M_CLK GPIO_MODE_01
#define GPIO_CTP_EINT_PIN_CLK CLK_OUT2
#define GPIO_CTP_EINT_PIN_FREQ GPIO_CLKSRC_NONE
后面在代码里面控制GPIO就可以使用这些宏,代码需要包含如下头文件:
#include <mach/mt_gpio.h>
上面说的“cust_gpio_usage.h”文件,编译的时候会自动在out目录下生成一份,还有一份在“codegen.dws”文件所在的目录,一般需要在配置完GPIO之后,点击如下按钮手动生成:
以上就是GPIO的配置部分。
在代码里面控制GPIO,需要先包含头文件:
#include <mach/mt_gpio.h>
这个头文件里面有下面一些控制函数:
/******************************************************************************
* GPIO Driver interface
******************************************************************************/
/*direction*/
int mt_set_gpio_dir(unsigned long pin, unsigned long dir);
int mt_get_gpio_dir(unsigned long pin);
/*pull enable*/
int mt_set_gpio_pull_enable(unsigned long pin, unsigned long enable);
int mt_get_gpio_pull_enable(unsigned long pin);
/*schmitt trigger*/
int mt_set_gpio_smt(unsigned long pin, unsigned long enable);
int mt_get_gpio_smt(unsigned long pin);
/*IES*/
int mt_set_gpio_ies(unsigned long pin, unsigned long enable);
int mt_get_gpio_ies(unsigned long pin);
/*pull select*/
int mt_set_gpio_pull_select(unsigned long pin, unsigned long select);
int mt_get_gpio_pull_select(unsigned long pin);
/*data inversion*/
int mt_set_gpio_inversion(unsigned long pin, unsigned long enable);
int mt_get_gpio_inversion(unsigned long pin);
/*input/output*/
int mt_set_gpio_out(unsigned long pin, unsigned long output);
int mt_get_gpio_out(unsigned long pin);
int mt_get_gpio_in(unsigned long pin);
/*mode control*/
int mt_set_gpio_mode(unsigned long pin, unsigned long mode);
int mt_get_gpio_mode(unsigned long pin);
/*misc functions for protect GPIO*/
/* void mt_gpio_dump(GPIO_REGS *regs,GPIOEXT_REGS *regs_ext); */
void gpio_dump_regs(void);
如下方式可以控制GPIO输出高电平:
mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_OUT);
mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ONE);
其中“GPIO_CTP_EINT_PIN”和“GPIO_CTP_EINT_PIN_M_GPIO”就是之前配置GPIO的时候,在“cust_gpio_usage.h”文件里面生成的宏。“GPIO_DIR_OUT”和“GPIO_OUT_ONE”是“mt_gpio.h”文件里面定义的宏,这个文件在:kernel-3.10\include\mach
以此类推,可以使用“mt_gpio.h”文件里面的函数,控制GPIO的输入输出,模式切换等。
简单分析一下控制GPIO的“mt_set_gpio_mode”这些函数的驱动。
“mt_set_gpio_mode”函数的实现,在文件“mt_gpio_core.c”,目录:kernel-3.10\drivers\misc\mediatek\gpio
分析一下这个文件,先通过“platform_driver_register”注册了GPIO的设备驱动:
#ifdef CONFIG_OF
static const struct of_device_id apgpio_of_ids[] = {
{
.compatible = "mediatek,GPIO", },
{
}
};
#endif
static struct platform_driver gpio_driver = {
.probe = mt_gpio_probe,
.remove = mt_gpio_remove,
#ifdef CONFIG_PM
.suspend = mtk_gpio_suspend,
.resume = mtk_gpio_resume,
#endif
.driver = {
.name = GPIO_DEVICE,
#ifdef CONFIG_OF
.of_match_table = apgpio_of_ids,
#endif
},
};
static int __init mt_gpio_init(void)
{
int ret = 0;
GPIOLOG("version: %s\n", VERSION);
ret = platform_driver_register(&gpio_driver);
return ret;
}
根据使用的“of_device_id”里面的“mediatek,GPIO”,查看dts文件如下:
GPIO@0x10211000 {
compatible = "mediatek,GPIO";
reg = <0x10211000 0x1000>;
};
就比较简单记录了GPIO硬件的寄存器地址,接下来看下“mt_gpio_probe”函数:
/*---------------------------------------------------------------------------*/
static struct file_operations mt_gpio_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = mt_gpio_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = mt_gpio_ioctl,
#endif
.open = mt_gpio_open,
.release = mt_gpio_release,
};
/*----------------------------------------------------------------------------*/
static struct miscdevice mt_gpio_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mtgpio",
.fops = &mt_gpio_fops,
};
/*---------------------------------------------------------------------------*/
static int mt_gpio_probe(struct platform_device *dev)
{
int err;
struct miscdevice *misc = &mt_gpio_device;
#ifdef CONFIG_OF
if (dev->dev.of_node) {
/* Setup IO addresses */
get_gpio_vbase(dev->dev.of_node);
}
get_io_cfg_vbase();
#endif
......
if ((err = misc_register(misc)))
GPIOERR("register gpio\n");
......
return err;
}
这部分代码比较主要的两个地方,一个是使用“get_gpio_vbase”函数设置了GPIO的基地址,就是dts文件里面记录的,这个函数在文件“mt_gpio_base.c”里,目录:kernel-3.10\drivers\misc\mediatek\gpio\platform;
一个是使用“misc_register”函数注册了一个misc设备,名字为“mtgpio”,对应的有open,release,ioctl函数。
主要看下ioctl函数:
static long mt_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct mt_gpio_obj_t *obj = mt_gpio;
long res;
unsigned long pin;
......
switch (cmd) {
......
case GPIO_IOCTMODE0:
{
pin = (unsigned long)arg;
res =
GIO_INVALID_OBJ(obj) ? (-EACCES) : mt_set_gpio_mode(pin, GPIO_MODE_00);
break;
}
......
return res;
}
这就看到了之前使用的“mt_set_gpio_mode”函数,这里就是允许用户层程序,通过misc设备,来控制GPIO。
int mt_set_gpio_mode(unsigned long pin, unsigned long mode)
{
if (mode >= GPIO_MODE_MAX) {
GPIOERR("Parameter mode error: %d\n", (int)mode);
return -ERINVAL;
}
return MT_GPIO_OPS_SET(pin, set_mode, mode);
}
EXPORT_SYMBOL(mt_set_gpio_mode);
“mt_set_gpio_mode”函数主要就是使用了一个宏“MT_GPIO_OPS_SET”:
#define MT_GPIO_OPS_SET(pin, operation, arg) \
({ unsigned long flags;\
u32 retval = 0;\
mt_gpio_pin_decrypt(&pin);\
spin_lock_irqsave(&mt_gpio_lock, flags);\
switch (MT_GPIO_PLACE(pin)) {\
case MT_BASE:\
if ((mt_gpio->base_ops == NULL) || (mt_gpio->base_ops->operation == NULL)) {\
GPIOERR("base access error, null point %d\n", (int)pin);\
retval = -ERACCESS;\
} else{\
retval = mt_gpio->base_ops->operation(pin, arg);\
if (retval < 0) \
GPIOERR("base operation fail %d\n", (int)retval);\
} \
break;\
case MT_EXT:\
if ((mt_gpio->ext_ops == NULL) || (mt_gpio->ext_ops->operation == NULL)) {\
GPIOERR("extention access error, null point %d\n", (int)pin);\
retval = -ERWRAPPER;\
} else{\
retval = mt_gpio->ext_ops->operation(pin, arg);\
if (retval < 0) \
GPIOERR("ext operation fail %d\n", (int)retval);\
} \
break;\
default:\
GPIOERR("Parameter error: %d\n", (int)pin);\
retval = -ERINVAL;\
break;\
} \
spin_unlock_irqrestore(&mt_gpio_lock, flags);\
retval; })
这个宏先判断“pin”是属于“MT_BASE”或者“MT_EXT”,对于“mt_set_gpio_mode”函数这个宏展开之后主要就是:
mt_gpio->base_ops->set_mode(pin, mode);//MT_BASE
mt_gpio->ext_ops->set_mode(pin, mode);//MT_EXT
这里使用了一个指针变量“mt_gpio”:
static struct mt_gpio_obj_t *mt_gpio = &mt_gpio_obj;
“mt_gpio”是对变量“mt_gpio_obj”取址:
struct mt_gpio_obj_t {
atomic_t ref;
dev_t devno;
struct class *cls;
struct device *dev;
struct cdev chrdev;
/* spinlock_t lock; */
struct miscdevice *misc;
struct mt_gpio_ops *base_ops;
struct mt_gpio_ops *ext_ops;
};
static struct mt_gpio_obj_t mt_gpio_obj = {
.ref = ATOMIC_INIT(0),
.cls = NULL,
.dev = NULL,
.base_ops = &mt_base_ops,//MT_BASE
.ext_ops = &mt_ext_ops,//MT_EXT
/* .lock = __SPIN_LOCK_UNLOCKED(die.lock), */
};
变量“mt_gpio_obj”里面的成员变量“base_ops”和“ext_ops”,又分别是对变量“mt_base_ops”和“mt_ext_ops”取址,这里以“mt_base_ops”为例:
struct mt_gpio_ops {
/* char name[MT_GPIO_MAX_NAME]; */
int (*set_dir) (unsigned long pin, unsigned long dir);
int (*get_dir) (unsigned long pin);
int (*set_pull_enable) (unsigned long pin, unsigned long enable);
int (*get_pull_enable) (unsigned long pin);
int (*set_smt) (unsigned long pin, unsigned long enable);
int (*get_smt) (unsigned long pin);
int (*set_ies) (unsigned long pin, unsigned long enable);
int (*get_ies) (unsigned long pin);
int (*set_pull_select) (unsigned long pin, unsigned long select);
int (*get_pull_select) (unsigned long pin);
int (*set_inversion) (unsigned long pin, unsigned long enable);
int (*get_inversion) (unsigned long pin);
int (*set_out) (unsigned long pin, unsigned long output);
int (*get_out) (unsigned long pin);
int (*get_in) (unsigned long pin);
int (*set_mode) (unsigned long pin, unsigned long mode);
int (*get_mode) (unsigned long pin);
};
static struct mt_gpio_ops mt_base_ops = {
.set_dir = mt_set_gpio_dir_base,
.get_dir = mt_get_gpio_dir_base,
.set_pull_enable = mt_set_gpio_pull_enable_base,
.get_pull_enable = mt_get_gpio_pull_enable_base,
.set_smt = mt_set_gpio_smt_base,
.get_smt = mt_get_gpio_smt_base,
.set_ies = mt_set_gpio_ies_base,
.get_ies = mt_get_gpio_ies_base,
.set_pull_select = mt_set_gpio_pull_select_base,
.get_pull_select = mt_get_gpio_pull_select_base,
.set_inversion = mt_set_gpio_inversion_base,
.get_inversion = mt_get_gpio_inversion_base,
.set_out = mt_set_gpio_out_base,
.get_out = mt_get_gpio_out_base,
.get_in = mt_get_gpio_in_base,
.set_mode = mt_set_gpio_mode_base,
.get_mode = mt_get_gpio_mode_base,
};
变量“mt_base_ops”里面的成员变量“set_mode”,是一个函数指针,指向“mt_set_gpio_mode_base”函数,这就是我们使用“mt_set_gpio_mode”设置GPIO的时候,最终调用到的地方,在文件“mt_gpio_base.c”里,目录:kernel-3.10\drivers\misc\mediatek\gpio\platform
“mt_set_gpio_mode_base”函数就直接通过判断“pin”和“mode”,去写GPIO的寄存器,来实现需要的GPIO控制。
以上就是GPIO驱动的简单分析!
文章浏览阅读342次,点赞4次,收藏6次。该函数还允许使用 kmeans 聚类聚合行。如果行数太大,以至于 R 无法再处理其分层聚类,大约超过 1000 行,则建议这样做。与其单独显示所有行,不如提前对行进行聚类,并仅显示聚类中心。可以通过参数kmeans_k调整集群的数量。来源:https://www.rdocumentation.org/packages/pheatmap/versions/1.0.12/topics/pheatmap。一个绘制聚类热图的函数,可以更好地控制一些图形参数,如单元大小等。Examples 例子。_pheatmap基于kmeans绘制热图
文章浏览阅读369次。<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml..._div四周阴影效果
文章浏览阅读1.7k次。Java 通过反射获取实体类对应的注释 _java获取实体类属性注解
文章浏览阅读2.3k次,点赞5次,收藏10次。在使用MyBatis进行多表联查时,想要获取关联外键的表的数据信息,使用association进行联查,但当外键表的字段名和主表相同时,外键表的数据就会被覆盖。_mybatis association绑定相同对象
文章浏览阅读2.7k次。体验1: 军神太强啦,1小时屯6题,瞬间AK,接下来的90分钟一直在跟榜体验2: A题原题,循环写得好就不麻烦,不然要写很多行,情况要想全并不难。 B题原题,有了上一场的提示之后,这题就不难了。 C题很简单(小声)。 D题卡掉了O(T*N*K*log(N))的方法,卡掉我5发logN ,不过还是可做。 E题水dp(组合数学)。 F题原题,记忆化搜索。体验3: 被DC两题卡到..._在湘大xx奶茶店夏天推出了新的饮料价格为5元。 很多学生都要买饮料,每个学生
文章浏览阅读2.8k次。需求: 点击预览图标查看该pdf报告问题: 1、最早是直接将请求倒的url放入到<web-view src="{{realUrl}}"></web-view>中展示,ios可以,安卓显示无法查看。 2、通过微信自身的API实现:wx.downloadFile({})、wx.saveFile({})、wx.openDocument({}) 3、对于文件较大的,下载较慢,需要点击过的进行缓存,再次点击无需下载,直接打开。 将点击过的下载的url添加给list的tem_微信浏览器请求pdf文件会缓存吗
文章浏览阅读680次。服务部署之配置网络策略服务(NPS)(基于Windows Server 2022)_windows server 部署网络策略服务
文章浏览阅读4.8k次,点赞6次,收藏29次。基于距离、概率、重构的视频异常检测概述_视频异常检测综述
文章浏览阅读107次。洛谷P3388#include<bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;const int N=2e4+5;const int mod=1e9+7;vector<int> g[N];set<int> v;int dfn[N],low[N],fa[N];int n,m,tot;void tarjan(int x){
文章浏览阅读1k次。导语:小编相信,经常会使用到电脑的朋友们,对于启用硬件加速这个词一定都是不陌生的吧!可是呢,对于一些电脑小白们来说,往往会搞不清楚,这个启用硬件加速到底是个什么意思呢?启用之后,我们的电脑又会发生什么变化呢?也有一些人,在启用之后,却不知道应该如何关闭这个硬件加速,接下来,小编就来为大家介绍一下启用硬件加速是什么意思,以及它应该如何关闭。启用硬件加速是什么意思?简而言之,硬件加速就是利用硬件模块来..._linux 禁用硬件加速合成、图层和素材面板
文章浏览阅读8.1k次,点赞13次,收藏191次。1. 写在前面很多高级的机器学习模型(xgboost, lgb, cat)和神经网络模型, 它们相对于普通线性模型在进行预测时往往有更好的精度,但是同时也失去了线性模型的可解释性, 所以这些模型也往往看作是黑箱模型, 在2017年,Lundberg和Lee的论文提出了SHAP值这一广泛适用的方法用来解释各种模型(分类以及回归), 使得前面的黑箱模型变得可解释了,这篇文章主要整理一下SHAP的使用, 这个在特征选择的时候特别好用。这次整理, 主要是在xgboost和lgb等树模型上的使用方式, 并且用一个_python对shap的计算只能针对大数值吗
文章浏览阅读625次。这篇文章深入探讨了操作系统的各个方面,以及相关的计算机科学概念。文章的结构包括对操作系统的定义和功能的讨论,涵盖了硬件管理、操作系统特征、启动过程、运行环境等多个方面。作者使用思维导图和具体版本(如哈工大版本、王道版本)作为辅助,系统性地介绍了操作系统的运行机制,包括中断与异常、系统调用等内容。文章还回顾了操作系统的历史发展,按照不同线索(如哈工大版本)进行叙述,涵盖了操作系统的发展与分类、体系结构等方面。最后,文章提到了一些考研真题,强调了对计算机科学相关概念的深入理解。_2021