Merge remote-tracking branches 'asoc/topic/samsung', 'asoc/topic/sgtl5000' and 'asoc...
authorMark Brown <broonie@kernel.org>
Mon, 3 Jul 2017 15:15:19 +0000 (16:15 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 3 Jul 2017 15:15:19 +0000 (16:15 +0100)
Documentation/devicetree/bindings/sound/samsung,odroid.txt
sound/soc/codecs/sgtl5000.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/sh/fsi.c

index c1ac70cb0afb470d079d202a83fcbdc2ed227ce6..c30934dd975bd0bc4090370311bcbc49566c0a39 100644 (file)
@@ -5,11 +5,6 @@ Required properties:
  - compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board,
                "samsung,odroidxu4-audio" - for Odroid XU4 board
  - model - the user-visible name of this sound complex
- - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
-    controller
- - 'codec' subnode with a 'sound-dai' property containing list of phandles
-    to the CODEC nodes, first entry must be corresponding to the MAX98090
-    CODEC and the second entry must be the phandle of the HDMI IP block node
  - clocks - should contain entries matching clock names in the clock-names
     property
  - clock-names - should contain following entries:
@@ -32,12 +27,18 @@ Required properties:
    For Odroid XU4:
      no entries
 
+Required sub-nodes:
+
+ - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
+    controller
+ - 'codec' subnode with a 'sound-dai' property containing list of phandles
+    to the CODEC nodes, first entry must be corresponding to the MAX98090
+    CODEC and the second entry must be the phandle of the HDMI IP block node
+
 Example:
 
 sound {
        compatible = "samsung,odroidxu3-audio";
-       samsung,cpu-dai = <&i2s0>;
-       samsung,codec-dai = <&max98090>;
        model = "Odroid-XU3";
        samsung,audio-routing =
                "Headphone Jack", "HPL",
index 5a2702edeb7709b765d744c6db8f11992c36a1ff..8f6814c1eb6b34aa7b83c04c87594cca18b90152 100644 (file)
@@ -74,6 +74,20 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
        { SGTL5000_DAP_AVC_DECAY,               0x0050 },
 };
 
+/* AVC: Threshold dB -> register: pre-calculated values */
+static const u16 avc_thr_db2reg[97] = {
+       0x5168, 0x488E, 0x40AA, 0x39A1, 0x335D, 0x2DC7, 0x28CC, 0x245D, 0x2068,
+       0x1CE2, 0x19BE, 0x16F1, 0x1472, 0x1239, 0x103E, 0x0E7A, 0x0CE6, 0x0B7F,
+       0x0A3F, 0x0922, 0x0824, 0x0741, 0x0677, 0x05C3, 0x0522, 0x0493, 0x0414,
+       0x03A2, 0x033D, 0x02E3, 0x0293, 0x024B, 0x020B, 0x01D2, 0x019F, 0x0172,
+       0x014A, 0x0126, 0x0106, 0x00E9, 0x00D0, 0x00B9, 0x00A5, 0x0093, 0x0083,
+       0x0075, 0x0068, 0x005D, 0x0052, 0x0049, 0x0041, 0x003A, 0x0034, 0x002E,
+       0x0029, 0x0025, 0x0021, 0x001D, 0x001A, 0x0017, 0x0014, 0x0012, 0x0010,
+       0x000E, 0x000D, 0x000B, 0x000A, 0x0009, 0x0008, 0x0007, 0x0006, 0x0005,
+       0x0005, 0x0004, 0x0004, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, 0x0002,
+       0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
+
 /* regulator supplies for sgtl5000, VDDD is an optional external supply */
 enum sgtl5000_regulator_supplies {
        VDDA,
@@ -382,6 +396,65 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+/*
+ * custom function to get AVC threshold
+ *
+ * The threshold dB is calculated by rearranging the calculation from the
+ * avc_put_threshold function: register_value = 10^(dB/20) * 0.636 * 2^15 ==>
+ * dB = ( fls(register_value) - 14.347 ) * 6.02
+ *
+ * As this calculation is expensive and the threshold dB values may not exeed
+ * 0 to 96 we use pre-calculated values.
+ */
+static int avc_get_threshold(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int db, i;
+       u16 reg = snd_soc_read(codec, SGTL5000_DAP_AVC_THRESHOLD);
+
+       /* register value 0 => -96dB */
+       if (!reg) {
+               ucontrol->value.integer.value[0] = 96;
+               ucontrol->value.integer.value[1] = 96;
+               return 0;
+       }
+
+       /* get dB from register value (rounded down) */
+       for (i = 0; avc_thr_db2reg[i] > reg; i++)
+               ;
+       db = i;
+
+       ucontrol->value.integer.value[0] = db;
+       ucontrol->value.integer.value[1] = db;
+
+       return 0;
+}
+
+/*
+ * custom function to put AVC threshold
+ *
+ * The register value is calculated by following formula:
+ *                                    register_value = 10^(dB/20) * 0.636 * 2^15
+ * As this calculation is expensive and the threshold dB values may not exeed
+ * 0 to 96 we use pre-calculated values.
+ */
+static int avc_put_threshold(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int db;
+       u16 reg;
+
+       db = (int)ucontrol->value.integer.value[0];
+       if (db < 0 || db > 96)
+               return -EINVAL;
+       reg = avc_thr_db2reg[db];
+       snd_soc_write(codec, SGTL5000_DAP_AVC_THRESHOLD, reg);
+
+       return 0;
+}
+
 static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);
 
 /* tlv for mic gain, 0db 20db 30db 40db */
@@ -396,6 +469,12 @@ static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0);
 /* tlv for lineout volume, 31 steps of .5db each */
 static const DECLARE_TLV_DB_SCALE(lineout_volume, -1550, 50, 0);
 
+/* tlv for dap avc max gain, 0db, 6db, 12db */
+static const DECLARE_TLV_DB_SCALE(avc_max_gain, 0, 600, 0);
+
+/* tlv for dap avc threshold, */
+static const DECLARE_TLV_DB_MINMAX(avc_threshold, 0, 9600);
+
 static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
        /* SOC_DOUBLE_S8_TLV with invert */
        {
@@ -434,6 +513,16 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
                        0x1f, 1,
                        lineout_volume),
        SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1),
