From patchwork Fri Nov 25 02:52:07 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: zhzhl555@gmail.com X-Patchwork-Id: 127636 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-bw0-f56.google.com (mail-bw0-f56.google.com [209.85.214.56]) (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 EE8FD1007D5 for ; Fri, 25 Nov 2011 13:55:00 +1100 (EST) Received: by bkbzu17 with SMTP id zu17sf3407929bkb.11 for ; Thu, 24 Nov 2011 18:54:55 -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=fZ/UFYOhVyN8f4w8/oSLhdOfoc1x0iaNSEynyuhsqYU=; b=ibOyzZVcdoWWes6VuxOItwEt+vHunjqrPw/wf3/ONbPCTJS2zpCJ8zpDWUwCcEgJ+I KrtNJ0qLUz44ejtkZxG9zKMHW4/OQ/kIzaCcEc7gaHYWgGCXH7ysp9FlrBKa+31OlsNG 9GYIhN0S5LJKxS7HzC9PtZ/xGjiqfztu77ATI= Received: by 10.204.41.201 with SMTP id p9mr3536324bke.18.1322189694894; Thu, 24 Nov 2011 18:54:54 -0800 (PST) MIME-Version: 1.0 X-BeenThere: rtc-linux@googlegroups.com Received: by 10.204.33.136 with SMTP id h8ls627694bkd.0.gmail; Thu, 24 Nov 2011 18:54:51 -0800 (PST) Received: by 10.100.59.18 with SMTP id h18mr8955724ana.46.1322189689885; Thu, 24 Nov 2011 18:54:49 -0800 (PST) Received: by 10.100.59.18 with SMTP id h18mr8955723ana.46.1322189689863; Thu, 24 Nov 2011 18:54:49 -0800 (PST) Received: from mail-yx0-f172.google.com (mail-yx0-f172.google.com [209.85.213.172]) by gmr-mx.google.com with ESMTPS id h59si3791494yhm.5.2011.11.24.18.54.49 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 24 Nov 2011 18:54:49 -0800 (PST) Received-SPF: pass (google.com: domain of zhzhl555@gmail.com designates 209.85.213.172 as permitted sender) client-ip=209.85.213.172; Received: by mail-yx0-f172.google.com with SMTP id l8so498387yen.3 for ; Thu, 24 Nov 2011 18:54:49 -0800 (PST) Received: by 10.101.180.38 with SMTP id h38mr3050434anp.1.1322189689685; Thu, 24 Nov 2011 18:54:49 -0800 (PST) Received: from localhost.localdomain ([182.148.112.76]) by mx.google.com with ESMTPS id 36sm28959588anz.2.2011.11.24.18.54.43 (version=SSLv3 cipher=OTHER); Thu, 24 Nov 2011 18:54:48 -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 V1] MIPS: Add RTC support for loongson1B Date: Fri, 25 Nov 2011 10:52:07 +0800 Message-Id: <1322189527-4761-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.213.172 as permitted sender) smtp.mail=zhzhl555@gmail.com; dkim=pass (test mode) 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 V1: replace __raw_writel/__raw_readl with writel/readl. thanks for Linus Wallei's advice. This patch adds RTC support(TOY counter0) for loongson1B. Signed-off-by: zhao zhang --- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-ls1x.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 224 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..48153fe 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -109,3 +109,4 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c new file mode 100644 index 0000000..c752a30 --- /dev/null +++ b/drivers/rtc/rtc-ls1x.c @@ -0,0 +1,213 @@ +/* + * 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; + + 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); + + t = rtm->tm_year + 1900; + writel(v, SYS_TOYWRITE0); + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) + usleep_range(1000, 3000); + __asm__ volatile ("sync"); + + writel(t, SYS_TOYWRITE1); + while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) + usleep_range(1000, 3000); + __asm__ volatile ("sync"); + + v = readl(SYS_COUNTER_CNTRL); + return 0; +} + +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); + __asm__ volatile("sync"); + } + /*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), +}; + +static int __init ls1x_rtc_init(void) +{ + return platform_driver_probe(&ls1x_rtc_driver, ls1x_rtc_probe); +} + +static void __exit ls1x_rtc_exit(void) +{ + platform_driver_unregister(&ls1x_rtc_driver); +} + + +module_init(ls1x_rtc_init); +module_exit(ls1x_rtc_exit); + + +MODULE_DESCRIPTION("LOONGSON1 TOY-counter-based RTC driver"); +MODULE_AUTHOR("zhao zhang "); +MODULE_LICENSE("GPL"); +