linux pinctrl驱动分析 altas200模块

  • 准备
  • 设备树节点
  • pinctrl驱动分析
    • pcs_probe函数
      • pcs_allocate_pin_table函数
      • pcs_add_pin函数
      • pinctrl_register_one_pin函数
      • pinctrl_enable函数
      • pinctrl_claim_hogs函数
  • 总结
    • 主要结构体
      • pcs_device
      • pinctrl_desc
      • pinctrl_dev
    • 总结

准备

  使用的源码包为华为官方的ascend200AI加速模块的SDK,其下载地址位于:点击跳转
  使用的固件与驱动版本为:1.0.9.alpha
  压缩包名称为:A200-3000-sdk_20.2.0.zip
  将A200-3000-sdk_20.2.0.zip解压后可以看到Ascend310-source-minirc.tar.gz压缩包,这个压缩包里有ascend200AI加速模块的linux内核源码包、设备树及驱动文件等。

设备树节点

  pinctrl的设备树节点位于source/dtb/hi1910-asic-000-pinctrl.dtsi
  这里以pmx_ctrl1节点和pmx_cfg1两个节点为例:

 pmx_ctrl1: pinmux@110080000 {compatible = "pinctrl-single", "pinctrl-single1";reg = <0x1 0x10080000 0x0 0x38>;#gpio-range-cells = <3>;pinctrl-single,register-width = <32>;pinctrl-single,function-mask = <7>;    gpio2_pmx_func: gpio2_pmx_func {pinctrl-single,pins = <0x2c    0x0>;};gpio2_pmx_idle: gpio2_pmx_idle {pinctrl-single,pins = <0x2c    0x0>;};gpio3_pmx_func: gpio3_pmx_func {pinctrl-single,pins = <0x30    0x0>;};gpio3_pmx_idle: gpio3_pmx_idle {pinctrl-single,pins = <0x30    0x0>;};                                    };
    pmx_cfg1: pinmux@110080800 {compatible = "pinconf-single", "pinctrl-single1";reg = <0x1 0x10080800 0x0 0x05c>;pinctrl-single,register-width = <32>;  gpio6_cfg_func: gpio6_cfg_func {pinctrl-single,pins = <0x28  0>;pinctrl-single,bias-pulldown = <0 2 0 2>;pinctrl-single,bias-pullup = <1 1 0 1>;   pinctrl-single,drive-strength = <0x30 0x70>;             };gpio6_cfg_idle: gpio6_cfg_idle {pinctrl-single,pins = <0x28  0>;pinctrl-single,bias-pulldown = <0 2 0 2>;pinctrl-single,bias-pullup = <1 1 0 1>;pinctrl-single,drive-strength = <0x30 0x70>;              };gpio2_cfg_func: gpio2_cfg_func {pinctrl-single,pins = <0x50  0>;pinctrl-single,bias-pulldown = <2 2 0 2>;pinctrl-single,bias-pullup = <0 1 0 1>;pinctrl-single,drive-strength = <0x30 0x70>;  pinctrl-single,input-schmitt-enable = <8 8 0 8>;     };gpio2_cfg_idle: gpio2_cfg_idle {pinctrl-single,pins = <0x50  0>;pinctrl-single,bias-pulldown = <2 2 0 2>;pinctrl-single,bias-pullup = <0 1 0 1>;pinctrl-single,drive-strength = <0x30 0x70>;  pinctrl-single,input-schmitt-enable = <8 8 0 8>;             };gpio3_cfg_func: gpio3_cfg_func {pinctrl-single,pins = <0x54  0>;pinctrl-single,bias-pulldown = <0 2 0 2>;pinctrl-single,bias-pullup = <1 1 0 1>;pinctrl-single,drive-strength = <0x30 0x70>;  pinctrl-single,input-schmitt-enable = <8 8 0 8>;     };gpio3_cfg_idle: gpio3_cfg_idle {pinctrl-single,pins = <0x54  0>;pinctrl-single,bias-pulldown = <0 2 0 2>;pinctrl-single,bias-pullup = <1 1 0 1>;pinctrl-single,drive-strength = <0x30 0x70>;  pinctrl-single,input-schmitt-enable = <8 8 0 8>;             };                  };

pinctrl驱动分析

  设备树节点无论是pinconf-single还是pinctrl-single匹配到的都是source\kernel\linux-4.19\drivers\pinctrl\pinctrl-single.c

pcs_probe函数

static int pcs_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;struct pcs_pdata *pdata;struct resource *res;struct pcs_device *pcs;const struct pcs_soc_data *soc;int ret;//of_device_get_match_data 判断dts中的compatible属性是否包含driver中指定的compatible,// 实际上返回的是dev->driver->of_match_table->data。// data是void *类型,自己如果想取到data里的值,就可以自己定义类型,里面可以放一些自己需要的参数。//of_device_get_match_data对于pmx_ctrl1节点,它的data为空,可以不管//而pmx_cfg1节点此时soc->flag=PCS_FEAT_PINCONF。让后给pcs分配内存//PCS_FEAT_PINCONF   (1 << 0)soc = of_device_get_match_data(&pdev->dev);if (WARN_ON(!soc))return -EINVAL;//申请pcs结构体内存,这个pdev->dev这个参数是为了绑定这片内存//devm_kzalloc分配的内存当指定的dev驱动被注销时会自动释放pcs = devm_kzalloc(&pdev->dev, sizeof(*pcs), GFP_KERNEL);if (!pcs)return -ENOMEM;//这个np是dtb转化的device_nodepcs->dev = &pdev->dev;pcs->np = np;raw_spin_lock_init(&pcs->lock);mutex_init(&pcs->mutex);//初始化链表INIT_LIST_HEAD(&pcs->gpiofuncs);//pcs->flags = PCS_FEAT_PINCONF = 1pcs->flags = soc->flags;//之后pcs->socdata指向soc结构体memcpy(&pcs->socdata, soc, sizeof(*soc));//获取"pinctrl-single,register-width"属性,好像是寄存器的位宽,都是32位的ret = of_property_read_u32(np, "pinctrl-single,register-width",&pcs->width);if (ret) {dev_err(pcs->dev, "register width not specified\n");return ret;}//pcs->fmask是7ret = of_property_read_u32(np, "pinctrl-single,function-mask",&pcs->fmask);if (!ret) {//存在属性,所以指向下面的代码//__ffs 用于找到一个int或者long行最高哪位是1,例如0x8000,就会返回15.//pcs->fshift 为2   pcs->fmax为1pcs->fshift = __ffs(pcs->fmask);pcs->fmax = pcs->fmask >> pcs->fshift;} else {/* If mask property doesn't exist, function mux is invalid. */pcs->fmask = 0;pcs->fshift = 0;pcs->fmax = 0;}//这个属性没有ret = of_property_read_u32(np, "pinctrl-single,function-off",&pcs->foff);if (ret)pcs->foff = PCS_OFF_DISABLED;//这个没有读到 也是0pcs->bits_per_mux = of_property_read_bool(np,"pinctrl-single,bit-per-mux");//pcs->bits_per_mux ? 2 : 1 为1//这个函数是老版的函数要找"#pinctrl-cells"属性,没有 直接返回0ret = pcs_quirk_missing_pinctrl_cells(pcs, np,pcs->bits_per_mux ? 2 : 1);if (ret) {dev_err(&pdev->dev, "unable to patch #pinctrl-cells\n");return ret;}//获取IORESOURCE_MEM资源,即reg属性//pmx_ctrl1节点reg = <0x1 0x10080000 0x0 0x38>;//pmx_cfg1节点为reg = <0x1 0x10080800 0x0 0x05c>;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) {dev_err(pcs->dev, "could not get resource\n");return -ENODEV;}//节点pmx_ctrl1//res->start:268959744 ----- res->end:268959799//resource_size:56//节点pmx_cfg1//res->start:268961792 ----- res->end:268961883//resource_size:92//devm_request_mem_region将res的物理空间iormmap映射出来,返回给pcs->res,能通过用户空间操作pcs->res = devm_request_mem_region(pcs->dev, res->start,resource_size(res), DRIVER_NAME);if (!pcs->res) {dev_err(pcs->dev, "could not get mem_region\n");return -EBUSY;}//这里的pcs的size和base就是映射出来的大小和基址pcs->size = resource_size(pcs->res);pcs->base = devm_ioremap(pcs->dev, pcs->res->start, pcs->size);if (!pcs->base) {dev_err(pcs->dev, "could not ioremap\n");return -ENODEV;}//pdev->device->device_data指针指向pcs,保存变量,pcs是malloc出来的内存platform_set_drvdata(pdev, pcs);//(pcs->width为32switch (pcs->width) {case 8:pcs->read = pcs_readb;pcs->write = pcs_writeb;break;case 16:pcs->read = pcs_readw;pcs->write = pcs_writew;break;case 32:pcs->read = pcs_readl;pcs->write = pcs_writel;break;default:break;}//DRIVER_NAME         "pinctrl-single"//构造pinctrl_desc结构体,desc.pctlops是引脚的操作功能,desc.pmxops是引脚复用功能//这两个函数是具体的硬件功能操作函数pcs->desc.name = DRIVER_NAME;pcs->desc.pctlops = &pcs_pinctrl_ops;pcs->desc.pmxops = &pcs_pinmux_ops;//pmx_cfg1://PCS_HAS_PINCONF = (pcs->flags & PCS_FEAT_PINCONF)//PCS_FEAT_PINCONF (1 << 0)//pcs->flag = PCS_FEAT_PINCONF    (1 << 0)//PCS_HAS_PINCONF = 1//注意:pmx_ctrl1节点没有flag属性,所以这个为0//pcs_pinconf_ops是配置功能,所以只有pmx_cfg1节点的desc有这个功能if (PCS_HAS_PINCONF)pcs->desc.confops = &pcs_pinconf_ops;pcs->desc.owner = THIS_MODULE;//这个函数啥也没干,只是设置pindesc等一些属性,主要是引脚树木等ret = pcs_allocate_pin_table(pcs);if (ret < 0)goto free;//pinctrl_register函数,构造pinctrl_dev结构体//1.传入pinctrl_desc,pctldev->desc指向传入的pinctrl_desc//2.申请pinctrl_dev结构体内存//3.初始化了pin_desc_tree、pin_group_tree、pin_function_tree三个树//4.检查pctldev->desc->pctlops是否有get_group_count和get_group_name函数//5.检查pctldev->desc->pmxops是否有必要的函数//6.检查pctldev->desc->confops是否有必要的函数//7.指向pinctrl_register_one_pin挨个注册管脚//8.将每个pin的pin_desc都加入到 &pcs->pctl(pinctrl_dev)管理起来ret = pinctrl_register_and_init(&pcs->desc, pcs->dev, pcs, &pcs->pctl);if (ret) {dev_err(pcs->dev, "could not register single pinctrl driver\n");goto free;}//去device_node找pinctrl-single,gpio-range和#pinctrl-single,gpio-range-cells,没有就直接返回了ret = pcs_add_gpio_func(np, pcs);if (ret < 0)goto free;//中断也没有,不用管pcs->socdata.irq = irq_of_parse_and_map(np, 0);if (pcs->socdata.irq)pcs->flags |= PCS_FEAT_IRQ;/* We still need auxdata for some omaps for PRM interrupts */pdata = dev_get_platdata(&pdev->dev);if (pdata) {if (pdata->rearm)pcs->socdata.rearm = pdata->rearm;if (pdata->irq) {pcs->socdata.irq = pdata->irq;pcs->flags |= PCS_FEAT_IRQ;}}//为0也不用管if (PCS_HAS_IRQ) {ret = pcs_irq_init_chained_handler(pcs, np);if (ret < 0)dev_warn(pcs->dev, "initialized with no interrupts\n");}dev_info(pcs->dev, "%i pins, size %u\n", pcs->desc.npins, pcs->size);return pinctrl_enable(pcs->pctl);free:pcs_free_resources(pcs);return ret;
}

