Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1/*
  2 * rtc-rc5t583.c -- RICOH RC5T583 Real Time Clock
  3 *
  4 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
  5 * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
  6 *
  7 * This program is free software; you can redistribute it and/or modify it
  8 * under the terms and conditions of the GNU General Public License,
  9 * version 2, as published by the Free Software Foundation.
 10 *
 11 * This program is distributed in the hope it will be useful, but WITHOUT
 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 14 * more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 18
 19#include <linux/kernel.h>
 20#include <linux/errno.h>
 21#include <linux/init.h>
 22#include <linux/module.h>
 23#include <linux/types.h>
 24#include <linux/rtc.h>
 25#include <linux/bcd.h>
 26#include <linux/platform_device.h>
 27#include <linux/interrupt.h>
 28#include <linux/mfd/rc5t583.h>
 29
 30struct rc5t583_rtc {
 31	struct rtc_device	*rtc;
 32	/* To store the list of enabled interrupts, during system suspend */
 33	u32 irqen;
 34};
 35
 36/* Total number of RTC registers needed to set time*/
 37#define NUM_TIME_REGS	(RC5T583_RTC_YEAR - RC5T583_RTC_SEC + 1)
 38
 39/* Total number of RTC registers needed to set Y-Alarm*/
 40#define NUM_YAL_REGS	(RC5T583_RTC_AY_YEAR - RC5T583_RTC_AY_MIN + 1)
 41
 42/* Set Y-Alarm interrupt */
 43#define SET_YAL BIT(5)
 44
 45/* Get Y-Alarm interrupt status*/
 46#define GET_YAL_STATUS BIT(3)
 47
 48static int rc5t583_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
 49{
 50	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 51	u8 val;
 52
 53	/* Set Y-Alarm, based on 'enabled' */
 54	val = enabled ? SET_YAL : 0;
 55
 56	return regmap_update_bits(rc5t583->regmap, RC5T583_RTC_CTL1, SET_YAL,
 57		val);
 58}
 59
 60/*
 61 * Gets current rc5t583 RTC time and date parameters.
 62 *
 63 * The RTC's time/alarm representation is not what gmtime(3) requires
 64 * Linux to use:
 65 *
 66 *  - Months are 1..12 vs Linux 0-11
 67 *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
 68 */
 69static int rc5t583_rtc_read_time(struct device *dev, struct rtc_time *tm)
 70{
 71	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 72	u8 rtc_data[NUM_TIME_REGS];
 73	int ret;
 74
 75	ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
 76		NUM_TIME_REGS);
 77	if (ret < 0) {
 78		dev_err(dev, "RTC read time failed with err:%d\n", ret);
 79		return ret;
 80	}
 81
 82	tm->tm_sec = bcd2bin(rtc_data[0]);
 83	tm->tm_min = bcd2bin(rtc_data[1]);
 84	tm->tm_hour = bcd2bin(rtc_data[2]);
 85	tm->tm_wday = bcd2bin(rtc_data[3]);
 86	tm->tm_mday = bcd2bin(rtc_data[4]);
 87	tm->tm_mon = bcd2bin(rtc_data[5]) - 1;
 88	tm->tm_year = bcd2bin(rtc_data[6]) + 100;
 89
 90	return ret;
 91}
 92
 93static int rc5t583_rtc_set_time(struct device *dev, struct rtc_time *tm)
 94{
 95	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 96	unsigned char rtc_data[NUM_TIME_REGS];
 97	int ret;
 98
 99	rtc_data[0] = bin2bcd(tm->tm_sec);
100	rtc_data[1] = bin2bcd(tm->tm_min);
101	rtc_data[2] = bin2bcd(tm->tm_hour);
102	rtc_data[3] = bin2bcd(tm->tm_wday);
103	rtc_data[4] = bin2bcd(tm->tm_mday);
104	rtc_data[5] = bin2bcd(tm->tm_mon + 1);
105	rtc_data[6] = bin2bcd(tm->tm_year - 100);
106
107	ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
108		NUM_TIME_REGS);
109	if (ret < 0) {
110		dev_err(dev, "RTC set time failed with error %d\n", ret);
111		return ret;
112	}
113
114	return ret;
115}
116
117static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
118{
119	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
120	unsigned char alarm_data[NUM_YAL_REGS];
121	u32 interrupt_enable;
122	int ret;
123
124	ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
125		NUM_YAL_REGS);
126	if (ret < 0) {
127		dev_err(dev, "rtc_read_alarm error %d\n", ret);
128		return ret;
129	}
130
131	alm->time.tm_min = bcd2bin(alarm_data[0]);
132	alm->time.tm_hour = bcd2bin(alarm_data[1]);
133	alm->time.tm_mday = bcd2bin(alarm_data[2]);
134	alm->time.tm_mon = bcd2bin(alarm_data[3]) - 1;
135	alm->time.tm_year = bcd2bin(alarm_data[4]) + 100;
136
137	ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1, &interrupt_enable);
138	if (ret < 0)
139		return ret;
140
141	/* check if YALE is set */
142	if (interrupt_enable & SET_YAL)
143		alm->enabled = 1;
144
145	return ret;
146}
147
148static int rc5t583_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
149{
150	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
151	unsigned char alarm_data[NUM_YAL_REGS];
152	int ret;
153
154	ret = rc5t583_rtc_alarm_irq_enable(dev, 0);
155	if (ret)
156		return ret;
157
158	alarm_data[0] = bin2bcd(alm->time.tm_min);
159	alarm_data[1] = bin2bcd(alm->time.tm_hour);
160	alarm_data[2] = bin2bcd(alm->time.tm_mday);
161	alarm_data[3] = bin2bcd(alm->time.tm_mon + 1);
162	alarm_data[4] = bin2bcd(alm->time.tm_year - 100);
163
164	ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
165		NUM_YAL_REGS);
166	if (ret) {
167		dev_err(dev, "rtc_set_alarm error %d\n", ret);
168		return ret;
169	}
170
171	if (alm->enabled)
172		ret = rc5t583_rtc_alarm_irq_enable(dev, 1);
173
174	return ret;
175}
176
177static irqreturn_t rc5t583_rtc_interrupt(int irq, void *rtc)
178{
179	struct device *dev = rtc;
180	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
181	struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
182	unsigned long events = 0;
183	int ret;
184	u32 rtc_reg;
185
186	ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL2, &rtc_reg);
187	if (ret < 0)
188		return IRQ_NONE;
189
190	if (rtc_reg & GET_YAL_STATUS) {
191		events = RTC_IRQF | RTC_AF;
192		/* clear pending Y-alarm interrupt bit */
193		rtc_reg &= ~GET_YAL_STATUS;
194	}
195
196	ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, rtc_reg);
197	if (ret)
198		return IRQ_NONE;
199
200	/* Notify RTC core on event */
201	rtc_update_irq(rc5t583_rtc->rtc, 1, events);
202
203	return IRQ_HANDLED;
204}
205
206static const struct rtc_class_ops rc5t583_rtc_ops = {
207	.read_time	= rc5t583_rtc_read_time,
208	.set_time	= rc5t583_rtc_set_time,
209	.read_alarm	= rc5t583_rtc_read_alarm,
210	.set_alarm	= rc5t583_rtc_set_alarm,
211	.alarm_irq_enable = rc5t583_rtc_alarm_irq_enable,
212};
213
214static int rc5t583_rtc_probe(struct platform_device *pdev)
215{
216	struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
217	struct rc5t583_rtc *ricoh_rtc;
218	struct rc5t583_platform_data *pmic_plat_data;
219	int ret;
220	int irq;
221
222	ricoh_rtc = devm_kzalloc(&pdev->dev, sizeof(struct rc5t583_rtc),
223			GFP_KERNEL);
224	if (!ricoh_rtc)
225		return -ENOMEM;
226
227	platform_set_drvdata(pdev, ricoh_rtc);
228
229	/* Clear pending interrupts */
230	ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, 0);
231	if (ret < 0)
232		return ret;
233
234	/* clear RTC Adjust register */
235	ret = regmap_write(rc5t583->regmap, RC5T583_RTC_ADJ, 0);
236	if (ret < 0) {
237		dev_err(&pdev->dev, "unable to program rtc_adjust reg\n");
238		return -EBUSY;
239	}
240
241	pmic_plat_data = dev_get_platdata(rc5t583->dev);
242	irq = pmic_plat_data->irq_base;
243	if (irq <= 0) {
244		dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
245			irq);
246		return ret;
247	}
248
249	irq += RC5T583_IRQ_YALE;
250	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
251		rc5t583_rtc_interrupt, IRQF_TRIGGER_LOW,
252		"rtc-rc5t583", &pdev->dev);
253	if (ret < 0) {
254		dev_err(&pdev->dev, "IRQ is not free.\n");
255		return ret;
256	}
257	device_init_wakeup(&pdev->dev, 1);
258
259	ricoh_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
260		&rc5t583_rtc_ops, THIS_MODULE);
261	if (IS_ERR(ricoh_rtc->rtc)) {
262		ret = PTR_ERR(ricoh_rtc->rtc);
263		dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
264		return ret;
265	}
266
267	return 0;
268}
269
270/*
271 * Disable rc5t583 RTC interrupts.
272 * Sets status flag to free.
273 */
274static int rc5t583_rtc_remove(struct platform_device *pdev)
275{
276	struct rc5t583_rtc *rc5t583_rtc = platform_get_drvdata(pdev);
277
278	rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0);
279	return 0;
280}
281
282#ifdef CONFIG_PM_SLEEP
283static int rc5t583_rtc_suspend(struct device *dev)
284{
285	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
286	struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
287	int ret;
288
289	/* Store current list of enabled interrupts*/
290	ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1,
291		&rc5t583_rtc->irqen);
292	return ret;
293}
294
295static int rc5t583_rtc_resume(struct device *dev)
296{
297	struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
298	struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
299
300	/* Restore list of enabled interrupts before suspend */
301	return regmap_write(rc5t583->regmap, RC5T583_RTC_CTL1,
302		rc5t583_rtc->irqen);
303}
304#endif
305
306static SIMPLE_DEV_PM_OPS(rc5t583_rtc_pm_ops, rc5t583_rtc_suspend,
307			rc5t583_rtc_resume);
308
309static struct platform_driver rc5t583_rtc_driver = {
310	.probe		= rc5t583_rtc_probe,
311	.remove		= rc5t583_rtc_remove,
312	.driver		= {
313		.owner	= THIS_MODULE,
314		.name	= "rtc-rc5t583",
315		.pm	= &rc5t583_rtc_pm_ops,
316	},
317};
318
319module_platform_driver(rc5t583_rtc_driver);
320MODULE_ALIAS("platform:rtc-rc5t583");
321MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
322MODULE_LICENSE("GPL v2");