linux/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Sony ACX565AKM LCD Panel driver
   4 *
   5 * Copyright (C) 2010 Nokia Corporation
   6 *
   7 * Original Driver Author: Imre Deak <imre.deak@nokia.com>
   8 * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@ti.com>
   9 * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
  10 */
  11
  12#include <linux/backlight.h>
  13#include <linux/delay.h>
  14#include <linux/gpio/consumer.h>
  15#include <linux/jiffies.h>
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/platform_device.h>
  19#include <linux/sched.h>
  20#include <linux/spi/spi.h>
  21
  22#include "../dss/omapdss.h"
  23
  24#define MIPID_CMD_READ_DISP_ID          0x04
  25#define MIPID_CMD_READ_RED              0x06
  26#define MIPID_CMD_READ_GREEN            0x07
  27#define MIPID_CMD_READ_BLUE             0x08
  28#define MIPID_CMD_READ_DISP_STATUS      0x09
  29#define MIPID_CMD_RDDSDR                0x0F
  30#define MIPID_CMD_SLEEP_IN              0x10
  31#define MIPID_CMD_SLEEP_OUT             0x11
  32#define MIPID_CMD_DISP_OFF              0x28
  33#define MIPID_CMD_DISP_ON               0x29
  34#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
  35#define MIPID_CMD_READ_DISP_BRIGHTNESS  0x52
  36#define MIPID_CMD_WRITE_CTRL_DISP       0x53
  37
  38#define CTRL_DISP_BRIGHTNESS_CTRL_ON    (1 << 5)
  39#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
  40#define CTRL_DISP_BACKLIGHT_ON          (1 << 2)
  41#define CTRL_DISP_AUTO_BRIGHTNESS_ON    (1 << 1)
  42
  43#define MIPID_CMD_READ_CTRL_DISP        0x54
  44#define MIPID_CMD_WRITE_CABC            0x55
  45#define MIPID_CMD_READ_CABC             0x56
  46
  47#define MIPID_VER_LPH8923               3
  48#define MIPID_VER_LS041Y3               4
  49#define MIPID_VER_L4F00311              8
  50#define MIPID_VER_ACX565AKM             9
  51
  52struct panel_drv_data {
  53        struct omap_dss_device  dssdev;
  54
  55        struct gpio_desc *reset_gpio;
  56
  57        struct videomode vm;
  58
  59        char            *name;
  60        int             enabled;
  61        int             model;
  62        int             revision;
  63        u8              display_id[3];
  64        unsigned        has_bc:1;
  65        unsigned        has_cabc:1;
  66        unsigned        cabc_mode;
  67        unsigned long   hw_guard_end;           /* next value of jiffies
  68                                                   when we can issue the
  69                                                   next sleep in/out command */
  70        unsigned long   hw_guard_wait;          /* max guard time in jiffies */
  71
  72        struct spi_device       *spi;
  73        struct mutex            mutex;
  74
  75        struct backlight_device *bl_dev;
  76};
  77
  78static const struct videomode acx565akm_panel_vm = {
  79        .hactive        = 800,
  80        .vactive        = 480,
  81        .pixelclock     = 24000000,
  82        .hfront_porch   = 28,
  83        .hsync_len      = 4,
  84        .hback_porch    = 24,
  85        .vfront_porch   = 3,
  86        .vsync_len      = 3,
  87        .vback_porch    = 4,
  88
  89        .flags          = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
  90};
  91
  92#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
  93
  94static void acx565akm_transfer(struct panel_drv_data *ddata, int cmd,
  95                              const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
  96{
  97        struct spi_message      m;
  98        struct spi_transfer     *x, xfer[5];
  99        int                     r;
 100
 101        BUG_ON(ddata->spi == NULL);
 102
 103        spi_message_init(&m);
 104
 105        memset(xfer, 0, sizeof(xfer));
 106        x = &xfer[0];
 107
 108        cmd &=  0xff;
 109        x->tx_buf = &cmd;
 110        x->bits_per_word = 9;
 111        x->len = 2;
 112
 113        if (rlen > 1 && wlen == 0) {
 114                /*
 115                 * Between the command and the response data there is a
 116                 * dummy clock cycle. Add an extra bit after the command
 117                 * word to account for this.
 118                 */
 119                x->bits_per_word = 10;
 120                cmd <<= 1;
 121        }
 122        spi_message_add_tail(x, &m);
 123
 124        if (wlen) {
 125                x++;
 126                x->tx_buf = wbuf;
 127                x->len = wlen;
 128                x->bits_per_word = 9;
 129                spi_message_add_tail(x, &m);
 130        }
 131
 132        if (rlen) {
 133                x++;
 134                x->rx_buf       = rbuf;
 135                x->len          = rlen;
 136                spi_message_add_tail(x, &m);
 137        }
 138
 139        r = spi_sync(ddata->spi, &m);
 140        if (r < 0)
 141                dev_dbg(&ddata->spi->dev, "spi_sync %d\n", r);
 142}
 143
 144static inline void acx565akm_cmd(struct panel_drv_data *ddata, int cmd)
 145{
 146        acx565akm_transfer(ddata, cmd, NULL, 0, NULL, 0);
 147}
 148
 149static inline void acx565akm_write(struct panel_drv_data *ddata,
 150                               int reg, const u8 *buf, int len)
 151{
 152        acx565akm_transfer(ddata, reg, buf, len, NULL, 0);
 153}
 154
 155static inline void acx565akm_read(struct panel_drv_data *ddata,
 156                              int reg, u8 *buf, int len)
 157{
 158        acx565akm_transfer(ddata, reg, NULL, 0, buf, len);
 159}
 160
 161static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
 162{
 163        ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
 164        ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
 165}
 166
 167static void hw_guard_wait(struct panel_drv_data *ddata)
 168{
 169        unsigned long wait = ddata->hw_guard_end - jiffies;
 170
 171        if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
 172                set_current_state(TASK_UNINTERRUPTIBLE);
 173                schedule_timeout(wait);
 174        }
 175}
 176
 177static void set_sleep_mode(struct panel_drv_data *ddata, int on)
 178{
 179        int cmd;
 180
 181        if (on)
 182                cmd = MIPID_CMD_SLEEP_IN;
 183        else
 184                cmd = MIPID_CMD_SLEEP_OUT;
 185        /*
 186         * We have to keep 120msec between sleep in/out commands.
 187         * (8.2.15, 8.2.16).
 188         */
 189        hw_guard_wait(ddata);
 190        acx565akm_cmd(ddata, cmd);
 191        hw_guard_start(ddata, 120);
 192}
 193
 194static void set_display_state(struct panel_drv_data *ddata, int enabled)
 195{
 196        int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
 197
 198        acx565akm_cmd(ddata, cmd);
 199}
 200
 201static int panel_enabled(struct panel_drv_data *ddata)
 202{
 203        __be32 v;
 204        u32 disp_status;
 205        int enabled;
 206
 207        acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, (u8 *)&v, 4);
 208        disp_status = __be32_to_cpu(v);
 209        enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
 210        dev_dbg(&ddata->spi->dev,
 211                "LCD panel %senabled by bootloader (status 0x%04x)\n",
 212                enabled ? "" : "not ", disp_status);
 213        return enabled;
 214}
 215
 216static int panel_detect(struct panel_drv_data *ddata)
 217{
 218        acx565akm_read(ddata, MIPID_CMD_READ_DISP_ID, ddata->display_id, 3);
 219        dev_dbg(&ddata->spi->dev, "MIPI display ID: %02x%02x%02x\n",
 220                ddata->display_id[0],
 221                ddata->display_id[1],
 222                ddata->display_id[2]);
 223
 224        switch (ddata->display_id[0]) {
 225        case 0x10:
 226                ddata->model = MIPID_VER_ACX565AKM;
 227                ddata->name = "acx565akm";
 228                ddata->has_bc = 1;
 229                ddata->has_cabc = 1;
 230                break;
 231        case 0x29:
 232                ddata->model = MIPID_VER_L4F00311;
 233                ddata->name = "l4f00311";
 234                break;
 235        case 0x45:
 236                ddata->model = MIPID_VER_LPH8923;
 237                ddata->name = "lph8923";
 238                break;
 239        case 0x83:
 240                ddata->model = MIPID_VER_LS041Y3;
 241                ddata->name = "ls041y3";
 242                break;
 243        default:
 244                ddata->name = "unknown";
 245                dev_err(&ddata->spi->dev, "invalid display ID\n");
 246                return -ENODEV;
 247        }
 248
 249        ddata->revision = ddata->display_id[1];
 250
 251        dev_info(&ddata->spi->dev, "omapfb: %s rev %02x LCD detected\n",
 252                        ddata->name, ddata->revision);
 253
 254        return 0;
 255}
 256
 257/*----------------------Backlight Control-------------------------*/
 258
 259static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable)
 260{
 261        u16 ctrl;
 262
 263        acx565akm_read(ddata, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
 264        if (enable) {
 265                ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
 266                        CTRL_DISP_BACKLIGHT_ON;
 267        } else {
 268                ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
 269                          CTRL_DISP_BACKLIGHT_ON);
 270        }
 271
 272        ctrl |= 1 << 8;
 273        acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
 274}
 275
 276static void set_cabc_mode(struct panel_drv_data *ddata, unsigned int mode)
 277{
 278        u16 cabc_ctrl;
 279
 280        ddata->cabc_mode = mode;
 281        if (!ddata->enabled)
 282                return;
 283        cabc_ctrl = 0;
 284        acx565akm_read(ddata, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
 285        cabc_ctrl &= ~3;
 286        cabc_ctrl |= (1 << 8) | (mode & 3);
 287        acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
 288}
 289
 290static unsigned int get_cabc_mode(struct panel_drv_data *ddata)
 291{
 292        return ddata->cabc_mode;
 293}
 294
 295static unsigned int get_hw_cabc_mode(struct panel_drv_data *ddata)
 296{
 297        u8 cabc_ctrl;
 298
 299        acx565akm_read(ddata, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
 300        return cabc_ctrl & 3;
 301}
 302
 303static void acx565akm_set_brightness(struct panel_drv_data *ddata, int level)
 304{
 305        int bv;
 306
 307        bv = level | (1 << 8);
 308        acx565akm_write(ddata, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
 309
 310        if (level)
 311                enable_backlight_ctrl(ddata, 1);
 312        else
 313                enable_backlight_ctrl(ddata, 0);
 314}
 315
 316static int acx565akm_get_actual_brightness(struct panel_drv_data *ddata)
 317{
 318        u8 bv;
 319
 320        acx565akm_read(ddata, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
 321
 322        return bv;
 323}
 324
 325
 326static int acx565akm_bl_update_status(struct backlight_device *dev)
 327{
 328        struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
 329        int level;
 330
 331        dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 332
 333        if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
 334                        dev->props.power == FB_BLANK_UNBLANK)
 335                level = dev->props.brightness;
 336        else
 337                level = 0;
 338
 339        if (ddata->has_bc)
 340                acx565akm_set_brightness(ddata, level);
 341        else
 342                return -ENODEV;
 343
 344        return 0;
 345}
 346
 347static int acx565akm_bl_get_intensity(struct backlight_device *dev)
 348{
 349        struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
 350
 351        dev_dbg(&dev->dev, "%s\n", __func__);
 352
 353        if (!ddata->has_bc)
 354                return -ENODEV;
 355
 356        if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
 357                        dev->props.power == FB_BLANK_UNBLANK) {
 358                if (ddata->has_bc)
 359                        return acx565akm_get_actual_brightness(ddata);
 360                else
 361                        return dev->props.brightness;
 362        }
 363
 364        return 0;
 365}
 366
 367static int acx565akm_bl_update_status_locked(struct backlight_device *dev)
 368{
 369        struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
 370        int r;
 371
 372        mutex_lock(&ddata->mutex);
 373        r = acx565akm_bl_update_status(dev);
 374        mutex_unlock(&ddata->mutex);
 375
 376        return r;
 377}
 378
 379static int acx565akm_bl_get_intensity_locked(struct backlight_device *dev)
 380{
 381        struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
 382        int r;
 383
 384        mutex_lock(&ddata->mutex);
 385        r = acx565akm_bl_get_intensity(dev);
 386        mutex_unlock(&ddata->mutex);
 387
 388        return r;
 389}
 390
 391static const struct backlight_ops acx565akm_bl_ops = {
 392        .get_brightness = acx565akm_bl_get_intensity_locked,
 393        .update_status  = acx565akm_bl_update_status_locked,
 394};
 395
 396/*--------------------Auto Brightness control via Sysfs---------------------*/
 397
 398static const char * const cabc_modes[] = {
 399        "off",          /* always used when CABC is not supported */
 400        "ui",
 401        "still-image",
 402        "moving-image",
 403};
 404
 405static ssize_t show_cabc_mode(struct device *dev,
 406                struct device_attribute *attr,
 407                char *buf)
 408{
 409        struct panel_drv_data *ddata = dev_get_drvdata(dev);
 410        const char *mode_str;
 411        int mode;
 412        int len;
 413
 414        if (!ddata->has_cabc)
 415                mode = 0;
 416        else
 417                mode = get_cabc_mode(ddata);
 418        mode_str = "unknown";
 419        if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
 420                mode_str = cabc_modes[mode];
 421        len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
 422
 423        return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
 424}
 425
 426static ssize_t store_cabc_mode(struct device *dev,
 427                struct device_attribute *attr,
 428                const char *buf, size_t count)
 429{
 430        struct panel_drv_data *ddata = dev_get_drvdata(dev);
 431        int i;
 432
 433        for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
 434                const char *mode_str = cabc_modes[i];
 435                int cmp_len = strlen(mode_str);
 436
 437                if (count > 0 && buf[count - 1] == '\n')
 438                        count--;
 439                if (count != cmp_len)
 440                        continue;
 441
 442                if (strncmp(buf, mode_str, cmp_len) == 0)
 443                        break;
 444        }
 445
 446        if (i == ARRAY_SIZE(cabc_modes))
 447                return -EINVAL;
 448
 449        if (!ddata->has_cabc && i != 0)
 450                return -EINVAL;
 451
 452        mutex_lock(&ddata->mutex);
 453        set_cabc_mode(ddata, i);
 454        mutex_unlock(&ddata->mutex);
 455
 456        return count;
 457}
 458
 459static ssize_t show_cabc_available_modes(struct device *dev,
 460                struct device_attribute *attr,
 461                char *buf)
 462{
 463        struct panel_drv_data *ddata = dev_get_drvdata(dev);
 464        int len;
 465        int i;
 466
 467        if (!ddata->has_cabc)
 468                return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
 469
 470        for (i = 0, len = 0;
 471             len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
 472                len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
 473                        i ? " " : "", cabc_modes[i],
 474                        i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
 475
 476        return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
 477}
 478
 479static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
 480                show_cabc_mode, store_cabc_mode);
 481static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
 482                show_cabc_available_modes, NULL);
 483
 484static struct attribute *bldev_attrs[] = {
 485        &dev_attr_cabc_mode.attr,
 486        &dev_attr_cabc_available_modes.attr,
 487        NULL,
 488};
 489
 490static const struct attribute_group bldev_attr_group = {
 491        .attrs = bldev_attrs,
 492};
 493
 494static int acx565akm_connect(struct omap_dss_device *src,
 495                             struct omap_dss_device *dst)
 496{
 497        return 0;
 498}
 499
 500static void acx565akm_disconnect(struct omap_dss_device *src,
 501                                 struct omap_dss_device *dst)
 502{
 503}
 504
 505static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
 506{
 507        struct panel_drv_data *ddata = to_panel_data(dssdev);
 508
 509        dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 510
 511        /*FIXME tweak me */
 512        msleep(50);
 513
 514        if (ddata->reset_gpio)
 515                gpiod_set_value(ddata->reset_gpio, 1);
 516
 517        if (ddata->enabled) {
 518                dev_dbg(&ddata->spi->dev, "panel already enabled\n");
 519                return 0;
 520        }
 521
 522        /*
 523         * We have to meet all the following delay requirements:
 524         * 1. tRW: reset pulse width 10usec (7.12.1)
 525         * 2. tRT: reset cancel time 5msec (7.12.1)
 526         * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
 527         *    case (7.6.2)
 528         * 4. 120msec before the sleep out command (7.12.1)
 529         */
 530        msleep(120);
 531
 532        set_sleep_mode(ddata, 0);
 533        ddata->enabled = 1;
 534
 535        /* 5msec between sleep out and the next command. (8.2.16) */
 536        usleep_range(5000, 10000);
 537        set_display_state(ddata, 1);
 538        set_cabc_mode(ddata, ddata->cabc_mode);
 539
 540        return acx565akm_bl_update_status(ddata->bl_dev);
 541}
 542
 543static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
 544{
 545        struct panel_drv_data *ddata = to_panel_data(dssdev);
 546
 547        dev_dbg(dssdev->dev, "%s\n", __func__);
 548
 549        if (!ddata->enabled)
 550                return;
 551
 552        set_display_state(ddata, 0);
 553        set_sleep_mode(ddata, 1);
 554        ddata->enabled = 0;
 555        /*
 556         * We have to provide PCLK,HS,VS signals for 2 frames (worst case
 557         * ~50msec) after sending the sleep in command and asserting the
 558         * reset signal. We probably could assert the reset w/o the delay
 559         * but we still delay to avoid possible artifacts. (7.6.1)
 560         */
 561        msleep(50);
 562
 563        if (ddata->reset_gpio)
 564                gpiod_set_value(ddata->reset_gpio, 0);
 565
 566        /* FIXME need to tweak this delay */
 567        msleep(100);
 568}
 569
 570static void acx565akm_enable(struct omap_dss_device *dssdev)
 571{
 572        struct panel_drv_data *ddata = to_panel_data(dssdev);
 573
 574        mutex_lock(&ddata->mutex);
 575        acx565akm_panel_power_on(dssdev);
 576        mutex_unlock(&ddata->mutex);
 577}
 578
 579static void acx565akm_disable(struct omap_dss_device *dssdev)
 580{
 581        struct panel_drv_data *ddata = to_panel_data(dssdev);
 582
 583        mutex_lock(&ddata->mutex);
 584        acx565akm_panel_power_off(dssdev);
 585        mutex_unlock(&ddata->mutex);
 586}
 587
 588static int acx565akm_get_modes(struct omap_dss_device *dssdev,
 589                               struct drm_connector *connector)
 590{
 591        struct panel_drv_data *ddata = to_panel_data(dssdev);
 592
 593        return omapdss_display_get_modes(connector, &ddata->vm);
 594}
 595
 596static const struct omap_dss_device_ops acx565akm_ops = {
 597        .connect        = acx565akm_connect,
 598        .disconnect     = acx565akm_disconnect,
 599
 600        .enable         = acx565akm_enable,
 601        .disable        = acx565akm_disable,
 602
 603        .get_modes      = acx565akm_get_modes,
 604};
 605
 606static int acx565akm_probe(struct spi_device *spi)
 607{
 608        struct panel_drv_data *ddata;
 609        struct omap_dss_device *dssdev;
 610        struct backlight_device *bldev;
 611        int max_brightness, brightness;
 612        struct backlight_properties props;
 613        struct gpio_desc *gpio;
 614        int r;
 615
 616        dev_dbg(&spi->dev, "%s\n", __func__);
 617
 618        spi->mode = SPI_MODE_3;
 619
 620        ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
 621        if (ddata == NULL)
 622                return -ENOMEM;
 623
 624        dev_set_drvdata(&spi->dev, ddata);
 625
 626        ddata->spi = spi;
 627
 628        mutex_init(&ddata->mutex);
 629
 630        gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
 631        if (IS_ERR(gpio)) {
 632                dev_err(&spi->dev, "failed to parse reset gpio\n");
 633                return PTR_ERR(gpio);
 634        }
 635
 636        ddata->reset_gpio = gpio;
 637
 638        if (ddata->reset_gpio)
 639                gpiod_set_value(ddata->reset_gpio, 1);
 640
 641        /*
 642         * After reset we have to wait 5 msec before the first
 643         * command can be sent.
 644         */
 645        usleep_range(5000, 10000);
 646
 647        ddata->enabled = panel_enabled(ddata);
 648
 649        r = panel_detect(ddata);
 650
 651        if (!ddata->enabled && ddata->reset_gpio)
 652                gpiod_set_value(ddata->reset_gpio, 0);
 653
 654        if (r) {
 655                dev_err(&spi->dev, "%s panel detect error\n", __func__);
 656                return r;
 657        }
 658
 659        memset(&props, 0, sizeof(props));
 660        props.fb_blank = FB_BLANK_UNBLANK;
 661        props.power = FB_BLANK_UNBLANK;
 662        props.type = BACKLIGHT_RAW;
 663
 664        bldev = backlight_device_register("acx565akm", &ddata->spi->dev,
 665                        ddata, &acx565akm_bl_ops, &props);
 666        if (IS_ERR(bldev))
 667                return PTR_ERR(bldev);
 668        ddata->bl_dev = bldev;
 669        if (ddata->has_cabc) {
 670                r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
 671                if (r) {
 672                        dev_err(&bldev->dev,
 673                                "%s failed to create sysfs files\n", __func__);
 674                        goto err_backlight_unregister;
 675                }
 676                ddata->cabc_mode = get_hw_cabc_mode(ddata);
 677        }
 678
 679        max_brightness = 255;
 680
 681        if (ddata->has_bc)
 682                brightness = acx565akm_get_actual_brightness(ddata);
 683        else
 684                brightness = 0;
 685
 686        bldev->props.max_brightness = max_brightness;
 687        bldev->props.brightness = brightness;
 688
 689        acx565akm_bl_update_status(bldev);
 690
 691
 692        ddata->vm = acx565akm_panel_vm;
 693
 694        dssdev = &ddata->dssdev;
 695        dssdev->dev = &spi->dev;
 696        dssdev->ops = &acx565akm_ops;
 697        dssdev->type = OMAP_DISPLAY_TYPE_SDI;
 698        dssdev->display = true;
 699        dssdev->owner = THIS_MODULE;
 700        dssdev->of_ports = BIT(0);
 701        dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
 702        dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH
 703                          | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE
 704                          | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
 705
 706        omapdss_display_init(dssdev);
 707        omapdss_device_register(dssdev);
 708
 709        return 0;
 710
 711err_backlight_unregister:
 712        backlight_device_unregister(bldev);
 713        return r;
 714}
 715
 716static int acx565akm_remove(struct spi_device *spi)
 717{
 718        struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 719        struct omap_dss_device *dssdev = &ddata->dssdev;
 720
 721        dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 722
 723        sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group);
 724        backlight_device_unregister(ddata->bl_dev);
 725
 726        omapdss_device_unregister(dssdev);
 727
 728        if (omapdss_device_is_enabled(dssdev))
 729                acx565akm_disable(dssdev);
 730
 731        return 0;
 732}
 733
 734static const struct of_device_id acx565akm_of_match[] = {
 735        { .compatible = "omapdss,sony,acx565akm", },
 736        {},
 737};
 738MODULE_DEVICE_TABLE(of, acx565akm_of_match);
 739
 740static struct spi_driver acx565akm_driver = {
 741        .driver = {
 742                .name   = "acx565akm",
 743                .of_match_table = acx565akm_of_match,
 744                .suppress_bind_attrs = true,
 745        },
 746        .probe  = acx565akm_probe,
 747        .remove = acx565akm_remove,
 748};
 749
 750module_spi_driver(acx565akm_driver);
 751
 752MODULE_ALIAS("spi:sony,acx565akm");
 753MODULE_AUTHOR("Nokia Corporation");
 754MODULE_DESCRIPTION("acx565akm LCD Driver");
 755MODULE_LICENSE("GPL");
 756