RTC for 6.13

New drivers:
  - Amlogic A4 and A5 RTC
  - Marvell 88PM886 PMIC RTC
  - Renesas RTCA-3 for Renesas RZ/G3S
 
 Drivers:
  - ab-eoz9: fix temperature and alarm support
  - cmos: improve locking behaviour
  - isl12022: add alarm support
  - m48t59: improve epoch handling
  - mt6359: add range
  - rzn1: fix BCD conversions and simplify driver
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmdKJY4ACgkQY6TcMGxw
 OjJvKhAAmxWzgm5wXTtzNdO/GvmlXehTQ+vdUbhldIGTDKekT2Dr4ijwAI/JOKJt
 CDasXOQw2jEQg1NyxMmcBHtEol6866pUW9+tMFwYi2SxphOfhMbuw7bQNpOPCWUS
 rK3y/sbz0CrHPaGv9RcAxSpzCboXNWCaIGE/JPC/3nhnlSYwW2XZMLxCVTJ1ixAV
 S0Z4CtwCo3E7t6+i1ZY0Lm1AXze9xOuEWF+r9x5TonpetY8z94EcB8xniHfLbrpZ
 1hpwewihyG7pJzvJr7+Q8Ze8P6m/LbohBk7TbzG035ILBSbUu6UHysQCocMgsz8j
 M4yOTTKPwprdc9DrhtykEK4sx+fF1V5tJV+Nl1sljpQco6PNWu+JP6BFrRR8OH0w
 OwmNytgLQux0+rtWjMMuyXYkSKJssTTrpZqpVRud/jf/IVyowQxbCQnTUK8WSm6v
 1cqI4KnVcUFx+kp0BeLJz4a31O8VeMhj+YYqruFhaGdhwMYimXp8X9ZMxZkCVpMa
 OlmtswPvBkN1b/+w72aOXBmrWFYafICZZY7MAViEzVHM0yoIVwEzSfBToT7hvV7h
 w2LFSvHqLIChnUYYEQUlCh7xXhUks7fwbyRG/2n/0G1We7ZsEKIlPXCmhRl0e2R+
 TGgkfUjczJ5z48m0oSy62yj1bmKVvtVdsJ/Ua5192eSxqBCTv78=
 =Q4/G
 -----END PGP SIGNATURE-----

Merge tag 'rtc-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "New drivers:
   - Amlogic A4 and A5 RTC
   - Marvell 88PM886 PMIC RTC
   - Renesas RTCA-3 for Renesas RZ/G3S

  Driver updates:
   - ab-eoz9: fix temperature and alarm support
   - cmos: improve locking behaviour
   - isl12022: add alarm support
   - m48t59: improve epoch handling
   - mt6359: add range
   - rzn1: fix BCD conversions and simplify driver"

* tag 'rtc-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (38 commits)
  rtc: ab-eoz9: don't fail temperature reads on undervoltage notification
  rtc: rzn1: reduce register access
  rtc: rzn1: drop superfluous wday calculation
  m68k: mvme147, mvme16x: Adopt rtc-m48t59 platform driver
  rtc: brcmstb-waketimer: don't include 'pm_wakeup.h' directly
  rtc: m48t59: Use platform_data struct for year offset value
  rtc: ab-eoz9: fix abeoz9_rtc_read_alarm
  rtc: rv3028: fix RV3028_TS_COUNT type
  rtc: rzn1: update Michel's email
  rtc: rzn1: fix BCD to rtc_time conversion errors
  rtc: amlogic-a4: fix compile error
  rtc: amlogic-a4: drop error messages
  MAINTAINERS: Add an entry for Amlogic RTC driver
  rtc: support for the Amlogic on-chip RTC
  dt-bindings: rtc: Add Amlogic A4 and A5 RTC
  rtc: add driver for Marvell 88PM886 PMIC RTC
  rtc: check if __rtc_read_time was successful in rtc_timer_do_work()
  rtc: pcf8563: Switch to regmap
  rtc: pcf8563: Sort headers alphabetically
  rtc: abx80x: Fix WDT bit position of the status register
  ...
This commit is contained in:
Linus Torvalds 2024-11-30 11:18:16 -08:00
commit 0e287d31b6
81 changed files with 2226 additions and 604 deletions

View File

@ -30,7 +30,9 @@ properties:
- const: allwinner,sun50i-a64-rtc - const: allwinner,sun50i-a64-rtc
- const: allwinner,sun8i-h3-rtc - const: allwinner,sun8i-h3-rtc
- items: - items:
- const: allwinner,sun20i-d1-rtc - enum:
- allwinner,sun20i-d1-rtc
- allwinner,sun55i-a523-rtc
- const: allwinner,sun50i-r329-rtc - const: allwinner,sun50i-r329-rtc
reg: reg:

View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2024 Amlogic, Inc. All rights reserved
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/amlogic,a4-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic A4 and A5 RTC
maintainers:
- Yiting Deng <yiting.deng@amlogic.com>
- Xianwei Zhao <xianwei.zhao@amlogic.com>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
enum:
- amlogic,a4-rtc
- amlogic,a5-rtc
reg:
maxItems: 1
clocks:
items:
- description: RTC clock source, available 24M or 32K crystal
oscillator source. when using 24M, need to divide 24M into 32K.
- description: RTC module accesses the clock of the apb bus.
clock-names:
items:
- const: osc
- const: sys
interrupts:
maxItems: 1
required:
- compatible
- reg
- clocks
- clock-names
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
apb {
#address-cells = <2>;
#size-cells = <2>;
rtc@8e600 {
compatible = "amlogic,a4-rtc";
reg = <0x0 0x8e600 0x0 0x38>;
clocks = <&xtal_32k>, <&clkc_periphs 1>;
clock-names = "osc", "sys";
interrupts = <GIC_SPI 131 IRQ_TYPE_EDGE_RISING>;
};
};

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/rtc/microchip,mfps-rtc.yaml# $id: http://devicetree.org/schemas/rtc/microchip,mpfs-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
@ -12,12 +12,14 @@ allOf:
maintainers: maintainers:
- Daire McNamara <daire.mcnamara@microchip.com> - Daire McNamara <daire.mcnamara@microchip.com>
- Lewis Hanly <lewis.hanly@microchip.com>
properties: properties:
compatible: compatible:
enum: oneOf:
- microchip,mpfs-rtc - items:
- const: microchip,pic64gx-rtc
- const: microchip,mpfs-rtc
- const: microchip,mpfs-rtc
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -0,0 +1,84 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/renesas,rz-rtca3.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RTCA-3 Real Time Clock
maintainers:
- Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
items:
- enum:
- renesas,r9a08g045-rtca3 # RZ/G3S
- const: renesas,rz-rtca3
reg:
maxItems: 1
interrupts:
items:
- description: Alarm interrupt
- description: Periodic interrupt
- description: Carry interrupt
interrupt-names:
items:
- const: alarm
- const: period
- const: carry
clocks:
items:
- description: RTC bus clock
- description: RTC counter clock
clock-names:
items:
- const: bus
- const: counter
power-domains:
maxItems: 1
resets:
items:
- description: VBATTB module reset
required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- power-domains
- resets
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r9a08g045-cpg.h>
#include <dt-bindings/clock/renesas,r9a08g045-vbattb.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
rtc@1004ec00 {
compatible = "renesas,r9a08g045-rtca3", "renesas,rz-rtca3";
reg = <0x1004ec00 0x400>;
interrupts = <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "alarm", "period", "carry";
clocks = <&cpg CPG_MOD R9A08G045_VBAT_BCLK>, <&vbattclk VBATTB_VBATTCLK>;
clock-names = "bus", "counter";
power-domains = <&cpg>;
resets = <&cpg R9A08G045_VBAT_BRESETN>;
};

View File

@ -1218,6 +1218,14 @@ F: Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml
F: drivers/perf/amlogic/ F: drivers/perf/amlogic/
F: include/soc/amlogic/ F: include/soc/amlogic/
AMLOGIC RTC DRIVER
M: Yiting Deng <yiting.deng@amlogic.com>
M: Xianwei Zhao <xianwei.zhao@amlogic.com>
L: linux-amlogic@lists.infradead.org
S: Maintained
F: Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
F: drivers/rtc/rtc-amlogic-a4.c
AMPHENOL CHIPCAP 2 HUMIDITY-TEMPERATURE IIO DRIVER AMPHENOL CHIPCAP 2 HUMIDITY-TEMPERATURE IIO DRIVER
M: Javier Carrasco <javier.carrasco.cruz@gmail.com> M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
L: linux-hwmon@vger.kernel.org L: linux-hwmon@vger.kernel.org
@ -13794,6 +13802,7 @@ F: Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml
F: drivers/input/misc/88pm886-onkey.c F: drivers/input/misc/88pm886-onkey.c
F: drivers/mfd/88pm886.c F: drivers/mfd/88pm886.c
F: drivers/regulator/88pm886-regulator.c F: drivers/regulator/88pm886-regulator.c
F: drivers/rtc/rtc-88pm886.c
F: include/linux/mfd/88pm886.h F: include/linux/mfd/88pm886.h
MARVELL ARMADA 3700 PHY DRIVERS MARVELL ARMADA 3700 PHY DRIVERS
@ -19915,6 +19924,14 @@ S: Supported
F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml
F: drivers/counter/rz-mtu3-cnt.c F: drivers/counter/rz-mtu3-cnt.c
RENESAS RTCA-3 RTC DRIVER
M: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
L: linux-rtc@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
F: drivers/rtc/rtc-renesas-rtca3.c
RENESAS RZ/N1 A5PSW SWITCH DRIVER RENESAS RZ/N1 A5PSW SWITCH DRIVER
M: Clément Léger <clement.leger@bootlin.com> M: Clément Léger <clement.leger@bootlin.com>
L: linux-renesas-soc@vger.kernel.org L: linux-renesas-soc@vger.kernel.org

View File

@ -503,6 +503,7 @@ CONFIG_UHID=m
# CONFIG_USB_SUPPORT is not set # CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set # CONFIG_RTC_NVMEM is not set
CONFIG_RTC_DRV_M48T59=m
CONFIG_RTC_DRV_MSM6242=m CONFIG_RTC_DRV_MSM6242=m
CONFIG_RTC_DRV_RP5C01=m CONFIG_RTC_DRV_RP5C01=m
CONFIG_RTC_DRV_GENERIC=m CONFIG_RTC_DRV_GENERIC=m

View File

@ -391,6 +391,7 @@ CONFIG_UHID=m
# CONFIG_USB_SUPPORT is not set # CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set # CONFIG_RTC_NVMEM is not set
CONFIG_RTC_DRV_M48T59=y
CONFIG_RTC_DRV_GENERIC=m CONFIG_RTC_DRV_GENERIC=m
# CONFIG_VIRTIO_MENU is not set # CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set # CONFIG_VHOST_MENU is not set

View File

@ -392,6 +392,7 @@ CONFIG_UHID=m
# CONFIG_USB_SUPPORT is not set # CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set # CONFIG_RTC_NVMEM is not set
CONFIG_RTC_DRV_M48T59=y
CONFIG_RTC_DRV_GENERIC=m CONFIG_RTC_DRV_GENERIC=m
# CONFIG_VIRTIO_MENU is not set # CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set # CONFIG_VHOST_MENU is not set

View File

