From bb2f15ca7d6eeedbf5634c93609da9dc61824d3c Mon Sep 17 00:00:00 2001 From: Brandon Low Date: Sun, 5 Mar 2006 22:14:53 +0000 Subject: 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 --- firmware/drivers/adc.c | 3 -- firmware/drivers/i2c-pp5020.c | 80 ++++++++++++++++++++++++++++--------------- firmware/drivers/rtc.c | 12 +------ firmware/drivers/wm8758.c | 21 ------------ 4 files changed, 53 insertions(+), 63 deletions(-) diff --git a/firmware/drivers/adc.c b/firmware/drivers/adc.c index f4bdb7a54f..f1a6d7e667 100644 --- a/firmware/drivers/adc.c +++ b/firmware/drivers/adc.c @@ -294,10 +294,7 @@ static struct adc_struct adcdata[NUM_ADC_CHANNELS]; 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); - set_irq_level(old_irq_level); /* This gives us a 13 bit value corresponding to 0-5.4 volts * The range of the value is 13FB-17FA */ data = (data<<2)+0x13FB; diff --git a/firmware/drivers/i2c-pp5020.c b/firmware/drivers/i2c-pp5020.c index 522ddbed77..77671e79d8 100644 --- a/firmware/drivers/i2c-pp5020.c +++ b/firmware/drivers/i2c-pp5020.c @@ -57,42 +57,48 @@ static int ipod_i2c_wait_not_busy(void) if (!(inb(IPOD_I2C_STATUS) & IPOD_I2C_BUSY)) { return 0; } + yield(); } return -1; } -/* Public functions */ - -int ipod_i2c_read_byte(unsigned int addr, unsigned int *data) +static int ipod_i2c_read_byte(unsigned int addr, unsigned int *data) { if (ipod_i2c_wait_not_busy() < 0) { return -1; } - /* clear top 15 bits, left shift 1, or in 0x1 for a read */ - outb(((addr << 17) >> 16) | 0x1, IPOD_I2C_ADDR); + { + int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); - outb(inb(IPOD_I2C_CTRL) | 0x20, IPOD_I2C_CTRL); + /* 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) | IPOD_I2C_SEND, IPOD_I2C_CTRL); + outb(inb(IPOD_I2C_CTRL) | 0x20, IPOD_I2C_CTRL); - if (ipod_i2c_wait_not_busy() < 0) - { - return -1; - } + outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); - if (data) - { - *data = inb(IPOD_I2C_DATA0); + 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; } -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; unsigned int i; @@ -107,26 +113,32 @@ int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data return -2; } - /* clear top 15 bits, left shift 1 */ - outb((addr << 17) >> 16, IPOD_I2C_ADDR); + { + int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); - outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL); + /* clear top 15 bits, left shift 1 */ + outb((addr << 17) >> 16, IPOD_I2C_ADDR); - data_addr = IPOD_I2C_DATA0; - for ( i = 0; i < len; i++ ) - { - outb(*data++, data_addr); - data_addr += 4; - } + 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) & ~0x26) | ((len-1) << 1), IPOD_I2C_CTRL); - outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); + outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); + + set_irq_level(old_irq_level); + } 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]; @@ -135,25 +147,35 @@ int ipod_i2c_send_byte(unsigned int addr, int data0) 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 retval; int data; + mutex_lock(&i2c_mutex); ipod_i2c_send_byte(dev_addr, addr); ipod_i2c_read_byte(dev_addr, &data); + mutex_unlock(&i2c_mutex); return data; } int ipod_i2c_send(unsigned int addr, int data0, int data1) { + int retval; unsigned char data[2]; data[0] = data0; 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) @@ -175,5 +197,7 @@ void i2c_init(void) outl(0x0, 0x600060a4); outl(0x80 | (0 << 8), 0x600060a4); + mutex_init(&i2c_mutex); + i2c_readbyte(0x8, 0); } diff --git a/firmware/drivers/rtc.c b/firmware/drivers/rtc.c index ecfd2ac6ba..4b4b45826f 100644 --- a/firmware/drivers/rtc.c +++ b/firmware/drivers/rtc.c @@ -36,28 +36,18 @@ void rtc_init(void) } int rtc_read_datetime(unsigned char* buf) { - int rc; - 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; + return pcf50605_read_multiple(0x0a, buf, 7); } int rtc_write_datetime(unsigned char* buf) { int i; - int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); for (i=0;i<7;i++) { pcf50605_write(0x0a+i, buf[i]); } - set_irq_level(old_irq_level); - return 1; } #elif CONFIG_RTC == RTC_PCF50606 diff --git a/firmware/drivers/wm8758.c b/firmware/drivers/wm8758.c index 7c9ac77395..3867748417 100644 --- a/firmware/drivers/wm8758.c +++ b/firmware/drivers/wm8758.c @@ -86,8 +86,6 @@ void wm8758_write(int reg, int data) * Note, I'm using the WM8750 datasheet as its apparently close. */ int wmcodec_init(void) { - int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); - /* normal outputs for CDI and I2S pin groups */ outl(inl(0x70000020) & ~0x300, 0x70000020); @@ -108,7 +106,6 @@ int wmcodec_init(void) { /* external dev clock to 24MHz */ outl(inl(0x70000018) & ~0xc, 0x70000018); - set_irq_level(old_irq_level); return 0; } @@ -117,8 +114,6 @@ void wmcodec_enable_output(bool enable) { if (enable) { - int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); - /* reset the I2S controller into known state */ i2s_reset(); @@ -142,7 +137,6 @@ void wmcodec_enable_output(bool enable) wm8758_write(LOUTMIX,0x1); /* Enable mixer */ wm8758_write(ROUTMIX,0x1); /* Enable mixer */ wmcodec_mute(0); - set_irq_level(old_irq_level); } else { 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 old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); /* OUT1 */ wm8758_write(LOUT1VOL, vol_l); 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(ROUT2VOL, 0x100 | vol_r); - set_irq_level(old_irq_level); - return 0; } @@ -204,8 +195,6 @@ void wmcodec_set_treble(int value) int wmcodec_mute(int mute) { - int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); - if (mute) { /* Set DACMU = 1 to soft-mute the audio DACs. */ @@ -215,16 +204,12 @@ int wmcodec_mute(int mute) wm8758_write(DACCTRL, 0x0); } - set_irq_level(old_irq_level); - return 0; } /* Nice shutdown of WM8758 codec */ void wmcodec_close(void) { - int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); - wmcodec_mute(1); wm8758_write(PWRMGMT3, 0x0); @@ -232,8 +217,6 @@ void wmcodec_close(void) wm8758_write(PWRMGMT1, 0x0); wm8758_write(PWRMGMT2, 0x40); - - set_irq_level(old_irq_level); } /* 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 */ void wmcodec_set_sample_rate(int sampling_control) { - int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); - /**** We force 44.1KHz for now. ****/ (void)sampling_control; @@ -264,8 +245,6 @@ void wmcodec_set_sample_rate(int sampling_control) /* set srate */ wm8758_write(SRATECTRL, (0 << 1)); - - set_irq_level(old_irq_level); } void wmcodec_enable_recording(bool source_mic) -- cgit v1.2.3