From patchwork Fri Aug 14 15:09:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suneel Garapati X-Patchwork-Id: 507448 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-vk0-x237.google.com (mail-vk0-x237.google.com [IPv6:2607:f8b0:400c:c05::237]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 008F3140291 for ; Sat, 15 Aug 2015 01:09:31 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.b=rLck/o59; dkim-atps=neutral Received: by vkaw128 with SMTP id w128sf4378694vka.1 for ; Fri, 14 Aug 2015 08:09:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20120806; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:spamdiagnosticoutput :spamdiagnosticmetadata:spamdiagnosticoutput:spamdiagnosticmetadata :spamdiagnosticoutput:spamdiagnosticmetadata:x-original-sender :x-original-authentication-results:reply-to:precedence:mailing-list :list-id:x-spam-checked-in-group:list-post:list-help:list-archive :sender:list-subscribe:list-unsubscribe; bh=fpuAGuHzV0sTXOWvdORUowcbgxJVMjOhrU1c9d/+Yp8=; b=rLck/o592TnIDpRevDRvNT5w+tB0OUiVPugKuYIQ4djf7vbMl959G64FQUcJrhn+PN aGWHzjfHiO/euavfmclIjQrmjxI0XWs+j6rSQ3hbDUPAYB2DjhhDbkx/fGbqBLNxY6nF Y0W0OdOCLqedVL6g3LjRcV9gA5q/YALXe8IVpppH2ryexdyP9VeyT6lyKTN4+sppa2Qr S6H9wt8cYcITpDa9SR1MP233jxibJTz2lYwB0Y50wWdvw7zhieXnDJu0/sR3AddwpDBM 2CV+GoYw4GbDC/nAZ7uQ/Oj2q55mUEnds7Zm28n41Mse2x8qjyG2AgHHwGayLEQ611Sp Ru1Q== X-Received: by 10.140.101.129 with SMTP id u1mr307297qge.27.1439564968834; Fri, 14 Aug 2015 08:09:28 -0700 (PDT) X-BeenThere: rtc-linux@googlegroups.com Received: by 10.140.96.76 with SMTP id j70ls1358876qge.11.gmail; Fri, 14 Aug 2015 08:09:28 -0700 (PDT) X-Received: by 10.13.207.1 with SMTP id r1mr12419388ywd.53.1439564968518; Fri, 14 Aug 2015 08:09:28 -0700 (PDT) Received: from na01-bl2-obe.outbound.protection.outlook.com (mail-bl2on0054.outbound.protection.outlook.com. [65.55.169.54]) by gmr-mx.google.com with ESMTPS id k128si634579ywe.0.2015.08.14.08.09.28 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 14 Aug 2015 08:09:28 -0700 (PDT) Received-SPF: pass (google.com: domain of suneel.garapati@xilinx.com designates 65.55.169.54 as permitted sender) client-ip=65.55.169.54; Received: from BY2FFO11OLC002.protection.gbl (10.1.14.32) by BY2FFO11HUB054.protection.gbl (10.1.14.243) with Microsoft SMTP Server (TLS) id 15.1.243.9; Fri, 14 Aug 2015 15:09:20 +0000 Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.60.83 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.60.83; helo=xsj-pvapsmtpgw01; Received: from xsj-pvapsmtpgw01 (149.199.60.83) by BY2FFO11OLC002.mail.protection.outlook.com (10.1.15.178) with Microsoft SMTP Server (TLS) id 15.1.243.9 via Frontend Transport; Fri, 14 Aug 2015 15:09:19 +0000 Received: from unknown-38-66.xilinx.com ([149.199.38.66] helo=xsj-pvapsmtp01) by xsj-pvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1ZQGbe-0003m3-OL; Fri, 14 Aug 2015 08:09:18 -0700 Received: from [127.0.0.1] (helo=localhost) by xsj-pvapsmtp01 with smtp (Exim 4.63) (envelope-from ) id 1ZQGbe-00086R-IQ; Fri, 14 Aug 2015 08:09:18 -0700 Received: from xsj-pvapsmtp01 (smtp3.xilinx.com [149.199.38.66]) by xsj-smtp-dlp2.xlnx.xilinx.com (8.13.8/8.13.1) with ESMTP id t7EF8l4Y010968; Fri, 14 Aug 2015 08:08:47 -0700 Received: from [172.23.64.217] (helo=xhd-lin64re105.xilinx.com) by xsj-pvapsmtp01 with esmtp (Exim 4.63) (envelope-from ) id 1ZQGbW-000850-SU; Fri, 14 Aug 2015 08:09:11 -0700 From: Suneel Garapati To: , , CC: Alexandre Belloni , , , Alessandro Zummo , Suneel Garapati Subject: [rtc-linux] [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Date: Fri, 14 Aug 2015 20:39:03 +0530 Message-ID: <1439564943-21590-2-git-send-email-suneel.garapati@xilinx.com> X-Mailer: git-send-email 2.1.2 In-Reply-To: <1439564943-21590-1-git-send-email-suneel.garapati@xilinx.com> References: <1439564943-21590-1-git-send-email-suneel.garapati@xilinx.com> X-RCIS-Action: ALLOW X-TM-AS-Product-Ver: IMSS-7.1.0.1224-8.0.0.1202-21744.005 X-TM-AS-User-Approved-Sender: Yes;Yes X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11OLC002; 1:oILkLWLsFyP0Gd1wNXf16iNthvfVq+8T52TYf/nNO695hcX5WjT8irzzEyMtcN7S7a/Exds9bISNHIXCH3LjAFUu6l4jtvjOBTNxG6jMEk7gzJQ3LZifrv8M288rDoIrJSimPmSmRiRa+xPu+b3uWYjZ14omXJzn2l+ppV+rxn+fuCJHsEoj3mgJOQoP7XDcmqZVnPhwHN9iugiDUiP4ZWGKbvSxcBnB/FbstHpsmq69Rns+ZaskS4H/uLylWMBKeX51jGnbLyan31IP28jcw+jSNBW62nykJObDstc/t4uSWB1JTaqMAA/rB1FuhvU28f/Qv0V9QmpzOy06Hj4NlofvYGoFTqRoAPqryYYXuJYaRK1Gs+9foAIH0kEzQ8cj X-Forefront-Antispam-Report: CIP:149.199.60.83; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(2980300002)(438002)(3050300001)(189002)(199003)(47776003)(2201001)(5001960100002)(15975445007)(87936001)(48376002)(50226001)(86362001)(5001770100001)(46102003)(36756003)(50466002)(575784001)(63266004)(106466001)(5003940100001)(81156007)(4001540100001)(189998001)(5001860100001)(36386004)(2950100001)(50986999)(62966003)(6806004)(107886002)(19580395003)(229853001)(19580405001)(92566002)(33646002)(77156002)(5001830100001)(64706001)(5003600100002)(76176999)(77096005)(2004002)(107986001)(4001430100001)(2101003); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2FFO11HUB054; H:xsj-pvapsmtpgw01; FPR:; SPF:Pass; PTR:unknown-60-83.xilinx.com; MX:1; A:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11HUB054; 2:CF+9wdfyHrnXBkNsrXYzxtKyMzS2Ems4sMgA7cOcSKZEbfoi8Vcq6vBUgRyZE1qJXvCftwRQEVidu1QqRrrx0X3/MphD8V8KwhmJVLIH1zPAoLV2NUHI4XvNIA5e2tgG+OnYulM4epnOWypM3+VdwsCQYUqCnUD0ajcM2aY0cA8=; 3:Y72GMnUlMV09x7E17A3cQmbaA6Z1GMtzcSH4/M8FKr7AyffI6HD9WEXJuA97pGTjx/MXfyINiUkxmGDnh/VD/K3NeoscpAxaSM3WY9A5gGIAsuTnOqUD3vaDTXMvmJ5XNehenGtnNpT+nNmI2M3GuVcmrAFiWcuRsS1taOS07lrH7mpK1StGFcWl4p6r1NuCZnBKCmlAXt9bGUDDhTV4a8rgU/1b65cdc0LDMNcIZNA=; 25:zUJ5tzmciv2q2GzCzqDpiWHIW+9J3eyIt2h6/6OnTHRhkJE2uP+6FeSTAzKhDOIZUFw2cUnDj8yKe5NslfIG5ApMHVJL46iYP+79aTTknmjLGwLs1Zz3aEl1T7LgDJP7tHfsZ/x+MKhOmJMyHvttepQh+yQ6iolyc8qQW9afPu4L9qarBcuU+GqflTfY+OJE08Pfaig9mCIMkHtYjLDrauF8vjxg2HJp6WxrdnkGXCNrVDDw/CrxwsRvV+yA1KcBR6GpFUt+AynD1L3zMkqVCQ== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2FFO11HUB054; X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11HUB054; 20:f6QQKk8sd8pa5qC3Wa/8YehaTVxJc1hnx0DcZUozcLh+KdEXexcNy3kKbKjjxUqFAQ4a0krPw/fehHXrVumNYuXTi2G5qyD7odvtmU3fISHBzdACly+OS1KgcbfRXbY6t6jniSoOtA3Kje7z+nk8wBvWAbXhyAqD6ais6/AnkL8caBDquY0hicznAGxvFdnzHJ7opcwZRhwmyC9oh60I9hZ6C/2kTuWZsZ2t9OKHhN+JNjEI9oepMDrIzmuWfD6BR/KXH5/VE0uBqlRJUZgCWHDmdSPFbrDezsdOWt+sEg3QETJ0iNHp5BQ2idEvYMk2DKWEFULYJlM8Sw2UMUUvjwxCi032wdQKz0Bc6nmlqlISCX9yzdWdI+GWK3hqKZGX/Yw5q5gejN3I+d5P5S0Gb2a6pRjSqFnEaSCx2hIQFo2uaMJFgvr54o5hmdqBOnAI2DhB0GRvmdQqDAg69kMseW83H1ZoOrG3FSC5wY1yJms0h027g88r8Mvc2mkYg/oB; 4:cRFDO+BkAvZE5mdOw4FeDJzUsmcXXuTq1RUwk7FGs9tguf7jtpxkD3D4SBZMpvB1Zbu6CPs1bQnwB2rgpC589Z3VDSEbujwZULIUmgYuuPuSTLAXT1mgq2ofzQM/2XgQlpwNppt+33jDGRVpWEwGEW0gW+q6n/jQ99nwIJSj4Gue4LrrsMmr5fNqT1vNMOYzmDrzj+dYGah323XY8LuQZFAydSDxmXxV2wuN8KOYkOo7tBa0yv4KPMPrf0o5EikcXdSXpJ6ETkPaHeDJo7GH07r+lZiwxnYdKckJyEblBrAn2Yi87QzsYyUsLWykFeCLafLuIn2qSbOxk9RqNDGZ2Eof81q5YHotSoJw0eaWckU= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(8121501024)(8121501016)(3002001); SRVR:BY2FFO11HUB054; BCL:0; PCL:0; RULEID:; SRVR:BY2FFO11HUB054; X-Forefront-PRVS: 066898046A X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY2FFO11HUB054; 23:Jxfk5GYQDFovo1WpOfMdcSEOthsmk5H6wZf1nSC5?= =?us-ascii?Q?MFBzzU49qzfdaLKLd83U96RCNbG3j+upD57PljhJJrm7uSDqH090kNzKhE9h?= =?us-ascii?Q?FTiQOPVGeBimM+dliIJs/J1BmdLV64NZPItwGiesTYH4Nr6QVE6Q7w4g+ToM?= =?us-ascii?Q?KrwVLenVC8L1V//4hT7kOdGMcx/PRuRcUPNBm1pBClox1CFw3PYnIEVCySIN?= =?us-ascii?Q?tdzT8UhlOgh8TKB3Nybn94wfqaX3Bad0CjQxPL5bvrTaTvIhFpTP3iRxOhQr?= =?us-ascii?Q?SKfPQiCx3xx26+9kJYlb1PfnAG4LwD9b4GZECDpsCkieRY/nYaS63P4roM6E?= =?us-ascii?Q?BOqAjdmEPLhJv1xdUEgreZVhkwIboP996kPH8bXkr240qdjd+oRGfbTphuq0?= =?us-ascii?Q?59VHgkYQMPzqIIGVDcxYj2MBTy1q9dmoR2C9KIUsnSPUEx+4+Ypri+bgTe1Y?= =?us-ascii?Q?iLWtCNUat7fJmsirSZU7sXL5AACQhZQNktz0I8tYAW0svIe5bwjeYlLbCKmR?= =?us-ascii?Q?eUrJKZxW7L28R7d3bCCd5Y+Z+ctl14jSabnMNwxdgh65SfF4lL4fx/20+qp/?= =?us-ascii?Q?c8UmHxzbxISK45gOp0Rtm4ylJmD/euI9H8eN6R2PiJC5rs1OCx/L7h9VVuL7?= =?us-ascii?Q?+NOkc6YP2RUU+2ml8QWkGzAUdjIeX33B4LT+eOdcbZp8X0swZVmxiNPfEt+V?= =?us-ascii?Q?XbER8KG9RTCaJ0/B7FULnAMJ99fEGtLhe+HJimj7DCFhsd8C2VRfw/v/89bY?= =?us-ascii?Q?ohJkg9aHgYmnCtqgHBLN6mzxeMRYsg4mhPE1fcTZp6Aw+aVL7M96EqOLFWtv?= =?us-ascii?Q?0Wd6Yq2hF7hn+e6e2WOEUyA7V3SqZLZuOrBVX9uOXdRCaUu5ry/cYB9U806x?= =?us-ascii?Q?47PholGwKWHkkrmud7XJ+vKERe7e7vV4Utq3jyFWoeW7Ydsix1HQVJfjdDXm?= =?us-ascii?Q?V81zt3yzeMMUz9bFJUjRemBGh1/zE6+l1VxwXxgSylf5Zt6UYealXYYSOUPq?= =?us-ascii?Q?xA5kEaWCQSlEABEkCvhKKtT344q5eKnRYsFjESMcJDjrEfHaJB2q4r5ssr4N?= =?us-ascii?Q?X4WCJ9AAOFtWn9W3IGteFehuT82s0NqptJ0Y4JclzmClqP67Y1dXgWjl/Ybi?= =?us-ascii?Q?CwiQfWzMOHr1XDVFquOvir7P8yhpcJnAhNZyjCWR9m6s5PyE7ZNLpjPISKnB?= =?us-ascii?Q?g925ry1EV/G4KaBOZoYFc0+HVnYQeXIqnPuj0IDws+FUI7qb5XAgHcMFvzmS?= =?us-ascii?Q?KXTb+sCYMxiA/y1SuHd1doXAuGnCm6ZCXZBTdYo0?= X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11HUB054; 5:nWMMC1+DgHJ+dtMVIrm6vC3ld73FtBWC/o/lD74U8cfvrCRRFsoUiu/l0sUH87je19Ypty9VINSED71l07lqzoFgTRgMojm8GDuYqWTo4ZQdSRrUnLOPG1XU05HIxGDZUM9KDEi5IbE/slReN58P/w==; 24:tAoTfO5Rn6q1nXrZCJMsbCRY++R8Wjf+3eiKI+y33TACO2bUhbecI2EO7+Z4wQRlA+y1WwIA/QRXCjMTAeCkUgnfgkmeQdD+ISdEcXEk9OU= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Aug 2015 15:09:19.0212 (UTC) X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.60.83]; Helo=[xsj-pvapsmtpgw01] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2FFO11HUB054 X-Original-Sender: suneel.garapati@xilinx.com X-Original-Authentication-Results: gmr-mx.google.com; spf=pass (google.com: domain of suneel.garapati@xilinx.com designates 65.55.169.54 as permitted sender) smtp.mailfrom=suneel.garapati@xilinx.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-Spam-Checked-In-Group: rtc-linux@googlegroups.com X-Google-Group-Id: 712029733259 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , adds support for RTC controller found on Xilinx Zynq Ultrascale+ MPSoC platform. Signed-off-by: Suneel Garapati --- Changes v3 - fix checkpatch errors - check time in secs arg against max sec val - order header files - use ptr_err_or_zero macro - use time64 variants Changes v2 - change alm to alarm --- drivers/rtc/Kconfig | 7 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-zynqmp.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/rtc/rtc-zynqmp.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 35ea04c..bc96277 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1116,6 +1116,13 @@ config RTC_DRV_OPAL This driver can also be built as a module. If so, the module will be called rtc-opal. +config RTC_DRV_ZYNQMP + tristate "Xilinx Zynq Ultrascale+ MPSoC RTC" + depends on OF + help + If you say yes here you get support for the RTC controller found on + Xilinx Zynq Ultrascale+ MPSoC. + comment "on-CPU RTC drivers" config RTC_DRV_DAVINCI diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2797384..e491eb5 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -159,3 +159,4 @@ 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_XGENE) += rtc-xgene.o +obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c new file mode 100644 index 0000000..8b28762 --- /dev/null +++ b/drivers/rtc/rtc-zynqmp.c @@ -0,0 +1,279 @@ +/* + * Xilinx Zynq Ultrascale+ MPSoC Real Time Clock Driver + * + * Copyright (C) 2015 Xilinx, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* RTC Registers */ +#define RTC_SET_TM_WR 0x00 +#define RTC_SET_TM_RD 0x04 +#define RTC_CALIB_WR 0x08 +#define RTC_CALIB_RD 0x0C +#define RTC_CUR_TM 0x10 +#define RTC_CUR_TICK 0x14 +#define RTC_ALRM 0x18 +#define RTC_INT_STS 0x20 +#define RTC_INT_MASK 0x24 +#define RTC_INT_EN 0x28 +#define RTC_INT_DIS 0x2C +#define RTC_CTRL 0x40 + +#define RTC_FR_EN BIT(20) +#define RTC_FR_DATSHIFT 16 +#define RTC_TICK_MASK 0xFFFF +#define RTC_INT_SEC BIT(0) +#define RTC_INT_ALRM BIT(1) +#define RTC_OSC_EN BIT(24) + +#define RTC_CALIB_DEF 0x198233 +#define RTC_CALIB_MASK 0x1FFFFF +#define RTC_SEC_MAX_VAL 0xFFFFFFFF + +struct xlnx_rtc_dev { + struct rtc_device *rtc; + void __iomem *reg_base; + int alarm_irq; + int sec_irq; +}; + +static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + unsigned long new_time; + + new_time = rtc_tm_to_time64(tm); + + if (new_time > RTC_SEC_MAX_VAL) + return -EINVAL; + + writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR); + + return 0; +} + +static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm); + + return rtc_valid_tm(tm); +} + +static int xlnx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_ALRM), &alrm->time); + alrm->enabled = readl(xrtcdev->reg_base + RTC_INT_MASK) & RTC_INT_ALRM; + + return 0; +} + +static int xlnx_rtc_alarm_irq_enable(struct device *dev, u32 enabled) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + if (enabled) + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN); + else + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS); + + return 0; +} + +static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + unsigned long alarm_time; + + alarm_time = rtc_tm_to_time64(&alrm->time); + + if (alarm_time > RTC_SEC_MAX_VAL) + return -EINVAL; + + writel((u32)alarm_time, (xrtcdev->reg_base + RTC_ALRM)); + + xlnx_rtc_alarm_irq_enable(dev, alrm->enabled); + + return 0; +} + +static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev, u32 calibval) +{ + /* + * Based on crystal freq of 33.330 KHz + * set the seconds counter and enable, set fractions counter + * to default value suggested as per design spec + * to correct RTC delay in frequency over period of time. + */ + calibval &= RTC_CALIB_MASK; + writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR)); +} + +static const struct rtc_class_ops xlnx_rtc_ops = { + .set_time = xlnx_rtc_set_time, + .read_time = xlnx_rtc_read_time, + .read_alarm = xlnx_rtc_read_alarm, + .set_alarm = xlnx_rtc_set_alarm, + .alarm_irq_enable = xlnx_rtc_alarm_irq_enable, +}; + +static irqreturn_t xlnx_rtc_interrupt(int irq, void *id) +{ + struct xlnx_rtc_dev *xrtcdev = (struct xlnx_rtc_dev *)id; + unsigned int status; + + status = readl(xrtcdev->reg_base + RTC_INT_STS); + /* Check if interrupt asserted */ + if (!(status & (RTC_INT_SEC | RTC_INT_ALRM))) + return IRQ_NONE; + + /* Clear interrupt */ + writel(status, xrtcdev->reg_base + RTC_INT_STS); + + if (status & RTC_INT_SEC) + rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_UF); + if (status & RTC_INT_ALRM) + rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int xlnx_rtc_probe(struct platform_device *pdev) +{ + struct xlnx_rtc_dev *xrtcdev; + struct resource *res; + int ret; + unsigned int calibvalue; + + xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL); + if (!xrtcdev) + return -ENOMEM; + + platform_set_drvdata(pdev, xrtcdev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + xrtcdev->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xrtcdev->reg_base)) + return PTR_ERR(xrtcdev->reg_base); + + xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm"); + if (xrtcdev->alarm_irq < 0) { + dev_err(&pdev->dev, "no irq resource\n"); + return xrtcdev->alarm_irq; + } + ret = devm_request_irq(&pdev->dev, xrtcdev->alarm_irq, + xlnx_rtc_interrupt, 0, + dev_name(&pdev->dev), xrtcdev); + if (ret) { + dev_err(&pdev->dev, "request irq failed\n"); + return ret; + } + + xrtcdev->sec_irq = platform_get_irq_byname(pdev, "sec"); + if (xrtcdev->sec_irq < 0) { + dev_err(&pdev->dev, "no irq resource\n"); + return xrtcdev->sec_irq; + } + ret = devm_request_irq(&pdev->dev, xrtcdev->sec_irq, + xlnx_rtc_interrupt, 0, + dev_name(&pdev->dev), xrtcdev); + if (ret) { + dev_err(&pdev->dev, "request irq failed\n"); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, "calibration", + &calibvalue); + if (ret) + calibvalue = RTC_CALIB_DEF; + + xlnx_init_rtc(xrtcdev, calibvalue); + + device_init_wakeup(&pdev->dev, 1); + + xrtcdev->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &xlnx_rtc_ops, THIS_MODULE); + return PTR_ERR_OR_ZERO(xrtcdev->rtc); +} + +static int xlnx_rtc_remove(struct platform_device *pdev) +{ + xlnx_rtc_alarm_irq_enable(&pdev->dev, 0); + device_init_wakeup(&pdev->dev, 0); + + return 0; +} + +static int __maybe_unused xlnx_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(xrtcdev->alarm_irq); + else + xlnx_rtc_alarm_irq_enable(dev, 0); + + return 0; +} + +static int __maybe_unused xlnx_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(xrtcdev->alarm_irq); + else + xlnx_rtc_alarm_irq_enable(dev, 1); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xlnx_rtc_pm_ops, xlnx_rtc_suspend, xlnx_rtc_resume); + +static const struct of_device_id xlnx_rtc_of_match[] = { + {.compatible = "xlnx,zynqmp-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match); + +static struct platform_driver xlnx_rtc_driver = { + .probe = xlnx_rtc_probe, + .remove = xlnx_rtc_remove, + .driver = { + .name = KBUILD_MODNAME, + .pm = &xlnx_rtc_pm_ops, + .of_match_table = xlnx_rtc_of_match, + }, +}; + +module_platform_driver(xlnx_rtc_driver); + +MODULE_DESCRIPTION("Xilinx Zynq MPSoC RTC driver"); +MODULE_AUTHOR("Xilinx Inc."); +MODULE_LICENSE("GPL v2");