Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 5b04644a authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'asoc/topic/max98925', 'asoc/topic/max98927',...

Merge remote-tracking branches 'asoc/topic/max98925', 'asoc/topic/max98927', 'asoc/topic/msm8916' and 'asoc/topic/omap' into asoc-next
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -579,7 +579,7 @@ static int max98925_i2c_probe(struct i2c_client *i2c,
		ret = PTR_ERR(max98925->regmap);
		dev_err(&i2c->dev,
				"Failed to allocate regmap: %d\n", ret);
		goto err_out;
		return ret;
	}

	if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
@@ -596,16 +596,20 @@ static int max98925_i2c_probe(struct i2c_client *i2c,
		}
		max98925->i_slot = value;
	}
	ret = regmap_read(max98925->regmap,
			MAX98925_REV_VERSION, &reg);
	if ((ret < 0) ||
		((reg != MAX98925_VERSION) &&
		(reg != MAX98925_VERSION1))) {
		dev_err(&i2c->dev,
			"device initialization error (%d 0x%02X)\n",

	ret = regmap_read(max98925->regmap, MAX98925_REV_VERSION, &reg);
	if (ret < 0) {
		dev_err(&i2c->dev, "Read revision failed\n");
		return ret;
	}

	if ((reg != MAX98925_VERSION) && (reg != MAX98925_VERSION1)) {
		ret = -ENODEV;
		dev_err(&i2c->dev, "Invalid revision (%d 0x%02X)\n",
			ret, reg);
		goto err_out;
		return ret;
	}

	dev_info(&i2c->dev, "device version 0x%02X\n", reg);

	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925,
@@ -613,7 +617,6 @@ static int max98925_i2c_probe(struct i2c_client *i2c,
	if (ret < 0)
		dev_err(&i2c->dev,
				"Failed to register codec: %d\n", ret);
err_out:
	return ret;
}

+124 −31
Original line number Diff line number Diff line
/*
 * max98927.c  --  MAX98927 ALSA Soc Audio driver
 *
 * Copyright (C) 2016 Maxim Integrated Products
 * Copyright (C) 2016-2017 Maxim Integrated Products
 * Author: Ryan Lee <ryans.lee@maximintegrated.com>
 *
 *  This program is free software; you can redistribute  it and/or modify it
@@ -146,6 +146,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
	unsigned int mode = 0;
	unsigned int format = 0;
	bool use_pdm = false;
	unsigned int invert = 0;

	dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
@@ -187,22 +188,27 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
	/* interface format */
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		max98927->iface |= SND_SOC_DAIFMT_I2S;
		format = MAX98927_PCM_FORMAT_I2S;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
		format = MAX98927_PCM_FORMAT_LJ;
		break;
	case SND_SOC_DAIFMT_DSP_A:
		format = MAX98927_PCM_FORMAT_TDM_MODE1;
		break;
	case SND_SOC_DAIFMT_DSP_B:
		format = MAX98927_PCM_FORMAT_TDM_MODE0;
		break;
	case SND_SOC_DAIFMT_PDM:
		max98927->iface |= SND_SOC_DAIFMT_PDM;
		use_pdm = true;
		break;
	default:
		return -EINVAL;
	}
	max98927->iface = fmt & SND_SOC_DAIFMT_FORMAT_MASK;

	if (!use_pdm) {
		/* pcm channel configuration */
	if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
		regmap_update_bits(max98927->regmap,
			MAX98927_R0018_PCM_RX_EN_A,
			MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
@@ -217,13 +223,11 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
			MAX98927_R003B_SPK_SRC_SEL,
			MAX98927_SPK_SRC_MASK, 0);

	} else
		regmap_update_bits(max98927->regmap,
			MAX98927_R0018_PCM_RX_EN_A,
			MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);

			MAX98927_R0035_PDM_RX_CTRL,
			MAX98927_PDM_RX_EN_MASK, 0);
	} else {
		/* pdm channel configuration */
	if (max98927->iface & SND_SOC_DAIFMT_PDM) {
		regmap_update_bits(max98927->regmap,
			MAX98927_R0035_PDM_RX_CTRL,
			MAX98927_PDM_RX_EN_MASK, 1);
@@ -231,10 +235,11 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
		regmap_update_bits(max98927->regmap,
			MAX98927_R003B_SPK_SRC_SEL,
			MAX98927_SPK_SRC_MASK, 3);
	} else

		regmap_update_bits(max98927->regmap,
			MAX98927_R0035_PDM_RX_CTRL,
			MAX98927_PDM_RX_EN_MASK, 0);
			MAX98927_R0018_PCM_RX_EN_A,
			MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
	}
	return 0;
}

@@ -245,6 +250,21 @@ static const int rate_table[] = {
	13000000, 19200000,
};

/* BCLKs per LRCLK */
static const int bclk_sel_table[] = {
	32, 48, 64, 96, 128, 192, 256, 384, 512,
};

