blob: 0e14ccb7b7e91a2389f53365c37f5cc0b890160f [file] [log] [blame]
/*
* drivers/rtc/rtc-max77663.c
* Max77663 RTC driver
*
* Copyright 2011-2012, Maxim Integrated Products, Inc.
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/mfd/max77663-core.h>
/* RTC Registers */
#define MAX77663_RTC_IRQ 0x00
#define MAX77663_RTC_IRQ_MASK 0x01
#define MAX77663_RTC_CTRL_MODE 0x02
#define MAX77663_RTC_CTRL 0x03
#define MAX77663_RTC_UPDATE0 0x04
#define MAX77663_RTC_UPDATE1 0x05
#define MAX77663_RTC_SEC 0x07
#define MAX77663_RTC_MIN 0x08
#define MAX77663_RTC_HOUR 0x09
#define MAX77663_RTC_WEEKDAY 0x0A
#define MAX77663_RTC_MONTH 0x0B
#define MAX77663_RTC_YEAR 0x0C
#define MAX77663_RTC_MONTHDAY 0x0D
#define MAX77663_RTC_ALARM_SEC1 0x0E
#define MAX77663_RTC_ALARM_MIN1 0x0F
#define MAX77663_RTC_ALARM_HOUR1 0x10
#define MAX77663_RTC_ALARM_WEEKDAY1 0x11
#define MAX77663_RTC_ALARM_MONTH1 0x12
#define MAX77663_RTC_ALARM_YEAR1 0x13
#define MAX77663_RTC_ALARM_MONTHDAY1 0x14
#define RTC_IRQ_60SEC_MASK (1 << 0)
#define RTC_IRQ_ALARM1_MASK (1 << 1)
#define RTC_IRQ_ALARM2_MASK (1 << 2)
#define RTC_IRQ_SMPL_MASK (1 << 3)
#define RTC_IRQ_1SEC_MASK (1 << 4)
#define RTC_IRQ_MASK 0x1F
#define BCD_MODE_MASK (1 << 0)
#define HR_MODE_MASK (1 << 1)
#define WB_UPDATE_MASK (1 << 0)
#define FLAG_AUTO_CLEAR_MASK (1 << 1)
#define FREEZE_SEC_MASK (1 << 2)
#define RTC_WAKE_MASK (1 << 3)
#define RB_UPDATE_MASK (1 << 4)
#define WB_UPDATE_FLAG_MASK (1 << 0)
#define RB_UPDATE_FLAG_MASK (1 << 1)
#define SEC_MASK 0x7F
#define MIN_MASK 0x7F
#define HOUR_MASK 0x3F
#define WEEKDAY_MASK 0x7F
#define MONTH_MASK 0x1F
#define YEAR_MASK 0xFF
#define MONTHDAY_MASK 0x3F
#define ALARM_EN_MASK 0x80
#define ALARM_EN_SHIFT 7
#define RTC_YEAR_BASE 100
#define RTC_YEAR_MAX 99
/* ON/OFF Registers */
#define MAX77663_REG_ONOFF_CFG2 0x42
#define ONOFF_WK_ALARM1_MASK (1 << 2)
enum {
RTC_SEC,
RTC_MIN,
RTC_HOUR,
RTC_WEEKDAY,
RTC_MONTH,
RTC_YEAR,
RTC_MONTHDAY,
RTC_NR
};
struct max77663_rtc {
struct rtc_device *rtc;
struct device *dev;
struct mutex io_lock;
int irq;
u8 irq_mask;
bool shutdown_ongoing;
};
static inline struct device *_to_parent(struct max77663_rtc *rtc)
{
return rtc->dev->parent;
}
static inline int max77663_rtc_update_buffer(struct max77663_rtc *rtc,
int write)
{
struct device *parent = _to_parent(rtc);
u8 val = FLAG_AUTO_CLEAR_MASK | RTC_WAKE_MASK;
int ret;
if (write)
val |= WB_UPDATE_MASK;
else
val |= RB_UPDATE_MASK;
dev_dbg(rtc->dev, "rtc_update_buffer: write=%d, addr=0x%x, val=0x%x\n",
write, MAX77663_RTC_UPDATE0, val);
ret = max77663_write(parent, MAX77663_RTC_UPDATE0, &val, 1, 1);
if (ret < 0) {
dev_err(rtc->dev, "rtc_update_buffer: "
"Failed to get rtc update0\n");
return ret;
}
/*
* Must wait 14ms for buffer update.
* If the sleeping time is 10us - 20ms, usleep_range() is recommended.
* Please refer Documentation/timers/timers-howto.txt.
*/
usleep_range(14000, 14000);
return 0;
}
static inline int max77663_rtc_write(struct max77663_rtc *rtc, u8 addr,
void *values, u32 len, int update_buffer)
{
struct device *parent = _to_parent(rtc);
int ret;
mutex_lock(&rtc->io_lock);
dev_dbg(rtc->dev, "rtc_write: addr=0x%x, values=0x%x, len=%u, "
"update_buffer=%d\n",
addr, *((u8 *)values), len, update_buffer);
ret = max77663_write(parent, addr, values, len, 1);
if (ret < 0)
goto out;
if (update_buffer)
ret = max77663_rtc_update_buffer(rtc, 1);
out:
mutex_unlock(&rtc->io_lock);
return ret;
}
static inline int max77663_rtc_read(struct max77663_rtc *rtc, u8 addr,
void *values, u32 len, int update_buffer)
{
struct device *parent = _to_parent(rtc);
int ret;
mutex_lock(&rtc->io_lock);
if (update_buffer) {
ret = max77663_rtc_update_buffer(rtc, 0);
if (ret < 0)
goto out;
}
ret = max77663_read(parent, addr, values, len, 1);
dev_dbg(rtc->dev, "rtc_read: addr=0x%x, values=0x%x, len=%u, "
"update_buffer=%d\n",
addr, *((u8 *)values), len, update_buffer);
out:
mutex_unlock(&rtc->io_lock);
return ret;
}
static inline int max77663_rtc_reg_to_tm(struct max77663_rtc *rtc, u8 *buf,
struct rtc_time *tm)
{
int wday = buf[RTC_WEEKDAY] & WEEKDAY_MASK;
if (unlikely(!wday)) {
dev_err(rtc->dev,
"rtc_reg_to_tm: Invalid day of week, %d\n", wday);
return -EINVAL;
}
tm->tm_sec = (int)(buf[RTC_SEC] & SEC_MASK);
tm->tm_min = (int)(buf[RTC_MIN] & MIN_MASK);
tm->tm_hour = (int)(buf[RTC_HOUR] & HOUR_MASK);
tm->tm_mday = (int)(buf[RTC_MONTHDAY] & MONTHDAY_MASK);
tm->tm_mon = (int)(buf[RTC_MONTH] & MONTH_MASK) - 1;
tm->tm_year = (int)(buf[RTC_YEAR] & YEAR_MASK) + RTC_YEAR_BASE;
tm->tm_wday = ffs(wday) - 1;
return 0;
}
static inline int max77663_rtc_tm_to_reg(struct max77663_rtc *rtc, u8 *buf,
struct rtc_time *tm, int alarm)
{
u8 alarm_mask = alarm ? ALARM_EN_MASK : 0;
if (unlikely((tm->tm_year < RTC_YEAR_BASE) ||
(tm->tm_year > RTC_YEAR_BASE + RTC_YEAR_MAX))) {
dev_err(rtc->dev,
"rtc_tm_to_reg: Invalid year, %d\n", tm->tm_year);
return -EINVAL;
}
buf[RTC_SEC] = tm->tm_sec | alarm_mask;
buf[RTC_MIN] = tm->tm_min | alarm_mask;
buf[RTC_HOUR] = tm->tm_hour | alarm_mask;
buf[RTC_MONTHDAY] = tm->tm_mday | alarm_mask;
buf[RTC_MONTH] = (tm->tm_mon + 1) | alarm_mask;
buf[RTC_YEAR] = (tm->tm_year - RTC_YEAR_BASE) | alarm_mask;
/* The wday is configured only when disabled alarm. */
if (!alarm)
buf[RTC_WEEKDAY] = (1 << tm->tm_wday);
else {
/* Configure its default reset value 0x01, and not enable it. */
buf[RTC_WEEKDAY] = 0x01;
}
return 0;
}
static inline int max77663_rtc_irq_mask(struct max77663_rtc *rtc, u8 irq)
{
struct device *parent = _to_parent(rtc);
u8 irq_mask = rtc->irq_mask | irq;
int ret = 0;
ret = max77663_write(parent, MAX77663_RTC_IRQ_MASK, &irq_mask, 1, 1);
if (ret < 0) {
dev_err(rtc->dev, "rtc_irq_mask: Failed to set rtc irq mask\n");
goto out;
}
rtc->irq_mask = irq_mask;
out:
return ret;
}
static inline int max77663_rtc_irq_unmask(struct max77663_rtc *rtc, u8 irq)
{
struct device *parent = _to_parent(rtc);
u8 irq_mask = rtc->irq_mask & ~irq;
int ret = 0;
ret = max77663_write(parent, MAX77663_RTC_IRQ_MASK, &irq_mask, 1, 1);
if (ret < 0) {
dev_err(rtc->dev,
"rtc_irq_unmask: Failed to set rtc irq mask\n");
goto out;
}
rtc->irq_mask = irq_mask;
out:
return ret;
}
static inline int max77663_rtc_do_irq(struct max77663_rtc *rtc)
{
struct device *parent = _to_parent(rtc);
u8 irq_status;
int ret;
ret = max77663_rtc_update_buffer(rtc, 0);
if (ret < 0) {
dev_err(rtc->dev, "rtc_irq: Failed to get rtc update buffer\n");
return ret;
}
ret = max77663_read(parent, MAX77663_RTC_IRQ, &irq_status, 1, 1);
if (ret < 0) {
dev_err(rtc->dev, "rtc_irq: Failed to get rtc irq status\n");
return ret;
}
dev_dbg(rtc->dev, "rtc_do_irq: irq_mask=0x%02x, irq_status=0x%02x\n",
rtc->irq_mask, irq_status);
if (!(rtc->irq_mask & RTC_IRQ_ALARM1_MASK) &&
(irq_status & RTC_IRQ_ALARM1_MASK))
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
if (!(rtc->irq_mask & RTC_IRQ_1SEC_MASK) &&
(irq_status & RTC_IRQ_1SEC_MASK))
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
return ret;
}
static irqreturn_t max77663_rtc_irq(int irq, void *data)
{
struct max77663_rtc *rtc = (struct max77663_rtc *)data;
max77663_rtc_do_irq(rtc);
return IRQ_HANDLED;
}
static int max77663_rtc_alarm_irq_enable(struct device *dev,
unsigned int enabled)
{
struct max77663_rtc *rtc = dev_get_drvdata(dev);
int ret = 0;
if (rtc->irq < 0)
return -ENXIO;
mutex_lock(&rtc->io_lock);
/* Handle pending interrupt */
ret = max77663_rtc_do_irq(rtc);
if (ret < 0)
goto out;
/* Config alarm interrupt */
if (enabled) {
ret = max77663_rtc_irq_unmask(rtc, RTC_IRQ_ALARM1_MASK);
if (ret < 0)
goto out;
} else {
ret = max77663_rtc_irq_mask(rtc, RTC_IRQ_ALARM1_MASK);
if (ret < 0)
goto out;
}
out:
mutex_unlock(&rtc->io_lock);
return ret;
}
static int max77663_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct max77663_rtc *rtc = dev_get_drvdata(dev);
u8 buf[RTC_NR];
int ret;
ret = max77663_rtc_read(rtc, MAX77663_RTC_SEC, buf, sizeof(buf), 1);
if (ret < 0) {
dev_err(rtc->dev, "rtc_read_time: Failed to read rtc time\n");
return ret;
}
dev_dbg(rtc->dev, "rtc_read_time: "
"buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY],
buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]);
ret = max77663_rtc_reg_to_tm(rtc, buf, tm);
if (ret < 0) {
dev_err(rtc->dev, "rtc_read_time: "
"Failed to convert register format into time format\n");
return ret;
}
dev_dbg(rtc->dev, "rtc_read_time: "
"tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d\n",
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec, tm->tm_wday);
return ret;
}
static int max77663_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct max77663_rtc *rtc = dev_get_drvdata(dev);
u8 buf[RTC_NR];
int ret;
dev_dbg(rtc->dev, "rtc_set_time: "
"tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d\n",
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec, tm->tm_wday);
ret = max77663_rtc_tm_to_reg(rtc, buf, tm, 0);
if (ret < 0) {
dev_err(rtc->dev, "rtc_set_time: "
"Failed to convert time format into register format\n");
return ret;
}
dev_dbg(rtc->dev, "rtc_set_time: "
"buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY],
buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]);
return max77663_rtc_write(rtc, MAX77663_RTC_SEC, buf, sizeof(buf), 1);
}
static int max77663_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max77663_rtc *rtc = dev_get_drvdata(dev);
u8 buf[RTC_NR];
int ret;
ret = max77663_rtc_read(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf),
1);
if (ret < 0) {
dev_err(rtc->dev,
"rtc_read_alarm: Failed to read rtc alarm time\n");
return ret;
}
dev_dbg(rtc->dev, "rtc_read_alarm: "
"buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY],
buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]);
ret = max77663_rtc_reg_to_tm(rtc, buf, &alrm->time);
if (ret < 0) {
dev_err(rtc->dev, "rtc_read_alarm: "
"Failed to convert register format into time format\n");
return ret;
}
dev_dbg(rtc->dev, "rtc_read_alarm: "
"tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d\n",
alrm->time.tm_year, alrm->time.tm_mon, alrm->time.tm_mday,
alrm->time.tm_hour, alrm->time.tm_min, alrm->time.tm_sec,
alrm->time.tm_wday);
if (rtc->irq_mask & RTC_IRQ_ALARM1_MASK)
alrm->enabled = 0;
else
alrm->enabled = 1;
return 0;
}
static int max77663_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max77663_rtc *rtc = dev_get_drvdata(dev);
u8 buf[RTC_NR];
int ret;
if (rtc->shutdown_ongoing) {
dev_warn(rtc->dev, "rtc_set_alarm: "
"Device shutdown on-going, skip alarm setting.\n");
return -ESHUTDOWN;
}
dev_dbg(rtc->dev, "rtc_set_alarm: "
"tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d [%s]\n",
alrm->time.tm_year, alrm->time.tm_mon, alrm->time.tm_mday,
alrm->time.tm_hour, alrm->time.tm_min, alrm->time.tm_sec,
alrm->time.tm_wday, alrm->enabled?"enable":"disable");
ret = max77663_rtc_tm_to_reg(rtc, buf, &alrm->time, 1);
if (ret < 0) {
dev_err(rtc->dev, "rtc_set_alarm: "
"Failed to convert time format into register format\n");
return ret;
}
dev_dbg(rtc->dev, "rtc_set_alarm: "
"buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY],
buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]);
ret = max77663_rtc_write(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf),
1);
if (ret < 0) {
dev_err(rtc->dev,
"rtc_set_alarm: Failed to write rtc alarm time\n");
return ret;
}
ret = max77663_rtc_alarm_irq_enable(dev, alrm->enabled);
if (ret < 0) {
dev_err(rtc->dev,
"rtc_set_alarm: Failed to enable rtc alarm\n");
return ret;
}
return ret;
}
static const struct rtc_class_ops max77663_rtc_ops = {
.read_time = max77663_rtc_read_time,
.set_time = max77663_rtc_set_time,
.read_alarm = max77663_rtc_read_alarm,
.set_alarm = max77663_rtc_set_alarm,
.alarm_irq_enable = max77663_rtc_alarm_irq_enable,
};
static int max77663_rtc_preinit(struct max77663_rtc *rtc)
{
struct device *parent = _to_parent(rtc);
u8 val;
int ret;
/* Mask all interrupts */
rtc->irq_mask = 0xFF;
ret = max77663_rtc_write(rtc, MAX77663_RTC_IRQ_MASK, &rtc->irq_mask, 1,
0);
if (ret < 0) {
dev_err(rtc->dev, "preinit: Failed to set rtc irq mask\n");
return ret;
}
/* Configure Binary mode and 24hour mode */
val = HR_MODE_MASK;
ret = max77663_rtc_write(rtc, MAX77663_RTC_CTRL, &val, 1, 0);
if (ret < 0) {
dev_err(rtc->dev, "preinit: Failed to set rtc control\n");
return ret;
}
/* It should be disabled alarm wakeup to wakeup from sleep
* by EN1 input signal */
ret = max77663_set_bits(parent, MAX77663_REG_ONOFF_CFG2,
ONOFF_WK_ALARM1_MASK, 0, 0);
if (ret < 0) {
dev_err(rtc->dev, "preinit: Failed to set onoff cfg2\n");
return ret;
}
return 0;
}
static int max77663_rtc_probe(struct platform_device *pdev)
{
struct max77663_platform_data *parent_pdata =
pdev->dev.parent->platform_data;
static struct max77663_rtc *rtc;
int ret = 0;
rtc = kzalloc(sizeof(struct max77663_rtc), GFP_KERNEL);
if (!rtc) {
dev_err(&pdev->dev, "probe: kzalloc() failed\n");
return -ENOMEM;
}
rtc->shutdown_ongoing = false;
dev_set_drvdata(&pdev->dev, rtc);
rtc->dev = &pdev->dev;
mutex_init(&rtc->io_lock);
ret = max77663_rtc_preinit(rtc);
if (ret) {
dev_err(&pdev->dev, "probe: Failed to rtc preinit\n");
goto out_kfree;
}
/*
* RTC should be a wakeup source, or alarm dev can't link to
* this devices. that cause Android time change not set into
* RTC register.
*/
device_init_wakeup(&pdev->dev, true);
rtc->rtc = rtc_device_register("max77663-rtc", &pdev->dev,
&max77663_rtc_ops, THIS_MODULE);
if (IS_ERR_OR_NULL(rtc->rtc)) {
dev_err(&pdev->dev, "probe: Failed to register rtc\n");
ret = PTR_ERR(rtc->rtc);
goto out_kfree;
}
if (parent_pdata->irq_base < 0)
goto out;
rtc->irq = parent_pdata->irq_base + MAX77663_IRQ_RTC;
ret = request_threaded_irq(rtc->irq, NULL, max77663_rtc_irq,
IRQF_ONESHOT, "max77663-rtc", rtc);
if (ret < 0) {
dev_err(rtc->dev, "probe: Failed to request irq %d\n",
rtc->irq);
rtc->irq = -1;
} else {
device_init_wakeup(rtc->dev, 1);
enable_irq_wake(rtc->irq);
}
return 0;
out_kfree:
mutex_destroy(&rtc->io_lock);
kfree(rtc->rtc);
out:
return ret;
}
static int max77663_rtc_remove(struct platform_device *pdev)
{
struct max77663_rtc *rtc = dev_get_drvdata(&pdev->dev);
if (rtc->irq != -1)
free_irq(rtc->irq, rtc);
rtc_device_unregister(rtc->rtc);
mutex_destroy(&rtc->io_lock);
kfree(rtc);
return 0;
}
static void max77663_rtc_shutdown(struct platform_device *pdev)
{
struct max77663_rtc *rtc = dev_get_drvdata(&pdev->dev);
u8 buf[RTC_NR] = { 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x1 };
rtc->shutdown_ongoing = true;
dev_info(rtc->dev, "rtc_shutdown: clean alarm\n");
max77663_rtc_write(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf), 1);
max77663_rtc_alarm_irq_enable(&pdev->dev, 0);
}
static struct platform_driver max77663_rtc_driver = {
.probe = max77663_rtc_probe,
.remove = max77663_rtc_remove,
.driver = {
.name = "max77663-rtc",
.owner = THIS_MODULE,
},
.shutdown = max77663_rtc_shutdown,
};
static int __init max77663_rtc_init(void)
{
return platform_driver_register(&max77663_rtc_driver);
}
module_init(max77663_rtc_init);
static void __exit max77663_rtc_exit(void)
{
platform_driver_unregister(&max77663_rtc_driver);
}
module_exit(max77663_rtc_exit);
MODULE_DESCRIPTION("max77663 RTC driver");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");