Merge branch 'akpm' (Andrew's patch-bomb)

Merge misc patches from Andrew Morton:
 "The MM tree is rather stuck while I wait to find out what the heck is
  happening with sched/numa.  Probably I'll need to route around all the
  code which was added to -next, sigh.

  So this is "everything else", or at least most of it - other small
  bits are still awaiting resolutions of various kinds."

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (180 commits)
  lib/decompress.c add __init to decompress_method and data
  kernel/resource.c: fix stack overflow in __reserve_region_with_split()
  omfs: convert to use beXX_add_cpu()
  taskstats: cgroupstats_user_cmd() may leak on error
  aoe: update aoe-internal version number to 50
  aoe: update documentation to better reflect aoe-plus-udev usage
  aoe: remove unused code
  aoe: make dynamic block minor numbers the default
  aoe: update and specify AoE address guards and error messages
  aoe: retain static block device numbers for backwards compatibility
  aoe: support more AoE addresses with dynamic block device minor numbers
  aoe: update documentation with new URL and VM settings reference
  aoe: update copyright year in touched files
  aoe: update internal version number to 49
  aoe: remove unused code and add cosmetic improvements
  aoe: increase net_device reference count while using it
  aoe: associate frames with the AoE storage target
  aoe: disallow unsupported AoE minor addresses
  aoe: do revalidation steps in order
  aoe: failover remote interface based on aoe_deadsecs parameter
  ...
This commit is contained in:
Linus Torvalds
2012-10-06 03:09:16 +09:00
308 changed files with 7397 additions and 2732 deletions

View File

@@ -19,7 +19,6 @@ if RTC_CLASS
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
depends on RTC_CLASS = y
default y
help
If you say yes here, the system time (wall clock) will be set using
@@ -51,7 +50,6 @@ config RTC_HCTOSYS_DEVICE
config RTC_DEBUG
bool "RTC debug support"
depends on RTC_CLASS = y
help
Say yes here to enable debugging support in the RTC framework
and individual RTC drivers.
@@ -61,7 +59,6 @@ comment "RTC interfaces"
config RTC_INTF_SYSFS
boolean "/sys/class/rtc/rtcN (sysfs)"
depends on SYSFS
default RTC_CLASS
help
Say yes here if you want to use your RTCs using sysfs interfaces,
/sys/class/rtc/rtc0 through /sys/.../rtcN.
@@ -69,19 +66,19 @@ config RTC_INTF_SYSFS
If unsure, say Y.
config RTC_INTF_PROC
boolean "/proc/driver/rtc (procfs for rtc0)"
boolean "/proc/driver/rtc (procfs for rtcN)"
depends on PROC_FS
default RTC_CLASS
help
Say yes here if you want to use your first RTC through the proc
interface, /proc/driver/rtc. Other RTCs will not be available
through that API.
Say yes here if you want to use your system clock RTC through
the proc interface, /proc/driver/rtc.
Other RTCs will not be available through that API.
If there is no RTC for the system clock, then the first RTC(rtc0)
is used by default.
If unsure, say Y.
config RTC_INTF_DEV
boolean "/dev/rtcN (character devices)"
default RTC_CLASS
help
Say yes here if you want to use your RTCs using the /dev
interfaces, which "udev" sets up as /dev/rtc0 through
@@ -127,7 +124,7 @@ if I2C
config RTC_DRV_88PM860X
tristate "Marvell 88PM860x"
depends on RTC_CLASS && I2C && MFD_88PM860X
depends on I2C && MFD_88PM860X
help
If you say yes here you get support for RTC function in Marvell
88PM860x chips.
@@ -137,7 +134,7 @@ config RTC_DRV_88PM860X
config RTC_DRV_88PM80X
tristate "Marvell 88PM80x"
depends on RTC_CLASS && I2C && MFD_88PM800
depends on I2C && MFD_88PM800
help
If you say yes here you get support for RTC function in Marvell
88PM80x chips.
@@ -165,7 +162,7 @@ config RTC_DRV_DS1307
config RTC_DRV_DS1374
tristate "Dallas/Maxim DS1374"
depends on RTC_CLASS && I2C
depends on I2C
help
If you say yes here you get support for Dallas Semiconductor
DS1374 real-time clock chips. If an interrupt is associated
@@ -185,7 +182,7 @@ config RTC_DRV_DS1672
config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232"
depends on RTC_CLASS && I2C
depends on I2C
help
If you say yes here you get support for Dallas Semiconductor
DS3232 real-time clock chips. If an interrupt is associated
@@ -203,6 +200,16 @@ config RTC_DRV_MAX6900
This driver can also be built as a module. If so, the module
will be called rtc-max6900.
config RTC_DRV_MAX8907
tristate "Maxim MAX8907"
depends on MFD_MAX8907
help
If you say yes here you will get support for the
RTC of Maxim MAX8907 PMIC.
This driver can also be built as a module. If so, the module
will be called rtc-max8907.
config RTC_DRV_MAX8925
tristate "Maxim MAX8925"
depends on MFD_MAX8925
@@ -325,7 +332,7 @@ config RTC_DRV_TWL92330
config RTC_DRV_TWL4030
tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
depends on RTC_CLASS && TWL4030_CORE
depends on TWL4030_CORE
help
If you say yes here you get support for the RTC on the
TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
@@ -333,6 +340,26 @@ config RTC_DRV_TWL4030
This driver can also be built as a module. If so, the module
will be called rtc-twl.
config RTC_DRV_TPS65910
tristate "TI TPS65910 RTC driver"
depends on RTC_CLASS && MFD_TPS65910
help
If you say yes here you get support for the RTC on the
TPS65910 chips.
This driver can also be built as a module. If so, the module
will be called rtc-tps65910.
config RTC_DRV_RC5T583
tristate "RICOH 5T583 RTC driver"
depends on MFD_RC5T583
help
If you say yes here you get support for the RTC on the
RICOH 5T583 chips.
This driver can also be built as a module. If so, the module
will be called rtc-rc5t583.
config RTC_DRV_S35390A
tristate "Seiko Instruments S-35390A"
select BITREVERSE
@@ -538,7 +565,6 @@ config RTC_DRV_DS1302
config RTC_DRV_DS1511
tristate "Dallas DS1511"
depends on RTC_CLASS
help
If you say yes here you get support for the
Dallas DS1511 timekeeping/watchdog chip.
@@ -583,7 +609,6 @@ config RTC_DRV_EFI
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
depends on RTC_CLASS
help
If you say yes here you get support for the
Simtek STK17TA8 timekeeping chip.
@@ -658,6 +683,15 @@ config RTC_DRV_V3020
This driver can also be built as a module. If so, the module
will be called rtc-v3020.
config RTC_DRV_DS2404
tristate "Dallas DS2404"
help
If you say yes here you get support for the
Dallas DS2404 RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-ds2404.
config RTC_DRV_WM831X
tristate "Wolfson Microelectronics WM831x RTC"
depends on MFD_WM831X
@@ -704,6 +738,7 @@ config RTC_DRV_AB3100
config RTC_DRV_AB8500
tristate "ST-Ericsson AB8500 RTC"
depends on AB8500_CORE
select RTC_INTF_DEV
select RTC_INTF_DEV_UIE_EMUL
help
Select this to enable the ST-Ericsson AB8500 power management IC RTC
@@ -711,7 +746,7 @@ config RTC_DRV_AB8500
config RTC_DRV_NUC900
tristate "NUC910/NUC920 RTC driver"
depends on RTC_CLASS && ARCH_W90X900
depends on ARCH_W90X900
help
If you say yes here you get support for the RTC subsystem of the
NUC910/NUC920 used in embedded systems.
@@ -731,7 +766,6 @@ config RTC_DRV_DAVINCI
config RTC_DRV_IMXDI
tristate "Freescale IMX DryIce Real Time Clock"
depends on SOC_IMX25
depends on RTC_CLASS
help
Support for Freescale IMX DryIce RTC
@@ -791,7 +825,7 @@ config RTC_DRV_SA1100
config RTC_DRV_SH
tristate "SuperH On-Chip RTC"
depends on RTC_CLASS && SUPERH && HAVE_CLK
depends on SUPERH && HAVE_CLK
help
Say Y here to enable support for the on-chip RTC found in
most SuperH processors.
@@ -1023,7 +1057,6 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
depends on RTC_CLASS
depends on MACH_JZ4740
help
If you say yes here you get support for the Ingenic JZ4740 SoC RTC
@@ -1053,7 +1086,7 @@ config RTC_DRV_PM8XXX
config RTC_DRV_TEGRA
tristate "NVIDIA Tegra Internal RTC driver"
depends on RTC_CLASS && ARCH_TEGRA
depends on ARCH_TEGRA
help
If you say yes here you get support for the
Tegra 200 series internal RTC module.
@@ -1090,7 +1123,6 @@ config RTC_DRV_LOONGSON1
config RTC_DRV_MXC
tristate "Freescale MXC Real Time Clock"
depends on ARCH_MXC
depends on RTC_CLASS
help
If you say yes here you get support for the Freescale MXC
RTC module.
@@ -1098,4 +1130,15 @@ config RTC_DRV_MXC
This driver can also be built as a module, if so, the module
will be called "rtc-mxc".
config RTC_DRV_SNVS
tristate "Freescale SNVS RTC support"
depends on HAS_IOMEM
depends on OF
help
If you say yes here you get support for the Freescale SNVS
Low Power (LP) RTC module.
This driver can also be built as a module, if so, the module
will be called "rtc-snvs".
endif # RTC_CLASS

View File

@@ -43,6 +43,7 @@ obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
@@ -64,6 +65,7 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
@@ -85,6 +87,7 @@ obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
@@ -96,6 +99,7 @@ obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
@@ -105,6 +109,7 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o

View File

@@ -31,8 +31,12 @@ static void rtc_device_release(struct device *dev)
kfree(rtc);
}
#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
#ifdef CONFIG_RTC_HCTOSYS_DEVICE
/* Result of the last RTC to system clock attempt. */
int rtc_hctosys_ret = -ENODEV;
#endif
#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
/*
* On suspend(), measure the delta between one RTC and the
* system's wall clock; restore it on resume().
@@ -84,6 +88,7 @@ static int rtc_resume(struct device *dev)
struct timespec new_system, new_rtc;
struct timespec sleep_time;
rtc_hctosys_ret = -ENODEV;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
@@ -117,6 +122,7 @@ static int rtc_resume(struct device *dev)
if (sleep_time.tv_sec >= 0)
timekeeping_inject_sleeptime(&sleep_time);
rtc_hctosys_ret = 0;
return 0;
}
@@ -238,6 +244,7 @@ void rtc_device_unregister(struct rtc_device *rtc)
rtc_proc_del_device(rtc);
device_unregister(&rtc->dev);
rtc->ops = NULL;
ida_simple_remove(&rtc_ida, rtc->id);
mutex_unlock(&rtc->ops_lock);
put_device(&rtc->dev);
}

View File

@@ -22,8 +22,6 @@
* the best guess is to add 0.5s.
*/
int rtc_hctosys_ret = -ENODEV;
static int __init rtc_hctosys(void)
{
int err = -ENODEV;
@@ -56,7 +54,7 @@ static int __init rtc_hctosys(void)
rtc_tm_to_time(&tm, &tv.tv_sec);
do_settimeofday(&tv);
err = do_settimeofday(&tv);
dev_info(rtc->dev.parent,
"setting system clock to "

View File

@@ -473,18 +473,7 @@ static struct platform_driver at91_rtc_driver = {
},
};
static int __init at91_rtc_init(void)
{
return platform_driver_register(&at91_rtc_driver);
}
module_init(at91_rtc_init);
static void __exit at91_rtc_exit(void)
{
platform_driver_unregister(&at91_rtc_driver);
}
module_exit(at91_rtc_exit);
module_platform_driver(at91_rtc_driver);
MODULE_AUTHOR("Michel Benoit");
MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");

View File

@@ -276,8 +276,7 @@ static void coh901331_shutdown(struct platform_device *pdev)
clk_enable(rtap->clk);
writel(0, rtap->virtbase + COH901331_IRQ_MASK);
clk_disable(rtap->clk);
clk_unprepare(rtap->clk);
clk_disable_unprepare(rtap->clk);
}
static struct platform_driver coh901331_driver = {

View File

@@ -37,8 +37,17 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
unsigned char buf[4];
struct i2c_msg msgs[] = {
{client->addr, 0, 1, &addr}, /* setup read ptr */
{client->addr, I2C_M_RD, 4, buf}, /* read date */
{/* setup read ptr */
.addr = client->addr,
.len = 1,
.buf = &addr
},
{/* read date */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 4,
.buf = buf
},
};
/* read date registers */
@@ -99,8 +108,17 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
unsigned char addr = DS1672_REG_CONTROL;
struct i2c_msg msgs[] = {
{client->addr, 0, 1, &addr}, /* setup read ptr */
{client->addr, I2C_M_RD, 1, status}, /* read control */
{/* setup read ptr */
.addr = client->addr,
.len = 1,
.buf = &addr
},
{/* read control */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = status
},
};
/* read control register */

303
drivers/rtc/rtc-ds2404.c Normal file
View File

@@ -0,0 +1,303 @@
/*
* Copyright (C) 2012 Sven Schnelle <svens@stackframe.org>
*
* 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
* published by the Free Software Foundation.
*
*/
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rtc.h>
#include <linux/types.h>
#include <linux/bcd.h>
#include <linux/rtc-ds2404.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/io.h>
#define DS2404_STATUS_REG 0x200
#define DS2404_CONTROL_REG 0x201
#define DS2404_RTC_REG 0x202
#define DS2404_WRITE_SCRATCHPAD_CMD 0x0f
#define DS2404_READ_SCRATCHPAD_CMD 0xaa
#define DS2404_COPY_SCRATCHPAD_CMD 0x55
#define DS2404_READ_MEMORY_CMD 0xf0
struct ds2404;
struct ds2404_chip_ops {
int (*map_io)(struct ds2404 *chip, struct platform_device *pdev,
struct ds2404_platform_data *pdata);
void (*unmap_io)(struct ds2404 *chip);
};
#define DS2404_RST 0
#define DS2404_CLK 1
#define DS2404_DQ 2
struct ds2404_gpio {
const char *name;
unsigned int gpio;
};
struct ds2404 {
struct ds2404_gpio *gpio;
struct ds2404_chip_ops *ops;
struct rtc_device *rtc;
};
static struct ds2404_gpio ds2404_gpio[] = {
{ "RTC RST", 0 },
{ "RTC CLK", 0 },
{ "RTC DQ", 0 },
};
static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
struct ds2404_platform_data *pdata)
{
int i, err;
ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst;
ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk;
ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq;
for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
if (err) {
printk(KERN_ERR "error mapping gpio %s: %d\n",
ds2404_gpio[i].name, err);
goto err_request;
}
if (i != DS2404_DQ)
gpio_direction_output(ds2404_gpio[i].gpio, 1);
}
chip->gpio = ds2404_gpio;
return 0;
err_request:
while (--i >= 0)
gpio_free(ds2404_gpio[i].gpio);
return err;
}
static void ds2404_gpio_unmap(struct ds2404 *chip)
{
int i;
for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++)
gpio_free(ds2404_gpio[i].gpio);
}
static struct ds2404_chip_ops ds2404_gpio_ops = {
.map_io = ds2404_gpio_map,
.unmap_io = ds2404_gpio_unmap,
};
static void ds2404_reset(struct device *dev)
{
gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0);
udelay(1000);
gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1);
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0);
udelay(10);
}
static void ds2404_write_byte(struct device *dev, u8 byte)
{
int i;
gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1);
for (i = 0; i < 8; i++) {
gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i));
udelay(10);
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
udelay(10);
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
udelay(10);
}
}
static u8 ds2404_read_byte(struct device *dev)
{
int i;
u8 ret = 0;
gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
for (i = 0; i < 8; i++) {
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
udelay(10);
if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
ret |= 1 << i;
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
udelay(10);
}
return ret;
}
static void ds2404_read_memory(struct device *dev, u16 offset,
int length, u8 *out)
{
ds2404_reset(dev);
ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD);
ds2404_write_byte(dev, offset & 0xff);
ds2404_write_byte(dev, (offset >> 8) & 0xff);
while (length--)
*out++ = ds2404_read_byte(dev);
}
static void ds2404_write_memory(struct device *dev, u16 offset,
int length, u8 *out)
{
int i;
u8 ta01, ta02, es;
ds2404_reset(dev);
ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD);
ds2404_write_byte(dev, offset & 0xff);
ds2404_write_byte(dev, (offset >> 8) & 0xff);
for (i = 0; i < length; i++)
ds2404_write_byte(dev, out[i]);
ds2404_reset(dev);
ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD);
ta01 = ds2404_read_byte(dev);
ta02 = ds2404_read_byte(dev);
es = ds2404_read_byte(dev);
for (i = 0; i < length; i++) {
if (out[i] != ds2404_read_byte(dev)) {
printk(KERN_ERR "read invalid data\n");
return;
}
}
ds2404_reset(dev);
ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD);
ds2404_write_byte(dev, ta01);
ds2404_write_byte(dev, ta02);
ds2404_write_byte(dev, es);
gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
;
}
static void ds2404_enable_osc(struct device *dev)
{
u8 in[1] = { 0x10 }; /* enable oscillator */
ds2404_write_memory(dev, 0x201, 1, in);
}
static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
{
unsigned long time = 0;
ds2404_read_memory(dev, 0x203, 4, (u8 *)&time);
time = le32_to_cpu(time);
rtc_time_to_tm(time, dt);
return rtc_valid_tm(dt);
}
static int ds2404_set_mmss(struct device *dev, unsigned long secs)
{
u32 time = cpu_to_le32(secs);
ds2404_write_memory(dev, 0x203, 4, (u8 *)&time);
return 0;
}
static const struct rtc_class_ops ds2404_rtc_ops = {
.read_time = ds2404_read_time,
.set_mmss = ds2404_set_mmss,
};
static int rtc_probe(struct platform_device *pdev)
{
struct ds2404_platform_data *pdata = pdev->dev.platform_data;
struct ds2404 *chip;
int retval = -EBUSY;
chip = kzalloc(sizeof(struct ds2404), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->ops = &ds2404_gpio_ops;
retval = chip->ops->map_io(chip, pdev, pdata);
if (retval)
goto err_chip;
dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n",
chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio,
chip->gpio[DS2404_DQ].gpio);
platform_set_drvdata(pdev, chip);
chip->rtc = rtc_device_register("ds2404",
&pdev->dev, &ds2404_rtc_ops, THIS_MODULE);
if (IS_ERR(chip->rtc)) {
retval = PTR_ERR(chip->rtc);
goto err_io;
}
ds2404_enable_osc(&pdev->dev);
return 0;
err_io:
chip->ops->unmap_io(chip);
err_chip:
kfree(chip);
return retval;
}
static int rtc_remove(struct platform_device *dev)
{
struct ds2404 *chip = platform_get_drvdata(dev);
struct rtc_device *rtc = chip->rtc;
if (rtc)
rtc_device_unregister(rtc);
chip->ops->unmap_io(chip);
kfree(chip);
return 0;
}
static struct platform_driver rtc_device_driver = {
.probe = rtc_probe,
.remove = rtc_remove,
.driver = {
.name = "ds2404",
.owner = THIS_MODULE,
},
};
static __init int ds2404_init(void)
{
return platform_driver_register(&rtc_device_driver);
}
static __exit void ds2404_exit(void)
{
platform_driver_unregister(&rtc_device_driver);
}
module_init(ds2404_init);
module_exit(ds2404_exit);
MODULE_DESCRIPTION("DS2404 RTC");
MODULE_AUTHOR("Sven Schnelle");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ds2404");

View File

@@ -49,8 +49,17 @@ static int em3027_get_time(struct device *dev, struct rtc_time *tm)
unsigned char buf[7];
struct i2c_msg msgs[] = {
{client->addr, 0, 1, &addr}, /* setup read addr */
{client->addr, I2C_M_RD, 7, buf}, /* read time/date */
{/* setup read addr */
.addr = client->addr,
.len = 1,
.buf = &addr
},
{/* read time/date */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 7,
.buf = buf
},
};
/* read time/date registers */
@@ -76,7 +85,9 @@ static int em3027_set_time(struct device *dev, struct rtc_time *tm)
unsigned char buf[8];
struct i2c_msg msg = {
client->addr, 0, 8, buf, /* write time/date */
.addr = client->addr,
.len = 8,
.buf = buf, /* write time/date */
};
buf[0] = EM3027_REG_WATCH_SEC;

View File

@@ -68,9 +68,17 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
{
u8 reg_addr[1] = { reg };
struct i2c_msg msgs[2] = {
{client->addr, 0, sizeof(reg_addr), reg_addr}
,
{client->addr, I2C_M_RD, len, buf}
{
.addr = client->addr,
.len = sizeof(reg_addr),
.buf = reg_addr
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf
}
};
int ret;
@@ -90,7 +98,11 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
{
u8 i2c_buf[ISL1208_REG_USR2 + 2];
struct i2c_msg msgs[1] = {
{client->addr, 0, len + 1, i2c_buf}
{
.addr = client->addr,
.len = len + 1,
.buf = i2c_buf
}
};
int ret;
@@ -697,6 +709,7 @@ isl1208_remove(struct i2c_client *client)
static const struct i2c_device_id isl1208_id[] = {
{ "isl1208", 0 },
{ "isl1218", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl1208_id);

View File

@@ -42,7 +42,7 @@ struct jz4740_rtc {
struct rtc_device *rtc;
unsigned int irq;
int irq;
spinlock_t lock;
};

View File

@@ -213,163 +213,14 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
return m41t80_set_datetime(to_i2c_client(dev), tm);
}
static int m41t80_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
int rc;
rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (rc < 0)
goto err;
if (enabled)
rc |= M41T80_ALMON_AFE;
else
rc &= ~M41T80_ALMON_AFE;
if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0)
goto err;
return 0;
err:
return -EIO;
}
static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
u8 wbuf[1 + M41T80_ALARM_REG_SIZE];
u8 *buf = &wbuf[1];
u8 *reg = buf - M41T80_REG_ALARM_MON;
u8 dt_addr[1] = { M41T80_REG_ALARM_MON };
struct i2c_msg msgs_in[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = dt_addr,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = M41T80_ALARM_REG_SIZE,
.buf = buf,
},
};
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1 + M41T80_ALARM_REG_SIZE,
.buf = wbuf,
},
};
if (i2c_transfer(client->adapter, msgs_in, 2) < 0) {
dev_err(&client->dev, "read error\n");
return -EIO;
}
reg[M41T80_REG_ALARM_MON] &= ~(0x1f | M41T80_ALMON_AFE);
reg[M41T80_REG_ALARM_DAY] = 0;
reg[M41T80_REG_ALARM_HOUR] &= ~(0x3f | 0x80);
reg[M41T80_REG_ALARM_MIN] = 0;
reg[M41T80_REG_ALARM_SEC] = 0;
wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */
reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ?
bin2bcd(t->time.tm_sec) : 0x80;
reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ?
bin2bcd(t->time.tm_min) : 0x80;
reg[M41T80_REG_ALARM_HOUR] |= t->time.tm_hour >= 0 ?
bin2bcd(t->time.tm_hour) : 0x80;
reg[M41T80_REG_ALARM_DAY] |= t->time.tm_mday >= 0 ?
bin2bcd(t->time.tm_mday) : 0x80;
if (t->time.tm_mon >= 0)
reg[M41T80_REG_ALARM_MON] |= bin2bcd(t->time.tm_mon + 1);
else
reg[M41T80_REG_ALARM_DAY] |= 0x40;
if (i2c_transfer(client->adapter, msgs, 1) != 1) {
dev_err(&client->dev, "write error\n");
return -EIO;
}
if (t->enabled) {
reg[M41T80_REG_ALARM_MON] |= M41T80_ALMON_AFE;
if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
reg[M41T80_REG_ALARM_MON]) < 0) {
dev_err(&client->dev, "write error\n");
return -EIO;
}
}
return 0;
}
static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
u8 buf[M41T80_ALARM_REG_SIZE + 1]; /* all alarm regs and flags */
u8 dt_addr[1] = { M41T80_REG_ALARM_MON };
u8 *reg = buf - M41T80_REG_ALARM_MON;
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = dt_addr,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = M41T80_ALARM_REG_SIZE + 1,
.buf = buf,
},
};
if (i2c_transfer(client->adapter, msgs, 2) < 0) {
dev_err(&client->dev, "read error\n");
return -EIO;
}
t->time.tm_sec = -1;
t->time.tm_min = -1;
t->time.tm_hour = -1;
t->time.tm_mday = -1;
t->time.tm_mon = -1;
if (!(reg[M41T80_REG_ALARM_SEC] & 0x80))
t->time.tm_sec = bcd2bin(reg[M41T80_REG_ALARM_SEC] & 0x7f);
if (!(reg[M41T80_REG_ALARM_MIN] & 0x80))
t->time.tm_min = bcd2bin(reg[M41T80_REG_ALARM_MIN] & 0x7f);
if (!(reg[M41T80_REG_ALARM_HOUR] & 0x80))
t->time.tm_hour = bcd2bin(reg[M41T80_REG_ALARM_HOUR] & 0x3f);
if (!(reg[M41T80_REG_ALARM_DAY] & 0x80))
t->time.tm_mday = bcd2bin(reg[M41T80_REG_ALARM_DAY] & 0x3f);
if (!(reg[M41T80_REG_ALARM_DAY] & 0x40))
t->time.tm_mon = bcd2bin(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1;
t->time.tm_year = -1;
t->time.tm_wday = -1;
t->time.tm_yday = -1;
t->time.tm_isdst = -1;
t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE);
t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF);
return 0;
}
/*
* XXX - m41t80 alarm functionality is reported broken.
* until it is fixed, don't register alarm functions.
*/
static struct rtc_class_ops m41t80_rtc_ops = {
.read_time = m41t80_rtc_read_time,
.set_time = m41t80_rtc_set_time,
/*
* XXX - m41t80 alarm functionality is reported broken.
* until it is fixed, don't register alarm functions.
*
.read_alarm = m41t80_rtc_read_alarm,
.set_alarm = m41t80_rtc_set_alarm,
*/
.proc = m41t80_rtc_proc,
/*
* See above comment on broken alarm
*
.alarm_irq_enable = m41t80_rtc_alarm_irq_enable,
*/
};
#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)

