linux/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2021 Linaro Ltd.
   3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
   4 *   Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
   5 */
   6
   7#include <linux/delay.h>
   8#include <linux/gpio/consumer.h>
   9#include <linux/module.h>
  10#include <linux/of.h>
  11#include <linux/regulator/consumer.h>
  12
  13#include <video/mipi_display.h>
  14
  15#include <drm/drm_mipi_dsi.h>
  16#include <drm/drm_modes.h>
  17#include <drm/drm_panel.h>
  18
  19struct sharp_ls060 {
  20        struct drm_panel panel;
  21        struct mipi_dsi_device *dsi;
  22        struct regulator *vddi_supply;
  23        struct regulator *vddh_supply;
  24        struct regulator *avdd_supply;
  25        struct regulator *avee_supply;
  26        struct gpio_desc *reset_gpio;
  27        bool prepared;
  28};
  29
  30static inline struct sharp_ls060 *to_sharp_ls060(struct drm_panel *panel)
  31{
  32        return container_of(panel, struct sharp_ls060, panel);
  33}
  34
  35#define dsi_dcs_write_seq(dsi, seq...) ({                               \
  36                static const u8 d[] = { seq };                          \
  37                                                                        \
  38                mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d));       \
  39        })
  40
  41static void sharp_ls060_reset(struct sharp_ls060 *ctx)
  42{
  43        gpiod_set_value_cansleep(ctx->reset_gpio, 0);
  44        usleep_range(10000, 11000);
  45        gpiod_set_value_cansleep(ctx->reset_gpio, 1);
  46        usleep_range(10000, 11000);
  47        gpiod_set_value_cansleep(ctx->reset_gpio, 0);
  48        usleep_range(10000, 11000);
  49}
  50
  51static int sharp_ls060_on(struct sharp_ls060 *ctx)
  52{
  53        struct mipi_dsi_device *dsi = ctx->dsi;
  54        struct device *dev = &dsi->dev;
  55        int ret;
  56
  57        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  58
  59        ret = dsi_dcs_write_seq(dsi, 0xbb, 0x13);
  60        if (ret < 0) {
  61                dev_err(dev, "Failed to send command: %d\n", ret);
  62                return ret;
  63        }
  64
  65        ret = dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);
  66        if (ret < 0) {
  67                dev_err(dev, "Failed to send command: %d\n", ret);
  68                return ret;
  69        }
  70
  71        ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
  72        if (ret < 0) {
  73                dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
  74                return ret;
  75        }
  76        msleep(120);
  77
  78        ret = mipi_dsi_dcs_set_display_on(dsi);
  79        if (ret < 0) {
  80                dev_err(dev, "Failed to set display on: %d\n", ret);
  81                return ret;
  82        }
  83        msleep(50);
  84
  85        return 0;
  86}
  87
  88static int sharp_ls060_off(struct sharp_ls060 *ctx)
  89{
  90        struct mipi_dsi_device *dsi = ctx->dsi;
  91        struct device *dev = &dsi->dev;
  92        int ret;
  93
  94        dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
  95
  96        ret = mipi_dsi_dcs_set_display_off(dsi);
  97        if (ret < 0) {
  98                dev_err(dev, "Failed to set display off: %d\n", ret);
  99                return ret;
 100        }
 101        usleep_range(2000, 3000);
 102
 103        ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
 104        if (ret < 0) {
 105                dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
 106                return ret;
 107        }
 108        msleep(121);
 109
 110        return 0;
 111}
 112
 113static int sharp_ls060_prepare(struct drm_panel *panel)
 114{
 115        struct sharp_ls060 *ctx = to_sharp_ls060(panel);
 116        struct device *dev = &ctx->dsi->dev;
 117        int ret;
 118
 119        if (ctx->prepared)
 120                return 0;
 121
 122        ret = regulator_enable(ctx->vddi_supply);
 123        if (ret < 0)
 124                return ret;
 125
 126        ret = regulator_enable(ctx->avdd_supply);
 127        if (ret < 0)
 128                goto err_avdd;
 129
 130        usleep_range(1000, 2000);
 131
 132        ret = regulator_enable(ctx->avee_supply);
 133        if (ret < 0)
 134                goto err_avee;
 135
 136        usleep_range(10000, 11000);
 137
 138        ret = regulator_enable(ctx->vddh_supply);
 139        if (ret < 0)
 140                goto err_vddh;
 141
 142        usleep_range(10000, 11000);
 143
 144        sharp_ls060_reset(ctx);
 145
 146        ret = sharp_ls060_on(ctx);
 147        if (ret < 0) {
 148                dev_err(dev, "Failed to initialize panel: %d\n", ret);
 149                goto err_on;
 150        }
 151
 152        ctx->prepared = true;
 153
 154        return 0;
 155
 156err_on:
 157        regulator_disable(ctx->vddh_supply);
 158
 159        usleep_range(10000, 11000);
 160
 161err_vddh:
 162        regulator_disable(ctx->avee_supply);
 163
 164err_avee:
 165        regulator_disable(ctx->avdd_supply);
 166
 167        gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 168
 169err_avdd:
 170        regulator_disable(ctx->vddi_supply);
 171
 172        return ret;
 173}
 174
 175static int sharp_ls060_unprepare(struct drm_panel *panel)
 176{
 177        struct sharp_ls060 *ctx = to_sharp_ls060(panel);
 178        struct device *dev = &ctx->dsi->dev;
 179        int ret;
 180
 181        if (!ctx->prepared)
 182                return 0;
 183
 184        ret = sharp_ls060_off(ctx);
 185        if (ret < 0)
 186                dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
 187
 188        regulator_disable(ctx->vddh_supply);
 189
 190        usleep_range(10000, 11000);
 191
 192        regulator_disable(ctx->avee_supply);
 193        regulator_disable(ctx->avdd_supply);
 194
 195        gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 196
 197        regulator_disable(ctx->vddi_supply);
 198
 199        ctx->prepared = false;
 200        return 0;
 201}
 202
 203static const struct drm_display_mode sharp_ls060_mode = {
 204        .clock = (1080 + 96 + 16 + 64) * (1920 + 4 + 1 + 16) * 60 / 1000,
 205        .hdisplay = 1080,
 206        .hsync_start = 1080 + 96,
 207        .hsync_end = 1080 + 96 + 16,
 208        .htotal = 1080 + 96 + 16 + 64,
 209        .vdisplay = 1920,
 210        .vsync_start = 1920 + 4,
 211        .vsync_end = 1920 + 4 + 1,
 212        .vtotal = 1920 + 4 + 1 + 16,
 213        .width_mm = 75,
 214        .height_mm = 132,
 215};
 216
 217static int sharp_ls060_get_modes(struct drm_panel *panel,
 218                                 struct drm_connector *connector)
 219{
 220        struct drm_display_mode *mode;
 221
 222        mode = drm_mode_duplicate(connector->dev, &sharp_ls060_mode);
 223        if (!mode)
 224                return -ENOMEM;
 225
 226        drm_mode_set_name(mode);
 227
 228        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 229        connector->display_info.width_mm = mode->width_mm;
 230        connector->display_info.height_mm = mode->height_mm;
 231        drm_mode_probed_add(connector, mode);
 232
 233        return 1;
 234}
 235
 236static const struct drm_panel_funcs sharp_ls060_panel_funcs = {
 237        .prepare = sharp_ls060_prepare,
 238        .unprepare = sharp_ls060_unprepare,
 239        .get_modes = sharp_ls060_get_modes,
 240};
 241
 242static int sharp_ls060_probe(struct mipi_dsi_device *dsi)
 243{
 244        struct device *dev = &dsi->dev;
 245        struct sharp_ls060 *ctx;
 246        int ret;
 247
 248        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 249        if (!ctx)
 250                return -ENOMEM;
 251
 252        ctx->vddi_supply = devm_regulator_get(dev, "vddi");
 253        if (IS_ERR(ctx->vddi_supply))
 254                return PTR_ERR(ctx->vddi_supply);
 255
 256        ctx->vddh_supply = devm_regulator_get(dev, "vddh");
 257        if (IS_ERR(ctx->vddh_supply))
 258                return PTR_ERR(ctx->vddh_supply);
 259
 260        ctx->avdd_supply = devm_regulator_get(dev, "avdd");
 261        if (IS_ERR(ctx->avdd_supply))
 262                return PTR_ERR(ctx->avdd_supply);
 263
 264        ctx->avee_supply = devm_regulator_get(dev, "avee");
 265        if (IS_ERR(ctx->avee_supply))
 266                return PTR_ERR(ctx->avee_supply);
 267
 268        ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
 269        if (IS_ERR(ctx->reset_gpio))
 270                return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
 271                                     "Failed to get reset-gpios\n");
 272
 273        ctx->dsi = dsi;
 274        mipi_dsi_set_drvdata(dsi, ctx);
 275
 276        dsi->lanes = 4;
 277        dsi->format = MIPI_DSI_FMT_RGB888;
 278        dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
 279                          MIPI_DSI_MODE_NO_EOT_PACKET |
 280                          MIPI_DSI_CLOCK_NON_CONTINUOUS;
 281
 282        drm_panel_init(&ctx->panel, dev, &sharp_ls060_panel_funcs,
 283                       DRM_MODE_CONNECTOR_DSI);
 284
 285        ret = drm_panel_of_backlight(&ctx->panel);
 286        if (ret)
 287                return dev_err_probe(dev, ret, "Failed to get backlight\n");
 288
 289        drm_panel_add(&ctx->panel);
 290
 291        ret = mipi_dsi_attach(dsi);
 292        if (ret < 0) {
 293                dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
 294                drm_panel_remove(&ctx->panel);
 295                return ret;
 296        }
 297
 298        return 0;
 299}
 300
 301static int sharp_ls060_remove(struct mipi_dsi_device *dsi)
 302{
 303        struct sharp_ls060 *ctx = mipi_dsi_get_drvdata(dsi);
 304        int ret;
 305
 306        ret = mipi_dsi_detach(dsi);
 307        if (ret < 0)
 308                dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
 309
 310        drm_panel_remove(&ctx->panel);
 311
 312        return 0;
 313}
 314
 315static const struct of_device_id sharp_ls060t1sx01_of_match[] = {
 316        { .compatible = "sharp,ls060t1sx01" },
 317        { /* sentinel */ }
 318};
 319MODULE_DEVICE_TABLE(of, sharp_ls060t1sx01_of_match);
 320
 321static struct mipi_dsi_driver sharp_ls060_driver = {
 322        .probe = sharp_ls060_probe,
 323        .remove = sharp_ls060_remove,
 324        .driver = {
 325                .name = "panel-sharp-ls060t1sx01",
 326                .of_match_table = sharp_ls060t1sx01_of_match,
 327        },
 328};
 329module_mipi_dsi_driver(sharp_ls060_driver);
 330
 331MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
 332MODULE_DESCRIPTION("DRM driver for Sharp LS060T1SX01 1080p video mode dsi panel");
 333MODULE_LICENSE("GPL v2");
 334