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