pinctrl_select_state函数使用示例

  在驱动中,芯片休眠后,为了节省电流,需要设置引脚的状态,可参考如下的例子。

在引脚控制文件中,添加如下定义如kernel/arch/arm/boot/dts/qcom/msm8996-pinctrl.c

gpio_12_active: gpio_12_active {
           mux {
                pins ="gpio12";
                function = "gpio";
           };
                       
           config {
               pins = "gpio12";
               drive-strength = <2>;
               bias-disable;
           };
};

gpio_12_suspend: gpio_12_suspend {
         mux {
                pins ="gpio12";
                function = "gpio";
           };
                       
         config {
                 pins = "gpio12";
                 drive-strength = <2>;
                 bias-pull-down;
          };
};

在具体的板级文件中,添加设备的引脚,如kernle/arch/arm/boot/dts/qcom/msm8996-mtp.c

gpio_dbg {
        compatible = "gpio_dbg";
        status = "okay";
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&gpio_12_active>;
        pinctrl-1 = <&gpio_12_suspend>;
 };
其中pinctrl-n代表的一组io的配置(非一个)如

 pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release";
                        pinctrl-0 = <&ts_int_active &ts_reset_active>;
                        pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
                        pinctrl-2 = <&ts_release>;

具体的驱动如下

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
 
static struct pinctrl *pinctrl;
static struct pinctrl_state *gpio_state_active;
static struct pinctrl_state *gpio_state_suspend;
 
 
static int gpio_dbg_suspend(struct device *dev)
{
    int ret;
    dev_dbg(dev,"%s\n",__func__);
    ret = pinctrl_select_state(pinctrl,gpio_state_suspend);
    if (ret){
		pr_err("%s:Error selecting suspend state",__func__);
    }
    else{
        pr_err("%s:Ok selecting suspend state",__func__);
    }
    return ret;
}
 
static int gpio_dbg_resume(struct device *dev)
{
    int ret;
    dev_dbg(dev,"%s\n",__func__);
    ret = pinctrl_select_state(pinctrl,gpio_state_active);
    if (ret){
		pr_err("%s:Error selecting active state",__func__);
    }
    else{
        pr_err("%s:OK selecting active state",__func__);
    }
    return ret;
}
 
static const struct dev_pm_ops gpio_dbg_ops = {
    .suspend = gpio_dbg_suspend,
    .resume  = gpio_dbg_resume,
};
 
static ssize_t gpio_suspend_show(struct device *dev,struct device_attribute *attr, char *buf)
{
    int ret;
    ret=gpio_dbg_suspend(dev);
    return ret;
}
 
static ssize_t gpio_resume_show(struct device *dev,struct device_attribute *attr, char *buf)
{
    int ret;
    ret=gpio_dbg_resume(dev);
    return ret;
}
 
static DEVICE_ATTR_RO(gpio_suspend);
static DEVICE_ATTR_RO(gpio_resume);
 
 
static int gpio_dbg_probe(struct platform_device *pdev)
{
    struct pinctrl_state *set_state;
    int err;
    pinctrl = devm_pinctrl_get(&pdev->dev);
    if (IS_ERR_OR_NULL(pinctrl)) {
        pr_err("%s(): Pinctrl not defined", __func__);
    } else {
        pr_err("%s(): Using Pinctrl", __func__);
        set_state = pinctrl_lookup_state(pinctrl,PINCTRL_STATE_DEFAULT);
        if (IS_ERR_OR_NULL(set_state)) {
            dev_err(&pdev->dev,"pinctrl lookup failed for default state");
            goto pinctrl_fail;
       }
       gpio_state_active = set_state;
       set_state = pinctrl_lookup_state(pinctrl,PINCTRL_STATE_SLEEP);
       if (IS_ERR_OR_NULL(set_state)) {
                       dev_err(&pdev->dev, "pinctrl lookup failed for sleep state");
                       goto pinctrl_fail;
       }
       pr_err("%s(): Pinctrl state sleep %p\n", __func__,set_state);
       gpio_state_suspend = set_state;
    }
    err = device_create_file(&pdev->dev, &dev_attr_gpio_suspend);
    if (err)
        goto err;
    err = device_create_file(&pdev->dev, &dev_attr_gpio_resume);
    if (err)
        goto err;
    return err;
pinctrl_fail:
    dev_err(&pdev->dev,"pinctrl err\n");
err:
    dev_err(&pdev->dev,"create file err\n");
    return err;
}

 
static struct of_device_id gpio_dbg_match_table[] = {
    { .compatible = "gpio_dbg",},
    {}
};
 
static struct platform_driver gpio_dbg_driver =
{
    .probe  = gpio_dbg_probe,
    .driver = {
            .name   =    	 "gpio_dbg",
            .owner  =  		 THIS_MODULE,
            .pm     =  		 &gpio_dbg_ops,
       .of_match_table = gpio_dbg_match_table,       
        },
};
 
static int gpio_dbg_init(void)
{
 
    platform_driver_register(&gpio_dbg_driver);
    return 0;
}
 
