Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: leds-pca995x: Add support for NXP PCA9956B

Add support for PCA9956B chip, which belongs to the same family.

This chip features 24 instead of 16 outputs, so add a chipdef struct to
deal with the different register layouts.

Reviewed-by: Marek Vasut <marex@denx.de>
Signed-off-by: Pieterjan Camerlynck <pieterjanca@gmail.com>
Link: https://lore.kernel.org/r/20240711-pca995x-v4-2-702a67148065@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Pieterjan Camerlynck and committed by
Lee Jones
68d6520d 7f5e1906

+39 -20
+39 -20
drivers/leds/leds-pca995x.c
··· 19 19 #define PCA995X_MODE1 0x00 20 20 #define PCA995X_MODE2 0x01 21 21 #define PCA995X_LEDOUT0 0x02 22 - #define PCA9955B_PWM0 0x08 23 - #define PCA9952_PWM0 0x0A 24 - #define PCA9952_IREFALL 0x43 25 - #define PCA9955B_IREFALL 0x45 26 22 27 23 /* Auto-increment disabled. Normal mode */ 28 24 #define PCA995X_MODE1_CFG 0x00 ··· 30 34 #define PCA995X_LDRX_MASK 0x3 31 35 #define PCA995X_LDRX_BITS 2 32 36 33 - #define PCA995X_MAX_OUTPUTS 16 37 + #define PCA995X_MAX_OUTPUTS 24 34 38 #define PCA995X_OUTPUTS_PER_REG 4 35 39 36 40 #define PCA995X_IREFALL_FULL_CFG 0xFF 37 41 #define PCA995X_IREFALL_HALF_CFG (PCA995X_IREFALL_FULL_CFG / 2) 38 42 39 - #define PCA995X_TYPE_NON_B 0 40 - #define PCA995X_TYPE_B 1 41 - 42 43 #define ldev_to_led(c) container_of(c, struct pca995x_led, ldev) 44 + 45 + struct pca995x_chipdef { 46 + unsigned int num_leds; 47 + u8 pwm_base; 48 + u8 irefall; 49 + }; 50 + 51 + static const struct pca995x_chipdef pca9952_chipdef = { 52 + .num_leds = 16, 53 + .pwm_base = 0x0a, 54 + .irefall = 0x43, 55 + }; 56 + 57 + static const struct pca995x_chipdef pca9955b_chipdef = { 58 + .num_leds = 16, 59 + .pwm_base = 0x08, 60 + .irefall = 0x45, 61 + }; 62 + 63 + static const struct pca995x_chipdef pca9956b_chipdef = { 64 + .num_leds = 24, 65 + .pwm_base = 0x0a, 66 + .irefall = 0x40, 67 + }; 43 68 44 69 struct pca995x_led { 45 70 unsigned int led_no; ··· 71 54 struct pca995x_chip { 72 55 struct regmap *regmap; 73 56 struct pca995x_led leds[PCA995X_MAX_OUTPUTS]; 74 - int btype; 57 + const struct pca995x_chipdef *chipdef; 75 58 }; 76 59 77 60 static int pca995x_brightness_set(struct led_classdev *led_cdev, ··· 79 62 { 80 63 struct pca995x_led *led = ldev_to_led(led_cdev); 81 64 struct pca995x_chip *chip = led->chip; 65 + const struct pca995x_chipdef *chipdef = chip->chipdef; 82 66 u8 ledout_addr, pwmout_addr; 83 67 int shift, ret; 84 68 85 - pwmout_addr = (chip->btype ? PCA9955B_PWM0 : PCA9952_PWM0) + led->led_no; 69 + pwmout_addr = chipdef->pwm_base + led->led_no; 86 70 ledout_addr = PCA995X_LEDOUT0 + (led->led_no / PCA995X_OUTPUTS_PER_REG); 87 71 shift = PCA995X_LDRX_BITS * (led->led_no % PCA995X_OUTPUTS_PER_REG); 88 72 ··· 122 104 struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 }; 123 105 struct fwnode_handle *np, *child; 124 106 struct device *dev = &client->dev; 107 + const struct pca995x_chipdef *chipdef; 125 108 struct pca995x_chip *chip; 126 109 struct pca995x_led *led; 127 - int i, btype, reg, ret; 110 + int i, reg, ret; 128 111 129 - btype = (unsigned long)device_get_match_data(&client->dev); 112 + chipdef = device_get_match_data(&client->dev); 130 113 131 114 np = dev_fwnode(dev); 132 115 if (!np) ··· 137 118 if (!chip) 138 119 return -ENOMEM; 139 120 140 - chip->btype = btype; 121 + chip->chipdef = chipdef; 141 122 chip->regmap = devm_regmap_init_i2c(client, &pca995x_regmap); 142 123 if (IS_ERR(chip->regmap)) 143 124 return PTR_ERR(chip->regmap); ··· 189 170 return ret; 190 171 191 172 /* IREF Output current value for all LEDn outputs */ 192 - return regmap_write(chip->regmap, 193 - btype ? PCA9955B_IREFALL : PCA9952_IREFALL, 194 - PCA995X_IREFALL_HALF_CFG); 173 + return regmap_write(chip->regmap, chipdef->irefall, PCA995X_IREFALL_HALF_CFG); 195 174 } 196 175 197 176 static const struct i2c_device_id pca995x_id[] = { 198 - { "pca9952", .driver_data = (kernel_ulong_t)PCA995X_TYPE_NON_B }, 199 - { "pca9955b", .driver_data = (kernel_ulong_t)PCA995X_TYPE_B }, 177 + { "pca9952", .driver_data = (kernel_ulong_t)&pca9952_chipdef }, 178 + { "pca9955b", .driver_data = (kernel_ulong_t)&pca9955b_chipdef }, 179 + { "pca9956b", .driver_data = (kernel_ulong_t)&pca9956b_chipdef }, 200 180 {} 201 181 }; 202 182 MODULE_DEVICE_TABLE(i2c, pca995x_id); 203 183 204 184 static const struct of_device_id pca995x_of_match[] = { 205 - { .compatible = "nxp,pca9952", .data = (void *)PCA995X_TYPE_NON_B }, 206 - { .compatible = "nxp,pca9955b", .data = (void *)PCA995X_TYPE_B }, 185 + { .compatible = "nxp,pca9952", .data = &pca9952_chipdef }, 186 + { .compatible = "nxp,pca9955b", . data = &pca9955b_chipdef }, 187 + { .compatible = "nxp,pca9956b", .data = &pca9956b_chipdef }, 207 188 {}, 208 189 }; 209 190 MODULE_DEVICE_TABLE(of, pca995x_of_match);