mirror of
https://github.com/torvalds/linux.git
synced 2026-05-22 22:22:08 +02:00
drm/rockchip: rk3066_hdmi: switch to drm bridge
Convert it to drm bridge driver, it will be convenient for us to migrate the connector part to the display driver later. Note: I don't have the hardware to test this driver, so for now I can only do the compilation test. Signed-off-by: Andy Yan <andy.yan@rock-chips.com> Tested-by: Heiko Stuebner <heiko@sntech.de> #rk3066-marsboard Signed-off-by: Heiko Stuebner <heiko@sntech.de> Link: https://lore.kernel.org/r/20250428102309.1501986-1-andyshrk@163.com
This commit is contained in:
parent
e782ac9369
commit
57d6811e8a
|
|
@ -5,6 +5,9 @@
|
|||
*/
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/display/drm_hdmi_helper.h>
|
||||
#include <drm/display/drm_hdmi_state_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
|
@ -46,27 +49,20 @@ struct rk3066_hdmi {
|
|||
struct clk *hclk;
|
||||
void __iomem *regs;
|
||||
|
||||
struct drm_connector connector;
|
||||
struct drm_bridge bridge;
|
||||
struct drm_connector *connector;
|
||||
struct rockchip_encoder encoder;
|
||||
|
||||
struct rk3066_hdmi_i2c *i2c;
|
||||
struct i2c_adapter *ddc;
|
||||
|
||||
unsigned int tmdsclk;
|
||||
|
||||
struct hdmi_data_info hdmi_data;
|
||||
};
|
||||
|
||||
static struct rk3066_hdmi *encoder_to_rk3066_hdmi(struct drm_encoder *encoder)
|
||||
static struct rk3066_hdmi *bridge_to_rk3066_hdmi(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
|
||||
|
||||
return container_of(rkencoder, struct rk3066_hdmi, encoder);
|
||||
}
|
||||
|
||||
static struct rk3066_hdmi *connector_to_rk3066_hdmi(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct rk3066_hdmi, connector);
|
||||
return container_of(bridge, struct rk3066_hdmi, bridge);
|
||||
}
|
||||
|
||||
static inline u8 hdmi_readb(struct rk3066_hdmi *hdmi, u16 offset)
|
||||
|
|
@ -161,57 +157,40 @@ static void rk3066_hdmi_set_power_mode(struct rk3066_hdmi *hdmi, int mode)
|
|||
hdmi->tmdsclk = DEFAULT_PLLA_RATE;
|
||||
}
|
||||
|
||||
static int
|
||||
rk3066_hdmi_upload_frame(struct rk3066_hdmi *hdmi, int setup_rc,
|
||||
union hdmi_infoframe *frame, u32 frame_index,
|
||||
u32 mask, u32 disable, u32 enable)
|
||||
static int rk3066_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
|
||||
enum hdmi_infoframe_type type)
|
||||
{
|
||||
if (mask)
|
||||
hdmi_modb(hdmi, HDMI_CP_AUTO_SEND_CTRL, mask, disable);
|
||||
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, frame_index);
|
||||
|
||||
if (setup_rc >= 0) {
|
||||
u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
|
||||
ssize_t rc, i;
|
||||
|
||||
rc = hdmi_infoframe_pack(frame, packed_frame,
|
||||
sizeof(packed_frame));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < rc; i++)
|
||||
hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4,
|
||||
packed_frame[i]);
|
||||
|
||||
if (mask)
|
||||
hdmi_modb(hdmi, HDMI_CP_AUTO_SEND_CTRL, mask, enable);
|
||||
if (type != HDMI_INFOFRAME_TYPE_AVI) {
|
||||
drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return setup_rc;
|
||||
hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, HDMI_INFOFRAME_AVI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3066_hdmi_config_avi(struct rk3066_hdmi *hdmi,
|
||||
struct drm_display_mode *mode)
|
||||
static int
|
||||
rk3066_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
|
||||
enum hdmi_infoframe_type type,
|
||||
const u8 *buffer, size_t len)
|
||||
{
|
||||
union hdmi_infoframe frame;
|
||||
int rc;
|
||||
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
|
||||
ssize_t i;
|
||||
|
||||
rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
&hdmi->connector, mode);
|
||||
if (type != HDMI_INFOFRAME_TYPE_AVI) {
|
||||
drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444)
|
||||
frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
|
||||
else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422)
|
||||
frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
|
||||
else
|
||||
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
|
||||
rk3066_hdmi_bridge_clear_infoframe(bridge, type);
|
||||
|
||||
frame.avi.colorimetry = hdmi->hdmi_data.colorimetry;
|
||||
frame.avi.scan_mode = HDMI_SCAN_MODE_NONE;
|
||||
for (i = 0; i < len; i++)
|
||||
hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4, buffer[i]);
|
||||
|
||||
return rk3066_hdmi_upload_frame(hdmi, rc, &frame,
|
||||
HDMI_INFOFRAME_AVI, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3066_hdmi_config_video_timing(struct rk3066_hdmi *hdmi,
|
||||
|
|
@ -324,9 +303,27 @@ static void rk3066_hdmi_config_phy(struct rk3066_hdmi *hdmi)
|
|||
}
|
||||
|
||||
static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
|
||||
struct drm_display_mode *mode)
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_display_info *display = &hdmi->connector.display_info;
|
||||
struct drm_bridge *bridge = &hdmi->bridge;
|
||||
struct drm_connector *connector;
|
||||
struct drm_display_info *display;
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_connector_state *new_conn_state;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
|
||||
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
|
||||
|
||||
new_conn_state = drm_atomic_get_new_connector_state(state, connector);
|
||||
if (WARN_ON(!new_conn_state))
|
||||
return -EINVAL;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
|
||||
if (WARN_ON(!new_crtc_state))
|
||||
return -EINVAL;
|
||||
|
||||
display = &connector->display_info;
|
||||
mode = &new_crtc_state->adjusted_mode;
|
||||
|
||||
hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
|
||||
hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB;
|
||||
|
|
@ -363,7 +360,7 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
|
|||
if (display->is_hdmi) {
|
||||
hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK,
|
||||
HDMI_VIDEO_MODE_HDMI);
|
||||
rk3066_hdmi_config_avi(hdmi, mode);
|
||||
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
|
||||
} else {
|
||||
hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK, 0);
|
||||
}
|
||||
|
|
@ -386,15 +383,15 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
static void rk3066_hdmi_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
|
||||
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
|
||||
struct drm_connector_state *conn_state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int mux, val;
|
||||
|
||||
conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector);
|
||||
conn_state = drm_atomic_get_new_connector_state(state, hdmi->connector);
|
||||
if (WARN_ON(!conn_state))
|
||||
return;
|
||||
|
||||
|
|
@ -402,7 +399,7 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder,
|
|||
if (WARN_ON(!crtc_state))
|
||||
return;
|
||||
|
||||
mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
|
||||
mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, &hdmi->encoder.encoder);
|
||||
if (mux)
|
||||
val = (HDMI_VIDEO_SEL << 16) | HDMI_VIDEO_SEL;
|
||||
else
|
||||
|
|
@ -413,13 +410,13 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder,
|
|||
DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder enable select: vop%s\n",
|
||||
(mux) ? "1" : "0");
|
||||
|
||||
rk3066_hdmi_setup(hdmi, &crtc_state->adjusted_mode);
|
||||
rk3066_hdmi_setup(hdmi, state);
|
||||
}
|
||||
|
||||
static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
static void rk3066_hdmi_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
|
||||
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
|
||||
|
||||
DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder disable\n");
|
||||
|
||||
|
|
@ -450,39 +447,34 @@ rk3066_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
|
|||
static const
|
||||
struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = {
|
||||
.atomic_check = rk3066_hdmi_encoder_atomic_check,
|
||||
.atomic_enable = rk3066_hdmi_encoder_enable,
|
||||
.atomic_disable = rk3066_hdmi_encoder_disable,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
rk3066_hdmi_bridge_detect(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
|
||||
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
|
||||
|
||||
return (hdmi_readb(hdmi, HDMI_HPG_MENS_STA) & HDMI_HPG_IN_STATUS_HIGH) ?
|
||||
connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
|
||||
static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
static const struct drm_edid *
|
||||
rk3066_hdmi_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector)
|
||||
{
|
||||
struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
|
||||
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
|
||||
const struct drm_edid *drm_edid;
|
||||
int ret = 0;
|
||||
|
||||
if (!hdmi->ddc)
|
||||
return 0;
|
||||
drm_edid = drm_edid_read_ddc(connector, bridge->ddc);
|
||||
if (!drm_edid)
|
||||
dev_dbg(hdmi->dev, "failed to get edid\n");
|
||||
|
||||
drm_edid = drm_edid_read_ddc(connector, hdmi->ddc);
|
||||
drm_edid_connector_update(connector, drm_edid);
|
||||
ret = drm_edid_connector_add_modes(connector);
|
||||
drm_edid_free(drm_edid);
|
||||
|
||||
return ret;
|
||||
return drm_edid;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
rk3066_hdmi_connector_mode_valid(struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode)
|
||||
rk3066_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
u32 vic = drm_match_cea_mode(mode);
|
||||
|
||||
|
|
@ -492,82 +484,19 @@ rk3066_hdmi_connector_mode_valid(struct drm_connector *connector,
|
|||
return MODE_BAD;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
rk3066_hdmi_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
|
||||
|
||||
return &hdmi->encoder.encoder;
|
||||
}
|
||||
|
||||
static int
|
||||
rk3066_hdmi_probe_single_connector_modes(struct drm_connector *connector,
|
||||
uint32_t maxX, uint32_t maxY)
|
||||
{
|
||||
if (maxX > 1920)
|
||||
maxX = 1920;
|
||||
if (maxY > 1080)
|
||||
maxY = 1080;
|
||||
|
||||
return drm_helper_probe_single_connector_modes(connector, maxX, maxY);
|
||||
}
|
||||
|
||||
static void rk3066_hdmi_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_unregister(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs rk3066_hdmi_connector_funcs = {
|
||||
.fill_modes = rk3066_hdmi_probe_single_connector_modes,
|
||||
.detect = rk3066_hdmi_connector_detect,
|
||||
.destroy = rk3066_hdmi_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
static const struct drm_bridge_funcs rk3066_hdmi_bridge_funcs = {
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.atomic_enable = rk3066_hdmi_bridge_atomic_enable,
|
||||
.atomic_disable = rk3066_hdmi_bridge_atomic_disable,
|
||||
.detect = rk3066_hdmi_bridge_detect,
|
||||
.edid_read = rk3066_hdmi_bridge_edid_read,
|
||||
.hdmi_clear_infoframe = rk3066_hdmi_bridge_clear_infoframe,
|
||||
.hdmi_write_infoframe = rk3066_hdmi_bridge_write_infoframe,
|
||||
.mode_valid = rk3066_hdmi_bridge_mode_valid,
|
||||
};
|
||||
|
||||
static const
|
||||
struct drm_connector_helper_funcs rk3066_hdmi_connector_helper_funcs = {
|
||||
.get_modes = rk3066_hdmi_connector_get_modes,
|
||||
.mode_valid = rk3066_hdmi_connector_mode_valid,
|
||||
.best_encoder = rk3066_hdmi_connector_best_encoder,
|
||||
};
|
||||
|
||||
static int
|
||||
rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
|
||||
{
|
||||
struct drm_encoder *encoder = &hdmi->encoder.encoder;
|
||||
struct device *dev = hdmi->dev;
|
||||
|
||||
encoder->possible_crtcs =
|
||||
drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
* supposed to be connected to, it's because the CRTC has
|
||||
* not been registered yet. Defer probing, and hope that
|
||||
* the required CRTC is added later.
|
||||
*/
|
||||
if (encoder->possible_crtcs == 0)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs);
|
||||
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
drm_connector_helper_add(&hdmi->connector,
|
||||
&rk3066_hdmi_connector_helper_funcs);
|
||||
drm_connector_init_with_ddc(drm, &hdmi->connector,
|
||||
&rk3066_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA,
|
||||
hdmi->ddc);
|
||||
|
||||
drm_connector_attach_encoder(&hdmi->connector, encoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t rk3066_hdmi_hardirq(int irq, void *dev_id)
|
||||
{
|
||||
|
|
@ -597,7 +526,7 @@ static irqreturn_t rk3066_hdmi_irq(int irq, void *dev_id)
|
|||
{
|
||||
struct rk3066_hdmi *hdmi = dev_id;
|
||||
|
||||
drm_helper_hpd_irq_event(hdmi->connector.dev);
|
||||
drm_helper_hpd_irq_event(hdmi->connector->dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -720,7 +649,7 @@ static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi)
|
|||
strscpy(adap->name, "RK3066 HDMI", sizeof(adap->name));
|
||||
i2c_set_adapdata(adap, hdmi);
|
||||
|
||||
ret = i2c_add_adapter(adap);
|
||||
ret = devm_i2c_add_adapter(hdmi->dev, adap);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(hdmi->dev, "cannot add %s I2C adapter\n",
|
||||
adap->name);
|
||||
|
|
@ -735,6 +664,66 @@ static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi)
|
|||
return adap;
|
||||
}
|
||||
|
||||
static int
|
||||
rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
|
||||
{
|
||||
struct drm_encoder *encoder = &hdmi->encoder.encoder;
|
||||
struct device *dev = hdmi->dev;
|
||||
int ret;
|
||||
|
||||
encoder->possible_crtcs =
|
||||
drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
* supposed to be connected to, it's because the CRTC has
|
||||
* not been registered yet. Defer probing, and hope that
|
||||
* the required CRTC is added later.
|
||||
*/
|
||||
if (encoder->possible_crtcs == 0)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs);
|
||||
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
hdmi->bridge.driver_private = hdmi;
|
||||
hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs;
|
||||
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT |
|
||||
DRM_BRIDGE_OP_EDID |
|
||||
DRM_BRIDGE_OP_HDMI |
|
||||
DRM_BRIDGE_OP_HPD;
|
||||
hdmi->bridge.of_node = hdmi->dev->of_node;
|
||||
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
hdmi->bridge.vendor = "Rockchip";
|
||||
hdmi->bridge.product = "RK3066 HDMI";
|
||||
|
||||
hdmi->bridge.ddc = rk3066_hdmi_i2c_adapter(hdmi);
|
||||
if (IS_ERR(hdmi->bridge.ddc))
|
||||
return PTR_ERR(hdmi->bridge.ddc);
|
||||
|
||||
if (IS_ERR(hdmi->bridge.ddc))
|
||||
return PTR_ERR(hdmi->bridge.ddc);
|
||||
|
||||
ret = devm_drm_bridge_add(dev, &hdmi->bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hdmi->connector = drm_bridge_connector_init(drm, encoder);
|
||||
if (IS_ERR(hdmi->connector)) {
|
||||
ret = PTR_ERR(hdmi->connector);
|
||||
dev_err(hdmi->dev, "failed to init bridge connector: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_connector_attach_encoder(hdmi->connector, encoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3066_hdmi_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
|
|
@ -781,13 +770,6 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
|
|||
/* internal hclk = hdmi_hclk / 25 */
|
||||
hdmi_writeb(hdmi, HDMI_INTERNAL_CLK_DIVIDER, 25);
|
||||
|
||||
hdmi->ddc = rk3066_hdmi_i2c_adapter(hdmi);
|
||||
if (IS_ERR(hdmi->ddc)) {
|
||||
ret = PTR_ERR(hdmi->ddc);
|
||||
hdmi->ddc = NULL;
|
||||
goto err_disable_hclk;
|
||||
}
|
||||
|
||||
rk3066_hdmi_set_power_mode(hdmi, HDMI_SYS_POWER_MODE_B);
|
||||
usleep_range(999, 1000);
|
||||
hdmi_writeb(hdmi, HDMI_INTR_MASK1, HDMI_INTR_HOTPLUG);
|
||||
|
|
@ -798,7 +780,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
|
|||
|
||||
ret = rk3066_hdmi_register(drm, hdmi);
|
||||
if (ret)
|
||||
goto err_disable_i2c;
|
||||
goto err_disable_hclk;
|
||||
|
||||
dev_set_drvdata(dev, hdmi);
|
||||
|
||||
|
|
@ -813,10 +795,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
|
|||
return 0;
|
||||
|
||||
err_cleanup_hdmi:
|
||||
hdmi->connector.funcs->destroy(&hdmi->connector);
|
||||
hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
|
||||
err_disable_i2c:
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
err_disable_hclk:
|
||||
clk_disable_unprepare(hdmi->hclk);
|
||||
|
||||
|
|
@ -828,10 +807,8 @@ static void rk3066_hdmi_unbind(struct device *dev, struct device *master,
|
|||
{
|
||||
struct rk3066_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
hdmi->connector.funcs->destroy(&hdmi->connector);
|
||||
hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
|
||||
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
clk_disable_unprepare(hdmi->hclk);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user