244
drivers/rtc/rtc-max8907.c Normal file
View File

@@ -0,0 +1,244 @@
/*
* RTC driver for Maxim MAX8907
*
* Copyright (c) 2011-2012, NVIDIA Corporation.
*
* Based on drivers/rtc/rtc-max8925.c,
* Copyright (C) 2009-2010 Marvell International Ltd.
*
* 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
* published by the Free Software Foundation.
*/
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/mfd/max8907.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/slab.h>
enum {
RTC_SEC = 0,
RTC_MIN,
RTC_HOUR,
RTC_WEEKDAY,
RTC_DATE,
RTC_MONTH,
RTC_YEAR1,
RTC_YEAR2,
};
#define TIME_NUM 8
#define ALARM_1SEC (1 << 7)
#define HOUR_12 (1 << 7)
#define HOUR_AM_PM (1 << 5)
#define ALARM0_IRQ (1 << 3)
#define ALARM1_IRQ (1 << 2)
#define ALARM0_STATUS (1 << 2)
#define ALARM1_STATUS (1 << 1)
struct max8907_rtc {
struct max8907 *max8907;
struct regmap *regmap;
struct rtc_device *rtc_dev;
int irq;
};
static irqreturn_t max8907_irq_handler(int irq, void *data)
{
struct max8907_rtc *rtc = data;
regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0);
rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static void regs_to_tm(u8 *regs, struct rtc_time *tm)
{
tm->tm_year = bcd2bin(regs[RTC_YEAR2]) * 100 +
bcd2bin(regs[RTC_YEAR1]) - 1900;
tm->tm_mon = bcd2bin(regs[RTC_MONTH] & 0x1f) - 1;
tm->tm_mday = bcd2bin(regs[RTC_DATE] & 0x3f);
tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07) - 1;
if (regs[RTC_HOUR] & HOUR_12) {
tm->tm_hour = bcd2bin(regs[RTC_HOUR] & 0x01f);
if (tm->tm_hour == 12)
tm->tm_hour = 0;
if (regs[RTC_HOUR] & HOUR_AM_PM)
tm->tm_hour += 12;
} else {
tm->tm_hour = bcd2bin(regs[RTC_HOUR] & 0x03f);
}
tm->tm_min = bcd2bin(regs[RTC_MIN] & 0x7f);
tm->tm_sec = bcd2bin(regs[RTC_SEC] & 0x7f);
}
static void tm_to_regs(struct rtc_time *tm, u8 *regs)
{
u8 high, low;
high = (tm->tm_year + 1900) / 100;
low = tm->tm_year % 100;
regs[RTC_YEAR2] = bin2bcd(high);
regs[RTC_YEAR1] = bin2bcd(low);
regs[RTC_MONTH] = bin2bcd(tm->tm_mon + 1);
regs[RTC_DATE] = bin2bcd(tm->tm_mday);
regs[RTC_WEEKDAY] = tm->tm_wday + 1;
regs[RTC_HOUR] = bin2bcd(tm->tm_hour);
regs[RTC_MIN] = bin2bcd(tm->tm_min);
regs[RTC_SEC] = bin2bcd(tm->tm_sec);
}
static int max8907_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct max8907_rtc *rtc = dev_get_drvdata(dev);
u8 regs[TIME_NUM];
int ret;
ret = regmap_bulk_read(rtc->regmap, MAX8907_REG_RTC_SEC, regs,
TIME_NUM);
if (ret < 0)
return ret;
regs_to_tm(regs, tm);
return 0;
}
static int max8907_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct max8907_rtc *rtc = dev_get_drvdata(dev);
u8 regs[TIME_NUM];
tm_to_regs(tm, regs);
return regmap_bulk_write(rtc->regmap, MAX8907_REG_RTC_SEC, regs,
TIME_NUM);
}
static int max8907_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max8907_rtc *rtc = dev_get_drvdata(dev);
u8 regs[TIME_NUM];
unsigned int val;
int ret;
ret = regmap_bulk_read(rtc->regmap, MAX8907_REG_ALARM0_SEC, regs,
TIME_NUM);
if (ret < 0)
return ret;
regs_to_tm(regs, &alrm->time);
ret = regmap_read(rtc->regmap, MAX8907_REG_ALARM0_CNTL, &val);
if (ret < 0)
return ret;
alrm->enabled = !!(val & 0x7f);
return 0;
}
static int max8907_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max8907_rtc *rtc = dev_get_drvdata(dev);
u8 regs[TIME_NUM];
int ret;
tm_to_regs(&alrm->time, regs);
/* Disable alarm while we update the target time */
ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0);
if (ret < 0)
return ret;
ret = regmap_bulk_write(rtc->regmap, MAX8907_REG_ALARM0_SEC, regs,
TIME_NUM);
if (ret < 0)
return ret;
if (alrm->enabled)
ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL,
0x7f, 0x7f);
return ret;
}
static const struct rtc_class_ops max8907_rtc_ops = {
.read_time = max8907_rtc_read_time,
.set_time = max8907_rtc_set_time,
.read_alarm = max8907_rtc_read_alarm,
.set_alarm = max8907_rtc_set_alarm,
};
static int __devinit max8907_rtc_probe(struct platform_device *pdev)
{
struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
struct max8907_rtc *rtc;
int ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
rtc->max8907 = max8907;
rtc->regmap = max8907->regmap_rtc;
rtc->rtc_dev = rtc_device_register("max8907-rtc", &pdev->dev,
&max8907_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc_dev)) {
ret = PTR_ERR(rtc->rtc_dev);
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
return ret;
}
rtc->irq = regmap_irq_get_virq(max8907->irqc_rtc,
MAX8907_IRQ_RTC_ALARM0);
if (rtc->irq < 0) {
ret = rtc->irq;
goto err_unregister;
}
ret = request_threaded_irq(rtc->irq, NULL, max8907_irq_handler,
IRQF_ONESHOT, "max8907-alarm0", rtc);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n",
rtc->irq, ret);
goto err_unregister;
}
return 0;
err_unregister:
rtc_device_unregister(rtc->rtc_dev);
return ret;
}
static int __devexit max8907_rtc_remove(struct platform_device *pdev)
{
struct max8907_rtc *rtc = platform_get_drvdata(pdev);
free_irq(rtc->irq, rtc);
rtc_device_unregister(rtc->rtc_dev);
return 0;
}
static struct platform_driver max8907_rtc_driver = {
.driver = {
.name = "max8907-rtc",
.owner = THIS_MODULE,
},
.probe = max8907_rtc_probe,
.remove = __devexit_p(max8907_rtc_remove),
};
module_platform_driver(max8907_rtc_driver);
MODULE_DESCRIPTION("Maxim MAX8907 RTC driver");
MODULE_LICENSE("GPL v2");

View File

@@ -343,7 +343,7 @@ static struct rtc_class_ops mxc_rtc_ops = {
.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
};
static int __init mxc_rtc_probe(struct platform_device *pdev)
static int __devinit mxc_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct rtc_device *rtc;
@@ -367,14 +367,14 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
pdata->ioaddr = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
pdata->clk = clk_get(&pdev->dev, "rtc");
pdata->clk = devm_clk_get(&pdev->dev, NULL);
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);
clk_prepare_enable(pdata->clk);
rate = clk_get_rate(pdata->clk);
if (rate == 32768)
@@ -426,22 +426,20 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
exit_clr_drvdata:
platform_set_drvdata(pdev, NULL);
exit_put_clk:
clk_disable(pdata->clk);
clk_put(pdata->clk);
clk_disable_unprepare(pdata->clk);
exit_free_pdata:
return ret;
}
static int __exit mxc_rtc_remove(struct platform_device *pdev)
static int __devexit mxc_rtc_remove(struct platform_device *pdev)
{
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
rtc_device_unregister(pdata->rtc);
clk_disable(pdata->clk);
clk_put(pdata->clk);
clk_disable_unprepare(pdata->clk);
platform_set_drvdata(pdev, NULL);
return 0;
@@ -482,21 +480,11 @@ static struct platform_driver mxc_rtc_driver = {
#endif
.owner = THIS_MODULE,
},
.remove = __exit_p(mxc_rtc_remove),
.probe = mxc_rtc_probe,
.remove = __devexit_p(mxc_rtc_remove),
};
static int __init mxc_rtc_init(void)
{
return platform_driver_probe(&mxc_rtc_driver, mxc_rtc_probe);
}
static void __exit mxc_rtc_exit(void)
{
platform_driver_unregister(&mxc_rtc_driver);
}
module_init(mxc_rtc_init);
module_exit(mxc_rtc_exit);
module_platform_driver(mxc_rtc_driver)
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
MODULE_DESCRIPTION("RTC driver for Freescale MXC");

View File

@@ -78,8 +78,17 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
{ client->addr, 0, 1, buf }, /* setup read ptr */
{ client->addr, I2C_M_RD, 13, buf }, /* read status + date */
{/* setup read ptr */
.addr = client->addr,
.len = 1,
.buf = buf
},
{/* read status + date */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 13,
.buf = buf
},
};
/* read registers */

View File

@@ -18,6 +18,26 @@
#include "rtc-core.h"
#define NAME_SIZE 10
#if defined(CONFIG_RTC_HCTOSYS_DEVICE)
static bool is_rtc_hctosys(struct rtc_device *rtc)
{
int size;
char name[NAME_SIZE];
size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id);
if (size > NAME_SIZE)
return false;
return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE);
}
#else
static bool is_rtc_hctosys(struct rtc_device *rtc)
{
return (rtc->id == 0);
}
#endif
static int rtc_proc_show(struct seq_file *seq, void *offset)
{
@@ -117,12 +137,12 @@ static const struct file_operations rtc_proc_fops = {
void rtc_proc_add_device(struct rtc_device *rtc)
{
if (rtc->id == 0)
if (is_rtc_hctosys(rtc))
proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);
}
void rtc_proc_del_device(struct rtc_device *rtc)
{
if (rtc->id == 0)
if (is_rtc_hctosys(rtc))
remove_proc_entry("driver/rtc", NULL);
}

331
drivers/rtc/rtc-rc5t583.c Normal file
View File

@@ -0,0 +1,331 @@
/*
* rtc-rc5t583.c -- RICOH RC5T583 Real Time Clock
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
* Author: Venu Byravarasu <vbyravarasu@nvidia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mfd/rc5t583.h>
struct rc5t583_rtc {
struct rtc_device *rtc;
/* To store the list of enabled interrupts, during system suspend */
u32 irqen;
};
/* Total number of RTC registers needed to set time*/
#define NUM_TIME_REGS (RC5T583_RTC_YEAR - RC5T583_RTC_SEC + 1)
/* Total number of RTC registers needed to set Y-Alarm*/
#define NUM_YAL_REGS (RC5T583_RTC_AY_YEAR - RC5T583_RTC_AY_MIN + 1)
/* Set Y-Alarm interrupt */
#define SET_YAL BIT(5)
/* Get Y-Alarm interrupt status*/
#define GET_YAL_STATUS BIT(3)
static int rc5t583_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
u8 val;
/* Set Y-Alarm, based on 'enabled' */
val = enabled ? SET_YAL : 0;
return regmap_update_bits(rc5t583->regmap, RC5T583_RTC_CTL1, SET_YAL,
val);
}
/*
* Gets current rc5t583 RTC time and date parameters.
*
* The RTC's time/alarm representation is not what gmtime(3) requires
* Linux to use:
*
* - Months are 1..12 vs Linux 0-11
* - Years are 0..99 vs Linux 1900..N (we assume 21st century)
*/
static int rc5t583_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
u8 rtc_data[NUM_TIME_REGS];
int ret;
ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "RTC read time failed with err:%d\n", ret);
return ret;
}
tm->tm_sec = bcd2bin(rtc_data[0]);
tm->tm_min = bcd2bin(rtc_data[1]);
tm->tm_hour = bcd2bin(rtc_data[2]);
tm->tm_wday = bcd2bin(rtc_data[3]);
tm->tm_mday = bcd2bin(rtc_data[4]);
tm->tm_mon = bcd2bin(rtc_data[5]) - 1;
tm->tm_year = bcd2bin(rtc_data[6]) + 100;
return ret;
}
static int rc5t583_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
unsigned char rtc_data[NUM_TIME_REGS];
int ret;
rtc_data[0] = bin2bcd(tm->tm_sec);
rtc_data[1] = bin2bcd(tm->tm_min);
rtc_data[2] = bin2bcd(tm->tm_hour);
rtc_data[3] = bin2bcd(tm->tm_wday);
rtc_data[4] = bin2bcd(tm->tm_mday);
rtc_data[5] = bin2bcd(tm->tm_mon + 1);
rtc_data[6] = bin2bcd(tm->tm_year - 100);
ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "RTC set time failed with error %d\n", ret);
return ret;
}
return ret;
}
static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
unsigned char alarm_data[NUM_YAL_REGS];
u32 interrupt_enable;
int ret;
ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
NUM_YAL_REGS);
if (ret < 0) {
dev_err(dev, "rtc_read_alarm error %d\n", ret);
return ret;
}
alm->time.tm_min = bcd2bin(alarm_data[0]);
alm->time.tm_hour = bcd2bin(alarm_data[1]);
alm->time.tm_mday = bcd2bin(alarm_data[2]);
alm->time.tm_mon = bcd2bin(alarm_data[3]) - 1;
alm->time.tm_year = bcd2bin(alarm_data[4]) + 100;
ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1, &interrupt_enable);
if (ret < 0)
return ret;
/* check if YALE is set */
if (interrupt_enable & SET_YAL)
alm->enabled = 1;
return ret;
}
static int rc5t583_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
unsigned char alarm_data[NUM_YAL_REGS];
int ret;
ret = rc5t583_rtc_alarm_irq_enable(dev, 0);
if (ret)
return ret;
alarm_data[0] = bin2bcd(alm->time.tm_min);
alarm_data[1] = bin2bcd(alm->time.tm_hour);
alarm_data[2] = bin2bcd(alm->time.tm_mday);
alarm_data[3] = bin2bcd(alm->time.tm_mon + 1);
alarm_data[4] = bin2bcd(alm->time.tm_year - 100);
ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
NUM_YAL_REGS);
if (ret) {
dev_err(dev, "rtc_set_alarm error %d\n", ret);
return ret;
}
if (alm->enabled)
ret = rc5t583_rtc_alarm_irq_enable(dev, 1);
return ret;
}
static irqreturn_t rc5t583_rtc_interrupt(int irq, void *rtc)
{
struct device *dev = rtc;
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
unsigned long events = 0;
int ret;
u32 rtc_reg;
ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL2, &rtc_reg);
if (ret < 0)
return IRQ_NONE;
if (rtc_reg & GET_YAL_STATUS) {
events = RTC_IRQF | RTC_AF;
/* clear pending Y-alarm interrupt bit */
rtc_reg &= ~GET_YAL_STATUS;
}
ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, rtc_reg);
if (ret)
return IRQ_NONE;
/* Notify RTC core on event */
rtc_update_irq(rc5t583_rtc->rtc, 1, events);
return IRQ_HANDLED;
}
static const struct rtc_class_ops rc5t583_rtc_ops = {
.read_time = rc5t583_rtc_read_time,
.set_time = rc5t583_rtc_set_time,
.read_alarm = rc5t583_rtc_read_alarm,
.set_alarm = rc5t583_rtc_set_alarm,
.alarm_irq_enable = rc5t583_rtc_alarm_irq_enable,
};
static int __devinit rc5t583_rtc_probe(struct platform_device *pdev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
struct rc5t583_rtc *ricoh_rtc;
struct rc5t583_platform_data *pmic_plat_data;
int ret;
int irq;
ricoh_rtc = devm_kzalloc(&pdev->dev, sizeof(struct rc5t583_rtc),
GFP_KERNEL);
if (!ricoh_rtc)
return -ENOMEM;
platform_set_drvdata(pdev, ricoh_rtc);
/* Clear pending interrupts */
ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, 0);
if (ret < 0)
return ret;
/* clear RTC Adjust register */
ret = regmap_write(rc5t583->regmap, RC5T583_RTC_ADJ, 0);
if (ret < 0) {
dev_err(&pdev->dev, "unable to program rtc_adjust reg\n");
return -EBUSY;
}
pmic_plat_data = dev_get_platdata(rc5t583->dev);
irq = pmic_plat_data->irq_base;
if (irq <= 0) {
dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
irq);
return ret;
}
irq += RC5T583_IRQ_YALE;
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
rc5t583_rtc_interrupt, IRQF_TRIGGER_LOW,
"rtc-rc5t583", &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");
return ret;
}
device_init_wakeup(&pdev->dev, 1);
ricoh_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
&rc5t583_rtc_ops, THIS_MODULE);
if (IS_ERR(ricoh_rtc->rtc)) {
ret = PTR_ERR(ricoh_rtc->rtc);
dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
return ret;
}
return 0;
}
/*
* Disable rc5t583 RTC interrupts.
* Sets status flag to free.
*/
static int __devexit rc5t583_rtc_remove(struct platform_device *pdev)
{
struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(&pdev->dev);
rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0);
rtc_device_unregister(rc5t583_rtc->rtc);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rc5t583_rtc_suspend(struct device *dev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
int ret;
/* Store current list of enabled interrupts*/
ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1,
&rc5t583_rtc->irqen);
return ret;
}
static int rc5t583_rtc_resume(struct device *dev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
/* Restore list of enabled interrupts before suspend */
return regmap_write(rc5t583->regmap, RC5T583_RTC_CTL1,
rc5t583_rtc->irqen);
}
static const struct dev_pm_ops rc5t583_rtc_pm_ops = {
.suspend = rc5t583_rtc_suspend,
.resume = rc5t583_rtc_resume,
};
#define DEV_PM_OPS (&rc5t583_rtc_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif
static struct platform_driver rc5t583_rtc_driver = {
.probe = rc5t583_rtc_probe,
.remove = __devexit_p(rc5t583_rtc_remove),
.driver = {
.owner = THIS_MODULE,
.name = "rtc-rc5t583",
.pm = DEV_PM_OPS,
},
};
module_platform_driver(rc5t583_rtc_driver);
MODULE_ALIAS("platform:rtc-rc5t583");
MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
MODULE_LICENSE("GPL v2");