@ -4,24 +4,7 @@
#include <asm/irq.h> #include <asm/irq.h>
typedef struct { #define MVME147_RTC_BASE 0xfffe0000
unsigned char
ctrl,
bcd_sec,
bcd_min,
bcd_hr,
bcd_dow,
bcd_dom,
bcd_mth,
bcd_year;
} MK48T02;
#define RTC_WRITE 0x80
#define RTC_READ 0x40
#define RTC_STOP 0x20
#define m147_rtc ((MK48T02 * volatile)0xfffe07f8)
struct pcc_regs { struct pcc_regs {
volatile u_long dma_tadr; volatile u_long dma_tadr;

View File

@ -24,23 +24,7 @@ typedef struct {
#define mvmelp ((*(volatile MVMElpPtr)(MVME_LPR_BASE))) #define mvmelp ((*(volatile MVMElpPtr)(MVME_LPR_BASE)))
typedef struct { #define MVME_RTC_BASE 0xfffc0000
unsigned char
ctrl,
bcd_sec,
bcd_min,
bcd_hr,
bcd_dow,
bcd_dom,
bcd_mth,
bcd_year;
} MK48T08_t, *MK48T08ptr_t;
#define RTC_WRITE 0x80
#define RTC_READ 0x40
#define RTC_STOP 0x20
#define MVME_RTC_BASE 0xfffc1ff8
#define MVME_I596_BASE 0xfff46000 #define MVME_I596_BASE 0xfff46000

View File

@ -19,8 +19,9 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/rtc.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/rtc/m48t59.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/bootinfo-vme.h> #include <asm/bootinfo-vme.h>
@ -36,13 +37,9 @@
static void mvme147_get_model(char *model); static void mvme147_get_model(char *model);
static void __init mvme147_sched_init(void); static void __init mvme147_sched_init(void);
extern int mvme147_hwclk (int, struct rtc_time *);
extern void mvme147_reset (void); extern void mvme147_reset (void);
static int bcd2int (unsigned char b);
int __init mvme147_parse_bootinfo(const struct bi_record *bi) int __init mvme147_parse_bootinfo(const struct bi_record *bi)
{ {
uint16_t tag = be16_to_cpu(bi->tag); uint16_t tag = be16_to_cpu(bi->tag);
@ -80,7 +77,6 @@ void __init config_mvme147(void)
{ {
mach_sched_init = mvme147_sched_init; mach_sched_init = mvme147_sched_init;
mach_init_IRQ = mvme147_init_IRQ; mach_init_IRQ = mvme147_init_IRQ;
mach_hwclk = mvme147_hwclk;
mach_reset = mvme147_reset; mach_reset = mvme147_reset;
mach_get_model = mvme147_get_model; mach_get_model = mvme147_get_model;
@ -89,6 +85,28 @@ void __init config_mvme147(void)
vme_brdtype = VME_TYPE_MVME147; vme_brdtype = VME_TYPE_MVME147;
} }
static struct resource m48t59_rsrc[] = {
DEFINE_RES_MEM(MVME147_RTC_BASE, 0x800),
};
static struct m48t59_plat_data m48t59_data = {
.type = M48T59RTC_TYPE_M48T02,
.yy_offset = 70,
};
static int __init mvme147_platform_init(void)
{
if (!MACH_IS_MVME147)
return 0;
platform_device_register_resndata(NULL, "rtc-m48t59", -1,
m48t59_rsrc, ARRAY_SIZE(m48t59_rsrc),
&m48t59_data, sizeof(m48t59_data));
return 0;
}
arch_initcall(mvme147_platform_init);
static u64 mvme147_read_clk(struct clocksource *cs); static u64 mvme147_read_clk(struct clocksource *cs);
static struct clocksource mvme147_clk = { static struct clocksource mvme147_clk = {
@ -162,31 +180,6 @@ static u64 mvme147_read_clk(struct clocksource *cs)
return ticks; return ticks;
} }
static int bcd2int (unsigned char b)
{
return ((b>>4)*10 + (b&15));
}
int mvme147_hwclk(int op, struct rtc_time *t)
{
if (!op) {
m147_rtc->ctrl = RTC_READ;
t->tm_year = bcd2int (m147_rtc->bcd_year);
t->tm_mon = bcd2int(m147_rtc->bcd_mth) - 1;
t->tm_mday = bcd2int (m147_rtc->bcd_dom);
t->tm_hour = bcd2int (m147_rtc->bcd_hr);
t->tm_min = bcd2int (m147_rtc->bcd_min);
t->tm_sec = bcd2int (m147_rtc->bcd_sec);
m147_rtc->ctrl = 0;
if (t->tm_year < 70)
t->tm_year += 100;
} else {
/* FIXME Setting the time is not yet supported */
return -EOPNOTSUPP;
}
return 0;
}
static void scc_delay(void) static void scc_delay(void)
{ {
__asm__ __volatile__ ("nop; nop;"); __asm__ __volatile__ ("nop; nop;");

View File

@ -3,4 +3,4 @@
# Makefile for Linux arch/m68k/mvme16x source directory # Makefile for Linux arch/m68k/mvme16x source directory
# #
obj-y := config.o rtc.o obj-y := config.o

View File

@ -21,9 +21,10 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/rtc.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc/m48t59.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/bootinfo-vme.h> #include <asm/bootinfo-vme.h>
@ -39,16 +40,10 @@
extern t_bdid mvme_bdid; extern t_bdid mvme_bdid;
static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
static void mvme16x_get_model(char *model); static void mvme16x_get_model(char *model);
extern void mvme16x_sched_init(void); extern void mvme16x_sched_init(void);
extern int mvme16x_hwclk (int, struct rtc_time *);
extern void mvme16x_reset (void); extern void mvme16x_reset (void);
int bcd2int (unsigned char b);
unsigned short mvme16x_config; unsigned short mvme16x_config;
EXPORT_SYMBOL(mvme16x_config); EXPORT_SYMBOL(mvme16x_config);
@ -268,7 +263,6 @@ void __init config_mvme16x(void)
mach_sched_init = mvme16x_sched_init; mach_sched_init = mvme16x_sched_init;
mach_init_IRQ = mvme16x_init_IRQ; mach_init_IRQ = mvme16x_init_IRQ;
mach_hwclk = mvme16x_hwclk;
mach_reset = mvme16x_reset; mach_reset = mvme16x_reset;
mach_get_model = mvme16x_get_model; mach_get_model = mvme16x_get_model;
mach_get_hardware_list = mvme16x_get_hardware_list; mach_get_hardware_list = mvme16x_get_hardware_list;
@ -312,6 +306,28 @@ void __init config_mvme16x(void)
} }
} }
static struct resource m48t59_rsrc[] = {
DEFINE_RES_MEM(MVME_RTC_BASE, 0x2000),
};
static struct m48t59_plat_data m48t59_data = {
.type = M48T59RTC_TYPE_M48T08,
.yy_offset = 70,
};
static int __init mvme16x_platform_init(void)
{
if (!MACH_IS_MVME16x)
return 0;
platform_device_register_resndata(NULL, "rtc-m48t59", -1,
m48t59_rsrc, ARRAY_SIZE(m48t59_rsrc),
&m48t59_data, sizeof(m48t59_data));
return 0;
}
arch_initcall(mvme16x_platform_init);
static irqreturn_t mvme16x_abort_int (int irq, void *dev_id) static irqreturn_t mvme16x_abort_int (int irq, void *dev_id)
{ {
unsigned long *new = (unsigned long *)vectors; unsigned long *new = (unsigned long *)vectors;
@ -426,28 +442,3 @@ static u64 mvme16x_read_clk(struct clocksource *cs)
return ticks; return ticks;
} }
int bcd2int (unsigned char b)
{
return ((b>>4)*10 + (b&15));
}
int mvme16x_hwclk(int op, struct rtc_time *t)
{
if (!op) {
rtc->ctrl = RTC_READ;
t->tm_year = bcd2int (rtc->bcd_year);
t->tm_mon = bcd2int(rtc->bcd_mth) - 1;
t->tm_mday = bcd2int (rtc->bcd_dom);
t->tm_hour = bcd2int (rtc->bcd_hr);
t->tm_min = bcd2int (rtc->bcd_min);
t->tm_sec = bcd2int (rtc->bcd_sec);
rtc->ctrl = 0;
if (t->tm_year < 70)
t->tm_year += 100;
} else {
/* FIXME Setting the time is not yet supported */
return -EOPNOTSUPP;
}
return 0;
}

View File

@ -1,165 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Real Time Clock interface for Linux on the MVME16x
*
* Based on the PC driver by Paul Gortmaker.
*/
#define RTC_VERSION "1.00"
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/capability.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/rtc.h> /* For struct rtc_time and ioctls, etc */
#include <linux/bcd.h>
#include <asm/mvme16xhw.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <asm/setup.h>
/*
* We sponge a minor off of the misc major. No need slurping
* up another valuable major dev number for this. If you add
* an ioctl, make sure you don't conflict with SPARC's RTC
* ioctls.
*/
static const unsigned char days_in_mo[] =
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static atomic_t rtc_ready = ATOMIC_INIT(1);
static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
volatile MK48T08ptr_t rtc = (MK48T08ptr_t)MVME_RTC_BASE;
unsigned long flags;
struct rtc_time wtime;
void __user *argp = (void __user *)arg;
switch (cmd) {
case RTC_RD_TIME: /* Read the time/date from RTC */
{
local_irq_save(flags);
/* Ensure clock and real-time-mode-register are accessible */
rtc->ctrl = RTC_READ;
memset(&wtime, 0, sizeof(struct rtc_time));
wtime.tm_sec = bcd2bin(rtc->bcd_sec);
wtime.tm_min = bcd2bin(rtc->bcd_min);
wtime.tm_hour = bcd2bin(rtc->bcd_hr);
wtime.tm_mday = bcd2bin(rtc->bcd_dom);
wtime.tm_mon = bcd2bin(rtc->bcd_mth)-1;
wtime.tm_year = bcd2bin(rtc->bcd_year);
if (wtime.tm_year < 70)
wtime.tm_year += 100;
wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
rtc->ctrl = 0;
local_irq_restore(flags);
return copy_to_user(argp, &wtime, sizeof wtime) ?
-EFAULT : 0;
}
case RTC_SET_TIME: /* Set the RTC */
{
struct rtc_time rtc_tm;
unsigned char mon, day, hrs, min, sec, leap_yr;
unsigned int yrs;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time)))
return -EFAULT;
yrs = rtc_tm.tm_year;
if (yrs < 1900)
yrs += 1900;
mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
day = rtc_tm.tm_mday;
hrs = rtc_tm.tm_hour;
min = rtc_tm.tm_min;
sec = rtc_tm.tm_sec;
leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
if ((mon > 12) || (day == 0))
return -EINVAL;
if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
return -EINVAL;
if ((hrs >= 24) || (min >= 60) || (sec >= 60))
return -EINVAL;
if (yrs >= 2070)
return -EINVAL;
local_irq_save(flags);
rtc->ctrl = RTC_WRITE;
rtc->bcd_sec = bin2bcd(sec);
rtc->bcd_min = bin2bcd(min);
rtc->bcd_hr = bin2bcd(hrs);
rtc->bcd_dom = bin2bcd(day);
rtc->bcd_mth = bin2bcd(mon);
rtc->bcd_year = bin2bcd(yrs%100);
rtc->ctrl = 0;
local_irq_restore(flags);
return 0;
}
default:
return -EINVAL;
}
}
/*
* We enforce only one user at a time here with the open/close.
*/
static int rtc_open(struct inode *inode, struct file *file)
{
if( !atomic_dec_and_test(&rtc_ready) )
{
atomic_inc( &rtc_ready );
return -EBUSY;
}
return 0;
}
static int rtc_release(struct inode *inode, struct file *file)
{
atomic_inc( &rtc_ready );
return 0;
}
/*
* The various file operations we support.
*/
static const struct file_operations rtc_fops = {
.unlocked_ioctl = rtc_ioctl,
.open = rtc_open,
.release = rtc_release,
.llseek = noop_llseek,
};
static struct miscdevice rtc_dev=
{
.minor = RTC_MINOR,
.name = "rtc",
.fops = &rtc_fops
};
static int __init rtc_MK48T08_init(void)
{
if (!MACH_IS_MVME16x)
return -ENODEV;
pr_info("MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
return misc_register(&rtc_dev);
}
device_initcall(rtc_MK48T08_init);

View File

@ -255,6 +255,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
static struct m48t59_plat_data m48t59_data = { static struct m48t59_plat_data m48t59_data = {
.read_byte = mostek_read_byte, .read_byte = mostek_read_byte,
.write_byte = mostek_write_byte, .write_byte = mostek_write_byte,
.yy_offset = 68,
}; };
/* resource is set at runtime */ /* resource is set at runtime */

View File

@ -544,6 +544,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
static struct m48t59_plat_data m48t59_data = { static struct m48t59_plat_data m48t59_data = {
.read_byte = mostek_read_byte, .read_byte = mostek_read_byte,
.write_byte = mostek_write_byte, .write_byte = mostek_write_byte,
.yy_offset = 68,
}; };
static struct platform_device m48t59_rtc = { static struct platform_device m48t59_rtc = {

View File

@ -182,6 +182,16 @@ config RTC_DRV_88PM80X
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-88pm80x. will be called rtc-88pm80x.
config RTC_DRV_88PM886
tristate "Marvell 88PM886 RTC driver"
depends on MFD_88PM886_PMIC
help
If you say yes here you will get support for the RTC function in the
Marvell 88PM886 chip.
This driver can also be built as a module. If so, the module
will be called rtc-88pm886.
config RTC_DRV_ABB5ZES3 config RTC_DRV_ABB5ZES3
select REGMAP_I2C select REGMAP_I2C
tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3" tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
@ -496,6 +506,7 @@ config RTC_DRV_PCF85363
config RTC_DRV_PCF8563 config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564" tristate "Philips PCF8563/Epson RTC8564"
select REGMAP_I2C
help help
If you say yes here you get support for the If you say yes here you get support for the
Philips PCF8563 RTC chip. The Epson RTC8564 Philips PCF8563 RTC chip. The Epson RTC8564
@ -2005,6 +2016,16 @@ config RTC_DRV_MA35D1
This driver can also be built as a module, if so, the module This driver can also be built as a module, if so, the module
will be called "rtc-ma35d1". will be called "rtc-ma35d1".
config RTC_DRV_RENESAS_RTCA3
tristate "Renesas RTCA-3 RTC"
depends on ARCH_RENESAS
help
If you say yes here you get support for the Renesas RTCA-3 RTC
available on the Renesas RZ/G3S SoC.
This driver can also be built as a module, if so, the module
will be called "rtc-rtca3".
comment "HID Sensor RTC drivers" comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME config RTC_DRV_HID_SENSOR_TIME
@ -2070,4 +2091,16 @@ config RTC_DRV_SSD202D
This driver can also be built as a module, if so, the module This driver can also be built as a module, if so, the module
will be called "rtc-ssd20xd". will be called "rtc-ssd20xd".
config RTC_DRV_AMLOGIC_A4
tristate "Amlogic RTC"
depends on ARCH_MESON || COMPILE_TEST
select REGMAP_MMIO
default y
help
If you say yes here you get support for the RTC block on the
Amlogic A113L2(A4) and A113X2(A5) SoCs.
This driver can also be built as a module. If so, the module
will be called "rtc-amlogic-a4".
endif # RTC_CLASS endif # RTC_CLASS

View File

@ -21,11 +21,13 @@ obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o
obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_88PM886) += rtc-88pm886.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABEOZ9) += rtc-ab-eoz9.o obj-$(CONFIG_RTC_DRV_ABEOZ9) += rtc-ab-eoz9.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
obj-$(CONFIG_RTC_DRV_AMLOGIC_A4) += rtc-amlogic-a4.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
@ -158,13 +160,14 @@ obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8111) += rtc-rx8111.o obj-$(CONFIG_RTC_DRV_RX8111) += rtc-rx8111.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o
obj-$(CONFIG_RTC_DRV_RENESAS_RTCA3) += rtc-renesas-rtca3.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o

View File

@ -904,13 +904,18 @@ void rtc_timer_do_work(struct work_struct *work)
struct timerqueue_node *next; struct timerqueue_node *next;
ktime_t now; ktime_t now;
struct rtc_time tm; struct rtc_time tm;
int err;
struct rtc_device *rtc = struct rtc_device *rtc =
container_of(work, struct rtc_device, irqwork); container_of(work, struct rtc_device, irqwork);
mutex_lock(&rtc->ops_lock); mutex_lock(&rtc->ops_lock);
again: again:
__rtc_read_time(rtc, &tm); err = __rtc_read_time(rtc, &tm);
if (err) {
mutex_unlock(&rtc->ops_lock);
return;
}
now = rtc_tm_to_ktime(tm); now = rtc_tm_to_ktime(tm);
while ((next = timerqueue_getnext(&rtc->timerqueue))) { while ((next = timerqueue_getnext(&rtc->timerqueue))) {
if (next->expires > now) if (next->expires > now)

View File

@ -329,7 +329,7 @@ static struct platform_driver pm80x_rtc_driver = {
.pm = &pm80x_rtc_pm_ops, .pm = &pm80x_rtc_pm_ops,
}, },
.probe = pm80x_rtc_probe, .probe = pm80x_rtc_probe,
.remove_new = pm80x_rtc_remove, .remove = pm80x_rtc_remove,
}; };
module_platform_driver(pm80x_rtc_driver); module_platform_driver(pm80x_rtc_driver);

View File

@ -371,7 +371,7 @@ static struct platform_driver pm860x_rtc_driver = {
.pm = &pm860x_rtc_pm_ops, .pm = &pm860x_rtc_pm_ops,
}, },
.probe = pm860x_rtc_probe, .probe = pm860x_rtc_probe,
.remove_new = pm860x_rtc_remove, .remove = pm860x_rtc_remove,
}; };
module_platform_driver(pm860x_rtc_driver); module_platform_driver(pm860x_rtc_driver);

97
drivers/rtc/rtc-88pm886.c Normal file
View File

@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/limits.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/mfd/88pm886.h>
/*
* Time is calculated as the sum of a 32-bit read-only advancing counter and a
* writeable constant offset stored in the chip's spare registers.
*/
static int pm886_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct regmap *regmap = dev_get_drvdata(dev);
u32 time;
u32 buf;
int ret;
ret = regmap_bulk_read(regmap, PM886_REG_RTC_SPARE1, &buf, 4);
if (ret)
return ret;
time = buf;
ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4);
if (ret)
return ret;
time += buf;
rtc_time64_to_tm(time, tm);
return 0;
}
static int pm886_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct regmap *regmap = dev_get_drvdata(dev);
u32 buf;
int ret;
ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4);
if (ret)
return ret;
buf = rtc_tm_to_time64(tm) - buf;
return regmap_bulk_write(regmap, PM886_REG_RTC_SPARE1, &buf, 4);
}
static const struct rtc_class_ops pm886_rtc_ops = {
.read_time = pm886_rtc_read_time,
.set_time = pm886_rtc_set_time,
};
static int pm886_rtc_probe(struct platform_device *pdev)
{
struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct rtc_device *rtc;
int ret;
platform_set_drvdata(pdev, chip->regmap);
rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc))
return dev_err_probe(dev, PTR_ERR(rtc),
"Failed to allocate RTC device\n");
rtc->ops = &pm886_rtc_ops;
rtc->range_max = U32_MAX;
ret = devm_rtc_register_device(rtc);
if (ret)
return dev_err_probe(dev, ret, "Failed to register RTC device\n");
return 0;
}
static const struct platform_device_id pm886_rtc_id_table[] = {
{ "88pm886-rtc", },
{ }
};
MODULE_DEVICE_TABLE(platform, pm886_rtc_id_table);
static struct platform_driver pm886_rtc_driver = {
.driver = {
.name = "88pm886-rtc",
},
.probe = pm886_rtc_probe,
.id_table = pm886_rtc_id_table,
};
module_platform_driver(pm886_rtc_driver);
MODULE_DESCRIPTION("Marvell 88PM886 RTC driver");
MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>");
MODULE_LICENSE("GPL");

View File

@ -64,7 +64,7 @@
#define ABEOZ9_BIT_ALARM_MIN GENMASK(6, 0) #define ABEOZ9_BIT_ALARM_MIN GENMASK(6, 0)
#define ABEOZ9_REG_ALARM_HOURS 0x12 #define ABEOZ9_REG_ALARM_HOURS 0x12
#define ABEOZ9_BIT_ALARM_HOURS_PM BIT(5) #define ABEOZ9_BIT_ALARM_HOURS_PM BIT(5)
#define ABEOZ9_BIT_ALARM_HOURS GENMASK(4, 0) #define ABEOZ9_BIT_ALARM_HOURS GENMASK(5, 0)
#define ABEOZ9_REG_ALARM_DAYS 0x13 #define ABEOZ9_REG_ALARM_DAYS 0x13
#define ABEOZ9_BIT_ALARM_DAYS GENMASK(5, 0) #define ABEOZ9_BIT_ALARM_DAYS GENMASK(5, 0)
#define ABEOZ9_REG_ALARM_WEEKDAYS 0x14 #define ABEOZ9_REG_ALARM_WEEKDAYS 0x14
@ -231,8 +231,6 @@ static int abeoz9_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
alarm->time.tm_sec = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_SEC, regs[0])); alarm->time.tm_sec = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_SEC, regs[0]));
alarm->time.tm_min = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_MIN, regs[1])); alarm->time.tm_min = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_MIN, regs[1]));
alarm->time.tm_hour = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_HOURS, regs[2])); alarm->time.tm_hour = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_HOURS, regs[2]));
if (FIELD_GET(ABEOZ9_BIT_ALARM_HOURS_PM, regs[2]))
alarm->time.tm_hour += 12;
alarm->time.tm_mday = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_DAYS, regs[3])); alarm->time.tm_mday = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_DAYS, regs[3]));
@ -396,13 +394,6 @@ static int abeoz9z3_temp_read(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; return ret;
if ((val & ABEOZ9_REG_CTRL_STATUS_V1F) ||
(val & ABEOZ9_REG_CTRL_STATUS_V2F)) {
dev_err(dev,
"thermometer might be disabled due to low voltage\n");
return -EINVAL;
}
switch (attr) { switch (attr) {
case hwmon_temp_input: case hwmon_temp_input:
ret = regmap_read(regmap, ABEOZ9_REG_REG_TEMP, &val); ret = regmap_read(regmap, ABEOZ9_REG_REG_TEMP, &val);

View File

@ -403,7 +403,7 @@ static struct platform_driver ab8500_rtc_driver = {
.name = "ab8500-rtc", .name = "ab8500-rtc",
}, },
.probe = ab8500_rtc_probe, .probe = ab8500_rtc_probe,
.remove_new = ab8500_rtc_remove, .remove = ab8500_rtc_remove,
.id_table = ab85xx_rtc_ids, .id_table = ab85xx_rtc_ids,
}; };

View File

@ -39,7 +39,7 @@
#define ABX8XX_REG_STATUS 0x0f #define ABX8XX_REG_STATUS 0x0f
#define ABX8XX_STATUS_AF BIT(2) #define ABX8XX_STATUS_AF BIT(2)
#define ABX8XX_STATUS_BLF BIT(4) #define ABX8XX_STATUS_BLF BIT(4)
#define ABX8XX_STATUS_WDT BIT(6) #define ABX8XX_STATUS_WDT BIT(5)
#define ABX8XX_REG_CTRL1 0x10 #define ABX8XX_REG_CTRL1 0x10
#define ABX8XX_CTRL_WRITE BIT(0) #define ABX8XX_CTRL_WRITE BIT(0)

View File

