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/err.h> 10 #include <linux/gpio/consumer.h> 11 #include <linux/leds-expresswire.h> 12 #include <linux/led-class-flash.h> 13 #include <linux/module.h> 14 #include <linux/mutex.h> 15 #include <linux/of.h> 16 #include <linux/platform_device.h> 17 #include <linux/regulator/consumer.h> 18 19 /* Value related the movie mode */ 20 #define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16 21 #define KTD2692_MM_TO_FL_RATIO(x) ((x) / 3) 22 #define KTD2692_MM_MIN_CURR_THRESHOLD_SCALE 8 23 24 /* Value related the flash mode */ 25 #define KTD2692_FLASH_MODE_TIMEOUT_LEVELS 8 26 #define KTD2692_FLASH_MODE_TIMEOUT_DISABLE 0 27 #define KTD2692_FLASH_MODE_CURR_PERCENT(x) (((x) * 16) / 100) 28 29 /* Macro for getting offset of flash timeout */ 30 #define GET_TIMEOUT_OFFSET(timeout, step) ((timeout) / (step)) 31 32 /* Base register address */ 33 #define KTD2692_REG_LVP_BASE 0x00 34 #define KTD2692_REG_FLASH_TIMEOUT_BASE 0x20 35 #define KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE 0x40 36 #define KTD2692_REG_MOVIE_CURRENT_BASE 0x60 37 #define KTD2692_REG_FLASH_CURRENT_BASE 0x80 38 #define KTD2692_REG_MODE_BASE 0xA0 39 40 /* KTD2692 default length of name */ 41 #define KTD2692_NAME_LENGTH 20 42 43 /* Movie / Flash Mode Control */ 44 enum ktd2692_led_mode { 45 KTD2692_MODE_DISABLE = 0, /* default */ 46 KTD2692_MODE_MOVIE, 47 KTD2692_MODE_FLASH, 48 }; 49 50 struct ktd2692_led_config_data { 51 /* maximum LED current in movie mode */ 52 u32 movie_max_microamp; 53 /* maximum LED current in flash mode */ 54 u32 flash_max_microamp; 55 /* maximum flash timeout */ 56 u32 flash_max_timeout; 57 /* max LED brightness level */ 58 enum led_brightness max_brightness; 59 }; 60 61 const struct expresswire_timing ktd2692_timing = { 62 .poweroff_us = 700, 63 .data_start_us = 10, 64 .end_of_data_low_us = 10, 65 .end_of_data_high_us = 350, 66 .short_bitset_us = 4, 67 .long_bitset_us = 12 68 }; 69 70 struct ktd2692_context { 71 /* Common ExpressWire properties (ctrl GPIO and timing) */ 72 struct expresswire_common_props props; 73 74 /* Related LED Flash class device */ 75 struct led_classdev_flash fled_cdev; 76 77 /* secures access to the device */ 78 struct mutex lock; 79 struct regulator *regulator; 80 81 struct gpio_desc *aux_gpio; 82 83 enum ktd2692_led_mode mode; 84 enum led_brightness torch_brightness; 85 }; 86 87 static struct ktd2692_context *fled_cdev_to_led( 88 struct led_classdev_flash *fled_cdev) 89 { 90 return container_of(fled_cdev, struct ktd2692_context, fled_cdev); 91 } 92 93 static int ktd2692_led_brightness_set(struct led_classdev *led_cdev, 94 enum led_brightness brightness) 95 { 96 struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 97 struct ktd2692_context *led = fled_cdev_to_led(fled_cdev); 98 99 mutex_lock(&led->lock); 100 101 if (brightness == LED_OFF) { 102 led->mode = KTD2692_MODE_DISABLE; 103 gpiod_direction_output(led->aux_gpio, 0); 104 } else { 105 expresswire_write_u8(&led->props, brightness | 106 KTD2692_REG_MOVIE_CURRENT_BASE); 107 led->mode = KTD2692_MODE_MOVIE; 108 } 109 110 expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE); 111 mutex_unlock(&led->lock); 112 113 return 0; 114 } 115 116 static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev, 117 bool state) 118 { 119 struct ktd2692_context *led = fled_cdev_to_led(fled_cdev); 120 struct led_flash_setting *timeout = &fled_cdev->timeout; 121 u32 flash_tm_reg; 122 123 mutex_lock(&led->lock); 124 125 if (state) { 126 flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step); 127 expresswire_write_u8(&led->props, flash_tm_reg 128 | KTD2692_REG_FLASH_TIMEOUT_BASE); 129 130 led->mode = KTD2692_MODE_FLASH; 131 gpiod_direction_output(led->aux_gpio, 1); 132 } else { 133 led->mode = KTD2692_MODE_DISABLE; 134 gpiod_direction_output(led->aux_gpio, 0); 135 } 136 137 expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE); 138 139 fled_cdev->led_cdev.brightness = LED_OFF; 140 led->mode = KTD2692_MODE_DISABLE; 141 142 mutex_unlock(&led->lock); 143 144 return 0; 145 } 146 147 static int ktd2692_led_flash_timeout_set(struct led_classdev_flash *fled_cdev, 148 u32 timeout) 149 { 150 return 0; 151 } 152 153 static void ktd2692_init_movie_current_max(struct ktd2692_led_config_data *cfg) 154 { 155 u32 offset, step; 156 u32 movie_current_microamp; 157 158 offset = KTD2692_MOVIE_MODE_CURRENT_LEVELS; 159 step = KTD2692_MM_TO_FL_RATIO(cfg->flash_max_microamp) 160 / KTD2692_MOVIE_MODE_CURRENT_LEVELS; 161 162 do { 163 movie_current_microamp = step * offset; 164 offset--; 165 } while ((movie_current_microamp > cfg->movie_max_microamp) && 166 (offset > 0)); 167 168 cfg->max_brightness = offset; 169 } 170 171 static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev, 172 struct ktd2692_led_config_data *cfg) 173 { 174 struct led_flash_setting *setting; 175 176 setting = &fled_cdev->timeout; 177 setting->min = KTD2692_FLASH_MODE_TIMEOUT_DISABLE; 178 setting->max = cfg->flash_max_timeout; 179 setting->step = cfg->flash_max_timeout 180 / (KTD2692_FLASH_MODE_TIMEOUT_LEVELS - 1); 181 setting->val = cfg->flash_max_timeout; 182 } 183 184 static void ktd2692_setup(struct ktd2692_context *led) 185 { 186 led->mode = KTD2692_MODE_DISABLE; 187 expresswire_power_off(&led->props); 188 gpiod_direction_output(led->aux_gpio, 0); 189 190 expresswire_write_u8(&led->props, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1) 191 | KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE); 192 expresswire_write_u8(&led->props, KTD2692_FLASH_MODE_CURR_PERCENT(45) 193 | KTD2692_REG_FLASH_CURRENT_BASE); 194 } 195 196 static void regulator_disable_action(void *_data) 197 { 198 struct device *dev = _data; 199 struct ktd2692_context *led = dev_get_drvdata(dev); 200 int ret; 201 202 ret = regulator_disable(led->regulator); 203 if (ret) 204 dev_err(dev, "Failed to disable supply: %d\n", ret); 205 } 206 207 static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, 208 struct ktd2692_led_config_data *cfg) 209 { 210 struct device_node *np = dev_of_node(dev); 211 struct device_node *child_node; 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 child_node = of_get_next_available_child(np, NULL); 243 if (!child_node) { 244 dev_err(dev, "No DT child node found for connected LED.\n"); 245 return -EINVAL; 246 } 247 248 led->fled_cdev.led_cdev.name = 249 of_get_property(child_node, "label", NULL) ? : child_node->name; 250 251 ret = of_property_read_u32(child_node, "led-max-microamp", 252 &cfg->movie_max_microamp); 253 if (ret) { 254 dev_err(dev, "failed to parse led-max-microamp\n"); 255 goto err_parse_dt; 256 } 257 258 ret = of_property_read_u32(child_node, "flash-max-microamp", 259 &cfg->flash_max_microamp); 260 if (ret) { 261 dev_err(dev, "failed to parse flash-max-microamp\n"); 262 goto err_parse_dt; 263 } 264 265 ret = of_property_read_u32(child_node, "flash-max-timeout-us", 266 &cfg->flash_max_timeout); 267 if (ret) { 268 dev_err(dev, "failed to parse flash-max-timeout-us\n"); 269 goto err_parse_dt; 270 } 271 272 err_parse_dt: 273 of_node_put(child_node); 274 return ret; 275 } 276 277 static const struct led_flash_ops flash_ops = { 278 .strobe_set = ktd2692_led_flash_strobe_set, 279 .timeout_set = ktd2692_led_flash_timeout_set, 280 }; 281 282 static int ktd2692_probe(struct platform_device *pdev) 283 { 284 struct ktd2692_context *led; 285 struct led_classdev *led_cdev; 286 struct led_classdev_flash *fled_cdev; 287 struct ktd2692_led_config_data led_cfg; 288 int ret; 289 290 led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); 291 if (!led) 292 return -ENOMEM; 293 294 fled_cdev = &led->fled_cdev; 295 led_cdev = &fled_cdev->led_cdev; 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_new = 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