|
@@ -33,6 +33,7 @@
|
|
|
|
|
|
#define DS1337_CTL 0x0E
|
|
|
#define DS1337_STAT 0x0F
|
|
|
+#define DS1337_ALRM1 0x07
|
|
|
|
|
|
static int model_detected;
|
|
|
|
|
@@ -113,6 +114,20 @@ static int ds13307_start_oscillator(struct i2c_client *client) {
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
+/* Checks if the hour value is set to 12h format and checks if it
|
|
|
+ * was AM or PM, returns 0 if the value was not in 12h format
|
|
|
+ * or the value was AM so no conversion is necessary
|
|
|
+ */
|
|
|
+static int ds13307_check_12h_am_pm(u8 *byte) {
|
|
|
+ if (*byte & 0x40) {
|
|
|
+ (*byte) = *byte ^ 0x40;
|
|
|
+ if (*byte & 0x20) {
|
|
|
+ (*byte) = *byte ^ 0x20;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
static int ds13307_read_time(struct device *dev, struct rtc_time *time) {
|
|
|
struct i2c_client *client;
|
|
@@ -135,13 +150,7 @@ static int ds13307_read_time(struct device *dev, struct rtc_time *time) {
|
|
|
printk(KERN_ERR "%s: Oscillator stop bit is set, values read from rtc device cannot be trusted\n", M_NAME);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- if (buf[COMMON_HOUR] & 0x40) {
|
|
|
- buf[COMMON_HOUR] = buf[COMMON_HOUR] ^ 0x40;
|
|
|
- if (buf[COMMON_HOUR] & 0x20) {
|
|
|
- buf[COMMON_HOUR] = buf[COMMON_HOUR] ^ 0x20;
|
|
|
- h12 = 1;
|
|
|
- }
|
|
|
- }
|
|
|
+ h12 = ds13307_check_12h_am_pm(&buf[COMMON_HOUR]);
|
|
|
if (model_detected == DEVICE_DS1337) {
|
|
|
century = buf[COMMON_MONTH] & COMMON_HIGH_BIT;
|
|
|
buf[COMMON_MONTH] = buf[COMMON_MONTH] & 0x7F;
|
|
@@ -194,7 +203,42 @@ static int ds13307_set_time(struct device *dev, struct rtc_time *time) {
|
|
|
|
|
|
}
|
|
|
|
|
|
-static const struct rtc_class_ops ds13307_rtc_ops = {
|
|
|
+static int ds13307_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) {
|
|
|
+ struct i2c_client *client;
|
|
|
+ u8 buf[5], ctl[2], addr = DS1337_CTL;
|
|
|
+ int h12;
|
|
|
+ client = to_i2c_client(dev);
|
|
|
+ if(ds13307_read_bytes(client, &addr, ctl, 2)) {
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ // select for A1IE bit
|
|
|
+ alarm->enabled = ctl[0] & 0x01;
|
|
|
+ // select for A1F bit
|
|
|
+ alarm->pending = ctl[1] & 0x01;
|
|
|
+
|
|
|
+ addr = DS1337_ALRM1;
|
|
|
+ if (!ds13307_read_bytes(client, &addr, buf, 4)) {
|
|
|
+ alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
|
|
|
+ alarm->time.tm_min = bcd2bin(buf[1] & 0x7F);
|
|
|
+ h12 = ds13307_check_12h_am_pm(&buf[2]);
|
|
|
+ alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
|
|
|
+ if(h12) {
|
|
|
+ alarm->time.tm_hour += 12;
|
|
|
+ }
|
|
|
+ /* if bit is set to 1, it matches the day of the week,
|
|
|
+ * otherwise the day of the month.
|
|
|
+ */
|
|
|
+ if (buf[3] & 0x40) {
|
|
|
+ alarm->time.tm_wday = bcd2bin(buf[3] & 0x3F);
|
|
|
+ } else {
|
|
|
+ alarm->time.tm_mday = bcd2bin(buf[3] & 0x3F);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return -EIO;
|
|
|
+}
|
|
|
+
|
|
|
+static struct rtc_class_ops ds13307_rtc_ops = {
|
|
|
.read_time = ds13307_read_time,
|
|
|
.set_time = ds13307_set_time
|
|
|
};
|
|
@@ -260,6 +304,8 @@ static int ds13307_probe(struct i2c_client *client,
|
|
|
ds1307_nvmem.reg_write = ds13307_nvram_write;
|
|
|
ds1307_nvmem.priv = client;
|
|
|
rtc->nvmem_config = &ds1307_nvmem;
|
|
|
+ } else {
|
|
|
+ ds13307_rtc_ops.read_alarm = ds13307_read_alarm;
|
|
|
}
|
|
|
rtc->ops = &ds13307_rtc_ops;
|
|
|
i2c_set_clientdata(client,rtc);
|