root/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. jbt_ret_write_0
  2. jbt_reg_write_1
  3. jbt_reg_write_2
  4. td028ttec1_panel_connect
  5. td028ttec1_panel_disconnect
  6. td028ttec1_panel_enable
  7. td028ttec1_panel_disable
  8. td028ttec1_panel_set_timings
  9. td028ttec1_panel_get_timings
  10. td028ttec1_panel_check_timings
  11. td028ttec1_probe_of
  12. td028ttec1_panel_probe
  13. td028ttec1_panel_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Toppoly TD028TTEC1 panel support
   4  *
   5  * Copyright (C) 2008 Nokia Corporation
   6  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
   7  *
   8  * Neo 1973 code (jbt6k74.c):
   9  * Copyright (C) 2006-2007 by OpenMoko, Inc.
  10  * Author: Harald Welte <laforge@openmoko.org>
  11  *
  12  * Ported and adapted from Neo 1973 U-Boot by:
  13  * H. Nikolaus Schaller <hns@goldelico.com>
  14  */
  15 
  16 #include <linux/module.h>
  17 #include <linux/delay.h>
  18 #include <linux/spi/spi.h>
  19 #include <linux/gpio.h>
  20 #include <video/omapfb_dss.h>
  21 
  22 struct panel_drv_data {
  23         struct omap_dss_device dssdev;
  24         struct omap_dss_device *in;
  25 
  26         int data_lines;
  27 
  28         struct omap_video_timings videomode;
  29 
  30         struct spi_device *spi_dev;
  31 };
  32 
  33 static const struct omap_video_timings td028ttec1_panel_timings = {
  34         .x_res          = 480,
  35         .y_res          = 640,
  36         .pixelclock     = 22153000,
  37         .hfp            = 24,
  38         .hsw            = 8,
  39         .hbp            = 8,
  40         .vfp            = 4,
  41         .vsw            = 2,
  42         .vbp            = 2,
  43 
  44         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  45         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  46 
  47         .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
  48         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
  49         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
  50 };
  51 
  52 #define JBT_COMMAND     0x000
  53 #define JBT_DATA        0x100
  54 
  55 static int jbt_ret_write_0(struct panel_drv_data *ddata, u8 reg)
  56 {
  57         int rc;
  58         u16 tx_buf = JBT_COMMAND | reg;
  59 
  60         rc = spi_write(ddata->spi_dev, (u8 *)&tx_buf,
  61                         1*sizeof(u16));
  62         if (rc != 0)
  63                 dev_err(&ddata->spi_dev->dev,
  64                         "jbt_ret_write_0 spi_write ret %d\n", rc);
  65 
  66         return rc;
  67 }
  68 
  69 static int jbt_reg_write_1(struct panel_drv_data *ddata, u8 reg, u8 data)
  70 {
  71         int rc;
  72         u16 tx_buf[2];
  73 
  74         tx_buf[0] = JBT_COMMAND | reg;
  75         tx_buf[1] = JBT_DATA | data;
  76         rc = spi_write(ddata->spi_dev, (u8 *)tx_buf,
  77                         2*sizeof(u16));
  78         if (rc != 0)
  79                 dev_err(&ddata->spi_dev->dev,
  80                         "jbt_reg_write_1 spi_write ret %d\n", rc);
  81 
  82         return rc;
  83 }
  84 
  85 static int jbt_reg_write_2(struct panel_drv_data *ddata, u8 reg, u16 data)
  86 {
  87         int rc;
  88         u16 tx_buf[3];
  89 
  90         tx_buf[0] = JBT_COMMAND | reg;
  91         tx_buf[1] = JBT_DATA | (data >> 8);
  92         tx_buf[2] = JBT_DATA | (data & 0xff);
  93 
  94         rc = spi_write(ddata->spi_dev, (u8 *)tx_buf,
  95                         3*sizeof(u16));
  96 
  97         if (rc != 0)
  98                 dev_err(&ddata->spi_dev->dev,
  99                         "jbt_reg_write_2 spi_write ret %d\n", rc);
 100 
 101         return rc;
 102 }
 103 
 104 enum jbt_register {
 105         JBT_REG_SLEEP_IN                = 0x10,
 106         JBT_REG_SLEEP_OUT               = 0x11,
 107 
 108         JBT_REG_DISPLAY_OFF             = 0x28,
 109         JBT_REG_DISPLAY_ON              = 0x29,
 110 
 111         JBT_REG_RGB_FORMAT              = 0x3a,
 112         JBT_REG_QUAD_RATE               = 0x3b,
 113 
 114         JBT_REG_POWER_ON_OFF            = 0xb0,
 115         JBT_REG_BOOSTER_OP              = 0xb1,
 116         JBT_REG_BOOSTER_MODE            = 0xb2,
 117         JBT_REG_BOOSTER_FREQ            = 0xb3,
 118         JBT_REG_OPAMP_SYSCLK            = 0xb4,
 119         JBT_REG_VSC_VOLTAGE             = 0xb5,
 120         JBT_REG_VCOM_VOLTAGE            = 0xb6,
 121         JBT_REG_EXT_DISPL               = 0xb7,
 122         JBT_REG_OUTPUT_CONTROL          = 0xb8,
 123         JBT_REG_DCCLK_DCEV              = 0xb9,
 124         JBT_REG_DISPLAY_MODE1           = 0xba,
 125         JBT_REG_DISPLAY_MODE2           = 0xbb,
 126         JBT_REG_DISPLAY_MODE            = 0xbc,
 127         JBT_REG_ASW_SLEW                = 0xbd,
 128         JBT_REG_DUMMY_DISPLAY           = 0xbe,
 129         JBT_REG_DRIVE_SYSTEM            = 0xbf,
 130 
 131         JBT_REG_SLEEP_OUT_FR_A          = 0xc0,
 132         JBT_REG_SLEEP_OUT_FR_B          = 0xc1,
 133         JBT_REG_SLEEP_OUT_FR_C          = 0xc2,
 134         JBT_REG_SLEEP_IN_LCCNT_D        = 0xc3,
 135         JBT_REG_SLEEP_IN_LCCNT_E        = 0xc4,
 136         JBT_REG_SLEEP_IN_LCCNT_F        = 0xc5,
 137         JBT_REG_SLEEP_IN_LCCNT_G        = 0xc6,
 138 
 139         JBT_REG_GAMMA1_FINE_1           = 0xc7,
 140         JBT_REG_GAMMA1_FINE_2           = 0xc8,
 141         JBT_REG_GAMMA1_INCLINATION      = 0xc9,
 142         JBT_REG_GAMMA1_BLUE_OFFSET      = 0xca,
 143 
 144         JBT_REG_BLANK_CONTROL           = 0xcf,
 145         JBT_REG_BLANK_TH_TV             = 0xd0,
 146         JBT_REG_CKV_ON_OFF              = 0xd1,
 147         JBT_REG_CKV_1_2                 = 0xd2,
 148         JBT_REG_OEV_TIMING              = 0xd3,
 149         JBT_REG_ASW_TIMING_1            = 0xd4,
 150         JBT_REG_ASW_TIMING_2            = 0xd5,
 151 
 152         JBT_REG_HCLOCK_VGA              = 0xec,
 153         JBT_REG_HCLOCK_QVGA             = 0xed,
 154 };
 155 
 156 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
 157 
 158 static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
 159 {
 160         struct panel_drv_data *ddata = to_panel_data(dssdev);
 161         struct omap_dss_device *in = ddata->in;
 162         int r;
 163 
 164         if (omapdss_device_is_connected(dssdev))
 165                 return 0;
 166 
 167         r = in->ops.dpi->connect(in, dssdev);
 168         if (r)
 169                 return r;
 170 
 171         return 0;
 172 }
 173 
 174 static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
 175 {
 176         struct panel_drv_data *ddata = to_panel_data(dssdev);
 177         struct omap_dss_device *in = ddata->in;
 178 
 179         if (!omapdss_device_is_connected(dssdev))
 180                 return;
 181 
 182         in->ops.dpi->disconnect(in, dssdev);
 183 }
 184 
 185 static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
 186 {
 187         struct panel_drv_data *ddata = to_panel_data(dssdev);
 188         struct omap_dss_device *in = ddata->in;
 189         int r;
 190 
 191         if (!omapdss_device_is_connected(dssdev))
 192                 return -ENODEV;
 193 
 194         if (omapdss_device_is_enabled(dssdev))
 195                 return 0;
 196 
 197         if (ddata->data_lines)
 198                 in->ops.dpi->set_data_lines(in, ddata->data_lines);
 199         in->ops.dpi->set_timings(in, &ddata->videomode);
 200 
 201         r = in->ops.dpi->enable(in);
 202         if (r)
 203                 return r;
 204 
 205         dev_dbg(dssdev->dev, "td028ttec1_panel_enable() - state %d\n",
 206                 dssdev->state);
 207 
 208         /* three times command zero */
 209         r |= jbt_ret_write_0(ddata, 0x00);
 210         usleep_range(1000, 2000);
 211         r |= jbt_ret_write_0(ddata, 0x00);
 212         usleep_range(1000, 2000);
 213         r |= jbt_ret_write_0(ddata, 0x00);
 214         usleep_range(1000, 2000);
 215 
 216         if (r) {
 217                 dev_warn(dssdev->dev, "transfer error\n");
 218                 goto transfer_err;
 219         }
 220 
 221         /* deep standby out */
 222         r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x17);
 223 
 224         /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */
 225         r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE, 0x80);
 226 
 227         /* Quad mode off */
 228         r |= jbt_reg_write_1(ddata, JBT_REG_QUAD_RATE, 0x00);
 229 
 230         /* AVDD on, XVDD on */
 231         r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x16);
 232 
 233         /* Output control */
 234         r |= jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0xfff9);
 235 
 236         /* Sleep mode off */
 237         r |= jbt_ret_write_0(ddata, JBT_REG_SLEEP_OUT);
 238 
 239         /* at this point we have like 50% grey */
 240 
 241         /* initialize register set */
 242         r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE1, 0x01);
 243         r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE2, 0x00);
 244         r |= jbt_reg_write_1(ddata, JBT_REG_RGB_FORMAT, 0x60);
 245         r |= jbt_reg_write_1(ddata, JBT_REG_DRIVE_SYSTEM, 0x10);
 246         r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_OP, 0x56);
 247         r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_MODE, 0x33);
 248         r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
 249         r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
 250         r |= jbt_reg_write_1(ddata, JBT_REG_OPAMP_SYSCLK, 0x02);
 251         r |= jbt_reg_write_1(ddata, JBT_REG_VSC_VOLTAGE, 0x2b);
 252         r |= jbt_reg_write_1(ddata, JBT_REG_VCOM_VOLTAGE, 0x40);
 253         r |= jbt_reg_write_1(ddata, JBT_REG_EXT_DISPL, 0x03);
 254         r |= jbt_reg_write_1(ddata, JBT_REG_DCCLK_DCEV, 0x04);
 255         /*
 256          * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement
 257          * to avoid red / blue flicker
 258          */
 259         r |= jbt_reg_write_1(ddata, JBT_REG_ASW_SLEW, 0x04);
 260         r |= jbt_reg_write_1(ddata, JBT_REG_DUMMY_DISPLAY, 0x00);
 261 
 262         r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_A, 0x11);
 263         r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_B, 0x11);
 264         r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_C, 0x11);
 265         r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040);
 266         r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0);
 267         r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020);
 268         r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0);
 269 
 270         r |= jbt_reg_write_2(ddata, JBT_REG_GAMMA1_FINE_1, 0x5533);
 271         r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_FINE_2, 0x00);
 272         r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_INCLINATION, 0x00);
 273         r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
 274 
 275         r |= jbt_reg_write_2(ddata, JBT_REG_HCLOCK_VGA, 0x1f0);
 276         r |= jbt_reg_write_1(ddata, JBT_REG_BLANK_CONTROL, 0x02);
 277         r |= jbt_reg_write_2(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
 278 
 279         r |= jbt_reg_write_1(ddata, JBT_REG_CKV_ON_OFF, 0x01);
 280         r |= jbt_reg_write_2(ddata, JBT_REG_CKV_1_2, 0x0000);
 281 
 282         r |= jbt_reg_write_2(ddata, JBT_REG_OEV_TIMING, 0x0d0e);
 283         r |= jbt_reg_write_2(ddata, JBT_REG_ASW_TIMING_1, 0x11a4);
 284         r |= jbt_reg_write_1(ddata, JBT_REG_ASW_TIMING_2, 0x0e);
 285 
 286         r |= jbt_ret_write_0(ddata, JBT_REG_DISPLAY_ON);
 287 
 288         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 289 
 290 transfer_err:
 291 
 292         return r ? -EIO : 0;
 293 }
 294 
 295 static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
 296 {
 297         struct panel_drv_data *ddata = to_panel_data(dssdev);
 298         struct omap_dss_device *in = ddata->in;
 299 
 300         if (!omapdss_device_is_enabled(dssdev))
 301                 return;
 302 
 303         dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n");
 304 
 305         jbt_ret_write_0(ddata, JBT_REG_DISPLAY_OFF);
 306         jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002);
 307         jbt_ret_write_0(ddata, JBT_REG_SLEEP_IN);
 308         jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
 309 
 310         in->ops.dpi->disable(in);
 311 
 312         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 313 }
 314 
 315 static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
 316                 struct omap_video_timings *timings)
 317 {
 318         struct panel_drv_data *ddata = to_panel_data(dssdev);
 319         struct omap_dss_device *in = ddata->in;
 320 
 321         ddata->videomode = *timings;
 322         dssdev->panel.timings = *timings;
 323 
 324         in->ops.dpi->set_timings(in, timings);
 325 }
 326 
 327 static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
 328                 struct omap_video_timings *timings)
 329 {
 330         struct panel_drv_data *ddata = to_panel_data(dssdev);
 331 
 332         *timings = ddata->videomode;
 333 }
 334 
 335 static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
 336                 struct omap_video_timings *timings)
 337 {
 338         struct panel_drv_data *ddata = to_panel_data(dssdev);
 339         struct omap_dss_device *in = ddata->in;
 340 
 341         return in->ops.dpi->check_timings(in, timings);
 342 }
 343 
 344 static struct omap_dss_driver td028ttec1_ops = {
 345         .connect        = td028ttec1_panel_connect,
 346         .disconnect     = td028ttec1_panel_disconnect,
 347 
 348         .enable         = td028ttec1_panel_enable,
 349         .disable        = td028ttec1_panel_disable,
 350 
 351         .set_timings    = td028ttec1_panel_set_timings,
 352         .get_timings    = td028ttec1_panel_get_timings,
 353         .check_timings  = td028ttec1_panel_check_timings,
 354 };
 355 
 356 static int td028ttec1_probe_of(struct spi_device *spi)
 357 {
 358         struct device_node *node = spi->dev.of_node;
 359         struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 360         struct omap_dss_device *in;
 361 
 362         in = omapdss_of_find_source_for_first_ep(node);
 363         if (IS_ERR(in)) {
 364                 dev_err(&spi->dev, "failed to find video source\n");
 365                 return PTR_ERR(in);
 366         }
 367 
 368         ddata->in = in;
 369 
 370         return 0;
 371 }
 372 
 373 static int td028ttec1_panel_probe(struct spi_device *spi)
 374 {
 375         struct panel_drv_data *ddata;
 376         struct omap_dss_device *dssdev;
 377         int r;
 378 
 379         dev_dbg(&spi->dev, "%s\n", __func__);
 380 
 381         if (!spi->dev.of_node)
 382                 return -ENODEV;
 383 
 384         spi->bits_per_word = 9;
 385         spi->mode = SPI_MODE_3;
 386 
 387         r = spi_setup(spi);
 388         if (r < 0) {
 389                 dev_err(&spi->dev, "spi_setup failed: %d\n", r);
 390                 return r;
 391         }
 392 
 393         ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
 394         if (ddata == NULL)
 395                 return -ENOMEM;
 396 
 397         dev_set_drvdata(&spi->dev, ddata);
 398 
 399         ddata->spi_dev = spi;
 400 
 401         r = td028ttec1_probe_of(spi);
 402         if (r)
 403                 return r;
 404 
 405         ddata->videomode = td028ttec1_panel_timings;
 406 
 407         dssdev = &ddata->dssdev;
 408         dssdev->dev = &spi->dev;
 409         dssdev->driver = &td028ttec1_ops;
 410         dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 411         dssdev->owner = THIS_MODULE;
 412         dssdev->panel.timings = ddata->videomode;
 413         dssdev->phy.dpi.data_lines = ddata->data_lines;
 414 
 415         r = omapdss_register_display(dssdev);
 416         if (r) {
 417                 dev_err(&spi->dev, "Failed to register panel\n");
 418                 goto err_reg;
 419         }
 420 
 421         return 0;
 422 
 423 err_reg:
 424         omap_dss_put_device(ddata->in);
 425         return r;
 426 }
 427 
 428 static int td028ttec1_panel_remove(struct spi_device *spi)
 429 {
 430         struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 431         struct omap_dss_device *dssdev = &ddata->dssdev;
 432         struct omap_dss_device *in = ddata->in;
 433 
 434         dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__);
 435 
 436         omapdss_unregister_display(dssdev);
 437 
 438         td028ttec1_panel_disable(dssdev);
 439         td028ttec1_panel_disconnect(dssdev);
 440 
 441         omap_dss_put_device(in);
 442 
 443         return 0;
 444 }
 445 
 446 static const struct of_device_id td028ttec1_of_match[] = {
 447         { .compatible = "omapdss,tpo,td028ttec1", },
 448         /* keep to not break older DTB */
 449         { .compatible = "omapdss,toppoly,td028ttec1", },
 450         {},
 451 };
 452 
 453 MODULE_DEVICE_TABLE(of, td028ttec1_of_match);
 454 
 455 static const struct spi_device_id td028ttec1_ids[] = {
 456         { "toppoly,td028ttec1", 0 },
 457         { "tpo,td028ttec1", 0},
 458         { /* sentinel */ }
 459 };
 460 
 461 MODULE_DEVICE_TABLE(spi, td028ttec1_ids);
 462 
 463 static struct spi_driver td028ttec1_spi_driver = {
 464         .probe          = td028ttec1_panel_probe,
 465         .remove         = td028ttec1_panel_remove,
 466         .id_table       = td028ttec1_ids,
 467 
 468         .driver         = {
 469                 .name   = "panel-tpo-td028ttec1",
 470                 .of_match_table = td028ttec1_of_match,
 471                 .suppress_bind_attrs = true,
 472         },
 473 };
 474 
 475 module_spi_driver(td028ttec1_spi_driver);
 476 
 477 MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
 478 MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver");
 479 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */