1717#include <linux/sysfs.h>
1818#include <linux/types.h>
1919#include <linux/dma/imx-dma.h>
20+ #include <linux/log2.h>
2021#include <sound/dmaengine_pcm.h>
2122#include <sound/pcm.h>
2223#include <sound/pcm_params.h>
@@ -92,6 +93,9 @@ struct fsl_micfil_soc_data {
9293 bool volume_sx ;
9394 u64 formats ;
9495 int fifo_offset ;
96+ enum quality default_quality ;
97+ /* stores const value in formula to calculate range */
98+ int rangeadj_const [3 ][2 ];
9599};
96100
97101static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
@@ -102,6 +106,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
102106 .formats = SNDRV_PCM_FMTBIT_S16_LE ,
103107 .volume_sx = true,
104108 .fifo_offset = 0 ,
109+ .default_quality = QUALITY_VLOW0 ,
105110};
106111
107112static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
@@ -112,6 +117,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
112117 .formats = SNDRV_PCM_FMTBIT_S32_LE ,
113118 .volume_sx = false,
114119 .fifo_offset = 0 ,
120+ .default_quality = QUALITY_MEDIUM ,
121+ .rangeadj_const = {{27 , 7 }, {27 , 7 }, {26 , 7 }},
115122};
116123
117124static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
@@ -124,6 +131,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
124131 .use_verid = true,
125132 .volume_sx = false,
126133 .fifo_offset = 0 ,
134+ .default_quality = QUALITY_MEDIUM ,
135+ .rangeadj_const = {{30 , 6 }, {30 , 6 }, {29 , 6 }},
127136};
128137
129138static struct fsl_micfil_soc_data fsl_micfil_imx943 = {
@@ -136,6 +145,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = {
136145 .use_verid = true,
137146 .volume_sx = false,
138147 .fifo_offset = -4 ,
148+ .default_quality = QUALITY_MEDIUM ,
149+ .rangeadj_const = {{34 , 6 }, {34 , 6 }, {33 , 6 }},
139150};
140151
141152static const struct of_device_id fsl_micfil_dt_ids [] = {
@@ -162,9 +173,69 @@ static const struct soc_enum fsl_micfil_quality_enum =
162173
163174static DECLARE_TLV_DB_SCALE (gain_tlv , 0 , 100 , 0 ) ;
164175
176+ static int micfil_get_max_range (struct fsl_micfil * micfil )
177+ {
178+ int max_range ;
179+
180+ switch (micfil -> quality ) {
181+ case QUALITY_HIGH :
182+ case QUALITY_VLOW0 :
183+ max_range = micfil -> soc -> rangeadj_const [0 ][0 ] - micfil -> soc -> rangeadj_const [0 ][1 ] *
184+ ilog2 (2 * MICFIL_OSR_DEFAULT );
185+ break ;
186+ case QUALITY_MEDIUM :
187+ case QUALITY_VLOW1 :
188+ max_range = micfil -> soc -> rangeadj_const [1 ][0 ] - micfil -> soc -> rangeadj_const [1 ][1 ] *
189+ ilog2 (MICFIL_OSR_DEFAULT );
190+ break ;
191+ case QUALITY_LOW :
192+ case QUALITY_VLOW2 :
193+ max_range = micfil -> soc -> rangeadj_const [2 ][0 ] - micfil -> soc -> rangeadj_const [2 ][1 ] *
194+ ilog2 (MICFIL_OSR_DEFAULT );
195+ break ;
196+ default :
197+ return 0 ;
198+ }
199+ max_range = max_range < 0 ? 0 : max_range ;
200+
201+ return max_range ;
202+ }
203+
204+ static int micfil_range_set (struct snd_kcontrol * kcontrol ,
205+ struct snd_ctl_elem_value * ucontrol )
206+ {
207+ struct snd_soc_component * cmpnt = snd_kcontrol_chip (kcontrol );
208+ struct fsl_micfil * micfil = snd_soc_component_get_drvdata (cmpnt );
209+ struct soc_mixer_control * mc =
210+ (struct soc_mixer_control * )kcontrol -> private_value ;
211+ unsigned int shift = mc -> shift ;
212+ int max_range , new_range ;
213+
214+ new_range = ucontrol -> value .integer .value [0 ];
215+ max_range = micfil_get_max_range (micfil );
216+ if (new_range > max_range )
217+ dev_warn (& micfil -> pdev -> dev , "range makes channel %d data unreliable\n" , shift / 4 );
218+
219+ regmap_update_bits (micfil -> regmap , REG_MICFIL_OUT_CTRL , 0xF << shift , new_range << shift );
220+
221+ return 0 ;
222+ }
223+
165224static int micfil_set_quality (struct fsl_micfil * micfil )
166225{
167- u32 qsel ;
226+ int range , max_range ;
227+ u32 qsel , val ;
228+ int i ;
229+
230+ if (!micfil -> soc -> volume_sx ) {
231+ regmap_read (micfil -> regmap , REG_MICFIL_OUT_CTRL , & val );
232+ max_range = micfil_get_max_range (micfil );
233+ for (i = 0 ; i < micfil -> soc -> fifos ; i ++ ) {
234+ range = (val >> MICFIL_OUTGAIN_CHX_SHIFT (i )) & 0xF ;
235+ if (range > max_range )
236+ dev_warn (& micfil -> pdev -> dev , "please reset channel %d range\n" , i );
237+ }
238+ }
168239
169240 switch (micfil -> quality ) {
170241 case QUALITY_HIGH :
@@ -362,23 +433,31 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol,
362433 return 0 ;
363434}
364435
365- static const struct snd_kcontrol_new fsl_micfil_volume_controls [] = {
366- SOC_SINGLE_TLV ("CH0 Volume" , REG_MICFIL_OUT_CTRL ,
367- MICFIL_OUTGAIN_CHX_SHIFT (0 ), 0xF , 0 , gain_tlv ),
368- SOC_SINGLE_TLV ("CH1 Volume" , REG_MICFIL_OUT_CTRL ,
369- MICFIL_OUTGAIN_CHX_SHIFT (1 ), 0xF , 0 , gain_tlv ),
370- SOC_SINGLE_TLV ("CH2 Volume" , REG_MICFIL_OUT_CTRL ,
371- MICFIL_OUTGAIN_CHX_SHIFT (2 ), 0xF , 0 , gain_tlv ),
372- SOC_SINGLE_TLV ("CH3 Volume" , REG_MICFIL_OUT_CTRL ,
373- MICFIL_OUTGAIN_CHX_SHIFT (3 ), 0xF , 0 , gain_tlv ),
374- SOC_SINGLE_TLV ("CH4 Volume" , REG_MICFIL_OUT_CTRL ,
375- MICFIL_OUTGAIN_CHX_SHIFT (4 ), 0xF , 0 , gain_tlv ),
376- SOC_SINGLE_TLV ("CH5 Volume" , REG_MICFIL_OUT_CTRL ,
377- MICFIL_OUTGAIN_CHX_SHIFT (5 ), 0xF , 0 , gain_tlv ),
378- SOC_SINGLE_TLV ("CH6 Volume" , REG_MICFIL_OUT_CTRL ,
379- MICFIL_OUTGAIN_CHX_SHIFT (6 ), 0xF , 0 , gain_tlv ),
380- SOC_SINGLE_TLV ("CH7 Volume" , REG_MICFIL_OUT_CTRL ,
381- MICFIL_OUTGAIN_CHX_SHIFT (7 ), 0xF , 0 , gain_tlv ),
436+ static const struct snd_kcontrol_new fsl_micfil_range_controls [] = {
437+ SOC_SINGLE_EXT ("CH0 Range" , REG_MICFIL_OUT_CTRL ,
438+ MICFIL_OUTGAIN_CHX_SHIFT (0 ), 0xF , 0 ,
439+ snd_soc_get_volsw , micfil_range_set ),
440+ SOC_SINGLE_EXT ("CH1 Range" , REG_MICFIL_OUT_CTRL ,
441+ MICFIL_OUTGAIN_CHX_SHIFT (1 ), 0xF , 0 ,
442+ snd_soc_get_volsw , micfil_range_set ),
443+ SOC_SINGLE_EXT ("CH2 Range" , REG_MICFIL_OUT_CTRL ,
444+ MICFIL_OUTGAIN_CHX_SHIFT (2 ), 0xF , 0 ,
445+ snd_soc_get_volsw , micfil_range_set ),
446+ SOC_SINGLE_EXT ("CH3 Range" , REG_MICFIL_OUT_CTRL ,
447+ MICFIL_OUTGAIN_CHX_SHIFT (3 ), 0xF , 0 ,
448+ snd_soc_get_volsw , micfil_range_set ),
449+ SOC_SINGLE_EXT ("CH4 Range" , REG_MICFIL_OUT_CTRL ,
450+ MICFIL_OUTGAIN_CHX_SHIFT (4 ), 0xF , 0 ,
451+ snd_soc_get_volsw , micfil_range_set ),
452+ SOC_SINGLE_EXT ("CH5 Range" , REG_MICFIL_OUT_CTRL ,
453+ MICFIL_OUTGAIN_CHX_SHIFT (5 ), 0xF , 0 ,
454+ snd_soc_get_volsw , micfil_range_set ),
455+ SOC_SINGLE_EXT ("CH6 Range" , REG_MICFIL_OUT_CTRL ,
456+ MICFIL_OUTGAIN_CHX_SHIFT (6 ), 0xF , 0 ,
457+ snd_soc_get_volsw , micfil_range_set ),
458+ SOC_SINGLE_EXT ("CH7 Range" , REG_MICFIL_OUT_CTRL ,
459+ MICFIL_OUTGAIN_CHX_SHIFT (7 ), 0xF , 0 ,
460+ snd_soc_get_volsw , micfil_range_set ),
382461};
383462
384463static const struct snd_kcontrol_new fsl_micfil_volume_sx_controls [] = {
@@ -890,13 +969,20 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
890969 struct fsl_micfil * micfil = dev_get_drvdata (cpu_dai -> dev );
891970 struct device * dev = cpu_dai -> dev ;
892971 unsigned int val = 0 ;
893- int ret , i ;
972+ int ret , i , max_range ;
894973
895- micfil -> quality = QUALITY_VLOW0 ;
974+ micfil -> quality = micfil -> soc -> default_quality ;
896975 micfil -> card = cpu_dai -> component -> card ;
897976
898977 /* set default gain to 2 */
899- regmap_write (micfil -> regmap , REG_MICFIL_OUT_CTRL , 0x22222222 );
978+ if (micfil -> soc -> volume_sx ) {
979+ regmap_write (micfil -> regmap , REG_MICFIL_OUT_CTRL , 0x22222222 );
980+ } else {
981+ max_range = micfil_get_max_range (micfil );
982+ for (i = 1 ; i < micfil -> soc -> fifos ; i ++ )
983+ max_range |= max_range << 4 ;
984+ regmap_write (micfil -> regmap , REG_MICFIL_OUT_CTRL , max_range );
985+ }
900986
901987 /* set DC Remover in bypass mode*/
902988 for (i = 0 ; i < MICFIL_OUTPUT_CHANNELS ; i ++ )
@@ -930,8 +1016,8 @@ static int fsl_micfil_component_probe(struct snd_soc_component *component)
9301016 snd_soc_add_component_controls (component , fsl_micfil_volume_sx_controls ,
9311017 ARRAY_SIZE (fsl_micfil_volume_sx_controls ));
9321018 else
933- snd_soc_add_component_controls (component , fsl_micfil_volume_controls ,
934- ARRAY_SIZE (fsl_micfil_volume_controls ));
1019+ snd_soc_add_component_controls (component , fsl_micfil_range_controls ,
1020+ ARRAY_SIZE (fsl_micfil_range_controls ));
9351021
9361022 return 0 ;
9371023}
0 commit comments