|
@@ -12,6 +12,7 @@
|
|
|
#include <linux/rtc.h>
|
|
|
#include <linux/i2c.h>
|
|
|
#include <linux/bcd.h>
|
|
|
+#include <linux/slab.h>
|
|
|
|
|
|
#define M_NAME "rtc-ds13307" /* Module name */
|
|
|
|
|
@@ -63,12 +64,37 @@ static int ds13307_read_bytes(struct i2c_client *client,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* Writes a specified number of bytes via 2ic, returns 0 on success */
|
|
|
+static int ds13307_write_bytes(struct i2c_client *client,
|
|
|
+ u8 *addr, u8 *bytes, int length) {
|
|
|
+ int r;
|
|
|
+ u8 *buf;
|
|
|
+ struct i2c_msg msg;
|
|
|
+ buf = (u8*) kmalloc(length +1, GFP_KERNEL);
|
|
|
+ if (buf == NULL) {
|
|
|
+ printk(KERN_ERR "%s: Could not allocate memory for buffer\n", M_NAME);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ buf[0] = (*addr);
|
|
|
+ memmove(buf + 1, bytes, length);
|
|
|
+ msg.addr = client->addr;
|
|
|
+ msg.len = length + 1;
|
|
|
+ msg.buf = addr;
|
|
|
+ r = i2c_transfer(client->adapter, &msg, 1);
|
|
|
+ kfree(buf);
|
|
|
+ if (r == 1) {
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* The oscillator is stopped for both chips when power is first applied,
|
|
|
* therefore this function checks its status and clears the stop bit.
|
|
|
*/
|
|
|
static int ds13307_start_oscillator(struct i2c_client *client) {
|
|
|
- u8 data, addr, buf[2];
|
|
|
- int r, v;
|
|
|
+ u8 data, addr, buf;
|
|
|
+ int r, v = 0;
|
|
|
if (model_detected == DEVICE_DS1307) {
|
|
|
addr = COMMON_SEC;
|
|
|
} else {
|
|
@@ -76,16 +102,13 @@ static int ds13307_start_oscillator(struct i2c_client *client) {
|
|
|
}
|
|
|
r = ds13307_read_bytes(client, &addr, &data, 1);
|
|
|
if (data & COMMON_HIGH_BIT) {
|
|
|
- buf[0] = addr;
|
|
|
- buf[1] = data ^ COMMON_HIGH_BIT;
|
|
|
- v = i2c_master_send(client, buf, 2);
|
|
|
- if (v == 2) {
|
|
|
+ buf = data ^ COMMON_HIGH_BIT;
|
|
|
+ v = ds13307_write_bytes(client, &addr, &buf, 1);
|
|
|
+ if (!v) {
|
|
|
printk(KERN_DEBUG "%s: oscillator stop bit successfully cleared\n", M_NAME);
|
|
|
}
|
|
|
- } else {
|
|
|
- v = 2;
|
|
|
}
|
|
|
- if ((r<0) || (v!=2)) {
|
|
|
+ if ((r<0) || (v)) {
|
|
|
return -EIO;
|
|
|
}
|
|
|
return 0;
|
|
@@ -143,28 +166,28 @@ static int ds13307_read_time(struct device *dev, struct rtc_time *time) {
|
|
|
|
|
|
static int ds13307_set_time(struct device *dev, struct rtc_time *time) {
|
|
|
struct i2c_client *client;
|
|
|
- u8 buf[8];
|
|
|
+ u8 buf[7], addr;
|
|
|
client = to_i2c_client(dev);
|
|
|
if (ds13307_start_oscillator(client)) {
|
|
|
printk(KERN_ERR "%s: failed to initialize the oscillator\n", M_NAME);
|
|
|
return -EIO;
|
|
|
}
|
|
|
- buf[0] = COMMON_SEC;
|
|
|
- buf[1] = bin2bcd(time->tm_sec);
|
|
|
- buf[2] = bin2bcd(time->tm_min);
|
|
|
- buf[3] = bin2bcd(time->tm_hour);
|
|
|
- buf[4] = bin2bcd(time->tm_wday);
|
|
|
- buf[5] = bin2bcd(time->tm_mday);
|
|
|
+ addr = COMMON_SEC;
|
|
|
+ buf[0] = bin2bcd(time->tm_sec);
|
|
|
+ buf[1] = bin2bcd(time->tm_min);
|
|
|
+ buf[2] = bin2bcd(time->tm_hour);
|
|
|
+ buf[3] = bin2bcd(time->tm_wday);
|
|
|
+ buf[4] = bin2bcd(time->tm_mday);
|
|
|
if ((model_detected == DEVICE_DS1337) && (time->tm_year >= 100)) {
|
|
|
- buf[6] = bin2bcd(time->tm_mon + 1) | COMMON_HIGH_BIT;
|
|
|
+ buf[5] = bin2bcd(time->tm_mon + 1) | COMMON_HIGH_BIT;
|
|
|
} else if ((model_detected == DEVICE_DS1307) && (time->tm_year < 100)) {
|
|
|
printk(KERN_ERR "%s: device does not support century information, dates before 2000 are not possible\n", M_NAME);
|
|
|
return -EINVAL;
|
|
|
} else {
|
|
|
- buf[6] = bin2bcd(time->tm_mon + 1);
|
|
|
+ buf[5] = bin2bcd(time->tm_mon + 1);
|
|
|
}
|
|
|
- buf[7] = bin2bcd(time->tm_year % 100);
|
|
|
- if (i2c_master_send(client, buf, 8) != 8) {
|
|
|
+ buf[6] = bin2bcd(time->tm_year % 100);
|
|
|
+ if(ds13307_write_bytes(client, &addr, buf, 7)) {
|
|
|
return -EIO;
|
|
|
}
|
|
|
return 0;
|