linux/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 InforceComputing
   3 * Author: Vinay Simha BN <simhavcs@gmail.com>
   4 *
   5 * Copyright (C) 2016 Linaro Ltd
   6 * Author: Sumit Semwal <sumit.semwal@linaro.org>
   7 *
   8 * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a
   9 * JDI model LT070ME05000, and its data sheet is at:
  10 * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet
  11 *
  12 * This program is free software; you can redistribute it and/or modify it
  13 * under the terms of the GNU General Public License version 2 as published by
  14 * the Free Software Foundation.
  15 *
  16 * This program is distributed in the hope that it will be useful, but WITHOUT
  17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  18 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  19 * more details.
  20 *
  21 * You should have received a copy of the GNU General Public License along with
  22 * this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24#include <linux/backlight.h>
  25#include <linux/gpio/consumer.h>
  26#include <linux/module.h>
  27#include <linux/of.h>
  28#include <linux/regulator/consumer.h>
  29
  30#include <drm/drmP.h>
  31#include <drm/drm_crtc.h>
  32#include <drm/drm_mipi_dsi.h>
  33#include <drm/drm_panel.h>
  34
  35#include <video/mipi_display.h>
  36
  37static const char * const regulator_names[] = {
  38        "vddp",
  39        "iovcc"
  40};
  41
  42struct jdi_panel {
  43        struct drm_panel base;
  44        struct mipi_dsi_device *dsi;
  45
  46        struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
  47
  48        struct gpio_desc *enable_gpio;
  49        struct gpio_desc *reset_gpio;
  50        struct gpio_desc *dcdc_en_gpio;
  51        struct backlight_device *backlight;
  52
  53        bool prepared;
  54        bool enabled;
  55
  56        const struct drm_display_mode *mode;
  57};
  58
  59static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel)
  60{
  61        return container_of(panel, struct jdi_panel, base);
  62}
  63
  64static int jdi_panel_init(struct jdi_panel *jdi)
  65{
  66        struct mipi_dsi_device *dsi = jdi->dsi;
  67        struct device *dev = &jdi->dsi->dev;
  68        int ret;
  69
  70        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  71
  72        ret = mipi_dsi_dcs_soft_reset(dsi);
  73        if (ret < 0)
  74                return ret;
  75
  76        usleep_range(10000, 20000);
  77
  78        ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
  79        if (ret < 0) {
  80                dev_err(dev, "failed to set pixel format: %d\n", ret);
  81                return ret;
  82        }
  83
  84        ret = mipi_dsi_dcs_set_column_address(dsi, 0, jdi->mode->hdisplay - 1);
  85        if (ret < 0) {
  86                dev_err(dev, "failed to set column address: %d\n", ret);
  87                return ret;
  88        }
  89
  90        ret = mipi_dsi_dcs_set_page_address(dsi, 0, jdi->mode->vdisplay - 1);
  91        if (ret < 0) {
  92                dev_err(dev, "failed to set page address: %d\n", ret);
  93                return ret;
  94        }
  95
  96        /*
  97         * BIT(5) BCTRL = 1 Backlight Control Block On, Brightness registers
  98         *                  are active
  99         * BIT(3) BL = 1    Backlight Control On
 100         * BIT(2) DD = 0    Display Dimming is Off
 101         */
 102        ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
 103                                 (u8[]){ 0x24 }, 1);
 104        if (ret < 0) {
 105                dev_err(dev, "failed to write control display: %d\n", ret);
 106                return ret;
 107        }
 108
 109        /* CABC off */
 110        ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE,
 111                                 (u8[]){ 0x00 }, 1);
 112        if (ret < 0) {
 113                dev_err(dev, "failed to set cabc off: %d\n", ret);
 114                return ret;
 115        }
 116
 117        ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
 118        if (ret < 0) {
 119                dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
 120                return ret;
 121        }
 122
 123        msleep(120);
 124
 125        ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x00}, 2);
 126        if (ret < 0) {
 127                dev_err(dev, "failed to set mcap: %d\n", ret);
 128                return ret;
 129        }
 130
 131        mdelay(10);
 132
 133        /* Interface setting, video mode */
 134        ret = mipi_dsi_generic_write(dsi, (u8[])
 135                                     {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00}, 6);
 136        if (ret < 0) {
 137                dev_err(dev, "failed to set display interface setting: %d\n"
 138                        , ret);
 139                return ret;
 140        }
 141
 142        mdelay(20);
 143
 144        ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x03}, 2);
 145        if (ret < 0) {
 146                dev_err(dev, "failed to set default values for mcap: %d\n"
 147                        , ret);
 148                return ret;
 149        }
 150
 151        return 0;
 152}
 153
 154static int jdi_panel_on(struct jdi_panel *jdi)
 155{
 156        struct mipi_dsi_device *dsi = jdi->dsi;
 157        struct device *dev = &jdi->dsi->dev;
 158        int ret;
 159
 160        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 161
 162        ret = mipi_dsi_dcs_set_display_on(dsi);
 163        if (ret < 0)
 164                dev_err(dev, "failed to set display on: %d\n", ret);
 165
 166        return ret;
 167}
 168
 169static void jdi_panel_off(struct jdi_panel *jdi)
 170{
 171        struct mipi_dsi_device *dsi = jdi->dsi;
 172        struct device *dev = &jdi->dsi->dev;
 173        int ret;
 174
 175        dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 176
 177        ret = mipi_dsi_dcs_set_display_off(dsi);
 178        if (ret < 0)
 179                dev_err(dev, "failed to set display off: %d\n", ret);
 180
 181        ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
 182        if (ret < 0)
 183                dev_err(dev, "failed to enter sleep mode: %d\n", ret);
 184
 185        msleep(100);
 186}
 187
 188static int jdi_panel_disable(struct drm_panel *panel)
 189{
 190        struct jdi_panel *jdi = to_jdi_panel(panel);
 191
 192        if (!jdi->enabled)
 193                return 0;
 194
 195        backlight_disable(jdi->backlight);
 196
 197        jdi->enabled = false;
 198
 199        return 0;
 200}
 201
 202static int jdi_panel_unprepare(struct drm_panel *panel)
 203{
 204        struct jdi_panel *jdi = to_jdi_panel(panel);
 205        struct device *dev = &jdi->dsi->dev;
 206        int ret;
 207
 208        if (!jdi->prepared)
 209                return 0;
 210
 211        jdi_panel_off(jdi);
 212
 213        ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
 214        if (ret < 0)
 215                dev_err(dev, "regulator disable failed, %d\n", ret);
 216
 217        gpiod_set_value(jdi->enable_gpio, 0);
 218
 219        gpiod_set_value(jdi->reset_gpio, 1);
 220
 221        gpiod_set_value(jdi->dcdc_en_gpio, 0);
 222
 223        jdi->prepared = false;
 224
 225        return 0;
 226}
 227
 228static int jdi_panel_prepare(struct drm_panel *panel)
 229{
 230        struct jdi_panel *jdi = to_jdi_panel(panel);
 231        struct device *dev = &jdi->dsi->dev;
 232        int ret;
 233
 234        if (jdi->prepared)
 235                return 0;
 236
 237        ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
 238        if (ret < 0) {
 239                dev_err(dev, "regulator enable failed, %d\n", ret);
 240                return ret;
 241        }
 242
 243        msleep(20);
 244
 245        gpiod_set_value(jdi->dcdc_en_gpio, 1);
 246        usleep_range(10, 20);
 247
 248        gpiod_set_value(jdi->reset_gpio, 0);
 249        usleep_range(10, 20);
 250
 251        gpiod_set_value(jdi->enable_gpio, 1);
 252        usleep_range(10, 20);
 253
 254        ret = jdi_panel_init(jdi);
 255        if (ret < 0) {
 256                dev_err(dev, "failed to init panel: %d\n", ret);
 257                goto poweroff;
 258        }
 259
 260        ret = jdi_panel_on(jdi);
 261        if (ret < 0) {
 262                dev_err(dev, "failed to set panel on: %d\n", ret);
 263                goto poweroff;
 264        }
 265
 266        jdi->prepared = true;
 267
 268        return 0;
 269
 270poweroff:
 271        ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
 272        if (ret < 0)
 273                dev_err(dev, "regulator disable failed, %d\n", ret);
 274
 275        gpiod_set_value(jdi->enable_gpio, 0);
 276
 277        gpiod_set_value(jdi->reset_gpio, 1);
 278
 279        gpiod_set_value(jdi->dcdc_en_gpio, 0);
 280
 281        return ret;
 282}
 283
 284static int jdi_panel_enable(struct drm_panel *panel)
 285{
 286        struct jdi_panel *jdi = to_jdi_panel(panel);
 287
 288        if (jdi->enabled)
 289                return 0;
 290
 291        backlight_enable(jdi->backlight);
 292
 293        jdi->enabled = true;
 294
 295        return 0;
 296}
 297
 298static const struct drm_display_mode default_mode = {
 299                .clock = 155493,
 300                .hdisplay = 1200,
 301                .hsync_start = 1200 + 48,
 302                .hsync_end = 1200 + 48 + 32,
 303                .htotal = 1200 + 48 + 32 + 60,
 304                .vdisplay = 1920,
 305                .vsync_start = 1920 + 3,
 306                .vsync_end = 1920 + 3 + 5,
 307                .vtotal = 1920 + 3 + 5 + 6,
 308                .vrefresh = 60,
 309                .flags = 0,
 310};
 311
 312static int jdi_panel_get_modes(struct drm_panel *panel)
 313{
 314        struct drm_display_mode *mode;
 315        struct jdi_panel *jdi = to_jdi_panel(panel);
 316        struct device *dev = &jdi->dsi->dev;
 317
 318        mode = drm_mode_duplicate(panel->drm, &default_mode);
 319        if (!mode) {
 320                dev_err(dev, "failed to add mode %ux%ux@%u\n",
 321                        default_mode.hdisplay, default_mode.vdisplay,
 322                        default_mode.vrefresh);
 323                return -ENOMEM;
 324        }
 325
 326        drm_mode_set_name(mode);
 327
 328        drm_mode_probed_add(panel->connector, mode);
 329
 330        panel->connector->display_info.width_mm = 95;
 331        panel->connector->display_info.height_mm = 151;
 332
 333        return 1;
 334}
 335
 336static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
 337{
 338        struct mipi_dsi_device *dsi = bl_get_data(bl);
 339        int ret;
 340        u16 brightness = bl->props.brightness;
 341
 342        dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 343
 344        ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
 345        if (ret < 0)
 346                return ret;
 347
 348        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 349
 350        return brightness & 0xff;
 351}
 352
 353static int dsi_dcs_bl_update_status(struct backlight_device *bl)
 354{
 355        struct mipi_dsi_device *dsi = bl_get_data(bl);
 356        int ret;
 357
 358        dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 359
 360        ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
 361        if (ret < 0)
 362                return ret;
 363
 364        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 365
 366        return 0;
 367}
 368
 369static const struct backlight_ops dsi_bl_ops = {
 370        .update_status = dsi_dcs_bl_update_status,
 371        .get_brightness = dsi_dcs_bl_get_brightness,
 372};
 373
 374static struct backlight_device *
 375drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
 376{
 377        struct device *dev = &dsi->dev;
 378        struct backlight_properties props;
 379
 380        memset(&props, 0, sizeof(props));
 381        props.type = BACKLIGHT_RAW;
 382        props.brightness = 255;
 383        props.max_brightness = 255;
 384
 385        return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
 386                                              &dsi_bl_ops, &props);
 387}
 388
 389static const struct drm_panel_funcs jdi_panel_funcs = {
 390        .disable = jdi_panel_disable,
 391        .unprepare = jdi_panel_unprepare,
 392        .prepare = jdi_panel_prepare,
 393        .enable = jdi_panel_enable,
 394        .get_modes = jdi_panel_get_modes,
 395};
 396
 397static const struct of_device_id jdi_of_match[] = {
 398        { .compatible = "jdi,lt070me05000", },
 399        { }
 400};
 401MODULE_DEVICE_TABLE(of, jdi_of_match);
 402
 403static int jdi_panel_add(struct jdi_panel *jdi)
 404{
 405        struct device *dev = &jdi->dsi->dev;
 406        int ret;
 407        unsigned int i;
 408
 409        jdi->mode = &default_mode;
 410
 411        for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++)
 412                jdi->supplies[i].supply = regulator_names[i];
 413
 414        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),
 415                                      jdi->supplies);
 416        if (ret < 0) {
 417                dev_err(dev, "failed to init regulator, ret=%d\n", ret);
 418                return ret;
 419        }
 420
 421        jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
 422        if (IS_ERR(jdi->enable_gpio)) {
 423                ret = PTR_ERR(jdi->enable_gpio);
 424                dev_err(dev, "cannot get enable-gpio %d\n", ret);
 425                return ret;
 426        }
 427
 428        jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
 429        if (IS_ERR(jdi->reset_gpio)) {
 430                ret = PTR_ERR(jdi->reset_gpio);
 431                dev_err(dev, "cannot get reset-gpios %d\n", ret);
 432                return ret;
 433        }
 434
 435        jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);
 436        if (IS_ERR(jdi->dcdc_en_gpio)) {
 437                ret = PTR_ERR(jdi->dcdc_en_gpio);
 438                dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret);
 439                return ret;
 440        }
 441
 442        jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);
 443        if (IS_ERR(jdi->backlight)) {
 444                ret = PTR_ERR(jdi->backlight);
 445                dev_err(dev, "failed to register backlight %d\n", ret);
 446                return ret;
 447        }
 448
 449        drm_panel_init(&jdi->base);
 450        jdi->base.funcs = &jdi_panel_funcs;
 451        jdi->base.dev = &jdi->dsi->dev;
 452
 453        ret = drm_panel_add(&jdi->base);
 454
 455        return ret;
 456}
 457
 458static void jdi_panel_del(struct jdi_panel *jdi)
 459{
 460        if (jdi->base.dev)
 461                drm_panel_remove(&jdi->base);
 462}
 463
 464static int jdi_panel_probe(struct mipi_dsi_device *dsi)
 465{
 466        struct jdi_panel *jdi;
 467        int ret;
 468
 469        dsi->lanes = 4;
 470        dsi->format = MIPI_DSI_FMT_RGB888;
 471        dsi->mode_flags =  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
 472                           MIPI_DSI_CLOCK_NON_CONTINUOUS;
 473
 474        jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);
 475        if (!jdi)
 476                return -ENOMEM;
 477
 478        mipi_dsi_set_drvdata(dsi, jdi);
 479
 480        jdi->dsi = dsi;
 481
 482        ret = jdi_panel_add(jdi);
 483        if (ret < 0)
 484                return ret;
 485
 486        return mipi_dsi_attach(dsi);
 487}
 488
 489static int jdi_panel_remove(struct mipi_dsi_device *dsi)
 490{
 491        struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
 492        int ret;
 493
 494        ret = jdi_panel_disable(&jdi->base);
 495        if (ret < 0)
 496                dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
 497
 498        ret = mipi_dsi_detach(dsi);
 499        if (ret < 0)
 500                dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
 501                        ret);
 502
 503        drm_panel_detach(&jdi->base);
 504        jdi_panel_del(jdi);
 505
 506        return 0;
 507}
 508
 509static void jdi_panel_shutdown(struct mipi_dsi_device *dsi)
 510{
 511        struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
 512
 513        jdi_panel_disable(&jdi->base);
 514}
 515
 516static struct mipi_dsi_driver jdi_panel_driver = {
 517        .driver = {
 518                .name = "panel-jdi-lt070me05000",
 519                .of_match_table = jdi_of_match,
 520        },
 521        .probe = jdi_panel_probe,
 522        .remove = jdi_panel_remove,
 523        .shutdown = jdi_panel_shutdown,
 524};
 525module_mipi_dsi_driver(jdi_panel_driver);
 526
 527MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
 528MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
 529MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");
 530MODULE_LICENSE("GPL v2");
 531