Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: sun4i: Add support for enabling DDC I2C bus to sun8i_dw_hdmi glue

Orange Pi 3 board requires enabling a voltage shifting circuit via GPIO
for the DDC bus to be usable.

Add support for hdmi-connector node's optional ddc-en-gpios property to
support this use case.

Signed-off-by: Ondrej Jirman <megous@megous.com>
Reviewed-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20190806155744.10263-4-megous@megous.com

authored by

Ondrej Jirman and committed by
Maxime Ripard
4c8b4c38 f6700060

+52 -4
+50 -4
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
··· 97 97 return crtcs; 98 98 } 99 99 100 + static int sun8i_dw_hdmi_find_connector_pdev(struct device *dev, 101 + struct platform_device **pdev_out) 102 + { 103 + struct platform_device *pdev; 104 + struct device_node *remote; 105 + 106 + remote = of_graph_get_remote_node(dev->of_node, 1, -1); 107 + if (!remote) 108 + return -ENODEV; 109 + 110 + if (!of_device_is_compatible(remote, "hdmi-connector")) { 111 + of_node_put(remote); 112 + return -ENODEV; 113 + } 114 + 115 + pdev = of_find_device_by_node(remote); 116 + of_node_put(remote); 117 + if (!pdev) 118 + return -ENODEV; 119 + 120 + *pdev_out = pdev; 121 + return 0; 122 + } 123 + 100 124 static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, 101 125 void *data) 102 126 { 103 - struct platform_device *pdev = to_platform_device(dev); 127 + struct platform_device *pdev = to_platform_device(dev), *connector_pdev; 104 128 struct dw_hdmi_plat_data *plat_data; 105 129 struct drm_device *drm = data; 106 130 struct device_node *phy_node; ··· 174 150 return PTR_ERR(hdmi->regulator); 175 151 } 176 152 153 + ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev); 154 + if (!ret) { 155 + hdmi->ddc_en = gpiod_get_optional(&connector_pdev->dev, 156 + "ddc-en", GPIOD_OUT_HIGH); 157 + platform_device_put(connector_pdev); 158 + 159 + if (IS_ERR(hdmi->ddc_en)) { 160 + dev_err(dev, "Couldn't get ddc-en gpio\n"); 161 + return PTR_ERR(hdmi->ddc_en); 162 + } 163 + } 164 + 177 165 ret = regulator_enable(hdmi->regulator); 178 166 if (ret) { 179 167 dev_err(dev, "Failed to enable regulator\n"); 180 - return ret; 168 + goto err_unref_ddc_en; 181 169 } 170 + 171 + gpiod_set_value(hdmi->ddc_en, 1); 182 172 183 173 ret = reset_control_deassert(hdmi->rst_ctrl); 184 174 if (ret) { 185 175 dev_err(dev, "Could not deassert ctrl reset control\n"); 186 - goto err_disable_regulator; 176 + goto err_disable_ddc_en; 187 177 } 188 178 189 179 ret = clk_prepare_enable(hdmi->clk_tmds); ··· 250 212 clk_disable_unprepare(hdmi->clk_tmds); 251 213 err_assert_ctrl_reset: 252 214 reset_control_assert(hdmi->rst_ctrl); 253 - err_disable_regulator: 215 + err_disable_ddc_en: 216 + gpiod_set_value(hdmi->ddc_en, 0); 254 217 regulator_disable(hdmi->regulator); 218 + err_unref_ddc_en: 219 + if (hdmi->ddc_en) 220 + gpiod_put(hdmi->ddc_en); 255 221 256 222 return ret; 257 223 } ··· 269 227 sun8i_hdmi_phy_remove(hdmi); 270 228 clk_disable_unprepare(hdmi->clk_tmds); 271 229 reset_control_assert(hdmi->rst_ctrl); 230 + gpiod_set_value(hdmi->ddc_en, 0); 272 231 regulator_disable(hdmi->regulator); 232 + 233 + if (hdmi->ddc_en) 234 + gpiod_put(hdmi->ddc_en); 273 235 } 274 236 275 237 static const struct component_ops sun8i_dw_hdmi_ops = {
+2
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
··· 9 9 #include <drm/bridge/dw_hdmi.h> 10 10 #include <drm/drm_encoder.h> 11 11 #include <linux/clk.h> 12 + #include <linux/gpio/consumer.h> 12 13 #include <linux/regmap.h> 13 14 #include <linux/regulator/consumer.h> 14 15 #include <linux/reset.h> ··· 191 190 struct regulator *regulator; 192 191 const struct sun8i_dw_hdmi_quirks *quirks; 193 192 struct reset_control *rst_ctrl; 193 + struct gpio_desc *ddc_en; 194 194 }; 195 195 196 196 static inline struct sun8i_dw_hdmi *