drm: msm: dsi-staging: add support for LCD mode select GPIO

Certian DSI panels support both single/dual port modes based on
whether it is configured in split DSI or single DSI mode with
DSC enabled. The LCD mode select GPIO is needed to configure the
panel accordingly. Add support for this GPIO.

CRs-Fixed: 2008002
Change-Id: Ib96143d08ffb395f6fa6acd9e14d213b2bd32cae
Signed-off-by: Padmanabhan Komanduru <pkomandu@codeaurora.org>
Signed-off-by: Shashank Babu Chinta Venkata <sbchin@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index b9052ec..87c7dca 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -91,7 +91,18 @@
 		}
 	}
 
+	if (gpio_is_valid(r_config->lcd_mode_sel_gpio)) {
+		rc = gpio_request(r_config->lcd_mode_sel_gpio, "mode_gpio");
+		if (rc) {
+			pr_err("request for mode_gpio failed, rc=%d\n", rc);
+			goto error_release_mode_sel;
+		}
+	}
+
 	goto error;
+error_release_mode_sel:
+	if (gpio_is_valid(panel->bl_config.en_gpio))
+		gpio_free(panel->bl_config.en_gpio);
 error_release_disp_en:
 	if (gpio_is_valid(r_config->disp_en_gpio))
 		gpio_free(r_config->disp_en_gpio);
@@ -116,6 +127,9 @@
 	if (gpio_is_valid(panel->bl_config.en_gpio))
 		gpio_free(panel->bl_config.en_gpio);
 
+	if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio))
+		gpio_free(panel->reset_config.lcd_mode_sel_gpio);
+
 	return rc;
 }
 
@@ -157,6 +171,25 @@
 		if (rc)
 			pr_err("unable to set dir for bklt gpio rc=%d\n", rc);
 	}
+
+	if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) {
+		bool out = true;
+
+		if ((panel->reset_config.mode_sel_state == MODE_SEL_DUAL_PORT)
+				|| (panel->reset_config.mode_sel_state
+					== MODE_GPIO_LOW))
+			out = false;
+		else if ((panel->reset_config.mode_sel_state
+				== MODE_SEL_SINGLE_PORT) ||
+				(panel->reset_config.mode_sel_state
+				 == MODE_GPIO_HIGH))
+			out = true;
+
+		rc = gpio_direction_output(
+			panel->reset_config.lcd_mode_sel_gpio, out);
+		if (rc)
+			pr_err("unable to set dir for mode gpio rc=%d\n", rc);
+	}
 exit:
 	return rc;
 }
@@ -230,6 +263,9 @@
 	if (gpio_is_valid(panel->reset_config.reset_gpio))
 		gpio_set_value(panel->reset_config.reset_gpio, 0);
 
+	if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio))
+		gpio_set_value(panel->reset_config.lcd_mode_sel_gpio, 0);
+
 	rc = dsi_panel_set_pinctrl_state(panel, false);
 	if (rc) {
 		pr_err("[%s] failed set pinctrl state, rc=%d\n", panel->name,
@@ -1347,6 +1383,7 @@
 				 struct device_node *of_node)
 {
 	int rc = 0;
+	const char *data;
 
 	panel->reset_config.reset_gpio = of_get_named_gpio(of_node,
 					      "qcom,platform-reset-gpio",
@@ -1372,6 +1409,31 @@
 		}
 	}
 
+	panel->reset_config.lcd_mode_sel_gpio = of_get_named_gpio(of_node,
+		"qcom,panel-mode-gpio", 0);
+	if (!gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio))
+		pr_debug("%s:%d mode gpio not specified\n", __func__, __LINE__);
+
+	data = of_get_property(of_node,
+		"qcom,mdss-dsi-mode-sel-gpio-state", NULL);
+	if (data) {
+		if (!strcmp(data, "single_port"))
+			panel->reset_config.mode_sel_state =
+				MODE_SEL_SINGLE_PORT;
+		else if (!strcmp(data, "dual_port"))
+			panel->reset_config.mode_sel_state =
+				MODE_SEL_DUAL_PORT;
+		else if (!strcmp(data, "high"))
+			panel->reset_config.mode_sel_state =
+				MODE_GPIO_HIGH;
+		else if (!strcmp(data, "low"))
+			panel->reset_config.mode_sel_state =
+				MODE_GPIO_LOW;
+	} else {
+		/* Set default mode as SPLIT mode */
+		panel->reset_config.mode_sel_state = MODE_SEL_DUAL_PORT;
+	}
+
 	/* TODO:  release memory */
 	rc = dsi_panel_parse_reset_sequence(panel, of_node);
 	if (rc) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 1bf8787..de79dc7 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -69,6 +69,14 @@
 	DSI_BACKLIGHT_MAX,
 };
 
+enum {
+	MODE_GPIO_NOT_VALID = 0,
+	MODE_SEL_DUAL_PORT,
+	MODE_SEL_SINGLE_PORT,
+	MODE_GPIO_HIGH,
+	MODE_GPIO_LOW,
+};
+
 struct dsi_dfps_capabilities {
 	bool dfps_support;
 	enum dsi_dfps_type type;
@@ -131,6 +139,8 @@
 
 	int reset_gpio;
 	int disp_en_gpio;
+	int lcd_mode_sel_gpio;
+	u32 mode_sel_state;
 };
 
 struct dsi_panel {