1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2015, Sony Mobile Communications, AB. 3 */ 4 5 #include <linux/delay.h> 6 #include <linux/interrupt.h> 7 #include <linux/ktime.h> 8 #include <linux/kernel.h> 9 #include <linux/backlight.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_device.h> 13 #include <linux/of_address.h> 14 #include <linux/regmap.h> 15 16 /* From DT binding */ 17 #define WLED_MAX_STRINGS 4 18 #define MOD_A 0 19 #define MOD_B 1 20 21 #define WLED_DEFAULT_BRIGHTNESS 2048 22 #define WLED_SOFT_START_DLY_US 10000 23 #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF 24 #define WLED5_SINK_REG_BRIGHT_MAX_12B 0xFFF 25 #define WLED5_SINK_REG_BRIGHT_MAX_15B 0x7FFF 26 27 /* WLED3/WLED4 control registers */ 28 #define WLED3_CTRL_REG_FAULT_STATUS 0x08 29 #define WLED3_CTRL_REG_ILIM_FAULT_BIT BIT(0) 30 #define WLED3_CTRL_REG_OVP_FAULT_BIT BIT(1) 31 #define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) 32 #define WLED5_CTRL_REG_OVP_PRE_ALARM_BIT BIT(4) 33 34 #define WLED3_CTRL_REG_INT_RT_STS 0x10 35 #define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1) 36 37 #define WLED3_CTRL_REG_MOD_EN 0x46 38 #define WLED3_CTRL_REG_MOD_EN_MASK BIT(7) 39 #define WLED3_CTRL_REG_MOD_EN_SHIFT 7 40 41 #define WLED3_CTRL_REG_FEEDBACK_CONTROL 0x48 42 43 #define WLED3_CTRL_REG_FREQ 0x4c 44 #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0) 45 46 #define WLED3_CTRL_REG_OVP 0x4d 47 #define WLED3_CTRL_REG_OVP_MASK GENMASK(1, 0) 48 #define WLED5_CTRL_REG_OVP_MASK GENMASK(3, 0) 49 50 #define WLED3_CTRL_REG_ILIMIT 0x4e 51 #define WLED3_CTRL_REG_ILIMIT_MASK GENMASK(2, 0) 52 53 /* WLED3/WLED4 sink registers */ 54 #define WLED3_SINK_REG_SYNC 0x47 55 #define WLED3_SINK_REG_SYNC_CLEAR 0x00 56 57 #define WLED3_SINK_REG_CURR_SINK 0x4f 58 #define WLED3_SINK_REG_CURR_SINK_MASK GENMASK(7, 5) 59 #define WLED3_SINK_REG_CURR_SINK_SHFT 5 60 61 /* WLED3 specific per-'string' registers below */ 62 #define WLED3_SINK_REG_BRIGHT(n) (0x40 + n) 63 64 #define WLED3_SINK_REG_STR_MOD_EN(n) (0x60 + (n * 0x10)) 65 #define WLED3_SINK_REG_STR_MOD_MASK BIT(7) 66 67 #define WLED3_SINK_REG_STR_FULL_SCALE_CURR(n) (0x62 + (n * 0x10)) 68 #define WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK GENMASK(4, 0) 69 70 #define WLED3_SINK_REG_STR_MOD_SRC(n) (0x63 + (n * 0x10)) 71 #define WLED3_SINK_REG_STR_MOD_SRC_MASK BIT(0) 72 #define WLED3_SINK_REG_STR_MOD_SRC_INT 0x00 73 #define WLED3_SINK_REG_STR_MOD_SRC_EXT 0x01 74 75 #define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10)) 76 #define WLED3_SINK_REG_STR_CABC_MASK BIT(7) 77 78 /* WLED4 specific control registers */ 79 #define WLED4_CTRL_REG_SHORT_PROTECT 0x5e 80 #define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7) 81 82 #define WLED4_CTRL_REG_SEC_ACCESS 0xd0 83 #define WLED4_CTRL_REG_SEC_UNLOCK 0xa5 84 85 #define WLED4_CTRL_REG_TEST1 0xe2 86 #define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09 87 88 /* WLED4 specific sink registers */ 89 #define WLED4_SINK_REG_CURR_SINK 0x46 90 #define WLED4_SINK_REG_CURR_SINK_MASK GENMASK(7, 4) 91 #define WLED4_SINK_REG_CURR_SINK_SHFT 4 92 93 /* WLED4 specific per-'string' registers below */ 94 #define WLED4_SINK_REG_STR_MOD_EN(n) (0x50 + (n * 0x10)) 95 #define WLED4_SINK_REG_STR_MOD_MASK BIT(7) 96 97 #define WLED4_SINK_REG_STR_FULL_SCALE_CURR(n) (0x52 + (n * 0x10)) 98 #define WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK GENMASK(3, 0) 99 100 #define WLED4_SINK_REG_STR_MOD_SRC(n) (0x53 + (n * 0x10)) 101 #define WLED4_SINK_REG_STR_MOD_SRC_MASK BIT(0) 102 #define WLED4_SINK_REG_STR_MOD_SRC_INT 0x00 103 #define WLED4_SINK_REG_STR_MOD_SRC_EXT 0x01 104 105 #define WLED4_SINK_REG_STR_CABC(n) (0x56 + (n * 0x10)) 106 #define WLED4_SINK_REG_STR_CABC_MASK BIT(7) 107 108 #define WLED4_SINK_REG_BRIGHT(n) (0x57 + (n * 0x10)) 109 110 /* WLED5 specific control registers */ 111 #define WLED5_CTRL_REG_OVP_INT_CTL 0x5f 112 #define WLED5_CTRL_REG_OVP_INT_TIMER_MASK GENMASK(2, 0) 113 114 /* WLED5 specific sink registers */ 115 #define WLED5_SINK_REG_MOD_A_EN 0x50 116 #define WLED5_SINK_REG_MOD_B_EN 0x60 117 #define WLED5_SINK_REG_MOD_EN_MASK BIT(7) 118 119 #define WLED5_SINK_REG_MOD_A_SRC_SEL 0x51 120 #define WLED5_SINK_REG_MOD_B_SRC_SEL 0x61 121 #define WLED5_SINK_REG_MOD_SRC_SEL_HIGH 0 122 #define WLED5_SINK_REG_MOD_SRC_SEL_EXT 0x03 123 #define WLED5_SINK_REG_MOD_SRC_SEL_MASK GENMASK(1, 0) 124 125 #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL 0x52 126 #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL 0x62 127 #define WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B 0 128 #define WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B 1 129 130 #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB 0x53 131 #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_MSB 0x54 132 #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB 0x63 133 #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_MSB 0x64 134 135 #define WLED5_SINK_REG_MOD_SYNC_BIT 0x65 136 #define WLED5_SINK_REG_SYNC_MOD_A_BIT BIT(0) 137 #define WLED5_SINK_REG_SYNC_MOD_B_BIT BIT(1) 138 #define WLED5_SINK_REG_SYNC_MASK GENMASK(1, 0) 139 140 /* WLED5 specific per-'string' registers below */ 141 #define WLED5_SINK_REG_STR_FULL_SCALE_CURR(n) (0x72 + (n * 0x10)) 142 143 #define WLED5_SINK_REG_STR_SRC_SEL(n) (0x73 + (n * 0x10)) 144 #define WLED5_SINK_REG_SRC_SEL_MOD_A 0 145 #define WLED5_SINK_REG_SRC_SEL_MOD_B 1 146 #define WLED5_SINK_REG_SRC_SEL_MASK GENMASK(1, 0) 147 148 struct wled_var_cfg { 149 const u32 *values; 150 u32 (*fn)(u32); 151 int size; 152 }; 153 154 struct wled_u32_opts { 155 const char *name; 156 u32 *val_ptr; 157 const struct wled_var_cfg *cfg; 158 }; 159 160 struct wled_bool_opts { 161 const char *name; 162 bool *val_ptr; 163 }; 164 165 struct wled_config { 166 u32 boost_i_limit; 167 u32 ovp; 168 u32 switch_freq; 169 u32 num_strings; 170 u32 string_i_limit; 171 u32 enabled_strings[WLED_MAX_STRINGS]; 172 u32 mod_sel; 173 u32 cabc_sel; 174 bool cs_out_en; 175 bool ext_gen; 176 bool cabc; 177 bool external_pfet; 178 bool auto_detection_enabled; 179 }; 180 181 struct wled { 182 const char *name; 183 struct device *dev; 184 struct regmap *regmap; 185 struct mutex lock; /* Lock to avoid race from thread irq handler */ 186 ktime_t last_short_event; 187 ktime_t start_ovp_fault_time; 188 u16 ctrl_addr; 189 u16 sink_addr; 190 u16 max_string_count; 191 u16 auto_detection_ovp_count; 192 u32 brightness; 193 u32 max_brightness; 194 u32 short_count; 195 u32 auto_detect_count; 196 u32 version; 197 bool disabled_by_short; 198 bool has_short_detect; 199 bool cabc_disabled; 200 int short_irq; 201 int ovp_irq; 202 203 struct wled_config cfg; 204 struct delayed_work ovp_work; 205 206 /* Configures the brightness. Applicable for wled3, wled4 and wled5 */ 207 int (*wled_set_brightness)(struct wled *wled, u16 brightness); 208 209 /* Configures the cabc register. Applicable for wled4 and wled5 */ 210 int (*wled_cabc_config)(struct wled *wled, bool enable); 211 212 /* 213 * Toggles the sync bit for the brightness update to take place. 214 * Applicable for WLED3, WLED4 and WLED5. 215 */ 216 int (*wled_sync_toggle)(struct wled *wled); 217 218 /* 219 * Time to wait before checking the OVP status after wled module enable. 220 * Applicable for WLED4 and WLED5. 221 */ 222 int (*wled_ovp_delay)(struct wled *wled); 223 224 /* 225 * Determines if the auto string detection is required. 226 * Applicable for WLED4 and WLED5 227 */ 228 bool (*wled_auto_detection_required)(struct wled *wled); 229 }; 230 231 static int wled3_set_brightness(struct wled *wled, u16 brightness) 232 { 233 int rc, i; 234 u8 v[2]; 235 236 v[0] = brightness & 0xff; 237 v[1] = (brightness >> 8) & 0xf; 238 239 for (i = 0; i < wled->cfg.num_strings; ++i) { 240 rc = regmap_bulk_write(wled->regmap, wled->ctrl_addr + 241 WLED3_SINK_REG_BRIGHT(i), v, 2); 242 if (rc < 0) 243 return rc; 244 } 245 246 return 0; 247 } 248 249 static int wled4_set_brightness(struct wled *wled, u16 brightness) 250 { 251 int rc, i; 252 u16 low_limit = wled->max_brightness * 4 / 1000; 253 u8 v[2]; 254 255 /* WLED4's lower limit of operation is 0.4% */ 256 if (brightness > 0 && brightness < low_limit) 257 brightness = low_limit; 258 259 v[0] = brightness & 0xff; 260 v[1] = (brightness >> 8) & 0xf; 261 262 for (i = 0; i < wled->cfg.num_strings; ++i) { 263 rc = regmap_bulk_write(wled->regmap, wled->sink_addr + 264 WLED4_SINK_REG_BRIGHT(i), v, 2); 265 if (rc < 0) 266 return rc; 267 } 268 269 return 0; 270 } 271 272 static int wled5_set_brightness(struct wled *wled, u16 brightness) 273 { 274 int rc, offset; 275 u16 low_limit = wled->max_brightness * 1 / 1000; 276 u8 v[2]; 277 278 /* WLED5's lower limit is 0.1% */ 279 if (brightness < low_limit) 280 brightness = low_limit; 281 282 v[0] = brightness & 0xff; 283 v[1] = (brightness >> 8) & 0x7f; 284 285 offset = (wled->cfg.mod_sel == MOD_A) ? 286 WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB : 287 WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB; 288 289 rc = regmap_bulk_write(wled->regmap, wled->sink_addr + offset, 290 v, 2); 291 return rc; 292 } 293 294 static void wled_ovp_work(struct work_struct *work) 295 { 296 struct wled *wled = container_of(work, 297 struct wled, ovp_work.work); 298 enable_irq(wled->ovp_irq); 299 } 300 301 static int wled_module_enable(struct wled *wled, int val) 302 { 303 int rc; 304 305 if (wled->disabled_by_short) 306 return -ENXIO; 307 308 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 309 WLED3_CTRL_REG_MOD_EN, 310 WLED3_CTRL_REG_MOD_EN_MASK, 311 val << WLED3_CTRL_REG_MOD_EN_SHIFT); 312 if (rc < 0) 313 return rc; 314 315 if (wled->ovp_irq > 0) { 316 if (val) { 317 /* 318 * The hardware generates a storm of spurious OVP 319 * interrupts during soft start operations. So defer 320 * enabling the IRQ for 10ms to ensure that the 321 * soft start is complete. 322 */ 323 schedule_delayed_work(&wled->ovp_work, HZ / 100); 324 } else { 325 if (!cancel_delayed_work_sync(&wled->ovp_work)) 326 disable_irq(wled->ovp_irq); 327 } 328 } 329 330 return 0; 331 } 332 333 static int wled3_sync_toggle(struct wled *wled) 334 { 335 int rc; 336 unsigned int mask = GENMASK(wled->max_string_count - 1, 0); 337 338 rc = regmap_update_bits(wled->regmap, 339 wled->sink_addr + WLED3_SINK_REG_SYNC, 340 mask, WLED3_SINK_REG_SYNC_CLEAR); 341 if (rc < 0) 342 return rc; 343 344 rc = regmap_update_bits(wled->regmap, 345 wled->sink_addr + WLED3_SINK_REG_SYNC, 346 mask, mask); 347 348 return rc; 349 } 350 351 static int wled5_mod_sync_toggle(struct wled *wled) 352 { 353 int rc; 354 u8 val; 355 356 rc = regmap_update_bits(wled->regmap, 357 wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, 358 WLED5_SINK_REG_SYNC_MASK, 0); 359 if (rc < 0) 360 return rc; 361 362 val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : 363 WLED5_SINK_REG_SYNC_MOD_B_BIT; 364 return regmap_update_bits(wled->regmap, 365 wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, 366 WLED5_SINK_REG_SYNC_MASK, val); 367 } 368 369 static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) 370 { 371 int rc; 372 u32 int_rt_sts, fault_sts; 373 374 *fault_set = false; 375 rc = regmap_read(wled->regmap, 376 wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, 377 &int_rt_sts); 378 if (rc < 0) { 379 dev_err(wled->dev, "Failed to read INT_RT_STS rc=%d\n", rc); 380 return rc; 381 } 382 383 rc = regmap_read(wled->regmap, 384 wled->ctrl_addr + WLED3_CTRL_REG_FAULT_STATUS, 385 &fault_sts); 386 if (rc < 0) { 387 dev_err(wled->dev, "Failed to read FAULT_STATUS rc=%d\n", rc); 388 return rc; 389 } 390 391 if (int_rt_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS) 392 *fault_set = true; 393 394 if (wled->version == 4 && (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT)) 395 *fault_set = true; 396 397 if (wled->version == 5 && (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT | 398 WLED5_CTRL_REG_OVP_PRE_ALARM_BIT))) 399 *fault_set = true; 400 401 if (*fault_set) 402 dev_dbg(wled->dev, "WLED OVP fault detected, int_rt_sts=0x%x fault_sts=0x%x\n", 403 int_rt_sts, fault_sts); 404 405 return rc; 406 } 407 408 static int wled4_ovp_delay(struct wled *wled) 409 { 410 return WLED_SOFT_START_DLY_US; 411 } 412 413 static int wled5_ovp_delay(struct wled *wled) 414 { 415 int rc, delay_us; 416 u32 val; 417 u8 ovp_timer_ms[8] = {1, 2, 4, 8, 12, 16, 20, 24}; 418 419 /* For WLED5, get the delay based on OVP timer */ 420 rc = regmap_read(wled->regmap, wled->ctrl_addr + 421 WLED5_CTRL_REG_OVP_INT_CTL, &val); 422 if (rc < 0) 423 delay_us = 424 ovp_timer_ms[val & WLED5_CTRL_REG_OVP_INT_TIMER_MASK] * 1000; 425 else 426 delay_us = 2 * WLED_SOFT_START_DLY_US; 427 428 dev_dbg(wled->dev, "delay_time_us: %d\n", delay_us); 429 430 return delay_us; 431 } 432 433 static int wled_update_status(struct backlight_device *bl) 434 { 435 struct wled *wled = bl_get_data(bl); 436 u16 brightness = backlight_get_brightness(bl); 437 int rc = 0; 438 439 mutex_lock(&wled->lock); 440 if (brightness) { 441 rc = wled->wled_set_brightness(wled, brightness); 442 if (rc < 0) { 443 dev_err(wled->dev, "wled failed to set brightness rc:%d\n", 444 rc); 445 goto unlock_mutex; 446 } 447 448 if (wled->version < 5) { 449 rc = wled->wled_sync_toggle(wled); 450 if (rc < 0) { 451 dev_err(wled->dev, "wled sync failed rc:%d\n", rc); 452 goto unlock_mutex; 453 } 454 } else { 455 /* 456 * For WLED5 toggling the MOD_SYNC_BIT updates the 457 * brightness 458 */ 459 rc = wled5_mod_sync_toggle(wled); 460 if (rc < 0) { 461 dev_err(wled->dev, "wled mod sync failed rc:%d\n", 462 rc); 463 goto unlock_mutex; 464 } 465 } 466 } 467 468 if (!!brightness != !!wled->brightness) { 469 rc = wled_module_enable(wled, !!brightness); 470 if (rc < 0) { 471 dev_err(wled->dev, "wled enable failed rc:%d\n", rc); 472 goto unlock_mutex; 473 } 474 } 475 476 wled->brightness = brightness; 477 478 unlock_mutex: 479 mutex_unlock(&wled->lock); 480 481 return rc; 482 } 483 484 static int wled4_cabc_config(struct wled *wled, bool enable) 485 { 486 int i, j, rc; 487 u8 val; 488 489 for (i = 0; i < wled->cfg.num_strings; i++) { 490 j = wled->cfg.enabled_strings[i]; 491 492 val = enable ? WLED4_SINK_REG_STR_CABC_MASK : 0; 493 rc = regmap_update_bits(wled->regmap, wled->sink_addr + 494 WLED4_SINK_REG_STR_CABC(j), 495 WLED4_SINK_REG_STR_CABC_MASK, val); 496 if (rc < 0) 497 return rc; 498 } 499 500 return 0; 501 } 502 503 static int wled5_cabc_config(struct wled *wled, bool enable) 504 { 505 int rc, offset; 506 u8 reg; 507 508 if (wled->cabc_disabled) 509 return 0; 510 511 reg = enable ? wled->cfg.cabc_sel : 0; 512 offset = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_A_SRC_SEL : 513 WLED5_SINK_REG_MOD_B_SRC_SEL; 514 515 rc = regmap_update_bits(wled->regmap, wled->sink_addr + offset, 516 WLED5_SINK_REG_MOD_SRC_SEL_MASK, reg); 517 if (rc < 0) { 518 pr_err("Error in configuring CABC rc=%d\n", rc); 519 return rc; 520 } 521 522 if (!wled->cfg.cabc_sel) 523 wled->cabc_disabled = true; 524 525 return 0; 526 } 527 528 #define WLED_SHORT_DLY_MS 20 529 #define WLED_SHORT_CNT_MAX 5 530 #define WLED_SHORT_RESET_CNT_DLY_US USEC_PER_SEC 531 532 static irqreturn_t wled_short_irq_handler(int irq, void *_wled) 533 { 534 struct wled *wled = _wled; 535 int rc; 536 s64 elapsed_time; 537 538 wled->short_count++; 539 mutex_lock(&wled->lock); 540 rc = wled_module_enable(wled, false); 541 if (rc < 0) { 542 dev_err(wled->dev, "wled disable failed rc:%d\n", rc); 543 goto unlock_mutex; 544 } 545 546 elapsed_time = ktime_us_delta(ktime_get(), 547 wled->last_short_event); 548 if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US) 549 wled->short_count = 1; 550 551 if (wled->short_count > WLED_SHORT_CNT_MAX) { 552 dev_err(wled->dev, "Short triggered %d times, disabling WLED forever!\n", 553 wled->short_count); 554 wled->disabled_by_short = true; 555 goto unlock_mutex; 556 } 557 558 wled->last_short_event = ktime_get(); 559 560 msleep(WLED_SHORT_DLY_MS); 561 rc = wled_module_enable(wled, true); 562 if (rc < 0) 563 dev_err(wled->dev, "wled enable failed rc:%d\n", rc); 564 565 unlock_mutex: 566 mutex_unlock(&wled->lock); 567 568 return IRQ_HANDLED; 569 } 570 571 #define AUTO_DETECT_BRIGHTNESS 200 572 573 static void wled_auto_string_detection(struct wled *wled) 574 { 575 int rc = 0, i, delay_time_us; 576 u32 sink_config = 0; 577 u8 sink_test = 0, sink_valid = 0, val; 578 bool fault_set; 579 580 /* Read configured sink configuration */ 581 rc = regmap_read(wled->regmap, wled->sink_addr + 582 WLED4_SINK_REG_CURR_SINK, &sink_config); 583 if (rc < 0) { 584 dev_err(wled->dev, "Failed to read SINK configuration rc=%d\n", 585 rc); 586 goto failed_detect; 587 } 588 589 /* Disable the module before starting detection */ 590 rc = regmap_update_bits(wled->regmap, 591 wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, 592 WLED3_CTRL_REG_MOD_EN_MASK, 0); 593 if (rc < 0) { 594 dev_err(wled->dev, "Failed to disable WLED module rc=%d\n", rc); 595 goto failed_detect; 596 } 597 598 /* Set low brightness across all sinks */ 599 rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS); 600 if (rc < 0) { 601 dev_err(wled->dev, "Failed to set brightness for auto detection rc=%d\n", 602 rc); 603 goto failed_detect; 604 } 605 606 if (wled->cfg.cabc) { 607 rc = wled->wled_cabc_config(wled, false); 608 if (rc < 0) 609 goto failed_detect; 610 } 611 612 /* Disable all sinks */ 613 rc = regmap_write(wled->regmap, 614 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0); 615 if (rc < 0) { 616 dev_err(wled->dev, "Failed to disable all sinks rc=%d\n", rc); 617 goto failed_detect; 618 } 619 620 /* Iterate through the strings one by one */ 621 for (i = 0; i < wled->cfg.num_strings; i++) { 622 sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + i)); 623 624 /* Enable feedback control */ 625 rc = regmap_write(wled->regmap, wled->ctrl_addr + 626 WLED3_CTRL_REG_FEEDBACK_CONTROL, i + 1); 627 if (rc < 0) { 628 dev_err(wled->dev, "Failed to enable feedback for SINK %d rc = %d\n", 629 i + 1, rc); 630 goto failed_detect; 631 } 632 633 /* Enable the sink */ 634 rc = regmap_write(wled->regmap, wled->sink_addr + 635 WLED4_SINK_REG_CURR_SINK, sink_test); 636 if (rc < 0) { 637 dev_err(wled->dev, "Failed to configure SINK %d rc=%d\n", 638 i + 1, rc); 639 goto failed_detect; 640 } 641 642 /* Enable the module */ 643 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 644 WLED3_CTRL_REG_MOD_EN, 645 WLED3_CTRL_REG_MOD_EN_MASK, 646 WLED3_CTRL_REG_MOD_EN_MASK); 647 if (rc < 0) { 648 dev_err(wled->dev, "Failed to enable WLED module rc=%d\n", 649 rc); 650 goto failed_detect; 651 } 652 653 delay_time_us = wled->wled_ovp_delay(wled); 654 usleep_range(delay_time_us, delay_time_us + 1000); 655 656 rc = wled_ovp_fault_status(wled, &fault_set); 657 if (rc < 0) { 658 dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n", 659 rc); 660 goto failed_detect; 661 } 662 663 if (fault_set) 664 dev_dbg(wled->dev, "WLED OVP fault detected with SINK %d\n", 665 i + 1); 666 else 667 sink_valid |= sink_test; 668 669 /* Disable the module */ 670 rc = regmap_update_bits(wled->regmap, 671 wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, 672 WLED3_CTRL_REG_MOD_EN_MASK, 0); 673 if (rc < 0) { 674 dev_err(wled->dev, "Failed to disable WLED module rc=%d\n", 675 rc); 676 goto failed_detect; 677 } 678 } 679 680 if (!sink_valid) { 681 dev_err(wled->dev, "No valid WLED sinks found\n"); 682 wled->disabled_by_short = true; 683 goto failed_detect; 684 } 685 686 if (sink_valid != sink_config) { 687 dev_warn(wled->dev, "%x is not a valid sink configuration - using %x instead\n", 688 sink_config, sink_valid); 689 sink_config = sink_valid; 690 } 691 692 /* Write the new sink configuration */ 693 rc = regmap_write(wled->regmap, 694 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 695 sink_config); 696 if (rc < 0) { 697 dev_err(wled->dev, "Failed to reconfigure the default sink rc=%d\n", 698 rc); 699 goto failed_detect; 700 } 701 702 /* Enable valid sinks */ 703 if (wled->version == 4) { 704 for (i = 0; i < wled->cfg.num_strings; i++) { 705 if (sink_config & 706 BIT(WLED4_SINK_REG_CURR_SINK_SHFT + i)) 707 val = WLED4_SINK_REG_STR_MOD_MASK; 708 else 709 /* Disable modulator_en for unused sink */ 710 val = 0; 711 712 rc = regmap_write(wled->regmap, wled->sink_addr + 713 WLED4_SINK_REG_STR_MOD_EN(i), val); 714 if (rc < 0) { 715 dev_err(wled->dev, "Failed to configure MODULATOR_EN rc=%d\n", 716 rc); 717 goto failed_detect; 718 } 719 } 720 } 721 722 /* Enable CABC */ 723 rc = wled->wled_cabc_config(wled, true); 724 if (rc < 0) 725 goto failed_detect; 726 727 /* Restore the feedback setting */ 728 rc = regmap_write(wled->regmap, 729 wled->ctrl_addr + WLED3_CTRL_REG_FEEDBACK_CONTROL, 0); 730 if (rc < 0) { 731 dev_err(wled->dev, "Failed to restore feedback setting rc=%d\n", 732 rc); 733 goto failed_detect; 734 } 735 736 /* Restore brightness */ 737 rc = wled4_set_brightness(wled, wled->brightness); 738 if (rc < 0) { 739 dev_err(wled->dev, "Failed to set brightness after auto detection rc=%d\n", 740 rc); 741 goto failed_detect; 742 } 743 744 rc = regmap_update_bits(wled->regmap, 745 wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, 746 WLED3_CTRL_REG_MOD_EN_MASK, 747 WLED3_CTRL_REG_MOD_EN_MASK); 748 if (rc < 0) { 749 dev_err(wled->dev, "Failed to enable WLED module rc=%d\n", rc); 750 goto failed_detect; 751 } 752 753 failed_detect: 754 return; 755 } 756 757 #define WLED_AUTO_DETECT_OVP_COUNT 5 758 #define WLED_AUTO_DETECT_CNT_DLY_US USEC_PER_SEC 759 760 static bool wled4_auto_detection_required(struct wled *wled) 761 { 762 s64 elapsed_time_us; 763 764 if (!wled->cfg.auto_detection_enabled) 765 return false; 766 767 /* 768 * Check if the OVP fault was an occasional one 769 * or if it's firing continuously, the latter qualifies 770 * for an auto-detection check. 771 */ 772 if (!wled->auto_detection_ovp_count) { 773 wled->start_ovp_fault_time = ktime_get(); 774 wled->auto_detection_ovp_count++; 775 } else { 776 elapsed_time_us = ktime_us_delta(ktime_get(), 777 wled->start_ovp_fault_time); 778 if (elapsed_time_us > WLED_AUTO_DETECT_CNT_DLY_US) 779 wled->auto_detection_ovp_count = 0; 780 else 781 wled->auto_detection_ovp_count++; 782 783 if (wled->auto_detection_ovp_count >= 784 WLED_AUTO_DETECT_OVP_COUNT) { 785 wled->auto_detection_ovp_count = 0; 786 return true; 787 } 788 } 789 790 return false; 791 } 792 793 static bool wled5_auto_detection_required(struct wled *wled) 794 { 795 if (!wled->cfg.auto_detection_enabled) 796 return false; 797 798 /* 799 * Unlike WLED4, WLED5 has OVP fault density interrupt configuration 800 * i.e. to count the number of OVP alarms for a certain duration before 801 * triggering OVP fault interrupt. By default, number of OVP fault 802 * events counted before an interrupt is fired is 32 and the time 803 * interval is 12 ms. If we see one OVP fault interrupt, then that 804 * should qualify for a real OVP fault condition to run auto detection 805 * algorithm. 806 */ 807 return true; 808 } 809 810 static int wled_auto_detection_at_init(struct wled *wled) 811 { 812 int rc; 813 bool fault_set; 814 815 if (!wled->cfg.auto_detection_enabled) 816 return 0; 817 818 rc = wled_ovp_fault_status(wled, &fault_set); 819 if (rc < 0) { 820 dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n", 821 rc); 822 return rc; 823 } 824 825 if (fault_set) { 826 mutex_lock(&wled->lock); 827 wled_auto_string_detection(wled); 828 mutex_unlock(&wled->lock); 829 } 830 831 return rc; 832 } 833 834 static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) 835 { 836 struct wled *wled = _wled; 837 int rc; 838 u32 int_sts, fault_sts; 839 840 rc = regmap_read(wled->regmap, 841 wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, &int_sts); 842 if (rc < 0) { 843 dev_err(wled->dev, "Error in reading WLED3_INT_RT_STS rc=%d\n", 844 rc); 845 return IRQ_HANDLED; 846 } 847 848 rc = regmap_read(wled->regmap, wled->ctrl_addr + 849 WLED3_CTRL_REG_FAULT_STATUS, &fault_sts); 850 if (rc < 0) { 851 dev_err(wled->dev, "Error in reading WLED_FAULT_STATUS rc=%d\n", 852 rc); 853 return IRQ_HANDLED; 854 } 855 856 if (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT | 857 WLED3_CTRL_REG_ILIM_FAULT_BIT)) 858 dev_dbg(wled->dev, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n", 859 int_sts, fault_sts); 860 861 if (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT) { 862 if (wled->wled_auto_detection_required(wled)) { 863 mutex_lock(&wled->lock); 864 wled_auto_string_detection(wled); 865 mutex_unlock(&wled->lock); 866 } 867 } 868 869 return IRQ_HANDLED; 870 } 871 872 static int wled3_setup(struct wled *wled) 873 { 874 u16 addr; 875 u8 sink_en = 0; 876 int rc, i, j; 877 878 rc = regmap_update_bits(wled->regmap, 879 wled->ctrl_addr + WLED3_CTRL_REG_OVP, 880 WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp); 881 if (rc) 882 return rc; 883 884 rc = regmap_update_bits(wled->regmap, 885 wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, 886 WLED3_CTRL_REG_ILIMIT_MASK, 887 wled->cfg.boost_i_limit); 888 if (rc) 889 return rc; 890 891 rc = regmap_update_bits(wled->regmap, 892 wled->ctrl_addr + WLED3_CTRL_REG_FREQ, 893 WLED3_CTRL_REG_FREQ_MASK, 894 wled->cfg.switch_freq); 895 if (rc) 896 return rc; 897 898 for (i = 0; i < wled->cfg.num_strings; ++i) { 899 j = wled->cfg.enabled_strings[i]; 900 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_EN(j); 901 rc = regmap_update_bits(wled->regmap, addr, 902 WLED3_SINK_REG_STR_MOD_MASK, 903 WLED3_SINK_REG_STR_MOD_MASK); 904 if (rc) 905 return rc; 906 907 if (wled->cfg.ext_gen) { 908 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_SRC(j); 909 rc = regmap_update_bits(wled->regmap, addr, 910 WLED3_SINK_REG_STR_MOD_SRC_MASK, 911 WLED3_SINK_REG_STR_MOD_SRC_EXT); 912 if (rc) 913 return rc; 914 } 915 916 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_FULL_SCALE_CURR(j); 917 rc = regmap_update_bits(wled->regmap, addr, 918 WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK, 919 wled->cfg.string_i_limit); 920 if (rc) 921 return rc; 922 923 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_CABC(j); 924 rc = regmap_update_bits(wled->regmap, addr, 925 WLED3_SINK_REG_STR_CABC_MASK, 926 wled->cfg.cabc ? 927 WLED3_SINK_REG_STR_CABC_MASK : 0); 928 if (rc) 929 return rc; 930 931 sink_en |= BIT(j + WLED3_SINK_REG_CURR_SINK_SHFT); 932 } 933 934 rc = regmap_update_bits(wled->regmap, 935 wled->ctrl_addr + WLED3_SINK_REG_CURR_SINK, 936 WLED3_SINK_REG_CURR_SINK_MASK, sink_en); 937 if (rc) 938 return rc; 939 940 return 0; 941 } 942 943 static const struct wled_config wled3_config_defaults = { 944 .boost_i_limit = 3, 945 .string_i_limit = 20, 946 .ovp = 2, 947 .num_strings = 3, 948 .switch_freq = 5, 949 .cs_out_en = false, 950 .ext_gen = false, 951 .cabc = false, 952 .enabled_strings = {0, 1, 2, 3}, 953 }; 954 955 static int wled4_setup(struct wled *wled) 956 { 957 int rc, temp, i, j; 958 u16 addr; 959 u8 sink_en = 0; 960 u32 sink_cfg; 961 962 rc = regmap_update_bits(wled->regmap, 963 wled->ctrl_addr + WLED3_CTRL_REG_OVP, 964 WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp); 965 if (rc < 0) 966 return rc; 967 968 rc = regmap_update_bits(wled->regmap, 969 wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, 970 WLED3_CTRL_REG_ILIMIT_MASK, 971 wled->cfg.boost_i_limit); 972 if (rc < 0) 973 return rc; 974 975 rc = regmap_update_bits(wled->regmap, 976 wled->ctrl_addr + WLED3_CTRL_REG_FREQ, 977 WLED3_CTRL_REG_FREQ_MASK, 978 wled->cfg.switch_freq); 979 if (rc < 0) 980 return rc; 981 982 if (wled->cfg.external_pfet) { 983 /* Unlock the secure register access */ 984 rc = regmap_write(wled->regmap, wled->ctrl_addr + 985 WLED4_CTRL_REG_SEC_ACCESS, 986 WLED4_CTRL_REG_SEC_UNLOCK); 987 if (rc < 0) 988 return rc; 989 990 rc = regmap_write(wled->regmap, 991 wled->ctrl_addr + WLED4_CTRL_REG_TEST1, 992 WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2); 993 if (rc < 0) 994 return rc; 995 } 996 997 rc = regmap_read(wled->regmap, wled->sink_addr + 998 WLED4_SINK_REG_CURR_SINK, &sink_cfg); 999 if (rc < 0) 1000 return rc; 1001 1002 for (i = 0; i < wled->cfg.num_strings; i++) { 1003 j = wled->cfg.enabled_strings[i]; 1004 temp = j + WLED4_SINK_REG_CURR_SINK_SHFT; 1005 sink_en |= 1 << temp; 1006 } 1007 1008 if (sink_cfg == sink_en) { 1009 rc = wled_auto_detection_at_init(wled); 1010 return rc; 1011 } 1012 1013 rc = regmap_update_bits(wled->regmap, 1014 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 1015 WLED4_SINK_REG_CURR_SINK_MASK, 0); 1016 if (rc < 0) 1017 return rc; 1018 1019 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 1020 WLED3_CTRL_REG_MOD_EN, 1021 WLED3_CTRL_REG_MOD_EN_MASK, 0); 1022 if (rc < 0) 1023 return rc; 1024 1025 /* Per sink/string configuration */ 1026 for (i = 0; i < wled->cfg.num_strings; i++) { 1027 j = wled->cfg.enabled_strings[i]; 1028 1029 addr = wled->sink_addr + 1030 WLED4_SINK_REG_STR_MOD_EN(j); 1031 rc = regmap_update_bits(wled->regmap, addr, 1032 WLED4_SINK_REG_STR_MOD_MASK, 1033 WLED4_SINK_REG_STR_MOD_MASK); 1034 if (rc < 0) 1035 return rc; 1036 1037 addr = wled->sink_addr + 1038 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j); 1039 rc = regmap_update_bits(wled->regmap, addr, 1040 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK, 1041 wled->cfg.string_i_limit); 1042 if (rc < 0) 1043 return rc; 1044 } 1045 1046 rc = wled4_cabc_config(wled, wled->cfg.cabc); 1047 if (rc < 0) 1048 return rc; 1049 1050 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 1051 WLED3_CTRL_REG_MOD_EN, 1052 WLED3_CTRL_REG_MOD_EN_MASK, 1053 WLED3_CTRL_REG_MOD_EN_MASK); 1054 if (rc < 0) 1055 return rc; 1056 1057 rc = regmap_update_bits(wled->regmap, 1058 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 1059 WLED4_SINK_REG_CURR_SINK_MASK, sink_en); 1060 if (rc < 0) 1061 return rc; 1062 1063 rc = wled->wled_sync_toggle(wled); 1064 if (rc < 0) { 1065 dev_err(wled->dev, "Failed to toggle sync reg rc:%d\n", rc); 1066 return rc; 1067 } 1068 1069 rc = wled_auto_detection_at_init(wled); 1070 1071 return rc; 1072 } 1073 1074 static const struct wled_config wled4_config_defaults = { 1075 .boost_i_limit = 4, 1076 .string_i_limit = 10, 1077 .ovp = 1, 1078 .num_strings = 4, 1079 .switch_freq = 11, 1080 .cabc = false, 1081 .external_pfet = false, 1082 .auto_detection_enabled = false, 1083 }; 1084 1085 static int wled5_setup(struct wled *wled) 1086 { 1087 int rc, temp, i, j, offset; 1088 u8 sink_en = 0; 1089 u16 addr; 1090 u32 val; 1091 1092 rc = regmap_update_bits(wled->regmap, 1093 wled->ctrl_addr + WLED3_CTRL_REG_OVP, 1094 WLED5_CTRL_REG_OVP_MASK, wled->cfg.ovp); 1095 if (rc < 0) 1096 return rc; 1097 1098 rc = regmap_update_bits(wled->regmap, 1099 wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, 1100 WLED3_CTRL_REG_ILIMIT_MASK, 1101 wled->cfg.boost_i_limit); 1102 if (rc < 0) 1103 return rc; 1104 1105 rc = regmap_update_bits(wled->regmap, 1106 wled->ctrl_addr + WLED3_CTRL_REG_FREQ, 1107 WLED3_CTRL_REG_FREQ_MASK, 1108 wled->cfg.switch_freq); 1109 if (rc < 0) 1110 return rc; 1111 1112 /* Per sink/string configuration */ 1113 for (i = 0; i < wled->cfg.num_strings; ++i) { 1114 j = wled->cfg.enabled_strings[i]; 1115 addr = wled->sink_addr + 1116 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j); 1117 rc = regmap_update_bits(wled->regmap, addr, 1118 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK, 1119 wled->cfg.string_i_limit); 1120 if (rc < 0) 1121 return rc; 1122 1123 addr = wled->sink_addr + WLED5_SINK_REG_STR_SRC_SEL(j); 1124 rc = regmap_update_bits(wled->regmap, addr, 1125 WLED5_SINK_REG_SRC_SEL_MASK, 1126 wled->cfg.mod_sel == MOD_A ? 1127 WLED5_SINK_REG_SRC_SEL_MOD_A : 1128 WLED5_SINK_REG_SRC_SEL_MOD_B); 1129 1130 temp = j + WLED4_SINK_REG_CURR_SINK_SHFT; 1131 sink_en |= 1 << temp; 1132 } 1133 1134 rc = wled5_cabc_config(wled, wled->cfg.cabc_sel ? true : false); 1135 if (rc < 0) 1136 return rc; 1137 1138 /* Enable one of the modulators A or B based on mod_sel */ 1139 addr = wled->sink_addr + WLED5_SINK_REG_MOD_A_EN; 1140 val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_EN_MASK : 0; 1141 rc = regmap_update_bits(wled->regmap, addr, 1142 WLED5_SINK_REG_MOD_EN_MASK, val); 1143 if (rc < 0) 1144 return rc; 1145 1146 addr = wled->sink_addr + WLED5_SINK_REG_MOD_B_EN; 1147 val = (wled->cfg.mod_sel == MOD_B) ? WLED5_SINK_REG_MOD_EN_MASK : 0; 1148 rc = regmap_update_bits(wled->regmap, addr, 1149 WLED5_SINK_REG_MOD_EN_MASK, val); 1150 if (rc < 0) 1151 return rc; 1152 1153 offset = (wled->cfg.mod_sel == MOD_A) ? 1154 WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL : 1155 WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL; 1156 1157 addr = wled->sink_addr + offset; 1158 val = (wled->max_brightness == WLED5_SINK_REG_BRIGHT_MAX_15B) ? 1159 WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B : 1160 WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B; 1161 rc = regmap_write(wled->regmap, addr, val); 1162 if (rc < 0) 1163 return rc; 1164 1165 rc = regmap_update_bits(wled->regmap, 1166 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 1167 WLED4_SINK_REG_CURR_SINK_MASK, sink_en); 1168 if (rc < 0) 1169 return rc; 1170 1171 /* This updates only FSC configuration in WLED5 */ 1172 rc = wled->wled_sync_toggle(wled); 1173 if (rc < 0) { 1174 pr_err("Failed to toggle sync reg rc:%d\n", rc); 1175 return rc; 1176 } 1177 1178 rc = wled_auto_detection_at_init(wled); 1179 if (rc < 0) 1180 return rc; 1181 1182 return 0; 1183 } 1184 1185 static const struct wled_config wled5_config_defaults = { 1186 .boost_i_limit = 5, 1187 .string_i_limit = 10, 1188 .ovp = 4, 1189 .num_strings = 4, 1190 .switch_freq = 11, 1191 .mod_sel = 0, 1192 .cabc_sel = 0, 1193 .cabc = false, 1194 .external_pfet = false, 1195 .auto_detection_enabled = false, 1196 }; 1197 1198 static const u32 wled3_boost_i_limit_values[] = { 1199 105, 385, 525, 805, 980, 1260, 1400, 1680, 1200 }; 1201 1202 static const struct wled_var_cfg wled3_boost_i_limit_cfg = { 1203 .values = wled3_boost_i_limit_values, 1204 .size = ARRAY_SIZE(wled3_boost_i_limit_values), 1205 }; 1206 1207 static const u32 wled4_boost_i_limit_values[] = { 1208 105, 280, 450, 620, 970, 1150, 1300, 1500, 1209 }; 1210 1211 static const struct wled_var_cfg wled4_boost_i_limit_cfg = { 1212 .values = wled4_boost_i_limit_values, 1213 .size = ARRAY_SIZE(wled4_boost_i_limit_values), 1214 }; 1215 1216 static inline u32 wled5_boost_i_limit_values_fn(u32 idx) 1217 { 1218 return 525 + (idx * 175); 1219 } 1220 1221 static const struct wled_var_cfg wled5_boost_i_limit_cfg = { 1222 .fn = wled5_boost_i_limit_values_fn, 1223 .size = 8, 1224 }; 1225 1226 static const u32 wled3_ovp_values[] = { 1227 35, 32, 29, 27, 1228 }; 1229 1230 static const struct wled_var_cfg wled3_ovp_cfg = { 1231 .values = wled3_ovp_values, 1232 .size = ARRAY_SIZE(wled3_ovp_values), 1233 }; 1234 1235 static const u32 wled4_ovp_values[] = { 1236 31100, 29600, 19600, 18100, 1237 }; 1238 1239 static const struct wled_var_cfg wled4_ovp_cfg = { 1240 .values = wled4_ovp_values, 1241 .size = ARRAY_SIZE(wled4_ovp_values), 1242 }; 1243 1244 static inline u32 wled5_ovp_values_fn(u32 idx) 1245 { 1246 /* 1247 * 0000 - 38.5 V 1248 * 0001 - 37 V .. 1249 * 1111 - 16 V 1250 */ 1251 return 38500 - (idx * 1500); 1252 } 1253 1254 static const struct wled_var_cfg wled5_ovp_cfg = { 1255 .fn = wled5_ovp_values_fn, 1256 .size = 16, 1257 }; 1258 1259 static u32 wled3_num_strings_values_fn(u32 idx) 1260 { 1261 return idx + 1; 1262 } 1263 1264 static const struct wled_var_cfg wled3_num_strings_cfg = { 1265 .fn = wled3_num_strings_values_fn, 1266 .size = 3, 1267 }; 1268 1269 static const struct wled_var_cfg wled4_num_strings_cfg = { 1270 .fn = wled3_num_strings_values_fn, 1271 .size = 4, 1272 }; 1273 1274 static u32 wled3_switch_freq_values_fn(u32 idx) 1275 { 1276 return 19200 / (2 * (1 + idx)); 1277 } 1278 1279 static const struct wled_var_cfg wled3_switch_freq_cfg = { 1280 .fn = wled3_switch_freq_values_fn, 1281 .size = 16, 1282 }; 1283 1284 static const struct wled_var_cfg wled3_string_i_limit_cfg = { 1285 .size = 26, 1286 }; 1287 1288 static const u32 wled4_string_i_limit_values[] = { 1289 0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000, 1290 22500, 25000, 27500, 30000, 1291 }; 1292 1293 static const struct wled_var_cfg wled4_string_i_limit_cfg = { 1294 .values = wled4_string_i_limit_values, 1295 .size = ARRAY_SIZE(wled4_string_i_limit_values), 1296 }; 1297 1298 static const struct wled_var_cfg wled5_mod_sel_cfg = { 1299 .size = 2, 1300 }; 1301 1302 static const struct wled_var_cfg wled5_cabc_sel_cfg = { 1303 .size = 4, 1304 }; 1305 1306 static u32 wled_values(const struct wled_var_cfg *cfg, u32 idx) 1307 { 1308 if (idx >= cfg->size) 1309 return UINT_MAX; 1310 if (cfg->fn) 1311 return cfg->fn(idx); 1312 if (cfg->values) 1313 return cfg->values[idx]; 1314 return idx; 1315 } 1316 1317 static int wled_configure(struct wled *wled) 1318 { 1319 struct wled_config *cfg = &wled->cfg; 1320 struct device *dev = wled->dev; 1321 const __be32 *prop_addr; 1322 u32 size, val, c; 1323 int rc, i, j, string_len; 1324 1325 const struct wled_u32_opts *u32_opts = NULL; 1326 const struct wled_u32_opts wled3_opts[] = { 1327 { 1328 .name = "qcom,current-boost-limit", 1329 .val_ptr = &cfg->boost_i_limit, 1330 .cfg = &wled3_boost_i_limit_cfg, 1331 }, 1332 { 1333 .name = "qcom,current-limit", 1334 .val_ptr = &cfg->string_i_limit, 1335 .cfg = &wled3_string_i_limit_cfg, 1336 }, 1337 { 1338 .name = "qcom,ovp", 1339 .val_ptr = &cfg->ovp, 1340 .cfg = &wled3_ovp_cfg, 1341 }, 1342 { 1343 .name = "qcom,switching-freq", 1344 .val_ptr = &cfg->switch_freq, 1345 .cfg = &wled3_switch_freq_cfg, 1346 }, 1347 { 1348 .name = "qcom,num-strings", 1349 .val_ptr = &cfg->num_strings, 1350 .cfg = &wled3_num_strings_cfg, 1351 }, 1352 }; 1353 1354 const struct wled_u32_opts wled4_opts[] = { 1355 { 1356 .name = "qcom,current-boost-limit", 1357 .val_ptr = &cfg->boost_i_limit, 1358 .cfg = &wled4_boost_i_limit_cfg, 1359 }, 1360 { 1361 .name = "qcom,current-limit-microamp", 1362 .val_ptr = &cfg->string_i_limit, 1363 .cfg = &wled4_string_i_limit_cfg, 1364 }, 1365 { 1366 .name = "qcom,ovp-millivolt", 1367 .val_ptr = &cfg->ovp, 1368 .cfg = &wled4_ovp_cfg, 1369 }, 1370 { 1371 .name = "qcom,switching-freq", 1372 .val_ptr = &cfg->switch_freq, 1373 .cfg = &wled3_switch_freq_cfg, 1374 }, 1375 { 1376 .name = "qcom,num-strings", 1377 .val_ptr = &cfg->num_strings, 1378 .cfg = &wled4_num_strings_cfg, 1379 }, 1380 }; 1381 1382 const struct wled_u32_opts wled5_opts[] = { 1383 { 1384 .name = "qcom,current-boost-limit", 1385 .val_ptr = &cfg->boost_i_limit, 1386 .cfg = &wled5_boost_i_limit_cfg, 1387 }, 1388 { 1389 .name = "qcom,current-limit-microamp", 1390 .val_ptr = &cfg->string_i_limit, 1391 .cfg = &wled4_string_i_limit_cfg, 1392 }, 1393 { 1394 .name = "qcom,ovp-millivolt", 1395 .val_ptr = &cfg->ovp, 1396 .cfg = &wled5_ovp_cfg, 1397 }, 1398 { 1399 .name = "qcom,switching-freq", 1400 .val_ptr = &cfg->switch_freq, 1401 .cfg = &wled3_switch_freq_cfg, 1402 }, 1403 { 1404 .name = "qcom,num-strings", 1405 .val_ptr = &cfg->num_strings, 1406 .cfg = &wled4_num_strings_cfg, 1407 }, 1408 { 1409 .name = "qcom,modulator-sel", 1410 .val_ptr = &cfg->mod_sel, 1411 .cfg = &wled5_mod_sel_cfg, 1412 }, 1413 { 1414 .name = "qcom,cabc-sel", 1415 .val_ptr = &cfg->cabc_sel, 1416 .cfg = &wled5_cabc_sel_cfg, 1417 }, 1418 }; 1419 1420 const struct wled_bool_opts bool_opts[] = { 1421 { "qcom,cs-out", &cfg->cs_out_en, }, 1422 { "qcom,ext-gen", &cfg->ext_gen, }, 1423 { "qcom,cabc", &cfg->cabc, }, 1424 { "qcom,external-pfet", &cfg->external_pfet, }, 1425 { "qcom,auto-string-detection", &cfg->auto_detection_enabled, }, 1426 }; 1427 1428 prop_addr = of_get_address(dev->of_node, 0, NULL, NULL); 1429 if (!prop_addr) { 1430 dev_err(wled->dev, "invalid IO resources\n"); 1431 return -EINVAL; 1432 } 1433 wled->ctrl_addr = be32_to_cpu(*prop_addr); 1434 1435 rc = of_property_read_string(dev->of_node, "label", &wled->name); 1436 if (rc) 1437 wled->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node); 1438 1439 switch (wled->version) { 1440 case 3: 1441 u32_opts = wled3_opts; 1442 size = ARRAY_SIZE(wled3_opts); 1443 *cfg = wled3_config_defaults; 1444 wled->wled_set_brightness = wled3_set_brightness; 1445 wled->wled_sync_toggle = wled3_sync_toggle; 1446 wled->max_string_count = 3; 1447 wled->sink_addr = wled->ctrl_addr; 1448 break; 1449 1450 case 4: 1451 u32_opts = wled4_opts; 1452 size = ARRAY_SIZE(wled4_opts); 1453 *cfg = wled4_config_defaults; 1454 wled->wled_set_brightness = wled4_set_brightness; 1455 wled->wled_sync_toggle = wled3_sync_toggle; 1456 wled->wled_cabc_config = wled4_cabc_config; 1457 wled->wled_ovp_delay = wled4_ovp_delay; 1458 wled->wled_auto_detection_required = 1459 wled4_auto_detection_required; 1460 wled->max_string_count = 4; 1461 1462 prop_addr = of_get_address(dev->of_node, 1, NULL, NULL); 1463 if (!prop_addr) { 1464 dev_err(wled->dev, "invalid IO resources\n"); 1465 return -EINVAL; 1466 } 1467 wled->sink_addr = be32_to_cpu(*prop_addr); 1468 break; 1469 1470 case 5: 1471 u32_opts = wled5_opts; 1472 size = ARRAY_SIZE(wled5_opts); 1473 *cfg = wled5_config_defaults; 1474 wled->wled_set_brightness = wled5_set_brightness; 1475 wled->wled_sync_toggle = wled3_sync_toggle; 1476 wled->wled_cabc_config = wled5_cabc_config; 1477 wled->wled_ovp_delay = wled5_ovp_delay; 1478 wled->wled_auto_detection_required = 1479 wled5_auto_detection_required; 1480 wled->max_string_count = 4; 1481 1482 prop_addr = of_get_address(dev->of_node, 1, NULL, NULL); 1483 if (!prop_addr) { 1484 dev_err(wled->dev, "invalid IO resources\n"); 1485 return -EINVAL; 1486 } 1487 wled->sink_addr = be32_to_cpu(*prop_addr); 1488 break; 1489 1490 default: 1491 dev_err(wled->dev, "Invalid WLED version\n"); 1492 return -EINVAL; 1493 } 1494 1495 for (i = 0; i < size; ++i) { 1496 rc = of_property_read_u32(dev->of_node, u32_opts[i].name, &val); 1497 if (rc == -EINVAL) { 1498 continue; 1499 } else if (rc) { 1500 dev_err(dev, "error reading '%s'\n", u32_opts[i].name); 1501 return rc; 1502 } 1503 1504 c = UINT_MAX; 1505 for (j = 0; c != val; j++) { 1506 c = wled_values(u32_opts[i].cfg, j); 1507 if (c == UINT_MAX) { 1508 dev_err(dev, "invalid value for '%s'\n", 1509 u32_opts[i].name); 1510 return -EINVAL; 1511 } 1512 1513 if (c == val) 1514 break; 1515 } 1516 1517 dev_dbg(dev, "'%s' = %u\n", u32_opts[i].name, c); 1518 *u32_opts[i].val_ptr = j; 1519 } 1520 1521 for (i = 0; i < ARRAY_SIZE(bool_opts); ++i) { 1522 if (of_property_read_bool(dev->of_node, bool_opts[i].name)) 1523 *bool_opts[i].val_ptr = true; 1524 } 1525 1526 cfg->num_strings = cfg->num_strings + 1; 1527 1528 string_len = of_property_count_elems_of_size(dev->of_node, 1529 "qcom,enabled-strings", 1530 sizeof(u32)); 1531 if (string_len > 0) 1532 of_property_read_u32_array(dev->of_node, 1533 "qcom,enabled-strings", 1534 wled->cfg.enabled_strings, 1535 sizeof(u32)); 1536 1537 return 0; 1538 } 1539 1540 static int wled_configure_short_irq(struct wled *wled, 1541 struct platform_device *pdev) 1542 { 1543 int rc; 1544 1545 if (!wled->has_short_detect) 1546 return 0; 1547 1548 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 1549 WLED4_CTRL_REG_SHORT_PROTECT, 1550 WLED4_CTRL_REG_SHORT_EN_MASK, 1551 WLED4_CTRL_REG_SHORT_EN_MASK); 1552 if (rc < 0) 1553 return rc; 1554 1555 wled->short_irq = platform_get_irq_byname(pdev, "short"); 1556 if (wled->short_irq < 0) { 1557 dev_dbg(&pdev->dev, "short irq is not used\n"); 1558 return 0; 1559 } 1560 1561 rc = devm_request_threaded_irq(wled->dev, wled->short_irq, 1562 NULL, wled_short_irq_handler, 1563 IRQF_ONESHOT, 1564 "wled_short_irq", wled); 1565 if (rc < 0) 1566 dev_err(wled->dev, "Unable to request short_irq (err:%d)\n", 1567 rc); 1568 1569 return rc; 1570 } 1571 1572 static int wled_configure_ovp_irq(struct wled *wled, 1573 struct platform_device *pdev) 1574 { 1575 int rc; 1576 u32 val; 1577 1578 wled->ovp_irq = platform_get_irq_byname(pdev, "ovp"); 1579 if (wled->ovp_irq < 0) { 1580 dev_dbg(&pdev->dev, "OVP IRQ not found - disabling automatic string detection\n"); 1581 return 0; 1582 } 1583 1584 rc = devm_request_threaded_irq(wled->dev, wled->ovp_irq, NULL, 1585 wled_ovp_irq_handler, IRQF_ONESHOT, 1586 "wled_ovp_irq", wled); 1587 if (rc < 0) { 1588 dev_err(wled->dev, "Unable to request ovp_irq (err:%d)\n", 1589 rc); 1590 wled->ovp_irq = 0; 1591 return 0; 1592 } 1593 1594 rc = regmap_read(wled->regmap, wled->ctrl_addr + 1595 WLED3_CTRL_REG_MOD_EN, &val); 1596 if (rc < 0) 1597 return rc; 1598 1599 /* Keep OVP irq disabled until module is enabled */ 1600 if (!(val & WLED3_CTRL_REG_MOD_EN_MASK)) 1601 disable_irq(wled->ovp_irq); 1602 1603 return 0; 1604 } 1605 1606 static const struct backlight_ops wled_ops = { 1607 .update_status = wled_update_status, 1608 }; 1609 1610 static int wled_probe(struct platform_device *pdev) 1611 { 1612 struct backlight_properties props; 1613 struct backlight_device *bl; 1614 struct wled *wled; 1615 struct regmap *regmap; 1616 u32 val; 1617 int rc; 1618 1619 regmap = dev_get_regmap(pdev->dev.parent, NULL); 1620 if (!regmap) { 1621 dev_err(&pdev->dev, "Unable to get regmap\n"); 1622 return -EINVAL; 1623 } 1624 1625 wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL); 1626 if (!wled) 1627 return -ENOMEM; 1628 1629 wled->regmap = regmap; 1630 wled->dev = &pdev->dev; 1631 1632 wled->version = (uintptr_t)of_device_get_match_data(&pdev->dev); 1633 if (!wled->version) { 1634 dev_err(&pdev->dev, "Unknown device version\n"); 1635 return -ENODEV; 1636 } 1637 1638 mutex_init(&wled->lock); 1639 rc = wled_configure(wled); 1640 if (rc) 1641 return rc; 1642 1643 val = WLED3_SINK_REG_BRIGHT_MAX; 1644 of_property_read_u32(pdev->dev.of_node, "max-brightness", &val); 1645 wled->max_brightness = val; 1646 1647 switch (wled->version) { 1648 case 3: 1649 wled->cfg.auto_detection_enabled = false; 1650 rc = wled3_setup(wled); 1651 if (rc) { 1652 dev_err(&pdev->dev, "wled3_setup failed\n"); 1653 return rc; 1654 } 1655 break; 1656 1657 case 4: 1658 wled->has_short_detect = true; 1659 rc = wled4_setup(wled); 1660 if (rc) { 1661 dev_err(&pdev->dev, "wled4_setup failed\n"); 1662 return rc; 1663 } 1664 break; 1665 1666 case 5: 1667 wled->has_short_detect = true; 1668 if (wled->cfg.cabc_sel) 1669 wled->max_brightness = WLED5_SINK_REG_BRIGHT_MAX_12B; 1670 1671 rc = wled5_setup(wled); 1672 if (rc) { 1673 dev_err(&pdev->dev, "wled5_setup failed\n"); 1674 return rc; 1675 } 1676 break; 1677 1678 default: 1679 dev_err(wled->dev, "Invalid WLED version\n"); 1680 break; 1681 } 1682 1683 INIT_DELAYED_WORK(&wled->ovp_work, wled_ovp_work); 1684 1685 rc = wled_configure_short_irq(wled, pdev); 1686 if (rc < 0) 1687 return rc; 1688 1689 rc = wled_configure_ovp_irq(wled, pdev); 1690 if (rc < 0) 1691 return rc; 1692 1693 val = WLED_DEFAULT_BRIGHTNESS; 1694 of_property_read_u32(pdev->dev.of_node, "default-brightness", &val); 1695 1696 memset(&props, 0, sizeof(struct backlight_properties)); 1697 props.type = BACKLIGHT_RAW; 1698 props.brightness = val; 1699 props.max_brightness = wled->max_brightness; 1700 bl = devm_backlight_device_register(&pdev->dev, wled->name, 1701 &pdev->dev, wled, 1702 &wled_ops, &props); 1703 return PTR_ERR_OR_ZERO(bl); 1704 }; 1705 1706 static int wled_remove(struct platform_device *pdev) 1707 { 1708 struct wled *wled = platform_get_drvdata(pdev); 1709 1710 mutex_destroy(&wled->lock); 1711 cancel_delayed_work_sync(&wled->ovp_work); 1712 disable_irq(wled->short_irq); 1713 disable_irq(wled->ovp_irq); 1714 1715 return 0; 1716 } 1717 1718 static const struct of_device_id wled_match_table[] = { 1719 { .compatible = "qcom,pm8941-wled", .data = (void *)3 }, 1720 { .compatible = "qcom,pmi8994-wled", .data = (void *)4 }, 1721 { .compatible = "qcom,pmi8998-wled", .data = (void *)4 }, 1722 { .compatible = "qcom,pm660l-wled", .data = (void *)4 }, 1723 { .compatible = "qcom,pm8150l-wled", .data = (void *)5 }, 1724 {} 1725 }; 1726 MODULE_DEVICE_TABLE(of, wled_match_table); 1727 1728 static struct platform_driver wled_driver = { 1729 .probe = wled_probe, 1730 .remove = wled_remove, 1731 .driver = { 1732 .name = "qcom,wled", 1733 .of_match_table = wled_match_table, 1734 }, 1735 }; 1736 1737 module_platform_driver(wled_driver); 1738 1739 MODULE_DESCRIPTION("Qualcomm WLED driver"); 1740 MODULE_LICENSE("GPL v2"); 1741