RTC for 4.20
Subsystem: - non devm managed registration is now removed from the driver API. - all the unnecessary rtc_valid_tm() calls have been removed Drivers: - abx80X: watchdog support - cmos: fix non ACPI support - sc27xx: fix alarm support - Remove a possible sysfs race condition for ab8500, ds1307, ds1685, isl1208 - Fix a possible race condition where an irq handler may be called before the rtc_device struct is allocated for mt6397, pl030, menelaus, armada38x -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEXx9Viay1+e7J/aM4AyWl4gNJNJIFAlvTekMACgkQAyWl4gNJ NJIJaA/+ONa/L5xvbMXRAAx164WX1f/8kZUZzku5rDAdnwrfj/4N13LRj3rtQlpD 0tv7/JZW3f1P8Ccfd3AkIZa1t7i3ruFpsCvQ9ModzB+gAR9n9ic+k8ugExEXXi4d wrVwEiPHgoYyX/GwGKLUrbTJTqOBcp3PeSW5jK2WhKdnCnYVOQNL38MVmBxSCZ/m 3p+lOBsR4ND2bIf3QjJpck6K+6thaX0JQUIuM14oK2rmNA5dfrhaUw2benlBG/dv Cd/H7TO5qRuUaY+HwwUB/M78wYhaLyVjPU0JbfHwVf04dZFyWQYuZxVZJh9boowO XwkwKBPgti43Opa9i6VIcOR6j2/ym2U8JJcU5eL4scFxjwoTUbbE2WAvNJ9/sF5J z434yfn9Iy0dVEmp/K5Dl0YQAhNHVQChi0RsQ0UnqxDzuxEU8J26JQvp8MHNKYsp FxeyCDjEMf8u+xqQpCQ24chzyIKUGSyFurYGVDhDOW2/Rh08Z17GMhiLfOO73pFU B9GAaEpsJwfZbmtlqJAm3lE521kCo4JBoVM7tY+75p3b9epPW5L6tGQIDdj6Q2A7 VJkCo+O/2cVO3NRXWopTe6/vMm8mvJALvaQVccrLqx/oBpN6GBDFPXfz4a6AB+GF o2XBNEkUOrEAkSONfGKEKAkKU//tIssr9Yx6XmpjFOcrZxgfAL0= =5JM5 -----END PGP SIGNATURE----- Merge tag 'rtc-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "This cycle, there were mostly non urgent fixes in drivers. I also finally unexported the non managed registration. Subsystem: - non devm managed registration is now removed from the driver API - all the unnecessary rtc_valid_tm() calls have been removed Drivers: - abx80X: watchdog support - cmos: fix non ACPI support - sc27xx: fix alarm support - Remove a possible sysfs race condition for ab8500, ds1307, ds1685, isl1208 - Fix a possible race condition where an irq handler may be called before the rtc_device struct is allocated for mt6397, pl030, menelaus, armada38x" * tag 'rtc-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (54 commits) rtc: sc27xx: Always read normal alarm when registering RTC device rtc: sc27xx: Add check to see if need to enable the alarm interrupt rtc: sc27xx: Remove interrupts disable and clear in probe() rtc: sc27xx: Clear SPG value update interrupt status rtc: sc27xx: Set wakeup capability before registering rtc device rtc: s35390a: Change buf's type to u8 in s35390a_init rtc: ds1307: fix ds1339 wakealarm support rtc: ds1685: simplify getting .driver_data rtc: m41t80: mark expected switch fall-through rtc: tegra: Propagate errors from platform_get_irq() rtc: cmos: Remove the `use_acpi_alarm' module parameter for !ACPI rtc: cmos: Fix non-ACPI undefined reference to `hpet_rtc_interrupt' rtc: mv: let the core handle invalid alarms rtc: vr41xx: switch to rtc_time64_to_tm/rtc_tm_to_time64 rtc: ab8500: remove useless check rtc: ab8500: let the core handle range rtc: ab8500: use rtc_add_group rtc: rs5c348: report error when time is invalid rtc: rs5c348: remove forward declaration rtc: rs5c348: remove useless label ...
This commit is contained in:
commit
c7b7eefa57
|
@ -75,7 +75,7 @@ config MIPS
|
|||
select MODULES_USE_ELF_RELA if MODULES && 64BIT
|
||||
select MODULES_USE_ELF_REL if MODULES
|
||||
select PERF_USE_VMALLOC
|
||||
select RTC_LIB if !MACH_LOONGSON64
|
||||
select RTC_LIB
|
||||
select SYSCTL_EXCEPTION_TRACE
|
||||
select VIRT_TO_BUS
|
||||
select NO_BOOTMEM
|
||||
|
|
|
@ -268,7 +268,7 @@ if RTC_LIB=n
|
|||
|
||||
config RTC
|
||||
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
|
||||
depends on ALPHA || (MIPS && MACH_LOONGSON64)
|
||||
depends on ALPHA
|
||||
---help---
|
||||
If you say Y here and create a character special file /dev/rtc with
|
||||
major number 10 and minor number 135 using mknod ("man mknod"), you
|
||||
|
|
|
@ -187,6 +187,7 @@ config RTC_DRV_ABB5ZES3
|
|||
|
||||
config RTC_DRV_ABX80X
|
||||
tristate "Abracon ABx80x"
|
||||
select WATCHDOG_CORE if WATCHDOG
|
||||
help
|
||||
If you say yes here you get support for Abracon AB080X and AB180X
|
||||
families of ultra-low-power battery- and capacitor-backed real-time
|
||||
|
@ -1007,17 +1008,6 @@ config RTC_DRV_DS17885
|
|||
|
||||
endchoice
|
||||
|
||||
config RTC_DS1685_PROC_REGS
|
||||
bool "Display register values in /proc"
|
||||
depends on RTC_DRV_DS1685_FAMILY && PROC_FS
|
||||
help
|
||||
Enable this to display a readout of all of the RTC registers in
|
||||
/proc/drivers/rtc. Keep in mind that this can potentially lead
|
||||
to lost interrupts, as reading Control Register C will clear
|
||||
all pending IRQ flags.
|
||||
|
||||
Unless you are debugging this driver, choose N.
|
||||
|
||||
config RTC_DRV_DS1742
|
||||
tristate "Maxim/Dallas DS1742/1743"
|
||||
depends on HAS_IOMEM
|
||||
|
@ -1587,7 +1577,7 @@ config RTC_DRV_MPC5121
|
|||
|
||||
config RTC_DRV_JZ4740
|
||||
tristate "Ingenic JZ4740 SoC"
|
||||
depends on MACH_INGENIC || COMPILE_TEST
|
||||
depends on MIPS || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
|
||||
controllers.
|
||||
|
|
|
@ -36,9 +36,9 @@ obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
|
|||
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_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_BRCMSTB) += rtc-brcmstb-waketimer.o
|
||||
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
|
||||
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
|
||||
obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o
|
||||
|
@ -71,6 +71,7 @@ obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
|
|||
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
|
||||
obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o
|
||||
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
|
||||
obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o
|
||||
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
|
||||
|
@ -78,10 +79,10 @@ 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_LOONGSON1) += rtc-ls1x.o
|
||||
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
|
||||
obj-$(CONFIG_RTC_DRV_LPC24XX) += rtc-lpc24xx.o
|
||||
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
|
||||
obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
|
||||
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
|
||||
obj-$(CONFIG_RTC_DRV_M41T93) += rtc-m41t93.o
|
||||
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
|
||||
|
@ -100,7 +101,6 @@ obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
|
|||
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
|
||||
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
|
||||
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
|
||||
obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
|
||||
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
|
||||
obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
|
||||
obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
|
||||
|
@ -116,8 +116,8 @@ obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
|
|||
obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
|
||||
obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o
|
||||
|
@ -154,9 +154,9 @@ obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
|
|||
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
|
||||
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
|
||||
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
|
||||
obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
|
||||
obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o
|
||||
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
|
||||
obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
|
||||
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
|
||||
obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o
|
||||
obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o
|
||||
|
@ -169,10 +169,10 @@ obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
|
|||
obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
|
||||
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
|
||||
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
|
||||
obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
|
||||
obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o
|
||||
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
|
||||
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
|
||||
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
|
||||
obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
|
||||
obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o
|
||||
obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o
|
||||
|
|
|
@ -286,9 +286,10 @@ static void rtc_device_get_offset(struct rtc_device *rtc)
|
|||
*
|
||||
* 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)
|
||||
static 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;
|
||||
|
@ -351,15 +352,13 @@ exit:
|
|||
name, err);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_device_register);
|
||||
|
||||
|
||||
/**
|
||||
* rtc_device_unregister - removes the previously registered RTC class device
|
||||
*
|
||||
* @rtc: the RTC class device to destroy
|
||||
*/
|
||||
void rtc_device_unregister(struct rtc_device *rtc)
|
||||
static void rtc_device_unregister(struct rtc_device *rtc)
|
||||
{
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
/*
|
||||
|
@ -372,7 +371,6 @@ void rtc_device_unregister(struct rtc_device *rtc)
|
|||
mutex_unlock(&rtc->ops_lock);
|
||||
put_device(&rtc->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_device_unregister);
|
||||
|
||||
static void devm_rtc_device_release(struct device *dev, void *res)
|
||||
{
|
||||
|
|
|
@ -596,7 +596,6 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
|
|||
* This function is called when an AIE, UIE or PIE mode interrupt
|
||||
* has occurred (or been emulated).
|
||||
*
|
||||
* Triggers the registered irq_task function callback.
|
||||
*/
|
||||
void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
|
||||
{
|
||||
|
@ -741,7 +740,6 @@ static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
|
|||
/**
|
||||
* rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
|
||||
* @rtc: the rtc device
|
||||
* @task: currently registered with rtc_irq_register()
|
||||
* @enabled: true to enable periodic IRQs
|
||||
* Context: any
|
||||
*
|
||||
|
@ -764,7 +762,6 @@ int rtc_irq_set_state(struct rtc_device *rtc, int enabled)
|
|||
/**
|
||||
* rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
|
||||
* @rtc: the rtc device
|
||||
* @task: currently registered with rtc_irq_register()
|
||||
* @freq: positive frequency
|
||||
* Context: any
|
||||
*
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#define RTC_STATUS_DATA 0x01
|
||||
|
||||
#define COUNTS_PER_SEC (0xF000 / 60)
|
||||
#define AB8500_RTC_EPOCH 2000
|
||||
|
||||
static const u8 ab8500_rtc_time_regs[] = {
|
||||
AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
|
||||
|
@ -59,23 +58,6 @@ static const u8 ab8500_rtc_alarm_regs[] = {
|
|||
AB8500_RTC_ALRM_MIN_LOW_REG
|
||||
};
|
||||
|
||||
/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
|
||||
static unsigned long get_elapsed_seconds(int year)
|
||||
{
|
||||
unsigned long secs;
|
||||
struct rtc_time tm = {
|
||||
.tm_year = year - 1900,
|
||||
.tm_mday = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* This function calculates secs from 1970 and not from
|
||||
* 1900, even if we supply the offset from year 1900.
|
||||
*/
|
||||
rtc_tm_to_time(&tm, &secs);
|
||||
return secs;
|
||||
}
|
||||
|
||||
static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned long timeout = jiffies + HZ;
|
||||
|
@ -118,9 +100,6 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
secs = secs / COUNTS_PER_SEC;
|
||||
secs = secs + (mins * 60);
|
||||
|
||||
/* Add back the initially subtracted number of seconds */
|
||||
secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
rtc_time_to_tm(secs, tm);
|
||||
return 0;
|
||||
}
|
||||
|
@ -131,21 +110,8 @@ static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
|
||||
unsigned long no_secs, no_mins, secs = 0;
|
||||
|
||||
if (tm->tm_year < (AB8500_RTC_EPOCH - 1900)) {
|
||||
dev_dbg(dev, "year should be equal to or greater than %d\n",
|
||||
AB8500_RTC_EPOCH);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the number of seconds since 1970 */
|
||||
rtc_tm_to_time(tm, &secs);
|
||||
|
||||
/*
|
||||
* Convert it to the number of seconds since 01-01-2000 00:00:00, since
|
||||
* we only have a small counter in the RTC.
|
||||
*/
|
||||
secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
no_mins = secs / 60;
|
||||
|
||||
no_secs = secs % 60;
|
||||
|
@ -202,12 +168,9 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
|
||||
secs = mins * 60;
|
||||
|
||||
/* Add back the initially subtracted number of seconds */
|
||||
secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
rtc_time_to_tm(secs, &alarm->time);
|
||||
|
||||
return rtc_valid_tm(&alarm->time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
@ -224,12 +187,6 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
unsigned long mins, secs = 0, cursec = 0;
|
||||
struct rtc_time curtm;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -245,12 +202,6 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert it to the number of seconds since 01-01-2000 00:00:00, since
|
||||
* we only have a small counter in the RTC.
|
||||
*/
|
||||
secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
|
||||
|
||||
mins = secs / 60;
|
||||
|
||||
buf[2] = mins & 0xFF;
|
||||
|
@ -360,15 +311,14 @@ static DEVICE_ATTR(rtc_calibration, S_IRUGO | S_IWUSR,
|
|||
ab8500_sysfs_show_rtc_calibration,
|
||||
ab8500_sysfs_store_rtc_calibration);
|
||||
|
||||
static int ab8500_sysfs_rtc_register(struct device *dev)
|
||||
{
|
||||
return device_create_file(dev, &dev_attr_rtc_calibration);
|
||||
}
|
||||
static struct attribute *ab8500_rtc_attrs[] = {
|
||||
&dev_attr_rtc_calibration.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void ab8500_sysfs_rtc_unregister(struct device *dev)
|
||||
{
|
||||
device_remove_file(dev, &dev_attr_rtc_calibration);
|
||||
}
|
||||
static const struct attribute_group ab8500_rtc_sysfs_files = {
|
||||
.attrs = ab8500_rtc_attrs,
|
||||
};
|
||||
|
||||
static irqreturn_t rtc_alarm_handler(int irq, void *data)
|
||||
{
|
||||
|
@ -429,14 +379,11 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc",
|
||||
(struct rtc_class_ops *)platid->driver_data,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
dev_err(&pdev->dev, "Registration failed\n");
|
||||
err = PTR_ERR(rtc);
|
||||
return err;
|
||||
}
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
rtc->ops = (struct rtc_class_ops *)platid->driver_data;
|
||||
|
||||
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
rtc_alarm_handler, IRQF_ONESHOT,
|
||||
|
@ -447,22 +394,23 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
|
|||
dev_pm_set_wake_irq(&pdev->dev, irq);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
err = ab8500_sysfs_rtc_register(&pdev->dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "sysfs RTC failed to register\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
rtc->uie_unsupported = 1;
|
||||
|
||||
return 0;
|
||||
rtc->range_max = (1ULL << 24) * 60 - 1; // 24-bit minutes + 59 secs
|
||||
rtc->start_secs = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->set_start_time = true;
|
||||
|
||||
err = rtc_add_group(rtc, &ab8500_rtc_sysfs_files);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static int ab8500_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
ab8500_sysfs_rtc_unregister(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define ABX8XX_REG_HTH 0x00
|
||||
#define ABX8XX_REG_SC 0x01
|
||||
|
@ -37,6 +38,7 @@
|
|||
|
||||
#define ABX8XX_REG_STATUS 0x0f
|
||||
#define ABX8XX_STATUS_AF BIT(2)
|
||||
#define ABX8XX_STATUS_WDT BIT(6)
|
||||
|
||||
#define ABX8XX_REG_CTRL1 0x10
|
||||
#define ABX8XX_CTRL_WRITE BIT(0)
|
||||
|
@ -61,6 +63,14 @@
|
|||
#define ABX8XX_OSS_OF BIT(1)
|
||||
#define ABX8XX_OSS_OMODE BIT(4)
|
||||
|
||||
#define ABX8XX_REG_WDT 0x1b
|
||||
#define ABX8XX_WDT_WDS BIT(7)
|
||||
#define ABX8XX_WDT_BMB_MASK 0x7c
|
||||
#define ABX8XX_WDT_BMB_SHIFT 2
|
||||
#define ABX8XX_WDT_MAX_TIME (ABX8XX_WDT_BMB_MASK >> ABX8XX_WDT_BMB_SHIFT)
|
||||
#define ABX8XX_WDT_WRB_MASK 0x03
|
||||
#define ABX8XX_WDT_WRB_1HZ 0x02
|
||||
|
||||
#define ABX8XX_REG_CFG_KEY 0x1f
|
||||
#define ABX8XX_CFG_KEY_OSC 0xa1
|
||||
#define ABX8XX_CFG_KEY_MISC 0x9d
|
||||
|
@ -80,20 +90,27 @@ enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
|
|||
struct abx80x_cap {
|
||||
u16 pn;
|
||||
bool has_tc;
|
||||
bool has_wdog;
|
||||
};
|
||||
|
||||
static struct abx80x_cap abx80x_caps[] = {
|
||||
[AB0801] = {.pn = 0x0801},
|
||||
[AB0803] = {.pn = 0x0803},
|
||||
[AB0804] = {.pn = 0x0804, .has_tc = true},
|
||||
[AB0805] = {.pn = 0x0805, .has_tc = true},
|
||||
[AB0804] = {.pn = 0x0804, .has_tc = true, .has_wdog = true},
|
||||
[AB0805] = {.pn = 0x0805, .has_tc = true, .has_wdog = true},
|
||||
[AB1801] = {.pn = 0x1801},
|
||||
[AB1803] = {.pn = 0x1803},
|
||||
[AB1804] = {.pn = 0x1804, .has_tc = true},
|
||||
[AB1805] = {.pn = 0x1805, .has_tc = true},
|
||||
[AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true},
|
||||
[AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
|
||||
[ABX80X] = {.pn = 0}
|
||||
};
|
||||
|
||||
struct abx80x_priv {
|
||||
struct rtc_device *rtc;
|
||||
struct i2c_client *client;
|
||||
struct watchdog_device wdog;
|
||||
};
|
||||
|
||||
static int abx80x_is_rc_mode(struct i2c_client *client)
|
||||
{
|
||||
int flags = 0;
|
||||
|
@ -218,7 +235,8 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct i2c_client *client = dev_id;
|
||||
struct rtc_device *rtc = i2c_get_clientdata(client);
|
||||
struct abx80x_priv *priv = i2c_get_clientdata(client);
|
||||
struct rtc_device *rtc = priv->rtc;
|
||||
int status;
|
||||
|
||||
status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS);
|
||||
|
@ -228,6 +246,13 @@ static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
|
|||
if (status & ABX8XX_STATUS_AF)
|
||||
rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
|
||||
|
||||
/*
|
||||
* It is unclear if we'll get an interrupt before the external
|
||||
* reset kicks in.
|
||||
*/
|
||||
if (status & ABX8XX_STATUS_WDT)
|
||||
dev_alert(&client->dev, "watchdog timeout interrupt.\n");
|
||||
|
||||
i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -529,11 +554,94 @@ static void rtc_calib_remove_sysfs_group(void *_dev)
|
|||
sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
|
||||
static inline u8 timeout_bits(unsigned int timeout)
|
||||
{
|
||||
return ((timeout << ABX8XX_WDT_BMB_SHIFT) & ABX8XX_WDT_BMB_MASK) |
|
||||
ABX8XX_WDT_WRB_1HZ;
|
||||
}
|
||||
|
||||
static int __abx80x_wdog_set_timeout(struct watchdog_device *wdog,
|
||||
unsigned int timeout)
|
||||
{
|
||||
struct abx80x_priv *priv = watchdog_get_drvdata(wdog);
|
||||
u8 val = ABX8XX_WDT_WDS | timeout_bits(timeout);
|
||||
|
||||
/*
|
||||
* Writing any timeout to the WDT register resets the watchdog timer.
|
||||
* Writing 0 disables it.
|
||||
*/
|
||||
return i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_WDT, val);
|
||||
}
|
||||
|
||||
static int abx80x_wdog_set_timeout(struct watchdog_device *wdog,
|
||||
unsigned int new_timeout)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (watchdog_hw_running(wdog))
|
||||
err = __abx80x_wdog_set_timeout(wdog, new_timeout);
|
||||
|
||||
if (err == 0)
|
||||
wdog->timeout = new_timeout;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int abx80x_wdog_ping(struct watchdog_device *wdog)
|
||||
{
|
||||
return __abx80x_wdog_set_timeout(wdog, wdog->timeout);
|
||||
}
|
||||
|
||||
static int abx80x_wdog_start(struct watchdog_device *wdog)
|
||||
{
|
||||
return __abx80x_wdog_set_timeout(wdog, wdog->timeout);
|
||||
}
|
||||
|
||||
static int abx80x_wdog_stop(struct watchdog_device *wdog)
|
||||
{
|
||||
return __abx80x_wdog_set_timeout(wdog, 0);
|
||||
}
|
||||
|
||||
static const struct watchdog_info abx80x_wdog_info = {
|
||||
.identity = "abx80x watchdog",
|
||||
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
|
||||
};
|
||||
|
||||
static const struct watchdog_ops abx80x_wdog_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = abx80x_wdog_start,
|
||||
.stop = abx80x_wdog_stop,
|
||||
.ping = abx80x_wdog_ping,
|
||||
.set_timeout = abx80x_wdog_set_timeout,
|
||||
};
|
||||
|
||||
static int abx80x_setup_watchdog(struct abx80x_priv *priv)
|
||||
{
|
||||
priv->wdog.parent = &priv->client->dev;
|
||||
priv->wdog.ops = &abx80x_wdog_ops;
|
||||
priv->wdog.info = &abx80x_wdog_info;
|
||||
priv->wdog.min_timeout = 1;
|
||||
priv->wdog.max_timeout = ABX8XX_WDT_MAX_TIME;
|
||||
priv->wdog.timeout = ABX8XX_WDT_MAX_TIME;
|
||||
|
||||
watchdog_set_drvdata(&priv->wdog, priv);
|
||||
|
||||
return devm_watchdog_register_device(&priv->client->dev, &priv->wdog);
|
||||
}
|
||||
#else
|
||||
static int abx80x_setup_watchdog(struct abx80x_priv *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int abx80x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device_node *np = client->dev.of_node;
|
||||
struct rtc_device *rtc;
|
||||
struct abx80x_priv *priv;
|
||||
int i, data, err, trickle_cfg = -EINVAL;
|
||||
char buf[7];
|
||||
unsigned int part = id->driver_data;
|
||||
|
@ -610,13 +718,24 @@ static int abx80x_probe(struct i2c_client *client,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->ops = &abx80x_rtc_ops;
|
||||
priv->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(priv->rtc))
|
||||
return PTR_ERR(priv->rtc);
|
||||
|
||||
i2c_set_clientdata(client, rtc);
|
||||
priv->rtc->ops = &abx80x_rtc_ops;
|
||||
priv->client = client;
|
||||
|
||||
i2c_set_clientdata(client, priv);
|
||||
|
||||
if (abx80x_caps[part].has_wdog) {
|
||||
err = abx80x_setup_watchdog(priv);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (client->irq > 0) {
|
||||
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
|
||||
|
@ -649,7 +768,7 @@ static int abx80x_probe(struct i2c_client *client,
|
|||
return err;
|
||||
}
|
||||
|
||||
err = rtc_register_device(rtc);
|
||||
err = rtc_register_device(priv->rtc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
time = rtc->data->read_rtc_reg(rtc, RTC_TIME);
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
rtc_time_to_tm(time, tm);
|
||||
rtc_time64_to_tm(time, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -249,13 +249,9 @@ static void armada38x_rtc_reset(struct armada38x_rtc *rtc)
|
|||
static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
unsigned long time, flags;
|
||||
|
||||
ret = rtc_tm_to_time(tm, &time);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
time = rtc_tm_to_time64(tm);
|
||||
|
||||
if (!rtc->initialized)
|
||||
armada38x_rtc_reset(rtc);
|
||||
|
@ -264,8 +260,7 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
rtc_delayed_write(time, rtc, RTC_TIME);
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
@ -284,7 +279,7 @@ static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
alrm->enabled = val ? 1 : 0;
|
||||
rtc_time_to_tm(time, &alrm->time);
|
||||
rtc_time64_to_tm(time, &alrm->time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -295,12 +290,8 @@ static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm);
|
||||
u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
|
||||
unsigned long time, flags;
|
||||
int ret = 0;
|
||||
|
||||
ret = rtc_tm_to_time(&alrm->time, &time);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
time = rtc_tm_to_time64(&alrm->time);
|
||||
|
||||
spin_lock_irqsave(&rtc->lock, flags);
|
||||
|
||||
|
@ -313,8 +304,7 @@ static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada38x_rtc_alarm_irq_enable(struct device *dev,
|
||||
|
@ -514,7 +504,6 @@ MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
|
|||
|
||||
static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct rtc_class_ops *ops;
|
||||
struct resource *res;
|
||||
struct armada38x_rtc *rtc;
|
||||
const struct of_device_id *match;
|
||||
|
@ -551,6 +540,11 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "no irq\n");
|
||||
return rtc->irq;
|
||||
}
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq,
|
||||
0, pdev->name, rtc) < 0) {
|
||||
dev_warn(&pdev->dev, "Interrupt not available.\n");
|
||||
|
@ -560,28 +554,26 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
if (rtc->irq != -1) {
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
ops = &armada38x_rtc_ops;
|
||||
rtc->rtc_dev->ops = &armada38x_rtc_ops;
|
||||
} else {
|
||||
/*
|
||||
* If there is no interrupt available then we can't
|
||||
* use the alarm
|
||||
*/
|
||||
ops = &armada38x_rtc_ops_noirq;
|
||||
rtc->rtc_dev->ops = &armada38x_rtc_ops_noirq;
|
||||
}
|
||||
rtc->data = (struct armada38x_rtc_data *)match->data;
|
||||
|
||||
|
||||
/* Update RTC-MBUS bridge timing parameters */
|
||||
rtc->data->update_mbus_timing(rtc);
|
||||
|
||||
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc_dev)) {
|
||||
ret = PTR_ERR(rtc->rtc_dev);
|
||||
rtc->rtc_dev->range_max = U32_MAX;
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/*
|
||||
* Use ACPI SCI to replace HPET interrupt for RTC Alarm event
|
||||
*
|
||||
|
@ -61,6 +62,18 @@
|
|||
static bool use_acpi_alarm;
|
||||
module_param(use_acpi_alarm, bool, 0444);
|
||||
|
||||
static inline int cmos_use_acpi_alarm(void)
|
||||
{
|
||||
return use_acpi_alarm;
|
||||
}
|
||||
#else /* !CONFIG_ACPI */
|
||||
|
||||
static inline int cmos_use_acpi_alarm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct cmos_rtc {
|
||||
struct rtc_device *rtc;
|
||||
struct device *dev;
|
||||
|
@ -167,9 +180,9 @@ static inline int hpet_unregister_irq_handler(irq_handler_t handler)
|
|||
#endif
|
||||
|
||||
/* Don't use HPET for RTC Alarm event if ACPI Fixed event is used */
|
||||
static int use_hpet_alarm(void)
|
||||
static inline int use_hpet_alarm(void)
|
||||
{
|
||||
return is_hpet_enabled() && !use_acpi_alarm;
|
||||
return is_hpet_enabled() && !cmos_use_acpi_alarm();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
@ -340,7 +353,7 @@ static void cmos_irq_enable(struct cmos_rtc *cmos, unsigned char mask)
|
|||
if (use_hpet_alarm())
|
||||
hpet_set_rtc_irq_bit(mask);
|
||||
|
||||
if ((mask & RTC_AIE) && use_acpi_alarm) {
|
||||
if ((mask & RTC_AIE) && cmos_use_acpi_alarm()) {
|
||||
if (cmos->wake_on)
|
||||
cmos->wake_on(cmos->dev);
|
||||
}
|
||||
|
@ -358,7 +371,7 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
|
|||
if (use_hpet_alarm())
|
||||
hpet_mask_rtc_irq_bit(mask);
|
||||
|
||||
if ((mask & RTC_AIE) && use_acpi_alarm) {
|
||||
if ((mask & RTC_AIE) && cmos_use_acpi_alarm()) {
|
||||
if (cmos->wake_off)
|
||||
cmos->wake_off(cmos->dev);
|
||||
}
|
||||
|
@ -980,7 +993,7 @@ static int cmos_suspend(struct device *dev)
|
|||
}
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
if ((tmp & RTC_AIE) && !use_acpi_alarm) {
|
||||
if ((tmp & RTC_AIE) && !cmos_use_acpi_alarm()) {
|
||||
cmos->enabled_wake = 1;
|
||||
if (cmos->wake_on)
|
||||
cmos->wake_on(dev);
|
||||
|
@ -1031,7 +1044,7 @@ static void cmos_check_wkalrm(struct device *dev)
|
|||
* ACPI RTC wake event is cleared after resume from STR,
|
||||
* ACK the rtc irq here
|
||||
*/
|
||||
if (t_now >= cmos->alarm_expires && use_acpi_alarm) {
|
||||
if (t_now >= cmos->alarm_expires && cmos_use_acpi_alarm()) {
|
||||
cmos_interrupt(0, (void *)cmos->rtc);
|
||||
return;
|
||||
}
|
||||
|
@ -1053,7 +1066,7 @@ static int __maybe_unused cmos_resume(struct device *dev)
|
|||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
unsigned char tmp;
|
||||
|
||||
if (cmos->enabled_wake && !use_acpi_alarm) {
|
||||
if (cmos->enabled_wake && !cmos_use_acpi_alarm()) {
|
||||
if (cmos->wake_off)
|
||||
cmos->wake_off(dev);
|
||||
else
|
||||
|
@ -1132,7 +1145,7 @@ static u32 rtc_handler(void *context)
|
|||
* Or else, ACPI SCI is enabled during suspend/resume only,
|
||||
* update rtc irq in that case.
|
||||
*/
|
||||
if (use_acpi_alarm)
|
||||
if (cmos_use_acpi_alarm())
|
||||
cmos_interrupt(0, (void *)cmos->rtc);
|
||||
else {
|
||||
/* Fix me: can we use cmos_interrupt() here as well? */
|
||||
|
|
|
@ -40,23 +40,9 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc)
|
|||
|
||||
#ifdef CONFIG_RTC_INTF_SYSFS
|
||||
const struct attribute_group **rtc_get_dev_attribute_groups(void);
|
||||
int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp);
|
||||
int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps);
|
||||
#else
|
||||
static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -114,6 +114,20 @@ enum ds_type {
|
|||
# define RX8025_BIT_VDET 0x40
|
||||
# define RX8025_BIT_XST 0x20
|
||||
|
||||
#define M41TXX_REG_CONTROL 0x07
|
||||
# define M41TXX_BIT_OUT BIT(7)
|
||||
# define M41TXX_BIT_FT BIT(6)
|
||||
# define M41TXX_BIT_CALIB_SIGN BIT(5)
|
||||
# define M41TXX_M_CALIBRATION GENMASK(4, 0)
|
||||
|
||||
/* negative offset step is -2.034ppm */
|
||||
#define M41TXX_NEG_OFFSET_STEP_PPB 2034
|
||||
/* positive offset step is +4.068ppm */
|
||||
#define M41TXX_POS_OFFSET_STEP_PPB 4068
|
||||
/* Min and max values supported with 'offset' interface by M41TXX */
|
||||
#define M41TXX_MIN_OFFSET ((-31) * M41TXX_NEG_OFFSET_STEP_PPB)
|
||||
#define M41TXX_MAX_OFFSET ((31) * M41TXX_POS_OFFSET_STEP_PPB)
|
||||
|
||||
struct ds1307 {
|
||||
enum ds_type type;
|
||||
unsigned long flags;
|
||||
|
@ -146,6 +160,9 @@ struct chip_desc {
|
|||
|
||||
static int ds1307_get_time(struct device *dev, struct rtc_time *t);
|
||||
static int ds1307_set_time(struct device *dev, struct rtc_time *t);
|
||||
static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t);
|
||||
static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t);
|
||||
static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled);
|
||||
static u8 do_trickle_setup_ds1339(struct ds1307 *, u32 ohms, bool diode);
|
||||
static irqreturn_t rx8130_irq(int irq, void *dev_id);
|
||||
static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t);
|
||||
|
@ -155,6 +172,8 @@ static irqreturn_t mcp794xx_irq(int irq, void *dev_id);
|
|||
static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t);
|
||||
static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t);
|
||||
static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled);
|
||||
static int m41txx_rtc_read_offset(struct device *dev, long *offset);
|
||||
static int m41txx_rtc_set_offset(struct device *dev, long offset);
|
||||
|
||||
static const struct rtc_class_ops rx8130_rtc_ops = {
|
||||
.read_time = ds1307_get_time,
|
||||
|
@ -172,6 +191,16 @@ static const struct rtc_class_ops mcp794xx_rtc_ops = {
|
|||
.alarm_irq_enable = mcp794xx_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static const struct rtc_class_ops m41txx_rtc_ops = {
|
||||
.read_time = ds1307_get_time,
|
||||
.set_time = ds1307_set_time,
|
||||
.read_alarm = ds1337_read_alarm,
|
||||
.set_alarm = ds1337_set_alarm,
|
||||
.alarm_irq_enable = ds1307_alarm_irq_enable,
|
||||
.read_offset = m41txx_rtc_read_offset,
|
||||
.set_offset = m41txx_rtc_set_offset,
|
||||
};
|
||||
|
||||
static const struct chip_desc chips[last_ds_type] = {
|
||||
[ds_1307] = {
|
||||
.nvram_offset = 8,
|
||||
|
@ -228,10 +257,17 @@ static const struct chip_desc chips[last_ds_type] = {
|
|||
.irq_handler = rx8130_irq,
|
||||
.rtc_ops = &rx8130_rtc_ops,
|
||||
},
|
||||
[m41t0] = {
|
||||
.rtc_ops = &m41txx_rtc_ops,
|
||||
},
|
||||
[m41t00] = {
|
||||
.rtc_ops = &m41txx_rtc_ops,
|
||||
},
|
||||
[m41t11] = {
|
||||
/* this is battery backed SRAM */
|
||||
.nvram_offset = 8,
|
||||
.nvram_size = 56,
|
||||
.rtc_ops = &m41txx_rtc_ops,
|
||||
},
|
||||
[mcp794xx] = {
|
||||
.alarm = 1,
|
||||
|
@ -973,6 +1009,110 @@ static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
enabled ? MCP794XX_BIT_ALM0_EN : 0);
|
||||
}
|
||||
|
||||
static int m41txx_rtc_read_offset(struct device *dev, long *offset)
|
||||
{
|
||||
struct ds1307 *ds1307 = dev_get_drvdata(dev);
|
||||
unsigned int ctrl_reg;
|
||||
u8 val;
|
||||
|
||||
regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
|
||||
|
||||
val = ctrl_reg & M41TXX_M_CALIBRATION;
|
||||
|
||||
/* check if positive */
|
||||
if (ctrl_reg & M41TXX_BIT_CALIB_SIGN)
|
||||
*offset = (val * M41TXX_POS_OFFSET_STEP_PPB);
|
||||
else
|
||||
*offset = -(val * M41TXX_NEG_OFFSET_STEP_PPB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41txx_rtc_set_offset(struct device *dev, long offset)
|
||||
{
|
||||
struct ds1307 *ds1307 = dev_get_drvdata(dev);
|
||||
unsigned int ctrl_reg;
|
||||
|
||||
if ((offset < M41TXX_MIN_OFFSET) || (offset > M41TXX_MAX_OFFSET))
|
||||
return -ERANGE;
|
||||
|
||||
if (offset >= 0) {
|
||||
ctrl_reg = DIV_ROUND_CLOSEST(offset,
|
||||
M41TXX_POS_OFFSET_STEP_PPB);
|
||||
ctrl_reg |= M41TXX_BIT_CALIB_SIGN;
|
||||
} else {
|
||||
ctrl_reg = DIV_ROUND_CLOSEST(abs(offset),
|
||||
M41TXX_NEG_OFFSET_STEP_PPB);
|
||||
}
|
||||
|
||||
return regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL,
|
||||
M41TXX_M_CALIBRATION | M41TXX_BIT_CALIB_SIGN,
|
||||
ctrl_reg);
|
||||
}
|
||||
|
||||
static ssize_t frequency_test_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ds1307 *ds1307 = dev_get_drvdata(dev->parent);
|
||||
bool freq_test_en;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &freq_test_en);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to store RTC Frequency Test attribute\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL, M41TXX_BIT_FT,
|
||||
freq_test_en ? M41TXX_BIT_FT : 0);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t frequency_test_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ds1307 *ds1307 = dev_get_drvdata(dev->parent);
|
||||
unsigned int ctrl_reg;
|
||||
|
||||
regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, (ctrl_reg & M41TXX_BIT_FT) ? "on\n" :
|
||||
"off\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(frequency_test);
|
||||
|
||||
static struct attribute *rtc_freq_test_attrs[] = {
|
||||
&dev_attr_frequency_test.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group rtc_freq_test_attr_group = {
|
||||
.attrs = rtc_freq_test_attrs,
|
||||
};
|
||||
|
||||
static int ds1307_add_frequency_test(struct ds1307 *ds1307)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (ds1307->type) {
|
||||
case m41t0:
|
||||
case m41t00:
|
||||
case m41t11:
|
||||
err = rtc_add_group(ds1307->rtc, &rtc_freq_test_attr_group);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static int ds1307_nvram_read(void *priv, unsigned int offset, void *val,
|
||||
|
@ -1384,7 +1524,6 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
|
|||
static const struct regmap_config regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x9,
|
||||
};
|
||||
|
||||
static int ds1307_probe(struct i2c_client *client,
|
||||
|
@ -1711,6 +1850,10 @@ read_rtc:
|
|||
}
|
||||
|
||||
ds1307->rtc->ops = chip->rtc_ops ?: &ds13xx_rtc_ops;
|
||||
err = ds1307_add_frequency_test(ds1307);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rtc_register_device(ds1307->rtc);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -770,33 +770,6 @@ static const char *ds1685_rtc_sqw_freq[16] = {
|
|||
"512Hz", "256Hz", "128Hz", "64Hz", "32Hz", "16Hz", "8Hz", "4Hz", "2Hz"
|
||||
};
|
||||
|
||||
#ifdef CONFIG_RTC_DS1685_PROC_REGS
|
||||
/**
|
||||
* ds1685_rtc_print_regs - helper function to print register values.
|
||||
* @hex: hex byte to convert into binary bits.
|
||||
* @dest: destination char array.
|
||||
*
|
||||
* This is basically a hex->binary function, just with extra spacing between
|
||||
* the digits. It only works on 1-byte values (8 bits).
|
||||
*/
|
||||
static char*
|
||||
ds1685_rtc_print_regs(u8 hex, char *dest)
|
||||
{
|
||||
u32 i, j;
|
||||
char *tmp = dest;
|
||||
|
||||
for (i = 0; i < NUM_BITS; i++) {
|
||||
*tmp++ = ((hex & 0x80) != 0 ? '1' : '0');
|
||||
for (j = 0; j < NUM_SPACES; j++)
|
||||
*tmp++ = ' ';
|
||||
hex <<= 1;
|
||||
}
|
||||
*tmp++ = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ds1685_rtc_proc - procfs access function.
|
||||
* @dev: pointer to device structure.
|
||||
|
@ -805,13 +778,9 @@ ds1685_rtc_print_regs(u8 hex, char *dest)
|
|||
static int
|
||||
ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b, ssn[8];
|
||||
char *model;
|
||||
#ifdef CONFIG_RTC_DS1685_PROC_REGS
|
||||
char bits[NUM_REGS][(NUM_BITS * NUM_SPACES) + NUM_BITS + 1];
|
||||
#endif
|
||||
|
||||
/* Read all the relevant data from the control registers. */
|
||||
ds1685_rtc_switch_to_bank1(rtc);
|
||||
|
@ -859,28 +828,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
|
|||
"Periodic IRQ\t: %s\n"
|
||||
"Periodic Rate\t: %s\n"
|
||||
"SQW Freq\t: %s\n"
|
||||
#ifdef CONFIG_RTC_DS1685_PROC_REGS
|
||||
"Serial #\t: %8phC\n"
|
||||
"Register Status\t:\n"
|
||||
" Ctrl A\t: UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0\n"
|
||||
"\t\t: %s\n"
|
||||
" Ctrl B\t: SET PIE AIE UIE SQWE DM 2412 DSE\n"
|
||||
"\t\t: %s\n"
|
||||
" Ctrl C\t: IRQF PF AF UF --- --- --- ---\n"
|
||||
"\t\t: %s\n"
|
||||
" Ctrl D\t: VRT --- --- --- --- --- --- ---\n"
|
||||
"\t\t: %s\n"
|
||||
#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
|
||||
" Ctrl 4A\t: VRT2 INCR BME --- PAB RF WF KF\n"
|
||||
#else
|
||||
" Ctrl 4A\t: VRT2 INCR --- --- PAB RF WF KF\n"
|
||||
#endif
|
||||
"\t\t: %s\n"
|
||||
" Ctrl 4B\t: ABE E32k CS RCE PRS RIE WIE KSE\n"
|
||||
"\t\t: %s\n",
|
||||
#else
|
||||
"Serial #\t: %8phC\n",
|
||||
#endif
|
||||
model,
|
||||
((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"),
|
||||
((ctrlb & RTC_CTRL_B_2412) ? "24-hour" : "12-hour"),
|
||||
|
@ -894,17 +842,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
|
|||
ds1685_rtc_pirq_rate[(ctrla & RTC_CTRL_A_RS_MASK)] : "none"),
|
||||
(!((ctrl4b & RTC_CTRL_4B_E32K)) ?
|
||||
ds1685_rtc_sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32768Hz"),
|
||||
#ifdef CONFIG_RTC_DS1685_PROC_REGS
|
||||
ssn,
|
||||
ds1685_rtc_print_regs(ctrla, bits[0]),
|
||||
ds1685_rtc_print_regs(ctrlb, bits[1]),
|
||||
ds1685_rtc_print_regs(ctrlc, bits[2]),
|
||||
ds1685_rtc_print_regs(ctrld, bits[3]),
|
||||
ds1685_rtc_print_regs(ctrl4a, bits[4]),
|
||||
ds1685_rtc_print_regs(ctrl4b, bits[5]));
|
||||
#else
|
||||
ssn);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -927,30 +865,13 @@ ds1685_rtc_ops = {
|
|||
};
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* SysFS interface */
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
/**
|
||||
* ds1685_rtc_sysfs_nvram_read - reads rtc nvram via sysfs.
|
||||
* @file: pointer to file structure.
|
||||
* @kobj: pointer to kobject structure.
|
||||
* @bin_attr: pointer to bin_attribute structure.
|
||||
* @buf: pointer to char array to hold the output.
|
||||
* @pos: current file position pointer.
|
||||
* @size: size of the data to read.
|
||||
*/
|
||||
static ssize_t
|
||||
ds1685_rtc_sysfs_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
static int ds1685_nvram_read(void *priv, unsigned int pos, void *val,
|
||||
size_t size)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
to_platform_device(container_of(kobj, struct device, kobj));
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = priv;
|
||||
ssize_t count;
|
||||
unsigned long flags = 0;
|
||||
u8 *buf = val;
|
||||
|
||||
spin_lock_irqsave(&rtc->lock, flags);
|
||||
ds1685_rtc_switch_to_bank0(rtc);
|
||||
|
@ -1004,33 +925,16 @@ ds1685_rtc_sysfs_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
#endif /* !CONFIG_RTC_DRV_DS1689 */
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
/*
|
||||
* XXX: Bug? this appears to cause the function to get executed
|
||||
* several times in succession. But it's the only way to actually get
|
||||
* data written out to a file.
|
||||
*/
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ds1685_rtc_sysfs_nvram_write - writes rtc nvram via sysfs.
|
||||
* @file: pointer to file structure.
|
||||
* @kobj: pointer to kobject structure.
|
||||
* @bin_attr: pointer to bin_attribute structure.
|
||||
* @buf: pointer to char array to hold the input.
|
||||
* @pos: current file position pointer.
|
||||
* @size: size of the data to write.
|
||||
*/
|
||||
static ssize_t
|
||||
ds1685_rtc_sysfs_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
static int ds1685_nvram_write(void *priv, unsigned int pos, void *val,
|
||||
size_t size)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
to_platform_device(container_of(kobj, struct device, kobj));
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = priv;
|
||||
ssize_t count;
|
||||
unsigned long flags = 0;
|
||||
u8 *buf = val;
|
||||
|
||||
spin_lock_irqsave(&rtc->lock, flags);
|
||||
ds1685_rtc_switch_to_bank0(rtc);
|
||||
|
@ -1084,26 +988,11 @@ ds1685_rtc_sysfs_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
#endif /* !CONFIG_RTC_DRV_DS1689 */
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ds1685_rtc_sysfs_nvram_attr - sysfs attributes for rtc nvram.
|
||||
* @attr: nvram attributes.
|
||||
* @read: nvram read function.
|
||||
* @write: nvram write function.
|
||||
* @size: nvram total size (bank0 + extended).
|
||||
*/
|
||||
static struct bin_attribute
|
||||
ds1685_rtc_sysfs_nvram_attr = {
|
||||
.attr = {
|
||||
.name = "nvram",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
},
|
||||
.read = ds1685_rtc_sysfs_nvram_read,
|
||||
.write = ds1685_rtc_sysfs_nvram_write,
|
||||
.size = NVRAM_TOTAL_SZ
|
||||
};
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* SysFS interface */
|
||||
|
||||
/**
|
||||
* ds1685_rtc_sysfs_battery_show - sysfs file for main battery status.
|
||||
|
@ -1188,43 +1077,6 @@ ds1685_rtc_sysfs_misc_grp = {
|
|||
.attrs = ds1685_rtc_sysfs_misc_attrs,
|
||||
};
|
||||
|
||||
/**
|
||||
* ds1685_rtc_sysfs_register - register sysfs files.
|
||||
* @dev: pointer to device structure.
|
||||
*/
|
||||
static int
|
||||
ds1685_rtc_sysfs_register(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sysfs_bin_attr_init(&ds1685_rtc_sysfs_nvram_attr);
|
||||
ret = sysfs_create_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ds1685_rtc_sysfs_unregister - unregister sysfs files.
|
||||
* @dev: pointer to device structure.
|
||||
*/
|
||||
static int
|
||||
ds1685_rtc_sysfs_unregister(struct device *dev)
|
||||
{
|
||||
sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
|
||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* Driver Probe/Removal */
|
||||
|
||||
|
@ -1242,6 +1094,12 @@ ds1685_rtc_probe(struct platform_device *pdev)
|
|||
u8 ctrla, ctrlb, hours;
|
||||
unsigned char am_pm;
|
||||
int ret = 0;
|
||||
struct nvmem_config nvmem_cfg = {
|
||||
.name = "ds1685_nvram",
|
||||
.size = NVRAM_TOTAL_SZ,
|
||||
.reg_read = ds1685_nvram_read,
|
||||
.reg_write = ds1685_nvram_write,
|
||||
};
|
||||
|
||||
/* Get the platform data. */
|
||||
pdata = (struct ds1685_rtc_platform_data *) pdev->dev.platform_data;
|
||||
|
@ -1499,11 +1357,15 @@ ds1685_rtc_probe(struct platform_device *pdev)
|
|||
/* Setup complete. */
|
||||
ds1685_rtc_switch_to_bank0(rtc);
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
ret = ds1685_rtc_sysfs_register(&pdev->dev);
|
||||
ret = rtc_add_group(rtc_dev, &ds1685_rtc_sysfs_misc_grp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtc_dev->nvram_old_abi = true;
|
||||
nvmem_cfg.priv = rtc;
|
||||
ret = rtc_nvmem_register(rtc_dev, &nvmem_cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
return rtc_register_device(rtc_dev);
|
||||
}
|
||||
|
@ -1517,10 +1379,6 @@ ds1685_rtc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
ds1685_rtc_sysfs_unregister(&pdev->dev);
|
||||
#endif
|
||||
|
||||
/* Read Ctrl B and clear PIE/AIE/UIE. */
|
||||
rtc->write(rtc, RTC_CTRL_B,
|
||||
(rtc->read(rtc, RTC_CTRL_B) &
|
||||
|
|
|
@ -10,12 +10,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/rtc.h>
|
||||
#include "rtc-core.h"
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/* Register map */
|
||||
/* rtc section */
|
||||
|
@ -518,7 +517,7 @@ static ssize_t timestamp0_store(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
int sr;
|
||||
|
||||
sr = isl1208_i2c_get_sr(client);
|
||||
|
@ -540,7 +539,7 @@ static ssize_t timestamp0_store(struct device *dev,
|
|||
static ssize_t timestamp0_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
u8 regs[ISL1219_EVT_SECTION_LEN] = { 0, };
|
||||
struct rtc_time tm;
|
||||
int sr;
|
||||
|
@ -650,7 +649,7 @@ static ssize_t
|
|||
isl1208_sysfs_show_atrim(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int atr = isl1208_i2c_get_atr(to_i2c_client(dev));
|
||||
int atr = isl1208_i2c_get_atr(to_i2c_client(dev->parent));
|
||||
if (atr < 0)
|
||||
return atr;
|
||||
|
||||
|
@ -663,7 +662,7 @@ static ssize_t
|
|||
isl1208_sysfs_show_dtrim(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
|
||||
int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev->parent));
|
||||
if (dtr < 0)
|
||||
return dtr;
|
||||
|
||||
|
@ -676,7 +675,7 @@ static ssize_t
|
|||
isl1208_sysfs_show_usr(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int usr = isl1208_i2c_get_usr(to_i2c_client(dev));
|
||||
int usr = isl1208_i2c_get_usr(to_i2c_client(dev->parent));
|
||||
if (usr < 0)
|
||||
return usr;
|
||||
|
||||
|
@ -701,7 +700,10 @@ isl1208_sysfs_store_usr(struct device *dev,
|
|||
if (usr < 0 || usr > 0xffff)
|
||||
return -EINVAL;
|
||||
|
||||
return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
|
||||
if (isl1208_i2c_set_usr(to_i2c_client(dev->parent), usr))
|
||||
return -EIO;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
|
||||
|
@ -765,7 +767,6 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
rtc->ops = &isl1208_rtc_ops;
|
||||
|
||||
i2c_set_clientdata(client, rtc);
|
||||
dev_set_drvdata(&rtc->dev, client);
|
||||
|
||||
rc = isl1208_i2c_get_sr(client);
|
||||
if (rc < 0) {
|
||||
|
@ -804,7 +805,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
evdet_irq = of_irq_get_byname(np, "evdet");
|
||||
}
|
||||
|
||||
rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
|
||||
rc = rtc_add_group(rtc, &isl1208_rtc_sysfs_files);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -821,14 +822,6 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
return rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static int
|
||||
isl1208_remove(struct i2c_client *client)
|
||||
{
|
||||
sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id isl1208_id[] = {
|
||||
{ "isl1208", TYPE_ISL1208 },
|
||||
{ "isl1218", TYPE_ISL1218 },
|
||||
|
@ -851,7 +844,6 @@ static struct i2c_driver isl1208_driver = {
|
|||
.of_match_table = of_match_ptr(isl1208_of_match),
|
||||
},
|
||||
.probe = isl1208_probe,
|
||||
.remove = isl1208_remove,
|
||||
.id_table = isl1208_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ EXPORT_SYMBOL(rtc_year_days);
|
|||
|
||||
|
||||
/*
|
||||
* rtc_time_to_tm64 - Converts time64_t to rtc_time.
|
||||
* rtc_time64_to_tm - Converts time64_t to rtc_time.
|
||||
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
|
||||
*/
|
||||
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
|
||||
|
|
|
@ -745,7 +745,7 @@ static int wdt_ioctl(struct file *file, unsigned int cmd,
|
|||
return -EINVAL;
|
||||
wdt_margin = new_margin;
|
||||
wdt_ping();
|
||||
/* Fall */
|
||||
/* Fall through */
|
||||
case WDIOC_GETTIMEOUT:
|
||||
return put_user(wdt_margin, (int __user *)arg);
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time)
|
|||
unsigned long flags;
|
||||
|
||||
if (vrtc_is_updating())
|
||||
mdelay(20);
|
||||
msleep(20);
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
time->tm_sec = vrtc_cmos_read(RTC_SECONDS);
|
||||
|
@ -261,11 +261,10 @@ static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
|
||||
static int mrst_procfs(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
unsigned char rtc_control, valid;
|
||||
unsigned char rtc_control;
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
rtc_control = vrtc_cmos_read(RTC_CONTROL);
|
||||
valid = vrtc_cmos_read(RTC_VALID);
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
seq_printf(seq,
|
||||
|
|
|
@ -332,6 +332,10 @@ static int mtk_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(rtc->dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
ret = request_threaded_irq(rtc->irq, NULL,
|
||||
mtk_rtc_irq_handler_thread,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
|
||||
|
@ -344,11 +348,11 @@ static int mtk_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
rtc->rtc_dev = rtc_device_register("mt6397-rtc", &pdev->dev,
|
||||
&mtk_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc_dev)) {
|
||||
rtc->rtc_dev->ops = &mtk_rtc_ops;
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register rtc device failed\n");
|
||||
ret = PTR_ERR(rtc->rtc_dev);
|
||||
goto out_free_irq;
|
||||
}
|
||||
|
||||
|
@ -365,7 +369,6 @@ static int mtk_rtc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct mt6397_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
rtc_device_unregister(rtc->rtc_dev);
|
||||
free_irq(rtc->irq, rtc->rtc_dev);
|
||||
irq_dispose_mapping(rtc->irq);
|
||||
|
||||
|
|
|
@ -125,13 +125,9 @@ static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
/* hw counts from year 2000, but tm_year is relative to 1900 */
|
||||
alm->time.tm_year = bcd2bin(year) + 100;
|
||||
|
||||
if (rtc_valid_tm(&alm->time) < 0) {
|
||||
dev_err(dev, "retrieved alarm date/time is not valid.\n");
|
||||
rtc_time_to_tm(0, &alm->time);
|
||||
}
|
||||
|
||||
alm->enabled = !!readl(ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
|
||||
return 0;
|
||||
|
||||
return rtc_valid_tm(&alm->time);
|
||||
}
|
||||
|
||||
static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
|
|
|
@ -421,12 +421,6 @@ static struct omap_rtc *omap_rtc_power_off_rtc;
|
|||
* The RTC can be used to control an external PMIC via the pmic_power_en pin,
|
||||
* which can be configured to transition to OFF on ALARM2 events.
|
||||
*
|
||||
* Notes:
|
||||
* The two-second alarm offset is the shortest offset possible as the alarm
|
||||
* registers must be set before the next timer update and the offset
|
||||
* calculation is too heavy for everything to be done within a single access
|
||||
* period (~15 us).
|
||||
*
|
||||
* Called with local interrupts disabled.
|
||||
*/
|
||||
static void omap_rtc_power_off(void)
|
||||
|
@ -434,6 +428,7 @@ static void omap_rtc_power_off(void)
|
|||
struct omap_rtc *rtc = omap_rtc_power_off_rtc;
|
||||
struct rtc_time tm;
|
||||
unsigned long now;
|
||||
int seconds;
|
||||
u32 val;
|
||||
|
||||
rtc->type->unlock(rtc);
|
||||
|
@ -441,11 +436,13 @@ static void omap_rtc_power_off(void)
|
|||
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
|
||||
rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
|
||||
|
||||
/* set alarm two seconds from now */
|
||||
again:
|
||||
/* set alarm one second from now */
|
||||
omap_rtc_read_time_raw(rtc, &tm);
|
||||
seconds = tm.tm_sec;
|
||||
bcd2tm(&tm);
|
||||
rtc_tm_to_time(&tm, &now);
|
||||
rtc_time_to_tm(now + 2, &tm);
|
||||
rtc_time_to_tm(now + 1, &tm);
|
||||
|
||||
if (tm2bcd(&tm) < 0) {
|
||||
dev_err(&rtc->rtc->dev, "power off failed\n");
|
||||
|
@ -470,14 +467,22 @@ static void omap_rtc_power_off(void)
|
|||
val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
|
||||
rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG,
|
||||
val | OMAP_RTC_INTERRUPTS_IT_ALARM2);
|
||||
|
||||
/* Retry in case roll over happened before alarm was armed. */
|
||||
if (rtc_read(rtc, OMAP_RTC_SECONDS_REG) != seconds) {
|
||||
val = rtc_read(rtc, OMAP_RTC_STATUS_REG);
|
||||
if (!(val & OMAP_RTC_STATUS_ALARM2))
|
||||
goto again;
|
||||
}
|
||||
|
||||
rtc->type->lock(rtc);
|
||||
|
||||
/*
|
||||
* Wait for alarm to trigger (within two seconds) and external PMIC to
|
||||
* Wait for alarm to trigger (within one second) and external PMIC to
|
||||
* power off the system. Add a 500 ms margin for external latencies
|
||||
* (e.g. debounce circuits).
|
||||
*/
|
||||
mdelay(2500);
|
||||
mdelay(1500);
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops omap_rtc_ops = {
|
||||
|
@ -721,8 +726,7 @@ static int omap_rtc_probe(struct platform_device *pdev)
|
|||
if (of_id) {
|
||||
rtc->type = of_id->data;
|
||||
rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
|
||||
of_property_read_bool(pdev->dev.of_node,
|
||||
"system-power-controller");
|
||||
of_device_is_system_power_controller(pdev->dev.of_node);
|
||||
} else {
|
||||
id_entry = platform_get_device_id(pdev);
|
||||
rtc->type = (void *)id_entry->driver_data;
|
||||
|
|
|
@ -112,6 +112,13 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
goto err_rtc;
|
||||
}
|
||||
|
||||
rtc->rtc = devm_rtc_allocate_device(&dev->dev);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
goto err_rtc;
|
||||
}
|
||||
|
||||
rtc->rtc->ops = &pl030_ops;
|
||||
rtc->base = ioremap(dev->res.start, resource_size(&dev->res));
|
||||
if (!rtc->base) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -128,12 +135,9 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
if (ret)
|
||||
goto err_irq;
|
||||
|
||||
rtc->rtc = rtc_device_register("pl030", &dev->dev, &pl030_ops,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
ret = rtc_register_device(rtc->rtc);
|
||||
if (ret)
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -154,7 +158,6 @@ static int pl030_remove(struct amba_device *dev)
|
|||
writel(0, rtc->base + RTC_CR);
|
||||
|
||||
free_irq(dev->irq[0], rtc);
|
||||
rtc_device_unregister(rtc->rtc);
|
||||
iounmap(rtc->base);
|
||||
amba_release_regions(dev);
|
||||
|
||||
|
|
|
@ -310,7 +310,6 @@ static int pl031_remove(struct amba_device *adev)
|
|||
device_init_wakeup(&adev->dev, false);
|
||||
if (adev->irq[0])
|
||||
free_irq(adev->irq[0], ldata);
|
||||
rtc_device_unregister(ldata->rtc);
|
||||
amba_release_regions(adev);
|
||||
|
||||
return 0;
|
||||
|
@ -383,24 +382,25 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
}
|
||||
|
||||
device_init_wakeup(&adev->dev, true);
|
||||
ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(ldata->rtc)) {
|
||||
ret = PTR_ERR(ldata->rtc);
|
||||
ldata->rtc = devm_rtc_allocate_device(&adev->dev);
|
||||
if (IS_ERR(ldata->rtc))
|
||||
return PTR_ERR(ldata->rtc);
|
||||
|
||||
ldata->rtc->ops = ops;
|
||||
|
||||
ret = rtc_register_device(ldata->rtc);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (adev->irq[0]) {
|
||||
ret = request_irq(adev->irq[0], pl031_interrupt,
|
||||
vendor->irqflags, "rtc-pl031", ldata);
|
||||
if (ret)
|
||||
goto out_no_irq;
|
||||
goto out;
|
||||
dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_no_irq:
|
||||
rtc_device_unregister(ldata->rtc);
|
||||
out:
|
||||
amba_release_regions(adev);
|
||||
err_req:
|
||||
|
|
|
@ -66,6 +66,17 @@ rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
u8 txbuf[5+7], *txp;
|
||||
int ret;
|
||||
|
||||
ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret & RS5C348_BIT_XSTP) {
|
||||
txbuf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
|
||||
txbuf[1] = 0;
|
||||
ret = spi_write_then_read(spi, txbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Transfer 5 bytes before writing SEC. This gives 31us for carry. */
|
||||
txp = txbuf;
|
||||
txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
|
||||
|
@ -102,6 +113,16 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
u8 txbuf[5], rxbuf[7];
|
||||
int ret;
|
||||
|
||||
ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret & RS5C348_BIT_VDET)
|
||||
dev_warn(&spi->dev, "voltage-low detected.\n");
|
||||
if (ret & RS5C348_BIT_XSTP) {
|
||||
dev_warn(&spi->dev, "oscillator-stop detected.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Transfer 5 byte befores reading SEC. This gives 31us for carry. */
|
||||
txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
|
||||
txbuf[1] = 0; /* dummy */
|
||||
|
@ -143,8 +164,6 @@ static const struct rtc_class_ops rs5c348_rtc_ops = {
|
|||
.set_time = rs5c348_rtc_set_time,
|
||||
};
|
||||
|
||||
static struct spi_driver rs5c348_driver;
|
||||
|
||||
static int rs5c348_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
|
@ -161,53 +180,27 @@ static int rs5c348_probe(struct spi_device *spi)
|
|||
ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_SECS));
|
||||
if (ret < 0 || (ret & 0x80)) {
|
||||
dev_err(&spi->dev, "not found.\n");
|
||||
goto kfree_exit;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&spi->dev, "spiclk %u KHz.\n",
|
||||
(spi->max_speed_hz + 500) / 1000);
|
||||
|
||||
/* turn RTC on if it was not on */
|
||||
ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
|
||||
if (ret < 0)
|
||||
goto kfree_exit;
|
||||
if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
|
||||
u8 buf[2];
|
||||
struct rtc_time tm;
|
||||
if (ret & RS5C348_BIT_VDET)
|
||||
dev_warn(&spi->dev, "voltage-low detected.\n");
|
||||
if (ret & RS5C348_BIT_XSTP)
|
||||
dev_warn(&spi->dev, "oscillator-stop detected.\n");
|
||||
rtc_time_to_tm(0, &tm); /* 1970/1/1 */
|
||||
ret = rs5c348_rtc_set_time(&spi->dev, &tm);
|
||||
if (ret < 0)
|
||||
goto kfree_exit;
|
||||
buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
|
||||
buf[1] = 0;
|
||||
ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
|
||||
if (ret < 0)
|
||||
goto kfree_exit;
|
||||
}
|
||||
|
||||
ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1));
|
||||
if (ret < 0)
|
||||
goto kfree_exit;
|
||||
return ret;
|
||||
if (ret & RS5C348_BIT_24H)
|
||||
pdata->rtc_24h = 1;
|
||||
|
||||
rtc = devm_rtc_device_register(&spi->dev, rs5c348_driver.driver.name,
|
||||
&rs5c348_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rtc)) {
|
||||
ret = PTR_ERR(rtc);
|
||||
goto kfree_exit;
|
||||
}
|
||||
rtc = devm_rtc_allocate_device(&spi->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
pdata->rtc = rtc;
|
||||
|
||||
return 0;
|
||||
kfree_exit:
|
||||
return ret;
|
||||
rtc->ops = &rs5c348_rtc_ops;
|
||||
|
||||
return rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static struct spi_driver rs5c348_driver = {
|
||||
|
|
|
@ -615,6 +615,7 @@ static int rv8803_probe(struct i2c_client *client,
|
|||
|
||||
static const struct i2c_device_id rv8803_id[] = {
|
||||
{ "rv8803", rv_8803 },
|
||||
{ "rx8803", rv_8803 },
|
||||
{ "rx8900", rx_8900 },
|
||||
{ }
|
||||
};
|
||||
|
@ -623,7 +624,11 @@ MODULE_DEVICE_TABLE(i2c, rv8803_id);
|
|||
static const struct of_device_id rv8803_of_match[] = {
|
||||
{
|
||||
.compatible = "microcrystal,rv8803",
|
||||
.data = (void *)rx_8900
|
||||
.data = (void *)rv_8803
|
||||
},
|
||||
{
|
||||
.compatible = "epson,rx8803",
|
||||
.data = (void *)rv_8803
|
||||
},
|
||||
{
|
||||
.compatible = "epson,rx8900",
|
||||
|
|
|
@ -108,7 +108,7 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
|
|||
|
||||
static int s35390a_init(struct s35390a *s35390a)
|
||||
{
|
||||
char buf;
|
||||
u8 buf;
|
||||
int ret;
|
||||
unsigned initcount = 0;
|
||||
|
||||
|
|
|
@ -129,19 +129,6 @@ static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc)
|
|||
SPRD_RTC_ALM_INT_MASK);
|
||||
}
|
||||
|
||||
static int sprd_rtc_disable_ints(struct sprd_rtc *rtc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
|
||||
SPRD_RTC_INT_MASK, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
|
||||
SPRD_RTC_INT_MASK);
|
||||
}
|
||||
|
||||
static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
|
||||
{
|
||||
int ret;
|
||||
|
@ -172,7 +159,8 @@ static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
|
|||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
|
||||
SPRD_RTC_SPG_UPD_EN);
|
||||
}
|
||||
|
||||
static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
|
||||
|
@ -427,10 +415,14 @@ static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
u32 val;
|
||||
|
||||
/*
|
||||
* If aie_timer is enabled, we should get the normal alarm time.
|
||||
* Before RTC device is registered, it will check to see if there is an
|
||||
* alarm already set in RTC hardware, and we always read the normal
|
||||
* alarm at this time.
|
||||
*
|
||||
* Or if aie_timer is enabled, we should get the normal alarm time.
|
||||
* Otherwise we should get auxiliary alarm time.
|
||||
*/
|
||||
if (rtc->rtc && rtc->rtc->aie_timer.enabled == 0)
|
||||
if (rtc->rtc && rtc->rtc->registered && rtc->rtc->aie_timer.enabled == 0)
|
||||
return sprd_rtc_read_aux_alarm(dev, alrm);
|
||||
|
||||
ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs);
|
||||
|
@ -575,6 +567,32 @@ static int sprd_rtc_check_power_down(struct sprd_rtc *rtc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_rtc_check_alarm_int(struct sprd_rtc *rtc)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The SPRD_RTC_INT_EN register is not put in always-power-on region
|
||||
* supplied by VDDRTC, so we should check if we need enable the alarm
|
||||
* interrupt when system booting.
|
||||
*
|
||||
* If we have set SPRD_RTC_POWEROFF_ALM_FLAG which is saved in
|
||||
* always-power-on region, that means we have set one alarm last time,
|
||||
* so we should enable the alarm interrupt to help RTC core to see if
|
||||
* there is an alarm already set in RTC hardware.
|
||||
*/
|
||||
if (!(val & SPRD_RTC_POWEROFF_ALM_FLAG))
|
||||
return 0;
|
||||
|
||||
return regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
|
||||
SPRD_RTC_ALARM_EN, SPRD_RTC_ALARM_EN);
|
||||
}
|
||||
|
||||
static int sprd_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
@ -608,10 +626,10 @@ static int sprd_rtc_probe(struct platform_device *pdev)
|
|||
rtc->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
/* clear all RTC interrupts and disable all RTC interrupts */
|
||||
ret = sprd_rtc_disable_ints(rtc);
|
||||
/* check if we need set the alarm interrupt */
|
||||
ret = sprd_rtc_check_alarm_int(rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to disable RTC interrupts\n");
|
||||
dev_err(&pdev->dev, "failed to check RTC alarm interrupt\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -631,16 +649,18 @@ static int sprd_rtc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
rtc->rtc->ops = &sprd_rtc_ops;
|
||||
rtc->rtc->range_min = 0;
|
||||
rtc->rtc->range_max = 5662310399LL;
|
||||
ret = rtc_register_device(rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register rtc device\n");
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -199,8 +199,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
|
|||
if (!rtc)
|
||||
return;
|
||||
|
||||
clk_data = kzalloc(sizeof(*clk_data) + (sizeof(*clk_data->hws) * 2),
|
||||
GFP_KERNEL);
|
||||
clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL);
|
||||
if (!clk_data) {
|
||||
kfree(rtc);
|
||||
return;
|
||||
|
|
|
@ -338,8 +338,8 @@ int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
|
|||
|
||||
new_cnt = old_cnt + add_cnt + 1;
|
||||
groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(groups))
|
||||
return PTR_ERR(groups);
|
||||
if (!groups)
|
||||
return -ENOMEM;
|
||||
memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups));
|
||||
memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups));
|
||||
groups[old_cnt + add_cnt] = NULL;
|
||||
|
|
|
@ -322,9 +322,13 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(info->rtc_base))
|
||||
return PTR_ERR(info->rtc_base);
|
||||
|
||||
info->tegra_rtc_irq = platform_get_irq(pdev, 0);
|
||||
if (info->tegra_rtc_irq <= 0)
|
||||
return -EBUSY;
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "failed to get platform IRQ: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
info->tegra_rtc_irq = ret;
|
||||
|
||||
info->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(info->clk))
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* An RTC test device/driver
|
||||
* Copyright (C) 2005 Tower Technologies
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* 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/module.h>
|
||||
|
@ -197,7 +194,7 @@ static void __exit test_exit(void)
|
|||
|
||||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("RTC test driver/device");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
module_init(test_init);
|
||||
module_exit(test_exit);
|
||||
|
|
|
@ -253,9 +253,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int irq, ret;
|
||||
struct nvmem_config nvmem_cfg = {
|
||||
.name = "rv8803_nvram",
|
||||
.word_size = 4,
|
||||
.stride = 4,
|
||||
.name = "tx4939_nvram",
|
||||
.size = TX4939_RTC_REG_RAMSIZE,
|
||||
.reg_read = tx4939_nvram_read,
|
||||
.reg_write = tx4939_nvram_write,
|
||||
|
|
|
@ -136,8 +136,7 @@ static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time)
|
|||
time64_t epoch_sec, current_sec;
|
||||
|
||||
epoch_sec = mktime64(epoch, 1, 1, 0, 0, 0);
|
||||
current_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
current_sec = rtc_tm_to_time64(time);
|
||||
|
||||
write_elapsed_second(current_sec - epoch_sec);
|
||||
|
||||
|
@ -158,7 +157,7 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
rtc_time_to_tm((high << 17) | (mid << 1) | (low >> 15), time);
|
||||
rtc_time64_to_tm((high << 17) | (mid << 1) | (low >> 15), time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -166,10 +165,8 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||
static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
time64_t alarm_sec;
|
||||
struct rtc_time *time = &wkalrm->time;
|
||||
|
||||
alarm_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
alarm_sec = rtc_tm_to_time64(&wkalrm->time);
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
|
||||
|
|
|
@ -167,17 +167,12 @@ struct rtc_device {
|
|||
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
||||
#define RTC_TIMESTAMP_END_2099 4102444799LL /* 2099-12-31 23:59:59 */
|
||||
|
||||
extern struct rtc_device *rtc_device_register(const char *name,
|
||||
struct device *dev,
|
||||
const struct rtc_class_ops *ops,
|
||||
struct module *owner);
|
||||
extern struct rtc_device *devm_rtc_device_register(struct device *dev,
|
||||
const char *name,
|
||||
const struct rtc_class_ops *ops,
|
||||
struct module *owner);
|
||||
struct rtc_device *devm_rtc_allocate_device(struct device *dev);
|
||||
int __rtc_register_device(struct module *owner, struct rtc_device *rtc);
|
||||
extern void rtc_device_unregister(struct rtc_device *rtc);
|
||||
extern void devm_rtc_device_unregister(struct device *dev,
|
||||
struct rtc_device *rtc);
|
||||
|
||||
|
@ -277,4 +272,20 @@ static inline int rtc_nvmem_register(struct rtc_device *rtc,
|
|||
static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTC_INTF_SYSFS
|
||||
int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp);
|
||||
int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps);
|
||||
#else
|
||||
static inline
|
||||
int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* _LINUX_RTC_H_ */
|
||||
|
|
Loading…
Reference in New Issue