summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/hdmi/hdmi_connector.c')
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c172
1 files changed, 62 insertions, 110 deletions
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index a3b05ae52dae..26129bff2dd6 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -28,7 +28,7 @@ struct hdmi_connector {
};
#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
-static void hdmi_phy_reset(struct hdmi *hdmi)
+static void msm_hdmi_phy_reset(struct hdmi *hdmi)
{
unsigned int val;
@@ -81,114 +81,54 @@ static int gpio_config(struct hdmi *hdmi, bool on)
{
struct device *dev = &hdmi->pdev->dev;
const struct hdmi_platform_config *config = hdmi->config;
- int ret;
+ int ret, i;
if (on) {
- if (config->ddc_clk_gpio != -1) {
- ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
- if (ret) {
- dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
- "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
- goto error1;
- }
- gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
- }
-
- if (config->ddc_data_gpio != -1) {
- ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
- if (ret) {
- dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
- "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
- goto error2;
- }
- gpio_set_value_cansleep(config->ddc_data_gpio, 1);
- }
-
- ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
- if (ret) {
- dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
- "HDMI_HPD", config->hpd_gpio, ret);
- goto error3;
- }
- gpio_direction_input(config->hpd_gpio);
- gpio_set_value_cansleep(config->hpd_gpio, 1);
-
- if (config->mux_en_gpio != -1) {
- ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN");
- if (ret) {
- dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
- "HDMI_MUX_EN", config->mux_en_gpio, ret);
- goto error4;
- }
- gpio_set_value_cansleep(config->mux_en_gpio, 1);
- }
-
- if (config->mux_sel_gpio != -1) {
- ret = gpio_request(config->mux_sel_gpio, "HDMI_MUX_SEL");
- if (ret) {
- dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
- "HDMI_MUX_SEL", config->mux_sel_gpio, ret);
- goto error5;
+ for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
+ struct hdmi_gpio_data gpio = config->gpios[i];
+
+ if (gpio.num != -1) {
+ ret = gpio_request(gpio.num, gpio.label);
+ if (ret) {
+ dev_err(dev,
+ "'%s'(%d) gpio_request failed: %d\n",
+ gpio.label, gpio.num, ret);
+ goto err;
+ }
+
+ if (gpio.output) {
+ gpio_direction_output(gpio.num,
+ gpio.value);
+ } else {
+ gpio_direction_input(gpio.num);
+ gpio_set_value_cansleep(gpio.num,
+ gpio.value);
+ }
}
- gpio_set_value_cansleep(config->mux_sel_gpio, 0);
}
- if (config->mux_lpm_gpio != -1) {
- ret = gpio_request(config->mux_lpm_gpio,
- "HDMI_MUX_LPM");
- if (ret) {
- dev_err(dev,
- "'%s'(%d) gpio_request failed: %d\n",
- "HDMI_MUX_LPM",
- config->mux_lpm_gpio, ret);
- goto error6;
- }
- gpio_set_value_cansleep(config->mux_lpm_gpio, 1);
- }
DBG("gpio on");
} else {
- if (config->ddc_clk_gpio != -1)
- gpio_free(config->ddc_clk_gpio);
-
- if (config->ddc_data_gpio != -1)
- gpio_free(config->ddc_data_gpio);
+ for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
+ struct hdmi_gpio_data gpio = config->gpios[i];
- gpio_free(config->hpd_gpio);
+ if (gpio.output) {
+ int value = gpio.value ? 0 : 1;
- if (config->mux_en_gpio != -1) {
- gpio_set_value_cansleep(config->mux_en_gpio, 0);
- gpio_free(config->mux_en_gpio);
- }
+ gpio_set_value_cansleep(gpio.num, value);
+ }
- if (config->mux_sel_gpio != -1) {
- gpio_set_value_cansleep(config->mux_sel_gpio, 1);
- gpio_free(config->mux_sel_gpio);
- }
+ gpio_free(gpio.num);
+ };
- if (config->mux_lpm_gpio != -1) {
- gpio_set_value_cansleep(config->mux_lpm_gpio, 0);
- gpio_free(config->mux_lpm_gpio);
- }
DBG("gpio off");
}
return 0;
+err:
+ while (i--)
+ gpio_free(config->gpios[i].num);
-error6:
- if (config->mux_sel_gpio != -1)
- gpio_free(config->mux_sel_gpio);
-error5:
- if (config->mux_en_gpio != -1)
- gpio_free(config->mux_en_gpio);
-error4:
- gpio_free(config->hpd_gpio);
-error3:
- if (config->ddc_data_gpio != -1)
- gpio_free(config->ddc_data_gpio);
-error2:
- if (config->ddc_clk_gpio != -1)
- gpio_free(config->ddc_clk_gpio);
-error1:
return ret;
}
@@ -239,9 +179,9 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
}
}
- hdmi_set_mode(hdmi, false);
- hdmi_phy_reset(hdmi);
- hdmi_set_mode(hdmi, true);
+ msm_hdmi_set_mode(hdmi, false);
+ msm_hdmi_phy_reset(hdmi);
+ msm_hdmi_set_mode(hdmi, true);
hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
@@ -278,7 +218,7 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector)
/* Disable HPD interrupt */
hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
- hdmi_set_mode(hdmi, false);
+ msm_hdmi_set_mode(hdmi, false);
for (i = 0; i < config->hpd_clk_cnt; i++)
clk_disable_unprepare(hdmi->hpd_clks[i]);
@@ -300,7 +240,7 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector)
}
static void
-hotplug_work(struct work_struct *work)
+msm_hdmi_hotplug_work(struct work_struct *work)
{
struct hdmi_connector *hdmi_connector =
container_of(work, struct hdmi_connector, hpd_work);
@@ -308,7 +248,7 @@ hotplug_work(struct work_struct *work)
drm_helper_hpd_irq_event(connector->dev);
}
-void hdmi_connector_irq(struct drm_connector *connector)
+void msm_hdmi_connector_irq(struct drm_connector *connector)
{
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
struct hdmi *hdmi = hdmi_connector->hdmi;
@@ -345,10 +285,13 @@ static enum drm_connector_status detect_reg(struct hdmi *hdmi)
connector_status_connected : connector_status_disconnected;
}
+#define HPD_GPIO_INDEX 2
static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
{
const struct hdmi_platform_config *config = hdmi->config;
- return gpio_get_value(config->hpd_gpio) ?
+ struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
+
+ return gpio_get_value(hpd_gpio.num) ?
connector_status_connected :
connector_status_disconnected;
}
@@ -358,9 +301,18 @@ static enum drm_connector_status hdmi_connector_detect(
{
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
struct hdmi *hdmi = hdmi_connector->hdmi;
+ const struct hdmi_platform_config *config = hdmi->config;
+ struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
enum drm_connector_status stat_gpio, stat_reg;
int retry = 20;
+ /*
+ * some platforms may not have hpd gpio. Rely only on the status
+ * provided by REG_HDMI_HPD_INT_STATUS in this case.
+ */
+ if (hpd_gpio.num == -1)
+ return detect_reg(hdmi);
+
do {
stat_gpio = detect_gpio(hdmi);
stat_reg = detect_reg(hdmi);
@@ -395,7 +347,7 @@ static void hdmi_connector_destroy(struct drm_connector *connector)
kfree(hdmi_connector);
}
-static int hdmi_connector_get_modes(struct drm_connector *connector)
+static int msm_hdmi_connector_get_modes(struct drm_connector *connector)
{
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
struct hdmi *hdmi = hdmi_connector->hdmi;
@@ -421,7 +373,7 @@ static int hdmi_connector_get_modes(struct drm_connector *connector)
return ret;
}
-static int hdmi_connector_mode_valid(struct drm_connector *connector,
+static int msm_hdmi_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
@@ -451,7 +403,7 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
}
static struct drm_encoder *
-hdmi_connector_best_encoder(struct drm_connector *connector)
+msm_hdmi_connector_best_encoder(struct drm_connector *connector)
{
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
return hdmi_connector->hdmi->encoder;
@@ -467,14 +419,14 @@ static const struct drm_connector_funcs hdmi_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
-static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
- .get_modes = hdmi_connector_get_modes,
- .mode_valid = hdmi_connector_mode_valid,
- .best_encoder = hdmi_connector_best_encoder,
+static const struct drm_connector_helper_funcs msm_hdmi_connector_helper_funcs = {
+ .get_modes = msm_hdmi_connector_get_modes,
+ .mode_valid = msm_hdmi_connector_mode_valid,
+ .best_encoder = msm_hdmi_connector_best_encoder,
};
/* initialize connector */
-struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
+struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi)
{
struct drm_connector *connector = NULL;
struct hdmi_connector *hdmi_connector;
@@ -487,13 +439,13 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
}
hdmi_connector->hdmi = hdmi;
- INIT_WORK(&hdmi_connector->hpd_work, hotplug_work);
+ INIT_WORK(&hdmi_connector->hpd_work, msm_hdmi_hotplug_work);
connector = &hdmi_connector->base;
drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
- drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
+ drm_connector_helper_add(connector, &msm_hdmi_connector_helper_funcs);
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;