diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2008-05-13 03:20:51 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-05-19 07:19:16 -0400 |
commit | e58aee95806c9d2bbcfc84cb85ce958e360165ef (patch) | |
tree | 8385cb486591002e7a9ddefff9a9477b9f9bf679 /sound/pci/oxygen | |
parent | c13650079ba3bed1c0bdd9bf4a13274be7676ff6 (diff) |
[ALSA] oxygen: save register writes
Save the written values of all CMI8788 and AC97 registers and of some of
the DAC/ADC registers so that it is possible to restore the register
state later.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r-- | sound/pci/oxygen/oxygen.c | 17 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen.h | 6 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_io.c | 22 | ||||
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 54 |
4 files changed, 67 insertions, 32 deletions
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index c1b30cc75935..8287ac28fe78 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -80,6 +80,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); | |||
80 | 80 | ||
81 | struct generic_data { | 81 | struct generic_data { |
82 | u8 ak4396_ctl2; | 82 | u8 ak4396_ctl2; |
83 | u16 saved_wm8785_registers[2]; | ||
83 | }; | 84 | }; |
84 | 85 | ||
85 | static void ak4396_write(struct oxygen *chip, unsigned int codec, | 86 | static void ak4396_write(struct oxygen *chip, unsigned int codec, |
@@ -99,12 +100,16 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec, | |||
99 | 100 | ||
100 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) | 101 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) |
101 | { | 102 | { |
103 | struct generic_data *data = chip->model_data; | ||
104 | |||
102 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | 105 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | |
103 | OXYGEN_SPI_DATA_LENGTH_2 | | 106 | OXYGEN_SPI_DATA_LENGTH_2 | |
104 | OXYGEN_SPI_CLOCK_160 | | 107 | OXYGEN_SPI_CLOCK_160 | |
105 | (3 << OXYGEN_SPI_CODEC_SHIFT) | | 108 | (3 << OXYGEN_SPI_CODEC_SHIFT) | |
106 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 109 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
107 | (reg << 9) | value); | 110 | (reg << 9) | value); |
111 | if (reg < ARRAY_SIZE(data->saved_wm8785_registers)) | ||
112 | data->saved_wm8785_registers[reg] = value; | ||
108 | } | 113 | } |
109 | 114 | ||
110 | static void ak4396_init(struct oxygen *chip) | 115 | static void ak4396_init(struct oxygen *chip) |
@@ -135,10 +140,16 @@ static void ak5385_init(struct oxygen *chip) | |||
135 | 140 | ||
136 | static void wm8785_init(struct oxygen *chip) | 141 | static void wm8785_init(struct oxygen *chip) |
137 | { | 142 | { |
143 | struct generic_data *data = chip->model_data; | ||
144 | |||
145 | data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE | | ||
146 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST; | ||
147 | data->saved_wm8785_registers[1] = WM8785_WL_24; | ||
148 | |||
138 | wm8785_write(chip, WM8785_R7, 0); | 149 | wm8785_write(chip, WM8785_R7, 0); |
139 | wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE | | 150 | wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]); |
140 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST); | 151 | wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]); |
141 | wm8785_write(chip, WM8785_R1, WM8785_WL_24); | 152 | |
142 | snd_component_add(chip->card, "WM8785"); | 153 | snd_component_add(chip->card, "WM8785"); |
143 | } | 154 | } |
144 | 155 | ||
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 6c6efede4d2f..29c9fa4964b2 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -80,6 +80,12 @@ struct oxygen { | |||
80 | struct work_struct spdif_input_bits_work; | 80 | struct work_struct spdif_input_bits_work; |
81 | struct work_struct gpio_work; | 81 | struct work_struct gpio_work; |
82 | wait_queue_head_t ac97_waitqueue; | 82 | wait_queue_head_t ac97_waitqueue; |
83 | union { | ||
84 | u8 _8[OXYGEN_IO_SIZE]; | ||
85 | __le16 _16[OXYGEN_IO_SIZE / 2]; | ||
86 | __le32 _32[OXYGEN_IO_SIZE / 4]; | ||
87 | } saved_registers; | ||
88 | u16 saved_ac97_registers[2][0x40]; | ||
83 | }; | 89 | }; |
84 | 90 | ||
85 | struct oxygen_model { | 91 | struct oxygen_model { |
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 5569606ee87f..83f135f80df4 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c | |||
@@ -44,18 +44,21 @@ EXPORT_SYMBOL(oxygen_read32); | |||
44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) | 44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) |
45 | { | 45 | { |
46 | outb(value, chip->addr + reg); | 46 | outb(value, chip->addr + reg); |
47 | chip->saved_registers._8[reg] = value; | ||
47 | } | 48 | } |
48 | EXPORT_SYMBOL(oxygen_write8); | 49 | EXPORT_SYMBOL(oxygen_write8); |
49 | 50 | ||
50 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) | 51 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) |
51 | { | 52 | { |
52 | outw(value, chip->addr + reg); | 53 | outw(value, chip->addr + reg); |
54 | chip->saved_registers._16[reg / 2] = cpu_to_le16(value); | ||
53 | } | 55 | } |
54 | EXPORT_SYMBOL(oxygen_write16); | 56 | EXPORT_SYMBOL(oxygen_write16); |
55 | 57 | ||
56 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) | 58 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) |
57 | { | 59 | { |
58 | outl(value, chip->addr + reg); | 60 | outl(value, chip->addr + reg); |
61 | chip->saved_registers._32[reg / 4] = cpu_to_le32(value); | ||
59 | } | 62 | } |
60 | EXPORT_SYMBOL(oxygen_write32); | 63 | EXPORT_SYMBOL(oxygen_write32); |
61 | 64 | ||
@@ -63,7 +66,10 @@ void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, | |||
63 | u8 value, u8 mask) | 66 | u8 value, u8 mask) |
64 | { | 67 | { |
65 | u8 tmp = inb(chip->addr + reg); | 68 | u8 tmp = inb(chip->addr + reg); |
66 | outb((tmp & ~mask) | (value & mask), chip->addr + reg); | 69 | tmp &= ~mask; |
70 | tmp |= value & mask; | ||
71 | outb(tmp, chip->addr + reg); | ||
72 | chip->saved_registers._8[reg] = tmp; | ||
67 | } | 73 | } |
68 | EXPORT_SYMBOL(oxygen_write8_masked); | 74 | EXPORT_SYMBOL(oxygen_write8_masked); |
69 | 75 | ||
@@ -71,7 +77,10 @@ void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, | |||
71 | u16 value, u16 mask) | 77 | u16 value, u16 mask) |
72 | { | 78 | { |
73 | u16 tmp = inw(chip->addr + reg); | 79 | u16 tmp = inw(chip->addr + reg); |
74 | outw((tmp & ~mask) | (value & mask), chip->addr + reg); | 80 | tmp &= ~mask; |
81 | tmp |= value & mask; | ||
82 | outw(tmp, chip->addr + reg); | ||
83 | chip->saved_registers._16[reg / 2] = cpu_to_le16(tmp); | ||
75 | } | 84 | } |
76 | EXPORT_SYMBOL(oxygen_write16_masked); | 85 | EXPORT_SYMBOL(oxygen_write16_masked); |
77 | 86 | ||
@@ -79,7 +88,10 @@ void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, | |||
79 | u32 value, u32 mask) | 88 | u32 value, u32 mask) |
80 | { | 89 | { |
81 | u32 tmp = inl(chip->addr + reg); | 90 | u32 tmp = inl(chip->addr + reg); |
82 | outl((tmp & ~mask) | (value & mask), chip->addr + reg); | 91 | tmp &= ~mask; |
92 | tmp |= value & mask; | ||
93 | outl(tmp, chip->addr + reg); | ||
94 | chip->saved_registers._32[reg / 4] = cpu_to_le32(tmp); | ||
83 | } | 95 | } |
84 | EXPORT_SYMBOL(oxygen_write32_masked); | 96 | EXPORT_SYMBOL(oxygen_write32_masked); |
85 | 97 | ||
@@ -128,8 +140,10 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, | |||
128 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); | 140 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); |
129 | /* require two "completed" writes, just to be sure */ | 141 | /* require two "completed" writes, just to be sure */ |
130 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && | 142 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && |
131 | ++succeeded >= 2) | 143 | ++succeeded >= 2) { |
144 | chip->saved_ac97_registers[codec][index / 2] = data; | ||
132 | return; | 145 | return; |
146 | } | ||
133 | } | 147 | } |
134 | snd_printk(KERN_ERR "AC'97 write timeout\n"); | 148 | snd_printk(KERN_ERR "AC'97 write timeout\n"); |
135 | } | 149 | } |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 4618a622a296..110786b2e3b8 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -132,6 +132,9 @@ struct xonar_data { | |||
132 | u8 ext_power_int_reg; | 132 | u8 ext_power_int_reg; |
133 | u8 ext_power_bit; | 133 | u8 ext_power_bit; |
134 | u8 has_power; | 134 | u8 has_power; |
135 | u8 pcm1796_oversampling; | ||
136 | u8 cs4398_fm; | ||
137 | u8 cs4362a_fm; | ||
135 | }; | 138 | }; |
136 | 139 | ||
137 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, | 140 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, |
@@ -186,12 +189,13 @@ static void xonar_d2_init(struct oxygen *chip) | |||
186 | 189 | ||
187 | data->anti_pop_delay = 300; | 190 | data->anti_pop_delay = 300; |
188 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | 191 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; |
192 | data->pcm1796_oversampling = PCM1796_OS_64; | ||
189 | 193 | ||
190 | for (i = 0; i < 4; ++i) { | 194 | for (i = 0; i < 4; ++i) { |
191 | pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED | | 195 | pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED | |
192 | PCM1796_FMT_24_LJUST | PCM1796_ATLD); | 196 | PCM1796_FMT_24_LJUST | PCM1796_ATLD); |
193 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | 197 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); |
194 | pcm1796_write(chip, i, 20, PCM1796_OS_64); | 198 | pcm1796_write(chip, i, 20, data->pcm1796_oversampling); |
195 | pcm1796_write(chip, i, 21, 0); | 199 | pcm1796_write(chip, i, 21, 0); |
196 | pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */ | 200 | pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */ |
197 | pcm1796_write(chip, i, 17, 0x0f); | 201 | pcm1796_write(chip, i, 17, 0x0f); |
@@ -226,6 +230,9 @@ static void xonar_dx_init(struct oxygen *chip) | |||
226 | data->ext_power_reg = OXYGEN_GPI_DATA; | 230 | data->ext_power_reg = OXYGEN_GPI_DATA; |
227 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 231 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
228 | data->ext_power_bit = GPI_DX_EXT_POWER; | 232 | data->ext_power_bit = GPI_DX_EXT_POWER; |
233 | data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; | ||
234 | data->cs4362a_fm = CS4362A_FM_SINGLE | | ||
235 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | ||
229 | 236 | ||
230 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 237 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, |
231 | OXYGEN_2WIRE_LENGTH_8 | | 238 | OXYGEN_2WIRE_LENGTH_8 | |
@@ -236,8 +243,7 @@ static void xonar_dx_init(struct oxygen *chip) | |||
236 | cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); | 243 | cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); |
237 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); | 244 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); |
238 | /* configure */ | 245 | /* configure */ |
239 | cs4398_write(chip, 2, CS4398_FM_SINGLE | | 246 | cs4398_write(chip, 2, data->cs4398_fm); |
240 | CS4398_DEM_NONE | CS4398_DIF_LJUST); | ||
241 | cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); | 247 | cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); |
242 | cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE); | 248 | cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE); |
243 | cs4398_write(chip, 5, 0xfe); | 249 | cs4398_write(chip, 5, 0xfe); |
@@ -249,16 +255,13 @@ static void xonar_dx_init(struct oxygen *chip) | |||
249 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); | 255 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); |
250 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); | 256 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); |
251 | cs4362a_write(chip, 0x05, 0); | 257 | cs4362a_write(chip, 0x05, 0); |
252 | cs4362a_write(chip, 0x06, CS4362A_FM_SINGLE | | 258 | cs4362a_write(chip, 0x06, data->cs4362a_fm); |
253 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
254 | cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE); | 259 | cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE); |
255 | cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE); | 260 | cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE); |
256 | cs4362a_write(chip, 0x09, CS4362A_FM_SINGLE | | 261 | cs4362a_write(chip, 0x09, data->cs4362a_fm); |
257 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
258 | cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE); | 262 | cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE); |
259 | cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE); | 263 | cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE); |
260 | cs4362a_write(chip, 0x0c, CS4362A_FM_SINGLE | | 264 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); |
261 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
262 | cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE); | 265 | cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE); |
263 | cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE); | 266 | cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE); |
264 | /* clear power down */ | 267 | /* clear power down */ |
@@ -294,12 +297,13 @@ static void xonar_dx_cleanup(struct oxygen *chip) | |||
294 | static void set_pcm1796_params(struct oxygen *chip, | 297 | static void set_pcm1796_params(struct oxygen *chip, |
295 | struct snd_pcm_hw_params *params) | 298 | struct snd_pcm_hw_params *params) |
296 | { | 299 | { |
300 | struct xonar_data *data = chip->model_data; | ||
297 | unsigned int i; | 301 | unsigned int i; |
298 | u8 value; | ||
299 | 302 | ||
300 | value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | 303 | data->pcm1796_oversampling = |
304 | params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | ||
301 | for (i = 0; i < 4; ++i) | 305 | for (i = 0; i < 4; ++i) |
302 | pcm1796_write(chip, i, 20, value); | 306 | pcm1796_write(chip, i, 20, data->pcm1796_oversampling); |
303 | } | 307 | } |
304 | 308 | ||
305 | static void update_pcm1796_volume(struct oxygen *chip) | 309 | static void update_pcm1796_volume(struct oxygen *chip) |
@@ -342,24 +346,24 @@ static void set_cs53x1_params(struct oxygen *chip, | |||
342 | static void set_cs43xx_params(struct oxygen *chip, | 346 | static void set_cs43xx_params(struct oxygen *chip, |
343 | struct snd_pcm_hw_params *params) | 347 | struct snd_pcm_hw_params *params) |
344 | { | 348 | { |
345 | u8 fm_cs4398, fm_cs4362a; | 349 | struct xonar_data *data = chip->model_data; |
346 | 350 | ||
347 | fm_cs4398 = CS4398_DEM_NONE | CS4398_DIF_LJUST; | 351 | data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; |
348 | fm_cs4362a = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | 352 | data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
349 | if (params_rate(params) <= 50000) { | 353 | if (params_rate(params) <= 50000) { |
350 | fm_cs4398 |= CS4398_FM_SINGLE; | 354 | data->cs4398_fm |= CS4398_FM_SINGLE; |
351 | fm_cs4362a |= CS4362A_FM_SINGLE; | 355 | data->cs4362a_fm |= CS4362A_FM_SINGLE; |
352 | } else if (params_rate(params) <= 100000) { | 356 | } else if (params_rate(params) <= 100000) { |
353 | fm_cs4398 |= CS4398_FM_DOUBLE; | 357 | data->cs4398_fm |= CS4398_FM_DOUBLE; |
354 | fm_cs4362a |= CS4362A_FM_DOUBLE; | 358 | data->cs4362a_fm |= CS4362A_FM_DOUBLE; |
355 | } else { | 359 | } else { |
356 | fm_cs4398 |= CS4398_FM_QUAD; | 360 | data->cs4398_fm |= CS4398_FM_QUAD; |
357 | fm_cs4362a |= CS4362A_FM_QUAD; | 361 | data->cs4362a_fm |= CS4362A_FM_QUAD; |
358 | } | 362 | } |
359 | cs4398_write(chip, 2, fm_cs4398); | 363 | cs4398_write(chip, 2, data->cs4398_fm); |
360 | cs4362a_write(chip, 0x06, fm_cs4362a); | 364 | cs4362a_write(chip, 0x06, data->cs4362a_fm); |
361 | cs4362a_write(chip, 0x09, fm_cs4362a); | 365 | cs4362a_write(chip, 0x09, data->cs4362a_fm); |
362 | cs4362a_write(chip, 0x0c, fm_cs4362a); | 366 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); |
363 | } | 367 | } |
364 | 368 | ||
365 | static void update_cs4362a_volumes(struct oxygen *chip) | 369 | static void update_cs4362a_volumes(struct oxygen *chip) |