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        jdi->backlight->props.power = FB_BLANK_POWERDOWN;
 196        backlight_update_status(jdi->backlight);
 197
 198        jdi->enabled = false;
 199
 200        return 0;
 201}
 202
 203static int jdi_panel_unprepare(struct drm_panel *panel)
 204{
 205        struct jdi_panel *jdi = to_jdi_panel(panel);
 206        struct device *dev = &jdi->dsi->dev;
 207        int ret;
 208
 209        if (!jdi->prepared)
 210                return 0;
 211
 212        jdi_panel_off(jdi);
 213
 214        ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
 215        if (ret < 0)
 216                dev_err(dev, "regulator disable failed, %d\n", ret);
 217
 218        gpiod_set_value(jdi->enable_gpio, 0);
 219
 220        gpiod_set_value(jdi->reset_gpio, 1);
 221
 222        gpiod_set_value(jdi->dcdc_en_gpio, 0);
 223
 224        jdi->prepared = false;
 225
 226        return 0;
 227}
 228
 229static int jdi_panel_prepare(struct drm_panel *panel)
 230{
 231        struct jdi_panel *jdi = to_jdi_panel(panel);
 232        struct device *dev = &jdi->dsi->dev;
 233        int ret;
 234
 235        if (jdi->prepared)
 236                return 0;
 237
 238        ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
 239        if (ret < 0) {
 240                dev_err(dev, "regulator enable failed, %d\n", ret);
 241                return ret;
 242        }
 243
 244        msleep(20);
 245
 246        gpiod_set_value(jdi->dcdc_en_gpio, 1);
 247        usleep_range(10, 20);
 248
 249        gpiod_set_value(jdi->reset_gpio, 0);
 250        usleep_range(10, 20);
 251
 252        gpiod_set_value(jdi->enable_gpio, 1);
 253        usleep_range(10, 20);
 254
 255        ret = jdi_panel_init(jdi);
 256        if (ret < 0) {
 257                dev_err(dev, "failed to init panel: %d\n", ret);
 258                goto poweroff;
 259        }
 260
 261        ret = jdi_panel_on(jdi);
 262        if (ret < 0) {
 263                dev_err(dev, "failed to set panel on: %d\n", ret);
 264                goto poweroff;
 265        }
 266
 267        jdi->prepared = true;
 268
 269        return 0;
 270
 271poweroff:
 272        ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
 273        if (ret < 0)
 274                dev_err(dev, "regulator disable failed, %d\n", ret);
 275
 276        gpiod_set_value(jdi->enable_gpio, 0);
 277
 278        gpiod_set_value(jdi->reset_gpio, 1);
 279
 280        gpiod_set_value(jdi->dcdc_en_gpio, 0);
 281
 282        return ret;
 283}
 284
 285static int jdi_panel_enable(struct drm_panel *panel)
 286{
 287        struct jdi_panel *jdi = to_jdi_panel(panel);
 288
 289        if (jdi->enabled)
 290                return 0;
 291
 292        jdi->backlight->props.power = FB_BLANK_UNBLANK;
 293        backlight_update_status(jdi->backlight);
 294
 295        jdi->enabled = true;
 296
 297        return 0;
 298}
 299
 300static const struct drm_display_mode default_mode = {
 301                .clock = 155493,
 302                .hdisplay = 1200,
 303                .hsync_start = 1200 + 48,
 304                .hsync_end = 1200 + 48 + 32,
 305                .htotal = 1200 + 48 + 32 + 60,
 306                .vdisplay = 1920,
 307                .vsync_start = 1920 + 3,
 308                .vsync_end = 1920 + 3 + 5,
 309                .vtotal = 1920 + 3 + 5 + 6,
 310                .vrefresh = 60,
 311                .flags = 0,
 312};
 313
 314static int jdi_panel_get_modes(struct drm_panel *panel)
 315{
 316        struct drm_display_mode *mode;
 317        struct jdi_panel *jdi = to_jdi_panel(panel);
 318        struct device *dev = &jdi->dsi->dev;
 319
 320        mode = drm_mode_duplicate(panel->drm, &default_mode);
 321        if (!mode) {
 322                dev_err(dev, "failed to add mode %ux%ux@%u\n",
 323                        default_mode.hdisplay, default_mode.vdisplay,
 324                        default_mode.vrefresh);
 325                return -ENOMEM;
 326        }
 327
 328        drm_mode_set_name(mode);
 329
 330        drm_mode_probed_add(panel->connector, mode);
 331
 332        panel->connector->display_info.width_mm = 95;
 333        panel->connector->display_info.height_mm = 151;
 334
 335        return 1;
 336}
 337
 338static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
 339{
 340        struct mipi_dsi_device *dsi = bl_get_data(bl);
 341        int ret;
 342        u16 brightness = bl->props.brightness;
 343
 344        dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 345
 346        ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
 347        if (ret < 0)
 348                return ret;
 349
 350        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 351
 352        return brightness & 0xff;
 353}
 354
 355static int dsi_dcs_bl_update_status(struct backlight_device *bl)
 356{
 357        struct mipi_dsi_device *dsi = bl_get_data(bl);
 358        int ret;
 359
 360        dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 361
 362        ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
 363        if (ret < 0)
 364                return ret;
 365
 366        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 367
 368        return 0;
 369}
 370
 371static const struct backlight_ops dsi_bl_ops = {
 372        .update_status = dsi_dcs_bl_update_status,
 373        .get_brightness = dsi_dcs_bl_get_brightness,
 374};
 375
 376static struct backlight_device *
 377drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
 378{
 379        struct device *dev = &dsi->dev;
 380        struct backlight_properties props;
 381
 382        memset(&props, 0, sizeof(props));
 383        props.type = BACKLIGHT_RAW;
 384        props.brightness = 255;
 385        props.max_brightness = 255;
 386
 387        return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
 388                                              &dsi_bl_ops, &props);
 389}
 390
 391static const struct drm_panel_funcs jdi_panel_funcs = {
 392        .disable = jdi_panel_disable,
 393        .unprepare = jdi_panel_unprepare,
 394        .prepare = jdi_panel_prepare,
 395        .enable = jdi_panel_enable,
 396        .get_modes = jdi_panel_get_modes,
 397};
 398
 399static const struct of_device_id jdi_of_match[] = {
 400        { .compatible = "jdi,lt070me05000", },
 401        { }
 402};
 403MODULE_DEVICE_TABLE(of, jdi_of_match);
 404
 405static int jdi_panel_add(struct jdi_panel *jdi)
 406{
 407        struct device *dev = &jdi->dsi->dev;
 408        int ret;
 409        unsigned int i;
 410
 411        jdi->mode = &default_mode;
 412
 413        for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++)
 414                jdi->supplies[i].supply = regulator_names[i];
 415
 416        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),
 417                                      jdi->supplies);
 418        if (ret < 0) {
 419                dev_err(dev, "failed to init regulator, ret=%d\n", ret);
 420                return ret;
 421        }
 422
 423        jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
 424        if (IS_ERR(jdi->enable_gpio)) {
 425                ret = PTR_ERR(jdi->enable_gpio);
 426                dev_err(dev, "cannot get enable-gpio %d\n", ret);
 427                return ret;
 428        }
 429
 430        jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
 431        if (IS_ERR(jdi->reset_gpio)) {
 432                ret = PTR_ERR(jdi->reset_gpio);
 433                dev_err(dev, "cannot get reset-gpios %d\n", ret);
 434                return ret;
 435        }
 436
 437        jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);
 438        if (IS_ERR(jdi->dcdc_en_gpio)) {
 439                ret = PTR_ERR(jdi->dcdc_en_gpio);
 440                dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret);
 441                return ret;
 442        }
 443
 444        jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);
 445        if (IS_ERR(jdi->backlight)) {
 446                ret = PTR_ERR(jdi->backlight);
 447                dev_err(dev, "failed to register backlight %d\n", ret);
 448                return ret;
 449        }
 450
 451        drm_panel_init(&jdi->base);
 452        jdi->base.funcs = &jdi_panel_funcs;
 453        jdi->base.dev = &jdi->dsi->dev;
 454
 455        ret = drm_panel_add(&jdi->base);
 456
 457        return ret;
 458}
 459
 460static void jdi_panel_del(struct jdi_panel *jdi)
 461{
 462        if (jdi->base.dev)
 463                drm_panel_remove(&jdi->base);
 464}
 465
 466static int jdi_panel_probe(struct mipi_dsi_device *dsi)
 467{
 468        struct jdi_panel *jdi;
 469        int ret;
 470
 471        dsi->lanes = 4;
 472        dsi->format = MIPI_DSI_FMT_RGB888;
 473        dsi->mode_flags =  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
 474                           MIPI_DSI_CLOCK_NON_CONTINUOUS;
 475
 476        jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);
 477        if (!jdi)
 478                return -ENOMEM;
 479
 480        mipi_dsi_set_drvdata(dsi, jdi);
 481
 482        jdi->dsi = dsi;
 483
 484        ret = jdi_panel_add(jdi);
 485        if (ret < 0)
 486                return ret;
 487
 488        return mipi_dsi_attach(dsi);
 489}
 490
 491static int jdi_panel_remove(struct mipi_dsi_device *dsi)
 492{
 493        struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
 494        int ret;
 495
 496        ret = jdi_panel_disable(&jdi->base);
 497        if (ret < 0)
 498                dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
 499
 500        ret = mipi_dsi_detach(dsi);
 501        if (ret < 0)
 502                dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
 503                        ret);
 504
 505        drm_panel_detach(&jdi->base);
 506        jdi_panel_del(jdi);
 507
 508        return 0;
 509}
 510
 511static void jdi_panel_shutdown(struct mipi_dsi_device *dsi)
 512{
 513        struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
 514
 515        jdi_panel_disable(&jdi->base);
 516}
 517
 518static struct mipi_dsi_driver jdi_panel_driver = {
 519        .driver = {
 520                .name = "panel-jdi-lt070me05000",
 521                .of_match_table = jdi_of_match,
 522        },
 523        .probe = jdi_panel_probe,
 524        .remove = jdi_panel_remove,
 525        .shutdown = jdi_panel_shutdown,
 526};
 527module_mipi_dsi_driver(jdi_panel_driver);
 528
 529MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
 530MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
 531MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");
 532MODULE_LICENSE("GPL v2");
 533