+
+       /* Automatic Volume Control (DAP AVC) */
+       SOC_SINGLE("AVC Switch", SGTL5000_DAP_AVC_CTRL, 0, 1, 0),
+       SOC_SINGLE("AVC Hard Limiter Switch", SGTL5000_DAP_AVC_CTRL, 5, 1, 0),
+       SOC_SINGLE_TLV("AVC Max Gain Volume", SGTL5000_DAP_AVC_CTRL, 12, 2, 0,
+                       avc_max_gain),
+       SOC_SINGLE("AVC Integrator Response", SGTL5000_DAP_AVC_CTRL, 8, 3, 0),
+       SOC_SINGLE_EXT_TLV("AVC Threshold Volume", SGTL5000_DAP_AVC_THRESHOLD,
+                       0, 96, 0, avc_get_threshold, avc_put_threshold,
+                       avc_threshold),
 };
 
 /* mute the codec used by alsa core */
index 81a78940967cb167f71bbfdac33c981bee6ab747..55538e333cc8958463b86500afc39fc11f546037 100644 (file)
@@ -44,7 +44,7 @@ struct s3c24xx_uda134x {
 
 static unsigned int rates[33 * 2];
 #ifdef ENFORCE_RATES
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
        .count  = ARRAY_SIZE(rates),
        .list   = rates,
        .mask   = 0,
index ead520182e2684fb4c8109f913e4148ecb4b2227..7c4bdd82bb955bbbd35d5c78f5bd780da4ef7178 100644 (file)
@@ -301,7 +301,12 @@ struct fsi_master {
        spinlock_t lock;
 };
 
-static int fsi_stream_is_play(struct fsi_priv *fsi, struct fsi_stream *io);
+static inline int fsi_stream_is_play(struct fsi_priv *fsi,
+                                    struct fsi_stream *io)
+{
+       return &fsi->playback == io;
+}
+
 
 /*
  *             basic read write function
@@ -489,12 +494,6 @@ static void fsi_count_fifo_err(struct fsi_priv *fsi)
 /*
  *             fsi_stream_xx() function
  */
-static inline int fsi_stream_is_play(struct fsi_priv *fsi,
-                                    struct fsi_stream *io)
-{
-       return &fsi->playback == io;
-}
-
 static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi,
                                        struct snd_pcm_substream *substream)
 {