aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.txt26
-rw-r--r--Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt28
-rw-r--r--Documentation/devicetree/bindings/display/panel/sitronix,st7789v.txt37
-rw-r--r--Documentation/devicetree/bindings/display/panel/winstar,wf35ltiacd.txt48
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--drivers/gpu/drm/panel/Kconfig13
-rw-r--r--drivers/gpu/drm/panel/Makefile2
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c739
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c56
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7789v.c449
10 files changed, 1399 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.txt b/Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.txt
new file mode 100644
index 000000000000..6812280cb109
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.txt
@@ -0,0 +1,26 @@
1Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
2
3This binding is compatible with the simple-panel binding, which is specified
4in simple-panel.txt in this directory.
5
6Required properties:
7- compatible: should be "ampire,am-480272h3tmqw-t01h"
8
9Optional properties:
10- power-supply: regulator to provide the supply voltage
11- enable-gpios: GPIO pin to enable or disable the panel
12- backlight: phandle of the backlight device attached to the panel
13
14Optional nodes:
15- Video port for RGB input.
16
17Example:
18 panel_rgb: panel-rgb {
19 compatible = "ampire,am-480272h3tmqw-t01h";
20 enable-gpios = <&gpioa 8 1>;
21 port {
22 panel_in_rgb: endpoint {
23 remote-endpoint = <&controller_out_rgb>;
24 };
25 };
26 };
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
new file mode 100644
index 000000000000..18854f4c8376
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
@@ -0,0 +1,28 @@
1Samsung S6E3HA2 5.7" 1440x2560 AMOLED panel
2
3Required properties:
4 - compatible: "samsung,s6e3ha2"
5 - reg: the virtual channel number of a DSI peripheral
6 - vdd3-supply: I/O voltage supply
7 - vci-supply: voltage supply for analog circuits
8 - reset-gpios: a GPIO spec for the reset pin (active low)
9 - enable-gpios: a GPIO spec for the panel enable pin (active high)
10
11Optional properties:
12 - te-gpios: a GPIO spec for the tearing effect synchronization signal
13 gpio pin (active high)
14
15Example:
16&dsi {
17 ...
18
19 panel@0 {
20 compatible = "samsung,s6e3ha2";
21 reg = <0>;
22 vdd3-supply = <&ldo27_reg>;
23 vci-supply = <&ldo28_reg>;
24 reset-gpios = <&gpg0 0 GPIO_ACTIVE_LOW>;
25 enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>;
26 te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>;
27 };
28};
diff --git a/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.txt b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.txt
new file mode 100644
index 000000000000..c6995dde641b
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.txt
@@ -0,0 +1,37 @@
1Sitronix ST7789V RGB panel with SPI control bus
2
3Required properties:
4 - compatible: "sitronix,st7789v"
5 - reg: Chip select of the panel on the SPI bus
6 - reset-gpios: a GPIO phandle for the reset pin
7 - power-supply: phandle of the regulator that provides the supply voltage
8
9Optional properties:
10 - backlight: phandle to the backlight used
11
12The generic bindings for the SPI slaves documented in [1] also applies
13
14The device node can contain one 'port' child node with one child
15'endpoint' node, according to the bindings defined in [2]. This
16node should describe panel's video bus.
17
18[1]: Documentation/devicetree/bindings/spi/spi-bus.txt
19[2]: Documentation/devicetree/bindings/graph.txt
20
21Example:
22
23panel@0 {
24 compatible = "sitronix,st7789v";
25 reg = <0>;
26 reset-gpios = <&pio 6 11 GPIO_ACTIVE_LOW>;
27 backlight = <&pwm_bl>;
28 spi-max-frequency = <100000>;
29 spi-cpol;
30 spi-cpha;
31
32 port {
33 panel_input: endpoint {
34 remote-endpoint = <&tcon0_out_panel>;
35 };
36 };
37};
diff --git a/Documentation/devicetree/bindings/display/panel/winstar,wf35ltiacd.txt b/Documentation/devicetree/bindings/display/panel/winstar,wf35ltiacd.txt
new file mode 100644
index 000000000000..2a7e6e3ba64c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/winstar,wf35ltiacd.txt
@@ -0,0 +1,48 @@
1Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel
2
3Required properties:
4- compatible: should be "winstar,wf35ltiacd"
5- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
6
7This binding is compatible with the simple-panel binding, which is specified
8in simple-panel.txt in this directory.
9
10Example:
11 backlight: backlight {
12 compatible = "pwm-backlight";
13 pwms = <&hlcdc_pwm 0 50000 PWM_POLARITY_INVERTED>;
14 brightness-levels = <0 31 63 95 127 159 191 223 255>;
15 default-brightness-level = <191>;
16 power-supply = <&bl_reg>;
17 };
18
19 bl_reg: backlight_regulator {
20 compatible = "regulator-fixed";
21 regulator-name = "backlight-power-supply";
22 regulator-min-microvolt = <5000000>;
23 regulator-max-microvolt = <5000000>;
24 };
25
26 panel: panel {
27 compatible = "winstar,wf35ltiacd", "simple-panel";
28 backlight = <&backlight>;
29 power-supply = <&panel_reg>;
30 #address-cells = <1>;
31 #size-cells = <0>;
32
33 port {
34 #address-cells = <1>;
35 #size-cells = <0>;
36
37 panel_input: endpoint {
38 remote-endpoint = <&hlcdc_panel_output>;
39 };
40 };
41 };
42
43 panel_reg: panel_regulator {
44 compatible = "regulator-fixed";
45 regulator-name = "panel-power-supply";
46 regulator-min-microvolt = <3300000>;
47 regulator-max-microvolt = <3300000>;
48 };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 4686f4bdaca0..aed180d8e585 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -336,6 +336,7 @@ wd Western Digital Corp.
336wetek WeTek Electronics, limited. 336wetek WeTek Electronics, limited.
337wexler Wexler 337wexler Wexler
338winbond Winbond Electronics corp. 338winbond Winbond Electronics corp.
339winstar Winstar Display Corp.
339wlf Wolfson Microelectronics 340wlf Wolfson Microelectronics
340wm Wondermedia Technologies, Inc. 341wm Wondermedia Technologies, Inc.
341x-powers X-Powers 342x-powers X-Powers
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 5dc2106da2bc..3e29a9903303 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -62,6 +62,12 @@ config DRM_PANEL_PANASONIC_VVX10F034N00
62 WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some 62 WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some
63 Xperia Z2 tablets 63 Xperia Z2 tablets
64 64
65config DRM_PANEL_SAMSUNG_S6E3HA2
66 tristate "Samsung S6E3HA2 DSI video mode panel"
67 depends on OF
68 depends on DRM_MIPI_DSI
69 select VIDEOMODE_HELPERS
70
65config DRM_PANEL_SAMSUNG_S6E8AA0 71config DRM_PANEL_SAMSUNG_S6E8AA0
66 tristate "Samsung S6E8AA0 DSI video mode panel" 72 tristate "Samsung S6E8AA0 DSI video mode panel"
67 depends on OF 73 depends on OF
@@ -91,4 +97,11 @@ config DRM_PANEL_SHARP_LS043T1LE01
91 Say Y here if you want to enable support for Sharp LS043T1LE01 qHD 97 Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
92 (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard 98 (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard
93 99
100config DRM_PANEL_SITRONIX_ST7789V
101 tristate "Sitronix ST7789V panel"
102 depends on OF && SPI
103 help
104 Say Y here if you want to enable support for the Sitronix
105 ST7789V controller for 240x320 LCD panels
106
94endmenu 107endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 20b5060d1f47..292b3c77aede 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -4,6 +4,8 @@ obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
4obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o 4obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
5obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o 5obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
6obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o 6obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
7obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
7obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o 8obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
8obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o 9obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
9obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o 10obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
11obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
new file mode 100644
index 000000000000..4cc08d7b3de4
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
@@ -0,0 +1,739 @@
1/*
2 * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
3 *
4 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
5 * Donghwa Lee <dh09.lee@samsung.com>
6 * Hyungwon Hwang <human.hwang@samsung.com>
7 * Hoegeun Kwon <hoegeun.kwon@samsung.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <drm/drmP.h>
15#include <drm/drm_mipi_dsi.h>
16#include <drm/drm_panel.h>
17#include <linux/backlight.h>
18#include <linux/gpio/consumer.h>
19#include <linux/regulator/consumer.h>
20
21#define S6E3HA2_MIN_BRIGHTNESS 0
22#define S6E3HA2_MAX_BRIGHTNESS 100
23#define S6E3HA2_DEFAULT_BRIGHTNESS 80
24
25#define S6E3HA2_NUM_GAMMA_STEPS 46
26#define S6E3HA2_GAMMA_CMD_CNT 35
27#define S6E3HA2_VINT_STATUS_MAX 10
28
29static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = {
30 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x82, 0x83,
31 0x85, 0x88, 0x8b, 0x8b, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8c,
32 0x94, 0x84, 0xb1, 0xaf, 0x8e, 0xcf, 0xad, 0xc9, 0x00, 0x00, 0x00,
33 0x00, 0x00 },
34 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x84, 0x84,
35 0x85, 0x87, 0x8b, 0x8a, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8a,
36 0x93, 0x84, 0xb0, 0xae, 0x8e, 0xc9, 0xa8, 0xc5, 0x00, 0x00, 0x00,
37 0x00, 0x00 },
38 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
39 0x85, 0x86, 0x8a, 0x8a, 0x84, 0x88, 0x81, 0x84, 0x8a, 0x88, 0x8a,
40 0x91, 0x84, 0xb1, 0xae, 0x8b, 0xd5, 0xb2, 0xcc, 0x00, 0x00, 0x00,
41 0x00, 0x00 },
42 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
43 0x85, 0x86, 0x8a, 0x8a, 0x84, 0x87, 0x81, 0x84, 0x8a, 0x87, 0x8a,
44 0x91, 0x85, 0xae, 0xac, 0x8a, 0xc3, 0xa3, 0xc0, 0x00, 0x00, 0x00,
45 0x00, 0x00 },
46 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x85, 0x85,
47 0x86, 0x85, 0x88, 0x89, 0x84, 0x89, 0x82, 0x84, 0x87, 0x85, 0x8b,
48 0x91, 0x88, 0xad, 0xab, 0x8a, 0xb7, 0x9b, 0xb6, 0x00, 0x00, 0x00,
49 0x00, 0x00 },
50 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
51 0x85, 0x86, 0x89, 0x8a, 0x84, 0x89, 0x83, 0x83, 0x86, 0x84, 0x8b,
52 0x90, 0x84, 0xb0, 0xae, 0x8b, 0xce, 0xad, 0xc8, 0x00, 0x00, 0x00,
53 0x00, 0x00 },
54 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
55 0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x89,
56 0x8f, 0x84, 0xac, 0xaa, 0x89, 0xb1, 0x98, 0xaf, 0x00, 0x00, 0x00,
57 0x00, 0x00 },
58 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
59 0x85, 0x86, 0x88, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8c,
60 0x91, 0x86, 0xac, 0xaa, 0x89, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
61 0x00, 0x00 },
62 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
63 0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x88,
64 0x8b, 0x82, 0xad, 0xaa, 0x8a, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
65 0x00, 0x00 },
66 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
67 0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8a,
68 0x8e, 0x84, 0xae, 0xac, 0x89, 0xda, 0xb7, 0xd0, 0x00, 0x00, 0x00,
69 0x00, 0x00 },
70 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
71 0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x80, 0x83, 0x82, 0x8b,
72 0x8e, 0x85, 0xac, 0xaa, 0x89, 0xc8, 0xaa, 0xc1, 0x00, 0x00, 0x00,
73 0x00, 0x00 },
74 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
75 0x85, 0x86, 0x87, 0x89, 0x81, 0x85, 0x81, 0x84, 0x86, 0x84, 0x8c,
76 0x8c, 0x84, 0xa9, 0xa8, 0x87, 0xa3, 0x92, 0xa1, 0x00, 0x00, 0x00,
77 0x00, 0x00 },
78 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
79 0x85, 0x86, 0x87, 0x89, 0x84, 0x86, 0x83, 0x80, 0x83, 0x81, 0x8c,
80 0x8d, 0x84, 0xaa, 0xaa, 0x89, 0xce, 0xaf, 0xc5, 0x00, 0x00, 0x00,
81 0x00, 0x00 },
82 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
83 0x85, 0x86, 0x87, 0x89, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
84 0x8c, 0x84, 0xa8, 0xa8, 0x88, 0xb5, 0x9f, 0xb0, 0x00, 0x00, 0x00,
85 0x00, 0x00 },
86 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
87 0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
88 0x8b, 0x84, 0xab, 0xa8, 0x86, 0xd4, 0xb4, 0xc9, 0x00, 0x00, 0x00,
89 0x00, 0x00 },
90 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
91 0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x84, 0x84, 0x85, 0x8b,
92 0x8a, 0x83, 0xa6, 0xa5, 0x84, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
93 0x00, 0x00 },
94 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
95 0x86, 0x85, 0x86, 0x86, 0x82, 0x85, 0x81, 0x82, 0x83, 0x84, 0x8e,
96 0x8b, 0x83, 0xa4, 0xa3, 0x8a, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
97 0x00, 0x00 },
98 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
99 0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8e,
100 0x8b, 0x83, 0xa4, 0xa2, 0x86, 0xc1, 0xa9, 0xb7, 0x00, 0x00, 0x00,
101 0x00, 0x00 },
102 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
103 0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8d,
104 0x89, 0x82, 0xa2, 0xa1, 0x84, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
105 0x00, 0x00 },
106 { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
107 0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x83, 0x83, 0x85, 0x8c,
108 0x87, 0x7f, 0xa2, 0x9d, 0x88, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
109 0x00, 0x00 },
110 { 0x00, 0xbb, 0x00, 0xc5, 0x00, 0xb4, 0x87, 0x86, 0x86, 0x84, 0x83,
111 0x86, 0x87, 0x87, 0x87, 0x80, 0x82, 0x7f, 0x86, 0x86, 0x88, 0x8a,
112 0x84, 0x7e, 0x9d, 0x9c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
113 0x00, 0x00 },
114 { 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb7, 0x87, 0x85, 0x85, 0x84, 0x83,
115 0x86, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x83, 0x84, 0x85, 0x8a,
116 0x85, 0x7e, 0x9c, 0x9b, 0x85, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
117 0x00, 0x00 },
118 { 0x00, 0xc0, 0x00, 0xca, 0x00, 0xbb, 0x87, 0x86, 0x85, 0x83, 0x83,
119 0x85, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x84, 0x85, 0x86, 0x89,
120 0x83, 0x7d, 0x9c, 0x99, 0x87, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
121 0x00, 0x00 },
122 { 0x00, 0xc4, 0x00, 0xcd, 0x00, 0xbe, 0x87, 0x86, 0x85, 0x83, 0x83,
123 0x86, 0x85, 0x85, 0x87, 0x81, 0x82, 0x80, 0x82, 0x82, 0x83, 0x8a,
124 0x85, 0x7f, 0x9f, 0x9b, 0x86, 0xb4, 0xa1, 0xac, 0x00, 0x00, 0x00,
125 0x00, 0x00 },
126 { 0x00, 0xc7, 0x00, 0xd0, 0x00, 0xc2, 0x87, 0x85, 0x85, 0x83, 0x82,
127 0x85, 0x85, 0x85, 0x86, 0x82, 0x83, 0x80, 0x82, 0x82, 0x84, 0x87,
128 0x86, 0x80, 0x9e, 0x9a, 0x87, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
129 0x00, 0x00 },
130 { 0x00, 0xca, 0x00, 0xd2, 0x00, 0xc5, 0x87, 0x85, 0x84, 0x82, 0x82,
131 0x84, 0x85, 0x85, 0x86, 0x81, 0x82, 0x7f, 0x82, 0x82, 0x84, 0x88,
132 0x86, 0x81, 0x9d, 0x98, 0x86, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
133 0x00, 0x00 },
134 { 0x00, 0xce, 0x00, 0xd6, 0x00, 0xca, 0x86, 0x85, 0x84, 0x83, 0x83,
135 0x85, 0x84, 0x84, 0x85, 0x81, 0x82, 0x80, 0x81, 0x81, 0x82, 0x89,
136 0x86, 0x81, 0x9c, 0x97, 0x86, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
137 0x00, 0x00 },
138 { 0x00, 0xd1, 0x00, 0xd9, 0x00, 0xce, 0x86, 0x84, 0x83, 0x83, 0x82,
139 0x85, 0x85, 0x85, 0x86, 0x81, 0x83, 0x81, 0x82, 0x82, 0x83, 0x86,
140 0x83, 0x7f, 0x99, 0x95, 0x86, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
141 0x00, 0x00 },
142 { 0x00, 0xd4, 0x00, 0xdb, 0x00, 0xd1, 0x86, 0x85, 0x83, 0x83, 0x82,
143 0x85, 0x84, 0x84, 0x85, 0x80, 0x83, 0x82, 0x80, 0x80, 0x81, 0x87,
144 0x84, 0x81, 0x98, 0x93, 0x85, 0xae, 0x9c, 0xa8, 0x00, 0x00, 0x00,
145 0x00, 0x00 },
146 { 0x00, 0xd8, 0x00, 0xde, 0x00, 0xd6, 0x86, 0x84, 0x83, 0x81, 0x81,
147 0x83, 0x85, 0x85, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x83, 0x86,
148 0x84, 0x80, 0x98, 0x91, 0x85, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
149 0x00, 0x00 },
150 { 0x00, 0xdc, 0x00, 0xe2, 0x00, 0xda, 0x85, 0x84, 0x83, 0x82, 0x82,
151 0x84, 0x84, 0x84, 0x85, 0x81, 0x82, 0x82, 0x80, 0x80, 0x81, 0x83,
152 0x82, 0x7f, 0x99, 0x93, 0x86, 0x94, 0x8b, 0x92, 0x00, 0x00, 0x00,
153 0x00, 0x00 },
154 { 0x00, 0xdf, 0x00, 0xe5, 0x00, 0xde, 0x85, 0x84, 0x82, 0x82, 0x82,
155 0x84, 0x83, 0x83, 0x84, 0x81, 0x81, 0x80, 0x83, 0x82, 0x84, 0x82,
156 0x81, 0x7f, 0x99, 0x92, 0x86, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
157 0x00, 0x00 },
158 { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
159 0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x83, 0x83, 0x84, 0x80,
160 0x81, 0x7c, 0x99, 0x92, 0x87, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
161 0x00, 0x00 },
162 { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x85, 0x84, 0x83, 0x81, 0x81,
163 0x82, 0x82, 0x82, 0x83, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
164 0x82, 0x80, 0x91, 0x8d, 0x83, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
165 0x00, 0x00 },
166 { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
167 0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
168 0x81, 0x7f, 0x91, 0x8c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
169 0x00, 0x00 },
170 { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
171 0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x82,
172 0x82, 0x7f, 0x94, 0x89, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
173 0x00, 0x00 },
174 { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
175 0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x83,
176 0x82, 0x7f, 0x91, 0x85, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
177 0x00, 0x00 },
178 { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
179 0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x83, 0x82, 0x84, 0x83,
180 0x82, 0x7f, 0x90, 0x84, 0x81, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
181 0x00, 0x00 },
182 { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x80, 0x80,
183 0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81,
184 0x82, 0x83, 0x7e, 0x80, 0x7c, 0xa4, 0x97, 0x9f, 0x00, 0x00, 0x00,
185 0x00, 0x00 },
186 { 0x00, 0xe9, 0x00, 0xec, 0x00, 0xe8, 0x84, 0x83, 0x82, 0x81, 0x81,
187 0x82, 0x82, 0x82, 0x83, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x83,
188 0x83, 0x84, 0x79, 0x7c, 0x79, 0xb1, 0xa0, 0xaa, 0x00, 0x00, 0x00,
189 0x00, 0x00 },
190 { 0x00, 0xed, 0x00, 0xf0, 0x00, 0xec, 0x83, 0x83, 0x82, 0x80, 0x80,
191 0x81, 0x82, 0x82, 0x82, 0x7f, 0x7f, 0x7e, 0x81, 0x81, 0x82, 0x80,
192 0x81, 0x81, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
193 0x00, 0x00 },
194 { 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xf1, 0x83, 0x82, 0x82, 0x80, 0x80,
195 0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7d,
196 0x7e, 0x7f, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
197 0x00, 0x00 },
198 { 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf5, 0x82, 0x82, 0x81, 0x80, 0x80,
199 0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x82,
200 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
201 0x00, 0x00 },
202 { 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfa, 0x81, 0x81, 0x81, 0x80, 0x80,
203 0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
204 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
205 0x00, 0x00 },
206 { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
207 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
208 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
209 0x00, 0x00 },
210 { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
211 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
212 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
213 0x00, 0x00 }
214};
215
216unsigned char vint_table[S6E3HA2_VINT_STATUS_MAX] = {
217 0x18, 0x19, 0x1a, 0x1b, 0x1c,
218 0x1d, 0x1e, 0x1f, 0x20, 0x21
219};
220
221struct s6e3ha2 {
222 struct device *dev;
223 struct drm_panel panel;
224 struct backlight_device *bl_dev;
225
226 struct regulator_bulk_data supplies[2];
227 struct gpio_desc *reset_gpio;
228 struct gpio_desc *enable_gpio;
229};
230
231static int s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len)
232{
233 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
234
235 return mipi_dsi_dcs_write_buffer(dsi, data, len);
236}
237
238#define s6e3ha2_dcs_write_seq_static(ctx, seq...) do { \
239 static const u8 d[] = { seq }; \
240 int ret; \
241 ret = s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d)); \
242 if (ret < 0) \
243 return ret; \
244} while (0)
245
246#define s6e3ha2_call_write_func(ret, func) do { \
247 ret = (func); \
248 if (ret < 0) \
249 return ret; \
250} while (0)
251
252static int s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx)
253{
254 s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
255 return 0;
256}
257
258static int s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx)
259{
260 s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0xa5, 0xa5);
261 return 0;
262}
263
264static int s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx)
265{
266 s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
267 return 0;
268}
269
270static int s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx)
271{
272 s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0xa5, 0xa5);
273 return 0;
274}
275
276static int s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx)
277{
278 s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67);
279 s6e3ha2_dcs_write_seq_static(ctx, 0xf9, 0x09);
280 return 0;
281}
282
283static int s6e3ha2_freq_calibration(struct s6e3ha2 *ctx)
284{
285 s6e3ha2_dcs_write_seq_static(ctx, 0xfd, 0x1c);
286 s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20, 0x39);
287 s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0xa0);
288 s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20);
289 s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x12, 0x62, 0x40,
290 0x80, 0xc0, 0x28, 0x28, 0x28, 0x28, 0x39, 0xc5);
291 return 0;
292}
293
294static int s6e3ha2_aor_control(struct s6e3ha2 *ctx)
295{
296 s6e3ha2_dcs_write_seq_static(ctx, 0xb2, 0x03, 0x10);
297 return 0;
298}
299
300static int s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx)
301{
302 s6e3ha2_dcs_write_seq_static(ctx, 0xb6, 0x9c, 0x0a);
303 return 0;
304}
305
306static int s6e3ha2_acl_off(struct s6e3ha2 *ctx)
307{
308 s6e3ha2_dcs_write_seq_static(ctx, 0x55, 0x00);
309 return 0;
310}
311
312static int s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx)
313{
314 s6e3ha2_dcs_write_seq_static(ctx, 0xb5, 0x40);
315 return 0;
316}
317
318static int s6e3ha2_test_global(struct s6e3ha2 *ctx)
319{
320 s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x07);
321 return 0;
322}
323
324static int s6e3ha2_test(struct s6e3ha2 *ctx)
325{
326 s6e3ha2_dcs_write_seq_static(ctx, 0xb8, 0x19);
327 return 0;
328}
329
330static int s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx)
331{
332 s6e3ha2_dcs_write_seq_static(ctx, 0xbd, 0x33, 0x11, 0x02,
333 0x16, 0x02, 0x16);
334 return 0;
335}
336
337static int s6e3ha2_pentile_control(struct s6e3ha2 *ctx)
338{
339 s6e3ha2_dcs_write_seq_static(ctx, 0xc0, 0x00, 0x00, 0xd8, 0xd8);
340 return 0;
341}
342
343static int s6e3ha2_poc_global(struct s6e3ha2 *ctx)
344{
345 s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x20);
346 return 0;
347}
348
349static int s6e3ha2_poc_setting(struct s6e3ha2 *ctx)
350{
351 s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x08);
352 return 0;
353}
354
355static int s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx)
356{
357 s6e3ha2_dcs_write_seq_static(ctx, 0xcc, 0x40, 0x51);
358 return 0;
359}
360
361static int s6e3ha2_err_fg_set(struct s6e3ha2 *ctx)
362{
363 s6e3ha2_dcs_write_seq_static(ctx, 0xed, 0x44);
364 return 0;
365}
366
367static int s6e3ha2_hbm_off(struct s6e3ha2 *ctx)
368{
369 s6e3ha2_dcs_write_seq_static(ctx, 0x53, 0x00);
370 return 0;
371}
372
373static int s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
374{
375 s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
376 return 0;
377}
378
379static int s6e3ha2_gamma_update(struct s6e3ha2 *ctx)
380{
381 s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x03);
382 ndelay(100); /* need for 100ns delay */
383 s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x00);
384 return 0;
385}
386
387static int s6e3ha2_get_brightness(struct backlight_device *bl_dev)
388{
389 return bl_dev->props.brightness;
390}
391
392static int s6e3ha2_set_vint(struct s6e3ha2 *ctx)
393{
394 struct backlight_device *bl_dev = ctx->bl_dev;
395 unsigned int brightness = bl_dev->props.brightness;
396 unsigned char data[] = { 0xf4, 0x8b,
397 vint_table[brightness * (S6E3HA2_VINT_STATUS_MAX - 1) /
398 S6E3HA2_MAX_BRIGHTNESS] };
399
400 return s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data));
401}
402
403static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness)
404{
405 return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1)) /
406 S6E3HA2_MAX_BRIGHTNESS;
407}
408
409static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness)
410{
411 struct backlight_device *bl_dev = ctx->bl_dev;
412 unsigned int index = s6e3ha2_get_brightness_index(brightness);
413 u8 data[S6E3HA2_GAMMA_CMD_CNT + 1] = { 0xca, };
414 int ret;
415
416 memcpy(data + 1, gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT);
417 s6e3ha2_call_write_func(ret,
418 s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data)));
419
420 s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
421 bl_dev->props.brightness = brightness;
422
423 return 0;
424}
425
426static int s6e3ha2_set_brightness(struct backlight_device *bl_dev)
427{
428 struct s6e3ha2 *ctx = bl_get_data(bl_dev);
429 unsigned int brightness = bl_dev->props.brightness;
430 int ret;
431
432 if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
433 brightness > bl_dev->props.max_brightness) {
434 dev_err(ctx->dev, "Invalid brightness: %u\n", brightness);
435 return -EINVAL;
436 }
437
438 if (bl_dev->props.power > FB_BLANK_NORMAL)
439 return -EPERM;
440
441 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
442 s6e3ha2_call_write_func(ret, s6e3ha2_update_gamma(ctx, brightness));
443 s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
444 s6e3ha2_call_write_func(ret, s6e3ha2_set_vint(ctx));
445 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
446
447 return 0;
448}
449
450static const struct backlight_ops s6e3ha2_bl_ops = {
451 .get_brightness = s6e3ha2_get_brightness,
452 .update_status = s6e3ha2_set_brightness,
453};
454
455static int s6e3ha2_panel_init(struct s6e3ha2 *ctx)
456{
457 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
458 int ret;
459
460 s6e3ha2_call_write_func(ret, mipi_dsi_dcs_exit_sleep_mode(dsi));
461 usleep_range(5000, 6000);
462
463 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
464 s6e3ha2_call_write_func(ret, s6e3ha2_single_dsi_set(ctx));
465 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
466 s6e3ha2_call_write_func(ret, s6e3ha2_freq_calibration(ctx));
467 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
468 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
469
470 return 0;
471}
472
473static int s6e3ha2_power_off(struct s6e3ha2 *ctx)
474{
475 return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
476}
477
478static int s6e3ha2_disable(struct drm_panel *panel)
479{
480 struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
481 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
482 int ret;
483
484 s6e3ha2_call_write_func(ret, mipi_dsi_dcs_enter_sleep_mode(dsi));
485 s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_off(dsi));
486
487 msleep(40);
488 ctx->bl_dev->props.power = FB_BLANK_NORMAL;
489
490 return 0;
491}
492
493static int s6e3ha2_unprepare(struct drm_panel *panel)
494{
495 struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
496
497 return s6e3ha2_power_off(ctx);
498}
499
500static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
501{
502 int ret;
503
504 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
505 if (ret < 0)
506 return ret;
507
508 msleep(120);
509
510 gpiod_set_value(ctx->enable_gpio, 0);
511 usleep_range(5000, 6000);
512 gpiod_set_value(ctx->enable_gpio, 1);
513
514 gpiod_set_value(ctx->reset_gpio, 1);
515 usleep_range(5000, 6000);
516 gpiod_set_value(ctx->reset_gpio, 0);
517 usleep_range(5000, 6000);
518
519 return 0;
520}
521static int s6e3ha2_prepare(struct drm_panel *panel)
522{
523 struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
524 int ret;
525
526 ret = s6e3ha2_power_on(ctx);
527 if (ret < 0)
528 return ret;
529
530 ret = s6e3ha2_panel_init(ctx);
531 if (ret < 0)
532 goto err;
533
534 ctx->bl_dev->props.power = FB_BLANK_NORMAL;
535
536 return 0;
537
538err:
539 s6e3ha2_power_off(ctx);
540 return ret;
541}
542
543static int s6e3ha2_enable(struct drm_panel *panel)
544{
545 struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
546 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
547 int ret;
548
549 /* common setting */
550 s6e3ha2_call_write_func(ret,
551 mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK));
552
553 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
554 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
555 s6e3ha2_call_write_func(ret, s6e3ha2_touch_hsync_on1(ctx));
556 s6e3ha2_call_write_func(ret, s6e3ha2_pentile_control(ctx));
557 s6e3ha2_call_write_func(ret, s6e3ha2_poc_global(ctx));
558 s6e3ha2_call_write_func(ret, s6e3ha2_poc_setting(ctx));
559 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
560
561 /* pcd setting off for TB */
562 s6e3ha2_call_write_func(ret, s6e3ha2_pcd_set_off(ctx));
563 s6e3ha2_call_write_func(ret, s6e3ha2_err_fg_set(ctx));
564 s6e3ha2_call_write_func(ret, s6e3ha2_te_start_setting(ctx));
565
566 /* brightness setting */
567 s6e3ha2_call_write_func(ret, s6e3ha2_set_brightness(ctx->bl_dev));
568 s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
569 s6e3ha2_call_write_func(ret, s6e3ha2_caps_elvss_set(ctx));
570 s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
571 s6e3ha2_call_write_func(ret, s6e3ha2_acl_off(ctx));
572 s6e3ha2_call_write_func(ret, s6e3ha2_acl_off_opr(ctx));
573 s6e3ha2_call_write_func(ret, s6e3ha2_hbm_off(ctx));
574
575 /* elvss temp compensation */
576 s6e3ha2_call_write_func(ret, s6e3ha2_test_global(ctx));
577 s6e3ha2_call_write_func(ret, s6e3ha2_test(ctx));
578 s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
579
580 s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_on(dsi));
581 ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
582
583 return 0;
584}
585
586static const struct drm_display_mode default_mode = {
587 .clock = 222372,
588 .hdisplay = 1440,
589 .hsync_start = 1440 + 1,
590 .hsync_end = 1440 + 1 + 1,
591 .htotal = 1440 + 1 + 1 + 1,
592 .vdisplay = 2560,
593 .vsync_start = 2560 + 1,
594 .vsync_end = 2560 + 1 + 1,
595 .vtotal = 2560 + 1 + 1 + 15,
596 .vrefresh = 60,
597 .flags = 0,
598};
599
600static int s6e3ha2_get_modes(struct drm_panel *panel)
601{
602 struct drm_connector *connector = panel->connector;
603 struct drm_display_mode *mode;
604
605 mode = drm_mode_duplicate(panel->drm, &default_mode);
606 if (!mode) {
607 DRM_ERROR("failed to add mode %ux%ux@%u\n",
608 default_mode.hdisplay, default_mode.vdisplay,
609 default_mode.vrefresh);
610 return -ENOMEM;
611 }
612
613 drm_mode_set_name(mode);
614
615 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
616 drm_mode_probed_add(connector, mode);
617
618 connector->display_info.width_mm = 71;
619 connector->display_info.height_mm = 125;
620
621 return 1;
622}
623
624static const struct drm_panel_funcs s6e3ha2_drm_funcs = {
625 .disable = s6e3ha2_disable,
626 .unprepare = s6e3ha2_unprepare,
627 .prepare = s6e3ha2_prepare,
628 .enable = s6e3ha2_enable,
629 .get_modes = s6e3ha2_get_modes,
630};
631
632static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
633{
634 struct device *dev = &dsi->dev;
635 struct s6e3ha2 *ctx;
636 int ret;
637
638 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
639 if (!ctx)
640 return -ENOMEM;
641
642 mipi_dsi_set_drvdata(dsi, ctx);
643
644 ctx->dev = dev;
645
646 dsi->lanes = 4;
647 dsi->format = MIPI_DSI_FMT_RGB888;
648 dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
649
650 ctx->supplies[0].supply = "vdd3";
651 ctx->supplies[1].supply = "vci";
652
653 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
654 ctx->supplies);
655 if (ret < 0) {
656 dev_err(dev, "failed to get regulators: %d\n", ret);
657 return ret;
658 }
659
660 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
661 if (IS_ERR(ctx->reset_gpio)) {
662 dev_err(dev, "cannot get reset-gpios %ld\n",
663 PTR_ERR(ctx->reset_gpio));
664 return PTR_ERR(ctx->reset_gpio);
665 }
666
667 ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
668 if (IS_ERR(ctx->enable_gpio)) {
669 dev_err(dev, "cannot get enable-gpios %ld\n",
670 PTR_ERR(ctx->enable_gpio));
671 return PTR_ERR(ctx->enable_gpio);
672 }
673
674 ctx->bl_dev = backlight_device_register("s6e3ha2", dev, ctx,
675 &s6e3ha2_bl_ops, NULL);
676 if (IS_ERR(ctx->bl_dev)) {
677 dev_err(dev, "failed to register backlight device\n");
678 return PTR_ERR(ctx->bl_dev);
679 }
680
681 ctx->bl_dev->props.max_brightness = S6E3HA2_MAX_BRIGHTNESS;
682 ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
683 ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
684
685 drm_panel_init(&ctx->panel);
686 ctx->panel.dev = dev;
687 ctx->panel.funcs = &s6e3ha2_drm_funcs;
688
689 ret = drm_panel_add(&ctx->panel);
690 if (ret < 0)
691 goto unregister_backlight;
692
693 ret = mipi_dsi_attach(dsi);
694 if (ret < 0)
695 goto remove_panel;
696
697 return ret;
698
699remove_panel:
700 drm_panel_remove(&ctx->panel);
701
702unregister_backlight:
703 backlight_device_unregister(ctx->bl_dev);
704
705 return ret;
706}
707
708static int s6e3ha2_remove(struct mipi_dsi_device *dsi)
709{
710 struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi);
711
712 mipi_dsi_detach(dsi);
713 drm_panel_remove(&ctx->panel);
714 backlight_device_unregister(ctx->bl_dev);
715
716 return 0;
717}
718
719static const struct of_device_id s6e3ha2_of_match[] = {
720 { .compatible = "samsung,s6e3ha2" },
721 { }
722};
723MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
724
725static struct mipi_dsi_driver s6e3ha2_driver = {
726 .probe = s6e3ha2_probe,
727 .remove = s6e3ha2_remove,
728 .driver = {
729 .name = "panel-samsung-s6e3ha2",
730 .of_match_table = s6e3ha2_of_match,
731 },
732};
733module_mipi_dsi_driver(s6e3ha2_driver);
734
735MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
736MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>");
737MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>");
738MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver");
739MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 89eb0422821c..c4566ce8fda7 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -386,6 +386,31 @@ static void panel_simple_shutdown(struct device *dev)
386 panel_simple_disable(&panel->base); 386 panel_simple_disable(&panel->base);
387} 387}
388 388
389static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = {
390 .clock = 9000,
391 .hdisplay = 480,
392 .hsync_start = 480 + 2,
393 .hsync_end = 480 + 2 + 41,
394 .htotal = 480 + 2 + 41 + 2,
395 .vdisplay = 272,
396 .vsync_start = 272 + 2,
397 .vsync_end = 272 + 2 + 10,
398 .vtotal = 272 + 2 + 10 + 2,
399 .vrefresh = 60,
400 .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
401};
402
403static const struct panel_desc ampire_am_480272h3tmqw_t01h = {
404 .modes = &ampire_am_480272h3tmqw_t01h_mode,
405 .num_modes = 1,
406 .bpc = 8,
407 .size = {
408 .width = 105,
409 .height = 67,
410 },
411 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
412};
413
389static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = { 414static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = {
390 .clock = 33333, 415 .clock = 33333,
391 .hdisplay = 800, 416 .hdisplay = 800,
@@ -1806,8 +1831,36 @@ static const struct panel_desc urt_umsh_8596md_parallel = {
1806 .bus_format = MEDIA_BUS_FMT_RGB666_1X18, 1831 .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
1807}; 1832};
1808 1833
1834static const struct drm_display_mode winstar_wf35ltiacd_mode = {
1835 .clock = 6410,
1836 .hdisplay = 320,
1837 .hsync_start = 320 + 20,
1838 .hsync_end = 320 + 20 + 30,
1839 .htotal = 320 + 20 + 30 + 38,
1840 .vdisplay = 240,
1841 .vsync_start = 240 + 4,
1842 .vsync_end = 240 + 4 + 3,
1843 .vtotal = 240 + 4 + 3 + 15,
1844 .vrefresh = 60,
1845 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
1846};
1847
1848static const struct panel_desc winstar_wf35ltiacd = {
1849 .modes = &winstar_wf35ltiacd_mode,
1850 .num_modes = 1,
1851 .bpc = 8,
1852 .size = {
1853 .width = 70,
1854 .height = 53,
1855 },
1856 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
1857};
1858
1809static const struct of_device_id platform_of_match[] = { 1859static const struct of_device_id platform_of_match[] = {
1810 { 1860 {
1861 .compatible = "ampire,am-480272h3tmqw-t01h",
1862 .data = &ampire_am_480272h3tmqw_t01h,
1863 }, {
1811 .compatible = "ampire,am800480r3tmqwa1h", 1864 .compatible = "ampire,am800480r3tmqwa1h",
1812 .data = &ampire_am800480r3tmqwa1h, 1865 .data = &ampire_am800480r3tmqwa1h,
1813 }, { 1866 }, {
@@ -1994,6 +2047,9 @@ static const struct of_device_id platform_of_match[] = {
1994 .compatible = "urt,umsh-8596md-20t", 2047 .compatible = "urt,umsh-8596md-20t",
1995 .data = &urt_umsh_8596md_parallel, 2048 .data = &urt_umsh_8596md_parallel,
1996 }, { 2049 }, {
2050 .compatible = "winstar,wf35ltiacd",
2051 .data = &winstar_wf35ltiacd,
2052 }, {
1997 /* sentinel */ 2053 /* sentinel */
1998 } 2054 }
1999}; 2055};
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
new file mode 100644
index 000000000000..358c64ef1922
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -0,0 +1,449 @@
1/*
2 * Copyright (C) 2017 Free Electrons
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License version
6 * 2 as published by the Free Software Foundation.
7 */
8
9#include <linux/gpio/consumer.h>
10#include <linux/regulator/consumer.h>
11#include <linux/spi/spi.h>
12
13#include <drm/drmP.h>
14#include <drm/drm_panel.h>
15
16#include <video/mipi_display.h>
17
18#define ST7789V_COLMOD_RGB_FMT_18BITS (6 << 4)
19#define ST7789V_COLMOD_CTRL_FMT_18BITS (6 << 0)
20
21#define ST7789V_RAMCTRL_CMD 0xb0
22#define ST7789V_RAMCTRL_RM_RGB BIT(4)
23#define ST7789V_RAMCTRL_DM_RGB BIT(0)
24#define ST7789V_RAMCTRL_MAGIC (3 << 6)
25#define ST7789V_RAMCTRL_EPF(n) (((n) & 3) << 4)
26
27#define ST7789V_RGBCTRL_CMD 0xb1
28#define ST7789V_RGBCTRL_WO BIT(7)
29#define ST7789V_RGBCTRL_RCM(n) (((n) & 3) << 5)
30#define ST7789V_RGBCTRL_VSYNC_HIGH BIT(3)
31#define ST7789V_RGBCTRL_HSYNC_HIGH BIT(2)
32#define ST7789V_RGBCTRL_PCLK_HIGH BIT(1)
33#define ST7789V_RGBCTRL_VBP(n) ((n) & 0x7f)
34#define ST7789V_RGBCTRL_HBP(n) ((n) & 0x1f)
35
36#define ST7789V_PORCTRL_CMD 0xb2
37#define ST7789V_PORCTRL_IDLE_BP(n) (((n) & 0xf) << 4)
38#define ST7789V_PORCTRL_IDLE_FP(n) ((n) & 0xf)
39#define ST7789V_PORCTRL_PARTIAL_BP(n) (((n) & 0xf) << 4)
40#define ST7789V_PORCTRL_PARTIAL_FP(n) ((n) & 0xf)
41
42#define ST7789V_GCTRL_CMD 0xb7
43#define ST7789V_GCTRL_VGHS(n) (((n) & 7) << 4)
44#define ST7789V_GCTRL_VGLS(n) ((n) & 7)
45
46#define ST7789V_VCOMS_CMD 0xbb
47
48#define ST7789V_LCMCTRL_CMD 0xc0
49#define ST7789V_LCMCTRL_XBGR BIT(5)
50#define ST7789V_LCMCTRL_XMX BIT(3)
51#define ST7789V_LCMCTRL_XMH BIT(2)
52
53#define ST7789V_VDVVRHEN_CMD 0xc2
54#define ST7789V_VDVVRHEN_CMDEN BIT(0)
55
56#define ST7789V_VRHS_CMD 0xc3
57
58#define ST7789V_VDVS_CMD 0xc4
59
60#define ST7789V_FRCTRL2_CMD 0xc6
61
62#define ST7789V_PWCTRL1_CMD 0xd0
63#define ST7789V_PWCTRL1_MAGIC 0xa4
64#define ST7789V_PWCTRL1_AVDD(n) (((n) & 3) << 6)
65#define ST7789V_PWCTRL1_AVCL(n) (((n) & 3) << 4)
66#define ST7789V_PWCTRL1_VDS(n) ((n) & 3)
67
68#define ST7789V_PVGAMCTRL_CMD 0xe0
69#define ST7789V_PVGAMCTRL_JP0(n) (((n) & 3) << 4)
70#define ST7789V_PVGAMCTRL_JP1(n) (((n) & 3) << 4)
71#define ST7789V_PVGAMCTRL_VP0(n) ((n) & 0xf)
72#define ST7789V_PVGAMCTRL_VP1(n) ((n) & 0x3f)
73#define ST7789V_PVGAMCTRL_VP2(n) ((n) & 0x3f)
74#define ST7789V_PVGAMCTRL_VP4(n) ((n) & 0x1f)
75#define ST7789V_PVGAMCTRL_VP6(n) ((n) & 0x1f)
76#define ST7789V_PVGAMCTRL_VP13(n) ((n) & 0xf)
77#define ST7789V_PVGAMCTRL_VP20(n) ((n) & 0x7f)
78#define ST7789V_PVGAMCTRL_VP27(n) ((n) & 7)
79#define ST7789V_PVGAMCTRL_VP36(n) (((n) & 7) << 4)
80#define ST7789V_PVGAMCTRL_VP43(n) ((n) & 0x7f)
81#define ST7789V_PVGAMCTRL_VP50(n) ((n) & 0xf)
82#define ST7789V_PVGAMCTRL_VP57(n) ((n) & 0x1f)
83#define ST7789V_PVGAMCTRL_VP59(n) ((n) & 0x1f)
84#define ST7789V_PVGAMCTRL_VP61(n) ((n) & 0x3f)
85#define ST7789V_PVGAMCTRL_VP62(n) ((n) & 0x3f)
86#define ST7789V_PVGAMCTRL_VP63(n) (((n) & 0xf) << 4)
87
88#define ST7789V_NVGAMCTRL_CMD 0xe1
89#define ST7789V_NVGAMCTRL_JN0(n) (((n) & 3) << 4)
90#define ST7789V_NVGAMCTRL_JN1(n) (((n) & 3) << 4)
91#define ST7789V_NVGAMCTRL_VN0(n) ((n) & 0xf)
92#define ST7789V_NVGAMCTRL_VN1(n) ((n) & 0x3f)
93#define ST7789V_NVGAMCTRL_VN2(n) ((n) & 0x3f)
94#define ST7789V_NVGAMCTRL_VN4(n) ((n) & 0x1f)
95#define ST7789V_NVGAMCTRL_VN6(n) ((n) & 0x1f)
96#define ST7789V_NVGAMCTRL_VN13(n) ((n) & 0xf)
97#define ST7789V_NVGAMCTRL_VN20(n) ((n) & 0x7f)
98#define ST7789V_NVGAMCTRL_VN27(n) ((n) & 7)
99#define ST7789V_NVGAMCTRL_VN36(n) (((n) & 7) << 4)
100#define ST7789V_NVGAMCTRL_VN43(n) ((n) & 0x7f)
101#define ST7789V_NVGAMCTRL_VN50(n) ((n) & 0xf)
102#define ST7789V_NVGAMCTRL_VN57(n) ((n) & 0x1f)
103#define ST7789V_NVGAMCTRL_VN59(n) ((n) & 0x1f)
104#define ST7789V_NVGAMCTRL_VN61(n) ((n) & 0x3f)
105#define ST7789V_NVGAMCTRL_VN62(n) ((n) & 0x3f)
106#define ST7789V_NVGAMCTRL_VN63(n) (((n) & 0xf) << 4)
107
108#define ST7789V_TEST(val, func) \
109 do { \
110 if ((val = (func))) \
111 return val; \
112 } while (0)
113
114struct st7789v {
115 struct drm_panel panel;
116 struct spi_device *spi;
117 struct gpio_desc *reset;
118 struct backlight_device *backlight;
119 struct regulator *power;
120};
121
122enum st7789v_prefix {
123 ST7789V_COMMAND = 0,
124 ST7789V_DATA = 1,
125};
126
127static inline struct st7789v *panel_to_st7789v(struct drm_panel *panel)
128{
129 return container_of(panel, struct st7789v, panel);
130}
131
132static int st7789v_spi_write(struct st7789v *ctx, enum st7789v_prefix prefix,
133 u8 data)
134{
135 struct spi_transfer xfer = { };
136 struct spi_message msg;
137 u16 txbuf = ((prefix & 1) << 8) | data;
138
139 spi_message_init(&msg);
140
141 xfer.tx_buf = &txbuf;
142 xfer.bits_per_word = 9;
143 xfer.len = sizeof(txbuf);
144
145 spi_message_add_tail(&xfer, &msg);
146 return spi_sync(ctx->spi, &msg);
147}
148
149static int st7789v_write_command(struct st7789v *ctx, u8 cmd)
150{
151 return st7789v_spi_write(ctx, ST7789V_COMMAND, cmd);
152}
153
154static int st7789v_write_data(struct st7789v *ctx, u8 cmd)
155{
156 return st7789v_spi_write(ctx, ST7789V_DATA, cmd);
157}
158
159static const struct drm_display_mode default_mode = {
160 .clock = 7000,
161 .hdisplay = 240,
162 .hsync_start = 240 + 38,
163 .hsync_end = 240 + 38 + 10,
164 .htotal = 240 + 38 + 10 + 10,
165 .vdisplay = 320,
166 .vsync_start = 320 + 8,
167 .vsync_end = 320 + 8 + 4,
168 .vtotal = 320 + 8 + 4 + 4,
169 .vrefresh = 60,
170};
171
172static int st7789v_get_modes(struct drm_panel *panel)
173{
174 struct drm_connector *connector = panel->connector;
175 struct drm_display_mode *mode;
176
177 mode = drm_mode_duplicate(panel->drm, &default_mode);
178 if (!mode) {
179 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
180 default_mode.hdisplay, default_mode.vdisplay,
181 default_mode.vrefresh);
182 return -ENOMEM;
183 }
184
185 drm_mode_set_name(mode);
186
187 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
188 drm_mode_probed_add(connector, mode);
189
190 panel->connector->display_info.width_mm = 61;
191 panel->connector->display_info.height_mm = 103;
192
193 return 1;
194}
195
196static int st7789v_prepare(struct drm_panel *panel)
197{
198 struct st7789v *ctx = panel_to_st7789v(panel);
199 int ret;
200
201 ret = regulator_enable(ctx->power);
202 if (ret)
203 return ret;
204
205 gpiod_set_value(ctx->reset, 1);
206 msleep(30);
207 gpiod_set_value(ctx->reset, 0);
208 msleep(120);
209
210 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_EXIT_SLEEP_MODE));
211
212 /* We need to wait 120ms after a sleep out command */
213 msleep(120);
214
215 ST7789V_TEST(ret, st7789v_write_command(ctx,
216 MIPI_DCS_SET_ADDRESS_MODE));
217 ST7789V_TEST(ret, st7789v_write_data(ctx, 0));
218
219 ST7789V_TEST(ret, st7789v_write_command(ctx,
220 MIPI_DCS_SET_PIXEL_FORMAT));
221 ST7789V_TEST(ret, st7789v_write_data(ctx,
222 (MIPI_DCS_PIXEL_FMT_18BIT << 4) |
223 (MIPI_DCS_PIXEL_FMT_18BIT)));
224
225 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PORCTRL_CMD));
226 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xc));
227 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xc));
228 ST7789V_TEST(ret, st7789v_write_data(ctx, 0));
229 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PORCTRL_IDLE_BP(3) |
230 ST7789V_PORCTRL_IDLE_FP(3)));
231 ST7789V_TEST(ret, st7789v_write_data(ctx,
232 ST7789V_PORCTRL_PARTIAL_BP(3) |
233 ST7789V_PORCTRL_PARTIAL_FP(3)));
234
235 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_GCTRL_CMD));
236 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_GCTRL_VGLS(5) |
237 ST7789V_GCTRL_VGHS(3)));
238
239 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VCOMS_CMD));
240 ST7789V_TEST(ret, st7789v_write_data(ctx, 0x2b));
241
242 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_LCMCTRL_CMD));
243 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_LCMCTRL_XMH |
244 ST7789V_LCMCTRL_XMX |
245 ST7789V_LCMCTRL_XBGR));
246
247 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VDVVRHEN_CMD));
248 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_VDVVRHEN_CMDEN));
249
250 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VRHS_CMD));
251 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xf));
252
253 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VDVS_CMD));
254 ST7789V_TEST(ret, st7789v_write_data(ctx, 0x20));
255
256 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_FRCTRL2_CMD));
257 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xf));
258
259 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PWCTRL1_CMD));
260 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PWCTRL1_MAGIC));
261 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PWCTRL1_AVDD(2) |
262 ST7789V_PWCTRL1_AVCL(2) |
263 ST7789V_PWCTRL1_VDS(1)));
264
265 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PVGAMCTRL_CMD));
266 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP63(0xd)));
267 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP1(0xca)));
268 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP2(0xe)));
269 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP4(8)));
270 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP6(9)));
271 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP13(7)));
272 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP20(0x2d)));
273 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP27(0xb) |
274 ST7789V_PVGAMCTRL_VP36(3)));
275 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP43(0x3d)));
276 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_JP1(3) |
277 ST7789V_PVGAMCTRL_VP50(4)));
278 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP57(0xa)));
279 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP59(0xa)));
280 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP61(0x1b)));
281 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP62(0x28)));
282
283 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_NVGAMCTRL_CMD));
284 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN63(0xd)));
285 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN1(0xca)));
286 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN2(0xf)));
287 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN4(8)));
288 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN6(8)));
289 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN13(7)));
290 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN20(0x2e)));
291 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN27(0xc) |
292 ST7789V_NVGAMCTRL_VN36(5)));
293 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN43(0x40)));
294 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_JN1(3) |
295 ST7789V_NVGAMCTRL_VN50(4)));
296 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN57(9)));
297 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN59(0xb)));
298 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN61(0x1b)));
299 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN62(0x28)));
300
301 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_ENTER_INVERT_MODE));
302
303 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_RAMCTRL_CMD));
304 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RAMCTRL_DM_RGB |
305 ST7789V_RAMCTRL_RM_RGB));
306 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RAMCTRL_EPF(3) |
307 ST7789V_RAMCTRL_MAGIC));
308
309 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_RGBCTRL_CMD));
310 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_WO |
311 ST7789V_RGBCTRL_RCM(2) |
312 ST7789V_RGBCTRL_VSYNC_HIGH |
313 ST7789V_RGBCTRL_HSYNC_HIGH |
314 ST7789V_RGBCTRL_PCLK_HIGH));
315 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_VBP(8)));
316 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_HBP(20)));
317
318 return 0;
319}
320
321static int st7789v_enable(struct drm_panel *panel)
322{
323 struct st7789v *ctx = panel_to_st7789v(panel);
324
325 if (ctx->backlight) {
326 ctx->backlight->props.state &= ~BL_CORE_FBBLANK;
327 ctx->backlight->props.power = FB_BLANK_UNBLANK;
328 backlight_update_status(ctx->backlight);
329 }
330
331 return st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_ON);
332}
333
334static int st7789v_disable(struct drm_panel *panel)
335{
336 struct st7789v *ctx = panel_to_st7789v(panel);
337 int ret;
338
339 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_OFF));
340
341 if (ctx->backlight) {
342 ctx->backlight->props.power = FB_BLANK_POWERDOWN;
343 ctx->backlight->props.state |= BL_CORE_FBBLANK;
344 backlight_update_status(ctx->backlight);
345 }
346
347 return 0;
348}
349
350static int st7789v_unprepare(struct drm_panel *panel)
351{
352 struct st7789v *ctx = panel_to_st7789v(panel);
353 int ret;
354
355 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_ENTER_SLEEP_MODE));
356
357 regulator_disable(ctx->power);
358
359 return 0;
360}
361
362static const struct drm_panel_funcs st7789v_drm_funcs = {
363 .disable = st7789v_disable,
364 .enable = st7789v_enable,
365 .get_modes = st7789v_get_modes,
366 .prepare = st7789v_prepare,
367 .unprepare = st7789v_unprepare,
368};
369
370static int st7789v_probe(struct spi_device *spi)
371{
372 struct device_node *backlight;
373 struct st7789v *ctx;
374 int ret;
375
376 ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL);
377 if (!ctx)
378 return -ENOMEM;
379
380 spi_set_drvdata(spi, ctx);
381 ctx->spi = spi;
382
383 ctx->panel.dev = &spi->dev;
384 ctx->panel.funcs = &st7789v_drm_funcs;
385
386 ctx->power = devm_regulator_get(&spi->dev, "power");
387 if (IS_ERR(ctx->power))
388 return PTR_ERR(ctx->power);
389
390 ctx->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
391 if (IS_ERR(ctx->reset)) {
392 dev_err(&spi->dev, "Couldn't get our reset line\n");
393 return PTR_ERR(ctx->reset);
394 }
395
396 backlight = of_parse_phandle(spi->dev.of_node, "backlight", 0);
397 if (backlight) {
398 ctx->backlight = of_find_backlight_by_node(backlight);
399 of_node_put(backlight);
400
401 if (!ctx->backlight)
402 return -EPROBE_DEFER;
403 }
404
405 ret = drm_panel_add(&ctx->panel);
406 if (ret < 0)
407 goto err_free_backlight;
408
409 return 0;
410
411err_free_backlight:
412 if (ctx->backlight)
413 put_device(&ctx->backlight->dev);
414
415 return ret;
416}
417
418static int st7789v_remove(struct spi_device *spi)
419{
420 struct st7789v *ctx = spi_get_drvdata(spi);
421
422 drm_panel_detach(&ctx->panel);
423 drm_panel_remove(&ctx->panel);
424
425 if (ctx->backlight)
426 put_device(&ctx->backlight->dev);
427
428 return 0;
429}
430
431static const struct of_device_id st7789v_of_match[] = {
432 { .compatible = "sitronix,st7789v" },
433 { }
434};
435MODULE_DEVICE_TABLE(of, st7789v_of_match);
436
437static struct spi_driver st7789v_driver = {
438 .probe = st7789v_probe,
439 .remove = st7789v_remove,
440 .driver = {
441 .name = "st7789v",
442 .of_match_table = st7789v_of_match,
443 },
444};
445module_spi_driver(st7789v_driver);
446
447MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
448MODULE_DESCRIPTION("Sitronix st7789v LCD Driver");
449MODULE_LICENSE("GPL v2");