?? pxa-wm8971.c
字號:
#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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -