507 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Toppoly TD043MTEA1 Panel Driver4 *5 * Copyright (C) 2019 Texas Instruments Incorporated6 *7 * Based on the omapdrm-specific panel-tpo-td043mtea1 driver8 *9 * Author: Gražvydas Ignotas <notasas@gmail.com>10 */11 12#include <linux/delay.h>13#include <linux/module.h>14#include <linux/regulator/consumer.h>15#include <linux/spi/spi.h>16 17#include <drm/drm_connector.h>18#include <drm/drm_modes.h>19#include <drm/drm_panel.h>20 21#define TPO_R02_MODE(x) ((x) & 7)22#define TPO_R02_MODE_800x480 723#define TPO_R02_NCLK_RISING BIT(3)24#define TPO_R02_HSYNC_HIGH BIT(4)25#define TPO_R02_VSYNC_HIGH BIT(5)26 27#define TPO_R03_NSTANDBY BIT(0)28#define TPO_R03_EN_CP_CLK BIT(1)29#define TPO_R03_EN_VGL_PUMP BIT(2)30#define TPO_R03_EN_PWM BIT(3)31#define TPO_R03_DRIVING_CAP_100 BIT(4)32#define TPO_R03_EN_PRE_CHARGE BIT(6)33#define TPO_R03_SOFTWARE_CTL BIT(7)34 35#define TPO_R04_NFLIP_H BIT(0)36#define TPO_R04_NFLIP_V BIT(1)37#define TPO_R04_CP_CLK_FREQ_1H BIT(2)38#define TPO_R04_VGL_FREQ_1H BIT(4)39 40#define TPO_R03_VAL_NORMAL \41 (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | TPO_R03_EN_VGL_PUMP | \42 TPO_R03_EN_PWM | TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \43 TPO_R03_SOFTWARE_CTL)44 45#define TPO_R03_VAL_STANDBY \46 (TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \47 TPO_R03_SOFTWARE_CTL)48 49static const u16 td043mtea1_def_gamma[12] = {50 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 102351};52 53struct td043mtea1_panel {54 struct drm_panel panel;55 56 struct spi_device *spi;57 struct regulator *vcc_reg;58 struct gpio_desc *reset_gpio;59 60 unsigned int mode;61 u16 gamma[12];62 bool vmirror;63 bool powered_on;64 bool spi_suspended;65 bool power_on_resume;66};67 68#define to_td043mtea1_device(p) container_of(p, struct td043mtea1_panel, panel)69 70/* -----------------------------------------------------------------------------71 * Hardware Access72 */73 74static int td043mtea1_write(struct td043mtea1_panel *lcd, u8 addr, u8 value)75{76 struct spi_message msg;77 struct spi_transfer xfer;78 u16 data;79 int ret;80 81 spi_message_init(&msg);82 83 memset(&xfer, 0, sizeof(xfer));84 85 data = ((u16)addr << 10) | (1 << 8) | value;86 xfer.tx_buf = &data;87 xfer.bits_per_word = 16;88 xfer.len = 2;89 spi_message_add_tail(&xfer, &msg);90 91 ret = spi_sync(lcd->spi, &msg);92 if (ret < 0)93 dev_warn(&lcd->spi->dev, "failed to write to LCD reg (%d)\n",94 ret);95 96 return ret;97}98 99static void td043mtea1_write_gamma(struct td043mtea1_panel *lcd)100{101 const u16 *gamma = lcd->gamma;102 unsigned int i;103 u8 val;104 105 /* gamma bits [9:8] */106 for (val = i = 0; i < 4; i++)107 val |= (gamma[i] & 0x300) >> ((i + 1) * 2);108 td043mtea1_write(lcd, 0x11, val);109 110 for (val = i = 0; i < 4; i++)111 val |= (gamma[i + 4] & 0x300) >> ((i + 1) * 2);112 td043mtea1_write(lcd, 0x12, val);113 114 for (val = i = 0; i < 4; i++)115 val |= (gamma[i + 8] & 0x300) >> ((i + 1) * 2);116 td043mtea1_write(lcd, 0x13, val);117 118 /* gamma bits [7:0] */119 for (i = 0; i < 12; i++)120 td043mtea1_write(lcd, 0x14 + i, gamma[i] & 0xff);121}122 123static int td043mtea1_write_mirror(struct td043mtea1_panel *lcd)124{125 u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V |126 TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;127 if (lcd->vmirror)128 reg4 &= ~TPO_R04_NFLIP_V;129 130 return td043mtea1_write(lcd, 4, reg4);131}132 133static int td043mtea1_power_on(struct td043mtea1_panel *lcd)134{135 int ret;136 137 if (lcd->powered_on)138 return 0;139 140 ret = regulator_enable(lcd->vcc_reg);141 if (ret < 0)142 return ret;143 144 /* Wait for the panel to stabilize. */145 msleep(160);146 147 gpiod_set_value(lcd->reset_gpio, 0);148 149 td043mtea1_write(lcd, 2, TPO_R02_MODE(lcd->mode) | TPO_R02_NCLK_RISING);150 td043mtea1_write(lcd, 3, TPO_R03_VAL_NORMAL);151 td043mtea1_write(lcd, 0x20, 0xf0);152 td043mtea1_write(lcd, 0x21, 0xf0);153 td043mtea1_write_mirror(lcd);154 td043mtea1_write_gamma(lcd);155 156 lcd->powered_on = true;157 158 return 0;159}160 161static void td043mtea1_power_off(struct td043mtea1_panel *lcd)162{163 if (!lcd->powered_on)164 return;165 166 td043mtea1_write(lcd, 3, TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);167 168 gpiod_set_value(lcd->reset_gpio, 1);169 170 /* wait for at least 2 vsyncs before cutting off power */171 msleep(50);172 173 td043mtea1_write(lcd, 3, TPO_R03_VAL_STANDBY);174 175 regulator_disable(lcd->vcc_reg);176 177 lcd->powered_on = false;178}179 180/* -----------------------------------------------------------------------------181 * sysfs182 */183 184static ssize_t vmirror_show(struct device *dev, struct device_attribute *attr,185 char *buf)186{187 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);188 189 return sysfs_emit(buf, "%d\n", lcd->vmirror);190}191 192static ssize_t vmirror_store(struct device *dev, struct device_attribute *attr,193 const char *buf, size_t count)194{195 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);196 int val;197 int ret;198 199 ret = kstrtoint(buf, 0, &val);200 if (ret < 0)201 return ret;202 203 lcd->vmirror = !!val;204 205 ret = td043mtea1_write_mirror(lcd);206 if (ret < 0)207 return ret;208 209 return count;210}211 212static ssize_t mode_show(struct device *dev, struct device_attribute *attr,213 char *buf)214{215 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);216 217 return sysfs_emit(buf, "%d\n", lcd->mode);218}219 220static ssize_t mode_store(struct device *dev, struct device_attribute *attr,221 const char *buf, size_t count)222{223 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);224 long val;225 int ret;226 227 ret = kstrtol(buf, 0, &val);228 if (ret != 0 || val & ~7)229 return -EINVAL;230 231 lcd->mode = val;232 233 val |= TPO_R02_NCLK_RISING;234 td043mtea1_write(lcd, 2, val);235 236 return count;237}238 239static ssize_t gamma_show(struct device *dev, struct device_attribute *attr,240 char *buf)241{242 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);243 ssize_t len = 0;244 unsigned int i;245 int ret;246 247 for (i = 0; i < ARRAY_SIZE(lcd->gamma); i++) {248 ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",249 lcd->gamma[i]);250 if (ret < 0)251 return ret;252 len += ret;253 }254 buf[len - 1] = '\n';255 256 return len;257}258 259static ssize_t gamma_store(struct device *dev, struct device_attribute *attr,260 const char *buf, size_t count)261{262 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);263 unsigned int g[12];264 unsigned int i;265 int ret;266 267 ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",268 &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],269 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);270 if (ret != 12)271 return -EINVAL;272 273 for (i = 0; i < 12; i++)274 lcd->gamma[i] = g[i];275 276 td043mtea1_write_gamma(lcd);277 278 return count;279}280 281static DEVICE_ATTR_RW(vmirror);282static DEVICE_ATTR_RW(mode);283static DEVICE_ATTR_RW(gamma);284 285static struct attribute *td043mtea1_attrs[] = {286 &dev_attr_vmirror.attr,287 &dev_attr_mode.attr,288 &dev_attr_gamma.attr,289 NULL,290};291 292static const struct attribute_group td043mtea1_attr_group = {293 .attrs = td043mtea1_attrs,294};295 296/* -----------------------------------------------------------------------------297 * Panel Operations298 */299 300static int td043mtea1_unprepare(struct drm_panel *panel)301{302 struct td043mtea1_panel *lcd = to_td043mtea1_device(panel);303 304 if (!lcd->spi_suspended)305 td043mtea1_power_off(lcd);306 307 return 0;308}309 310static int td043mtea1_prepare(struct drm_panel *panel)311{312 struct td043mtea1_panel *lcd = to_td043mtea1_device(panel);313 int ret;314 315 /*316 * If we are resuming from system suspend, SPI might not be enabled317 * yet, so we'll program the LCD from SPI PM resume callback.318 */319 if (lcd->spi_suspended)320 return 0;321 322 ret = td043mtea1_power_on(lcd);323 if (ret) {324 dev_err(&lcd->spi->dev, "%s: power on failed (%d)\n",325 __func__, ret);326 return ret;327 }328 329 return 0;330}331 332static const struct drm_display_mode td043mtea1_mode = {333 .clock = 36000,334 .hdisplay = 800,335 .hsync_start = 800 + 68,336 .hsync_end = 800 + 68 + 1,337 .htotal = 800 + 68 + 1 + 214,338 .vdisplay = 480,339 .vsync_start = 480 + 39,340 .vsync_end = 480 + 39 + 1,341 .vtotal = 480 + 39 + 1 + 34,342 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,343 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,344 .width_mm = 94,345 .height_mm = 56,346};347 348static int td043mtea1_get_modes(struct drm_panel *panel,349 struct drm_connector *connector)350{351 struct drm_display_mode *mode;352 353 mode = drm_mode_duplicate(connector->dev, &td043mtea1_mode);354 if (!mode)355 return -ENOMEM;356 357 drm_mode_set_name(mode);358 drm_mode_probed_add(connector, mode);359 360 connector->display_info.width_mm = td043mtea1_mode.width_mm;361 connector->display_info.height_mm = td043mtea1_mode.height_mm;362 /*363 * FIXME: According to the datasheet sync signals are sampled on the364 * rising edge of the clock, but the code running on the OMAP3 Pandora365 * indicates sampling on the falling edge. This should be tested on a366 * real device.367 */368 connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH369 | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE370 | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE;371 372 return 1;373}374 375static const struct drm_panel_funcs td043mtea1_funcs = {376 .unprepare = td043mtea1_unprepare,377 .prepare = td043mtea1_prepare,378 .get_modes = td043mtea1_get_modes,379};380 381/* -----------------------------------------------------------------------------382 * Power Management, Probe and Remove383 */384 385static int __maybe_unused td043mtea1_suspend(struct device *dev)386{387 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);388 389 if (lcd->powered_on) {390 td043mtea1_power_off(lcd);391 lcd->powered_on = true;392 }393 394 lcd->spi_suspended = true;395 396 return 0;397}398 399static int __maybe_unused td043mtea1_resume(struct device *dev)400{401 struct td043mtea1_panel *lcd = dev_get_drvdata(dev);402 int ret;403 404 lcd->spi_suspended = false;405 406 if (lcd->powered_on) {407 lcd->powered_on = false;408 ret = td043mtea1_power_on(lcd);409 if (ret)410 return ret;411 }412 413 return 0;414}415 416static SIMPLE_DEV_PM_OPS(td043mtea1_pm_ops, td043mtea1_suspend,417 td043mtea1_resume);418 419static int td043mtea1_probe(struct spi_device *spi)420{421 struct td043mtea1_panel *lcd;422 int ret;423 424 lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);425 if (lcd == NULL)426 return -ENOMEM;427 428 spi_set_drvdata(spi, lcd);429 lcd->spi = spi;430 lcd->mode = TPO_R02_MODE_800x480;431 memcpy(lcd->gamma, td043mtea1_def_gamma, sizeof(lcd->gamma));432 433 lcd->vcc_reg = devm_regulator_get(&spi->dev, "vcc");434 if (IS_ERR(lcd->vcc_reg))435 return dev_err_probe(&spi->dev, PTR_ERR(lcd->vcc_reg),436 "failed to get VCC regulator\n");437 438 lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);439 if (IS_ERR(lcd->reset_gpio))440 return dev_err_probe(&spi->dev, PTR_ERR(lcd->reset_gpio),441 "failed to get reset GPIO\n");442 443 spi->bits_per_word = 16;444 spi->mode = SPI_MODE_0;445 446 ret = spi_setup(spi);447 if (ret < 0) {448 dev_err(&spi->dev, "failed to setup SPI: %d\n", ret);449 return ret;450 }451 452 ret = sysfs_create_group(&spi->dev.kobj, &td043mtea1_attr_group);453 if (ret < 0) {454 dev_err(&spi->dev, "failed to create sysfs files\n");455 return ret;456 }457 458 drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs,459 DRM_MODE_CONNECTOR_DPI);460 461 drm_panel_add(&lcd->panel);462 463 return 0;464}465 466static void td043mtea1_remove(struct spi_device *spi)467{468 struct td043mtea1_panel *lcd = spi_get_drvdata(spi);469 470 drm_panel_remove(&lcd->panel);471 drm_panel_disable(&lcd->panel);472 drm_panel_unprepare(&lcd->panel);473 474 sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group);475}476 477static const struct of_device_id td043mtea1_of_match[] = {478 { .compatible = "tpo,td043mtea1", },479 { /* sentinel */ },480};481 482MODULE_DEVICE_TABLE(of, td043mtea1_of_match);483 484static const struct spi_device_id td043mtea1_ids[] = {485 { "td043mtea1", 0 },486 { /* sentinel */ }487};488 489MODULE_DEVICE_TABLE(spi, td043mtea1_ids);490 491static struct spi_driver td043mtea1_driver = {492 .probe = td043mtea1_probe,493 .remove = td043mtea1_remove,494 .id_table = td043mtea1_ids,495 .driver = {496 .name = "panel-tpo-td043mtea1",497 .pm = &td043mtea1_pm_ops,498 .of_match_table = td043mtea1_of_match,499 },500};501 502module_spi_driver(td043mtea1_driver);503 504MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");505MODULE_DESCRIPTION("TPO TD043MTEA1 Panel Driver");506MODULE_LICENSE("GPL");507