Android MTK GPIO 控制驱动

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";

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星papa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值