Merge tag 'rtc-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "Here is the pull-request for the RTC subsystem for 4.13.

  Subsystem:

   - expose non volatile RAM using nvmem instead of open coding in many
     drivers. Unfortunately, this option has to be enabled by default to
     not break existing users.

   - rtctest can now test for cutoff dates, showing when an RTC will
     start failing to properly save time and date.

   - new RTC registration functions to remove race conditions in drivers

  Newly supported RTCs:

   - Broadcom STB wake-timer

   - Epson RX8130CE

   - Maxim IC DS1308

   - STMicroelectronics STM32H7

  Drivers:

   - ds1307: use regmap, use nvmem, more cleanups

   - ds3232: temperature reading support

   - gemini: renamed to ftrtc010

   - m41t80: use CCF to expose the clock

   - rv8803: use nvmem

   - s3c: many cleanups

   - st-lpc: fix y2106 bug"

* tag 'rtc-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (51 commits)
  rtc: Remove wrong deprecation comment
  nvmem: include linux/err.h from header
  rtc: st-lpc: make it robust against y2038/2106 bug
  rtc: rtctest: add check for problematic dates
  tools: timer: add rtctest_setdate
  rtc: ds1307: remove ds1307_remove
  rtc: ds1307: use generic nvmem
  rtc: ds1307: switch to rtc_register_device
  rtc: rv8803: remove rv8803_remove
  rtc: rv8803: use generic nvmem support
  rtc: rv8803: switch to rtc_register_device
  rtc: add generic nvmem support
  rtc: at91rm9200: remove race condition
  rtc: introduce new registration method
  rtc: class separate id allocation from registration
  rtc: class separate device allocation from registration
  rtc: stm32: add STM32H7 RTC support
  dt-bindings: rtc: stm32: add support for STM32H7
  rtc: ds1307: add ds1308 variant
  rtc: ds3232: add temperature support
  ...
