mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
RTC for 6.15
Core:
- setdate is removed as it has better replacements
- skip alarms with a second resolution when we know the RTC doesn't support
those.
Subsystem:
- remove unnecessary private struct members
- use devm_pm_set_wake_irq were relevant
Drivers:
- ds1307: stop disabling alarms on probe for DS1337, DS1339, DS1341 and DS3231
- max31335: add max31331 support
- pcf50633 is removed as support for the related SoC has been removed
- pcf85063: properly handle POR failures
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmftwMgACgkQY6TcMGxw
OjKk1g//dwDeinPyXC8+isDYCf07U6xy1OmvZcQSqG1qL64rONY1KoUKVq92mQUs
1+rijwIJMi4MNJqaCwYHAEhvXxYJNoQLcV3uHkqVjrRfGQY0Mgl4/pLALGNp6P4U
QixG8qJiVzAMolTVUozqp/amTc0zztFT6Fnr1EbrLkx0JZX5D09Na5pgdbvoBFX3
pH5kxYQotpBD8x8CUHFU0oz8dEeSAbISEVJKX1Ct9xTqhYX9/OB92jQvvg46STPU
2J6n9Yl9eH77itX8GmaDyNyKIIzAZktWuZofiPkni090W/H+uVIdSo0/pHRinvsA
hoZBLc9CjUDFfqK9uuFOszl1lW/zpVkLdz3VR9OYxjIFzDk5KKnAK9g669VIBm3P
yPlYQL9TzW+uacpzdN7YhUW0Oy5opRcYjjCrTg5znTtFFplxrMucveyXb8wAP3DG
m68C1LJzCOxzYAqnfzh59UYSr+JexDJgEH1u79d0GYFrTXZ4mY6i94yva4lIOofX
uaUuTOsUyQY4ZxMEXw2FlUzvSmQBaALj7ycMFmSBWYa5efI7UWZ2r2HZ0jX30HQU
m+bG/+eMMZq9gYsiCrYxo0J+afpZ0lTRmyecnuCqP79rYPTCrOui/2n3fZryGfjV
cDUYbFl5VbsYpwT/sBUrsKU8e9YYb85ACep3WbRlnS7YI5qkM+Y=
=QJeg
-----END PGP SIGNATURE-----
Merge tag 'rtc-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni:
"We see a net reduction of the number of lines of code thanks to the
removal of a now unused driver and a testing tool that is not used
anymore. Apart from this, the max31335 driver gets support for a new
part number and pm8xxx gets UEFI support.
Core:
- setdate is removed as it has better replacements
- skip alarms with a second resolution when we know the RTC doesn't
support those.
Subsystem:
- remove unnecessary private struct members
- use devm_pm_set_wake_irq were relevant
Drivers:
- ds1307: stop disabling alarms on probe for DS1337, DS1339, DS1341
and DS3231
- max31335: add max31331 support
- pcf50633 is removed as support for the related SoC has been removed
- pcf85063: properly handle POR failures"
* tag 'rtc-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (50 commits)
rtc: remove 'setdate' test program
selftest: rtc: skip some tests if the alarm only supports minutes
rtc: mt6397: drop unused defines
rtc: pcf85063: replace dev_err+return with return dev_err_probe
rtc: pcf85063: do a SW reset if POR failed
rtc: max31335: Add driver support for max31331
dt-bindings: rtc: max31335: Add max31331 support
rtc: cros-ec: Avoid a couple of -Wflex-array-member-not-at-end warnings
dt-bindings: rtc: pcf2127: Reference spi-peripheral-props.yaml
rtc: rzn1: implement one-second accuracy for alarms
rtc: pcf50633: Remove
rtc: pm8xxx: implement qcom,no-alarm flag for non-HLOS owned alarm
rtc: pm8xxx: mitigate flash wear
rtc: pm8xxx: add support for uefi offset
dt-bindings: rtc: qcom-pm8xxx: document qcom,no-alarm flag
rtc: rv3032: drop WADA
rtc: rv3032: fix EERD location
rtc: pm8xxx: switch to devm_device_init_wakeup
rtc: pm8xxx: fix possible race condition
rtc: mpfs: switch to devm_device_init_wakeup
...
This commit is contained in:
commit
5916a6fbc0
|
|
@ -18,7 +18,9 @@ allOf:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,max31335
|
||||
enum:
|
||||
- adi,max31331
|
||||
- adi,max31335
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ title: NXP PCF2127 Real Time Clock
|
|||
|
||||
allOf:
|
||||
- $ref: rtc.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
maintainers:
|
||||
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
|
|
@ -34,7 +35,7 @@ required:
|
|||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ properties:
|
|||
items:
|
||||
- const: offset
|
||||
|
||||
qcom,no-alarm:
|
||||
type: boolean
|
||||
description:
|
||||
RTC alarm is not owned by the OS
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
required:
|
||||
|
|
|
|||
|
|
@ -1321,13 +1321,6 @@ config RTC_DRV_SPEAR
|
|||
If you say Y here you will get support for the RTC found on
|
||||
spear
|
||||
|
||||
config RTC_DRV_PCF50633
|
||||
depends on MFD_PCF50633
|
||||
tristate "NXP PCF50633 RTC"
|
||||
help
|
||||
If you say yes here you get support for the RTC subsystem of the
|
||||
NXP PCF50633 used in embedded systems.
|
||||
|
||||
config RTC_DRV_AB8500
|
||||
tristate "ST-Ericsson AB8500 RTC"
|
||||
depends on AB8500_CORE
|
||||
|
|
|
|||
|
|
@ -126,7 +126,6 @@ obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
|
|||
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
|
||||
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_PCF8523) += rtc-pcf8523.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
|
||||
|
|
|
|||
|
|
@ -426,29 +426,9 @@ static umode_t abeoz9_is_visible(const void *data,
|
|||
}
|
||||
}
|
||||
|
||||
static const u32 abeoz9_chip_config[] = {
|
||||
HWMON_C_REGISTER_TZ,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info abeoz9_chip = {
|
||||
.type = hwmon_chip,
|
||||
.config = abeoz9_chip_config,
|
||||
};
|
||||
|
||||
static const u32 abeoz9_temp_config[] = {
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info abeoz9_temp = {
|
||||
.type = hwmon_temp,
|
||||
.config = abeoz9_temp_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info * const abeoz9_info[] = {
|
||||
&abeoz9_chip,
|
||||
&abeoz9_temp,
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
devm_device_init_wakeup(&pdev->dev);
|
||||
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc))
|
||||
|
|
@ -375,7 +375,7 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
dev_pm_set_wake_irq(&pdev->dev, irq);
|
||||
devm_pm_set_wake_irq(&pdev->dev, irq);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features);
|
||||
|
|
@ -392,18 +392,11 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
|
|||
return devm_rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static void ab8500_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
}
|
||||
|
||||
static struct platform_driver ab8500_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "ab8500-rtc",
|
||||
},
|
||||
.probe = ab8500_rtc_probe,
|
||||
.remove = ab8500_rtc_remove,
|
||||
.id_table = ab85xx_rtc_ids,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include <linux/io.h>
|
||||
|
||||
struct aspeed_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
|
|
@ -85,6 +84,7 @@ static const struct rtc_class_ops aspeed_rtc_ops = {
|
|||
static int aspeed_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct aspeed_rtc *rtc;
|
||||
struct rtc_device *rtc_dev;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
|
|
@ -94,17 +94,17 @@ static int aspeed_rtc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(rtc->base))
|
||||
return PTR_ERR(rtc->base);
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc_dev))
|
||||
return PTR_ERR(rtc_dev);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
rtc->rtc_dev->ops = &aspeed_rtc_ops;
|
||||
rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */
|
||||
rtc_dev->ops = &aspeed_rtc_ops;
|
||||
rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */
|
||||
|
||||
return devm_rtc_register_device(rtc->rtc_dev);
|
||||
return devm_rtc_register_device(rtc_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_rtc_match[] = {
|
||||
|
|
|
|||
|
|
@ -35,21 +35,18 @@ struct cros_ec_rtc {
|
|||
static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command,
|
||||
u32 *response)
|
||||
{
|
||||
DEFINE_RAW_FLEX(struct cros_ec_command, msg, data,
|
||||
sizeof(struct ec_response_rtc));
|
||||
int ret;
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_response_rtc data;
|
||||
} __packed msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg.command = command;
|
||||
msg.msg.insize = sizeof(msg.data);
|
||||
msg->command = command;
|
||||
msg->insize = sizeof(struct ec_response_rtc);
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
|
||||
ret = cros_ec_cmd_xfer_status(cros_ec, msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*response = msg.data.time;
|
||||
*response = ((struct ec_response_rtc *)msg->data)->time;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -57,18 +54,15 @@ static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command,
|
|||
static int cros_ec_rtc_set(struct cros_ec_device *cros_ec, u32 command,
|
||||
u32 param)
|
||||
{
|
||||
DEFINE_RAW_FLEX(struct cros_ec_command, msg, data,
|
||||
sizeof(struct ec_response_rtc));
|
||||
int ret;
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_response_rtc data;
|
||||
} __packed msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg.command = command;
|
||||
msg.msg.outsize = sizeof(msg.data);
|
||||
msg.data.time = param;
|
||||
msg->command = command;
|
||||
msg->outsize = sizeof(struct ec_response_rtc);
|
||||
((struct ec_response_rtc *)msg->data)->time = param;
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
|
||||
ret = cros_ec_cmd_xfer_status(cros_ec, msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1807,10 +1807,8 @@ static int ds1307_probe(struct i2c_client *client)
|
|||
* For some variants, be sure alarms can trigger when we're
|
||||
* running on Vbackup (BBSQI/BBSQW)
|
||||
*/
|
||||
if (want_irq || ds1307_can_wakeup_device) {
|
||||
if (want_irq || ds1307_can_wakeup_device)
|
||||
regs[0] |= DS1337_BIT_INTCN | chip->bbsqi_bit;
|
||||
regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
|
||||
}
|
||||
|
||||
regmap_write(ds1307->regmap, DS1337_REG_CONTROL,
|
||||
regs[0]);
|
||||
|
|
|
|||
|
|
@ -427,18 +427,13 @@ static int ds1343_probe(struct spi_device *spi)
|
|||
"unable to request irq for rtc ds1343\n");
|
||||
} else {
|
||||
device_init_wakeup(&spi->dev, true);
|
||||
dev_pm_set_wake_irq(&spi->dev, spi->irq);
|
||||
devm_pm_set_wake_irq(&spi->dev, spi->irq);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ds1343_remove(struct spi_device *spi)
|
||||
{
|
||||
dev_pm_clear_wake_irq(&spi->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int ds1343_suspend(struct device *dev)
|
||||
|
|
@ -471,7 +466,6 @@ static struct spi_driver ds1343_driver = {
|
|||
.pm = &ds1343_pm,
|
||||
},
|
||||
.probe = ds1343_probe,
|
||||
.remove = ds1343_remove,
|
||||
.id_table = ds1343_id,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ struct ds2404 {
|
|||
struct gpio_desc *rst_gpiod;
|
||||
struct gpio_desc *clk_gpiod;
|
||||
struct gpio_desc *dq_gpiod;
|
||||
struct rtc_device *rtc;
|
||||
};
|
||||
|
||||
static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev)
|
||||
|
|
@ -182,6 +181,7 @@ static const struct rtc_class_ops ds2404_rtc_ops = {
|
|||
static int rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ds2404 *chip;
|
||||
struct rtc_device *rtc;
|
||||
int retval = -EBUSY;
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(struct ds2404), GFP_KERNEL);
|
||||
|
|
@ -190,9 +190,9 @@ static int rtc_probe(struct platform_device *pdev)
|
|||
|
||||
chip->dev = &pdev->dev;
|
||||
|
||||
chip->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(chip->rtc))
|
||||
return PTR_ERR(chip->rtc);
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
retval = ds2404_gpio_map(chip, pdev);
|
||||
if (retval)
|
||||
|
|
@ -200,10 +200,10 @@ static int rtc_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
chip->rtc->ops = &ds2404_rtc_ops;
|
||||
chip->rtc->range_max = U32_MAX;
|
||||
rtc->ops = &ds2404_rtc_ops;
|
||||
rtc->range_max = U32_MAX;
|
||||
|
||||
retval = devm_rtc_register_device(chip->rtc);
|
||||
retval = devm_rtc_register_device(rtc);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
|
|
|||
|
|
@ -339,29 +339,9 @@ static int ds3232_hwmon_read(struct device *dev,
|
|||
return err;
|
||||
}
|
||||
|
||||
static u32 ds3232_hwmon_chip_config[] = {
|
||||
HWMON_C_REGISTER_TZ,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info ds3232_hwmon_chip = {
|
||||
.type = hwmon_chip,
|
||||
.config = ds3232_hwmon_chip_config,
|
||||
};
|
||||
|
||||
static u32 ds3232_hwmon_temp_config[] = {
|
||||
HWMON_T_INPUT,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info ds3232_hwmon_temp = {
|
||||
.type = hwmon_temp,
|
||||
.config = ds3232_hwmon_temp_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info * const ds3232_hwmon_info[] = {
|
||||
&ds3232_hwmon_chip,
|
||||
&ds3232_hwmon_temp,
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
struct ep93xx_rtc {
|
||||
void __iomem *mmio_base;
|
||||
struct rtc_device *rtc;
|
||||
};
|
||||
|
||||
static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
|
||||
|
|
@ -123,6 +122,7 @@ static const struct attribute_group ep93xx_rtc_sysfs_files = {
|
|||
static int ep93xx_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_rtc *ep93xx_rtc;
|
||||
struct rtc_device *rtc;
|
||||
int err;
|
||||
|
||||
ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
|
||||
|
|
@ -135,18 +135,18 @@ static int ep93xx_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, ep93xx_rtc);
|
||||
|
||||
ep93xx_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(ep93xx_rtc->rtc))
|
||||
return PTR_ERR(ep93xx_rtc->rtc);
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
ep93xx_rtc->rtc->ops = &ep93xx_rtc_ops;
|
||||
ep93xx_rtc->rtc->range_max = U32_MAX;
|
||||
rtc->ops = &ep93xx_rtc_ops;
|
||||
rtc->range_max = U32_MAX;
|
||||
|
||||
err = rtc_add_group(ep93xx_rtc->rtc, &ep93xx_rtc_sysfs_files);
|
||||
err = rtc_add_group(rtc, &ep93xx_rtc_sysfs_files);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return devm_rtc_register_device(ep93xx_rtc->rtc);
|
||||
return devm_rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static const struct of_device_id ep93xx_rtc_of_ids[] = {
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ static const struct of_device_id ftm_rtc_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, ftm_rtc_match);
|
||||
|
||||
static const struct acpi_device_id ftm_imx_acpi_ids[] = {
|
||||
static const struct acpi_device_id ftm_imx_acpi_ids[] __maybe_unused = {
|
||||
{"NXP0014",},
|
||||
{ }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ MODULE_LICENSE("GPL");
|
|||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
||||
struct ftrtc010_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *rtc_base;
|
||||
int rtc_irq;
|
||||
struct clk *pclk;
|
||||
|
|
@ -113,6 +112,7 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
|
|||
struct ftrtc010_rtc *rtc;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct rtc_device *rtc_dev;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
|
|
@ -160,29 +160,28 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
|
|||
goto err_disable_extclk;
|
||||
}
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(rtc->rtc_dev)) {
|
||||
ret = PTR_ERR(rtc->rtc_dev);
|
||||
rtc_dev = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(rtc_dev)) {
|
||||
ret = PTR_ERR(rtc_dev);
|
||||
goto err_disable_extclk;
|
||||
}
|
||||
|
||||
rtc->rtc_dev->ops = &ftrtc010_rtc_ops;
|
||||
rtc_dev->ops = &ftrtc010_rtc_ops;
|
||||
|
||||
sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
|
||||
min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
|
||||
hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
|
||||
days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
|
||||
|
||||
rtc->rtc_dev->range_min = (u64)days * 86400 + hour * 3600 +
|
||||
min * 60 + sec;
|
||||
rtc->rtc_dev->range_max = U32_MAX + rtc->rtc_dev->range_min;
|
||||
rtc_dev->range_min = (u64)days * 86400 + hour * 3600 + min * 60 + sec;
|
||||
rtc_dev->range_max = U32_MAX + rtc_dev->range_min;
|
||||
|
||||
ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
|
||||
IRQF_SHARED, pdev->name, dev);
|
||||
if (unlikely(ret))
|
||||
goto err_disable_extclk;
|
||||
|
||||
return devm_rtc_register_device(rtc->rtc_dev);
|
||||
return devm_rtc_register_device(rtc_dev);
|
||||
|
||||
err_disable_extclk:
|
||||
clk_disable_unprepare(rtc->extclk);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
struct m48t86_rtc_info {
|
||||
void __iomem *index_reg;
|
||||
void __iomem *data_reg;
|
||||
struct rtc_device *rtc;
|
||||
};
|
||||
|
||||
static unsigned char m48t86_readb(struct device *dev, unsigned long addr)
|
||||
|
|
@ -219,6 +218,7 @@ static bool m48t86_verify_chip(struct platform_device *pdev)
|
|||
static int m48t86_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct m48t86_rtc_info *info;
|
||||
struct rtc_device *rtc;
|
||||
unsigned char reg;
|
||||
int err;
|
||||
struct nvmem_config m48t86_nvmem_cfg = {
|
||||
|
|
@ -250,17 +250,17 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
info->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(info->rtc))
|
||||
return PTR_ERR(info->rtc);
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
info->rtc->ops = &m48t86_rtc_ops;
|
||||
rtc->ops = &m48t86_rtc_ops;
|
||||
|
||||
err = devm_rtc_register_device(info->rtc);
|
||||
err = devm_rtc_register_device(rtc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
devm_rtc_nvmem_register(info->rtc, &m48t86_nvmem_cfg);
|
||||
devm_rtc_nvmem_register(rtc, &m48t86_nvmem_cfg);
|
||||
|
||||
/* read battery status */
|
||||
reg = m48t86_readb(&pdev->dev, M48T86_D);
|
||||
|
|
|
|||
|
|
@ -184,31 +184,91 @@
|
|||
#define MAX31335_RAM_SIZE 32
|
||||
#define MAX31335_TIME_SIZE 0x07
|
||||
|
||||
/* MAX31331 Register Map */
|
||||
#define MAX31331_RTC_CONFIG2 0x04
|
||||
|
||||
#define clk_hw_to_max31335(_hw) container_of(_hw, struct max31335_data, clkout)
|
||||
|
||||
/* Supported Maxim RTC */
|
||||
enum max_rtc_ids {
|
||||
ID_MAX31331,
|
||||
ID_MAX31335,
|
||||
MAX_RTC_ID_NR
|
||||
};
|
||||
|
||||
struct chip_desc {
|
||||
u8 sec_reg;
|
||||
u8 alarm1_sec_reg;
|
||||
|
||||
u8 int_en_reg;
|
||||
u8 int_status_reg;
|
||||
|
||||
u8 ram_reg;
|
||||
u8 ram_size;
|
||||
|
||||
u8 temp_reg;
|
||||
|
||||
u8 trickle_reg;
|
||||
|
||||
u8 clkout_reg;
|
||||
|
||||
enum max_rtc_ids id;
|
||||
};
|
||||
|
||||
struct max31335_data {
|
||||
struct regmap *regmap;
|
||||
struct rtc_device *rtc;
|
||||
struct clk_hw clkout;
|
||||
struct clk *clkin;
|
||||
const struct chip_desc *chip;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static const int max31335_clkout_freq[] = { 1, 64, 1024, 32768 };
|
||||
|
||||
static const struct chip_desc chip[MAX_RTC_ID_NR] = {
|
||||
[ID_MAX31331] = {
|
||||
.id = ID_MAX31331,
|
||||
.int_en_reg = 0x01,
|
||||
.int_status_reg = 0x00,
|
||||
.sec_reg = 0x08,
|
||||
.alarm1_sec_reg = 0x0F,
|
||||
.ram_reg = 0x20,
|
||||
.ram_size = 32,
|
||||
.trickle_reg = 0x1B,
|
||||
.clkout_reg = 0x04,
|
||||
},
|
||||
[ID_MAX31335] = {
|
||||
.id = ID_MAX31335,
|
||||
.int_en_reg = 0x01,
|
||||
.int_status_reg = 0x00,
|
||||
.sec_reg = 0x0A,
|
||||
.alarm1_sec_reg = 0x11,
|
||||
.ram_reg = 0x40,
|
||||
.ram_size = 32,
|
||||
.temp_reg = 0x35,
|
||||
.trickle_reg = 0x1D,
|
||||
.clkout_reg = 0x06,
|
||||
},
|
||||
};
|
||||
|
||||
static const u16 max31335_trickle_resistors[] = {3000, 6000, 11000};
|
||||
|
||||
static bool max31335_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
struct max31335_data *max31335 = dev_get_drvdata(dev);
|
||||
const struct chip_desc *chip = max31335->chip;
|
||||
|
||||
/* time keeping registers */
|
||||
if (reg >= MAX31335_SECONDS &&
|
||||
reg < MAX31335_SECONDS + MAX31335_TIME_SIZE)
|
||||
if (reg >= chip->sec_reg && reg < chip->sec_reg + MAX31335_TIME_SIZE)
|
||||
return true;
|
||||
|
||||
/* interrupt status register */
|
||||
if (reg == MAX31335_STATUS1)
|
||||
if (reg == chip->int_status_reg)
|
||||
return true;
|
||||
|
||||
/* temperature registers */
|
||||
if (reg == MAX31335_TEMP_DATA_MSB || reg == MAX31335_TEMP_DATA_LSB)
|
||||
/* temperature registers if valid */
|
||||
if (chip->temp_reg && (reg == chip->temp_reg || reg == chip->temp_reg + 1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -227,7 +287,7 @@ static int max31335_read_time(struct device *dev, struct rtc_time *tm)
|
|||
u8 date[7];
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(max31335->regmap, MAX31335_SECONDS, date,
|
||||
ret = regmap_bulk_read(max31335->regmap, max31335->chip->sec_reg, date,
|
||||
sizeof(date));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -262,7 +322,7 @@ static int max31335_set_time(struct device *dev, struct rtc_time *tm)
|
|||
if (tm->tm_year >= 200)
|
||||
date[5] |= FIELD_PREP(MAX31335_MONTH_CENTURY, 1);
|
||||
|
||||
return regmap_bulk_write(max31335->regmap, MAX31335_SECONDS, date,
|
||||
return regmap_bulk_write(max31335->regmap, max31335->chip->sec_reg, date,
|
||||
sizeof(date));
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +333,7 @@ static int max31335_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
struct rtc_time time;
|
||||
u8 regs[6];
|
||||
|
||||
ret = regmap_bulk_read(max31335->regmap, MAX31335_ALM1_SEC, regs,
|
||||
ret = regmap_bulk_read(max31335->regmap, max31335->chip->alarm1_sec_reg, regs,
|
||||
sizeof(regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -292,11 +352,11 @@ static int max31335_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
if (time.tm_year >= 200)
|
||||
alrm->time.tm_year += 100;
|
||||
|
||||
ret = regmap_read(max31335->regmap, MAX31335_INT_EN1, &ctrl);
|
||||
ret = regmap_read(max31335->regmap, max31335->chip->int_en_reg, &ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(max31335->regmap, MAX31335_STATUS1, &status);
|
||||
ret = regmap_read(max31335->regmap, max31335->chip->int_status_reg, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -320,18 +380,18 @@ static int max31335_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
regs[4] = bin2bcd(alrm->time.tm_mon + 1);
|
||||
regs[5] = bin2bcd(alrm->time.tm_year % 100);
|
||||
|
||||
ret = regmap_bulk_write(max31335->regmap, MAX31335_ALM1_SEC,
|
||||
ret = regmap_bulk_write(max31335->regmap, max31335->chip->alarm1_sec_reg,
|
||||
regs, sizeof(regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg = FIELD_PREP(MAX31335_INT_EN1_A1IE, alrm->enabled);
|
||||
ret = regmap_update_bits(max31335->regmap, MAX31335_INT_EN1,
|
||||
ret = regmap_update_bits(max31335->regmap, max31335->chip->int_en_reg,
|
||||
MAX31335_INT_EN1_A1IE, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(max31335->regmap, MAX31335_STATUS1,
|
||||
ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg,
|
||||
MAX31335_STATUS1_A1F, 0);
|
||||
|
||||
return 0;
|
||||
|
|
@ -341,23 +401,33 @@ static int max31335_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
{
|
||||
struct max31335_data *max31335 = dev_get_drvdata(dev);
|
||||
|
||||
return regmap_update_bits(max31335->regmap, MAX31335_INT_EN1,
|
||||
return regmap_update_bits(max31335->regmap, max31335->chip->int_en_reg,
|
||||
MAX31335_INT_EN1_A1IE, enabled);
|
||||
}
|
||||
|
||||
static irqreturn_t max31335_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct max31335_data *max31335 = dev_id;
|
||||
bool status;
|
||||
int ret;
|
||||
struct mutex *lock = &max31335->rtc->ops_lock;
|
||||
int ret, status;
|
||||
|
||||
ret = regmap_update_bits_check(max31335->regmap, MAX31335_STATUS1,
|
||||
MAX31335_STATUS1_A1F, 0, &status);
|
||||
mutex_lock(lock);
|
||||
|
||||
ret = regmap_read(max31335->regmap, max31335->chip->int_status_reg, &status);
|
||||
if (ret)
|
||||
return IRQ_HANDLED;
|
||||
goto exit;
|
||||
|
||||
if (FIELD_GET(MAX31335_STATUS1_A1F, status)) {
|
||||
ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg,
|
||||
MAX31335_STATUS1_A1F, 0);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
if (status)
|
||||
rtc_update_irq(max31335->rtc, 1, RTC_AF | RTC_IRQF);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -404,7 +474,7 @@ static int max31335_trickle_charger_setup(struct device *dev,
|
|||
|
||||
i = i + trickle_cfg;
|
||||
|
||||
return regmap_write(max31335->regmap, MAX31335_TRICKLE_REG,
|
||||
return regmap_write(max31335->regmap, max31335->chip->trickle_reg,
|
||||
FIELD_PREP(MAX31335_TRICKLE_REG_TRICKLE, i) |
|
||||
FIELD_PREP(MAX31335_TRICKLE_REG_EN_TRICKLE,
|
||||
chargeable));
|
||||
|
|
@ -418,7 +488,7 @@ static unsigned long max31335_clkout_recalc_rate(struct clk_hw *hw,
|
|||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(max31335->regmap, MAX31335_RTC_CONFIG2, ®);
|
||||
ret = regmap_read(max31335->regmap, max31335->chip->clkout_reg, ®);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
|
|
@ -449,23 +519,23 @@ static int max31335_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
ARRAY_SIZE(max31335_clkout_freq));
|
||||
freq_mask = __roundup_pow_of_two(ARRAY_SIZE(max31335_clkout_freq)) - 1;
|
||||
|
||||
return regmap_update_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
|
||||
freq_mask, index);
|
||||
return regmap_update_bits(max31335->regmap, max31335->chip->clkout_reg,
|
||||
freq_mask, index);
|
||||
}
|
||||
|
||||
static int max31335_clkout_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct max31335_data *max31335 = clk_hw_to_max31335(hw);
|
||||
|
||||
return regmap_set_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
|
||||
MAX31335_RTC_CONFIG2_ENCLKO);
|
||||
return regmap_set_bits(max31335->regmap, max31335->chip->clkout_reg,
|
||||
MAX31335_RTC_CONFIG2_ENCLKO);
|
||||
}
|
||||
|
||||
static void max31335_clkout_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct max31335_data *max31335 = clk_hw_to_max31335(hw);
|
||||
|
||||
regmap_clear_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
|
||||
regmap_clear_bits(max31335->regmap, max31335->chip->clkout_reg,
|
||||
MAX31335_RTC_CONFIG2_ENCLKO);
|
||||
}
|
||||
|
||||
|
|
@ -475,7 +545,7 @@ static int max31335_clkout_is_enabled(struct clk_hw *hw)
|
|||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(max31335->regmap, MAX31335_RTC_CONFIG2, ®);
|
||||
ret = regmap_read(max31335->regmap, max31335->chip->clkout_reg, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -500,7 +570,7 @@ static int max31335_nvmem_reg_read(void *priv, unsigned int offset,
|
|||
void *val, size_t bytes)
|
||||
{
|
||||
struct max31335_data *max31335 = priv;
|
||||
unsigned int reg = MAX31335_TS0_SEC_1_128 + offset;
|
||||
unsigned int reg = max31335->chip->ram_reg + offset;
|
||||
|
||||
return regmap_bulk_read(max31335->regmap, reg, val, bytes);
|
||||
}
|
||||
|
|
@ -509,7 +579,7 @@ static int max31335_nvmem_reg_write(void *priv, unsigned int offset,
|
|||
void *val, size_t bytes)
|
||||
{
|
||||
struct max31335_data *max31335 = priv;
|
||||
unsigned int reg = MAX31335_TS0_SEC_1_128 + offset;
|
||||
unsigned int reg = max31335->chip->ram_reg + offset;
|
||||
|
||||
return regmap_bulk_write(max31335->regmap, reg, val, bytes);
|
||||
}
|
||||
|
|
@ -533,7 +603,7 @@ static int max31335_read_temp(struct device *dev, enum hwmon_sensor_types type,
|
|||
if (type != hwmon_temp || attr != hwmon_temp_input)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = regmap_bulk_read(max31335->regmap, MAX31335_TEMP_DATA_MSB,
|
||||
ret = regmap_bulk_read(max31335->regmap, max31335->chip->temp_reg,
|
||||
reg, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -577,8 +647,8 @@ static int max31335_clkout_register(struct device *dev)
|
|||
int ret;
|
||||
|
||||
if (!device_property_present(dev, "#clock-cells"))
|
||||
return regmap_clear_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
|
||||
MAX31335_RTC_CONFIG2_ENCLKO);
|
||||
return regmap_clear_bits(max31335->regmap, max31335->chip->clkout_reg,
|
||||
MAX31335_RTC_CONFIG2_ENCLKO);
|
||||
|
||||
max31335->clkout.init = &max31335_clk_init;
|
||||
|
||||
|
|
@ -605,6 +675,7 @@ static int max31335_probe(struct i2c_client *client)
|
|||
#if IS_REACHABLE(HWMON)
|
||||
struct device *hwmon;
|
||||
#endif
|
||||
const struct chip_desc *match;
|
||||
int ret;
|
||||
|
||||
max31335 = devm_kzalloc(&client->dev, sizeof(*max31335), GFP_KERNEL);
|
||||
|
|
@ -616,7 +687,10 @@ static int max31335_probe(struct i2c_client *client)
|
|||
return PTR_ERR(max31335->regmap);
|
||||
|
||||
i2c_set_clientdata(client, max31335);
|
||||
|
||||
match = i2c_get_match_data(client);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
max31335->chip = match;
|
||||
max31335->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(max31335->rtc))
|
||||
return PTR_ERR(max31335->rtc);
|
||||
|
|
@ -639,6 +713,8 @@ static int max31335_probe(struct i2c_client *client)
|
|||
dev_warn(&client->dev,
|
||||
"unable to request IRQ, alarm max31335 disabled\n");
|
||||
client->irq = 0;
|
||||
} else {
|
||||
max31335->irq = client->irq;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -652,13 +728,13 @@ static int max31335_probe(struct i2c_client *client)
|
|||
"cannot register rtc nvmem\n");
|
||||
|
||||
#if IS_REACHABLE(HWMON)
|
||||
hwmon = devm_hwmon_device_register_with_info(&client->dev, client->name,
|
||||
max31335,
|
||||
&max31335_chip_info,
|
||||
NULL);
|
||||
if (IS_ERR(hwmon))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(hwmon),
|
||||
"cannot register hwmon device\n");
|
||||
if (max31335->chip->temp_reg) {
|
||||
hwmon = devm_hwmon_device_register_with_info(&client->dev, client->name, max31335,
|
||||
&max31335_chip_info, NULL);
|
||||
if (IS_ERR(hwmon))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(hwmon),
|
||||
"cannot register hwmon device\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = max31335_trickle_charger_setup(&client->dev, max31335);
|
||||
|
|
@ -669,14 +745,16 @@ static int max31335_probe(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id max31335_id[] = {
|
||||
{ "max31335" },
|
||||
{ "max31331", (kernel_ulong_t)&chip[ID_MAX31331] },
|
||||
{ "max31335", (kernel_ulong_t)&chip[ID_MAX31335] },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, max31335_id);
|
||||
|
||||
static const struct of_device_id max31335_of_match[] = {
|
||||
{ .compatible = "adi,max31335" },
|
||||
{ .compatible = "adi,max31331", .data = &chip[ID_MAX31331] },
|
||||
{ .compatible = "adi,max31335", .data = &chip[ID_MAX31335] },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
@ -693,5 +771,6 @@ static struct i2c_driver max31335_driver = {
|
|||
module_i2c_driver(max31335_driver);
|
||||
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
|
||||
MODULE_AUTHOR("Saket Kumar Purwar <Saket.Kumarpurwar@analog.com>");
|
||||
MODULE_DESCRIPTION("MAX31335 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ struct max77686_rtc_driver_data {
|
|||
|
||||
struct max77686_rtc_info {
|
||||
struct device *dev;
|
||||
struct i2c_client *rtc;
|
||||
struct rtc_device *rtc_dev;
|
||||
struct mutex lock;
|
||||
|
||||
|
|
@ -691,6 +690,7 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
|
|||
{
|
||||
struct device *parent = info->dev->parent;
|
||||
struct i2c_client *parent_i2c = to_i2c_client(parent);
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
if (info->drv_data->rtc_irq_from_platform) {
|
||||
|
|
@ -704,40 +704,35 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
|
|||
}
|
||||
|
||||
info->regmap = dev_get_regmap(parent, NULL);
|
||||
if (!info->regmap) {
|
||||
dev_err(info->dev, "Failed to get rtc regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!info->regmap)
|
||||
return dev_err_probe(info->dev, -ENODEV,
|
||||
"Failed to get rtc regmap\n");
|
||||
|
||||
if (info->drv_data->rtc_i2c_addr == MAX77686_INVALID_I2C_ADDR) {
|
||||
info->rtc_regmap = info->regmap;
|
||||
goto add_rtc_irq;
|
||||
}
|
||||
|
||||
info->rtc = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter,
|
||||
info->drv_data->rtc_i2c_addr);
|
||||
if (IS_ERR(info->rtc)) {
|
||||
dev_err(info->dev, "Failed to allocate I2C device for RTC\n");
|
||||
return PTR_ERR(info->rtc);
|
||||
}
|
||||
client = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter,
|
||||
info->drv_data->rtc_i2c_addr);
|
||||
if (IS_ERR(client))
|
||||
return dev_err_probe(info->dev, PTR_ERR(client),
|
||||
"Failed to allocate I2C device for RTC\n");
|
||||
|
||||
info->rtc_regmap = devm_regmap_init_i2c(info->rtc,
|
||||
info->rtc_regmap = devm_regmap_init_i2c(client,
|
||||
info->drv_data->regmap_config);
|
||||
if (IS_ERR(info->rtc_regmap)) {
|
||||
ret = PTR_ERR(info->rtc_regmap);
|
||||
dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(info->rtc_regmap))
|
||||
return dev_err_probe(info->dev, PTR_ERR(info->rtc_regmap),
|
||||
"Failed to allocate RTC regmap\n");
|
||||
|
||||
add_rtc_irq:
|
||||
ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED,
|
||||
0, info->drv_data->rtc_irq_chip,
|
||||
&info->rtc_irq_data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(info->dev, ret,
|
||||
"Failed to add RTC irq chip\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
struct meson_vrtc_data {
|
||||
void __iomem *io_alarm;
|
||||
struct rtc_device *rtc;
|
||||
unsigned long alarm_time;
|
||||
bool enabled;
|
||||
};
|
||||
|
|
@ -65,6 +64,7 @@ static const struct rtc_class_ops meson_vrtc_ops = {
|
|||
static int meson_vrtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_vrtc_data *vrtc;
|
||||
struct rtc_device *rtc;
|
||||
|
||||
vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL);
|
||||
if (!vrtc)
|
||||
|
|
@ -78,12 +78,12 @@ static int meson_vrtc_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, vrtc);
|
||||
|
||||
vrtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(vrtc->rtc))
|
||||
return PTR_ERR(vrtc->rtc);
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
vrtc->rtc->ops = &meson_vrtc_ops;
|
||||
return devm_rtc_register_device(vrtc->rtc);
|
||||
rtc->ops = &meson_vrtc_ops;
|
||||
return devm_rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static int __maybe_unused meson_vrtc_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@
|
|||
#define MESON_STATIC_DEFAULT (MESON_STATIC_BIAS_CUR | MESON_STATIC_VOLTAGE)
|
||||
|
||||
struct meson_rtc {
|
||||
struct rtc_device *rtc; /* rtc device we created */
|
||||
struct device *dev; /* device we bound from */
|
||||
struct reset_control *reset; /* reset source */
|
||||
struct regulator *vdd; /* voltage input */
|
||||
|
|
@ -292,6 +291,7 @@ static int meson_rtc_probe(struct platform_device *pdev)
|
|||
};
|
||||
struct device *dev = &pdev->dev;
|
||||
struct meson_rtc *rtc;
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
u32 tm;
|
||||
|
|
@ -300,16 +300,16 @@ static int meson_rtc_probe(struct platform_device *pdev)
|
|||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->rtc = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(rtc->rtc))
|
||||
return PTR_ERR(rtc->rtc);
|
||||
rtc_dev = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(rtc_dev))
|
||||
return PTR_ERR(rtc_dev);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
rtc->dev = dev;
|
||||
|
||||
rtc->rtc->ops = &meson_rtc_ops;
|
||||
rtc->rtc->range_max = U32_MAX;
|
||||
rtc_dev->ops = &meson_rtc_ops;
|
||||
rtc_dev->range_max = U32_MAX;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
|
|
@ -365,11 +365,11 @@ static int meson_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
meson_rtc_nvmem_config.priv = rtc;
|
||||
ret = devm_rtc_nvmem_register(rtc->rtc, &meson_rtc_nvmem_config);
|
||||
ret = devm_rtc_nvmem_register(rtc_dev, &meson_rtc_nvmem_config);
|
||||
if (ret)
|
||||
goto out_disable_vdd;
|
||||
|
||||
ret = devm_rtc_register_device(rtc->rtc);
|
||||
ret = devm_rtc_register_device(rtc_dev);
|
||||
if (ret)
|
||||
goto out_disable_vdd;
|
||||
|
||||
|
|
|
|||
|
|
@ -266,19 +266,14 @@ static int mpfs_rtc_probe(struct platform_device *pdev)
|
|||
writel(prescaler, rtcdev->base + PRESCALER_REG);
|
||||
dev_info(&pdev->dev, "prescaler set to: %lu\n", prescaler);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
ret = dev_pm_set_wake_irq(&pdev->dev, wakeup_irq);
|
||||
devm_device_init_wakeup(&pdev->dev);
|
||||
ret = devm_pm_set_wake_irq(&pdev->dev, wakeup_irq);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to enable irq wake\n");
|
||||
|
||||
return devm_rtc_register_device(rtcdev->rtc);
|
||||
}
|
||||
|
||||
static void mpfs_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id mpfs_rtc_of_match[] = {
|
||||
{ .compatible = "microchip,mpfs-rtc" },
|
||||
{ }
|
||||
|
|
@ -288,7 +283,6 @@ MODULE_DEVICE_TABLE(of, mpfs_rtc_of_match);
|
|||
|
||||
static struct platform_driver mpfs_rtc_driver = {
|
||||
.probe = mpfs_rtc_probe,
|
||||
.remove = mpfs_rtc_remove,
|
||||
.driver = {
|
||||
.name = "mpfs_rtc",
|
||||
.of_match_table = mpfs_rtc_of_match,
|
||||
|
|
|
|||
|
|
@ -189,36 +189,26 @@ static int bbnsm_rtc_probe(struct platform_device *pdev)
|
|||
/* clear all the pending events */
|
||||
regmap_write(bbnsm->regmap, BBNSM_EVENTS, 0x7A);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
dev_pm_set_wake_irq(&pdev->dev, bbnsm->irq);
|
||||
ret = devm_device_init_wakeup(&pdev->dev);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to init wakeup, %d\n", ret);
|
||||
|
||||
ret = devm_pm_set_wake_irq(&pdev->dev, bbnsm->irq);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to set wake irq, %d\n", ret);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_rtc_irq_handler,
|
||||
IRQF_SHARED, "rtc alarm", &pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request irq %d: %d\n",
|
||||
bbnsm->irq, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bbnsm->rtc->ops = &bbnsm_rtc_ops;
|
||||
bbnsm->rtc->range_max = U32_MAX;
|
||||
|
||||
ret = devm_rtc_register_device(bbnsm->rtc);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bbnsm_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
return devm_rtc_register_device(bbnsm->rtc);
|
||||
}
|
||||
|
||||
static const struct of_device_id bbnsm_dt_ids[] = {
|
||||
|
|
@ -233,7 +223,6 @@ static struct platform_driver bbnsm_rtc_driver = {
|
|||
.of_match_table = bbnsm_dt_ids,
|
||||
},
|
||||
.probe = bbnsm_rtc_probe,
|
||||
.remove = bbnsm_rtc_remove,
|
||||
};
|
||||
module_platform_driver(bbnsm_rtc_driver);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,284 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* NXP PCF50633 RTC Driver
|
||||
*
|
||||
* (C) 2006-2008 by Openmoko, Inc.
|
||||
* Author: Balaji Rao <balajirrao@openmoko.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Broken down from monstrous PCF50633 driver mainly by
|
||||
* Harald Welte, Andy Green and Werner Almesberger
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/mfd/pcf50633/core.h>
|
||||
|
||||
#define PCF50633_REG_RTCSC 0x59 /* Second */
|
||||
#define PCF50633_REG_RTCMN 0x5a /* Minute */
|
||||
#define PCF50633_REG_RTCHR 0x5b /* Hour */
|
||||
#define PCF50633_REG_RTCWD 0x5c /* Weekday */
|
||||
#define PCF50633_REG_RTCDT 0x5d /* Day */
|
||||
#define PCF50633_REG_RTCMT 0x5e /* Month */
|
||||
#define PCF50633_REG_RTCYR 0x5f /* Year */
|
||||
#define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */
|
||||
#define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */
|
||||
#define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */
|
||||
#define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */
|
||||
#define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */
|
||||
#define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */
|
||||
#define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */
|
||||
|
||||
enum pcf50633_time_indexes {
|
||||
PCF50633_TI_SEC,
|
||||
PCF50633_TI_MIN,
|
||||
PCF50633_TI_HOUR,
|
||||
PCF50633_TI_WKDAY,
|
||||
PCF50633_TI_DAY,
|
||||
PCF50633_TI_MONTH,
|
||||
PCF50633_TI_YEAR,
|
||||
PCF50633_TI_EXTENT /* always last */
|
||||
};
|
||||
|
||||
struct pcf50633_time {
|
||||
u_int8_t time[PCF50633_TI_EXTENT];
|
||||
};
|
||||
|
||||
struct pcf50633_rtc {
|
||||
int alarm_enabled;
|
||||
int alarm_pending;
|
||||
|
||||
struct pcf50633 *pcf;
|
||||
struct rtc_device *rtc_dev;
|
||||
};
|
||||
|
||||
static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)
|
||||
{
|
||||
rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]);
|
||||
rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]);
|
||||
rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);
|
||||
rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);
|
||||
rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]);
|
||||
rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]) - 1;
|
||||
rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;
|
||||
}
|
||||
|
||||
static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)
|
||||
{
|
||||
pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec);
|
||||
pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min);
|
||||
pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);
|
||||
pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);
|
||||
pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday);
|
||||
pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon + 1);
|
||||
pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);
|
||||
}
|
||||
|
||||
static int
|
||||
pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct pcf50633_rtc *rtc = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
if (enabled)
|
||||
err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
else
|
||||
err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rtc->alarm_enabled = enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pcf50633_rtc *rtc;
|
||||
struct pcf50633_time pcf_tm;
|
||||
int ret;
|
||||
|
||||
rtc = dev_get_drvdata(dev);
|
||||
|
||||
ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC,
|
||||
PCF50633_TI_EXTENT,
|
||||
&pcf_tm.time[0]);
|
||||
if (ret != PCF50633_TI_EXTENT) {
|
||||
dev_err(dev, "Failed to read time\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
|
||||
pcf_tm.time[PCF50633_TI_DAY],
|
||||
pcf_tm.time[PCF50633_TI_MONTH],
|
||||
pcf_tm.time[PCF50633_TI_YEAR],
|
||||
pcf_tm.time[PCF50633_TI_HOUR],
|
||||
pcf_tm.time[PCF50633_TI_MIN],
|
||||
pcf_tm.time[PCF50633_TI_SEC]);
|
||||
|
||||
pcf2rtc_time(tm, &pcf_tm);
|
||||
|
||||
dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pcf50633_rtc *rtc;
|
||||
struct pcf50633_time pcf_tm;
|
||||
int alarm_masked, ret = 0;
|
||||
|
||||
rtc = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
|
||||
|
||||
rtc2pcf_time(&pcf_tm, tm);
|
||||
|
||||
dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
|
||||
pcf_tm.time[PCF50633_TI_DAY],
|
||||
pcf_tm.time[PCF50633_TI_MONTH],
|
||||
pcf_tm.time[PCF50633_TI_YEAR],
|
||||
pcf_tm.time[PCF50633_TI_HOUR],
|
||||
pcf_tm.time[PCF50633_TI_MIN],
|
||||
pcf_tm.time[PCF50633_TI_SEC]);
|
||||
|
||||
|
||||
alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
|
||||
if (!alarm_masked)
|
||||
pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
|
||||
/* Returns 0 on success */
|
||||
ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC,
|
||||
PCF50633_TI_EXTENT,
|
||||
&pcf_tm.time[0]);
|
||||
|
||||
if (!alarm_masked)
|
||||
pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct pcf50633_rtc *rtc;
|
||||
struct pcf50633_time pcf_tm;
|
||||
int ret = 0;
|
||||
|
||||
rtc = dev_get_drvdata(dev);
|
||||
|
||||
alrm->enabled = rtc->alarm_enabled;
|
||||
alrm->pending = rtc->alarm_pending;
|
||||
|
||||
ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
|
||||
PCF50633_TI_EXTENT, &pcf_tm.time[0]);
|
||||
if (ret != PCF50633_TI_EXTENT) {
|
||||
dev_err(dev, "Failed to read time\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pcf2rtc_time(&alrm->time, &pcf_tm);
|
||||
|
||||
return rtc_valid_tm(&alrm->time);
|
||||
}
|
||||
|
||||
static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct pcf50633_rtc *rtc;
|
||||
struct pcf50633_time pcf_tm;
|
||||
int alarm_masked, ret = 0;
|
||||
|
||||
rtc = dev_get_drvdata(dev);
|
||||
|
||||
rtc2pcf_time(&pcf_tm, &alrm->time);
|
||||
|
||||
/* do like mktime does and ignore tm_wday */
|
||||
pcf_tm.time[PCF50633_TI_WKDAY] = 7;
|
||||
|
||||
alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
|
||||
/* disable alarm interrupt */
|
||||
if (!alarm_masked)
|
||||
pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
|
||||
/* Returns 0 on success */
|
||||
ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,
|
||||
PCF50633_TI_EXTENT, &pcf_tm.time[0]);
|
||||
if (!alrm->enabled)
|
||||
rtc->alarm_pending = 0;
|
||||
|
||||
if (!alarm_masked || alrm->enabled)
|
||||
pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
rtc->alarm_enabled = alrm->enabled;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops pcf50633_rtc_ops = {
|
||||
.read_time = pcf50633_rtc_read_time,
|
||||
.set_time = pcf50633_rtc_set_time,
|
||||
.read_alarm = pcf50633_rtc_read_alarm,
|
||||
.set_alarm = pcf50633_rtc_set_alarm,
|
||||
.alarm_irq_enable = pcf50633_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static void pcf50633_rtc_irq(int irq, void *data)
|
||||
{
|
||||
struct pcf50633_rtc *rtc = data;
|
||||
|
||||
rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
|
||||
rtc->alarm_pending = 1;
|
||||
}
|
||||
|
||||
static int pcf50633_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pcf50633_rtc *rtc;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->pcf = dev_to_pcf50633(pdev->dev.parent);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "pcf50633-rtc",
|
||||
&pcf50633_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
|
||||
pcf50633_rtc_irq, rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcf50633_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pcf50633_rtc *rtc;
|
||||
|
||||
rtc = platform_get_drvdata(pdev);
|
||||
pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
|
||||
}
|
||||
|
||||
static struct platform_driver pcf50633_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "pcf50633-rtc",
|
||||
},
|
||||
.probe = pcf50633_rtc_probe,
|
||||
.remove = pcf50633_rtc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(pcf50633_rtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("PCF50633 RTC driver");
|
||||
MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
#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_CTRL1_SWR 0x58
|
||||
|
||||
#define PCF85063_REG_CTRL2 0x01
|
||||
#define PCF85063_CTRL2_AF BIT(6)
|
||||
|
|
@ -589,16 +590,30 @@ static int pcf85063_probe(struct i2c_client *client)
|
|||
|
||||
i2c_set_clientdata(client, pcf85063);
|
||||
|
||||
err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "RTC chip is not present\n");
|
||||
return err;
|
||||
}
|
||||
err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp);
|
||||
if (err)
|
||||
return dev_err_probe(&client->dev, err, "RTC chip is not present\n");
|
||||
|
||||
pcf85063->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(pcf85063->rtc))
|
||||
return PTR_ERR(pcf85063->rtc);
|
||||
|
||||
/*
|
||||
* If a Power loss is detected, SW reset the device.
|
||||
* From PCF85063A datasheet:
|
||||
* There is a low probability that some devices will have corruption
|
||||
* of the registers after the automatic power-on reset...
|
||||
*/
|
||||
if (tmp & PCF85063_REG_SC_OS) {
|
||||
dev_warn(&client->dev,
|
||||
"POR issue detected, sending a SW reset\n");
|
||||
err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1,
|
||||
PCF85063_REG_CTRL1_SWR);
|
||||
if (err < 0)
|
||||
dev_warn(&client->dev,
|
||||
"SW reset failed, trying to continue\n");
|
||||
}
|
||||
|
||||
err = pcf85063_load_capacitance(pcf85063, client->dev.of_node,
|
||||
config->force_cap_7000 ? 7000 : 0);
|
||||
if (err < 0)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#define RTC_CR_MIE (1 << 0)
|
||||
|
||||
struct pl030_rtc {
|
||||
struct rtc_device *rtc;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
|
|
@ -86,6 +85,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
{
|
||||
struct pl030_rtc *rtc;
|
||||
int ret;
|
||||
struct rtc_device *rtc_dev;
|
||||
|
||||
ret = amba_request_regions(dev, NULL);
|
||||
if (ret)
|
||||
|
|
@ -97,14 +97,14 @@ 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);
|
||||
rtc_dev = devm_rtc_allocate_device(&dev->dev);
|
||||
if (IS_ERR(rtc_dev)) {
|
||||
ret = PTR_ERR(rtc_dev);
|
||||
goto err_rtc;
|
||||
}
|
||||
|
||||
rtc->rtc->ops = &pl030_ops;
|
||||
rtc->rtc->range_max = U32_MAX;
|
||||
rtc_dev->ops = &pl030_ops;
|
||||
rtc_dev->range_max = U32_MAX;
|
||||
rtc->base = ioremap(dev->res.start, resource_size(&dev->res));
|
||||
if (!rtc->base) {
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -121,7 +121,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
if (ret)
|
||||
goto err_irq;
|
||||
|
||||
ret = devm_rtc_register_device(rtc->rtc);
|
||||
ret = devm_rtc_register_device(rtc_dev);
|
||||
if (ret)
|
||||
goto err_reg;
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ static void pl030_remove(struct amba_device *dev)
|
|||
amba_release_regions(dev);
|
||||
}
|
||||
|
||||
static struct amba_id pl030_ids[] = {
|
||||
static const struct amba_id pl030_ids[] = {
|
||||
{
|
||||
.id = 0x00041030,
|
||||
.mask = 0x000fffff,
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@
|
|||
* @st_weekday: if this is an ST Microelectronics silicon version that need
|
||||
* the weekday fix
|
||||
* @irqflags: special IRQ flags per variant
|
||||
* @range_min: minimum date/time supported by the RTC
|
||||
* @range_max: maximum date/time supported by the RTC
|
||||
*/
|
||||
struct pl031_vendor_data {
|
||||
struct rtc_class_ops ops;
|
||||
|
|
@ -284,8 +286,6 @@ static void pl031_remove(struct amba_device *adev)
|
|||
{
|
||||
struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
|
||||
|
||||
dev_pm_clear_wake_irq(&adev->dev);
|
||||
device_init_wakeup(&adev->dev, false);
|
||||
if (adev->irq[0])
|
||||
free_irq(adev->irq[0], ldata);
|
||||
amba_release_regions(adev);
|
||||
|
|
@ -350,7 +350,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
}
|
||||
}
|
||||
|
||||
device_init_wakeup(&adev->dev, true);
|
||||
devm_device_init_wakeup(&adev->dev);
|
||||
ldata->rtc = devm_rtc_allocate_device(&adev->dev);
|
||||
if (IS_ERR(ldata->rtc)) {
|
||||
ret = PTR_ERR(ldata->rtc);
|
||||
|
|
@ -373,7 +373,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
vendor->irqflags, "rtc-pl031", ldata);
|
||||
if (ret)
|
||||
goto out;
|
||||
dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
|
||||
devm_pm_set_wake_irq(&adev->dev, adev->irq[0]);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (c) 2023, Linaro Limited
|
||||
*/
|
||||
#include <linux/efi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
|
|
@ -16,9 +17,10 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/* RTC_CTRL register bit fields */
|
||||
#define PM8xxx_RTC_ENABLE BIT(7)
|
||||
#define PM8xxx_RTC_ALARM_CLEAR BIT(0)
|
||||
|
|
@ -46,28 +48,125 @@ struct pm8xxx_rtc_regs {
|
|||
unsigned int alarm_en;
|
||||
};
|
||||
|
||||
struct qcom_uefi_rtc_info {
|
||||
__le32 offset_gps;
|
||||
u8 reserved[8];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct pm8xxx_rtc - RTC driver internal structure
|
||||
* @rtc: RTC device
|
||||
* @regmap: regmap used to access registers
|
||||
* @allow_set_time: whether the time can be set
|
||||
* @use_uefi: use UEFI variable as fallback for offset
|
||||
* @alarm_irq: alarm irq number
|
||||
* @regs: register description
|
||||
* @dev: device structure
|
||||
* @rtc_info: qcom uefi rtc-info structure
|
||||
* @nvmem_cell: nvmem cell for offset
|
||||
* @offset: offset from epoch in seconds
|
||||
* @offset_dirty: offset needs to be stored on shutdown
|
||||
*/
|
||||
struct pm8xxx_rtc {
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
bool allow_set_time;
|
||||
bool use_uefi;
|
||||
int alarm_irq;
|
||||
const struct pm8xxx_rtc_regs *regs;
|
||||
struct device *dev;
|
||||
struct qcom_uefi_rtc_info rtc_info;
|
||||
struct nvmem_cell *nvmem_cell;
|
||||
u32 offset;
|
||||
bool offset_dirty;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
|
||||
MODULE_IMPORT_NS("EFIVAR");
|
||||
|
||||
#define QCOM_UEFI_NAME L"RTCInfo"
|
||||
#define QCOM_UEFI_GUID EFI_GUID(0x882f8c2b, 0x9646, 0x435f, \
|
||||
0x8d, 0xe5, 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd)
|
||||
#define QCOM_UEFI_ATTRS (EFI_VARIABLE_NON_VOLATILE | \
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | \
|
||||
EFI_VARIABLE_RUNTIME_ACCESS)
|
||||
|
||||
static int pm8xxx_rtc_read_uefi_offset(struct pm8xxx_rtc *rtc_dd)
|
||||
{
|
||||
struct qcom_uefi_rtc_info *rtc_info = &rtc_dd->rtc_info;
|
||||
unsigned long size = sizeof(*rtc_info);
|
||||
struct device *dev = rtc_dd->dev;
|
||||
efi_status_t status;
|
||||
u32 offset_gps;
|
||||
int rc;
|
||||
|
||||
rc = efivar_lock();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
status = efivar_get_variable(QCOM_UEFI_NAME, &QCOM_UEFI_GUID, NULL,
|
||||
&size, rtc_info);
|
||||
efivar_unlock();
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
dev_dbg(dev, "failed to read UEFI offset: %lu\n", status);
|
||||
return efi_status_to_err(status);
|
||||
}
|
||||
|
||||
if (size != sizeof(*rtc_info)) {
|
||||
dev_dbg(dev, "unexpected UEFI structure size %lu\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "uefi_rtc_info = %*ph\n", (int)size, rtc_info);
|
||||
|
||||
/* Convert from GPS to Unix time offset */
|
||||
offset_gps = le32_to_cpu(rtc_info->offset_gps);
|
||||
rtc_dd->offset = offset_gps + (u32)RTC_TIMESTAMP_EPOCH_GPS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_write_uefi_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
|
||||
{
|
||||
struct qcom_uefi_rtc_info *rtc_info = &rtc_dd->rtc_info;
|
||||
unsigned long size = sizeof(*rtc_info);
|
||||
struct device *dev = rtc_dd->dev;
|
||||
efi_status_t status;
|
||||
u32 offset_gps;
|
||||
|
||||
/* Convert from Unix to GPS time offset */
|
||||
offset_gps = offset - (u32)RTC_TIMESTAMP_EPOCH_GPS;
|
||||
|
||||
rtc_info->offset_gps = cpu_to_le32(offset_gps);
|
||||
|
||||
dev_dbg(dev, "efi_rtc_info = %*ph\n", (int)size, rtc_info);
|
||||
|
||||
status = efivar_set_variable(QCOM_UEFI_NAME, &QCOM_UEFI_GUID,
|
||||
QCOM_UEFI_ATTRS, size, rtc_info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
dev_dbg(dev, "failed to write UEFI offset: %lx\n", status);
|
||||
return efi_status_to_err(status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_EFI */
|
||||
|
||||
static int pm8xxx_rtc_read_uefi_offset(struct pm8xxx_rtc *rtc_dd)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_write_uefi_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EFI */
|
||||
|
||||
static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd)
|
||||
{
|
||||
size_t len;
|
||||
|
|
@ -110,14 +209,6 @@ static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd)
|
||||
{
|
||||
if (!rtc_dd->nvmem_cell)
|
||||
return 0;
|
||||
|
||||
return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
|
||||
{
|
||||
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
|
||||
|
|
@ -155,7 +246,7 @@ static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
|
|||
u32 offset;
|
||||
int rc;
|
||||
|
||||
if (!rtc_dd->nvmem_cell)
|
||||
if (!rtc_dd->nvmem_cell && !rtc_dd->use_uefi)
|
||||
return -ENODEV;
|
||||
|
||||
rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs);
|
||||
|
|
@ -167,10 +258,25 @@ static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
|
|||
if (offset == rtc_dd->offset)
|
||||
return 0;
|
||||
|
||||
rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
|
||||
/*
|
||||
* Reduce flash wear by deferring updates due to clock drift until
|
||||
* shutdown.
|
||||
*/
|
||||
if (abs_diff(offset, rtc_dd->offset) < 30) {
|
||||
rtc_dd->offset_dirty = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rtc_dd->nvmem_cell)
|
||||
rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
|
||||
else
|
||||
rc = pm8xxx_rtc_write_uefi_offset(rtc_dd, offset);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rtc_dd->offset_dirty = false;
|
||||
out:
|
||||
rtc_dd->offset = offset;
|
||||
|
||||
return 0;
|
||||
|
|
@ -455,6 +561,30 @@ static const struct of_device_id pm8xxx_id_table[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
|
||||
|
||||
static int pm8xxx_rtc_probe_offset(struct pm8xxx_rtc *rtc_dd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rtc_dd->nvmem_cell = devm_nvmem_cell_get(rtc_dd->dev, "offset");
|
||||
if (IS_ERR(rtc_dd->nvmem_cell)) {
|
||||
rc = PTR_ERR(rtc_dd->nvmem_cell);
|
||||
if (rc != -ENOENT)
|
||||
return rc;
|
||||
rtc_dd->nvmem_cell = NULL;
|
||||
} else {
|
||||
return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
|
||||
}
|
||||
|
||||
/* Use UEFI storage as fallback if available */
|
||||
if (efivar_is_available()) {
|
||||
rc = pm8xxx_rtc_read_uefi_offset(rtc_dd);
|
||||
if (rc == 0)
|
||||
rtc_dd->use_uefi = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
|
|
@ -469,30 +599,23 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
|
|||
if (rtc_dd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc_dd->regs = match->data;
|
||||
rtc_dd->dev = &pdev->dev;
|
||||
|
||||
rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!rtc_dd->regmap)
|
||||
return -ENXIO;
|
||||
|
||||
rtc_dd->alarm_irq = platform_get_irq(pdev, 0);
|
||||
if (rtc_dd->alarm_irq < 0)
|
||||
return -ENXIO;
|
||||
if (!of_property_read_bool(pdev->dev.of_node, "qcom,no-alarm")) {
|
||||
rtc_dd->alarm_irq = platform_get_irq(pdev, 0);
|
||||
if (rtc_dd->alarm_irq < 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
|
||||
"allow-set-time");
|
||||
|
||||
rtc_dd->nvmem_cell = devm_nvmem_cell_get(&pdev->dev, "offset");
|
||||
if (IS_ERR(rtc_dd->nvmem_cell)) {
|
||||
rc = PTR_ERR(rtc_dd->nvmem_cell);
|
||||
if (rc != -ENOENT)
|
||||
return rc;
|
||||
rtc_dd->nvmem_cell = NULL;
|
||||
}
|
||||
|
||||
rtc_dd->regs = match->data;
|
||||
rtc_dd->dev = &pdev->dev;
|
||||
|
||||
if (!rtc_dd->allow_set_time) {
|
||||
rc = pm8xxx_rtc_read_offset(rtc_dd);
|
||||
rc = pm8xxx_rtc_probe_offset(rtc_dd);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -503,8 +626,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, rtc_dd);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc_dd->rtc))
|
||||
return PTR_ERR(rtc_dd->rtc);
|
||||
|
|
@ -512,32 +633,41 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
|
|||
rtc_dd->rtc->ops = &pm8xxx_rtc_ops;
|
||||
rtc_dd->rtc->range_max = U32_MAX;
|
||||
|
||||
rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq,
|
||||
pm8xxx_alarm_trigger,
|
||||
IRQF_TRIGGER_RISING,
|
||||
"pm8xxx_rtc_alarm", rtc_dd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rtc_dd->alarm_irq) {
|
||||
rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq,
|
||||
pm8xxx_alarm_trigger,
|
||||
IRQF_TRIGGER_RISING,
|
||||
"pm8xxx_rtc_alarm", rtc_dd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = devm_rtc_register_device(rtc_dd->rtc);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = devm_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq);
|
||||
if (rc)
|
||||
return rc;
|
||||
devm_device_init_wakeup(&pdev->dev);
|
||||
} else {
|
||||
clear_bit(RTC_FEATURE_ALARM, rtc_dd->rtc->features);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return devm_rtc_register_device(rtc_dd->rtc);
|
||||
}
|
||||
|
||||
static void pm8xxx_remove(struct platform_device *pdev)
|
||||
static void pm8xxx_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
|
||||
|
||||
if (rtc_dd->offset_dirty) {
|
||||
if (rtc_dd->nvmem_cell)
|
||||
pm8xxx_rtc_write_nvmem_offset(rtc_dd, rtc_dd->offset);
|
||||
else
|
||||
pm8xxx_rtc_write_uefi_offset(rtc_dd, rtc_dd->offset);
|
||||
}
|
||||
}
|
||||
|
||||
static struct platform_driver pm8xxx_rtc_driver = {
|
||||
.probe = pm8xxx_rtc_probe,
|
||||
.remove = pm8xxx_remove,
|
||||
.shutdown = pm8xxx_shutdown,
|
||||
.driver = {
|
||||
.name = "rtc-pm8xxx",
|
||||
.of_match_table = pm8xxx_id_table,
|
||||
|
|
|
|||
|
|
@ -586,17 +586,14 @@ static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv)
|
|||
*/
|
||||
usleep_range(sleep_us, sleep_us + 10);
|
||||
|
||||
/* Disable all interrupts. */
|
||||
mask = RTCA3_RCR1_AIE | RTCA3_RCR1_CIE | RTCA3_RCR1_PIE;
|
||||
ret = rtca3_alarm_irq_set_helper(priv, mask, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mask = RTCA3_RCR2_START | RTCA3_RCR2_HR24;
|
||||
val = readb(priv->base + RTCA3_RCR2);
|
||||
/* Nothing to do if already started in 24 hours and calendar count mode. */
|
||||
if ((val & mask) == mask)
|
||||
return 0;
|
||||
/* Only disable the interrupts if already started in 24 hours and calendar count mode. */
|
||||
if ((val & mask) == mask) {
|
||||
/* Disable all interrupts. */
|
||||
mask = RTCA3_RCR1_AIE | RTCA3_RCR1_CIE | RTCA3_RCR1_PIE;
|
||||
return rtca3_alarm_irq_set_helper(priv, mask, 0);
|
||||
}
|
||||
|
||||
/* Reconfigure the RTC in 24 hours and calendar count mode. */
|
||||
mask = RTCA3_RCR2_START | RTCA3_RCR2_CNTMD;
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@
|
|||
#define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5)
|
||||
#define RV3032_CLKOUT2_OS BIT(7)
|
||||
|
||||
#define RV3032_CTRL1_EERD BIT(3)
|
||||
#define RV3032_CTRL1_WADA BIT(5)
|
||||
#define RV3032_CTRL1_EERD BIT(2)
|
||||
|
||||
#define RV3032_CTRL2_STOP BIT(0)
|
||||
#define RV3032_CTRL2_EIE BIT(2)
|
||||
|
|
@ -947,11 +946,6 @@ static int rv3032_probe(struct i2c_client *client)
|
|||
if (!client->irq)
|
||||
clear_bit(RTC_FEATURE_ALARM, rv3032->rtc->features);
|
||||
|
||||
ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL1,
|
||||
RV3032_CTRL1_WADA, RV3032_CTRL1_WADA);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rv3032_trickle_charger_setup(&client->dev, rv3032);
|
||||
|
||||
set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3032->rtc->features);
|
||||
|
|
|
|||
|
|
@ -52,11 +52,6 @@
|
|||
#define RX8571_USER_RAM 0x10
|
||||
#define RX8571_NVRAM_SIZE 0x10
|
||||
|
||||
struct rx8581 {
|
||||
struct regmap *regmap;
|
||||
struct rtc_device *rtc;
|
||||
};
|
||||
|
||||
struct rx85x1_config {
|
||||
struct regmap_config regmap;
|
||||
unsigned int num_nvram;
|
||||
|
|
@ -72,14 +67,14 @@ static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
unsigned char date[7];
|
||||
unsigned int data;
|
||||
int err;
|
||||
struct rx8581 *rx8581 = i2c_get_clientdata(client);
|
||||
struct regmap *regmap = i2c_get_clientdata(client);
|
||||
|
||||
/* First we ensure that the "update flag" is not set, we read the
|
||||
* time and date then re-read the "update flag". If the update flag
|
||||
* has been set, we know that the time has changed during the read so
|
||||
* we repeat the whole process again.
|
||||
*/
|
||||
err = regmap_read(rx8581->regmap, RX8581_REG_FLAG, &data);
|
||||
err = regmap_read(regmap, RX8581_REG_FLAG, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -92,20 +87,20 @@ static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
do {
|
||||
/* If update flag set, clear it */
|
||||
if (data & RX8581_FLAG_UF) {
|
||||
err = regmap_write(rx8581->regmap, RX8581_REG_FLAG,
|
||||
data & ~RX8581_FLAG_UF);
|
||||
err = regmap_write(regmap, RX8581_REG_FLAG,
|
||||
data & ~RX8581_FLAG_UF);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Now read time and date */
|
||||
err = regmap_bulk_read(rx8581->regmap, RX8581_REG_SC, date,
|
||||
err = regmap_bulk_read(regmap, RX8581_REG_SC, date,
|
||||
sizeof(date));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Check flag register */
|
||||
err = regmap_read(rx8581->regmap, RX8581_REG_FLAG, &data);
|
||||
err = regmap_read(regmap, RX8581_REG_FLAG, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} while (data & RX8581_FLAG_UF);
|
||||
|
|
@ -137,7 +132,7 @@ static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int err;
|
||||
unsigned char buf[7];
|
||||
struct rx8581 *rx8581 = i2c_get_clientdata(client);
|
||||
struct regmap *regmap = i2c_get_clientdata(client);
|
||||
|
||||
dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
|
|
@ -160,25 +155,23 @@ static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
buf[RX8581_REG_DW] = (0x1 << tm->tm_wday);
|
||||
|
||||
/* Stop the clock */
|
||||
err = regmap_update_bits(rx8581->regmap, RX8581_REG_CTRL,
|
||||
err = regmap_update_bits(regmap, RX8581_REG_CTRL,
|
||||
RX8581_CTRL_STOP, RX8581_CTRL_STOP);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* write register's data */
|
||||
err = regmap_bulk_write(rx8581->regmap, RX8581_REG_SC,
|
||||
buf, sizeof(buf));
|
||||
err = regmap_bulk_write(regmap, RX8581_REG_SC, buf, sizeof(buf));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* get VLF and clear it */
|
||||
err = regmap_update_bits(rx8581->regmap, RX8581_REG_FLAG,
|
||||
RX8581_FLAG_VLF, 0);
|
||||
err = regmap_update_bits(regmap, RX8581_REG_FLAG, RX8581_FLAG_VLF, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Restart the clock */
|
||||
return regmap_update_bits(rx8581->regmap, RX8581_REG_CTRL,
|
||||
return regmap_update_bits(regmap, RX8581_REG_CTRL,
|
||||
RX8581_CTRL_STOP, 0);
|
||||
}
|
||||
|
||||
|
|
@ -190,29 +183,27 @@ static const struct rtc_class_ops rx8581_rtc_ops = {
|
|||
static int rx8571_nvram_read(void *priv, unsigned int offset, void *val,
|
||||
size_t bytes)
|
||||
{
|
||||
struct rx8581 *rx8581 = priv;
|
||||
struct regmap *regmap = priv;
|
||||
|
||||
return regmap_bulk_read(rx8581->regmap, RX8571_USER_RAM + offset,
|
||||
val, bytes);
|
||||
return regmap_bulk_read(regmap, RX8571_USER_RAM + offset, val, bytes);
|
||||
}
|
||||
|
||||
static int rx8571_nvram_write(void *priv, unsigned int offset, void *val,
|
||||
size_t bytes)
|
||||
{
|
||||
struct rx8581 *rx8581 = priv;
|
||||
struct regmap *regmap = priv;
|
||||
|
||||
return regmap_bulk_write(rx8581->regmap, RX8571_USER_RAM + offset,
|
||||
val, bytes);
|
||||
return regmap_bulk_write(regmap, RX8571_USER_RAM + offset, val, bytes);
|
||||
}
|
||||
|
||||
static int rx85x1_nvram_read(void *priv, unsigned int offset, void *val,
|
||||
size_t bytes)
|
||||
{
|
||||
struct rx8581 *rx8581 = priv;
|
||||
struct regmap *regmap = priv;
|
||||
unsigned int tmp_val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(rx8581->regmap, RX8581_REG_RAM, &tmp_val);
|
||||
ret = regmap_read(regmap, RX8581_REG_RAM, &tmp_val);
|
||||
(*(unsigned char *)val) = (unsigned char) tmp_val;
|
||||
|
||||
return ret;
|
||||
|
|
@ -221,12 +212,11 @@ static int rx85x1_nvram_read(void *priv, unsigned int offset, void *val,
|
|||
static int rx85x1_nvram_write(void *priv, unsigned int offset, void *val,
|
||||
size_t bytes)
|
||||
{
|
||||
struct rx8581 *rx8581 = priv;
|
||||
struct regmap *regmap = priv;
|
||||
unsigned char tmp_val;
|
||||
|
||||
tmp_val = *((unsigned char *)val);
|
||||
return regmap_write(rx8581->regmap, RX8581_REG_RAM,
|
||||
(unsigned int)tmp_val);
|
||||
return regmap_write(regmap, RX8581_REG_RAM, (unsigned int)tmp_val);
|
||||
}
|
||||
|
||||
static const struct rx85x1_config rx8581_config = {
|
||||
|
|
@ -249,9 +239,10 @@ static const struct rx85x1_config rx8571_config = {
|
|||
|
||||
static int rx8581_probe(struct i2c_client *client)
|
||||
{
|
||||
struct rx8581 *rx8581;
|
||||
struct regmap *regmap;
|
||||
const struct rx85x1_config *config = &rx8581_config;
|
||||
const void *data = of_device_get_match_data(&client->dev);
|
||||
struct rtc_device *rtc;
|
||||
static struct nvmem_config nvmem_cfg[] = {
|
||||
{
|
||||
.name = "rx85x1-",
|
||||
|
|
@ -276,31 +267,27 @@ static int rx8581_probe(struct i2c_client *client)
|
|||
if (data)
|
||||
config = data;
|
||||
|
||||
rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL);
|
||||
if (!rx8581)
|
||||
return -ENOMEM;
|
||||
regmap = devm_regmap_init_i2c(client, &config->regmap);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
i2c_set_clientdata(client, rx8581);
|
||||
i2c_set_clientdata(client, regmap);
|
||||
|
||||
rx8581->regmap = devm_regmap_init_i2c(client, &config->regmap);
|
||||
if (IS_ERR(rx8581->regmap))
|
||||
return PTR_ERR(rx8581->regmap);
|
||||
rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
rx8581->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rx8581->rtc))
|
||||
return PTR_ERR(rx8581->rtc);
|
||||
rtc->ops = &rx8581_rtc_ops;
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->start_secs = 0;
|
||||
rtc->set_start_time = true;
|
||||
|
||||
rx8581->rtc->ops = &rx8581_rtc_ops;
|
||||
rx8581->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rx8581->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rx8581->rtc->start_secs = 0;
|
||||
rx8581->rtc->set_start_time = true;
|
||||
|
||||
ret = devm_rtc_register_device(rx8581->rtc);
|
||||
ret = devm_rtc_register_device(rtc);
|
||||
|
||||
for (i = 0; i < config->num_nvram; i++) {
|
||||
nvmem_cfg[i].priv = rx8581;
|
||||
devm_rtc_nvmem_register(rx8581->rtc, &nvmem_cfg[i]);
|
||||
nvmem_cfg[i].priv = regmap;
|
||||
devm_rtc_nvmem_register(rtc, &nvmem_cfg[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define RZN1_RTC_CTL0 0x00
|
||||
#define RZN1_RTC_CTL0_SLSB_SUBU 0
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
#define RZN1_RTC_CTL0_CE BIT(7)
|
||||
|
||||
#define RZN1_RTC_CTL1 0x04
|
||||
#define RZN1_RTC_CTL1_1SE BIT(3)
|
||||
#define RZN1_RTC_CTL1_ALME BIT(4)
|
||||
|
||||
#define RZN1_RTC_CTL2 0x08
|
||||
|
|
@ -58,6 +60,13 @@
|
|||
struct rzn1_rtc {
|
||||
struct rtc_device *rtcdev;
|
||||
void __iomem *base;
|
||||
/*
|
||||
* Protects access to RZN1_RTC_CTL1 reg. rtc_lock with threaded_irqs
|
||||
* would introduce race conditions when switching interrupts because
|
||||
* of potential sleeps
|
||||
*/
|
||||
spinlock_t ctl1_access_lock;
|
||||
struct rtc_time tm_alarm;
|
||||
};
|
||||
|
||||
static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
|
||||
|
|
@ -135,8 +144,38 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rzn1_rtc *rtc = dev_id;
|
||||
u32 ctl1, set_irq_bits = 0;
|
||||
|
||||
rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
|
||||
if (rtc->tm_alarm.tm_sec == 0)
|
||||
rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
|
||||
else
|
||||
/* Switch to 1s interrupts */
|
||||
set_irq_bits = RZN1_RTC_CTL1_1SE;
|
||||
|
||||
guard(spinlock)(&rtc->ctl1_access_lock);
|
||||
|
||||
ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
|
||||
ctl1 &= ~RZN1_RTC_CTL1_ALME;
|
||||
ctl1 |= set_irq_bits;
|
||||
writel(ctl1, rtc->base + RZN1_RTC_CTL1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rzn1_rtc_1s_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rzn1_rtc *rtc = dev_id;
|
||||
u32 ctl1;
|
||||
|
||||
if (readl(rtc->base + RZN1_RTC_SECC) == bin2bcd(rtc->tm_alarm.tm_sec)) {
|
||||
guard(spinlock)(&rtc->ctl1_access_lock);
|
||||
|
||||
ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
|
||||
ctl1 &= ~RZN1_RTC_CTL1_1SE;
|
||||
writel(ctl1, rtc->base + RZN1_RTC_CTL1);
|
||||
|
||||
rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -144,14 +183,38 @@ static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id)
|
|||
static int rzn1_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
struct rzn1_rtc *rtc = dev_get_drvdata(dev);
|
||||
u32 ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
|
||||
struct rtc_time *tm = &rtc->tm_alarm, tm_now;
|
||||
u32 ctl1;
|
||||
int ret;
|
||||
|
||||
if (enable)
|
||||
ctl1 |= RZN1_RTC_CTL1_ALME;
|
||||
else
|
||||
ctl1 &= ~RZN1_RTC_CTL1_ALME;
|
||||
guard(spinlock_irqsave)(&rtc->ctl1_access_lock);
|
||||
|
||||
writel(ctl1, rtc->base + RZN1_RTC_CTL1);
|
||||
ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
|
||||
|
||||
if (enable) {
|
||||
/*
|
||||
* Use alarm interrupt if alarm time is at least a minute away
|
||||
* or less than a minute but in the next minute. Otherwise use
|
||||
* 1 second interrupt to wait for the proper second
|
||||
*/
|
||||
do {
|
||||
ctl1 &= ~(RZN1_RTC_CTL1_ALME | RZN1_RTC_CTL1_1SE);
|
||||
|
||||
ret = rzn1_rtc_read_time(dev, &tm_now);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rtc_tm_sub(tm, &tm_now) > 59 || tm->tm_min != tm_now.tm_min)
|
||||
ctl1 |= RZN1_RTC_CTL1_ALME;
|
||||
else
|
||||
ctl1 |= RZN1_RTC_CTL1_1SE;
|
||||
|
||||
writel(ctl1, rtc->base + RZN1_RTC_CTL1);
|
||||
} while (readl(rtc->base + RZN1_RTC_SECC) != bin2bcd(tm_now.tm_sec));
|
||||
} else {
|
||||
ctl1 &= ~(RZN1_RTC_CTL1_ALME | RZN1_RTC_CTL1_1SE);
|
||||
writel(ctl1, rtc->base + RZN1_RTC_CTL1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -185,7 +248,7 @@ static int rzn1_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
}
|
||||
|
||||
ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
|
||||
alrm->enabled = !!(ctl1 & RZN1_RTC_CTL1_ALME);
|
||||
alrm->enabled = !!(ctl1 & (RZN1_RTC_CTL1_ALME | RZN1_RTC_CTL1_1SE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -216,6 +279,8 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
writel(bin2bcd(tm->tm_hour), rtc->base + RZN1_RTC_ALH);
|
||||
writel(BIT(wday), rtc->base + RZN1_RTC_ALW);
|
||||
|
||||
rtc->tm_alarm = alrm->time;
|
||||
|
||||
rzn1_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
|
||||
return 0;
|
||||
|
|
@ -304,7 +369,7 @@ static const struct rtc_class_ops rzn1_rtc_ops = {
|
|||
static int rzn1_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rzn1_rtc *rtc;
|
||||
int alarm_irq;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
|
|
@ -317,9 +382,9 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(rtc->base))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(rtc->base), "Missing reg\n");
|
||||
|
||||
alarm_irq = platform_get_irq(pdev, 0);
|
||||
if (alarm_irq < 0)
|
||||
return alarm_irq;
|
||||
irq = platform_get_irq_byname(pdev, "alarm");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtcdev))
|
||||
|
|
@ -329,8 +394,6 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
|
|||
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->rtcdev->alarm_offset_max = 7 * 86400;
|
||||
rtc->rtcdev->ops = &rzn1_rtc_ops;
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
|
||||
|
||||
ret = devm_pm_runtime_enable(&pdev->dev);
|
||||
if (ret < 0)
|
||||
|
|
@ -349,13 +412,24 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
|
|||
/* Disable all interrupts */
|
||||
writel(0, rtc->base + RZN1_RTC_CTL1);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, alarm_irq, rzn1_rtc_alarm_irq, 0,
|
||||
dev_name(&pdev->dev), rtc);
|
||||
spin_lock_init(&rtc->ctl1_access_lock);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "RTC timer interrupt not available\n");
|
||||
dev_err(&pdev->dev, "RTC alarm interrupt not available\n");
|
||||
goto dis_runtime_pm;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname_optional(pdev, "pps");
|
||||
if (irq >= 0)
|
||||
ret = devm_request_irq(&pdev->dev, irq, rzn1_rtc_1s_irq, 0, "RZN1 RTC 1s", rtc);
|
||||
|
||||
if (irq < 0 || ret) {
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
|
||||
dev_warn(&pdev->dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n");
|
||||
}
|
||||
|
||||
ret = devm_rtc_register_device(rtc->rtcdev);
|
||||
if (ret)
|
||||
goto dis_runtime_pm;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ MODULE_DEVICE_TABLE(of, s35390a_of_match);
|
|||
|
||||
struct s35390a {
|
||||
struct i2c_client *client[8];
|
||||
struct rtc_device *rtc;
|
||||
int twentyfourhour;
|
||||
};
|
||||
|
||||
|
|
@ -422,6 +421,7 @@ static int s35390a_probe(struct i2c_client *client)
|
|||
int err, err_read;
|
||||
unsigned int i;
|
||||
struct s35390a *s35390a;
|
||||
struct rtc_device *rtc;
|
||||
char buf, status1;
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
|
|
@ -447,9 +447,9 @@ static int s35390a_probe(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
s35390a->rtc = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(s35390a->rtc))
|
||||
return PTR_ERR(s35390a->rtc);
|
||||
rtc = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
err_read = s35390a_read_status(s35390a, &status1);
|
||||
if (err_read < 0) {
|
||||
|
|
@ -480,17 +480,17 @@ static int s35390a_probe(struct i2c_client *client)
|
|||
|
||||
device_set_wakeup_capable(dev, 1);
|
||||
|
||||
s35390a->rtc->ops = &s35390a_rtc_ops;
|
||||
s35390a->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
s35390a->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->ops = &s35390a_rtc_ops;
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, s35390a->rtc->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, s35390a->rtc->features );
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
|
||||
|
||||
if (status1 & S35390A_FLAG_INT2)
|
||||
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
|
||||
rtc_update_irq(rtc, 1, RTC_AF);
|
||||
|
||||
return devm_rtc_register_device(s35390a->rtc);
|
||||
return devm_rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static struct i2c_driver s35390a_driver = {
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ static const struct s5m_rtc_reg_config s2mps15_rtc_regs = {
|
|||
|
||||
struct s5m_rtc_info {
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c;
|
||||
struct sec_pmic_dev *s5m87xx;
|
||||
struct regmap *regmap;
|
||||
struct rtc_device *rtc_dev;
|
||||
|
|
@ -627,11 +626,10 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
|
|||
}
|
||||
|
||||
info->rtc_24hr_mode = 1;
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(info->dev, ret,
|
||||
"%s: fail to write controlm reg\n",
|
||||
__func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -640,6 +638,7 @@ static int s5m_rtc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent);
|
||||
struct s5m_rtc_info *info;
|
||||
struct i2c_client *i2c;
|
||||
const struct regmap_config *regmap_cfg;
|
||||
int ret, alarm_irq;
|
||||
|
||||
|
|
@ -669,26 +668,21 @@ static int s5m_rtc_probe(struct platform_device *pdev)
|
|||
alarm_irq = S5M8767_IRQ_RTCA1;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev,
|
||||
"Device type %lu is not supported by RTC driver\n",
|
||||
platform_get_device_id(pdev)->driver_data);
|
||||
return -ENODEV;
|
||||
return dev_err_probe(&pdev->dev, -ENODEV,
|
||||
"Device type %lu is not supported by RTC driver\n",
|
||||
platform_get_device_id(pdev)->driver_data);
|
||||
}
|
||||
|
||||
info->i2c = devm_i2c_new_dummy_device(&pdev->dev, s5m87xx->i2c->adapter,
|
||||
RTC_I2C_ADDR);
|
||||
if (IS_ERR(info->i2c)) {
|
||||
dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n");
|
||||
return PTR_ERR(info->i2c);
|
||||
}
|
||||
i2c = devm_i2c_new_dummy_device(&pdev->dev, s5m87xx->i2c->adapter,
|
||||
RTC_I2C_ADDR);
|
||||
if (IS_ERR(i2c))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c),
|
||||
"Failed to allocate I2C for RTC\n");
|
||||
|
||||
info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg);
|
||||
if (IS_ERR(info->regmap)) {
|
||||
ret = PTR_ERR(info->regmap);
|
||||
dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
info->regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
|
||||
if (IS_ERR(info->regmap))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(info->regmap),
|
||||
"Failed to allocate RTC register map\n");
|
||||
|
||||
info->dev = &pdev->dev;
|
||||
info->s5m87xx = s5m87xx;
|
||||
|
|
@ -696,11 +690,10 @@ static int s5m_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
if (s5m87xx->irq_data) {
|
||||
info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq);
|
||||
if (info->irq <= 0) {
|
||||
dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
|
||||
alarm_irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (info->irq <= 0)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"Failed to get virtual IRQ %d\n",
|
||||
alarm_irq);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
|
@ -724,11 +717,10 @@ static int s5m_rtc_probe(struct platform_device *pdev)
|
|||
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
|
||||
s5m_rtc_alarm_irq, 0, "rtc-alarm0",
|
||||
info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
|
||||
info->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to request alarm IRQ %d\n",
|
||||
info->irq);
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
struct sd2405al {
|
||||
struct device *dev;
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
|
|
@ -167,6 +166,7 @@ static const struct regmap_config sd2405al_regmap_conf = {
|
|||
static int sd2405al_probe(struct i2c_client *client)
|
||||
{
|
||||
struct sd2405al *sd2405al;
|
||||
struct rtc_device *rtc;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
|
|
@ -182,17 +182,17 @@ static int sd2405al_probe(struct i2c_client *client)
|
|||
if (IS_ERR(sd2405al->regmap))
|
||||
return PTR_ERR(sd2405al->regmap);
|
||||
|
||||
sd2405al->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(sd2405al->rtc))
|
||||
return PTR_ERR(sd2405al->rtc);
|
||||
rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
sd2405al->rtc->ops = &sd2405al_rtc_ops;
|
||||
sd2405al->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
sd2405al->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->ops = &sd2405al_rtc_ops;
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
dev_set_drvdata(&client->dev, sd2405al);
|
||||
|
||||
ret = devm_rtc_register_device(sd2405al->rtc);
|
||||
ret = devm_rtc_register_device(rtc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -36,11 +36,6 @@
|
|||
*/
|
||||
#define WRITE_PROTECT_EN 0
|
||||
|
||||
struct sd3078 {
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
/*
|
||||
* In order to prevent arbitrary modification of the time register,
|
||||
* when modification of the register,
|
||||
|
|
@ -49,14 +44,11 @@ struct sd3078 {
|
|||
* 2. set WRITE2 bit
|
||||
* 3. set WRITE3 bit
|
||||
*/
|
||||
static void sd3078_enable_reg_write(struct sd3078 *sd3078)
|
||||
static void sd3078_enable_reg_write(struct regmap *regmap)
|
||||
{
|
||||
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
|
||||
KEY_WRITE1, KEY_WRITE1);
|
||||
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
|
||||
KEY_WRITE2, KEY_WRITE2);
|
||||
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
|
||||
KEY_WRITE3, KEY_WRITE3);
|
||||
regmap_update_bits(regmap, SD3078_REG_CTRL2, KEY_WRITE1, KEY_WRITE1);
|
||||
regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE2, KEY_WRITE2);
|
||||
regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE3, KEY_WRITE3);
|
||||
}
|
||||
|
||||
#if WRITE_PROTECT_EN
|
||||
|
|
@ -69,14 +61,11 @@ static void sd3078_enable_reg_write(struct sd3078 *sd3078)
|
|||
* 2. clear WRITE3 bit
|
||||
* 3. clear WRITE1 bit
|
||||
*/
|
||||
static void sd3078_disable_reg_write(struct sd3078 *sd3078)
|
||||
static void sd3078_disable_reg_write(struct regmap *regmap)
|
||||
{
|
||||
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
|
||||
KEY_WRITE2, 0);
|
||||
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
|
||||
KEY_WRITE3, 0);
|
||||
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
|
||||
KEY_WRITE1, 0);
|
||||
regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE2, 0);
|
||||
regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE3, 0);
|
||||
regmap_update_bits(regmap, SD3078_REG_CTRL2, KEY_WRITE1, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -85,11 +74,10 @@ static int sd3078_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
unsigned char hour;
|
||||
unsigned char rtc_data[NUM_TIME_REGS] = {0};
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct sd3078 *sd3078 = i2c_get_clientdata(client);
|
||||
struct regmap *regmap = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(sd3078->regmap, SD3078_REG_SC, rtc_data,
|
||||
NUM_TIME_REGS);
|
||||
ret = regmap_bulk_read(regmap, SD3078_REG_SC, rtc_data, NUM_TIME_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "reading from RTC failed with err:%d\n", ret);
|
||||
return ret;
|
||||
|
|
@ -123,7 +111,7 @@ static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
{
|
||||
unsigned char rtc_data[NUM_TIME_REGS];
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct sd3078 *sd3078 = i2c_get_clientdata(client);
|
||||
struct regmap *regmap = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
rtc_data[SD3078_REG_SC] = bin2bcd(tm->tm_sec);
|
||||
|
|
@ -135,10 +123,10 @@ static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
rtc_data[SD3078_REG_YR] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
#if WRITE_PROTECT_EN
|
||||
sd3078_enable_reg_write(sd3078);
|
||||
sd3078_enable_reg_write(regmap);
|
||||
#endif
|
||||
|
||||
ret = regmap_bulk_write(sd3078->regmap, SD3078_REG_SC, rtc_data,
|
||||
ret = regmap_bulk_write(regmap, SD3078_REG_SC, rtc_data,
|
||||
NUM_TIME_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "writing to RTC failed with err:%d\n", ret);
|
||||
|
|
@ -146,7 +134,7 @@ static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
}
|
||||
|
||||
#if WRITE_PROTECT_EN
|
||||
sd3078_disable_reg_write(sd3078);
|
||||
sd3078_disable_reg_write(regmap);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
@ -166,36 +154,33 @@ static const struct regmap_config regmap_config = {
|
|||
static int sd3078_probe(struct i2c_client *client)
|
||||
{
|
||||
int ret;
|
||||
struct sd3078 *sd3078;
|
||||
struct regmap *regmap;
|
||||
struct rtc_device *rtc;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return -ENODEV;
|
||||
|
||||
sd3078 = devm_kzalloc(&client->dev, sizeof(*sd3078), GFP_KERNEL);
|
||||
if (!sd3078)
|
||||
return -ENOMEM;
|
||||
|
||||
sd3078->regmap = devm_regmap_init_i2c(client, ®map_config);
|
||||
if (IS_ERR(sd3078->regmap)) {
|
||||
regmap = devm_regmap_init_i2c(client, ®map_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "regmap allocation failed\n");
|
||||
return PTR_ERR(sd3078->regmap);
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, sd3078);
|
||||
i2c_set_clientdata(client, regmap);
|
||||
|
||||
sd3078->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(sd3078->rtc))
|
||||
return PTR_ERR(sd3078->rtc);
|
||||
rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
sd3078->rtc->ops = &sd3078_rtc_ops;
|
||||
sd3078->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->ops = &sd3078_rtc_ops;
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
ret = devm_rtc_register_device(sd3078->rtc);
|
||||
ret = devm_rtc_register_device(rtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sd3078_enable_reg_write(sd3078);
|
||||
sd3078_enable_reg_write(regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1143,11 +1143,11 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
|||
goto err;
|
||||
}
|
||||
|
||||
ret = device_init_wakeup(&pdev->dev, true);
|
||||
ret = devm_device_init_wakeup(&pdev->dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = dev_pm_set_wake_irq(&pdev->dev, rtc->irq_alarm);
|
||||
ret = devm_pm_set_wake_irq(&pdev->dev, rtc->irq_alarm);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
|
@ -1208,9 +1208,6 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
|||
if (rtc->data->need_dbp)
|
||||
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
|
||||
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1237,9 +1234,6 @@ static void stm32_rtc_remove(struct platform_device *pdev)
|
|||
/* Enable backup domain write protection if needed */
|
||||
if (rtc->data->need_dbp)
|
||||
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
|
||||
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
}
|
||||
|
||||
static int stm32_rtc_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -60,11 +60,6 @@
|
|||
#define RTC_PDN2 0x002e
|
||||
#define RTC_PDN2_PWRON_ALARM BIT(4)
|
||||
|
||||
#define RTC_MIN_YEAR 1968
|
||||
#define RTC_BASE_YEAR 1900
|
||||
#define RTC_NUM_YEARS 128
|
||||
#define RTC_MIN_YEAR_OFFSET (RTC_MIN_YEAR - RTC_BASE_YEAR)
|
||||
|
||||
#define MTK_RTC_POLL_DELAY_US 10
|
||||
#define MTK_RTC_POLL_TIMEOUT (jiffies_to_usecs(HZ))
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ struct rtc_device {
|
|||
/* useful timestamps */
|
||||
#define RTC_TIMESTAMP_BEGIN_0000 -62167219200ULL /* 0000-01-01 00:00:00 */
|
||||
#define RTC_TIMESTAMP_BEGIN_1900 -2208988800LL /* 1900-01-01 00:00:00 */
|
||||
#define RTC_TIMESTAMP_EPOCH_GPS 315964800LL /* 1980-01-06 00:00:00 */
|
||||
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
||||
#define RTC_TIMESTAMP_END_2063 2966371199LL /* 2063-12-31 23:59:59 */
|
||||
#define RTC_TIMESTAMP_END_2079 3471292799LL /* 2079-12-31 23:59:59 */
|
||||
|
|
|
|||
1
tools/testing/selftests/rtc/.gitignore
vendored
1
tools/testing/selftests/rtc/.gitignore
vendored
|
|
@ -1,3 +1,2 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
rtctest
|
||||
setdate
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ LDLIBS += -lrt -lpthread -lm
|
|||
|
||||
TEST_GEN_PROGS = rtctest
|
||||
|
||||
TEST_GEN_PROGS_EXTENDED = setdate
|
||||
|
||||
TEST_FILES := settings
|
||||
|
||||
include ../lib.mk
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ enum rtc_alarm_state {
|
|||
RTC_ALARM_UNKNOWN,
|
||||
RTC_ALARM_ENABLED,
|
||||
RTC_ALARM_DISABLED,
|
||||
RTC_ALARM_RES_MINUTE,
|
||||
};
|
||||
|
||||
FIXTURE(rtc) {
|
||||
|
|
@ -88,7 +89,7 @@ static void nanosleep_with_retries(long ns)
|
|||
}
|
||||
}
|
||||
|
||||
static enum rtc_alarm_state get_rtc_alarm_state(int fd)
|
||||
static enum rtc_alarm_state get_rtc_alarm_state(int fd, int need_seconds)
|
||||
{
|
||||
struct rtc_param param = { 0 };
|
||||
int rc;
|
||||
|
|
@ -103,6 +104,10 @@ static enum rtc_alarm_state get_rtc_alarm_state(int fd)
|
|||
if ((param.uvalue & _BITUL(RTC_FEATURE_ALARM)) == 0)
|
||||
return RTC_ALARM_DISABLED;
|
||||
|
||||
/* Check if alarm has desired granularity */
|
||||
if (need_seconds && (param.uvalue & _BITUL(RTC_FEATURE_ALARM_RES_MINUTE)))
|
||||
return RTC_ALARM_RES_MINUTE;
|
||||
|
||||
return RTC_ALARM_ENABLED;
|
||||
}
|
||||
|
||||
|
|
@ -227,9 +232,11 @@ TEST_F(rtc, alarm_alm_set) {
|
|||
SKIP(return, "Skipping test since %s does not exist", rtc_file);
|
||||
ASSERT_NE(-1, self->fd);
|
||||
|
||||
alarm_state = get_rtc_alarm_state(self->fd);
|
||||
alarm_state = get_rtc_alarm_state(self->fd, 1);
|
||||
if (alarm_state == RTC_ALARM_DISABLED)
|
||||
SKIP(return, "Skipping test since alarms are not supported.");
|
||||
if (alarm_state == RTC_ALARM_RES_MINUTE)
|
||||
SKIP(return, "Skipping test since alarms has only minute granularity.");
|
||||
|
||||
rc = ioctl(self->fd, RTC_RD_TIME, &tm);
|
||||
ASSERT_NE(-1, rc);
|
||||
|
|
@ -295,9 +302,11 @@ TEST_F(rtc, alarm_wkalm_set) {
|
|||
SKIP(return, "Skipping test since %s does not exist", rtc_file);
|
||||
ASSERT_NE(-1, self->fd);
|
||||
|
||||
alarm_state = get_rtc_alarm_state(self->fd);
|
||||
alarm_state = get_rtc_alarm_state(self->fd, 1);
|
||||
if (alarm_state == RTC_ALARM_DISABLED)
|
||||
SKIP(return, "Skipping test since alarms are not supported.");
|
||||
if (alarm_state == RTC_ALARM_RES_MINUTE)
|
||||
SKIP(return, "Skipping test since alarms has only minute granularity.");
|
||||
|
||||
rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
|
||||
ASSERT_NE(-1, rc);
|
||||
|
|
@ -357,7 +366,7 @@ TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
|
|||
SKIP(return, "Skipping test since %s does not exist", rtc_file);
|
||||
ASSERT_NE(-1, self->fd);
|
||||
|
||||
alarm_state = get_rtc_alarm_state(self->fd);
|
||||
alarm_state = get_rtc_alarm_state(self->fd, 0);
|
||||
if (alarm_state == RTC_ALARM_DISABLED)
|
||||
SKIP(return, "Skipping test since alarms are not supported.");
|
||||
|
||||
|
|
@ -425,7 +434,7 @@ TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
|
|||
SKIP(return, "Skipping test since %s does not exist", rtc_file);
|
||||
ASSERT_NE(-1, self->fd);
|
||||
|
||||
alarm_state = get_rtc_alarm_state(self->fd);
|
||||
alarm_state = get_rtc_alarm_state(self->fd, 0);
|
||||
if (alarm_state == RTC_ALARM_DISABLED)
|
||||
SKIP(return, "Skipping test since alarms are not supported.");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Real Time Clock Driver Test
|
||||
* by: Benjamin Gaignard (benjamin.gaignard@linaro.org)
|
||||
*
|
||||
* To build
|
||||
* gcc rtctest_setdate.c -o rtctest_setdate
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const char default_time[] = "00:00:00";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd, retval;
|
||||
struct rtc_time new, current;
|
||||
const char *rtc, *date;
|
||||
const char *time = default_time;
|
||||
|
||||
switch (argc) {
|
||||
case 4:
|
||||
time = argv[3];
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
date = argv[2];
|
||||
rtc = argv[1];
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "usage: rtctest_setdate <rtcdev> <DD-MM-YYYY> [HH:MM:SS]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd = open(rtc, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror(rtc);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
sscanf(date, "%d-%d-%d", &new.tm_mday, &new.tm_mon, &new.tm_year);
|
||||
new.tm_mon -= 1;
|
||||
new.tm_year -= 1900;
|
||||
sscanf(time, "%d:%d:%d", &new.tm_hour, &new.tm_min, &new.tm_sec);
|
||||
|
||||
fprintf(stderr, "Test will set RTC date/time to %d-%d-%d, %02d:%02d:%02d.\n",
|
||||
new.tm_mday, new.tm_mon + 1, new.tm_year + 1900,
|
||||
new.tm_hour, new.tm_min, new.tm_sec);
|
||||
|
||||
/* Write the new date in RTC */
|
||||
retval = ioctl(fd, RTC_SET_TIME, &new);
|
||||
if (retval == -1) {
|
||||
perror("RTC_SET_TIME ioctl");
|
||||
close(fd);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
/* Read back */
|
||||
retval = ioctl(fd, RTC_RD_TIME, ¤t);
|
||||
if (retval == -1) {
|
||||
perror("RTC_RD_TIME ioctl");
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
|
||||
current.tm_mday, current.tm_mon + 1, current.tm_year + 1900,
|
||||
current.tm_hour, current.tm_min, current.tm_sec);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user