brintos

brintos / linux-shallow public Read only

0
0
Text · 18.7 KiB · 9f93b23 Raw
729 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// ALSA SoC Texas Instruments TAS2770 20-W Digital Input Mono Class-D4// Audio Amplifier with Speaker I/V Sense5//6// Copyright (C) 2016-2017 Texas Instruments Incorporated - https://www.ti.com/7//	Author: Tracy Yi <tracy-yi@ti.com>8//	Frank Shi <shifu0704@thundersoft.com>9 10#include <linux/module.h>11#include <linux/moduleparam.h>12#include <linux/err.h>13#include <linux/init.h>14#include <linux/delay.h>15#include <linux/pm.h>16#include <linux/i2c.h>17#include <linux/gpio/consumer.h>18#include <linux/regulator/consumer.h>19#include <linux/firmware.h>20#include <linux/regmap.h>21#include <linux/of.h>22#include <linux/slab.h>23#include <sound/soc.h>24#include <sound/pcm.h>25#include <sound/pcm_params.h>26#include <sound/initval.h>27#include <sound/tlv.h>28 29#include "tas2770.h"30 31#define TAS2770_MDELAY 0xFFFFFFFE32 33static void tas2770_reset(struct tas2770_priv *tas2770)34{35	if (tas2770->reset_gpio) {36		gpiod_set_value_cansleep(tas2770->reset_gpio, 0);37		msleep(20);38		gpiod_set_value_cansleep(tas2770->reset_gpio, 1);39		usleep_range(1000, 2000);40	}41 42	snd_soc_component_write(tas2770->component, TAS2770_SW_RST,43		TAS2770_RST);44	usleep_range(1000, 2000);45}46 47static int tas2770_update_pwr_ctrl(struct tas2770_priv *tas2770)48{49	struct snd_soc_component *component = tas2770->component;50	unsigned int val;51	int ret;52 53	if (tas2770->dac_powered)54		val = tas2770->unmuted ?55			TAS2770_PWR_CTRL_ACTIVE : TAS2770_PWR_CTRL_MUTE;56	else57		val = TAS2770_PWR_CTRL_SHUTDOWN;58 59	ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,60					    TAS2770_PWR_CTRL_MASK, val);61	if (ret < 0)62		return ret;63 64	return 0;65}66 67#ifdef CONFIG_PM68static int tas2770_codec_suspend(struct snd_soc_component *component)69{70	struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);71	int ret = 0;72 73	regcache_cache_only(tas2770->regmap, true);74	regcache_mark_dirty(tas2770->regmap);75 76	if (tas2770->sdz_gpio) {77		gpiod_set_value_cansleep(tas2770->sdz_gpio, 0);78	} else {79		ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,80						    TAS2770_PWR_CTRL_MASK,81						    TAS2770_PWR_CTRL_SHUTDOWN);82		if (ret < 0) {83			regcache_cache_only(tas2770->regmap, false);84			regcache_sync(tas2770->regmap);85			return ret;86		}87 88		ret = 0;89	}90 91	return ret;92}93 94static int tas2770_codec_resume(struct snd_soc_component *component)95{96	struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);97	int ret;98 99	if (tas2770->sdz_gpio) {100		gpiod_set_value_cansleep(tas2770->sdz_gpio, 1);101		usleep_range(1000, 2000);102	} else {103		ret = tas2770_update_pwr_ctrl(tas2770);104		if (ret < 0)105			return ret;106	}107 108	regcache_cache_only(tas2770->regmap, false);109 110	return regcache_sync(tas2770->regmap);111}112#else113#define tas2770_codec_suspend NULL114#define tas2770_codec_resume NULL115#endif116 117static const char * const tas2770_ASI1_src[] = {118	"I2C offset", "Left", "Right", "LeftRightDiv2",119};120 121static SOC_ENUM_SINGLE_DECL(122	tas2770_ASI1_src_enum, TAS2770_TDM_CFG_REG2,123	4, tas2770_ASI1_src);124 125static const struct snd_kcontrol_new tas2770_asi1_mux =126	SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum);127 128static int tas2770_dac_event(struct snd_soc_dapm_widget *w,129			     struct snd_kcontrol *kcontrol, int event)130{131	struct snd_soc_component *component =132			snd_soc_dapm_to_component(w->dapm);133	struct tas2770_priv *tas2770 =134			snd_soc_component_get_drvdata(component);135	int ret;136 137	switch (event) {138	case SND_SOC_DAPM_POST_PMU:139		tas2770->dac_powered = 1;140		ret = tas2770_update_pwr_ctrl(tas2770);141		break;142	case SND_SOC_DAPM_PRE_PMD:143		tas2770->dac_powered = 0;144		ret = tas2770_update_pwr_ctrl(tas2770);145		break;146	default:147		dev_err(tas2770->dev, "Not supported evevt\n");148		return -EINVAL;149	}150 151	return ret;152}153 154static const struct snd_kcontrol_new isense_switch =155	SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 3, 1, 1);156static const struct snd_kcontrol_new vsense_switch =157	SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1);158 159static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {160	SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),161	SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2770_asi1_mux),162	SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch),163	SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch),164	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,165			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),166	SND_SOC_DAPM_OUTPUT("OUT"),167	SND_SOC_DAPM_SIGGEN("VMON"),168	SND_SOC_DAPM_SIGGEN("IMON")169};170 171static const struct snd_soc_dapm_route tas2770_audio_map[] = {172	{"ASI1 Sel", "I2C offset", "ASI1"},173	{"ASI1 Sel", "Left", "ASI1"},174	{"ASI1 Sel", "Right", "ASI1"},175	{"ASI1 Sel", "LeftRightDiv2", "ASI1"},176	{"DAC", NULL, "ASI1 Sel"},177	{"OUT", NULL, "DAC"},178	{"ISENSE", "Switch", "IMON"},179	{"VSENSE", "Switch", "VMON"},180};181 182static int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction)183{184	struct snd_soc_component *component = dai->component;185	struct tas2770_priv *tas2770 =186			snd_soc_component_get_drvdata(component);187 188	tas2770->unmuted = !mute;189	return tas2770_update_pwr_ctrl(tas2770);190}191 192static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)193{194	int ret;195	struct snd_soc_component *component = tas2770->component;196 197	switch (bitwidth) {198	case SNDRV_PCM_FORMAT_S16_LE:199		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,200						    TAS2770_TDM_CFG_REG2_RXW_MASK,201						    TAS2770_TDM_CFG_REG2_RXW_16BITS);202		tas2770->v_sense_slot = tas2770->i_sense_slot + 2;203		break;204	case SNDRV_PCM_FORMAT_S24_LE:205		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,206						    TAS2770_TDM_CFG_REG2_RXW_MASK,207						    TAS2770_TDM_CFG_REG2_RXW_24BITS);208		tas2770->v_sense_slot = tas2770->i_sense_slot + 4;209		break;210	case SNDRV_PCM_FORMAT_S32_LE:211		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,212						    TAS2770_TDM_CFG_REG2_RXW_MASK,213						    TAS2770_TDM_CFG_REG2_RXW_32BITS);214		tas2770->v_sense_slot = tas2770->i_sense_slot + 4;215		break;216 217	default:218		return -EINVAL;219	}220 221	if (ret < 0)222		return ret;223 224	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG5,225					    TAS2770_TDM_CFG_REG5_VSNS_MASK |226					    TAS2770_TDM_CFG_REG5_50_MASK,227					    TAS2770_TDM_CFG_REG5_VSNS_ENABLE |228		tas2770->v_sense_slot);229	if (ret < 0)230		return ret;231 232	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG6,233					    TAS2770_TDM_CFG_REG6_ISNS_MASK |234					    TAS2770_TDM_CFG_REG6_50_MASK,235					    TAS2770_TDM_CFG_REG6_ISNS_ENABLE |236					    tas2770->i_sense_slot);237	if (ret < 0)238		return ret;239 240	return 0;241}242 243static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate)244{245	struct snd_soc_component *component = tas2770->component;246	int ramp_rate_val;247	int ret;248 249	switch (samplerate) {250	case 48000:251		ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ |252				TAS2770_TDM_CFG_REG0_31_44_1_48KHZ;253		break;254	case 44100:255		ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ |256				TAS2770_TDM_CFG_REG0_31_44_1_48KHZ;257		break;258	case 96000:259		ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ |260				TAS2770_TDM_CFG_REG0_31_88_2_96KHZ;261		break;262	case 88200:263		ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ |264				TAS2770_TDM_CFG_REG0_31_88_2_96KHZ;265		break;266	case 192000:267		ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ |268				TAS2770_TDM_CFG_REG0_31_176_4_192KHZ;269		break;270	case 176400:271		ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ |272				TAS2770_TDM_CFG_REG0_31_176_4_192KHZ;273		break;274	default:275		return -EINVAL;276	}277 278	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0,279					    TAS2770_TDM_CFG_REG0_SMP_MASK |280					    TAS2770_TDM_CFG_REG0_31_MASK,281					    ramp_rate_val);282	if (ret < 0)283		return ret;284 285	return 0;286}287 288static int tas2770_hw_params(struct snd_pcm_substream *substream,289			     struct snd_pcm_hw_params *params,290			     struct snd_soc_dai *dai)291{292	struct snd_soc_component *component = dai->component;293	struct tas2770_priv *tas2770 =294			snd_soc_component_get_drvdata(component);295	int ret;296 297	ret = tas2770_set_bitwidth(tas2770, params_format(params));298	if (ret)299		return ret;300 301	return tas2770_set_samplerate(tas2770, params_rate(params));302}303 304static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)305{306	struct snd_soc_component *component = dai->component;307	struct tas2770_priv *tas2770 =308			snd_soc_component_get_drvdata(component);309	u8 tdm_rx_start_slot = 0, invert_fpol = 0, fpol_preinv = 0, asi_cfg_1 = 0;310	int ret;311 312	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {313	case SND_SOC_DAIFMT_CBC_CFC:314		break;315	default:316		dev_err(tas2770->dev, "ASI invalid DAI clocking\n");317		return -EINVAL;318	}319 320	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {321	case SND_SOC_DAIFMT_NB_IF:322		invert_fpol = 1;323		fallthrough;324	case SND_SOC_DAIFMT_NB_NF:325		asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING;326		break;327	case SND_SOC_DAIFMT_IB_IF:328		invert_fpol = 1;329		fallthrough;330	case SND_SOC_DAIFMT_IB_NF:331		asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING;332		break;333	default:334		dev_err(tas2770->dev, "ASI format Inverse is not found\n");335		return -EINVAL;336	}337 338	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1,339					    TAS2770_TDM_CFG_REG1_RX_MASK,340					    asi_cfg_1);341	if (ret < 0)342		return ret;343 344	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {345	case SND_SOC_DAIFMT_I2S:346		tdm_rx_start_slot = 1;347		fpol_preinv = 0;348		break;349	case SND_SOC_DAIFMT_DSP_A:350		tdm_rx_start_slot = 0;351		fpol_preinv = 1;352		break;353	case SND_SOC_DAIFMT_DSP_B:354		tdm_rx_start_slot = 1;355		fpol_preinv = 1;356		break;357	case SND_SOC_DAIFMT_LEFT_J:358		tdm_rx_start_slot = 0;359		fpol_preinv = 1;360		break;361	default:362		dev_err(tas2770->dev,363			"DAI Format is not found, fmt=0x%x\n", fmt);364		return -EINVAL;365	}366 367	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1,368					    TAS2770_TDM_CFG_REG1_MASK,369					    (tdm_rx_start_slot << TAS2770_TDM_CFG_REG1_51_SHIFT));370	if (ret < 0)371		return ret;372 373	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0,374					    TAS2770_TDM_CFG_REG0_FPOL_MASK,375					    (fpol_preinv ^ invert_fpol)376					     ? TAS2770_TDM_CFG_REG0_FPOL_RSING377					     : TAS2770_TDM_CFG_REG0_FPOL_FALING);378	if (ret < 0)379		return ret;380 381	return 0;382}383 384static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,385				unsigned int tx_mask,386				unsigned int rx_mask,387				int slots, int slot_width)388{389	struct snd_soc_component *component = dai->component;390	int left_slot, right_slot;391	int ret;392 393	if (tx_mask == 0 || rx_mask != 0)394		return -EINVAL;395 396	left_slot = __ffs(tx_mask);397	tx_mask &= ~(1 << left_slot);398	if (tx_mask == 0) {399		right_slot = left_slot;400	} else {401		right_slot = __ffs(tx_mask);402		tx_mask &= ~(1 << right_slot);403	}404 405	if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)406		return -EINVAL;407 408	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3,409					    TAS2770_TDM_CFG_REG3_30_MASK,410					    (left_slot << TAS2770_TDM_CFG_REG3_30_SHIFT));411	if (ret < 0)412		return ret;413	ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3,414					    TAS2770_TDM_CFG_REG3_RXS_MASK,415					    (right_slot << TAS2770_TDM_CFG_REG3_RXS_SHIFT));416	if (ret < 0)417		return ret;418 419	switch (slot_width) {420	case 16:421		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,422						    TAS2770_TDM_CFG_REG2_RXS_MASK,423						    TAS2770_TDM_CFG_REG2_RXS_16BITS);424		break;425	case 24:426		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,427						    TAS2770_TDM_CFG_REG2_RXS_MASK,428						    TAS2770_TDM_CFG_REG2_RXS_24BITS);429		break;430	case 32:431		ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,432						    TAS2770_TDM_CFG_REG2_RXS_MASK,433						    TAS2770_TDM_CFG_REG2_RXS_32BITS);434		break;435	case 0:436		/* Do not change slot width */437		ret = 0;438		break;439	default:440		ret = -EINVAL;441	}442 443	if (ret < 0)444		return ret;445 446	return 0;447}448 449static const struct snd_soc_dai_ops tas2770_dai_ops = {450	.mute_stream = tas2770_mute,451	.hw_params  = tas2770_hw_params,452	.set_fmt    = tas2770_set_fmt,453	.set_tdm_slot = tas2770_set_dai_tdm_slot,454	.no_capture_mute = 1,455};456 457#define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\458		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)459 460#define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\461					   SNDRV_PCM_RATE_96000 |\462					    SNDRV_PCM_RATE_192000\463					  )464 465static struct snd_soc_dai_driver tas2770_dai_driver[] = {466	{467		.name = "tas2770 ASI1",468		.id = 0,469		.playback = {470			.stream_name    = "ASI1 Playback",471			.channels_min   = 1,472			.channels_max   = 2,473			.rates      = TAS2770_RATES,474			.formats    = TAS2770_FORMATS,475		},476		.capture = {477			.stream_name    = "ASI1 Capture",478			.channels_min   = 0,479			.channels_max   = 2,480			.rates          = TAS2770_RATES,481			.formats    = TAS2770_FORMATS,482		},483		.ops = &tas2770_dai_ops,484		.symmetric_rate = 1,485	},486};487 488static const struct regmap_config tas2770_i2c_regmap;489 490static int tas2770_codec_probe(struct snd_soc_component *component)491{492	struct tas2770_priv *tas2770 =493			snd_soc_component_get_drvdata(component);494 495	tas2770->component = component;496 497	if (tas2770->sdz_gpio) {498		gpiod_set_value_cansleep(tas2770->sdz_gpio, 1);499		usleep_range(1000, 2000);500	}501 502	tas2770_reset(tas2770);503	regmap_reinit_cache(tas2770->regmap, &tas2770_i2c_regmap);504 505	return 0;506}507 508static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);509static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0);510 511static const struct snd_kcontrol_new tas2770_snd_controls[] = {512	SOC_SINGLE_TLV("Speaker Playback Volume", TAS2770_PLAY_CFG_REG2,513		       0, TAS2770_PLAY_CFG_REG2_VMAX, 1, tas2770_playback_volume),514	SOC_SINGLE_TLV("Amp Gain Volume", TAS2770_PLAY_CFG_REG0, 0, 0x14, 0,515		       tas2770_digital_tlv),516};517 518static const struct snd_soc_component_driver soc_component_driver_tas2770 = {519	.probe			= tas2770_codec_probe,520	.suspend		= tas2770_codec_suspend,521	.resume			= tas2770_codec_resume,522	.controls		= tas2770_snd_controls,523	.num_controls		= ARRAY_SIZE(tas2770_snd_controls),524	.dapm_widgets		= tas2770_dapm_widgets,525	.num_dapm_widgets	= ARRAY_SIZE(tas2770_dapm_widgets),526	.dapm_routes		= tas2770_audio_map,527	.num_dapm_routes	= ARRAY_SIZE(tas2770_audio_map),528	.idle_bias_on		= 1,529	.endianness		= 1,530};531 532static int tas2770_register_codec(struct tas2770_priv *tas2770)533{534	return devm_snd_soc_register_component(tas2770->dev,535		&soc_component_driver_tas2770,536		tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver));537}538 539static const struct reg_default tas2770_reg_defaults[] = {540	{ TAS2770_PAGE, 0x00 },541	{ TAS2770_SW_RST, 0x00 },542	{ TAS2770_PWR_CTRL, 0x0e },543	{ TAS2770_PLAY_CFG_REG0, 0x10 },544	{ TAS2770_PLAY_CFG_REG1, 0x01 },545	{ TAS2770_PLAY_CFG_REG2, 0x00 },546	{ TAS2770_MSC_CFG_REG0, 0x07 },547	{ TAS2770_TDM_CFG_REG1, 0x02 },548	{ TAS2770_TDM_CFG_REG2, 0x0a },549	{ TAS2770_TDM_CFG_REG3, 0x10 },550	{ TAS2770_INT_MASK_REG0, 0xfc },551	{ TAS2770_INT_MASK_REG1, 0xb1 },552	{ TAS2770_INT_CFG, 0x05 },553	{ TAS2770_MISC_IRQ, 0x81 },554	{ TAS2770_CLK_CGF, 0x0c },555 556};557 558static bool tas2770_volatile(struct device *dev, unsigned int reg)559{560	switch (reg) {561	case TAS2770_PAGE: /* regmap implementation requires this */562	case TAS2770_SW_RST: /* always clears after write */563	case TAS2770_BO_PRV_REG0:/* has a self clearing bit */564	case TAS2770_LVE_INT_REG0:565	case TAS2770_LVE_INT_REG1:566	case TAS2770_LAT_INT_REG0:/* Sticky interrupt flags */567	case TAS2770_LAT_INT_REG1:/* Sticky interrupt flags */568	case TAS2770_VBAT_MSB:569	case TAS2770_VBAT_LSB:570	case TAS2770_TEMP_MSB:571	case TAS2770_TEMP_LSB:572		return true;573	}574 575	return false;576}577 578static bool tas2770_writeable(struct device *dev, unsigned int reg)579{580	switch (reg) {581	case TAS2770_LVE_INT_REG0:582	case TAS2770_LVE_INT_REG1:583	case TAS2770_LAT_INT_REG0:584	case TAS2770_LAT_INT_REG1:585	case TAS2770_VBAT_MSB:586	case TAS2770_VBAT_LSB:587	case TAS2770_TEMP_MSB:588	case TAS2770_TEMP_LSB:589	case TAS2770_TDM_CLK_DETC:590	case TAS2770_REV_AND_GPID:591		return false;592	}593 594	return true;595}596 597static const struct regmap_range_cfg tas2770_regmap_ranges[] = {598	{599		.range_min = 0,600		.range_max = 1 * 128,601		.selector_reg = TAS2770_PAGE,602		.selector_mask = 0xff,603		.selector_shift = 0,604		.window_start = 0,605		.window_len = 128,606	},607};608 609static const struct regmap_config tas2770_i2c_regmap = {610	.reg_bits = 8,611	.val_bits = 8,612	.writeable_reg = tas2770_writeable,613	.volatile_reg = tas2770_volatile,614	.reg_defaults = tas2770_reg_defaults,615	.num_reg_defaults = ARRAY_SIZE(tas2770_reg_defaults),616	.cache_type = REGCACHE_RBTREE,617	.ranges = tas2770_regmap_ranges,618	.num_ranges = ARRAY_SIZE(tas2770_regmap_ranges),619	.max_register = 1 * 128,620};621 622static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770)623{624	int rc = 0;625 626	rc = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",627				      &tas2770->i_sense_slot);628	if (rc) {629		dev_info(tas2770->dev, "Property %s is missing setting default slot\n",630			 "ti,imon-slot-no");631 632		tas2770->i_sense_slot = 0;633	}634 635	rc = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",636				      &tas2770->v_sense_slot);637	if (rc) {638		dev_info(tas2770->dev, "Property %s is missing setting default slot\n",639			 "ti,vmon-slot-no");640 641		tas2770->v_sense_slot = 2;642	}643 644	tas2770->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);645	if (IS_ERR(tas2770->sdz_gpio)) {646		if (PTR_ERR(tas2770->sdz_gpio) == -EPROBE_DEFER)647			return -EPROBE_DEFER;648 649		tas2770->sdz_gpio = NULL;650	}651 652	return 0;653}654 655static int tas2770_i2c_probe(struct i2c_client *client)656{657	struct tas2770_priv *tas2770;658	int result;659 660	tas2770 = devm_kzalloc(&client->dev, sizeof(struct tas2770_priv),661			       GFP_KERNEL);662	if (!tas2770)663		return -ENOMEM;664 665	tas2770->dev = &client->dev;666	i2c_set_clientdata(client, tas2770);667	dev_set_drvdata(&client->dev, tas2770);668 669	tas2770->regmap = devm_regmap_init_i2c(client, &tas2770_i2c_regmap);670	if (IS_ERR(tas2770->regmap)) {671		result = PTR_ERR(tas2770->regmap);672		dev_err(&client->dev, "Failed to allocate register map: %d\n",673			result);674		return result;675	}676 677	if (client->dev.of_node) {678		result = tas2770_parse_dt(&client->dev, tas2770);679		if (result) {680			dev_err(tas2770->dev, "%s: Failed to parse devicetree\n",681				__func__);682			return result;683		}684	}685 686	tas2770->reset_gpio = devm_gpiod_get_optional(tas2770->dev, "reset",687						      GPIOD_OUT_HIGH);688	if (IS_ERR(tas2770->reset_gpio)) {689		if (PTR_ERR(tas2770->reset_gpio) == -EPROBE_DEFER) {690			tas2770->reset_gpio = NULL;691			return -EPROBE_DEFER;692		}693	}694 695	result = tas2770_register_codec(tas2770);696	if (result)697		dev_err(tas2770->dev, "Register codec failed.\n");698 699	return result;700}701 702static const struct i2c_device_id tas2770_i2c_id[] = {703	{ "tas2770"},704	{ }705};706MODULE_DEVICE_TABLE(i2c, tas2770_i2c_id);707 708#if defined(CONFIG_OF)709static const struct of_device_id tas2770_of_match[] = {710	{ .compatible = "ti,tas2770" },711	{},712};713MODULE_DEVICE_TABLE(of, tas2770_of_match);714#endif715 716static struct i2c_driver tas2770_i2c_driver = {717	.driver = {718		.name   = "tas2770",719		.of_match_table = of_match_ptr(tas2770_of_match),720	},721	.probe      = tas2770_i2c_probe,722	.id_table   = tas2770_i2c_id,723};724module_i2c_driver(tas2770_i2c_driver);725 726MODULE_AUTHOR("Shi Fu <shifu0704@thundersoft.com>");727MODULE_DESCRIPTION("TAS2770 I2C Smart Amplifier driver");728MODULE_LICENSE("GPL v2");729