This commit is contained in:
Linus Torvalds
2017-07-13 12:15:06 -07:00
33 changed files with 2040 additions and 905 deletions
+32 -5
View File
@@ -77,6 +77,14 @@ config RTC_DEBUG
Say yes here to enable debugging support in the RTC framework
and individual RTC drivers.
config RTC_NVMEM
bool "RTC non volatile storage support"
select NVMEM
default RTC_CLASS
help
Say yes here to add support for the non volatile (often battery
backed) storage present on RTCs.
comment "RTC interfaces"
config RTC_INTF_SYSFS
@@ -197,6 +205,17 @@ config RTC_DRV_AC100
This driver can also be built as a module. If so, the module
will be called rtc-ac100.
config RTC_DRV_BRCMSTB
tristate "Broadcom STB wake-timer"
depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
default ARCH_BRCMSTB || BMIPS_GENERIC
help
If you say yes here you get support for the wake-timer found on
Broadcom STB SoCs (BCM7xxx).
This driver can also be built as a module. If so, the module will
be called rtc-brcmstb-waketimer.
config RTC_DRV_AS3722
tristate "ams AS3722 RTC driver"
depends on MFD_AS3722
@@ -791,6 +810,14 @@ config RTC_DRV_DS3232
This driver can also be built as a module. If so, the module
will be called rtc-ds3232.
config RTC_DRV_DS3232_HWMON
bool "HWMON support for Dallas/Maxim DS3232/DS3234"
depends on RTC_DRV_DS3232 && HWMON && !(RTC_DRV_DS3232=y && HWMON=m)
default y
help
Say Y here if you want to expose temperature sensor data on
rtc-ds3232
config RTC_DRV_PCF2127
tristate "NXP PCF2127"
depends on RTC_I2C_AND_SPI
@@ -1484,16 +1511,16 @@ config RTC_DRV_ARMADA38X
This driver can also be built as a module. If so, the module
will be called armada38x-rtc.
config RTC_DRV_GEMINI
tristate "Gemini SoC RTC"
depends on ARCH_GEMINI || COMPILE_TEST
config RTC_DRV_FTRTC010
tristate "Faraday Technology FTRTC010 RTC"
depends on HAS_IOMEM
default ARCH_GEMINI
help
If you say Y here you will get support for the
RTC found on Gemini SoC's.
Faraday Technolog FTRTC010 found on e.g. Gemini SoC's.
This driver can also be built as a module. If so, the module
will be called rtc-gemini.
will be called rtc-ftrtc010.
config RTC_DRV_PS3
tristate "PS3 RTC"
+3 -1
View File
@@ -15,6 +15,7 @@ ifdef CONFIG_RTC_DRV_EFI
rtc-core-y += rtc-efi-platform.o
endif
rtc-core-$(CONFIG_RTC_NVMEM) += nvmem.o
rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
@@ -67,7 +69,7 @@ obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_GEMINI) += rtc-gemini.o
obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o
+153 -49
View File
@@ -150,59 +150,19 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
#define RTC_CLASS_DEV_PM_OPS NULL
#endif
/**
* rtc_device_register - register w/ RTC class
* @dev: the device to register
*
* rtc_device_unregister() must be called when the class device is no
* longer needed.
*
* Returns the pointer to the new struct class device.
*/
struct rtc_device *rtc_device_register(const char *name, struct device *dev,
const struct rtc_class_ops *ops,
struct module *owner)
/* Ensure the caller will set the id before releasing the device */
static struct rtc_device *rtc_allocate_device(void)
{
struct rtc_device *rtc;
struct rtc_wkalrm alrm;
int of_id = -1, id = -1, err;
if (dev->of_node)
of_id = of_alias_get_id(dev->of_node, "rtc");
else if (dev->parent && dev->parent->of_node)
of_id = of_alias_get_id(dev->parent->of_node, "rtc");
if (of_id >= 0) {
id = ida_simple_get(&rtc_ida, of_id, of_id + 1,
GFP_KERNEL);
if (id < 0)
dev_warn(dev, "/aliases ID %d not available\n",
of_id);
}
if (id < 0) {
id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
err = id;
goto exit;
}
}
rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
if (rtc == NULL) {
err = -ENOMEM;
goto exit_ida;
}
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return NULL;
device_initialize(&rtc->dev);
rtc->id = id;
rtc->ops = ops;
rtc->owner = owner;
rtc->irq_freq = 1;
rtc->max_user_freq = 64;
rtc->dev.parent = dev;
rtc->dev.class = rtc_class;
rtc->dev.groups = rtc_get_dev_attribute_groups();
rtc->dev.release = rtc_device_release;
@@ -224,7 +184,64 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
rtc->pie_timer.function = rtc_pie_update_irq;
rtc->pie_enabled = 0;
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
return rtc;
}
static int rtc_device_get_id(struct device *dev)
{
int of_id = -1, id = -1;
if (dev->of_node)
of_id = of_alias_get_id(dev->of_node, "rtc");
else if (dev->parent && dev->parent->of_node)
of_id = of_alias_get_id(dev->parent->of_node, "rtc");
if (of_id >= 0) {
id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL);
if (id < 0)
dev_warn(dev, "/aliases ID %d not available\n", of_id);
}
if (id < 0)
id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
return id;
}
/**
* rtc_device_register - register w/ RTC class
* @dev: the device to register
*
* rtc_device_unregister() must be called when the class device is no
* longer needed.
*
* Returns the pointer to the new struct class device.
*/
struct rtc_device *rtc_device_register(const char *name, struct device *dev,
const struct rtc_class_ops *ops,
struct module *owner)
{
struct rtc_device *rtc;
struct rtc_wkalrm alrm;
int id, err;
id = rtc_device_get_id(dev);
if (id < 0) {
err = id;
goto exit;
}
rtc = rtc_allocate_device();
if (!rtc) {
err = -ENOMEM;
goto exit_ida;
}
rtc->id = id;
rtc->ops = ops;
rtc->owner = owner;
rtc->dev.parent = dev;
dev_set_name(&rtc->dev, "rtc%d", id);
/* Check to see if there is an ALARM already set in hw */
@@ -238,20 +255,20 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
err = cdev_device_add(&rtc->char_dev, &rtc->dev);
if (err) {
dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n",
rtc->name, MAJOR(rtc->dev.devt), rtc->id);
name, MAJOR(rtc->dev.devt), rtc->id);
/* This will free both memory and the ID */
put_device(&rtc->dev);
goto exit;
} else {
dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name,
dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", name,
MAJOR(rtc->dev.devt), rtc->id);
}
rtc_proc_add_device(rtc);
dev_info(dev, "rtc core: registered %s as %s\n",
rtc->name, dev_name(&rtc->dev));
name, dev_name(&rtc->dev));
return rtc;
@@ -273,6 +290,8 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
*/
void rtc_device_unregister(struct rtc_device *rtc)
{
rtc_nvmem_unregister(rtc);
mutex_lock(&rtc->ops_lock);
/*
* Remove innards of this RTC, then disable it, before
@@ -356,6 +375,91 @@ void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc)
}
EXPORT_SYMBOL_GPL(devm_rtc_device_unregister);
static void devm_rtc_release_device(struct device *dev, void *res)
{
struct rtc_device *rtc = *(struct rtc_device **)res;
if (rtc->registered)
rtc_device_unregister(rtc);
else
put_device(&rtc->dev);
}
struct rtc_device *devm_rtc_allocate_device(struct device *dev)
{
struct rtc_device **ptr, *rtc;
int id, err;
id = rtc_device_get_id(dev);
if (id < 0)
return ERR_PTR(id);
ptr = devres_alloc(devm_rtc_release_device, sizeof(*ptr), GFP_KERNEL);
if (!ptr) {
err = -ENOMEM;
goto exit_ida;
}
rtc = rtc_allocate_device();
if (!rtc) {
err = -ENOMEM;
goto exit_devres;
}
*ptr = rtc;
devres_add(dev, ptr);
rtc->id = id;
rtc->dev.parent = dev;
dev_set_name(&rtc->dev, "rtc%d", id);
return rtc;
exit_devres:
devres_free(ptr);
exit_ida:
ida_simple_remove(&rtc_ida, id);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(devm_rtc_allocate_device);
int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
{
struct rtc_wkalrm alrm;
int err;
if (!rtc->ops)
return -EINVAL;
rtc->owner = owner;
/* Check to see if there is an ALARM already set in hw */
err = __rtc_read_alarm(rtc, &alrm);
if (!err && !rtc_valid_tm(&alrm.time))
rtc_initialize_alarm(rtc, &alrm);
rtc_dev_prepare(rtc);
err = cdev_device_add(&rtc->char_dev, &rtc->dev);
if (err)
dev_warn(rtc->dev.parent, "failed to add char device %d:%d\n",
MAJOR(rtc->dev.devt), rtc->id);
else
dev_dbg(rtc->dev.parent, "char device (%d:%d)\n",
MAJOR(rtc->dev.devt), rtc->id);
rtc_proc_add_device(rtc);
rtc_nvmem_register(rtc);
rtc->registered = true;
dev_info(rtc->dev.parent, "registered as %s\n",
dev_name(&rtc->dev));
return 0;
}
EXPORT_SYMBOL_GPL(__rtc_register_device);
static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc");
+8 -1
View File
@@ -227,6 +227,13 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
missing = year;
}
/* Can't proceed if alarm is still invalid after replacing
* missing fields.
*/
err = rtc_valid_tm(&alarm->time);
if (err)
goto done;
/* with luck, no rollover is needed */
t_now = rtc_tm_to_time64(&now);
t_alm = rtc_tm_to_time64(&alarm->time);
@@ -278,9 +285,9 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
dev_warn(&rtc->dev, "alarm rollover not handled\n");
}
done:
err = rtc_valid_tm(&alarm->time);
done:
if (err) {
dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
+113
View File
@@ -0,0 +1,113 @@
/*
* RTC subsystem, nvmem interface
*
* Copyright (C) 2017 Alexandre Belloni
*
* 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/err.h>
#include <linux/types.h>
#include <linux/nvmem-consumer.h>
#include <linux/rtc.h>
#include <linux/sysfs.h>
#include "rtc-core.h"
/*
* Deprecated ABI compatibility, this should be removed at some point
*/
static const char nvram_warning[] = "Deprecated ABI, please use nvmem";
static ssize_t
rtc_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct rtc_device *rtc = attr->private;
dev_warn_once(kobj_to_dev(kobj), nvram_warning);
return nvmem_device_read(rtc->nvmem, off, count, buf);
}
static ssize_t
rtc_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct rtc_device *rtc = attr->private;
dev_warn_once(kobj_to_dev(kobj), nvram_warning);
return nvmem_device_write(rtc->nvmem, off, count, buf);
}
static int rtc_nvram_register(struct rtc_device *rtc)
{
int err;
rtc->nvram = devm_kzalloc(rtc->dev.parent,
sizeof(struct bin_attribute),
GFP_KERNEL);
if (!rtc->nvram)
return -ENOMEM;
rtc->nvram->attr.name = "nvram";
rtc->nvram->attr.mode = 0644;
rtc->nvram->private = rtc;
sysfs_bin_attr_init(rtc->nvram);
rtc->nvram->read = rtc_nvram_read;
rtc->nvram->write = rtc_nvram_write;
rtc->nvram->size = rtc->nvmem_config->size;
err = sysfs_create_bin_file(&rtc->dev.parent->kobj,
rtc->nvram);
if (err) {
devm_kfree(rtc->dev.parent, rtc->nvram);
rtc->nvram = NULL;
}
return err;
}
static void rtc_nvram_unregister(struct rtc_device *rtc)
{
sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram);
}
/*
* New ABI, uses nvmem
*/
void rtc_nvmem_register(struct rtc_device *rtc)
{
if (!rtc->nvmem_config)
return;
rtc->nvmem_config->dev = &rtc->dev;
rtc->nvmem_config->owner = rtc->owner;
rtc->nvmem = nvmem_register(rtc->nvmem_config);
if (IS_ERR_OR_NULL(rtc->nvmem))
return;
/* Register the old ABI */
if (rtc->nvram_old_abi)
rtc_nvram_register(rtc);
}
void rtc_nvmem_unregister(struct rtc_device *rtc)
{
if (IS_ERR_OR_NULL(rtc->nvmem))
return;
/* unregister the old ABI */
if (rtc->nvram)
rtc_nvram_unregister(rtc);
nvmem_unregister(rtc->nvmem);
}
+8 -6
View File
@@ -409,6 +409,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
}
rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
platform_set_drvdata(pdev, rtc);
sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(sclk))
return PTR_ERR(sclk);
@@ -441,13 +446,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
if (!device_can_wakeup(&pdev->dev))
device_init_wakeup(&pdev->dev, 1);
rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&at91_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc);
rtc->ops = &at91_rtc_ops;
ret = rtc_register_device(rtc);
if (ret)
goto err_clk;
}
platform_set_drvdata(pdev, rtc);
/* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy
* completion.
+330
View File
@@ -0,0 +1,330 @@
/*
* Copyright © 2014-2017 Broadcom
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_wakeup.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/stat.h>
#include <linux/suspend.h>
struct brcmstb_waketmr {
struct rtc_device *rtc;
struct device *dev;
void __iomem *base;
int irq;
struct notifier_block reboot_notifier;
struct clk *clk;
u32 rate;
};
#define BRCMSTB_WKTMR_EVENT 0x00
#define BRCMSTB_WKTMR_COUNTER 0x04
#define BRCMSTB_WKTMR_ALARM 0x08
#define BRCMSTB_WKTMR_PRESCALER 0x0C
#define BRCMSTB_WKTMR_PRESCALER_VAL 0x10
#define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000
static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
{
writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT);
(void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
}
static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
unsigned int secs)
{
brcmstb_waketmr_clear_alarm(timer);
writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM);
}
static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
{
struct brcmstb_waketmr *timer = data;
pm_wakeup_event(timer->dev, 0);
return IRQ_HANDLED;
}
struct wktmr_time {
u32 sec;
u32 pre;
};
static void wktmr_read(struct brcmstb_waketmr *timer,
struct wktmr_time *t)
{
u32 tmp;
do {
t->sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
tmp = readl_relaxed(timer->base + BRCMSTB_WKTMR_PRESCALER_VAL);
} while (tmp >= timer->rate);
t->pre = timer->rate - tmp;
}
static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
{
struct device *dev = timer->dev;
int ret = 0;
if (device_may_wakeup(dev)) {
ret = enable_irq_wake(timer->irq);
if (ret) {
dev_err(dev, "failed to enable wake-up interrupt\n");
return ret;
}
}
return ret;
}
/* If enabled as a wakeup-source, arm the timer when powering off */
static int brcmstb_waketmr_reboot(struct notifier_block *nb,
unsigned long action, void *data)
{
struct brcmstb_waketmr *timer;
timer = container_of(nb, struct brcmstb_waketmr, reboot_notifier);
/* Set timer for cold boot */
if (action == SYS_POWER_OFF)
brcmstb_waketmr_prepare_suspend(timer);
return NOTIFY_DONE;
}
static int brcmstb_waketmr_gettime(struct device *dev,
struct rtc_time *tm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
struct wktmr_time now;
wktmr_read(timer, &now);
rtc_time_to_tm(now.sec, tm);
return 0;
}
static int brcmstb_waketmr_settime(struct device *dev,
struct rtc_time *tm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
time64_t sec;
sec = rtc_tm_to_time64(tm);
if (sec > U32_MAX || sec < 0)
return -EINVAL;
writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER);
return 0;
}
static int brcmstb_waketmr_getalarm(struct device *dev,
struct rtc_wkalrm *alarm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
time64_t sec;
u32 reg;
sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
if (sec != 0) {
/* Alarm is enabled */
alarm->enabled = 1;
rtc_time64_to_tm(sec, &alarm->time);
}
reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
alarm->pending = !!(reg & 1);
return 0;
}
static int brcmstb_waketmr_setalarm(struct device *dev,
struct rtc_wkalrm *alarm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
time64_t sec;
if (alarm->enabled)
sec = rtc_tm_to_time64(&alarm->time);
else
sec = 0;
if (sec > U32_MAX || sec < 0)
return -EINVAL;
brcmstb_waketmr_set_alarm(timer, sec);
return 0;
}
/*
* Does not do much but keep the RTC class happy. We always support
* alarms.
*/
static int brcmstb_waketmr_alarm_enable(struct device *dev,
unsigned int enabled)
{
return 0;
}
static const struct rtc_class_ops brcmstb_waketmr_ops = {
.read_time = brcmstb_waketmr_gettime,
.set_time = brcmstb_waketmr_settime,
.read_alarm = brcmstb_waketmr_getalarm,
.set_alarm = brcmstb_waketmr_setalarm,
.alarm_irq_enable = brcmstb_waketmr_alarm_enable,
};
static int brcmstb_waketmr_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct brcmstb_waketmr *timer;
struct resource *res;
int ret;
timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
if (!timer)
return -ENOMEM;
platform_set_drvdata(pdev, timer);
timer->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
timer->base = devm_ioremap_resource(dev, res);
if (IS_ERR(timer->base))
return PTR_ERR(timer->base);
/*
* Set wakeup capability before requesting wakeup interrupt, so we can
* process boot-time "wakeups" (e.g., from S5 soft-off)
*/
device_set_wakeup_capable(dev, true);
device_wakeup_enable(dev);
timer->irq = platform_get_irq(pdev, 0);
if (timer->irq < 0)
return -ENODEV;
timer->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(timer->clk)) {
ret = clk_prepare_enable(timer->clk);
if (ret)
return ret;
timer->rate = clk_get_rate(timer->clk);
if (!timer->rate)
timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
} else {
timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
timer->clk = NULL;
}
ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0,
"brcmstb-waketimer", timer);
if (ret < 0)
return ret;
timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
register_reboot_notifier(&timer->reboot_notifier);
timer->rtc = rtc_device_register("brcmstb-waketmr", dev,
&brcmstb_waketmr_ops, THIS_MODULE);
if (IS_ERR(timer->rtc)) {
dev_err(dev, "unable to register device\n");
unregister_reboot_notifier(&timer->reboot_notifier);
return PTR_ERR(timer->rtc);
}
dev_info(dev, "registered, with irq %d\n", timer->irq);
return ret;
}
static int brcmstb_waketmr_remove(struct platform_device *pdev)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
unregister_reboot_notifier(&timer->reboot_notifier);
rtc_device_unregister(timer->rtc);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int brcmstb_waketmr_suspend(struct device *dev)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
return brcmstb_waketmr_prepare_suspend(timer);
}
static int brcmstb_waketmr_resume(struct device *dev)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
int ret;
if (!device_may_wakeup(dev))
return 0;
ret = disable_irq_wake(timer->irq);
brcmstb_waketmr_clear_alarm(timer);
return ret;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops,
brcmstb_waketmr_suspend, brcmstb_waketmr_resume);
static const struct of_device_id brcmstb_waketmr_of_match[] = {
{ .compatible = "brcm,brcmstb-waketimer" },
{ /* sentinel */ },
};
static struct platform_driver brcmstb_waketmr_driver = {
.probe = brcmstb_waketmr_probe,
.remove = brcmstb_waketmr_remove,
.driver = {
.name = "brcmstb-waketimer",
.pm = &brcmstb_waketmr_pm_ops,
.of_match_table = of_match_ptr(brcmstb_waketmr_of_match),
}
};
module_platform_driver(brcmstb_waketmr_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris");
MODULE_AUTHOR("Markus Mayer");
MODULE_DESCRIPTION("Wake-up timer driver for STB chips");
+8
View File
@@ -45,3 +45,11 @@ static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
return NULL;
}
#endif
#ifdef CONFIG_RTC_NVMEM
void rtc_nvmem_register(struct rtc_device *rtc);
void rtc_nvmem_unregister(struct rtc_device *rtc);
#else
static inline void rtc_nvmem_register(struct rtc_device *rtc) {}
static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {}
#endif
+1 -1
View File
@@ -464,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
return;
if (rtc->id >= RTC_DEV_MAX) {
dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name);
dev_dbg(&rtc->dev, "too many RTC devices\n");
return;
}
+440 -519
View File
File diff suppressed because it is too large Load Diff
+119
View File
@@ -22,6 +22,7 @@
#include <linux/bcd.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/hwmon.h>
#define DS3232_REG_SECONDS 0x00
#define DS3232_REG_MINUTES 0x01
@@ -46,6 +47,8 @@
# define DS3232_REG_SR_A2F 0x02
# define DS3232_REG_SR_A1F 0x01
#define DS3232_REG_TEMPERATURE 0x11
struct ds3232 {
struct device *dev;
struct regmap *regmap;
@@ -275,6 +278,120 @@ static int ds3232_update_alarm(struct device *dev, unsigned int enabled)
return ret;
}
/*
* Temperature sensor support for ds3232/ds3234 devices.
* A user-initiated temperature conversion is not started by this function,
* so the temperature is updated once every 64 seconds.
*/
static int ds3232_hwmon_read_temp(struct device *dev, long int *mC)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
u8 temp_buf[2];
s16 temp;
int ret;
ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_TEMPERATURE, temp_buf,
sizeof(temp_buf));
if (ret < 0)
return ret;
/*
* Temperature is represented as a 10-bit code with a resolution of
* 0.25 degree celsius and encoded in two's complement format.
*/
temp = (temp_buf[0] << 8) | temp_buf[1];
temp >>= 6;
*mC = temp * 250;
return 0;
}
static umode_t ds3232_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
if (type != hwmon_temp)
return 0;
switch (attr) {
case hwmon_temp_input:
return 0444;
default:
return 0;
}
}
static int ds3232_hwmon_read(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel, long *temp)
{
int err;
switch (attr) {
case hwmon_temp_input:
err = ds3232_hwmon_read_temp(dev, temp);
break;
default:
err = -EOPNOTSUPP;
break;
}
return err;
}
static u32 ds3232_hwmon_chip_config[] = {
HWMON_C_REGISTER_TZ,
0
};
static const struct hwmon_channel_info ds3232_hwmon_chip = {
.type = hwmon_chip,
.config = ds3232_hwmon_chip_config,
};
static u32 ds3232_hwmon_temp_config[] = {
HWMON_T_INPUT,
0
};
static const struct hwmon_channel_info ds3232_hwmon_temp = {
.type = hwmon_temp,
.config = ds3232_hwmon_temp_config,
};
static const struct hwmon_channel_info *ds3232_hwmon_info[] = {
&ds3232_hwmon_chip,
&ds3232_hwmon_temp,
NULL
};
static const struct hwmon_ops ds3232_hwmon_hwmon_ops = {
.is_visible = ds3232_hwmon_is_visible,
.read = ds3232_hwmon_read,
};
static const struct hwmon_chip_info ds3232_hwmon_chip_info = {
.ops = &ds3232_hwmon_hwmon_ops,
.info = ds3232_hwmon_info,
};
static void ds3232_hwmon_register(struct device *dev, const char *name)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct device *hwmon_dev;
if (!IS_ENABLED(CONFIG_RTC_DRV_DS3232_HWMON))
return;
hwmon_dev = devm_hwmon_device_register_with_info(dev, name, ds3232,
&ds3232_hwmon_chip_info,
NULL);
if (IS_ERR(hwmon_dev)) {
dev_err(dev, "unable to register hwmon device %ld\n",
PTR_ERR(hwmon_dev));
}
}
static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
@@ -366,6 +483,8 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
if (ds3232->irq > 0)
device_init_wakeup(dev, 1);
ds3232_hwmon_register(dev, name);
ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
THIS_MODULE);
if (IS_ERR(ds3232->rtc))
@@ -1,5 +1,5 @@
/*
* Gemini OnChip RTC
* Faraday Technology FTRTC010 driver
*
* Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
*
@@ -26,33 +26,36 @@
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/clk.h>
#define DRV_NAME "rtc-gemini"
#define DRV_NAME "rtc-ftrtc010"
MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>");
MODULE_DESCRIPTION("RTC driver for Gemini SoC");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);
struct gemini_rtc {
struct ftrtc010_rtc {
struct rtc_device *rtc_dev;
void __iomem *rtc_base;
int rtc_irq;
struct clk *pclk;
struct clk *extclk;
};
enum gemini_rtc_offsets {
GEMINI_RTC_SECOND = 0x00,
GEMINI_RTC_MINUTE = 0x04,
GEMINI_RTC_HOUR = 0x08,
GEMINI_RTC_DAYS = 0x0C,
GEMINI_RTC_ALARM_SECOND = 0x10,
GEMINI_RTC_ALARM_MINUTE = 0x14,
GEMINI_RTC_ALARM_HOUR = 0x18,
GEMINI_RTC_RECORD = 0x1C,
GEMINI_RTC_CR = 0x20
enum ftrtc010_rtc_offsets {
FTRTC010_RTC_SECOND = 0x00,
FTRTC010_RTC_MINUTE = 0x04,
FTRTC010_RTC_HOUR = 0x08,
FTRTC010_RTC_DAYS = 0x0C,
FTRTC010_RTC_ALARM_SECOND = 0x10,
FTRTC010_RTC_ALARM_MINUTE = 0x14,
FTRTC010_RTC_ALARM_HOUR = 0x18,
FTRTC010_RTC_RECORD = 0x1C,
FTRTC010_RTC_CR = 0x20,
};
static irqreturn_t gemini_rtc_interrupt(int irq, void *dev)
static irqreturn_t ftrtc010_rtc_interrupt(int irq, void *dev)
{
return IRQ_HANDLED;
}
@@ -66,18 +69,18 @@ static irqreturn_t gemini_rtc_interrupt(int irq, void *dev)
* the same thing, without the rtc-lib.c calls.
*/
static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct gemini_rtc *rtc = dev_get_drvdata(dev);
struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
unsigned int days, hour, min, sec;
unsigned long offset, time;
sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
days = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
offset = readl(rtc->rtc_base + GEMINI_RTC_RECORD);
sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD);
time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
@@ -86,9 +89,9 @@ static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm)
return 0;
}
static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct gemini_rtc *rtc = dev_get_drvdata(dev);
struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
unsigned int sec, min, hour, day;
unsigned long offset, time;
@@ -97,27 +100,27 @@ static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_tm_to_time(tm, &time);
sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
day = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);
writel(offset, rtc->rtc_base + GEMINI_RTC_RECORD);
writel(0x01, rtc->rtc_base + GEMINI_RTC_CR);
writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD);
writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR);
return 0;
}
static const struct rtc_class_ops gemini_rtc_ops = {
.read_time = gemini_rtc_read_time,
.set_time = gemini_rtc_set_time,
static const struct rtc_class_ops ftrtc010_rtc_ops = {
.read_time = ftrtc010_rtc_read_time,
.set_time = ftrtc010_rtc_set_time,
};
static int gemini_rtc_probe(struct platform_device *pdev)
static int ftrtc010_rtc_probe(struct platform_device *pdev)
{
struct gemini_rtc *rtc;
struct ftrtc010_rtc *rtc;
struct device *dev = &pdev->dev;
struct resource *res;
int ret;
@@ -127,6 +130,27 @@ static int gemini_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
rtc->pclk = devm_clk_get(dev, "PCLK");
if (IS_ERR(rtc->pclk)) {
dev_err(dev, "could not get PCLK\n");
} else {
ret = clk_prepare_enable(rtc->pclk);
if (ret) {
dev_err(dev, "failed to enable PCLK\n");
return ret;
}
}
rtc->extclk = devm_clk_get(dev, "EXTCLK");
if (IS_ERR(rtc->extclk)) {
dev_err(dev, "could not get EXTCLK\n");
} else {
ret = clk_prepare_enable(rtc->extclk);
if (ret) {
dev_err(dev, "failed to enable EXTCLK\n");
return ret;
}
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res)
return -ENODEV;
@@ -142,38 +166,43 @@ static int gemini_rtc_probe(struct platform_device *pdev)
if (!rtc->rtc_base)
return -ENOMEM;
ret = devm_request_irq(dev, rtc->rtc_irq, gemini_rtc_interrupt,
ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
IRQF_SHARED, pdev->name, dev);
if (unlikely(ret))
return ret;
rtc->rtc_dev = rtc_device_register(pdev->name, dev,
&gemini_rtc_ops, THIS_MODULE);
&ftrtc010_rtc_ops, THIS_MODULE);
return PTR_ERR_OR_ZERO(rtc->rtc_dev);
}
static int gemini_rtc_remove(struct platform_device *pdev)
static int ftrtc010_rtc_remove(struct platform_device *pdev)
{
struct gemini_rtc *rtc = platform_get_drvdata(pdev);
struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev);
if (!IS_ERR(rtc->extclk))
clk_disable_unprepare(rtc->extclk);
if (!IS_ERR(rtc->pclk))
clk_disable_unprepare(rtc->pclk);
rtc_device_unregister(rtc->rtc_dev);
return 0;
}
static const struct of_device_id gemini_rtc_dt_match[] = {
static const struct of_device_id ftrtc010_rtc_dt_match[] = {
{ .compatible = "cortina,gemini-rtc" },
{ .compatible = "faraday,ftrtc010" },
{ }
};
MODULE_DEVICE_TABLE(of, gemini_rtc_dt_match);
MODULE_DEVICE_TABLE(of, ftrtc010_rtc_dt_match);
static struct platform_driver gemini_rtc_driver = {
static struct platform_driver ftrtc010_rtc_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = gemini_rtc_dt_match,
.of_match_table = ftrtc010_rtc_dt_match,
},
.probe = gemini_rtc_probe,
.remove = gemini_rtc_remove,
.probe = ftrtc010_rtc_probe,
.remove = ftrtc010_rtc_remove,
};
module_platform_driver_probe(gemini_rtc_driver, gemini_rtc_probe);
module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);
+187 -88
View File
@@ -16,6 +16,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bcd.h>
#include <linux/clk-provider.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -53,6 +54,8 @@
#define M41T80_ALARM_REG_SIZE \
(M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON)
#define M41T80_SQW_MAX_FREQ 32768
#define M41T80_SEC_ST BIT(7) /* ST: Stop Bit */
#define M41T80_ALMON_AFE BIT(7) /* AFE: AF Enable Bit */
#define M41T80_ALMON_SQWE BIT(6) /* SQWE: SQW Enable Bit */
@@ -147,7 +150,11 @@ MODULE_DEVICE_TABLE(of, m41t80_of_match);
struct m41t80_data {
unsigned long features;
struct i2c_client *client;
struct rtc_device *rtc;
#ifdef CONFIG_COMMON_CLK
struct clk_hw sqw;
#endif
};
static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
@@ -227,6 +234,7 @@ static int m41t80_get_datetime(struct i2c_client *client,
/* Sets the given date and time to the real time clock. */
static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct m41t80_data *clientdata = i2c_get_clientdata(client);
unsigned char buf[8];
int err, flags;
@@ -242,6 +250,17 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
buf[M41T80_REG_WDAY] = tm->tm_wday;
/* If the square wave output is controlled in the weekday register */
if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
int val;
val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY);
if (val < 0)
return val;
buf[M41T80_REG_WDAY] |= (val & 0xf0);
}
err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
sizeof(buf), buf);
if (err < 0) {
@@ -332,6 +351,9 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return err;
}
/* Keep SQWE bit value */
alarmvals[0] |= (ret & M41T80_ALMON_SQWE);
ret = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
if (ret < 0)
return ret;
@@ -431,96 +453,8 @@ static ssize_t flags_show(struct device *dev,
}
static DEVICE_ATTR_RO(flags);
static ssize_t sqwfreq_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct m41t80_data *clientdata = i2c_get_clientdata(client);
int val, reg_sqw;
if (!(clientdata->features & M41T80_FEATURE_SQ))
return -EINVAL;
reg_sqw = M41T80_REG_SQW;
if (clientdata->features & M41T80_FEATURE_SQ_ALT)
reg_sqw = M41T80_REG_WDAY;
val = i2c_smbus_read_byte_data(client, reg_sqw);
if (val < 0)
return val;
val = (val >> 4) & 0xf;
switch (val) {
case 0:
break;
case 1:
val = 32768;
break;
default:
val = 32768 >> val;
}
return sprintf(buf, "%d\n", val);
}
static ssize_t sqwfreq_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct m41t80_data *clientdata = i2c_get_clientdata(client);
int almon, sqw, reg_sqw, rc;
unsigned long val;
rc = kstrtoul(buf, 0, &val);
if (rc < 0)
return rc;
if (!(clientdata->features & M41T80_FEATURE_SQ))
return -EINVAL;
if (val) {
if (!is_power_of_2(val))
return -EINVAL;
val = ilog2(val);
if (val == 15)
val = 1;
else if (val < 14)
val = 15 - val;
else
return -EINVAL;
}
/* disable SQW, set SQW frequency & re-enable */
almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (almon < 0)
return almon;
reg_sqw = M41T80_REG_SQW;
if (clientdata->features & M41T80_FEATURE_SQ_ALT)
reg_sqw = M41T80_REG_WDAY;
sqw = i2c_smbus_read_byte_data(client, reg_sqw);
if (sqw < 0)
return sqw;
sqw = (sqw & 0x0f) | (val << 4);
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
almon & ~M41T80_ALMON_SQWE);
if (rc < 0)
return rc;
if (val) {
rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw);
if (rc < 0)
return rc;
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
almon | M41T80_ALMON_SQWE);
if (rc < 0)
return rc;
}
return count;
}
static DEVICE_ATTR_RW(sqwfreq);
static struct attribute *attrs[] = {
&dev_attr_flags.attr,
&dev_attr_sqwfreq.attr,
NULL,
};
@@ -528,6 +462,166 @@ static struct attribute_group attr_group = {
.attrs = attrs,
};
#ifdef CONFIG_COMMON_CLK
#define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw)
static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
struct i2c_client *client = m41t80->client;
int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
M41T80_REG_WDAY : M41T80_REG_SQW;
int ret = i2c_smbus_read_byte_data(client, reg_sqw);
unsigned long val = M41T80_SQW_MAX_FREQ;
if (ret < 0)
return 0;
ret >>= 4;
if (ret == 0)
val = 0;
else if (ret > 1)
val = val / (1 << ret);
return val;
}
static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
int i, freq = M41T80_SQW_MAX_FREQ;
if (freq <= rate)
return freq;
for (i = 2; i <= ilog2(M41T80_SQW_MAX_FREQ); i++) {
freq /= 1 << i;
if (freq <= rate)
return freq;
}
return 0;
}
static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
struct i2c_client *client = m41t80->client;
int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
M41T80_REG_WDAY : M41T80_REG_SQW;
int reg, ret, val = 0;
if (rate) {
if (!is_power_of_2(rate))
return -EINVAL;
val = ilog2(rate);
if (val == ilog2(M41T80_SQW_MAX_FREQ))
val = 1;
else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1))
val = ilog2(M41T80_SQW_MAX_FREQ) - val;
else
return -EINVAL;
}
reg = i2c_smbus_read_byte_data(client, reg_sqw);
if (reg < 0)
return reg;
reg = (reg & 0x0f) | (val << 4);
ret = i2c_smbus_write_byte_data(client, reg_sqw, reg);
if (ret < 0)
return ret;
return -EINVAL;
}
static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
{
struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
struct i2c_client *client = m41t80->client;
int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (ret < 0)
return ret;
if (enable)
ret |= M41T80_ALMON_SQWE;
else
ret &= ~M41T80_ALMON_SQWE;
return i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
}
static int m41t80_sqw_prepare(struct clk_hw *hw)
{
return m41t80_sqw_control(hw, 1);
}
static void m41t80_sqw_unprepare(struct clk_hw *hw)
{
m41t80_sqw_control(hw, 0);
}
static int m41t80_sqw_is_prepared(struct clk_hw *hw)
{
struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
struct i2c_client *client = m41t80->client;
int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (ret < 0)
return ret;
return !!(ret & M41T80_ALMON_SQWE);
}
static const struct clk_ops m41t80_sqw_ops = {
.prepare = m41t80_sqw_prepare,
.unprepare = m41t80_sqw_unprepare,
.is_prepared = m41t80_sqw_is_prepared,
.recalc_rate = m41t80_sqw_recalc_rate,
.round_rate = m41t80_sqw_round_rate,
.set_rate = m41t80_sqw_set_rate,
};
static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
{
struct i2c_client *client = m41t80->client;
struct device_node *node = client->dev.of_node;
struct clk *clk;
struct clk_init_data init;
int ret;
/* First disable the clock */
ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (ret < 0)
return ERR_PTR(ret);
ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
ret & ~(M41T80_ALMON_SQWE));
if (ret < 0)
return ERR_PTR(ret);
init.name = "m41t80-sqw";
init.ops = &m41t80_sqw_ops;
init.flags = 0;
init.parent_names = NULL;
init.num_parents = 0;
m41t80->sqw.init = &init;
/* optional override of the clockname */
of_property_read_string(node, "clock-output-names", &init.name);
/* register the clock */
clk = clk_register(&client->dev, &m41t80->sqw);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
return clk;
}
#endif
#ifdef CONFIG_RTC_DRV_M41T80_WDT
/*
*****************************************************************************
@@ -845,6 +939,7 @@ static int m41t80_probe(struct i2c_client *client,
if (!m41t80_data)
return -ENOMEM;
m41t80_data->client = client;
if (client->dev.of_node)
m41t80_data->features = (unsigned long)
of_device_get_match_data(&client->dev);
@@ -936,6 +1031,10 @@ static int m41t80_probe(struct i2c_client *client,
return rc;
}
}
#endif
#ifdef CONFIG_COMMON_CLK
if (m41t80_data->features & M41T80_FEATURE_SQ)
m41t80_sqw_register_clk(m41t80_data);
#endif
return 0;
}
-11
View File
@@ -43,17 +43,6 @@
#define MAX_PIE_NUM 9
#define MAX_PIE_FREQ 512
static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
{ 2, RTC_2HZ_BIT },
{ 4, RTC_SAM0_BIT },
{ 8, RTC_SAM1_BIT },
{ 16, RTC_SAM2_BIT },
{ 32, RTC_SAM3_BIT },
{ 64, RTC_SAM4_BIT },
{ 128, RTC_SAM5_BIT },
{ 256, RTC_SAM6_BIT },
{ MAX_PIE_FREQ, RTC_SAM7_BIT },
};
#define MXC_RTC_TIME 0
#define MXC_RTC_ALARM 1
+1 -1
View File
@@ -93,7 +93,7 @@ static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc)
__raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER);
while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB)
&& timeout--)
&& --timeout)
mdelay(1);
if (!timeout)
+31 -1
View File
@@ -142,6 +142,16 @@ static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
y_m_d = be32_to_cpu(__y_m_d);
h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
/* check if no alarm is set */
if (y_m_d == 0 && h_m_s_ms == 0) {
pr_debug("No alarm is set\n");
rc = -ENOENT;
goto exit;
} else {
pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
}
opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
exit:
@@ -157,7 +167,14 @@ static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
u32 y_m_d = 0;
int token, rc;
tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
/* if alarm is enabled */
if (alarm->enabled) {
tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
} else {
pr_debug("Alarm getting disabled\n");
}
token = opal_async_get_token_interruptible();
if (token < 0) {
@@ -190,6 +207,18 @@ exit:
return rc;
}
int opal_tpo_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct rtc_wkalrm alarm = { .enabled = 0 };
/*
* TPO is automatically enabled when opal_set_tpo_time() is called with
* non-zero rtc-time. We only handle disable case which needs to be
* explicitly told to opal.
*/
return enabled ? 0 : opal_set_tpo_time(dev, &alarm);
}
static struct rtc_class_ops opal_rtc_ops = {
.read_time = opal_get_rtc_time,
.set_time = opal_set_rtc_time,
@@ -205,6 +234,7 @@ static int opal_rtc_probe(struct platform_device *pdev)
device_set_wakeup_capable(&pdev->dev, true);
opal_rtc_ops.read_alarm = opal_get_tpo_time;
opal_rtc_ops.set_alarm = opal_set_tpo_time;
opal_rtc_ops.alarm_irq_enable = opal_tpo_alarm_irq_enable;
}
rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops,
+1 -1
View File
@@ -606,7 +606,7 @@ static int pcf8563_probe(struct i2c_client *client,
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8563_irq,
IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING,
pcf8563->rtc->name, client);
pcf8563_driver.driver.name, client);
if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n",
client->irq);
+29 -43
View File
@@ -68,6 +68,7 @@ struct rv8803_data {
struct mutex flags_lock;
u8 ctrl;
enum rv8803_type type;
struct nvmem_config nvmem_cfg;
};
static int rv8803_read_reg(const struct i2c_client *client, u8 reg)
@@ -460,48 +461,32 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
}
}
static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
static int rv8803_nvram_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct device *dev = kobj_to_dev(kobj);
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = rv8803_write_reg(client, RV8803_RAM, buf[0]);
ret = rv8803_write_reg(priv, RV8803_RAM, *(u8 *)val);
if (ret)
return ret;
return 1;
return 0;
}
static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
static int rv8803_nvram_read(void *priv, unsigned int offset,
void *val, size_t bytes)
{
struct device *dev = kobj_to_dev(kobj);
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = rv8803_read_reg(client, RV8803_RAM);
ret = rv8803_read_reg(priv, RV8803_RAM);
if (ret < 0)
return ret;
buf[0] = ret;
*(u8 *)val = ret;
return 1;
return 0;
}
static struct bin_attribute rv8803_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
},
.size = 1,
.read = rv8803_nvram_read,
.write = rv8803_nvram_write,
};
static struct rtc_class_ops rv8803_rtc_ops = {
.read_time = rv8803_get_time,
.set_time = rv8803_set_time,
@@ -577,6 +562,11 @@ static int rv8803_probe(struct i2c_client *client,
if (flags & RV8803_FLAG_AF)
dev_warn(&client->dev, "An alarm maybe have been missed.\n");
rv8803->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(rv8803->rtc)) {
return PTR_ERR(rv8803->rtc);
}
if (client->irq > 0) {
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv8803_handle_irq,
@@ -592,12 +582,20 @@ static int rv8803_probe(struct i2c_client *client,
}
}
rv8803->rtc = devm_rtc_device_register(&client->dev, client->name,
&rv8803_rtc_ops, THIS_MODULE);
if (IS_ERR(rv8803->rtc)) {
dev_err(&client->dev, "unable to register the class device\n");
return PTR_ERR(rv8803->rtc);
}
rv8803->nvmem_cfg.name = "rv8803_nvram",
rv8803->nvmem_cfg.word_size = 1,
rv8803->nvmem_cfg.stride = 1,
rv8803->nvmem_cfg.size = 1,
rv8803->nvmem_cfg.reg_read = rv8803_nvram_read,
rv8803->nvmem_cfg.reg_write = rv8803_nvram_write,
rv8803->nvmem_cfg.priv = client;
rv8803->rtc->ops = &rv8803_rtc_ops;
rv8803->rtc->nvmem_config = &rv8803->nvmem_cfg;
rv8803->rtc->nvram_old_abi = true;
err = rtc_register_device(rv8803->rtc);
if (err)
return err;
err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
if (err)
@@ -609,22 +607,11 @@ static int rv8803_probe(struct i2c_client *client,
return err;
}
err = device_create_bin_file(&client->dev, &rv8803_nvram_attr);
if (err)
return err;
rv8803->rtc->max_user_freq = 1;
return 0;
}
static int rv8803_remove(struct i2c_client *client)
{
device_remove_bin_file(&client->dev, &rv8803_nvram_attr);
return 0;
}
static const struct i2c_device_id rv8803_id[] = {
{ "rv8803", rv_8803 },
{ "rx8900", rx_8900 },
@@ -651,7 +638,6 @@ static struct i2c_driver rv8803_driver = {
.of_match_table = of_match_ptr(rv8803_of_match),
},
.probe = rv8803_probe,
.remove = rv8803_remove,
.id_table = rv8803_id,
};
module_i2c_driver(rv8803_driver);
+96 -51
View File
@@ -41,7 +41,7 @@ struct s3c_rtc {
struct clk *rtc_src_clk;
bool clk_disabled;
struct s3c_rtc_data *data;
const struct s3c_rtc_data *data;
int irq_alarm;
int irq_tick;
@@ -49,7 +49,8 @@ struct s3c_rtc {
spinlock_t pie_lock;
spinlock_t alarm_clk_lock;
int ticnt_save, ticnt_en_save;
int ticnt_save;
int ticnt_en_save;
bool wake_en;
};
@@ -67,18 +68,32 @@ struct s3c_rtc_data {
void (*disable) (struct s3c_rtc *info);
};
static void s3c_rtc_enable_clk(struct s3c_rtc *info)
static int s3c_rtc_enable_clk(struct s3c_rtc *info)
{
unsigned long irq_flags;
int ret = 0;
spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
if (info->clk_disabled) {
clk_enable(info->rtc_clk);
if (info->data->needs_src_clk)
clk_enable(info->rtc_src_clk);
ret = clk_enable(info->rtc_clk);
if (ret)
goto out;
if (info->data->needs_src_clk) {
ret = clk_enable(info->rtc_src_clk);
if (ret) {
clk_disable(info->rtc_clk);
goto out;
}
}
info->clk_disabled = false;
}
out:
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
return ret;
}
static void s3c_rtc_disable_clk(struct s3c_rtc *info)
@@ -121,10 +136,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
unsigned int tmp;
int ret;
dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
@@ -135,10 +153,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
s3c_rtc_disable_clk(info);
if (enabled)
s3c_rtc_enable_clk(info);
else
if (enabled) {
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
} else {
s3c_rtc_disable_clk(info);
}
return 0;
}
@@ -146,10 +167,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
/* Set RTC frequency */
static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
{
int ret;
if (!is_power_of_2(freq))
return -EINVAL;
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
spin_lock_irq(&info->pie_lock);
if (info->data->set_freq)
@@ -166,10 +191,13 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
unsigned int have_retried = 0;
int ret;
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
retry_get_time:
retry_get_time:
rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN);
rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
@@ -199,8 +227,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
rtc_tm->tm_year += 100;
dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
rtc_tm->tm_mon -= 1;
@@ -211,10 +239,11 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
int year = tm->tm_year - 100;
int ret;
dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
/* we get around y2k by simply not supporting it */
@@ -223,7 +252,9 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
return -EINVAL;
}
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC);
writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
@@ -242,8 +273,11 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct s3c_rtc *info = dev_get_drvdata(dev);
struct rtc_time *alm_tm = &alrm->time;
unsigned int alm_en;
int ret;
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC);
alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN);
@@ -259,9 +293,9 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alm_en,
1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
alm_en,
1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
/* decode the alarm enable field */
if (alm_en & S3C2410_RTCALM_SECEN)
@@ -292,14 +326,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct s3c_rtc *info = dev_get_drvdata(dev);
struct rtc_time *tm = &alrm->time;
unsigned int alrm_en;
int ret;
int year = tm->tm_year - 100;
dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alrm->enabled,
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
alrm->enabled,
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
writeb(0x00, info->base + S3C2410_RTCALM);
@@ -348,8 +385,11 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
int ret;
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
if (info->data->enable_tick)
info->data->enable_tick(info, seq);
@@ -378,8 +418,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
dev_info(info->dev, "rtc disabled, re-enabling\n");
tmp = readw(info->base + S3C2410_RTCCON);
writew(tmp | S3C2410_RTCCON_RTCEN,
info->base + S3C2410_RTCCON);
writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
}
if (con & S3C2410_RTCCON_CNTSEL) {
@@ -387,7 +426,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
tmp = readw(info->base + S3C2410_RTCCON);
writew(tmp & ~S3C2410_RTCCON_CNTSEL,
info->base + S3C2410_RTCCON);
info->base + S3C2410_RTCCON);
}
if (con & S3C2410_RTCCON_CLKRST) {
@@ -395,7 +434,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
tmp = readw(info->base + S3C2410_RTCCON);
writew(tmp & ~S3C2410_RTCCON_CLKRST,
info->base + S3C2410_RTCCON);
info->base + S3C2410_RTCCON);
}
}
@@ -437,12 +476,12 @@ static int s3c_rtc_remove(struct platform_device *pdev)
static const struct of_device_id s3c_rtc_dt_match[];
static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
static const struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
return (struct s3c_rtc_data *)match->data;
return match->data;
}
static int s3c_rtc_probe(struct platform_device *pdev)
@@ -481,7 +520,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
}
dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
info->irq_tick, info->irq_alarm);
info->irq_tick, info->irq_alarm);
/* get the memory region */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -498,7 +537,9 @@ static int s3c_rtc_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
return ret;
}
clk_prepare_enable(info->rtc_clk);
ret = clk_prepare_enable(info->rtc_clk);
if (ret)
return ret;
if (info->data->needs_src_clk) {
info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
@@ -510,10 +551,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
else
dev_dbg(&pdev->dev,
"probe deferred due to missing rtc src clk\n");
clk_disable_unprepare(info->rtc_clk);
return ret;
goto err_src_clk;
}
clk_prepare_enable(info->rtc_src_clk);
ret = clk_prepare_enable(info->rtc_src_clk);
if (ret)
goto err_src_clk;
}
/* check to see if everything is setup correctly */
@@ -521,7 +563,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
info->data->enable(info);
dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
readw(info->base + S3C2410_RTCCON));
readw(info->base + S3C2410_RTCCON));
device_init_wakeup(&pdev->dev, 1);
@@ -541,7 +583,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
/* register RTC and exit */
info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
THIS_MODULE);
THIS_MODULE);
if (IS_ERR(info->rtc)) {
dev_err(&pdev->dev, "cannot attach rtc\n");
ret = PTR_ERR(info->rtc);
@@ -549,14 +591,14 @@ static int s3c_rtc_probe(struct platform_device *pdev)
}
ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
0, "s3c2410-rtc alarm", info);
0, "s3c2410-rtc alarm", info);
if (ret) {
dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
goto err_nortc;
}
ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
0, "s3c2410-rtc tick", info);
0, "s3c2410-rtc tick", info);
if (ret) {
dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
goto err_nortc;
@@ -569,12 +611,13 @@ static int s3c_rtc_probe(struct platform_device *pdev)
return 0;
err_nortc:
err_nortc:
if (info->data->disable)
info->data->disable(info);
if (info->data->needs_src_clk)
clk_disable_unprepare(info->rtc_src_clk);
err_src_clk:
clk_disable_unprepare(info->rtc_clk);
return ret;
@@ -585,8 +628,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
static int s3c_rtc_suspend(struct device *dev)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
int ret;
s3c_rtc_enable_clk(info);
ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
/* save TICNT for anyone using periodic interrupts */
if (info->data->save_tick_cnt)
@@ -747,8 +793,7 @@ static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
writel(info->ticnt_save, info->base + S3C2410_TICNT);
if (info->ticnt_en_save) {
con = readw(info->base + S3C2410_RTCCON);
writew(con | info->ticnt_en_save,
info->base + S3C2410_RTCCON);
writew(con | info->ticnt_en_save, info->base + S3C2410_RTCCON);
}
}
@@ -802,19 +847,19 @@ static struct s3c_rtc_data const s3c6410_rtc_data = {
static const struct of_device_id s3c_rtc_dt_match[] = {
{
.compatible = "samsung,s3c2410-rtc",
.data = (void *)&s3c2410_rtc_data,
.data = &s3c2410_rtc_data,
}, {
.compatible = "samsung,s3c2416-rtc",
.data = (void *)&s3c2416_rtc_data,
.data = &s3c2416_rtc_data,
}, {
.compatible = "samsung,s3c2443-rtc",
.data = (void *)&s3c2443_rtc_data,
.data = &s3c2443_rtc_data,
}, {
.compatible = "samsung,s3c6410-rtc",
.data = (void *)&s3c6410_rtc_data,
.data = &s3c6410_rtc_data,
}, {
.compatible = "samsung,exynos3250-rtc",
.data = (void *)&s3c6410_rtc_data,
.data = &s3c6410_rtc_data,
},
{ /* sentinel */ },
};
+8 -11
View File
@@ -99,7 +99,7 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
lpt = ((unsigned long long)lpt_msb << 32) | lpt_lsb;
do_div(lpt, rtc->clkrate);
rtc_time_to_tm(lpt, tm);
rtc_time64_to_tm(lpt, tm);
return 0;
}
@@ -107,13 +107,10 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int st_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct st_rtc *rtc = dev_get_drvdata(dev);
unsigned long long lpt;
unsigned long secs, flags;
int ret;
unsigned long long lpt, secs;
unsigned long flags;
ret = rtc_tm_to_time(tm, &secs);
if (ret)
return ret;
secs = rtc_tm_to_time64(tm);
lpt = (unsigned long long)secs * rtc->clkrate;
@@ -161,13 +158,13 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct st_rtc *rtc = dev_get_drvdata(dev);
struct rtc_time now;
unsigned long now_secs;
unsigned long alarm_secs;
unsigned long long now_secs;
unsigned long long alarm_secs;
unsigned long long lpa;
st_rtc_read_time(dev, &now);
rtc_tm_to_time(&now, &now_secs);
rtc_tm_to_time(&t->time, &alarm_secs);
now_secs = rtc_tm_to_time64(&now);
alarm_secs = rtc_tm_to_time64(&t->time);
/* Invalid alarm time */
if (now_secs > alarm_secs)

Some files were not shown because too many files have changed in this diff Show More