18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCM1681 ASoC codec driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) StreamUnlimited GmbH 2013 68c2ecf20Sopenharmony_ci * Marek Belisko <marek.belisko@streamunlimited.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/gpio.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 188c2ecf20Sopenharmony_ci#include <sound/pcm.h> 198c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 208c2ecf20Sopenharmony_ci#include <sound/soc.h> 218c2ecf20Sopenharmony_ci#include <sound/tlv.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 248c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define PCM1681_PCM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ 278c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 288c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ 298c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define PCM1681_SOFT_MUTE_ALL 0xff 328c2ecf20Sopenharmony_ci#define PCM1681_DEEMPH_RATE_MASK 0x18 338c2ecf20Sopenharmony_ci#define PCM1681_DEEMPH_MASK 0x01 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define PCM1681_ATT_CONTROL(X) (X <= 6 ? X : X + 9) /* Attenuation level */ 368c2ecf20Sopenharmony_ci#define PCM1681_SOFT_MUTE 0x07 /* Soft mute control register */ 378c2ecf20Sopenharmony_ci#define PCM1681_DAC_CONTROL 0x08 /* DAC operation control */ 388c2ecf20Sopenharmony_ci#define PCM1681_FMT_CONTROL 0x09 /* Audio interface data format */ 398c2ecf20Sopenharmony_ci#define PCM1681_DEEMPH_CONTROL 0x0a /* De-emphasis control */ 408c2ecf20Sopenharmony_ci#define PCM1681_ZERO_DETECT_STATUS 0x0e /* Zero detect status reg */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const struct reg_default pcm1681_reg_defaults[] = { 438c2ecf20Sopenharmony_ci { 0x01, 0xff }, 448c2ecf20Sopenharmony_ci { 0x02, 0xff }, 458c2ecf20Sopenharmony_ci { 0x03, 0xff }, 468c2ecf20Sopenharmony_ci { 0x04, 0xff }, 478c2ecf20Sopenharmony_ci { 0x05, 0xff }, 488c2ecf20Sopenharmony_ci { 0x06, 0xff }, 498c2ecf20Sopenharmony_ci { 0x07, 0x00 }, 508c2ecf20Sopenharmony_ci { 0x08, 0x00 }, 518c2ecf20Sopenharmony_ci { 0x09, 0x06 }, 528c2ecf20Sopenharmony_ci { 0x0A, 0x00 }, 538c2ecf20Sopenharmony_ci { 0x0B, 0xff }, 548c2ecf20Sopenharmony_ci { 0x0C, 0x0f }, 558c2ecf20Sopenharmony_ci { 0x0D, 0x00 }, 568c2ecf20Sopenharmony_ci { 0x10, 0xff }, 578c2ecf20Sopenharmony_ci { 0x11, 0xff }, 588c2ecf20Sopenharmony_ci { 0x12, 0x00 }, 598c2ecf20Sopenharmony_ci { 0x13, 0x00 }, 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic bool pcm1681_accessible_reg(struct device *dev, unsigned int reg) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return !((reg == 0x00) || (reg == 0x0f)); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic bool pcm1681_writeable_reg(struct device *dev, unsigned int reg) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci return pcm1681_accessible_reg(dev, reg) && 708c2ecf20Sopenharmony_ci (reg != PCM1681_ZERO_DETECT_STATUS); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistruct pcm1681_private { 748c2ecf20Sopenharmony_ci struct regmap *regmap; 758c2ecf20Sopenharmony_ci unsigned int format; 768c2ecf20Sopenharmony_ci /* Current deemphasis status */ 778c2ecf20Sopenharmony_ci unsigned int deemph; 788c2ecf20Sopenharmony_ci /* Current rate for deemphasis control */ 798c2ecf20Sopenharmony_ci unsigned int rate; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const int pcm1681_deemph[] = { 44100, 48000, 32000 }; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int pcm1681_set_deemph(struct snd_soc_component *component) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); 878c2ecf20Sopenharmony_ci int i = 0, val = -1, enable = 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (priv->deemph) { 908c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) { 918c2ecf20Sopenharmony_ci if (pcm1681_deemph[i] == priv->rate) { 928c2ecf20Sopenharmony_ci val = i; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (val != -1) { 998c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, 1008c2ecf20Sopenharmony_ci PCM1681_DEEMPH_RATE_MASK, val << 3); 1018c2ecf20Sopenharmony_ci enable = 1; 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci enable = 0; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* enable/disable deemphasis functionality */ 1078c2ecf20Sopenharmony_ci return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, 1088c2ecf20Sopenharmony_ci PCM1681_DEEMPH_MASK, enable); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int pcm1681_get_deemph(struct snd_kcontrol *kcontrol, 1128c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1158c2ecf20Sopenharmony_ci struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = priv->deemph; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int pcm1681_put_deemph(struct snd_kcontrol *kcontrol, 1238c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1268c2ecf20Sopenharmony_ci struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci priv->deemph = ucontrol->value.integer.value[0]; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return pcm1681_set_deemph(component); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai, 1348c2ecf20Sopenharmony_ci unsigned int format) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 1378c2ecf20Sopenharmony_ci struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* The PCM1681 can only be slave to all clocks */ 1408c2ecf20Sopenharmony_ci if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { 1418c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid clocking mode\n"); 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci priv->format = format; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int pcm1681_mute(struct snd_soc_dai *dai, int mute, int direction) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 1538c2ecf20Sopenharmony_ci struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); 1548c2ecf20Sopenharmony_ci int val; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (mute) 1578c2ecf20Sopenharmony_ci val = PCM1681_SOFT_MUTE_ALL; 1588c2ecf20Sopenharmony_ci else 1598c2ecf20Sopenharmony_ci val = 0; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int pcm1681_hw_params(struct snd_pcm_substream *substream, 1658c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 1668c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 1698c2ecf20Sopenharmony_ci struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); 1708c2ecf20Sopenharmony_ci int val = 0, ret; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci priv->rate = params_rate(params); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { 1758c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 1768c2ecf20Sopenharmony_ci switch (params_width(params)) { 1778c2ecf20Sopenharmony_ci case 24: 1788c2ecf20Sopenharmony_ci val = 0; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci case 16: 1818c2ecf20Sopenharmony_ci val = 3; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci default: 1848c2ecf20Sopenharmony_ci return -EINVAL; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 1888c2ecf20Sopenharmony_ci val = 0x04; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 1918c2ecf20Sopenharmony_ci val = 0x05; 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci default: 1948c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid DAI format\n"); 1958c2ecf20Sopenharmony_ci return -EINVAL; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val); 1998c2ecf20Sopenharmony_ci if (ret < 0) 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return pcm1681_set_deemph(component); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops pcm1681_dai_ops = { 2068c2ecf20Sopenharmony_ci .set_fmt = pcm1681_set_dai_fmt, 2078c2ecf20Sopenharmony_ci .hw_params = pcm1681_hw_params, 2088c2ecf20Sopenharmony_ci .mute_stream = pcm1681_mute, 2098c2ecf20Sopenharmony_ci .no_capture_mute = 1, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget pcm1681_dapm_widgets[] = { 2138c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT1"), 2148c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT2"), 2158c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT3"), 2168c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT4"), 2178c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT5"), 2188c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT6"), 2198c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT7"), 2208c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT8"), 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route pcm1681_dapm_routes[] = { 2248c2ecf20Sopenharmony_ci { "VOUT1", NULL, "Playback" }, 2258c2ecf20Sopenharmony_ci { "VOUT2", NULL, "Playback" }, 2268c2ecf20Sopenharmony_ci { "VOUT3", NULL, "Playback" }, 2278c2ecf20Sopenharmony_ci { "VOUT4", NULL, "Playback" }, 2288c2ecf20Sopenharmony_ci { "VOUT5", NULL, "Playback" }, 2298c2ecf20Sopenharmony_ci { "VOUT6", NULL, "Playback" }, 2308c2ecf20Sopenharmony_ci { "VOUT7", NULL, "Playback" }, 2318c2ecf20Sopenharmony_ci { "VOUT8", NULL, "Playback" }, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcm1681_controls[] = { 2378c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume", 2388c2ecf20Sopenharmony_ci PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0, 2398c2ecf20Sopenharmony_ci 0x7f, 0, pcm1681_dac_tlv), 2408c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume", 2418c2ecf20Sopenharmony_ci PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0, 2428c2ecf20Sopenharmony_ci 0x7f, 0, pcm1681_dac_tlv), 2438c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume", 2448c2ecf20Sopenharmony_ci PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0, 2458c2ecf20Sopenharmony_ci 0x7f, 0, pcm1681_dac_tlv), 2468c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume", 2478c2ecf20Sopenharmony_ci PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0, 2488c2ecf20Sopenharmony_ci 0x7f, 0, pcm1681_dac_tlv), 2498c2ecf20Sopenharmony_ci SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, 2508c2ecf20Sopenharmony_ci pcm1681_get_deemph, pcm1681_put_deemph), 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver pcm1681_dai = { 2548c2ecf20Sopenharmony_ci .name = "pcm1681-hifi", 2558c2ecf20Sopenharmony_ci .playback = { 2568c2ecf20Sopenharmony_ci .stream_name = "Playback", 2578c2ecf20Sopenharmony_ci .channels_min = 2, 2588c2ecf20Sopenharmony_ci .channels_max = 8, 2598c2ecf20Sopenharmony_ci .rates = PCM1681_PCM_RATES, 2608c2ecf20Sopenharmony_ci .formats = PCM1681_PCM_FORMATS, 2618c2ecf20Sopenharmony_ci }, 2628c2ecf20Sopenharmony_ci .ops = &pcm1681_dai_ops, 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 2668c2ecf20Sopenharmony_cistatic const struct of_device_id pcm1681_dt_ids[] = { 2678c2ecf20Sopenharmony_ci { .compatible = "ti,pcm1681", }, 2688c2ecf20Sopenharmony_ci { } 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pcm1681_dt_ids); 2718c2ecf20Sopenharmony_ci#endif 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic const struct regmap_config pcm1681_regmap = { 2748c2ecf20Sopenharmony_ci .reg_bits = 8, 2758c2ecf20Sopenharmony_ci .val_bits = 8, 2768c2ecf20Sopenharmony_ci .max_register = 0x13, 2778c2ecf20Sopenharmony_ci .reg_defaults = pcm1681_reg_defaults, 2788c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(pcm1681_reg_defaults), 2798c2ecf20Sopenharmony_ci .writeable_reg = pcm1681_writeable_reg, 2808c2ecf20Sopenharmony_ci .readable_reg = pcm1681_accessible_reg, 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_pcm1681 = { 2848c2ecf20Sopenharmony_ci .controls = pcm1681_controls, 2858c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(pcm1681_controls), 2868c2ecf20Sopenharmony_ci .dapm_widgets = pcm1681_dapm_widgets, 2878c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(pcm1681_dapm_widgets), 2888c2ecf20Sopenharmony_ci .dapm_routes = pcm1681_dapm_routes, 2898c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(pcm1681_dapm_routes), 2908c2ecf20Sopenharmony_ci .idle_bias_on = 1, 2918c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 2928c2ecf20Sopenharmony_ci .endianness = 1, 2938c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 2948c2ecf20Sopenharmony_ci}; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic const struct i2c_device_id pcm1681_i2c_id[] = { 2978c2ecf20Sopenharmony_ci {"pcm1681", 0}, 2988c2ecf20Sopenharmony_ci {} 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int pcm1681_i2c_probe(struct i2c_client *client, 3038c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci int ret; 3068c2ecf20Sopenharmony_ci struct pcm1681_private *priv; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 3098c2ecf20Sopenharmony_ci if (!priv) 3108c2ecf20Sopenharmony_ci return -ENOMEM; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap); 3138c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap)) { 3148c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->regmap); 3158c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to create regmap: %d\n", ret); 3168c2ecf20Sopenharmony_ci return ret; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci i2c_set_clientdata(client, priv); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(&client->dev, 3228c2ecf20Sopenharmony_ci &soc_component_dev_pcm1681, 3238c2ecf20Sopenharmony_ci &pcm1681_dai, 1); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic struct i2c_driver pcm1681_i2c_driver = { 3278c2ecf20Sopenharmony_ci .driver = { 3288c2ecf20Sopenharmony_ci .name = "pcm1681", 3298c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(pcm1681_dt_ids), 3308c2ecf20Sopenharmony_ci }, 3318c2ecf20Sopenharmony_ci .id_table = pcm1681_i2c_id, 3328c2ecf20Sopenharmony_ci .probe = pcm1681_i2c_probe, 3338c2ecf20Sopenharmony_ci}; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cimodule_i2c_driver(pcm1681_i2c_driver); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver"); 3388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>"); 3398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 340