diff options
Diffstat (limited to 'sound/soc/omap/abe/abe_gain.c')
-rw-r--r-- | sound/soc/omap/abe/abe_gain.c | 790 |
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)); +} |