linux/drivers/video/backlight/lm3630a_bl.c
<<
>>
Prefs
   1/*
   2* Simple driver for Texas Instruments LM3630A Backlight driver chip
   3* Copyright (C) 2012 Texas Instruments
   4*
   5* This program is free software; you can redistribute it and/or modify
   6* it under the terms of the GNU General Public License version 2 as
   7* published by the Free Software Foundation.
   8*
   9*/
  10#include <linux/module.h>
  11#include <linux/slab.h>
  12#include <linux/i2c.h>
  13#include <linux/backlight.h>
  14#include <linux/err.h>
  15#include <linux/delay.h>
  16#include <linux/uaccess.h>
  17#include <linux/interrupt.h>
  18#include <linux/regmap.h>
  19#include <linux/pwm.h>
  20#include <linux/platform_data/lm3630a_bl.h>
  21
  22#define REG_CTRL        0x00
  23#define REG_BOOST       0x02
  24#define REG_CONFIG      0x01
  25#define REG_BRT_A       0x03
  26#define REG_BRT_B       0x04
  27#define REG_I_A         0x05
  28#define REG_I_B         0x06
  29#define REG_INT_STATUS  0x09
  30#define REG_INT_EN      0x0A
  31#define REG_FAULT       0x0B
  32#define REG_PWM_OUTLOW  0x12
  33#define REG_PWM_OUTHIGH 0x13
  34#define REG_MAX         0x1F
  35
  36#define INT_DEBOUNCE_MSEC       10
  37struct lm3630a_chip {
  38        struct device *dev;
  39        struct delayed_work work;
  40
  41        int irq;
  42        struct workqueue_struct *irqthread;
  43        struct lm3630a_platform_data *pdata;
  44        struct backlight_device *bleda;
  45        struct backlight_device *bledb;
  46        struct regmap *regmap;
  47        struct pwm_device *pwmd;
  48};
  49
  50/* i2c access */
  51static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg)
  52{
  53        int rval;
  54        unsigned int reg_val;
  55
  56        rval = regmap_read(pchip->regmap, reg, &reg_val);
  57        if (rval < 0)
  58                return rval;
  59        return reg_val & 0xFF;
  60}
  61
  62static int lm3630a_write(struct lm3630a_chip *pchip,
  63                         unsigned int reg, unsigned int data)
  64{
  65        return regmap_write(pchip->regmap, reg, data);
  66}
  67
  68static int lm3630a_update(struct lm3630a_chip *pchip,
  69                          unsigned int reg, unsigned int mask,
  70                          unsigned int data)
  71{
  72        return regmap_update_bits(pchip->regmap, reg, mask, data);
  73}
  74
  75/* initialize chip */
  76static int lm3630a_chip_init(struct lm3630a_chip *pchip)
  77{
  78        int rval;
  79        struct lm3630a_platform_data *pdata = pchip->pdata;
  80
  81        usleep_range(1000, 2000);
  82        /* set Filter Strength Register */
  83        rval = lm3630a_write(pchip, 0x50, 0x03);
  84        /* set Cofig. register */
  85        rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl);
  86        /* set boost control */
  87        rval |= lm3630a_write(pchip, REG_BOOST, 0x38);
  88        /* set current A */
  89        rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F);
  90        /* set current B */
  91        rval |= lm3630a_write(pchip, REG_I_B, 0x1F);
  92        /* set control */
  93        rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl);
  94        rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl);
  95        usleep_range(1000, 2000);
  96        /* set brightness A and B */
  97        rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt);
  98        rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt);
  99
 100        if (rval < 0)
 101                dev_err(pchip->dev, "i2c failed to access register\n");
 102        return rval;
 103}
 104
 105/* interrupt handling */
 106static void lm3630a_delayed_func(struct work_struct *work)
 107{
 108        int rval;
 109        struct lm3630a_chip *pchip;
 110
 111        pchip = container_of(work, struct lm3630a_chip, work.work);
 112
 113        rval = lm3630a_read(pchip, REG_INT_STATUS);
 114        if (rval < 0) {
 115                dev_err(pchip->dev,
 116                        "i2c failed to access REG_INT_STATUS Register\n");
 117                return;
 118        }
 119
 120        dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval);
 121}
 122
 123static irqreturn_t lm3630a_isr_func(int irq, void *chip)
 124{
 125        int rval;
 126        struct lm3630a_chip *pchip = chip;
 127        unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);
 128
 129        queue_delayed_work(pchip->irqthread, &pchip->work, delay);
 130
 131        rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
 132        if (rval < 0) {
 133                dev_err(pchip->dev, "i2c failed to access register\n");
 134                return IRQ_NONE;
 135        }
 136        return IRQ_HANDLED;
 137}
 138
 139static int lm3630a_intr_config(struct lm3630a_chip *pchip)
 140{
 141        int rval;
 142
 143        rval = lm3630a_write(pchip, REG_INT_EN, 0x87);
 144        if (rval < 0)
 145                return rval;
 146
 147        INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func);
 148        pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd");
 149        if (!pchip->irqthread) {
 150                dev_err(pchip->dev, "create irq thread fail\n");
 151                return -ENOMEM;
 152        }
 153        if (request_threaded_irq
 154            (pchip->irq, NULL, lm3630a_isr_func,
 155             IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) {
 156                dev_err(pchip->dev, "request threaded irq fail\n");
 157                destroy_workqueue(pchip->irqthread);
 158                return -ENOMEM;
 159        }
 160        return rval;
 161}
 162
 163static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
 164{
 165        unsigned int period = pwm_get_period(pchip->pwmd);
 166        unsigned int duty = br * period / br_max;
 167
 168        pwm_config(pchip->pwmd, duty, period);
 169        if (duty)
 170                pwm_enable(pchip->pwmd);
 171        else
 172                pwm_disable(pchip->pwmd);
 173}
 174
 175/* update and get brightness */
 176static int lm3630a_bank_a_update_status(struct backlight_device *bl)
 177{
 178        int ret;
 179        struct lm3630a_chip *pchip = bl_get_data(bl);
 180        enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
 181
 182        /* pwm control */
 183        if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
 184                lm3630a_pwm_ctrl(pchip, bl->props.brightness,
 185                                 bl->props.max_brightness);
 186                return bl->props.brightness;
 187        }
 188
 189        /* disable sleep */
 190        ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
 191        if (ret < 0)
 192                goto out_i2c_err;
 193        usleep_range(1000, 2000);
 194        /* minimum brightness is 0x04 */
 195        ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness);
 196        if (bl->props.brightness < 0x4)
 197                ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);
 198        else
 199                ret |= lm3630a_update(pchip, REG_CTRL,
 200                                      LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);
 201        if (ret < 0)
 202                goto out_i2c_err;
 203        return bl->props.brightness;
 204
 205out_i2c_err:
 206        dev_err(pchip->dev, "i2c failed to access\n");
 207        return bl->props.brightness;
 208}
 209
 210static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
 211{
 212        int brightness, rval;
 213        struct lm3630a_chip *pchip = bl_get_data(bl);
 214        enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
 215
 216        if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
 217                rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
 218                if (rval < 0)
 219                        goto out_i2c_err;
 220                brightness = (rval & 0x01) << 8;
 221                rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
 222                if (rval < 0)
 223                        goto out_i2c_err;
 224                brightness |= rval;
 225                goto out;
 226        }
 227
 228        /* disable sleep */
 229        rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
 230        if (rval < 0)
 231                goto out_i2c_err;
 232        usleep_range(1000, 2000);
 233        rval = lm3630a_read(pchip, REG_BRT_A);
 234        if (rval < 0)
 235                goto out_i2c_err;
 236        brightness = rval;
 237
 238out:
 239        bl->props.brightness = brightness;
 240        return bl->props.brightness;
 241out_i2c_err:
 242        dev_err(pchip->dev, "i2c failed to access register\n");
 243        return 0;
 244}
 245
 246static const struct backlight_ops lm3630a_bank_a_ops = {
 247        .options = BL_CORE_SUSPENDRESUME,
 248        .update_status = lm3630a_bank_a_update_status,
 249        .get_brightness = lm3630a_bank_a_get_brightness,
 250};
 251
 252/* update and get brightness */
 253static int lm3630a_bank_b_update_status(struct backlight_device *bl)
 254{
 255        int ret;
 256        struct lm3630a_chip *pchip = bl_get_data(bl);
 257        enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
 258
 259        /* pwm control */
 260        if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
 261                lm3630a_pwm_ctrl(pchip, bl->props.brightness,
 262                                 bl->props.max_brightness);
 263                return bl->props.brightness;
 264        }
 265
 266        /* disable sleep */
 267        ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
 268        if (ret < 0)
 269                goto out_i2c_err;
 270        usleep_range(1000, 2000);
 271        /* minimum brightness is 0x04 */
 272        ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness);
 273        if (bl->props.brightness < 0x4)
 274                ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);
 275        else
 276                ret |= lm3630a_update(pchip, REG_CTRL,
 277                                      LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);
 278        if (ret < 0)
 279                goto out_i2c_err;
 280        return bl->props.brightness;
 281
 282out_i2c_err:
 283        dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
 284        return bl->props.brightness;
 285}
 286
 287static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
 288{
 289        int brightness, rval;
 290        struct lm3630a_chip *pchip = bl_get_data(bl);
 291        enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
 292
 293        if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
 294                rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
 295                if (rval < 0)
 296                        goto out_i2c_err;
 297                brightness = (rval & 0x01) << 8;
 298                rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
 299                if (rval < 0)
 300                        goto out_i2c_err;
 301                brightness |= rval;
 302                goto out;
 303        }
 304
 305        /* disable sleep */
 306        rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
 307        if (rval < 0)
 308                goto out_i2c_err;
 309        usleep_range(1000, 2000);
 310        rval = lm3630a_read(pchip, REG_BRT_B);
 311        if (rval < 0)
 312                goto out_i2c_err;
 313        brightness = rval;
 314
 315out:
 316        bl->props.brightness = brightness;
 317        return bl->props.brightness;
 318out_i2c_err:
 319        dev_err(pchip->dev, "i2c failed to access register\n");
 320        return 0;
 321}
 322
 323static const struct backlight_ops lm3630a_bank_b_ops = {
 324        .options = BL_CORE_SUSPENDRESUME,
 325        .update_status = lm3630a_bank_b_update_status,
 326        .get_brightness = lm3630a_bank_b_get_brightness,
 327};
 328
 329static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
 330{
 331        struct backlight_properties props;
 332        struct lm3630a_platform_data *pdata = pchip->pdata;
 333
 334        props.type = BACKLIGHT_RAW;
 335        if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {
 336                props.brightness = pdata->leda_init_brt;
 337                props.max_brightness = pdata->leda_max_brt;
 338                pchip->bleda =
 339                    devm_backlight_device_register(pchip->dev, "lm3630a_leda",
 340                                                   pchip->dev, pchip,
 341                                                   &lm3630a_bank_a_ops, &props);
 342                if (IS_ERR(pchip->bleda))
 343                        return PTR_ERR(pchip->bleda);
 344        }
 345
 346        if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) &&
 347            (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) {
 348                props.brightness = pdata->ledb_init_brt;
 349                props.max_brightness = pdata->ledb_max_brt;
 350                pchip->bledb =
 351                    devm_backlight_device_register(pchip->dev, "lm3630a_ledb",
 352                                                   pchip->dev, pchip,
 353                                                   &lm3630a_bank_b_ops, &props);
 354                if (IS_ERR(pchip->bledb))
 355                        return PTR_ERR(pchip->bledb);
 356        }
 357        return 0;
 358}
 359
 360static const struct regmap_config lm3630a_regmap = {
 361        .reg_bits = 8,
 362        .val_bits = 8,
 363        .max_register = REG_MAX,
 364};
 365
 366static int lm3630a_probe(struct i2c_client *client,
 367                         const struct i2c_device_id *id)
 368{
 369        struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev);
 370        struct lm3630a_chip *pchip;
 371        int rval;
 372
 373        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 374                dev_err(&client->dev, "fail : i2c functionality check\n");
 375                return -EOPNOTSUPP;
 376        }
 377
 378        pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip),
 379                             GFP_KERNEL);
 380        if (!pchip)
 381                return -ENOMEM;
 382        pchip->dev = &client->dev;
 383
 384        pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap);
 385        if (IS_ERR(pchip->regmap)) {
 386                rval = PTR_ERR(pchip->regmap);
 387                dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval);
 388                return rval;
 389        }
 390
 391        i2c_set_clientdata(client, pchip);
 392        if (pdata == NULL) {
 393                pdata = devm_kzalloc(pchip->dev,
 394                                     sizeof(struct lm3630a_platform_data),
 395                                     GFP_KERNEL);
 396                if (pdata == NULL)
 397                        return -ENOMEM;
 398                /* default values */
 399                pdata->leda_ctrl = LM3630A_LEDA_ENABLE;
 400                pdata->ledb_ctrl = LM3630A_LEDB_ENABLE;
 401                pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS;
 402                pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS;
 403                pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS;
 404                pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS;
 405        }
 406        pchip->pdata = pdata;
 407
 408        /* chip initialize */
 409        rval = lm3630a_chip_init(pchip);
 410        if (rval < 0) {
 411                dev_err(&client->dev, "fail : init chip\n");
 412                return rval;
 413        }
 414        /* backlight register */
 415        rval = lm3630a_backlight_register(pchip);
 416        if (rval < 0) {
 417                dev_err(&client->dev, "fail : backlight register.\n");
 418                return rval;
 419        }
 420        /* pwm */
 421        if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {
 422                pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");
 423                if (IS_ERR(pchip->pwmd)) {
 424                        dev_err(&client->dev, "fail : get pwm device\n");
 425                        return PTR_ERR(pchip->pwmd);
 426                }
 427        }
 428        pchip->pwmd->period = pdata->pwm_period;
 429
 430        /* interrupt enable  : irq 0 is not allowed */
 431        pchip->irq = client->irq;
 432        if (pchip->irq) {
 433                rval = lm3630a_intr_config(pchip);
 434                if (rval < 0)
 435                        return rval;
 436        }
 437        dev_info(&client->dev, "LM3630A backlight register OK.\n");
 438        return 0;
 439}
 440
 441static int lm3630a_remove(struct i2c_client *client)
 442{
 443        int rval;
 444        struct lm3630a_chip *pchip = i2c_get_clientdata(client);
 445
 446        rval = lm3630a_write(pchip, REG_BRT_A, 0);
 447        if (rval < 0)
 448                dev_err(pchip->dev, "i2c failed to access register\n");
 449
 450        rval = lm3630a_write(pchip, REG_BRT_B, 0);
 451        if (rval < 0)
 452                dev_err(pchip->dev, "i2c failed to access register\n");
 453
 454        if (pchip->irq) {
 455                free_irq(pchip->irq, pchip);
 456                flush_workqueue(pchip->irqthread);
 457                destroy_workqueue(pchip->irqthread);
 458        }
 459        return 0;
 460}
 461
 462static const struct i2c_device_id lm3630a_id[] = {
 463        {LM3630A_NAME, 0},
 464        {}
 465};
 466
 467MODULE_DEVICE_TABLE(i2c, lm3630a_id);
 468
 469static struct i2c_driver lm3630a_i2c_driver = {
 470        .driver = {
 471                   .name = LM3630A_NAME,
 472                   },
 473        .probe = lm3630a_probe,
 474        .remove = lm3630a_remove,
 475        .id_table = lm3630a_id,
 476};
 477
 478module_i2c_driver(lm3630a_i2c_driver);
 479
 480MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A");
 481MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
 482MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>");
 483MODULE_LICENSE("GPL v2");
 484