linux/drivers/leds/leds-aat1290.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *      LED Flash class driver for the AAT1290
   4 *      1.5A Step-Up Current Regulator for Flash LEDs
   5 *
   6 *      Copyright (C) 2015, Samsung Electronics Co., Ltd.
   7 *      Author: Jacek Anaszewski <j.anaszewski@samsung.com>
   8 */
   9
  10#include <linux/delay.h>
  11#include <linux/gpio/consumer.h>
  12#include <linux/led-class-flash.h>
  13#include <linux/leds.h>
  14#include <linux/module.h>
  15#include <linux/mutex.h>
  16#include <linux/of.h>
  17#include <linux/pinctrl/consumer.h>
  18#include <linux/platform_device.h>
  19#include <linux/slab.h>
  20#include <media/v4l2-flash-led-class.h>
  21
  22#define AAT1290_MOVIE_MODE_CURRENT_ADDR 17
  23#define AAT1290_MAX_MM_CURR_PERCENT_0   16
  24#define AAT1290_MAX_MM_CURR_PERCENT_100 1
  25
  26#define AAT1290_FLASH_SAFETY_TIMER_ADDR 18
  27
  28#define AAT1290_MOVIE_MODE_CONFIG_ADDR  19
  29#define AAT1290_MOVIE_MODE_OFF          1
  30#define AAT1290_MOVIE_MODE_ON           3
  31
  32#define AAT1290_MM_CURRENT_RATIO_ADDR   20
  33#define AAT1290_MM_TO_FL_1_92           1
  34
  35#define AAT1290_MM_TO_FL_RATIO          1000 / 1920
  36#define AAT1290_MAX_MM_CURRENT(fl_max)  (fl_max * AAT1290_MM_TO_FL_RATIO)
  37
  38#define AAT1290_LATCH_TIME_MIN_US       500
  39#define AAT1290_LATCH_TIME_MAX_US       1000
  40#define AAT1290_EN_SET_TICK_TIME_US     1
  41#define AAT1290_FLEN_OFF_DELAY_TIME_US  10
  42#define AAT1290_FLASH_TM_NUM_LEVELS     16
  43#define AAT1290_MM_CURRENT_SCALE_SIZE   15
  44
  45#define AAT1290_NAME                    "aat1290"
  46
  47
  48struct aat1290_led_config_data {
  49        /* maximum LED current in movie mode */
  50        u32 max_mm_current;
  51        /* maximum LED current in flash mode */
  52        u32 max_flash_current;
  53        /* maximum flash timeout */
  54        u32 max_flash_tm;
  55        /* external strobe capability */
  56        bool has_external_strobe;
  57        /* max LED brightness level */
  58        enum led_brightness max_brightness;
  59};
  60
  61struct aat1290_led {
  62        /* platform device data */
  63        struct platform_device *pdev;
  64        /* secures access to the device */
  65        struct mutex lock;
  66
  67        /* corresponding LED Flash class device */
  68        struct led_classdev_flash fled_cdev;
  69        /* V4L2 Flash device */
  70        struct v4l2_flash *v4l2_flash;
  71
  72        /* FLEN pin */
  73        struct gpio_desc *gpio_fl_en;
  74        /* EN|SET pin  */
  75        struct gpio_desc *gpio_en_set;
  76        /* movie mode current scale */
  77        int *mm_current_scale;
  78        /* device mode */
  79        bool movie_mode;
  80        /* brightness cache */
  81        unsigned int torch_brightness;
  82};
  83
  84static struct aat1290_led *fled_cdev_to_led(
  85                                struct led_classdev_flash *fled_cdev)
  86{
  87        return container_of(fled_cdev, struct aat1290_led, fled_cdev);
  88}
  89
  90static struct led_classdev_flash *led_cdev_to_fled_cdev(
  91                                struct led_classdev *led_cdev)
  92{
  93        return container_of(led_cdev, struct led_classdev_flash, led_cdev);
  94}
  95
  96static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value)
  97{
  98        int i;
  99
 100        gpiod_direction_output(led->gpio_fl_en, 0);
 101        gpiod_direction_output(led->gpio_en_set, 0);
 102
 103        udelay(AAT1290_FLEN_OFF_DELAY_TIME_US);
 104
 105        /* write address */
 106        for (i = 0; i < addr; ++i) {
 107                udelay(AAT1290_EN_SET_TICK_TIME_US);
 108                gpiod_direction_output(led->gpio_en_set, 0);
 109                udelay(AAT1290_EN_SET_TICK_TIME_US);
 110                gpiod_direction_output(led->gpio_en_set, 1);
 111        }
 112
 113        usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US);
 114
 115        /* write data */
 116        for (i = 0; i < value; ++i) {
 117                udelay(AAT1290_EN_SET_TICK_TIME_US);
 118                gpiod_direction_output(led->gpio_en_set, 0);
 119                udelay(AAT1290_EN_SET_TICK_TIME_US);
 120                gpiod_direction_output(led->gpio_en_set, 1);
 121        }
 122
 123        usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US);
 124}
 125
 126static void aat1290_set_flash_safety_timer(struct aat1290_led *led,
 127                                        unsigned int micro_sec)
 128{
 129        struct led_classdev_flash *fled_cdev = &led->fled_cdev;
 130        struct led_flash_setting *flash_tm = &fled_cdev->timeout;
 131        int flash_tm_reg = AAT1290_FLASH_TM_NUM_LEVELS -
 132                                (micro_sec / flash_tm->step) + 1;
 133
 134        aat1290_as2cwire_write(led, AAT1290_FLASH_SAFETY_TIMER_ADDR,
 135                                                        flash_tm_reg);
 136}
 137
 138/* LED subsystem callbacks */
 139
 140static int aat1290_led_brightness_set(struct led_classdev *led_cdev,
 141                                        enum led_brightness brightness)
 142{
 143        struct led_classdev_flash *fled_cdev = led_cdev_to_fled_cdev(led_cdev);
 144        struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
 145
 146        mutex_lock(&led->lock);
 147
 148        if (brightness == 0) {
 149                gpiod_direction_output(led->gpio_fl_en, 0);
 150                gpiod_direction_output(led->gpio_en_set, 0);
 151                led->movie_mode = false;
 152        } else {
 153                if (!led->movie_mode) {
 154                        aat1290_as2cwire_write(led,
 155                                AAT1290_MM_CURRENT_RATIO_ADDR,
 156                                AAT1290_MM_TO_FL_1_92);
 157                        led->movie_mode = true;
 158                }
 159
 160                aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CURRENT_ADDR,
 161                                AAT1290_MAX_MM_CURR_PERCENT_0 - brightness);
 162                aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CONFIG_ADDR,
 163                                AAT1290_MOVIE_MODE_ON);
 164        }
 165
 166        mutex_unlock(&led->lock);
 167
 168        return 0;
 169}
 170
 171static int aat1290_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,
 172                                         bool state)
 173
 174{
 175        struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
 176        struct led_classdev *led_cdev = &fled_cdev->led_cdev;
 177        struct led_flash_setting *timeout = &fled_cdev->timeout;
 178
 179        mutex_lock(&led->lock);
 180
 181        if (state) {
 182                aat1290_set_flash_safety_timer(led, timeout->val);
 183                gpiod_direction_output(led->gpio_fl_en, 1);
 184        } else {
 185                gpiod_direction_output(led->gpio_fl_en, 0);
 186                gpiod_direction_output(led->gpio_en_set, 0);
 187        }
 188
 189        /*
 190         * To reenter movie mode after a flash event the part must be cycled
 191         * off and back on to reset the movie mode and reprogrammed via the
 192         * AS2Cwire. Therefore the brightness and movie_mode properties needs
 193         * to be updated here to reflect the actual state.
 194         */
 195        led_cdev->brightness = 0;
 196        led->movie_mode = false;
 197
 198        mutex_unlock(&led->lock);
 199
 200        return 0;
 201}
 202
 203static int aat1290_led_flash_timeout_set(struct led_classdev_flash *fled_cdev,
 204                                                u32 timeout)
 205{
 206        /*
 207         * Don't do anything - flash timeout is cached in the led-class-flash
 208         * core and will be applied in the strobe_set op, as writing the
 209         * safety timer register spuriously turns the torch mode on.
 210         */
 211
 212        return 0;
 213}
 214
 215static int aat1290_led_parse_dt(struct aat1290_led *led,
 216                        struct aat1290_led_config_data *cfg,
 217                        struct device_node **sub_node)
 218{
 219        struct device *dev = &led->pdev->dev;
 220        struct device_node *child_node;
 221#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
 222        struct pinctrl *pinctrl;
 223#endif
 224        int ret = 0;
 225
 226        led->gpio_fl_en = devm_gpiod_get(dev, "flen", GPIOD_ASIS);
 227        if (IS_ERR(led->gpio_fl_en)) {
 228                ret = PTR_ERR(led->gpio_fl_en);
 229                dev_err(dev, "Unable to claim gpio \"flen\".\n");
 230                return ret;
 231        }
 232
 233        led->gpio_en_set = devm_gpiod_get(dev, "enset", GPIOD_ASIS);
 234        if (IS_ERR(led->gpio_en_set)) {
 235                ret = PTR_ERR(led->gpio_en_set);
 236                dev_err(dev, "Unable to claim gpio \"enset\".\n");
 237                return ret;
 238        }
 239
 240#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
 241        pinctrl = devm_pinctrl_get_select_default(&led->pdev->dev);
 242        if (IS_ERR(pinctrl)) {
 243                cfg->has_external_strobe = false;
 244                dev_info(dev,
 245                         "No support for external strobe detected.\n");
 246        } else {
 247                cfg->has_external_strobe = true;
 248        }
 249#endif
 250
 251        child_node = of_get_next_available_child(dev_of_node(dev), NULL);
 252        if (!child_node) {
 253                dev_err(dev, "No DT child node found for connected LED.\n");
 254                return -EINVAL;
 255        }
 256
 257        ret = of_property_read_u32(child_node, "led-max-microamp",
 258                                &cfg->max_mm_current);
 259        /*
 260         * led-max-microamp will default to 1/20 of flash-max-microamp
 261         * in case it is missing.
 262         */
 263        if (ret < 0)
 264                dev_warn(dev,
 265                        "led-max-microamp DT property missing\n");
 266
 267        ret = of_property_read_u32(child_node, "flash-max-microamp",
 268                                &cfg->max_flash_current);
 269        if (ret < 0) {
 270                dev_err(dev,
 271                        "flash-max-microamp DT property missing\n");
 272                goto err_parse_dt;
 273        }
 274
 275        ret = of_property_read_u32(child_node, "flash-max-timeout-us",
 276                                &cfg->max_flash_tm);
 277        if (ret < 0) {
 278                dev_err(dev,
 279                        "flash-max-timeout-us DT property missing\n");
 280                goto err_parse_dt;
 281        }
 282
 283        *sub_node = child_node;
 284
 285err_parse_dt:
 286        of_node_put(child_node);
 287
 288        return ret;
 289}
 290
 291static void aat1290_led_validate_mm_current(struct aat1290_led *led,
 292                                        struct aat1290_led_config_data *cfg)
 293{
 294        int i, b = 0, e = AAT1290_MM_CURRENT_SCALE_SIZE;
 295
 296        while (e - b > 1) {
 297                i = b + (e - b) / 2;
 298                if (cfg->max_mm_current < led->mm_current_scale[i])
 299                        e = i;
 300                else
 301                        b = i;
 302        }
 303
 304        cfg->max_mm_current = led->mm_current_scale[b];
 305        cfg->max_brightness = b + 1;
 306}
 307
 308static int init_mm_current_scale(struct aat1290_led *led,
 309                        struct aat1290_led_config_data *cfg)
 310{
 311        static const int max_mm_current_percent[] = {
 312                20, 22, 25, 28, 32, 36, 40, 45, 50, 56,
 313                63, 71, 79, 89, 100
 314        };
 315        int i, max_mm_current =
 316                        AAT1290_MAX_MM_CURRENT(cfg->max_flash_current);
 317
 318        led->mm_current_scale = devm_kzalloc(&led->pdev->dev,
 319                                        sizeof(max_mm_current_percent),
 320                                        GFP_KERNEL);
 321        if (!led->mm_current_scale)
 322                return -ENOMEM;
 323
 324        for (i = 0; i < AAT1290_MM_CURRENT_SCALE_SIZE; ++i)
 325                led->mm_current_scale[i] = max_mm_current *
 326                                          max_mm_current_percent[i] / 100;
 327
 328        return 0;
 329}
 330
 331static int aat1290_led_get_configuration(struct aat1290_led *led,
 332                                        struct aat1290_led_config_data *cfg,
 333                                        struct device_node **sub_node)
 334{
 335        int ret;
 336
 337        ret = aat1290_led_parse_dt(led, cfg, sub_node);
 338        if (ret < 0)
 339                return ret;
 340        /*
 341         * Init non-linear movie mode current scale basing
 342         * on the max flash current from led configuration.
 343         */
 344        ret = init_mm_current_scale(led, cfg);
 345        if (ret < 0)
 346                return ret;
 347
 348        aat1290_led_validate_mm_current(led, cfg);
 349
 350#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
 351#else
 352        devm_kfree(&led->pdev->dev, led->mm_current_scale);
 353#endif
 354
 355        return 0;
 356}
 357
 358static void aat1290_init_flash_timeout(struct aat1290_led *led,
 359                                struct aat1290_led_config_data *cfg)
 360{
 361        struct led_classdev_flash *fled_cdev = &led->fled_cdev;
 362        struct led_flash_setting *setting;
 363
 364        /* Init flash timeout setting */
 365        setting = &fled_cdev->timeout;
 366        setting->min = cfg->max_flash_tm / AAT1290_FLASH_TM_NUM_LEVELS;
 367        setting->max = cfg->max_flash_tm;
 368        setting->step = setting->min;
 369        setting->val = setting->max;
 370}
 371
 372#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
 373static enum led_brightness aat1290_intensity_to_brightness(
 374                                        struct v4l2_flash *v4l2_flash,
 375                                        s32 intensity)
 376{
 377        struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
 378        struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
 379        int i;
 380
 381        for (i = AAT1290_MM_CURRENT_SCALE_SIZE - 1; i >= 0; --i)
 382                if (intensity >= led->mm_current_scale[i])
 383                        return i + 1;
 384
 385        return 1;
 386}
 387
 388static s32 aat1290_brightness_to_intensity(struct v4l2_flash *v4l2_flash,
 389                                        enum led_brightness brightness)
 390{
 391        struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
 392        struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
 393
 394        return led->mm_current_scale[brightness - 1];
 395}
 396
 397static int aat1290_led_external_strobe_set(struct v4l2_flash *v4l2_flash,
 398                                                bool enable)
 399{
 400        struct aat1290_led *led = fled_cdev_to_led(v4l2_flash->fled_cdev);
 401        struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
 402        struct led_classdev *led_cdev = &fled_cdev->led_cdev;
 403        struct pinctrl *pinctrl;
 404
 405        gpiod_direction_output(led->gpio_fl_en, 0);
 406        gpiod_direction_output(led->gpio_en_set, 0);
 407
 408        led->movie_mode = false;
 409        led_cdev->brightness = 0;
 410
 411        pinctrl = devm_pinctrl_get_select(&led->pdev->dev,
 412                                                enable ? "isp" : "host");
 413        if (IS_ERR(pinctrl)) {
 414                dev_warn(&led->pdev->dev, "Unable to switch strobe source.\n");
 415                return PTR_ERR(pinctrl);
 416        }
 417
 418        return 0;
 419}
 420
 421static void aat1290_init_v4l2_flash_config(struct aat1290_led *led,
 422                                        struct aat1290_led_config_data *led_cfg,
 423                                        struct v4l2_flash_config *v4l2_sd_cfg)
 424{
 425        struct led_classdev *led_cdev = &led->fled_cdev.led_cdev;
 426        struct led_flash_setting *s;
 427
 428        strlcpy(v4l2_sd_cfg->dev_name, led_cdev->dev->kobj.name,
 429                sizeof(v4l2_sd_cfg->dev_name));
 430
 431        s = &v4l2_sd_cfg->intensity;
 432        s->min = led->mm_current_scale[0];
 433        s->max = led_cfg->max_mm_current;
 434        s->step = 1;
 435        s->val = s->max;
 436
 437        v4l2_sd_cfg->has_external_strobe = led_cfg->has_external_strobe;
 438}
 439
 440static const struct v4l2_flash_ops v4l2_flash_ops = {
 441        .external_strobe_set = aat1290_led_external_strobe_set,
 442        .intensity_to_led_brightness = aat1290_intensity_to_brightness,
 443        .led_brightness_to_intensity = aat1290_brightness_to_intensity,
 444};
 445#else
 446static inline void aat1290_init_v4l2_flash_config(struct aat1290_led *led,
 447                                struct aat1290_led_config_data *led_cfg,
 448                                struct v4l2_flash_config *v4l2_sd_cfg)
 449{
 450}
 451static const struct v4l2_flash_ops v4l2_flash_ops;
 452#endif
 453
 454static const struct led_flash_ops flash_ops = {
 455        .strobe_set = aat1290_led_flash_strobe_set,
 456        .timeout_set = aat1290_led_flash_timeout_set,
 457};
 458
 459static int aat1290_led_probe(struct platform_device *pdev)
 460{
 461        struct device *dev = &pdev->dev;
 462        struct device_node *sub_node = NULL;
 463        struct aat1290_led *led;
 464        struct led_classdev *led_cdev;
 465        struct led_classdev_flash *fled_cdev;
 466        struct led_init_data init_data = {};
 467        struct aat1290_led_config_data led_cfg = {};
 468        struct v4l2_flash_config v4l2_sd_cfg = {};
 469        int ret;
 470
 471        led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
 472        if (!led)
 473                return -ENOMEM;
 474
 475        led->pdev = pdev;
 476        platform_set_drvdata(pdev, led);
 477
 478        fled_cdev = &led->fled_cdev;
 479        fled_cdev->ops = &flash_ops;
 480        led_cdev = &fled_cdev->led_cdev;
 481
 482        ret = aat1290_led_get_configuration(led, &led_cfg, &sub_node);
 483        if (ret < 0)
 484                return ret;
 485
 486        mutex_init(&led->lock);
 487
 488        /* Initialize LED Flash class device */
 489        led_cdev->brightness_set_blocking = aat1290_led_brightness_set;
 490        led_cdev->max_brightness = led_cfg.max_brightness;
 491        led_cdev->flags |= LED_DEV_CAP_FLASH;
 492
 493        aat1290_init_flash_timeout(led, &led_cfg);
 494
 495        init_data.fwnode = of_fwnode_handle(sub_node);
 496        init_data.devicename = AAT1290_NAME;
 497
 498        /* Register LED Flash class device */
 499        ret = led_classdev_flash_register_ext(&pdev->dev, fled_cdev,
 500                                              &init_data);
 501        if (ret < 0)
 502                goto err_flash_register;
 503
 504        aat1290_init_v4l2_flash_config(led, &led_cfg, &v4l2_sd_cfg);
 505
 506        /* Create V4L2 Flash subdev. */
 507        led->v4l2_flash = v4l2_flash_init(dev, of_fwnode_handle(sub_node),
 508                                          fled_cdev, &v4l2_flash_ops,
 509                                          &v4l2_sd_cfg);
 510        if (IS_ERR(led->v4l2_flash)) {
 511                ret = PTR_ERR(led->v4l2_flash);
 512                goto error_v4l2_flash_init;
 513        }
 514
 515        return 0;
 516
 517error_v4l2_flash_init:
 518        led_classdev_flash_unregister(fled_cdev);
 519err_flash_register:
 520        mutex_destroy(&led->lock);
 521
 522        return ret;
 523}
 524
 525static int aat1290_led_remove(struct platform_device *pdev)
 526{
 527        struct aat1290_led *led = platform_get_drvdata(pdev);
 528
 529        v4l2_flash_release(led->v4l2_flash);
 530        led_classdev_flash_unregister(&led->fled_cdev);
 531
 532        mutex_destroy(&led->lock);
 533
 534        return 0;
 535}
 536
 537static const struct of_device_id aat1290_led_dt_match[] = {
 538        { .compatible = "skyworks,aat1290" },
 539        {},
 540};
 541MODULE_DEVICE_TABLE(of, aat1290_led_dt_match);
 542
 543static struct platform_driver aat1290_led_driver = {
 544        .probe          = aat1290_led_probe,
 545        .remove         = aat1290_led_remove,
 546        .driver         = {
 547                .name   = "aat1290",
 548                .of_match_table = aat1290_led_dt_match,
 549        },
 550};
 551
 552module_platform_driver(aat1290_led_driver);
 553
 554MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
 555MODULE_DESCRIPTION("Skyworks Current Regulator for Flash LEDs");
 556MODULE_LICENSE("GPL v2");
 557