static int max98927_get_bclk_sel(int bclk)
{
	int i;
	/* match BCLKs per LRCLK */
	for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
		if (bclk_sel_table[i] == bclk)
			return i + 2;
	}
	return 0;
}
static int max98927_set_clock(struct max98927_priv *max98927,
	struct snd_pcm_hw_params *params)
{
@@ -270,23 +290,20 @@ static int max98927_set_clock(struct max98927_priv *max98927,
			i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
	}

	switch (blr_clk_ratio) {
	case 32:
		value = 2;
		break;
	case 48:
		value = 3;
		break;
	case 64:
		value = 4;
		break;
	default:
	if (!max98927->tdm_mode) {
		/* BCLK configuration */
		value = max98927_get_bclk_sel(blr_clk_ratio);
		if (!value) {
			dev_err(codec->dev, "format unsupported %d\n",
				params_format(params));
			return -EINVAL;
		}

		regmap_update_bits(max98927->regmap,
			MAX98927_R0022_PCM_CLK_SETUP,
			MAX98927_PCM_CLK_SETUP_BSEL_MASK,
			value);
	}
	return 0;
}

@@ -386,6 +403,78 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
	return -EINVAL;
}

static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
	unsigned int tx_mask, unsigned int rx_mask,
	int slots, int slot_width)
{
	struct snd_soc_codec *codec = dai->codec;
	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
	int bsel = 0;
	unsigned int chan_sz = 0;

	max98927->tdm_mode = true;

	/* BCLK configuration */
	bsel = max98927_get_bclk_sel(slots * slot_width);
	if (bsel == 0) {
		dev_err(codec->dev, "BCLK %d not supported\n",
			slots * slot_width);
		return -EINVAL;
	}

	regmap_update_bits(max98927->regmap,
		MAX98927_R0022_PCM_CLK_SETUP,
		MAX98927_PCM_CLK_SETUP_BSEL_MASK,
		bsel);

	/* Channel size configuration */
	switch (slot_width) {
	case 16:
		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
		break;
	case 24:
		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
		break;
	case 32:
		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
		break;
	default:
		dev_err(codec->dev, "format unsupported %d\n",
			slot_width);
		return -EINVAL;
	}

	regmap_update_bits(max98927->regmap,
		MAX98927_R0020_PCM_MODE_CFG,
		MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);

	/* Rx slot configuration */
	regmap_write(max98927->regmap,
		MAX98927_R0018_PCM_RX_EN_A,
		rx_mask & 0xFF);
	regmap_write(max98927->regmap,
		MAX98927_R0019_PCM_RX_EN_B,
		(rx_mask & 0xFF00) >> 8);

	/* Tx slot configuration */
	regmap_write(max98927->regmap,
		MAX98927_R001A_PCM_TX_EN_A,
		tx_mask & 0xFF);
	regmap_write(max98927->regmap,
		MAX98927_R001B_PCM_TX_EN_B,
		(tx_mask & 0xFF00) >> 8);

	/* Tx slot Hi-Z configuration */
	regmap_write(max98927->regmap,
		MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
		~tx_mask & 0xFF);
	regmap_write(max98927->regmap,
		MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
		(~tx_mask & 0xFF00) >> 8);

	return 0;
}

#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000

#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -405,6 +494,7 @@ static const struct snd_soc_dai_ops max98927_dai_ops = {
	.set_sysclk = max98927_dai_set_sysclk,
	.set_fmt = max98927_dai_set_fmt,
	.hw_params = max98927_dai_hw_params,
	.set_tdm_slot = max98927_dai_tdm_slot,
};

static int max98927_dac_event(struct snd_soc_dapm_widget *w,
@@ -414,6 +504,9 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		max98927->tdm_mode = 0;
		break;
	case SND_SOC_DAPM_POST_PMU:
		regmap_update_bits(max98927->regmap,
			MAX98927_R003A_AMP_EN,
+5 −2
Original line number Diff line number Diff line
/*
 * max98927.h  --  MAX98927 ALSA Soc Audio driver
 *
 * Copyright 2013-15 Maxim Integrated Products
 * Copyright (C) 2016-2017 Maxim Integrated Products
 * Author: Ryan Lee <ryans.lee@maximintegrated.com>
 *
 *  This program is free software; you can redistribute  it and/or modify it
@@ -161,7 +161,9 @@
#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3)
#define MAX98927_PCM_FORMAT_I2S (0x0 << 0)
#define MAX98927_PCM_FORMAT_LJ (0x1 << 0)

#define MAX98927_PCM_FORMAT_TDM_MODE0 (0x3 << 0)
#define MAX98927_PCM_FORMAT_TDM_MODE1 (0x4 << 0)
#define MAX98927_PCM_FORMAT_TDM_MODE2 (0x5 << 0)
#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
@@ -268,5 +270,6 @@ struct max98927_priv {
	unsigned int iface;
	unsigned int master;
	unsigned int digital_gain;
	bool tdm_mode;
};
#endif
+59 −53
Original line number Diff line number Diff line
@@ -285,7 +285,7 @@ struct pm8916_wcd_analog_priv {
	u16 codec_version;
	bool	mbhc_btn_enabled;
	/* special event to detect accessory type */
	bool	mbhc_btn0_pressed;
	int	mbhc_btn0_released;
	bool	detect_accessory_type;
	struct clk *mclk;
	struct snd_soc_codec *codec;
@@ -444,50 +444,6 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
						     wcd->micbias1_cap_mode);
}

