2828#include <sound/pcm_params.h>
2929#include <sound/soc.h>
3030#include <sound/tlv.h>
31+ #include <asm/unaligned.h>
3132
3233#include "tas571x.h"
3334
@@ -63,6 +64,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
6364 case TAS571X_INPUT_MUX_REG :
6465 case TAS571X_CH4_SRC_SELECT_REG :
6566 case TAS571X_PWM_MUX_REG :
67+ case TAS5717_CH1_RIGHT_CH_MIX_REG :
68+ case TAS5717_CH1_LEFT_CH_MIX_REG :
69+ case TAS5717_CH2_LEFT_CH_MIX_REG :
70+ case TAS5717_CH2_RIGHT_CH_MIX_REG :
6671 return 4 ;
6772 default :
6873 return 1 ;
@@ -135,6 +140,129 @@ static int tas571x_reg_read(void *context, unsigned int reg,
135140 return 0 ;
136141}
137142
143+ /*
144+ * register write for 8- and 20-byte registers
145+ */
146+ static int tas571x_reg_write_multiword (struct i2c_client * client ,
147+ unsigned int reg , const long values [], size_t len )
148+ {
149+ size_t i ;
150+ uint8_t * buf , * p ;
151+ int ret ;
152+ size_t send_size = 1 + len * sizeof (uint32_t );
153+
154+ buf = kzalloc (send_size , GFP_KERNEL | GFP_DMA );
155+ if (!buf )
156+ return - ENOMEM ;
157+ buf [0 ] = reg ;
158+
159+ for (i = 0 , p = buf + 1 ; i < len ; i ++ , p += sizeof (uint32_t ))
160+ put_unaligned_be32 (values [i ], p );
161+
162+ ret = i2c_master_send (client , buf , send_size );
163+
164+ kfree (buf );
165+
166+ if (ret == send_size )
167+ return 0 ;
168+ else if (ret < 0 )
169+ return ret ;
170+ else
171+ return - EIO ;
172+ }
173+
174+ /*
175+ * register read for 8- and 20-byte registers
176+ */
177+ static int tas571x_reg_read_multiword (struct i2c_client * client ,
178+ unsigned int reg , long values [], size_t len )
179+ {
180+ unsigned int i ;
181+ uint8_t send_buf ;
182+ uint8_t * recv_buf , * p ;
183+ struct i2c_msg msgs [2 ];
184+ unsigned int recv_size = len * sizeof (uint32_t );
185+ int ret ;
186+
187+ recv_buf = kzalloc (recv_size , GFP_KERNEL | GFP_DMA );
188+ if (!recv_buf )
189+ return - ENOMEM ;
190+
191+ send_buf = reg ;
192+
193+ msgs [0 ].addr = client -> addr ;
194+ msgs [0 ].len = sizeof (send_buf );
195+ msgs [0 ].buf = & send_buf ;
196+ msgs [0 ].flags = 0 ;
197+
198+ msgs [1 ].addr = client -> addr ;
199+ msgs [1 ].len = recv_size ;
200+ msgs [1 ].buf = recv_buf ;
201+ msgs [1 ].flags = I2C_M_RD ;
202+
203+ ret = i2c_transfer (client -> adapter , msgs , ARRAY_SIZE (msgs ));
204+ if (ret < 0 )
205+ goto err_ret ;
206+ else if (ret != ARRAY_SIZE (msgs )) {
207+ ret = - EIO ;
208+ goto err_ret ;
209+ }
210+
211+ for (i = 0 , p = recv_buf ; i < len ; i ++ , p += sizeof (uint32_t ))
212+ values [i ] = get_unaligned_be32 (p );
213+
214+ err_ret :
215+ kfree (recv_buf );
216+ return ret ;
217+ }
218+
219+ /*
220+ * Integer array controls for setting biquad, mixer, DRC coefficients.
221+ * According to the datasheet each coefficient is effectively 26bits,
222+ * i.e. stored as 32bits, where bits [31:26] are ignored.
223+ * TI's TAS57xx Graphical Development Environment tool however produces
224+ * coefficients with more than 26 bits. For this reason we allow values
225+ * in the full 32-bits reange.
226+ * The coefficients are ordered as given in the TAS571x data sheet:
227+ * b0, b1, b2, a1, a2
228+ */
229+
230+ static int tas571x_coefficient_info (struct snd_kcontrol * kcontrol ,
231+ struct snd_ctl_elem_info * uinfo )
232+ {
233+ int numcoef = kcontrol -> private_value >> 16 ;
234+
235+ uinfo -> type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
236+ uinfo -> count = numcoef ;
237+ uinfo -> value .integer .min = 0 ;
238+ uinfo -> value .integer .max = 0xffffffff ;
239+ return 0 ;
240+ }
241+
242+ static int tas571x_coefficient_get (struct snd_kcontrol * kcontrol ,
243+ struct snd_ctl_elem_value * ucontrol )
244+ {
245+ struct snd_soc_codec * codec = snd_soc_kcontrol_codec (kcontrol );
246+ struct i2c_client * i2c = to_i2c_client (codec -> dev );
247+ int numcoef = kcontrol -> private_value >> 16 ;
248+ int index = kcontrol -> private_value & 0xffff ;
249+
250+ return tas571x_reg_read_multiword (i2c , index ,
251+ ucontrol -> value .integer .value , numcoef );
252+ }
253+
254+ static int tas571x_coefficient_put (struct snd_kcontrol * kcontrol ,
255+ struct snd_ctl_elem_value * ucontrol )
256+ {
257+ struct snd_soc_codec * codec = snd_soc_kcontrol_codec (kcontrol );
258+ struct i2c_client * i2c = to_i2c_client (codec -> dev );
259+ int numcoef = kcontrol -> private_value >> 16 ;
260+ int index = kcontrol -> private_value & 0xffff ;
261+
262+ return tas571x_reg_write_multiword (i2c , index ,
263+ ucontrol -> value .integer .value , numcoef );
264+ }
265+
138266static int tas571x_set_dai_fmt (struct snd_soc_dai * dai , unsigned int format )
139267{
140268 struct tas571x_private * priv = snd_soc_codec_get_drvdata (dai -> codec );
@@ -241,6 +369,15 @@ static const struct snd_soc_dai_ops tas571x_dai_ops = {
241369 .digital_mute = tas571x_mute ,
242370};
243371
372+
373+ #define BIQUAD_COEFS (xname , reg ) \
374+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
375+ .info = tas571x_coefficient_info, \
376+ .get = tas571x_coefficient_get,\
377+ .put = tas571x_coefficient_put, \
378+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
379+ .private_value = reg | (5 << 16) }
380+
244381static const char * const tas5711_supply_names [] = {
245382 "AVDD" ,
246383 "DVDD" ,
@@ -264,6 +401,16 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
264401 TAS571X_SOFT_MUTE_REG ,
265402 TAS571X_SOFT_MUTE_CH1_SHIFT , TAS571X_SOFT_MUTE_CH2_SHIFT ,
266403 1 , 1 ),
404+
405+ SOC_DOUBLE_R_RANGE ("CH1 Mixer Volume" ,
406+ TAS5717_CH1_LEFT_CH_MIX_REG ,
407+ TAS5717_CH1_RIGHT_CH_MIX_REG ,
408+ 16 , 0 , 0x80 , 0 ),
409+
410+ SOC_DOUBLE_R_RANGE ("CH2 Mixer Volume" ,
411+ TAS5717_CH2_LEFT_CH_MIX_REG ,
412+ TAS5717_CH2_RIGHT_CH_MIX_REG ,
413+ 16 , 0 , 0x80 , 0 ),
267414};
268415
269416static const struct regmap_range tas571x_readonly_regs_range [] = {
@@ -340,6 +487,43 @@ static const struct snd_kcontrol_new tas5717_controls[] = {
340487 TAS571X_SOFT_MUTE_REG ,
341488 TAS571X_SOFT_MUTE_CH1_SHIFT , TAS571X_SOFT_MUTE_CH2_SHIFT ,
342489 1 , 1 ),
490+
491+ /*
492+ * The biquads are named according to the register names.
493+ * Please note that TI's TAS57xx Graphical Development Environment
494+ * tool names them different.
495+ */
496+ BIQUAD_COEFS ("CH1 - Biquad 0" , TAS5717_CH1_BQ0_REG ),
497+ BIQUAD_COEFS ("CH1 - Biquad 1" , TAS5717_CH1_BQ1_REG ),
498+ BIQUAD_COEFS ("CH1 - Biquad 2" , TAS5717_CH1_BQ2_REG ),
499+ BIQUAD_COEFS ("CH1 - Biquad 3" , TAS5717_CH1_BQ3_REG ),
500+ BIQUAD_COEFS ("CH1 - Biquad 4" , TAS5717_CH1_BQ4_REG ),
501+ BIQUAD_COEFS ("CH1 - Biquad 5" , TAS5717_CH1_BQ5_REG ),
502+ BIQUAD_COEFS ("CH1 - Biquad 6" , TAS5717_CH1_BQ6_REG ),
503+ BIQUAD_COEFS ("CH1 - Biquad 7" , TAS5717_CH1_BQ7_REG ),
504+ BIQUAD_COEFS ("CH1 - Biquad 8" , TAS5717_CH1_BQ8_REG ),
505+ BIQUAD_COEFS ("CH1 - Biquad 9" , TAS5717_CH1_BQ9_REG ),
506+ BIQUAD_COEFS ("CH1 - Biquad 10" , TAS5717_CH1_BQ10_REG ),
507+ BIQUAD_COEFS ("CH1 - Biquad 11" , TAS5717_CH1_BQ11_REG ),
508+
509+ BIQUAD_COEFS ("CH2 - Biquad 0" , TAS5717_CH2_BQ0_REG ),
510+ BIQUAD_COEFS ("CH2 - Biquad 1" , TAS5717_CH2_BQ1_REG ),
511+ BIQUAD_COEFS ("CH2 - Biquad 2" , TAS5717_CH2_BQ2_REG ),
512+ BIQUAD_COEFS ("CH2 - Biquad 3" , TAS5717_CH2_BQ3_REG ),
513+ BIQUAD_COEFS ("CH2 - Biquad 4" , TAS5717_CH2_BQ4_REG ),
514+ BIQUAD_COEFS ("CH2 - Biquad 5" , TAS5717_CH2_BQ5_REG ),
515+ BIQUAD_COEFS ("CH2 - Biquad 6" , TAS5717_CH2_BQ6_REG ),
516+ BIQUAD_COEFS ("CH2 - Biquad 7" , TAS5717_CH2_BQ7_REG ),
517+ BIQUAD_COEFS ("CH2 - Biquad 8" , TAS5717_CH2_BQ8_REG ),
518+ BIQUAD_COEFS ("CH2 - Biquad 9" , TAS5717_CH2_BQ9_REG ),
519+ BIQUAD_COEFS ("CH2 - Biquad 10" , TAS5717_CH2_BQ10_REG ),
520+ BIQUAD_COEFS ("CH2 - Biquad 11" , TAS5717_CH2_BQ11_REG ),
521+
522+ BIQUAD_COEFS ("CH3 - Biquad 0" , TAS5717_CH3_BQ0_REG ),
523+ BIQUAD_COEFS ("CH3 - Biquad 1" , TAS5717_CH3_BQ1_REG ),
524+
525+ BIQUAD_COEFS ("CH4 - Biquad 0" , TAS5717_CH4_BQ0_REG ),
526+ BIQUAD_COEFS ("CH4 - Biquad 1" , TAS5717_CH4_BQ1_REG ),
343527};
344528
345529static const struct reg_default tas5717_reg_defaults [] = {
@@ -350,6 +534,10 @@ static const struct reg_default tas5717_reg_defaults[] = {
350534 { 0x08 , 0x00c0 },
351535 { 0x09 , 0x00c0 },
352536 { 0x1b , 0x82 },
537+ { TAS5717_CH1_RIGHT_CH_MIX_REG , 0x0 },
538+ { TAS5717_CH1_LEFT_CH_MIX_REG , 0x800000 },
539+ { TAS5717_CH2_LEFT_CH_MIX_REG , 0x0 },
540+ { TAS5717_CH2_RIGHT_CH_MIX_REG , 0x800000 },
353541};
354542
355543static const struct regmap_config tas5717_regmap_config = {
0 commit comments