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