mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-21 03:33:59 +08:00
023f333a99
The purpose of this option is to allow ARM/etc systems that rely on the class RTC subsystem to have the same kind of automatic NTP based synchronization that we have on PC platforms. Today ARM does not implement update_persistent_clock and makes extensive use of the class RTC system. When enabled CONFIG_RTC_SYSTOHC will provide a generic rtc_update_persistent_clock that stores the current time in the RTC and is intended complement the existing CONFIG_RTC_HCTOSYS option that loads the RTC at boot. Like with RTC_HCTOSYS the platform's update_persistent_clock is used first, if it works. Platforms with mixed class RTC and non-RTC drivers need to return ENODEV when class RTC should be used. Such an update for PPC is included in this patch. Long term, implementations of update_persistent_clock should migrate to proper class RTC drivers and use CONFIG_RTC_SYSTOHC instead. Tested on ARM kirkwood and PPC405 Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: John Stultz <john.stultz@linaro.org>
195 lines
6.2 KiB
C
195 lines
6.2 KiB
C
/*
|
|
* Generic RTC interface.
|
|
* This version contains the part of the user interface to the Real Time Clock
|
|
* service. It is used with both the legacy mc146818 and also EFI
|
|
* Struct rtc_time and first 12 ioctl by Paul Gortmaker, 1996 - separated out
|
|
* from <linux/mc146818rtc.h> to this file for 2.4 kernels.
|
|
*
|
|
* Copyright (C) 1999 Hewlett-Packard Co.
|
|
* Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
|
|
*/
|
|
#ifndef _LINUX_RTC_H_
|
|
#define _LINUX_RTC_H_
|
|
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/interrupt.h>
|
|
#include <uapi/linux/rtc.h>
|
|
|
|
extern int rtc_month_days(unsigned int month, unsigned int year);
|
|
extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year);
|
|
extern int rtc_valid_tm(struct rtc_time *tm);
|
|
extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
|
|
extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
|
|
ktime_t rtc_tm_to_ktime(struct rtc_time tm);
|
|
struct rtc_time rtc_ktime_to_tm(ktime_t kt);
|
|
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/timerqueue.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
extern struct class *rtc_class;
|
|
|
|
/*
|
|
* For these RTC methods the device parameter is the physical device
|
|
* on whatever bus holds the hardware (I2C, Platform, SPI, etc), which
|
|
* was passed to rtc_device_register(). Its driver_data normally holds
|
|
* device state, including the rtc_device pointer for the RTC.
|
|
*
|
|
* Most of these methods are called with rtc_device.ops_lock held,
|
|
* through the rtc_*(struct rtc_device *, ...) calls.
|
|
*
|
|
* The (current) exceptions are mostly filesystem hooks:
|
|
* - the proc() hook for procfs
|
|
* - non-ioctl() chardev hooks: open(), release(), read_callback()
|
|
*
|
|
* REVISIT those periodic irq calls *do* have ops_lock when they're
|
|
* issued through ioctl() ...
|
|
*/
|
|
struct rtc_class_ops {
|
|
int (*open)(struct device *);
|
|
void (*release)(struct device *);
|
|
int (*ioctl)(struct device *, unsigned int, unsigned long);
|
|
int (*read_time)(struct device *, struct rtc_time *);
|
|
int (*set_time)(struct device *, struct rtc_time *);
|
|
int (*read_alarm)(struct device *, struct rtc_wkalrm *);
|
|
int (*set_alarm)(struct device *, struct rtc_wkalrm *);
|
|
int (*proc)(struct device *, struct seq_file *);
|
|
int (*set_mmss)(struct device *, unsigned long secs);
|
|
int (*read_callback)(struct device *, int data);
|
|
int (*alarm_irq_enable)(struct device *, unsigned int enabled);
|
|
};
|
|
|
|
#define RTC_DEVICE_NAME_SIZE 20
|
|
typedef struct rtc_task {
|
|
void (*func)(void *private_data);
|
|
void *private_data;
|
|
} rtc_task_t;
|
|
|
|
|
|
struct rtc_timer {
|
|
struct rtc_task task;
|
|
struct timerqueue_node node;
|
|
ktime_t period;
|
|
int enabled;
|
|
};
|
|
|
|
|
|
/* flags */
|
|
#define RTC_DEV_BUSY 0
|
|
|
|
struct rtc_device
|
|
{
|
|
struct device dev;
|
|
struct module *owner;
|
|
|
|
int id;
|
|
char name[RTC_DEVICE_NAME_SIZE];
|
|
|
|
const struct rtc_class_ops *ops;
|
|
struct mutex ops_lock;
|
|
|
|
struct cdev char_dev;
|
|
unsigned long flags;
|
|
|
|
unsigned long irq_data;
|
|
spinlock_t irq_lock;
|
|
wait_queue_head_t irq_queue;
|
|
struct fasync_struct *async_queue;
|
|
|
|
struct rtc_task *irq_task;
|
|
spinlock_t irq_task_lock;
|
|
int irq_freq;
|
|
int max_user_freq;
|
|
|
|
struct timerqueue_head timerqueue;
|
|
struct rtc_timer aie_timer;
|
|
struct rtc_timer uie_rtctimer;
|
|
struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
|
|
int pie_enabled;
|
|
struct work_struct irqwork;
|
|
/* Some hardware can't support UIE mode */
|
|
int uie_unsupported;
|
|
|
|
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
|
struct work_struct uie_task;
|
|
struct timer_list uie_timer;
|
|
/* Those fields are protected by rtc->irq_lock */
|
|
unsigned int oldsecs;
|
|
unsigned int uie_irq_active:1;
|
|
unsigned int stop_uie_polling:1;
|
|
unsigned int uie_task_active:1;
|
|
unsigned int uie_timer_active:1;
|
|
#endif
|
|
};
|
|
#define to_rtc_device(d) container_of(d, struct rtc_device, dev)
|
|
|
|
extern struct rtc_device *rtc_device_register(const char *name,
|
|
struct device *dev,
|
|
const struct rtc_class_ops *ops,
|
|
struct module *owner);
|
|
extern void rtc_device_unregister(struct rtc_device *rtc);
|
|
|
|
extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
|
|
extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
|
|
extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs);
|
|
extern int rtc_set_ntp_time(struct timespec now);
|
|
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
|
|
extern int rtc_read_alarm(struct rtc_device *rtc,
|
|
struct rtc_wkalrm *alrm);
|
|
extern int rtc_set_alarm(struct rtc_device *rtc,
|
|
struct rtc_wkalrm *alrm);
|
|
extern int rtc_initialize_alarm(struct rtc_device *rtc,
|
|
struct rtc_wkalrm *alrm);
|
|
extern void rtc_update_irq(struct rtc_device *rtc,
|
|
unsigned long num, unsigned long events);
|
|
|
|
extern struct rtc_device *rtc_class_open(char *name);
|
|
extern void rtc_class_close(struct rtc_device *rtc);
|
|
|
|
extern int rtc_irq_register(struct rtc_device *rtc,
|
|
struct rtc_task *task);
|
|
extern void rtc_irq_unregister(struct rtc_device *rtc,
|
|
struct rtc_task *task);
|
|
extern int rtc_irq_set_state(struct rtc_device *rtc,
|
|
struct rtc_task *task, int enabled);
|
|
extern int rtc_irq_set_freq(struct rtc_device *rtc,
|
|
struct rtc_task *task, int freq);
|
|
extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled);
|
|
extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
|
|
extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
|
|
unsigned int enabled);
|
|
|
|
void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode);
|
|
void rtc_aie_update_irq(void *private);
|
|
void rtc_uie_update_irq(void *private);
|
|
enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer);
|
|
|
|
int rtc_register(rtc_task_t *task);
|
|
int rtc_unregister(rtc_task_t *task);
|
|
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
|
|
|
|
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data);
|
|
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
|
|
ktime_t expires, ktime_t period);
|
|
int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer);
|
|
void rtc_timer_do_work(struct work_struct *work);
|
|
|
|
static inline bool is_leap_year(unsigned int year)
|
|
{
|
|
return (!(year % 4) && (year % 100)) || !(year % 400);
|
|
}
|
|
|
|
#ifdef CONFIG_RTC_HCTOSYS_DEVICE
|
|
extern int rtc_hctosys_ret;
|
|
#else
|
|
#define rtc_hctosys_ret -ENODEV
|
|
#endif
|
|
|
|
#endif /* _LINUX_RTC_H_ */
|