pcs_allocate_pin_table函数

static int pcs_allocate_pin_table(struct pcs_device *pcs)
{int mux_bytes, nr_pins, i;int num_pins_in_register = 0;//mux_bytes = 4mux_bytes = pcs->width / BITS_PER_BYTE;//pinctrl-single,bit-per-mux属性未定义//所以bits_per_mux =0if (pcs->bits_per_mux) {pcs->bits_per_pin = fls(pcs->fmask);nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;num_pins_in_register = pcs->width / pcs->bits_per_pin;} else {nr_pins = pcs->size / mux_bytes;}//pmx_ctrl1节点://nr_pins = 0x38/4 = 14//pmx_cfg1节点://nr_pins = 0x5C/4 = 23dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins);//这个pcs->dev就是device_node//分配nr_pins个struct pinctrl_pin_desc *pa;的内存大小给pcs->pins.papcs->pins.pa = devm_kcalloc(pcs->dev,nr_pins, sizeof(*pcs->pins.pa),GFP_KERNEL);if (!pcs->pins.pa)return -ENOMEM;//npins表示每个控制器pin的数目pcs->desc.pins = pcs->pins.pa;pcs->desc.npins = nr_pins;for (i = 0; i < pcs->desc.npins; i++) {unsigned offset;int res;int byte_num;int pin_pos = 0;//pcs->bits_per_mux为0执行的是下面的那一句if (pcs->bits_per_mux) {byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE;offset = (byte_num / mux_bytes) * mux_bytes;pin_pos = i % num_pins_in_register;} else {//每次循环offset偏移加4offset = i * mux_bytes;}//传进来的pin_pos为0,这个函数貌似啥也没干,执行结束后只是pcs->pins.cur变成了14res = pcs_add_pin(pcs, offset, pin_pos);if (res < 0) {dev_err(pcs->dev, "error adding pins: %i\n", res);return res;}}printk("pcs_allocate_pin_table end\n");return 0;
}

