Commit a44769b4 authored by Linus Walleij's avatar Linus Walleij Committed by Rob Clark

drm/msm/hdmi: Convert to use GPIO descriptors

This switches the MSM HDMI code to use GPIO descriptors.
Normally we would fetch the GPIOs from the device with the
flags GPIOD_IN or GPIOD_OUT_[LOW|HIGH] to set up the lines
immediately, but since the code seems eager to actively
drive the lines high/low when turning HDMI on and off, we
just fetch the GPIOs as-is and keep the code explicitly
driving them.

The old code would try legacy bindings (GPIOs without any
"-gpios" suffix) but this has been moved to the gpiolib
as a quirk by the previous patch.

Cc: Rob Clark <robdclark@gmail.com>
Cc: Sean Paul <sean@poorly.run>
Cc: linux-arm-msm@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 86fe3f54
...@@ -425,38 +425,6 @@ static const struct { ...@@ -425,38 +425,6 @@ static const struct {
{ "qcom,hdmi-tx-mux-lpm", true, 1, "HDMI_MUX_LPM" }, { "qcom,hdmi-tx-mux-lpm", true, 1, "HDMI_MUX_LPM" },
}; };
static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name)
{
int gpio;
/* try with the gpio names as in the table (downstream bindings) */
gpio = of_get_named_gpio(of_node, name, 0);
if (gpio < 0) {
char name2[32];
/* try with the gpio names as in the upstream bindings */
snprintf(name2, sizeof(name2), "%s-gpios", name);
gpio = of_get_named_gpio(of_node, name2, 0);
if (gpio < 0) {
char name3[32];
/*
* try again after stripping out the "qcom,hdmi-tx"
* prefix. This is mainly to match "hpd-gpios" used
* in the upstream bindings
*/
if (sscanf(name2, "qcom,hdmi-tx-%s", name3))
gpio = of_get_named_gpio(of_node, name3, 0);
}
if (gpio < 0) {
DBG("failed to get gpio: %s (%d)", name, gpio);
gpio = -1;
}
}
return gpio;
}
/* /*
* HDMI audio codec callbacks * HDMI audio codec callbacks
*/ */
...@@ -582,11 +550,39 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -582,11 +550,39 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
hdmi_cfg->qfprom_mmio_name = "qfprom_physical"; hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
hdmi_cfg->gpios[i].num = msm_hdmi_get_gpio(of_node, const char *name = msm_hdmi_gpio_pdata[i].name;
msm_hdmi_gpio_pdata[i].name); struct gpio_desc *gpiod;
/*
* We are fetching the GPIO lines "as is" since the connector
* code is enabling and disabling the lines. Until that point
* the power-on default value will be kept.
*/
gpiod = devm_gpiod_get_optional(dev, name, GPIOD_ASIS);
/* This will catch e.g. -PROBE_DEFER */
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
if (!gpiod) {
/* Try a second time, stripping down the name */
char name3[32];
/*
* Try again after stripping out the "qcom,hdmi-tx"
* prefix. This is mainly to match "hpd-gpios" used
* in the upstream bindings.
*/
if (sscanf(name, "qcom,hdmi-tx-%s", name3))
gpiod = devm_gpiod_get_optional(dev, name3, GPIOD_ASIS);
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
if (!gpiod)
DBG("failed to get gpio: %s", name);
}
hdmi_cfg->gpios[i].gpiod = gpiod;
if (gpiod)
gpiod_set_consumer_name(gpiod, msm_hdmi_gpio_pdata[i].label);
hdmi_cfg->gpios[i].output = msm_hdmi_gpio_pdata[i].output; hdmi_cfg->gpios[i].output = msm_hdmi_gpio_pdata[i].output;
hdmi_cfg->gpios[i].value = msm_hdmi_gpio_pdata[i].value; hdmi_cfg->gpios[i].value = msm_hdmi_gpio_pdata[i].value;
hdmi_cfg->gpios[i].label = msm_hdmi_gpio_pdata[i].label;
} }
dev->platform_data = hdmi_cfg; dev->platform_data = hdmi_cfg;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include "msm_drv.h" #include "msm_drv.h"
...@@ -22,10 +23,9 @@ struct hdmi_phy; ...@@ -22,10 +23,9 @@ struct hdmi_phy;
struct hdmi_platform_config; struct hdmi_platform_config;
struct hdmi_gpio_data { struct hdmi_gpio_data {
int num; struct gpio_desc *gpiod;
bool output; bool output;
int value; int value;
const char *label;
}; };
struct hdmi_audio { struct hdmi_audio {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include "msm_kms.h" #include "msm_kms.h"
...@@ -69,30 +69,21 @@ static void msm_hdmi_phy_reset(struct hdmi *hdmi) ...@@ -69,30 +69,21 @@ static void msm_hdmi_phy_reset(struct hdmi *hdmi)
static int gpio_config(struct hdmi *hdmi, bool on) static int gpio_config(struct hdmi *hdmi, bool on)
{ {
struct device *dev = &hdmi->pdev->dev;
const struct hdmi_platform_config *config = hdmi->config; const struct hdmi_platform_config *config = hdmi->config;
int ret, i; int i;
if (on) { if (on) {
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i]; struct hdmi_gpio_data gpio = config->gpios[i];
if (gpio.num != -1) { if (gpio.gpiod) {
ret = gpio_request(gpio.num, gpio.label);
if (ret) {
DRM_DEV_ERROR(dev,
"'%s'(%d) gpio_request failed: %d\n",
gpio.label, gpio.num, ret);
goto err;
}
if (gpio.output) { if (gpio.output) {
gpio_direction_output(gpio.num, gpiod_direction_output(gpio.gpiod,
gpio.value); gpio.value);
} else { } else {
gpio_direction_input(gpio.num); gpiod_direction_input(gpio.gpiod);
gpio_set_value_cansleep(gpio.num, gpiod_set_value_cansleep(gpio.gpiod,
gpio.value); gpio.value);
} }
} }
} }
...@@ -102,29 +93,20 @@ static int gpio_config(struct hdmi *hdmi, bool on) ...@@ -102,29 +93,20 @@ static int gpio_config(struct hdmi *hdmi, bool on)
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i]; struct hdmi_gpio_data gpio = config->gpios[i];
if (gpio.num == -1) if (!gpio.gpiod)
continue; continue;
if (gpio.output) { if (gpio.output) {
int value = gpio.value ? 0 : 1; int value = gpio.value ? 0 : 1;
gpio_set_value_cansleep(gpio.num, value); gpiod_set_value_cansleep(gpio.gpiod, value);
} }
gpio_free(gpio.num);
}; };
DBG("gpio off"); DBG("gpio off");
} }
return 0; return 0;
err:
while (i--) {
if (config->gpios[i].num != -1)
gpio_free(config->gpios[i].num);
}
return ret;
} }
static void enable_hpd_clocks(struct hdmi *hdmi, bool enable) static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
...@@ -312,7 +294,7 @@ static enum drm_connector_status detect_gpio(struct hdmi *hdmi) ...@@ -312,7 +294,7 @@ static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
const struct hdmi_platform_config *config = hdmi->config; const struct hdmi_platform_config *config = hdmi->config;
struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX]; struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
return gpio_get_value(hpd_gpio.num) ? return gpiod_get_value(hpd_gpio.gpiod) ?
connector_status_connected : connector_status_connected :
connector_status_disconnected; connector_status_disconnected;
} }
...@@ -331,7 +313,7 @@ static enum drm_connector_status hdmi_connector_detect( ...@@ -331,7 +313,7 @@ static enum drm_connector_status hdmi_connector_detect(
* some platforms may not have hpd gpio. Rely only on the status * some platforms may not have hpd gpio. Rely only on the status
* provided by REG_HDMI_HPD_INT_STATUS in this case. * provided by REG_HDMI_HPD_INT_STATUS in this case.
*/ */
if (hpd_gpio.num == -1) if (!hpd_gpio.gpiod)
return detect_reg(hdmi); return detect_reg(hdmi);
do { do {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment