Linux:使用pinctrl子系统动态切换复用pin脚的功能

      Linux:使用pinctrl子系统动态切换复用pin脚的功能

 

 

一、许多soc内部都包含有pin控制器,通过pin控制器的寄存器,我们可以配置一个或者一组引脚的功能和特性。在软件方面,Linux内核提供了pinctrl子系统,目的是为了统一各soc厂商的pin脚管理。

二、常用API介绍

1、struct pinctrl *devm_pinctrl_get(struct device *dev)

2、struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,const char *name)

3、int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)

 

四、实例测试,动态切换i2c0和gpio功能

1、dts文件添加

	gpio_i2c_exchage{
	   compatible= "gpio-i2c-exchage";
	   pinctrl-names= "default", "gpio";
	   pinctrl-0= <&i2c0_function>;
	   pinctrl-1= <&i2c0_gpio>;
	 };

     i2c0_option{
			i2c0_function: i2c0-function {
				rockchip,pins =
					<2 GPIO_D0 RK_FUNC_1 &pcfg_pull_none_smt>,
					<2 GPIO_D1 RK_FUNC_1 &pcfg_pull_none_smt>;
			};
			i2c0_gpio: i2c0-gpio {
				rockchip,pins =
					<2 GPIO_D0 RK_FUNC_GPIO &pcfg_pull_none_smt>,
					<2 GPIO_D1 RK_FUNC_GPIO &pcfg_pull_none_smt>;
			};
        };

2、测试driver代码kernel\drivers\char\pinctrl.c

#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>
 
struct pinctrl *i2c0_pinctrl;
struct pinctrl_state   *i2c0_default;//uart
struct pinctrl_state   *i2c0_gpio;//gpio

#define ROCKCHIP_GPIO_NR(bank, nr)          (((bank)) * 32 + (nr))

#define I2C0_SCLK	ROCKCHIP_GPIO_NR(2,24)


const char   *I2C0_PINCTRL_STATE_DEFAULT = "default";
const char   *I2C0_PINCTRL_STATE_GPIO = "gpio";
 
static int biada_pinctrl_request_gpios(int state)
{
    int result = 0;
 
    if(state==0)
	{
        result = pinctrl_select_state(i2c0_pinctrl, i2c0_default);
        if (result) {
            printk("%s: Can not set %s pins\n",
            __func__, "default");
        }
    }else
    {
        result = pinctrl_select_state(i2c0_pinctrl, i2c0_gpio);
        if (result) {
            printk("%s: Can not set %s pins\n",
            __func__, "gpio");
        }
    }
    printk(KERN_ERR "%s,request state(%s) ok, result = %d\n",
            __func__, state ? "default" : "gpio",result);
 
    return result;
}
static ssize_t pinctrl_show(struct device* cd,struct device_attribute *attr, char* buf) 
{ 
    ssize_t ret = 0; 
    sprintf(buf, "%s\n",__func__);  
    ret = strlen(buf) + 1;
    return ret; 
} 
 
static ssize_t pinctrl_store(struct device* cd, struct device_attribute *attr, 
const char* buf, size_t len) 
{ 
    unsigned long select = simple_strtoul(buf, NULL, 10); 
    printk("%s: %lu\n",__func__, select); 
    biada_pinctrl_request_gpios(select);
 
    if(select)
	{
        printk("%s: set gpio low level\n", __func__);
        gpio_direction_output(I2C0_SCLK, 0);
	    mdelay(100);
		printk("%s: set gpio low high\n", __func__);
		gpio_direction_output(I2C0_SCLK, 1);
    }
    return len; 
}
static DEVICE_ATTR(biada_pinctrl,S_IRUGO | S_IWUSR, pinctrl_show, pinctrl_store); 
static int biada_pinctrl_init(struct platform_device *pdata)
{

    i2c0_pinctrl = devm_pinctrl_get(&pdata->dev);
	printk("\n[************%s************devm_pinctrl_get]\n", __func__);
    if (IS_ERR_OR_NULL(i2c0_pinctrl)) {
        printk("Failed to get pin ctrl\n");
        return PTR_ERR(i2c0_pinctrl);
    }
 
    // default
    printk("\n[************%s************pinctrl_lookup_state i2c0_default]\n", __func__);
    i2c0_default = pinctrl_lookup_state(i2c0_pinctrl,
                I2C0_PINCTRL_STATE_DEFAULT);
    if (IS_ERR_OR_NULL(i2c0_default)) {
        printk("Failed to lookup pinctrl default state\n");
        return PTR_ERR(i2c0_default);
    }
 
    // gpio
    printk("\n[************%s************pinctrl_lookup_state i2c0_gpio]\n", __func__);
    i2c0_gpio = pinctrl_lookup_state(i2c0_pinctrl,
                I2C0_PINCTRL_STATE_GPIO);
    if (IS_ERR_OR_NULL(i2c0_gpio)) {
        printk("Failed to lookup pinctrl gpio state\n");
        return PTR_ERR(i2c0_gpio);
    }
    printk("\n[************%s************]\n", __func__);
    return 0;
 
}
// echo 0 >/sys/bus/platform/devices/gpio_i2c_exchage.35/biada_pinctrl //i2c0 mode
// echo 1 >/sys/bus/platform/devices/gpio_i2c_exchage.35/biada_pinctrl //gpio mode
static int biada_pinctrl_probe(struct platform_device *pdev)
{
    int ret = 0;
    biada_pinctrl_init(pdev);
    if(device_create_file(&pdev->dev, &dev_attr_biada_pinctrl)) 
    printk(KERN_ERR "Unable to createsysfs entry: '%s'\n", 
            dev_attr_biada_pinctrl.attr.name); 

	printk("\n[************%s************]\n", __func__);		
    return ret;
 
}
static int biada_pinctrl_remove(struct platform_device *plat)
{
    return 0;
}
 
static struct of_device_id __attribute__ ((unused)) biada_pinctrl_of_match[] = {
    { .compatible = "gpio-i2c-exchage", },
    {}
};
 
static struct platform_driver biada_pinctrl_driver = {
    .probe = biada_pinctrl_probe,
    .remove = biada_pinctrl_remove,
    .driver = {
        .name = "gpio-exchage",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(biada_pinctrl_of_match),
    },
};
 
static int __init biada_init(void)
{
    return platform_driver_register(&biada_pinctrl_driver);
}
 
static void __exit biada_exit(void)
{
    platform_driver_unregister(&biada_pinctrl_driver);
}
 
MODULE_LICENSE("GPLv2");
MODULE_AUTHOR("trump, trump@usa-chips.com");
MODULE_DESCRIPTION("Driver for Rockchip I2C Bus");
MODULE_VERSION("2.0");
 
module_init(biada_init);
module_exit(biada_exit);

3、运行结果效果如下,可以动态在i2c和gpio之间切换,用示波器测试gpio有波形,i2c可以work。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值