使用pinctrl子系统实现引脚功能动态切换

34 篇文章 9 订阅
24 篇文章 16 订阅

使用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";配置,驱动中通过名称进行查找引脚状态。


  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值