Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/817301/?format=api
{ "id": 817301, "url": "http://patchwork.ozlabs.org/api/patches/817301/?format=api", "web_url": "http://patchwork.ozlabs.org/project/rtc-linux/patch/5b2a7e5c9c5bc179f89e48fb614b2ae789be4254.1506049341.git.sean.wang@mediatek.com/", "project": { "id": 9, "url": "http://patchwork.ozlabs.org/api/projects/9/?format=api", "name": "Linux RTC development", "link_name": "rtc-linux", "list_id": "linux-rtc.vger.kernel.org", "list_email": "linux-rtc@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<5b2a7e5c9c5bc179f89e48fb614b2ae789be4254.1506049341.git.sean.wang@mediatek.com>", "list_archive_url": null, "date": "2017-09-22T03:33:15", "name": "[2/4] rtc: mediatek: add driver for RTC on MT7622 SoC", "commit_ref": null, "pull_url": null, "state": "changes-requested", "archived": false, "hash": "a7f6326b4aaee1267523ef1de1e37cb827f8da47", "submitter": { "id": 69660, "url": "http://patchwork.ozlabs.org/api/people/69660/?format=api", "name": "Sean Wang", "email": "sean.wang@mediatek.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/rtc-linux/patch/5b2a7e5c9c5bc179f89e48fb614b2ae789be4254.1506049341.git.sean.wang@mediatek.com/mbox/", "series": [ { "id": 4534, "url": "http://patchwork.ozlabs.org/api/series/4534/?format=api", "web_url": "http://patchwork.ozlabs.org/project/rtc-linux/list/?series=4534", "date": "2017-09-22T03:33:13", "name": "rtc: mediatek: add support for SoC based RTC on MT7622", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/4534/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/817301/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/817301/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<linux-rtc-owner@vger.kernel.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=linux-rtc-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xyzc13rzYz9t33\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 22 Sep 2017 13:34:09 +1000 (AEST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751886AbdIVDdn (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tThu, 21 Sep 2017 23:33:43 -0400", "from mailgw02.mediatek.com ([210.61.82.184]:36787 \"EHLO\n\tmailgw02.mediatek.com\" rhost-flags-OK-FAIL-OK-FAIL) by\n\tvger.kernel.org with ESMTP id S1751791AbdIVDdl (ORCPT\n\t<rfc822; linux-rtc@vger.kernel.org>); Thu, 21 Sep 2017 23:33:41 -0400", "from mtkexhb02.mediatek.inc [(172.21.101.103)] by\n\tmailgw02.mediatek.com (envelope-from <sean.wang@mediatek.com>)\n\t(mhqrelay.mediatek.com ESMTP with TLS)\n\twith ESMTP id 1102889353; Fri, 22 Sep 2017 11:33:36 +0800", "from mtkcas09.mediatek.inc (172.21.101.178) by\n\tmtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server\n\t(TLS) id 15.0.1210.3; Fri, 22 Sep 2017 11:33:16 +0800", "from mtkswgap22.mediatek.inc (172.21.77.33) by\n\tmtkcas09.mediatek.inc\n\t(172.21.101.73) with Microsoft SMTP Server id 15.0.1210.3 via\n\tFrontend Transport; Fri, 22 Sep 2017 11:33:51 +0800" ], "X-UUID": "99013c2a15c14cde8a94fb8521240032-20170922", "From": "<sean.wang@mediatek.com>", "To": "<a.zummo@towertech.it>, <alexandre.belloni@free-electrons.com>,\n\t<robh+dt@kernel.org>, <mark.rutland@arm.com>", "CC": "<linux-rtc@vger.kernel.org>, <devicetree@vger.kernel.org>,\n\t<linux-mediatek@lists.infradead.org>,\n\t<linux-kernel@vger.kernel.org>, Sean Wang <sean.wang@mediatek.com>", "Subject": "[PATCH 2/4] rtc: mediatek: add driver for RTC on MT7622 SoC", "Date": "Fri, 22 Sep 2017 11:33:15 +0800", "Message-ID": "<5b2a7e5c9c5bc179f89e48fb614b2ae789be4254.1506049341.git.sean.wang@mediatek.com>", "X-Mailer": "git-send-email 1.7.9.5", "In-Reply-To": "<cover.1506049341.git.sean.wang@mediatek.com>", "References": "<cover.1506049341.git.sean.wang@mediatek.com>", "MIME-Version": "1.0", "Content-Type": "text/plain", "X-MTK": "N", "Sender": "linux-rtc-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<linux-rtc.vger.kernel.org>", "X-Mailing-List": "linux-rtc@vger.kernel.org" }, "content": "From: Sean Wang <sean.wang@mediatek.com>\n\nThis patch introduces the driver for the RTC on MT7622 SoC.\n\nSigned-off-by: Sean Wang <sean.wang@mediatek.com>\n---\n drivers/rtc/Kconfig | 10 ++\n drivers/rtc/Makefile | 1 +\n drivers/rtc/rtc-mediatek.c | 398 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 409 insertions(+)\n create mode 100644 drivers/rtc/rtc-mediatek.c", "diff": "diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig\nindex e0e58f3..4226295 100644\n--- a/drivers/rtc/Kconfig\n+++ b/drivers/rtc/Kconfig\n@@ -1705,6 +1705,16 @@ config RTC_DRV_MOXART\n \t This driver can also be built as a module. If so, the module\n \t will be called rtc-moxart\n \n+config RTC_DRV_MEDIATEK\n+\ttristate \"MediaTek SoC based RTC\"\n+\tdepends on ARCH_MEDIATEK || COMPILE_TEST\n+\thelp\n+\t This enables support for the real time clock built in the MediaTek\n+\t SoCs.\n+\n+\t This drive can also be built as a module. If so, the module\n+\t will be called rtc-mediatek.\n+\n config RTC_DRV_MT6397\n \ttristate \"Mediatek Real Time Clock driver\"\n \tdepends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)\ndiff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile\nindex 7230014..ba0206a 100644\n--- a/drivers/rtc/Makefile\n+++ b/drivers/rtc/Makefile\n@@ -101,6 +101,7 @@ obj-$(CONFIG_RTC_DRV_MOXART)\t+= rtc-moxart.o\n obj-$(CONFIG_RTC_DRV_MPC5121)\t+= rtc-mpc5121.o\n obj-$(CONFIG_RTC_DRV_VRTC)\t+= rtc-mrst.o\n obj-$(CONFIG_RTC_DRV_MSM6242)\t+= rtc-msm6242.o\n+obj-$(CONFIG_RTC_DRV_MEDIATEK)\t+= rtc-mediatek.o\n obj-$(CONFIG_RTC_DRV_MT6397)\t+= rtc-mt6397.o\n obj-$(CONFIG_RTC_DRV_MV)\t+= rtc-mv.o\n obj-$(CONFIG_RTC_DRV_MXC)\t+= rtc-mxc.o\ndiff --git a/drivers/rtc/rtc-mediatek.c b/drivers/rtc/rtc-mediatek.c\nnew file mode 100644\nindex 0000000..c6c06fe\n--- /dev/null\n+++ b/drivers/rtc/rtc-mediatek.c\n@@ -0,0 +1,398 @@\n+/*\n+ * Driver for MediaTek SoC based RTC\n+ *\n+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>\n+ *\n+ * This program is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU General Public License as\n+ * published by the Free Software Foundation; either version 2 of\n+ * the License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+ * GNU General Public License for more details.\n+ */\n+\n+#include <linux/clk.h>\n+#include <linux/interrupt.h>\n+#include <linux/module.h>\n+#include <linux/of_address.h>\n+#include <linux/of_device.h>\n+#include <linux/platform_device.h>\n+#include <linux/rtc.h>\n+\n+#define MTK_RTC_DEV KBUILD_MODNAME\n+\n+#define MTK_RTC_PWRCHK1\t\t0x4\n+#define\tRTC_PWRCHK1_MAGIC\t0xc6\n+\n+#define MTK_RTC_PWRCHK2\t\t0x8\n+#define\tRTC_PWRCHK2_MAGIC\t0x9a\n+\n+#define MTK_RTC_KEY\t\t0xc\n+#define\tRTC_KEY_MAGIC\t\t0x59\n+\n+#define MTK_RTC_PROT1\t\t0x10\n+#define\tRTC_PROT1_MAGIC\t\t0xa3\n+\n+#define MTK_RTC_PROT2\t\t0x14\n+#define\tRTC_PROT2_MAGIC\t\t0x57\n+\n+#define MTK_RTC_PROT3\t\t0x18\n+#define\tRTC_PROT3_MAGIC\t\t0x67\n+\n+#define MTK_RTC_PROT4\t\t0x1c\n+#define\tRTC_PROT4_MAGIC\t\t0xd2\n+\n+#define MTK_RTC_CTL\t\t0x20\n+#define\tRTC_RC_STOP\t\tBIT(0)\n+\n+#define MTK_RTC_DEBNCE\t\t0x2c\n+#define\tRTC_DEBNCE_MASK\t\tGENMASK(2, 0)\n+\n+#define MTK_RTC_INT\t\t0x30\n+#define RTC_INT_AL_STA\t\tBIT(4)\n+\n+/* Ranges from 0x40 to 0x78 provide RTC time setup for year, month,\n+ * day of month, day of week, hour, minute and second.\n+ */\n+#define MTK_RTC_TREG(_t, _f)\t(0x40 + (0x4 * (_f)) + ((_t) * 0x20))\n+\n+#define MTK_RTC_AL_CTL\t\t0x7c\n+#define\tRTC_AL_EN\t\tBIT(0)\n+#define\tRTC_AL_ALL\t\tGENMASK(7, 0)\n+\n+/* Types of the function the RTC provides are time counter and alarm. */\n+enum {\n+\tMTK_TC,\n+\tMTK_AL\n+};\n+\n+/* Indexes are used for the pointer to relevant registers in MTK_RTC_TREG */\n+enum {\n+\tMTK_YEA,\n+\tMTK_MON,\n+\tMTK_DOM,\n+\tMTK_DOW,\n+\tMTK_HOU,\n+\tMTK_MIN,\n+\tMTK_SEC\n+};\n+\n+struct mtk_rtc {\n+\tstruct rtc_device *rtc;\n+\tvoid __iomem *base;\n+\tint irq;\n+\tstruct clk *clk;\n+};\n+\n+static void mtk_w32(struct mtk_rtc *rtc, u32 reg, u32 val)\n+{\n+\t__raw_writel(val, rtc->base + reg);\n+}\n+\n+static u32 mtk_r32(struct mtk_rtc *rtc, u32 reg)\n+{\n+\treturn __raw_readl(rtc->base + reg);\n+}\n+\n+static void mtk_rmw(struct mtk_rtc *rtc, u32 reg, u32 mask, u32 set)\n+{\n+\tu32 val;\n+\n+\tval = mtk_r32(rtc, reg);\n+\tval &= ~mask;\n+\tval |= set;\n+\tmtk_w32(rtc, reg, val);\n+}\n+\n+static void mtk_set(struct mtk_rtc *rtc, u32 reg, u32 val)\n+{\n+\tmtk_rmw(rtc, reg, 0, val);\n+}\n+\n+static void mtk_clr(struct mtk_rtc *rtc, u32 reg, u32 val)\n+{\n+\tmtk_rmw(rtc, reg, val, 0);\n+}\n+\n+static void mtk_rtc_hw_init(struct mtk_rtc *hw)\n+{\n+\t/* The setup of the init sequence is for allowing RTC got to work */\n+\tmtk_w32(hw, MTK_RTC_PWRCHK1, RTC_PWRCHK1_MAGIC);\n+\tmtk_w32(hw, MTK_RTC_PWRCHK2, RTC_PWRCHK2_MAGIC);\n+\tmtk_w32(hw, MTK_RTC_KEY, RTC_KEY_MAGIC);\n+\tmtk_w32(hw, MTK_RTC_PROT1, RTC_PROT1_MAGIC);\n+\tmtk_w32(hw, MTK_RTC_PROT2, RTC_PROT2_MAGIC);\n+\tmtk_w32(hw, MTK_RTC_PROT3, RTC_PROT3_MAGIC);\n+\tmtk_w32(hw, MTK_RTC_PROT4, RTC_PROT4_MAGIC);\n+\tmtk_rmw(hw, MTK_RTC_DEBNCE, RTC_DEBNCE_MASK, 0);\n+\tmtk_clr(hw, MTK_RTC_CTL, RTC_RC_STOP);\n+}\n+\n+static void mtk_rtc_get_alarm_or_time(struct mtk_rtc *hw, struct rtc_time *tm,\n+\t\t\t\t int time_alarm)\n+{\n+\tu32 year, mon, mday, wday, hour, min, sec;\n+\n+\t/*\n+\t * Read again until all fields are not changed for all fields in the\n+\t * consistent state.\n+\t */\n+\tdo {\n+\t\tyear = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_YEA));\n+\t\tmon = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MON));\n+\t\twday = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOW));\n+\t\tmday = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOM));\n+\t\thour = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_HOU));\n+\t\tmin = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MIN));\n+\t\tsec = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC));\n+\t} while (year != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_YEA)) ||\n+\t\t mon != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MON)) ||\n+\t\t mday != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOM))\t||\n+\t\t wday != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOW))\t||\n+\t\t hour != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_HOU))\t||\n+\t\t min != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MIN))\t||\n+\t\t sec != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC))\n+\t\t);\n+\n+\ttm->tm_sec = sec;\n+\ttm->tm_min = min;\n+\ttm->tm_hour = hour;\n+\ttm->tm_wday = wday;\n+\ttm->tm_mday = mday;\n+\ttm->tm_mon = mon - 1;\n+\ttm->tm_year = year;\n+\ttm->tm_year += 100;\n+}\n+\n+static void mtk_rtc_set_alarm_or_time(struct mtk_rtc *hw, struct rtc_time *tm,\n+\t\t\t\t int time_alarm)\n+{\n+\tmtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_YEA), tm->tm_year - 100);\n+\tmtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_MON), tm->tm_mon + 1);\n+\tmtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_DOW), tm->tm_wday);\n+\tmtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_DOM), tm->tm_mday);\n+\tmtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_HOU), tm->tm_hour);\n+\tmtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_MIN), tm->tm_min);\n+\tmtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC), tm->tm_sec);\n+}\n+\n+static irqreturn_t mtk_rtc_alarmirq(int irq, void *id)\n+{\n+\tstruct mtk_rtc *hw = (struct mtk_rtc *)id;\n+\tu32 irq_sta;\n+\n+\t/* Stop alarm also implicitly disable the alarm interrupt */\n+\tmtk_w32(hw, MTK_RTC_AL_CTL, 0);\n+\tirq_sta = mtk_r32(hw, MTK_RTC_INT);\n+\tif (irq_sta & RTC_INT_AL_STA) {\n+\t\trtc_update_irq(hw->rtc, 1, RTC_IRQF | RTC_AF);\n+\n+\t\t/* Ack alarm interrupt status */\n+\t\tmtk_w32(hw, MTK_RTC_INT, RTC_INT_AL_STA);\n+\t\treturn IRQ_HANDLED;\n+\t}\n+\n+\treturn IRQ_NONE;\n+}\n+\n+static int mtk_rtc_gettime(struct device *dev, struct rtc_time *tm)\n+{\n+\tstruct mtk_rtc *hw = dev_get_drvdata(dev);\n+\n+\tmtk_rtc_get_alarm_or_time(hw, tm, MTK_TC);\n+\n+\treturn rtc_valid_tm(tm);\n+}\n+\n+static int mtk_rtc_settime(struct device *dev, struct rtc_time *tm)\n+{\n+\tstruct mtk_rtc *hw = dev_get_drvdata(dev);\n+\n+\t/* Stop time counter before setting a new one*/\n+\tmtk_set(hw, MTK_RTC_CTL, RTC_RC_STOP);\n+\n+\t/* Epoch == 1900 */\n+\tif (tm->tm_year < 100 || tm->tm_year > 199)\n+\t\treturn -EINVAL;\n+\n+\tmtk_rtc_set_alarm_or_time(hw, tm, MTK_TC);\n+\n+\t/* Restart the time counter */\n+\tmtk_clr(hw, MTK_RTC_CTL, RTC_RC_STOP);\n+\n+\treturn 0;\n+}\n+\n+static int mtk_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)\n+{\n+\tstruct mtk_rtc *hw = dev_get_drvdata(dev);\n+\tstruct rtc_time *alrm_tm = &wkalrm->time;\n+\n+\tmtk_rtc_get_alarm_or_time(hw, alrm_tm, MTK_AL);\n+\n+\twkalrm->enabled = !!(mtk_r32(hw, MTK_RTC_AL_CTL) & RTC_AL_EN);\n+\twkalrm->pending = !!(mtk_r32(hw, MTK_RTC_INT) & RTC_INT_AL_STA);\n+\n+\treturn 0;\n+}\n+\n+static int mtk_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)\n+{\n+\tstruct mtk_rtc *hw = dev_get_drvdata(dev);\n+\tstruct rtc_time *alrm_tm = &wkalrm->time;\n+\n+\t/* Epoch == 1900 */\n+\tif (alrm_tm->tm_year < 100 || alrm_tm->tm_year > 199)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * Stop the alarm also implicitly including disables interrupt before\n+\t * setting a new one.\n+\t */\n+\tmtk_clr(hw, MTK_RTC_AL_CTL, RTC_AL_EN);\n+\n+\t/*\n+\t * Avoid contention between mtk_rtc_setalarm and IRQ handler so that\n+\t * disabling the interrupt and awaiting for pending IRQ handler to\n+\t * complete.\n+\t */\n+\tsynchronize_irq(hw->irq);\n+\n+\tmtk_rtc_set_alarm_or_time(hw, alrm_tm, MTK_AL);\n+\n+\t/* Restart the alarm with the new setup */\n+\tmtk_w32(hw, MTK_RTC_AL_CTL, RTC_AL_ALL);\n+\n+\treturn 0;\n+}\n+\n+static const struct rtc_class_ops mtk_rtc_ops = {\n+\t.read_time\t\t= mtk_rtc_gettime,\n+\t.set_time\t\t= mtk_rtc_settime,\n+\t.read_alarm\t\t= mtk_rtc_getalarm,\n+\t.set_alarm\t\t= mtk_rtc_setalarm,\n+};\n+\n+static const struct of_device_id mtk_rtc_match[] = {\n+\t{ .compatible = \"mediatek,mt7622-rtc\" },\n+\t{ .compatible = \"mediatek,soc-rtc\" },\n+\t{},\n+};\n+\n+static int mtk_rtc_probe(struct platform_device *pdev)\n+{\n+\tstruct mtk_rtc *hw;\n+\tstruct resource *res;\n+\tint ret;\n+\n+\thw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);\n+\tif (!hw)\n+\t\treturn -ENOMEM;\n+\n+\tplatform_set_drvdata(pdev, hw);\n+\n+\tres = platform_get_resource(pdev, IORESOURCE_MEM, 0);\n+\thw->base = devm_ioremap_resource(&pdev->dev, res);\n+\tif (IS_ERR(hw->base))\n+\t\treturn PTR_ERR(hw->base);\n+\n+\thw->clk = devm_clk_get(&pdev->dev, \"rtc\");\n+\tif (IS_ERR(hw->clk)) {\n+\t\tdev_err(&pdev->dev, \"No clock\\n\");\n+\t\treturn PTR_ERR(hw->clk);\n+\t}\n+\n+\tret = clk_prepare_enable(hw->clk);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\thw->irq = platform_get_irq(pdev, 0);\n+\tif (hw->irq < 0) {\n+\t\tdev_err(&pdev->dev, \"No IRQ resource\\n\");\n+\t\tret = hw->irq;\n+\t\tgoto err;\n+\t}\n+\n+\tret = devm_request_irq(&pdev->dev, hw->irq, mtk_rtc_alarmirq,\n+\t\t\t 0, dev_name(&pdev->dev), hw);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Can't request IRQ\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tmtk_rtc_hw_init(hw);\n+\n+\tdevice_init_wakeup(&pdev->dev, true);\n+\n+\thw->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,\n+\t\t\t\t\t &mtk_rtc_ops, THIS_MODULE);\n+\tif (IS_ERR(hw->rtc)) {\n+\t\tret = PTR_ERR(hw->rtc);\n+\t\tdev_err(&pdev->dev, \"Unable to register device\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tdev_info(&pdev->dev, \"MediaTek SoC based RTC enabled\\n\");\n+\n+\treturn 0;\n+err:\n+\tclk_disable_unprepare(hw->clk);\n+\n+\treturn ret;\n+}\n+\n+static int mtk_rtc_remove(struct platform_device *pdev)\n+{\n+\tstruct mtk_rtc *hw = platform_get_drvdata(pdev);\n+\n+\tclk_disable_unprepare(hw->clk);\n+\n+\treturn 0;\n+}\n+\n+#ifdef CONFIG_PM_SLEEP\n+static int mtk_rtc_suspend(struct device *dev)\n+{\n+\tstruct mtk_rtc *hw = dev_get_drvdata(dev);\n+\n+\tif (device_may_wakeup(dev))\n+\t\tenable_irq_wake(hw->irq);\n+\n+\treturn 0;\n+}\n+\n+static int mtk_rtc_resume(struct device *dev)\n+{\n+\tstruct mtk_rtc *hw = dev_get_drvdata(dev);\n+\n+\tif (device_may_wakeup(dev))\n+\t\tdisable_irq_wake(hw->irq);\n+\n+\treturn 0;\n+}\n+\n+static SIMPLE_DEV_PM_OPS(mtk_rtc_pm_ops, mtk_rtc_suspend, mtk_rtc_resume);\n+\n+#define MTK_RTC_PM_OPS (&mtk_rtc_pm_ops)\n+#else\t/* CONFIG_PM */\n+#define MTK_RTC_PM_OPS NULL\n+#endif\t/* CONFIG_PM */\n+\n+static struct platform_driver mtk_rtc_driver = {\n+\t.probe\t= mtk_rtc_probe,\n+\t.remove\t= mtk_rtc_remove,\n+\t.driver = {\n+\t\t.name = MTK_RTC_DEV,\n+\t\t.of_match_table = mtk_rtc_match,\n+\t\t.pm = MTK_RTC_PM_OPS,\n+\t},\n+};\n+\n+module_platform_driver(mtk_rtc_driver);\n+\n+MODULE_DESCRIPTION(\"MediaTek SoC based RTC Driver\");\n+MODULE_AUTHOR(\"Sean Wang <sean.wang@mediatek.com>\");\n+MODULE_LICENSE(\"GPL\");\n", "prefixes": [ "2/4" ] }