linux/drivers/leds/leds-lp5521.c
<<
>>
Prefs
   1/*
   2 * LP5521 LED chip driver.
   3 *
   4 * Copyright (C) 2010 Nokia Corporation
   5 * Copyright (C) 2012 Texas Instruments
   6 *
   7 * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
   8 *          Milo(Woogyom) Kim <milo.kim@ti.com>
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License
  12 * version 2 as published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but
  15 * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  22 * 02110-1301 USA
  23 */
  24
  25#include <linux/delay.h>
  26#include <linux/firmware.h>
  27#include <linux/i2c.h>
  28#include <linux/init.h>
  29#include <linux/leds.h>
  30#include <linux/module.h>
  31#include <linux/mutex.h>
  32#include <linux/platform_data/leds-lp55xx.h>
  33#include <linux/slab.h>
  34
  35#include "leds-lp55xx-common.h"
  36
  37#define LP5521_PROGRAM_LENGTH           32
  38#define LP5521_MAX_LEDS                 3
  39#define LP5521_CMD_DIRECT               0x3F
  40
  41/* Registers */
  42#define LP5521_REG_ENABLE               0x00
  43#define LP5521_REG_OP_MODE              0x01
  44#define LP5521_REG_R_PWM                0x02
  45#define LP5521_REG_G_PWM                0x03
  46#define LP5521_REG_B_PWM                0x04
  47#define LP5521_REG_R_CURRENT            0x05
  48#define LP5521_REG_G_CURRENT            0x06
  49#define LP5521_REG_B_CURRENT            0x07
  50#define LP5521_REG_CONFIG               0x08
  51#define LP5521_REG_STATUS               0x0C
  52#define LP5521_REG_RESET                0x0D
  53#define LP5521_REG_R_PROG_MEM           0x10
  54#define LP5521_REG_G_PROG_MEM           0x30
  55#define LP5521_REG_B_PROG_MEM           0x50
  56
  57/* Base register to set LED current */
  58#define LP5521_REG_LED_CURRENT_BASE     LP5521_REG_R_CURRENT
  59/* Base register to set the brightness */
  60#define LP5521_REG_LED_PWM_BASE         LP5521_REG_R_PWM
  61
  62/* Bits in ENABLE register */
  63#define LP5521_MASTER_ENABLE            0x40    /* Chip master enable */
  64#define LP5521_LOGARITHMIC_PWM          0x80    /* Logarithmic PWM adjustment */
  65#define LP5521_EXEC_RUN                 0x2A
  66#define LP5521_ENABLE_DEFAULT   \
  67        (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM)
  68#define LP5521_ENABLE_RUN_PROGRAM       \
  69        (LP5521_ENABLE_DEFAULT | LP5521_EXEC_RUN)
  70
  71/* CONFIG register */
  72#define LP5521_PWM_HF                   0x40    /* PWM: 0 = 256Hz, 1 = 558Hz */
  73#define LP5521_PWRSAVE_EN               0x20    /* 1 = Power save mode */
  74#define LP5521_CP_MODE_OFF              0       /* Charge pump (CP) off */
  75#define LP5521_CP_MODE_BYPASS           8       /* CP forced to bypass mode */
  76#define LP5521_CP_MODE_1X5              0x10    /* CP forced to 1.5x mode */
  77#define LP5521_CP_MODE_AUTO             0x18    /* Automatic mode selection */
  78#define LP5521_R_TO_BATT                0x04    /* R out: 0 = CP, 1 = Vbat */
  79#define LP5521_CLK_INT                  0x01    /* Internal clock */
  80#define LP5521_DEFAULT_CFG              \
  81        (LP5521_PWM_HF | LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO)
  82
  83/* Status */
  84#define LP5521_EXT_CLK_USED             0x08
  85
  86/* default R channel current register value */
  87#define LP5521_REG_R_CURR_DEFAULT       0xAF
  88
  89/* Reset register value */
  90#define LP5521_RESET                    0xFF
  91
  92/* Program Memory Operations */
  93#define LP5521_MODE_R_M                 0x30    /* Operation Mode Register */
  94#define LP5521_MODE_G_M                 0x0C
  95#define LP5521_MODE_B_M                 0x03
  96#define LP5521_LOAD_R                   0x10
  97#define LP5521_LOAD_G                   0x04
  98#define LP5521_LOAD_B                   0x01
  99
 100#define LP5521_R_IS_LOADING(mode)       \
 101        ((mode & LP5521_MODE_R_M) == LP5521_LOAD_R)
 102#define LP5521_G_IS_LOADING(mode)       \
 103        ((mode & LP5521_MODE_G_M) == LP5521_LOAD_G)
 104#define LP5521_B_IS_LOADING(mode)       \
 105        ((mode & LP5521_MODE_B_M) == LP5521_LOAD_B)
 106
 107#define LP5521_EXEC_R_M                 0x30    /* Enable Register */
 108#define LP5521_EXEC_G_M                 0x0C
 109#define LP5521_EXEC_B_M                 0x03
 110#define LP5521_EXEC_M                   0x3F
 111#define LP5521_RUN_R                    0x20
 112#define LP5521_RUN_G                    0x08
 113#define LP5521_RUN_B                    0x02
 114
 115static inline void lp5521_wait_opmode_done(void)
 116{
 117        /* operation mode change needs to be longer than 153 us */
 118        usleep_range(200, 300);
 119}
 120
 121static inline void lp5521_wait_enable_done(void)
 122{
 123        /* it takes more 488 us to update ENABLE register */
 124        usleep_range(500, 600);
 125}
 126
 127static void lp5521_set_led_current(struct lp55xx_led *led, u8 led_current)
 128{
 129        led->led_current = led_current;
 130        lp55xx_write(led->chip, LP5521_REG_LED_CURRENT_BASE + led->chan_nr,
 131                led_current);
 132}
 133
 134static void lp5521_load_engine(struct lp55xx_chip *chip)
 135{
 136        enum lp55xx_engine_index idx = chip->engine_idx;
 137        u8 mask[] = {
 138                [LP55XX_ENGINE_1] = LP5521_MODE_R_M,
 139                [LP55XX_ENGINE_2] = LP5521_MODE_G_M,
 140                [LP55XX_ENGINE_3] = LP5521_MODE_B_M,
 141        };
 142
 143        u8 val[] = {
 144                [LP55XX_ENGINE_1] = LP5521_LOAD_R,
 145                [LP55XX_ENGINE_2] = LP5521_LOAD_G,
 146                [LP55XX_ENGINE_3] = LP5521_LOAD_B,
 147        };
 148
 149        lp55xx_update_bits(chip, LP5521_REG_OP_MODE, mask[idx], val[idx]);
 150
 151        lp5521_wait_opmode_done();
 152}
 153
 154static void lp5521_stop_engine(struct lp55xx_chip *chip)
 155{
 156        lp55xx_write(chip, LP5521_REG_OP_MODE, 0);
 157        lp5521_wait_opmode_done();
 158}
 159
 160static void lp5521_run_engine(struct lp55xx_chip *chip, bool start)
 161{
 162        int ret;
 163        u8 mode;
 164        u8 exec;
 165
 166        /* stop engine */
 167        if (!start) {
 168                lp5521_stop_engine(chip);
 169                lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
 170                lp5521_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, LP5521_REG_OP_MODE, &mode);
 180        if (ret)
 181                return;
 182
 183        ret = lp55xx_read(chip, LP5521_REG_ENABLE, &exec);
 184        if (ret)
 185                return;
 186
 187        /* change operation mode to RUN only when each engine is loading */
 188        if (LP5521_R_IS_LOADING(mode)) {
 189                mode = (mode & ~LP5521_MODE_R_M) | LP5521_RUN_R;
 190                exec = (exec & ~LP5521_EXEC_R_M) | LP5521_RUN_R;
 191        }
 192
 193        if (LP5521_G_IS_LOADING(mode)) {
 194                mode = (mode & ~LP5521_MODE_G_M) | LP5521_RUN_G;
 195                exec = (exec & ~LP5521_EXEC_G_M) | LP5521_RUN_G;
 196        }
 197
 198        if (LP5521_B_IS_LOADING(mode)) {
 199                mode = (mode & ~LP5521_MODE_B_M) | LP5521_RUN_B;
 200                exec = (exec & ~LP5521_EXEC_B_M) | LP5521_RUN_B;
 201        }
 202
 203        lp55xx_write(chip, LP5521_REG_OP_MODE, mode);
 204        lp5521_wait_opmode_done();
 205
 206        lp55xx_update_bits(chip, LP5521_REG_ENABLE, LP5521_EXEC_M, exec);
 207        lp5521_wait_enable_done();
 208}
 209
 210static int lp5521_update_program_memory(struct lp55xx_chip *chip,
 211                                        const u8 *data, size_t size)
 212{
 213        enum lp55xx_engine_index idx = chip->engine_idx;
 214        u8 pattern[LP5521_PROGRAM_LENGTH] = {0};
 215        u8 addr[] = {
 216                [LP55XX_ENGINE_1] = LP5521_REG_R_PROG_MEM,
 217                [LP55XX_ENGINE_2] = LP5521_REG_G_PROG_MEM,
 218                [LP55XX_ENGINE_3] = LP5521_REG_B_PROG_MEM,
 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 < LP5521_PROGRAM_LENGTH; i++)
 230                lp55xx_write(chip, addr[idx] + i, 0);
 231
 232        i = 0;
 233        while ((offset < size - 1) && (i < LP5521_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 lp5521_firmware_loaded(struct lp55xx_chip *chip)
 264{
 265        const struct firmware *fw = chip->fw;
 266
 267        if (fw->size > LP5521_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        lp5521_load_engine(chip);
 280        lp5521_update_program_memory(chip, fw->data, fw->size);
 281}
 282
 283static int lp5521_post_init_device(struct lp55xx_chip *chip)
 284{
 285        int ret;
 286        u8 val;
 287
 288        /*
 289         * Make sure that the chip is reset by reading back the r channel
 290         * current reg. This is dummy read is required on some platforms -
 291         * otherwise further access to the R G B channels in the
 292         * LP5521_REG_ENABLE register will not have any effect - strange!
 293         */
 294        ret = lp55xx_read(chip, LP5521_REG_R_CURRENT, &val);
 295        if (ret) {
 296                dev_err(&chip->cl->dev, "error in resetting chip\n");
 297                return ret;
 298        }
 299        if (val != LP5521_REG_R_CURR_DEFAULT) {
 300                dev_err(&chip->cl->dev,
 301                        "unexpected data in register (expected 0x%x got 0x%x)\n",
 302                        LP5521_REG_R_CURR_DEFAULT, val);
 303                ret = -EINVAL;
 304                return ret;
 305        }
 306        usleep_range(10000, 20000);
 307
 308        /* Set all PWMs to direct control mode */
 309        ret = lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
 310
 311        /* Update configuration for the clock setting */
 312        val = LP5521_DEFAULT_CFG;
 313        if (!lp55xx_is_extclk_used(chip))
 314                val |= LP5521_CLK_INT;
 315
 316        ret = lp55xx_write(chip, LP5521_REG_CONFIG, val);
 317        if (ret)
 318                return ret;
 319
 320        /* Initialize all channels PWM to zero -> leds off */
 321        lp55xx_write(chip, LP5521_REG_R_PWM, 0);
 322        lp55xx_write(chip, LP5521_REG_G_PWM, 0);
 323        lp55xx_write(chip, LP5521_REG_B_PWM, 0);
 324
 325        /* Set engines are set to run state when OP_MODE enables engines */
 326        ret = lp55xx_write(chip, LP5521_REG_ENABLE, LP5521_ENABLE_RUN_PROGRAM);
 327        if (ret)
 328                return ret;
 329
 330        lp5521_wait_enable_done();
 331
 332        return 0;
 333}
 334
 335static int lp5521_run_selftest(struct lp55xx_chip *chip, char *buf)
 336{
 337        struct lp55xx_platform_data *pdata = chip->pdata;
 338        int ret;
 339        u8 status;
 340
 341        ret = lp55xx_read(chip, LP5521_REG_STATUS, &status);
 342        if (ret < 0)
 343                return ret;
 344
 345        if (pdata->clock_mode != LP55XX_CLOCK_EXT)
 346                return 0;
 347
 348        /* Check that ext clock is really in use if requested */
 349        if  ((status & LP5521_EXT_CLK_USED) == 0)
 350                return -EIO;
 351
 352        return 0;
 353}
 354
 355static void lp5521_led_brightness_work(struct work_struct *work)
 356{
 357        struct lp55xx_led *led = container_of(work, struct lp55xx_led,
 358                                              brightness_work);
 359        struct lp55xx_chip *chip = led->chip;
 360
 361        mutex_lock(&chip->lock);
 362        lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
 363                led->brightness);
 364        mutex_unlock(&chip->lock);
 365}
 366
 367static ssize_t lp5521_selftest(struct device *dev,
 368                               struct device_attribute *attr,
 369                               char *buf)
 370{
 371        struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
 372        struct lp55xx_chip *chip = led->chip;
 373        int ret;
 374
 375        mutex_lock(&chip->lock);
 376        ret = lp5521_run_selftest(chip, buf);
 377        mutex_unlock(&chip->lock);
 378
 379        return scnprintf(buf, PAGE_SIZE, "%s\n", ret ? "FAIL" : "OK");
 380}
 381
 382/* device attributes */
 383static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
 384
 385static struct attribute *lp5521_attributes[] = {
 386        &dev_attr_selftest.attr,
 387        NULL
 388};
 389
 390static const struct attribute_group lp5521_group = {
 391        .attrs = lp5521_attributes,
 392};
 393
 394/* Chip specific configurations */
 395static struct lp55xx_device_config lp5521_cfg = {
 396        .reset = {
 397                .addr = LP5521_REG_RESET,
 398                .val  = LP5521_RESET,
 399        },
 400        .enable = {
 401                .addr = LP5521_REG_ENABLE,
 402                .val  = LP5521_ENABLE_DEFAULT,
 403        },
 404        .max_channel  = LP5521_MAX_LEDS,
 405        .post_init_device   = lp5521_post_init_device,
 406        .brightness_work_fn = lp5521_led_brightness_work,
 407        .set_led_current    = lp5521_set_led_current,
 408        .firmware_cb        = lp5521_firmware_loaded,
 409        .run_engine         = lp5521_run_engine,
 410        .dev_attr_group     = &lp5521_group,
 411};
 412
 413static int lp5521_probe(struct i2c_client *client,
 414                        const struct i2c_device_id *id)
 415{
 416        int ret;
 417        struct lp55xx_chip *chip;
 418        struct lp55xx_led *led;
 419        struct lp55xx_platform_data *pdata = client->dev.platform_data;
 420
 421        if (!pdata) {
 422                dev_err(&client->dev, "no platform data\n");
 423                return -EINVAL;
 424        }
 425
 426        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
 427        if (!chip)
 428                return -ENOMEM;
 429
 430        led = devm_kzalloc(&client->dev,
 431                        sizeof(*led) * pdata->num_channels, GFP_KERNEL);
 432        if (!led)
 433                return -ENOMEM;
 434
 435        chip->cl = client;
 436        chip->pdata = pdata;
 437        chip->cfg = &lp5521_cfg;
 438
 439        mutex_init(&chip->lock);
 440
 441        i2c_set_clientdata(client, led);
 442
 443        ret = lp55xx_init_device(chip);
 444        if (ret)
 445                goto err_init;
 446
 447        dev_info(&client->dev, "%s programmable led chip found\n", id->name);
 448
 449        ret = lp55xx_register_leds(led, chip);
 450        if (ret)
 451                goto err_register_leds;
 452
 453        ret = lp55xx_register_sysfs(chip);
 454        if (ret) {
 455                dev_err(&client->dev, "registering sysfs failed\n");
 456                goto err_register_sysfs;
 457        }
 458
 459        return 0;
 460
 461err_register_sysfs:
 462        lp55xx_unregister_leds(led, chip);
 463err_register_leds:
 464        lp55xx_deinit_device(chip);
 465err_init:
 466        return ret;
 467}
 468
 469static int lp5521_remove(struct i2c_client *client)
 470{
 471        struct lp55xx_led *led = i2c_get_clientdata(client);
 472        struct lp55xx_chip *chip = led->chip;
 473
 474        lp5521_stop_engine(chip);
 475        lp55xx_unregister_sysfs(chip);
 476        lp55xx_unregister_leds(led, chip);
 477        lp55xx_deinit_device(chip);
 478
 479        return 0;
 480}
 481
 482static const struct i2c_device_id lp5521_id[] = {
 483        { "lp5521", 0 }, /* Three channel chip */
 484        { }
 485};
 486MODULE_DEVICE_TABLE(i2c, lp5521_id);
 487
 488static struct i2c_driver lp5521_driver = {
 489        .driver = {
 490                .name   = "lp5521",
 491        },
 492        .probe          = lp5521_probe,
 493        .remove         = lp5521_remove,
 494        .id_table       = lp5521_id,
 495};
 496
 497module_i2c_driver(lp5521_driver);
 498
 499MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo");
 500MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
 501MODULE_DESCRIPTION("LP5521 LED engine");
 502MODULE_LICENSE("GPL v2");
 503
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.