1
1
/*
2
- * wm8580.c -- WM8580 ALSA Soc Audio driver
2
+ * wm8580.c -- WM8580 and WM8581 ALSA Soc Audio driver
3
3
*
4
4
* Copyright 2008-12 Wolfson Microelectronics PLC.
5
5
*
12
12
* The WM8580 is a multichannel codec with S/PDIF support, featuring six
13
13
* DAC channels and two ADC channels.
14
14
*
15
+ * The WM8581 is a multichannel codec with S/PDIF support, featuring eight
16
+ * DAC channels and two ADC channels.
17
+ *
15
18
* Currently only the primary audio interface is supported - S/PDIF and
16
19
* the secondary audio interfaces are not.
17
20
*/
65
68
#define WM8580_DIGITAL_ATTENUATION_DACR2 0x17
66
69
#define WM8580_DIGITAL_ATTENUATION_DACL3 0x18
67
70
#define WM8580_DIGITAL_ATTENUATION_DACR3 0x19
71
+ #define WM8581_DIGITAL_ATTENUATION_DACL4 0x1A
72
+ #define WM8581_DIGITAL_ATTENUATION_DACR4 0x1B
68
73
#define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C
69
74
#define WM8580_ADC_CONTROL1 0x1D
70
75
#define WM8580_SPDTXCHAN0 0x1E
@@ -236,12 +241,17 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
236
241
"PVDD" ,
237
242
};
238
243
244
+ struct wm8580_driver_data {
245
+ int num_dacs ;
246
+ };
247
+
239
248
/* codec private data */
240
249
struct wm8580_priv {
241
250
struct regmap * regmap ;
242
251
struct regulator_bulk_data supplies [WM8580_NUM_SUPPLIES ];
243
252
struct pll_state a ;
244
253
struct pll_state b ;
254
+ const struct wm8580_driver_data * drvdata ;
245
255
int sysclk [2 ];
246
256
};
247
257
@@ -306,6 +316,19 @@ SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
306
316
SOC_SINGLE ("Capture High-Pass Filter Switch" , WM8580_ADC_CONTROL1 , 4 , 1 , 0 ),
307
317
};
308
318
319
+ static const struct snd_kcontrol_new wm8581_snd_controls [] = {
320
+ SOC_DOUBLE_R_EXT_TLV ("DAC4 Playback Volume" ,
321
+ WM8581_DIGITAL_ATTENUATION_DACL4 ,
322
+ WM8581_DIGITAL_ATTENUATION_DACR4 ,
323
+ 0 , 0xff , 0 , snd_soc_get_volsw , wm8580_out_vu , dac_tlv ),
324
+
325
+ SOC_SINGLE ("DAC4 Deemphasis Switch" , WM8580_DAC_CONTROL3 , 3 , 1 , 0 ),
326
+
327
+ SOC_DOUBLE ("DAC4 Invert Switch" , WM8580_DAC_CONTROL4 , 8 , 7 , 1 , 0 ),
328
+
329
+ SOC_SINGLE ("DAC4 Switch" , WM8580_DAC_CONTROL5 , 3 , 1 , 1 ),
330
+ };
331
+
309
332
static const struct snd_soc_dapm_widget wm8580_dapm_widgets [] = {
310
333
SND_SOC_DAPM_DAC ("DAC1" , "Playback" , WM8580_PWRDN1 , 2 , 1 ),
311
334
SND_SOC_DAPM_DAC ("DAC2" , "Playback" , WM8580_PWRDN1 , 3 , 1 ),
@@ -324,6 +347,13 @@ SND_SOC_DAPM_INPUT("AINL"),
324
347
SND_SOC_DAPM_INPUT ("AINR" ),
325
348
};
326
349
350
+ static const struct snd_soc_dapm_widget wm8581_dapm_widgets [] = {
351
+ SND_SOC_DAPM_DAC ("DAC4" , "Playback" , WM8580_PWRDN1 , 5 , 1 ),
352
+
353
+ SND_SOC_DAPM_OUTPUT ("VOUT4L" ),
354
+ SND_SOC_DAPM_OUTPUT ("VOUT4R" ),
355
+ };
356
+
327
357
static const struct snd_soc_dapm_route wm8580_dapm_routes [] = {
328
358
{ "VOUT1L" , NULL , "DAC1" },
329
359
{ "VOUT1R" , NULL , "DAC1" },
@@ -338,6 +368,11 @@ static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {
338
368
{ "ADC" , NULL , "AINR" },
339
369
};
340
370
371
+ static const struct snd_soc_dapm_route wm8581_dapm_routes [] = {
372
+ { "VOUT4L" , NULL , "DAC4" },
373
+ { "VOUT4R" , NULL , "DAC4" },
374
+ };
375
+
341
376
/* PLL divisors */
342
377
struct _pll_div {
343
378
u32 prescale :1 ;
@@ -815,10 +850,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
815
850
return 0 ;
816
851
}
817
852
853
+ static int wm8580_playback_startup (struct snd_pcm_substream * substream ,
854
+ struct snd_soc_dai * dai )
855
+ {
856
+ struct snd_soc_codec * codec = dai -> codec ;
857
+ struct wm8580_priv * wm8580 = snd_soc_codec_get_drvdata (codec );
858
+
859
+ return snd_pcm_hw_constraint_minmax (substream -> runtime ,
860
+ SNDRV_PCM_HW_PARAM_CHANNELS , 1 , wm8580 -> drvdata -> num_dacs * 2 );
861
+ }
862
+
818
863
#define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
819
864
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
820
865
821
866
static const struct snd_soc_dai_ops wm8580_dai_ops_playback = {
867
+ .startup = wm8580_playback_startup ,
822
868
.set_sysclk = wm8580_set_sysclk ,
823
869
.hw_params = wm8580_paif_hw_params ,
824
870
.set_fmt = wm8580_set_paif_dai_fmt ,
@@ -842,7 +888,6 @@ static struct snd_soc_dai_driver wm8580_dai[] = {
842
888
.playback = {
843
889
.stream_name = "Playback" ,
844
890
.channels_min = 1 ,
845
- .channels_max = 6 ,
846
891
.rates = SNDRV_PCM_RATE_8000_192000 ,
847
892
.formats = WM8580_FORMATS ,
848
893
},
@@ -865,8 +910,22 @@ static struct snd_soc_dai_driver wm8580_dai[] = {
865
910
static int wm8580_probe (struct snd_soc_codec * codec )
866
911
{
867
912
struct wm8580_priv * wm8580 = snd_soc_codec_get_drvdata (codec );
913
+ struct snd_soc_dapm_context * dapm = snd_soc_codec_get_dapm (codec );
868
914
int ret = 0 ;
869
915
916
+ switch (wm8580 -> drvdata -> num_dacs ) {
917
+ case 4 :
918
+ snd_soc_add_codec_controls (codec , wm8581_snd_controls ,
919
+ ARRAY_SIZE (wm8581_snd_controls ));
920
+ snd_soc_dapm_new_controls (dapm , wm8581_dapm_widgets ,
921
+ ARRAY_SIZE (wm8581_dapm_widgets ));
922
+ snd_soc_dapm_add_routes (dapm , wm8581_dapm_routes ,
923
+ ARRAY_SIZE (wm8581_dapm_routes ));
924
+ break ;
925
+ default :
926
+ break ;
927
+ }
928
+
870
929
ret = regulator_bulk_enable (ARRAY_SIZE (wm8580 -> supplies ),
871
930
wm8580 -> supplies );
872
931
if (ret != 0 ) {
@@ -914,12 +973,6 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
914
973
},
915
974
};
916
975
917
- static const struct of_device_id wm8580_of_match [] = {
918
- { .compatible = "wlf,wm8580" },
919
- { },
920
- };
921
- MODULE_DEVICE_TABLE (of , wm8580_of_match );
922
-
923
976
static const struct regmap_config wm8580_regmap = {
924
977
.reg_bits = 7 ,
925
978
.val_bits = 9 ,
@@ -932,10 +985,25 @@ static const struct regmap_config wm8580_regmap = {
932
985
.volatile_reg = wm8580_volatile ,
933
986
};
934
987
935
- #if IS_ENABLED (CONFIG_I2C )
988
+ static const struct wm8580_driver_data wm8580_data = {
989
+ .num_dacs = 3 ,
990
+ };
991
+
992
+ static const struct wm8580_driver_data wm8581_data = {
993
+ .num_dacs = 4 ,
994
+ };
995
+
996
+ static const struct of_device_id wm8580_of_match [] = {
997
+ { .compatible = "wlf,wm8580" , .data = & wm8580_data },
998
+ { .compatible = "wlf,wm8581" , .data = & wm8581_data },
999
+ { },
1000
+ };
1001
+ MODULE_DEVICE_TABLE (of , wm8580_of_match );
1002
+
936
1003
static int wm8580_i2c_probe (struct i2c_client * i2c ,
937
1004
const struct i2c_device_id * id )
938
1005
{
1006
+ const struct of_device_id * of_id ;
939
1007
struct wm8580_priv * wm8580 ;
940
1008
int ret , i ;
941
1009
@@ -960,6 +1028,15 @@ static int wm8580_i2c_probe(struct i2c_client *i2c,
960
1028
961
1029
i2c_set_clientdata (i2c , wm8580 );
962
1030
1031
+ of_id = of_match_device (wm8580_of_match , & i2c -> dev );
1032
+ if (of_id )
1033
+ wm8580 -> drvdata = of_id -> data ;
1034
+
1035
+ if (!wm8580 -> drvdata ) {
1036
+ dev_err (& i2c -> dev , "failed to find driver data\n" );
1037
+ return - EINVAL ;
1038
+ }
1039
+
963
1040
ret = snd_soc_register_codec (& i2c -> dev ,
964
1041
& soc_codec_dev_wm8580 , wm8580_dai , ARRAY_SIZE (wm8580_dai ));
965
1042
@@ -973,7 +1050,8 @@ static int wm8580_i2c_remove(struct i2c_client *client)
973
1050
}
974
1051
975
1052
static const struct i2c_device_id wm8580_i2c_id [] = {
976
- { "wm8580" , 0 },
1053
+ { "wm8580" , (kernel_ulong_t )& wm8580_data },
1054
+ { "wm8581" , (kernel_ulong_t )& wm8581_data },
977
1055
{ }
978
1056
};
979
1057
MODULE_DEVICE_TABLE (i2c , wm8580_i2c_id );
@@ -987,31 +1065,10 @@ static struct i2c_driver wm8580_i2c_driver = {
987
1065
.remove = wm8580_i2c_remove ,
988
1066
.id_table = wm8580_i2c_id ,
989
1067
};
990
- #endif
991
1068
992
- static int __init wm8580_modinit (void )
993
- {
994
- int ret = 0 ;
995
-
996
- #if IS_ENABLED (CONFIG_I2C )
997
- ret = i2c_add_driver (& wm8580_i2c_driver );
998
- if (ret != 0 ) {
999
- pr_err ("Failed to register WM8580 I2C driver: %d\n" , ret );
1000
- }
1001
- #endif
1002
-
1003
- return ret ;
1004
- }
1005
- module_init (wm8580_modinit );
1006
-
1007
- static void __exit wm8580_exit (void )
1008
- {
1009
- #if IS_ENABLED (CONFIG_I2C )
1010
- i2c_del_driver (& wm8580_i2c_driver );
1011
- #endif
1012
- }
1013
- module_exit (wm8580_exit );
1069
+ module_i2c_driver (wm8580_i2c_driver );
1014
1070
1015
1071
MODULE_DESCRIPTION ("ASoC WM8580 driver" );
1016
1072
MODULE_AUTHOR (
"Mark Brown <[email protected] >" );
1073
+ MODULE_AUTHOR (
"Matt Flax <[email protected] >" );
1017
1074
MODULE_LICENSE ("GPL" );
0 commit comments