@@ -74,6 +74,152 @@ struct aic32x4_priv {
74
74
struct regulator * supply_iov ;
75
75
struct regulator * supply_dv ;
76
76
struct regulator * supply_av ;
77
+
78
+ struct aic32x4_setup_data * setup ;
79
+ struct device * dev ;
80
+ };
81
+
82
+ static int aic32x4_get_mfp1_gpio (struct snd_kcontrol * kcontrol ,
83
+ struct snd_ctl_elem_value * ucontrol )
84
+ {
85
+ struct snd_soc_codec * codec = snd_kcontrol_chip (kcontrol );
86
+ u8 val ;
87
+
88
+ val = snd_soc_read (codec , AIC32X4_DINCTL );
89
+
90
+ ucontrol -> value .integer .value [0 ] = (val & 0x01 );
91
+
92
+ return 0 ;
93
+ };
94
+
95
+ static int aic32x4_set_mfp2_gpio (struct snd_kcontrol * kcontrol ,
96
+ struct snd_ctl_elem_value * ucontrol )
97
+ {
98
+ struct snd_soc_codec * codec = snd_kcontrol_chip (kcontrol );
99
+ u8 val ;
100
+ u8 gpio_check ;
101
+
102
+ val = snd_soc_read (codec , AIC32X4_DOUTCTL );
103
+ gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED );
104
+ if (gpio_check != AIC32X4_MFP_GPIO_ENABLED ) {
105
+ printk (KERN_ERR "%s: MFP2 is not configure as a GPIO output\n" ,
106
+ __func__ );
107
+ return - EINVAL ;
108
+ }
109
+
110
+ if (ucontrol -> value .integer .value [0 ] == (val & AIC32X4_MFP2_GPIO_OUT_HIGH ))
111
+ return 0 ;
112
+
113
+ if (ucontrol -> value .integer .value [0 ])
114
+ val |= ucontrol -> value .integer .value [0 ];
115
+ else
116
+ val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH ;
117
+
118
+ snd_soc_write (codec , AIC32X4_DOUTCTL , val );
119
+
120
+ return 0 ;
121
+ };
122
+
123
+ static int aic32x4_get_mfp3_gpio (struct snd_kcontrol * kcontrol ,
124
+ struct snd_ctl_elem_value * ucontrol )
125
+ {
126
+ struct snd_soc_codec * codec = snd_kcontrol_chip (kcontrol );
127
+ u8 val ;
128
+
129
+ val = snd_soc_read (codec , AIC32X4_SCLKCTL );
130
+
131
+ ucontrol -> value .integer .value [0 ] = (val & 0x01 );
132
+
133
+ return 0 ;
134
+ };
135
+
136
+ static int aic32x4_set_mfp4_gpio (struct snd_kcontrol * kcontrol ,
137
+ struct snd_ctl_elem_value * ucontrol )
138
+ {
139
+ struct snd_soc_codec * codec = snd_kcontrol_chip (kcontrol );
140
+ u8 val ;
141
+ u8 gpio_check ;
142
+
143
+ val = snd_soc_read (codec , AIC32X4_MISOCTL );
144
+ gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED );
145
+ if (gpio_check != AIC32X4_MFP_GPIO_ENABLED ) {
146
+ printk (KERN_ERR "%s: MFP4 is not configure as a GPIO output\n" ,
147
+ __func__ );
148
+ return - EINVAL ;
149
+ }
150
+
151
+ if (ucontrol -> value .integer .value [0 ] == (val & AIC32X4_MFP5_GPIO_OUT_HIGH ))
152
+ return 0 ;
153
+
154
+ if (ucontrol -> value .integer .value [0 ])
155
+ val |= ucontrol -> value .integer .value [0 ];
156
+ else
157
+ val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH ;
158
+
159
+ snd_soc_write (codec , AIC32X4_MISOCTL , val );
160
+
161
+ return 0 ;
162
+ };
163
+
164
+ static int aic32x4_get_mfp5_gpio (struct snd_kcontrol * kcontrol ,
165
+ struct snd_ctl_elem_value * ucontrol )
166
+ {
167
+ struct snd_soc_codec * codec = snd_kcontrol_chip (kcontrol );
168
+ u8 val ;
169
+
170
+ val = snd_soc_read (codec , AIC32X4_GPIOCTL );
171
+ ucontrol -> value .integer .value [0 ] = ((val & 0x2 ) >> 1 );
172
+
173
+ return 0 ;
174
+ };
175
+
176
+ static int aic32x4_set_mfp5_gpio (struct snd_kcontrol * kcontrol ,
177
+ struct snd_ctl_elem_value * ucontrol )
178
+ {
179
+ struct snd_soc_codec * codec = snd_kcontrol_chip (kcontrol );
180
+ u8 val ;
181
+ u8 gpio_check ;
182
+
183
+ val = snd_soc_read (codec , AIC32X4_GPIOCTL );
184
+ gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT );
185
+ if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT ) {
186
+ printk (KERN_ERR "%s: MFP5 is not configure as a GPIO output\n" ,
187
+ __func__ );
188
+ return - EINVAL ;
189
+ }
190
+
191
+ if (ucontrol -> value .integer .value [0 ] == (val & 0x1 ))
192
+ return 0 ;
193
+
194
+ if (ucontrol -> value .integer .value [0 ])
195
+ val |= ucontrol -> value .integer .value [0 ];
196
+ else
197
+ val &= 0xfe ;
198
+
199
+ snd_soc_write (codec , AIC32X4_GPIOCTL , val );
200
+
201
+ return 0 ;
202
+ };
203
+
204
+ static const struct snd_kcontrol_new aic32x4_mfp1 [] = {
205
+ SOC_SINGLE_BOOL_EXT ("MFP1 GPIO" , 0 , aic32x4_get_mfp1_gpio , NULL ),
206
+ };
207
+
208
+ static const struct snd_kcontrol_new aic32x4_mfp2 [] = {
209
+ SOC_SINGLE_BOOL_EXT ("MFP2 GPIO" , 0 , NULL , aic32x4_set_mfp2_gpio ),
210
+ };
211
+
212
+ static const struct snd_kcontrol_new aic32x4_mfp3 [] = {
213
+ SOC_SINGLE_BOOL_EXT ("MFP3 GPIO" , 0 , aic32x4_get_mfp3_gpio , NULL ),
214
+ };
215
+
216
+ static const struct snd_kcontrol_new aic32x4_mfp4 [] = {
217
+ SOC_SINGLE_BOOL_EXT ("MFP4 GPIO" , 0 , NULL , aic32x4_set_mfp4_gpio ),
218
+ };
219
+
220
+ static const struct snd_kcontrol_new aic32x4_mfp5 [] = {
221
+ SOC_SINGLE_BOOL_EXT ("MFP5 GPIO" , 0 , aic32x4_get_mfp5_gpio ,
222
+ aic32x4_set_mfp5_gpio ),
77
223
};
78
224
79
225
/* 0dB min, 0.5dB steps */
@@ -734,6 +880,52 @@ static struct snd_soc_dai_driver aic32x4_dai = {
734
880
.symmetric_rates = 1 ,
735
881
};
736
882
883
+ static void aic32x4_setup_gpios (struct snd_soc_codec * codec )
884
+ {
885
+ struct aic32x4_priv * aic32x4 = snd_soc_codec_get_drvdata (codec );
886
+
887
+ /* setup GPIO functions */
888
+ /* MFP1 */
889
+ if (aic32x4 -> setup -> gpio_func [0 ] != AIC32X4_MFPX_DEFAULT_VALUE ) {
890
+ snd_soc_write (codec , AIC32X4_DINCTL ,
891
+ aic32x4 -> setup -> gpio_func [0 ]);
892
+ snd_soc_add_codec_controls (codec , aic32x4_mfp1 ,
893
+ ARRAY_SIZE (aic32x4_mfp1 ));
894
+ }
895
+
896
+ /* MFP2 */
897
+ if (aic32x4 -> setup -> gpio_func [1 ] != AIC32X4_MFPX_DEFAULT_VALUE ) {
898
+ snd_soc_write (codec , AIC32X4_DOUTCTL ,
899
+ aic32x4 -> setup -> gpio_func [1 ]);
900
+ snd_soc_add_codec_controls (codec , aic32x4_mfp2 ,
901
+ ARRAY_SIZE (aic32x4_mfp2 ));
902
+ }
903
+
904
+ /* MFP3 */
905
+ if (aic32x4 -> setup -> gpio_func [2 ] != AIC32X4_MFPX_DEFAULT_VALUE ) {
906
+ snd_soc_write (codec , AIC32X4_SCLKCTL ,
907
+ aic32x4 -> setup -> gpio_func [2 ]);
908
+ snd_soc_add_codec_controls (codec , aic32x4_mfp3 ,
909
+ ARRAY_SIZE (aic32x4_mfp3 ));
910
+ }
911
+
912
+ /* MFP4 */
913
+ if (aic32x4 -> setup -> gpio_func [3 ] != AIC32X4_MFPX_DEFAULT_VALUE ) {
914
+ snd_soc_write (codec , AIC32X4_MISOCTL ,
915
+ aic32x4 -> setup -> gpio_func [3 ]);
916
+ snd_soc_add_codec_controls (codec , aic32x4_mfp4 ,
917
+ ARRAY_SIZE (aic32x4_mfp4 ));
918
+ }
919
+
920
+ /* MFP5 */
921
+ if (aic32x4 -> setup -> gpio_func [4 ] != AIC32X4_MFPX_DEFAULT_VALUE ) {
922
+ snd_soc_write (codec , AIC32X4_GPIOCTL ,
923
+ aic32x4 -> setup -> gpio_func [4 ]);
924
+ snd_soc_add_codec_controls (codec , aic32x4_mfp5 ,
925
+ ARRAY_SIZE (aic32x4_mfp5 ));
926
+ }
927
+ }
928
+
737
929
static int aic32x4_codec_probe (struct snd_soc_codec * codec )
738
930
{
739
931
struct aic32x4_priv * aic32x4 = snd_soc_codec_get_drvdata (codec );
@@ -746,6 +938,9 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec)
746
938
747
939
snd_soc_write (codec , AIC32X4_RESET , 0x01 );
748
940
941
+ if (aic32x4 -> setup )
942
+ aic32x4_setup_gpios (codec );
943
+
749
944
/* Power platform configuration */
750
945
if (aic32x4 -> power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN ) {
751
946
snd_soc_write (codec , AIC32X4_MICBIAS , AIC32X4_MICBIAS_LDOIN |
@@ -810,10 +1005,20 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
810
1005
static int aic32x4_parse_dt (struct aic32x4_priv * aic32x4 ,
811
1006
struct device_node * np )
812
1007
{
1008
+ struct aic32x4_setup_data * aic32x4_setup ;
1009
+
1010
+ aic32x4_setup = devm_kzalloc (aic32x4 -> dev , sizeof (* aic32x4_setup ),
1011
+ GFP_KERNEL );
1012
+ if (!aic32x4_setup )
1013
+ return - ENOMEM ;
1014
+
813
1015
aic32x4 -> swapdacs = false;
814
1016
aic32x4 -> micpga_routing = 0 ;
815
1017
aic32x4 -> rstn_gpio = of_get_named_gpio (np , "reset-gpios" , 0 );
816
1018
1019
+ if (of_property_read_u32_array (np , "aic32x4-gpio-func" ,
1020
+ aic32x4_setup -> gpio_func , 5 ) >= 0 )
1021
+ aic32x4 -> setup = aic32x4_setup ;
817
1022
return 0 ;
818
1023
}
819
1024
@@ -932,6 +1137,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
932
1137
if (aic32x4 == NULL )
933
1138
return - ENOMEM ;
934
1139
1140
+ aic32x4 -> dev = dev ;
935
1141
dev_set_drvdata (dev , aic32x4 );
936
1142
937
1143
if (pdata ) {
0 commit comments