pcs_add_pin函数

static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,unsigned pin_pos)
{struct pcs_soc_data *pcs_soc = &pcs->socdata;struct pinctrl_pin_desc *pin;int i;i = pcs->pins.cur;if (i >= pcs->desc.npins) {dev_err(pcs->dev, "too many pins, max %i\n",pcs->desc.npins);return -ENOMEM;}if (pcs_soc->irq_enable_mask) {unsigned val;val = pcs->read(pcs->base + offset);if (val & pcs_soc->irq_enable_mask) {dev_dbg(pcs->dev, "irq enabled at boot for pin at %lx (%x), clearing\n",(unsigned long)pcs->res->start + offset, val);val &= ~pcs_soc->irq_enable_mask;pcs->write(val, pcs->base + offset);}}pin = &pcs->pins.pa[i];pin->number = i;pcs->pins.cur++;return i;
}

pinctrl_register_one_pin函数

static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,const struct pinctrl_pin_desc *pin)
{struct pin_desc *pindesc;//查看是否已经注册这个pinpindesc = pin_desc_get(pctldev, pin->number);if (pindesc) {dev_err(pctldev->dev, "pin %d already registered\n",pin->number);return -EINVAL;}//分配内存pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);if (!pindesc)return -ENOMEM;/* Set owner */pindesc->pctldev = pctldev;/* Copy basic pin info */if (pin->name) {//如果指定了名字,则设定为默认pindesc->name = pin->name;} else {//设置默认名字pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);if (!pindesc->name) {kfree(pindesc);return -ENOMEM;}pindesc->dynamic_name = true;}pindesc->drv_data = pin->drv_data;//将该pin添加到pctldev中radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);pr_debug("registered pin %d (%s) on %s\n",pin->number, pindesc->name, pctldev->desc->name);return 0;
}

