Merge remote-tracking branches 'asoc/topic/max98925', 'asoc/topic/max98927', 'asoc...
authorMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:31:20 +0000 (21:31 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:31:20 +0000 (21:31 +0000)
sound/soc/codecs/max98925.c
sound/soc/codecs/max98927.c
sound/soc/codecs/max98927.h
sound/soc/codecs/msm8916-wcd-analog.c
sound/soc/omap/omap-hdmi-audio.c

index 327eaa25c9bd798df29b7fe6b055127193899a9b..921f95fc396dbc04e2cc4f8fbe7a6b7dcd6abdd6 100644 (file)
@@ -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;
 }
 
index d9dbbe72f8ad4cb9cfbbccba06153359cc1529bc..a1d39353719d72cb4e3f0f1fcaa6b9b69d16acbf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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;
 
-       /* pcm channel configuration */
-       if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
+       if (!use_pdm) {
+               /* pcm channel configuration */
                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);
-
-       /* pdm channel configuration */
-       if (max98927->iface & SND_SOC_DAIFMT_PDM) {
+                       MAX98927_R0035_PDM_RX_CTRL,
+                       MAX98927_PDM_RX_EN_MASK, 0);
+       } else {
+               /* pdm channel configuration */
                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:
-               return -EINVAL;
+       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);
        }
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0022_PCM_CLK_SETUP,
-               MAX98927_PCM_CLK_SETUP_BSEL_MASK,
-               value);
        return 0;
 }
 
@@ -386,6 +403,78 @@ err:
        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,
index ece6a608cbe1ee65383aa9d4feef873110bc516a..9ea839735433d2c22d6cab24f9caf9d1478a10b2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
 #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
index 8d5821bddf58254a2876989233aee09077a7635b..5f3c42c4f74ad7d12d5c697c56e028c8329c48cb 100644 (file)
@@ -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",
index 3e9cc4842a1db14c2e8b0dc0a60dd462305f07aa..8eeac7cab1c1945742c5307d8b40b05f63842bfe 100644 (file)
@@ -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);