diff mbox series

[v1] leds: cat9532: support cat9532 in pca955x

Message ID 20250212071525.1148988-1-marshall_zhan@wiwynn.com
State New
Headers show
Series [v1] leds: cat9532: support cat9532 in pca955x | expand

Commit Message

MarshallZhan-wiwynn Feb. 12, 2025, 7:15 a.m. UTC
The CAT9532 chips are almost 100% compatible with PCA9552, except that
the CAT9532 used the opposite polarity in register that sets on/off.

Compare the state at INPUT with the state of LSn and dynamically
adjust how you program LSn

Signed-off-by: MarshallZhan-wiwynn <marshall_zhan@wiwynn.com>
---
 drivers/leds/leds-pca955x.c | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

--
2.25.1

WIWYNN PROPRIETARY
This email (and any attachments) contains proprietary or confidential information and is for the sole use of its intended recipient. Any unauthorized review, use, copying or distribution of this email or the content of this email is strictly prohibited. If you are not the intended recipient, please notify the sender and delete this email immediately.
diff mbox series

Patch

diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 94a9f8a54b35..c5bb81473b6a 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -13,6 +13,7 @@ 
  *     PCA9550         2-bit driver            0x60 .. 0x61
  *     PCA9551         8-bit driver            0x60 .. 0x67
  *     PCA9552         16-bit driver           0x60 .. 0x67
+ *     CAT9532         16-bit driver           0x60 .. 0x67
  *     PCA9553/01      4-bit driver            0x62
  *     PCA9553/02      4-bit driver            0x63
  *
@@ -235,6 +236,20 @@  static int pca955x_read_pwm(struct i2c_client *client, int n, u8 *val)
        return 0;
 }

+static int pca955x_read_input_bit(struct pca955x *pca955x, int led_num)
+{
+       u8 cmd = led_num / 8;
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(pca955x->client, cmd);
+       if (ret < 0) {
+               dev_err(&pca955x->client->dev, "%s: reg 0x%x, err %d\n", __func__, led_num, ret);
+               return ret;
+       }
+       return (ret >> (led_num % 8)) & 1;
+
+}
+
 static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev)
 {
        struct pca955x_led *pca955x_led = container_of(led_cdev,
@@ -251,10 +266,11 @@  static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev)
        ls = (ls >> ((pca955x_led->led_num % 4) << 1)) & 0x3;
        switch (ls) {
        case PCA955X_LS_LED_ON:
-               ret = LED_FULL;
-               break;
        case PCA955X_LS_LED_OFF:
-               ret = LED_OFF;
+               if (pca955x_read_input_bit(pca955x, pca955x_led->led_num))
+                       ret = LED_FULL;
+               else
+                       ret = LED_OFF;
                break;
        case PCA955X_LS_BLINK0:
                ret = LED_HALF;
@@ -276,6 +292,8 @@  static int pca955x_led_set(struct led_classdev *led_cdev,
        struct pca955x_led *pca955x_led;
        struct pca955x *pca955x;
        u8 ls;
+       u8 ls_last_state;
+       int inupt_bit;
        int chip_ls;    /* which LSx to use (0-3 potentially) */
        int ls_led;     /* which set of bits within LSx to use (0-3) */
        int ret;
@@ -292,12 +310,21 @@  static int pca955x_led_set(struct led_classdev *led_cdev,
        if (ret)
                goto out;

+       ls_last_state = pca955x_ledstate(ls, bit);
        switch (value) {
        case LED_FULL:
-               ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
+               input_bit = pca955x_read_input_bit(pca955x, pca955x_led->led_num);
+               if (ls_last_state == input_bit)
+                       ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
+               else
+                       ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_OFF);
                break;
        case LED_OFF:
-               ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_OFF);
+               input_bit = pca955x_read_input_bit(pca955x, pca955x_led->led_num);
+               if (ls_last_state == input_bit)
+                       ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_OFF);
+               else
+                       ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
                break;
        case LED_HALF:
                ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK0);