Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Toppoly TD043MTEA1 Panel Driver
0004  *
0005  * Copyright (C) 2019 Texas Instruments Incorporated
0006  *
0007  * Based on the omapdrm-specific panel-tpo-td043mtea1 driver
0008  *
0009  * Author: Gražvydas Ignotas <notasas@gmail.com>
0010  */
0011 
0012 #include <linux/delay.h>
0013 #include <linux/module.h>
0014 #include <linux/regulator/consumer.h>
0015 #include <linux/spi/spi.h>
0016 
0017 #include <drm/drm_connector.h>
0018 #include <drm/drm_modes.h>
0019 #include <drm/drm_panel.h>
0020 
0021 #define TPO_R02_MODE(x)         ((x) & 7)
0022 #define TPO_R02_MODE_800x480        7
0023 #define TPO_R02_NCLK_RISING     BIT(3)
0024 #define TPO_R02_HSYNC_HIGH      BIT(4)
0025 #define TPO_R02_VSYNC_HIGH      BIT(5)
0026 
0027 #define TPO_R03_NSTANDBY        BIT(0)
0028 #define TPO_R03_EN_CP_CLK       BIT(1)
0029 #define TPO_R03_EN_VGL_PUMP     BIT(2)
0030 #define TPO_R03_EN_PWM          BIT(3)
0031 #define TPO_R03_DRIVING_CAP_100     BIT(4)
0032 #define TPO_R03_EN_PRE_CHARGE       BIT(6)
0033 #define TPO_R03_SOFTWARE_CTL        BIT(7)
0034 
0035 #define TPO_R04_NFLIP_H         BIT(0)
0036 #define TPO_R04_NFLIP_V         BIT(1)
0037 #define TPO_R04_CP_CLK_FREQ_1H      BIT(2)
0038 #define TPO_R04_VGL_FREQ_1H     BIT(4)
0039 
0040 #define TPO_R03_VAL_NORMAL \
0041     (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | TPO_R03_EN_VGL_PUMP | \
0042      TPO_R03_EN_PWM | TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
0043      TPO_R03_SOFTWARE_CTL)
0044 
0045 #define TPO_R03_VAL_STANDBY \
0046     (TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
0047      TPO_R03_SOFTWARE_CTL)
0048 
0049 static const u16 td043mtea1_def_gamma[12] = {
0050     105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023
0051 };
0052 
0053 struct td043mtea1_panel {
0054     struct drm_panel panel;
0055 
0056     struct spi_device *spi;
0057     struct regulator *vcc_reg;
0058     struct gpio_desc *reset_gpio;
0059 
0060     unsigned int mode;
0061     u16 gamma[12];
0062     bool vmirror;
0063     bool powered_on;
0064     bool spi_suspended;
0065     bool power_on_resume;
0066 };
0067 
0068 #define to_td043mtea1_device(p) container_of(p, struct td043mtea1_panel, panel)
0069 
0070 /* -----------------------------------------------------------------------------
0071  * Hardware Access
0072  */
0073 
0074 static int td043mtea1_write(struct td043mtea1_panel *lcd, u8 addr, u8 value)
0075 {
0076     struct spi_message msg;
0077     struct spi_transfer xfer;
0078     u16 data;
0079     int ret;
0080 
0081     spi_message_init(&msg);
0082 
0083     memset(&xfer, 0, sizeof(xfer));
0084 
0085     data = ((u16)addr << 10) | (1 << 8) | value;
0086     xfer.tx_buf = &data;
0087     xfer.bits_per_word = 16;
0088     xfer.len = 2;
0089     spi_message_add_tail(&xfer, &msg);
0090 
0091     ret = spi_sync(lcd->spi, &msg);
0092     if (ret < 0)
0093         dev_warn(&lcd->spi->dev, "failed to write to LCD reg (%d)\n",
0094              ret);
0095 
0096     return ret;
0097 }
0098 
0099 static void td043mtea1_write_gamma(struct td043mtea1_panel *lcd)
0100 {
0101     const u16 *gamma = lcd->gamma;
0102     unsigned int i;
0103     u8 val;
0104 
0105     /* gamma bits [9:8] */
0106     for (val = i = 0; i < 4; i++)
0107         val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
0108     td043mtea1_write(lcd, 0x11, val);
0109 
0110     for (val = i = 0; i < 4; i++)
0111         val |= (gamma[i + 4] & 0x300) >> ((i + 1) * 2);
0112     td043mtea1_write(lcd, 0x12, val);
0113 
0114     for (val = i = 0; i < 4; i++)
0115         val |= (gamma[i + 8] & 0x300) >> ((i + 1) * 2);
0116     td043mtea1_write(lcd, 0x13, val);
0117 
0118     /* gamma bits [7:0] */
0119     for (i = 0; i < 12; i++)
0120         td043mtea1_write(lcd, 0x14 + i, gamma[i] & 0xff);
0121 }
0122 
0123 static int td043mtea1_write_mirror(struct td043mtea1_panel *lcd)
0124 {
0125     u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V |
0126         TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
0127     if (lcd->vmirror)
0128         reg4 &= ~TPO_R04_NFLIP_V;
0129 
0130     return td043mtea1_write(lcd, 4, reg4);
0131 }
0132 
0133 static int td043mtea1_power_on(struct td043mtea1_panel *lcd)
0134 {
0135     int ret;
0136 
0137     if (lcd->powered_on)
0138         return 0;
0139 
0140     ret = regulator_enable(lcd->vcc_reg);
0141     if (ret < 0)
0142         return ret;
0143 
0144     /* Wait for the panel to stabilize. */
0145     msleep(160);
0146 
0147     gpiod_set_value(lcd->reset_gpio, 0);
0148 
0149     td043mtea1_write(lcd, 2, TPO_R02_MODE(lcd->mode) | TPO_R02_NCLK_RISING);
0150     td043mtea1_write(lcd, 3, TPO_R03_VAL_NORMAL);
0151     td043mtea1_write(lcd, 0x20, 0xf0);
0152     td043mtea1_write(lcd, 0x21, 0xf0);
0153     td043mtea1_write_mirror(lcd);
0154     td043mtea1_write_gamma(lcd);
0155 
0156     lcd->powered_on = true;
0157 
0158     return 0;
0159 }
0160 
0161 static void td043mtea1_power_off(struct td043mtea1_panel *lcd)
0162 {
0163     if (!lcd->powered_on)
0164         return;
0165 
0166     td043mtea1_write(lcd, 3, TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
0167 
0168     gpiod_set_value(lcd->reset_gpio, 1);
0169 
0170     /* wait for at least 2 vsyncs before cutting off power */
0171     msleep(50);
0172 
0173     td043mtea1_write(lcd, 3, TPO_R03_VAL_STANDBY);
0174 
0175     regulator_disable(lcd->vcc_reg);
0176 
0177     lcd->powered_on = false;
0178 }
0179 
0180 /* -----------------------------------------------------------------------------
0181  * sysfs
0182  */
0183 
0184 static ssize_t vmirror_show(struct device *dev, struct device_attribute *attr,
0185                 char *buf)
0186 {
0187     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0188 
0189     return sysfs_emit(buf, "%d\n", lcd->vmirror);
0190 }
0191 
0192 static ssize_t vmirror_store(struct device *dev, struct device_attribute *attr,
0193                  const char *buf, size_t count)
0194 {
0195     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0196     int val;
0197     int ret;
0198 
0199     ret = kstrtoint(buf, 0, &val);
0200     if (ret < 0)
0201         return ret;
0202 
0203     lcd->vmirror = !!val;
0204 
0205     ret = td043mtea1_write_mirror(lcd);
0206     if (ret < 0)
0207         return ret;
0208 
0209     return count;
0210 }
0211 
0212 static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
0213              char *buf)
0214 {
0215     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0216 
0217     return sysfs_emit(buf, "%d\n", lcd->mode);
0218 }
0219 
0220 static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
0221               const char *buf, size_t count)
0222 {
0223     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0224     long val;
0225     int ret;
0226 
0227     ret = kstrtol(buf, 0, &val);
0228     if (ret != 0 || val & ~7)
0229         return -EINVAL;
0230 
0231     lcd->mode = val;
0232 
0233     val |= TPO_R02_NCLK_RISING;
0234     td043mtea1_write(lcd, 2, val);
0235 
0236     return count;
0237 }
0238 
0239 static ssize_t gamma_show(struct device *dev, struct device_attribute *attr,
0240               char *buf)
0241 {
0242     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0243     ssize_t len = 0;
0244     unsigned int i;
0245     int ret;
0246 
0247     for (i = 0; i < ARRAY_SIZE(lcd->gamma); i++) {
0248         ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
0249                    lcd->gamma[i]);
0250         if (ret < 0)
0251             return ret;
0252         len += ret;
0253     }
0254     buf[len - 1] = '\n';
0255 
0256     return len;
0257 }
0258 
0259 static ssize_t gamma_store(struct device *dev, struct device_attribute *attr,
0260                const char *buf, size_t count)
0261 {
0262     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0263     unsigned int g[12];
0264     unsigned int i;
0265     int ret;
0266 
0267     ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
0268              &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
0269              &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
0270     if (ret != 12)
0271         return -EINVAL;
0272 
0273     for (i = 0; i < 12; i++)
0274         lcd->gamma[i] = g[i];
0275 
0276     td043mtea1_write_gamma(lcd);
0277 
0278     return count;
0279 }
0280 
0281 static DEVICE_ATTR_RW(vmirror);
0282 static DEVICE_ATTR_RW(mode);
0283 static DEVICE_ATTR_RW(gamma);
0284 
0285 static struct attribute *td043mtea1_attrs[] = {
0286     &dev_attr_vmirror.attr,
0287     &dev_attr_mode.attr,
0288     &dev_attr_gamma.attr,
0289     NULL,
0290 };
0291 
0292 static const struct attribute_group td043mtea1_attr_group = {
0293     .attrs = td043mtea1_attrs,
0294 };
0295 
0296 /* -----------------------------------------------------------------------------
0297  * Panel Operations
0298  */
0299 
0300 static int td043mtea1_unprepare(struct drm_panel *panel)
0301 {
0302     struct td043mtea1_panel *lcd = to_td043mtea1_device(panel);
0303 
0304     if (!lcd->spi_suspended)
0305         td043mtea1_power_off(lcd);
0306 
0307     return 0;
0308 }
0309 
0310 static int td043mtea1_prepare(struct drm_panel *panel)
0311 {
0312     struct td043mtea1_panel *lcd = to_td043mtea1_device(panel);
0313     int ret;
0314 
0315     /*
0316      * If we are resuming from system suspend, SPI might not be enabled
0317      * yet, so we'll program the LCD from SPI PM resume callback.
0318      */
0319     if (lcd->spi_suspended)
0320         return 0;
0321 
0322     ret = td043mtea1_power_on(lcd);
0323     if (ret) {
0324         dev_err(&lcd->spi->dev, "%s: power on failed (%d)\n",
0325             __func__, ret);
0326         return ret;
0327     }
0328 
0329     return 0;
0330 }
0331 
0332 static const struct drm_display_mode td043mtea1_mode = {
0333     .clock = 36000,
0334     .hdisplay = 800,
0335     .hsync_start = 800 + 68,
0336     .hsync_end = 800 + 68 + 1,
0337     .htotal = 800 + 68 + 1 + 214,
0338     .vdisplay = 480,
0339     .vsync_start = 480 + 39,
0340     .vsync_end = 480 + 39 + 1,
0341     .vtotal = 480 + 39 + 1 + 34,
0342     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
0343     .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
0344     .width_mm = 94,
0345     .height_mm = 56,
0346 };
0347 
0348 static int td043mtea1_get_modes(struct drm_panel *panel,
0349                 struct drm_connector *connector)
0350 {
0351     struct drm_display_mode *mode;
0352 
0353     mode = drm_mode_duplicate(connector->dev, &td043mtea1_mode);
0354     if (!mode)
0355         return -ENOMEM;
0356 
0357     drm_mode_set_name(mode);
0358     drm_mode_probed_add(connector, mode);
0359 
0360     connector->display_info.width_mm = td043mtea1_mode.width_mm;
0361     connector->display_info.height_mm = td043mtea1_mode.height_mm;
0362     /*
0363      * FIXME: According to the datasheet sync signals are sampled on the
0364      * rising edge of the clock, but the code running on the OMAP3 Pandora
0365      * indicates sampling on the falling edge. This should be tested on a
0366      * real device.
0367      */
0368     connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH
0369                       | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE
0370                       | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE;
0371 
0372     return 1;
0373 }
0374 
0375 static const struct drm_panel_funcs td043mtea1_funcs = {
0376     .unprepare = td043mtea1_unprepare,
0377     .prepare = td043mtea1_prepare,
0378     .get_modes = td043mtea1_get_modes,
0379 };
0380 
0381 /* -----------------------------------------------------------------------------
0382  * Power Management, Probe and Remove
0383  */
0384 
0385 static int __maybe_unused td043mtea1_suspend(struct device *dev)
0386 {
0387     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0388 
0389     if (lcd->powered_on) {
0390         td043mtea1_power_off(lcd);
0391         lcd->powered_on = true;
0392     }
0393 
0394     lcd->spi_suspended = true;
0395 
0396     return 0;
0397 }
0398 
0399 static int __maybe_unused td043mtea1_resume(struct device *dev)
0400 {
0401     struct td043mtea1_panel *lcd = dev_get_drvdata(dev);
0402     int ret;
0403 
0404     lcd->spi_suspended = false;
0405 
0406     if (lcd->powered_on) {
0407         lcd->powered_on = false;
0408         ret = td043mtea1_power_on(lcd);
0409         if (ret)
0410             return ret;
0411     }
0412 
0413     return 0;
0414 }
0415 
0416 static SIMPLE_DEV_PM_OPS(td043mtea1_pm_ops, td043mtea1_suspend,
0417              td043mtea1_resume);
0418 
0419 static int td043mtea1_probe(struct spi_device *spi)
0420 {
0421     struct td043mtea1_panel *lcd;
0422     int ret;
0423 
0424     lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
0425     if (lcd == NULL)
0426         return -ENOMEM;
0427 
0428     spi_set_drvdata(spi, lcd);
0429     lcd->spi = spi;
0430     lcd->mode = TPO_R02_MODE_800x480;
0431     memcpy(lcd->gamma, td043mtea1_def_gamma, sizeof(lcd->gamma));
0432 
0433     lcd->vcc_reg = devm_regulator_get(&spi->dev, "vcc");
0434     if (IS_ERR(lcd->vcc_reg))
0435         return dev_err_probe(&spi->dev, PTR_ERR(lcd->vcc_reg),
0436                      "failed to get VCC regulator\n");
0437 
0438     lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
0439     if (IS_ERR(lcd->reset_gpio))
0440         return dev_err_probe(&spi->dev, PTR_ERR(lcd->reset_gpio),
0441                      "failed to get reset GPIO\n");
0442 
0443     spi->bits_per_word = 16;
0444     spi->mode = SPI_MODE_0;
0445 
0446     ret = spi_setup(spi);
0447     if (ret < 0) {
0448         dev_err(&spi->dev, "failed to setup SPI: %d\n", ret);
0449         return ret;
0450     }
0451 
0452     ret = sysfs_create_group(&spi->dev.kobj, &td043mtea1_attr_group);
0453     if (ret < 0) {
0454         dev_err(&spi->dev, "failed to create sysfs files\n");
0455         return ret;
0456     }
0457 
0458     drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs,
0459                DRM_MODE_CONNECTOR_DPI);
0460 
0461     drm_panel_add(&lcd->panel);
0462 
0463     return 0;
0464 }
0465 
0466 static void td043mtea1_remove(struct spi_device *spi)
0467 {
0468     struct td043mtea1_panel *lcd = spi_get_drvdata(spi);
0469 
0470     drm_panel_remove(&lcd->panel);
0471     drm_panel_disable(&lcd->panel);
0472     drm_panel_unprepare(&lcd->panel);
0473 
0474     sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group);
0475 }
0476 
0477 static const struct of_device_id td043mtea1_of_match[] = {
0478     { .compatible = "tpo,td043mtea1", },
0479     { /* sentinel */ },
0480 };
0481 
0482 MODULE_DEVICE_TABLE(of, td043mtea1_of_match);
0483 
0484 static const struct spi_device_id td043mtea1_ids[] = {
0485     { "td043mtea1", 0 },
0486     { /* sentinel */ }
0487 };
0488 
0489 MODULE_DEVICE_TABLE(spi, td043mtea1_ids);
0490 
0491 static struct spi_driver td043mtea1_driver = {
0492     .probe      = td043mtea1_probe,
0493     .remove     = td043mtea1_remove,
0494     .id_table   = td043mtea1_ids,
0495     .driver     = {
0496         .name   = "panel-tpo-td043mtea1",
0497         .pm = &td043mtea1_pm_ops,
0498         .of_match_table = td043mtea1_of_match,
0499     },
0500 };
0501 
0502 module_spi_driver(td043mtea1_driver);
0503 
0504 MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
0505 MODULE_DESCRIPTION("TPO TD043MTEA1 Panel Driver");
0506 MODULE_LICENSE("GPL");