View File

@@ -104,7 +104,12 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
{
struct i2c_client *client = rs5c->client;
struct i2c_msg msgs[] = {
{ client->addr, I2C_M_RD, sizeof rs5c->buf, rs5c->buf },
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(rs5c->buf),
.buf = rs5c->buf
},
};
/* This implements the third reading method from the datasheet, using

View File

@@ -19,6 +19,8 @@
#define S35390A_CMD_STATUS1 0
#define S35390A_CMD_STATUS2 1
#define S35390A_CMD_TIME1 2
#define S35390A_CMD_TIME2 3
#define S35390A_CMD_INT2_REG1 5
#define S35390A_BYTE_YEAR 0
#define S35390A_BYTE_MONTH 1
@@ -28,12 +30,23 @@
#define S35390A_BYTE_MINS 5
#define S35390A_BYTE_SECS 6
#define S35390A_ALRM_BYTE_WDAY 0
#define S35390A_ALRM_BYTE_HOURS 1
#define S35390A_ALRM_BYTE_MINS 2
#define S35390A_FLAG_POC 0x01
#define S35390A_FLAG_BLD 0x02
#define S35390A_FLAG_24H 0x40
#define S35390A_FLAG_RESET 0x80
#define S35390A_FLAG_TEST 0x01
#define S35390A_INT2_MODE_MASK 0xF0
#define S35390A_INT2_MODE_NOINTR 0x00
#define S35390A_INT2_MODE_FREQ 0x10
#define S35390A_INT2_MODE_ALARM 0x40
#define S35390A_INT2_MODE_PMIN_EDG 0x20
static const struct i2c_device_id s35390a_id[] = {
{ "s35390a", 0 },
{ }
@@ -50,7 +63,11 @@ static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len)
{
struct i2c_client *client = s35390a->client[reg];
struct i2c_msg msg[] = {
{ client->addr, 0, len, buf },
{
.addr = client->addr,
.len = len,
.buf = buf
},
};
if ((i2c_transfer(client->adapter, msg, 1)) != 1)
@@ -63,7 +80,12 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
{
struct i2c_client *client = s35390a->client[reg];
struct i2c_msg msg[] = {
{ client->addr, I2C_M_RD, len, buf },
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf
},
};
if ((i2c_transfer(client->adapter, msg, 1)) != 1)
@@ -184,6 +206,104 @@ static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm)
return rtc_valid_tm(tm);
}
static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
{
struct s35390a *s35390a = i2c_get_clientdata(client);
char buf[3], sts = 0;
int err, i;
dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\
"mon=%d, year=%d, wday=%d\n", __func__, alm->time.tm_sec,
alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
/* disable interrupt */
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
return err;
/* clear pending interrupt, if any */
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts));
if (err < 0)
return err;
if (alm->enabled)
sts = S35390A_INT2_MODE_ALARM;
else
sts = S35390A_INT2_MODE_NOINTR;
/* This chip expects the bits of each byte to be in reverse order */
sts = bitrev8(sts);
/* set interupt mode*/
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
return err;
if (alm->time.tm_wday != -1)
buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
alm->time.tm_hour) | 0x80;
buf[S35390A_ALRM_BYTE_MINS] = bin2bcd(alm->time.tm_min) | 0x80;
if (alm->time.tm_hour >= 12)
buf[S35390A_ALRM_BYTE_HOURS] |= 0x40;
for (i = 0; i < 3; ++i)
buf[i] = bitrev8(buf[i]);
err = s35390a_set_reg(s35390a, S35390A_CMD_INT2_REG1, buf,
sizeof(buf));
return err;
}
static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
{
struct s35390a *s35390a = i2c_get_clientdata(client);
char buf[3], sts;
int i, err;
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
return err;
if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
return -EINVAL;
err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
if (err < 0)
return err;
/* This chip returns the bits of each byte in reverse order */
for (i = 0; i < 3; ++i) {
buf[i] = bitrev8(buf[i]);
buf[i] &= ~0x80;
}
alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
alm->time.tm_hour = s35390a_reg2hr(s35390a,
buf[S35390A_ALRM_BYTE_HOURS]);
alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
__func__, alm->time.tm_min, alm->time.tm_hour,
alm->time.tm_wday);
return 0;
}
static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
return s35390a_read_alarm(to_i2c_client(dev), alm);
}
static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
return s35390a_set_alarm(to_i2c_client(dev), alm);
}
static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return s35390a_get_datetime(to_i2c_client(dev), tm);
@@ -197,6 +317,9 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm)
static const struct rtc_class_ops s35390a_rtc_ops = {
.read_time = s35390a_rtc_read_time,
.set_time = s35390a_rtc_set_time,
.set_alarm = s35390a_rtc_set_alarm,
.read_alarm = s35390a_rtc_read_alarm,
};
static struct i2c_driver s35390a_driver;
@@ -261,6 +384,8 @@ static int s35390a_probe(struct i2c_client *client,
if (s35390a_get_datetime(client, &tm) < 0)
dev_warn(&client->dev, "clock needs to be set\n");
device_set_wakeup_capable(&client->dev, 1);
s35390a->rtc = rtc_device_register(s35390a_driver.driver.name,
&client->dev, &s35390a_rtc_ops, THIS_MODULE);

View File

@@ -476,13 +476,13 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
s3c_rtc_tickno = platform_get_irq(pdev, 1);
if (s3c_rtc_tickno < 0) {
dev_err(&pdev->dev, "no irq for rtc tick\n");
return -ENOENT;
return s3c_rtc_tickno;
}
s3c_rtc_alarmno = platform_get_irq(pdev, 0);
if (s3c_rtc_alarmno < 0) {
dev_err(&pdev->dev, "no irq for alarm\n");
return -ENOENT;
return s3c_rtc_alarmno;
}
pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",

350
drivers/rtc/rtc-snvs.c Normal file
View File

@@ -0,0 +1,350 @@
/*
* Copyright (C) 2011-2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
/* These register offsets are relative to LP (Low Power) range */
#define SNVS_LPCR 0x04
#define SNVS_LPSR 0x18
#define SNVS_LPSRTCMR 0x1c
#define SNVS_LPSRTCLR 0x20
#define SNVS_LPTAR 0x24
#define SNVS_LPPGDR 0x30
#define SNVS_LPCR_SRTC_ENV (1 << 0)
#define SNVS_LPCR_LPTA_EN (1 << 1)
#define SNVS_LPCR_LPWUI_EN (1 << 3)
#define SNVS_LPSR_LPTA (1 << 0)
#define SNVS_LPPGDR_INIT 0x41736166
#define CNTR_TO_SECS_SH 15
struct snvs_rtc_data {
struct rtc_device *rtc;
void __iomem *ioaddr;
int irq;
spinlock_t lock;
};
static u32 rtc_read_lp_counter(void __iomem *ioaddr)
{
u64 read1, read2;
do {
read1 = readl(ioaddr + SNVS_LPSRTCMR);
read1 <<= 32;
read1 |= readl(ioaddr + SNVS_LPSRTCLR);
read2 = readl(ioaddr + SNVS_LPSRTCMR);
read2 <<= 32;
read2 |= readl(ioaddr + SNVS_LPSRTCLR);
} while (read1 != read2);
/* Convert 47-bit counter to 32-bit raw second count */
return (u32) (read1 >> CNTR_TO_SECS_SH);
}
static void rtc_write_sync_lp(void __iomem *ioaddr)
{
u32 count1, count2, count3;
int i;
/* Wait for 3 CKIL cycles */
for (i = 0; i < 3; i++) {
do {
count1 = readl(ioaddr + SNVS_LPSRTCLR);
count2 = readl(ioaddr + SNVS_LPSRTCLR);
} while (count1 != count2);
/* Now wait until counter value changes */
do {
do {
count2 = readl(ioaddr + SNVS_LPSRTCLR);
count3 = readl(ioaddr + SNVS_LPSRTCLR);
} while (count2 != count3);
} while (count3 == count1);
}
}
static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable)
{
unsigned long flags;
int timeout = 1000;
u32 lpcr;
spin_lock_irqsave(&data->lock, flags);
lpcr = readl(data->ioaddr + SNVS_LPCR);
if (enable)
lpcr |= SNVS_LPCR_SRTC_ENV;
else
lpcr &= ~SNVS_LPCR_SRTC_ENV;
writel(lpcr, data->ioaddr + SNVS_LPCR);
spin_unlock_irqrestore(&data->lock, flags);
while (--timeout) {
lpcr = readl(data->ioaddr + SNVS_LPCR);
if (enable) {
if (lpcr & SNVS_LPCR_SRTC_ENV)
break;
} else {
if (!(lpcr & SNVS_LPCR_SRTC_ENV))
break;
}
}
if (!timeout)
return -ETIMEDOUT;
return 0;
}
static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
unsigned long time = rtc_read_lp_counter(data->ioaddr);
rtc_time_to_tm(time, tm);
return 0;
}
static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
unsigned long time;
rtc_tm_to_time(tm, &time);
/* Disable RTC first */
snvs_rtc_enable(data, false);
/* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */
writel(time << CNTR_TO_SECS_SH, data->ioaddr + SNVS_LPSRTCLR);
writel(time >> (32 - CNTR_TO_SECS_SH), data->ioaddr + SNVS_LPSRTCMR);
/* Enable RTC again */
snvs_rtc_enable(data, true);
return 0;
}
static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
u32 lptar, lpsr;
lptar = readl(data->ioaddr + SNVS_LPTAR);
rtc_time_to_tm(lptar, &alrm->time);
lpsr = readl(data->ioaddr + SNVS_LPSR);
alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0;
return 0;
}
static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
u32 lpcr;
unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
lpcr = readl(data->ioaddr + SNVS_LPCR);
if (enable)
lpcr |= (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN);
else
lpcr &= ~(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN);
writel(lpcr, data->ioaddr + SNVS_LPCR);
spin_unlock_irqrestore(&data->lock, flags);
rtc_write_sync_lp(data->ioaddr);
return 0;
}
static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
struct rtc_time *alrm_tm = &alrm->time;
unsigned long time;
unsigned long flags;
u32 lpcr;
rtc_tm_to_time(alrm_tm, &time);
spin_lock_irqsave(&data->lock, flags);
/* Have to clear LPTA_EN before programming new alarm time in LPTAR */
lpcr = readl(data->ioaddr + SNVS_LPCR);
lpcr &= ~SNVS_LPCR_LPTA_EN;
writel(lpcr, data->ioaddr + SNVS_LPCR);
spin_unlock_irqrestore(&data->lock, flags);
writel(time, data->ioaddr + SNVS_LPTAR);
/* Clear alarm interrupt status bit */
writel(SNVS_LPSR_LPTA, data->ioaddr + SNVS_LPSR);
return snvs_rtc_alarm_irq_enable(dev, alrm->enabled);
}
static const struct rtc_class_ops snvs_rtc_ops = {
.read_time = snvs_rtc_read_time,
.set_time = snvs_rtc_set_time,
.read_alarm = snvs_rtc_read_alarm,
.set_alarm = snvs_rtc_set_alarm,
.alarm_irq_enable = snvs_rtc_alarm_irq_enable,
};
static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id)
{
struct device *dev = dev_id;
struct snvs_rtc_data *data = dev_get_drvdata(dev);
u32 lpsr;
u32 events = 0;
lpsr = readl(data->ioaddr + SNVS_LPSR);
if (lpsr & SNVS_LPSR_LPTA) {
events |= (RTC_AF | RTC_IRQF);
/* RTC alarm should be one-shot */
snvs_rtc_alarm_irq_enable(dev, 0);
rtc_update_irq(data->rtc, 1, events);
}
/* clear interrupt status */
writel(lpsr, data->ioaddr + SNVS_LPSR);
return events ? IRQ_HANDLED : IRQ_NONE;
}
static int __devinit snvs_rtc_probe(struct platform_device *pdev)
{
struct snvs_rtc_data *data;
struct resource *res;
int ret;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->ioaddr = devm_request_and_ioremap(&pdev->dev, res);
if (!data->ioaddr)
return -EADDRNOTAVAIL;
data->irq = platform_get_irq(pdev, 0);
if (data->irq < 0)
return data->irq;
platform_set_drvdata(pdev, data);
spin_lock_init(&data->lock);
/* Initialize glitch detect */
writel(SNVS_LPPGDR_INIT, data->ioaddr + SNVS_LPPGDR);
/* Clear interrupt status */
writel(0xffffffff, data->ioaddr + SNVS_LPSR);
/* Enable RTC */
snvs_rtc_enable(data, true);
device_init_wakeup(&pdev->dev, true);
ret = devm_request_irq(&pdev->dev, data->irq, snvs_rtc_irq_handler,
IRQF_SHARED, "rtc alarm", &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to request irq %d: %d\n",
data->irq, ret);
return ret;
}
data->rtc = rtc_device_register(pdev->name, &pdev->dev,
&snvs_rtc_ops, THIS_MODULE);
if (IS_ERR(data->rtc)) {
ret = PTR_ERR(data->rtc);
dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
return ret;
}
return 0;
}
static int __devexit snvs_rtc_remove(struct platform_device *pdev)
{
struct snvs_rtc_data *data = platform_get_drvdata(pdev);
rtc_device_unregister(data->rtc);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int snvs_rtc_suspend(struct device *dev)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(data->irq);
return 0;
}
static int snvs_rtc_resume(struct device *dev)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(data->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume);
static const struct of_device_id __devinitconst snvs_dt_ids[] = {
{ .compatible = "fsl,sec-v4.0-mon-rtc-lp", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, snvs_dt_ids);
static struct platform_driver snvs_rtc_driver = {
.driver = {
.name = "snvs_rtc",
.owner = THIS_MODULE,
.pm = &snvs_rtc_pm_ops,
.of_match_table = snvs_dt_ids,
},
.probe = snvs_rtc_probe,
.remove = __devexit_p(snvs_rtc_remove),
};
module_platform_driver(snvs_rtc_driver);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("Freescale SNVS RTC Driver");
MODULE_LICENSE("GPL");

View File

@@ -235,7 +235,7 @@ static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct spear_rtc_config *config = dev_get_drvdata(dev);
unsigned int time, date, err = 0;
unsigned int time, date;
if (tm2bcd(tm) < 0)
return -EINVAL;
@@ -247,11 +247,8 @@ static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
(tm->tm_year << YEAR_SHIFT);
writel(time, config->ioaddr + TIME_REG);
writel(date, config->ioaddr + DATE_REG);
err = is_write_complete(config);
if (err < 0)
return err;
return 0;
return is_write_complete(config);
}
/*
@@ -295,7 +292,8 @@ static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct spear_rtc_config *config = dev_get_drvdata(dev);
unsigned int time, date, err = 0;
unsigned int time, date;
int err;
if (tm2bcd(&alm->time) < 0)
return -EINVAL;
@@ -357,7 +355,7 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct spear_rtc_config *config;
unsigned int status = 0;
int status = 0;
int irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

View File

@@ -102,6 +102,12 @@ rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
return n;
}
/**
* rtc_sysfs_show_hctosys - indicate if the given RTC set the system time
*
* Returns 1 if the system clock was set by this RTC at the last
* boot or resume event.
*/
static ssize_t
rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
char *buf)

