linux/drivers/video/backlight/lp855x_bl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * TI LP855x Backlight Driver
   4 *
   5 *                      Copyright (C) 2011 Texas Instruments
   6 */
   7
   8#include <linux/acpi.h>
   9#include <linux/module.h>
  10#include <linux/slab.h>
  11#include <linux/i2c.h>
  12#include <linux/backlight.h>
  13#include <linux/delay.h>
  14#include <linux/err.h>
  15#include <linux/of.h>
  16#include <linux/platform_data/lp855x.h>
  17#include <linux/pwm.h>
  18#include <linux/regulator/consumer.h>
  19
  20/* LP8550/1/2/3/6 Registers */
  21#define LP855X_BRIGHTNESS_CTRL          0x00
  22#define LP855X_DEVICE_CTRL              0x01
  23#define LP855X_EEPROM_START             0xA0
  24#define LP855X_EEPROM_END               0xA7
  25#define LP8556_EPROM_START              0xA0
  26#define LP8556_EPROM_END                0xAF
  27
  28/* LP8555/7 Registers */
  29#define LP8557_BL_CMD                   0x00
  30#define LP8557_BL_MASK                  0x01
  31#define LP8557_BL_ON                    0x01
  32#define LP8557_BL_OFF                   0x00
  33#define LP8557_BRIGHTNESS_CTRL          0x04
  34#define LP8557_CONFIG                   0x10
  35#define LP8555_EPROM_START              0x10
  36#define LP8555_EPROM_END                0x7A
  37#define LP8557_EPROM_START              0x10
  38#define LP8557_EPROM_END                0x1E
  39
  40#define DEFAULT_BL_NAME         "lcd-backlight"
  41#define MAX_BRIGHTNESS          255
  42
  43enum lp855x_brightness_ctrl_mode {
  44        PWM_BASED = 1,
  45        REGISTER_BASED,
  46};
  47
  48struct lp855x;
  49
  50/*
  51 * struct lp855x_device_config
  52 * @pre_init_device: init device function call before updating the brightness
  53 * @reg_brightness: register address for brigthenss control
  54 * @reg_devicectrl: register address for device control
  55 * @post_init_device: late init device function call
  56 */
  57struct lp855x_device_config {
  58        int (*pre_init_device)(struct lp855x *);
  59        u8 reg_brightness;
  60        u8 reg_devicectrl;
  61        int (*post_init_device)(struct lp855x *);
  62};
  63
  64struct lp855x {
  65        const char *chipname;
  66        enum lp855x_chip_id chip_id;
  67        enum lp855x_brightness_ctrl_mode mode;
  68        struct lp855x_device_config *cfg;
  69        struct i2c_client *client;
  70        struct backlight_device *bl;
  71        struct device *dev;
  72        struct lp855x_platform_data *pdata;
  73        struct pwm_device *pwm;
  74        struct regulator *supply;       /* regulator for VDD input */
  75        struct regulator *enable;       /* regulator for EN/VDDIO input */
  76};
  77
  78static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
  79{
  80        return i2c_smbus_write_byte_data(lp->client, reg, data);
  81}
  82
  83static int lp855x_update_bit(struct lp855x *lp, u8 reg, u8 mask, u8 data)
  84{
  85        int ret;
  86        u8 tmp;
  87
  88        ret = i2c_smbus_read_byte_data(lp->client, reg);
  89        if (ret < 0) {
  90                dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
  91                return ret;
  92        }
  93
  94        tmp = (u8)ret;
  95        tmp &= ~mask;
  96        tmp |= data & mask;
  97
  98        return lp855x_write_byte(lp, reg, tmp);
  99}
 100
 101static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
 102{
 103        u8 start, end;
 104
 105        switch (lp->chip_id) {
 106        case LP8550:
 107        case LP8551:
 108        case LP8552:
 109        case LP8553:
 110                start = LP855X_EEPROM_START;
 111                end = LP855X_EEPROM_END;
 112                break;
 113        case LP8556:
 114                start = LP8556_EPROM_START;
 115                end = LP8556_EPROM_END;
 116                break;
 117        case LP8555:
 118                start = LP8555_EPROM_START;
 119                end = LP8555_EPROM_END;
 120                break;
 121        case LP8557:
 122                start = LP8557_EPROM_START;
 123                end = LP8557_EPROM_END;
 124                break;
 125        default:
 126                return false;
 127        }
 128
 129        return addr >= start && addr <= end;
 130}
 131
 132static int lp8557_bl_off(struct lp855x *lp)
 133{
 134        /* BL_ON = 0 before updating EPROM settings */
 135        return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
 136                                LP8557_BL_OFF);
 137}
 138
 139static int lp8557_bl_on(struct lp855x *lp)
 140{
 141        /* BL_ON = 1 after updating EPROM settings */
 142        return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
 143                                LP8557_BL_ON);
 144}
 145
 146static struct lp855x_device_config lp855x_dev_cfg = {
 147        .reg_brightness = LP855X_BRIGHTNESS_CTRL,
 148        .reg_devicectrl = LP855X_DEVICE_CTRL,
 149};
 150
 151static struct lp855x_device_config lp8557_dev_cfg = {
 152        .reg_brightness = LP8557_BRIGHTNESS_CTRL,
 153        .reg_devicectrl = LP8557_CONFIG,
 154        .pre_init_device = lp8557_bl_off,
 155        .post_init_device = lp8557_bl_on,
 156};
 157
 158/*
 159 * Device specific configuration flow
 160 *
 161 *    a) pre_init_device(optional)
 162 *    b) update the brightness register
 163 *    c) update device control register
 164 *    d) update ROM area(optional)
 165 *    e) post_init_device(optional)
 166 *
 167 */
 168static int lp855x_configure(struct lp855x *lp)
 169{
 170        u8 val, addr;
 171        int i, ret;
 172        struct lp855x_platform_data *pd = lp->pdata;
 173
 174        if (lp->cfg->pre_init_device) {
 175                ret = lp->cfg->pre_init_device(lp);
 176                if (ret) {
 177                        dev_err(lp->dev, "pre init device err: %d\n", ret);
 178                        goto err;
 179                }
 180        }
 181
 182        val = pd->initial_brightness;
 183        ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
 184        if (ret)
 185                goto err;
 186
 187        val = pd->device_control;
 188        ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val);
 189        if (ret)
 190                goto err;
 191
 192        if (pd->size_program > 0) {
 193                for (i = 0; i < pd->size_program; i++) {
 194                        addr = pd->rom_data[i].addr;
 195                        val = pd->rom_data[i].val;
 196                        if (!lp855x_is_valid_rom_area(lp, addr))
 197                                continue;
 198
 199                        ret = lp855x_write_byte(lp, addr, val);
 200                        if (ret)
 201                                goto err;
 202                }
 203        }
 204
 205        if (lp->cfg->post_init_device) {
 206                ret = lp->cfg->post_init_device(lp);
 207                if (ret) {
 208                        dev_err(lp->dev, "post init device err: %d\n", ret);
 209                        goto err;
 210                }
 211        }
 212
 213        return 0;
 214
 215err:
 216        return ret;
 217}
 218
 219static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
 220{
 221        unsigned int period = lp->pdata->period_ns;
 222        unsigned int duty = br * period / max_br;
 223        struct pwm_device *pwm;
 224
 225        /* request pwm device with the consumer name */
 226        if (!lp->pwm) {
 227                pwm = devm_pwm_get(lp->dev, lp->chipname);
 228                if (IS_ERR(pwm))
 229                        return;
 230
 231                lp->pwm = pwm;
 232
 233                /*
 234                 * FIXME: pwm_apply_args() should be removed when switching to
 235                 * the atomic PWM API.
 236                 */
 237                pwm_apply_args(pwm);
 238        }
 239
 240        pwm_config(lp->pwm, duty, period);
 241        if (duty)
 242                pwm_enable(lp->pwm);
 243        else
 244                pwm_disable(lp->pwm);
 245}
 246
 247static int lp855x_bl_update_status(struct backlight_device *bl)
 248{
 249        struct lp855x *lp = bl_get_data(bl);
 250        int brightness = bl->props.brightness;
 251
 252        if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
 253                brightness = 0;
 254
 255        if (lp->mode == PWM_BASED)
 256                lp855x_pwm_ctrl(lp, brightness, bl->props.max_brightness);
 257        else if (lp->mode == REGISTER_BASED)
 258                lp855x_write_byte(lp, lp->cfg->reg_brightness, (u8)brightness);
 259
 260        return 0;
 261}
 262
 263static const struct backlight_ops lp855x_bl_ops = {
 264        .options = BL_CORE_SUSPENDRESUME,
 265        .update_status = lp855x_bl_update_status,
 266};
 267
 268static int lp855x_backlight_register(struct lp855x *lp)
 269{
 270        struct backlight_device *bl;
 271        struct backlight_properties props;
 272        struct lp855x_platform_data *pdata = lp->pdata;
 273        const char *name = pdata->name ? : DEFAULT_BL_NAME;
 274
 275        memset(&props, 0, sizeof(props));
 276        props.type = BACKLIGHT_PLATFORM;
 277        props.max_brightness = MAX_BRIGHTNESS;
 278
 279        if (pdata->initial_brightness > props.max_brightness)
 280                pdata->initial_brightness = props.max_brightness;
 281
 282        props.brightness = pdata->initial_brightness;
 283
 284        bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp,
 285                                       &lp855x_bl_ops, &props);
 286        if (IS_ERR(bl))
 287                return PTR_ERR(bl);
 288
 289        lp->bl = bl;
 290
 291        return 0;
 292}
 293
 294static ssize_t lp855x_get_chip_id(struct device *dev,
 295                                struct device_attribute *attr, char *buf)
 296{
 297        struct lp855x *lp = dev_get_drvdata(dev);
 298
 299        return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
 300}
 301
 302static ssize_t lp855x_get_bl_ctl_mode(struct device *dev,
 303                                     struct device_attribute *attr, char *buf)
 304{
 305        struct lp855x *lp = dev_get_drvdata(dev);
 306        char *strmode = NULL;
 307
 308        if (lp->mode == PWM_BASED)
 309                strmode = "pwm based";
 310        else if (lp->mode == REGISTER_BASED)
 311                strmode = "register based";
 312
 313        return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
 314}
 315
 316static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
 317static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL);
 318
 319static struct attribute *lp855x_attributes[] = {
 320        &dev_attr_chip_id.attr,
 321        &dev_attr_bl_ctl_mode.attr,
 322        NULL,
 323};
 324
 325static const struct attribute_group lp855x_attr_group = {
 326        .attrs = lp855x_attributes,
 327};
 328
 329#ifdef CONFIG_OF
 330static int lp855x_parse_dt(struct lp855x *lp)
 331{
 332        struct device *dev = lp->dev;
 333        struct device_node *node = dev->of_node;
 334        struct lp855x_platform_data *pdata = lp->pdata;
 335        int rom_length;
 336
 337        if (!node) {
 338                dev_err(dev, "no platform data\n");
 339                return -EINVAL;
 340        }
 341
 342        of_property_read_string(node, "bl-name", &pdata->name);
 343        of_property_read_u8(node, "dev-ctrl", &pdata->device_control);
 344        of_property_read_u8(node, "init-brt", &pdata->initial_brightness);
 345        of_property_read_u32(node, "pwm-period", &pdata->period_ns);
 346
 347        /* Fill ROM platform data if defined */
 348        rom_length = of_get_child_count(node);
 349        if (rom_length > 0) {
 350                struct lp855x_rom_data *rom;
 351                struct device_node *child;
 352                int i = 0;
 353
 354                rom = devm_kcalloc(dev, rom_length, sizeof(*rom), GFP_KERNEL);
 355                if (!rom)
 356                        return -ENOMEM;
 357
 358                for_each_child_of_node(node, child) {
 359                        of_property_read_u8(child, "rom-addr", &rom[i].addr);
 360                        of_property_read_u8(child, "rom-val", &rom[i].val);
 361                        i++;
 362                }
 363
 364                pdata->size_program = rom_length;
 365                pdata->rom_data = &rom[0];
 366        }
 367
 368        return 0;
 369}
 370#else
 371static int lp855x_parse_dt(struct lp855x *lp)
 372{
 373        return -EINVAL;
 374}
 375#endif
 376
 377static int lp855x_parse_acpi(struct lp855x *lp)
 378{
 379        int ret;
 380
 381        /*
 382         * On ACPI the device has already been initialized by the firmware
 383         * and is in register mode, so we can read back the settings from
 384         * the registers.
 385         */
 386        ret = i2c_smbus_read_byte_data(lp->client, lp->cfg->reg_brightness);
 387        if (ret < 0)
 388                return ret;
 389
 390        lp->pdata->initial_brightness = ret;
 391
 392        ret = i2c_smbus_read_byte_data(lp->client, lp->cfg->reg_devicectrl);
 393        if (ret < 0)
 394                return ret;
 395
 396        lp->pdata->device_control = ret;
 397        return 0;
 398}
 399
 400static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 401{
 402        const struct acpi_device_id *acpi_id = NULL;
 403        struct device *dev = &cl->dev;
 404        struct lp855x *lp;
 405        int ret;
 406
 407        if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
 408                return -EIO;
 409
 410        lp = devm_kzalloc(dev, sizeof(struct lp855x), GFP_KERNEL);
 411        if (!lp)
 412                return -ENOMEM;
 413
 414        lp->client = cl;
 415        lp->dev = dev;
 416        lp->pdata = dev_get_platdata(dev);
 417
 418        if (id) {
 419                lp->chipname = id->name;
 420                lp->chip_id = id->driver_data;
 421        } else {
 422                acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
 423                if (!acpi_id)
 424                        return -ENODEV;
 425
 426                lp->chipname = acpi_id->id;
 427                lp->chip_id = acpi_id->driver_data;
 428        }
 429
 430        switch (lp->chip_id) {
 431        case LP8550:
 432        case LP8551:
 433        case LP8552:
 434        case LP8553:
 435        case LP8556:
 436                lp->cfg = &lp855x_dev_cfg;
 437                break;
 438        case LP8555:
 439        case LP8557:
 440                lp->cfg = &lp8557_dev_cfg;
 441                break;
 442        default:
 443                return -EINVAL;
 444        }
 445
 446        if (!lp->pdata) {
 447                lp->pdata = devm_kzalloc(dev, sizeof(*lp->pdata), GFP_KERNEL);
 448                if (!lp->pdata)
 449                        return -ENOMEM;
 450
 451                if (id) {
 452                        ret = lp855x_parse_dt(lp);
 453                        if (ret < 0)
 454                                return ret;
 455                } else {
 456                        ret = lp855x_parse_acpi(lp);
 457                        if (ret < 0)
 458                                return ret;
 459                }
 460        }
 461
 462        if (lp->pdata->period_ns > 0)
 463                lp->mode = PWM_BASED;
 464        else
 465                lp->mode = REGISTER_BASED;
 466
 467        lp->supply = devm_regulator_get(dev, "power");
 468        if (IS_ERR(lp->supply)) {
 469                if (PTR_ERR(lp->supply) == -EPROBE_DEFER)
 470                        return -EPROBE_DEFER;
 471                lp->supply = NULL;
 472        }
 473
 474        lp->enable = devm_regulator_get_optional(dev, "enable");
 475        if (IS_ERR(lp->enable)) {
 476                ret = PTR_ERR(lp->enable);
 477                if (ret == -ENODEV) {
 478                        lp->enable = NULL;
 479                } else {
 480                        return dev_err_probe(dev, ret, "getting enable regulator\n");
 481                }
 482        }
 483
 484        if (lp->supply) {
 485                ret = regulator_enable(lp->supply);
 486                if (ret < 0) {
 487                        dev_err(dev, "failed to enable supply: %d\n", ret);
 488                        return ret;
 489                }
 490        }
 491
 492        if (lp->enable) {
 493                ret = regulator_enable(lp->enable);
 494                if (ret < 0) {
 495                        dev_err(dev, "failed to enable vddio: %d\n", ret);
 496                        goto disable_supply;
 497                }
 498
 499                /*
 500                 * LP8555 datasheet says t_RESPONSE (time between VDDIO and
 501                 * I2C) is 1ms.
 502                 */
 503                usleep_range(1000, 2000);
 504        }
 505
 506        i2c_set_clientdata(cl, lp);
 507
 508        ret = lp855x_configure(lp);
 509        if (ret) {
 510                dev_err(dev, "device config err: %d", ret);
 511                goto disable_vddio;
 512        }
 513
 514        ret = lp855x_backlight_register(lp);
 515        if (ret) {
 516                dev_err(dev, "failed to register backlight. err: %d\n", ret);
 517                goto disable_vddio;
 518        }
 519
 520        ret = sysfs_create_group(&dev->kobj, &lp855x_attr_group);
 521        if (ret) {
 522                dev_err(dev, "failed to register sysfs. err: %d\n", ret);
 523                goto disable_vddio;
 524        }
 525
 526        backlight_update_status(lp->bl);
 527
 528        return 0;
 529
 530disable_vddio:
 531        if (lp->enable)
 532                regulator_disable(lp->enable);
 533disable_supply:
 534        if (lp->supply)
 535                regulator_disable(lp->supply);
 536
 537        return ret;
 538}
 539
 540static int lp855x_remove(struct i2c_client *cl)
 541{
 542        struct lp855x *lp = i2c_get_clientdata(cl);
 543
 544        lp->bl->props.brightness = 0;
 545        backlight_update_status(lp->bl);
 546        if (lp->enable)
 547                regulator_disable(lp->enable);
 548        if (lp->supply)
 549                regulator_disable(lp->supply);
 550        sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
 551
 552        return 0;
 553}
 554
 555static const struct of_device_id lp855x_dt_ids[] = {
 556        { .compatible = "ti,lp8550", },
 557        { .compatible = "ti,lp8551", },
 558        { .compatible = "ti,lp8552", },
 559        { .compatible = "ti,lp8553", },
 560        { .compatible = "ti,lp8555", },
 561        { .compatible = "ti,lp8556", },
 562        { .compatible = "ti,lp8557", },
 563        { }
 564};
 565MODULE_DEVICE_TABLE(of, lp855x_dt_ids);
 566
 567static const struct i2c_device_id lp855x_ids[] = {
 568        {"lp8550", LP8550},
 569        {"lp8551", LP8551},
 570        {"lp8552", LP8552},
 571        {"lp8553", LP8553},
 572        {"lp8555", LP8555},
 573        {"lp8556", LP8556},
 574        {"lp8557", LP8557},
 575        { }
 576};
 577MODULE_DEVICE_TABLE(i2c, lp855x_ids);
 578
 579#ifdef CONFIG_ACPI
 580static const struct acpi_device_id lp855x_acpi_match[] = {
 581        /* Xiaomi specific HID used for the LP8556 on the Mi Pad 2 */
 582        { "XMCC0001", LP8556 },
 583        { }
 584};
 585MODULE_DEVICE_TABLE(acpi, lp855x_acpi_match);
 586#endif
 587
 588static struct i2c_driver lp855x_driver = {
 589        .driver = {
 590                   .name = "lp855x",
 591                   .of_match_table = of_match_ptr(lp855x_dt_ids),
 592                   .acpi_match_table = ACPI_PTR(lp855x_acpi_match),
 593                   },
 594        .probe = lp855x_probe,
 595        .remove = lp855x_remove,
 596        .id_table = lp855x_ids,
 597};
 598
 599module_i2c_driver(lp855x_driver);
 600
 601MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
 602MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
 603MODULE_LICENSE("GPL");
 604