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

📄 pxa-wm8971.c

📁 声音播放器新片驱动
💻 C
📖 第 1 页 / 共 3 页
字号:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/pm.h>
//#include <sound/driver.h>
//#include <sound/core.h>
//#include <sound/pcm.h>
//#include <sound/pcm_params.h>
//#include <sound/soc.h>
//#include <sound/soc-dpm.h>
//#include <sound/initval.h>
#include <linux/slab.h>#include <linux/pci.h>#include <linux/completion.h>#include <linux/poll.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/proc_fs.h>#include <asm-arm/arch-pxa/pxa-regs.h>
#include <asm/hardware.h>#include <asm/arch/ssp.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/arch/system.h>#include <asm/dma.h>

#include "wm8971.h"#include "pxa-audio.h"extern int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,u32 speed);

#define AUDIO_NAME "wm8971"
#define WM8971_VERSION "0.2"
#define CONFIG_PROC_FS

#define PFX AUDIO_NAME
#undef	WM8971_DEBUG

#ifdef WM8971_DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)


#define WM8971_2W_ADDR1			0x1a
#define	WM8971_2W_ADDR2			0x1b#define SSP_PORT2 (u32)2

#define I2C_DRIVERID_WM8971		0xfdfd		/* need to get a real ID */


static unsigned short normal_i2c[] = { WM8971_2W_ADDR1, WM8971_2W_ADDR2, I2C_CLIENT_END };
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };	/* (required for kernel 2.6.10) */


/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;

//static struct i2c_driver wm8971_i2c_driver;
//static struct i2c_client client_template;


#define	WM8971_REG_COUNT		43

/*
 * wm8971 register cache
 * We can't read the WM8971 register space when we 
 * are using 2 wire for device control, so we cache them instead. 
 */  	/*	0x32f0,0x3580,0x35f8,0x0097,0x0297,
	0x0440,0x0640,0x1400,0x1600,0x0579,
	0x0779,0x0a00,0x0e02,0x1000,0x15e0,
	0x17e0,0x180f,0x1a0f,0x227b,0x2400,
	0x2632,0x2800,0x2ac3,0x2cc3,0x2ec0,
	0x3050,0x3e00,0x4000,0x4200,0x4550,
	0x4650,0x4850,0x4b50,0x4c50,0x4e50,
	0x5179,0x5379,0x5479*/		
static u16 wm8971_reg[] = {
	0x0097, 0x0097, 0x0179, 0x0179,  /*  0 */
	0x0000, 0x0a00, 0x0000, 0x0e02,  /*  4 */
	0x0000, 0x0000, 0x01e0, 0x01ff,  /*  8 */
	0x000f, 0x000f, 0x0000, 0x0000,  /* 12 */
	0x0000, 0x007b, 0x0000, 0x0032,  /* 16 */
	0x0000, 0x00c3, 0x00c3, 0x00c0,  /* 20 */
	0x0000, 0x0000, 0x0000, 0x0000,  /* 24 */
	0x0000, 0x0000, 0x0000, 0x0000,  /* 28 */
	0x0000, 0x0000, 0x0050, 0x0050,  /* 32 */
	0x0050, 0x0150, 0x0050, 0x0050,  /* 36 */
	0x0179, 0x0179, 0x0079,          /* 40 */
};

/* OSS interface to WM8971 */#define WM8971_STEREO_MASK (SOUND_MASK_VOLUME | SOUND_MASK_IGAIN)#define WM8971_SUPPORTED_MASK (WM8971_STEREO_MASK | \	SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC)//#define WM8971_RECORD_MASK (SOUND_MASK_MIC | SOUND_MASK_IGAIN)
//add by tony 8/31

