Merge branch 'master' into for-next
This commit is contained in:
@@ -611,6 +611,13 @@ config RTC_DRV_AB3100
|
||||
Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC
|
||||
support. This chip contains a battery- and capacitor-backed RTC.
|
||||
|
||||
config RTC_DRV_AB8500
|
||||
tristate "ST-Ericsson AB8500 RTC"
|
||||
depends on AB8500_CORE
|
||||
help
|
||||
Select this to enable the ST-Ericsson AB8500 power management IC RTC
|
||||
support. This chip contains a battery- and capacitor-backed RTC.
|
||||
|
||||
config RTC_DRV_NUC900
|
||||
tristate "NUC910/NUC920 RTC driver"
|
||||
depends on RTC_CLASS && ARCH_W90X900
|
||||
@@ -640,7 +647,7 @@ config RTC_DRV_OMAP
|
||||
|
||||
config RTC_DRV_S3C
|
||||
tristate "Samsung S3C series SoC RTC"
|
||||
depends on ARCH_S3C2410
|
||||
depends on ARCH_S3C2410 || ARCH_S3C64XX
|
||||
help
|
||||
RTC (Realtime Clock) driver for the clock inbuilt into the
|
||||
Samsung S3C24XX series of SoCs. This can provide periodic
|
||||
|
@@ -18,6 +18,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
|
||||
# Keep the list ordered.
|
||||
|
||||
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
|
||||
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
|
||||
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
|
||||
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
|
||||
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/mfd/ab3100.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
|
||||
/* Clock rate in Hz */
|
||||
#define AB3100_RTC_CLOCK_RATE 32768
|
||||
@@ -45,7 +45,6 @@
|
||||
*/
|
||||
static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs)
|
||||
{
|
||||
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
|
||||
u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2,
|
||||
AB3100_TI3, AB3100_TI4, AB3100_TI5};
|
||||
unsigned char buf[6];
|
||||
@@ -61,27 +60,26 @@ static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs)
|
||||
buf[5] = (fat_time >> 40) & 0xFF;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
err = ab3100_set_register_interruptible(ab3100_data,
|
||||
err = abx500_set_register_interruptible(dev, 0,
|
||||
regs[i], buf[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set the flag to mark that the clock is now set */
|
||||
return ab3100_mask_and_set_register_interruptible(ab3100_data,
|
||||
return abx500_mask_and_set_register_interruptible(dev, 0,
|
||||
AB3100_RTC,
|
||||
0xFE, 0x01);
|
||||
0x01, 0x01);
|
||||
|
||||
}
|
||||
|
||||
static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
|
||||
unsigned long time;
|
||||
u8 rtcval;
|
||||
int err;
|
||||
|
||||
err = ab3100_get_register_interruptible(ab3100_data,
|
||||
err = abx500_get_register_interruptible(dev, 0,
|
||||
AB3100_RTC, &rtcval);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -94,7 +92,7 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
u8 buf[6];
|
||||
|
||||
/* Read out time registers */
|
||||
err = ab3100_get_register_page_interruptible(ab3100_data,
|
||||
err = abx500_get_register_page_interruptible(dev, 0,
|
||||
AB3100_TI0,
|
||||
buf, 6);
|
||||
if (err != 0)
|
||||
@@ -114,7 +112,6 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
|
||||
unsigned long time;
|
||||
u64 fat_time;
|
||||
u8 buf[6];
|
||||
@@ -122,7 +119,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
int err;
|
||||
|
||||
/* Figure out if alarm is enabled or not */
|
||||
err = ab3100_get_register_interruptible(ab3100_data,
|
||||
err = abx500_get_register_interruptible(dev, 0,
|
||||
AB3100_RTC, &rtcval);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -133,7 +130,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
/* No idea how this could be represented */
|
||||
alarm->pending = 0;
|
||||
/* Read out alarm registers, only 4 bytes */
|
||||
err = ab3100_get_register_page_interruptible(ab3100_data,
|
||||
err = abx500_get_register_page_interruptible(dev, 0,
|
||||
AB3100_AL0, buf, 4);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -148,7 +145,6 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
|
||||
static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
|
||||
u8 regs[] = {AB3100_AL0, AB3100_AL1, AB3100_AL2, AB3100_AL3};
|
||||
unsigned char buf[4];
|
||||
unsigned long secs;
|
||||
@@ -165,21 +161,19 @@ static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
|
||||
/* Set the alarm */
|
||||
for (i = 0; i < 4; i++) {
|
||||
err = ab3100_set_register_interruptible(ab3100_data,
|
||||
err = abx500_set_register_interruptible(dev, 0,
|
||||
regs[i], buf[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
/* Then enable the alarm */
|
||||
return ab3100_mask_and_set_register_interruptible(ab3100_data,
|
||||
AB3100_RTC, ~(1 << 2),
|
||||
return abx500_mask_and_set_register_interruptible(dev, 0,
|
||||
AB3100_RTC, (1 << 2),
|
||||
alarm->enabled << 2);
|
||||
}
|
||||
|
||||
static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* It's not possible to enable/disable the alarm IRQ for this RTC.
|
||||
* It does not actually trigger any IRQ: instead its only function is
|
||||
@@ -188,12 +182,12 @@ static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
|
||||
* and need to be handled there instead.
|
||||
*/
|
||||
if (enabled)
|
||||
return ab3100_mask_and_set_register_interruptible(ab3100_data,
|
||||
AB3100_RTC, ~(1 << 2),
|
||||
return abx500_mask_and_set_register_interruptible(dev, 0,
|
||||
AB3100_RTC, (1 << 2),
|
||||
1 << 2);
|
||||
else
|
||||
return ab3100_mask_and_set_register_interruptible(ab3100_data,
|
||||
AB3100_RTC, ~(1 << 2),
|
||||
return abx500_mask_and_set_register_interruptible(dev, 0,
|
||||
AB3100_RTC, (1 << 2),
|
||||
0);
|
||||
}
|
||||
|
||||
@@ -210,10 +204,9 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
|
||||
int err;
|
||||
u8 regval;
|
||||
struct rtc_device *rtc;
|
||||
struct ab3100 *ab3100_data = platform_get_drvdata(pdev);
|
||||
|
||||
/* The first RTC register needs special treatment */
|
||||
err = ab3100_get_register_interruptible(ab3100_data,
|
||||
err = abx500_get_register_interruptible(&pdev->dev, 0,
|
||||
AB3100_RTC, ®val);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "unable to read RTC register\n");
|
||||
@@ -231,7 +224,7 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
|
||||
* This bit remains until RTC power is lost.
|
||||
*/
|
||||
regval = 1 | RTC_SETTING;
|
||||
err = ab3100_set_register_interruptible(ab3100_data,
|
||||
err = abx500_set_register_interruptible(&pdev->dev, 0,
|
||||
AB3100_RTC, regval);
|
||||
/* Ignore any error on this write */
|
||||
}
|
||||
|
363
drivers/rtc/rtc-ab8500.c
Normal file
363
drivers/rtc/rtc-ab8500.c
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2010
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* Author: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>
|
||||
*
|
||||
* RTC clock driver for the RTC part of the AB8500 Power management chip.
|
||||
* Based on RTC clock driver for the AB3100 Analog Baseband Chip by
|
||||
* Linus Walleij <linus.walleij@stericsson.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/mfd/ab8500.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define AB8500_RTC_SOFF_STAT_REG 0x0F00
|
||||
#define AB8500_RTC_CC_CONF_REG 0x0F01
|
||||
#define AB8500_RTC_READ_REQ_REG 0x0F02
|
||||
#define AB8500_RTC_WATCH_TSECMID_REG 0x0F03
|
||||
#define AB8500_RTC_WATCH_TSECHI_REG 0x0F04
|
||||
#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x0F05
|
||||
#define AB8500_RTC_WATCH_TMIN_MID_REG 0x0F06
|
||||
#define AB8500_RTC_WATCH_TMIN_HI_REG 0x0F07
|
||||
#define AB8500_RTC_ALRM_MIN_LOW_REG 0x0F08
|
||||
#define AB8500_RTC_ALRM_MIN_MID_REG 0x0F09
|
||||
#define AB8500_RTC_ALRM_MIN_HI_REG 0x0F0A
|
||||
#define AB8500_RTC_STAT_REG 0x0F0B
|
||||
#define AB8500_RTC_BKUP_CHG_REG 0x0F0C
|
||||
#define AB8500_RTC_FORCE_BKUP_REG 0x0F0D
|
||||
#define AB8500_RTC_CALIB_REG 0x0F0E
|
||||
#define AB8500_RTC_SWITCH_STAT_REG 0x0F0F
|
||||
#define AB8500_REV_REG 0x1080
|
||||
|
||||
/* RtcReadRequest bits */
|
||||
#define RTC_READ_REQUEST 0x01
|
||||
#define RTC_WRITE_REQUEST 0x02
|
||||
|
||||
/* RtcCtrl bits */
|
||||
#define RTC_ALARM_ENA 0x04
|
||||
#define RTC_STATUS_DATA 0x01
|
||||
|
||||
#define COUNTS_PER_SEC (0xF000 / 60)
|
||||
#define AB8500_RTC_EPOCH 2000
|
||||
|
||||
static const unsigned long ab8500_rtc_time_regs[] = {
|
||||
AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
|
||||
AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG,
|
||||
AB8500_RTC_WATCH_TSECMID_REG
|
||||
};
|
||||
|
||||
static const unsigned long ab8500_rtc_alarm_regs[] = {
|
||||
AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG,
|
||||
AB8500_RTC_ALRM_MIN_LOW_REG
|
||||
};
|
||||
|
||||
/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
|
||||
static unsigned long get_elapsed_seconds(int year)
|
||||
{
|
||||
unsigned long secs;
|
||||
struct rtc_time tm = {
|
||||
.tm_year = year - 1900,
|
||||
.tm_mday = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* This function calculates secs from 1970 and not from
|
||||
* 1900, even if we supply the offset from year 1900.
|
||||
*/
|
||||
rtc_tm_to_time(&tm, &secs);
|
||||
return secs;
|
||||
}
|
||||
|
||||
static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
|
||||
unsigned long timeout = jiffies + HZ;
|
||||
int retval, i;
|
||||
unsigned long mins, secs;
|
||||
unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
|
||||
|
||||
/* Request a data read */
|
||||
retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG,
|
||||
RTC_READ_REQUEST);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
/* Early AB8500 chips will not clear the rtc read request bit */
|
||||
if (ab8500->revision == 0) {
|
||||
msleep(1);
|
||||
} else {
|
||||
/* Wait for some cycles after enabling the rtc read in ab8500 */
|
||||
while (time_before(jiffies, timeout)) {
|
||||
retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
if (!(retval & RTC_READ_REQUEST))
|
||||
break;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the Watchtime registers */
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
|
||||
retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
buf[i] = retval;
|
||||
}
|
||||
|
||||
mins = (buf[0] << 16) | (buf[1] << 8) | buf[2];
|
||||
|
||||
secs = (buf[3] << 8) | buf[4];
|
||||
secs = secs / COUNTS_PER_SEC;
|
||||
secs = secs + (mins * 60);
|
||||
|
||||
/* Add back the initially subtracted number of seconds */
|
||||
secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
rtc_time_to_tm(secs, tm);
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
|
||||
int retval, i;
|
||||
unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
|
||||
unsigned long no_secs, no_mins, secs = 0;
|
||||
|
||||
if (tm->tm_year < (AB8500_RTC_EPOCH - 1900)) {
|
||||
dev_dbg(dev, "year should be equal to or greater than %d\n",
|
||||
AB8500_RTC_EPOCH);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the number of seconds since 1970 */
|
||||
rtc_tm_to_time(tm, &secs);
|
||||
|
||||
/*
|
||||
* Convert it to the number of seconds since 01-01-2000 00:00:00, since
|
||||
* we only have a small counter in the RTC.
|
||||
*/
|
||||
secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
no_mins = secs / 60;
|
||||
|
||||
no_secs = secs % 60;
|
||||
/* Make the seconds count as per the RTC resolution */
|
||||
no_secs = no_secs * COUNTS_PER_SEC;
|
||||
|
||||
buf[4] = no_secs & 0xFF;
|
||||
buf[3] = (no_secs >> 8) & 0xFF;
|
||||
|
||||
buf[2] = no_mins & 0xFF;
|
||||
buf[1] = (no_mins >> 8) & 0xFF;
|
||||
buf[0] = (no_mins >> 16) & 0xFF;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
|
||||
retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Request a data write */
|
||||
return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
|
||||
}
|
||||
|
||||
static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
|
||||
int retval, i;
|
||||
int rtc_ctrl;
|
||||
unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
|
||||
unsigned long secs, mins;
|
||||
|
||||
/* Check if the alarm is enabled or not */
|
||||
rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
|
||||
if (rtc_ctrl < 0)
|
||||
return rtc_ctrl;
|
||||
|
||||
if (rtc_ctrl & RTC_ALARM_ENA)
|
||||
alarm->enabled = 1;
|
||||
else
|
||||
alarm->enabled = 0;
|
||||
|
||||
alarm->pending = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
|
||||
retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
buf[i] = retval;
|
||||
}
|
||||
|
||||
mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
|
||||
secs = mins * 60;
|
||||
|
||||
/* Add back the initially subtracted number of seconds */
|
||||
secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
rtc_time_to_tm(secs, &alarm->time);
|
||||
|
||||
return rtc_valid_tm(&alarm->time);
|
||||
}
|
||||
|
||||
static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
|
||||
|
||||
return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
|
||||
enabled ? RTC_ALARM_ENA : 0);
|
||||
}
|
||||
|
||||
static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
|
||||
int retval, i;
|
||||
unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
|
||||
unsigned long mins, secs = 0;
|
||||
|
||||
if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
|
||||
dev_dbg(dev, "year should be equal to or greater than %d\n",
|
||||
AB8500_RTC_EPOCH);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the number of seconds since 1970 */
|
||||
rtc_tm_to_time(&alarm->time, &secs);
|
||||
|
||||
/*
|
||||
* Convert it to the number of seconds since 01-01-2000 00:00:00, since
|
||||
* we only have a small counter in the RTC.
|
||||
*/
|
||||
secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
mins = secs / 60;
|
||||
|
||||
buf[2] = mins & 0xFF;
|
||||
buf[1] = (mins >> 8) & 0xFF;
|
||||
buf[0] = (mins >> 16) & 0xFF;
|
||||
|
||||
/* Set the alarm time */
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
|
||||
retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
return ab8500_rtc_irq_enable(dev, alarm->enabled);
|
||||
}
|
||||
|
||||
static irqreturn_t rtc_alarm_handler(int irq, void *data)
|
||||
{
|
||||
struct rtc_device *rtc = data;
|
||||
unsigned long events = RTC_IRQF | RTC_AF;
|
||||
|
||||
dev_dbg(&rtc->dev, "%s\n", __func__);
|
||||
rtc_update_irq(rtc, 1, events);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops ab8500_rtc_ops = {
|
||||
.read_time = ab8500_rtc_read_time,
|
||||
.set_time = ab8500_rtc_set_time,
|
||||
.read_alarm = ab8500_rtc_read_alarm,
|
||||
.set_alarm = ab8500_rtc_set_alarm,
|
||||
.alarm_irq_enable = ab8500_rtc_irq_enable,
|
||||
};
|
||||
|
||||
static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
|
||||
int err;
|
||||
struct rtc_device *rtc;
|
||||
int rtc_ctrl;
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "ALARM");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
/* For RTC supply test */
|
||||
err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA,
|
||||
RTC_STATUS_DATA);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Wait for reset by the PorRtc */
|
||||
msleep(1);
|
||||
|
||||
rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
|
||||
if (rtc_ctrl < 0)
|
||||
return rtc_ctrl;
|
||||
|
||||
/* Check if the RTC Supply fails */
|
||||
if (!(rtc_ctrl & RTC_STATUS_DATA)) {
|
||||
dev_err(&pdev->dev, "RTC supply failure\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
dev_err(&pdev->dev, "Registration failed\n");
|
||||
err = PTR_ERR(rtc);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = request_threaded_irq(irq, NULL, rtc_alarm_handler, 0,
|
||||
"ab8500-rtc", rtc);
|
||||
if (err < 0) {
|
||||
rtc_device_unregister(rtc);
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rtc_device *rtc = platform_get_drvdata(pdev);
|
||||
int irq = platform_get_irq_byname(pdev, "ALARM");
|
||||
|
||||
free_irq(irq, rtc);
|
||||
rtc_device_unregister(rtc);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ab8500_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "ab8500-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ab8500_rtc_probe,
|
||||
.remove = __devexit_p(ab8500_rtc_remove),
|
||||
};
|
||||
|
||||
static int __init ab8500_rtc_init(void)
|
||||
{
|
||||
return platform_driver_register(&ab8500_rtc_driver);
|
||||
}
|
||||
|
||||
static void __exit ab8500_rtc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ab8500_rtc_driver);
|
||||
}
|
||||
|
||||
module_init(ab8500_rtc_init);
|
||||
module_exit(ab8500_rtc_exit);
|
||||
MODULE_AUTHOR("Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>");
|
||||
MODULE_DESCRIPTION("AB8500 RTC Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -238,31 +238,32 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
/* REVISIT this assumes PC style usage: always BCD */
|
||||
|
||||
if (((unsigned)t->time.tm_sec) < 0x60)
|
||||
t->time.tm_sec = bcd2bin(t->time.tm_sec);
|
||||
else
|
||||
t->time.tm_sec = -1;
|
||||
if (((unsigned)t->time.tm_min) < 0x60)
|
||||
t->time.tm_min = bcd2bin(t->time.tm_min);
|
||||
else
|
||||
t->time.tm_min = -1;
|
||||
if (((unsigned)t->time.tm_hour) < 0x24)
|
||||
t->time.tm_hour = bcd2bin(t->time.tm_hour);
|
||||
else
|
||||
t->time.tm_hour = -1;
|
||||
|
||||
if (cmos->day_alrm) {
|
||||
if (((unsigned)t->time.tm_mday) <= 0x31)
|
||||
t->time.tm_mday = bcd2bin(t->time.tm_mday);
|
||||
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
||||
if (((unsigned)t->time.tm_sec) < 0x60)
|
||||
t->time.tm_sec = bcd2bin(t->time.tm_sec);
|
||||
else
|
||||
t->time.tm_mday = -1;
|
||||
if (cmos->mon_alrm) {
|
||||
if (((unsigned)t->time.tm_mon) <= 0x12)
|
||||
t->time.tm_mon = bcd2bin(t->time.tm_mon) - 1;
|
||||
t->time.tm_sec = -1;
|
||||
if (((unsigned)t->time.tm_min) < 0x60)
|
||||
t->time.tm_min = bcd2bin(t->time.tm_min);
|
||||
else
|
||||
t->time.tm_min = -1;
|
||||
if (((unsigned)t->time.tm_hour) < 0x24)
|
||||
t->time.tm_hour = bcd2bin(t->time.tm_hour);
|
||||
else
|
||||
t->time.tm_hour = -1;
|
||||
|
||||
if (cmos->day_alrm) {
|
||||
if (((unsigned)t->time.tm_mday) <= 0x31)
|
||||
t->time.tm_mday = bcd2bin(t->time.tm_mday);
|
||||
else
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_mday = -1;
|
||||
|
||||
if (cmos->mon_alrm) {
|
||||
if (((unsigned)t->time.tm_mon) <= 0x12)
|
||||
t->time.tm_mon = bcd2bin(t->time.tm_mon)-1;
|
||||
else
|
||||
t->time.tm_mon = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
t->time.tm_year = -1;
|
||||
@@ -322,29 +323,26 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
|
||||
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
unsigned char mon, mday, hrs, min, sec;
|
||||
unsigned char mon, mday, hrs, min, sec, rtc_control;
|
||||
|
||||
if (!is_valid_irq(cmos->irq))
|
||||
return -EIO;
|
||||
|
||||
/* REVISIT this assumes PC style usage: always BCD */
|
||||
|
||||
/* Writing 0xff means "don't care" or "match all". */
|
||||
|
||||
mon = t->time.tm_mon + 1;
|
||||
mon = (mon <= 12) ? bin2bcd(mon) : 0xff;
|
||||
|
||||
mday = t->time.tm_mday;
|
||||
mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff;
|
||||
|
||||
hrs = t->time.tm_hour;
|
||||
hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff;
|
||||
|
||||
min = t->time.tm_min;
|
||||
min = (min < 60) ? bin2bcd(min) : 0xff;
|
||||
|
||||
sec = t->time.tm_sec;
|
||||
sec = (sec < 60) ? bin2bcd(sec) : 0xff;
|
||||
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
||||
/* Writing 0xff means "don't care" or "match all". */
|
||||
mon = (mon <= 12) ? bin2bcd(mon) : 0xff;
|
||||
mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff;
|
||||
hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff;
|
||||
min = (min < 60) ? bin2bcd(min) : 0xff;
|
||||
sec = (sec < 60) ? bin2bcd(sec) : 0xff;
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
|
||||
@@ -478,7 +476,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
|
||||
"update_IRQ\t: %s\n"
|
||||
"HPET_emulated\t: %s\n"
|
||||
// "square_wave\t: %s\n"
|
||||
// "BCD\t\t: %s\n"
|
||||
"BCD\t\t: %s\n"
|
||||
"DST_enable\t: %s\n"
|
||||
"periodic_freq\t: %d\n"
|
||||
"batt_status\t: %s\n",
|
||||
@@ -486,7 +484,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
|
||||
(rtc_control & RTC_UIE) ? "yes" : "no",
|
||||
is_hpet_enabled() ? "yes" : "no",
|
||||
// (rtc_control & RTC_SQWE) ? "yes" : "no",
|
||||
// (rtc_control & RTC_DM_BINARY) ? "no" : "yes",
|
||||
(rtc_control & RTC_DM_BINARY) ? "no" : "yes",
|
||||
(rtc_control & RTC_DST_EN) ? "yes" : "no",
|
||||
cmos->rtc->irq_freq,
|
||||
(valid & RTC_VRT) ? "okay" : "dead");
|
||||
@@ -721,6 +719,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
}
|
||||
}
|
||||
|
||||
cmos_rtc.dev = dev;
|
||||
dev_set_drvdata(dev, &cmos_rtc);
|
||||
|
||||
cmos_rtc.rtc = rtc_device_register(driver_name, dev,
|
||||
&cmos_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(cmos_rtc.rtc)) {
|
||||
@@ -728,8 +729,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
goto cleanup0;
|
||||
}
|
||||
|
||||
cmos_rtc.dev = dev;
|
||||
dev_set_drvdata(dev, &cmos_rtc);
|
||||
rename_region(ports, dev_name(&cmos_rtc.rtc->dev));
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
@@ -751,12 +750,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
/* FIXME teach the alarm code how to handle binary mode;
|
||||
/* FIXME:
|
||||
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
|
||||
*/
|
||||
if (is_valid_irq(rtc_irq) &&
|
||||
(!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) {
|
||||
dev_dbg(dev, "only 24-hr BCD mode supported\n");
|
||||
if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
|
||||
dev_warn(dev, "only 24-hr supported\n");
|
||||
retval = -ENXIO;
|
||||
goto cleanup1;
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
#define DRV_NAME "rtc-ds1302"
|
||||
#define DRV_VERSION "0.1.1"
|
||||
@@ -34,14 +33,55 @@
|
||||
#define RTC_ADDR_MIN 0x01 /* Address of minute register */
|
||||
#define RTC_ADDR_SEC 0x00 /* Address of second register */
|
||||
|
||||
#ifdef CONFIG_SH_SECUREEDGE5410
|
||||
#include <asm/rtc.h>
|
||||
#include <mach/snapgear.h>
|
||||
|
||||
#define RTC_RESET 0x1000
|
||||
#define RTC_IODATA 0x0800
|
||||
#define RTC_SCLK 0x0400
|
||||
|
||||
#ifdef CONFIG_SH_SECUREEDGE5410
|
||||
#include <mach/snapgear.h>
|
||||
#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
|
||||
#define get_dp() SECUREEDGE_READ_IOPORT()
|
||||
#define ds1302_set_tx()
|
||||
#define ds1302_set_rx()
|
||||
|
||||
static inline int ds1302_hw_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ds1302_reset(void)
|
||||
{
|
||||
set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
|
||||
}
|
||||
|
||||
static inline void ds1302_clock(void)
|
||||
{
|
||||
set_dp(get_dp() | RTC_SCLK); /* clock high */
|
||||
set_dp(get_dp() & ~RTC_SCLK); /* clock low */
|
||||
}
|
||||
|
||||
static inline void ds1302_start(void)
|
||||
{
|
||||
set_dp(get_dp() | RTC_RESET);
|
||||
}
|
||||
|
||||
static inline void ds1302_stop(void)
|
||||
{
|
||||
set_dp(get_dp() & ~RTC_RESET);
|
||||
}
|
||||
|
||||
static inline void ds1302_txbit(int bit)
|
||||
{
|
||||
set_dp((get_dp() & ~RTC_IODATA) | (bit ? RTC_IODATA : 0));
|
||||
}
|
||||
|
||||
static inline int ds1302_rxbit(void)
|
||||
{
|
||||
return !!(get_dp() & RTC_IODATA);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Add support for your platform"
|
||||
#endif
|
||||
@@ -50,11 +90,11 @@ static void ds1302_sendbits(unsigned int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
ds1302_set_tx();
|
||||
|
||||
for (i = 8; (i); i--, val >>= 1) {
|
||||
set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
|
||||
RTC_IODATA : 0));
|
||||
set_dp(get_dp() | RTC_SCLK); /* clock high */
|
||||
set_dp(get_dp() & ~RTC_SCLK); /* clock low */
|
||||
ds1302_txbit(val & 0x1);
|
||||
ds1302_clock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,10 +103,11 @@ static unsigned int ds1302_recvbits(void)
|
||||
unsigned int val;
|
||||
int i;
|
||||
|
||||
ds1302_set_rx();
|
||||
|
||||
for (i = 0, val = 0; (i < 8); i++) {
|
||||
val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
|
||||
set_dp(get_dp() | RTC_SCLK); /* clock high */
|
||||
set_dp(get_dp() & ~RTC_SCLK); /* clock low */
|
||||
val |= (ds1302_rxbit() << i);
|
||||
ds1302_clock();
|
||||
}
|
||||
|
||||
return val;
|
||||
@@ -76,23 +117,24 @@ static unsigned int ds1302_readbyte(unsigned int addr)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
|
||||
ds1302_reset();
|
||||
|
||||
set_dp(get_dp() | RTC_RESET);
|
||||
ds1302_start();
|
||||
ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
|
||||
val = ds1302_recvbits();
|
||||
set_dp(get_dp() & ~RTC_RESET);
|
||||
ds1302_stop();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ds1302_writebyte(unsigned int addr, unsigned int val)
|
||||
{
|
||||
set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
|
||||
set_dp(get_dp() | RTC_RESET);
|
||||
ds1302_reset();
|
||||
|
||||
ds1302_start();
|
||||
ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
|
||||
ds1302_sendbits(val);
|
||||
set_dp(get_dp() & ~RTC_RESET);
|
||||
ds1302_stop();
|
||||
}
|
||||
|
||||
static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
@@ -167,13 +209,20 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
|
||||
if (ds1302_hw_init()) {
|
||||
dev_err(&pdev->dev, "Failed to init communication channel");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
|
||||
ds1302_reset();
|
||||
|
||||
/* Write a magic value to the DS1302 RAM, and see if it sticks. */
|
||||
ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
|
||||
if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
|
||||
if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) {
|
||||
dev_err(&pdev->dev, "Failed to probe");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rtc = rtc_device_register("ds1302", &pdev->dev,
|
||||
&ds1302_rtc_ops, THIS_MODULE);
|
||||
|
@@ -403,7 +403,6 @@ out_irq:
|
||||
free_irq(client->irq, client);
|
||||
|
||||
out_free:
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(ds1374);
|
||||
return ret;
|
||||
}
|
||||
@@ -422,7 +421,6 @@ static int __devexit ds1374_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
rtc_device_unregister(ds1374->rtc);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(ds1374);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -462,39 +462,16 @@ isl1208_sysfs_store_usr(struct device *dev,
|
||||
static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
|
||||
isl1208_sysfs_store_usr);
|
||||
|
||||
static int
|
||||
isl1208_sysfs_register(struct device *dev)
|
||||
{
|
||||
int err;
|
||||
static struct attribute *isl1208_rtc_attrs[] = {
|
||||
&dev_attr_atrim.attr,
|
||||
&dev_attr_dtrim.attr,
|
||||
&dev_attr_usr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
err = device_create_file(dev, &dev_attr_atrim);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = device_create_file(dev, &dev_attr_dtrim);
|
||||
if (err) {
|
||||
device_remove_file(dev, &dev_attr_atrim);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = device_create_file(dev, &dev_attr_usr);
|
||||
if (err) {
|
||||
device_remove_file(dev, &dev_attr_atrim);
|
||||
device_remove_file(dev, &dev_attr_dtrim);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
isl1208_sysfs_unregister(struct device *dev)
|
||||
{
|
||||
device_remove_file(dev, &dev_attr_dtrim);
|
||||
device_remove_file(dev, &dev_attr_atrim);
|
||||
device_remove_file(dev, &dev_attr_usr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct attribute_group isl1208_rtc_sysfs_files = {
|
||||
.attrs = isl1208_rtc_attrs,
|
||||
};
|
||||
|
||||
static int
|
||||
isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
@@ -529,7 +506,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
dev_warn(&client->dev, "rtc power failure detected, "
|
||||
"please set clock.\n");
|
||||
|
||||
rc = isl1208_sysfs_register(&client->dev);
|
||||
rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
|
||||
if (rc)
|
||||
goto exit_unregister;
|
||||
|
||||
@@ -546,7 +523,7 @@ isl1208_remove(struct i2c_client *client)
|
||||
{
|
||||
struct rtc_device *rtc = i2c_get_clientdata(client);
|
||||
|
||||
isl1208_sysfs_unregister(&client->dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
|
||||
rtc_device_unregister(rtc);
|
||||
|
||||
return 0;
|
||||
|
@@ -595,10 +595,6 @@ static void wdt_disable(void)
|
||||
static ssize_t wdt_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
/* Can't seek (pwrite) on this device
|
||||
if (ppos != &file->f_pos)
|
||||
return -ESPIPE;
|
||||
*/
|
||||
if (count) {
|
||||
wdt_ping();
|
||||
return 1;
|
||||
@@ -623,7 +619,7 @@ static ssize_t wdt_read(struct file *file, char __user *buf,
|
||||
* according to their available features. We only actually usefully support
|
||||
* querying capabilities and current status.
|
||||
*/
|
||||
static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
static int wdt_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int new_margin, rv;
|
||||
@@ -676,6 +672,18 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
ret = wdt_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* wdt_open:
|
||||
* @inode: inode of device
|
||||
@@ -695,7 +703,7 @@ static int wdt_open(struct inode *inode, struct file *file)
|
||||
*/
|
||||
wdt_is_open = 1;
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
return nonseekable_open(inode, file);
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -736,7 +744,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
|
||||
static const struct file_operations wdt_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = wdt_read,
|
||||
.ioctl = wdt_ioctl,
|
||||
.unlocked_ioctl = wdt_unlocked_ioctl,
|
||||
.write = wdt_write,
|
||||
.open = wdt_open,
|
||||
.release = wdt_release,
|
||||
|
@@ -279,7 +279,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op,
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->regs = of_iomap(op->node, 0);
|
||||
rtc->regs = of_iomap(op->dev.of_node, 0);
|
||||
if (!rtc->regs) {
|
||||
dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
|
||||
err = -ENOSYS;
|
||||
@@ -290,7 +290,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op,
|
||||
|
||||
dev_set_drvdata(&op->dev, rtc);
|
||||
|
||||
rtc->irq = irq_of_parse_and_map(op->node, 1);
|
||||
rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
|
||||
err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
|
||||
"mpc5121-rtc", &op->dev);
|
||||
if (err) {
|
||||
@@ -299,7 +299,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op,
|
||||
goto out_dispose;
|
||||
}
|
||||
|
||||
rtc->irq_periodic = irq_of_parse_and_map(op->node, 0);
|
||||
rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
|
||||
err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
|
||||
IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
|
||||
if (err) {
|
||||
@@ -365,9 +365,11 @@ static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
|
||||
};
|
||||
|
||||
static struct of_platform_driver mpc5121_rtc_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mpc5121-rtc",
|
||||
.match_table = mpc5121_rtc_match,
|
||||
.driver = {
|
||||
.name = "mpc5121-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = mpc5121_rtc_match,
|
||||
},
|
||||
.probe = mpc5121_rtc_probe,
|
||||
.remove = __devexit_p(mpc5121_rtc_remove),
|
||||
};
|
||||
|
@@ -379,7 +379,6 @@ static struct rtc_class_ops mxc_rtc_ops = {
|
||||
|
||||
static int __init mxc_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct resource *res;
|
||||
struct rtc_device *rtc;
|
||||
struct rtc_plat_data *pdata = NULL;
|
||||
@@ -402,14 +401,15 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
|
||||
pdata->ioaddr = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
|
||||
clk = clk_get(&pdev->dev, "ckil");
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
pdata->clk = clk_get(&pdev->dev, "rtc");
|
||||
if (IS_ERR(pdata->clk)) {
|
||||
dev_err(&pdev->dev, "unable to get clock!\n");
|
||||
ret = PTR_ERR(pdata->clk);
|
||||
goto exit_free_pdata;
|
||||
}
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
clk_put(clk);
|
||||
clk_enable(pdata->clk);
|
||||
rate = clk_get_rate(pdata->clk);
|
||||
|
||||
if (rate == 32768)
|
||||
reg = RTC_INPUT_CLK_32768HZ;
|
||||
@@ -420,7 +420,7 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
|
||||
else {
|
||||
dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate);
|
||||
ret = -EINVAL;
|
||||
goto exit_free_pdata;
|
||||
goto exit_put_clk;
|
||||
}
|
||||
|
||||
reg |= RTC_ENABLE_BIT;
|
||||
@@ -428,18 +428,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
|
||||
if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
|
||||
dev_err(&pdev->dev, "hardware module can't be enabled!\n");
|
||||
ret = -EIO;
|
||||
goto exit_free_pdata;
|
||||
goto exit_put_clk;
|
||||
}
|
||||
|
||||
pdata->clk = clk_get(&pdev->dev, "rtc");
|
||||
if (IS_ERR(pdata->clk)) {
|
||||
dev_err(&pdev->dev, "unable to get clock!\n");
|
||||
ret = PTR_ERR(pdata->clk);
|
||||
goto exit_free_pdata;
|
||||
}
|
||||
|
||||
clk_enable(pdata->clk);
|
||||
|
||||
rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
|
@@ -632,7 +632,6 @@ errout_reg:
|
||||
rtc_device_unregister(rx8025->rtc);
|
||||
|
||||
errout_free:
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(rx8025);
|
||||
|
||||
errout:
|
||||
@@ -656,7 +655,6 @@ static int __devexit rx8025_remove(struct i2c_client *client)
|
||||
|
||||
rx8025_sysfs_unregister(&client->dev);
|
||||
rtc_device_unregister(rx8025->rtc);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(rx8025);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -275,7 +275,6 @@ exit_dummy:
|
||||
if (s35390a->client[i])
|
||||
i2c_unregister_device(s35390a->client[i]);
|
||||
kfree(s35390a);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
@@ -292,7 +291,6 @@ static int s35390a_remove(struct i2c_client *client)
|
||||
|
||||
rtc_device_unregister(s35390a->rtc);
|
||||
kfree(s35390a);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -29,6 +29,11 @@
|
||||
#include <asm/irq.h>
|
||||
#include <plat/regs-rtc.h>
|
||||
|
||||
enum s3c_cpu_type {
|
||||
TYPE_S3C2410,
|
||||
TYPE_S3C64XX,
|
||||
};
|
||||
|
||||
/* I have yet to find an S3C implementation with more than one
|
||||
* of these rtc blocks in */
|
||||
|
||||
@@ -37,6 +42,7 @@ static struct resource *s3c_rtc_mem;
|
||||
static void __iomem *s3c_rtc_base;
|
||||
static int s3c_rtc_alarmno = NO_IRQ;
|
||||
static int s3c_rtc_tickno = NO_IRQ;
|
||||
static enum s3c_cpu_type s3c_rtc_cpu_type;
|
||||
|
||||
static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
|
||||
|
||||
@@ -80,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
|
||||
pr_debug("%s: pie=%d\n", __func__, enabled);
|
||||
|
||||
spin_lock_irq(&s3c_rtc_pie_lock);
|
||||
tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
|
||||
|
||||
if (enabled)
|
||||
tmp |= S3C2410_TICNT_ENABLE;
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
|
||||
tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
|
||||
tmp &= ~S3C64XX_RTCCON_TICEN;
|
||||
|
||||
if (enabled)
|
||||
tmp |= S3C64XX_RTCCON_TICEN;
|
||||
|
||||
writeb(tmp, s3c_rtc_base + S3C2410_RTCCON);
|
||||
} else {
|
||||
tmp = readb(s3c_rtc_base + S3C2410_TICNT);
|
||||
tmp &= ~S3C2410_TICNT_ENABLE;
|
||||
|
||||
if (enabled)
|
||||
tmp |= S3C2410_TICNT_ENABLE;
|
||||
|
||||
writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
|
||||
}
|
||||
|
||||
writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
|
||||
spin_unlock_irq(&s3c_rtc_pie_lock);
|
||||
|
||||
return 0;
|
||||
@@ -93,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
|
||||
|
||||
static int s3c_rtc_setfreq(struct device *dev, int freq)
|
||||
{
|
||||
unsigned int tmp;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
|
||||
unsigned int tmp = 0;
|
||||
|
||||
if (!is_power_of_2(freq))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irq(&s3c_rtc_pie_lock);
|
||||
|
||||
tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
|
||||
tmp |= (128 / freq)-1;
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C2410) {
|
||||
tmp = readb(s3c_rtc_base + S3C2410_TICNT);
|
||||
tmp &= S3C2410_TICNT_ENABLE;
|
||||
}
|
||||
|
||||
tmp |= (rtc_dev->max_user_freq / freq)-1;
|
||||
|
||||
writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
|
||||
spin_unlock_irq(&s3c_rtc_pie_lock);
|
||||
@@ -283,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
|
||||
unsigned int ticnt;
|
||||
|
||||
seq_printf(seq, "periodic_IRQ\t: %s\n",
|
||||
(ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
|
||||
ticnt = readb(s3c_rtc_base + S3C2410_RTCCON);
|
||||
ticnt &= S3C64XX_RTCCON_TICEN;
|
||||
} else {
|
||||
ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
|
||||
ticnt &= S3C2410_TICNT_ENABLE;
|
||||
}
|
||||
|
||||
seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -353,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
|
||||
|
||||
if (!en) {
|
||||
tmp = readb(base + S3C2410_RTCCON);
|
||||
writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
|
||||
tmp &= ~S3C64XX_RTCCON_TICEN;
|
||||
tmp &= ~S3C2410_RTCCON_RTCEN;
|
||||
writeb(tmp, base + S3C2410_RTCCON);
|
||||
|
||||
tmp = readb(base + S3C2410_TICNT);
|
||||
writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C2410) {
|
||||
tmp = readb(base + S3C2410_TICNT);
|
||||
tmp &= ~S3C2410_TICNT_ENABLE;
|
||||
writeb(tmp, base + S3C2410_TICNT);
|
||||
}
|
||||
} else {
|
||||
/* re-enable the device, and check it is ok */
|
||||
|
||||
@@ -457,8 +495,6 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
|
||||
pr_debug("s3c2410_rtc: RTCCON=%02x\n",
|
||||
readb(s3c_rtc_base + S3C2410_RTCCON));
|
||||
|
||||
s3c_rtc_setfreq(&pdev->dev, 1);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
/* register RTC and exit */
|
||||
@@ -472,9 +508,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
|
||||
goto err_nortc;
|
||||
}
|
||||
|
||||
rtc->max_user_freq = 128;
|
||||
s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
|
||||
rtc->max_user_freq = 32768;
|
||||
else
|
||||
rtc->max_user_freq = 128;
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
s3c_rtc_setfreq(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_nortc:
|
||||
@@ -492,20 +536,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
/* RTC Power management control */
|
||||
|
||||
static int ticnt_save;
|
||||
static int ticnt_save, ticnt_en_save;
|
||||
|
||||
static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
/* save TICNT for anyone using periodic interrupts */
|
||||
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
|
||||
ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON);
|
||||
ticnt_en_save &= S3C64XX_RTCCON_TICEN;
|
||||
}
|
||||
s3c_rtc_enable(pdev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_rtc_resume(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
s3c_rtc_enable(pdev, 1);
|
||||
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
|
||||
if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
|
||||
tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
|
||||
writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
@@ -513,13 +567,27 @@ static int s3c_rtc_resume(struct platform_device *pdev)
|
||||
#define s3c_rtc_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver s3c2410_rtc_driver = {
|
||||
static struct platform_device_id s3c_rtc_driver_ids[] = {
|
||||
{
|
||||
.name = "s3c2410-rtc",
|
||||
.driver_data = TYPE_S3C2410,
|
||||
}, {
|
||||
.name = "s3c64xx-rtc",
|
||||
.driver_data = TYPE_S3C64XX,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
|
||||
|
||||
static struct platform_driver s3c_rtc_driver = {
|
||||
.probe = s3c_rtc_probe,
|
||||
.remove = __devexit_p(s3c_rtc_remove),
|
||||
.suspend = s3c_rtc_suspend,
|
||||
.resume = s3c_rtc_resume,
|
||||
.id_table = s3c_rtc_driver_ids,
|
||||
.driver = {
|
||||
.name = "s3c2410-rtc",
|
||||
.name = "s3c-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
@@ -529,12 +597,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics
|
||||
static int __init s3c_rtc_init(void)
|
||||
{
|
||||
printk(banner);
|
||||
return platform_driver_register(&s3c2410_rtc_driver);
|
||||
return platform_driver_register(&s3c_rtc_driver);
|
||||
}
|
||||
|
||||
static void __exit s3c_rtc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&s3c2410_rtc_driver);
|
||||
platform_driver_unregister(&s3c_rtc_driver);
|
||||
}
|
||||
|
||||
module_init(s3c_rtc_init);
|
||||
|
@@ -449,17 +449,17 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = wm831x_request_irq(wm831x, per_irq, wm831x_per_irq,
|
||||
IRQF_TRIGGER_RISING, "wm831x_rtc_per",
|
||||
wm831x_rtc);
|
||||
ret = request_threaded_irq(per_irq, NULL, wm831x_per_irq,
|
||||
IRQF_TRIGGER_RISING, "RTC period",
|
||||
wm831x_rtc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n",
|
||||
per_irq, ret);
|
||||
}
|
||||
|
||||
ret = wm831x_request_irq(wm831x, alm_irq, wm831x_alm_irq,
|
||||
IRQF_TRIGGER_RISING, "wm831x_rtc_alm",
|
||||
wm831x_rtc);
|
||||
ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq,
|
||||
IRQF_TRIGGER_RISING, "RTC alarm",
|
||||
wm831x_rtc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
|
||||
alm_irq, ret);
|
||||
@@ -478,8 +478,8 @@ static int __devexit wm831x_rtc_remove(struct platform_device *pdev)
|
||||
int per_irq = platform_get_irq_byname(pdev, "PER");
|
||||
int alm_irq = platform_get_irq_byname(pdev, "ALM");
|
||||
|
||||
wm831x_free_irq(wm831x_rtc->wm831x, alm_irq, wm831x_rtc);
|
||||
wm831x_free_irq(wm831x_rtc->wm831x, per_irq, wm831x_rtc);
|
||||
free_irq(alm_irq, wm831x_rtc);
|
||||
free_irq(per_irq, wm831x_rtc);
|
||||
rtc_device_unregister(wm831x_rtc->rtc);
|
||||
kfree(wm831x_rtc);
|
||||
|
||||
|
Reference in New Issue
Block a user