Merge 'akpm' patch series
* Merge akpm patch series: (122 commits) drivers/connector/cn_proc.c: remove unused local Documentation/SubmitChecklist: add RCU debug config options reiserfs: use hweight_long() reiserfs: use proper little-endian bitops pnpacpi: register disabled resources drivers/rtc/rtc-tegra.c: properly initialize spinlock drivers/rtc/rtc-twl.c: check return value of twl_rtc_write_u8() in twl_rtc_set_time() drivers/rtc: add support for Qualcomm PMIC8xxx RTC drivers/rtc/rtc-s3c.c: support clock gating drivers/rtc/rtc-mpc5121.c: add support for RTC on MPC5200 init: skip calibration delay if previously done misc/eeprom: add eeprom access driver for digsy_mtc board misc/eeprom: add driver for microwire 93xx46 EEPROMs checkpatch.pl: update $logFunctions checkpatch: make utf-8 test --strict checkpatch.pl: add ability to ignore various messages checkpatch: add a "prefer __aligned" check checkpatch: validate signature styles and To: and Cc: lines checkpatch: add __rcu as a sparse modifier checkpatch: suggest using min_t or max_t ... Did this as a merge because of (trivial) conflicts in - Documentation/feature-removal-schedule.txt - arch/xtensa/include/asm/uaccess.h that were just easier to fix up in the merge than in the patch series.
This commit is contained in:
@@ -1006,10 +1006,10 @@ config RTC_DRV_MC13XXX
|
||||
|
||||
config RTC_DRV_MPC5121
|
||||
tristate "Freescale MPC5121 built-in RTC"
|
||||
depends on PPC_MPC512x && RTC_CLASS
|
||||
depends on PPC_MPC512x || PPC_MPC52xx
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
built-in RTC MPC5121.
|
||||
built-in RTC on MPC5121 or on MPC5200.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-mpc5121.
|
||||
@@ -1034,6 +1034,16 @@ config RTC_DRV_LPC32XX
|
||||
This driver can also be buillt as a module. If so, the module
|
||||
will be called rtc-lpc32xx.
|
||||
|
||||
config RTC_DRV_PM8XXX
|
||||
tristate "Qualcomm PMIC8XXX RTC"
|
||||
depends on MFD_PM8XXX
|
||||
help
|
||||
If you say yes here you get support for the
|
||||
Qualcomm PMIC8XXX RTC.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rtc-pm8xxx.
|
||||
|
||||
config RTC_DRV_TEGRA
|
||||
tristate "NVIDIA Tegra Internal RTC driver"
|
||||
depends on RTC_CLASS && ARCH_TEGRA
|
||||
|
@@ -77,6 +77,7 @@ obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
|
||||
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
|
||||
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
|
||||
obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
|
||||
obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
|
||||
obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
|
||||
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
|
||||
|
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
|
||||
* Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
|
||||
* Copyright 2011, Dmitry Eremin-Solenikov
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -145,6 +146,55 @@ static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc5200_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
|
||||
struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
|
||||
int tmp;
|
||||
|
||||
tm->tm_sec = in_8(®s->second);
|
||||
tm->tm_min = in_8(®s->minute);
|
||||
|
||||
/* 12 hour format? */
|
||||
if (in_8(®s->hour) & 0x20)
|
||||
tm->tm_hour = (in_8(®s->hour) >> 1) +
|
||||
(in_8(®s->hour) & 1 ? 12 : 0);
|
||||
else
|
||||
tm->tm_hour = in_8(®s->hour);
|
||||
|
||||
tmp = in_8(®s->wday_mday);
|
||||
tm->tm_mday = tmp & 0x1f;
|
||||
tm->tm_mon = in_8(®s->month) - 1;
|
||||
tm->tm_year = in_be16(®s->year) - 1900;
|
||||
tm->tm_wday = (tmp >> 5) % 7;
|
||||
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
|
||||
tm->tm_isdst = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc5200_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
|
||||
struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
|
||||
|
||||
mpc5121_rtc_update_smh(regs, tm);
|
||||
|
||||
/* date */
|
||||
out_8(®s->month_set, tm->tm_mon + 1);
|
||||
out_8(®s->weekday_set, tm->tm_wday ? tm->tm_wday : 7);
|
||||
out_8(®s->date_set, tm->tm_mday);
|
||||
out_be16(®s->year_set, tm->tm_year + 1900);
|
||||
|
||||
/* set date sequence */
|
||||
out_8(®s->set_date, 0x1);
|
||||
out_8(®s->set_date, 0x3);
|
||||
out_8(®s->set_date, 0x1);
|
||||
out_8(®s->set_date, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
|
||||
@@ -248,11 +298,18 @@ static const struct rtc_class_ops mpc5121_rtc_ops = {
|
||||
.alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static const struct rtc_class_ops mpc5200_rtc_ops = {
|
||||
.read_time = mpc5200_rtc_read_time,
|
||||
.set_time = mpc5200_rtc_set_time,
|
||||
.read_alarm = mpc5121_rtc_read_alarm,
|
||||
.set_alarm = mpc5121_rtc_set_alarm,
|
||||
.alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int __devinit mpc5121_rtc_probe(struct platform_device *op)
|
||||
{
|
||||
struct mpc5121_rtc_data *rtc;
|
||||
int err = 0;
|
||||
u32 ka;
|
||||
|
||||
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
@@ -287,15 +344,22 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op)
|
||||
goto out_dispose2;
|
||||
}
|
||||
|
||||
ka = in_be32(&rtc->regs->keep_alive);
|
||||
if (ka & 0x02) {
|
||||
dev_warn(&op->dev,
|
||||
"mpc5121-rtc: Battery or oscillator failure!\n");
|
||||
out_be32(&rtc->regs->keep_alive, ka);
|
||||
if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) {
|
||||
u32 ka;
|
||||
ka = in_be32(&rtc->regs->keep_alive);
|
||||
if (ka & 0x02) {
|
||||
dev_warn(&op->dev,
|
||||
"mpc5121-rtc: Battery or oscillator failure!\n");
|
||||
out_be32(&rtc->regs->keep_alive, ka);
|
||||
}
|
||||
|
||||
rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
|
||||
&mpc5121_rtc_ops, THIS_MODULE);
|
||||
} else {
|
||||
rtc->rtc = rtc_device_register("mpc5200-rtc", &op->dev,
|
||||
&mpc5200_rtc_ops, THIS_MODULE);
|
||||
}
|
||||
|
||||
rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
|
||||
&mpc5121_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
err = PTR_ERR(rtc->rtc);
|
||||
goto out_free_irq;
|
||||
@@ -340,6 +404,7 @@ static int __devexit mpc5121_rtc_remove(struct platform_device *op)
|
||||
|
||||
static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
|
||||
{ .compatible = "fsl,mpc5121-rtc", },
|
||||
{ .compatible = "fsl,mpc5200-rtc", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
550
drivers/rtc/rtc-pm8xxx.c
Normal file
550
drivers/rtc/rtc-pm8xxx.c
Normal file
@@ -0,0 +1,550 @@
|
||||
/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
#include <linux/mfd/pm8xxx/rtc.h>
|
||||
|
||||
|
||||
/* RTC Register offsets from RTC CTRL REG */
|
||||
#define PM8XXX_ALARM_CTRL_OFFSET 0x01
|
||||
#define PM8XXX_RTC_WRITE_OFFSET 0x02
|
||||
#define PM8XXX_RTC_READ_OFFSET 0x06
|
||||
#define PM8XXX_ALARM_RW_OFFSET 0x0A
|
||||
|
||||
/* RTC_CTRL register bit fields */
|
||||
#define PM8xxx_RTC_ENABLE BIT(7)
|
||||
#define PM8xxx_RTC_ALARM_ENABLE BIT(1)
|
||||
#define PM8xxx_RTC_ALARM_CLEAR BIT(0)
|
||||
|
||||
#define NUM_8_BIT_RTC_REGS 0x4
|
||||
|
||||
/**
|
||||
* struct pm8xxx_rtc - rtc driver internal structure
|
||||
* @rtc: rtc device for this driver.
|
||||
* @rtc_alarm_irq: rtc alarm irq number.
|
||||
* @rtc_base: address of rtc control register.
|
||||
* @rtc_read_base: base address of read registers.
|
||||
* @rtc_write_base: base address of write registers.
|
||||
* @alarm_rw_base: base address of alarm registers.
|
||||
* @ctrl_reg: rtc control register.
|
||||
* @rtc_dev: device structure.
|
||||
* @ctrl_reg_lock: spinlock protecting access to ctrl_reg.
|
||||
*/
|
||||
struct pm8xxx_rtc {
|
||||
struct rtc_device *rtc;
|
||||
int rtc_alarm_irq;
|
||||
int rtc_base;
|
||||
int rtc_read_base;
|
||||
int rtc_write_base;
|
||||
int alarm_rw_base;
|
||||
u8 ctrl_reg;
|
||||
struct device *rtc_dev;
|
||||
spinlock_t ctrl_reg_lock;
|
||||
};
|
||||
|
||||
/*
|
||||
* The RTC registers need to be read/written one byte at a time. This is a
|
||||
* hardware limitation.
|
||||
*/
|
||||
static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
|
||||
int base, int count)
|
||||
{
|
||||
int i, rc;
|
||||
struct device *parent = rtc_dd->rtc_dev->parent;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
rc = pm8xxx_readb(parent, base + i, &rtc_val[i]);
|
||||
if (rc < 0) {
|
||||
dev_err(rtc_dd->rtc_dev, "PMIC read failed\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
|
||||
int base, int count)
|
||||
{
|
||||
int i, rc;
|
||||
struct device *parent = rtc_dd->rtc_dev->parent;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
rc = pm8xxx_writeb(parent, base + i, rtc_val[i]);
|
||||
if (rc < 0) {
|
||||
dev_err(rtc_dd->rtc_dev, "PMIC write failed\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Steps to write the RTC registers.
|
||||
* 1. Disable alarm if enabled.
|
||||
* 2. Write 0x00 to LSB.
|
||||
* 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
|
||||
* 4. Enable alarm if disabled in step 1.
|
||||
*/
|
||||
static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
int rc, i;
|
||||
unsigned long secs, irq_flags;
|
||||
u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg;
|
||||
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
|
||||
|
||||
rtc_tm_to_time(tm, &secs);
|
||||
|
||||
for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
|
||||
value[i] = secs & 0xFF;
|
||||
secs >>= 8;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
|
||||
|
||||
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
ctrl_reg = rtc_dd->ctrl_reg;
|
||||
|
||||
if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) {
|
||||
alarm_enabled = 1;
|
||||
ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
|
||||
1);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC control register "
|
||||
"failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
rtc_dd->ctrl_reg = ctrl_reg;
|
||||
} else
|
||||
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
|
||||
/* Write 0 to Byte[0] */
|
||||
reg = 0;
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, ®, rtc_dd->rtc_write_base, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC write data register failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
|
||||
/* Write Byte[1], Byte[2], Byte[3] */
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, value + 1,
|
||||
rtc_dd->rtc_write_base + 1, 3);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC write data register failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
|
||||
/* Write Byte[0] */
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC write data register failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
|
||||
if (alarm_enabled) {
|
||||
ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
|
||||
1);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC control register "
|
||||
"failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
rtc_dd->ctrl_reg = ctrl_reg;
|
||||
}
|
||||
|
||||
rtc_rw_fail:
|
||||
if (alarm_enabled)
|
||||
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
int rc;
|
||||
u8 value[NUM_8_BIT_RTC_REGS], reg;
|
||||
unsigned long secs;
|
||||
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
|
||||
|
||||
rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base,
|
||||
NUM_8_BIT_RTC_REGS);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "RTC read data register failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the LSB again and check if there has been a carry over.
|
||||
* If there is, redo the read operation.
|
||||
*/
|
||||
rc = pm8xxx_read_wrapper(rtc_dd, ®, rtc_dd->rtc_read_base, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "RTC read data register failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (unlikely(reg < value[0])) {
|
||||
rc = pm8xxx_read_wrapper(rtc_dd, value,
|
||||
rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "RTC read data register failed\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
|
||||
|
||||
rtc_time_to_tm(secs, tm);
|
||||
|
||||
rc = rtc_valid_tm(tm);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Invalid time read from RTC\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
|
||||
secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int rc, i;
|
||||
u8 value[NUM_8_BIT_RTC_REGS], ctrl_reg;
|
||||
unsigned long secs, irq_flags;
|
||||
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
|
||||
|
||||
rtc_tm_to_time(&alarm->time, &secs);
|
||||
|
||||
for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
|
||||
value[i] = secs & 0xFF;
|
||||
secs >>= 8;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
|
||||
NUM_8_BIT_RTC_REGS);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC ALARM register failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
|
||||
ctrl_reg = rtc_dd->ctrl_reg;
|
||||
ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
|
||||
(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
|
||||
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC control register failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
|
||||
rtc_dd->ctrl_reg = ctrl_reg;
|
||||
|
||||
dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
|
||||
alarm->time.tm_hour, alarm->time.tm_min,
|
||||
alarm->time.tm_sec, alarm->time.tm_mday,
|
||||
alarm->time.tm_mon, alarm->time.tm_year);
|
||||
rtc_rw_fail:
|
||||
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int rc;
|
||||
u8 value[NUM_8_BIT_RTC_REGS];
|
||||
unsigned long secs;
|
||||
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
|
||||
|
||||
rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
|
||||
NUM_8_BIT_RTC_REGS);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "RTC alarm time read failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
|
||||
|
||||
rtc_time_to_tm(secs, &alarm->time);
|
||||
|
||||
rc = rtc_valid_tm(&alarm->time);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Invalid alarm time read from RTC\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
|
||||
alarm->time.tm_hour, alarm->time.tm_min,
|
||||
alarm->time.tm_sec, alarm->time.tm_mday,
|
||||
alarm->time.tm_mon, alarm->time.tm_year);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
int rc;
|
||||
unsigned long irq_flags;
|
||||
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
|
||||
u8 ctrl_reg;
|
||||
|
||||
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
ctrl_reg = rtc_dd->ctrl_reg;
|
||||
ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
|
||||
(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
|
||||
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Write to RTC control register failed\n");
|
||||
goto rtc_rw_fail;
|
||||
}
|
||||
|
||||
rtc_dd->ctrl_reg = ctrl_reg;
|
||||
|
||||
rtc_rw_fail:
|
||||
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct rtc_class_ops pm8xxx_rtc_ops = {
|
||||
.read_time = pm8xxx_rtc_read_time,
|
||||
.set_alarm = pm8xxx_rtc_set_alarm,
|
||||
.read_alarm = pm8xxx_rtc_read_alarm,
|
||||
.alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
|
||||
{
|
||||
struct pm8xxx_rtc *rtc_dd = dev_id;
|
||||
u8 ctrl_reg;
|
||||
int rc;
|
||||
unsigned long irq_flags;
|
||||
|
||||
rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
|
||||
/* Clear the alarm enable bit */
|
||||
ctrl_reg = rtc_dd->ctrl_reg;
|
||||
ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
|
||||
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
|
||||
if (rc < 0) {
|
||||
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
dev_err(rtc_dd->rtc_dev, "Write to RTC control register "
|
||||
"failed\n");
|
||||
goto rtc_alarm_handled;
|
||||
}
|
||||
|
||||
rtc_dd->ctrl_reg = ctrl_reg;
|
||||
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
|
||||
|
||||
/* Clear RTC alarm register */
|
||||
rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
|
||||
PM8XXX_ALARM_CTRL_OFFSET, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read "
|
||||
"failed\n");
|
||||
goto rtc_alarm_handled;
|
||||
}
|
||||
|
||||
ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR;
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
|
||||
PM8XXX_ALARM_CTRL_OFFSET, 1);
|
||||
if (rc < 0)
|
||||
dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register"
|
||||
" failed\n");
|
||||
|
||||
rtc_alarm_handled:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit pm8xxx_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
u8 ctrl_reg;
|
||||
bool rtc_write_enable = false;
|
||||
struct pm8xxx_rtc *rtc_dd;
|
||||
struct resource *rtc_resource;
|
||||
const struct pm8xxx_rtc_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (pdata != NULL)
|
||||
rtc_write_enable = pdata->rtc_write_enable;
|
||||
|
||||
rtc_dd = kzalloc(sizeof(*rtc_dd), GFP_KERNEL);
|
||||
if (rtc_dd == NULL) {
|
||||
dev_err(&pdev->dev, "Unable to allocate memory!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Initialise spinlock to protect RTC control register */
|
||||
spin_lock_init(&rtc_dd->ctrl_reg_lock);
|
||||
|
||||
rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
|
||||
if (rtc_dd->rtc_alarm_irq < 0) {
|
||||
dev_err(&pdev->dev, "Alarm IRQ resource absent!\n");
|
||||
rc = -ENXIO;
|
||||
goto fail_rtc_enable;
|
||||
}
|
||||
|
||||
rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
|
||||
"pmic_rtc_base");
|
||||
if (!(rtc_resource && rtc_resource->start)) {
|
||||
dev_err(&pdev->dev, "RTC IO resource absent!\n");
|
||||
rc = -ENXIO;
|
||||
goto fail_rtc_enable;
|
||||
}
|
||||
|
||||
rtc_dd->rtc_base = rtc_resource->start;
|
||||
|
||||
/* Setup RTC register addresses */
|
||||
rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET;
|
||||
rtc_dd->rtc_read_base = rtc_dd->rtc_base + PM8XXX_RTC_READ_OFFSET;
|
||||
rtc_dd->alarm_rw_base = rtc_dd->rtc_base + PM8XXX_ALARM_RW_OFFSET;
|
||||
|
||||
rtc_dd->rtc_dev = &pdev->dev;
|
||||
|
||||
/* Check if the RTC is on, else turn it on */
|
||||
rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "RTC control register read failed!\n");
|
||||
goto fail_rtc_enable;
|
||||
}
|
||||
|
||||
if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
|
||||
ctrl_reg |= PM8xxx_RTC_ENABLE;
|
||||
rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
|
||||
1);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "Write to RTC control register "
|
||||
"failed\n");
|
||||
goto fail_rtc_enable;
|
||||
}
|
||||
}
|
||||
|
||||
rtc_dd->ctrl_reg = ctrl_reg;
|
||||
if (rtc_write_enable == true)
|
||||
pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time;
|
||||
|
||||
platform_set_drvdata(pdev, rtc_dd);
|
||||
|
||||
/* Register the RTC device */
|
||||
rtc_dd->rtc = rtc_device_register("pm8xxx_rtc", &pdev->dev,
|
||||
&pm8xxx_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc_dd->rtc)) {
|
||||
dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",
|
||||
__func__, PTR_ERR(rtc_dd->rtc));
|
||||
rc = PTR_ERR(rtc_dd->rtc);
|
||||
goto fail_rtc_enable;
|
||||
}
|
||||
|
||||
/* Request the alarm IRQ */
|
||||
rc = request_any_context_irq(rtc_dd->rtc_alarm_irq,
|
||||
pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING,
|
||||
"pm8xxx_rtc_alarm", rtc_dd);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
|
||||
goto fail_req_irq;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
dev_dbg(&pdev->dev, "Probe success !!\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_req_irq:
|
||||
rtc_device_unregister(rtc_dd->rtc);
|
||||
fail_rtc_enable:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(rtc_dd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
|
||||
rtc_device_unregister(rtc_dd->rtc);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(rtc_dd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pm8xxx_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(rtc_dd->rtc_alarm_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(rtc_dd->rtc_alarm_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
|
||||
|
||||
static struct platform_driver pm8xxx_rtc_driver = {
|
||||
.probe = pm8xxx_rtc_probe,
|
||||
.remove = __devexit_p(pm8xxx_rtc_remove),
|
||||
.driver = {
|
||||
.name = PM8XXX_RTC_DEV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm8xxx_rtc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pm8xxx_rtc_init(void)
|
||||
{
|
||||
return platform_driver_register(&pm8xxx_rtc_driver);
|
||||
}
|
||||
module_init(pm8xxx_rtc_init);
|
||||
|
||||
static void __exit pm8xxx_rtc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pm8xxx_rtc_driver);
|
||||
}
|
||||
module_exit(pm8xxx_rtc_exit);
|
||||
|
||||
MODULE_ALIAS("platform:rtc-pm8xxx");
|
||||
MODULE_DESCRIPTION("PMIC8xxx RTC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>");
|
@@ -57,11 +57,13 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
|
||||
{
|
||||
struct rtc_device *rdev = id;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
|
||||
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
|
||||
writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP);
|
||||
|
||||
clk_disable(rtc_clk);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -69,11 +71,13 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
|
||||
{
|
||||
struct rtc_device *rdev = id;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
|
||||
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
|
||||
writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP);
|
||||
|
||||
clk_disable(rtc_clk);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -84,12 +88,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
|
||||
|
||||
pr_debug("%s: aie=%d\n", __func__, enabled);
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
|
||||
|
||||
if (enabled)
|
||||
tmp |= S3C2410_RTCALM_ALMEN;
|
||||
|
||||
writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
|
||||
clk_disable(rtc_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -103,6 +109,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq)
|
||||
if (!is_power_of_2(freq))
|
||||
return -EINVAL;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
spin_lock_irq(&s3c_rtc_pie_lock);
|
||||
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C2410) {
|
||||
@@ -114,6 +121,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq)
|
||||
|
||||
writel(tmp, s3c_rtc_base + S3C2410_TICNT);
|
||||
spin_unlock_irq(&s3c_rtc_pie_lock);
|
||||
clk_disable(rtc_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -125,6 +133,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
||||
unsigned int have_retried = 0;
|
||||
void __iomem *base = s3c_rtc_base;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
retry_get_time:
|
||||
rtc_tm->tm_min = readb(base + S3C2410_RTCMIN);
|
||||
rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
|
||||
@@ -157,6 +166,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
||||
rtc_tm->tm_year += 100;
|
||||
rtc_tm->tm_mon -= 1;
|
||||
|
||||
clk_disable(rtc_clk);
|
||||
return rtc_valid_tm(rtc_tm);
|
||||
}
|
||||
|
||||
@@ -165,6 +175,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
void __iomem *base = s3c_rtc_base;
|
||||
int year = tm->tm_year - 100;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
@@ -182,6 +193,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);
|
||||
writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);
|
||||
writeb(bin2bcd(year), base + S3C2410_RTCYEAR);
|
||||
clk_disable(rtc_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -192,6 +204,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
void __iomem *base = s3c_rtc_base;
|
||||
unsigned int alm_en;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
alm_tm->tm_sec = readb(base + S3C2410_ALMSEC);
|
||||
alm_tm->tm_min = readb(base + S3C2410_ALMMIN);
|
||||
alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);
|
||||
@@ -243,6 +256,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
else
|
||||
alm_tm->tm_year = -1;
|
||||
|
||||
clk_disable(rtc_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -252,6 +266,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
void __iomem *base = s3c_rtc_base;
|
||||
unsigned int alrm_en;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
alrm->enabled,
|
||||
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
|
||||
@@ -282,6 +297,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
s3c_rtc_setaie(dev, alrm->enabled);
|
||||
|
||||
clk_disable(rtc_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -289,6 +305,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
unsigned int ticnt;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
|
||||
ticnt = readw(s3c_rtc_base + S3C2410_RTCCON);
|
||||
ticnt &= S3C64XX_RTCCON_TICEN;
|
||||
@@ -298,6 +315,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
}
|
||||
|
||||
seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
|
||||
clk_disable(rtc_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -360,6 +378,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
|
||||
if (s3c_rtc_base == NULL)
|
||||
return;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
if (!en) {
|
||||
tmp = readw(base + S3C2410_RTCCON);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
|
||||
@@ -399,6 +418,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
|
||||
base + S3C2410_RTCCON);
|
||||
}
|
||||
}
|
||||
clk_disable(rtc_clk);
|
||||
}
|
||||
|
||||
static int __devexit s3c_rtc_remove(struct platform_device *dev)
|
||||
@@ -410,7 +430,6 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
|
||||
|
||||
s3c_rtc_setaie(&dev->dev, 0);
|
||||
|
||||
clk_disable(rtc_clk);
|
||||
clk_put(rtc_clk);
|
||||
rtc_clk = NULL;
|
||||
|
||||
@@ -529,6 +548,8 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
s3c_rtc_setfreq(&pdev->dev, 1);
|
||||
|
||||
clk_disable(rtc_clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_nortc:
|
||||
@@ -554,6 +575,7 @@ static int ticnt_save, ticnt_en_save;
|
||||
|
||||
static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
clk_enable(rtc_clk);
|
||||
/* save TICNT for anyone using periodic interrupts */
|
||||
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
|
||||
@@ -568,6 +590,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
else
|
||||
dev_err(&pdev->dev, "enable_irq_wake failed\n");
|
||||
}
|
||||
clk_disable(rtc_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -576,6 +599,7 @@ static int s3c_rtc_resume(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
s3c_rtc_enable(pdev, 1);
|
||||
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
|
||||
@@ -587,6 +611,7 @@ static int s3c_rtc_resume(struct platform_device *pdev)
|
||||
disable_irq_wake(s3c_rtc_alarmno);
|
||||
wake_en = false;
|
||||
}
|
||||
clk_disable(rtc_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -343,7 +343,7 @@ static int __devinit tegra_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
/* set context info. */
|
||||
info->pdev = pdev;
|
||||
info->tegra_rtc_lock = __SPIN_LOCK_UNLOCKED(info->tegra_rtc_lock);
|
||||
spin_lock_init(&info->tegra_rtc_lock);
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
|
@@ -275,7 +275,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
goto out;
|
||||
|
||||
save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
|
||||
twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
|
||||
ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
Reference in New Issue
Block a user