9
9
10
10
#include <linux/module.h>
11
11
#include <linux/init.h>
12
+ #include <linux/clk.h>
12
13
#include <linux/delay.h>
13
14
#include <linux/slab.h>
14
15
#include <sound/core.h>
@@ -303,6 +304,116 @@ bool adau17x1_has_dsp(struct adau *adau)
303
304
}
304
305
EXPORT_SYMBOL_GPL (adau17x1_has_dsp );
305
306
307
+ static int adau17x1_set_dai_pll (struct snd_soc_dai * dai , int pll_id ,
308
+ int source , unsigned int freq_in , unsigned int freq_out )
309
+ {
310
+ struct snd_soc_codec * codec = dai -> codec ;
311
+ struct adau * adau = snd_soc_codec_get_drvdata (codec );
312
+ int ret ;
313
+
314
+ if (freq_in < 8000000 || freq_in > 27000000 )
315
+ return - EINVAL ;
316
+
317
+ ret = adau_calc_pll_cfg (freq_in , freq_out , adau -> pll_regs );
318
+ if (ret < 0 )
319
+ return ret ;
320
+
321
+ /* The PLL register is 6 bytes long and can only be written at once. */
322
+ ret = regmap_raw_write (adau -> regmap , ADAU17X1_PLL_CONTROL ,
323
+ adau -> pll_regs , ARRAY_SIZE (adau -> pll_regs ));
324
+ if (ret )
325
+ return ret ;
326
+
327
+ adau -> pll_freq = freq_out ;
328
+
329
+ return 0 ;
330
+ }
331
+
332
+ static int adau17x1_set_dai_sysclk (struct snd_soc_dai * dai ,
333
+ int clk_id , unsigned int freq , int dir )
334
+ {
335
+ struct snd_soc_dapm_context * dapm = snd_soc_codec_get_dapm (dai -> codec );
336
+ struct adau * adau = snd_soc_codec_get_drvdata (dai -> codec );
337
+ bool is_pll ;
338
+ bool was_pll ;
339
+
340
+ switch (clk_id ) {
341
+ case ADAU17X1_CLK_SRC_MCLK :
342
+ is_pll = false;
343
+ break ;
344
+ case ADAU17X1_CLK_SRC_PLL_AUTO :
345
+ if (!adau -> mclk )
346
+ return - EINVAL ;
347
+ /* Fall-through */
348
+ case ADAU17X1_CLK_SRC_PLL :
349
+ is_pll = true;
350
+ break ;
351
+ default :
352
+ return - EINVAL ;
353
+ }
354
+
355
+ switch (adau -> clk_src ) {
356
+ case ADAU17X1_CLK_SRC_MCLK :
357
+ was_pll = false;
358
+ break ;
359
+ case ADAU17X1_CLK_SRC_PLL :
360
+ case ADAU17X1_CLK_SRC_PLL_AUTO :
361
+ was_pll = true;
362
+ break ;
363
+ default :
364
+ return - EINVAL ;
365
+ }
366
+
367
+ adau -> sysclk = freq ;
368
+
369
+ if (is_pll != was_pll ) {
370
+ if (is_pll ) {
371
+ snd_soc_dapm_add_routes (dapm ,
372
+ & adau17x1_dapm_pll_route , 1 );
373
+ } else {
374
+ snd_soc_dapm_del_routes (dapm ,
375
+ & adau17x1_dapm_pll_route , 1 );
376
+ }
377
+ }
378
+
379
+ adau -> clk_src = clk_id ;
380
+
381
+ return 0 ;
382
+ }
383
+
384
+ static int adau17x1_auto_pll (struct snd_soc_dai * dai ,
385
+ struct snd_pcm_hw_params * params )
386
+ {
387
+ struct adau * adau = snd_soc_dai_get_drvdata (dai );
388
+ unsigned int pll_rate ;
389
+
390
+ switch (params_rate (params )) {
391
+ case 48000 :
392
+ case 8000 :
393
+ case 12000 :
394
+ case 16000 :
395
+ case 24000 :
396
+ case 32000 :
397
+ case 96000 :
398
+ pll_rate = 48000 * 1024 ;
399
+ break ;
400
+ case 44100 :
401
+ case 7350 :
402
+ case 11025 :
403
+ case 14700 :
404
+ case 22050 :
405
+ case 29400 :
406
+ case 88200 :
407
+ pll_rate = 44100 * 1024 ;
408
+ break ;
409
+ default :
410
+ return - EINVAL ;
411
+ }
412
+
413
+ return adau17x1_set_dai_pll (dai , ADAU17X1_PLL , ADAU17X1_PLL_SRC_MCLK ,
414
+ clk_get_rate (adau -> mclk ), pll_rate );
415
+ }
416
+
306
417
static int adau17x1_hw_params (struct snd_pcm_substream * substream ,
307
418
struct snd_pcm_hw_params * params , struct snd_soc_dai * dai )
308
419
{
@@ -312,10 +423,19 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
312
423
unsigned int freq ;
313
424
int ret ;
314
425
315
- if (adau -> clk_src == ADAU17X1_CLK_SRC_PLL )
426
+ switch (adau -> clk_src ) {
427
+ case ADAU17X1_CLK_SRC_PLL_AUTO :
428
+ ret = adau17x1_auto_pll (dai , params );
429
+ if (ret )
430
+ return ret ;
431
+ /* Fall-through */
432
+ case ADAU17X1_CLK_SRC_PLL :
316
433
freq = adau -> pll_freq ;
317
- else
434
+ break ;
435
+ default :
318
436
freq = adau -> sysclk ;
437
+ break ;
438
+ }
319
439
320
440
if (freq % params_rate (params ) != 0 )
321
441
return - EINVAL ;
@@ -387,62 +507,6 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
387
507
ADAU17X1_SERIAL_PORT1_DELAY_MASK , val );
388
508
}
389
509
390
- static int adau17x1_set_dai_pll (struct snd_soc_dai * dai , int pll_id ,
391
- int source , unsigned int freq_in , unsigned int freq_out )
392
- {
393
- struct snd_soc_codec * codec = dai -> codec ;
394
- struct adau * adau = snd_soc_codec_get_drvdata (codec );
395
- int ret ;
396
-
397
- if (freq_in < 8000000 || freq_in > 27000000 )
398
- return - EINVAL ;
399
-
400
- ret = adau_calc_pll_cfg (freq_in , freq_out , adau -> pll_regs );
401
- if (ret < 0 )
402
- return ret ;
403
-
404
- /* The PLL register is 6 bytes long and can only be written at once. */
405
- ret = regmap_raw_write (adau -> regmap , ADAU17X1_PLL_CONTROL ,
406
- adau -> pll_regs , ARRAY_SIZE (adau -> pll_regs ));
407
- if (ret )
408
- return ret ;
409
-
410
- adau -> pll_freq = freq_out ;
411
-
412
- return 0 ;
413
- }
414
-
415
- static int adau17x1_set_dai_sysclk (struct snd_soc_dai * dai ,
416
- int clk_id , unsigned int freq , int dir )
417
- {
418
- struct snd_soc_dapm_context * dapm = snd_soc_codec_get_dapm (dai -> codec );
419
- struct adau * adau = snd_soc_codec_get_drvdata (dai -> codec );
420
-
421
- switch (clk_id ) {
422
- case ADAU17X1_CLK_SRC_MCLK :
423
- case ADAU17X1_CLK_SRC_PLL :
424
- break ;
425
- default :
426
- return - EINVAL ;
427
- }
428
-
429
- adau -> sysclk = freq ;
430
-
431
- if (adau -> clk_src != clk_id ) {
432
- if (clk_id == ADAU17X1_CLK_SRC_PLL ) {
433
- snd_soc_dapm_add_routes (dapm ,
434
- & adau17x1_dapm_pll_route , 1 );
435
- } else {
436
- snd_soc_dapm_del_routes (dapm ,
437
- & adau17x1_dapm_pll_route , 1 );
438
- }
439
- }
440
-
441
- adau -> clk_src = clk_id ;
442
-
443
- return 0 ;
444
- }
445
-
446
510
static int adau17x1_set_dai_fmt (struct snd_soc_dai * dai ,
447
511
unsigned int fmt )
448
512
{
@@ -827,6 +891,10 @@ int adau17x1_add_routes(struct snd_soc_codec *codec)
827
891
ret = snd_soc_dapm_add_routes (dapm , adau17x1_no_dsp_dapm_routes ,
828
892
ARRAY_SIZE (adau17x1_no_dsp_dapm_routes ));
829
893
}
894
+
895
+ if (adau -> clk_src != ADAU17X1_CLK_SRC_MCLK )
896
+ snd_soc_dapm_add_routes (dapm , & adau17x1_dapm_pll_route , 1 );
897
+
830
898
return ret ;
831
899
}
832
900
EXPORT_SYMBOL_GPL (adau17x1_add_routes );
@@ -849,6 +917,7 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
849
917
const char * firmware_name )
850
918
{
851
919
struct adau * adau ;
920
+ int ret ;
852
921
853
922
if (IS_ERR (regmap ))
854
923
return PTR_ERR (regmap );
@@ -857,6 +926,30 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
857
926
if (!adau )
858
927
return - ENOMEM ;
859
928
929
+ adau -> mclk = devm_clk_get (dev , "mclk" );
930
+ if (IS_ERR (adau -> mclk )) {
931
+ if (PTR_ERR (adau -> mclk ) != - ENOENT )
932
+ return PTR_ERR (adau -> mclk );
933
+ /* Clock is optional (for the driver) */
934
+ adau -> mclk = NULL ;
935
+ } else if (adau -> mclk ) {
936
+ adau -> clk_src = ADAU17X1_CLK_SRC_PLL_AUTO ;
937
+
938
+ /*
939
+ * Any valid PLL output rate will work at this point, use one
940
+ * that is likely to be chosen later as well. The register will
941
+ * be written when the PLL is powered up for the first time.
942
+ */
943
+ ret = adau_calc_pll_cfg (clk_get_rate (adau -> mclk ), 48000 * 1024 ,
944
+ adau -> pll_regs );
945
+ if (ret < 0 )
946
+ return ret ;
947
+
948
+ ret = clk_prepare_enable (adau -> mclk );
949
+ if (ret )
950
+ return ret ;
951
+ }
952
+
860
953
adau -> regmap = regmap ;
861
954
adau -> switch_mode = switch_mode ;
862
955
adau -> type = type ;
@@ -880,6 +973,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
880
973
}
881
974
EXPORT_SYMBOL_GPL (adau17x1_probe );
882
975
976
+ void adau17x1_remove (struct device * dev )
977
+ {
978
+ struct adau * adau = dev_get_drvdata (dev );
979
+
980
+ snd_soc_unregister_codec (dev );
981
+ if (adau -> mclk )
982
+ clk_disable_unprepare (adau -> mclk );
983
+ }
984
+ EXPORT_SYMBOL_GPL (adau17x1_remove );
985
+
883
986
MODULE_DESCRIPTION ("ASoC ADAU1X61/ADAU1X81 common code" );
884
987
MODULE_AUTHOR (
"Lars-Peter Clausen <[email protected] >" );
885
988
MODULE_LICENSE ("GPL" );
0 commit comments