Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f34448c3 authored by Chandan Uddaraju's avatar Chandan Uddaraju Committed by Gerrit - the friendly Code Review server
Browse files

mdss: display-port: add support for DP related gpios



The DP driver will need GPIOs to configure the
AUX channel and orientation of USB type-C port. Add
support for the GPIOs.

Change-Id: I9940ff3cbcca7dd0ac972cabbfddcbd9ac4657fa
Signed-off-by: default avatarChandan Uddaraju <chandanu@codeaurora.org>
parent 48965d20
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ Required properties
- clocks:				List of Phandles for clock device nodes
					needed by the device.
- clock-names:				List of clock names needed by the device.
- qcom,aux-en-gpio:			Specifies the aux-channel enable gpio.
- qcom,aux-sel-gpio:			Specifies the aux-channel select gpio.
- qcom,usbplug-cc-gpio:			Specifies the usbplug orientation gpio.

Optional properties:
- qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the
@@ -42,6 +45,12 @@ Optional properties:
					-- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
					-- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
					-- qcom,supply-post-off-sleep: time to sleep (ms) after turning off
- qcom,hpd-gpio:			Specifies the HPD gpio.
- pinctrl-names:			List of names to assign mdss pin states defined in pinctrl device node
					Refer to pinctrl-bindings.txt
- pinctrl-<0..n>:			Lists phandles each pointing to the pin configuration node within a pin
					controller. These pin configurations are installed in the pinctrl
					device node. Refer to pinctrl-bindings.txt

Example:
	mdss_dp_ctrl: qcom,dp_ctrl@c990000 {
@@ -115,5 +124,15 @@ Example:
				qcom,supply-disable-load = <32>;
			};
		};

		pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
		pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active
				&mdss_dp_hpd_active>;
		pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend
				&mdss_dp_hpd_suspend>;
		qcom,aux-en-gpio = <&tlmm 77 0>;
		qcom,aux-sel-gpio = <&tlmm 78 0>;
		qcom,usbplug-cc-gpio = <&tlmm 38 0>;
		qcom,hpd-gpio = <&tlmm 34 0>;
	};
+232 −0
Original line number Diff line number Diff line
@@ -551,6 +551,218 @@ static int mdss_dp_regulator_init(struct platform_device *pdev,
	return rc;
}

static int mdss_dp_pinctrl_set_state(
	struct mdss_dp_drv_pdata *dp,
	bool active)
{
	struct pinctrl_state *pin_state;
	int rc = -EFAULT;

	if (IS_ERR_OR_NULL(dp->pin_res.pinctrl))
		return PTR_ERR(dp->pin_res.pinctrl);

	pin_state = active ? dp->pin_res.state_active
				: dp->pin_res.state_suspend;
	if (!IS_ERR_OR_NULL(pin_state)) {
		rc = pinctrl_select_state(dp->pin_res.pinctrl,
				pin_state);
		if (rc)
			pr_err("can not set %s pins\n",
			       active ? "mdss_dp_active"
			       : "mdss_dp_sleep");
	} else {
		pr_err("invalid '%s' pinstate\n",
		       active ? "mdss_dp_active"
		       : "mdss_dp_sleep");
	}
	return rc;
}

static int mdss_dp_pinctrl_init(struct platform_device *pdev,
			struct mdss_dp_drv_pdata *dp)
{
	dp->pin_res.pinctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR_OR_NULL(dp->pin_res.pinctrl)) {
		pr_err("failed to get pinctrl\n");
		return PTR_ERR(dp->pin_res.pinctrl);
	}

	dp->pin_res.state_active
		= pinctrl_lookup_state(dp->pin_res.pinctrl,
				"mdss_dp_active");
	if (IS_ERR_OR_NULL(dp->pin_res.state_active)) {
		pr_err("can not get dp active pinstate\n");
		return PTR_ERR(dp->pin_res.state_active);
	}

	dp->pin_res.state_suspend
		= pinctrl_lookup_state(dp->pin_res.pinctrl,
				"mdss_dp_sleep");
	if (IS_ERR_OR_NULL(dp->pin_res.state_suspend)) {
		pr_err("can not get dp sleep pinstate\n");
		return PTR_ERR(dp->pin_res.state_suspend);
	}

	return 0;
}

