141 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * DSI interface to the Samsung S6E63M0 panel.4 * (C) 2019 Linus Walleij5 */6 7#include <linux/module.h>8#include <linux/delay.h>9#include <linux/mod_devicetable.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 0xb017#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 void s6e63m0_dsi_remove(struct mipi_dsi_device *dsi)117{118 mipi_dsi_detach(dsi);119 s6e63m0_remove(&dsi->dev);120}121 122static const struct of_device_id s6e63m0_dsi_of_match[] = {123 { .compatible = "samsung,s6e63m0" },124 { /* sentinel */ }125};126MODULE_DEVICE_TABLE(of, s6e63m0_dsi_of_match);127 128static struct mipi_dsi_driver s6e63m0_dsi_driver = {129 .probe = s6e63m0_dsi_probe,130 .remove = s6e63m0_dsi_remove,131 .driver = {132 .name = "panel-samsung-s6e63m0",133 .of_match_table = s6e63m0_dsi_of_match,134 },135};136module_mipi_dsi_driver(s6e63m0_dsi_driver);137 138MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>");139MODULE_DESCRIPTION("s6e63m0 LCD DSI Driver");140MODULE_LICENSE("GPL v2");141