@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, ac100_rtc_match);
static struct platform_driver ac100_rtc_driver = { static struct platform_driver ac100_rtc_driver = {
.probe = ac100_rtc_probe, .probe = ac100_rtc_probe,
.remove_new = ac100_rtc_remove, .remove = ac100_rtc_remove,
.driver = { .driver = {
.name = "ac100-rtc", .name = "ac100-rtc",
.of_match_table = of_match_ptr(ac100_rtc_match), .of_match_table = of_match_ptr(ac100_rtc_match),

View File

@ -0,0 +1,465 @@
// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
/*
* Copyright (C) 2024 Amlogic, Inc. All rights reserved
* Author: Yiting Deng <yiting.deng@amlogic.com>
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/time64.h>
/* rtc oscillator rate */
#define OSC_32K 32768
#define OSC_24M 24000000
#define RTC_CTRL (0x0 << 2) /* Control RTC */
#define RTC_ALRM0_EN BIT(0)
#define RTC_OSC_SEL BIT(8)
#define RTC_ENABLE BIT(12)
#define RTC_COUNTER_REG (0x1 << 2) /* Program RTC counter initial value */
#define RTC_ALARM0_REG (0x2 << 2) /* Program RTC alarm0 value */
#define RTC_SEC_ADJUST_REG (0x6 << 2) /* Control second-based timing adjustment */
#define RTC_MATCH_COUNTER GENMASK(18, 0)
#define RTC_SEC_ADJUST_CTRL GENMASK(20, 19)
#define RTC_ADJ_VALID BIT(23)
#define RTC_INT_MASK (0x8 << 2) /* RTC interrupt mask */
#define RTC_ALRM0_IRQ_MSK BIT(0)
#define RTC_INT_CLR (0x9 << 2) /* Clear RTC interrupt */
#define RTC_ALRM0_IRQ_CLR BIT(0)
#define RTC_OSCIN_CTRL0 (0xa << 2) /* Control RTC clk from 24M */
#define RTC_OSCIN_CTRL1 (0xb << 2) /* Control RTC clk from 24M */
#define RTC_OSCIN_IN_EN BIT(31)
#define RTC_OSCIN_OUT_CFG GENMASK(29, 28)
#define RTC_OSCIN_OUT_N0M0 GENMASK(11, 0)
#define RTC_OSCIN_OUT_N1M1 GENMASK(23, 12)
#define RTC_INT_STATUS (0xc << 2) /* RTC interrupt status */
#define RTC_ALRM0_IRQ_STATUS BIT(0)
#define RTC_REAL_TIME (0xd << 2) /* RTC time value */
#define RTC_OSCIN_OUT_32K_N0 0x2dc
#define RTC_OSCIN_OUT_32K_N1 0x2db
#define RTC_OSCIN_OUT_32K_M0 0x1
#define RTC_OSCIN_OUT_32K_M1 0x2
#define RTC_SWALLOW_SECOND 0x2
#define RTC_INSERT_SECOND 0x3
struct aml_rtc_config {
bool gray_stored;
};
struct aml_rtc_data {
struct regmap *map;
struct rtc_device *rtc_dev;
int irq;
struct clk *rtc_clk;
struct clk *sys_clk;
int rtc_enabled;
const struct aml_rtc_config *config;
};
static const struct regmap_config aml_rtc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = RTC_REAL_TIME,
};
static inline u32 gray_to_binary(u32 gray)
{
u32 bcd = gray;
int size = sizeof(bcd) * 8;
int i;
for (i = 0; (1 << i) < size; i++)
bcd ^= bcd >> (1 << i);
return bcd;
}
static inline u32 binary_to_gray(u32 bcd)
{
return bcd ^ (bcd >> 1);
}
static int aml_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
u32 time_sec;
/* if RTC disabled, read time failed */
if (!rtc->rtc_enabled)
return -EINVAL;
regmap_read(rtc->map, RTC_REAL_TIME, &time_sec);
if (rtc->config->gray_stored)
time_sec = gray_to_binary(time_sec);
rtc_time64_to_tm(time_sec, tm);
dev_dbg(dev, "%s: read time = %us\n", __func__, time_sec);
return 0;
}
static int aml_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
u32 time_sec;
/* if RTC disabled, first enable it */
if (!rtc->rtc_enabled) {
regmap_write_bits(rtc->map, RTC_CTRL, RTC_ENABLE, RTC_ENABLE);
usleep_range(100, 200);
rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE);
if (!rtc->rtc_enabled)
return -EINVAL;
}
time_sec = rtc_tm_to_time64(tm);
if (rtc->config->gray_stored)
time_sec = binary_to_gray(time_sec);
regmap_write(rtc->map, RTC_COUNTER_REG, time_sec);
dev_dbg(dev, "%s: set time = %us\n", __func__, time_sec);
return 0;
}
static int aml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
time64_t alarm_sec;
/* if RTC disabled, set alarm failed */
if (!rtc->rtc_enabled)
return -EINVAL;
regmap_update_bits(rtc->map, RTC_CTRL,
RTC_ALRM0_EN, RTC_ALRM0_EN);
regmap_update_bits(rtc->map, RTC_INT_MASK,
RTC_ALRM0_IRQ_MSK, 0);
alarm_sec = rtc_tm_to_time64(&alarm->time);
if (rtc->config->gray_stored)
alarm_sec = binary_to_gray(alarm_sec);
regmap_write(rtc->map, RTC_ALARM0_REG, alarm_sec);
dev_dbg(dev, "%s: alarm->enabled=%d alarm_set=%llds\n", __func__,
alarm->enabled, alarm_sec);
return 0;
}
static int aml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
u32 alarm_sec;
int alarm_enable;
int alarm_mask;
/* if RTC disabled, read alarm failed */
if (!rtc->rtc_enabled)
return -EINVAL;
regmap_read(rtc->map, RTC_ALARM0_REG, &alarm_sec);
if (rtc->config->gray_stored)
alarm_sec = gray_to_binary(alarm_sec);
rtc_time64_to_tm(alarm_sec, &alarm->time);
alarm_enable = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN);
alarm_mask = regmap_test_bits(rtc->map, RTC_INT_MASK, RTC_ALRM0_IRQ_MSK);
alarm->enabled = (alarm_enable && !alarm_mask) ? 1 : 0;
dev_dbg(dev, "%s: alarm->enabled=%d alarm=%us\n", __func__,
alarm->enabled, alarm_sec);
return 0;
}
static int aml_rtc_read_offset(struct device *dev, long *offset)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
u32 reg_val;
long val;
int sign, match_counter, enable;
/* if RTC disabled, read offset failed */
if (!rtc->rtc_enabled)
return -EINVAL;
regmap_read(rtc->map, RTC_SEC_ADJUST_REG, &reg_val);
enable = FIELD_GET(RTC_ADJ_VALID, reg_val);
if (!enable) {
val = 0;
} else {
sign = FIELD_GET(RTC_SEC_ADJUST_CTRL, reg_val);
match_counter = FIELD_GET(RTC_MATCH_COUNTER, reg_val);
val = 1000000000 / (match_counter + 1);
if (sign == RTC_SWALLOW_SECOND)
val = -val;
}
*offset = val;
return 0;
}
static int aml_rtc_set_offset(struct device *dev, long offset)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
int sign = 0;
int match_counter = 0;
int enable = 0;
u32 reg_val;
/* if RTC disabled, set offset failed */
if (!rtc->rtc_enabled)
return -EINVAL;
if (offset) {
enable = 1;
sign = offset < 0 ? RTC_SWALLOW_SECOND : RTC_INSERT_SECOND;
match_counter = 1000000000 / abs(offset) - 1;
if (match_counter < 0 || match_counter > RTC_MATCH_COUNTER)
return -EINVAL;
}
reg_val = FIELD_PREP(RTC_ADJ_VALID, enable) |
FIELD_PREP(RTC_SEC_ADJUST_CTRL, sign) |
FIELD_PREP(RTC_MATCH_COUNTER, match_counter);
regmap_write(rtc->map, RTC_SEC_ADJUST_REG, reg_val);
return 0;
}
static int aml_rtc_alarm_enable(struct device *dev, unsigned int enabled)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
if (enabled) {
regmap_update_bits(rtc->map, RTC_CTRL,
RTC_ALRM0_EN, RTC_ALRM0_EN);
regmap_update_bits(rtc->map, RTC_INT_MASK,
RTC_ALRM0_IRQ_MSK, 0);
} else {
regmap_update_bits(rtc->map, RTC_INT_MASK,
RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK);
regmap_update_bits(rtc->map, RTC_CTRL,
RTC_ALRM0_EN, 0);
}
return 0;
}
static const struct rtc_class_ops aml_rtc_ops = {
.read_time = aml_rtc_read_time,
.set_time = aml_rtc_set_time,
.read_alarm = aml_rtc_read_alarm,
.set_alarm = aml_rtc_set_alarm,
.alarm_irq_enable = aml_rtc_alarm_enable,
.read_offset = aml_rtc_read_offset,
.set_offset = aml_rtc_set_offset,
};
static irqreturn_t aml_rtc_handler(int irq, void *data)
{
struct aml_rtc_data *rtc = (struct aml_rtc_data *)data;
regmap_write(rtc->map, RTC_ALARM0_REG, 0);
regmap_write(rtc->map, RTC_INT_CLR, RTC_ALRM0_IRQ_STATUS);
rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
return IRQ_HANDLED;
}
static void aml_rtc_init(struct aml_rtc_data *rtc)
{
u32 reg_val = 0;
rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE);
if (!rtc->rtc_enabled) {
if (clk_get_rate(rtc->rtc_clk) == OSC_24M) {
/* select 24M oscillator */
regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, RTC_OSC_SEL);
/*
* Set RTC oscillator to freq_out to freq_in/((N0*M0+N1*M1)/(M0+M1))
* Enable clock_in gate of oscillator 24MHz
* Set N0 to 733, N1 to 732
*/
reg_val = FIELD_PREP(RTC_OSCIN_IN_EN, 1)
| FIELD_PREP(RTC_OSCIN_OUT_CFG, 1)
| FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_N0)
| FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_N1);
regmap_write_bits(rtc->map, RTC_OSCIN_CTRL0, RTC_OSCIN_IN_EN
| RTC_OSCIN_OUT_CFG | RTC_OSCIN_OUT_N0M0
| RTC_OSCIN_OUT_N1M1, reg_val);
/* Set M0 to 2, M1 to 3, so freq_out = 32768 Hz*/
reg_val = FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_M0)
| FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_M1);
regmap_write_bits(rtc->map, RTC_OSCIN_CTRL1, RTC_OSCIN_OUT_N0M0
| RTC_OSCIN_OUT_N1M1, reg_val);
} else {
/* select 32K oscillator */
regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, 0);
}
}
regmap_write_bits(rtc->map, RTC_INT_MASK,
RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK);
regmap_write_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN, 0);
}
static int aml_rtc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct aml_rtc_data *rtc;
void __iomem *base;
int ret = 0;
rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->config = of_device_get_match_data(dev);
if (!rtc->config)
return -ENODEV;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base), "resource ioremap failed\n");
rtc->map = devm_regmap_init_mmio(dev, base, &aml_rtc_regmap_config);
if (IS_ERR(rtc->map))
return dev_err_probe(dev, PTR_ERR(rtc->map), "regmap init failed\n");
rtc->irq = platform_get_irq(pdev, 0);
if (rtc->irq < 0)
return rtc->irq;
rtc->rtc_clk = devm_clk_get(dev, "osc");
if (IS_ERR(rtc->rtc_clk))
return dev_err_probe(dev, PTR_ERR(rtc->rtc_clk),
"failed to find rtc clock\n");
if (clk_get_rate(rtc->rtc_clk) != OSC_32K && clk_get_rate(rtc->rtc_clk) != OSC_24M)
return dev_err_probe(dev, -EINVAL, "Invalid clock configuration\n");
rtc->sys_clk = devm_clk_get_enabled(dev, "sys");
if (IS_ERR(rtc->sys_clk))
return dev_err_probe(dev, PTR_ERR(rtc->sys_clk),
"failed to get_enable rtc sys clk\n");
aml_rtc_init(rtc);
device_init_wakeup(dev, 1);
platform_set_drvdata(pdev, rtc);
rtc->rtc_dev = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc->rtc_dev)) {
ret = PTR_ERR(rtc->rtc_dev);
goto err_clk;
}
ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler,
IRQF_ONESHOT, "aml-rtc alarm", rtc);
if (ret) {
dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n",
rtc->irq, ret);
goto err_clk;
}
rtc->rtc_dev->ops = &aml_rtc_ops;
rtc->rtc_dev->range_min = 0;
rtc->rtc_dev->range_max = U32_MAX;
ret = devm_rtc_register_device(rtc->rtc_dev);
if (ret) {
dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret);
goto err_clk;
}
return 0;
err_clk:
clk_disable_unprepare(rtc->sys_clk);
device_init_wakeup(dev, 0);
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int aml_rtc_suspend(struct device *dev)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(rtc->irq);
return 0;
}
static int aml_rtc_resume(struct device *dev)
{
struct aml_rtc_data *rtc = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(rtc->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops,
aml_rtc_suspend, aml_rtc_resume);
static void aml_rtc_remove(struct platform_device *pdev)
{
struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev);
clk_disable_unprepare(rtc->sys_clk);
device_init_wakeup(&pdev->dev, 0);
}
static const struct aml_rtc_config a5_rtc_config = {
};
static const struct aml_rtc_config a4_rtc_config = {
.gray_stored = true,
};
static const struct of_device_id aml_rtc_device_id[] = {
{
.compatible = "amlogic,a4-rtc",
.data = &a4_rtc_config,
},
{
.compatible = "amlogic,a5-rtc",
.data = &a5_rtc_config,
},
{ }
};
MODULE_DEVICE_TABLE(of, aml_rtc_device_id);
static struct platform_driver aml_rtc_driver = {
.probe = aml_rtc_probe,
.remove = aml_rtc_remove,
.driver = {
.name = "aml-rtc",
.pm = &aml_rtc_pm_ops,
.of_match_table = aml_rtc_device_id,
},
};
module_platform_driver(aml_rtc_driver);
MODULE_DESCRIPTION("Amlogic RTC driver");
MODULE_AUTHOR("Yiting Deng <yiting.deng@amlogic.com>");
MODULE_LICENSE("GPL");

View File

@ -325,7 +325,7 @@ MODULE_DEVICE_TABLE(of, asm9260_dt_ids);
static struct platform_driver asm9260_rtc_driver = { static struct platform_driver asm9260_rtc_driver = {
.probe = asm9260_rtc_probe, .probe = asm9260_rtc_probe,
.remove_new = asm9260_rtc_remove, .remove = asm9260_rtc_remove,
.driver = { .driver = {
.name = "asm9260-rtc", .name = "asm9260-rtc",
.of_match_table = asm9260_dt_ids, .of_match_table = asm9260_dt_ids,

View File

@ -640,7 +640,7 @@ static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
* triggering a section mismatch warning. * triggering a section mismatch warning.
*/ */
static struct platform_driver at91_rtc_driver __refdata = { static struct platform_driver at91_rtc_driver __refdata = {
.remove_new = __exit_p(at91_rtc_remove), .remove = __exit_p(at91_rtc_remove),
.shutdown = at91_rtc_shutdown, .shutdown = at91_rtc_shutdown,
.driver = { .driver = {
.name = "at91_rtc", .name = "at91_rtc",

View File

@ -530,7 +530,7 @@ MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
static struct platform_driver at91_rtc_driver = { static struct platform_driver at91_rtc_driver = {
.probe = at91_rtc_probe, .probe = at91_rtc_probe,
.remove_new = at91_rtc_remove, .remove = at91_rtc_remove,
.shutdown = at91_rtc_shutdown, .shutdown = at91_rtc_shutdown,
.driver = { .driver = {
.name = "rtc-at91sam9", .name = "rtc-at91sam9",

View File

@ -17,7 +17,6 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_wakeup.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/stat.h> #include <linux/stat.h>
@ -417,7 +416,7 @@ static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = {
static struct platform_driver brcmstb_waketmr_driver = { static struct platform_driver brcmstb_waketmr_driver = {
.probe = brcmstb_waketmr_probe, .probe = brcmstb_waketmr_probe,
.remove_new = brcmstb_waketmr_remove, .remove = brcmstb_waketmr_remove,
.driver = { .driver = {
.name = "brcmstb-waketimer", .name = "brcmstb-waketimer",
.pm = &brcmstb_waketmr_pm_ops, .pm = &brcmstb_waketmr_pm_ops,

View File

@ -402,7 +402,7 @@ static struct platform_driver cdns_rtc_driver = {
.pm = &cdns_rtc_pm_ops, .pm = &cdns_rtc_pm_ops,
}, },
.probe = cdns_rtc_probe, .probe = cdns_rtc_probe,
.remove_new = cdns_rtc_remove, .remove = cdns_rtc_remove,
}; };
module_platform_driver(cdns_rtc_driver); module_platform_driver(cdns_rtc_driver);

View File

@ -645,18 +645,17 @@ static int cmos_nvram_read(void *priv, unsigned int off, void *val,
unsigned char *buf = val; unsigned char *buf = val;
off += NVRAM_OFFSET; off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock); for (; count; count--, off++, buf++) {
for (; count; count--, off++) { guard(spinlock_irq)(&rtc_lock);
if (off < 128) if (off < 128)
*buf++ = CMOS_READ(off); *buf = CMOS_READ(off);
else if (can_bank2) else if (can_bank2)
*buf++ = cmos_read_bank2(off); *buf = cmos_read_bank2(off);
else else
break; return -EIO;
} }
spin_unlock_irq(&rtc_lock);
return count ? -EIO : 0; return 0;
} }
static int cmos_nvram_write(void *priv, unsigned int off, void *val, static int cmos_nvram_write(void *priv, unsigned int off, void *val,
@ -671,23 +670,23 @@ static int cmos_nvram_write(void *priv, unsigned int off, void *val,
* NVRAM to update, updating checksums is also part of its job. * NVRAM to update, updating checksums is also part of its job.
*/ */
off += NVRAM_OFFSET; off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock); for (; count; count--, off++, buf++) {
for (; count; count--, off++) {
/* don't trash RTC registers */ /* don't trash RTC registers */
if (off == cmos->day_alrm if (off == cmos->day_alrm
|| off == cmos->mon_alrm || off == cmos->mon_alrm
|| off == cmos->century) || off == cmos->century)
buf++; continue;
else if (off < 128)
CMOS_WRITE(*buf++, off);
else if (can_bank2)
cmos_write_bank2(*buf++, off);
else
break;
}
spin_unlock_irq(&rtc_lock);
return count ? -EIO : 0; guard(spinlock_irq)(&rtc_lock);
if (off < 128)
CMOS_WRITE(*buf, off);
else if (can_bank2)
cmos_write_bank2(*buf, off);
else
return -EIO;
}
return 0;
} }
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
@ -1528,7 +1527,7 @@ static void cmos_platform_shutdown(struct platform_device *pdev)
MODULE_ALIAS("platform:rtc_cmos"); MODULE_ALIAS("platform:rtc_cmos");
static struct platform_driver cmos_platform_driver = { static struct platform_driver cmos_platform_driver = {
.remove_new = cmos_platform_remove, .remove = cmos_platform_remove,
.shutdown = cmos_platform_shutdown, .shutdown = cmos_platform_shutdown,
.driver = { .driver = {
.name = driver_name, .name = driver_name,

View File

@ -401,7 +401,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_rtc_id);
static struct platform_driver cros_ec_rtc_driver = { static struct platform_driver cros_ec_rtc_driver = {
.probe = cros_ec_rtc_probe, .probe = cros_ec_rtc_probe,
.remove_new = cros_ec_rtc_remove, .remove = cros_ec_rtc_remove,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.pm = &cros_ec_rtc_pm_ops, .pm = &cros_ec_rtc_pm_ops,

View File

@ -1354,7 +1354,7 @@ static struct platform_driver ds1685_rtc_driver = {
.name = "rtc-ds1685", .name = "rtc-ds1685",
}, },
.probe = ds1685_rtc_probe, .probe = ds1685_rtc_probe,
.remove_new = ds1685_rtc_remove, .remove = ds1685_rtc_remove,
}; };
module_platform_driver(ds1685_rtc_driver); module_platform_driver(ds1685_rtc_driver);
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */

View File

@ -214,7 +214,7 @@ static struct platform_driver ftrtc010_rtc_driver = {
.of_match_table = ftrtc010_rtc_dt_match, .of_match_table = ftrtc010_rtc_dt_match,
}, },
.probe = ftrtc010_rtc_probe, .probe = ftrtc010_rtc_probe,
.remove_new = ftrtc010_rtc_remove, .remove = ftrtc010_rtc_remove,
}; };
module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe); module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);

View File

@ -319,7 +319,7 @@ static struct platform_driver hid_time_platform_driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
}, },
.probe = hid_time_probe, .probe = hid_time_probe,
.remove_new = hid_time_remove, .remove = hid_time_remove,
}; };
module_platform_driver(hid_time_platform_driver); module_platform_driver(hid_time_platform_driver);

View File

@ -860,7 +860,7 @@ static struct platform_driver dryice_rtc_driver __refdata = {
.name = "imxdi_rtc", .name = "imxdi_rtc",
.of_match_table = dryice_dt_ids, .of_match_table = dryice_dt_ids,
}, },
.remove_new = __exit_p(dryice_rtc_remove), .remove = __exit_p(dryice_rtc_remove),
}; };
module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe); module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe);

