mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
RTC for 6.12
New driver: - DFRobot SD2405AL Drivers: - stm32: add alarm A out and LSCO support - sun6i: disable automatic clock input switching - m48t59: set range -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmbzMJ8ACgkQY6TcMGxw OjIVpw//YU/pOMIjD7I+cVcedK8UNGSP5GKlpd/4rK8sN7U3MiowbnvpSQT8rHvG N8WaRUjKkZRV6+Yo8iX5JQXacGTFv/WFfqQDCr3QgnU934AGibQT4WAQCooc8IrP fKB3Wzljcdr5cZZCWL5IBDiB6P7oWRdbdAHvwQUeTDMbF8zFd2ortLKDdCdHykXd iiK8gDDh7iVt2eiQ8duhhvruQXMLmxc7GdNNkTG/hhO6kis4sMUuwNwf+ifuO0fD 00HOJr0wEJkje5CeTlcU+R2z2Nf3PMnQMMyQzrQnoUv0AEaTcUDx4MiNN9YZ7Kds IGkJpVkH5UCMT2RyvVuKVcL2OWA9m2RP63NVfq1iV+lmFRf7neJlQ4Ul/sYcMaL8 wEL8UwIx4ya61O7mIZT8wI4ntl0yNm+hJw5r2yrIX1Cb7BACK4g0PzK6SoOOsMwN xbDkMrFQlpQm5YNL1vSV7ojFYvBwbvJXJfU3WTxF9V0O5RgqFFUSn/mlYog/DCZD zenPXYBQo4tp6Jkmg2A8J5g1R/274PQf08k4IQo4HTqtkjHyNRMEILDnneFX8Q0r f5W0k1HaWeYR8k08n6XI8A12lAj232RoGvFAtwaxRrqaEM5I5plcwrZIsMcpLSfK z0qnreEs9OAL2ZxNUYNNpWyphT4X3IDDSpRkh0Vj0chwgu1IQwo= =sjE7 -----END PGP SIGNATURE----- Merge tag 'rtc-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "More conversions of DT bindings to yaml. There is one new driver, for the DFRobot SD2405AL and support for important features of the stm32 RTC. Summary: New driver: - DFRobot SD2405AL Drivers: - stm32: add alarm A out and LSCO support - sun6i: disable automatic clock input switching - m48t59: set range" * tag 'rtc-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: rtc: rc5t619: use proper module tables rtc: m48t59: set range dt-bindings: rtc: microcrystal,rv3028: add #clock-cells property rtc: m48t59: Remove division condition with direct comparison rtc: at91sam9: fix OF node leak in probe() error path rtc: sun6i: disable automatic clock input switching dt-bindings: rtc: Drop non-trivial duplicate compatibles dt-bindings: vendor-prefixes: Add DFRobot. dt-bindings: rtc: Add support for SD2405AL. rtc: Add driver for SD2405AL rtc: s35390a: Drop vendorless compatible string from match table rtc: twl: convert comma to semicolon dt-bindings: rtc: sprd,sc2731-rtc: convert to YAML rtc: stm32: add alarm A out feature rtc: stm32: add Low Speed Clock Output (LSCO) support rtc: stm32: add pinctrl and pinmux interfaces dt-bindings: rtc: stm32: describe pinmux nodes
This commit is contained in:
commit
b2149f948c
@ -22,6 +22,9 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
trickle-resistor-ohms:
|
||||
enum:
|
||||
- 3000
|
||||
|
49
Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml
Normal file
49
Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml
Normal file
@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/sprd,sc2731-rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Spreadtrum SC2731 Real Time Clock
|
||||
|
||||
maintainers:
|
||||
- Orson Zhai <orsonzhai@gmail.com>
|
||||
- Baolin Wang <baolin.wang7@gmail.com>
|
||||
- Chunyan Zhang <zhang.lyra@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sprd,sc2731-rtc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: rtc.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rtc@280 {
|
||||
compatible = "sprd,sc2731-rtc";
|
||||
reg = <0x280>;
|
||||
interrupt-parent = <&sc2731_pmic>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,26 +0,0 @@
|
||||
Spreadtrum SC27xx Real Time Clock
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "sprd,sc2731-rtc".
|
||||
- reg: address offset of rtc register.
|
||||
- interrupts: rtc alarm interrupt.
|
||||
|
||||
Example:
|
||||
|
||||
sc2731_pmic: pmic@0 {
|
||||
compatible = "sprd,sc2731";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <26000000>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rtc@280 {
|
||||
compatible = "sprd,sc2731-rtc";
|
||||
reg = <0x280>;
|
||||
interrupt-parent = <&sc2731_pmic>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
@ -53,6 +53,28 @@ properties:
|
||||
override default rtc_ck parent clock phandle of the new parent clock of rtc_ck
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^rtc-[a-z]+-[0-9]+$":
|
||||
type: object
|
||||
$ref: /schemas/pinctrl/pinmux-node.yaml
|
||||
description: |
|
||||
Configuration of STM32 RTC pins description. STM32 RTC is able to output
|
||||
some signals on specific pins:
|
||||
- LSCO (Low Speed Clock Output) that allow to output LSE clock on a pin.
|
||||
- Alarm out that allow to send a pulse on a pin when alarm A of the RTC
|
||||
expires.
|
||||
additionalProperties: false
|
||||
properties:
|
||||
function:
|
||||
enum:
|
||||
- lsco
|
||||
- alarm-a
|
||||
pins:
|
||||
enum:
|
||||
- out1
|
||||
- out2
|
||||
- out2_rmp
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
@ -68,6 +90,9 @@ allOf:
|
||||
|
||||
clock-names: false
|
||||
|
||||
patternProperties:
|
||||
"^rtc-[a-z]+-[0-9]+$": false
|
||||
|
||||
required:
|
||||
- st,syscfg
|
||||
|
||||
@ -83,6 +108,9 @@ allOf:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
patternProperties:
|
||||
"^rtc-[a-z]+-[0-9]+$": false
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- st,syscfg
|
||||
|
@ -38,12 +38,13 @@ properties:
|
||||
- dallas,ds1672
|
||||
# Extremely Accurate I²C RTC with Integrated Crystal and SRAM
|
||||
- dallas,ds3232
|
||||
# SD2405AL Real-Time Clock
|
||||
- dfrobot,sd2405al
|
||||
# EM Microelectronic EM3027 RTC
|
||||
- emmicro,em3027
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
- epson,rx8010
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
- epson,rx8025
|
||||
- epson,rx8035
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM
|
||||
- epson,rx8111
|
||||
@ -52,10 +53,6 @@ properties:
|
||||
- epson,rx8581
|
||||
# Android Goldfish Real-time Clock
|
||||
- google,goldfish-rtc
|
||||
# Intersil ISL1208 Low Power RTC with Battery Backed SRAM
|
||||
- isil,isl1208
|
||||
# Intersil ISL1218 Low Power RTC with Battery Backed SRAM
|
||||
- isil,isl1218
|
||||
# Mvebu Real-time Clock
|
||||
- marvell,orion-rtc
|
||||
# Maxim DS1742/DS1743 Real-time Clock
|
||||
@ -68,8 +65,6 @@ properties:
|
||||
- microcrystal,rv8523
|
||||
# NXP LPC32xx SoC Real-time Clock
|
||||
- nxp,lpc3220-rtc
|
||||
# Real-time Clock Module
|
||||
- pericom,pt7c4338
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
- ricoh,r2025sd
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
|
@ -368,6 +368,8 @@ patternProperties:
|
||||
description: Devantech, Ltd.
|
||||
"^dfi,.*":
|
||||
description: DFI Inc.
|
||||
"^dfrobot,.*":
|
||||
description: DFRobot Corporation
|
||||
"^dh,.*":
|
||||
description: DH electronics GmbH
|
||||
"^difrnce,.*":
|
||||
|
@ -6557,6 +6557,12 @@ F: include/net/devlink.h
|
||||
F: include/uapi/linux/devlink.h
|
||||
F: net/devlink/
|
||||
|
||||
DFROBOT SD2405AL RTC DRIVER
|
||||
M: Tóth János <gomba007@gmail.com>
|
||||
L: linux-rtc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/rtc/rtc-sd2405al.c
|
||||
|
||||
DH ELECTRONICS IMX6 DHCOM/DHCOR BOARD SUPPORT
|
||||
M: Christoph Niedermaier <cniedermaier@dh-electronics.com>
|
||||
L: kernel@dh-electronics.com
|
||||
|
@ -743,6 +743,16 @@ config RTC_DRV_S5M
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-s5m.
|
||||
|
||||
config RTC_DRV_SD2405AL
|
||||
tristate "DFRobot SD2405AL"
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
DFRobot SD2405AL I2C RTC Module.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-sd2405al.
|
||||
|
||||
config RTC_DRV_SD3078
|
||||
tristate "ZXW Shenzhen whwave SD3078"
|
||||
select REGMAP_I2C
|
||||
@ -1934,6 +1944,12 @@ config RTC_DRV_STM32
|
||||
tristate "STM32 RTC"
|
||||
select REGMAP_MMIO
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on PINCTRL
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
If you say yes here you get support for the STM32 On-Chip
|
||||
Real Time Clock.
|
||||
|
@ -163,6 +163,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
|
||||
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
|
||||
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
|
||||
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
|
||||
obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o
|
||||
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
|
||||
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
|
||||
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
|
||||
|
@ -368,6 +368,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
rtc->gpbr = syscon_node_to_regmap(args.np);
|
||||
of_node_put(args.np);
|
||||
rtc->gpbr_offset = args.args[0];
|
||||
if (IS_ERR(rtc->gpbr)) {
|
||||
dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
|
||||
|
@ -132,7 +132,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
|
||||
M48T59_WRITE(bin2bcd(year % 100), M48T59_YEAR);
|
||||
|
||||
if (pdata->type == M48T59RTC_TYPE_M48T59 && (year / 100))
|
||||
if (pdata->type == M48T59RTC_TYPE_M48T59 && (year >= 100))
|
||||
val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
|
||||
val |= (bin2bcd(tm->tm_wday) & 0x07);
|
||||
M48T59_WRITE(val, M48T59_WDAY);
|
||||
@ -458,6 +458,8 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, m48t59);
|
||||
|
||||
m48t59->rtc->ops = &m48t59_rtc_ops;
|
||||
m48t59->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
m48t59->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
nvmem_cfg.size = pdata->offset;
|
||||
ret = devm_rtc_nvmem_register(m48t59->rtc, &nvmem_cfg);
|
||||
|
@ -429,14 +429,23 @@ static int rc5t619_rtc_probe(struct platform_device *pdev)
|
||||
return devm_rtc_register_device(rtc->rtc);
|
||||
}
|
||||
|
||||
static const struct platform_device_id rc5t619_rtc_id[] = {
|
||||
{
|
||||
.name = "rc5t619-rtc",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, rc5t619_rtc_id);
|
||||
|
||||
static struct platform_driver rc5t619_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "rc5t619-rtc",
|
||||
},
|
||||
.probe = rc5t619_rtc_probe,
|
||||
.id_table = rc5t619_rtc_id,
|
||||
};
|
||||
|
||||
module_platform_driver(rc5t619_rtc_driver);
|
||||
MODULE_ALIAS("platform:rc5t619-rtc");
|
||||
|
||||
MODULE_DESCRIPTION("RICOH RC5T619 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -56,7 +56,6 @@ static const struct i2c_device_id s35390a_id[] = {
|
||||
MODULE_DEVICE_TABLE(i2c, s35390a_id);
|
||||
|
||||
static const __maybe_unused struct of_device_id s35390a_of_match[] = {
|
||||
{ .compatible = "s35390a" },
|
||||
{ .compatible = "sii,s35390a" },
|
||||
{ }
|
||||
};
|
||||
|
227
drivers/rtc/rtc-sd2405al.c
Normal file
227
drivers/rtc/rtc-sd2405al.c
Normal file
@ -0,0 +1,227 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* RTC driver for the SD2405AL Real-Time Clock
|
||||
*
|
||||
* Datasheet:
|
||||
* https://image.dfrobot.com/image/data/TOY0021/SD2405AL%20datasheet%20(Angelo%20v0.1).pdf
|
||||
*
|
||||
* Copyright (C) 2024 Tóth János <gomba007@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/* Real time clock registers */
|
||||
#define SD2405AL_REG_T_SEC 0x00
|
||||
#define SD2405AL_REG_T_MIN 0x01
|
||||
#define SD2405AL_REG_T_HOUR 0x02
|
||||
# define SD2405AL_BIT_12H_PM BIT(5)
|
||||
# define SD2405AL_BIT_24H BIT(7)
|
||||
#define SD2405AL_REG_T_WEEK 0x03
|
||||
#define SD2405AL_REG_T_DAY 0x04
|
||||
#define SD2405AL_REG_T_MON 0x05
|
||||
#define SD2405AL_REG_T_YEAR 0x06
|
||||
|
||||
#define SD2405AL_NUM_T_REGS (SD2405AL_REG_T_YEAR - SD2405AL_REG_T_SEC + 1)
|
||||
|
||||
/* Control registers */
|
||||
#define SD2405AL_REG_CTR1 0x0F
|
||||
# define SD2405AL_BIT_WRTC2 BIT(2)
|
||||
# define SD2405AL_BIT_WRTC3 BIT(7)
|
||||
#define SD2405AL_REG_CTR2 0x10
|
||||
# define SD2405AL_BIT_WRTC1 BIT(7)
|
||||
#define SD2405AL_REG_CTR3 0x11
|
||||
#define SD2405AL_REG_TTF 0x12
|
||||
#define SD2405AL_REG_CNTDWN 0x13
|
||||
|
||||
/* General RAM */
|
||||
#define SD2405AL_REG_M_START 0x14
|
||||
#define SD2405AL_REG_M_END 0x1F
|
||||
|
||||
struct sd2405al {
|
||||
struct device *dev;
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int sd2405al_enable_reg_write(struct sd2405al *sd2405al)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* order of writes is important */
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR2,
|
||||
SD2405AL_BIT_WRTC1, SD2405AL_BIT_WRTC1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR1,
|
||||
SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3,
|
||||
SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd2405al_disable_reg_write(struct sd2405al *sd2405al)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* order of writes is important */
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR1,
|
||||
SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR2,
|
||||
SD2405AL_BIT_WRTC1, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd2405al_read_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
u8 data[SD2405AL_NUM_T_REGS] = { 0 };
|
||||
struct sd2405al *sd2405al = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(sd2405al->regmap, SD2405AL_REG_T_SEC, data,
|
||||
SD2405AL_NUM_T_REGS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
time->tm_sec = bcd2bin(data[SD2405AL_REG_T_SEC] & 0x7F);
|
||||
time->tm_min = bcd2bin(data[SD2405AL_REG_T_MIN] & 0x7F);
|
||||
|
||||
if (data[SD2405AL_REG_T_HOUR] & SD2405AL_BIT_24H)
|
||||
time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR] & 0x3F);
|
||||
else
|
||||
if (data[SD2405AL_REG_T_HOUR] & SD2405AL_BIT_12H_PM)
|
||||
time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR]
|
||||
& 0x1F) + 12;
|
||||
else /* 12 hour mode, AM */
|
||||
time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR]
|
||||
& 0x1F);
|
||||
|
||||
time->tm_wday = bcd2bin(data[SD2405AL_REG_T_WEEK] & 0x07);
|
||||
time->tm_mday = bcd2bin(data[SD2405AL_REG_T_DAY] & 0x3F);
|
||||
time->tm_mon = bcd2bin(data[SD2405AL_REG_T_MON] & 0x1F) - 1;
|
||||
time->tm_year = bcd2bin(data[SD2405AL_REG_T_YEAR]) + 100;
|
||||
|
||||
dev_dbg(sd2405al->dev, "read time: %ptR (%d)\n", time, time->tm_wday);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd2405al_set_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
u8 data[SD2405AL_NUM_T_REGS];
|
||||
struct sd2405al *sd2405al = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
data[SD2405AL_REG_T_SEC] = bin2bcd(time->tm_sec);
|
||||
data[SD2405AL_REG_T_MIN] = bin2bcd(time->tm_min);
|
||||
data[SD2405AL_REG_T_HOUR] = bin2bcd(time->tm_hour) | SD2405AL_BIT_24H;
|
||||
data[SD2405AL_REG_T_DAY] = bin2bcd(time->tm_mday);
|
||||
data[SD2405AL_REG_T_WEEK] = bin2bcd(time->tm_wday);
|
||||
data[SD2405AL_REG_T_MON] = bin2bcd(time->tm_mon) + 1;
|
||||
data[SD2405AL_REG_T_YEAR] = bin2bcd(time->tm_year - 100);
|
||||
|
||||
ret = sd2405al_enable_reg_write(sd2405al);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_write(sd2405al->regmap, SD2405AL_REG_T_SEC, data,
|
||||
SD2405AL_NUM_T_REGS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(sd2405al->regmap, SD2405AL_REG_TTF, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sd2405al_disable_reg_write(sd2405al);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(sd2405al->dev, "set time: %ptR (%d)\n", time, time->tm_wday);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops sd2405al_rtc_ops = {
|
||||
.read_time = sd2405al_read_time,
|
||||
.set_time = sd2405al_set_time,
|
||||
};
|
||||
|
||||
static const struct regmap_config sd2405al_regmap_conf = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = SD2405AL_REG_M_END,
|
||||
};
|
||||
|
||||
static int sd2405al_probe(struct i2c_client *client)
|
||||
{
|
||||
struct sd2405al *sd2405al;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return -ENODEV;
|
||||
|
||||
sd2405al = devm_kzalloc(&client->dev, sizeof(*sd2405al), GFP_KERNEL);
|
||||
if (!sd2405al)
|
||||
return -ENOMEM;
|
||||
|
||||
sd2405al->dev = &client->dev;
|
||||
|
||||
sd2405al->regmap = devm_regmap_init_i2c(client, &sd2405al_regmap_conf);
|
||||
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);
|
||||
|
||||
sd2405al->rtc->ops = &sd2405al_rtc_ops;
|
||||
sd2405al->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
sd2405al->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
dev_set_drvdata(&client->dev, sd2405al);
|
||||
|
||||
ret = devm_rtc_register_device(sd2405al->rtc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sd2405al_id[] = {
|
||||
{ "sd2405al" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sd2405al_id);
|
||||
|
||||
static const __maybe_unused struct of_device_id sd2405al_of_match[] = {
|
||||
{ .compatible = "dfrobot,sd2405al" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sd2405al_of_match);
|
||||
|
||||
static struct i2c_driver sd2405al_driver = {
|
||||
.driver = {
|
||||
.name = "sd2405al",
|
||||
.of_match_table = of_match_ptr(sd2405al_of_match),
|
||||
},
|
||||
.probe = sd2405al_probe,
|
||||
.id_table = sd2405al_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(sd2405al_driver);
|
||||
|
||||
MODULE_AUTHOR("Tóth János <gomba007@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SD2405AL RTC driver");
|
@ -7,12 +7,16 @@
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -42,6 +46,12 @@
|
||||
#define STM32_RTC_CR_FMT BIT(6)
|
||||
#define STM32_RTC_CR_ALRAE BIT(8)
|
||||
#define STM32_RTC_CR_ALRAIE BIT(12)
|
||||
#define STM32_RTC_CR_OSEL GENMASK(22, 21)
|
||||
#define STM32_RTC_CR_OSEL_ALARM_A FIELD_PREP(STM32_RTC_CR_OSEL, 0x01)
|
||||
#define STM32_RTC_CR_COE BIT(23)
|
||||
#define STM32_RTC_CR_TAMPOE BIT(26)
|
||||
#define STM32_RTC_CR_TAMPALRM_TYPE BIT(30)
|
||||
#define STM32_RTC_CR_OUT2EN BIT(31)
|
||||
|
||||
/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
|
||||
#define STM32_RTC_ISR_ALRAWF BIT(0)
|
||||
@ -78,6 +88,12 @@
|
||||
/* STM32_RTC_SR/_SCR bit fields */
|
||||
#define STM32_RTC_SR_ALRA BIT(0)
|
||||
|
||||
/* STM32_RTC_CFGR bit fields */
|
||||
#define STM32_RTC_CFGR_OUT2_RMP BIT(0)
|
||||
#define STM32_RTC_CFGR_LSCOEN GENMASK(2, 1)
|
||||
#define STM32_RTC_CFGR_LSCOEN_OUT1 1
|
||||
#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2
|
||||
|
||||
/* STM32_RTC_VERR bit fields */
|
||||
#define STM32_RTC_VERR_MINREV_SHIFT 0
|
||||
#define STM32_RTC_VERR_MINREV GENMASK(3, 0)
|
||||
@ -107,6 +123,14 @@
|
||||
/* STM32 RTC driver time helpers */
|
||||
#define SEC_PER_DAY (24 * 60 * 60)
|
||||
|
||||
/* STM32 RTC pinctrl helpers */
|
||||
#define STM32_RTC_PINMUX(_name, _action, ...) { \
|
||||
.name = (_name), \
|
||||
.action = (_action), \
|
||||
.groups = ((const char *[]){ __VA_ARGS__ }), \
|
||||
.num_groups = ARRAY_SIZE(((const char *[]){ __VA_ARGS__ })), \
|
||||
}
|
||||
|
||||
struct stm32_rtc;
|
||||
|
||||
struct stm32_rtc_registers {
|
||||
@ -119,6 +143,7 @@ struct stm32_rtc_registers {
|
||||
u16 wpr;
|
||||
u16 sr;
|
||||
u16 scr;
|
||||
u16 cfgr;
|
||||
u16 verr;
|
||||
};
|
||||
|
||||
@ -134,6 +159,8 @@ struct stm32_rtc_data {
|
||||
bool need_dbp;
|
||||
bool need_accuracy;
|
||||
bool rif_protected;
|
||||
bool has_lsco;
|
||||
bool has_alarm_out;
|
||||
};
|
||||
|
||||
struct stm32_rtc {
|
||||
@ -146,6 +173,7 @@ struct stm32_rtc {
|
||||
struct clk *rtc_ck;
|
||||
const struct stm32_rtc_data *data;
|
||||
int irq_alarm;
|
||||
struct clk *clk_lsco;
|
||||
};
|
||||
|
||||
struct stm32_rtc_rif_resource {
|
||||
@ -171,6 +199,209 @@ static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
|
||||
writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + regs->wpr);
|
||||
}
|
||||
|
||||
enum stm32_rtc_pin_name {
|
||||
NONE,
|
||||
OUT1,
|
||||
OUT2,
|
||||
OUT2_RMP
|
||||
};
|
||||
|
||||
static const struct pinctrl_pin_desc stm32_rtc_pinctrl_pins[] = {
|
||||
PINCTRL_PIN(OUT1, "out1"),
|
||||
PINCTRL_PIN(OUT2, "out2"),
|
||||
PINCTRL_PIN(OUT2_RMP, "out2_rmp"),
|
||||
};
|
||||
|
||||
static int stm32_rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
return ARRAY_SIZE(stm32_rtc_pinctrl_pins);
|
||||
}
|
||||
|
||||
static const char *stm32_rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector)
|
||||
{
|
||||
return stm32_rtc_pinctrl_pins[selector].name;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector,
|
||||
const unsigned int **pins,
|
||||
unsigned int *num_pins)
|
||||
{
|
||||
*pins = &stm32_rtc_pinctrl_pins[selector].number;
|
||||
*num_pins = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pinctrl_ops stm32_rtc_pinctrl_ops = {
|
||||
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
||||
.dt_free_map = pinconf_generic_dt_free_map,
|
||||
.get_groups_count = stm32_rtc_pinctrl_get_groups_count,
|
||||
.get_group_name = stm32_rtc_pinctrl_get_group_name,
|
||||
.get_group_pins = stm32_rtc_pinctrl_get_group_pins,
|
||||
};
|
||||
|
||||
struct stm32_rtc_pinmux_func {
|
||||
const char *name;
|
||||
const char * const *groups;
|
||||
const unsigned int num_groups;
|
||||
int (*action)(struct pinctrl_dev *pctl_dev, unsigned int pin);
|
||||
};
|
||||
|
||||
static int stm32_rtc_pinmux_action_alarm(struct pinctrl_dev *pctldev, unsigned int pin)
|
||||
{
|
||||
struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
unsigned int cr = readl_relaxed(rtc->base + regs.cr);
|
||||
unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
|
||||
|
||||
if (!rtc->data->has_alarm_out)
|
||||
return -EPERM;
|
||||
|
||||
cr &= ~STM32_RTC_CR_OSEL;
|
||||
cr |= STM32_RTC_CR_OSEL_ALARM_A;
|
||||
cr &= ~STM32_RTC_CR_TAMPOE;
|
||||
cr &= ~STM32_RTC_CR_COE;
|
||||
cr &= ~STM32_RTC_CR_TAMPALRM_TYPE;
|
||||
|
||||
switch (pin) {
|
||||
case OUT1:
|
||||
cr &= ~STM32_RTC_CR_OUT2EN;
|
||||
cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
|
||||
break;
|
||||
case OUT2:
|
||||
cr |= STM32_RTC_CR_OUT2EN;
|
||||
cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
|
||||
break;
|
||||
case OUT2_RMP:
|
||||
cr |= STM32_RTC_CR_OUT2EN;
|
||||
cfgr |= STM32_RTC_CFGR_OUT2_RMP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
writel_relaxed(cr, rtc->base + regs.cr);
|
||||
writel_relaxed(cfgr, rtc->base + regs.cfgr);
|
||||
stm32_rtc_wpr_lock(rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_lsco_available(struct pinctrl_dev *pctldev, unsigned int pin)
|
||||
{
|
||||
struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
unsigned int cr = readl_relaxed(rtc->base + regs.cr);
|
||||
unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
|
||||
unsigned int calib = STM32_RTC_CR_COE;
|
||||
unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL;
|
||||
|
||||
switch (pin) {
|
||||
case OUT1:
|
||||
if ((!(cr & STM32_RTC_CR_OUT2EN) &&
|
||||
((cr & calib) || cr & tampalrm)) ||
|
||||
((cr & calib) && (cr & tampalrm)))
|
||||
return -EBUSY;
|
||||
break;
|
||||
case OUT2_RMP:
|
||||
if ((cr & STM32_RTC_CR_OUT2EN) &&
|
||||
(cfgr & STM32_RTC_CFGR_OUT2_RMP) &&
|
||||
((cr & calib) || (cr & tampalrm)))
|
||||
return -EBUSY;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (clk_get_rate(rtc->rtc_ck) != 32768)
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_action_lsco(struct pinctrl_dev *pctldev, unsigned int pin)
|
||||
{
|
||||
struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
struct device *dev = rtc->rtc_dev->dev.parent;
|
||||
u8 lscoen;
|
||||
int ret;
|
||||
|
||||
if (!rtc->data->has_lsco)
|
||||
return -EPERM;
|
||||
|
||||
ret = stm32_rtc_pinmux_lsco_available(pctldev, pin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lscoen = (pin == OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : STM32_RTC_CFGR_LSCOEN_OUT2_RMP;
|
||||
|
||||
rtc->clk_lsco = clk_register_gate(dev, "rtc_lsco", __clk_get_name(rtc->rtc_ck),
|
||||
CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
|
||||
rtc->base + regs.cfgr, lscoen, 0, NULL);
|
||||
if (IS_ERR(rtc->clk_lsco))
|
||||
return PTR_ERR(rtc->clk_lsco);
|
||||
|
||||
of_clk_add_provider(dev->of_node, of_clk_src_simple_get, rtc->clk_lsco);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stm32_rtc_pinmux_func stm32_rtc_pinmux_functions[] = {
|
||||
STM32_RTC_PINMUX("lsco", &stm32_rtc_pinmux_action_lsco, "out1", "out2_rmp"),
|
||||
STM32_RTC_PINMUX("alarm-a", &stm32_rtc_pinmux_action_alarm, "out1", "out2", "out2_rmp"),
|
||||
};
|
||||
|
||||
static int stm32_rtc_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
return ARRAY_SIZE(stm32_rtc_pinmux_functions);
|
||||
}
|
||||
|
||||
static const char *stm32_rtc_pinmux_get_fname(struct pinctrl_dev *pctldev, unsigned int selector)
|
||||
{
|
||||
return stm32_rtc_pinmux_functions[selector].name;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned int selector,
|
||||
const char * const **groups, unsigned int * const num_groups)
|
||||
{
|
||||
*groups = stm32_rtc_pinmux_functions[selector].groups;
|
||||
*num_groups = stm32_rtc_pinmux_functions[selector].num_groups;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
|
||||
unsigned int group)
|
||||
{
|
||||
struct stm32_rtc_pinmux_func selected_func = stm32_rtc_pinmux_functions[selector];
|
||||
struct pinctrl_pin_desc pin = stm32_rtc_pinctrl_pins[group];
|
||||
|
||||
/* Call action */
|
||||
if (selected_func.action)
|
||||
return selected_func.action(pctldev, pin.number);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct pinmux_ops stm32_rtc_pinmux_ops = {
|
||||
.get_functions_count = stm32_rtc_pinmux_get_functions_count,
|
||||
.get_function_name = stm32_rtc_pinmux_get_fname,
|
||||
.get_function_groups = stm32_rtc_pinmux_get_groups,
|
||||
.set_mux = stm32_rtc_pinmux_set_mux,
|
||||
.strict = true,
|
||||
};
|
||||
|
||||
static struct pinctrl_desc stm32_rtc_pdesc = {
|
||||
.name = DRIVER_NAME,
|
||||
.pins = stm32_rtc_pinctrl_pins,
|
||||
.npins = ARRAY_SIZE(stm32_rtc_pinctrl_pins),
|
||||
.owner = THIS_MODULE,
|
||||
.pctlops = &stm32_rtc_pinctrl_ops,
|
||||
.pmxops = &stm32_rtc_pinmux_ops,
|
||||
};
|
||||
|
||||
static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
|
||||
{
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
@ -576,6 +807,8 @@ static const struct stm32_rtc_data stm32_rtc_data = {
|
||||
.need_dbp = true,
|
||||
.need_accuracy = false,
|
||||
.rif_protected = false,
|
||||
.has_lsco = false,
|
||||
.has_alarm_out = false,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@ -586,6 +819,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
||||
.scr = UNDEF_REG,
|
||||
.cfgr = UNDEF_REG,
|
||||
.verr = UNDEF_REG,
|
||||
},
|
||||
.events = {
|
||||
@ -599,6 +833,8 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
|
||||
.need_dbp = true,
|
||||
.need_accuracy = false,
|
||||
.rif_protected = false,
|
||||
.has_lsco = false,
|
||||
.has_alarm_out = false,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@ -609,6 +845,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
||||
.scr = UNDEF_REG,
|
||||
.cfgr = UNDEF_REG,
|
||||
.verr = UNDEF_REG,
|
||||
},
|
||||
.events = {
|
||||
@ -631,6 +868,8 @@ static const struct stm32_rtc_data stm32mp1_data = {
|
||||
.need_dbp = false,
|
||||
.need_accuracy = true,
|
||||
.rif_protected = false,
|
||||
.has_lsco = true,
|
||||
.has_alarm_out = true,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@ -641,6 +880,7 @@ static const struct stm32_rtc_data stm32mp1_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x50,
|
||||
.scr = 0x5C,
|
||||
.cfgr = 0x60,
|
||||
.verr = 0x3F4,
|
||||
},
|
||||
.events = {
|
||||
@ -654,6 +894,8 @@ static const struct stm32_rtc_data stm32mp25_data = {
|
||||
.need_dbp = false,
|
||||
.need_accuracy = true,
|
||||
.rif_protected = true,
|
||||
.has_lsco = true,
|
||||
.has_alarm_out = true,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@ -664,6 +906,7 @@ static const struct stm32_rtc_data stm32mp25_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x50,
|
||||
.scr = 0x5C,
|
||||
.cfgr = 0x60,
|
||||
.verr = 0x3F4,
|
||||
},
|
||||
.events = {
|
||||
@ -681,6 +924,30 @@ static const struct of_device_id stm32_rtc_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
|
||||
|
||||
static void stm32_rtc_clean_outs(struct stm32_rtc *rtc)
|
||||
{
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
unsigned int cr = readl_relaxed(rtc->base + regs.cr);
|
||||
|
||||
cr &= ~STM32_RTC_CR_OSEL;
|
||||
cr &= ~STM32_RTC_CR_TAMPOE;
|
||||
cr &= ~STM32_RTC_CR_COE;
|
||||
cr &= ~STM32_RTC_CR_TAMPALRM_TYPE;
|
||||
cr &= ~STM32_RTC_CR_OUT2EN;
|
||||
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
writel_relaxed(cr, rtc->base + regs.cr);
|
||||
stm32_rtc_wpr_lock(rtc);
|
||||
|
||||
if (regs.cfgr != UNDEF_REG) {
|
||||
unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
|
||||
|
||||
cfgr &= ~STM32_RTC_CFGR_LSCOEN;
|
||||
cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
|
||||
writel_relaxed(cfgr, rtc->base + regs.cfgr);
|
||||
}
|
||||
}
|
||||
|
||||
static int stm32_rtc_check_rif(struct stm32_rtc *stm32_rtc,
|
||||
struct stm32_rtc_rif_resource res)
|
||||
{
|
||||
@ -791,6 +1058,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_rtc *rtc;
|
||||
const struct stm32_rtc_registers *regs;
|
||||
struct pinctrl_dev *pctl;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
@ -912,6 +1180,16 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
stm32_rtc_clean_outs(rtc);
|
||||
|
||||
ret = devm_pinctrl_register_and_init(&pdev->dev, &stm32_rtc_pdesc, rtc, &pctl);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "pinctrl register failed");
|
||||
|
||||
ret = pinctrl_enable(pctl);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "pinctrl enable failed");
|
||||
|
||||
/*
|
||||
* If INITS flag is reset (calendar year field set to 0x00), calendar
|
||||
* must be initialized
|
||||
@ -950,6 +1228,9 @@ static void stm32_rtc_remove(struct platform_device *pdev)
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int cr;
|
||||
|
||||
if (!IS_ERR_OR_NULL(rtc->clk_lsco))
|
||||
clk_unregister_gate(rtc->clk_lsco);
|
||||
|
||||
/* Disable interrupts */
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
|
@ -402,6 +402,7 @@ CLK_OF_DECLARE_DRIVER(sun8i_r40_rtc_clk, "allwinner,sun8i-r40-rtc",
|
||||
static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = {
|
||||
.rc_osc_rate = 32000,
|
||||
.has_out_clk = 1,
|
||||
.has_auto_swt = 1,
|
||||
};
|
||||
|
||||
static void __init sun8i_v3_rtc_clk_init(struct device_node *node)
|
||||
|
@ -591,8 +591,8 @@ static int twl_rtc_probe(struct platform_device *pdev)
|
||||
memset(&nvmem_cfg, 0, sizeof(nvmem_cfg));
|
||||
nvmem_cfg.name = "twl-secured-";
|
||||
nvmem_cfg.type = NVMEM_TYPE_BATTERY_BACKED;
|
||||
nvmem_cfg.reg_read = twl_nvram_read,
|
||||
nvmem_cfg.reg_write = twl_nvram_write,
|
||||
nvmem_cfg.reg_read = twl_nvram_read;
|
||||
nvmem_cfg.reg_write = twl_nvram_write;
|
||||
nvmem_cfg.word_size = 1;
|
||||
nvmem_cfg.stride = 1;
|
||||
if (twl_class_is_4030()) {
|
||||
|
Loading…
Reference in New Issue
Block a user