linux/drivers/leds/leds-ktd2692.c
<<
>>
Prefs
   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 KTD2962_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
  51enum ktd2692_bitset {
  52        KTD2692_LOW = 0,
  53        KTD2692_HIGH,
  54};
  55
  56/* Movie / Flash Mode Control */
  57enum ktd2692_led_mode {
  58        KTD2692_MODE_DISABLE = 0,       /* default */
  59        KTD2692_MODE_MOVIE,
  60        KTD2692_MODE_FLASH,
  61};
  62
  63struct 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
  74struct 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
  89static 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
  95static 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
 101static 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
 107static 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
 115static 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
 146static 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
 156static 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
 179static 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
 210static int ktd2692_led_flash_timeout_set(struct led_classdev_flash *fled_cdev,
 211                                         u32 timeout)
 212{
 213        return 0;
 214}
 215
 216static 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
 234static 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
 247static 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, (KTD2962_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
 259static 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
 323err_parse_dt:
 324        of_node_put(child_node);
 325        return ret;
 326}
 327
 328static 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
 333static 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
 377static 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
 396static const struct of_device_id ktd2692_match[] = {
 397        { .compatible = "kinetic,ktd2692", },
 398        { /* sentinel */ },
 399};
 400MODULE_DEVICE_TABLE(of, ktd2692_match);
 401
 402static 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
 411module_platform_driver(ktd2692_driver);
 412
 413MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>");
 414MODULE_DESCRIPTION("Kinetic KTD2692 LED driver");
 415MODULE_LICENSE("GPL v2");
 416