pinctrl使用例項

lethe1203發表於2024-03-23

不同半導體廠商的pinctrl設計均不同,這裡以高通的pinctrl使用舉例:

dts修改:

 // mtp-pinctrl.dtsi
 leds_redon:leds_redon{
             mux {
                  pins = "gpio161";
                  function = "gpio";
             };
             config {
                 pins = "gpio161";
                 drive-strength = <2>;
                 output-high;
                 bias-pull-up;
         };
};

 leds_redoff:leds_redoff{
             mux {
                  pins = "gpio161";
                  function = "gpio";
             };
             config {
                 pins = "gpio161";
                 drive-strength = <2>;
                 output-low;
                 bias-pull-up;
         };
};

 leds_blueon:leds_blueon{
             mux {
                  pins = "gpio160";
                  function = "gpio";
             };
             config {
                 pins = "gpio160";
                 drive-strength = <2>;
                 output-high;
                 bias-pull-up;
         };
};

 leds_blueoff:leds_blueoff{
             mux {
                  pins = "gpio160";
                  function = "gpio";
             };
             config {
                 pins = "gpio160";
                 drive-strength = <2>;
                 output-low;
                 bias-pull-up;
         };
};

// mtp-xr.dtsi
        leds_3 {
            status = "ok";
            compatible = "qcom,leds_3";
            pinctrl-names = "default","leds_redon","leds_redoff",
            "leds_blueon","leds_blueoff";
            pinctrl-0 = <&pwm_out_gpio6_default>;
            pinctrl-1 = <&leds_redon>;
            pinctrl-2 = <&leds_redoff>;
            pinctrl-3 = <&leds_blueon>;
            pinctrl-4 = <&leds_blueoff>;
            pwms = <&pm8150l_pwm 0 1000000>;
            pwm-names = "pwm-leds";

        };
        
&pm8150l_gpios {
        pwm_out_gpio6 {
                pwm_out_gpio6_default: pwm_out_gpio6_default {
                        pins = "gpio6";
                        function = "func1";
                        bias-disable;
                        power-source = <0>;
                        output-high;
                        qcom,drive-strength = <3>;
                        drive-push-pull;
                };
        };
};

leds3.c

#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <linux/pwm.h>
#include <linux/pinctrl/consumer.h>

//static struct kobject   *leds_kobj;
//static struct leds_dev *leds;
struct pinctrl *power_leds_pinctrl;

static struct pwm_device *pwm_dev;
static struct pwm_state pstate;

static struct pinctrl_state *leds_redon = NULL, *leds_redoff = NULL,
                *leds_blueon = NULL, *leds_blueoff = NULL;
//static bool LED_STATUE = true;
//static int led_level = 1;

struct leds_dev {
    struct device *dev;
    struct regmap *regmap;
    struct kobject *leds_kobj;
};

static ssize_t led_red_store(struct device *dev, struct device_attribute *attr,
                 const char *buf, size_t len)
{
    int rc = 0;
    unsigned long level;
    rc = kstrtoul(buf, 10, &level);
    switch (level) {
    case 0:
        printk("led_red_store gpio_set_value 0.\n");
        pinctrl_select_state(power_leds_pinctrl, leds_redoff);
        break;
    case 1:
        printk("led_red_store gpio_set_value 1.\n");
        pinctrl_select_state(power_leds_pinctrl, leds_redon);
        break;
    default:
        pr_err("%s: wrong level. (level 0 - 1)\n", __func__);
        return len;
    }

    return len;
}

static ssize_t led_blue_store(struct device *dev, struct device_attribute *attr,
                  const char *buf, size_t len)
{
    int rc = 0;
    unsigned long level;
    rc = kstrtoul(buf, 10, &level);
    switch (level) {
    case 0:
        pinctrl_select_state(power_leds_pinctrl, leds_blueoff);
        break;
    case 1:
        pinctrl_select_state(power_leds_pinctrl, leds_blueon);
        break;
    default:
        pr_err("%s: wrong level. (level 0 - 1)\n", __func__);
        return len;
    }

    return len;
}

static ssize_t led_green_store(struct device *dev,
                   struct device_attribute *attr, const char *buf,
                   size_t len)
{
    int rc = 0;
    unsigned long duty = 0;
    rc = kstrtoul(buf, 10, &duty);
    duty = duty * 100;
    if (duty > pstate.period) {
        pr_err("%s:invaild duty value, duty > period\n", __func__);
        return len;
    }
    pstate.duty_cycle = duty * 100;
    //pstate.polarity = PWM_POLARITY_INVERSED;
    pr_err("%s: duty %ld\n", __func__, duty);
    rc = pwm_apply_state(pwm_dev, &pstate);
    if (rc < 0) {
        pr_err("%s:pwm apply state failed in store\n", __func__);
        return rc;
    }
    return len;
}

static ssize_t red_show(struct device *dev, struct device_attribute *attr,
            char *buf)
{
    return 0;
}