static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
{
	struct snd_soc_codec *codec = wcd->codec;
	u32 plug_type = 0;
	u32 int_en_mask;

	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
		      CDC_A_MBHC_DET_CTL_L_DET_EN |
		      CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
		      CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
		      CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);

	if (wcd->hphl_jack_type_normally_open)
		plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;

	if (wcd->gnd_jack_type_normally_open)
		plug_type |= CDC_A_GND_PLUG_TYPE_NO;

	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
		      CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
		      CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
		      plug_type |
		      CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);


	snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
		      CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
		      CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);

	/* enable MBHC clock */
	snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
			    DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
			    DIG_CLK_CTL_D_MBHC_CLK_EN);

	int_en_mask = MBHC_SWITCH_INT;
	if (wcd->mbhc_btn_enabled)
		int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;

	snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
	snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
	wcd->mbhc_btn0_pressed = false;
	wcd->detect_accessory_type = true;
}

static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
				      bool micbias2_enabled)
{
@@ -535,6 +491,56 @@ static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
	return 0;
}

static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
{
	struct snd_soc_codec *codec = wcd->codec;
	bool micbias_enabled = false;
	u32 plug_type = 0;
	u32 int_en_mask;

	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
		      CDC_A_MBHC_DET_CTL_L_DET_EN |
		      CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
		      CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
		      CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);

	if (wcd->hphl_jack_type_normally_open)
		plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;

	if (wcd->gnd_jack_type_normally_open)
		plug_type |= CDC_A_GND_PLUG_TYPE_NO;

	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
		      CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
		      CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
		      plug_type |
		      CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);


	snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
		      CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
		      CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);

	/* enable MBHC clock */
	snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
			    DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
			    DIG_CLK_CTL_D_MBHC_CLK_EN);

	if (snd_soc_read(codec, CDC_A_MICB_2_EN) & CDC_A_MICB_2_EN_ENABLE)
		micbias_enabled = true;

	pm8916_mbhc_configure_bias(wcd, micbias_enabled);

	int_en_mask = MBHC_SWITCH_INT;
	if (wcd->mbhc_btn_enabled)
		int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;

	snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
	snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
	wcd->mbhc_btn0_released = false;
	wcd->detect_accessory_type = true;
}

static int pm8916_wcd_analog_enable_micbias_int2(struct
						  snd_soc_dapm_widget
						  *w, struct snd_kcontrol
@@ -952,7 +958,7 @@ static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)

		/* check if its BTN0 thats released */
		if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
			priv->mbhc_btn0_pressed = false;
			priv->mbhc_btn0_released = true;

	} else {
		snd_soc_jack_report(priv->jack, 0, btn_mask);
@@ -985,9 +991,7 @@ static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
		break;
	case 0x0:
		/* handle BTN_0 specially for type detection */
		if (priv->detect_accessory_type)
			priv->mbhc_btn0_pressed = true;
		else
		if (!priv->detect_accessory_type)
			snd_soc_jack_report(priv->jack,
					    SND_JACK_BTN_0, btn_mask);
		break;
@@ -1031,19 +1035,19 @@ static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
		 * both press and release event received then its
		 * a headset.
		 */
		if (priv->mbhc_btn0_pressed)
		if (priv->mbhc_btn0_released)
			snd_soc_jack_report(priv->jack,
					    SND_JACK_HEADPHONE, hs_jack_mask);
					    SND_JACK_HEADSET, hs_jack_mask);
		else
			snd_soc_jack_report(priv->jack,
					    SND_JACK_HEADSET, hs_jack_mask);
					    SND_JACK_HEADPHONE, hs_jack_mask);

		priv->detect_accessory_type = false;

	} else { /* removal */
		snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
		priv->detect_accessory_type = true;
		priv->mbhc_btn0_pressed = false;
		priv->mbhc_btn0_released = false;
	}

	return IRQ_HANDLED;
@@ -1243,6 +1247,8 @@ static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
	{ }
};

MODULE_DEVICE_TABLE(of, pm8916_wcd_analog_spmi_match_table);

static struct platform_driver pm8916_wcd_analog_spmi_driver = {
	.driver = {
		   .name = "qcom,pm8916-wcd-spmi-codec",
+3 −0
Original line number Diff line number Diff line
@@ -362,6 +362,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)

	card->name = devm_kasprintf(dev, GFP_KERNEL,
				    "HDMI %s", dev_name(ad->dssdev));
	if (!card->name)
		return -ENOMEM;

	card->owner = THIS_MODULE;
	card->dai_link =
		devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);