驱动代码分析
引脚名字和编号解析与存储
- imx6ull.dtsi
iomuxc: iomuxc@20e0000 {
compatible = "fsl,imx6ul-iomuxc";
reg = <0x20e0000 0x4000>;
};
- pinctrl-imx6ul.c
static struct platform_driver imx6ul_pinctrl_driver = {
.driver = {
.name = "imx6ul-pinctrl",
.of_match_table = imx6ul_pinctrl_of_match,
.suppress_bind_attrs = true,
},
.probe = imx6ul_pinctrl_probe,
};
static const struct of_device_id imx6ul_pinctrl_of_match[] = {
{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
{ /* sentinel */ }
};
设备树当中的compatible属性与驱动平台当中的imx6ul_pinctrl_of_match相匹配,匹配成功以后执行对应的imx6ul_pinctrl_probe函数。
imx6ul_pinctrl_probe()函数
drivers/pinctrl/freescale/pinctrl-imx6ul.c
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
const struct imx_pinctrl_soc_info *pinctrl_info;
const struct of_device_id *match;
//通过dev获取对应的pinctrl信息
pinctrl_info = of_device_get_match_data(&pdev->dev);
if (!pinctrl_info)
return -ENODEV;
return imx_pinctrl_probe(pdev, pinctrl_info);
}
imx6ul_pinctrl_pads
- 引脚的编号和名字表
IMX_PINCTRL_PIN宏
drivers/pinctrl/freescale/pinctrl-imx.h
#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
PINCTRL_PIN宏
include/linux/pinctrl/pinctrl.h
#define PINCTRL_PIN(a, b) { .number = a, .name = b }
imx_pinctrl_probe()函数
int imx_pinctrl_probe(struct platform_device *pdev,
const struct imx_pinctrl_soc_info *info)
{
struct imx_pinctrl *ipctl; //存储外设基地址,引脚的名字和编号原始表
struct pinctrl_desc *imx_pinctrl_desc; //以基数树的方式存储引脚名字和编号,以及三个操作函数
...
//为imx_pinctrl分配内存
ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
...
//获取寄存器的资源,这里是获取reg即reg = <0x20e0000 0x4000>
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
//将iomuxc物理地址映射为虚拟地址,寄存器的起始地址
ipctl->base = devm_ioremap_resource(&pdev->dev, res);
...
//为imx_pinctrl_desc开辟内存
imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),GFP_KERNEL);
...
imx_pinctrl_desc->name = dev_name(&pdev->dev);
imx_pinctrl_desc->pins = info->pins;
imx_pinctrl_desc->npins = info->npins;
//pinctrl的三个操作函数
imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
imx_pinctrl_desc->pmxops = &imx_pmx_ops;
imx_pinctrl_desc->confops = &imx_pinconf_ops;
imx_pinctrl_desc->owner = THIS_MODULE;
...
ipctl->info = info;
ipctl->dev = &pdev->dev;
...
//这个函数主要是初始化ipctl->pctl的值,为每一个pin创建一个pindesc,将pindesc放到pin_desc_tree基数树当中
//最后一个参数是pinctrl_dev结构体指针(现在是一个空指针)
ret = devm_pinctrl_register_and_init(&pdev->dev,
imx_pinctrl_desc, ipctl,
&ipctl->pctl);
...
//将pinctrl当中的配置信息存储起来
ret = imx_pinctrl_probe_dt(pdev, ipctl);
...
//将iomuxc节点当中的pin-name等信息解析出来并配置
return pinctrl_enable(ipctl->pctl);
...
return ret;
}
devm_pinctrl_register_and_init()函数
drivers/pinctrl/core.c
int devm_pinctrl_register_and_init(struct device *dev,
struct pinctrl_desc *pctldesc,
void *driver_data,
struct pinctrl_dev **pctldev)
{
struct pinctrl_dev **ptr;
int error;
ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL);
//调用
error = pinctrl_register_and_init(pctldesc, dev, driver_data, pctldev);
*ptr = *pctldev;
devres_add(dev, ptr);
return 0;
}
pinctrl_register_and_init()函数
int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data,
struct pinctrl_dev **pctldev)
{
struct pinctrl_dev *p;
//调用
p = pinctrl_init_controller(pctldesc, dev, driver_data);
*pctldev = p;
return 0;
}
pinctrl_init_controller()函数
drivers/pinctrl/core.c
三个参数imx_pinctrl_desc, iomuxc节点对应device,ipctl
static struct pinctrl_dev *
pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
void *driver_data)
{
struct pinctrl_dev *pctldev;
...
//为pinctrl_dev分配内存
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
...
pctldev->owner = pctldesc->owner;
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data; // 就是imux_pinctrl ipctl
/*初始化基数树*/
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
//使用pin_desc_tree作为根节点来初始化基数树
...
pctldev->dev = dev;
...
ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
...
return pctldev;
...
}
pinctrl_register_pins()函数
drivers/pinctrl/core.c
static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pins, //imx6ul_pinctrl_pads,
unsigned num_descs) //芯片引脚数量
{
unsigned i;
int ret = 0;
for (i = 0; i < num_descs; i++) {//num_descs表示pin的数量
//为每个pin创建一个pin_desc,赋值对应的name
//其中pin【i】就是IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0)等
ret = pinctrl_register_one_pin(pctldev, &pins[i]);
if (ret)
return ret;
}
return 0;
}
pinctrl_register_one_pin()函数
drivers/pinctrl/core.c
static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pin)
{
struct pin_desc *pindesc;
//从pin_desc基数树当中查找对应编号的pin_desc结构体
pindesc = pin_desc_get(pctldev, pin->number);
//因为之前只初始化了基数树,因此肯定是查不到的
if (pindesc) {
dev_err(pctldev->dev, "pin %d already registered\n",
pin->number);
return -EINVAL;
}
//为pindesc动态分配内存
pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
...
pindesc->pctldev = pctldev;
...
//pin是存储名字和编号的结构体
if (pin->name) {
//将对应的名字赋给pin_desc
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的结构体指针
radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
...
return 0;
}