/* * Some fields take zero as a valid value so use a high bit flag that won't * get written to the device to mark those.
*/ #define CS35L36_VALID_PDATA 0x80000000
staticbool cs35l36_readable_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case CS35L36_SW_RESET: case CS35L36_SW_REV: case CS35L36_HW_REV: case CS35L36_TESTKEY_CTRL: case CS35L36_USERKEY_CTL: case CS35L36_OTP_MEM30: case CS35L36_OTP_CTRL1: case CS35L36_OTP_CTRL2: case CS35L36_OTP_CTRL3: case CS35L36_OTP_CTRL4: case CS35L36_OTP_CTRL5: case CS35L36_PAC_CTL1: case CS35L36_PAC_CTL2: case CS35L36_PAC_CTL3: case CS35L36_DEVICE_ID: case CS35L36_FAB_ID: case CS35L36_REV_ID: case CS35L36_PWR_CTRL1: case CS35L36_PWR_CTRL2: case CS35L36_PWR_CTRL3: case CS35L36_CTRL_OVRRIDE: case CS35L36_AMP_OUT_MUTE: case CS35L36_OTP_TRIM_STATUS: case CS35L36_DISCH_FILT: case CS35L36_PROTECT_REL_ERR: case CS35L36_PAD_INTERFACE: case CS35L36_PLL_CLK_CTRL: case CS35L36_GLOBAL_CLK_CTRL: case CS35L36_ADC_CLK_CTRL: case CS35L36_SWIRE_CLK_CTRL: case CS35L36_SP_SCLK_CLK_CTRL: case CS35L36_TST_FS_MON0: case CS35L36_MDSYNC_EN: case CS35L36_MDSYNC_TX_ID: case CS35L36_MDSYNC_PWR_CTRL: case CS35L36_MDSYNC_DATA_TX: case CS35L36_MDSYNC_TX_STATUS: case CS35L36_MDSYNC_RX_STATUS: case CS35L36_MDSYNC_ERR_STATUS: case CS35L36_BSTCVRT_VCTRL1: case CS35L36_BSTCVRT_VCTRL2: case CS35L36_BSTCVRT_PEAK_CUR: case CS35L36_BSTCVRT_SFT_RAMP: case CS35L36_BSTCVRT_COEFF: case CS35L36_BSTCVRT_SLOPE_LBST: case CS35L36_BSTCVRT_SW_FREQ: case CS35L36_BSTCVRT_DCM_CTRL: case CS35L36_BSTCVRT_DCM_MODE_FORCE: case CS35L36_BSTCVRT_OVERVOLT_CTRL: case CS35L36_BST_TST_MANUAL: case CS35L36_BST_ANA2_TEST: case CS35L36_VPI_LIMIT_MODE: case CS35L36_VPI_LIMIT_MINMAX: case CS35L36_VPI_VP_THLD: case CS35L36_VPI_TRACK_CTRL: case CS35L36_VPI_TRIG_MODE_CTRL: case CS35L36_VPI_TRIG_STEPS: case CS35L36_VI_SPKMON_FILT: case CS35L36_VI_SPKMON_GAIN: case CS35L36_VI_SPKMON_IP_SEL: case CS35L36_DTEMP_WARN_THLD: case CS35L36_DTEMP_STATUS: case CS35L36_VPVBST_FS_SEL: case CS35L36_VPVBST_VP_CTRL: case CS35L36_VPVBST_VBST_CTRL: case CS35L36_ASP_TX_PIN_CTRL: case CS35L36_ASP_RATE_CTRL: case CS35L36_ASP_FORMAT: case CS35L36_ASP_FRAME_CTRL: case CS35L36_ASP_TX1_TX2_SLOT: case CS35L36_ASP_TX3_TX4_SLOT: case CS35L36_ASP_TX5_TX6_SLOT: case CS35L36_ASP_TX7_TX8_SLOT: case CS35L36_ASP_RX1_SLOT: case CS35L36_ASP_RX_TX_EN: case CS35L36_ASP_RX1_SEL: case CS35L36_ASP_TX1_SEL: case CS35L36_ASP_TX2_SEL: case CS35L36_ASP_TX3_SEL: case CS35L36_ASP_TX4_SEL: case CS35L36_ASP_TX5_SEL: case CS35L36_ASP_TX6_SEL: case CS35L36_SWIRE_P1_TX1_SEL: case CS35L36_SWIRE_P1_TX2_SEL: case CS35L36_SWIRE_P2_TX1_SEL: case CS35L36_SWIRE_P2_TX2_SEL: case CS35L36_SWIRE_P2_TX3_SEL: case CS35L36_SWIRE_DP1_FIFO_CFG: case CS35L36_SWIRE_DP2_FIFO_CFG: case CS35L36_SWIRE_DP3_FIFO_CFG: case CS35L36_SWIRE_PCM_RX_DATA: case CS35L36_SWIRE_FS_SEL: case CS35L36_AMP_DIG_VOL_CTRL: case CS35L36_VPBR_CFG: case CS35L36_VBBR_CFG: case CS35L36_VPBR_STATUS: case CS35L36_VBBR_STATUS: case CS35L36_OVERTEMP_CFG: case CS35L36_AMP_ERR_VOL: case CS35L36_CLASSH_CFG: case CS35L36_CLASSH_FET_DRV_CFG: case CS35L36_NG_CFG: case CS35L36_AMP_GAIN_CTRL: case CS35L36_PWM_MOD_IO_CTRL: case CS35L36_PWM_MOD_STATUS: case CS35L36_DAC_MSM_CFG: case CS35L36_AMP_SLOPE_CTRL: case CS35L36_AMP_PDM_VOLUME: case CS35L36_AMP_PDM_RATE_CTRL: case CS35L36_PDM_CH_SEL: case CS35L36_AMP_NG_CTRL: case CS35L36_PDM_HIGHFILT_CTRL: case CS35L36_INT1_STATUS: case CS35L36_INT2_STATUS: case CS35L36_INT3_STATUS: case CS35L36_INT4_STATUS: case CS35L36_INT1_RAW_STATUS: case CS35L36_INT2_RAW_STATUS: case CS35L36_INT3_RAW_STATUS: case CS35L36_INT4_RAW_STATUS: case CS35L36_INT1_MASK: case CS35L36_INT2_MASK: case CS35L36_INT3_MASK: case CS35L36_INT4_MASK: case CS35L36_INT1_EDGE_LVL_CTRL: case CS35L36_INT3_EDGE_LVL_CTRL: case CS35L36_PAC_INT_STATUS: case CS35L36_PAC_INT_RAW_STATUS: case CS35L36_PAC_INT_FLUSH_CTRL: case CS35L36_PAC_INT0_CTRL: case CS35L36_PAC_INT1_CTRL: case CS35L36_PAC_INT2_CTRL: case CS35L36_PAC_INT3_CTRL: case CS35L36_PAC_INT4_CTRL: case CS35L36_PAC_INT5_CTRL: case CS35L36_PAC_INT6_CTRL: case CS35L36_PAC_INT7_CTRL: returntrue; default: if (reg >= CS35L36_PAC_PMEM_WORD0 &&
reg <= CS35L36_PAC_PMEM_WORD1023) returntrue; else returnfalse;
}
}
staticbool cs35l36_precious_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case CS35L36_TESTKEY_CTRL: case CS35L36_USERKEY_CTL: case CS35L36_TST_FS_MON0: returntrue; default: returnfalse;
}
}
staticbool cs35l36_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case CS35L36_SW_RESET: case CS35L36_SW_REV: case CS35L36_HW_REV: case CS35L36_TESTKEY_CTRL: case CS35L36_USERKEY_CTL: case CS35L36_DEVICE_ID: case CS35L36_FAB_ID: case CS35L36_REV_ID: case CS35L36_INT1_STATUS: case CS35L36_INT2_STATUS: case CS35L36_INT3_STATUS: case CS35L36_INT4_STATUS: case CS35L36_INT1_RAW_STATUS: case CS35L36_INT2_RAW_STATUS: case CS35L36_INT3_RAW_STATUS: case CS35L36_INT4_RAW_STATUS: case CS35L36_INT1_MASK: case CS35L36_INT2_MASK: case CS35L36_INT3_MASK: case CS35L36_INT4_MASK: case CS35L36_INT1_EDGE_LVL_CTRL: case CS35L36_INT3_EDGE_LVL_CTRL: case CS35L36_PAC_INT_STATUS: case CS35L36_PAC_INT_RAW_STATUS: case CS35L36_PAC_INT_FLUSH_CTRL: returntrue; default: if (reg >= CS35L36_PAC_PMEM_WORD0 &&
reg <= CS35L36_PAC_PMEM_WORD1023) returntrue; else returnfalse;
}
}
for (i = 0; i < ARRAY_SIZE(cs35l36_fs_rates); i++) { if (global_fs == cs35l36_fs_rates[i].rate)
regmap_update_bits(cs35l36->regmap,
CS35L36_GLOBAL_CLK_CTRL,
CS35L36_GLOBAL_FS_MASK,
cs35l36_fs_rates[i].fs_cfg <<
CS35L36_GLOBAL_FS_SHIFT);
}
switch (params_width(params)) { case 16:
asp_width = CS35L36_ASP_WIDTH_16; break; case 24:
asp_width = CS35L36_ASP_WIDTH_24; break; case 32:
asp_width = CS35L36_ASP_WIDTH_32; break; default: return -EINVAL;
}
if (cs35l36->pdata.amp_pcm_inv)
regmap_update_bits(cs35l36->regmap, CS35L36_AMP_DIG_VOL_CTRL,
CS35L36_AMP_PCM_INV_MASK,
CS35L36_AMP_PCM_INV_MASK);
if (cs35l36->pdata.multi_amp_mode)
regmap_update_bits(cs35l36->regmap, CS35L36_ASP_TX_PIN_CTRL,
CS35L36_ASP_TX_HIZ_MASK,
CS35L36_ASP_TX_HIZ_MASK);
if (cs35l36->pdata.imon_pol_inv)
regmap_update_bits(cs35l36->regmap, CS35L36_VI_SPKMON_FILT,
CS35L36_IMON_POL_MASK, 0);
if (cs35l36->pdata.vmon_pol_inv)
regmap_update_bits(cs35l36->regmap, CS35L36_VI_SPKMON_FILT,
CS35L36_VMON_POL_MASK, 0);
if (cs35l36->pdata.bst_vctl)
regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_VCTRL1,
CS35L35_BSTCVRT_CTL_MASK,
cs35l36->pdata.bst_vctl);
if (cs35l36->pdata.bst_vctl_sel)
regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_VCTRL2,
CS35L35_BSTCVRT_CTL_SEL_MASK,
cs35l36->pdata.bst_vctl_sel);
if (cs35l36->pdata.bst_ipk)
regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_PEAK_CUR,
CS35L36_BST_IPK_MASK,
cs35l36->pdata.bst_ipk);
if (cs35l36->pdata.boost_ind) {
ret = cs35l36_boost_inductor(cs35l36, cs35l36->pdata.boost_ind); if (ret < 0) {
dev_err(cs35l36->dev, "Boost inductor config failed(%d)\n", ret); return ret;
}
}
if (cs35l36->pdata.temp_warn_thld)
regmap_update_bits(cs35l36->regmap, CS35L36_DTEMP_WARN_THLD,
CS35L36_TEMP_THLD_MASK,
cs35l36->pdata.temp_warn_thld);
if (cs35l36->pdata.irq_drv_sel)
regmap_update_bits(cs35l36->regmap, CS35L36_PAD_INTERFACE,
CS35L36_INT_DRV_SEL_MASK,
cs35l36->pdata.irq_drv_sel <<
CS35L36_INT_DRV_SEL_SHIFT);
if (cs35l36->pdata.irq_gpio_sel)
regmap_update_bits(cs35l36->regmap, CS35L36_PAD_INTERFACE,
CS35L36_INT_GPIO_SEL_MASK,
cs35l36->pdata.irq_gpio_sel <<
CS35L36_INT_GPIO_SEL_SHIFT);
/* * Rev B0 has 2 versions * L36 is 10V * L37 is 12V * If L36 we need to clamp some values for safety * after probe has setup dt values. We want to make * sure we dont miss any values set in probe
*/ if (cs35l36->chip_version == CS35L36_10V_L36) {
regmap_update_bits(cs35l36->regmap,
CS35L36_BSTCVRT_OVERVOLT_CTRL,
CS35L36_BST_OVP_THLD_MASK,
CS35L36_BST_OVP_THLD_11V);
/* * RevA and B require the disabling of * SYNC_GLOBAL_OVR when GLOBAL_EN = 0. * Just turn it off from default
*/
regmap_update_bits(cs35l36->regmap, CS35L36_CTRL_OVRRIDE,
CS35L36_SYNC_GLOBAL_OVR_MASK,
0 << CS35L36_SYNC_GLOBAL_OVR_SHIFT);
/* Check to see if unmasked bits are active */ if (!(status[0] & ~masks[0]) && !(status[1] & ~masks[1]) &&
!(status[2] & ~masks[2]) && !(status[3] & ~masks[3])) { return IRQ_NONE;
}
/* * The following interrupts require a * protection release cycle to get the * speaker out of Safe-Mode.
*/ if (status[2] & CS35L36_AMP_SHORT_ERR) {
dev_crit(cs35l36->dev, "Amp short error\n");
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_AMP_SHORT_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_AMP_SHORT_ERR_RLS,
CS35L36_AMP_SHORT_ERR_RLS);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_AMP_SHORT_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_INT3_STATUS,
CS35L36_AMP_SHORT_ERR,
CS35L36_AMP_SHORT_ERR);
ret = IRQ_HANDLED;
}
if (status[0] & CS35L36_TEMP_WARN) {
dev_crit(cs35l36->dev, "Over temperature warning\n");
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_WARN_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_WARN_ERR_RLS,
CS35L36_TEMP_WARN_ERR_RLS);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_WARN_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS,
CS35L36_TEMP_WARN, CS35L36_TEMP_WARN);
ret = IRQ_HANDLED;
}
if (status[0] & CS35L36_TEMP_ERR) {
dev_crit(cs35l36->dev, "Over temperature error\n");
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_ERR_RLS, CS35L36_TEMP_ERR_RLS);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS,
CS35L36_TEMP_ERR, CS35L36_TEMP_ERR);
ret = IRQ_HANDLED;
}
if (status[0] & CS35L36_BST_OVP_ERR) {
dev_crit(cs35l36->dev, "VBST Over Voltage error\n");
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_ERR_RLS, CS35L36_TEMP_ERR_RLS);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_TEMP_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS,
CS35L36_BST_OVP_ERR, CS35L36_BST_OVP_ERR);
ret = IRQ_HANDLED;
}
if (status[0] & CS35L36_BST_DCM_UVP_ERR) {
dev_crit(cs35l36->dev, "DCM VBST Under Voltage Error\n");
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_BST_UVP_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_BST_UVP_ERR_RLS,
CS35L36_BST_UVP_ERR_RLS);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_BST_UVP_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS,
CS35L36_BST_DCM_UVP_ERR,
CS35L36_BST_DCM_UVP_ERR);
ret = IRQ_HANDLED;
}
if (status[0] & CS35L36_BST_SHORT_ERR) {
dev_crit(cs35l36->dev, "LBST SHORT error!\n");
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_BST_SHORT_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_BST_SHORT_ERR_RLS,
CS35L36_BST_SHORT_ERR_RLS);
regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR,
CS35L36_BST_SHORT_ERR_RLS, 0);
regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS,
CS35L36_BST_SHORT_ERR,
CS35L36_BST_SHORT_ERR);
ret = IRQ_HANDLED;
}
cs35l36 = devm_kzalloc(dev, sizeof(struct cs35l36_private), GFP_KERNEL); if (!cs35l36) return -ENOMEM;
cs35l36->dev = dev;
i2c_set_clientdata(i2c_client, cs35l36);
cs35l36->regmap = devm_regmap_init_i2c(i2c_client, &cs35l36_regmap); if (IS_ERR(cs35l36->regmap)) {
ret = PTR_ERR(cs35l36->regmap);
dev_err(dev, "regmap_init() failed: %d\n", ret); return ret;
}
cs35l36->num_supplies = ARRAY_SIZE(cs35l36_supplies); for (i = 0; i < ARRAY_SIZE(cs35l36_supplies); i++)
cs35l36->supplies[i].supply = cs35l36_supplies[i];
ret = devm_regulator_bulk_get(dev, cs35l36->num_supplies,
cs35l36->supplies); if (ret != 0) {
dev_err(dev, "Failed to request core supplies: %d\n", ret); return ret;
}
if (pdata) {
cs35l36->pdata = *pdata;
} else {
pdata = devm_kzalloc(dev, sizeof(struct cs35l36_platform_data),
GFP_KERNEL); if (!pdata) return -ENOMEM;
if (i2c_client->dev.of_node) {
ret = cs35l36_handle_of_data(i2c_client, pdata); if (ret != 0) return ret;
}
cs35l36->pdata = *pdata;
}
ret = regulator_bulk_enable(cs35l36->num_supplies, cs35l36->supplies); if (ret != 0) {
dev_err(dev, "Failed to enable core supplies: %d\n", ret); return ret;
}
/* returning NULL can be an option if in stereo mode */
cs35l36->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW); if (IS_ERR(cs35l36->reset_gpio)) {
ret = PTR_ERR(cs35l36->reset_gpio);
cs35l36->reset_gpio = NULL; if (ret == -EBUSY) {
dev_info(dev, "Reset line busy, assuming shared reset\n");
} else {
dev_err(dev, "Failed to get reset GPIO: %d\n", ret); goto err_disable_regs;
}
}
if (cs35l36->reset_gpio)
gpiod_set_value_cansleep(cs35l36->reset_gpio, 1);
usleep_range(2000, 2100);
/* initialize amplifier */
ret = regmap_read(cs35l36->regmap, CS35L36_SW_RESET, ®_id); if (ret < 0) {
dev_err(dev, "Get Device ID failed %d\n", ret); goto err;
}
if (reg_id != CS35L36_CHIP_ID) {
dev_err(dev, "Device ID (%X). Expected ID %X\n", reg_id,
CS35L36_CHIP_ID);
ret = -ENODEV; goto err;
}
ret = regmap_read(cs35l36->regmap, CS35L36_REV_ID, ®_revid); if (ret < 0) {
dev_err(&i2c_client->dev, "Get Revision ID failed %d\n", ret); goto err;
}
cs35l36->rev_id = reg_revid >> 8;
ret = regmap_read(cs35l36->regmap, CS35L36_OTP_MEM30, &l37_id_reg); if (ret < 0) {
dev_err(&i2c_client->dev, "Failed to read otp_id Register %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.