View File

@ -21,7 +21,7 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
/* ISL register offsets */ /* RTC - Real time clock registers */
#define ISL12022_REG_SC 0x00 #define ISL12022_REG_SC 0x00
#define ISL12022_REG_MN 0x01 #define ISL12022_REG_MN 0x01
#define ISL12022_REG_HR 0x02 #define ISL12022_REG_HR 0x02
@ -30,21 +30,36 @@
#define ISL12022_REG_YR 0x05 #define ISL12022_REG_YR 0x05
#define ISL12022_REG_DW 0x06 #define ISL12022_REG_DW 0x06
/* CSR - Control and status registers */
#define ISL12022_REG_SR 0x07 #define ISL12022_REG_SR 0x07
#define ISL12022_REG_INT 0x08 #define ISL12022_REG_INT 0x08
#define ISL12022_REG_PWR_VBAT 0x0a #define ISL12022_REG_PWR_VBAT 0x0a
#define ISL12022_REG_BETA 0x0d #define ISL12022_REG_BETA 0x0d
/* ALARM - Alarm registers */
#define ISL12022_REG_SCA0 0x10
#define ISL12022_REG_MNA0 0x11
#define ISL12022_REG_HRA0 0x12
#define ISL12022_REG_DTA0 0x13
#define ISL12022_REG_MOA0 0x14
#define ISL12022_REG_DWA0 0x15
#define ISL12022_ALARM ISL12022_REG_SCA0
#define ISL12022_ALARM_LEN (ISL12022_REG_DWA0 - ISL12022_REG_SCA0 + 1)
/* TEMP - Temperature sensor registers */
#define ISL12022_REG_TEMP_L 0x28 #define ISL12022_REG_TEMP_L 0x28
/* ISL register bits */ /* ISL register bits */
#define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */ #define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */
#define ISL12022_SR_ALM (1 << 4)
#define ISL12022_SR_LBAT85 (1 << 2) #define ISL12022_SR_LBAT85 (1 << 2)
#define ISL12022_SR_LBAT75 (1 << 1) #define ISL12022_SR_LBAT75 (1 << 1)
#define ISL12022_INT_ARST (1 << 7)
#define ISL12022_INT_WRTC (1 << 6) #define ISL12022_INT_WRTC (1 << 6)
#define ISL12022_INT_IM (1 << 5)
#define ISL12022_INT_FOBATB (1 << 4)
#define ISL12022_INT_FO_MASK GENMASK(3, 0) #define ISL12022_INT_FO_MASK GENMASK(3, 0)
#define ISL12022_INT_FO_OFF 0x0 #define ISL12022_INT_FO_OFF 0x0
#define ISL12022_INT_FO_32K 0x1 #define ISL12022_INT_FO_32K 0x1
@ -52,8 +67,19 @@
#define ISL12022_REG_VB85_MASK GENMASK(5, 3) #define ISL12022_REG_VB85_MASK GENMASK(5, 3)
#define ISL12022_REG_VB75_MASK GENMASK(2, 0) #define ISL12022_REG_VB75_MASK GENMASK(2, 0)
#define ISL12022_ALARM_ENABLE (1 << 7) /* for all ALARM registers */
#define ISL12022_BETA_TSE (1 << 7) #define ISL12022_BETA_TSE (1 << 7)
static struct i2c_driver isl12022_driver;
struct isl12022 {
struct rtc_device *rtc;
struct regmap *regmap;
int irq;
bool irq_enabled;
};
static umode_t isl12022_hwmon_is_visible(const void *data, static umode_t isl12022_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type, enum hwmon_sensor_types type,
u32 attr, int channel) u32 attr, int channel)
@ -116,7 +142,8 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = {
static void isl12022_hwmon_register(struct device *dev) static void isl12022_hwmon_register(struct device *dev)
{ {
struct regmap *regmap = dev_get_drvdata(dev); struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
struct device *hwmon; struct device *hwmon;
int ret; int ret;
@ -143,8 +170,9 @@ static void isl12022_hwmon_register(struct device *dev)
*/ */
static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
struct regmap *regmap = dev_get_drvdata(dev); struct isl12022 *isl12022 = dev_get_drvdata(dev);
uint8_t buf[ISL12022_REG_INT + 1]; struct regmap *regmap = isl12022->regmap;
u8 buf[ISL12022_REG_INT + 1];
int ret; int ret;
ret = regmap_bulk_read(regmap, ISL12022_REG_SC, buf, sizeof(buf)); ret = regmap_bulk_read(regmap, ISL12022_REG_SC, buf, sizeof(buf));
@ -178,9 +206,10 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
{ {
struct regmap *regmap = dev_get_drvdata(dev); struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
int ret; int ret;
uint8_t buf[ISL12022_REG_DW + 1]; u8 buf[ISL12022_REG_DW + 1];
dev_dbg(dev, "%s: %ptR\n", __func__, tm); dev_dbg(dev, "%s: %ptR\n", __func__, tm);
@ -208,9 +237,198 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf)); return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf));
} }
static int isl12022_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct rtc_time *tm = &alarm->time;
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u8 buf[ISL12022_ALARM_LEN];
unsigned int i, yr;
int ret;
ret = regmap_bulk_read(regmap, ISL12022_ALARM, buf, sizeof(buf));
if (ret) {
dev_dbg(dev, "%s: reading ALARM registers failed\n",
__func__);
return ret;
}
/* The alarm doesn't store the year so get it from the rtc section */
ret = regmap_read(regmap, ISL12022_REG_YR, &yr);
if (ret) {
dev_dbg(dev, "%s: reading YR register failed\n", __func__);
return ret;
}
dev_dbg(dev,
"%s: sc=%02x, mn=%02x, hr=%02x, dt=%02x, mo=%02x, dw=%02x yr=%u\n",
__func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], yr);
tm->tm_sec = bcd2bin(buf[ISL12022_REG_SCA0 - ISL12022_ALARM] & 0x7F);
tm->tm_min = bcd2bin(buf[ISL12022_REG_MNA0 - ISL12022_ALARM] & 0x7F);
tm->tm_hour = bcd2bin(buf[ISL12022_REG_HRA0 - ISL12022_ALARM] & 0x3F);
tm->tm_mday = bcd2bin(buf[ISL12022_REG_DTA0 - ISL12022_ALARM] & 0x3F);
tm->tm_mon = bcd2bin(buf[ISL12022_REG_MOA0 - ISL12022_ALARM] & 0x1F) - 1;
tm->tm_wday = buf[ISL12022_REG_DWA0 - ISL12022_ALARM] & 0x07;
tm->tm_year = bcd2bin(yr) + 100;
for (i = 0; i < ISL12022_ALARM_LEN; i++) {
if (buf[i] & ISL12022_ALARM_ENABLE) {
alarm->enabled = 1;
break;
}
}
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
return 0;
}
static int isl12022_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct rtc_time *alarm_tm = &alarm->time;
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u8 regs[ISL12022_ALARM_LEN] = { 0, };
struct rtc_time rtc_tm;
int ret, enable, dw;
ret = isl12022_rtc_read_time(dev, &rtc_tm);
if (ret)
return ret;
/* If the alarm time is before the current time disable the alarm */
if (!alarm->enabled || rtc_tm_sub(alarm_tm, &rtc_tm) <= 0)
enable = 0;
else
enable = ISL12022_ALARM_ENABLE;
/*
* Set non-matching day of the week to safeguard against early false
* matching while setting all the alarm registers (this rtc lacks a
* general alarm/irq enable/disable bit).
*/
ret = regmap_read(regmap, ISL12022_REG_DW, &dw);
if (ret) {
dev_dbg(dev, "%s: reading DW failed\n", __func__);
return ret;
}
/* ~4 days into the future should be enough to avoid match */
dw = ((dw + 4) % 7) | ISL12022_ALARM_ENABLE;
ret = regmap_write(regmap, ISL12022_REG_DWA0, dw);
if (ret) {
dev_dbg(dev, "%s: writing DWA0 failed\n", __func__);
return ret;
}
/* Program the alarm and enable it for each setting */
regs[ISL12022_REG_SCA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_sec) | enable;
regs[ISL12022_REG_MNA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_min) | enable;
regs[ISL12022_REG_HRA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_hour) | enable;
regs[ISL12022_REG_DTA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mday) | enable;
regs[ISL12022_REG_MOA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mon + 1) | enable;
regs[ISL12022_REG_DWA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_wday & 7) | enable;
/* write ALARM registers */
ret = regmap_bulk_write(regmap, ISL12022_ALARM, &regs, sizeof(regs));
if (ret) {
dev_dbg(dev, "%s: writing ALARM registers failed\n", __func__);
return ret;
}
return 0;
}
static irqreturn_t isl12022_rtc_interrupt(int irq, void *data)
{
struct isl12022 *isl12022 = data;
struct rtc_device *rtc = isl12022->rtc;
struct device *dev = &rtc->dev;
struct regmap *regmap = isl12022->regmap;
u32 val = 0;
unsigned long events = 0;
int ret;
ret = regmap_read(regmap, ISL12022_REG_SR, &val);
if (ret) {
dev_dbg(dev, "%s: reading SR failed\n", __func__);
return IRQ_HANDLED;
}
if (val & ISL12022_SR_ALM)
events |= RTC_IRQF | RTC_AF;
if (events & RTC_AF)
dev_dbg(dev, "alarm!\n");
if (!events)
return IRQ_NONE;
rtc_update_irq(rtc, 1, events);
return IRQ_HANDLED;
}
static int isl12022_rtc_alarm_irq_enable(struct device *dev,
unsigned int enabled)
{
struct isl12022 *isl12022 = dev_get_drvdata(dev);
/* Make sure enabled is 0 or 1 */
enabled = !!enabled;
if (isl12022->irq_enabled == enabled)
return 0;
if (enabled)
enable_irq(isl12022->irq);
else
disable_irq(isl12022->irq);
isl12022->irq_enabled = enabled;
return 0;
}
static int isl12022_setup_irq(struct device *dev, int irq)
{
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
unsigned int reg_mask, reg_val;
u8 buf[ISL12022_ALARM_LEN] = { 0, };
int ret;
/* Clear and disable all alarm registers */
ret = regmap_bulk_write(regmap, ISL12022_ALARM, buf, sizeof(buf));
if (ret)
return ret;
/*
* Enable automatic reset of ALM bit and enable single event interrupt
* mode.
*/
reg_mask = ISL12022_INT_ARST | ISL12022_INT_IM | ISL12022_INT_FO_MASK;
reg_val = ISL12022_INT_ARST | ISL12022_INT_FO_OFF;
ret = regmap_write_bits(regmap, ISL12022_REG_INT,
reg_mask, reg_val);
if (ret)
return ret;
ret = devm_request_threaded_irq(dev, irq, NULL,
isl12022_rtc_interrupt,
IRQF_SHARED | IRQF_ONESHOT,
isl12022_driver.driver.name,
isl12022);
if (ret)
return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
isl12022->irq = irq;
return 0;
}
static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{ {
struct regmap *regmap = dev_get_drvdata(dev); struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u32 user, val; u32 user, val;
int ret; int ret;
@ -238,6 +456,9 @@ static const struct rtc_class_ops isl12022_rtc_ops = {
.ioctl = isl12022_rtc_ioctl, .ioctl = isl12022_rtc_ioctl,
.read_time = isl12022_rtc_read_time, .read_time = isl12022_rtc_read_time,
.set_time = isl12022_rtc_set_time, .set_time = isl12022_rtc_set_time,
.read_alarm = isl12022_rtc_read_alarm,
.set_alarm = isl12022_rtc_set_alarm,
.alarm_irq_enable = isl12022_rtc_alarm_irq_enable,
}; };
static const struct regmap_config regmap_config = { static const struct regmap_config regmap_config = {
@ -248,7 +469,8 @@ static const struct regmap_config regmap_config = {
static int isl12022_register_clock(struct device *dev) static int isl12022_register_clock(struct device *dev)
{ {
struct regmap *regmap = dev_get_drvdata(dev); struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
struct clk_hw *hw; struct clk_hw *hw;
int ret; int ret;
@ -288,7 +510,8 @@ static const u32 trip_levels[2][7] = {
static void isl12022_set_trip_levels(struct device *dev) static void isl12022_set_trip_levels(struct device *dev)
{ {
struct regmap *regmap = dev_get_drvdata(dev); struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u32 levels[2] = {0, 0}; u32 levels[2] = {0, 0};
int ret, i, j, x[2]; int ret, i, j, x[2];
u8 val, mask; u8 val, mask;
@ -325,6 +548,7 @@ static void isl12022_set_trip_levels(struct device *dev)
static int isl12022_probe(struct i2c_client *client) static int isl12022_probe(struct i2c_client *client)
{ {
struct isl12022 *isl12022;
struct rtc_device *rtc; struct rtc_device *rtc;
struct regmap *regmap; struct regmap *regmap;
int ret; int ret;
@ -332,13 +556,17 @@ static int isl12022_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV; return -ENODEV;
regmap = devm_regmap_init_i2c(client, &regmap_config); /* Allocate driver state */
if (IS_ERR(regmap)) { isl12022 = devm_kzalloc(&client->dev, sizeof(*isl12022), GFP_KERNEL);
dev_err(&client->dev, "regmap allocation failed\n"); if (!isl12022)
return PTR_ERR(regmap); return -ENOMEM;
}
dev_set_drvdata(&client->dev, regmap); regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(&client->dev, PTR_ERR(regmap), "regmap allocation failed\n");
isl12022->regmap = regmap;
dev_set_drvdata(&client->dev, isl12022);
ret = isl12022_register_clock(&client->dev); ret = isl12022_register_clock(&client->dev);
if (ret) if (ret)
@ -350,11 +578,20 @@ static int isl12022_probe(struct i2c_client *client)
rtc = devm_rtc_allocate_device(&client->dev); rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(rtc)) if (IS_ERR(rtc))
return PTR_ERR(rtc); return PTR_ERR(rtc);
isl12022->rtc = rtc;
rtc->ops = &isl12022_rtc_ops; rtc->ops = &isl12022_rtc_ops;
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->range_max = RTC_TIMESTAMP_END_2099; rtc->range_max = RTC_TIMESTAMP_END_2099;
if (client->irq > 0) {
ret = isl12022_setup_irq(&client->dev, client->irq);
if (ret)
return ret;
} else {
clear_bit(RTC_FEATURE_ALARM, rtc->features);
}
return devm_rtc_register_device(rtc); return devm_rtc_register_device(rtc);
} }

View File

@ -381,7 +381,7 @@ MODULE_DEVICE_TABLE(acpi, loongson_rtc_acpi_match);
static struct platform_driver loongson_rtc_driver = { static struct platform_driver loongson_rtc_driver = {
.probe = loongson_rtc_probe, .probe = loongson_rtc_probe,
.remove_new = loongson_rtc_remove, .remove = loongson_rtc_remove,
.driver = { .driver = {
.name = "loongson-rtc", .name = "loongson-rtc",
.of_match_table = loongson_rtc_of_match, .of_match_table = loongson_rtc_of_match,

View File

@ -285,7 +285,7 @@ MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match);
static struct platform_driver lpc24xx_rtc_driver = { static struct platform_driver lpc24xx_rtc_driver = {
.probe = lpc24xx_rtc_probe, .probe = lpc24xx_rtc_probe,
.remove_new = lpc24xx_rtc_remove, .remove = lpc24xx_rtc_remove,
.driver = { .driver = {
.name = "lpc24xx-rtc", .name = "lpc24xx-rtc",
.of_match_table = lpc24xx_rtc_match, .of_match_table = lpc24xx_rtc_match,

View File

@ -71,7 +71,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* Issue the READ command */ /* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)); tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset;
/* tm_mon is 0-11 */ /* tm_mon is 0-11 */
tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY)); tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY));
@ -82,10 +82,6 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
dev_dbg(dev, "Century bit is enabled\n"); dev_dbg(dev, "Century bit is enabled\n");
tm->tm_year += 100; /* one century */ tm->tm_year += 100; /* one century */
} }
#ifdef CONFIG_SPARC
/* Sun SPARC machines count years since 1968 */
tm->tm_year += 68;
#endif
tm->tm_wday = bcd2bin(val & 0x07); tm->tm_wday = bcd2bin(val & 0x07);
tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F); tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F);
@ -106,12 +102,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct m48t59_private *m48t59 = dev_get_drvdata(dev); struct m48t59_private *m48t59 = dev_get_drvdata(dev);
unsigned long flags; unsigned long flags;
u8 val = 0; u8 val = 0;
int year = tm->tm_year; int year = tm->tm_year - pdata->yy_offset;
#ifdef CONFIG_SPARC
/* Sun SPARC machines count years since 1968 */
year -= 68;
#endif
dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n", dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n",
year + 1900, tm->tm_mon, tm->tm_mday, year + 1900, tm->tm_mon, tm->tm_mday,
@ -162,11 +153,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
/* Issue the READ command */ /* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)); tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset;
#ifdef CONFIG_SPARC
/* Sun SPARC machines count years since 1968 */
tm->tm_year += 68;
#endif
/* tm_mon is 0-11 */ /* tm_mon is 0-11 */
tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
@ -197,12 +184,7 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time; struct rtc_time *tm = &alrm->time;
u8 mday, hour, min, sec; u8 mday, hour, min, sec;
unsigned long flags; unsigned long flags;
int year = tm->tm_year; int year = tm->tm_year - pdata->yy_offset;
#ifdef CONFIG_SPARC
/* Sun SPARC machines count years since 1968 */
year -= 68;
#endif
/* If no irq, we don't support ALARM */ /* If no irq, we don't support ALARM */
if (m48t59->irq == NO_IRQ) if (m48t59->irq == NO_IRQ)

View File

@ -875,7 +875,7 @@ static struct platform_driver max77686_rtc_driver = {
.pm = &max77686_rtc_pm_ops, .pm = &max77686_rtc_pm_ops,
}, },
.probe = max77686_rtc_probe, .probe = max77686_rtc_probe,
.remove_new = max77686_rtc_remove, .remove = max77686_rtc_remove,
.id_table = rtc_id, .id_table = rtc_id,
}; };

View File

@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
static struct platform_driver mc13xxx_rtc_driver = { static struct platform_driver mc13xxx_rtc_driver = {
.id_table = mc13xxx_rtc_idtable, .id_table = mc13xxx_rtc_idtable,
.remove_new = mc13xxx_rtc_remove, .remove = mc13xxx_rtc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
}, },

View File

@ -216,7 +216,7 @@ int mc146818_set_time(struct rtc_time *time)
unsigned char save_control, save_freq_select; unsigned char save_control, save_freq_select;
unsigned int yrs; unsigned int yrs;
#ifdef CONFIG_MACH_DECSTATION #ifdef CONFIG_MACH_DECSTATION
unsigned int real_yrs, leap_yr; unsigned int real_yrs;
#endif #endif
unsigned char century = 0; unsigned char century = 0;
@ -232,8 +232,6 @@ int mc146818_set_time(struct rtc_time *time)
#ifdef CONFIG_MACH_DECSTATION #ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs; real_yrs = yrs;
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
!((yrs + 1900) % 400));
yrs = 72; yrs = 72;
/* /*
@ -241,7 +239,7 @@ int mc146818_set_time(struct rtc_time *time)
* for non-leap years, so that Feb, 29th is handled * for non-leap years, so that Feb, 29th is handled
* correctly. * correctly.
*/ */
if (!leap_yr && mon < 3) { if (!is_leap_year(real_yrs + 1900) && mon < 3) {
real_yrs--; real_yrs--;
yrs = 73; yrs = 73;
} }

View File

@ -398,7 +398,7 @@ static struct platform_driver mpc5121_rtc_driver = {
.of_match_table = of_match_ptr(mpc5121_rtc_match), .of_match_table = of_match_ptr(mpc5121_rtc_match),
}, },
.probe = mpc5121_rtc_probe, .probe = mpc5121_rtc_probe,
.remove_new = mpc5121_rtc_remove, .remove = mpc5121_rtc_remove,
}; };
module_platform_driver(mpc5121_rtc_driver); module_platform_driver(mpc5121_rtc_driver);

