2c68614713
Our patch needs to be adjusted after commit 58e4a2d27d32 ("extcon: Fix extcon_get_extcon_dev() error handling"). Also generate all other patch headers, and make it possible to apply patch 0008 and 0009 with git am.
906 lines
26 KiB
Diff
906 lines
26 KiB
Diff
From ef45d556725b6e29196e805795a9a2756fa6d706 Mon Sep 17 00:00:00 2001
|
|
From: Jack Knightly <J__A__K@hotmail.com>
|
|
Date: Fri, 14 Oct 2022 20:58:17 +0200
|
|
Subject: [PATCH 08/13] Add s6evr02 panel
|
|
|
|
This adds the s6evr02 panel which the Samsung Galaxy Note II
|
|
uses. After this is merged I will create another MR for t0lte to be
|
|
added as a new device.
|
|
|
|
PLEASE NOTE - I did not write the panel driver, but merely brought up
|
|
an old driver that worked with mainline a few years ago. The driver
|
|
was written by forkbomb and can be found here:
|
|
https://github.com/fourkbomb/linux/blob/master/drivers/gpu/drm/panel/panel-samsung-s6evr02.c
|
|
Given it is based on another panel driver that is still in mainline
|
|
today, I applied the commits that that panel driver underwent between
|
|
then and now, and it works.
|
|
---
|
|
arch/arm/boot/dts/exynos4412-n710x.dts | 69 ++
|
|
drivers/gpu/drm/panel/Kconfig | 6 +
|
|
drivers/gpu/drm/panel/Makefile | 1 +
|
|
drivers/gpu/drm/panel/panel-samsung-s6evr02.c | 764 ++++++++++++++++++
|
|
4 files changed, 840 insertions(+)
|
|
create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6evr02.c
|
|
|
|
diff --git a/arch/arm/boot/dts/exynos4412-n710x.dts b/arch/arm/boot/dts/exynos4412-n710x.dts
|
|
index 9ae05b0d684c..da0e475b1063 100644
|
|
--- a/arch/arm/boot/dts/exynos4412-n710x.dts
|
|
+++ b/arch/arm/boot/dts/exynos4412-n710x.dts
|
|
@@ -38,6 +38,75 @@ &cam_io_reg {
|
|
status = "okay";
|
|
};
|
|
|
|
+
|
|
+&dsi_0 {
|
|
+ vddcore-supply = <&ldo8_reg>;
|
|
+ vddio-supply = <&ldo10_reg>;
|
|
+ samsung,burst-clock-frequency = <500000000>;
|
|
+ samsung,esc-clock-frequency = <20000000>;
|
|
+ samsung,pll-clock-frequency = <24000000>;
|
|
+ status = "okay";
|
|
+
|
|
+ ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ port@1 {
|
|
+ reg = <1>;
|
|
+
|
|
+ dsi_out: endpoint@0 {
|
|
+ samsung,burst-clock-frequency = <500000000>;
|
|
+ samsung,esc-clock-frequency = <20000000>;
|
|
+ //status = "disabled";
|
|
+ remote-endpoint = <&dsi_in_s6evr02>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ s6evr02: panel-s6evr02@0 {
|
|
+ compatible = "samsung,s6evr02";
|
|
+ reg = <0>;
|
|
+ vdd3-supply = <&ldo13_reg>;
|
|
+ vci-supply = <&ldo25_reg>;
|
|
+ reset-gpios = <&gpf2 1 GPIO_ACTIVE_HIGH>;
|
|
+ power-on-delay = <50>;
|
|
+ reset-delay = <100>;
|
|
+ init-delay = <100>;
|
|
+ panel-width-mm = <69>;
|
|
+ panel-height-mm = <123>;
|
|
+ // HIGH means s6evr02
|
|
+ present-gpios = <&gpf1 0 GPIO_ACTIVE_HIGH>;
|
|
+ //status = "disabled";
|
|
+ status = "okay";
|
|
+
|
|
+ display-timings {
|
|
+ timing0_s6evr02: timing-0 {
|
|
+ clock-frequency = <62614944>;
|
|
+ hactive = <720>;
|
|
+ vactive = <1280>;
|
|
+ hfront-porch = <70>;
|
|
+ hback-porch = <40>;
|
|
+ hsync-len = <3>;
|
|
+ vfront-porch = <13>;
|
|
+ vback-porch = <1>;
|
|
+ vsync-len = <2>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ port {
|
|
+ dsi_in_s6evr02: endpoint {
|
|
+ //status = "disabled";
|
|
+ remote-endpoint = <&dsi_out>;
|
|
+ status = "okay";
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+};
|
|
+
|
|
&i2c_3 {
|
|
samsung,i2c-sda-delay = <100>;
|
|
samsung,i2c-slave-addr = <0x10>;
|
|
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
|
|
index a9043eacce97..6b7c6ef55a01 100644
|
|
--- a/drivers/gpu/drm/panel/Kconfig
|
|
+++ b/drivers/gpu/drm/panel/Kconfig
|
|
@@ -536,6 +536,12 @@ config DRM_PANEL_SAMSUNG_S6E8AA0
|
|
depends on OF
|
|
select DRM_MIPI_DSI
|
|
select VIDEOMODE_HELPERS
|
|
+
|
|
+config DRM_PANEL_SAMSUNG_S6EVR02
|
|
+ tristate "Samsung S6EVR02 DSI video mode panel"
|
|
+ depends on OF
|
|
+ select DRM_MIPI_DSI
|
|
+ select VIDEOMODE_HELPERS
|
|
|
|
config DRM_PANEL_SAMSUNG_SOFEF00
|
|
tristate "Samsung sofef00/s6e3fc2x01 OnePlus 6/6T DSI cmd mode panels"
|
|
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
|
|
index 34e717382dbb..b3d149475a38 100644
|
|
--- a/drivers/gpu/drm/panel/Makefile
|
|
+++ b/drivers/gpu/drm/panel/Makefile
|
|
@@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_SPI) += panel-samsung-s6e63m0-spi.o
|
|
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o
|
|
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o
|
|
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
|
|
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6EVR02) += panel-samsung-s6evr02.o
|
|
obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF00) += panel-samsung-sofef00.o
|
|
obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
|
|
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
|
|
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6evr02.c b/drivers/gpu/drm/panel/panel-samsung-s6evr02.c
|
|
new file mode 100644
|
|
index 000000000000..f1612a6c262c
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/panel/panel-samsung-s6evr02.c
|
|
@@ -0,0 +1,764 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+/*
|
|
+ * MIPI-DSI based S6EVR02 AMOLED LCD 5.5 inch panel driver.
|
|
+ *
|
|
+ * Copyright (c) 2017 Simon Shields, <simon@lineageos.org>
|
|
+ *
|
|
+ * Based on the s6e8aa0 panel driver,
|
|
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
|
|
+ *
|
|
+ * Inki Dae, <inki.dae@samsung.com>
|
|
+ * Donghwa Lee, <dh09.lee@samsung.com>
|
|
+ * Joongmock Shin <jmock.shin@samsung.com>
|
|
+ * Eunchul Kim <chulspro.kim@samsung.com>
|
|
+ * Tomasz Figa <t.figa@samsung.com>
|
|
+ * Andrzej Hajda <a.hajda@samsung.com>
|
|
+*/
|
|
+
|
|
+#include <linux/delay.h>
|
|
+#include <linux/gpio/consumer.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+
|
|
+#include <linux/backlight.h>
|
|
+#include <video/mipi_display.h>
|
|
+#include <video/of_videomode.h>
|
|
+#include <video/videomode.h>
|
|
+
|
|
+#include <drm/drm_mipi_dsi.h>
|
|
+#include <drm/drm_modes.h>
|
|
+#include <drm/drm_panel.h>
|
|
+
|
|
+#define UB_VERSION 0x10
|
|
+
|
|
+#define LDI_MTP_LENGTH 24
|
|
+#define GAMMA_LEVEL_NUM 33
|
|
+#define GAMMA_TABLE_LEN 34
|
|
+
|
|
+typedef u8 s6evr02_gamma_table[GAMMA_TABLE_LEN];
|
|
+
|
|
+#define S6EVR02_STATE_BIT_ENABLED 0
|
|
+
|
|
+struct s6evr02 {
|
|
+ struct device *dev;
|
|
+ struct drm_panel panel;
|
|
+
|
|
+ struct regulator_bulk_data supplies[2];
|
|
+ struct gpio_desc *reset_gpio;
|
|
+ u32 power_on_delay;
|
|
+ u32 reset_delay;
|
|
+ u32 init_delay;
|
|
+ struct videomode vm;
|
|
+ u32 width_mm;
|
|
+ u32 height_mm;
|
|
+
|
|
+ unsigned long state;
|
|
+ u8 version;
|
|
+ u8 id;
|
|
+ int brightness;
|
|
+
|
|
+ /* This field is tested by functions directly accessing DSI bus before
|
|
+ * transfer, transfer is skipped if it is set. In case of transfer
|
|
+ * failure or unexpected response the field is set to error value.
|
|
+ * Such construct allows to eliminate many checks in higher level
|
|
+ * functions.
|
|
+ */
|
|
+ int error;
|
|
+};
|
|
+
|
|
+static const s6evr02_gamma_table s6evr02_gamma_tables[GAMMA_LEVEL_NUM] = {
|
|
+ {
|
|
+ /* 20cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x86, 0x87, 0x87,
|
|
+ 0x86, 0x86, 0x85, 0x88, 0x8a, 0x88, 0x86, 0x85, 0x88, 0x75,
|
|
+ 0x63, 0x83, 0x63, 0x60, 0x7d, 0x78, 0x85, 0xb8, 0x33, 0x3f,
|
|
+ 0x2c, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 30cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x86, 0x87, 0x87,
|
|
+ 0x86, 0x85, 0x84, 0x88, 0x8a, 0x87, 0x85, 0x84, 0x87, 0x80,
|
|
+ 0x76, 0x85, 0x68, 0x60, 0x76, 0x78, 0x85, 0xb0, 0x33, 0x3f,
|
|
+ 0x2c, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 40cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x85, 0x86, 0x87,
|
|
+ 0x86, 0x86, 0x85, 0x87, 0x88, 0x86, 0x86, 0x85, 0x89, 0x80,
|
|
+ 0x80, 0x83, 0x6a, 0x5c, 0x71, 0x77, 0x81, 0xaa, 0x37, 0x45,
|
|
+ 0x2f, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 50cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x85, 0x86, 0x87,
|
|
+ 0x85, 0x85, 0x84, 0x88, 0x89, 0x87, 0x84, 0x82, 0x86, 0x83,
|
|
+ 0x84, 0x85, 0x6f, 0x63, 0x71, 0x7d, 0x81, 0xa5, 0x37, 0x45,
|
|
+ 0x2f, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 60cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x85, 0x86, 0x87,
|
|
+ 0x85, 0x85, 0x84, 0x86, 0x88, 0x85, 0x83, 0x81, 0x85, 0x81,
|
|
+ 0x80, 0x83, 0x77, 0x69, 0x76, 0x7f, 0x81, 0xa0, 0x37, 0x45,
|
|
+ 0x2f, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 70cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x84, 0x85, 0x86,
|
|
+ 0x85, 0x85, 0x84, 0x87, 0x89, 0x87, 0x83, 0x81, 0x85, 0x81,
|
|
+ 0x80, 0x83, 0x71, 0x64, 0x6f, 0x89, 0x88, 0xa3, 0x37, 0x45,
|
|
+ 0x2f, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 80cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x84, 0x85, 0x86,
|
|
+ 0x85, 0x85, 0x84, 0x86, 0x87, 0x85, 0x84, 0x82, 0x87, 0x81,
|
|
+ 0x80, 0x83, 0x73, 0x66, 0x6f, 0x8a, 0x88, 0xa0, 0x37, 0x45,
|
|
+ 0x2f, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 90cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x84, 0x85, 0x86,
|
|
+ 0x85, 0x85, 0x84, 0x86, 0x87, 0x85, 0x81, 0x7f, 0x85, 0x7e,
|
|
+ 0x7c, 0x80, 0x7a, 0x6d, 0x75, 0x8b, 0x88, 0x9e, 0x37, 0x45,
|
|
+ 0x2f, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 100cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x84, 0x85, 0x86,
|
|
+ 0x84, 0x83, 0x83, 0x87, 0x88, 0x86, 0x81, 0x7f, 0x85, 0x7e,
|
|
+ 0x7c, 0x80, 0x7a, 0x70, 0x75, 0x86, 0x7d, 0x98, 0x3b, 0x4b,
|
|
+ 0x33, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 102cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x84, 0x85, 0x86,
|
|
+ 0x85, 0x85, 0x84, 0x86, 0x87, 0x85, 0x81, 0x7f, 0x85, 0x7e,
|
|
+ 0x7c, 0x80, 0x7a, 0x70, 0x75, 0x94, 0x93, 0xa1, 0x33, 0x3f,
|
|
+ 0x2c, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 104cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x84, 0x85, 0x86,
|
|
+ 0x85, 0x85, 0x84, 0x86, 0x87, 0x85, 0x84, 0x82, 0x87, 0x81,
|
|
+ 0x80, 0x83, 0x74, 0x6a, 0x6f, 0x94, 0x92, 0xa7, 0x33, 0x3f,
|
|
+ 0x2c, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 106cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x84, 0x85, 0x86,
|
|
+ 0x85, 0x85, 0x84, 0x87, 0x89, 0x87, 0x83, 0x81, 0x85, 0x81,
|
|
+ 0x80, 0x83, 0x74, 0x6a, 0x6f, 0x95, 0x92, 0x9d, 0x33, 0x3f,
|
|
+ 0x2c, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 108cd */
|
|
+ 0xca, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xbb, 0x85, 0x86, 0x87,
|
|
+ 0x84, 0x84, 0x83, 0x87, 0x89, 0x87, 0x83, 0x81, 0x85, 0x81,
|
|
+ 0x80, 0x83, 0x74, 0x6a, 0x6f, 0x95, 0x91, 0x9d, 0x33, 0x3f,
|
|
+ 0x2c, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 110cd */
|
|
+ 0xca, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd3, 0x82, 0x84, 0x85,
|
|
+ 0x82, 0x82, 0x81, 0x84, 0x85, 0x84, 0x82, 0x80, 0x83, 0x81,
|
|
+ 0x82, 0x83, 0x7b, 0x75, 0x78, 0x85, 0x80, 0x8e, 0x2f, 0x39,
|
|
+ 0x29, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 120cd */
|
|
+ 0xca, 0x00, 0xdf, 0x00, 0xdb, 0x00, 0xda, 0x82, 0x83, 0x84,
|
|
+ 0x81, 0x81, 0x80, 0x83, 0x83, 0x82, 0x82, 0x81, 0x83, 0x80,
|
|
+ 0x80, 0x82, 0x7e, 0x7a, 0x7b, 0x86, 0x83, 0x8d, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 130cd */
|
|
+ 0xca, 0x00, 0xe4, 0x00, 0xe0, 0x00, 0xe0, 0x82, 0x83, 0x84,
|
|
+ 0x81, 0x80, 0x7f, 0x82, 0x82, 0x81, 0x83, 0x82, 0x84, 0x7e,
|
|
+ 0x7f, 0x80, 0x7b, 0x76, 0x79, 0x86, 0x83, 0x8d, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 140cd */
|
|
+ 0xca, 0x00, 0xe8, 0x00, 0xe5, 0x00, 0xe5, 0x81, 0x82, 0x82,
|
|
+ 0x80, 0x80, 0x7f, 0x82, 0x82, 0x82, 0x81, 0x80, 0x82, 0x7f,
|
|
+ 0x7f, 0x81, 0x7e, 0x7a, 0x7c, 0x81, 0x7d, 0x88, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 150cd */
|
|
+ 0xca, 0x00, 0xec, 0x00, 0xea, 0x00, 0xe9, 0x81, 0x82, 0x82,
|
|
+ 0x80, 0x80, 0x7f, 0x81, 0x82, 0x81, 0x81, 0x80, 0x81, 0x80,
|
|
+ 0x80, 0x81, 0x7a, 0x77, 0x79, 0x87, 0x86, 0x8d, 0x84, 0x86,
|
|
+ 0x83, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 160cd */
|
|
+ 0xca, 0x00, 0xf1, 0x00, 0xef, 0x00, 0xef, 0x80, 0x80, 0x81,
|
|
+ 0x80, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x82, 0x81, 0x82, 0x7f,
|
|
+ 0x7f, 0x7f, 0x7d, 0x7b, 0x7c, 0x82, 0x80, 0x88, 0x84, 0x86,
|
|
+ 0x83, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 170cd */
|
|
+ 0xca, 0x00, 0xf5, 0x00, 0xf3, 0x00, 0xf3, 0x80, 0x80, 0x81,
|
|
+ 0x7f, 0x7f, 0x7f, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80,
|
|
+ 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7d, 0x7b, 0x83, 0x84, 0x86,
|
|
+ 0x83, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 180cd */
|
|
+ 0xca, 0x00, 0xf9, 0x00, 0xf8, 0x00, 0xf8, 0x80, 0x80, 0x80,
|
|
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x81, 0x81,
|
|
+ 0x81, 0x81, 0x7d, 0x7c, 0x7d, 0x83, 0x83, 0x87, 0x7f, 0x7f,
|
|
+ 0x7f, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 182cd */
|
|
+ 0xca, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0xf0, 0x80, 0x81, 0x81,
|
|
+ 0x80, 0x7f, 0x7f, 0x81, 0x81, 0x81, 0x81, 0x80, 0x81, 0x7f,
|
|
+ 0x7f, 0x7f, 0x7d, 0x7b, 0x7c, 0x83, 0x81, 0x87, 0x84, 0x86,
|
|
+ 0x83, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 184cd */
|
|
+ 0xca, 0x00, 0xec, 0x00, 0xea, 0x00, 0xe9, 0x81, 0x82, 0x82,
|
|
+ 0x7f, 0x7f, 0x7f, 0x81, 0x81, 0x81, 0x82, 0x81, 0x83, 0x7d,
|
|
+ 0x7d, 0x7f, 0x7e, 0x7a, 0x7c, 0x82, 0x7f, 0x86, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 186cd */
|
|
+ 0xca, 0x00, 0xe8, 0x00, 0xe4, 0x00, 0xe4, 0x81, 0x82, 0x83,
|
|
+ 0x80, 0x80, 0x7f, 0x82, 0x82, 0x81, 0x80, 0x80, 0x81, 0x7e,
|
|
+ 0x7f, 0x80, 0x7b, 0x76, 0x79, 0x87, 0x85, 0x8a, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 188cd */
|
|
+ 0xca, 0x00, 0xe4, 0x00, 0xe0, 0x00, 0xe0, 0x81, 0x82, 0x83,
|
|
+ 0x80, 0x80, 0x7f, 0x81, 0x82, 0x81, 0x80, 0x7f, 0x82, 0x80,
|
|
+ 0x80, 0x82, 0x78, 0x72, 0x75, 0x8c, 0x8b, 0x90, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 190cd */
|
|
+ 0xca, 0x00, 0xde, 0x00, 0xda, 0x00, 0xda, 0x81, 0x82, 0x83,
|
|
+ 0x81, 0x81, 0x80, 0x83, 0x84, 0x82, 0x81, 0x80, 0x83, 0x7f,
|
|
+ 0x7f, 0x81, 0x7b, 0x75, 0x78, 0x86, 0x82, 0x8b, 0x2f, 0x39,
|
|
+ 0x29, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 200cd */
|
|
+ 0xca, 0x00, 0xe3, 0x00, 0xdf, 0x00, 0xdf, 0x81, 0x82, 0x83,
|
|
+ 0x80, 0x80, 0x7f, 0x81, 0x82, 0x81, 0x82, 0x81, 0x83, 0x80,
|
|
+ 0x80, 0x82, 0x78, 0x72, 0x75, 0x86, 0x82, 0x8b, 0x2f, 0x39,
|
|
+ 0x29, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 210cd */
|
|
+ 0xca, 0x00, 0xe6, 0x00, 0xe3, 0x00, 0xe3, 0x81, 0x82, 0x82,
|
|
+ 0x80, 0x7f, 0x7f, 0x81, 0x81, 0x81, 0x81, 0x80, 0x82, 0x7d,
|
|
+ 0x7e, 0x7f, 0x7e, 0x7a, 0x7b, 0x87, 0x85, 0x8a, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 220cd */
|
|
+ 0xca, 0x00, 0xea, 0x00, 0xe7, 0x00, 0xe6, 0x80, 0x80, 0x81,
|
|
+ 0x80, 0x80, 0x7f, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x7e,
|
|
+ 0x7f, 0x80, 0x7b, 0x76, 0x79, 0x87, 0x85, 0x8a, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 230cd */
|
|
+ 0xca, 0x00, 0xec, 0x00, 0xea, 0x00, 0xe9, 0x80, 0x81, 0x82,
|
|
+ 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x7f,
|
|
+ 0x7f, 0x81, 0x78, 0x73, 0x76, 0x87, 0x85, 0x8a, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 240cd */
|
|
+ 0xca, 0x00, 0xef, 0x00, 0xed, 0x00, 0xed, 0x80, 0x80, 0x81,
|
|
+ 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x7e, 0x7e, 0x7f, 0x7f,
|
|
+ 0x7f, 0x81, 0x7e, 0x7a, 0x7c, 0x82, 0x7f, 0x85, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 250cd */
|
|
+ 0xca, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0xf0, 0x80, 0x80, 0x81,
|
|
+ 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80,
|
|
+ 0x80, 0x81, 0x7a, 0x77, 0x79, 0x82, 0x7f, 0x85, 0x2b, 0x34,
|
|
+ 0x27, 0x02, 0x03, 0x02
|
|
+ }, {
|
|
+ /* 300cd */
|
|
+ 0xca, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x80, 0x7f, 0x7f,
|
|
+ 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f,
|
|
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f,
|
|
+ 0x7f, 0x02, 0x03, 0x02
|
|
+ },
|
|
+};
|
|
+
|
|
+static inline struct s6evr02 *panel_to_s6evr02(struct drm_panel *panel)
|
|
+{
|
|
+ return container_of(panel, struct s6evr02, panel);
|
|
+}
|
|
+
|
|
+static int s6evr02_clear_error(struct s6evr02 *ctx)
|
|
+{
|
|
+ int ret = ctx->error;
|
|
+
|
|
+ ctx->error = 0;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void s6evr02_dcs_write(struct s6evr02 *ctx, const void *data, size_t len)
|
|
+{
|
|
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
+ ssize_t ret;
|
|
+
|
|
+ if (ctx->error < 0)
|
|
+ return;
|
|
+
|
|
+ ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
|
|
+ if (ret < 0) {
|
|
+ dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret,
|
|
+ (int)len, data);
|
|
+ ctx->error = ret;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int s6evr02_read(struct s6evr02 *ctx, u8 cmd, void *data, size_t len)
|
|
+{
|
|
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
+ int ret;
|
|
+
|
|
+ if (ctx->error < 0)
|
|
+ return ctx->error;
|
|
+
|
|
+ ret = mipi_dsi_generic_read(dsi, &cmd, 1, data, len);
|
|
+ if (ret < 0) {
|
|
+ dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd);
|
|
+ ctx->error = ret;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+#define s6evr02_dcs_write_seq_static(ctx, seq...) \
|
|
+({\
|
|
+ static const u8 d[] = { seq };\
|
|
+ s6evr02_dcs_write(ctx, d, ARRAY_SIZE(d));\
|
|
+})
|
|
+
|
|
+static void s6evr02_apply_level_2_key(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
|
|
+}
|
|
+
|
|
+static void s6evr02_etc_elvss_control(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_dcs_write_seq_static(ctx, 0xb6, 0x08, 0x07);
|
|
+}
|
|
+
|
|
+static void s6evr02_aid_set(struct s6evr02 *ctx)
|
|
+{
|
|
+ u8 aid_cmd[] = {
|
|
+ 0x51, 0xff, 0x00,
|
|
+ };
|
|
+
|
|
+ const u8 aid_arg[GAMMA_LEVEL_NUM] = {
|
|
+ 0x28, 0x3c, 0x51, 0x66, 0x7d, 0x93, 0xab, 0xc2, /* 20-90cd */
|
|
+ 0xda, 0xcd, 0xc0, 0xb3, 0xa6, 0x99, 0x99, 0x99, /* 100-130cd */
|
|
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0xad, 0xc2, 0xd6, /* 140-186cd */
|
|
+ 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 188-250cd */
|
|
+ 0xff, /* 300cd */
|
|
+ };
|
|
+
|
|
+ if (ctx->error)
|
|
+ return;
|
|
+
|
|
+ aid_cmd[2] = aid_arg[ctx->brightness];
|
|
+
|
|
+ s6evr02_dcs_write(ctx, aid_cmd, ARRAY_SIZE(aid_cmd));
|
|
+}
|
|
+
|
|
+static void s6evr02_acl_set(struct s6evr02 *ctx)
|
|
+{
|
|
+ u8 acl_seq[] = {0x55, 0x02, 0x00};
|
|
+ if (ctx->error)
|
|
+ return;
|
|
+
|
|
+ switch (ctx->brightness) {
|
|
+ case 0:
|
|
+ acl_seq[1] = 0x00;
|
|
+ break;
|
|
+ case 1:
|
|
+ acl_seq[1] = 0x01;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ s6evr02_dcs_write(ctx, acl_seq, ARRAY_SIZE(acl_seq));
|
|
+}
|
|
+
|
|
+static void s6evr02_elvss_set(struct s6evr02 *ctx)
|
|
+{
|
|
+ u8 elvss_cmd[] = {
|
|
+ 0xb6, 0x08, 0x00,
|
|
+ };
|
|
+
|
|
+ const u8 elvss_arg[GAMMA_LEVEL_NUM] = {
|
|
+ 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1e, 0x1c, /* 20-100cd */
|
|
+ 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x19, 0x17, 0x16, /* 102-140cd */
|
|
+ 0x14, 0x12, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, /* 150-188cd */
|
|
+ 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x10, 0x0b, /* 190-300cd */
|
|
+ };
|
|
+
|
|
+ if (ctx->error)
|
|
+ return;
|
|
+
|
|
+ elvss_cmd[2] = elvss_arg[ctx->brightness];
|
|
+
|
|
+ s6evr02_dcs_write(ctx, elvss_cmd, ARRAY_SIZE(elvss_cmd));
|
|
+}
|
|
+
|
|
+
|
|
+static void s6evr02_brightness_set(struct s6evr02 *ctx)
|
|
+{
|
|
+ const u8 *gamma;
|
|
+
|
|
+ if (ctx->error)
|
|
+ return;
|
|
+
|
|
+ gamma = s6evr02_gamma_tables[ctx->brightness];
|
|
+
|
|
+ s6evr02_dcs_write(ctx, gamma, GAMMA_TABLE_LEN);
|
|
+
|
|
+ /* apply gamma table update. */
|
|
+ s6evr02_dcs_write_seq_static(ctx, 0xf7, 0x03, 0x00);
|
|
+
|
|
+ s6evr02_aid_set(ctx);
|
|
+ s6evr02_acl_set(ctx);
|
|
+ s6evr02_elvss_set(ctx);
|
|
+}
|
|
+
|
|
+static void s6evr02_gamma_cond_set(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_dcs_write_seq_static(ctx,
|
|
+ 0xca, 0x01, 0x27, 0x01, 0x3d, 0x01, 0x47, 0xd1, 0xd7, 0xd1,
|
|
+ 0xca, 0xce, 0xcc, 0xc4, 0xb3, 0xb1, 0xa1, 0xb9, 0xb8, 0xa2,
|
|
+ 0xce, 0xba, 0xc8, 0xc9, 0xad, 0x9b, 0x85, 0x53, 0x6a, 0x7e,
|
|
+ 0xe3, 0x09, 0x09, 0x0b);
|
|
+}
|
|
+
|
|
+static void s6evr02_gamma_update(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_dcs_write_seq_static(ctx, 0xf7, 0x03, 0x00);
|
|
+}
|
|
+
|
|
+static void s6evr02_brightness_control_on(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_dcs_write_seq_static(ctx, 0x53, 0x20, 0x00);
|
|
+}
|
|
+
|
|
+static void s6evr02_aor_control(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_dcs_write_seq_static(ctx, 0x51, 0xff, 0x00);
|
|
+}
|
|
+
|
|
+static void s6evr02_acl_off(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_dcs_write_seq_static(ctx, 0x55, 0x00, 0x00);
|
|
+}
|
|
+
|
|
+static void s6evr02_panel_init(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_apply_level_2_key(ctx);
|
|
+ s6evr02_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
|
|
+ msleep(20);
|
|
+
|
|
+ if (ctx->version == UB_VERSION) {
|
|
+ s6evr02_gamma_cond_set(ctx);
|
|
+ s6evr02_gamma_update(ctx);
|
|
+ }
|
|
+
|
|
+ s6evr02_brightness_control_on(ctx);
|
|
+ s6evr02_aor_control(ctx);
|
|
+ s6evr02_etc_elvss_control(ctx);
|
|
+ s6evr02_acl_off(ctx);
|
|
+}
|
|
+
|
|
+static void s6evr02_set_maximum_return_packet_size(struct s6evr02 *ctx,
|
|
+ u16 size)
|
|
+{
|
|
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
|
+ int ret;
|
|
+
|
|
+ if (ctx->error < 0)
|
|
+ return;
|
|
+
|
|
+ ret = mipi_dsi_set_maximum_return_packet_size(dsi, size);
|
|
+ if (ret < 0) {
|
|
+ dev_err(ctx->dev,
|
|
+ "error %d setting maximum return packet size to %d\n",
|
|
+ ret, size);
|
|
+ ctx->error = ret;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void s6evr02_read_mtp_id(struct s6evr02 *ctx)
|
|
+{
|
|
+ u8 id[3] = {0, 0, 0};
|
|
+ int ret;
|
|
+
|
|
+ /* the panel seems not to respond properly
|
|
+ * to read commands until we write something to it
|
|
+ */
|
|
+ s6evr02_apply_level_2_key(ctx);
|
|
+
|
|
+ ret = s6evr02_read(ctx, 0xd7, id, ARRAY_SIZE(id));
|
|
+ if (ret < 0 || ret < ARRAY_SIZE(id) || id[0] == 0x00) {
|
|
+ dev_err(ctx->dev, "failed to read ID from panel\n");
|
|
+ ctx->error = -EIO;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ dev_info(ctx->dev, "ID: 0x%2x, 0x%2x, 0x%2x\n", id[0], id[1], id[2]);
|
|
+
|
|
+ ctx->version = id[1];
|
|
+ ctx->id = id[2];
|
|
+}
|
|
+
|
|
+static void s6evr02_set_sequence(struct s6evr02 *ctx)
|
|
+{
|
|
+ s6evr02_set_maximum_return_packet_size(ctx, 3);
|
|
+ s6evr02_read_mtp_id(ctx);
|
|
+ s6evr02_panel_init(ctx);
|
|
+ s6evr02_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
|
|
+}
|
|
+
|
|
+static int s6evr02_power_on(struct s6evr02 *ctx)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ msleep(ctx->power_on_delay);
|
|
+
|
|
+ gpiod_set_value(ctx->reset_gpio, 0);
|
|
+ usleep_range(5000, 6000);
|
|
+ gpiod_set_value(ctx->reset_gpio, 1);
|
|
+ usleep_range(5000, 6000);
|
|
+
|
|
+ msleep(ctx->reset_delay);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int s6evr02_power_off(struct s6evr02 *ctx)
|
|
+{
|
|
+ return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
|
|
+}
|
|
+
|
|
+static int s6evr02_disable(struct drm_panel *panel)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int s6evr02_unprepare(struct drm_panel *panel)
|
|
+{
|
|
+ struct s6evr02 *ctx = panel_to_s6evr02(panel);
|
|
+
|
|
+ clear_bit(S6EVR02_STATE_BIT_ENABLED, &ctx->state);
|
|
+ s6evr02_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
|
|
+ s6evr02_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
|
|
+ msleep(40);
|
|
+
|
|
+ s6evr02_clear_error(ctx);
|
|
+
|
|
+ return s6evr02_power_off(ctx);
|
|
+}
|
|
+
|
|
+static int s6evr02_prepare(struct drm_panel *panel)
|
|
+{
|
|
+ struct s6evr02 *ctx = panel_to_s6evr02(panel);
|
|
+ int ret;
|
|
+
|
|
+ ret = s6evr02_power_on(ctx);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ s6evr02_set_sequence(ctx);
|
|
+ ret = ctx->error;
|
|
+
|
|
+ if (ret < 0)
|
|
+ s6evr02_unprepare(panel);
|
|
+ else
|
|
+ set_bit(S6EVR02_STATE_BIT_ENABLED, &ctx->state);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int s6evr02_enable(struct drm_panel *panel)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int s6evr02_get_modes(struct drm_panel *panel,
|
|
+ struct drm_connector *connector)
|
|
+{
|
|
+ struct s6evr02 *ctx = panel_to_s6evr02(panel);
|
|
+ struct drm_display_mode *mode;
|
|
+
|
|
+ mode = drm_mode_create(connector->dev);
|
|
+ if (!mode) {
|
|
+ dev_err(panel->dev, "failed to create a new display mode\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ drm_display_mode_from_videomode(&ctx->vm, mode);
|
|
+ mode->width_mm = ctx->width_mm;
|
|
+ mode->height_mm = ctx->height_mm;
|
|
+ connector->display_info.width_mm = mode->width_mm;
|
|
+ connector->display_info.height_mm = mode->height_mm;
|
|
+
|
|
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
|
+ drm_mode_probed_add(connector, mode);
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static const struct drm_panel_funcs s6evr02_drm_funcs = {
|
|
+ .disable = s6evr02_disable,
|
|
+ .unprepare = s6evr02_unprepare,
|
|
+ .prepare = s6evr02_prepare,
|
|
+ .enable = s6evr02_enable,
|
|
+ .get_modes = s6evr02_get_modes,
|
|
+};
|
|
+
|
|
+static int s6evr02_get_brightness(struct backlight_device *bd)
|
|
+{
|
|
+ return bd->props.brightness;
|
|
+}
|
|
+
|
|
+static int s6evr02_set_brightness(struct backlight_device *bd)
|
|
+{
|
|
+ struct s6evr02 *ctx = bl_get_data(bd);
|
|
+
|
|
+ bd->props.power = FB_BLANK_UNBLANK;
|
|
+ if (ctx->brightness != bd->props.brightness) {
|
|
+ ctx->brightness = bd->props.brightness;
|
|
+ if (test_bit(S6EVR02_STATE_BIT_ENABLED, &ctx->state))
|
|
+ s6evr02_brightness_set(ctx);
|
|
+ }
|
|
+
|
|
+ return s6evr02_clear_error(ctx);
|
|
+}
|
|
+
|
|
+static const struct backlight_ops s6evr02_backlight_ops = {
|
|
+ .get_brightness = s6evr02_get_brightness,
|
|
+ .update_status = s6evr02_set_brightness,
|
|
+};
|
|
+
|
|
+static void s6evr02_backlight_register(struct s6evr02 *ctx)
|
|
+{
|
|
+ struct backlight_properties props = {
|
|
+ .type = BACKLIGHT_RAW,
|
|
+ .brightness = ctx->brightness,
|
|
+ .max_brightness = GAMMA_LEVEL_NUM - 1
|
|
+ };
|
|
+ struct device *dev = ctx->dev;
|
|
+ struct backlight_device *bd;
|
|
+
|
|
+ bd = devm_backlight_device_register(dev, "panel", dev, ctx,
|
|
+ &s6evr02_backlight_ops, &props);
|
|
+ if (IS_ERR(bd))
|
|
+ dev_err(dev, "error registering backlight device (%ld)\n",
|
|
+ PTR_ERR(bd));
|
|
+}
|
|
+
|
|
+static int s6evr02_parse_dt(struct s6evr02 *ctx)
|
|
+{
|
|
+ struct device *dev = ctx->dev;
|
|
+ struct device_node *np = dev->of_node;
|
|
+ int ret;
|
|
+
|
|
+ ret = of_get_videomode(np, &ctx->vm, 0);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
|
|
+ of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
|
|
+ of_property_read_u32(np, "init-delay", &ctx->init_delay);
|
|
+ of_property_read_u32(np, "panel-width-mm", &ctx->width_mm);
|
|
+ of_property_read_u32(np, "panel-height-mm", &ctx->height_mm);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int s6evr02_probe(struct mipi_dsi_device *dsi)
|
|
+{
|
|
+ struct device *dev = &dsi->dev;
|
|
+ struct s6evr02 *ctx;
|
|
+ int ret = 0;
|
|
+
|
|
+ ctx = devm_kzalloc(dev, sizeof(struct s6evr02), GFP_KERNEL);
|
|
+ if (!ctx)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ pr_err("s6evr02 probing\n");
|
|
+
|
|
+ mipi_dsi_set_drvdata(dsi, ctx);
|
|
+
|
|
+ ctx->dev = dev;
|
|
+
|
|
+ dsi->lanes = 4;
|
|
+ dsi->format = MIPI_DSI_FMT_RGB888;
|
|
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
|
|
+ | MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP
|
|
+ | MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_NO_EOT_PACKET
|
|
+ | MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT;
|
|
+
|
|
+ ret = s6evr02_parse_dt(ctx);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ctx->supplies[0].supply = "vdd3";
|
|
+ ctx->supplies[1].supply = "vci";
|
|
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
|
|
+ ctx->supplies);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to get regulators: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
|
+ if (IS_ERR(ctx->reset_gpio)) {
|
|
+ dev_err(dev, "cannot get reset-gpios %ld\n",
|
|
+ PTR_ERR(ctx->reset_gpio));
|
|
+ return PTR_ERR(ctx->reset_gpio);
|
|
+ }
|
|
+
|
|
+ ctx->brightness = GAMMA_LEVEL_NUM - 1;
|
|
+
|
|
+ drm_panel_init(&ctx->panel, dev, &s6evr02_drm_funcs, DRM_MODE_CONNECTOR_DSI);
|
|
+
|
|
+ drm_panel_add(&ctx->panel);
|
|
+
|
|
+ ret = mipi_dsi_attach(dsi);
|
|
+ if (ret < 0)
|
|
+ drm_panel_remove(&ctx->panel);
|
|
+
|
|
+ s6evr02_backlight_register(ctx);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int s6evr02_remove(struct mipi_dsi_device *dsi)
|
|
+{
|
|
+ struct s6evr02 *ctx = mipi_dsi_get_drvdata(dsi);
|
|
+
|
|
+ mipi_dsi_detach(dsi);
|
|
+ drm_panel_remove(&ctx->panel);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id s6evr02_of_match[] = {
|
|
+ { .compatible = "samsung,s6evr02" },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, s6evr02_of_match);
|
|
+
|
|
+static struct mipi_dsi_driver s6evr02_driver = {
|
|
+ .probe = s6evr02_probe,
|
|
+ .remove = s6evr02_remove,
|
|
+ .driver = {
|
|
+ .name = "panel-samsung-s6evr02",
|
|
+ .of_match_table = s6evr02_of_match,
|
|
+ },
|
|
+};
|
|
+module_mipi_dsi_driver(s6evr02_driver);
|
|
+
|
|
+MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
|
|
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
|
|
+MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
|
+MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
|
|
+MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
|
|
+MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
|
|
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
|
|
+MODULE_DESCRIPTION("MIPI-DSI based s6evr02 AMOLED LCD Panel Driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
+
|
|
--
|
|
2.38.0
|
|
|