diff options
| author | Dave Airlie <airlied@redhat.com> | 2016-09-12 20:28:17 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2016-09-12 20:28:17 -0400 |
| commit | 8506912b969b60aacc733315eeeb46b014d920a4 (patch) | |
| tree | 42a786a5e6d20470f9eec8cd2614d9e827505a9c /drivers/gpu/drm/i2c | |
| parent | b4eac5465b23a9bcb4a66376a5664086b4913288 (diff) | |
| parent | df0bd1e8f3c508bf4c3445f94b12e38289b65f13 (diff) | |
Merge branch 'drm-tda998x-devel' of git://git.armlinux.org.uk/~rmk/linux-arm into drm-next
This adds the ASoC codec interfaces for TDA998x HDMI audio from
Jyri Sarha.
* 'drm-tda998x-devel' of git://git.armlinux.org.uk/~rmk/linux-arm:
ARM: dts: am335x-boneblack: Add HDMI audio support
drm/i2c: tda998x: Register ASoC hdmi-codec and add audio DT binding
drm/i2c: tda998x: Improve tda998x_configure_audio() audio related pdata
Diffstat (limited to 'drivers/gpu/drm/i2c')
| -rw-r--r-- | drivers/gpu/drm/i2c/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/i2c/tda998x_drv.c | 297 |
2 files changed, 257 insertions, 41 deletions
diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 4d341db462a2..a6c92beb410a 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig | |||
| @@ -22,6 +22,7 @@ config DRM_I2C_SIL164 | |||
| 22 | config DRM_I2C_NXP_TDA998X | 22 | config DRM_I2C_NXP_TDA998X |
| 23 | tristate "NXP Semiconductors TDA998X HDMI encoder" | 23 | tristate "NXP Semiconductors TDA998X HDMI encoder" |
| 24 | default m if DRM_TILCDC | 24 | default m if DRM_TILCDC |
| 25 | select SND_SOC_HDMI_CODEC if SND_SOC | ||
| 25 | help | 26 | help |
| 26 | Support for NXP Semiconductors TDA998X HDMI encoders. | 27 | Support for NXP Semiconductors TDA998X HDMI encoders. |
| 27 | 28 | ||
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index f4315bc8d471..9798d400d817 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
| 22 | #include <sound/asoundef.h> | 22 | #include <sound/asoundef.h> |
| 23 | #include <sound/hdmi-codec.h> | ||
| 23 | 24 | ||
| 24 | #include <drm/drmP.h> | 25 | #include <drm/drmP.h> |
| 25 | #include <drm/drm_atomic_helper.h> | 26 | #include <drm/drm_atomic_helper.h> |
| @@ -30,6 +31,11 @@ | |||
| 30 | 31 | ||
| 31 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) | 32 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) |
| 32 | 33 | ||
| 34 | struct tda998x_audio_port { | ||
| 35 | u8 format; /* AFMT_xxx */ | ||
| 36 | u8 config; /* AP value */ | ||
| 37 | }; | ||
| 38 | |||
| 33 | struct tda998x_priv { | 39 | struct tda998x_priv { |
| 34 | struct i2c_client *cec; | 40 | struct i2c_client *cec; |
| 35 | struct i2c_client *hdmi; | 41 | struct i2c_client *hdmi; |
| @@ -41,7 +47,10 @@ struct tda998x_priv { | |||
| 41 | u8 vip_cntrl_0; | 47 | u8 vip_cntrl_0; |
| 42 | u8 vip_cntrl_1; | 48 | u8 vip_cntrl_1; |
| 43 | u8 vip_cntrl_2; | 49 | u8 vip_cntrl_2; |
| 44 | struct tda998x_encoder_params params; | 50 | struct tda998x_audio_params audio_params; |
| 51 | |||
| 52 | struct platform_device *audio_pdev; | ||
| 53 | struct mutex audio_mutex; | ||
| 45 | 54 | ||
| 46 | wait_queue_head_t wq_edid; | 55 | wait_queue_head_t wq_edid; |
| 47 | volatile int wq_edid_wait; | 56 | volatile int wq_edid_wait; |
| @@ -53,6 +62,8 @@ struct tda998x_priv { | |||
| 53 | 62 | ||
| 54 | struct drm_encoder encoder; | 63 | struct drm_encoder encoder; |
| 55 | struct drm_connector connector; | 64 | struct drm_connector connector; |
| 65 | |||
| 66 | struct tda998x_audio_port audio_port[2]; | ||
| 56 | }; | 67 | }; |
| 57 | 68 | ||
| 58 | #define conn_to_tda998x_priv(x) \ | 69 | #define conn_to_tda998x_priv(x) \ |
| @@ -666,26 +677,16 @@ tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr, | |||
| 666 | reg_set(priv, REG_DIP_IF_FLAGS, bit); | 677 | reg_set(priv, REG_DIP_IF_FLAGS, bit); |
| 667 | } | 678 | } |
| 668 | 679 | ||
| 669 | static void | 680 | static int tda998x_write_aif(struct tda998x_priv *priv, |
| 670 | tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) | 681 | struct hdmi_audio_infoframe *cea) |
| 671 | { | 682 | { |
| 672 | union hdmi_infoframe frame; | 683 | union hdmi_infoframe frame; |
| 673 | 684 | ||
| 674 | hdmi_audio_infoframe_init(&frame.audio); | 685 | frame.audio = *cea; |
| 675 | |||
| 676 | frame.audio.channels = p->audio_frame[1] & 0x07; | ||
| 677 | frame.audio.channel_allocation = p->audio_frame[4]; | ||
| 678 | frame.audio.level_shift_value = (p->audio_frame[5] & 0x78) >> 3; | ||
| 679 | frame.audio.downmix_inhibit = (p->audio_frame[5] & 0x80) >> 7; | ||
| 680 | |||
| 681 | /* | ||
| 682 | * L-PCM and IEC61937 compressed audio shall always set sample | ||
| 683 | * frequency to "refer to stream". For others, see the HDMI | ||
| 684 | * specification. | ||
| 685 | */ | ||
| 686 | frame.audio.sample_frequency = (p->audio_frame[2] & 0x1c) >> 2; | ||
| 687 | 686 | ||
| 688 | tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame); | 687 | tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame); |
| 688 | |||
| 689 | return 0; | ||
| 689 | } | 690 | } |
| 690 | 691 | ||
| 691 | static void | 692 | static void |
| @@ -710,20 +711,21 @@ static void tda998x_audio_mute(struct tda998x_priv *priv, bool on) | |||
| 710 | } | 711 | } |
| 711 | } | 712 | } |
| 712 | 713 | ||
| 713 | static void | 714 | static int |
| 714 | tda998x_configure_audio(struct tda998x_priv *priv, | 715 | tda998x_configure_audio(struct tda998x_priv *priv, |
| 715 | struct drm_display_mode *mode, struct tda998x_encoder_params *p) | 716 | struct tda998x_audio_params *params, |
| 717 | unsigned mode_clock) | ||
| 716 | { | 718 | { |
| 717 | u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv; | 719 | u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv; |
| 718 | u32 n; | 720 | u32 n; |
| 719 | 721 | ||
| 720 | /* Enable audio ports */ | 722 | /* Enable audio ports */ |
| 721 | reg_write(priv, REG_ENA_AP, p->audio_cfg); | 723 | reg_write(priv, REG_ENA_AP, params->config); |
| 722 | reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg); | ||
| 723 | 724 | ||
| 724 | /* Set audio input source */ | 725 | /* Set audio input source */ |
| 725 | switch (p->audio_format) { | 726 | switch (params->format) { |
| 726 | case AFMT_SPDIF: | 727 | case AFMT_SPDIF: |
| 728 | reg_write(priv, REG_ENA_ACLK, 0); | ||
| 727 | reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); | 729 | reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); |
| 728 | clksel_aip = AIP_CLKSEL_AIP_SPDIF; | 730 | clksel_aip = AIP_CLKSEL_AIP_SPDIF; |
| 729 | clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; | 731 | clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; |
| @@ -731,15 +733,29 @@ tda998x_configure_audio(struct tda998x_priv *priv, | |||
| 731 | break; | 733 | break; |
| 732 | 734 | ||
| 733 | case AFMT_I2S: | 735 | case AFMT_I2S: |
| 736 | reg_write(priv, REG_ENA_ACLK, 1); | ||
| 734 | reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); | 737 | reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); |
| 735 | clksel_aip = AIP_CLKSEL_AIP_I2S; | 738 | clksel_aip = AIP_CLKSEL_AIP_I2S; |
| 736 | clksel_fs = AIP_CLKSEL_FS_ACLK; | 739 | clksel_fs = AIP_CLKSEL_FS_ACLK; |
| 737 | cts_n = CTS_N_M(3) | CTS_N_K(3); | 740 | switch (params->sample_width) { |
| 741 | case 16: | ||
| 742 | cts_n = CTS_N_M(3) | CTS_N_K(1); | ||
| 743 | break; | ||
| 744 | case 18: | ||
| 745 | case 20: | ||
| 746 | case 24: | ||
| 747 | cts_n = CTS_N_M(3) | CTS_N_K(2); | ||
| 748 | break; | ||
| 749 | default: | ||
| 750 | case 32: | ||
| 751 | cts_n = CTS_N_M(3) | CTS_N_K(3); | ||
| 752 | break; | ||
| 753 | } | ||
| 738 | break; | 754 | break; |
| 739 | 755 | ||
| 740 | default: | 756 | default: |
| 741 | BUG(); | 757 | dev_err(&priv->hdmi->dev, "Unsupported I2S format\n"); |
| 742 | return; | 758 | return -EINVAL; |
| 743 | } | 759 | } |
| 744 | 760 | ||
| 745 | reg_write(priv, REG_AIP_CLKSEL, clksel_aip); | 761 | reg_write(priv, REG_AIP_CLKSEL, clksel_aip); |
| @@ -755,11 +771,11 @@ tda998x_configure_audio(struct tda998x_priv *priv, | |||
| 755 | * assume 100MHz requires larger divider. | 771 | * assume 100MHz requires larger divider. |
| 756 | */ | 772 | */ |
| 757 | adiv = AUDIO_DIV_SERCLK_8; | 773 | adiv = AUDIO_DIV_SERCLK_8; |
| 758 | if (mode->clock > 100000) | 774 | if (mode_clock > 100000) |
| 759 | adiv++; /* AUDIO_DIV_SERCLK_16 */ | 775 | adiv++; /* AUDIO_DIV_SERCLK_16 */ |
| 760 | 776 | ||
| 761 | /* S/PDIF asks for a larger divider */ | 777 | /* S/PDIF asks for a larger divider */ |
| 762 | if (p->audio_format == AFMT_SPDIF) | 778 | if (params->format == AFMT_SPDIF) |
| 763 | adiv++; /* AUDIO_DIV_SERCLK_16 or _32 */ | 779 | adiv++; /* AUDIO_DIV_SERCLK_16 or _32 */ |
| 764 | 780 | ||
| 765 | reg_write(priv, REG_AUDIO_DIV, adiv); | 781 | reg_write(priv, REG_AUDIO_DIV, adiv); |
| @@ -768,7 +784,7 @@ tda998x_configure_audio(struct tda998x_priv *priv, | |||
| 768 | * This is the approximate value of N, which happens to be | 784 | * This is the approximate value of N, which happens to be |
| 769 | * the recommended values for non-coherent clocks. | 785 | * the recommended values for non-coherent clocks. |
| 770 | */ | 786 | */ |
| 771 | n = 128 * p->audio_sample_rate / 1000; | 787 | n = 128 * params->sample_rate / 1000; |
| 772 | 788 | ||
| 773 | /* Write the CTS and N values */ | 789 | /* Write the CTS and N values */ |
| 774 | buf[0] = 0x44; | 790 | buf[0] = 0x44; |
| @@ -786,20 +802,21 @@ tda998x_configure_audio(struct tda998x_priv *priv, | |||
| 786 | reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); | 802 | reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); |
| 787 | reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); | 803 | reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); |
| 788 | 804 | ||
| 789 | /* Write the channel status */ | 805 | /* Write the channel status |
| 790 | buf[0] = IEC958_AES0_CON_NOT_COPYRIGHT; | 806 | * The REG_CH_STAT_B-registers skip IEC958 AES2 byte, because |
| 791 | buf[1] = 0x00; | 807 | * there is a separate register for each I2S wire. |
| 792 | buf[2] = IEC958_AES3_CON_FS_NOTID; | 808 | */ |
| 793 | buf[3] = IEC958_AES4_CON_ORIGFS_NOTID | | 809 | buf[0] = params->status[0]; |
| 794 | IEC958_AES4_CON_MAX_WORDLEN_24; | 810 | buf[1] = params->status[1]; |
| 811 | buf[2] = params->status[3]; | ||
| 812 | buf[3] = params->status[4]; | ||
| 795 | reg_write_range(priv, REG_CH_STAT_B(0), buf, 4); | 813 | reg_write_range(priv, REG_CH_STAT_B(0), buf, 4); |
| 796 | 814 | ||
| 797 | tda998x_audio_mute(priv, true); | 815 | tda998x_audio_mute(priv, true); |
| 798 | msleep(20); | 816 | msleep(20); |
| 799 | tda998x_audio_mute(priv, false); | 817 | tda998x_audio_mute(priv, false); |
| 800 | 818 | ||
| 801 | /* Write the audio information packet */ | 819 | return tda998x_write_aif(priv, ¶ms->cea); |
| 802 | tda998x_write_aif(priv, p); | ||
| 803 | } | 820 | } |
| 804 | 821 | ||
| 805 | /* DRM encoder functions */ | 822 | /* DRM encoder functions */ |
| @@ -820,7 +837,7 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv, | |||
| 820 | VIP_CNTRL_2_SWAP_F(p->swap_f) | | 837 | VIP_CNTRL_2_SWAP_F(p->swap_f) | |
| 821 | (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); | 838 | (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); |
| 822 | 839 | ||
| 823 | priv->params = *p; | 840 | priv->audio_params = p->audio_params; |
| 824 | } | 841 | } |
| 825 | 842 | ||
| 826 | static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) | 843 | static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) |
| @@ -1057,9 +1074,13 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, | |||
| 1057 | 1074 | ||
| 1058 | tda998x_write_avi(priv, adjusted_mode); | 1075 | tda998x_write_avi(priv, adjusted_mode); |
| 1059 | 1076 | ||
| 1060 | if (priv->params.audio_cfg) | 1077 | if (priv->audio_params.format != AFMT_UNUSED) { |
| 1061 | tda998x_configure_audio(priv, adjusted_mode, | 1078 | mutex_lock(&priv->audio_mutex); |
| 1062 | &priv->params); | 1079 | tda998x_configure_audio(priv, |
| 1080 | &priv->audio_params, | ||
| 1081 | adjusted_mode->clock); | ||
| 1082 | mutex_unlock(&priv->audio_mutex); | ||
| 1083 | } | ||
| 1063 | } | 1084 | } |
| 1064 | } | 1085 | } |
| 1065 | 1086 | ||
| @@ -1159,6 +1180,8 @@ static int tda998x_connector_get_modes(struct drm_connector *connector) | |||
| 1159 | drm_mode_connector_update_edid_property(connector, edid); | 1180 | drm_mode_connector_update_edid_property(connector, edid); |
| 1160 | n = drm_add_edid_modes(connector, edid); | 1181 | n = drm_add_edid_modes(connector, edid); |
| 1161 | priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); | 1182 | priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); |
| 1183 | drm_edid_to_eld(connector, edid); | ||
| 1184 | |||
| 1162 | kfree(edid); | 1185 | kfree(edid); |
| 1163 | 1186 | ||
| 1164 | return n; | 1187 | return n; |
| @@ -1180,6 +1203,9 @@ static void tda998x_destroy(struct tda998x_priv *priv) | |||
| 1180 | cec_write(priv, REG_CEC_RXSHPDINTENA, 0); | 1203 | cec_write(priv, REG_CEC_RXSHPDINTENA, 0); |
| 1181 | reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); | 1204 | reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); |
| 1182 | 1205 | ||
| 1206 | if (priv->audio_pdev) | ||
| 1207 | platform_device_unregister(priv->audio_pdev); | ||
| 1208 | |||
| 1183 | if (priv->hdmi->irq) | 1209 | if (priv->hdmi->irq) |
| 1184 | free_irq(priv->hdmi->irq, priv); | 1210 | free_irq(priv->hdmi->irq, priv); |
| 1185 | 1211 | ||
| @@ -1189,8 +1215,189 @@ static void tda998x_destroy(struct tda998x_priv *priv) | |||
| 1189 | i2c_unregister_device(priv->cec); | 1215 | i2c_unregister_device(priv->cec); |
| 1190 | } | 1216 | } |
| 1191 | 1217 | ||
| 1218 | static int tda998x_audio_hw_params(struct device *dev, void *data, | ||
| 1219 | struct hdmi_codec_daifmt *daifmt, | ||
| 1220 | struct hdmi_codec_params *params) | ||
| 1221 | { | ||
| 1222 | struct tda998x_priv *priv = dev_get_drvdata(dev); | ||
| 1223 | int i, ret; | ||
| 1224 | struct tda998x_audio_params audio = { | ||
| 1225 | .sample_width = params->sample_width, | ||
| 1226 | .sample_rate = params->sample_rate, | ||
| 1227 | .cea = params->cea, | ||
| 1228 | }; | ||
| 1229 | |||
| 1230 | if (!priv->encoder.crtc) | ||
| 1231 | return -ENODEV; | ||
| 1232 | |||
| 1233 | memcpy(audio.status, params->iec.status, | ||
| 1234 | min(sizeof(audio.status), sizeof(params->iec.status))); | ||
| 1235 | |||
| 1236 | switch (daifmt->fmt) { | ||
| 1237 | case HDMI_I2S: | ||
| 1238 | if (daifmt->bit_clk_inv || daifmt->frame_clk_inv || | ||
| 1239 | daifmt->bit_clk_master || daifmt->frame_clk_master) { | ||
| 1240 | dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, | ||
| 1241 | daifmt->bit_clk_inv, daifmt->frame_clk_inv, | ||
| 1242 | daifmt->bit_clk_master, | ||
| 1243 | daifmt->frame_clk_master); | ||
| 1244 | return -EINVAL; | ||
| 1245 | } | ||
| 1246 | for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) | ||
| 1247 | if (priv->audio_port[i].format == AFMT_I2S) | ||
| 1248 | audio.config = priv->audio_port[i].config; | ||
| 1249 | audio.format = AFMT_I2S; | ||
| 1250 | break; | ||
| 1251 | case HDMI_SPDIF: | ||
| 1252 | for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) | ||
| 1253 | if (priv->audio_port[i].format == AFMT_SPDIF) | ||
| 1254 | audio.config = priv->audio_port[i].config; | ||
| 1255 | audio.format = AFMT_SPDIF; | ||
| 1256 | break; | ||
| 1257 | default: | ||
| 1258 | dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); | ||
| 1259 | return -EINVAL; | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | if (audio.config == 0) { | ||
| 1263 | dev_err(dev, "%s: No audio configutation found\n", __func__); | ||
| 1264 | return -EINVAL; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | mutex_lock(&priv->audio_mutex); | ||
| 1268 | ret = tda998x_configure_audio(priv, | ||
| 1269 | &audio, | ||
| 1270 | priv->encoder.crtc->hwmode.clock); | ||
| 1271 | |||
| 1272 | if (ret == 0) | ||
| 1273 | priv->audio_params = audio; | ||
| 1274 | mutex_unlock(&priv->audio_mutex); | ||
| 1275 | |||
| 1276 | return ret; | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | static void tda998x_audio_shutdown(struct device *dev, void *data) | ||
| 1280 | { | ||
| 1281 | struct tda998x_priv *priv = dev_get_drvdata(dev); | ||
| 1282 | |||
| 1283 | mutex_lock(&priv->audio_mutex); | ||
| 1284 | |||
| 1285 | reg_write(priv, REG_ENA_AP, 0); | ||
| 1286 | |||
| 1287 | priv->audio_params.format = AFMT_UNUSED; | ||
| 1288 | |||
| 1289 | mutex_unlock(&priv->audio_mutex); | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable) | ||
| 1293 | { | ||
| 1294 | struct tda998x_priv *priv = dev_get_drvdata(dev); | ||
| 1295 | |||
| 1296 | mutex_lock(&priv->audio_mutex); | ||
| 1297 | |||
| 1298 | tda998x_audio_mute(priv, enable); | ||
| 1299 | |||
| 1300 | mutex_unlock(&priv->audio_mutex); | ||
| 1301 | return 0; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | static int tda998x_audio_get_eld(struct device *dev, void *data, | ||
| 1305 | uint8_t *buf, size_t len) | ||
| 1306 | { | ||
| 1307 | struct tda998x_priv *priv = dev_get_drvdata(dev); | ||
| 1308 | struct drm_mode_config *config = &priv->encoder.dev->mode_config; | ||
| 1309 | struct drm_connector *connector; | ||
| 1310 | int ret = -ENODEV; | ||
| 1311 | |||
| 1312 | mutex_lock(&config->mutex); | ||
| 1313 | list_for_each_entry(connector, &config->connector_list, head) { | ||
| 1314 | if (&priv->encoder == connector->encoder) { | ||
| 1315 | memcpy(buf, connector->eld, | ||
| 1316 | min(sizeof(connector->eld), len)); | ||
| 1317 | ret = 0; | ||
| 1318 | } | ||
| 1319 | } | ||
| 1320 | mutex_unlock(&config->mutex); | ||
| 1321 | |||
| 1322 | return ret; | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | static const struct hdmi_codec_ops audio_codec_ops = { | ||
| 1326 | .hw_params = tda998x_audio_hw_params, | ||
| 1327 | .audio_shutdown = tda998x_audio_shutdown, | ||
| 1328 | .digital_mute = tda998x_audio_digital_mute, | ||
| 1329 | .get_eld = tda998x_audio_get_eld, | ||
| 1330 | }; | ||
| 1331 | |||
| 1332 | static int tda998x_audio_codec_init(struct tda998x_priv *priv, | ||
| 1333 | struct device *dev) | ||
| 1334 | { | ||
| 1335 | struct hdmi_codec_pdata codec_data = { | ||
| 1336 | .ops = &audio_codec_ops, | ||
| 1337 | .max_i2s_channels = 2, | ||
| 1338 | }; | ||
| 1339 | int i; | ||
| 1340 | |||
| 1341 | for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) { | ||
| 1342 | if (priv->audio_port[i].format == AFMT_I2S && | ||
| 1343 | priv->audio_port[i].config != 0) | ||
| 1344 | codec_data.i2s = 1; | ||
| 1345 | if (priv->audio_port[i].format == AFMT_SPDIF && | ||
| 1346 | priv->audio_port[i].config != 0) | ||
| 1347 | codec_data.spdif = 1; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | priv->audio_pdev = platform_device_register_data( | ||
| 1351 | dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, | ||
| 1352 | &codec_data, sizeof(codec_data)); | ||
| 1353 | |||
| 1354 | return PTR_ERR_OR_ZERO(priv->audio_pdev); | ||
| 1355 | } | ||
| 1356 | |||
| 1192 | /* I2C driver functions */ | 1357 | /* I2C driver functions */ |
| 1193 | 1358 | ||
| 1359 | static int tda998x_get_audio_ports(struct tda998x_priv *priv, | ||
| 1360 | struct device_node *np) | ||
| 1361 | { | ||
| 1362 | const u32 *port_data; | ||
| 1363 | u32 size; | ||
| 1364 | int i; | ||
| 1365 | |||
| 1366 | port_data = of_get_property(np, "audio-ports", &size); | ||
| 1367 | if (!port_data) | ||
| 1368 | return 0; | ||
| 1369 | |||
| 1370 | size /= sizeof(u32); | ||
| 1371 | if (size > 2 * ARRAY_SIZE(priv->audio_port) || size % 2 != 0) { | ||
| 1372 | dev_err(&priv->hdmi->dev, | ||
| 1373 | "Bad number of elements in audio-ports dt-property\n"); | ||
| 1374 | return -EINVAL; | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | size /= 2; | ||
| 1378 | |||
| 1379 | for (i = 0; i < size; i++) { | ||
| 1380 | u8 afmt = be32_to_cpup(&port_data[2*i]); | ||
| 1381 | u8 ena_ap = be32_to_cpup(&port_data[2*i+1]); | ||
| 1382 | |||
| 1383 | if (afmt != AFMT_SPDIF && afmt != AFMT_I2S) { | ||
| 1384 | dev_err(&priv->hdmi->dev, | ||
| 1385 | "Bad audio format %u\n", afmt); | ||
| 1386 | return -EINVAL; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | priv->audio_port[i].format = afmt; | ||
| 1390 | priv->audio_port[i].config = ena_ap; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | if (priv->audio_port[0].format == priv->audio_port[1].format) { | ||
| 1394 | dev_err(&priv->hdmi->dev, | ||
| 1395 | "There can only be on I2S port and one SPDIF port\n"); | ||
| 1396 | return -EINVAL; | ||
| 1397 | } | ||
| 1398 | return 0; | ||
| 1399 | } | ||
| 1400 | |||
| 1194 | static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) | 1401 | static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) |
| 1195 | { | 1402 | { |
| 1196 | struct device_node *np = client->dev.of_node; | 1403 | struct device_node *np = client->dev.of_node; |
| @@ -1304,7 +1511,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) | |||
| 1304 | if (!np) | 1511 | if (!np) |
| 1305 | return 0; /* non-DT */ | 1512 | return 0; /* non-DT */ |
| 1306 | 1513 | ||
| 1307 | /* get the optional video properties */ | 1514 | /* get the device tree parameters */ |
| 1308 | ret = of_property_read_u32(np, "video-ports", &video); | 1515 | ret = of_property_read_u32(np, "video-ports", &video); |
| 1309 | if (ret == 0) { | 1516 | if (ret == 0) { |
| 1310 | priv->vip_cntrl_0 = video >> 16; | 1517 | priv->vip_cntrl_0 = video >> 16; |
| @@ -1312,8 +1519,16 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) | |||
| 1312 | priv->vip_cntrl_2 = video; | 1519 | priv->vip_cntrl_2 = video; |
| 1313 | } | 1520 | } |
| 1314 | 1521 | ||
| 1315 | return 0; | 1522 | mutex_init(&priv->audio_mutex); /* Protect access from audio thread */ |
| 1316 | 1523 | ||
| 1524 | ret = tda998x_get_audio_ports(priv, np); | ||
| 1525 | if (ret) | ||
| 1526 | goto fail; | ||
| 1527 | |||
| 1528 | if (priv->audio_port[0].format != AFMT_UNUSED) | ||
| 1529 | tda998x_audio_codec_init(priv, &client->dev); | ||
| 1530 | |||
| 1531 | return 0; | ||
| 1317 | fail: | 1532 | fail: |
| 1318 | /* if encoder_init fails, the encoder slave is never registered, | 1533 | /* if encoder_init fails, the encoder slave is never registered, |
| 1319 | * so cleanup here: | 1534 | * so cleanup here: |