pinctrl_enable函数

int pinctrl_enable(struct pinctrl_dev *pctldev)
{int error;error = pinctrl_claim_hogs(pctldev);if (error) {dev_err(pctldev->dev, "could not claim hogs: %i\n",error);mutex_destroy(&pctldev->mutex);kfree(pctldev);return error;}mutex_lock(&pinctrldev_list_mutex);list_add_tail(&pctldev->node, &pinctrldev_list);mutex_unlock(&pinctrldev_list_mutex);pinctrl_init_device_debugfs(pctldev);return 0;
}

pinctrl_claim_hogs函数

pinctrl_claim_hogs()//构建pinctrl结构体pctldev->p = create_pinctrl(pctldev->dev, pctldev);{//分配pin ctrl占用的内存并初始化;p = kzalloc(sizeof(*p), GFP_KERNEL); //解析设备树节点信息ret = pinctrl_dt_to_map(p, pctldev);{for (state = 0; ; state++) {propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);//寻找这个节点下的pinctrl-%d属性prop = of_find_property(np, propname, &size);//根据state找到pinctrl-names中的第几个字符串,返回给statenameret = of_property_read_string_index(np, "pinctrl-names",state, &statename);for (config = 0; config < size; config++) {phandle = be32_to_cpup(list++);//查找整个设备树。从根节点开始,找到属性带pinctrl-%d的device_nodenp_config = of_find_node_by_phandle(phandle);//这个函数会找到pinctrl-%d属性的父节点//调用父节点的pctldev->desc->pctlop->dt_node_to_map函数//本驱动中dt_node_to_map会根据pinctrl-single,pins属性来设置复用寄存器的值ret = dt_to_map_one_config(p, pctldev, statename,np_config);}}}}
}

