in rtc-at91sam9.c [335:440]
static int at91_rtc_probe(struct platform_device *pdev)
{
struct sam9_rtc *rtc;
int ret, irq;
u32 mr;
unsigned int sclk_rate;
struct of_phandle_args args;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
spin_lock_init(&rtc->lock);
rtc->irq = irq;
/* platform setup code should have handled this; sigh */
if (!device_can_wakeup(&pdev->dev))
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, rtc);
rtc->rtt = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rtc->rtt))
return PTR_ERR(rtc->rtt);
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
"atmel,rtt-rtc-time-reg", 1, 0,
&args);
if (ret)
return ret;
rtc->gpbr = syscon_node_to_regmap(args.np);
rtc->gpbr_offset = args.args[0];
if (IS_ERR(rtc->gpbr)) {
dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
return -ENOMEM;
}
rtc->sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rtc->sclk))
return PTR_ERR(rtc->sclk);
ret = clk_prepare_enable(rtc->sclk);
if (ret) {
dev_err(&pdev->dev, "Could not enable slow clock\n");
return ret;
}
sclk_rate = clk_get_rate(rtc->sclk);
if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) {
dev_err(&pdev->dev, "Invalid slow clock rate\n");
ret = -EINVAL;
goto err_clk;
}
mr = rtt_readl(rtc, MR);
/* unless RTT is counting at 1 Hz, re-initialize it */
if ((mr & AT91_RTT_RTPRES) != sclk_rate) {
mr = AT91_RTT_RTTRST | (sclk_rate & AT91_RTT_RTPRES);
gpbr_writel(rtc, 0);
}
/* disable all interrupts (same as on shutdown path) */
mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
rtt_writel(rtc, MR, mr);
rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc->rtcdev)) {
ret = PTR_ERR(rtc->rtcdev);
goto err_clk;
}
rtc->rtcdev->ops = &at91_rtc_ops;
rtc->rtcdev->range_max = U32_MAX;
/* register irq handler after we know what name we'll use */
ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
IRQF_SHARED | IRQF_COND_SUSPEND,
dev_name(&rtc->rtcdev->dev), rtc);
if (ret) {
dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
goto err_clk;
}
/* NOTE: sam9260 rev A silicon has a ROM bug which resets the
* RTT on at least some reboots. If you have that chip, you must
* initialize the time from some external source like a GPS, wall
* clock, discrete RTC, etc
*/
if (gpbr_readl(rtc) == 0)
dev_warn(&pdev->dev, "%s: SET TIME!\n",
dev_name(&rtc->rtcdev->dev));
return devm_rtc_register_device(rtc->rtcdev);
err_clk:
clk_disable_unprepare(rtc->sclk);
return ret;
}