tiny4412 设备树之pinctrl(番外)

来源:互联网 发布:电玩游戏平台源码 编辑:程序博客网 时间:2024/05/21 06:49

开发板:tiny4412(1611)
内核:linux4.4
编译器: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320)

  许多Soc内部都包含pin控制器,通过pin控制器的寄存器,我们可以配置一个或者一组引脚的功能和特性。
  在软件方面,linux内核中提供了pinctrl子系统,目的是为了统一各SoC厂商的pin脚管理,避免各SoC厂商各自实现相同的pin脚管理子系统,减少SoC厂商系统移植工作量。
  通过pinctrl驱动可以操作pin控制器,完成如下工作:
  1. 枚举并且命名pin控制器可控制的所有引脚;
   2. 提供引脚的复用能力;
   3. 提供配置引脚的能力,如驱动能力、上拉下拉和数据属性等;


下面以配置使用一个IO口,来介绍pinctrl的使用。

这里写图片描述

在设备树根节点添加如下信息:

(gpj属于pinctrl_0)&pinctrl_0{        gpio_in: gpj1_3in{                        samsung,pins = "gpj1-3";                        samsung,pin-function = <0>;                        samsung,pin-pud = <0>;                        samsung,pin-drv = <0>;                };        gpio_out: gpj1_3out{                        samsung,pins = "gpj1-3";                        samsung,pin-function = <1>;                        samsung,pin-pud = <0>;                        samsung,pin-drv = <0>;                };};PS:    samsung,pin-function、samsung,pin-pud、samsung,pin-drv实际上是SOC厂商对寄存器配置的封装。

这里写图片描述

在设备树上引用pinctrl子节点:

 demo@11400260{                compatible         ="gpio_j1-3";                reg = <0x11400260 0x14>;                tiny4412,demo      =<&gpj1 3 GPIO_ACTIVE_HIGH>;                pinctrl-names = "in","out";                pinctrl-0 = <&gpio_in>;                pinctrl-1 = <&gpio_out>;        };

驱动中解析配置所需API:

//申请引脚pin=of_get_named_gpio(dev->of_node,"tiny4412,demo",0);devm_gpio_request_one(dev,pin,GPIOF_OUT_INIT_HIGH,"gpj1_3");//配置状态pctrl=devm_pinctrl_get(dev);psate_in=pinctrl_looup_state(pctrl,"in");pinctrl_select_state(pin,psate_in);//读写IOgpio_set_value(pin,voltage);gpio_get_value(pin);

驱动:

#include <linux/init.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/gpio.h>#include <linux/of.h>#include <linux/of_gpio.h>#include <linux/interrupt.h>#include <linux/sched.h> #include <linux/cdev.h> #include <asm/uaccess.h>#include <linux/kdev_t.h>#include <linux/fs.h>#define dev_num 1struct device *dev;static struct pinctrl *pinctrl; static struct pinctrl_state *pinctrl_in;static struct pinctrl_state *pinctrl_out;static struct cdev gpj1_3_cdev;static struct class *gpj_class;static struct device *class_dev;static int major;static dev_t devid;static int gpj1_3_pin;static char devname[]="gpj_1_3";static int gpj1_3_open(struct inode * inode, struct file * file){    printk("%s enter.\n", __func__);    devm_gpio_request_one(dev, gpj1_3_pin,GPIOF_OUT_INIT_HIGH,"gpj1-3");    pinctrl=devm_pinctrl_get(dev);    pinctrl_out=pinctrl_lookup_state(pinctrl,"out");    pinctrl_in=pinctrl_lookup_state(pinctrl,"in");    return 0;}static ssize_t gpj1_3_read(struct file *file, char __user *to, size_t count, loff_t *off){    int voltage;    printk("%s enter.\n", __func__);    pinctrl_select_state(pinctrl,pinctrl_in);    voltage=gpio_get_value(gpj1_3_pin);    copy_to_user(to,&voltage,sizeof(voltage));    return sizeof(voltage);}static ssize_t gpj1_3_write (struct file *file, const char __user *from, size_t count, loff_t *off){    int voltage;    printk("%s enter.\n", __func__);    pinctrl_select_state(pinctrl,pinctrl_out);    copy_from_user(&voltage,from,sizeof(voltage));    gpio_set_value(gpj1_3_pin,voltage);    return sizeof(voltage);}static int gpj1_3_release(struct inode *inode, struct file *file){    devm_gpio_free(dev,gpj1_3_pin);    return 0;}static const struct file_operations gpj1_3_fops={      .owner   = THIS_MODULE,      .open     = gpj1_3_open,      .read     = gpj1_3_read,      .write    = gpj1_3_write,    .release = gpj1_3_release,  };  static int pinctrl_probe(struct platform_device *pdev) {    int error;    dev = &pdev->dev;    printk("%s enter.\n", __func__);    if (!dev->of_node) {            dev_err(dev, "no platform data.\n");            goto err0;    }    gpj1_3_pin=of_get_named_gpio(dev->of_node,"tiny4412,demo",0);    error=alloc_chrdev_region(&devid, 0, dev_num, "gpj1_3");    if(error){        dev_err(dev, "alloc region failed.\n");        goto err0;    }    major = MAJOR(devid);    cdev_init(&gpj1_3_cdev, &gpj1_3_fops);    cdev_add(&gpj1_3_cdev, MKDEV(major, 0), dev_num);        gpj_class=class_create(THIS_MODULE,"gpj_1_3");          class_dev=device_create(gpj_class, NULL, devid, NULL, devname);     return 0;err0:        return -EINVAL;}static int pinctrl_remove(struct platform_device *pdev) {    printk("%s enter.\n", __func__);    unregister_chrdev_region(devid,dev_num);    cdev_del(&gpj1_3_cdev);    device_destroy(gpj_class,MKDEV(major, 0));    class_destroy(gpj_class);    return 0;}static const struct of_device_id dt_ids[] = {        { .compatible = "gpio_j1-3", },        {},};MODULE_DEVICE_TABLE(of, dt_ids);static struct platform_driver pinctrl_driver = {    .driver        = {         .name    = "gpj1_3",         .of_match_table    = of_match_ptr(dt_ids),    },     .probe        = pinctrl_probe,     .remove        = pinctrl_remove,};static int pinctrl_init(void){    int ret;    printk("%s enter.\n", __func__);         ret = platform_driver_register(&pinctrl_driver);        if (ret)            printk(KERN_ERR "int demo: probe failed: %d\n", ret);        return ret;}static void pinctrl_exit(void){    printk("%s enter.\n", __func__);    platform_driver_unregister(&pinctrl_driver);}module_init(pinctrl_init);module_exit(pinctrl_exit);MODULE_LICENSE("GPL");

测试程序:

include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>int main(){        int fd;        int i;        fd=open("/dev/gpj_1_3",O_RDWR);        while(1){                i=0;                write(fd,&i,sizeof(i));                sleep(1);                i=1;                write(fd,&i,sizeof(i));                sleep(1);        }        return 0;}

这里写图片描述