From patchwork Mon Apr 1 23:22:41 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alexander Clouter X-Patchwork-Id: 232839 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 28E0B2C0127 for ; Tue, 2 Apr 2013 10:27:00 +1100 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UMo4q-0006n0-Bk; Mon, 01 Apr 2013 23:23:48 +0000 Received: from marmot.wormnet.eu ([2a03:9800:10:2d:3203:b3a5:8bdc:5b68]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UMo4E-0006dl-33 for linux-arm-kernel@lists.infradead.org; Mon, 01 Apr 2013 23:23:13 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=digriz.org.uk; s=wopr; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=72P3PAtRFNQQSPaMJxMQSvgNWeRRHWRq3SDXOx3cnds=; b=A2s8cWpzohna0O/DOZeSQ5FqJt/YZhLx9NGkdojUSKdGH4jmPPY/wTqTMpYIL3U46BD1dxYftwtZOsfZsgVWITZTMobVDoxzlceBLhbS6wwqLV5EWshb9zlagqRfQRfQJQVc6AW47Wl1MkvG33Ezq/AbPD611yTxt0dt7J2lwtw=; Received: from [2a01:348:45:1000:e978:af85:4e49:7987] (helo=berk.digriz.org.uk) by marmot.wormnet.eu with smtp (Exim 4.80) (envelope-from ) id 1UMo3y-0002Hi-AG; Tue, 02 Apr 2013 00:22:58 +0100 Received: (nullmailer pid 17767 invoked by uid 1000); Mon, 01 Apr 2013 23:22:47 -0000 From: Alexander Clouter To: Alessandro Zummo , Hartley Sweeten , Grant Likely , Jason Cooper , Ryan Mallon , Rob Herring , Andrew Lunn Subject: [PATCH 2/6] rtc: rtc-m48t86: add hooks to support driver side memory mapping Date: Tue, 2 Apr 2013 00:22:41 +0100 Message-Id: <1364858565-17192-3-git-send-email-alex@digriz.org.uk> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1364858565-17192-1-git-send-email-alex@digriz.org.uk> References: <1364858565-17192-1-git-send-email-alex@digriz.org.uk> MIME-Version: 1.0 X-WormNet-Spam-Score: 0.6 (/) X-WormNet-Spam-Report: from marmot.wormnet.eu 1.7 KHOP_BIG_TO_CC Sent to 10+ recipients instaed of Bcc or a list -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.8 RDNS_NONE Delivered to internal network by a host with no rDNS Tokens: new, 76; hammy, 151; neutral, 176; spammy, 0. X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130401_192310_645741_A07E645E X-CRM114-Status: GOOD ( 20.15 ) X-Spam-Score: -0.3 (/) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-0.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- 1.7 KHOP_BIG_TO_CC Sent to 10+ recipients instaed of Bcc or a list -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: devicetree-discuss@lists.ozlabs.org, rtc-linux@googlegroups.com, linux-arm-kernel@lists.infradead.org, Alexander Clouter X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org If platform_data is not defined (as before), then named memory io ranges need to be defined ("rtc_index" and "rtc_data"). The driver then maps those regions and uses them as the RTC index and data addresses. Does compile with the following warnings, I cannot see the codepath affected myself: ---- drivers/rtc/rtc-m48t86.c: In function ‘m48t86_rtc_probe’: drivers/rtc/rtc-m48t86.c:180: warning: ‘res_index’ may be used uninitialized in this function drivers/rtc/rtc-m48t86.c:180: warning: ‘res_data’ may be used uninitialized in this function ---- Signed-off-by: Alexander Clouter --- drivers/rtc/rtc-m48t86.c | 230 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 173 insertions(+), 57 deletions(-) diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 25e0116..6f99e64 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #define M48T86_REG_SEC 0x00 #define M48T86_REG_SECALRM 0x01 @@ -41,40 +43,71 @@ #define DRV_VERSION "0.1" +struct m48t86_rtc_private_data { + void __iomem *io_index; + void __iomem *io_data; + + struct rtc_device *rtc; + struct m48t86_ops *ops; +}; + +static void m48t86_rtc_writebyte(struct device *dev, + unsigned char value, unsigned long addr) +{ + struct m48t86_rtc_private_data *priv = dev_get_drvdata(dev); + + if (priv->ops) { + priv->ops->writebyte(value, addr); + return; + } + + writeb(addr, priv->io_index); + writeb(value, priv->io_data); +} + +static unsigned char m48t86_rtc_readbyte(struct device *dev, + unsigned long addr) +{ + struct m48t86_rtc_private_data *priv = dev_get_drvdata(dev); + + if (priv->ops) + return priv->ops->readbyte(addr); + + writeb(addr, priv->io_index); + return readb(priv->io_data); +} static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; - struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; - reg = ops->readbyte(M48T86_REG_B); + reg = m48t86_rtc_readbyte(dev, M48T86_REG_B); if (reg & M48T86_REG_B_DM) { /* data (binary) mode */ - tm->tm_sec = ops->readbyte(M48T86_REG_SEC); - tm->tm_min = ops->readbyte(M48T86_REG_MIN); - tm->tm_hour = ops->readbyte(M48T86_REG_HOUR) & 0x3F; - tm->tm_mday = ops->readbyte(M48T86_REG_DOM); + tm->tm_sec = m48t86_rtc_readbyte(dev, M48T86_REG_SEC); + tm->tm_min = m48t86_rtc_readbyte(dev, M48T86_REG_MIN); + tm->tm_hour = m48t86_rtc_readbyte(dev, M48T86_REG_HOUR) & 0x3F; + tm->tm_mday = m48t86_rtc_readbyte(dev, M48T86_REG_DOM); /* tm_mon is 0-11 */ - tm->tm_mon = ops->readbyte(M48T86_REG_MONTH) - 1; - tm->tm_year = ops->readbyte(M48T86_REG_YEAR) + 100; - tm->tm_wday = ops->readbyte(M48T86_REG_DOW); + tm->tm_mon = m48t86_rtc_readbyte(dev, M48T86_REG_MONTH) - 1; + tm->tm_year = m48t86_rtc_readbyte(dev, M48T86_REG_YEAR) + 100; + tm->tm_wday = m48t86_rtc_readbyte(dev, M48T86_REG_DOW); } else { /* bcd mode */ - tm->tm_sec = bcd2bin(ops->readbyte(M48T86_REG_SEC)); - tm->tm_min = bcd2bin(ops->readbyte(M48T86_REG_MIN)); - tm->tm_hour = bcd2bin(ops->readbyte(M48T86_REG_HOUR) & 0x3F); - tm->tm_mday = bcd2bin(ops->readbyte(M48T86_REG_DOM)); + tm->tm_sec = bcd2bin(m48t86_rtc_readbyte(dev, M48T86_REG_SEC)); + tm->tm_min = bcd2bin(m48t86_rtc_readbyte(dev, M48T86_REG_MIN)); + tm->tm_hour = bcd2bin(m48t86_rtc_readbyte(dev, M48T86_REG_HOUR) & 0x3F); + tm->tm_mday = bcd2bin(m48t86_rtc_readbyte(dev, M48T86_REG_DOM)); /* tm_mon is 0-11 */ - tm->tm_mon = bcd2bin(ops->readbyte(M48T86_REG_MONTH)) - 1; - tm->tm_year = bcd2bin(ops->readbyte(M48T86_REG_YEAR)) + 100; - tm->tm_wday = bcd2bin(ops->readbyte(M48T86_REG_DOW)); + tm->tm_mon = bcd2bin(m48t86_rtc_readbyte(dev, M48T86_REG_MONTH)) - 1; + tm->tm_year = bcd2bin(m48t86_rtc_readbyte(dev, M48T86_REG_YEAR)) + 100; + tm->tm_wday = bcd2bin(m48t86_rtc_readbyte(dev, M48T86_REG_DOW)); } /* correct the hour if the clock is in 12h mode */ if (!(reg & M48T86_REG_B_H24)) - if (ops->readbyte(M48T86_REG_HOUR) & 0x80) + if (m48t86_rtc_readbyte(dev, M48T86_REG_HOUR) & 0x80) tm->tm_hour += 12; return rtc_valid_tm(tm); @@ -83,38 +116,36 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; - struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; - reg = ops->readbyte(M48T86_REG_B); + reg = m48t86_rtc_readbyte(dev, M48T86_REG_B); /* update flag and 24h mode */ reg |= M48T86_REG_B_SET | M48T86_REG_B_H24; - ops->writebyte(reg, M48T86_REG_B); + m48t86_rtc_writebyte(dev, reg, M48T86_REG_B); if (reg & M48T86_REG_B_DM) { /* data (binary) mode */ - ops->writebyte(tm->tm_sec, M48T86_REG_SEC); - ops->writebyte(tm->tm_min, M48T86_REG_MIN); - ops->writebyte(tm->tm_hour, M48T86_REG_HOUR); - ops->writebyte(tm->tm_mday, M48T86_REG_DOM); - ops->writebyte(tm->tm_mon + 1, M48T86_REG_MONTH); - ops->writebyte(tm->tm_year % 100, M48T86_REG_YEAR); - ops->writebyte(tm->tm_wday, M48T86_REG_DOW); + m48t86_rtc_writebyte(dev, tm->tm_sec, M48T86_REG_SEC); + m48t86_rtc_writebyte(dev, tm->tm_min, M48T86_REG_MIN); + m48t86_rtc_writebyte(dev, tm->tm_hour, M48T86_REG_HOUR); + m48t86_rtc_writebyte(dev, tm->tm_mday, M48T86_REG_DOM); + m48t86_rtc_writebyte(dev, tm->tm_mon + 1, M48T86_REG_MONTH); + m48t86_rtc_writebyte(dev, tm->tm_year % 100, M48T86_REG_YEAR); + m48t86_rtc_writebyte(dev, tm->tm_wday, M48T86_REG_DOW); } else { /* bcd mode */ - ops->writebyte(bin2bcd(tm->tm_sec), M48T86_REG_SEC); - ops->writebyte(bin2bcd(tm->tm_min), M48T86_REG_MIN); - ops->writebyte(bin2bcd(tm->tm_hour), M48T86_REG_HOUR); - ops->writebyte(bin2bcd(tm->tm_mday), M48T86_REG_DOM); - ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_REG_MONTH); - ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_REG_YEAR); - ops->writebyte(bin2bcd(tm->tm_wday), M48T86_REG_DOW); + m48t86_rtc_writebyte(dev, bin2bcd(tm->tm_sec), M48T86_REG_SEC); + m48t86_rtc_writebyte(dev, bin2bcd(tm->tm_min), M48T86_REG_MIN); + m48t86_rtc_writebyte(dev, bin2bcd(tm->tm_hour), M48T86_REG_HOUR); + m48t86_rtc_writebyte(dev, bin2bcd(tm->tm_mday), M48T86_REG_DOM); + m48t86_rtc_writebyte(dev, bin2bcd(tm->tm_mon + 1), M48T86_REG_MONTH); + m48t86_rtc_writebyte(dev, bin2bcd(tm->tm_year % 100), M48T86_REG_YEAR); + m48t86_rtc_writebyte(dev, bin2bcd(tm->tm_wday), M48T86_REG_DOW); } /* update ended */ reg &= ~M48T86_REG_B_SET; - ops->writebyte(reg, M48T86_REG_B); + m48t86_rtc_writebyte(dev, reg, M48T86_REG_B); return 0; } @@ -122,15 +153,13 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) { unsigned char reg; - struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; - reg = ops->readbyte(M48T86_REG_B); + reg = m48t86_rtc_readbyte(dev, M48T86_REG_B); seq_printf(seq, "mode\t\t: %s\n", (reg & M48T86_REG_B_DM) ? "binary" : "bcd"); - reg = ops->readbyte(M48T86_REG_D); + reg = m48t86_rtc_readbyte(dev, M48T86_REG_D); seq_printf(seq, "battery\t\t: %s\n", (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted"); @@ -144,34 +173,121 @@ static const struct rtc_class_ops m48t86_rtc_ops = { .proc = m48t86_rtc_proc, }; -static int m48t86_rtc_probe(struct platform_device *dev) +static int m48t86_rtc_probe(struct platform_device *pdev) { unsigned char reg; - struct m48t86_ops *ops = dev->dev.platform_data; - struct rtc_device *rtc = rtc_device_register("m48t86", - &dev->dev, &m48t86_rtc_ops, THIS_MODULE); - - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - platform_set_drvdata(dev, rtc); + int err; + struct resource *res_index, *res_data; + struct m48t86_rtc_private_data *priv; + + /* Allocate memory for the device structure (and zero it) */ + priv = kzalloc(sizeof(struct m48t86_rtc_private_data), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + if (!pdev->dev.platform_data) { + res_index = platform_get_resource_byname( + pdev, IORESOURCE_MEM, "rtc_index"); + if (!res_index) { + err = -ENXIO; + goto out_free; + } + + res_data = platform_get_resource_byname( + pdev, IORESOURCE_MEM, "rtc_data"); + if (!res_data) { + err = -ENXIO; + goto out_free; + } + + if (!request_mem_region(res_index->start, + resource_size(res_index), + dev_name(&pdev->dev))) { + err = -EBUSY; + goto out_free; + } + + if (!request_mem_region(res_data->start, + resource_size(res_data), + dev_name(&pdev->dev))) { + err = -EBUSY; + goto out_release_index; + } + + priv->io_index = ioremap(res_index->start, + resource_size(res_index)); + if (!priv->io_index) { + err = -EIO; + goto out_release_data; + } + + priv->io_data = ioremap(res_data->start, + resource_size(res_data)); + if (!priv->io_data) { + err = -EIO; + goto out_io_index; + } + } else + priv->ops = pdev->dev.platform_data; + + priv->rtc = rtc_device_register("m48t86", + &pdev->dev, &m48t86_rtc_ops, THIS_MODULE); + if (IS_ERR(priv->rtc)) { + err = PTR_ERR(priv->rtc); + if (!pdev->dev.platform_data) + goto out_io_data; + else + goto out_free; + } /* read battery status */ - reg = ops->readbyte(M48T86_REG_D); - dev_info(&dev->dev, "battery %s\n", + reg = m48t86_rtc_readbyte(&pdev->dev, M48T86_REG_D); + dev_info(&pdev->dev, "battery %s\n", (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted"); return 0; + +out_io_data: + iounmap(priv->io_data); +out_io_index: + iounmap(priv->io_index); +out_release_data: + release_mem_region(res_data->start, resource_size(res_data)); +out_release_index: + release_mem_region(res_index->start, resource_size(res_index)); +out_free: + platform_set_drvdata(pdev, NULL); + kfree(priv); + return err; } -static int m48t86_rtc_remove(struct platform_device *dev) +static int m48t86_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(dev); + struct resource *res; + struct m48t86_rtc_private_data *priv = platform_get_drvdata(pdev); + + if (priv->rtc) + rtc_device_unregister(priv->rtc); + + if (priv->io_data) { + iounmap(priv->io_data); + res = platform_get_resource_byname( + pdev, IORESOURCE_MEM, "rtc_data"); + release_mem_region(res->start, resource_size(res)); + } + + if (priv->io_index) { + iounmap(priv->io_index); + res = platform_get_resource_byname( + pdev, IORESOURCE_MEM, "rtc_index"); + release_mem_region(res->start, resource_size(res)); + } - if (rtc) - rtc_device_unregister(rtc); + platform_set_drvdata(pdev, NULL); - platform_set_drvdata(dev, NULL); + kfree(priv); return 0; }