Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 49 additions & 76 deletions drivers/gpu/drm/bridge/lontium-lt9611uxc.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
#include <linux/wait.h>
#include <linux/workqueue.h>

#include <sound/hdmi-codec.h>

#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
Expand All @@ -27,6 +25,8 @@
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>

#include <drm/display/drm_hdmi_audio_helper.h>

#define EDID_BLOCK_SIZE 128
#define EDID_NUM_BLOCKS 2

Expand All @@ -48,7 +48,6 @@ struct lt9611uxc {
struct device_node *dsi1_node;
struct mipi_dsi_device *dsi0;
struct mipi_dsi_device *dsi1;
struct platform_device *audio_pdev;

struct gpio_desc *reset_gpio;
struct gpio_desc *enable_gpio;
Expand Down Expand Up @@ -437,12 +436,52 @@ static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *brid
return drm_edid_read_custom(connector, lt9611uxc_get_edid_block, lt9611uxc);
}

static void lt9611uxc_bridge_hpd_notify(struct drm_bridge *bridge,
struct drm_connector *connector,
enum drm_connector_status status)
{
const struct drm_edid *drm_edid;

if (status == connector_status_disconnected) {
drm_connector_hdmi_audio_plugged_notify(connector, false);
drm_edid_connector_update(connector, NULL);
return;
}

drm_edid = lt9611uxc_bridge_edid_read(bridge, connector);
drm_edid_connector_update(connector, drm_edid);
drm_edid_free(drm_edid);

if (status == connector_status_connected)
drm_connector_hdmi_audio_plugged_notify(connector, true);
}

static int lt9611uxc_hdmi_audio_prepare(struct drm_bridge *bridge,
struct drm_connector *connector,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms)
{
/*
* LT9611UXC will automatically detect rate and sample size, so no need
* to setup anything here.
*/
return 0;
}

static void lt9611uxc_hdmi_audio_shutdown(struct drm_bridge *bridge,
struct drm_connector *connector)
{
}

static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = {
.attach = lt9611uxc_bridge_attach,
.mode_valid = lt9611uxc_bridge_mode_valid,
.mode_set = lt9611uxc_bridge_mode_set,
.detect = lt9611uxc_bridge_detect,
.edid_read = lt9611uxc_bridge_edid_read,
.hpd_notify = lt9611uxc_bridge_hpd_notify,
.hdmi_audio_prepare = lt9611uxc_hdmi_audio_prepare,
.hdmi_audio_shutdown = lt9611uxc_hdmi_audio_shutdown,
};

static int lt9611uxc_parse_dt(struct device *dev,
Expand Down Expand Up @@ -516,73 +555,6 @@ static int lt9611uxc_read_version(struct lt9611uxc *lt9611uxc)
return ret < 0 ? ret : rev;
}

static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms)
{
/*
* LT9611UXC will automatically detect rate and sample size, so no need
* to setup anything here.
*/
return 0;
}

static void lt9611uxc_audio_shutdown(struct device *dev, void *data)
{
}

static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
struct device_node *endpoint,
void *data)
{
struct of_endpoint of_ep;
int ret;

ret = of_graph_parse_endpoint(endpoint, &of_ep);
if (ret < 0)
return ret;

/*
* HDMI sound should be located as reg = <2>
* Then, it is sound port 0
*/
if (of_ep.port == 2)
return 0;

return -EINVAL;
}

static const struct hdmi_codec_ops lt9611uxc_codec_ops = {
.hw_params = lt9611uxc_hdmi_hw_params,
.audio_shutdown = lt9611uxc_audio_shutdown,
.get_dai_id = lt9611uxc_hdmi_i2s_get_dai_id,
};

static int lt9611uxc_audio_init(struct device *dev, struct lt9611uxc *lt9611uxc)
{
struct hdmi_codec_pdata codec_data = {
.ops = &lt9611uxc_codec_ops,
.max_i2s_channels = 2,
.i2s = 1,
.data = lt9611uxc,
};

lt9611uxc->audio_pdev =
platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
PLATFORM_DEVID_AUTO,
&codec_data, sizeof(codec_data));

return PTR_ERR_OR_ZERO(lt9611uxc->audio_pdev);
}

static void lt9611uxc_audio_exit(struct lt9611uxc *lt9611uxc)
{
if (lt9611uxc->audio_pdev) {
platform_device_unregister(lt9611uxc->audio_pdev);
lt9611uxc->audio_pdev = NULL;
}
}

#define LT9611UXC_FW_PAGE_SIZE 32
static void lt9611uxc_firmware_write_page(struct lt9611uxc *lt9611uxc, u16 addr, const u8 *buf)
{
Expand Down Expand Up @@ -866,11 +838,17 @@ static int lt9611uxc_probe(struct i2c_client *client)
i2c_set_clientdata(client, lt9611uxc);

lt9611uxc->bridge.of_node = client->dev.of_node;
lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT |
DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HDMI_AUDIO;
if (lt9611uxc->hpd_supported)
lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_HPD;
lt9611uxc->bridge.type = DRM_MODE_CONNECTOR_HDMIA;

lt9611uxc->bridge.hdmi_audio_dev = dev;
lt9611uxc->bridge.hdmi_audio_max_i2s_playback_channels = 2;
lt9611uxc->bridge.hdmi_audio_dai_port = 2;

drm_bridge_add(&lt9611uxc->bridge);

/* Attach primary DSI */
Expand All @@ -889,10 +867,6 @@ static int lt9611uxc_probe(struct i2c_client *client)
}
}

ret = lt9611uxc_audio_init(dev, lt9611uxc);
if (ret)
goto err_remove_bridge;

return 0;

err_remove_bridge:
Expand All @@ -916,7 +890,6 @@ static void lt9611uxc_remove(struct i2c_client *client)

free_irq(client->irq, lt9611uxc);
cancel_work_sync(&lt9611uxc->work);
lt9611uxc_audio_exit(lt9611uxc);
drm_bridge_remove(&lt9611uxc->bridge);

mutex_destroy(&lt9611uxc->ocm_lock);
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/display/drm_bridge_connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static void drm_bridge_connector_hpd_notify(struct drm_connector *connector,
/* Notify all bridges in the pipeline of hotplug events. */
drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge) {
if (bridge->funcs->hpd_notify)
bridge->funcs->hpd_notify(bridge, status);
bridge->funcs->hpd_notify(bridge, connector, status);
}
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/meson/meson_encoder_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge,
}

static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge,
struct drm_connector *connector,
enum drm_connector_status status)
{
struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/msm/dp/dp_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -1784,7 +1784,8 @@ void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge)
}

void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge,
enum drm_connector_status status)
struct drm_connector *connector,
enum drm_connector_status status)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge);
struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/msm/dp/dp_drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge);
void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge);
void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge,
enum drm_connector_status status);
struct drm_connector *connector,
enum drm_connector_status status);

#endif /* _DP_DRM_H_ */
1 change: 1 addition & 0 deletions drivers/gpu/drm/omapdrm/dss/hdmi4.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ static void hdmi4_bridge_disable(struct drm_bridge *bridge,
}

static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge,
struct drm_connector *connector,
enum drm_connector_status status)
{
struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
Expand Down
1 change: 1 addition & 0 deletions include/drm/drm_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ struct drm_bridge_funcs {
* controllers for HDMI bridges.
*/
void (*hpd_notify)(struct drm_bridge *bridge,
struct drm_connector *connector,
enum drm_connector_status status);

/**
Expand Down