Browse Source

add i2c probe function with device detection support

Helmut Pozimski 5 years ago
parent
commit
319e80c65e
1 changed files with 93 additions and 6 deletions
  1. 93 6
      rtc-ds13307.c

+ 93 - 6
rtc-ds13307.c

@@ -9,16 +9,103 @@
  */
 
 #include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/i2c.h>
 
-#define RTCDS13307 "rtc-ds13307" /* Module name */
+#define M_NAME "rtc-ds13307" /* Module name */
 
-static int __init ds13307_init(void) {
-	return 0;
+#define DEVICE_DS1307 1
+#define DEVICE_DS1337 2
+
+#define DS1307_MAX_ADDR 0x3F
+
+#define DS1337_CTL 0x0E
+
+static int model_detected;
+
+static const struct rtc_class_ops ds13307_rtc_ops = {
+};
+
+/* Reads a single byte via i2c, returns 0 on success */
+static int ds13307_read_single_byte(struct i2c_client *client,
+		unsigned char *addr, u8 *byte) {
+	int r;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.len = 1,
+			.buf = addr
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = 1,
+			.buf = byte
+		}
+	};
+	r = i2c_transfer(client->adapter, msgs, 2);
+	if (r == 2) {
+		return 0;
+	} else {
+		return r;
+	}
+}
+
+/* Performs the device detection to distinguish between the
+ * DS1307 and DS1337 chips. Returns the defined device ID or
+ * -1 on failure
+ */
+static int ds13307_detect_device(struct i2c_client *client) {
+	u8 data;
+	int result;
+	unsigned char addr = DS1307_MAX_ADDR;
+	result = ds13307_read_single_byte(client, &addr, &data);
+	if (!result) {
+		printk(KERN_INFO "%s: Detected device DS1307\n", M_NAME);
+		return DEVICE_DS1307;
+	}
+        addr = DS1337_CTL;
+	result = ds13307_read_single_byte(client, &addr, &data);
+	if (!result) {	
+		printk(KERN_INFO "%s: Detected device DS1337\n", M_NAME);
+ 		return DEVICE_DS1337;
+	}
+	printk(KERN_ERR "%s: Could not talk to I2C device at addr %x, is it connected?\n",
+			M_NAME, client->addr);
+	return -1;
 }
 
-static void __exit ds13307_exit(void) {
+static int ds13307_probe(struct i2c_client *client,
+		const struct i2c_device_id *id) {
+	model_detected = ds13307_detect_device(client);
+	if ((model_detected != DEVICE_DS1307) && (model_detected != DEVICE_DS1337)) {
+		return -EIO;
+	}
+	return 0;
 }
 
-module_init(ds13307_init);
-module_exit(ds13307_exit);
+static struct i2c_device_id ds13307_idtable[] = {
+	{ "ds1307", 0 }, {}
+};
+MODULE_DEVICE_TABLE(i2c, ds13307_idtable);
+
+static struct of_device_id ds13307_of_match[] = {
+	{ .compatible = "dallas,ds1307" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ds13307_of_match);
+
+static struct i2c_driver ds13307_driver = {
+	.driver = {
+		.name = "rtc-ds13307",
+		.of_match_table = of_match_ptr(ds13307_of_match),
+	},
+	.id_table = ds13307_idtable,
+	.probe = ds13307_probe,
+};
+
+module_i2c_driver(ds13307_driver);
+
+MODULE_AUTHOR("Helmut Pozimski <helmut@pozimski.eu>");
+MODULE_DESCRIPTION("DS1307 and DS1337 RTC driver");
 MODULE_LICENSE("GPL");