root/drivers/leds/leds-ktd2692.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fled_cdev_to_led
  2. ktd2692_expresswire_start
  3. ktd2692_expresswire_reset
  4. ktd2692_expresswire_end
  5. ktd2692_expresswire_set_bit
  6. ktd2692_expresswire_write
  7. ktd2692_led_brightness_set
  8. ktd2692_led_flash_strobe_set
  9. ktd2692_led_flash_timeout_set
  10. ktd2692_init_movie_current_max
  11. ktd2692_init_flash_timeout
  12. ktd2692_setup
  13. ktd2692_parse_dt
  14. ktd2692_probe
  15. ktd2692_remove

   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/delay.h>
  10 #include <linux/err.h>
  11 #include <linux/gpio/consumer.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 /* Set bit coding time for expresswire interface */
  41 #define KTD2692_TIME_RESET_US                   700
  42 #define KTD2692_TIME_DATA_START_TIME_US         10
  43 #define KTD2692_TIME_HIGH_END_OF_DATA_US        350
  44 #define KTD2692_TIME_LOW_END_OF_DATA_US         10
  45 #define KTD2692_TIME_SHORT_BITSET_US            4
  46 #define KTD2692_TIME_LONG_BITSET_US             12
  47 
  48 /* KTD2692 default length of name */
  49 #define KTD2692_NAME_LENGTH                     20
  50 
  51 enum ktd2692_bitset {
  52         KTD2692_LOW = 0,
  53         KTD2692_HIGH,
  54 };
  55 
  56 /* Movie / Flash Mode Control */
  57 enum ktd2692_led_mode {
  58         KTD2692_MODE_DISABLE = 0,       /* default */
  59         KTD2692_MODE_MOVIE,
  60         KTD2692_MODE_FLASH,
  61 };
  62 
  63 struct ktd2692_led_config_data {
  64         /* maximum LED current in movie mode */
  65         u32 movie_max_microamp;
  66         /* maximum LED current in flash mode */
  67         u32 flash_max_microamp;
  68         /* maximum flash timeout */
  69         u32 flash_max_timeout;
  70         /* max LED brightness level */
  71         enum led_brightness max_brightness;
  72 };
  73 
  74 struct ktd2692_context {
  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         struct gpio_desc *ctrl_gpio;
  84 
  85         enum ktd2692_led_mode mode;
  86         enum led_brightness torch_brightness;
  87 };
  88 
  89 static struct ktd2692_context *fled_cdev_to_led(
  90                                 struct led_classdev_flash *fled_cdev)
  91 {
  92         return container_of(fled_cdev, struct ktd2692_context, fled_cdev);
  93 }
  94 
  95 static void ktd2692_expresswire_start(struct ktd2692_context *led)
  96 {
  97         gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
  98         udelay(KTD2692_TIME_DATA_START_TIME_US);
  99 }
 100 
 101 static void ktd2692_expresswire_reset(struct ktd2692_context *led)
 102 {
 103         gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
 104         udelay(KTD2692_TIME_RESET_US);
 105 }
 106 
 107 static void ktd2692_expresswire_end(struct ktd2692_context *led)
 108 {
 109         gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
 110         udelay(KTD2692_TIME_LOW_END_OF_DATA_US);
 111         gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
 112         udelay(KTD2692_TIME_HIGH_END_OF_DATA_US);
 113 }
 114 
 115 static void ktd2692_expresswire_set_bit(struct ktd2692_context *led, bool bit)
 116 {
 117         /*
 118          * The Low Bit(0) and High Bit(1) is based on a time detection
 119          * algorithm between time low and time high
 120          * Time_(L_LB) : Low time of the Low Bit(0)
 121          * Time_(H_LB) : High time of the LOW Bit(0)
 122          * Time_(L_HB) : Low time of the High Bit(1)
 123          * Time_(H_HB) : High time of the High Bit(1)
 124          *
 125          * It can be simplified to:
 126          * Low Bit(0) : 2 * Time_(H_LB) < Time_(L_LB)
 127          * High Bit(1) : 2 * Time_(L_HB) < Time_(H_HB)
 128          * HIGH  ___           ____    _..     _________    ___
 129          *          |_________|    |_..  |____|         |__|
 130          * LOW        <L_LB>  <H_LB>     <L_HB>  <H_HB>
 131          *          [  Low Bit (0) ]     [  High Bit(1) ]
 132          */
 133         if (bit) {
 134                 gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
 135                 udelay(KTD2692_TIME_SHORT_BITSET_US);
 136                 gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
 137                 udelay(KTD2692_TIME_LONG_BITSET_US);
 138         } else {
 139                 gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
 140                 udelay(KTD2692_TIME_LONG_BITSET_US);
 141                 gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
 142                 udelay(KTD2692_TIME_SHORT_BITSET_US);
 143         }
 144 }
 145 
 146 static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value)
 147 {
 148         int i;
 149 
 150         ktd2692_expresswire_start(led);
 151         for (i = 7; i >= 0; i--)
 152                 ktd2692_expresswire_set_bit(led, value & BIT(i));
 153         ktd2692_expresswire_end(led);
 154 }
 155 
 156 static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
 157                                        enum led_brightness brightness)
 158 {
 159         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
 160         struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
 161 
 162         mutex_lock(&led->lock);
 163 
 164         if (brightness == LED_OFF) {
 165                 led->mode = KTD2692_MODE_DISABLE;
 166                 gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
 167         } else {
 168                 ktd2692_expresswire_write(led, brightness |
 169                                         KTD2692_REG_MOVIE_CURRENT_BASE);
 170                 led->mode = KTD2692_MODE_MOVIE;
 171         }
 172 
 173         ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
 174         mutex_unlock(&led->lock);
 175 
 176         return 0;
 177 }
 178 
 179 static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,
 180                                         bool state)
 181 {
 182         struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
 183         struct led_flash_setting *timeout = &fled_cdev->timeout;
 184         u32 flash_tm_reg;
 185 
 186         mutex_lock(&led->lock);
 187 
 188         if (state) {
 189                 flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step);
 190                 ktd2692_expresswire_write(led, flash_tm_reg
 191                                 | KTD2692_REG_FLASH_TIMEOUT_BASE);
 192 
 193                 led->mode = KTD2692_MODE_FLASH;
 194                 gpiod_direction_output(led->aux_gpio, KTD2692_HIGH);
 195         } else {
 196                 led->mode = KTD2692_MODE_DISABLE;
 197                 gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
 198         }
 199 
 200         ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
 201 
 202         fled_cdev->led_cdev.brightness = LED_OFF;
 203         led->mode = KTD2692_MODE_DISABLE;
 204 
 205         mutex_unlock(&led->lock);
 206 
 207         return 0;
 208 }
 209 
 210 static int ktd2692_led_flash_timeout_set(struct led_classdev_flash *fled_cdev,
 211                                          u32 timeout)
 212 {
 213         return 0;
 214 }
 215 
 216 static void ktd2692_init_movie_current_max(struct ktd2692_led_config_data *cfg)
 217 {
 218         u32 offset, step;
 219         u32 movie_current_microamp;
 220 
 221         offset = KTD2692_MOVIE_MODE_CURRENT_LEVELS;
 222         step = KTD2692_MM_TO_FL_RATIO(cfg->flash_max_microamp)
 223                 / KTD2692_MOVIE_MODE_CURRENT_LEVELS;
 224 
 225         do {
 226                 movie_current_microamp = step * offset;
 227                 offset--;
 228         } while ((movie_current_microamp > cfg->movie_max_microamp) &&
 229                 (offset > 0));
 230 
 231         cfg->max_brightness = offset;
 232 }
 233 
 234 static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev,
 235                                        struct ktd2692_led_config_data *cfg)
 236 {
 237         struct led_flash_setting *setting;
 238 
 239         setting = &fled_cdev->timeout;
 240         setting->min = KTD2692_FLASH_MODE_TIMEOUT_DISABLE;
 241         setting->max = cfg->flash_max_timeout;
 242         setting->step = cfg->flash_max_timeout
 243                         / (KTD2692_FLASH_MODE_TIMEOUT_LEVELS - 1);
 244         setting->val = cfg->flash_max_timeout;
 245 }
 246 
 247 static void ktd2692_setup(struct ktd2692_context *led)
 248 {
 249         led->mode = KTD2692_MODE_DISABLE;
 250         ktd2692_expresswire_reset(led);
 251         gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
 252 
 253         ktd2692_expresswire_write(led, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1)
 254                                  | KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE);
 255         ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45)
 256                                  | KTD2692_REG_FLASH_CURRENT_BASE);
 257 }
 258 
 259 static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
 260                             struct ktd2692_led_config_data *cfg)
 261 {
 262         struct device_node *np = dev->of_node;
 263         struct device_node *child_node;
 264         int ret;
 265 
 266         if (!dev->of_node)
 267                 return -ENXIO;
 268 
 269         led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
 270         ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
 271         if (ret) {
 272                 dev_err(dev, "cannot get ctrl-gpios %d\n", ret);
 273                 return ret;
 274         }
 275 
 276         led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS);
 277         ret = PTR_ERR_OR_ZERO(led->aux_gpio);
 278         if (ret) {
 279                 dev_err(dev, "cannot get aux-gpios %d\n", ret);
 280                 return ret;
 281         }
 282 
 283         led->regulator = devm_regulator_get(dev, "vin");
 284         if (IS_ERR(led->regulator))
 285                 led->regulator = NULL;
 286 
 287         if (led->regulator) {
 288                 ret = regulator_enable(led->regulator);
 289                 if (ret)
 290                         dev_err(dev, "Failed to enable supply: %d\n", ret);
 291         }
 292 
 293         child_node = of_get_next_available_child(np, NULL);
 294         if (!child_node) {
 295                 dev_err(dev, "No DT child node found for connected LED.\n");
 296                 return -EINVAL;
 297         }
 298 
 299         led->fled_cdev.led_cdev.name =
 300                 of_get_property(child_node, "label", NULL) ? : child_node->name;
 301 
 302         ret = of_property_read_u32(child_node, "led-max-microamp",
 303                                    &cfg->movie_max_microamp);
 304         if (ret) {
 305                 dev_err(dev, "failed to parse led-max-microamp\n");
 306                 goto err_parse_dt;
 307         }
 308 
 309         ret = of_property_read_u32(child_node, "flash-max-microamp",
 310                                    &cfg->flash_max_microamp);
 311         if (ret) {
 312                 dev_err(dev, "failed to parse flash-max-microamp\n");
 313                 goto err_parse_dt;
 314         }
 315 
 316         ret = of_property_read_u32(child_node, "flash-max-timeout-us",
 317                                    &cfg->flash_max_timeout);
 318         if (ret) {
 319                 dev_err(dev, "failed to parse flash-max-timeout-us\n");
 320                 goto err_parse_dt;
 321         }
 322 
 323 err_parse_dt:
 324         of_node_put(child_node);
 325         return ret;
 326 }
 327 
 328 static const struct led_flash_ops flash_ops = {
 329         .strobe_set = ktd2692_led_flash_strobe_set,
 330         .timeout_set = ktd2692_led_flash_timeout_set,
 331 };
 332 
 333 static int ktd2692_probe(struct platform_device *pdev)
 334 {
 335         struct ktd2692_context *led;
 336         struct led_classdev *led_cdev;
 337         struct led_classdev_flash *fled_cdev;
 338         struct ktd2692_led_config_data led_cfg;
 339         int ret;
 340 
 341         led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
 342         if (!led)
 343                 return -ENOMEM;
 344 
 345         fled_cdev = &led->fled_cdev;
 346         led_cdev = &fled_cdev->led_cdev;
 347 
 348         ret = ktd2692_parse_dt(led, &pdev->dev, &led_cfg);
 349         if (ret)
 350                 return ret;
 351 
 352         ktd2692_init_flash_timeout(fled_cdev, &led_cfg);
 353         ktd2692_init_movie_current_max(&led_cfg);
 354 
 355         fled_cdev->ops = &flash_ops;
 356 
 357         led_cdev->max_brightness = led_cfg.max_brightness;
 358         led_cdev->brightness_set_blocking = ktd2692_led_brightness_set;
 359         led_cdev->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH;
 360 
 361         mutex_init(&led->lock);
 362 
 363         platform_set_drvdata(pdev, led);
 364 
 365         ret = led_classdev_flash_register(&pdev->dev, fled_cdev);
 366         if (ret) {
 367                 dev_err(&pdev->dev, "can't register LED %s\n", led_cdev->name);
 368                 mutex_destroy(&led->lock);
 369                 return ret;
 370         }
 371 
 372         ktd2692_setup(led);
 373 
 374         return 0;
 375 }
 376 
 377 static int ktd2692_remove(struct platform_device *pdev)
 378 {
 379         struct ktd2692_context *led = platform_get_drvdata(pdev);
 380         int ret;
 381 
 382         led_classdev_flash_unregister(&led->fled_cdev);
 383 
 384         if (led->regulator) {
 385                 ret = regulator_disable(led->regulator);
 386                 if (ret)
 387                         dev_err(&pdev->dev,
 388                                 "Failed to disable supply: %d\n", ret);
 389         }
 390 
 391         mutex_destroy(&led->lock);
 392 
 393         return 0;
 394 }
 395 
 396 static const struct of_device_id ktd2692_match[] = {
 397         { .compatible = "kinetic,ktd2692", },
 398         { /* sentinel */ },
 399 };
 400 MODULE_DEVICE_TABLE(of, ktd2692_match);
 401 
 402 static struct platform_driver ktd2692_driver = {
 403         .driver = {
 404                 .name  = "ktd2692",
 405                 .of_match_table = ktd2692_match,
 406         },
 407         .probe  = ktd2692_probe,
 408         .remove = ktd2692_remove,
 409 };
 410 
 411 module_platform_driver(ktd2692_driver);
 412 
 413 MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>");
 414 MODULE_DESCRIPTION("Kinetic KTD2692 LED driver");
 415 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */