Couple of nit-picks and one issue with error handling, see below. > +static int cs35l41_otp_unpack(void *data) > +{ > + struct cs35l41_private *cs35l41 = data; > + u32 *otp_mem = NULL; initialization is not necessary? Even a static analyzer would not complain here, would it? > + int i; > + int bit_offset, word_offset; > + unsigned int bit_sum = 8; > + u32 otp_val, otp_id_reg; > + const struct cs35l41_otp_map_element_t *otp_map_match = NULL; same, this is directly assigned below. > + const struct cs35l41_otp_packed_element_t *otp_map = NULL; same, you assign it with otp_map = otp_map_match->map; > + unsigned int orig_spi_freq; > + int ret; > + > + otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), > + GFP_KERNEL); > + if (!otp_mem) > + return -ENOMEM; > + > + ret = regmap_read(cs35l41->regmap, CS35L41_OTPID, &otp_id_reg); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Read OTP ID failed\n"); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + > + otp_map_match = cs35l41_find_otp_map(otp_id_reg); > + > + if (otp_map_match == NULL) { if (!otp_map_match) > + dev_err(cs35l41->dev, "OTP Map matching ID %d not found\n", > + otp_id_reg); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + > + if (cs35l41->otp_setup) > + cs35l41->otp_setup(cs35l41, true, &orig_spi_freq); > + > + ret = regmap_bulk_read(cs35l41->regmap, CS35L41_OTP_MEM0, otp_mem, > + CS35L41_OTP_SIZE_WORDS); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Read OTP Mem failed\n"); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + > + if (cs35l41->otp_setup) > + cs35l41->otp_setup(cs35l41, false, &orig_spi_freq); > + > + otp_map = otp_map_match->map; > + > + bit_offset = otp_map_match->bit_offset; > + word_offset = otp_map_match->word_offset; > + > + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000055); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Write Unlock key failed 1/2\n"); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000AA); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Write Unlock key failed 2/2\n"); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + > + for (i = 0; i < otp_map_match->num_elements; i++) { > + dev_dbg(cs35l41->dev, > + "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n", > + bit_offset, word_offset, bit_sum % 32); > + if (bit_offset + otp_map[i].size - 1 >= 32) { > + otp_val = (otp_mem[word_offset] & > + GENMASK(31, bit_offset)) >> > + bit_offset; > + otp_val |= (otp_mem[++word_offset] & > + GENMASK(bit_offset + > + otp_map[i].size - 33, 0)) << > + (32 - bit_offset); > + bit_offset += otp_map[i].size - 32; > + } else { > + > + otp_val = (otp_mem[word_offset] & > + GENMASK(bit_offset + otp_map[i].size - 1, > + bit_offset)) >> bit_offset; > + bit_offset += otp_map[i].size; > + } > + bit_sum += otp_map[i].size; > + > + if (bit_offset == 32) { > + bit_offset = 0; > + word_offset++; > + } > + > + if (otp_map[i].reg != 0) { > + ret = regmap_update_bits(cs35l41->regmap, > + otp_map[i].reg, > + GENMASK(otp_map[i].shift + > + otp_map[i].size - 1, > + otp_map[i].shift), > + otp_val << otp_map[i].shift); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Write OTP val failed\n"); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + } > + } > + > + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000CC); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Write Lock key failed 1/2\n"); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000033); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Write Lock key failed 2/2\n"); > + ret = -EINVAL; > + goto err_otp_unpack; > + } > + ret = 0; > + > +err_otp_unpack: > + kfree(otp_mem); > + return ret; > +} > +static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, > + struct snd_kcontrol *kcontrol, int event) > +{ > + struct snd_soc_component *component = > + snd_soc_dapm_to_component(w->dapm); > + struct cs35l41_private *cs35l41 = > + snd_soc_component_get_drvdata(component); > + int ret = 0; > + int i; > + bool pdn; > + unsigned int val; reverse x-mas tree style for declarations? [...] > +static int cs35l41_pcm_hw_params(struct snd_pcm_substream *substream, > + struct snd_pcm_hw_params *params, > + struct snd_soc_dai *dai) > +{ > + struct cs35l41_private *cs35l41 = > + snd_soc_component_get_drvdata(dai->component); > + int i; > + unsigned int rate = params_rate(params); > + u8 asp_wl; reverse xmas-tree, move 'int i' to last line of declaration block? > + for (i = 0; i < ARRAY_SIZE(cs35l41_fs_rates); i++) { > + if (rate == cs35l41_fs_rates[i].rate) > + break; > + } > + > + if (i >= ARRAY_SIZE(cs35l41_fs_rates)) { > + dev_err(cs35l41->dev, "%s: Unsupported rate: %u\n", > + __func__, rate); > + return -EINVAL; > + } > + > + asp_wl = params_width(params); > + > + if (i < ARRAY_SIZE(cs35l41_fs_rates)) > + regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL, > + CS35L41_GLOBAL_FS_MASK, > + cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT); > + > + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { > + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, > + CS35L41_ASP_WIDTH_RX_MASK, > + asp_wl << CS35L41_ASP_WIDTH_RX_SHIFT); > + regmap_update_bits(cs35l41->regmap, CS35L41_SP_RX_WL, > + CS35L41_ASP_RX_WL_MASK, > + asp_wl << CS35L41_ASP_RX_WL_SHIFT); > + if (cs35l41->i2s_mode) { > + regmap_update_bits(cs35l41->regmap, > + CS35L41_SP_FRAME_RX_SLOT, > + CS35L41_ASP_RX1_SLOT_MASK, > + ((cs35l41->pdata.right_channel) ? 1 : 0) > + << CS35L41_ASP_RX1_SLOT_SHIFT); > + regmap_update_bits(cs35l41->regmap, > + CS35L41_SP_FRAME_RX_SLOT, > + CS35L41_ASP_RX2_SLOT_MASK, > + ((cs35l41->pdata.right_channel) ? 0 : 1) > + << CS35L41_ASP_RX2_SLOT_SHIFT); > + } > + } else { > + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, > + CS35L41_ASP_WIDTH_TX_MASK, > + asp_wl << CS35L41_ASP_WIDTH_TX_SHIFT); > + regmap_update_bits(cs35l41->regmap, CS35L41_SP_TX_WL, > + CS35L41_ASP_TX_WL_MASK, > + asp_wl << CS35L41_ASP_TX_WL_SHIFT); > + } > + > + return 0; > +} > + > +static int cs35l41_boost_config(struct cs35l41_private *cs35l41, > + int boost_ind, int boost_cap, int boost_ipk) > +{ > + int ret; move this last? > + unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; > + struct regmap *regmap = cs35l41->regmap; > + struct device *dev = cs35l41->dev; > + > + switch (boost_ind) { > + case 1000: /* 1.0 uH */ > + bst_lbst_val = 0; > + break; > + case 1200: /* 1.2 uH */ > + bst_lbst_val = 1; > + break; > + case 1500: /* 1.5 uH */ > + bst_lbst_val = 2; > + break; > + case 2200: /* 2.2 uH */ > + bst_lbst_val = 3; > + break; > + default: > + dev_err(dev, "Invalid boost inductor value: %d nH\n", > + boost_ind); > + return -EINVAL; > + } > + > + switch (boost_cap) { > + case 0 ... 19: > + bst_cbst_range = 0; > + break; > + case 20 ... 50: > + bst_cbst_range = 1; > + break; > + case 51 ... 100: > + bst_cbst_range = 2; > + break; > + case 101 ... 200: > + bst_cbst_range = 3; > + break; > + default: /* 201 uF and greater */ > + bst_cbst_range = 4; > + } > + > + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, > + CS35L41_BST_K1_MASK, > + cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] > + << CS35L41_BST_K1_SHIFT); > + if (ret) { > + dev_err(dev, "Failed to write boost K1 coefficient\n"); > + return ret; > + } > + > + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, > + CS35L41_BST_K2_MASK, > + cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] > + << CS35L41_BST_K2_SHIFT); > + if (ret) { > + dev_err(dev, "Failed to write boost K2 coefficient\n"); > + return ret; > + } > + > + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, > + CS35L41_BST_SLOPE_MASK, > + cs35l41_bst_slope_table[bst_lbst_val] > + << CS35L41_BST_SLOPE_SHIFT); > + if (ret) { > + dev_err(dev, "Failed to write boost slope coefficient\n"); > + return ret; > + } > + > + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, > + CS35L41_BST_LBST_VAL_MASK, > + bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); > + if (ret) { > + dev_err(dev, "Failed to write boost inductor value\n"); > + return ret; > + } > + > + if ((boost_ipk < 1600) || (boost_ipk > 4500)) { > + dev_err(dev, "Invalid boost inductor peak current: %d mA\n", > + boost_ipk); > + return -EINVAL; > + } > + bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; > + > + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, > + CS35L41_BST_IPK_MASK, > + bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); > + if (ret) { > + dev_err(dev, "Failed to write boost inductor peak current\n"); > + return ret; > + } > + > + return 0; > +} > + > +int cs35l41_probe(struct cs35l41_private *cs35l41, > + struct cs35l41_platform_data *pdata) > +{ > + int ret; > + u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match; > + int timeout; > + int irq_pol = 0; > + > + > + for (i = 0; i < CS35L41_NUM_SUPPLIES; i++) > + cs35l41->supplies[i].supply = cs35l41_supplies[i]; > + > + ret = devm_regulator_bulk_get(cs35l41->dev, CS35L41_NUM_SUPPLIES, > + cs35l41->supplies); > + if (ret != 0) { > + dev_err(cs35l41->dev, > + "Failed to request core supplies: %d\n", > + ret); > + return ret; > + } > + > + if (pdata) { > + cs35l41->pdata = *pdata; > + } else { > + ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->pdata, > + cs35l41); > + if (ret != 0) { > + ret = -ENODEV; > + goto err; so here you will disable regulators that have not been enabled, is it intentional? mixing gotos and returns is confusing... and in addition you will set the reset_gpio that you only get a couple of lines below, that will be a page fault? > + } > + } > + > + ret = regulator_bulk_enable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); > + if (ret != 0) { > + dev_err(cs35l41->dev, > + "Failed to enable core supplies: %d\n", ret); > + return ret; > + } > + > + /* returning NULL can be an option if in stereo mode */ > + cs35l41->reset_gpio = devm_gpiod_get_optional(cs35l41->dev, "reset", > + GPIOD_OUT_LOW); > + if (IS_ERR(cs35l41->reset_gpio)) { > + ret = PTR_ERR(cs35l41->reset_gpio); > + cs35l41->reset_gpio = NULL; > + if (ret == -EBUSY) { > + dev_info(cs35l41->dev, > + "Reset line busy, assuming shared reset\n"); > + } else { > + dev_err(cs35l41->dev, > + "Failed to get reset GPIO: %d\n", ret); > + goto err; > + } > + } > + if (cs35l41->reset_gpio) { > + /* satisfy minimum reset pulse width spec */ > + usleep_range(2000, 2100); > + gpiod_set_value_cansleep(cs35l41->reset_gpio, 1); > + } > + > + usleep_range(2000, 2100); > + > + timeout = 100; > + do { > + if (timeout == 0) { > + dev_err(cs35l41->dev, > + "Timeout waiting for OTP_BOOT_DONE\n"); > + ret = -EBUSY; > + goto err; > + } > + usleep_range(1000, 1100); > + regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS4, &int_status); > + timeout--; > + } while (!(int_status & CS35L41_OTP_BOOT_DONE)); > + > + regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_status); > + if (int_status & CS35L41_OTP_BOOT_ERR) { > + dev_err(cs35l41->dev, "OTP Boot error\n"); > + ret = -EINVAL; > + goto err; > + } > + > + ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, ®id); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Get Device ID failed\n"); > + goto err; > + } > + > + ret = regmap_read(cs35l41->regmap, CS35L41_REVID, ®_revid); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Get Revision ID failed\n"); > + goto err; > + } > + > + mtl_revid = reg_revid & CS35L41_MTLREVID_MASK; > + > + /* CS35L41 will have even MTLREVID > + * CS35L41R will have odd MTLREVID > + */ > + chipid_match = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID; > + if (regid != chipid_match) { > + dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", > + regid, chipid_match); > + ret = -ENODEV; > + goto err; > + } > + > + switch (reg_revid) { > + case CS35L41_REVID_A0: > + ret = regmap_register_patch(cs35l41->regmap, > + cs35l41_reva0_errata_patch, > + ARRAY_SIZE(cs35l41_reva0_errata_patch)); > + if (ret < 0) { > + dev_err(cs35l41->dev, > + "Failed to apply A0 errata patch %d\n", ret); > + goto err; > + } > + break; > + case CS35L41_REVID_B0: > + ret = regmap_register_patch(cs35l41->regmap, > + cs35l41_revb0_errata_patch, > + ARRAY_SIZE(cs35l41_revb0_errata_patch)); > + if (ret < 0) { > + dev_err(cs35l41->dev, > + "Failed to apply B0 errata patch %d\n", ret); > + goto err; > + } > + break; > + case CS35L41_REVID_B2: > + ret = regmap_register_patch(cs35l41->regmap, > + cs35l41_revb2_errata_patch, > + ARRAY_SIZE(cs35l41_revb2_errata_patch)); > + if (ret < 0) { > + dev_err(cs35l41->dev, > + "Failed to apply B2 errata patch %d\n", ret); > + goto err; > + } > + break; > + } > + > + irq_pol = cs35l41_irq_gpio_config(cs35l41); > + > + /* Set interrupt masks for critical errors */ > + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, > + CS35L41_INT1_MASK_DEFAULT); > + > + ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, > + cs35l41_irq, IRQF_ONESHOT | IRQF_SHARED | irq_pol, > + "cs35l41", cs35l41); > + > + /* CS35L41 needs INT for PDN_DONE */ > + if (ret != 0) { > + dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret); > + ret = -ENODEV; > + goto err; > + } > + > + ret = cs35l41_otp_unpack(cs35l41); > + if (ret < 0) { > + dev_err(cs35l41->dev, "OTP Unpack failed\n"); > + goto err; > + } > + > + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_CCM_CORE_CTRL, 0); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Write CCM_CORE_CTRL failed\n"); > + goto err; > + } > + > + ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, > + CS35L41_AMP_EN_MASK, 0); > + if (ret < 0) { > + dev_err(cs35l41->dev, "Write CS35L41_PWR_CTRL2 failed\n"); > + goto err; > + } > + > + ret = devm_snd_soc_register_component(cs35l41->dev, > + &soc_component_dev_cs35l41, > + cs35l41_dai, ARRAY_SIZE(cs35l41_dai)); > + if (ret < 0) { > + dev_err(cs35l41->dev, "%s: Register codec failed\n", __func__); > + goto err; > + } > + > + ret = cs35l41_set_pdata(cs35l41); > + if (ret < 0) { > + dev_err(cs35l41->dev, "%s: Set pdata failed\n", __func__); > + goto err; > + } > + > + dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", > + regid, reg_revid); > + > + return 0; > + > +err: > + regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); > + gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); > + return ret; > +} > + > +int cs35l41_remove(struct cs35l41_private *cs35l41) > +{ > + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); > + regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); > + gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); > + return 0; > +} > + >