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