PINCTRL代码

来源:互联网 发布:手机淘宝千牛怎么用 编辑:程序博客网 时间:2024/05/01 09:32

Linux Pin Ctrl 代码

1.kernel\drivers\pinctrl\qcom\pinctrl-msm8937.c
static int __init msm8937_pinctrl_init(void){return platform_driver_register(&msm8937_pinctrl_driver);}arch_initcall(msm8937_pinctrl_init);//在module_init()之前已经注册

int msm_pinctrl_probe(struct platform_device *pdev,      const struct msm_pinctrl_soc_data *soc_data){struct msm_pinctrl *pctrl;//一个总的msm平台相关的pinctrl_devstruct resource *res;int ret;u32 tlmm_emmc_boot_select;pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);pctrl->dev = &pdev->dev;pctrl->soc = soc_data;pctrl->chip = msm_gpio_template;spin_lock_init(&pctrl->lock);res = platform_get_resource(pdev, IORESOURCE_MEM, 0);pctrl->regs = devm_ioremap_resource(&pdev->dev, res);pctrl->irq = platform_get_irq(pdev, 0);//将dts中的interrupts通过irq controller有关的map函数,转化为linux irq num,类似于gpio_to_irq()API调用msm_pinctrl_desc.name = dev_name(&pdev->dev);msm_pinctrl_desc.pins = pctrl->soc->pins;msm_pinctrl_desc.npins = pctrl->soc->npins;pctrl->pctrl = pinctrl_register(&msm_pinctrl_desc, &pdev->dev, pctrl);//注册一个pinctrl_deviceret = msm_gpio_init(pctrl);pctrl->irq_chip_extn = &mpm_pinctrl_extn;platform_set_drvdata(pdev, pctrl);return 0;}

/** * 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 * @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 { //用来描述一个总的pinctrl 设备struct list_head node;struct pinctrl_desc *desc;struct radix_tree_root pin_desc_tree;struct 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};



struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,    struct device *dev, void *driver_data){struct pinctrl_dev *pctldev;int ret;pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);/* Initialize pin control device struct */pctldev->owner = pctldesc->owner;pctldev->desc = pctldesc;pctldev->driver_data = driver_data;INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);INIT_LIST_HEAD(&pctldev->gpio_ranges);pctldev->dev = dev;mutex_init(&pctldev->mutex);/* check core ops for sanity */if (pinctrl_check_ops(pctldev)) {dev_err(dev, "pinctrl ops lacks necessary functions\n");goto out_err;}/* If we're implementing pinmuxing, check the ops for sanity */if (pctldesc->pmxops) {if (pinmux_check_ops(pctldev))goto out_err;}/* If we're implementing pinconfig, check the ops for sanity */if (pctldesc->confops) {if (pinconf_check_ops(pctldev))goto out_err;}/* Register all the pins */dev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);//mutex_lock(&pinctrldev_list_mutex);list_add_tail(&pctldev->node, &pinctrldev_list);//注册设备到节点上mutex_unlock(&pinctrldev_list_mutex);pctldev->p = pinctrl_get(pctldev->dev);//pinctrl_get()API,通过解析dev设备节点下是否有"pinctrl-"属性,来获取dev设备使用的PIN脚的处理接口。                此处应该返回错误,接下来的if语句不会被执行。if (!IS_ERR(pctldev->p)) {pctldev->hog_default =pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);if (IS_ERR(pctldev->hog_default)) {dev_dbg(dev, "failed to lookup the default state\n");} else {if (pinctrl_select_state(pctldev->p,pctldev->hog_default))dev_err(dev,"failed to select default state\n");}pctldev->hog_sleep =pinctrl_lookup_state(pctldev->p,    PINCTRL_STATE_SLEEP);if (IS_ERR(pctldev->hog_sleep))dev_dbg(dev, "failed to lookup the sleep state\n");}pinctrl_init_device_debugfs(pctldev);return pctldev;}

struct  pinctrl结构体说明,每个使用pin control机制的设备(dts节点中有pinctrl-0,pinctrl-1属性)都会有该结构体来描述。
/** * struct pinctrl - per-device pin control state holder  * @node: global list node * @dev: the device using this pin control handle * @states: a list of states for this device * @state: the current state * @dt_maps: the mapping table chunks dynamically parsed from device tree for *this device, if any * @users: reference count */struct pinctrl {struct list_head node;struct device *dev;struct list_head states;struct pinctrl_state *state;struct list_head dt_maps;struct kref users;};
以eeprom设备节点为例。
eeprom0: qcom,eeprom@0 {
                ......
cell-index = <0>;
compatible = "qcom,eeprom";
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk0_default
&cam_sensor_rear_default>;
pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>;
                ......

};
cam_sensor_mclk0_default: cam_sensor_mclk0_default {
/* MCLK0 */
mux {
/* CLK, DATA */
pins = "gpio26";
function = "cam_mclk";
};


config {
pins = "gpio26";
bias-disable; /* No PULL */
drive-strength = <2>; /* 2 MA */
};
};


cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep {
/* MCLK0 */
mux {
/* CLK, DATA */
pins = "gpio26";
function = "cam_mclk";
};


config {
pins = "gpio26";
bias-pull-down; /* PULL DOWN */
drive-strength = <2>; /* 2 MA */
};
};

在eeprom设备的驱动文件通过platform_driver_register()注册时,必定会走到\kernel\drivers\base\dd.c文件的static int really_probe(struct device *dev, struct device_driver *drv)函数,进而执行ret = pinctrl_bind_pins(dev)函数。

/** * pinctrl_bind_pins() - called by the device core before probe * @dev: the device that is just about to probe */int pinctrl_bind_pins(struct device *dev){int ret;dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);if (!dev->pins)return -ENOMEM;dev->pins->p = devm_pinctrl_get(dev);//核心函数为pinctrl_get()if (IS_ERR(dev->pins->p)) {dev_dbg(dev, "no pinctrl handle\n");ret = PTR_ERR(dev->pins->p);goto cleanup_alloc;}dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_DEFAULT);if (IS_ERR(dev->pins->default_state)) {dev_dbg(dev, "no default pinctrl state\n");ret = 0;goto cleanup_get;}ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);if (ret) {dev_dbg(dev, "failed to activate default pinctrl state\n");goto cleanup_get;}return 0;}



