diff options
Diffstat (limited to 'drivers/staging/intel_sst/intelmid_ctrl.c')
-rw-r--r-- | drivers/staging/intel_sst/intelmid_ctrl.c | 304 |
1 files changed, 297 insertions, 7 deletions
diff --git a/drivers/staging/intel_sst/intelmid_ctrl.c b/drivers/staging/intel_sst/intelmid_ctrl.c index 69af0704ce94..19ec474b362a 100644 --- a/drivers/staging/intel_sst/intelmid_ctrl.c +++ b/drivers/staging/intel_sst/intelmid_ctrl.c @@ -29,17 +29,37 @@ #include <sound/core.h> #include <sound/control.h> -#include "jack.h" #include "intel_sst.h" #include "intel_sst_ioctl.h" #include "intelmid_snd_control.h" #include "intelmid.h" +#define HW_CH_BASE 4 + + +#define HW_CH_0 "Hw1" +#define HW_CH_1 "Hw2" +#define HW_CH_2 "Hw3" +#define HW_CH_3 "Hw4" + +static char *router_dmics[] = { "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", + "DMIC5", + "DMIC6" + }; + static char *out_names_mrst[] = {"Headphones", "Internal speakers"}; static char *in_names_mrst[] = {"AMIC", "DMIC", "HS_MIC"}; +static char *line_out_names_mfld[] = {"Headset", + "IHF ", + "Vibra1 ", + "Vibra2 ", + "NONE "}; static char *out_names_mfld[] = {"Headset ", "EarPiece "}; static char *in_names_mfld[] = {"AMIC", @@ -60,9 +80,11 @@ struct snd_control_val intelmad_ctrl_val[MAX_VENDORS] = { }, { .playback_vol_max = 0, - .playback_vol_min = -126, + .playback_vol_min = -31, .capture_vol_max = 0, .capture_vol_min = -31, + .master_vol_max = 0, + .master_vol_min = -126, }, }; @@ -139,6 +161,15 @@ static int snd_intelmad_playback_volume_info(struct snd_kcontrol *kcontrol, return 0; } +static int snd_intelmad_master_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + snd_intelmad_volume_info(uinfo, STEREO_CNTL, + intelmad_ctrl_val[sst_card_vendor_id].master_vol_max, + intelmad_ctrl_val[sst_card_vendor_id].master_vol_min); + return 0; +} + /** * snd_intelmad_device_info_mrst - provides information about the devices available * @@ -179,13 +210,27 @@ static int snd_intelmad_device_info_mrst(struct snd_kcontrol *kcontrol, static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + struct snd_pmic_ops *scard_ops; + struct snd_intelmad *intelmaddata; + WARN_ON(!kcontrol); WARN_ON(!uinfo); + + intelmaddata = kcontrol->private_data; + + WARN_ON(!intelmaddata->sstdrv_ops); + + scard_ops = intelmaddata->sstdrv_ops->scard_ops; /* setup device select as drop down controls with different values */ if (kcontrol->id.numid == OUTPUT_SEL) uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mfld); - else + else if (kcontrol->id.numid == INPUT_SEL) uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mfld); + else if (kcontrol->id.numid == LINEOUT_SEL_MFLD) { + uinfo->value.enumerated.items = ARRAY_SIZE(line_out_names_mfld); + scard_ops->line_out_names_cnt = uinfo->value.enumerated.items; + } else + return -EINVAL; uinfo->count = MONO_CNTL; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -195,10 +240,16 @@ static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol, strncpy(uinfo->value.enumerated.name, out_names_mfld[uinfo->value.enumerated.item], sizeof(uinfo->value.enumerated.name)-1); - else + else if (kcontrol->id.numid == INPUT_SEL) strncpy(uinfo->value.enumerated.name, in_names_mfld[uinfo->value.enumerated.item], sizeof(uinfo->value.enumerated.name)-1); + else if (kcontrol->id.numid == LINEOUT_SEL_MFLD) + strncpy(uinfo->value.enumerated.name, + line_out_names_mfld[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)-1); + else + return -EINVAL; return 0; } @@ -241,6 +292,11 @@ static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol, case CAPTURE_VOL: cntl_list[0] = PMIC_SND_CAPTURE_VOL; break; + + case MASTER_VOL: + cntl_list[0] = PMIC_SND_RIGHT_MASTER_VOL; + cntl_list[1] = PMIC_SND_LEFT_MASTER_VOL; + break; default: return -EINVAL; } @@ -251,7 +307,8 @@ static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol, if (ret_val) return ret_val; - if (kcontrol->id.numid == PLAYBACK_VOL) { + if (kcontrol->id.numid == PLAYBACK_VOL || + kcontrol->id.numid == MASTER_VOL) { ret_val = scard_ops->get_vol(cntl_list[1], &value); uval->value.integer.value[1] = value; } @@ -359,6 +416,12 @@ static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol, case CAPTURE_VOL: cntl_list[0] = PMIC_SND_CAPTURE_VOL; break; + + case MASTER_VOL: + cntl_list[0] = PMIC_SND_LEFT_MASTER_VOL; + cntl_list[1] = PMIC_SND_RIGHT_MASTER_VOL; + break; + default: return -EINVAL; } @@ -368,7 +431,8 @@ static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol, if (ret_val) return ret_val; - if (kcontrol->id.numid == PLAYBACK_VOL) + if (kcontrol->id.numid == PLAYBACK_VOL || + kcontrol->id.numid == MASTER_VOL) ret_val = scard_ops->set_vol(cntl_list[1], uval->value.integer.value[1]); return ret_val; @@ -464,14 +528,36 @@ static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol, WARN_ON(!kcontrol); intelmaddata = kcontrol->private_data; + scard_ops = intelmaddata->sstdrv_ops->scard_ops; if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) { - scard_ops = intelmaddata->sstdrv_ops->scard_ops; if (kcontrol->id.numid == OUTPUT_SEL) uval->value.enumerated.item[0] = scard_ops->output_dev_id; else if (kcontrol->id.numid == INPUT_SEL) uval->value.enumerated.item[0] = scard_ops->input_dev_id; + else if (kcontrol->id.numid == LINEOUT_SEL_MFLD) + uval->value.enumerated.item[0] = + scard_ops->lineout_dev_id; + else + return -EINVAL; + } else if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) { + if (kcontrol->id.numid == OUTPUT_SEL) + /* There is a mismatch here. + * ALSA expects 1 for internal speaker. + * But internally, we may give 2 for internal speaker. + */ + if (scard_ops->output_dev_id == MONO_EARPIECE || + scard_ops->output_dev_id == INTERNAL_SPKR) + uval->value.enumerated.item[0] = MONO_EARPIECE; + else if (scard_ops->output_dev_id == STEREO_HEADPHONE) + uval->value.enumerated.item[0] = + STEREO_HEADPHONE; + else + return -EINVAL; + else if (kcontrol->id.numid == INPUT_SEL) + uval->value.enumerated.item[0] = + scard_ops->input_dev_id; else return -EINVAL; } else @@ -534,6 +620,11 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol, uval->value.enumerated.item[0]); intelmaddata->input_sel = uval->value.enumerated.item[0]; break; + case LINEOUT_SEL_MFLD: + ret_val = scard_ops->set_lineout_dev( + uval->value.enumerated.item[0]); + intelmaddata->lineout_sel = uval->value.enumerated.item[0]; + break; default: return -EINVAL; } @@ -541,6 +632,151 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol, return ret_val; } +static int snd_intelmad_device_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uval) +{ + struct snd_intelmad *intelmaddata; + struct snd_pmic_ops *scard_ops; + + WARN_ON(!uval); + WARN_ON(!kcontrol); + + intelmaddata = kcontrol->private_data; + scard_ops = intelmaddata->sstdrv_ops->scard_ops; + + if (scard_ops->input_dev_id != DMIC) { + pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id); + return 0; + } + + if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) + uval->value.enumerated.item[0] = kcontrol->private_value; + else + pr_debug(" CPU id = 0x%xis invalid.\n", + intelmaddata->cpu_id); + return 0; +} + +void msic_set_bit(u8 index, unsigned int *available_dmics) +{ + *available_dmics |= (1 << index); +} + +void msic_clear_bit(u8 index, unsigned int *available_dmics) +{ + *available_dmics &= ~(1 << index); +} + +int msic_is_set_bit(u8 index, unsigned int *available_dmics) +{ + int ret_val; + + ret_val = (*available_dmics & (1 << index)); + return ret_val; +} + +static int snd_intelmad_device_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uval) +{ + struct snd_intelmad *intelmaddata; + struct snd_pmic_ops *scard_ops; + int i, dmic_index; + unsigned int available_dmics; + int jump_count; + int max_dmics = ARRAY_SIZE(router_dmics); + + WARN_ON(!uval); + WARN_ON(!kcontrol); + + intelmaddata = kcontrol->private_data; + WARN_ON(!intelmaddata->sstdrv_ops); + + scard_ops = intelmaddata->sstdrv_ops->scard_ops; + WARN_ON(!scard_ops); + + if (scard_ops->input_dev_id != DMIC) { + pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id); + return 0; + } + + available_dmics = scard_ops->available_dmics; + + if (kcontrol->private_value > uval->value.enumerated.item[0]) { + pr_debug("jump count -1.\n"); + jump_count = -1; + } else { + pr_debug("jump count 1.\n"); + jump_count = 1; + } + + dmic_index = uval->value.enumerated.item[0]; + pr_debug("set function. dmic_index = %d, avl_dmic = 0x%x\n", + dmic_index, available_dmics); + for (i = 0; i < max_dmics; i++) { + pr_debug("set function. loop index = 0x%x. dmic_index = 0x%x\n", + i, dmic_index); + if (!msic_is_set_bit(dmic_index, &available_dmics)) { + msic_clear_bit(kcontrol->private_value, + &available_dmics); + msic_set_bit(dmic_index, &available_dmics); + kcontrol->private_value = dmic_index; + scard_ops->available_dmics = available_dmics; + scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] = + kcontrol->private_value; + scard_ops->set_hw_dmic_route + (kcontrol->id.numid-HW_CH_BASE); + return 0; + } + + dmic_index += jump_count; + + if (dmic_index > (max_dmics - 1) && jump_count == 1) { + pr_debug("Resettingthe dmic index to 0.\n"); + dmic_index = 0; + } else if (dmic_index == -1 && jump_count == -1) { + pr_debug("Resetting the dmic index to 5.\n"); + dmic_index = max_dmics - 1; + } + } + + return -EINVAL; +} + +static int snd_intelmad_device_dmic_info_mfld(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_intelmad *intelmaddata; + struct snd_pmic_ops *scard_ops; + + uinfo->count = MONO_CNTL; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = ARRAY_SIZE(router_dmics); + + intelmaddata = kcontrol->private_data; + WARN_ON(!intelmaddata->sstdrv_ops); + + scard_ops = intelmaddata->sstdrv_ops->scard_ops; + WARN_ON(!scard_ops); + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + + strncpy(uinfo->value.enumerated.name, + router_dmics[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)-1); + + + msic_set_bit(kcontrol->private_value, &scard_ops->available_dmics); + pr_debug("info function. avl_dmic = 0x%x", + scard_ops->available_dmics); + + scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] = + kcontrol->private_value; + + return 0; +} + struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -598,6 +834,15 @@ struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_intelmad_master_volume_info, + .get = snd_intelmad_volume_get, + .put = snd_intelmad_volume_set, + .private_value = 0, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = snd_intelmad_mute_info, @@ -627,5 +872,50 @@ snd_intelmad_controls_mfld[MAX_CTRL_MFLD] __devinitdata = { .put = snd_intelmad_device_set, .private_value = 0, }, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line out", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_intelmad_device_info_mfld, + .get = snd_intelmad_device_get, + .put = snd_intelmad_device_set, + .private_value = 0, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = HW_CH_0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_intelmad_device_dmic_info_mfld, + .get = snd_intelmad_device_dmic_get, + .put = snd_intelmad_device_dmic_set, + .private_value = 0 +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = HW_CH_1, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_intelmad_device_dmic_info_mfld, + .get = snd_intelmad_device_dmic_get, + .put = snd_intelmad_device_dmic_set, + .private_value = 1 +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = HW_CH_2, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_intelmad_device_dmic_info_mfld, + .get = snd_intelmad_device_dmic_get, + .put = snd_intelmad_device_dmic_set, + .private_value = 2 +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = HW_CH_3, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_intelmad_device_dmic_info_mfld, + .get = snd_intelmad_device_dmic_get, + .put = snd_intelmad_device_dmic_set, + .private_value = 3 +} }; |