aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/omap/abe/abe_gain.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/omap/abe/abe_gain.c')
-rw-r--r--sound/soc/omap/abe/abe_gain.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/sound/soc/omap/abe/abe_gain.c b/sound/soc/omap/abe/abe_gain.c
new file mode 100644
index 0000000..9c148da
--- /dev/null
+++ b/sound/soc/omap/abe/abe_gain.c
@@ -0,0 +1,790 @@
+/*
+
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright(c) 2010-2011 Texas Instruments Incorporated,
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ BSD LICENSE
+
+ Copyright(c) 2010-2011 Texas Instruments Incorporated,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "abe_dbg.h"
+#include "abe.h"
+#include "abe_gain.h"
+#include "abe_mem.h"
+
+/*
+ * ABE CONST AREA FOR PARAMETERS TRANSLATION
+ */
+#define min_mdb (-12000)
+#define max_mdb (3000)
+#define sizeof_db2lin_table (1 + ((max_mdb - min_mdb)/100))
+
+const u32 abe_db2lin_table[sizeof_db2lin_table] = {
+ 0x00000000, /* SMEM coding of -120 dB */
+ 0x00000000, /* SMEM coding of -119 dB */
+ 0x00000000, /* SMEM coding of -118 dB */
+ 0x00000000, /* SMEM coding of -117 dB */
+ 0x00000000, /* SMEM coding of -116 dB */
+ 0x00000000, /* SMEM coding of -115 dB */
+ 0x00000000, /* SMEM coding of -114 dB */
+ 0x00000000, /* SMEM coding of -113 dB */
+ 0x00000000, /* SMEM coding of -112 dB */
+ 0x00000000, /* SMEM coding of -111 dB */
+ 0x00000000, /* SMEM coding of -110 dB */
+ 0x00000000, /* SMEM coding of -109 dB */
+ 0x00000001, /* SMEM coding of -108 dB */
+ 0x00000001, /* SMEM coding of -107 dB */
+ 0x00000001, /* SMEM coding of -106 dB */
+ 0x00000001, /* SMEM coding of -105 dB */
+ 0x00000001, /* SMEM coding of -104 dB */
+ 0x00000001, /* SMEM coding of -103 dB */
+ 0x00000002, /* SMEM coding of -102 dB */
+ 0x00000002, /* SMEM coding of -101 dB */
+ 0x00000002, /* SMEM coding of -100 dB */
+ 0x00000002, /* SMEM coding of -99 dB */
+ 0x00000003, /* SMEM coding of -98 dB */
+ 0x00000003, /* SMEM coding of -97 dB */
+ 0x00000004, /* SMEM coding of -96 dB */
+ 0x00000004, /* SMEM coding of -95 dB */
+ 0x00000005, /* SMEM coding of -94 dB */
+ 0x00000005, /* SMEM coding of -93 dB */
+ 0x00000006, /* SMEM coding of -92 dB */
+ 0x00000007, /* SMEM coding of -91 dB */
+ 0x00000008, /* SMEM coding of -90 dB */
+ 0x00000009, /* SMEM coding of -89 dB */
+ 0x0000000A, /* SMEM coding of -88 dB */
+ 0x0000000B, /* SMEM coding of -87 dB */
+ 0x0000000D, /* SMEM coding of -86 dB */
+ 0x0000000E, /* SMEM coding of -85 dB */
+ 0x00000010, /* SMEM coding of -84 dB */
+ 0x00000012, /* SMEM coding of -83 dB */
+ 0x00000014, /* SMEM coding of -82 dB */
+ 0x00000017, /* SMEM coding of -81 dB */
+ 0x0000001A, /* SMEM coding of -80 dB */
+ 0x0000001D, /* SMEM coding of -79 dB */
+ 0x00000021, /* SMEM coding of -78 dB */
+ 0x00000025, /* SMEM coding of -77 dB */
+ 0x00000029, /* SMEM coding of -76 dB */
+ 0x0000002E, /* SMEM coding of -75 dB */
+ 0x00000034, /* SMEM coding of -74 dB */
+ 0x0000003A, /* SMEM coding of -73 dB */
+ 0x00000041, /* SMEM coding of -72 dB */
+ 0x00000049, /* SMEM coding of -71 dB */
+ 0x00000052, /* SMEM coding of -70 dB */
+ 0x0000005D, /* SMEM coding of -69 dB */
+ 0x00000068, /* SMEM coding of -68 dB */
+ 0x00000075, /* SMEM coding of -67 dB */
+ 0x00000083, /* SMEM coding of -66 dB */
+ 0x00000093, /* SMEM coding of -65 dB */
+ 0x000000A5, /* SMEM coding of -64 dB */
+ 0x000000B9, /* SMEM coding of -63 dB */
+ 0x000000D0, /* SMEM coding of -62 dB */
+ 0x000000E9, /* SMEM coding of -61 dB */
+ 0x00000106, /* SMEM coding of -60 dB */
+ 0x00000126, /* SMEM coding of -59 dB */
+ 0x0000014A, /* SMEM coding of -58 dB */
+ 0x00000172, /* SMEM coding of -57 dB */
+ 0x0000019F, /* SMEM coding of -56 dB */
+ 0x000001D2, /* SMEM coding of -55 dB */
+ 0x0000020B, /* SMEM coding of -54 dB */
+ 0x0000024A, /* SMEM coding of -53 dB */
+ 0x00000292, /* SMEM coding of -52 dB */
+ 0x000002E2, /* SMEM coding of -51 dB */
+ 0x0000033C, /* SMEM coding of -50 dB */
+ 0x000003A2, /* SMEM coding of -49 dB */
+ 0x00000413, /* SMEM coding of -48 dB */
+ 0x00000492, /* SMEM coding of -47 dB */
+ 0x00000521, /* SMEM coding of -46 dB */
+ 0x000005C2, /* SMEM coding of -45 dB */
+ 0x00000676, /* SMEM coding of -44 dB */
+ 0x0000073F, /* SMEM coding of -43 dB */
+ 0x00000822, /* SMEM coding of -42 dB */
+ 0x00000920, /* SMEM coding of -41 dB */
+ 0x00000A3D, /* SMEM coding of -40 dB */
+ 0x00000B7D, /* SMEM coding of -39 dB */
+ 0x00000CE4, /* SMEM coding of -38 dB */
+ 0x00000E76, /* SMEM coding of -37 dB */
+ 0x0000103A, /* SMEM coding of -36 dB */
+ 0x00001235, /* SMEM coding of -35 dB */
+ 0x0000146E, /* SMEM coding of -34 dB */
+ 0x000016EC, /* SMEM coding of -33 dB */
+ 0x000019B8, /* SMEM coding of -32 dB */
+ 0x00001CDC, /* SMEM coding of -31 dB */
+ 0x00002061, /* SMEM coding of -30 dB */
+ 0x00002455, /* SMEM coding of -29 dB */
+ 0x000028C4, /* SMEM coding of -28 dB */
+ 0x00002DBD, /* SMEM coding of -27 dB */
+ 0x00003352, /* SMEM coding of -26 dB */
+ 0x00003995, /* SMEM coding of -25 dB */
+ 0x0000409C, /* SMEM coding of -24 dB */
+ 0x0000487E, /* SMEM coding of -23 dB */
+ 0x00005156, /* SMEM coding of -22 dB */
+ 0x00005B43, /* SMEM coding of -21 dB */
+ 0x00006666, /* SMEM coding of -20 dB */
+ 0x000072E5, /* SMEM coding of -19 dB */
+ 0x000080E9, /* SMEM coding of -18 dB */
+ 0x000090A4, /* SMEM coding of -17 dB */
+ 0x0000A24B, /* SMEM coding of -16 dB */
+ 0x0000B618, /* SMEM coding of -15 dB */
+ 0x0000CC50, /* SMEM coding of -14 dB */
+ 0x0000E53E, /* SMEM coding of -13 dB */
+ 0x00010137, /* SMEM coding of -12 dB */
+ 0x0001209A, /* SMEM coding of -11 dB */
+ 0x000143D1, /* SMEM coding of -10 dB */
+ 0x00016B54, /* SMEM coding of -9 dB */
+ 0x000197A9, /* SMEM coding of -8 dB */
+ 0x0001C967, /* SMEM coding of -7 dB */
+ 0x00020137, /* SMEM coding of -6 dB */
+ 0x00023FD6, /* SMEM coding of -5 dB */
+ 0x00028619, /* SMEM coding of -4 dB */
+ 0x0002D4EF, /* SMEM coding of -3 dB */
+ 0x00032D64, /* SMEM coding of -2 dB */
+ 0x000390A4, /* SMEM coding of -1 dB */
+ 0x00040000, /* SMEM coding of 0 dB */
+ 0x00047CF2, /* SMEM coding of 1 dB */
+ 0x00050923, /* SMEM coding of 2 dB */
+ 0x0005A670, /* SMEM coding of 3 dB */
+ 0x000656EE, /* SMEM coding of 4 dB */
+ 0x00071CF5, /* SMEM coding of 5 dB */
+ 0x0007FB26, /* SMEM coding of 6 dB */
+ 0x0008F473, /* SMEM coding of 7 dB */
+ 0x000A0C2B, /* SMEM coding of 8 dB */
+ 0x000B4606, /* SMEM coding of 9 dB */
+ 0x000CA62C, /* SMEM coding of 10 dB */
+ 0x000E314A, /* SMEM coding of 11 dB */
+ 0x000FEC9E, /* SMEM coding of 12 dB */
+ 0x0011DE0A, /* SMEM coding of 13 dB */
+ 0x00140C28, /* SMEM coding of 14 dB */
+ 0x00167E60, /* SMEM coding of 15 dB */
+ 0x00193D00, /* SMEM coding of 16 dB */
+ 0x001C515D, /* SMEM coding of 17 dB */
+ 0x001FC5EB, /* SMEM coding of 18 dB */
+ 0x0023A668, /* SMEM coding of 19 dB */
+ 0x00280000, /* SMEM coding of 20 dB */
+ 0x002CE178, /* SMEM coding of 21 dB */
+ 0x00325B65, /* SMEM coding of 22 dB */
+ 0x00388062, /* SMEM coding of 23 dB */
+ 0x003F654E, /* SMEM coding of 24 dB */
+ 0x00472194, /* SMEM coding of 25 dB */
+ 0x004FCF7C, /* SMEM coding of 26 dB */
+ 0x00598C81, /* SMEM coding of 27 dB */
+ 0x006479B7, /* SMEM coding of 28 dB */
+ 0x0070BC3D, /* SMEM coding of 29 dB */
+ 0x007E7DB9, /* SMEM coding of 30 dB */
+};
+
+const u32 abe_1_alpha_iir[64] = {
+ 0x040002, 0x040002, 0x040002, 0x040002, /* 0 */
+ 0x50E955, 0x48CA65, 0x40E321, 0x72BE78, /* 1 [ms] */
+ 0x64BA68, 0x57DF14, 0x4C3D60, 0x41D690, /* 2 */
+ 0x38A084, 0x308974, 0x297B00, 0x235C7C, /* 4 */
+ 0x1E14B0, 0x198AF0, 0x15A800, 0x125660, /* 8 */
+ 0x0F82A0, 0x0D1B5C, 0x0B113C, 0x0956CC, /* 16 */
+ 0x07E054, 0x06A3B8, 0x059844, 0x04B680, /* 32 */
+ 0x03F80C, 0x035774, 0x02D018, 0x025E0C, /* 64 */
+ 0x7F8057, 0x6B482F, 0x5A4297, 0x4BEECB, /* 128 */
+ 0x3FE00B, 0x35BAA7, 0x2D3143, 0x2602AF, /* 256 */
+ 0x1FF803, 0x1AE2FB, 0x169C9F, 0x13042B, /* 512 */
+ 0x0FFE03, 0x0D72E7, 0x0B4F4F, 0x0982CB, /* 1.024 [s] */
+ 0x07FF83, 0x06B9CF, 0x05A7E7, 0x04C193, /* 2.048 */
+ 0x03FFE3, 0x035CFF, 0x02D403, 0x0260D7, /* 4.096 */
+ 0x01FFFB, 0x01AE87, 0x016A07, 0x01306F, /* 8.192 */
+ 0x00FFFF, 0x00D743, 0x00B503, 0x009837,
+};
+
+const u32 abe_alpha_iir[64] = {
+ 0x000000, 0x000000, 0x000000, 0x000000, /* 0 */
+ 0x5E2D58, 0x6E6B3C, 0x7E39C0, 0x46A0C5, /* 1 [ms] */
+ 0x4DA2CD, 0x541079, 0x59E151, 0x5F14B9, /* 2 */
+ 0x63AFC1, 0x67BB45, 0x6B4281, 0x6E51C1, /* 4 */
+ 0x70F5A9, 0x733A89, 0x752C01, 0x76D4D1, /* 8 */
+ 0x783EB1, 0x797251, 0x7A7761, 0x7B549D, /* 16 */
+ 0x7C0FD5, 0x7CAE25, 0x7D33DD, 0x7DA4C1, /* 32 */
+ 0x7E03FD, 0x7E5449, 0x7E97F5, 0x7ED0F9, /* 64 */
+ 0x7F0101, 0x7F2971, 0x7F4B7D, 0x7F6825, /* 128 */
+ 0x7F8041, 0x7F948D, 0x7FA59D, 0x7FB3FD, /* 256 */
+ 0x7FC011, 0x7FCA3D, 0x7FD2C9, 0x7FD9F9, /* 512 */
+ 0x7FE005, 0x7FE51D, 0x7FE961, 0x7FECFD, /* 1.024 [s] */
+ 0x7FF001, 0x7FF28D, 0x7FF4B1, 0x7FF67D, /* 2.048 */
+ 0x7FF801, 0x7FF949, 0x7FFA59, 0x7FFB41, /* 4.096 */
+ 0x7FFC01, 0x7FFCA5, 0x7FFD2D, 0x7FFDA1, /* 8.192 */
+ 0x7FFE01, 0x7FFE51, 0x7FFE95, 0x7FFED1,
+};
+
+/**
+ * abe_int_2_float
+ * returns a mantissa on 16 bits and the exponent
+ * 0x4000.0000 leads to M=0x4000 X=15
+ * 0x0004.0000 leads to M=0x4000 X=4
+ * 0x0000.0001 leads to M=0x4000 X=-14
+ *
+ */
+void abe_int_2_float16(u32 data, u32 *mantissa, u32 *exp)
+{
+ u32 i;
+ *exp = 0;
+ *mantissa = 0;
+ for (i = 0; i < 32; i++) {
+ if ((1 << i) > data)
+ break;
+ }
+ *exp = i - 15;
+ *mantissa = (*exp > 0) ? data >> (*exp) : data << (*exp);
+}
+
+/**
+ * abe_use_compensated_gain
+ * @on_off:
+ *
+ * Selects the automatic Mixer's gain management
+ * on_off = 1 allows the "abe_write_gain" to adjust the overall
+ * gains of the mixer to be tuned not to create saturation
+ */
+int omap_abe_use_compensated_gain(struct omap_abe *abe, int on_off)
+{
+ abe->compensated_mixer_gain = on_off;
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_use_compensated_gain);
+
+/**
+ * omap_abe_gain_offset
+ * returns the offset to firmware data structures
+ *
+ */
+void omap_abe_gain_offset(struct omap_abe *abe, u32 id, u32 *mixer_offset)
+{
+ switch (id) {
+ default:
+ case GAINS_DMIC1:
+ *mixer_offset = dmic1_gains_offset;
+ break;
+ case GAINS_DMIC2:
+ *mixer_offset = dmic2_gains_offset;
+ break;
+ case GAINS_DMIC3:
+ *mixer_offset = dmic3_gains_offset;
+ break;
+ case GAINS_AMIC:
+ *mixer_offset = amic_gains_offset;
+ break;
+ case GAINS_DL1:
+ *mixer_offset = dl1_gains_offset;
+ break;
+ case GAINS_DL2:
+ *mixer_offset = dl2_gains_offset;
+ break;
+ case GAINS_SPLIT:
+ *mixer_offset = splitters_gains_offset;
+ break;
+ case MIXDL1:
+ *mixer_offset = mixer_dl1_offset;
+ break;
+ case MIXDL2:
+ *mixer_offset = mixer_dl2_offset;
+ break;
+ case MIXECHO:
+ *mixer_offset = mixer_echo_offset;
+ break;
+ case MIXSDT:
+ *mixer_offset = mixer_sdt_offset;
+ break;
+ case MIXVXREC:
+ *mixer_offset = mixer_vxrec_offset;
+ break;
+ case MIXAUDUL:
+ *mixer_offset = mixer_audul_offset;
+ break;
+ case GAINS_BTUL:
+ *mixer_offset = btul_gains_offset;
+ break;
+ }
+}
+
+/**
+ * oamp_abe_write_equalizer
+ * @abe: Pointer on abe handle
+ * @id: name of the equalizer
+ * @param : equalizer coefficients
+ *
+ * Load the coefficients in CMEM.
+ */
+int omap_abe_write_equalizer(struct omap_abe *abe,
+ u32 id, struct omap_abe_equ *param)
+{
+ u32 eq_offset, length, *src, eq_mem, eq_mem_len;
+ _log(ABE_ID_WRITE_EQUALIZER, id, 0, 0);
+ switch (id) {
+ default:
+ case EQ1:
+ eq_offset = OMAP_ABE_C_DL1_COEFS_ADDR;
+ eq_mem = OMAP_ABE_S_DL1_M_EQ_DATA_ADDR;
+ eq_mem_len = OMAP_ABE_S_DL1_M_EQ_DATA_SIZE;
+ break;
+ case EQ2L:
+ eq_offset = OMAP_ABE_C_DL2_L_COEFS_ADDR;
+ eq_mem = OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR;
+ eq_mem_len = OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE;
+ break;
+ case EQ2R:
+ eq_offset = OMAP_ABE_C_DL2_R_COEFS_ADDR;
+ eq_mem = OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR;
+ eq_mem_len = OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE;
+ break;
+ case EQSDT:
+ eq_offset = OMAP_ABE_C_SDT_COEFS_ADDR;
+ eq_mem = OMAP_ABE_S_SDT_F_DATA_ADDR;
+ eq_mem_len = OMAP_ABE_S_SDT_F_DATA_SIZE;
+ break;
+ case EQAMIC:
+ eq_offset = OMAP_ABE_C_96_48_AMIC_COEFS_ADDR;
+ eq_mem = OMAP_ABE_S_AMIC_96_48_DATA_ADDR;
+ eq_mem_len = OMAP_ABE_S_AMIC_96_48_DATA_SIZE;
+ break;
+ case EQDMIC:
+ eq_offset = OMAP_ABE_C_96_48_DMIC_COEFS_ADDR;
+ eq_mem = OMAP_ABE_S_DMIC0_96_48_DATA_ADDR;
+ eq_mem_len = OMAP_ABE_S_DMIC0_96_48_DATA_SIZE;
+ /* three DMIC are clear at the same time DMIC0 DMIC1 DMIC2 */
+ eq_mem_len *= 3;
+ break;
+ }
+ /* reset SMEM buffers before the coefficients are loaded */
+ omap_abe_reset_mem(abe, OMAP_ABE_SMEM, eq_mem, eq_mem_len);
+
+ length = param->equ_length;
+ src = (u32 *) ((param->coef).type1);
+ /* translate in bytes */
+ length <<= 2;
+ omap_abe_mem_write(abe, OMAP_ABE_CMEM, eq_offset, src, length);
+
+ /* reset SMEM buffers after the coefficients are loaded */
+ omap_abe_reset_mem(abe, OMAP_ABE_SMEM, eq_mem, eq_mem_len);
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_write_equalizer);
+
+/**
+ * omap_abe_disable_gain
+ * @abe: Pointer on abe handle
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+int omap_abe_disable_gain(struct omap_abe *abe, u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ omap_abe_gain_offset(abe, id, &mixer_offset);
+ /* save the input parameters for mute/unmute */
+ ramp = abe->desired_ramp_delay_ms[mixer_offset + p];
+ f_g = GAIN_MUTE;
+ if (!(abe->muted_gains_indicator[mixer_offset + p] &
+ OMAP_ABE_GAIN_DISABLED)) {
+ /* Check if we are in mute */
+ if (!(abe->muted_gains_indicator[mixer_offset + p] &
+ OMAP_ABE_GAIN_MUTED)) {
+ abe->muted_gains_decibel[mixer_offset + p] =
+ abe->desired_gains_decibel[mixer_offset + p];
+ /* mute the gain */
+ omap_abe_write_gain(abe, id, f_g, ramp, p);
+ }
+ abe->muted_gains_indicator[mixer_offset + p] |=
+ OMAP_ABE_GAIN_DISABLED;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_disable_gain);
+
+/**
+ * omap_abe_enable_gain
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+int omap_abe_enable_gain(struct omap_abe *abe, u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ omap_abe_gain_offset(abe, id, &mixer_offset);
+ if ((abe->muted_gains_indicator[mixer_offset + p] &
+ OMAP_ABE_GAIN_DISABLED)) {
+ /* restore the input parameters for mute/unmute */
+ f_g = abe->muted_gains_decibel[mixer_offset + p];
+ ramp = abe->desired_ramp_delay_ms[mixer_offset + p];
+ abe->muted_gains_indicator[mixer_offset + p] &=
+ ~OMAP_ABE_GAIN_DISABLED;
+ /* unmute the gain */
+ omap_abe_write_gain(abe, id, f_g, ramp, p);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_enable_gain);
+/**
+ * omap_abe_mute_gain
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+int omap_abe_mute_gain(struct omap_abe *abe, u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ omap_abe_gain_offset(abe, id, &mixer_offset);
+ /* save the input parameters for mute/unmute */
+ ramp = abe->desired_ramp_delay_ms[mixer_offset + p];
+ f_g = GAIN_MUTE;
+ if (!abe->muted_gains_indicator[mixer_offset + p]) {
+ abe->muted_gains_decibel[mixer_offset + p] =
+ abe->desired_gains_decibel[mixer_offset + p];
+ /* mute the gain */
+ omap_abe_write_gain(abe, id, f_g, ramp, p);
+ }
+ abe->muted_gains_indicator[mixer_offset + p] |= OMAP_ABE_GAIN_MUTED;
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_mute_gain);
+/**
+ * omap_abe_unmute_gain
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+int omap_abe_unmute_gain(struct omap_abe *abe, u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ omap_abe_gain_offset(abe, id, &mixer_offset);
+ if ((abe->muted_gains_indicator[mixer_offset + p] &
+ OMAP_ABE_GAIN_MUTED)) {
+ /* restore the input parameters for mute/unmute */
+ f_g = abe->muted_gains_decibel[mixer_offset + p];
+ ramp = abe->desired_ramp_delay_ms[mixer_offset + p];
+ abe->muted_gains_indicator[mixer_offset + p] &=
+ ~OMAP_ABE_GAIN_MUTED;
+ /* unmute the gain */
+ omap_abe_write_gain(abe, id, f_g, ramp, p);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_unmute_gain);
+
+/**
+ * omap_abe_write_gain
+ * @id: gain name or mixer name
+ * @f_g: list of input gains of the mixer
+ * @ramp: gain ramp speed factor
+ * @p: list of ports corresponding to the above gains
+ *
+ * Loads the gain coefficients to FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's gain
+ * in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+int omap_abe_write_gain(struct omap_abe *abe,
+ u32 id, s32 f_g, u32 ramp, u32 p)
+{
+ u32 lin_g, sum_g, mixer_target, mixer_offset, i, mean_gain, mean_exp;
+ u32 new_gain_linear[4];
+ s32 gain_index;
+ u32 alpha, beta;
+ u32 ramp_index;
+
+ _log(ABE_ID_WRITE_GAIN, id, f_g, p);
+ gain_index = ((f_g - min_mdb) / 100);
+ gain_index = maximum(gain_index, 0);
+ gain_index = minimum(gain_index, sizeof_db2lin_table);
+ lin_g = abe_db2lin_table[gain_index];
+ omap_abe_gain_offset(abe, id, &mixer_offset);
+ /* save the input parameters for mute/unmute */
+ abe->desired_gains_linear[mixer_offset + p] = lin_g;
+ abe->desired_gains_decibel[mixer_offset + p] = f_g;
+ abe->desired_ramp_delay_ms[mixer_offset + p] = ramp;
+ /* SMEM address in bytes */
+ mixer_target = OMAP_ABE_S_GTARGET1_ADDR;
+ mixer_target += (mixer_offset<<2);
+ mixer_target += (p<<2);
+
+ if (abe->compensated_mixer_gain) {
+ switch (id) {
+ case MIXDL1:
+ case MIXDL2:
+ case MIXVXREC:
+ case MIXAUDUL:
+ /* compute the sum of the gain of the mixer */
+ for (sum_g = i = 0; i < 4; i++)
+ sum_g += abe->desired_gains_linear[mixer_offset +
+ i];
+ /* lets avoid a division by 0 */
+ if (sum_g == 0)
+ break;
+ /* if the sum is OK with less than 1, then
+ do not weight the gains */
+ if (sum_g < 0x00040000) { /* REMOVE HARD CONST */
+ /* recompute all gains from original
+ desired values */
+ sum_g = 0x00040000;
+ }
+ /* translate it in Q16 format for the later division */
+ abe_int_2_float16(sum_g, &mean_gain, &mean_exp);
+ mean_exp = 10 - mean_exp;
+ for (i = 0; i < 4; i++) {
+ /* new gain = desired gain divided by sum of gains */
+ new_gain_linear[i] =
+ (abe->desired_gains_linear
+ [mixer_offset + i]
+ << 8) / mean_gain;
+ new_gain_linear[i] = (mean_exp > 0) ?
+ new_gain_linear[i] << mean_exp :
+ new_gain_linear[i] >> mean_exp;
+ }
+ /* load the whole adpated S_G_Target SMEM MIXER table */
+ omap_abe_mem_write(abe, OMAP_ABE_SMEM,
+ mixer_target - (p << 2),
+ new_gain_linear, (4 * sizeof(lin_g)));
+ break;
+ default:
+ /* load the S_G_Target SMEM table */
+ omap_abe_mem_write(abe, OMAP_ABE_SMEM,
+ mixer_target,
+ (u32 *) &lin_g, sizeof(lin_g));
+ break;
+ }
+ } else {
+ if (!abe->muted_gains_indicator[mixer_offset + p])
+ /* load the S_G_Target SMEM table */
+ omap_abe_mem_write(abe, OMAP_ABE_SMEM,
+ mixer_target, (u32 *) &lin_g,
+ sizeof(lin_g));
+ else
+ /* update muted gain with new value */
+ abe->muted_gains_decibel[mixer_offset + p] = f_g;
+ }
+ ramp = maximum(minimum(RAMP_MAXLENGTH, ramp), RAMP_MINLENGTH);
+ /* ramp data should be interpolated in the table instead */
+ ramp_index = 3;
+ if ((RAMP_2MS <= ramp) && (ramp < RAMP_5MS))
+ ramp_index = 8;
+ if ((RAMP_5MS <= ramp) && (ramp < RAMP_50MS))
+ ramp_index = 24;
+ if ((RAMP_50MS <= ramp) && (ramp < RAMP_500MS))
+ ramp_index = 36;
+ if (ramp > RAMP_500MS)
+ ramp_index = 48;
+ beta = abe_alpha_iir[ramp_index];
+ alpha = abe_1_alpha_iir[ramp_index];
+ /* CMEM bytes address */
+ mixer_target = OMAP_ABE_C_1_ALPHA_ADDR;
+ /* a pair of gains is updated once in the firmware */
+ mixer_target += ((p + mixer_offset) >> 1) << 2;
+ /* load the ramp delay data */
+ omap_abe_mem_write(abe, OMAP_ABE_CMEM, mixer_target,
+ (u32 *) &alpha, sizeof(alpha));
+ /* CMEM bytes address */
+ mixer_target = OMAP_ABE_C_ALPHA_ADDR;
+ /* a pair of gains is updated once in the firmware */
+ mixer_target += ((p + mixer_offset) >> 1) << 2;
+ omap_abe_mem_write(abe, OMAP_ABE_CMEM, mixer_target,
+ (u32 *) &beta, sizeof(beta));
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_write_gain);
+/**
+ * omap_abe_write_mixer
+ * @id: name of the mixer
+ * @param: input gains and delay ramp of the mixer
+ * @p: port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's
+ * gain in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+int omap_abe_write_mixer(struct omap_abe *abe,
+ u32 id, s32 f_g, u32 f_ramp, u32 p)
+{
+ _log(ABE_ID_WRITE_MIXER, id, f_ramp, p);
+ omap_abe_write_gain(abe, id, f_g, f_ramp, p);
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_write_mixer);
+
+/**
+ * omap_abe_read_gain
+ * @id: name of the mixer
+ * @param: list of input gains of the mixer
+ * @p: list of port corresponding to the above gains
+ *
+ */
+int omap_abe_read_gain(struct omap_abe *abe,
+ u32 id, u32 *f_g, u32 p)
+{
+ u32 mixer_target, mixer_offset, i;
+ _log(ABE_ID_READ_GAIN, id, (u32) f_g, p);
+ omap_abe_gain_offset(abe, id, &mixer_offset);
+ /* SMEM bytes address */
+ mixer_target = OMAP_ABE_S_GTARGET1_ADDR;
+ mixer_target += (mixer_offset<<2);
+ mixer_target += (p<<2);
+ if (!abe->muted_gains_indicator[mixer_offset + p]) {
+ /* load the S_G_Target SMEM table */
+ omap_abe_mem_read(abe, OMAP_ABE_SMEM, mixer_target,
+ (u32 *) f_g, sizeof(*f_g));
+ for (i = 0; i < sizeof_db2lin_table; i++) {
+ if (abe_db2lin_table[i] == *f_g)
+ goto found;
+ }
+ *f_g = 0;
+ return -1;
+ found:
+ *f_g = (i * 100) + min_mdb;
+ } else {
+ /* update muted gain with new value */
+ *f_g = abe->muted_gains_decibel[mixer_offset + p];
+ }
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_read_gain);
+
+/**
+ * abe_read_mixer
+ * @id: name of the mixer
+ * @param: gains of the mixer
+ * @p: port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's
+ * gain in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+int omap_abe_read_mixer(struct omap_abe *abe,
+ u32 id, u32 *f_g, u32 p)
+{
+ _log(ABE_ID_READ_MIXER, id, 0, p);
+ omap_abe_read_gain(abe, id, f_g, p);
+ return 0;
+}
+EXPORT_SYMBOL(omap_abe_read_mixer);
+
+/**
+ * abe_reset_gain_mixer
+ * @id: name of the mixer
+ * @p: list of port corresponding to the above gains
+ *
+ * restart the working gain value of the mixers when a port is enabled
+ */
+void omap_abe_reset_gain_mixer(struct omap_abe *abe, u32 id, u32 p)
+{
+ u32 lin_g, mixer_target, mixer_offset;
+ switch (id) {
+ default:
+ case GAINS_DMIC1:
+ mixer_offset = dmic1_gains_offset;
+ break;
+ case GAINS_DMIC2:
+ mixer_offset = dmic2_gains_offset;
+ break;
+ case GAINS_DMIC3:
+ mixer_offset = dmic3_gains_offset;
+ break;
+ case GAINS_AMIC:
+ mixer_offset = amic_gains_offset;
+ break;
+ case GAINS_DL1:
+ mixer_offset = dl1_gains_offset;
+ break;
+ case GAINS_DL2:
+ mixer_offset = dl2_gains_offset;
+ break;
+ case GAINS_SPLIT:
+ mixer_offset = splitters_gains_offset;
+ break;
+ case MIXDL1:
+ mixer_offset = mixer_dl1_offset;
+ break;
+ case MIXDL2:
+ mixer_offset = mixer_dl2_offset;
+ break;
+ case MIXECHO:
+ mixer_offset = mixer_echo_offset;
+ break;
+ case MIXSDT:
+ mixer_offset = mixer_sdt_offset;
+ break;
+ case MIXVXREC:
+ mixer_offset = mixer_vxrec_offset;
+ break;
+ case MIXAUDUL:
+ mixer_offset = mixer_audul_offset;
+ break;
+ case GAINS_BTUL:
+ mixer_offset = btul_gains_offset;
+ break;
+ }
+ /* SMEM bytes address for the CURRENT gain values */
+ mixer_target = OMAP_ABE_S_GCURRENT_ADDR;
+ mixer_target += (mixer_offset<<2);
+ mixer_target += (p<<2);
+ lin_g = 0;
+ /* load the S_G_Target SMEM table */
+ omap_abe_mem_write(abe, OMAP_ABE_SMEM, mixer_target,
+ (u32 *) &lin_g, sizeof(lin_g));
+}