View File

@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, mpfs_rtc_of_match);
static struct platform_driver mpfs_rtc_driver = { static struct platform_driver mpfs_rtc_driver = {
.probe = mpfs_rtc_probe, .probe = mpfs_rtc_probe,
.remove_new = mpfs_rtc_remove, .remove = mpfs_rtc_remove,
.driver = { .driver = {
.name = "mpfs_rtc", .name = "mpfs_rtc",
.of_match_table = mpfs_rtc_of_match, .of_match_table = mpfs_rtc_of_match,

View File

@ -75,6 +75,7 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
tm->tm_min = data[RTC_OFFSET_MIN]; tm->tm_min = data[RTC_OFFSET_MIN];
tm->tm_hour = data[RTC_OFFSET_HOUR]; tm->tm_hour = data[RTC_OFFSET_HOUR];
tm->tm_mday = data[RTC_OFFSET_DOM]; tm->tm_mday = data[RTC_OFFSET_DOM];
tm->tm_wday = data[RTC_OFFSET_DOW];
tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK; tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK;
tm->tm_year = data[RTC_OFFSET_YEAR]; tm->tm_year = data[RTC_OFFSET_YEAR];
@ -86,9 +87,8 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm) static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
time64_t time;
struct mt6397_rtc *rtc = dev_get_drvdata(dev); struct mt6397_rtc *rtc = dev_get_drvdata(dev);
int days, sec, ret; int sec, ret;
do { do {
ret = __mtk_rtc_read_time(rtc, tm, &sec); ret = __mtk_rtc_read_time(rtc, tm, &sec);
@ -96,21 +96,9 @@ static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
goto exit; goto exit;
} while (sec < tm->tm_sec); } while (sec < tm->tm_sec);
/* HW register use 7 bits to store year data, minus /* HW register start mon/wday from one, but tm_mon/tm_wday start from zero. */
* RTC_MIN_YEAR_OFFSET before write year data to register, and plus
* RTC_MIN_YEAR_OFFSET back after read year from register
*/
tm->tm_year += RTC_MIN_YEAR_OFFSET;
/* HW register start mon from one, but tm_mon start from zero. */
tm->tm_mon--; tm->tm_mon--;
time = rtc_tm_to_time64(tm); tm->tm_wday--;
/* rtc_tm_to_time64 covert Gregorian date to seconds since
* 01-01-1970 00:00:00, and this date is Thursday.
*/
days = div_s64(time, 86400);
tm->tm_wday = (days + 4) % 7;
exit: exit:
return ret; return ret;
@ -122,13 +110,14 @@ static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
int ret; int ret;
u16 data[RTC_OFFSET_COUNT]; u16 data[RTC_OFFSET_COUNT];
tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++; tm->tm_mon++;
tm->tm_wday++;
data[RTC_OFFSET_SEC] = tm->tm_sec; data[RTC_OFFSET_SEC] = tm->tm_sec;
data[RTC_OFFSET_MIN] = tm->tm_min; data[RTC_OFFSET_MIN] = tm->tm_min;
data[RTC_OFFSET_HOUR] = tm->tm_hour; data[RTC_OFFSET_HOUR] = tm->tm_hour;
data[RTC_OFFSET_DOM] = tm->tm_mday; data[RTC_OFFSET_DOM] = tm->tm_mday;
data[RTC_OFFSET_DOW] = tm->tm_wday;
data[RTC_OFFSET_MTH] = tm->tm_mon; data[RTC_OFFSET_MTH] = tm->tm_mon;
data[RTC_OFFSET_YEAR] = tm->tm_year; data[RTC_OFFSET_YEAR] = tm->tm_year;
@ -178,7 +167,6 @@ static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK; tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK;
tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK; tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK;
tm->tm_year += RTC_MIN_YEAR_OFFSET;
tm->tm_mon--; tm->tm_mon--;
return 0; return 0;
@ -194,7 +182,6 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
int ret; int ret;
u16 data[RTC_OFFSET_COUNT]; u16 data[RTC_OFFSET_COUNT];
tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++; tm->tm_mon++;
mutex_lock(&rtc->lock); mutex_lock(&rtc->lock);
@ -302,6 +289,10 @@ static int mtk_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1); device_init_wakeup(&pdev->dev, 1);
rtc->rtc_dev->ops = &mtk_rtc_ops; rtc->rtc_dev->ops = &mtk_rtc_ops;
rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
rtc->rtc_dev->range_max = mktime64(2027, 12, 31, 23, 59, 59);
rtc->rtc_dev->start_secs = mktime64(1968, 1, 2, 0, 0, 0);
rtc->rtc_dev->set_start_time = true;
return devm_rtc_register_device(rtc->rtc_dev); return devm_rtc_register_device(rtc->rtc_dev);
} }

View File

@ -394,7 +394,7 @@ static SIMPLE_DEV_PM_OPS(mtk_rtc_pm_ops, mtk_rtc_suspend, mtk_rtc_resume);
static struct platform_driver mtk_rtc_driver = { static struct platform_driver mtk_rtc_driver = {
.probe = mtk_rtc_probe, .probe = mtk_rtc_probe,
.remove_new = mtk_rtc_remove, .remove = mtk_rtc_remove,
.driver = { .driver = {
.name = MTK_RTC_DEV, .name = MTK_RTC_DEV,
.of_match_table = mtk_rtc_match, .of_match_table = mtk_rtc_match,

View File

@ -308,7 +308,7 @@ MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table);
* triggering a section mismatch warning. * triggering a section mismatch warning.
*/ */
static struct platform_driver mv_rtc_driver __refdata = { static struct platform_driver mv_rtc_driver __refdata = {
.remove_new = __exit_p(mv_rtc_remove), .remove = __exit_p(mv_rtc_remove),
.driver = { .driver = {
.name = "rtc-mv", .name = "rtc-mv",
.of_match_table = of_match_ptr(rtc_mv_of_match_table), .of_match_table = of_match_ptr(rtc_mv_of_match_table),

View File

@ -381,7 +381,7 @@ static struct platform_driver mxc_rtc_driver = {
.of_match_table = mxc_ids, .of_match_table = mxc_ids,
}, },
.probe = mxc_rtc_probe, .probe = mxc_rtc_probe,
.remove_new = mxc_rtc_remove, .remove = mxc_rtc_remove,
}; };
module_platform_driver(mxc_rtc_driver); module_platform_driver(mxc_rtc_driver);

View File

@ -197,13 +197,28 @@ static int bbnsm_rtc_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to request irq %d: %d\n", dev_err(&pdev->dev, "failed to request irq %d: %d\n",
bbnsm->irq, ret); bbnsm->irq, ret);
return ret; goto err;
} }
bbnsm->rtc->ops = &bbnsm_rtc_ops; bbnsm->rtc->ops = &bbnsm_rtc_ops;
bbnsm->rtc->range_max = U32_MAX; bbnsm->rtc->range_max = U32_MAX;
return devm_rtc_register_device(bbnsm->rtc); 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);
} }
static const struct of_device_id bbnsm_dt_ids[] = { static const struct of_device_id bbnsm_dt_ids[] = {
@ -218,6 +233,7 @@ static struct platform_driver bbnsm_rtc_driver = {
.of_match_table = bbnsm_dt_ids, .of_match_table = bbnsm_dt_ids,
}, },
.probe = bbnsm_rtc_probe, .probe = bbnsm_rtc_probe,
.remove = bbnsm_rtc_remove,
}; };
module_platform_driver(bbnsm_rtc_driver); module_platform_driver(bbnsm_rtc_driver);

View File

@ -1014,7 +1014,7 @@ static void omap_rtc_shutdown(struct platform_device *pdev)
static struct platform_driver omap_rtc_driver = { static struct platform_driver omap_rtc_driver = {
.probe = omap_rtc_probe, .probe = omap_rtc_probe,
.remove_new = omap_rtc_remove, .remove = omap_rtc_remove,
.shutdown = omap_rtc_shutdown, .shutdown = omap_rtc_shutdown,
.driver = { .driver = {
.name = "omap_rtc", .name = "omap_rtc",

View File

@ -346,7 +346,7 @@ MODULE_DEVICE_TABLE(of, of_palmas_rtc_match);
static struct platform_driver palmas_rtc_driver = { static struct platform_driver palmas_rtc_driver = {
.probe = palmas_rtc_probe, .probe = palmas_rtc_probe,
.remove_new = palmas_rtc_remove, .remove = palmas_rtc_remove,
.driver = { .driver = {
.name = "palmas-rtc", .name = "palmas-rtc",
.pm = &palmas_rtc_pm_ops, .pm = &palmas_rtc_pm_ops,

View File

@ -273,7 +273,7 @@ static struct platform_driver pcf50633_rtc_driver = {
.name = "pcf50633-rtc", .name = "pcf50633-rtc",
}, },
.probe = pcf50633_rtc_probe, .probe = pcf50633_rtc_probe,
.remove_new = pcf50633_rtc_remove, .remove = pcf50633_rtc_remove,
}; };
module_platform_driver(pcf50633_rtc_driver); module_platform_driver(pcf50633_rtc_driver);

View File

@ -11,14 +11,15 @@
* https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf * https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf
*/ */
#include <linux/clk-provider.h>
#include <linux/i2c.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/rtc.h> #include <linux/clk-provider.h>
#include <linux/slab.h> #include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/err.h> #include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#define PCF8563_REG_ST1 0x00 /* status */ #define PCF8563_REG_ST1 0x00 /* status */
#define PCF8563_REG_ST2 0x01 #define PCF8563_REG_ST2 0x01
@ -77,64 +78,18 @@ struct pcf8563 {
*/ */
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
struct i2c_client *client; struct regmap *regmap;
#ifdef CONFIG_COMMON_CLK #ifdef CONFIG_COMMON_CLK
struct clk_hw clkout_hw; struct clk_hw clkout_hw;
#endif #endif
}; };
static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, static int pcf8563_set_alarm_mode(struct pcf8563 *pcf8563, bool on)
unsigned char length, unsigned char *buf)
{ {
struct i2c_msg msgs[] = { u32 buf;
{/* setup read ptr */
.addr = client->addr,
.len = 1,
.buf = &reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = buf
},
};
if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
return 0;
}
static int pcf8563_write_block_data(struct i2c_client *client,
unsigned char reg, unsigned char length,
unsigned char *buf)
{
int i, err;
for (i = 0; i < length; i++) {
unsigned char data[2] = { reg + i, buf[i] };
err = i2c_master_send(client, data, sizeof(data));
if (err != sizeof(data)) {
dev_err(&client->dev,
"%s: err=%d addr=%02x, data=%02x\n",
__func__, err, data[0], data[1]);
return -EIO;
}
}
return 0;
}
static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
{
unsigned char buf;
int err; int err;
err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf);
if (err < 0) if (err < 0)
return err; return err;
@ -145,23 +100,17 @@ static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N); buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N);
err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); return regmap_write(pcf8563->regmap, PCF8563_REG_ST2, buf);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return -EIO;
}
return 0;
} }
static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en, static int pcf8563_get_alarm_mode(struct pcf8563 *pcf8563, unsigned char *en,
unsigned char *pen) unsigned char *pen)
{ {
unsigned char buf; u32 buf;
int err; int err;
err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf);
if (err) if (err < 0)
return err; return err;
if (en) if (en)
@ -174,17 +123,17 @@ static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en,
static irqreturn_t pcf8563_irq(int irq, void *dev_id) static irqreturn_t pcf8563_irq(int irq, void *dev_id)
{ {
struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id); struct pcf8563 *pcf8563 = dev_id;
int err;
char pending; char pending;
int err;
err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending); err = pcf8563_get_alarm_mode(pcf8563, NULL, &pending);
if (err) if (err)
return IRQ_NONE; return IRQ_NONE;
if (pending) { if (pending) {
rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF); rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF);
pcf8563_set_alarm_mode(pcf8563->client, 1); pcf8563_set_alarm_mode(pcf8563, 1);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -197,22 +146,22 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id)
*/ */
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
struct i2c_client *client = to_i2c_client(dev); struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
unsigned char buf[9]; unsigned char buf[9];
int err; int err;
err = pcf8563_read_block_data(client, PCF8563_REG_ST1, 9, buf); err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_ST1, buf,
if (err) sizeof(buf));
if (err < 0)
return err; return err;
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) { if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
dev_err(&client->dev, dev_err(dev,
"low voltage detected, date/time is not reliable.\n"); "low voltage detected, date/time is not reliable.\n");
return -EINVAL; return -EINVAL;
} }
dev_dbg(&client->dev, dev_dbg(dev,
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, " "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n", "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
__func__, __func__,
@ -220,7 +169,6 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
buf[4], buf[5], buf[6], buf[7], buf[4], buf[5], buf[6], buf[7],
buf[8]); buf[8]);
tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F); tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F); tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */ tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
@ -232,7 +180,7 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ? pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
(tm->tm_year >= 100) : (tm->tm_year < 100); (tm->tm_year >= 100) : (tm->tm_year < 100);
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n", "mday=%d, mon=%d, year=%d, wday=%d\n",
__func__, __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_sec, tm->tm_min, tm->tm_hour,
@ -243,11 +191,10 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
{ {
struct i2c_client *client = to_i2c_client(dev); struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
unsigned char buf[9]; unsigned char buf[9];
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n", "mday=%d, mon=%d, year=%d, wday=%d\n",
__func__, __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_sec, tm->tm_min, tm->tm_hour,
@ -270,22 +217,24 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
return pcf8563_write_block_data(client, PCF8563_REG_SC, return regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC,
9 - PCF8563_REG_SC, buf + PCF8563_REG_SC); buf + PCF8563_REG_SC,
sizeof(buf) - PCF8563_REG_SC);
} }
static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{ {
struct i2c_client *client = to_i2c_client(dev); struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
int ret; int ret;
switch (cmd) { switch (cmd) {
case RTC_VL_READ: case RTC_VL_READ:
ret = i2c_smbus_read_byte_data(client, PCF8563_REG_SC); ret = regmap_test_bits(pcf8563->regmap, PCF8563_REG_SC,
PCF8563_SC_LV);
if (ret < 0) if (ret < 0)
return ret; return ret;
return put_user(ret & PCF8563_SC_LV ? RTC_VL_DATA_INVALID : 0, return put_user(ret ? RTC_VL_DATA_INVALID : 0,
(unsigned int __user *)arg); (unsigned int __user *)arg);
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
@ -294,15 +243,16 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
{ {
struct i2c_client *client = to_i2c_client(dev); struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4]; unsigned char buf[4];
int err; int err;
err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf); err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_AMN, buf,
if (err) sizeof(buf));
if (err < 0)
return err; return err;
dev_dbg(&client->dev, dev_dbg(dev,
"%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n", "%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
__func__, buf[0], buf[1], buf[2], buf[3]); __func__, buf[0], buf[1], buf[2], buf[3]);
@ -312,11 +262,11 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
tm->time.tm_mday = bcd2bin(buf[2] & 0x3F); tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
tm->time.tm_wday = bcd2bin(buf[3] & 0x7); tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending); err = pcf8563_get_alarm_mode(pcf8563, &tm->enabled, &tm->pending);
if (err < 0) if (err < 0)
return err; return err;
dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d," dev_dbg(dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d,"
" enabled=%d, pending=%d\n", __func__, tm->time.tm_min, " enabled=%d, pending=%d\n", __func__, tm->time.tm_min,
tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday, tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday,
tm->enabled, tm->pending); tm->enabled, tm->pending);
@ -326,7 +276,7 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
{ {
struct i2c_client *client = to_i2c_client(dev); struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4]; unsigned char buf[4];
int err; int err;
@ -335,17 +285,20 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
buf[2] = bin2bcd(tm->time.tm_mday); buf[2] = bin2bcd(tm->time.tm_mday);
buf[3] = tm->time.tm_wday & 0x07; buf[3] = tm->time.tm_wday & 0x07;
err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf); err = regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC, buf,
sizeof(buf));
if (err) if (err)
return err; return err;
return pcf8563_set_alarm_mode(client, !!tm->enabled); return pcf8563_set_alarm_mode(pcf8563, !!tm->enabled);
} }
static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
{ {
struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
dev_dbg(dev, "%s: en=%d\n", __func__, enabled); dev_dbg(dev, "%s: en=%d\n", __func__, enabled);
return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); return pcf8563_set_alarm_mode(pcf8563, !!enabled);
} }
#ifdef CONFIG_COMMON_CLK #ifdef CONFIG_COMMON_CLK
@ -366,10 +319,10 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client; u32 buf;
unsigned char buf; int ret;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0) if (ret < 0)
return 0; return 0;
@ -393,11 +346,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client; int i, ret;
unsigned char buf; u32 buf;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
int i;
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -405,10 +357,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] == rate) { if (clkout_rates[i] == rate) {
buf &= ~PCF8563_REG_CLKO_F_MASK; buf &= ~PCF8563_REG_CLKO_F_MASK;
buf |= i; buf |= i;
ret = pcf8563_write_block_data(client, return regmap_update_bits(pcf8563->regmap,
PCF8563_REG_CLKO, 1, PCF8563_REG_CLKO,
&buf); PCF8563_REG_CLKO_F_MASK,
return ret; buf);
} }
return -EINVAL; return -EINVAL;
@ -417,10 +369,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
static int pcf8563_clkout_control(struct clk_hw *hw, bool enable) static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
{ {
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client; u32 buf;
unsigned char buf; int ret;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -429,8 +381,8 @@ static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
else else
buf &= ~PCF8563_REG_CLKO_FE; buf &= ~PCF8563_REG_CLKO_FE;
ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); return regmap_update_bits(pcf8563->regmap, PCF8563_REG_CLKO,
return ret; PCF8563_REG_CLKO_FE, buf);
} }
static int pcf8563_clkout_prepare(struct clk_hw *hw) static int pcf8563_clkout_prepare(struct clk_hw *hw)
@ -446,10 +398,10 @@ static void pcf8563_clkout_unprepare(struct clk_hw *hw)
static int pcf8563_clkout_is_prepared(struct clk_hw *hw) static int pcf8563_clkout_is_prepared(struct clk_hw *hw)
{ {
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client; u32 buf;
unsigned char buf; int ret;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -467,16 +419,14 @@ 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 i2c_client *client = pcf8563->client; struct device_node *node = pcf8563->rtc->dev.of_node;
struct device_node *node = client->dev.of_node;
struct clk *clk;
struct clk_init_data init; struct clk_init_data init;
struct clk *clk;
int ret; int ret;
unsigned char buf;
/* disable the clkout output */ /* disable the clkout output */
buf = 0; ret = regmap_clear_bits(pcf8563->regmap, PCF8563_REG_CLKO,
ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); PCF8563_REG_CLKO_FE);
if (ret < 0) if (ret < 0)
return ERR_PTR(ret); return ERR_PTR(ret);
@ -491,7 +441,7 @@ static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
of_property_read_string(node, "clock-output-names", &init.name); of_property_read_string(node, "clock-output-names", &init.name);
/* register the clock */ /* register the clock */
clk = devm_clk_register(&client->dev, &pcf8563->clkout_hw); clk = devm_clk_register(&pcf8563->rtc->dev, &pcf8563->clkout_hw);
if (!IS_ERR(clk)) if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk); of_clk_add_provider(node, of_clk_src_simple_get, clk);
@ -509,11 +459,16 @@ static const struct rtc_class_ops pcf8563_rtc_ops = {
.alarm_irq_enable = pcf8563_irq_enable, .alarm_irq_enable = pcf8563_irq_enable,
}; };
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xF,
};
static int pcf8563_probe(struct i2c_client *client) static int pcf8563_probe(struct i2c_client *client)
{ {
struct pcf8563 *pcf8563; struct pcf8563 *pcf8563;
int err; int err;
unsigned char buf;
dev_dbg(&client->dev, "%s\n", __func__); dev_dbg(&client->dev, "%s\n", __func__);
@ -525,20 +480,23 @@ static int pcf8563_probe(struct i2c_client *client)
if (!pcf8563) if (!pcf8563)
return -ENOMEM; return -ENOMEM;
pcf8563->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(pcf8563->regmap))
return PTR_ERR(pcf8563->regmap);
i2c_set_clientdata(client, pcf8563); i2c_set_clientdata(client, pcf8563);
pcf8563->client = client; device_set_wakeup_capable(&client->dev, 1);
/* Set timer to lowest frequency to save power (ref Haoyu datasheet) */ /* Set timer to lowest frequency to save power (ref Haoyu datasheet) */
buf = PCF8563_TMRC_1_60; err = regmap_set_bits(pcf8563->regmap, PCF8563_REG_TMRC,
err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf); PCF8563_TMRC_1_60);
if (err < 0) { if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__); dev_err(&client->dev, "%s: write error\n", __func__);
return err; return err;
} }
/* Clear flags and disable interrupts */ /* Clear flags and disable interrupts */
buf = 0; err = regmap_write(pcf8563->regmap, PCF8563_REG_ST2, 0);
err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
if (err < 0) { if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__); dev_err(&client->dev, "%s: write error\n", __func__);
return err; return err;