static void __exit gpio_dbg_exit(void)
{
    platform_driver_unregister(&gpio_dbg_driver);
}
 
 
module_init(gpio_dbg_init);
module_exit(gpio_dbg_exit); 

其中pinctrl_look_state的第二个参数为引脚的名字,这个可自己定义。

附上内核中的相关宏和函数定义

#define PINCTRL_STATE_DEFAULT "default"
#define PINCTRL_STATE_IDLE "idle"
#define PINCTRL_STATE_SLEEP "sleep"

struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
						 const char *name)
{
	struct pinctrl_state *state;

	state = find_state(p, name);
	if (!state) {
		if (pinctrl_dummy_state) {
			/* create dummy state */
			dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",
				name);
			state = create_state(p, name);
		} else
			state = ERR_PTR(-ENODEV);
	}

	return state;
}
EXPORT_SYMBOL_GPL(pinctrl_lookup_state);

int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
{
	struct pinctrl_setting *setting, *setting2;
	struct pinctrl_state *old_state = p->state;
	int ret;

	if (p->state == state)
		return 0;

	if (p->state) {
		/*
		 * The set of groups with a mux configuration in the old state
		 * may not be identical to the set of groups with a mux setting
		 * in the new state. While this might be unusual, it's entirely
		 * possible for the "user"-supplied mapping table to be written
		 * that way. For each group that was configured in the old state
		 * but not in the new state, this code puts that group into a
		 * safe/disabled state.
		 */
		list_for_each_entry(setting, &p->state->settings, node) {
			bool found = false;
			if (setting->type != PIN_MAP_TYPE_MUX_GROUP)
				continue;
			list_for_each_entry(setting2, &state->settings, node) {
				if (setting2->type != PIN_MAP_TYPE_MUX_GROUP)
					continue;
				if (setting2->data.mux.group ==
						setting->data.mux.group) {
					found = true;
					break;
				}
			}
			if (!found)
				pinmux_disable_setting(setting);
		}
	}

	p->state = NULL;

	/* 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);
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			ret = pinconf_apply_setting(setting);
			break;
		default:
			ret = -EINVAL;
			break;
		}

		if (ret < 0) {
			goto unapply_new_state;
		}
	}

	p->state = state;

	return 0;

unapply_new_state:
	dev_err(p->dev, "Error applying setting, reverse things back\n");

	list_for_each_entry(setting2, &state->settings, node) {
		if (&setting2->node == &setting->node)
			break;
		/*
		 * All we can do here is pinmux_disable_setting.
		 * That means that some pins are muxed differently now
		 * than they were before applying the setting (We can't
		 * "unmux a pin"!), but it's not a big deal since the pins
		 * are free to be muxed by another apply_setting.
		 */
		if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
			pinmux_disable_setting(setting2);
	}

	/* There's no infinite recursive loop here because p->state is NULL */
	if (old_state)
		pinctrl_select_state(p, old_state);

	return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_select_state);



  • 2
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pinctrl-single是Linux内核中的一个驱动程序,用于控制一个GPIO引脚的配置和使用。bits是指每个GPIO引脚所占用的位数,通常为1或2。 在设备树中,可以使用以下属性来配置pinctrl-single: - gpio-controller: 表示这是一个GPIO控制器 - #gpio-cells: 每个GPIO单元所包含的参数数量,通常为2。第一个参数表示GPIO编号,第二个参数表示参数标志位。 - pinctrl-single,bits: 每个GPIO引脚所占用的位数 - pinctrl-single,gpio: GPIO控制器的地址 例如,下面是一个设备树节点的示例,用于配置一个具有8个GPIO引脚的pinctrl-single控制器: ```dts gpio: gpio@10012000 { compatible = "pinctrl-single"; gpio-controller; #gpio-cells = <2>; pinctrl-single,bits = <8>; reg = <0x10012000 0x1000>; }; ``` 在Linux内核中,可以使用以下函数来配置和使用pinctrl-single: - pinctrl_lookup_state: 查找一个pinctrl状态 - pinctrl_select_state: 选择一个pinctrl状态 - pinctrl_gpio_request: 请求一个GPIO引脚 - pinctrl_gpio_free: 释放一个GPIO引脚 例如,下面是一个示例,用于配置和使用一个具有8个GPIO引脚的pinctrl-single控制器: ```c struct pinctrl *pinctrl; struct pinctrl_state *state; int gpio; /* 查找pinctrl状态 */ pinctrl = devm_pinctrl_get(&pdev->dev); state = pinctrl_lookup_state(pinctrl, "state1"); /* 选择pinctrl状态 */ pinctrl_select_state(pinctrl, state); /* 请求GPIO引脚 */ gpio = pinctrl_lookup_gpio(pinctrl, "gpio1"); if (gpio < 0) { dev_err(&pdev->dev, "Failed to request GPIO\n"); return gpio; } /* 使用GPIO引脚 */ gpio_direction_output(gpio, 1); /* 释放GPIO引脚 */ pinctrl_free_gpio(gpio); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值