X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=sound%2Fisa%2Fcs423x%2Fcs4231_lib.c;h=521db705d179f94a3edcb6963773448e0ded2f09;hb=17489c058e8c63ab5ebdc67ab52ca70d1bc270b1;hp=642bdaa703be5b900d52e20589ebfba49305910c;hpb=e2340465ec9587362a057524d3e2163377366771;p=pandora-kernel.git diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 642bdaa703be..521db705d179 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Jaroslav Kysela * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips * * Bugs: @@ -24,7 +24,6 @@ * */ -#include #include #include #include @@ -39,7 +38,7 @@ #include #include -MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips"); MODULE_LICENSE("GPL"); @@ -74,7 +73,7 @@ static unsigned int rates[14] = { }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = 14, + .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; @@ -120,6 +119,42 @@ static unsigned char snd_cs4231_original_image[32] = 0x00, /* 1f/31 - cbrl */ }; +static unsigned char snd_opti93x_original_image[32] = +{ + 0x00, /* 00/00 - l_mixout_outctrl */ + 0x00, /* 01/01 - r_mixout_outctrl */ + 0x88, /* 02/02 - l_cd_inctrl */ + 0x88, /* 03/03 - r_cd_inctrl */ + 0x88, /* 04/04 - l_a1/fm_inctrl */ + 0x88, /* 05/05 - r_a1/fm_inctrl */ + 0x80, /* 06/06 - l_dac_inctrl */ + 0x80, /* 07/07 - r_dac_inctrl */ + 0x00, /* 08/08 - ply_dataform_reg */ + 0x00, /* 09/09 - if_conf */ + 0x00, /* 0a/10 - pin_ctrl */ + 0x00, /* 0b/11 - err_init_reg */ + 0x0a, /* 0c/12 - id_reg */ + 0x00, /* 0d/13 - reserved */ + 0x00, /* 0e/14 - ply_upcount_reg */ + 0x00, /* 0f/15 - ply_lowcount_reg */ + 0x88, /* 10/16 - reserved/l_a1_inctrl */ + 0x88, /* 11/17 - reserved/r_a1_inctrl */ + 0x88, /* 12/18 - l_line_inctrl */ + 0x88, /* 13/19 - r_line_inctrl */ + 0x88, /* 14/20 - l_mic_inctrl */ + 0x88, /* 15/21 - r_mic_inctrl */ + 0x80, /* 16/22 - l_out_outctrl */ + 0x80, /* 17/23 - r_out_outctrl */ + 0x00, /* 18/24 - reserved */ + 0x00, /* 19/25 - reserved */ + 0x00, /* 1a/26 - reserved */ + 0x00, /* 1b/27 - reserved */ + 0x00, /* 1c/28 - cap_dataform_reg */ + 0x00, /* 1d/29 - reserved */ + 0x00, /* 1e/30 - cap_upcount_reg */ + 0x00 /* 1f/31 - cap_lowcount_reg */ +}; + /* * Basic I/O functions */ @@ -134,29 +169,31 @@ static inline u8 cs4231_inb(struct snd_cs4231 *chip, u8 offset) return inb(chip->port + offset); } -static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, - unsigned char mask, unsigned char value) +static void snd_cs4231_wait(struct snd_cs4231 *chip) { int timeout; - unsigned char tmp; for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) udelay(100); +} + +static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, + unsigned char mask, unsigned char value) +{ + unsigned char tmp = (chip->image[reg] & mask) | value; + + snd_cs4231_wait(chip); #ifdef CONFIG_SND_DEBUG if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); #endif - if (chip->calibrate_mute) { - chip->image[reg] &= mask; - chip->image[reg] |= value; - } else { + chip->image[reg] = tmp; + if (!chip->calibrate_mute) { cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); - mb(); - tmp = (chip->image[reg] & mask) | value; + wmb(); cs4231_outb(chip, CS4231P(REG), tmp); - chip->image[reg] = tmp; mb(); } } @@ -176,12 +213,7 @@ static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) { - int timeout; - - for (timeout = 250; - timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + snd_cs4231_wait(chip); #ifdef CONFIG_SND_DEBUG if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); @@ -190,19 +222,13 @@ void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char va cs4231_outb(chip, CS4231P(REG), value); chip->image[reg] = value; mb(); -#if 0 - printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value); -#endif + snd_printdd("codec out - reg 0x%x = 0x%x\n", + chip->mce_bit | reg, value); } unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg) { - int timeout; - - for (timeout = 250; - timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + snd_cs4231_wait(chip); #ifdef CONFIG_SND_DEBUG if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("in: auto calibration time out - reg = 0x%x\n", reg); @@ -304,8 +330,7 @@ void snd_cs4231_mce_up(struct snd_cs4231 *chip) unsigned long flags; int timeout; - for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) - udelay(100); + snd_cs4231_wait(chip); #ifdef CONFIG_SND_DEBUG if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("mce_up - auto calibration time out (0)\n"); @@ -323,12 +348,11 @@ void snd_cs4231_mce_up(struct snd_cs4231 *chip) void snd_cs4231_mce_down(struct snd_cs4231 *chip) { unsigned long flags; + unsigned long end_time; int timeout; snd_cs4231_busy_wait(chip); -#if 0 - printk("(1) timeout = %i\n", timeout); -#endif + #ifdef CONFIG_SND_DEBUG if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL)); @@ -344,44 +368,43 @@ void snd_cs4231_mce_down(struct snd_cs4231 *chip) !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) { return; } - snd_cs4231_busy_wait(chip); - /* calibration process */ + /* + * Wait for (possible -- during init auto-calibration may not be set) + * calibration process to start. Needs upto 5 sample periods on AD1848 + * which at the slowest possible rate of 5.5125 kHz means 907 us. + */ + msleep(1); - for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--) - udelay(10); - if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { - snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); - return; - } -#if 0 - printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies); -#endif - /* in 10 ms increments, check condition, up to 250 ms */ - timeout = 25; - while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { - if (--timeout < 0) { - snd_printk("mce_down - auto calibration time out (2)\n"); + snd_printdd("(1) jiffies = %lu\n", jiffies); + + /* check condition up to 250 ms */ + end_time = jiffies + msecs_to_jiffies(250); + while (snd_cs4231_in(chip, CS4231_TEST_INIT) & + CS4231_CALIB_IN_PROGRESS) { + + if (time_after(jiffies, end_time)) { + snd_printk(KERN_ERR "mce_down - " + "auto calibration time out (2)\n"); return; } - msleep(10); + msleep(1); } -#if 0 - printk("(3) jiffies = %li\n", jiffies); -#endif - /* in 10 ms increments, check condition, up to 100 ms */ - timeout = 10; + + snd_printdd("(2) jiffies = %lu\n", jiffies); + + /* check condition up to 100 ms */ + end_time = jiffies + msecs_to_jiffies(100); while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { - if (--timeout < 0) { + if (time_after(jiffies, end_time)) { snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); return; } - msleep(10); + msleep(1); } -#if 0 - printk("(4) jiffies = %li\n", jiffies); - snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); -#endif + + snd_printdd("(3) jiffies = %lu\n", jiffies); + snd_printd("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); } static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size) @@ -459,11 +482,11 @@ static unsigned char snd_cs4231_get_rate(unsigned int rate) { int i; - for (i = 0; i < 14; i++) + for (i = 0; i < ARRAY_SIZE(rates); i++) if (rate == rates[i]) return freq_bits[i]; // snd_BUG(); - return freq_bits[13]; + return freq_bits[ARRAY_SIZE(rates) - 1]; } static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, @@ -908,7 +931,7 @@ static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream) return 0; } -static void snd_cs4231_overrange(struct snd_cs4231 *chip) +void snd_cs4231_overrange(struct snd_cs4231 *chip) { unsigned long flags; unsigned char res; @@ -1067,8 +1090,11 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip) chip->image[CS4231_IFACE_CTRL] = (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | (chip->single_dma ? CS4231_SINGLE_DMA : 0); - chip->image[CS4231_ALT_FEATURE_1] = 0x80; - chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; + if (chip->hardware != CS4231_HW_OPTI93X) { + chip->image[CS4231_ALT_FEATURE_1] = 0x80; + chip->image[CS4231_ALT_FEATURE_2] = + chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; + } ptr = (unsigned char *) &chip->image; snd_cs4231_mce_down(chip); spin_lock_irqsave(&chip->reg_lock, flags); @@ -1389,6 +1415,7 @@ const char *snd_cs4231_chip_id(struct snd_cs4231 *chip) case CS4231_HW_INTERWAVE: return "AMD InterWave"; case CS4231_HW_OPL3SA2: return chip->card->shortname; case CS4231_HW_AD1845: return "AD1845"; + case CS4231_HW_OPTI93X: return "OPTi 93x"; default: return "???"; } } @@ -1414,8 +1441,13 @@ static int snd_cs4231_new(struct snd_card *card, chip->rate_constraint = snd_cs4231_xrate; chip->set_playback_format = snd_cs4231_playback_format; chip->set_capture_format = snd_cs4231_capture_format; - memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); - + if (chip->hardware == CS4231_HW_OPTI93X) + memcpy(&chip->image, &snd_opti93x_original_image, + sizeof(snd_opti93x_original_image)); + else + memcpy(&chip->image, &snd_cs4231_original_image, + sizeof(snd_cs4231_original_image)); + *rchip = chip; return 0; } @@ -1803,6 +1835,48 @@ CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1) }; +static struct snd_kcontrol_new snd_opti93x_controls[] = { +CS4231_DOUBLE("Master Playback Switch", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), +CS4231_DOUBLE("Master Playback Volume", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), +CS4231_DOUBLE("PCM Playback Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +CS4231_DOUBLE("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), +CS4231_DOUBLE("FM Playback Switch", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("FM Playback Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), +CS4231_DOUBLE("Line Playback Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +CS4231_DOUBLE("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), +CS4231_DOUBLE("Mic Playback Switch", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("Mic Playback Volume", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), +CS4231_DOUBLE("Mic Boost", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), +CS4231_DOUBLE("CD Playback Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("CD Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), +CS4231_DOUBLE("Aux Playback Switch", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("Aux Playback Volume", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), +CS4231_DOUBLE("Capture Volume", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = snd_cs4231_info_mux, + .get = snd_cs4231_get_mux, + .put = snd_cs4231_put_mux, +} +}; + int snd_cs4231_mixer(struct snd_cs4231 *chip) { struct snd_card *card; @@ -1815,10 +1889,22 @@ int snd_cs4231_mixer(struct snd_cs4231 *chip) strcpy(card->mixername, chip->pcm->name); - for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip))) < 0) - return err; - } + if (chip->hardware == CS4231_HW_OPTI93X) + for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_opti93x_controls[idx], + chip)); + if (err < 0) + return err; + } + else + for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_cs4231_controls[idx], + chip)); + if (err < 0) + return err; + } return 0; } @@ -1828,6 +1914,7 @@ EXPORT_SYMBOL(snd_cs4236_ext_out); EXPORT_SYMBOL(snd_cs4236_ext_in); EXPORT_SYMBOL(snd_cs4231_mce_up); EXPORT_SYMBOL(snd_cs4231_mce_down); +EXPORT_SYMBOL(snd_cs4231_overrange); EXPORT_SYMBOL(snd_cs4231_interrupt); EXPORT_SYMBOL(snd_cs4231_chip_id); EXPORT_SYMBOL(snd_cs4231_create);