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

📄 uda1341_c.txt

📁 2410uda1341的测试代码
💻 TXT
📖 第 1 页 / 共 2 页
字号:
/*
 * Philips UDA1341 mixer device driver
 *
 * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
 *
 * Portions are Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License.
 *
 * History:
 *
 * 2000-05-21	Nicolas Pitre	Initial release.
 *
 * 2000-08-19	Erik Bunce	More inline w/ OSS API and UDA1341 docs
 * 				including fixed AGC and audio source handling
 *
 * 2000-11-30	Nicolas Pitre	- More mixer functionalities.
 *
 * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on
 * 				the former sa1100-uda1341.c driver.
 *
 * 2001-08-13	Russell King	Re-written as part of the L3 interface
 */

//#define DEBUG 1
#include "debug.h"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/err.h>

#include "l3.h"
#include "uda1341.h"

#include <sound/driver.h>
#include <sound/core.h>
#include <sound/control.h>

#ifdef DEBUG
#undef pr_debug
#define pr_debug(fmt,arg...) printk(fmt,##arg)
#endif

/*
 * UDA1341 L3 address and command types
 */
#define UDA1341_L3ADDR		5
#define UDA1341_DATA0		(UDA1341_L3ADDR << 2 | 0)
#define UDA1341_DATA1		(UDA1341_L3ADDR << 2 | 1)
#define UDA1341_STATUS		(UDA1341_L3ADDR << 2 | 2)

struct uda1341_regs {
	unsigned char	stat0;
	char            dirty0;
#define STAT0			0x00
#define STAT0_RST		(1 << 6)
#define STAT0_SC_MASK		(3 << 4)
#define STAT0_SC_512FS		(0 << 4)
#define STAT0_SC_384FS		(1 << 4)
#define STAT0_SC_256FS		(2 << 4)
#define STAT0_IF_MASK		(7 << 1)
#define STAT0_IF_I2S		(0 << 1)
#define STAT0_IF_LSB16		(1 << 1)
#define STAT0_IF_LSB18		(2 << 1)
#define STAT0_IF_LSB20		(3 << 1)
#define STAT0_IF_MSB		(4 << 1)
#define STAT0_IF_LSB16MSB	(5 << 1)
#define STAT0_IF_LSB18MSB	(6 << 1)
#define STAT0_IF_LSB20MSB	(7 << 1)
#define STAT0_DC_FILTER		(1 << 0)

	unsigned char	stat1;
	char            dirty1;
#define STAT1			0x80
#define STAT1_DAC_GAIN		(1 << 6)	/* gain of DAC */
#define STAT1_ADC_GAIN		(1 << 5)	/* gain of ADC */
#define STAT1_ADC_POL		(1 << 4)	/* polarity of ADC */
#define STAT1_DAC_POL		(1 << 3)	/* polarity of DAC */
#define STAT1_DBL_SPD		(1 << 2)	/* double speed playback */
#define STAT1_ADC_ON		(1 << 1)	/* ADC powered */
#define STAT1_DAC_ON		(1 << 0)	/* DAC powered */

	unsigned char	data0[9];
	char            dirty[9];
#define REGDIR0	0
#define REGDIR1	1
#define REGDIR2	2
#define REGEXT0	3
#define REGEXT1	4
#define REGEXT2	5
#define REGEXT4	6
#define REGEXT5	7
#define REGEXT6	8

#define DIR0			0x00
#define DATA0_VOLUME_MASK	0x3f
#define DATA0_VOLUME(x)		(x)

#define DIR1			0x40
#define DATA1_BASS(x)		((x) << 2)
#define DATA1_BASS_MASK		(15 << 2)
#define DATA1_TREBLE(x)		((x))
#define DATA1_TREBLE_MASK	(3)

#define DIR2			0x80
#define DATA2_PEAKAFTER		(1 << 5)
#define DATA2_DEEMP_NONE	(0 << 3)
#define DATA2_DEEMP_32KHz	(1 << 3)
#define DATA2_DEEMP_44KHz	(2 << 3)
#define DATA2_DEEMP_48KHz	(3 << 3)
#define DATA2_MUTE		(1 << 2)
#define DATA2_FILTER_FLAT	(0 << 0)
#define DATA2_FILTER_MIN	(1 << 0)
#define DATA2_FILTER_MAX	(3 << 0)

#define EXTADDR(n)		(0xc0 | (n))
#define EXTDATA(d)		(0xe0 | (d))

#define EXT0			0
#define EXT0_CH1_GAIN(x)	(x)

#define EXT1			1
#define EXT1_CH2_GAIN(x)	(x)

#define EXT2			2
#define EXT2_MIC_GAIN_MASK	(7 << 2)
#define EXT2_MIC_GAIN(x)	((x) << 2)
#define EXT2_MIXMODE_DOUBLEDIFF	(0)
#define EXT2_MIXMODE_CH1	(1)
#define EXT2_MIXMODE_CH2	(2)
#define EXT2_MIXMODE_MIX	(3)

#define EXT4			4
#define EXT4_AGC_ENABLE		(1 << 4)
#define EXT4_INPUT_GAIN_MASK	(3)
#define EXT4_INPUT_GAIN(x)	((x) & 3)

#define EXT5			5
#define EXT5_INPUT_GAIN(x)	((x) >> 2)

#define EXT6			6
#define EXT6_AGC_CONSTANT_MASK	(7 << 2)
#define EXT6_AGC_CONSTANT(x)	((x) << 2)
#define EXT6_AGC_LEVEL_MASK	(3)
#define EXT6_AGC_LEVEL(x)	(x)
};