View File

@ -371,7 +371,7 @@ MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids);
static struct platform_driver pic32_rtc_driver = { static struct platform_driver pic32_rtc_driver = {
.probe = pic32_rtc_probe, .probe = pic32_rtc_probe,
.remove_new = pic32_rtc_remove, .remove = pic32_rtc_remove,
.driver = { .driver = {
.name = "pic32-rtc", .name = "pic32-rtc",
.of_match_table = of_match_ptr(pic32_rtc_dt_ids), .of_match_table = of_match_ptr(pic32_rtc_dt_ids),

View File

@ -537,7 +537,7 @@ static void pm8xxx_remove(struct platform_device *pdev)
static struct platform_driver pm8xxx_rtc_driver = { static struct platform_driver pm8xxx_rtc_driver = {
.probe = pm8xxx_rtc_probe, .probe = pm8xxx_rtc_probe,
.remove_new = pm8xxx_remove, .remove = pm8xxx_remove,
.driver = { .driver = {
.name = "rtc-pm8xxx", .name = "rtc-pm8xxx",
.of_match_table = pm8xxx_id_table, .of_match_table = pm8xxx_id_table,

View File

@ -409,7 +409,7 @@ static SIMPLE_DEV_PM_OPS(pxa_rtc_pm_ops, pxa_rtc_suspend, pxa_rtc_resume);
* triggering a section mismatch warning. * triggering a section mismatch warning.
*/ */
static struct platform_driver pxa_rtc_driver __refdata = { static struct platform_driver pxa_rtc_driver __refdata = {
.remove_new = __exit_p(pxa_rtc_remove), .remove = __exit_p(pxa_rtc_remove),
.driver = { .driver = {
.name = "pxa-rtc", .name = "pxa-rtc",
.of_match_table = of_match_ptr(pxa_rtc_dt_ids), .of_match_table = of_match_ptr(pxa_rtc_dt_ids),

View File

@ -298,7 +298,7 @@ static SIMPLE_DEV_PM_OPS(rc5t583_rtc_pm_ops, rc5t583_rtc_suspend,
static struct platform_driver rc5t583_rtc_driver = { static struct platform_driver rc5t583_rtc_driver = {
.probe = rc5t583_rtc_probe, .probe = rc5t583_rtc_probe,
.remove_new = rc5t583_rtc_remove, .remove = rc5t583_rtc_remove,
.driver = { .driver = {
.name = "rtc-rc5t583", .name = "rtc-rc5t583",
.pm = &rc5t583_rtc_pm_ops, .pm = &rc5t583_rtc_pm_ops,

View File

@ -0,0 +1,900 @@
// SPDX-License-Identifier: GPL-2.0
/*
* On-Chip RTC Support available on RZ/G3S SoC
*
* Copyright (C) 2024 Renesas Electronics Corp.
*/
#include <linux/bcd.h>
#include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/rtc.h>
/* Counter registers. */
#define RTCA3_RSECCNT 0x2
#define RTCA3_RSECCNT_SEC GENMASK(6, 0)
#define RTCA3_RMINCNT 0x4
#define RTCA3_RMINCNT_MIN GENMASK(6, 0)
#define RTCA3_RHRCNT 0x6
#define RTCA3_RHRCNT_HR GENMASK(5, 0)
#define RTCA3_RHRCNT_PM BIT(6)
#define RTCA3_RWKCNT 0x8
#define RTCA3_RWKCNT_WK GENMASK(2, 0)
#define RTCA3_RDAYCNT 0xa
#define RTCA3_RDAYCNT_DAY GENMASK(5, 0)
#define RTCA3_RMONCNT 0xc
#define RTCA3_RMONCNT_MONTH GENMASK(4, 0)
#define RTCA3_RYRCNT 0xe
#define RTCA3_RYRCNT_YEAR GENMASK(7, 0)
/* Alarm registers. */
#define RTCA3_RSECAR 0x10
#define RTCA3_RSECAR_SEC GENMASK(6, 0)
#define RTCA3_RMINAR 0x12
#define RTCA3_RMINAR_MIN GENMASK(6, 0)
#define RTCA3_RHRAR 0x14
#define RTCA3_RHRAR_HR GENMASK(5, 0)
#define RTCA3_RHRAR_PM BIT(6)
#define RTCA3_RWKAR 0x16
#define RTCA3_RWKAR_DAYW GENMASK(2, 0)
#define RTCA3_RDAYAR 0x18
#define RTCA3_RDAYAR_DATE GENMASK(5, 0)
#define RTCA3_RMONAR 0x1a
#define RTCA3_RMONAR_MON GENMASK(4, 0)
#define RTCA3_RYRAR 0x1c
#define RTCA3_RYRAR_YR GENMASK(7, 0)
#define RTCA3_RYRAREN 0x1e
/* Alarm enable bit (for all alarm registers). */
#define RTCA3_AR_ENB BIT(7)
/* Control registers. */
#define RTCA3_RCR1 0x22
#define RTCA3_RCR1_AIE BIT(0)
#define RTCA3_RCR1_CIE BIT(1)
#define RTCA3_RCR1_PIE BIT(2)
#define RTCA3_RCR1_PES GENMASK(7, 4)
#define RTCA3_RCR1_PES_1_64_SEC 0x8
#define RTCA3_RCR2 0x24
#define RTCA3_RCR2_START BIT(0)
#define RTCA3_RCR2_RESET BIT(1)
#define RTCA3_RCR2_AADJE BIT(4)
#define RTCA3_RCR2_ADJP BIT(5)
#define RTCA3_RCR2_HR24 BIT(6)
#define RTCA3_RCR2_CNTMD BIT(7)
#define RTCA3_RSR 0x20
#define RTCA3_RSR_AF BIT(0)
#define RTCA3_RSR_CF BIT(1)
#define RTCA3_RSR_PF BIT(2)
#define RTCA3_RADJ 0x2e
#define RTCA3_RADJ_ADJ GENMASK(5, 0)
#define RTCA3_RADJ_ADJ_MAX 0x3f
#define RTCA3_RADJ_PMADJ GENMASK(7, 6)
#define RTCA3_RADJ_PMADJ_NONE 0
#define RTCA3_RADJ_PMADJ_ADD 1
#define RTCA3_RADJ_PMADJ_SUB 2
/* Polling operation timeouts. */
#define RTCA3_DEFAULT_TIMEOUT_US 150
#define RTCA3_IRQSET_TIMEOUT_US 5000
#define RTCA3_START_TIMEOUT_US 150000
#define RTCA3_RESET_TIMEOUT_US 200000
/**
* enum rtca3_alrm_set_step - RTCA3 alarm set steps
* @RTCA3_ALRM_SSTEP_DONE: alarm setup done step
* @RTCA3_ALRM_SSTEP_IRQ: two 1/64 periodic IRQs were generated step
* @RTCA3_ALRM_SSTEP_INIT: alarm setup initialization step
*/
enum rtca3_alrm_set_step {
RTCA3_ALRM_SSTEP_DONE = 0,
RTCA3_ALRM_SSTEP_IRQ = 1,
RTCA3_ALRM_SSTEP_INIT = 3,
};
/**
* struct rtca3_ppb_per_cycle - PPB per cycle
* @ten_sec: PPB per cycle in 10 seconds adjutment mode
* @sixty_sec: PPB per cycle in 60 seconds adjustment mode
*/
struct rtca3_ppb_per_cycle {
int ten_sec;
int sixty_sec;
};
/**
* struct rtca3_priv - RTCA3 private data structure
* @base: base address
* @rtc_dev: RTC device
* @rstc: reset control
* @set_alarm_completion: alarm setup completion
* @alrm_sstep: alarm setup step (see enum rtca3_alrm_set_step)
* @lock: device lock
* @ppb: ppb per cycle for each the available adjustment modes
* @wakeup_irq: wakeup IRQ
*/
struct rtca3_priv {
void __iomem *base;
struct rtc_device *rtc_dev;
struct reset_control *rstc;
struct completion set_alarm_completion;
atomic_t alrm_sstep;
spinlock_t lock;
struct rtca3_ppb_per_cycle ppb;
int wakeup_irq;
};
static void rtca3_byte_update_bits(struct rtca3_priv *priv, u8 off, u8 mask, u8 val)
{
u8 tmp;
tmp = readb(priv->base + off);
tmp &= ~mask;
tmp |= (val & mask);
writeb(tmp, priv->base + off);
}
static u8 rtca3_alarm_handler_helper(struct rtca3_priv *priv)
{
u8 val, pending;
val = readb(priv->base + RTCA3_RSR);
pending = val & RTCA3_RSR_AF;
writeb(val & ~pending, priv->base + RTCA3_RSR);
if (pending)
rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);
return pending;
}
static irqreturn_t rtca3_alarm_handler(int irq, void *dev_id)
{
struct rtca3_priv *priv = dev_id;
u8 pending;
guard(spinlock)(&priv->lock);
pending = rtca3_alarm_handler_helper(priv);
return IRQ_RETVAL(pending);
}
static irqreturn_t rtca3_periodic_handler(int irq, void *dev_id)
{
struct rtca3_priv *priv = dev_id;
u8 val, pending;
guard(spinlock)(&priv->lock);
val = readb(priv->base + RTCA3_RSR);
pending = val & RTCA3_RSR_PF;
if (pending) {
writeb(val & ~pending, priv->base + RTCA3_RSR);
if (atomic_read(&priv->alrm_sstep) > RTCA3_ALRM_SSTEP_IRQ) {
/* Alarm setup in progress. */
atomic_dec(&priv->alrm_sstep);
if (atomic_read(&priv->alrm_sstep) == RTCA3_ALRM_SSTEP_IRQ) {
/*
* We got 2 * 1/64 periodic interrupts. Disable
* interrupt and let alarm setup continue.
*/
rtca3_byte_update_bits(priv, RTCA3_RCR1,
RTCA3_RCR1_PIE, 0);
readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, val,
!(val & RTCA3_RCR1_PIE),
10, RTCA3_DEFAULT_TIMEOUT_US);
complete(&priv->set_alarm_completion);
}
}
}
return IRQ_RETVAL(pending);
}
static void rtca3_prepare_cntalrm_regs_for_read(struct rtca3_priv *priv, bool cnt)
{
/* Offset b/w time and alarm registers. */
u8 offset = cnt ? 0 : 0xe;
/*
* According to HW manual (section 22.6.4. Notes on writing to and
* reading from registers) after writing to count registers, alarm
* registers, year alarm enable register, bits RCR2.AADJE, AADJP,
* and HR24 register, we need to do 3 empty reads before being
* able to fetch the registers content.
*/
for (u8 i = 0; i < 3; i++) {
readb(priv->base + RTCA3_RSECCNT + offset);
readb(priv->base + RTCA3_RMINCNT + offset);
readb(priv->base + RTCA3_RHRCNT + offset);
readb(priv->base + RTCA3_RWKCNT + offset);
readb(priv->base + RTCA3_RDAYCNT + offset);
readw(priv->base + RTCA3_RYRCNT + offset);
if (!cnt)
readb(priv->base + RTCA3_RYRAREN);
}
}
static int rtca3_read_time(struct device *dev, struct rtc_time *tm)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
u8 sec, min, hour, wday, mday, month, tmp;
u8 trials = 0;
u32 year100;
u16 year;
guard(spinlock_irqsave)(&priv->lock);
tmp = readb(priv->base + RTCA3_RCR2);
if (!(tmp & RTCA3_RCR2_START))
return -EINVAL;
do {
/* Clear carry interrupt. */
rtca3_byte_update_bits(priv, RTCA3_RSR, RTCA3_RSR_CF, 0);
/* Read counters. */
sec = readb(priv->base + RTCA3_RSECCNT);
min = readb(priv->base + RTCA3_RMINCNT);
hour = readb(priv->base + RTCA3_RHRCNT);
wday = readb(priv->base + RTCA3_RWKCNT);
mday = readb(priv->base + RTCA3_RDAYCNT);
month = readb(priv->base + RTCA3_RMONCNT);
year = readw(priv->base + RTCA3_RYRCNT);
tmp = readb(priv->base + RTCA3_RSR);
/*
* We cannot generate carries due to reading 64Hz counter as
* the driver doesn't implement carry, thus, carries will be
* generated once per seconds. Add a timeout of 5 trials here
* to avoid infinite loop, if any.
*/
} while ((tmp & RTCA3_RSR_CF) && ++trials < 5);
if (trials >= 5)
return -ETIMEDOUT;
tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECCNT_SEC, sec));
tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINCNT_MIN, min));
tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRCNT_HR, hour));
tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKCNT_WK, wday));
tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYCNT_DAY, mday));
tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONCNT_MONTH, month)) - 1;
year = FIELD_GET(RTCA3_RYRCNT_YEAR, year);
year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
return 0;
}
static int rtca3_set_time(struct device *dev, struct rtc_time *tm)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
u8 rcr2, tmp;
int ret;
guard(spinlock_irqsave)(&priv->lock);
/* Stop the RTC. */
rcr2 = readb(priv->base + RTCA3_RCR2);
writeb(rcr2 & ~RTCA3_RCR2_START, priv->base + RTCA3_RCR2);
ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
!(tmp & RTCA3_RCR2_START),
10, RTCA3_DEFAULT_TIMEOUT_US);
if (ret)
return ret;
/* Update time. */
writeb(bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECCNT);
writeb(bin2bcd(tm->tm_min), priv->base + RTCA3_RMINCNT);
writeb(bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRCNT);
writeb(bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKCNT);
writeb(bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYCNT);
writeb(bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONCNT);
writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRCNT);
/* Make sure we can read back the counters. */
rtca3_prepare_cntalrm_regs_for_read(priv, true);
/* Start RTC. */
writeb(rcr2 | RTCA3_RCR2_START, priv->base + RTCA3_RCR2);
return readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
(tmp & RTCA3_RCR2_START),
10, RTCA3_DEFAULT_TIMEOUT_US);
}
static int rtca3_alarm_irq_set_helper(struct rtca3_priv *priv,
u8 interrupts,
unsigned int enabled)
{
u8 tmp, val;
if (enabled) {
/*
* AIE, CIE, PIE bit indexes in RSR corresponds with
* those on RCR1. Same interrupts mask can be used.
*/
rtca3_byte_update_bits(priv, RTCA3_RSR, interrupts, 0);
val = interrupts;
} else {
val = 0;
}
rtca3_byte_update_bits(priv, RTCA3_RCR1, interrupts, val);
return readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
((tmp & interrupts) == val),
10, RTCA3_IRQSET_TIMEOUT_US);
}
static int rtca3_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
guard(spinlock_irqsave)(&priv->lock);
return rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, enabled);
}
static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
u8 sec, min, hour, wday, mday, month;
struct rtc_time *tm = &wkalrm->time;
u32 year100;
u16 year;
guard(spinlock_irqsave)(&priv->lock);
sec = readb(priv->base + RTCA3_RSECAR);
min = readb(priv->base + RTCA3_RMINAR);
hour = readb(priv->base + RTCA3_RHRAR);
wday = readb(priv->base + RTCA3_RWKAR);
mday = readb(priv->base + RTCA3_RDAYAR);
month = readb(priv->base + RTCA3_RMONAR);
year = readw(priv->base + RTCA3_RYRAR);
tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECAR_SEC, sec));
tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINAR_MIN, min));
tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRAR_HR, hour));
tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKAR_DAYW, wday));
tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYAR_DATE, mday));
tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONAR_MON, month)) - 1;
year = FIELD_GET(RTCA3_RYRAR_YR, year);
year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
wkalrm->enabled = !!(readb(priv->base + RTCA3_RCR1) & RTCA3_RCR1_AIE);
return 0;
}
static int rtca3_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
struct rtc_time *tm = &wkalrm->time;
u8 rcr1, tmp;
int ret;
scoped_guard(spinlock_irqsave, &priv->lock) {
tmp = readb(priv->base + RTCA3_RCR2);
if (!(tmp & RTCA3_RCR2_START))
return -EPERM;
/* Disable AIE to prevent false interrupts. */
rcr1 = readb(priv->base + RTCA3_RCR1);
rcr1 &= ~RTCA3_RCR1_AIE;
writeb(rcr1, priv->base + RTCA3_RCR1);
ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
!(tmp & RTCA3_RCR1_AIE),
10, RTCA3_DEFAULT_TIMEOUT_US);
if (ret)
return ret;
/* Set the time and enable the alarm. */
writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECAR);
writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_min), priv->base + RTCA3_RMINAR);
writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRAR);
writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKAR);
writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYAR);
writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONAR);
writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRAR);
writeb(RTCA3_AR_ENB, priv->base + RTCA3_RYRAREN);
/* Make sure we can read back the counters. */
rtca3_prepare_cntalrm_regs_for_read(priv, false);
/* Need to wait for 2 * 1/64 periodic interrupts to be generated. */
atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_INIT);
reinit_completion(&priv->set_alarm_completion);
/* Enable periodic interrupt. */
rcr1 |= RTCA3_RCR1_PIE;
writeb(rcr1, priv->base + RTCA3_RCR1);
ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
(tmp & RTCA3_RCR1_PIE),
10, RTCA3_IRQSET_TIMEOUT_US);
}
if (ret)
goto setup_failed;
/* Wait for the 2 * 1/64 periodic interrupts. */
ret = wait_for_completion_interruptible_timeout(&priv->set_alarm_completion,
msecs_to_jiffies(500));
if (ret <= 0) {
ret = -ETIMEDOUT;
goto setup_failed;
}
scoped_guard(spinlock_irqsave, &priv->lock) {
ret = rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, wkalrm->enabled);
atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
}
return ret;
setup_failed:
scoped_guard(spinlock_irqsave, &priv->lock) {
/*
* Disable PIE to avoid interrupt storm in case HW needed more than
* specified timeout for setup.
*/
writeb(rcr1 & ~RTCA3_RCR1_PIE, priv->base + RTCA3_RCR1);
readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & ~RTCA3_RCR1_PIE),
10, RTCA3_DEFAULT_TIMEOUT_US);
atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
}
return ret;
}
static int rtca3_read_offset(struct device *dev, long *offset)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
u8 val, radj, cycles;
u32 ppb_per_cycle;
scoped_guard(spinlock_irqsave, &priv->lock) {
radj = readb(priv->base + RTCA3_RADJ);
val = readb(priv->base + RTCA3_RCR2);
}
cycles = FIELD_GET(RTCA3_RADJ_ADJ, radj);
if (!cycles) {
*offset = 0;
return 0;
}
if (val & RTCA3_RCR2_ADJP)
ppb_per_cycle = priv->ppb.ten_sec;
else
ppb_per_cycle = priv->ppb.sixty_sec;
*offset = cycles * ppb_per_cycle;
val = FIELD_GET(RTCA3_RADJ_PMADJ, radj);
if (val == RTCA3_RADJ_PMADJ_SUB)
*offset = -(*offset);
return 0;
}
static int rtca3_set_offset(struct device *dev, long offset)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
int cycles, cycles10, cycles60;
u8 radj, adjp, tmp;
int ret;
/*
* Automatic time error adjustment could be set at intervals of 10
* or 60 seconds.
*/
cycles10 = DIV_ROUND_CLOSEST(offset, priv->ppb.ten_sec);
cycles60 = DIV_ROUND_CLOSEST(offset, priv->ppb.sixty_sec);
/* We can set b/w 1 and 63 clock cycles. */
if (cycles60 >= -RTCA3_RADJ_ADJ_MAX &&
cycles60 <= RTCA3_RADJ_ADJ_MAX) {
cycles = cycles60;
adjp = 0;
} else if (cycles10 >= -RTCA3_RADJ_ADJ_MAX &&
cycles10 <= RTCA3_RADJ_ADJ_MAX) {
cycles = cycles10;
adjp = RTCA3_RCR2_ADJP;
} else {
return -ERANGE;
}
radj = FIELD_PREP(RTCA3_RADJ_ADJ, abs(cycles));
if (!cycles)
radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_NONE);
else if (cycles > 0)
radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_ADD);
else
radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_SUB);
guard(spinlock_irqsave)(&priv->lock);
tmp = readb(priv->base + RTCA3_RCR2);
if ((tmp & RTCA3_RCR2_ADJP) != adjp) {
/* RADJ.PMADJ need to be set to zero before setting RCR2.ADJP. */
writeb(0, priv->base + RTCA3_RADJ);
ret = readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, !tmp,
10, RTCA3_DEFAULT_TIMEOUT_US);
if (ret)
return ret;
rtca3_byte_update_bits(priv, RTCA3_RCR2, RTCA3_RCR2_ADJP, adjp);
ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
((tmp & RTCA3_RCR2_ADJP) == adjp),
10, RTCA3_DEFAULT_TIMEOUT_US);
if (ret)
return ret;
}
writeb(radj, priv->base + RTCA3_RADJ);
return readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, (tmp == radj),
10, RTCA3_DEFAULT_TIMEOUT_US);
}
static const struct rtc_class_ops rtca3_ops = {
.read_time = rtca3_read_time,
.set_time = rtca3_set_time,
.read_alarm = rtca3_read_alarm,
.set_alarm = rtca3_set_alarm,
.alarm_irq_enable = rtca3_alarm_irq_enable,
.set_offset = rtca3_set_offset,
.read_offset = rtca3_read_offset,
};
static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv)
{
unsigned long osc32k_rate;
u8 val, tmp, mask;
u32 sleep_us;
int ret;
osc32k_rate = clk_get_rate(clk);
if (!osc32k_rate)
return -EINVAL;
sleep_us = DIV_ROUND_UP_ULL(1000000ULL, osc32k_rate) * 6;
priv->ppb.ten_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 10));
priv->ppb.sixty_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 60));
/*
* According to HW manual (section 22.4.2. Clock and count mode setting procedure)
* we need to wait at least 6 cycles of the 32KHz clock after clock was enabled.
*/
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;
/* Reconfigure the RTC in 24 hours and calendar count mode. */
mask = RTCA3_RCR2_START | RTCA3_RCR2_CNTMD;
writeb(0, priv->base + RTCA3_RCR2);
ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask),
10, RTCA3_DEFAULT_TIMEOUT_US);
if (ret)
return ret;
/*
* Set 24 hours mode. According to HW manual (section 22.3.19. RTC Control
* Register 2) this needs to be done separate from stop operation.
*/
mask = RTCA3_RCR2_HR24;
val = RTCA3_RCR2_HR24;
writeb(val, priv->base + RTCA3_RCR2);
ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, (tmp & mask),
10, RTCA3_DEFAULT_TIMEOUT_US);
if (ret)
return ret;
/* Execute reset. */
mask = RTCA3_RCR2_RESET;
writeb(val | RTCA3_RCR2_RESET, priv->base + RTCA3_RCR2);
ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask),
10, RTCA3_RESET_TIMEOUT_US);
if (ret)
return ret;
/*
* According to HW manual (section 22.6.3. Notes on writing to and reading
* from registers) after reset we need to wait 6 clock cycles before
* writing to RTC registers.
*/
usleep_range(sleep_us, sleep_us + 10);
/* Set no adjustment. */
writeb(0, priv->base + RTCA3_RADJ);
ret = readb_poll_timeout(priv->base + RTCA3_RADJ, tmp, !tmp, 10,
RTCA3_DEFAULT_TIMEOUT_US);
/* Start the RTC and enable automatic time error adjustment. */
mask = RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
val |= RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
writeb(val, priv->base + RTCA3_RCR2);
ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, ((tmp & mask) == mask),
10, RTCA3_START_TIMEOUT_US);
if (ret)
return ret;
/*
* According to HW manual (section 22.6.4. Notes on writing to and reading
* from registers) we need to wait 1/128 seconds while the clock is operating
* (RCR2.START bit = 1) to be able to read the counters after a return from
* reset.
*/
usleep_range(8000, 9000);
/* Set period interrupt to 1/64 seconds. It is necessary for alarm setup. */
val = FIELD_PREP(RTCA3_RCR1_PES, RTCA3_RCR1_PES_1_64_SEC);
rtca3_byte_update_bits(priv, RTCA3_RCR1, RTCA3_RCR1_PES, val);
return readb_poll_timeout(priv->base + RTCA3_RCR1, tmp, ((tmp & RTCA3_RCR1_PES) == val),
10, RTCA3_DEFAULT_TIMEOUT_US);
}
static int rtca3_request_irqs(struct platform_device *pdev, struct rtca3_priv *priv)
{
struct device *dev = &pdev->dev;
int ret, irq;
irq = platform_get_irq_byname(pdev, "alarm");
if (irq < 0)
return dev_err_probe(dev, irq, "Failed to get alarm IRQ!\n");
ret = devm_request_irq(dev, irq, rtca3_alarm_handler, 0, "rtca3-alarm", priv);
if (ret)
return dev_err_probe(dev, ret, "Failed to request alarm IRQ!\n");
priv->wakeup_irq = irq;
irq = platform_get_irq_byname(pdev, "period");
if (irq < 0)
return dev_err_probe(dev, irq, "Failed to get period IRQ!\n");
ret = devm_request_irq(dev, irq, rtca3_periodic_handler, 0, "rtca3-period", priv);
if (ret)
return dev_err_probe(dev, ret, "Failed to request period IRQ!\n");
/*
* Driver doesn't implement carry handler. Just get the IRQ here
* for backward compatibility, in case carry support will be added later.
*/
irq = platform_get_irq_byname(pdev, "carry");
if (irq < 0)
return dev_err_probe(dev, irq, "Failed to get carry IRQ!\n");
return 0;
}
static void rtca3_action(void *data)
{
struct device *dev = data;
struct rtca3_priv *priv = dev_get_drvdata(dev);
int ret;
ret = reset_control_assert(priv->rstc);
if (ret)
dev_err(dev, "Failed to de-assert reset!");
ret = pm_runtime_put_sync(dev);
if (ret < 0)
dev_err(dev, "Failed to runtime suspend!");
}
static int rtca3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rtca3_priv *priv;
struct clk *clk;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
priv->rstc = devm_reset_control_get_shared(dev, NULL);
if (IS_ERR(priv->rstc))
return PTR_ERR(priv->rstc);
ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
ret = reset_control_deassert(priv->rstc);
if (ret) {
pm_runtime_put_sync(dev);
return ret;
}
dev_set_drvdata(dev, priv);
ret = devm_add_action_or_reset(dev, rtca3_action, dev);
if (ret)
return ret;
/*
* This must be an always-on clock to keep the RTC running even after
* driver is unbinded.
*/
clk = devm_clk_get_enabled(dev, "counter");
if (IS_ERR(clk))
return PTR_ERR(clk);
spin_lock_init(&priv->lock);
atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
init_completion(&priv->set_alarm_completion);
ret = rtca3_initial_setup(clk, priv);
if (ret)
return dev_err_probe(dev, ret, "Failed to setup the RTC!\n");
ret = rtca3_request_irqs(pdev, priv);
if (ret)
return ret;
device_init_wakeup(&pdev->dev, 1);
priv->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(priv->rtc_dev))
return PTR_ERR(priv->rtc_dev);
priv->rtc_dev->ops = &rtca3_ops;
priv->rtc_dev->max_user_freq = 256;
priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
return devm_rtc_register_device(priv->rtc_dev);
}
static void rtca3_remove(struct platform_device *pdev)
{
struct rtca3_priv *priv = platform_get_drvdata(pdev);
guard(spinlock_irqsave)(&priv->lock);
/*
* Disable alarm, periodic interrupts. The RTC device cannot
* power up the system.
*/
rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE | RTCA3_RCR1_PIE, 0);
}
static int rtca3_suspend(struct device *dev)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
if (!device_may_wakeup(dev))
return 0;
/* Alarm setup in progress. */
if (atomic_read(&priv->alrm_sstep) != RTCA3_ALRM_SSTEP_DONE)
return -EBUSY;
enable_irq_wake(priv->wakeup_irq);
return 0;
}
static int rtca3_clean_alarm(struct rtca3_priv *priv)
{
struct rtc_device *rtc_dev = priv->rtc_dev;
time64_t alarm_time, now;
struct rtc_wkalrm alarm;
struct rtc_time tm;
u8 pending;
int ret;
ret = rtc_read_alarm(rtc_dev, &alarm);
if (ret)
return ret;
if (!alarm.enabled)
return 0;
ret = rtc_read_time(rtc_dev, &tm);
if (ret)
return ret;
alarm_time = rtc_tm_to_time64(&alarm.time);
now = rtc_tm_to_time64(&tm);
if (alarm_time >= now)
return 0;
/*
* Heuristically, it has been determined that when returning from deep
* sleep state the RTCA3_RSR.AF is zero even though the alarm expired.
* Call again the rtc_update_irq() if alarm helper detects this.
*/
guard(spinlock_irqsave)(&priv->lock);
pending = rtca3_alarm_handler_helper(priv);
if (!pending)
rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);
return 0;
}
static int rtca3_resume(struct device *dev)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
if (!device_may_wakeup(dev))
return 0;
disable_irq_wake(priv->wakeup_irq);
/*
* According to the HW manual (section 22.6.4 Notes on writing to
* and reading from registers) we need to wait 1/128 seconds while
* RCR2.START = 1 to be able to read the counters after a return from low
* power consumption state.
*/
mdelay(8);
/*
* The alarm cannot wake the system from deep sleep states. In case
* we return from deep sleep states and the alarm expired we need
* to disable it to avoid failures when setting another alarm.
*/
return rtca3_clean_alarm(priv);
}
static DEFINE_SIMPLE_DEV_PM_OPS(rtca3_pm_ops, rtca3_suspend, rtca3_resume);
static const struct of_device_id rtca3_of_match[] = {
{ .compatible = "renesas,rz-rtca3", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rtca3_of_match);
static struct platform_driver rtca3_platform_driver = {
.driver = {
.name = "rtc-rtca3",
.pm = pm_ptr(&rtca3_pm_ops),
.of_match_table = rtca3_of_match,
},
.probe = rtca3_probe,
.remove = rtca3_remove,
};
module_platform_driver(rtca3_platform_driver);
MODULE_DESCRIPTION("Renesas RTCA-3 RTC driver");
MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
MODULE_LICENSE("GPL");

View File

@ -228,7 +228,7 @@ static void rtd119x_rtc_remove(struct platform_device *pdev)
static struct platform_driver rtd119x_rtc_driver = { static struct platform_driver rtd119x_rtc_driver = {
.probe = rtd119x_rtc_probe, .probe = rtd119x_rtc_probe,
.remove_new = rtd119x_rtc_remove, .remove = rtd119x_rtc_remove,
.driver = { .driver = {
.name = "rtd1295-rtc", .name = "rtd1295-rtc",
.of_match_table = rtd119x_rtc_dt_ids, .of_match_table = rtd119x_rtc_dt_ids,

View File

@ -120,8 +120,9 @@ static ssize_t timestamp0_show(struct device *dev,
{ {
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent); struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
struct rtc_time tm; struct rtc_time tm;
int ret, count; unsigned int count;
u8 date[6]; u8 date[6];
int ret;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count); ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret) if (ret)
@ -156,7 +157,8 @@ static ssize_t timestamp0_count_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent); struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
int ret, count; unsigned int count;
int ret;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count); ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret) if (ret)

View File

@ -7,7 +7,7 @@
* - 2022 Schneider Electric * - 2022 Schneider Electric
* *
* Authors: * Authors:
* - Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com> * - Michel Pollet <buserror@gmail.com>
* - Miquel Raynal <miquel.raynal@bootlin.com> * - Miquel Raynal <miquel.raynal@bootlin.com>
*/ */
@ -35,13 +35,13 @@
#define RZN1_RTC_CTL2_WUST BIT(5) #define RZN1_RTC_CTL2_WUST BIT(5)
#define RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST) #define RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST)
#define RZN1_RTC_SEC 0x14 #define RZN1_RTC_TIME 0x30
#define RZN1_RTC_MIN 0x18 #define RZN1_RTC_TIME_MIN_SHIFT 8
#define RZN1_RTC_HOUR 0x1c #define RZN1_RTC_TIME_HOUR_SHIFT 16
#define RZN1_RTC_WEEK 0x20 #define RZN1_RTC_CAL 0x34
#define RZN1_RTC_DAY 0x24 #define RZN1_RTC_CAL_DAY_SHIFT 8
#define RZN1_RTC_MONTH 0x28 #define RZN1_RTC_CAL_MON_SHIFT 16
#define RZN1_RTC_YEAR 0x2c #define RZN1_RTC_CAL_YEAR_SHIFT 24
#define RZN1_RTC_SUBU 0x38 #define RZN1_RTC_SUBU 0x38
#define RZN1_RTC_SUBU_DEV BIT(7) #define RZN1_RTC_SUBU_DEV BIT(7)
@ -52,12 +52,8 @@
#define RZN1_RTC_ALW 0x48 #define RZN1_RTC_ALW 0x48
#define RZN1_RTC_SECC 0x4c #define RZN1_RTC_SECC 0x4c
#define RZN1_RTC_MINC 0x50 #define RZN1_RTC_TIMEC 0x68
#define RZN1_RTC_HOURC 0x54 #define RZN1_RTC_CALC 0x6c
#define RZN1_RTC_WEEKC 0x58
#define RZN1_RTC_DAYC 0x5c
#define RZN1_RTC_MONTHC 0x60
#define RZN1_RTC_YEARC 0x64
struct rzn1_rtc { struct rzn1_rtc {
struct rtc_device *rtcdev; struct rtc_device *rtcdev;
@ -66,26 +62,18 @@ struct rzn1_rtc {
static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm) static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
{ {
tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC); u32 val;
tm->tm_min = readl(rtc->base + RZN1_RTC_MINC);
tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC);
tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC);
tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC);
tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC);
tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC);
}
static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm) val = readl(rtc->base + RZN1_RTC_TIMEC);
{ tm->tm_sec = bcd2bin(val);
time64_t time; tm->tm_min = bcd2bin(val >> RZN1_RTC_TIME_MIN_SHIFT);
unsigned int days; tm->tm_hour = bcd2bin(val >> RZN1_RTC_TIME_HOUR_SHIFT);
u32 secs;
time = rtc_tm_to_time64(tm); val = readl(rtc->base + RZN1_RTC_CALC);
days = div_s64_rem(time, 86400, &secs); tm->tm_wday = val & 0x0f;
tm->tm_mday = bcd2bin(val >> RZN1_RTC_CAL_DAY_SHIFT);
/* day of the week, 1970-01-01 was a Thursday */ tm->tm_mon = bcd2bin(val >> RZN1_RTC_CAL_MON_SHIFT) - 1;
return (days + 4) % 7; tm->tm_year = bcd2bin(val >> RZN1_RTC_CAL_YEAR_SHIFT) + 100;
} }
static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm) static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
@ -103,17 +91,9 @@ static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
rzn1_rtc_get_time_snapshot(rtc, tm); rzn1_rtc_get_time_snapshot(rtc, tm);
secs = readl(rtc->base + RZN1_RTC_SECC); secs = readl(rtc->base + RZN1_RTC_SECC);
if (tm->tm_sec != secs) if (tm->tm_sec != bcd2bin(secs))
rzn1_rtc_get_time_snapshot(rtc, tm); rzn1_rtc_get_time_snapshot(rtc, tm);
tm->tm_sec = bcd2bin(tm->tm_sec);
tm->tm_min = bcd2bin(tm->tm_min);
tm->tm_hour = bcd2bin(tm->tm_hour);
tm->tm_wday = bcd2bin(tm->tm_wday);
tm->tm_mday = bcd2bin(tm->tm_mday);
tm->tm_mon = bcd2bin(tm->tm_mon);
tm->tm_year = bcd2bin(tm->tm_year);
return 0; return 0;
} }
@ -123,14 +103,6 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
u32 val; u32 val;
int ret; int ret;
tm->tm_sec = bin2bcd(tm->tm_sec);
tm->tm_min = bin2bcd(tm->tm_min);
tm->tm_hour = bin2bcd(tm->tm_hour);
tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm));
tm->tm_mday = bin2bcd(tm->tm_mday);
tm->tm_mon = bin2bcd(tm->tm_mon);
tm->tm_year = bin2bcd(tm->tm_year);
val = readl(rtc->base + RZN1_RTC_CTL2); val = readl(rtc->base + RZN1_RTC_CTL2);
if (!(val & RZN1_RTC_CTL2_STOPPED)) { if (!(val & RZN1_RTC_CTL2_STOPPED)) {
/* Hold the counter if it was counting up */ /* Hold the counter if it was counting up */
@ -144,13 +116,17 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
return ret; return ret;
} }
writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC); val = bin2bcd(tm->tm_sec);
writel(tm->tm_min, rtc->base + RZN1_RTC_MIN); val |= bin2bcd(tm->tm_min) << RZN1_RTC_TIME_MIN_SHIFT;
writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR); val |= bin2bcd(tm->tm_hour) << RZN1_RTC_TIME_HOUR_SHIFT;
writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK); writel(val, rtc->base + RZN1_RTC_TIME);
writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY);
writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH); val = tm->tm_wday;
writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR); val |= bin2bcd(tm->tm_mday) << RZN1_RTC_CAL_DAY_SHIFT;
val |= bin2bcd(tm->tm_mon + 1) << RZN1_RTC_CAL_MON_SHIFT;
val |= bin2bcd(tm->tm_year - 100) << RZN1_RTC_CAL_YEAR_SHIFT;
writel(val, rtc->base + RZN1_RTC_CAL);
writel(0, rtc->base + RZN1_RTC_CTL2); writel(0, rtc->base + RZN1_RTC_CTL2);
return 0; return 0;
@ -405,7 +381,7 @@ MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match);
static struct platform_driver rzn1_rtc_driver = { static struct platform_driver rzn1_rtc_driver = {
.probe = rzn1_rtc_probe, .probe = rzn1_rtc_probe,
.remove_new = rzn1_rtc_remove, .remove = rzn1_rtc_remove,
.driver = { .driver = {
.name = "rzn1-rtc", .name = "rzn1-rtc",
.of_match_table = rzn1_rtc_of_match, .of_match_table = rzn1_rtc_of_match,
@ -413,7 +389,7 @@ static struct platform_driver rzn1_rtc_driver = {
}; };
module_platform_driver(rzn1_rtc_driver); module_platform_driver(rzn1_rtc_driver);
MODULE_AUTHOR("Michel Pollet <Michel.Pollet@bp.renesas.com"); MODULE_AUTHOR("Michel Pollet <buserror@gmail.com>");
MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com"); MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
MODULE_DESCRIPTION("RZ/N1 RTC driver"); MODULE_DESCRIPTION("RZ/N1 RTC driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -597,7 +597,7 @@ MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
static struct platform_driver s3c_rtc_driver = { static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe, .probe = s3c_rtc_probe,
.remove_new = s3c_rtc_remove, .remove = s3c_rtc_remove,
.driver = { .driver = {
.name = "s3c-rtc", .name = "s3c-rtc",
.pm = &s3c_rtc_pm_ops, .pm = &s3c_rtc_pm_ops,

View File

@ -341,7 +341,7 @@ MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
static struct platform_driver sa1100_rtc_driver = { static struct platform_driver sa1100_rtc_driver = {
.probe = sa1100_rtc_probe, .probe = sa1100_rtc_probe,
.remove_new = sa1100_rtc_remove, .remove = sa1100_rtc_remove,
.driver = { .driver = {
.name = "sa1100-rtc", .name = "sa1100-rtc",
.pm = &sa1100_rtc_pm_ops, .pm = &sa1100_rtc_pm_ops,

View File

@ -678,7 +678,7 @@ static struct platform_driver sh_rtc_platform_driver __refdata = {
.pm = &sh_rtc_pm_ops, .pm = &sh_rtc_pm_ops,
.of_match_table = sh_rtc_of_match, .of_match_table = sh_rtc_of_match,
}, },
.remove_new = __exit_p(sh_rtc_remove), .remove = __exit_p(sh_rtc_remove),
}; };
module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe); module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe);

View File

@ -475,7 +475,7 @@ MODULE_DEVICE_TABLE(of, spear_rtc_id_table);
static struct platform_driver spear_rtc_driver = { static struct platform_driver spear_rtc_driver = {
.probe = spear_rtc_probe, .probe = spear_rtc_probe,
.remove_new = spear_rtc_remove, .remove = spear_rtc_remove,
.shutdown = spear_rtc_shutdown, .shutdown = spear_rtc_shutdown,
.driver = { .driver = {
.name = "rtc-spear", .name = "rtc-spear",

View File

@ -218,15 +218,14 @@ static int st_rtc_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler, 0, ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler,
pdev->name, rtc); IRQF_NO_AUTOEN, pdev->name, rtc);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq); dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq);
return ret; return ret;
} }
enable_irq_wake(rtc->irq); enable_irq_wake(rtc->irq);
disable_irq(rtc->irq);
rtc->clk = devm_clk_get_enabled(&pdev->dev, NULL); rtc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(rtc->clk)) if (IS_ERR(rtc->clk))

View File

@ -1287,7 +1287,7 @@ static const struct dev_pm_ops stm32_rtc_pm_ops = {
static struct platform_driver stm32_rtc_driver = { static struct platform_driver stm32_rtc_driver = {
.probe = stm32_rtc_probe, .probe = stm32_rtc_probe,
.remove_new = stm32_rtc_remove, .remove = stm32_rtc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.pm = &stm32_rtc_pm_ops, .pm = &stm32_rtc_pm_ops,

View File

@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(of, rtc_dt_ids);
static struct platform_driver stmp3xxx_rtcdrv = { static struct platform_driver stmp3xxx_rtcdrv = {
.probe = stmp3xxx_rtc_probe, .probe = stmp3xxx_rtc_probe,
.remove_new = stmp3xxx_rtc_remove, .remove = stmp3xxx_rtc_remove,
.driver = { .driver = {
.name = "stmp3xxx-rtc", .name = "stmp3xxx-rtc",
.pm = &stmp3xxx_rtc_pm_ops, .pm = &stmp3xxx_rtc_pm_ops,

View File

@ -344,7 +344,7 @@ static SIMPLE_DEV_PM_OPS(sp_rtc_pm_ops, sp_rtc_suspend, sp_rtc_resume);
static struct platform_driver sp_rtc_driver = { static struct platform_driver sp_rtc_driver = {
.probe = sp_rtc_probe, .probe = sp_rtc_probe,
.remove_new = sp_rtc_remove, .remove = sp_rtc_remove,
.driver = { .driver = {
.name = "sp7021-rtc", .name = "sp7021-rtc",
.of_match_table = sp_rtc_of_match, .of_match_table = sp_rtc_of_match,

View File

@ -399,7 +399,7 @@ static void tegra_rtc_shutdown(struct platform_device *pdev)
static struct platform_driver tegra_rtc_driver = { static struct platform_driver tegra_rtc_driver = {
.probe = tegra_rtc_probe, .probe = tegra_rtc_probe,
.remove_new = tegra_rtc_remove, .remove = tegra_rtc_remove,
.shutdown = tegra_rtc_shutdown, .shutdown = tegra_rtc_shutdown,
.driver = { .driver = {
.name = "tegra_rtc", .name = "tegra_rtc",

View File

@ -317,7 +317,7 @@ static struct platform_driver tps6586x_rtc_driver = {
.pm = &tps6586x_pm_ops, .pm = &tps6586x_pm_ops,
}, },
.probe = tps6586x_rtc_probe, .probe = tps6586x_rtc_probe,
.remove_new = tps6586x_rtc_remove, .remove = tps6586x_rtc_remove,
}; };
module_platform_driver(tps6586x_rtc_driver); module_platform_driver(tps6586x_rtc_driver);

View File

@ -673,7 +673,7 @@ MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
static struct platform_driver twl4030rtc_driver = { static struct platform_driver twl4030rtc_driver = {
.probe = twl_rtc_probe, .probe = twl_rtc_probe,
.remove_new = twl_rtc_remove, .remove = twl_rtc_remove,
.shutdown = twl_rtc_shutdown, .shutdown = twl_rtc_shutdown,
.driver = { .driver = {
.name = "twl_rtc", .name = "twl_rtc",

View File

@ -251,7 +251,7 @@ MODULE_DEVICE_TABLE(of, wmt_dt_ids);
static struct platform_driver vt8500_rtc_driver = { static struct platform_driver vt8500_rtc_driver = {
.probe = vt8500_rtc_probe, .probe = vt8500_rtc_probe,
.remove_new = vt8500_rtc_remove, .remove = vt8500_rtc_remove,
.driver = { .driver = {
.name = "vt8500-rtc", .name = "vt8500-rtc",
.of_match_table = wmt_dt_ids, .of_match_table = wmt_dt_ids,

View File

@ -459,7 +459,7 @@ static SIMPLE_DEV_PM_OPS(wm8350_rtc_pm_ops, wm8350_rtc_suspend,
static struct platform_driver wm8350_rtc_driver = { static struct platform_driver wm8350_rtc_driver = {
.probe = wm8350_rtc_probe, .probe = wm8350_rtc_probe,
.remove_new = wm8350_rtc_remove, .remove = wm8350_rtc_remove,
.driver = { .driver = {
.name = "wm8350-rtc", .name = "wm8350-rtc",
.pm = &wm8350_rtc_pm_ops, .pm = &wm8350_rtc_pm_ops,

View File

@ -263,7 +263,7 @@ MODULE_DEVICE_TABLE(of, xgene_rtc_of_match);
static struct platform_driver xgene_rtc_driver = { static struct platform_driver xgene_rtc_driver = {
.probe = xgene_rtc_probe, .probe = xgene_rtc_probe,
.remove_new = xgene_rtc_remove, .remove = xgene_rtc_remove,
.driver = { .driver = {
.name = "xgene-rtc", .name = "xgene-rtc",
.pm = &xgene_rtc_pm_ops, .pm = &xgene_rtc_pm_ops,

View File

@ -382,7 +382,7 @@ MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match);
static struct platform_driver xlnx_rtc_driver = { static struct platform_driver xlnx_rtc_driver = {
.probe = xlnx_rtc_probe, .probe = xlnx_rtc_probe,
.remove_new = xlnx_rtc_remove, .remove = xlnx_rtc_remove,
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.pm = &xlnx_rtc_pm_ops, .pm = &xlnx_rtc_pm_ops,

View File

@ -31,6 +31,15 @@
#define PM886_INT_WC BIT(1) #define PM886_INT_WC BIT(1)
#define PM886_INT_MASK_MODE BIT(2) #define PM886_INT_MASK_MODE BIT(2)
#define PM886_REG_RTC_CNT1 0xd1
#define PM886_REG_RTC_CNT2 0xd2
#define PM886_REG_RTC_CNT3 0xd3
#define PM886_REG_RTC_CNT4 0xd4
#define PM886_REG_RTC_SPARE1 0xea
#define PM886_REG_RTC_SPARE2 0xeb
#define PM886_REG_RTC_SPARE3 0xec
#define PM886_REG_RTC_SPARE4 0xed
#define PM886_REG_RTC_SPARE5 0xee
#define PM886_REG_RTC_SPARE6 0xef #define PM886_REG_RTC_SPARE6 0xef
#define PM886_REG_BUCK_EN 0x08 #define PM886_REG_BUCK_EN 0x08

View File

@ -56,6 +56,9 @@ struct m48t59_plat_data {
void __iomem *ioaddr; void __iomem *ioaddr;
/* offset to RTC registers, automatically set according to the type */ /* offset to RTC registers, automatically set according to the type */
unsigned int offset; unsigned int offset;
/* YY digits (in RTC) are offset, i.e. year is 1900 + yy_offset + YY */
int yy_offset;
}; };
#endif /* _LINUX_RTC_M48T59_H_ */ #endif /* _LINUX_RTC_M48T59_H_ */