349
drivers/rtc/rtc-tps65910.c Normal file
View File

@@ -0,0 +1,349 @@
/*
* rtc-tps65910.c -- TPS65910 Real Time Clock interface
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
* Author: Venu Byravarasu <vbyravarasu@nvidia.com>
*
* Based on original TI driver rtc-twl.c
* Copyright (C) 2007 MontaVista Software, Inc
* Author: Alexandre Rusev <source@mvista.com>
*
* 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/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mfd/tps65910.h>
struct tps65910_rtc {
struct rtc_device *rtc;
/* To store the list of enabled interrupts */
u32 irqstat;
};
/* Total number of RTC registers needed to set time*/
#define NUM_TIME_REGS (TPS65910_YEARS - TPS65910_SECONDS + 1)
static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
{
struct tps65910 *tps = dev_get_drvdata(dev->parent);
u8 val = 0;
if (enabled)
val = TPS65910_RTC_INTERRUPTS_IT_ALARM;
return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, val);
}
/*
* Gets current tps65910 RTC time and date parameters.
*
* The RTC's time/alarm representation is not what gmtime(3) requires
* Linux to use:
*
* - Months are 1..12 vs Linux 0-11
* - Years are 0..99 vs Linux 1900..N (we assume 21st century)
*/
static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
unsigned char rtc_data[NUM_TIME_REGS];
struct tps65910 *tps = dev_get_drvdata(dev->parent);
int ret;
/* Copy RTC counting registers to static registers or latches */
ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
TPS65910_RTC_CTRL_GET_TIME, TPS65910_RTC_CTRL_GET_TIME);
if (ret < 0) {
dev_err(dev, "RTC CTRL reg update failed with err:%d\n", ret);
return ret;
}
ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "reading from RTC failed with err:%d\n", ret);
return ret;
}
tm->tm_sec = bcd2bin(rtc_data[0]);
tm->tm_min = bcd2bin(rtc_data[1]);
tm->tm_hour = bcd2bin(rtc_data[2]);
tm->tm_mday = bcd2bin(rtc_data[3]);
tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
tm->tm_year = bcd2bin(rtc_data[5]) + 100;
return ret;
}
static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned char rtc_data[NUM_TIME_REGS];
struct tps65910 *tps = dev_get_drvdata(dev->parent);
int ret;
rtc_data[0] = bin2bcd(tm->tm_sec);
rtc_data[1] = bin2bcd(tm->tm_min);
rtc_data[2] = bin2bcd(tm->tm_hour);
rtc_data[3] = bin2bcd(tm->tm_mday);
rtc_data[4] = bin2bcd(tm->tm_mon + 1);
rtc_data[5] = bin2bcd(tm->tm_year - 100);
/* Stop RTC while updating the RTC time registers */
ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
TPS65910_RTC_CTRL_STOP_RTC, 0);
if (ret < 0) {
dev_err(dev, "RTC stop failed with err:%d\n", ret);
return ret;
}
/* update all the time registers in one shot */
ret = regmap_bulk_write(tps->regmap, TPS65910_SECONDS, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "rtc_set_time error %d\n", ret);
return ret;
}
/* Start back RTC */
ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
TPS65910_RTC_CTRL_STOP_RTC, 1);
if (ret < 0)
dev_err(dev, "RTC start failed with err:%d\n", ret);
return ret;
}
/*
* Gets current tps65910 RTC alarm time.
*/
static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
unsigned char alarm_data[NUM_TIME_REGS];
u32 int_val;
struct tps65910 *tps = dev_get_drvdata(dev->parent);
int ret;
ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, alarm_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "rtc_read_alarm error %d\n", ret);
return ret;
}
alm->time.tm_sec = bcd2bin(alarm_data[0]);
alm->time.tm_min = bcd2bin(alarm_data[1]);
alm->time.tm_hour = bcd2bin(alarm_data[2]);
alm->time.tm_mday = bcd2bin(alarm_data[3]);
alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, &int_val);
if (ret < 0)
return ret;
if (int_val & TPS65910_RTC_INTERRUPTS_IT_ALARM)
alm->enabled = 1;
return ret;
}
static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
unsigned char alarm_data[NUM_TIME_REGS];
struct tps65910 *tps = dev_get_drvdata(dev->parent);
int ret;
ret = tps65910_rtc_alarm_irq_enable(dev, 0);
if (ret)
return ret;
alarm_data[0] = bin2bcd(alm->time.tm_sec);
alarm_data[1] = bin2bcd(alm->time.tm_min);
alarm_data[2] = bin2bcd(alm->time.tm_hour);
alarm_data[3] = bin2bcd(alm->time.tm_mday);
alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
/* update all the alarm registers in one shot */
ret = regmap_bulk_write(tps->regmap, TPS65910_ALARM_SECONDS,
alarm_data, NUM_TIME_REGS);
if (ret) {
dev_err(dev, "rtc_set_alarm error %d\n", ret);
return ret;
}
if (alm->enabled)
ret = tps65910_rtc_alarm_irq_enable(dev, 1);
return ret;
}
static irqreturn_t tps65910_rtc_interrupt(int irq, void *rtc)
{
struct device *dev = rtc;
unsigned long events = 0;
struct tps65910 *tps = dev_get_drvdata(dev->parent);
struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
int ret;
u32 rtc_reg;
ret = regmap_read(tps->regmap, TPS65910_RTC_STATUS, &rtc_reg);
if (ret)
return IRQ_NONE;
if (rtc_reg & TPS65910_RTC_STATUS_ALARM)
events = RTC_IRQF | RTC_AF;
ret = regmap_write(tps->regmap, TPS65910_RTC_STATUS, rtc_reg);
if (ret)
return IRQ_NONE;
/* Notify RTC core on event */
rtc_update_irq(tps_rtc->rtc, 1, events);
return IRQ_HANDLED;
}
static const struct rtc_class_ops tps65910_rtc_ops = {
.read_time = tps65910_rtc_read_time,
.set_time = tps65910_rtc_set_time,
.read_alarm = tps65910_rtc_read_alarm,
.set_alarm = tps65910_rtc_set_alarm,
.alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
};
static int __devinit tps65910_rtc_probe(struct platform_device *pdev)
{
struct tps65910 *tps65910 = NULL;
struct tps65910_rtc *tps_rtc = NULL;
int ret;
int irq;
u32 rtc_reg;
tps65910 = dev_get_drvdata(pdev->dev.parent);
tps_rtc = devm_kzalloc(&pdev->dev, sizeof(struct tps65910_rtc),
GFP_KERNEL);
if (!tps_rtc)
return -ENOMEM;
/* Clear pending interrupts */
ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg);
if (ret < 0)
return ret;
ret = regmap_write(tps65910->regmap, TPS65910_RTC_STATUS, rtc_reg);
if (ret < 0)
return ret;
dev_dbg(&pdev->dev, "Enabling rtc-tps65910.\n");
rtc_reg = TPS65910_RTC_CTRL_STOP_RTC;
ret = regmap_write(tps65910->regmap, TPS65910_RTC_CTRL, rtc_reg);
if (ret < 0)
return ret;
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
irq);
return ret;
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
"rtc-tps65910", &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");
return ret;
}
device_init_wakeup(&pdev->dev, 1);
tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
&tps65910_rtc_ops, THIS_MODULE);
if (IS_ERR(tps_rtc->rtc)) {
ret = PTR_ERR(tps_rtc->rtc);
dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, tps_rtc);
return 0;
}
/*
* Disable tps65910 RTC interrupts.
* Sets status flag to free.
*/
static int __devexit tps65910_rtc_remove(struct platform_device *pdev)
{
/* leave rtc running, but disable irqs */
struct rtc_device *rtc = platform_get_drvdata(pdev);
tps65910_rtc_alarm_irq_enable(&rtc->dev, 0);
rtc_device_unregister(rtc);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int tps65910_rtc_suspend(struct device *dev)
{
struct tps65910 *tps = dev_get_drvdata(dev->parent);
u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM;
int ret;
/* Store current list of enabled interrupts*/
ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS,
&tps->rtc->irqstat);
if (ret < 0)
return ret;
/* Enable RTC ALARM interrupt only */
return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm);
}
static int tps65910_rtc_resume(struct device *dev)
{
struct tps65910 *tps = dev_get_drvdata(dev->parent);
/* Restore list of enabled interrupts before suspend */
return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS,
tps->rtc->irqstat);
}
static const struct dev_pm_ops tps65910_rtc_pm_ops = {
.suspend = tps65910_rtc_suspend,
.resume = tps65910_rtc_resume,
};
#define DEV_PM_OPS (&tps65910_rtc_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif
static struct platform_driver tps65910_rtc_driver = {
.probe = tps65910_rtc_probe,
.remove = __devexit_p(tps65910_rtc_remove),
.driver = {
.owner = THIS_MODULE,
.name = "tps65910-rtc",
.pm = DEV_PM_OPS,
},
};
module_platform_driver(tps65910_rtc_driver);
MODULE_ALIAS("platform:rtc-tps65910");
MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
MODULE_LICENSE("GPL");