static ssize_t blue_show(struct device *dev, struct device_attribute *attr,
             char *buf)
{
    return 0;
}

static ssize_t green_show(struct device *dev, struct device_attribute *attr,
              char *buf)
{
    return 0;
}

static DEVICE_ATTR(led_red, 0664, red_show, led_red_store);
static DEVICE_ATTR(led_blue, 0664, blue_show, led_blue_store);
static DEVICE_ATTR(led_green, 0664, green_show, led_green_store);
//static DEVICE_ATTR(led_link, 0664, NULL, led_link_store);

static struct attribute *leds_attrs[] = {
    &dev_attr_led_red.attr,
    &dev_attr_led_blue.attr,
    &dev_attr_led_green.attr,
    NULL,
};

static struct attribute_group leds_attr_group = {
    .attrs = leds_attrs,
};

static int leds_3_probe(struct platform_device *pdev)
{
    int rc = 0, rs;
    int ret = 0;
    struct leds_dev *leds = dev_get_drvdata(&pdev->dev);

    rs = gpio_get_value(1110);
    if (rs) {
    printk("leds no probe");
    return 0;
    }
    leds = devm_kzalloc(&pdev->dev, sizeof(*leds), GFP_KERNEL);
    if (IS_ERR(leds)) {
        pr_err("%s: can't alloc memery for leds device.\n", __func__);
        return -1;
    }

    leds->leds_kobj = kobject_create_and_add("leds_3", kernel_kobj);
    if (!leds->leds_kobj) {
        dev_err(&pdev->dev, "kobject leds ENOMEM\n");
        goto fail;
    }

    rc = sysfs_create_group(leds->leds_kobj, &leds_attr_group);
    if (rc < 0) {
        pr_err("%s: sysfs create failed. rc = %d.\n", __func__, rc);
        goto fail;
    } else
        pr_err("%s: sysfs create success. rc = %d.\n", __func__, rc);

    power_leds_pinctrl = devm_pinctrl_get(&pdev->dev);
    if (IS_ERR(power_leds_pinctrl)) {
        printk("devm_pinctrl_get is error\n");

        ret = PTR_ERR(power_leds_pinctrl);

        return ret;
    }

    leds_redon = pinctrl_lookup_state(power_leds_pinctrl, "leds_redon");
    if (IS_ERR(leds_redon)) {
        printk("get the state of the gpioup is fail\n");

        ret = PTR_ERR(leds_redon);

        return ret;
    }

    leds_redoff = pinctrl_lookup_state(power_leds_pinctrl, "leds_redoff");
    if (IS_ERR(leds_redoff)) {
        printk("get the state of the gpioup is fail\n");

        ret = PTR_ERR(leds_redoff);

        return ret;
    }

    leds_blueon = pinctrl_lookup_state(power_leds_pinctrl, "leds_blueon");
    if (IS_ERR(leds_blueon)) {
        printk("get the state of the gpioup is fail\n");

        ret = PTR_ERR(leds_blueon);

        return ret;
    }

    leds_blueoff = pinctrl_lookup_state(power_leds_pinctrl, "leds_blueoff");
    if (IS_ERR(leds_blueoff)) {
        printk("get the state of the gpioup is fail\n");

        ret = PTR_ERR(leds_blueoff);

        return ret;
    }

    printk("leds power up finish");
    /**pwm**/
    pwm_dev = pwm_get(&pdev->dev, "pwm-leds");
    if (IS_ERR(pwm_dev)) {
        pr_err("%s: get pwm device failed\n", __func__);
        PTR_ERR(pwm_dev);
    }

    /* ******************** set PWM ********************** */
    pstate.enabled = 0;
    pstate.period = 10000;
    pstate.duty_cycle = 0;
    //pstate.output_pattern->num_entries = 10;
    pwm_apply_state(pwm_dev, &pstate);
    //pstate->output_pattern.cycles_per_duty = 10;
    pstate.output_type = PWM_OUTPUT_MODULATED;

fail:
    return rc;
}

static int leds_3_remove(struct platform_device *pdev)
{
    struct leds_dev *leds = dev_get_drvdata(&pdev->dev);

    dev_set_drvdata(leds->dev, NULL);
    sysfs_remove_group(leds->leds_kobj, &leds_attr_group);
    pwm_put(pwm_dev);
    return 0;
};
static const struct of_device_id leds_match_table[] = {
    {
        .compatible = "qcom,leds_3",
    },
    {},
};

static struct platform_driver leds_3_driver = {
    .driver = {
        .name = "leds_3_driver",
        .owner = THIS_MODULE,
        .of_match_table = leds_match_table,
    },
    .probe = leds_3_probe,
    .remove = leds_3_remove,
};

static int __init leds_init(void)
{
    pr_err("leds_3_init\n");
    return platform_driver_register(&leds_3_driver);
}

static void __exit leds_exit(void)
{
    return platform_driver_unregister(&leds_3_driver);
}

module_init(leds_init);
module_exit(leds_exit);
MODULE_LICENSE("GPL v2");

相關文章