linux/drivers/leds/leds-lp5562.c
<<
>>
Prefs
   1/*
   2 * LP5562 LED driver
   3 *
   4 * Copyright (C) 2013 Texas Instruments
   5 *
   6 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/delay.h>
  14#include <linux/firmware.h>
  15#include <linux/i2c.h>
  16#include <linux/leds.h>
  17#include <linux/module.h>
  18#include <linux/mutex.h>
  19#include <linux/of.h>
  20#include <linux/platform_data/leds-lp55xx.h>
  21#include <linux/slab.h>
  22
  23#include "leds-lp55xx-common.h"
  24
  25#define LP5562_PROGRAM_LENGTH           32
  26#define LP5562_MAX_LEDS                 4
  27
  28/* ENABLE Register 00h */
  29#define LP5562_REG_ENABLE               0x00
  30#define LP5562_EXEC_ENG1_M              0x30
  31#define LP5562_EXEC_ENG2_M              0x0C
  32#define LP5562_EXEC_ENG3_M              0x03
  33#define LP5562_EXEC_M                   0x3F
  34#define LP5562_MASTER_ENABLE            0x40    /* Chip master enable */
  35#define LP5562_LOGARITHMIC_PWM          0x80    /* Logarithmic PWM adjustment */
  36#define LP5562_EXEC_RUN                 0x2A
  37#define LP5562_ENABLE_DEFAULT   \
  38        (LP5562_MASTER_ENABLE | LP5562_LOGARITHMIC_PWM)
  39#define LP5562_ENABLE_RUN_PROGRAM       \
  40        (LP5562_ENABLE_DEFAULT | LP5562_EXEC_RUN)
  41
  42/* OPMODE Register 01h */
  43#define LP5562_REG_OP_MODE              0x01
  44#define LP5562_MODE_ENG1_M              0x30
  45#define LP5562_MODE_ENG2_M              0x0C
  46#define LP5562_MODE_ENG3_M              0x03
  47#define LP5562_LOAD_ENG1                0x10
  48#define LP5562_LOAD_ENG2                0x04
  49#define LP5562_LOAD_ENG3                0x01
  50#define LP5562_RUN_ENG1                 0x20
  51#define LP5562_RUN_ENG2                 0x08
  52#define LP5562_RUN_ENG3                 0x02
  53#define LP5562_ENG1_IS_LOADING(mode)    \
  54        ((mode & LP5562_MODE_ENG1_M) == LP5562_LOAD_ENG1)
  55#define LP5562_ENG2_IS_LOADING(mode)    \
  56        ((mode & LP5562_MODE_ENG2_M) == LP5562_LOAD_ENG2)
  57#define LP5562_ENG3_IS_LOADING(mode)    \
  58        ((mode & LP5562_MODE_ENG3_M) == LP5562_LOAD_ENG3)
  59
  60/* BRIGHTNESS Registers */
  61#define LP5562_REG_R_PWM                0x04
  62#define LP5562_REG_G_PWM                0x03
  63#define LP5562_REG_B_PWM                0x02
  64#define LP5562_REG_W_PWM                0x0E
  65
  66/* CURRENT Registers */
  67#define LP5562_REG_R_CURRENT            0x07
  68#define LP5562_REG_G_CURRENT            0x06
  69#define LP5562_REG_B_CURRENT            0x05
  70#define LP5562_REG_W_CURRENT            0x0F
  71
  72/* CONFIG Register 08h */
  73#define LP5562_REG_CONFIG               0x08
  74#define LP5562_PWM_HF                   0x40
  75#define LP5562_PWRSAVE_EN               0x20
  76#define LP5562_CLK_INT                  0x01    /* Internal clock */
  77#define LP5562_DEFAULT_CFG              (LP5562_PWM_HF | LP5562_PWRSAVE_EN)
  78
  79/* RESET Register 0Dh */
  80#define LP5562_REG_RESET                0x0D
  81#define LP5562_RESET                    0xFF
  82
  83/* PROGRAM ENGINE Registers */
  84#define LP5562_REG_PROG_MEM_ENG1        0x10
  85#define LP5562_REG_PROG_MEM_ENG2        0x30
  86#define LP5562_REG_PROG_MEM_ENG3        0x50
  87
  88/* LEDMAP Register 70h */
  89#define LP5562_REG_ENG_SEL              0x70
  90#define LP5562_ENG_SEL_PWM              0
  91#define LP5562_ENG_FOR_RGB_M            0x3F
  92#define LP5562_ENG_SEL_RGB              0x1B    /* R:ENG1, G:ENG2, B:ENG3 */
  93#define LP5562_ENG_FOR_W_M              0xC0
  94#define LP5562_ENG1_FOR_W               0x40    /* W:ENG1 */
  95#define LP5562_ENG2_FOR_W               0x80    /* W:ENG2 */
  96#define LP5562_ENG3_FOR_W               0xC0    /* W:ENG3 */
  97
  98/* Program Commands */
  99#define LP5562_CMD_DISABLE              0x00
 100#define LP5562_CMD_LOAD                 0x15
 101#define LP5562_CMD_RUN                  0x2A
 102#define LP5562_CMD_DIRECT               0x3F
 103#define LP5562_PATTERN_OFF              0
 104
 105static inline void lp5562_wait_opmode_done(void)
 106{
 107        /* operation mode change needs to be longer than 153 us */
 108        usleep_range(200, 300);
 109}
 110
 111static inline void lp5562_wait_enable_done(void)
 112{
 113        /* it takes more 488 us to update ENABLE register */
 114        usleep_range(500, 600);
 115}
 116
 117static void lp5562_set_led_current(struct lp55xx_led *led, u8 led_current)
 118{
 119        u8 addr[] = {
 120                LP5562_REG_R_CURRENT,
 121                LP5562_REG_G_CURRENT,
 122                LP5562_REG_B_CURRENT,
 123                LP5562_REG_W_CURRENT,
 124        };
 125
 126        led->led_current = led_current;
 127        lp55xx_write(led->chip, addr[led->chan_nr], led_current);
 128}
 129
 130static void lp5562_load_engine(struct lp55xx_chip *chip)
 131{
 132        enum lp55xx_engine_index idx = chip->engine_idx;
 133        u8 mask[] = {
 134                [LP55XX_ENGINE_1] = LP5562_MODE_ENG1_M,
 135                [LP55XX_ENGINE_2] = LP5562_MODE_ENG2_M,
 136                [LP55XX_ENGINE_3] = LP5562_MODE_ENG3_M,
 137        };
 138
 139        u8 val[] = {
 140                [LP55XX_ENGINE_1] = LP5562_LOAD_ENG1,
 141                [LP55XX_ENGINE_2] = LP5562_LOAD_ENG2,
 142                [LP55XX_ENGINE_3] = LP5562_LOAD_ENG3,
 143        };
 144
 145        lp55xx_update_bits(chip, LP5562_REG_OP_MODE, mask[idx], val[idx]);
 146
 147        lp5562_wait_opmode_done();
 148}
 149
 150static void lp5562_stop_engine(struct lp55xx_chip *chip)
 151{
 152        lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DISABLE);
 153        lp5562_wait_opmode_done();
 154}
 155
 156static void lp5562_run_engine(struct lp55xx_chip *chip, bool start)
 157{
 158        int ret;
 159        u8 mode;
 160        u8 exec;
 161
 162        /* stop engine */
 163        if (!start) {
 164                lp55xx_write(chip, LP5562_REG_ENABLE, LP5562_ENABLE_DEFAULT);
 165                lp5562_wait_enable_done();
 166                lp5562_stop_engine(chip);
 167                lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
 168                lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
 169                lp5562_wait_opmode_done();
 170                return;
 171        }
 172
 173        /*
 174         * To run the engine,
 175         * operation mode and enable register should updated at the same time
 176         */
 177
 178        ret = lp55xx_read(chip, LP5562_REG_OP_MODE, &mode);
 179        if (ret)
 180                return;
 181
 182        ret = lp55xx_read(chip, LP5562_REG_ENABLE, &exec);
 183        if (ret)
 184                return;
 185
 186        /* change operation mode to RUN only when each engine is loading */
 187        if (LP5562_ENG1_IS_LOADING(mode)) {
 188                mode = (mode & ~LP5562_MODE_ENG1_M) | LP5562_RUN_ENG1;
 189                exec = (exec & ~LP5562_EXEC_ENG1_M) | LP5562_RUN_ENG1;
 190        }
 191
 192        if (LP5562_ENG2_IS_LOADING(mode)) {
 193                mode = (mode & ~LP5562_MODE_ENG2_M) | LP5562_RUN_ENG2;
 194                exec = (exec & ~LP5562_EXEC_ENG2_M) | LP5562_RUN_ENG2;
 195        }
 196
 197        if (LP5562_ENG3_IS_LOADING(mode)) {
 198                mode = (mode & ~LP5562_MODE_ENG3_M) | LP5562_RUN_ENG3;
 199                exec = (exec & ~LP5562_EXEC_ENG3_M) | LP5562_RUN_ENG3;
 200        }
 201
 202        lp55xx_write(chip, LP5562_REG_OP_MODE, mode);
 203        lp5562_wait_opmode_done();
 204
 205        lp55xx_update_bits(chip, LP5562_REG_ENABLE, LP5562_EXEC_M, exec);
 206        lp5562_wait_enable_done();
 207}
 208
 209static int lp5562_update_firmware(struct lp55xx_chip *chip,
 210                                        const u8 *data, size_t size)
 211{
 212        enum lp55xx_engine_index idx = chip->engine_idx;
 213        u8 pattern[LP5562_PROGRAM_LENGTH] = {0};
 214        u8 addr[] = {
 215                [LP55XX_ENGINE_1] = LP5562_REG_PROG_MEM_ENG1,
 216                [LP55XX_ENGINE_2] = LP5562_REG_PROG_MEM_ENG2,
 217                [LP55XX_ENGINE_3] = LP5562_REG_PROG_MEM_ENG3,
 218        };
 219        unsigned cmd;
 220        char c[3];
 221        int program_size;
 222        int nrchars;
 223        int offset = 0;
 224        int ret;
 225        int i;
 226
 227        /* clear program memory before updating */
 228        for (i = 0; i < LP5562_PROGRAM_LENGTH; i++)
 229                lp55xx_write(chip, addr[idx] + i, 0);
 230
 231        i = 0;
 232        while ((offset < size - 1) && (i < LP5562_PROGRAM_LENGTH)) {
 233                /* separate sscanfs because length is working only for %s */
 234                ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
 235                if (ret != 1)
 236                        goto err;
 237
 238                ret = sscanf(c, "%2x", &cmd);
 239                if (ret != 1)
 240                        goto err;
 241
 242                pattern[i] = (u8)cmd;
 243                offset += nrchars;
 244                i++;
 245        }
 246
 247        /* Each instruction is 16bit long. Check that length is even */
 248        if (i % 2)
 249                goto err;
 250
 251        program_size = i;
 252        for (i = 0; i < program_size; i++)
 253                lp55xx_write(chip, addr[idx] + i, pattern[i]);
 254
 255        return 0;
 256
 257err:
 258        dev_err(&chip->cl->dev, "wrong pattern format\n");
 259        return -EINVAL;
 260}
 261
 262static void lp5562_firmware_loaded(struct lp55xx_chip *chip)
 263{
 264        const struct firmware *fw = chip->fw;
 265
 266        if (fw->size > LP5562_PROGRAM_LENGTH) {
 267                dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
 268                        fw->size);
 269                return;
 270        }
 271
 272        /*
 273         * Program momery sequence
 274         *  1) set engine mode to "LOAD"
 275         *  2) write firmware data into program memory
 276         */
 277
 278        lp5562_load_engine(chip);
 279        lp5562_update_firmware(chip, fw->data, fw->size);
 280}
 281
 282static int lp5562_post_init_device(struct lp55xx_chip *chip)
 283{
 284        int ret;
 285        u8 cfg = LP5562_DEFAULT_CFG;
 286
 287        /* Set all PWMs to direct control mode */
 288        ret = lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
 289        if (ret)
 290                return ret;
 291
 292        lp5562_wait_opmode_done();
 293
 294        /* Update configuration for the clock setting */
 295        if (!lp55xx_is_extclk_used(chip))
 296                cfg |= LP5562_CLK_INT;
 297
 298        ret = lp55xx_write(chip, LP5562_REG_CONFIG, cfg);
 299        if (ret)
 300                return ret;
 301
 302        /* Initialize all channels PWM to zero -> leds off */
 303        lp55xx_write(chip, LP5562_REG_R_PWM, 0);
 304        lp55xx_write(chip, LP5562_REG_G_PWM, 0);
 305        lp55xx_write(chip, LP5562_REG_B_PWM, 0);
 306        lp55xx_write(chip, LP5562_REG_W_PWM, 0);
 307
 308        /* Set LED map as register PWM by default */
 309        lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
 310
 311        return 0;
 312}
 313
 314static int lp5562_led_brightness(struct lp55xx_led *led)
 315{
 316        struct lp55xx_chip *chip = led->chip;
 317        u8 addr[] = {
 318                LP5562_REG_R_PWM,
 319                LP5562_REG_G_PWM,
 320                LP5562_REG_B_PWM,
 321                LP5562_REG_W_PWM,
 322        };
 323        int ret;
 324
 325        mutex_lock(&chip->lock);
 326        ret = lp55xx_write(chip, addr[led->chan_nr], led->brightness);
 327        mutex_unlock(&chip->lock);
 328
 329        return ret;
 330}
 331
 332static void lp5562_write_program_memory(struct lp55xx_chip *chip,
 333                                        u8 base, const u8 *rgb, int size)
 334{
 335        int i;
 336
 337        if (!rgb || size <= 0)
 338                return;
 339
 340        for (i = 0; i < size; i++)
 341                lp55xx_write(chip, base + i, *(rgb + i));
 342
 343        lp55xx_write(chip, base + i, 0);
 344        lp55xx_write(chip, base + i + 1, 0);
 345}
 346
 347/* check the size of program count */
 348static inline bool _is_pc_overflow(struct lp55xx_predef_pattern *ptn)
 349{
 350        return ptn->size_r >= LP5562_PROGRAM_LENGTH ||
 351               ptn->size_g >= LP5562_PROGRAM_LENGTH ||
 352               ptn->size_b >= LP5562_PROGRAM_LENGTH;
 353}
 354
 355static int lp5562_run_predef_led_pattern(struct lp55xx_chip *chip, int mode)
 356{
 357        struct lp55xx_predef_pattern *ptn;
 358        int i;
 359
 360        if (mode == LP5562_PATTERN_OFF) {
 361                lp5562_run_engine(chip, false);
 362                return 0;
 363        }
 364
 365        ptn = chip->pdata->patterns + (mode - 1);
 366        if (!ptn || _is_pc_overflow(ptn)) {
 367                dev_err(&chip->cl->dev, "invalid pattern data\n");
 368                return -EINVAL;
 369        }
 370
 371        lp5562_stop_engine(chip);
 372
 373        /* Set LED map as RGB */
 374        lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_RGB);
 375
 376        /* Load engines */
 377        for (i = LP55XX_ENGINE_1; i <= LP55XX_ENGINE_3; i++) {
 378                chip->engine_idx = i;
 379                lp5562_load_engine(chip);
 380        }
 381
 382        /* Clear program registers */
 383        lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG1, 0);
 384        lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG1 + 1, 0);
 385        lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG2, 0);
 386        lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG2 + 1, 0);
 387        lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG3, 0);
 388        lp55xx_write(chip, LP5562_REG_PROG_MEM_ENG3 + 1, 0);
 389
 390        /* Program engines */
 391        lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG1,
 392                                ptn->r, ptn->size_r);
 393        lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG2,
 394                                ptn->g, ptn->size_g);
 395        lp5562_write_program_memory(chip, LP5562_REG_PROG_MEM_ENG3,
 396                                ptn->b, ptn->size_b);
 397
 398        /* Run engines */
 399        lp5562_run_engine(chip, true);
 400
 401        return 0;
 402}
 403
 404static ssize_t lp5562_store_pattern(struct device *dev,
 405                                struct device_attribute *attr,
 406                                const char *buf, size_t len)
 407{
 408        struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
 409        struct lp55xx_chip *chip = led->chip;
 410        struct lp55xx_predef_pattern *ptn = chip->pdata->patterns;
 411        int num_patterns = chip->pdata->num_patterns;
 412        unsigned long mode;
 413        int ret;
 414
 415        ret = kstrtoul(buf, 0, &mode);
 416        if (ret)
 417                return ret;
 418
 419        if (mode > num_patterns || !ptn)
 420                return -EINVAL;
 421
 422        mutex_lock(&chip->lock);
 423        ret = lp5562_run_predef_led_pattern(chip, mode);
 424        mutex_unlock(&chip->lock);
 425
 426        if (ret)
 427                return ret;
 428
 429        return len;
 430}
 431
 432static ssize_t lp5562_store_engine_mux(struct device *dev,
 433                                     struct device_attribute *attr,
 434                                     const char *buf, size_t len)
 435{
 436        struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
 437        struct lp55xx_chip *chip = led->chip;
 438        u8 mask;
 439        u8 val;
 440
 441        /* LED map
 442         * R ... Engine 1 (fixed)
 443         * G ... Engine 2 (fixed)
 444         * B ... Engine 3 (fixed)
 445         * W ... Engine 1 or 2 or 3
 446         */
 447
 448        if (sysfs_streq(buf, "RGB")) {
 449                mask = LP5562_ENG_FOR_RGB_M;
 450                val = LP5562_ENG_SEL_RGB;
 451        } else if (sysfs_streq(buf, "W")) {
 452                enum lp55xx_engine_index idx = chip->engine_idx;
 453
 454                mask = LP5562_ENG_FOR_W_M;
 455                switch (idx) {
 456                case LP55XX_ENGINE_1:
 457                        val = LP5562_ENG1_FOR_W;
 458                        break;
 459                case LP55XX_ENGINE_2:
 460                        val = LP5562_ENG2_FOR_W;
 461                        break;
 462                case LP55XX_ENGINE_3:
 463                        val = LP5562_ENG3_FOR_W;
 464                        break;
 465                default:
 466                        return -EINVAL;
 467                }
 468
 469        } else {
 470                dev_err(dev, "choose RGB or W\n");
 471                return -EINVAL;
 472        }
 473
 474        mutex_lock(&chip->lock);
 475        lp55xx_update_bits(chip, LP5562_REG_ENG_SEL, mask, val);
 476        mutex_unlock(&chip->lock);
 477
 478        return len;
 479}
 480
 481static LP55XX_DEV_ATTR_WO(led_pattern, lp5562_store_pattern);
 482static LP55XX_DEV_ATTR_WO(engine_mux, lp5562_store_engine_mux);
 483
 484static struct attribute *lp5562_attributes[] = {
 485        &dev_attr_led_pattern.attr,
 486        &dev_attr_engine_mux.attr,
 487        NULL,
 488};
 489
 490static const struct attribute_group lp5562_group = {
 491        .attrs = lp5562_attributes,
 492};
 493
 494/* Chip specific configurations */
 495static struct lp55xx_device_config lp5562_cfg = {
 496        .max_channel  = LP5562_MAX_LEDS,
 497        .reset = {
 498                .addr = LP5562_REG_RESET,
 499                .val  = LP5562_RESET,
 500        },
 501        .enable = {
 502                .addr = LP5562_REG_ENABLE,
 503                .val  = LP5562_ENABLE_DEFAULT,
 504        },
 505        .post_init_device   = lp5562_post_init_device,
 506        .set_led_current    = lp5562_set_led_current,
 507        .brightness_fn      = lp5562_led_brightness,
 508        .run_engine         = lp5562_run_engine,
 509        .firmware_cb        = lp5562_firmware_loaded,
 510        .dev_attr_group     = &lp5562_group,
 511};
 512
 513static int lp5562_probe(struct i2c_client *client,
 514                        const struct i2c_device_id *id)
 515{
 516        int ret;
 517        struct lp55xx_chip *chip;
 518        struct lp55xx_led *led;
 519        struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
 520        struct device_node *np = client->dev.of_node;
 521
 522        if (!pdata) {
 523                if (np) {
 524                        pdata = lp55xx_of_populate_pdata(&client->dev, np);
 525                        if (IS_ERR(pdata))
 526                                return PTR_ERR(pdata);
 527                } else {
 528                        dev_err(&client->dev, "no platform data\n");
 529                        return -EINVAL;
 530                }
 531        }
 532
 533        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
 534        if (!chip)
 535                return -ENOMEM;
 536
 537        led = devm_kzalloc(&client->dev,
 538                        sizeof(*led) * pdata->num_channels, GFP_KERNEL);
 539        if (!led)
 540                return -ENOMEM;
 541
 542        chip->cl = client;
 543        chip->pdata = pdata;
 544        chip->cfg = &lp5562_cfg;
 545
 546        mutex_init(&chip->lock);
 547
 548        i2c_set_clientdata(client, led);
 549
 550        ret = lp55xx_init_device(chip);
 551        if (ret)
 552                goto err_init;
 553
 554        ret = lp55xx_register_leds(led, chip);
 555        if (ret)
 556                goto err_register_leds;
 557
 558        ret = lp55xx_register_sysfs(chip);
 559        if (ret) {
 560                dev_err(&client->dev, "registering sysfs failed\n");
 561                goto err_register_sysfs;
 562        }
 563
 564        return 0;
 565
 566err_register_sysfs:
 567        lp55xx_unregister_leds(led, chip);
 568err_register_leds:
 569        lp55xx_deinit_device(chip);
 570err_init:
 571        return ret;
 572}
 573
 574static int lp5562_remove(struct i2c_client *client)
 575{
 576        struct lp55xx_led *led = i2c_get_clientdata(client);
 577        struct lp55xx_chip *chip = led->chip;
 578
 579        lp5562_stop_engine(chip);
 580
 581        lp55xx_unregister_sysfs(chip);
 582        lp55xx_unregister_leds(led, chip);
 583        lp55xx_deinit_device(chip);
 584
 585        return 0;
 586}
 587
 588static const struct i2c_device_id lp5562_id[] = {
 589        { "lp5562", 0 },
 590        { }
 591};
 592MODULE_DEVICE_TABLE(i2c, lp5562_id);
 593
 594#ifdef CONFIG_OF
 595static const struct of_device_id of_lp5562_leds_match[] = {
 596        { .compatible = "ti,lp5562", },
 597        {},
 598};
 599
 600MODULE_DEVICE_TABLE(of, of_lp5562_leds_match);
 601#endif
 602
 603static struct i2c_driver lp5562_driver = {
 604        .driver = {
 605                .name   = "lp5562",
 606                .of_match_table = of_match_ptr(of_lp5562_leds_match),
 607        },
 608        .probe          = lp5562_probe,
 609        .remove         = lp5562_remove,
 610        .id_table       = lp5562_id,
 611};
 612
 613module_i2c_driver(lp5562_driver);
 614
 615MODULE_DESCRIPTION("Texas Instruments LP5562 LED Driver");
 616MODULE_AUTHOR("Milo Kim");
 617MODULE_LICENSE("GPL");
 618