中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站推廣預(yù)期達(dá)到的目標(biāo)泰安網(wǎng)絡(luò)推廣培訓(xùn)

網(wǎng)站推廣預(yù)期達(dá)到的目標(biāo),泰安網(wǎng)絡(luò)推廣培訓(xùn),設(shè)計(jì)頭條,wordpress網(wǎng)站導(dǎo)航子菜單往期內(nèi)容 本專欄往期內(nèi)容: Pinctrl子系統(tǒng)和其主要結(jié)構(gòu)體引入Pinctrl子系統(tǒng)pinctrl_desc結(jié)構(gòu)體進(jìn)一步介紹Pinctrl子系統(tǒng)中client端設(shè)備樹相關(guān)數(shù)據(jù)結(jié)構(gòu)介紹和解析inctrl子系統(tǒng)中Pincontroller構(gòu)造過程驅(qū)動(dòng)分析:imx_pinctrl_soc_info結(jié)構(gòu)體 input子系統(tǒng)專欄…

往期內(nèi)容

本專欄往期內(nèi)容:

  1. Pinctrl子系統(tǒng)和其主要結(jié)構(gòu)體引入
  2. Pinctrl子系統(tǒng)pinctrl_desc結(jié)構(gòu)體進(jìn)一步介紹
  3. Pinctrl子系統(tǒng)中client端設(shè)備樹相關(guān)數(shù)據(jù)結(jié)構(gòu)介紹和解析
  4. inctrl子系統(tǒng)中Pincontroller構(gòu)造過程驅(qū)動(dòng)分析:imx_pinctrl_soc_info結(jié)構(gòu)體

input子系統(tǒng)專欄:

  1. 專欄地址:input子系統(tǒng)
  2. input角度:I2C觸摸屏驅(qū)動(dòng)分析和編寫一個(gè)簡(jiǎn)單的I2C驅(qū)動(dòng)程序
    – 末片,有往期內(nèi)容觀看順序

I2C子系統(tǒng)專欄:

  1. 專欄地址:IIC子系統(tǒng)
  2. 具體芯片的IIC控制器驅(qū)動(dòng)程序分析:i2c-imx.c-CSDN博客
    – 末篇,有往期內(nèi)容觀看順序

總線和設(shè)備樹專欄:

  1. 專欄地址:總線和設(shè)備樹
  2. 設(shè)備樹與 Linux 內(nèi)核設(shè)備驅(qū)動(dòng)模型的整合-CSDN博客
    – 末篇,有往期內(nèi)容觀看順序

img

前言

本節(jié)就不提供相關(guān)源碼文件了,各個(gè)代碼塊處都有標(biāo)明該函數(shù)的文件路徑,需要的可以自行去查看。

主要講解作為使用者來說去使用pinctrl,其相關(guān)驅(qū)動(dòng)程序是如何去進(jìn)行獲取pinctrl信息,對(duì)其進(jìn)行解析將引腳轉(zhuǎn)為map,在轉(zhuǎn)為setting存儲(chǔ)起來,去進(jìn)行使用,也就是其如何去配置、復(fù)用引腳的。

1.回顧client的數(shù)據(jù)結(jié)構(gòu)

看之前的文章:Pinctrl子系統(tǒng)中client端設(shè)備樹相關(guān)數(shù)據(jù)結(jié)構(gòu)介紹和解析

右側(cè)是Pinctrl節(jié)點(diǎn),左側(cè)是client端節(jié)點(diǎn)。Pinctrl節(jié)點(diǎn)中設(shè)置了要使用的引腳的信息以及復(fù)用的功能,client節(jié)點(diǎn)則是對(duì)要使用的引腳進(jìn)行引用,其實(shí)就是模塊的設(shè)備節(jié)點(diǎn)。

img

img

  Pin Controller:有自己的驅(qū)動(dòng)程序
