aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/atom/sst-atom-controls.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/atom/sst-atom-controls.c')
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c187
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
777int 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
790static 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
814static 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
834int 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 */
780static const struct sst_ssp_config sst_ssp_configs = { 892static 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
908void 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
794int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) 931int 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
835static int sst_set_be_modules(struct snd_soc_dapm_widget *w, 956static 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;