From patchwork Wed Oct 5 10:46:48 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 117815 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-wy0-f184.google.com (mail-wy0-f184.google.com [74.125.82.184]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority" (verified OK)) by ozlabs.org (Postfix) with ESMTPS id 25E73B6F9A for ; Wed, 5 Oct 2011 21:47:12 +1100 (EST) Received: by wyj26 with SMTP id 26sf2213332wyj.11 for ; Wed, 05 Oct 2011 03:47:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=beta; h=x-beenthere:received-spf:from:to:cc:subject:date:message-id :x-mailer:mime-version:x-original-sender :x-original-authentication-results:reply-to:precedence:mailing-list :list-id:x-google-group-id:list-post:list-help:list-archive:sender :list-subscribe:list-unsubscribe:content-type; bh=CzvXGlCqdvmTlKBqABNdY+ChY6/S87TS9+Aji3pfWfM=; b=BG4/dpTjk0FaSa8UWx0TJJTtUpm4P+e0jObEcd04v29yZFRhgMejINNv0eICtGABRg gmoIxKBfH52O0OAdSLBHZH2JPdUMw5PcteQk4WS/EwmNBO+Gr4y5NNKl32cmXgNQfxUE eHygYkcrHA+1T6+bNTwRkBfzP5OB+9igsH+24= Received: by 10.216.176.2 with SMTP id a2mr923959wem.12.1317811627926; Wed, 05 Oct 2011 03:47:07 -0700 (PDT) X-BeenThere: rtc-linux@googlegroups.com Received: by 10.14.13.202 with SMTP id b50ls129547eeb.4.canary; Wed, 05 Oct 2011 03:47:06 -0700 (PDT) Received: by 10.14.5.7 with SMTP id 7mr99979eek.12.1317811626855; Wed, 05 Oct 2011 03:47:06 -0700 (PDT) Received: by 10.14.5.7 with SMTP id 7mr99978eek.12.1317811626836; Wed, 05 Oct 2011 03:47:06 -0700 (PDT) Received: from eu1sys200aog111.obsmtp.com (eu1sys200aog111.obsmtp.com. [207.126.144.131]) by gmr-mx.google.com with SMTP id x14si2041eef.2.2011.10.05.03.47.03 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 05 Oct 2011 03:47:06 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.131 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.131; Received: from beta.dmz-us.st.com ([167.4.1.35]) (using TLSv1) by eu1sys200aob111.postini.com ([207.126.147.11]) with SMTP; Wed, 05 Oct 2011 10:47:06 UTC Received: from zeta.dmz-us.st.com (ns4.st.com [167.4.16.71]) by beta.dmz-us.st.com (STMicroelectronics) with ESMTP id 1B41251; Wed, 5 Oct 2011 10:47:00 +0000 (GMT) Received: from relay2.stm.gmessaging.net (unknown [10.230.100.18]) by zeta.dmz-us.st.com (STMicroelectronics) with ESMTP id 802944A; Wed, 5 Oct 2011 10:46:59 +0000 (GMT) Received: from exdcvycastm022.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm022", Issuer "exdcvycastm022" (not verified)) by relay2.stm.gmessaging.net (Postfix) with ESMTPS id 91F28A8072; Wed, 5 Oct 2011 12:46:54 +0200 (CEST) Received: from localhost.localdomain (10.230.100.153) by smtp.stericsson.com (10.230.100.30) with Microsoft SMTP Server (TLS) id 8.3.83.0; Wed, 5 Oct 2011 12:46:58 +0200 From: Linus Walleij To: Alessandro Zummo , Cc: Lee Jones , Mark Godfrey , Linus Walleij Subject: [rtc-linux] [PATCH] rtc: ab8500: Add calibration attribute to AB8500 RTC Date: Wed, 5 Oct 2011 12:46:48 +0200 Message-ID: <1317811608-29975-1-git-send-email-linus.walleij@stericsson.com> X-Mailer: git-send-email 1.7.3.2 MIME-Version: 1.0 X-Original-Sender: linus.walleij@stericsson.com X-Original-Authentication-Results: gmr-mx.google.com; spf=neutral (google.com: 207.126.144.131 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) smtp.mail=linus.walleij@stericsson.com Reply-To: rtc-linux@googlegroups.com Precedence: list Mailing-list: list rtc-linux@googlegroups.com; contact rtc-linux+owners@googlegroups.com List-ID: X-Google-Group-Id: 712029733259 List-Post: , List-Help: , List-Archive: Sender: rtc-linux@googlegroups.com List-Subscribe: , List-Unsubscribe: , From: Mark Godfrey The rtc_calibration attribute allows user-space to get and set the AB8500's RtcCalibration register. The AB8500 will then use the value in this register to compensate for RTC drift every 60 seconds. Signed-off-by: Mark Godfrey Signed-off-by: Linus Walleij --- .../sysfs-class-rtc-rtc0-device-rtc_calibration | 12 ++ drivers/rtc/rtc-ab8500.c | 109 ++++++++++++++++++++ 2 files changed, 121 insertions(+), 0 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration diff --git a/Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration b/Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration new file mode 100644 index 0000000..4cf1e72 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration @@ -0,0 +1,12 @@ +What: Attribute for calibrating ST-Ericsson AB8500 Real Time Clock +Date: Oct 2011 +KernelVersion: 3.0 +Contact: Mark Godfrey +Description: The rtc_calibration attribute allows the userspace to + calibrate the AB8500.s 32KHz Real Time Clock. + Every 60 seconds the AB8500 will correct the RTC's value + by adding to it the value of this attribute. + The range of the attribute is -127 to +127 in units of + 30.5 micro-seconds (half-parts-per-million of the 32KHz clock) +Users: The /vendor/st-ericsson/base_utilities/core/rtc_calibration + daemon uses this interface. diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 326a1a5..ad90a5b 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -258,6 +258,106 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) return ab8500_rtc_irq_enable(dev, alarm->enabled); } + +static int ab8500_rtc_set_calibration(struct device *dev, int calibration) +{ + int retval; + u8 rtccal = 0; + + /* + * Check that the calibration value (which is in units of 0.5 parts-per-million) + * is in the AB8500's range for RtcCalibration register. + */ + if ((calibration < -127) || (calibration > 127)) { + dev_err(dev, "RtcCalibration value outside permitted range\n"); + return -EINVAL; + } + + /* + * The AB8500 uses sign (in bit7) and magnitude (in bits0-7) + * so need to convert to this sort of representation before writing + * into RtcCalibration register... + */ + if (calibration >= 0) + rtccal = 0x7F & calibration; + else + rtccal = ~(calibration -1) | 0x80; + + retval = abx500_set_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_CALIB_REG, rtccal); + + return retval; +} + +static int ab8500_rtc_get_calibration(struct device *dev, int *calibration) +{ + int retval; + u8 rtccal = 0; + + retval = abx500_get_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_CALIB_REG, &rtccal); + if (retval >= 0) { + /* + * The AB8500 uses sign (in bit7) and magnitude (in bits0-7) + * so need to convert value from RtcCalibration register into + * a two's complement signed value... + */ + if (rtccal & 0x80) + *calibration = 0 - (rtccal & 0x7F); + else + *calibration = 0x7F & rtccal; + } + + return retval; +} + +static ssize_t ab8500_sysfs_store_rtc_calibration(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + int calibration = 0; + + if (sscanf(buf, " %i ", &calibration) != 1) { + dev_err(dev, "Failed to store RTC calibration attribute\n"); + return -EINVAL; + } + + retval = ab8500_rtc_set_calibration(dev, calibration); + + return retval ? retval : count; +} + +static ssize_t ab8500_sysfs_show_rtc_calibration(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int retval = 0; + int calibration = 0; + + retval = ab8500_rtc_get_calibration(dev, &calibration); + if (retval < 0) { + dev_err(dev, "Failed to read RTC calibration attribute\n"); + sprintf(buf, "0\n"); + return retval; + } + + return sprintf(buf, "%d\n", calibration); +} + +static DEVICE_ATTR(rtc_calibration, S_IRUGO | S_IWUSR, + ab8500_sysfs_show_rtc_calibration, + ab8500_sysfs_store_rtc_calibration); + +static int ab8500_sysfs_rtc_register(struct device *dev) +{ + return device_create_file(dev, &dev_attr_rtc_calibration); +} + +static void ab8500_sysfs_rtc_unregister(struct device *dev) +{ + device_remove_file(dev, &dev_attr_rtc_calibration); +} + static irqreturn_t rtc_alarm_handler(int irq, void *data) { struct rtc_device *rtc = data; @@ -327,6 +427,13 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); + + err = ab8500_sysfs_rtc_register(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "sysfs RTC failed to register\n"); + return err; + } + return 0; } @@ -335,6 +442,8 @@ static int __devexit ab8500_rtc_remove(struct platform_device *pdev) struct rtc_device *rtc = platform_get_drvdata(pdev); int irq = platform_get_irq_byname(pdev, "ALARM"); + ab8500_sysfs_rtc_unregister(&pdev->dev); + free_irq(irq, rtc); rtc_device_unregister(rtc); platform_set_drvdata(pdev, NULL);