Commit b35a6301 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Jaroslav Kysela

[PATCH] ALSA update [1/12] - 2002/08/09

  - Corrections for PCM sample silence (24-bits)
  - OPL3 code fixes (delays)
  - CS4281
    - added the power management code
    - added mixer controls for internal FM and PCM volumes
  - EMU10K1
    - fixed the dma mask
  - ICE1712
    - replaced EREMOTE with EIO
    - check the return value from ews88mt_chip_select()
  - Maestro3
    - corrected the wrong pci id for inspiron 8000
    - use the quirk list for gpio workarounds
parent 1d819b9d
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc2"
#define CONFIG_SND_DATE " (Mon Aug 05 14:24:05 2002 UTC)"
#define CONFIG_SND_DATE " (Fri Aug 09 11:49:03 2002 UTC)"
......@@ -15,7 +15,7 @@
* 2002-04-04 Tomas Kasparek better rates handling (allow non-standard rates)
*/
/* $Id: sa11xx-uda1341.c,v 1.3 2002/05/25 10:26:06 perex Exp $ */
/* $Id: sa11xx-uda1341.c,v 1.4 2002/08/06 18:03:25 perex Exp $ */
#include <sound/driver.h>
#include <linux/module.h>
......
......@@ -460,7 +460,6 @@ static int __init snd_ioctl32_init(void)
return err;
}
#endif
return 0;
}
......
......@@ -329,6 +329,18 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
return 0x0000800000008000ULL;
case SNDRV_PCM_FORMAT_U32_BE:
return 0x0000008000000080ULL;
case SNDRV_PCM_FORMAT_U24_3LE:
return 0x0000800000800000ULL;
case SNDRV_PCM_FORMAT_U24_3BE:
return 0x0080000080000080ULL;
case SNDRV_PCM_FORMAT_U20_3LE:
return 0x0000080000080000ULL;
case SNDRV_PCM_FORMAT_U20_3BE:
return 0x0008000008000008ULL;
case SNDRV_PCM_FORMAT_U18_3LE:
return 0x0000020000020000ULL;
case SNDRV_PCM_FORMAT_U18_3BE:
return 0x0002000002000002ULL;
#else
case SNDRV_PCM_FORMAT_U16_LE:
return 0x0080008000800080ULL;
......@@ -342,16 +354,19 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
return 0x0080000000800000ULL;
case SNDRV_PCM_FORMAT_U32_BE:
return 0x8000000080000000ULL;
#endif
case SNDRV_PCM_FORMAT_U24_3LE:
return 0x0080000080000080ULL;
case SNDRV_PCM_FORMAT_U24_3BE:
return 0x0000800000800000ULL;
case SNDRV_PCM_FORMAT_U20_3LE:
return 0x0008000008000008ULL;
case SNDRV_PCM_FORMAT_U20_3BE:
return 0x0000080000080000ULL;
case SNDRV_PCM_FORMAT_U18_3LE:
return 0x0002000002000002ULL;
case SNDRV_PCM_FORMAT_U18_3BE:
return 0x0000020000020000ULL;
#endif
case SNDRV_PCM_FORMAT_FLOAT_LE:
{
union {
......@@ -471,11 +486,16 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
if (! silence)
memset(data, 0, samples * 3);
else {
/* FIXME: rewrite in the more better way.. */
int i;
while (samples-- > 0) {
for (i = 0; i < 3; i++)
*((u_int8_t *)data)++ = silence >> (i * 8);
#ifdef SNDRV_LITTLE_ENDIAN
*((u_int8_t *)data)++ = silence >> 0;
*((u_int8_t *)data)++ = silence >> 8;
*((u_int8_t *)data)++ = silence >> 16;
#else
*((u_int8_t *)data)++ = silence >> 16;
*((u_int8_t *)data)++ = silence >> 8;
*((u_int8_t *)data)++ = silence >> 0;
#endif
}
}
}
......
......@@ -1616,7 +1616,6 @@ int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream)
snd_assert(err >= 0, return -EINVAL);
err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
//err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
snd_assert(err >= 0, return -EINVAL);
err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);
......
......@@ -101,8 +101,10 @@ void snd_opl3_cs4281_command(opl3_t * opl3, unsigned short cmd, unsigned char va
spin_lock_irqsave(&opl3->reg_lock, flags);
writel((unsigned int)cmd, port << 2);
udelay(10);
writel((unsigned int)val, (port + 1) << 2);
udelay(30);
spin_unlock_irqrestore(&opl3->reg_lock, flags);
}
......
......@@ -6,7 +6,7 @@ comment 'PCI devices'
dep_tristate 'ALi PCI Audio M5451' CONFIG_SND_ALI5451 $CONFIG_SND
dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SND_CS46XX $CONFIG_SND
dep_mbool ' Cirrus Logic (Sound Fusion) New DSP support (EXPERIMENTAL)' CONFIG_SND_CS46XX_NEW_DSP $CONFIG_SND_CS46XX $CONFIG_EXPERIMENTAL
dep_tristate 'Cirrus Logic CS4281' CONFIG_SND_CS4281 $CONFIG_SND
dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND
dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
......
......@@ -362,6 +362,8 @@ MODULE_PARM_SYNTAX(snd_dual_codec, SNDRV_ENABLED ",allows:{{0,3}}");
#define BA0_SRCSA 0x075c /* SRC Slot Assignments */
#define BA0_PPLVC 0x0760 /* PCM Playback Left Volume Control */
#define BA0_PPRVC 0x0764 /* PCM Playback Right Volume Control */
#define BA0_PASR 0x0768 /* playback sample rate */
#define BA0_CASR 0x076C /* capture sample rate */
/* Source Slot Numbers - Playback */
#define SRCSLOT_LEFT_PCM_PLAYBACK 0
......@@ -465,6 +467,8 @@ struct snd_cs4281_dma {
int frag; /* period number */
};
#define SUSPEND_REGISTERS 20
struct snd_cs4281 {
int irq;
......@@ -506,6 +510,11 @@ struct snd_cs4281 {
snd_info_entry_t *proc_entry;
struct snd_cs4281_gameport *gameport;
#ifdef CONFIG_PM
u32 suspend_regs[SUSPEND_REGISTERS];
#endif
};
static void snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs);
......@@ -527,23 +536,35 @@ MODULE_DEVICE_TABLE(pci, snd_cs4281_ids);
* common I/O routines
*/
static void snd_cs4281_delay(unsigned int delay)
static void snd_cs4281_delay(unsigned int delay, int can_schedule)
{
if (delay > 999) {
signed long end_time;
delay = (delay * HZ) / 1000000;
if (delay < 1)
delay = 1;
end_time = jiffies + delay;
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
if (can_schedule) {
signed long end_time;
delay = (delay * HZ) / 1000000;
if (delay < 1)
delay = 1;
end_time = jiffies + delay;
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
} else
mdelay(delay);
} else {
udelay(delay);
}
}
inline static void snd_cs4281_delay_long(int can_schedule)
{
if (can_schedule) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} else
mdelay(1999 / HZ);
}
static inline void snd_cs4281_pokeBA0(cs4281_t *chip, unsigned long offset, unsigned int val)
{
writel(val, chip->ba0 + offset);
......@@ -717,6 +738,9 @@ static int snd_cs4281_trigger(snd_pcm_substream_t *substream, int cmd)
dma->valDMR &= ~(BA0_DMR_DMA|BA0_DMR_POLL);
dma->valDCR |= BA0_DCR_MSK;
dma->valFCR &= ~BA0_FCR_FEN;
/* Leave wave playback FIFO enabled for FM */
if (dma->regFCR != BA0_FCR0)
dma->valFCR &= ~BA0_FCR_FEN;
break;
default:
spin_unlock_irqrestore(&chip->reg_lock, flags);
......@@ -800,12 +824,18 @@ static void snd_cs4281_mode(cs4281_t *chip, cs4281_dma_t *dma, snd_pcm_runtime_t
}
}
__skip_src:
/* Deactivate wave playback FIFO before changing slot assignments */
if (dma->regFCR == BA0_FCR0)
snd_cs4281_pokeBA0(chip, dma->regFCR, snd_cs4281_peekBA0(chip, dma->regFCR) & ~BA0_FCR_FEN);
/* Initialize FIFO */
dma->valFCR = BA0_FCR_LS(dma->left_slot) |
BA0_FCR_RS(capture && (dma->valDMR & BA0_DMR_MONO) ? 31 : dma->right_slot) |
BA0_FCR_SZ(CS4281_FIFO_SIZE) |
BA0_FCR_OF(dma->fifo_offset);
snd_cs4281_pokeBA0(chip, dma->regFCR, dma->valFCR | (capture ? BA0_FCR_PSH : 0));
/* Activate FIFO again for FM playback */
if (dma->regFCR == BA0_FCR0)
snd_cs4281_pokeBA0(chip, dma->regFCR, dma->valFCR | BA0_FCR_FEN);
/* Clear FIFO Status and Interrupt Control Register */
snd_cs4281_pokeBA0(chip, dma->regFSIC, 0);
}
......@@ -855,7 +885,7 @@ static snd_pcm_uframes_t snd_cs4281_pointer(snd_pcm_substream_t * substream)
// printk("DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, jiffies);
return runtime->buffer_size -
snd_cs4281_peekBA0(chip, dma->regDCC);
snd_cs4281_peekBA0(chip, dma->regDCC) - 1;
}
static snd_pcm_hardware_t snd_cs4281_playback =
......@@ -1024,6 +1054,76 @@ static int __devinit snd_cs4281_pcm(cs4281_t * chip, int device, snd_pcm_t ** rp
* Mixer section
*/
#define CS_VOL_MASK 0x1f
static int snd_cs4281_info_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = CS_VOL_MASK;
return 0;
}
static int snd_cs4281_get_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
cs4281_t *chip = snd_kcontrol_chip(kcontrol);
int regL = (kcontrol->private_value >> 16) & 0xffff;
int regR = kcontrol->private_value & 0xffff;
int volL, volR;
volL = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regL) & CS_VOL_MASK);
volR = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regR) & CS_VOL_MASK);
ucontrol->value.integer.value[0] = volL;
ucontrol->value.integer.value[1] = volR;
return 0;
}
static int snd_cs4281_put_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
cs4281_t *chip = snd_kcontrol_chip(kcontrol);
int change = 0;
int regL = (kcontrol->private_value >> 16) & 0xffff;
int regR = kcontrol->private_value & 0xffff;
int volL, volR;
volL = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regL) & CS_VOL_MASK);
volR = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regR) & CS_VOL_MASK);
if (ucontrol->value.integer.value[0] != volL) {
volL = CS_VOL_MASK - (ucontrol->value.integer.value[0] & CS_VOL_MASK);
snd_cs4281_pokeBA0(chip, regL, volL);
change = 1;
}
if (ucontrol->value.integer.value[0] != volL) {
volR = CS_VOL_MASK - (ucontrol->value.integer.value[1] & CS_VOL_MASK);
snd_cs4281_pokeBA0(chip, regR, volR);
change = 1;
}
return change;
}
static snd_kcontrol_new_t snd_cs4281_fm_vol =
{
iface: SNDRV_CTL_ELEM_IFACE_MIXER,
name: "Synth Playback Volume",
info: snd_cs4281_info_volume,
get: snd_cs4281_get_volume,
put: snd_cs4281_put_volume,
private_value: ((BA0_FMLVC << 16) | BA0_FMRVC),
};
static snd_kcontrol_new_t snd_cs4281_pcm_vol =
{
iface: SNDRV_CTL_ELEM_IFACE_MIXER,
name: "PCM Stream Playback Volume",
info: snd_cs4281_info_volume,
get: snd_cs4281_get_volume,
put: snd_cs4281_put_volume,
private_value: ((BA0_PPLVC << 16) | BA0_PPRVC),
};
static void snd_cs4281_mixer_free_ac97(ac97_t *ac97)
{
cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return);
......@@ -1051,11 +1151,16 @@ static int __devinit snd_cs4281_mixer(cs4281_t * chip)
if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97_secondary)) < 0)
return err;
}
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_fm_vol, chip))) < 0)
return err;
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_pcm_vol, chip))) < 0)
return err;
return 0;
}
/*
/*
* proc interface
*/
static void snd_cs4281_proc_read(snd_info_entry_t *entry,
......@@ -1337,14 +1442,18 @@ static int snd_cs4281_dev_free(snd_device_t *device)
return snd_cs4281_free(chip);
}
static int snd_cs4281_chip_init(cs4281_t *chip, int can_schedule); /* defined below */
#ifdef CONFIG_PM
static int snd_cs4281_set_power_state(snd_card_t *card, unsigned int power_state);
#endif
static int __devinit snd_cs4281_create(snd_card_t * card,
struct pci_dev *pci,
cs4281_t ** rchip,
struct pci_dev *pci,
cs4281_t ** rchip,
int dual_codec)
{
cs4281_t *chip;
unsigned int tmp;
signed long end_time;
int err;
static snd_device_ops_t ops = {
dev_free: snd_cs4281_dev_free,
......@@ -1393,13 +1502,39 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
return -ENOMEM;
}
tmp = snd_cs4281_chip_init(chip, 0);
if (tmp) {
snd_cs4281_free(chip);
return tmp;
}
snd_cs4281_proc_init(chip);
#ifdef CONFIG_PM
card->set_power_state = snd_cs4281_set_power_state;
card->power_state_private_data = chip;
#endif
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_cs4281_free(chip);
return err;
}
*rchip = chip;
return 0;
}
static int snd_cs4281_chip_init(cs4281_t *chip, int can_schedule)
{
unsigned int tmp;
int timeout;
tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);
if (tmp != BA0_CFLR_DEFAULT) {
snd_cs4281_pokeBA0(chip, BA0_CFLR, BA0_CFLR_DEFAULT);
tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);
if (tmp != BA0_CFLR_DEFAULT) {
snd_printk(KERN_ERR "CFLR setup failed (0x%x)\n", tmp);
snd_cs4281_free(chip);
return -EIO;
}
}
......@@ -1411,12 +1546,10 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC1)) != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) {
snd_printk(KERN_ERR "SERC1 AC'97 check failed (0x%x)\n", tmp);
snd_cs4281_free(chip);
return -EIO;
}
if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC2)) != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) {
snd_printk(KERN_ERR "SERC2 AC'97 check failed (0x%x)\n", tmp);
snd_cs4281_free(chip);
return -EIO;
}
......@@ -1445,7 +1578,7 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
snd_cs4281_pokeBA0(chip, BA0_SPMC, 0);
udelay(50);
snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN);
snd_cs4281_delay(50000);
snd_cs4281_delay(50000, can_schedule);
if (chip->dual_codec)
snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN | BA0_SPMC_ASDI2E);
......@@ -1461,13 +1594,13 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
* Start the DLL Clock logic.
*/
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_DLLP);
snd_cs4281_delay(50000);
snd_cs4281_delay(50000, can_schedule);
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_SWCE | BA0_CLKCR1_DLLP);
/*
* Wait for the DLL ready signal from the clock logic.
*/
end_time = (jiffies + HZ / 4) + 1;
timeout = HZ;
do {
/*
* Read the AC97 status register to see if we've seen a CODEC
......@@ -1475,12 +1608,10 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
*/
if (snd_cs4281_peekBA0(chip, BA0_CLKCR1) & BA0_CLKCR1_DLLRDY)
goto __ok0;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
snd_cs4281_delay_long(can_schedule);
} while (timeout-- > 0);
snd_printk(KERN_ERR "DLLRDY not seen\n");
snd_cs4281_free(chip);
return -EIO;
__ok0:
......@@ -1495,7 +1626,7 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
/*
* Wait for the codec ready signal from the AC97 codec.
*/
end_time = (jiffies + (3 * HZ) / 4) + 1;
timeout = HZ;
do {
/*
* Read the AC97 status register to see if we've seen a CODEC
......@@ -1503,23 +1634,20 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
*/
if (snd_cs4281_peekBA0(chip, BA0_ACSTS) & BA0_ACSTS_CRDY)
goto __ok1;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
snd_cs4281_delay_long(can_schedule);
} while (timeout-- > 0);
snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));
snd_cs4281_free(chip);
return -EIO;
__ok1:
if (chip->dual_codec) {
end_time = (jiffies + (3 * HZ) / 4) + 1;
timeout = HZ;
do {
if (snd_cs4281_peekBA0(chip, BA0_ACSTS2) & BA0_ACSTS_CRDY)
goto __codec2_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
snd_cs4281_delay_long(can_schedule);
} while (timeout-- > 0);
snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");
chip->dual_codec = 0;
__codec2_ok: ;
......@@ -1537,7 +1665,7 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
* the codec is pumping ADC data across the AC-link.
*/
end_time = (jiffies + (5 * HZ) / 4) + 1;
timeout = HZ;
do {
/*
* Read the input slot valid register and see if input slots 3
......@@ -1545,12 +1673,10 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
*/
if ((snd_cs4281_peekBA0(chip, BA0_ACISV) & (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) == (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4)))
goto __ok2;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (end_time - (signed long)jiffies >= 0);
snd_cs4281_delay_long(can_schedule);
} while (timeout-- > 0);
snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n");
snd_cs4281_free(chip);
return -EIO;
__ok2:
......@@ -1588,12 +1714,21 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
chip->src_left_rec_slot = 10; /* AC'97 left PCM record (3) */
chip->src_right_rec_slot = 11; /* AC'97 right PCM record (4) */
/* Activate wave playback FIFO for FM playback */
chip->dma[0].valFCR = BA0_FCR_FEN | BA0_FCR_LS(0) |
BA0_FCR_RS(1) |
BA0_FCR_SZ(CS4281_FIFO_SIZE) |
BA0_FCR_OF(chip->dma[0].fifo_offset);
snd_cs4281_pokeBA0(chip, chip->dma[0].regFCR, chip->dma[0].valFCR);
snd_cs4281_pokeBA0(chip, BA0_SRCSA, (chip->src_left_play_slot << 0) |
(chip->src_right_play_slot << 8) |
(chip->src_left_rec_slot << 16) |
(chip->src_right_rec_slot << 24));
/* Initialize digital volume */
snd_cs4281_pokeBA0(chip, BA0_PPLVC, 0);
snd_cs4281_pokeBA0(chip, BA0_PPRVC, 0);
snd_cs4281_proc_init(chip);
/* Enable IRQs */
snd_cs4281_pokeBA0(chip, BA0_HICR, BA0_HICR_EOI);
/* Unmask interrupts */
......@@ -1606,12 +1741,6 @@ static int __devinit snd_cs4281_create(snd_card_t * card,
BA0_HISR_DMA(3)));
synchronize_irq(chip->irq);
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_cs4281_free(chip);
return err;
}
*rchip = chip;
return 0;
}
......@@ -1917,22 +2046,180 @@ static int __devinit snd_cs4281_probe(struct pci_dev *pci,
return err;
}
pci_set_drvdata(pci, card);
pci_set_drvdata(pci, chip);
dev++;
return 0;
}
static void __devexit snd_cs4281_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
cs4281_t *chip = pci_get_drvdata(pci);
snd_card_free(chip->card);
pci_set_drvdata(pci, NULL);
}
/*
* Power Management
*/
#ifdef CONFIG_PM
static int saved_regs[SUSPEND_REGISTERS] = {
BA0_JSCTL,
BA0_GPIOR,
BA0_SSCR,
BA0_MIDCR,
BA0_SRCSA,
BA0_PASR,
BA0_CASR,
BA0_DACSR,
BA0_ADCSR,
BA0_FMLVC,
BA0_FMRVC,
BA0_PPLVC,
BA0_PPRVC,
};
#define number_of(array) (sizeof(array) / sizeof(array[0]))
#define CLKCR1_CKRA 0x00010000L
static void cs4281_suspend(cs4281_t *chip)
{
snd_card_t *card = chip->card;
u32 ulCLK;
int i;
snd_power_lock(card);
if (card->power_state == SNDRV_CTL_POWER_D3hot)
goto __skip;
snd_pcm_suspend_all(chip->pcm);
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK |= CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
/* Disable interrupts. */
snd_cs4281_pokeBA0(chip, BA0_HICR, BA0_HICR_CHGM);
/* remember the status registers */
for (i = 0; number_of(saved_regs); i++)
chip->suspend_regs[i] = snd_cs4281_peekBA0(chip, saved_regs[i]);
/* Turn off the serial ports. */
snd_cs4281_pokeBA0(chip, BA0_SERMC, 0);
/* Power off FM, Joystick, AC link, */
snd_cs4281_pokeBA0(chip, BA0_SSPM, 0);
/* DLL off. */
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, 0);
/* AC link off. */
snd_cs4281_pokeBA0(chip, BA0_SPMC, 0);
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK &= ~CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
__skip:
snd_power_unlock(card);
}
static void cs4281_resume(cs4281_t *chip)
{
snd_card_t *card = chip->card;
int i;
u32 ulCLK;
snd_power_lock(card);
if (card->power_state == SNDRV_CTL_POWER_D0)
goto __skip;
pci_enable_device(chip->pci);
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK |= CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
snd_cs4281_chip_init(chip, 0);
/* restore the status registers */
for (i = 0; number_of(saved_regs); i++)
snd_cs4281_pokeBA0(chip, saved_regs[i], chip->suspend_regs[i]);
if (chip->ac97)
snd_ac97_resume(chip->ac97);
if (chip->ac97_secondary)
snd_ac97_resume(chip->ac97_secondary);
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK &= ~CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
__skip:
snd_power_unlock(card);
}
#ifndef PCI_OLD_SUSPEND
static int snd_cs4281_suspend(struct pci_dev *dev, u32 state)
{
cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return -ENXIO);
cs4281_suspend(chip);
return 0;
}
static int snd_cs4281_resume(struct pci_dev *dev)
{
cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return -ENXIO);
cs4281_resume(chip);
return 0;
}
#else
static void snd_cs4281_suspend(struct pci_dev *dev)
{
cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return);
cs4281_suspend(chip);
}
static void snd_cs4281_resume(struct pci_dev *dev)
{
cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return);
cs4281_resume(chip);
}
#endif
/* callback */
static int snd_cs4281_set_power_state(snd_card_t *card, unsigned int power_state)
{
cs4281_t *chip = snd_magic_cast(cs4281_t, card->power_state_private_data, return -ENXIO);
switch (power_state) {
case SNDRV_CTL_POWER_D0:
case SNDRV_CTL_POWER_D1:
case SNDRV_CTL_POWER_D2:
cs4281_resume(chip);
break;
case SNDRV_CTL_POWER_D3hot:
case SNDRV_CTL_POWER_D3cold:
cs4281_suspend(chip);
break;
default:
return -EINVAL;
}
return 0;
}
#endif /* CONFIG_PM */
static struct pci_driver driver = {
name: "CS4281",
id_table: snd_cs4281_ids,
probe: snd_cs4281_probe,
remove: __devexit_p(snd_cs4281_remove),
#ifdef CONFIG_PM
suspend: snd_cs4281_suspend,
resume: snd_cs4281_resume,
#endif
};
static int __init alsa_card_cs4281_init(void)
......
......@@ -534,24 +534,31 @@ int __devinit snd_emu10k1_create(snd_card_t * card,
{
emu10k1_t *emu;
int err;
int is_audigy;
static snd_device_ops_t ops = {
dev_free: snd_emu10k1_dev_free,
};
*remu = NULL;
// is_audigy = (int)pci->driver_data;
is_audigy = (pci->device == 0x0004);
/* enable PCI device */
if ((err = pci_enable_device(pci)) < 0)
return err;
/* check, if we can restrict PCI DMA transfers to 31 bits */
if (!pci_dma_supported(pci, 0x7fffffff)) {
snd_printk("architecture does not support 31bit PCI busmaster DMA\n");
return -ENXIO;
/* set the DMA transfer mask */
if (is_audigy) {
if (pci_set_dma_mask(pci, 0xffffffff) < 0) {
snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
return -ENXIO;
}
} else {
if (pci_set_dma_mask(pci, 0x1fffffff) < 0) {
snd_printk(KERN_ERR "architecture does not support 29bit PCI busmaster DMA\n");
return -ENXIO;
}
}
if (pci_get_drvdata(pci))
pci_set_dma_mask(pci, 0xffffffff); /* audigy */
else
pci_set_dma_mask(pci, 0x7fffffff);
emu = snd_magic_kcalloc(emu10k1_t, 0, GFP_KERNEL);
if (emu == NULL)
......@@ -572,11 +579,8 @@ int __devinit snd_emu10k1_create(snd_card_t * card,
emu->get_synth_voice = NULL;
emu->port = pci_resource_start(pci, 0);
// emu->audigy = (int)pci->driver_data;
if (pci->device == 0x0004)
emu->audigy = 1;
if (emu->audigy)
emu->audigy = is_audigy;
if (is_audigy)
emu->gpr_base = A_FXGPREGBASE;
else
emu->gpr_base = FXGPREGBASE;
......
......@@ -960,17 +960,25 @@ static snd_i2c_bit_ops_t snd_ice1712_ewx_cs8427_bit_ops = {
};
/* AK4524 chip select; address 0x48 bit 0-3 */
static void snd_ice1712_ews88mt_chip_select(ice1712_t *ice, int chip_mask)
static int snd_ice1712_ews88mt_chip_select(ice1712_t *ice, int chip_mask)
{
unsigned char data, ndata;
snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return);
snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL);
snd_i2c_lock(ice->i2c);
snd_runtime_check(snd_i2c_readbytes(ice->pcf8574[1], &data, 1) == 1, snd_i2c_unlock(ice->i2c); return);
if (snd_i2c_readbytes(ice->pcf8574[1], &data, 1) != 1)
goto __error;
ndata = (data & 0xf0) | chip_mask;
if (ndata != data)
snd_runtime_check(snd_i2c_sendbytes(ice->pcf8574[1], &ndata, 1) == 1, snd_i2c_unlock(ice->i2c); return);
if (snd_i2c_sendbytes(ice->pcf8574[1], &ndata, 1) != 1)
goto __error;
snd_i2c_unlock(ice->i2c);
return 0;
__error:
snd_i2c_unlock(ice->i2c);
snd_printk(KERN_ERR "AK4524 chip select failed, check cable to the front module\n");
return -EIO;
}
/*
......@@ -988,7 +996,8 @@ static void snd_ice1712_ak4524_write(ice1712_t *ice, int chip,
if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_EWS88MT) {
/* assert AK4524 CS */
snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f);
if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0)
return;
//snd_ice1712_ews88mt_chip_select(ice, 0x0f);
}
......@@ -1147,11 +1156,11 @@ static int snd_ice1712_cs8427_set_input_clock(ice1712_t *ice, int spdif_clock)
snd_i2c_lock(ice->i2c);
if (snd_i2c_sendbytes(ice->cs8427, reg, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
if (snd_i2c_readbytes(ice->cs8427, &val, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
nval = val & 0xf0;
if (spdif_clock)
......@@ -1161,7 +1170,7 @@ static int snd_ice1712_cs8427_set_input_clock(ice1712_t *ice, int spdif_clock)
if (val != nval) {
reg[1] = nval;
if (snd_i2c_sendbytes(ice->cs8427, reg, 2) != 2) {
res = -EREMOTE;
res = -EIO;
} else {
res++;
}
......@@ -3187,7 +3196,7 @@ static int snd_ice1712_ews88mt_output_sense_get(snd_kcontrol_t *kcontrol, snd_ct
snd_i2c_lock(ice->i2c);
if (snd_i2c_readbytes(ice->pcf8574[1], &data, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
snd_i2c_unlock(ice->i2c);
ucontrol->value.enumerated.item[0] = data & ICE1712_EWS88MT_OUTPUT_SENSE ? 1 : 0; /* high = -10dBV, low = +4dBu */
......@@ -3203,12 +3212,12 @@ static int snd_ice1712_ews88mt_output_sense_put(snd_kcontrol_t *kcontrol, snd_ct
snd_i2c_lock(ice->i2c);
if (snd_i2c_readbytes(ice->pcf8574[1], &data, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0);
if (ndata != data && snd_i2c_sendbytes(ice->pcf8574[1], &ndata, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
snd_i2c_unlock(ice->i2c);
return ndata != data;
......@@ -3225,7 +3234,7 @@ static int snd_ice1712_ews88mt_input_sense_get(snd_kcontrol_t *kcontrol, snd_ctl
snd_i2c_lock(ice->i2c);
if (snd_i2c_readbytes(ice->pcf8574[0], &data, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
/* reversed; high = +4dBu, low = -10dBV */
ucontrol->value.enumerated.item[0] = data & (1 << channel) ? 0 : 1;
......@@ -3243,12 +3252,12 @@ static int snd_ice1712_ews88mt_input_sense_put(snd_kcontrol_t *kcontrol, snd_ctl
snd_i2c_lock(ice->i2c);
if (snd_i2c_readbytes(ice->pcf8574[0], &data, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel));
if (ndata != data && snd_i2c_sendbytes(ice->pcf8574[0], &ndata, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
snd_i2c_unlock(ice->i2c);
return ndata != data;
......@@ -3294,7 +3303,7 @@ static int snd_ice1712_ews88d_control_get(snd_kcontrol_t *kcontrol, snd_ctl_elem
snd_i2c_lock(ice->i2c);
if (snd_i2c_readbytes(ice->pcf8575, data, 2) != 2) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
snd_i2c_unlock(ice->i2c);
data[0] = (data[shift >> 3] >> (shift & 7)) & 0x01;
......@@ -3315,7 +3324,7 @@ static int snd_ice1712_ews88d_control_put(snd_kcontrol_t * kcontrol, snd_ctl_ele
snd_i2c_lock(ice->i2c);
if (snd_i2c_readbytes(ice->pcf8575, data, 2) != 2) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
ndata[shift >> 3] = data[shift >> 3] & ~(1 << (shift & 7));
if (invert) {
......@@ -3328,7 +3337,7 @@ static int snd_ice1712_ews88d_control_put(snd_kcontrol_t * kcontrol, snd_ctl_ele
change = (data[shift >> 3] != ndata[shift >> 3]);
if (change && snd_i2c_sendbytes(ice->pcf8575, data, 2) != 2) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
snd_i2c_unlock(ice->i2c);
return change;
......@@ -3366,7 +3375,7 @@ static int snd_ice1712_6fire_read_pca(ice1712_t *ice)
snd_i2c_sendbytes(ice->pcf8575, &byte, 1);
if (snd_i2c_readbytes(ice->pcf8575, &byte, 1) != 1) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
snd_i2c_unlock(ice->i2c);
return byte;
......@@ -3380,7 +3389,7 @@ static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char data)
bytes[1] = data;
if (snd_i2c_sendbytes(ice->pcf8575, bytes, 2) != 2) {
snd_i2c_unlock(ice->i2c);
return -EREMOTE;
return -EIO;
}
snd_i2c_unlock(ice->i2c);
return 0;
......@@ -3836,11 +3845,15 @@ static int __devinit snd_ice1712_chip_init(ice1712_t *ice)
}
/* second stage of initialization, analog parts and others */
switch (ice->eeprom.subvendor) {
case ICE1712_SUBDEVICE_EWS88MT:
/* Check if the front module is connected */
if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0)
return err;
/* Fall through */
case ICE1712_SUBDEVICE_DELTA66:
case ICE1712_SUBDEVICE_DELTA44:
case ICE1712_SUBDEVICE_AUDIOPHILE:
case ICE1712_SUBDEVICE_EWX2496:
case ICE1712_SUBDEVICE_EWS88MT:
case ICE1712_SUBDEVICE_DMX6FIRE:
snd_ice1712_ak4524_init(ice);
break;
......
......@@ -776,6 +776,14 @@ typedef struct snd_m3 m3_t;
#define chip_t m3_t
/* quirk lists */
struct m3_quirk {
u16 vendor, device; /* subsystem ids */
int amp_gpio; /* gpio pin # for external amp, -1 = default */
int irda_workaround; /* non-zero if avoid to touch 0x10 on GPIO_DIRECTION
(e.g. for IrDA on Dell Inspirons) */
};
struct m3_list {
int curlen;
int mem_addr;
......@@ -825,9 +833,7 @@ struct snd_m3 {
snd_pcm_t *pcm;
struct pci_dev *pci;
/* pci_dev in 2.2 kernel doesn't have them, so we keep them private */
u16 subsystem_vendor;
u16 subsystem_device;
struct m3_quirk *quirk;
int dacs_active;
int timer_users;
......@@ -908,6 +914,33 @@ static struct pci_device_id snd_m3_ids[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, snd_m3_ids);
static struct m3_quirk m3_quirk_list[] = {
/* panasonic CF-28 "toughbook" */
{
vendor: 0x10f7,
device: 0x833e,
amp_gpio: 0x0d,
},
/* Dell Inspiron 4000 */
{
vendor: 0x1028,
device: 0x00b0,
amp_gpio: -1,
irda_workaround: 1,
},
/* Dell Inspiron 8000 */
{
vendor: 0x1028,
device: 0x00a4,
amp_gpio: -1,
irda_workaround: 1,
},
/* FIXME: Inspiron 8100 and 8200 ids should be here, too */
/* END */
{ 0 }
};
/*
* lowlevel functions
*/
......@@ -1859,10 +1892,7 @@ static void snd_m3_ac97_reset(m3_t *chip, int busywait)
for (i = 0; i < 5; i++) {
dir = inw(io + GPIO_DIRECTION);
if (chip->subsystem_vendor == 0x1028 &&
chip->subsystem_device == 0x00b0) /* Dell Inspiron 4000 */
; /* seems conflicting with IrDA */
else
if (! chip->quirk || ! chip->quirk->irda_workaround)
dir |= 0x10; /* assuming pci bus master? */
snd_m3_remote_codec_config(io, 0);
......@@ -2470,6 +2500,8 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
{
m3_t *chip;
int i, err;
struct m3_quirk *quirk;
u16 subsystem_vendor, subsystem_device;
static snd_device_ops_t ops = {
dev_free: snd_m3_dev_free,
};
......@@ -2500,29 +2532,35 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
break;
}
chip->card = card;
chip->pci = pci;
chip->irq = -1;
#ifndef LINUX_2_2
chip->subsystem_vendor = pci->subsystem_vendor;
chip->subsystem_device = pci->subsystem_device;
subsystem_vendor = pci->subsystem_vendor;
subsystem_device = pci->subsystem_device;
#else
pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->subsystem_vendor);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->subsystem_device);
pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
#endif
for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
if (subsystem_vendor == quirk->vendor &&
subsystem_device == quirk->device) {
chip->quirk = quirk;
break;
}
}
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->external_amp = enable_amp;
if (amp_gpio >= 0 && amp_gpio <= 0x0f)
chip->amp_gpio = amp_gpio;
else if (chip->allegro_flag) {
/* panasonic CF-28 "toughbook" has different GPIO connection.. */
if (chip->subsystem_vendor == 0x10f7 &&
chip->subsystem_device == 0x833e)
chip->amp_gpio = 0x0d;
else
chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
} else
chip->amp_gpio = GPO_EXT_AMP_M3; /* presumably this is for all 'maestro3's.. */
else if (chip->quirk && chip->quirk->amp_gpio >= 0)
chip->amp_gpio = chip->quirk->amp_gpio;
else if (chip->allegro_flag)
chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
else /* presumably this is for all 'maestro3's.. */
chip->amp_gpio = GPO_EXT_AMP_M3;
chip->num_substreams = NR_DSPS;
chip->substreams = kmalloc(sizeof(m3_dma_t) * chip->num_substreams, GFP_KERNEL);
if (chip->substreams == NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment