/* * Copyright (C) 2014 NXP Semiconductors, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #include "dbgprint.h" #include "tfa_container.h" #include "tfa.h" #include "tfa98xx_tfafieldnames.h" #include "tfa_internal.h" /* handle macro for bitfield */ #define TFA_MK_BF(reg, pos, len) ((reg<<8)|(pos<<4)|(len-1)) /* abstract family for register */ #define FAM_TFA98XX_CF_CONTROLS (TFA_FAM(tfa, RST) >> 8) #define FAM_TFA98XX_CF_MEM (TFA_FAM(tfa, MEMA) >> 8) #define FAM_TFA98XX_MTP0 (TFA_FAM(tfa, MTPOTC) >> 8) #define FAM_TFA98xx_INT_EN (TFA_FAM(tfa, INTENVDDS) >> 8) #define CF_STATUS_I2C_CMD_ACK 0x01 /* Defines below are used for irq function (this removed the genregs include) */ #define TFA98XX_INTERRUPT_ENABLE_REG1 0x48 #define TFA98XX_INTERRUPT_IN_REG1 0x44 #define TFA98XX_INTERRUPT_OUT_REG1 0x40 #define TFA98XX_STATUS_POLARITY_REG1 0x4c #define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK 0x2 #define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK 0x1 #define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS 1 #define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_POS 0 #define ERR -1 void tfanone_ops(struct tfa_device_ops *ops); void tfa9872_ops(struct tfa_device_ops *ops); void tfa9874_ops(struct tfa_device_ops *ops); void tfa9878_ops(struct tfa_device_ops *ops); void tfa9912_ops(struct tfa_device_ops *ops); void tfa9888_ops(struct tfa_device_ops *ops); void tfa9891_ops(struct tfa_device_ops *ops); void tfa9897_ops(struct tfa_device_ops *ops); void tfa9896_ops(struct tfa_device_ops *ops); void tfa9890_ops(struct tfa_device_ops *ops); void tfa9895_ops(struct tfa_device_ops *ops); void tfa9894_ops(struct tfa_device_ops *ops); #ifndef MIN #define MIN(A, B) (A < B?A:B) #endif /* retry values */ #define CFSTABLE_TRIES 10 #define AMPOFFWAIT_TRIES 50 #define MTPBWAIT_TRIES 50 #define MTPEX_WAIT_NTRIES 50 /* calibration done executed */ #define TFA_MTPEX_POS TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS /**/ int tfa_get_calibration_info(struct tfa_device *tfa, int channel) { return tfa->mohm[channel]; } /* return sign extended tap pattern */ int tfa_get_tap_pattern(struct tfa_device *tfa) { int value = tfa_get_bf(tfa, TFA9912_BF_CFTAPPAT); int bitshift; /* length of bitfield */ uint8_t field_len = 1 + (TFA9912_BF_CFTAPPAT & 0x0f); bitshift = 8 * sizeof(int) - field_len; /* signextend */ value = (value << bitshift) >> bitshift; return value; } /* * interrupt bit function to clear */ int tfa_irq_clear(struct tfa_device *tfa, enum tfa9912_irq bit) { unsigned char reg; /* make bitfield enum */ if (bit == tfa9912_irq_all) { /* operate on all bits */ for (reg = TFA98XX_INTERRUPT_IN_REG1; reg < TFA98XX_INTERRUPT_IN_REG1 + 3; reg++) reg_write(tfa, reg, 0xffff); /* all bits */ } else if (bit < tfa9912_irq_max) { reg = (unsigned char)(TFA98XX_INTERRUPT_IN_REG1 + (bit >> 4)); reg_write(tfa, reg, 1 << (bit & 0x0f)); /* only this bit */ } else return ERR; return 0; } /* * return state of irq or -1 if illegal bit */ int tfa_irq_get(struct tfa_device *tfa, enum tfa9912_irq bit) { uint16_t value; int reg, mask; if (bit < tfa9912_irq_max) { /* only this bit */ reg = TFA98XX_INTERRUPT_OUT_REG1 + (bit >> 4); mask = 1 << (bit & 0x0f); reg_read(tfa, (unsigned char)reg, &value); } else return ERR; return (value & mask) != 0; } /* * interrupt bit function that operates on the shadow regs in the handle */ int tfa_irq_ena(struct tfa_device *tfa, enum tfa9912_irq bit, int state) { uint16_t value, new_value; int reg = 0, mask; /* */ if (bit == tfa9912_irq_all) { /* operate on all bits */ for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) { /* all bits */ reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1] = state ? 0xffff : 0; /* all bits */ } } else if (bit < tfa9912_irq_max) { /* only this bit */ reg = TFA98XX_INTERRUPT_ENABLE_REG1 + (bit >> 4); mask = 1 << (bit & 0x0f); reg_read(tfa, (unsigned char)reg, &value); if (state) //set new_value = (uint16_t)(value | mask); else // clear new_value = value & ~mask; if (new_value != value) { reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1] = new_value; } } else return ERR; return 0; } /* * mask interrupts by disabling them */ int tfa_irq_mask(struct tfa_device *tfa) { int reg; /* operate on all bits */ for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) reg_write(tfa, (unsigned char)reg, 0); return 0; } /* * unmask interrupts by enabling them again */ int tfa_irq_unmask(struct tfa_device *tfa) { int reg; /* operate on all bits */ for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) reg_write(tfa, (unsigned char)reg, tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1]); return 0; } /* * interrupt bit function that sets the polarity */ int tfa_irq_set_pol(struct tfa_device *tfa, enum tfa9912_irq bit, int state) { uint16_t value, new_value; int reg = 0, mask; if (bit == tfa9912_irq_all) { /* operate on all bits */ for (reg = TFA98XX_STATUS_POLARITY_REG1; reg <= TFA98XX_STATUS_POLARITY_REG1 + tfa9912_irq_max / 16; reg++) { /* all bits */ reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); } } else if (bit < tfa9912_irq_max) { /* only this bit */ reg = TFA98XX_STATUS_POLARITY_REG1 + (bit >> 4); mask = 1 << (bit & 0x0f); reg_read(tfa, (unsigned char)reg, &value); if (state) /* Active High */ new_value = (uint16_t)(value | mask); else /* Active Low */ new_value = value & ~mask; if (new_value != value) { reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ } } else return ERR; return 0; } /* * set device info and register device ops */ void tfa_set_query_info(struct tfa_device *tfa) { /* invalidate device struct cached values */ tfa->hw_feature_bits = -1; tfa->sw_feature_bits[0] = -1; tfa->sw_feature_bits[1] = -1; tfa->profile = -1; tfa->vstep = -1; /* defaults */ tfa->is_probus_device = 0; tfa->advance_keys_handling = 0; /*artf65038*/ tfa->tfa_family = 1; tfa->daimap = Tfa98xx_DAI_I2S; /* all others */ tfa->spkr_count = 1; tfa->spkr_select = 0; tfa->support_tcoef = supportYes; tfa->supportDrc = supportNotSet; tfa->support_saam = supportNotSet; /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ tfa->ext_dsp = -1; tfa->bus = 0; tfa->partial_enable = 0; tfa->convert_dsp32 = 0; tfa->sync_iv_delay = 0; /* TODO use the getfeatures() for retrieving the features [artf103523] tfa->supportDrc = supportNotSet;*/ switch (tfa->rev & 0xff) { case 0: /* tfanone : non-i2c external DSP device */ /* e.g. qc adsp */ tfa->supportDrc = supportYes; tfa->tfa_family = 0; tfa->spkr_count = 0; tfa->daimap = 0; tfanone_ops(&tfa->dev_ops); /* register device operations via tfa hal*/ tfa->bus = 1; break; case 0x72: /* tfa9872 */ tfa->supportDrc = supportYes; tfa->tfa_family = 2; tfa->spkr_count = 1; tfa->is_probus_device = 1; tfa->daimap = Tfa98xx_DAI_TDM; tfa9872_ops(&tfa->dev_ops); /* register device operations */ break; case 0x74: /* tfa9874 */ tfa->supportDrc = supportYes; tfa->tfa_family = 2; tfa->spkr_count = 1; tfa->is_probus_device = 1; tfa->daimap = Tfa98xx_DAI_TDM; tfa9874_ops(&tfa->dev_ops); /* register device operations */ break; case 0x78: /* tfa9878 */ tfa->supportDrc = supportYes; tfa->tfa_family = 2; tfa->spkr_count = 1; tfa->is_probus_device = 1; tfa->advance_keys_handling = 1; /*artf65038*/ tfa->daimap = Tfa98xx_DAI_TDM; tfa9878_ops(&tfa->dev_ops); /* register device operations */ break; case 0x88: /* tfa9888 */ tfa->tfa_family = 2; tfa->spkr_count = 2; tfa->daimap = Tfa98xx_DAI_TDM; tfa9888_ops(&tfa->dev_ops); /* register device operations */ break; case 0x97: /* tfa9897 */ tfa->supportDrc = supportNo; tfa->spkr_count = 1; tfa->daimap = Tfa98xx_DAI_TDM; tfa9897_ops(&tfa->dev_ops); /* register device operations */ break; case 0x96: /* tfa9896 */ tfa->supportDrc = supportNo; tfa->spkr_count = 1; tfa->daimap = Tfa98xx_DAI_TDM; tfa9896_ops(&tfa->dev_ops); /* register device operations */ break; case 0x92: /* tfa9891 */ tfa->spkr_count = 1; tfa->daimap = (Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S); tfa9891_ops(&tfa->dev_ops); /* register device operations */ break; case 0x91: /* tfa9890B */ tfa->spkr_count = 1; tfa->daimap = (Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S); break; case 0x80: case 0x81: /* tfa9890 */ tfa->spkr_count = 1; tfa->daimap = Tfa98xx_DAI_I2S; tfa->supportDrc = supportNo; tfa->supportFramework = supportNo; tfa9890_ops(&tfa->dev_ops); /* register device operations */ break; case 0x12: /* tfa9895 */ tfa->spkr_count = 1; tfa->daimap = Tfa98xx_DAI_I2S; tfa9895_ops(&tfa->dev_ops); /* register device operations */ break; case 0x13: /* tfa9912 */ tfa->tfa_family = 2; tfa->spkr_count = 1; tfa->daimap = Tfa98xx_DAI_TDM; tfa9912_ops(&tfa->dev_ops); /* register device operations */ break; case 0x94: /* tfa9894 */ tfa->tfa_family = 2; tfa->spkr_count = 1; tfa->daimap = Tfa98xx_DAI_TDM; tfa9894_ops(&tfa->dev_ops); /* register device operations */ break; default: pr_err("unknown device type : 0x%02x\n", tfa->rev); _ASSERT(0); break; } } /* * lookup the device type and return the family type */ int tfa98xx_dev2family(int dev_type) { /* only look at the die ID part (lsb byte) */ switch (dev_type & 0xff) { case 0x12: case 0x80: case 0x81: case 0x91: case 0x92: case 0x97: case 0x96: return 1; case 0x88: case 0x72: case 0x13: case 0x74: case 0x94: return 2; case 0x50: return 3; default: return 0; } } /* * return the target address for the filter on this device filter_index: [0..9] reserved for EQ (not deployed, calc. is available) [10..12] anti-alias filter [13] integrator filter */ enum Tfa98xx_DMEM tfa98xx_filter_mem(struct tfa_device *tfa, int filter_index, unsigned short *address, int channel) { enum Tfa98xx_DMEM dmem = -1; int idx; unsigned short bq_table[7][4] = { /* index: 10, 11, 12, 13 */ {346, 351, 356, 288}, //87 BRA_MAX_MRA4-2_7.00 {346, 351, 356, 288}, //90 BRA_MAX_MRA6_9.02 {467, 472, 477, 409}, //95 BRA_MAX_MRA7_10.02 {406, 411, 416, 348}, //97 BRA_MAX_MRA9_12.01 {467, 472, 477, 409}, //91 BRA_MAX_MRAA_13.02 {8832, 8837, 8842, 8847}, //88 part1 {8853, 8858, 8863, 8868} //88 part2 /* Since the 88 is stereo we have 2 parts. * Every index has 5 values except index 13 this one * has 6 values */ }; if ((10 <= filter_index) && (filter_index <= 13)) { dmem = Tfa98xx_DMEM_YMEM; /* for all devices */ idx = filter_index - 10; switch (tfa->rev & 0xff) { // only compare lower byte case 0x12: *address = bq_table[2][idx]; break; case 0x97: *address = bq_table[3][idx]; break; case 0x96: *address = bq_table[3][idx]; break; case 0x80: case 0x81: // for the RAM version case 0x91: *address = bq_table[1][idx]; break; case 0x92: *address = bq_table[4][idx]; break; case 0x88: /* Channel 1 = primary, 2 = secondary */ if (channel == 1) *address = bq_table[5][idx]; else *address = bq_table[6][idx]; break; case 0x72: case 0x74: case 0x13: default: /* unsupported case, possibly intermediate version */ return ERR; _ASSERT(0); } } return dmem; } /************************ query functions ******************************/ /** * return revision * Used by the LTT */ void tfa98xx_rev(int *major, int *minor, int *revision) { char version_str[] = TFA98XX_API_REV_STR; sscanf(version_str, "v%d.%d.%d", major, minor, revision); } /** * tfa_supported_speakers * returns the number of the supported speaker count */ enum Tfa98xx_Error tfa_supported_speakers(struct tfa_device *tfa, int *spkr_count) { if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; else *spkr_count = tfa->spkr_count; return Tfa98xx_Error_Ok; } /* * tfa98xx_supported_saam * returns the supportedspeaker as microphone feature */ enum Tfa98xx_Error tfa98xx_supported_saam(struct tfa_device *tfa, enum Tfa98xx_saam *saam) { int features; enum Tfa98xx_Error error; if (tfa->support_saam == supportNotSet) { error = tfa98xx_dsp_get_hw_feature_bits(tfa, &features); if (error != Tfa98xx_Error_Ok) return error; tfa->support_saam = (features & 0x8000) ? supportYes : supportNo; /* SAAM is bit15 */ } *saam = tfa->support_saam == supportYes ? Tfa98xx_saam : Tfa98xx_saam_none; return Tfa98xx_Error_Ok; } /* * tfa98xx_compare_features * Obtains features_from_MTP and features_from_cnt */ enum Tfa98xx_Error tfa98xx_compare_features(struct tfa_device *tfa, int features_from_MTP[3], int features_from_cnt[3]) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; uint32_t value; uint16_t mtpbf; unsigned char bytes[3 * 2]; int status; tfa98xx_dsp_system_stable(tfa, &status); if (!status) return Tfa98xx_Error_NoClock; // Only test when we have a clock. /* Set proper MTP location per device: */ if (tfa->tfa_family == 1) { mtpbf = 0x850f; /* MTP5 for tfa1,16 bits */ } else { mtpbf = 0xf907; /* MTP9 for tfa2, 8 bits */ } /* Read HW features from MTP: */ value = tfa_read_reg(tfa, mtpbf) & 0xffff; features_from_MTP[0] = tfa->hw_feature_bits = value; /* Read SW features: */ error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, FW_PAR_ID_GET_FEATURE_INFO, sizeof(bytes), bytes); if (error != Tfa98xx_Error_Ok) /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ return error; tfa98xx_convert_bytes2data(sizeof(bytes), bytes, &features_from_MTP[1]); /* check if feature bits from MTP match feature bits from cnt file: */ get_hw_features_from_cnt(tfa, &features_from_cnt[0]); get_sw_features_from_cnt(tfa, &features_from_cnt[1]); return error; } /********************************* device specific ops **********************/ /* the wrapper for DspReset, in case of full */ enum Tfa98xx_Error tfa98xx_dsp_reset(struct tfa_device *tfa, int state) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; error = (tfa->dev_ops.dsp_reset)(tfa, state); return error; } /* the ops wrapper for tfa98xx_dsp_SystemStable */ enum Tfa98xx_Error tfa98xx_dsp_system_stable(struct tfa_device *tfa, int *ready) { return (tfa->dev_ops.dsp_system_stable)(tfa, ready); } /* the ops wrapper for tfa98xx_dsp_system_stable */ enum Tfa98xx_Error tfa98xx_auto_copy_mtp_to_iic(struct tfa_device *tfa) { return (tfa->dev_ops.auto_copy_mtp_to_iic)(tfa); } /* the ops wrapper for tfa98xx_faim_protect */ enum Tfa98xx_Error tfa98xx_faim_protect(struct tfa_device *tfa, int state) { return (tfa->dev_ops.faim_protect)(tfa, state); } /* * bring the device into a state similar to reset */ enum Tfa98xx_Error tfa98xx_init(struct tfa_device *tfa) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; uint16_t value = 0; /* reset all i2C registers to default * Write the register directly to avoid the read in the bitfield function. * The I2CR bit may overwrite the full register because it is reset anyway. * This will save a reg read transaction. */ TFA_SET_BF_VALUE(tfa, I2CR, 1, &value); TFA_WRITE_REG(tfa, I2CR, value); /* Put DSP in reset */ tfa98xx_dsp_reset(tfa, 1); /* in pair of tfaRunStartDSP() */ /* some other registers must be set for optimal amplifier behaviour * This is implemented in a file specific for the type number */ if (tfa->dev_ops.tfa_init) error = (tfa->dev_ops.tfa_init)(tfa); return error; } enum Tfa98xx_Error tfa98xx_dsp_write_tables(struct tfa_device *tfa, int sample_rate) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; error = (tfa->dev_ops.dsp_write_tables)(tfa, sample_rate); return error; } /** Set internal oscillator into power down mode. * * @param[in] tfa device description structure * @param[in] state new state 0 - oscillator is on, 1 oscillator is off. * * @return Tfa98xx_Error_Ok when successfull, error otherwise. */ enum Tfa98xx_Error tfa98xx_set_osc_powerdown(struct tfa_device *tfa, int state) { if (tfa->dev_ops.set_osc_powerdown) { return tfa->dev_ops.set_osc_powerdown(tfa, state); } return Tfa98xx_Error_Not_Implemented; } /** update low power mode of the device. * * @param[in] tfa device description structure * @param[in] state new state 0 - LPMODE is on, 1 LPMODE is off. * * @return Tfa98xx_Error_Ok when successfull, error otherwise. */ enum Tfa98xx_Error tfa98xx_update_lpm(struct tfa_device *tfa, int state) { if (tfa->dev_ops.update_lpm) { return tfa->dev_ops.update_lpm(tfa, state); } return Tfa98xx_Error_Not_Implemented; } /** Check presence of powerswitch=1 in configuration and optimal setting. * * @param[in] tfa device description structure * * @return -1 when error, 0 or 1 depends on switch settings. */ int tfa98xx_powerswitch_is_enabled(struct tfa_device *tfa) { uint16_t value; enum Tfa98xx_Error ret; if (((tfa->rev & 0xff) == 0x13) || ((tfa->rev & 0xff) == 0x88)) { ret = reg_read(tfa, 0xc6, &value); if (ret != Tfa98xx_Error_Ok) { return ERR; } /* * PLMA5539: Check actual value of powerswitch. TODO: regmap v1.40 * should make this bit public. */ return (int)(value & (1u << 6)); } return 1; } /********************* new tfa2 ***************************************/ /* newly added messaging for tfa2 tfa1? */ enum Tfa98xx_Error tfa98xx_dsp_get_memory(struct tfa_device *tfa, int memoryType, int offset, int length, unsigned char bytes[]) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; char msg[4 * 3]; int nr = 0; msg[nr++] = 8; msg[nr++] = MODULE_FRAMEWORK + 128; msg[nr++] = FW_PAR_ID_GET_MEMORY; msg[nr++] = 0; msg[nr++] = 0; msg[nr++] = (char)memoryType; msg[nr++] = 0; msg[nr++] = (offset >> 8) & 0xff; msg[nr++] = offset & 0xff; msg[nr++] = 0; msg[nr++] = (length >> 8) & 0xff; msg[nr++] = length & 0xff; /* send msg */ error = dsp_msg(tfa, nr, (char *)msg); if (error != Tfa98xx_Error_Ok) return error; /* read the data from the device (length * 3) */ error = dsp_msg_read(tfa, length * 3, bytes); return error; } enum Tfa98xx_Error tfa98xx_dsp_set_memory(struct tfa_device *tfa, int memoryType, int offset, int length, int value) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; int nr = 0; char msg[5 * 3]; msg[nr++] = 8; msg[nr++] = MODULE_FRAMEWORK + 128; msg[nr++] = FW_PAR_ID_SET_MEMORY; msg[nr++] = 0; msg[nr++] = 0; msg[nr++] = (char)memoryType; msg[nr++] = 0; msg[nr++] = (offset >> 8) & 0xff; msg[nr++] = offset & 0xff; msg[nr++] = 0; msg[nr++] = (length >> 8) & 0xff; msg[nr++] = length & 0xff; msg[nr++] = (value >> 16) & 0xff; msg[nr++] = (value >> 8) & 0xff; msg[nr++] = value & 0xff; /* send msg */ error = dsp_msg(tfa, nr, (char *)msg); return error; } /****************************** calibration support **************************/ /* * get/set the mtp with user controllable values * * check if the relevant clocks are available */ enum Tfa98xx_Error tfa98xx_get_mtp(struct tfa_device *tfa, uint16_t *value) { int status; int result; /* not possible if PLL in powerdown */ if (TFA_GET_BF(tfa, PWDN)) { pr_debug("PLL in powerdown\n"); return Tfa98xx_Error_NoClock; } tfa98xx_dsp_system_stable(tfa, &status); if (status == 0) { pr_debug("PLL not running\n"); return Tfa98xx_Error_NoClock; } result = TFA_READ_REG(tfa, MTP0); if (result < 0) { return -result; } *value = (uint16_t)result; return Tfa98xx_Error_Ok; } /* * lock or unlock KEY2 * lock = 1 will lock * lock = 0 will unlock * * note that on return all the hidden key will be off */ void tfa98xx_key2(struct tfa_device *tfa, int lock) { /* unhide lock registers */ reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 : 0x0F, 0x5A6B); /* lock/unlock key2 MTPK */ TFA_WRITE_REG(tfa, MTPKEY2, lock ? 0 : 0x5A); /* unhide lock registers */ if (!tfa->advance_keys_handling) /*artf65038*/ reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 : 0x0F, 0); } void tfa2_manual_mtp_cpy(struct tfa_device *tfa, uint16_t reg_row_to_keep, uint16_t reg_row_to_set, uint8_t row)///MCH_TO_TEST { uint16_t value; int loop = 0; enum Tfa98xx_Error error; /* Assure FAIM is enabled (enable it when neccesery) */ if (tfa->is_probus_device) { error = tfa98xx_faim_protect(tfa, 1); if (tfa->verbose) { pr_debug("FAIM enabled (err:%d).\n", error); } } reg_read(tfa, (unsigned char)reg_row_to_keep, &value); if (!row) { reg_write(tfa, 0xA7, value); reg_write(tfa, 0xA8, reg_row_to_set); } else { reg_write(tfa, 0xA7, reg_row_to_set); reg_write(tfa, 0xA8, value); } reg_write(tfa, 0xA3, 0x10 | row); if (tfa->is_probus_device) { /* Assure FAIM is enabled (enable it when neccesery) */ for (loop = 0; loop < 100 /*x10ms*/; loop++) { msleep_interruptible(10); /* wait 10ms to avoid busload */ if (tfa_dev_get_mtpb(tfa) == 0) break; } error = tfa98xx_faim_protect(tfa, 0); if (tfa->verbose) { pr_debug("FAIM disabled (err:%d).\n", error); } } } enum Tfa98xx_Error tfa98xx_set_mtp(struct tfa_device *tfa, uint16_t value, uint16_t mask) { unsigned short mtp_old, mtp_new; int loop, status; enum Tfa98xx_Error error; error = tfa98xx_get_mtp(tfa, &mtp_old); if (error != Tfa98xx_Error_Ok) return error; mtp_new = (value & mask) | (mtp_old & ~mask); if (mtp_old == mtp_new) /* no change */ { if (tfa->verbose) pr_info("No change in MTP. Value not written! \n"); return Tfa98xx_Error_Ok; } error = tfa98xx_update_lpm(tfa, 1); if (error) { return error; } /* Assure FAIM is enabled (enable it when neccesery) */ error = tfa98xx_faim_protect(tfa, 1); if (error) { return error; } if (tfa->verbose) { pr_debug("MTP clock enabled.\n"); } /* assure that the clock is up, else we can't write MTP */ error = tfa98xx_dsp_system_stable(tfa, &status); if (error) { return error; } if (status == 0) { return Tfa98xx_Error_NoClock; } tfa98xx_key2(tfa, 0); /* unlock */ TFA_WRITE_REG(tfa, MTP0, mtp_new); /* write to i2c shadow reg */ /* CIMTP=1 start copying all the data from i2c regs_mtp to mtp*/ if (tfa->tfa_family == 2) tfa2_manual_mtp_cpy(tfa, 0xF1, mtp_new, 0); else TFA_SET_BF(tfa, CIMTP, 1); /* wait until MTP write is done */ error = Tfa98xx_Error_StateTimedOut; for (loop = 0; loop < 100 /*x10ms*/; loop++) { msleep_interruptible(10); /* wait 10ms to avoid busload */ if (tfa_dev_get_mtpb(tfa) == 0) { error = Tfa98xx_Error_Ok; break; } } tfa98xx_key2(tfa, 1); /* lock */ /* MTP setting failed due to timeout ?*/ if (error) { tfa98xx_faim_protect(tfa, 0); return error; } /* Disable the FAIM, if this is neccessary */ error = tfa98xx_faim_protect(tfa, 0); if (error) { return error; } if (tfa->verbose) { pr_debug("MTP clock disabled.\n"); } error = tfa98xx_update_lpm(tfa, 0); if (error) { return error; } return error; } /* * clear mtpex * set ACS * start tfa */ int tfa_calibrate(struct tfa_device *tfa) { enum Tfa98xx_Error error; /* clear mtpex */ error = tfa98xx_set_mtp(tfa, 0, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); if (error) return error; /* set RST=1 to put the DSP in Reset */ TFA_SET_BF(tfa, RST, 1); /* set ACS/coldboot state */ error = tfaRunColdboot(tfa, 1); /* start tfa by playing */ return error; } static short twos(short x) { return (x < 0) ? x + 512 : x; } void tfa98xx_set_exttemp(struct tfa_device *tfa, short ext_temp) { if ((-256 <= ext_temp) && (ext_temp <= 255)) { /* make twos complement */ pr_debug("Using ext temp %d C\n", twos(ext_temp)); TFA_SET_BF(tfa, TROS, 1); TFA_SET_BF(tfa, EXTTS, twos(ext_temp)); } else { pr_debug("Clearing ext temp settings\n"); TFA_SET_BF(tfa, TROS, 0); } } short tfa98xx_get_exttemp(struct tfa_device *tfa) { short ext_temp = (short)TFA_GET_BF(tfa, EXTTS); return twos(ext_temp); } /******************* tfa simple bitfield interfacing *************************/ /* convenience functions */ enum Tfa98xx_Error tfa98xx_set_volume_level(struct tfa_device *tfa, unsigned short vol) { if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; if (vol > 255) /* restricted to 8 bits */ vol = 255; /* 0x00 -> 0.0 dB * 0x01 -> -0.5 dB * ... * 0xFE -> -127dB * 0xFF -> muted */ /* volume value is in the top 8 bits of the register */ return -TFA_SET_BF(tfa, VOL, (uint16_t)vol); } static enum Tfa98xx_Error tfa98xx_set_mute_tfa2(struct tfa_device *tfa, enum Tfa98xx_Mute mute) { enum Tfa98xx_Error error; if (tfa->dev_ops.set_mute == NULL) return Tfa98xx_Error_Not_Supported; switch (mute) { case Tfa98xx_Mute_Off: error = tfa->dev_ops.set_mute(tfa, 0); TFA_SET_BF(tfa, AMPE, 1); break; case Tfa98xx_Mute_Amplifier: case Tfa98xx_Mute_Digital: error = tfa->dev_ops.set_mute(tfa, 1); TFA_SET_BF(tfa, AMPE, 0); break; default: return Tfa98xx_Error_Bad_Parameter; } return error; } static enum Tfa98xx_Error tfa98xx_set_mute_tfa1(struct tfa_device *tfa, enum Tfa98xx_Mute mute) { enum Tfa98xx_Error error; unsigned short audioctrl_value; unsigned short sysctrl_value; int value; value = TFA_READ_REG(tfa, CFSM); /* audio control register */ if (value < 0) return -value; audioctrl_value = (unsigned short)value; value = TFA_READ_REG(tfa, AMPE); /* system control register */ if (value < 0) return -value; sysctrl_value = (unsigned short)value; switch (mute) { case Tfa98xx_Mute_Off: /* previous state can be digital or amplifier mute, * clear the cf_mute and set the enbl_amplifier bits * * To reduce PLOP at power on it is needed to switch the * amplifier on with the DCDC in follower mode * (enbl_boost = 0 ?). * This workaround is also needed when toggling the * powerdown bit! */ TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); TFA_SET_BF_VALUE(tfa, DCA, 1, &sysctrl_value); break; case Tfa98xx_Mute_Digital: /* expect the amplifier to run */ /* set the cf_mute bit */ TFA_SET_BF_VALUE(tfa, CFSM, 1, &audioctrl_value); /* set the enbl_amplifier bit */ TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); /* clear active mode */ TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); break; case Tfa98xx_Mute_Amplifier: /* clear the cf_mute bit */ TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); /* clear the enbl_amplifier bit and active mode */ TFA_SET_BF_VALUE(tfa, AMPE, 0, &sysctrl_value); TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); break; default: return Tfa98xx_Error_Bad_Parameter; } error = -TFA_WRITE_REG(tfa, CFSM, audioctrl_value); if (error) return error; error = -TFA_WRITE_REG(tfa, AMPE, sysctrl_value); return error; } enum Tfa98xx_Error tfa98xx_set_mute(struct tfa_device *tfa, enum Tfa98xx_Mute mute) { if (tfa->in_use == 0) { pr_err("device is not opened \n"); return Tfa98xx_Error_NotOpen; } if (tfa->tfa_family == 1) return tfa98xx_set_mute_tfa1(tfa, mute); else return tfa98xx_set_mute_tfa2(tfa, mute); } /****************** patching ***********************************************/ static enum Tfa98xx_Error tfa98xx_process_patch_file(struct tfa_device *tfa, int length, const unsigned char *bytes) { unsigned short size; int index = 0; enum Tfa98xx_Error error = Tfa98xx_Error_Ok; while (index < length) { size = bytes[index] + bytes[index + 1] * 256; index += 2; if ((index + size) > length) { /* outside the buffer, error in the input data */ return Tfa98xx_Error_Bad_Parameter; } if (size > tfa->buffer_size) { /* too big, must fit buffer */ return Tfa98xx_Error_Bad_Parameter; } error = tfa98xx_write_raw(tfa, size, &bytes[index]); if (error != Tfa98xx_Error_Ok) break; index += size; } return error; } /* the patch contains a header with the following * IC revision register: 1 byte, 0xFF means don't care * XMEM address to check: 2 bytes, big endian, 0xFFFF means don't care * XMEM value to expect: 3 bytes, big endian */ static enum Tfa98xx_Error tfa98xx_check_ic_rom_version(struct tfa_device *tfa, const unsigned char patchheader[]) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; unsigned short checkrev, revid; unsigned char lsb_revid; unsigned short checkaddress; int checkvalue; int value = 0; int status; checkrev = patchheader[0]; lsb_revid = tfa->rev & 0xff; /* only compare lower byte */ if ((checkrev != 0xFF) && (checkrev != lsb_revid)) return Tfa98xx_Error_Not_Supported; checkaddress = (patchheader[1] << 8) + patchheader[2]; checkvalue = (patchheader[3] << 16) + (patchheader[4] << 8) + patchheader[5]; if (checkaddress != 0xFFFF) { /* before reading XMEM, check if we can access the DSP */ error = tfa98xx_dsp_system_stable(tfa, &status); if (error == Tfa98xx_Error_Ok) { if (!status) { /* DSP subsys not running */ error = Tfa98xx_Error_DSP_not_running; } } /* read register to check the correct ROM version */ if (error == Tfa98xx_Error_Ok) { error = mem_read(tfa, checkaddress, 1, &value); } if (error == Tfa98xx_Error_Ok) { if (value != checkvalue) { pr_err("patch file romid type check failed [0x%04x]: \ expected 0x%02x, actual 0x%02x\n", checkaddress, value, checkvalue); error = Tfa98xx_Error_Not_Supported; } } } else { /* == 0xffff */ /* check if the revid subtype is in there */ if (checkvalue != 0xFFFFFF && checkvalue != 0) { revid = patchheader[5] << 8 | patchheader[0]; /* full revid */ if (revid != tfa->rev) { pr_err("patch file device type check failed: expected 0x%02x, actual 0x%02x\n", tfa->rev, revid); return Tfa98xx_Error_Not_Supported; } } } return error; } #define PATCH_HEADER_LENGTH 6 enum Tfa98xx_Error tfa_dsp_patch(struct tfa_device *tfa, int patchLength, const unsigned char *patchBytes) { enum Tfa98xx_Error error; int status; if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; if (patchLength < PATCH_HEADER_LENGTH) return Tfa98xx_Error_Bad_Parameter; error = tfa98xx_check_ic_rom_version(tfa, patchBytes); if (Tfa98xx_Error_Ok != error) { return error; } tfa98xx_dsp_system_stable(tfa, &status); if (!status) return Tfa98xx_Error_NoClock; // Only test when we have a clock. /******MCH_TO_TEST**************/ if (error == Tfa98xx_Error_Ok) { error = tfaRunColdboot(tfa, 1); if (error) return Tfa98xx_Error_DSP_not_running; } /**************************/ error = tfa98xx_process_patch_file(tfa, patchLength - PATCH_HEADER_LENGTH, patchBytes + PATCH_HEADER_LENGTH); return error; } /****************** end patching *****************************************/ TFA_INTERNAL enum Tfa98xx_Error tfa98xx_wait_result(struct tfa_device *tfa, int wait_retry_count) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; int cf_status; /* the contents of the CF_STATUS register */ int tries = 0; do { cf_status = TFA_GET_BF(tfa, ACK); if (cf_status < 0) error = -cf_status; tries++; } // i2c_cmd_ack /* don't wait forever, DSP is pretty quick to respond (< 1ms) */ while ((error == Tfa98xx_Error_Ok) && ((cf_status & CF_STATUS_I2C_CMD_ACK) == 0) && (tries < wait_retry_count)); if (tries >= wait_retry_count) { /* something wrong with communication with DSP */ error = Tfa98xx_Error_DSP_not_running; } return error; } /* * * support functions for data conversion */ /** convert memory bytes to signed 24 bit integers input: bytes contains "num_bytes" byte elements output: data contains "num_bytes/3" int24 elements */ void tfa98xx_convert_bytes2data(int num_bytes, const unsigned char bytes[], int data[]) { int i; /* index for data */ int k; /* index for bytes */ int d; int num_data = num_bytes / 3; _ASSERT((num_bytes % 3) == 0); for (i = 0, k = 0; i < num_data; ++i, k += 3) { d = (bytes[k] << 16) | (bytes[k + 1] << 8) | (bytes[k + 2]); _ASSERT(d >= 0); _ASSERT(d < (1 << 24)); /* max 24 bits in use */ if (bytes[k] & 0x80) /* sign bit was set */ d = -((1 << 24) - d); data[i] = d; } } /** convert signed 32 bit integers to 24 bit aligned bytes input: data contains "num_data" int elements output: bytes contains "3 * num_data" byte elements */ void tfa98xx_convert_data2bytes(int num_data, const int data[], unsigned char bytes[]) { int i; /* index for data */ int k; /* index for bytes */ int d; /* note: cannot just take the lowest 3 bytes from the 32 bit * integer, because also need to take care of clipping any * value > 2&23 */ for (i = 0, k = 0; i < num_data; ++i, k += 3) { if (data[i] >= 0) d = MIN(data[i], (1 << 23) - 1); else { /* 2's complement */ d = (1 << 24) - MIN(-data[i], 1 << 23); } _ASSERT(d >= 0); _ASSERT(d < (1 << 24)); /* max 24 bits in use */ bytes[k] = (d >> 16) & 0xFF; /* MSB */ bytes[k + 1] = (d >> 8) & 0xFF; bytes[k + 2] = (d) & 0xFF; /* LSB */ } } /* * DSP RPC message support functions * depending on framework to be up and running * need base i2c of memaccess (tfa1=0x70/tfa2=0x90) */ /* write dsp messages in function tfa_dsp_msg() */ /* note the 'old' write_parameter() was more efficient because all * i2c was in one burst transaction */ /* * TODO properly handle bitfields: state should be restored! * (now it will change eg dmesg field to xmem) */ enum Tfa98xx_Error tfa_dsp_msg_write(struct tfa_device *tfa, int length, const char *buffer) { int offset = 0; /* XMEM word size */ int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); int remaining_bytes = length; enum Tfa98xx_Error error = Tfa98xx_Error_Ok; uint16_t cfctl; int value; value = TFA_READ_REG(tfa, DMEM); if (value < 0) { error = -value; return error; } cfctl = (uint16_t)value; /* assume no I2C errors from here */ /* set cf ctl to DMEM */ TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl); /* set to autoincrement */ TFA_WRITE_REG(tfa, DMEM, cfctl); /* xmem[1] is start of message * direct write to register to save cycles avoiding read-modify-write */ TFA_WRITE_REG(tfa, MADD, 1); /* due to autoincrement in cf_ctrl, next write will happen at * the next address */ while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { if (remaining_bytes < chunk_size) chunk_size = remaining_bytes; /* else chunk_size remains at initialize value above */ error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, chunk_size, (const unsigned char *)buffer + offset); remaining_bytes -= chunk_size; offset += chunk_size; } /* notify the DSP */ if (error == Tfa98xx_Error_Ok) { /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ /* set the cf_req1 and cf_int bit */ TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl); /* bit 0 */ TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl); error = -TFA_WRITE_REG(tfa, CFINT, cfctl); } return error; } enum Tfa98xx_Error tfa_dsp_msg_write_id(struct tfa_device *tfa, int length, const char *buffer, uint8_t cmdid[3]) { int offset = 0; int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); /* XMEM word size */ int remaining_bytes = length; enum Tfa98xx_Error error = Tfa98xx_Error_Ok; uint16_t cfctl; int value; value = TFA_READ_REG(tfa, DMEM); if (value < 0) { error = -value; return error; } cfctl = (uint16_t)value; /* assume no I2C errors from here */ /* set cf ctl to DMEM */ TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl); /* set to autoincrement */ TFA_WRITE_REG(tfa, DMEM, cfctl); /* xmem[1] is start of message * direct write to register to save cycles avoiding read-modify-write */ TFA_WRITE_REG(tfa, MADD, 1); /* write cmd-id */ error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, (const unsigned char *)cmdid); /* due to autoincrement in cf_ctrl, next write will happen at * the next address */ while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { if (remaining_bytes < chunk_size) chunk_size = remaining_bytes; /* else chunk_size remains at initialize value above */ error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, chunk_size, (const unsigned char *)buffer + offset); remaining_bytes -= chunk_size; offset += chunk_size; } /* notify the DSP */ if (error == Tfa98xx_Error_Ok) { /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ /* set the cf_req1 and cf_int bit */ TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl); /* bit 0 */ TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl); error = -TFA_WRITE_REG(tfa, CFINT, cfctl); } return error; } /* * status function used by tfa_dsp_msg() to retrieve command/msg status: * return a <0 status of the DSP did not ACK. */ enum Tfa98xx_Error tfa_dsp_msg_status(struct tfa_device *tfa, int *pRpcStatus) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; error = tfa98xx_wait_result(tfa, 2); /* 2 is only one try */ if (error == Tfa98xx_Error_DSP_not_running) { *pRpcStatus = -1; return Tfa98xx_Error_Ok; } else if (error != Tfa98xx_Error_Ok) return error; error = tfa98xx_check_rpc_status(tfa, pRpcStatus); return error; } const char *tfa98xx_get_i2c_status_id_string(int status) { const char *p_id_str; switch (status) { case Tfa98xx_DSP_Not_Running: p_id_str = "No response from DSP"; break; case Tfa98xx_I2C_Req_Done: p_id_str = "Ok"; break; case Tfa98xx_I2C_Req_Busy: p_id_str = "Request is being processed"; break; case Tfa98xx_I2C_Req_Invalid_M_ID: p_id_str = "Provided M-ID does not fit in valid rang [0..2]"; break; case Tfa98xx_I2C_Req_Invalid_P_ID: p_id_str = "Provided P-ID is not valid in the given M-ID context"; break; case Tfa98xx_I2C_Req_Invalid_CC: p_id_str = "Invalid channel configuration bits (SC|DS|DP|DC) combination"; break; case Tfa98xx_I2C_Req_Invalid_Seq: p_id_str = "Invalid sequence of commands, in case the DSP expects some \ commands in a specific order"; break; case Tfa98xx_I2C_Req_Invalid_Param: p_id_str = "Generic error, invalid parameter"; break; case Tfa98xx_I2C_Req_Buffer_Overflow: p_id_str = "I2C buffer has overflowed: host has sent too many \ parameters, memory integrity is not guaranteed"; break; case Tfa98xx_I2C_Req_Calib_Busy: p_id_str = "Calibration not completed"; break; case Tfa98xx_I2C_Req_Calib_Failed: p_id_str = "Calibration failed"; break; default: p_id_str = "Unspecified error"; } return p_id_str; } enum Tfa98xx_Error tfa_dsp_msg_read(struct tfa_device *tfa, int length, unsigned char *bytes) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; int burst_size; /* number of words per burst size */ int bytes_per_word = 3; int num_bytes; int offset = 0; unsigned short start_offset = 2; /* msg starts @xmem[2] ,[1]=cmd */ if (length > TFA2_MAX_PARAM_SIZE) return Tfa98xx_Error_Bad_Parameter; TFA_SET_BF(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM); error = -TFA_WRITE_REG(tfa, MADD, start_offset); if (error != Tfa98xx_Error_Ok) return error; num_bytes = length; /* input param */ while (num_bytes > 0) { burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); if (num_bytes < burst_size) burst_size = num_bytes; error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, bytes + offset); if (error != Tfa98xx_Error_Ok) return error; num_bytes -= burst_size; offset += burst_size; } return error; } enum Tfa98xx_Error dsp_msg(struct tfa_device *tfa, int length24, const char *buf24) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; int lastmessage = 0; uint8_t *blob; int i; int *intbuf = NULL; char *buf = (char *)buf24; int length = length24; if (tfa->convert_dsp32) { int idx = 0; length = 4 * length24 / 3; intbuf = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); buf = (char *)intbuf; /* convert 24 bit DSP messages to a 32 bit integer */ for (i = 0; i < length24; i += 3) { int tmp = (buf24[i] << 16) + (buf24[i + 1] << 8) + buf24[i + 2]; /* Sign extend to 32-bit from 24-bit */ intbuf[idx++] = ((int32_t)tmp << 8) >> 8; } } /* Only create multi-msg when the dsp is cold */ if (tfa->ext_dsp == 1) { /* Creating the multi-msg */ error = tfa_tib_dsp_msgmulti(tfa, length, buf); if (error == Tfa98xx_Error_Fail) return Tfa98xx_Error_Fail; /* if the buffer is full we need to send the existing message * and add the current message */ if (error == Tfa98xx_Error_Buffer_too_small) { int len; /* (a) send the existing (full) message */ blob = kmalloc(64 * 1024, GFP_KERNEL); // max length is 64k len = tfa_tib_dsp_msgmulti(tfa, -1, (const char *)blob); if (tfa->verbose) { pr_debug("Multi-message buffer full. Sending multi-message,\ length=%d \n", len); } if (tfa->has_msg == 0) /* via i2c */ { /* Send tot the target selected */ error = (tfa->dev_ops.dsp_msg)(tfa, len, (const char *)blob); } else { /* via msg hal */ error = tfa98xx_write_dsp(tfa, len, (const char *)blob); } kfree(blob); /* (b) add the current DSP message to a new multi-message */ error = tfa_tib_dsp_msgmulti(tfa, length, buf); if (error == Tfa98xx_Error_Fail) { return Tfa98xx_Error_Fail; } } lastmessage = error; /* When the lastmessage is done we can send the multi-msg to the target */ if (lastmessage == 1) { /* Get the full multi-msg data */ blob = kmalloc(64 * 1024, GFP_KERNEL); //max length is 64k length = tfa_tib_dsp_msgmulti(tfa, -1, (const char *)blob); if (tfa->verbose) pr_debug("Last message for the multi-message received.\ Multi-message length=%d \n", length); if (tfa->has_msg == 0) /* via i2c */ { /* Send tot the target selected */ error = (tfa->dev_ops.dsp_msg)(tfa, length, (const char *)blob); } else { /* via msg hal */ error = tfa98xx_write_dsp(tfa, length, (const char *)blob); } kfree(blob); /* Free the kmalloc blob */ lastmessage = 0; /* reset to be able to re-start */ } } else { if (tfa->has_msg == 0) /* via i2c */ { error = (tfa->dev_ops.dsp_msg)(tfa, length, buf); } else { /* via msg hal */ error = tfa98xx_write_dsp(tfa, length, (const char *)buf); } } if (error != Tfa98xx_Error_Ok) /* Get actual error code from softDSP */ error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* DSP verbose has argument 0x04 */ if ((tfa->verbose & 0x04) != 0) { pr_debug("DSP w [%d]: ", length); for (i = 0; i < length; i++) pr_debug("0x%02x ", (uint8_t)buf[i]); pr_debug("\n"); } if (tfa->convert_dsp32) { kmem_cache_free(tfa->cachep, intbuf); } return error; } enum Tfa98xx_Error dsp_msg_read(struct tfa_device *tfa, int length24, unsigned char *bytes24) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; int i; int length = length24; unsigned char *bytes = bytes24; if (tfa->convert_dsp32) { length = 4 * length24 / 3; bytes = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); } if (tfa->has_msg == 0) /* via i2c */ { error = (tfa->dev_ops.dsp_msg_read)(tfa, length, bytes); } else { /* via msg hal */ error = tfa98xx_read_dsp(tfa, length, bytes); } if (error != Tfa98xx_Error_Ok) error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ /* DSP verbose has argument 0x04 */ if ((tfa->verbose & 0x04) != 0) { pr_debug("DSP R [%d]: ", length); for (i = 0; i < length; i++) pr_debug("0x%02x ", (uint8_t)bytes[i]); pr_debug("\n"); } if (tfa->convert_dsp32) { int idx = 0; /* convert 32 bit LE to 24 bit BE */ for (i = 0; i < length; i += 4) { bytes24[idx++] = bytes[i + 2]; bytes24[idx++] = bytes[i + 1]; bytes24[idx++] = bytes[i + 0]; } kmem_cache_free(tfa->cachep, bytes); } return error; } enum Tfa98xx_Error reg_read(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value) { enum Tfa98xx_Error error; error = (tfa->dev_ops.reg_read)(tfa, subaddress, value); if (error != Tfa98xx_Error_Ok) error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ return error; } enum Tfa98xx_Error reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) { enum Tfa98xx_Error error; error = (tfa->dev_ops.reg_write)(tfa, subaddress, value); if (error != Tfa98xx_Error_Ok) error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ return error; } enum Tfa98xx_Error mem_read(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues) { enum Tfa98xx_Error error; error = (tfa->dev_ops.mem_read)(tfa, start_offset, num_words, pValues); if (error != Tfa98xx_Error_Ok) error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ return error; } enum Tfa98xx_Error mem_write(struct tfa_device *tfa, unsigned short address, int value, int memtype) { enum Tfa98xx_Error error; error = (tfa->dev_ops.mem_write)(tfa, address, value, memtype); if (error != Tfa98xx_Error_Ok) error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ return error; } /* * write/read raw msg functions : * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. * The functions will return immediately and do not not wait for DSP reponse. */ #define MAX_WORDS (300) enum Tfa98xx_Error tfa_dsp_msg(struct tfa_device *tfa, int length, const char *buf) { enum Tfa98xx_Error error; int tries, rpc_status = Tfa98xx_I2C_Req_Done; /* write the message and notify the DSP */ error = tfa_dsp_msg_write(tfa, length, buf); if (error != Tfa98xx_Error_Ok) return error; /* get the result from the DSP (polling) */ for (tries = TFA98XX_WAITRESULT_NTRIES; tries > 0; tries--) { error = tfa_dsp_msg_status(tfa, &rpc_status); if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) break; /* If the rpc status is a specific error we want to know it. * If it is busy or not running it should retry */ if (rpc_status != Tfa98xx_I2C_Req_Busy && rpc_status != Tfa98xx_DSP_Not_Running) break; } if (rpc_status != Tfa98xx_I2C_Req_Done) { /* DSP RPC call returned an error */ error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); } return error; } /** * write/read raw msg functions: * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. * The functions will return immediately and do not not wait for DSP reponse. * An ID is added to modify the command-ID */ enum Tfa98xx_Error tfa_dsp_msg_id(struct tfa_device *tfa, int length, const char *buf, uint8_t cmdid[3]) { enum Tfa98xx_Error error; int tries, rpc_status = Tfa98xx_I2C_Req_Done; /* write the message and notify the DSP */ error = tfa_dsp_msg_write_id(tfa, length, buf, cmdid); if (error != Tfa98xx_Error_Ok) return error; /* get the result from the DSP (polling) */ for (tries = TFA98XX_WAITRESULT_NTRIES; tries > 0; tries--) { error = tfa_dsp_msg_status(tfa, &rpc_status); if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) break; } if (rpc_status != Tfa98xx_I2C_Req_Done) { /* DSP RPC call returned an error */ error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); } return error; } /* read the return code for the RPC call */ TFA_INTERNAL enum Tfa98xx_Error tfa98xx_check_rpc_status(struct tfa_device *tfa, int *pRpcStatus) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; /* the value to sent to the * CF_CONTROLS register: cf_req=00000000, * cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ unsigned short cf_ctrl = 0x0002; /* memory address to be accessed (0: Status, 1: ID, 2: parameters) */ unsigned short cf_mad = 0x0000; if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; if (pRpcStatus == NULL) return Tfa98xx_Error_Bad_Parameter; /* 1) write DMEM=XMEM to the DSP XMEM */ { /* minimize the number of I2C transactions by making use of the autoincrement in I2C */ unsigned char buffer[4]; /* first the data for CF_CONTROLS */ buffer[0] = (unsigned char)((cf_ctrl >> 8) & 0xFF); buffer[1] = (unsigned char)(cf_ctrl & 0xFF); /* write the contents of CF_MAD which is the subaddress following CF_CONTROLS */ buffer[2] = (unsigned char)((cf_mad >> 8) & 0xFF); buffer[3] = (unsigned char)(cf_mad & 0xFF); error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_CONTROLS, sizeof(buffer), buffer); } if (error == Tfa98xx_Error_Ok) { /* read 1 word (24 bit) from XMEM */ error = tfa98xx_dsp_read_mem(tfa, 0, 1, pRpcStatus); } return error; } /***************************** xmem only **********************************/ enum Tfa98xx_Error tfa98xx_dsp_read_mem(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; unsigned char *bytes; int burst_size; /* number of words per burst size */ const int bytes_per_word = 3; int dmem; int num_bytes; int *p; bytes = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); if (bytes == NULL) return Tfa98xx_Error_Fail; /* If no offset is given, assume XMEM! */ if (((start_offset >> 16) & 0xf) > 0) dmem = (start_offset >> 16) & 0xf; else dmem = Tfa98xx_DMEM_XMEM; /* Remove offset from adress */ start_offset = start_offset & 0xffff; num_bytes = num_words * bytes_per_word; p = pValues; TFA_SET_BF(tfa, DMEM, (uint16_t)dmem); error = -TFA_WRITE_REG(tfa, MADD, (unsigned short)start_offset); if (error != Tfa98xx_Error_Ok) goto tfa98xx_dsp_read_mem_exit; for (; num_bytes > 0;) { burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); if (num_bytes < burst_size) burst_size = num_bytes; _ASSERT(burst_size <= sizeof(bytes)); error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, bytes); if (error != Tfa98xx_Error_Ok) goto tfa98xx_dsp_read_mem_exit; tfa98xx_convert_bytes2data(burst_size, bytes, p); num_bytes -= burst_size; p += burst_size / bytes_per_word; } tfa98xx_dsp_read_mem_exit: kmem_cache_free(tfa->cachep, bytes); return error; } enum Tfa98xx_Error tfa98xx_dsp_write_mem_word(struct tfa_device *tfa, unsigned short address, int value, int memtype) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; unsigned char bytes[3]; TFA_SET_BF(tfa, DMEM, (uint16_t)memtype); error = -TFA_WRITE_REG(tfa, MADD, address); if (error != Tfa98xx_Error_Ok) return error; tfa98xx_convert_data2bytes(1, &value, bytes); error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, bytes); return error; } enum Tfa98xx_Error tfa_cont_write_filterbank(struct tfa_device *tfa, nxpTfaFilter_t *filter) { unsigned char biquad_index; enum Tfa98xx_Error error = Tfa98xx_Error_Ok; for (biquad_index = 0; biquad_index < 10; biquad_index++) { if (filter[biquad_index].enabled) { error = tfa_dsp_cmd_id_write(tfa, MODULE_BIQUADFILTERBANK, biquad_index + 1, //start @1 sizeof(filter[biquad_index].biquad.bytes), filter[biquad_index].biquad.bytes); } else { error = Tfa98xx_DspBiquad_Disable(tfa, biquad_index + 1); } if (error) return error; } return error; } enum Tfa98xx_Error Tfa98xx_DspBiquad_Disable(struct tfa_device *tfa, int biquad_index) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; int coeff_buffer[BIQUAD_COEFF_SIZE]; unsigned char bytes[3 + BIQUAD_COEFF_SIZE * 3]; int nr = 0; if (biquad_index > TFA98XX_BIQUAD_NUM) return Tfa98xx_Error_Bad_Parameter; if (biquad_index < 1) return Tfa98xx_Error_Bad_Parameter; /* make opcode */ bytes[nr++] = 0; bytes[nr++] = MODULE_BIQUADFILTERBANK + 128; bytes[nr++] = (unsigned char)biquad_index; /* set in correct order and format for the DSP */ coeff_buffer[0] = (int)-8388608; /* -1.0f */ coeff_buffer[1] = 0; coeff_buffer[2] = 0; coeff_buffer[3] = 0; coeff_buffer[4] = 0; coeff_buffer[5] = 0; /* convert to packed 24 */ tfa98xx_convert_data2bytes(BIQUAD_COEFF_SIZE, coeff_buffer, &bytes[nr]); nr += BIQUAD_COEFF_SIZE * 3; error = dsp_msg(tfa, nr, (char *)bytes); return error; } /* wrapper for dsp_msg that adds opcode */ enum Tfa98xx_Error tfa_dsp_cmd_id_write(struct tfa_device *tfa, unsigned char module_id, unsigned char param_id, int num_bytes, const unsigned char data[]) { enum Tfa98xx_Error error; unsigned char *buffer; int nr = 0; buffer = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); if (buffer == NULL) return Tfa98xx_Error_Fail; buffer[nr++] = tfa->spkr_select; buffer[nr++] = module_id + 128; buffer[nr++] = param_id; memcpy(&buffer[nr], data, num_bytes); nr += num_bytes; error = dsp_msg(tfa, nr, (char *)buffer); kmem_cache_free(tfa->cachep, buffer); return error; } /* wrapper for dsp_msg that adds opcode */ /* this is as the former tfa98xx_dsp_get_param() */ enum Tfa98xx_Error tfa_dsp_cmd_id_write_read(struct tfa_device *tfa, unsigned char module_id, unsigned char param_id, int num_bytes, unsigned char data[]) { enum Tfa98xx_Error error; unsigned char buffer[3]; int nr = 0; if (num_bytes <= 0) { pr_debug("Error: The number of READ bytes is smaller or equal to 0! \n"); return Tfa98xx_Error_Fail; } if ((tfa->is_probus_device) && (tfa->cnt->ndev == 1) && (param_id == SB_PARAM_GET_RE25C || param_id == SB_PARAM_GET_LSMODEL || param_id == SB_PARAM_GET_ALGO_PARAMS)) { /* Modifying the ID for GetRe25C */ buffer[nr++] = 4; } else { buffer[nr++] = tfa->spkr_select; } buffer[nr++] = module_id + 128; buffer[nr++] = param_id; error = dsp_msg(tfa, nr, (char *)buffer); if (error != Tfa98xx_Error_Ok) return error; /* read the data from the dsp */ error = dsp_msg_read(tfa, num_bytes, data); return error; } /* wrapper for dsp_msg that adds opcode and 3 bytes required for coefs */ enum Tfa98xx_Error tfa_dsp_cmd_id_coefs(struct tfa_device *tfa, unsigned char module_id, unsigned char param_id, int num_bytes, unsigned char data[]) { enum Tfa98xx_Error error; unsigned char buffer[2 * 3]; int nr = 0; buffer[nr++] = tfa->spkr_select; buffer[nr++] = module_id + 128; buffer[nr++] = param_id; buffer[nr++] = 0; buffer[nr++] = 0; buffer[nr++] = 0; error = dsp_msg(tfa, nr, (char *)buffer); if (error != Tfa98xx_Error_Ok) return error; /* read the data from the dsp */ error = dsp_msg_read(tfa, num_bytes, data); return error; } /* wrapper for dsp_msg that adds opcode and 3 bytes required for MBDrcDynamics */ enum Tfa98xx_Error tfa_dsp_cmd_id_MBDrc_dynamics(struct tfa_device *tfa, unsigned char module_id, unsigned char param_id, int index_subband, int num_bytes, unsigned char data[]) { enum Tfa98xx_Error error; unsigned char buffer[2 * 3]; int nr = 0; buffer[nr++] = tfa->spkr_select; buffer[nr++] = module_id + 128; buffer[nr++] = param_id; buffer[nr++] = 0; buffer[nr++] = 0; buffer[nr++] = (unsigned char)index_subband; error = dsp_msg(tfa, nr, (char *)buffer); if (error != Tfa98xx_Error_Ok) return error; /* read the data from the dsp */ error = dsp_msg_read(tfa, num_bytes, data); return error; } enum Tfa98xx_Error tfa98xx_dsp_write_preset(struct tfa_device *tfa, int length, const unsigned char *p_preset_bytes) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; if (p_preset_bytes != NULL) { /* by design: keep the data opaque and no * interpreting/calculation */ error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, SB_PARAM_SET_PRESET, length, p_preset_bytes); } else { error = Tfa98xx_Error_Bad_Parameter; } return error; } /* * get features from MTP */ enum Tfa98xx_Error tfa98xx_dsp_get_hw_feature_bits(struct tfa_device *tfa, int *features) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; uint32_t value; uint16_t mtpbf; /* return the cache data if it's valid */ if (tfa->hw_feature_bits != -1) { *features = tfa->hw_feature_bits; } else { /* for tfa1 check if we have clock */ if (tfa->tfa_family == 1) { int status; tfa98xx_dsp_system_stable(tfa, &status); if (!status) { get_hw_features_from_cnt(tfa, features); /* skip reading MTP: */ return (*features == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; } mtpbf = 0x850f; /* MTP5 for tfa1,16 bits */ } else mtpbf = 0xf907; /* MTP9 for tfa2, 8 bits */ value = tfa_read_reg(tfa, mtpbf) & 0xffff; *features = tfa->hw_feature_bits = value; } return error; } enum Tfa98xx_Error tfa98xx_dsp_get_sw_feature_bits(struct tfa_device *tfa, int features[2]) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; const int byte_size = 2 * 3; unsigned char bytes[2 * 3]; /* return the cache data if it's valid */ if (tfa->sw_feature_bits[0] != -1) { features[0] = tfa->sw_feature_bits[0]; features[1] = tfa->sw_feature_bits[1]; } else { /* for tfa1 check if we have clock */ if (tfa->tfa_family == 1) { int status; tfa98xx_dsp_system_stable(tfa, &status); if (!status) { get_sw_features_from_cnt(tfa, features); /* skip reading MTP: */ return (features[0] == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; } } error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, FW_PAR_ID_GET_FEATURE_INFO, byte_size, bytes); if (error != Tfa98xx_Error_Ok) { /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ return error; } tfa98xx_convert_bytes2data(byte_size, bytes, features); } return error; } enum Tfa98xx_Error tfa98xx_dsp_get_state_info(struct tfa_device *tfa, unsigned char bytes[], unsigned int *statesize) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int bSupportFramework = 0; unsigned int stateSize = 9; err = tfa98xx_dsp_support_framework(tfa, &bSupportFramework); if (err == Tfa98xx_Error_Ok) { if (bSupportFramework) { err = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, FW_PARAM_GET_STATE, 3 * stateSize, bytes); } else { /* old ROM code, ask SpeakerBoost and only do first portion */ stateSize = 8; err = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, SB_PARAM_GET_STATE, 3 * stateSize, bytes); } } *statesize = stateSize; return err; } enum Tfa98xx_Error tfa98xx_dsp_support_drc(struct tfa_device *tfa, int *pbSupportDrc) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; *pbSupportDrc = 0; if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; if (tfa->supportDrc != supportNotSet) { *pbSupportDrc = (tfa->supportDrc == supportYes); } else { int featureBits[2]; error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); if (error == Tfa98xx_Error_Ok) { /* easy case: new API available */ /* bit=0 means DRC enabled */ *pbSupportDrc = (featureBits[0] & FEATURE1_DRC) == 0; } else if (error == Tfa98xx_Error_RpcParamId) { /* older ROM code, doesn't support it */ *pbSupportDrc = 0; error = Tfa98xx_Error_Ok; } /* else some other error, return transparently */ /* pbSupportDrc only changed when error == Tfa98xx_Error_Ok */ if (error == Tfa98xx_Error_Ok) { tfa->supportDrc = *pbSupportDrc ? supportYes : supportNo; } } return error; } enum Tfa98xx_Error tfa98xx_dsp_support_framework(struct tfa_device *tfa, int *pbSupportFramework) { int featureBits[2] = { 0, 0 }; enum Tfa98xx_Error error = Tfa98xx_Error_Ok; _ASSERT(pbSupportFramework != 0); if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; if (tfa->supportFramework != supportNotSet) { if (tfa->supportFramework == supportNo) *pbSupportFramework = 0; else *pbSupportFramework = 1; } else { error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); if (error == Tfa98xx_Error_Ok) { *pbSupportFramework = 1; tfa->supportFramework = supportYes; } else { *pbSupportFramework = 0; tfa->supportFramework = supportNo; error = Tfa98xx_Error_Ok; } } /* *pbSupportFramework only changed when error == Tfa98xx_Error_Ok */ return error; } enum Tfa98xx_Error tfa98xx_dsp_write_speaker_parameters(struct tfa_device *tfa, int length, const unsigned char *p_speaker_bytes) { enum Tfa98xx_Error error; int bSupportDrc; if (p_speaker_bytes != NULL) { /* by design: keep the data opaque and no * interpreting/calculation */ /* Use long WaitResult retry count */ error = tfa_dsp_cmd_id_write( tfa, MODULE_SPEAKERBOOST, SB_PARAM_SET_LSMODEL, length, p_speaker_bytes); } else { error = Tfa98xx_Error_Bad_Parameter; } if (error != Tfa98xx_Error_Ok) return error; error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); if (error != Tfa98xx_Error_Ok) return error; if (bSupportDrc) { /* Need to set AgcGainInsert back to PRE, * as the SetConfig forces it to POST */ uint8_t bytes[3] = { 0, 0, 0 }; error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, SB_PARAM_SET_AGCINS, 3, bytes); } return error; } enum Tfa98xx_Error tfa98xx_dsp_write_config(struct tfa_device *tfa, int length, const unsigned char *p_config_bytes) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; int bSupportDrc; error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, SB_PARAM_SET_CONFIG, length, p_config_bytes); if (error != Tfa98xx_Error_Ok) return error; error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); if (error != Tfa98xx_Error_Ok) return error; if (bSupportDrc) { /* Need to set AgcGainInsert back to PRE, * as the SetConfig forces it to POST */ uint8_t bytes[3] = { 0, 0, 0 }; error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, SB_PARAM_SET_AGCINS, 3, bytes); } return error; } /* load all the parameters for the DRC settings from a file */ enum Tfa98xx_Error tfa98xx_dsp_write_drc(struct tfa_device *tfa, int length, const unsigned char *p_drc_bytes) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; if (p_drc_bytes != NULL) { error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, SB_PARAM_SET_DRC, length, p_drc_bytes); } else { error = Tfa98xx_Error_Bad_Parameter; } return error; } enum Tfa98xx_Error tfa98xx_powerdown(struct tfa_device *tfa, int powerdown) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; error = TFA_SET_BF(tfa, PWDN, (uint16_t)powerdown); if (powerdown) { /* Workaround for ticket PLMA5337 */ if (tfa->tfa_family == 2) { TFA_SET_BF_VOLATILE(tfa, AMPE, 0); } } return error; } enum Tfa98xx_Error tfa98xx_select_mode(struct tfa_device *tfa, enum Tfa98xx_Mode mode) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; if (tfa->in_use == 0) return Tfa98xx_Error_NotOpen; if (error == Tfa98xx_Error_Ok) { switch (mode) { default: error = Tfa98xx_Error_Bad_Parameter; } } return error; } int tfa_set_bf(struct tfa_device *tfa, const uint16_t bf, const uint16_t value) { enum Tfa98xx_Error err; uint16_t regvalue, msk, oldvalue; /* * bitfield enum: * - 0..3 : len * - 4..7 : pos * - 8..15 : address */ uint8_t len = bf & 0x0f; uint8_t pos = (bf >> 4) & 0x0f; uint8_t address = (bf >> 8) & 0xff; err = reg_read(tfa, address, ®value); if (err) { pr_err("Error getting bf :%d \n", -err); return -err; } oldvalue = regvalue; msk = ((1 << (len + 1)) - 1) << pos; regvalue &= ~msk; regvalue |= value << pos; /* Only write when the current register value is not the same as the new value */ if (oldvalue != regvalue) { err = reg_write(tfa, address, regvalue); if (err) { pr_err("Error setting bf :%d \n", -err); return -err; } } return 0; } int tfa_set_bf_volatile(struct tfa_device *tfa, const uint16_t bf, const uint16_t value) { enum Tfa98xx_Error err; uint16_t regvalue, msk; /* * bitfield enum: * - 0..3 : len * - 4..7 : pos * - 8..15 : address */ uint8_t len = bf & 0x0f; uint8_t pos = (bf >> 4) & 0x0f; uint8_t address = (bf >> 8) & 0xff; err = reg_read(tfa, address, ®value); if (err) { pr_err("Error getting bf :%d \n", -err); return -err; } msk = ((1 << (len + 1)) - 1) << pos; regvalue &= ~msk; regvalue |= value << pos; err = reg_write(tfa, address, regvalue); if (err) { pr_err("Error setting bf :%d \n", -err); return -err; } return 0; } int tfa_get_bf(struct tfa_device *tfa, const uint16_t bf) { enum Tfa98xx_Error err; uint16_t regvalue, msk; uint16_t value; /* * bitfield enum: * - 0..3 : len * - 4..7 : pos * - 8..15 : address */ uint8_t len = bf & 0x0f; uint8_t pos = (bf >> 4) & 0x0f; uint8_t address = (bf >> 8) & 0xff; err = reg_read(tfa, address, ®value); if (err) { pr_err("Error getting bf :%d \n", -err); return -err; } msk = ((1 << (len + 1)) - 1) << pos; regvalue &= msk; value = regvalue >> pos; return value; } int tfa_set_bf_value(const uint16_t bf, const uint16_t bf_value, uint16_t *p_reg_value) { uint16_t regvalue, msk; /* * bitfield enum: * - 0..3 : len * - 4..7 : pos * - 8..15 : address */ uint8_t len = bf & 0x0f; uint8_t pos = (bf >> 4) & 0x0f; regvalue = *p_reg_value; msk = ((1 << (len + 1)) - 1) << pos; regvalue &= ~msk; regvalue |= bf_value << pos; *p_reg_value = regvalue; return 0; } uint16_t tfa_get_bf_value(const uint16_t bf, const uint16_t reg_value) { uint16_t msk, value; /* * bitfield enum: * - 0..3 : len * - 4..7 : pos * - 8..15 : address */ uint8_t len = bf & 0x0f; uint8_t pos = (bf >> 4) & 0x0f; msk = ((1 << (len + 1)) - 1) << pos; value = (reg_value & msk) >> pos; return value; } int tfa_write_reg(struct tfa_device *tfa, const uint16_t bf, const uint16_t reg_value) { enum Tfa98xx_Error err; /* bitfield enum - 8..15 : address */ uint8_t address = (bf >> 8) & 0xff; err = reg_write(tfa, address, reg_value); if (err) return -err; return 0; } int tfa_read_reg(struct tfa_device *tfa, const uint16_t bf) { enum Tfa98xx_Error err; uint16_t regvalue; /* bitfield enum - 8..15 : address */ uint8_t address = (bf >> 8) & 0xff; err = reg_read(tfa, address, ®value); if (err) return -err; return regvalue; } /* * powerup the coolflux subsystem and wait for it */ enum Tfa98xx_Error tfa_cf_powerup(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int tries, status; /* power on the sub system */ TFA_SET_BF_VOLATILE(tfa, PWDN, 0); // wait until everything is stable, in case clock has been off if (tfa->verbose) pr_info("Waiting for DSP system stable...\n"); for (tries = CFSTABLE_TRIES; tries > 0; tries--) { err = tfa98xx_dsp_system_stable(tfa, &status); _ASSERT(err == Tfa98xx_Error_Ok); if (status) break; else msleep_interruptible(10); /* wait 10ms to avoid busload */ } if (tries == 0) {// timedout pr_err("DSP subsystem start timed out\n"); return Tfa98xx_Error_StateTimedOut; } return err; } /* * Enable/Disable the I2S output for TFA1 devices * without TDM interface */ static enum Tfa98xx_Error tfa98xx_aec_output(struct tfa_device *tfa, int enable) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; if ((tfa->daimap & Tfa98xx_DAI_TDM) == Tfa98xx_DAI_TDM) return err; if (tfa->tfa_family == 1) err = -tfa_set_bf(tfa, TFA1_BF_I2SDOE, (enable != 0)); else { pr_err("I2SDOE on unsupported family\n"); err = Tfa98xx_Error_Not_Supported; } return err; } /* * Print the current state of the hardware manager * Device manager status information, man_state from TFA9888_N1B_I2C_regmap_V12 */ int is_94_N2_device(struct tfa_device *tfa) { return ((((tfa->rev) & 0xff) == 0x94) && (((tfa->rev >> 8) & 0xff) > 0x1a)); } enum Tfa98xx_Error show_current_state(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int manstate = -1; if (tfa->tfa_family == 2 && tfa->verbose) { if (is_94_N2_device(tfa)) manstate = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); else manstate = TFA_GET_BF(tfa, MANSTATE); if (manstate < 0) return -manstate; pr_debug("Current HW manager state: "); switch (manstate) { case 0: pr_debug("power_down_state \n"); break; case 1: pr_debug("wait_for_source_settings_state \n"); break; case 2: pr_debug("connnect_pll_input_state \n"); break; case 3: pr_debug("disconnect_pll_input_state \n"); break; case 4: pr_debug("enable_pll_state \n"); break; case 5: pr_debug("enable_cgu_state \n"); break; case 6: pr_debug("init_cf_state \n"); break; case 7: pr_debug("enable_amplifier_state \n"); break; case 8: pr_debug("alarm_state \n"); break; case 9: pr_debug("operating_state \n"); break; case 10: pr_debug("mute_audio_state \n"); break; case 11: pr_debug("disable_cgu_pll_state \n"); break; default: pr_debug("Unable to find current state \n"); break; } } return err; } enum Tfa98xx_Error tfaGetFwApiVersion(struct tfa_device *tfa, unsigned char *pFirmwareVersion) { enum Tfa98xx_Error err = 0; char cmd_buf[4]; int cmd_len, res_len; if (tfa == NULL) return Tfa98xx_Error_Bad_Parameter; if (!tfa->is_probus_device) { err = mem_read(tfa, FW_VAR_API_VERSION, 1, (int *)pFirmwareVersion); if (err) { pr_debug("%s Error: Unable to get API Version from DSP \n", __FUNCTION__); return err; } } else { cmd_len = 0x03; /* GetAPI: Command is 0x00 0x80 0xFE */ cmd_buf[0] = 0x00; cmd_buf[1] = 0x80; cmd_buf[2] = 0xFE; /* Write the command.*/ err = tfa98xx_write_dsp(tfa, cmd_len, (const char *)cmd_buf); /* Read the API Value.*/ if (err == 0) { res_len = 3; err = tfa98xx_read_dsp(tfa, res_len, (unsigned char *)pFirmwareVersion); } } return err; } /* * start the speakerboost algorithm * this implies a full system startup when the system was not already started * */ enum Tfa98xx_Error tfaRunSpeakerBoost(struct tfa_device *tfa, int force, int profile) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int value; if (force) { err = tfaRunColdStartup(tfa, profile); if (err) return err; } /* Returns 1 when device is "cold" and 0 when device is warm */ value = tfa_is_cold(tfa); pr_debug("Startup of device [%s] is a %sstart\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), value ? "cold" : "warm"); /* cold start and not tap profile */ if (value) { /* Run startup and write all files */ err = tfaRunSpeakerStartup(tfa, force, profile); if (err) return err; /* Save the current profile and set the vstep to 0 */ /* This needs to be overwriten even in CF bypass */ tfa_dev_set_swprof(tfa, (unsigned short)profile); tfa_dev_set_swvstep(tfa, 0); /* Synchonize I/V delay on 96/97 at cold start */ if ((tfa->tfa_family == 1) && (tfa->daimap == Tfa98xx_DAI_TDM)) tfa->sync_iv_delay = 1; } return err; } enum Tfa98xx_Error tfaRunSpeakerStartup(struct tfa_device *tfa, int force, int profile) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; if (!force) { // in case of force CF already runnning err = tfaRunStartup(tfa, profile); PRINT_ASSERT(err); if (err) return err; /* Startup with CF in bypass then return here */ if (tfa_cf_enabled(tfa) == 0) return err; /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ if (tfa->ext_dsp == -1) { err = tfaRunStartDSP(tfa); if (err) return err; } } /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1 */ tfa98xx_auto_copy_mtp_to_iic(tfa); err = tfaGetFwApiVersion(tfa, (unsigned char *)&tfa->fw_itf_ver[0]); if (err) { pr_debug("[%s] cannot get FWAPI error = %d \n", __FUNCTION__, err); return err; } /* write all the files from the device list */ err = tfaContWriteFiles(tfa); if (err) { pr_debug("[%s] tfaContWriteFiles error = %d \n", __FUNCTION__, err); return err; } /* write all the files from the profile list (use volumstep 0) */ err = tfaContWriteFilesProf(tfa, profile, 0); if (err) { pr_debug("[%s] tfaContWriteFilesProf error = %d \n", __FUNCTION__, err); return err; } return err; } /* * Run calibration */ enum Tfa98xx_Error tfaRunSpeakerCalibration(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int calibrateDone; /* return if there is no audio running */ if ((tfa->tfa_family == 2) && TFA_GET_BF(tfa, NOCLK)) return Tfa98xx_Error_NoClock; /* When MTPOTC is set (cal=once) unlock key2 */ if (TFA_GET_BF(tfa, MTPOTC) == 1) { tfa98xx_key2(tfa, 0); } /* await calibration, this should return ok */ err = tfaRunWaitCalibration(tfa, &calibrateDone); if (err == Tfa98xx_Error_Ok) { err = tfa_dsp_get_calibration_impedance(tfa); PRINT_ASSERT(err); } /* When MTPOTC is set (cal=once) re-lock key2 */ if (TFA_GET_BF(tfa, MTPOTC) == 1) { tfa98xx_key2(tfa, 1); } return err; } enum Tfa98xx_Error tfaRunColdboot(struct tfa_device *tfa, int state) { #define CF_CONTROL 0x8100 enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int tries = 10; /* repeat set ACS bit until set as requested */ while (state != TFA_GET_BF(tfa, ACS)) { /* set colstarted in CF_CONTROL to force ACS */ err = mem_write(tfa, CF_CONTROL, state, Tfa98xx_DMEM_IOMEM); PRINT_ASSERT(err); if (tries-- == 0) { pr_debug("coldboot (ACS) did not %s\n", state ? "set" : "clear"); return Tfa98xx_Error_Other; } } return err; } /* * load the patch if any * else tell no loaded */ static enum Tfa98xx_Error tfa_run_load_patch(struct tfa_device *tfa) { return tfaContWritePatch(tfa); } /* * this will load the patch witch will implicitly start the DSP * if no patch is available the DPS is started immediately */ enum Tfa98xx_Error tfaRunStartDSP(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; err = tfa_run_load_patch(tfa); if (err) { /* patch load is fatal so return immediately*/ return err; } /* Clear count_boot, should be reset to 0 before the DSP reset is released */ err = mem_write(tfa, 512, 0, Tfa98xx_DMEM_XMEM); PRINT_ASSERT(err); /* Reset DSP once for sure after initializing */ if (err == Tfa98xx_Error_Ok) { err = tfa98xx_dsp_reset(tfa, 0); PRINT_ASSERT(err); } /* Sample rate is needed to set the correct tables */ err = tfa98xx_dsp_write_tables(tfa, TFA_GET_BF(tfa, AUDFS)); PRINT_ASSERT(err); return err; } /* * start the clocks and wait until the AMP is switching * on return the DSP sub system will be ready for loading */ enum Tfa98xx_Error tfaRunStartup(struct tfa_device *tfa, int profile) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); int i, noinit = 0, audfs = 0, fractdel = 0; if (dev == NULL) return Tfa98xx_Error_Fail; if (dev->bus) /* no i2c device, do nothing */ return Tfa98xx_Error_Ok; /* process the device list to see if the user implemented the noinit */ for (i = 0; i < dev->length; i++) { if (dev->list[i].type == dscNoInit) { noinit = 1; break; } } if (!noinit) { /* Read AUDFS & FRACTDEL prior to (re)init. */ audfs = TFA_GET_BF(tfa, AUDFS); fractdel = TFA_GET_BF(tfa, FRACTDEL); /* load the optimal TFA98XX in HW settings */ err = tfa98xx_init(tfa); PRINT_ASSERT(err); /* Restore audfs & fractdel after coldboot, so we can calibrate with correct fs setting. * in case something else was given in cnt file, profile below will apply this. */ TFA_SET_BF(tfa, AUDFS, audfs); TFA_SET_BF(tfa, FRACTDEL, fractdel); } else { pr_debug("\nWarning: No init keyword found in the cnt file. Init is skipped! \n"); } /* I2S settings to define the audio input properties * these must be set before the subsys is up */ // this will run the list until a non-register item is encountered err = tfaContWriteRegsDev(tfa); // write device register settings PRINT_ASSERT(err); // also write register the settings from the default profile // NOTE we may still have ACS=1 so we can switch sample rate here err = tfaContWriteRegsProf(tfa, profile); PRINT_ASSERT(err); /* Factory trimming for the Boost converter */ tfa98xx_factory_trimmer(tfa); /* Go to the initCF state */ tfa_dev_set_state(tfa, TFA_STATE_INIT_CF, strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, profile), ".cal") != NULL); err = show_current_state(tfa); return err; } /* * run the startup/init sequence and set ACS bit */ enum Tfa98xx_Error tfaRunColdStartup(struct tfa_device *tfa, int profile) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; err = tfaRunStartup(tfa, profile); PRINT_ASSERT(err); if (err) return err; if (!tfa->is_probus_device) { /* force cold boot */ err = tfaRunColdboot(tfa, 1); // set ACS PRINT_ASSERT(err); if (err) return err; } /* start */ err = tfaRunStartDSP(tfa); PRINT_ASSERT(err); return err; } /* * */ enum Tfa98xx_Error tfaRunMute(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int status; int tries = 0; /* signal the TFA98XX to mute */ if (tfa->tfa_family == 1) { err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); if (err == Tfa98xx_Error_Ok) { /* now wait for the amplifier to turn off */ do { status = TFA_GET_BF(tfa, SWS); if (status != 0) msleep_interruptible(10); /* wait 10ms to avoid busload */ else break; tries++; } while (tries < AMPOFFWAIT_TRIES); if (tfa->verbose) pr_debug("-------------------- muted --------------------\n"); /*The amplifier is always switching*/ if (tries == AMPOFFWAIT_TRIES) return Tfa98xx_Error_Other; } } return err; } /* * */ enum Tfa98xx_Error tfaRunUnmute(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; /* signal the TFA98XX to mute */ err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); if (tfa->verbose) pr_debug("-------------------unmuted ------------------\n"); return err; } static void individual_calibration_results(struct tfa_device *tfa) { int value_P, value_S; /* Read the calibration result in xmem (529=primary channel) (530=secondary channel) */ mem_read(tfa, 529, 1, &value_P); mem_read(tfa, 530, 1, &value_S); if (value_P != 1 && value_S != 1) pr_debug("Calibration failed on both channels! \n"); else if (value_P != 1) { pr_debug("Calibration failed on Primary (Left) channel! \n"); TFA_SET_BF_VOLATILE(tfa, SSLEFTE, 0); /* Disable the sound for the left speaker */ } else if (value_S != 1) { pr_debug("Calibration failed on Secondary (Right) channel! \n"); TFA_SET_BF_VOLATILE(tfa, SSRIGHTE, 0); /* Disable the sound for the right speaker */ } TFA_SET_BF_VOLATILE(tfa, AMPINSEL, 0); /* Set amplifier input to TDM */ TFA_SET_BF_VOLATILE(tfa, SBSL, 1); } /* * wait for calibrateDone */ enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateDone) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int tries = 0, mtp_busy = 1, tries_mtp_busy = 0; *calibrateDone = 0; /* in case of calibrate once wait for MTPEX */ if (TFA_GET_BF(tfa, MTPOTC)) { // Check if MTP_busy is clear! while (tries_mtp_busy < MTPBWAIT_TRIES) { mtp_busy = tfa_dev_get_mtpb(tfa); if (mtp_busy == 1) msleep_interruptible(10); /* wait 10ms to avoid busload */ else break; tries_mtp_busy++; } if (tries_mtp_busy < MTPBWAIT_TRIES) { /* Because of the msleep TFA98XX_API_WAITRESULT_NTRIES is way to long! * Setting this to 25 will take it atleast 25*50ms = 1.25 sec */ while ((*calibrateDone == 0) && (tries < MTPEX_WAIT_NTRIES)) { *calibrateDone = TFA_GET_BF(tfa, MTPEX); if (*calibrateDone == 1) break; msleep_interruptible(50); /* wait 50ms to avoid busload */ tries++; } if (tries >= MTPEX_WAIT_NTRIES) { tries = TFA98XX_API_WAITRESULT_NTRIES; } } else { pr_err("MTP bussy after %d tries\n", MTPBWAIT_TRIES); } } /* poll xmem for calibrate always * calibrateDone = 0 means "calibrating", * calibrateDone = -1 (or 0xFFFFFF) means "fails" * calibrateDone = 1 means calibration done */ while ((*calibrateDone != 1) && (tries < TFA98XX_API_WAITRESULT_NTRIES)) { err = mem_read(tfa, TFA_FW_XMEM_CALIBRATION_DONE, 1, calibrateDone); if (*calibrateDone == -1) break; tries++; } if (*calibrateDone != 1) { pr_err("Calibration failed! \n"); err = Tfa98xx_Error_Bad_Parameter; } else if (tries == TFA98XX_API_WAITRESULT_NTRIES) { pr_debug("Calibration has timedout! \n"); err = Tfa98xx_Error_StateTimedOut; } else if (tries_mtp_busy == 1000) { pr_err("Calibrate Failed: MTP_busy stays high! \n"); err = Tfa98xx_Error_StateTimedOut; } /* Give reason why calibration failed! */ if (err != Tfa98xx_Error_Ok) { if ((tfa->tfa_family == 2) && (TFA_GET_BF(tfa, REFCKSEL) == 1)) { pr_err("Unable to calibrate the device with the internal clock! \n"); } } /* Check which speaker calibration failed. Only for 88C */ if ((err != Tfa98xx_Error_Ok) && ((tfa->rev & 0x0FFF) == 0xc88)) { individual_calibration_results(tfa); } return err; } /* * tfa_dev_start will only do the basics: Going from powerdown to operating or a profile switch. * for calibrating or akoustic shock handling use the tfa98xxCalibration function. */ enum tfa_error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int active_profile = -1; /* Get currentprofile */ active_profile = tfa_dev_get_swprof(tfa); if (active_profile == 0xff) active_profile = -1; /* TfaRun_SpeakerBoost implies un-mute */ pr_debug("Active_profile:%s, next_profile:%s\n", tfaContProfileName(tfa->cnt, tfa->dev_idx, active_profile), tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile)); err = show_current_state(tfa); if (tfa->tfa_family == 1) { /* TODO move this to ini file */ /* Enable I2S output on TFA1 devices without TDM */ err = tfa98xx_aec_output(tfa, 1); if (err != Tfa98xx_Error_Ok) goto error_exit; } if (tfa->bus != 0) { /* non i2c */ #ifndef __KERNEL__ tfadsp_fw_start(tfa, next_profile, vstep); #endif /* __KERNEL__ */ } else { /* Check if we need coldstart or ACS is set */ err = tfaRunSpeakerBoost(tfa, 0, next_profile); if (err != Tfa98xx_Error_Ok) goto error_exit; /* Make sure internal oscillator is running for DSP devices (non-dsp and max1 this is no-op) */ tfa98xx_set_osc_powerdown(tfa, 0); /* Go to the Operating state */ tfa_dev_set_state(tfa, TFA_STATE_OPERATING | TFA_STATE_MUTE, 0); } active_profile = tfa_dev_get_swprof(tfa); /* Profile switching */ if ((next_profile != active_profile && active_profile >= 0)) { err = tfaContWriteProfile(tfa, next_profile, vstep); if (err != Tfa98xx_Error_Ok) goto error_exit; } /* If the profile contains the .standby suffix go to powerdown * else we should be in operating state */ if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile), ".standby") != NULL) { tfa_dev_set_swprof(tfa, (unsigned short)next_profile); tfa_dev_set_swvstep(tfa, (unsigned short)vstep); goto error_exit; } err = show_current_state(tfa); if ((TFA_GET_BF(tfa, CFE) != 0) && (vstep != tfa->vstep) && (vstep != -1)) { err = tfaContWriteFilesVstep(tfa, next_profile, vstep); if (err != Tfa98xx_Error_Ok) goto error_exit; } /* Always search and apply filters after a startup */ err = tfa_set_filters(tfa, next_profile); if (err != Tfa98xx_Error_Ok) goto error_exit; tfa_dev_set_swprof(tfa, (unsigned short)next_profile); tfa_dev_set_swvstep(tfa, (unsigned short)vstep); /* PLMA5539: Gives information about current setting of powerswitch */ if (tfa->verbose) { if (!tfa98xx_powerswitch_is_enabled(tfa)) pr_info("Device start without powerswitch enabled!\n"); } error_exit: show_current_state(tfa); return (enum tfa_error)err; } enum tfa_error tfa_dev_stop(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; /* mute */ tfaRunMute(tfa); /* Make sure internal oscillator is not running for DSP devices (non-dsp and max1 this is no-op) */ tfa98xx_set_osc_powerdown(tfa, 1); /* powerdown CF */ err = tfa98xx_powerdown(tfa, 1); if (err != Tfa98xx_Error_Ok) return (enum tfa_error)err; /* disable I2S output on TFA1 devices without TDM */ err = tfa98xx_aec_output(tfa, 0); return (enum tfa_error)err; } /* * int registers and coldboot dsp */ int tfa_reset(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int state = -1; int retry_cnt = 0; /* Check device state. Print warning if reset is done from other state than powerdown (when verbose) */ state = tfa_dev_get_state(tfa); if (tfa->verbose) { if (((tfa->tfa_family == 1) && state != TFA_STATE_RESET) || ((tfa->tfa_family == 2) && state != TFA_STATE_POWERDOWN)) { pr_info("WARNING: Device reset should be performed in POWERDOWN state\n"); } } /* Split TFA1 behavior from TFA2*/ if (tfa->tfa_family == 1) { err = TFA_SET_BF(tfa, I2CR, 1); if (err) return err; err = tfa98xx_powerdown(tfa, 0); if (err) return err; err = tfa_cf_powerup(tfa); if (err) return err; err = tfaRunColdboot(tfa, 1); if (err) return err; err = TFA_SET_BF(tfa, I2CR, 1); } else { /* Probus devices needs extra protection to ensure proper reset behavior, this step is valid only in state other than powerdown */ if (tfa->is_probus_device && state != TFA_STATE_POWERDOWN) { err = TFA_SET_BF_VOLATILE(tfa, AMPE, 0); if (err) return err; err = tfa98xx_powerdown(tfa, 1); if (err) return err; } err = TFA_SET_BF_VOLATILE(tfa, I2CR, 1); if (err) return err; /* Restore MANSCONF to POR state */ err = TFA_SET_BF_VOLATILE(tfa, MANSCONF, 0); if (err) return err; /* Probus devices HW are already reseted here, Last step is to send init message to softDSP */ if (tfa->is_probus_device) { if (tfa->ext_dsp > 0) { err = tfa98xx_init_dsp(tfa); /* ext_dsp status from warm to cold after reset */ if (tfa->ext_dsp == 2) { tfa->ext_dsp = 1; } } } else { /* Restore MANCOLD to POR state */ TFA_SET_BF_VOLATILE(tfa, MANCOLD, 1); /* Coolflux has to be powered on to ensure proper ACS bit state */ /* Powerup CF to access CF io */ err = tfa98xx_powerdown(tfa, 0); if (err) return err; /* For clock */ err = tfa_cf_powerup(tfa); if (err) return err; /* Force cold boot */ err = tfaRunColdboot(tfa, 1); /* Set ACS */ if (err) return err; /* Set PWDN = 1, this will transfer device into powerdown state */ err = TFA_SET_BF_VOLATILE(tfa, PWDN, 1); if (err) return err; /* 88 needs SBSL on top of PWDN bit to start transition, for 92 and 94 this doesn't matter */ err = TFA_SET_BF_VOLATILE(tfa, SBSL, 1); if (err) return err; /* Powerdown state should be reached within 1ms */ for (retry_cnt = 0; retry_cnt < TFA98XX_WAITRESULT_NTRIES; retry_cnt++) { if (is_94_N2_device(tfa)) state = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); else state = TFA_GET_BF(tfa, MANSTATE); if (state < 0) { return err; } /* Check for MANSTATE=Powerdown (0) */ if (state == 0) break; msleep_interruptible(2); } /* Reset all I2C registers to default values, now device state is consistent, same as after powerup */ err = TFA_SET_BF(tfa, I2CR, 1); } } return err; } /* * Write all the bytes specified by num_bytes and data */ enum Tfa98xx_Error tfa98xx_write_data(struct tfa_device *tfa, unsigned char subaddress, int num_bytes, const unsigned char data[]) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; /* subaddress followed by data */ const int bytes2write = num_bytes + 1; unsigned char *write_data; if (num_bytes > TFA2_MAX_PARAM_SIZE) return Tfa98xx_Error_Bad_Parameter; write_data = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); if (write_data == NULL) return Tfa98xx_Error_Fail; write_data[0] = subaddress; memcpy(&write_data[1], data, num_bytes); error = tfa98xx_write_raw(tfa, bytes2write, write_data); kmem_cache_free(tfa->cachep, write_data); return error; } /* * fill the calibration value as milli ohms in the struct * * assume that the device has been calibrated */ enum Tfa98xx_Error tfa_dsp_get_calibration_impedance(struct tfa_device *tfa) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; unsigned char bytes[3 * 2] = { 0 }; int nr_bytes, i, data[2], calibrateDone, spkr_count = 0, cal_idx = 0; unsigned int scaled_data; int tries = 0; error = tfa_supported_speakers(tfa, &spkr_count); if (tfa_dev_mtp_get(tfa, TFA_MTP_OTC)) { pr_debug("Getting calibration values from MTP\n"); if ((tfa->rev & 0xFF) == 0x88) { for (i = 0; i < spkr_count; i++) { if (i == 0) tfa->mohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_PRIM); else tfa->mohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_SEC); } } else { tfa->mohm[0] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25); } } else { pr_debug("Getting calibration values from Speakerboost\n"); /* Make sure the calibrateDone bit is set before getting the values from speakerboost! * This does not work for 72 (because the dsp cannot set this bit) */ if (!tfa->is_probus_device) { /* poll xmem for calibrate always * calibrateDone = 0 means "calibrating", * calibrateDone = -1 (or 0xFFFFFF) means "fails" * calibrateDone = 1 means calibration done */ calibrateDone = 0; while ((calibrateDone != 1) && (tries < TFA98XX_API_WAITRESULT_NTRIES)) { error = mem_read(tfa, TFA_FW_XMEM_CALIBRATION_DONE, 1, &calibrateDone); if (calibrateDone == 1) break; tries++; } if (calibrateDone != 1) { pr_err("Calibration failed! \n"); error = Tfa98xx_Error_Bad_Parameter; } else if (tries == TFA98XX_API_WAITRESULT_NTRIES) { pr_debug("Calibration has timedout! \n"); error = Tfa98xx_Error_StateTimedOut; } } /* SoftDSP interface differs from hw-dsp interfaces */ if (tfa->is_probus_device && tfa->cnt->ndev > 1) { spkr_count = tfa->cnt->ndev; } nr_bytes = spkr_count * 3; error = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, SB_PARAM_GET_RE25C, nr_bytes, bytes); if (error == Tfa98xx_Error_Ok) { tfa98xx_convert_bytes2data(nr_bytes, bytes, data); for (i = 0; i < spkr_count; i++) { /* for probus devices, calibration values coming from soft-dsp speakerboost, are ordered in a different way. Re-align to standard representation. */ cal_idx = i; if ((tfa->is_probus_device && tfa->dev_idx >= 1)) { cal_idx = 0; } /* signed data has a limit of 30 Ohm */ scaled_data = data[i]; if (tfa->tfa_family == 2) tfa->mohm[cal_idx] = (scaled_data * 1000) / TFA2_FW_ReZ_SCALE; else tfa->mohm[cal_idx] = (scaled_data * 1000) / TFA1_FW_ReZ_SCALE; } } } return error; } /* start count from 1, 0 is invalid */ int tfa_dev_get_swprof(struct tfa_device *tfa) { return (tfa->dev_ops.get_swprof)(tfa); } int tfa_dev_set_swprof(struct tfa_device *tfa, unsigned short new_value) { return (tfa->dev_ops.set_swprof)(tfa, new_value + 1); } /* same value for all channels * start count from 1, 0 is invalid */ int tfa_dev_get_swvstep(struct tfa_device *tfa) { return (tfa->dev_ops.get_swvstep)(tfa); } int tfa_dev_set_swvstep(struct tfa_device *tfa, unsigned short new_value) { return (tfa->dev_ops.set_swvstep)(tfa, new_value + 1); } /* function overload for MTPB */ int tfa_dev_get_mtpb(struct tfa_device *tfa) { return (tfa->dev_ops.get_mtpb)(tfa); } int tfa_is_cold(struct tfa_device *tfa) { int value; /* * check for cold boot status */ if (tfa->is_probus_device) { if (tfa->ext_dsp > 0) { if (tfa->ext_dsp == 2) value = 0; // warm else /* no dsp or cold */ value = 1; // cold } else { value = (TFA_GET_BF(tfa, MANSCONF) == 0); } } else { value = TFA_GET_BF(tfa, ACS); } return value; } int tfa_needs_reset(struct tfa_device *tfa) { int value; /* checks if the DSP commands SetAlgoParams and SetMBDrc * need a DSP reset (now: at coldstart or during calibration) */ if (tfa_is_cold(tfa) == 1 || tfa->needs_reset == 1) value = 1; else value = 0; return value; } int tfa_cf_enabled(struct tfa_device *tfa) { int value; /* For 72 there is no CF */ if (tfa->is_probus_device) { value = (tfa->ext_dsp != 0); } else { value = TFA_GET_BF(tfa, CFE); } return value; } #define NR_COEFFS 6 #define NR_BIQUADS 28 #define BQ_SIZE (3 * NR_COEFFS) #define DSP_MSG_OVERHEAD 27 #pragma pack (push, 1) struct dsp_msg_all_coeff { uint8_t select_eq[3]; uint8_t biquad[NR_BIQUADS][NR_COEFFS][3]; }; #pragma pack (pop) /* number of biquads for each equalizer */ static const int eq_biquads[] = { 10, 10, 2, 2, 2, 2 }; #define NR_EQ (int)(sizeof(eq_biquads) / sizeof(int)) enum Tfa98xx_Error dsp_partial_coefficients(struct tfa_device *tfa, uint8_t *prev, uint8_t *next) { uint8_t bq, eq; int eq_offset; int new_cost, old_cost; uint32_t eq_biquad_mask[NR_EQ]; enum Tfa98xx_Error err = Tfa98xx_Error_Ok; struct dsp_msg_all_coeff *data1 = (struct dsp_msg_all_coeff *)prev; struct dsp_msg_all_coeff *data2 = (struct dsp_msg_all_coeff *)next; old_cost = DSP_MSG_OVERHEAD + 3 + sizeof(struct dsp_msg_all_coeff); new_cost = 0; eq_offset = 0; for (eq = 0; eq < NR_EQ; eq++) { uint8_t *eq1 = &data1->biquad[eq_offset][0][0]; uint8_t *eq2 = &data2->biquad[eq_offset][0][0]; eq_biquad_mask[eq] = 0; if (memcmp(eq1, eq2, BQ_SIZE*eq_biquads[eq]) != 0) { int nr_bq = 0; int bq_sz, eq_sz; for (bq = 0; bq < eq_biquads[eq]; bq++) { uint8_t *bq1 = &eq1[bq*BQ_SIZE]; uint8_t *bq2 = &eq2[bq*BQ_SIZE]; if (memcmp(bq1, bq2, BQ_SIZE) != 0) { eq_biquad_mask[eq] |= (1 << bq); nr_bq++; } } bq_sz = (2 * 3 + BQ_SIZE) * nr_bq; eq_sz = 2 * 3 + BQ_SIZE * eq_biquads[eq]; /* dsp message i2c transaction overhead */ bq_sz += DSP_MSG_OVERHEAD * nr_bq; eq_sz += DSP_MSG_OVERHEAD; if (bq_sz >= eq_sz) { eq_biquad_mask[eq] = 0xffffffff; new_cost += eq_sz; } else { new_cost += bq_sz; } } pr_debug("eq_biquad_mask[%d] = 0x%.8x\n", eq, eq_biquad_mask[eq]); eq_offset += eq_biquads[eq]; } pr_debug("cost for writing all coefficients = %d\n", old_cost); pr_debug("cost for writing changed coefficients = %d\n", new_cost); if (new_cost >= old_cost) { const int buffer_sz = 3 + sizeof(struct dsp_msg_all_coeff); uint8_t *buffer; buffer = kmalloc(buffer_sz, GFP_KERNEL); if (buffer == NULL) return Tfa98xx_Error_Fail; /* cmd id */ buffer[0] = 0x00; buffer[1] = 0x82; buffer[2] = 0x00; /* parameters */ memcpy(&buffer[3], data2, sizeof(struct dsp_msg_all_coeff)); err = dsp_msg(tfa, buffer_sz, (const char *)buffer); kfree(buffer); if (err) return err; } else { eq_offset = 0; for (eq = 0; eq < NR_EQ; eq++) { uint8_t *eq2 = &data2->biquad[eq_offset][0][0]; if (eq_biquad_mask[eq] == 0xffffffff) { const int msg_sz = 6 + BQ_SIZE * eq_biquads[eq]; uint8_t *msg; msg = kmalloc(msg_sz, GFP_KERNEL); if (msg == NULL) return Tfa98xx_Error_Fail; /* cmd id */ msg[0] = 0x00; msg[1] = 0x82; msg[2] = 0x00; /* select eq and bq */ msg[3] = 0x00; msg[4] = eq + 1; msg[5] = 0x00; /* all biquads */ /* biquad parameters */ memcpy(&msg[6], eq2, BQ_SIZE * eq_biquads[eq]); err = dsp_msg(tfa, msg_sz, (const char *)msg); kfree(msg); if (err) return err; } else if (eq_biquad_mask[eq] != 0) { for (bq = 0; bq < eq_biquads[eq]; bq++) { if (eq_biquad_mask[eq] & (1 << bq)) { uint8_t *bq2 = &eq2[bq*BQ_SIZE]; const int msg_sz = 6 + BQ_SIZE; uint8_t *msg; msg = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); if (msg == NULL) return Tfa98xx_Error_Fail; /* cmd id */ msg[0] = 0x00; msg[1] = 0x82; msg[2] = 0x00; /* select eq and bq*/ msg[3] = 0x00; msg[4] = eq + 1; msg[5] = bq + 1; /* biquad parameters */ memcpy(&msg[6], bq2, BQ_SIZE); err = dsp_msg(tfa, msg_sz, (const char *)msg); kmem_cache_free(tfa->cachep, msg); if (err) return err; } } } eq_offset += eq_biquads[eq]; } } return err; } /* fill context info */ int tfa_dev_probe(int slave, struct tfa_device *tfa) { uint16_t rev; tfa->slave_address = (unsigned char)slave; /* read revid via low level hal, register 3 */ if (tfa98xx_read_register16(tfa, 3, &rev) != Tfa98xx_Error_Ok) { PRINT("\nError: Unable to read revid from slave:0x%02x \n", slave); return ERR; } tfa->rev = rev; tfa->dev_idx = -1; tfa->state = TFA_STATE_UNKNOWN; tfa->p_regInfo = NULL; tfa_set_query_info(tfa); tfa->in_use = 1; return 0; } enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, int is_calibration) { enum tfa_error err = tfa_error_ok; int loop = 50, ready = 0; int count; /* Base states */ /* Do not change the order of setting bits as this is important! */ switch (state & 0x0f) { case TFA_STATE_POWERDOWN: /* PLL in powerdown, Algo up */ break; case TFA_STATE_INIT_HW: /* load I2C/PLL hardware setting (~wait2srcsettings) */ break; case TFA_STATE_INIT_CF: /* coolflux HW access possible (~initcf) */ /* Start with SBSL=0 to stay in initCF state */ if (!tfa->is_probus_device) TFA_SET_BF(tfa, SBSL, 0); /* We want to leave Wait4SrcSettings state for max2 */ if (tfa->tfa_family == 2) TFA_SET_BF(tfa, MANSCONF, 1); /* And finally set PWDN to 0 to leave powerdown state */ TFA_SET_BF(tfa, PWDN, 0); /* Make sure the DSP is running! */ do { err = (enum tfa_error)tfa98xx_dsp_system_stable(tfa, &ready); if (err != tfa_error_ok) return err; if (ready) break; } while (loop--); if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { /* Enable FAIM when clock is stable, to avoid MTP corruption */ err = (enum tfa_error)tfa98xx_faim_protect(tfa, 1); if (tfa->verbose) { pr_debug("FAIM enabled (err:%d).\n", err); } } break; case TFA_STATE_INIT_FW: /* DSP framework active (~patch loaded) */ break; case TFA_STATE_OPERATING: /* Amp and Algo running */ /* Depending on our previous state we need to set 3 bits */ TFA_SET_BF(tfa, PWDN, 0); /* Coming from state 0 */ TFA_SET_BF(tfa, MANSCONF, 1); /* Coming from state 1 */ if (!tfa->is_probus_device) TFA_SET_BF(tfa, SBSL, 1); /* Coming from state 6 */ else TFA_SET_BF(tfa, AMPE, 1); /* No SBSL for probus device, we set AMPE to 1 */ /* * Disable MTP clock to protect memory. * However in case of calibration wait for DSP! (This should be case only during calibration). */ if (TFA_GET_BF(tfa, MTPOTC) == 1 && tfa->tfa_family == 2) { count = MTPEX_WAIT_NTRIES * 4; /* Calibration takes a lot of time */ while ((TFA_GET_BF(tfa, MTPEX) != 1) && count) { msleep_interruptible(10); count--; } } if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { err = (enum tfa_error)tfa98xx_faim_protect(tfa, 0); if (tfa->verbose) { pr_debug("FAIM disabled (err:%d).\n", err); } } /* Synchonize I/V delay on 96/97 at cold start */ if (tfa->sync_iv_delay) { if (tfa->verbose) pr_debug("syncing I/V delay for %x\n", (tfa->rev & 0xff)); /* wait for ACS to be cleared */ count = 10; while ((TFA_GET_BF(tfa, ACS) == 1) && (count-- > 0)) { msleep_interruptible(1); } tfa98xx_dsp_reset(tfa, 1); tfa98xx_dsp_reset(tfa, 0); tfa->sync_iv_delay = 0; } break; case TFA_STATE_FAULT: /* An alarm or error occurred */ break; case TFA_STATE_RESET: /* I2C reset and ACS set */ tfa98xx_init(tfa); break; default: if (state & 0x0f) return tfa_error_bad_param; } /* state modifiers */ if (state & TFA_STATE_MUTE) tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); if (state & TFA_STATE_UNMUTE) tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); tfa->state = state; return tfa_error_ok; } enum tfa_state tfa_dev_get_state(struct tfa_device *tfa) { int cold = 0; int manstate; /* different per family type */ if (tfa->tfa_family == 1) { cold = TFA_GET_BF(tfa, ACS); if (cold && TFA_GET_BF(tfa, PWDN)) tfa->state = TFA_STATE_RESET; else if (!cold && TFA_GET_BF(tfa, SWS)) tfa->state = TFA_STATE_OPERATING; } else /* family 2 */ { if (is_94_N2_device(tfa)) manstate = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); else manstate = TFA_GET_BF(tfa, MANSTATE); switch (manstate) { case 0: tfa->state = TFA_STATE_POWERDOWN; break; case 8: /* if dsp reset if off assume framework is running */ tfa->state = TFA_GET_BF(tfa, RST) ? TFA_STATE_INIT_CF : TFA_STATE_INIT_FW; break; case 9: tfa->state = TFA_STATE_OPERATING; break; default: break; } } return tfa->state; } int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item) { int value = 0; switch (item) { case TFA_MTP_OTC: value = TFA_GET_BF(tfa, MTPOTC); break; case TFA_MTP_EX: value = TFA_GET_BF(tfa, MTPEX); break; case TFA_MTP_RE25: case TFA_MTP_RE25_PRIM: if (tfa->tfa_family == 2) { if ((tfa->rev & 0xFF) == 0x88) value = TFA_GET_BF(tfa, R25CL); else if ((tfa->rev & 0xFF) == 0x13) value = tfa_get_bf(tfa, TFA9912_BF_R25C); else value = TFA_GET_BF(tfa, R25C); } else { reg_read(tfa, 0x83, (unsigned short *)&value); } break; case TFA_MTP_RE25_SEC: if ((tfa->rev & 0xFF) == 0x88) { value = TFA_GET_BF(tfa, R25CR); } else { pr_debug("Error: Current device has no secondary Re25 channel \n"); } break; case TFA_MTP_LOCK: break; } return value; } enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value) { enum tfa_error err = tfa_error_ok; switch (item) { case TFA_MTP_OTC: err = (enum tfa_error)tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK); break; case TFA_MTP_EX: err = (enum tfa_error)tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); break; case TFA_MTP_RE25: case TFA_MTP_RE25_PRIM: if (tfa->tfa_family == 2) { tfa98xx_key2(tfa, 0); /* unlock */ if ((tfa->rev & 0xFF) == 0x88) TFA_SET_BF(tfa, R25CL, (uint16_t)value); else { if (tfa->is_probus_device == 1 && TFA_GET_BF(tfa, MTPOTC) == 1) tfa2_manual_mtp_cpy(tfa, 0xF4, value, 2); TFA_SET_BF(tfa, R25C, (uint16_t)value); } tfa98xx_key2(tfa, 1); /* lock */ } break; case TFA_MTP_RE25_SEC: if ((tfa->rev & 0xFF) == 0x88) { TFA_SET_BF(tfa, R25CR, (uint16_t)value); } else { pr_debug("Error: Current device has no secondary Re25 channel \n"); err = tfa_error_bad_param; } break; case TFA_MTP_LOCK: break; } return (enum tfa_error)err; } int tfa_get_pga_gain(struct tfa_device *tfa) { return TFA_GET_BF(tfa, SAAMGAIN); } int tfa_set_pga_gain(struct tfa_device *tfa, uint16_t value) { return TFA_SET_BF(tfa, SAAMGAIN, value); } int tfa_get_noclk(struct tfa_device *tfa) { return TFA_GET_BF(tfa, NOCLK); } enum Tfa98xx_Error tfa_status(struct tfa_device *tfa) { int value; uint16_t val; /* * check IC status bits: cold start * and DSP watch dog bit to re init */ value = TFA_READ_REG(tfa, VDDS); /* STATUSREG */ if (value < 0) return -value; val = (uint16_t)value; /* pr_debug("SYS_STATUS0: 0x%04x\n", val); */ if (TFA_GET_BF_VALUE(tfa, ACS, val) || TFA_GET_BF_VALUE(tfa, WDS, val)) { if (TFA_GET_BF_VALUE(tfa, ACS, val)) pr_err("ERROR: ACS\n"); if (TFA_GET_BF_VALUE(tfa, WDS, val)) pr_err("ERROR: WDS\n"); return Tfa98xx_Error_DSP_not_running; } if (TFA_GET_BF_VALUE(tfa, SPKS, val)) pr_err("ERROR: SPKS\n"); if (!TFA_GET_BF_VALUE(tfa, SWS, val)) pr_err("ERROR: SWS\n"); /* Check secondary errors */ if (!TFA_GET_BF_VALUE(tfa, CLKS, val) || !TFA_GET_BF_VALUE(tfa, UVDS, val) || !TFA_GET_BF_VALUE(tfa, OVDS, val) || !TFA_GET_BF_VALUE(tfa, OTDS, val) || !TFA_GET_BF_VALUE(tfa, PLLS, val) || (!(tfa->daimap & Tfa98xx_DAI_TDM) && !TFA_GET_BF_VALUE(tfa, VDDS, val))) pr_err("Misc errors detected: STATUS_FLAG0 = 0x%x\n", val); if ((tfa->daimap & Tfa98xx_DAI_TDM) && (tfa->tfa_family == 2)) { value = TFA_READ_REG(tfa, TDMERR); /* STATUS_FLAGS1 */ if (value < 0) return -value; val = (uint16_t)value; if (TFA_GET_BF_VALUE(tfa, TDMERR, val) || TFA_GET_BF_VALUE(tfa, TDMLUTER, val)) pr_err("TDM related errors: STATUS_FLAG1 = 0x%x\n", val); } return Tfa98xx_Error_Ok; } int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep) { enum Tfa98xx_Error err; int no_clk = 0; /* Remove sticky bit by reading it once */ TFA_GET_BF(tfa, NOCLK); /* No clock detected */ if (tfa_irq_get(tfa, tfa9912_irq_stnoclk)) { no_clk = TFA_GET_BF(tfa, NOCLK); /* Detect for clock is lost! (clock is not stable) */ if (no_clk == 1) { /* Clock is lost. Set I2CR to remove POP noise */ pr_info("No clock detected. Resetting the I2CR to avoid pop on 72! \n"); err = (enum Tfa98xx_Error)tfa_dev_start(tfa, profile, vstep); if (err != Tfa98xx_Error_Ok) { pr_err("Error loading i2c registers (tfa_dev_start), err=%d\n", err); } else { pr_info("Setting i2c registers after I2CR succesfull\n"); tfa_dev_set_state(tfa, TFA_STATE_UNMUTE, 0); } /* Remove sticky bit by reading it once */ tfa_get_noclk(tfa); /* This is only for SAAM on the 72. Since the NOCLK interrupt is only enabled for 72 this is the place However: Not tested yet! But also does not harm normal flow! */ if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, profile), ".saam")) { pr_info("Powering down from a SAAM profile, workaround PLMA4766 used! \n"); TFA_SET_BF(tfa, PWDN, 1); TFA_SET_BF(tfa, AMPE, 0); TFA_SET_BF(tfa, SAMMODE, 0); } } /* If clk is stable set polarity to check for LOW (no clock)*/ tfa_irq_set_pol(tfa, tfa9912_irq_stnoclk, (no_clk == 0)); /* clear interrupt */ tfa_irq_clear(tfa, tfa9912_irq_stnoclk); } /* return no_clk to know we called tfa_dev_start */ return no_clk; } void tfa_lp_mode_interrupt(struct tfa_device *tfa) { const int irq_stclp0 = 36; /* FIXME: this 72 interrupt does not excist for 9912 */ int lp0, lp1; if (tfa_irq_get(tfa, irq_stclp0)) { lp0 = TFA_GET_BF(tfa, LP0); if (lp0 > 0) { pr_info("lowpower mode 0 detected\n"); } else { pr_info("lowpower mode 0 not detected\n"); } tfa_irq_set_pol(tfa, irq_stclp0, (lp0 == 0)); /* clear interrupt */ tfa_irq_clear(tfa, irq_stclp0); } if (tfa_irq_get(tfa, tfa9912_irq_stclpr)) { lp1 = TFA_GET_BF(tfa, LP1); if (lp1 > 0) { pr_info("lowpower mode 1 detected\n"); } else { pr_info("lowpower mode 1 not detected\n"); } tfa_irq_set_pol(tfa, tfa9912_irq_stclpr, (lp1 == 0)); /* clear interrupt */ tfa_irq_clear(tfa, tfa9912_irq_stclpr); } }