?? pxa-wm8971.c
字號:
client_template.addr = addr; int ret; if ((wm8971_codec.wm8971_2w_client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)) == NULL) { printk("kmalloc error \n"); return -ENOMEM; } memcpy(wm8971_codec.wm8971_2w_client, &client_template, sizeof(struct i2c_client)); i2c_set_clientdata(wm8971_codec.wm8971_2w_client,(void*)&wm8971_codec); /* wm8971_codec.wm8971_2w_client->data = (void*)&wm8971_codec; */ if (wm8971_reset(wm8971_codec.wm8971_2w_client) != 0) { kfree (wm8971_codec.wm8971_2w_client); err("cannot reset the WM8971"); return -EIO; } ret=i2c_attach_client(wm8971_codec.wm8971_2w_client); return ret;}
/* * Detach WM8971 2 wire client */static int wm8971_detach(struct i2c_client *client){ i2c_detach_client(client); kfree(client); return 0;}
static int wm8971_reset(struct i2c_client *client){ return wm8971_2w_write (client, WM8971_RESET, 0);}
/* * Probe Bulverde I2C adapter for WM8971 */static int wm8971_probe(struct i2c_adapter *adap){ if (adap->id == (I2C_ALGO_PXA)) { return i2c_probe(adap, &addr_data, wm8971_attach); } return 0;}
static u16 wm8971_read_reg_cache(u8 reg){ return wm8971_reg[reg - 1];}
static void wm8971_write_reg_cache(u8 reg, u16 value){ wm8971_reg[reg - 1] = value;}
static int wm8971_2w_write(struct i2c_client *client, u8 reg, u16 value){ u8 data[2]; int i; //printk("1.this is wm8971_2w_write function\n"); /* data is * D15..D9 WM971 register offset * D8...D0 register data */ data[0] = (reg << 1) | ((value >> 8) & 0x0001); data[1] = value & 0x00ff; wm8971_write_reg_cache (reg, value); //printk("2.this is wm8971_2w_write function\n"); i=i2c_master_send(client, data, 2); //printk("3.this is wm8971_2w_write function\n"); if (i == 2) return 0; else return -1;}
/* * Set WM8971 ADC and DAC sample rates and * enable SSP port 2 at the correct speed. * * returns sample rate on success, else error. */static int wm8971_set_adcdac_rate(int val){ int ret = val; //u16 clock; //clock = wm8971_read_reg_cache(WM8971_CLOCK) & 0x3f; switch (val) { #if 0 case 8000: /* ADC/DAC 8kHz */ if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_SRATE, WM8971_A8D8) != 0) ret = -EIO; if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_CLOCK, WM8971_VD8K | clock) !=0) ret = -EIO; if (wm8971_psp_open(WM8971_SSP_8K) != 0) ret = -EIO; if (hifi) wm8971_i2s_open(WM8971_I2S_8K); break; case 12000: /* ADC/DAC 12kHz */ if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_SRATE, WM8971_A12D12) != 0) ret = -EIO; if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_CLOCK, WM8971_VD12K | clock) !=0) ret = -EIO; if (wm8971_psp_open(WM8971_SSP_12K) != 0) ret = -EIO; if (hifi) wm8971_i2s_open(WM8971_I2S_12K); break; case 16000: /* ADC/DAC 16kHz */ if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_SRATE, WM8971_A16D16) != 0) ret = -EIO; if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_CLOCK, WM8971_VD16K | clock) !=0) ret = -EIO; if (wm8971_psp_open(WM8971_SSP_16K) != 0) ret = -EIO; if (hifi) wm8971_i2s_open(WM8971_I2S_16K); break; case 24000: /* ADC/DAC 24kHz - Voice DAC only*/ if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_SRATE, WM8971_A24D24) != 0) ret = -EIO; if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_CLOCK, WM8971_VD24K | clock) !=0) ret = -EIO; if (wm8971_psp_open(WM8971_SSP_24K) != 0) ret = -EIO; break; #endif case 44100: if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_SRATE, 0x0020) != 0) ret = -EIO; if (wm8971_psp_open(WM8971_SSP_24K) != 0) ret = -EIO; break; // #if 0 case 48000: /* ADC/DAC 48kHz */ if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_SRATE, WM8971_VD48K) != 0) ret = -EIO; // if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_CLOCK, WM8971_VD48K | clock) !=0)// ret = -EIO; //if (wm8971_psp_open(WM8971_SSP_44_1K) != 0) // ret = -EIO; //if (hifi) wm8971_i2s_open(WM8971_I2S_441K); break; // #endif default: /* desired rate is not permitted */ ret = -EPERM; break; } //if (ret != -EIO) // ssp_enable(&wm8971_codec.ssp); return ret;}
static int wm8971_i2s_open(int speed){
GPCR0 |= 0xC0000000; //0x40E00024
GPDR0 &= 0x0fffffff;
GPDR0 |= 1U<<30|1U<<31|1U<<28;
GAFR0_U = (GAFR0_U & 0x00FFFFFF) | 0x59000000;
//GAFR1_L = (GAFR1_L&0xfffffffc)|0x1; SACR0&=0x0;
SACR0 |= (0xe<<12)|(0x1<<8)|(0x1<<2);
SACR1=0;
SACR1&=~((0x1<<4)|(0x1<<3)|(0x1<<0));
SAIMR=0;
SACR1|=0x1<<3;
SADIV = speed;
SACR0|=0x1<<0; //SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1) | SACR0_BCKD; //SACR1 &= ~(SACR1_DRPL | SACR1_DREC | SACR1_AMSL); //SAIMR |= SAIMR_RFS | SAIMR_TFS; //SADIV = speed; //SACR0 |= SACR0_ENB; return 0;}
static void wm8971_i2s_close(){ SACR0 &= ~SACR0_ENB; CKEN &= ~CKEN8_I2S;}
#ifdef CONFIG_PM/* * WM8971 Power Management */static int wm8971_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data){ switch(rqst) { case PM_SUSPEND: wm8971_suspend(); break; case PM_RESUME: wm8971_resume(); break; } return 0;}/* * Power down the codec *//* PM NOT TESTED */static void wm8971_suspend(void){ /* powerdown everything, set Vmid to 500kOhm */ if ((wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_PWR1, 0x0100) != 0) && (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_PWR2, 0x0000) != 0)) err("could not powerdown WM8971");}/* * Power up the Codec */static void wm8971_resume(void){ /* powerup everything, set Vmid to 50kOhm */ if (wm8971_power_up()) err("could not powerup WM8971");}#endif#ifdef CONFIG_PROC_FSstatic int wm8971_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0, i; struct wm8971_codec_t* c; if ((c = data) == NULL) return -ENODEV; /* driver version */ len = sprintf (page+len, "Wolfson WM8971 Version %s\n", WM8971_VERSION); /* reg dump */ for (i = 0; i<43; i++) len = sprintf (page+len, "0x%2.2x %3x\n", i, wm8971_read_reg_cache(i)); return len;}#endif
/*have not been configed below*/
static int wm8971_power_up(void){ //u16 pwr = 0xf0; /* set Vmid to 5kOhm, enable VREF */ if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_PWR1, 0x00f0) != 0) return -EIO; /* enable LOUT 1, ROUT1.... */ if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_PWR2, 0x0180) != 0) return -EIO; /* let WM8971 powerup and then set Vmid to 50kOhm */ mdelay(1); if (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_PWR2, 0x01f8) != 0) return -EIO; return 0;}
static int wm8971_power_down(){ if ((wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_PWR1, 0x0000) != 0) && (wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_PWR2, 0x0000) != 0)) { err("could not powerdown WM8971"); return -EIO; } return 0;}
/* * initiliase the WM8971 */static int wm8971_init(void){ int ret = 0; CKEN |= CKEN8_I2S; /* power up the device */ if ((ret = wm8971_power_up()) != 0) { ret = -EIO; goto out; } /* set up GPIO and alternate functions for SSP2/I2S */ //GAFR0_U=(GAFR0_U&0xFFC03FFF)|0x3FC000; //set_GPIO_mode(GPIO28_BITCLK_I2S_MD); //set_GPIO_mode(GPIO29_SDATA_IN_I2S_MD); //set_GPIO_mode(GPIO30_SDATA_OUT_I2S_MD); // not sure of correct GPIO for SSP2 RX //set_GPIO_mode(GPIO31_SYNC_I2S_MD); wm8971_i2s_open(WM8971_I2S_441K); /* set up default ADC/DAC sample rate */// if ((ret = wm8971_set_adcdac_rate(WM8971_DEFAULT_SRATE)) != WM8971_DEFAULT_SRATE) {// err("could not set WM8971 sample rate to %d", WM8971_DEFAULT_SRATE);// ret = -EIO;// goto out;// } ret=0; ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_LINVOL, 0x0097); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_RINVOL, 0x0097); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_LOUT1V, 0x0040); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_ROUT1V, 0x0040); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_LDAC, 0x0000); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_RDAC, 0x0000); //ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_LDAC, 0x01fb); //ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_RDAC, 0x01fb); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_LOUT1V, 0x0179); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_ROUT1V, 0x0179); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_ADCDAC, 0x0000); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_AUDIO, 0x0002); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_SRATE, 0x0020); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_LDAC, 0x01e5); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_RDAC, 0x01e5); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_BASS, 0x000f); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_TREBLE,0x000f); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_ALC1, 0x007b); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_ALC2, 0x0000); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_ALC3, 0x0032); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_NGATE, 0x0000); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_LADC, 0x00c3); ret += wm8971_2w_write(wm8971_codec.wm8971_2w_client, WM8971_RADC, 0x00c3);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -