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

drm: bridge: dw-hdmi: Report connector status using callback

Allow codec driver register callback function for plug event.

The callback registration flow:
dw-hdmi <--- hw-hdmi-i2s-audio <--- hdmi-codec

dw-hdmi-i2s-audio implements hook_plugged_cb op
so codec driver can register the callback.

dw-hdmi exports a function dw_hdmi_set_plugged_cb so platform device
can register the callback.

When connector plug/unplug event happens, report this event using the
callback.

Make sure that audio and drm are using the single source of truth for
connector status.

Signed-off-by: Cheng-Yi Chiang <cychiang@chromium.org>
Link: https://lore.kernel.org/r/20191028071930.145899-2-cychiang@chromium.org
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Cheng-Yi Chiang and committed by
Mark Brown
a9c82d63 c3ad1092

+55 -1
+11
drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
··· 151 151 return -EINVAL; 152 152 } 153 153 154 + static int dw_hdmi_i2s_hook_plugged_cb(struct device *dev, void *data, 155 + hdmi_codec_plugged_cb fn, 156 + struct device *codec_dev) 157 + { 158 + struct dw_hdmi_i2s_audio_data *audio = data; 159 + struct dw_hdmi *hdmi = audio->hdmi; 160 + 161 + return dw_hdmi_set_plugged_cb(hdmi, fn, codec_dev); 162 + } 163 + 154 164 static struct hdmi_codec_ops dw_hdmi_i2s_ops = { 155 165 .hw_params = dw_hdmi_i2s_hw_params, 156 166 .audio_shutdown = dw_hdmi_i2s_audio_shutdown, 157 167 .get_eld = dw_hdmi_i2s_get_eld, 158 168 .get_dai_id = dw_hdmi_i2s_get_dai_id, 169 + .hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb, 159 170 }; 160 171 161 172 static int snd_dw_hdmi_probe(struct platform_device *pdev)
+40 -1
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
··· 191 191 192 192 struct mutex cec_notifier_mutex; 193 193 struct cec_notifier *cec_notifier; 194 + 195 + hdmi_codec_plugged_cb plugged_cb; 196 + struct device *codec_dev; 197 + enum drm_connector_status last_connector_result; 194 198 }; 195 199 196 200 #define HDMI_IH_PHY_STAT0_RX_SENSE \ ··· 218 214 219 215 return val; 220 216 } 217 + 218 + static void handle_plugged_change(struct dw_hdmi *hdmi, bool plugged) 219 + { 220 + if (hdmi->plugged_cb && hdmi->codec_dev) 221 + hdmi->plugged_cb(hdmi->codec_dev, plugged); 222 + } 223 + 224 + int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, 225 + struct device *codec_dev) 226 + { 227 + bool plugged; 228 + 229 + mutex_lock(&hdmi->mutex); 230 + hdmi->plugged_cb = fn; 231 + hdmi->codec_dev = codec_dev; 232 + plugged = hdmi->last_connector_result == connector_status_connected; 233 + handle_plugged_change(hdmi, plugged); 234 + mutex_unlock(&hdmi->mutex); 235 + 236 + return 0; 237 + } 238 + EXPORT_SYMBOL_GPL(dw_hdmi_set_plugged_cb); 221 239 222 240 static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) 223 241 { ··· 2187 2161 { 2188 2162 struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, 2189 2163 connector); 2164 + enum drm_connector_status result; 2190 2165 2191 2166 mutex_lock(&hdmi->mutex); 2192 2167 hdmi->force = DRM_FORCE_UNSPECIFIED; ··· 2195 2168 dw_hdmi_update_phy_mask(hdmi); 2196 2169 mutex_unlock(&hdmi->mutex); 2197 2170 2198 - return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); 2171 + result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); 2172 + 2173 + mutex_lock(&hdmi->mutex); 2174 + if (result != hdmi->last_connector_result) { 2175 + dev_dbg(hdmi->dev, "read_hpd result: %d", result); 2176 + handle_plugged_change(hdmi, 2177 + result == connector_status_connected); 2178 + hdmi->last_connector_result = result; 2179 + } 2180 + mutex_unlock(&hdmi->mutex); 2181 + 2182 + return result; 2199 2183 } 2200 2184 2201 2185 static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ··· 2657 2619 hdmi->rxsense = true; 2658 2620 hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE); 2659 2621 hdmi->mc_clkdis = 0x7f; 2622 + hdmi->last_connector_result = connector_status_disconnected; 2660 2623 2661 2624 mutex_init(&hdmi->mutex); 2662 2625 mutex_init(&hdmi->audio_mutex);
+4
include/drm/bridge/dw_hdmi.h
··· 6 6 #ifndef __DW_HDMI__ 7 7 #define __DW_HDMI__ 8 8 9 + #include <sound/hdmi-codec.h> 10 + 9 11 struct drm_connector; 10 12 struct drm_display_mode; 11 13 struct drm_encoder; ··· 156 154 157 155 void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); 158 156 157 + int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, 158 + struct device *codec_dev); 159 159 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); 160 160 void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt); 161 161 void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca);