forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrtc_ds1307.c
160 lines (127 loc) · 4.46 KB
/
rtc_ds1307.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Arunmani Alagarsamy
* Author: Arunmani Alagarsamy <[email protected]>
*/
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/rtc.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/util.h>
#define DT_DRV_COMPAT maxim_ds1307
LOG_MODULE_REGISTER(ds1307, CONFIG_RTC_LOG_LEVEL);
/* 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)
#define VALIDATE_24HR BIT(6)
struct ds1307_config {
struct i2c_dt_spec i2c_bus;
};
struct ds1307_data {
struct k_spinlock 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_spinlock_key_t key = k_spin_lock(&data->lock);
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 % 100));
err = i2c_burst_write_dt(&config->i2c_bus, DS1307_REG_SECONDS, regs, sizeof(regs));
k_spin_unlock(&data->lock, key);
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_spinlock_key_t key = k_spin_lock(&data->lock);
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);
timeptr->tm_year = timeptr->tm_year + 100;
/* Not used */
timeptr->tm_nsec = 0;
timeptr->tm_isdst = -1;
timeptr->tm_yday = -1;
/* Validate the chip in 24hr mode */
if (regs[2] & VALIDATE_24HR) {
err = -ENODATA;
goto unlock;
}
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_spin_unlock(&data->lock, key);
return err;
}
static const struct rtc_driver_api ds1307_driver_api = {
.set_time = ds1307_set_time,
.get_time = ds1307_get_time,
};
static int ds1307_init(const struct device *dev)
{
int err;
const struct ds1307_config *config = dev->config;
if (!i2c_is_ready_dt(&config->i2c_bus)) {
LOG_ERR("I2C bus not ready");
return -ENODEV;
}
/* Disable squarewave output */
err = i2c_reg_write_byte_dt(&config->i2c_bus, DS1307_REG_CTRL, 0x00);
if (err < 0) {
LOG_ERR("Error: SQW:%d\n", err);
}
/* Make clock halt = 0 */
err = i2c_reg_write_byte_dt(&config->i2c_bus, DS1307_REG_SECONDS, 0x00);
if (err < 0) {
LOG_ERR("Error: Set clock halt bit:%d\n", err);
}
return 0;
}
#define DS1307_DEFINE(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_DEFINE)