You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'rtc-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni:
"This contains a few series that have been in preparation for a while
and that will help systems with RTCs that will fail in 2038, 2069 or
2100.
Subsystem:
- Add tracepoints
- Rework of the RTC/nvmem API to allow drivers to discard struct
nvmem_config after registration
- New range API, drivers can now expose the useful range of the RTC
- New offset API the core is now able to add an offset to the RTC
time, modifying the supported range.
- Multiple rtc_time64_to_tm fixes
- Handle time_t overflow on 32 bit platforms in the core instead of
letting drivers do crazy things.
- remove rtc_control API
New driver:
- Intersil ISL12026
Drivers:
- Drivers exposing the RTC non volatile memory have been converted to
use nvmem
- Removed useless time and date validation
- Removed an indirection pattern that was a cargo cult from ancient
drivers
- Removed VLA usage
- Fixed a possible race condition in probe functions
- AB8540 support is dropped from ab8500
- pcf85363 now has alarm support"
* tag 'rtc-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (128 commits)
rtc: snvs: Fix usage of snvs_rtc_enable
rtc: mt7622: fix module autoloading for OF platform drivers
rtc: isl12022: use true and false for boolean values
rtc: ab8500: Drop AB8540 support
rtc: remove a warning during scripts/kernel-doc step
rtc: 88pm860x: remove artificial limitation
rtc: 88pm80x: remove artificial limitation
rtc: st-lpc: remove artificial limitation
rtc: mrst: remove artificial limitation
rtc: mv: remove artificial limitation
rtc: hctosys: Ensure system time doesn't overflow time_t
parisc: time: stop validating rtc_time in .read_time
rtc: pcf85063: fix clearing bits in pcf85063_start_clock
rtc: at91sam9: Set name of regmap_config
rtc: s5m: Remove VLA usage
rtc: s5m: Move enum from rtc.h to rtc-s5m.c
rtc: remove VLA usage
rtc: Add useful timestamp definitions
rtc: Add one offset seconds to expand RTC range
rtc: Factor out the RTC range validation into rtc_valid_range()
...
This commit is contained in:
@@ -43,6 +43,14 @@ Contact: linux-rtc@vger.kernel.org
|
||||
Description:
|
||||
(RO) The name of the RTC corresponding to this sysfs directory
|
||||
|
||||
What: /sys/class/rtc/rtcX/range
|
||||
Date: January 2018
|
||||
KernelVersion: 4.16
|
||||
Contact: linux-rtc@vger.kernel.org
|
||||
Description:
|
||||
Valid time range for the RTC, as seconds from epoch, formatted
|
||||
as [min, max]
|
||||
|
||||
What: /sys/class/rtc/rtcX/since_epoch
|
||||
Date: March 2006
|
||||
KernelVersion: 2.6.17
|
||||
@@ -57,14 +65,6 @@ Contact: linux-rtc@vger.kernel.org
|
||||
Description:
|
||||
(RO) RTC-provided time in 24-hour notation (hh:mm:ss)
|
||||
|
||||
What: /sys/class/rtc/rtcX/*/nvmem
|
||||
Date: February 2016
|
||||
KernelVersion: 4.6
|
||||
Contact: linux-rtc@vger.kernel.org
|
||||
Description:
|
||||
(RW) The non volatile storage exported as a raw file, as
|
||||
described in Documentation/nvmem/nvmem.txt
|
||||
|
||||
What: /sys/class/rtc/rtcX/offset
|
||||
Date: February 2016
|
||||
KernelVersion: 4.6
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
ISL12026 I2C RTC/EEPROM
|
||||
|
||||
ISL12026 is an I2C RTC/EEPROM combination device. The RTC and control
|
||||
registers respond at bus address 0x6f, and the EEPROM array responds
|
||||
at bus address 0x57. The canonical "reg" value will be for the RTC portion.
|
||||
|
||||
Required properties supported by the device:
|
||||
|
||||
- "compatible": must be "isil,isl12026"
|
||||
- "reg": I2C bus address of the device (always 0x6f)
|
||||
|
||||
Optional properties:
|
||||
|
||||
- "isil,pwr-bsw": If present PWR.BSW bit must be set to the specified
|
||||
value for proper operation.
|
||||
|
||||
- "isil,pwr-sbib": If present PWR.SBIB bit must be set to the specified
|
||||
value for proper operation.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
rtc@6f {
|
||||
compatible = "isil,isl12026";
|
||||
reg = <0x6f>;
|
||||
isil,pwr-bsw = <0>;
|
||||
isil,pwr-sbib = <1>;
|
||||
}
|
||||
+1
-1
@@ -11810,7 +11810,7 @@ X: kernel/torture.c
|
||||
|
||||
REAL TIME CLOCK (RTC) SUBSYSTEM
|
||||
M: Alessandro Zummo <a.zummo@towertech.it>
|
||||
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
M: Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
L: linux-rtc@vger.kernel.org
|
||||
Q: http://patchwork.ozlabs.org/project/rtc-linux/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
|
||||
|
||||
@@ -174,7 +174,7 @@ static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
/* we treat tod_sec as unsigned, so this can work until year 2106 */
|
||||
rtc_time64_to_tm(tod_data.tod_sec, tm);
|
||||
return rtc_valid_tm(tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
@@ -809,89 +809,6 @@ static __poll_t rtc_poll(struct file *file, poll_table *wait)
|
||||
}
|
||||
#endif
|
||||
|
||||
int rtc_register(rtc_task_t *task)
|
||||
{
|
||||
#ifndef RTC_IRQ
|
||||
return -EIO;
|
||||
#else
|
||||
if (task == NULL || task->func == NULL)
|
||||
return -EINVAL;
|
||||
spin_lock_irq(&rtc_lock);
|
||||
if (rtc_status & RTC_IS_OPEN) {
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
spin_lock(&rtc_task_lock);
|
||||
if (rtc_callback) {
|
||||
spin_unlock(&rtc_task_lock);
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
rtc_status |= RTC_IS_OPEN;
|
||||
rtc_callback = task;
|
||||
spin_unlock(&rtc_task_lock);
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(rtc_register);
|
||||
|
||||
int rtc_unregister(rtc_task_t *task)
|
||||
{
|
||||
#ifndef RTC_IRQ
|
||||
return -EIO;
|
||||
#else
|
||||
unsigned char tmp;
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
spin_lock(&rtc_task_lock);
|
||||
if (rtc_callback != task) {
|
||||
spin_unlock(&rtc_task_lock);
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
return -ENXIO;
|
||||
}
|
||||
rtc_callback = NULL;
|
||||
|
||||
/* disable controls */
|
||||
if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
|
||||
tmp = CMOS_READ(RTC_CONTROL);
|
||||
tmp &= ~RTC_PIE;
|
||||
tmp &= ~RTC_AIE;
|
||||
tmp &= ~RTC_UIE;
|
||||
CMOS_WRITE(tmp, RTC_CONTROL);
|
||||
CMOS_READ(RTC_INTR_FLAGS);
|
||||
}
|
||||
if (rtc_status & RTC_TIMER_ON) {
|
||||
rtc_status &= ~RTC_TIMER_ON;
|
||||
del_timer(&rtc_irq_timer);
|
||||
}
|
||||
rtc_status &= ~RTC_IS_OPEN;
|
||||
spin_unlock(&rtc_task_lock);
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(rtc_unregister);
|
||||
|
||||
int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
#ifndef RTC_IRQ
|
||||
return -EIO;
|
||||
#else
|
||||
unsigned long flags;
|
||||
if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
|
||||
return -EINVAL;
|
||||
spin_lock_irqsave(&rtc_task_lock, flags);
|
||||
if (rtc_callback != task) {
|
||||
spin_unlock_irqrestore(&rtc_task_lock, flags);
|
||||
return -ENXIO;
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc_task_lock, flags);
|
||||
return rtc_do_ioctl(cmd, arg, 1);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(rtc_control);
|
||||
|
||||
/*
|
||||
* The various file operations we support.
|
||||
*/
|
||||
|
||||
+12
-1
@@ -407,6 +407,16 @@ config RTC_DRV_ISL12022
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-isl12022.
|
||||
|
||||
config RTC_DRV_ISL12026
|
||||
tristate "Intersil ISL12026"
|
||||
depends on OF || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for the
|
||||
Intersil ISL12026 RTC chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-isl12026.
|
||||
|
||||
config RTC_DRV_X1205
|
||||
tristate "Xicor/Intersil X1205"
|
||||
help
|
||||
@@ -1413,6 +1423,7 @@ config RTC_DRV_AT91RM9200
|
||||
config RTC_DRV_AT91SAM9
|
||||
tristate "AT91SAM9 RTT as RTC"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which
|
||||
@@ -1502,7 +1513,7 @@ config RTC_DRV_STARFIRE
|
||||
|
||||
config RTC_DRV_TX4939
|
||||
tristate "TX4939 SoC"
|
||||
depends on SOC_TX4939
|
||||
depends on SOC_TX4939 || COMPILE_TEST
|
||||
help
|
||||
Driver for the internal RTC (Realtime Clock) module found on
|
||||
Toshiba TX4939 SoC.
|
||||
|
||||
@@ -75,6 +75,7 @@ obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
|
||||
obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o
|
||||
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
|
||||
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
|
||||
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
|
||||
|
||||
+73
-4
@@ -211,6 +211,73 @@ static int rtc_device_get_id(struct device *dev)
|
||||
return id;
|
||||
}
|
||||
|
||||
static void rtc_device_get_offset(struct rtc_device *rtc)
|
||||
{
|
||||
time64_t range_secs;
|
||||
u32 start_year;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If RTC driver did not implement the range of RTC hardware device,
|
||||
* then we can not expand the RTC range by adding or subtracting one
|
||||
* offset.
|
||||
*/
|
||||
if (rtc->range_min == rtc->range_max)
|
||||
return;
|
||||
|
||||
ret = device_property_read_u32(rtc->dev.parent, "start-year",
|
||||
&start_year);
|
||||
if (!ret) {
|
||||
rtc->start_secs = mktime64(start_year, 1, 1, 0, 0, 0);
|
||||
rtc->set_start_time = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If user did not implement the start time for RTC driver, then no
|
||||
* need to expand the RTC range.
|
||||
*/
|
||||
if (!rtc->set_start_time)
|
||||
return;
|
||||
|
||||
range_secs = rtc->range_max - rtc->range_min + 1;
|
||||
|
||||
/*
|
||||
* If the start_secs is larger than the maximum seconds (rtc->range_max)
|
||||
* supported by RTC hardware or the maximum seconds of new expanded
|
||||
* range (start_secs + rtc->range_max - rtc->range_min) is less than
|
||||
* rtc->range_min, which means the minimum seconds (rtc->range_min) of
|
||||
* RTC hardware will be mapped to start_secs by adding one offset, so
|
||||
* the offset seconds calculation formula should be:
|
||||
* rtc->offset_secs = rtc->start_secs - rtc->range_min;
|
||||
*
|
||||
* If the start_secs is larger than the minimum seconds (rtc->range_min)
|
||||
* supported by RTC hardware, then there is one region is overlapped
|
||||
* between the original RTC hardware range and the new expanded range,
|
||||
* and this overlapped region do not need to be mapped into the new
|
||||
* expanded range due to it is valid for RTC device. So the minimum
|
||||
* seconds of RTC hardware (rtc->range_min) should be mapped to
|
||||
* rtc->range_max + 1, then the offset seconds formula should be:
|
||||
* rtc->offset_secs = rtc->range_max - rtc->range_min + 1;
|
||||
*
|
||||
* If the start_secs is less than the minimum seconds (rtc->range_min),
|
||||
* which is similar to case 2. So the start_secs should be mapped to
|
||||
* start_secs + rtc->range_max - rtc->range_min + 1, then the
|
||||
* offset seconds formula should be:
|
||||
* rtc->offset_secs = -(rtc->range_max - rtc->range_min + 1);
|
||||
*
|
||||
* Otherwise the offset seconds should be 0.
|
||||
*/
|
||||
if (rtc->start_secs > rtc->range_max ||
|
||||
rtc->start_secs + range_secs - 1 < rtc->range_min)
|
||||
rtc->offset_secs = rtc->start_secs - rtc->range_min;
|
||||
else if (rtc->start_secs > rtc->range_min)
|
||||
rtc->offset_secs = range_secs;
|
||||
else if (rtc->start_secs < rtc->range_min)
|
||||
rtc->offset_secs = -range_secs;
|
||||
else
|
||||
rtc->offset_secs = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rtc_device_register - register w/ RTC class
|
||||
* @dev: the device to register
|
||||
@@ -247,6 +314,8 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
||||
|
||||
dev_set_name(&rtc->dev, "rtc%d", id);
|
||||
|
||||
rtc_device_get_offset(rtc);
|
||||
|
||||
/* Check to see if there is an ALARM already set in hw */
|
||||
err = __rtc_read_alarm(rtc, &alrm);
|
||||
|
||||
@@ -293,8 +362,6 @@ 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
|
||||
@@ -312,6 +379,7 @@ static void devm_rtc_device_release(struct device *dev, void *res)
|
||||
{
|
||||
struct rtc_device *rtc = *(struct rtc_device **)res;
|
||||
|
||||
rtc_nvmem_unregister(rtc);
|
||||
rtc_device_unregister(rtc);
|
||||
}
|
||||
|
||||
@@ -382,6 +450,8 @@ static void devm_rtc_release_device(struct device *dev, void *res)
|
||||
{
|
||||
struct rtc_device *rtc = *(struct rtc_device **)res;
|
||||
|
||||
rtc_nvmem_unregister(rtc);
|
||||
|
||||
if (rtc->registered)
|
||||
rtc_device_unregister(rtc);
|
||||
else
|
||||
@@ -435,6 +505,7 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
|
||||
return -EINVAL;
|
||||
|
||||
rtc->owner = owner;
|
||||
rtc_device_get_offset(rtc);
|
||||
|
||||
/* Check to see if there is an ALARM already set in hw */
|
||||
err = __rtc_read_alarm(rtc, &alrm);
|
||||
@@ -453,8 +524,6 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
|
||||
|
||||
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));
|
||||
|
||||
@@ -49,6 +49,11 @@ static int __init rtc_hctosys(void)
|
||||
|
||||
tv64.tv_sec = rtc_tm_to_time64(&tm);
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
if (tv64.tv_sec > INT_MAX)
|
||||
goto err_read;
|
||||
#endif
|
||||
|
||||
err = do_settimeofday64(&tv64);
|
||||
|
||||
dev_info(rtc->dev.parent,
|
||||
|
||||
@@ -17,9 +17,73 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/rtc.h>
|
||||
|
||||
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
|
||||
static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
|
||||
|
||||
static void rtc_add_offset(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
{
|
||||
time64_t secs;
|
||||
|
||||
if (!rtc->offset_secs)
|
||||
return;
|
||||
|
||||
secs = rtc_tm_to_time64(tm);
|
||||
|
||||
/*
|
||||
* Since the reading time values from RTC device are always in the RTC
|
||||
* original valid range, but we need to skip the overlapped region
|
||||
* between expanded range and original range, which is no need to add
|
||||
* the offset.
|
||||
*/
|
||||
if ((rtc->start_secs > rtc->range_min && secs >= rtc->start_secs) ||
|
||||
(rtc->start_secs < rtc->range_min &&
|
||||
secs <= (rtc->start_secs + rtc->range_max - rtc->range_min)))
|
||||
return;
|
||||
|
||||
rtc_time64_to_tm(secs + rtc->offset_secs, tm);
|
||||
}
|
||||
|
||||
static void rtc_subtract_offset(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
{
|
||||
time64_t secs;
|
||||
|
||||
if (!rtc->offset_secs)
|
||||
return;
|
||||
|
||||
secs = rtc_tm_to_time64(tm);
|
||||
|
||||
/*
|
||||
* If the setting time values are in the valid range of RTC hardware
|
||||
* device, then no need to subtract the offset when setting time to RTC
|
||||
* device. Otherwise we need to subtract the offset to make the time
|
||||
* values are valid for RTC hardware device.
|
||||
*/
|
||||
if (secs >= rtc->range_min && secs <= rtc->range_max)
|
||||
return;
|
||||
|
||||
rtc_time64_to_tm(secs - rtc->offset_secs, tm);
|
||||
}
|
||||
|
||||
static int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
{
|
||||
if (rtc->range_min != rtc->range_max) {
|
||||
time64_t time = rtc_tm_to_time64(tm);
|
||||
time64_t range_min = rtc->set_start_time ? rtc->start_secs :
|
||||
rtc->range_min;
|
||||
time64_t range_max = rtc->set_start_time ?
|
||||
(rtc->start_secs + rtc->range_max - rtc->range_min) :
|
||||
rtc->range_max;
|
||||
|
||||
if (time < range_min || time > range_max)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
{
|
||||
int err;
|
||||
@@ -36,6 +100,8 @@ static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
return err;
|
||||
}
|
||||
|
||||
rtc_add_offset(rtc, tm);
|
||||
|
||||
err = rtc_valid_tm(tm);
|
||||
if (err < 0)
|
||||
dev_dbg(&rtc->dev, "read_time: rtc_time isn't valid\n");
|
||||
@@ -53,6 +119,8 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
|
||||
err = __rtc_read_time(rtc, tm);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
trace_rtc_read_time(rtc_tm_to_time64(tm), err);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_read_time);
|
||||
@@ -65,6 +133,12 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
err = rtc_valid_range(rtc, tm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rtc_subtract_offset(rtc, tm);
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -87,6 +161,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
/* A timer might have just expired */
|
||||
schedule_work(&rtc->irqwork);
|
||||
|
||||
trace_rtc_set_time(rtc_tm_to_time64(tm), err);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_set_time);
|
||||
@@ -119,6 +195,8 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
|
||||
}
|
||||
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -316,6 +394,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
}
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_read_alarm);
|
||||
@@ -329,6 +408,8 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
err = rtc_valid_tm(&alarm->time);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rtc_subtract_offset(rtc, &alarm->time);
|
||||
scheduled = rtc_tm_to_time64(&alarm->time);
|
||||
|
||||
/* Make sure we're not setting alarms in the past */
|
||||
@@ -352,6 +433,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
else
|
||||
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
|
||||
|
||||
trace_rtc_set_alarm(rtc_tm_to_time64(&alarm->time), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -363,6 +445,10 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
err = rtc_valid_range(rtc, &alarm->time);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -375,6 +461,8 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
|
||||
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
rtc_add_offset(rtc, &alarm->time);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_set_alarm);
|
||||
@@ -406,6 +494,7 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
|
||||
rtc->aie_timer.enabled = 1;
|
||||
timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
|
||||
trace_rtc_timer_enqueue(&rtc->aie_timer);
|
||||
}
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return err;
|
||||
@@ -435,6 +524,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
||||
err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
|
||||
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
trace_rtc_alarm_irq_enable(enabled, err);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
|
||||
@@ -709,6 +800,8 @@ retry:
|
||||
rtc->pie_enabled = enabled;
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
|
||||
trace_rtc_irq_set_state(enabled, err);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
|
||||
@@ -745,6 +838,8 @@ retry:
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
|
||||
trace_rtc_irq_set_freq(freq, err);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
|
||||
@@ -779,6 +874,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
}
|
||||
|
||||
timerqueue_add(&rtc->timerqueue, &timer->node);
|
||||
trace_rtc_timer_enqueue(timer);
|
||||
if (!next || ktime_before(timer->node.expires, next->expires)) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
@@ -790,6 +886,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
schedule_work(&rtc->irqwork);
|
||||
} else if (err) {
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
trace_rtc_timer_dequeue(timer);
|
||||
timer->enabled = 0;
|
||||
return err;
|
||||
}
|
||||
@@ -803,6 +900,7 @@ static void rtc_alarm_disable(struct rtc_device *rtc)
|
||||
return;
|
||||
|
||||
rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
|
||||
trace_rtc_alarm_irq_enable(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -821,6 +919,7 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
{
|
||||
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
trace_rtc_timer_dequeue(timer);
|
||||
timer->enabled = 0;
|
||||
if (next == &timer->node) {
|
||||
struct rtc_wkalrm alarm;
|
||||
@@ -871,16 +970,19 @@ again:
|
||||
/* expire timer */
|
||||
timer = container_of(next, struct rtc_timer, node);
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
trace_rtc_timer_dequeue(timer);
|
||||
timer->enabled = 0;
|
||||
if (timer->task.func)
|
||||
timer->task.func(timer->task.private_data);
|
||||
|
||||
trace_rtc_timer_fired(timer);
|
||||
/* Re-add/fwd periodic timers */
|
||||
if (ktime_to_ns(timer->period)) {
|
||||
timer->node.expires = ktime_add(timer->node.expires,
|
||||
timer->period);
|
||||
timer->enabled = 1;
|
||||
timerqueue_add(&rtc->timerqueue, &timer->node);
|
||||
trace_rtc_timer_enqueue(timer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,6 +1004,7 @@ reprogram:
|
||||
|
||||
timer = container_of(next, struct rtc_timer, node);
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
trace_rtc_timer_dequeue(timer);
|
||||
timer->enabled = 0;
|
||||
dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err);
|
||||
goto again;
|
||||
@@ -992,6 +1095,8 @@ int rtc_read_offset(struct rtc_device *rtc, long *offset)
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
ret = rtc->ops->read_offset(rtc->dev.parent, offset);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
trace_rtc_read_offset(*offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1025,5 +1130,7 @@ int rtc_set_offset(struct rtc_device *rtc, long offset)
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
ret = rtc->ops->set_offset(rtc->dev.parent, offset);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
trace_rtc_set_offset(offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+17
-12
@@ -14,8 +14,6 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include "rtc-core.h"
|
||||
|
||||
/*
|
||||
* Deprecated ABI compatibility, this should be removed at some point
|
||||
*/
|
||||
@@ -46,7 +44,7 @@ rtc_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
return nvmem_device_write(rtc->nvmem, off, count, buf);
|
||||
}
|
||||
|
||||
static int rtc_nvram_register(struct rtc_device *rtc)
|
||||
static int rtc_nvram_register(struct rtc_device *rtc, size_t size)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -64,7 +62,7 @@ static int rtc_nvram_register(struct rtc_device *rtc)
|
||||
|
||||
rtc->nvram->read = rtc_nvram_read;
|
||||
rtc->nvram->write = rtc_nvram_write;
|
||||
rtc->nvram->size = rtc->nvmem_config->size;
|
||||
rtc->nvram->size = size;
|
||||
|
||||
err = sysfs_create_bin_file(&rtc->dev.parent->kobj,
|
||||
rtc->nvram);
|
||||
@@ -84,21 +82,28 @@ static void rtc_nvram_unregister(struct rtc_device *rtc)
|
||||
/*
|
||||
* New ABI, uses nvmem
|
||||
*/
|
||||
void rtc_nvmem_register(struct rtc_device *rtc)
|
||||
int rtc_nvmem_register(struct rtc_device *rtc,
|
||||
struct nvmem_config *nvmem_config)
|
||||
{
|
||||
if (!rtc->nvmem_config)
|
||||
return;
|
||||
if (!IS_ERR_OR_NULL(rtc->nvmem))
|
||||
return -EBUSY;
|
||||
|
||||
rtc->nvmem_config->dev = &rtc->dev;
|
||||
rtc->nvmem_config->owner = rtc->owner;
|
||||
rtc->nvmem = nvmem_register(rtc->nvmem_config);
|
||||
if (!nvmem_config)
|
||||
return -ENODEV;
|
||||
|
||||
nvmem_config->dev = rtc->dev.parent;
|
||||
nvmem_config->owner = rtc->owner;
|
||||
rtc->nvmem = nvmem_register(nvmem_config);
|
||||
if (IS_ERR_OR_NULL(rtc->nvmem))
|
||||
return;
|
||||
return PTR_ERR(rtc->nvmem);
|
||||
|
||||
/* Register the old ABI */
|
||||
if (rtc->nvram_old_abi)
|
||||
rtc_nvram_register(rtc);
|
||||
rtc_nvram_register(rtc, nvmem_config->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_nvmem_register);
|
||||
|
||||
void rtc_nvmem_unregister(struct rtc_device *rtc)
|
||||
{
|
||||
|
||||
@@ -134,9 +134,9 @@ static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
struct pm80x_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned char buf[4];
|
||||
unsigned long ticks, base, data;
|
||||
if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
|
||||
if (tm->tm_year > 206) {
|
||||
dev_dbg(info->dev,
|
||||
"Set time %d out of range. Please set time between 1970 to 2038.\n",
|
||||
"Set time %d out of range. Please set time between 1970 to 2106.\n",
|
||||
1900 + tm->tm_year);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -135,9 +135,9 @@ static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
unsigned char buf[4];
|
||||
unsigned long ticks, base, data;
|
||||
|
||||
if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
|
||||
if (tm->tm_year > 206) {
|
||||
dev_dbg(info->dev, "Set time %d out of range. "
|
||||
"Please set time between 1970 to 2038.\n",
|
||||
"Please set time between 1970 to 2106.\n",
|
||||
1900 + tm->tm_year);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
|
||||
u8 regs[ABB5ZES3_REG_RTC_SC + ABB5ZES3_RTC_SEC_LEN];
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* As we need to read CTRL1 register anyway to access 24/12h
|
||||
@@ -255,8 +255,6 @@ static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
tm->tm_mon = bcd2bin(regs[ABB5ZES3_REG_RTC_MO]) - 1; /* starts at 1 */
|
||||
tm->tm_year = bcd2bin(regs[ABB5ZES3_REG_RTC_YR]) + 100;
|
||||
|
||||
ret = rtc_valid_tm(tm);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
rtc_time64_to_tm(time, tm);
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
|
||||
@@ -36,10 +36,6 @@
|
||||
#define AB8500_RTC_FORCE_BKUP_REG 0x0D
|
||||
#define AB8500_RTC_CALIB_REG 0x0E
|
||||
#define AB8500_RTC_SWITCH_STAT_REG 0x0F
|
||||
#define AB8540_RTC_ALRM_SEC 0x22
|
||||
#define AB8540_RTC_ALRM_MIN_LOW_REG 0x23
|
||||
#define AB8540_RTC_ALRM_MIN_MID_REG 0x24
|
||||
#define AB8540_RTC_ALRM_MIN_HI_REG 0x25
|
||||
|
||||
/* RtcReadRequest bits */
|
||||
#define RTC_READ_REQUEST 0x01
|
||||
@@ -63,11 +59,6 @@ static const u8 ab8500_rtc_alarm_regs[] = {
|
||||
AB8500_RTC_ALRM_MIN_LOW_REG
|
||||
};
|
||||
|
||||
static const u8 ab8540_rtc_alarm_regs[] = {
|
||||
AB8540_RTC_ALRM_MIN_HI_REG, AB8540_RTC_ALRM_MIN_MID_REG,
|
||||
AB8540_RTC_ALRM_MIN_LOW_REG, AB8540_RTC_ALRM_SEC
|
||||
};
|
||||
|
||||
/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
|
||||
static unsigned long get_elapsed_seconds(int year)
|
||||
{
|
||||
@@ -131,7 +122,7 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
rtc_time_to_tm(secs, tm);
|
||||
return rtc_valid_tm(tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
@@ -277,43 +268,6 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
return ab8500_rtc_irq_enable(dev, alarm->enabled);
|
||||
}
|
||||
|
||||
static int ab8540_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int retval, i;
|
||||
unsigned char buf[ARRAY_SIZE(ab8540_rtc_alarm_regs)];
|
||||
unsigned long mins, secs = 0;
|
||||
|
||||
if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
|
||||
dev_dbg(dev, "year should be equal to or greater than %d\n",
|
||||
AB8500_RTC_EPOCH);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the number of seconds since 1970 */
|
||||
rtc_tm_to_time(&alarm->time, &secs);
|
||||
|
||||
/*
|
||||
* Convert it to the number of seconds since 01-01-2000 00:00:00
|
||||
*/
|
||||
secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
mins = secs / 60;
|
||||
|
||||
buf[3] = secs % 60;
|
||||
buf[2] = mins & 0xFF;
|
||||
buf[1] = (mins >> 8) & 0xFF;
|
||||
buf[0] = (mins >> 16) & 0xFF;
|
||||
|
||||
/* Set the alarm time */
|
||||
for (i = 0; i < ARRAY_SIZE(ab8540_rtc_alarm_regs); i++) {
|
||||
retval = abx500_set_register_interruptible(dev, AB8500_RTC,
|
||||
ab8540_rtc_alarm_regs[i], buf[i]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
return ab8500_rtc_irq_enable(dev, alarm->enabled);
|
||||
}
|
||||
|
||||
static int ab8500_rtc_set_calibration(struct device *dev, int calibration)
|
||||
{
|
||||
int retval;
|
||||
@@ -435,17 +389,8 @@ static const struct rtc_class_ops ab8500_rtc_ops = {
|
||||
.alarm_irq_enable = ab8500_rtc_irq_enable,
|
||||
};
|
||||
|
||||
static const struct rtc_class_ops ab8540_rtc_ops = {
|
||||
.read_time = ab8500_rtc_read_time,
|
||||
.set_time = ab8500_rtc_set_time,
|
||||
.read_alarm = ab8500_rtc_read_alarm,
|
||||
.set_alarm = ab8540_rtc_set_alarm,
|
||||
.alarm_irq_enable = ab8500_rtc_irq_enable,
|
||||
};
|
||||
|
||||
static const struct platform_device_id ab85xx_rtc_ids[] = {
|
||||
{ "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, },
|
||||
{ "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids);
|
||||
|
||||
@@ -172,11 +172,7 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
tm->tm_mon = bcd2bin(buf[ABX8XX_REG_MO] & 0x1F) - 1;
|
||||
tm->tm_year = bcd2bin(buf[ABX8XX_REG_YR]) + 100;
|
||||
|
||||
err = rtc_valid_tm(tm);
|
||||
if (err < 0)
|
||||
dev_err(&client->dev, "retrieved date/time is not valid.\n");
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
+24
-2
@@ -183,7 +183,29 @@ static int ac100_clkout_determine_rate(struct clk_hw *hw,
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
|
||||
unsigned long tmp, prate = clk_hw_get_rate(parent);
|
||||
unsigned long tmp, prate;
|
||||
|
||||
/*
|
||||
* The clock has two parents, one is a fixed clock which is
|
||||
* internally registered by the ac100 driver. The other parent
|
||||
* is a clock from the codec side of the chip, which we
|
||||
* properly declare and reference in the devicetree and is
|
||||
* not implemented in any driver right now.
|
||||
* If the clock core looks for the parent of that second
|
||||
* missing clock, it can't find one that is registered and
|
||||
* returns NULL.
|
||||
* So we end up in a situation where clk_hw_get_num_parents
|
||||
* returns the amount of clocks we can be parented to, but
|
||||
* clk_hw_get_parent_by_index will not return the orphan
|
||||
* clocks.
|
||||
* Thus we need to check if the parent exists before
|
||||
* we get the parent rate, so we could use the RTC
|
||||
* without waiting for the codec to be supported.
|
||||
*/
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
prate = clk_hw_get_rate(parent);
|
||||
|
||||
tmp = ac100_clkout_round_rate(hw, req->rate, prate);
|
||||
|
||||
@@ -387,7 +409,7 @@ static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
|
||||
rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK) +
|
||||
AC100_YEAR_OFF;
|
||||
|
||||
return rtc_valid_tm(rtc_tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac100_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
|
||||
|
||||
@@ -349,6 +349,7 @@ static const struct rtc_class_ops at91_rtc_ops = {
|
||||
};
|
||||
|
||||
static const struct regmap_config gpbr_regmap_config = {
|
||||
.name = "gpbr",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
|
||||
@@ -36,7 +36,7 @@ static int au1xtoy_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
rtc_time_to_tm(t, tm);
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xtoy_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user