wm8570: switch to generic volume control v2
PATCH 2/2 wm8570: switch to generic volume control v2
Make use of AUD_set_volume_in/out for muting and OUT2V, drop all internally applied mute masks. Avoids pow() in favor of a look-up table.
Successfully tested with the MusicPal. Line-in volume control still needs to be added - I'm lacking an appropriate test case, and the AUD layer is not yet supporting it anyway.
Signed-off-by Jan Kiszka <[email protected]>
--- hw/wm8750.c | 55 +++++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 28 deletions(-)
hw/wm8750.c +27 -28
@@ -39,10 +39,16 @@ struct wm8750_s {uint8_t diff[2 ], pol, ds, monomix[2 ], alc, mute;uint8_t path[4 ], mpath[2 ], power, format; -uint32_t inmask, outmask;const struct wm_rate_s *rate; }; +/* pow(10.0, -i / 20.0), i = 0..42 */ +static const uint8_t vol_db_table[] = { +255 ,227 ,203 ,181 ,161 ,143 ,128 ,114 ,102 ,90 ,81 ,72 ,64 ,57 ,51 ,45 , +40 ,36 ,32 ,29 ,26 ,23 ,20 ,18 ,16 ,14 ,13 ,11 ,10 ,9 ,8 ,7 ,6 ,6 ,5 ,5 , +4 ,4 ,3 ,3 ,3 ,2 ,2 +}; +static inline void wm8750_in_load (struct wm8750_s *s) {int acquired;
@@ -125,6 +131,16 @@ static const struct wm_rate_s wm_rate_ta { 192, 88200, 192, 88200 }, /* SR: 11111 */ }; +static void wm8750_vol_update (struct wm8750_s *s) +{ +AUD_set_volume_in (*s->in[0 ], s->mute, + s->inmute[0 ] ?0 :0xff , + s->inmute[1 ] ?0 :0xff ); +AUD_set_volume_out (*s->out[0 ], s->mute, + s->outmute[0 ] ?0 : vol_db_table[(0x7f -s->outvol[4 ])/3 ], + s->outmute[1 ] ?0 : vol_db_table[(0x7f -s->outvol[5 ])/3 ]); +} +static void wm8750_set_format (struct wm8750_s *s) {int i;
@@ -185,6 +201,8 @@ static void wm8750_set_format(struct wm8 CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);/* no sense emulating OUT3 which is a mix of other outputs */ +wm8750_vol_update (s); +/* We should connect the left and right channels to their * respective inputs/outputs but we have completely no need * for mixing or combining paths to different ports, so we
@@ -195,22 +213,6 @@ static void wm8750_set_format(struct wm8AUD_set_active_out (*s->out[0 ],1 ); } -static void inline wm8750_mask_update (struct wm8750_s *s) -{ -#define R_ONLY 0x0000ffff -#define L_ONLY 0xffff0000 -#define BOTH (R_ONLY | L_ONLY) -#define NONE (R_ONLY & L_ONLY) - s->inmask = - (s->inmute[0 ] ?R_ONLY :BOTH ) & - (s->inmute[1 ] ?L_ONLY :BOTH ) & - (s->mute ?NONE :BOTH ); - s->outmask = - (s->outmute[0 ] ?R_ONLY :BOTH ) & - (s->outmute[1 ] ?L_ONLY :BOTH ) & - (s->mute ?NONE :BOTH ); -} -void wm8750_reset (i2c_slave *i2c) {struct wm8750_s *s = (struct wm8750_s *) i2c;
@@ -249,7 +251,7 @@ void wm8750_reset(i2c_slave *i2c) s->req_in =0 ; s->idx_out =0 ; s->req_out =0 ; -wm8750_mask_update (s); +wm8750_vol_update (s); s->i2c_len =0 ; }
@@ -367,19 +369,19 @@ static int wm8750_tx(i2c_slave *i2c, uincase WM8750_LINVOL :/* Left Channel PGA */ s->invol[0 ] = value &0x3f ;/* LINVOL */ s->inmute[0 ] = (value >>7 ) &1 ;/* LINMUTE */ -wm8750_mask_update (s); +wm8750_vol_update (s);break ;case WM8750_RINVOL :/* Right Channel PGA */ s->invol[1 ] = value &0x3f ;/* RINVOL */ s->inmute[1 ] = (value >>7 ) &1 ;/* RINMUTE */ -wm8750_mask_update (s); +wm8750_vol_update (s);break ;case WM8750_ADCDAC :/* ADC and DAC Control */ s->pol = (value >>5 ) &3 ;/* ADCPOL */ s->mute = (value >>3 ) &1 ;/* DACMU */ -wm8750_mask_update (s); +wm8750_vol_update (s);break ;case WM8750_ADCTL3 :/* Additional Control (3) */
@@ -442,6 +444,7 @@ static int wm8750_tx(i2c_slave *i2c, uincase WM8750_LOUT2V :/* LOUT2 Volume */ s->outvol[4 ] = value &0x7f ;/* LOUT2VOL */ +wm8750_vol_update (s);break ;case WM8750_ROUT1V :/* ROUT1 Volume */
@@ -450,6 +453,7 @@ static int wm8750_tx(i2c_slave *i2c, uincase WM8750_ROUT2V :/* ROUT2 Volume */ s->outvol[5 ] = value &0x7f ;/* ROUT2VOL */ +wm8750_vol_update (s);break ;case WM8750_MOUTV :/* MONOOUT Volume */
@@ -531,8 +535,6 @@ static void wm8750_save(QEMUFile *f, voiqemu_put_8s (f, &s->mpath[i]);qemu_put_8s (f, &s->format);qemu_put_8s (f, &s->power); -qemu_put_be32s (f, &s->inmask); -qemu_put_be32s (f, &s->outmask);qemu_put_byte (f, (s->rate - wm_rate_table) /sizeof (*s->rate));i2c_slave_save (f, &s->i2c); }
@@ -573,8 +575,6 @@ static int wm8750_load(QEMUFile *f, voidqemu_get_8s (f, &s->mpath[i]);qemu_get_8s (f, &s->format);qemu_get_8s (f, &s->power); -qemu_get_be32s (f, &s->inmask); -qemu_get_be32s (f, &s->outmask); s->rate = &wm_rate_table[(uint8_t )qemu_get_byte (f) &0x1f ];i2c_slave_load (f, &s->i2c);return 0 ;
@@ -619,8 +619,7 @@ void wm8750_data_req_set(i2c_slave *i2c,void wm8750_dac_dat (void *opaque,uint32_t sample) {struct wm8750_s *s = (struct wm8750_s *) opaque; -uint32_t *data = (uint32_t *) &s->data_out[s->idx_out]; - *data = sample & s->outmask; + *(uint32_t *) &s->data_out[s->idx_out] = sample; s->req_out -=4 ; s->idx_out +=4 ;if (s->idx_out >=sizeof (s->data_out) || s->req_out <=0 )
@@ -654,5 +653,5 @@ uint32_t wm8750_adc_dat(void *opaque) data = (uint32_t *) &s->data_in[s->idx_in]; s->req_in -=4 ; s->idx_in +=4 ; -return *data & s->inmask; +return *data; }