mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-06 00:45:22 +08:00
[dm][rtc] update rtc and new drivers (#11033)
* [dd][rtc] set the RTC alarm thread stack size default. Signed-off-by: GuEe-GUI <2991707448@qq.com> * [dm][rtc] make Kconfig import for DM Signed-off-by: GuEe-GUI <2991707448@qq.com> * [dm][rtc] support DM API for RTC 1. rtc_dev_set_name for RTC device init the name auto. 2. rtc_wkalarm_to_timestamp and rtc_timestamp_to_wkalarm for rt_rtc_wkalarm/time_t convert. Signed-off-by: GuEe-GUI <2991707448@qq.com> * [dm][rtc] add new drivers 1. Dallas/Maxim DS1302 2. Dallas/Maxim DS1307/37/38/39/40, ST M41T11 3. Goldfish Real Time Clock 4. Haoyu Microelectronics HYM8563 5. NXP PCF8523 6. Philips PCF8563/Epson RTC8564 7. ARM PL031 8. Epson RX8010SJ Signed-off-by: GuEe-GUI <2991707448@qq.com> --------- Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
config RT_USING_RTC
|
||||
menuconfig RT_USING_RTC
|
||||
bool "Using RTC device drivers"
|
||||
default n
|
||||
|
||||
@@ -10,7 +10,7 @@ config RT_USING_RTC
|
||||
if RT_USING_ALARM
|
||||
config RT_ALARM_STACK_SIZE
|
||||
int "stack size for alarm thread"
|
||||
default 2048
|
||||
default IDLE_THREAD_STACK_SIZE
|
||||
|
||||
config RT_ALARM_TIMESLICE
|
||||
int "timeslice for alarm thread"
|
||||
@@ -30,3 +30,61 @@ config RT_USING_RTC
|
||||
bool "Using software simulation RTC device"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_RTC_DS1302
|
||||
bool "Dallas/Maxim DS1302"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
depends on RT_USING_SPI
|
||||
default n
|
||||
|
||||
config RT_RTC_DS1307
|
||||
bool "Dallas/Maxim DS1307/37/38/39/40, ST M41T11"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
depends on RT_USING_I2C
|
||||
default n
|
||||
|
||||
config RT_RTC_GOLDFISH
|
||||
bool "Goldfish Real Time Clock"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
default n
|
||||
|
||||
config RT_RTC_HYM8563
|
||||
bool "Haoyu Microelectronics HYM8563"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
depends on RT_USING_I2C
|
||||
default n
|
||||
|
||||
config RT_RTC_PCF8523
|
||||
bool "NXP PCF8523"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
depends on RT_USING_I2C
|
||||
default n
|
||||
|
||||
config RT_RTC_PCF8563
|
||||
bool "Philips PCF8563/Epson RTC8564"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
depends on RT_USING_I2C
|
||||
default n
|
||||
|
||||
config RT_RTC_PL031
|
||||
bool "ARM PL031"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
default n
|
||||
|
||||
config RT_RTC_RX8010
|
||||
bool "Epson RX8010SJ"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_RTC
|
||||
depends on RT_USING_I2C
|
||||
default n
|
||||
|
||||
if RT_USING_DM && RT_USING_RTC
|
||||
osource "$(SOC_DM_RTC_DIR)/Kconfig"
|
||||
endif
|
||||
|
||||
@@ -13,6 +13,33 @@ if GetDepend(['RT_USING_RTC']):
|
||||
if GetDepend(['RT_USING_SOFT_RTC']):
|
||||
src = src + ['dev_soft_rtc.c']
|
||||
|
||||
if GetDepend(['RT_USING_DM']):
|
||||
src += ['rtc_dm.c']
|
||||
|
||||
if GetDepend(['RT_RTC_DS1302']):
|
||||
src += ['rtc-ds1302.c']
|
||||
|
||||
if GetDepend(['RT_RTC_DS1307']):
|
||||
src += ['rtc-ds1307.c']
|
||||
|
||||
if GetDepend(['RT_RTC_GOLDFISH']):
|
||||
src += ['rtc-goldfish.c']
|
||||
|
||||
if GetDepend(['RT_RTC_HYM8563']):
|
||||
src += ['rtc-hym8563.c']
|
||||
|
||||
if GetDepend(['RT_RTC_PCF8523']):
|
||||
src += ['rtc-pcf8523.c']
|
||||
|
||||
if GetDepend(['RT_RTC_PCF8563']):
|
||||
src += ['rtc-pcf8563.c']
|
||||
|
||||
if GetDepend(['RT_RTC_PL031']):
|
||||
src += ['rtc-pl031.c']
|
||||
|
||||
if GetDepend(['RT_RTC_RX8010']):
|
||||
src += ['rtc-rx8010.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_RTC'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
||||
256
components/drivers/rtc/rtc-ds1302.c
Normal file
256
components/drivers/rtc/rtc-ds1302.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-23 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "rtc_dm.h"
|
||||
|
||||
#define DBG_TAG "rtc.ds1302"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define RTC_CMD_READ 0x81 /* Read command */
|
||||
#define RTC_CMD_WRITE 0x80 /* Write command */
|
||||
|
||||
#define RTC_CMD_WRITE_ENABLE 0x00 /* Write enable */
|
||||
#define RTC_CMD_WRITE_DISABLE 0x80 /* Write disable */
|
||||
|
||||
#define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */
|
||||
#define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */
|
||||
#define RTC_CLCK_BURST 0x1F /* Address of clock burst */
|
||||
#define RTC_CLCK_LEN 0x08 /* Size of clock burst */
|
||||
#define RTC_ADDR_CTRL 0x07 /* Address of control register */
|
||||
#define RTC_ADDR_YEAR 0x06 /* Address of year register */
|
||||
#define RTC_ADDR_DAY 0x05 /* Address of day of week register */
|
||||
#define RTC_ADDR_MON 0x04 /* Address of month register */
|
||||
#define RTC_ADDR_DATE 0x03 /* Address of day of month register */
|
||||
#define RTC_ADDR_HOUR 0x02 /* Address of hour register */
|
||||
#define RTC_ADDR_MIN 0x01 /* Address of minute register */
|
||||
#define RTC_ADDR_SEC 0x00 /* Address of second register */
|
||||
|
||||
static rt_err_t ds1302_rtc_get_time(struct rt_spi_device *spi_dev, time_t *sec)
|
||||
{
|
||||
struct tm tm;
|
||||
rt_err_t err;
|
||||
rt_uint8_t addr = RTC_CLCK_BURST << 1 | RTC_CMD_READ, buf[RTC_CLCK_LEN - 1];
|
||||
|
||||
err = rt_spi_send_then_recv(spi_dev, &addr, sizeof(addr), buf, sizeof(buf));
|
||||
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Decode the registers */
|
||||
tm.tm_sec = rt_bcd2bin(buf[RTC_ADDR_SEC]);
|
||||
tm.tm_min = rt_bcd2bin(buf[RTC_ADDR_MIN]);
|
||||
tm.tm_hour = rt_bcd2bin(buf[RTC_ADDR_HOUR]);
|
||||
tm.tm_wday = buf[RTC_ADDR_DAY] - 1;
|
||||
tm.tm_mday = rt_bcd2bin(buf[RTC_ADDR_DATE]);
|
||||
tm.tm_mon = rt_bcd2bin(buf[RTC_ADDR_MON]) - 1;
|
||||
tm.tm_year = rt_bcd2bin(buf[RTC_ADDR_YEAR]) + 100;
|
||||
|
||||
*sec = timegm(&tm);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t ds1302_rtc_set_time(struct rt_spi_device *spi_dev, time_t *sec)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct tm *tm;
|
||||
rt_uint8_t buf[1 + RTC_CLCK_LEN], *bp;
|
||||
|
||||
tm = localtime(sec);
|
||||
|
||||
/* Enable writing */
|
||||
bp = buf;
|
||||
*bp++ = RTC_ADDR_CTRL << 1 | RTC_CMD_WRITE;
|
||||
*bp++ = RTC_CMD_WRITE_ENABLE;
|
||||
|
||||
err = rt_spi_send_then_recv(spi_dev, buf, 2, RT_NULL, 0);
|
||||
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Write registers starting at the first time/date address. */
|
||||
bp = buf;
|
||||
*bp++ = RTC_CLCK_BURST << 1 | RTC_CMD_WRITE;
|
||||
|
||||
*bp++ = rt_bin2bcd(tm->tm_sec);
|
||||
*bp++ = rt_bin2bcd(tm->tm_min);
|
||||
*bp++ = rt_bin2bcd(tm->tm_hour);
|
||||
*bp++ = rt_bin2bcd(tm->tm_mday);
|
||||
*bp++ = rt_bin2bcd(tm->tm_mon + 1);
|
||||
*bp++ = tm->tm_wday + 1;
|
||||
*bp++ = rt_bin2bcd(tm->tm_year % 100);
|
||||
*bp++ = RTC_CMD_WRITE_DISABLE;
|
||||
|
||||
return rt_spi_send_then_recv(spi_dev, buf, sizeof(buf), RT_NULL, 0);
|
||||
}
|
||||
|
||||
static rt_err_t ds1302_rtc_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct rt_spi_device *spi_dev = dev->user_data;
|
||||
|
||||
if (!args)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_RTC_GET_TIME:
|
||||
err = ds1302_rtc_get_time(spi_dev, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_TIME:
|
||||
err = ds1302_rtc_set_time(spi_dev, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
|
||||
err = ds1302_rtc_get_time(spi_dev, (time_t *)&((struct timeval *)args)->tv_sec);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
|
||||
err = ds1302_rtc_set_time(spi_dev, (time_t *)&((struct timeval *)args)->tv_sec);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_GET_ALARM:
|
||||
case RT_DEVICE_CTRL_RTC_SET_ALARM:
|
||||
err = -RT_ENOSYS;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -RT_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops ds1302_rtc_ops =
|
||||
{
|
||||
.control = ds1302_rtc_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
static rt_err_t ds1302_rtc_probe(struct rt_spi_device *spi_dev)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
const char *dev_name;
|
||||
rt_uint8_t addr, buf[4];
|
||||
|
||||
if (spi_dev->config.max_hz > 2000000)
|
||||
{
|
||||
LOG_E("Speed is too high");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
else if (spi_dev->config.mode & RT_SPI_CPHA)
|
||||
{
|
||||
LOG_E("Bad mode");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
addr = RTC_ADDR_CTRL << 1 | RTC_CMD_READ;
|
||||
|
||||
if ((err = rt_spi_send_then_recv(spi_dev, &addr, sizeof(addr), buf, 1)))
|
||||
{
|
||||
LOG_E("Control register read error = %s", rt_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((buf[0] & ~RTC_CMD_WRITE_DISABLE) != 0)
|
||||
{
|
||||
if ((err = rt_spi_send_then_recv(spi_dev, &addr, sizeof(addr), buf, 1)))
|
||||
{
|
||||
LOG_E("Control register read error = %s", rt_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((buf[0] & ~RTC_CMD_WRITE_DISABLE) != 0)
|
||||
{
|
||||
LOG_E("Junk in control register");
|
||||
return -RT_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf[0] == 0)
|
||||
{
|
||||
buf[0] = RTC_ADDR_CTRL << 1 | RTC_CMD_WRITE;
|
||||
buf[1] = RTC_CMD_WRITE_DISABLE;
|
||||
|
||||
if ((err = rt_spi_send_then_recv(spi_dev, buf, 2, RT_NULL, 0)))
|
||||
{
|
||||
LOG_E("Control register write error = %s", rt_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
addr = RTC_ADDR_CTRL << 1 | RTC_CMD_READ;
|
||||
|
||||
if ((err = rt_spi_send_then_recv(spi_dev, &addr, sizeof(addr), buf, 1)))
|
||||
{
|
||||
LOG_E("Reading control register error = %s", rt_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
if (buf[0] != RTC_CMD_WRITE_DISABLE)
|
||||
{
|
||||
LOG_E("Failed to detect chip");
|
||||
return -RT_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
spi_dev->parent.user_data = spi_dev;
|
||||
|
||||
spi_dev->parent.type = RT_Device_Class_RTC;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
spi_dev->parent.ops = &ds1302_rtc_ops;
|
||||
#else
|
||||
spi_dev->parent.control = ds1302_rtc_control;
|
||||
#endif
|
||||
|
||||
rtc_dev_set_name(&spi_dev->parent);
|
||||
dev_name = rt_dm_dev_get_name(&spi_dev->parent);
|
||||
err = rt_device_register(&spi_dev->parent, dev_name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t ds1302_rtc_remove(struct rt_spi_device *spi_dev)
|
||||
{
|
||||
rt_device_unregister(&spi_dev->parent);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_spi_device_id ds1302_rtc_ids[] =
|
||||
{
|
||||
{ .name = "ds1302" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static const struct rt_ofw_node_id ds1302_rtc_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "maxim,ds1302" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct rt_spi_driver ds1302_rtc_driver =
|
||||
{
|
||||
.ids = ds1302_rtc_ids,
|
||||
.ofw_ids = ds1302_rtc_ofw_ids,
|
||||
|
||||
.probe = ds1302_rtc_probe,
|
||||
.remove = ds1302_rtc_remove,
|
||||
};
|
||||
RT_SPI_DRIVER_EXPORT(ds1302_rtc_driver);
|
||||
643
components/drivers/rtc/rtc-ds1307.c
Normal file
643
components/drivers/rtc/rtc-ds1307.c
Normal file
File diff suppressed because it is too large
Load Diff
270
components/drivers/rtc/rtc-goldfish.c
Normal file
270
components/drivers/rtc/rtc-goldfish.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-11-26 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "rtc_dm.h"
|
||||
|
||||
#define GOLDFISH_RTC_TIME_LOW 0x00 /* get low bits of current time and update GOLDFISH_RTC_TIME_HIGH */
|
||||
#define GOLDFISH_RTC_TIME_HIGH 0x04 /* get high bits of time at last GOLDFISH_RTC_TIME_LOW read */
|
||||
#define GOLDFISH_RTC_ALARM_LOW 0x08 /* set low bits of alarm and activate it */
|
||||
#define GOLDFISH_RTC_ALARM_HIGH 0x0c /* set high bits of next alarm */
|
||||
#define GOLDFISH_RTC_IRQ_ENABLED 0x10 /* enable alarm interrupt */
|
||||
#define GOLDFISH_RTC_CLEAR_ALARM 0x14 /* disarm an existing alarm */
|
||||
#define GOLDFISH_RTC_ALARM_STATUS 0x18 /* alarm status (running or not) */
|
||||
#define GOLDFISH_RTC_CLEAR_INTERRUPT 0x1c /* clear interrupt */
|
||||
|
||||
#define NSEC_PER_SEC 1000000000L
|
||||
|
||||
struct goldfish_rtc
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
int irq;
|
||||
void *base;
|
||||
|
||||
struct rt_rtc_wkalarm wkalarm;
|
||||
};
|
||||
|
||||
#define raw_to_goldfish_rtc(raw) rt_container_of(raw, struct goldfish_rtc, parent)
|
||||
|
||||
rt_inline rt_uint32_t goldfish_rtc_read(struct goldfish_rtc *grtc, int offset)
|
||||
{
|
||||
return HWREG32(grtc->base + offset);
|
||||
}
|
||||
|
||||
rt_inline void goldfish_rtc_write(struct goldfish_rtc *grtc, int offset, rt_uint32_t value)
|
||||
{
|
||||
HWREG32(grtc->base + offset) = value;
|
||||
}
|
||||
|
||||
static void goldfish_rtc_isr(int irqno, void *param)
|
||||
{
|
||||
struct goldfish_rtc *grtc = param;
|
||||
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_CLEAR_INTERRUPT, 1);
|
||||
|
||||
rt_alarm_update(&grtc->parent, 1);
|
||||
}
|
||||
|
||||
static void goldfish_rtc_get_secs(struct goldfish_rtc *grtc, time_t *sec)
|
||||
{
|
||||
rt_uint64_t time = goldfish_rtc_read(grtc, GOLDFISH_RTC_TIME_LOW);
|
||||
|
||||
if (sizeof(*sec) >= sizeof(rt_uint64_t))
|
||||
{
|
||||
rt_uint64_t time_high = goldfish_rtc_read(grtc, GOLDFISH_RTC_TIME_HIGH);
|
||||
|
||||
time |= time_high << 32;
|
||||
}
|
||||
|
||||
rt_do_div(time, NSEC_PER_SEC);
|
||||
|
||||
rt_memcpy(sec, &time, sizeof(*sec));
|
||||
}
|
||||
|
||||
static void goldfish_rtc_set_secs(struct goldfish_rtc *grtc, time_t *sec)
|
||||
{
|
||||
rt_uint64_t time = 0;
|
||||
|
||||
rt_memcpy(&time, sec, sizeof(*sec));
|
||||
|
||||
time *= NSEC_PER_SEC;
|
||||
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_TIME_LOW, (rt_uint32_t)(time & RT_UINT32_MAX));
|
||||
|
||||
if (sizeof(*sec) >= sizeof(rt_uint64_t))
|
||||
{
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_TIME_HIGH, (rt_uint32_t)(time >> 32));
|
||||
}
|
||||
}
|
||||
|
||||
static void goldfish_rtc_get_alarm(struct goldfish_rtc *grtc, struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
*alarm = grtc->wkalarm;
|
||||
|
||||
if (goldfish_rtc_read(grtc, GOLDFISH_RTC_ALARM_STATUS))
|
||||
{
|
||||
alarm->enable = RT_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
alarm->enable = RT_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void goldfish_rtc_set_alarm(struct goldfish_rtc *grtc, struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
struct rt_rtc_wkalarm *wkalarm = &grtc->wkalarm;
|
||||
|
||||
wkalarm->enable = alarm->enable;
|
||||
wkalarm->tm_hour = alarm->tm_hour;
|
||||
wkalarm->tm_min = alarm->tm_min;
|
||||
wkalarm->tm_sec = alarm->tm_sec;
|
||||
|
||||
if (alarm->enable)
|
||||
{
|
||||
rt_uint64_t time = alarm->tm_hour * 3600 + alarm->tm_min * 60 + alarm->tm_sec;
|
||||
|
||||
time *= NSEC_PER_SEC;
|
||||
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_ALARM_HIGH, (rt_uint32_t)(time >> 32));
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_ALARM_LOW, (rt_uint32_t)(time & RT_UINT32_MAX));
|
||||
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_IRQ_ENABLED, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (goldfish_rtc_read(grtc, GOLDFISH_RTC_ALARM_STATUS))
|
||||
{
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_CLEAR_ALARM, 1);
|
||||
}
|
||||
|
||||
goldfish_rtc_write(grtc, GOLDFISH_RTC_IRQ_ENABLED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t goldfish_rtc_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct goldfish_rtc *grtc = raw_to_goldfish_rtc(dev);
|
||||
|
||||
if (!args)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_RTC_GET_TIME:
|
||||
goldfish_rtc_get_secs(grtc, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_TIME:
|
||||
goldfish_rtc_set_secs(grtc, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
|
||||
goldfish_rtc_get_secs(grtc, (time_t *)&((struct timeval *)args)->tv_sec);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
|
||||
goldfish_rtc_set_secs(grtc, (time_t *)&((struct timeval *)args)->tv_sec);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_GET_ALARM:
|
||||
goldfish_rtc_get_alarm(grtc, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_ALARM:
|
||||
goldfish_rtc_set_alarm(grtc, args);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -RT_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops goldfish_rtc_ops =
|
||||
{
|
||||
.control = goldfish_rtc_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
static rt_err_t goldfish_rtc_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
const char *dev_name;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct goldfish_rtc *grtc = rt_calloc(1, sizeof(*grtc));
|
||||
|
||||
if (!grtc)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
grtc->base = rt_dm_dev_iomap(dev, 0);
|
||||
|
||||
if (!grtc->base)
|
||||
{
|
||||
err = -RT_EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
grtc->irq = rt_dm_dev_get_irq(dev, 0);
|
||||
|
||||
if (grtc->irq < 0)
|
||||
{
|
||||
err = grtc->irq;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
dev->user_data = grtc;
|
||||
|
||||
grtc->parent.type = RT_Device_Class_RTC;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
grtc->parent.ops = &goldfish_rtc_ops;
|
||||
#else
|
||||
grtc->parent.control = goldfish_rtc_control;
|
||||
#endif
|
||||
|
||||
rtc_dev_set_name(&grtc->parent);
|
||||
dev_name = rt_dm_dev_get_name(&grtc->parent);
|
||||
rt_device_register(&grtc->parent, dev_name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
rt_hw_interrupt_install(grtc->irq, goldfish_rtc_isr, grtc, "rtc-goldfish");
|
||||
rt_hw_interrupt_umask(grtc->irq);
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (grtc->base)
|
||||
{
|
||||
rt_iounmap(grtc->base);
|
||||
}
|
||||
|
||||
rt_free(grtc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t goldfish_rtc_remove(struct rt_platform_device *pdev)
|
||||
{
|
||||
struct goldfish_rtc *grtc = pdev->parent.user_data;
|
||||
|
||||
rt_hw_interrupt_mask(grtc->irq);
|
||||
rt_pic_detach_irq(grtc->irq, grtc);
|
||||
|
||||
rt_device_unregister(&grtc->parent);
|
||||
|
||||
rt_iounmap(grtc->base);
|
||||
|
||||
rt_free(grtc);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id goldfish_rtc_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "google,goldfish-rtc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver goldfish_rtc_driver =
|
||||
{
|
||||
.name = "rtc-goldfish",
|
||||
.ids = goldfish_rtc_ofw_ids,
|
||||
|
||||
.probe = goldfish_rtc_probe,
|
||||
.remove = goldfish_rtc_remove,
|
||||
};
|
||||
RT_PLATFORM_DRIVER_EXPORT(goldfish_rtc_driver);
|
||||
767
components/drivers/rtc/rtc-hym8563.c
Normal file
767
components/drivers/rtc/rtc-hym8563.c
Normal file
File diff suppressed because it is too large
Load Diff
538
components/drivers/rtc/rtc-pcf8523.c
Normal file
538
components/drivers/rtc/rtc-pcf8523.c
Normal file
File diff suppressed because it is too large
Load Diff
673
components/drivers/rtc/rtc-pcf8563.c
Normal file
673
components/drivers/rtc/rtc-pcf8563.c
Normal file
File diff suppressed because it is too large
Load Diff
294
components/drivers/rtc/rtc-pl031.c
Normal file
294
components/drivers/rtc/rtc-pl031.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-11-26 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "rtc_dm.h"
|
||||
|
||||
#define PL031_DR 0x00 /* data read register */
|
||||
#define PL031_MR 0x04 /* match register */
|
||||
#define PL031_LR 0x08 /* data load register */
|
||||
#define PL031_CR 0x0c /* control register */
|
||||
#define PL031_IMSC 0x10 /* interrupt mask and set register */
|
||||
#define PL031_RIS 0x14 /* raw interrupt status register */
|
||||
#define PL031_MIS 0x18 /* masked interrupt status register */
|
||||
#define PL031_ICR 0x1c /* interrupt clear register */
|
||||
|
||||
#define PL031_CR_OPEN 1
|
||||
#define PL031_CR_CLOSE 0
|
||||
#define PL031_BIT_AI RT_BIT(0) /* Alarm interrupt bit */
|
||||
#define PL031_BIT_PI RT_BIT(1) /* Periodic interrupt bit. ST variants only. */
|
||||
|
||||
struct pl031
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
int irq;
|
||||
void *base;
|
||||
struct rt_clk *pclk;
|
||||
|
||||
struct rt_rtc_wkalarm wkalarm;
|
||||
};
|
||||
|
||||
#define raw_to_pl031(raw) rt_container_of(raw, struct pl031, parent)
|
||||
|
||||
rt_inline rt_uint32_t pl031_read(struct pl031 *pl031, int offset)
|
||||
{
|
||||
return HWREG32(pl031->base + offset);
|
||||
}
|
||||
|
||||
rt_inline void pl031_write(struct pl031 *pl031, int offset, rt_uint32_t value)
|
||||
{
|
||||
HWREG32(pl031->base + offset) = value;
|
||||
}
|
||||
|
||||
static void pl031_isr(int irqno, void *param)
|
||||
{
|
||||
struct pl031 *pl031 = param;
|
||||
rt_uint32_t rtcmis = pl031_read(pl031, PL031_MIS);
|
||||
|
||||
if (rtcmis & PL031_BIT_AI)
|
||||
{
|
||||
pl031_write(pl031, PL031_ICR, PL031_BIT_AI);
|
||||
|
||||
rt_alarm_update(&pl031->parent, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void pl031_get_secs(struct pl031 *pl031, time_t *sec)
|
||||
{
|
||||
*(rt_uint32_t *)sec = pl031_read(pl031, PL031_DR);
|
||||
}
|
||||
|
||||
static void pl031_set_secs(struct pl031 *pl031, time_t *sec)
|
||||
{
|
||||
pl031_write(pl031, PL031_LR, *(rt_uint32_t *)sec);
|
||||
}
|
||||
|
||||
static void pl031_get_alarm(struct pl031 *pl031, struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
*alarm = pl031->wkalarm;
|
||||
|
||||
alarm->enable = pl031_read(pl031, PL031_IMSC) & PL031_BIT_AI;
|
||||
}
|
||||
|
||||
static void pl031_set_alarm(struct pl031 *pl031, struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
rt_uint32_t imsc, time;
|
||||
struct rt_rtc_wkalarm *wkalarm = &pl031->wkalarm;
|
||||
|
||||
wkalarm->enable = alarm->enable;
|
||||
wkalarm->tm_hour = alarm->tm_hour;
|
||||
wkalarm->tm_min = alarm->tm_min;
|
||||
wkalarm->tm_sec = alarm->tm_sec;
|
||||
|
||||
time = pl031_read(pl031, PL031_DR);
|
||||
|
||||
/* Get alarm time */
|
||||
time += alarm->tm_hour * 3600 + alarm->tm_min * 60 + alarm->tm_sec;
|
||||
|
||||
pl031_write(pl031, PL031_MR, time);
|
||||
|
||||
/* Clear any pending alarm interrupts. */
|
||||
pl031_write(pl031, PL031_ICR, PL031_BIT_AI);
|
||||
|
||||
imsc = pl031_read(pl031, PL031_IMSC);
|
||||
|
||||
if (alarm->enable)
|
||||
{
|
||||
pl031_write(pl031, PL031_IMSC, imsc | PL031_BIT_AI);
|
||||
}
|
||||
else
|
||||
{
|
||||
pl031_write(pl031, PL031_IMSC, imsc & ~PL031_BIT_AI);
|
||||
}
|
||||
}
|
||||
|
||||
static void pl031_get_timeval(struct pl031 *pl031, struct timeval *tv)
|
||||
{
|
||||
tv->tv_sec = pl031_read(pl031, PL031_DR);
|
||||
}
|
||||
|
||||
static void pl031_set_timeval(struct pl031 *pl031, struct timeval *tv)
|
||||
{
|
||||
pl031_write(pl031, PL031_LR, *(rt_uint32_t *)&tv->tv_sec);
|
||||
}
|
||||
|
||||
static rt_err_t pl031_init(rt_device_t dev)
|
||||
{
|
||||
struct pl031 *pl031 = raw_to_pl031(dev);
|
||||
|
||||
pl031_write(pl031, PL031_CR, PL031_CR_OPEN);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t pl031_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct pl031 *pl031 = raw_to_pl031(dev);
|
||||
|
||||
if (!args)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_RTC_GET_TIME:
|
||||
pl031_get_secs(pl031, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_TIME:
|
||||
pl031_set_secs(pl031, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
|
||||
pl031_get_timeval(pl031, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
|
||||
pl031_set_timeval(pl031, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_GET_ALARM:
|
||||
pl031_get_alarm(pl031, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RTC_SET_ALARM:
|
||||
pl031_set_alarm(pl031, args);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -RT_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops pl031_rtc_ops =
|
||||
{
|
||||
.init = pl031_init,
|
||||
.control = pl031_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
static rt_err_t pl031_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
const char *dev_name;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct pl031 *pl031 = rt_calloc(1, sizeof(*pl031));
|
||||
|
||||
if (!pl031)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
pl031->base = rt_dm_dev_iomap(dev, 0);
|
||||
|
||||
if (!pl031->base)
|
||||
{
|
||||
err = -RT_EIO;
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
pl031->irq = rt_dm_dev_get_irq(dev, 0);
|
||||
|
||||
if (pl031->irq < 0)
|
||||
{
|
||||
err = pl031->irq;
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
pl031->pclk = rt_clk_get_by_name(dev, "apb_pclk");
|
||||
|
||||
if (rt_is_err(pl031->pclk))
|
||||
{
|
||||
err = rt_ptr_err(pl031->pclk);
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if ((err = rt_clk_prepare_enable(pl031->pclk)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
dev->user_data = pl031;
|
||||
|
||||
pl031->parent.type = RT_Device_Class_RTC;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
pl031->parent.ops = &pl031_rtc_ops;
|
||||
#else
|
||||
pl031->parent.init = pl031_init;
|
||||
pl031->parent.control = pl031_control;
|
||||
#endif
|
||||
|
||||
rtc_dev_set_name(&pl031->parent);
|
||||
dev_name = rt_dm_dev_get_name(&pl031->parent);
|
||||
rt_device_register(&pl031->parent, dev_name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
rt_hw_interrupt_install(pl031->irq, pl031_isr, pl031, "rtc-pl031");
|
||||
rt_hw_interrupt_umask(pl031->irq);
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (pl031->base)
|
||||
{
|
||||
rt_iounmap(pl031->base);
|
||||
}
|
||||
|
||||
if (!rt_is_err_or_null(pl031->pclk))
|
||||
{
|
||||
rt_clk_disable_unprepare(pl031->pclk);
|
||||
rt_clk_put(pl031->pclk);
|
||||
}
|
||||
|
||||
rt_free(pl031);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t pl031_remove(struct rt_platform_device *pdev)
|
||||
{
|
||||
struct pl031 *pl031 = pdev->parent.user_data;
|
||||
|
||||
rt_hw_interrupt_mask(pl031->irq);
|
||||
rt_pic_detach_irq(pl031->irq, pl031);
|
||||
|
||||
rt_device_unregister(&pl031->parent);
|
||||
|
||||
rt_clk_disable_unprepare(pl031->pclk);
|
||||
rt_clk_put(pl031->pclk);
|
||||
|
||||
rt_free(pl031);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id pl031_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "arm,pl031" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver pl031_driver =
|
||||
{
|
||||
.name = "rtc-pl031",
|
||||
.ids = pl031_ofw_ids,
|
||||
|
||||
.probe = pl031_probe,
|
||||
.remove = pl031_remove,
|
||||
};
|
||||
RT_PLATFORM_DRIVER_EXPORT(pl031_driver);
|
||||
637
components/drivers/rtc/rtc-rx8010.c
Normal file
637
components/drivers/rtc/rtc-rx8010.c
Normal file
File diff suppressed because it is too large
Load Diff
61
components/drivers/rtc/rtc_dm.c
Normal file
61
components/drivers/rtc/rtc_dm.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include <rtatomic.h>
|
||||
#include "rtc_dm.h"
|
||||
|
||||
#define DBG_TAG "rtc.dm"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
int rtc_dev_set_name(struct rt_device *rtc_dev)
|
||||
{
|
||||
int id;
|
||||
static volatile rt_atomic_t uid = 1;
|
||||
|
||||
RT_ASSERT(rtc_dev != RT_NULL)
|
||||
|
||||
if (rt_device_find("rtc"))
|
||||
{
|
||||
id = (int)rt_atomic_add(&uid, 1);
|
||||
|
||||
return rt_dm_dev_set_name(rtc_dev, "rtc%u", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return rt_dm_dev_set_name(rtc_dev, "rtc");
|
||||
}
|
||||
}
|
||||
|
||||
time_t rtc_wkalarm_to_timestamp(struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
struct tm tm_time;
|
||||
time_t current_time;
|
||||
|
||||
current_time = time(RT_NULL);
|
||||
localtime_r(¤t_time, &tm_time);
|
||||
|
||||
tm_time.tm_sec = alarm->tm_sec;
|
||||
tm_time.tm_min = alarm->tm_min;
|
||||
tm_time.tm_hour = alarm->tm_hour;
|
||||
|
||||
return timegm(&tm_time);
|
||||
}
|
||||
|
||||
void rtc_timestamp_to_wkalarm(time_t timestamp, struct rt_rtc_wkalarm *alarm)
|
||||
{
|
||||
struct tm tm_time;
|
||||
|
||||
localtime_r(×tamp, &tm_time);
|
||||
|
||||
alarm->tm_sec = tm_time.tm_sec;
|
||||
alarm->tm_min = tm_time.tm_min;
|
||||
alarm->tm_hour = tm_time.tm_hour;
|
||||
}
|
||||
24
components/drivers/rtc/rtc_dm.h
Normal file
24
components/drivers/rtc/rtc_dm.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __RTC_DM_H__
|
||||
#define __RTC_DM_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
int rtc_dev_set_name(struct rt_device *rtc_dev);
|
||||
time_t rtc_wkalarm_to_timestamp(struct rt_rtc_wkalarm *alarm);
|
||||
void rtc_timestamp_to_wkalarm(time_t timestamp, struct rt_rtc_wkalarm *alarm);
|
||||
|
||||
#endif /* __RTC_DM_H__ */
|
||||
Reference in New Issue
Block a user