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

📄 wm8976.c

📁 这个代码是基于JADE X90+ wm8976 的 ALSA标准接口的驱动
💻 C
字号:
/* *  Routines for control of the TEA6330T circuit via i2c bus *  Sound fader control circuit for car radios by Philips Semiconductors *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> * * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#include <sound/driver.h>#include <linux/init.h>#include <linux/slab.h>#include <sound/core.h>#include <sound/wm8976.h>#include<asm/arch-x900/apb_i2c_module.h>#include <linux/delay.h>#include <sound/info.h>MODULE_AUTHOR("yolanda <zouzf@hotmail.com>");MODULE_DESCRIPTION("Routines for control of the wm8976 circuit via i2c bus");MODULE_LICENSE("GPL");#define WM8976_ADDR			(0x34>>1) /* fixed address */#define PIN_MASKBASE			0x20020000static unsigned char script_wm8976[][3] = //Lout1 SLAVE MODE with pll mckl=27MHz{	{0x34,0x00,0x00},//R0  0X000		   	{0x34,0x02,0x2d},//R1  0X02D		{0x34,0x05,0x91},//R2  0X191 	{0x34,0x06,0x0F},//R3  0X00F	{0x34,0x08,0x10},//R4  0X010	{0x34,0x0a,0x00},//R5  0X000#ifdef SLAVEMODE	{0x34,0x0d,0x4d},//R6  0X14d#else	{0x34,0x0d,0x4c},//R6  0X14c	 //set pll out#endif	{0x34,0x0e,0x00},//R7  0X00A     //set sample rate 48khz	{0x34,0x17,0xff},//R11 0X1ff	{0x34,0x19,0xff},//R12 0X1ff	{0x34,0x1F,0xff},//R15 0X1FF	{0x34,0x48,0x17},//R36 0X017	{0x34,0x4A,0x12},//R37 0X012	{0x34,0x4C,0x11},//R38 0X011	{0x34,0x4E,0x96},//R39 0X096	//set pll 12.288Mhz	{0x34,0x58,0x00},//R44 0X000	{0x34,0x5f,0x55},//R47 0X005	{0X34,0x62,0x02},//R49 0X002	{0x34,0x64,0x01},//R50 0X001	{0x34,0x66,0x01},//R51 0X001	{0x34,0x69,0x3f},//R52 0X13f	{0x34,0x6b,0x3f},//R53 0X13f};static int PinMask( int device , int enable ){	u32 mask;	int error = 0;	switch( device )	{	case 0:		// disable 656 out ( 68k clock ).		mask = (1<<14);		break;	case 1:		// i2c out		mask = 0x00000480;		break;	case 2:		mask = (1<<21);	// disable 656 out ( sensor clock enable)		break;	case 3:		// 68k enable( sci disable )		mask = (1<<15);		break;	default:		error = 1;	}	if( mask )	{		volatile int* pinmark = (volatile int*)ioremap( PIN_MASKBASE , 0x1000);		if( pinmark )		{			if( enable )				pinmark[0x10c/4] |= mask;			else				pinmark[0x10c/4] &= ~mask;			iounmap( (void*)pinmark );		}		else		{			error = 2;		}	}	return error;}unsigned char wm8976_for_close={0x34,0x02,0x0}; void jade_open(void){	unsigned int count,i;	 i2cInst* t;	      PinMask( 1 , 1 );       // enable i2c pin mask	 	   t =init_i2c();		   	count= sizeof(script_wm8976) / sizeof(script_wm8976[0]);		for( i=0; i<count; i++ )	        transmitData( 2 , &script_wm8976[i][1] , script_wm8976[i][0]/2 );	/* Wait for the wm8976 to wake up */	 mdelay(1);	dele_i2c(t); }void jade_close(wm8976_t *wm8976){	 i2cInst* t;	 unsigned char *wm8976_for_close={0x34,0x02,0x0};	t = init_i2c();	transmitData( 2 , &wm8976_for_close[1], 0x34/2 );	mdelay(1);		dele_i2c(t);}void jade_command(wm8976_t *wm8976,unsigned char * buffer){	i2cInst* t;		t=init_i2c();	transmitData( 2 , &buffer, 0x34/2 );		mdelay(1);		dele_i2c(t);}#define WM8976_MODE(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_wm8976_info_mode, \  .get = snd_wm8976_get_mode, .put = snd_wm8976_put_mode }static int snd_wm8976_info_mode(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int snd_wm8976_get_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);		ucontrol->value.integer.value[0] = wm->mode;		return 0;}static int snd_wm8976_put_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){     wm8976_t *wm = snd_kcontrol_chip(kcontrol);	int change, count;	unsigned char bytes[2];	unsigned char val1;		val1 =ucontrol->value.integer.value[0] ;	change = val1 != wm->mode;	wm->mode = val1;		count = 0;	bytes[count++] = CLK_GEN<<1;	if (change) 					bytes[count++] = 0x4c |(0 ^ val1);			jade_command(wm,bytes );			return change;}#define WM8976_BASS(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_wm8976_info_bass, \  .get = snd_wm8976_get_bass, .put = snd_wm8976_put_bass }static int snd_wm8976_info_bass(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int snd_wm8976_get_bass(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);		ucontrol->value.integer.value[0] = wm->bass;		return 0;}static int  snd_wm8976_put_bass(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);	int change, count;	unsigned char bytes_l[2];	unsigned char bytes_r[2];		unsigned char val1;		val1 =ucontrol->value.integer.value[0] ;	change = val1 != wm->bass;	wm->bass = val1;		count = 0;	bytes_l[count++] = LEFT_MIXER_CTL<<1;	bytes_r[count++] =RIGHT_MIXER_CTL<<1;		if (change) 	{				bytes_l[count++] = val1;						bytes_r[count++] = val1;			jade_command(wm,bytes_l );				jade_command(wm,bytes_r );		}	return change;}/* {{{ Proc interface */static void snd_wm8976_proc_read(snd_info_entry_t *entry, 				  snd_info_buffer_t * buffer){	 wm8976_t *clnt = entry->private_data;	 wm8976_t *uda = clnt->driver_data;		snd_iprintf(buffer, "%s\n\n", uda->card->longname);}static void __devinit snd_wm8976_proc_init(snd_card_t *card, struct wm8976_t *clnt){	snd_info_entry_t *entry;	if (! snd_card_proc_new(card, "wm8976", &entry))		snd_info_set_text_ops(entry, clnt, 1024, snd_wm8976_proc_read);	}/* }}} */#define WM8976_PLAYBACK_VOL(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_wm8976_info_playvol, \  .get = snd_wm8976_get_playvol, .put = snd_wm8976_put_playvol}static int snd_wm8976_info_playvol(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 =9;	return 0;}static int  snd_wm8976_get_playvol(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);		ucontrol->value.integer.value[0] = wm->play_vol;	}static int  snd_wm8976_put_playvol(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);	int change, count;	unsigned char bytes_l[2];	unsigned char bytes_r[2];		unsigned char val1;		val1 =ucontrol->value.integer.value[0] ;	change = val1 != wm->play_vol;	if (change) 		{			if  (val1 > wm->play_vol)							wm->play_vol =wm->play_vol << 1;						else 				wm->play_vol =wm->play_vol >> 1;				count = 0;		bytes_l[count++] = LDAC_VOL<<1 | 0x01;		bytes_r[count++] =RDAC_VOL<<1 | 0x01;				bytes_l[count++] = wm->play_vol ;		bytes_r[count++] = wm->play_vol ;		jade_command(wm,bytes_l);				jade_command(wm,bytes_r);		}	return change;}#define WM8976_CAPTURE_VOL(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_wm8976_info_capvol, \  .get = snd_wm8976_get_capvol, .put = snd_wm8976_put_capvol}static int snd_wm8976_info_capvol(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 =9;	return 0;}static int  snd_wm8976_get_capvol(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);		ucontrol->value.integer.value[0] = wm->record_vol;	}static int  snd_wm8976_put_capvol(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	 wm8976_t *wm = snd_kcontrol_chip(kcontrol);	int change, count;	unsigned char bytes[2];		unsigned char val1;		val1 =  ucontrol->value.integer.value[0];	change = val1 != wm->play_vol;	if (change) 	{		wm->record_vol = val1;		if  (val1 > wm->record_vol)							wm->record_vol =wm->record_vol << 1;					else 				wm->record_vol =wm->record_vol >> 1;						count = 0;	bytes[count++] = ADC_VOL<<1 | 0x01;	bytes[count++] = wm->record_vol;				jade_command(wm,bytes);					}	return change;}#define WM8976_RESET(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_wm8976_info_reset, \  .get = snd_wm8976_get_reset, .put = snd_wm8976_put_reset}static int snd_wm8976_info_reset(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int wm8976_dev_free(snd_device_t *device){	struct wm8976_t *clnt = device->device_data;	kfree(clnt);	return 0;}static int snd_wm8976_get_reset(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);		ucontrol->value.integer.value[0] = wm->reset;		return 0;}static int  snd_wm8976_put_reset(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	wm8976_t *wm = snd_kcontrol_chip(kcontrol);	int change, count, err;	unsigned char bytes[3];			unsigned char val1;		val1 =ucontrol->value.integer.value[0] ;	change = val1 != wm->reset;	wm->reset = val1;		count = 0;	bytes[count++] = SOFT_RESET<<1;			if (change) 	{		bytes[count++] = val1;		jade_command(wm,bytes);			}	return change;}static snd_kcontrol_new_t snd_wm8976_controls[] = {	WM8976_MODE("Master Slave Switch", 0),	WM8976_BASS("Bypass mode change", 0),	WM8976_PLAYBACK_VOL("Playback Vol control", 0),	WM8976_CAPTURE_VOL("Capture Vol control", 0),//	WM8976_SET_FORMAT("Digital Format ",0),	WM8976_RESET(" Soft Reset Codec",0)};int  snd_chip_wm8976_mixer_new(snd_card_t *card,struct wm8976_t **clnt){	static snd_device_ops_t ops = {		.dev_free =     wm8976_dev_free,	};	 wm8976_t *wm8976;	int idx, err;	snd_assert(card != NULL, return -EINVAL);	wm8976 = kzalloc(sizeof(*wm8976), GFP_KERNEL);	if (wm8976 == NULL)		return -ENOMEM;     	if ((err = snd_device_new(card, SNDRV_DEV_CODEC, wm8976, &ops)) < 0) {			kfree(wm8976);		return err;	}	for (idx = 0; idx < ARRAY_SIZE(snd_wm8976_controls); idx++) {		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_wm8976_controls[idx], wm8976))) < 0)			return err;	}	*clnt = wm8976;	strcpy(card->mixername, "WM8976 Mixer");	((wm8976_t *)wm8976->driver_data)->card = card;        	snd_wm8976_proc_init(card, wm8976);        	return 0;}EXPORT_SYMBOL(snd_chip_wm8976_mixer_new);EXPORT_SYMBOL(jade_open);EXPORT_SYMBOL(jade_close);EXPORT_SYMBOL(jade_command);/* *  INIT part */static int __init alsa_wm8976_init(void){	return 0;}static void __exit alsa_wm8976_exit(void){}module_init(alsa_wm8976_init)module_exit(alsa_wm8976_exit)

⌨️ 快捷键说明

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