summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mauderer <Christian.Mauderer@embedded-brains.de>2014-07-15 16:20:37 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-08-11 08:01:26 +0200
commit81329f9ecf7c289c67cf0ff7ee54898d9311429e (patch)
tree3253001f2d0690a361a901ad5b06ed0e07f4ca2d
parentbsp/altera-cyclone-v: Add a simple I2C driver. (diff)
downloadrtems-81329f9ecf7c289c67cf0ff7ee54898d9311429e.tar.bz2
bsp/altera-cyclone-v: Add RTC driver.
-rw-r--r--c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am4
-rw-r--r--c/src/lib/libbsp/arm/altera-cyclone-v/README15
-rw-r--r--c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am6
-rw-r--r--c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c360
4 files changed, 381 insertions, 4 deletions
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am b/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am
index 01b02724b2..939ccc7c56 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am
@@ -200,6 +200,10 @@ libbsp_a_SOURCES += i2c/i2cdrv.c
libbsp_a_SOURCES += i2c/i2cdrv-config.c
include_bsp_HEADERS += include/i2cdrv.h
+# RTC
+libbsp_a_SOURCES += ../../shared/tod.c
+libbsp_a_SOURCES += rtc/rtc.c
+
# Cache
libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
libbsp_a_SOURCES += ../shared/include/arm-cache-l1.h
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/README b/c/src/lib/libbsp/arm/altera-cyclone-v/README
index 575b72e4f5..0a5bc05505 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/README
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/README
@@ -1,3 +1,16 @@
+Overview
+--------
Evaluation board for this BSP:
- Cyclone V SoC FPGA Development Kit
-- DK-DEV-5CSXC6N/ES-0L \ No newline at end of file
+- DK-DEV-5CSXC6N/ES-0L
+
+RTC
+---
+The evaluation board contains a DS1339C RTC connected to I2C0. To use it you
+have to set the following options:
+
+ #define CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
+ #define CONFIGURE_BSP_PREREQUISITE_DRIVERS I2C_DRIVER_TABLE_ENTRY
+
+Additional there has to be one free file descriptor to access the i2c. Set the
+CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS accordingly.
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am b/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am
index c13ef6ada0..4e3b586341 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am
@@ -5,14 +5,14 @@ $(srcdir)/preinstall.am: Makefile.am
$(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am
endif
+PREINSTALL_DIRS =
+DISTCLEANFILES += $(PREINSTALL_DIRS)
+
all-am: $(PREINSTALL_FILES)
PREINSTALL_FILES =
CLEANFILES = $(PREINSTALL_FILES)
-PREINSTALL_DIRS =
-DISTCLEANFILES += $(PREINSTALL_DIRS)
-
all-local: $(TMPINSTALL_FILES)
TMPINSTALL_FILES =
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
new file mode 100644
index 0000000000..3c18d1cf9b
--- /dev/null
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <info@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+/*
+ * Driver for the DS1339 RTC.
+ *
+ * Please note the following points:
+ * - The day of week is ignored.
+ * - The century bit is interpreted the following way:
+ * - century not set: TOD_BASE_YEAR .. 1999
+ * - century set: 2000 .. 2099
+ * - century not set: 2100 .. (TOD_BASE_YEAR + 200)
+ */
+
+#include <libchip/rtc.h>
+#include <assert.h>
+#include <rtems/score/todimpl.h>
+#include <sys/filio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <bsp/i2cdrv.h>
+
+#define ALTERA_CYCLONE_V_RTC_NUMBER 1
+
+#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
+
+#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_STATUS_CLEAR (0x00)
+
+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;
+#define DS1339_MONTH_CENTURY 0x80
+ 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)
+
+/* 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;
+ 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;
+ 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) {
+ value += 10;
+ }
+ if(time->hours & DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS) {
+ if(time->hours & DS1339_HOURS_12_24_FLAG) {
+ value += 12;
+ } 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;
+ 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;
+ return tens * 10 + ones;
+}
+
+static unsigned int 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) {
+ year += 100;
+ }
+ 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;
+
+ tens = second / 10;
+ ones = second % 10;
+ time->seconds = tens << 4 | ones;
+
+ tens = minute / 10;
+ ones = minute % 10;
+ time->minutes = tens << 4 | ones;
+
+ tens = hour / 10;
+ ones = hour % 10;
+ time->hours = tens << 4 | ones;
+
+ /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
+ time->weekday = 1;
+
+ tens = day / 10;
+ ones = day % 10;
+ time->date = tens << 4 | ones;
+
+ tens = month / 10;
+ ones = month % 10;
+ 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)
+{
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ *fd = open(DS1339_I2C_BUS_DEVICE, O_RDWR);
+ if ( *fd == -1 ) {
+ sc = RTEMS_IO_ERROR;
+ }
+
+ if ( sc == RTEMS_SUCCESSFUL ) {
+ rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, DS1339_I2C_ADDRESS);
+ 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)
+{
+ int fd = -1;
+ int rv = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = ds1339_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 ds1339 register address addr. */
+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;
+ /* 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;
+
+ assert(write_size <= DS1339_MAX_WRITE_SIZE);
+
+ local_buf[0] = addr;
+ memcpy(&local_buf[1], buf, size);
+
+ sc = ds1339_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_rtc_initialize(int minor)
+{
+ 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) {
+ /* RTC has been stopped. Initialise it. */
+ ds1339_time_t time;
+
+ uint8_t write = DS1339_CTRL_DEFAULT;
+ sc = ds1339_write(DS1339_ADDR_CTRL, &write, sizeof(write));
+ assert(sc == RTEMS_SUCCESSFUL);
+
+ write = DS1339_STATUS_CLEAR;
+ sc = ds1339_write(DS1339_ADDR_STATUS, &write, sizeof(write));
+ assert(sc == RTEMS_SUCCESSFUL);
+
+ 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)
+{
+ 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));
+
+ 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);
+
+ if ( _TOD_Validate(&temp_tod) ) {
+ memcpy(tod, &temp_tod, sizeof(temp_tod));
+ } else {
+ sc = RTEMS_INVALID_CLOCK;
+ }
+ }
+
+ return -sc;
+}
+
+static int altera_cyclone_v_rtc_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
+ );
+
+ sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
+
+ return -sc;
+}
+
+static bool altera_cyclone_v_rtc_probe(int minor)
+{
+ /* FIXME: Probe for i2c device */
+ 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
+};
+
+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] = {
+ {
+ .sDeviceName = "/dev/rtc",
+ .deviceType = RTC_CUSTOM,
+ .pDeviceFns = &altera_cyclone_v_rtc_ops,
+ .deviceProbe = altera_cyclone_v_rtc_probe,
+ .pDeviceParams = NULL,
+ .ulCtrlPort1 = 0,
+ .ulDataPort = 0,
+ .getRegister = NULL,
+ .setRegister = NULL
+ }
+};