linux/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * DSI interface to the Samsung S6E63M0 panel.
   4 * (C) 2019 Linus Walleij
   5 */
   6
   7#include <linux/module.h>
   8#include <linux/delay.h>
   9#include <linux/of_device.h>
  10
  11#include <drm/drm_mipi_dsi.h>
  12#include <drm/drm_print.h>
  13
  14#include "panel-samsung-s6e63m0.h"
  15
  16#define MCS_GLOBAL_PARAM        0xb0
  17#define S6E63M0_DSI_MAX_CHUNK   15 /* CMD + 15 bytes max */
  18
  19static int s6e63m0_dsi_dcs_read(struct device *dev, void *trsp,
  20                                const u8 cmd, u8 *data)
  21{
  22        struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
  23        int ret;
  24
  25        ret = mipi_dsi_dcs_read(dsi, cmd, data, 1);
  26        if (ret < 0) {
  27                dev_err(dev, "could not read DCS CMD %02x\n", cmd);
  28                return ret;
  29        }
  30
  31        dev_dbg(dev, "DSI read CMD %02x = %02x\n", cmd, *data);
  32
  33        return 0;
  34}
  35
  36static int s6e63m0_dsi_dcs_write(struct device *dev, void *trsp,
  37                                 const u8 *data, size_t len)
  38{
  39        struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
  40        const u8 *seqp = data;
  41        u8 cmd;
  42        u8 cmdwritten;
  43        int remain;
  44        int chunk;
  45        int ret;
  46
  47        dev_dbg(dev, "DSI writing dcs seq: %*ph\n", (int)len, data);
  48
  49        /* Pick out and skip past the DCS command */
  50        cmd = *seqp;
  51        seqp++;
  52        cmdwritten = 0;
  53        remain = len - 1;
  54        chunk = remain;
  55
  56        /* Send max S6E63M0_DSI_MAX_CHUNK bytes at a time */
  57        if (chunk > S6E63M0_DSI_MAX_CHUNK)
  58                chunk = S6E63M0_DSI_MAX_CHUNK;
  59        ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk);
  60        if (ret < 0) {
  61                dev_err(dev, "error sending DCS command seq cmd %02x\n", cmd);
  62                return ret;
  63        }
  64        cmdwritten += chunk;
  65        seqp += chunk;
  66
  67        while (cmdwritten < remain) {
  68                chunk = remain - cmdwritten;
  69                if (chunk > S6E63M0_DSI_MAX_CHUNK)
  70                        chunk = S6E63M0_DSI_MAX_CHUNK;
  71                ret = mipi_dsi_dcs_write(dsi, MCS_GLOBAL_PARAM, &cmdwritten, 1);
  72                if (ret < 0) {
  73                        dev_err(dev, "error sending CMD %02x global param %02x\n",
  74                                cmd, cmdwritten);
  75                        return ret;
  76                }
  77                ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk);
  78                if (ret < 0) {
  79                        dev_err(dev, "error sending CMD %02x chunk\n", cmd);
  80                        return ret;
  81                }
  82                cmdwritten += chunk;
  83                seqp += chunk;
  84        }
  85        dev_dbg(dev, "sent command %02x %02x bytes\n", cmd, cmdwritten);
  86
  87        usleep_range(8000, 9000);
  88
  89        return 0;
  90}
  91
  92static int s6e63m0_dsi_probe(struct mipi_dsi_device *dsi)
  93{
  94        struct device *dev = &dsi->dev;
  95        int ret;
  96
  97        dsi->lanes = 2;
  98        dsi->format = MIPI_DSI_FMT_RGB888;
  99        dsi->hs_rate = 349440000;
 100        dsi->lp_rate = 9600000;
 101        dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
 102                MIPI_DSI_MODE_VIDEO_BURST;
 103
 104        ret = s6e63m0_probe(dev, NULL, s6e63m0_dsi_dcs_read,
 105                            s6e63m0_dsi_dcs_write, true);
 106        if (ret)
 107                return ret;
 108
 109        ret = mipi_dsi_attach(dsi);
 110        if (ret < 0)
 111                s6e63m0_remove(dev);
 112
 113        return ret;
 114}
 115
 116static int s6e63m0_dsi_remove(struct mipi_dsi_device *dsi)
 117{
 118        mipi_dsi_detach(dsi);
 119        s6e63m0_remove(&dsi->dev);
 120        return 0;
 121}
 122
 123static const struct of_device_id s6e63m0_dsi_of_match[] = {
 124        { .compatible = "samsung,s6e63m0" },
 125        { /* sentinel */ }
 126};
 127MODULE_DEVICE_TABLE(of, s6e63m0_dsi_of_match);
 128
 129static struct mipi_dsi_driver s6e63m0_dsi_driver = {
 130        .probe                  = s6e63m0_dsi_probe,
 131        .remove                 = s6e63m0_dsi_remove,
 132        .driver                 = {
 133                .name           = "panel-samsung-s6e63m0",
 134                .of_match_table = s6e63m0_dsi_of_match,
 135        },
 136};
 137module_mipi_dsi_driver(s6e63m0_dsi_driver);
 138
 139MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>");
 140MODULE_DESCRIPTION("s6e63m0 LCD DSI Driver");
 141MODULE_LICENSE("GPL v2");
 142