]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/rtc/rtc-ds1307.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[karo-tx-linux.git] / drivers / rtc / rtc-ds1307.c
index ecb7dbae9be9daa0ee96ede34a446a78e8e7debd..8e1c5cb6ece6f60619e5cafcea4271e056d96778 100644 (file)
@@ -275,9 +275,13 @@ static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
 {
        u8 suboffset = 0;
 
-       if (length <= I2C_SMBUS_BLOCK_MAX)
-               return i2c_smbus_write_i2c_block_data(client,
+       if (length <= I2C_SMBUS_BLOCK_MAX) {
+               s32 retval = i2c_smbus_write_i2c_block_data(client,
                                        command, length, values);
+               if (retval < 0)
+                       return retval;
+               return length;
+       }
 
        while (suboffset < length) {
                s32 retval = i2c_smbus_write_i2c_block_data(client,
@@ -478,11 +482,6 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
        t->time.tm_min = bcd2bin(ds1307->regs[1] & 0x7f);
        t->time.tm_hour = bcd2bin(ds1307->regs[2] & 0x3f);
        t->time.tm_mday = bcd2bin(ds1307->regs[3] & 0x3f);
-       t->time.tm_mon = -1;
-       t->time.tm_year = -1;
-       t->time.tm_wday = -1;
-       t->time.tm_yday = -1;
-       t->time.tm_isdst = -1;
 
        /* ... and status */
        t->enabled = !!(ds1307->regs[7] & DS1337_BIT_A1IE);
@@ -538,12 +537,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        buf[5] = 0;
        buf[6] = 0;
 
-       /* optionally enable ALARM1 */
+       /* disable alarms */
        buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
-       if (t->enabled) {
-               dev_dbg(dev, "alarm IRQ armed\n");
-               buf[7] |= DS1337_BIT_A1IE;      /* only ALARM1 is used */
-       }
        buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
 
        ret = ds1307->write_block_data(client,
@@ -553,6 +548,13 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                return ret;
        }
 
+       /* optionally enable ALARM1 */
+       if (t->enabled) {
+               dev_dbg(dev, "alarm IRQ armed\n");
+               buf[7] |= DS1337_BIT_A1IE;      /* only ALARM1 is used */
+               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, buf[7]);
+       }
+
        return 0;
 }
 
@@ -595,6 +597,8 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
  * Alarm support for mcp794xx devices.
  */
 
+#define MCP794XX_REG_WEEKDAY           0x3
+#define MCP794XX_REG_WEEKDAY_WDAY_MASK 0x7
 #define MCP794XX_REG_CONTROL           0x07
 #      define MCP794XX_BIT_ALM0_EN     0x10
 #      define MCP794XX_BIT_ALM1_EN     0x20
@@ -1144,12 +1148,10 @@ static struct clk_init_data ds3231_clks_init[] = {
        [DS3231_CLK_SQW] = {
                .name = "ds3231_clk_sqw",
                .ops = &ds3231_clk_sqw_ops,
-               .flags = CLK_IS_ROOT,
        },
        [DS3231_CLK_32KHZ] = {
                .name = "ds3231_clk_32khz",
                .ops = &ds3231_clk_32khz_ops,
-               .flags = CLK_IS_ROOT,
        },
 };
 
@@ -1226,13 +1228,16 @@ static int ds1307_probe(struct i2c_client *client,
 {
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
-       int                     tmp;
+       int                     tmp, wday;
        struct chip_desc        *chip = &chips[id->driver_data];
        struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
        bool                    want_irq = false;
        bool                    ds1307_can_wakeup_device = false;
        unsigned char           *buf;
        struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct rtc_time         tm;
+       unsigned long           timestamp;
+
        irq_handler_t   irq_handler = ds1307_irq;
 
        static const int        bbsqi_bitpos[] = {
@@ -1521,6 +1526,27 @@ read_rtc:
                                bin2bcd(tmp));
        }
 
+       /*
+        * Some IPs have weekday reset value = 0x1 which might not correct
+        * hence compute the wday using the current date/month/year values
+        */
+       ds1307_get_time(&client->dev, &tm);
+       wday = tm.tm_wday;
+       timestamp = rtc_tm_to_time64(&tm);
+       rtc_time64_to_tm(timestamp, &tm);
+
+       /*
+        * Check if reset wday is different from the computed wday
+        * If different then set the wday which we computed using
+        * timestamp
+        */
+       if (wday != tm.tm_wday) {
+               wday = i2c_smbus_read_byte_data(client, MCP794XX_REG_WEEKDAY);
+               wday = wday & ~MCP794XX_REG_WEEKDAY_WDAY_MASK;
+               wday = wday | (tm.tm_wday + 1);
+               i2c_smbus_write_byte_data(client, MCP794XX_REG_WEEKDAY, wday);
+       }
+
        if (want_irq) {
                device_set_wakeup_capable(&client->dev, true);
                set_bit(HAS_ALARM, &ds1307->flags);