总结

主要结构体

pcs_device

 * struct pcs_device - pinctrl device instance* @res:   resources* @base:  virtual address of the controller* @saved_vals: saved values for the controller* @size:   size of the ioremapped area* @dev: device entry* @np:     device tree node* @pctl:   pin controller device* @flags: mask of PCS_FEAT_xxx values* @missing_nr_pinctrl_cells: for legacy binding, may go away* @socdata:    soc specific data* @lock:  spinlock for register access* @mutex:  mutex protecting the lists* @width:    bits per mux register* @fmask: function register mask* @fshift:   function register shift* @foff:    value to turn mux off* @fmax:  max number of functions in fmask* @bits_per_mux: number of bits per mux* @bits_per_pin: number of bits per pin* @pins:   physical pins on the SoC* @gpiofuncs:  list of gpio functions* @irqs: list of interrupt registers* @chip:    chip container for this instance* @domain: IRQ domain for this instance* @desc:   pin controller descriptor* @read:  register read function to use* @write: register write function to use
struct pcs_device {struct resource *res;void __iomem *base;void *saved_vals;unsigned size;struct device *dev;struct device_node *np;struct pinctrl_dev *pctl;unsigned flags;
#define PCS_CONTEXT_LOSS_OFF    (1 << 3)
#define PCS_QUIRK_SHARED_IRQ    (1 << 2)
#define PCS_FEAT_IRQ        (1 << 1)
#define PCS_FEAT_PINCONF    (1 << 0)struct property *missing_nr_pinctrl_cells;struct pcs_soc_data socdata;raw_spinlock_t lock;struct mutex mutex;unsigned width;unsigned fmask;unsigned fshift;unsigned foff;unsigned fmax;bool bits_per_mux;unsigned bits_per_pin;struct pcs_data pins;struct list_head gpiofuncs;struct list_head irqs;struct irq_chip chip;struct irq_domain *domain;struct pinctrl_desc desc;unsigned (*read)(void __iomem *reg);void (*write)(unsigned val, void __iomem *reg);
};

厂家自定义的结构体,probe函数主要是填充这个结构体,每个pinctrl控制器的节点会构造一个结构体

pinctrl_desc

/*** struct pinctrl_desc - pin controller descriptor, register this to pin* control subsystem* @name: name for the pin controller* @pins: an array of pin descriptors describing all the pins handled by*  this pin controller* @npins: number of descriptors in the array, usually just ARRAY_SIZE()*    of the pins field above* @pctlops: pin control operation vtable, to support global concepts like*  grouping of pins, this is optional.* @pmxops: pinmux operations vtable, if you support pinmuxing in your driver* @confops: pin config operations vtable, if you support pin configuration in* your driver* @owner: module providing the pin controller, used for refcounting* @num_custom_params: Number of driver-specific custom parameters to be parsed* from the hardware description* @custom_params: List of driver_specific custom parameters to be parsed from*    the hardware description* @custom_conf_items: Information how to print @params in debugfs, must be*   the same size as the @custom_params, i.e. @num_custom_params*/
struct pinctrl_desc {const char *name;const struct pinctrl_pin_desc *pins;unsigned int npins;const struct pinctrl_ops *pctlops;const struct pinmux_ops *pmxops;const struct pinconf_ops *confops;struct module *owner;
#ifdef CONFIG_GENERIC_PINCONFunsigned int num_custom_params;const struct pinconf_generic_params *custom_params;const struct pin_config_item *custom_conf_items;
#endif
};

