1290 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic DSI Command Mode panel driver4 *5 * Copyright (C) 2013 Texas Instruments6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>7 */8 9/* #define DEBUG */10 11#include <linux/backlight.h>12#include <linux/delay.h>13#include <linux/err.h>14#include <linux/fb.h>15#include <linux/gpio/consumer.h>16#include <linux/interrupt.h>17#include <linux/jiffies.h>18#include <linux/mod_devicetable.h>19#include <linux/module.h>20#include <linux/platform_device.h>21#include <linux/sched/signal.h>22#include <linux/slab.h>23#include <linux/workqueue.h>24 25#include <video/omapfb_dss.h>26#include <video/mipi_display.h>27 28/* DSI Virtual channel. Hardcoded for now. */29#define TCH 030 31#define DCS_READ_NUM_ERRORS 0x0532#define DCS_BRIGHTNESS 0x5133#define DCS_CTRL_DISPLAY 0x5334#define DCS_GET_ID1 0xda35#define DCS_GET_ID2 0xdb36#define DCS_GET_ID3 0xdc37 38struct panel_drv_data {39 struct omap_dss_device dssdev;40 struct omap_dss_device *in;41 42 struct omap_video_timings timings;43 44 struct platform_device *pdev;45 46 struct mutex lock;47 48 struct backlight_device *bldev;49 50 unsigned long hw_guard_end; /* next value of jiffies when we can51 * issue the next sleep in/out command52 */53 unsigned long hw_guard_wait; /* max guard time in jiffies */54 55 /* panel HW configuration from DT or platform data */56 struct gpio_desc *reset_gpio;57 struct gpio_desc *ext_te_gpio;58 59 bool use_dsi_backlight;60 61 struct omap_dsi_pin_config pin_config;62 63 /* runtime variables */64 bool enabled;65 66 bool te_enabled;67 68 atomic_t do_update;69 int channel;70 71 struct delayed_work te_timeout_work;72 73 bool intro_printed;74 75 bool ulps_enabled;76 unsigned ulps_timeout;77 struct delayed_work ulps_work;78};79 80#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)81 82static irqreturn_t dsicm_te_isr(int irq, void *data);83static void dsicm_te_timeout_work_callback(struct work_struct *work);84static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable);85 86static int dsicm_panel_reset(struct panel_drv_data *ddata);87 88static void dsicm_ulps_work(struct work_struct *work);89 90static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)91{92 ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);93 ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;94}95 96static void hw_guard_wait(struct panel_drv_data *ddata)97{98 unsigned long wait = ddata->hw_guard_end - jiffies;99 100 if ((long)wait > 0 && time_before_eq(wait, ddata->hw_guard_wait)) {101 set_current_state(TASK_UNINTERRUPTIBLE);102 schedule_timeout(wait);103 }104}105 106static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)107{108 struct omap_dss_device *in = ddata->in;109 int r;110 u8 buf[1];111 112 r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1);113 114 if (r < 0)115 return r;116 117 *data = buf[0];118 119 return 0;120}121 122static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)123{124 struct omap_dss_device *in = ddata->in;125 return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1);126}127 128static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)129{130 struct omap_dss_device *in = ddata->in;131 u8 buf[2] = { dcs_cmd, param };132 133 return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2);134}135 136static int dsicm_sleep_in(struct panel_drv_data *ddata)137 138{139 struct omap_dss_device *in = ddata->in;140 u8 cmd;141 int r;142 143 hw_guard_wait(ddata);144 145 cmd = MIPI_DCS_ENTER_SLEEP_MODE;146 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1);147 if (r)148 return r;149 150 hw_guard_start(ddata, 120);151 152 usleep_range(5000, 10000);153 154 return 0;155}156 157static int dsicm_sleep_out(struct panel_drv_data *ddata)158{159 int r;160 161 hw_guard_wait(ddata);162 163 r = dsicm_dcs_write_0(ddata, MIPI_DCS_EXIT_SLEEP_MODE);164 if (r)165 return r;166 167 hw_guard_start(ddata, 120);168 169 usleep_range(5000, 10000);170 171 return 0;172}173 174static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)175{176 int r;177 178 r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);179 if (r)180 return r;181 r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);182 if (r)183 return r;184 r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);185 if (r)186 return r;187 188 return 0;189}190 191static int dsicm_set_update_window(struct panel_drv_data *ddata,192 u16 x, u16 y, u16 w, u16 h)193{194 struct omap_dss_device *in = ddata->in;195 int r;196 u16 x1 = x;197 u16 x2 = x + w - 1;198 u16 y1 = y;199 u16 y2 = y + h - 1;200 201 u8 buf[5];202 buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;203 buf[1] = (x1 >> 8) & 0xff;204 buf[2] = (x1 >> 0) & 0xff;205 buf[3] = (x2 >> 8) & 0xff;206 buf[4] = (x2 >> 0) & 0xff;207 208 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));209 if (r)210 return r;211 212 buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;213 buf[1] = (y1 >> 8) & 0xff;214 buf[2] = (y1 >> 0) & 0xff;215 buf[3] = (y2 >> 8) & 0xff;216 buf[4] = (y2 >> 0) & 0xff;217 218 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));219 if (r)220 return r;221 222 in->ops.dsi->bta_sync(in, ddata->channel);223 224 return r;225}226 227static void dsicm_queue_ulps_work(struct panel_drv_data *ddata)228{229 if (ddata->ulps_timeout > 0)230 schedule_delayed_work(&ddata->ulps_work,231 msecs_to_jiffies(ddata->ulps_timeout));232}233 234static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)235{236 cancel_delayed_work(&ddata->ulps_work);237}238 239static int dsicm_enter_ulps(struct panel_drv_data *ddata)240{241 struct omap_dss_device *in = ddata->in;242 int r;243 244 if (ddata->ulps_enabled)245 return 0;246 247 dsicm_cancel_ulps_work(ddata);248 249 r = _dsicm_enable_te(ddata, false);250 if (r)251 goto err;252 253 if (ddata->ext_te_gpio)254 disable_irq(gpiod_to_irq(ddata->ext_te_gpio));255 256 in->ops.dsi->disable(in, false, true);257 258 ddata->ulps_enabled = true;259 260 return 0;261 262err:263 dev_err(&ddata->pdev->dev, "enter ULPS failed");264 dsicm_panel_reset(ddata);265 266 ddata->ulps_enabled = false;267 268 dsicm_queue_ulps_work(ddata);269 270 return r;271}272 273static int dsicm_exit_ulps(struct panel_drv_data *ddata)274{275 struct omap_dss_device *in = ddata->in;276 int r;277 278 if (!ddata->ulps_enabled)279 return 0;280 281 r = in->ops.dsi->enable(in);282 if (r) {283 dev_err(&ddata->pdev->dev, "failed to enable DSI\n");284 goto err1;285 }286 287 in->ops.dsi->enable_hs(in, ddata->channel, true);288 289 r = _dsicm_enable_te(ddata, true);290 if (r) {291 dev_err(&ddata->pdev->dev, "failed to re-enable TE");292 goto err2;293 }294 295 if (ddata->ext_te_gpio)296 enable_irq(gpiod_to_irq(ddata->ext_te_gpio));297 298 dsicm_queue_ulps_work(ddata);299 300 ddata->ulps_enabled = false;301 302 return 0;303 304err2:305 dev_err(&ddata->pdev->dev, "failed to exit ULPS");306 307 r = dsicm_panel_reset(ddata);308 if (!r) {309 if (ddata->ext_te_gpio)310 enable_irq(gpiod_to_irq(ddata->ext_te_gpio));311 ddata->ulps_enabled = false;312 }313err1:314 dsicm_queue_ulps_work(ddata);315 316 return r;317}318 319static int dsicm_wake_up(struct panel_drv_data *ddata)320{321 if (ddata->ulps_enabled)322 return dsicm_exit_ulps(ddata);323 324 dsicm_cancel_ulps_work(ddata);325 dsicm_queue_ulps_work(ddata);326 return 0;327}328 329static int dsicm_bl_update_status(struct backlight_device *dev)330{331 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);332 struct omap_dss_device *in = ddata->in;333 int r;334 int level = backlight_get_brightness(dev);335 336 dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level);337 338 mutex_lock(&ddata->lock);339 340 if (ddata->enabled) {341 in->ops.dsi->bus_lock(in);342 343 r = dsicm_wake_up(ddata);344 if (!r)345 r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);346 347 in->ops.dsi->bus_unlock(in);348 } else {349 r = 0;350 }351 352 mutex_unlock(&ddata->lock);353 354 return r;355}356 357static int dsicm_bl_get_intensity(struct backlight_device *dev)358{359 return backlight_get_brightness(dev);360}361 362static const struct backlight_ops dsicm_bl_ops = {363 .get_brightness = dsicm_bl_get_intensity,364 .update_status = dsicm_bl_update_status,365};366 367static void dsicm_get_resolution(struct omap_dss_device *dssdev,368 u16 *xres, u16 *yres)369{370 *xres = dssdev->panel.timings.x_res;371 *yres = dssdev->panel.timings.y_res;372}373 374static ssize_t dsicm_num_errors_show(struct device *dev,375 struct device_attribute *attr, char *buf)376{377 struct panel_drv_data *ddata = dev_get_drvdata(dev);378 struct omap_dss_device *in = ddata->in;379 u8 errors = 0;380 int r;381 382 mutex_lock(&ddata->lock);383 384 if (ddata->enabled) {385 in->ops.dsi->bus_lock(in);386 387 r = dsicm_wake_up(ddata);388 if (!r)389 r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS,390 &errors);391 392 in->ops.dsi->bus_unlock(in);393 } else {394 r = -ENODEV;395 }396 397 mutex_unlock(&ddata->lock);398 399 if (r)400 return r;401 402 return sysfs_emit(buf, "%d\n", errors);403}404 405static ssize_t dsicm_hw_revision_show(struct device *dev,406 struct device_attribute *attr, char *buf)407{408 struct panel_drv_data *ddata = dev_get_drvdata(dev);409 struct omap_dss_device *in = ddata->in;410 u8 id1, id2, id3;411 int r;412 413 mutex_lock(&ddata->lock);414 415 if (ddata->enabled) {416 in->ops.dsi->bus_lock(in);417 418 r = dsicm_wake_up(ddata);419 if (!r)420 r = dsicm_get_id(ddata, &id1, &id2, &id3);421 422 in->ops.dsi->bus_unlock(in);423 } else {424 r = -ENODEV;425 }426 427 mutex_unlock(&ddata->lock);428 429 if (r)430 return r;431 432 return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3);433}434 435static ssize_t dsicm_store_ulps(struct device *dev,436 struct device_attribute *attr,437 const char *buf, size_t count)438{439 struct panel_drv_data *ddata = dev_get_drvdata(dev);440 struct omap_dss_device *in = ddata->in;441 unsigned long t;442 int r;443 444 r = kstrtoul(buf, 0, &t);445 if (r)446 return r;447 448 mutex_lock(&ddata->lock);449 450 if (ddata->enabled) {451 in->ops.dsi->bus_lock(in);452 453 if (t)454 r = dsicm_enter_ulps(ddata);455 else456 r = dsicm_wake_up(ddata);457 458 in->ops.dsi->bus_unlock(in);459 }460 461 mutex_unlock(&ddata->lock);462 463 if (r)464 return r;465 466 return count;467}468 469static ssize_t dsicm_show_ulps(struct device *dev,470 struct device_attribute *attr,471 char *buf)472{473 struct panel_drv_data *ddata = dev_get_drvdata(dev);474 unsigned t;475 476 mutex_lock(&ddata->lock);477 t = ddata->ulps_enabled;478 mutex_unlock(&ddata->lock);479 480 return sysfs_emit(buf, "%u\n", t);481}482 483static ssize_t dsicm_store_ulps_timeout(struct device *dev,484 struct device_attribute *attr,485 const char *buf, size_t count)486{487 struct panel_drv_data *ddata = dev_get_drvdata(dev);488 struct omap_dss_device *in = ddata->in;489 unsigned long t;490 int r;491 492 r = kstrtoul(buf, 0, &t);493 if (r)494 return r;495 496 mutex_lock(&ddata->lock);497 ddata->ulps_timeout = t;498 499 if (ddata->enabled) {500 /* dsicm_wake_up will restart the timer */501 in->ops.dsi->bus_lock(in);502 r = dsicm_wake_up(ddata);503 in->ops.dsi->bus_unlock(in);504 }505 506 mutex_unlock(&ddata->lock);507 508 if (r)509 return r;510 511 return count;512}513 514static ssize_t dsicm_show_ulps_timeout(struct device *dev,515 struct device_attribute *attr,516 char *buf)517{518 struct panel_drv_data *ddata = dev_get_drvdata(dev);519 unsigned t;520 521 mutex_lock(&ddata->lock);522 t = ddata->ulps_timeout;523 mutex_unlock(&ddata->lock);524 525 return sysfs_emit(buf, "%u\n", t);526}527 528static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL);529static DEVICE_ATTR(hw_revision, S_IRUGO, dsicm_hw_revision_show, NULL);530static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,531 dsicm_show_ulps, dsicm_store_ulps);532static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,533 dsicm_show_ulps_timeout, dsicm_store_ulps_timeout);534 535static struct attribute *dsicm_attrs[] = {536 &dev_attr_num_dsi_errors.attr,537 &dev_attr_hw_revision.attr,538 &dev_attr_ulps.attr,539 &dev_attr_ulps_timeout.attr,540 NULL,541};542 543static const struct attribute_group dsicm_attr_group = {544 .attrs = dsicm_attrs,545};546 547static void dsicm_hw_reset(struct panel_drv_data *ddata)548{549 /*550 * Note that we appear to activate the reset line here. However551 * existing DTSes specified incorrect polarity for it (active high),552 * so in fact this deasserts the reset line.553 */554 gpiod_set_value_cansleep(ddata->reset_gpio, 1);555 udelay(10);556 /* reset the panel */557 gpiod_set_value_cansleep(ddata->reset_gpio, 0);558 /* keep reset asserted */559 udelay(10);560 /* release reset line */561 gpiod_set_value_cansleep(ddata->reset_gpio, 1);562 /* wait after releasing reset */563 usleep_range(5000, 10000);564}565 566static int dsicm_power_on(struct panel_drv_data *ddata)567{568 struct omap_dss_device *in = ddata->in;569 u8 id1, id2, id3;570 int r;571 struct omap_dss_dsi_config dsi_config = {572 .mode = OMAP_DSS_DSI_CMD_MODE,573 .pixel_format = OMAP_DSS_DSI_FMT_RGB888,574 .timings = &ddata->timings,575 .hs_clk_min = 150000000,576 .hs_clk_max = 300000000,577 .lp_clk_min = 7000000,578 .lp_clk_max = 10000000,579 };580 581 if (ddata->pin_config.num_pins > 0) {582 r = in->ops.dsi->configure_pins(in, &ddata->pin_config);583 if (r) {584 dev_err(&ddata->pdev->dev,585 "failed to configure DSI pins\n");586 goto err0;587 }588 }589 590 r = in->ops.dsi->set_config(in, &dsi_config);591 if (r) {592 dev_err(&ddata->pdev->dev, "failed to configure DSI\n");593 goto err0;594 }595 596 r = in->ops.dsi->enable(in);597 if (r) {598 dev_err(&ddata->pdev->dev, "failed to enable DSI\n");599 goto err0;600 }601 602 dsicm_hw_reset(ddata);603 604 in->ops.dsi->enable_hs(in, ddata->channel, false);605 606 r = dsicm_sleep_out(ddata);607 if (r)608 goto err;609 610 r = dsicm_get_id(ddata, &id1, &id2, &id3);611 if (r)612 goto err;613 614 r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, 0xff);615 if (r)616 goto err;617 618 r = dsicm_dcs_write_1(ddata, DCS_CTRL_DISPLAY,619 (1<<2) | (1<<5)); /* BL | BCTRL */620 if (r)621 goto err;622 623 r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_PIXEL_FORMAT,624 MIPI_DCS_PIXEL_FMT_24BIT);625 if (r)626 goto err;627 628 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_ON);629 if (r)630 goto err;631 632 r = _dsicm_enable_te(ddata, ddata->te_enabled);633 if (r)634 goto err;635 636 r = in->ops.dsi->enable_video_output(in, ddata->channel);637 if (r)638 goto err;639 640 ddata->enabled = 1;641 642 if (!ddata->intro_printed) {643 dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n",644 id1, id2, id3);645 ddata->intro_printed = true;646 }647 648 in->ops.dsi->enable_hs(in, ddata->channel, true);649 650 return 0;651err:652 dev_err(&ddata->pdev->dev, "error while enabling panel, issuing HW reset\n");653 654 dsicm_hw_reset(ddata);655 656 in->ops.dsi->disable(in, true, false);657err0:658 return r;659}660 661static void dsicm_power_off(struct panel_drv_data *ddata)662{663 struct omap_dss_device *in = ddata->in;664 int r;665 666 in->ops.dsi->disable_video_output(in, ddata->channel);667 668 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF);669 if (!r)670 r = dsicm_sleep_in(ddata);671 672 if (r) {673 dev_err(&ddata->pdev->dev,674 "error disabling panel, issuing HW reset\n");675 dsicm_hw_reset(ddata);676 }677 678 in->ops.dsi->disable(in, true, false);679 680 ddata->enabled = 0;681}682 683static int dsicm_panel_reset(struct panel_drv_data *ddata)684{685 dev_err(&ddata->pdev->dev, "performing LCD reset\n");686 687 dsicm_power_off(ddata);688 dsicm_hw_reset(ddata);689 return dsicm_power_on(ddata);690}691 692static int dsicm_connect(struct omap_dss_device *dssdev)693{694 struct panel_drv_data *ddata = to_panel_data(dssdev);695 struct omap_dss_device *in = ddata->in;696 struct device *dev = &ddata->pdev->dev;697 int r;698 699 if (omapdss_device_is_connected(dssdev))700 return 0;701 702 r = in->ops.dsi->connect(in, dssdev);703 if (r) {704 dev_err(dev, "Failed to connect to video source\n");705 return r;706 }707 708 r = in->ops.dsi->request_vc(ddata->in, &ddata->channel);709 if (r) {710 dev_err(dev, "failed to get virtual channel\n");711 goto err_req_vc;712 }713 714 r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH);715 if (r) {716 dev_err(dev, "failed to set VC_ID\n");717 goto err_vc_id;718 }719 720 return 0;721 722err_vc_id:723 in->ops.dsi->release_vc(ddata->in, ddata->channel);724err_req_vc:725 in->ops.dsi->disconnect(in, dssdev);726 return r;727}728 729static void dsicm_disconnect(struct omap_dss_device *dssdev)730{731 struct panel_drv_data *ddata = to_panel_data(dssdev);732 struct omap_dss_device *in = ddata->in;733 734 if (!omapdss_device_is_connected(dssdev))735 return;736 737 in->ops.dsi->release_vc(in, ddata->channel);738 in->ops.dsi->disconnect(in, dssdev);739}740 741static int dsicm_enable(struct omap_dss_device *dssdev)742{743 struct panel_drv_data *ddata = to_panel_data(dssdev);744 struct omap_dss_device *in = ddata->in;745 int r;746 747 dev_dbg(&ddata->pdev->dev, "enable\n");748 749 mutex_lock(&ddata->lock);750 751 if (!omapdss_device_is_connected(dssdev)) {752 r = -ENODEV;753 goto err;754 }755 756 if (omapdss_device_is_enabled(dssdev)) {757 r = 0;758 goto err;759 }760 761 in->ops.dsi->bus_lock(in);762 763 r = dsicm_power_on(ddata);764 765 in->ops.dsi->bus_unlock(in);766 767 if (r)768 goto err;769 770 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;771 772 mutex_unlock(&ddata->lock);773 774 return 0;775err:776 dev_dbg(&ddata->pdev->dev, "enable failed\n");777 mutex_unlock(&ddata->lock);778 return r;779}780 781static void dsicm_disable(struct omap_dss_device *dssdev)782{783 struct panel_drv_data *ddata = to_panel_data(dssdev);784 struct omap_dss_device *in = ddata->in;785 int r;786 787 dev_dbg(&ddata->pdev->dev, "disable\n");788 789 mutex_lock(&ddata->lock);790 791 dsicm_cancel_ulps_work(ddata);792 793 in->ops.dsi->bus_lock(in);794 795 if (omapdss_device_is_enabled(dssdev)) {796 r = dsicm_wake_up(ddata);797 if (!r)798 dsicm_power_off(ddata);799 }800 801 in->ops.dsi->bus_unlock(in);802 803 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;804 805 mutex_unlock(&ddata->lock);806}807 808static void dsicm_framedone_cb(int err, void *data)809{810 struct panel_drv_data *ddata = data;811 struct omap_dss_device *in = ddata->in;812 813 dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);814 in->ops.dsi->bus_unlock(ddata->in);815}816 817static irqreturn_t dsicm_te_isr(int irq, void *data)818{819 struct panel_drv_data *ddata = data;820 struct omap_dss_device *in = ddata->in;821 int old;822 int r;823 824 old = atomic_cmpxchg(&ddata->do_update, 1, 0);825 826 if (old) {827 cancel_delayed_work(&ddata->te_timeout_work);828 829 r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,830 ddata);831 if (r)832 goto err;833 }834 835 return IRQ_HANDLED;836err:837 dev_err(&ddata->pdev->dev, "start update failed\n");838 in->ops.dsi->bus_unlock(in);839 return IRQ_HANDLED;840}841 842static void dsicm_te_timeout_work_callback(struct work_struct *work)843{844 struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,845 te_timeout_work.work);846 struct omap_dss_device *in = ddata->in;847 848 dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");849 850 atomic_set(&ddata->do_update, 0);851 in->ops.dsi->bus_unlock(in);852}853 854static int dsicm_update(struct omap_dss_device *dssdev,855 u16 x, u16 y, u16 w, u16 h)856{857 struct panel_drv_data *ddata = to_panel_data(dssdev);858 struct omap_dss_device *in = ddata->in;859 int r;860 861 dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);862 863 mutex_lock(&ddata->lock);864 in->ops.dsi->bus_lock(in);865 866 r = dsicm_wake_up(ddata);867 if (r)868 goto err;869 870 if (!ddata->enabled) {871 r = 0;872 goto err;873 }874 875 /* XXX no need to send this every frame, but dsi break if not done */876 r = dsicm_set_update_window(ddata, 0, 0,877 dssdev->panel.timings.x_res,878 dssdev->panel.timings.y_res);879 if (r)880 goto err;881 882 if (ddata->te_enabled && ddata->ext_te_gpio) {883 schedule_delayed_work(&ddata->te_timeout_work,884 msecs_to_jiffies(250));885 atomic_set(&ddata->do_update, 1);886 } else {887 r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,888 ddata);889 if (r)890 goto err;891 }892 893 /* note: no bus_unlock here. unlock is in framedone_cb */894 mutex_unlock(&ddata->lock);895 return 0;896err:897 in->ops.dsi->bus_unlock(in);898 mutex_unlock(&ddata->lock);899 return r;900}901 902static int dsicm_sync(struct omap_dss_device *dssdev)903{904 struct panel_drv_data *ddata = to_panel_data(dssdev);905 struct omap_dss_device *in = ddata->in;906 907 dev_dbg(&ddata->pdev->dev, "sync\n");908 909 mutex_lock(&ddata->lock);910 in->ops.dsi->bus_lock(in);911 in->ops.dsi->bus_unlock(in);912 mutex_unlock(&ddata->lock);913 914 dev_dbg(&ddata->pdev->dev, "sync done\n");915 916 return 0;917}918 919static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)920{921 struct omap_dss_device *in = ddata->in;922 int r;923 924 if (enable)925 r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_TEAR_ON, 0);926 else927 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF);928 929 if (!ddata->ext_te_gpio)930 in->ops.dsi->enable_te(in, enable);931 932 /* possible panel bug */933 msleep(100);934 935 return r;936}937 938static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)939{940 struct panel_drv_data *ddata = to_panel_data(dssdev);941 struct omap_dss_device *in = ddata->in;942 int r;943 944 mutex_lock(&ddata->lock);945 946 if (ddata->te_enabled == enable)947 goto end;948 949 in->ops.dsi->bus_lock(in);950 951 if (ddata->enabled) {952 r = dsicm_wake_up(ddata);953 if (r)954 goto err;955 956 r = _dsicm_enable_te(ddata, enable);957 if (r)958 goto err;959 }960 961 ddata->te_enabled = enable;962 963 in->ops.dsi->bus_unlock(in);964end:965 mutex_unlock(&ddata->lock);966 967 return 0;968err:969 in->ops.dsi->bus_unlock(in);970 mutex_unlock(&ddata->lock);971 972 return r;973}974 975static int dsicm_get_te(struct omap_dss_device *dssdev)976{977 struct panel_drv_data *ddata = to_panel_data(dssdev);978 int r;979 980 mutex_lock(&ddata->lock);981 r = ddata->te_enabled;982 mutex_unlock(&ddata->lock);983 984 return r;985}986 987static int dsicm_memory_read(struct omap_dss_device *dssdev,988 void *buf, size_t size,989 u16 x, u16 y, u16 w, u16 h)990{991 struct panel_drv_data *ddata = to_panel_data(dssdev);992 struct omap_dss_device *in = ddata->in;993 int r;994 int first = 1;995 int plen;996 unsigned buf_used = 0;997 998 if (size < w * h * 3)999 return -ENOMEM;1000 1001 mutex_lock(&ddata->lock);1002 1003 if (!ddata->enabled) {1004 r = -ENODEV;1005 goto err1;1006 }1007 1008 size = min(w * h * 3,1009 dssdev->panel.timings.x_res *1010 dssdev->panel.timings.y_res * 3);1011 1012 in->ops.dsi->bus_lock(in);1013 1014 r = dsicm_wake_up(ddata);1015 if (r)1016 goto err2;1017 1018 /* plen 1 or 2 goes into short packet. until checksum error is fixed,1019 * use short packets. plen 32 works, but bigger packets seem to cause1020 * an error. */1021 if (size % 2)1022 plen = 1;1023 else1024 plen = 2;1025 1026 dsicm_set_update_window(ddata, x, y, w, h);1027 1028 r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen);1029 if (r)1030 goto err2;1031 1032 while (buf_used < size) {1033 u8 dcs_cmd = first ? 0x2e : 0x3e;1034 first = 0;1035 1036 r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd,1037 buf + buf_used, size - buf_used);1038 1039 if (r < 0) {1040 dev_err(dssdev->dev, "read error\n");1041 goto err3;1042 }1043 1044 buf_used += r;1045 1046 if (r < plen) {1047 dev_err(&ddata->pdev->dev, "short read\n");1048 break;1049 }1050 1051 if (signal_pending(current)) {1052 dev_err(&ddata->pdev->dev, "signal pending, "1053 "aborting memory read\n");1054 r = -ERESTARTSYS;1055 goto err3;1056 }1057 }1058 1059 r = buf_used;1060 1061err3:1062 in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1);1063err2:1064 in->ops.dsi->bus_unlock(in);1065err1:1066 mutex_unlock(&ddata->lock);1067 return r;1068}1069 1070static void dsicm_ulps_work(struct work_struct *work)1071{1072 struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,1073 ulps_work.work);1074 struct omap_dss_device *dssdev = &ddata->dssdev;1075 struct omap_dss_device *in = ddata->in;1076 1077 mutex_lock(&ddata->lock);1078 1079 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !ddata->enabled) {1080 mutex_unlock(&ddata->lock);1081 return;1082 }1083 1084 in->ops.dsi->bus_lock(in);1085 1086 dsicm_enter_ulps(ddata);1087 1088 in->ops.dsi->bus_unlock(in);1089 mutex_unlock(&ddata->lock);1090}1091 1092static struct omap_dss_driver dsicm_ops = {1093 .connect = dsicm_connect,1094 .disconnect = dsicm_disconnect,1095 1096 .enable = dsicm_enable,1097 .disable = dsicm_disable,1098 1099 .update = dsicm_update,1100 .sync = dsicm_sync,1101 1102 .get_resolution = dsicm_get_resolution,1103 .get_recommended_bpp = omapdss_default_get_recommended_bpp,1104 1105 .enable_te = dsicm_enable_te,1106 .get_te = dsicm_get_te,1107 1108 .memory_read = dsicm_memory_read,1109};1110 1111static int dsicm_probe(struct platform_device *pdev)1112{1113 struct backlight_properties props;1114 struct panel_drv_data *ddata;1115 struct backlight_device *bldev = NULL;1116 struct device *dev = &pdev->dev;1117 struct omap_dss_device *dssdev;1118 int r;1119 1120 dev_dbg(dev, "probe\n");1121 1122 if (!pdev->dev.of_node)1123 return -ENODEV;1124 1125 ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);1126 if (!ddata)1127 return -ENOMEM;1128 1129 platform_set_drvdata(pdev, ddata);1130 ddata->pdev = pdev;1131 1132 ddata->in = omapdss_of_find_source_for_first_ep(pdev->dev.of_node);1133 r = PTR_ERR_OR_ZERO(ddata->in);1134 if (r) {1135 dev_err(&pdev->dev, "failed to find video source: %d\n", r);1136 return r;1137 }1138 1139 ddata->timings.x_res = 864;1140 ddata->timings.y_res = 480;1141 ddata->timings.pixelclock = 864 * 480 * 60;1142 1143 dssdev = &ddata->dssdev;1144 dssdev->dev = dev;1145 dssdev->driver = &dsicm_ops;1146 dssdev->panel.timings = ddata->timings;1147 dssdev->type = OMAP_DISPLAY_TYPE_DSI;1148 dssdev->owner = THIS_MODULE;1149 1150 dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;1151 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |1152 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;1153 1154 r = omapdss_register_display(dssdev);1155 if (r) {1156 dev_err(dev, "Failed to register panel\n");1157 goto err_reg;1158 }1159 1160 mutex_init(&ddata->lock);1161 1162 atomic_set(&ddata->do_update, 0);1163 1164 ddata->reset_gpio = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);1165 r = PTR_ERR_OR_ZERO(ddata->reset_gpio);1166 if (r) {1167 dev_err(&pdev->dev, "Failed to request reset gpio: %d\n", r);1168 return r;1169 }1170 1171 gpiod_set_consumer_name(ddata->reset_gpio, "taal rst");1172 1173 ddata->ext_te_gpio = devm_gpiod_get_optional(&pdev->dev, "te",1174 GPIOD_IN);1175 r = PTR_ERR_OR_ZERO(ddata->ext_te_gpio);1176 if (r) {1177 dev_err(&pdev->dev, "Failed to request TE gpio: %d\n", r);1178 return r;1179 }1180 1181 if (ddata->ext_te_gpio) {1182 gpiod_set_consumer_name(ddata->ext_te_gpio, "taal irq");1183 1184 r = devm_request_irq(dev, gpiod_to_irq(ddata->ext_te_gpio),1185 dsicm_te_isr,1186 IRQF_TRIGGER_RISING,1187 "taal vsync", ddata);1188 1189 if (r) {1190 dev_err(dev, "IRQ request failed\n");1191 return r;1192 }1193 1194 INIT_DEFERRABLE_WORK(&ddata->te_timeout_work,1195 dsicm_te_timeout_work_callback);1196 1197 dev_dbg(dev, "Using GPIO TE\n");1198 }1199 1200 INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work);1201 1202 dsicm_hw_reset(ddata);1203 1204 if (ddata->use_dsi_backlight) {1205 memset(&props, 0, sizeof(struct backlight_properties));1206 props.max_brightness = 255;1207 1208 props.type = BACKLIGHT_RAW;1209 bldev = backlight_device_register(dev_name(dev),1210 dev, ddata, &dsicm_bl_ops, &props);1211 if (IS_ERR(bldev)) {1212 r = PTR_ERR(bldev);1213 goto err_reg;1214 }1215 1216 ddata->bldev = bldev;1217 1218 bldev->props.power = FB_BLANK_UNBLANK;1219 bldev->props.brightness = 255;1220 1221 dsicm_bl_update_status(bldev);1222 }1223 1224 r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);1225 if (r) {1226 dev_err(dev, "failed to create sysfs files\n");1227 goto err_sysfs_create;1228 }1229 1230 return 0;1231 1232err_sysfs_create:1233 if (bldev != NULL)1234 backlight_device_unregister(bldev);1235err_reg:1236 return r;1237}1238 1239static void dsicm_remove(struct platform_device *pdev)1240{1241 struct panel_drv_data *ddata = platform_get_drvdata(pdev);1242 struct omap_dss_device *dssdev = &ddata->dssdev;1243 struct backlight_device *bldev;1244 1245 dev_dbg(&pdev->dev, "remove\n");1246 1247 omapdss_unregister_display(dssdev);1248 1249 dsicm_disable(dssdev);1250 dsicm_disconnect(dssdev);1251 1252 sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);1253 1254 bldev = ddata->bldev;1255 if (bldev != NULL) {1256 bldev->props.power = FB_BLANK_POWERDOWN;1257 dsicm_bl_update_status(bldev);1258 backlight_device_unregister(bldev);1259 }1260 1261 omap_dss_put_device(ddata->in);1262 1263 dsicm_cancel_ulps_work(ddata);1264 1265 /* reset, to be sure that the panel is in a valid state */1266 dsicm_hw_reset(ddata);1267}1268 1269static const struct of_device_id dsicm_of_match[] = {1270 { .compatible = "omapdss,panel-dsi-cm", },1271 {},1272};1273 1274MODULE_DEVICE_TABLE(of, dsicm_of_match);1275 1276static struct platform_driver dsicm_driver = {1277 .probe = dsicm_probe,1278 .remove = dsicm_remove,1279 .driver = {1280 .name = "panel-dsi-cm",1281 .of_match_table = dsicm_of_match,1282 },1283};1284 1285module_platform_driver(dsicm_driver);1286 1287MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");1288MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");1289MODULE_LICENSE("GPL");1290