brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 53ec717 Raw
208 lines · c
1// SPDX-License-Identifier: GPL-2.02/* drivers/rtc/rtc-goldfish.c3 *4 * Copyright (C) 2007 Google, Inc.5 * Copyright (C) 2017 Imagination Technologies Ltd.6 */7 8#include <linux/io.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/platform_device.h>12#include <linux/rtc.h>13#include <linux/goldfish.h>14#include <clocksource/timer-goldfish.h>15 16struct goldfish_rtc {17	void __iomem *base;18	int irq;19	struct rtc_device *rtc;20};21 22static int goldfish_rtc_read_alarm(struct device *dev,23				   struct rtc_wkalrm *alrm)24{25	u64 rtc_alarm;26	u64 rtc_alarm_low;27	u64 rtc_alarm_high;28	void __iomem *base;29	struct goldfish_rtc *rtcdrv;30 31	rtcdrv = dev_get_drvdata(dev);32	base = rtcdrv->base;33 34	rtc_alarm_low = gf_ioread32(base + TIMER_ALARM_LOW);35	rtc_alarm_high = gf_ioread32(base + TIMER_ALARM_HIGH);36	rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low;37 38	do_div(rtc_alarm, NSEC_PER_SEC);39	memset(alrm, 0, sizeof(struct rtc_wkalrm));40 41	rtc_time64_to_tm(rtc_alarm, &alrm->time);42 43	if (gf_ioread32(base + TIMER_ALARM_STATUS))44		alrm->enabled = 1;45	else46		alrm->enabled = 0;47 48	return 0;49}50 51static int goldfish_rtc_set_alarm(struct device *dev,52				  struct rtc_wkalrm *alrm)53{54	struct goldfish_rtc *rtcdrv;55	u64 rtc_alarm64;56	u64 rtc_status_reg;57	void __iomem *base;58 59	rtcdrv = dev_get_drvdata(dev);60	base = rtcdrv->base;61 62	if (alrm->enabled) {63		rtc_alarm64 = rtc_tm_to_time64(&alrm->time) * NSEC_PER_SEC;64		gf_iowrite32((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH);65		gf_iowrite32(rtc_alarm64, base + TIMER_ALARM_LOW);66		gf_iowrite32(1, base + TIMER_IRQ_ENABLED);67	} else {68		/*69		 * if this function was called with enabled=070		 * then it could mean that the application is71		 * trying to cancel an ongoing alarm72		 */73		rtc_status_reg = gf_ioread32(base + TIMER_ALARM_STATUS);74		if (rtc_status_reg)75			gf_iowrite32(1, base + TIMER_CLEAR_ALARM);76	}77 78	return 0;79}80 81static int goldfish_rtc_alarm_irq_enable(struct device *dev,82					 unsigned int enabled)83{84	void __iomem *base;85	struct goldfish_rtc *rtcdrv;86 87	rtcdrv = dev_get_drvdata(dev);88	base = rtcdrv->base;89 90	if (enabled)91		gf_iowrite32(1, base + TIMER_IRQ_ENABLED);92	else93		gf_iowrite32(0, base + TIMER_IRQ_ENABLED);94 95	return 0;96}97 98static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id)99{100	struct goldfish_rtc *rtcdrv = dev_id;101	void __iomem *base = rtcdrv->base;102 103	gf_iowrite32(1, base + TIMER_CLEAR_INTERRUPT);104 105	rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF);106 107	return IRQ_HANDLED;108}109 110static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm)111{112	struct goldfish_rtc *rtcdrv;113	void __iomem *base;114	u64 time_high;115	u64 time_low;116	u64 time;117 118	rtcdrv = dev_get_drvdata(dev);119	base = rtcdrv->base;120 121	time_low = gf_ioread32(base + TIMER_TIME_LOW);122	time_high = gf_ioread32(base + TIMER_TIME_HIGH);123	time = (time_high << 32) | time_low;124 125	do_div(time, NSEC_PER_SEC);126 127	rtc_time64_to_tm(time, tm);128 129	return 0;130}131 132static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm)133{134	struct goldfish_rtc *rtcdrv;135	void __iomem *base;136	u64 now64;137 138	rtcdrv = dev_get_drvdata(dev);139	base = rtcdrv->base;140 141	now64 = rtc_tm_to_time64(tm) * NSEC_PER_SEC;142	gf_iowrite32((now64 >> 32), base + TIMER_TIME_HIGH);143	gf_iowrite32(now64, base + TIMER_TIME_LOW);144 145	return 0;146}147 148static const struct rtc_class_ops goldfish_rtc_ops = {149	.read_time	= goldfish_rtc_read_time,150	.set_time	= goldfish_rtc_set_time,151	.read_alarm	= goldfish_rtc_read_alarm,152	.set_alarm	= goldfish_rtc_set_alarm,153	.alarm_irq_enable = goldfish_rtc_alarm_irq_enable154};155 156static int goldfish_rtc_probe(struct platform_device *pdev)157{158	struct goldfish_rtc *rtcdrv;159	int err;160 161	rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL);162	if (!rtcdrv)163		return -ENOMEM;164 165	platform_set_drvdata(pdev, rtcdrv);166	rtcdrv->base = devm_platform_ioremap_resource(pdev, 0);167	if (IS_ERR(rtcdrv->base))168		return PTR_ERR(rtcdrv->base);169 170	rtcdrv->irq = platform_get_irq(pdev, 0);171	if (rtcdrv->irq < 0)172		return -ENODEV;173 174	rtcdrv->rtc = devm_rtc_allocate_device(&pdev->dev);175	if (IS_ERR(rtcdrv->rtc))176		return PTR_ERR(rtcdrv->rtc);177 178	rtcdrv->rtc->ops = &goldfish_rtc_ops;179	rtcdrv->rtc->range_max = U64_MAX / NSEC_PER_SEC;180 181	err = devm_request_irq(&pdev->dev, rtcdrv->irq,182			       goldfish_rtc_interrupt,183			       0, pdev->name, rtcdrv);184	if (err)185		return err;186 187	return devm_rtc_register_device(rtcdrv->rtc);188}189 190static const struct of_device_id goldfish_rtc_of_match[] = {191	{ .compatible = "google,goldfish-rtc", },192	{},193};194MODULE_DEVICE_TABLE(of, goldfish_rtc_of_match);195 196static struct platform_driver goldfish_rtc = {197	.probe = goldfish_rtc_probe,198	.driver = {199		.name = "goldfish_rtc",200		.of_match_table = goldfish_rtc_of_match,201	}202};203 204module_platform_driver(goldfish_rtc);205 206MODULE_DESCRIPTION("Android Goldfish Real Time Clock driver");207MODULE_LICENSE("GPL v2");208