0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include <linux/module.h>
0019 #include <linux/moduleparam.h>
0020 #include <linux/init.h>
0021 #include <linux/delay.h>
0022 #include <linux/pm.h>
0023 #include <linux/regmap.h>
0024 #include <linux/slab.h>
0025 #include <sound/core.h>
0026 #include <sound/pcm.h>
0027 #include <sound/pcm_params.h>
0028 #include <sound/soc.h>
0029 #include <sound/tlv.h>
0030 #include <sound/initval.h>
0031
0032 #include "tlv320aic23.h"
0033
0034
0035
0036
0037 static const struct reg_default tlv320aic23_reg[] = {
0038 { 0, 0x0097 },
0039 { 1, 0x0097 },
0040 { 2, 0x00F9 },
0041 { 3, 0x00F9 },
0042 { 4, 0x001A },
0043 { 5, 0x0004 },
0044 { 6, 0x0007 },
0045 { 7, 0x0001 },
0046 { 8, 0x0020 },
0047 { 9, 0x0000 },
0048 };
0049
0050 const struct regmap_config tlv320aic23_regmap = {
0051 .reg_bits = 7,
0052 .val_bits = 9,
0053
0054 .max_register = TLV320AIC23_RESET,
0055 .reg_defaults = tlv320aic23_reg,
0056 .num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg),
0057 .cache_type = REGCACHE_RBTREE,
0058 };
0059 EXPORT_SYMBOL(tlv320aic23_regmap);
0060
0061 static const char *rec_src_text[] = { "Line", "Mic" };
0062 static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
0063
0064 static SOC_ENUM_SINGLE_DECL(rec_src_enum,
0065 TLV320AIC23_ANLG, 2, rec_src_text);
0066
0067 static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
0068 SOC_DAPM_ENUM("Input Select", rec_src_enum);
0069
0070 static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph,
0071 TLV320AIC23_DIGT, 1, deemph_text);
0072
0073 static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
0074 static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
0075 static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
0076
0077 static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
0078 struct snd_ctl_elem_value *ucontrol)
0079 {
0080 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
0081 u16 val, reg;
0082
0083 val = (ucontrol->value.integer.value[0] & 0x07);
0084
0085
0086
0087
0088
0089
0090
0091
0092 val = (val >= 4) ? 4 : (3 - val);
0093
0094 reg = snd_soc_component_read(component, TLV320AIC23_ANLG) & (~0x1C0);
0095 snd_soc_component_write(component, TLV320AIC23_ANLG, reg | (val << 6));
0096
0097 return 0;
0098 }
0099
0100 static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
0101 struct snd_ctl_elem_value *ucontrol)
0102 {
0103 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
0104 u16 val;
0105
0106 val = snd_soc_component_read(component, TLV320AIC23_ANLG) & (0x1C0);
0107 val = val >> 6;
0108 val = (val >= 4) ? 4 : (3 - val);
0109 ucontrol->value.integer.value[0] = val;
0110 return 0;
0111
0112 }
0113
0114 static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
0115 SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
0116 TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
0117 SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
0118 SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
0119 TLV320AIC23_RINVOL, 7, 1, 0),
0120 SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
0121 TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
0122 SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
0123 SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
0124 SOC_SINGLE_EXT_TLV("Sidetone Volume", TLV320AIC23_ANLG, 6, 4, 0,
0125 snd_soc_tlv320aic23_get_volsw,
0126 snd_soc_tlv320aic23_put_volsw, sidetone_vol_tlv),
0127 SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
0128 };
0129
0130
0131 static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
0132 SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
0133 SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
0134 SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
0135 };
0136
0137 static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
0138 SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
0139 SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
0140 SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
0141 &tlv320aic23_rec_src_mux_controls),
0142 SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
0143 &tlv320aic23_output_mixer_controls[0],
0144 ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
0145 SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
0146 SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
0147
0148 SND_SOC_DAPM_OUTPUT("LHPOUT"),
0149 SND_SOC_DAPM_OUTPUT("RHPOUT"),
0150 SND_SOC_DAPM_OUTPUT("LOUT"),
0151 SND_SOC_DAPM_OUTPUT("ROUT"),
0152
0153 SND_SOC_DAPM_INPUT("LLINEIN"),
0154 SND_SOC_DAPM_INPUT("RLINEIN"),
0155
0156 SND_SOC_DAPM_INPUT("MICIN"),
0157 };
0158
0159 static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
0160
0161 {"Output Mixer", "Line Bypass Switch", "Line Input"},
0162 {"Output Mixer", "Playback Switch", "DAC"},
0163 {"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
0164
0165
0166 {"RHPOUT", NULL, "Output Mixer"},
0167 {"LHPOUT", NULL, "Output Mixer"},
0168 {"LOUT", NULL, "Output Mixer"},
0169 {"ROUT", NULL, "Output Mixer"},
0170
0171
0172 {"Line Input", NULL, "LLINEIN"},
0173 {"Line Input", NULL, "RLINEIN"},
0174 {"Mic Input", NULL, "MICIN"},
0175
0176
0177 {"Capture Source", "Line", "Line Input"},
0178 {"Capture Source", "Mic", "Mic Input"},
0179 {"ADC", NULL, "Capture Source"},
0180
0181 };
0182
0183
0184 struct aic23 {
0185 struct regmap *regmap;
0186 int mclk;
0187 int requested_adc;
0188 int requested_dac;
0189 };
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 static const int bosr_usb_divisor_table[] = {
0205 128, 125, 192, 136
0206 };
0207 #define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7))
0208 #define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11) | (1<<15))
0209 static const unsigned short sr_valid_mask[] = {
0210 LOWER_GROUP|UPPER_GROUP,
0211 LOWER_GROUP,
0212 LOWER_GROUP|UPPER_GROUP,
0213 UPPER_GROUP,
0214 };
0215
0216
0217
0218 #define SR_MULT (11*12)
0219 #define A(x) (SR_MULT/x)
0220 static const unsigned char sr_adc_mult_table[] = {
0221 A(2), A(2), A(12), A(12), 0, 0, A(3), A(1),
0222 A(2), A(2), A(11), A(11), 0, 0, 0, A(1)
0223 };
0224 static const unsigned char sr_dac_mult_table[] = {
0225 A(2), A(12), A(2), A(12), 0, 0, A(3), A(1),
0226 A(2), A(11), A(2), A(11), 0, 0, 0, A(1)
0227 };
0228
0229 static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc,
0230 int dac, int dac_l, int dac_h, int need_dac)
0231 {
0232 if ((adc >= adc_l) && (adc <= adc_h) &&
0233 (dac >= dac_l) && (dac <= dac_h)) {
0234 int diff_adc = need_adc - adc;
0235 int diff_dac = need_dac - dac;
0236 return abs(diff_adc) + abs(diff_dac);
0237 }
0238 return UINT_MAX;
0239 }
0240
0241 static int find_rate(int mclk, u32 need_adc, u32 need_dac)
0242 {
0243 int i, j;
0244 int best_i = -1;
0245 int best_j = -1;
0246 int best_div = 0;
0247 unsigned best_score = UINT_MAX;
0248 int adc_l, adc_h, dac_l, dac_h;
0249
0250 need_adc *= SR_MULT;
0251 need_dac *= SR_MULT;
0252
0253
0254
0255 adc_l = need_adc - (need_adc >> 5);
0256 adc_h = need_adc + (need_adc >> 5);
0257 dac_l = need_dac - (need_dac >> 5);
0258 dac_h = need_dac + (need_dac >> 5);
0259 for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) {
0260 int base = mclk / bosr_usb_divisor_table[i];
0261 int mask = sr_valid_mask[i];
0262 for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table);
0263 j++, mask >>= 1) {
0264 int adc;
0265 int dac;
0266 int score;
0267 if ((mask & 1) == 0)
0268 continue;
0269 adc = base * sr_adc_mult_table[j];
0270 dac = base * sr_dac_mult_table[j];
0271 score = get_score(adc, adc_l, adc_h, need_adc,
0272 dac, dac_l, dac_h, need_dac);
0273 if (best_score > score) {
0274 best_score = score;
0275 best_i = i;
0276 best_j = j;
0277 best_div = 0;
0278 }
0279 score = get_score((adc >> 1), adc_l, adc_h, need_adc,
0280 (dac >> 1), dac_l, dac_h, need_dac);
0281
0282 if ((score != UINT_MAX) && (best_score >= score)) {
0283 best_score = score;
0284 best_i = i;
0285 best_j = j;
0286 best_div = 1;
0287 }
0288 }
0289 }
0290 return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT);
0291 }
0292
0293 #ifdef DEBUG
0294 static void get_current_sample_rates(struct snd_soc_component *component, int mclk,
0295 u32 *sample_rate_adc, u32 *sample_rate_dac)
0296 {
0297 int src = snd_soc_component_read(component, TLV320AIC23_SRATE);
0298 int sr = (src >> 2) & 0x0f;
0299 int val = (mclk / bosr_usb_divisor_table[src & 3]);
0300 int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
0301 int dac = (val * sr_dac_mult_table[sr]) / SR_MULT;
0302 if (src & TLV320AIC23_CLKIN_HALF) {
0303 adc >>= 1;
0304 dac >>= 1;
0305 }
0306 *sample_rate_adc = adc;
0307 *sample_rate_dac = dac;
0308 }
0309 #endif
0310
0311 static int set_sample_rate_control(struct snd_soc_component *component, int mclk,
0312 u32 sample_rate_adc, u32 sample_rate_dac)
0313 {
0314
0315 int data = find_rate(mclk, sample_rate_adc, sample_rate_dac);
0316 if (data < 0) {
0317 printk(KERN_ERR "%s:Invalid rate %u,%u requested\n",
0318 __func__, sample_rate_adc, sample_rate_dac);
0319 return -EINVAL;
0320 }
0321 snd_soc_component_write(component, TLV320AIC23_SRATE, data);
0322 #ifdef DEBUG
0323 {
0324 u32 adc, dac;
0325 get_current_sample_rates(component, mclk, &adc, &dac);
0326 printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n",
0327 adc, dac, data);
0328 }
0329 #endif
0330 return 0;
0331 }
0332
0333 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
0334 struct snd_pcm_hw_params *params,
0335 struct snd_soc_dai *dai)
0336 {
0337 struct snd_soc_component *component = dai->component;
0338 u16 iface_reg;
0339 int ret;
0340 struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
0341 u32 sample_rate_adc = aic23->requested_adc;
0342 u32 sample_rate_dac = aic23->requested_dac;
0343 u32 sample_rate = params_rate(params);
0344
0345 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0346 aic23->requested_dac = sample_rate_dac = sample_rate;
0347 if (!sample_rate_adc)
0348 sample_rate_adc = sample_rate;
0349 } else {
0350 aic23->requested_adc = sample_rate_adc = sample_rate;
0351 if (!sample_rate_dac)
0352 sample_rate_dac = sample_rate;
0353 }
0354 ret = set_sample_rate_control(component, aic23->mclk, sample_rate_adc,
0355 sample_rate_dac);
0356 if (ret < 0)
0357 return ret;
0358
0359 iface_reg = snd_soc_component_read(component, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
0360
0361 switch (params_width(params)) {
0362 case 16:
0363 break;
0364 case 20:
0365 iface_reg |= (0x01 << 2);
0366 break;
0367 case 24:
0368 iface_reg |= (0x02 << 2);
0369 break;
0370 case 32:
0371 iface_reg |= (0x03 << 2);
0372 break;
0373 }
0374 snd_soc_component_write(component, TLV320AIC23_DIGT_FMT, iface_reg);
0375
0376 return 0;
0377 }
0378
0379 static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
0380 struct snd_soc_dai *dai)
0381 {
0382 struct snd_soc_component *component = dai->component;
0383
0384
0385 snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0001);
0386
0387 return 0;
0388 }
0389
0390 static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
0391 struct snd_soc_dai *dai)
0392 {
0393 struct snd_soc_component *component = dai->component;
0394 struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
0395
0396
0397 if (!snd_soc_component_active(component)) {
0398 udelay(50);
0399 snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0);
0400 }
0401 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0402 aic23->requested_dac = 0;
0403 else
0404 aic23->requested_adc = 0;
0405 }
0406
0407 static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute, int direction)
0408 {
0409 struct snd_soc_component *component = dai->component;
0410 u16 reg;
0411
0412 reg = snd_soc_component_read(component, TLV320AIC23_DIGT);
0413 if (mute)
0414 reg |= TLV320AIC23_DACM_MUTE;
0415
0416 else
0417 reg &= ~TLV320AIC23_DACM_MUTE;
0418
0419 snd_soc_component_write(component, TLV320AIC23_DIGT, reg);
0420
0421 return 0;
0422 }
0423
0424 static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
0425 unsigned int fmt)
0426 {
0427 struct snd_soc_component *component = codec_dai->component;
0428 u16 iface_reg;
0429
0430 iface_reg = snd_soc_component_read(component, TLV320AIC23_DIGT_FMT) & (~0x03);
0431
0432 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0433 case SND_SOC_DAIFMT_CBP_CFP:
0434 iface_reg |= TLV320AIC23_MS_MASTER;
0435 break;
0436 case SND_SOC_DAIFMT_CBC_CFC:
0437 iface_reg &= ~TLV320AIC23_MS_MASTER;
0438 break;
0439 default:
0440 return -EINVAL;
0441
0442 }
0443
0444
0445 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0446 case SND_SOC_DAIFMT_I2S:
0447 iface_reg |= TLV320AIC23_FOR_I2S;
0448 break;
0449 case SND_SOC_DAIFMT_DSP_A:
0450 iface_reg |= TLV320AIC23_LRP_ON;
0451 fallthrough;
0452 case SND_SOC_DAIFMT_DSP_B:
0453 iface_reg |= TLV320AIC23_FOR_DSP;
0454 break;
0455 case SND_SOC_DAIFMT_RIGHT_J:
0456 break;
0457 case SND_SOC_DAIFMT_LEFT_J:
0458 iface_reg |= TLV320AIC23_FOR_LJUST;
0459 break;
0460 default:
0461 return -EINVAL;
0462
0463 }
0464
0465 snd_soc_component_write(component, TLV320AIC23_DIGT_FMT, iface_reg);
0466
0467 return 0;
0468 }
0469
0470 static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
0471 int clk_id, unsigned int freq, int dir)
0472 {
0473 struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai);
0474 aic23->mclk = freq;
0475 return 0;
0476 }
0477
0478 static int tlv320aic23_set_bias_level(struct snd_soc_component *component,
0479 enum snd_soc_bias_level level)
0480 {
0481 u16 reg = snd_soc_component_read(component, TLV320AIC23_PWR) & 0x17f;
0482
0483 switch (level) {
0484 case SND_SOC_BIAS_ON:
0485
0486 reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \
0487 TLV320AIC23_DAC_OFF);
0488 snd_soc_component_write(component, TLV320AIC23_PWR, reg);
0489 break;
0490 case SND_SOC_BIAS_PREPARE:
0491 break;
0492 case SND_SOC_BIAS_STANDBY:
0493
0494 snd_soc_component_write(component, TLV320AIC23_PWR,
0495 reg | TLV320AIC23_CLK_OFF);
0496 break;
0497 case SND_SOC_BIAS_OFF:
0498
0499 snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0);
0500 snd_soc_component_write(component, TLV320AIC23_PWR, 0x1ff);
0501 break;
0502 }
0503 return 0;
0504 }
0505
0506 #define AIC23_RATES SNDRV_PCM_RATE_8000_96000
0507 #define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
0508 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
0509
0510 static const struct snd_soc_dai_ops tlv320aic23_dai_ops = {
0511 .prepare = tlv320aic23_pcm_prepare,
0512 .hw_params = tlv320aic23_hw_params,
0513 .shutdown = tlv320aic23_shutdown,
0514 .mute_stream = tlv320aic23_mute,
0515 .set_fmt = tlv320aic23_set_dai_fmt,
0516 .set_sysclk = tlv320aic23_set_dai_sysclk,
0517 .no_capture_mute = 1,
0518 };
0519
0520 static struct snd_soc_dai_driver tlv320aic23_dai = {
0521 .name = "tlv320aic23-hifi",
0522 .playback = {
0523 .stream_name = "Playback",
0524 .channels_min = 2,
0525 .channels_max = 2,
0526 .rates = AIC23_RATES,
0527 .formats = AIC23_FORMATS,},
0528 .capture = {
0529 .stream_name = "Capture",
0530 .channels_min = 2,
0531 .channels_max = 2,
0532 .rates = AIC23_RATES,
0533 .formats = AIC23_FORMATS,},
0534 .ops = &tlv320aic23_dai_ops,
0535 };
0536
0537 static int tlv320aic23_resume(struct snd_soc_component *component)
0538 {
0539 struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
0540 regcache_mark_dirty(aic23->regmap);
0541 regcache_sync(aic23->regmap);
0542
0543 return 0;
0544 }
0545
0546 static int tlv320aic23_component_probe(struct snd_soc_component *component)
0547 {
0548
0549 snd_soc_component_write(component, TLV320AIC23_RESET, 0);
0550
0551 snd_soc_component_write(component, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
0552
0553
0554 snd_soc_component_update_bits(component, TLV320AIC23_LINVOL,
0555 TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
0556
0557 snd_soc_component_update_bits(component, TLV320AIC23_RINVOL,
0558 TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
0559
0560 snd_soc_component_update_bits(component, TLV320AIC23_ANLG,
0561 TLV320AIC23_BYPASS_ON | TLV320AIC23_MICM_MUTED,
0562 0);
0563
0564
0565 snd_soc_component_write(component, TLV320AIC23_LCHNVOL,
0566 TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
0567 snd_soc_component_write(component, TLV320AIC23_RCHNVOL,
0568 TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
0569
0570 snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x1);
0571
0572 return 0;
0573 }
0574
0575 static const struct snd_soc_component_driver soc_component_dev_tlv320aic23 = {
0576 .probe = tlv320aic23_component_probe,
0577 .resume = tlv320aic23_resume,
0578 .set_bias_level = tlv320aic23_set_bias_level,
0579 .controls = tlv320aic23_snd_controls,
0580 .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls),
0581 .dapm_widgets = tlv320aic23_dapm_widgets,
0582 .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
0583 .dapm_routes = tlv320aic23_intercon,
0584 .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
0585 .suspend_bias_off = 1,
0586 .idle_bias_on = 1,
0587 .use_pmdown_time = 1,
0588 .endianness = 1,
0589 };
0590
0591 int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
0592 {
0593 struct aic23 *aic23;
0594
0595 if (IS_ERR(regmap))
0596 return PTR_ERR(regmap);
0597
0598 aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL);
0599 if (aic23 == NULL)
0600 return -ENOMEM;
0601
0602 aic23->regmap = regmap;
0603
0604 dev_set_drvdata(dev, aic23);
0605
0606 return devm_snd_soc_register_component(dev,
0607 &soc_component_dev_tlv320aic23,
0608 &tlv320aic23_dai, 1);
0609 }
0610 EXPORT_SYMBOL(tlv320aic23_probe);
0611
0612 MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
0613 MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
0614 MODULE_LICENSE("GPL");