文章目录
一、pinctrl子系统简介
pinctrl子系统的平台设备驱动文件:drivers/pinctrl/freescale/pinctrl-imx6ul.c
pinctrl子系统预先确定引脚的数量和名字:
1、为每个引脚的配置信息分配内存
2、管理每个引脚的使用状态
平台驱动结构体如下:
static struct platform_driver imx6ul_pinctrl_driver = {
.driver = {
.name = "imx6ul-pinctrl",
.owner = THIS_MODULE,
// #define of_match_ptr(_ptr) (_ptr)
// imx6ul_pinctrl_of_match 详见下
.of_match_table = of_match_ptr(imx6ul_pinctrl_of_match),
},
.probe = imx6ul_pinctrl_probe,
.remove = imx_pinctrl_remove,
};
此平台驱动的设备匹配表:imx6ul_pinctrl_of_match
static struct of_device_id imx6ul_pinctrl_of_match[] = {
// imx6ul_pinctrl_info 存放pin的名字、编号、总数等。
{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
{ /* sentinel */ }
};
/*
* Struct used for matching a device
*/
struct of_device_id {
char name[32];
char type[32];
char compatible[128];
const void *data;
};
pin信息:imx6ul_pinctrl_info
static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = {
// 指向一个结构体数组,主要保存 pin 的名字和编号
.pins = imx6ul_pinctrl_pads,
// 上面数组的 size
.npins = ARRAY_SIZE(imx6ul_pinctrl_pads),
};
struct imx_pinctrl_soc_info {
struct device *dev;
const struct pinctrl_pin_desc *pins;
unsigned int npins;
struct imx_pin_reg *pin_regs;
struct imx_pin_group *groups;
unsigned int ngroups;
struct imx_pmx_func *functions;
unsigned int nfunctions;
unsigned int flags;
u32 grp_index;
};
imx6ul_pinctrl_pads保存pin的名字和编号(编号和pin mux reg 的 offset 成正比)
/* Pad names for the pinmux subsystem */
static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = {
// MX6UL_PAD_RESERVE0 = 0,
// #define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
// #define PINCTRL_PIN(a, b) { .number = a, .name = b }
IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0),
// MX6UL_PAD_RESERVE1 = 1,此值与 对应 pin 的 mux reg offset 成 4 倍关系
IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE1),
...
IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA07),
};
/**
* struct pinctrl_pin_desc - boards/machines provide information on their
* pins, pads or other muxable units in this struct
* @number: unique pin number from the global pin number space
* @name: a name for this pin
* @drv_data: driver-defined per-pin data. pinctrl core does not touch this
*/
struct pinctrl_pin_desc {
unsigned number;
const char *name;
void *drv_data;
};
imx6ul_pinctrl_probe()函数
pinctrl子系统驱动文件: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;
pinctrl_info = of_device_get_match_data(&pdev->dev);
if (!pinctrl_info)
return -ENODEV;
match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);
if (!match)
return -ENODEV;
pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
return imx_pinctrl_probe(pdev, pinctrl_info);
}
// 此结构体一般嵌在下面的结构体中
struct pinctrl_pin_desc {
// 引脚编号,和 mux_reg 也就是服用寄存器offset值成4倍关系
unsigned number;
// 引脚名字
const char *name;
void *drv_data;
};
// 此结构体一般嵌在下面的结构体的data成员中
struct imx_pinctrl_soc_info {
// 指向一个结构体数组
const struct pinctrl_pin_desc *pins;
// 上面数组的长度
unsigned int npins;
unsigned int flags;
const char *gpr_compatible;
...
}
/*
* Struct used for matching a device
*/
struct of_device_id {
char name[32];
char type[32];
char compatible[128];
const void *data;
};
of_device_get_match_data()函数
drivers/of/device.c
const void *of_device_get_match_data(const struct device *dev)
{
const struct of_device_id *match;
match = of_match_device(dev->driver->of_match_table, dev);
if (!match)
return NULL;
return match->data;
}
of_match_device()函数
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
if ((!matches) || (!dev->of_node))
return NULL;
return of_match_node(matches, dev->of_node);
}
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
// number 表示 pin 的编号,与此pin的 mux 寄存器的偏移地址成正比,4倍关系
#define PINCTRL_PIN(a, b) { .number = a, .name = b }
引脚编号与复用寄存器的关系
pin.num = mux/4
imx_pinctrl:存储引脚的名字和编号原始表
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;
...
ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
...
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ipctl->base = devm_ioremap_resource(&pdev->dev, res);
...
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;
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;
platform_set_drvdata(pdev, ipctl);
...
ret = devm_pinctrl_register_and_init(&pdev->dev,
imx_pinctrl_desc, ipctl,
&ipctl->pctl);
...
ret = imx_pinctrl_probe_dt(pdev, ipctl);
...
return pinctrl_enable(ipctl->pctl);
...
return ret;
}
pinctrl_desc:以基数树的方式存储引脚的名字,记录引脚的使用状态
devm_pinctrl_register_and_init()函数
drivers/pinctrl/core.c
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);
if (IS_ERR(p))
return PTR_ERR(p);
*pctldev = p;
return 0;
}
pinctrl_init_controller()函数
drivers/pinctrl/core.c
static struct pinctrl_dev *
pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
void *driver_data)
{
struct pinctrl_dev *pctldev;
...
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
...
pctldev->owner = pctldesc->owner;
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
/*初始化基数树*/
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
...
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,
unsigned num_descs)
{
unsigned i;
int ret = 0;
for (i = 0; i < num_descs; i++) {
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;
pindesc = 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);
...
pindesc->pctldev = pctldev;
...
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;
}
...
radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
...
return 0;
}