cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rtc-as3722.c (6727B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs
      4 *
      5 * Copyright (C) 2013 ams AG
      6 * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
      7 *
      8 * Author: Florian Lobmaier <florian.lobmaier@ams.com>
      9 * Author: Laxman Dewangan <ldewangan@nvidia.com>
     10 */
     11
     12#include <linux/bcd.h>
     13#include <linux/completion.h>
     14#include <linux/delay.h>
     15#include <linux/interrupt.h>
     16#include <linux/ioctl.h>
     17#include <linux/kernel.h>
     18#include <linux/module.h>
     19#include <linux/mfd/as3722.h>
     20#include <linux/platform_device.h>
     21#include <linux/rtc.h>
     22#include <linux/time.h>
     23
     24#define AS3722_RTC_START_YEAR	  2000
     25struct as3722_rtc {
     26	struct rtc_device	*rtc;
     27	struct device		*dev;
     28	struct as3722		*as3722;
     29	int			alarm_irq;
     30	bool			irq_enable;
     31};
     32
     33static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm)
     34{
     35	rbuff[0] = bin2bcd(tm->tm_sec);
     36	rbuff[1] = bin2bcd(tm->tm_min);
     37	rbuff[2] = bin2bcd(tm->tm_hour);
     38	rbuff[3] = bin2bcd(tm->tm_mday);
     39	rbuff[4] = bin2bcd(tm->tm_mon + 1);
     40	rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900));
     41}
     42
     43static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm)
     44{
     45	tm->tm_sec = bcd2bin(rbuff[0] & 0x7F);
     46	tm->tm_min = bcd2bin(rbuff[1] & 0x7F);
     47	tm->tm_hour = bcd2bin(rbuff[2] & 0x3F);
     48	tm->tm_mday = bcd2bin(rbuff[3] & 0x3F);
     49	tm->tm_mon = bcd2bin(rbuff[4] & 0x1F) - 1;
     50	tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F);
     51	return;
     52}
     53
     54static int as3722_rtc_read_time(struct device *dev, struct rtc_time *tm)
     55{
     56	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
     57	struct as3722 *as3722 = as3722_rtc->as3722;
     58	u8 as_time_array[6];
     59	int ret;
     60
     61	ret = as3722_block_read(as3722, AS3722_RTC_SECOND_REG,
     62			6, as_time_array);
     63	if (ret < 0) {
     64		dev_err(dev, "RTC_SECOND reg block read failed %d\n", ret);
     65		return ret;
     66	}
     67	as3722_reg_to_time(as_time_array, tm);
     68	return 0;
     69}
     70
     71static int as3722_rtc_set_time(struct device *dev, struct rtc_time *tm)
     72{
     73	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
     74	struct as3722 *as3722 = as3722_rtc->as3722;
     75	u8 as_time_array[6];
     76	int ret;
     77
     78	if (tm->tm_year < (AS3722_RTC_START_YEAR - 1900))
     79		return -EINVAL;
     80
     81	as3722_time_to_reg(as_time_array, tm);
     82	ret = as3722_block_write(as3722, AS3722_RTC_SECOND_REG, 6,
     83			as_time_array);
     84	if (ret < 0)
     85		dev_err(dev, "RTC_SECOND reg block write failed %d\n", ret);
     86	return ret;
     87}
     88
     89static int as3722_rtc_alarm_irq_enable(struct device *dev,
     90		unsigned int enabled)
     91{
     92	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
     93
     94	if (enabled && !as3722_rtc->irq_enable) {
     95		enable_irq(as3722_rtc->alarm_irq);
     96		as3722_rtc->irq_enable = true;
     97	} else if (!enabled && as3722_rtc->irq_enable)  {
     98		disable_irq(as3722_rtc->alarm_irq);
     99		as3722_rtc->irq_enable = false;
    100	}
    101	return 0;
    102}
    103
    104static int as3722_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
    105{
    106	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
    107	struct as3722 *as3722 = as3722_rtc->as3722;
    108	u8 as_time_array[6];
    109	int ret;
    110
    111	ret = as3722_block_read(as3722, AS3722_RTC_ALARM_SECOND_REG, 6,
    112			as_time_array);
    113	if (ret < 0) {
    114		dev_err(dev, "RTC_ALARM_SECOND block read failed %d\n", ret);
    115		return ret;
    116	}
    117
    118	as3722_reg_to_time(as_time_array, &alrm->time);
    119	return 0;
    120}
    121
    122static int as3722_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
    123{
    124	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
    125	struct as3722 *as3722 = as3722_rtc->as3722;
    126	u8 as_time_array[6];
    127	int ret;
    128
    129	if (alrm->time.tm_year < (AS3722_RTC_START_YEAR - 1900))
    130		return -EINVAL;
    131
    132	ret = as3722_rtc_alarm_irq_enable(dev, 0);
    133	if (ret < 0) {
    134		dev_err(dev, "Disable RTC alarm failed\n");
    135		return ret;
    136	}
    137
    138	as3722_time_to_reg(as_time_array, &alrm->time);
    139	ret = as3722_block_write(as3722, AS3722_RTC_ALARM_SECOND_REG, 6,
    140			as_time_array);
    141	if (ret < 0) {
    142		dev_err(dev, "RTC_ALARM_SECOND block write failed %d\n", ret);
    143		return ret;
    144	}
    145
    146	if (alrm->enabled)
    147		ret = as3722_rtc_alarm_irq_enable(dev, alrm->enabled);
    148	return ret;
    149}
    150
    151static irqreturn_t as3722_alarm_irq(int irq, void *data)
    152{
    153	struct as3722_rtc *as3722_rtc = data;
    154
    155	rtc_update_irq(as3722_rtc->rtc, 1, RTC_IRQF | RTC_AF);
    156	return IRQ_HANDLED;
    157}
    158
    159static const struct rtc_class_ops as3722_rtc_ops = {
    160	.read_time = as3722_rtc_read_time,
    161	.set_time = as3722_rtc_set_time,
    162	.read_alarm = as3722_rtc_read_alarm,
    163	.set_alarm = as3722_rtc_set_alarm,
    164	.alarm_irq_enable = as3722_rtc_alarm_irq_enable,
    165};
    166
    167static int as3722_rtc_probe(struct platform_device *pdev)
    168{
    169	struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
    170	struct as3722_rtc *as3722_rtc;
    171	int ret;
    172
    173	as3722_rtc = devm_kzalloc(&pdev->dev, sizeof(*as3722_rtc), GFP_KERNEL);
    174	if (!as3722_rtc)
    175		return -ENOMEM;
    176
    177	as3722_rtc->as3722 = as3722;
    178	as3722_rtc->dev = &pdev->dev;
    179	platform_set_drvdata(pdev, as3722_rtc);
    180
    181	/* Enable the RTC to make sure it is running. */
    182	ret = as3722_update_bits(as3722, AS3722_RTC_CONTROL_REG,
    183			AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN,
    184			AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN);
    185	if (ret < 0) {
    186		dev_err(&pdev->dev, "RTC_CONTROL reg write failed: %d\n", ret);
    187		return ret;
    188	}
    189
    190	device_init_wakeup(&pdev->dev, 1);
    191
    192	as3722_rtc->rtc = devm_rtc_device_register(&pdev->dev, "as3722-rtc",
    193				&as3722_rtc_ops, THIS_MODULE);
    194	if (IS_ERR(as3722_rtc->rtc)) {
    195		ret = PTR_ERR(as3722_rtc->rtc);
    196		dev_err(&pdev->dev, "RTC register failed: %d\n", ret);
    197		return ret;
    198	}
    199
    200	as3722_rtc->alarm_irq = platform_get_irq(pdev, 0);
    201	dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq);
    202
    203	ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL,
    204			as3722_alarm_irq, IRQF_ONESHOT,
    205			"rtc-alarm", as3722_rtc);
    206	if (ret < 0) {
    207		dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
    208				as3722_rtc->alarm_irq, ret);
    209		return ret;
    210	}
    211	disable_irq(as3722_rtc->alarm_irq);
    212	return 0;
    213}
    214
    215#ifdef CONFIG_PM_SLEEP
    216static int as3722_rtc_suspend(struct device *dev)
    217{
    218	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
    219
    220	if (device_may_wakeup(dev))
    221		enable_irq_wake(as3722_rtc->alarm_irq);
    222
    223	return 0;
    224}
    225
    226static int as3722_rtc_resume(struct device *dev)
    227{
    228	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
    229
    230	if (device_may_wakeup(dev))
    231		disable_irq_wake(as3722_rtc->alarm_irq);
    232	return 0;
    233}
    234#endif
    235
    236static SIMPLE_DEV_PM_OPS(as3722_rtc_pm_ops, as3722_rtc_suspend,
    237			 as3722_rtc_resume);
    238
    239static struct platform_driver as3722_rtc_driver = {
    240	.probe = as3722_rtc_probe,
    241	.driver = {
    242		.name = "as3722-rtc",
    243		.pm = &as3722_rtc_pm_ops,
    244	},
    245};
    246module_platform_driver(as3722_rtc_driver);
    247
    248MODULE_DESCRIPTION("RTC driver for AS3722 PMICs");
    249MODULE_ALIAS("platform:as3722-rtc");
    250MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>");
    251MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
    252MODULE_LICENSE("GPL");