View File

@@ -97,8 +97,17 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
int i;
struct i2c_msg msgs[] = {
{ client->addr, 0, 2, dt_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 8, buf }, /* read date */
{/* setup read ptr */
.addr = client->addr,
.len = 2,
.buf = dt_addr
},
{/* read date */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 8,
.buf = buf
},
};
/* read date registers */
@@ -142,8 +151,17 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
struct i2c_msg msgs[] = {
{ client->addr, 0, 2, sr_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 1, sr }, /* read status */
{ /* setup read ptr */
.addr = client->addr,
.len = 2,
.buf = sr_addr
},
{ /* read status */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = sr
},
};
/* read status register */
@@ -279,8 +297,17 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim)
static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
struct i2c_msg msgs[] = {
{ client->addr, 0, 2, dtr_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 1, &dtr }, /* read dtr */
{ /* setup read ptr */
.addr = client->addr,
.len = 2,
.buf = dtr_addr
},
{ /* read dtr */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &dtr
},
};
/* read dtr register */
@@ -311,8 +338,17 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
struct i2c_msg msgs[] = {
{ client->addr, 0, 2, atr_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 1, &atr }, /* read atr */
{/* setup read ptr */
.addr = client->addr,
.len = 2,
.buf = atr_addr
},
{/* read atr */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &atr
},
};
/* read atr register */
@@ -381,8 +417,17 @@ static int x1205_validate_client(struct i2c_client *client)
unsigned char addr[2] = { 0, probe_zero_pattern[i] };
struct i2c_msg msgs[2] = {
{ client->addr, 0, 2, addr },
{ client->addr, I2C_M_RD, 1, &buf },
{
.addr = client->addr,
.len = 2,
.buf = addr
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &buf
},
};
if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
@@ -409,8 +454,17 @@ static int x1205_validate_client(struct i2c_client *client)
unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
struct i2c_msg msgs[2] = {
{ client->addr, 0, 2, addr },
{ client->addr, I2C_M_RD, 1, &reg },
{
.addr = client->addr,
.len = 2,
.buf = addr
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &reg
},
};
if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
@@ -444,8 +498,18 @@ static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static unsigned char int_addr[2] = { 0, X1205_REG_INT };
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msgs[] = {
{ client->addr, 0, 2, int_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 1, &intreg }, /* read INT register */
{ /* setup read ptr */
.addr = client->addr,
.len = 2,
.buf = int_addr
},
{/* read INT register */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &intreg
},
};
/* read interrupt register and status register */