blob: 9c148da365cdd53ae9cdefb04cac420e09046d26 [file] [log] [blame]
/*
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));
}