| From befd34e3c24cd92f7f8bec303a9fda088f692b9a Mon Sep 17 00:00:00 2001 |
| From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Date: Tue, 17 Jan 2017 10:29:00 +0200 |
| Subject: [PATCH 245/255] drm: bridge: dw-hdmi: Implement DRM bridge |
| registration |
| |
| As an option for drivers not based on the component framework, register |
| the bridge with the DRM core with the DRM bridge API. Existing drivers |
| based on dw_hdmi_bind() and dw_hdmi_unbind() are not affected as those |
| functions are preserved with their current behaviour. |
| |
| Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Reviewed-by: Jose Abreu <joabreu@synopsys.com> |
| Signed-off-by: Archit Taneja <architt@codeaurora.org> |
| Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-11-laurent.pinchart+renesas@ideasonboard.com |
| (cherry picked from commit 69497eb9234eb34994b9a0d2f2c17c4c09f2e969) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/gpu/drm/bridge/dw-hdmi.c | 112 +++++++++++++++++++++++++++------------ |
| include/drm/bridge/dw_hdmi.h | 3 + |
| 2 files changed, 83 insertions(+), 32 deletions(-) |
| |
| --- a/drivers/gpu/drm/bridge/dw-hdmi.c |
| +++ b/drivers/gpu/drm/bridge/dw-hdmi.c |
| @@ -1836,24 +1836,9 @@ static irqreturn_t dw_hdmi_irq(int irq, |
| return IRQ_HANDLED; |
| } |
| |
| -static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi) |
| -{ |
| - struct drm_bridge *bridge = &hdmi->bridge; |
| - int ret; |
| - |
| - bridge->driver_private = hdmi; |
| - bridge->funcs = &dw_hdmi_bridge_funcs; |
| - ret = drm_bridge_attach(encoder, bridge, NULL); |
| - if (ret) { |
| - DRM_ERROR("Failed to initialize bridge with drm\n"); |
| - return -EINVAL; |
| - } |
| - |
| - return 0; |
| -} |
| - |
| -int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, |
| - const struct dw_hdmi_plat_data *plat_data) |
| +static struct dw_hdmi * |
| +__dw_hdmi_probe(struct platform_device *pdev, |
| + const struct dw_hdmi_plat_data *plat_data) |
| { |
| struct device *dev = &pdev->dev; |
| struct device_node *np = dev->of_node; |
| @@ -1869,7 +1854,7 @@ int dw_hdmi_bind(struct platform_device |
| |
| hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); |
| if (!hdmi) |
| - return -ENOMEM; |
| + return ERR_PTR(-ENOMEM); |
| |
| hdmi->plat_data = plat_data; |
| hdmi->dev = dev; |
| @@ -1896,7 +1881,7 @@ int dw_hdmi_bind(struct platform_device |
| break; |
| default: |
| dev_err(dev, "reg-io-width must be 1 or 4\n"); |
| - return -EINVAL; |
| + return ERR_PTR(-EINVAL); |
| } |
| |
| ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); |
| @@ -1905,7 +1890,7 @@ int dw_hdmi_bind(struct platform_device |
| of_node_put(ddc_node); |
| if (!hdmi->ddc) { |
| dev_dbg(hdmi->dev, "failed to read ddc node\n"); |
| - return -EPROBE_DEFER; |
| + return ERR_PTR(-EPROBE_DEFER); |
| } |
| |
| } else { |
| @@ -1956,8 +1941,10 @@ int dw_hdmi_bind(struct platform_device |
| initialize_hdmi_ih_mutes(hdmi); |
| |
| irq = platform_get_irq(pdev, 0); |
| - if (irq < 0) |
| + if (irq < 0) { |
| + ret = irq; |
| goto err_iahb; |
| + } |
| |
| ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, |
| dw_hdmi_irq, IRQF_SHARED, |
| @@ -1988,11 +1975,11 @@ int dw_hdmi_bind(struct platform_device |
| hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, |
| HDMI_IH_PHY_STAT0); |
| |
| - ret = dw_hdmi_fb_registered(hdmi); |
| - if (ret) |
| - goto err_iahb; |
| + hdmi->bridge.driver_private = hdmi; |
| + hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; |
| + hdmi->bridge.of_node = pdev->dev.of_node; |
| |
| - ret = dw_hdmi_register(encoder, hdmi); |
| + ret = dw_hdmi_fb_registered(hdmi); |
| if (ret) |
| goto err_iahb; |
| |
| @@ -2041,7 +2028,7 @@ int dw_hdmi_bind(struct platform_device |
| |
| platform_set_drvdata(pdev, hdmi); |
| |
| - return 0; |
| + return hdmi; |
| |
| err_iahb: |
| if (hdmi->i2c) { |
| @@ -2055,14 +2042,11 @@ err_isfr: |
| err_res: |
| i2c_put_adapter(hdmi->ddc); |
| |
| - return ret; |
| + return ERR_PTR(ret); |
| } |
| -EXPORT_SYMBOL_GPL(dw_hdmi_bind); |
| |
| -void dw_hdmi_unbind(struct device *dev) |
| +static void __dw_hdmi_remove(struct dw_hdmi *hdmi) |
| { |
| - struct dw_hdmi *hdmi = dev_get_drvdata(dev); |
| - |
| if (hdmi->audio && !IS_ERR(hdmi->audio)) |
| platform_device_unregister(hdmi->audio); |
| |
| @@ -2077,6 +2061,70 @@ void dw_hdmi_unbind(struct device *dev) |
| else |
| i2c_put_adapter(hdmi->ddc); |
| } |
| + |
| +/* ----------------------------------------------------------------------------- |
| + * Probe/remove API, used from platforms based on the DRM bridge API. |
| + */ |
| +int dw_hdmi_probe(struct platform_device *pdev, |
| + const struct dw_hdmi_plat_data *plat_data) |
| +{ |
| + struct dw_hdmi *hdmi; |
| + int ret; |
| + |
| + hdmi = __dw_hdmi_probe(pdev, plat_data); |
| + if (IS_ERR(hdmi)) |
| + return PTR_ERR(hdmi); |
| + |
| + ret = drm_bridge_add(&hdmi->bridge); |
| + if (ret < 0) { |
| + __dw_hdmi_remove(hdmi); |
| + return ret; |
| + } |
| + |
| + return 0; |
| +} |
| +EXPORT_SYMBOL_GPL(dw_hdmi_probe); |
| + |
| +void dw_hdmi_remove(struct platform_device *pdev) |
| +{ |
| + struct dw_hdmi *hdmi = platform_get_drvdata(pdev); |
| + |
| + drm_bridge_remove(&hdmi->bridge); |
| + |
| + __dw_hdmi_remove(hdmi); |
| +} |
| +EXPORT_SYMBOL_GPL(dw_hdmi_remove); |
| + |
| +/* ----------------------------------------------------------------------------- |
| + * Bind/unbind API, used from platforms based on the component framework. |
| + */ |
| +int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, |
| + const struct dw_hdmi_plat_data *plat_data) |
| +{ |
| + struct dw_hdmi *hdmi; |
| + int ret; |
| + |
| + hdmi = __dw_hdmi_probe(pdev, plat_data); |
| + if (IS_ERR(hdmi)) |
| + return PTR_ERR(hdmi); |
| + |
| + ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL); |
| + if (ret) { |
| + dw_hdmi_remove(pdev); |
| + DRM_ERROR("Failed to initialize bridge with drm\n"); |
| + return ret; |
| + } |
| + |
| + return 0; |
| +} |
| +EXPORT_SYMBOL_GPL(dw_hdmi_bind); |
| + |
| +void dw_hdmi_unbind(struct device *dev) |
| +{ |
| + struct dw_hdmi *hdmi = dev_get_drvdata(dev); |
| + |
| + __dw_hdmi_remove(hdmi); |
| +} |
| EXPORT_SYMBOL_GPL(dw_hdmi_unbind); |
| |
| MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); |
| --- a/include/drm/bridge/dw_hdmi.h |
| +++ b/include/drm/bridge/dw_hdmi.h |
| @@ -56,6 +56,9 @@ struct dw_hdmi_plat_data { |
| struct drm_display_mode *mode); |
| }; |
| |
| +int dw_hdmi_probe(struct platform_device *pdev, |
| + const struct dw_hdmi_plat_data *plat_data); |
| +void dw_hdmi_remove(struct platform_device *pdev); |
| void dw_hdmi_unbind(struct device *dev); |
| int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, |
| const struct dw_hdmi_plat_data *plat_data); |