virtual_pincontroller {compatible = "100ask,virtual_pinctrl";myled_pin: myled_pin {functions = "gpio";groups = "pin0";configs = <0x11223344>;};
};GPIO Controller:有自己的驅(qū)動(dòng)程序
gpio_virt: virtual_gpiocontroller {compatible = "100ask,virtual_gpio";gpio-controller;#gpio-cells = <2>;ngpios = <4>;
};Client:有自己的驅(qū)動(dòng)程序
myled {compatible = "100ask,leddrv";led-gpios = <&gpio_virt 0 GPIO_ACTIVE_LOW>;pinctrl-names = "default";pinctrl-0 = <&myled_pin>;	
};另一種寫法(正確寫法):讓GPIO和Pinctrl之間建立聯(lián)系
/ {pinctrl_virt: virtual_pincontroller {compatible = "100ask,virtual_pinctrl";myled_pin: myled_pin {functions = "gpio";groups = "pin0";configs = <0x11223344>;};i2cgrp: i2cgrp {functions = "i2c", "i2c";groups = "pin0", "pin1";configs = <0x11223344  0x55667788>;};};gpio_virt: virtual_gpiocontroller {compatible = "100ask,virtual_gpio";gpio-controller;#gpio-cells = <2>;ngpios = <4>;gpio-ranges = <&pinctrl_virt 0 0 4>;  //GPIO控制器的第0號(hào)引腳對(duì)應(yīng)pinctrl_virt的第0號(hào)引腳(也就是對(duì)應(yīng)myled_pin),數(shù)量為4};myled {compatible = "100ask,leddrv";led-gpios = <&gpio_virt 2 GPIO_ACTIVE_LOW>;};
};

2.client的pinctrl構(gòu)造過程

相同state的描述引腳的設(shè)備樹節(jié)點(diǎn)如何轉(zhuǎn)換為pinctrl_map,這些pinctrl_map又如何轉(zhuǎn)換為pinctrl_setting存放在pinctrl_state結(jié)構(gòu)體中的settings鏈表中

2.1 總圖

比較長(zhǎng),看下圖就行了。

img

really_probe pinctrl_bind_pinsdev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);dev->pins->p = devm_pinctrl_get(dev); create_pinctrl(dev);ret = pinctrl_dt_to_map(p);for_each_maps(maps_node, i, map) {ret = add_setting(p, map);}dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_DEFAULT);	

2.2 解析

如果想深入了解各個(gè)代碼的含義,可以繼續(xù)看:

really_probe  //\Linux-4.9.88\drivers\base\dd.c//* If using pinctrl, bind pins now before probing */pinctrl_bind_pins //\Linux-4.9.88\drivers\base\dd.cdev->pins->p = devm_pinctrl_get(dev); //直接從該函數(shù)進(jìn)入看p = pinctrl_get(dev);//D\Linux-4.9.88\drivers\pinctrl\core.c

pinctrl_get內(nèi)部實(shí)現(xiàn)如下,根據(jù)其注釋可以知道,去獲取到pinctrl的句柄,但是在第一次的時(shí)候肯定是沒有的,所以最后會(huì)去調(diào)用create_pinctrl函數(shù)去創(chuàng)建pinctrl

\Linux-4.9.88\drivers\pinctrl\core.c/*** pinctrl_get() - retrieves the pinctrl handle for a device* @dev: the device to obtain the handle for*/
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);if (p != NULL) {dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");kref_get(&p->users);return p;}return create_pinctrl(dev);
}

進(jìn)入create_pinctrl函數(shù)看看:

\Linux-4.9.88\drivers\pinctrl\core.c
/static struct pinctrl *create_pinctrl(struct device *dev)
{struct pinctrl *p;               // 指向創(chuàng)建的引腳控制結(jié)構(gòu)體const char *devname;             // 設(shè)備的名稱struct pinctrl_maps *maps_node;  // 引腳映射節(jié)點(diǎn)指針int i;                           // 循環(huán)計(jì)數(shù)器struct pinctrl_map const *map;   // 當(dāng)前的引腳映射int ret;                         // 存儲(chǔ)返回值,用于錯(cuò)誤檢查/* * 為每個(gè)映射創(chuàng)建狀態(tài)存儲(chǔ)結(jié)構(gòu)體 pinctrl* 消費(fèi)者可以通過 pinctrl_get() 請(qǐng)求該引腳控制句柄*/p = kzalloc(sizeof(*p), GFP_KERNEL);if (p == NULL) {dev_err(dev, "failed to alloc struct pinctrl\n");return ERR_PTR(-ENOMEM);}p->dev = dev;                    // 關(guān)聯(lián)設(shè)備指針INIT_LIST_HEAD(&p->states);      // 初始化引腳控制的狀態(tài)列表INIT_LIST_HEAD(&p->dt_maps);     // 初始化設(shè)備樹的引腳映射列表// 將設(shè)備樹映射到引腳控制結(jié)構(gòu)體中ret = pinctrl_dt_to_map(p);if (ret < 0) {                   // 檢查映射是否成功kfree(p);                 // 釋放已分配的內(nèi)存return ERR_PTR(ret);      // 返回錯(cuò)誤指針}devname = dev_name(dev);          // 獲取設(shè)備名稱mutex_lock(&pinctrl_maps_mutex);  // 加鎖以保護(hù)全局映射/* 遍歷所有引腳控制映射以找到合適的映射 */for_each_maps(maps_node, i, map) {/* 檢查映射是否屬于當(dāng)前設(shè)備 */if (strcmp(map->dev_name, devname))continue;// 將映射添加到引腳控制結(jié)構(gòu)體中ret = add_setting(p, map);/** 此時(shí)添加設(shè)置可能會(huì):* - 延遲:如果引腳控制設(shè)備尚未可用* - 失敗:如果設(shè)置是 hog 類型并且引腳控制設(shè)備尚不可用* 如果返回的錯(cuò)誤不是 -EPROBE_DEFER,則積累錯(cuò)誤* 以檢查是否有 -EPROBE_DEFER 的情況,因?yàn)槟鞘亲钤愀獾那闆r。*/if (ret == -EPROBE_DEFER) {pinctrl_free(p, false);     // 釋放 pinctrl 結(jié)構(gòu)體mutex_unlock(&pinctrl_maps_mutex);  // 解鎖return ERR_PTR(ret);        // 返回延遲錯(cuò)誤指針}}mutex_unlock(&pinctrl_maps_mutex);  // 解鎖映射互斥量if (ret < 0) {/* 如果發(fā)生延遲以外的其他錯(cuò)誤,返回錯(cuò)誤 */pinctrl_free(p, false);return ERR_PTR(ret);}kref_init(&p->users);            // 初始化引用計(jì)數(shù)/* 將 pinctrl 句柄添加到全局列表中 */mutex_lock(&pinctrl_list_mutex);list_add_tail(&p->node, &pinctrl_list);mutex_unlock(&pinctrl_list_mutex);return p;  // 返回創(chuàng)建的引腳控制結(jié)構(gòu)體
}

