From patchwork Sun Jun 13 10:12:38 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 55414 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-ww0-f56.google.com (mail-ww0-f56.google.com [74.125.82.56]) by ozlabs.org (Postfix) with ESMTP id 2FF15B7D98 for ; Sun, 13 Jun 2010 20:12:43 +1000 (EST) Received: by wwi14 with SMTP id 14sf812020wwi.11 for ; Sun, 13 Jun 2010 03:12:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=beta; h=domainkey-signature:received:x-beenthere:received:received:received :received:received-spf:received:received:date:from:sender:to:cc :subject:message-id:user-agent:mime-version :x-original-authentication-results:x-original-sender:reply-to :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-subscribe:list-unsubscribe:content-type; bh=151HomPbsTQ/mleyPHQB84GPMksd8mJRoqG03Ig19Rg=; b=yMIcrKD/D0wAtwTrmfV+LoAOwW/j3NObf1vNoFAfB86FMGpp1tVDjbtbxQb6ci+5rj Yzesx6NPkVE9jPCTucjANXDQV+0aY7Wf79/zoEEBF1vs6QA78CGNtbKZZORAmsj+mjwO X44fjti7aLJTOVOUJoktMljjCwhBUEGaQQo6Y= DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlegroups.com; s=beta; h=x-beenthere:received-spf:date:from:sender:to:cc:subject:message-id :user-agent:mime-version:x-original-authentication-results :x-original-sender:reply-to:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-subscribe:list-unsubscribe :content-type; b=ZveRe7DQQqzaxzdVdWVY8QOm+hGjsDGEInEvh1qiadyGNiWOTJWf85azxGNlRLpcgU p0gVpTaVuQHdjGOM5Nicrh2swU394cKpnLf5tH3LB1NzX+hegiEtknvnazhouZDP3UV0 vCoOUH0/pzRYlHVfu+wGVg699l6yHpz6B+Oxo= Received: by 10.216.63.202 with SMTP id a52mr320432wed.21.1276423961187; Sun, 13 Jun 2010 03:12:41 -0700 (PDT) X-BeenThere: rtc-linux@googlegroups.com Received: by 10.216.213.8 with SMTP id z8ls3498242weo.1.p; Sun, 13 Jun 2010 03:12:39 -0700 (PDT) Received: by 10.216.170.140 with SMTP id p12mr206626wel.13.1276423959444; Sun, 13 Jun 2010 03:12:39 -0700 (PDT) Received: by 10.216.170.140 with SMTP id p12mr206625wel.13.1276423959419; Sun, 13 Jun 2010 03:12:39 -0700 (PDT) Received: from jacques.telenet-ops.be (jacques.telenet-ops.be [195.130.132.50]) by gmr-mx.google.com with ESMTP id d35si2340020wbd.2.2010.06.13.03.12.39; Sun, 13 Jun 2010 03:12:39 -0700 (PDT) Received-SPF: neutral (google.com: 195.130.132.50 is neither permitted nor denied by best guess record for domain of geert@linux-m68k.org) client-ip=195.130.132.50; Received: from ayla.of.borg ([94.224.189.190]) by jacques.telenet-ops.be with bizsmtp id VNCe1e00C46vLmN0JNCeyq; Sun, 13 Jun 2010 12:12:39 +0200 Received: from geert (helo=localhost) by ayla.of.borg with local-esmtp (Exim 4.71) (envelope-from ) id 1ONkBC-0004nl-Fd; Sun, 13 Jun 2010 12:12:38 +0200 Date: Sun, 13 Jun 2010 12:12:38 +0200 (CEST) From: Geert Uytterhoeven Sender: rtc-linux@googlegroups.com To: Alessandro Zummo cc: Linux/m68k , rtc-linux@googlegroups.com, Linux Kernel Development Subject: [rtc-linux] [PATCH] rtc: rp5c01 - Add NVRAM support Message-ID: User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) MIME-Version: 1.0 X-Original-Authentication-Results: gmr-mx.google.com; spf=neutral (google.com: 195.130.132.50 is neither permitted nor denied by best guess record for domain of geert@linux-m68k.org) smtp.mail=geert@linux-m68k.org X-Original-Sender: geert@linux-m68k.org Reply-To: rtc-linux@googlegroups.com Precedence: list Mailing-list: list rtc-linux@googlegroups.com; contact rtc-linux+owners@googlegroups.com List-ID: List-Post: , List-Help: , List-Archive: List-Subscribe: , List-Unsubscribe: , The Ricoh RP5C01 RTC contains 26 x 4 bits of NVRAM. Provide access to it via a sysfs "nvram" attribute file. Signed-off-by: Geert Uytterhoeven --- Question: Is a spinlock in priv the right kind of locking? Should I use e.g. rtc-device.ops_lock instead? diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index a95f733..36eb661 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -63,6 +63,8 @@ enum { struct rp5c01_priv { u32 __iomem *regs; struct rtc_device *rtc; + spinlock_t lock; /* against concurrent RTC/NVRAM access */ + struct bin_attribute nvram_attr; }; static inline unsigned int rp5c01_read(struct rp5c01_priv *priv, @@ -92,6 +94,7 @@ static int rp5c01_read_time(struct device *dev, struct rtc_time *tm) { struct rp5c01_priv *priv = dev_get_drvdata(dev); + spin_lock_irq(&priv->lock); rp5c01_lock(priv); tm->tm_sec = rp5c01_read(priv, RP5C01_10_SECOND) * 10 + @@ -111,6 +114,7 @@ static int rp5c01_read_time(struct device *dev, struct rtc_time *tm) tm->tm_year += 100; rp5c01_unlock(priv); + spin_unlock_irq(&priv->lock); return rtc_valid_tm(tm); } @@ -119,6 +123,7 @@ static int rp5c01_set_time(struct device *dev, struct rtc_time *tm) { struct rp5c01_priv *priv = dev_get_drvdata(dev); + spin_lock_irq(&priv->lock); rp5c01_lock(priv); rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND); @@ -139,6 +144,7 @@ static int rp5c01_set_time(struct device *dev, struct rtc_time *tm) rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR); rp5c01_unlock(priv); + spin_unlock_irq(&priv->lock); return 0; } @@ -147,6 +153,72 @@ static const struct rtc_class_ops rp5c01_rtc_ops = { .set_time = rp5c01_set_time, }; + +/* + * The NVRAM is organized as 2 blocks of 13 nibbles of 4 bits. + * We provide access to them like AmigaOS does: the high nibble of each 8-bit + * byte is stored in BLOCK10, the low nibble in BLOCK11. + */ + +static ssize_t rp5c01_nvram_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct rp5c01_priv *priv = dev_get_drvdata(dev); + ssize_t count; + + spin_lock_irq(&priv->lock); + + for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { + u8 data; + + rp5c01_write(priv, + RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK10, + RP5C01_MODE); + data = rp5c01_read(priv, pos) << 4; + rp5c01_write(priv, + RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK11, + RP5C01_MODE); + data |= rp5c01_read(priv, pos++); + rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01, + RP5C01_MODE); + *buf++ = data; + } + + spin_unlock_irq(&priv->lock); + return count; +} + +static ssize_t rp5c01_nvram_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct rp5c01_priv *priv = dev_get_drvdata(dev); + ssize_t count; + + spin_lock_irq(&priv->lock); + + for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { + u8 data = *buf++; + + rp5c01_write(priv, + RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK10, + RP5C01_MODE); + rp5c01_write(priv, data >> 4, pos); + rp5c01_write(priv, + RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK11, + RP5C01_MODE); + rp5c01_write(priv, data & 0xf, pos++); + rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01, + RP5C01_MODE); + } + + spin_unlock_irq(&priv->lock); + return count; +} + static int __init rp5c01_rtc_probe(struct platform_device *dev) { struct resource *res; @@ -168,6 +240,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) goto out_free_priv; } + sysfs_bin_attr_init(&priv->nvram_attr); + priv->nvram_attr.attr.name = "nvram"; + priv->nvram_attr.attr.mode = S_IRUGO | S_IWUSR; + priv->nvram_attr.read = rp5c01_nvram_read; + priv->nvram_attr.write = rp5c01_nvram_write; + priv->nvram_attr.size = RP5C01_MODE; + + spin_lock_init(&priv->lock); + rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -177,8 +258,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) priv->rtc = rtc; platform_set_drvdata(dev, priv); + + error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); + if (error) + goto out_unregister; + return 0; +out_unregister: + rtc_device_unregister(rtc); out_unmap: iounmap(priv->regs); out_free_priv: @@ -190,6 +278,7 @@ static int __exit rp5c01_rtc_remove(struct platform_device *dev) { struct rp5c01_priv *priv = platform_get_drvdata(dev); + sysfs_remove_bin_file(&dev->dev.kobj, &priv->nvram_attr); rtc_device_unregister(priv->rtc); iounmap(priv->regs); kfree(priv);