pinctrl_desc描述了该pinctrl设备的相关信息,引脚数量,引脚配置操作函数,硬件功能操作函数,引脚复用操作函数

struct pinctrl_ops {//获取系统中pin groups的个数,后续的操作,将以相应的索引为单位(类似数组的下标,个数为数组的大小)int (*get_groups_count) (struct pinctrl_dev *pctldev);//获取指定group(由索引selector指定)的名称const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector);//获取指定group的所有pins(由索引selector指定),结果保存在pins(指针数组)和num_pins(指针)中int (*get_group_pins) (struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins);void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);//用于将device tree中的pin state信息转换为pin mapint (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps);void (*dt_free_map) (struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps);
};
struct pinmux_ops {//检查某个pin是否已作它用,用于管脚复用时的互斥int (*request) (struct pinctrl_dev *pctldev, unsigned offset);//request的反操作int (*free) (struct pinctrl_dev *pctldev, unsigned offset);//获取系统中function的个数int (*get_functions_count) (struct pinctrl_dev *pctldev);//获取指定function的名称const char *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector);//获取指定function所占用的pin groupint (*get_function_groups) (struct pinctrl_dev *pctldev, unsigned selector, const char * const **groups, unsigned *num_groups);//将指定的pin group(group_selector)设置为指定的function(func_selector)int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector);//以下是gpio相关的操作int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);void (*gpio_disable_free) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);int (*gpio_set_direction) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input);//为true时,说明该pin controller不允许某个pin作为gpio和其它功能同时使用bool strict;
};
struct pinconf_ops {#ifdef CONFIG_GENERIC_PINCONFbool is_generic;
#endif//获取指定 pin 的当前配置,保存在 config 指针中int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config);//设置指定pin的配置int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs);//获取指定pin group的配置项int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config);//设置指定pin group的配置项int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *configs, unsigned num_configs);......

pinctrl_dev

/*** struct pinctrl_dev - pin control class device* @node: node to include this pin controller in the global pin controller list* @desc: the pin controller descriptor supplied when initializing this pin*    controller* @pin_desc_tree: each pin descriptor for this pin controller is stored in*  this radix tree* @pin_group_tree: optionally each pin group can be stored in this radix tree* @num_groups: optionally number of groups can be kept here* @pin_function_tree: optionally each function can be stored in this radix tree* @num_functions: optionally number of functions can be kept here* @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,*  ranges are added to this list at runtime* @dev: the device entry for this pin controller* @owner: module providing the pin controller, used for refcounting* @driver_data: driver data for drivers registering to the pin controller*    subsystem* @p: result of pinctrl_get() for this device* @hog_default: default state for pins hogged by this device* @hog_sleep: sleep state for pins hogged by this device* @mutex: mutex taken on each pin controller specific action* @device_root: debugfs root for this device*/
struct pinctrl_dev {struct list_head node;struct pinctrl_desc *desc;struct radix_tree_root pin_desc_tree;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPSstruct radix_tree_root pin_group_tree;unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONSstruct radix_tree_root pin_function_tree;unsigned int num_functions;
#endifstruct list_head gpio_ranges;struct device *dev;struct module *owner;void *driver_data;struct pinctrl *p;struct pinctrl_state *hog_default;struct pinctrl_state *hog_sleep;struct mutex mutex;
#ifdef CONFIG_DEBUG_FSstruct dentry *device_root;
#endif
};

总结

  probe函数填充pcs_device结构体信息,pcs_allocate_pin_table遍历出所有pin的树木和信息,设置pcs->desc.pins和pcs->desc.npins。指向pinctrl_register_and_init,主要是为了构造pinctrl_dev结构体,初始化了pin_desc_tree、pin_group_tree、pin_function_tree三个树,检查pctldev->desc->pctlops、pmxops、pmxops是否有必要的函数,让后将每个pin的pin_desc加入到pinctrl_dev的pin_desc_tree串起来。pcs_add_gpio_func去device_node找pinctrl-single,gpio-range和#pinctrl-single,gpio-range-cells,没有就直接返回了。pinctrl_enable还会解析设备树节点查找是否有设置过pinctrl-%d和pinctrl-names的信息,pinctrl-%d属性的值是要使用pinctrl的节点,调用dt_node_to_map会根据pinctrl-single,pins属性来设置复用寄存器的值。gpio的子系统底层也会调用pinctrl,以后在研究

linux pinctrl驱动分析相关推荐

