311 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Innolux/Chimei EJ030NA TFT LCD panel driver4 *5 * Copyright (C) 2020, Paul Cercueil <paul@crapouillou.net>6 * Copyright (C) 2020, Christophe Branchereau <cbranchereau@gmail.com>7 */8 9#include <linux/delay.h>10#include <linux/device.h>11#include <linux/gpio/consumer.h>12#include <linux/media-bus-format.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/regmap.h>17#include <linux/regulator/consumer.h>18#include <linux/spi/spi.h>19 20#include <drm/drm_modes.h>21#include <drm/drm_panel.h>22 23struct ej030na_info {24 const struct drm_display_mode *display_modes;25 unsigned int num_modes;26 u16 width_mm, height_mm;27 u32 bus_format, bus_flags;28};29 30struct ej030na {31 struct drm_panel panel;32 struct spi_device *spi;33 struct regmap *map;34 35 const struct ej030na_info *panel_info;36 37 struct regulator *supply;38 struct gpio_desc *reset_gpio;39};40 41static inline struct ej030na *to_ej030na(struct drm_panel *panel)42{43 return container_of(panel, struct ej030na, panel);44}45 46static const struct reg_sequence ej030na_init_sequence[] = {47 { 0x05, 0x1e },48 { 0x05, 0x5c },49 { 0x02, 0x14 },50 { 0x03, 0x40 },51 { 0x04, 0x07 },52 { 0x06, 0x12 },53 { 0x07, 0xd2 },54 { 0x0c, 0x06 },55 { 0x0d, 0x40 },56 { 0x0e, 0x40 },57 { 0x0f, 0x40 },58 { 0x10, 0x40 },59 { 0x11, 0x40 },60 { 0x2f, 0x40 },61 { 0x5a, 0x02 },62 63 { 0x30, 0x07 },64 { 0x31, 0x57 },65 { 0x32, 0x53 },66 { 0x33, 0x77 },67 { 0x34, 0xb8 },68 { 0x35, 0xbd },69 { 0x36, 0xb8 },70 { 0x37, 0xe7 },71 { 0x38, 0x04 },72 { 0x39, 0xff },73 74 { 0x40, 0x0b },75 { 0x41, 0xb8 },76 { 0x42, 0xab },77 { 0x43, 0xb9 },78 { 0x44, 0x6a },79 { 0x45, 0x56 },80 { 0x46, 0x61 },81 { 0x47, 0x08 },82 { 0x48, 0x0f },83 { 0x49, 0x0f },84};85 86static int ej030na_prepare(struct drm_panel *panel)87{88 struct ej030na *priv = to_ej030na(panel);89 struct device *dev = &priv->spi->dev;90 int err;91 92 err = regulator_enable(priv->supply);93 if (err) {94 dev_err(dev, "Failed to enable power supply: %d\n", err);95 return err;96 }97 98 /* Reset the chip */99 gpiod_set_value_cansleep(priv->reset_gpio, 1);100 usleep_range(50, 150);101 gpiod_set_value_cansleep(priv->reset_gpio, 0);102 usleep_range(50, 150);103 104 err = regmap_multi_reg_write(priv->map, ej030na_init_sequence,105 ARRAY_SIZE(ej030na_init_sequence));106 if (err) {107 dev_err(dev, "Failed to init registers: %d\n", err);108 goto err_disable_regulator;109 }110 111 return 0;112 113err_disable_regulator:114 regulator_disable(priv->supply);115 return err;116}117 118static int ej030na_unprepare(struct drm_panel *panel)119{120 struct ej030na *priv = to_ej030na(panel);121 122 gpiod_set_value_cansleep(priv->reset_gpio, 1);123 regulator_disable(priv->supply);124 125 return 0;126}127 128static int ej030na_enable(struct drm_panel *panel)129{130 struct ej030na *priv = to_ej030na(panel);131 132 /* standby off */133 regmap_write(priv->map, 0x2b, 0x01);134 135 if (panel->backlight) {136 /* Wait for the picture to be ready before enabling backlight */137 msleep(120);138 }139 140 return 0;141}142 143static int ej030na_disable(struct drm_panel *panel)144{145 struct ej030na *priv = to_ej030na(panel);146 147 /* standby on */148 regmap_write(priv->map, 0x2b, 0x00);149 150 return 0;151}152 153static int ej030na_get_modes(struct drm_panel *panel,154 struct drm_connector *connector)155{156 struct ej030na *priv = to_ej030na(panel);157 const struct ej030na_info *panel_info = priv->panel_info;158 struct drm_display_mode *mode;159 unsigned int i;160 161 for (i = 0; i < panel_info->num_modes; i++) {162 mode = drm_mode_duplicate(connector->dev,163 &panel_info->display_modes[i]);164 if (!mode)165 return -ENOMEM;166 167 drm_mode_set_name(mode);168 169 mode->type = DRM_MODE_TYPE_DRIVER;170 if (panel_info->num_modes == 1)171 mode->type |= DRM_MODE_TYPE_PREFERRED;172 173 drm_mode_probed_add(connector, mode);174 }175 176 connector->display_info.bpc = 8;177 connector->display_info.width_mm = panel_info->width_mm;178 connector->display_info.height_mm = panel_info->height_mm;179 180 drm_display_info_set_bus_formats(&connector->display_info,181 &panel_info->bus_format, 1);182 connector->display_info.bus_flags = panel_info->bus_flags;183 184 return panel_info->num_modes;185}186 187static const struct drm_panel_funcs ej030na_funcs = {188 .prepare = ej030na_prepare,189 .unprepare = ej030na_unprepare,190 .enable = ej030na_enable,191 .disable = ej030na_disable,192 .get_modes = ej030na_get_modes,193};194 195static const struct regmap_config ej030na_regmap_config = {196 .reg_bits = 8,197 .val_bits = 8,198 .max_register = 0x5a,199};200 201static int ej030na_probe(struct spi_device *spi)202{203 struct device *dev = &spi->dev;204 struct ej030na *priv;205 int err;206 207 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);208 if (!priv)209 return -ENOMEM;210 211 priv->spi = spi;212 spi_set_drvdata(spi, priv);213 214 priv->map = devm_regmap_init_spi(spi, &ej030na_regmap_config);215 if (IS_ERR(priv->map)) {216 dev_err(dev, "Unable to init regmap\n");217 return PTR_ERR(priv->map);218 }219 220 priv->panel_info = of_device_get_match_data(dev);221 if (!priv->panel_info)222 return -EINVAL;223 224 priv->supply = devm_regulator_get(dev, "power");225 if (IS_ERR(priv->supply))226 return dev_err_probe(dev, PTR_ERR(priv->supply),227 "Failed to get power supply\n");228 229 priv->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);230 if (IS_ERR(priv->reset_gpio))231 return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),232 "Failed to get reset GPIO\n");233 234 drm_panel_init(&priv->panel, dev, &ej030na_funcs,235 DRM_MODE_CONNECTOR_DPI);236 237 err = drm_panel_of_backlight(&priv->panel);238 if (err)239 return err;240 241 drm_panel_add(&priv->panel);242 243 return 0;244}245 246static void ej030na_remove(struct spi_device *spi)247{248 struct ej030na *priv = spi_get_drvdata(spi);249 250 drm_panel_remove(&priv->panel);251 drm_panel_disable(&priv->panel);252 drm_panel_unprepare(&priv->panel);253}254 255static const struct drm_display_mode ej030na_modes[] = {256 { /* 60 Hz */257 .clock = 14400,258 .hdisplay = 320,259 .hsync_start = 320 + 10,260 .hsync_end = 320 + 10 + 37,261 .htotal = 320 + 10 + 37 + 33,262 .vdisplay = 480,263 .vsync_start = 480 + 102,264 .vsync_end = 480 + 102 + 9 + 9,265 .vtotal = 480 + 102 + 9 + 9,266 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,267 },268 { /* 50 Hz */269 .clock = 12000,270 .hdisplay = 320,271 .hsync_start = 320 + 10,272 .hsync_end = 320 + 10 + 37,273 .htotal = 320 + 10 + 37 + 33,274 .vdisplay = 480,275 .vsync_start = 480 + 102,276 .vsync_end = 480 + 102 + 9,277 .vtotal = 480 + 102 + 9 + 9,278 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,279 },280};281 282static const struct ej030na_info ej030na_info = {283 .display_modes = ej030na_modes,284 .num_modes = ARRAY_SIZE(ej030na_modes),285 .width_mm = 70,286 .height_mm = 51,287 .bus_format = MEDIA_BUS_FMT_RGB888_3X8_DELTA,288 .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE | DRM_BUS_FLAG_DE_LOW,289};290 291static const struct of_device_id ej030na_of_match[] = {292 { .compatible = "innolux,ej030na", .data = &ej030na_info },293 { /* sentinel */ }294};295MODULE_DEVICE_TABLE(of, ej030na_of_match);296 297static struct spi_driver ej030na_driver = {298 .driver = {299 .name = "panel-innolux-ej030na",300 .of_match_table = ej030na_of_match,301 },302 .probe = ej030na_probe,303 .remove = ej030na_remove,304};305module_spi_driver(ej030na_driver);306 307MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");308MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");309MODULE_DESCRIPTION("Innolux/Chimei EJ030NA TFT LCD panel driver");310MODULE_LICENSE("GPL v2");311