struct pinctrl *pinctrl_get(struct device *dev){struct pinctrl *p;if (WARN_ON(!dev))return ERR_PTR(-EINVAL);/* * See if somebody else (such as the device core) has already * obtained a handle to the pinctrl for this device. In that case, * return another pointer to it. */p = find_pinctrl(dev);//系统内每个设备的pinctrl类型都会在pinctrl_list链表中if (p != NULL) {dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");kref_get(&p->users);return p;}return create_pinctrl(dev);//设备的驱动注册时,执行该函数}


static struct pinctrl *create_pinctrl(struct device *dev){struct pinctrl *p;const char *devname;struct pinctrl_maps *maps_node;int i;struct pinctrl_map const *map;int ret;/* * create the state cookie holder struct pinctrl for each * mapping, this is what consumers will get when requesting * a pin control handle with pinctrl_get() */p = kzalloc(sizeof(*p), GFP_KERNEL);p->dev = dev;INIT_LIST_HEAD(&p->states);INIT_LIST_HEAD(&p->dt_maps);ret = pinctrl_dt_to_map(p);if (ret < 0) {kfree(p);return ERR_PTR(ret);}devname = dev_name(dev);mutex_lock(&pinctrl_maps_mutex);/* Iterate over the pin control maps to locate the right ones */for_each_maps(maps_node, i, map) {/* Map must be for this device */if (strcmp(map->dev_name, devname))continue;ret = add_setting(p, map);/* * At this point the adding of a setting may: * * - Defer, if the pinctrl device is not yet available * - Fail, if the pinctrl device is not yet available, *   AND the setting is a hog. We cannot defer that, since *   the hog will kick in immediately after the device *   is registered. * * If the error returned was not -EPROBE_DEFER then we * accumulate the errors to see if we end up with * an -EPROBE_DEFER later, as that is the worst case. */if (ret == -EPROBE_DEFER) {pinctrl_free(p, false);mutex_unlock(&pinctrl_maps_mutex);return ERR_PTR(ret);}}mutex_unlock(&pinctrl_maps_mutex);if (ret < 0) {/* If some other error than deferral occured, return here */pinctrl_free(p, false);return ERR_PTR(ret);}kref_init(&p->users);/* Add the pinctrl handle to the global list */mutex_lock(&pinctrl_list_mutex);list_add_tail(&p->node, &pinctrl_list);mutex_unlock(&pinctrl_list_mutex);return p;}

下面来分析pinctrl_dt_to_map()函数。
int pinctrl_dt_to_map(struct pinctrl *p){struct device_node *np = p->dev->of_node;//eeprom的设备节点int state, ret;char *propname;struct property *prop;const char *statename;const __be32 *list;int size, config;phandle phandle;struct device_node *np_config;/* CONFIG_OF enabled, p->dev not instantiated from DT */if (!np) {if (of_have_populated_dt())dev_dbg(p->dev,"no of_node; not parsing pinctrl DT\n");return 0;}/* We may store pointers to property names within the node */of_node_get(np);/* For each defined state ID */for (state = 0; ; state++) {/* Retrieve the pinctrl-* property */propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);prop = of_find_property(np, propname, &size);//size代表什么意思? struct property结构体中int length变量。表示该property的value的存储大小?kfree(propname);if (!prop) {if (!state) {ret = -EINVAL;goto err;}break;}list = prop->value;//value值,表示cam_sensor_mclk0_default 或者cam_sensor_rear_default两个struct device_node的指针值?size /= sizeof(*list);//表示pinctrl-0属性中,有两个value,即cam_sensor_mclk0_default  cam_sensor_rear_default??/* Determine whether pinctrl-names property names the state */ret = of_property_read_string_index(np, "pinctrl-names",    state, &statename);//state为0时,statename为cam_default;state为1时,statename为cam_suspend/* * If not, statename is just the integer state ID. But rather * than dynamically allocate it and have to free it later, * just point part way into the property name for the string. */if (ret < 0) {/* strlen("pinctrl-") == 8 */statename = prop->name + 8;}/* For every referenced pin configuration node in it */for (config = 0; config < size; config++) {phandle = be32_to_cpup(list++);/* Look up the pin configuration node */np_config = of_find_node_by_phandle(phandle);//通过phandle找到cam_sensor_mclk0_default等节点if (!np_config) {dev_err(p->dev,"prop %s index %i invalid phandle\n",prop->name, config);ret = -EINVAL;goto err;}/* Parse the node */ret = dt_to_map_one_config(p, statename, np_config);//解析cam_sensor_mclk0_default节点,并保存在struct pinctrl_map结构体中of_node_put(np_config);if (ret < 0)goto err;}/* No entries in DT? Generate a dummy state table entry */if (!size) {ret = dt_remember_dummy_state(p, statename);if (ret < 0)goto err;}}return 0;err:pinctrl_dt_free_maps(p);return ret;}


static int dt_to_map_one_config(struct pinctrl *p, const char *statename,struct device_node *np_config){struct device_node *np_pctldev;struct pinctrl_dev *pctldev;const struct pinctrl_ops *ops;int ret;struct pinctrl_map *map;unsigned num_maps;/* Find the pin controller containing np_config */np_pctldev = of_node_get(np_config);for (;;) {np_pctldev = of_get_next_parent(np_pctldev);if (!np_pctldev || of_node_is_root(np_pctldev)) {dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",np_config->full_name);of_node_put(np_pctldev);/* OK let's just assume this will appear later then */return -EPROBE_DEFER;}pctldev = get_pinctrl_dev_from_of_node(np_pctldev);//找到之前注册的struct pinctrl_dev 设备if (pctldev)break;/* Do not defer probing of hogs (circular loop) */if (np_pctldev == p->dev->of_node) {of_node_put(np_pctldev);return -ENODEV;}}of_node_put(np_pctldev);/* * Call pinctrl driver to parse device tree node, and * generate mapping table entries */ops = pctldev->desc->pctlops;if (!ops->dt_node_to_map) {dev_err(p->dev, "pctldev %s doesn't support DT\n",dev_name(pctldev->dev));return -ENODEV;}ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);//解析节点中的pins,function,bias-disable等属性,并保存在struct pinctrl_map map中。if (ret < 0)return ret;/* Stash the mapping table chunk away for later use */return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);//}
struct pinctrl_map结构体中各变量的

struct pinctrl_map {const char *dev_name;const char *name;enum pinctrl_map_type type;const char *ctrl_dev_name;union {struct pinctrl_map_mux mux;struct pinctrl_map_configs configs;} data;};
经过ops->dt_node_to_map()转换后,以cam_sensor_mclk0_default节点为例,num_maps为3。
每个struct pinctrl_map的成员data分别为:
struct pinctrl_map_mux mux.type = PIN_MAP_TYPE_MUX_GROUP;
struct pinctrl_map_mux mux.data.mux.group = gpio26;
struct pinctrl_map_mux mux.function = cam_mclk;


struct pinctrl_map_configs configs.type = PIN_MAP_TYPE_CONFIGS_GROUP;
struct pinctrl_map_configs configs.group_or_pin = gpio26;
struct pinctrl_map_configs configs.configs = pinconf_to_config_packed(PIN_CONFIG_BIAS_DISABLE,0);
struct pinctrl_map_configs configs.num_configs = 2;


struct pinctrl_map_configs configs.type = PIN_MAP_TYPE_CONFIGS_GROUP;
struct pinctrl_map_configs configs.group_or_pin = gpio26;
struct pinctrl_map_configs configs.configs = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,2);
struct pinctrl_map_configs configs.num_configs = 2;

static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,   struct pinctrl_dev *pctldev,   struct pinctrl_map *map, unsigned num_maps){int i;struct pinctrl_dt_map *dt_map;/* Initialize common mapping table entry fields */for (i = 0; i < num_maps; i++) {map[i].dev_name = dev_name(p->dev);map[i].name = statename;if (pctldev)map[i].ctrl_dev_name = dev_name(pctldev->dev);}/* Remember the converted mapping table entries */dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);if (!dt_map) {dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");dt_free_map(pctldev, map, num_maps);return -ENOMEM;}dt_map->pctldev = pctldev;dt_map->map = map;dt_map->num_maps = num_maps;list_add_tail(&dt_map->node, &p->dt_maps);return pinctrl_register_map(map, num_maps, false);}


int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, bool dup){int i, ret;struct pinctrl_maps *maps_node;maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);if (!maps_node) {pr_err("failed to alloc struct pinctrl_maps\n");return -ENOMEM;}maps_node->num_maps = num_maps;maps_node->maps = maps;mutex_lock(&pinctrl_maps_mutex);list_add_tail(&maps_node->node, &pinctrl_maps);mutex_unlock(&pinctrl_maps_mutex);return 0;}

回到create_pinctrl()函数中的for_each_maps(maps_node, i, map) 部分

for_each_maps(maps_node, i, map) {  //遍历pinctrl_maps链表,/* Map must be for this device */if (strcmp(map->dev_name, devname))continue;ret = add_setting(p, map);if (ret == -EPROBE_DEFER) {pinctrl_free(p, false);mutex_unlock(&pinctrl_maps_mutex);return ERR_PTR(ret);}}mutex_unlock(&pinctrl_maps_mutex);kref_init(&p->users);/* Add the pinctrl handle to the global list */mutex_lock(&pinctrl_list_mutex);list_add_tail(&p->node, &pinctrl_list);//将每个设备的struct pinctrl加入到pinctrl_list链表中mutex_unlock(&pinctrl_list_mutex);return p;



static int add_setting(struct pinctrl *p, struct pinctrl_map const *map){struct pinctrl_state *state;struct pinctrl_setting *setting;int ret;state = find_state(p, map->name);if (!state)state = create_state(p, map->name);//按照pinctrl-names中的cam_default,cam_suspend创建struct pinctrl_state,加入到pinctrl的成员states链表上if (IS_ERR(state))return PTR_ERR(state);if (map->type == PIN_MAP_TYPE_DUMMY_STATE)return 0;setting = kzalloc(sizeof(*setting), GFP_KERNEL);if (setting == NULL) {dev_err(p->dev,"failed to alloc struct pinctrl_setting\n");return -ENOMEM;}setting->type = map->type;setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);if (setting->pctldev == NULL) { //该段代码不会走到kfree(setting);/* Do not defer probing of hogs (circular loop) */if (!strcmp(map->ctrl_dev_name, map->dev_name))return -ENODEV;/* * OK let us guess that the driver is not there yet, and * let's defer obtaining this pinctrl handle to later... */dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",map->ctrl_dev_name);return -EPROBE_DEFER;}setting->dev_name = map->dev_name;//将struct pinctrl_map变量,转换为struct pinctrl_settingswitch (map->type) {case PIN_MAP_TYPE_MUX_GROUP://mux节点的会走到ret = pinmux_map_to_setting(map, setting);break;case PIN_MAP_TYPE_CONFIGS_PIN:case PIN_MAP_TYPE_CONFIGS_GROUP://config节点的会走到ret = pinconf_map_to_setting(map, setting);break;default:ret = -EINVAL;break;}list_add_tail(&setting->node, &state->settings);return 0;}




struct pinctrl_setting {struct list_head node;enum pinctrl_map_type type;struct pinctrl_dev *pctldev;const char *dev_name;union {struct pinctrl_setting_mux mux;struct pinctrl_setting_configs configs;} data;};





在设备驱动的具体probe函数中,可以通过
devm_pinctrl_get()
pinctrl_lookup_state()
pinctrl_select_state()
来设置具体PIN脚的function和config了。




0 0
原创粉丝点击