|
@@ -99,54 +99,93 @@ static int output_select_put(struct snd_kcontrol *ctl,
|
|
|
return changed;
|
|
|
}
|
|
|
|
|
|
-static int hp_volume_offset_info(struct snd_kcontrol *ctl,
|
|
|
- struct snd_ctl_elem_info *info)
|
|
|
+/* CS4245 Headphone Channels A&B Volume Control */
|
|
|
+
|
|
|
+static int hp_stereo_volume_info(struct snd_kcontrol *ctl,
|
|
|
+ struct snd_ctl_elem_info *info)
|
|
|
{
|
|
|
- static const char *const names[3] = {
|
|
|
- "< 64 ohms", "64-150 ohms", "150-300 ohms"
|
|
|
- };
|
|
|
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
|
|
+ info->count = 2;
|
|
|
+ info->value.integer.min = 0;
|
|
|
+ info->value.integer.max = 255;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- return snd_ctl_enum_info(info, 1, 3, names);
|
|
|
+static int hp_stereo_volume_get(struct snd_kcontrol *ctl,
|
|
|
+ struct snd_ctl_elem_value *val)
|
|
|
+{
|
|
|
+ struct oxygen *chip = ctl->private_data;
|
|
|
+ struct dg *data = chip->model_data;
|
|
|
+ unsigned int tmp;
|
|
|
+
|
|
|
+ mutex_lock(&chip->mutex);
|
|
|
+ tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
|
|
|
+ val->value.integer.value[0] = tmp;
|
|
|
+ tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
|
|
|
+ val->value.integer.value[1] = tmp;
|
|
|
+ mutex_unlock(&chip->mutex);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static int hp_volume_offset_get(struct snd_kcontrol *ctl,
|
|
|
- struct snd_ctl_elem_value *value)
|
|
|
+static int hp_stereo_volume_put(struct snd_kcontrol *ctl,
|
|
|
+ struct snd_ctl_elem_value *val)
|
|
|
{
|
|
|
struct oxygen *chip = ctl->private_data;
|
|
|
struct dg *data = chip->model_data;
|
|
|
+ int ret;
|
|
|
+ int changed = 0;
|
|
|
+ long new1 = val->value.integer.value[0];
|
|
|
+ long new2 = val->value.integer.value[1];
|
|
|
+
|
|
|
+ if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0))
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
mutex_lock(&chip->mutex);
|
|
|
- if (data->hp_vol_att > 2 * 7)
|
|
|
- value->value.enumerated.item[0] = 0;
|
|
|
- else if (data->hp_vol_att > 0)
|
|
|
- value->value.enumerated.item[0] = 1;
|
|
|
- else
|
|
|
- value->value.enumerated.item[0] = 2;
|
|
|
+ if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) ||
|
|
|
+ (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) {
|
|
|
+ data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1;
|
|
|
+ data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2;
|
|
|
+ ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL);
|
|
|
+ if (ret >= 0)
|
|
|
+ ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
|
|
|
+ changed = ret >= 0 ? 1 : ret;
|
|
|
+ }
|
|
|
+ mutex_unlock(&chip->mutex);
|
|
|
+
|
|
|
+ return changed;
|
|
|
+}
|
|
|
+
|
|
|
+/* Headphone Mute */
|
|
|
+
|
|
|
+static int hp_mute_get(struct snd_kcontrol *ctl,
|
|
|
+ struct snd_ctl_elem_value *val)
|
|
|
+{
|
|
|
+ struct oxygen *chip = ctl->private_data;
|
|
|
+ struct dg *data = chip->model_data;
|
|
|
+
|
|
|
+ mutex_lock(&chip->mutex);
|
|
|
+ val->value.integer.value[0] =
|
|
|
+ !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC);
|
|
|
mutex_unlock(&chip->mutex);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int hp_volume_offset_put(struct snd_kcontrol *ctl,
|
|
|
- struct snd_ctl_elem_value *value)
|
|
|
+static int hp_mute_put(struct snd_kcontrol *ctl,
|
|
|
+ struct snd_ctl_elem_value *val)
|
|
|
{
|
|
|
- static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
|
|
|
struct oxygen *chip = ctl->private_data;
|
|
|
struct dg *data = chip->model_data;
|
|
|
- s8 att;
|
|
|
+ int ret;
|
|
|
int changed;
|
|
|
|
|
|
- if (value->value.enumerated.item[0] > 2)
|
|
|
+ if (val->value.integer.value[0] > 1)
|
|
|
return -EINVAL;
|
|
|
- att = atts[value->value.enumerated.item[0]];
|
|
|
mutex_lock(&chip->mutex);
|
|
|
- changed = att != data->hp_vol_att;
|
|
|
- if (changed) {
|
|
|
- data->hp_vol_att = att;
|
|
|
- if (data->output_sel) {
|
|
|
- cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
|
|
|
- cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
|
|
|
- }
|
|
|
- }
|
|
|
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
|
|
|
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
|
|
|
+ (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
|
|
|
+ ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
|
|
|
+ changed = ret >= 0 ? 1 : ret;
|
|
|
mutex_unlock(&chip->mutex);
|
|
|
return changed;
|
|
|
}
|
|
@@ -312,6 +351,7 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
|
|
|
.tlv = { .p = cs4245_pga_db_scale }, \
|
|
|
.private_value = index, \
|
|
|
}
|
|
|
+static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0);
|
|
|
static const struct snd_kcontrol_new dg_controls[] = {
|
|
|
{
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
@@ -322,10 +362,21 @@ static const struct snd_kcontrol_new dg_controls[] = {
|
|
|
},
|
|
|
{
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
- .name = "Headphones Impedance Playback Enum",
|
|
|
- .info = hp_volume_offset_info,
|
|
|
- .get = hp_volume_offset_get,
|
|
|
- .put = hp_volume_offset_put,
|
|
|
+ .name = "Headphone Playback Volume",
|
|
|
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
|
|
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
|
|
+ .info = hp_stereo_volume_info,
|
|
|
+ .get = hp_stereo_volume_get,
|
|
|
+ .put = hp_stereo_volume_put,
|
|
|
+ .tlv = { .p = hp_db_scale, },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
+ .name = "Headphone Playback Switch",
|
|
|
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
|
|
+ .info = snd_ctl_boolean_mono_info,
|
|
|
+ .get = hp_mute_get,
|
|
|
+ .put = hp_mute_put,
|
|
|
},
|
|
|
INPUT_VOLUME("Mic Capture Volume", 0),
|
|
|
INPUT_VOLUME("Aux Capture Volume", 1),
|