diff --git a/apps/gui/gwps-common.c b/apps/gui/gwps-common.c index 70f5565b61..8fa80c725a 100644 --- a/apps/gui/gwps-common.c +++ b/apps/gui/gwps-common.c @@ -23,7 +23,9 @@ #include #include "system.h" #include "settings.h" +#ifdef CONFIG_RTC #include "rtc.h" +#endif #include "audio.h" #include "status.h" #include "power.h" @@ -972,6 +974,11 @@ static char* get_tag(struct wps_data* wps_data, #ifdef CONFIG_RTC case 'c': /* Real Time Clock display */ *flags |= WPS_REFRESH_DYNAMIC; +#if CONFIG_RTC == RTC_DS1339_DS3231 + if(!rtc_detected) + return NULL; + else +#endif { int value; char *format = 0; diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c index fbd8943315..a36ae15974 100644 --- a/apps/gui/statusbar.c +++ b/apps/gui/statusbar.c @@ -28,6 +28,9 @@ #include "powermgmt.h" #include "usb.h" #include "led.h" +#ifdef CONFIG_RTC +#include "rtc.h" +#endif #include "status.h" /* needed for battery_state global var */ #include "action.h" /* for keys_locked */ @@ -239,6 +242,9 @@ void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw) bar->info.led = led_read(HZ/2); /* delay should match polling interval */ #endif #ifdef CONFIG_RTC +#if CONFIG_RTC == RTC_DS1339_DS3231 + if(rtc_detected) +#endif { struct tm* tm = get_time(); bar->info.hour = tm->tm_hour; @@ -324,6 +330,9 @@ void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw) gui_statusbar_icon_lock_remote(display); #endif #ifdef CONFIG_RTC +#if CONFIG_RTC == RTC_DS1339_DS3231 + if(rtc_detected) +#endif gui_statusbar_time(display, bar->info.hour, bar->info.minute); #endif /* CONFIG_RTC */ #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 508f7214a1..818271b623 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -38,6 +38,12 @@ #ifdef HAVE_ALARM_MOD #include "alarm_menu.h" #endif +#ifdef CONFIG_RTC +#include "rtc.h" +#endif + +/* callback to display rtc menus dynamically */ +int rtc_detect_callback(int action,const struct menu_item_ex *this_item); /***********************************/ /* TAGCACHE MENU */ @@ -206,7 +212,7 @@ static int timedate_set(void) MENUITEM_FUNCTION(time_set, ID2P(LANG_TIME), timedate_set, NULL, NOICON); MENUITEM_SETTING(timeformat, &global_settings.timeformat, NULL); -MAKE_MENU(time_menu, ID2P(LANG_TIME_MENU), 0, NOICON, &time_set, &timeformat); +MAKE_MENU(time_menu, ID2P(LANG_TIME_MENU), rtc_detect_callback, NOICON, &time_set, &timeformat); #endif /* System menu */ @@ -246,7 +252,7 @@ MENUITEM_FUNCTION(sleep_timer_call, ID2P(LANG_SLEEP_TIMER), sleep_timer, setting to the user */ #ifdef HAVE_ALARM_MOD MENUITEM_FUNCTION(alarm_screen_call, ID2P(LANG_ALARM_MOD_ALARM_MENU), - (menu_function)alarm_screen, NULL, NOICON); + (menu_function)alarm_screen, rtc_detect_callback, NOICON); #endif /* Limits menu */ @@ -383,3 +389,23 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0, &bookmark_settings_menu, &browse_langs, &voice_settings_menu ); /* SETTINGS MENU */ /***********************************/ + +/* callback to display rtc menus dynamically */ +int rtc_detect_callback(int action,const struct menu_item_ex *this_item) +{ + if (action != ACTION_REQUEST_MENUITEM) + return action; + +#if defined(CONFIG_RTC) && CONFIG_RTC == RTC_DS1339_DS3231 + if ((this_item == &time_menu) || + (this_item == &alarm_screen_call)) + { + if (!rtc_detected) + return ACTION_EXIT_MENUITEM; + } +#else + (void)this_item; +#endif + + return action; +} diff --git a/apps/misc.c b/apps/misc.c index 22f6fb50a6..339bc1d0b7 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -60,6 +60,7 @@ #include "gui/gwps-common.h" #include "misc.h" +#include "rtc.h" /* Format a large-range value for output, using the appropriate unit so that * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" @@ -414,6 +415,12 @@ void screen_dump(void) #endif #ifdef CONFIG_RTC +#if CONFIG_RTC == RTC_DS1339_DS3231 + if(!rtc_detected) + create_numbered_filename(filename, "", "dump_", ".bmp", 4 + IF_CNFN_NUM_(, NULL)); + else +#endif create_datetime_filename(filename, "", "dump ", ".bmp", false); #else create_numbered_filename(filename, "", "dump_", ".bmp", 4 diff --git a/apps/plugins/clock.c b/apps/plugins/clock.c index 7e52e2b552..010e293bac 100644 --- a/apps/plugins/clock.c +++ b/apps/plugins/clock.c @@ -277,7 +277,7 @@ extern const fb_data clock_timesup[]; #define EXIT_BUTTON BUTTON_MENU #define MODE_NEXT_BUTTON BUTTON_RIGHT #define MODE_PREV_BUTTON BUTTON_LEFT -#elif (CONFIG_KEYPAD == IRIVER_H300_PAD) +#elif (CONFIG_KEYPAD == IRIVER_H300_PAD) || (CONFIG_KEYPAD == IRIVER_H100_PAD) #define COUNTER_TOGGLE_BUTTON (BUTTON_ON|BUTTON_REL) #define COUNTER_RESET_BUTTON (BUTTON_ON|BUTTON_REPEAT) #define MENU_BUTTON BUTTON_SELECT diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 8eea24d82d..2c5fc32b28 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c @@ -68,6 +68,9 @@ #include "screen_access.h" #include "action.h" #include "radio.h" +#ifdef CONFIG_RTC +#include "rtc.h" +#endif #ifdef HAVE_RECORDING static bool in_screen = false; @@ -521,6 +524,12 @@ char *rec_create_filename(char *buffer) #ifdef CONFIG_RTC /* We'll wait at least up to the start of the next second so no duplicate names are created */ +#if CONFIG_RTC == RTC_DS1339_DS3231 + if(!rtc_detected) + return create_numbered_filename(buffer, buffer, "rec_", ext, 4 + IF_CNFN_NUM_(, &file_number)); + else +#endif return create_datetime_filename(buffer, buffer, "R", ext, true); #else return create_numbered_filename(buffer, buffer, "rec_", ext, 4 diff --git a/apps/scrobbler.c b/apps/scrobbler.c index a339429cab..1c0d98cbc6 100644 --- a/apps/scrobbler.c +++ b/apps/scrobbler.c @@ -35,6 +35,7 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging #ifdef CONFIG_RTC #include "time.h" #include "timefuncs.h" +#include "rtc.h" #endif #include "scrobbler.h" @@ -208,6 +209,11 @@ void scrobbler_change_event(struct mp3entry *id) logf("SCROBBLER: add pending"); copy_mp3entry(&scrobbler_entry, id); #ifdef CONFIG_RTC +#if CONFIG_RTC == RTC_DS1339_DS3231 + if(!rtc_detected) + timestamp = 0; + else +#endif timestamp = mktime(get_time()); #else timestamp = 0; diff --git a/firmware/SOURCES b/firmware/SOURCES index 03d2b16d1d..f07145ca06 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -137,6 +137,8 @@ drivers/rtc/rtc_pcf50606.c drivers/rtc/rtc_pcf50605.c #elif (CONFIG_RTC == RTC_E8564) drivers/rtc/rtc_e8564.c +#elif (CONFIG_RTC == RTC_DS1339_DS3231) +drivers/rtc/rtc_ds1339_ds3231.c #elif (CONFIG_RTC == RTC_S3C2440) drivers/rtc/rtc_s3c2440.c #elif (CONFIG_RTC == RTC_AS3514) @@ -380,6 +382,7 @@ target/coldfire/pcf50606-coldfire.c target/coldfire/iriver/ata-iriver.c target/coldfire/iriver/lcd-remote-iriver.c target/coldfire/iriver/system-iriver.c +target/coldfire/iriver/h300/sw_i2c-h300.c target/coldfire/iriver/h300/adc-h300.c target/coldfire/iriver/h300/backlight-h300.c target/coldfire/iriver/h300/button-h300.c @@ -400,6 +403,7 @@ target/coldfire/ata-as-coldfire.S target/coldfire/iriver/ata-iriver.c target/coldfire/iriver/lcd-remote-iriver.c target/coldfire/iriver/system-iriver.c +target/coldfire/iriver/h100/sw_i2c-h100.c target/coldfire/iriver/h100/adc-h100.c target/coldfire/iriver/h100/backlight-h100.c target/coldfire/iriver/h100/button-h100.c diff --git a/firmware/common/timefuncs.c b/firmware/common/timefuncs.c index e48aadd0a2..881bc23e53 100644 --- a/firmware/common/timefuncs.c +++ b/firmware/common/timefuncs.c @@ -49,6 +49,19 @@ struct tm *get_time(void) #ifdef CONFIG_RTC static long timeout = 0; +#if CONFIG_RTC == RTC_DS1339_DS3231 + if(!rtc_detected) { + tm.tm_sec = 0; + tm.tm_min = 0; + tm.tm_hour = 0; + tm.tm_mday = 1; + tm.tm_mon = 0; + tm.tm_year = 70; + tm.tm_wday = 1; + tm.tm_yday = 0; /* Not implemented for now */ + tm.tm_isdst = -1; /* Not implemented for now */ + } else +#endif /* Don't read the RTC more than once per second */ if (current_tick > timeout) { char rtcbuf[7]; diff --git a/firmware/drivers/eeprom_24cxx.c b/firmware/drivers/eeprom_24cxx.c index 6016c0f841..a0d8f83eb7 100644 --- a/firmware/drivers/eeprom_24cxx.c +++ b/firmware/drivers/eeprom_24cxx.c @@ -16,274 +16,21 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "lcd.h" -#include "cpu.h" -#include "system.h" -#include "kernel.h" -#include "thread.h" -#include "debug.h" + #include "logf.h" -#include "sprintf.h" #include "string.h" #include "inttypes.h" +#include "sw_i2c.h" + #include "eeprom_24cxx.h" -/** - * I2C-functions are copied and ported from fmradio.c. - */ - -#define SW_I2C_WRITE 0 -#define SW_I2C_READ 1 - /* Use cache to speedup writing to the chip. */ static char data_cache[EEPROM_SIZE]; static uint8_t cached_bitfield[EEPROM_SIZE/8]; #define IS_CACHED(addr) (cached_bitfield[addr/8] & (1 << (addr % 8))) -#define SET_CACHED(addr) (cached_bitfield[addr/8] |= 1 << (addr % 8)) - -/* h1x0 needs its own i2c driver, - h3x0 uses the pcf i2c driver */ - -#ifdef IRIVER_H100_SERIES - -/* cute little functions, atomic read-modify-write */ - -/* SCL is GPIO, 12 */ -#define SCL ( 0x00001000 & GPIO_READ) -#define SCL_OUT_LO and_l(~0x00001000, &GPIO_OUT) -#define SCL_LO or_l( 0x00001000, &GPIO_ENABLE) -#define SCL_HI and_l(~0x00001000, &GPIO_ENABLE) - -/* SDA is GPIO1, 13 */ -#define SDA ( 0x00002000 & GPIO1_READ) -#define SDA_OUT_LO and_l(~0x00002000, &GPIO1_OUT) -#define SDA_LO or_l( 0x00002000, &GPIO1_ENABLE) -#define SDA_HI and_l(~0x00002000, &GPIO1_ENABLE) - -/* delay loop to achieve 400kHz at 120MHz CPU frequency */ -#define DELAY do { int _x; for(_x=0;_x<22;_x++);} while(0) - -static void sw_i2c_init(void) -{ - logf("sw_i2c_init"); - or_l(0x00001000, &GPIO_FUNCTION); - or_l(0x00002000, &GPIO1_FUNCTION); - SDA_HI; - SCL_HI; - SDA_OUT_LO; - SCL_OUT_LO; -} - -static void sw_i2c_start(void) -{ - SCL_LO; - DELAY; - SDA_HI; - DELAY; - SCL_HI; - DELAY; - SDA_LO; - DELAY; - SCL_LO; -} - -static void sw_i2c_stop(void) -{ - SCL_HI; - DELAY; - SDA_HI; - DELAY; -} - -static void sw_i2c_ack(void) -{ - SCL_LO; - DELAY; - SDA_LO; - DELAY; - - SCL_HI; - DELAY; -} - -static bool sw_i2c_getack(void) -{ - bool ret = true; - int count = 10; - - SCL_LO; - DELAY; - SDA_HI; /* sets to input */ - DELAY; - SCL_HI; - DELAY; - - while (SDA && count--) - DELAY; - - if (SDA) - /* ack failed */ - ret = false; - - SCL_LO; - DELAY; - SDA_LO; - - return ret; -} - -static void sw_i2c_outb(unsigned char byte) -{ - int i; - - /* clock out each bit, MSB first */ - for ( i=0x80; i; i>>=1 ) - { - SCL_LO; - DELAY; - if ( i & byte ) - SDA_HI; - else - SDA_LO; - DELAY; - SCL_HI; - DELAY; - } -} - -static unsigned char sw_i2c_inb(void) -{ - int i; - unsigned char byte = 0; - - SDA_HI; /* sets to input */ - - /* clock in each bit, MSB first */ - for ( i=0x80; i; i>>=1 ) - { - SCL_HI; - DELAY; - if ( SDA ) - byte |= i; - SCL_LO; - DELAY; - } - - sw_i2c_ack(); - - return byte; -} - -#else - -#include "pcf50606.h" - -#define sw_i2c_init() /* no extra init required */ -#define sw_i2c_start() pcf50606_i2c_start() -#define sw_i2c_stop() pcf50606_i2c_stop() -#define sw_i2c_ack() pcf50606_i2c_ack(true) -#define sw_i2c_getack() pcf50606_i2c_getack() -#define sw_i2c_outb(x) pcf50606_i2c_outb(x) -#define sw_i2c_inb() pcf50606_i2c_inb(false) - -#endif /* IRIVER_H100_SERIES */ - - -int sw_i2c_write(int location, const unsigned char* buf, int count) -{ - int i; - - sw_i2c_start(); - sw_i2c_outb((EEPROM_ADDR & 0xfe) | SW_I2C_WRITE); - if (!sw_i2c_getack()) - { - sw_i2c_stop(); - return -1; - } - - sw_i2c_outb(location); - if (!sw_i2c_getack()) - { - sw_i2c_stop(); - return -2; - } - - for (i=0; itm_year - 80) << 9) | @@ -958,7 +965,14 @@ static void fat_time(unsigned short* date, if (tenth) *tenth = (tm->tm_sec & 1) * 100; -#else + +#if CONFIG_RTC == RTC_DS1339_DS3231 + } + else +#endif /* CONFIG_RTC == RTC_DS1339_DS3231 */ +#endif /* CONFIG_RTC */ +#if !defined(CONFIG_RTC) || CONFIG_RTC == RTC_DS1339_DS3231 + { /* non-RTC version returns an increment from the supplied time, or a * fixed standard time/date if no time given as input */ bool next_day = false; @@ -1025,9 +1039,9 @@ static void fat_time(unsigned short* date, } if (tenth) *tenth = 0; -#endif /* CONFIG_RTC */ + } +#endif /* !defined(CONFIG_RTC) || CONFIG_RTC == RTC_DS1339_DS3231 */ } - static int write_long_name(struct fat_file* file, unsigned int firstentry, unsigned int numentries, diff --git a/firmware/drivers/rtc/rtc_ds1339_ds3231.c b/firmware/drivers/rtc/rtc_ds1339_ds3231.c new file mode 100644 index 0000000000..df67fed735 --- /dev/null +++ b/firmware/drivers/rtc/rtc_ds1339_ds3231.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Robert Kukla + * based on Archos code by Linus Nielsen Feltzing, Uwe Freese, Laurent Baum + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "rtc.h" +#include "logf.h" +#include "sw_i2c.h" + +#define RTC_ADDR 0xD0 + +bool rtc_detected = false; + +void rtc_init(void) +{ + char byte; + + sw_i2c_init(); + + /* read one byte from RTC; 0 on success */ + rtc_detected = !sw_i2c_read(RTC_ADDR, 0, &byte, 1); + +#ifdef HAVE_ALARM_MOD + /* Check + save alarm bit first, before the power thread starts watching */ + rtc_check_alarm_started(false); +#endif + +} + +#ifdef HAVE_ALARM_MOD + +/* check whether the unit has been started by the RTC alarm function */ +/* (check for A2F, which => started using wakeup alarm) */ +bool rtc_check_alarm_started(bool release_alarm) +{ + static bool alarm_state, run_before; + bool rc; + + if (run_before) { + rc = alarm_state; + alarm_state &= ~release_alarm; + } else { + /* This call resets AF, so we store the state for later recall */ + rc = alarm_state = rtc_check_alarm_flag(); + run_before = true; + } + + return rc; +} +/* + * Checks the A2F flag. This call resets A2F once read. + * + */ +bool rtc_check_alarm_flag(void) +{ + unsigned char buf[1]; + bool flag = false; + + sw_i2c_read(RTC_ADDR, 0x0f, buf, 1); + if (buf[0] & 0x02) flag = true; + + rtc_enable_alarm(false); + + return flag; +} + +/* set alarm time registers to the given time (repeat once per day) */ +void rtc_set_alarm(int h, int m) +{ + unsigned char buf[3]; + + buf[0] = (((m / 10) << 4) | (m % 10)) & 0x7f; /* minutes */ + buf[1] = (((h / 10) << 4) | (h % 10)) & 0x3f; /* hour */ + buf[2] = 0x80; /* repeat every day */ + + sw_i2c_write(RTC_ADDR, 0x0b, buf, 3); +} + +/* read out the current alarm time */ +void rtc_get_alarm(int *h, int *m) +{ + unsigned char buf[2]; + + sw_i2c_read(RTC_ADDR, 0x0b, buf, 2); + + *m = ((buf[0] & 0x70) >> 4) * 10 + (buf[0] & 0x0f); + *h = ((buf[1] & 0x30) >> 4) * 10 + (buf[1] & 0x0f); +} + +/* turn alarm on or off by setting the alarm flag enable */ +/* the alarm is automatically disabled when the RTC gets Vcc power at startup */ +/* avoid that an alarm occurs when the device is on because this locks the ON key forever */ +/* returns false if alarm was set and alarm flag (output) is off */ +/* returns true if alarm flag went on, which would lock the device, so the alarm was disabled again */ +bool rtc_enable_alarm(bool enable) +{ + unsigned char buf[2]; + + buf[0] = enable ? 0x26 : 0x04; /* BBSQI INTCN A2IE vs INTCH only */ + buf[1] = 0x00; /* reset alarm flags (and OSF for good measure) */ + + sw_i2c_write(RTC_ADDR, 0x0e, buf, 2); + + return false; /* all ok */ +} + +#endif /* HAVE_ALARM_MOD */ + +int rtc_read_datetime(unsigned char* buf) +{ + int i; + + i = sw_i2c_read(RTC_ADDR, 0, buf, 7); + + buf[3]--; /* timefuncs wants 0..6 for wday */ + + return i; +} + +int rtc_write_datetime(unsigned char* buf) +{ + int i; + + buf[3]++; /* chip wants 1..7 for wday */ + buf[5]|=0x80; /* chip wants century (always 20xx) */ + + i = sw_i2c_write(RTC_ADDR, 0, buf, 7); + + return i; +} + diff --git a/firmware/export/config-h120.h b/firmware/export/config-h120.h index e7fb73ea0f..9dccf22d0e 100644 --- a/firmware/export/config-h120.h +++ b/firmware/export/config-h120.h @@ -45,7 +45,13 @@ /* Define this if you do software codec */ #define CONFIG_CODEC SWCODEC -/* Define this if you have an remote lcd */ +#ifndef SIMULATOR +/* RTC is autodetected on target only */ +#define CONFIG_RTC RTC_DS1339_DS3231 +#define HAVE_ALARM_MOD +#endif + + /* Define this if you have an remote lcd */ #define HAVE_REMOTE_LCD #define CONFIG_LCD LCD_S1D15E06 diff --git a/firmware/export/config.h b/firmware/export/config.h index ac2ee688e4..085f86af53 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -153,6 +153,7 @@ #define RTC_S3C2440 4 #define RTC_E8564 5 /* iriver H10 */ #define RTC_AS3514 6 /* Sandisk Sansa e200 series */ +#define RTC_DS1339_DS3231 7 /* h1x0 RTC mod */ /* USB On-the-go */ #define USBOTG_ISP1362 1362 /* iriver H300 */ diff --git a/firmware/export/rtc.h b/firmware/export/rtc.h index c7e3c4a96b..2f13cbb578 100644 --- a/firmware/export/rtc.h +++ b/firmware/export/rtc.h @@ -20,6 +20,7 @@ #define _RTC_H_ #include +#include #ifdef CONFIG_RTC @@ -27,6 +28,10 @@ extern const int dayname[]; extern const int monthname[]; +#if CONFIG_RTC == RTC_DS1339_DS3231 +extern bool rtc_detected; +#endif + /* Common functions for all targets */ void rtc_init(void); int rtc_read_datetime(unsigned char* buf); @@ -40,6 +45,8 @@ int rtc_read(unsigned char address); int rtc_read_multiple(unsigned char address, unsigned char *buf, int numbytes); int rtc_write(unsigned char address, unsigned char value); +#endif /* RTC_M41ST84W */ + #ifdef HAVE_ALARM_MOD void rtc_set_alarm(int h, int m); void rtc_get_alarm(int *h, int *m); @@ -48,8 +55,6 @@ bool rtc_check_alarm_started(bool release_alarm); bool rtc_check_alarm_flag(void); #endif /* HAVE_ALARM_MOD */ -#endif /* RTC_M41ST84W */ - #endif /* CONFIG_RTC */ #endif diff --git a/firmware/export/sw_i2c.h b/firmware/export/sw_i2c.h new file mode 100644 index 0000000000..42dccad742 --- /dev/null +++ b/firmware/export/sw_i2c.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Robert Kukla + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _SW_I2C_H +#define _SW_I2C_H + +#define SW_I2C_WRITE 0 +#define SW_I2C_READ 1 + +void sw_i2c_init(void); +int sw_i2c_write(unsigned char chip, unsigned char location, const unsigned char* buf, int count); +int sw_i2c_read (unsigned char chip, unsigned char location, unsigned char* buf, int count); + +#endif diff --git a/firmware/target/coldfire/iriver/h100/sw_i2c-h100.c b/firmware/target/coldfire/iriver/h100/sw_i2c-h100.c new file mode 100644 index 0000000000..cb061875e0 --- /dev/null +++ b/firmware/target/coldfire/iriver/h100/sw_i2c-h100.c @@ -0,0 +1,259 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Miika Pekkarinen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "logf.h" +#include "inttypes.h" + +#include "sw_i2c.h" + +/** + * I2C-functions are copied and ported from fmradio.c. + * later fixed, adapted and moved to a seperate file so they can be re-used by the rtc-ds1339c code by Robert Kukla + */ + +/* cute little functions, atomic read-modify-write */ + +/* SCL is GPIO, 12 */ +#define SCL ( 0x00001000 & GPIO_READ) +#define SCL_OUT_LO and_l(~0x00001000, &GPIO_OUT) +#define SCL_LO or_l( 0x00001000, &GPIO_ENABLE) +#define SCL_HI and_l(~0x00001000, &GPIO_ENABLE) + +/* SDA is GPIO1, 13 */ +#define SDA ( 0x00002000 & GPIO1_READ) +#define SDA_OUT_LO and_l(~0x00002000, &GPIO1_OUT) +#define SDA_LO or_l( 0x00002000, &GPIO1_ENABLE) +#define SDA_HI and_l(~0x00002000, &GPIO1_ENABLE) + +/* delay loop to achieve 400kHz at 120MHz CPU frequency */ +#define DELAY do { int _x; for(_x=0;_x<22;_x++);} while(0) + +void sw_i2c_init(void) +{ + or_l(0x00001000, &GPIO_FUNCTION); + or_l(0x00002000, &GPIO1_FUNCTION); + SDA_HI; + SCL_HI; + SDA_OUT_LO; + SCL_OUT_LO; +} + +/* in: C=? D=? + * out: C=L D=L + */ +static void sw_i2c_start(void) +{ + SCL_LO; + DELAY; + SDA_HI; + DELAY; + SCL_HI; + DELAY; + SDA_LO; + DELAY; + SCL_LO; +} + +/* in: C=L D=? + * out: C=H D=H + */ +static void sw_i2c_stop(void) +{ + SDA_LO; + DELAY; + SCL_HI; + DELAY; + SDA_HI; +} + +/* in: C=L D=H + * out: C=L D=L + */ +static void sw_i2c_ack(void) +{ + SDA_LO; + DELAY; + + SCL_HI; + DELAY; + SCL_LO; +} + +/* in: C=L D=H + * out: C=L D=H + */ +static void sw_i2c_nack(void) +{ + SDA_HI; /* redundant */ + DELAY; + + SCL_HI; + DELAY; + SCL_LO; +} + +/* in: C=L D=? + * out: C=L D=H + */ +static bool sw_i2c_getack(void) +{ + bool ret = true; +/* int count = 10; */ + + SDA_HI; /* sets to input */ + DELAY; + SCL_HI; + DELAY; + +/* while (SDA && count--) */ +/* DELAY; */ + + if (SDA) + /* ack failed */ + ret = false; + + SCL_LO; + + return ret; +} + +/* in: C=L D=? + * out: C=L D=? + */ +static void sw_i2c_outb(unsigned char byte) +{ + int i; + + /* clock out each bit, MSB first */ + for ( i=0x80; i; i>>=1 ) + { + if ( i & byte ) + SDA_HI; + else + SDA_LO; + DELAY; + + SCL_HI; + DELAY; + SCL_LO; + } +} + +/* in: C=L D=? + * out: C=L D=H + */ +static unsigned char sw_i2c_inb(void) +{ + int i; + unsigned char byte = 0; + + SDA_HI; /* sets to input */ + + /* clock in each bit, MSB first */ + for ( i=0x80; i; i>>=1 ) + { + DELAY; + do { + SCL_HI; + DELAY; + } + while(SCL==0); /* wait for any SCL clock stretching */ + if ( SDA ) + byte |= i; + SCL_LO; + } + + return byte; +} + +int sw_i2c_write(unsigned char chip, unsigned char location, const unsigned char* buf, int count) +{ + int i; + + sw_i2c_start(); + sw_i2c_outb((chip & 0xfe) | SW_I2C_WRITE); + if (!sw_i2c_getack()) + { + sw_i2c_stop(); + return -1; + } + + sw_i2c_outb(location); + if (!sw_i2c_getack()) + { + sw_i2c_stop(); + return -2; + } + + for (i=0; i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Miika Pekkarinen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "logf.h" +#include "inttypes.h" + +#include "sw_i2c.h" + +#include "pcf50606.h" + +void sw_i2c_init(void) +{ + /* no extra init required */ +} + +int sw_i2c_write(unsigned char chip, unsigned char location, const unsigned char* buf, int count) +{ + int i; + + pcf50606_i2c_start(); + pcf50606_i2c_outb((chip & 0xfe) | SW_I2C_WRITE); + if (!pcf50606_i2c_getack()) + { + pcf50606_i2c_stop(); + return -1; + } + + pcf50606_i2c_outb(location); + if (!pcf50606_i2c_getack()) + { + pcf50606_i2c_stop(); + return -2; + } + + for (i=0; i