Android MTK GPIO 控制驱动
——— MTK GPIO 驱动控制
手机Android系统驱动控制GPIO的操作是最常规的操作,此篇将简述 在MTK6765平台Android 9.0 (kernel-4.9) 为例的添加的GPIO控制驱动
目录
一、添加驱动控制文件
1、驱动文件
(1)添加驱动文件夹和文件路径
\kernel-4.9\drivers\misc\mediatek\gpio_pin_ctl\Makefile
\kernel-4.9\drivers\misc\mediatek\gpio_pin_ctl\gpio_pin_ctl.c
说明:
misc:杂项文件夹
gpio_pin_ctl:自定义文件夹
gpio_pin_ctl.c:自定义驱动文件
Makefile:makefile编译文件
(2)make文件内容
在.makefile文件中添加如下内容
#include $(srctree)/drivers/misc/mediatek/Makefile.custom
obj-y := gpio_pin_ctl.o
(3)驱动文件描述
驱动文件整个框架见下面代码,我将描述说明直接写在代码中:
//首先是引用的头文件
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/log2.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#endif
#if defined(CONFIG_MTK_LEGACY)
#include <mach/mt_gpio.h>
#include <cust_gpio_usage.h>
#endif
#include <linux/workqueue.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/kernel.h>
//这里是自己定义的宏
#define INIT_ON 1
#define INIT_OFF 0
static u8 init_interface_count = 0;
//============================== Upper interface value ==============================//
//驱动模块名称定义
#define DW_MODULE_NAME "dw_pin_ctl" // Name of this driver module
#define DW_MISC_NAME "dw_miscdev" // Name used to register as 'misc' device
//模块函数接口定义,java上层引用的接口,这里我们通过MM_DEV_MAGIC的值来区分其它系统接口,通过_IO()来左移8移位加上自己的编号作为接口number
//此处建议加上功注释方便提供给上层做APP接口使用
#define MM_DEV_MAGIC 'N'
//SYSTEM POWER
#define WIFI_VBAT _IO(MM_DEV_MAGIC, 22)//WIFI供电3.3V
#define MODULE_UART_VBAT _IO(MM_DEV_MAGIC, 12)//2G 3G 4G电源//1.8V 2.8V串口转换供电
#define STM32_VBAT _IO(MM_DEV_MAGIC, 21)//STM32系统供电1.8V
#define NR_VBAT _IO(MM_DEV_MAGIC, 46)//5G电源
//======================= Control definition ==========================//
//开关控制接口名称定义
static DEFINE_MUTEX(dw_request_mutex);
static struct pinctrl *dw_pinctrl = NULL;
struct pinctrl_state *wifi_vbat_on, *wifi_vbat_off;
struct pinctrl_state *module_uart_vbat_on, *module_uart_vbat_off;
struct pinctrl_state *stm32_vbat_on, *stm32_vbat_off;
struct pinctrl_state *nr_vbat_on, *nr_vbat_off;
//======================= Function definition =========================//
//控制函数定义,为了方便添加,我使用统一的开关格式来定义每一个函数,前面增加一个前缀,我加dc记得好像是直接控制的意思,看自己偏好。简单的if-else不做过多解释。
static void dc_wifi_vbat(int on_off)
{
printk("[dc_pin] %s on_off = %d \n",__func__,on_off);
mutex_lock(&dw_request_mutex);
if(on_off)
pinctrl_select_state(dw_pinctrl,wifi_vbat_on);
else
pinctrl_select_state(dw_pinctrl,wifi_vbat_off);
init_interface_count++;//启动时累加计数
mutex_unlock(&dw_request_mutex);
}
static void dc_module_uart_vbat(int on_off)
{
printk("[dc_pin] %s on_off = %d \n",__func__,on_off);
mutex_lock(&dw_request_mutex);
if(on_off)
pinctrl_select_state(dw_pinctrl,module_uart_vbat_on);
else
pinctrl_select_state(dw_pinctrl,module_uart_vbat_off);
init_interface_count++;
mutex_unlock(&dw_request_mutex);
}
static void dc_stm32_vbat(int on_off)
{
printk("[dc_pin] %s on_off = %d \n",__func__,on_off);
mutex_lock(&dw_request_mutex);
if(on_off)
pinctrl_select_state(dw_pinctrl,stm32_vbat_on);
else
pinctrl_select_state(dw_pinctrl,stm32_vbat_off);
init_interface_count++;
mutex_unlock(&dw_request_mutex);
}
static void dc_nr_vbat(int on_off)
{
printk("[dc_pin] %s on_off = %d \n",__func__,on_off);
mutex_lock(&dw_request_mutex);
if(on_off)
pinctrl_select_state(dw_pinctrl,nr_vbat_on);
else
pinctrl_select_state(dw_pinctrl,nr_vbat_on);
init_interface_count++;
mutex_unlock(&dw_request_mutex);
}
//============================= Entrance of upper interface function ===============================//
//上层调用接口函数入口
static long dw_misc_ioctl(struct file* file, unsigned int cmd, unsigned long arg)
{
printk("[dc_pin] %s --cmd = %d, arg = %d\n",__func__,cmd,arg);
switch(cmd)
{
case WIFI_VBAT:
dc_wifi_vbat(arg);
break;
case MODULE_UART_VBAT:
dc_module_uart_vbat(arg);
break;
case STM32_VBAT:
dc_stm32_vbat(arg);
break;
case NR_VBAT:
dc_nr_vbat(arg);
break;
default:
printk("[dc_pin] %s default: break\n",__func__);
break;
}
return 0;
}
static int dw_misc_open(struct inode* node, struct file* file)
{
printk("[dc_pin] %s --\n",__func__);
return 0;
}
static int dw_misc_release(struct inode* node, struct file* file)
{
printk("[dc_pin] %s --\n",__func__);
return 0;
}
//======================= init GPIO =========================//
//初始化函数//开机初始化操作控制IO口
static void dw_pin_init(void)
{
printk("[dc_pin] %s -- start --\n",__func__);
dc_wifi_vbat(INIT_OFF);
dc_module_uart_vbat(INIT_OFF);
dc_stm32_vbat(INIT_OFF);
dc_nr_vbat(INIT_OFF);
printk("[dc_pin] %s -- end -- # init_interface_count = %d \r\n",__func__,init_interface_count);
}
//========================== Initialize the device tree node ===========================//
设备树
static int dw_gpio_dts_init(struct platform_device *pdev)
{
int retval;
printk("[dc_pin] %s --\n",__func__);
dw_pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(dw_pinctrl)) {
printk("[dc_pin] %s : dw_pinctrl error \n", __func__);
retval = PTR_ERR(dw_pinctrl);
}
wifi_vbat_on = pinctrl_lookup_state(dw_pinctrl,"wifi_vbat_on");
if (IS_ERR(wifi_vbat_on))
{
retval = PTR_ERR(wifi_vbat_on);
printk("[dc_pin] %s : init err, wifi_vbat_on error \n", __func__);
}
wifi_vbat_off = pinctrl_lookup_state(dw_pinctrl , "wifi_vbat_off");
if( IS_ERR (wifi_vbat_off))
{
retval = PTR_ERR(wifi_vbat_off);
printk("[dc_pin] %s wifi_vbat_off error \n",__func__);
}
module_uart_vbat_on = pinctrl_lookup_state(dw_pinctrl,"module_uart_vbat_on");
if (IS_ERR(module_uart_vbat_on))
{
retval = PTR_ERR(module_uart_vbat_on);
printk("[dc_pin] %s : init err, module_uart_vbat_on error \n", __func__);
}
module_uart_vbat_off = pinctrl_lookup_state(dw_pinctrl,"module_uart_vbat_off");
if (IS_ERR(module_uart_vbat_off))
{
retval = PTR_ERR(module_uart_vbat_off);
printk("[dc_pin] %s : init err, module_uart_vbat_off error \n", __func__);
}
stm32_vbat_on = pinctrl_lookup_state(dw_pinctrl,"stm32_vbat_on");
if (IS_ERR(stm32_vbat_on))
{
retval = PTR_ERR(stm32_vbat_on);
printk("[dc_pin] %s : init err, stm32_vbat_on error \n", __func__);
}
stm32_vbat_off = pinctrl_lookup_state(dw_pinctrl,"stm32_vbat_off");
if (IS_ERR(stm32_vbat_off))
{
retval = PTR_ERR(stm32_vbat_off);
printk("[dc_pin] %s : init err, stm32_vbat_off error \n", __func__);
}
nr_vbat_on = pinctrl_lookup_state(dw_pinctrl,"nr_vbat_on");
if (IS_ERR(nr_vbat_on))
{
retval = PTR_ERR(nr_vbat_on);
printk("[dc_pin] %s : init err, nr_vbat_on error \n", __func__);
}
nr_vbat_off = pinctrl_lookup_state(dw_pinctrl,"nr_vbat_off");
if (IS_ERR(nr_vbat_off))
{
retval = PTR_ERR(nr_vbat_off);
printk("[dc_pin] %s : init err, nr_vbat_off error \n", __func__);
}
//init GPIO
//内核初始化开始
dw_pin_init();
return retval;
}
//杂项文件操作结构体指针
static const struct file_operations dw_ctl_fops =
{
.owner = THIS_MODULE,
// .unlocked_ioctl = dw_misc_ioctl, // for 32 bit
.compat_ioctl = dw_misc_ioctl, // for 64 bit
.open = dw_misc_open,
.release = dw_misc_release,
};
//注册一个杂项设备
static struct miscdevice dw_misc_device =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DW_MISC_NAME,
.fops = &dw_ctl_fops,
};
//注册驱动
static int dw_platform_probe(struct platform_device *pdev)
{
printk("[dc_pin] %s --\n",__func__);
misc_register(&dw_misc_device);
dw_gpio_dts_init(pdev);
return 0;
}
//注销驱动
static int dw_platform_remove(struct platform_device *pdev)
{
printk("[dc_pin] %s --\n",__func__);
misc_deregister(&dw_misc_device);
return 0;
}
//设备树对应节点
static struct of_device_id dw_of_match[] = {
{ .compatible = "mediatek,dw_pin_ctl", },
{ },
};
//启动接口定义
static struct platform_driver dw_platform_driver =
{
.probe = dw_platform_probe,
.remove = dw_platform_remove,
.driver =
{
.name = DW_MODULE_NAME,
.of_match_table = dw_of_match,
.owner = THIS_MODULE,
}
};
//初始化模块
static int __init dw_mod_init(void)
{
printk("[dc_pin] %s --\n",__func__);
if(platform_driver_register(&dw_platform_driver))
{
printk("[dc_pin] %s failed to platform_driver_register driver \n",__func__);
return -ENODEV;
}
return 0;
}
//初始化退出
static void __exit dw_mod_exit(void)
{
printk("[dc_pin] %s --\n",__func__);
platform_driver_unregister(&dw_platform_driver);
}
//初始化和退出模块函数
module_init(dw_mod_init);
module_exit(dw_mod_exit);
MODULE_DESCRIPTION("Dw Driver");
MODULE_AUTHOR("Allen.Cai");
MODULE_LICENSE("GPL");
2、添加DTS设备树
(1)、设备树路径
\kernel-4.9\arch\arm64\boot\dts\mediatek\k65v1_64_bsp.dts
\kernel-4.9\arch\arm64\boot\dts\mediatek\mt6765.dts
(2)、添加设备树
1、k65v1_64_bsp.dts 中添加对应值:
&dw_ctl {
pinctrl-names = "wifi_vbat_on", "wifi_vbat_off",
"module_uart_vbat_on","module_uart_vbat_off",
"stm32_vbat_on","stm32_vbat_off",
"nr_vbat_on","nr_vbat_off";
pinctrl-0 = <&io_wifi_vbat_on>;
pinctrl-1 = <&io_wifi_vbat_off>;
pinctrl-2 = <&io_module_uart_vbat_on>;
pinctrl-3 = <&io_module_uart_vbat_off>;
pinctrl-4 = <&io_stm32_vbat_on>;
status = "okay";
};
&pio {
io_wifi_vbat_on: dw_ctl@0 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO22__FUNC_GPIO22>;
slew-rate = <1>;
output-high;
};
};
io_wifi_vbat_off: dw_ctl@1 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO22__FUNC_GPIO22>;
slew-rate = <1>;
output-low;
};
};
io_module_uart_vbat_on: dw_ctl@2 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO12__FUNC_GPIO12>;
slew-rate = <1>;
output-high;
};
};
io_module_uart_vbat_off: dw_ctl@3 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO12__FUNC_GPIO12>;
slew-rate = <1>;
output-low;
};
};
io_stm32_vbat_on: dw_ctl@4 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO21__FUNC_GPIO21>;
slew-rate = <1>;
output-high;
};
};
io_stm32_vbat_off: dw_ctl@5 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO21__FUNC_GPIO21>;
slew-rate = <1>;
output-low;
};
};
io_nr_vbat_on: dw_ctl@6 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO46__FUNC_GPIO46>;
slew-rate = <1>;
output-high;
};
};
io_nr_vbat_off: dw_ctl@7 {
pins_cmd_dat {
pinmux = <PINMUX_GPIO46__FUNC_GPIO46>;
slew-rate = <1>;
output-low;
};
};
};
2、mt6765.dts中添加主干别名
dw_ctl: dw_pin_ctl {
compatible = "mediatek,dw_pin_ctl";