* [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc @ 2015-08-19 9:53 Suneel Garapati 2015-08-19 9:53 ` [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Suneel Garapati 2015-08-24 7:42 ` [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc Alexandre Belloni 0 siblings, 2 replies; 11+ messages in thread From: Suneel Garapati @ 2015-08-19 9:53 UTC (permalink / raw) To: linux-arm-kernel adds file for description on device node bindings for RTC found on Xilinx Zynq Ultrascale+ MPSoC. Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> --- Changes v3 - none Changes v2 - add examples for interrupt-names - change alm to alarm --- Documentation/devicetree/bindings/rtc/xlnx-rtc.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/xlnx-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt new file mode 100644 index 0000000..0df6f01 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt @@ -0,0 +1,25 @@ +* Xilinx Zynq Ultrascale+ MPSoC Real Time Clock + +RTC controller for the Xilinx Zynq MPSoC Real Time Clock +Separate IRQ lines for seconds and alarm + +Required properties: +- compatible: Should be "xlnx,zynqmp-rtc" +- reg: Physical base address of the controller and length + of memory mapped region. +- interrupts: IRQ lines for the RTC. +- interrupt-names: interrupt line names eg. "sec" "alarm" + +Optional: +- calibration: calibration value for 1 sec period which will + be programmed directly to calibration register + +Example: +rtc: rtc at ffa60000 { + compatible = "xlnx,zynqmp-rtc"; + reg = <0x0 0xffa60000 0x100>; + interrupt-parent = <&gic>; + interrupts = <0 26 4>, <0 27 4>; + interrupt-names = "alarm", "sec"; + calibration = <0x198233>; +}; -- 2.1.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-19 9:53 [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc Suneel Garapati @ 2015-08-19 9:53 ` Suneel Garapati 2015-08-19 18:19 ` Moritz Fischer 2015-08-24 7:43 ` Alexandre Belloni 2015-08-24 7:42 ` [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc Alexandre Belloni 1 sibling, 2 replies; 11+ messages in thread From: Suneel Garapati @ 2015-08-19 9:53 UTC (permalink / raw) To: linux-arm-kernel adds support for RTC controller found on Xilinx Zynq Ultrascale+ MPSoC platform. Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> --- 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 <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +/* 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"); -- 2.1.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-19 9:53 ` [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Suneel Garapati @ 2015-08-19 18:19 ` Moritz Fischer [not found] ` <c713c202-1d5e-4656-9e4f-1e15bc4dac14@googlegroups.com> 2015-08-24 7:43 ` Alexandre Belloni 1 sibling, 1 reply; 11+ messages in thread From: Moritz Fischer @ 2015-08-19 18:19 UTC (permalink / raw) To: linux-arm-kernel Hi Suneel, looks good, minor nit below. On Wed, Aug 19, 2015 at 2:53 AM, Suneel Garapati <suneel.garapati@xilinx.com> wrote: > adds support for RTC controller found on > Xilinx Zynq Ultrascale+ MPSoC platform. > > Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> > --- > 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 <http://www.gnu.org/licenses/>. > + * > + */ > + > +#include <linux/delay.h> > +#include <linux/init.h> > +#include <linux/io.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/platform_device.h> > +#include <linux/rtc.h> > + > +/* 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); Do you want to check for return value here? > + > + 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"); > -- > 2.1.2 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel Cheers, Moritz ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <c713c202-1d5e-4656-9e4f-1e15bc4dac14@googlegroups.com>]
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver [not found] ` <c713c202-1d5e-4656-9e4f-1e15bc4dac14@googlegroups.com> @ 2015-08-20 16:27 ` Moritz Fischer 0 siblings, 0 replies; 11+ messages in thread From: Moritz Fischer @ 2015-08-20 16:27 UTC (permalink / raw) To: linux-arm-kernel Hi Suneel On Wed, Aug 19, 2015 at 9:37 PM, <suneelgarapati@gmail.com> wrote: > Hi Moritz, > > devm_ioremap_resource validates the argument pointer of struct resource. > Hence no explicit validation of return value of platform_get_resource > function. > It seems to be common practice with all other drivers in drivers/rtc. Fair enough. Acked-by: Moritz Fischer <moritz.fischer@ettus.com> > > Regards, > Suneel > > On Wednesday, August 19, 2015 at 11:49:49 PM UTC+5:30, Moritz Fischer wrote: >> >> Hi Suneel, >> >> looks good, minor nit below. >> >> On Wed, Aug 19, 2015 at 2:53 AM, Suneel Garapati >> <suneel....@xilinx.com> wrote: >> > adds support for RTC controller found on >> > Xilinx Zynq Ultrascale+ MPSoC platform. >> > >> > Signed-off-by: Suneel Garapati <suneel....@xilinx.com> >> > --- >> > 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 <http://www.gnu.org/licenses/>. >> > + * >> > + */ >> > + >> > +#include <linux/delay.h> >> > +#include <linux/init.h> >> > +#include <linux/io.h> >> > +#include <linux/module.h> >> > +#include <linux/of.h> >> > +#include <linux/platform_device.h> >> > +#include <linux/rtc.h> >> > + >> > +/* 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); >> Do you want to check for return value here? >> > + >> > + 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"); >> > -- >> > 2.1.2 >> > >> > >> > _______________________________________________ >> > linux-arm-kernel mailing list >> > linux-ar... at lists.infradead.org >> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >> >> Cheers, >> >> Moritz Cheers, Moritz ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-19 9:53 ` [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Suneel Garapati 2015-08-19 18:19 ` Moritz Fischer @ 2015-08-24 7:43 ` Alexandre Belloni 2015-08-24 7:48 ` Michal Simek 1 sibling, 1 reply; 11+ messages in thread From: Alexandre Belloni @ 2015-08-24 7:43 UTC (permalink / raw) To: linux-arm-kernel On 19/08/2015 at 15:23:22 +0530, Suneel Garapati wrote : > adds support for RTC controller found on > Xilinx Zynq Ultrascale+ MPSoC platform. > > Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> > --- > 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 > Applied, thanks. -- Alexandre Belloni, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-24 7:43 ` Alexandre Belloni @ 2015-08-24 7:48 ` Michal Simek 2015-08-24 8:08 ` Alexandre Belloni 0 siblings, 1 reply; 11+ messages in thread From: Michal Simek @ 2015-08-24 7:48 UTC (permalink / raw) To: linux-arm-kernel On 08/24/2015 09:43 AM, Alexandre Belloni wrote: > On 19/08/2015 at 15:23:22 +0530, Suneel Garapati wrote : >> adds support for RTC controller found on >> Xilinx Zynq Ultrascale+ MPSoC platform. >> >> Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> >> --- >> 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 >> > Applied, thanks. > Thanks, Michal ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-24 7:48 ` Michal Simek @ 2015-08-24 8:08 ` Alexandre Belloni 2015-08-24 9:18 ` Michal Simek 0 siblings, 1 reply; 11+ messages in thread From: Alexandre Belloni @ 2015-08-24 8:08 UTC (permalink / raw) To: linux-arm-kernel On 24/08/2015 at 09:48:42 +0200, Michal Simek wrote : > On 08/24/2015 09:43 AM, Alexandre Belloni wrote: > > On 19/08/2015 at 15:23:22 +0530, Suneel Garapati wrote : > >> adds support for RTC controller found on > >> Xilinx Zynq Ultrascale+ MPSoC platform. > >> > >> Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> > >> --- > >> 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 > >> > > Applied, thanks. > > > Actually, I got the following message: A message that you sent could not be delivered to one or more of its recipients. This is a permanent error. The following address(es) failed: suneel.garapati at xilinx.com Unknown User I'm not fond of carrying patches with uncontactable authors. Is that a permanent error? -- Alexandre Belloni, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-24 8:08 ` Alexandre Belloni @ 2015-08-24 9:18 ` Michal Simek 2015-08-24 9:45 ` Alexandre Belloni 0 siblings, 1 reply; 11+ messages in thread From: Michal Simek @ 2015-08-24 9:18 UTC (permalink / raw) To: linux-arm-kernel Hi, On 08/24/2015 10:08 AM, Alexandre Belloni wrote: > On 24/08/2015 at 09:48:42 +0200, Michal Simek wrote : >> On 08/24/2015 09:43 AM, Alexandre Belloni wrote: >>> On 19/08/2015 at 15:23:22 +0530, Suneel Garapati wrote : >>>> adds support for RTC controller found on >>>> Xilinx Zynq Ultrascale+ MPSoC platform. >>>> >>>> Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> >>>> --- >>>> 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 >>>> >>> Applied, thanks. >>> >> > > Actually, I got the following message: > A message that you sent could not be delivered to one or more of its > recipients. This is a permanent error. The following address(es) failed: > > suneel.garapati at xilinx.com > Unknown User > > I'm not fond of carrying patches with uncontactable authors. Is that a > permanent error? Unfortunately. That guy left Xilinx last week but don't be scared that none will be responsible about this driver. I have well proven history on Linux and others project and I am here if you need to do some testing or ACK for changes. Just let me know when you need something. get_maintainer returns me and Soren that's why you shouldn't have any problem with it. [linux]$ ./scripts/get_maintainer.pl -f drivers/rtc/rtc-zynqmp.c Alessandro Zummo <a.zummo@towertech.it> (maintainer:REAL TIME CLOCK (RTC) SUBSYSTEM) Alexandre Belloni <alexandre.belloni@free-electrons.com> (maintainer:REAL TIME CLOCK (RTC) SUBSYSTEM) Michal Simek <michal.simek@xilinx.com> (supporter:ARM/ZYNQ ARCHITECTURE) "S?ren Brinkmann" <soren.brinkmann@xilinx.com> (reviewer) rtc-linux at googlegroups.com (open list:REAL TIME CLOCK (RTC) SUBSYSTEM) linux-arm-kernel at lists.infradead.org (moderated list:ARM/ZYNQ ARCHITECTURE) linux-kernel at vger.kernel.org (open list) Thanks, Michal ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-24 9:18 ` Michal Simek @ 2015-08-24 9:45 ` Alexandre Belloni 0 siblings, 0 replies; 11+ messages in thread From: Alexandre Belloni @ 2015-08-24 9:45 UTC (permalink / raw) To: linux-arm-kernel On 24/08/2015 at 11:18:19 +0200, Michal Simek wrote : > > I'm not fond of carrying patches with uncontactable authors. Is that a > > permanent error? > > Unfortunately. That guy left Xilinx last week but don't be scared that > none will be responsible about this driver. I have well proven history > on Linux and others project and I am here if you need to do some testing > or ACK for changes. Just let me know when you need something. > > get_maintainer returns me and Soren that's why you shouldn't have any > problem with it. > > [linux]$ ./scripts/get_maintainer.pl -f drivers/rtc/rtc-zynqmp.c > Alessandro Zummo <a.zummo@towertech.it> (maintainer:REAL TIME CLOCK > (RTC) SUBSYSTEM) > Alexandre Belloni <alexandre.belloni@free-electrons.com> > (maintainer:REAL TIME CLOCK (RTC) SUBSYSTEM) > Michal Simek <michal.simek@xilinx.com> (supporter:ARM/ZYNQ ARCHITECTURE) > "S?ren Brinkmann" <soren.brinkmann@xilinx.com> (reviewer) > rtc-linux at googlegroups.com (open list:REAL TIME CLOCK (RTC) SUBSYSTEM) > linux-arm-kernel at lists.infradead.org (moderated list:ARM/ZYNQ ARCHITECTURE) > linux-kernel at vger.kernel.org (open list) > Perfect, thanks! -- Alexandre Belloni, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc 2015-08-19 9:53 [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc Suneel Garapati 2015-08-19 9:53 ` [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Suneel Garapati @ 2015-08-24 7:42 ` Alexandre Belloni 1 sibling, 0 replies; 11+ messages in thread From: Alexandre Belloni @ 2015-08-24 7:42 UTC (permalink / raw) To: linux-arm-kernel On 19/08/2015 at 15:23:21 +0530, Suneel Garapati wrote : > adds file for description on device node bindings for RTC > found on Xilinx Zynq Ultrascale+ MPSoC. > > Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> > --- > Changes v3 > - none > Changes v2 > - add examples for interrupt-names > - change alm to alarm > --- > Documentation/devicetree/bindings/rtc/xlnx-rtc.txt | 25 ++++++++++++++++++++++ > 1 file changed, 25 insertions(+) > create mode 100644 Documentation/devicetree/bindings/rtc/xlnx-rtc.txt > Applied, thanks. -- Alexandre Belloni, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc @ 2015-08-14 15:09 Suneel Garapati 2015-08-14 15:09 ` [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Suneel Garapati 0 siblings, 1 reply; 11+ messages in thread From: Suneel Garapati @ 2015-08-14 15:09 UTC (permalink / raw) To: linux-arm-kernel adds file for description on device node bindings for RTC found on Xilinx Zynq Ultrascale+ MPSoC. Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> --- Changes v3 - none Changes v2 - add examples for interrupt-names - change alm to alarm --- Documentation/devicetree/bindings/rtc/xlnx-rtc.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/xlnx-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt new file mode 100644 index 0000000..0df6f01 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt @@ -0,0 +1,25 @@ +* Xilinx Zynq Ultrascale+ MPSoC Real Time Clock + +RTC controller for the Xilinx Zynq MPSoC Real Time Clock +Separate IRQ lines for seconds and alarm + +Required properties: +- compatible: Should be "xlnx,zynqmp-rtc" +- reg: Physical base address of the controller and length + of memory mapped region. +- interrupts: IRQ lines for the RTC. +- interrupt-names: interrupt line names eg. "sec" "alarm" + +Optional: +- calibration: calibration value for 1 sec period which will + be programmed directly to calibration register + +Example: +rtc: rtc at ffa60000 { + compatible = "xlnx,zynqmp-rtc"; + reg = <0x0 0xffa60000 0x100>; + interrupt-parent = <&gic>; + interrupts = <0 26 4>, <0 27 4>; + interrupt-names = "alarm", "sec"; + calibration = <0x198233>; +}; -- 2.1.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver 2015-08-14 15:09 Suneel Garapati @ 2015-08-14 15:09 ` Suneel Garapati 0 siblings, 0 replies; 11+ messages in thread From: Suneel Garapati @ 2015-08-14 15:09 UTC (permalink / raw) To: linux-arm-kernel adds support for RTC controller found on Xilinx Zynq Ultrascale+ MPSoC platform. Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> --- 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 <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +/* 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"); -- 2.1.2 ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2015-08-24 9:45 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-19 9:53 [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc Suneel Garapati
2015-08-19 9:53 ` [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Suneel Garapati
2015-08-19 18:19 ` Moritz Fischer
[not found] ` <c713c202-1d5e-4656-9e4f-1e15bc4dac14@googlegroups.com>
2015-08-20 16:27 ` Moritz Fischer
2015-08-24 7:43 ` Alexandre Belloni
2015-08-24 7:48 ` Michal Simek
2015-08-24 8:08 ` Alexandre Belloni
2015-08-24 9:18 ` Michal Simek
2015-08-24 9:45 ` Alexandre Belloni
2015-08-24 7:42 ` [PATCH v3 1/2] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc Alexandre Belloni
-- strict thread matches above, loose matches on Subject: below --
2015-08-14 15:09 Suneel Garapati
2015-08-14 15:09 ` [PATCH v3 2/2] drivers: rtc: add xilinx zynqmp rtc driver Suneel Garapati
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).