diff options
Diffstat (limited to 'sound/soc/intel/atom/sst-atom-controls.c')
-rw-r--r-- | sound/soc/intel/atom/sst-atom-controls.c | 187 |
1 files changed, 152 insertions, 35 deletions
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 90aa5c0476f3..31e9b9ecbb8a 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c | |||
@@ -774,8 +774,120 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) | |||
774 | return ret; | 774 | return ret; |
775 | } | 775 | } |
776 | 776 | ||
777 | int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
778 | unsigned int rx_mask, int slots, int slot_width) | ||
779 | { | ||
780 | struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); | ||
781 | |||
782 | ctx->ssp_cmd.nb_slots = slots; | ||
783 | ctx->ssp_cmd.active_tx_slot_map = tx_mask; | ||
784 | ctx->ssp_cmd.active_rx_slot_map = rx_mask; | ||
785 | ctx->ssp_cmd.nb_bits_per_slots = slot_width; | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int sst_get_frame_sync_polarity(struct snd_soc_dai *dai, | ||
791 | unsigned int fmt) | ||
792 | { | ||
793 | int format; | ||
794 | |||
795 | format = fmt & SND_SOC_DAIFMT_INV_MASK; | ||
796 | dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); | ||
797 | |||
798 | switch (format) { | ||
799 | case SND_SOC_DAIFMT_NB_NF: | ||
800 | return SSP_FS_ACTIVE_LOW; | ||
801 | case SND_SOC_DAIFMT_NB_IF: | ||
802 | return SSP_FS_ACTIVE_HIGH; | ||
803 | case SND_SOC_DAIFMT_IB_IF: | ||
804 | return SSP_FS_ACTIVE_LOW; | ||
805 | case SND_SOC_DAIFMT_IB_NF: | ||
806 | return SSP_FS_ACTIVE_HIGH; | ||
807 | default: | ||
808 | dev_err(dai->dev, "Invalid frame sync polarity %d\n", format); | ||
809 | } | ||
810 | |||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt) | ||
815 | { | ||
816 | int format; | ||
817 | |||
818 | format = (fmt & SND_SOC_DAIFMT_MASTER_MASK); | ||
819 | dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); | ||
820 | |||
821 | switch (format) { | ||
822 | case SND_SOC_DAIFMT_CBS_CFS: | ||
823 | return SSP_MODE_MASTER; | ||
824 | case SND_SOC_DAIFMT_CBM_CFM: | ||
825 | return SSP_MODE_SLAVE; | ||
826 | default: | ||
827 | dev_err(dai->dev, "Invalid ssp protocol: %d\n", format); | ||
828 | } | ||
829 | |||
830 | return -EINVAL; | ||
831 | } | ||
832 | |||
833 | |||
834 | int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt) | ||
835 | { | ||
836 | unsigned int mode; | ||
837 | int fs_polarity; | ||
838 | struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); | ||
839 | |||
840 | mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
841 | |||
842 | switch (mode) { | ||
843 | case SND_SOC_DAIFMT_DSP_B: | ||
844 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM; | ||
845 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1); | ||
846 | ctx->ssp_cmd.start_delay = 0; | ||
847 | ctx->ssp_cmd.data_polarity = 1; | ||
848 | ctx->ssp_cmd.frame_sync_width = 1; | ||
849 | break; | ||
850 | |||
851 | case SND_SOC_DAIFMT_DSP_A: | ||
852 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM; | ||
853 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1); | ||
854 | ctx->ssp_cmd.start_delay = 1; | ||
855 | ctx->ssp_cmd.data_polarity = 1; | ||
856 | ctx->ssp_cmd.frame_sync_width = 1; | ||
857 | break; | ||
858 | |||
859 | case SND_SOC_DAIFMT_I2S: | ||
860 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S; | ||
861 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1); | ||
862 | ctx->ssp_cmd.start_delay = 1; | ||
863 | ctx->ssp_cmd.data_polarity = 0; | ||
864 | ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots; | ||
865 | break; | ||
866 | |||
867 | case SND_SOC_DAIFMT_LEFT_J: | ||
868 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S; | ||
869 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1); | ||
870 | ctx->ssp_cmd.start_delay = 0; | ||
871 | ctx->ssp_cmd.data_polarity = 0; | ||
872 | ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots; | ||
873 | break; | ||
874 | |||
875 | default: | ||
876 | dev_dbg(dai->dev, "using default ssp configs\n"); | ||
877 | } | ||
878 | |||
879 | fs_polarity = sst_get_frame_sync_polarity(dai, fmt); | ||
880 | if (fs_polarity < 0) | ||
881 | return fs_polarity; | ||
882 | |||
883 | ctx->ssp_cmd.frame_sync_polarity = fs_polarity; | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
777 | /** | 888 | /** |
778 | * sst_ssp_config - contains SSP configuration for media UC | 889 | * sst_ssp_config - contains SSP configuration for media UC |
890 | * this can be overwritten by set_dai_xxx APIs | ||
779 | */ | 891 | */ |
780 | static const struct sst_ssp_config sst_ssp_configs = { | 892 | static const struct sst_ssp_config sst_ssp_configs = { |
781 | .ssp_id = SSP_CODEC, | 893 | .ssp_id = SSP_CODEC, |
@@ -789,47 +901,56 @@ static const struct sst_ssp_config sst_ssp_configs = { | |||
789 | .fs_frequency = SSP_FS_48_KHZ, | 901 | .fs_frequency = SSP_FS_48_KHZ, |
790 | .active_slot_map = 0xF, | 902 | .active_slot_map = 0xF, |
791 | .start_delay = 0, | 903 | .start_delay = 0, |
904 | .frame_sync_polarity = SSP_FS_ACTIVE_HIGH, | ||
905 | .data_polarity = 1, | ||
792 | }; | 906 | }; |
793 | 907 | ||
908 | void sst_fill_ssp_defaults(struct snd_soc_dai *dai) | ||
909 | { | ||
910 | const struct sst_ssp_config *config; | ||
911 | struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); | ||
912 | |||
913 | config = &sst_ssp_configs; | ||
914 | |||
915 | ctx->ssp_cmd.selection = config->ssp_id; | ||
916 | ctx->ssp_cmd.nb_bits_per_slots = config->bits_per_slot; | ||
917 | ctx->ssp_cmd.nb_slots = config->slots; | ||
918 | ctx->ssp_cmd.mode = config->ssp_mode | (config->pcm_mode << 1); | ||
919 | ctx->ssp_cmd.duplex = config->duplex; | ||
920 | ctx->ssp_cmd.active_tx_slot_map = config->active_slot_map; | ||
921 | ctx->ssp_cmd.active_rx_slot_map = config->active_slot_map; | ||
922 | ctx->ssp_cmd.frame_sync_frequency = config->fs_frequency; | ||
923 | ctx->ssp_cmd.frame_sync_polarity = config->frame_sync_polarity; | ||
924 | ctx->ssp_cmd.data_polarity = config->data_polarity; | ||
925 | ctx->ssp_cmd.frame_sync_width = config->fs_width; | ||
926 | ctx->ssp_cmd.ssp_protocol = config->ssp_protocol; | ||
927 | ctx->ssp_cmd.start_delay = config->start_delay; | ||
928 | ctx->ssp_cmd.reserved1 = ctx->ssp_cmd.reserved2 = 0xFF; | ||
929 | } | ||
930 | |||
794 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) | 931 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) |
795 | { | 932 | { |
796 | struct sst_cmd_sba_hw_set_ssp cmd; | ||
797 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | 933 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); |
798 | const struct sst_ssp_config *config; | 934 | const struct sst_ssp_config *config; |
799 | 935 | ||
800 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); | 936 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); |
801 | 937 | ||
802 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | 938 | SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst); |
803 | cmd.header.command_id = SBA_HW_SET_SSP; | 939 | drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP; |
804 | cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) | 940 | drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) |
805 | - sizeof(struct sst_dsp_header); | 941 | - sizeof(struct sst_dsp_header); |
806 | 942 | ||
807 | config = &sst_ssp_configs; | 943 | config = &sst_ssp_configs; |
808 | dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); | 944 | dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); |
809 | 945 | ||
810 | if (enable) | 946 | if (enable) |
811 | cmd.switch_state = SST_SWITCH_ON; | 947 | drv->ssp_cmd.switch_state = SST_SWITCH_ON; |
812 | else | 948 | else |
813 | cmd.switch_state = SST_SWITCH_OFF; | 949 | drv->ssp_cmd.switch_state = SST_SWITCH_OFF; |
814 | |||
815 | cmd.selection = config->ssp_id; | ||
816 | cmd.nb_bits_per_slots = config->bits_per_slot; | ||
817 | cmd.nb_slots = config->slots; | ||
818 | cmd.mode = config->ssp_mode | (config->pcm_mode << 1); | ||
819 | cmd.duplex = config->duplex; | ||
820 | cmd.active_tx_slot_map = config->active_slot_map; | ||
821 | cmd.active_rx_slot_map = config->active_slot_map; | ||
822 | cmd.frame_sync_frequency = config->fs_frequency; | ||
823 | cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH; | ||
824 | cmd.data_polarity = 1; | ||
825 | cmd.frame_sync_width = config->fs_width; | ||
826 | cmd.ssp_protocol = config->ssp_protocol; | ||
827 | cmd.start_delay = config->start_delay; | ||
828 | cmd.reserved1 = cmd.reserved2 = 0xFF; | ||
829 | 950 | ||
830 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | 951 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, |
831 | SST_TASK_SBA, 0, &cmd, | 952 | SST_TASK_SBA, 0, &drv->ssp_cmd, |
832 | sizeof(cmd.header) + cmd.header.length); | 953 | sizeof(drv->ssp_cmd.header) + drv->ssp_cmd.header.length); |
833 | } | 954 | } |
834 | 955 | ||
835 | static int sst_set_be_modules(struct snd_soc_dapm_widget *w, | 956 | static int sst_set_be_modules(struct snd_soc_dapm_widget *w, |
@@ -1280,36 +1401,32 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, | |||
1280 | down_read(&card->controls_rwsem); | 1401 | down_read(&card->controls_rwsem); |
1281 | 1402 | ||
1282 | list_for_each_entry(kctl, &card->controls, list) { | 1403 | list_for_each_entry(kctl, &card->controls, list) { |
1283 | idx = strstr(kctl->id.name, " "); | 1404 | idx = strchr(kctl->id.name, ' '); |
1284 | if (idx == NULL) | 1405 | if (idx == NULL) |
1285 | continue; | 1406 | continue; |
1286 | index = strlen(kctl->id.name) - strlen(idx); | 1407 | index = idx - (char*)kctl->id.name; |
1408 | if (strncmp(kctl->id.name, w->name, index)) | ||
1409 | continue; | ||
1287 | 1410 | ||
1288 | if (strstr(kctl->id.name, "Volume") && | 1411 | if (strstr(kctl->id.name, "Volume")) |
1289 | !strncmp(kctl->id.name, w->name, index)) | ||
1290 | ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN); | 1412 | ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN); |
1291 | 1413 | ||
1292 | else if (strstr(kctl->id.name, "params") && | 1414 | else if (strstr(kctl->id.name, "params")) |
1293 | !strncmp(kctl->id.name, w->name, index)) | ||
1294 | ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO); | 1415 | ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO); |
1295 | 1416 | ||
1296 | else if (strstr(kctl->id.name, "Switch") && | 1417 | else if (strstr(kctl->id.name, "Switch") && |
1297 | !strncmp(kctl->id.name, w->name, index) && | ||
1298 | strstr(kctl->id.name, "Gain")) { | 1418 | strstr(kctl->id.name, "Gain")) { |
1299 | struct sst_gain_mixer_control *mc = | 1419 | struct sst_gain_mixer_control *mc = |
1300 | (void *)kctl->private_value; | 1420 | (void *)kctl->private_value; |
1301 | 1421 | ||
1302 | mc->w = w; | 1422 | mc->w = w; |
1303 | 1423 | ||
1304 | } else if (strstr(kctl->id.name, "interleaver") && | 1424 | } else if (strstr(kctl->id.name, "interleaver")) { |
1305 | !strncmp(kctl->id.name, w->name, index)) { | ||
1306 | struct sst_enum *e = (void *)kctl->private_value; | 1425 | struct sst_enum *e = (void *)kctl->private_value; |
1307 | 1426 | ||
1308 | e->w = w; | 1427 | e->w = w; |
1309 | 1428 | ||
1310 | } else if (strstr(kctl->id.name, "deinterleaver") && | 1429 | } else if (strstr(kctl->id.name, "deinterleaver")) { |
1311 | !strncmp(kctl->id.name, w->name, index)) { | ||
1312 | |||
1313 | struct sst_enum *e = (void *)kctl->private_value; | 1430 | struct sst_enum *e = (void *)kctl->private_value; |
1314 | 1431 | ||
1315 | e->w = w; | 1432 | e->w = w; |