FS#6419 - driver for H1x0 series RTC Mod with runtime detection

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12520 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Robert Kukla 2007-02-28 13:20:36 +00:00
parent 343c428f2c
commit 50b5ee4781
18 changed files with 660 additions and 268 deletions

View File

@ -23,7 +23,9 @@
#include <stdlib.h>
#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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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];

View File

@ -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; i<count; i++)
{
sw_i2c_outb(buf[i]);
if (!sw_i2c_getack())
{
sw_i2c_stop();
return -3;
}
}
sw_i2c_stop();
return 0;
}
int sw_i2c_write_byte(int location, unsigned char byte)
{
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;
}
sw_i2c_outb(byte);
if (!sw_i2c_getack())
{
sw_i2c_stop();
return -3;
}
sw_i2c_stop();
return 0;
}
int sw_i2c_read(unsigned char location, unsigned char* byte)
{
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;
}
sw_i2c_start();
sw_i2c_outb((EEPROM_ADDR & 0xfe) | SW_I2C_READ);
if (!sw_i2c_getack())
{
sw_i2c_stop();
return -3;
}
*byte = sw_i2c_inb();
sw_i2c_stop();
return 0;
}
#define SET_CACHED(addr) (cached_bitfield[addr/8] |= 1 << (addr % 8))
void eeprom_24cxx_init(void)
{
@ -314,7 +61,7 @@ int eeprom_24cxx_read_byte(unsigned int address, char *c)
*c = 0;
do
{
ret = sw_i2c_read(address, &byte);
ret = sw_i2c_read(EEPROM_ADDR, address, &byte, 1);
} while (ret < 0 && count++ < 200);
if (ret < 0)
@ -357,7 +104,7 @@ int eeprom_24cxx_write_byte(unsigned int address, char c)
do
{
ret = sw_i2c_write_byte(address, c);
ret = sw_i2c_write(EEPROM_ADDR, address, &c, 1);
} while (ret < 0 && count++ < 200) ;
if (ret < 0)

View File

@ -31,6 +31,9 @@
#include "rbunicode.h"
#include "logf.h"
#include "atoi.h"
#ifdef CONFIG_RTC
#include "rtc.h"
#endif
#define BYTES2INT16(array,pos) \
(array[pos] | (array[pos+1] << 8 ))
@ -945,6 +948,10 @@ static void fat_time(unsigned short* date,
{
#ifdef CONFIG_RTC
struct tm* tm = get_time();
#if CONFIG_RTC == RTC_DS1339_DS3231
if(rtc_detected)
{
#endif /* CONFIG_RTC == RTC_DS1339_DS3231 */
if (date)
*date = ((tm->tm_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,

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -20,6 +20,7 @@
#define _RTC_H_
#include <stdbool.h>
#include <system.h>
#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

30
firmware/export/sw_i2c.h Normal file
View File

@ -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

View File

@ -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<count; i++)
{
sw_i2c_outb(buf[i]);
if (!sw_i2c_getack())
{
sw_i2c_stop();
return -3;
}
}
sw_i2c_stop();
return 0;
}
int sw_i2c_read(unsigned char chip, unsigned char location, 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;
}
sw_i2c_start();
sw_i2c_outb((chip & 0xfe) | SW_I2C_READ);
if (!sw_i2c_getack())
{
sw_i2c_stop();
return -3;
}
for (i=0; i<count-1; i++)
{
buf[i] = sw_i2c_inb();
sw_i2c_ack();
}
/* 1byte min */
buf[i] = sw_i2c_inb();
sw_i2c_nack();
sw_i2c_stop();
return 0;
}

View File

@ -0,0 +1,105 @@
/***************************************************************************
* __________ __ ___.
* 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"
#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<count; i++)
{
pcf50606_i2c_outb(buf[i]);
if (!pcf50606_i2c_getack())
{
pcf50606_i2c_stop();
return -3;
}
}
pcf50606_i2c_stop();
return 0;
}
int sw_i2c_read(unsigned char chip, unsigned char location, 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;
}
pcf50606_i2c_start();
pcf50606_i2c_outb((chip & 0xfe) | SW_I2C_READ);
if (!pcf50606_i2c_getack())
{
pcf50606_i2c_stop();
return -3;
}
for (i=0; i<count-1; i++)
{
buf[i] = pcf50606_i2c_inb(true);
}
/* 1byte min */
buf[i] = pcf50606_i2c_inb(false);
pcf50606_i2c_stop();
return 0;
}