Browse Source

implement reading of the alarm registers for DS1337

Helmut Pozimski 5 years ago
parent
commit
47e8d95c41
1 changed files with 54 additions and 8 deletions
  1. 54 8
      rtc-ds13307.c

+ 54 - 8
rtc-ds13307.c

@@ -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);