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