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