| @@ -1,860 +1,866 @@ | | | @@ -1,860 +1,866 @@ |
1 | /* $NetBSD: ds1307.c,v 1.30 2018/12/14 22:05:36 macallan Exp $ */ | | 1 | /* $NetBSD: ds1307.c,v 1.31 2018/12/20 21:36:53 macallan Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2003 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2003 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Steve C. Woodford and Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Steve C. Woodford and Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software | | 17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: | | 18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by | | 19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. | | 20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | | 21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior | | 22 | * or promote products derived from this software without specific prior |
23 | * written permission. | | 23 | * written permission. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | | 25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | #include <sys/cdefs.h> | | 38 | #include <sys/cdefs.h> |
39 | __KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1.30 2018/12/14 22:05:36 macallan Exp $"); | | 39 | __KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1.31 2018/12/20 21:36:53 macallan Exp $"); |
40 | | | 40 | |
41 | #include <sys/param.h> | | 41 | #include <sys/param.h> |
42 | #include <sys/systm.h> | | 42 | #include <sys/systm.h> |
43 | #include <sys/device.h> | | 43 | #include <sys/device.h> |
44 | #include <sys/kernel.h> | | 44 | #include <sys/kernel.h> |
45 | #include <sys/fcntl.h> | | 45 | #include <sys/fcntl.h> |
46 | #include <sys/uio.h> | | 46 | #include <sys/uio.h> |
47 | #include <sys/conf.h> | | 47 | #include <sys/conf.h> |
48 | #include <sys/event.h> | | 48 | #include <sys/event.h> |
49 | | | 49 | |
50 | #include <dev/clock_subr.h> | | 50 | #include <dev/clock_subr.h> |
51 | | | 51 | |
52 | #include <dev/i2c/i2cvar.h> | | 52 | #include <dev/i2c/i2cvar.h> |
53 | #include <dev/i2c/ds1307reg.h> | | 53 | #include <dev/i2c/ds1307reg.h> |
54 | #include <dev/sysmon/sysmonvar.h> | | 54 | #include <dev/sysmon/sysmonvar.h> |
55 | | | 55 | |
56 | #include "ioconf.h" | | 56 | #include "ioconf.h" |
57 | #include "opt_dsrtc.h" | | 57 | #include "opt_dsrtc.h" |
58 | | | 58 | |
59 | struct dsrtc_model { | | 59 | struct dsrtc_model { |
60 | const i2c_addr_t *dm_valid_addrs; | | 60 | const i2c_addr_t *dm_valid_addrs; |
61 | uint16_t dm_model; | | 61 | uint16_t dm_model; |
62 | uint8_t dm_ch_reg; | | 62 | uint8_t dm_ch_reg; |
63 | uint8_t dm_ch_value; | | 63 | uint8_t dm_ch_value; |
64 | uint8_t dm_vbaten_reg; | | 64 | uint8_t dm_vbaten_reg; |
65 | uint8_t dm_vbaten_value; | | 65 | uint8_t dm_vbaten_value; |
66 | uint8_t dm_rtc_start; | | 66 | uint8_t dm_rtc_start; |
67 | uint8_t dm_rtc_size; | | 67 | uint8_t dm_rtc_size; |
68 | uint8_t dm_nvram_start; | | 68 | uint8_t dm_nvram_start; |
69 | uint8_t dm_nvram_size; | | 69 | uint8_t dm_nvram_size; |
70 | uint8_t dm_flags; | | 70 | uint8_t dm_flags; |
71 | #define DSRTC_FLAG_CLOCK_HOLD 0x01 | | 71 | #define DSRTC_FLAG_CLOCK_HOLD 0x01 |
72 | #define DSRTC_FLAG_BCD 0x02 | | 72 | #define DSRTC_FLAG_BCD 0x02 |
73 | #define DSRTC_FLAG_TEMP 0x04 | | 73 | #define DSRTC_FLAG_TEMP 0x04 |
74 | #define DSRTC_FLAG_VBATEN 0x08 | | 74 | #define DSRTC_FLAG_VBATEN 0x08 |
75 | #define DSRTC_FLAG_YEAR_START_2K 0x10 | | 75 | #define DSRTC_FLAG_YEAR_START_2K 0x10 |
76 | #define DSRTC_FLAG_CLOCK_HOLD_REVERSED 0x20 | | 76 | #define DSRTC_FLAG_CLOCK_HOLD_REVERSED 0x20 |
77 | }; | | 77 | }; |
78 | | | 78 | |
79 | static const i2c_addr_t ds1307_valid_addrs[] = { DS1307_ADDR, 0 }; | | 79 | static const i2c_addr_t ds1307_valid_addrs[] = { DS1307_ADDR, 0 }; |
80 | static const struct dsrtc_model ds1307_model = { | | 80 | static const struct dsrtc_model ds1307_model = { |
81 | .dm_valid_addrs = ds1307_valid_addrs, | | 81 | .dm_valid_addrs = ds1307_valid_addrs, |
82 | .dm_model = 1307, | | 82 | .dm_model = 1307, |
83 | .dm_ch_reg = DSXXXX_SECONDS, | | 83 | .dm_ch_reg = DSXXXX_SECONDS, |
84 | .dm_ch_value = DS1307_SECONDS_CH, | | 84 | .dm_ch_value = DS1307_SECONDS_CH, |
85 | .dm_rtc_start = DS1307_RTC_START, | | 85 | .dm_rtc_start = DS1307_RTC_START, |
86 | .dm_rtc_size = DS1307_RTC_SIZE, | | 86 | .dm_rtc_size = DS1307_RTC_SIZE, |
87 | .dm_nvram_start = DS1307_NVRAM_START, | | 87 | .dm_nvram_start = DS1307_NVRAM_START, |
88 | .dm_nvram_size = DS1307_NVRAM_SIZE, | | 88 | .dm_nvram_size = DS1307_NVRAM_SIZE, |
89 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD, | | 89 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD, |
90 | }; | | 90 | }; |
91 | | | 91 | |
92 | static const struct dsrtc_model ds1339_model = { | | 92 | static const struct dsrtc_model ds1339_model = { |
93 | .dm_valid_addrs = ds1307_valid_addrs, | | 93 | .dm_valid_addrs = ds1307_valid_addrs, |
94 | .dm_model = 1339, | | 94 | .dm_model = 1339, |
95 | .dm_rtc_start = DS1339_RTC_START, | | 95 | .dm_rtc_start = DS1339_RTC_START, |
96 | .dm_rtc_size = DS1339_RTC_SIZE, | | 96 | .dm_rtc_size = DS1339_RTC_SIZE, |
97 | .dm_flags = DSRTC_FLAG_BCD, | | 97 | .dm_flags = DSRTC_FLAG_BCD, |
98 | }; | | 98 | }; |
99 | | | 99 | |
100 | static const struct dsrtc_model ds1340_model = { | | 100 | static const struct dsrtc_model ds1340_model = { |
101 | .dm_valid_addrs = ds1307_valid_addrs, | | 101 | .dm_valid_addrs = ds1307_valid_addrs, |
102 | .dm_model = 1340, | | 102 | .dm_model = 1340, |
103 | .dm_ch_reg = DSXXXX_SECONDS, | | 103 | .dm_ch_reg = DSXXXX_SECONDS, |
104 | .dm_ch_value = DS1340_SECONDS_EOSC, | | 104 | .dm_ch_value = DS1340_SECONDS_EOSC, |
105 | .dm_rtc_start = DS1340_RTC_START, | | 105 | .dm_rtc_start = DS1340_RTC_START, |
106 | .dm_rtc_size = DS1340_RTC_SIZE, | | 106 | .dm_rtc_size = DS1340_RTC_SIZE, |
107 | .dm_flags = DSRTC_FLAG_BCD, | | 107 | .dm_flags = DSRTC_FLAG_BCD, |
108 | }; | | 108 | }; |
109 | | | 109 | |
110 | static const struct dsrtc_model ds1672_model = { | | 110 | static const struct dsrtc_model ds1672_model = { |
111 | .dm_valid_addrs = ds1307_valid_addrs, | | 111 | .dm_valid_addrs = ds1307_valid_addrs, |
112 | .dm_model = 1672, | | 112 | .dm_model = 1672, |
113 | .dm_rtc_start = DS1672_RTC_START, | | 113 | .dm_rtc_start = DS1672_RTC_START, |
114 | .dm_rtc_size = DS1672_RTC_SIZE, | | 114 | .dm_rtc_size = DS1672_RTC_SIZE, |
115 | .dm_ch_reg = DS1672_CONTROL, | | 115 | .dm_ch_reg = DS1672_CONTROL, |
116 | .dm_ch_value = DS1672_CONTROL_CH, | | 116 | .dm_ch_value = DS1672_CONTROL_CH, |
117 | .dm_flags = 0, | | 117 | .dm_flags = 0, |
118 | }; | | 118 | }; |
119 | | | 119 | |
120 | static const struct dsrtc_model ds3231_model = { | | 120 | static const struct dsrtc_model ds3231_model = { |
121 | .dm_valid_addrs = ds1307_valid_addrs, | | 121 | .dm_valid_addrs = ds1307_valid_addrs, |
122 | .dm_model = 3231, | | 122 | .dm_model = 3231, |
123 | .dm_rtc_start = DS3232_RTC_START, | | 123 | .dm_rtc_start = DS3232_RTC_START, |
124 | .dm_rtc_size = DS3232_RTC_SIZE, | | 124 | .dm_rtc_size = DS3232_RTC_SIZE, |
125 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_TEMP, | | 125 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_TEMP, |
126 | }; | | 126 | }; |
127 | | | 127 | |
128 | static const struct dsrtc_model ds3232_model = { | | 128 | static const struct dsrtc_model ds3232_model = { |
129 | .dm_valid_addrs = ds1307_valid_addrs, | | 129 | .dm_valid_addrs = ds1307_valid_addrs, |
130 | .dm_model = 3232, | | 130 | .dm_model = 3232, |
131 | .dm_rtc_start = DS3232_RTC_START, | | 131 | .dm_rtc_start = DS3232_RTC_START, |
132 | .dm_rtc_size = DS3232_RTC_SIZE, | | 132 | .dm_rtc_size = DS3232_RTC_SIZE, |
133 | .dm_nvram_start = DS3232_NVRAM_START, | | 133 | .dm_nvram_start = DS3232_NVRAM_START, |
134 | .dm_nvram_size = DS3232_NVRAM_SIZE, | | 134 | .dm_nvram_size = DS3232_NVRAM_SIZE, |
135 | /* | | 135 | /* |
136 | * XXX | | 136 | * XXX |
137 | * the DS3232 likely has the temperature sensor too but I can't | | 137 | * the DS3232 likely has the temperature sensor too but I can't |
138 | * easily verify or test that right now | | 138 | * easily verify or test that right now |
139 | */ | | 139 | */ |
140 | .dm_flags = DSRTC_FLAG_BCD, | | 140 | .dm_flags = DSRTC_FLAG_BCD, |
141 | }; | | 141 | }; |
142 | | | 142 | |
143 | static const i2c_addr_t mcp7940_valid_addrs[] = { MCP7940_ADDR, 0 }; | | 143 | static const i2c_addr_t mcp7940_valid_addrs[] = { MCP7940_ADDR, 0 }; |
144 | static const struct dsrtc_model mcp7940_model = { | | 144 | static const struct dsrtc_model mcp7940_model = { |
145 | .dm_valid_addrs = mcp7940_valid_addrs, | | 145 | .dm_valid_addrs = mcp7940_valid_addrs, |
146 | .dm_model = 7940, | | 146 | .dm_model = 7940, |
147 | .dm_rtc_start = DS1307_RTC_START, | | 147 | .dm_rtc_start = DS1307_RTC_START, |
148 | .dm_rtc_size = DS1307_RTC_SIZE, | | 148 | .dm_rtc_size = DS1307_RTC_SIZE, |
149 | .dm_ch_reg = DSXXXX_SECONDS, | | 149 | .dm_ch_reg = DSXXXX_SECONDS, |
150 | .dm_ch_value = DS1307_SECONDS_CH, | | 150 | .dm_ch_value = DS1307_SECONDS_CH, |
151 | .dm_vbaten_reg = DSXXXX_DAY, | | 151 | .dm_vbaten_reg = DSXXXX_DAY, |
152 | .dm_vbaten_value = MCP7940_TOD_DAY_VBATEN, | | 152 | .dm_vbaten_value = MCP7940_TOD_DAY_VBATEN, |
153 | .dm_nvram_start = MCP7940_NVRAM_START, | | 153 | .dm_nvram_start = MCP7940_NVRAM_START, |
154 | .dm_nvram_size = MCP7940_NVRAM_SIZE, | | 154 | .dm_nvram_size = MCP7940_NVRAM_SIZE, |
155 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD | | | 155 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD | |
156 | DSRTC_FLAG_VBATEN | DSRTC_FLAG_CLOCK_HOLD_REVERSED, | | 156 | DSRTC_FLAG_VBATEN | DSRTC_FLAG_CLOCK_HOLD_REVERSED, |
157 | }; | | 157 | }; |
158 | | | 158 | |
159 | static const struct device_compatible_entry compat_data[] = { | | 159 | static const struct device_compatible_entry compat_data[] = { |
160 | { "dallas,ds1307", (uintptr_t)&ds1307_model }, | | 160 | { "dallas,ds1307", (uintptr_t)&ds1307_model }, |
161 | { "maxim,ds1307", (uintptr_t)&ds1307_model }, | | 161 | { "maxim,ds1307", (uintptr_t)&ds1307_model }, |
162 | | | 162 | |
163 | { "dallas,ds1339", (uintptr_t)&ds1339_model }, | | 163 | { "dallas,ds1339", (uintptr_t)&ds1339_model }, |
164 | { "maxim,ds1339", (uintptr_t)&ds1339_model }, | | 164 | { "maxim,ds1339", (uintptr_t)&ds1339_model }, |
165 | | | 165 | |
166 | { "dallas,ds1340", (uintptr_t)&ds1340_model }, | | 166 | { "dallas,ds1340", (uintptr_t)&ds1340_model }, |
167 | { "maxim,ds1340", (uintptr_t)&ds1340_model }, | | 167 | { "maxim,ds1340", (uintptr_t)&ds1340_model }, |
168 | | | 168 | |
169 | { "dallas,ds1672", (uintptr_t)&ds1672_model }, | | 169 | { "dallas,ds1672", (uintptr_t)&ds1672_model }, |
170 | { "maxim,ds1672", (uintptr_t)&ds1672_model }, | | 170 | { "maxim,ds1672", (uintptr_t)&ds1672_model }, |
171 | | | 171 | |
172 | { "dallas,ds3231", (uintptr_t)&ds3231_model }, | | 172 | { "dallas,ds3231", (uintptr_t)&ds3231_model }, |
173 | { "maxim,ds3231", (uintptr_t)&ds3231_model }, | | 173 | { "maxim,ds3231", (uintptr_t)&ds3231_model }, |
174 | | | 174 | |
175 | { "dallas,ds3232", (uintptr_t)&ds3232_model }, | | 175 | { "dallas,ds3232", (uintptr_t)&ds3232_model }, |
176 | { "maxim,ds3232", (uintptr_t)&ds3232_model }, | | 176 | { "maxim,ds3232", (uintptr_t)&ds3232_model }, |
177 | | | 177 | |
178 | { "microchip,mcp7940", (uintptr_t)&mcp7940_model }, | | 178 | { "microchip,mcp7940", (uintptr_t)&mcp7940_model }, |
179 | | | 179 | |
180 | { NULL, 0 } | | 180 | { NULL, 0 } |
181 | }; | | 181 | }; |
182 | | | 182 | |
183 | struct dsrtc_softc { | | 183 | struct dsrtc_softc { |
184 | device_t sc_dev; | | 184 | device_t sc_dev; |
185 | i2c_tag_t sc_tag; | | 185 | i2c_tag_t sc_tag; |
186 | uint8_t sc_address; | | 186 | uint8_t sc_address; |
187 | bool sc_open; | | 187 | bool sc_open; |
188 | struct dsrtc_model sc_model; | | 188 | struct dsrtc_model sc_model; |
189 | struct todr_chip_handle sc_todr; | | 189 | struct todr_chip_handle sc_todr; |
190 | struct sysmon_envsys *sc_sme; | | 190 | struct sysmon_envsys *sc_sme; |
191 | envsys_data_t sc_sensor; | | 191 | envsys_data_t sc_sensor; |
192 | }; | | 192 | }; |
193 | | | 193 | |
194 | static void dsrtc_attach(device_t, device_t, void *); | | 194 | static void dsrtc_attach(device_t, device_t, void *); |
195 | static int dsrtc_match(device_t, cfdata_t, void *); | | 195 | static int dsrtc_match(device_t, cfdata_t, void *); |
196 | | | 196 | |
197 | CFATTACH_DECL_NEW(dsrtc, sizeof(struct dsrtc_softc), | | 197 | CFATTACH_DECL_NEW(dsrtc, sizeof(struct dsrtc_softc), |
198 | dsrtc_match, dsrtc_attach, NULL, NULL); | | 198 | dsrtc_match, dsrtc_attach, NULL, NULL); |
199 | | | 199 | |
200 | dev_type_open(dsrtc_open); | | 200 | dev_type_open(dsrtc_open); |
201 | dev_type_close(dsrtc_close); | | 201 | dev_type_close(dsrtc_close); |
202 | dev_type_read(dsrtc_read); | | 202 | dev_type_read(dsrtc_read); |
203 | dev_type_write(dsrtc_write); | | 203 | dev_type_write(dsrtc_write); |
204 | | | 204 | |
205 | const struct cdevsw dsrtc_cdevsw = { | | 205 | const struct cdevsw dsrtc_cdevsw = { |
206 | .d_open = dsrtc_open, | | 206 | .d_open = dsrtc_open, |
207 | .d_close = dsrtc_close, | | 207 | .d_close = dsrtc_close, |
208 | .d_read = dsrtc_read, | | 208 | .d_read = dsrtc_read, |
209 | .d_write = dsrtc_write, | | 209 | .d_write = dsrtc_write, |
210 | .d_ioctl = noioctl, | | 210 | .d_ioctl = noioctl, |
211 | .d_stop = nostop, | | 211 | .d_stop = nostop, |
212 | .d_tty = notty, | | 212 | .d_tty = notty, |
213 | .d_poll = nopoll, | | 213 | .d_poll = nopoll, |
214 | .d_mmap = nommap, | | 214 | .d_mmap = nommap, |
215 | .d_kqfilter = nokqfilter, | | 215 | .d_kqfilter = nokqfilter, |
216 | .d_discard = nodiscard, | | 216 | .d_discard = nodiscard, |
217 | .d_flag = D_OTHER | | 217 | .d_flag = D_OTHER |
218 | }; | | 218 | }; |
219 | | | 219 | |
220 | static int dsrtc_gettime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); | | 220 | static int dsrtc_gettime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); |
221 | static int dsrtc_settime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); | | 221 | static int dsrtc_settime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); |
222 | static int dsrtc_clock_read_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); | | 222 | static int dsrtc_clock_read_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); |
223 | static int dsrtc_clock_write_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); | | 223 | static int dsrtc_clock_write_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); |
224 | | | 224 | |
225 | static int dsrtc_gettime_timeval(struct todr_chip_handle *, struct timeval *); | | 225 | static int dsrtc_gettime_timeval(struct todr_chip_handle *, struct timeval *); |
226 | static int dsrtc_settime_timeval(struct todr_chip_handle *, struct timeval *); | | 226 | static int dsrtc_settime_timeval(struct todr_chip_handle *, struct timeval *); |
227 | static int dsrtc_clock_read_timeval(struct dsrtc_softc *, time_t *); | | 227 | static int dsrtc_clock_read_timeval(struct dsrtc_softc *, time_t *); |
228 | static int dsrtc_clock_write_timeval(struct dsrtc_softc *, time_t); | | 228 | static int dsrtc_clock_write_timeval(struct dsrtc_softc *, time_t); |
229 | | | 229 | |
230 | static int dsrtc_read_temp(struct dsrtc_softc *, uint32_t *); | | 230 | static int dsrtc_read_temp(struct dsrtc_softc *, uint32_t *); |
231 | static void dsrtc_refresh(struct sysmon_envsys *, envsys_data_t *); | | 231 | static void dsrtc_refresh(struct sysmon_envsys *, envsys_data_t *); |
232 | | | 232 | |
233 | static const struct dsrtc_model * | | 233 | static const struct dsrtc_model * |
234 | dsrtc_model_by_number(u_int model) | | 234 | dsrtc_model_by_number(u_int model) |
235 | { | | 235 | { |
236 | const struct device_compatible_entry *dce; | | 236 | const struct device_compatible_entry *dce; |
237 | const struct dsrtc_model *dm; | | 237 | const struct dsrtc_model *dm; |
238 | | | 238 | |
239 | /* no model given, assume it's a DS1307 */ | | 239 | /* no model given, assume it's a DS1307 */ |
240 | if (model == 0) | | 240 | if (model == 0) |
241 | return &ds1307_model; | | 241 | return &ds1307_model; |
242 | | | 242 | |
243 | for (dce = compat_data; dce->compat != NULL; dce++) { | | 243 | for (dce = compat_data; dce->compat != NULL; dce++) { |
244 | dm = (void *)dce->data; | | 244 | dm = (void *)dce->data; |
245 | if (dm->dm_model == model) | | 245 | if (dm->dm_model == model) |
246 | return dm; | | 246 | return dm; |
247 | } | | 247 | } |
248 | return NULL; | | 248 | return NULL; |
249 | } | | 249 | } |
250 | | | 250 | |
251 | static const struct dsrtc_model * | | 251 | static const struct dsrtc_model * |
252 | dsrtc_model_by_compat(const struct i2c_attach_args *ia) | | 252 | dsrtc_model_by_compat(const struct i2c_attach_args *ia) |
253 | { | | 253 | { |
254 | const struct dsrtc_model *dm = NULL; | | 254 | const struct dsrtc_model *dm = NULL; |
255 | const struct device_compatible_entry *dce; | | 255 | const struct device_compatible_entry *dce; |
256 | | | 256 | |
257 | if (iic_compatible_match(ia, compat_data, &dce)) | | 257 | if (iic_compatible_match(ia, compat_data, &dce)) |
258 | dm = (void *)dce->data; | | 258 | dm = (void *)dce->data; |
259 | | | 259 | |
260 | return dm; | | 260 | return dm; |
261 | } | | 261 | } |
262 | | | 262 | |
263 | static bool | | 263 | static bool |
264 | dsrtc_is_valid_addr_for_model(const struct dsrtc_model *dm, i2c_addr_t addr) | | 264 | dsrtc_is_valid_addr_for_model(const struct dsrtc_model *dm, i2c_addr_t addr) |
265 | { | | 265 | { |
266 | | | 266 | |
267 | for (int i = 0; dm->dm_valid_addrs[i] != 0; i++) { | | 267 | for (int i = 0; dm->dm_valid_addrs[i] != 0; i++) { |
268 | if (addr == dm->dm_valid_addrs[i]) | | 268 | if (addr == dm->dm_valid_addrs[i]) |
269 | return true; | | 269 | return true; |
270 | } | | 270 | } |
271 | return false; | | 271 | return false; |
272 | } | | 272 | } |
273 | | | 273 | |
274 | static int | | 274 | static int |
275 | dsrtc_match(device_t parent, cfdata_t cf, void *arg) | | 275 | dsrtc_match(device_t parent, cfdata_t cf, void *arg) |
276 | { | | 276 | { |
277 | struct i2c_attach_args *ia = arg; | | 277 | struct i2c_attach_args *ia = arg; |
278 | const struct dsrtc_model *dm; | | 278 | const struct dsrtc_model *dm; |
279 | int match_result; | | 279 | int match_result; |
280 | | | 280 | |
281 | if (iic_use_direct_match(ia, cf, compat_data, &match_result)) | | 281 | if (iic_use_direct_match(ia, cf, compat_data, &match_result)) |
282 | return match_result; | | 282 | return match_result; |
283 | | | 283 | |
284 | dm = dsrtc_model_by_number(cf->cf_flags & 0xffff); | | 284 | dm = dsrtc_model_by_number(cf->cf_flags & 0xffff); |
285 | if (dm == NULL) | | 285 | if (dm == NULL) |
286 | return 0; | | 286 | return 0; |
287 | | | 287 | |
288 | if (dsrtc_is_valid_addr_for_model(dm, ia->ia_addr)) | | 288 | if (dsrtc_is_valid_addr_for_model(dm, ia->ia_addr)) |
289 | return I2C_MATCH_ADDRESS_ONLY; | | 289 | return I2C_MATCH_ADDRESS_ONLY; |
290 | | | 290 | |
291 | return 0; | | 291 | return 0; |
292 | } | | 292 | } |
293 | | | 293 | |
294 | static void | | 294 | static void |
295 | dsrtc_attach(device_t parent, device_t self, void *arg) | | 295 | dsrtc_attach(device_t parent, device_t self, void *arg) |
296 | { | | 296 | { |
297 | struct dsrtc_softc *sc = device_private(self); | | 297 | struct dsrtc_softc *sc = device_private(self); |
298 | struct i2c_attach_args *ia = arg; | | 298 | struct i2c_attach_args *ia = arg; |
299 | const struct dsrtc_model *dm; | | 299 | const struct dsrtc_model *dm; |
| | | 300 | prop_dictionary_t dict = device_properties(self); |
| | | 301 | bool base_2k = FALSE; |
300 | | | 302 | |
301 | if ((dm = dsrtc_model_by_compat(ia)) == NULL) | | 303 | if ((dm = dsrtc_model_by_compat(ia)) == NULL) |
302 | dm = dsrtc_model_by_number(device_cfdata(self)->cf_flags); | | 304 | dm = dsrtc_model_by_number(device_cfdata(self)->cf_flags); |
303 | | | 305 | |
304 | if (dm == NULL) { | | 306 | if (dm == NULL) { |
305 | aprint_error(": unable to determine model!\n"); | | 307 | aprint_error(": unable to determine model!\n"); |
306 | return; | | 308 | return; |
307 | } | | 309 | } |
308 | | | 310 | |
309 | aprint_naive(": Real-time Clock%s\n", | | 311 | aprint_naive(": Real-time Clock%s\n", |
310 | dm->dm_nvram_size > 0 ? "/NVRAM" : ""); | | 312 | dm->dm_nvram_size > 0 ? "/NVRAM" : ""); |
311 | aprint_normal(": DS%u Real-time Clock%s\n", dm->dm_model, | | 313 | aprint_normal(": DS%u Real-time Clock%s\n", dm->dm_model, |
312 | dm->dm_nvram_size > 0 ? "/NVRAM" : ""); | | 314 | dm->dm_nvram_size > 0 ? "/NVRAM" : ""); |
313 | | | 315 | |
314 | sc->sc_tag = ia->ia_tag; | | 316 | sc->sc_tag = ia->ia_tag; |
315 | sc->sc_address = ia->ia_addr; | | 317 | sc->sc_address = ia->ia_addr; |
316 | sc->sc_model = *dm; | | 318 | sc->sc_model = *dm; |
317 | sc->sc_dev = self; | | 319 | sc->sc_dev = self; |
318 | sc->sc_open = 0; | | 320 | sc->sc_open = 0; |
319 | sc->sc_todr.cookie = sc; | | 321 | sc->sc_todr.cookie = sc; |
320 | | | 322 | |
321 | if (dm->dm_flags & DSRTC_FLAG_BCD) { | | 323 | if (dm->dm_flags & DSRTC_FLAG_BCD) { |
322 | sc->sc_todr.todr_gettime_ymdhms = dsrtc_gettime_ymdhms; | | 324 | sc->sc_todr.todr_gettime_ymdhms = dsrtc_gettime_ymdhms; |
323 | sc->sc_todr.todr_settime_ymdhms = dsrtc_settime_ymdhms; | | 325 | sc->sc_todr.todr_settime_ymdhms = dsrtc_settime_ymdhms; |
324 | } else { | | 326 | } else { |
325 | sc->sc_todr.todr_gettime = dsrtc_gettime_timeval; | | 327 | sc->sc_todr.todr_gettime = dsrtc_gettime_timeval; |
326 | sc->sc_todr.todr_settime = dsrtc_settime_timeval; | | 328 | sc->sc_todr.todr_settime = dsrtc_settime_timeval; |
327 | } | | 329 | } |
328 | sc->sc_todr.todr_setwen = NULL; | | 330 | sc->sc_todr.todr_setwen = NULL; |
329 | | | 331 | |
330 | #ifdef DSRTC_YEAR_START_2K | | 332 | #ifdef DSRTC_YEAR_START_2K |
331 | sc->sc_model.dm_flags |= DSRTC_FLAG_YEAR_START_2K; | | 333 | sc->sc_model.dm_flags |= DSRTC_FLAG_YEAR_START_2K; |
332 | #endif | | 334 | #endif |
333 | | | 335 | |
| | | 336 | prop_dictionary_get_bool(dict, "base_year_is_2000", &base_2k); |
| | | 337 | if (base_2k) sc->sc_model.dm_flags |= DSRTC_FLAG_YEAR_START_2K; |
| | | 338 | |
| | | 339 | |
334 | todr_attach(&sc->sc_todr); | | 340 | todr_attach(&sc->sc_todr); |
335 | if ((sc->sc_model.dm_flags & DSRTC_FLAG_TEMP) != 0) { | | 341 | if ((sc->sc_model.dm_flags & DSRTC_FLAG_TEMP) != 0) { |
336 | int error; | | 342 | int error; |
337 | | | 343 | |
338 | sc->sc_sme = sysmon_envsys_create(); | | 344 | sc->sc_sme = sysmon_envsys_create(); |
339 | sc->sc_sme->sme_name = device_xname(self); | | 345 | sc->sc_sme->sme_name = device_xname(self); |
340 | sc->sc_sme->sme_cookie = sc; | | 346 | sc->sc_sme->sme_cookie = sc; |
341 | sc->sc_sme->sme_refresh = dsrtc_refresh; | | 347 | sc->sc_sme->sme_refresh = dsrtc_refresh; |
342 | | | 348 | |
343 | sc->sc_sensor.units = ENVSYS_STEMP; | | 349 | sc->sc_sensor.units = ENVSYS_STEMP; |
344 | sc->sc_sensor.state = ENVSYS_SINVALID; | | 350 | sc->sc_sensor.state = ENVSYS_SINVALID; |
345 | sc->sc_sensor.flags = 0; | | 351 | sc->sc_sensor.flags = 0; |
346 | (void)strlcpy(sc->sc_sensor.desc, "temperature", | | 352 | (void)strlcpy(sc->sc_sensor.desc, "temperature", |
347 | sizeof(sc->sc_sensor.desc)); | | 353 | sizeof(sc->sc_sensor.desc)); |
348 | | | 354 | |
349 | if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { | | 355 | if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { |
350 | aprint_error_dev(self, "unable to attach sensor\n"); | | 356 | aprint_error_dev(self, "unable to attach sensor\n"); |
351 | goto bad; | | 357 | goto bad; |
352 | } | | 358 | } |
353 | | | 359 | |
354 | error = sysmon_envsys_register(sc->sc_sme); | | 360 | error = sysmon_envsys_register(sc->sc_sme); |
355 | if (error) { | | 361 | if (error) { |
356 | aprint_error_dev(self, | | 362 | aprint_error_dev(self, |
357 | "error %d registering with sysmon\n", error); | | 363 | "error %d registering with sysmon\n", error); |
358 | goto bad; | | 364 | goto bad; |
359 | } | | 365 | } |
360 | } | | 366 | } |
361 | return; | | 367 | return; |
362 | bad: | | 368 | bad: |
363 | sysmon_envsys_destroy(sc->sc_sme); | | 369 | sysmon_envsys_destroy(sc->sc_sme); |
364 | } | | 370 | } |
365 | | | 371 | |
366 | /*ARGSUSED*/ | | 372 | /*ARGSUSED*/ |
367 | int | | 373 | int |
368 | dsrtc_open(dev_t dev, int flag, int fmt, struct lwp *l) | | 374 | dsrtc_open(dev_t dev, int flag, int fmt, struct lwp *l) |
369 | { | | 375 | { |
370 | struct dsrtc_softc *sc; | | 376 | struct dsrtc_softc *sc; |
371 | | | 377 | |
372 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) | | 378 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) |
373 | return ENXIO; | | 379 | return ENXIO; |
374 | | | 380 | |
375 | /* XXX: Locking */ | | 381 | /* XXX: Locking */ |
376 | if (sc->sc_open) | | 382 | if (sc->sc_open) |
377 | return EBUSY; | | 383 | return EBUSY; |
378 | | | 384 | |
379 | sc->sc_open = true; | | 385 | sc->sc_open = true; |
380 | return 0; | | 386 | return 0; |
381 | } | | 387 | } |
382 | | | 388 | |
383 | /*ARGSUSED*/ | | 389 | /*ARGSUSED*/ |
384 | int | | 390 | int |
385 | dsrtc_close(dev_t dev, int flag, int fmt, struct lwp *l) | | 391 | dsrtc_close(dev_t dev, int flag, int fmt, struct lwp *l) |
386 | { | | 392 | { |
387 | struct dsrtc_softc *sc; | | 393 | struct dsrtc_softc *sc; |
388 | | | 394 | |
389 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) | | 395 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) |
390 | return ENXIO; | | 396 | return ENXIO; |
391 | | | 397 | |
392 | sc->sc_open = false; | | 398 | sc->sc_open = false; |
393 | return 0; | | 399 | return 0; |
394 | } | | 400 | } |
395 | | | 401 | |
396 | /*ARGSUSED*/ | | 402 | /*ARGSUSED*/ |
397 | int | | 403 | int |
398 | dsrtc_read(dev_t dev, struct uio *uio, int flags) | | 404 | dsrtc_read(dev_t dev, struct uio *uio, int flags) |
399 | { | | 405 | { |
400 | struct dsrtc_softc *sc; | | 406 | struct dsrtc_softc *sc; |
401 | int error; | | 407 | int error; |
402 | | | 408 | |
403 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) | | 409 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) |
404 | return ENXIO; | | 410 | return ENXIO; |
405 | | | 411 | |
406 | const struct dsrtc_model * const dm = &sc->sc_model; | | 412 | const struct dsrtc_model * const dm = &sc->sc_model; |
407 | if (uio->uio_offset >= dm->dm_nvram_size) | | 413 | if (uio->uio_offset >= dm->dm_nvram_size) |
408 | return EINVAL; | | 414 | return EINVAL; |
409 | | | 415 | |
410 | if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) | | 416 | if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) |
411 | return error; | | 417 | return error; |
412 | | | 418 | |
413 | KASSERT(uio->uio_offset >= 0); | | 419 | KASSERT(uio->uio_offset >= 0); |
414 | while (uio->uio_resid && uio->uio_offset < dm->dm_nvram_size) { | | 420 | while (uio->uio_resid && uio->uio_offset < dm->dm_nvram_size) { |
415 | uint8_t ch, cmd; | | 421 | uint8_t ch, cmd; |
416 | const u_int a = uio->uio_offset; | | 422 | const u_int a = uio->uio_offset; |
417 | cmd = a + dm->dm_nvram_start; | | 423 | cmd = a + dm->dm_nvram_start; |
418 | if ((error = iic_exec(sc->sc_tag, | | 424 | if ((error = iic_exec(sc->sc_tag, |
419 | uio->uio_resid > 1 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP, | | 425 | uio->uio_resid > 1 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP, |
420 | sc->sc_address, &cmd, 1, &ch, 1, 0)) != 0) { | | 426 | sc->sc_address, &cmd, 1, &ch, 1, 0)) != 0) { |
421 | iic_release_bus(sc->sc_tag, 0); | | 427 | iic_release_bus(sc->sc_tag, 0); |
422 | aprint_error_dev(sc->sc_dev, | | 428 | aprint_error_dev(sc->sc_dev, |
423 | "%s: read failed at 0x%x: %d\n", | | 429 | "%s: read failed at 0x%x: %d\n", |
424 | __func__, a, error); | | 430 | __func__, a, error); |
425 | return error; | | 431 | return error; |
426 | } | | 432 | } |
427 | if ((error = uiomove(&ch, 1, uio)) != 0) { | | 433 | if ((error = uiomove(&ch, 1, uio)) != 0) { |
428 | iic_release_bus(sc->sc_tag, 0); | | 434 | iic_release_bus(sc->sc_tag, 0); |
429 | return error; | | 435 | return error; |
430 | } | | 436 | } |
431 | } | | 437 | } |
432 | | | 438 | |
433 | iic_release_bus(sc->sc_tag, 0); | | 439 | iic_release_bus(sc->sc_tag, 0); |
434 | | | 440 | |
435 | return 0; | | 441 | return 0; |
436 | } | | 442 | } |
437 | | | 443 | |
438 | /*ARGSUSED*/ | | 444 | /*ARGSUSED*/ |
439 | int | | 445 | int |
440 | dsrtc_write(dev_t dev, struct uio *uio, int flags) | | 446 | dsrtc_write(dev_t dev, struct uio *uio, int flags) |
441 | { | | 447 | { |
442 | struct dsrtc_softc *sc; | | 448 | struct dsrtc_softc *sc; |
443 | int error; | | 449 | int error; |
444 | | | 450 | |
445 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) | | 451 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) |
446 | return ENXIO; | | 452 | return ENXIO; |
447 | | | 453 | |
448 | const struct dsrtc_model * const dm = &sc->sc_model; | | 454 | const struct dsrtc_model * const dm = &sc->sc_model; |
449 | if (uio->uio_offset >= dm->dm_nvram_size) | | 455 | if (uio->uio_offset >= dm->dm_nvram_size) |
450 | return EINVAL; | | 456 | return EINVAL; |
451 | | | 457 | |
452 | if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) | | 458 | if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) |
453 | return error; | | 459 | return error; |
454 | | | 460 | |
455 | while (uio->uio_resid && uio->uio_offset < dm->dm_nvram_size) { | | 461 | while (uio->uio_resid && uio->uio_offset < dm->dm_nvram_size) { |
456 | uint8_t cmdbuf[2]; | | 462 | uint8_t cmdbuf[2]; |
457 | const u_int a = (int)uio->uio_offset; | | 463 | const u_int a = (int)uio->uio_offset; |
458 | cmdbuf[0] = a + dm->dm_nvram_start; | | 464 | cmdbuf[0] = a + dm->dm_nvram_start; |
459 | if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0) | | 465 | if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0) |
460 | break; | | 466 | break; |
461 | | | 467 | |
462 | if ((error = iic_exec(sc->sc_tag, | | 468 | if ((error = iic_exec(sc->sc_tag, |
463 | uio->uio_resid ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, | | 469 | uio->uio_resid ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, |
464 | sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) { | | 470 | sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) { |
465 | aprint_error_dev(sc->sc_dev, | | 471 | aprint_error_dev(sc->sc_dev, |
466 | "%s: write failed at 0x%x: %d\n", | | 472 | "%s: write failed at 0x%x: %d\n", |
467 | __func__, a, error); | | 473 | __func__, a, error); |
468 | break; | | 474 | break; |
469 | } | | 475 | } |
470 | } | | 476 | } |
471 | | | 477 | |
472 | iic_release_bus(sc->sc_tag, 0); | | 478 | iic_release_bus(sc->sc_tag, 0); |
473 | | | 479 | |
474 | return error; | | 480 | return error; |
475 | } | | 481 | } |
476 | | | 482 | |
477 | static int | | 483 | static int |
478 | dsrtc_gettime_ymdhms(struct todr_chip_handle *ch, struct clock_ymdhms *dt) | | 484 | dsrtc_gettime_ymdhms(struct todr_chip_handle *ch, struct clock_ymdhms *dt) |
479 | { | | 485 | { |
480 | struct dsrtc_softc *sc = ch->cookie; | | 486 | struct dsrtc_softc *sc = ch->cookie; |
481 | struct clock_ymdhms check; | | 487 | struct clock_ymdhms check; |
482 | int retries; | | 488 | int retries; |
483 | | | 489 | |
484 | memset(dt, 0, sizeof(*dt)); | | 490 | memset(dt, 0, sizeof(*dt)); |
485 | memset(&check, 0, sizeof(check)); | | 491 | memset(&check, 0, sizeof(check)); |
486 | | | 492 | |
487 | /* | | 493 | /* |
488 | * Since we don't support Burst Read, we have to read the clock twice | | 494 | * Since we don't support Burst Read, we have to read the clock twice |
489 | * until we get two consecutive identical results. | | 495 | * until we get two consecutive identical results. |
490 | */ | | 496 | */ |
491 | retries = 5; | | 497 | retries = 5; |
492 | do { | | 498 | do { |
493 | dsrtc_clock_read_ymdhms(sc, dt); | | 499 | dsrtc_clock_read_ymdhms(sc, dt); |
494 | dsrtc_clock_read_ymdhms(sc, &check); | | 500 | dsrtc_clock_read_ymdhms(sc, &check); |
495 | } while (memcmp(dt, &check, sizeof(check)) != 0 && --retries); | | 501 | } while (memcmp(dt, &check, sizeof(check)) != 0 && --retries); |
496 | | | 502 | |
497 | return 0; | | 503 | return 0; |
498 | } | | 504 | } |
499 | | | 505 | |
500 | static int | | 506 | static int |
501 | dsrtc_settime_ymdhms(struct todr_chip_handle *ch, struct clock_ymdhms *dt) | | 507 | dsrtc_settime_ymdhms(struct todr_chip_handle *ch, struct clock_ymdhms *dt) |
502 | { | | 508 | { |
503 | struct dsrtc_softc *sc = ch->cookie; | | 509 | struct dsrtc_softc *sc = ch->cookie; |
504 | | | 510 | |
505 | if (dsrtc_clock_write_ymdhms(sc, dt) == 0) | | 511 | if (dsrtc_clock_write_ymdhms(sc, dt) == 0) |
506 | return -1; | | 512 | return -1; |
507 | | | 513 | |
508 | return 0; | | 514 | return 0; |
509 | } | | 515 | } |
510 | | | 516 | |
511 | static int | | 517 | static int |
512 | dsrtc_clock_read_ymdhms(struct dsrtc_softc *sc, struct clock_ymdhms *dt) | | 518 | dsrtc_clock_read_ymdhms(struct dsrtc_softc *sc, struct clock_ymdhms *dt) |
513 | { | | 519 | { |
514 | struct dsrtc_model * const dm = &sc->sc_model; | | 520 | struct dsrtc_model * const dm = &sc->sc_model; |
515 | uint8_t bcd[DSXXXX_RTC_SIZE], cmdbuf[1]; | | 521 | uint8_t bcd[DSXXXX_RTC_SIZE], cmdbuf[1]; |
516 | int error; | | 522 | int error; |
517 | | | 523 | |
518 | KASSERT(DSXXXX_RTC_SIZE >= dm->dm_rtc_size); | | 524 | KASSERT(DSXXXX_RTC_SIZE >= dm->dm_rtc_size); |
519 | | | 525 | |
520 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { | | 526 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { |
521 | aprint_error_dev(sc->sc_dev, | | 527 | aprint_error_dev(sc->sc_dev, |
522 | "%s: failed to acquire I2C bus: %d\n", | | 528 | "%s: failed to acquire I2C bus: %d\n", |
523 | __func__, error); | | 529 | __func__, error); |
524 | return 0; | | 530 | return 0; |
525 | } | | 531 | } |
526 | | | 532 | |
527 | /* Read each RTC register in order. */ | | 533 | /* Read each RTC register in order. */ |
528 | for (u_int i = 0; !error && i < dm->dm_rtc_size; i++) { | | 534 | for (u_int i = 0; !error && i < dm->dm_rtc_size; i++) { |
529 | cmdbuf[0] = dm->dm_rtc_start + i; | | 535 | cmdbuf[0] = dm->dm_rtc_start + i; |
530 | | | 536 | |
531 | error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | | 537 | error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, |
532 | sc->sc_address, cmdbuf, 1, &bcd[i], 1, I2C_F_POLL); | | 538 | sc->sc_address, cmdbuf, 1, &bcd[i], 1, I2C_F_POLL); |
533 | } | | 539 | } |
534 | | | 540 | |
535 | /* Done with I2C */ | | 541 | /* Done with I2C */ |
536 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 542 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
537 | | | 543 | |
538 | if (error != 0) { | | 544 | if (error != 0) { |
539 | aprint_error_dev(sc->sc_dev, | | 545 | aprint_error_dev(sc->sc_dev, |
540 | "%s: failed to read rtc at 0x%x: %d\n", | | 546 | "%s: failed to read rtc at 0x%x: %d\n", |
541 | __func__, cmdbuf[0], error); | | 547 | __func__, cmdbuf[0], error); |
542 | return 0; | | 548 | return 0; |
543 | } | | 549 | } |
544 | | | 550 | |
545 | /* | | 551 | /* |
546 | * Convert the RTC's register values into something useable | | 552 | * Convert the RTC's register values into something useable |
547 | */ | | 553 | */ |
548 | dt->dt_sec = bcdtobin(bcd[DSXXXX_SECONDS] & DSXXXX_SECONDS_MASK); | | 554 | dt->dt_sec = bcdtobin(bcd[DSXXXX_SECONDS] & DSXXXX_SECONDS_MASK); |
549 | dt->dt_min = bcdtobin(bcd[DSXXXX_MINUTES] & DSXXXX_MINUTES_MASK); | | 555 | dt->dt_min = bcdtobin(bcd[DSXXXX_MINUTES] & DSXXXX_MINUTES_MASK); |
550 | | | 556 | |
551 | if ((bcd[DSXXXX_HOURS] & DSXXXX_HOURS_12HRS_MODE) != 0) { | | 557 | if ((bcd[DSXXXX_HOURS] & DSXXXX_HOURS_12HRS_MODE) != 0) { |
552 | dt->dt_hour = bcdtobin(bcd[DSXXXX_HOURS] & | | 558 | dt->dt_hour = bcdtobin(bcd[DSXXXX_HOURS] & |
553 | DSXXXX_HOURS_12MASK) % 12; /* 12AM -> 0, 12PM -> 12 */ | | 559 | DSXXXX_HOURS_12MASK) % 12; /* 12AM -> 0, 12PM -> 12 */ |
554 | if (bcd[DSXXXX_HOURS] & DSXXXX_HOURS_12HRS_PM) | | 560 | if (bcd[DSXXXX_HOURS] & DSXXXX_HOURS_12HRS_PM) |
555 | dt->dt_hour += 12; | | 561 | dt->dt_hour += 12; |
556 | } else | | 562 | } else |
557 | dt->dt_hour = bcdtobin(bcd[DSXXXX_HOURS] & | | 563 | dt->dt_hour = bcdtobin(bcd[DSXXXX_HOURS] & |
558 | DSXXXX_HOURS_24MASK); | | 564 | DSXXXX_HOURS_24MASK); |
559 | | | 565 | |
560 | dt->dt_day = bcdtobin(bcd[DSXXXX_DATE] & DSXXXX_DATE_MASK); | | 566 | dt->dt_day = bcdtobin(bcd[DSXXXX_DATE] & DSXXXX_DATE_MASK); |
561 | dt->dt_mon = bcdtobin(bcd[DSXXXX_MONTH] & DSXXXX_MONTH_MASK); | | 567 | dt->dt_mon = bcdtobin(bcd[DSXXXX_MONTH] & DSXXXX_MONTH_MASK); |
562 | | | 568 | |
563 | /* XXX: Should be an MD way to specify EPOCH used by BIOS/Firmware */ | | 569 | /* XXX: Should be an MD way to specify EPOCH used by BIOS/Firmware */ |
564 | if (sc->sc_model.dm_flags & DSRTC_FLAG_YEAR_START_2K) | | 570 | if (sc->sc_model.dm_flags & DSRTC_FLAG_YEAR_START_2K) |
565 | dt->dt_year = bcdtobin(bcd[DSXXXX_YEAR]) + 2000; | | 571 | dt->dt_year = bcdtobin(bcd[DSXXXX_YEAR]) + 2000; |
566 | else { | | 572 | else { |
567 | dt->dt_year = bcdtobin(bcd[DSXXXX_YEAR]) + POSIX_BASE_YEAR; | | 573 | dt->dt_year = bcdtobin(bcd[DSXXXX_YEAR]) + POSIX_BASE_YEAR; |
568 | if (bcd[DSXXXX_MONTH] & DSXXXX_MONTH_CENTURY) | | 574 | if (bcd[DSXXXX_MONTH] & DSXXXX_MONTH_CENTURY) |
569 | dt->dt_year += 100; | | 575 | dt->dt_year += 100; |
570 | } | | 576 | } |
571 | | | 577 | |
572 | return 1; | | 578 | return 1; |
573 | } | | 579 | } |
574 | | | 580 | |
575 | static int | | 581 | static int |
576 | dsrtc_clock_write_ymdhms(struct dsrtc_softc *sc, struct clock_ymdhms *dt) | | 582 | dsrtc_clock_write_ymdhms(struct dsrtc_softc *sc, struct clock_ymdhms *dt) |
577 | { | | 583 | { |
578 | struct dsrtc_model * const dm = &sc->sc_model; | | 584 | struct dsrtc_model * const dm = &sc->sc_model; |
579 | uint8_t bcd[DSXXXX_RTC_SIZE], cmdbuf[2]; | | 585 | uint8_t bcd[DSXXXX_RTC_SIZE], cmdbuf[2]; |
580 | int error, offset; | | 586 | int error, offset; |
581 | | | 587 | |
582 | KASSERT(DSXXXX_RTC_SIZE >= dm->dm_rtc_size); | | 588 | KASSERT(DSXXXX_RTC_SIZE >= dm->dm_rtc_size); |
583 | | | 589 | |
584 | /* | | 590 | /* |
585 | * Convert our time representation into something the DSXXXX | | 591 | * Convert our time representation into something the DSXXXX |
586 | * can understand. | | 592 | * can understand. |
587 | */ | | 593 | */ |
588 | bcd[DSXXXX_SECONDS] = bintobcd(dt->dt_sec); | | 594 | bcd[DSXXXX_SECONDS] = bintobcd(dt->dt_sec); |
589 | bcd[DSXXXX_MINUTES] = bintobcd(dt->dt_min); | | 595 | bcd[DSXXXX_MINUTES] = bintobcd(dt->dt_min); |
590 | bcd[DSXXXX_HOURS] = bintobcd(dt->dt_hour); /* DSXXXX_HOURS_12HRS_MODE=0 */ | | 596 | bcd[DSXXXX_HOURS] = bintobcd(dt->dt_hour); /* DSXXXX_HOURS_12HRS_MODE=0 */ |
591 | bcd[DSXXXX_DATE] = bintobcd(dt->dt_day); | | 597 | bcd[DSXXXX_DATE] = bintobcd(dt->dt_day); |
592 | bcd[DSXXXX_DAY] = bintobcd(dt->dt_wday); | | 598 | bcd[DSXXXX_DAY] = bintobcd(dt->dt_wday); |
593 | bcd[DSXXXX_MONTH] = bintobcd(dt->dt_mon); | | 599 | bcd[DSXXXX_MONTH] = bintobcd(dt->dt_mon); |
594 | | | 600 | |
595 | if (sc->sc_model.dm_flags & DSRTC_FLAG_YEAR_START_2K) { | | 601 | if (sc->sc_model.dm_flags & DSRTC_FLAG_YEAR_START_2K) { |
596 | offset = 2000; | | 602 | offset = 2000; |
597 | } else { | | 603 | } else { |
598 | offset = POSIX_BASE_YEAR; | | 604 | offset = POSIX_BASE_YEAR; |
599 | } | | 605 | } |
600 | | | 606 | |
601 | bcd[DSXXXX_YEAR] = bintobcd((dt->dt_year - offset) % 100); | | 607 | bcd[DSXXXX_YEAR] = bintobcd((dt->dt_year - offset) % 100); |
602 | if (dt->dt_year - offset >= 100) | | 608 | if (dt->dt_year - offset >= 100) |
603 | bcd[DSXXXX_MONTH] |= DSXXXX_MONTH_CENTURY; | | 609 | bcd[DSXXXX_MONTH] |= DSXXXX_MONTH_CENTURY; |
604 | | | 610 | |
605 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { | | 611 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { |
606 | aprint_error_dev(sc->sc_dev, | | 612 | aprint_error_dev(sc->sc_dev, |
607 | "%s: failed to acquire I2C bus: %d\n", | | 613 | "%s: failed to acquire I2C bus: %d\n", |
608 | __func__, error); | | 614 | __func__, error); |
609 | return 0; | | 615 | return 0; |
610 | } | | 616 | } |
611 | | | 617 | |
612 | /* Stop the clock */ | | 618 | /* Stop the clock */ |
613 | cmdbuf[0] = dm->dm_ch_reg; | | 619 | cmdbuf[0] = dm->dm_ch_reg; |
614 | | | 620 | |
615 | if ((error = iic_exec(sc->sc_tag, I2C_OP_READ, sc->sc_address, | | 621 | if ((error = iic_exec(sc->sc_tag, I2C_OP_READ, sc->sc_address, |
616 | cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) != 0) { | | 622 | cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) != 0) { |
617 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 623 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
618 | aprint_error_dev(sc->sc_dev, | | 624 | aprint_error_dev(sc->sc_dev, |
619 | "%s: failed to read Hold Clock: %d\n", | | 625 | "%s: failed to read Hold Clock: %d\n", |
620 | __func__, error); | | 626 | __func__, error); |
621 | return 0; | | 627 | return 0; |
622 | } | | 628 | } |
623 | | | 629 | |
624 | if (sc->sc_model.dm_flags & DSRTC_FLAG_CLOCK_HOLD_REVERSED) | | 630 | if (sc->sc_model.dm_flags & DSRTC_FLAG_CLOCK_HOLD_REVERSED) |
625 | cmdbuf[1] &= ~dm->dm_ch_value; | | 631 | cmdbuf[1] &= ~dm->dm_ch_value; |
626 | else | | 632 | else |
627 | cmdbuf[1] |= dm->dm_ch_value; | | 633 | cmdbuf[1] |= dm->dm_ch_value; |
628 | | | 634 | |
629 | if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, | | 635 | if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, |
630 | cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) != 0) { | | 636 | cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) != 0) { |
631 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 637 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
632 | aprint_error_dev(sc->sc_dev, | | 638 | aprint_error_dev(sc->sc_dev, |
633 | "%s: failed to write Hold Clock: %d\n", | | 639 | "%s: failed to write Hold Clock: %d\n", |
634 | __func__, error); | | 640 | __func__, error); |
635 | return 0; | | 641 | return 0; |
636 | } | | 642 | } |
637 | | | 643 | |
638 | /* | | 644 | /* |
639 | * Write registers in reverse order. The last write (to the Seconds | | 645 | * Write registers in reverse order. The last write (to the Seconds |
640 | * register) will undo the Clock Hold, above. | | 646 | * register) will undo the Clock Hold, above. |
641 | */ | | 647 | */ |
642 | uint8_t op = I2C_OP_WRITE; | | 648 | uint8_t op = I2C_OP_WRITE; |
643 | for (signed int i = dm->dm_rtc_size - 1; i >= 0; i--) { | | 649 | for (signed int i = dm->dm_rtc_size - 1; i >= 0; i--) { |
644 | cmdbuf[0] = dm->dm_rtc_start + i; | | 650 | cmdbuf[0] = dm->dm_rtc_start + i; |
645 | if ((dm->dm_flags & DSRTC_FLAG_VBATEN) && | | 651 | if ((dm->dm_flags & DSRTC_FLAG_VBATEN) && |
646 | dm->dm_rtc_start + i == dm->dm_vbaten_reg) | | 652 | dm->dm_rtc_start + i == dm->dm_vbaten_reg) |
647 | bcd[i] |= dm->dm_vbaten_value; | | 653 | bcd[i] |= dm->dm_vbaten_value; |
648 | if (dm->dm_rtc_start + i == dm->dm_ch_reg) { | | 654 | if (dm->dm_rtc_start + i == dm->dm_ch_reg) { |
649 | op = I2C_OP_WRITE_WITH_STOP; | | 655 | op = I2C_OP_WRITE_WITH_STOP; |
650 | if (dm->dm_flags & DSRTC_FLAG_CLOCK_HOLD_REVERSED) | | 656 | if (dm->dm_flags & DSRTC_FLAG_CLOCK_HOLD_REVERSED) |
651 | bcd[i] |= dm->dm_ch_value; | | 657 | bcd[i] |= dm->dm_ch_value; |
652 | } | | 658 | } |
653 | if ((error = iic_exec(sc->sc_tag, op, sc->sc_address, | | 659 | if ((error = iic_exec(sc->sc_tag, op, sc->sc_address, |
654 | cmdbuf, 1, &bcd[i], 1, I2C_F_POLL)) != 0) { | | 660 | cmdbuf, 1, &bcd[i], 1, I2C_F_POLL)) != 0) { |
655 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 661 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
656 | aprint_error_dev(sc->sc_dev, | | 662 | aprint_error_dev(sc->sc_dev, |
657 | "%s: failed to write rtc at 0x%x: %d\n", | | 663 | "%s: failed to write rtc at 0x%x: %d\n", |
658 | __func__, i, error); | | 664 | __func__, i, error); |
659 | /* XXX: Clock Hold is likely still asserted! */ | | 665 | /* XXX: Clock Hold is likely still asserted! */ |
660 | return 0; | | 666 | return 0; |
661 | } | | 667 | } |
662 | } | | 668 | } |
663 | /* | | 669 | /* |
664 | * If the clock hold register isn't the same register as seconds, | | 670 | * If the clock hold register isn't the same register as seconds, |
665 | * we need to reeanble the clock. | | 671 | * we need to reeanble the clock. |
666 | */ | | 672 | */ |
667 | if (op != I2C_OP_WRITE_WITH_STOP) { | | 673 | if (op != I2C_OP_WRITE_WITH_STOP) { |
668 | cmdbuf[0] = dm->dm_ch_reg; | | 674 | cmdbuf[0] = dm->dm_ch_reg; |
669 | if (dm->dm_flags & DSRTC_FLAG_CLOCK_HOLD_REVERSED) | | 675 | if (dm->dm_flags & DSRTC_FLAG_CLOCK_HOLD_REVERSED) |
670 | cmdbuf[1] |= dm->dm_ch_value; | | 676 | cmdbuf[1] |= dm->dm_ch_value; |
671 | else | | 677 | else |
672 | cmdbuf[1] &= ~dm->dm_ch_value; | | 678 | cmdbuf[1] &= ~dm->dm_ch_value; |
673 | | | 679 | |
674 | if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, | | 680 | if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, |
675 | sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, | | 681 | sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, |
676 | I2C_F_POLL)) != 0) { | | 682 | I2C_F_POLL)) != 0) { |
677 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 683 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
678 | aprint_error_dev(sc->sc_dev, | | 684 | aprint_error_dev(sc->sc_dev, |
679 | "%s: failed to Hold Clock: %d\n", | | 685 | "%s: failed to Hold Clock: %d\n", |
680 | __func__, error); | | 686 | __func__, error); |
681 | return 0; | | 687 | return 0; |
682 | } | | 688 | } |
683 | } | | 689 | } |
684 | | | 690 | |
685 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 691 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
686 | | | 692 | |
687 | return 1; | | 693 | return 1; |
688 | } | | 694 | } |
689 | | | 695 | |
690 | static int | | 696 | static int |
691 | dsrtc_gettime_timeval(struct todr_chip_handle *ch, struct timeval *tv) | | 697 | dsrtc_gettime_timeval(struct todr_chip_handle *ch, struct timeval *tv) |
692 | { | | 698 | { |
693 | struct dsrtc_softc *sc = ch->cookie; | | 699 | struct dsrtc_softc *sc = ch->cookie; |
694 | struct timeval check; | | 700 | struct timeval check; |
695 | int retries; | | 701 | int retries; |
696 | | | 702 | |
697 | memset(tv, 0, sizeof(*tv)); | | 703 | memset(tv, 0, sizeof(*tv)); |
698 | memset(&check, 0, sizeof(check)); | | 704 | memset(&check, 0, sizeof(check)); |
699 | | | 705 | |
700 | /* | | 706 | /* |
701 | * Since we don't support Burst Read, we have to read the clock twice | | 707 | * Since we don't support Burst Read, we have to read the clock twice |
702 | * until we get two consecutive identical results. | | 708 | * until we get two consecutive identical results. |
703 | */ | | 709 | */ |
704 | retries = 5; | | 710 | retries = 5; |
705 | do { | | 711 | do { |
706 | dsrtc_clock_read_timeval(sc, &tv->tv_sec); | | 712 | dsrtc_clock_read_timeval(sc, &tv->tv_sec); |
707 | dsrtc_clock_read_timeval(sc, &check.tv_sec); | | 713 | dsrtc_clock_read_timeval(sc, &check.tv_sec); |
708 | } while (memcmp(tv, &check, sizeof(check)) != 0 && --retries); | | 714 | } while (memcmp(tv, &check, sizeof(check)) != 0 && --retries); |
709 | | | 715 | |
710 | return 0; | | 716 | return 0; |
711 | } | | 717 | } |
712 | | | 718 | |
713 | static int | | 719 | static int |
714 | dsrtc_settime_timeval(struct todr_chip_handle *ch, struct timeval *tv) | | 720 | dsrtc_settime_timeval(struct todr_chip_handle *ch, struct timeval *tv) |
715 | { | | 721 | { |
716 | struct dsrtc_softc *sc = ch->cookie; | | 722 | struct dsrtc_softc *sc = ch->cookie; |
717 | | | 723 | |
718 | if (dsrtc_clock_write_timeval(sc, tv->tv_sec) == 0) | | 724 | if (dsrtc_clock_write_timeval(sc, tv->tv_sec) == 0) |
719 | return -1; | | 725 | return -1; |
720 | | | 726 | |
721 | return 0; | | 727 | return 0; |
722 | } | | 728 | } |
723 | | | 729 | |
724 | /* | | 730 | /* |
725 | * The RTC probably has a nice Clock Burst Read/Write command, but we can't use | | 731 | * The RTC probably has a nice Clock Burst Read/Write command, but we can't use |
726 | * it, since some I2C controllers don't support anything other than single-byte | | 732 | * it, since some I2C controllers don't support anything other than single-byte |
727 | * transfers. | | 733 | * transfers. |
728 | */ | | 734 | */ |
729 | static int | | 735 | static int |
730 | dsrtc_clock_read_timeval(struct dsrtc_softc *sc, time_t *tp) | | 736 | dsrtc_clock_read_timeval(struct dsrtc_softc *sc, time_t *tp) |
731 | { | | 737 | { |
732 | const struct dsrtc_model * const dm = &sc->sc_model; | | 738 | const struct dsrtc_model * const dm = &sc->sc_model; |
733 | uint8_t buf[4]; | | 739 | uint8_t buf[4]; |
734 | int error; | | 740 | int error; |
735 | | | 741 | |
736 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { | | 742 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { |
737 | aprint_error_dev(sc->sc_dev, | | 743 | aprint_error_dev(sc->sc_dev, |
738 | "%s: failed to acquire I2C bus: %d\n", | | 744 | "%s: failed to acquire I2C bus: %d\n", |
739 | __func__, error); | | 745 | __func__, error); |
740 | return 0; | | 746 | return 0; |
741 | } | | 747 | } |
742 | | | 748 | |
743 | /* read all registers: */ | | 749 | /* read all registers: */ |
744 | uint8_t reg = dm->dm_rtc_start; | | 750 | uint8_t reg = dm->dm_rtc_start; |
745 | error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, | | 751 | error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, |
746 | ®, 1, buf, 4, I2C_F_POLL); | | 752 | ®, 1, buf, 4, I2C_F_POLL); |
747 | | | 753 | |
748 | /* Done with I2C */ | | 754 | /* Done with I2C */ |
749 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 755 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
750 | | | 756 | |
751 | if (error != 0) { | | 757 | if (error != 0) { |
752 | aprint_error_dev(sc->sc_dev, | | 758 | aprint_error_dev(sc->sc_dev, |
753 | "%s: failed to read rtc at 0x%x: %d\n", | | 759 | "%s: failed to read rtc at 0x%x: %d\n", |
754 | __func__, reg, error); | | 760 | __func__, reg, error); |
755 | return 0; | | 761 | return 0; |
756 | } | | 762 | } |
757 | | | 763 | |
758 | uint32_t v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | | 764 | uint32_t v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; |
759 | *tp = v; | | 765 | *tp = v; |
760 | | | 766 | |
761 | aprint_debug_dev(sc->sc_dev, "%s: cntr=0x%08"PRIx32"\n", | | 767 | aprint_debug_dev(sc->sc_dev, "%s: cntr=0x%08"PRIx32"\n", |
762 | __func__, v); | | 768 | __func__, v); |
763 | | | 769 | |
764 | return 1; | | 770 | return 1; |
765 | } | | 771 | } |
766 | | | 772 | |
767 | static int | | 773 | static int |
768 | dsrtc_clock_write_timeval(struct dsrtc_softc *sc, time_t t) | | 774 | dsrtc_clock_write_timeval(struct dsrtc_softc *sc, time_t t) |
769 | { | | 775 | { |
770 | const struct dsrtc_model * const dm = &sc->sc_model; | | 776 | const struct dsrtc_model * const dm = &sc->sc_model; |
771 | size_t buflen = dm->dm_rtc_size + 2; | | 777 | size_t buflen = dm->dm_rtc_size + 2; |
772 | uint8_t buf[buflen]; | | 778 | uint8_t buf[buflen]; |
773 | int error; | | 779 | int error; |
774 | | | 780 | |
775 | KASSERT((dm->dm_flags & DSRTC_FLAG_CLOCK_HOLD) == 0); | | 781 | KASSERT((dm->dm_flags & DSRTC_FLAG_CLOCK_HOLD) == 0); |
776 | KASSERT(dm->dm_ch_reg == dm->dm_rtc_start + 4); | | 782 | KASSERT(dm->dm_ch_reg == dm->dm_rtc_start + 4); |
777 | | | 783 | |
778 | buf[0] = dm->dm_rtc_start; | | 784 | buf[0] = dm->dm_rtc_start; |
779 | buf[1] = (t >> 0) & 0xff; | | 785 | buf[1] = (t >> 0) & 0xff; |
780 | buf[2] = (t >> 8) & 0xff; | | 786 | buf[2] = (t >> 8) & 0xff; |
781 | buf[3] = (t >> 16) & 0xff; | | 787 | buf[3] = (t >> 16) & 0xff; |
782 | buf[4] = (t >> 24) & 0xff; | | 788 | buf[4] = (t >> 24) & 0xff; |
783 | buf[5] = 0; | | 789 | buf[5] = 0; |
784 | | | 790 | |
785 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { | | 791 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { |
786 | aprint_error_dev(sc->sc_dev, | | 792 | aprint_error_dev(sc->sc_dev, |
787 | "%s: failed to acquire I2C bus: %d\n", | | 793 | "%s: failed to acquire I2C bus: %d\n", |
788 | __func__, error); | | 794 | __func__, error); |
789 | return 0; | | 795 | return 0; |
790 | } | | 796 | } |
791 | | | 797 | |
792 | error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, | | 798 | error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, |
793 | &buf, buflen, NULL, 0, I2C_F_POLL); | | 799 | &buf, buflen, NULL, 0, I2C_F_POLL); |
794 | | | 800 | |
795 | /* Done with I2C */ | | 801 | /* Done with I2C */ |
796 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 802 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
797 | | | 803 | |
798 | /* send data */ | | 804 | /* send data */ |
799 | if (error != 0) { | | 805 | if (error != 0) { |
800 | aprint_error_dev(sc->sc_dev, | | 806 | aprint_error_dev(sc->sc_dev, |
801 | "%s: failed to set time: %d\n", | | 807 | "%s: failed to set time: %d\n", |
802 | __func__, error); | | 808 | __func__, error); |
803 | return 0; | | 809 | return 0; |
804 | } | | 810 | } |
805 | | | 811 | |
806 | return 1; | | 812 | return 1; |
807 | } | | 813 | } |
808 | | | 814 | |
809 | static int | | 815 | static int |
810 | dsrtc_read_temp(struct dsrtc_softc *sc, uint32_t *temp) | | 816 | dsrtc_read_temp(struct dsrtc_softc *sc, uint32_t *temp) |
811 | { | | 817 | { |
812 | int error, tc; | | 818 | int error, tc; |
813 | uint8_t reg = DS3232_TEMP_MSB; | | 819 | uint8_t reg = DS3232_TEMP_MSB; |
814 | uint8_t buf[2]; | | 820 | uint8_t buf[2]; |
815 | | | 821 | |
816 | if ((sc->sc_model.dm_flags & DSRTC_FLAG_TEMP) == 0) | | 822 | if ((sc->sc_model.dm_flags & DSRTC_FLAG_TEMP) == 0) |
817 | return ENOTSUP; | | 823 | return ENOTSUP; |
818 | | | 824 | |
819 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { | | 825 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { |
820 | aprint_error_dev(sc->sc_dev, | | 826 | aprint_error_dev(sc->sc_dev, |
821 | "%s: failed to acquire I2C bus: %d\n", | | 827 | "%s: failed to acquire I2C bus: %d\n", |
822 | __func__, error); | | 828 | __func__, error); |
823 | return 0; | | 829 | return 0; |
824 | } | | 830 | } |
825 | | | 831 | |
826 | /* read temperature registers: */ | | 832 | /* read temperature registers: */ |
827 | error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, | | 833 | error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, |
828 | ®, 1, buf, 2, I2C_F_POLL); | | 834 | ®, 1, buf, 2, I2C_F_POLL); |
829 | | | 835 | |
830 | /* Done with I2C */ | | 836 | /* Done with I2C */ |
831 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 837 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
832 | | | 838 | |
833 | if (error != 0) { | | 839 | if (error != 0) { |
834 | aprint_error_dev(sc->sc_dev, | | 840 | aprint_error_dev(sc->sc_dev, |
835 | "%s: failed to read temperature: %d\n", | | 841 | "%s: failed to read temperature: %d\n", |
836 | __func__, error); | | 842 | __func__, error); |
837 | return 0; | | 843 | return 0; |
838 | } | | 844 | } |
839 | | | 845 | |
840 | /* convert to microkelvin */ | | 846 | /* convert to microkelvin */ |
841 | tc = buf[0] * 1000000 + (buf[1] >> 6) * 250000; | | 847 | tc = buf[0] * 1000000 + (buf[1] >> 6) * 250000; |
842 | *temp = tc + 273150000; | | 848 | *temp = tc + 273150000; |
843 | return 1; | | 849 | return 1; |
844 | } | | 850 | } |
845 | | | 851 | |
846 | static void | | 852 | static void |
847 | dsrtc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 853 | dsrtc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
848 | { | | 854 | { |
849 | struct dsrtc_softc *sc = sme->sme_cookie; | | 855 | struct dsrtc_softc *sc = sme->sme_cookie; |
850 | uint32_t temp = 0; /* XXX gcc */ | | 856 | uint32_t temp = 0; /* XXX gcc */ |
851 | | | 857 | |
852 | if (dsrtc_read_temp(sc, &temp) == 0) { | | 858 | if (dsrtc_read_temp(sc, &temp) == 0) { |
853 | edata->state = ENVSYS_SINVALID; | | 859 | edata->state = ENVSYS_SINVALID; |
854 | return; | | 860 | return; |
855 | } | | 861 | } |
856 | | | 862 | |
857 | edata->value_cur = temp; | | 863 | edata->value_cur = temp; |
858 | | | 864 | |
859 | edata->state = ENVSYS_SVALID; | | 865 | edata->state = ENVSYS_SVALID; |
860 | } | | 866 | } |