  1. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  2. Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)

    一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下: 1.1.基本特性 该芯片最大支持10 ...

  3. Linux spi驱动分析----SPI设备驱动(W25Q32BV)

    转载地址:http://blog.chinaunix.net/uid-25445243-id-4026974.html 一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它 ...

  4. Linux网卡驱动分析之RTL8139(五)

    Linux网卡驱动分析之RTL8139(五) deliver_skb(dev.c) // 该函数就是调用个协议的接收函数处理该skb 包,进入第三层网络层处理 static __inline__ in ...

  5. Linux UART驱动分析及测试

    1.Linux TTY驱动程序框架 Linux TTY驱动程序代码位于/drivers/tty下面.TTY的层次接口包括TTY应用层.TTY文件层.TTY线路规程层.TTY驱动层.TTY设备驱动层.T ...

  6. linux 网卡驱动分析,LINUX_网卡驱动分析

    LINUX_网卡驱动分析 (36页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 Linux DM9000网卡驱动程序完全分析说明仁 本文分 ...

  7. linux 网卡驱动分析,基于linux下网卡驱动分析及实现技术研究

    摘    要 Linux技术是当前计算机技术中最大的一个热点,在我国以及全世界得到了迅猛的发展,被广泛的应用于嵌入式系统.服务器.网络系统.安全等领域.从而使得掌握在 Linux环境下的开发技术,成为 ...

  8. linux 触摸屏驱动分析

    mini2440驱动分析系列之 ---------------------------------------Mini2440触摸屏程序分析 By JeefJiang July,8th,2009 这是 ...

  9. Linux网络设备驱动分析,以W5300以太网驱动为例

    前言 本文是笔者在分析Linux网络驱动时记录的笔记,在这里分享给大家.因为笔者目前也属于学习阶段,因此可能会存在分析不清楚甚至分析错误的地方,欢迎大家评判指正!! 版本说明 Linux内核版本:4. ...

最新文章

  1. 检测你的机子上装了什么版本的.net framework
  2. GPL协议 与 LGPL协议
  3. ITK:使用连通性细分具有相似统计信息的像素
  4. Direct2D的使用
  5. 数据库编程连接mysql_使用JDBC编程-连接MySQL数据库
  6. oracle中@,深入理解Oracle中的DBCA
  7. mysql concat 能否返回数字_关于Mysql中GROUP_CONCAT函数返回值长度的坑
  8. IAR8.3安装步骤
  9. 飞客蠕虫病毒的介绍与处理办法
  10. Flutter 页面弹出毛玻璃浮层
  11. 权威发布丨2020 中国开源先锋 33 人之心尖上的开源人物
  12. 携程航班信息爬取(python)---第一次写博客,不好请别见外!
  13. Grafana密码重置
  14. 以代码绘制圣诞,过快乐圣诞节!
  15. iOS实现微信发送位置效果
  16. HTMLCSS 【三】-- TABLES, DIVS, AND SPANS
  17. RIFF和WAVE文件格式
  18. 51单片机定时器介绍
  19. 烤仔喊你写作业 | 今天你做出来了吗?
  20. 数字图像处理课程实习——傅里叶变换与频域滤波

热门文章

  1. 【换脸详细教程】手把手教你进行AI换脸:换脸流程及源码详解
  2. UML应用开发详解(更新程度:完毕)
  3. python绘制六角星_python画六角星,目前本人只想出这一种方法,有没有更直接的?~~...
  4. 交通信号灯控制系统设计
  5. 初学后端,如何做好表结构设计?
  6. 安装双系统ubuntu(16.04,20.04)相关
  7. [寒江孤叶丶的Cocos2d-x之旅_30]Cocos2d-x 3.5 EditBox无法显示字体的原因
  8. C语言依然位居榜单前列,依然值得程序员学习
  9. Programming Differential Privacy第五章
  10. 解决neo4j数据库desktop版本与community版本并存导致desktop本地数据无法访问问题