6c0f55bc68
SVN-Revision: 8509
329 lines
7.4 KiB
C
329 lines
7.4 KiB
C
/*
|
|
* a.lp_mp3 - VS1011B driver for Fonera
|
|
* Copyright (c) 2007 phrozen.org - John Crispin <john@phrozen.org>
|
|
*
|
|
* 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, MA02111-1307USA
|
|
*
|
|
* Feedback, Bugs.... mail john@phrozen.org
|
|
*
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/string.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/init.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/system.h>
|
|
#include <asm/irq.h>
|
|
#include "ar531xlnx.h"
|
|
|
|
#define AR5315_DSLBASE 0xB1000000
|
|
#define AR5315_GPIO_DI (AR5315_DSLBASE + 0x0088)
|
|
#define AR5315_GPIO_DO (AR5315_DSLBASE + 0x0090)
|
|
#define AR5315_GPIO_CR (AR5315_DSLBASE + 0x0098)
|
|
#define AR5315_GPIO_INT (AR5315_DSLBASE + 0x00a0)
|
|
|
|
#define GPIO_0 1<<0
|
|
#define GPIO_1 1<<1
|
|
#define GPIO_2 1<<2
|
|
#define GPIO_3 1<<3
|
|
#define GPIO_4 1<<4
|
|
#define GPIO_6 1<<6
|
|
#define GPIO_7 1<<7
|
|
|
|
#define DREQ ((unsigned int)GPIO_7)
|
|
#define SCK ((unsigned int)GPIO_1)
|
|
#define SI ((unsigned int)GPIO_4)
|
|
#define BSYNC ((unsigned int)GPIO_3)
|
|
#define CS ((unsigned int)GPIO_0)
|
|
#define SO ((unsigned int)GPIO_6)
|
|
#define RES ((unsigned int)GPIO_2)
|
|
|
|
#define REG_MODE 0x0
|
|
#define REG_STATUS 0x1
|
|
#define REG_BASS 0x2
|
|
#define REG_CLOCKF 0x3
|
|
#define REG_DECODETIME 0x4
|
|
#define REG_AUDATA 0x5
|
|
#define REG_WRAM 0x6
|
|
#define REG_WRAMADDR 0x7
|
|
#define REG_HDAT0 0x8
|
|
#define REG_HDAT1 0x9
|
|
#define REG_A1ADDR 0xa
|
|
#define REG_VOL 0xb
|
|
#define REG_A1CTRL0 0xc
|
|
#define REG_A1CTRL1 0xd
|
|
#define REG_A1CTRL2 0xe
|
|
|
|
#define VS1011_NEEDS_DATA spi_get_bit(DREQ)
|
|
#define VS1011_NEEDS_NO_DATA (spi_get_bit(DREQ)== 0x00)
|
|
#define VS1011_WHILE_NEEDS_NO_DATA while(spi_get_bit(DREQ)== 0x00){}
|
|
|
|
#define VS_CS_LO spi_clear_bit(CS)
|
|
#define VS_CS_HI spi_set_bit(CS)
|
|
|
|
#define VS_BSYNC_LO spi_clear_bit(BSYNC)
|
|
#define VS_BSYNC_HI spi_set_bit(BSYNC)
|
|
|
|
#define VS_RESET_LO spi_clear_bit(RES)
|
|
#define VS_RESET_HI spi_set_bit(RES)
|
|
|
|
#define VS1011_READ SPI_io_vs1011b(0x03)
|
|
#define VS1011_WRITE SPI_io_vs1011b(0x02)
|
|
|
|
void msDelay(int ms) {
|
|
int i,a;
|
|
int delayvar=10;
|
|
|
|
for (a=0;a<ms;a++) {
|
|
for (i=0;i<33084;i++) {
|
|
delayvar*=2;
|
|
delayvar/=2;
|
|
}
|
|
}
|
|
}
|
|
|
|
int spi_get_bit(unsigned int pin){
|
|
return ((sysRegRead(AR5315_GPIO_DI)&pin)?(1):(0));
|
|
}
|
|
|
|
void spi_set_bit(unsigned int pin){
|
|
sysRegWrite(AR5315_GPIO_DO, (sysRegRead(AR5315_GPIO_DO) | pin));
|
|
}
|
|
|
|
void spi_clear_bit(unsigned int pin){
|
|
sysRegWrite(AR5315_GPIO_DO, (sysRegRead(AR5315_GPIO_DO) & ~pin));
|
|
}
|
|
|
|
void SPI_clock_vs1011b(void){
|
|
spi_clear_bit(SCK);
|
|
spi_set_bit(SCK);
|
|
}
|
|
|
|
unsigned char SPI_io_vs1011b(unsigned char byte){
|
|
int i;
|
|
unsigned char this_bit;
|
|
unsigned char byte_out = 0;
|
|
for(i = 7; i>=0; i--){
|
|
if(byte & (1<<i)){
|
|
this_bit = 1;
|
|
} else {
|
|
this_bit = 0;
|
|
}
|
|
if(this_bit){
|
|
spi_set_bit(SI);
|
|
} else {
|
|
spi_clear_bit(SI);
|
|
}
|
|
SPI_clock_vs1011b();
|
|
byte_out += spi_get_bit(SO)<<i;
|
|
}
|
|
return byte_out;
|
|
}
|
|
|
|
void SPI_init_vs1011(void){
|
|
sysRegWrite(AR5315_GPIO_CR, (sysRegRead(AR5315_GPIO_CR) | SI | SCK | CS | BSYNC | RES) & ~(SO|DREQ));
|
|
spi_clear_bit(SCK);
|
|
spi_clear_bit(SI);
|
|
VS_CS_HI;
|
|
VS_BSYNC_HI;
|
|
}
|
|
|
|
void VS1011_send_SCI(unsigned char reg, unsigned int data){
|
|
VS_CS_LO;
|
|
VS1011_WRITE;
|
|
SPI_io_vs1011b(reg);
|
|
SPI_io_vs1011b((data>>8)&0xff);
|
|
SPI_io_vs1011b(data&0xff);
|
|
VS_CS_HI;
|
|
}
|
|
|
|
unsigned int VS1011_read_SCI(unsigned char reg){
|
|
unsigned int data;
|
|
VS_CS_LO;
|
|
VS1011_READ;
|
|
SPI_io_vs1011b(reg);
|
|
data = 0;
|
|
data = SPI_io_vs1011b(0x00);
|
|
data <<= 8;
|
|
data += SPI_io_vs1011b(0x00);
|
|
VS_CS_HI;
|
|
return data;
|
|
}
|
|
|
|
void VS1011_send_SDI(unsigned char byte){
|
|
int i;
|
|
VS_BSYNC_LO;
|
|
for(i = 7; i>=0; i--){
|
|
if(byte & (1<<i)){
|
|
spi_set_bit(SI);
|
|
|
|
} else {
|
|
spi_clear_bit(SI);
|
|
}
|
|
spi_clear_bit(SCK);
|
|
spi_set_bit(SCK);
|
|
}
|
|
VS_BSYNC_HI;
|
|
}
|
|
|
|
void VS1011_send_SDI_32(unsigned char* data){
|
|
int i;
|
|
VS1011_WHILE_NEEDS_NO_DATA;
|
|
for(i=0; i<32; i++){
|
|
VS1011_send_SDI(data[i]);
|
|
}
|
|
}
|
|
|
|
void VS1011_send_zeros(unsigned char count){
|
|
do{
|
|
VS1011_send_SDI(0x0);
|
|
count--;
|
|
}while(count);
|
|
}
|
|
|
|
void VS1011_set_volume(unsigned int vol){
|
|
VS1011_send_SCI(REG_VOL, vol);
|
|
}
|
|
|
|
void VS1011_SW_reset(unsigned int _crystal_freq){
|
|
unsigned int regval = 0x0804;
|
|
unsigned long int i = 0;
|
|
msDelay(100);
|
|
VS1011_send_zeros(32);
|
|
VS1011_send_SCI(REG_MODE, regval);
|
|
msDelay(10);
|
|
while((VS1011_NEEDS_NO_DATA) && (i++<0xffff)){};
|
|
VS1011_send_SCI(REG_CLOCKF, _crystal_freq);
|
|
VS1011_send_zeros(16);
|
|
VS1011_set_volume(0x00);
|
|
}
|
|
|
|
void VS1011_HW_reset(void){
|
|
|
|
VS_RESET_LO;
|
|
msDelay(1);
|
|
VS_RESET_HI;
|
|
msDelay(1);
|
|
}
|
|
|
|
void VS1011_init(unsigned int _crystal_freq, unsigned char hw){
|
|
if(hw){
|
|
SPI_init_vs1011();
|
|
}
|
|
printk("mp3_drv.ko : Init start\n");
|
|
if(hw){
|
|
VS1011_HW_reset();
|
|
}
|
|
VS1011_SW_reset(_crystal_freq);
|
|
printk("mp3_drv.ko : init_ok\n");
|
|
}
|
|
|
|
void VS1011_sine(unsigned char state, unsigned char freq){
|
|
VS1011_send_zeros(16);
|
|
if(state == 0x01){
|
|
VS1011_send_SDI(0x53);
|
|
VS1011_send_SDI(0xEF);
|
|
VS1011_send_SDI(0x6E);
|
|
VS1011_send_SDI(freq);
|
|
VS1011_send_zeros(0x04);
|
|
} else {
|
|
VS1011_send_SDI(0x45);
|
|
VS1011_send_SDI(0x78);
|
|
VS1011_send_SDI(0x69);
|
|
VS1011_send_SDI(0x74);
|
|
VS1011_send_zeros(0x04);
|
|
}
|
|
}
|
|
|
|
unsigned int VS1011_get_volume(void){
|
|
return VS1011_read_SCI(REG_VOL);
|
|
}
|
|
|
|
unsigned int VS1011_get_decode_time(void){
|
|
return VS1011_read_SCI(REG_DECODETIME);
|
|
}
|
|
|
|
const unsigned int sample_rate_values[] = {0, 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
|
|
|
|
void VS1011_get_audio_data(AUDIO_DATA* audio){
|
|
unsigned int audata = VS1011_read_SCI(REG_AUDATA);
|
|
audio->sample_rate = sample_rate_values[(audata&0x1E00)>>9];
|
|
audio->bitrate = audata&0x1FF;
|
|
audio->is_stereo = (audata&0x8000)>>15;
|
|
}
|
|
|
|
void VS1011_print_registers(void){
|
|
unsigned char i;
|
|
for(i = 0; i< 14; i++){
|
|
unsigned int regval = VS1011_read_SCI(i);
|
|
printk("mp3_drv.ko : %d \n", regval);
|
|
}
|
|
}
|
|
|
|
void VS1011_volume(unsigned char left, unsigned char right){
|
|
unsigned int regval = left;
|
|
regval <<=8;
|
|
regval += right;
|
|
VS1011_send_SCI(REG_VOL, regval);
|
|
}
|
|
|
|
void VS1011_set_bass(unsigned int regval){
|
|
VS1011_send_SCI(REG_BASS, regval);
|
|
}
|
|
|
|
void VS1011_set_reg(unsigned int reg, unsigned int regval){
|
|
VS1011_send_SCI(reg, regval);
|
|
}
|
|
|
|
/*
|
|
int vs_test(void) {
|
|
SPI_init_vs1011();
|
|
printk("%u\n", *R_GEN_CONFIG);
|
|
VS1001_init(_crystal_freq);
|
|
VS1001_print_registers();
|
|
VS1001_volume(0x30, 0x30);
|
|
msDelay(1000);
|
|
VS1001_sine(1, 0x30);
|
|
msDelay(1000);
|
|
VS1001_sine(0, 0);
|
|
VS1001_send_zeros(0x20);
|
|
msDelay(1000);
|
|
VS1001_sine(1, 0x30);
|
|
msDelay(1000);
|
|
VS1001_sine(0, 0);
|
|
VS1001_send_zeros(0x20);
|
|
msDelay(1000);
|
|
VS1001_sine(1, 0x30);
|
|
msDelay(1000);
|
|
VS1001_sine(0, 0);
|
|
|
|
AUDIO_DATA a;
|
|
VS1001_get_audio_data(&a);
|
|
printk("mp3_drv.ko : rate : %d, bit : %d, stereo : %d \n", a.sample_rate, a.bitrate, a.is_stereo);
|
|
VS1001_SW_reset(_crystal_freq);
|
|
return 0;
|
|
}*/
|
|
|