aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@linaro.org>2020-03-23 15:38:27 +0800
committerBryan O'Donoghue <bryan.odonoghue@linaro.org>2022-07-09 02:23:05 +0100
commitd8cf4eb5b47d6085f7c90021586ff98e236d8da7 (patch)
treef1c5d1d942a25af9e458545d11f3f6739885e12c
parentd8b67fa6449e2c6ed46f55457a9ad5007e05e33e (diff)
drm/panel: Add driver for Truly panel with R65530 IC
It adds a drm panel driver for Truly panel with R65530 driver IC. It supports not only Truly panel but also panel from AUO that is integrated with a R65530 driver IC, although the driver is named after Truly. Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
-rw-r--r--drivers/gpu/drm/panel/Kconfig8
-rw-r--r--drivers/gpu/drm/panel/Makefile1
-rw-r--r--drivers/gpu/drm/panel/panel-truly-r63350.c697
3 files changed, 706 insertions, 0 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 38799effd00a..7fa03f524580 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -677,6 +677,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA
Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI
Video Mode panel
+config DRM_PANEL_TRULY_R65530
+ tristate "Truly panel with R65530 driver IC"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ help
+ Say Y here if you want to enable support for Truly DSI panel with
+ R65530 driver IC.
+
config DRM_PANEL_VISIONOX_RM69299
tristate "Visionox RM69299"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 42a7ab54234b..09b20ae5870d 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
+obj-$(CONFIG_DRM_PANEL_TRULY_R65530) += panel-truly-r63350.o
obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o
obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o
diff --git a/drivers/gpu/drm/panel/panel-truly-r63350.c b/drivers/gpu/drm/panel/panel-truly-r63350.c
new file mode 100644
index 000000000000..adb47c78f459
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-truly-r63350.c
@@ -0,0 +1,697 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+static const char * const regulator_names[] = {
+ "iovcc",
+ "avdd",
+ "avee",
+};
+
+struct cmd_set {
+ const u8 *payload;
+ size_t size;
+ int wait_ms;
+};
+
+struct truly_data {
+ const struct cmd_set *panel_oncmds;
+ unsigned int num_oncmds;
+ const struct cmd_set *panel_offcmds;
+ unsigned int num_offcmds;
+};
+
+struct truly_panel {
+ struct drm_panel panel;
+ struct device *dev;
+ struct mipi_dsi_device *dsi;
+ const struct truly_data *data;
+
+ struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
+ struct gpio_desc *reset_gpio;
+
+ bool prepared;
+ bool enabled;
+};
+
+static inline struct truly_panel *panel_to_truly(struct drm_panel *panel)
+{
+ return container_of(panel, struct truly_panel, panel);
+}
+
+static int truly_r63350_power_off(struct truly_panel *truly)
+{
+ gpiod_set_value(truly->reset_gpio, 1);
+ return regulator_bulk_disable(ARRAY_SIZE(truly->supplies),
+ truly->supplies);
+}
+
+static int truly_r63350_power_on(struct truly_panel *truly)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(truly->supplies),
+ truly->supplies);
+ if (ret)
+ return ret;
+
+ /* Reset panel */
+ gpiod_set_value(truly->reset_gpio, 0);
+ usleep_range(20000, 30000);
+
+ gpiod_set_value(truly->reset_gpio, 1);
+ usleep_range(10000, 20000);
+
+ gpiod_set_value(truly->reset_gpio, 0);
+ usleep_range(20000, 30000);
+
+ return 0;
+}
+
+static int truly_r63350_unprepare(struct drm_panel *panel)
+{
+ struct truly_panel *truly = panel_to_truly(panel);
+ const struct truly_data *data = truly->data;
+ const struct cmd_set *cmds = data->panel_offcmds;
+ unsigned int num_cmds = data->num_offcmds;
+ struct mipi_dsi_device *dsi = truly->dsi;
+ struct device *dev = truly->dev;
+ int ret;
+ int i;
+
+ if (!truly->prepared)
+ return 0;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "set_display_off cmd failed: %d\n", ret);
+ return ret;
+ }
+
+ /* 120ms delay required here as per DCS spec */
+ msleep(120);
+
+ ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "enter_sleep cmd failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Panel-off magic commands */
+ for (i = 0; i < num_cmds; i++) {
+ ret = mipi_dsi_dcs_write_buffer(dsi, cmds[i].payload,
+ cmds[i].size);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "off cmd tx%d failed: %d\n", i, ret);
+ return ret;
+ }
+
+ if (cmds[i].wait_ms)
+ msleep(cmds[i].wait_ms);
+ else
+ usleep_range(80, 100);
+ }
+
+ ret = truly_r63350_power_off(truly);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "power_off failed: %d\n", ret);
+ return ret;
+ }
+
+ truly->prepared = false;
+
+ return 0;
+}
+
+static int truly_r63350_prepare(struct drm_panel *panel)
+{
+ struct truly_panel *truly = panel_to_truly(panel);
+ const struct truly_data *data = truly->data;
+ const struct cmd_set *cmds = data->panel_oncmds;
+ unsigned int num_cmds = data->num_oncmds;
+ struct mipi_dsi_device *dsi = truly->dsi;
+ struct device *dev = truly->dev;
+ int ret;
+ int i;
+
+ if (truly->prepared)
+ return 0;
+
+ ret = truly_r63350_power_on(truly);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "failed to power on: %d\n", ret);
+ return ret;
+ }
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_soft_reset(dsi);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(10000, 20000);
+
+ /* Panel-on magic commands */
+ for (i = 0; i < num_cmds; i++) {
+ ret = mipi_dsi_dcs_write_buffer(dsi, cmds[i].payload,
+ cmds[i].size);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "on cmd tx%d failed: %d\n", i, ret);
+ goto power_off;
+ }
+
+ if (cmds[i].wait_ms)
+ msleep(cmds[i].wait_ms);
+ else
+ usleep_range(80, 100);
+ }
+
+ ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "exit_sleep_mode cmd failed: %d\n", ret);
+ goto power_off;
+ }
+
+ /* Per DSI spec wait 120ms after sending exit sleep DCS command */
+ msleep(120);
+
+ ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "set_display_on cmd failed: %d\n", ret);
+ goto power_off;
+ }
+
+ /* Per DSI spec wait 120ms after sending set_display_on DCS command */
+ msleep(120);
+
+ truly->prepared = true;
+
+ return 0;
+
+power_off:
+ truly_r63350_power_off(truly);
+ return ret;
+}
+
+static const struct drm_display_mode truly_fhd_mode = {
+ .clock = 144981,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 92,
+ .hsync_end = 1080 + 92 + 20,
+ .htotal = 1080 + 92 + 20 + 60,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 4,
+ .vsync_end = 1920 + 4 + 1,
+ .vtotal = 1920 + 4 + 1 + 5,
+ .vrefresh = 60,
+ .flags = 0,
+};
+
+static int truly_r63350_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct truly_panel *truly = panel_to_truly(panel);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, &truly_fhd_mode);
+ if (!mode) {
+ DRM_DEV_ERROR(truly->dev,
+ "failed to add display mode\n");
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+
+ connector->display_info.width_mm = 68;
+ connector->display_info.height_mm = 121;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs truly_r63350_drm_funcs = {
+ .prepare = truly_r63350_prepare,
+ .unprepare = truly_r63350_unprepare,
+ .get_modes = truly_r63350_get_modes,
+};
+
+static int truly_r63350_panel_add(struct truly_panel *truly)
+{
+ struct device *dev = truly->dev;
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(truly->supplies); i++)
+ truly->supplies[i].supply = regulator_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(truly->supplies),
+ truly->supplies);
+ if (ret) {
+ dev_err(dev, "failed to get regulator: %d\n", ret);
+ return ret;
+ }
+
+ truly->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(truly->reset_gpio)) {
+ DRM_DEV_ERROR(dev, "failed to get reset gpio %ld\n",
+ PTR_ERR(truly->reset_gpio));
+ return PTR_ERR(truly->reset_gpio);
+ }
+
+ drm_panel_init(&truly->panel, dev, &truly_r63350_drm_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ ret = drm_panel_of_backlight(&truly->panel);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to find backlight: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_panel_add(&truly->panel);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to add panel: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const u8 truly_oncmd0[] = {
+ 0xb0, 0x00,
+};
+
+static const u8 truly_oncmd1[] = {
+ 0xd6, 0x01,
+};
+
+static const u8 truly_oncmd2[] = {
+ 0xb3, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 truly_oncmd3[] = {
+ 0xb4, 0x0c, 0x00,
+};
+
+static const u8 truly_oncmd4[] = {
+ 0xb6, 0x4b, 0xdb, 0x16,
+};
+
+static const u8 truly_oncmd5[] = {
+ 0xbe, 0x00, 0x04,
+};
+
+static const u8 truly_oncmd6[] = {
+ 0xc0, 0x66,
+};
+
+static const u8 truly_oncmd7[] = {
+ 0xc1, 0x04, 0x60, 0x00, 0x20, 0xa9, 0x30, 0x20,
+ 0x63, 0xf0, 0xff, 0xff, 0x9b, 0x7b, 0xcf, 0xb5,
+ 0xff, 0xff, 0x87, 0x8c, 0x41, 0x22, 0x54, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x33, 0x03,
+ 0x22, 0x00, 0xff,
+};
+
+static const u8 truly_oncmd8[] = {
+ 0xc2, 0x31, 0xf7, 0x80, 0x06, 0x04, 0x00, 0x00,
+ 0x08,
+};
+
+static const u8 truly_oncmd9[] = {
+ 0xc3, 0x00, 0x00, 0x00,
+};
+
+static const u8 truly_oncmd10[] = {
+ 0xc4, 0x70, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x00, 0x02,
+};
+
+static const u8 truly_oncmd11[] = {
+ 0xc5, 0x00,
+};
+
+static const u8 truly_oncmd12[] = {
+ 0xc6, 0xc8, 0x3c, 0x3c, 0x07, 0x01, 0x07, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1a, 0x07, 0xc8,
+};
+
+static const u8 truly_oncmd13[] = {
+ 0xc7, 0x03, 0x15, 0x1f, 0x2a, 0x39, 0x46, 0x4e,
+ 0x5b, 0x3d, 0x45, 0x52, 0x5f, 0x68, 0x6d, 0x72,
+ 0x01, 0x15, 0x1f, 0x2a, 0x39, 0x46, 0x4e, 0x5b,
+ 0x3d, 0x45, 0x52, 0x5f, 0x68, 0x6d, 0x78,
+};
+
+static const u8 truly_oncmd14[] = {
+ 0xcb, 0xff, 0xe1, 0x87, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xe1, 0x87, 0xff, 0xe8, 0x00, 0x00,
+};
+
+static const u8 truly_oncmd15[] = {
+ 0xcc, 0x34,
+};
+
+static const u8 truly_oncmd16[] = {
+ 0xd0, 0x11, 0x00, 0x00, 0x56, 0xd5, 0x40, 0x19,
+ 0x19, 0x09, 0x00,
+};
+
+static const u8 truly_oncmd17[] = {
+ 0xd1, 0x00, 0x48, 0x16, 0x0f,
+};
+
+static const u8 truly_oncmd18[] = {
+ 0xd2, 0x5c, 0x00, 0x00,
+};
+
+static const u8 truly_oncmd19[] = {
+ 0xd3, 0x1b, 0x33, 0xbb, 0xbb, 0xb3, 0x33, 0x33,
+ 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0,
+ 0x0c, 0x4d, 0x4d, 0x33, 0x33, 0x72, 0x12, 0x8a,
+ 0x57, 0x3d, 0xbc,
+};
+
+static const u8 truly_oncmd20[] = {
+ 0xd5, 0x06, 0x00, 0x00, 0x01, 0x39, 0x01, 0x39,
+};
+
+static const u8 truly_oncmd21[] = {
+ 0xd8, 0x00, 0x00, 0x00,
+};
+
+static const u8 truly_oncmd22[] = {
+ 0xd9, 0x00, 0x00, 0x00,
+};
+
+static const u8 truly_oncmd23[] = {
+ 0xfd, 0x00, 0x00, 0x00, 0x30,
+};
+
+static const u8 truly_oncmd24[] = {
+ 0x35, 0x00,
+};
+
+static const u8 truly_oncmd25[] = {
+ 0x29,
+};
+
+static const u8 truly_oncmd26[] = {
+ 0x11,
+};
+
+static const struct cmd_set truly_oncmds[] = {
+ { truly_oncmd0, ARRAY_SIZE(truly_oncmd0), },
+ { truly_oncmd1, ARRAY_SIZE(truly_oncmd1), },
+ { truly_oncmd2, ARRAY_SIZE(truly_oncmd2), },
+ { truly_oncmd3, ARRAY_SIZE(truly_oncmd3), },
+ { truly_oncmd4, ARRAY_SIZE(truly_oncmd4), },
+ { truly_oncmd5, ARRAY_SIZE(truly_oncmd5), },
+ { truly_oncmd6, ARRAY_SIZE(truly_oncmd6), },
+ { truly_oncmd7, ARRAY_SIZE(truly_oncmd7), },
+ { truly_oncmd8, ARRAY_SIZE(truly_oncmd8), },
+ { truly_oncmd9, ARRAY_SIZE(truly_oncmd9), },
+ { truly_oncmd10, ARRAY_SIZE(truly_oncmd10), },
+ { truly_oncmd11, ARRAY_SIZE(truly_oncmd11), },
+ { truly_oncmd12, ARRAY_SIZE(truly_oncmd12), },
+ { truly_oncmd13, ARRAY_SIZE(truly_oncmd13), },
+ { truly_oncmd14, ARRAY_SIZE(truly_oncmd14), },
+ { truly_oncmd15, ARRAY_SIZE(truly_oncmd15), },
+ { truly_oncmd16, ARRAY_SIZE(truly_oncmd16), },
+ { truly_oncmd17, ARRAY_SIZE(truly_oncmd17), },
+ { truly_oncmd18, ARRAY_SIZE(truly_oncmd18), },
+ { truly_oncmd19, ARRAY_SIZE(truly_oncmd19), },
+ { truly_oncmd20, ARRAY_SIZE(truly_oncmd20), },
+ { truly_oncmd21, ARRAY_SIZE(truly_oncmd21), },
+ { truly_oncmd22, ARRAY_SIZE(truly_oncmd22), },
+ { truly_oncmd23, ARRAY_SIZE(truly_oncmd23), },
+ { truly_oncmd24, ARRAY_SIZE(truly_oncmd24), },
+ { truly_oncmd25, ARRAY_SIZE(truly_oncmd25), 50, },
+ { truly_oncmd26, ARRAY_SIZE(truly_oncmd26), 120, },
+};
+
+static const u8 truly_offcmd0[] = {
+ 0x28,
+};
+
+static const u8 truly_offcmd1[] = {
+ 0xb0, 0x04,
+};
+
+static const u8 truly_offcmd2[] = {
+ 0xd3, 0x13, 0x33, 0xbb, 0xb3, 0xb3, 0x33, 0x33,
+ 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0,
+ 0x0c, 0x4d, 0x4d, 0x33, 0x33, 0x72, 0x12, 0x8a,
+ 0x57, 0x3d, 0xbc,
+};
+
+static const u8 truly_offcmd3[] = {
+ 0x10,
+};
+
+static const u8 truly_offcmd4[] = {
+ 0xb0, 0x00,
+};
+
+static const u8 truly_offcmd5[] = {
+ 0xb1, 0x01,
+};
+
+static const struct cmd_set truly_offcmds[] = {
+ { truly_offcmd0, ARRAY_SIZE(truly_offcmd0), 20, },
+ { truly_offcmd1, ARRAY_SIZE(truly_offcmd1), },
+ { truly_offcmd2, ARRAY_SIZE(truly_offcmd2), 27, },
+ { truly_offcmd3, ARRAY_SIZE(truly_offcmd3), 120, },
+ { truly_offcmd4, ARRAY_SIZE(truly_offcmd4), },
+ { truly_offcmd5, ARRAY_SIZE(truly_offcmd5), },
+};
+
+static const struct truly_data truly_fhd_data = {
+ .panel_oncmds = truly_oncmds,
+ .num_oncmds = ARRAY_SIZE(truly_oncmds),
+ .panel_offcmds = truly_offcmds,
+ .num_offcmds = ARRAY_SIZE(truly_offcmds),
+};
+
+static const u8 auo_oncmd0[] = {
+ 0xb0, 0x04,
+};
+
+static const u8 auo_oncmd1[] = {
+ 0xd6, 0x01,
+};
+
+static const u8 auo_oncmd2[] = {
+ 0xb3, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 auo_oncmd3[] = {
+ 0xb4, 0x0c, 0x00,
+};
+
+static const u8 auo_oncmd4[] = {
+ 0xb6, 0x4b, 0xdb, 0x00,
+};
+
+static const u8 auo_oncmd5[] = {
+ 0xc0, 0x66,
+};
+
+static const u8 auo_oncmd6[] = {
+ 0xc1, 0x04, 0x60, 0x00, 0x20, 0x29, 0x41, 0x22,
+ 0xfb, 0xf0, 0xff, 0xff, 0x9b, 0x7b, 0xcf, 0xb5,
+ 0xff, 0xff, 0x87, 0x8c, 0xc5, 0x11, 0x54, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x11, 0x02,
+ 0x21, 0x00, 0xff, 0x11,
+};
+
+static const u8 auo_oncmd7[] = {
+ 0xc2, 0x31, 0xf7, 0x80, 0x06, 0x04, 0x00, 0x00,
+ 0x08,
+};
+
+static const u8 auo_oncmd8[] = {
+ 0xc4, 0x70, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x00, 0x02,
+};
+
+static const u8 auo_oncmd9[] = {
+ 0xc6, 0xc8, 0x3c, 0x3c, 0x07, 0x01, 0x07, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1a, 0x07, 0xc8,
+};
+
+static const u8 auo_oncmd10[] = {
+ 0xc7, 0x0a, 0x18, 0x20, 0x29, 0x37, 0x43, 0x4d,
+ 0x5b, 0x3f, 0x46, 0x52, 0x5f, 0x67, 0x70, 0x7c,
+ 0x0a, 0x18, 0x20, 0x29, 0x37, 0x43, 0x4d, 0x5b,
+ 0x3f, 0x46, 0x52, 0x5f, 0x67, 0x70, 0x7c,
+};
+
+static const u8 auo_oncmd11[] = {
+ 0xcb, 0x7f, 0xe1, 0x87, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
+};
+
+static const u8 auo_oncmd12[] = {
+ 0xcc, 0x32,
+};
+
+static const u8 auo_oncmd13[] = {
+ 0xd0, 0x11, 0x00, 0x00, 0x56, 0xd7, 0x40, 0x19,
+ 0x19, 0x09, 0x00,
+};
+
+static const u8 auo_oncmd14[] = {
+ 0xd1, 0x00, 0x48, 0x16, 0x0f,
+};
+
+static const u8 auo_oncmd15[] = {
+ 0xd3, 0x1b, 0x33, 0xbb, 0xbb, 0xb3, 0x33, 0x33,
+ 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0,
+ 0x0c, 0x37, 0x37, 0x33, 0x33, 0x72, 0x12, 0x8a,
+ 0x57, 0x3d, 0xbc,
+};
+
+static const u8 auo_oncmd16[] = {
+ 0xd5, 0x06, 0x00, 0x00, 0x01, 0x35, 0x01, 0x35,
+};
+
+static const u8 auo_oncmd17[] = {
+ 0x29,
+};
+
+static const u8 auo_oncmd18[] = {
+ 0x11,
+};
+
+static const struct cmd_set auo_oncmds[] = {
+ { auo_oncmd0, ARRAY_SIZE(auo_oncmd0), },
+ { auo_oncmd1, ARRAY_SIZE(auo_oncmd1), },
+ { auo_oncmd2, ARRAY_SIZE(auo_oncmd2), },
+ { auo_oncmd3, ARRAY_SIZE(auo_oncmd3), },
+ { auo_oncmd4, ARRAY_SIZE(auo_oncmd4), },
+ { auo_oncmd5, ARRAY_SIZE(auo_oncmd5), },
+ { auo_oncmd6, ARRAY_SIZE(auo_oncmd6), },
+ { auo_oncmd7, ARRAY_SIZE(auo_oncmd7), },
+ { auo_oncmd8, ARRAY_SIZE(auo_oncmd8), },
+ { auo_oncmd9, ARRAY_SIZE(auo_oncmd9), },
+ { auo_oncmd10, ARRAY_SIZE(auo_oncmd10), },
+ { auo_oncmd11, ARRAY_SIZE(auo_oncmd11), },
+ { auo_oncmd12, ARRAY_SIZE(auo_oncmd12), },
+ { auo_oncmd13, ARRAY_SIZE(auo_oncmd13), },
+ { auo_oncmd14, ARRAY_SIZE(auo_oncmd14), },
+ { auo_oncmd15, ARRAY_SIZE(auo_oncmd15), },
+ { auo_oncmd16, ARRAY_SIZE(auo_oncmd16), },
+ { auo_oncmd17, ARRAY_SIZE(auo_oncmd17), 100, },
+ { auo_oncmd18, ARRAY_SIZE(auo_oncmd18), 120, },
+};
+
+static const u8 auo_offcmd0[] = {
+ 0x28,
+};
+
+static const u8 auo_offcmd1[] = {
+ 0xb0, 0x04,
+};
+
+static const struct cmd_set auo_offcmds[] = {
+ { auo_offcmd0, ARRAY_SIZE(auo_offcmd0), 10, },
+ { auo_offcmd1, ARRAY_SIZE(auo_offcmd1), 120, },
+};
+
+static const struct truly_data auo_fhd_data = {
+ .panel_oncmds = auo_oncmds,
+ .num_oncmds = ARRAY_SIZE(auo_oncmds),
+ .panel_offcmds = auo_offcmds,
+ .num_offcmds = ARRAY_SIZE(auo_offcmds),
+};
+
+static int truly_r63350_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct truly_panel *truly;
+ int ret;
+
+ truly = devm_kzalloc(dev, sizeof(*truly), GFP_KERNEL);
+ if (!truly)
+ return -ENOMEM;
+
+ truly->data = of_device_get_match_data(dev);
+ if (!truly->data)
+ return -ENODEV;
+
+ truly->dev = dev;
+
+ ret = truly_r63350_panel_add(truly);
+ if (ret)
+ return ret;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_LPM;
+ truly->dsi = dsi;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to attach DSI device: %d\n", ret);
+ goto rm_panel;
+ }
+
+ mipi_dsi_set_drvdata(dsi, truly);
+
+ return 0;
+
+rm_panel:
+ drm_panel_remove(&truly->panel);
+ return ret;
+}
+
+static int truly_r63350_remove(struct mipi_dsi_device *dsi)
+{
+ struct truly_panel *truly = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(truly->dsi);
+ drm_panel_remove(&truly->panel);
+
+ return 0;
+}
+
+static const struct of_device_id truly_r63350_of_match[] = {
+ { .compatible = "truly,r63350-fhd", .data = &truly_fhd_data, },
+ { .compatible = "auo,r63350-fhd", .data = &auo_fhd_data, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, truly_r63350_of_match);
+
+static struct mipi_dsi_driver truly_r63350_driver = {
+ .driver = {
+ .name = "panel-truly-r63350",
+ .of_match_table = truly_r63350_of_match,
+ },
+ .probe = truly_r63350_probe,
+ .remove = truly_r63350_remove,
+};
+module_mipi_dsi_driver(truly_r63350_driver);
+
+MODULE_DESCRIPTION("Truly R63350 DSI Panel Driver");
+MODULE_LICENSE("GPL v2");