From patchwork Wed Jan 18 08:17:04 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: zhzhl555@gmail.com X-Patchwork-Id: 136567 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-iy0-f184.google.com (mail-iy0-f184.google.com [209.85.210.184]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority" (not verified)) by ozlabs.org (Postfix) with ESMTPS id BDA51B6F9B for ; Wed, 18 Jan 2012 19:17:28 +1100 (EST) Received: by iahk25 with SMTP id k25sf25703216iah.11 for ; Wed, 18 Jan 2012 00:17:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=beta; h=mime-version:x-beenthere:received-spf:from:to:cc:subject:date :message-id:x-mailer: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=JWi0JVCPEL8JF7PFv/sxuvQIFXZWnUU3FSpT0e9zK98=; b=FQoRQ02GBdIqdFTVHDm7GG7vRVQZkHV15gbvVh1ndIVfKvKibWP5pPAjzUDro/vqpD Tdrm/tER7RtSFcAbvD3vXi39Pvmh/5BuK7l+CCxzNxFid70fnBAahRsdDFf6AqwswN/U vIXOHrEBZ/pUXueuAVpa7tOnMajTX8IYVmC50= Received: by 10.50.217.135 with SMTP id oy7mr5532347igc.0.1326874644398; Wed, 18 Jan 2012 00:17:24 -0800 (PST) MIME-Version: 1.0 X-BeenThere: rtc-linux@googlegroups.com Received: by 10.50.207.65 with SMTP id lu1ls13707557igc.0.canary; Wed, 18 Jan 2012 00:17:23 -0800 (PST) Received: by 10.50.149.130 with SMTP id ua2mr9352603igb.0.1326874643500; Wed, 18 Jan 2012 00:17:23 -0800 (PST) Received: by 10.50.149.130 with SMTP id ua2mr9352601igb.0.1326874643488; Wed, 18 Jan 2012 00:17:23 -0800 (PST) Received: from mail-iy0-f171.google.com (mail-iy0-f171.google.com [209.85.210.171]) by gmr-mx.google.com with ESMTPS id wm10si7247979igc.1.2012.01.18.00.17.23 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 18 Jan 2012 00:17:23 -0800 (PST) Received-SPF: pass (google.com: domain of zhzhl555@gmail.com designates 209.85.210.171 as permitted sender) client-ip=209.85.210.171; Received: by mail-iy0-f171.google.com with SMTP id k25so12273012iah.16 for ; Wed, 18 Jan 2012 00:17:23 -0800 (PST) Received: by 10.50.87.132 with SMTP id ay4mr1270389igb.2.1326874643357; Wed, 18 Jan 2012 00:17:23 -0800 (PST) Received: from localhost.localdomain ([182.148.112.76]) by mx.google.com with ESMTPS id 5sm86504429ibe.8.2012.01.18.00.17.16 (version=SSLv3 cipher=OTHER); Wed, 18 Jan 2012 00:17:21 -0800 (PST) From: zhzhl555@gmail.com To: a.zummo@towertech.it, rtc-linux@googlegroups.com, linux-mips@linux-mips.org, linux-kernel@vger.kernel.org Cc: ralf@linux-mips.org, keguang.zhang@gmail.com, wuzhangjin@gmail.com, r0bertz@gentoo.org, zhao zhang Subject: [rtc-linux] [PATCH V3] MIPS: Add RTC support for loongson1B Date: Wed, 18 Jan 2012 16:17:04 +0800 Message-Id: <1326874624-17867-1-git-send-email-zhzhl555@gmail.com> X-Mailer: git-send-email 1.7.0.4 X-Original-Sender: zhzhl555@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; spf=pass (google.com: domain of zhzhl555@gmail.com designates 209.85.210.171 as permitted sender) smtp.mail=zhzhl555@gmail.com; dkim=pass header.i=@gmail.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: zhao zhang This patch adds RTC support(TOY counter0) for loongson1B SOC change log: V3:Remove sync instruction. V2:Use new module_platform_driver macro. V1:Replace __raw_writel/__raw_readl with writel/readl. Signed-off-by: zhao zhang Acked-by: Linus Walleij --- drivers/rtc/Kconfig | 10 +++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-ls1x.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 0 deletions(-) create mode 100644 drivers/rtc/rtc-ls1x.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 5a538fc..6f8c2d7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1070,4 +1070,14 @@ config RTC_DRV_PUV3 This drive can also be built as a module. If so, the module will be called rtc-puv3. +config RTC_DRV_LOONGSON1 + tristate "loongson1 RTC support" + depends on MACH_LOONGSON1 + help + This is a driver for the loongson1 on-chip Counter0 (Time-Of-Year + counter) to be used as a RTC. + + This driver can also be built as a module. If so, the module + will be called rtc-ls1x. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6e69823..6c9387a 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o +obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M41T93) += rtc-m41t93.o obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c new file mode 100644 index 0000000..7305986 --- /dev/null +++ b/drivers/rtc/rtc-ls1x.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2011 Zhao Zhang + * + * Derived from driver/rtc/rtc-au1xxx.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LS1X_RTC_REG_OFFSET (LS1X_RTC_BASE + 0x20) +#define LS1X_RTC_REGS(x) \ + ((void __iomem *)KSEG1ADDR(LS1X_RTC_REG_OFFSET + (x))) + +/*RTC programmable counters 0 and 1*/ +#define SYS_COUNTER_CNTRL (LS1X_RTC_REGS(0x20)) +#define SYS_CNTRL_ERS (1 << 23) +#define SYS_CNTRL_RTS (1 << 20) +#define SYS_CNTRL_RM2 (1 << 19) +#define SYS_CNTRL_RM1 (1 << 18) +#define SYS_CNTRL_RM0 (1 << 17) +#define SYS_CNTRL_RS (1 << 16) +#define SYS_CNTRL_BP (1 << 14) +#define SYS_CNTRL_REN (1 << 13) +#define SYS_CNTRL_BRT (1 << 12) +#define SYS_CNTRL_TEN (1 << 11) +#define SYS_CNTRL_BTT (1 << 10) +#define SYS_CNTRL_E0 (1 << 8) +#define SYS_CNTRL_ETS (1 << 7) +#define SYS_CNTRL_32S (1 << 5) +#define SYS_CNTRL_TTS (1 << 4) +#define SYS_CNTRL_TM2 (1 << 3) +#define SYS_CNTRL_TM1 (1 << 2) +#define SYS_CNTRL_TM0 (1 << 1) +#define SYS_CNTRL_TS (1 << 0) + +/* Programmable Counter 0 Registers */ +#define SYS_TOYTRIM (LS1X_RTC_REGS(0)) +#define SYS_TOYWRITE0 (LS1X_RTC_REGS(4)) +#define SYS_TOYWRITE1 (LS1X_RTC_REGS(8)) +#define SYS_TOYREAD0 (LS1X_RTC_REGS(0xC)) +#define SYS_TOYREAD1 (LS1X_RTC_REGS(0x10)) +#define SYS_TOYMATCH0 (LS1X_RTC_REGS(0x14)) +#define SYS_TOYMATCH1 (LS1X_RTC_REGS(0x18)) +#define SYS_TOYMATCH2 (LS1X_RTC_REGS(0x1C)) + +/* Programmable Counter 1 Registers */ +#define SYS_RTCTRIM (LS1X_RTC_REGS(0x40)) +#define SYS_RTCWRITE0 (LS1X_RTC_REGS(0x44)) +#define SYS_RTCREAD0 (LS1X_RTC_REGS(0x48)) +#define SYS_RTCMATCH0 (LS1X_RTC_REGS(0x4C)) +#define SYS_RTCMATCH1 (LS1X_RTC_REGS(0x50)) +#define SYS_RTCMATCH2 (LS1X_RTC_REGS(0x54)) + +#define LS1X_SEC_OFFSET (4) +#define LS1X_MIN_OFFSET (10) +#define LS1X_HOUR_OFFSET (16) +#define LS1X_DAY_OFFSET (21) +#define LS1X_MONTH_OFFSET (26) + + +#define LS1X_SEC_MASK (0x3f) +#define LS1X_MIN_MASK (0x3f) +#define LS1X_HOUR_MASK (0x1f) +#define LS1X_DAY_MASK (0x1f) +#define LS1X_MONTH_MASK (0x3f) +#define LS1X_YEAR_MASK (0xffffffff) + +#define ls1x_get_sec(t) (((t) >> LS1X_SEC_OFFSET) & LS1X_SEC_MASK) +#define ls1x_get_min(t) (((t) >> LS1X_MIN_OFFSET) & LS1X_MIN_MASK) +#define ls1x_get_hour(t) (((t) >> LS1X_HOUR_OFFSET) & LS1X_HOUR_MASK) +#define ls1x_get_day(t) (((t) >> LS1X_DAY_OFFSET) & LS1X_DAY_MASK) +#define ls1x_get_month(t) (((t) >> LS1X_MONTH_OFFSET) & LS1X_MONTH_MASK) + +#define RTC_CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S) + +static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm) +{ + unsigned long v, t; + + v = readl(SYS_TOYREAD0); + t = readl(SYS_TOYREAD1); + + memset(rtm, 0, sizeof(struct rtc_time)); + t = mktime((t & LS1X_YEAR_MASK), ls1x_get_month(v), + ls1x_get_day(v), ls1x_get_hour(v), + ls1x_get_min(v), ls1x_get_sec(v)); + rtc_time_to_tm(t, rtm); + + return rtc_valid_tm(rtm); +} + +static int ls1x_rtc_set_time(struct device *dev, struct rtc_time *rtm) +{ + unsigned long v, t, c; + int ret = -ETIMEDOUT; + + v = ((rtm->tm_mon + 1) << LS1X_MONTH_OFFSET) + | (rtm->tm_mday << LS1X_DAY_OFFSET) + | (rtm->tm_hour << LS1X_HOUR_OFFSET) + | (rtm->tm_min << LS1X_MIN_OFFSET) + | (rtm->tm_sec << LS1X_SEC_OFFSET); + + writel(v, SYS_TOYWRITE0); + c = 0x10000; + /* add timeout check counter, for more safe */ + while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) + usleep_range(1000, 3000); + + if (!c) { + dev_err(dev, "set time timeout!\n"); + goto err; + } + + t = rtm->tm_year + 1900; + writel(t, SYS_TOYWRITE1); + c = 0x10000; + while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) + usleep_range(1000, 3000); + + if (!c) { + dev_err(dev, "set time timeout!\n"); + goto err; + } + return 0; +err: + return ret; +} + +static struct rtc_class_ops ls1x_rtc_ops = { + .read_time = ls1x_rtc_read_time, + .set_time = ls1x_rtc_set_time, +}; + +static int __devinit ls1x_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtcdev; + unsigned long v; + int ret; + + v = readl(SYS_COUNTER_CNTRL); + if (!(v & RTC_CNTR_OK)) { + dev_err(&pdev->dev, "rtc counters not working\n"); + ret = -ENODEV; + goto err; + } + ret = -ETIMEDOUT; + /* set to 1 HZ if needed */ + if (readl(SYS_TOYTRIM) != 32767) { + v = 0x100000; + while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) && --v) + usleep_range(1000, 3000); + + if (!v) { + dev_err(&pdev->dev, "time out\n"); + goto err; + } + writel(32767, SYS_TOYTRIM); + } + /* this loop coundn't be endless */ + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) + usleep_range(1000, 3000); + + rtcdev = rtc_device_register("ls1x-rtc", &pdev->dev, + &ls1x_rtc_ops , THIS_MODULE); + if (IS_ERR(rtcdev)) { + ret = PTR_ERR(rtcdev); + goto err; + } + + platform_set_drvdata(pdev, rtcdev); + return 0; +err: + return ret; +} + +static int __devexit ls1x_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtcdev = platform_get_drvdata(pdev); + + rtc_device_unregister(rtcdev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ls1x_rtc_driver = { + .driver = { + .name = "ls1x-rtc", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(ls1x_rtc_remove), + .probe = ls1x_rtc_probe, +}; + +module_platform_driver(ls1x_rtc_driver); + +MODULE_AUTHOR("zhao zhang "); +MODULE_LICENSE("GPL"); +