其中最主要的就是ret = pinctrl_dt_to_map(p);將設(shè)備樹節(jié)點(diǎn)轉(zhuǎn)為mapping,ret = add_setting(p, map);將mapping轉(zhuǎn)為setting并添加進(jìn)pinctrl結(jié)構(gòu)體中。這個(gè)在之前對(duì)client端的相關(guān)結(jié)構(gòu)體介紹的時(shí)候也有講解過,下面來看看代碼中是如何實(shí)現(xiàn)的:

2.2.1 轉(zhuǎn)mapping

\Linux-4.9.88\drivers\pinctrl\devicetree.c
int pinctrl_dt_to_map(struct pinctrl *p)
{struct device_node *np = p->dev->of_node;   // 獲取設(shè)備樹節(jié)點(diǎn)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 啟用時(shí),p->dev 可能沒有從 DT 中實(shí)例化 */if (!np) {if (of_have_populated_dt())dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");return 0;}// 斷言引腳控制設(shè)置ret = dt_gpio_assert_pinctrl(p);if (ret) {dev_dbg(p->dev, "failed to assert pinctrl setting: %d\n", ret);return ret;}// 獲取節(jié)點(diǎn)引用of_node_get(np);/* 遍歷每個(gè)狀態(tài) ID */for (state = 0; ; state++) {// 獲取當(dāng)前狀態(tài)的引腳控制屬性名,如 "pinctrl-0", "pinctrl-1" 等propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);prop = of_find_property(np, propname, &size);   // 查找屬性kfree(propname);if (!prop) {// 若狀態(tài)為 0 但找不到屬性,說明沒有定義if (state == 0) {of_node_put(np);return -ENODEV;}break;   // 沒有更多狀態(tài)}list = prop->value;       // 獲取屬性值列表size /= sizeof(*list);    // 計(jì)算列表中的項(xiàng)數(shù)// 從 "pinctrl-names" 中讀取狀態(tài)名ret = of_property_read_string_index(np, "pinctrl-names", state, &statename);/** 如果沒有在 `pinctrl-names` 中找到狀態(tài)名,將狀態(tài)名設(shè)置為 `pinctrl-*`* 屬性名中的 ID 值。例如,"pinctrl-0" 中的 `0` 可以作為狀態(tài)名*/if (ret < 0) {// 跳過 "pinctrl-" 的 8 個(gè)字符,使用屬性名中的 IDstatename = prop->name + 8;}// 遍歷每個(gè)引用的引腳配置節(jié)點(diǎn)for (config = 0; config < size; config++) {phandle = be32_to_cpup(list++);    // 獲取 phandle 值// 查找引腳配置節(jié)點(diǎn) ---- 下圖中標(biāo)注  1np_config = of_find_node_by_phandle(phandle);if (!np_config) {dev_err(p->dev, "prop %s index %i invalid phandle\n",prop->name, config);ret = -EINVAL;goto err;}// 解析引腳配置節(jié)點(diǎn),并創(chuàng)建對(duì)應(yīng)的映射 --- 下圖中標(biāo)注  2ret = dt_to_map_one_config(p, statename, np_config);of_node_put(np_config);if (ret < 0)goto err;}// 如果 DT 中沒有項(xiàng),生成一個(gè)空狀態(tài)表項(xiàng)if (!size) {ret = dt_remember_dummy_state(p, statename);if (ret < 0)goto err;}}return 0;err:pinctrl_dt_free_maps(p);  // 如果有錯(cuò)誤,釋放分配的映射return ret;
}

img

來看看ret = dt_to_map_one_config(p, statename, np_config);是如何解析設(shè)備樹節(jié)點(diǎn)中的引腳,轉(zhuǎn)為map。

