From: Alexandre Belloni <alexandre.belloni@bootlin.com>
To: Jan Kotas <jank@cadence.com>
Cc: a.zummo@towertech.it, robh+dt@kernel.org, mark.rutland@arm.com,
linux-rtc@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] rtc: Add Cadence RTC driver
Date: Thu, 10 Jan 2019 23:27:26 +0100 [thread overview]
Message-ID: <20190110222726.GI2362@piout.net> (raw)
In-Reply-To: <20190108122242.12411-3-jank@cadence.com>
Hello,
On 08/01/2019 12:22:42+0000, Jan Kotas wrote:
> drivers/rtc/Kconfig | 10 ++
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-cadence.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++
I would prefer a name that is a bit less generic, unless you can
guarantee this driver will be able to handle every RTCs from Cadence.
> +static int cdns_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> + struct cdns_rtc *crtc = dev_get_drvdata(dev);
> +
> + if (enabled) {
> + writel((CDNS_RTC_AEI_SEC | CDNS_RTC_AEI_MIN | CDNS_RTC_AEI_HOUR
> + | CDNS_RTC_AEI_DATE | CDNS_RTC_AEI_SEC),
CDNS_RTC_AEI_SEC is used twice here.
> + crtc->regs + CDNS_RTC_AENR);
> + writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IENR);
> + } else {
> + writel(0, crtc->regs + CDNS_RTC_AENR);
> + writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IDISR);
> + }
> +
> + return 0;
> +}
> +
> +static int cdns_rtc_probe(struct platform_device *pdev)
> +{
> + struct cdns_rtc *crtc;
> + struct resource *res;
> + int ret;
> + unsigned long ref_clk_freq;
> +
> + crtc = devm_kzalloc(&pdev->dev, sizeof(*crtc), GFP_KERNEL);
> + if (!crtc)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + crtc->regs = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(crtc->regs))
> + return PTR_ERR(crtc->regs);
> +
> + crtc->irq = platform_get_irq(pdev, 0);
> + if (crtc->irq < 0)
> + return -EINVAL;
> +
> + crtc->pclk = devm_clk_get(&pdev->dev, "pclk");
> + if (IS_ERR(crtc->pclk)) {
> + ret = PTR_ERR(crtc->pclk);
> + dev_err(&pdev->dev,
> + "Failed to retrieve the peripheral clock, %d\n", ret);
> + return ret;
> + }
> +
> + crtc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
> + if (IS_ERR(crtc->ref_clk)) {
> + ret = PTR_ERR(crtc->ref_clk);
> + dev_err(&pdev->dev,
> + "Failed to retrieve the reference clock, %d\n", ret);
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(crtc->pclk);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "Failed to enable the peripheral clock, %d\n", ret);
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(crtc->ref_clk);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "Failed to enable the reference clock, %d\n", ret);
> + goto err_disable_pclk;
> + }
> +
> + ref_clk_freq = clk_get_rate(crtc->ref_clk);
> + if ((ref_clk_freq != 1) && (ref_clk_freq != 100)) {
> + dev_err(&pdev->dev,
> + "Invalid reference clock frequency %lu Hz.\n",
> + ref_clk_freq);
> + ret = -EINVAL;
> + goto err_disable_ref_clk;
> + }
> +
> + ret = devm_request_irq(&pdev->dev, crtc->irq,
> + cdns_rtc_irq_handler, 0,
> + dev_name(&pdev->dev), &pdev->dev);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "Unable to request interrupt for the device, %d\n",
> + ret);
> + goto err_disable_ref_clk;
> + }
> +
You should use devm_rtc_allocate_device to allocate crtc->rtc_dev before
requesting the IRQ. Else, this leaves a race condition open.
Also, please set crtc->rtc_dev->range_min and crtc->rtc_dev->range_max
according to the fully contiguous range of time that is supported by the
RTC. You can use
https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/rtc-tools.git/tree/rtc-range.c
to assist you.
> + /* Always use 24-hour mode */
> + writel(0, crtc->regs + CDNS_RTC_HMR);
> +
> + device_init_wakeup(&pdev->dev, 1);
> + platform_set_drvdata(pdev, crtc);
> + cdns_rtc_set_enabled(crtc, true);
Is that really necessary? I guess you could check whether it has already
been enabled to know whether the currently set time is valid so
cdns_rtc_read_time could return -EINVAL when it knows it isn't valid.
cdns_rtc_set_time will enable the RTC once the time has been set anyway.
> +
> + crtc->rtc_dev = devm_rtc_device_register(&pdev->dev,
> + dev_name(&pdev->dev),
> + &cdns_rtc_ops,
> + THIS_MODULE);
> + if (IS_ERR(crtc->rtc_dev)) {
> + ret = PTR_ERR(crtc->rtc_dev);
> + dev_err(&pdev->dev, "Unable to register the rtc device, %d\n",
> + ret);
> + goto err_stop_rtc;
> + }
> +
> + return 0;
> +
> +err_stop_rtc:
> + cdns_rtc_set_enabled(crtc, false);
> +
> +err_disable_ref_clk:
> + clk_disable_unprepare(crtc->ref_clk);
> +
> +err_disable_pclk:
> + clk_disable_unprepare(crtc->pclk);
> +
> + return ret;
> +}
> +
> +static int cdns_rtc_remove(struct platform_device *pdev)
> +{
> + struct cdns_rtc *crtc = platform_get_drvdata(pdev);
> +
> + cdns_rtc_alarm_irq_enable(&pdev->dev, 0);
> + device_init_wakeup(&pdev->dev, 0);
> +
> + clk_disable_unprepare(crtc->pclk);
> + clk_disable_unprepare(crtc->ref_clk);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int cdns_rtc_suspend(struct device *dev)
> +{
> + struct cdns_rtc *crtc = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev))
> + enable_irq_wake(crtc->irq);
> +
> + return 0;
> +}
> +
> +static int cdns_rtc_resume(struct device *dev)
> +{
> + struct cdns_rtc *crtc = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev))
> + disable_irq_wake(crtc->irq);
> +
> + return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(cdns_rtc_pm_ops, cdns_rtc_suspend, cdns_rtc_resume);
> +
> +static const struct of_device_id cdns_rtc_of_match[] = {
> + { .compatible = "cdns,rtc-r109v3" },
Is r109v3 an IP name or a revision?
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, cdns_rtc_of_match);
> +
> +static struct platform_driver cdns_rtc_driver = {
> + .driver = {
> + .name = "cdns-rtc",
> + .of_match_table = cdns_rtc_of_match,
> + .pm = &cdns_rtc_pm_ops,
> + },
> + .probe = cdns_rtc_probe,
> + .remove = cdns_rtc_remove,
> +};
> +module_platform_driver(cdns_rtc_driver);
> +
> +MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
> +MODULE_DESCRIPTION("Cadence RTC driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:cdns-rtc");
> --
> 2.15.0
>
--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
next prev parent reply other threads:[~2019-01-10 22:27 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-08 12:22 [PATCH 0/2] rtc: Add a driver for Cadence RTC Jan Kotas
2019-01-08 12:22 ` Jan Kotas
2019-01-08 12:22 ` [PATCH 1/2] dt-bindings: rtc: Add bindings " Jan Kotas
2019-01-08 12:22 ` Jan Kotas
2019-01-08 12:22 ` [PATCH 2/2] rtc: Add Cadence RTC driver Jan Kotas
2019-01-08 12:22 ` Jan Kotas
2019-01-10 22:27 ` Alexandre Belloni [this message]
2019-01-11 10:12 ` Janek Kotas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190110222726.GI2362@piout.net \
--to=alexandre.belloni@bootlin.com \
--cc=a.zummo@towertech.it \
--cc=devicetree@vger.kernel.org \
--cc=jank@cadence.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rtc@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.