不同半導體廠商的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");