使用pinctrl子系统实现引脚功能动态切换
2017-07-11 10:41
435 查看
使用pinctrl子系统实现动态切换引脚功能
设备dts (msm8909-pinctrl.dtsi)
&soc {tlmm_pinmux:pinctrl@1000000 {
compatible= "qcom,msm-tlmm-8916";
reg= <0x1000000 0x300000>;
interrupts= <0 208 0>;
/*Generalpurpose pins*/
gp:gp {
qcom,num-pins= <113>;
#qcom,pin-cells= <1>;
msm_gpio:msm_gpio {
compatible= "qcom,msm-tlmm-gp";
gpio-controller;
#gpio-cells= <2>;
interrupt-controller;
#interrupt-cells= <2>;
num_irqs= <113>;
};
};
cam_sensor_mclk0{
/*MCLK */
qcom,pins= <&gp 26>;
qcom,num-grp-pins= <1>;
qcom,pin-func= <1>;
label= "cam-sensor-mclk0";
/* active state */
cam_sensor_mclk0_default:default {
drive-strength= <2>; /* 2 MA */
bias-disable= <0>; /* No PULL */
};
};
cam_sensor_mclk0_sleep{
/*MCLK */
qcom,pins= <&gp 26>;
qcom,num-grp-pins= <1>;
label= "cam-sensor-mclk0-sleep";
/*suspend state */
cam_sensor_mclk0_sleep:sleep {
drive-strength= <2>; /* 2 MA */
bias-pull-down;/* PULL DOWN */
};
};
/*test */
uart_0_console{
qcom,pins= <&gp 4>, <&gp 5>;
qcom,num-grp-pins= <2>;
qcom,pin-func= <2>;
label= "uart0-console";
uart_0_active:uart_0_active {
drive-strength = <8>;
bias-pull-down;
};
};
uart_0_gpio{
qcom,pins= <&gp 4>, <&gp 5>;
qcom,num-grp-pins= <2>;
qcom,pin-func= <0>;
label= "uart0-gpio";
uart_0_gpio:uart_0_gpio {
drive-strength = <8>;
bias-pull-down;
output-high;
};
};
};
};
定义串口引脚的两个状态uart_0_console(uart_0_active)和uart_0_gpio(uart_0_gpio)。
前者是配置gpio4/5作为uart功能,function2。后者配置gpio4,5作为普通gpio功能,function0。
具体设备引用:
&soc {
gpio_uart_exchage{
compatible= "gpio-uart-exchage";
pinctrl-names= "default", "gpio";
pinctrl-0= <&uart_0_active>;
pinctrl-1= <&uart_0_gpio>;
};
};
注意:
"default"对应的引脚配置为pinctrl-0;
"gpio"对应的引脚配置为pinctrl-1;
一般引脚的状态为两个就可以了,一个为活跃状态的引脚状态,一个是休眠状态的引脚状态。
如SDIO接口配置;
pinctrl-names= "active", "sleep";
pinctrl-0= <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
pinctrl-1= <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off&sdc2_cd_off>;
站在应用的逻辑上来讲,设置某模块的两种工作状态。
驱动
设备配置好了,我们来看驱动程序。首先介绍下主要pinctrl函数(Core.c (drivers\pinctrl))
头文件:#include <linux/pinctrl/consumer.h>
参考:http://blog.csdn.net/hanp_linux/article/details/72818437
1. 获取一个pinctrl句柄,参数是dev是包含这个pin的device结构体即xxx这个设备的device
[cpp] view plain copy
/**
* struct devm_pinctrl_get() - Resource managed pinctrl_get()
* @dev: the device to obtain the handle for
*
* If there is a need to explicitly destroy the returned struct pinctrl,
* devm_pinctrl_put() should be used, rather than plain pinctrl_put().
*/
struct pinctrl *devm_pinctrl_get(struct device *dev)
2. 获取这个pin对应pin_state,引脚状态
[cpp] view plain copy
/**
* pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle
* @p: the pinctrl handle to retrieve the state from
* @name: the state name to retrieve
*/
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name)
3.设置引脚为为某个state
[cpp] view plain copy
/**
* pinctrl_select_state() - select/activate/program a pinctrl state to HW
* @p: the pinctrl handle for the device that requests configuration
* @state: the state handle to select/activate/program
*/
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
下面是一个简单驱动程序:
#define pr_fmt(fmt) "%s:" fmt, __func__
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include<linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/io.h>
#include<linux/uaccess.h>
#include<linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include<linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/gpio.h>
unsigned long isGPIO =0;
struct pinctrl *gp_pinctrl;
struct pinctrl_state*gp_default;//uart
struct pinctrl_state*gp_gpio;//gpio
const char*gp_PINCTRL_STATE_DEFAULT = "default";
const char*gp_PINCTRL_STATE_GPIO = "gpio";
static int gp_request_gpios(intstate)
{
int result = 0;
if(state){
result = pinctrl_select_state(gp_pinctrl, gp_default);
if (result) {
printk("%s: Can not set %s pins\n",
__func__, "default");
}
}else{
result = pinctrl_select_state(gp_pinctrl, gp_gpio);
if (result) {
printk("%s: Can not set %s pins\n",
__func__, "gpio");
}
}
printk(KERN_ERR "%s, eliot request state(%s) ok, result = %d\n",
__func__, state ? "default" : "gpio",result);
return result;
}
static ssize_t lock_show(structdevice* cd,struct device_attribute *attr, char* buf)
{
ssize_t ret = 0;
sprintf(buf, "%lu\n",isGPIO);
ret = strlen(buf) + 1;
return ret;
}
static ssize_tlock_store(struct device* cd, struct device_attribute *attr,
const char* buf, size_tlen)
{
unsigned long on_off = simple_strtoul(buf, NULL, 10);
isGPIO = on_off;
printk("%s: %lu\n",__func__, isGPIO);
gp_request_gpios(!!isGPIO);
if(!isGPIO){
printk(KERN_ERR "set gpio 4 & 5to 0\n");
gpio_set_value(4 + 911, !!isGPIO);
gpio_set_value(5 + 911, !!isGPIO);
}
return len;
}
static DEVICE_ATTR(gp_ex,S_IRUGO | S_IWUSR, lock_show, lock_store);
static intgp_pinctrl_init(struct platform_device *pdata)
{
gp_pinctrl = devm_pinctrl_get(&pdata->dev);
if (IS_ERR_OR_NULL(gp_pinctrl)) {
printk("Failed to get pin ctrl\n");
return PTR_ERR(gp_pinctrl);
}
// default
gp_default = pinctrl_lookup_state(gp_pinctrl,
gp_PINCTRL_STATE_DEFAULT);
if (IS_ERR_OR_NULL(gp_default)) {
printk("Failed to lookup pinctrl default state\n");
return PTR_ERR(gp_default);
}
// gpio
gp_gpio = pinctrl_lookup_state(gp_pinctrl,
gp_PINCTRL_STATE_GPIO);
if (IS_ERR_OR_NULL(gp_gpio)) {
printk("Failed to lookup pinctrl gpio state\n");
return PTR_ERR(gp_gpio);
}
printk("eliot %s,---ok\n", __func__);
return 0;
}
// echo 0 >/sys/bus/platform/devices/gpio_uart_exchage.67/gp_ex //设置为普通GPIO
// echo 1 >/sys/bus/platform/devices/gpio_uart_exchage.67/gp_ex //设置为UART模式
static int gp_ex_probe(structplatform_device *pdev)
{
int ret = 0;
printk(KERN_ERR "eliot :gp_ex_probe\n");
gp_pinctrl_init(pdev);
if(device_create_file(&pdev->dev, &dev_attr_gp_ex))
printk(KERN_ERR "Unable to createsysfs entry: '%s'\n",
dev_attr_gp_ex.attr.name);
return ret;
}
static int gp_ex_remove(structplatform_device *plat)
{
return 0;
}
static struct of_device_id__attribute__ ((unused)) gp_ex_of_match[] = {
{ .compatible = "gpio-uart-exchage", },
{}
};
static struct platform_drivergp_ex_driver = {
.probe = gp_ex_probe,
.remove = gp_ex_remove,
.driver = {
.name = "gpio-exchage",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(gp_ex_of_match),
},
};
static int __initgp_ex_init(void)
{
return platform_driver_register(&gp_ex_driver);
}
static void __exitgp_ex_exit(void)
{
platform_driver_unregister(&gp_ex_driver);
}
MODULE_LICENSE("GPLv2");
MODULE_AUTHOR("Eliot shao<http://blog.csdn.net/eliot_shao>");
MODULE_DESCRIPTION("Driverto exchager gpio4/5.");
MODULE_VERSION("1.0");
module_init(gp_ex_init);
module_exit(gp_ex_exit);
在sys文件系统下面创建一个节点,通过读写这个节点来设置gpio4,5的状态。使用方法:
// echo 0 >/sys/bus/platform/devices/gpio_uart_exchage.67/gp_ex //设置为普通GPIO
// echo 1 >/sys/bus/platform/devices/gpio_uart_exchage.67/gp_ex //设置为UART模式
其中调用的接口函数
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
来选择在dts中配置的两个引脚状态。
另外函数:
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name)
中的name在dts中pinctrl-names ="default", "gpio";配置,驱动中通过名称进行查找引脚状态。
相关文章推荐
- 使用Jquery的局部刷新功能,实现菜单内容的动态切换
- 使用javascript操作多选列表框,实现动态增加删除,左右移动,上下排序移动等功能。
- 关于使用DataGrid的ButtonColumn,动态添加DataGrid列,实现不定列n个文件的下载功能
- 使用JDK中的Proxy技术实现AOP功能[动态代理]
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- unity-使用NGUI 两个Button实现左右切换功能
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- python使用pyhook监控键盘并实现切换歌曲的功能
- VS.Net2005中使用本地化功能实现多语言的切换
- Qt的国际化示例程序以及步骤--实现Qt程序的动态切换语言功能
- 使用动态SQL实现按列递减的功能
- JDK核心API:使用动态代理实现AOP功能
- 转载 使用AJAX实现动态刷新页面功能
- 使用Ajax实现动态双组合功能(asp.net)
- java根据properties配置文件来实现功能模块的动态切换
- SpringMVC 使用jndi 多个数据源且利用AbstractRoutingDataSource实现动态数据源切换
- 使用动态SQL实现行列转换和按列递减的功能
- 使用.net FtpWebRequest 实现FTP常用功能 上传 下载 获取文件列表 移动 切换目录 改名