This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

lp3943 in linux 3.14.x

Other Parts Discussed in Thread: LP3943, LP5523

Hi,

I want to use lp3943 to control 10 LEDs in linux 3.14.x, but I can not control the gpio function and pwm function at the same time.

My purpose is to control the LEDs' brightness and on/off separately, but I can not add the gpio control and pwm control in the device tree at the same time.

Is it possible to control the gpio and pwm for each LED at the same time?

How to create the devicetree for linux 3.14.x to support this function?

I followed the sample devicetree on TI's website but when I tried to add gpio and pwm in the devicetree, there is only one function(gpio or PWM) can be controlled.

Thank you.

  • Hi Naiying,

    Yes, you're correct. PWM and GPIO can not be used at the same time. LP3943 provides pin selector configuration through register 0x06 ~ 0x09. If you try to use same pin, then you will get -EBUSY error from pwm-lp3943 or gpio-lp3943.

    For the device tree example,  please refer to the documents under your working Linux kernel directory.

    • Documentation/devicetree/bindings/mfd/lp3943.txt
    • Documentation/devicetree/bindings/gpio/gpio-lp3943.txt
    • Documentation/devicetree/bindings/pwm/pwmlp3943.txt

    The following diagram represents the driver structure with LED use case.

    Best regards,

    Milo

  • Hi Milo,

    Thanks for your reply.

    In the devicetree of Documentation/devicetree/bindings/mfd/lp3943.txt, it includes gpio and pwm.

    My purpose is to control each LED's brightness, and other LEDs could be turned off.

    But when I try to control them with lp3943-gpio, there're only on/off can be used for each LED, if I choose lp3943-pwm, all LEDs' brightness will be changed at the same time.

    Is it linux driver's limitation?

    Regards,

    -Naiying

  • Hi Naiying,

    For gpio-leds, it provides simple on/off. CPU heartbeat or power status LED would be good examples.
    For the brightness change, please use the PWM controller.

    LP3943 has two PWM controllers, so you can change the brightness up to two groups.
    For example, let's assume that LED 8,9, 10 are controlled by PWM0 of LP3943 and LED3 is controlled by PWM1. (through the DTB)
    If you change the duty of PWM0, then LED8,9,10 are controlled at the same time.
    If you set the duty of PWM1, then brightness of LED3 is changed.

    Best regards,
    Milo
  • Hi Milo,
    Yes, I can control the brightness with pwm and device tree, but there're only 2 pwm can be used.
    Could we change the pwm indicator to different LED at the run time?
    Thus we can use pwm0 to control one LED's brightness and pwm1 to disable other LEDs.
    Thank you

    Regards,
    -Naiying
  • Oh, I see. You want to configure the PWMs at run time. It sounds like pinmux through the pinctrl subsystem.
    It's not available in LP3943 driver. Please let me consider this feature and get back to you soon.

    Best regards,
    Milo
  • Hi Naiying,

    I just reviewed your requirement and technically it's possible but please note that it's a special use case.
    The 'pwm_map' should be removed and re-created whenever new PWM is requested, but it's not generic PWM operation in Linux.
    To support this, additional device attribute(s) maybe required.

    Best regards,
    Milo
  • Hi Milo,

    Thank you.
    But if I can use pwm and gpio at the same time, I can indicate all LEDs to pwm0 to change the brightness then disable some LEDs that I don't want to turn on at run time by gpio. Is it possible?

    Regards,
    -Naiying
  • Well, LP3943 pwm_map is fixed while the driver is probed. If gpio-lp3943 is not used, then you can disable it in the dts. (status="disabled")
    I'm afraid I misunderstood your question. Could you explain why gpio usage is required in this case?

    Best regards,
    Milo
  • For example,
    If I only want to control the brightness of LED3, I can turn off all other LEDs by gpio function and use pwm0 to change the brightness of LED3.

    Regards,
    -Naiying
  • Yes, it's available. Thanks for clear explanation.

    Best regards,
    Milo
  • But we can not create the pwm and gpio in the devicetree at the same time.
    Is there any complete example?
    Thank you.

    Regards,
    -Naiying
  • Hi Naiying,

    I have no available LP3943 EVM so it will take more time to generate the dts in my side.
    However, the LP3943 dt-binding were created based on real target device.

    Could you send me your dts and kernel message?
    And please share the results of the commands below.

    # cat /sys/kernel/debug/gpio

    # cat /sys/kernel/debug/pwm

    # ls -la /sys/class/pwm/

    # ls -la /sys/class/leds/

    Best regards,
    Milo
  • Hi Milo,

    I'm Naiying's colleague.
    Our dts and kernel message please refer following info :
    -----------------------------------------------------------------------------
    i2c_0: i2c@78b7000 { /* BLSP1 QUP2 */
    pinctrl-0 = <&i2c_0_pins>;
    pinctrl-1 = <&i2c_0_pins>;
    pinctrl-names = "i2c_active", "i2c_sleep";
    status = "ok";
    lp3943@60 {
    compatible = "ti,lp3943";
    reg = <0x60>;

    pwm3943: pwm {
    label = "LED0";
    compatible = "ti,lp3943-pwm";
    #pwm-cells = <2>;
    ti,pwm0 = <0 1 2 3 4 5>;
    };
    gpioex: gpio {
    compatible = "ti,lp3943-gpio";
    gpio-controller;
    #gpio-cells = <2>;
    };
    };
    };
    leds {
    compatible = "gpio-leds";
    indicator1 {
    label = "LED0";
    gpios = <&gpioex 0 GPIO_ACTIVE_LOW>;
    };
    indicator2 {
    label = "LED1";
    gpios = <&gpioex 1 GPIO_ACTIVE_LOW>;
    };
    indicator3 {
    label = "LED2";
    gpios = <&gpioex 2 GPIO_ACTIVE_LOW>;
    };
    indicator4 {
    label = "LED3";
    gpios = <&gpioex 3 GPIO_ACTIVE_LOW>;
    };
    indicator5 {
    label = "LED4";
    gpios = <&gpioex 4 GPIO_ACTIVE_LOW>;
    };
    };
    pwmleds {
    compatible = "pwm-leds";
    rgb {
    label = "LEDD";
    max-brightness = <255>;
    pwms = <&pwm3943 0 10000>;
    };
    };
    -----------------------------------------------------------------------------
    # cat /sys/kernel/debug/gpio
    GPIOs 0-69, platform/1000000.pinctrl, 1000000.pinctrl:
    gpio0 : in 0 2mA keeper
    gpio1 : in 0 2mA keeper
    gpio2 : in 0 2mA keeper
    gpio3 : in 0 2mA no pull
    gpio4 : in 0 2mA keeper
    gpio5 : in 0 2mA pull down
    gpio6 : in 1 2mA keeper
    gpio7 : in 1 2mA keeper
    gpio8 : out 1 2mA no pull
    gpio9 : out 1 2mA no pull
    gpio10 : in 0 2mA keeper
    gpio11 : in 0 2mA keeper
    gpio12 : in 1 2mA no pull
    gpio13 : in 1 2mA no pull
    gpio14 : in 1 2mA no pull
    gpio15 : in 1 2mA no pull
    gpio16 : out 1 2mA no pull
    gpio17 : out 1 2mA no pull
    gpio18 : in 0 2mA pull down
    gpio19 : in 1 2mA pull down
    gpio20 : in 0 2mA keeper
    gpio21 : in 0 2mA keeper
    gpio22 : in 0 2mA keeper
    gpio23 : in 1 10mA keeper
    gpio24 : in 1 10mA keeper
    gpio25 : in 1 10mA keeper
    gpio26 : in 1 10mA keeper
    gpio27 : in 1 16mA keeper
    gpio28 : out 0 10mA keeper
    gpio29 : in 1 10mA keeper
    gpio30 : in 1 10mA keeper
    gpio31 : in 1 10mA keeper
    gpio32 : in 1 10mA no pull
    gpio33 : in 0 2mA no pull
    gpio34 : in 0 2mA keeper
    gpio35 : in 0 2mA keeper
    gpio36 : in 3 2mA pull down
    gpio37 : in 0 2mA pull down
    gpio38 : out 0 2mA pull down
    gpio39 : in 0 2mA keeper
    gpio40 : in 5 2mA pull down
    gpio41 : in 0 2mA pull down
    gpio42 : out 0 2mA pull down
    gpio43 : in 0 2mA pull down
    gpio44 : in 0 2mA pull down
    gpio45 : in 0 2mA pull down
    gpio46 : in 0 2mA pull down
    gpio47 : in 0 2mA pull down
    gpio48 : in 0 2mA pull down
    gpio49 : in 0 2mA pull down
    gpio50 : out 0 2mA keeper
    gpio51 : in 0 2mA pull down
    gpio52 : in 1 2mA keeper
    gpio53 : in 1 2mA keeper
    gpio54 : in 1 2mA pull down
    gpio55 : in 1 2mA pull down
    gpio56 : in 1 2mA pull down
    gpio57 : in 1 2mA pull down
    gpio58 : in 1 2mA keeper
    gpio59 : in 1 2mA keeper
    gpio60 : in 1 2mA pull down
    gpio61 : in 1 2mA pull down
    gpio62 : in 1 2mA pull down
    gpio63 : in 1 2mA pull down
    gpio64 : in 1 2mA pull down
    gpio65 : in 1 2mA pull down
    gpio66 : in 1 2mA pull down
    gpio67 : in 1 2mA pull down
    gpio68 : in 1 2mA pull down
    gpio69 : in 1 2mA pull down

    GPIOs 240-255, platform/lp3943-gpio, lp3943, can sleep:
    -----------------------------------------------------------------------------
    cat /sys/kernel/debug/pwm
    platform/lp3943-pwm, 2 PWM devices
    pwm-0 (rgb ): requested
    pwm-1 ((null) ):
    -----------------------------------------------------------------------------
    ls -la /sys/class/pwm/
    drwxr-xr-x 2 root root 0 Jan 1 1970 .
    drwxr-xr-x 41 root root 0 Jan 1 1970 ..
    lrwxrwxrwx 1 root root 0 Jan 1 1970 pwmchip0 -> ../../devices/soc.0/78b7000.i2c/i2c-0/0-0060/lp3943-pwm/pwm/pwmchip0
    -----------------------------------------------------------------------------
    ls -la /sys/class/leds/
    drwxr-xr-x 2 root root 0 Jan 1 1970 .
    drwxr-xr-x 41 root root 0 Jan 1 1970 ..
    lrwxrwxrwx 1 root root 0 Jan 1 1970 LEDD -> ../../devices/soc.0/pwmleds.8/leds/LEDD
    -----------------------------------------------------------------------------
    thank you!!

    Best regards,
    Kay
  • Hi,

    As I noted, LED output can not be used for mutually exclusive way. I think there is -EBUSY error (-16) in your whole kernel message. Based on your dts, 6 LEDs are controlled by PWM and GPIO.

    ti,pwm0 = <0 1 2 3 4 5>;  // this is OK. PWM controller maps LED0~5

    The following GPIO DT tries to request to map LED0~5 for GPIO usage, but pin request will get failed if PWM controller has already configured LED0~5 as PWM usage.

    gpios = <&gpioex 0 GPIO_ACTIVE_LOW>;

    gpios = <&gpioex 1 GPIO_ACTIVE_LOW>;

    gpios = <&gpioex 2 GPIO_ACTIVE_LOW>;

    gpios = <&gpioex 3 GPIO_ACTIVE_LOW>;

    gpios = <&gpioex 4 GPIO_ACTIVE_LOW>;

    gpios = <&gpioex 5 GPIO_ACTIVE_LOW>;

    Please check your pins again for PWM and GPIO usage.

    If LED0~5 is for PWM and other LEDs are for GPIOs, it gonna be OK.

    For example,

    gpios = <&gpioex 6 GPIO_ACTIVE_LOW>;

    gpios = <&gpioex 7 GPIO_ACTIVE_LOW>;

    ...

    Best regards,

    Milo

  • thanks for your replay

    If refer your example for dts
    I can only control all brightness of LED0~5, cannot control a single one among LED0 ~ 5,
    and LED6/7 can only control turning the light on or off, cannot control 0~255 brightness.
    Is it possible to control the brightness of each LED individually?

    thank you!!

    Best regards,
    Kay
  • Hi Kay,

    No, it's not available. If you want to change the brightness of each LED separately , then LP3943 is not appropriate.
    I think LP5523 would be good but it has 9 LED outputs. Your local TI Sales person will help you to choose the best device.

    Best regards,
    Milo
  • Hi Milo,

    OK, I understand, thanks for your suggestion and reply.
    Thank you very much.
    :)

    Best regards,
    Kay
  • Hi Milo,

    I was wondering, can you tell us where the "value" comes from in the gpio-lp3943.c ?

    static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
    {
        struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
        u8 data;

        if (value)
            data = LP3943_GPIO_OUT_HIGH;
        else
            data = LP3943_GPIO_OUT_LOW;

        lp3943_gpio_set_mode(lp3943_gpio, offset, data);
    }

    Thanks!!

    Best regards,

    Kay

  • Hi Kay,

    Linux GPIO subsystem has two parts - GPIO controller and consumer.

    GPIO consumer requests a pin and set the value. GPIO controller works HW pin control from GPIO consumer's request.

    LP3943 is a GPIO controller. Generic GPIO led driver (drivers/leds/leds-gpio.c) is the consumer.

    As 'leds-gpio' driver sets the value (0 or 1), then lp3943_gpio_set() is called. The argument, 'value' is 0 or 1.

    0 means set requested pin as low. 1 is setting the pin as high.

    The 'offset' is a pin number such like LED0, 1 ... 15 of LP3943.

    Best regards,

    Milo

  • Hi Milo,

    Thanks for your replay.
    Is any way to get brightness value of sys/class/leds/LED/brightness in the drivers/leds/leds-gpio.c ?

    Best regards,
    Kay
  • No, it's not available because 'leds-gpio' simply turns on and off the LED.
    If the brightness is nonzero, set GPIO to high. Otherwise, set GPIO to low.

    You can check the code below.

    git.kernel.org/.../leds-gpio.c

    static void gpio_led_set(struct led_classdev *led_cdev,
    enum led_brightness value)
    {
    struct gpio_led_data *led_dat = cdev_to_gpio_led_data(led_cdev);
    int level;

    if (value == LED_OFF)
    level = 0;
    else
    level = 1;

    if (led_dat->blinking) {
    led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
    NULL, NULL);
    led_dat->blinking = 0;
    } else {
    if (led_dat->can_sleep)
    gpiod_set_value_cansleep(led_dat->gpiod, level);
    else
    gpiod_set_value(led_dat->gpiod, level);
    }
    }

    Best regards,
    Milo
  • Hi Milo,

    You mean if I set /sys/class/leds/LED/brightness 1~255, level will be set 1 (turn on)?
    Then if I set "0", level will be set 0 (turn off)?
    I try to modify the leds-gpio.c driver, but it look like no reaction.
    Example :
      static void gpio_led_set(struct led_classdev *led_cdev,
       enum led_brightness value)
      {
       struct gpio_led_data *led_dat = cdev_to_gpio_led_data(led_cdev);
       int level;

      if (value == LED_OFF)
      level = 1;
      else
      level = 0;
    The result will not be the opposite(set 0->trun on, set 1~255->turn off).

    Best regards,
    Kay
  • Have you checked the pin level by using digital multi-meter?
    If not changed, please check the register value by accessing the debugfs.
    You can check register values (reg 06 ~ 09h) by using 'cat /sys/kernel/debug/regmap/lp3943/registers'.
    According the the datasheet, the value should be 0 (output hi-z) or 1 (output low).

    Best regards,
    Milo
  • Hi Milo,

    Thanks for your reply.
    When I set value 1~255 in /sys/class/leds/LED/brightness, I think the code will run gpio-lp3943.c.
    Please check the code below.

      static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
      {
      struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
      u8 data;

      if (value)
      data = LP3943_GPIO_OUT_HIGH;
      else
       data = LP3943_GPIO_OUT_LOW;

      lp3943_gpio_set_mode(lp3943_gpio, offset, data);
      }

    If /sys/class/leds/LED/brightness have value(1~255), "data" will equal LP3943_GPIO_OUT_LOW (0x1).
    On behalf of /sys/class/leds/LED/brightness equal 1~255, value will equal 0.
    I want to know in the lp3943_gpio_set(), where the "value" was judged to be 0 or 1 ?
    And what's the different between leds-gpio.c->static void gpio_led_set() and gpio-lp3943.c->static void lp3943_gpio_set() ?

    Best regards,
    Kay
  • Hi Kay,

    > When I set value 1~255 in /sys/class/leds/LED/brightness, I think the code will run gpio-lp3943.c.

    No, drivers/leds/leds-gpio.c will process the sysfs request from /sys/class/leds/<name>/brightness.

    Please note that gpio-lp3943.c is not LED driver but GPIO controller.

    > I want to know in the lp3943_gpio_set(), where the "value" was judged to be 0 or 1 ?

    The leds-gpio.c will choose the value 0 or 1 in gpio_led_set() because it's a LED controller.

    Please see the diagram below.

  • Hi Milo,

    Thanks for your suggestion.

    I will continue to try.

    Best regards,

    Kay