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

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

Version: ~ [ linux-5.14-rc1 ] ~ [ linux-5.13.1 ] ~ [ linux-5.12.16 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.49 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.131 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.197 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.239 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.275 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.275 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ 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.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 //
  3 // ak4613.c  --  Asahi Kasei ALSA Soc Audio driver
  4 //
  5 // Copyright (C) 2015 Renesas Electronics Corporation
  6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  7 //
  8 // Based on ak4642.c by Kuninori Morimoto
  9 // Based on wm8731.c by Richard Purdie
 10 // Based on ak4535.c by Richard Purdie
 11 // Based on wm8753.c by Liam Girdwood
 12 
 13 #include <linux/clk.h>
 14 #include <linux/delay.h>
 15 #include <linux/i2c.h>
 16 #include <linux/slab.h>
 17 #include <linux/of_device.h>
 18 #include <linux/module.h>
 19 #include <linux/regmap.h>
 20 #include <sound/soc.h>
 21 #include <sound/pcm_params.h>
 22 #include <sound/tlv.h>
 23 
 24 #define PW_MGMT1        0x00 /* Power Management 1 */
 25 #define PW_MGMT2        0x01 /* Power Management 2 */
 26 #define PW_MGMT3        0x02 /* Power Management 3 */
 27 #define CTRL1           0x03 /* Control 1 */
 28 #define CTRL2           0x04 /* Control 2 */
 29 #define DEMP1           0x05 /* De-emphasis1 */
 30 #define DEMP2           0x06 /* De-emphasis2 */
 31 #define OFD             0x07 /* Overflow Detect */
 32 #define ZRD             0x08 /* Zero Detect */
 33 #define ICTRL           0x09 /* Input Control */
 34 #define OCTRL           0x0a /* Output Control */
 35 #define LOUT1           0x0b /* LOUT1 Volume Control */
 36 #define ROUT1           0x0c /* ROUT1 Volume Control */
 37 #define LOUT2           0x0d /* LOUT2 Volume Control */
 38 #define ROUT2           0x0e /* ROUT2 Volume Control */
 39 #define LOUT3           0x0f /* LOUT3 Volume Control */
 40 #define ROUT3           0x10 /* ROUT3 Volume Control */
 41 #define LOUT4           0x11 /* LOUT4 Volume Control */
 42 #define ROUT4           0x12 /* ROUT4 Volume Control */
 43 #define LOUT5           0x13 /* LOUT5 Volume Control */
 44 #define ROUT5           0x14 /* ROUT5 Volume Control */
 45 #define LOUT6           0x15 /* LOUT6 Volume Control */
 46 #define ROUT6           0x16 /* ROUT6 Volume Control */
 47 
 48 /* PW_MGMT1 */
 49 #define RSTN            BIT(0)
 50 #define PMDAC           BIT(1)
 51 #define PMADC           BIT(2)
 52 #define PMVR            BIT(3)
 53 
 54 /* PW_MGMT2 */
 55 #define PMAD_ALL        0x7
 56 
 57 /* PW_MGMT3 */
 58 #define PMDA_ALL        0x3f
 59 
 60 /* CTRL1 */
 61 #define DIF0            BIT(3)
 62 #define DIF1            BIT(4)
 63 #define DIF2            BIT(5)
 64 #define TDM0            BIT(6)
 65 #define TDM1            BIT(7)
 66 #define NO_FMT          (0xff)
 67 #define FMT_MASK        (0xf8)
 68 
 69 /* CTRL2 */
 70 #define DFS_MASK                (3 << 2)
 71 #define DFS_NORMAL_SPEED        (0 << 2)
 72 #define DFS_DOUBLE_SPEED        (1 << 2)
 73 #define DFS_QUAD_SPEED          (2 << 2)
 74 
 75 /* ICTRL */
 76 #define ICTRL_MASK      (0x3)
 77 
 78 /* OCTRL */
 79 #define OCTRL_MASK      (0x3F)
 80 
 81 struct ak4613_formats {
 82         unsigned int width;
 83         unsigned int fmt;
 84 };
 85 
 86 struct ak4613_interface {
 87         struct ak4613_formats capture;
 88         struct ak4613_formats playback;
 89 };
 90 
 91 struct ak4613_priv {
 92         struct mutex lock;
 93         const struct ak4613_interface *iface;
 94         struct snd_pcm_hw_constraint_list constraint;
 95         struct work_struct dummy_write_work;
 96         struct snd_soc_component *component;
 97         unsigned int rate;
 98         unsigned int sysclk;
 99 
100         unsigned int fmt;
101         u8 oc;
102         u8 ic;
103         int cnt;
104 };
105 
106 /*
107  * Playback Volume
108  *
109  * max : 0x00 : 0 dB
110  *       ( 0.5 dB step )
111  * min : 0xFE : -127.0 dB
112  * mute: 0xFF
113  */
114 static const DECLARE_TLV_DB_SCALE(out_tlv, -12750, 50, 1);
115 
116 static const struct snd_kcontrol_new ak4613_snd_controls[] = {
117         SOC_DOUBLE_R_TLV("Digital Playback Volume1", LOUT1, ROUT1,
118                          0, 0xFF, 1, out_tlv),
119         SOC_DOUBLE_R_TLV("Digital Playback Volume2", LOUT2, ROUT2,
120                          0, 0xFF, 1, out_tlv),
121         SOC_DOUBLE_R_TLV("Digital Playback Volume3", LOUT3, ROUT3,
122                          0, 0xFF, 1, out_tlv),
123         SOC_DOUBLE_R_TLV("Digital Playback Volume4", LOUT4, ROUT4,
124                          0, 0xFF, 1, out_tlv),
125         SOC_DOUBLE_R_TLV("Digital Playback Volume5", LOUT5, ROUT5,
126                          0, 0xFF, 1, out_tlv),
127         SOC_DOUBLE_R_TLV("Digital Playback Volume6", LOUT6, ROUT6,
128                          0, 0xFF, 1, out_tlv),
129 };
130 
131 static const struct reg_default ak4613_reg[] = {
132         { 0x0,  0x0f }, { 0x1,  0x07 }, { 0x2,  0x3f }, { 0x3,  0x20 },
133         { 0x4,  0x20 }, { 0x5,  0x55 }, { 0x6,  0x05 }, { 0x7,  0x07 },
134         { 0x8,  0x0f }, { 0x9,  0x07 }, { 0xa,  0x3f }, { 0xb,  0x00 },
135         { 0xc,  0x00 }, { 0xd,  0x00 }, { 0xe,  0x00 }, { 0xf,  0x00 },
136         { 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, { 0x13, 0x00 },
137         { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
138 };
139 
140 #define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3)
141 #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
142 static const struct ak4613_interface ak4613_iface[] = {
143         /* capture */                           /* playback */
144         /* [0] - [2] are not supported */
145         [3] = { AUDIO_IFACE(24, LEFT_J),        AUDIO_IFACE(24, LEFT_J) },
146         [4] = { AUDIO_IFACE(24, I2S),           AUDIO_IFACE(24, I2S) },
147 };
148 
149 static const struct regmap_config ak4613_regmap_cfg = {
150         .reg_bits               = 8,
151         .val_bits               = 8,
152         .max_register           = 0x16,
153         .reg_defaults           = ak4613_reg,
154         .num_reg_defaults       = ARRAY_SIZE(ak4613_reg),
155         .cache_type             = REGCACHE_RBTREE,
156 };
157 
158 static const struct of_device_id ak4613_of_match[] = {
159         { .compatible = "asahi-kasei,ak4613",   .data = &ak4613_regmap_cfg },
160         {},
161 };
162 MODULE_DEVICE_TABLE(of, ak4613_of_match);
163 
164 static const struct i2c_device_id ak4613_i2c_id[] = {
165         { "ak4613", (kernel_ulong_t)&ak4613_regmap_cfg },
166         { }
167 };
168 MODULE_DEVICE_TABLE(i2c, ak4613_i2c_id);
169 
170 static const struct snd_soc_dapm_widget ak4613_dapm_widgets[] = {
171 
172         /* Outputs */
173         SND_SOC_DAPM_OUTPUT("LOUT1"),
174         SND_SOC_DAPM_OUTPUT("LOUT2"),
175         SND_SOC_DAPM_OUTPUT("LOUT3"),
176         SND_SOC_DAPM_OUTPUT("LOUT4"),
177         SND_SOC_DAPM_OUTPUT("LOUT5"),
178         SND_SOC_DAPM_OUTPUT("LOUT6"),
179 
180         SND_SOC_DAPM_OUTPUT("ROUT1"),
181         SND_SOC_DAPM_OUTPUT("ROUT2"),
182         SND_SOC_DAPM_OUTPUT("ROUT3"),
183         SND_SOC_DAPM_OUTPUT("ROUT4"),
184         SND_SOC_DAPM_OUTPUT("ROUT5"),
185         SND_SOC_DAPM_OUTPUT("ROUT6"),
186 
187         /* Inputs */
188         SND_SOC_DAPM_INPUT("LIN1"),
189         SND_SOC_DAPM_INPUT("LIN2"),
190 
191         SND_SOC_DAPM_INPUT("RIN1"),
192         SND_SOC_DAPM_INPUT("RIN2"),
193 
194         /* DAC */
195         SND_SOC_DAPM_DAC("DAC1", NULL, PW_MGMT3, 0, 0),
196         SND_SOC_DAPM_DAC("DAC2", NULL, PW_MGMT3, 1, 0),
197         SND_SOC_DAPM_DAC("DAC3", NULL, PW_MGMT3, 2, 0),
198         SND_SOC_DAPM_DAC("DAC4", NULL, PW_MGMT3, 3, 0),
199         SND_SOC_DAPM_DAC("DAC5", NULL, PW_MGMT3, 4, 0),
200         SND_SOC_DAPM_DAC("DAC6", NULL, PW_MGMT3, 5, 0),
201 
202         /* ADC */
203         SND_SOC_DAPM_ADC("ADC1", NULL, PW_MGMT2, 0, 0),
204         SND_SOC_DAPM_ADC("ADC2", NULL, PW_MGMT2, 1, 0),
205 };
206 
207 static const struct snd_soc_dapm_route ak4613_intercon[] = {
208         {"LOUT1", NULL, "DAC1"},
209         {"LOUT2", NULL, "DAC2"},
210         {"LOUT3", NULL, "DAC3"},
211         {"LOUT4", NULL, "DAC4"},
212         {"LOUT5", NULL, "DAC5"},
213         {"LOUT6", NULL, "DAC6"},
214 
215         {"ROUT1", NULL, "DAC1"},
216         {"ROUT2", NULL, "DAC2"},
217         {"ROUT3", NULL, "DAC3"},
218         {"ROUT4", NULL, "DAC4"},
219         {"ROUT5", NULL, "DAC5"},
220         {"ROUT6", NULL, "DAC6"},
221 
222         {"DAC1", NULL, "Playback"},
223         {"DAC2", NULL, "Playback"},
224         {"DAC3", NULL, "Playback"},
225         {"DAC4", NULL, "Playback"},
226         {"DAC5", NULL, "Playback"},
227         {"DAC6", NULL, "Playback"},
228 
229         {"Capture", NULL, "ADC1"},
230         {"Capture", NULL, "ADC2"},
231 
232         {"ADC1", NULL, "LIN1"},
233         {"ADC2", NULL, "LIN2"},
234 
235         {"ADC1", NULL, "RIN1"},
236         {"ADC2", NULL, "RIN2"},
237 };
238 
239 static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
240                                struct snd_soc_dai *dai)
241 {
242         struct snd_soc_component *component = dai->component;
243         struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
244         struct device *dev = component->dev;
245 
246         mutex_lock(&priv->lock);
247         priv->cnt--;
248         if (priv->cnt < 0) {
249                 dev_err(dev, "unexpected counter error\n");
250                 priv->cnt = 0;
251         }
252         if (!priv->cnt)
253                 priv->iface = NULL;
254         mutex_unlock(&priv->lock);
255 }
256 
257 static void ak4613_hw_constraints(struct ak4613_priv *priv,
258                                   struct snd_pcm_runtime *runtime)
259 {
260         static const unsigned int ak4613_rates[] = {
261                  32000,
262                  44100,
263                  48000,
264                  64000,
265                  88200,
266                  96000,
267                 176400,
268                 192000,
269         };
270         struct snd_pcm_hw_constraint_list *constraint = &priv->constraint;
271         unsigned int fs;
272         int i;
273 
274         constraint->list        = ak4613_rates;
275         constraint->mask        = 0;
276         constraint->count       = 0;
277 
278         /*
279          * Slave Mode
280          *      Normal: [32kHz, 48kHz] : 256fs,384fs or 512fs
281          *      Double: [64kHz, 96kHz] : 256fs
282          *      Quad  : [128kHz,192kHz]: 128fs
283          *
284          * Master mode
285          *      Normal: [32kHz, 48kHz] : 256fs or 512fs
286          *      Double: [64kHz, 96kHz] : 256fs
287          *      Quad  : [128kHz,192kHz]: 128fs
288         */
289         for (i = 0; i < ARRAY_SIZE(ak4613_rates); i++) {
290                 /* minimum fs on each range */
291                 fs = (ak4613_rates[i] <= 96000) ? 256 : 128;
292 
293                 if (priv->sysclk >= ak4613_rates[i] * fs)
294                         constraint->count = i + 1;
295         }
296 
297         snd_pcm_hw_constraint_list(runtime, 0,
298                                 SNDRV_PCM_HW_PARAM_RATE, constraint);
299 }
300 
301 static int ak4613_dai_startup(struct snd_pcm_substream *substream,
302                               struct snd_soc_dai *dai)
303 {
304         struct snd_soc_component *component = dai->component;
305         struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
306 
307         priv->cnt++;
308 
309         ak4613_hw_constraints(priv, substream->runtime);
310 
311         return 0;
312 }
313 
314 static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai,
315                                  int clk_id, unsigned int freq, int dir)
316 {
317         struct snd_soc_component *component = codec_dai->component;
318         struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
319 
320         priv->sysclk = freq;
321 
322         return 0;
323 }
324 
325 static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
326 {
327         struct snd_soc_component *component = dai->component;
328         struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
329 
330         fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
331 
332         switch (fmt) {
333         case SND_SOC_DAIFMT_LEFT_J:
334         case SND_SOC_DAIFMT_I2S:
335                 priv->fmt = fmt;
336                 break;
337         default:
338                 return -EINVAL;
339         }
340 
341         return 0;
342 }
343 
344 static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
345                                     int is_play,
346                                     unsigned int fmt, unsigned int width)
347 {
348         const struct ak4613_formats *fmts;
349 
350         fmts = (is_play) ? &iface->playback : &iface->capture;
351 
352         if (fmts->fmt != fmt)
353                 return false;
354 
355         if (fmts->width != width)
356                 return false;
357 
358         return true;
359 }
360 
361 static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
362                                 struct snd_pcm_hw_params *params,
363                                 struct snd_soc_dai *dai)
364 {
365         struct snd_soc_component *component = dai->component;
366         struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
367         const struct ak4613_interface *iface;
368         struct device *dev = component->dev;
369         unsigned int width = params_width(params);
370         unsigned int fmt = priv->fmt;
371         unsigned int rate;
372         int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
373         int i, ret;
374         u8 fmt_ctrl, ctrl2;
375 
376         rate = params_rate(params);
377         switch (rate) {
378         case 32000:
379         case 44100:
380         case 48000:
381                 ctrl2 = DFS_NORMAL_SPEED;
382                 break;
383         case 64000:
384         case 88200:
385         case 96000:
386                 ctrl2 = DFS_DOUBLE_SPEED;
387                 break;
388         case 176400:
389         case 192000:
390                 ctrl2 = DFS_QUAD_SPEED;
391                 break;
392         default:
393                 return -EINVAL;
394         }
395         priv->rate = rate;
396 
397         /*
398          * FIXME
399          *
400          * It doesn't support TDM at this point
401          */
402         fmt_ctrl = NO_FMT;
403         ret = -EINVAL;
404         iface = NULL;
405 
406         mutex_lock(&priv->lock);
407         if (priv->iface) {
408                 if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width))
409                         iface = priv->iface;
410         } else {
411                 for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
412                         if (!ak4613_dai_fmt_matching(ak4613_iface + i,
413                                                      is_play,
414                                                      fmt, width))
415                                 continue;
416                         iface = ak4613_iface + i;
417                         break;
418                 }
419         }
420 
421         if ((priv->iface == NULL) ||
422             (priv->iface == iface)) {
423                 priv->iface = iface;
424                 ret = 0;
425         }
426         mutex_unlock(&priv->lock);
427 
428         if (ret < 0)
429                 goto hw_params_end;
430 
431         fmt_ctrl = AUDIO_IFACE_TO_VAL(iface);
432 
433         snd_soc_component_update_bits(component, CTRL1, FMT_MASK, fmt_ctrl);
434         snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2);
435 
436         snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic);
437         snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc);
438 
439 hw_params_end:
440         if (ret < 0)
441                 dev_warn(dev, "unsupported data width/format combination\n");
442 
443         return ret;
444 }
445 
446 static int ak4613_set_bias_level(struct snd_soc_component *component,
447                                  enum snd_soc_bias_level level)
448 {
449         u8 mgmt1 = 0;
450 
451         switch (level) {
452         case SND_SOC_BIAS_ON:
453                 mgmt1 |= RSTN;
454                 /* fall through */
455         case SND_SOC_BIAS_PREPARE:
456                 mgmt1 |= PMADC | PMDAC;
457                 /* fall through */
458         case SND_SOC_BIAS_STANDBY:
459                 mgmt1 |= PMVR;
460                 /* fall through */
461         case SND_SOC_BIAS_OFF:
462         default:
463                 break;
464         }
465 
466         snd_soc_component_write(component, PW_MGMT1, mgmt1);
467 
468         return 0;
469 }
470 
471 static void ak4613_dummy_write(struct work_struct *work)
472 {
473         struct ak4613_priv *priv = container_of(work,
474                                                 struct ak4613_priv,
475                                                 dummy_write_work);
476         struct snd_soc_component *component = priv->component;
477         unsigned int mgmt1;
478         unsigned int mgmt3;
479 
480         /*
481          * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
482          *
483          * Note
484          *
485          * To avoid extra delay, we want to avoid preemption here,
486          * but we can't. Because it uses I2C access which is using IRQ
487          * and sleep. Thus, delay might be more than 5 LR clocks
488          * see also
489          *      ak4613_dai_trigger()
490          */
491         udelay(5000000 / priv->rate);
492 
493         snd_soc_component_read(component, PW_MGMT1, &mgmt1);
494         snd_soc_component_read(component, PW_MGMT3, &mgmt3);
495 
496         snd_soc_component_write(component, PW_MGMT1, mgmt1);
497         snd_soc_component_write(component, PW_MGMT3, mgmt3);
498 }
499 
500 static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
501                               struct snd_soc_dai *dai)
502 {
503         struct snd_soc_component *component = dai->component;
504         struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
505 
506         /*
507          * FIXME
508          *
509          * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
510          * from Power Down Release. Otherwise, Playback volume will be 0dB.
511          * To avoid complex multiple delay/dummy_write method from
512          * ak4613_set_bias_level() / SND_SOC_DAPM_DAC_E("DACx", ...),
513          * call it once here.
514          *
515          * But, unfortunately, we can't "write" here because here is atomic
516          * context (It uses I2C access for writing).
517          * Thus, use schedule_work() to switching to normal context
518          * immediately.
519          *
520          * Note
521          *
522          * Calling ak4613_dummy_write() function might be delayed.
523          * In such case, ak4613 volume might be temporarily 0dB when
524          * beggining of playback.
525          * see also
526          *      ak4613_dummy_write()
527          */
528 
529         if ((cmd != SNDRV_PCM_TRIGGER_START) &&
530             (cmd != SNDRV_PCM_TRIGGER_RESUME))
531                 return 0;
532 
533         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
534                 return  0;
535 
536         priv->component = component;
537         schedule_work(&priv->dummy_write_work);
538 
539         return 0;
540 }
541 
542 static const struct snd_soc_dai_ops ak4613_dai_ops = {
543         .startup        = ak4613_dai_startup,
544         .shutdown       = ak4613_dai_shutdown,
545         .set_sysclk     = ak4613_dai_set_sysclk,
546         .set_fmt        = ak4613_dai_set_fmt,
547         .trigger        = ak4613_dai_trigger,
548         .hw_params      = ak4613_dai_hw_params,
549 };
550 
551 #define AK4613_PCM_RATE         (SNDRV_PCM_RATE_32000  |\
552                                  SNDRV_PCM_RATE_44100  |\
553                                  SNDRV_PCM_RATE_48000  |\
554                                  SNDRV_PCM_RATE_64000  |\
555                                  SNDRV_PCM_RATE_88200  |\
556                                  SNDRV_PCM_RATE_96000  |\
557                                  SNDRV_PCM_RATE_176400 |\
558                                  SNDRV_PCM_RATE_192000)
559 #define AK4613_PCM_FMTBIT       (SNDRV_PCM_FMTBIT_S24_LE)
560 
561 static struct snd_soc_dai_driver ak4613_dai = {
562         .name = "ak4613-hifi",
563         .playback = {
564                 .stream_name    = "Playback",
565                 .channels_min   = 2,
566                 .channels_max   = 2,
567                 .rates          = AK4613_PCM_RATE,
568                 .formats        = AK4613_PCM_FMTBIT,
569         },
570         .capture = {
571                 .stream_name    = "Capture",
572                 .channels_min   = 2,
573                 .channels_max   = 2,
574                 .rates          = AK4613_PCM_RATE,
575                 .formats        = AK4613_PCM_FMTBIT,
576         },
577         .ops = &ak4613_dai_ops,
578         .symmetric_rates = 1,
579 };
580 
581 static int ak4613_suspend(struct snd_soc_component *component)
582 {
583         struct regmap *regmap = dev_get_regmap(component->dev, NULL);
584 
585         regcache_cache_only(regmap, true);
586         regcache_mark_dirty(regmap);
587         return 0;
588 }
589 
590 static int ak4613_resume(struct snd_soc_component *component)
591 {
592         struct regmap *regmap = dev_get_regmap(component->dev, NULL);
593 
594         regcache_cache_only(regmap, false);
595         return regcache_sync(regmap);
596 }
597 
598 static const struct snd_soc_component_driver soc_component_dev_ak4613 = {
599         .suspend                = ak4613_suspend,
600         .resume                 = ak4613_resume,
601         .set_bias_level         = ak4613_set_bias_level,
602         .controls               = ak4613_snd_controls,
603         .num_controls           = ARRAY_SIZE(ak4613_snd_controls),
604         .dapm_widgets           = ak4613_dapm_widgets,
605         .num_dapm_widgets       = ARRAY_SIZE(ak4613_dapm_widgets),
606         .dapm_routes            = ak4613_intercon,
607         .num_dapm_routes        = ARRAY_SIZE(ak4613_intercon),
608         .idle_bias_on           = 1,
609         .endianness             = 1,
610         .non_legacy_dai_naming  = 1,
611 };
612 
613 static void ak4613_parse_of(struct ak4613_priv *priv,
614                             struct device *dev)
615 {
616         struct device_node *np = dev->of_node;
617         char prop[32];
618         int i;
619 
620         /* Input 1 - 2 */
621         for (i = 0; i < 2; i++) {
622                 snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
623                 if (!of_get_property(np, prop, NULL))
624                         priv->ic |= 1 << i;
625         }
626 
627         /* Output 1 - 6 */
628         for (i = 0; i < 6; i++) {
629                 snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
630                 if (!of_get_property(np, prop, NULL))
631                         priv->oc |= 1 << i;
632         }
633 }
634 
635 static int ak4613_i2c_probe(struct i2c_client *i2c,
636                             const struct i2c_device_id *id)
637 {
638         struct device *dev = &i2c->dev;
639         struct device_node *np = dev->of_node;
640         const struct regmap_config *regmap_cfg;
641         struct regmap *regmap;
642         struct ak4613_priv *priv;
643 
644         regmap_cfg = NULL;
645         if (np) {
646                 const struct of_device_id *of_id;
647 
648                 of_id = of_match_device(ak4613_of_match, dev);
649                 if (of_id)
650                         regmap_cfg = of_id->data;
651         } else {
652                 regmap_cfg = (const struct regmap_config *)id->driver_data;
653         }
654 
655         if (!regmap_cfg)
656                 return -EINVAL;
657 
658         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
659         if (!priv)
660                 return -ENOMEM;
661 
662         ak4613_parse_of(priv, dev);
663 
664         priv->iface             = NULL;
665         priv->cnt               = 0;
666         priv->sysclk            = 0;
667         INIT_WORK(&priv->dummy_write_work, ak4613_dummy_write);
668 
669         mutex_init(&priv->lock);
670 
671         i2c_set_clientdata(i2c, priv);
672 
673         regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
674         if (IS_ERR(regmap))
675                 return PTR_ERR(regmap);
676 
677         return devm_snd_soc_register_component(dev, &soc_component_dev_ak4613,
678                                       &ak4613_dai, 1);
679 }
680 
681 static int ak4613_i2c_remove(struct i2c_client *client)
682 {
683         return 0;
684 }
685 
686 static struct i2c_driver ak4613_i2c_driver = {
687         .driver = {
688                 .name = "ak4613-codec",
689                 .of_match_table = ak4613_of_match,
690         },
691         .probe          = ak4613_i2c_probe,
692         .remove         = ak4613_i2c_remove,
693         .id_table       = ak4613_i2c_id,
694 };
695 
696 module_i2c_driver(ak4613_i2c_driver);
697 
698 MODULE_DESCRIPTION("Soc AK4613 driver");
699 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
700 MODULE_LICENSE("GPL v2");
701 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp