1*07e028d9SEdelweise Escala // SPDX-License-Identifier: GPL-2.0 2*07e028d9SEdelweise Escala /* 3*07e028d9SEdelweise Escala * LTC3220 18-Channel LED Driver 4*07e028d9SEdelweise Escala * 5*07e028d9SEdelweise Escala * Copyright 2026 Analog Devices Inc. 6*07e028d9SEdelweise Escala * 7*07e028d9SEdelweise Escala * Author: Edelweise Escala <edelweise.escala@analog.com> 8*07e028d9SEdelweise Escala */ 9*07e028d9SEdelweise Escala 10*07e028d9SEdelweise Escala #include <linux/bitfield.h> 11*07e028d9SEdelweise Escala #include <linux/delay.h> 12*07e028d9SEdelweise Escala #include <linux/device.h> 13*07e028d9SEdelweise Escala #include <linux/gpio/consumer.h> 14*07e028d9SEdelweise Escala #include <linux/i2c.h> 15*07e028d9SEdelweise Escala #include <linux/leds.h> 16*07e028d9SEdelweise Escala #include <linux/module.h> 17*07e028d9SEdelweise Escala #include <linux/property.h> 18*07e028d9SEdelweise Escala #include <linux/regmap.h> 19*07e028d9SEdelweise Escala #include <linux/types.h> 20*07e028d9SEdelweise Escala 21*07e028d9SEdelweise Escala /* LTC3220 Registers */ 22*07e028d9SEdelweise Escala #define LTC3220_COMMAND_REG 0x00 23*07e028d9SEdelweise Escala #define LTC3220_QUICK_WRITE_MASK BIT(0) 24*07e028d9SEdelweise Escala #define LTC3220_SHUTDOWN_MASK BIT(3) 25*07e028d9SEdelweise Escala 26*07e028d9SEdelweise Escala #define LTC3220_ULED_REG(x) (0x01 + (x)) 27*07e028d9SEdelweise Escala #define LTC3220_LED_CURRENT_MASK GENMASK(5, 0) 28*07e028d9SEdelweise Escala #define LTC3220_LED_MODE_MASK GENMASK(7, 6) 29*07e028d9SEdelweise Escala 30*07e028d9SEdelweise Escala #define LTC3220_GRAD_BLINK_REG 0x13 31*07e028d9SEdelweise Escala #define LTC3220_GRADATION_MASK GENMASK(2, 0) 32*07e028d9SEdelweise Escala #define LTC3220_GRADATION_DIRECTION_MASK BIT(0) 33*07e028d9SEdelweise Escala #define LTC3220_GRADATION_PERIOD_MASK GENMASK(2, 1) 34*07e028d9SEdelweise Escala #define LTC3220_BLINK_MASK GENMASK(4, 3) 35*07e028d9SEdelweise Escala 36*07e028d9SEdelweise Escala #define LTC3220_NUM_LEDS 18 37*07e028d9SEdelweise Escala #define LTC3220_MAX_BRIGHTNESS 63 38*07e028d9SEdelweise Escala 39*07e028d9SEdelweise Escala #define LTC3220_GRADATION_RAMP_TIME_240MS 240 40*07e028d9SEdelweise Escala #define LTC3220_GRADATION_RAMP_TIME_480MS 480 41*07e028d9SEdelweise Escala 42*07e028d9SEdelweise Escala #define LTC3220_BLINK_ON_156MS 156 43*07e028d9SEdelweise Escala #define LTC3220_BLINK_ON_625MS 625 44*07e028d9SEdelweise Escala #define LTC3220_BLINK_PERIOD_1250MS 1250 45*07e028d9SEdelweise Escala #define LTC3220_BLINK_PERIOD_2500MS 2500 46*07e028d9SEdelweise Escala 47*07e028d9SEdelweise Escala #define LTC3220_BLINK_SHORT_ON_TIME BIT(0) 48*07e028d9SEdelweise Escala #define LTC3220_BLINK_LONG_PERIOD BIT(1) 49*07e028d9SEdelweise Escala 50*07e028d9SEdelweise Escala enum ltc3220_led_mode { 51*07e028d9SEdelweise Escala LTC3220_NORMAL_MODE, 52*07e028d9SEdelweise Escala LTC3220_BLINK_MODE, 53*07e028d9SEdelweise Escala LTC3220_GRADATION_MODE, 54*07e028d9SEdelweise Escala }; 55*07e028d9SEdelweise Escala 56*07e028d9SEdelweise Escala enum ltc3220_blink_mode { 57*07e028d9SEdelweise Escala LTC3220_BLINK_MODE_625MS_1250MS, 58*07e028d9SEdelweise Escala LTC3220_BLINK_MODE_156MS_1250MS, 59*07e028d9SEdelweise Escala LTC3220_BLINK_MODE_625MS_2500MS, 60*07e028d9SEdelweise Escala LTC3220_BLINK_MODE_156MS_2500MS 61*07e028d9SEdelweise Escala }; 62*07e028d9SEdelweise Escala 63*07e028d9SEdelweise Escala enum ltc3220_gradation_mode { 64*07e028d9SEdelweise Escala LTC3220_GRADATION_MODE_DISABLED, 65*07e028d9SEdelweise Escala LTC3220_GRADATION_MODE_240MS_RAMP_TIME, 66*07e028d9SEdelweise Escala LTC3220_GRADATION_MODE_480MS_RAMP_TIME, 67*07e028d9SEdelweise Escala LTC3220_GRADATION_MODE_960MS_RAMP_TIME 68*07e028d9SEdelweise Escala }; 69*07e028d9SEdelweise Escala 70*07e028d9SEdelweise Escala static const struct regmap_config ltc3220_regmap_config = { 71*07e028d9SEdelweise Escala .reg_bits = 8, 72*07e028d9SEdelweise Escala .val_bits = 8, 73*07e028d9SEdelweise Escala .max_register = LTC3220_GRAD_BLINK_REG, 74*07e028d9SEdelweise Escala .cache_type = REGCACHE_FLAT_S, 75*07e028d9SEdelweise Escala }; 76*07e028d9SEdelweise Escala 77*07e028d9SEdelweise Escala struct ltc3220_uled_cfg { 78*07e028d9SEdelweise Escala struct led_classdev led_cdev; 79*07e028d9SEdelweise Escala u8 reg_value; 80*07e028d9SEdelweise Escala u8 led_index; 81*07e028d9SEdelweise Escala bool registered; 82*07e028d9SEdelweise Escala }; 83*07e028d9SEdelweise Escala 84*07e028d9SEdelweise Escala struct ltc3220 { 85*07e028d9SEdelweise Escala struct ltc3220_uled_cfg uled_cfg[LTC3220_NUM_LEDS]; 86*07e028d9SEdelweise Escala struct regmap *regmap; 87*07e028d9SEdelweise Escala struct mutex lock; 88*07e028d9SEdelweise Escala }; 89*07e028d9SEdelweise Escala 90*07e028d9SEdelweise Escala /* 91*07e028d9SEdelweise Escala * Set LED brightness. Hardware supports 0-63 brightness levels. 92*07e028d9SEdelweise Escala * Mode switching (blink/gradation) is handled through dedicated callbacks. 93*07e028d9SEdelweise Escala * 94*07e028d9SEdelweise Escala * In aggregated mode only a single LED (reg = 1) is registered and the 95*07e028d9SEdelweise Escala * hardware quick-write feature propagates the write to all 18 channels, so 96*07e028d9SEdelweise Escala * there is no need to update the other registers explicitly. 97*07e028d9SEdelweise Escala */ 98*07e028d9SEdelweise Escala static int __ltc3220_set_led_data(struct ltc3220 *ltc3220, 99*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *uled_cfg, 100*07e028d9SEdelweise Escala enum led_brightness brightness) 101*07e028d9SEdelweise Escala { 102*07e028d9SEdelweise Escala int ret; 103*07e028d9SEdelweise Escala 104*07e028d9SEdelweise Escala brightness &= LTC3220_LED_CURRENT_MASK; 105*07e028d9SEdelweise Escala 106*07e028d9SEdelweise Escala ret = regmap_write(ltc3220->regmap, LTC3220_ULED_REG(uled_cfg->led_index), 107*07e028d9SEdelweise Escala brightness); 108*07e028d9SEdelweise Escala if (ret) 109*07e028d9SEdelweise Escala return ret; 110*07e028d9SEdelweise Escala 111*07e028d9SEdelweise Escala uled_cfg->reg_value = brightness; 112*07e028d9SEdelweise Escala 113*07e028d9SEdelweise Escala return 0; 114*07e028d9SEdelweise Escala } 115*07e028d9SEdelweise Escala 116*07e028d9SEdelweise Escala static int ltc3220_set_led_data(struct led_classdev *led_cdev, 117*07e028d9SEdelweise Escala enum led_brightness brightness) 118*07e028d9SEdelweise Escala { 119*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *uled_cfg = container_of(led_cdev, struct ltc3220_uled_cfg, 120*07e028d9SEdelweise Escala led_cdev); 121*07e028d9SEdelweise Escala struct ltc3220 *ltc3220 = container_of(uled_cfg - uled_cfg->led_index, struct ltc3220, 122*07e028d9SEdelweise Escala uled_cfg[0]); 123*07e028d9SEdelweise Escala int ret; 124*07e028d9SEdelweise Escala 125*07e028d9SEdelweise Escala mutex_lock(<c3220->lock); 126*07e028d9SEdelweise Escala ret = __ltc3220_set_led_data(ltc3220, uled_cfg, brightness); 127*07e028d9SEdelweise Escala mutex_unlock(<c3220->lock); 128*07e028d9SEdelweise Escala 129*07e028d9SEdelweise Escala return ret; 130*07e028d9SEdelweise Escala } 131*07e028d9SEdelweise Escala 132*07e028d9SEdelweise Escala static enum led_brightness ltc3220_get_led_data(struct led_classdev *led_cdev) 133*07e028d9SEdelweise Escala { 134*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *uled_cfg = container_of(led_cdev, struct ltc3220_uled_cfg, 135*07e028d9SEdelweise Escala led_cdev); 136*07e028d9SEdelweise Escala 137*07e028d9SEdelweise Escala return uled_cfg->reg_value; 138*07e028d9SEdelweise Escala } 139*07e028d9SEdelweise Escala 140*07e028d9SEdelweise Escala /* 141*07e028d9SEdelweise Escala * LTC3220 pattern support for hardware-assisted breathing/gradation. 142*07e028d9SEdelweise Escala * The hardware supports 3 gradation ramp times (240ms, 480ms, 960ms) 143*07e028d9SEdelweise Escala * and can ramp up or down. The gradation period and direction are chip-global 144*07e028d9SEdelweise Escala * registers (LTC3220_GRAD_BLINK_REG), affecting all 18 channels simultaneously. 145*07e028d9SEdelweise Escala * This is a hardware limitation, not a driver bug. 146*07e028d9SEdelweise Escala * 147*07e028d9SEdelweise Escala * Pattern array interpretation: 148*07e028d9SEdelweise Escala * pattern[0].brightness = start brightness (0-63) 149*07e028d9SEdelweise Escala * pattern[0].delta_t = ramp time in milliseconds 150*07e028d9SEdelweise Escala * pattern[1].brightness = end brightness (0-63) 151*07e028d9SEdelweise Escala * pattern[1].delta_t = (optional, can be 0 or same as pattern[0].delta_t) 152*07e028d9SEdelweise Escala */ 153*07e028d9SEdelweise Escala static int ltc3220_pattern_set(struct led_classdev *led_cdev, 154*07e028d9SEdelweise Escala struct led_pattern *pattern, 155*07e028d9SEdelweise Escala u32 len, int repeat) 156*07e028d9SEdelweise Escala { 157*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *uled_cfg = container_of(led_cdev, struct ltc3220_uled_cfg, 158*07e028d9SEdelweise Escala led_cdev); 159*07e028d9SEdelweise Escala struct ltc3220 *ltc3220 = container_of(uled_cfg - uled_cfg->led_index, struct ltc3220, 160*07e028d9SEdelweise Escala uled_cfg[0]); 161*07e028d9SEdelweise Escala u8 gradation_period; 162*07e028d9SEdelweise Escala u8 start_brightness; 163*07e028d9SEdelweise Escala u8 end_brightness; 164*07e028d9SEdelweise Escala u8 gradation_val; 165*07e028d9SEdelweise Escala u8 led_mode; 166*07e028d9SEdelweise Escala bool is_increasing; 167*07e028d9SEdelweise Escala int ret; 168*07e028d9SEdelweise Escala 169*07e028d9SEdelweise Escala if (len != 2) 170*07e028d9SEdelweise Escala return -EINVAL; 171*07e028d9SEdelweise Escala 172*07e028d9SEdelweise Escala start_brightness = clamp_val(pattern[0].brightness, 0, LTC3220_LED_CURRENT_MASK); 173*07e028d9SEdelweise Escala end_brightness = clamp_val(pattern[1].brightness, 0, LTC3220_LED_CURRENT_MASK); 174*07e028d9SEdelweise Escala 175*07e028d9SEdelweise Escala is_increasing = end_brightness > start_brightness; 176*07e028d9SEdelweise Escala 177*07e028d9SEdelweise Escala if (pattern[0].delta_t == 0) 178*07e028d9SEdelweise Escala gradation_period = LTC3220_GRADATION_MODE_DISABLED; 179*07e028d9SEdelweise Escala else if (pattern[0].delta_t <= LTC3220_GRADATION_RAMP_TIME_240MS) 180*07e028d9SEdelweise Escala gradation_period = LTC3220_GRADATION_MODE_240MS_RAMP_TIME; 181*07e028d9SEdelweise Escala else if (pattern[0].delta_t <= LTC3220_GRADATION_RAMP_TIME_480MS) 182*07e028d9SEdelweise Escala gradation_period = LTC3220_GRADATION_MODE_480MS_RAMP_TIME; 183*07e028d9SEdelweise Escala else 184*07e028d9SEdelweise Escala gradation_period = LTC3220_GRADATION_MODE_960MS_RAMP_TIME; 185*07e028d9SEdelweise Escala 186*07e028d9SEdelweise Escala gradation_val = FIELD_PREP(LTC3220_GRADATION_PERIOD_MASK, gradation_period); 187*07e028d9SEdelweise Escala gradation_val |= FIELD_PREP(LTC3220_GRADATION_DIRECTION_MASK, is_increasing); 188*07e028d9SEdelweise Escala 189*07e028d9SEdelweise Escala /* 190*07e028d9SEdelweise Escala * With the ramp disabled (delta_t == 0) there is no gradation to run, 191*07e028d9SEdelweise Escala * so apply the end brightness directly in NORMAL mode instead of 192*07e028d9SEdelweise Escala * leaving the channel in gradation mode with a disabled ramp. 193*07e028d9SEdelweise Escala */ 194*07e028d9SEdelweise Escala led_mode = gradation_period == LTC3220_GRADATION_MODE_DISABLED ? 195*07e028d9SEdelweise Escala LTC3220_NORMAL_MODE : LTC3220_GRADATION_MODE; 196*07e028d9SEdelweise Escala 197*07e028d9SEdelweise Escala mutex_lock(<c3220->lock); 198*07e028d9SEdelweise Escala 199*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, LTC3220_GRAD_BLINK_REG, 200*07e028d9SEdelweise Escala LTC3220_GRADATION_MASK, gradation_val); 201*07e028d9SEdelweise Escala if (ret) 202*07e028d9SEdelweise Escala goto unlock; 203*07e028d9SEdelweise Escala 204*07e028d9SEdelweise Escala if (led_mode == LTC3220_GRADATION_MODE) { 205*07e028d9SEdelweise Escala ret = regmap_write(ltc3220->regmap, LTC3220_ULED_REG(uled_cfg->led_index), 206*07e028d9SEdelweise Escala start_brightness & LTC3220_LED_CURRENT_MASK); 207*07e028d9SEdelweise Escala if (ret) 208*07e028d9SEdelweise Escala goto unlock; 209*07e028d9SEdelweise Escala 210*07e028d9SEdelweise Escala ret = regmap_write(ltc3220->regmap, LTC3220_ULED_REG(uled_cfg->led_index), 211*07e028d9SEdelweise Escala FIELD_PREP(LTC3220_LED_MODE_MASK, led_mode) | 212*07e028d9SEdelweise Escala (end_brightness & LTC3220_LED_CURRENT_MASK)); 213*07e028d9SEdelweise Escala if (ret) 214*07e028d9SEdelweise Escala goto unlock; 215*07e028d9SEdelweise Escala 216*07e028d9SEdelweise Escala uled_cfg->reg_value = end_brightness; 217*07e028d9SEdelweise Escala } else { 218*07e028d9SEdelweise Escala ret = __ltc3220_set_led_data(ltc3220, uled_cfg, end_brightness); 219*07e028d9SEdelweise Escala if (ret) 220*07e028d9SEdelweise Escala goto unlock; 221*07e028d9SEdelweise Escala } 222*07e028d9SEdelweise Escala 223*07e028d9SEdelweise Escala unlock: 224*07e028d9SEdelweise Escala mutex_unlock(<c3220->lock); 225*07e028d9SEdelweise Escala return ret; 226*07e028d9SEdelweise Escala } 227*07e028d9SEdelweise Escala 228*07e028d9SEdelweise Escala static int ltc3220_pattern_clear(struct led_classdev *led_cdev) 229*07e028d9SEdelweise Escala { 230*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *uled_cfg = container_of(led_cdev, struct ltc3220_uled_cfg, 231*07e028d9SEdelweise Escala led_cdev); 232*07e028d9SEdelweise Escala struct ltc3220 *ltc3220 = container_of(uled_cfg - uled_cfg->led_index, struct ltc3220, 233*07e028d9SEdelweise Escala uled_cfg[0]); 234*07e028d9SEdelweise Escala int ret; 235*07e028d9SEdelweise Escala 236*07e028d9SEdelweise Escala mutex_lock(<c3220->lock); 237*07e028d9SEdelweise Escala 238*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, LTC3220_ULED_REG(uled_cfg->led_index), 239*07e028d9SEdelweise Escala LTC3220_LED_MODE_MASK, LTC3220_NORMAL_MODE); 240*07e028d9SEdelweise Escala if (ret) 241*07e028d9SEdelweise Escala goto unlock; 242*07e028d9SEdelweise Escala 243*07e028d9SEdelweise Escala ret = __ltc3220_set_led_data(ltc3220, uled_cfg, LED_OFF); 244*07e028d9SEdelweise Escala 245*07e028d9SEdelweise Escala unlock: 246*07e028d9SEdelweise Escala mutex_unlock(<c3220->lock); 247*07e028d9SEdelweise Escala return ret; 248*07e028d9SEdelweise Escala } 249*07e028d9SEdelweise Escala 250*07e028d9SEdelweise Escala /* 251*07e028d9SEdelweise Escala * LTC3220 has a global blink configuration that affects all LEDs. 252*07e028d9SEdelweise Escala * This implementation allows per-LED blink requests via sysfs, but setting 253*07e028d9SEdelweise Escala * blink on any LED reprograms the timing for all 18 channels simultaneously. 254*07e028d9SEdelweise Escala * The delay values are mapped to the hardware's discrete blink rates. 255*07e028d9SEdelweise Escala * 256*07e028d9SEdelweise Escala * HARDWARE LIMITATION: This is not a driver bug. Per-LED blink timing control 257*07e028d9SEdelweise Escala * is not possible with this hardware due to the global blink register. 258*07e028d9SEdelweise Escala */ 259*07e028d9SEdelweise Escala static int ltc3220_blink_set(struct led_classdev *led_cdev, 260*07e028d9SEdelweise Escala unsigned long *delay_on, 261*07e028d9SEdelweise Escala unsigned long *delay_off) 262*07e028d9SEdelweise Escala { 263*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *uled_cfg = container_of(led_cdev, struct ltc3220_uled_cfg, 264*07e028d9SEdelweise Escala led_cdev); 265*07e028d9SEdelweise Escala struct ltc3220 *ltc3220 = container_of(uled_cfg - uled_cfg->led_index, struct ltc3220, 266*07e028d9SEdelweise Escala uled_cfg[0]); 267*07e028d9SEdelweise Escala u8 blink_brightness; 268*07e028d9SEdelweise Escala u8 blink_mode = 0; 269*07e028d9SEdelweise Escala int ret; 270*07e028d9SEdelweise Escala 271*07e028d9SEdelweise Escala if (*delay_on <= LTC3220_BLINK_ON_156MS) 272*07e028d9SEdelweise Escala blink_mode = LTC3220_BLINK_SHORT_ON_TIME; 273*07e028d9SEdelweise Escala 274*07e028d9SEdelweise Escala if (*delay_on + *delay_off > LTC3220_BLINK_PERIOD_1250MS) 275*07e028d9SEdelweise Escala blink_mode |= LTC3220_BLINK_LONG_PERIOD; 276*07e028d9SEdelweise Escala 277*07e028d9SEdelweise Escala switch (blink_mode) { 278*07e028d9SEdelweise Escala case LTC3220_BLINK_MODE_625MS_1250MS: 279*07e028d9SEdelweise Escala *delay_on = LTC3220_BLINK_ON_625MS; 280*07e028d9SEdelweise Escala *delay_off = LTC3220_BLINK_PERIOD_1250MS - LTC3220_BLINK_ON_625MS; 281*07e028d9SEdelweise Escala break; 282*07e028d9SEdelweise Escala case LTC3220_BLINK_MODE_156MS_1250MS: 283*07e028d9SEdelweise Escala *delay_on = LTC3220_BLINK_ON_156MS; 284*07e028d9SEdelweise Escala *delay_off = LTC3220_BLINK_PERIOD_1250MS - LTC3220_BLINK_ON_156MS; 285*07e028d9SEdelweise Escala break; 286*07e028d9SEdelweise Escala case LTC3220_BLINK_MODE_625MS_2500MS: 287*07e028d9SEdelweise Escala *delay_on = LTC3220_BLINK_ON_625MS; 288*07e028d9SEdelweise Escala *delay_off = LTC3220_BLINK_PERIOD_2500MS - LTC3220_BLINK_ON_625MS; 289*07e028d9SEdelweise Escala break; 290*07e028d9SEdelweise Escala case LTC3220_BLINK_MODE_156MS_2500MS: 291*07e028d9SEdelweise Escala *delay_on = LTC3220_BLINK_ON_156MS; 292*07e028d9SEdelweise Escala *delay_off = LTC3220_BLINK_PERIOD_2500MS - LTC3220_BLINK_ON_156MS; 293*07e028d9SEdelweise Escala break; 294*07e028d9SEdelweise Escala } 295*07e028d9SEdelweise Escala 296*07e028d9SEdelweise Escala mutex_lock(<c3220->lock); 297*07e028d9SEdelweise Escala 298*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, LTC3220_GRAD_BLINK_REG, 299*07e028d9SEdelweise Escala LTC3220_BLINK_MASK, FIELD_PREP(LTC3220_BLINK_MASK, blink_mode)); 300*07e028d9SEdelweise Escala if (ret) 301*07e028d9SEdelweise Escala goto unlock; 302*07e028d9SEdelweise Escala 303*07e028d9SEdelweise Escala blink_brightness = uled_cfg->reg_value ? : led_cdev->max_brightness; 304*07e028d9SEdelweise Escala 305*07e028d9SEdelweise Escala ret = regmap_write(ltc3220->regmap, LTC3220_ULED_REG(uled_cfg->led_index), 306*07e028d9SEdelweise Escala FIELD_PREP(LTC3220_LED_MODE_MASK, LTC3220_BLINK_MODE) | 307*07e028d9SEdelweise Escala (blink_brightness & LTC3220_LED_CURRENT_MASK)); 308*07e028d9SEdelweise Escala if (ret) 309*07e028d9SEdelweise Escala goto unlock; 310*07e028d9SEdelweise Escala 311*07e028d9SEdelweise Escala uled_cfg->reg_value = blink_brightness; 312*07e028d9SEdelweise Escala 313*07e028d9SEdelweise Escala unlock: 314*07e028d9SEdelweise Escala mutex_unlock(<c3220->lock); 315*07e028d9SEdelweise Escala return ret; 316*07e028d9SEdelweise Escala } 317*07e028d9SEdelweise Escala 318*07e028d9SEdelweise Escala static void ltc3220_reset_gpio_action(void *data) 319*07e028d9SEdelweise Escala { 320*07e028d9SEdelweise Escala struct gpio_desc *reset_gpio = data; 321*07e028d9SEdelweise Escala 322*07e028d9SEdelweise Escala gpiod_set_value_cansleep(reset_gpio, 1); 323*07e028d9SEdelweise Escala } 324*07e028d9SEdelweise Escala 325*07e028d9SEdelweise Escala static int ltc3220_reset(struct ltc3220 *ltc3220, struct i2c_client *client) 326*07e028d9SEdelweise Escala { 327*07e028d9SEdelweise Escala struct gpio_desc *reset_gpio; 328*07e028d9SEdelweise Escala int ret; 329*07e028d9SEdelweise Escala 330*07e028d9SEdelweise Escala reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); 331*07e028d9SEdelweise Escala if (IS_ERR(reset_gpio)) 332*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, PTR_ERR(reset_gpio), "Failed on reset GPIO\n"); 333*07e028d9SEdelweise Escala 334*07e028d9SEdelweise Escala if (reset_gpio) { 335*07e028d9SEdelweise Escala usleep_range(10000, 12000); 336*07e028d9SEdelweise Escala gpiod_set_value_cansleep(reset_gpio, 0); 337*07e028d9SEdelweise Escala usleep_range(10000, 12000); 338*07e028d9SEdelweise Escala 339*07e028d9SEdelweise Escala ret = devm_add_action_or_reset(&client->dev, ltc3220_reset_gpio_action, 340*07e028d9SEdelweise Escala reset_gpio); 341*07e028d9SEdelweise Escala if (ret) 342*07e028d9SEdelweise Escala return ret; 343*07e028d9SEdelweise Escala } 344*07e028d9SEdelweise Escala 345*07e028d9SEdelweise Escala ret = regmap_write(ltc3220->regmap, LTC3220_COMMAND_REG, 0); 346*07e028d9SEdelweise Escala if (ret) 347*07e028d9SEdelweise Escala return ret; 348*07e028d9SEdelweise Escala 349*07e028d9SEdelweise Escala for (int i = 0; i < LTC3220_NUM_LEDS; i++) { 350*07e028d9SEdelweise Escala ret = regmap_write(ltc3220->regmap, LTC3220_ULED_REG(i), 0); 351*07e028d9SEdelweise Escala if (ret) 352*07e028d9SEdelweise Escala return ret; 353*07e028d9SEdelweise Escala } 354*07e028d9SEdelweise Escala 355*07e028d9SEdelweise Escala return regmap_write(ltc3220->regmap, LTC3220_GRAD_BLINK_REG, 0); 356*07e028d9SEdelweise Escala } 357*07e028d9SEdelweise Escala 358*07e028d9SEdelweise Escala static int ltc3220_suspend(struct device *dev) 359*07e028d9SEdelweise Escala { 360*07e028d9SEdelweise Escala struct ltc3220 *ltc3220 = i2c_get_clientdata(to_i2c_client(dev)); 361*07e028d9SEdelweise Escala int ret; 362*07e028d9SEdelweise Escala 363*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, LTC3220_COMMAND_REG, 364*07e028d9SEdelweise Escala LTC3220_SHUTDOWN_MASK, LTC3220_SHUTDOWN_MASK); 365*07e028d9SEdelweise Escala if (ret) 366*07e028d9SEdelweise Escala return ret; 367*07e028d9SEdelweise Escala 368*07e028d9SEdelweise Escala regcache_mark_dirty(ltc3220->regmap); 369*07e028d9SEdelweise Escala 370*07e028d9SEdelweise Escala return 0; 371*07e028d9SEdelweise Escala } 372*07e028d9SEdelweise Escala 373*07e028d9SEdelweise Escala static int ltc3220_resume(struct device *dev) 374*07e028d9SEdelweise Escala { 375*07e028d9SEdelweise Escala struct ltc3220 *ltc3220 = i2c_get_clientdata(to_i2c_client(dev)); 376*07e028d9SEdelweise Escala bool quick_write_enabled; 377*07e028d9SEdelweise Escala unsigned int command_reg; 378*07e028d9SEdelweise Escala int ret; 379*07e028d9SEdelweise Escala 380*07e028d9SEdelweise Escala ret = regmap_read(ltc3220->regmap, LTC3220_COMMAND_REG, &command_reg); 381*07e028d9SEdelweise Escala if (ret) 382*07e028d9SEdelweise Escala return ret; 383*07e028d9SEdelweise Escala 384*07e028d9SEdelweise Escala quick_write_enabled = command_reg & LTC3220_QUICK_WRITE_MASK; 385*07e028d9SEdelweise Escala 386*07e028d9SEdelweise Escala if (quick_write_enabled) { 387*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, LTC3220_COMMAND_REG, 388*07e028d9SEdelweise Escala LTC3220_QUICK_WRITE_MASK, 0); 389*07e028d9SEdelweise Escala if (ret) 390*07e028d9SEdelweise Escala return ret; 391*07e028d9SEdelweise Escala } 392*07e028d9SEdelweise Escala 393*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, LTC3220_COMMAND_REG, 394*07e028d9SEdelweise Escala LTC3220_SHUTDOWN_MASK, 0); 395*07e028d9SEdelweise Escala if (ret) 396*07e028d9SEdelweise Escala return ret; 397*07e028d9SEdelweise Escala 398*07e028d9SEdelweise Escala usleep_range(10000, 12000); 399*07e028d9SEdelweise Escala 400*07e028d9SEdelweise Escala ret = regcache_sync(ltc3220->regmap); 401*07e028d9SEdelweise Escala if (ret) 402*07e028d9SEdelweise Escala return ret; 403*07e028d9SEdelweise Escala 404*07e028d9SEdelweise Escala if (quick_write_enabled) { 405*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, LTC3220_COMMAND_REG, 406*07e028d9SEdelweise Escala LTC3220_QUICK_WRITE_MASK, 407*07e028d9SEdelweise Escala LTC3220_QUICK_WRITE_MASK); 408*07e028d9SEdelweise Escala if (ret) 409*07e028d9SEdelweise Escala return ret; 410*07e028d9SEdelweise Escala } 411*07e028d9SEdelweise Escala 412*07e028d9SEdelweise Escala return 0; 413*07e028d9SEdelweise Escala } 414*07e028d9SEdelweise Escala 415*07e028d9SEdelweise Escala static DEFINE_SIMPLE_DEV_PM_OPS(ltc3220_pm_ops, ltc3220_suspend, ltc3220_resume); 416*07e028d9SEdelweise Escala 417*07e028d9SEdelweise Escala static int ltc3220_probe(struct i2c_client *client) 418*07e028d9SEdelweise Escala { 419*07e028d9SEdelweise Escala struct ltc3220 *ltc3220; 420*07e028d9SEdelweise Escala bool aggregated_led_found = false; 421*07e028d9SEdelweise Escala int num_leds = 0; 422*07e028d9SEdelweise Escala u8 led_index = 0; 423*07e028d9SEdelweise Escala int ret; 424*07e028d9SEdelweise Escala 425*07e028d9SEdelweise Escala ltc3220 = devm_kzalloc(&client->dev, sizeof(*ltc3220), GFP_KERNEL); 426*07e028d9SEdelweise Escala if (!ltc3220) 427*07e028d9SEdelweise Escala return -ENOMEM; 428*07e028d9SEdelweise Escala 429*07e028d9SEdelweise Escala ltc3220->regmap = devm_regmap_init_i2c(client, <c3220_regmap_config); 430*07e028d9SEdelweise Escala if (IS_ERR(ltc3220->regmap)) 431*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, PTR_ERR(ltc3220->regmap), 432*07e028d9SEdelweise Escala "Failed to initialize regmap\n"); 433*07e028d9SEdelweise Escala 434*07e028d9SEdelweise Escala ret = devm_mutex_init(&client->dev, <c3220->lock); 435*07e028d9SEdelweise Escala if (ret) 436*07e028d9SEdelweise Escala return ret; 437*07e028d9SEdelweise Escala 438*07e028d9SEdelweise Escala i2c_set_clientdata(client, ltc3220); 439*07e028d9SEdelweise Escala 440*07e028d9SEdelweise Escala ret = ltc3220_reset(ltc3220, client); 441*07e028d9SEdelweise Escala if (ret) 442*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, ret, "Failed to reset device\n"); 443*07e028d9SEdelweise Escala 444*07e028d9SEdelweise Escala /* First pass: validate configuration and set up LED structures */ 445*07e028d9SEdelweise Escala device_for_each_child_node_scoped(&client->dev, child) { 446*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *led; 447*07e028d9SEdelweise Escala u32 source; 448*07e028d9SEdelweise Escala 449*07e028d9SEdelweise Escala ret = fwnode_property_read_u32(child, "reg", &source); 450*07e028d9SEdelweise Escala if (ret) 451*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, ret, "Couldn't read LED address\n"); 452*07e028d9SEdelweise Escala 453*07e028d9SEdelweise Escala if (!source || source > LTC3220_NUM_LEDS) 454*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, "LED address out of range\n"); 455*07e028d9SEdelweise Escala 456*07e028d9SEdelweise Escala if (fwnode_property_present(child, "led-sources")) { 457*07e028d9SEdelweise Escala u32 led_sources[LTC3220_NUM_LEDS]; 458*07e028d9SEdelweise Escala int count; 459*07e028d9SEdelweise Escala 460*07e028d9SEdelweise Escala if (source != 1) 461*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 462*07e028d9SEdelweise Escala "Aggregated LED out of range\n"); 463*07e028d9SEdelweise Escala 464*07e028d9SEdelweise Escala if (aggregated_led_found) 465*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 466*07e028d9SEdelweise Escala "One Aggregated LED only\n"); 467*07e028d9SEdelweise Escala 468*07e028d9SEdelweise Escala count = fwnode_property_count_u32(child, "led-sources"); 469*07e028d9SEdelweise Escala if (count != LTC3220_NUM_LEDS) 470*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 471*07e028d9SEdelweise Escala "Aggregated mode requires all %d outputs in led-sources, got %d\n", 472*07e028d9SEdelweise Escala LTC3220_NUM_LEDS, count); 473*07e028d9SEdelweise Escala 474*07e028d9SEdelweise Escala ret = fwnode_property_read_u32_array(child, "led-sources", 475*07e028d9SEdelweise Escala led_sources, LTC3220_NUM_LEDS); 476*07e028d9SEdelweise Escala if (ret) 477*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, ret, 478*07e028d9SEdelweise Escala "Failed to read led-sources array\n"); 479*07e028d9SEdelweise Escala 480*07e028d9SEdelweise Escala /* 481*07e028d9SEdelweise Escala * Validate array contents for DT correctness. The hardware 482*07e028d9SEdelweise Escala * quick-write broadcasts to all 18 channels regardless of 483*07e028d9SEdelweise Escala * array contents, but checking helps catch DT mistakes. 484*07e028d9SEdelweise Escala */ 485*07e028d9SEdelweise Escala for (int i = 0; i < LTC3220_NUM_LEDS; i++) { 486*07e028d9SEdelweise Escala if (led_sources[i] < 1 || led_sources[i] > LTC3220_NUM_LEDS) 487*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 488*07e028d9SEdelweise Escala "Invalid output %u in led-sources\n", 489*07e028d9SEdelweise Escala led_sources[i]); 490*07e028d9SEdelweise Escala } 491*07e028d9SEdelweise Escala 492*07e028d9SEdelweise Escala aggregated_led_found = true; 493*07e028d9SEdelweise Escala } 494*07e028d9SEdelweise Escala 495*07e028d9SEdelweise Escala num_leds++; 496*07e028d9SEdelweise Escala 497*07e028d9SEdelweise Escala /* LED node reg/index/address goes from 1 to 18 */ 498*07e028d9SEdelweise Escala led_index = source - 1; 499*07e028d9SEdelweise Escala led = <c3220->uled_cfg[led_index]; 500*07e028d9SEdelweise Escala 501*07e028d9SEdelweise Escala if (led->registered) 502*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 503*07e028d9SEdelweise Escala "Duplicate LED reg %u found\n", source); 504*07e028d9SEdelweise Escala 505*07e028d9SEdelweise Escala led->registered = true; 506*07e028d9SEdelweise Escala led->led_index = led_index; 507*07e028d9SEdelweise Escala led->reg_value = 0; 508*07e028d9SEdelweise Escala led->led_cdev.brightness_set_blocking = ltc3220_set_led_data; 509*07e028d9SEdelweise Escala led->led_cdev.brightness_get = ltc3220_get_led_data; 510*07e028d9SEdelweise Escala led->led_cdev.max_brightness = LTC3220_MAX_BRIGHTNESS; 511*07e028d9SEdelweise Escala led->led_cdev.blink_set = ltc3220_blink_set; 512*07e028d9SEdelweise Escala led->led_cdev.pattern_set = ltc3220_pattern_set; 513*07e028d9SEdelweise Escala led->led_cdev.pattern_clear = ltc3220_pattern_clear; 514*07e028d9SEdelweise Escala } 515*07e028d9SEdelweise Escala 516*07e028d9SEdelweise Escala /* 517*07e028d9SEdelweise Escala * Aggregated LED mode uses hardware quick-write to control all 18 LEDs 518*07e028d9SEdelweise Escala * simultaneously. This is mutually exclusive with individual LED control. 519*07e028d9SEdelweise Escala * See Documentation/devicetree/bindings/leds/adi,ltc3220.yaml for details 520*07e028d9SEdelweise Escala * on how to configure aggregated LED mode. 521*07e028d9SEdelweise Escala */ 522*07e028d9SEdelweise Escala if (aggregated_led_found && num_leds > 1) 523*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 524*07e028d9SEdelweise Escala "Aggregated LED must be the only LED node\n"); 525*07e028d9SEdelweise Escala 526*07e028d9SEdelweise Escala if (num_leds == 0) 527*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 528*07e028d9SEdelweise Escala "No LED nodes found in device tree\n"); 529*07e028d9SEdelweise Escala 530*07e028d9SEdelweise Escala if (aggregated_led_found) { 531*07e028d9SEdelweise Escala ret = regmap_update_bits(ltc3220->regmap, 532*07e028d9SEdelweise Escala LTC3220_COMMAND_REG, 533*07e028d9SEdelweise Escala LTC3220_QUICK_WRITE_MASK, 534*07e028d9SEdelweise Escala LTC3220_QUICK_WRITE_MASK); 535*07e028d9SEdelweise Escala if (ret) 536*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, ret, 537*07e028d9SEdelweise Escala "Failed to set quick write mode\n"); 538*07e028d9SEdelweise Escala } 539*07e028d9SEdelweise Escala 540*07e028d9SEdelweise Escala /* Second pass: register LEDs after validation */ 541*07e028d9SEdelweise Escala device_for_each_child_node_scoped(&client->dev, child) { 542*07e028d9SEdelweise Escala struct led_init_data init_data = {}; 543*07e028d9SEdelweise Escala struct ltc3220_uled_cfg *led; 544*07e028d9SEdelweise Escala u32 source; 545*07e028d9SEdelweise Escala 546*07e028d9SEdelweise Escala ret = fwnode_property_read_u32(child, "reg", &source); 547*07e028d9SEdelweise Escala if (ret) 548*07e028d9SEdelweise Escala return ret; 549*07e028d9SEdelweise Escala 550*07e028d9SEdelweise Escala if (!source || source > LTC3220_NUM_LEDS) 551*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, -EINVAL, 552*07e028d9SEdelweise Escala "LED address out of range in second pass\n"); 553*07e028d9SEdelweise Escala 554*07e028d9SEdelweise Escala init_data.fwnode = child; 555*07e028d9SEdelweise Escala init_data.devicename = "ltc3220"; 556*07e028d9SEdelweise Escala 557*07e028d9SEdelweise Escala led_index = source - 1; 558*07e028d9SEdelweise Escala led = <c3220->uled_cfg[led_index]; 559*07e028d9SEdelweise Escala 560*07e028d9SEdelweise Escala ret = devm_led_classdev_register_ext(&client->dev, &led->led_cdev, &init_data); 561*07e028d9SEdelweise Escala if (ret) 562*07e028d9SEdelweise Escala return dev_err_probe(&client->dev, ret, "Failed to register LED class\n"); 563*07e028d9SEdelweise Escala } 564*07e028d9SEdelweise Escala 565*07e028d9SEdelweise Escala return 0; 566*07e028d9SEdelweise Escala } 567*07e028d9SEdelweise Escala 568*07e028d9SEdelweise Escala static const struct of_device_id ltc3220_of_match[] = { 569*07e028d9SEdelweise Escala { .compatible = "adi,ltc3220" }, 570*07e028d9SEdelweise Escala { } 571*07e028d9SEdelweise Escala }; 572*07e028d9SEdelweise Escala MODULE_DEVICE_TABLE(of, ltc3220_of_match); 573*07e028d9SEdelweise Escala 574*07e028d9SEdelweise Escala static struct i2c_driver ltc3220_led_driver = { 575*07e028d9SEdelweise Escala .driver = { 576*07e028d9SEdelweise Escala .name = "ltc3220", 577*07e028d9SEdelweise Escala .of_match_table = ltc3220_of_match, 578*07e028d9SEdelweise Escala .pm = pm_sleep_ptr(<c3220_pm_ops), 579*07e028d9SEdelweise Escala }, 580*07e028d9SEdelweise Escala .probe = ltc3220_probe, 581*07e028d9SEdelweise Escala }; 582*07e028d9SEdelweise Escala module_i2c_driver(ltc3220_led_driver); 583*07e028d9SEdelweise Escala 584*07e028d9SEdelweise Escala MODULE_AUTHOR("Edelweise Escala <edelweise.escala@analog.com>"); 585*07e028d9SEdelweise Escala MODULE_DESCRIPTION("LED driver for LTC3220 controllers"); 586*07e028d9SEdelweise Escala MODULE_LICENSE("GPL"); 587