summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Volgmann <Thomas.Volgmann@dsa-volgmann.de>2015-04-10 08:23:00 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-04-10 08:23:00 +0200
commita1d6f7a405328f8eb5a7d86bdf509db77e74b683 (patch)
treed9ea22b58dea1cc88c83d6b4316d7dd7c79f271c
parentarm: Align ARM exception frame to 8 bytes (diff)
downloadrtems-a1d6f7a405328f8eb5a7d86bdf509db77e74b683.tar.bz2
bsp/altera-cyclone-v: Add RTC driver
-rw-r--r--c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c766
1 files changed, 622 insertions, 144 deletions
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c b/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c
index 3c18d1cf9b..aab39b321f 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c
@@ -13,7 +13,8 @@
*/
/*
- * Driver for the DS1339 RTC.
+ * Driver for the DS1339 RTC (Maxim Semiconductors) -> RTC1
+ * and the M41ST87 RTC (ST Microelectronics) -> RTC2
*
* Please note the following points:
* - The day of week is ignored.
@@ -31,114 +32,147 @@
#include <unistd.h>
#include <bsp/i2cdrv.h>
-#define ALTERA_CYCLONE_V_RTC_NUMBER 1
+#define ALTERA_CYCLONE_V_RTC_NUMBER 2
-#define DS1339_I2C_ADDRESS 0x68
-#define DS1339_I2C_BUS_DEVICE "/dev/i2c0"
-#define DS1339_ADDR_CTRL 0x0E
-#define DS1339_CTRL_EOSC 0x80
-#define DS1339_CTRL_BBSQI 0x20
-#define DS1339_CTRL_RS2 0x10
-#define DS1339_CTRL_RS1 0x08
-#define DS1339_CTRL_INTCN 0x04
-#define DS1339_CTRL_A2IE 0x02
-#define DS1339_CTRL_A1IE 0x01
+/* ******************************* DS1339 ********************************** */
-#define DS1339_CTRL_DEFAULT (0x00)
-#define DS1339_ADDR_TIME 0x00
-#define DS1339_ADDR_STATUS 0x0F
-#define DS1339_STATUS_OSF 0x80
-#define DS1339_STATUS_A2F 0x02
-#define DS1339_STATUS_A1F 0x01
+#define DS1339_I2C_ADDRESS (0xD0 >> 1) /* 7-bit addressing! */
+#define DS1339_I2C_BUS_DEVICE "/dev/i2c0"
-#define DS1339_STATUS_CLEAR (0x00)
+#define DS1339_ADDR_TIME 0x00
-typedef struct {
- uint8_t seconds;
- uint8_t minutes;
- uint8_t hours;
+#define DS1339_ADDR_CTRL 0x0E
+#define DS1339_CTRL_EOSC 0x80
+#define DS1339_CTRL_BBSQI 0x20
+#define DS1339_CTRL_RS2 0x10
+#define DS1339_CTRL_RS1 0x08
+#define DS1339_CTRL_INTCN 0x04
+#define DS1339_CTRL_A2IE 0x02
+#define DS1339_CTRL_A1IE 0x01
+
+#define DS1339_CTRL_DEFAULT (0x00)
+
+#define DS1339_ADDR_STATUS 0x0F
+#define DS1339_STATUS_OSF 0x80
+#define DS1339_STATUS_A2F 0x02
+#define DS1339_STATUS_A1F 0x01
+
+#define DS1339_STATUS_CLEAR (0x00)
+
+#define DS1339_ADDR_TRICKLE_CHARGE 0x10
+
+
+typedef struct
+{
+ uint8_t seconds;
+ uint8_t minutes;
+ uint8_t hours;
#define DS1339_HOURS_12_24_FLAG 0x40
#define DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS 0x20
#define DS1339_HOURS_10_HOURS 0x10
- uint8_t weekday;
- uint8_t date;
- uint8_t month;
+ uint8_t weekday;
+ uint8_t date;
+ uint8_t month;
#define DS1339_MONTH_CENTURY 0x80
- uint8_t year;
-} ds1339_time_t;
+ uint8_t year;
+}
+ds1339_time_t;
+
/* The longest write transmission is writing the time + one address bit */
-#define DS1339_MAX_WRITE_SIZE (sizeof(ds1339_time_t) + 1)
+#define DS1339_MAX_WRITE_SIZE (sizeof(ds1339_time_t) + 1)
+
/* Functions for converting the fields */
-static unsigned int get_seconds (ds1339_time_t *time) {
- uint8_t tens = time->seconds >> 4;
- uint8_t ones = time->seconds & 0x0F;
+static unsigned int ds1339_get_seconds(ds1339_time_t* time)
+{
+ uint8_t tens = time->seconds >> 4;
+ uint8_t ones = time->seconds & 0x0F;
+
return tens * 10 + ones;
}
-static unsigned int get_minutes (ds1339_time_t *time) {
- uint8_t tens = time->minutes >> 4;
- uint8_t ones = time->minutes & 0x0F;
+
+static unsigned int ds1339_get_minutes(ds1339_time_t* time)
+{
+ uint8_t tens = time->minutes >> 4;
+ uint8_t ones = time->minutes & 0x0F;
+
return tens * 10 + ones;
}
-static unsigned int get_hours (ds1339_time_t *time) {
- uint8_t value = time->hours & 0x0F;
- if(time->hours & DS1339_HOURS_10_HOURS) {
+static unsigned int ds1339_get_hours(ds1339_time_t* time)
+{
+
+ uint8_t value = time->hours & 0x0F;
+
+ if (time->hours & DS1339_HOURS_10_HOURS)
+ {
value += 10;
}
- if(time->hours & DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS) {
- if(time->hours & DS1339_HOURS_12_24_FLAG) {
+ if (time->hours & DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS)
+ {
+ if (time->hours & DS1339_HOURS_12_24_FLAG)
value += 12;
- } else {
+ else
value += 20;
- }
}
return value;
}
-static unsigned int get_day_of_month (ds1339_time_t *time) {
- uint8_t tens = time->date >> 4;
- uint8_t ones = time->date & 0x0F;
+
+static unsigned int ds1339_get_day_of_month(ds1339_time_t* time)
+{
+
+ uint8_t tens = time->date >> 4;
+ uint8_t ones = time->date & 0x0F;
+
return tens * 10 + ones;
}
-static unsigned int get_month (ds1339_time_t *time) {
- uint8_t tens = (time->month >> 4) & 0x07;
- uint8_t ones = time->month & 0x0F;
+
+static unsigned int ds1339_get_month(ds1339_time_t* time)
+{
+
+ uint8_t tens = (time->month >> 4) & 0x07;
+ uint8_t ones = time->month & 0x0F;
+
return tens * 10 + ones;
}
-static unsigned int get_year (ds1339_time_t *time) {
- unsigned int year = 1900;
+
+static unsigned int ds1339_get_year(ds1339_time_t* time)
+{
+
+ unsigned int year = 1900;
+
year += (time->year >> 4) * 10;
year += time->year & 0x0F;
- if(time->month & DS1339_MONTH_CENTURY) {
+ if (time->month & DS1339_MONTH_CENTURY)
year += 100;
- }
- if(year < TOD_BASE_YEAR) {
+ if (year < TOD_BASE_YEAR)
year += 200;
- }
+
return year;
}
-static void set_time (
- ds1339_time_t *time,
- unsigned int second,
- unsigned int minute,
- unsigned int hour,
- unsigned int day,
- unsigned int month,
- unsigned int year
-) {
- unsigned int tens;
- unsigned int ones;
- uint8_t century = 0;
+
+static void ds1339_set_time(ds1339_time_t* time,
+ unsigned int second,
+ unsigned int minute,
+ unsigned int hour,
+ unsigned int day,
+ unsigned int month,
+ unsigned int year)
+{
+
+ unsigned int tens;
+ unsigned int ones;
+ uint8_t century = 0;
tens = second / 10;
ones = second % 10;
@@ -161,78 +195,83 @@ static void set_time (
tens = month / 10;
ones = month % 10;
- if(year >= 2000 && year < 2100) {
+ if ((year >= 2000) && (year < 2100))
century = DS1339_MONTH_CENTURY;
- }
time->month = century | tens << 4 | ones;
tens = (year % 100) / 10;
ones = year % 10;
time->year = tens << 4 | ones;
+
}
-static rtems_status_code ds1339_open_file(int *fd)
+
+
+static rtems_status_code ds1339_open_file(int* fd)
{
- int rv = 0;
- rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
*fd = open(DS1339_I2C_BUS_DEVICE, O_RDWR);
- if ( *fd == -1 ) {
+ if (*fd == -1)
sc = RTEMS_IO_ERROR;
- }
- if ( sc == RTEMS_SUCCESSFUL ) {
+ if (sc == RTEMS_SUCCESSFUL)
+ {
rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, DS1339_I2C_ADDRESS);
- if ( rv == -1 ) {
+ if (rv == -1)
sc = RTEMS_IO_ERROR;
- }
}
return sc;
}
+
/* Read size bytes from ds1339 register address addr to buf. */
-static rtems_status_code ds1339_read(uint8_t addr, void *buf, size_t size)
+static rtems_status_code ds1339_read(uint8_t addr, void* buf, size_t size)
{
- int fd = -1;
- int rv = 0;
- rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ int fd = -1;
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
sc = ds1339_open_file(&fd);
- if ( sc == RTEMS_SUCCESSFUL ) {
+ if (sc == RTEMS_SUCCESSFUL)
+ {
rv = write(fd, &addr, sizeof(addr));
- if ( rv != sizeof(addr) ) {
+ if (rv != sizeof(addr))
sc = RTEMS_IO_ERROR;
- }
}
- if ( sc == RTEMS_SUCCESSFUL ) {
+ if (sc == RTEMS_SUCCESSFUL)
+ {
rv = read(fd, buf, size);
- if ( rv != size ) {
+ if (rv != size)
sc = RTEMS_IO_ERROR;
- }
}
rv = close(fd);
- if ( rv != 0 ) {
+ if (rv != 0)
sc = RTEMS_IO_ERROR;
- }
return sc;
}
+
/* Write size bytes from buf to ds1339 register address addr. */
-static rtems_status_code ds1339_write(uint8_t addr, void *buf, size_t size)
+static rtems_status_code ds1339_write(uint8_t addr, void* buf, size_t size)
{
- int fd = -1;
- int rv = 0;
- rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ int fd = -1;
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
/* The driver never writes many bytes. Therefore it should be less expensive
* to reserve the maximum number of bytes that will be written in one go than
* use a malloc. */
- uint8_t local_buf[DS1339_MAX_WRITE_SIZE];
- int write_size = size + 1;
+ uint8_t local_buf[DS1339_MAX_WRITE_SIZE];
+ int write_size = size + 1;
assert(write_size <= DS1339_MAX_WRITE_SIZE);
@@ -241,34 +280,37 @@ static rtems_status_code ds1339_write(uint8_t addr, void *buf, size_t size)
sc = ds1339_open_file(&fd);
- if ( sc == RTEMS_SUCCESSFUL ) {
+ if (sc == RTEMS_SUCCESSFUL)
+ {
rv = write(fd, local_buf, write_size);
- if ( rv != write_size ) {
+ if (rv != write_size)
sc = RTEMS_IO_ERROR;
- }
}
rv = close(fd);
- if ( rv != 0 ) {
+ if (rv != 0)
sc = RTEMS_IO_ERROR;
- }
return RTEMS_SUCCESSFUL;
}
-static void altera_cyclone_v_rtc_initialize(int minor)
+
+static void altera_cyclone_v_ds1339_initialize(int minor)
{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- uint8_t status = 0;
+
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint8_t status = 0;
/* Check RTC valid */
sc = ds1339_read(DS1339_ADDR_STATUS, &status, sizeof(status));
assert(sc == RTEMS_SUCCESSFUL);
- if(status & DS1339_STATUS_OSF) {
+
+ if (status & DS1339_STATUS_OSF)
+ {
/* RTC has been stopped. Initialise it. */
ds1339_time_t time;
- uint8_t write = DS1339_CTRL_DEFAULT;
+ uint8_t write = DS1339_CTRL_DEFAULT;
sc = ds1339_write(DS1339_ADDR_CTRL, &write, sizeof(write));
assert(sc == RTEMS_SUCCESSFUL);
@@ -276,81 +318,517 @@ static void altera_cyclone_v_rtc_initialize(int minor)
sc = ds1339_write(DS1339_ADDR_STATUS, &write, sizeof(write));
assert(sc == RTEMS_SUCCESSFUL);
- set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
+ ds1339_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
assert(sc == RTEMS_SUCCESSFUL);
}
+
}
-static int altera_cyclone_v_rtc_get_time(int minor, rtems_time_of_day *tod)
+
+static int altera_cyclone_v_ds1339_get_time(int minor, rtems_time_of_day* tod)
{
- ds1339_time_t time;
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- rtems_time_of_day temp_tod;
- sc = ds1339_read(DS1339_ADDR_TIME, &time, sizeof(time));
+ ds1339_time_t time;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_time_of_day temp_tod;
- if ( sc == RTEMS_SUCCESSFUL ) {
- temp_tod.ticks = 0;
- temp_tod.second = get_seconds(&time);
- temp_tod.minute = get_minutes(&time);
- temp_tod.hour = get_hours(&time);
- temp_tod.day = get_day_of_month(&time);
- temp_tod.month = get_month(&time);
- temp_tod.year = get_year(&time);
+ sc = ds1339_read(DS1339_ADDR_TIME, &time, sizeof(time));
- if ( _TOD_Validate(&temp_tod) ) {
+ if (sc == RTEMS_SUCCESSFUL)
+ {
+ temp_tod.ticks = 0;
+ temp_tod.second = ds1339_get_seconds(&time);
+ temp_tod.minute = ds1339_get_minutes(&time);
+ temp_tod.hour = ds1339_get_hours(&time);
+ temp_tod.day = ds1339_get_day_of_month(&time);
+ temp_tod.month = ds1339_get_month(&time);
+ temp_tod.year = ds1339_get_year(&time);
+
+ if (_TOD_Validate(&temp_tod))
memcpy(tod, &temp_tod, sizeof(temp_tod));
- } else {
+ else
sc = RTEMS_INVALID_CLOCK;
- }
}
return -sc;
}
-static int altera_cyclone_v_rtc_set_time(int minor, const rtems_time_of_day *tod)
+
+static int altera_cyclone_v_ds1339_set_time(int minor, const rtems_time_of_day* tod)
{
- ds1339_time_t time;
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- set_time (
- &time,
- tod->second,
- tod->minute,
- tod->hour,
- tod->day,
- tod->month,
- tod->year
- );
+ ds1339_time_t time;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ ds1339_set_time(&time,
+ tod->second,
+ tod->minute,
+ tod->hour,
+ tod->day,
+ tod->month,
+ tod->year
+ );
sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
return -sc;
}
-static bool altera_cyclone_v_rtc_probe(int minor)
+
+static bool altera_cyclone_v_ds1339_probe(int minor)
+{
+
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint8_t buf;
+
+ /* try to read from register address 0x00 */
+ sc = ds1339_read(0x00, &buf, 1);
+ if (sc != RTEMS_SUCCESSFUL)
+ /* no RTC implemented */
+ return false;
+ /* try to read from register address 0x20 (not implemented in DS1339) */
+ sc = ds1339_read(0x20, &buf, 1);
+ if (sc == RTEMS_SUCCESSFUL)
+ /* RTC is not DS1339 */
+ return false;
+
+ printk("RTC detected, type = DS1339\n");
+ return true;
+
+}
+
+
+/* ******************************* M41ST87 ********************************** */
+
+
+#define M41ST87_I2C_ADDRESS (0xD0 >> 1) /* 7-bit addressing! */
+#define M41ST87_I2C_BUS_DEVICE "/dev/i2c0"
+
+#define M41ST87_ADDR_TIME 0x00
+
+#define M41ST87_ADDR_CTRL 0x08
+#define M41ST87_CTRL_OUT 0x80
+#define M41ST87_CTRL_FT 0x40
+#define M41ST87_CTRL_S 0x20
+#define M41ST87_CTRL_CAL 0x1F
+
+#define M41ST87_ADDR_ALARM_HOUR 0x0C
+#define M41ST87_BIT_HT 0x40
+
+#define M41ST87_ADDR_FLAGS 0x0F
+#define M41ST87_FLAG_WDF 0x80
+#define M41ST87_FLAG_AF 0x40
+#define M41ST87_FLAG_BL 0x10
+#define M41ST87_FLAG_OF 0x04
+#define M41ST87_FLAG_TB1 0x02
+#define M41ST87_FLAG_TB2 0x01
+
+#define M41ST87_ADDR_USER_RAM 0x20
+
+
+typedef struct
+{
+ uint8_t sec100;
+ uint8_t seconds;
+#define M41ST87_BIT_ST 0x80
+ uint8_t minutes;
+#define M41ST87_BIT_OFIE 0x80
+ uint8_t hours;
+#define M41ST87_BIT_CB1 0x80
+#define M41ST87_BIT_CB0 0x40
+ uint8_t weekday;
+#define M41ST87_BIT_TR 0x80
+#define M41ST87_BIT_THS 0x40
+#define M41ST87_BIT_CLRPW1 0x20
+#define M41ST87_BIT_CLRPW0 0x10
+#define M41ST87_BIT_32KE 0x08
+ uint8_t day;
+#define M41ST87_BIT_PFOD 0x80
+ uint8_t month;
+ uint8_t year;
+}
+m41st87_time_t;
+
+
+/* The longest write transmission is writing the time + one address bit */
+#define M41ST87_MAX_WRITE_SIZE (sizeof(m41st87_time_t) + 1)
+
+
+/* Functions for converting the fields */
+
+/*
+static unsigned int m41st87_get_sec100(m41st87_time_t* time)
+{
+
+ uint8_t tens = time->sec100 >> 4;
+ uint8_t ones = time->sec100 & 0x0F;
+
+ return tens * 10 + ones;
+}
+*/
+
+
+static unsigned int m41st87_get_seconds(m41st87_time_t* time)
+{
+
+ uint8_t tens = (time->seconds >> 4) & 0x07;
+ uint8_t ones = time->seconds & 0x0F;
+
+ return tens * 10 + ones;
+}
+
+
+static unsigned int m41st87_get_minutes(m41st87_time_t* time)
+{
+
+ uint8_t tens = (time->minutes >> 4) & 0x07;
+ uint8_t ones = time->minutes & 0x0F;
+
+ return tens * 10 + ones;
+}
+
+
+static unsigned int m41st87_get_hours(m41st87_time_t* time)
+{
+
+ uint8_t tens = (time->hours >> 4) & 0x03;
+ uint8_t ones = time->hours & 0x0F;
+
+ return tens * 10 + ones;
+}
+
+
+/*
+static unsigned int m41st87_get_day_of_week(m41st87_time_t* time)
+{
+
+ return time->weekday & 0x07;
+}
+*/
+
+
+static unsigned int m41st87_get_day_of_month(m41st87_time_t* time)
+{
+
+ uint8_t tens = (time->day >> 4) & 0x03;
+ uint8_t ones = time->day & 0x0F;
+
+ return tens * 10 + ones;
+}
+
+
+static unsigned int m41st87_get_month(m41st87_time_t* time)
+{
+
+ uint8_t tens = (time->month >> 4) & 0x01;
+ uint8_t ones = time->month & 0x0F;
+
+ return tens * 10 + ones;
+}
+
+
+static unsigned int m41st87_get_year(m41st87_time_t* time)
+{
+
+ uint8_t century = time->hours >> 6;
+ uint8_t tens = time->year >> 4;
+ uint8_t ones = time->year & 0x0F;
+
+ return 1900 + century * 100 + tens * 10 + ones;
+}
+
+
+static void m41st87_set_time(m41st87_time_t* time,
+ unsigned int second,
+ unsigned int minute,
+ unsigned int hour,
+ unsigned int day,
+ unsigned int month,
+ unsigned int year)
+{
+
+ unsigned int century;
+ unsigned int tens;
+ unsigned int ones;
+
+ if (year < 1900)
+ year = 1900;
+ if (year > 2399)
+ year = 2399;
+ century = (year - 1900) / 100;
+
+ /* Hundreds of seconds is not used, set to 0 */
+ time->sec100 = 0;
+
+ tens = second / 10;
+ ones = second % 10;
+ time->seconds = (time->seconds & 0x80) | (tens << 4) | ones;
+
+ tens = minute / 10;
+ ones = minute % 10;
+ time->minutes = (time->minutes & 0x80) | (tens << 4) | ones;
+
+ tens = hour / 10;
+ ones = hour % 10;
+ time->hours = (century << 6) | (tens << 4) | ones;
+
+ /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
+ time->weekday = (time->weekday & 0xF8) | 1;
+
+ tens = day / 10;
+ ones = day % 10;
+ time->day = (time->day & 0x80) | (tens << 4) | ones;
+
+ tens = month / 10;
+ ones = month % 10;
+ time->month = (tens << 4) | ones;
+
+ tens = (year % 100) / 10;
+ ones = year % 10;
+ time->year = (tens << 4) | ones;
+
+}
+
+
+
+static rtems_status_code m41st87_open_file(int* fd)
+{
+
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ *fd = open(M41ST87_I2C_BUS_DEVICE, O_RDWR);
+ if (*fd == -1)
+ sc = RTEMS_IO_ERROR;
+
+ if (sc == RTEMS_SUCCESSFUL)
+ {
+ rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, M41ST87_I2C_ADDRESS);
+ if (rv == -1)
+ sc = RTEMS_IO_ERROR;
+ }
+
+ return sc;
+}
+
+
+/* Read size bytes from m41st87 register address addr to buf. */
+static rtems_status_code m41st87_read(uint8_t addr, void* buf, size_t size)
+{
+
+ int fd = -1;
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = m41st87_open_file(&fd);
+
+ if (sc == RTEMS_SUCCESSFUL)
+ {
+ rv = write(fd, &addr, sizeof(addr));
+ if (rv != sizeof(addr))
+ sc = RTEMS_IO_ERROR;
+ }
+
+ if (sc == RTEMS_SUCCESSFUL)
+ {
+ rv = read(fd, buf, size);
+ if (rv != size)
+ sc = RTEMS_IO_ERROR;
+ }
+
+ rv = close(fd);
+ if (rv != 0)
+ sc = RTEMS_IO_ERROR;
+
+ return sc;
+}
+
+
+/* Write size bytes from buf to m41st87 register address addr. */
+static rtems_status_code m41st87_write(uint8_t addr, void* buf, size_t size)
+{
+
+ int fd = -1;
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ /* The driver never writes many bytes. Therefore it should be less expensive
+ * to reserve the maximum number of bytes that will be written in one go than
+ * use a malloc. */
+ uint8_t local_buf[M41ST87_MAX_WRITE_SIZE];
+ int write_size = size + 1;
+
+ assert(write_size <= M41ST87_MAX_WRITE_SIZE);
+
+ local_buf[0] = addr;
+ memcpy(&local_buf[1], buf, size);
+
+ sc = m41st87_open_file(&fd);
+
+ if (sc == RTEMS_SUCCESSFUL)
+ {
+ rv = write(fd, local_buf, write_size);
+ if (rv != write_size)
+ sc = RTEMS_IO_ERROR;
+ }
+
+ rv = close(fd);
+ if (rv != 0)
+ sc = RTEMS_IO_ERROR;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+static void altera_cyclone_v_m41st87_initialize(int minor)
+{
+
+ m41st87_time_t time;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint8_t value;
+
+ /* Check RTC valid */
+ sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
+ assert(sc == RTEMS_SUCCESSFUL);
+
+ if (time.seconds & M41ST87_BIT_ST)
+ {
+ /* RTC has been stopped. Reset stop flag. */
+ time.seconds = 0;
+ /* Initialise RTC. */
+ m41st87_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
+ sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));
+ assert(sc == RTEMS_SUCCESSFUL);
+ }
+
+ /* Reset HT bit */
+ sc = m41st87_read(M41ST87_ADDR_ALARM_HOUR, &value, 1);
+ assert(sc == RTEMS_SUCCESSFUL);
+ value &= ~M41ST87_BIT_HT;
+ sc = m41st87_write(M41ST87_ADDR_ALARM_HOUR, &value, 1);
+ assert(sc == RTEMS_SUCCESSFUL);
+
+}
+
+
+static int altera_cyclone_v_m41st87_get_time(int minor, rtems_time_of_day* tod)
+{
+
+ m41st87_time_t time;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_time_of_day temp_tod;
+
+ sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
+ if (sc != RTEMS_SUCCESSFUL)
+ return -sc;
+
+ temp_tod.ticks = 0;
+ temp_tod.second = m41st87_get_seconds(&time);
+ temp_tod.minute = m41st87_get_minutes(&time);
+ temp_tod.hour = m41st87_get_hours(&time);
+ temp_tod.day = m41st87_get_day_of_month(&time);
+ temp_tod.month = m41st87_get_month(&time);
+ temp_tod.year = m41st87_get_year(&time);
+
+ if (_TOD_Validate(&temp_tod))
+ memcpy(tod, &temp_tod, sizeof(temp_tod));
+ else
+ sc = RTEMS_INVALID_CLOCK;
+
+ return -sc;
+}
+
+
+static int altera_cyclone_v_m41st87_set_time(int minor, const rtems_time_of_day* tod)
+{
+
+ m41st87_time_t time;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ /* first read to preserve the additional flags */
+ sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
+ if (sc != RTEMS_SUCCESSFUL)
+ return -sc;
+
+ m41st87_set_time(&time,
+ tod->second,
+ tod->minute,
+ tod->hour,
+ tod->day,
+ tod->month,
+ tod->year
+ );
+
+ sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));
+
+ return -sc;
+}
+
+
+static bool altera_cyclone_v_m41st87_probe(int minor)
{
- /* FIXME: Probe for i2c device */
+
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint8_t buf;
+
+ /* try to read from register address 0x00 */
+ sc = m41st87_read(0x00, &buf, 1);
+ if (sc != RTEMS_SUCCESSFUL)
+ /* no RTC implemented */
+ return false;
+ /* try to read from register address 0x20 (implemented in M41ST87) */
+ sc = m41st87_read(0x20, &buf, 1);
+ if (sc != RTEMS_SUCCESSFUL)
+ /* RTC is not M41ST87 */
+ return false;
+
+ printk("RTC detected, type = M41ST87\n");
return true;
+
}
-const rtc_fns altera_cyclone_v_rtc_ops = {
- .deviceInitialize = altera_cyclone_v_rtc_initialize,
- .deviceGetTime = altera_cyclone_v_rtc_get_time,
- .deviceSetTime = altera_cyclone_v_rtc_set_time
+
+/* **************************************** General ********************************** */
+
+
+const rtc_fns altera_cyclone_v_ds1339_ops =
+{
+ .deviceInitialize = altera_cyclone_v_ds1339_initialize,
+ .deviceGetTime = altera_cyclone_v_ds1339_get_time,
+ .deviceSetTime = altera_cyclone_v_ds1339_set_time
};
-size_t RTC_Count = ALTERA_CYCLONE_V_RTC_NUMBER;
-rtems_device_minor_number RTC_Minor = 0;
+const rtc_fns altera_cyclone_v_m41st87_ops =
+{
+ .deviceInitialize = altera_cyclone_v_m41st87_initialize,
+ .deviceGetTime = altera_cyclone_v_m41st87_get_time,
+ .deviceSetTime = altera_cyclone_v_m41st87_set_time
+};
+
+
+size_t RTC_Count = ALTERA_CYCLONE_V_RTC_NUMBER;
+rtems_device_minor_number RTC_Minor = 0;
+
-rtc_tbl RTC_Table [ALTERA_CYCLONE_V_RTC_NUMBER] = {
+rtc_tbl RTC_Table[ALTERA_CYCLONE_V_RTC_NUMBER] =
+{
+ {
+ .sDeviceName = "/dev/rtc",
+ .deviceType = RTC_CUSTOM,
+ .pDeviceFns = &altera_cyclone_v_ds1339_ops,
+ .deviceProbe = altera_cyclone_v_ds1339_probe,
+ .pDeviceParams = NULL,
+ .ulCtrlPort1 = 0,
+ .ulDataPort = 0,
+ .getRegister = NULL,
+ .setRegister = NULL
+ },
{
.sDeviceName = "/dev/rtc",
.deviceType = RTC_CUSTOM,
- .pDeviceFns = &altera_cyclone_v_rtc_ops,
- .deviceProbe = altera_cyclone_v_rtc_probe,
+ .pDeviceFns = &altera_cyclone_v_m41st87_ops,
+ .deviceProbe = altera_cyclone_v_m41st87_probe,
.pDeviceParams = NULL,
.ulCtrlPort1 = 0,
.ulDataPort = 0,