static int mdss_dp_request_gpios(struct mdss_dp_drv_pdata *dp)
{
	int rc = 0;
	struct device *dev = NULL;

	if (!dp) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	dev = &dp->pdev->dev;
	if (gpio_is_valid(dp->aux_en_gpio)) {
		rc = devm_gpio_request(dev, dp->aux_en_gpio,
						"aux_enable");
		if (rc) {
			pr_err("request aux_en gpio failed, rc=%d\n",
				       rc);
			goto aux_en_gpio_err;
		}
	}
	if (gpio_is_valid(dp->aux_sel_gpio)) {
		rc = devm_gpio_request(dev, dp->aux_sel_gpio, "aux_sel");
		if (rc) {
			pr_err("request aux_sel gpio failed, rc=%d\n",
				rc);
			goto aux_sel_gpio_err;
		}
	}
	if (gpio_is_valid(dp->usbplug_cc_gpio)) {
		rc = devm_gpio_request(dev, dp->usbplug_cc_gpio,
						"usbplug_cc");
		if (rc) {
			pr_err("request usbplug_cc gpio failed, rc=%d\n",
				rc);
			goto usbplug_cc_gpio_err;
		}
	}
	if (gpio_is_valid(dp->hpd_gpio)) {
		rc = devm_gpio_request(dev, dp->hpd_gpio, "hpd");
		if (rc) {
			pr_err("request hpd gpio failed, rc=%d\n",
				rc);
			goto hpd_gpio_err;
		}
	}
	return rc;

hpd_gpio_err:
	if (gpio_is_valid(dp->usbplug_cc_gpio))
		gpio_free(dp->usbplug_cc_gpio);
usbplug_cc_gpio_err:
	if (gpio_is_valid(dp->aux_sel_gpio))
		gpio_free(dp->aux_sel_gpio);
aux_sel_gpio_err:
	if (gpio_is_valid(dp->aux_en_gpio))
		gpio_free(dp->aux_en_gpio);
aux_en_gpio_err:
	return rc;
}

static int mdss_dp_config_gpios(struct mdss_dp_drv_pdata *dp, bool enable)
{
	int rc = 0;

	if (enable == true) {
		rc = mdss_dp_request_gpios(dp);
		if (rc) {
			pr_err("gpio request failed\n");
			return rc;
		}

		if (gpio_is_valid(dp->aux_en_gpio)) {
			rc = gpio_direction_output(
				dp->aux_en_gpio, 0);
			if (rc)
				pr_err("unable to set dir for aux_en gpio\n");
		}
		if (gpio_is_valid(dp->aux_sel_gpio)) {
			rc = gpio_direction_output(
				dp->aux_sel_gpio, 0);
			if (rc)
				pr_err("unable to set dir for aux_sel gpio\n");
		}
		if (gpio_is_valid(dp->usbplug_cc_gpio)) {
			gpio_set_value(
				dp->usbplug_cc_gpio, 0);
		}
		if (gpio_is_valid(dp->hpd_gpio)) {
			gpio_set_value(
				dp->hpd_gpio, 1);
		}
	} else {
		if (gpio_is_valid(dp->aux_en_gpio)) {
			gpio_set_value((dp->aux_en_gpio), 0);
			gpio_free(dp->aux_en_gpio);
		}
		if (gpio_is_valid(dp->aux_sel_gpio)) {
			gpio_set_value((dp->aux_sel_gpio), 0);
			gpio_free(dp->aux_sel_gpio);
		}
		if (gpio_is_valid(dp->usbplug_cc_gpio)) {
			gpio_set_value((dp->usbplug_cc_gpio), 0);
			gpio_free(dp->usbplug_cc_gpio);
		}
		if (gpio_is_valid(dp->hpd_gpio)) {
			gpio_set_value((dp->hpd_gpio), 0);
			gpio_free(dp->hpd_gpio);
		}
	}
	return 0;
}

