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

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

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

~ [ 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