Commit 9c894183 authored by allocom's avatar allocom Committed by Phil Elwell
Browse files

allo-piano-dac-plus: Master volume added

Master volume added, which controls both DACs volumes.

See: https://github.com/raspberrypi/linux/pull/2149
parent a6d7c735
Loading
Loading
Loading
Loading
+204 −24
Original line number Diff line number Diff line
@@ -28,6 +28,13 @@
#include <sound/tlv.h>
#include "../codecs/pcm512x.h"

#define P_DAC_LEFT_MUTE		0x10
#define P_DAC_RIGHT_MUTE	0x01
#define P_DAC_MUTE		0x11
#define P_DAC_UNMUTE		0x00
#define P_MUTE			1
#define P_UNMUTE		0

struct dsp_code {
	char i2c_addr;
	char offset;
@@ -129,16 +136,20 @@ static int __snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
		return 1;

	case 1: /* 2.0 */
		snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE, 0x00);
		snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE, 0x11);
		snd_soc_write(rtd->codec_dais[0]->codec,
				PCM512x_MUTE, P_DAC_UNMUTE);
		snd_soc_write(rtd->codec_dais[1]->codec,
				PCM512x_MUTE, P_DAC_MUTE);
		glb_ptr->set_rate = rate;
		glb_ptr->set_mode = mode;
		glb_ptr->set_lowpass = lowpass;
		return 1;

	default:
		snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE, 0x00);
		snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE, 0x00);
		snd_soc_write(rtd->codec_dais[0]->codec,
				PCM512x_MUTE, P_DAC_UNMUTE);
		snd_soc_write(rtd->codec_dais[1]->codec,
				PCM512x_MUTE, P_DAC_UNMUTE);
	}

	for (dac = 0; dac < rtd->num_codecs; dac++) {
@@ -211,8 +222,8 @@ static int snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,

	mutex_lock(&glb_ptr->lock);

	ret = __snd_allo_piano_dsp_program(rtd,
				mode, rate, lowpass);
	ret = __snd_allo_piano_dsp_program(rtd, mode, rate, lowpass);

	mutex_unlock(&glb_ptr->lock);

	return ret;
@@ -245,19 +256,20 @@ static int snd_allo_piano_dual_mode_put(struct snd_kcontrol *kcontrol,
	if (ucontrol->value.integer.value[0] > 0) {
		glb_ptr->dual_mode = ucontrol->value.integer.value[0];
		glb_ptr->set_mode = 0;
	} else if (ucontrol->value.integer.value[0] <= 0) {
	} else {
		if (glb_ptr->set_mode <= 0) {
			glb_ptr->dual_mode = 1;
			glb_ptr->set_mode = 0;
		}
		} else {
			glb_ptr->dual_mode = 0;
		return 0;
		}
	}

	if (glb_ptr->dual_mode == 1) {
		snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE, 0x01);
		snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE, 0x10);
	if (glb_ptr->dual_mode == 1) { // Dual Mono
		snd_soc_write(rtd->codec_dais[0]->codec,
				PCM512x_MUTE, P_DAC_RIGHT_MUTE);
		snd_soc_write(rtd->codec_dais[1]->codec,
				PCM512x_MUTE, P_DAC_LEFT_MUTE);
		snd_soc_write(rtd->codec_dais[0]->codec,
				PCM512x_DIGITAL_VOLUME_3, 0xff);
		snd_soc_write(rtd->codec_dais[1]->codec,
@@ -292,8 +304,10 @@ static int snd_allo_piano_dual_mode_put(struct snd_kcontrol *kcontrol,
				PCM512x_DIGITAL_VOLUME_3, left_val);
		snd_soc_write(rtd->codec_dais[1]->codec,
				PCM512x_DIGITAL_VOLUME_2, right_val);
		snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE, 0x00);
		snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE, 0x00);
		snd_soc_write(rtd->codec_dais[0]->codec,
				PCM512x_MUTE, P_DAC_UNMUTE);
		snd_soc_write(rtd->codec_dais[1]->codec,
				PCM512x_MUTE, P_DAC_UNMUTE);
	}

	return 0;
@@ -447,8 +461,10 @@ static int pcm512x_get_reg_sub_switch(struct snd_kcontrol *kcontrol,
	if (val < 0)
		return val;

	ucontrol->value.integer.value[0] = (val & 0x10) ? 0 : 1;
	ucontrol->value.integer.value[1] = (val & 0x01) ? 0 : 1;
	ucontrol->value.integer.value[0] =
			(val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
	ucontrol->value.integer.value[1] =
			(val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;

	return val;
}
@@ -474,7 +490,153 @@ static int pcm512x_set_reg_sub_switch(struct snd_kcontrol *kcontrol,

}

static int pcm512x_get_reg_master(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_value *ucontrol)
{
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
	struct glb_pool *glb_ptr = card->drvdata;
	struct snd_soc_pcm_runtime *rtd;
	unsigned int left_val = 0, right_val = 0;

	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);

	left_val = snd_soc_read(rtd->codec_dais[0]->codec,
			PCM512x_DIGITAL_VOLUME_2);
	if (left_val < 0)
		return left_val;

	if (glb_ptr->dual_mode == 1) {
		right_val = snd_soc_read(rtd->codec_dais[1]->codec,
				PCM512x_DIGITAL_VOLUME_3);
		if (right_val < 0)
			return right_val;
	} else {
		right_val = snd_soc_read(rtd->codec_dais[0]->codec,
				PCM512x_DIGITAL_VOLUME_3);
		if (right_val < 0)
			return right_val;
	}

	ucontrol->value.integer.value[0] =
		(~(left_val  >> mc->shift)) & mc->max;
	ucontrol->value.integer.value[1] =
		(~(right_val >> mc->shift)) & mc->max;

	return 0;
}

static int pcm512x_set_reg_master(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_value *ucontrol)
{
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
	struct glb_pool *glb_ptr = card->drvdata;
	struct snd_soc_pcm_runtime *rtd;
	unsigned int left_val = (ucontrol->value.integer.value[0] & mc->max);
	unsigned int right_val = (ucontrol->value.integer.value[1] & mc->max);
	int ret = 0;

	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);

	if (glb_ptr->dual_mode != 1) {
		ret = snd_soc_write(rtd->codec_dais[1]->codec,
				PCM512x_DIGITAL_VOLUME_2, (~left_val));
		if (ret < 0)
			return ret;

		ret = snd_soc_write(rtd->codec_dais[0]->codec,
				PCM512x_DIGITAL_VOLUME_3, (~right_val));
		if (ret < 0)
			return ret;

	}

	ret = snd_soc_write(rtd->codec_dais[1]->codec,
			PCM512x_DIGITAL_VOLUME_3, (~right_val));
	if (ret < 0)
		return ret;

	ret = snd_soc_write(rtd->codec_dais[0]->codec,
			PCM512x_DIGITAL_VOLUME_2, (~left_val));
	if (ret < 0)
		return ret;
	return 1;
}

static int pcm512x_get_reg_master_switch(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
	struct glb_pool *glb_ptr = card->drvdata;
	struct snd_soc_pcm_runtime *rtd;
	int val = 0;

	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);

	val = snd_soc_read(rtd->codec_dais[0]->codec, PCM512x_MUTE);
	if (val < 0)
		return val;

	ucontrol->value.integer.value[0] =
			(val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;

	if (glb_ptr->dual_mode == 1) {
		val = snd_soc_read(rtd->codec_dais[1]->codec, PCM512x_MUTE);
		if (val < 0)
			return val;
	}
	ucontrol->value.integer.value[1] =
			(val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;

	return val;
}

static int pcm512x_set_reg_master_switch(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
	struct snd_soc_pcm_runtime *rtd;
	struct glb_pool *glb_ptr = card->drvdata;
	unsigned int left_val = (ucontrol->value.integer.value[0]);
	unsigned int right_val = (ucontrol->value.integer.value[1]);
	int ret = 0;

	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
	if (glb_ptr->dual_mode == 1) {
		ret = snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE,
				~((left_val & 0x01)<<4));
		if (ret < 0)
			return ret;
		ret = snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE,
				~((right_val & 0x01)));
		if (ret < 0)
			return ret;

	} else if (glb_ptr->set_mode == 1) {
		ret = snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE,
				~((left_val & 0x01)<<4 | (right_val & 0x01)));
		if (ret < 0)
			return ret;

	} else {
		ret = snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE,
				~((left_val & 0x01)<<4 | (right_val & 0x01)));
		if (ret < 0)
			return ret;

		ret = snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE,
				~((left_val & 0x01)<<4 | (right_val & 0x01)));
		if (ret < 0)
			return ret;
	}
	return 1;
}

static const DECLARE_TLV_DB_SCALE(digital_tlv_sub, -10350, 50, 1);
static const DECLARE_TLV_DB_SCALE(digital_tlv_master, -10350, 50, 1);

static const struct snd_kcontrol_new allo_piano_controls[] = {
	SOC_ENUM_EXT("Subwoofer mode Route",
@@ -504,6 +666,20 @@ static const struct snd_kcontrol_new allo_piano_controls[] = {
			PCM512x_RQMR_SHIFT, 1, 1,
			pcm512x_get_reg_sub_switch,
			pcm512x_set_reg_sub_switch),

	SOC_DOUBLE_R_EXT_TLV("Master Playback Volume",
			PCM512x_DIGITAL_VOLUME_2,
			PCM512x_DIGITAL_VOLUME_3, 0, 255, 1,
			pcm512x_get_reg_master,
			pcm512x_set_reg_master,
			digital_tlv_master),

	SOC_DOUBLE_EXT("Master Playback Switch",
			PCM512x_MUTE,
			PCM512x_RQML_SHIFT,
			PCM512x_RQMR_SHIFT, 1, 1,
			pcm512x_get_reg_master_switch,
			pcm512x_set_reg_master_switch),
};

static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
@@ -535,19 +711,19 @@ static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
static void snd_allo_piano_gpio_mute(struct snd_soc_card *card)
{
	if (mute_gpio[0])
		gpiod_set_value_cansleep(mute_gpio[0], 1);
		gpiod_set_value_cansleep(mute_gpio[0], P_MUTE);

	if (mute_gpio[1])
		gpiod_set_value_cansleep(mute_gpio[1], 1);
		gpiod_set_value_cansleep(mute_gpio[1], P_MUTE);
}

static void snd_allo_piano_gpio_unmute(struct snd_soc_card *card)
{
	if (mute_gpio[0])
		gpiod_set_value_cansleep(mute_gpio[0], 0);
		gpiod_set_value_cansleep(mute_gpio[0], P_UNMUTE);

	if (mute_gpio[1])
		gpiod_set_value_cansleep(mute_gpio[1], 0);
		gpiod_set_value_cansleep(mute_gpio[1], P_UNMUTE);
}

static int snd_allo_piano_set_bias_level(struct snd_soc_card *card,
@@ -645,6 +821,10 @@ static int snd_allo_piano_dac_hw_params(
		if (ret < 0)
			dev_warn(card->dev, "Failed to set volume limit: %d\n",
				ret);
		ret = snd_soc_limit_volume(card, "Master Playback Volume", 207);
		if (ret < 0)
			dev_warn(card->dev, "Failed to set volume limit: %d\n",
				ret);
	}

	ret = snd_allo_piano_dsp_program(rtd, glb_ptr->set_mode, rate,