dt_to_map_one_config 函數(shù)用于解析一個(gè)設(shè)備樹中的引腳配置節(jié)點(diǎn) (np_config),并將其轉(zhuǎn)換為內(nèi)核 pinctrl 映射表。這個(gè)過程涉及查找引腳控制器設(shè)備 (pinctrl_dev),并調(diào)用設(shè)備特定的解析函數(shù)來生成映射表。 其中最重要的就是調(diào)用到了pinctrl_desc->pinctrl_ops->dt_node_to_map,這個(gè)在之前的pincontroller的數(shù)據(jù)結(jié)構(gòu)講解中有提過(Pinctrl子系統(tǒng)pinctrl_desc結(jié)構(gòu)體進(jìn)一步介紹)。接下來看代碼:

\Linux-4.9.88\Linux-4.9.88\drivers\pinctrl\devicetree.cstatic 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;/* 查找包含 np_config 的引腳控制器節(jié)點(diǎn) */np_pctldev = of_node_get(np_config);  // 獲取配置節(jié)點(diǎn)的引用for (;;) {np_pctldev = of_get_next_parent(np_pctldev);  // 獲取上級(jí)節(jié)點(diǎn)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);  // 釋放節(jié)點(diǎn)引用/* 如果未找到引腳控制器,假設(shè)稍后會(huì)出現(xiàn) */return -EPROBE_DEFER;}pctldev = get_pinctrl_dev_from_of_node(np_pctldev);  // 獲取引腳控制器設(shè)備if (pctldev)break;  // 找到引腳控制器設(shè)備,退出循環(huán)/* 不要延遲對(duì) hog 配置的探測(cè)(避免循環(huán)依賴) */if (np_pctldev == p->dev->of_node) {of_node_put(np_pctldev);return -ENODEV;}}of_node_put(np_pctldev);  // 釋放父節(jié)點(diǎn)的引用/** 調(diào)用引腳控制器驅(qū)動(dòng)解析設(shè)備樹節(jié)點(diǎn),并生成映射表項(xiàng)*/ops = pctldev->desc->pctlops;  // 獲取引腳控制器的操作函數(shù)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);  // 解析配置if (ret < 0)return ret;/* 將映射表項(xiàng)保存以備后用 */return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}
  • 查找引腳控制器設(shè)備:函數(shù)首先查找與 np_config 對(duì)應(yīng)的引腳控制器節(jié)點(diǎn)。通過向上遍歷父節(jié)點(diǎn),找到第一個(gè)包含配置的 pinctrl_dev,這是引腳控制器的核心設(shè)備。如果找不到合適的引腳控制器,返回 -EPROBE_DEFER 表示稍后再次嘗試探測(cè)。
  • 避免循環(huán)依賴:在遍歷父節(jié)點(diǎn)時(shí),如果發(fā)現(xiàn)父節(jié)點(diǎn)是當(dāng)前設(shè)備自身(hog 配置),則返回 -ENODEV 以避免循環(huán)依賴。
  • 解析設(shè)備樹節(jié)點(diǎn):找到引腳控制器設(shè)備后,通過 pctlops->dt_node_to_map 調(diào)用設(shè)備特定的函數(shù)來解析 np_config 節(jié)點(diǎn)并生成映射表項(xiàng)。
  • 存儲(chǔ)映射表項(xiàng):最后,通過 dt_remember_or_free_map 函數(shù)將生成的映射表項(xiàng)存儲(chǔ)到 pinctrl 結(jié)構(gòu)體中,以便后續(xù)使用。

ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);調(diào)用的是哪些map函數(shù)呢????這就得去Pincontroller的驅(qū)動(dòng)程序中去看了,因?yàn)檫@個(gè)函數(shù)是pinctrl_desc->pinctrl_ops的,是屬于Pincontroller的:\Linux-4.9.88\drivers\pinctrl\freescale\pinctrl-imx.c📎pinctrl-imx.c

static const struct pinctrl_ops imx_pctrl_ops = {.get_groups_count = imx_get_groups_count,.get_group_name = imx_get_group_name,.get_group_pins = imx_get_group_pins,.pin_dbg_show = imx_pin_dbg_show,.dt_node_to_map = imx_dt_node_to_map,  //就是這個(gè)函數(shù).dt_free_map = imx_dt_free_map,
};
static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,struct device_node *np,struct pinctrl_map **map, unsigned *num_maps)
{struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);const struct imx_pinctrl_soc_info *info = ipctl->info;const struct imx_pin_group *grp;struct pinctrl_map *new_map;struct device_node *parent;int map_num = 1;int i, j;/** 首先找到該節(jié)點(diǎn)的引腳組,并檢查是否需要為引腳創(chuàng)建配置映射*/grp = imx_pinctrl_find_group_by_name(info, np->name);if (!grp) {dev_err(info->dev, "unable to find group for node %s\n",np->name);return -EINVAL;}// 確定所需的映射數(shù)量if (info->flags & IMX8_USE_SCU) {map_num += grp->npins;} else {for (i = 0; i < grp->npins; i++) {if (!(grp->pins[i].pin_conf.pin_memmap.config &IMX_NO_PAD_CTL))map_num++;}}// 分配內(nèi)存存儲(chǔ)新映射new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);if (!new_map)return -ENOMEM;*map = new_map;*num_maps = map_num;/* 創(chuàng)建復(fù)用映射 */parent = of_get_parent(np);if (!parent) {kfree(new_map);return -EINVAL;}new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;new_map[0].data.mux.function = parent->name;new_map[0].data.mux.group = np->name;of_node_put(parent);/* 創(chuàng)建配置映射 */new_map++;for (i = j = 0; i < grp->npins; i++) {if (info->flags & IMX8_USE_SCU) {new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;new_map[j].data.configs.group_or_pin =pin_get_name(pctldev, grp->pins[i].pin);new_map[j].data.configs.configs =(unsigned long *)&grp->pins[i].pin_conf.pin_scu.mux;new_map[j].data.configs.num_configs = 2;j++;} else if (!(grp->pins[i].pin_conf.pin_memmap.config & IMX_NO_PAD_CTL)) {new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;new_map[j].data.configs.group_or_pin =pin_get_name(pctldev, grp->pins[i].pin);new_map[j].data.configs.configs =&grp->pins[i].pin_conf.pin_memmap.config;new_map[j].data.configs.num_configs = 1;j++;}}dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",(*map)->data.mux.function, (*map)->data.mux.group, map_num);return 0;
}

