bool cs42l43_readable_register(struct device *dev, unsignedint reg)
{ switch (reg) { case CS42L43_DEVID: case CS42L43_REVID: case CS42L43_RELID: case CS42L43_SFT_RESET: case CS42L43_DRV_CTRL1: case CS42L43_DRV_CTRL3: case CS42L43_DRV_CTRL4: case CS42L43_DRV_CTRL_5: case CS42L43_GPIO_CTRL1: case CS42L43_GPIO_CTRL2: case CS42L43_GPIO_STS: case CS42L43_GPIO_FN_SEL: case CS42L43_MCLK_SRC_SEL: case CS42L43_SAMPLE_RATE1 ... CS42L43_SAMPLE_RATE4: case CS42L43_PLL_CONTROL: case CS42L43_FS_SELECT1 ... CS42L43_FS_SELECT4: case CS42L43_PDM_CONTROL: case CS42L43_ASP_CLK_CONFIG1 ... CS42L43_ASP_CLK_CONFIG2: case CS42L43_OSC_DIV_SEL: case CS42L43_ADC_B_CTRL1 ... CS42L43_ADC_B_CTRL2: case CS42L43_DECIM_HPF_WNF_CTRL1 ... CS42L43_DECIM_HPF_WNF_CTRL4: case CS42L43_DMIC_PDM_CTRL: case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4: case CS42L43_INTP_VOLUME_CTRL1 ... CS42L43_INTP_VOLUME_CTRL2: case CS42L43_AMP1_2_VOL_RAMP: case CS42L43_ASP_CTRL: case CS42L43_ASP_FSYNC_CTRL1 ... CS42L43_ASP_FSYNC_CTRL4: case CS42L43_ASP_DATA_CTRL: case CS42L43_ASP_RX_EN ... CS42L43_ASP_TX_EN: case CS42L43_ASP_RX_CH1_CTRL ... CS42L43_ASP_RX_CH6_CTRL: case CS42L43_ASP_TX_CH1_CTRL ... CS42L43_ASP_TX_CH6_CTRL: case CS42L43_OTP_REVISION_ID: case CS42L43_ASPTX1_INPUT: case CS42L43_ASPTX2_INPUT: case CS42L43_ASPTX3_INPUT: case CS42L43_ASPTX4_INPUT: case CS42L43_ASPTX5_INPUT: case CS42L43_ASPTX6_INPUT: case CS42L43_SWIRE_DP1_CH1_INPUT: case CS42L43_SWIRE_DP1_CH2_INPUT: case CS42L43_SWIRE_DP1_CH3_INPUT: case CS42L43_SWIRE_DP1_CH4_INPUT: case CS42L43_SWIRE_DP2_CH1_INPUT: case CS42L43_SWIRE_DP2_CH2_INPUT: case CS42L43_SWIRE_DP3_CH1_INPUT: case CS42L43_SWIRE_DP3_CH2_INPUT: case CS42L43_SWIRE_DP4_CH1_INPUT: case CS42L43_SWIRE_DP4_CH2_INPUT: case CS42L43_ASRC_INT1_INPUT1: case CS42L43_ASRC_INT2_INPUT1: case CS42L43_ASRC_INT3_INPUT1: case CS42L43_ASRC_INT4_INPUT1: case CS42L43_ASRC_DEC1_INPUT1: case CS42L43_ASRC_DEC2_INPUT1: case CS42L43_ASRC_DEC3_INPUT1: case CS42L43_ASRC_DEC4_INPUT1: case CS42L43_ISRC1INT1_INPUT1: case CS42L43_ISRC1INT2_INPUT1: case CS42L43_ISRC1DEC1_INPUT1: case CS42L43_ISRC1DEC2_INPUT1: case CS42L43_ISRC2INT1_INPUT1: case CS42L43_ISRC2INT2_INPUT1: case CS42L43_ISRC2DEC1_INPUT1: case CS42L43_ISRC2DEC2_INPUT1: case CS42L43_EQ1MIX_INPUT1 ... CS42L43_EQ1MIX_INPUT4: case CS42L43_EQ2MIX_INPUT1 ... CS42L43_EQ2MIX_INPUT4: case CS42L43_SPDIF1_INPUT1: case CS42L43_SPDIF2_INPUT1: case CS42L43_AMP1MIX_INPUT1 ... CS42L43_AMP1MIX_INPUT4: case CS42L43_AMP2MIX_INPUT1 ... CS42L43_AMP2MIX_INPUT4: case CS42L43_AMP3MIX_INPUT1 ... CS42L43_AMP3MIX_INPUT4: case CS42L43_AMP4MIX_INPUT1 ... CS42L43_AMP4MIX_INPUT4: case CS42L43_ASRC_INT_ENABLES ... CS42L43_ASRC_DEC_ENABLES: case CS42L43_PDNCNTL: case CS42L43_RINGSENSE_DEB_CTRL: case CS42L43_TIPSENSE_DEB_CTRL: case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS: case CS42L43_HS2: case CS42L43_HS_STAT: case CS42L43_MCU_SW_INTERRUPT: case CS42L43_STEREO_MIC_CTRL: case CS42L43_STEREO_MIC_CLAMP_CTRL: case CS42L43_BLOCK_EN2 ... CS42L43_BLOCK_EN11: case CS42L43_TONE_CH1_CTRL ... CS42L43_TONE_CH2_CTRL: case CS42L43_MIC_DETECT_CONTROL_1: case CS42L43_DETECT_STATUS_1: case CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL: case CS42L43_MIC_DETECT_CONTROL_ANDROID: case CS42L43_ISRC1_CTRL: case CS42L43_ISRC2_CTRL: case CS42L43_CTRL_REG: case CS42L43_FDIV_FRAC: case CS42L43_CAL_RATIO: case CS42L43_SPI_CLK_CONFIG1: case CS42L43_SPI_CONFIG1 ... CS42L43_SPI_CONFIG4: case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2: case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG8: case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3: case CS42L43_TX_DATA: case CS42L43_RX_DATA: case CS42L43_DACCNFG1 ... CS42L43_DACCNFG2: case CS42L43_HPPATHVOL: case CS42L43_PGAVOL: case CS42L43_LOADDETRESULTS: case CS42L43_LOADDETENA: case CS42L43_CTRL: case CS42L43_COEFF_DATA_IN0: case CS42L43_COEFF_RD_WR0: case CS42L43_INIT_DONE0: case CS42L43_START_EQZ0: case CS42L43_MUTE_EQ_IN0: case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT: case CS42L43_DECIM_MASK ... CS42L43_HPOUT_MASK: case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW: case CS42L43_BOOT_CONTROL: case CS42L43_BLOCK_EN: case CS42L43_SHUTTER_CONTROL: case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX: returntrue; default: returnfalse;
}
}
EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, "MFD_CS42L43");
bool cs42l43_precious_register(struct device *dev, unsignedint reg)
{ switch (reg) { case CS42L43_SFT_RESET: case CS42L43_TX_DATA: case CS42L43_RX_DATA: case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT: case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX: returntrue; default: returnfalse;
}
}
EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, "MFD_CS42L43");
bool cs42l43_volatile_register(struct device *dev, unsignedint reg)
{ switch (reg) { case CS42L43_DEVID: case CS42L43_REVID: case CS42L43_RELID: case CS42L43_GPIO_STS: case CS42L43_OTP_REVISION_ID: case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS: case CS42L43_HS_STAT: case CS42L43_MCU_SW_INTERRUPT: case CS42L43_DETECT_STATUS_1: case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2: case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG2: case CS42L43_TRAN_CONFIG8: case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3: case CS42L43_LOADDETRESULTS: case CS42L43_INIT_DONE0: case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW: case CS42L43_BOOT_CONTROL: case CS42L43_BLOCK_EN: returntrue; default: return cs42l43_precious_register(dev, reg);
}
}
EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, "MFD_CS42L43");
/* * If the device is connected over Soundwire, as well as soft resetting the * device, this function will also way for the device to detach from the bus * before returning.
*/ staticint cs42l43_soft_reset(struct cs42l43 *cs42l43)
{ staticconststruct reg_sequence reset[] = {
{ CS42L43_SFT_RESET, CS42L43_SFT_RESET_VAL },
};
reinit_completion(&cs42l43->device_detach);
/* * Apply cache only because the soft reset will cause the device to * detach from the soundwire bus.
*/
regcache_cache_only(cs42l43->regmap, true);
regmap_multi_reg_write_bypassed(cs42l43->regmap, reset, ARRAY_SIZE(reset));
msleep(CS42L43_RESET_DELAY_MS);
if (cs42l43->sdw) { unsignedlong timeout = msecs_to_jiffies(CS42L43_SDW_DETACH_TIMEOUT_MS); unsignedlong time;
time = wait_for_completion_timeout(&cs42l43->device_detach, timeout); if (!time) {
dev_err(cs42l43->dev, "Timed out waiting for device detach\n"); return -ETIMEDOUT;
}
}
return -EAGAIN;
}
/* * This function is essentially a no-op on I2C, but will wait for the device to * attach when the device is used on a SoundWire bus.
*/ staticint cs42l43_wait_for_attach(struct cs42l43 *cs42l43)
{ if (!cs42l43->attached) { unsignedlong timeout = msecs_to_jiffies(CS42L43_SDW_ATTACH_TIMEOUT_MS); unsignedlong time;
time = wait_for_completion_timeout(&cs42l43->device_attach, timeout); if (!time) {
dev_err(cs42l43->dev, "Timed out waiting for device re-attach\n"); return -ETIMEDOUT;
}
}
regcache_cache_only(cs42l43->regmap, false);
/* The hardware requires enabling OSC_DIV before doing any SoundWire reads. */ if (cs42l43->sdw)
regmap_write(cs42l43->regmap, CS42L43_OSC_DIV_SEL,
CS42L43_OSC_DIV2_EN_MASK);
return 0;
}
/* * This function will advance the firmware into boot stage 3 from boot stage 2. * Boot stage 3 is required to send commands to the firmware. This is achieved * by setting the firmware NEED configuration register to zero, this indicates * no configuration is required forcing the firmware to advance to boot stage 3. * * Later revisions of the firmware require the use of an alternative register * for this purpose, which is indicated through the shadow flag.
*/ staticint cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow)
{ unsignedint need_reg = CS42L43_NEED_CONFIGS; unsignedint val; int ret;
if (shadow)
need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
regmap_write(cs42l43->regmap, need_reg, 0);
ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS,
val, (val == CS42L43_MCU_BOOT_STAGE3),
CS42L43_MCU_POLL_US, CS42L43_MCU_CMD_TIMEOUT_US); if (ret) {
dev_err(cs42l43->dev, "Failed to move to stage 3: %d, 0x%x\n", ret, val); return ret;
}
return -EAGAIN;
}
/* * This function will return the firmware to boot stage 2 from boot stage 3. * Boot stage 2 is required to apply updates to the firmware. This is achieved * by setting the firmware NEED configuration register to FW_PATCH_NEED_CFG, * setting the HAVE configuration register to 0, and soft resetting. The * firmware will see it is missing a patch configuration and will pause in boot * stage 2. * * Note: Unlike cs42l43_mcu_stage_2_3 there is no need to consider the shadow * register here as the driver will only return to boot stage 2 if the firmware * requires update which means the revision does not include shadow register * support.
*/ staticint cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43)
{
regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_NEED_CONFIGS,
CS42L43_FW_PATCH_NEED_CFG_MASK);
regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_HAVE_CONFIGS, 0);
return cs42l43_soft_reset(cs42l43);
}
/* * Disable the firmware running on the device such that the driver can access * the registers without fear of the MCU changing them under it.
*/ staticint cs42l43_mcu_disable(struct cs42l43 *cs42l43)
{ unsignedint val; int ret;
staticint cs42l43_mcu_is_hw_compatible(struct cs42l43 *cs42l43, unsignedint mcu_rev, unsignedint bios_rev)
{ /* * The firmware has two revision numbers bringing either of them up to a * supported version will provide the disable the driver requires.
*/ if (mcu_rev < CS42L43_MCU_SUPPORTED_REV &&
bios_rev < CS42L43_MCU_SUPPORTED_BIOS_REV) {
dev_err(cs42l43->dev, "Firmware too old to support disable\n"); return -EINVAL;
}
return 0;
}
/* * The process of updating the firmware is split into a series of steps, at the * end of each step a soft reset of the device might be required which will * require the driver to wait for the device to re-attach on the SoundWire bus, * if that control bus is being used.
*/ staticint cs42l43_mcu_update_step(struct cs42l43 *cs42l43)
{ unsignedint mcu_rev, bios_rev, boot_status, secure_cfg; bool patched, shadow; int ret;
/* Clear any stale software interrupt bits. */
regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev);
ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status); if (ret) {
dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret); return ret;
}
ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev); if (ret) {
dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret); return ret;
}
/* * The firmware has two revision numbers both of them being at the ROM * revision indicates no patch has been applied.
*/
patched = mcu_rev != CS42L43_MCU_ROM_REV || bios_rev != CS42L43_MCU_ROM_BIOS_REV; /* * Later versions of the firmwware require the driver to access some * features through a set of shadow registers.
*/
shadow = (mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV) ||
(bios_rev >= CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV);
ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg); if (ret) {
dev_err(cs42l43->dev, "Failed to read security settings: %d\n", ret); return ret;
}
irq_flags = irqd_get_trigger_type(irq_data); switch (irq_flags) { case IRQF_TRIGGER_LOW: case IRQF_TRIGGER_HIGH: case IRQF_TRIGGER_RISING: case IRQF_TRIGGER_FALLING: break; case IRQ_TYPE_NONE: default:
irq_flags = IRQF_TRIGGER_LOW; break;
}
irq_flags |= IRQF_ONESHOT;
ret = devm_regmap_add_irq_chip(cs42l43->dev, cs42l43->regmap,
cs42l43->irq, irq_flags, 0,
&cs42l43->irq_chip, &cs42l43->irq_data); if (ret) {
dev_err(cs42l43->dev, "Failed to add IRQ chip: %d\n", ret); return ret;
}
dev_dbg(cs42l43->dev, "Configured IRQ %d with flags 0x%lx\n",
cs42l43->irq, irq_flags);
cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(cs42l43->reset)) return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset), "Failed to get reset\n");
gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p"); if (IS_ERR(cs42l43->vdd_p)) return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p), "Failed to get vdd-p\n");
cs42l43->vdd_d = devm_regulator_get(cs42l43->dev, "vdd-d"); if (IS_ERR(cs42l43->vdd_d)) return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_d), "Failed to get vdd-d\n");
for (i = 0; i < CS42L43_N_SUPPLIES; i++)
cs42l43->core_supplies[i].supply = cs42l43_core_supplies[i];
ret = devm_regulator_bulk_get(cs42l43->dev, CS42L43_N_SUPPLIES,
cs42l43->core_supplies); if (ret) return dev_err_probe(cs42l43->dev, ret, "Failed to get core supplies\n");
ret = cs42l43_power_up(cs42l43); if (ret) return ret;
ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_remove, cs42l43); if (ret) return ret;
pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME_MS);
pm_runtime_use_autosuspend(cs42l43->dev);
pm_runtime_set_active(cs42l43->dev); /* * The device is already powered up, but keep it from suspending until * the boot work runs.
*/
pm_runtime_get_noresume(cs42l43->dev);
ret = devm_pm_runtime_enable(cs42l43->dev); if (ret) return ret;
ret = pm_runtime_resume_and_get(dev); if (ret) {
dev_err(cs42l43->dev, "Failed to resume for suspend: %d\n", ret); return ret;
}
/* The IRQs will be re-enabled on resume by the cache sync */
ret = regmap_multi_reg_write_bypassed(cs42l43->regmap,
mask_all, ARRAY_SIZE(mask_all)); if (ret) {
dev_err(cs42l43->dev, "Failed to mask IRQs: %d\n", ret); return ret;
}
disable_irq(cs42l43->irq);
ret = pm_runtime_force_suspend(dev); if (ret) {
dev_err(cs42l43->dev, "Failed to force suspend: %d\n", ret);
pm_runtime_put_noidle(dev); return ret;
}
pm_runtime_put_noidle(dev);
ret = cs42l43_power_down(cs42l43); if (ret) return ret;
/* * Whilst the driver doesn't power the chip down here, going into runtime * suspend lets the SoundWire bus power down, which means the driver * can't communicate with the device any more.
*/
regcache_cache_only(cs42l43->regmap, true);
ret = cs42l43_wait_for_attach(cs42l43); if (ret) return ret;
ret = regmap_read(cs42l43->regmap, CS42L43_RELID, &reset_canary); if (ret) {
dev_err(cs42l43->dev, "Failed to check reset canary: %d\n", ret); goto err;
}
if (!reset_canary) { /* * If the canary has cleared the chip has reset, re-handle the * MCU and mark the cache as dirty to indicate the chip reset.
*/
ret = cs42l43_mcu_update(cs42l43); if (ret) goto err;
regcache_mark_dirty(cs42l43->regmap);
}
ret = regcache_sync(cs42l43->regmap); if (ret) {
dev_err(cs42l43->dev, "Failed to restore register cache: %d\n", ret); goto err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.