~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/adau7118.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 //
  3 // Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver
  4 //
  5 // Copyright 2019 Analog Devices Inc.
  6 
  7 #include <linux/bitfield.h>
  8 #include <linux/module.h>
  9 #include <linux/regmap.h>
 10 #include <linux/regulator/consumer.h>
 11 #include <sound/pcm_params.h>
 12 #include <sound/soc.h>
 13 
 14 #include "adau7118.h"
 15 
 16 #define ADAU7118_DEC_RATIO_MASK         GENMASK(1, 0)
 17 #define ADAU7118_DEC_RATIO(x)           FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x)
 18 #define ADAU7118_CLK_MAP_MASK           GENMASK(7, 4)
 19 #define ADAU7118_SLOT_WIDTH_MASK        GENMASK(5, 4)
 20 #define ADAU7118_SLOT_WIDTH(x)          FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x)
 21 #define ADAU7118_TRISTATE_MASK          BIT(6)
 22 #define ADAU7118_TRISTATE(x)            FIELD_PREP(ADAU7118_TRISTATE_MASK, x)
 23 #define ADAU7118_DATA_FMT_MASK          GENMASK(3, 1)
 24 #define ADAU7118_DATA_FMT(x)            FIELD_PREP(ADAU7118_DATA_FMT_MASK, x)
 25 #define ADAU7118_SAI_MODE_MASK          BIT(0)
 26 #define ADAU7118_SAI_MODE(x)            FIELD_PREP(ADAU7118_SAI_MODE_MASK, x)
 27 #define ADAU7118_LRCLK_BCLK_POL_MASK    GENMASK(1, 0)
 28 #define ADAU7118_LRCLK_BCLK_POL(x) \
 29                                 FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x)
 30 #define ADAU7118_SPT_SLOT_MASK          GENMASK(7, 4)
 31 #define ADAU7118_SPT_SLOT(x)            FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x)
 32 #define ADAU7118_FULL_SOFT_R_MASK       BIT(1)
 33 #define ADAU7118_FULL_SOFT_R(x)         FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x)
 34 
 35 struct adau7118_data {
 36         struct regmap *map;
 37         struct device *dev;
 38         struct regulator *iovdd;
 39         struct regulator *dvdd;
 40         u32 slot_width;
 41         u32 slots;
 42         bool hw_mode;
 43         bool right_j;
 44 };
 45 
 46 /* Input Enable */
 47 static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = {
 48         SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0),
 49         SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0),
 50         SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0),
 51         SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0),
 52 };
 53 
 54 static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = {
 55         /* Input Enable Switches */
 56         SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0,
 57                             &adau7118_dapm_pdm_control[0]),
 58         SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0,
 59                             &adau7118_dapm_pdm_control[1]),
 60         SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0,
 61                             &adau7118_dapm_pdm_control[2]),
 62         SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0,
 63                             &adau7118_dapm_pdm_control[3]),
 64 
 65         /* PDM Clocks */
 66         SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0),
 67         SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0),
 68 
 69         /* Output channels */
 70         SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),
 71                              0, 0),
 72         SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),
 73                              0, 0),
 74         SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),
 75                              0, 0),
 76         SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),
 77                              0, 0),
 78         SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),
 79                              0, 0),
 80         SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),
 81                              0, 0),
 82         SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),
 83                              0, 0),
 84         SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),
 85                              0, 0),
 86 };
 87 
 88 static const struct snd_soc_dapm_route adau7118_routes_sw[] = {
 89         { "PDM0", "Capture Switch", "PDM_DAT0" },
 90         { "PDM1", "Capture Switch", "PDM_DAT1" },
 91         { "PDM2", "Capture Switch", "PDM_DAT2" },
 92         { "PDM3", "Capture Switch", "PDM_DAT3" },
 93         { "AIF1TX1", NULL, "PDM0" },
 94         { "AIF1TX2", NULL, "PDM0" },
 95         { "AIF1TX3", NULL, "PDM1" },
 96         { "AIF1TX4", NULL, "PDM1" },
 97         { "AIF1TX5", NULL, "PDM2" },
 98         { "AIF1TX6", NULL, "PDM2" },
 99         { "AIF1TX7", NULL, "PDM3" },
100         { "AIF1TX8", NULL, "PDM3" },
101         { "Capture", NULL, "PDM_CLK0" },
102         { "Capture", NULL, "PDM_CLK1" },
103 };
104 
105 static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = {
106         SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0),
107 };
108 
109 static const struct snd_soc_dapm_route adau7118_routes_hw[] = {
110         { "AIF1TX", NULL, "PDM_DAT0" },
111         { "AIF1TX", NULL, "PDM_DAT1" },
112         { "AIF1TX", NULL, "PDM_DAT2" },
113         { "AIF1TX", NULL, "PDM_DAT3" },
114 };
115 
116 static const struct snd_soc_dapm_widget adau7118_widgets[] = {
117         SND_SOC_DAPM_INPUT("PDM_DAT0"),
118         SND_SOC_DAPM_INPUT("PDM_DAT1"),
119         SND_SOC_DAPM_INPUT("PDM_DAT2"),
120         SND_SOC_DAPM_INPUT("PDM_DAT3"),
121 };
122 
123 static int adau7118_set_channel_map(struct snd_soc_dai *dai,
124                                     unsigned int tx_num,
125                                     const unsigned int *tx_slot,
126                                     unsigned int rx_num,
127                                     const unsigned int *rx_slot)
128 {
129         struct adau7118_data *st =
130                 snd_soc_component_get_drvdata(dai->component);
131         int chan, ret;
132 
133         dev_dbg(st->dev, "Set channel map, %d", tx_num);
134 
135         for (chan = 0; chan < tx_num; chan++) {
136                 ret = snd_soc_component_update_bits(dai->component,
137                                         ADAU7118_REG_SPT_CX(chan),
138                                         ADAU7118_SPT_SLOT_MASK,
139                                         ADAU7118_SPT_SLOT(tx_slot[chan]));
140                 if (ret < 0)
141                         return ret;
142         }
143 
144         return 0;
145 }
146 
147 static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
148 {
149         struct adau7118_data *st =
150                 snd_soc_component_get_drvdata(dai->component);
151         int ret = 0;
152         u32 regval;
153 
154         dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);
155 
156         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
157         case SND_SOC_DAIFMT_I2S:
158                 ret = snd_soc_component_update_bits(dai->component,
159                                                     ADAU7118_REG_SPT_CTRL1,
160                                                     ADAU7118_DATA_FMT_MASK,
161                                                     ADAU7118_DATA_FMT(0));
162                 break;
163         case SND_SOC_DAIFMT_LEFT_J:
164                 ret = snd_soc_component_update_bits(dai->component,
165                                                     ADAU7118_REG_SPT_CTRL1,
166                                                     ADAU7118_DATA_FMT_MASK,
167                                                     ADAU7118_DATA_FMT(1));
168                 break;
169         case SND_SOC_DAIFMT_RIGHT_J:
170                 st->right_j = true;
171                 break;
172         default:
173                 dev_err(st->dev, "Invalid format %d",
174                         fmt & SND_SOC_DAIFMT_FORMAT_MASK);
175                 return -EINVAL;
176         }
177 
178         if (ret < 0)
179                 return ret;
180 
181         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
182         case SND_SOC_DAIFMT_NB_NF:
183                 regval = ADAU7118_LRCLK_BCLK_POL(0);
184                 break;
185         case SND_SOC_DAIFMT_NB_IF:
186                 regval = ADAU7118_LRCLK_BCLK_POL(2);
187                 break;
188         case SND_SOC_DAIFMT_IB_NF:
189                 regval = ADAU7118_LRCLK_BCLK_POL(1);
190                 break;
191         case SND_SOC_DAIFMT_IB_IF:
192                 regval = ADAU7118_LRCLK_BCLK_POL(3);
193                 break;
194         default:
195                 dev_err(st->dev, "Invalid Inv mask %d",
196                         fmt & SND_SOC_DAIFMT_INV_MASK);
197                 return -EINVAL;
198         }
199 
200         ret = snd_soc_component_update_bits(dai->component,
201                                             ADAU7118_REG_SPT_CTRL2,
202                                             ADAU7118_LRCLK_BCLK_POL_MASK,
203                                             regval);
204         if (ret < 0)
205                 return ret;
206 
207         return 0;
208 }
209 
210 static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)
211 {
212         struct adau7118_data *st =
213                 snd_soc_component_get_drvdata(dai->component);
214         int ret;
215 
216         dev_dbg(st->dev, "Set tristate, %d\n", tristate);
217 
218         ret = snd_soc_component_update_bits(dai->component,
219                                             ADAU7118_REG_SPT_CTRL1,
220                                             ADAU7118_TRISTATE_MASK,
221                                             ADAU7118_TRISTATE(tristate));
222         if (ret < 0)
223                 return ret;
224 
225         return 0;
226 }
227 
228 static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
229                                  unsigned int rx_mask, int slots,
230                                  int slot_width)
231 {
232         struct adau7118_data *st =
233                 snd_soc_component_get_drvdata(dai->component);
234         int ret = 0;
235         u32 regval;
236 
237         dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);
238 
239         switch (slot_width) {
240         case 32:
241                 regval = ADAU7118_SLOT_WIDTH(0);
242                 break;
243         case 24:
244                 regval = ADAU7118_SLOT_WIDTH(2);
245                 break;
246         case 16:
247                 regval = ADAU7118_SLOT_WIDTH(1);
248                 break;
249         default:
250                 dev_err(st->dev, "Invalid slot width:%d\n", slot_width);
251                 return -EINVAL;
252         }
253 
254         ret = snd_soc_component_update_bits(dai->component,
255                                             ADAU7118_REG_SPT_CTRL1,
256                                             ADAU7118_SLOT_WIDTH_MASK, regval);
257         if (ret < 0)
258                 return ret;
259 
260         st->slot_width = slot_width;
261         st->slots = slots;
262 
263         return 0;
264 }
265 
266 static int adau7118_hw_params(struct snd_pcm_substream *substream,
267                               struct snd_pcm_hw_params *params,
268                               struct snd_soc_dai *dai)
269 {
270         struct adau7118_data *st =
271                 snd_soc_component_get_drvdata(dai->component);
272         u32 data_width = params_width(params), slots_width;
273         int ret;
274         u32 regval;
275 
276         if (!st->slots) {
277                 /* set stereo mode */
278                 ret = snd_soc_component_update_bits(dai->component,
279                                                     ADAU7118_REG_SPT_CTRL1,
280                                                     ADAU7118_SAI_MODE_MASK,
281                                                     ADAU7118_SAI_MODE(0));
282                 if (ret < 0)
283                         return ret;
284 
285                 slots_width = 32;
286         } else {
287                 slots_width = st->slot_width;
288         }
289 
290         if (data_width > slots_width) {
291                 dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",
292                         data_width, slots_width);
293                 return -EINVAL;
294         }
295 
296         if (st->right_j) {
297                 switch (slots_width - data_width) {
298                 case 8:
299                         /* delay bclck by 8 */
300                         regval = ADAU7118_DATA_FMT(2);
301                         break;
302                 case 12:
303                         /* delay bclck by 12 */
304                         regval = ADAU7118_DATA_FMT(3);
305                         break;
306                 case 16:
307                         /* delay bclck by 16 */
308                         regval = ADAU7118_DATA_FMT(4);
309                         break;
310                 default:
311                         dev_err(st->dev,
312                                 "Cannot set right_j setting, slot_w:%d, data_w:%d\n",
313                                         slots_width, data_width);
314                         return -EINVAL;
315                 }
316 
317                 ret = snd_soc_component_update_bits(dai->component,
318                                                     ADAU7118_REG_SPT_CTRL1,
319                                                     ADAU7118_DATA_FMT_MASK,
320                                                     regval);
321                 if (ret < 0)
322                         return ret;
323         }
324 
325         return 0;
326 }
327 
328 static int adau7118_set_bias_level(struct snd_soc_component *component,
329                                    enum snd_soc_bias_level level)
330 {
331         struct adau7118_data *st = snd_soc_component_get_drvdata(component);
332         int ret = 0;
333 
334         dev_dbg(st->dev, "Set bias level %d\n", level);
335 
336         switch (level) {
337         case SND_SOC_BIAS_ON:
338         case SND_SOC_BIAS_PREPARE:
339                 break;
340 
341         case SND_SOC_BIAS_STANDBY:
342                 if (snd_soc_component_get_bias_level(component) ==
343                                                         SND_SOC_BIAS_OFF) {
344                         /* power on */
345                         ret = regulator_enable(st->iovdd);
346                         if (ret)
347                                 return ret;
348 
349                         /* there's no timing constraints before enabling dvdd */
350                         ret = regulator_enable(st->dvdd);
351                         if (ret) {
352                                 regulator_disable(st->iovdd);
353                                 return ret;
354                         }
355 
356                         if (st->hw_mode)
357                                 return 0;
358 
359                         regcache_cache_only(st->map, false);
360                         /* sync cache */
361                         ret = snd_soc_component_cache_sync(component);
362                 }
363                 break;
364         case SND_SOC_BIAS_OFF:
365                 /* power off */
366                 ret = regulator_disable(st->dvdd);
367                 if (ret)
368                         return ret;
369 
370                 ret = regulator_disable(st->iovdd);
371                 if (ret)
372                         return ret;
373 
374                 if (st->hw_mode)
375                         return 0;
376 
377                 /* cache only */
378                 regcache_mark_dirty(st->map);
379                 regcache_cache_only(st->map, true);
380 
381                 break;
382         }
383 
384         return ret;
385 }
386 
387 static int adau7118_component_probe(struct snd_soc_component *component)
388 {
389         struct adau7118_data *st = snd_soc_component_get_drvdata(component);
390         struct snd_soc_dapm_context *dapm =
391                                         snd_soc_component_get_dapm(component);
392         int ret = 0;
393 
394         if (st->hw_mode) {
395                 ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,
396                                         ARRAY_SIZE(adau7118_widgets_hw));
397                 if (ret)
398                         return ret;
399 
400                 ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,
401                                               ARRAY_SIZE(adau7118_routes_hw));
402         } else {
403                 snd_soc_component_init_regmap(component, st->map);
404                 ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,
405                                         ARRAY_SIZE(adau7118_widgets_sw));
406                 if (ret)
407                         return ret;
408 
409                 ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,
410                                               ARRAY_SIZE(adau7118_routes_sw));
411         }
412 
413         return ret;
414 }
415 
416 static const struct snd_soc_dai_ops adau7118_ops = {
417         .hw_params = adau7118_hw_params,
418         .set_channel_map = adau7118_set_channel_map,
419         .set_fmt = adau7118_set_fmt,
420         .set_tdm_slot = adau7118_set_tdm_slot,
421         .set_tristate = adau7118_set_tristate,
422 };
423 
424 static struct snd_soc_dai_driver adau7118_dai = {
425         .name = "adau7118-hifi-capture",
426         .capture = {
427                 .stream_name = "Capture",
428                 .channels_min = 1,
429                 .channels_max = 8,
430                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
431                         SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
432                         SNDRV_PCM_FMTBIT_S24_3LE,
433                 .rates = SNDRV_PCM_RATE_CONTINUOUS,
434                 .rate_min = 4000,
435                 .rate_max = 192000,
436                 .sig_bits = 24,
437         },
438 };
439 
440 static const struct snd_soc_component_driver adau7118_component_driver = {
441         .probe                  = adau7118_component_probe,
442         .set_bias_level         = adau7118_set_bias_level,
443         .dapm_widgets           = adau7118_widgets,
444         .num_dapm_widgets       = ARRAY_SIZE(adau7118_widgets),
445         .use_pmdown_time        = 1,
446         .endianness             = 1,
447 };
448 
449 static int adau7118_regulator_setup(struct adau7118_data *st)
450 {
451         st->iovdd = devm_regulator_get(st->dev, "iovdd");
452         if (IS_ERR(st->iovdd)) {
453                 dev_err(st->dev, "Could not get iovdd: %ld\n",
454                         PTR_ERR(st->iovdd));
455                 return PTR_ERR(st->iovdd);
456         }
457 
458         st->dvdd = devm_regulator_get(st->dev, "dvdd");
459         if (IS_ERR(st->dvdd)) {
460                 dev_err(st->dev, "Could not get dvdd: %ld\n",
461                         PTR_ERR(st->dvdd));
462                 return PTR_ERR(st->dvdd);
463         }
464         /* just assume the device is in reset */
465         if (!st->hw_mode) {
466                 regcache_mark_dirty(st->map);
467                 regcache_cache_only(st->map, true);
468         }
469 
470         return 0;
471 }
472 
473 static int adau7118_parset_dt(const struct adau7118_data *st)
474 {
475         int ret;
476         u32 dec_ratio = 0;
477         /* 4 inputs */
478         u32 clk_map[4], regval;
479 
480         if (st->hw_mode)
481                 return 0;
482 
483         ret = device_property_read_u32(st->dev, "adi,decimation-ratio",
484                                        &dec_ratio);
485         if (!ret) {
486                 switch (dec_ratio) {
487                 case 64:
488                         regval = ADAU7118_DEC_RATIO(0);
489                         break;
490                 case 32:
491                         regval = ADAU7118_DEC_RATIO(1);
492                         break;
493                 case 16:
494                         regval = ADAU7118_DEC_RATIO(2);
495                         break;
496                 default:
497                         dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);
498                         return -EINVAL;
499                 }
500 
501                 ret = regmap_update_bits(st->map,
502                                          ADAU7118_REG_DEC_RATIO_CLK_MAP,
503                                          ADAU7118_DEC_RATIO_MASK, regval);
504                 if (ret)
505                         return ret;
506         }
507 
508         ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",
509                                              clk_map, ARRAY_SIZE(clk_map));
510         if (!ret) {
511                 int pdm;
512                 u32 _clk_map = 0;
513 
514                 for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)
515                         _clk_map |= (clk_map[pdm] << (pdm + 4));
516 
517                 ret = regmap_update_bits(st->map,
518                                          ADAU7118_REG_DEC_RATIO_CLK_MAP,
519                                          ADAU7118_CLK_MAP_MASK, _clk_map);
520                 if (ret)
521                         return ret;
522         }
523 
524         return 0;
525 }
526 
527 int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)
528 {
529         struct adau7118_data *st;
530         int ret;
531 
532         st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
533         if (!st)
534                 return -ENOMEM;
535 
536         st->dev = dev;
537         st->hw_mode = hw_mode;
538         dev_set_drvdata(dev, st);
539 
540         if (!hw_mode) {
541                 st->map = map;
542                 adau7118_dai.ops = &adau7118_ops;
543                 /*
544                  * Perform a full soft reset. This will set all register's
545                  * with their reset values.
546                  */
547                 ret = regmap_update_bits(map, ADAU7118_REG_RESET,
548                                          ADAU7118_FULL_SOFT_R_MASK,
549                                          ADAU7118_FULL_SOFT_R(1));
550                 if (ret)
551                         return ret;
552         }
553 
554         ret = adau7118_parset_dt(st);
555         if (ret)
556                 return ret;
557 
558         ret = adau7118_regulator_setup(st);
559         if (ret)
560                 return ret;
561 
562         return devm_snd_soc_register_component(dev,
563                                                &adau7118_component_driver,
564                                                &adau7118_dai, 1);
565 }
566 EXPORT_SYMBOL_GPL(adau7118_probe);
567 
568 MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
569 MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
570 MODULE_LICENSE("GPL");
571 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php