struct uda1341 {
	spinlock_t		lock;
	int			active;
	struct l3_adapter	*l3_bus;
	struct uda1341_regs	regs;
};

static const unsigned char regv[] = {
	[REGDIR0] = DIR0,
	[REGDIR1] = DIR1,
	[REGDIR2] = DIR2,
	[REGEXT0] = EXT0,
	[REGEXT1] = EXT1,
	[REGEXT2] = EXT2,
	[REGEXT4] = EXT4,
	[REGEXT5] = EXT5,
	[REGEXT6] = EXT6
};

static inline unsigned char *uda1341_add_reg(struct uda1341 *uda, unsigned char *p, int ctl)
{
	pr_debug("--- %s\n", __FUNCTION__);
	if (ctl < REGEXT0) {
		*p++ = regv[ctl] | uda->regs.data0[ctl];
	} else {
		*p++ = regv[ctl] | 0xc0;
		*p++ = uda->regs.data0[ctl] | 0xe0;
	}
	return p;
}

static void uda1341_sync(struct uda1341 *uda)
{
	unsigned char buf[24], *p = buf;
	int i;

	pr_debug(">>> %s\n", __FUNCTION__);

	if (uda->regs.dirty0) {
		*p++ = STAT0 | uda->regs.stat0;
		uda->regs.dirty0 = 0;
	}
	if (uda->regs.dirty1) {
		*p++ = STAT1 | uda->regs.stat1;
		uda->regs.dirty1 = 0;
	}

	if (p != buf)
		l3_write(uda->l3_bus, UDA1341_STATUS, buf, p - buf);

	
	p = buf;
	for(i=REGDIR0; i<=REGEXT6; i++) {
		if (uda->regs.dirty[i]) {
			p = uda1341_add_reg(uda, p, i);
			uda->regs.dirty[i] = 0;
		}
	}

	if (p != buf)
		l3_write(uda->l3_bus, UDA1341_DATA0, buf, p - buf);
}

int uda1341_configure(struct uda1341 *uda, struct uda1341_cfg *conf)
{
	int ret = 0;

	pr_debug(">>> %s\n", __FUNCTION__);

	uda->regs.stat0 &= ~(STAT0_SC_MASK | STAT0_IF_MASK);

	switch (conf->fs) {
	case 512: uda->regs.stat0 |= STAT0_SC_512FS;	break;
	case 384: uda->regs.stat0 |= STAT0_SC_384FS;	break;
	case 256: uda->regs.stat0 |= STAT0_SC_256FS;	break;
	default:  ret = -EINVAL;			break;
	}

	switch (conf->format) {
	case FMT_I2S:		uda->regs.stat0 |= STAT0_IF_I2S;	break;
	case FMT_LSB16:		uda->regs.stat0 |= STAT0_IF_LSB16;	break;
	case FMT_LSB18:		uda->regs.stat0 |= STAT0_IF_LSB18;	break;
	case FMT_LSB20:		uda->regs.stat0 |= STAT0_IF_LSB20;	break;
	case FMT_MSB:		uda->regs.stat0 |= STAT0_IF_MSB;	break;
	case FMT_LSB16MSB:	uda->regs.stat0 |= STAT0_IF_LSB16MSB;	break;
	case FMT_LSB18MSB:	uda->regs.stat0 |= STAT0_IF_LSB18MSB;	break;
	case FMT_LSB20MSB:	uda->regs.stat0 |= STAT0_IF_LSB20MSB;	break;
	default:		ret = -EINVAL;				break;
	}

	if (ret == 0) {
		unsigned char buf[2] ;

		buf[0] = uda->regs.stat0 | STAT0 | STAT0_DC_FILTER; //| STAT0_RST;
		buf[1] = uda->regs.stat1 | STAT1;
		if (conf->record) {
			buf[1] |= STAT1_ADC_ON;
		}
		if (conf->play) {
			buf[1] |= STAT1_DAC_ON;
		}
		pr_debug(">>> %s %d 0x%02x 0x%02x\n", __FUNCTION__, 1, buf[0], buf[1]);
		l3_write(uda->l3_bus, UDA1341_STATUS, buf, 2);
	}	
	return ret;
}
EXPORT_SYMBOL(uda1341_configure);

