brintos

brintos / linux-shallow public Read only

0
0
Text · 6.6 KiB · 0f21af2 Raw
253 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs4 *5 * Copyright (C) 2013 ams AG6 * 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	  200025struct 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_SLEEP216static 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#endif235 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");253