aboutsummaryrefslogtreecommitdiff
path: root/drivers/rtc/rtc-ds1307.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/rtc-ds1307.c')
-rw-r--r--drivers/rtc/rtc-ds1307.c597
1 files changed, 423 insertions, 174 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index d827ce570a8..f03d5ba96db 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -4,6 +4,7 @@
* Copyright (C) 2005 James Chapman (ds1337 core)
* Copyright (C) 2006 David Brownell
* Copyright (C) 2009 Matthias Fuchs (rx8025 support)
+ * Copyright (C) 2012 Bertrand Achard (nvram access fixes)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,10 +18,10 @@
#include <linux/string.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/rtc/ds1307.h>
-
-
-/* We can't determine type by probing, but if we expect pre-Linux code
+/*
+ * We can't determine type by probing, but if we expect pre-Linux code
* to have set the chip up as a clock (turning on the oscillator and
* setting the date and time), Linux can ignore the non-clock features.
* That's a natural job for a factory or repair bench.
@@ -34,8 +35,10 @@ enum ds_type {
ds_1388,
ds_3231,
m41t00,
+ mcp7941x,
rx_8025,
- // rs5c372 too? different address...
+ last_ds_type /* always last */
+ /* rs5c372 too? different address... */
};
@@ -43,6 +46,7 @@ enum ds_type {
#define DS1307_REG_SECS 0x00 /* 00-59 */
# define DS1307_BIT_CH 0x80
# define DS1340_BIT_nEOSC 0x80
+# define MCP7941X_BIT_ST 0x80
#define DS1307_REG_MIN 0x01 /* 00-59 */
#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
# define DS1307_BIT_12HR 0x40 /* in REG_HOUR */
@@ -50,12 +54,14 @@ enum ds_type {
# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
#define DS1307_REG_WDAY 0x03 /* 01-07 */
+# define MCP7941X_BIT_VBATEN 0x08
#define DS1307_REG_MDAY 0x04 /* 01-31 */
#define DS1307_REG_MONTH 0x05 /* 01-12 */
# define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */
#define DS1307_REG_YEAR 0x06 /* 00-99 */
-/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+/*
+ * Other registers (control, status, alarms, trickle charge, NVRAM, etc)
* start at 7, and they differ a LOT. Only control and status matter for
* basic RTC date and time functionality; be careful using them.
*/
@@ -86,7 +92,8 @@ enum ds_type {
# define DS1337_BIT_A2I 0x02
# define DS1337_BIT_A1I 0x01
#define DS1339_REG_ALARM1_SECS 0x07
-#define DS1339_REG_TRICKLE 0x10
+
+#define DS13XX_TRICKLE_CHARGER_MAGIC 0xa0
#define RX8025_REG_CTRL1 0x0e
# define RX8025_BIT_2412 0x20
@@ -99,6 +106,8 @@ enum ds_type {
struct ds1307 {
u8 offset; /* register's offset */
u8 regs[11];
+ u16 nvram_offset;
+ struct bin_attribute *nvram;
enum ds_type type;
unsigned long flags;
#define HAS_NVRAM 0 /* bit 0 == sysfs file active */
@@ -106,39 +115,51 @@ struct ds1307 {
struct i2c_client *client;
struct rtc_device *rtc;
struct work_struct work;
- s32 (*read_block_data)(struct i2c_client *client, u8 command,
+ s32 (*read_block_data)(const struct i2c_client *client, u8 command,
u8 length, u8 *values);
- s32 (*write_block_data)(struct i2c_client *client, u8 command,
+ s32 (*write_block_data)(const struct i2c_client *client, u8 command,
u8 length, const u8 *values);
};
struct chip_desc {
- unsigned nvram56:1;
unsigned alarm:1;
+ u16 nvram_offset;
+ u16 nvram_size;
+ u16 trickle_charger_reg;
};
-static const struct chip_desc chips[] = {
-[ds_1307] = {
- .nvram56 = 1,
-},
-[ds_1337] = {
- .alarm = 1,
-},
-[ds_1338] = {
- .nvram56 = 1,
-},
-[ds_1339] = {
- .alarm = 1,
-},
-[ds_1340] = {
-},
-[ds_3231] = {
- .alarm = 1,
-},
-[m41t00] = {
-},
-[rx_8025] = {
-}, };
+static const struct chip_desc chips[last_ds_type] = {
+ [ds_1307] = {
+ .nvram_offset = 8,
+ .nvram_size = 56,
+ },
+ [ds_1337] = {
+ .alarm = 1,
+ },
+ [ds_1338] = {
+ .nvram_offset = 8,
+ .nvram_size = 56,
+ },
+ [ds_1339] = {
+ .alarm = 1,
+ .trickle_charger_reg = 0x10,
+ },
+ [ds_1340] = {
+ .trickle_charger_reg = 0x08,
+ },
+ [ds_1388] = {
+ .trickle_charger_reg = 0x0a,
+ },
+ [ds_3231] = {
+ .alarm = 1,
+ },
+ [mcp7941x] = {
+ .alarm = 1,
+ /* this is battery backed SRAM */
+ .nvram_offset = 0x20,
+ .nvram_size = 0x40,
+ },
+};
static const struct i2c_device_id ds1307_id[] = {
{ "ds1307", ds_1307 },
@@ -149,6 +170,8 @@ static const struct i2c_device_id ds1307_id[] = {
{ "ds1340", ds_1340 },
{ "ds3231", ds_3231 },
{ "m41t00", m41t00 },
+ { "mcp7941x", mcp7941x },
+ { "pt7c4338", ds_1307 },
{ "rx8025", rx_8025 },
{ }
};
@@ -158,8 +181,8 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id);
#define BLOCK_DATA_MAX_TRIES 10
-static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
- u8 length, u8 *values)
+static s32 ds1307_read_block_data_once(const struct i2c_client *client,
+ u8 command, u8 length, u8 *values)
{
s32 i, data;
@@ -172,10 +195,10 @@ static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
return i;
}
-static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
+static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
u8 length, u8 *values)
{
- u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
+ u8 oldvalues[255];
s32 ret;
int tries = 0;
@@ -198,10 +221,10 @@ static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
return length;
}
-static s32 ds1307_write_block_data(struct i2c_client *client, u8 command,
+static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
u8 length, const u8 *values)
{
- u8 currvalues[I2C_SMBUS_BLOCK_MAX];
+ u8 currvalues[255];
int tries = 0;
dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
@@ -229,6 +252,57 @@ static s32 ds1307_write_block_data(struct i2c_client *client, u8 command,
/*----------------------------------------------------------------------*/
+/* These RTC devices are not designed to be connected to a SMbus adapter.
+ SMbus limits block operations length to 32 bytes, whereas it's not
+ limited on I2C buses. As a result, accesses may exceed 32 bytes;
+ in that case, split them into smaller blocks */
+
+static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
+ u8 command, u8 length, const u8 *values)
+{
+ u8 suboffset = 0;
+
+ if (length <= I2C_SMBUS_BLOCK_MAX)
+ return i2c_smbus_write_i2c_block_data(client,
+ command, length, values);
+
+ while (suboffset < length) {
+ s32 retval = i2c_smbus_write_i2c_block_data(client,
+ command + suboffset,
+ min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
+ values + suboffset);
+ if (retval < 0)
+ return retval;
+
+ suboffset += I2C_SMBUS_BLOCK_MAX;
+ }
+ return length;
+}
+
+static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
+ u8 command, u8 length, u8 *values)
+{
+ u8 suboffset = 0;
+
+ if (length <= I2C_SMBUS_BLOCK_MAX)
+ return i2c_smbus_read_i2c_block_data(client,
+ command, length, values);
+
+ while (suboffset < length) {
+ s32 retval = i2c_smbus_read_i2c_block_data(client,
+ command + suboffset,
+ min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
+ values + suboffset);
+ if (retval < 0)
+ return retval;
+
+ suboffset += I2C_SMBUS_BLOCK_MAX;
+ }
+ return length;
+}
+
+/*----------------------------------------------------------------------*/
+
/*
* The IRQ logic includes a "real" handler running in IRQ context just
* long enough to schedule this workqueue entry. We need a task context
@@ -301,12 +375,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
return -EIO;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
- "read",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6]);
+ dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
@@ -364,13 +433,20 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
| DS1340_BIT_CENTURY;
break;
+ case mcp7941x:
+ /*
+ * these bits were cleared when preparing the date/time
+ * values and need to be set again before writing the
+ * buffer out to the device.
+ */
+ buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
+ buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
+ break;
default:
break;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
- "write", buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6]);
+ dev_dbg(dev, "%s: %7ph\n", "write", buf);
result = ds1307->write_block_data(ds1307->client,
ds1307->offset, 7, buf);
@@ -406,7 +482,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
ds1307->regs[6], ds1307->regs[7],
ds1307->regs[8]);
- /* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
+ /*
+ * report alarm time (ALARM1); assume 24 hour and day-of-month modes,
* and that all four fields are checked matches
*/
t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f);
@@ -434,7 +511,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
unsigned char *buf = ds1307->regs;
u8 control, status;
@@ -495,66 +572,213 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
return 0;
}
-static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
int ret;
- switch (cmd) {
- case RTC_AIE_OFF:
- if (!test_bit(HAS_ALARM, &ds1307->flags))
- return -ENOTTY;
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -ENOTTY;
- ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
- if (ret < 0)
- return ret;
+ ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+ if (ret < 0)
+ return ret;
+ if (enabled)
+ ret |= DS1337_BIT_A1IE;
+ else
ret &= ~DS1337_BIT_A1IE;
- ret = i2c_smbus_write_byte_data(client,
- DS1337_REG_CONTROL, ret);
- if (ret < 0)
- return ret;
+ ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret);
+ if (ret < 0)
+ return ret;
- break;
+ return 0;
+}
- case RTC_AIE_ON:
- if (!test_bit(HAS_ALARM, &ds1307->flags))
- return -ENOTTY;
+static const struct rtc_class_ops ds13xx_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+ .read_alarm = ds1337_read_alarm,
+ .set_alarm = ds1337_set_alarm,
+ .alarm_irq_enable = ds1307_alarm_irq_enable,
+};
- ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
- if (ret < 0)
- return ret;
+/*----------------------------------------------------------------------*/
- ret |= DS1337_BIT_A1IE;
+/*
+ * Alarm support for mcp7941x devices.
+ */
- ret = i2c_smbus_write_byte_data(client,
- DS1337_REG_CONTROL, ret);
- if (ret < 0)
- return ret;
+#define MCP7941X_REG_CONTROL 0x07
+# define MCP7941X_BIT_ALM0_EN 0x10
+# define MCP7941X_BIT_ALM1_EN 0x20
+#define MCP7941X_REG_ALARM0_BASE 0x0a
+#define MCP7941X_REG_ALARM0_CTRL 0x0d
+#define MCP7941X_REG_ALARM1_BASE 0x11
+#define MCP7941X_REG_ALARM1_CTRL 0x14
+# define MCP7941X_BIT_ALMX_IF (1 << 3)
+# define MCP7941X_BIT_ALMX_C0 (1 << 4)
+# define MCP7941X_BIT_ALMX_C1 (1 << 5)
+# define MCP7941X_BIT_ALMX_C2 (1 << 6)
+# define MCP7941X_BIT_ALMX_POL (1 << 7)
+# define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \
+ MCP7941X_BIT_ALMX_C1 | \
+ MCP7941X_BIT_ALMX_C2)
+
+static void mcp7941x_work(struct work_struct *work)
+{
+ struct ds1307 *ds1307 = container_of(work, struct ds1307, work);
+ struct i2c_client *client = ds1307->client;
+ int reg, ret;
- break;
+ mutex_lock(&ds1307->rtc->ops_lock);
- default:
- return -ENOIOCTLCMD;
- }
+ /* Check and clear alarm 0 interrupt flag. */
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL);
+ if (reg < 0)
+ goto out;
+ if (!(reg & MCP7941X_BIT_ALMX_IF))
+ goto out;
+ reg &= ~MCP7941X_BIT_ALMX_IF;
+ ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg);
+ if (ret < 0)
+ goto out;
+
+ /* Disable alarm 0. */
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ if (reg < 0)
+ goto out;
+ reg &= ~MCP7941X_BIT_ALM0_EN;
+ ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+ if (ret < 0)
+ goto out;
+
+ rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+
+out:
+ if (test_bit(HAS_ALARM, &ds1307->flags))
+ enable_irq(client->irq);
+ mutex_unlock(&ds1307->rtc->ops_lock);
+}
+
+static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ u8 *regs = ds1307->regs;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ /* Read control and alarm 0 registers. */
+ ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN);
+
+ /* Report alarm 0 time assuming 24-hour and day-of-month modes. */
+ t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f);
+ t->time.tm_min = bcd2bin(ds1307->regs[4] & 0x7f);
+ t->time.tm_hour = bcd2bin(ds1307->regs[5] & 0x3f);
+ t->time.tm_wday = bcd2bin(ds1307->regs[6] & 0x7) - 1;
+ t->time.tm_mday = bcd2bin(ds1307->regs[7] & 0x3f);
+ t->time.tm_mon = bcd2bin(ds1307->regs[8] & 0x1f) - 1;
+ t->time.tm_year = -1;
+ t->time.tm_yday = -1;
+ t->time.tm_isdst = -1;
+
+ dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+ "enabled=%d polarity=%d irq=%d match=%d\n", __func__,
+ t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+ t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
+ !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL),
+ !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF),
+ (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4);
return 0;
}
-static const struct rtc_class_ops ds13xx_rtc_ops = {
+static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ unsigned char *regs = ds1307->regs;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+ "enabled=%d pending=%d\n", __func__,
+ t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+ t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
+ t->enabled, t->pending);
+
+ /* Read control and alarm 0 registers. */
+ ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ /* Set alarm 0, using 24-hour and day-of-month modes. */
+ regs[3] = bin2bcd(t->time.tm_sec);
+ regs[4] = bin2bcd(t->time.tm_min);
+ regs[5] = bin2bcd(t->time.tm_hour);
+ regs[6] = bin2bcd(t->time.tm_wday) + 1;
+ regs[7] = bin2bcd(t->time.tm_mday);
+ regs[8] = bin2bcd(t->time.tm_mon) + 1;
+
+ /* Clear the alarm 0 interrupt flag. */
+ regs[6] &= ~MCP7941X_BIT_ALMX_IF;
+ /* Set alarm match: second, minute, hour, day, date, month. */
+ regs[6] |= MCP7941X_MSK_ALMX_MATCH;
+
+ if (t->enabled)
+ regs[0] |= MCP7941X_BIT_ALM0_EN;
+ else
+ regs[0] &= ~MCP7941X_BIT_ALM0_EN;
+
+ ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ int reg;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ if (reg < 0)
+ return reg;
+
+ if (enabled)
+ reg |= MCP7941X_BIT_ALM0_EN;
+ else
+ reg &= ~MCP7941X_BIT_ALM0_EN;
+
+ return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+}
+
+static const struct rtc_class_ops mcp7941x_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
- .read_alarm = ds1337_read_alarm,
- .set_alarm = ds1337_set_alarm,
- .ioctl = ds1307_ioctl,
+ .read_alarm = mcp7941x_read_alarm,
+ .set_alarm = mcp7941x_set_alarm,
+ .alarm_irq_enable = mcp7941x_alarm_irq_enable,
};
/*----------------------------------------------------------------------*/
-#define NVRAM_SIZE 56
-
static ssize_t
ds1307_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
@@ -567,14 +791,15 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj,
client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);
- if (unlikely(off >= NVRAM_SIZE))
+ if (unlikely(off >= ds1307->nvram->size))
return 0;
- if ((off + count) > NVRAM_SIZE)
- count = NVRAM_SIZE - off;
+ if ((off + count) > ds1307->nvram->size)
+ count = ds1307->nvram->size - off;
if (unlikely(!count))
return count;
- result = ds1307->read_block_data(client, 8 + off, count, buf);
+ result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
+ count, buf);
if (result < 0)
dev_err(&client->dev, "%s error %d\n", "nvram read", result);
return result;
@@ -592,14 +817,15 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);
- if (unlikely(off >= NVRAM_SIZE))
+ if (unlikely(off >= ds1307->nvram->size))
return -EFBIG;
- if ((off + count) > NVRAM_SIZE)
- count = NVRAM_SIZE - off;
+ if ((off + count) > ds1307->nvram->size)
+ count = ds1307->nvram->size - off;
if (unlikely(!count))
return count;
- result = ds1307->write_block_data(client, 8 + off, count, buf);
+ result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
+ count, buf);
if (result < 0) {
dev_err(&client->dev, "%s error %d\n", "nvram write", result);
return result;
@@ -607,54 +833,47 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
return count;
}
-static struct bin_attribute nvram = {
- .attr = {
- .name = "nvram",
- .mode = S_IRUGO | S_IWUSR,
- },
-
- .read = ds1307_nvram_read,
- .write = ds1307_nvram_write,
- .size = NVRAM_SIZE,
-};
-
/*----------------------------------------------------------------------*/
-static struct i2c_driver ds1307_driver;
-
-static int __devinit ds1307_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ds1307_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds1307 *ds1307;
int err = -ENODEV;
int tmp;
const struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- int want_irq = false;
+ bool want_irq = false;
unsigned char *buf;
+ struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
static const int bbsqi_bitpos[] = {
[ds_1337] = 0,
[ds_1339] = DS1339_BIT_BBSQI,
[ds_3231] = DS3231_BIT_BBSQW,
};
+ const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
- if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
+ ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL);
+ if (!ds1307)
return -ENOMEM;
i2c_set_clientdata(client, ds1307);
ds1307->client = client;
ds1307->type = id->driver_data;
- ds1307->offset = 0;
+
+ if (pdata && pdata->trickle_charger_setup && chip->trickle_charger_reg)
+ i2c_smbus_write_byte_data(client, chip->trickle_charger_reg,
+ DS13XX_TRICKLE_CHARGER_MAGIC | pdata->trickle_charger_setup);
buf = ds1307->regs;
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
- ds1307->read_block_data = i2c_smbus_read_i2c_block_data;
- ds1307->write_block_data = i2c_smbus_write_i2c_block_data;
+ ds1307->read_block_data = ds1307_native_smbus_read_block_data;
+ ds1307->write_block_data = ds1307_native_smbus_write_block_data;
} else {
ds1307->read_block_data = ds1307_read_block_data;
ds1307->write_block_data = ds1307_write_block_data;
@@ -664,32 +883,32 @@ static int __devinit ds1307_probe(struct i2c_client *client,
case ds_1337:
case ds_1339:
case ds_3231:
- /* has IRQ? */
- if (ds1307->client->irq > 0 && chip->alarm) {
- INIT_WORK(&ds1307->work, ds1307_work);
- want_irq = true;
- }
/* get registers that the "rtc" read below won't read... */
tmp = ds1307->read_block_data(ds1307->client,
DS1337_REG_CONTROL, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* oscillator off? turn it on, so clock can tick. */
if (ds1307->regs[0] & DS1337_BIT_nEOSC)
ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
- /* Using IRQ? Disable the square wave and both alarms.
+ /*
+ * Using IRQ? Disable the square wave and both alarms.
* For some variants, be sure alarms can trigger when we're
* running on Vbackup (BBSQI/BBSQW)
*/
- if (want_irq) {
+ if (ds1307->client->irq > 0 && chip->alarm) {
+ INIT_WORK(&ds1307->work, ds1307_work);
+
ds1307->regs[0] |= DS1337_BIT_INTCN
| bbsqi_bitpos[ds1307->type];
ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+
+ want_irq = true;
}
i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
@@ -707,9 +926,9 @@ static int __devinit ds1307_probe(struct i2c_client *client,
tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* oscillator off? turn it on, so clock can tick. */
@@ -751,9 +970,9 @@ static int __devinit ds1307_probe(struct i2c_client *client,
tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* correct hour */
@@ -771,6 +990,13 @@ static int __devinit ds1307_probe(struct i2c_client *client,
case ds_1388:
ds1307->offset = 1; /* Seconds starts at 1 */
break;
+ case mcp7941x:
+ rtc_ops = &mcp7941x_rtc_ops;
+ if (ds1307->client->irq > 0 && chip->alarm) {
+ INIT_WORK(&ds1307->work, mcp7941x_work);
+ want_irq = true;
+ }
+ break;
default:
break;
}
@@ -779,12 +1005,13 @@ read_rtc:
/* read RTC registers */
tmp = ds1307->read_block_data(ds1307->client, ds1307->offset, 8, buf);
if (tmp != 8) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
- /* minimal sanity checking; some chips (like DS1340) don't
+ /*
+ * minimal sanity checking; some chips (like DS1340) don't
* specify the extra bits as must-be-zero, but there are
* still a few values that are clearly out-of-range.
*/
@@ -820,9 +1047,9 @@ read_rtc:
tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
if (tmp < 0) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* oscillator fault? clear flag, and warn */
@@ -831,11 +1058,24 @@ read_rtc:
dev_warn(&client->dev, "SET TIME!\n");
}
break;
- case rx_8025:
- case ds_1337:
- case ds_1339:
- case ds_1388:
- case ds_3231:
+ case mcp7941x:
+ /* make sure that the backup battery is enabled */
+ if (!(ds1307->regs[DS1307_REG_WDAY] & MCP7941X_BIT_VBATEN)) {
+ i2c_smbus_write_byte_data(client, DS1307_REG_WDAY,
+ ds1307->regs[DS1307_REG_WDAY]
+ | MCP7941X_BIT_VBATEN);
+ }
+
+ /* clock halted? turn it on, so clock can tick. */
+ if (!(tmp & MCP7941X_BIT_ST)) {
+ i2c_smbus_write_byte_data(client, DS1307_REG_SECS,
+ MCP7941X_BIT_ST);
+ dev_warn(&client->dev, "SET TIME!\n");
+ goto read_rtc;
+ }
+
+ break;
+ default:
break;
}
@@ -843,7 +1083,8 @@ read_rtc:
switch (ds1307->type) {
case ds_1340:
case m41t00:
- /* NOTE: ignores century bits; fix before deploying
+ /*
+ * NOTE: ignores century bits; fix before deploying
* systems that will run through year 2100.
*/
break;
@@ -853,7 +1094,8 @@ read_rtc:
if (!(tmp & DS1307_BIT_12HR))
break;
- /* Be sure we're in 24 hour mode. Multi-master systems
+ /*
+ * Be sure we're in 24 hour mode. Multi-master systems
* take note...
*/
tmp = bcd2bin(tmp & 0x1f);
@@ -866,49 +1108,68 @@ read_rtc:
bin2bcd(tmp));
}
- ds1307->rtc = rtc_device_register(client->name, &client->dev,
- &ds13xx_rtc_ops, THIS_MODULE);
+ device_set_wakeup_capable(&client->dev, want_irq);
+ ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
+ rtc_ops, THIS_MODULE);
if (IS_ERR(ds1307->rtc)) {
- err = PTR_ERR(ds1307->rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
- goto exit_free;
+ return PTR_ERR(ds1307->rtc);
}
if (want_irq) {
err = request_irq(client->irq, ds1307_irq, IRQF_SHARED,
ds1307->rtc->name, client);
if (err) {
- dev_err(&client->dev,
- "unable to request IRQ!\n");
- goto exit_irq;
- }
+ client->irq = 0;
+ dev_err(&client->dev, "unable to request IRQ!\n");
+ } else {
- device_set_wakeup_capable(&client->dev, 1);
- set_bit(HAS_ALARM, &ds1307->flags);
- dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+ set_bit(HAS_ALARM, &ds1307->flags);
+ dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+ }
}
- if (chip->nvram56) {
- err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
- if (err == 0) {
- set_bit(HAS_NVRAM, &ds1307->flags);
- dev_info(&client->dev, "56 bytes nvram\n");
+ if (chip->nvram_size) {
+
+ ds1307->nvram = devm_kzalloc(&client->dev,
+ sizeof(struct bin_attribute),
+ GFP_KERNEL);
+ if (!ds1307->nvram) {
+ dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n");
+ } else {
+
+ ds1307->nvram->attr.name = "nvram";
+ ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
+
+ sysfs_bin_attr_init(ds1307->nvram);
+
+ ds1307->nvram->read = ds1307_nvram_read;
+ ds1307->nvram->write = ds1307_nvram_write;
+ ds1307->nvram->size = chip->nvram_size;
+ ds1307->nvram_offset = chip->nvram_offset;
+
+ err = sysfs_create_bin_file(&client->dev.kobj,
+ ds1307->nvram);
+ if (err) {
+ dev_err(&client->dev,
+ "unable to create sysfs file: %s\n",
+ ds1307->nvram->attr.name);
+ } else {
+ set_bit(HAS_NVRAM, &ds1307->flags);
+ dev_info(&client->dev, "%zu bytes nvram\n",
+ ds1307->nvram->size);
+ }
}
}
return 0;
-exit_irq:
- rtc_device_unregister(ds1307->rtc);
-exit_free:
- kfree(ds1307);
+exit:
return err;
}
-static int __devexit ds1307_remove(struct i2c_client *client)
+static int ds1307_remove(struct i2c_client *client)
{
- struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
free_irq(client->irq, client);
@@ -916,10 +1177,8 @@ static int __devexit ds1307_remove(struct i2c_client *client)
}
if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
- sysfs_remove_bin_file(&client->dev.kobj, &nvram);
+ sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
- rtc_device_unregister(ds1307->rtc);
- kfree(ds1307);
return 0;
}
@@ -929,21 +1188,11 @@ static struct i2c_driver ds1307_driver = {
.owner = THIS_MODULE,
},
.probe = ds1307_probe,
- .remove = __devexit_p(ds1307_remove),
+ .remove = ds1307_remove,
.id_table = ds1307_id,
};
-static int __init ds1307_init(void)
-{
- return i2c_add_driver(&ds1307_driver);
-}
-module_init(ds1307_init);
-
-static void __exit ds1307_exit(void)
-{
- i2c_del_driver(&ds1307_driver);
-}
-module_exit(ds1307_exit);
+module_i2c_driver(ds1307_driver);
MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
MODULE_LICENSE("GPL");