From patchwork Sat Oct 24 07:31:11 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergey Matyukevich X-Patchwork-Id: 36829 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-yx0-f158.google.com (mail-yx0-f158.google.com [209.85.210.158]) by ozlabs.org (Postfix) with ESMTP id 720CBB7BD1 for ; Sat, 24 Oct 2009 18:37:50 +1100 (EST) Received: by yxe30 with SMTP id 30so8096705yxe.29 for ; Sat, 24 Oct 2009 00:37:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=beta; h=domainkey-signature:received:received:x-sender:x-apparently-to :received:received:received:received-spf:received:dkim-signature :domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:reply-to:sender:precedence:x-google-loop :mailing-list:list-id:list-post:list-help:list-unsubscribe :x-beenthere-env:x-beenthere; bh=EuqhNZC75qiWcogLZLvL2d3jxxEVZQQwFEAh3xBc5rU=; b=L+VsfdwYCyMlSUz3EsBMfpZ9p1opUbPEp8/awPntoG3uxDK04k6cJYknRd6meXyoKh f5EJqM6iIqnyENzkiQrY0DOKSlWpKF7MZn48gy/LipdDQWifbLOuTX63zfkUktMaaVPu ISDABaoxTJnk2o65EhVZN383sLRbpZP8Gu62U= DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlegroups.com; s=beta; h=x-sender:x-apparently-to:received-spf:authentication-results :dkim-signature:domainkey-signature:from:to:cc:subject:date :message-id:x-mailer:reply-to:sender:precedence:x-google-loop :mailing-list:list-id:list-post:list-help:list-unsubscribe :x-beenthere-env:x-beenthere; b=eVYvZerysEedE4PAccDLt7XuMwCayeljz9IhR1+Eln8fJcTQBUqrrzuaIJR2zWpGJR h/Tauy20TZyN731JYcgxw+bcf6jU7bX5/1+gRMZVU8pE81wzPniZyiWGUOXeJkxg3FiR XM/PnoZnjSNkHTsvPYfJ4ig3U/rRbi6UFTXZM= Received: by 10.91.54.37 with SMTP id g37mr588363agk.20.1256369867465; Sat, 24 Oct 2009 00:37:47 -0700 (PDT) Received: by 10.176.233.14 with SMTP id f14gr2984yqh.0; Sat, 24 Oct 2009 00:37:47 -0700 (PDT) X-Sender: geomatsi@gmail.com X-Apparently-To: rtc-linux@googlegroups.com Received: by 10.211.174.12 with SMTP id b12mr911449ebp.15.1256369866836; Sat, 24 Oct 2009 00:37:46 -0700 (PDT) Received: by 10.211.174.12 with SMTP id b12mr911448ebp.15.1256369866811; Sat, 24 Oct 2009 00:37:46 -0700 (PDT) Received: from mail-ew0-f228.google.com (mail-ew0-f228.google.com [209.85.219.228]) by gmr-mx.google.com with ESMTP id 15si636028ewy.0.2009.10.24.00.37.45; Sat, 24 Oct 2009 00:37:45 -0700 (PDT) Received-SPF: pass (google.com: domain of geomatsi@gmail.com designates 209.85.219.228 as permitted sender) client-ip=209.85.219.228; Authentication-Results: gmr-mx.google.com; spf=pass (google.com: domain of geomatsi@gmail.com designates 209.85.219.228 as permitted sender) smtp.mail=geomatsi@gmail.com; dkim=pass (test mode) header.i=@gmail.com Received: by mail-ew0-f228.google.com with SMTP id 28so3637896ewy.42 for ; Sat, 24 Oct 2009 00:37:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=PV+tja9wxomBRQzpjOPx8gGmkKvrKIEO08o8srr34TE=; b=ZimPScrs47++uQ+tOeFoqhNn8NdLt7N88Fe60uo8YWWVpBb3SqU5qHBbvu08XtqP17 Xvs4gm8PGVal5Oia7BQ9+uWaryW0NRw+cWcvoONFs9tUYvl9o0WrZTiT2NxsRePKNZMB d4YlIBdwlbuwZvWnLy/tBfFLz67nYXehR2WWY= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=bJdLvyIrEHVwPVfjEeKiCorYB+CXr1myB7VhzLMPzHi8yhtDNKL0oipEfTZfitD/oK M1YUYefLTOpJnHhnCkvXmjxI0mtIpph5A+8YwUCZ54Zv+YqXioxwlNugYPnEB4DjRo7r w7wOb/apH/y0JWz+MKUyDwEfyCxEArIAZURN8= Received: by 10.210.7.23 with SMTP id 23mr1667597ebg.38.1256369862921; Sat, 24 Oct 2009 00:37:42 -0700 (PDT) Received: from localhost.localdomain (92-100-229-197.dynamic.avangarddsl.ru [92.100.229.197]) by mx.google.com with ESMTPS id 10sm7827550eyz.3.2009.10.24.00.37.41 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sat, 24 Oct 2009 00:37:42 -0700 (PDT) From: Sergey Matyukevich To: rtc-linux@googlegroups.com Cc: Sergey Lapin , Sergey Matyukevich Subject: [rtc-linux] [PATCH] RTC: fm3130 fixes Date: Sat, 24 Oct 2009 11:31:11 +0400 Message-Id: <1256369471-11901-1-git-send-email-geomatsi@gmail.com> X-Mailer: git-send-email 1.6.2.5 Reply-To: rtc-linux@googlegroups.com Sender: rtc-linux@googlegroups.com Precedence: bulk X-Google-Loop: groups Mailing-List: list rtc-linux@googlegroups.com; contact rtc-linux+owner@googlegroups.com List-Id: List-Post: List-Help: List-Unsubscribe: , X-BeenThere-Env: rtc-linux@googlegroups.com X-BeenThere: rtc-linux@googlegroups.com This patch contains the following fixes and enhancements for fm3130 rtc driver: * add missing braces for multiline 'if' statements in fm3130_probe * add sanity check for alarm data in fm3130_probe * fix fm3130_set_alarm: according to datasheet, setting match bit '0' indicates that the corresponding alarm field will be used in the match process * add ioctls for RTC_AIE_ON, RTC_AIE_OFF * Remove clearing of AF bit after reading rtc/alarm control register: according to datasheet this bit is cleared anyway when rtc/alarm control register is read * add whitespaces for '#define' to improve readability Signed-off-by: Sergey Matyukevich --- drivers/rtc/rtc-fm3130.c | 213 ++++++++++++++++++++++++++++++++-------------- 1 files changed, 148 insertions(+), 65 deletions(-) diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index 3a7be11..27e8616 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -31,15 +31,15 @@ #define FM3130_ALARM_MONTHS (0xd) #define FM3130_ALARM_WP_CONTROL (0xe) -#define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */ -#define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */ -#define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */ -#define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */ -#define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */ -#define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */ -#define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */ -#define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* W=1 -> write mode W=0 normal */ -#define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* R=1 -> read mode R=0 normal */ +#define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */ +#define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */ +#define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */ +#define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */ +#define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */ +#define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */ +#define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */ +#define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* Write RTC */ +#define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* Read RTC */ #define FM3130_CLOCK_REGS 7 #define FM3130_ALARM_REGS 5 @@ -51,8 +51,8 @@ struct fm3130 { struct i2c_msg msg[4]; struct i2c_client *client; struct rtc_device *rtc; + int alarm_valid; int data_valid; - int alarm; }; static const struct i2c_device_id fm3130_id[] = { { "fm3130", 0 }, @@ -74,7 +74,7 @@ static void fm3130_rtc_mode(struct device *dev, int mode) case FM3130_MODE_NORMAL: fm3130->regs[FM3130_RTC_CONTROL] &= ~(FM3130_RTC_CONTROL_BIT_WRITE | - FM3130_RTC_CONTROL_BIT_READ); + FM3130_RTC_CONTROL_BIT_READ); break; case FM3130_MODE_WRITE: fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_WRITE; @@ -86,11 +86,7 @@ static void fm3130_rtc_mode(struct device *dev, int mode) dev_dbg(dev, "invalid mode %d\n", mode); break; } - /* Checking for alarm */ - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { - fm3130->alarm = 1; - fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; - } + i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]); } @@ -103,7 +99,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t) if (!fm3130->data_valid) { /* We have invalid data in RTC, probably due to battery faults or other problems. Return EIO - for now, it will allow us to set data later insted + for now, it will allow us to set data later instead of error during probing which disables device */ return -EIO; } @@ -153,7 +149,6 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t) return rtc_valid_tm(t); } - static int fm3130_set_time(struct device *dev, struct rtc_time *t) { struct fm3130 *fm3130 = dev_get_drvdata(dev); @@ -207,6 +202,15 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct fm3130 *fm3130 = dev_get_drvdata(dev); int tmp; struct rtc_time *tm = &alrm->time; + + if (!fm3130->alarm_valid) { + /* We have invalid alarm in RTC, probably due + to battery faults or other problems. Return EIO + for now, it will allow us to set alarm value later + instead of error during probing which disables device */ + return -EIO; + } + /* read the RTC alarm registers all at once */ tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), &fm3130->msg[2], 2); @@ -214,6 +218,7 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) dev_err(dev, "%s error %d\n", "read", tmp); return -EIO; } + dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n", fm3130->regs[FM3130_ALARM_SECONDS], fm3130->regs[FM3130_ALARM_MINUTES], @@ -221,20 +226,30 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) fm3130->regs[FM3130_ALARM_DATE], fm3130->regs[FM3130_ALARM_MONTHS]); - tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F); tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F); tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F); tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F); tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F); + if (tm->tm_mon > 0) tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ + dev_dbg(dev, "%s secs=%d, mins=%d, " "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", "read alarm", tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + /* check if alarm enabled */ + fm3130->regs[FM3130_RTC_CONTROL] = + i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); + + if ((fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AEN) && + (~fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL)) { + alrm->enabled = 1; + } + return 0; } @@ -250,25 +265,20 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - if (tm->tm_sec != -1) - fm3130->regs[FM3130_ALARM_SECONDS] = - bin2bcd(tm->tm_sec) | 0x80; + fm3130->regs[FM3130_ALARM_SECONDS] = + (tm->tm_sec != -1) ? bin2bcd(tm->tm_sec) : 0x80; - if (tm->tm_min != -1) - fm3130->regs[FM3130_ALARM_MINUTES] = - bin2bcd(tm->tm_min) | 0x80; + fm3130->regs[FM3130_ALARM_MINUTES] = + (tm->tm_min != -1) ? bin2bcd(tm->tm_min) : 0x80; - if (tm->tm_hour != -1) - fm3130->regs[FM3130_ALARM_HOURS] = - bin2bcd(tm->tm_hour) | 0x80; + fm3130->regs[FM3130_ALARM_HOURS] = + (tm->tm_hour != -1) ? bin2bcd(tm->tm_hour) : 0x80; - if (tm->tm_mday != -1) - fm3130->regs[FM3130_ALARM_DATE] = - bin2bcd(tm->tm_mday) | 0x80; + fm3130->regs[FM3130_ALARM_DATE] = + (tm->tm_mday != -1) ? bin2bcd(tm->tm_mday) : 0x80; - if (tm->tm_mon != -1) - fm3130->regs[FM3130_ALARM_MONTHS] = - bin2bcd(tm->tm_mon + 1) | 0x80; + fm3130->regs[FM3130_ALARM_MONTHS] = + (tm->tm_mon != -1) ? bin2bcd(tm->tm_mon + 1) : 0x80; dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n", fm3130->regs[FM3130_ALARM_SECONDS], @@ -276,19 +286,18 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) fm3130->regs[FM3130_ALARM_HOURS], fm3130->regs[FM3130_ALARM_DATE], fm3130->regs[FM3130_ALARM_MONTHS]); + /* Writing time registers, we don't support multibyte transfers */ for (i = 0; i < FM3130_ALARM_REGS; i++) { i2c_smbus_write_byte_data(fm3130->client, FM3130_ALARM_SECONDS + i, fm3130->regs[FM3130_ALARM_SECONDS + i]); } + fm3130->regs[FM3130_RTC_CONTROL] = i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); - /* Checking for alarm */ - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { - fm3130->alarm = 1; - fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; - } + + /* enable or disable alarm */ if (alrm->enabled) { i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, (fm3130->regs[FM3130_RTC_CONTROL] & @@ -297,12 +306,52 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) } else { i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] & - ~(FM3130_RTC_CONTROL_BIT_AEN)); + ~(FM3130_RTC_CONTROL_BIT_CAL) & + ~(FM3130_RTC_CONTROL_BIT_AEN)); } + + /* We assume here that data is valid once written */ + if (!fm3130->alarm_valid) + fm3130->alarm_valid = 1; + return 0; } +static int fm3130_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct fm3130 *fm3130 = dev_get_drvdata(dev); + int ret = 0; + + fm3130->regs[FM3130_RTC_CONTROL] = + i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); + + dev_dbg(dev, "ioctl: cmd=%08x, FM3130_RTC_CONTROL=%08x\n", + cmd, fm3130->regs[FM3130_RTC_CONTROL]); + + switch (cmd) { + case RTC_AIE_OFF: /* alarm off */ + ret = i2c_smbus_write_byte_data(fm3130->client, + FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] & + ~(FM3130_RTC_CONTROL_BIT_CAL) & + ~(FM3130_RTC_CONTROL_BIT_AEN)); + break; + case RTC_AIE_ON: /* alarm on */ + ret = i2c_smbus_write_byte_data(fm3130->client, + FM3130_RTC_CONTROL, (fm3130->regs[FM3130_RTC_CONTROL] & + ~(FM3130_RTC_CONTROL_BIT_CAL)) | + FM3130_RTC_CONTROL_BIT_AEN); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + static const struct rtc_class_ops fm3130_rtc_ops = { + .ioctl = fm3130_ioctl, .read_time = fm3130_get_time, .set_time = fm3130_set_time, .read_alarm = fm3130_read_alarm, @@ -355,6 +404,7 @@ static int __devinit fm3130_probe(struct i2c_client *client, fm3130->msg[3].len = FM3130_ALARM_REGS; fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS]; + fm3130->alarm_valid = 0; fm3130->data_valid = 0; tmp = i2c_transfer(adapter, fm3130->msg, 4); @@ -366,30 +416,27 @@ static int __devinit fm3130_probe(struct i2c_client *client, fm3130->regs[FM3130_RTC_CONTROL] = i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL); + fm3130->regs[FM3130_CAL_CONTROL] = i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL); - /* Checking for alarm */ - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { - fm3130->alarm = 1; - fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; - } - /* Disabling calibration mode */ - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) { i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] & ~(FM3130_RTC_CONTROL_BIT_CAL)); dev_warn(&client->dev, "Disabling calibration mode!\n"); + } /* Disabling read and write modes */ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE || - fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) + fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) { i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] & ~(FM3130_RTC_CONTROL_BIT_READ | FM3130_RTC_CONTROL_BIT_WRITE)); dev_warn(&client->dev, "Disabling READ or WRITE mode!\n"); + } /* oscillator off? turn it on, so clock can tick. */ if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN) @@ -397,44 +444,80 @@ static int __devinit fm3130_probe(struct i2c_client *client, fm3130->regs[FM3130_CAL_CONTROL] & ~(FM3130_CAL_CONTROL_BIT_nOSCEN)); - /* oscillator fault? clear flag, and warn */ - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) + /* low battery? clear flag, and warn */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) { + i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, + fm3130->regs[FM3130_RTC_CONTROL] & + ~(FM3130_RTC_CONTROL_BIT_LB)); dev_warn(&client->dev, "Low battery!\n"); + } - /* oscillator fault? clear flag, and warn */ + /* check if Power On Reset bit is set */ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) { i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] & ~FM3130_RTC_CONTROL_BIT_POR); - dev_warn(&client->dev, "SET TIME!\n"); + dev_dbg(&client->dev, "POR bit is set\n"); } + /* ACS is controlled by alarm */ i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80); - /* TODO */ - /* TODO need to sanity check alarm */ - tmp = fm3130->regs[FM3130_RTC_SECONDS]; - tmp = bcd2bin(tmp & 0x7f); - if (tmp > 60) - goto exit_bad; + /* alarm registers sanity check */ + tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); + if (tmp > 59) + goto bad_alarm; + tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); - if (tmp > 60) - goto exit_bad; + if (tmp > 59) + goto bad_alarm; + + tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f); + if (tmp > 23) + goto bad_alarm; tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); if (tmp == 0 || tmp > 31) - goto exit_bad; + goto bad_alarm; tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); if (tmp == 0 || tmp > 12) - goto exit_bad; + goto bad_alarm; + + fm3130->alarm_valid = 1; + +bad_alarm: + + /* clock registers sanity chek */ + tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); + if (tmp > 59) + goto bad_clock; + + tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); + if (tmp > 59) + goto bad_clock; + + tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f); + if (tmp > 23) + goto bad_clock; - tmp = fm3130->regs[FM3130_RTC_HOURS]; + tmp = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x7); + if (tmp == 0 || tmp > 7) + goto bad_clock; + + tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); + if (tmp == 0 || tmp > 31) + goto bad_clock; + + tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); + if (tmp == 0 || tmp > 12) + goto bad_clock; fm3130->data_valid = 1; -exit_bad: - if (!fm3130->data_valid) +bad_clock: + + if (!fm3130->data_valid || !fm3130->alarm_valid) dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x" "%02x %02x %02x %02x %02x %02x %02x\n",