From 19f4c2a093698940482aad6df0bd8478a82f2a9d Mon Sep 17 00:00:00 2001 From: Brandon Low Date: Thu, 9 Mar 2006 19:47:12 +0000 Subject: Improve ipod i2c driver somewhat by at least taking advantage of the in-device addressing in the pcf50605, also switch to a 10bit resistive divider for the ipod battery reading, this is easily configurable if it needs changing, or even to become a user/runtime setting git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8980 a1c6a512-1295-4272-9138-f99709370657 --- firmware/common/timefuncs.c | 9 +++--- firmware/drivers/adc.c | 67 +++++++++++++++++++++---------------------- firmware/drivers/i2c-pp5002.c | 10 +++++++ firmware/drivers/i2c-pp5020.c | 32 +++++++++++++++------ firmware/drivers/pcf50605.c | 12 ++------ firmware/drivers/rtc.c | 2 +- firmware/export/i2c-pp5002.h | 1 + firmware/export/i2c-pp5020.h | 1 + 8 files changed, 77 insertions(+), 57 deletions(-) diff --git a/firmware/common/timefuncs.c b/firmware/common/timefuncs.c index 275fc6c782..5cf1a35a77 100644 --- a/firmware/common/timefuncs.c +++ b/firmware/common/timefuncs.c @@ -47,12 +47,13 @@ struct tm *get_time(void) { #ifndef SIMULATOR #ifdef CONFIG_RTC - static long last_tick = 0; + static long timeout = 0; - /* Don't read the RTC more than 4 times per second */ - if (last_tick + HZ < current_tick) { + /* Don't read the RTC more than once per second */ + if (current_tick > timeout) { char rtcbuf[7]; - last_tick = HZ * (current_tick / HZ); + /* Once per second, 1/10th of a second off */ + timeout = HZ * (current_tick / HZ + 1) + HZ / 5; rtc_read_datetime(rtcbuf); tm.tm_sec = ((rtcbuf[0] & 0x70) >> 4) * 10 + (rtcbuf[0] & 0x0f); diff --git a/firmware/drivers/adc.c b/firmware/drivers/adc.c index a75f788417..4a99a49753 100644 --- a/firmware/drivers/adc.c +++ b/firmware/drivers/adc.c @@ -286,60 +286,57 @@ void adc_init(void) #elif CONFIG_CPU == PP5020 || (CONFIG_CPU == PP5002) struct adc_struct { - long last_read; - unsigned short (*conversion)(unsigned short data); + long timeout; + void (*conversion)(unsigned short *data); short channelnum; unsigned short data; }; static struct adc_struct adcdata[NUM_ADC_CHANNELS] IDATA_ATTR; -/* This takes 10 bit ADC data from the subtractor circuit and scales it to - * a 13 bit value corresponding to 0-5.4v, the resulting range is 13FB-17FA, - * representing 3.1-5.4v */ -static unsigned short ten_bit_subtractor(unsigned short data) { - return (data<<2)+0x4FB; -} - -static unsigned short _adc_scan(struct adc_struct *adc) +static unsigned short _adc_read(struct adc_struct *adc) { - unsigned short data; - - /* ADCC1, 8 bit, start */ - pcf50605_write(0x2f, 0x80 | (adc->channelnum << 1) | 0x1); - data = pcf50605_read(0x30); /* ADCS1 */ - - if (adc->conversion) { - data = adc->conversion(data); + if (adc->timeout < current_tick) { + unsigned char data[2]; + unsigned short value; + /* 5x per 2 seconds */ + adc->timeout = current_tick + (HZ * 2 / 5); + + /* ADCC1, 10 bit, start */ + pcf50605_write(0x2f, (adc->channelnum << 1) | 0x1); + pcf50605_read_multiple(0x30, data, 2); /* ADCS1, ADCS2 */ + value = data[0]; + value <<= 2; + value |= data[1] & 0x3; + + if (adc->conversion) { + adc->conversion(&value); + } + adc->data = value; + return value; + } else { + return adc->data; } - adc->data = data; - return data; } /* Force an ADC scan _now_ */ unsigned short adc_scan(int channel) { - return _adc_scan(&adcdata[channel]); + struct adc_struct *adc = &adcdata[channel]; + adc->timeout = 0; + return _adc_read(adc); } -/* Retrieve the ADC value, only does a scan once per second or less */ -unsigned short adc_read(int channel) -{ - struct adc_struct *adc = &adcdata[channel]; - if (adc->last_read + HZ < current_tick) { - adc->last_read = current_tick; - return _adc_scan(adc); - } else { - return adc->data; - } +/* Retrieve the ADC value, only does a scan periodically */ +unsigned short adc_read(int channel) { + return _adc_read(&adcdata[channel]); } void adc_init(void) { struct adc_struct *adc_battery = &adcdata[ADC_BATTERY]; - adc_battery->channelnum = 0x3; /* ADCVIN1, subtractor */ - adc_battery->conversion = ten_bit_subtractor; - adc_battery->last_read = current_tick; - _adc_scan(adc_battery); + adc_battery->channelnum = 0x2; /* ADCVIN1, resistive divider */ + adc_battery->timeout = 0; + _adc_read(adc_battery); } #elif CONFIG_CPU == PNX0101 diff --git a/firmware/drivers/i2c-pp5002.c b/firmware/drivers/i2c-pp5002.c index dc26d8a5d9..958ddeebe4 100644 --- a/firmware/drivers/i2c-pp5002.c +++ b/firmware/drivers/i2c-pp5002.c @@ -136,6 +136,16 @@ int ipod_i2c_send_byte(unsigned int addr, int data0) return ipod_i2c_send_bytes(addr, 1, data); } +int i2c_readbytes(unsigned int dev_addr, int addr, int len, unsigned char *data) { + unsigned int temp; + int i; + ipod_i2c_send_byte(dev_addr, addr); + for (i = 0; i < len; i++) { + ipod_i2c_read_byte(dev_addr, &temp); + data[i] = temp; + } + return i; +} int i2c_readbyte(unsigned int dev_addr, int addr) { diff --git a/firmware/drivers/i2c-pp5020.c b/firmware/drivers/i2c-pp5020.c index 232de9cb5a..8b48375e3d 100644 --- a/firmware/drivers/i2c-pp5020.c +++ b/firmware/drivers/i2c-pp5020.c @@ -63,7 +63,6 @@ static int ipod_i2c_wait_not_busy(void) return -1; } - static int ipod_i2c_read_byte(unsigned int addr, unsigned int *data) { if (ipod_i2c_wait_not_busy() < 0) @@ -72,6 +71,7 @@ static int ipod_i2c_read_byte(unsigned int addr, unsigned int *data) } { + unsigned int byte; int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); /* clear top 15 bits, left shift 1, or in 0x1 for a read */ @@ -81,15 +81,18 @@ static int ipod_i2c_read_byte(unsigned int addr, unsigned int *data) outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); - if (data) + set_irq_level(old_irq_level); + if (ipod_i2c_wait_not_busy() < 0) { - if (ipod_i2c_wait_not_busy() < 0) - { - set_irq_level(old_irq_level); - return -1; - } - *data = inb(IPOD_I2C_DATA0); + return -1; } + old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); + + byte = inb(IPOD_I2C_DATA0); + + if (data) + *data = byte; + set_irq_level(old_irq_level); } @@ -148,6 +151,19 @@ static int ipod_i2c_send_byte(unsigned int addr, int data0) /* Public functions */ static struct mutex i2c_mutex; +int i2c_readbytes(unsigned int dev_addr, int addr, int len, unsigned char *data) { + unsigned int temp; + int i; + mutex_lock(&i2c_mutex); + ipod_i2c_send_byte(dev_addr, addr); + for (i = 0; i < len; i++) { + ipod_i2c_read_byte(dev_addr, &temp); + data[i] = temp; + } + mutex_unlock(&i2c_mutex); + return i; +} + int i2c_readbyte(unsigned int dev_addr, int addr) { int data; diff --git a/firmware/drivers/pcf50605.c b/firmware/drivers/pcf50605.c index c8ea4a499f..a8c61b1789 100644 --- a/firmware/drivers/pcf50605.c +++ b/firmware/drivers/pcf50605.c @@ -23,6 +23,7 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "system.h" #include "config.h" #if CONFIG_I2C == I2C_PP5020 #include "i2c-pp5020.h" @@ -72,15 +73,8 @@ int pcf50605_read(int address) int pcf50605_read_multiple(int address, unsigned char* buf, int count) { - int i; - - for (i=0;i