static int mdss_dp_parse_gpio_params(struct platform_device *pdev,
	struct mdss_dp_drv_pdata *dp)
{
	dp->aux_en_gpio = of_get_named_gpio(
			pdev->dev.of_node,
			"qcom,aux-en-gpio", 0);

	if (!gpio_is_valid(dp->aux_en_gpio)) {
		pr_err("%d, Aux_en gpio not specified\n",
					__LINE__);
		return -EINVAL;
	}

	dp->aux_sel_gpio = of_get_named_gpio(
			pdev->dev.of_node,
			"qcom,aux-sel-gpio", 0);

	if (!gpio_is_valid(dp->aux_sel_gpio)) {
		pr_err("%d, Aux_sel gpio not specified\n",
					__LINE__);
		return -EINVAL;
	}

	dp->usbplug_cc_gpio = of_get_named_gpio(
			pdev->dev.of_node,
			"qcom,usbplug-cc-gpio", 0);

	if (!gpio_is_valid(dp->usbplug_cc_gpio)) {
		pr_err("%d,usbplug_cc gpio not specified\n",
					__LINE__);
		return -EINVAL;
	}

	dp->hpd_gpio = of_get_named_gpio(
			pdev->dev.of_node,
			"qcom,hpd-gpio", 0);

	if (!gpio_is_valid(dp->hpd_gpio)) {
		pr_info("%d,hpd gpio not specified\n",
					__LINE__);
	}

	return 0;
}

void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp)
{
	/*
@@ -759,6 +971,9 @@ int mdss_dp_off(struct mdss_panel_data *pdata)
	mdss_dp_mainlink_reset(&dp_drv->ctrl_io);
	mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false);

	mdss_dp_config_gpios(dp_drv, false);
	mdss_dp_pinctrl_set_state(dp_drv, false);

	mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false);
	mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, false);
	mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false);
@@ -791,6 +1006,9 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
		goto vreg_error;
	}

	mdss_dp_pinctrl_set_state(dp_drv, true);
	mdss_dp_config_gpios(dp_drv, true);

	ret = mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, true);
	if (ret) {
		pr_err("Unabled to start core clocks\n");
@@ -1166,6 +1384,20 @@ static int mdss_dp_probe(struct platform_device *pdev)

	platform_set_drvdata(pdev, dp_drv);

	ret = mdss_dp_pinctrl_init(pdev, dp_drv);
	if (ret) {
		pr_err("pinctrl init failed, ret=%d\n",
						ret);
		goto probe_err;
	}

	ret = mdss_dp_parse_gpio_params(pdev, dp_drv);
	if (ret) {
		pr_err("failed to parse gpio params, ret=%d\n",
						ret);
		goto probe_err;
	}

	mdss_dp_device_register(dp_drv);

	dp_drv->inited = true;
+12 −0
Original line number Diff line number Diff line
@@ -258,6 +258,13 @@ struct dp_statistic {
#define DPCD_LINK_VOLTAGE_MAX	4
#define DPCD_LINK_PRE_EMPHASIS_MAX	4

struct dp_pinctrl_res {
	struct pinctrl *pinctrl;
	struct pinctrl_state *state_active;
	struct pinctrl_state *state_hpd_active;
	struct pinctrl_state *state_suspend;
};

irqreturn_t dp_isr(int irq, void *ptr);

struct mdss_dp_drv_pdata {
@@ -302,6 +309,11 @@ struct mdss_dp_drv_pdata {

	/* regulators */
	struct dss_module_power power_data[DP_MAX_PM];
	struct dp_pinctrl_res pin_res;
	int aux_sel_gpio;
	int aux_en_gpio;
	int usbplug_cc_gpio;
	int hpd_gpio;
	int clk_on;

	/* hpd */