Merge "drm:msm:dsi: support additional gpios in display panel"
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 1a29b0e..e2584cd 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -252,6 +252,103 @@
return rc;
}
+static int dsi_panel_exd_gpio_request(struct dsi_panel *panel)
+{
+ int rc = 0;
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return 0;
+
+ if (gpio_is_valid(e_config->display_1p8_en)) {
+ rc = gpio_request(e_config->display_1p8_en, "display_1p8_en");
+ if (rc) {
+ pr_err("request for display_1p8_en failed, rc=%d\n",
+ rc);
+ goto error;
+ }
+ }
+
+ if (gpio_is_valid(e_config->led_5v_en)) {
+ rc = gpio_request(e_config->led_5v_en, "led_5v_en");
+ if (rc) {
+ pr_err("request for led_5v_en failed, rc=%d\n",
+ rc);
+ goto error_release_1p8;
+ }
+ }
+
+ if (gpio_is_valid(e_config->led_en1)) {
+ rc = gpio_request(e_config->led_en1, "led_en1");
+ if (rc) {
+ pr_err("request for led_en1 failed, rc=%d\n",
+ rc);
+ goto error_release_5v;
+ }
+ }
+
+ if (gpio_is_valid(e_config->led_en2)) {
+ rc = gpio_request(e_config->led_en2, "led_en2");
+ if (rc) {
+ pr_err("request for led_en2 failed, rc=%d\n",
+ rc);
+ goto error_release_led;
+ }
+ }
+
+ if (gpio_is_valid(e_config->oenab)) {
+ rc = gpio_request(e_config->oenab, "oenab");
+ if (rc) {
+ pr_err("request for oenab failed, rc=%d\n",
+ rc);
+ goto error_release_led2;
+ }
+ }
+
+ if (gpio_is_valid(e_config->selab)) {
+ rc = gpio_request(e_config->selab, "selab");
+ if (rc) {
+ pr_err("request for selab failed, rc=%d\n",
+ rc);
+ goto error_release_oenab;
+ }
+ }
+
+ if (gpio_is_valid(e_config->switch_power)) {
+ rc = gpio_request(e_config->switch_power, "switch_power");
+ if (rc) {
+ pr_err("request for switch_power failed, rc=%d\n",
+ rc);
+ goto error_release_selab;
+ }
+ }
+ return rc;
+
+error_release_selab:
+ if (gpio_is_valid(e_config->selab))
+ gpio_free(e_config->selab);
+error_release_oenab:
+ if (gpio_is_valid(e_config->oenab))
+ gpio_free(e_config->oenab);
+error_release_led2:
+ if (gpio_is_valid(e_config->led_en2))
+ gpio_free(e_config->led_en2);
+error_release_led:
+ if (gpio_is_valid(e_config->led_en1))
+ gpio_free(e_config->led_en1);
+error_release_5v:
+ if (gpio_is_valid(e_config->led_5v_en))
+ gpio_free(e_config->led_5v_en);
+error_release_1p8:
+ if (gpio_is_valid(e_config->display_1p8_en))
+ gpio_free(e_config->display_1p8_en);
+error:
+ return rc;
+}
+
static int dsi_panel_gpio_request(struct dsi_panel *panel)
{
int rc = 0;
@@ -303,6 +400,34 @@
return rc;
}
+static int dsi_panel_exd_gpio_release(struct dsi_panel *panel)
+{
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return 0;
+
+ if (gpio_is_valid(e_config->display_1p8_en))
+ gpio_free(e_config->display_1p8_en);
+ if (gpio_is_valid(e_config->led_5v_en))
+ gpio_free(e_config->led_5v_en);
+ if (gpio_is_valid(e_config->led_en1))
+ gpio_free(e_config->led_en1);
+ if (gpio_is_valid(e_config->led_en2))
+ gpio_free(e_config->led_en2);
+ if (gpio_is_valid(e_config->oenab))
+ gpio_free(e_config->oenab);
+ if (gpio_is_valid(e_config->selab))
+ gpio_free(e_config->selab);
+ if (gpio_is_valid(e_config->switch_power))
+ gpio_free(e_config->switch_power);
+
+ return 0;
+}
+
static int dsi_panel_gpio_release(struct dsi_panel *panel)
{
int rc = 0;
@@ -426,6 +551,110 @@
return rc;
}
+static int dsi_panel_exd_enable(struct dsi_panel *panel)
+{
+ int rc = 0;
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return 0;
+
+ if (gpio_is_valid(e_config->display_1p8_en)) {
+ rc = gpio_direction_output(e_config->display_1p8_en, 0);
+ if (rc) {
+ pr_err("unable to set dir for disp_1p8_en rc:%d\n",
+ rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->display_1p8_en, 1);
+ }
+
+ if (gpio_is_valid(e_config->switch_power)) {
+ rc = gpio_direction_output(e_config->switch_power, 0);
+ if (rc) {
+ pr_err("unable to set dir for switch_power rc:%d\n",
+ rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->switch_power, 1);
+ }
+
+ if (gpio_is_valid(e_config->led_5v_en)) {
+ rc = gpio_direction_output(e_config->led_5v_en, 0);
+ if (rc) {
+ pr_err("unable to set dir for led_5v_en rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->led_5v_en, 1);
+ }
+
+ if (gpio_is_valid(e_config->led_en1)) {
+ rc = gpio_direction_output(e_config->led_en1, 0);
+ if (rc) {
+ pr_err("unable to set dir for led_en1 rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->led_en1, 1);
+ }
+
+ if (gpio_is_valid(e_config->led_en2)) {
+ rc = gpio_direction_output(e_config->led_en2, 0);
+ if (rc) {
+ pr_err("unable to set dir for led_en2 rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->led_en2, 1);
+ }
+
+ if (gpio_is_valid(e_config->oenab)) {
+ rc = gpio_direction_output(e_config->oenab, 0);
+ if (rc) {
+ pr_err("unable to set dir for oenab rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->oenab, 0);
+ }
+
+ if (gpio_is_valid(e_config->selab)) {
+ rc = gpio_direction_output(e_config->selab, 0);
+ if (rc) {
+ pr_err("unable to set dir for selab rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->selab, 1);
+ }
+exit:
+ return rc;
+}
+
+static void dsi_panel_exd_disable(struct dsi_panel *panel)
+{
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return;
+
+ if (gpio_is_valid(e_config->display_1p8_en))
+ gpio_set_value(e_config->display_1p8_en, 0);
+ if (gpio_is_valid(e_config->led_5v_en))
+ gpio_set_value(e_config->led_5v_en, 0);
+ if (gpio_is_valid(e_config->led_en1))
+ gpio_set_value(e_config->led_en1, 0);
+ if (gpio_is_valid(e_config->led_en2))
+ gpio_set_value(e_config->led_en2, 0);
+ if (gpio_is_valid(e_config->oenab))
+ gpio_set_value(e_config->oenab, 1);
+ if (gpio_is_valid(e_config->selab))
+ gpio_set_value(e_config->selab, 0);
+ if (gpio_is_valid(e_config->switch_power))
+ gpio_set_value(e_config->switch_power, 0);
+}
static int dsi_panel_power_on(struct dsi_panel *panel)
{
@@ -449,6 +678,13 @@
goto error_disable_gpio;
}
+ rc = dsi_panel_exd_enable(panel);
+ if (rc) {
+ pr_err("[%s] failed to reset panel, rc=%d\n", panel->name, rc);
+ dsi_panel_exd_disable(panel);
+ goto error_disable_gpio;
+ }
+
goto exit;
error_disable_gpio:
@@ -471,6 +707,8 @@
{
int rc = 0;
+ dsi_panel_exd_disable(panel);
+
if (gpio_is_valid(panel->reset_config.disp_en_gpio))
gpio_set_value(panel->reset_config.disp_en_gpio, 0);
@@ -1887,6 +2125,63 @@
return rc;
}
+static int dsi_panel_exd_parse_gpios(struct dsi_panel *panel,
+ struct device_node *of_node)
+{
+ int rc = 0;
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ e_config->display_1p8_en = of_get_named_gpio(of_node,
+ "qcom,1p8-en-gpio", 0);
+ if (!e_config->display_1p8_en) {
+ pr_debug("%s qcom,display-1p8-en-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->led_5v_en = of_get_named_gpio(of_node,
+ "qcom,led-5v-en-gpio", 0);
+ if (!e_config->led_5v_en) {
+ pr_debug("%s qcom,led-5v-en-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->led_en1 = of_get_named_gpio(of_node,
+ "qcom,led-driver-en1-gpio", 0);
+ if (!e_config->led_en1) {
+ pr_debug("%s qcom,led-driver-en1-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->led_en2 = of_get_named_gpio(of_node,
+ "qcom,led-driver-en2-gpio", 0);
+ if (!e_config->led_en2) {
+ pr_debug("%s qcom,led-driver-en2-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->oenab = of_get_named_gpio(of_node,
+ "qcom,oenab-gpio", 0);
+ if (!e_config->oenab) {
+ pr_debug("%s qcom,oenab-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->selab = of_get_named_gpio(of_node,
+ "qcom,selab-gpio", 0);
+ if (!e_config->selab) {
+ pr_debug("%s qcom,selab-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->switch_power = of_get_named_gpio(of_node,
+ "qcom,switch-power-gpio", 0);
+ if (!e_config->switch_power) {
+ pr_debug("%s qcom,switch_power not found\n", __func__);
+ return -EINVAL;
+ }
+ return rc;
+}
+
static int dsi_panel_parse_gpios(struct dsi_panel *panel,
struct device_node *of_node)
{
@@ -1942,6 +2237,12 @@
panel->reset_config.mode_sel_state = MODE_SEL_DUAL_PORT;
}
+ /* Extended display panel gpios parsed */
+ rc = dsi_panel_exd_parse_gpios(panel, of_node);
+ if (rc && rc != -EINVAL)
+ pr_err("[%s] failed to parse gpios, rc=%d\n",
+ panel->name, rc);
+
/* TODO: release memory */
rc = dsi_panel_parse_reset_sequence(panel, of_node);
if (rc) {
@@ -3105,8 +3406,17 @@
goto error_gpio_release;
}
+ rc = dsi_panel_exd_gpio_request(panel);
+ if (rc) {
+ pr_err("[%s] failed to request gpios, rc=%d\n", panel->name,
+ rc);
+ goto error_exd_gpio_release;
+ }
+
goto exit;
+error_exd_gpio_release:
+ (void)dsi_panel_exd_gpio_release(panel);
error_gpio_release:
(void)dsi_panel_gpio_release(panel);
error_pinctrl_deinit:
@@ -3142,6 +3452,11 @@
pr_err("[%s] failed to release gpios, rc=%d\n", panel->name,
rc);
+ rc = dsi_panel_exd_gpio_release(panel);
+ if (rc)
+ pr_err("[%s] failed to release gpios, rc=%d\n", panel->name,
+ rc);
+
rc = dsi_panel_pinctrl_deinit(panel);
if (rc)
pr_err("[%s] failed to deinit gpios, rc=%d\n", panel->name,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index ab8ccee..8702375 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -161,6 +161,17 @@
DSI_PANEL_TYPE_MAX,
};
+/* Extended Panel config for panels with additional gpios */
+struct dsi_panel_exd_config {
+ int display_1p8_en;
+ int led_5v_en;
+ int switch_power;
+ int led_en1;
+ int led_en2;
+ int oenab;
+ int selab;
+};
+
struct dsi_panel {
const char *name;
enum dsi_panel_type type;
@@ -204,6 +215,8 @@
enum dsi_dms_mode dms_mode;
bool sync_broadcast_en;
+
+ struct dsi_panel_exd_config exd_config;
};
static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel)