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,sun8i-h3-rtc
- items:
- const: allwinner,sun20i-d1-rtc
- enum:
- allwinner,sun20i-d1-rtc
- allwinner,sun55i-a523-rtc
- const: allwinner,sun50i-r329-rtc
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)
%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#
@ -12,12 +12,14 @@ allOf:
maintainers:
- Daire McNamara <daire.mcnamara@microchip.com>
- Lewis Hanly <lewis.hanly@microchip.com>
properties:
compatible:
enum:
- microchip,mpfs-rtc
oneOf:
- items:
- const: microchip,pic64gx-rtc
- const: microchip,mpfs-rtc
- const: microchip,mpfs-rtc
reg:
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: 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
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
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/mfd/88pm886.c
F: drivers/regulator/88pm886-regulator.c
F: drivers/rtc/rtc-88pm886.c
F: include/linux/mfd/88pm886.h
MARVELL ARMADA 3700 PHY DRIVERS
@ -19915,6 +19924,14 @@ S: Supported
F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml
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
M: Clément Léger <clement.leger@bootlin.com>
L: linux-renesas-soc@vger.kernel.org

View File

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

View File

@ -391,6 +391,7 @@ CONFIG_UHID=m
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set
CONFIG_RTC_DRV_M48T59=y
CONFIG_RTC_DRV_GENERIC=m
# CONFIG_VIRTIO_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_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set
CONFIG_RTC_DRV_M48T59=y
CONFIG_RTC_DRV_GENERIC=m
# CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set

View File

@ -4,24 +4,7 @@
#include <asm/irq.h>
typedef struct {
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)
#define MVME147_RTC_BASE 0xfffe0000
struct pcc_regs {
volatile u_long dma_tadr;

View File

@ -24,23 +24,7 @@ typedef struct {
#define mvmelp ((*(volatile MVMElpPtr)(MVME_LPR_BASE)))
typedef struct {
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_RTC_BASE 0xfffc0000
#define MVME_I596_BASE 0xfff46000

View File

@ -19,8 +19,9 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/rtc.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/rtc/m48t59.h>
#include <asm/bootinfo.h>
#include <asm/bootinfo-vme.h>
@ -36,13 +37,9 @@
static void mvme147_get_model(char *model);
static void __init mvme147_sched_init(void);
extern int mvme147_hwclk (int, struct rtc_time *);
extern void mvme147_reset (void);
static int bcd2int (unsigned char b);
int __init mvme147_parse_bootinfo(const struct bi_record *bi)
{
uint16_t tag = be16_to_cpu(bi->tag);
@ -80,7 +77,6 @@ void __init config_mvme147(void)
{
mach_sched_init = mvme147_sched_init;
mach_init_IRQ = mvme147_init_IRQ;
mach_hwclk = mvme147_hwclk;
mach_reset = mvme147_reset;
mach_get_model = mvme147_get_model;
@ -89,6 +85,28 @@ void __init config_mvme147(void)
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 struct clocksource mvme147_clk = {
@ -162,31 +180,6 @@ static u64 mvme147_read_clk(struct clocksource *cs)
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)
{
__asm__ __volatile__ ("nop; nop;");

View File

@ -3,4 +3,4 @@
# 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/init.h>
#include <linux/major.h>
#include <linux/rtc.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc/m48t59.h>
#include <asm/bootinfo.h>
#include <asm/bootinfo-vme.h>
@ -39,16 +40,10 @@
extern t_bdid mvme_bdid;
static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
static void mvme16x_get_model(char *model);
extern void mvme16x_sched_init(void);
extern int mvme16x_hwclk (int, struct rtc_time *);
extern void mvme16x_reset (void);
int bcd2int (unsigned char b);
unsigned short mvme16x_config;
EXPORT_SYMBOL(mvme16x_config);
@ -268,7 +263,6 @@ void __init config_mvme16x(void)
mach_sched_init = mvme16x_sched_init;
mach_init_IRQ = mvme16x_init_IRQ;
mach_hwclk = mvme16x_hwclk;
mach_reset = mvme16x_reset;
mach_get_model = mvme16x_get_model;
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)
{
unsigned long *new = (unsigned long *)vectors;
@ -426,28 +442,3 @@ static u64 mvme16x_read_clk(struct clocksource *cs)
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 = {
.read_byte = mostek_read_byte,
.write_byte = mostek_write_byte,
.yy_offset = 68,
};
/* 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 = {
.read_byte = mostek_read_byte,
.write_byte = mostek_write_byte,
.yy_offset = 68,
};
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
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
select REGMAP_I2C
tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
@ -496,6 +506,7 @@ config RTC_DRV_PCF85363
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
select REGMAP_I2C
help
If you say yes here you get support for the
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
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"
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
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

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_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_88PM886) += rtc-88pm886.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABEOZ9) += rtc-ab-eoz9.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.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_AS3722) += rtc-as3722.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_RX8581) += rtc-rx8581.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_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.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;
ktime_t now;
struct rtc_time tm;
int err;
struct rtc_device *rtc =
container_of(work, struct rtc_device, irqwork);
mutex_lock(&rtc->ops_lock);
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);
while ((next = timerqueue_getnext(&rtc->timerqueue))) {
if (next->expires > now)

View File

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

View File

@ -371,7 +371,7 @@ static struct platform_driver pm860x_rtc_driver = {
.pm = &pm860x_rtc_pm_ops,
},
.probe = pm860x_rtc_probe,
.remove_new = pm860x_rtc_remove,
.remove = pm860x_rtc_remove,
};
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_REG_ALARM_HOURS 0x12
#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_BIT_ALARM_DAYS GENMASK(5, 0)
#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_min = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_MIN, regs[1]));
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]));
@ -396,13 +394,6 @@ static int abeoz9z3_temp_read(struct device *dev,
if (ret < 0)
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) {
case hwmon_temp_input:
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",
},
.probe = ab8500_rtc_probe,
.remove_new = ab8500_rtc_remove,
.remove = ab8500_rtc_remove,
.id_table = ab85xx_rtc_ids,
};

View File

@ -39,7 +39,7 @@
#define ABX8XX_REG_STATUS 0x0f
#define ABX8XX_STATUS_AF BIT(2)
#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_CTRL_WRITE BIT(0)

View File

@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, ac100_rtc_match);
static struct platform_driver ac100_rtc_driver = {
.probe = ac100_rtc_probe,
.remove_new = ac100_rtc_remove,
.remove = ac100_rtc_remove,
.driver = {
.name = "ac100-rtc",
.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 = {
.probe = asm9260_rtc_probe,
.remove_new = asm9260_rtc_remove,
.remove = asm9260_rtc_remove,
.driver = {
.name = "asm9260-rtc",
.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.
*/
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,
.driver = {
.name = "at91_rtc",

View File

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

View File

@ -17,7 +17,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_wakeup.h>
#include <linux/reboot.h>
#include <linux/rtc.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 = {
.probe = brcmstb_waketmr_probe,
.remove_new = brcmstb_waketmr_remove,
.remove = brcmstb_waketmr_remove,
.driver = {
.name = "brcmstb-waketimer",
.pm = &brcmstb_waketmr_pm_ops,

View File

@ -402,7 +402,7 @@ static struct platform_driver cdns_rtc_driver = {
.pm = &cdns_rtc_pm_ops,
},
.probe = cdns_rtc_probe,
.remove_new = cdns_rtc_remove,
.remove = cdns_rtc_remove,
};
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;
off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock);
for (; count; count--, off++) {
for (; count; count--, off++, buf++) {
guard(spinlock_irq)(&rtc_lock);
if (off < 128)
*buf++ = CMOS_READ(off);
*buf = CMOS_READ(off);
else if (can_bank2)
*buf++ = cmos_read_bank2(off);
*buf = cmos_read_bank2(off);
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,
@ -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.
*/
off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock);
for (; count; count--, off++) {
for (; count; count--, off++, buf++) {
/* don't trash RTC registers */
if (off == cmos->day_alrm
|| off == cmos->mon_alrm
|| off == cmos->century)
buf++;
else if (off < 128)
CMOS_WRITE(*buf++, off);
else if (can_bank2)
cmos_write_bank2(*buf++, off);
else
break;
}
spin_unlock_irq(&rtc_lock);
continue;
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");
static struct platform_driver cmos_platform_driver = {
.remove_new = cmos_platform_remove,
.remove = cmos_platform_remove,
.shutdown = cmos_platform_shutdown,
.driver = {
.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 = {
.probe = cros_ec_rtc_probe,
.remove_new = cros_ec_rtc_remove,
.remove = cros_ec_rtc_remove,
.driver = {
.name = DRV_NAME,
.pm = &cros_ec_rtc_pm_ops,

View File

@ -1354,7 +1354,7 @@ static struct platform_driver ds1685_rtc_driver = {
.name = "rtc-ds1685",
},
.probe = ds1685_rtc_probe,
.remove_new = ds1685_rtc_remove,
.remove = ds1685_rtc_remove,
};
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,
},
.probe = ftrtc010_rtc_probe,
.remove_new = ftrtc010_rtc_remove,
.remove = ftrtc010_rtc_remove,
};
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,
},
.probe = hid_time_probe,
.remove_new = hid_time_remove,
.remove = hid_time_remove,
};
module_platform_driver(hid_time_platform_driver);

View File

@ -860,7 +860,7 @@ static struct platform_driver dryice_rtc_driver __refdata = {
.name = "imxdi_rtc",
.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);

View File

@ -21,7 +21,7 @@
#include <asm/byteorder.h>
/* ISL register offsets */
/* RTC - Real time clock registers */
#define ISL12022_REG_SC 0x00
#define ISL12022_REG_MN 0x01
#define ISL12022_REG_HR 0x02
@ -30,21 +30,36 @@
#define ISL12022_REG_YR 0x05
#define ISL12022_REG_DW 0x06
/* CSR - Control and status registers */
#define ISL12022_REG_SR 0x07
#define ISL12022_REG_INT 0x08
#define ISL12022_REG_PWR_VBAT 0x0a
#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
/* ISL register bits */
#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_LBAT75 (1 << 1)
#define ISL12022_INT_ARST (1 << 7)
#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_OFF 0x0
#define ISL12022_INT_FO_32K 0x1
@ -52,8 +67,19 @@
#define ISL12022_REG_VB85_MASK GENMASK(5, 3)
#define ISL12022_REG_VB75_MASK GENMASK(2, 0)
#define ISL12022_ALARM_ENABLE (1 << 7) /* for all ALARM registers */
#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,
enum hwmon_sensor_types type,
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)
{
struct regmap *regmap = dev_get_drvdata(dev);
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
struct device *hwmon;
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)
{
struct regmap *regmap = dev_get_drvdata(dev);
uint8_t buf[ISL12022_REG_INT + 1];
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u8 buf[ISL12022_REG_INT + 1];
int ret;
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)
{
struct regmap *regmap = dev_get_drvdata(dev);
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
int ret;
uint8_t buf[ISL12022_REG_DW + 1];
u8 buf[ISL12022_REG_DW + 1];
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));
}
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)
{
struct regmap *regmap = dev_get_drvdata(dev);
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u32 user, val;
int ret;
@ -238,6 +456,9 @@ static const struct rtc_class_ops isl12022_rtc_ops = {
.ioctl = isl12022_rtc_ioctl,
.read_time = isl12022_rtc_read_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 = {
@ -248,7 +469,8 @@ static const struct regmap_config regmap_config = {
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;
int ret;
@ -288,7 +510,8 @@ static const u32 trip_levels[2][7] = {
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};
int ret, i, j, x[2];
u8 val, mask;
@ -325,6 +548,7 @@ static void isl12022_set_trip_levels(struct device *dev)
static int isl12022_probe(struct i2c_client *client)
{
struct isl12022 *isl12022;
struct rtc_device *rtc;
struct regmap *regmap;
int ret;
@ -332,13 +556,17 @@ static int isl12022_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "regmap allocation failed\n");
return PTR_ERR(regmap);
}
/* Allocate driver state */
isl12022 = devm_kzalloc(&client->dev, sizeof(*isl12022), GFP_KERNEL);
if (!isl12022)
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);
if (ret)
@ -350,11 +578,20 @@ static int isl12022_probe(struct i2c_client *client)
rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
isl12022->rtc = rtc;
rtc->ops = &isl12022_rtc_ops;
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
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);
}

View File

@ -381,7 +381,7 @@ MODULE_DEVICE_TABLE(acpi, loongson_rtc_acpi_match);
static struct platform_driver loongson_rtc_driver = {
.probe = loongson_rtc_probe,
.remove_new = loongson_rtc_remove,
.remove = loongson_rtc_remove,
.driver = {
.name = "loongson-rtc",
.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 = {
.probe = lpc24xx_rtc_probe,
.remove_new = lpc24xx_rtc_remove,
.remove = lpc24xx_rtc_remove,
.driver = {
.name = "lpc24xx-rtc",
.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 */
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->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
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");
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_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);
unsigned long flags;
u8 val = 0;
int year = tm->tm_year;
#ifdef CONFIG_SPARC
/* Sun SPARC machines count years since 1968 */
year -= 68;
#endif
int year = tm->tm_year - pdata->yy_offset;
dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n",
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 */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
#ifdef CONFIG_SPARC
/* Sun SPARC machines count years since 1968 */
tm->tm_year += 68;
#endif
tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset;
/* tm_mon is 0-11 */
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;
u8 mday, hour, min, sec;
unsigned long flags;
int year = tm->tm_year;
#ifdef CONFIG_SPARC
/* Sun SPARC machines count years since 1968 */
year -= 68;
#endif
int year = tm->tm_year - pdata->yy_offset;
/* If no irq, we don't support ALARM */
if (m48t59->irq == NO_IRQ)

View File

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

View File

@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
static struct platform_driver mc13xxx_rtc_driver = {
.id_table = mc13xxx_rtc_idtable,
.remove_new = mc13xxx_rtc_remove,
.remove = mc13xxx_rtc_remove,
.driver = {
.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 int yrs;
#ifdef CONFIG_MACH_DECSTATION
unsigned int real_yrs, leap_yr;
unsigned int real_yrs;
#endif
unsigned char century = 0;
@ -232,8 +232,6 @@ int mc146818_set_time(struct rtc_time *time)
#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
!((yrs + 1900) % 400));
yrs = 72;
/*
@ -241,7 +239,7 @@ int mc146818_set_time(struct rtc_time *time)
* for non-leap years, so that Feb, 29th is handled
* correctly.
*/
if (!leap_yr && mon < 3) {
if (!is_leap_year(real_yrs + 1900) && mon < 3) {
real_yrs--;
yrs = 73;
}

View File

@ -398,7 +398,7 @@ static struct platform_driver mpc5121_rtc_driver = {
.of_match_table = of_match_ptr(mpc5121_rtc_match),
},
.probe = mpc5121_rtc_probe,
.remove_new = mpc5121_rtc_remove,
.remove = mpc5121_rtc_remove,
};
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 = {
.probe = mpfs_rtc_probe,
.remove_new = mpfs_rtc_remove,
.remove = mpfs_rtc_remove,
.driver = {
.name = "mpfs_rtc",
.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_hour = data[RTC_OFFSET_HOUR];
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_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)
{
time64_t time;
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
int days, sec, ret;
int sec, ret;
do {
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;
} while (sec < tm->tm_sec);
/* HW register use 7 bits to store year data, minus
* 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. */
/* HW register start mon/wday from one, but tm_mon/tm_wday start from zero. */
tm->tm_mon--;
time = rtc_tm_to_time64(tm);
/* 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;
tm->tm_wday--;
exit:
return ret;
@ -122,13 +110,14 @@ static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
int ret;
u16 data[RTC_OFFSET_COUNT];
tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++;
tm->tm_wday++;
data[RTC_OFFSET_SEC] = tm->tm_sec;
data[RTC_OFFSET_MIN] = tm->tm_min;
data[RTC_OFFSET_HOUR] = tm->tm_hour;
data[RTC_OFFSET_DOM] = tm->tm_mday;
data[RTC_OFFSET_DOW] = tm->tm_wday;
data[RTC_OFFSET_MTH] = tm->tm_mon;
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_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK;
tm->tm_year += RTC_MIN_YEAR_OFFSET;
tm->tm_mon--;
return 0;
@ -194,7 +182,6 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
int ret;
u16 data[RTC_OFFSET_COUNT];
tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++;
mutex_lock(&rtc->lock);
@ -302,6 +289,10 @@ static int mtk_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
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);
}

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 = {
.probe = mtk_rtc_probe,
.remove_new = mtk_rtc_remove,
.remove = mtk_rtc_remove,
.driver = {
.name = MTK_RTC_DEV,
.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.
*/
static struct platform_driver mv_rtc_driver __refdata = {
.remove_new = __exit_p(mv_rtc_remove),
.remove = __exit_p(mv_rtc_remove),
.driver = {
.name = "rtc-mv",
.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,
},
.probe = mxc_rtc_probe,
.remove_new = mxc_rtc_remove,
.remove = mxc_rtc_remove,
};
module_platform_driver(mxc_rtc_driver);

View File

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

View File

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

View File

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

View File

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

View File

@ -11,14 +11,15 @@
* 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/rtc.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.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_ST2 0x01
@ -77,64 +78,18 @@ struct pcf8563 {
*/
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
struct clk_hw clkout_hw;
#endif
};
static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg,
unsigned char length, unsigned char *buf)
static int pcf8563_set_alarm_mode(struct pcf8563 *pcf8563, bool on)
{
struct i2c_msg msgs[] = {
{/* 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;
u32 buf;
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)
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);
err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return -EIO;
}
return 0;
return regmap_write(pcf8563->regmap, PCF8563_REG_ST2, buf);
}
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 buf;
u32 buf;
int err;
err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
if (err)
err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf);
if (err < 0)
return err;
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)
{
struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id);
int err;
struct pcf8563 *pcf8563 = dev_id;
char pending;
int err;
err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending);
err = pcf8563_get_alarm_mode(pcf8563, NULL, &pending);
if (err)
return IRQ_NONE;
if (pending) {
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;
}
@ -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)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[9];
int err;
err = pcf8563_read_block_data(client, PCF8563_REG_ST1, 9, buf);
if (err)
err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_ST1, buf,
sizeof(buf));
if (err < 0)
return err;
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
dev_err(&client->dev,
dev_err(dev,
"low voltage detected, date/time is not reliable.\n");
return -EINVAL;
}
dev_dbg(&client->dev,
dev_dbg(dev,
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
__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[8]);
tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
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) ?
(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",
__func__,
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)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
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",
__func__,
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;
return pcf8563_write_block_data(client, PCF8563_REG_SC,
9 - PCF8563_REG_SC, buf + PCF8563_REG_SC);
return regmap_bulk_write(pcf8563->regmap, 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)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
int ret;
switch (cmd) {
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)
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);
default:
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)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4];
int err;
err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf);
if (err)
err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_AMN, buf,
sizeof(buf));
if (err < 0)
return err;
dev_dbg(&client->dev,
dev_dbg(dev,
"%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
__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_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)
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,
tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday,
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)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4];
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[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)
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)
{
struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
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
@ -366,10 +319,10 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client;
unsigned char buf;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
u32 buf;
int ret;
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return 0;
@ -393,11 +346,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client;
unsigned char buf;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
int i;
int i, ret;
u32 buf;
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@ -405,10 +357,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] == rate) {
buf &= ~PCF8563_REG_CLKO_F_MASK;
buf |= i;
ret = pcf8563_write_block_data(client,
PCF8563_REG_CLKO, 1,
&buf);
return ret;
return regmap_update_bits(pcf8563->regmap,
PCF8563_REG_CLKO,
PCF8563_REG_CLKO_F_MASK,
buf);
}
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)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client;
unsigned char buf;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
u32 buf;
int ret;
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@ -429,8 +381,8 @@ static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
else
buf &= ~PCF8563_REG_CLKO_FE;
ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
return ret;
return regmap_update_bits(pcf8563->regmap, PCF8563_REG_CLKO,
PCF8563_REG_CLKO_FE, buf);
}
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)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
struct i2c_client *client = pcf8563->client;
unsigned char buf;
int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
u32 buf;
int ret;
ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@ -467,16 +419,14 @@ static const struct clk_ops pcf8563_clkout_ops = {
static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
{
struct i2c_client *client = pcf8563->client;
struct device_node *node = client->dev.of_node;
struct clk *clk;
struct device_node *node = pcf8563->rtc->dev.of_node;
struct clk_init_data init;
struct clk *clk;
int ret;
unsigned char buf;
/* disable the clkout output */
buf = 0;
ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
ret = regmap_clear_bits(pcf8563->regmap, PCF8563_REG_CLKO,
PCF8563_REG_CLKO_FE);
if (ret < 0)
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);
/* 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))
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,
};
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xF,
};
static int pcf8563_probe(struct i2c_client *client)
{
struct pcf8563 *pcf8563;
int err;
unsigned char buf;
dev_dbg(&client->dev, "%s\n", __func__);
@ -525,20 +480,23 @@ static int pcf8563_probe(struct i2c_client *client)
if (!pcf8563)
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);
pcf8563->client = client;
device_set_wakeup_capable(&client->dev, 1);
/* Set timer to lowest frequency to save power (ref Haoyu datasheet) */
buf = PCF8563_TMRC_1_60;
err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf);
err = regmap_set_bits(pcf8563->regmap, PCF8563_REG_TMRC,
PCF8563_TMRC_1_60);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return err;
}
/* Clear flags and disable interrupts */
buf = 0;
err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
err = regmap_write(pcf8563->regmap, PCF8563_REG_ST2, 0);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return err;

View File

@ -371,7 +371,7 @@ MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids);
static struct platform_driver pic32_rtc_driver = {
.probe = pic32_rtc_probe,
.remove_new = pic32_rtc_remove,
.remove = pic32_rtc_remove,
.driver = {
.name = "pic32-rtc",
.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 = {
.probe = pm8xxx_rtc_probe,
.remove_new = pm8xxx_remove,
.remove = pm8xxx_remove,
.driver = {
.name = "rtc-pm8xxx",
.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.
*/
static struct platform_driver pxa_rtc_driver __refdata = {
.remove_new = __exit_p(pxa_rtc_remove),
.remove = __exit_p(pxa_rtc_remove),
.driver = {
.name = "pxa-rtc",
.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 = {
.probe = rc5t583_rtc_probe,
.remove_new = rc5t583_rtc_remove,
.remove = rc5t583_rtc_remove,
.driver = {
.name = "rtc-rc5t583",
.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 = {
.probe = rtd119x_rtc_probe,
.remove_new = rtd119x_rtc_remove,
.remove = rtd119x_rtc_remove,
.driver = {
.name = "rtd1295-rtc",
.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 rtc_time tm;
int ret, count;
unsigned int count;
u8 date[6];
int ret;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret)
@ -156,7 +157,8 @@ static ssize_t timestamp0_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
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);
if (ret)

View File

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

View File

@ -597,7 +597,7 @@ MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove_new = s3c_rtc_remove,
.remove = s3c_rtc_remove,
.driver = {
.name = "s3c-rtc",
.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 = {
.probe = sa1100_rtc_probe,
.remove_new = sa1100_rtc_remove,
.remove = sa1100_rtc_remove,
.driver = {
.name = "sa1100-rtc",
.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,
.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);

View File

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

View File

@ -218,15 +218,14 @@ static int st_rtc_probe(struct platform_device *pdev)
return -EINVAL;
}
ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler, 0,
pdev->name, rtc);
ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler,
IRQF_NO_AUTOEN, pdev->name, rtc);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq);
return ret;
}
enable_irq_wake(rtc->irq);
disable_irq(rtc->irq);
rtc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
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 = {
.probe = stm32_rtc_probe,
.remove_new = stm32_rtc_remove,
.remove = stm32_rtc_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &stm32_rtc_pm_ops,

View File

@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(of, rtc_dt_ids);
static struct platform_driver stmp3xxx_rtcdrv = {
.probe = stmp3xxx_rtc_probe,
.remove_new = stmp3xxx_rtc_remove,
.remove = stmp3xxx_rtc_remove,
.driver = {
.name = "stmp3xxx-rtc",
.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 = {
.probe = sp_rtc_probe,
.remove_new = sp_rtc_remove,
.remove = sp_rtc_remove,
.driver = {
.name = "sp7021-rtc",
.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 = {
.probe = tegra_rtc_probe,
.remove_new = tegra_rtc_remove,
.remove = tegra_rtc_remove,
.shutdown = tegra_rtc_shutdown,
.driver = {
.name = "tegra_rtc",

View File

@ -317,7 +317,7 @@ static struct platform_driver tps6586x_rtc_driver = {
.pm = &tps6586x_pm_ops,
},
.probe = tps6586x_rtc_probe,
.remove_new = tps6586x_rtc_remove,
.remove = tps6586x_rtc_remove,
};
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 = {
.probe = twl_rtc_probe,
.remove_new = twl_rtc_remove,
.remove = twl_rtc_remove,
.shutdown = twl_rtc_shutdown,
.driver = {
.name = "twl_rtc",

View File

@ -251,7 +251,7 @@ MODULE_DEVICE_TABLE(of, wmt_dt_ids);
static struct platform_driver vt8500_rtc_driver = {
.probe = vt8500_rtc_probe,
.remove_new = vt8500_rtc_remove,
.remove = vt8500_rtc_remove,
.driver = {
.name = "vt8500-rtc",
.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 = {
.probe = wm8350_rtc_probe,
.remove_new = wm8350_rtc_remove,
.remove = wm8350_rtc_remove,
.driver = {
.name = "wm8350-rtc",
.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 = {
.probe = xgene_rtc_probe,
.remove_new = xgene_rtc_remove,
.remove = xgene_rtc_remove,
.driver = {
.name = "xgene-rtc",
.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 = {
.probe = xlnx_rtc_probe,
.remove_new = xlnx_rtc_remove,
.remove = xlnx_rtc_remove,
.driver = {
.name = KBUILD_MODNAME,
.pm = &xlnx_rtc_pm_ops,

View File

@ -31,6 +31,15 @@
#define PM886_INT_WC BIT(1)
#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_BUCK_EN 0x08

View File

@ -56,6 +56,9 @@ struct m48t59_plat_data {
void __iomem *ioaddr;
/* offset to RTC registers, automatically set according to the type */
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_ */