]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
leds: pca955x: Optimize probe LED selection
authorEddie James <eajames@linux.ibm.com>
Wed, 12 Feb 2025 14:30:37 +0000 (08:30 -0600)
committerLee Jones <lee@kernel.org>
Thu, 20 Feb 2025 14:29:13 +0000 (14:29 +0000)
Previously, the probe function might do up to 32 reads and writes
to the same 4 registers to program the LED selection. Reduce this to
a maximum of 5 operations by accumulating the changes to the LED
selection and comparing with the previous value to write the
selection if different.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20250212143038.1416501-4-eajames@linux.ibm.com
Signed-off-by: Lee Jones <lee@kernel.org>
drivers/leds/leds-pca955x.c

index 4990f8aff6d16377e29955699c281bae08dc3326..eb268e6ee2a8b7f4902b1d115423fd39d1e58d71 100644 (file)
@@ -446,7 +446,9 @@ static int pca955x_probe(struct i2c_client *client)
        struct led_classdev *led;
        struct led_init_data init_data;
        struct i2c_adapter *adapter;
-       int i, err;
+       int i, bit, err, nls, reg;
+       u8 ls1[4];
+       u8 ls2[4];
        struct pca955x_platform_data *pdata;
        bool set_default_label = false;
        bool keep_pwm = false;
@@ -504,6 +506,17 @@ static int pca955x_probe(struct i2c_client *client)
        init_data.devname_mandatory = false;
        init_data.devicename = "pca955x";
 
+       nls = pca955x_num_led_regs(chip->bits);
+       /* Use auto-increment feature to read all the LED selectors at once. */
+       err = i2c_smbus_read_i2c_block_data(client,
+                                           0x10 | (pca955x_num_input_regs(chip->bits) + 4), nls,
+                                           ls1);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < nls; i++)
+               ls2[i] = ls1[i];
+
        for (i = 0; i < chip->bits; i++) {
                pca955x_led = &pca955x->leds[i];
                pca955x_led->led_num = i;
@@ -515,19 +528,16 @@ static int pca955x_probe(struct i2c_client *client)
                case PCA955X_TYPE_GPIO:
                        break;
                case PCA955X_TYPE_LED:
+                       bit = i % 4;
+                       reg = i / 4;
                        led = &pca955x_led->led_cdev;
                        led->brightness_set_blocking = pca955x_led_set;
                        led->brightness_get = pca955x_led_get;
 
-                       if (pdata->leds[i].default_state == LEDS_DEFSTATE_OFF) {
-                               err = pca955x_led_set(led, LED_OFF);
-                               if (err)
-                                       return err;
-                       } else if (pdata->leds[i].default_state == LEDS_DEFSTATE_ON) {
-                               err = pca955x_led_set(led, LED_FULL);
-                               if (err)
-                                       return err;
-                       }
+                       if (pdata->leds[i].default_state == LEDS_DEFSTATE_OFF)
+                               ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_OFF);
+                       else if (pdata->leds[i].default_state == LEDS_DEFSTATE_ON)
+                               ls2[reg] = pca955x_ledsel(ls2[reg], bit, PCA955X_LS_LED_ON);
 
                        init_data.fwnode = pdata->leds[i].fwnode;
 
@@ -571,6 +581,14 @@ static int pca955x_probe(struct i2c_client *client)
                }
        }
 
+       for (i = 0; i < nls; i++) {
+               if (ls1[i] != ls2[i]) {
+                       err = pca955x_write_ls(pca955x, i, ls2[i]);
+                       if (err)
+                               return err;
+               }
+       }
+
        /* PWM0 is used for half brightness or 50% duty cycle */
        err = pca955x_write_pwm(pca955x, 0, 255 - LED_HALF);
        if (err)