RTC for 5.16
Subsystem: - Add new ioctl to get and set extra RTC parameters, this includes backup switch mode - Expose available features to userspace, in particular, when alarmas have a resolution of one minute instead of a second. - Let the core handle those alarms with a minute resolution New driver: - MSTAR MSC313 RTC Drivers: - Add SPI ID table where necessary - Add BSM support for rv3028, rv3032 and pcf8523 - s3c: set RTC range - rx8025: set range, implement .set_offset and .read_offset -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmGNm7AACgkQY6TcMGxw OjJBeA/+PHmLq0v1olnG2kx0Ch7nzYzonCO+3tvPi5xoPKUZln5TpdSqAECqDC6g PizHUdJaBNTc3Y7GMUkryuuWq67kYlzx1N7EHZqgARk7s6hus+SJmQb7kiCbiawD pP62na7ZJDCs6S70WD9VMCJQ21xokwwTWzL7nVD98LN1qkQCj4cSuoDPBEJQyeG2 S5Xi1CePW84c9eKx4Sy//bzLnCpSqb6tDHfsexwmLFTk5WN0onZRZSYD0/loY8N+ EEMX0Ts/9ERqM5QALDMB4YQNWvRCtGP7Fl0QPtVRXC2MXyg/GYhdC2F2SvQmYCRC VZoZwCJ82x4Pa2UTdg2L3WD0uKrvycnRaAYV71CME5PkAw1hQqLz3HZwjYXkITvp crhZQvCGHn9w2UOEAKnWWnCLsl3paWXkN0zGeFhYYGeAIf79fRnIGc3cGubjSgiv 9WU9oRL8EzY5bL07fP5P81leknzROZmK3Re6vefI5o2A4qY0qP9mU6zVKxZy/iHd 7GiE5jNact0oUB7Vhakh4wUchyOJCPZSFxfeNqPJzs6FlVUR74Ulw05Sywnz+W7a oXtODF0cmJPVeUJYmo5EKfLAId4iPmcq8Fh16ayw4595pwc6iHE+GRL6j7Zjk+AX u9UA2qXqYhE5PgcxC6pd/hMV29p1S81BKdjyf0HF7oxWgBoT1lc= =pTlj -----END PGP SIGNATURE----- Merge tag 'rtc-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "This includes new ioctls to get and set parameters and in particular the backup switch mode that is needed for some RTCs to actually enable the backup voltage (and have a useful RTC). The same interface can also be used to get the actual features supported by the RTC so userspace has a better way than trying and failing. Summary: Subsystem: - Add new ioctl to get and set extra RTC parameters, this includes backup switch mode - Expose available features to userspace, in particular, when alarmas have a resolution of one minute instead of a second. - Let the core handle those alarms with a minute resolution New driver: - MSTAR MSC313 RTC Drivers: - Add SPI ID table where necessary - Add BSM support for rv3028, rv3032 and pcf8523 - s3c: set RTC range - rx8025: set range, implement .set_offset and .read_offset" * tag 'rtc-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (50 commits) rtc: rx8025: use .set_offset/.read_offset rtc: rx8025: use rtc_add_group rtc: rx8025: clear RTC_FEATURE_ALARM when alarm are not supported rtc: rx8025: set range rtc: rx8025: let the core handle the alarm resolution rtc: rx8025: switch to devm_rtc_allocate_device rtc: ab8500: let the core handle the alarm resolution rtc: ab-eoz9: support UIE when available rtc: ab-eoz9: use RTC_FEATURE_UPDATE_INTERRUPT rtc: rv3032: let the core handle the alarm resolution rtc: s35390a: let the core handle the alarm resolution rtc: handle alarms with a minute resolution rtc: pcf85063: silence cppcheck warning rtc: rv8803: fix writing back ctrl in flag register rtc: s3c: Add time range rtc: s3c: Extract read/write IO into separate functions rtc: s3c: Remove usage of devm_rtc_device_register() rtc: tps80031: Remove driver rtc: sun6i: Allow probing without an early clock provider rtc: pcf8523: add BSM support ...
This commit is contained in:
commit
3b81bf78b7
49
Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml
Normal file
49
Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml
Normal file
@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/mstar,msc313-rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mstar MSC313e RTC Device Tree Bindings
|
||||
|
||||
allOf:
|
||||
- $ref: "rtc.yaml#"
|
||||
|
||||
maintainers:
|
||||
- Daniel Palmer <daniel@0x0f.com>
|
||||
- Romain Perier <romain.perier@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mstar,msc313-rtc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
start-year: true
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
rtc@2400 {
|
||||
compatible = "mstar,msc313-rtc";
|
||||
reg = <0x2400 0x40>;
|
||||
clocks = <&xtal_div2>;
|
||||
interrupts-extended = <&intc_irq GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
...
|
@ -13,10 +13,19 @@ Optional property:
|
||||
expressed in femto Farad (fF). Valid values are 7000 and 12500.
|
||||
Default value (if no value is specified) is 7000fF.
|
||||
|
||||
Optional child node:
|
||||
- clock: Provide this if the square wave pin is used as boot-enabled fixed clock.
|
||||
|
||||
Example:
|
||||
|
||||
pcf85063: rtc@51 {
|
||||
compatible = "nxp,pcf85063";
|
||||
reg = <0x51>;
|
||||
quartz-load-femtofarads = <12500>;
|
||||
|
||||
clock {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
@ -2283,6 +2283,7 @@ F: arch/arm/boot/dts/mstar-*
|
||||
F: arch/arm/mach-mstar/
|
||||
F: drivers/clk/mstar/
|
||||
F: drivers/gpio/gpio-msc313.c
|
||||
F: drivers/rtc/rtc-msc313.c
|
||||
F: drivers/watchdog/msc313e_wdt.c
|
||||
F: include/dt-bindings/clock/mstar-*
|
||||
F: include/dt-bindings/gpio/msc313-gpio.h
|
||||
|
@ -441,6 +441,7 @@ config RTC_DRV_X1205
|
||||
|
||||
config RTC_DRV_PCF8523
|
||||
tristate "NXP PCF8523"
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the NXP PCF8523 RTC
|
||||
chips.
|
||||
@ -582,14 +583,6 @@ config RTC_DRV_TPS65910
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-tps65910.
|
||||
|
||||
config RTC_DRV_TPS80031
|
||||
tristate "TI TPS80031/TPS80032 RTC driver"
|
||||
depends on MFD_TPS80031
|
||||
help
|
||||
TI Power Management IC TPS80031 supports RTC functionality
|
||||
along with alarm. This driver supports the RTC driver for
|
||||
the TPS80031 RTC module.
|
||||
|
||||
config RTC_DRV_RC5T583
|
||||
tristate "RICOH 5T583 RTC driver"
|
||||
depends on MFD_RC5T583
|
||||
@ -1929,4 +1922,14 @@ config RTC_DRV_WILCO_EC
|
||||
This can also be built as a module. If so, the module will
|
||||
be named "rtc_wilco_ec".
|
||||
|
||||
config RTC_DRV_MSC313
|
||||
tristate "MStar MSC313 RTC"
|
||||
depends on ARCH_MSTARV7 || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for the Mstar MSC313e On-Chip
|
||||
Real Time Clock.
|
||||
|
||||
This driver can also be built as a module, if so, the module
|
||||
will be called "rtc-msc313".
|
||||
|
||||
endif # RTC_CLASS
|
||||
|
@ -103,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
|
||||
obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o
|
||||
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
|
||||
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
|
||||
obj-$(CONFIG_RTC_DRV_MSC313) += rtc-msc313.o
|
||||
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
|
||||
obj-$(CONFIG_RTC_DRV_MT2712) += rtc-mt2712.o
|
||||
obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
|
||||
@ -169,7 +170,6 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
|
||||
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.o
|
||||
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
|
||||
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
|
||||
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
|
||||
|
@ -232,6 +232,7 @@ static struct rtc_device *rtc_allocate_device(void)
|
||||
rtc->pie_enabled = 0;
|
||||
|
||||
set_bit(RTC_FEATURE_ALARM, rtc->features);
|
||||
set_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
|
||||
|
||||
return rtc;
|
||||
}
|
||||
@ -334,7 +335,8 @@ static void devm_rtc_unregister_device(void *data)
|
||||
* letting any rtc_class_open() users access it again
|
||||
*/
|
||||
rtc_proc_del_device(rtc);
|
||||
cdev_device_del(&rtc->char_dev, &rtc->dev);
|
||||
if (!test_bit(RTC_NO_CDEV, &rtc->flags))
|
||||
cdev_device_del(&rtc->char_dev, &rtc->dev);
|
||||
rtc->ops = NULL;
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
}
|
||||
@ -363,7 +365,9 @@ struct rtc_device *devm_rtc_allocate_device(struct device *dev)
|
||||
|
||||
rtc->id = id;
|
||||
rtc->dev.parent = dev;
|
||||
dev_set_name(&rtc->dev, "rtc%d", id);
|
||||
err = dev_set_name(&rtc->dev, "rtc%d", id);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = devm_add_action_or_reset(dev, devm_rtc_release_device, rtc);
|
||||
if (err)
|
||||
@ -386,6 +390,12 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc)
|
||||
if (!rtc->ops->set_alarm)
|
||||
clear_bit(RTC_FEATURE_ALARM, rtc->features);
|
||||
|
||||
if (rtc->uie_unsupported)
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
|
||||
|
||||
if (rtc->ops->set_offset)
|
||||
set_bit(RTC_FEATURE_CORRECTION, rtc->features);
|
||||
|
||||
rtc->owner = owner;
|
||||
rtc_device_get_offset(rtc);
|
||||
|
||||
@ -397,12 +407,14 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc)
|
||||
rtc_dev_prepare(rtc);
|
||||
|
||||
err = cdev_device_add(&rtc->char_dev, &rtc->dev);
|
||||
if (err)
|
||||
if (err) {
|
||||
set_bit(RTC_NO_CDEV, &rtc->flags);
|
||||
dev_warn(rtc->dev.parent, "failed to add char device %d:%d\n",
|
||||
MAJOR(rtc->dev.devt), rtc->id);
|
||||
else
|
||||
} else {
|
||||
dev_dbg(rtc->dev.parent, "char device (%d:%d)\n",
|
||||
MAJOR(rtc->dev.devt), rtc->id);
|
||||
}
|
||||
|
||||
rtc_proc_add_device(rtc);
|
||||
|
||||
|
@ -208,6 +208,7 @@ static long rtc_dev_ioctl(struct file *file,
|
||||
const struct rtc_class_ops *ops = rtc->ops;
|
||||
struct rtc_time tm;
|
||||
struct rtc_wkalrm alarm;
|
||||
struct rtc_param param;
|
||||
void __user *uarg = (void __user *)arg;
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
@ -221,6 +222,7 @@ static long rtc_dev_ioctl(struct file *file,
|
||||
switch (cmd) {
|
||||
case RTC_EPOCH_SET:
|
||||
case RTC_SET_TIME:
|
||||
case RTC_PARAM_SET:
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
err = -EACCES;
|
||||
break;
|
||||
@ -382,6 +384,69 @@ static long rtc_dev_ioctl(struct file *file,
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
|
||||
case RTC_PARAM_GET:
|
||||
if (copy_from_user(¶m, uarg, sizeof(param))) {
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
switch(param.param) {
|
||||
long offset;
|
||||
case RTC_PARAM_FEATURES:
|
||||
if (param.index != 0)
|
||||
err = -EINVAL;
|
||||
param.uvalue = rtc->features[0];
|
||||
break;
|
||||
|
||||
case RTC_PARAM_CORRECTION:
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
if (param.index != 0)
|
||||
return -EINVAL;
|
||||
err = rtc_read_offset(rtc, &offset);
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
if (err == 0)
|
||||
param.svalue = offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (rtc->ops->param_get)
|
||||
err = rtc->ops->param_get(rtc->dev.parent, ¶m);
|
||||
else
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
if (copy_to_user(uarg, ¶m, sizeof(param)))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case RTC_PARAM_SET:
|
||||
if (copy_from_user(¶m, uarg, sizeof(param))) {
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
switch(param.param) {
|
||||
case RTC_PARAM_FEATURES:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
||||
case RTC_PARAM_CORRECTION:
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
if (param.index != 0)
|
||||
return -EINVAL;
|
||||
return rtc_set_offset(rtc, param.svalue);
|
||||
|
||||
default:
|
||||
if (rtc->ops->param_set)
|
||||
err = rtc->ops->param_set(rtc->dev.parent, ¶m);
|
||||
else
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Finally try the driver's ioctl interface */
|
||||
if (ops->ioctl) {
|
||||
|
@ -423,6 +423,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
if (err)
|
||||
return err;
|
||||
now = rtc_tm_to_time64(&tm);
|
||||
|
||||
if (scheduled <= now)
|
||||
return -ETIME;
|
||||
/*
|
||||
@ -447,6 +448,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
|
||||
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
ktime_t alarm_time;
|
||||
int err;
|
||||
|
||||
if (!rtc->ops)
|
||||
@ -468,7 +470,15 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
if (rtc->aie_timer.enabled)
|
||||
rtc_timer_remove(rtc, &rtc->aie_timer);
|
||||
|
||||
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
|
||||
alarm_time = rtc_tm_to_ktime(alarm->time);
|
||||
/*
|
||||
* Round down so we never miss a deadline, checking for past deadline is
|
||||
* done in __rtc_set_alarm
|
||||
*/
|
||||
if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features))
|
||||
alarm_time = ktime_sub_ns(alarm_time, (u64)alarm->time.tm_sec * NSEC_PER_SEC);
|
||||
|
||||
rtc->aie_timer.node.expires = alarm_time;
|
||||
rtc->aie_timer.period = 0;
|
||||
if (alarm->enabled)
|
||||
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
|
||||
@ -561,7 +571,8 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
||||
if (rtc->uie_rtctimer.enabled == enabled)
|
||||
goto out;
|
||||
|
||||
if (rtc->uie_unsupported || !test_bit(RTC_FEATURE_ALARM, rtc->features)) {
|
||||
if (!test_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features) ||
|
||||
!test_bit(RTC_FEATURE_ALARM, rtc->features)) {
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
||||
return rtc_dev_update_irq_enable_emul(rtc, enabled);
|
||||
|
@ -534,7 +534,6 @@ static int abeoz9_probe(struct i2c_client *client,
|
||||
data->rtc->ops = &rtc_ops;
|
||||
data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
data->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
data->rtc->uie_unsupported = 1;
|
||||
clear_bit(RTC_FEATURE_ALARM, data->rtc->features);
|
||||
|
||||
if (client->irq > 0) {
|
||||
@ -546,6 +545,8 @@ static int abeoz9_probe(struct i2c_client *client,
|
||||
dev_err(dev, "failed to request alarm irq\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, data->rtc->features);
|
||||
}
|
||||
|
||||
if (client->irq > 0 || device_property_read_bool(dev, "wakeup-source")) {
|
||||
|
@ -184,25 +184,9 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int retval, i;
|
||||
unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
|
||||
unsigned long mins, secs = 0, cursec = 0;
|
||||
struct rtc_time curtm;
|
||||
unsigned long mins;
|
||||
|
||||
/* Get the number of seconds since 1970 */
|
||||
secs = rtc_tm_to_time64(&alarm->time);
|
||||
|
||||
/*
|
||||
* Check whether alarm is set less than 1min.
|
||||
* Since our RTC doesn't support alarm resolution less than 1min,
|
||||
* return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON
|
||||
*/
|
||||
ab8500_rtc_read_time(dev, &curtm); /* Read current time */
|
||||
cursec = rtc_tm_to_time64(&curtm);
|
||||
if ((secs - cursec) < 59) {
|
||||
dev_dbg(dev, "Alarm less than 1 minute not supported\r\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mins = secs / 60;
|
||||
mins = (unsigned long)rtc_tm_to_time64(&alarm->time) / 60;
|
||||
|
||||
buf[2] = mins & 0xFF;
|
||||
buf[1] = (mins >> 8) & 0xFF;
|
||||
@ -394,7 +378,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
|
||||
dev_pm_set_wake_irq(&pdev->dev, irq);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
rtc->uie_unsupported = 1;
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
|
||||
|
||||
rtc->range_max = (1ULL << 24) * 60 - 1; // 24-bit minutes + 59 secs
|
||||
rtc->start_secs = RTC_TIMESTAMP_BEGIN_2000;
|
||||
|
@ -199,11 +199,18 @@ static const struct of_device_id ds1302_dt_ids[] = {
|
||||
MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id ds1302_spi_ids[] = {
|
||||
{ .name = "ds1302", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ds1302_spi_ids);
|
||||
|
||||
static struct spi_driver ds1302_driver = {
|
||||
.driver.name = "rtc-ds1302",
|
||||
.driver.of_match_table = of_match_ptr(ds1302_dt_ids),
|
||||
.probe = ds1302_probe,
|
||||
.remove = ds1302_remove,
|
||||
.id_table = ds1302_spi_ids,
|
||||
};
|
||||
|
||||
module_spi_driver(ds1302_driver);
|
||||
|
@ -219,12 +219,19 @@ static const struct of_device_id ds1390_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ds1390_of_match);
|
||||
|
||||
static const struct spi_device_id ds1390_spi_ids[] = {
|
||||
{ .name = "ds1390" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ds1390_spi_ids);
|
||||
|
||||
static struct spi_driver ds1390_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-ds1390",
|
||||
.of_match_table = of_match_ptr(ds1390_of_match),
|
||||
},
|
||||
.probe = ds1390_probe,
|
||||
.id_table = ds1390_spi_ids,
|
||||
};
|
||||
|
||||
module_spi_driver(ds1390_driver);
|
||||
|
@ -557,7 +557,7 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
|
||||
* registered automatically when being referenced.
|
||||
*/
|
||||
of_node_put(fixed_clock);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* First disable the clock */
|
||||
|
@ -430,12 +430,19 @@ static const struct of_device_id mcp795_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, mcp795_of_match);
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id mcp795_spi_ids[] = {
|
||||
{ .name = "mcp795" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, mcp795_spi_ids);
|
||||
|
||||
static struct spi_driver mcp795_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-mcp795",
|
||||
.of_match_table = of_match_ptr(mcp795_of_match),
|
||||
},
|
||||
.probe = mcp795_probe,
|
||||
.id_table = mcp795_spi_ids,
|
||||
};
|
||||
|
||||
module_spi_driver(mcp795_driver);
|
||||
|
259
drivers/rtc/rtc-msc313.c
Normal file
259
drivers/rtc/rtc-msc313.c
Normal file
@ -0,0 +1,259 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Real time clocks driver for MStar/SigmaStar ARMv7 SoCs.
|
||||
* Based on "Real Time Clock driver for msb252x." that was contained
|
||||
* in various MStar kernels.
|
||||
*
|
||||
* (C) 2019 Daniel Palmer
|
||||
* (C) 2021 Romain Perier
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/* Registers */
|
||||
#define REG_RTC_CTRL 0x00
|
||||
#define REG_RTC_FREQ_CW_L 0x04
|
||||
#define REG_RTC_FREQ_CW_H 0x08
|
||||
#define REG_RTC_LOAD_VAL_L 0x0C
|
||||
#define REG_RTC_LOAD_VAL_H 0x10
|
||||
#define REG_RTC_MATCH_VAL_L 0x14
|
||||
#define REG_RTC_MATCH_VAL_H 0x18
|
||||
#define REG_RTC_STATUS_INT 0x1C
|
||||
#define REG_RTC_CNT_VAL_L 0x20
|
||||
#define REG_RTC_CNT_VAL_H 0x24
|
||||
|
||||
/* Control bits for REG_RTC_CTRL */
|
||||
#define SOFT_RSTZ_BIT BIT(0)
|
||||
#define CNT_EN_BIT BIT(1)
|
||||
#define WRAP_EN_BIT BIT(2)
|
||||
#define LOAD_EN_BIT BIT(3)
|
||||
#define READ_EN_BIT BIT(4)
|
||||
#define INT_MASK_BIT BIT(5)
|
||||
#define INT_FORCE_BIT BIT(6)
|
||||
#define INT_CLEAR_BIT BIT(7)
|
||||
|
||||
/* Control bits for REG_RTC_STATUS_INT */
|
||||
#define RAW_INT_BIT BIT(0)
|
||||
#define ALM_INT_BIT BIT(1)
|
||||
|
||||
struct msc313_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *rtc_base;
|
||||
};
|
||||
|
||||
static int msc313_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct msc313_rtc *priv = dev_get_drvdata(dev);
|
||||
unsigned long seconds;
|
||||
|
||||
seconds = readw(priv->rtc_base + REG_RTC_MATCH_VAL_L)
|
||||
| ((unsigned long)readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16);
|
||||
|
||||
rtc_time64_to_tm(seconds, &alarm->time);
|
||||
|
||||
if (!(readw(priv->rtc_base + REG_RTC_CTRL) & INT_MASK_BIT))
|
||||
alarm->enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msc313_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct msc313_rtc *priv = dev_get_drvdata(dev);
|
||||
u16 reg;
|
||||
|
||||
reg = readw(priv->rtc_base + REG_RTC_CTRL);
|
||||
if (enabled)
|
||||
reg &= ~INT_MASK_BIT;
|
||||
else
|
||||
reg |= INT_MASK_BIT;
|
||||
writew(reg, priv->rtc_base + REG_RTC_CTRL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msc313_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct msc313_rtc *priv = dev_get_drvdata(dev);
|
||||
unsigned long seconds;
|
||||
|
||||
seconds = rtc_tm_to_time64(&alarm->time);
|
||||
writew((seconds & 0xFFFF), priv->rtc_base + REG_RTC_MATCH_VAL_L);
|
||||
writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_MATCH_VAL_H);
|
||||
|
||||
msc313_rtc_alarm_irq_enable(dev, alarm->enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool msc313_rtc_get_enabled(struct msc313_rtc *priv)
|
||||
{
|
||||
return readw(priv->rtc_base + REG_RTC_CTRL) & CNT_EN_BIT;
|
||||
}
|
||||
|
||||
static void msc313_rtc_set_enabled(struct msc313_rtc *priv)
|
||||
{
|
||||
u16 reg;
|
||||
|
||||
reg = readw(priv->rtc_base + REG_RTC_CTRL);
|
||||
reg |= CNT_EN_BIT;
|
||||
writew(reg, priv->rtc_base + REG_RTC_CTRL);
|
||||
}
|
||||
|
||||
static int msc313_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct msc313_rtc *priv = dev_get_drvdata(dev);
|
||||
u32 seconds;
|
||||
u16 reg;
|
||||
|
||||
if (!msc313_rtc_get_enabled(priv))
|
||||
return -EINVAL;
|
||||
|
||||
reg = readw(priv->rtc_base + REG_RTC_CTRL);
|
||||
writew(reg | READ_EN_BIT, priv->rtc_base + REG_RTC_CTRL);
|
||||
|
||||
/* Wait for HW latch done */
|
||||
while (readw(priv->rtc_base + REG_RTC_CTRL) & READ_EN_BIT)
|
||||
udelay(1);
|
||||
|
||||
seconds = readw(priv->rtc_base + REG_RTC_CNT_VAL_L)
|
||||
| ((unsigned long)readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16);
|
||||
|
||||
rtc_time64_to_tm(seconds, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msc313_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct msc313_rtc *priv = dev_get_drvdata(dev);
|
||||
unsigned long seconds;
|
||||
u16 reg;
|
||||
|
||||
seconds = rtc_tm_to_time64(tm);
|
||||
writew(seconds & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_L);
|
||||
writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_H);
|
||||
|
||||
/* Enable load for loading value into internal RTC counter */
|
||||
reg = readw(priv->rtc_base + REG_RTC_CTRL);
|
||||
writew(reg | LOAD_EN_BIT, priv->rtc_base + REG_RTC_CTRL);
|
||||
|
||||
/* Wait for HW latch done */
|
||||
while (readw(priv->rtc_base + REG_RTC_CTRL) & LOAD_EN_BIT)
|
||||
udelay(1);
|
||||
msc313_rtc_set_enabled(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops msc313_rtc_ops = {
|
||||
.read_time = msc313_rtc_read_time,
|
||||
.set_time = msc313_rtc_set_time,
|
||||
.read_alarm = msc313_rtc_read_alarm,
|
||||
.set_alarm = msc313_rtc_set_alarm,
|
||||
.alarm_irq_enable = msc313_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static irqreturn_t msc313_rtc_interrupt(s32 irq, void *dev_id)
|
||||
{
|
||||
struct msc313_rtc *priv = dev_get_drvdata(dev_id);
|
||||
u16 reg;
|
||||
|
||||
reg = readw(priv->rtc_base + REG_RTC_STATUS_INT);
|
||||
if (!(reg & ALM_INT_BIT))
|
||||
return IRQ_NONE;
|
||||
|
||||
reg = readw(priv->rtc_base + REG_RTC_CTRL);
|
||||
reg |= INT_CLEAR_BIT;
|
||||
reg &= ~INT_FORCE_BIT;
|
||||
writew(reg, priv->rtc_base + REG_RTC_CTRL);
|
||||
|
||||
rtc_update_irq(priv->rtc_dev, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int msc313_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct msc313_rtc *priv;
|
||||
unsigned long rate;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct msc313_rtc), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->rtc_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->rtc_base))
|
||||
return PTR_ERR(priv->rtc_base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return -EINVAL;
|
||||
|
||||
priv->rtc_dev = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(priv->rtc_dev))
|
||||
return PTR_ERR(priv->rtc_dev);
|
||||
|
||||
priv->rtc_dev->ops = &msc313_rtc_ops;
|
||||
priv->rtc_dev->range_max = U32_MAX;
|
||||
|
||||
ret = devm_request_irq(dev, irq, msc313_rtc_interrupt, IRQF_SHARED,
|
||||
dev_name(&pdev->dev), &pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not request IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "No input reference clock\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable the reference clock, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
writew(rate & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_L);
|
||||
writew((rate >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_H);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return devm_rtc_register_device(priv->rtc_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id msc313_rtc_of_match_table[] = {
|
||||
{ .compatible = "mstar,msc313-rtc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, msc313_rtc_of_match_table);
|
||||
|
||||
static struct platform_driver msc313_rtc_driver = {
|
||||
.probe = msc313_rtc_probe,
|
||||
.driver = {
|
||||
.name = "msc313-rtc",
|
||||
.of_match_table = msc313_rtc_of_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(msc313_rtc_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
|
||||
MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
|
||||
MODULE_DESCRIPTION("MStar RTC Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1029,6 +1029,5 @@ static struct platform_driver omap_rtc_driver = {
|
||||
|
||||
module_platform_driver(omap_rtc_driver);
|
||||
|
||||
MODULE_ALIAS("platform:omap_rtc");
|
||||
MODULE_AUTHOR("George G. Davis (and others)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -451,12 +451,21 @@ static const struct of_device_id pcf2123_dt_ids[] = {
|
||||
MODULE_DEVICE_TABLE(of, pcf2123_dt_ids);
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id pcf2123_spi_ids[] = {
|
||||
{ .name = "pcf2123", },
|
||||
{ .name = "rv2123", },
|
||||
{ .name = "rtc-pcf2123", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, pcf2123_spi_ids);
|
||||
|
||||
static struct spi_driver pcf2123_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-pcf2123",
|
||||
.of_match_table = of_match_ptr(pcf2123_dt_ids),
|
||||
},
|
||||
.probe = pcf2123_probe,
|
||||
.id_table = pcf2123_spi_ids,
|
||||
};
|
||||
|
||||
module_spi_driver(pcf2123_driver);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#define PCF85063_REG_CTRL1 0x00 /* status */
|
||||
#define PCF85063_REG_CTRL1_CAP_SEL BIT(0)
|
||||
#define PCF85063_REG_CTRL1_STOP BIT(5)
|
||||
#define PCF85063_REG_CTRL1_EXT_TEST BIT(7)
|
||||
|
||||
#define PCF85063_REG_CTRL2 0x01
|
||||
#define PCF85063_CTRL2_AF BIT(6)
|
||||
@ -117,6 +118,7 @@ static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
* reset state until all time/date registers are written
|
||||
*/
|
||||
rc = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1,
|
||||
PCF85063_REG_CTRL1_EXT_TEST |
|
||||
PCF85063_REG_CTRL1_STOP,
|
||||
PCF85063_REG_CTRL1_STOP);
|
||||
if (rc)
|
||||
@ -297,7 +299,7 @@ static int pcf85063_ioctl(struct device *dev, unsigned int cmd,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
status = status & PCF85063_REG_SC_OS ? RTC_VL_DATA_INVALID : 0;
|
||||
status = (status & PCF85063_REG_SC_OS) ? RTC_VL_DATA_INVALID : 0;
|
||||
|
||||
return put_user(status, (unsigned int __user *)arg);
|
||||
|
||||
@ -479,6 +481,18 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
struct device_node *node = pcf85063->rtc->dev.parent->of_node;
|
||||
struct device_node *fixed_clock;
|
||||
|
||||
fixed_clock = of_get_child_by_name(node, "clock");
|
||||
if (fixed_clock) {
|
||||
/*
|
||||
* skip registering square wave clock when a fixed
|
||||
* clock has been registered. The fixed clock is
|
||||
* registered automatically when being referenced.
|
||||
*/
|
||||
of_node_put(fixed_clock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
init.name = "pcf85063-clkout";
|
||||
init.ops = &pcf85063_clkout_ops;
|
||||
|
@ -4,8 +4,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
@ -19,11 +21,10 @@
|
||||
#define PCF8523_CONTROL2_AF BIT(3)
|
||||
|
||||
#define PCF8523_REG_CONTROL3 0x02
|
||||
#define PCF8523_CONTROL3_PM_BLD BIT(7) /* battery low detection disabled */
|
||||
#define PCF8523_CONTROL3_PM_VDD BIT(6) /* switch-over disabled */
|
||||
#define PCF8523_CONTROL3_PM_DSM BIT(5) /* direct switching mode */
|
||||
#define PCF8523_CONTROL3_PM_MASK 0xe0
|
||||
#define PCF8523_CONTROL3_PM GENMASK(7,5)
|
||||
#define PCF8523_PM_STANDBY 0x7
|
||||
#define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */
|
||||
#define PCF8523_CONTROL3_BSF BIT(3)
|
||||
|
||||
#define PCF8523_REG_SECONDS 0x03
|
||||
#define PCF8523_SECONDS_OS BIT(7)
|
||||
@ -48,127 +49,45 @@
|
||||
|
||||
struct pcf8523 {
|
||||
struct rtc_device *rtc;
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep)
|
||||
static int pcf8523_load_capacitance(struct pcf8523 *pcf8523, struct device_node *node)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
u8 value = 0;
|
||||
int err;
|
||||
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(reg);
|
||||
msgs[0].buf = ®
|
||||
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(value);
|
||||
msgs[1].buf = &value;
|
||||
|
||||
err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*valuep = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
u8 buffer[2] = { reg, value };
|
||||
struct i2c_msg msg;
|
||||
int err;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(buffer);
|
||||
msg.buf = buffer;
|
||||
|
||||
err = i2c_transfer(client->adapter, &msg, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf8523_voltage_low(struct i2c_client *client)
|
||||
{
|
||||
u8 value;
|
||||
int err;
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return !!(value & PCF8523_CONTROL3_BLF);
|
||||
}
|
||||
|
||||
static int pcf8523_load_capacitance(struct i2c_client *client)
|
||||
{
|
||||
u32 load;
|
||||
u8 value;
|
||||
int err;
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
u32 load, value = 0;
|
||||
|
||||
load = 12500;
|
||||
of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads",
|
||||
&load);
|
||||
of_property_read_u32(node, "quartz-load-femtofarads", &load);
|
||||
|
||||
switch (load) {
|
||||
default:
|
||||
dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500",
|
||||
dev_warn(&pcf8523->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500",
|
||||
load);
|
||||
fallthrough;
|
||||
case 12500:
|
||||
value |= PCF8523_CONTROL1_CAP_SEL;
|
||||
break;
|
||||
case 7000:
|
||||
value &= ~PCF8523_CONTROL1_CAP_SEL;
|
||||
break;
|
||||
}
|
||||
|
||||
err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pcf8523_set_pm(struct i2c_client *client, u8 pm)
|
||||
{
|
||||
u8 value;
|
||||
int err;
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
value = (value & ~PCF8523_CONTROL3_PM_MASK) | pm;
|
||||
|
||||
err = pcf8523_write(client, PCF8523_REG_CONTROL3, value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1,
|
||||
PCF8523_CONTROL1_CAP_SEL, value);
|
||||
}
|
||||
|
||||
static irqreturn_t pcf8523_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct pcf8523 *pcf8523 = i2c_get_clientdata(dev_id);
|
||||
u8 value;
|
||||
struct pcf8523 *pcf8523 = dev_id;
|
||||
u32 value;
|
||||
int err;
|
||||
|
||||
err = pcf8523_read(pcf8523->client, PCF8523_REG_CONTROL2, &value);
|
||||
err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL2, &value);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (value & PCF8523_CONTROL2_AF) {
|
||||
value &= ~PCF8523_CONTROL2_AF;
|
||||
pcf8523_write(pcf8523->client, PCF8523_REG_CONTROL2, value);
|
||||
regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL2, value);
|
||||
rtc_update_irq(pcf8523->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -177,68 +96,14 @@ static irqreturn_t pcf8523_irq(int irq, void *dev_id)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int pcf8523_stop_rtc(struct i2c_client *client)
|
||||
{
|
||||
u8 value;
|
||||
int err;
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
value |= PCF8523_CONTROL1_STOP;
|
||||
|
||||
err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf8523_start_rtc(struct i2c_client *client)
|
||||
{
|
||||
u8 value;
|
||||
int err;
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
value &= ~PCF8523_CONTROL1_STOP;
|
||||
|
||||
err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 start = PCF8523_REG_SECONDS, regs[7];
|
||||
struct i2c_msg msgs[2];
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
u8 regs[7];
|
||||
int err;
|
||||
|
||||
err = pcf8523_voltage_low(client);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
} else if (err > 0) {
|
||||
dev_err(dev, "low voltage detected, time is unreliable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = &start;
|
||||
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(regs);
|
||||
msgs[1].buf = regs;
|
||||
|
||||
err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_SECONDS, regs,
|
||||
sizeof(regs));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -258,63 +123,50 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_msg msg;
|
||||
u8 regs[8];
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
u8 regs[7];
|
||||
int err;
|
||||
|
||||
err = pcf8523_stop_rtc(client);
|
||||
err = regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1,
|
||||
PCF8523_CONTROL1_STOP, PCF8523_CONTROL1_STOP);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
regs[0] = PCF8523_REG_SECONDS;
|
||||
/* This will purposely overwrite PCF8523_SECONDS_OS */
|
||||
regs[1] = bin2bcd(tm->tm_sec);
|
||||
regs[2] = bin2bcd(tm->tm_min);
|
||||
regs[3] = bin2bcd(tm->tm_hour);
|
||||
regs[4] = bin2bcd(tm->tm_mday);
|
||||
regs[5] = tm->tm_wday;
|
||||
regs[6] = bin2bcd(tm->tm_mon + 1);
|
||||
regs[7] = bin2bcd(tm->tm_year - 100);
|
||||
regs[0] = bin2bcd(tm->tm_sec);
|
||||
regs[1] = bin2bcd(tm->tm_min);
|
||||
regs[2] = bin2bcd(tm->tm_hour);
|
||||
regs[3] = bin2bcd(tm->tm_mday);
|
||||
regs[4] = tm->tm_wday;
|
||||
regs[5] = bin2bcd(tm->tm_mon + 1);
|
||||
regs[6] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(regs);
|
||||
msg.buf = regs;
|
||||
|
||||
err = i2c_transfer(client->adapter, &msg, 1);
|
||||
err = regmap_bulk_write(pcf8523->regmap, PCF8523_REG_SECONDS, regs,
|
||||
sizeof(regs));
|
||||
if (err < 0) {
|
||||
/*
|
||||
* If the time cannot be set, restart the RTC anyway. Note
|
||||
* that errors are ignored if the RTC cannot be started so
|
||||
* that we have a chance to propagate the original error.
|
||||
*/
|
||||
pcf8523_start_rtc(client);
|
||||
regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1,
|
||||
PCF8523_CONTROL1_STOP, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
return pcf8523_start_rtc(client);
|
||||
return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1,
|
||||
PCF8523_CONTROL1_STOP, 0);
|
||||
}
|
||||
|
||||
static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 start = PCF8523_REG_MINUTE_ALARM, regs[4];
|
||||
struct i2c_msg msgs[2];
|
||||
u8 value;
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
u8 regs[4];
|
||||
u32 value;
|
||||
int err;
|
||||
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = &start;
|
||||
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(regs);
|
||||
msgs[1].buf = regs;
|
||||
|
||||
err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_MINUTE_ALARM, regs,
|
||||
sizeof(regs));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -324,12 +176,12 @@ static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
tm->time.tm_mday = bcd2bin(regs[2] & 0x3F);
|
||||
tm->time.tm_wday = bcd2bin(regs[3] & 0x7);
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
|
||||
err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL1, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
tm->enabled = !!(value & PCF8523_CONTROL1_AIE);
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL2, &value);
|
||||
err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL2, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
tm->pending = !!(value & PCF8523_CONTROL2_AF);
|
||||
@ -339,30 +191,16 @@ static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
|
||||
static int pcf8523_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 value;
|
||||
int err;
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
value &= PCF8523_CONTROL1_AIE;
|
||||
|
||||
if (enabled)
|
||||
value |= PCF8523_CONTROL1_AIE;
|
||||
|
||||
err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1,
|
||||
PCF8523_CONTROL1_AIE, enabled ?
|
||||
PCF8523_CONTROL1_AIE : 0);
|
||||
}
|
||||
|
||||
static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_msg msg;
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
u8 regs[5];
|
||||
int err;
|
||||
|
||||
@ -370,7 +208,7 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = pcf8523_write(client, PCF8523_REG_CONTROL2, 0);
|
||||
err = regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL2, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -382,16 +220,13 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
rtc_time64_to_tm(alarm_time, &tm->time);
|
||||
}
|
||||
|
||||
regs[0] = PCF8523_REG_MINUTE_ALARM;
|
||||
regs[1] = bin2bcd(tm->time.tm_min);
|
||||
regs[2] = bin2bcd(tm->time.tm_hour);
|
||||
regs[3] = bin2bcd(tm->time.tm_mday);
|
||||
regs[4] = ALARM_DIS;
|
||||
msg.addr = client->addr;
|
||||
msg.flags = 0;
|
||||
msg.len = sizeof(regs);
|
||||
msg.buf = regs;
|
||||
err = i2c_transfer(client->adapter, &msg, 1);
|
||||
regs[0] = bin2bcd(tm->time.tm_min);
|
||||
regs[1] = bin2bcd(tm->time.tm_hour);
|
||||
regs[2] = bin2bcd(tm->time.tm_mday);
|
||||
regs[3] = ALARM_DIS;
|
||||
|
||||
err = regmap_bulk_write(pcf8523->regmap, PCF8523_REG_MINUTE_ALARM, regs,
|
||||
sizeof(regs));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -401,24 +236,101 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RTC_INTF_DEV
|
||||
static int pcf8523_param_get(struct device *dev, struct rtc_param *param)
|
||||
{
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
switch(param->param) {
|
||||
u32 value;
|
||||
|
||||
case RTC_PARAM_BACKUP_SWITCH_MODE:
|
||||
ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value = FIELD_GET(PCF8523_CONTROL3_PM, value);
|
||||
|
||||
switch(value) {
|
||||
case 0x0:
|
||||
case 0x4:
|
||||
param->uvalue = RTC_BSM_LEVEL;
|
||||
break;
|
||||
case 0x1:
|
||||
case 0x5:
|
||||
param->uvalue = RTC_BSM_DIRECT;
|
||||
break;
|
||||
case PCF8523_PM_STANDBY:
|
||||
param->uvalue = RTC_BSM_STANDBY;
|
||||
break;
|
||||
default:
|
||||
param->uvalue = RTC_BSM_DISABLED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf8523_param_set(struct device *dev, struct rtc_param *param)
|
||||
{
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
|
||||
switch(param->param) {
|
||||
u8 mode;
|
||||
case RTC_PARAM_BACKUP_SWITCH_MODE:
|
||||
switch (param->uvalue) {
|
||||
case RTC_BSM_DISABLED:
|
||||
mode = 0x2;
|
||||
break;
|
||||
case RTC_BSM_DIRECT:
|
||||
mode = 0x1;
|
||||
break;
|
||||
case RTC_BSM_LEVEL:
|
||||
mode = 0x0;
|
||||
break;
|
||||
case RTC_BSM_STANDBY:
|
||||
mode = PCF8523_PM_STANDBY;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL3,
|
||||
PCF8523_CONTROL3_PM,
|
||||
FIELD_PREP(PCF8523_CONTROL3_PM, mode));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
unsigned int flags = 0;
|
||||
u8 value;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_VL_READ:
|
||||
ret = pcf8523_voltage_low(client);
|
||||
ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret)
|
||||
|
||||
if (value & PCF8523_CONTROL3_BLF)
|
||||
flags |= RTC_VL_BACKUP_LOW;
|
||||
|
||||
ret = pcf8523_read(client, PCF8523_REG_SECONDS, &value);
|
||||
ret = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -431,18 +343,15 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define pcf8523_rtc_ioctl NULL
|
||||
#endif
|
||||
|
||||
static int pcf8523_rtc_read_offset(struct device *dev, long *offset)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
int err;
|
||||
u8 value;
|
||||
u32 value;
|
||||
s8 val;
|
||||
|
||||
err = pcf8523_read(client, PCF8523_REG_OFFSET, &value);
|
||||
err = regmap_read(pcf8523->regmap, PCF8523_REG_OFFSET, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -455,9 +364,9 @@ static int pcf8523_rtc_read_offset(struct device *dev, long *offset)
|
||||
|
||||
static int pcf8523_rtc_set_offset(struct device *dev, long offset)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
long reg_m0, reg_m1;
|
||||
u8 value;
|
||||
u32 value;
|
||||
|
||||
reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L);
|
||||
reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L);
|
||||
@ -467,7 +376,7 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset)
|
||||
else
|
||||
value = (reg_m1 & 0x7f) | PCF8523_OFFSET_MODE;
|
||||
|
||||
return pcf8523_write(client, PCF8523_REG_OFFSET, value);
|
||||
return regmap_write(pcf8523->regmap, PCF8523_REG_OFFSET, value);
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops pcf8523_rtc_ops = {
|
||||
@ -479,6 +388,14 @@ static const struct rtc_class_ops pcf8523_rtc_ops = {
|
||||
.ioctl = pcf8523_rtc_ioctl,
|
||||
.read_offset = pcf8523_rtc_read_offset,
|
||||
.set_offset = pcf8523_rtc_set_offset,
|
||||
.param_get = pcf8523_param_get,
|
||||
.param_set = pcf8523_param_set,
|
||||
};
|
||||
|
||||
static const struct regmap_config regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x13,
|
||||
};
|
||||
|
||||
static int pcf8523_probe(struct i2c_client *client,
|
||||
@ -487,6 +404,7 @@ static int pcf8523_probe(struct i2c_client *client,
|
||||
struct pcf8523 *pcf8523;
|
||||
struct rtc_device *rtc;
|
||||
bool wakeup_source = false;
|
||||
u32 value;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
@ -496,46 +414,60 @@ static int pcf8523_probe(struct i2c_client *client,
|
||||
if (!pcf8523)
|
||||
return -ENOMEM;
|
||||
|
||||
pcf8523->regmap = devm_regmap_init_i2c(client, ®map_config);
|
||||
if (IS_ERR(pcf8523->regmap))
|
||||
return PTR_ERR(pcf8523->regmap);
|
||||
|
||||
i2c_set_clientdata(client, pcf8523);
|
||||
pcf8523->client = client;
|
||||
|
||||
err = pcf8523_load_capacitance(client);
|
||||
if (err < 0)
|
||||
dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
|
||||
err);
|
||||
|
||||
err = pcf8523_set_pm(client, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
pcf8523->rtc = rtc;
|
||||
|
||||
err = pcf8523_load_capacitance(pcf8523, client->dev.of_node);
|
||||
if (err < 0)
|
||||
dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
|
||||
err);
|
||||
|
||||
err = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (value & PCF8523_SECONDS_OS) {
|
||||
err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (FIELD_GET(PCF8523_CONTROL3_PM, value) == PCF8523_PM_STANDBY) {
|
||||
err = regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL3,
|
||||
value & ~PCF8523_CONTROL3_PM);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
rtc->ops = &pcf8523_rtc_ops;
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->uie_unsupported = 1;
|
||||
|
||||
if (client->irq > 0) {
|
||||
err = pcf8523_write(client, PCF8523_TMR_CLKOUT_CTRL, 0x38);
|
||||
err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, pcf8523_irq,
|
||||
IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
|
||||
dev_name(&rtc->dev), client);
|
||||
dev_name(&rtc->dev), pcf8523);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_pm_set_wake_irq(&client->dev, client->irq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
wakeup_source = of_property_read_bool(client->dev.of_node, "wakeup-source");
|
||||
#endif
|
||||
if (client->irq > 0 || wakeup_source)
|
||||
device_init_wakeup(&client->dev, true);
|
||||
|
||||
@ -548,19 +480,17 @@ static const struct i2c_device_id pcf8523_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf8523_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pcf8523_of_match[] = {
|
||||
{ .compatible = "nxp,pcf8523" },
|
||||
{ .compatible = "microcrystal,rv8523" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcf8523_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver pcf8523_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-pcf8523",
|
||||
.of_match_table = of_match_ptr(pcf8523_of_match),
|
||||
.of_match_table = pcf8523_of_match,
|
||||
},
|
||||
.probe = pcf8523_probe,
|
||||
.id_table = pcf8523_id,
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -80,6 +81,10 @@
|
||||
|
||||
#define RV3028_BACKUP_TCE BIT(5)
|
||||
#define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
|
||||
#define RV3028_BACKUP_BSM GENMASK(3,2)
|
||||
|
||||
#define RV3028_BACKUP_BSM_DSM 0x1
|
||||
#define RV3028_BACKUP_BSM_LSM 0x3
|
||||
|
||||
#define OFFSET_STEP_PPT 953674
|
||||
|
||||
@ -512,6 +517,71 @@ exit_eerd:
|
||||
|
||||
}
|
||||
|
||||
static int rv3028_param_get(struct device *dev, struct rtc_param *param)
|
||||
{
|
||||
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
switch(param->param) {
|
||||
u32 value;
|
||||
|
||||
case RTC_PARAM_BACKUP_SWITCH_MODE:
|
||||
ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value = FIELD_GET(RV3028_BACKUP_BSM, value);
|
||||
|
||||
switch(value) {
|
||||
case RV3028_BACKUP_BSM_DSM:
|
||||
param->uvalue = RTC_BSM_DIRECT;
|
||||
break;
|
||||
case RV3028_BACKUP_BSM_LSM:
|
||||
param->uvalue = RTC_BSM_LEVEL;
|
||||
break;
|
||||
default:
|
||||
param->uvalue = RTC_BSM_DISABLED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3028_param_set(struct device *dev, struct rtc_param *param)
|
||||
{
|
||||
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
|
||||
|
||||
switch(param->param) {
|
||||
u8 mode;
|
||||
case RTC_PARAM_BACKUP_SWITCH_MODE:
|
||||
switch (param->uvalue) {
|
||||
case RTC_BSM_DISABLED:
|
||||
mode = 0;
|
||||
break;
|
||||
case RTC_BSM_DIRECT:
|
||||
mode = RV3028_BACKUP_BSM_DSM;
|
||||
break;
|
||||
case RTC_BSM_LEVEL:
|
||||
mode = RV3028_BACKUP_BSM_LSM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_BSM,
|
||||
FIELD_PREP(RV3028_BACKUP_BSM, mode));
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
|
||||
@ -776,6 +846,8 @@ static const struct rtc_class_ops rv3028_rtc_ops = {
|
||||
.read_offset = rv3028_read_offset,
|
||||
.set_offset = rv3028_set_offset,
|
||||
.ioctl = rv3028_ioctl,
|
||||
.param_get = rv3028_param_get,
|
||||
.param_set = rv3028_param_set,
|
||||
};
|
||||
|
||||
static const struct regmap_config regmap_config = {
|
||||
@ -878,6 +950,8 @@ static int rv3028_probe(struct i2c_client *client)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3028->rtc->features);
|
||||
|
||||
rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rv3028->rtc->ops = &rv3028_rtc_ops;
|
||||
|
@ -106,6 +106,7 @@
|
||||
struct rv3032_data {
|
||||
struct regmap *regmap;
|
||||
struct rtc_device *rtc;
|
||||
bool trickle_charger_set;
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
struct clk_hw clkout_hw;
|
||||
#endif
|
||||
@ -310,14 +311,6 @@ static int rv3032_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
u8 ctrl = 0;
|
||||
int ret;
|
||||
|
||||
/* The alarm has no seconds, round up to nearest minute */
|
||||
if (alrm->time.tm_sec) {
|
||||
time64_t alarm_time = rtc_tm_to_time64(&alrm->time);
|
||||
|
||||
alarm_time += 60 - alrm->time.tm_sec;
|
||||
rtc_time64_to_tm(alarm_time, &alrm->time);
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL2,
|
||||
RV3032_CTRL2_AIE | RV3032_CTRL2_UIE, 0);
|
||||
if (ret)
|
||||
@ -402,6 +395,75 @@ static int rv3032_set_offset(struct device *dev, long offset)
|
||||
FIELD_PREP(RV3032_OFFSET_MSK, offset));
|
||||
}
|
||||
|
||||
static int rv3032_param_get(struct device *dev, struct rtc_param *param)
|
||||
{
|
||||
struct rv3032_data *rv3032 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
switch(param->param) {
|
||||
u32 value;
|
||||
|
||||
case RTC_PARAM_BACKUP_SWITCH_MODE:
|
||||
ret = regmap_read(rv3032->regmap, RV3032_PMU, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value = FIELD_GET(RV3032_PMU_BSM, value);
|
||||
|
||||
switch(value) {
|
||||
case RV3032_PMU_BSM_DSM:
|
||||
param->uvalue = RTC_BSM_DIRECT;
|
||||
break;
|
||||
case RV3032_PMU_BSM_LSM:
|
||||
param->uvalue = RTC_BSM_LEVEL;
|
||||
break;
|
||||
default:
|
||||
param->uvalue = RTC_BSM_DISABLED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3032_param_set(struct device *dev, struct rtc_param *param)
|
||||
{
|
||||
struct rv3032_data *rv3032 = dev_get_drvdata(dev);
|
||||
|
||||
switch(param->param) {
|
||||
u8 mode;
|
||||
case RTC_PARAM_BACKUP_SWITCH_MODE:
|
||||
if (rv3032->trickle_charger_set)
|
||||
return -EINVAL;
|
||||
|
||||
switch (param->uvalue) {
|
||||
case RTC_BSM_DISABLED:
|
||||
mode = 0;
|
||||
break;
|
||||
case RTC_BSM_DIRECT:
|
||||
mode = RV3032_PMU_BSM_DSM;
|
||||
break;
|
||||
case RTC_BSM_LEVEL:
|
||||
mode = RV3032_PMU_BSM_LSM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return rv3032_update_cfg(rv3032, RV3032_PMU, RV3032_PMU_BSM,
|
||||
FIELD_PREP(RV3032_PMU_BSM, mode));
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3032_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct rv3032_data *rv3032 = dev_get_drvdata(dev);
|
||||
@ -541,6 +603,8 @@ static int rv3032_trickle_charger_setup(struct device *dev, struct rv3032_data *
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv3032->trickle_charger_set = true;
|
||||
|
||||
return rv3032_update_cfg(rv3032, RV3032_PMU,
|
||||
RV3032_PMU_TCR | RV3032_PMU_TCM | RV3032_PMU_BSM,
|
||||
val | FIELD_PREP(RV3032_PMU_TCR, i));
|
||||
@ -617,11 +681,11 @@ static int rv3032_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
ret = rv3032_enter_eerd(rv3032, &eerd);
|
||||
if (ret)
|
||||
goto exit_eerd;
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(rv3032->regmap, RV3032_CLKOUT1, hfd & 0xff);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto exit_eerd;
|
||||
|
||||
ret = regmap_write(rv3032->regmap, RV3032_CLKOUT2, RV3032_CLKOUT2_OS |
|
||||
FIELD_PREP(RV3032_CLKOUT2_HFD_MSK, hfd >> 8));
|
||||
@ -813,6 +877,8 @@ static const struct rtc_class_ops rv3032_rtc_ops = {
|
||||
.read_alarm = rv3032_get_alarm,
|
||||
.set_alarm = rv3032_set_alarm,
|
||||
.alarm_irq_enable = rv3032_alarm_irq_enable,
|
||||
.param_get = rv3032_param_get,
|
||||
.param_set = rv3032_param_set,
|
||||
};
|
||||
|
||||
static const struct regmap_config regmap_config = {
|
||||
@ -883,6 +949,9 @@ static int rv3032_probe(struct i2c_client *client)
|
||||
|
||||
rv3032_trickle_charger_setup(&client->dev, rv3032);
|
||||
|
||||
set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3032->rtc->features);
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rv3032->rtc->features);
|
||||
|
||||
rv3032->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rv3032->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rv3032->rtc->ops = &rv3032_rtc_ops;
|
||||
|
@ -340,8 +340,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
}
|
||||
}
|
||||
|
||||
ctrl[1] &= ~RV8803_FLAG_AF;
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[1]);
|
||||
ctrl[0] &= ~RV8803_FLAG_AF;
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[0]);
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -422,7 +422,7 @@ static struct regmap_config regmap_i2c_config = {
|
||||
static int rx6110_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct rx6110_data *rx6110;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
||||
|
@ -248,9 +248,6 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt)
|
||||
u8 date[7];
|
||||
int ret;
|
||||
|
||||
if ((dt->tm_year < 100) || (dt->tm_year > 199))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Here the read-only bits are written as "0". I'm not sure if that
|
||||
* is sound.
|
||||
@ -318,9 +315,6 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
u8 ald[2];
|
||||
int ctrl2, err;
|
||||
|
||||
if (client->irq <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
err = rx8025_read_regs(client, RX8025_REG_ALDMIN, 2, ald);
|
||||
if (err)
|
||||
return err;
|
||||
@ -355,20 +349,6 @@ static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
u8 ald[2];
|
||||
int err;
|
||||
|
||||
if (client->irq <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Hardware alarm precision is 1 minute!
|
||||
* round up to nearest minute
|
||||
*/
|
||||
if (t->time.tm_sec) {
|
||||
time64_t alarm_time = rtc_tm_to_time64(&t->time);
|
||||
|
||||
alarm_time += 60 - t->time.tm_sec;
|
||||
rtc_time64_to_tm(alarm_time, &t->time);
|
||||
}
|
||||
|
||||
ald[0] = bin2bcd(t->time.tm_min);
|
||||
if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)
|
||||
ald[1] = bin2bcd(t->time.tm_hour);
|
||||
@ -423,17 +403,7 @@ static int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops rx8025_rtc_ops = {
|
||||
.read_time = rx8025_get_time,
|
||||
.set_time = rx8025_set_time,
|
||||
.read_alarm = rx8025_read_alarm,
|
||||
.set_alarm = rx8025_set_alarm,
|
||||
.alarm_irq_enable = rx8025_alarm_irq_enable,
|
||||
};
|
||||
|
||||
/*
|
||||
* Clock precision adjustment support
|
||||
*
|
||||
* According to the RX8025 SA/NB application manual the frequency and
|
||||
* temperature characteristics can be approximated using the following
|
||||
* equation:
|
||||
@ -444,11 +414,8 @@ static const struct rtc_class_ops rx8025_rtc_ops = {
|
||||
* a : Coefficient = (-35 +-5) * 10**-9
|
||||
* ut: Ultimate temperature in degree = +25 +-5 degree
|
||||
* t : Any temperature in degree
|
||||
*
|
||||
* Note that the clock adjustment in ppb must be entered (which is
|
||||
* the negative value of the deviation).
|
||||
*/
|
||||
static int rx8025_get_clock_adjust(struct device *dev, int *adj)
|
||||
static int rx8025_read_offset(struct device *dev, long *offset)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int digoff;
|
||||
@ -457,63 +424,75 @@ static int rx8025_get_clock_adjust(struct device *dev, int *adj)
|
||||
if (digoff < 0)
|
||||
return digoff;
|
||||
|
||||
*adj = digoff >= 64 ? digoff - 128 : digoff;
|
||||
if (*adj > 0)
|
||||
(*adj)--;
|
||||
*adj *= -RX8025_ADJ_RESOLUTION;
|
||||
*offset = digoff >= 64 ? digoff - 128 : digoff;
|
||||
if (*offset > 0)
|
||||
(*offset)--;
|
||||
*offset *= RX8025_ADJ_RESOLUTION;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx8025_set_clock_adjust(struct device *dev, int adj)
|
||||
static int rx8025_set_offset(struct device *dev, long offset)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 digoff;
|
||||
int err;
|
||||
|
||||
adj /= -RX8025_ADJ_RESOLUTION;
|
||||
if (adj > RX8025_ADJ_DATA_MAX)
|
||||
adj = RX8025_ADJ_DATA_MAX;
|
||||
else if (adj < RX8025_ADJ_DATA_MIN)
|
||||
adj = RX8025_ADJ_DATA_MIN;
|
||||
else if (adj > 0)
|
||||
adj++;
|
||||
else if (adj < 0)
|
||||
adj += 128;
|
||||
digoff = adj;
|
||||
offset /= RX8025_ADJ_RESOLUTION;
|
||||
if (offset > RX8025_ADJ_DATA_MAX)
|
||||
offset = RX8025_ADJ_DATA_MAX;
|
||||
else if (offset < RX8025_ADJ_DATA_MIN)
|
||||
offset = RX8025_ADJ_DATA_MIN;
|
||||
else if (offset > 0)
|
||||
offset++;
|
||||
else if (offset < 0)
|
||||
offset += 128;
|
||||
digoff = offset;
|
||||
|
||||
err = rx8025_write_reg(client, RX8025_REG_DIGOFF, digoff);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_dbg(dev, "%s: write 0x%02x\n", __func__, digoff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops rx8025_rtc_ops = {
|
||||
.read_time = rx8025_get_time,
|
||||
.set_time = rx8025_set_time,
|
||||
.read_alarm = rx8025_read_alarm,
|
||||
.set_alarm = rx8025_set_alarm,
|
||||
.alarm_irq_enable = rx8025_alarm_irq_enable,
|
||||
.read_offset = rx8025_read_offset,
|
||||
.set_offset = rx8025_set_offset,
|
||||
};
|
||||
|
||||
static ssize_t rx8025_sysfs_show_clock_adjust(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int err, adj;
|
||||
long adj;
|
||||
int err;
|
||||
|
||||
err = rx8025_get_clock_adjust(dev, &adj);
|
||||
dev_warn_once(dev, "clock_adjust_ppb is deprecated, use offset\n");
|
||||
err = rx8025_read_offset(dev, &adj);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%d\n", adj);
|
||||
return sprintf(buf, "%ld\n", -adj);
|
||||
}
|
||||
|
||||
static ssize_t rx8025_sysfs_store_clock_adjust(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int adj, err;
|
||||
long adj;
|
||||
int err;
|
||||
|
||||
if (sscanf(buf, "%i", &adj) != 1)
|
||||
dev_warn_once(dev, "clock_adjust_ppb is deprecated, use offset\n");
|
||||
if (kstrtol(buf, 10, &adj) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
err = rx8025_set_clock_adjust(dev, adj);
|
||||
err = rx8025_set_offset(dev, -adj);
|
||||
|
||||
return err ? err : count;
|
||||
}
|
||||
@ -522,15 +501,14 @@ static DEVICE_ATTR(clock_adjust_ppb, S_IRUGO | S_IWUSR,
|
||||
rx8025_sysfs_show_clock_adjust,
|
||||
rx8025_sysfs_store_clock_adjust);
|
||||
|
||||
static int rx8025_sysfs_register(struct device *dev)
|
||||
{
|
||||
return device_create_file(dev, &dev_attr_clock_adjust_ppb);
|
||||
}
|
||||
static struct attribute *rx8025_attrs[] = {
|
||||
&dev_attr_clock_adjust_ppb.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void rx8025_sysfs_unregister(struct device *dev)
|
||||
{
|
||||
device_remove_file(dev, &dev_attr_clock_adjust_ppb);
|
||||
}
|
||||
static const struct attribute_group rx8025_attr_group = {
|
||||
.attrs = rx8025_attrs,
|
||||
};
|
||||
|
||||
static int rx8025_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
@ -559,12 +537,13 @@ static int rx8025_probe(struct i2c_client *client,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rx8025->rtc = devm_rtc_device_register(&client->dev, client->name,
|
||||
&rx8025_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rx8025->rtc)) {
|
||||
dev_err(&client->dev, "unable to register the class device\n");
|
||||
rx8025->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rx8025->rtc))
|
||||
return PTR_ERR(rx8025->rtc);
|
||||
}
|
||||
|
||||
rx8025->rtc->ops = &rx8025_rtc_ops;
|
||||
rx8025->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
rx8025->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
if (client->irq > 0) {
|
||||
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
|
||||
@ -572,25 +551,20 @@ static int rx8025_probe(struct i2c_client *client,
|
||||
rx8025_handle_irq,
|
||||
IRQF_ONESHOT,
|
||||
"rx8025", client);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
|
||||
client->irq = 0;
|
||||
}
|
||||
if (err)
|
||||
clear_bit(RTC_FEATURE_ALARM, rx8025->rtc->features);
|
||||
}
|
||||
|
||||
rx8025->rtc->max_user_freq = 1;
|
||||
|
||||
/* the rx8025 alarm only supports a minute accuracy */
|
||||
rx8025->rtc->uie_unsupported = 1;
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rx8025->rtc->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rx8025->rtc->features);
|
||||
|
||||
err = rx8025_sysfs_register(&client->dev);
|
||||
return err;
|
||||
}
|
||||
err = rtc_add_group(rx8025->rtc, &rx8025_attr_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
static int rx8025_remove(struct i2c_client *client)
|
||||
{
|
||||
rx8025_sysfs_unregister(&client->dev);
|
||||
return 0;
|
||||
return devm_rtc_register_device(rx8025->rtc);
|
||||
}
|
||||
|
||||
static struct i2c_driver rx8025_driver = {
|
||||
@ -598,7 +572,6 @@ static struct i2c_driver rx8025_driver = {
|
||||
.name = "rtc-rx8025",
|
||||
},
|
||||
.probe = rx8025_probe,
|
||||
.remove = rx8025_remove,
|
||||
.id_table = rx8025_id,
|
||||
};
|
||||
|
||||
|
@ -285,9 +285,6 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
|
||||
alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
|
||||
|
||||
if (alm->time.tm_sec != 0)
|
||||
dev_warn(&client->dev, "Alarms are only supported on a per minute basis!\n");
|
||||
|
||||
/* disable interrupt (which deasserts the irq line) */
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
|
||||
if (err < 0)
|
||||
@ -491,8 +488,8 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
s35390a->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
s35390a->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
/* supports per-minute alarms only, therefore set uie_unsupported */
|
||||
s35390a->rtc->uie_unsupported = 1;
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, s35390a->rtc->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, s35390a->rtc->features );
|
||||
|
||||
if (status1 & S35390A_FLAG_INT2)
|
||||
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
|
||||
|
@ -127,10 +127,9 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Time read/write */
|
||||
static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
||||
/* Read time from RTC and convert it from BCD */
|
||||
static int s3c_rtc_read_time(struct s3c_rtc *info, struct rtc_time *tm)
|
||||
{
|
||||
struct s3c_rtc *info = dev_get_drvdata(dev);
|
||||
unsigned int have_retried = 0;
|
||||
int ret;
|
||||
|
||||
@ -139,54 +138,40 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
||||
return ret;
|
||||
|
||||
retry_get_time:
|
||||
rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN);
|
||||
rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
|
||||
rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
|
||||
rtc_tm->tm_mon = readb(info->base + S3C2410_RTCMON);
|
||||
rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
|
||||
rtc_tm->tm_sec = readb(info->base + S3C2410_RTCSEC);
|
||||
tm->tm_min = readb(info->base + S3C2410_RTCMIN);
|
||||
tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
|
||||
tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
|
||||
tm->tm_mon = readb(info->base + S3C2410_RTCMON);
|
||||
tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
|
||||
tm->tm_sec = readb(info->base + S3C2410_RTCSEC);
|
||||
|
||||
/* the only way to work out whether the system was mid-update
|
||||
/*
|
||||
* The only way to work out whether the system was mid-update
|
||||
* when we read it is to check the second counter, and if it
|
||||
* is zero, then we re-try the entire read
|
||||
*/
|
||||
|
||||
if (rtc_tm->tm_sec == 0 && !have_retried) {
|
||||
if (tm->tm_sec == 0 && !have_retried) {
|
||||
have_retried = 1;
|
||||
goto retry_get_time;
|
||||
}
|
||||
|
||||
rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
|
||||
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
|
||||
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
|
||||
rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
|
||||
rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
|
||||
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
|
||||
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
rtc_tm->tm_year += 100;
|
||||
rtc_tm->tm_mon -= 1;
|
||||
tm->tm_sec = bcd2bin(tm->tm_sec);
|
||||
tm->tm_min = bcd2bin(tm->tm_min);
|
||||
tm->tm_hour = bcd2bin(tm->tm_hour);
|
||||
tm->tm_mday = bcd2bin(tm->tm_mday);
|
||||
tm->tm_mon = bcd2bin(tm->tm_mon);
|
||||
tm->tm_year = bcd2bin(tm->tm_year);
|
||||
|
||||
dev_dbg(dev, "read time %ptR\n", rtc_tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
/* Convert time to BCD and write it to RTC */
|
||||
static int s3c_rtc_write_time(struct s3c_rtc *info, const struct rtc_time *tm)
|
||||
{
|
||||
struct s3c_rtc *info = dev_get_drvdata(dev);
|
||||
int year = tm->tm_year - 100;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "set time %ptR\n", tm);
|
||||
|
||||
/* we get around y2k by simply not supporting it */
|
||||
|
||||
if (year < 0 || year >= 100) {
|
||||
dev_err(dev, "rtc only supports 100 years\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = s3c_rtc_enable_clk(info);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -195,14 +180,48 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
|
||||
writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
|
||||
writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
|
||||
writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON);
|
||||
writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR);
|
||||
writeb(bin2bcd(tm->tm_mon), info->base + S3C2410_RTCMON);
|
||||
writeb(bin2bcd(tm->tm_year), info->base + S3C2410_RTCYEAR);
|
||||
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_rtc_gettime(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct s3c_rtc *info = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = s3c_rtc_read_time(info, tm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Convert internal representation to actual date/time */
|
||||
tm->tm_year += 100;
|
||||
tm->tm_mon -= 1;
|
||||
|
||||
dev_dbg(dev, "read time %ptR\n", tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct s3c_rtc *info = dev_get_drvdata(dev);
|
||||
struct rtc_time rtc_tm = *tm;
|
||||
|
||||
dev_dbg(dev, "set time %ptR\n", tm);
|
||||
|
||||
/*
|
||||
* Convert actual date/time to internal representation.
|
||||
* We get around Y2K by simply not supporting it.
|
||||
*/
|
||||
rtc_tm.tm_year -= 100;
|
||||
rtc_tm.tm_mon += 1;
|
||||
|
||||
return s3c_rtc_write_time(info, &rtc_tm);
|
||||
}
|
||||
|
||||
static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct s3c_rtc *info = dev_get_drvdata(dev);
|
||||
@ -447,15 +466,20 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
/* register RTC and exit */
|
||||
info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
|
||||
THIS_MODULE);
|
||||
info->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(info->rtc)) {
|
||||
dev_err(&pdev->dev, "cannot attach rtc\n");
|
||||
ret = PTR_ERR(info->rtc);
|
||||
goto err_nortc;
|
||||
}
|
||||
|
||||
info->rtc->ops = &s3c_rtcops;
|
||||
info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
info->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
ret = devm_rtc_register_device(info->rtc);
|
||||
if (ret)
|
||||
goto err_nortc;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
|
||||
0, "s3c2410-rtc alarm", info);
|
||||
if (ret) {
|
||||
|
@ -861,4 +861,3 @@ module_platform_driver(s5m_rtc_driver);
|
||||
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:s5m-rtc");
|
||||
|
@ -673,8 +673,17 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
|
||||
struct sun6i_rtc_dev *chip = sun6i_rtc;
|
||||
int ret;
|
||||
|
||||
if (!chip)
|
||||
return -ENODEV;
|
||||
if (!chip) {
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
|
||||
chip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(chip->base))
|
||||
return PTR_ERR(chip->base);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
|
@ -1,324 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver
|
||||
*
|
||||
* RTC driver for TI TPS80031/TPS80032 Fully Integrated
|
||||
* Power Management with Power Path and Battery Charger
|
||||
*
|
||||
* Copyright (c) 2012, NVIDIA Corporation.
|
||||
*
|
||||
* Author: Laxman Dewangan <ldewangan@nvidia.com>
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/tps80031.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define ENABLE_ALARM_INT 0x08
|
||||
#define ALARM_INT_STATUS 0x40
|
||||
|
||||
/**
|
||||
* Setting bit to 1 in STOP_RTC will run the RTC and
|
||||
* setting this bit to 0 will freeze RTC.
|
||||
*/
|
||||
#define STOP_RTC 0x1
|
||||
|
||||
/* Power on reset Values of RTC registers */
|
||||
#define TPS80031_RTC_POR_YEAR 0
|
||||
#define TPS80031_RTC_POR_MONTH 1
|
||||
#define TPS80031_RTC_POR_DAY 1
|
||||
|
||||
/* Numbers of registers for time and alarms */
|
||||
#define TPS80031_RTC_TIME_NUM_REGS 7
|
||||
#define TPS80031_RTC_ALARM_NUM_REGS 6
|
||||
|
||||
/**
|
||||
* PMU RTC have only 2 nibbles to store year information, so using an
|
||||
* offset of 100 to set the base year as 2000 for our driver.
|
||||
*/
|
||||
#define RTC_YEAR_OFFSET 100
|
||||
|
||||
struct tps80031_rtc {
|
||||
struct rtc_device *rtc;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 buff[TPS80031_RTC_TIME_NUM_REGS];
|
||||
int ret;
|
||||
|
||||
ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_SECONDS_REG, TPS80031_RTC_TIME_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "reading RTC_SECONDS_REG failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tm->tm_sec = bcd2bin(buff[0]);
|
||||
tm->tm_min = bcd2bin(buff[1]);
|
||||
tm->tm_hour = bcd2bin(buff[2]);
|
||||
tm->tm_mday = bcd2bin(buff[3]);
|
||||
tm->tm_mon = bcd2bin(buff[4]) - 1;
|
||||
tm->tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET;
|
||||
tm->tm_wday = bcd2bin(buff[6]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 buff[7];
|
||||
int ret;
|
||||
|
||||
buff[0] = bin2bcd(tm->tm_sec);
|
||||
buff[1] = bin2bcd(tm->tm_min);
|
||||
buff[2] = bin2bcd(tm->tm_hour);
|
||||
buff[3] = bin2bcd(tm->tm_mday);
|
||||
buff[4] = bin2bcd(tm->tm_mon + 1);
|
||||
buff[5] = bin2bcd(tm->tm_year % RTC_YEAR_OFFSET);
|
||||
buff[6] = bin2bcd(tm->tm_wday);
|
||||
|
||||
/* Stop RTC while updating the RTC time registers */
|
||||
ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_CTRL_REG, STOP_RTC);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->parent, "Stop RTC failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_SECONDS_REG,
|
||||
TPS80031_RTC_TIME_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "writing RTC_SECONDS_REG failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_CTRL_REG, STOP_RTC);
|
||||
if (ret < 0)
|
||||
dev_err(dev->parent, "Start RTC failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (enable)
|
||||
ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT);
|
||||
else
|
||||
ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Update on RTC_INT failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
u8 buff[TPS80031_RTC_ALARM_NUM_REGS];
|
||||
int ret;
|
||||
|
||||
buff[0] = bin2bcd(alrm->time.tm_sec);
|
||||
buff[1] = bin2bcd(alrm->time.tm_min);
|
||||
buff[2] = bin2bcd(alrm->time.tm_hour);
|
||||
buff[3] = bin2bcd(alrm->time.tm_mday);
|
||||
buff[4] = bin2bcd(alrm->time.tm_mon + 1);
|
||||
buff[5] = bin2bcd(alrm->time.tm_year % RTC_YEAR_OFFSET);
|
||||
ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_ALARM_SECONDS_REG,
|
||||
TPS80031_RTC_ALARM_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Writing RTC_ALARM failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return tps80031_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
}
|
||||
|
||||
static int tps80031_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
u8 buff[6];
|
||||
int ret;
|
||||
|
||||
ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_ALARM_SECONDS_REG,
|
||||
TPS80031_RTC_ALARM_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->parent,
|
||||
"reading RTC_ALARM failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
alrm->time.tm_sec = bcd2bin(buff[0]);
|
||||
alrm->time.tm_min = bcd2bin(buff[1]);
|
||||
alrm->time.tm_hour = bcd2bin(buff[2]);
|
||||
alrm->time.tm_mday = bcd2bin(buff[3]);
|
||||
alrm->time.tm_mon = bcd2bin(buff[4]) - 1;
|
||||
alrm->time.tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clear_alarm_int_status(struct device *dev, struct tps80031_rtc *rtc)
|
||||
{
|
||||
int ret;
|
||||
u8 buf;
|
||||
|
||||
/**
|
||||
* As per datasheet, A dummy read of this RTC_STATUS_REG register
|
||||
* is necessary before each I2C read in order to update the status
|
||||
* register value.
|
||||
*/
|
||||
ret = tps80031_read(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_STATUS_REG, &buf);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "reading RTC_STATUS failed. err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clear Alarm status bits.*/
|
||||
ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_STATUS_REG, ALARM_INT_STATUS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "clear Alarm INT failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t tps80031_rtc_irq(int irq, void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct tps80031_rtc *rtc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clear_alarm_int_status(dev, rtc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops tps80031_rtc_ops = {
|
||||
.read_time = tps80031_rtc_read_time,
|
||||
.set_time = tps80031_rtc_set_time,
|
||||
.set_alarm = tps80031_rtc_set_alarm,
|
||||
.read_alarm = tps80031_rtc_read_alarm,
|
||||
.alarm_irq_enable = tps80031_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int tps80031_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps80031_rtc *rtc;
|
||||
struct rtc_time tm;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
/* Start RTC */
|
||||
ret = tps80031_set_bits(pdev->dev.parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_CTRL_REG, STOP_RTC);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to start RTC. err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If RTC have POR values, set time 01:01:2000 */
|
||||
tps80031_rtc_read_time(&pdev->dev, &tm);
|
||||
if ((tm.tm_year == RTC_YEAR_OFFSET + TPS80031_RTC_POR_YEAR) &&
|
||||
(tm.tm_mon == (TPS80031_RTC_POR_MONTH - 1)) &&
|
||||
(tm.tm_mday == TPS80031_RTC_POR_DAY)) {
|
||||
tm.tm_year = 2000;
|
||||
tm.tm_mday = 1;
|
||||
tm.tm_mon = 1;
|
||||
ret = tps80031_rtc_set_time(&pdev->dev, &tm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"RTC set time failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear alarm intretupt status if it is there */
|
||||
ret = clear_alarm_int_status(&pdev->dev, rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Clear alarm int failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&tps80031_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
dev_err(&pdev->dev, "RTC registration failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||
tps80031_rtc_irq,
|
||||
IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n",
|
||||
rtc->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tps80031_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct tps80031_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(rtc->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct tps80031_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(rtc->irq);
|
||||
return 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tps80031_pm_ops, tps80031_rtc_suspend,
|
||||
tps80031_rtc_resume);
|
||||
|
||||
static struct platform_driver tps80031_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "tps80031-rtc",
|
||||
.pm = &tps80031_pm_ops,
|
||||
},
|
||||
.probe = tps80031_rtc_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(tps80031_rtc_driver);
|
||||
|
||||
MODULE_ALIAS("platform:tps80031-rtc");
|
||||
MODULE_DESCRIPTION("TI TPS80031/TPS80032 RTC driver");
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -66,6 +66,8 @@ struct rtc_class_ops {
|
||||
int (*alarm_irq_enable)(struct device *, unsigned int enabled);
|
||||
int (*read_offset)(struct device *, long *offset);
|
||||
int (*set_offset)(struct device *, long offset);
|
||||
int (*param_get)(struct device *, struct rtc_param *param);
|
||||
int (*param_set)(struct device *, struct rtc_param *param);
|
||||
};
|
||||
|
||||
struct rtc_device;
|
||||
@ -80,6 +82,7 @@ struct rtc_timer {
|
||||
|
||||
/* flags */
|
||||
#define RTC_DEV_BUSY 0
|
||||
#define RTC_NO_CDEV 1
|
||||
|
||||
struct rtc_device {
|
||||
struct device dev;
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <linux/const.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* The struct used to pass data via the following ioctl. Similar to the
|
||||
@ -66,6 +67,17 @@ struct rtc_pll_info {
|
||||
long pll_clock; /* base PLL frequency */
|
||||
};
|
||||
|
||||
struct rtc_param {
|
||||
__u64 param;
|
||||
union {
|
||||
__u64 uvalue;
|
||||
__s64 svalue;
|
||||
__u64 ptr;
|
||||
};
|
||||
__u32 index;
|
||||
__u32 __pad;
|
||||
};
|
||||
|
||||
/*
|
||||
* ioctl calls that are permitted to the /dev/rtc interface, if
|
||||
* any of the RTC drivers are enabled.
|
||||
@ -95,6 +107,9 @@ struct rtc_pll_info {
|
||||
#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */
|
||||
#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */
|
||||
|
||||
#define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param) /* Get parameter */
|
||||
#define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param) /* Set parameter */
|
||||
|
||||
#define RTC_VL_DATA_INVALID _BITUL(0) /* Voltage too low, RTC data is invalid */
|
||||
#define RTC_VL_BACKUP_LOW _BITUL(1) /* Backup voltage is low */
|
||||
#define RTC_VL_BACKUP_EMPTY _BITUL(2) /* Backup empty or not present */
|
||||
@ -114,7 +129,21 @@ struct rtc_pll_info {
|
||||
#define RTC_FEATURE_ALARM 0
|
||||
#define RTC_FEATURE_ALARM_RES_MINUTE 1
|
||||
#define RTC_FEATURE_NEED_WEEK_DAY 2
|
||||
#define RTC_FEATURE_CNT 3
|
||||
#define RTC_FEATURE_ALARM_RES_2S 3
|
||||
#define RTC_FEATURE_UPDATE_INTERRUPT 4
|
||||
#define RTC_FEATURE_CORRECTION 5
|
||||
#define RTC_FEATURE_BACKUP_SWITCH_MODE 6
|
||||
#define RTC_FEATURE_CNT 7
|
||||
|
||||
/* parameter list */
|
||||
#define RTC_PARAM_FEATURES 0
|
||||
#define RTC_PARAM_CORRECTION 1
|
||||
#define RTC_PARAM_BACKUP_SWITCH_MODE 2
|
||||
|
||||
#define RTC_BSM_DISABLED 0
|
||||
#define RTC_BSM_DIRECT 1
|
||||
#define RTC_BSM_LEVEL 2
|
||||
#define RTC_BSM_STANDBY 3
|
||||
|
||||
#define RTC_MAX_FREQ 8192
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user