1
0
Fork 0
forked from len0rd/rockbox

Finer grained irq masking, blocking for i2c, plus a mutex to prevent conflicting read/writes

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8922 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Brandon Low 2006-03-05 22:14:53 +00:00
parent 03b8708f9e
commit bb2f15ca7d
4 changed files with 57 additions and 67 deletions

View file

@ -294,10 +294,7 @@ static struct adc_struct adcdata[NUM_ADC_CHANNELS];
static unsigned short adc_scan(struct adc_struct *adc) static unsigned short adc_scan(struct adc_struct *adc)
{ {
/* Disable interrupts during the I2C transaction */
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
unsigned short data = pcf50605_a2d_read(adc->channelnum); unsigned short data = pcf50605_a2d_read(adc->channelnum);
set_irq_level(old_irq_level);
/* This gives us a 13 bit value corresponding to 0-5.4 volts /* This gives us a 13 bit value corresponding to 0-5.4 volts
* The range of the value is 13FB-17FA */ * The range of the value is 13FB-17FA */
data = (data<<2)+0x13FB; data = (data<<2)+0x13FB;

View file

@ -57,42 +57,48 @@ static int ipod_i2c_wait_not_busy(void)
if (!(inb(IPOD_I2C_STATUS) & IPOD_I2C_BUSY)) { if (!(inb(IPOD_I2C_STATUS) & IPOD_I2C_BUSY)) {
return 0; return 0;
} }
yield();
} }
return -1; return -1;
} }
/* Public functions */ static int ipod_i2c_read_byte(unsigned int addr, unsigned int *data)
int ipod_i2c_read_byte(unsigned int addr, unsigned int *data)
{ {
if (ipod_i2c_wait_not_busy() < 0) if (ipod_i2c_wait_not_busy() < 0)
{ {
return -1; return -1;
} }
/* clear top 15 bits, left shift 1, or in 0x1 for a read */
outb(((addr << 17) >> 16) | 0x1, IPOD_I2C_ADDR);
outb(inb(IPOD_I2C_CTRL) | 0x20, IPOD_I2C_CTRL);
outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL);
if (ipod_i2c_wait_not_busy() < 0)
{ {
return -1; int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
}
if (data) /* clear top 15 bits, left shift 1, or in 0x1 for a read */
{ outb(((addr << 17) >> 16) | 0x1, IPOD_I2C_ADDR);
*data = inb(IPOD_I2C_DATA0);
outb(inb(IPOD_I2C_CTRL) | 0x20, IPOD_I2C_CTRL);
outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL);
set_irq_level(old_irq_level);
if (data)
{
if (ipod_i2c_wait_not_busy() < 0)
{
return -1;
}
old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
*data = inb(IPOD_I2C_DATA0);
set_irq_level(old_irq_level);
}
} }
return 0; return 0;
} }
int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data) static int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data)
{ {
int data_addr; int data_addr;
unsigned int i; unsigned int i;
@ -107,26 +113,32 @@ int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data
return -2; return -2;
} }
/* clear top 15 bits, left shift 1 */
outb((addr << 17) >> 16, IPOD_I2C_ADDR);
outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL);
data_addr = IPOD_I2C_DATA0;
for ( i = 0; i < len; i++ )
{ {
outb(*data++, data_addr); int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
data_addr += 4;
/* clear top 15 bits, left shift 1 */
outb((addr << 17) >> 16, IPOD_I2C_ADDR);
outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL);
data_addr = IPOD_I2C_DATA0;
for ( i = 0; i < len; i++ )
{
outb(*data++, data_addr);
data_addr += 4;
}
outb((inb(IPOD_I2C_CTRL) & ~0x26) | ((len-1) << 1), IPOD_I2C_CTRL);
outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL);
set_irq_level(old_irq_level);
} }
outb((inb(IPOD_I2C_CTRL) & ~0x26) | ((len-1) << 1), IPOD_I2C_CTRL);
outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL);
return 0x0; return 0x0;
} }
int ipod_i2c_send_byte(unsigned int addr, int data0) static int ipod_i2c_send_byte(unsigned int addr, int data0)
{ {
unsigned char data[1]; unsigned char data[1];
@ -135,25 +147,35 @@ int ipod_i2c_send_byte(unsigned int addr, int data0)
return ipod_i2c_send_bytes(addr, 1, data); return ipod_i2c_send_bytes(addr, 1, data);
} }
/* Public functions */
static struct mutex i2c_mutex;
int i2c_readbyte(unsigned int dev_addr, int addr) int i2c_readbyte(unsigned int dev_addr, int addr)
{ {
int retval;
int data; int data;
mutex_lock(&i2c_mutex);
ipod_i2c_send_byte(dev_addr, addr); ipod_i2c_send_byte(dev_addr, addr);
ipod_i2c_read_byte(dev_addr, &data); ipod_i2c_read_byte(dev_addr, &data);
mutex_unlock(&i2c_mutex);
return data; return data;
} }
int ipod_i2c_send(unsigned int addr, int data0, int data1) int ipod_i2c_send(unsigned int addr, int data0, int data1)
{ {
int retval;
unsigned char data[2]; unsigned char data[2];
data[0] = data0; data[0] = data0;
data[1] = data1; data[1] = data1;
return ipod_i2c_send_bytes(addr, 2, data); mutex_lock(&i2c_mutex);
retval = ipod_i2c_send_bytes(addr, 2, data);
mutex_unlock(&i2c_mutex);
return retval;
} }
void i2c_init(void) void i2c_init(void)
@ -175,5 +197,7 @@ void i2c_init(void)
outl(0x0, 0x600060a4); outl(0x0, 0x600060a4);
outl(0x80 | (0 << 8), 0x600060a4); outl(0x80 | (0 << 8), 0x600060a4);
mutex_init(&i2c_mutex);
i2c_readbyte(0x8, 0); i2c_readbyte(0x8, 0);
} }

View file

@ -36,28 +36,18 @@ void rtc_init(void)
} }
int rtc_read_datetime(unsigned char* buf) int rtc_read_datetime(unsigned char* buf)
{ {
int rc; return pcf50605_read_multiple(0x0a, buf, 7);
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
rc = pcf50605_read_multiple(0x0a, buf, 7);
set_irq_level(old_irq_level);
return rc;
} }
int rtc_write_datetime(unsigned char* buf) int rtc_write_datetime(unsigned char* buf)
{ {
int i; int i;
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
for (i=0;i<7;i++) { for (i=0;i<7;i++) {
pcf50605_write(0x0a+i, buf[i]); pcf50605_write(0x0a+i, buf[i]);
} }
set_irq_level(old_irq_level);
return 1; return 1;
} }
#elif CONFIG_RTC == RTC_PCF50606 #elif CONFIG_RTC == RTC_PCF50606

View file

@ -86,8 +86,6 @@ void wm8758_write(int reg, int data)
* Note, I'm using the WM8750 datasheet as its apparently close. * Note, I'm using the WM8750 datasheet as its apparently close.
*/ */
int wmcodec_init(void) { int wmcodec_init(void) {
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
/* normal outputs for CDI and I2S pin groups */ /* normal outputs for CDI and I2S pin groups */
outl(inl(0x70000020) & ~0x300, 0x70000020); outl(inl(0x70000020) & ~0x300, 0x70000020);
@ -108,7 +106,6 @@ int wmcodec_init(void) {
/* external dev clock to 24MHz */ /* external dev clock to 24MHz */
outl(inl(0x70000018) & ~0xc, 0x70000018); outl(inl(0x70000018) & ~0xc, 0x70000018);
set_irq_level(old_irq_level);
return 0; return 0;
} }
@ -117,8 +114,6 @@ void wmcodec_enable_output(bool enable)
{ {
if (enable) if (enable)
{ {
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
/* reset the I2S controller into known state */ /* reset the I2S controller into known state */
i2s_reset(); i2s_reset();
@ -142,7 +137,6 @@ void wmcodec_enable_output(bool enable)
wm8758_write(LOUTMIX,0x1); /* Enable mixer */ wm8758_write(LOUTMIX,0x1); /* Enable mixer */
wm8758_write(ROUTMIX,0x1); /* Enable mixer */ wm8758_write(ROUTMIX,0x1); /* Enable mixer */
wmcodec_mute(0); wmcodec_mute(0);
set_irq_level(old_irq_level);
} else { } else {
wmcodec_mute(1); wmcodec_mute(1);
} }
@ -150,7 +144,6 @@ void wmcodec_enable_output(bool enable)
int wmcodec_set_master_vol(int vol_l, int vol_r) int wmcodec_set_master_vol(int vol_l, int vol_r)
{ {
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
/* OUT1 */ /* OUT1 */
wm8758_write(LOUT1VOL, vol_l); wm8758_write(LOUT1VOL, vol_l);
wm8758_write(ROUT1VOL, 0x100 | vol_r); wm8758_write(ROUT1VOL, 0x100 | vol_r);
@ -159,8 +152,6 @@ int wmcodec_set_master_vol(int vol_l, int vol_r)
wm8758_write(LOUT2VOL, vol_l); wm8758_write(LOUT2VOL, vol_l);
wm8758_write(ROUT2VOL, 0x100 | vol_r); wm8758_write(ROUT2VOL, 0x100 | vol_r);
set_irq_level(old_irq_level);
return 0; return 0;
} }
@ -204,8 +195,6 @@ void wmcodec_set_treble(int value)
int wmcodec_mute(int mute) int wmcodec_mute(int mute)
{ {
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
if (mute) if (mute)
{ {
/* Set DACMU = 1 to soft-mute the audio DACs. */ /* Set DACMU = 1 to soft-mute the audio DACs. */
@ -215,16 +204,12 @@ int wmcodec_mute(int mute)
wm8758_write(DACCTRL, 0x0); wm8758_write(DACCTRL, 0x0);
} }
set_irq_level(old_irq_level);
return 0; return 0;
} }
/* Nice shutdown of WM8758 codec */ /* Nice shutdown of WM8758 codec */
void wmcodec_close(void) void wmcodec_close(void)
{ {
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
wmcodec_mute(1); wmcodec_mute(1);
wm8758_write(PWRMGMT3, 0x0); wm8758_write(PWRMGMT3, 0x0);
@ -232,8 +217,6 @@ void wmcodec_close(void)
wm8758_write(PWRMGMT1, 0x0); wm8758_write(PWRMGMT1, 0x0);
wm8758_write(PWRMGMT2, 0x40); wm8758_write(PWRMGMT2, 0x40);
set_irq_level(old_irq_level);
} }
/* Change the order of the noise shaper, 5th order is recommended above 32kHz */ /* Change the order of the noise shaper, 5th order is recommended above 32kHz */
@ -245,8 +228,6 @@ void wmcodec_set_nsorder(int order)
/* Note: Disable output before calling this function */ /* Note: Disable output before calling this function */
void wmcodec_set_sample_rate(int sampling_control) void wmcodec_set_sample_rate(int sampling_control)
{ {
int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL);
/**** We force 44.1KHz for now. ****/ /**** We force 44.1KHz for now. ****/
(void)sampling_control; (void)sampling_control;
@ -264,8 +245,6 @@ void wmcodec_set_sample_rate(int sampling_control)
/* set srate */ /* set srate */
wm8758_write(SRATECTRL, (0 << 1)); wm8758_write(SRATECTRL, (0 << 1));
set_irq_level(old_irq_level);
} }
void wmcodec_enable_recording(bool source_mic) void wmcodec_enable_recording(bool source_mic)