imx_dt_node_to_map 函數(shù)用于將指定設(shè)備樹節(jié)點(diǎn) (np) 轉(zhuǎn)換為 pinctrl_map 映射表,并將其存儲(chǔ)在 map 指針中,供引腳控制子系統(tǒng)使用。此函數(shù)特定于 i.MX 系列硬件平臺(tái),通過設(shè)備樹節(jié)點(diǎn)的信息生成引腳配置和復(fù)用映射。

  1. 獲取引腳組

    • 使用 imx_pinctrl_find_group_by_name 函數(shù),根據(jù)節(jié)點(diǎn)名稱 (np->name) 查找對(duì)應(yīng)的引腳組 (grp)。
  2. 計(jì)算映射數(shù)量

    • 如果 info->flags 標(biāo)記中設(shè)置了 IMX8_USE_SCU,則每個(gè)引腳都需要一個(gè)配置映射,因此總映射數(shù)為 1 + grp->npins。
    • 否則,遍歷每個(gè)引腳,僅為需要配置的引腳增加映射數(shù)。
  3. 內(nèi)存分配

    • 使用 kmalloc 為映射數(shù)組分配內(nèi)存,并初始化 mapnum_maps 指針。
    • 如果內(nèi)存分配失敗,函數(shù)返回 -ENOMEM 錯(cuò)誤。
  4. 創(chuàng)建復(fù)用映射

    • 獲取父節(jié)點(diǎn),檢查其名稱并為其創(chuàng)建復(fù)用 (MUX) 映射。
    • 將父節(jié)點(diǎn)的 name 作為 function,當(dāng)前節(jié)點(diǎn)的 name 作為 group
  5. 創(chuàng)建配置映射

    • 遍歷引腳組中的每個(gè)引腳,若符合條件,則創(chuàng)建配置映射。
    • 使用 pin_get_name 函數(shù)獲取引腳名稱,并設(shè)置相應(yīng)的配置。
    • IMX8_USE_SCU 標(biāo)志影響配置內(nèi)容;如果未設(shè)置此標(biāo)志,則僅為未設(shè)置 IMX_NO_PAD_CTL 的引腳創(chuàng)建配置。
  6. 調(diào)試信息

    • 使用 dev_dbg 輸出映射的 function、group 和映射數(shù)量 (map_num) 以供調(diào)試。

請(qǐng)?zhí)砑訄D片描述

2.2.2 mapping轉(zhuǎn)setting

那么解析獲取到mapping后,就要去轉(zhuǎn)化為setting,回到create_pinctrl函數(shù):

\Linux-4.9.88\drivers\pinctrl\core.c
/static struct pinctrl *create_pinctrl(struct device *dev)
{struct pinctrl *p;               // 指向創(chuàng)建的引腳控制結(jié)構(gòu)體const char *devname;             // 設(shè)備的名稱struct pinctrl_maps *maps_node;  // 引腳映射節(jié)點(diǎn)指針int i;                           // 循環(huán)計(jì)數(shù)器struct pinctrl_map const *map;   // 當(dāng)前的引腳映射int ret;                         // 存儲(chǔ)返回值,用于錯(cuò)誤檢查//...............// 將設(shè)備樹映射到引腳控制結(jié)構(gòu)體中ret = pinctrl_dt_to_map(p);devname = dev_name(dev);          // 獲取設(shè)備名稱mutex_lock(&pinctrl_maps_mutex);  // 加鎖以保護(hù)全局映射/* 遍歷所有引腳控制映射以找到合適的映射 */for_each_maps(maps_node, i, map) {/* 檢查映射是否屬于當(dāng)前設(shè)備 */if (strcmp(map->dev_name, devname))continue;// 將映射添加到引腳控制結(jié)構(gòu)體中ret = add_setting(p, map);}//...............}

直接省略掉其它內(nèi)容,對(duì)于pinctrl_dt_to_map在上文講到過,那么接下來就是add_setting函數(shù),把每一個(gè)pinctrl_map轉(zhuǎn)換為pinctrl_setting:

static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
{struct pinctrl_state *state;struct pinctrl_setting *setting;int ret;// 查找指定狀態(tài),如果不存在則創(chuàng)建一個(gè)新的狀態(tài)state = find_state(p, map->name);if (!state)state = create_state(p, map->name);if (IS_ERR(state))return PTR_ERR(state);// 如果映射類型是 PIN_MAP_TYPE_DUMMY_STATE,則無需添加設(shè)置,直接返回if (map->type == PIN_MAP_TYPE_DUMMY_STATE)return 0;// 為 pinctrl_setting 結(jié)構(gòu)體分配內(nèi)存,用于存儲(chǔ)此設(shè)置的信息setting = kzalloc(sizeof(*setting), GFP_KERNEL);if (setting == NULL) {dev_err(p->dev,"failed to alloc struct pinctrl_setting\n");return -ENOMEM;}// 設(shè)置類型,表示這是一個(gè)復(fù)用組或引腳配置setting->type = map->type;// 獲取映射中指定的 pinctrl_dev(引腳控制設(shè)備)setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);if (setting->pctldev == NULL) {// 如果設(shè)備名稱無法解析,釋放內(nèi)存并判斷是否需要延遲加載驅(qū)動(dòng)kfree(setting);// 對(duì)于 hog 引腳,不允許延遲加載,防止循環(huán)依賴if (!strcmp(map->ctrl_dev_name, map->dev_name))return -ENODEV;// 設(shè)備驅(qū)動(dòng)還未加載,輸出提示信息并返回 -EPROBE_DEFER 表示延遲加載dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",map->ctrl_dev_name);return -EPROBE_DEFER;}// 設(shè)置設(shè)備名稱setting->dev_name = map->dev_name;// 根據(jù)映射類型,將映射轉(zhuǎn)換為具體的設(shè)置內(nèi)容switch (map->type) {case PIN_MAP_TYPE_MUX_GROUP:// 如果是引腳復(fù)用組,調(diào)用 pinmux_map_to_setting 進(jìn)行設(shè)置轉(zhuǎn)換ret = pinmux_map_to_setting(map, setting);break;case PIN_MAP_TYPE_CONFIGS_PIN:case PIN_MAP_TYPE_CONFIGS_GROUP:// 如果是引腳或組的配置映射,調(diào)用 pinconf_map_to_setting 進(jìn)行設(shè)置轉(zhuǎn)換ret = pinconf_map_to_setting(map, setting);break;default:// 其他類型無效,返回錯(cuò)誤ret = -EINVAL;break;}if (ret < 0) {// 如果設(shè)置轉(zhuǎn)換失敗,釋放分配的內(nèi)存并返回錯(cuò)誤碼kfree(setting);return ret;}// 將新的設(shè)置添加到狀態(tài)的設(shè)置列表末尾list_add_tail(&setting->node, &state->settings);return 0;
}

主要就是pinmux_map_to_settingpinconf_map_to_setting函數(shù), 根據(jù)映射類型(復(fù)用組、引腳配置等),調(diào)用相應(yīng)的函數(shù) (pinmux_map_to_settingpinconf_map_to_setting) 將映射轉(zhuǎn)換為具體的引腳設(shè)置。 pinmux和pinconf在Pinccontroller結(jié)構(gòu)體的講解中也講過

先來看pinmux_map_to_setting函數(shù), 將一個(gè) pinctrl_map(引腳控制映射)條目中的復(fù)用功能映射轉(zhuǎn)換為一個(gè)具體的 pinctrl_setting 設(shè)置,用于配置指定設(shè)備的引腳復(fù)用功能。

  • 設(shè)備和操作集獲取:獲取 pinctrl_dev(引腳控制設(shè)備)和 pinmux_ops 操作集,用于查詢功能對(duì)應(yīng)的引腳組并設(shè)置引腳復(fù)用。
  • 功能選擇器索引轉(zhuǎn)換:將 map->data.mux.function 中指定的功能名稱轉(zhuǎn)換為功能選擇器索引,并存儲(chǔ)在 setting->data.mux.func 中。
  • 功能支持組查詢:通過 pmxops->get_function_groups 函數(shù)獲取該功能支持的引腳組列表和數(shù)量,確保該功能可以選擇特定的引腳組。
  • 引腳組驗(yàn)證:如果映射條目中指定了具體的引腳組名稱,則檢查該組是否在功能的支持列表中;如果未指定,則使用默認(rèn)的第一個(gè)組。
  • 組選擇器索引轉(zhuǎn)換:將引腳組名稱轉(zhuǎn)換為組選擇器索引,并存儲(chǔ)在 setting->data.mux.group 中。
  • 返回設(shè)置:將轉(zhuǎn)換后的功能和組選擇器索引存入 pinctrl_setting,用于后續(xù)的引腳控制配置操作。如果過程中發(fā)生錯(cuò)誤,則返回相應(yīng)的錯(cuò)誤碼。
\Linux-4.9.88\drivers\pinctrl\pinmux.c
int pinmux_map_to_setting(struct pinctrl_map const *map,struct pinctrl_setting *setting)
{// 獲取 pinctrl_dev 設(shè)備和 pinmux_ops 操作集,用于執(zhí)行引腳復(fù)用操作struct pinctrl_dev *pctldev = setting->pctldev;const struct pinmux_ops *pmxops = pctldev->desc->pmxops;char const * const *groups;  // 存儲(chǔ)功能所支持的組名unsigned num_groups;         // 功能所支持的組的數(shù)量int ret;const char *group;// 如果設(shè)備不支持引腳復(fù)用操作,返回錯(cuò)誤if (!pmxops) {dev_err(pctldev->dev, "does not support mux function\n");return -EINVAL;}// 將功能名稱轉(zhuǎn)換為功能選擇器索引ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);if (ret < 0) {dev_err(pctldev->dev, "invalid function %s in map table\n",map->data.mux.function);return ret;}setting->data.mux.func = ret;  // 設(shè)置功能選擇器// 查詢?cè)摴δ軐?duì)應(yīng)的引腳組,獲取組的列表和組數(shù)ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,&groups, &num_groups);if (ret < 0) {dev_err(pctldev->dev, "can't query groups for function %s\n",map->data.mux.function);return ret;}// 如果功能不支持任何引腳組,返回錯(cuò)誤if (!num_groups) {dev_err(pctldev->dev,"function %s can't be selected on any group\n",map->data.mux.function);return -EINVAL;}// 如果映射指定了特定的引腳組,驗(yàn)證該組是否存在于支持的組列表中if (map->data.mux.group) {group = map->data.mux.group;ret = match_string(groups, num_groups, group);if (ret < 0) {dev_err(pctldev->dev,"invalid group \"%s\" for function \"%s\"\n",group, map->data.mux.function);return ret;}} else {// 如果未指定引腳組,則使用默認(rèn)的第一個(gè)組group = groups[0];}// 將組名轉(zhuǎn)換為組選擇器索引ret = pinctrl_get_group_selector(pctldev, group);if (ret < 0) {dev_err(pctldev->dev, "invalid group %s in map table\n",map->data.mux.group);return ret;}setting->data.mux.group = ret;  // 設(shè)置組選擇器return 0;  // 成功返回 0
}

再來看看pinconf_map_to_setting函數(shù), 將 pinctrl_map(引腳控制映射)中的引腳或引腳組的配置映射轉(zhuǎn)換為 pinctrl_setting 設(shè)置,用于對(duì)指定設(shè)備的引腳或引腳組進(jìn)行特定的配置。

  • 設(shè)備獲取:從 pinctrl_setting 中獲取 pinctrl_dev 設(shè)備,用于引腳或引腳組的配置映射。

  • 配置類型判斷:根據(jù) setting->type 判斷配置類型。

    • 單引腳配置 (PIN_MAP_TYPE_CONFIGS_PIN):根據(jù)引腳名稱獲取引腳索引,并存儲(chǔ)在 setting->data.configs.group_or_pin 字段中。
    • 引腳組配置 (PIN_MAP_TYPE_CONFIGS_GROUP):根據(jù)引腳組名稱獲取引腳組選擇器索引,并存儲(chǔ)在 setting->data.configs.group_or_pin 字段中。
  • 配置項(xiàng)存儲(chǔ):將 map 中的配置數(shù)量和配置數(shù)組存儲(chǔ)到 setting 中,以便后續(xù)的配置應(yīng)用。

  • 返回狀態(tài):如果成功執(zhí)行映射和存儲(chǔ),則返回 0;如果引腳或組未找到,或類型無效,則返回相應(yīng)的錯(cuò)誤碼。

int pinconf_map_to_setting(struct pinctrl_map const *map,struct pinctrl_setting *setting)
{// 獲取與當(dāng)前設(shè)置相關(guān)聯(lián)的 pinctrl_dev 設(shè)備struct pinctrl_dev *pctldev = setting->pctldev;int pin;// 根據(jù)配置類型執(zhí)行相應(yīng)的操作switch (setting->type) {case PIN_MAP_TYPE_CONFIGS_PIN:  // 單個(gè)引腳配置// 根據(jù)引腳名稱獲取引腳索引pin = pin_get_from_name(pctldev, map->data.configs.group_or_pin);if (pin < 0) {  // 如果獲取失敗,打印錯(cuò)誤信息并返回錯(cuò)誤碼dev_err(pctldev->dev, "could not map pin config for \"%s\"",map->data.configs.group_or_pin);return pin;}// 將引腳索引存儲(chǔ)在設(shè)置的 group_or_pin 字段中setting->data.configs.group_or_pin = pin;break;case PIN_MAP_TYPE_CONFIGS_GROUP:  // 引腳組配置// 根據(jù)引腳組名稱獲取引腳組選擇器索引pin = pinctrl_get_group_selector(pctldev, map->data.configs.group_or_pin);if (pin < 0) {  // 如果獲取失敗,打印錯(cuò)誤信息并返回錯(cuò)誤碼dev_err(pctldev->dev, "could not map group config for \"%s\"",map->data.configs.group_or_pin);return pin;}// 將組選擇器索引存儲(chǔ)在設(shè)置的 group_or_pin 字段中setting->data.configs.group_or_pin = pin;break;default:// 如果配置類型無效,返回 -EINVAL 錯(cuò)誤碼return -EINVAL;}// 設(shè)置配置項(xiàng)的數(shù)量和配置數(shù)組setting->data.configs.num_configs = map->data.configs.num_configs;setting->data.configs.configs = map->data.configs.configs;return 0;  // 成功返回 0
}

3.切換state情景分析

這一部分看下圖簡(jiǎn)單了解一下就行了。

img

really_probepinctrl_bind_pinspinctrl_select_state/* Apply all the settings for the new state */list_for_each_entry(setting, &state->settings, node) {switch (setting->type) {case PIN_MAP_TYPE_MUX_GROUP:ret = pinmux_enable_setting(setting);ret = ops->set_mux(...);break;case PIN_MAP_TYPE_CONFIGS_PIN:case PIN_MAP_TYPE_CONFIGS_GROUP:ret = pinconf_apply_setting(setting);ret = ops->pin_config_group_set(...);break;default:ret = -EINVAL;break;}	
http://m.risenshineclean.com/news/64186.html

相關(guān)文章:

  • 萬網(wǎng)域名注冊(cè)網(wǎng)站網(wǎng)頁制作模板的網(wǎng)站
  • 商城網(wǎng)站開發(fā)視頻東莞網(wǎng)站建設(shè)排名
  • 怎么做網(wǎng)站地圖的樣式惡意點(diǎn)擊軟件有哪些
  • 購(gòu)物網(wǎng)站開發(fā)的描述幽默軟文廣告經(jīng)典案例
  • 昆明seo網(wǎng)站建設(shè)濟(jì)寧百度競(jìng)價(jià)推廣
  • 公關(guān)公司屬于什么行業(yè)北京網(wǎng)站seo設(shè)計(jì)
  • 建網(wǎng)站用什么發(fā)票創(chuàng)建軟件平臺(tái)該怎么做
  • pc網(wǎng)站建設(shè)需要提供哪些資料愛客crm
  • wordpress建站過程線上推廣的渠道有哪些
  • 十堰網(wǎng)站設(shè)計(jì)公司成都網(wǎng)多多
  • 新余網(wǎng)站制作關(guān)鍵詞seo優(yōu)化排名公司
  • 代理網(wǎng)頁游戲要多少錢福州seo網(wǎng)站管理
  • 青海網(wǎng)站建設(shè)公司軟文通
  • 網(wǎng)站開發(fā)名詞解釋百度問答兼職怎么做
  • matlab做網(wǎng)站爬蟲廣東疫情最新數(shù)據(jù)
  • 網(wǎng)站在線客服管理系統(tǒng)哈爾濱網(wǎng)站優(yōu)化
  • 網(wǎng)站的測(cè)試和網(wǎng)站上線宣傳渠道和宣傳方式有哪些
  • 廣州凡科公司是外包嗎seo免費(fèi)外鏈工具
  • 網(wǎng)站開發(fā)制做seo搜索引擎優(yōu)化工作內(nèi)容
  • 關(guān)于做問卷星網(wǎng)站的畢業(yè)論文安裝百度到手機(jī)桌面
  • wordpress u-degin優(yōu)化軟件刷排名seo
  • uc投放廣告網(wǎng)站要自己做嗎如何做網(wǎng)頁制作
  • 如何查到別人的網(wǎng)站做哪些競(jìng)價(jià)詞國(guó)外網(wǎng)站制作
  • 臥龍區(qū)微網(wǎng)站建設(shè)百度手機(jī)助手app下載并安裝
  • 自己做視頻網(wǎng)站有點(diǎn)卡公司網(wǎng)站首頁設(shè)計(jì)
  • 公司的網(wǎng)站怎么做廣州網(wǎng)絡(luò)推廣公司有哪些
  • 西數(shù) 網(wǎng)站建設(shè)seo網(wǎng)站推廣優(yōu)化就找微源優(yōu)化
  • html5響應(yīng)式網(wǎng)站建設(shè)今日新聞?wù)畻l
  • 的網(wǎng)站建立seo方式包括
  • 嘉興網(wǎng)站制作建設(shè)國(guó)內(nèi)專業(yè)的seo機(jī)構(gòu)