+static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ /* read all ALARM1, ALARM2, and status registers at once */
+ ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = 9;
+
+ ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+ ds1307->msg, 2);
+ if (ret != 2) {
+ dev_err(dev, "%s error %d\n", "alarm read", ret);
+ return -EIO;
+ }
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
+ "alarm read",
+ ds1307->regs[0], ds1307->regs[1],
+ ds1307->regs[2], ds1307->regs[3],
+ ds1307->regs[4], ds1307->regs[5],
+ ds1307->regs[6], ds1307->regs[7],
+ ds1307->regs[8]);
+
+ /* 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);
+ 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);
+ t->pending = !!(ds1307->regs[8] & DS1337_BIT_A1I);
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, enabled=%d, pending=%d\n",
+ "alarm read", t->time.tm_sec, t->time.tm_min,
+ t->time.tm_hour, t->time.tm_mday,
+ t->enabled, t->pending);
+
+ return 0;
+}
+
+static int ds1307_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 *buf = ds1307->regs;
+ u8 control, status;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, enabled=%d, pending=%d\n",
+ "alarm set", t->time.tm_sec, t->time.tm_min,
+ t->time.tm_hour, t->time.tm_mday,
+ t->enabled, t->pending);
+
+ /* read current status of both alarms and the chip */
+ ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = 9;
+
+ ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+ ds1307->msg, 2);
+ if (ret != 2) {
+ dev_err(dev, "%s error %d\n", "alarm write", ret);
+ return -EIO;
+ }
+ control = ds1307->regs[7];
+ status = ds1307->regs[8];
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
+ "alarm set (old status)",
+ ds1307->regs[0], ds1307->regs[1],
+ ds1307->regs[2], ds1307->regs[3],
+ ds1307->regs[4], ds1307->regs[5],
+ ds1307->regs[6], control, status);
+
+ /* set ALARM1, using 24 hour and day-of-month modes */
+ *buf++ = DS1339_REG_ALARM1_SECS; /* first register addr */
+ buf[0] = bin2bcd(t->time.tm_sec);
+ buf[1] = bin2bcd(t->time.tm_min);
+ buf[2] = bin2bcd(t->time.tm_hour);
+ buf[3] = bin2bcd(t->time.tm_mday);
+
+ /* set ALARM2 to non-garbage */
+ buf[4] = 0;
+ buf[5] = 0;
+ buf[6] = 0;
+
+ /* optionally enable ALARM1 */
+ 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);
+
+ ds1307->msg[1].flags = 0;
+ ds1307->msg[1].len = 10;
+
+ ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+ &ds1307->msg[1], 1);
+ if (ret != 1) {
+ dev_err(dev, "can't set alarm time\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ 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;
+
+ ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~DS1337_BIT_A1IE;
+
+ ret = i2c_smbus_write_byte_data(client,
+ DS1337_REG_CONTROL, ret);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ case RTC_AIE_ON:
+ 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 |= DS1337_BIT_A1IE;
+
+ ret = i2c_smbus_write_byte_data(client,
+ DS1337_REG_CONTROL, ret);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+