⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at73c213.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	spin_unlock_irq(&chip->lock);	return 0;}static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	int change, retval;	unsigned short val;	if (ucontrol->value.integer.value[0])		val = mask;	else		val = 0;	if (invert)		val = mask - val;	val <<= shift;	spin_lock_irq(&chip->lock);	val |= (chip->reg_image[reg] & ~(mask << shift));	change = val != chip->reg_image[reg];	retval = snd_at73c213_write_reg(chip, reg, val);	spin_unlock_irq(&chip->lock);	if (retval)		return retval;	return change;}static int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xff) - 1;	return 0;}static int snd_at73c213_line_capture_volume_info(		struct snd_kcontrol *kcontrol,		struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	/* When inverted will give values 0x10001 => 0. */	uinfo->value.integer.min = 14;	uinfo->value.integer.max = 31;	return 0;}static int snd_at73c213_aux_capture_volume_info(		struct snd_kcontrol *kcontrol,		struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	/* When inverted will give values 0x10001 => 0. */	uinfo->value.integer.min = 14;	uinfo->value.integer.max = 31;	return 0;}#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert)	\{									\	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				\	.name = xname,							\	.index = xindex,						\	.info = snd_at73c213_mono_switch_info,				\	.get = snd_at73c213_mono_switch_get,				\	.put = snd_at73c213_mono_switch_put,				\	.private_value = (reg | (shift << 8) | (mask << 16) | (invert << 24)) \}#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \{									\	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				\	.name = xname,							\	.index = xindex,						\	.info = snd_at73c213_stereo_info,				\	.get = snd_at73c213_stereo_get,					\	.put = snd_at73c213_stereo_put,					\	.private_value = (left_reg | (right_reg << 8)			\			| (shift_left << 16) | (shift_right << 19)	\			| (mask << 24) | (invert << 22))		\}static struct snd_kcontrol_new snd_at73c213_controls[] __devinitdata = {AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1),AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1),AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1),AT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1),AT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV,		     0x01, 0),{	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,	.name	= "PA Playback Volume",	.index	= 0,	.info	= snd_at73c213_pa_volume_info,	.get	= snd_at73c213_mono_get,	.put	= snd_at73c213_mono_put,	.private_value	= PA_CTRL | (PA_CTRL_APAGAIN << 8) | \		(0x0f << 16) | (1 << 24),},AT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP,		     0x01, 1),AT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0),{	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,	.name	= "Aux Capture Volume",	.index	= 0,	.info	= snd_at73c213_aux_capture_volume_info,	.get	= snd_at73c213_mono_get,	.put	= snd_at73c213_mono_put,	.private_value	= DAC_AUXG | (0 << 8) | (0x1f << 16) | (1 << 24),},AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN,		     0x01, 0),{	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,	.name	= "Line Capture Volume",	.index	= 0,	.info	= snd_at73c213_line_capture_volume_info,	.get	= snd_at73c213_stereo_get,	.put	= snd_at73c213_stereo_put,	.private_value	= DAC_LLIG | (DAC_RLIG << 8) | (0 << 16) | (0 << 19)		| (0x1f << 24) | (1 << 22),},AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0),};static int __devinit snd_at73c213_mixer(struct snd_at73c213 *chip){	struct snd_card *card;	int errval, idx;	if (chip == NULL || chip->pcm == NULL)		return -EINVAL;	card = chip->card;	strcpy(card->mixername, chip->pcm->name);	for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) {		errval = snd_ctl_add(card,				snd_ctl_new1(&snd_at73c213_controls[idx],					chip));		if (errval < 0)			goto cleanup;	}	return 0;cleanup:	for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) {		struct snd_kcontrol *kctl;		kctl = snd_ctl_find_numid(card, idx);		if (kctl)			snd_ctl_remove(card, kctl);	}	return errval;}/* * Device functions */static int snd_at73c213_ssc_init(struct snd_at73c213 *chip){	/*	 * Continuous clock output.	 * Starts on falling TF.	 * Delay 1 cycle (1 bit).	 * Periode is 16 bit (16 - 1).	 */	ssc_writel(chip->ssc->regs, TCMR,			SSC_BF(TCMR_CKO, 1)			| SSC_BF(TCMR_START, 4)			| SSC_BF(TCMR_STTDLY, 1)			| SSC_BF(TCMR_PERIOD, 16 - 1));	/*	 * Data length is 16 bit (16 - 1).	 * Transmit MSB first.	 * Transmit 2 words each transfer.	 * Frame sync length is 16 bit (16 - 1).	 * Frame starts on negative pulse.	 */	ssc_writel(chip->ssc->regs, TFMR,			SSC_BF(TFMR_DATLEN, 16 - 1)			| SSC_BIT(TFMR_MSBF)			| SSC_BF(TFMR_DATNB, 1)			| SSC_BF(TFMR_FSLEN, 16 - 1)			| SSC_BF(TFMR_FSOS, 1));	return 0;}static int snd_at73c213_chip_init(struct snd_at73c213 *chip){	int retval;	unsigned char dac_ctrl = 0;	retval = snd_at73c213_set_bitrate(chip);	if (retval)		goto out;	/* Enable DAC master clock. */	clk_enable(chip->board->dac_clk);	/* Initialize at73c213 on SPI bus. */	retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04);	if (retval)		goto out_clk;	msleep(1);	retval = snd_at73c213_write_reg(chip, DAC_RST, 0x03);	if (retval)		goto out_clk;	/* Precharge everything. */	retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0xff);	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, PA_CTRL, (1<<PA_CTRL_APAPRECH));	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, DAC_CTRL,			(1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR));	if (retval)		goto out_clk;	msleep(50);	/* Stop precharging PA. */	retval = snd_at73c213_write_reg(chip, PA_CTRL,			(1<<PA_CTRL_APALP) | 0x0f);	if (retval)		goto out_clk;	msleep(450);	/* Stop precharging DAC, turn on master power. */	retval = snd_at73c213_write_reg(chip, DAC_PRECH, (1<<DAC_PRECH_ONMSTR));	if (retval)		goto out_clk;	msleep(1);	/* Turn on DAC. */	dac_ctrl = (1<<DAC_CTRL_ONDACL) | (1<<DAC_CTRL_ONDACR)		| (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR);	retval = snd_at73c213_write_reg(chip, DAC_CTRL, dac_ctrl);	if (retval)		goto out_clk;	/* Mute sound. */	retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f);	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f);	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f);	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f);	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11);	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11);	if (retval)		goto out_clk;	retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11);	if (retval)		goto out_clk;	/* Enable I2S device, i.e. clock output. */	ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN));	goto out;out_clk:	clk_disable(chip->board->dac_clk);out:	return retval;}static int snd_at73c213_dev_free(struct snd_device *device){	struct snd_at73c213 *chip = device->device_data;	ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));	if (chip->irq >= 0) {		free_irq(chip->irq, chip);		chip->irq = -1;	}	return 0;}static int __devinit snd_at73c213_dev_init(struct snd_card *card,					 struct spi_device *spi){	static struct snd_device_ops ops = {		.dev_free	= snd_at73c213_dev_free,	};	struct snd_at73c213 *chip = get_chip(card);	int irq, retval;	irq = chip->ssc->irq;	if (irq < 0)		return irq;	spin_lock_init(&chip->lock);	chip->card = card;	chip->irq = -1;	retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip);	if (retval) {		dev_dbg(&chip->spi->dev, "unable to request irq %d\n", irq);		goto out;	}	chip->irq = irq;	memcpy(&chip->reg_image, &snd_at73c213_original_image,			sizeof(snd_at73c213_original_image));	retval = snd_at73c213_ssc_init(chip);	if (retval)		goto out_irq;	retval = snd_at73c213_chip_init(chip);	if (retval)		goto out_irq;	retval = snd_at73c213_pcm_new(chip, 0);	if (retval)		goto out_irq;	retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);	if (retval)		goto out_irq;	retval = snd_at73c213_mixer(chip);	if (retval)		goto out_snd_dev;	snd_card_set_dev(card, &spi->dev);	goto out;out_snd_dev:	snd_device_free(card, chip);out_irq:	free_irq(chip->irq, chip);	chip->irq = -1;out:	return retval;}static int snd_at73c213_probe(struct spi_device *spi){	struct snd_card			*card;	struct snd_at73c213		*chip;	struct at73c213_board_info	*board;	int				retval;	char				id[16];	board = spi->dev.platform_data;	if (!board) {		dev_dbg(&spi->dev, "no platform_data\n");		return -ENXIO;	}	if (!board->dac_clk) {		dev_dbg(&spi->dev, "no DAC clk\n");		return -ENXIO;	}	if (IS_ERR(board->dac_clk)) {		dev_dbg(&spi->dev, "no DAC clk\n");		return PTR_ERR(board->dac_clk);	}	retval = -ENOMEM;	/* Allocate "card" using some unused identifiers. */	snprintf(id, sizeof id, "at73c213_%d", board->ssc_id);	card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213));	if (!card)		goto out;	chip = card->private_data;	chip->spi = spi;	chip->board = board;	chip->ssc = ssc_request(board->ssc_id);	if (IS_ERR(chip->ssc)) {		dev_dbg(&spi->dev, "could not get ssc%d device\n",				board->ssc_id);		retval = PTR_ERR(chip->ssc);		goto out_card;	}	retval = snd_at73c213_dev_init(card, spi);	if (retval)		goto out_ssc;	strcpy(card->driver, "at73c213");	strcpy(card->shortname, board->shortname);	sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq);	retval = snd_card_register(card);	if (retval)		goto out_ssc;	dev_set_drvdata(&spi->dev, card);	goto out;out_ssc:	ssc_free(chip->ssc);out_card:	snd_card_free(card);out:	return retval;}static int __devexit snd_at73c213_remove(struct spi_device *spi){	struct snd_card *card = dev_get_drvdata(&spi->dev);	struct snd_at73c213 *chip = card->private_data;	int retval;	/* Stop playback. */	ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));	/* Mute sound. */	retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f);	if (retval)		goto out;	retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f);	if (retval)		goto out;	retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f);	if (retval)		goto out;	retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f);	if (retval)		goto out;	retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11);	if (retval)		goto out;	retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11);	if (retval)		goto out;	retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11);	if (retval)		goto out;	/* Turn off PA. */	retval = snd_at73c213_write_reg(chip, PA_CTRL,					chip->reg_image[PA_CTRL] | 0x0f);	if (retval)		goto out;	msleep(10);	retval = snd_at73c213_write_reg(chip, PA_CTRL,					(1 << PA_CTRL_APALP) | 0x0f);	if (retval)		goto out;	/* Turn off external DAC. */	retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x0c);	if (retval)		goto out;	msleep(2);	retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x00);	if (retval)		goto out;	/* Turn off master power. */	retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0x00);	if (retval)		goto out;out:	/* Stop DAC master clock. */	clk_disable(chip->board->dac_clk);	ssc_free(chip->ssc);	snd_card_free(card);	dev_set_drvdata(&spi->dev, NULL);	return 0;}#ifdef CONFIG_PMstatic int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg){	struct snd_card *card = dev_get_drvdata(&spi->dev);	struct snd_at73c213 *chip = card->private_data;	ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));	clk_disable(chip->board->dac_clk);	return 0;}static int snd_at73c213_resume(struct spi_device *spi){	struct snd_card *card = dev_get_drvdata(&spi->dev);	struct snd_at73c213 *chip = card->private_data;	clk_enable(chip->board->dac_clk);	ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN));	return 0;}#else#define snd_at73c213_suspend NULL#define snd_at73c213_resume NULL#endifstatic struct spi_driver at73c213_driver = {	.driver		= {		.name	= "at73c213",	},	.probe		= snd_at73c213_probe,	.suspend	= snd_at73c213_suspend,	.resume		= snd_at73c213_resume,	.remove		= __devexit_p(snd_at73c213_remove),};static int __init at73c213_init(void){	return spi_register_driver(&at73c213_driver);}module_init(at73c213_init);static void __exit at73c213_exit(void){	spi_unregister_driver(&at73c213_driver);}module_exit(at73c213_exit);MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -