| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ds1307.c,v 1.18 2014/07/25 08:10:37 dholland Exp $ */ | | 1 | /* $NetBSD: ds1307.c,v 1.18.2.1 2015/04/14 04:24:58 snj 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 |
| @@ -26,92 +26,106 @@ | | | @@ -26,92 +26,106 @@ |
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.18 2014/07/25 08:10:37 dholland Exp $"); | | 39 | __KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1.18.2.1 2015/04/14 04:24:58 snj 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 | | | 55 | |
55 | struct dsrtc_model { | | 56 | struct dsrtc_model { |
56 | uint16_t dm_model; | | 57 | uint16_t dm_model; |
57 | uint8_t dm_ch_reg; | | 58 | uint8_t dm_ch_reg; |
58 | uint8_t dm_ch_value; | | 59 | uint8_t dm_ch_value; |
59 | uint8_t dm_rtc_start; | | 60 | uint8_t dm_rtc_start; |
60 | uint8_t dm_rtc_size; | | 61 | uint8_t dm_rtc_size; |
61 | uint8_t dm_nvram_start; | | 62 | uint8_t dm_nvram_start; |
62 | uint8_t dm_nvram_size; | | 63 | uint8_t dm_nvram_size; |
63 | uint8_t dm_flags; | | 64 | uint8_t dm_flags; |
64 | #define DSRTC_FLAG_CLOCK_HOLD 1 | | 65 | #define DSRTC_FLAG_CLOCK_HOLD 1 |
65 | #define DSRTC_FLAG_BCD 2 | | 66 | #define DSRTC_FLAG_BCD 2 |
| | | 67 | #define DSRTC_FLAG_TEMP 4 |
66 | }; | | 68 | }; |
67 | | | 69 | |
68 | static const struct dsrtc_model dsrtc_models[] = { | | 70 | static const struct dsrtc_model dsrtc_models[] = { |
69 | { | | 71 | { |
70 | .dm_model = 1307, | | 72 | .dm_model = 1307, |
71 | .dm_ch_reg = DSXXXX_SECONDS, | | 73 | .dm_ch_reg = DSXXXX_SECONDS, |
72 | .dm_ch_value = DS1307_SECONDS_CH, | | 74 | .dm_ch_value = DS1307_SECONDS_CH, |
73 | .dm_rtc_start = DS1307_RTC_START, | | 75 | .dm_rtc_start = DS1307_RTC_START, |
74 | .dm_rtc_size = DS1307_RTC_SIZE, | | 76 | .dm_rtc_size = DS1307_RTC_SIZE, |
75 | .dm_nvram_start = DS1307_NVRAM_START, | | 77 | .dm_nvram_start = DS1307_NVRAM_START, |
76 | .dm_nvram_size = DS1307_NVRAM_SIZE, | | 78 | .dm_nvram_size = DS1307_NVRAM_SIZE, |
77 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD, | | 79 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD, |
78 | }, { | | 80 | }, { |
79 | .dm_model = 1339, | | 81 | .dm_model = 1339, |
80 | .dm_rtc_start = DS1339_RTC_START, | | 82 | .dm_rtc_start = DS1339_RTC_START, |
81 | .dm_rtc_size = DS1339_RTC_SIZE, | | 83 | .dm_rtc_size = DS1339_RTC_SIZE, |
82 | .dm_flags = DSRTC_FLAG_BCD, | | 84 | .dm_flags = DSRTC_FLAG_BCD, |
83 | }, { | | 85 | }, { |
84 | .dm_model = 1672, | | 86 | .dm_model = 1672, |
85 | .dm_rtc_start = DS1672_RTC_START, | | 87 | .dm_rtc_start = DS1672_RTC_START, |
86 | .dm_rtc_size = DS1672_RTC_SIZE, | | 88 | .dm_rtc_size = DS1672_RTC_SIZE, |
87 | .dm_flags = 0, | | 89 | .dm_flags = 0, |
88 | }, { | | 90 | }, { |
| | | 91 | .dm_model = 3231, |
| | | 92 | .dm_rtc_start = DS3232_RTC_START, |
| | | 93 | .dm_rtc_size = DS3232_RTC_SIZE, |
| | | 94 | /* |
| | | 95 | * XXX |
| | | 96 | * the DS3232 likely has the temperature sensor too but I can't |
| | | 97 | * easily verify or test that right now |
| | | 98 | */ |
| | | 99 | .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_TEMP, |
| | | 100 | }, { |
89 | .dm_model = 3232, | | 101 | .dm_model = 3232, |
90 | .dm_rtc_start = DS3232_RTC_START, | | 102 | .dm_rtc_start = DS3232_RTC_START, |
91 | .dm_rtc_size = DS3232_RTC_SIZE, | | 103 | .dm_rtc_size = DS3232_RTC_SIZE, |
92 | .dm_nvram_start = DS3232_NVRAM_START, | | 104 | .dm_nvram_start = DS3232_NVRAM_START, |
93 | .dm_nvram_size = DS3232_NVRAM_SIZE, | | 105 | .dm_nvram_size = DS3232_NVRAM_SIZE, |
94 | .dm_flags = DSRTC_FLAG_BCD, | | 106 | .dm_flags = DSRTC_FLAG_BCD, |
95 | }, | | 107 | }, |
96 | }; | | 108 | }; |
97 | | | 109 | |
98 | struct dsrtc_softc { | | 110 | struct dsrtc_softc { |
99 | device_t sc_dev; | | 111 | device_t sc_dev; |
100 | i2c_tag_t sc_tag; | | 112 | i2c_tag_t sc_tag; |
101 | uint8_t sc_address; | | 113 | uint8_t sc_address; |
102 | bool sc_open; | | 114 | bool sc_open; |
103 | struct dsrtc_model sc_model; | | 115 | struct dsrtc_model sc_model; |
104 | struct todr_chip_handle sc_todr; | | 116 | struct todr_chip_handle sc_todr; |
| | | 117 | struct sysmon_envsys *sc_sme; |
| | | 118 | envsys_data_t sc_sensor; |
105 | }; | | 119 | }; |
106 | | | 120 | |
107 | static void dsrtc_attach(device_t, device_t, void *); | | 121 | static void dsrtc_attach(device_t, device_t, void *); |
108 | static int dsrtc_match(device_t, cfdata_t, void *); | | 122 | static int dsrtc_match(device_t, cfdata_t, void *); |
109 | | | 123 | |
110 | CFATTACH_DECL_NEW(dsrtc, sizeof(struct dsrtc_softc), | | 124 | CFATTACH_DECL_NEW(dsrtc, sizeof(struct dsrtc_softc), |
111 | dsrtc_match, dsrtc_attach, NULL, NULL); | | 125 | dsrtc_match, dsrtc_attach, NULL, NULL); |
112 | extern struct cfdriver dsrtc_cd; | | 126 | extern struct cfdriver dsrtc_cd; |
113 | | | 127 | |
114 | dev_type_open(dsrtc_open); | | 128 | dev_type_open(dsrtc_open); |
115 | dev_type_close(dsrtc_close); | | 129 | dev_type_close(dsrtc_close); |
116 | dev_type_read(dsrtc_read); | | 130 | dev_type_read(dsrtc_read); |
117 | dev_type_write(dsrtc_write); | | 131 | dev_type_write(dsrtc_write); |
| @@ -131,26 +145,29 @@ const struct cdevsw dsrtc_cdevsw = { | | | @@ -131,26 +145,29 @@ const struct cdevsw dsrtc_cdevsw = { |
131 | .d_flag = D_OTHER | | 145 | .d_flag = D_OTHER |
132 | }; | | 146 | }; |
133 | | | 147 | |
134 | static int dsrtc_gettime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); | | 148 | static int dsrtc_gettime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); |
135 | static int dsrtc_settime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); | | 149 | static int dsrtc_settime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *); |
136 | static int dsrtc_clock_read_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); | | 150 | static int dsrtc_clock_read_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); |
137 | static int dsrtc_clock_write_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); | | 151 | static int dsrtc_clock_write_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *); |
138 | | | 152 | |
139 | static int dsrtc_gettime_timeval(struct todr_chip_handle *, struct timeval *); | | 153 | static int dsrtc_gettime_timeval(struct todr_chip_handle *, struct timeval *); |
140 | static int dsrtc_settime_timeval(struct todr_chip_handle *, struct timeval *); | | 154 | static int dsrtc_settime_timeval(struct todr_chip_handle *, struct timeval *); |
141 | static int dsrtc_clock_read_timeval(struct dsrtc_softc *, time_t *); | | 155 | static int dsrtc_clock_read_timeval(struct dsrtc_softc *, time_t *); |
142 | static int dsrtc_clock_write_timeval(struct dsrtc_softc *, time_t); | | 156 | static int dsrtc_clock_write_timeval(struct dsrtc_softc *, time_t); |
143 | | | 157 | |
| | | 158 | static int dsrtc_read_temp(struct dsrtc_softc *, uint32_t *); |
| | | 159 | static void dsrtc_refresh(struct sysmon_envsys *, envsys_data_t *); |
| | | 160 | |
144 | static const struct dsrtc_model * | | 161 | static const struct dsrtc_model * |
145 | dsrtc_model(u_int model) | | 162 | dsrtc_model(u_int model) |
146 | { | | 163 | { |
147 | /* no model given, assume it's a DS1307 (the first one) */ | | 164 | /* no model given, assume it's a DS1307 (the first one) */ |
148 | if (model == 0) | | 165 | if (model == 0) |
149 | return &dsrtc_models[0]; | | 166 | return &dsrtc_models[0]; |
150 | | | 167 | |
151 | for (const struct dsrtc_model *dm = dsrtc_models; | | 168 | for (const struct dsrtc_model *dm = dsrtc_models; |
152 | dm < dsrtc_models + __arraycount(dsrtc_models); dm++) { | | 169 | dm < dsrtc_models + __arraycount(dsrtc_models); dm++) { |
153 | if (dm->dm_model == model) | | 170 | if (dm->dm_model == model) |
154 | return dm; | | 171 | return dm; |
155 | } | | 172 | } |
156 | return NULL; | | 173 | return NULL; |
| @@ -192,26 +209,55 @@ dsrtc_attach(device_t parent, device_t s | | | @@ -192,26 +209,55 @@ dsrtc_attach(device_t parent, device_t s |
192 | sc->sc_dev = self; | | 209 | sc->sc_dev = self; |
193 | sc->sc_open = 0; | | 210 | sc->sc_open = 0; |
194 | sc->sc_todr.cookie = sc; | | 211 | sc->sc_todr.cookie = sc; |
195 | if (dm->dm_flags & DSRTC_FLAG_BCD) { | | 212 | if (dm->dm_flags & DSRTC_FLAG_BCD) { |
196 | sc->sc_todr.todr_gettime_ymdhms = dsrtc_gettime_ymdhms; | | 213 | sc->sc_todr.todr_gettime_ymdhms = dsrtc_gettime_ymdhms; |
197 | sc->sc_todr.todr_settime_ymdhms = dsrtc_settime_ymdhms; | | 214 | sc->sc_todr.todr_settime_ymdhms = dsrtc_settime_ymdhms; |
198 | } else { | | 215 | } else { |
199 | sc->sc_todr.todr_gettime = dsrtc_gettime_timeval; | | 216 | sc->sc_todr.todr_gettime = dsrtc_gettime_timeval; |
200 | sc->sc_todr.todr_settime = dsrtc_settime_timeval; | | 217 | sc->sc_todr.todr_settime = dsrtc_settime_timeval; |
201 | } | | 218 | } |
202 | sc->sc_todr.todr_setwen = NULL; | | 219 | sc->sc_todr.todr_setwen = NULL; |
203 | | | 220 | |
204 | todr_attach(&sc->sc_todr); | | 221 | todr_attach(&sc->sc_todr); |
| | | 222 | if ((sc->sc_model.dm_flags & DSRTC_FLAG_TEMP) != 0) { |
| | | 223 | int error; |
| | | 224 | |
| | | 225 | sc->sc_sme = sysmon_envsys_create(); |
| | | 226 | sc->sc_sme->sme_name = device_xname(self); |
| | | 227 | sc->sc_sme->sme_cookie = sc; |
| | | 228 | sc->sc_sme->sme_refresh = dsrtc_refresh; |
| | | 229 | |
| | | 230 | sc->sc_sensor.units = ENVSYS_STEMP; |
| | | 231 | sc->sc_sensor.state = ENVSYS_SINVALID; |
| | | 232 | sc->sc_sensor.flags = 0; |
| | | 233 | (void)strlcpy(sc->sc_sensor.desc, "temperature", |
| | | 234 | sizeof(sc->sc_sensor.desc)); |
| | | 235 | |
| | | 236 | if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { |
| | | 237 | aprint_error_dev(self, "unable to attach sensor\n"); |
| | | 238 | goto bad; |
| | | 239 | } |
| | | 240 | |
| | | 241 | error = sysmon_envsys_register(sc->sc_sme); |
| | | 242 | if (error) { |
| | | 243 | aprint_error_dev(self, |
| | | 244 | "error %d registering with sysmon\n", error); |
| | | 245 | goto bad; |
| | | 246 | } |
| | | 247 | } |
| | | 248 | return; |
| | | 249 | bad: |
| | | 250 | sysmon_envsys_destroy(sc->sc_sme); |
205 | } | | 251 | } |
206 | | | 252 | |
207 | /*ARGSUSED*/ | | 253 | /*ARGSUSED*/ |
208 | int | | 254 | int |
209 | dsrtc_open(dev_t dev, int flag, int fmt, struct lwp *l) | | 255 | dsrtc_open(dev_t dev, int flag, int fmt, struct lwp *l) |
210 | { | | 256 | { |
211 | struct dsrtc_softc *sc; | | 257 | struct dsrtc_softc *sc; |
212 | | | 258 | |
213 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) | | 259 | if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL) |
214 | return ENXIO; | | 260 | return ENXIO; |
215 | | | 261 | |
216 | /* XXX: Locking */ | | 262 | /* XXX: Locking */ |
217 | if (sc->sc_open) | | 263 | if (sc->sc_open) |
| @@ -614,13 +660,66 @@ dsrtc_clock_write_timeval(struct dsrtc_s | | | @@ -614,13 +660,66 @@ dsrtc_clock_write_timeval(struct dsrtc_s |
614 | /* Done with I2C */ | | 660 | /* Done with I2C */ |
615 | iic_release_bus(sc->sc_tag, I2C_F_POLL); | | 661 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
616 | | | 662 | |
617 | /* send data */ | | 663 | /* send data */ |
618 | if (error != 0) { | | 664 | if (error != 0) { |
619 | aprint_error_dev(sc->sc_dev, | | 665 | aprint_error_dev(sc->sc_dev, |
620 | "%s: failed to set time: %d\n", | | 666 | "%s: failed to set time: %d\n", |
621 | __func__, error); | | 667 | __func__, error); |
622 | return 0; | | 668 | return 0; |
623 | } | | 669 | } |
624 | | | 670 | |
625 | return 1; | | 671 | return 1; |
626 | } | | 672 | } |
| | | 673 | |
| | | 674 | static int |
| | | 675 | dsrtc_read_temp(struct dsrtc_softc *sc, uint32_t *temp) |
| | | 676 | { |
| | | 677 | int error, tc; |
| | | 678 | uint8_t reg = DS3232_TEMP_MSB; |
| | | 679 | uint8_t buf[2]; |
| | | 680 | |
| | | 681 | if ((sc->sc_model.dm_flags & DSRTC_FLAG_TEMP) == 0) |
| | | 682 | return ENOTSUP; |
| | | 683 | |
| | | 684 | if ((error = iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) != 0) { |
| | | 685 | aprint_error_dev(sc->sc_dev, |
| | | 686 | "%s: failed to acquire I2C bus: %d\n", |
| | | 687 | __func__, error); |
| | | 688 | return 0; |
| | | 689 | } |
| | | 690 | |
| | | 691 | /* read temperature registers: */ |
| | | 692 | error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, |
| | | 693 | ®, 1, buf, 2, I2C_F_POLL); |
| | | 694 | |
| | | 695 | /* Done with I2C */ |
| | | 696 | iic_release_bus(sc->sc_tag, I2C_F_POLL); |
| | | 697 | |
| | | 698 | if (error != 0) { |
| | | 699 | aprint_error_dev(sc->sc_dev, |
| | | 700 | "%s: failed to read temperature: %d\n", |
| | | 701 | __func__, error); |
| | | 702 | return 0; |
| | | 703 | } |
| | | 704 | |
| | | 705 | /* convert to microkelvin */ |
| | | 706 | tc = buf[0] * 1000000 + (buf[1] >> 6) * 250000; |
| | | 707 | *temp = tc + 273150000; |
| | | 708 | return 1; |
| | | 709 | } |
| | | 710 | |
| | | 711 | static void |
| | | 712 | dsrtc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
| | | 713 | { |
| | | 714 | struct dsrtc_softc *sc = sme->sme_cookie; |
| | | 715 | uint32_t temp = 0; /* XXX gcc */ |
| | | 716 | |
| | | 717 | if (dsrtc_read_temp(sc, &temp) == 0) { |
| | | 718 | edata->state = ENVSYS_SINVALID; |
| | | 719 | return; |
| | | 720 | } |
| | | 721 | |
| | | 722 | edata->value_cur = temp; |
| | | 723 | |
| | | 724 | edata->state = ENVSYS_SVALID; |
| | | 725 | } |