struct uda1341_ctl {
	const char *name;
	snd_kcontrol_new_t *ctl;
	unsigned char min;
	unsigned char max;
	unsigned char def;
	unsigned char reg;
	unsigned char mask;
	unsigned char off;
};

static int uda1341_ctl_simple_info(snd_kcontrol_t *kc, snd_ctl_elem_info_t *ei)
{
	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;

	pr_debug("--- %s\n", __FUNCTION__);
	ei->type = ctl->mask > 1 ? SNDRV_CTL_ELEM_TYPE_INTEGER :
				  SNDRV_CTL_ELEM_TYPE_BOOLEAN;
	ei->count = 1;
	if (ctl->min > ctl->max) {
		ei->value.integer.min = ctl->mask - ctl->min;
		ei->value.integer.max = ctl->mask - ctl->max;
	} else {
		ei->value.integer.min = ctl->min;
		ei->value.integer.max = ctl->max;
	}
	return 0;
}

static int uda1341_ctl_simple_get(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev)
{
	struct uda1341 *uda = kc->private_data;
	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;
	unsigned int val;

	pr_debug("--- %s\n", __FUNCTION__);
	val = (uda->regs.data0[ctl->reg] >> ctl->off) & ctl->mask;
	if (ctl->min > ctl->max)
		val = ctl->mask - val;

	ev->value.integer.value[0] = val;

	return 0;
}

static int uda1341_ctl_simple_put(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev)
{
	struct uda1341 *uda = kc->private_data;
	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;
	unsigned int val = ev->value.integer.value[0] & ctl->mask;

	pr_debug(">>> %s: %s\n", __FUNCTION__, ctl->name);

	if (ctl->reg == 0xff) {
	  printk("BUG @ %s: %s ... plaease report!\n", __FUNCTION__, ctl->name);
	}

	if (ctl->min > ctl->max)
		val = ctl->mask - val;

	spin_lock(&uda->lock);
	uda->regs.data0[ctl->reg] &= ~(ctl->mask << ctl->off);
	uda->regs.data0[ctl->reg] |= val << ctl->off;
	spin_unlock(&uda->lock);

	if (uda->active) {
		unsigned char buf[2], *p = buf;

		p = uda1341_add_reg(uda, buf, ctl->reg);

		pr_debug(">>> %s %d 0x%08x\n", __FUNCTION__, p-buf, buf[0]);
		l3_write(uda->l3_bus, UDA1341_DATA0, buf, p - buf);
	}
	else {
		uda->regs.dirty[ctl->reg] = 1;
	}

	return 0;
}

static int uda1341_ctl_stat1_get(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev)
{
	struct uda1341 *uda = kc->private_data;
	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;
	unsigned int val;

	pr_debug("--- %s\n", __FUNCTION__);
	val = (uda->regs.stat1 >> ctl->off) & ctl->mask;
	if (ctl->min > ctl->max)
		val = ctl->mask - val;

	ev->value.integer.value[0] = val;

	return 0;
}

static int uda1341_ctl_stat1_put(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev)
{
	struct uda1341 *uda = kc->private_data;
	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;
	unsigned int val = ev->value.integer.value[0] & ctl->mask;

	pr_debug(">>> %s\n", __FUNCTION__);

	if (ctl->min > ctl->max)
		val = ctl->mask - val;

	spin_lock(&uda->lock);
	uda->regs.stat1 &= ~(ctl->mask << ctl->off);
	uda->regs.stat1 |= val << ctl->off;
	uda->regs.dirty1 = 1;
	spin_unlock(&uda->lock);

	return 0;
}

static int uda1341_ctl_ch2ig_get(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev)
{
	struct uda1341 *uda = kc->private_data;
	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;
	unsigned int val;

	pr_debug("--- %s\n", __FUNCTION__);
	val = uda->regs.data0[REGEXT4] | 
		((uda->regs.data0[REGEXT5] & 31) << 2) ;
	if (ctl->min > ctl->max)
		val = ctl->mask - val;

	ev->value.integer.value[0] = val;

	return 0;
}

static int uda1341_ctl_ch2ig_put(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev)
{
	struct uda1341 *uda = kc->private_data;

⌨️ 快捷键说明

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