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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.12 539 lines 14 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Silergy SY7802 flash LED driver with an I2C interface 4 * 5 * Copyright 2024 André Apitzsch <git@apitzsch.eu> 6 */ 7 8#include <linux/gpio/consumer.h> 9#include <linux/i2c.h> 10#include <linux/kernel.h> 11#include <linux/led-class-flash.h> 12#include <linux/module.h> 13#include <linux/mutex.h> 14#include <linux/regmap.h> 15#include <linux/regulator/consumer.h> 16 17#define SY7802_MAX_LEDS 2 18#define SY7802_LED_JOINT 2 19 20#define SY7802_REG_ENABLE 0x10 21#define SY7802_REG_TORCH_BRIGHTNESS 0xa0 22#define SY7802_REG_FLASH_BRIGHTNESS 0xb0 23#define SY7802_REG_FLASH_DURATION 0xc0 24#define SY7802_REG_FLAGS 0xd0 25#define SY7802_REG_CONFIG_1 0xe0 26#define SY7802_REG_CONFIG_2 0xf0 27#define SY7802_REG_VIN_MONITOR 0x80 28#define SY7802_REG_LAST_FLASH 0x81 29#define SY7802_REG_VLED_MONITOR 0x30 30#define SY7802_REG_ADC_DELAY 0x31 31#define SY7802_REG_DEV_ID 0xff 32 33#define SY7802_MODE_OFF 0 34#define SY7802_MODE_TORCH 2 35#define SY7802_MODE_FLASH 3 36#define SY7802_MODE_MASK GENMASK(1, 0) 37 38#define SY7802_LEDS_SHIFT 3 39#define SY7802_LEDS_MASK(_id) (BIT(_id) << SY7802_LEDS_SHIFT) 40#define SY7802_LEDS_MASK_ALL (SY7802_LEDS_MASK(0) | SY7802_LEDS_MASK(1)) 41 42#define SY7802_TORCH_CURRENT_SHIFT 3 43#define SY7802_TORCH_CURRENT_MASK(_id) \ 44 (GENMASK(2, 0) << (SY7802_TORCH_CURRENT_SHIFT * (_id))) 45#define SY7802_TORCH_CURRENT_MASK_ALL \ 46 (SY7802_TORCH_CURRENT_MASK(0) | SY7802_TORCH_CURRENT_MASK(1)) 47 48#define SY7802_FLASH_CURRENT_SHIFT 4 49#define SY7802_FLASH_CURRENT_MASK(_id) \ 50 (GENMASK(3, 0) << (SY7802_FLASH_CURRENT_SHIFT * (_id))) 51#define SY7802_FLASH_CURRENT_MASK_ALL \ 52 (SY7802_FLASH_CURRENT_MASK(0) | SY7802_FLASH_CURRENT_MASK(1)) 53 54#define SY7802_TIMEOUT_DEFAULT_US 512000U 55#define SY7802_TIMEOUT_MIN_US 32000U 56#define SY7802_TIMEOUT_MAX_US 1024000U 57#define SY7802_TIMEOUT_STEPSIZE_US 32000U 58 59#define SY7802_TORCH_BRIGHTNESS_MAX 8 60 61#define SY7802_FLASH_BRIGHTNESS_DEFAULT 14 62#define SY7802_FLASH_BRIGHTNESS_MIN 0 63#define SY7802_FLASH_BRIGHTNESS_MAX 15 64#define SY7802_FLASH_BRIGHTNESS_STEP 1 65 66#define SY7802_FLAG_TIMEOUT BIT(0) 67#define SY7802_FLAG_THERMAL_SHUTDOWN BIT(1) 68#define SY7802_FLAG_LED_FAULT BIT(2) 69#define SY7802_FLAG_TX1_INTERRUPT BIT(3) 70#define SY7802_FLAG_TX2_INTERRUPT BIT(4) 71#define SY7802_FLAG_LED_THERMAL_FAULT BIT(5) 72#define SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW BIT(6) 73#define SY7802_FLAG_INPUT_VOLTAGE_LOW BIT(7) 74 75#define SY7802_CHIP_ID 0x51 76 77static const struct reg_default sy7802_regmap_defs[] = { 78 { SY7802_REG_ENABLE, SY7802_LEDS_MASK_ALL }, 79 { SY7802_REG_TORCH_BRIGHTNESS, 0x92 }, 80 { SY7802_REG_FLASH_BRIGHTNESS, SY7802_FLASH_BRIGHTNESS_DEFAULT | 81 SY7802_FLASH_BRIGHTNESS_DEFAULT << SY7802_FLASH_CURRENT_SHIFT }, 82 { SY7802_REG_FLASH_DURATION, 0x6f }, 83 { SY7802_REG_FLAGS, 0x0 }, 84 { SY7802_REG_CONFIG_1, 0x68 }, 85 { SY7802_REG_CONFIG_2, 0xf0 }, 86}; 87 88struct sy7802_led { 89 struct led_classdev_flash flash; 90 struct sy7802 *chip; 91 u8 led_id; 92}; 93 94struct sy7802 { 95 struct device *dev; 96 struct regmap *regmap; 97 struct mutex mutex; 98 99 struct gpio_desc *enable_gpio; 100 struct regulator *vin_regulator; 101 102 unsigned int fled_strobe_used; 103 unsigned int fled_torch_used; 104 unsigned int leds_active; 105 int num_leds; 106 struct sy7802_led leds[] __counted_by(num_leds); 107}; 108 109static int sy7802_torch_brightness_set(struct led_classdev *lcdev, enum led_brightness brightness) 110{ 111 struct sy7802_led *led = container_of(lcdev, struct sy7802_led, flash.led_cdev); 112 struct sy7802 *chip = led->chip; 113 u32 fled_torch_used_tmp; 114 u32 led_enable_mask; 115 u32 enable_mask; 116 u32 torch_mask; 117 u32 val; 118 int ret; 119 120 mutex_lock(&chip->mutex); 121 122 if (chip->fled_strobe_used) { 123 dev_warn(chip->dev, "Cannot set torch brightness whilst strobe is enabled\n"); 124 ret = -EBUSY; 125 goto unlock; 126 } 127 128 if (brightness) 129 fled_torch_used_tmp = chip->fled_torch_used | BIT(led->led_id); 130 else 131 fled_torch_used_tmp = chip->fled_torch_used & ~BIT(led->led_id); 132 133 led_enable_mask = led->led_id == SY7802_LED_JOINT ? 134 SY7802_LEDS_MASK_ALL : 135 SY7802_LEDS_MASK(led->led_id); 136 137 val = brightness ? led_enable_mask : SY7802_MODE_OFF; 138 if (fled_torch_used_tmp) 139 val |= SY7802_MODE_TORCH; 140 141 /* Disable torch to apply brightness */ 142 ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, SY7802_MODE_MASK, 143 SY7802_MODE_OFF); 144 if (ret) 145 goto unlock; 146 147 torch_mask = led->led_id == SY7802_LED_JOINT ? 148 SY7802_TORCH_CURRENT_MASK_ALL : 149 SY7802_TORCH_CURRENT_MASK(led->led_id); 150 151 /* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */ 152 if (brightness) 153 brightness -= 1; 154 155 brightness |= (brightness << SY7802_TORCH_CURRENT_SHIFT); 156 157 ret = regmap_update_bits(chip->regmap, SY7802_REG_TORCH_BRIGHTNESS, torch_mask, brightness); 158 if (ret) 159 goto unlock; 160 161 enable_mask = SY7802_MODE_MASK | led_enable_mask; 162 ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val); 163 if (ret) 164 goto unlock; 165 166 chip->fled_torch_used = fled_torch_used_tmp; 167 168unlock: 169 mutex_unlock(&chip->mutex); 170 return ret; 171} 172 173static int sy7802_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness) 174{ 175 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); 176 struct led_flash_setting *s = &fl_cdev->brightness; 177 u32 val = (brightness - s->min) / s->step; 178 struct sy7802 *chip = led->chip; 179 u32 flash_mask; 180 int ret; 181 182 val |= (val << SY7802_FLASH_CURRENT_SHIFT); 183 flash_mask = led->led_id == SY7802_LED_JOINT ? 184 SY7802_FLASH_CURRENT_MASK_ALL : 185 SY7802_FLASH_CURRENT_MASK(led->led_id); 186 187 mutex_lock(&chip->mutex); 188 ret = regmap_update_bits(chip->regmap, SY7802_REG_FLASH_BRIGHTNESS, flash_mask, val); 189 mutex_unlock(&chip->mutex); 190 191 return ret; 192} 193 194static int sy7802_strobe_set(struct led_classdev_flash *fl_cdev, bool state) 195{ 196 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); 197 struct sy7802 *chip = led->chip; 198 u32 fled_strobe_used_tmp; 199 u32 led_enable_mask; 200 u32 enable_mask; 201 u32 val; 202 int ret; 203 204 mutex_lock(&chip->mutex); 205 206 if (chip->fled_torch_used) { 207 dev_warn(chip->dev, "Cannot set strobe brightness whilst torch is enabled\n"); 208 ret = -EBUSY; 209 goto unlock; 210 } 211 212 if (state) 213 fled_strobe_used_tmp = chip->fled_strobe_used | BIT(led->led_id); 214 else 215 fled_strobe_used_tmp = chip->fled_strobe_used & ~BIT(led->led_id); 216 217 led_enable_mask = led->led_id == SY7802_LED_JOINT ? 218 SY7802_LEDS_MASK_ALL : 219 SY7802_LEDS_MASK(led->led_id); 220 221 val = state ? led_enable_mask : SY7802_MODE_OFF; 222 if (fled_strobe_used_tmp) 223 val |= SY7802_MODE_FLASH; 224 225 enable_mask = SY7802_MODE_MASK | led_enable_mask; 226 ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val); 227 228 if (ret) 229 goto unlock; 230 231 chip->fled_strobe_used = fled_strobe_used_tmp; 232 233unlock: 234 mutex_unlock(&chip->mutex); 235 return ret; 236} 237 238static int sy7802_strobe_get(struct led_classdev_flash *fl_cdev, bool *state) 239{ 240 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); 241 struct sy7802 *chip = led->chip; 242 243 mutex_lock(&chip->mutex); 244 *state = !!(chip->fled_strobe_used & BIT(led->led_id)); 245 mutex_unlock(&chip->mutex); 246 247 return 0; 248} 249 250static int sy7802_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout) 251{ 252 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); 253 struct led_flash_setting *s = &fl_cdev->timeout; 254 u32 val = (timeout - s->min) / s->step; 255 struct sy7802 *chip = led->chip; 256 257 return regmap_write(chip->regmap, SY7802_REG_FLASH_DURATION, val); 258} 259 260static int sy7802_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault) 261{ 262 struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); 263 struct sy7802 *chip = led->chip; 264 u32 val, led_faults = 0; 265 int ret; 266 267 /* NOTE: reading register clears fault status */ 268 ret = regmap_read(chip->regmap, SY7802_REG_FLAGS, &val); 269 if (ret) 270 return ret; 271 272 if (val & (SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW | SY7802_FLAG_INPUT_VOLTAGE_LOW)) 273 led_faults |= LED_FAULT_INPUT_VOLTAGE; 274 275 if (val & SY7802_FLAG_THERMAL_SHUTDOWN) 276 led_faults |= LED_FAULT_OVER_TEMPERATURE; 277 278 if (val & SY7802_FLAG_TIMEOUT) 279 led_faults |= LED_FAULT_TIMEOUT; 280 281 *fault = led_faults; 282 return 0; 283} 284 285static const struct led_flash_ops sy7802_flash_ops = { 286 .flash_brightness_set = sy7802_flash_brightness_set, 287 .strobe_set = sy7802_strobe_set, 288 .strobe_get = sy7802_strobe_get, 289 .timeout_set = sy7802_timeout_set, 290 .fault_get = sy7802_fault_get, 291}; 292 293static void sy7802_init_flash_brightness(struct led_classdev_flash *fl_cdev) 294{ 295 struct led_flash_setting *s; 296 297 /* Init flash brightness setting */ 298 s = &fl_cdev->brightness; 299 s->min = SY7802_FLASH_BRIGHTNESS_MIN; 300 s->max = SY7802_FLASH_BRIGHTNESS_MAX; 301 s->step = SY7802_FLASH_BRIGHTNESS_STEP; 302 s->val = SY7802_FLASH_BRIGHTNESS_DEFAULT; 303} 304 305static void sy7802_init_flash_timeout(struct led_classdev_flash *fl_cdev) 306{ 307 struct led_flash_setting *s; 308 309 /* Init flash timeout setting */ 310 s = &fl_cdev->timeout; 311 s->min = SY7802_TIMEOUT_MIN_US; 312 s->max = SY7802_TIMEOUT_MAX_US; 313 s->step = SY7802_TIMEOUT_STEPSIZE_US; 314 s->val = SY7802_TIMEOUT_DEFAULT_US; 315} 316 317static int sy7802_led_register(struct device *dev, struct sy7802_led *led, 318 struct device_node *np) 319{ 320 struct led_init_data init_data = {}; 321 int ret; 322 323 init_data.fwnode = of_fwnode_handle(np); 324 325 ret = devm_led_classdev_flash_register_ext(dev, &led->flash, &init_data); 326 if (ret) { 327 dev_err(dev, "Couldn't register flash %d\n", led->led_id); 328 return ret; 329 } 330 331 return 0; 332} 333 334static int sy7802_init_flash_properties(struct device *dev, struct sy7802_led *led, 335 struct device_node *np) 336{ 337 struct led_classdev_flash *flash = &led->flash; 338 struct led_classdev *lcdev = &flash->led_cdev; 339 u32 sources[SY7802_MAX_LEDS]; 340 int i, num, ret; 341 342 num = of_property_count_u32_elems(np, "led-sources"); 343 if (num < 1) { 344 dev_err(dev, "Not specified or wrong number of led-sources\n"); 345 return -EINVAL; 346 } 347 348 ret = of_property_read_u32_array(np, "led-sources", sources, num); 349 if (ret) 350 return ret; 351 352 for (i = 0; i < num; i++) { 353 if (sources[i] >= SY7802_MAX_LEDS) 354 return -EINVAL; 355 if (led->chip->leds_active & BIT(sources[i])) 356 return -EINVAL; 357 led->chip->leds_active |= BIT(sources[i]); 358 } 359 360 /* If both channels are specified in 'led-sources', joint flash output mode is used */ 361 led->led_id = num == 2 ? SY7802_LED_JOINT : sources[0]; 362 363 lcdev->max_brightness = SY7802_TORCH_BRIGHTNESS_MAX; 364 lcdev->brightness_set_blocking = sy7802_torch_brightness_set; 365 lcdev->flags |= LED_DEV_CAP_FLASH; 366 367 flash->ops = &sy7802_flash_ops; 368 369 sy7802_init_flash_brightness(flash); 370 sy7802_init_flash_timeout(flash); 371 372 return 0; 373} 374 375static int sy7802_chip_check(struct sy7802 *chip) 376{ 377 struct device *dev = chip->dev; 378 u32 chipid; 379 int ret; 380 381 ret = regmap_read(chip->regmap, SY7802_REG_DEV_ID, &chipid); 382 if (ret) 383 return dev_err_probe(dev, ret, "Failed to read chip ID\n"); 384 385 if (chipid != SY7802_CHIP_ID) 386 return dev_err_probe(dev, -ENODEV, "Unsupported chip detected: %x\n", chipid); 387 388 return 0; 389} 390 391static void sy7802_enable(struct sy7802 *chip) 392{ 393 gpiod_set_value_cansleep(chip->enable_gpio, 1); 394 usleep_range(200, 300); 395} 396 397static void sy7802_disable(struct sy7802 *chip) 398{ 399 gpiod_set_value_cansleep(chip->enable_gpio, 0); 400} 401 402static int sy7802_probe_dt(struct sy7802 *chip) 403{ 404 struct device_node *np = dev_of_node(chip->dev); 405 int child_num; 406 int ret; 407 408 regmap_write(chip->regmap, SY7802_REG_ENABLE, SY7802_MODE_OFF); 409 regmap_write(chip->regmap, SY7802_REG_TORCH_BRIGHTNESS, LED_OFF); 410 411 child_num = 0; 412 for_each_available_child_of_node_scoped(np, child) { 413 struct sy7802_led *led = chip->leds + child_num; 414 415 led->chip = chip; 416 led->led_id = child_num; 417 418 ret = sy7802_init_flash_properties(chip->dev, led, child); 419 if (ret) 420 return ret; 421 422 ret = sy7802_led_register(chip->dev, led, child); 423 if (ret) 424 return ret; 425 426 child_num++; 427 } 428 return 0; 429} 430 431static void sy7802_chip_disable_action(void *data) 432{ 433 struct sy7802 *chip = data; 434 435 sy7802_disable(chip); 436} 437 438static void sy7802_regulator_disable_action(void *data) 439{ 440 struct sy7802 *chip = data; 441 442 regulator_disable(chip->vin_regulator); 443} 444 445static const struct regmap_config sy7802_regmap_config = { 446 .reg_bits = 8, 447 .val_bits = 8, 448 .max_register = 0xff, 449 .cache_type = REGCACHE_MAPLE, 450 .reg_defaults = sy7802_regmap_defs, 451 .num_reg_defaults = ARRAY_SIZE(sy7802_regmap_defs), 452}; 453 454static int sy7802_probe(struct i2c_client *client) 455{ 456 struct device *dev = &client->dev; 457 struct sy7802 *chip; 458 size_t count; 459 int ret; 460 461 count = device_get_child_node_count(dev); 462 if (!count || count > SY7802_MAX_LEDS) 463 return dev_err_probe(dev, -EINVAL, "Invalid amount of LED nodes %zu\n", count); 464 465 chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL); 466 if (!chip) 467 return -ENOMEM; 468 469 chip->num_leds = count; 470 471 chip->dev = dev; 472 i2c_set_clientdata(client, chip); 473 474 chip->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 475 ret = PTR_ERR_OR_ZERO(chip->enable_gpio); 476 if (ret) 477 return dev_err_probe(dev, ret, "Failed to request enable gpio\n"); 478 479 chip->vin_regulator = devm_regulator_get(dev, "vin"); 480 ret = PTR_ERR_OR_ZERO(chip->vin_regulator); 481 if (ret) 482 return dev_err_probe(dev, ret, "Failed to request regulator\n"); 483 484 ret = regulator_enable(chip->vin_regulator); 485 if (ret) 486 return dev_err_probe(dev, ret, "Failed to enable regulator\n"); 487 488 ret = devm_add_action_or_reset(dev, sy7802_regulator_disable_action, chip); 489 if (ret) 490 return ret; 491 492 ret = devm_mutex_init(dev, &chip->mutex); 493 if (ret) 494 return ret; 495 496 mutex_lock(&chip->mutex); 497 498 chip->regmap = devm_regmap_init_i2c(client, &sy7802_regmap_config); 499 if (IS_ERR(chip->regmap)) { 500 ret = PTR_ERR(chip->regmap); 501 dev_err_probe(dev, ret, "Failed to allocate register map\n"); 502 goto error; 503 } 504 505 ret = sy7802_probe_dt(chip); 506 if (ret < 0) 507 goto error; 508 509 sy7802_enable(chip); 510 511 ret = devm_add_action_or_reset(dev, sy7802_chip_disable_action, chip); 512 if (ret) 513 goto error; 514 515 ret = sy7802_chip_check(chip); 516 517error: 518 mutex_unlock(&chip->mutex); 519 return ret; 520} 521 522static const struct of_device_id __maybe_unused sy7802_leds_match[] = { 523 { .compatible = "silergy,sy7802", }, 524 {} 525}; 526MODULE_DEVICE_TABLE(of, sy7802_leds_match); 527 528static struct i2c_driver sy7802_driver = { 529 .driver = { 530 .name = "sy7802", 531 .of_match_table = of_match_ptr(sy7802_leds_match), 532 }, 533 .probe = sy7802_probe, 534}; 535module_i2c_driver(sy7802_driver); 536 537MODULE_AUTHOR("André Apitzsch <git@apitzsch.eu>"); 538MODULE_DESCRIPTION("Silergy SY7802 flash LED driver"); 539MODULE_LICENSE("GPL");