|
@@ -9,16 +9,103 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#include <linux/module.h>
|
|
#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");
|
|
MODULE_LICENSE("GPL");
|