From 324ec8c2c4fc339e915aacafa62c16e552b77624 Mon Sep 17 00:00:00 2001 From: Arunmani Alagarsamy Date: Mon, 16 Oct 2023 18:26:37 +0530 Subject: [PATCH] drivers: rtc: new maxim ds1307 rtc driver Added rtc driver for ds1307. It allows to read and set the date and time Signed-off-by: Arunmani Alagarsamy --- drivers/rtc/CMakeLists.txt | 1 + drivers/rtc/Kconfig | 1 + drivers/rtc/Kconfig.ds1307 | 11 ++ drivers/rtc/rtc_ds1307.c | 156 +++++++++++++++++++++++++++++ dts/bindings/rtc/maxim,ds1307.yaml | 11 ++ 5 files changed, 180 insertions(+) create mode 100644 drivers/rtc/Kconfig.ds1307 create mode 100644 drivers/rtc/rtc_ds1307.c create mode 100644 dts/bindings/rtc/maxim,ds1307.yaml diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 5addee4faed2822..65d822dbe6e088a 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/rtc.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_RTC_AM1805 rtc_am1805.c) +zephyr_library_sources_ifdef(CONFIG_RTC_DS1307 rtc_ds1307.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE rtc_handlers.c) zephyr_library_sources_ifdef(CONFIG_RTC_EMUL rtc_emul.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8523 rtc_pcf8523.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index f9da0c293d7def3..10b228ceeabc7f2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -42,6 +42,7 @@ config RTC_SHELL RTC Shell commands source "drivers/rtc/Kconfig.am1805" +source "drivers/rtc/Kconfig.ds1307" source "drivers/rtc/Kconfig.emul" source "drivers/rtc/Kconfig.fake" source "drivers/rtc/Kconfig.pcf8523" diff --git a/drivers/rtc/Kconfig.ds1307 b/drivers/rtc/Kconfig.ds1307 new file mode 100644 index 000000000000000..b350846f58ec63d --- /dev/null +++ b/drivers/rtc/Kconfig.ds1307 @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Arunmani Alagarsamy +# Author: Arunmani Alagarsamy + +config RTC_DS1307 + bool "MAXIM DS1307 RTC driver" + default y + depends on DT_HAS_MAXIM_DS1307_ENABLED + select I2C + help + Enable the MAXIM DS1307 RTC driver. diff --git a/drivers/rtc/rtc_ds1307.c b/drivers/rtc/rtc_ds1307.c new file mode 100644 index 000000000000000..fd74dd2cac5d8a9 --- /dev/null +++ b/drivers/rtc/rtc_ds1307.c @@ -0,0 +1,156 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Arunmani Alagarsamy + * Author: Arunmani Alagarsamy + */ + +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT maxim_ds1307 + +LOG_MODULE_REGISTER(ds1307, CONFIG_RTC_LOG_LEVEL); + +#define DS1307_I2C_ADDR 0x68 + +/* DS1307 registers */ +#define DS1307_REG_SECONDS 0x00 +#define DS1307_REG_MINUTES 0x01 +#define DS1307_REG_HOURS 0x02 +#define DS1307_REG_DAY 0x03 +#define DS1307_REG_DATE 0x04 +#define DS1307_REG_MONTH 0x05 +#define DS1307_REG_YEAR 0x06 +#define DS1307_REG_CTRL 0x07 + +#define SECONDS_BITS GENMASK(6, 0) +#define MINUTES_BITS GENMASK(7, 0) +#define HOURS_BITS GENMASK(5, 0) +#define DATE_BITS GENMASK(5, 0) +#define MONTHS_BITS GENMASK(4, 0) +#define WEEKDAY_BITS GENMASK(2, 0) +#define YEAR_BITS GENMASK(7, 0) + +struct ds1307_config { + struct i2c_dt_spec i2c_bus; +}; + +struct ds1307_data { + struct k_mutex lock; +}; + +static int ds1307_set_time(const struct device *dev, const struct rtc_time *tm) +{ + int err; + uint8_t regs[7]; + + struct ds1307_data *data = dev->data; + const struct ds1307_config *config = dev->config; + + k_mutex_lock(&data->lock, K_FOREVER); + + LOG_DBG("set time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + regs[0] = bin2bcd(tm->tm_sec) & SECONDS_BITS; + regs[1] = bin2bcd(tm->tm_min); + regs[2] = bin2bcd(tm->tm_hour); + regs[3] = bin2bcd(tm->tm_wday); + regs[4] = bin2bcd(tm->tm_mday); + regs[5] = bin2bcd(tm->tm_mon); + regs[6] = bin2bcd(tm->tm_year); + + err = i2c_burst_write_dt(&config->i2c_bus, DS1307_REG_SECONDS, regs, sizeof(regs)); + + k_mutex_unlock(&data->lock); + + return err; +} + +static int ds1307_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + int err; + uint8_t regs[7]; + + struct ds1307_data *data = dev->data; + const struct ds1307_config *config = dev->config; + + k_mutex_lock(&data->lock, K_FOREVER); + + err = i2c_burst_read_dt(&config->i2c_bus, DS1307_REG_SECONDS, regs, sizeof(regs)); + if (err != 0) { + goto unlock; + } + + timeptr->tm_sec = bcd2bin(regs[0] & SECONDS_BITS); + timeptr->tm_min = bcd2bin(regs[1] & MINUTES_BITS); + timeptr->tm_hour = bcd2bin(regs[2] & HOURS_BITS); /* 24hr mode */ + timeptr->tm_wday = bcd2bin(regs[3] & WEEKDAY_BITS); + timeptr->tm_mday = bcd2bin(regs[4] & DATE_BITS); + timeptr->tm_mon = bcd2bin(regs[5] & MONTHS_BITS); + timeptr->tm_year = bcd2bin(regs[6] & YEAR_BITS); + + LOG_DBG("get time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +static const struct rtc_driver_api ds1307_driver_api = { + .set_time = ds1307_set_time, + .get_time = ds1307_get_time, +}; + +/* + * returns 1 : CH = 1; init failed + * returns 0 : CH = 0; init success + */ +static int ds1307_init(const struct device *dev) +{ + int err; + uint8_t ch; + uint8_t tx_buf[2]; + const struct ds1307_config *config = dev->config; + struct ds1307_data *data = dev->data; + + k_mutex_init(&data->lock); + + if (!i2c_is_ready_dt(&config->i2c_bus)) { + LOG_ERR("I2C bus not ready"); + return -ENODEV; + } + + tx_buf[0] = DS1307_REG_SECONDS; + tx_buf[1] = 0x00; + + /* Make clock halt = 0 */ + err = i2c_write_read_dt(&config->i2c_bus, tx_buf, sizeof(tx_buf), &ch, sizeof(ch)); + if (err < 0) { + LOG_ERR("Error: Set clock halt bit:%d\n", err); + } + + return ((ch >> 7) & 0x1); +} + +#define DS1307_INIT(inst) \ + static struct ds1307_data ds1307_data_##inst; \ + static const struct ds1307_config ds1307_config_##inst = { \ + .i2c_bus = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, &ds1307_init, NULL, &ds1307_data_##inst, \ + &ds1307_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ + &ds1307_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DS1307_INIT) diff --git a/dts/bindings/rtc/maxim,ds1307.yaml b/dts/bindings/rtc/maxim,ds1307.yaml new file mode 100644 index 000000000000000..ed3bd0aa9826547 --- /dev/null +++ b/dts/bindings/rtc/maxim,ds1307.yaml @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Arunmani Alagarsamy +# Author: Arunmani Alagarsamy + +description: MAXIM DS1307 RTC + +compatible: "maxim,ds1307" + +include: + - name: rtc-device.yaml + - name: i2c-device.yaml