1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * LED driver : leds-ktd2692.c 4 * 5 * Copyright (C) 2015 Samsung Electronics 6 * Ingi Kim <ingi2.kim@samsung.com> 7 */ 8 9 #include <linux/cleanup.h> 10 #include <linux/err.h> 11 #include <linux/gpio/consumer.h> 12 #include <linux/leds-expresswire.h> 13 #include <linux/led-class-flash.h> 14 #include <linux/module.h> 15 #include <linux/mutex.h> 16 #include <linux/of.h> 17 #include <linux/platform_device.h> 18 #include <linux/regulator/consumer.h> 19 20 /* Value related the movie mode */ 21 #define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16 22 #define KTD2692_MM_TO_FL_RATIO(x) ((x) / 3) 23 #define KTD2692_MM_MIN_CURR_THRESHOLD_SCALE 8 24 25 /* Value related the flash mode */ 26 #define KTD2692_FLASH_MODE_TIMEOUT_LEVELS 8 27 #define KTD2692_FLASH_MODE_TIMEOUT_DISABLE 0 28 #define KTD2692_FLASH_MODE_CURR_PERCENT(x) (((x) * 16) / 100) 29 30 /* Macro for getting offset of flash timeout */ 31 #define GET_TIMEOUT_OFFSET(timeout, step) ((timeout) / (step)) 32 33 /* Base register address */ 34 #define KTD2692_REG_LVP_BASE 0x00 35 #define KTD2692_REG_FLASH_TIMEOUT_BASE 0x20 36 #define KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE 0x40 37 #define KTD2692_REG_MOVIE_CURRENT_BASE 0x60 38 #define KTD2692_REG_FLASH_CURRENT_BASE 0x80 39 #define KTD2692_REG_MODE_BASE 0xA0 40 41 /* KTD2692 default length of name */ 42 #define KTD2692_NAME_LENGTH 20 43 44 /* Movie / Flash Mode Control */ 45 enum ktd2692_led_mode { 46 KTD2692_MODE_DISABLE = 0, /* default */ 47 KTD2692_MODE_MOVIE, 48 KTD2692_MODE_FLASH, 49 }; 50 51 struct ktd2692_led_config_data { 52 /* maximum LED current in movie mode */ 53 u32 movie_max_microamp; 54 /* maximum LED current in flash mode */ 55 u32 flash_max_microamp; 56 /* maximum flash timeout */ 57 u32 flash_max_timeout; 58 /* max LED brightness level */ 59 enum led_brightness max_brightness; 60 }; 61 62 const struct expresswire_timing ktd2692_timing = { 63 .poweroff_us = 700, 64 .data_start_us = 10, 65 .end_of_data_low_us = 10, 66 .end_of_data_high_us = 350, 67 .short_bitset_us = 4, 68 .long_bitset_us = 12 69 }; 70 71 struct ktd2692_context { 72 /* Common ExpressWire properties (ctrl GPIO and timing) */ 73 struct expresswire_common_props props; 74 75 /* Related LED Flash class device */ 76 struct led_classdev_flash fled_cdev; 77 78 /* secures access to the device */ 79 struct mutex lock; 80 struct regulator *regulator; 81 82 struct gpio_desc *aux_gpio; 83 84 enum ktd2692_led_mode mode; 85 enum led_brightness torch_brightness; 86 }; 87 88 static struct ktd2692_context *fled_cdev_to_led( 89 struct led_classdev_flash *fled_cdev) 90 { 91 return container_of(fled_cdev, struct ktd2692_context, fled_cdev); 92 } 93 94 static int ktd2692_led_brightness_set(struct led_classdev *led_cdev, 95 enum led_brightness brightness) 96 { 97 struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 98 struct ktd2692_context *led = fled_cdev_to_led(fled_cdev); 99 100 mutex_lock(&led->lock); 101 102 if (brightness == LED_OFF) { 103 led->mode = KTD2692_MODE_DISABLE; 104 gpiod_direction_output(led->aux_gpio, 0); 105 } else { 106 expresswire_write_u8(&led->props, brightness | 107 KTD2692_REG_MOVIE_CURRENT_BASE); 108 led->mode = KTD2692_MODE_MOVIE; 109 } 110 111 expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE); 112 mutex_unlock(&led->lock); 113 114 return 0; 115 } 116 117 static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev, 118 bool state) 119 { 120 struct ktd2692_context *led = fled_cdev_to_led(fled_cdev); 121 struct led_flash_setting *timeout = &fled_cdev->timeout; 122 u32 flash_tm_reg; 123 124 mutex_lock(&led->lock); 125 126 if (state) { 127 flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step); 128 expresswire_write_u8(&led->props, flash_tm_reg 129 | KTD2692_REG_FLASH_TIMEOUT_BASE); 130 131 led->mode = KTD2692_MODE_FLASH; 132 gpiod_direction_output(led->aux_gpio, 1); 133 } else { 134 led->mode = KTD2692_MODE_DISABLE; 135 gpiod_direction_output(led->aux_gpio, 0); 136 } 137 138 expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE); 139 140 fled_cdev->led_cdev.brightness = LED_OFF; 141 led->mode = KTD2692_MODE_DISABLE; 142 143 mutex_unlock(&led->lock); 144 145 return 0; 146 } 147 148 static int ktd2692_led_flash_timeout_set(struct led_classdev_flash *fled_cdev, 149 u32 timeout) 150 { 151 return 0; 152 } 153 154 static void ktd2692_init_movie_current_max(struct ktd2692_led_config_data *cfg) 155 { 156 u32 offset, step; 157 u32 movie_current_microamp; 158 159 offset = KTD2692_MOVIE_MODE_CURRENT_LEVELS; 160 step = KTD2692_MM_TO_FL_RATIO(cfg->flash_max_microamp) 161 / KTD2692_MOVIE_MODE_CURRENT_LEVELS; 162 163 do { 164 movie_current_microamp = step * offset; 165 offset--; 166 } while ((movie_current_microamp > cfg->movie_max_microamp) && 167 (offset > 0)); 168 169 cfg->max_brightness = offset; 170 } 171 172 static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev, 173 struct ktd2692_led_config_data *cfg) 174 { 175 struct led_flash_setting *setting; 176 177 setting = &fled_cdev->timeout; 178 setting->min = KTD2692_FLASH_MODE_TIMEOUT_DISABLE; 179 setting->max = cfg->flash_max_timeout; 180 setting->step = cfg->flash_max_timeout 181 / (KTD2692_FLASH_MODE_TIMEOUT_LEVELS - 1); 182 setting->val = cfg->flash_max_timeout; 183 } 184 185 static void ktd2692_setup(struct ktd2692_context *led) 186 { 187 led->mode = KTD2692_MODE_DISABLE; 188 expresswire_power_off(&led->props); 189 gpiod_direction_output(led->aux_gpio, 0); 190 191 expresswire_write_u8(&led->props, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1) 192 | KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE); 193 expresswire_write_u8(&led->props, KTD2692_FLASH_MODE_CURR_PERCENT(45) 194 | KTD2692_REG_FLASH_CURRENT_BASE); 195 } 196 197 static void regulator_disable_action(void *_data) 198 { 199 struct device *dev = _data; 200 struct ktd2692_context *led = dev_get_drvdata(dev); 201 int ret; 202 203 ret = regulator_disable(led->regulator); 204 if (ret) 205 dev_err(dev, "Failed to disable supply: %d\n", ret); 206 } 207 208 static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, 209 struct ktd2692_led_config_data *cfg) 210 { 211 struct device_node *np = dev_of_node(dev); 212 int ret; 213 214 if (!np) 215 return -ENXIO; 216 217 led->props.ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS); 218 ret = PTR_ERR_OR_ZERO(led->props.ctrl_gpio); 219 if (ret) 220 return dev_err_probe(dev, ret, "cannot get ctrl-gpios\n"); 221 222 led->aux_gpio = devm_gpiod_get_optional(dev, "aux", GPIOD_ASIS); 223 if (IS_ERR(led->aux_gpio)) 224 return dev_err_probe(dev, PTR_ERR(led->aux_gpio), "cannot get aux-gpios\n"); 225 226 led->regulator = devm_regulator_get(dev, "vin"); 227 if (IS_ERR(led->regulator)) 228 led->regulator = NULL; 229 230 if (led->regulator) { 231 ret = regulator_enable(led->regulator); 232 if (ret) { 233 dev_err(dev, "Failed to enable supply: %d\n", ret); 234 } else { 235 ret = devm_add_action_or_reset(dev, 236 regulator_disable_action, dev); 237 if (ret) 238 return ret; 239 } 240 } 241 242 struct device_node *child_node __free(device_node) = 243 of_get_next_available_child(np, NULL); 244 if (!child_node) { 245 dev_err(dev, "No DT child node found for connected LED.\n"); 246 return -EINVAL; 247 } 248 249 led->fled_cdev.led_cdev.name = 250 of_get_property(child_node, "label", NULL) ? : child_node->name; 251 252 ret = of_property_read_u32(child_node, "led-max-microamp", 253 &cfg->movie_max_microamp); 254 if (ret) { 255 dev_err(dev, "failed to parse led-max-microamp\n"); 256 return ret; 257 } 258 259 ret = of_property_read_u32(child_node, "flash-max-microamp", 260 &cfg->flash_max_microamp); 261 if (ret) { 262 dev_err(dev, "failed to parse flash-max-microamp\n"); 263 return ret; 264 } 265 266 ret = of_property_read_u32(child_node, "flash-max-timeout-us", 267 &cfg->flash_max_timeout); 268 if (ret) { 269 dev_err(dev, "failed to parse flash-max-timeout-us\n"); 270 return ret; 271 } 272 273 return 0; 274 } 275 276 static const struct led_flash_ops flash_ops = { 277 .strobe_set = ktd2692_led_flash_strobe_set, 278 .timeout_set = ktd2692_led_flash_timeout_set, 279 }; 280 281 static int ktd2692_probe(struct platform_device *pdev) 282 { 283 struct ktd2692_context *led; 284 struct led_classdev *led_cdev; 285 struct led_classdev_flash *fled_cdev; 286 struct ktd2692_led_config_data led_cfg; 287 int ret; 288 289 led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); 290 if (!led) 291 return -ENOMEM; 292 293 fled_cdev = &led->fled_cdev; 294 led_cdev = &fled_cdev->led_cdev; 295 led->props.timing = ktd2692_timing; 296 297 ret = ktd2692_parse_dt(led, &pdev->dev, &led_cfg); 298 if (ret) 299 return ret; 300 301 ktd2692_init_flash_timeout(fled_cdev, &led_cfg); 302 ktd2692_init_movie_current_max(&led_cfg); 303 304 fled_cdev->ops = &flash_ops; 305 306 led_cdev->max_brightness = led_cfg.max_brightness; 307 led_cdev->brightness_set_blocking = ktd2692_led_brightness_set; 308 led_cdev->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH; 309 310 mutex_init(&led->lock); 311 312 platform_set_drvdata(pdev, led); 313 314 ret = led_classdev_flash_register(&pdev->dev, fled_cdev); 315 if (ret) { 316 dev_err(&pdev->dev, "can't register LED %s\n", led_cdev->name); 317 mutex_destroy(&led->lock); 318 return ret; 319 } 320 321 ktd2692_setup(led); 322 323 return 0; 324 } 325 326 static void ktd2692_remove(struct platform_device *pdev) 327 { 328 struct ktd2692_context *led = platform_get_drvdata(pdev); 329 330 led_classdev_flash_unregister(&led->fled_cdev); 331 332 mutex_destroy(&led->lock); 333 } 334 335 static const struct of_device_id ktd2692_match[] = { 336 { .compatible = "kinetic,ktd2692", }, 337 { /* sentinel */ }, 338 }; 339 MODULE_DEVICE_TABLE(of, ktd2692_match); 340 341 static struct platform_driver ktd2692_driver = { 342 .driver = { 343 .name = "ktd2692", 344 .of_match_table = ktd2692_match, 345 }, 346 .probe = ktd2692_probe, 347 .remove = ktd2692_remove, 348 }; 349 350 module_platform_driver(ktd2692_driver); 351 352 MODULE_IMPORT_NS(EXPRESSWIRE); 353 MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>"); 354 MODULE_DESCRIPTION("Kinetic KTD2692 LED driver"); 355 MODULE_LICENSE("GPL v2"); 356