/* I2S sample rates */#define WM8971_I2S_8K		SADIV_513K#define WM8971_I2S_12K		SADIV_702K#define WM8971_I2S_16K		SADIV_1_026M#define WM8971_I2S_22K		SADIV_1_405M#define WM8971_I2S_44K		SADIV_2_836M#define WM8971_I2S_48K		12//SADIV_3_058M#define WM8971_I2S_441K		13//SADIV_3_058M//#define SSP_MODE_PSP 0x00000030
///////have not been configed/* SSP Port settings * We need to put the SSP port into 17bit mode because of corruption in* the MSB of the audio stream. The codec is in 16 bit mode and ignores * the corrupted bit 17. bug#1190412*/#define WM8971_SSP_MODE 	SSCR0_FRF | SSCR0_DSS | SSCR0_EDSS#define WM8971_SSP_SETUP 	SSCR1_RFT | SSCR1_TFT | SSCR1_TRAIL |SSCR1_TSRE | SSCR1_RSRE | SSCR1_TIE |SSCR1_RIE | SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_RWOT#define WM8971_SSP_PSP		SSPSP_SCMODE(3) | SSPSP_SFRMP#define WM8971_SSP_8K		101#define WM8971_SSP_12K		66#define WM8971_SSP_16K		50#define WM8971_SSP_24K		33#define WM8971_SSP_32K		24#define WM8971_SSP_48K		16#define WM8971_SSP_96K		7#define WM8971_SSP_44_1K
#define WM8971_DEFAULT_SRATE 48000//#define wm8971_reset(struct i2c_client *client)	wm8971_2w_write(client, WM8971_RESET, 0)static int wm8971_attach(struct i2c_adapter *adap, int addr, int kind);static int wm8971_detach(struct i2c_client *client);static int wm8971_probe(struct i2c_adapter *adap);static int wm8971_reset(struct i2c_client *client);static int wm8971_2w_write(struct i2c_client *client, u8 reg, u16 value);static int wm8971_psp_open(u8 speed);static int wm8971_i2s_open(int speed);static void wm8971_i2s_close(void);static int wm8971_set_adcdac_rate(int val);static u16 wm8971_read_reg_cache(u8 reg);static void wm8971_write_reg_cache(u8 reg, u16 value);static int wm8971_init(void);//static int wm8971_init_pll(void);static int wm8971_get_mixer(int cmd);static int wm8971_set_mixer(int cmd, int val);static int wm8971_mixer_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int wm8971_power_up(void);static int wm8971_power_down(void);#ifdef CONFIG_PMstatic int wm8971_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);static void wm8971_suspend(void);static void wm8971_resume(void);#endif#ifdef CONFIG_PROC_FSstatic int wm8971_read_proc (char *page, char **start, off_t off,		    int count, int *eof, void *data);#endifstatic struct i2c_driver wm8971_driver;//static struct i2c_client wm8971_client;
struct WM8971_codec_t {	char * name;
	//char * longname;
	//int (*probe)(struct i2c_adapter *adap);
	//int (*read)(u8 reg);
	//int (*write)(struct i2c_client *client, u8 reg, u16 value);	int modcnt;	int supported_mixers;	int stereo_mixers;	//int record_sources;	int codec_rate;	unsigned int mixer_state[SOUND_MIXER_NRDEVICES];#ifdef CONFIG_PROC_FS	struct proc_dir_entry * ps;#endif#ifdef CONFIG_PM	struct pm_dev* pdev;#endif	struct ssp_dev ssp;	int is_ssp_open:1;	struct i2c_client* wm8971_2w_client;};
//WM8971_codec_t.wm8971_2w_client->addr=WM8971_2W_ADDR1;
static struct WM8971_codec_t wm8971_codec = {	name: AUDIO_NAME,	modcnt: 0,	//probe:  wm8971_probe,	//read:  wm8971_read_reg_cache,	//write:  wm8971_2w_write,	codec_rate: WM8971_DEFAULT_SRATE,	supported_mixers:  WM8971_SUPPORTED_MASK,	stereo_mixers: WM8971_STEREO_MASK,  //record_sources: WM8971_RECORD_MASK,	is_ssp_open: 0,//	wm8971_2w_client: &wm8971_client,};void set_GPIO_mode(int gpio_mode){	int gpio = gpio_mode & GPIO_MD_MASK_NR;	int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;	int gafr;	if (gpio_mode & GPIO_MD_MASK_DIR)	{		GPDR(gpio) |= GPIO_bit(gpio);	}	else	{		GPDR(gpio) &= ~GPIO_bit(gpio);	}	gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));	GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));}static int wm8971_pcm_ioctl(struct inode *inode, struct file *file,		      unsigned int cmd, unsigned long arg){	int ret = 0;	long val = 0;	switch(cmd) {	case SNDCTL_DSP_STEREO:		ret = get_user(val, (int *) arg);		if (ret)			return ret;		ret = (val == 0) ? -EINVAL : 1;		return put_user(ret, (int *) arg);	case SNDCTL_DSP_CHANNELS:	case SOUND_PCM_READ_CHANNELS:		return put_user(1, (long *) arg);	case SNDCTL_DSP_SPEED:		ret = get_user(val, (long *) arg);		if (ret)			return ret;		if ((file->f_mode & FMODE_READ) || (file->f_mode & FMODE_WRITE)) {			if ((ret = wm8971_set_adcdac_rate(val)) == val)				wm8971_codec.codec_rate = val;			else				return ret;		}		/* fall through */	case SOUND_PCM_READ_RATE:		if ((file->f_mode & FMODE_READ) || (file->f_mode & FMODE_WRITE))			val = wm8971_codec.codec_rate;		return put_user(val, (long *) arg);	case SNDCTL_DSP_SETFMT:	case SNDCTL_DSP_GETFMTS:		/* FIXME: can we do other fmts? */		return put_user(AFMT_S16_LE, (long *) arg);	default:		/* Maybe this is meant for the mixer (As per OSS Docs) */		return wm8971_mixer_ioctl(inode, file, cmd, arg);	}	return 0;}static int wm8971_psp_open (u8 speed){	int i;	/* do we need to close existing connection ? */	if (wm8971_codec.is_ssp_open)		ssp_exit(&wm8971_codec.ssp);	i=ssp_init(&wm8971_codec.ssp, SSP_PORT2, WM8971_SSP_MODE, WM8971_SSP_SETUP, WM8971_SSP_PSP, SSCR0_SerClkDiv(speed));	if(i == 0)	{		wm8971_codec.is_ssp_open = 1;		return 0;	}	/* something went wrong */	err("could not open SSP port 2");	return -EIO;}
/* * WM8971 SSP Audio stuff */static audio_stream_t wm8971_audio_out = {	name:			"WM8971 audio out",	dcmd:		  (DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4),	drcmr:		&DRCMRTXSADR,//&DRCMRTXPCDR,//&DRCMRTXSS2DR,	dev_addr:		__PREG(SADR),//__PREG(SSDR_P2),};static audio_stream_t wm8971_audio_in = {	name:			"WM8971 audio in",	dcmd:			(DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4),	drcmr:		&DRCMRRXSADR,//&DRCMRRXPCDR,//&DRCMRRXSS2DR,	dev_addr:		__PREG(SADR),//__PREG(SSDR_P2),};static audio_state_t wm8971_pcm = {	output_stream:		&wm8971_audio_out,	input_stream:		&wm8971_audio_in,	client_ioctl:		wm8971_pcm_ioctl,	sem:			__MUTEX_INITIALIZER(wm8971_pcm.sem),};

static struct i2c_driver wm8971_driver = {	name:           "audio_driver",	id:             I2C_DRIVERID_WM8971,	flags:          I2C_DF_NOTIFY,	attach_adapter: wm8971_probe,	detach_client:  wm8971_detach,	command:        NULL,};

static struct i2c_client client_template = {	name:   "WM8971",	flags:  I2C_CLIENT_ALLOW_USE,	driver: &wm8971_driver,};

/* * open the WM8971 pcm audio driver */static int wm8971_pcm_open(struct inode *inode, struct file *file){		return pxa_audio_attach(inode, file, &wm8971_pcm);}



/* * Attach WM8971 2 wire client  */static int wm8971_attach(struct i2c_adapter *adap, int addr, int kind){	        client_template.adapter = adap;

⌨️ 快捷键说明

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