cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cs35l41_hda.c (16612B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// CS35l41 ALSA HDA audio driver
      4//
      5// Copyright 2021 Cirrus Logic, Inc.
      6//
      7// Author: Lucas Tanure <tanureal@opensource.cirrus.com>
      8
      9#include <linux/acpi.h>
     10#include <linux/module.h>
     11#include <sound/hda_codec.h>
     12#include "hda_local.h"
     13#include "hda_auto_parser.h"
     14#include "hda_jack.h"
     15#include "hda_generic.h"
     16#include "hda_component.h"
     17#include "cs35l41_hda.h"
     18
     19static const struct reg_sequence cs35l41_hda_config[] = {
     20	{ CS35L41_PLL_CLK_CTRL,		0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
     21	{ CS35L41_GLOBAL_CLK_CTRL,	0x00000003 }, // GLOBAL_FS = 48 kHz
     22	{ CS35L41_SP_ENABLES,		0x00010000 }, // ASP_RX1_EN = 1
     23	{ CS35L41_SP_RATE_CTRL,		0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
     24	{ CS35L41_SP_FORMAT,		0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
     25	{ CS35L41_DAC_PCM1_SRC,		0x00000008 }, // DACPCM1_SRC = ASPRX1
     26	{ CS35L41_AMP_DIG_VOL_CTRL,	0x00000000 }, // AMP_VOL_PCM  0.0 dB
     27	{ CS35L41_AMP_GAIN_CTRL,	0x00000084 }, // AMP_GAIN_PCM 4.5 dB
     28};
     29
     30static const struct reg_sequence cs35l41_hda_mute[] = {
     31	{ CS35L41_AMP_GAIN_CTRL,	0x00000000 }, // AMP_GAIN_PCM 0.5 dB
     32	{ CS35L41_AMP_DIG_VOL_CTRL,	0x0000A678 }, // AMP_VOL_PCM Mute
     33};
     34
     35/* Protection release cycle to get the speaker out of Safe-Mode */
     36static void cs35l41_error_release(struct device *dev, struct regmap *regmap, unsigned int mask)
     37{
     38	regmap_write(regmap, CS35L41_PROTECT_REL_ERR_IGN, 0);
     39	regmap_set_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
     40	regmap_clear_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
     41}
     42
     43/* Clear all errors to release safe mode. Global Enable must be cleared first. */
     44static void cs35l41_irq_release(struct cs35l41_hda *cs35l41)
     45{
     46	cs35l41_error_release(cs35l41->dev, cs35l41->regmap, cs35l41->irq_errors);
     47	cs35l41->irq_errors = 0;
     48}
     49
     50static void cs35l41_hda_playback_hook(struct device *dev, int action)
     51{
     52	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
     53	struct regmap *reg = cs35l41->regmap;
     54	int ret = 0;
     55
     56	switch (action) {
     57	case HDA_GEN_PCM_ACT_OPEN:
     58		regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
     59		ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
     60					 CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
     61		if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
     62			regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
     63		break;
     64	case HDA_GEN_PCM_ACT_PREPARE:
     65		ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1);
     66		break;
     67	case HDA_GEN_PCM_ACT_CLEANUP:
     68		regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
     69		ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0);
     70		break;
     71	case HDA_GEN_PCM_ACT_CLOSE:
     72		ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
     73					 CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
     74		if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
     75			regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
     76		cs35l41_irq_release(cs35l41);
     77		break;
     78	default:
     79		dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action);
     80		break;
     81	}
     82
     83	if (ret)
     84		dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret);
     85}
     86
     87static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot,
     88				    unsigned int rx_num, unsigned int *rx_slot)
     89{
     90	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
     91	static const char * const channel_name[] = { "L", "R" };
     92
     93	if (!cs35l41->amp_name) {
     94		if (*rx_slot >= ARRAY_SIZE(channel_name))
     95			return -EINVAL;
     96
     97		cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%s%d",
     98						   channel_name[*rx_slot], cs35l41->channel_index);
     99		if (!cs35l41->amp_name)
    100			return -ENOMEM;
    101	}
    102
    103	return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num,
    104				    rx_slot);
    105}
    106
    107static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data)
    108{
    109	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
    110	struct hda_component *comps = master_data;
    111
    112	if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS)
    113		return -EINVAL;
    114
    115	comps = &comps[cs35l41->index];
    116	if (comps->dev)
    117		return -EBUSY;
    118
    119	comps->dev = dev;
    120	strscpy(comps->name, dev_name(dev), sizeof(comps->name));
    121	comps->playback_hook = cs35l41_hda_playback_hook;
    122
    123	return 0;
    124}
    125
    126static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data)
    127{
    128	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
    129	struct hda_component *comps = master_data;
    130
    131	if (comps[cs35l41->index].dev == dev)
    132		memset(&comps[cs35l41->index], 0, sizeof(*comps));
    133}
    134
    135static const struct component_ops cs35l41_hda_comp_ops = {
    136	.bind = cs35l41_hda_bind,
    137	.unbind = cs35l41_hda_unbind,
    138};
    139
    140static irqreturn_t cs35l41_bst_short_err(int irq, void *data)
    141{
    142	struct cs35l41_hda *cs35l41 = data;
    143
    144	dev_crit_ratelimited(cs35l41->dev, "LBST Error\n");
    145	set_bit(CS35L41_BST_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
    146
    147	return IRQ_HANDLED;
    148}
    149
    150static irqreturn_t cs35l41_bst_dcm_uvp_err(int irq, void *data)
    151{
    152	struct cs35l41_hda *cs35l41 = data;
    153
    154	dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n");
    155	set_bit(CS35L41_BST_UVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
    156
    157	return IRQ_HANDLED;
    158}
    159
    160static irqreturn_t cs35l41_bst_ovp_err(int irq, void *data)
    161{
    162	struct cs35l41_hda *cs35l41 = data;
    163
    164	dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n");
    165	set_bit(CS35L41_BST_OVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
    166
    167	return IRQ_HANDLED;
    168}
    169
    170static irqreturn_t cs35l41_temp_err(int irq, void *data)
    171{
    172	struct cs35l41_hda *cs35l41 = data;
    173
    174	dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n");
    175	set_bit(CS35L41_TEMP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
    176
    177	return IRQ_HANDLED;
    178}
    179
    180static irqreturn_t cs35l41_temp_warn(int irq, void *data)
    181{
    182	struct cs35l41_hda *cs35l41 = data;
    183
    184	dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n");
    185	set_bit(CS35L41_TEMP_WARN_ERR_RLS_SHIFT, &cs35l41->irq_errors);
    186
    187	return IRQ_HANDLED;
    188}
    189
    190static irqreturn_t cs35l41_amp_short(int irq, void *data)
    191{
    192	struct cs35l41_hda *cs35l41 = data;
    193
    194	dev_crit_ratelimited(cs35l41->dev, "Amp short error\n");
    195	set_bit(CS35L41_AMP_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
    196
    197	return IRQ_HANDLED;
    198}
    199
    200static const struct cs35l41_irq cs35l41_irqs[] = {
    201	CS35L41_IRQ(BST_OVP_ERR, "Boost Overvoltage Error", cs35l41_bst_ovp_err),
    202	CS35L41_IRQ(BST_DCM_UVP_ERR, "Boost Undervoltage Error", cs35l41_bst_dcm_uvp_err),
    203	CS35L41_IRQ(BST_SHORT_ERR, "Boost Inductor Short Error", cs35l41_bst_short_err),
    204	CS35L41_IRQ(TEMP_WARN, "Temperature Warning", cs35l41_temp_warn),
    205	CS35L41_IRQ(TEMP_ERR, "Temperature Error", cs35l41_temp_err),
    206	CS35L41_IRQ(AMP_SHORT_ERR, "Amp Short", cs35l41_amp_short),
    207};
    208
    209static const struct regmap_irq cs35l41_reg_irqs[] = {
    210	CS35L41_REG_IRQ(IRQ1_STATUS1, BST_OVP_ERR),
    211	CS35L41_REG_IRQ(IRQ1_STATUS1, BST_DCM_UVP_ERR),
    212	CS35L41_REG_IRQ(IRQ1_STATUS1, BST_SHORT_ERR),
    213	CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_WARN),
    214	CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_ERR),
    215	CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR),
    216};
    217
    218static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
    219	.name = "cs35l41 IRQ1 Controller",
    220	.status_base = CS35L41_IRQ1_STATUS1,
    221	.mask_base = CS35L41_IRQ1_MASK1,
    222	.ack_base = CS35L41_IRQ1_STATUS1,
    223	.num_regs = 4,
    224	.irqs = cs35l41_reg_irqs,
    225	.num_irqs = ARRAY_SIZE(cs35l41_reg_irqs),
    226};
    227
    228static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
    229{
    230	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
    231	bool using_irq = false;
    232	int irq, irq_pol;
    233	int ret;
    234	int i;
    235
    236	if (!cs35l41->hw_cfg.valid)
    237		return -EINVAL;
    238
    239	ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg);
    240	if (ret)
    241		return ret;
    242
    243	if (hw_cfg->gpio1.valid) {
    244		switch (hw_cfg->gpio1.func) {
    245		case CS35L41_NOT_USED:
    246			break;
    247		case CS35l41_VSPK_SWITCH:
    248			hw_cfg->gpio1.func = CS35L41_GPIO1_GPIO;
    249			hw_cfg->gpio1.out_en = true;
    250			break;
    251		case CS35l41_SYNC:
    252			hw_cfg->gpio1.func = CS35L41_GPIO1_MDSYNC;
    253			break;
    254		default:
    255			dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n",
    256				hw_cfg->gpio1.func);
    257			return -EINVAL;
    258		}
    259	}
    260
    261	if (hw_cfg->gpio2.valid) {
    262		switch (hw_cfg->gpio2.func) {
    263		case CS35L41_NOT_USED:
    264			break;
    265		case CS35L41_INTERRUPT:
    266			using_irq = true;
    267			break;
    268		default:
    269			dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func);
    270			return -EINVAL;
    271		}
    272	}
    273
    274	irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
    275
    276	if (cs35l41->irq && using_irq) {
    277		ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq,
    278					       IRQF_ONESHOT | IRQF_SHARED | irq_pol,
    279					       0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data);
    280		if (ret)
    281			return ret;
    282
    283		for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) {
    284			irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq);
    285			if (irq < 0)
    286				return irq;
    287
    288			ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL,
    289							cs35l41_irqs[i].handler,
    290							IRQF_ONESHOT | IRQF_SHARED | irq_pol,
    291							cs35l41_irqs[i].name, cs35l41);
    292			if (ret)
    293				return ret;
    294		}
    295	}
    296
    297	return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
    298}
    299
    300static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
    301{
    302	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
    303	u32 values[HDA_MAX_COMPONENTS];
    304	struct acpi_device *adev;
    305	struct device *physdev;
    306	char *property;
    307	size_t nval;
    308	int i, ret;
    309
    310	adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
    311	if (!adev) {
    312		dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
    313		return -ENODEV;
    314	}
    315
    316	physdev = get_device(acpi_get_first_physical_node(adev));
    317	acpi_dev_put(adev);
    318
    319	property = "cirrus,dev-index";
    320	ret = device_property_count_u32(physdev, property);
    321	if (ret <= 0)
    322		goto no_acpi_dsd;
    323
    324	if (ret > ARRAY_SIZE(values)) {
    325		ret = -EINVAL;
    326		goto err;
    327	}
    328	nval = ret;
    329
    330	ret = device_property_read_u32_array(physdev, property, values, nval);
    331	if (ret)
    332		goto err;
    333
    334	cs35l41->index = -1;
    335	for (i = 0; i < nval; i++) {
    336		if (values[i] == id) {
    337			cs35l41->index = i;
    338			break;
    339		}
    340	}
    341	if (cs35l41->index == -1) {
    342		dev_err(cs35l41->dev, "No index found in %s\n", property);
    343		ret = -ENODEV;
    344		goto err;
    345	}
    346
    347	/* To use the same release code for all laptop variants we can't use devm_ version of
    348	 * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node
    349	 */
    350	cs35l41->reset_gpio = fwnode_gpiod_get_index(&adev->fwnode, "reset", cs35l41->index,
    351						     GPIOD_OUT_LOW, "cs35l41-reset");
    352
    353	property = "cirrus,speaker-position";
    354	ret = device_property_read_u32_array(physdev, property, values, nval);
    355	if (ret)
    356		goto err;
    357	hw_cfg->spk_pos = values[cs35l41->index];
    358
    359	cs35l41->channel_index = 0;
    360	for (i = 0; i < cs35l41->index; i++)
    361		if (values[i] == hw_cfg->spk_pos)
    362			cs35l41->channel_index++;
    363
    364	property = "cirrus,gpio1-func";
    365	ret = device_property_read_u32_array(physdev, property, values, nval);
    366	if (ret)
    367		goto err;
    368	hw_cfg->gpio1.func = values[cs35l41->index];
    369	hw_cfg->gpio1.valid = true;
    370
    371	property = "cirrus,gpio2-func";
    372	ret = device_property_read_u32_array(physdev, property, values, nval);
    373	if (ret)
    374		goto err;
    375	hw_cfg->gpio2.func = values[cs35l41->index];
    376	hw_cfg->gpio2.valid = true;
    377
    378	property = "cirrus,boost-peak-milliamp";
    379	ret = device_property_read_u32_array(physdev, property, values, nval);
    380	if (ret == 0)
    381		hw_cfg->bst_ipk = values[cs35l41->index];
    382	else
    383		hw_cfg->bst_ipk = -1;
    384
    385	property = "cirrus,boost-ind-nanohenry";
    386	ret = device_property_read_u32_array(physdev, property, values, nval);
    387	if (ret == 0)
    388		hw_cfg->bst_ind = values[cs35l41->index];
    389	else
    390		hw_cfg->bst_ind = -1;
    391
    392	property = "cirrus,boost-cap-microfarad";
    393	ret = device_property_read_u32_array(physdev, property, values, nval);
    394	if (ret == 0)
    395		hw_cfg->bst_cap = values[cs35l41->index];
    396	else
    397		hw_cfg->bst_cap = -1;
    398
    399	if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
    400		hw_cfg->bst_type = CS35L41_INT_BOOST;
    401	else
    402		hw_cfg->bst_type = CS35L41_EXT_BOOST;
    403
    404	hw_cfg->valid = true;
    405	put_device(physdev);
    406
    407	return 0;
    408
    409err:
    410	put_device(physdev);
    411	dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
    412
    413	return ret;
    414
    415no_acpi_dsd:
    416	/*
    417	 * Device CLSA0100 doesn't have _DSD so a gpiod_get by the label reset won't work.
    418	 * And devices created by i2c-multi-instantiate don't have their device struct pointing to
    419	 * the correct fwnode, so acpi_dev must be used here.
    420	 * And devm functions expect that the device requesting the resource has the correct
    421	 * fwnode.
    422	 */
    423	if (strncmp(hid, "CLSA0100", 8) != 0)
    424		return -EINVAL;
    425
    426	/* check I2C address to assign the index */
    427	cs35l41->index = id == 0x40 ? 0 : 1;
    428	cs35l41->hw_cfg.spk_pos = cs35l41->index;
    429	cs35l41->channel_index = 0;
    430	cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
    431	cs35l41->hw_cfg.bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
    432	hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN;
    433	hw_cfg->gpio2.valid = true;
    434	cs35l41->hw_cfg.valid = true;
    435	put_device(physdev);
    436
    437	return 0;
    438}
    439
    440int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
    441		      struct regmap *regmap)
    442{
    443	unsigned int int_sts, regid, reg_revid, mtl_revid, chipid, int_status;
    444	struct cs35l41_hda *cs35l41;
    445	int ret;
    446
    447	BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != ARRAY_SIZE(cs35l41_reg_irqs));
    448	BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != CS35L41_NUM_IRQ);
    449
    450	if (IS_ERR(regmap))
    451		return PTR_ERR(regmap);
    452
    453	cs35l41 = devm_kzalloc(dev, sizeof(*cs35l41), GFP_KERNEL);
    454	if (!cs35l41)
    455		return -ENOMEM;
    456
    457	cs35l41->dev = dev;
    458	cs35l41->irq = irq;
    459	cs35l41->regmap = regmap;
    460	dev_set_drvdata(dev, cs35l41);
    461
    462	ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
    463	if (ret) {
    464		dev_err_probe(cs35l41->dev, ret, "Platform not supported %d\n", ret);
    465		return ret;
    466	}
    467
    468	if (IS_ERR(cs35l41->reset_gpio)) {
    469		ret = PTR_ERR(cs35l41->reset_gpio);
    470		cs35l41->reset_gpio = NULL;
    471		if (ret == -EBUSY) {
    472			dev_info(cs35l41->dev, "Reset line busy, assuming shared reset\n");
    473		} else {
    474			dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO: %d\n", ret);
    475			goto err;
    476		}
    477	}
    478	if (cs35l41->reset_gpio) {
    479		usleep_range(2000, 2100);
    480		gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
    481	}
    482
    483	usleep_range(2000, 2100);
    484
    485	ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status,
    486				       int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000);
    487	if (ret) {
    488		dev_err(cs35l41->dev, "Failed waiting for OTP_BOOT_DONE: %d\n", ret);
    489		goto err;
    490	}
    491
    492	ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_sts);
    493	if (ret || (int_sts & CS35L41_OTP_BOOT_ERR)) {
    494		dev_err(cs35l41->dev, "OTP Boot status %x error: %d\n",
    495			int_sts & CS35L41_OTP_BOOT_ERR, ret);
    496		ret = -EIO;
    497		goto err;
    498	}
    499
    500	ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid);
    501	if (ret) {
    502		dev_err(cs35l41->dev, "Get Device ID failed: %d\n", ret);
    503		goto err;
    504	}
    505
    506	ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid);
    507	if (ret) {
    508		dev_err(cs35l41->dev, "Get Revision ID failed: %d\n", ret);
    509		goto err;
    510	}
    511
    512	mtl_revid = reg_revid & CS35L41_MTLREVID_MASK;
    513
    514	chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
    515	if (regid != chipid) {
    516		dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", regid, chipid);
    517		ret = -ENODEV;
    518		goto err;
    519	}
    520
    521	ret = cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
    522	if (ret)
    523		goto err;
    524
    525	ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid);
    526	if (ret)
    527		goto err;
    528
    529	ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
    530	if (ret) {
    531		dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
    532		goto err;
    533	}
    534
    535	ret = cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
    536	if (ret)
    537		goto err;
    538
    539	ret = cs35l41_hda_apply_properties(cs35l41);
    540	if (ret)
    541		goto err;
    542
    543	ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
    544	if (ret) {
    545		dev_err(cs35l41->dev, "Register component failed: %d\n", ret);
    546		goto err;
    547	}
    548
    549	dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid);
    550
    551	return 0;
    552
    553err:
    554	if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
    555		gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
    556	gpiod_put(cs35l41->reset_gpio);
    557
    558	return ret;
    559}
    560EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, SND_HDA_SCODEC_CS35L41);
    561
    562void cs35l41_hda_remove(struct device *dev)
    563{
    564	struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
    565
    566	component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
    567
    568	if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
    569		gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
    570	gpiod_put(cs35l41->reset_gpio);
    571}
    572EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
    573
    574MODULE_DESCRIPTION("CS35L41 HDA Driver");
    575MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
    576MODULE_LICENSE("GPL");