Created
December 4, 2023 03:33
-
-
Save system1357/26db117af7d8383323908b03f058a4d6 to your computer and use it in GitHub Desktop.
ClockworkPi RPi-6.1.y patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile | |
index 14ce8e7833d6..22d7fae2bf87 100644 | |
--- a/arch/arm/boot/dts/overlays/Makefile | |
+++ b/arch/arm/boot/dts/overlays/Makefile | |
@@ -41,6 +41,12 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ | |
cirrus-wm5102.dtbo \ | |
cm-swap-i2c0.dtbo \ | |
cma.dtbo \ | |
+ devterm-bt.dtbo \ | |
+ devterm-misc.dtbo \ | |
+ devterm-panel.dtbo \ | |
+ devterm-panel-uc.dtbo \ | |
+ devterm-pmu.dtbo \ | |
+ devterm-wifi.dtbo \ | |
crystalfontz-cfa050_pi_m.dtbo \ | |
cutiepi-panel.dtbo \ | |
dacberry400.dtbo \ | |
diff --git a/arch/arm/boot/dts/overlays/devterm-bt-overlay.dts b/arch/arm/boot/dts/overlays/devterm-bt-overlay.dts | |
new file mode 100755 | |
index 000000000000..4b634fdd3bda | |
--- /dev/null | |
+++ b/arch/arm/boot/dts/overlays/devterm-bt-overlay.dts | |
@@ -0,0 +1,40 @@ | |
+/dts-v1/; | |
+/plugin/; | |
+ | |
+/{ | |
+ compatible = "brcm,bcm2835"; | |
+ | |
+ fragment@0 { | |
+ target = <&uart0>; | |
+ __overlay__ { | |
+ pinctrl-names = "default"; | |
+ pinctrl-0 = <&uart0_pins &bt_pins>; | |
+ status = "okay"; | |
+ }; | |
+ }; | |
+ | |
+ fragment@1 { | |
+ target = <&gpio>; | |
+ __overlay__ { | |
+ uart0_pins: uart0_pins { | |
+ brcm,pins = <14 15 16 17>; | |
+ brcm,function = <4 4 7 7>; | |
+ brcm,pull = <0 2 0 2>; | |
+ }; | |
+ | |
+ bt_pins: bt_pins { | |
+ brcm,pins = <5 6 7>; | |
+ brcm,function = <1 0 1>; | |
+ brcm,pull = <0 2 0>; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+ fragment@2 { | |
+ target-path = "/aliases"; | |
+ __overlay__ { | |
+ serial1 = "/soc/serial@7e201000"; | |
+ serial0 = "/soc/serial@7e215040"; | |
+ }; | |
+ }; | |
+}; | |
diff --git a/arch/arm/boot/dts/overlays/devterm-misc-overlay.dts b/arch/arm/boot/dts/overlays/devterm-misc-overlay.dts | |
new file mode 100644 | |
index 000000000000..1eebe04480ac | |
--- /dev/null | |
+++ b/arch/arm/boot/dts/overlays/devterm-misc-overlay.dts | |
@@ -0,0 +1,87 @@ | |
+/dts-v1/; | |
+/plugin/; | |
+ | |
+/{ | |
+ compatible = "brcm,bcm2835"; | |
+ | |
+ fragment@0 { | |
+ target = <&i2c1>; | |
+ __overlay__ { | |
+ #address-cells = <1>; | |
+ #size-cells = <0>; | |
+ pinctrl-names = "default"; | |
+ pinctrl-0 = <&i2c1_pins>; | |
+ status = "okay"; | |
+ | |
+ adc101c: adc@54 { | |
+ reg = <0x54>; | |
+ compatible = "ti,adc101c"; | |
+ status = "okay"; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+ fragment@1 { | |
+ target = <&spi4>; | |
+ __overlay__ { | |
+ pinctrl-names = "default"; | |
+ pinctrl-0 = <&spi4_pins &spi4_cs_pins>; | |
+ cs-gpios = <&gpio 4 1>; | |
+ status = "okay"; | |
+ | |
+ spidev4_0: spidev@0 { | |
+ compatible = "spidev"; | |
+ reg = <0>; /* CE0 */ | |
+ #address-cells = <1>; | |
+ #size-cells = <0>; | |
+ spi-max-frequency = <125000000>; | |
+ status = "okay"; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+ fragment@2 { | |
+ target = <&uart1>; | |
+ __overlay__ { | |
+ pinctrl-names = "default"; | |
+ pinctrl-0 = <&uart1_pins>; | |
+ status = "okay"; | |
+ }; | |
+ }; | |
+ | |
+ fragment@3 { | |
+ target = <&gpio>; | |
+ __overlay__ { | |
+ | |
+ i2c1_pins: i2c1 { | |
+ brcm,pins = <44 45>; | |
+ brcm,function = <6>; | |
+ }; | |
+ | |
+ spi4_pins: spi4_pins { | |
+ brcm,pins = <6 7>; | |
+ brcm,function = <7>; | |
+ }; | |
+ | |
+ spi4_cs_pins: spi0_cs_pins { | |
+ brcm,pins = <4>; | |
+ brcm,function = <1>; | |
+ }; | |
+ | |
+ uart1_pins: uart1_pins { | |
+ brcm,pins = <14 15>; | |
+ brcm,function = <2>; | |
+ brcm,pull = <0 2>; | |
+ }; | |
+ | |
+ }; | |
+ }; | |
+ | |
+ fragment@4 { | |
+ target-path = "/chosen"; | |
+ __overlay__ { | |
+ bootargs = "8250.nr_uarts=1"; | |
+ }; | |
+ }; | |
+ | |
+}; | |
diff --git a/arch/arm/boot/dts/overlays/devterm-panel-overlay.dts b/arch/arm/boot/dts/overlays/devterm-panel-overlay.dts | |
new file mode 100644 | |
index 000000000000..b89793e87949 | |
--- /dev/null | |
+++ b/arch/arm/boot/dts/overlays/devterm-panel-overlay.dts | |
@@ -0,0 +1,47 @@ | |
+/dts-v1/; | |
+/plugin/; | |
+ | |
+/ { | |
+ compatible = "brcm,bcm2835"; | |
+ | |
+ fragment@0 { | |
+ target=<&dsi1>; | |
+ __overlay__ { | |
+ #address-cells = <1>; | |
+ #size-cells = <0>; | |
+ status = "okay"; | |
+ | |
+ port { | |
+ dsi_out_port: endpoint { | |
+ remote-endpoint = <&panel_dsi_port>; | |
+ }; | |
+ }; | |
+ | |
+ panel_cwd686: panel@0 { | |
+ compatible = "cw,cwd686"; | |
+ reg = <0>; | |
+ reset-gpio = <&gpio 8 1>; | |
+ backlight = <&ocp8178_backlight>; | |
+ rotation = <90>; | |
+ | |
+ port { | |
+ panel_dsi_port: endpoint { | |
+ remote-endpoint = <&dsi_out_port>; | |
+ }; | |
+ }; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+ fragment@1 { | |
+ target-path = "/"; | |
+ __overlay__ { | |
+ ocp8178_backlight: backlight@0 { | |
+ compatible = "ocp8178-backlight"; | |
+ backlight-control-gpios = <&gpio 9 0>; | |
+ default-brightness = <5>; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+}; | |
diff --git a/arch/arm/boot/dts/overlays/devterm-panel-uc-overlay.dts b/arch/arm/boot/dts/overlays/devterm-panel-uc-overlay.dts | |
new file mode 100644 | |
index 000000000000..6a66b6f5941c | |
--- /dev/null | |
+++ b/arch/arm/boot/dts/overlays/devterm-panel-uc-overlay.dts | |
@@ -0,0 +1,47 @@ | |
+/dts-v1/; | |
+/plugin/; | |
+ | |
+/ { | |
+ compatible = "brcm,bcm2835"; | |
+ | |
+ fragment@0 { | |
+ target=<&dsi1>; | |
+ __overlay__ { | |
+ #address-cells = <1>; | |
+ #size-cells = <0>; | |
+ status = "okay"; | |
+ | |
+ port { | |
+ dsi_out_port: endpoint { | |
+ remote-endpoint = <&panel_dsi_port>; | |
+ }; | |
+ }; | |
+ | |
+ panel_cwu50: panel@0 { | |
+ compatible = "cw,cwu50"; | |
+ reg = <0>; | |
+ reset-gpio = <&gpio 8 1>; | |
+ backlight = <&ocp8178_backlight>; | |
+ rotation = <90>; | |
+ | |
+ port { | |
+ panel_dsi_port: endpoint { | |
+ remote-endpoint = <&dsi_out_port>; | |
+ }; | |
+ }; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+ fragment@1 { | |
+ target-path = "/"; | |
+ __overlay__ { | |
+ ocp8178_backlight: backlight@0 { | |
+ compatible = "ocp8178-backlight"; | |
+ backlight-control-gpios = <&gpio 9 0>; | |
+ default-brightness = <5>; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+}; | |
diff --git a/arch/arm/boot/dts/overlays/devterm-pmu-overlay.dts b/arch/arm/boot/dts/overlays/devterm-pmu-overlay.dts | |
new file mode 100644 | |
index 000000000000..2339e8064edd | |
--- /dev/null | |
+++ b/arch/arm/boot/dts/overlays/devterm-pmu-overlay.dts | |
@@ -0,0 +1,104 @@ | |
+/dts-v1/; | |
+/plugin/; | |
+ | |
+/ { | |
+ compatible = "brcm,bcm2835"; | |
+ | |
+ fragment@0 { | |
+ target = <&i2c0if>; | |
+ __overlay__ { | |
+ #address-cells = <1>; | |
+ #size-cells = <0>; | |
+ pinctrl-0 = <&i2c0_pins>; | |
+ pinctrl-names = "default"; | |
+ status = "okay"; | |
+ | |
+ axp22x: pmic@34 { | |
+ interrupt-controller; | |
+ #interrupt-cells = <1>; | |
+ compatible = "x-powers,axp223"; | |
+ reg = <0x34>; /* i2c address */ | |
+ interrupt-parent = <&gpio>; | |
+ interrupts = <2 8>; /* IRQ_TYPE_EDGE_FALLING */ | |
+ irq-gpios = <&gpio 2 0>; | |
+ | |
+ regulators { | |
+ | |
+ x-powers,dcdc-freq = <3000>; | |
+ | |
+ reg_aldo1: aldo1 { | |
+ regulator-always-on; | |
+ regulator-min-microvolt = <3300000>; | |
+ regulator-max-microvolt = <3300000>; | |
+ regulator-name = "audio-vdd"; | |
+ }; | |
+ | |
+ reg_aldo2: aldo2 { | |
+ regulator-always-on; | |
+ regulator-min-microvolt = <3300000>; | |
+ regulator-max-microvolt = <3300000>; | |
+ regulator-name = "display-vcc"; | |
+ }; | |
+ | |
+ reg_dldo2: dldo2 { | |
+ regulator-always-on; | |
+ regulator-min-microvolt = <3300000>; | |
+ regulator-max-microvolt = <3300000>; | |
+ regulator-name = "dldo2"; | |
+ }; | |
+ | |
+ reg_dldo3: dldo3 { | |
+ regulator-always-on; | |
+ regulator-min-microvolt = <3300000>; | |
+ regulator-max-microvolt = <3300000>; | |
+ regulator-name = "dldo3"; | |
+ }; | |
+ | |
+ reg_dldo4: dldo4 { | |
+ regulator-always-on; | |
+ regulator-min-microvolt = <3300000>; | |
+ regulator-max-microvolt = <3300000>; | |
+ regulator-name = "dldo4"; | |
+ }; | |
+ | |
+ }; | |
+ | |
+ battery_power_supply: battery-power-supply { | |
+ compatible = "x-powers,axp221-battery-power-supply"; | |
+ monitored-battery = <&battery>; | |
+ }; | |
+ | |
+ ac_power_supply: ac_power_supply { | |
+ compatible = "x-powers,axp221-ac-power-supply"; | |
+ }; | |
+ | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+ fragment@1 { | |
+ target = <&i2c0if>; | |
+ __overlay__ { | |
+ compatible = "brcm,bcm2708-i2c"; | |
+ }; | |
+ }; | |
+ | |
+ fragment@2 { | |
+ target-path = "/aliases"; | |
+ __overlay__ { | |
+ i2c0 = "/soc/i2c@7e205000"; | |
+ }; | |
+ }; | |
+ | |
+ fragment@3 { | |
+ target-path = "/"; | |
+ __overlay__ { | |
+ battery: battery@0 { | |
+ compatible = "simple-battery"; | |
+ constant-charge-current-max-microamp = <2100000>; | |
+ voltage-min-design-microvolt = <3300000>; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+}; | |
diff --git a/arch/arm/boot/dts/overlays/devterm-wifi-overlay.dts b/arch/arm/boot/dts/overlays/devterm-wifi-overlay.dts | |
new file mode 100644 | |
index 000000000000..d5da786dc445 | |
--- /dev/null | |
+++ b/arch/arm/boot/dts/overlays/devterm-wifi-overlay.dts | |
@@ -0,0 +1,41 @@ | |
+/dts-v1/; | |
+/plugin/; | |
+ | |
+/* Enable SDIO from MMC interface via various GPIO groups */ | |
+ | |
+/{ | |
+ compatible = "brcm,bcm2835"; | |
+ | |
+ fragment@0 { | |
+ target = <&mmc>; | |
+ sdio_ovl: __overlay__ { | |
+ pinctrl-0 = <&sdio_ovl_pins>; | |
+ pinctrl-names = "default"; | |
+ non-removable; | |
+ bus-width = <4>; | |
+ status = "okay"; | |
+ }; | |
+ }; | |
+ | |
+ fragment@1 { | |
+ target = <&gpio>; | |
+ __overlay__ { | |
+ sdio_ovl_pins: sdio_ovl_pins { | |
+ brcm,pins = <22 23 24 25 26 27>; | |
+ brcm,function = <7>; /* ALT3 = SD1 */ | |
+ brcm,pull = <0 2 2 2 2 2>; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+ fragment@2 { | |
+ target-path = "/"; | |
+ __overlay__ { | |
+ wifi_pwrseq: wifi-pwrseq { | |
+ compatible = "mmc-pwrseq-simple"; | |
+ reset-gpios = <&gpio 3 0>; | |
+ }; | |
+ }; | |
+ }; | |
+ | |
+}; | |
diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig | |
index fc6d411adc86..5440ba24cc2c 100644 | |
--- a/arch/arm64/configs/bcm2711_defconfig | |
+++ b/arch/arm64/configs/bcm2711_defconfig | |
@@ -1673,3 +1673,17 @@ CONFIG_SCHED_TRACER=y | |
CONFIG_BLK_DEV_IO_TRACE=y | |
# CONFIG_UPROBE_EVENTS is not set | |
# CONFIG_STRICT_DEVMEM is not set | |
+CONFIG_REGMAP_I2C=y | |
+CONFIG_INPUT_AXP20X_PEK=y | |
+CONFIG_CHARGER_AXP20X=m | |
+CONFIG_BATTERY_AXP20X=m | |
+CONFIG_AXP20X_POWER=m | |
+CONFIG_MFD_AXP20X=y | |
+CONFIG_MFD_AXP20X_I2C=y | |
+CONFIG_REGULATOR_AXP20X=y | |
+CONFIG_DRM_PANEL_CWU50=m | |
+CONFIG_BACKLIGHT_OCP8178=m | |
+CONFIG_AXP20X_ADC=m | |
+CONFIG_TI_ADC081C=m | |
+CONFIG_CRYPTO_LIB_ARC4=y | |
+CONFIG_CRC_CCITT=y | |
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig | |
index 168403f59175..dcca9804d880 100644 | |
--- a/drivers/gpu/drm/panel/Kconfig | |
+++ b/drivers/gpu/drm/panel/Kconfig | |
@@ -749,4 +749,29 @@ config DRM_PANEL_XINPENG_XPP055C272 | |
Say Y here if you want to enable support for the Xinpeng | |
XPP055C272 controller for 720x1280 LCD panels with MIPI/RGB/SPI | |
system interfaces. | |
+ | |
+config DRM_PANEL_CWD686 | |
+ tristate "CWD686 panel" | |
+ depends on OF | |
+ depends on DRM_MIPI_DSI | |
+ depends on BACKLIGHT_CLASS_DEVICE | |
+ help | |
+ Say Y here if you want to enable support for CWD686 panel. | |
+ The panel has a 480x1280 resolution and uses 24 bit RGB per pixel. | |
+ | |
+ To compile this driver as a module, choose M here: the module | |
+ will be called panel-cwd686. | |
+ | |
+config DRM_PANEL_CWU50 | |
+ tristate "CWU50 panel" | |
+ depends on OF | |
+ depends on DRM_MIPI_DSI | |
+ depends on BACKLIGHT_CLASS_DEVICE | |
+ help | |
+ Say Y here if you want to enable support for CWU50 panel. | |
+ The panel has a 720x1280 resolution and uses 24 bit RGB per pixel. | |
+ | |
+ To compile this driver as a module, choose M here: the module | |
+ will be called panel-cwu50. | |
+ | |
endmenu | |
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile | |
index bc4ded65aa4b..d375ab77b891 100644 | |
--- a/drivers/gpu/drm/panel/Makefile | |
+++ b/drivers/gpu/drm/panel/Makefile | |
@@ -76,3 +76,5 @@ obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o | |
obj-$(CONFIG_DRM_PANEL_WAVESHARE_TOUCHSCREEN) += panel-waveshare-dsi.o | |
obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o | |
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o | |
+obj-$(CONFIG_DRM_PANEL_CWD686) += panel-cwd686.o | |
+obj-$(CONFIG_DRM_PANEL_CWU50) += panel-cwu50.o | |
diff --git a/drivers/gpu/drm/panel/panel-cwd686.c b/drivers/gpu/drm/panel/panel-cwd686.c | |
new file mode 100644 | |
index 000000000000..94f530961243 | |
--- /dev/null | |
+++ b/drivers/gpu/drm/panel/panel-cwd686.c | |
@@ -0,0 +1,294 @@ | |
+// SPDX-License-Identifier: GPL-2.0+ | |
+ | |
+#include <drm/drm_modes.h> | |
+#include <drm/drm_mipi_dsi.h> | |
+#include <drm/drm_panel.h> | |
+#include <linux/backlight.h> | |
+#include <linux/gpio/consumer.h> | |
+#include <linux/regulator/consumer.h> | |
+#include <linux/delay.h> | |
+#include <linux/of_device.h> | |
+#include <linux/module.h> | |
+ | |
+struct cwd686 { | |
+ struct device *dev; | |
+ struct drm_panel panel; | |
+ struct regulator *supply; | |
+ struct gpio_desc *reset_gpio; | |
+ struct backlight_device *backlight; | |
+ bool prepared; | |
+ bool enabled; | |
+ enum drm_panel_orientation orientation; | |
+}; | |
+ | |
+static const struct drm_display_mode default_mode = { | |
+ .clock = 54465, | |
+ .hdisplay = 480, | |
+ .hsync_start = 480 + 150, | |
+ .hsync_end = 480 + 150 + 24, | |
+ .htotal = 480 + 150 + 24 + 40, | |
+ .vdisplay = 1280, | |
+ .vsync_start = 1280 + 12, | |
+ .vsync_end = 1280 + 12+ 6, | |
+ .vtotal = 1280 + 12 + 6 + 10, | |
+}; | |
+ | |
+static inline struct cwd686 *panel_to_cwd686(struct drm_panel *panel) | |
+{ | |
+ return container_of(panel, struct cwd686, panel); | |
+} | |
+ | |
+#define dcs_write_seq(seq...) \ | |
+({ \ | |
+ static const u8 d[] = { seq }; \ | |
+ mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \ | |
+}) | |
+ | |
+static void cwd686_init_sequence(struct cwd686 *ctx) | |
+{ | |
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
+ | |
+ dcs_write_seq(0xF0,0x5A,0x59); | |
+ dcs_write_seq(0xF1,0xA5,0xA6); | |
+ dcs_write_seq(0xB0,0x54,0x32,0x23,0x45,0x44,0x44,0x44,0x44,0x9F,0x00,0x01,0x9F,0x00,0x01); | |
+ dcs_write_seq(0xB1,0x32,0x84,0x02,0x83,0x29,0x06,0x06,0x72,0x06,0x06); | |
+ dcs_write_seq(0xB2,0x73); | |
+ dcs_write_seq(0xB3,0x0B,0x09,0x13,0x11,0x0F,0x0D,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x05,0x07); | |
+ dcs_write_seq(0xB4,0x0A,0x08,0x12,0x10,0x0E,0x0C,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x06); | |
+ dcs_write_seq(0xB6,0x13,0x13); | |
+ dcs_write_seq(0xB8,0xB4,0x43,0x02,0xCC); | |
+ dcs_write_seq(0xB9,0xA5,0x20,0xFF,0xC8); | |
+ dcs_write_seq(0xBA,0x88,0x23); | |
+ dcs_write_seq(0xBD,0x43,0x0E,0x0E,0x50,0x50,0x29,0x10,0x03,0x44,0x03); | |
+ dcs_write_seq(0xC1,0x00,0x0C,0x16,0x04,0x00,0x30,0x10,0x04); | |
+ dcs_write_seq(0xC2,0x21,0x81); | |
+ dcs_write_seq(0xC3,0x02,0x30); | |
+ dcs_write_seq(0xC7,0x25,0x6A); | |
+ dcs_write_seq(0xC8,0x7C,0x68,0x59,0x4E,0x4B,0x3C,0x41,0x2B,0x44,0x43,0x43,0x60,0x4E,0x55,0x47,0x44,0x38,0x27,0x06,0x7C,0x68,0x59,0x4E,0x4B,0x3C,0x41,0x2B,0x44,0x43,0x43,0x60,0x4E,0x55,0x47,0x44,0x38,0x27,0x06);//GAMMA2.2 | |
+ //dcs_write_seq(0xC8,0x7C,0x66,0x56,0x4A,0x46,0x37,0x3B,0x24,0x3D,0x3C,0x3A,0x56,0x42,0x48,0x39,0x38,0x2C,0x17,0x06,0x7C,0x66,0x56,0x4A,0x46,0x37,0x3B,0x24,0x3D,0x3C,0x3A,0x56,0x42,0x48,0x39,0x38,0x2C,0x17,0x06);//GAMMA2.5 | |
+ //dcs_write_seq(0xC8,0x7C,0x69,0x5B,0x50,0x4E,0x40,0x46,0x31,0x4A,0x49,0x49,0x67,0x56,0x5E,0x51,0x4E,0x41,0x2F,0x06,0x7C,0x69,0x5B,0x50,0x4E,0x40,0x46,0x31,0x4A,0x49,0x49,0x67,0x56,0x5E,0x51,0x4E,0x41,0x2F,0x06);//GAMMA2.0 | |
+ //dcs_write_seq(0xC8,0x7C,0x6D,0x60,0x56,0x54,0x47,0x4c,0x37,0x50,0x4e,0x4e,0x6d,0x5c,0x66,0x59,0x56,0x4A,0x36,0x06,0x7C,0x6D,0x60,0x56,0x54,0x47,0x4c,0x37,0x50,0x4e,0x4e,0x6d,0x5c,0x66,0x59,0x56,0x4A,0x36,0x06);//GAMMA1.8 | |
+ //dcs_write_seq(0xC8,0x7C,0x6e,0x62,0x59,0x58,0x4b,0x52,0x3d,0x57,0x56,0x56,0x75,0x66,0x71,0x66,0x64,0x55,0x44,0x06,0x7C,0x6e,0x62,0x59,0x58,0x4b,0x52,0x3d,0x57,0x56,0x56,0x75,0x66,0x71,0x66,0x64,0x55,0x44,0x06);//GAMMA1.6 | |
+ dcs_write_seq(0xD4,0x00,0x00,0x00,0x32,0x04,0x51); | |
+ dcs_write_seq(0xF1,0x5A,0x59); | |
+ dcs_write_seq(0xF0,0xA5,0xA6); | |
+ dcs_write_seq(0x36,0x14); | |
+ dcs_write_seq(0x35,0x00); | |
+ dcs_write_seq(0x11); | |
+ msleep(120); | |
+ dcs_write_seq(0x29); | |
+ msleep(20); | |
+} | |
+ | |
+static int cwd686_disable(struct drm_panel *panel) | |
+{ | |
+ struct cwd686 *ctx = panel_to_cwd686(panel); | |
+ | |
+ if (!ctx->enabled) | |
+ return 0; | |
+ | |
+ backlight_disable(ctx->backlight); | |
+ | |
+ ctx->enabled = false; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwd686_unprepare(struct drm_panel *panel) | |
+{ | |
+ struct cwd686 *ctx = panel_to_cwd686(panel); | |
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
+ int ret; | |
+ | |
+ if (!ctx->prepared) | |
+ return 0; | |
+ | |
+ ret = mipi_dsi_dcs_set_display_off(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to turn display off (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ | |
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to enter sleep mode (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ msleep(120); | |
+ | |
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
+ msleep(5); | |
+ | |
+ ctx->prepared = false; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwd686_prepare(struct drm_panel *panel) | |
+{ | |
+ struct cwd686 *ctx = panel_to_cwd686(panel); | |
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
+ int ret; | |
+ | |
+ if (ctx->prepared) | |
+ return 0; | |
+ | |
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
+ msleep(10); | |
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1); | |
+ msleep(120); | |
+ | |
+ /* Enabe tearing mode: send TE (tearing effect) at VBLANK */ | |
+ ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to enable vblank TE (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ /* Exit sleep mode and power on */ | |
+ | |
+ cwd686_init_sequence(ctx); | |
+ | |
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to exit sleep mode (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ msleep(120); | |
+ | |
+ ret = mipi_dsi_dcs_set_display_on(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to turn display on (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ msleep(20); | |
+ | |
+ ctx->prepared = true; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwd686_enable(struct drm_panel *panel) | |
+{ | |
+ struct cwd686 *ctx = panel_to_cwd686(panel); | |
+ | |
+ if (ctx->enabled) | |
+ return 0; | |
+ | |
+ backlight_enable(ctx->backlight); | |
+ | |
+ ctx->enabled = true; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwd686_get_modes(struct drm_panel *panel, struct drm_connector *connector) | |
+{ | |
+ struct cwd686 *ctx = panel_to_cwd686(panel); | |
+ struct drm_display_mode *mode; | |
+ | |
+ mode = drm_mode_duplicate(connector->dev, &default_mode); | |
+ if (!mode) { | |
+ dev_err(panel->dev, "bad mode or failed to add mode\n"); | |
+ return -EINVAL; | |
+ } | |
+ drm_mode_set_name(mode); | |
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | |
+ | |
+ connector->display_info.width_mm = mode->width_mm; | |
+ connector->display_info.height_mm = mode->height_mm; | |
+ | |
+ /* set up connector's "panel orientation" property */ | |
+ drm_connector_set_panel_orientation(connector, ctx->orientation); | |
+ | |
+ drm_mode_probed_add(connector, mode); | |
+ | |
+ return 1; /* Number of modes */ | |
+} | |
+ | |
+static const struct drm_panel_funcs cwd686_drm_funcs = { | |
+ .disable = cwd686_disable, | |
+ .unprepare = cwd686_unprepare, | |
+ .prepare = cwd686_prepare, | |
+ .enable = cwd686_enable, | |
+ .get_modes = cwd686_get_modes, | |
+}; | |
+ | |
+static int cwd686_probe(struct mipi_dsi_device *dsi) | |
+{ | |
+ struct device *dev = &dsi->dev; | |
+ struct cwd686 *ctx; | |
+ int ret; | |
+ | |
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | |
+ if (!ctx) | |
+ return -ENOMEM; | |
+ | |
+ 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_SYNC_PULSE | MIPI_DSI_MODE_LPM; | |
+ | |
+ ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); | |
+ if (IS_ERR(ctx->reset_gpio)) { | |
+ ret = PTR_ERR(ctx->reset_gpio); | |
+ if (ret != -EPROBE_DEFER) | |
+ dev_err(dev, "failed to request GPIO (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ | |
+ ctx->backlight = devm_of_find_backlight(dev); | |
+ if (IS_ERR(ctx->backlight)) | |
+ return PTR_ERR(ctx->backlight); | |
+ | |
+ ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); | |
+ if (ret < 0) { | |
+ dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); | |
+ return ret; | |
+ } | |
+ | |
+ drm_panel_init(&ctx->panel, dev, &cwd686_drm_funcs, DRM_MODE_CONNECTOR_DSI); | |
+ | |
+ drm_panel_add(&ctx->panel); | |
+ | |
+ ret = mipi_dsi_attach(dsi); | |
+ if (ret < 0) { | |
+ dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret); | |
+ drm_panel_remove(&ctx->panel); | |
+ return ret; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static void cwd686_remove(struct mipi_dsi_device *dsi) | |
+{ | |
+ struct cwd686 *ctx = mipi_dsi_get_drvdata(dsi); | |
+ int ret; | |
+ | |
+ ret = mipi_dsi_detach(dsi); | |
+ if (ret < 0) | |
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); | |
+ | |
+ drm_panel_remove(&ctx->panel); | |
+} | |
+ | |
+static const struct of_device_id cwd686_of_match[] = { | |
+ { .compatible = "cw,cwd686" }, | |
+ { } | |
+}; | |
+MODULE_DEVICE_TABLE(of, cwd686_of_match); | |
+ | |
+static struct mipi_dsi_driver cwd686_driver = { | |
+ .probe = cwd686_probe, | |
+ .remove = cwd686_remove, | |
+ .driver = { | |
+ .name = "panel-cwd686", | |
+ .of_match_table = cwd686_of_match, | |
+ }, | |
+}; | |
+module_mipi_dsi_driver(cwd686_driver); | |
+ | |
+MODULE_DESCRIPTION("DRM Driver for cwd686 MIPI DSI panel"); | |
+MODULE_LICENSE("GPL v2"); | |
diff --git a/drivers/gpu/drm/panel/panel-cwu50.c b/drivers/gpu/drm/panel/panel-cwu50.c | |
new file mode 100644 | |
index 000000000000..540932453e7f | |
--- /dev/null | |
+++ b/drivers/gpu/drm/panel/panel-cwu50.c | |
@@ -0,0 +1,480 @@ | |
+// SPDX-License-Identifier: GPL-2.0+ | |
+ | |
+#include <drm/drm_modes.h> | |
+#include <drm/drm_mipi_dsi.h> | |
+#include <drm/drm_panel.h> | |
+#include <linux/backlight.h> | |
+#include <linux/gpio/consumer.h> | |
+#include <linux/regulator/consumer.h> | |
+#include <linux/delay.h> | |
+#include <linux/of_device.h> | |
+#include <linux/module.h> | |
+ | |
+struct cwu50 { | |
+ struct device *dev; | |
+ struct drm_panel panel; | |
+ struct regulator *supply; | |
+ struct gpio_desc *reset_gpio; | |
+ struct backlight_device *backlight; | |
+ bool prepared; | |
+ bool enabled; | |
+ enum drm_panel_orientation orientation; | |
+}; | |
+ | |
+static const struct drm_display_mode default_mode = { | |
+ .clock = 62500, | |
+ .hdisplay = 720, | |
+ .hsync_start = 720 + 43, | |
+ .hsync_end = 720+ 43 + 20, | |
+ .htotal = 720 + 43 + 20 + 20, | |
+ .vdisplay = 1280, | |
+ .vsync_start = 1280 + 8, | |
+ .vsync_end = 1280 + 8+ 2, | |
+ .vtotal = 1280 + 8 + 2 + 16, | |
+}; | |
+ | |
+static inline struct cwu50 *panel_to_cwu50(struct drm_panel *panel) | |
+{ | |
+ return container_of(panel, struct cwu50, panel); | |
+} | |
+ | |
+#define dcs_write_seq(seq...) \ | |
+({ \ | |
+ static const u8 d[] = { seq }; \ | |
+ mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \ | |
+}) | |
+ | |
+static void cwu50_init_sequence(struct cwu50 *ctx) | |
+{ | |
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
+ | |
+ dcs_write_seq(0xE1,0x93); | |
+ dcs_write_seq(0xE2,0x65); | |
+ dcs_write_seq(0xE3,0xF8); | |
+ dcs_write_seq(0x70,0x20); | |
+ dcs_write_seq(0x71,0x13); | |
+ dcs_write_seq(0x72,0x06); | |
+ dcs_write_seq(0x75,0x03); | |
+ dcs_write_seq(0xE0,0x01); | |
+ dcs_write_seq(0x00,0x00); | |
+ dcs_write_seq(0x01,0x47);//VCOM0x47 | |
+ dcs_write_seq(0x03,0x00); | |
+ dcs_write_seq(0x04,0x4D); | |
+ dcs_write_seq(0x0C,0x64); | |
+ dcs_write_seq(0x17,0x00); | |
+ dcs_write_seq(0x18,0xBF); | |
+ dcs_write_seq(0x19,0x00); | |
+ dcs_write_seq(0x1A,0x00); | |
+ dcs_write_seq(0x1B,0xBF); | |
+ dcs_write_seq(0x1C,0x00); | |
+ dcs_write_seq(0x1F,0x7E); | |
+ dcs_write_seq(0x20,0x24); | |
+ dcs_write_seq(0x21,0x24); | |
+ dcs_write_seq(0x22,0x4E); | |
+ dcs_write_seq(0x24,0xFE); | |
+ dcs_write_seq(0x37,0x09); | |
+ dcs_write_seq(0x38,0x04); | |
+ dcs_write_seq(0x3C,0x76); | |
+ dcs_write_seq(0x3D,0xFF); | |
+ dcs_write_seq(0x3E,0xFF); | |
+ dcs_write_seq(0x3F,0x7F); | |
+ dcs_write_seq(0x40,0x04);//Dot inversion type | |
+ dcs_write_seq(0x41,0xA0); | |
+ dcs_write_seq(0x44,0x11); | |
+ dcs_write_seq(0x55,0x02); | |
+ dcs_write_seq(0x56,0x01); | |
+ dcs_write_seq(0x57,0x49); | |
+ dcs_write_seq(0x58,0x09); | |
+ dcs_write_seq(0x59,0x2A); | |
+ dcs_write_seq(0x5A,0x1A); | |
+ dcs_write_seq(0x5B,0x1A); | |
+ dcs_write_seq(0x5D,0x78); | |
+ dcs_write_seq(0x5E,0x6E); | |
+ dcs_write_seq(0x5F,0x66); | |
+ dcs_write_seq(0x60,0x5E); | |
+ dcs_write_seq(0x61,0x60); | |
+ dcs_write_seq(0x62,0x54); | |
+ dcs_write_seq(0x63,0x5C); | |
+ dcs_write_seq(0x64,0x47); | |
+ dcs_write_seq(0x65,0x5F); | |
+ dcs_write_seq(0x66,0x5D); | |
+ dcs_write_seq(0x67,0x5B); | |
+ dcs_write_seq(0x68,0x76); | |
+ dcs_write_seq(0x69,0x61); | |
+ dcs_write_seq(0x6A,0x63); | |
+ dcs_write_seq(0x6B,0x50); | |
+ dcs_write_seq(0x6C,0x45); | |
+ dcs_write_seq(0x6D,0x34); | |
+ dcs_write_seq(0x6E,0x1C); | |
+ dcs_write_seq(0x6F,0x07); | |
+ dcs_write_seq(0x70,0x78); | |
+ dcs_write_seq(0x71,0x6E); | |
+ dcs_write_seq(0x72,0x66); | |
+ dcs_write_seq(0x73,0x5E); | |
+ dcs_write_seq(0x74,0x60); | |
+ dcs_write_seq(0x75,0x54); | |
+ dcs_write_seq(0x76,0x5C); | |
+ dcs_write_seq(0x77,0x47); | |
+ dcs_write_seq(0x78,0x5F); | |
+ dcs_write_seq(0x79,0x5D); | |
+ dcs_write_seq(0x7A,0x5B); | |
+ dcs_write_seq(0x7B,0x76); | |
+ dcs_write_seq(0x7C,0x61); | |
+ dcs_write_seq(0x7D,0x63); | |
+ dcs_write_seq(0x7E,0x50); | |
+ dcs_write_seq(0x7F,0x45); | |
+ dcs_write_seq(0x80,0x34); | |
+ dcs_write_seq(0x81,0x1C); | |
+ dcs_write_seq(0x82,0x07); | |
+ dcs_write_seq(0xE0,0x02); | |
+ dcs_write_seq(0x00,0x44); | |
+ dcs_write_seq(0x01,0x46); | |
+ dcs_write_seq(0x02,0x48); | |
+ dcs_write_seq(0x03,0x4A); | |
+ dcs_write_seq(0x04,0x40); | |
+ dcs_write_seq(0x05,0x42); | |
+ dcs_write_seq(0x06,0x1F); | |
+ dcs_write_seq(0x07,0x1F); | |
+ dcs_write_seq(0x08,0x1F); | |
+ dcs_write_seq(0x09,0x1F); | |
+ dcs_write_seq(0x0A,0x1F); | |
+ dcs_write_seq(0x0B,0x1F); | |
+ dcs_write_seq(0x0C,0x1F); | |
+ dcs_write_seq(0x0D,0x1F); | |
+ dcs_write_seq(0x0E,0x1F); | |
+ dcs_write_seq(0x0F,0x1F); | |
+ dcs_write_seq(0x10,0x1F); | |
+ dcs_write_seq(0x11,0x1F); | |
+ dcs_write_seq(0x12,0x1F); | |
+ dcs_write_seq(0x13,0x1F); | |
+ dcs_write_seq(0x14,0x1E); | |
+ dcs_write_seq(0x15,0x1F); | |
+ dcs_write_seq(0x16,0x45); | |
+ dcs_write_seq(0x17,0x47); | |
+ dcs_write_seq(0x18,0x49); | |
+ dcs_write_seq(0x19,0x4B); | |
+ dcs_write_seq(0x1A,0x41); | |
+ dcs_write_seq(0x1B,0x43); | |
+ dcs_write_seq(0x1C,0x1F); | |
+ dcs_write_seq(0x1D,0x1F); | |
+ dcs_write_seq(0x1E,0x1F); | |
+ dcs_write_seq(0x1F,0x1F); | |
+ dcs_write_seq(0x20,0x1F); | |
+ dcs_write_seq(0x21,0x1F); | |
+ dcs_write_seq(0x22,0x1F); | |
+ dcs_write_seq(0x23,0x1F); | |
+ dcs_write_seq(0x24,0x1F); | |
+ dcs_write_seq(0x25,0x1F); | |
+ dcs_write_seq(0x26,0x1F); | |
+ dcs_write_seq(0x27,0x1F); | |
+ dcs_write_seq(0x28,0x1F); | |
+ dcs_write_seq(0x29,0x1F); | |
+ dcs_write_seq(0x2A,0x1E); | |
+ dcs_write_seq(0x2B,0x1F); | |
+ dcs_write_seq(0x2C,0x0B); | |
+ dcs_write_seq(0x2D,0x09); | |
+ dcs_write_seq(0x2E,0x07); | |
+ dcs_write_seq(0x2F,0x05); | |
+ dcs_write_seq(0x30,0x03); | |
+ dcs_write_seq(0x31,0x01); | |
+ dcs_write_seq(0x32,0x1F); | |
+ dcs_write_seq(0x33,0x1F); | |
+ dcs_write_seq(0x34,0x1F); | |
+ dcs_write_seq(0x35,0x1F); | |
+ dcs_write_seq(0x36,0x1F); | |
+ dcs_write_seq(0x37,0x1F); | |
+ dcs_write_seq(0x38,0x1F); | |
+ dcs_write_seq(0x39,0x1F); | |
+ dcs_write_seq(0x3A,0x1F); | |
+ dcs_write_seq(0x3B,0x1F); | |
+ dcs_write_seq(0x3C,0x1F); | |
+ dcs_write_seq(0x3D,0x1F); | |
+ dcs_write_seq(0x3E,0x1F); | |
+ dcs_write_seq(0x3F,0x1F); | |
+ dcs_write_seq(0x40,0x1F); | |
+ dcs_write_seq(0x41,0x1E); | |
+ dcs_write_seq(0x42,0x0A); | |
+ dcs_write_seq(0x43,0x08); | |
+ dcs_write_seq(0x44,0x06); | |
+ dcs_write_seq(0x45,0x04); | |
+ dcs_write_seq(0x46,0x02); | |
+ dcs_write_seq(0x47,0x00); | |
+ dcs_write_seq(0x48,0x1F); | |
+ dcs_write_seq(0x49,0x1F); | |
+ dcs_write_seq(0x4A,0x1F); | |
+ dcs_write_seq(0x4B,0x1F); | |
+ dcs_write_seq(0x4C,0x1F); | |
+ dcs_write_seq(0x4D,0x1F); | |
+ dcs_write_seq(0x4E,0x1F); | |
+ dcs_write_seq(0x4F,0x1F); | |
+ dcs_write_seq(0x50,0x1F); | |
+ dcs_write_seq(0x51,0x1F); | |
+ dcs_write_seq(0x52,0x1F); | |
+ dcs_write_seq(0x53,0x1F); | |
+ dcs_write_seq(0x54,0x1F); | |
+ dcs_write_seq(0x55,0x1F); | |
+ dcs_write_seq(0x56,0x1F); | |
+ dcs_write_seq(0x57,0x1E); | |
+ dcs_write_seq(0x58,0x40); | |
+ dcs_write_seq(0x59,0x00); | |
+ dcs_write_seq(0x5A,0x00); | |
+ dcs_write_seq(0x5B,0x30); | |
+ dcs_write_seq(0x5C,0x02); | |
+ dcs_write_seq(0x5D,0x40); | |
+ dcs_write_seq(0x5E,0x01); | |
+ dcs_write_seq(0x5F,0x02); | |
+ dcs_write_seq(0x60,0x00); | |
+ dcs_write_seq(0x61,0x01); | |
+ dcs_write_seq(0x62,0x02); | |
+ dcs_write_seq(0x63,0x65); | |
+ dcs_write_seq(0x64,0x66); | |
+ dcs_write_seq(0x65,0x00); | |
+ dcs_write_seq(0x66,0x00); | |
+ dcs_write_seq(0x67,0x74); | |
+ dcs_write_seq(0x68,0x06); | |
+ dcs_write_seq(0x69,0x65); | |
+ dcs_write_seq(0x6A,0x66); | |
+ dcs_write_seq(0x6B,0x10); | |
+ dcs_write_seq(0x6C,0x00); | |
+ dcs_write_seq(0x6D,0x04); | |
+ dcs_write_seq(0x6E,0x04); | |
+ dcs_write_seq(0x6F,0x88); | |
+ dcs_write_seq(0x70,0x00); | |
+ dcs_write_seq(0x71,0x00); | |
+ dcs_write_seq(0x72,0x06); | |
+ dcs_write_seq(0x73,0x7B); | |
+ dcs_write_seq(0x74,0x00); | |
+ dcs_write_seq(0x75,0x87); | |
+ dcs_write_seq(0x76,0x00); | |
+ dcs_write_seq(0x77,0x5D); | |
+ dcs_write_seq(0x78,0x17); | |
+ dcs_write_seq(0x79,0x1F); | |
+ dcs_write_seq(0x7A,0x00); | |
+ dcs_write_seq(0x7B,0x00); | |
+ dcs_write_seq(0x7C,0x00); | |
+ dcs_write_seq(0x7D,0x03); | |
+ dcs_write_seq(0x7E,0x7B); | |
+ dcs_write_seq(0xE0,0x04); | |
+ dcs_write_seq(0x09,0x10); | |
+ dcs_write_seq(0xE0,0x00); | |
+ dcs_write_seq(0xE6,0x02); | |
+ dcs_write_seq(0xE7,0x02); | |
+ dcs_write_seq(0x11);// SLPOUT | |
+ msleep (120); | |
+ dcs_write_seq(0x29);// DSPON | |
+ msleep (20); | |
+ dcs_write_seq(0x35,0x00); | |
+} | |
+ | |
+static int cwu50_disable(struct drm_panel *panel) | |
+{ | |
+ struct cwu50 *ctx = panel_to_cwu50(panel); | |
+ | |
+ if (!ctx->enabled) | |
+ return 0; | |
+ | |
+ backlight_disable(ctx->backlight); | |
+ | |
+ ctx->enabled = false; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwu50_unprepare(struct drm_panel *panel) | |
+{ | |
+ struct cwu50 *ctx = panel_to_cwu50(panel); | |
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
+ int ret; | |
+ | |
+ if (!ctx->prepared) | |
+ return 0; | |
+ | |
+ ret = mipi_dsi_dcs_set_display_off(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to turn display off (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ | |
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to enter sleep mode (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ msleep(120); | |
+ | |
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
+ msleep(5); | |
+ | |
+ ctx->prepared = false; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwu50_prepare(struct drm_panel *panel) | |
+{ | |
+ struct cwu50 *ctx = panel_to_cwu50(panel); | |
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
+ int ret; | |
+ | |
+ if (ctx->prepared) | |
+ return 0; | |
+ | |
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
+ msleep(10); | |
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1); | |
+ msleep(120); | |
+ | |
+ /* Enabe tearing mode: send TE (tearing effect) at VBLANK */ | |
+ ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to enable vblank TE (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ /* Exit sleep mode and power on */ | |
+ | |
+ cwu50_init_sequence(ctx); | |
+ | |
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to exit sleep mode (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ msleep(120); | |
+ | |
+ ret = mipi_dsi_dcs_set_display_on(dsi); | |
+ if (ret < 0) { | |
+ dev_err(ctx->dev, "failed to turn display on (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ msleep(20); | |
+ | |
+ ctx->prepared = true; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwu50_enable(struct drm_panel *panel) | |
+{ | |
+ struct cwu50 *ctx = panel_to_cwu50(panel); | |
+ | |
+ if (ctx->enabled) | |
+ return 0; | |
+ | |
+ backlight_enable(ctx->backlight); | |
+ | |
+ ctx->enabled = true; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int cwu50_get_modes(struct drm_panel *panel, struct drm_connector *connector) | |
+{ | |
+ struct cwu50 *ctx = panel_to_cwu50(panel); | |
+ struct drm_display_mode *mode; | |
+ | |
+ mode = drm_mode_duplicate(connector->dev, &default_mode); | |
+ if (!mode) { | |
+ dev_err(panel->dev, "bad mode or failed to add mode\n"); | |
+ return -EINVAL; | |
+ } | |
+ drm_mode_set_name(mode); | |
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | |
+ | |
+ connector->display_info.width_mm = mode->width_mm; | |
+ connector->display_info.height_mm = mode->height_mm; | |
+ | |
+ /* set up connector's "panel orientation" property */ | |
+ drm_connector_set_panel_orientation(connector, ctx->orientation); | |
+ | |
+ drm_mode_probed_add(connector, mode); | |
+ | |
+ return 1; /* Number of modes */ | |
+} | |
+ | |
+static const struct drm_panel_funcs cwu50_drm_funcs = { | |
+ .disable = cwu50_disable, | |
+ .unprepare = cwu50_unprepare, | |
+ .prepare = cwu50_prepare, | |
+ .enable = cwu50_enable, | |
+ .get_modes = cwu50_get_modes, | |
+}; | |
+ | |
+static int cwu50_probe(struct mipi_dsi_device *dsi) | |
+{ | |
+ struct device *dev = &dsi->dev; | |
+ struct cwu50 *ctx; | |
+ int ret; | |
+ | |
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | |
+ if (!ctx) | |
+ return -ENOMEM; | |
+ | |
+ 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_SYNC_PULSE; | |
+ | |
+ ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); | |
+ if (IS_ERR(ctx->reset_gpio)) { | |
+ ret = PTR_ERR(ctx->reset_gpio); | |
+ if (ret != -EPROBE_DEFER) | |
+ dev_err(dev, "failed to request GPIO (%d)\n", ret); | |
+ return ret; | |
+ } | |
+ | |
+ ctx->backlight = devm_of_find_backlight(dev); | |
+ if (IS_ERR(ctx->backlight)) | |
+ return PTR_ERR(ctx->backlight); | |
+ | |
+ ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); | |
+ if (ret < 0) { | |
+ dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); | |
+ return ret; | |
+ } | |
+ | |
+ drm_panel_init(&ctx->panel, dev, &cwu50_drm_funcs, DRM_MODE_CONNECTOR_DSI); | |
+ | |
+ drm_panel_add(&ctx->panel); | |
+ | |
+ ret = mipi_dsi_attach(dsi); | |
+ if (ret < 0) { | |
+ dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret); | |
+ drm_panel_remove(&ctx->panel); | |
+ return ret; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static void cwu50_remove(struct mipi_dsi_device *dsi) | |
+{ | |
+ struct cwu50 *ctx = mipi_dsi_get_drvdata(dsi); | |
+ int ret; | |
+ | |
+ ret = mipi_dsi_detach(dsi); | |
+ if (ret < 0) | |
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); | |
+ | |
+ drm_panel_remove(&ctx->panel); | |
+} | |
+ | |
+static const struct of_device_id cwu50_of_match[] = { | |
+ { .compatible = "cw,cwu50" }, | |
+ { } | |
+}; | |
+MODULE_DEVICE_TABLE(of, cwu50_of_match); | |
+ | |
+static struct mipi_dsi_driver cwu50_driver = { | |
+ .probe = cwu50_probe, | |
+ .remove = cwu50_remove, | |
+ .driver = { | |
+ .name = "panel-cwu50", | |
+ .of_match_table = cwu50_of_match, | |
+ }, | |
+}; | |
+module_mipi_dsi_driver(cwu50_driver); | |
+ | |
+MODULE_DESCRIPTION("DRM Driver for cwu50 MIPI DSI panel"); | |
+MODULE_LICENSE("GPL v2"); | |
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c | |
index 0ee9ada428ab..c58c1030d1ef 100644 | |
--- a/drivers/gpu/drm/vc4/vc4_dsi.c | |
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c | |
@@ -747,7 +747,7 @@ static void vc4_dsi_ulps(struct vc4_dsi *dsi, bool ulps) | |
(dsi->lanes > 1 ? DSI1_STAT_PHY_D1_STOP : 0) | | |
(dsi->lanes > 2 ? DSI1_STAT_PHY_D2_STOP : 0) | | |
(dsi->lanes > 3 ? DSI1_STAT_PHY_D3_STOP : 0)); | |
- int ret; | |
+ int ret, i = 0; | |
bool ulps_currently_enabled = (DSI_PORT_READ(PHY_AFEC0) & | |
DSI_PORT_BIT(PHY_AFEC0_LATCH_ULPS)); | |
@@ -775,14 +775,15 @@ static void vc4_dsi_ulps(struct vc4_dsi *dsi, bool ulps) | |
DSI_PORT_WRITE(STAT, stat_stop); | |
DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); | |
- ret = wait_for((DSI_PORT_READ(STAT) & stat_stop) == stat_stop, 200); | |
- if (ret) { | |
- dev_warn(&dsi->pdev->dev, | |
- "Timeout waiting for DSI STOP entry: STAT 0x%08x", | |
- DSI_PORT_READ(STAT)); | |
- DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); | |
- return; | |
+ while(wait_for((DSI_PORT_READ(STAT) & stat_stop) == stat_stop, 200)){ | |
+ if(i++ == 10) { | |
+ DSI_PORT_WRITE(PHYC, DSI_PORT_READ(PHYC) & ~phyc_ulps); | |
+ break; | |
+ } | |
} | |
+ if(i > 0) | |
+ dev_warn(&dsi->pdev->dev, "Timeout waiting for DSI STOP entry: STAT 0x%08x %d", DSI_PORT_READ(STAT), i); | |
+ return; | |
} | |
static u32 | |
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c | |
index 880c41fa7021..6d866ce69c76 100644 | |
--- a/drivers/mfd/axp20x.c | |
+++ b/drivers/mfd/axp20x.c | |
@@ -1009,6 +1009,7 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) | |
return ret; | |
} | |
+ pm_power_off = 0; | |
if (!pm_power_off) { | |
axp20x_pm_power_off = axp20x; | |
pm_power_off = axp20x_power_off; | |
diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c | |
index 57e50208d537..61291aa52235 100644 | |
--- a/drivers/power/supply/axp20x_ac_power.c | |
+++ b/drivers/power/supply/axp20x_ac_power.c | |
@@ -53,6 +53,9 @@ static irqreturn_t axp20x_ac_power_irq(int irq, void *devid) | |
{ | |
struct axp20x_ac_power *power = devid; | |
+ regmap_update_bits(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, 0x03, 0x00); | |
+ regmap_update_bits(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, 0x03, 0x03); | |
+ | |
power_supply_changed(power->supply); | |
return IRQ_HANDLED; | |
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c | |
index 9106077c0dbb..17d3fb4a2ba4 100644 | |
--- a/drivers/power/supply/axp20x_battery.c | |
+++ b/drivers/power/supply/axp20x_battery.c | |
@@ -326,6 +326,42 @@ static int axp20x_battery_get_prop(struct power_supply *psy, | |
val->intval *= 1000; | |
break; | |
+ case POWER_SUPPLY_PROP_ENERGY_FULL: | |
+ case POWER_SUPPLY_PROP_ENERGY_NOW: | |
+ /* When no battery is present, return 0 */ | |
+ ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE, | |
+ ®); | |
+ if (ret) | |
+ return ret; | |
+ | |
+ if (!(reg & AXP20X_PWR_OP_BATT_PRESENT)) { | |
+ val->intval = 0; | |
+ return 0; | |
+ } | |
+ | |
+ if(psp == POWER_SUPPLY_PROP_ENERGY_FULL) { | |
+ val->intval = 8000000; | |
+ return 0; | |
+ } | |
+ | |
+ ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, ®); | |
+ if (ret) | |
+ return ret; | |
+ | |
+ if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID)) | |
+ return -EINVAL; | |
+ | |
+ val1 = reg & AXP209_FG_PERCENT; | |
+ if (val1 > 90) | |
+ val1= 80; | |
+ else if (val1 < 10) | |
+ val1 = 0; | |
+ else | |
+ val1 -= 10; | |
+ | |
+ val->intval = val1 * 100000; | |
+ break; | |
+ | |
default: | |
return -EINVAL; | |
} | |
@@ -497,6 +533,8 @@ static enum power_supply_property axp20x_battery_props[] = { | |
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | |
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | |
POWER_SUPPLY_PROP_CAPACITY, | |
+ POWER_SUPPLY_PROP_ENERGY_FULL, | |
+ POWER_SUPPLY_PROP_ENERGY_NOW, | |
}; | |
static int axp20x_battery_prop_writeable(struct power_supply *psy, | |
@@ -642,6 +680,12 @@ static int axp20x_power_probe(struct platform_device *pdev) | |
axp20x_get_constant_charge_current(axp20x_batt, | |
&axp20x_batt->max_ccc); | |
+ regmap_update_bits(axp20x_batt->regmap, AXP20X_VBUS_IPSOUT_MGMT, 0x03, 0x03); | |
+ regmap_update_bits(axp20x_batt->regmap, AXP20X_OFF_CTRL, 0x08, 0x08); | |
+ regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL2, 0x30, 0x20); | |
+ regmap_update_bits(axp20x_batt->regmap, AXP20X_PEK_KEY, 0x0f, 0x0b); | |
+ regmap_update_bits(axp20x_batt->regmap, AXP20X_GPIO0_CTRL, 0x07, 0x00); | |
+ | |
return 0; | |
} | |
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | |
index 6347becff898..685529c6cae9 100644 | |
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | |
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | |
@@ -10,7 +10,7 @@ | |
#include "bcm2835.h" | |
#include <soc/bcm2835/raspberrypi-firmware.h> | |
-static bool enable_hdmi, enable_hdmi0, enable_hdmi1; | |
+static bool enable_hdmi = true, enable_hdmi0, enable_hdmi1; | |
static bool enable_headphones = true; | |
static int num_channels = MAX_SUBSTREAMS; | |
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig | |
index 0e66152b02e6..c6a639adb819 100644 | |
--- a/drivers/video/backlight/Kconfig | |
+++ b/drivers/video/backlight/Kconfig | |
@@ -484,6 +484,12 @@ config BACKLIGHT_LED | |
If you have a LCD backlight adjustable by LED class driver, say Y | |
to enable this driver. | |
+config BACKLIGHT_OCP8178 | |
+ tristate "OCP8178 Backlight Driver" | |
+ depends on GPIOLIB | |
+ help | |
+ If you have an OCP8178, say Y to enable the backlight driver. | |
+ | |
endif # BACKLIGHT_CLASS_DEVICE | |
endmenu | |
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile | |
index ac878b4fb0ee..4d431321f1f2 100644 | |
--- a/drivers/video/backlight/Makefile | |
+++ b/drivers/video/backlight/Makefile | |
@@ -60,3 +60,4 @@ obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o | |
obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o | |
obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o | |
obj-$(CONFIG_BACKLIGHT_LED) += led_bl.o | |
+obj-$(CONFIG_BACKLIGHT_OCP8178) += ocp8178_bl.o | |
diff --git a/drivers/video/backlight/ocp8178_bl.c b/drivers/video/backlight/ocp8178_bl.c | |
new file mode 100644 | |
index 000000000000..db8db1771644 | |
--- /dev/null | |
+++ b/drivers/video/backlight/ocp8178_bl.c | |
@@ -0,0 +1,277 @@ | |
+/* | |
+ * ocp8178_bl.c - ocp8178 backlight driver | |
+ * | |
+ * This program is free software; you can redistribute it and/or modify | |
+ * it under the terms of the GNU General Public License version 2 as | |
+ * published by the Free Software Foundation. | |
+ */ | |
+ | |
+#include <linux/backlight.h> | |
+#include <linux/err.h> | |
+#include <linux/fb.h> | |
+#include <linux/gpio.h> /* Only for legacy support */ | |
+#include <linux/gpio/consumer.h> | |
+#include <linux/init.h> | |
+#include <linux/kernel.h> | |
+#include <linux/module.h> | |
+#include <linux/of.h> | |
+#include <linux/of_gpio.h> | |
+#include <linux/platform_data/gpio_backlight.h> | |
+#include <linux/platform_device.h> | |
+#include <linux/slab.h> | |
+#include <linux/delay.h> | |
+#include <linux/timer.h> | |
+#include <linux/poll.h> | |
+#include <linux/proc_fs.h> | |
+#include <linux/seq_file.h> | |
+#include <linux/sched.h> | |
+#include <linux/interrupt.h> | |
+#include <linux/irq.h> | |
+#include <linux/io.h> | |
+#include <linux/clk.h> | |
+ | |
+struct ocp8178_backlight { | |
+ struct device *dev; | |
+ struct device *fbdev; | |
+ | |
+ struct gpio_desc *gpiod; | |
+ int def_value; | |
+ int current_value; | |
+}; | |
+ | |
+#define DETECT_DELAY 200 | |
+#define DETECT_TIME 500 | |
+#define DETECT_WINDOW_TIME 1000 | |
+#define START_TIME 10 | |
+#define END_TIME 10 | |
+#define SHUTDOWN_TIME 3000 | |
+#define LOW_BIT_HIGH_TIME 10 | |
+#define LOW_BIT_LOW_TIME 50 | |
+#define HIGH_BIT_HIGH_TIME 50 | |
+#define HIGH_BIT_LOW_TIME 10 | |
+#define MAX_BRIGHTNESS_VALUE 9 | |
+ | |
+static void entry_1wire_mode(struct ocp8178_backlight *gbl) | |
+{ | |
+ unsigned long flags = 0; | |
+ local_irq_save(flags); | |
+ gpiod_set_value(gbl->gpiod, 0); | |
+ mdelay(SHUTDOWN_TIME/1000); | |
+ gpiod_set_value(gbl->gpiod, 1); | |
+ udelay(DETECT_DELAY); | |
+ gpiod_set_value(gbl->gpiod, 0); | |
+ udelay(DETECT_TIME); | |
+ gpiod_set_value(gbl->gpiod, 1); | |
+ udelay(DETECT_WINDOW_TIME); | |
+ local_irq_restore(flags); | |
+} | |
+ | |
+static inline void write_bit(struct ocp8178_backlight *gbl, int bit) | |
+{ | |
+ if (bit) { | |
+ gpiod_set_value(gbl->gpiod, 0); | |
+ udelay(HIGH_BIT_LOW_TIME); | |
+ gpiod_set_value(gbl->gpiod, 1); | |
+ udelay(HIGH_BIT_HIGH_TIME); | |
+ } else { | |
+ gpiod_set_value(gbl->gpiod, 0); | |
+ udelay(LOW_BIT_LOW_TIME); | |
+ gpiod_set_value(gbl->gpiod, 1); | |
+ udelay(LOW_BIT_HIGH_TIME); | |
+ } | |
+} | |
+ | |
+static void write_byte(struct ocp8178_backlight *gbl, int byte) | |
+{ | |
+ unsigned long flags = 0; | |
+ unsigned char data = 0x72; | |
+ int i; | |
+ | |
+ local_irq_save(flags); | |
+ | |
+ gpiod_set_value(gbl->gpiod, 1); | |
+ udelay(START_TIME); | |
+ for(i = 0; i < 8; i++) { | |
+ if(data & 0x80) { | |
+ write_bit(gbl, 1); | |
+ } else { | |
+ write_bit(gbl, 0); | |
+ } | |
+ data <<= 1; | |
+ } | |
+ gpiod_set_value(gbl->gpiod, 0); | |
+ udelay(END_TIME); | |
+ | |
+ data = byte & 0x1f; | |
+ | |
+ gpiod_set_value(gbl->gpiod, 1); | |
+ udelay(START_TIME); | |
+ for(i = 0; i < 8; i++) { | |
+ if(data & 0x80) { | |
+ write_bit(gbl, 1); | |
+ } else { | |
+ write_bit(gbl, 0); | |
+ } | |
+ data <<= 1; | |
+ } | |
+ gpiod_set_value(gbl->gpiod, 0); | |
+ udelay(END_TIME); | |
+ gpiod_set_value(gbl->gpiod, 1); | |
+ | |
+ local_irq_restore(flags); | |
+} | |
+ | |
+unsigned char ocp8178_bl_table[MAX_BRIGHTNESS_VALUE+1] = {0, 1, 4, 8, 12, 16, 20, 24, 28, 31}; | |
+ | |
+static int ocp8178_update_status(struct backlight_device *bl) | |
+{ | |
+ struct ocp8178_backlight *gbl = bl_get_data(bl); | |
+ int brightness = bl->props.brightness, i; | |
+ | |
+ if (bl->props.power != FB_BLANK_UNBLANK || | |
+ bl->props.fb_blank != FB_BLANK_UNBLANK || | |
+ bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) | |
+ brightness = 0; | |
+ | |
+ if(brightness > MAX_BRIGHTNESS_VALUE) | |
+ brightness = MAX_BRIGHTNESS_VALUE; | |
+ | |
+ for(i = 0; i < 2; i++) { | |
+ entry_1wire_mode(gbl); | |
+ write_byte(gbl, ocp8178_bl_table[brightness]); | |
+ } | |
+ gbl->current_value = brightness; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int ocp8178_get_brightness(struct backlight_device *bl) | |
+{ | |
+ struct ocp8178_backlight *gbl = bl_get_data(bl); | |
+ return gbl->current_value; | |
+} | |
+ | |
+static int ocp8178_check_fb(struct backlight_device *bl, | |
+ struct fb_info *info) | |
+{ | |
+ struct ocp8178_backlight *gbl = bl_get_data(bl); | |
+ return gbl->fbdev == NULL || gbl->fbdev == info->dev; | |
+} | |
+ | |
+static const struct backlight_ops ocp8178_backlight_ops = { | |
+ .options = BL_CORE_SUSPENDRESUME, | |
+ .update_status = ocp8178_update_status, | |
+ .get_brightness = ocp8178_get_brightness, | |
+ .check_fb = ocp8178_check_fb, | |
+}; | |
+ | |
+static int ocp8178_probe_dt(struct platform_device *pdev, | |
+ struct ocp8178_backlight *gbl) | |
+{ | |
+ struct device *dev = &pdev->dev; | |
+ struct device_node *np = dev->of_node; | |
+ enum gpiod_flags flags; | |
+ int ret = 0; | |
+ u32 value32; | |
+ | |
+ of_property_read_u32(np, "default-brightness", &value32); | |
+ if(value32 > MAX_BRIGHTNESS_VALUE) | |
+ gbl->def_value = MAX_BRIGHTNESS_VALUE; | |
+ else | |
+ gbl->def_value = value32; | |
+ flags = gbl->def_value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; | |
+ | |
+ gbl->gpiod = devm_gpiod_get(dev, "backlight-control", flags); | |
+ if (IS_ERR(gbl->gpiod)) { | |
+ ret = PTR_ERR(gbl->gpiod); | |
+ | |
+ if (ret != -EPROBE_DEFER) { | |
+ dev_err(dev, | |
+ "Error: The gpios parameter is missing or invalid.\n"); | |
+ } | |
+ } | |
+ | |
+ return ret; | |
+} | |
+ | |
+static struct backlight_device *backlight; | |
+ | |
+static int ocp8178_probe(struct platform_device *pdev) | |
+{ | |
+ struct backlight_properties props; | |
+ struct backlight_device *bl; | |
+ struct ocp8178_backlight *gbl; | |
+ struct device_node *np = pdev->dev.of_node; | |
+ int ret; | |
+ | |
+ if ( !np) { | |
+ dev_err(&pdev->dev, | |
+ "failed to find platform data or device tree node.\n"); | |
+ return -ENODEV; | |
+ } | |
+ | |
+ gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL); | |
+ if (gbl == NULL) | |
+ return -ENOMEM; | |
+ | |
+ gbl->dev = &pdev->dev; | |
+ | |
+ ret = ocp8178_probe_dt(pdev, gbl); | |
+ if (ret) | |
+ return ret; | |
+ | |
+ gbl->current_value = gbl->def_value; | |
+ | |
+ memset(&props, 0, sizeof(props)); | |
+ props.type = BACKLIGHT_RAW; | |
+ props.max_brightness = MAX_BRIGHTNESS_VALUE; | |
+ bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev), | |
+ &pdev->dev, gbl, &ocp8178_backlight_ops, | |
+ &props); | |
+ if (IS_ERR(bl)) { | |
+ dev_err(&pdev->dev, "failed to register backlight\n"); | |
+ return PTR_ERR(bl); | |
+ } | |
+ | |
+// entry_1wire_mode(gbl); | |
+ | |
+ bl->props.brightness = gbl->def_value; | |
+ backlight_update_status(bl); | |
+ | |
+ platform_set_drvdata(pdev, bl); | |
+ | |
+ backlight = bl; | |
+ return 0; | |
+} | |
+ | |
+static int ocp8178_suspend(struct platform_device *pdev, pm_message_t state) | |
+{ | |
+ return 0; | |
+} | |
+ | |
+static int ocp8178_resume(struct platform_device *pdev) | |
+{ | |
+ return 0; | |
+} | |
+ | |
+static struct of_device_id ocp8178_of_match[] = { | |
+ { .compatible = "ocp8178-backlight" }, | |
+ { /* sentinel */ } | |
+}; | |
+ | |
+MODULE_DEVICE_TABLE(of, ocp8178_of_match); | |
+ | |
+static struct platform_driver ocp8178_driver = { | |
+ .driver = { | |
+ .name = "ocp8178-backlight", | |
+ .of_match_table = of_match_ptr(ocp8178_of_match), | |
+ }, | |
+ .probe = ocp8178_probe, | |
+ .suspend = ocp8178_suspend, | |
+ .resume = ocp8178_resume, | |
+}; | |
+ | |
+module_platform_driver(ocp8178_driver); | |
+ | |
+MODULE_DESCRIPTION("OCP8178 Driver"); | |
+MODULE_LICENSE("GPL"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment