0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/delay.h>
0016 #include <linux/spi/spi.h>
0017 #include <linux/jiffies.h>
0018 #include <linux/sched.h>
0019 #include <linux/backlight.h>
0020 #include <linux/fb.h>
0021 #include <linux/gpio.h>
0022 #include <linux/of.h>
0023 #include <linux/of_gpio.h>
0024
0025 #include <video/omapfb_dss.h>
0026 #include <video/omap-panel-data.h>
0027
0028 #define MIPID_CMD_READ_DISP_ID 0x04
0029 #define MIPID_CMD_READ_RED 0x06
0030 #define MIPID_CMD_READ_GREEN 0x07
0031 #define MIPID_CMD_READ_BLUE 0x08
0032 #define MIPID_CMD_READ_DISP_STATUS 0x09
0033 #define MIPID_CMD_RDDSDR 0x0F
0034 #define MIPID_CMD_SLEEP_IN 0x10
0035 #define MIPID_CMD_SLEEP_OUT 0x11
0036 #define MIPID_CMD_DISP_OFF 0x28
0037 #define MIPID_CMD_DISP_ON 0x29
0038 #define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
0039 #define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
0040 #define MIPID_CMD_WRITE_CTRL_DISP 0x53
0041
0042 #define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
0043 #define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
0044 #define CTRL_DISP_BACKLIGHT_ON (1 << 2)
0045 #define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
0046
0047 #define MIPID_CMD_READ_CTRL_DISP 0x54
0048 #define MIPID_CMD_WRITE_CABC 0x55
0049 #define MIPID_CMD_READ_CABC 0x56
0050
0051 #define MIPID_VER_LPH8923 3
0052 #define MIPID_VER_LS041Y3 4
0053 #define MIPID_VER_L4F00311 8
0054 #define MIPID_VER_ACX565AKM 9
0055
0056 struct panel_drv_data {
0057 struct omap_dss_device dssdev;
0058 struct omap_dss_device *in;
0059
0060 int reset_gpio;
0061 int datapairs;
0062
0063 struct omap_video_timings videomode;
0064
0065 char *name;
0066 int enabled;
0067 int model;
0068 int revision;
0069 u8 display_id[3];
0070 unsigned has_bc:1;
0071 unsigned has_cabc:1;
0072 unsigned cabc_mode;
0073 unsigned long hw_guard_end;
0074
0075
0076 unsigned long hw_guard_wait;
0077
0078 struct spi_device *spi;
0079 struct mutex mutex;
0080
0081 struct backlight_device *bl_dev;
0082 };
0083
0084 static const struct omap_video_timings acx565akm_panel_timings = {
0085 .x_res = 800,
0086 .y_res = 480,
0087 .pixelclock = 24000000,
0088 .hfp = 28,
0089 .hsw = 4,
0090 .hbp = 24,
0091 .vfp = 3,
0092 .vsw = 3,
0093 .vbp = 4,
0094
0095 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
0096 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
0097
0098 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
0099 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
0100 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
0101 };
0102
0103 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
0104
0105 static void acx565akm_transfer(struct panel_drv_data *ddata, int cmd,
0106 const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
0107 {
0108 struct spi_message m;
0109 struct spi_transfer *x, xfer[5];
0110 int r;
0111
0112 BUG_ON(ddata->spi == NULL);
0113
0114 spi_message_init(&m);
0115
0116 memset(xfer, 0, sizeof(xfer));
0117 x = &xfer[0];
0118
0119 cmd &= 0xff;
0120 x->tx_buf = &cmd;
0121 x->bits_per_word = 9;
0122 x->len = 2;
0123
0124 if (rlen > 1 && wlen == 0) {
0125
0126
0127
0128
0129
0130 x->bits_per_word = 10;
0131 cmd <<= 1;
0132 }
0133 spi_message_add_tail(x, &m);
0134
0135 if (wlen) {
0136 x++;
0137 x->tx_buf = wbuf;
0138 x->len = wlen;
0139 x->bits_per_word = 9;
0140 spi_message_add_tail(x, &m);
0141 }
0142
0143 if (rlen) {
0144 x++;
0145 x->rx_buf = rbuf;
0146 x->len = rlen;
0147 spi_message_add_tail(x, &m);
0148 }
0149
0150 r = spi_sync(ddata->spi, &m);
0151 if (r < 0)
0152 dev_dbg(&ddata->spi->dev, "spi_sync %d\n", r);
0153 }
0154
0155 static inline void acx565akm_cmd(struct panel_drv_data *ddata, int cmd)
0156 {
0157 acx565akm_transfer(ddata, cmd, NULL, 0, NULL, 0);
0158 }
0159
0160 static inline void acx565akm_write(struct panel_drv_data *ddata,
0161 int reg, const u8 *buf, int len)
0162 {
0163 acx565akm_transfer(ddata, reg, buf, len, NULL, 0);
0164 }
0165
0166 static inline void acx565akm_read(struct panel_drv_data *ddata,
0167 int reg, u8 *buf, int len)
0168 {
0169 acx565akm_transfer(ddata, reg, NULL, 0, buf, len);
0170 }
0171
0172 static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
0173 {
0174 ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
0175 ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
0176 }
0177
0178 static void hw_guard_wait(struct panel_drv_data *ddata)
0179 {
0180 unsigned long wait = ddata->hw_guard_end - jiffies;
0181
0182 if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
0183 set_current_state(TASK_UNINTERRUPTIBLE);
0184 schedule_timeout(wait);
0185 }
0186 }
0187
0188 static void set_sleep_mode(struct panel_drv_data *ddata, int on)
0189 {
0190 int cmd;
0191
0192 if (on)
0193 cmd = MIPID_CMD_SLEEP_IN;
0194 else
0195 cmd = MIPID_CMD_SLEEP_OUT;
0196
0197
0198
0199
0200 hw_guard_wait(ddata);
0201 acx565akm_cmd(ddata, cmd);
0202 hw_guard_start(ddata, 120);
0203 }
0204
0205 static void set_display_state(struct panel_drv_data *ddata, int enabled)
0206 {
0207 int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
0208
0209 acx565akm_cmd(ddata, cmd);
0210 }
0211
0212 static int panel_enabled(struct panel_drv_data *ddata)
0213 {
0214 u32 disp_status;
0215 int enabled;
0216
0217 acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS,
0218 (u8 *)&disp_status, 4);
0219 disp_status = __be32_to_cpu(disp_status);
0220 enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
0221 dev_dbg(&ddata->spi->dev,
0222 "LCD panel %senabled by bootloader (status 0x%04x)\n",
0223 enabled ? "" : "not ", disp_status);
0224 return enabled;
0225 }
0226
0227 static int panel_detect(struct panel_drv_data *ddata)
0228 {
0229 acx565akm_read(ddata, MIPID_CMD_READ_DISP_ID, ddata->display_id, 3);
0230 dev_dbg(&ddata->spi->dev, "MIPI display ID: %02x%02x%02x\n",
0231 ddata->display_id[0],
0232 ddata->display_id[1],
0233 ddata->display_id[2]);
0234
0235 switch (ddata->display_id[0]) {
0236 case 0x10:
0237 ddata->model = MIPID_VER_ACX565AKM;
0238 ddata->name = "acx565akm";
0239 ddata->has_bc = 1;
0240 ddata->has_cabc = 1;
0241 break;
0242 case 0x29:
0243 ddata->model = MIPID_VER_L4F00311;
0244 ddata->name = "l4f00311";
0245 break;
0246 case 0x45:
0247 ddata->model = MIPID_VER_LPH8923;
0248 ddata->name = "lph8923";
0249 break;
0250 case 0x83:
0251 ddata->model = MIPID_VER_LS041Y3;
0252 ddata->name = "ls041y3";
0253 break;
0254 default:
0255 ddata->name = "unknown";
0256 dev_err(&ddata->spi->dev, "invalid display ID\n");
0257 return -ENODEV;
0258 }
0259
0260 ddata->revision = ddata->display_id[1];
0261
0262 dev_info(&ddata->spi->dev, "omapfb: %s rev %02x LCD detected\n",
0263 ddata->name, ddata->revision);
0264
0265 return 0;
0266 }
0267
0268
0269
0270 static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable)
0271 {
0272 u16 ctrl;
0273
0274 acx565akm_read(ddata, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
0275 if (enable) {
0276 ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
0277 CTRL_DISP_BACKLIGHT_ON;
0278 } else {
0279 ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
0280 CTRL_DISP_BACKLIGHT_ON);
0281 }
0282
0283 ctrl |= 1 << 8;
0284 acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
0285 }
0286
0287 static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode)
0288 {
0289 u16 cabc_ctrl;
0290
0291 ddata->cabc_mode = mode;
0292 if (!ddata->enabled)
0293 return;
0294 cabc_ctrl = 0;
0295 acx565akm_read(ddata, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
0296 cabc_ctrl &= ~3;
0297 cabc_ctrl |= (1 << 8) | (mode & 3);
0298 acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
0299 }
0300
0301 static unsigned get_cabc_mode(struct panel_drv_data *ddata)
0302 {
0303 return ddata->cabc_mode;
0304 }
0305
0306 static unsigned get_hw_cabc_mode(struct panel_drv_data *ddata)
0307 {
0308 u8 cabc_ctrl;
0309
0310 acx565akm_read(ddata, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
0311 return cabc_ctrl & 3;
0312 }
0313
0314 static void acx565akm_set_brightness(struct panel_drv_data *ddata, int level)
0315 {
0316 int bv;
0317
0318 bv = level | (1 << 8);
0319 acx565akm_write(ddata, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
0320
0321 if (level)
0322 enable_backlight_ctrl(ddata, 1);
0323 else
0324 enable_backlight_ctrl(ddata, 0);
0325 }
0326
0327 static int acx565akm_get_actual_brightness(struct panel_drv_data *ddata)
0328 {
0329 u8 bv;
0330
0331 acx565akm_read(ddata, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
0332
0333 return bv;
0334 }
0335
0336
0337 static int acx565akm_bl_update_status(struct backlight_device *dev)
0338 {
0339 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
0340 int level;
0341
0342 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
0343
0344 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
0345 dev->props.power == FB_BLANK_UNBLANK)
0346 level = dev->props.brightness;
0347 else
0348 level = 0;
0349
0350 if (ddata->has_bc)
0351 acx565akm_set_brightness(ddata, level);
0352 else
0353 return -ENODEV;
0354
0355 return 0;
0356 }
0357
0358 static int acx565akm_bl_get_intensity(struct backlight_device *dev)
0359 {
0360 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
0361
0362 dev_dbg(&dev->dev, "%s\n", __func__);
0363
0364 if (!ddata->has_bc)
0365 return -ENODEV;
0366
0367 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
0368 dev->props.power == FB_BLANK_UNBLANK) {
0369 if (ddata->has_bc)
0370 return acx565akm_get_actual_brightness(ddata);
0371 else
0372 return dev->props.brightness;
0373 }
0374
0375 return 0;
0376 }
0377
0378 static int acx565akm_bl_update_status_locked(struct backlight_device *dev)
0379 {
0380 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
0381 int r;
0382
0383 mutex_lock(&ddata->mutex);
0384 r = acx565akm_bl_update_status(dev);
0385 mutex_unlock(&ddata->mutex);
0386
0387 return r;
0388 }
0389
0390 static int acx565akm_bl_get_intensity_locked(struct backlight_device *dev)
0391 {
0392 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
0393 int r;
0394
0395 mutex_lock(&ddata->mutex);
0396 r = acx565akm_bl_get_intensity(dev);
0397 mutex_unlock(&ddata->mutex);
0398
0399 return r;
0400 }
0401
0402 static const struct backlight_ops acx565akm_bl_ops = {
0403 .get_brightness = acx565akm_bl_get_intensity_locked,
0404 .update_status = acx565akm_bl_update_status_locked,
0405 };
0406
0407
0408
0409 static const char * const cabc_modes[] = {
0410 "off",
0411 "ui",
0412 "still-image",
0413 "moving-image",
0414 };
0415
0416 static ssize_t show_cabc_mode(struct device *dev,
0417 struct device_attribute *attr,
0418 char *buf)
0419 {
0420 struct panel_drv_data *ddata = dev_get_drvdata(dev);
0421 const char *mode_str;
0422 int mode;
0423 int len;
0424
0425 if (!ddata->has_cabc)
0426 mode = 0;
0427 else
0428 mode = get_cabc_mode(ddata);
0429 mode_str = "unknown";
0430 if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
0431 mode_str = cabc_modes[mode];
0432 len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
0433
0434 return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
0435 }
0436
0437 static ssize_t store_cabc_mode(struct device *dev,
0438 struct device_attribute *attr,
0439 const char *buf, size_t count)
0440 {
0441 struct panel_drv_data *ddata = dev_get_drvdata(dev);
0442 int i;
0443
0444 for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
0445 const char *mode_str = cabc_modes[i];
0446 int cmp_len = strlen(mode_str);
0447
0448 if (count > 0 && buf[count - 1] == '\n')
0449 count--;
0450 if (count != cmp_len)
0451 continue;
0452
0453 if (strncmp(buf, mode_str, cmp_len) == 0)
0454 break;
0455 }
0456
0457 if (i == ARRAY_SIZE(cabc_modes))
0458 return -EINVAL;
0459
0460 if (!ddata->has_cabc && i != 0)
0461 return -EINVAL;
0462
0463 mutex_lock(&ddata->mutex);
0464 set_cabc_mode(ddata, i);
0465 mutex_unlock(&ddata->mutex);
0466
0467 return count;
0468 }
0469
0470 static ssize_t show_cabc_available_modes(struct device *dev,
0471 struct device_attribute *attr,
0472 char *buf)
0473 {
0474 struct panel_drv_data *ddata = dev_get_drvdata(dev);
0475 int len;
0476 int i;
0477
0478 if (!ddata->has_cabc)
0479 return sysfs_emit(buf, "%s\n", cabc_modes[0]);
0480
0481 for (i = 0, len = 0;
0482 len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
0483 len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
0484 i ? " " : "", cabc_modes[i],
0485 i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
0486
0487 return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
0488 }
0489
0490 static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
0491 show_cabc_mode, store_cabc_mode);
0492 static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
0493 show_cabc_available_modes, NULL);
0494
0495 static struct attribute *bldev_attrs[] = {
0496 &dev_attr_cabc_mode.attr,
0497 &dev_attr_cabc_available_modes.attr,
0498 NULL,
0499 };
0500
0501 static const struct attribute_group bldev_attr_group = {
0502 .attrs = bldev_attrs,
0503 };
0504
0505 static int acx565akm_connect(struct omap_dss_device *dssdev)
0506 {
0507 struct panel_drv_data *ddata = to_panel_data(dssdev);
0508 struct omap_dss_device *in = ddata->in;
0509
0510 if (omapdss_device_is_connected(dssdev))
0511 return 0;
0512
0513 return in->ops.sdi->connect(in, dssdev);
0514 }
0515
0516 static void acx565akm_disconnect(struct omap_dss_device *dssdev)
0517 {
0518 struct panel_drv_data *ddata = to_panel_data(dssdev);
0519 struct omap_dss_device *in = ddata->in;
0520
0521 if (!omapdss_device_is_connected(dssdev))
0522 return;
0523
0524 in->ops.sdi->disconnect(in, dssdev);
0525 }
0526
0527 static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
0528 {
0529 struct panel_drv_data *ddata = to_panel_data(dssdev);
0530 struct omap_dss_device *in = ddata->in;
0531 int r;
0532
0533 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
0534
0535 in->ops.sdi->set_timings(in, &ddata->videomode);
0536
0537 if (ddata->datapairs > 0)
0538 in->ops.sdi->set_datapairs(in, ddata->datapairs);
0539
0540 r = in->ops.sdi->enable(in);
0541 if (r) {
0542 pr_err("%s sdi enable failed\n", __func__);
0543 return r;
0544 }
0545
0546
0547 msleep(50);
0548
0549 if (gpio_is_valid(ddata->reset_gpio))
0550 gpio_set_value(ddata->reset_gpio, 1);
0551
0552 if (ddata->enabled) {
0553 dev_dbg(&ddata->spi->dev, "panel already enabled\n");
0554 return 0;
0555 }
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565 msleep(120);
0566
0567 set_sleep_mode(ddata, 0);
0568 ddata->enabled = 1;
0569
0570
0571 usleep_range(5000, 10000);
0572 set_display_state(ddata, 1);
0573 set_cabc_mode(ddata, ddata->cabc_mode);
0574
0575 return acx565akm_bl_update_status(ddata->bl_dev);
0576 }
0577
0578 static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
0579 {
0580 struct panel_drv_data *ddata = to_panel_data(dssdev);
0581 struct omap_dss_device *in = ddata->in;
0582
0583 dev_dbg(dssdev->dev, "%s\n", __func__);
0584
0585 if (!ddata->enabled)
0586 return;
0587
0588 set_display_state(ddata, 0);
0589 set_sleep_mode(ddata, 1);
0590 ddata->enabled = 0;
0591
0592
0593
0594
0595
0596
0597 msleep(50);
0598
0599 if (gpio_is_valid(ddata->reset_gpio))
0600 gpio_set_value(ddata->reset_gpio, 0);
0601
0602
0603 msleep(100);
0604
0605 in->ops.sdi->disable(in);
0606 }
0607
0608 static int acx565akm_enable(struct omap_dss_device *dssdev)
0609 {
0610 struct panel_drv_data *ddata = to_panel_data(dssdev);
0611 int r;
0612
0613 dev_dbg(dssdev->dev, "%s\n", __func__);
0614
0615 if (!omapdss_device_is_connected(dssdev))
0616 return -ENODEV;
0617
0618 if (omapdss_device_is_enabled(dssdev))
0619 return 0;
0620
0621 mutex_lock(&ddata->mutex);
0622 r = acx565akm_panel_power_on(dssdev);
0623 mutex_unlock(&ddata->mutex);
0624 if (r)
0625 return r;
0626
0627 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
0628
0629 return 0;
0630 }
0631
0632 static void acx565akm_disable(struct omap_dss_device *dssdev)
0633 {
0634 struct panel_drv_data *ddata = to_panel_data(dssdev);
0635
0636 dev_dbg(dssdev->dev, "%s\n", __func__);
0637
0638 if (!omapdss_device_is_enabled(dssdev))
0639 return;
0640
0641 mutex_lock(&ddata->mutex);
0642 acx565akm_panel_power_off(dssdev);
0643 mutex_unlock(&ddata->mutex);
0644
0645 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
0646 }
0647
0648 static void acx565akm_set_timings(struct omap_dss_device *dssdev,
0649 struct omap_video_timings *timings)
0650 {
0651 struct panel_drv_data *ddata = to_panel_data(dssdev);
0652 struct omap_dss_device *in = ddata->in;
0653
0654 ddata->videomode = *timings;
0655 dssdev->panel.timings = *timings;
0656
0657 in->ops.sdi->set_timings(in, timings);
0658 }
0659
0660 static void acx565akm_get_timings(struct omap_dss_device *dssdev,
0661 struct omap_video_timings *timings)
0662 {
0663 struct panel_drv_data *ddata = to_panel_data(dssdev);
0664
0665 *timings = ddata->videomode;
0666 }
0667
0668 static int acx565akm_check_timings(struct omap_dss_device *dssdev,
0669 struct omap_video_timings *timings)
0670 {
0671 struct panel_drv_data *ddata = to_panel_data(dssdev);
0672 struct omap_dss_device *in = ddata->in;
0673
0674 return in->ops.sdi->check_timings(in, timings);
0675 }
0676
0677 static struct omap_dss_driver acx565akm_ops = {
0678 .connect = acx565akm_connect,
0679 .disconnect = acx565akm_disconnect,
0680
0681 .enable = acx565akm_enable,
0682 .disable = acx565akm_disable,
0683
0684 .set_timings = acx565akm_set_timings,
0685 .get_timings = acx565akm_get_timings,
0686 .check_timings = acx565akm_check_timings,
0687
0688 .get_resolution = omapdss_default_get_resolution,
0689 };
0690
0691 static int acx565akm_probe_pdata(struct spi_device *spi)
0692 {
0693 const struct panel_acx565akm_platform_data *pdata;
0694 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
0695 struct omap_dss_device *dssdev, *in;
0696
0697 pdata = dev_get_platdata(&spi->dev);
0698
0699 ddata->reset_gpio = pdata->reset_gpio;
0700
0701 in = omap_dss_find_output(pdata->source);
0702 if (in == NULL) {
0703 dev_err(&spi->dev, "failed to find video source '%s'\n",
0704 pdata->source);
0705 return -EPROBE_DEFER;
0706 }
0707 ddata->in = in;
0708
0709 ddata->datapairs = pdata->datapairs;
0710
0711 dssdev = &ddata->dssdev;
0712 dssdev->name = pdata->name;
0713
0714 return 0;
0715 }
0716
0717 static int acx565akm_probe_of(struct spi_device *spi)
0718 {
0719 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
0720 struct device_node *np = spi->dev.of_node;
0721
0722 ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
0723
0724 ddata->in = omapdss_of_find_source_for_first_ep(np);
0725 if (IS_ERR(ddata->in)) {
0726 dev_err(&spi->dev, "failed to find video source\n");
0727 return PTR_ERR(ddata->in);
0728 }
0729
0730 return 0;
0731 }
0732
0733 static int acx565akm_probe(struct spi_device *spi)
0734 {
0735 struct panel_drv_data *ddata;
0736 struct omap_dss_device *dssdev;
0737 struct backlight_device *bldev;
0738 int max_brightness, brightness;
0739 struct backlight_properties props;
0740 int r;
0741
0742 dev_dbg(&spi->dev, "%s\n", __func__);
0743
0744 spi->mode = SPI_MODE_3;
0745
0746 ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
0747 if (ddata == NULL)
0748 return -ENOMEM;
0749
0750 dev_set_drvdata(&spi->dev, ddata);
0751
0752 ddata->spi = spi;
0753
0754 mutex_init(&ddata->mutex);
0755
0756 if (dev_get_platdata(&spi->dev)) {
0757 r = acx565akm_probe_pdata(spi);
0758 if (r)
0759 return r;
0760 } else if (spi->dev.of_node) {
0761 r = acx565akm_probe_of(spi);
0762 if (r)
0763 return r;
0764 } else {
0765 dev_err(&spi->dev, "platform data missing!\n");
0766 return -ENODEV;
0767 }
0768
0769 if (gpio_is_valid(ddata->reset_gpio)) {
0770 r = devm_gpio_request_one(&spi->dev, ddata->reset_gpio,
0771 GPIOF_OUT_INIT_LOW, "lcd reset");
0772 if (r)
0773 goto err_gpio;
0774 }
0775
0776 if (gpio_is_valid(ddata->reset_gpio))
0777 gpio_set_value(ddata->reset_gpio, 1);
0778
0779
0780
0781
0782
0783 usleep_range(5000, 10000);
0784
0785 ddata->enabled = panel_enabled(ddata);
0786
0787 r = panel_detect(ddata);
0788
0789 if (!ddata->enabled && gpio_is_valid(ddata->reset_gpio))
0790 gpio_set_value(ddata->reset_gpio, 0);
0791
0792 if (r) {
0793 dev_err(&spi->dev, "%s panel detect error\n", __func__);
0794 goto err_detect;
0795 }
0796
0797 memset(&props, 0, sizeof(props));
0798 props.fb_blank = FB_BLANK_UNBLANK;
0799 props.power = FB_BLANK_UNBLANK;
0800 props.type = BACKLIGHT_RAW;
0801
0802 bldev = backlight_device_register("acx565akm", &ddata->spi->dev,
0803 ddata, &acx565akm_bl_ops, &props);
0804 if (IS_ERR(bldev)) {
0805 r = PTR_ERR(bldev);
0806 goto err_reg_bl;
0807 }
0808 ddata->bl_dev = bldev;
0809 if (ddata->has_cabc) {
0810 r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
0811 if (r) {
0812 dev_err(&bldev->dev,
0813 "%s failed to create sysfs files\n", __func__);
0814 goto err_sysfs;
0815 }
0816 ddata->cabc_mode = get_hw_cabc_mode(ddata);
0817 }
0818
0819 max_brightness = 255;
0820
0821 if (ddata->has_bc)
0822 brightness = acx565akm_get_actual_brightness(ddata);
0823 else
0824 brightness = 0;
0825
0826 bldev->props.max_brightness = max_brightness;
0827 bldev->props.brightness = brightness;
0828
0829 acx565akm_bl_update_status(bldev);
0830
0831
0832 ddata->videomode = acx565akm_panel_timings;
0833
0834 dssdev = &ddata->dssdev;
0835 dssdev->dev = &spi->dev;
0836 dssdev->driver = &acx565akm_ops;
0837 dssdev->type = OMAP_DISPLAY_TYPE_SDI;
0838 dssdev->owner = THIS_MODULE;
0839 dssdev->panel.timings = ddata->videomode;
0840
0841 r = omapdss_register_display(dssdev);
0842 if (r) {
0843 dev_err(&spi->dev, "Failed to register panel\n");
0844 goto err_reg;
0845 }
0846
0847 return 0;
0848
0849 err_reg:
0850 sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group);
0851 err_sysfs:
0852 backlight_device_unregister(bldev);
0853 err_reg_bl:
0854 err_detect:
0855 err_gpio:
0856 omap_dss_put_device(ddata->in);
0857 return r;
0858 }
0859
0860 static void acx565akm_remove(struct spi_device *spi)
0861 {
0862 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
0863 struct omap_dss_device *dssdev = &ddata->dssdev;
0864 struct omap_dss_device *in = ddata->in;
0865
0866 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
0867
0868 sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group);
0869 backlight_device_unregister(ddata->bl_dev);
0870
0871 omapdss_unregister_display(dssdev);
0872
0873 acx565akm_disable(dssdev);
0874 acx565akm_disconnect(dssdev);
0875
0876 omap_dss_put_device(in);
0877 }
0878
0879 static const struct of_device_id acx565akm_of_match[] = {
0880 { .compatible = "omapdss,sony,acx565akm", },
0881 {},
0882 };
0883 MODULE_DEVICE_TABLE(of, acx565akm_of_match);
0884
0885 static struct spi_driver acx565akm_driver = {
0886 .driver = {
0887 .name = "acx565akm",
0888 .of_match_table = acx565akm_of_match,
0889 .suppress_bind_attrs = true,
0890 },
0891 .probe = acx565akm_probe,
0892 .remove = acx565akm_remove,
0893 };
0894
0895 module_spi_driver(acx565akm_driver);
0896
0897 MODULE_AUTHOR("Nokia Corporation");
0898 MODULE_DESCRIPTION("acx565akm LCD Driver");
0899 MODULE_LICENSE("GPL");