]>
Commit | Line | Data |
---|---|---|
fb9a1ffe MW |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Date & Time support for Micro Crystal RV-8803-C7. | |
4 | * | |
5 | * based on ds1307.c which is | |
6 | * (C) Copyright 2001, 2002, 2003 | |
7 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
8 | * Keith Outwater, [email protected]` | |
9 | * Steven Scholz, [email protected] | |
10 | * | |
11 | */ | |
12 | ||
13 | #include <common.h> | |
14 | #include <command.h> | |
15 | #include <dm.h> | |
f7ae49fc | 16 | #include <log.h> |
fb9a1ffe MW |
17 | #include <rtc.h> |
18 | #include <i2c.h> | |
cd93d625 | 19 | #include <linux/bitops.h> |
fb9a1ffe MW |
20 | |
21 | /* | |
22 | * RTC register addresses | |
23 | */ | |
24 | #define RTC_SEC_REG_ADDR 0x00 | |
25 | #define RTC_MIN_REG_ADDR 0x01 | |
26 | #define RTC_HR_REG_ADDR 0x02 | |
27 | #define RTC_DAY_REG_ADDR 0x03 | |
28 | #define RTC_DATE_REG_ADDR 0x04 | |
29 | #define RTC_MON_REG_ADDR 0x05 | |
30 | #define RTC_YR_REG_ADDR 0x06 | |
31 | ||
32 | #define RTC_FLAG_REG_ADDR 0x0E | |
33 | #define RTC_FLAG_BIT_V1F BIT(0) | |
34 | #define RTC_FLAG_BIT_V2F BIT(1) | |
35 | ||
36 | #define RTC_CTL_REG_ADDR 0x0F | |
37 | #define RTC_CTL_BIT_RST BIT(0) | |
38 | ||
39 | static int rv8803_rtc_set(struct udevice *dev, const struct rtc_time *tm) | |
40 | { | |
41 | int ret; | |
42 | u8 buf[7]; | |
43 | ||
44 | debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", | |
45 | tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, | |
46 | tm->tm_hour, tm->tm_min, tm->tm_sec); | |
47 | ||
48 | if (tm->tm_year < 2000 || tm->tm_year > 2099) | |
49 | printf("WARNING: year should be between 2000 and 2099!\n"); | |
50 | ||
51 | buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100); | |
8b42439a | 52 | buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon + 1); |
fb9a1ffe MW |
53 | buf[RTC_DAY_REG_ADDR] = 1 << (tm->tm_wday & 0x7); |
54 | buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday); | |
55 | buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour); | |
56 | buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min); | |
57 | buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec); | |
58 | ||
59 | ret = dm_i2c_write(dev, 0, buf, sizeof(buf)); | |
60 | if (ret < 0) | |
61 | return ret; | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | static int rv8803_rtc_get(struct udevice *dev, struct rtc_time *tm) | |
67 | { | |
68 | int ret; | |
69 | u8 buf[7]; | |
70 | int flags; | |
71 | ||
72 | flags = dm_i2c_reg_read(dev, RTC_FLAG_REG_ADDR); | |
73 | if (flags < 0) | |
74 | return flags; | |
75 | debug("%s: flags=%Xh\n", __func__, flags); | |
76 | ||
77 | if (flags & RTC_FLAG_BIT_V1F) | |
78 | printf("### Warning: temperature compensation has stopped\n"); | |
79 | ||
80 | if (flags & RTC_FLAG_BIT_V2F) { | |
81 | printf("### Warning: Voltage low, data is invalid\n"); | |
82 | return -1; | |
83 | } | |
84 | ||
85 | ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); | |
86 | if (ret < 0) | |
87 | return ret; | |
88 | ||
89 | tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F); | |
90 | tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F); | |
91 | tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F); | |
92 | tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F); | |
8b42439a | 93 | tm->tm_mon = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F) - 1; |
fb9a1ffe MW |
94 | tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + 2000; |
95 | tm->tm_wday = fls(buf[RTC_DAY_REG_ADDR] & 0x7F) - 1; | |
96 | tm->tm_yday = 0; | |
97 | tm->tm_isdst = 0; | |
98 | ||
99 | debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", | |
100 | tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, | |
101 | tm->tm_hour, tm->tm_min, tm->tm_sec); | |
102 | ||
103 | return 0; | |
104 | } | |
105 | ||
106 | static int rv8803_rtc_reset(struct udevice *dev) | |
107 | { | |
108 | int ret; | |
109 | struct rtc_time tmp = { | |
110 | .tm_year = 2000, | |
111 | .tm_mon = 1, | |
112 | .tm_mday = 1, | |
113 | .tm_hour = 0, | |
114 | .tm_min = 0, | |
115 | .tm_sec = 0, | |
116 | }; | |
117 | ||
118 | /* assert reset */ | |
119 | ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, RTC_CTL_BIT_RST); | |
120 | if (ret < 0) | |
121 | return ret; | |
122 | ||
123 | /* clear all flags */ | |
124 | ret = dm_i2c_reg_write(dev, RTC_FLAG_REG_ADDR, 0); | |
125 | if (ret < 0) | |
126 | return ret; | |
127 | ||
128 | ret = rv8803_rtc_set(dev, &tmp); | |
129 | if (ret < 0) | |
130 | return ret; | |
131 | ||
132 | /* clear reset */ | |
133 | ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, 0); | |
134 | if (ret < 0) | |
135 | return ret; | |
136 | ||
137 | debug("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n", | |
138 | tmp.tm_year, tmp.tm_mon, tmp.tm_mday, | |
139 | tmp.tm_hour, tmp.tm_min, tmp.tm_sec); | |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
144 | static int rv8803_probe(struct udevice *dev) | |
145 | { | |
146 | i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | | |
147 | DM_I2C_CHIP_WR_ADDRESS); | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | static const struct rtc_ops rv8803_rtc_ops = { | |
153 | .get = rv8803_rtc_get, | |
154 | .set = rv8803_rtc_set, | |
155 | .reset = rv8803_rtc_reset, | |
156 | }; | |
157 | ||
158 | static const struct udevice_id rv8803_rtc_ids[] = { | |
159 | { .compatible = "microcrystal,rv8803", }, | |
e1918ce2 HT |
160 | { .compatible = "epson,rx8803" }, |
161 | { .compatible = "epson,rx8900" }, | |
fb9a1ffe MW |
162 | { } |
163 | }; | |
164 | ||
165 | U_BOOT_DRIVER(rtc_rv8803) = { | |
166 | .name = "rtc-rv8803", | |
167 | .id = UCLASS_RTC, | |
168 | .probe = rv8803_probe, | |
169 | .of_match = rv8803_rtc_ids, | |
170 | .ops = &rv8803_rtc_ops, | |
171 | }; |