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->ctrl_addr + WLED3_SINK_REG_SYNC, 340 mask, mask); 341 if (rc < 0) 342 return rc; 343 344 rc = regmap_update_bits(wled->regmap, 345 wled->ctrl_addr + WLED3_SINK_REG_SYNC, 346 mask, WLED3_SINK_REG_SYNC_CLEAR); 347 348 return rc; 349 } 350 351 static int wled5_sync_toggle(struct wled *wled) 352 { 353 int rc; 354 u8 val; 355 356 val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : 357 WLED5_SINK_REG_SYNC_MOD_B_BIT; 358 rc = regmap_update_bits(wled->regmap, 359 wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, 360 WLED5_SINK_REG_SYNC_MASK, val); 361 if (rc < 0) 362 return rc; 363 364 return regmap_update_bits(wled->regmap, 365 wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, 366 WLED5_SINK_REG_SYNC_MASK, 0); 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 = bl->props.brightness; 437 int rc = 0; 438 439 if (bl->props.power != FB_BLANK_UNBLANK || 440 bl->props.fb_blank != FB_BLANK_UNBLANK || 441 bl->props.state & BL_CORE_FBBLANK) 442 brightness = 0; 443 444 mutex_lock(&wled->lock); 445 if (brightness) { 446 rc = wled->wled_set_brightness(wled, brightness); 447 if (rc < 0) { 448 dev_err(wled->dev, "wled failed to set brightness rc:%d\n", 449 rc); 450 goto unlock_mutex; 451 } 452 453 rc = wled->wled_sync_toggle(wled); 454 if (rc < 0) { 455 dev_err(wled->dev, "wled sync failed rc:%d\n", rc); 456 goto unlock_mutex; 457 } 458 } 459 460 if (!!brightness != !!wled->brightness) { 461 rc = wled_module_enable(wled, !!brightness); 462 if (rc < 0) { 463 dev_err(wled->dev, "wled enable failed rc:%d\n", rc); 464 goto unlock_mutex; 465 } 466 } 467 468 wled->brightness = brightness; 469 470 unlock_mutex: 471 mutex_unlock(&wled->lock); 472 473 return rc; 474 } 475 476 static int wled4_cabc_config(struct wled *wled, bool enable) 477 { 478 int i, j, rc; 479 u8 val; 480 481 for (i = 0; i < wled->cfg.num_strings; i++) { 482 j = wled->cfg.enabled_strings[i]; 483 484 val = enable ? WLED4_SINK_REG_STR_CABC_MASK : 0; 485 rc = regmap_update_bits(wled->regmap, wled->sink_addr + 486 WLED4_SINK_REG_STR_CABC(j), 487 WLED4_SINK_REG_STR_CABC_MASK, val); 488 if (rc < 0) 489 return rc; 490 } 491 492 return 0; 493 } 494 495 static int wled5_cabc_config(struct wled *wled, bool enable) 496 { 497 int rc, offset; 498 u8 reg; 499 500 if (wled->cabc_disabled) 501 return 0; 502 503 reg = enable ? wled->cfg.cabc_sel : 0; 504 offset = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_A_SRC_SEL : 505 WLED5_SINK_REG_MOD_B_SRC_SEL; 506 507 rc = regmap_update_bits(wled->regmap, wled->sink_addr + offset, 508 WLED5_SINK_REG_MOD_SRC_SEL_MASK, reg); 509 if (rc < 0) { 510 pr_err("Error in configuring CABC rc=%d\n", rc); 511 return rc; 512 } 513 514 if (!wled->cfg.cabc_sel) 515 wled->cabc_disabled = true; 516 517 return 0; 518 } 519 520 #define WLED_SHORT_DLY_MS 20 521 #define WLED_SHORT_CNT_MAX 5 522 #define WLED_SHORT_RESET_CNT_DLY_US USEC_PER_SEC 523 524 static irqreturn_t wled_short_irq_handler(int irq, void *_wled) 525 { 526 struct wled *wled = _wled; 527 int rc; 528 s64 elapsed_time; 529 530 wled->short_count++; 531 mutex_lock(&wled->lock); 532 rc = wled_module_enable(wled, false); 533 if (rc < 0) { 534 dev_err(wled->dev, "wled disable failed rc:%d\n", rc); 535 goto unlock_mutex; 536 } 537 538 elapsed_time = ktime_us_delta(ktime_get(), 539 wled->last_short_event); 540 if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US) 541 wled->short_count = 1; 542 543 if (wled->short_count > WLED_SHORT_CNT_MAX) { 544 dev_err(wled->dev, "Short triggered %d times, disabling WLED forever!\n", 545 wled->short_count); 546 wled->disabled_by_short = true; 547 goto unlock_mutex; 548 } 549 550 wled->last_short_event = ktime_get(); 551 552 msleep(WLED_SHORT_DLY_MS); 553 rc = wled_module_enable(wled, true); 554 if (rc < 0) 555 dev_err(wled->dev, "wled enable failed rc:%d\n", rc); 556 557 unlock_mutex: 558 mutex_unlock(&wled->lock); 559 560 return IRQ_HANDLED; 561 } 562 563 #define AUTO_DETECT_BRIGHTNESS 200 564 565 static void wled_auto_string_detection(struct wled *wled) 566 { 567 int rc = 0, i, delay_time_us; 568 u32 sink_config = 0; 569 u8 sink_test = 0, sink_valid = 0, val; 570 bool fault_set; 571 572 /* Read configured sink configuration */ 573 rc = regmap_read(wled->regmap, wled->sink_addr + 574 WLED4_SINK_REG_CURR_SINK, &sink_config); 575 if (rc < 0) { 576 dev_err(wled->dev, "Failed to read SINK configuration rc=%d\n", 577 rc); 578 goto failed_detect; 579 } 580 581 /* Disable the module before starting detection */ 582 rc = regmap_update_bits(wled->regmap, 583 wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, 584 WLED3_CTRL_REG_MOD_EN_MASK, 0); 585 if (rc < 0) { 586 dev_err(wled->dev, "Failed to disable WLED module rc=%d\n", rc); 587 goto failed_detect; 588 } 589 590 /* Set low brightness across all sinks */ 591 rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS); 592 if (rc < 0) { 593 dev_err(wled->dev, "Failed to set brightness for auto detection rc=%d\n", 594 rc); 595 goto failed_detect; 596 } 597 598 if (wled->cfg.cabc) { 599 rc = wled->wled_cabc_config(wled, false); 600 if (rc < 0) 601 goto failed_detect; 602 } 603 604 /* Disable all sinks */ 605 rc = regmap_write(wled->regmap, 606 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0); 607 if (rc < 0) { 608 dev_err(wled->dev, "Failed to disable all sinks rc=%d\n", rc); 609 goto failed_detect; 610 } 611 612 /* Iterate through the strings one by one */ 613 for (i = 0; i < wled->cfg.num_strings; i++) { 614 sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + i)); 615 616 /* Enable feedback control */ 617 rc = regmap_write(wled->regmap, wled->ctrl_addr + 618 WLED3_CTRL_REG_FEEDBACK_CONTROL, i + 1); 619 if (rc < 0) { 620 dev_err(wled->dev, "Failed to enable feedback for SINK %d rc = %d\n", 621 i + 1, rc); 622 goto failed_detect; 623 } 624 625 /* Enable the sink */ 626 rc = regmap_write(wled->regmap, wled->sink_addr + 627 WLED4_SINK_REG_CURR_SINK, sink_test); 628 if (rc < 0) { 629 dev_err(wled->dev, "Failed to configure SINK %d rc=%d\n", 630 i + 1, rc); 631 goto failed_detect; 632 } 633 634 /* Enable the module */ 635 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 636 WLED3_CTRL_REG_MOD_EN, 637 WLED3_CTRL_REG_MOD_EN_MASK, 638 WLED3_CTRL_REG_MOD_EN_MASK); 639 if (rc < 0) { 640 dev_err(wled->dev, "Failed to enable WLED module rc=%d\n", 641 rc); 642 goto failed_detect; 643 } 644 645 delay_time_us = wled->wled_ovp_delay(wled); 646 usleep_range(delay_time_us, delay_time_us + 1000); 647 648 rc = wled_ovp_fault_status(wled, &fault_set); 649 if (rc < 0) { 650 dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n", 651 rc); 652 goto failed_detect; 653 } 654 655 if (fault_set) 656 dev_dbg(wled->dev, "WLED OVP fault detected with SINK %d\n", 657 i + 1); 658 else 659 sink_valid |= sink_test; 660 661 /* Disable the module */ 662 rc = regmap_update_bits(wled->regmap, 663 wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, 664 WLED3_CTRL_REG_MOD_EN_MASK, 0); 665 if (rc < 0) { 666 dev_err(wled->dev, "Failed to disable WLED module rc=%d\n", 667 rc); 668 goto failed_detect; 669 } 670 } 671 672 if (!sink_valid) { 673 dev_err(wled->dev, "No valid WLED sinks found\n"); 674 wled->disabled_by_short = true; 675 goto failed_detect; 676 } 677 678 if (sink_valid != sink_config) { 679 dev_warn(wled->dev, "%x is not a valid sink configuration - using %x instead\n", 680 sink_config, sink_valid); 681 sink_config = sink_valid; 682 } 683 684 /* Write the new sink configuration */ 685 rc = regmap_write(wled->regmap, 686 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 687 sink_config); 688 if (rc < 0) { 689 dev_err(wled->dev, "Failed to reconfigure the default sink rc=%d\n", 690 rc); 691 goto failed_detect; 692 } 693 694 /* Enable valid sinks */ 695 if (wled->version == 4) { 696 for (i = 0; i < wled->cfg.num_strings; i++) { 697 if (sink_config & 698 BIT(WLED4_SINK_REG_CURR_SINK_SHFT + i)) 699 val = WLED4_SINK_REG_STR_MOD_MASK; 700 else 701 /* Disable modulator_en for unused sink */ 702 val = 0; 703 704 rc = regmap_write(wled->regmap, wled->sink_addr + 705 WLED4_SINK_REG_STR_MOD_EN(i), val); 706 if (rc < 0) { 707 dev_err(wled->dev, "Failed to configure MODULATOR_EN rc=%d\n", 708 rc); 709 goto failed_detect; 710 } 711 } 712 } 713 714 /* Enable CABC */ 715 rc = wled->wled_cabc_config(wled, true); 716 if (rc < 0) 717 goto failed_detect; 718 719 /* Restore the feedback setting */ 720 rc = regmap_write(wled->regmap, 721 wled->ctrl_addr + WLED3_CTRL_REG_FEEDBACK_CONTROL, 0); 722 if (rc < 0) { 723 dev_err(wled->dev, "Failed to restore feedback setting rc=%d\n", 724 rc); 725 goto failed_detect; 726 } 727 728 /* Restore brightness */ 729 rc = wled4_set_brightness(wled, wled->brightness); 730 if (rc < 0) { 731 dev_err(wled->dev, "Failed to set brightness after auto detection rc=%d\n", 732 rc); 733 goto failed_detect; 734 } 735 736 rc = regmap_update_bits(wled->regmap, 737 wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, 738 WLED3_CTRL_REG_MOD_EN_MASK, 739 WLED3_CTRL_REG_MOD_EN_MASK); 740 if (rc < 0) { 741 dev_err(wled->dev, "Failed to enable WLED module rc=%d\n", rc); 742 goto failed_detect; 743 } 744 745 failed_detect: 746 return; 747 } 748 749 #define WLED_AUTO_DETECT_OVP_COUNT 5 750 #define WLED_AUTO_DETECT_CNT_DLY_US USEC_PER_SEC 751 752 static bool wled4_auto_detection_required(struct wled *wled) 753 { 754 s64 elapsed_time_us; 755 756 if (!wled->cfg.auto_detection_enabled) 757 return false; 758 759 /* 760 * Check if the OVP fault was an occasional one 761 * or if it's firing continuously, the latter qualifies 762 * for an auto-detection check. 763 */ 764 if (!wled->auto_detection_ovp_count) { 765 wled->start_ovp_fault_time = ktime_get(); 766 wled->auto_detection_ovp_count++; 767 } else { 768 elapsed_time_us = ktime_us_delta(ktime_get(), 769 wled->start_ovp_fault_time); 770 if (elapsed_time_us > WLED_AUTO_DETECT_CNT_DLY_US) 771 wled->auto_detection_ovp_count = 0; 772 else 773 wled->auto_detection_ovp_count++; 774 775 if (wled->auto_detection_ovp_count >= 776 WLED_AUTO_DETECT_OVP_COUNT) { 777 wled->auto_detection_ovp_count = 0; 778 return true; 779 } 780 } 781 782 return false; 783 } 784 785 static bool wled5_auto_detection_required(struct wled *wled) 786 { 787 if (!wled->cfg.auto_detection_enabled) 788 return false; 789 790 /* 791 * Unlike WLED4, WLED5 has OVP fault density interrupt configuration 792 * i.e. to count the number of OVP alarms for a certain duration before 793 * triggering OVP fault interrupt. By default, number of OVP fault 794 * events counted before an interrupt is fired is 32 and the time 795 * interval is 12 ms. If we see one OVP fault interrupt, then that 796 * should qualify for a real OVP fault condition to run auto detection 797 * algorithm. 798 */ 799 return true; 800 } 801 802 static int wled_auto_detection_at_init(struct wled *wled) 803 { 804 int rc; 805 bool fault_set; 806 807 if (!wled->cfg.auto_detection_enabled) 808 return 0; 809 810 rc = wled_ovp_fault_status(wled, &fault_set); 811 if (rc < 0) { 812 dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n", 813 rc); 814 return rc; 815 } 816 817 if (fault_set) { 818 mutex_lock(&wled->lock); 819 wled_auto_string_detection(wled); 820 mutex_unlock(&wled->lock); 821 } 822 823 return rc; 824 } 825 826 static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) 827 { 828 struct wled *wled = _wled; 829 int rc; 830 u32 int_sts, fault_sts; 831 832 rc = regmap_read(wled->regmap, 833 wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, &int_sts); 834 if (rc < 0) { 835 dev_err(wled->dev, "Error in reading WLED3_INT_RT_STS rc=%d\n", 836 rc); 837 return IRQ_HANDLED; 838 } 839 840 rc = regmap_read(wled->regmap, wled->ctrl_addr + 841 WLED3_CTRL_REG_FAULT_STATUS, &fault_sts); 842 if (rc < 0) { 843 dev_err(wled->dev, "Error in reading WLED_FAULT_STATUS rc=%d\n", 844 rc); 845 return IRQ_HANDLED; 846 } 847 848 if (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT | 849 WLED3_CTRL_REG_ILIM_FAULT_BIT)) 850 dev_dbg(wled->dev, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n", 851 int_sts, fault_sts); 852 853 if (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT) { 854 if (wled->wled_auto_detection_required(wled)) { 855 mutex_lock(&wled->lock); 856 wled_auto_string_detection(wled); 857 mutex_unlock(&wled->lock); 858 } 859 } 860 861 return IRQ_HANDLED; 862 } 863 864 static int wled3_setup(struct wled *wled) 865 { 866 u16 addr; 867 u8 sink_en = 0; 868 int rc, i, j; 869 870 rc = regmap_update_bits(wled->regmap, 871 wled->ctrl_addr + WLED3_CTRL_REG_OVP, 872 WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp); 873 if (rc) 874 return rc; 875 876 rc = regmap_update_bits(wled->regmap, 877 wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, 878 WLED3_CTRL_REG_ILIMIT_MASK, 879 wled->cfg.boost_i_limit); 880 if (rc) 881 return rc; 882 883 rc = regmap_update_bits(wled->regmap, 884 wled->ctrl_addr + WLED3_CTRL_REG_FREQ, 885 WLED3_CTRL_REG_FREQ_MASK, 886 wled->cfg.switch_freq); 887 if (rc) 888 return rc; 889 890 for (i = 0; i < wled->cfg.num_strings; ++i) { 891 j = wled->cfg.enabled_strings[i]; 892 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_EN(j); 893 rc = regmap_update_bits(wled->regmap, addr, 894 WLED3_SINK_REG_STR_MOD_MASK, 895 WLED3_SINK_REG_STR_MOD_MASK); 896 if (rc) 897 return rc; 898 899 if (wled->cfg.ext_gen) { 900 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_MOD_SRC(j); 901 rc = regmap_update_bits(wled->regmap, addr, 902 WLED3_SINK_REG_STR_MOD_SRC_MASK, 903 WLED3_SINK_REG_STR_MOD_SRC_EXT); 904 if (rc) 905 return rc; 906 } 907 908 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_FULL_SCALE_CURR(j); 909 rc = regmap_update_bits(wled->regmap, addr, 910 WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK, 911 wled->cfg.string_i_limit); 912 if (rc) 913 return rc; 914 915 addr = wled->ctrl_addr + WLED3_SINK_REG_STR_CABC(j); 916 rc = regmap_update_bits(wled->regmap, addr, 917 WLED3_SINK_REG_STR_CABC_MASK, 918 wled->cfg.cabc ? 919 WLED3_SINK_REG_STR_CABC_MASK : 0); 920 if (rc) 921 return rc; 922 923 sink_en |= BIT(j + WLED3_SINK_REG_CURR_SINK_SHFT); 924 } 925 926 rc = regmap_update_bits(wled->regmap, 927 wled->ctrl_addr + WLED3_SINK_REG_CURR_SINK, 928 WLED3_SINK_REG_CURR_SINK_MASK, sink_en); 929 if (rc) 930 return rc; 931 932 return 0; 933 } 934 935 static const struct wled_config wled3_config_defaults = { 936 .boost_i_limit = 3, 937 .string_i_limit = 20, 938 .ovp = 2, 939 .num_strings = 3, 940 .switch_freq = 5, 941 .cs_out_en = false, 942 .ext_gen = false, 943 .cabc = false, 944 .enabled_strings = {0, 1, 2, 3}, 945 }; 946 947 static int wled4_setup(struct wled *wled) 948 { 949 int rc, temp, i, j; 950 u16 addr; 951 u8 sink_en = 0; 952 u32 sink_cfg; 953 954 rc = regmap_update_bits(wled->regmap, 955 wled->ctrl_addr + WLED3_CTRL_REG_OVP, 956 WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp); 957 if (rc < 0) 958 return rc; 959 960 rc = regmap_update_bits(wled->regmap, 961 wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, 962 WLED3_CTRL_REG_ILIMIT_MASK, 963 wled->cfg.boost_i_limit); 964 if (rc < 0) 965 return rc; 966 967 rc = regmap_update_bits(wled->regmap, 968 wled->ctrl_addr + WLED3_CTRL_REG_FREQ, 969 WLED3_CTRL_REG_FREQ_MASK, 970 wled->cfg.switch_freq); 971 if (rc < 0) 972 return rc; 973 974 if (wled->cfg.external_pfet) { 975 /* Unlock the secure register access */ 976 rc = regmap_write(wled->regmap, wled->ctrl_addr + 977 WLED4_CTRL_REG_SEC_ACCESS, 978 WLED4_CTRL_REG_SEC_UNLOCK); 979 if (rc < 0) 980 return rc; 981 982 rc = regmap_write(wled->regmap, 983 wled->ctrl_addr + WLED4_CTRL_REG_TEST1, 984 WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2); 985 if (rc < 0) 986 return rc; 987 } 988 989 rc = regmap_read(wled->regmap, wled->sink_addr + 990 WLED4_SINK_REG_CURR_SINK, &sink_cfg); 991 if (rc < 0) 992 return rc; 993 994 for (i = 0; i < wled->cfg.num_strings; i++) { 995 j = wled->cfg.enabled_strings[i]; 996 temp = j + WLED4_SINK_REG_CURR_SINK_SHFT; 997 sink_en |= 1 << temp; 998 } 999 1000 if (sink_cfg == sink_en) { 1001 rc = wled_auto_detection_at_init(wled); 1002 return rc; 1003 } 1004 1005 rc = regmap_update_bits(wled->regmap, 1006 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 1007 WLED4_SINK_REG_CURR_SINK_MASK, 0); 1008 if (rc < 0) 1009 return rc; 1010 1011 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 1012 WLED3_CTRL_REG_MOD_EN, 1013 WLED3_CTRL_REG_MOD_EN_MASK, 0); 1014 if (rc < 0) 1015 return rc; 1016 1017 /* Per sink/string configuration */ 1018 for (i = 0; i < wled->cfg.num_strings; i++) { 1019 j = wled->cfg.enabled_strings[i]; 1020 1021 addr = wled->sink_addr + 1022 WLED4_SINK_REG_STR_MOD_EN(j); 1023 rc = regmap_update_bits(wled->regmap, addr, 1024 WLED4_SINK_REG_STR_MOD_MASK, 1025 WLED4_SINK_REG_STR_MOD_MASK); 1026 if (rc < 0) 1027 return rc; 1028 1029 addr = wled->sink_addr + 1030 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j); 1031 rc = regmap_update_bits(wled->regmap, addr, 1032 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK, 1033 wled->cfg.string_i_limit); 1034 if (rc < 0) 1035 return rc; 1036 } 1037 1038 rc = wled4_cabc_config(wled, wled->cfg.cabc); 1039 if (rc < 0) 1040 return rc; 1041 1042 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 1043 WLED3_CTRL_REG_MOD_EN, 1044 WLED3_CTRL_REG_MOD_EN_MASK, 1045 WLED3_CTRL_REG_MOD_EN_MASK); 1046 if (rc < 0) 1047 return rc; 1048 1049 rc = regmap_update_bits(wled->regmap, 1050 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 1051 WLED4_SINK_REG_CURR_SINK_MASK, sink_en); 1052 if (rc < 0) 1053 return rc; 1054 1055 rc = wled->wled_sync_toggle(wled); 1056 if (rc < 0) { 1057 dev_err(wled->dev, "Failed to toggle sync reg rc:%d\n", rc); 1058 return rc; 1059 } 1060 1061 rc = wled_auto_detection_at_init(wled); 1062 1063 return rc; 1064 } 1065 1066 static const struct wled_config wled4_config_defaults = { 1067 .boost_i_limit = 4, 1068 .string_i_limit = 10, 1069 .ovp = 1, 1070 .num_strings = 4, 1071 .switch_freq = 11, 1072 .cabc = false, 1073 .external_pfet = false, 1074 .auto_detection_enabled = false, 1075 }; 1076 1077 static int wled5_setup(struct wled *wled) 1078 { 1079 int rc, temp, i, j, offset; 1080 u8 sink_en = 0; 1081 u16 addr; 1082 u32 val; 1083 1084 rc = regmap_update_bits(wled->regmap, 1085 wled->ctrl_addr + WLED3_CTRL_REG_OVP, 1086 WLED5_CTRL_REG_OVP_MASK, wled->cfg.ovp); 1087 if (rc < 0) 1088 return rc; 1089 1090 rc = regmap_update_bits(wled->regmap, 1091 wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, 1092 WLED3_CTRL_REG_ILIMIT_MASK, 1093 wled->cfg.boost_i_limit); 1094 if (rc < 0) 1095 return rc; 1096 1097 rc = regmap_update_bits(wled->regmap, 1098 wled->ctrl_addr + WLED3_CTRL_REG_FREQ, 1099 WLED3_CTRL_REG_FREQ_MASK, 1100 wled->cfg.switch_freq); 1101 if (rc < 0) 1102 return rc; 1103 1104 /* Per sink/string configuration */ 1105 for (i = 0; i < wled->cfg.num_strings; ++i) { 1106 j = wled->cfg.enabled_strings[i]; 1107 addr = wled->sink_addr + 1108 WLED4_SINK_REG_STR_FULL_SCALE_CURR(j); 1109 rc = regmap_update_bits(wled->regmap, addr, 1110 WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK, 1111 wled->cfg.string_i_limit); 1112 if (rc < 0) 1113 return rc; 1114 1115 addr = wled->sink_addr + WLED5_SINK_REG_STR_SRC_SEL(j); 1116 rc = regmap_update_bits(wled->regmap, addr, 1117 WLED5_SINK_REG_SRC_SEL_MASK, 1118 wled->cfg.mod_sel == MOD_A ? 1119 WLED5_SINK_REG_SRC_SEL_MOD_A : 1120 WLED5_SINK_REG_SRC_SEL_MOD_B); 1121 1122 temp = j + WLED4_SINK_REG_CURR_SINK_SHFT; 1123 sink_en |= 1 << temp; 1124 } 1125 1126 rc = wled5_cabc_config(wled, wled->cfg.cabc_sel ? true : false); 1127 if (rc < 0) 1128 return rc; 1129 1130 /* Enable one of the modulators A or B based on mod_sel */ 1131 addr = wled->sink_addr + WLED5_SINK_REG_MOD_A_EN; 1132 val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_EN_MASK : 0; 1133 rc = regmap_update_bits(wled->regmap, addr, 1134 WLED5_SINK_REG_MOD_EN_MASK, val); 1135 if (rc < 0) 1136 return rc; 1137 1138 addr = wled->sink_addr + WLED5_SINK_REG_MOD_B_EN; 1139 val = (wled->cfg.mod_sel == MOD_B) ? WLED5_SINK_REG_MOD_EN_MASK : 0; 1140 rc = regmap_update_bits(wled->regmap, addr, 1141 WLED5_SINK_REG_MOD_EN_MASK, val); 1142 if (rc < 0) 1143 return rc; 1144 1145 offset = (wled->cfg.mod_sel == MOD_A) ? 1146 WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL : 1147 WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL; 1148 1149 addr = wled->sink_addr + offset; 1150 val = (wled->max_brightness == WLED5_SINK_REG_BRIGHT_MAX_15B) ? 1151 WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B : 1152 WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B; 1153 rc = regmap_write(wled->regmap, addr, val); 1154 if (rc < 0) 1155 return rc; 1156 1157 rc = regmap_update_bits(wled->regmap, 1158 wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 1159 WLED4_SINK_REG_CURR_SINK_MASK, sink_en); 1160 if (rc < 0) 1161 return rc; 1162 1163 /* This updates only FSC configuration in WLED5 */ 1164 rc = wled->wled_sync_toggle(wled); 1165 if (rc < 0) { 1166 pr_err("Failed to toggle sync reg rc:%d\n", rc); 1167 return rc; 1168 } 1169 1170 rc = wled_auto_detection_at_init(wled); 1171 if (rc < 0) 1172 return rc; 1173 1174 return 0; 1175 } 1176 1177 static const struct wled_config wled5_config_defaults = { 1178 .boost_i_limit = 5, 1179 .string_i_limit = 10, 1180 .ovp = 4, 1181 .num_strings = 4, 1182 .switch_freq = 11, 1183 .mod_sel = 0, 1184 .cabc_sel = 0, 1185 .cabc = false, 1186 .external_pfet = false, 1187 .auto_detection_enabled = false, 1188 }; 1189 1190 static const u32 wled3_boost_i_limit_values[] = { 1191 105, 385, 525, 805, 980, 1260, 1400, 1680, 1192 }; 1193 1194 static const struct wled_var_cfg wled3_boost_i_limit_cfg = { 1195 .values = wled3_boost_i_limit_values, 1196 .size = ARRAY_SIZE(wled3_boost_i_limit_values), 1197 }; 1198 1199 static const u32 wled4_boost_i_limit_values[] = { 1200 105, 280, 450, 620, 970, 1150, 1300, 1500, 1201 }; 1202 1203 static const struct wled_var_cfg wled4_boost_i_limit_cfg = { 1204 .values = wled4_boost_i_limit_values, 1205 .size = ARRAY_SIZE(wled4_boost_i_limit_values), 1206 }; 1207 1208 static inline u32 wled5_boost_i_limit_values_fn(u32 idx) 1209 { 1210 return 525 + (idx * 175); 1211 } 1212 1213 static const struct wled_var_cfg wled5_boost_i_limit_cfg = { 1214 .fn = wled5_boost_i_limit_values_fn, 1215 .size = 8, 1216 }; 1217 1218 static const u32 wled3_ovp_values[] = { 1219 35, 32, 29, 27, 1220 }; 1221 1222 static const struct wled_var_cfg wled3_ovp_cfg = { 1223 .values = wled3_ovp_values, 1224 .size = ARRAY_SIZE(wled3_ovp_values), 1225 }; 1226 1227 static const u32 wled4_ovp_values[] = { 1228 31100, 29600, 19600, 18100, 1229 }; 1230 1231 static const struct wled_var_cfg wled4_ovp_cfg = { 1232 .values = wled4_ovp_values, 1233 .size = ARRAY_SIZE(wled4_ovp_values), 1234 }; 1235 1236 static inline u32 wled5_ovp_values_fn(u32 idx) 1237 { 1238 /* 1239 * 0000 - 38.5 V 1240 * 0001 - 37 V .. 1241 * 1111 - 16 V 1242 */ 1243 return 38500 - (idx * 1500); 1244 } 1245 1246 static const struct wled_var_cfg wled5_ovp_cfg = { 1247 .fn = wled5_ovp_values_fn, 1248 .size = 16, 1249 }; 1250 1251 static u32 wled3_num_strings_values_fn(u32 idx) 1252 { 1253 return idx + 1; 1254 } 1255 1256 static const struct wled_var_cfg wled3_num_strings_cfg = { 1257 .fn = wled3_num_strings_values_fn, 1258 .size = 3, 1259 }; 1260 1261 static const struct wled_var_cfg wled4_num_strings_cfg = { 1262 .fn = wled3_num_strings_values_fn, 1263 .size = 4, 1264 }; 1265 1266 static u32 wled3_switch_freq_values_fn(u32 idx) 1267 { 1268 return 19200 / (2 * (1 + idx)); 1269 } 1270 1271 static const struct wled_var_cfg wled3_switch_freq_cfg = { 1272 .fn = wled3_switch_freq_values_fn, 1273 .size = 16, 1274 }; 1275 1276 static const struct wled_var_cfg wled3_string_i_limit_cfg = { 1277 .size = 26, 1278 }; 1279 1280 static const u32 wled4_string_i_limit_values[] = { 1281 0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000, 1282 22500, 25000, 27500, 30000, 1283 }; 1284 1285 static const struct wled_var_cfg wled4_string_i_limit_cfg = { 1286 .values = wled4_string_i_limit_values, 1287 .size = ARRAY_SIZE(wled4_string_i_limit_values), 1288 }; 1289 1290 static const struct wled_var_cfg wled3_string_cfg = { 1291 .size = 8, 1292 }; 1293 1294 static const struct wled_var_cfg wled4_string_cfg = { 1295 .size = 16, 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 = wled5_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 = dev_get_drvdata(&pdev->dev); 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,pmi8998-wled", .data = (void *)4 }, 1721 { .compatible = "qcom,pm660l-wled", .data = (void *)4 }, 1722 { .compatible = "qcom,pm8150l-wled", .data = (void *)5 }, 1723 {} 1724 }; 1725 MODULE_DEVICE_TABLE(of, wled_match_table); 1726 1727 static struct platform_driver wled_driver = { 1728 .probe = wled_probe, 1729 .remove = wled_remove, 1730 .driver = { 1731 .name = "qcom,wled", 1732 .of_match_table = wled_match_table, 1733 }, 1734 }; 1735 1736 module_platform_driver(wled_driver); 1737 1738 MODULE_DESCRIPTION("Qualcomm WLED driver"); 1739 MODULE_LICENSE("GPL v2"); 1740