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/init.h>
  17#include <linux/leds.h>
  18#include <linux/module.h>
  19#include <linux/mutex.h>
  20#include <linux/of.h>
  21#include <linux/platform_data/leds-lp55xx.h>
  22#include <linux/slab.h>
  23
  24#include "leds-lp55xx-common.h"
  25
  26#define LP5562_PROGRAM_LENGTH           32
  27#define LP5562_MAX_LEDS                 4
  28
  29/* ENABLE Register 00h */
  30#define LP5562_REG_ENABLE               0x00
  31#define LP5562_EXEC_ENG1_M              0x30
  32#define LP5562_EXEC_ENG2_M              0x0C
  33#define LP5562_EXEC_ENG3_M              0x03
  34#define LP5562_EXEC_M                   0x3F
  35#define LP5562_MASTER_ENABLE            0x40    /* Chip master enable */
  36#define LP5562_LOGARITHMIC_PWM          0x80    /* Logarithmic PWM adjustment */
  37#define LP5562_EXEC_RUN                 0x2A
  38#define LP5562_ENABLE_DEFAULT   \
  39        (LP5562_MASTER_ENABLE | LP5562_LOGARITHMIC_PWM)
  40#define LP5562_ENABLE_RUN_PROGRAM       \
  41        (LP5562_ENABLE_DEFAULT | LP5562_EXEC_RUN)
  42
  43/* OPMODE Register 01h */
  44#define LP5562_REG_OP_MODE              0x01
  45#define LP5562_MODE_ENG1_M              0x30
  46#define LP5562_MODE_ENG2_M              0x0C
  47#define LP5562_MODE_ENG3_M              0x03
  48#define LP5562_LOAD_ENG1                0x10
  49#define LP5562_LOAD_ENG2                0x04
  50#define LP5562_LOAD_ENG3                0x01
  51#define LP5562_RUN_ENG1                 0x20
  52#define LP5562_RUN_ENG2                 0x08
  53#define LP5562_RUN_ENG3                 0x02
  54#define LP5562_ENG1_IS_LOADING(mode)    \
  55        ((mode & LP5562_MODE_ENG1_M) == LP5562_LOAD_ENG1)
  56#define LP5562_ENG2_IS_LOADING(mode)    \
  57        ((mode & LP5562_MODE_ENG2_M) == LP5562_LOAD_ENG2)
  58#define LP5562_ENG3_IS_LOADING(mode)    \
  59        ((mode & LP5562_MODE_ENG3_M) == LP5562_LOAD_ENG3)
  60
  61/* BRIGHTNESS Registers */
  62#define LP5562_REG_R_PWM                0x04
  63#define LP5562_REG_G_PWM                0x03
  64#define LP5562_REG_B_PWM                0x02
  65#define LP5562_REG_W_PWM                0x0E
  66
  67/* CURRENT Registers */
  68#define LP5562_REG_R_CURRENT            0x07
  69#define LP5562_REG_G_CURRENT            0x06
  70#define LP5562_REG_B_CURRENT            0x05
  71#define LP5562_REG_W_CURRENT            0x0F
  72
  73/* CONFIG Register 08h */
  74#define LP5562_REG_CONFIG               0x08
  75#define LP5562_PWM_HF                   0x40
  76#define LP5562_PWRSAVE_EN               0x20
  77#define LP5562_CLK_INT                  0x01    /* Internal clock */
  78#define LP5562_DEFAULT_CFG              (LP5562_PWM_HF | LP5562_PWRSAVE_EN)
  79
  80/* RESET Register 0Dh */
  81#define LP5562_REG_RESET                0x0D
  82#define LP5562_RESET                    0xFF
  83
  84/* PROGRAM ENGINE Registers */
  85#define LP5562_REG_PROG_MEM_ENG1        0x10
  86#define LP5562_REG_PROG_MEM_ENG2        0x30
  87#define LP5562_REG_PROG_MEM_ENG3        0x50
  88
  89/* LEDMAP Register 70h */
  90#define LP5562_REG_ENG_SEL              0x70
  91#define LP5562_ENG_SEL_PWM              0
  92#define LP5562_ENG_FOR_RGB_M            0x3F
  93#define LP5562_ENG_SEL_RGB              0x1B    /* R:ENG1, G:ENG2, B:ENG3 */
  94#define LP5562_ENG_FOR_W_M              0xC0
  95#define LP5562_ENG1_FOR_W               0x40    /* W:ENG1 */
  96#define LP5562_ENG2_FOR_W               0x80    /* W:ENG2 */
  97#define LP5562_ENG3_FOR_W               0xC0    /* W:ENG3 */
  98
  99/* Program Commands */
 100#define LP5562_CMD_DISABLE              0x00
 101#define LP5562_CMD_LOAD                 0x15
 102#define LP5562_CMD_RUN                  0x2A
 103#define LP5562_CMD_DIRECT               0x3F
 104#define LP5562_PATTERN_OFF              0
 105
 106static inline void lp5562_wait_opmode_done(void)
 107{
 108        /* operation mode change needs to be longer than 153 us */
 109        usleep_range(200, 300);
 110}
 111
 112static inline void lp5562_wait_enable_done(void)
 113{
 114        /* it takes more 488 us to update ENABLE register */
 115        usleep_range(500, 600);
 116}
 117
 118static void lp5562_set_led_current(struct lp55xx_led *led, u8 led_current)
 119{
 120        u8 addr[] = {
 121                LP5562_REG_R_CURRENT,
 122                LP5562_REG_G_CURRENT,
 123                LP5562_REG_B_CURRENT,
 124                LP5562_REG_W_CURRENT,
 125        };
 126
 127        led->led_current = led_current;
 128        lp55xx_write(led->chip, addr[led->chan_nr], led_current);
 129}
 130
 131static void lp5562_load_engine(struct lp55xx_chip *chip)
 132{
 133        enum lp55xx_engine_index idx = chip->engine_idx;
 134        u8 mask[] = {
 135                [LP55XX_ENGINE_1] = LP5562_MODE_ENG1_M,
 136                [LP55XX_ENGINE_2] = LP5562_MODE_ENG2_M,
 137                [LP55XX_ENGINE_3] = LP5562_MODE_ENG3_M,
 138        };
 139
 140        u8 val[] = {
 141                [LP55XX_ENGINE_1] = LP5562_LOAD_ENG1,
 142                [LP55XX_ENGINE_2] = LP5562_LOAD_ENG2,
 143                [LP55XX_ENGINE_3] = LP5562_LOAD_ENG3,
 144        };
 145
 146        lp55xx_update_bits(chip, LP5562_REG_OP_MODE, mask[idx], val[idx]);
 147
 148        lp5562_wait_opmode_done();
 149}
 150
 151static void lp5562_stop_engine(struct lp55xx_chip *chip)
 152{
 153        lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DISABLE);
 154        lp5562_wait_opmode_done();
 155}
 156
 157static void lp5562_run_engine(struct lp55xx_chip *chip, bool start)
 158{
 159        int ret;
 160        u8 mode;
 161        u8 exec;
 162
 163        /* stop engine */
 164        if (!start) {
 165                lp55xx_write(chip, LP5562_REG_ENABLE, LP5562_ENABLE_DEFAULT);
 166                lp5562_wait_enable_done();
 167                lp5562_stop_engine(chip);
 168                lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
 169                lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
 170                lp5562_wait_opmode_done();
 171                return;
 172        }
 173
 174        /*
 175         * To run the engine,
 176         * operation mode and enable register should updated at the same time
 177         */
 178
 179        ret = lp55xx_read(chip, LP5562_REG_OP_MODE, &mode);
 180        if (ret)
 181                return;
 182
 183        ret = lp55xx_read(chip, LP5562_REG_ENABLE, &exec);
 184        if (ret)
 185                return;
 186
 187        /* change operation mode to RUN only when each engine is loading */
 188        if (LP5562_ENG1_IS_LOADING(mode)) {
 189                mode = (mode & ~LP5562_MODE_ENG1_M) | LP5562_RUN_ENG1;
 190                exec = (exec & ~LP5562_EXEC_ENG1_M) | LP5562_RUN_ENG1;
 191        }
 192
 193        if (LP5562_ENG2_IS_LOADING(mode)) {
 194                mode = (mode & ~LP5562_MODE_ENG2_M) | LP5562_RUN_ENG2;
 195                exec = (exec & ~LP5562_EXEC_ENG2_M) | LP5562_RUN_ENG2;
 196        }
 197
 198        if (LP5562_ENG3_IS_LOADING(mode)) {
 199                mode = (mode & ~LP5562_MODE_ENG3_M) | LP5562_RUN_ENG3;
 200                exec = (exec & ~LP5562_EXEC_ENG3_M) | LP5562_RUN_ENG3;
 201        }
 202
 203        lp55xx_write(chip, LP5562_REG_OP_MODE, mode);
 204        lp5562_wait_opmode_done();
 205
 206        lp55xx_update_bits(chip, LP5562_REG_ENABLE, LP5562_EXEC_M, exec);
 207        lp5562_wait_enable_done();
 208}
 209
 210static int lp5562_update_firmware(struct lp55xx_chip *chip,
 211                                        const u8 *data, size_t size)
 212{
 213        enum lp55xx_engine_index idx = chip->engine_idx;
 214        u8 pattern[LP5562_PROGRAM_LENGTH] = {0};
 215        u8 addr[] = {
 216                [LP55XX_ENGINE_1] = LP5562_REG_PROG_MEM_ENG1,
 217                [LP55XX_ENGINE_2] = LP5562_REG_PROG_MEM_ENG2,
 218                [LP55XX_ENGINE_3] = LP5562_REG_PROG_MEM_ENG3,
 219        };
 220        unsigned cmd;
 221        char c[3];
 222        int program_size;
 223        int nrchars;
 224        int offset = 0;
 225        int ret;
 226        int i;
 227
 228        /* clear program memory before updating */
 229        for (i = 0; i < LP5562_PROGRAM_LENGTH; i++)
 230                lp55xx_write(chip, addr[idx] + i, 0);
 231
 232        i = 0;
 233        while ((offset < size - 1) && (i < LP5562_PROGRAM_LENGTH)) {
 234                /* separate sscanfs because length is working only for %s */
 235                ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
 236                if (ret != 1)
 237                        goto err;
 238
 239                ret = sscanf(c, "%2x", &cmd);
 240                if (ret != 1)
 241                        goto err;
 242
 243                pattern[i] = (u8)cmd;
 244                offset += nrchars;
 245                i++;
 246        }
 247
 248        /* Each instruction is 16bit long. Check that length is even */
 249        if (i % 2)
 250                goto err;
 251
 252        program_size = i;
 253        for (i = 0; i < program_size; i++)
 254                lp55xx_write(chip, addr[idx] + i, pattern[i]);
 255
 256        return 0;
 257
 258err:
 259        dev_err(&chip->cl->dev, "wrong pattern format\n");
 260        return -EINVAL;
 261}
 262
 263static void lp5562_firmware_loaded(struct lp55xx_chip *chip)
 264{
 265        const struct firmware *fw = chip->fw;
 266
 267        if (fw->size > LP5562_PROGRAM_LENGTH) {
 268                dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
 269                        fw->size);
 270                return;
 271        }
 272
 273        /*
 274         * Program momery sequence
 275         *  1) set engine mode to "LOAD"
 276         *  2) write firmware data into program memory
 277         */
 278
 279        lp5562_load_engine(chip);
 280        lp5562_update_firmware(chip, fw->data, fw->size);
 281}
 282
 283static int lp5562_post_init_device(struct lp55xx_chip *chip)
 284{
 285        int ret;
 286        u8 cfg = LP5562_DEFAULT_CFG;
 287
 288        /* Set all PWMs to direct control mode */
 289        ret = lp55xx_write(chip, LP5562_REG_OP_MODE, LP5562_CMD_DIRECT);
 290        if (ret)
 291                return ret;
 292
 293        lp5562_wait_opmode_done();
 294
 295        /* Update configuration for the clock setting */
 296        if (!lp55xx_is_extclk_used(chip))
 297                cfg |= LP5562_CLK_INT;
 298
 299        ret = lp55xx_write(chip, LP5562_REG_CONFIG, cfg);
 300        if (ret)
 301                return ret;
 302
 303        /* Initialize all channels PWM to zero -> leds off */
 304        lp55xx_write(chip, LP5562_REG_R_PWM, 0);
 305        lp55xx_write(chip, LP5562_REG_G_PWM, 0);
 306        lp55xx_write(chip, LP5562_REG_B_PWM, 0);
 307        lp55xx_write(chip, LP5562_REG_W_PWM, 0);
 308
 309        /* Set LED map as register PWM by default */
 310        lp55xx_write(chip, LP5562_REG_ENG_SEL, LP5562_ENG_SEL_PWM);
 311
 312        return 0;
 313}
 314
 315static void lp5562_led_brightness_work(struct work_struct *work)
 316{
 317        struct lp55xx_led *led = container_of(work, struct lp55xx_led,
 318                                              brightness_work);
 319        struct lp55xx_chip *chip = led->chip;
 320        u8 addr[] = {
 321                LP5562_REG_R_PWM,
 322                LP5562_REG_G_PWM,
 323                LP5562_REG_B_PWM,
 324                LP5562_REG_W_PWM,
 325        };
 326
 327        mutex_lock(&chip->lock);
 328        lp55xx_write(chip, addr[led->chan_nr], led->brightness);
 329        mutex_unlock(&chip->lock);
 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_work_fn = lp5562_led_brightness_work,
 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;
 520        struct device_node *np = client->dev.of_node;
 521
 522        if (!dev_get_platdata(&client->dev)) {
 523                if (np) {
 524                        ret = lp55xx_of_populate_pdata(&client->dev, np);
 525                        if (ret < 0)
 526                                return ret;
 527                } else {
 528                        dev_err(&client->dev, "no platform data\n");
 529                        return -EINVAL;
 530                }
 531        }
 532        pdata = dev_get_platdata(&client->dev);
 533
 534        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
 535        if (!chip)
 536                return -ENOMEM;
 537
 538        led = devm_kzalloc(&client->dev,
 539                        sizeof(*led) * pdata->num_channels, GFP_KERNEL);
 540        if (!led)
 541                return -ENOMEM;
 542
 543        chip->cl = client;
 544        chip->pdata = pdata;
 545        chip->cfg = &lp5562_cfg;
 546
 547        mutex_init(&chip->lock);
 548
 549        i2c_set_clientdata(client, led);
 550
 551        ret = lp55xx_init_device(chip);
 552        if (ret)
 553                goto err_init;
 554
 555        ret = lp55xx_register_leds(led, chip);
 556        if (ret)
 557                goto err_register_leds;
 558
 559        ret = lp55xx_register_sysfs(chip);
 560        if (ret) {
 561                dev_err(&client->dev, "registering sysfs failed\n");
 562                goto err_register_sysfs;
 563        }
 564
 565        return 0;
 566
 567err_register_sysfs:
 568        lp55xx_unregister_leds(led, chip);
 569err_register_leds:
 570        lp55xx_deinit_device(chip);
 571err_init:
 572        return ret;
 573}
 574
 575static int lp5562_remove(struct i2c_client *client)
 576{
 577        struct lp55xx_led *led = i2c_get_clientdata(client);
 578        struct lp55xx_chip *chip = led->chip;
 579
 580        lp5562_stop_engine(chip);
 581
 582        lp55xx_unregister_sysfs(chip);
 583        lp55xx_unregister_leds(led, chip);
 584        lp55xx_deinit_device(chip);
 585
 586        return 0;
 587}
 588
 589static const struct i2c_device_id lp5562_id[] = {
 590        { "lp5562", 0 },
 591        { }
 592};
 593MODULE_DEVICE_TABLE(i2c, lp5562_id);
 594
 595#ifdef CONFIG_OF
 596static const struct of_device_id of_lp5562_leds_match[] = {
 597        { .compatible = "ti,lp5562", },
 598        {},
 599};
 600
 601MODULE_DEVICE_TABLE(of, of_lp5562_leds_match);
 602#endif
 603
 604static struct i2c_driver lp5562_driver = {
 605        .driver = {
 606                .name   = "lp5562",
 607                .of_match_table = of_match_ptr(of_lp5562_leds_match),
 608        },
 609        .probe          = lp5562_probe,
 610        .remove         = lp5562_remove,
 611        .id_table       = lp5562_id,
 612};
 613
 614module_i2c_driver(lp5562_driver);
 615
 616MODULE_DESCRIPTION("Texas Instruments LP5562 LED Driver");
 617MODULE_AUTHOR("Milo Kim");
 618MODULE_LICENSE("GPL");
 619