mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:24:47 +01:00
RTC for 7.0
Drivers: - loongson: Loongson-2K0300 support - s35390a: nvmem support - zynqmp: rework calibration -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmmaW6UACgkQY6TcMGxw OjIEBA//T+wV/SxNKwTZc5+f0nA2ndhvSNQduy1Diguj0yt0pxweENopkRUMtyVh 5cHWqTNj9R7OWQiUBfAMCia4OgVHGVgp4zRONohFpwa1aKLTJJtgancRcrrKie5A MTyzWaOl0odk6utU1MEXMdA7cF1Wr2moPbMEvEyE7LhgT0dF+CM2jD8yGuZawum2 vH9aTDc6xMOofpjTlxOyb64fK3BJ9PUaSi++HJ22VP88+XS5GOPgpoBnYdA5lSju XWW3hAWYekg8F4Km9omEfjXWnJ5qvrJUBNnGz5m5ipp1rU/ZD3eg/kJ5YeNQZOfq YALhaNXfkHbrQXXfNHVaL77od2zUvpOWaN6DPbbKlYlqsZnWmD++8w3hVZT5jEP4 XJ3oNpHjMt2WT5GnF96Ya636ZR36PnZSgb3TgoDgJ9Xx8Ko4ov/v62Mz5v6oxh4P NeB0XqnwBxa0YJ/73XVNsiJ54U4LY4k3A9SqZ1mjpHEXFlf+MpErNmgTi0Q/BP81 RUcNI3GQuTAX/MaXSbceFn0K8XJxG+HKWqW3j0rmjN5BFSYqPGPGNWZaS8SUNwlt Xj6aeJRV9RTEc+fZqLss/ztxGXyCGcgM0+OOlXyQsVLHcQZAH36c67auM+OzmZZH uMhix3OcawZDlpDugHdJJtau0Clj7xtrrdSZqTuAuJXFIGNNtow= =YiJy -----END PGP SIGNATURE----- Merge tag 'rtc-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: - loongson: Loongson-2K0300 support - s35390a: nvmem support - zynqmp: rework calibration * tag 'rtc-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: rtc: ds1390: fix number of bytes read from RTC rtc: class: Remove duplicate check for alarm rtc: optee: simplify OP-TEE context match rtc: interface: Alarm race handling should not discard preceding error rtc: s35390a: implement nvmem support rtc: loongson: Add Loongson-2K0300 support dt-bindings: rtc: loongson: Document Loongson-2K0300 compatible dt-bindings: rtc: loongson: Correct Loongson-1C interrupts property dt-bindings: rtc: renesas,rz-rtca3: Add RZ/V2N support dt-bindings: rtc: cpcap: convert to schema rtc: zynqmp: use dynamic max and min offset ranges rtc: zynqmp: rework set_offset rtc: zynqmp: rework read_offset rtc: zynqmp: check calibration max value rtc: zynqmp: correct frequency value rtc: amlogic-a4: Remove IRQF_ONESHOT rtc: pcf8563: use correct of_node for output clock rtc: max31335: use correct CONFIG symbol in IS_REACHABLE() rtc: nvvrs: Add ARCH_TEGRA to the NV VRS RTC driver
This commit is contained in:
commit
5f2eac7767
14 changed files with 178 additions and 88 deletions
|
|
@ -1,18 +0,0 @@
|
||||||
Motorola CPCAP PMIC RTC
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
This module is part of the CPCAP. For more details about the whole
|
|
||||||
chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt.
|
|
||||||
|
|
||||||
Requires node properties:
|
|
||||||
- compatible: should contain "motorola,cpcap-rtc"
|
|
||||||
- interrupts: An interrupt specifier for alarm and 1 Hz irq
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
&cpcap {
|
|
||||||
cpcap_rtc: rtc {
|
|
||||||
compatible = "motorola,cpcap-rtc";
|
|
||||||
interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -23,6 +23,7 @@ properties:
|
||||||
- loongson,ls1b-rtc
|
- loongson,ls1b-rtc
|
||||||
- loongson,ls1c-rtc
|
- loongson,ls1c-rtc
|
||||||
- loongson,ls7a-rtc
|
- loongson,ls7a-rtc
|
||||||
|
- loongson,ls2k0300-rtc
|
||||||
- loongson,ls2k1000-rtc
|
- loongson,ls2k1000-rtc
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
|
@ -42,6 +43,18 @@ required:
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- loongson,ls1c-rtc
|
||||||
|
- loongson,ls2k0300-rtc
|
||||||
|
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
interrupts: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
#include <dt-bindings/interrupt-controller/irq.h>
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/rtc/motorola,cpcap-rtc.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Motorola CPCAP PMIC RTC
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Svyatoslav Ryhel <clamor95@gmail.com>
|
||||||
|
|
||||||
|
description:
|
||||||
|
This module is part of the Motorola CPCAP MFD device. For more details
|
||||||
|
see Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml. The
|
||||||
|
RTC is represented as a sub-node of the PMIC node on the device tree.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: motorola,cpcap-rtc
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
items:
|
||||||
|
- description: alarm interrupt
|
||||||
|
- description: 1 Hz interrupt
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- interrupts
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
...
|
||||||
|
|
@ -14,6 +14,7 @@ properties:
|
||||||
items:
|
items:
|
||||||
- enum:
|
- enum:
|
||||||
- renesas,r9a08g045-rtca3 # RZ/G3S
|
- renesas,r9a08g045-rtca3 # RZ/G3S
|
||||||
|
- renesas,r9a09g056-rtca3 # RZ/V2N
|
||||||
- renesas,r9a09g057-rtca3 # RZ/V2H
|
- renesas,r9a09g057-rtca3 # RZ/V2H
|
||||||
- const: renesas,rz-rtca3
|
- const: renesas,rz-rtca3
|
||||||
|
|
||||||
|
|
@ -82,7 +83,9 @@ allOf:
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
contains:
|
contains:
|
||||||
const: renesas,r9a09g057-rtca3
|
enum:
|
||||||
|
- renesas,r9a09g056-rtca3
|
||||||
|
- renesas,r9a09g057-rtca3
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
resets:
|
resets:
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,7 @@ config RTC_DRV_SPACEMIT_P1
|
||||||
|
|
||||||
config RTC_DRV_NVIDIA_VRS10
|
config RTC_DRV_NVIDIA_VRS10
|
||||||
tristate "NVIDIA VRS10 RTC device"
|
tristate "NVIDIA VRS10 RTC device"
|
||||||
|
depends on ARCH_TEGRA || COMPILE_TEST
|
||||||
help
|
help
|
||||||
If you say yes here you will get support for the battery backed RTC device
|
If you say yes here you will get support for the battery backed RTC device
|
||||||
of NVIDIA VRS (Voltage Regulator Specification). The RTC is connected via
|
of NVIDIA VRS (Voltage Regulator Specification). The RTC is connected via
|
||||||
|
|
|
||||||
|
|
@ -410,7 +410,7 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc)
|
||||||
|
|
||||||
/* Check to see if there is an ALARM already set in hw */
|
/* Check to see if there is an ALARM already set in hw */
|
||||||
err = __rtc_read_alarm(rtc, &alrm);
|
err = __rtc_read_alarm(rtc, &alrm);
|
||||||
if (!err && !rtc_valid_tm(&alrm.time))
|
if (!err)
|
||||||
rtc_initialize_alarm(rtc, &alrm);
|
rtc_initialize_alarm(rtc, &alrm);
|
||||||
|
|
||||||
rtc_dev_prepare(rtc);
|
rtc_dev_prepare(rtc);
|
||||||
|
|
|
||||||
|
|
@ -457,7 +457,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||||
* are in, we can return -ETIME to signal that the timer has already
|
* are in, we can return -ETIME to signal that the timer has already
|
||||||
* expired, which is true in both cases.
|
* expired, which is true in both cases.
|
||||||
*/
|
*/
|
||||||
if ((scheduled - now) <= 1) {
|
if (!err && (scheduled - now) <= 1) {
|
||||||
err = __rtc_read_time(rtc, &tm);
|
err = __rtc_read_time(rtc, &tm);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ static int ds1390_read_time(struct device *dev, struct rtc_time *dt)
|
||||||
chip->txrx_buf[0] = DS1390_REG_SECONDS;
|
chip->txrx_buf[0] = DS1390_REG_SECONDS;
|
||||||
|
|
||||||
/* do the i/o */
|
/* do the i/o */
|
||||||
status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 8);
|
status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 7);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@
|
||||||
* According to the LS1C manual, RTC_CTRL and alarm-related registers are not defined.
|
* According to the LS1C manual, RTC_CTRL and alarm-related registers are not defined.
|
||||||
* Accessing the relevant registers will cause the system to hang.
|
* Accessing the relevant registers will cause the system to hang.
|
||||||
*/
|
*/
|
||||||
#define LS1C_RTC_CTRL_WORKAROUND BIT(0)
|
#define LOONGSON_RTC_CTRL_WORKAROUND BIT(0)
|
||||||
|
#define LOONGSON_RTC_ALARM_WORKAROUND BIT(1)
|
||||||
|
|
||||||
struct loongson_rtc_config {
|
struct loongson_rtc_config {
|
||||||
u32 pm_offset; /* Offset of PM domain, for RTC alarm wakeup */
|
u32 pm_offset; /* Offset of PM domain, for RTC alarm wakeup */
|
||||||
|
|
@ -89,7 +90,7 @@ static const struct loongson_rtc_config ls1b_rtc_config = {
|
||||||
|
|
||||||
static const struct loongson_rtc_config ls1c_rtc_config = {
|
static const struct loongson_rtc_config ls1c_rtc_config = {
|
||||||
.pm_offset = 0,
|
.pm_offset = 0,
|
||||||
.flags = LS1C_RTC_CTRL_WORKAROUND,
|
.flags = LOONGSON_RTC_CTRL_WORKAROUND | LOONGSON_RTC_ALARM_WORKAROUND,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct loongson_rtc_config generic_rtc_config = {
|
static const struct loongson_rtc_config generic_rtc_config = {
|
||||||
|
|
@ -97,6 +98,11 @@ static const struct loongson_rtc_config generic_rtc_config = {
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct loongson_rtc_config ls2k0300_rtc_config = {
|
||||||
|
.pm_offset = 0x0,
|
||||||
|
.flags = LOONGSON_RTC_ALARM_WORKAROUND,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct loongson_rtc_config ls2k1000_rtc_config = {
|
static const struct loongson_rtc_config ls2k1000_rtc_config = {
|
||||||
.pm_offset = 0x800,
|
.pm_offset = 0x800,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
|
@ -153,7 +159,7 @@ static int loongson_rtc_set_enabled(struct device *dev)
|
||||||
{
|
{
|
||||||
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
|
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND)
|
if (priv->config->flags & LOONGSON_RTC_CTRL_WORKAROUND)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Enable RTC TOY counters and crystal */
|
/* Enable RTC TOY counters and crystal */
|
||||||
|
|
@ -167,7 +173,7 @@ static bool loongson_rtc_get_enabled(struct device *dev)
|
||||||
u32 ctrl_data;
|
u32 ctrl_data;
|
||||||
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
|
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND)
|
if (priv->config->flags & LOONGSON_RTC_CTRL_WORKAROUND)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
ret = regmap_read(priv->regmap, RTC_CTRL_REG, &ctrl_data);
|
ret = regmap_read(priv->regmap, RTC_CTRL_REG, &ctrl_data);
|
||||||
|
|
@ -299,9 +305,41 @@ static const struct rtc_class_ops loongson_rtc_ops = {
|
||||||
.alarm_irq_enable = loongson_rtc_alarm_irq_enable,
|
.alarm_irq_enable = loongson_rtc_alarm_irq_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int loongson_rtc_alarm_setting(struct platform_device *pdev, void __iomem *regs)
|
||||||
|
{
|
||||||
|
int ret = 0, alarm_irq;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (priv->config->flags & LOONGSON_RTC_ALARM_WORKAROUND) {
|
||||||
|
/* Loongson-1C/Loongson-2K0300 RTC does not support alarm */
|
||||||
|
clear_bit(RTC_FEATURE_ALARM, priv->rtcdev->features);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get RTC alarm irq */
|
||||||
|
alarm_irq = platform_get_irq(pdev, 0);
|
||||||
|
if (alarm_irq < 0)
|
||||||
|
return alarm_irq;
|
||||||
|
|
||||||
|
ret = devm_request_irq(dev, alarm_irq, loongson_rtc_isr, 0, "loongson-alarm",
|
||||||
|
priv);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
priv->pm_base = regs - priv->config->pm_offset;
|
||||||
|
device_init_wakeup(dev, true);
|
||||||
|
|
||||||
|
if (has_acpi_companion(dev))
|
||||||
|
acpi_install_fixed_event_handler(ACPI_EVENT_RTC,
|
||||||
|
loongson_rtc_handler, priv);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int loongson_rtc_probe(struct platform_device *pdev)
|
static int loongson_rtc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int ret, alarm_irq;
|
int ret;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
struct loongson_rtc_priv *priv;
|
struct loongson_rtc_priv *priv;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
|
@ -330,25 +368,9 @@ static int loongson_rtc_probe(struct platform_device *pdev)
|
||||||
return dev_err_probe(dev, PTR_ERR(priv->rtcdev),
|
return dev_err_probe(dev, PTR_ERR(priv->rtcdev),
|
||||||
"devm_rtc_allocate_device failed\n");
|
"devm_rtc_allocate_device failed\n");
|
||||||
|
|
||||||
/* Get RTC alarm irq */
|
ret = loongson_rtc_alarm_setting(pdev, regs);
|
||||||
alarm_irq = platform_get_irq(pdev, 0);
|
if (ret)
|
||||||
if (alarm_irq > 0) {
|
return ret;
|
||||||
ret = devm_request_irq(dev, alarm_irq, loongson_rtc_isr,
|
|
||||||
0, "loongson-alarm", priv);
|
|
||||||
if (ret < 0)
|
|
||||||
return dev_err_probe(dev, ret, "Unable to request irq %d\n",
|
|
||||||
alarm_irq);
|
|
||||||
|
|
||||||
priv->pm_base = regs - priv->config->pm_offset;
|
|
||||||
device_init_wakeup(dev, true);
|
|
||||||
|
|
||||||
if (has_acpi_companion(dev))
|
|
||||||
acpi_install_fixed_event_handler(ACPI_EVENT_RTC,
|
|
||||||
loongson_rtc_handler, priv);
|
|
||||||
} else {
|
|
||||||
/* Loongson-1C RTC does not support alarm */
|
|
||||||
clear_bit(RTC_FEATURE_ALARM, priv->rtcdev->features);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loongson RTC does not support UIE */
|
/* Loongson RTC does not support UIE */
|
||||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, priv->rtcdev->features);
|
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, priv->rtcdev->features);
|
||||||
|
|
@ -379,6 +401,7 @@ static const struct of_device_id loongson_rtc_of_match[] = {
|
||||||
{ .compatible = "loongson,ls1b-rtc", .data = &ls1b_rtc_config },
|
{ .compatible = "loongson,ls1b-rtc", .data = &ls1b_rtc_config },
|
||||||
{ .compatible = "loongson,ls1c-rtc", .data = &ls1c_rtc_config },
|
{ .compatible = "loongson,ls1c-rtc", .data = &ls1c_rtc_config },
|
||||||
{ .compatible = "loongson,ls7a-rtc", .data = &generic_rtc_config },
|
{ .compatible = "loongson,ls7a-rtc", .data = &generic_rtc_config },
|
||||||
|
{ .compatible = "loongson,ls2k0300-rtc", .data = &ls2k0300_rtc_config },
|
||||||
{ .compatible = "loongson,ls2k1000-rtc", .data = &ls2k1000_rtc_config },
|
{ .compatible = "loongson,ls2k1000-rtc", .data = &ls2k1000_rtc_config },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -591,7 +591,7 @@ static struct nvmem_config max31335_nvmem_cfg = {
|
||||||
.size = MAX31335_RAM_SIZE,
|
.size = MAX31335_RAM_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if IS_REACHABLE(HWMON)
|
#if IS_REACHABLE(CONFIG_HWMON)
|
||||||
static int max31335_read_temp(struct device *dev, enum hwmon_sensor_types type,
|
static int max31335_read_temp(struct device *dev, enum hwmon_sensor_types type,
|
||||||
u32 attr, int channel, long *val)
|
u32 attr, int channel, long *val)
|
||||||
{
|
{
|
||||||
|
|
@ -672,7 +672,7 @@ static int max31335_clkout_register(struct device *dev)
|
||||||
static int max31335_probe(struct i2c_client *client)
|
static int max31335_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct max31335_data *max31335;
|
struct max31335_data *max31335;
|
||||||
#if IS_REACHABLE(HWMON)
|
#if IS_REACHABLE(CONFIG_HWMON)
|
||||||
struct device *hwmon;
|
struct device *hwmon;
|
||||||
#endif
|
#endif
|
||||||
const struct chip_desc *match;
|
const struct chip_desc *match;
|
||||||
|
|
@ -727,7 +727,7 @@ static int max31335_probe(struct i2c_client *client)
|
||||||
return dev_err_probe(&client->dev, ret,
|
return dev_err_probe(&client->dev, ret,
|
||||||
"cannot register rtc nvmem\n");
|
"cannot register rtc nvmem\n");
|
||||||
|
|
||||||
#if IS_REACHABLE(HWMON)
|
#if IS_REACHABLE(CONFIG_HWMON)
|
||||||
if (max31335->chip->temp_reg) {
|
if (max31335->chip->temp_reg) {
|
||||||
hwmon = devm_hwmon_device_register_with_info(&client->dev, client->name, max31335,
|
hwmon = devm_hwmon_device_register_with_info(&client->dev, client->name, max31335,
|
||||||
&max31335_chip_info, NULL);
|
&max31335_chip_info, NULL);
|
||||||
|
|
|
||||||
|
|
@ -541,10 +541,7 @@ static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc,
|
||||||
|
|
||||||
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
|
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
|
||||||
{
|
{
|
||||||
if (ver->impl_id == TEE_IMPL_ID_OPTEE)
|
return (ver->impl_id == TEE_IMPL_ID_OPTEE);
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optee_rtc_probe(struct tee_client_device *rtc_device)
|
static int optee_rtc_probe(struct tee_client_device *rtc_device)
|
||||||
|
|
|
||||||
|
|
@ -424,7 +424,7 @@ static const struct clk_ops pcf8563_clkout_ops = {
|
||||||
|
|
||||||
static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
|
static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
|
||||||
{
|
{
|
||||||
struct device_node *node = pcf8563->rtc->dev.of_node;
|
struct device_node *node = pcf8563->rtc->dev.parent->of_node;
|
||||||
struct clk_init_data init;
|
struct clk_init_data init;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#define S35390A_CMD_TIME1 2
|
#define S35390A_CMD_TIME1 2
|
||||||
#define S35390A_CMD_TIME2 3
|
#define S35390A_CMD_TIME2 3
|
||||||
#define S35390A_CMD_INT2_REG1 5
|
#define S35390A_CMD_INT2_REG1 5
|
||||||
|
#define S35390A_CMD_FREE_REG 7
|
||||||
|
|
||||||
#define S35390A_BYTE_YEAR 0
|
#define S35390A_BYTE_YEAR 0
|
||||||
#define S35390A_BYTE_MONTH 1
|
#define S35390A_BYTE_MONTH 1
|
||||||
|
|
@ -416,6 +417,23 @@ static const struct rtc_class_ops s35390a_rtc_ops = {
|
||||||
.ioctl = s35390a_rtc_ioctl,
|
.ioctl = s35390a_rtc_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int s35390a_nvmem_read(void *priv, unsigned int offset, void *val,
|
||||||
|
size_t bytes)
|
||||||
|
{
|
||||||
|
struct s35390a *s35390a = priv;
|
||||||
|
|
||||||
|
/* The offset is ignored because the NVMEM region is only 1 byte */
|
||||||
|
return s35390a_get_reg(s35390a, S35390A_CMD_FREE_REG, val, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s35390a_nvmem_write(void *priv, unsigned int offset, void *val,
|
||||||
|
size_t bytes)
|
||||||
|
{
|
||||||
|
struct s35390a *s35390a = priv;
|
||||||
|
|
||||||
|
return s35390a_set_reg(s35390a, S35390A_CMD_FREE_REG, val, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
static int s35390a_probe(struct i2c_client *client)
|
static int s35390a_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int err, err_read;
|
int err, err_read;
|
||||||
|
|
@ -424,6 +442,15 @@ static int s35390a_probe(struct i2c_client *client)
|
||||||
struct rtc_device *rtc;
|
struct rtc_device *rtc;
|
||||||
u8 buf, status1;
|
u8 buf, status1;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
|
struct nvmem_config nvmem_cfg = {
|
||||||
|
.name = "s35390a_nvram",
|
||||||
|
.type = NVMEM_TYPE_BATTERY_BACKED,
|
||||||
|
.word_size = 1,
|
||||||
|
.stride = 1,
|
||||||
|
.size = 1,
|
||||||
|
.reg_read = s35390a_nvmem_read,
|
||||||
|
.reg_write = s35390a_nvmem_write,
|
||||||
|
};
|
||||||
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
@ -490,6 +517,11 @@ static int s35390a_probe(struct i2c_client *client)
|
||||||
if (status1 & S35390A_FLAG_INT2)
|
if (status1 & S35390A_FLAG_INT2)
|
||||||
rtc_update_irq(rtc, 1, RTC_AF);
|
rtc_update_irq(rtc, 1, RTC_AF);
|
||||||
|
|
||||||
|
nvmem_cfg.priv = s35390a;
|
||||||
|
err = devm_rtc_nvmem_register(rtc, &nvmem_cfg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
return devm_rtc_register_device(rtc);
|
return devm_rtc_register_device(rtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,7 @@
|
||||||
#define RTC_MSEC 1000
|
#define RTC_MSEC 1000
|
||||||
#define RTC_FR_MASK 0xF0000
|
#define RTC_FR_MASK 0xF0000
|
||||||
#define RTC_FR_MAX_TICKS 16
|
#define RTC_FR_MAX_TICKS 16
|
||||||
#define RTC_PPB 1000000000LL
|
#define RTC_PPB 1000000000
|
||||||
#define RTC_MIN_OFFSET -32768000
|
|
||||||
#define RTC_MAX_OFFSET 32767000
|
|
||||||
|
|
||||||
struct xlnx_rtc_dev {
|
struct xlnx_rtc_dev {
|
||||||
struct rtc_device *rtc;
|
struct rtc_device *rtc;
|
||||||
|
|
@ -178,21 +176,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
|
||||||
static int xlnx_rtc_read_offset(struct device *dev, long *offset)
|
static int xlnx_rtc_read_offset(struct device *dev, long *offset)
|
||||||
{
|
{
|
||||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||||
unsigned long long rtc_ppb = RTC_PPB;
|
unsigned int calibval, fract_data, fract_part;
|
||||||
unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
|
int freq = xrtcdev->freq;
|
||||||
unsigned int calibval;
|
int max_tick, tick_mult;
|
||||||
long offset_val;
|
long offset_val;
|
||||||
|
|
||||||
|
/* Tick to offset multiplier */
|
||||||
|
tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
|
||||||
|
|
||||||
calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
|
calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
|
||||||
/* Offset with seconds ticks */
|
/* Offset with seconds ticks */
|
||||||
offset_val = calibval & RTC_TICK_MASK;
|
max_tick = calibval & RTC_TICK_MASK;
|
||||||
offset_val = offset_val - RTC_CALIB_DEF;
|
offset_val = max_tick - freq;
|
||||||
offset_val = offset_val * tick_mult;
|
/* Convert to ppb */
|
||||||
|
offset_val *= tick_mult;
|
||||||
|
|
||||||
/* Offset with fractional ticks */
|
/* Offset with fractional ticks */
|
||||||
if (calibval & RTC_FR_EN)
|
if (calibval & RTC_FR_EN) {
|
||||||
offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
|
fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT;
|
||||||
* (tick_mult / RTC_FR_MAX_TICKS);
|
fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
|
||||||
|
offset_val += (fract_part * fract_data);
|
||||||
|
}
|
||||||
|
|
||||||
*offset = offset_val;
|
*offset = offset_val;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -201,44 +206,38 @@ static int xlnx_rtc_read_offset(struct device *dev, long *offset)
|
||||||
static int xlnx_rtc_set_offset(struct device *dev, long offset)
|
static int xlnx_rtc_set_offset(struct device *dev, long offset)
|
||||||
{
|
{
|
||||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||||
unsigned long long rtc_ppb = RTC_PPB;
|
int max_tick, tick_mult, fract_offset, fract_part;
|
||||||
unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
|
int freq = xrtcdev->freq;
|
||||||
unsigned char fract_tick = 0;
|
|
||||||
unsigned int calibval;
|
unsigned int calibval;
|
||||||
short int max_tick;
|
int fract_data = 0;
|
||||||
int fract_offset;
|
|
||||||
|
|
||||||
if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
|
/* Tick to offset multiplier */
|
||||||
return -ERANGE;
|
tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
|
||||||
|
|
||||||
/* Number ticks for given offset */
|
/* Number ticks for given offset */
|
||||||
max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
|
max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
|
||||||
|
|
||||||
|
if (freq + max_tick > RTC_TICK_MASK || (freq + max_tick < 1))
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
/* Number fractional ticks for given offset */
|
/* Number fractional ticks for given offset */
|
||||||
if (fract_offset) {
|
if (fract_offset) {
|
||||||
if (fract_offset < 0) {
|
fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
|
||||||
fract_offset = fract_offset + tick_mult;
|
fract_data = fract_offset / fract_part;
|
||||||
|
/* Subtract one from max_tick while adding fract_offset */
|
||||||
|
if (fract_offset < 0 && fract_data) {
|
||||||
max_tick--;
|
max_tick--;
|
||||||
}
|
fract_data += RTC_FR_MAX_TICKS;
|
||||||
if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
|
|
||||||
for (fract_tick = 1; fract_tick < 16; fract_tick++) {
|
|
||||||
if (fract_offset <=
|
|
||||||
(fract_tick *
|
|
||||||
(tick_mult / RTC_FR_MAX_TICKS)))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zynqmp RTC uses second and fractional tick
|
/* Zynqmp RTC uses second and fractional tick
|
||||||
* counters for compensation
|
* counters for compensation
|
||||||
*/
|
*/
|
||||||
calibval = max_tick + RTC_CALIB_DEF;
|
calibval = max_tick + freq;
|
||||||
|
|
||||||
if (fract_tick)
|
if (fract_data)
|
||||||
calibval |= RTC_FR_EN;
|
calibval |= (RTC_FR_EN | (fract_data << RTC_FR_DATSHIFT));
|
||||||
|
|
||||||
calibval |= (fract_tick << RTC_FR_DATSHIFT);
|
|
||||||
|
|
||||||
writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
|
writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
|
||||||
|
|
||||||
|
|
@ -345,7 +344,15 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
|
||||||
&xrtcdev->freq);
|
&xrtcdev->freq);
|
||||||
if (ret)
|
if (ret)
|
||||||
xrtcdev->freq = RTC_CALIB_DEF;
|
xrtcdev->freq = RTC_CALIB_DEF;
|
||||||
|
} else {
|
||||||
|
xrtcdev->freq--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xrtcdev->freq > RTC_TICK_MASK) {
|
||||||
|
dev_err(&pdev->dev, "Invalid RTC calibration value\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
|
ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
writel(xrtcdev->freq, (xrtcdev->reg_base + RTC_CALIB_WR));
|
writel(xrtcdev->freq, (xrtcdev->reg_base + RTC_CALIB_WR));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue