/* * Copyright 2014,215 NXP Semiconductors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 or later * as published by the Free Software Foundation. */ #include "tfa_dsp_fw.h" #include "tfa_service.h" #include "tfa_internal.h" #include "tfa98xx_tfafieldnames.h" static enum tfa98xx_error tfa9895_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; int result; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; /* all i2C registers are already set to default */ result = TFA_SET_BF(handle, AMPE, 1); if (result < 0) return -result; /* some other registers must be set for optimal amplifier behaviour */ reg_write(handle, 0x05, 0x13AB); reg_write(handle, 0x06, 0x001F); /* peak voltage protection is always on, but may be written */ reg_write(handle, 0x08, 0x3C4E); /*TFA98XX_SYSCTRL_DCA=0*/ reg_write(handle, 0x09, 0x024D); reg_write(handle, 0x41, 0x0308); error = reg_write(handle, 0x49, 0x0E82); return error; } static enum tfa98xx_error tfa9890_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; unsigned short regRead = 0; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; /* all i2C registers are already set to default for N1C2 */ /* some PLL registers must be set optimal for amplifier behaviour */ error = reg_write(handle, 0x40, 0x5a6b); if (error) return error; reg_read(handle, 0x59, ®Read); regRead |= 0x3; reg_write(handle, 0x59, regRead); error = reg_write(handle, 0x40, 0x0000); error = reg_write(handle, 0x47, 0x7BE1); return error; } static enum tfa98xx_error tfa9891_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; /* ----- generated code start ----- */ /* ----- version 18.0 ----- */ reg_write(handle, 0x09, 0x025d); /* POR=0x024d */ reg_write(handle, 0x10, 0x0018); /* POR=0x0024 */ reg_write(handle, 0x22, 0x0003); /* POR=0x0023 */ reg_write(handle, 0x25, 0x0001); /* POR=0x0000 */ reg_write(handle, 0x46, 0x0000); /* POR=0x4000 */ reg_write(handle, 0x55, 0x3ffb); /* POR=0x7fff */ /* ----- generated code end ----- */ return error; } static enum tfa98xx_error tfa9896_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; unsigned short check_value; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; /* all i2C registers must already set to default POR value */ /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. * When Iddqtestbst is set to "0", the slewrate is reduced. * This will lower overshoot on IN-B to avoid NMOS damage of booster. */ /* ----- generated code start ----- */ /*v17*/ reg_write(handle, 0x06, 0x000b); /* POR=0x0001 */ reg_write(handle, 0x07, 0x3e7f); /* POR=0x1e7f */ reg_write(handle, 0x0a, 0x0d8a); /* POR=0x0592 */ reg_write(handle, 0x48, 0x0300); /* POR=0x0308 */ reg_write(handle, 0x88, 0x0100); /* POR=0x0000 */ /* ----- generated code end ----- */ /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ error = reg_read(handle, 0x49, &check_value); check_value &= ~0x1; error = reg_write(handle, 0x49, check_value); return error; } static enum tfa98xx_error tfa9897_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; unsigned short check_value; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; /* all i2C registers must already set to default POR value */ /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. * When Iddqtestbst is set to "0", the slewrate is reduced. * This will lower overshoot on IN-B to avoid NMOS damage of booster. */ error = reg_write(handle, 0x48, 0x0300); /* POR value = 0x308 */ /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ error = reg_read(handle, 0x49, &check_value); check_value &= ~0x1; error = reg_write(handle, 0x49, check_value); return error; } static enum tfa98xx_error tfa9888_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; unsigned short value, xor; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; if ((handles_local[handle].rev & 0xff) != 0x88) { pr_err("This code is not for this device type: %x\n", handles_local[handle].rev); return TFA98XX_ERROR_BAD_PARAMETER; } /* Unlock keys to write settings */ error = reg_write(handle, 0x0F, 0x5A6B); error = reg_read(handle, 0xFB, &value); xor = value ^ 0x005A; error = reg_write(handle, 0xA0, xor); /* The optimal settings are different for 1c, 2c, 3b and 2b/1b */ if (handles_local[handle].rev == 0x2c88) { /* ----- generated code start ----- */ /* --------- Version v1 ---------- */ reg_write(handle, 0x00, 0x164d); /* POR=0x064d */ reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */ reg_write(handle, 0x02, 0x1dc8); /* POR=0x1828 */ reg_write(handle, 0x0e, 0x0080); /* POR=0x0000 */ reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */ reg_write(handle, 0x22, 0x543c); /* POR=0x545c */ reg_write(handle, 0x23, 0x0006); /* POR=0x0000 */ reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */ reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */ reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */ reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */ reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */ reg_write(handle, 0x52, 0xfafe); /* POR=0xbaf6 */ reg_write(handle, 0x70, 0x3ee4); /* POR=0x3ee6 */ reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */ reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */ /* ----- generated code end ----- */ } else if (handles_local[handle].rev == 0x1c88) { /* ----- generated code start ----- */ /* --------- Version v6 ---------- */ reg_write(handle, 0x00, 0x164d); /* POR=0x064d */ reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */ reg_write(handle, 0x02, 0x1dc8); /* POR=0x1828 */ reg_write(handle, 0x0e, 0x0080); /* POR=0x0000 */ reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */ reg_write(handle, 0x22, 0x543c); /* POR=0x545c */ reg_write(handle, 0x23, 0x0006); /* POR=0x0000 */ reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */ reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */ reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */ reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */ reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */ reg_write(handle, 0x52, 0xfafe); /* POR=0xbaf6 */ reg_write(handle, 0x70, 0x3ee4); /* POR=0x3ee6 */ reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */ reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */ /* ----- generated code end ----- */ } else if (handles_local[handle].rev == 0x3b88) { /* ----- generated code start ----- */ /* --------- Version v20 ---------- */ reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */ reg_write(handle, 0x02, 0x1dc8); /* POR=0x1828 */ reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */ reg_write(handle, 0x22, 0x543c); /* POR=0x545c */ reg_write(handle, 0x23, 0x0c06); /* POR=0x0000 */ reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */ reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */ reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */ reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */ reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */ reg_write(handle, 0x52, 0xfafe); /* POR=0xbaf6 */ reg_write(handle, 0x58, 0x1e1c); /* POR=0x161c */ reg_write(handle, 0x70, 0x3ee4); /* POR=0x3ee6 */ reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */ reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */ /* ----- generated code end ----- */ } else { /* If not 1c or 3b assume older version */ /* ----- generated code start ----- */ /* --------- Version v19 ---------- */ reg_write(handle, 0x00, 0x1e5d); /* POR=0x064d */ reg_write(handle, 0x01, 0x828b); /* POR=0x92cb */ reg_write(handle, 0x20, 0x089e); /* POR=0x0890 */ reg_write(handle, 0x23, 0x0c06); /* POR=0x0000 */ reg_write(handle, 0x24, 0x0014); /* POR=0x0000 */ reg_write(handle, 0x25, 0x000a); /* POR=0x0000 */ reg_write(handle, 0x26, 0x0100); /* POR=0x0000 */ reg_write(handle, 0x28, 0x1000); /* POR=0x0000 */ reg_write(handle, 0x51, 0x0000); /* POR=0x00c0 */ reg_write(handle, 0x52, 0x9ae2); /* POR=0xbaf6 */ reg_write(handle, 0x58, 0x1e1c); /* POR=0x161c */ reg_write(handle, 0x70, 0x3ce6); /* POR=0x3ee6 */ reg_write(handle, 0x71, 0x1074); /* POR=0x3074 */ reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */ /* ----- generated code end ----- */ } return error; } static enum tfa98xx_error tfa9872_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; uint16_t MANAOOSC = 0x0140; /* version 17 */ unsigned short value, xor; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; /* Unlock key 1 and 2 */ error = reg_write(handle, 0x0F, 0x5A6B); error = reg_read(handle, 0xFB, &value); xor = value ^ 0x005A; error = reg_write(handle, 0xA0, xor); tfa98xx_key2(handle, 0); switch (handles_local[handle].rev) { case 0x1a72: case 0x2a72: /* ----- generated code start ----- */ /* ----- version 26 ----- */ reg_write(handle, 0x00, 0x1801); /* POR=0x0001 */ reg_write(handle, 0x02, 0x2dc8); /* POR=0x2028 */ reg_write(handle, 0x20, 0x0890); /* POR=0x2890 */ reg_write(handle, 0x22, 0x043c); /* POR=0x045c */ reg_write(handle, 0x51, 0x0000); /* POR=0x0080 */ reg_write(handle, 0x52, 0x1a1c); /* POR=0x7ae8 */ reg_write(handle, 0x58, 0x161c); /* POR=0x101c */ reg_write(handle, 0x61, 0x0198); /* POR=0x0000 */ reg_write(handle, 0x65, 0x0a8b); /* POR=0x0a9a */ reg_write(handle, 0x70, 0x07f5); /* POR=0x06e6 */ reg_write(handle, 0x74, 0xcc84); /* POR=0xd823 */ reg_write(handle, 0x82, 0x01ed); /* POR=0x000d */ reg_write(handle, 0x83, 0x0014); /* POR=0x0013 */ reg_write(handle, 0x84, 0x0021); /* POR=0x0020 */ reg_write(handle, 0x85, 0x0001); /* POR=0x0003 */ /* ----- generated code end ----- */ break; case 0x1b72: case 0x2b72: case 0x3b72: /* ----- generated code start ----- */ /* ----- TFA9872 Probus Registers map N1B2 * - Version 21 (10/19/2016) ----- */ reg_write(handle, 0x02, 0x2dc8); /* POR=0x2828 */ reg_write(handle, 0x20, 0x0890); /* POR=0x2890 */ reg_write(handle, 0x22, 0x043c); /* POR=0x045c */ reg_write(handle, 0x23, 0x0001); /* POR=0x0003 */ reg_write(handle, 0x51, 0x0000); /* POR=0x0080 */ reg_write(handle, 0x52, 0x5a1c); /* POR=0x7a08 */ reg_write(handle, 0x61, 0x0198); /* POR=0x0000 */ reg_write(handle, 0x63, 0x0a9a); /* POR=0x0a93 */ reg_write(handle, 0x65, 0x0a82); /* POR=0x0a8d */ reg_write(handle, 0x6f, 0x01e3); /* POR=0x02e4 */ reg_write(handle, 0x70, 0x06fd); /* POR=0x06e6 */ reg_write(handle, 0x71, 0x307e); /* POR=0x207e */ reg_write(handle, 0x74, 0xcc84); /* POR=0xd913 */ reg_write(handle, 0x75, 0x1132); /* POR=0x118a */ reg_write(handle, 0x82, 0x01ed); /* POR=0x000d */ reg_write(handle, 0x83, 0x001a); /* POR=0x0013 */ /* ----- generated code end ----- */ break; default: pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x\n", handles_local[handle].rev); break; } /* Turn off the osc1m to save power: PLMA4928 */ error = tfa_set_bf(handle, MANAOOSC, 1); /* Bypass OVP by setting bit 3 from register 0xB0 (bypass_ovp=1): */ /* PLMA5258 */ error = reg_read(handle, 0xB0, &value); value |= 1 << 3; error = reg_write(handle, 0xB0, value); return error; } static enum tfa98xx_error tfa9912_specific(tfa98xx_handle_t handle) { enum tfa98xx_error error = TFA98XX_ERROR_OK; unsigned short value, xor; if (!tfa98xx_handle_is_open(handle)) return TFA98XX_ERROR_NOT_OPEN; if ((handles_local[handle].rev & 0xff) != 0x13) { pr_err("This code is not for this device type: %x\n", handles_local[handle].rev); return TFA98XX_ERROR_BAD_PARAMETER; } /* Unlock keys to write settings */ error = reg_write(handle, 0x0F, 0x5A6B); error = reg_read(handle, 0xFB, &value); xor = value ^ 0x005A; error = reg_write(handle, 0xA0, xor); /* The optimal settings */ if (handles_local[handle].rev == 0x1a13) { /* ----- generated code start ----- */ /* ----- version 1.34 ----- */ reg_write(handle, 0x00, 0x0255); /* POR=0x0245 */ reg_write(handle, 0x01, 0x838a); /* POR=0x83ca */ reg_write(handle, 0x02, 0x2dc8); /* POR=0x2828 */ reg_write(handle, 0x05, 0x762a); /* POR=0x766a */ reg_write(handle, 0x22, 0x543c); /* POR=0x545c */ reg_write(handle, 0x26, 0x0100); /* POR=0x0010 */ reg_write(handle, 0x51, 0x0000); /* POR=0x0080 */ reg_write(handle, 0x52, 0x551c); /* POR=0x1afc */ reg_write(handle, 0x61, 0x000c); /* POR=0x0018 */ reg_write(handle, 0x63, 0x0a96); /* POR=0x0a9a */ reg_write(handle, 0x65, 0x0a82); /* POR=0x0a8b */ reg_write(handle, 0x6c, 0x01d5); /* POR=0x02d5 */ reg_write(handle, 0x70, 0x26f8); /* POR=0x06e0 */ reg_write(handle, 0x71, 0x3074); /* POR=0x2074 */ reg_write(handle, 0x75, 0x4484); /* POR=0x4585 */ reg_write(handle, 0x76, 0x72ea); /* POR=0x54a2 */ reg_write(handle, 0x82, 0x024d); /* POR=0x000d */ reg_write(handle, 0x89, 0x0013); /* POR=0x0014 */ /* ----- generated code end ----- */ } return error; } /* * Tfa9890_DspSystemStable will compensate for the wrong behavior of CLKS * to determine if the DSP subsystem is ready for patch and config loading. * * A MTP calibration register is checked for non-zero. * * Note: This only works after i2c reset as this will clear the MTP contents. * When we are configured then the DSP communication will synchronize access. * */ static enum tfa98xx_error tfa9890_dsp_system_stable(tfa98xx_handle_t handle, int *ready) { enum tfa98xx_error error = TFA98XX_ERROR_OK; unsigned short status, mtp0; int result, tries; /* check the contents of the STATUS register */ result = TFA_READ_REG(handle, AREFS); if (result < 0) { error = -result; goto errorExit; } status = (unsigned short)result; /* if AMPS is set then we were already configured and running * no need to check further */ *ready = (TFA_GET_BF_VALUE(handle, AMPS, status) == 1); if (*ready) /* if ready go back */ return error; /* will be TFA98XX_ERROR_OK */ /* check AREFS and CLKS: not ready if either is clear */ *ready = !((TFA_GET_BF_VALUE(handle, AREFS, status) == 0) || (TFA_GET_BF_VALUE(handle, CLKS, status) == 0)); if (!*ready) /* if not ready go back */ return error; /* will be TFA98XX_ERROR_OK */ /* check MTPB * mtpbusy will be active when the subsys copies MTP to I2C * 2 times retry avoids catching this short mtpbusy active period */ for (tries = 2; tries > 0; tries--) { result = TFA_GET_BF(handle, MTPB); if (result < 0) { error = -result; goto errorExit; } status = (unsigned short)result; /* check the contents of the STATUS register */ *ready = (result == 0); if (*ready) /* if ready go on */ break; } if (tries == 0) /* ready will be 0 if retries exausted */ return TFA98XX_ERROR_OK; /* check the contents of MTP register for non-zero, * this indicates that the subsys is ready */ error = reg_read(handle, 0x84, &mtp0); if (error) goto errorExit; *ready = (mtp0 != 0); /* The MTP register written? */ return error; errorExit: *ready = 0; return error; } /* * The CurrentSense4 register is not in the datasheet, define local */ #define TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF (1<<2) #define TFA98XX_CURRENTSENSE4 0x49 /* * Disable clock gating */ static enum tfa98xx_error tfa9890_clockgating(tfa98xx_handle_t handle, int on) { enum tfa98xx_error error; unsigned short value; /* TFA9890 temporarily disable clock gating when dsp reset is used */ error = reg_read(handle, TFA98XX_CURRENTSENSE4, &value); if (error) return error; if (error == TFA98XX_ERROR_OK) { if (on) /* clock gating on - clear the bit */ value &= ~TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; else /* clock gating off - set the bit */ value |= TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; error = reg_write(handle, TFA98XX_CURRENTSENSE4, value); } return error; } /* * Tfa9890_DspReset will deal with clock gating control in order * to reset the DSP for warm state restart */ static enum tfa98xx_error tfa9890_dsp_reset(tfa98xx_handle_t handle, int state) { enum tfa98xx_error error; /* for TFA9890 temporarily disable clock gating * when dsp reset is used */ tfa9890_clockgating(handle, 0); TFA_SET_BF(handle, RST, (uint16_t)state); /* clock gating restore */ error = tfa9890_clockgating(handle, 1); return error; } /* * the int24 values for the vsfw delay table */ static unsigned char vsfwdelay_table[] = { 0, 0, 2, /*Index 0 - Current/Volt Fractional Delay for 8KHz */ 0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */ 0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */ 0, 0, 2, /*Index 3 - Current/Volt Fractional Delay for 16KHz */ 0, 0, 2, /*Index 4 - Current/Volt Fractional Delay for 22KHz */ 0, 0, 2, /*Index 5 - Current/Volt Fractional Delay for 24KHz */ 0, 0, 2, /*Index 6 - Current/Volt Fractional Delay for 32KHz */ 0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */ 0, 0, 3 /*Index 8 - Current/Volt Fractional Delay for 48KHz */ }; /* * TODO make this tfa98xx * Note that the former products write this table via the patch * so moving this to the tfa98xx API requires also updating all patches */ static enum tfa98xx_error tfa9896_dsp_write_vsfwdelay_table(tfa98xx_handle_t handle) { enum tfa98xx_error error; error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(vsfwdelay_table), vsfwdelay_table); return error; } /* * The int24 values for the fracdelay table * For now applicable only for 8 and 48 kHz */ static unsigned char cvfracdelay_table[] = { 0, 0, 51, /*Index 0 - Current/Volt Fractional Delay for 8KHz */ 0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */ 0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */ 0, 0, 38, /*Index 3 - Current/Volt Fractional Delay for 16KHz */ 0, 0, 34, /*Index 4 - Current/Volt Fractional Delay for 22KHz */ 0, 0, 33, /*Index 5 - Current/Volt Fractional Delay for 24KHz */ 0, 0, 11, /*Index 6 - Current/Volt Fractional Delay for 32KHz */ 0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */ 0, 0, 62 /*Index 8 - Current/Volt Fractional Delay for 48KHz */ }; enum tfa98xx_error tfa9896_dsp_write_cvfracdelay_table(tfa98xx_handle_t handle) { enum tfa98xx_error error; error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(cvfracdelay_table), cvfracdelay_table); return error; } static enum tfa98xx_error tfa9896_tfa_dsp_write_tables(tfa98xx_handle_t dev_idx, int sample_rate) { enum tfa98xx_error error; /* Not used for max1! */ //sample_rate = sample_rate; error = tfa9896_dsp_write_vsfwdelay_table(dev_idx); if (error == TFA98XX_ERROR_OK) error = tfa9896_dsp_write_cvfracdelay_table(dev_idx); tfa98xx_dsp_reset(dev_idx, 1); tfa98xx_dsp_reset(dev_idx, 0); return error; } #if defined(TFA9896_SET_TRIP_LEVEL) /* TODO: remove or use me */ static enum tfa98xx_error tfa9896_tfa_set_boost_trip_level(tfa98xx_handle_t handle, int Re25C) { enum tfa98xx_error error = TFA98XX_ERROR_OK; int trip_value; if (Re25C == 0) { pr_debug("\nWarning: No calibration values found: Boost trip level not adjusted!\n"); return error; } /* Read trip level: The trip level is already set * (if defined in cnt file) so we can just read the bitfield */ trip_value = tfa_get_bf(handle, TFA9896_BF_DCTRIP); pr_debug("\nCurrent calibration value is %d mOhm and the boost_trip_lvl is %d\n", Re25C, trip_value); if (Re25C > 0 && Re25C < 4000) trip_value = 0xa; else if (Re25C >= 4000 && Re25C < 6000) trip_value = 0x9; else if (Re25C >= 6000 && Re25C < 8000) trip_value = 0x8; else if (Re25C >= 8000) trip_value = 0x7; /* Set the boost trip level according to the new value */ error = tfa_set_bf(handle, TFA9896_BF_DCTRIP, (uint16_t)trip_value); pr_debug("New boost_trip_lvl is set to %d\n", trip_value); return error; } #endif /* * the int24 values for the vsfw delay table */ static unsigned char tfa9897_vsfwdelay_table[] = { 0, 0, 2, /*Index 0 - Current/Volt Fractional Delay for 8KHz */ 0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */ 0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */ 0, 0, 2, /*Index 3 - Current/Volt Fractional Delay for 16KHz */ 0, 0, 2, /*Index 4 - Current/Volt Fractional Delay for 22KHz */ 0, 0, 2, /*Index 5 - Current/Volt Fractional Delay for 24KHz */ 0, 0, 2, /*Index 6 - Current/Volt Fractional Delay for 32KHz */ 0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */ 0, 0, 3 /*Index 8 - Current/Volt Fractional Delay for 48KHz */ }; /* * TODO make this tfa98xx * Note that the former products write this table via the patch * so moving this to tfa98xx API requires also updating all patches */ static enum tfa98xx_error tfa9897_dsp_write_vsfwdelay_table(tfa98xx_handle_t handle) { enum tfa98xx_error error; error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(tfa9897_vsfwdelay_table), tfa9897_vsfwdelay_table); return error; } /* * The int24 values for the fracdelay table * For now applicable only for 8 and 48 kHz */ static unsigned char tfa9897_cvfracdelay_table[] = { 0, 0, 51, /*Index 0 - Current/Volt Fractional Delay for 8KHz */ 0, 0, 0, /*Index 1 - Current/Volt Fractional Delay for 11KHz */ 0, 0, 0, /*Index 2 - Current/Volt Fractional Delay for 12KHz */ 0, 0, 38, /*Index 3 - Current/Volt Fractional Delay for 16KHz */ 0, 0, 34, /*Index 4 - Current/Volt Fractional Delay for 22KHz */ 0, 0, 33, /*Index 5 - Current/Volt Fractional Delay for 24KHz */ 0, 0, 11, /*Index 6 - Current/Volt Fractional Delay for 32KHz */ 0, 0, 2, /*Index 7 - Current/Volt Fractional Delay for 44KHz */ 0, 0, 62 /*Index 8 - Current/Volt Fractional Delay for 48KHz */ }; enum tfa98xx_error tfa9897_dsp_write_cvfracdelay_table(tfa98xx_handle_t handle) { enum tfa98xx_error error; error = tfa_dsp_cmd_id_write(handle, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(tfa9897_cvfracdelay_table), tfa9897_cvfracdelay_table); return error; } static enum tfa98xx_error tfa9897_tfa_dsp_write_tables(tfa98xx_handle_t dev_idx, int sample_rate) { enum tfa98xx_error error; /* Not used for max1! */ //sample_rate = sample_rate; error = tfa9897_dsp_write_vsfwdelay_table(dev_idx); if (error == TFA98XX_ERROR_OK) error = tfa9897_dsp_write_cvfracdelay_table(dev_idx); tfa98xx_dsp_reset(dev_idx, 1); tfa98xx_dsp_reset(dev_idx, 0); return error; } static enum tfa98xx_error tfa9888_tfa_dsp_write_tables(tfa98xx_handle_t handle, int sample_rate) { unsigned char buffer[15] = {0}; int size = 15 * sizeof(char); /* Write the fractional delay in hardware register 'cs_frac_delay' */ switch (sample_rate) { case 0: /* 8kHz */ TFA_SET_BF(handle, FRACTDEL, 40); break; case 1: /* 11.025KHz */ TFA_SET_BF(handle, FRACTDEL, 38); break; case 2: /* 12kHz */ TFA_SET_BF(handle, FRACTDEL, 37); break; case 3: /* 16kHz */ TFA_SET_BF(handle, FRACTDEL, 59); break; case 4: /* 22.05KHz */ TFA_SET_BF(handle, FRACTDEL, 56); break; case 5: /* 24kHz */ TFA_SET_BF(handle, FRACTDEL, 56); break; case 6: /* 32kHz */ TFA_SET_BF(handle, FRACTDEL, 52); break; case 7: /* 44.1kHz */ TFA_SET_BF(handle, FRACTDEL, 48); break; case 8: default:/* 48kHz */ TFA_SET_BF(handle, FRACTDEL, 46); break; } /* First copy the msg_id to the buffer */ buffer[0] = (uint8_t) 0; buffer[1] = (uint8_t) MODULE_FRAMEWORK + 128; buffer[2] = (uint8_t) FW_PAR_ID_SET_SENSES_DELAY; /* Required for all FS exept 8kHz (8kHz is all zero) */ if (sample_rate != 0) { buffer[5] = 1; /* Vdelay_P */ buffer[8] = 0; /* Idelay_P */ buffer[11] = 1; /* Vdelay_S */ buffer[14] = 0; /* Idelay_S */ } /* send SetSensesDelay msg */ return dsp_msg(handle, size, (char *)buffer); } static enum tfa98xx_error tfa9912_tfa_dsp_write_tables(tfa98xx_handle_t handle, int sample_rate) { unsigned char buffer[15] = {0}; int size = 15 * sizeof(char); /* Write the fractional delay in hardware register 'cs_frac_delay' */ switch (sample_rate) { case 0: /* 8kHz */ TFA_SET_BF(handle, FRACTDEL, 40); break; case 1: /* 11.025KHz */ TFA_SET_BF(handle, FRACTDEL, 38); break; case 2: /* 12kHz */ TFA_SET_BF(handle, FRACTDEL, 37); break; case 3: /* 16kHz */ TFA_SET_BF(handle, FRACTDEL, 59); break; case 4: /* 22.05KHz */ TFA_SET_BF(handle, FRACTDEL, 56); break; case 5: /* 24kHz */ TFA_SET_BF(handle, FRACTDEL, 56); break; case 6: /* 32kHz */ TFA_SET_BF(handle, FRACTDEL, 52); break; case 7: /* 44.1kHz */ TFA_SET_BF(handle, FRACTDEL, 48); break; case 8: default:/* 48kHz */ TFA_SET_BF(handle, FRACTDEL, 46); break; } /* First copy the msg_id to the buffer */ buffer[0] = (uint8_t) 0; buffer[1] = (uint8_t) MODULE_FRAMEWORK + 128; buffer[2] = (uint8_t) FW_PAR_ID_SET_SENSES_DELAY; /* Required for all FS exept 8kHz (8kHz is all zero) */ if (sample_rate != 0) { buffer[5] = 1; /* Vdelay_P */ buffer[8] = 0; /* Idelay_P */ buffer[11] = 1; /* Vdelay_S */ buffer[14] = 0; /* Idelay_S */ } /* send SetSensesDelay msg */ return dsp_msg(handle, size, (char *)buffer); } /* * register device specifics functions */ void tfa9895_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9895_specific; } /* * register device specifics functions */ void tfa9890_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9890_specific; ops->tfa_dsp_reset = tfa9890_dsp_reset; ops->tfa_dsp_system_stable = tfa9890_dsp_system_stable; } /* * register device specifics functions */ void tfa9891_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9891_specific; } /* * register device specifics functions */ void tfa9896_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9896_specific; ops->tfa_dsp_write_tables = tfa9896_tfa_dsp_write_tables; } /* * register device specifics functions */ void tfa9897_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9897_specific; ops->tfa_dsp_write_tables = tfa9897_tfa_dsp_write_tables; } /* * register device specifics functions */ void tfa9888_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9888_specific; ops->tfa_dsp_write_tables = tfa9888_tfa_dsp_write_tables; } /* * register device specifics functions */ void tfa9872_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9872_specific; } /* * register device specifics functions */ void tfa9912_ops(struct tfa_device_ops *ops) { ops->tfa_init = tfa9912_specific; ops->tfa_dsp_write_tables = tfa9912_tfa_dsp_write_tables; }