RTC for 4.15

Subsystem:
  - Fix setting the alarm to the next expiring timer
 
 New driver:
  - Mediatek MT7622 RTC
  - NXP PCF85363
  - Spreadtrum SC27xx PMIC RTC
 
 Drivers:
  - Use generic nvmem to expose the Non volatile ram for ds1305, ds1511,
  m48t86 and omap
  - abx80x: solve possible race condition at probe
  - armada38x: support trimming the RTC oscillator
  - at91rm9200: fix reading the alarm value at boot
  - ds1511: allow waking platform
  - m41t80: rework square wave output
  - pcf8523: support trimming the RTC oscillator
  - pcf8563: fix clock output rate
  - pl031: make interrupt optional
  - xgene: fix suspend/resume
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEXx9Viay1+e7J/aM4AyWl4gNJNJIFAloTT70ACgkQAyWl4gNJ
 NJL7GhAAlHf/F+u4EfDyr7Rv4p0NlQrfmWVK021P4IuSyKispdQnCGWE0ZQJ2g6w
 8gNICyBiHubGVVwH9cHV3EhdCQ9DFqmMFrBn/+qbmRW2/U2pT0DuVk4u3TUHxBot
 e16T//k6xlT3vPjm5WYN/VZGKa2lxTio+EfSI914+LxBqs38YmKvwppTpWSIggQJ
 alGizKce+LZ/maORb11+GF+fgeXXek6gll0aJZQZW+JLbt0huQOBrOup8WrfWsrO
 Zj9fK6Xzzu0mAPhbu9D+keInLl1vavDdqWit/xYBOOXjsSRwU83e2NMHsZcTxIO5
 wU6qHZqK12fprOz+cl6xvXIy1jAAvPtpqGCTg/ssRsJTm52IuoqiCDuvJ84oAiNF
 TSFCxar0DHzAIQOP2rcWUdEEm7wPYfNn1XWR3KZ38pUKwxqa9PBKcT1Uro0naklL
 f7VHe/ZZJm/a7vgW8FunSXaSIvlbB8/ggC1aWpGpTXLJs1sTmg8vTv5Z+dSrkqa1
 ZJQd+YQgjIsxHNpoLqOHhho/oSun5c/YKzoc2eN/LSwKGv1jgCEi1v4iWNrv3pnS
 i12wef6mOrzg4iDKHx8rRXlkrb6wRgGG6ZB+yxIKjwB0ndUeSF9fCBkRBfgkyd5Q
 N3tHcqg2kbZaV1xl8stVkMrxbwtKHb3jTDH90e1SpzpoFXdjGXY=
 =tRVi
 -----END PGP SIGNATURE-----

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

Pull RTC updates from Alexandre Belloni:
 "There is nothing scary this cycle, mostly driver fixes and updates.

  The core fix has been in for a while and has been tested on multiple
  kernel revisions by multiple teams.

  Core:
   - Fix setting the alarm to the next expiring timer

  New drivers:
   - Mediatek MT7622 RTC
   - NXP PCF85363
   - Spreadtrum SC27xx PMIC RTC

  Drivers updates:
   - Use generic nvmem to expose the Non volatile ram for ds1305,
     ds1511, m48t86 and omap
   - abx80x: solve possible race condition at probe
   - armada38x: support trimming the RTC oscillator
   - at91rm9200: fix reading the alarm value at boot
   - ds1511: allow waking platform
   - m41t80: rework square wave output
   - pcf8523: support trimming the RTC oscillator
   - pcf8563: fix clock output rate
   - pl031: make interrupt optional
   - xgene: fix suspend/resume"

* tag 'rtc-4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (50 commits)
  dt-bindings: rtc: imxdi: Improve the bindings text
  rtc: sc27xx: Add Spreadtrum SC27xx PMIC RTC driver
  dt-bindings: rtc: Add Spreadtrum SC27xx RTC documentation
  rtc: at91rm9200: fix reading alarm value
  rtc: at91rm9200: stop calculating yday in at91_rtc_readalarm
  rtc: sysfs: Use time64_t variables to set time/alarm
  rtc: xgene: mark PM functions as __maybe_unused
  rtc: xgene: Fix suspend/resume
  rtc: pcf8563: don't alway enable the alarm
  rtc: pcf8563: fix output clock rate
  rtc: rx8010: Fix for incorrect return value
  rtc: rx8010: Specify correct address for RX8010_RESV31
  rtc: rx8010: Remove duplicate define
  rtc: m41t80: remove unneeded checks from m41t80_sqw_set_rate
  rtc: m41t80: avoid i2c read in m41t80_sqw_is_prepared
  rtc: m41t80: avoid i2c read in m41t80_sqw_recalc_rate
  rtc: m41t80: fix m41t80_sqw_round_rate return value
  rtc: m41t80: m41t80_sqw_set_rate should return 0 on success
  rtc: add support for NXP PCF85363 real-time clock
  rtc: omap: Support scratch registers
  ...
This commit is contained in:
Linus Torvalds 2017-11-22 20:58:23 -10:00
commit 1b8c5cd890
30 changed files with 1891 additions and 283 deletions

View File

@ -1,20 +1,20 @@
* i.MX25 Real Time Clock controller
This binding supports the following chips: i.MX25, i.MX53
Required properties:
- compatible: should be: "fsl,imx25-rtc"
- reg: physical base address of the controller and length of memory mapped
region.
- clocks: should contain the phandle for the rtc clock
- interrupts: rtc alarm interrupt
Optional properties:
- interrupts: dryice security violation interrupt
- interrupts: dryice security violation interrupt (second entry)
Example:
rtc@80056000 {
compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
reg = <0x80056000 2000>;
interrupts = <29 56>;
rtc@53ffc000 {
compatible = "fsl,imx25-rtc";
reg = <0x53ffc000 0x4000>;
clocks = <&clks 81>;
interrupts = <25 56>;
};

View File

@ -0,0 +1,17 @@
NXP PCF85363 Real Time Clock
============================
Required properties:
- compatible: Should contain "nxp,pcf85363".
- reg: I2C address for chip.
Optional properties:
- interrupts: IRQ line for the RTC (not implemented).
Example:
pcf85363: pcf85363@51 {
compatible = "nxp,pcf85363";
reg = <0x51>;
};

View File

@ -0,0 +1,21 @@
Device-Tree bindings for MediaTek SoC based RTC
Required properties:
- compatible : Should be
"mediatek,mt7622-rtc", "mediatek,soc-rtc" : for MT7622 SoC
- reg : Specifies base physical address and size of the registers;
- interrupts : Should contain the interrupt for RTC alarm;
- clocks : Specifies list of clock specifiers, corresponding to
entries in clock-names property;
- clock-names : Should contain "rtc" entries
Example:
rtc: rtc@10212800 {
compatible = "mediatek,mt7622-rtc",
"mediatek,soc-rtc";
reg = <0 0x10212800 0 0x200>;
interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>;
clocks = <&topckgen CLK_TOP_RTC>;
clock-names = "rtc";
};

View File

@ -0,0 +1,27 @@
Spreadtrum SC27xx Real Time Clock
Required properties:
- compatible: should be "sprd,sc2731-rtc".
- reg: address offset of rtc register.
- interrupt-parent: phandle for the interrupt controller.
- interrupts: rtc alarm interrupt.
Example:
sc2731_pmic: pmic@0 {
compatible = "sprd,sc2731";
reg = <0>;
spi-max-frequency = <26000000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <0>;
rtc@280 {
compatible = "sprd,sc2731-rtc";
reg = <0x280>;
interrupt-parent = <&sc2731_pmic>;
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
};
};

View File

@ -72,7 +72,6 @@ maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6621 PECI-to-I2C translator for PECI-to-SMBus/I2C protocol conversion
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
mc,rv3029c2 Real Time Clock Module with I2C-Bus
mcube,mc3230 mCube 3-axis 8-bit digital accelerometer
memsic,mxc6225 MEMSIC 2-axis 8-bit digital accelerometer
microchip,mcp4531-502 Microchip 7-bit Single I2C Digital Potentiometer (5k)
@ -141,6 +140,7 @@ microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Mem
microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k)
microchip,tc654 PWM Fan Speed Controller With Fan Fault Detection
microchip,tc655 PWM Fan Speed Controller With Fan Fault Detection
microcrystal,rv3029 Real Time Clock Module with I2C-Bus
miramems,da226 MiraMEMS DA226 2-axis 14-bit digital accelerometer
miramems,da280 MiraMEMS DA280 3-axis 14-bit digital accelerometer
miramems,da311 MiraMEMS DA311 3-axis 12-bit digital accelerometer

View File

@ -1590,10 +1590,13 @@ F: drivers/rtc/rtc-armada38x.c
ARM/Mediatek RTC DRIVER
M: Eddie Huang <eddie.huang@mediatek.com>
M: Sean Wang <sean.wang@mediatek.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/rtc/rtc-mt7622.txt
F: drivers/rtc/rtc-mt6397.c
F: drivers/rtc/rtc-mt7622.c
ARM/Mediatek SoC support
M: Matthias Brugger <matthias.bgg@gmail.com>

View File

@ -433,6 +433,19 @@ config RTC_DRV_PCF85063
This driver can also be built as a module. If so, the module
will be called rtc-pcf85063.
config RTC_DRV_PCF85363
tristate "NXP PCF85363"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for the PCF85363 RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-pcf85363.
The nvmem interface will be named pcf85363-#, where # is the
zero-based instance number.
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
help
@ -1174,6 +1187,17 @@ config RTC_DRV_WM8350
This driver can also be built as a module. If so, the module
will be called "rtc-wm8350".
config RTC_DRV_SC27XX
tristate "Spreadtrum SC27xx RTC"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
help
If you say Y here you will get support for the RTC subsystem
of the Spreadtrum SC27xx series PMICs. The SC27xx series PMICs
includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips.
This driver can also be built as a module. If so, the module
will be called rtc-sc27xx.
config RTC_DRV_SPEAR
tristate "SPEAR ST RTC"
depends on PLAT_SPEAR || COMPILE_TEST
@ -1706,14 +1730,24 @@ config RTC_DRV_MOXART
will be called rtc-moxart
config RTC_DRV_MT6397
tristate "Mediatek Real Time Clock driver"
tristate "MediaTek PMIC based RTC"
depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
help
This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
This selects the MediaTek(R) RTC driver. RTC is part of MediaTek
MT6397 PMIC. You should enable MT6397 PMIC MFD before select
Mediatek(R) RTC driver.
MediaTek(R) RTC driver.
If you want to use Mediatek(R) RTC interface, select Y or M here.
If you want to use MediaTek(R) RTC interface, select Y or M here.
config RTC_DRV_MT7622
tristate "MediaTek SoC based RTC"
depends on ARCH_MEDIATEK || COMPILE_TEST
help
This enables support for the real time clock built in the MediaTek
SoCs.
This drive can also be built as a module. If so, the module
will be called rtc-mt7622.
config RTC_DRV_XGENE
tristate "APM X-Gene RTC"

View File

@ -103,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
@ -114,6 +115,7 @@ obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
@ -144,6 +146,7 @@ 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_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o

View File

@ -779,7 +779,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
}
timerqueue_add(&rtc->timerqueue, &timer->node);
if (!next) {
if (!next || ktime_before(timer->node.expires, next->expires)) {
struct rtc_wkalrm alarm;
int err;
alarm.time = rtc_ktime_to_tm(timer->node.expires);
@ -1004,6 +1004,10 @@ int rtc_read_offset(struct rtc_device *rtc, long *offset)
* to compensate for differences in the actual clock rate due to temperature,
* the crystal, capacitor, etc.
*
* The adjustment applied is as follows:
* t = t0 * (1 + offset * 1e-9)
* where t0 is the measured length of 1 RTC second with offset = 0
*
* Kernel interface to adjust an rtc clock offset.
* Return 0 on success, or a negative number on error.
* If the rtc offset is not setable (or not implemented), return -EINVAL

View File

@ -614,12 +614,12 @@ static int abx80x_probe(struct i2c_client *client,
if (err)
return err;
rtc = devm_rtc_device_register(&client->dev, "abx8xx",
&abx80x_rtc_ops, THIS_MODULE);
rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
rtc->ops = &abx80x_rtc_ops;
i2c_set_clientdata(client, rtc);
if (client->irq > 0) {
@ -646,10 +646,14 @@ static int abx80x_probe(struct i2c_client *client,
err = devm_add_action_or_reset(&client->dev,
rtc_calib_remove_sysfs_group,
&client->dev);
if (err)
if (err) {
dev_err(&client->dev,
"Failed to add sysfs cleanup action: %d\n",
err);
return err;
}
err = rtc_register_device(rtc);
return err;
}

View File

@ -28,6 +28,8 @@
#define RTC_IRQ_AL_EN BIT(0)
#define RTC_IRQ_FREQ_EN BIT(1)
#define RTC_IRQ_FREQ_1HZ BIT(2)
#define RTC_CCR 0x18
#define RTC_CCR_MODE BIT(15)
#define RTC_TIME 0xC
#define RTC_ALARM1 0x10
@ -343,18 +345,117 @@ static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
return IRQ_HANDLED;
}
/*
* The information given in the Armada 388 functional spec is complex.
* They give two different formulas for calculating the offset value,
* but when considering "Offset" as an 8-bit signed integer, they both
* reduce down to (we shall rename "Offset" as "val" here):
*
* val = (f_ideal / f_measured - 1) / resolution where f_ideal = 32768
*
* Converting to time, f = 1/t:
* val = (t_measured / t_ideal - 1) / resolution where t_ideal = 1/32768
*
* => t_measured / t_ideal = val * resolution + 1
*
* "offset" in the RTC interface is defined as:
* t = t0 * (1 + offset * 1e-9)
* where t is the desired period, t0 is the measured period with a zero
* offset, which is t_measured above. With t0 = t_measured and t = t_ideal,
* offset = (t_ideal / t_measured - 1) / 1e-9
*
* => t_ideal / t_measured = offset * 1e-9 + 1
*
* so:
*
* offset * 1e-9 + 1 = 1 / (val * resolution + 1)
*
* We want "resolution" to be an integer, so resolution = R * 1e-9, giving
* offset = 1e18 / (val * R + 1e9) - 1e9
* val = (1e18 / (offset + 1e9) - 1e9) / R
* with a common transformation:
* f(x) = 1e18 / (x + 1e9) - 1e9
* offset = f(val * R)
* val = f(offset) / R
*
* Armada 38x supports two modes, fine mode (954ppb) and coarse mode (3815ppb).
*/
static long armada38x_ppb_convert(long ppb)
{
long div = ppb + 1000000000L;
return div_s64(1000000000000000000LL + div / 2, div) - 1000000000L;
}
static int armada38x_rtc_read_offset(struct device *dev, long *offset)
{
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
unsigned long ccr, flags;
long ppb_cor;
spin_lock_irqsave(&rtc->lock, flags);
ccr = rtc->data->read_rtc_reg(rtc, RTC_CCR);
spin_unlock_irqrestore(&rtc->lock, flags);
ppb_cor = (ccr & RTC_CCR_MODE ? 3815 : 954) * (s8)ccr;
/* ppb_cor + 1000000000L can never be zero */
*offset = armada38x_ppb_convert(ppb_cor);
return 0;
}
static int armada38x_rtc_set_offset(struct device *dev, long offset)
{
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
unsigned long ccr = 0;
long ppb_cor, off;
/*
* The maximum ppb_cor is -128 * 3815 .. 127 * 3815, but we
* need to clamp the input. This equates to -484270 .. 488558.
* Not only is this to stop out of range "off" but also to
* avoid the division by zero in armada38x_ppb_convert().
*/
offset = clamp(offset, -484270L, 488558L);
ppb_cor = armada38x_ppb_convert(offset);
/*
* Use low update mode where possible, which gives a better
* resolution of correction.
*/
off = DIV_ROUND_CLOSEST(ppb_cor, 954);
if (off > 127 || off < -128) {
ccr = RTC_CCR_MODE;
off = DIV_ROUND_CLOSEST(ppb_cor, 3815);
}
/*
* Armada 388 requires a bit pattern in bits 14..8 depending on
* the sign bit: { 0, ~S, S, S, S, S, S }
*/
ccr |= (off & 0x3fff) ^ 0x2000;
rtc_delayed_write(ccr, rtc, RTC_CCR);
return 0;
}
static const struct rtc_class_ops armada38x_rtc_ops = {
.read_time = armada38x_rtc_read_time,
.set_time = armada38x_rtc_set_time,
.read_alarm = armada38x_rtc_read_alarm,
.set_alarm = armada38x_rtc_set_alarm,
.alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
.read_offset = armada38x_rtc_read_offset,
.set_offset = armada38x_rtc_set_offset,
};
static const struct rtc_class_ops armada38x_rtc_ops_noirq = {
.read_time = armada38x_rtc_read_time,
.set_time = armada38x_rtc_set_time,
.read_alarm = armada38x_rtc_read_alarm,
.read_offset = armada38x_rtc_read_offset,
.set_offset = armada38x_rtc_set_offset,
};
static const struct armada38x_rtc_data armada38x_data = {

View File

@ -42,8 +42,6 @@
#define at91_rtc_write(field, val) \
writel_relaxed((val), at91_rtc_regs + field)
#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
struct at91_rtc_config {
bool use_shadow_imr;
};
@ -51,7 +49,6 @@ struct at91_rtc_config {
static const struct at91_rtc_config *at91_rtc_config;
static DECLARE_COMPLETION(at91_rtc_updated);
static DECLARE_COMPLETION(at91_rtc_upd_rdy);
static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
static void __iomem *at91_rtc_regs;
static int irq;
static DEFINE_SPINLOCK(at91_rtc_lock);
@ -131,8 +128,7 @@ static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
/*
* The Calendar Alarm register does not have a field for
* the year - so these will return an invalid value. When an
* alarm is set, at91_alarm_year will store the current year.
* the year - so these will return an invalid value.
*/
tm->tm_year = bcd2bin(date & AT91_RTC_CENT) * 100; /* century */
tm->tm_year += bcd2bin((date & AT91_RTC_YEAR) >> 8); /* year */
@ -208,15 +204,14 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time;
at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = at91_alarm_year - 1900;
tm->tm_year = -1;
alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
? 1 : 0;
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
dev_dbg(dev, "%s(): %02d-%02d %02d:%02d:%02d %sabled\n", __func__,
tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
alrm->enabled ? "en" : "dis");
return 0;
}
@ -230,8 +225,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
at91_alarm_year = tm.tm_year;
tm.tm_mon = alrm->time.tm_mon;
tm.tm_mday = alrm->time.tm_mday;
tm.tm_hour = alrm->time.tm_hour;
@ -255,7 +248,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
}
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
return 0;

View File

@ -514,56 +514,43 @@ static void msg_init(struct spi_message *m, struct spi_transfer *x,
spi_message_add_tail(x, m);
}
static ssize_t
ds1305_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
static int ds1305_nvram_read(void *priv, unsigned int off, void *buf,
size_t count)
{
struct spi_device *spi;
struct ds1305 *ds1305 = priv;
struct spi_device *spi = ds1305->spi;
u8 addr;
struct spi_message m;
struct spi_transfer x[2];
int status;
spi = to_spi_device(kobj_to_dev(kobj));
addr = DS1305_NVRAM + off;
msg_init(&m, x, &addr, count, NULL, buf);
status = spi_sync(spi, &m);
if (status < 0)
dev_err(&spi->dev, "nvram %s error %d\n", "read", status);
return (status < 0) ? status : count;
return spi_sync(spi, &m);
}
static ssize_t
ds1305_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
static int ds1305_nvram_write(void *priv, unsigned int off, void *buf,
size_t count)
{
struct spi_device *spi;
struct ds1305 *ds1305 = priv;
struct spi_device *spi = ds1305->spi;
u8 addr;
struct spi_message m;
struct spi_transfer x[2];
int status;
spi = to_spi_device(kobj_to_dev(kobj));
addr = (DS1305_WRITE | DS1305_NVRAM) + off;
msg_init(&m, x, &addr, count, buf, NULL);
status = spi_sync(spi, &m);
if (status < 0)
dev_err(&spi->dev, "nvram %s error %d\n", "write", status);
return (status < 0) ? status : count;
return spi_sync(spi, &m);
}
static struct bin_attribute nvram = {
.attr.name = "nvram",
.attr.mode = S_IRUGO | S_IWUSR,
.read = ds1305_nvram_read,
.write = ds1305_nvram_write,
static struct nvmem_config ds1305_nvmem_cfg = {
.name = "ds1305_nvram",
.word_size = 1,
.stride = 1,
.size = DS1305_NVRAM_LEN,
.reg_read = ds1305_nvram_read,
.reg_write = ds1305_nvram_write,
};
/*----------------------------------------------------------------------*/
@ -708,10 +695,19 @@ static int ds1305_probe(struct spi_device *spi)
dev_dbg(&spi->dev, "AM/PM\n");
/* register RTC ... from here on, ds1305->ctrl needs locking */
ds1305->rtc = devm_rtc_device_register(&spi->dev, "ds1305",
&ds1305_ops, THIS_MODULE);
ds1305->rtc = devm_rtc_allocate_device(&spi->dev);
if (IS_ERR(ds1305->rtc)) {
status = PTR_ERR(ds1305->rtc);
return PTR_ERR(ds1305->rtc);
}
ds1305->rtc->ops = &ds1305_ops;
ds1305_nvmem_cfg.priv = ds1305;
ds1305->rtc->nvmem_config = &ds1305_nvmem_cfg;
ds1305->rtc->nvram_old_abi = true;
status = rtc_register_device(ds1305->rtc);
if (status) {
dev_dbg(&spi->dev, "register rtc --> %d\n", status);
return status;
}
@ -734,12 +730,6 @@ static int ds1305_probe(struct spi_device *spi)
}
}
/* export NVRAM */
status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);
if (status < 0) {
dev_err(&spi->dev, "register nvram --> %d\n", status);
}
return 0;
}
@ -747,8 +737,6 @@ static int ds1305_remove(struct spi_device *spi)
{
struct ds1305 *ds1305 = spi_get_drvdata(spi);
sysfs_remove_bin_file(&spi->dev.kobj, &nvram);
/* carefully shut down irq and workqueue, if present */
if (spi->irq) {
set_bit(FLAG_EXITING, &ds1305->flags);

View File

@ -325,6 +325,10 @@ static const struct of_device_id ds1307_of_match[] = {
.compatible = "isil,isl12057",
.data = (void *)ds_1337
},
{
.compatible = "epson,rx8130",
.data = (void *)rx_8130
},
{ }
};
MODULE_DEVICE_TABLE(of, ds1307_of_match);
@ -348,6 +352,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = {
{ .id = "PT7C4338", .driver_data = ds_1307 },
{ .id = "RX8025", .driver_data = rx_8025 },
{ .id = "ISL12057", .driver_data = ds_1337 },
{ .id = "RX8130", .driver_data = rx_8130 },
{ }
};
MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
@ -787,8 +792,6 @@ static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled)
* Alarm support for mcp794xx devices.
*/
#define MCP794XX_REG_WEEKDAY 0x3
#define MCP794XX_REG_WEEKDAY_WDAY_MASK 0x7
#define MCP794XX_REG_CONTROL 0x07
# define MCP794XX_BIT_ALM0_EN 0x10
# define MCP794XX_BIT_ALM1_EN 0x20
@ -877,15 +880,38 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
return 0;
}
/*
* We may have a random RTC weekday, therefore calculate alarm weekday based
* on current weekday we read from the RTC timekeeping regs
*/
static int mcp794xx_alm_weekday(struct device *dev, struct rtc_time *tm_alarm)
{
struct rtc_time tm_now;
int days_now, days_alarm, ret;
ret = ds1307_get_time(dev, &tm_now);
if (ret)
return ret;
days_now = div_s64(rtc_tm_to_time64(&tm_now), 24 * 60 * 60);
days_alarm = div_s64(rtc_tm_to_time64(tm_alarm), 24 * 60 * 60);
return (tm_now.tm_wday + days_alarm - days_now) % 7 + 1;
}
static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
unsigned char regs[10];
int ret;
int wday, ret;
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
wday = mcp794xx_alm_weekday(dev, &t->time);
if (wday < 0)
return wday;
dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
"enabled=%d pending=%d\n", __func__,
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
@ -902,7 +928,7 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
regs[3] = bin2bcd(t->time.tm_sec);
regs[4] = bin2bcd(t->time.tm_min);
regs[5] = bin2bcd(t->time.tm_hour);
regs[6] = bin2bcd(t->time.tm_wday + 1);
regs[6] = wday;
regs[7] = bin2bcd(t->time.tm_mday);
regs[8] = bin2bcd(t->time.tm_mon + 1);
@ -1354,14 +1380,12 @@ static int ds1307_probe(struct i2c_client *client,
{
struct ds1307 *ds1307;
int err = -ENODEV;
int tmp, wday;
int tmp;
const struct chip_desc *chip;
bool want_irq;
bool ds1307_can_wakeup_device = false;
unsigned char regs[8];
struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
struct rtc_time tm;
unsigned long timestamp;
u8 trickle_charger_setup = 0;
ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL);
@ -1641,25 +1665,6 @@ static int ds1307_probe(struct i2c_client *client,
bin2bcd(tmp));
}
/*
* Some IPs have weekday reset value = 0x1 which might not correct
* hence compute the wday using the current date/month/year values
*/
ds1307_get_time(ds1307->dev, &tm);
wday = tm.tm_wday;
timestamp = rtc_tm_to_time64(&tm);
rtc_time64_to_tm(timestamp, &tm);
/*
* Check if reset wday is different from the computed wday
* If different then set the wday which we computed using
* timestamp
*/
if (wday != tm.tm_wday)
regmap_update_bits(ds1307->regmap, MCP794XX_REG_WEEKDAY,
MCP794XX_REG_WEEKDAY_WDAY_MASK,
tm.tm_wday + 1);
if (want_irq || ds1307_can_wakeup_device) {
device_set_wakeup_capable(ds1307->dev, true);
set_bit(HAS_ALARM, &ds1307->flags);

View File

@ -216,9 +216,16 @@ static int ds1390_probe(struct spi_device *spi)
return res;
}
static const struct of_device_id ds1390_of_match[] = {
{ .compatible = "dallas,ds1390" },
{}
};
MODULE_DEVICE_TABLE(of, ds1390_of_match);
static struct spi_driver ds1390_driver = {
.driver = {
.name = "rtc-ds1390",
.of_match_table = of_match_ptr(ds1390_of_match),
},
.probe = ds1390_probe,
};

View File

@ -398,42 +398,37 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
.alarm_irq_enable = ds1511_rtc_alarm_irq_enable,
};
static ssize_t
ds1511_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *ba,
char *buf, loff_t pos, size_t size)
static int ds1511_nvram_read(void *priv, unsigned int pos, void *buf,
size_t size)
{
ssize_t count;
int i;
rtc_write(pos, DS1511_RAMADDR_LSB);
for (count = 0; count < size; count++)
*buf++ = rtc_read(DS1511_RAMDATA);
for (i = 0; i < size; i++)
*(char *)buf++ = rtc_read(DS1511_RAMDATA);
return count;
return 0;
}
static ssize_t
ds1511_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf,
size_t size)
{
ssize_t count;
int i;
rtc_write(pos, DS1511_RAMADDR_LSB);
for (count = 0; count < size; count++)
rtc_write(*buf++, DS1511_RAMDATA);
for (i = 0; i < size; i++)
rtc_write(*(char *)buf++, DS1511_RAMDATA);
return count;
return 0;
}
static struct bin_attribute ds1511_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
},
static struct nvmem_config ds1511_nvmem_cfg = {
.name = "ds1511_nvram",
.word_size = 1,
.stride = 1,
.size = DS1511_RAM_MAX,
.read = ds1511_nvram_read,
.write = ds1511_nvram_write,
.reg_read = ds1511_nvram_read,
.reg_write = ds1511_nvram_write,
};
static int ds1511_rtc_probe(struct platform_device *pdev)
@ -477,11 +472,20 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
spin_lock_init(&pdata->lock);
platform_set_drvdata(pdev, pdata);
pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&ds1511_rtc_ops, THIS_MODULE);
pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(pdata->rtc))
return PTR_ERR(pdata->rtc);
pdata->rtc->ops = &ds1511_rtc_ops;
ds1511_nvmem_cfg.priv = &pdev->dev;
pdata->rtc->nvmem_config = &ds1511_nvmem_cfg;
pdata->rtc->nvram_old_abi = true;
ret = rtc_register_device(pdata->rtc);
if (ret)
return ret;
/*
* if the platform has an interrupt in mind for this device,
* then by all means, set it
@ -496,26 +500,6 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
}
}
ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
if (ret)
dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
ds1511_nvram_attr.attr.name);
return 0;
}
static int ds1511_rtc_remove(struct platform_device *pdev)
{
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
if (pdata->irq > 0) {
/*
* disable the alarm interrupt
*/
rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
rtc_read(RTC_CMD1);
}
return 0;
}
@ -524,7 +508,6 @@ MODULE_ALIAS("platform:ds1511");
static struct platform_driver ds1511_rtc_driver = {
.probe = ds1511_rtc_probe,
.remove = ds1511_rtc_remove,
.driver = {
.name = "ds1511",
},

View File

@ -82,7 +82,7 @@ static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
int timeout = 1000;
int timeout = 10000;
do {
ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
@ -94,7 +94,7 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
int ret, timeout = 1000;
int ret, timeout = 10000;
ret = jz4740_rtc_wait_write_ready(rtc);
if (ret != 0)
@ -368,7 +368,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678);
ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0);
if (ret) {
dev_err(&pdev->dev, "Could not write write to RTC registers\n");
dev_err(&pdev->dev, "Could not write to RTC registers\n");
return ret;
}
}

View File

@ -154,6 +154,8 @@ struct m41t80_data {
struct rtc_device *rtc;
#ifdef CONFIG_COMMON_CLK
struct clk_hw sqw;
unsigned long freq;
unsigned int sqwe;
#endif
};
@ -443,43 +445,40 @@ static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
#ifdef CONFIG_COMMON_CLK
#define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw)
static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
static unsigned long m41t80_decode_freq(int setting)
{
return (setting == 0) ? 0 : (setting == 1) ? M41T80_SQW_MAX_FREQ :
M41T80_SQW_MAX_FREQ >> setting;
}
static unsigned long m41t80_get_freq(struct m41t80_data *m41t80)
{
struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
struct i2c_client *client = m41t80->client;
int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
M41T80_REG_WDAY : M41T80_REG_SQW;
int ret = i2c_smbus_read_byte_data(client, reg_sqw);
unsigned long val = M41T80_SQW_MAX_FREQ;
if (ret < 0)
return 0;
return m41t80_decode_freq(ret >> 4);
}
ret >>= 4;
if (ret == 0)
val = 0;
else if (ret > 1)
val = val / (1 << ret);
return val;
static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return sqw_to_m41t80_data(hw)->freq;
}
static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
int i, freq = M41T80_SQW_MAX_FREQ;
if (freq <= rate)
return freq;
for (i = 2; i <= ilog2(M41T80_SQW_MAX_FREQ); i++) {
freq /= 1 << i;
if (freq <= rate)
return freq;
}
if (rate >= M41T80_SQW_MAX_FREQ)
return M41T80_SQW_MAX_FREQ;
if (rate >= M41T80_SQW_MAX_FREQ / 4)
return M41T80_SQW_MAX_FREQ / 4;
if (!rate)
return 0;
return 1 << ilog2(rate);
}
static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
@ -491,17 +490,12 @@ static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
M41T80_REG_WDAY : M41T80_REG_SQW;
int reg, ret, val = 0;
if (rate) {
if (!is_power_of_2(rate))
return -EINVAL;
val = ilog2(rate);
if (val == ilog2(M41T80_SQW_MAX_FREQ))
if (rate >= M41T80_SQW_MAX_FREQ)
val = 1;
else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1))
val = ilog2(M41T80_SQW_MAX_FREQ) - val;
else
return -EINVAL;
}
else if (rate >= M41T80_SQW_MAX_FREQ / 4)
val = 2;
else if (rate)
val = 15 - ilog2(rate);
reg = i2c_smbus_read_byte_data(client, reg_sqw);
if (reg < 0)
@ -510,10 +504,9 @@ static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
reg = (reg & 0x0f) | (val << 4);
ret = i2c_smbus_write_byte_data(client, reg_sqw, reg);
if (ret < 0)
if (!ret)
m41t80->freq = m41t80_decode_freq(val);
return ret;
return -EINVAL;
}
static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
@ -530,7 +523,10 @@ static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
else
ret &= ~M41T80_ALMON_SQWE;
return i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
if (!ret)
m41t80->sqwe = enable;
return ret;
}
static int m41t80_sqw_prepare(struct clk_hw *hw)
@ -545,14 +541,7 @@ static void m41t80_sqw_unprepare(struct clk_hw *hw)
static int m41t80_sqw_is_prepared(struct clk_hw *hw)
{
struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
struct i2c_client *client = m41t80->client;
int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (ret < 0)
return ret;
return !!(ret & M41T80_ALMON_SQWE);
return sqw_to_m41t80_data(hw)->sqwe;
}
static const struct clk_ops m41t80_sqw_ops = {
@ -587,6 +576,7 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
init.parent_names = NULL;
init.num_parents = 0;
m41t80->sqw.init = &init;
m41t80->freq = m41t80_get_freq(m41t80);
/* optional override of the clockname */
of_property_read_string(node, "clock-output-names", &init.name);

View File

@ -163,35 +163,30 @@ static const struct rtc_class_ops m48t86_rtc_ops = {
.proc = m48t86_rtc_proc,
};
static ssize_t m48t86_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
static int m48t86_nvram_read(void *priv, unsigned int off, void *buf,
size_t count)
{
struct device *dev = kobj_to_dev(kobj);
struct device *dev = priv;
unsigned int i;
for (i = 0; i < count; i++)
buf[i] = m48t86_readb(dev, M48T86_NVRAM(off + i));
((u8 *)buf)[i] = m48t86_readb(dev, M48T86_NVRAM(off + i));
return count;
return 0;
}
static ssize_t m48t86_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
static int m48t86_nvram_write(void *priv, unsigned int off, void *buf,
size_t count)
{
struct device *dev = kobj_to_dev(kobj);
struct device *dev = priv;
unsigned int i;
for (i = 0; i < count; i++)
m48t86_writeb(dev, buf[i], M48T86_NVRAM(off + i));
m48t86_writeb(dev, ((u8 *)buf)[i], M48T86_NVRAM(off + i));
return count;
return 0;
}
static BIN_ATTR(nvram, 0644, m48t86_nvram_read, m48t86_nvram_write,
M48T86_NVRAM_LEN);
/*
* The RTC is an optional feature at purchase time on some Technologic Systems
* boards. Verify that it actually exists by checking if the last two bytes
@ -223,11 +218,21 @@ static bool m48t86_verify_chip(struct platform_device *pdev)
return false;
}
static struct nvmem_config m48t86_nvmem_cfg = {
.name = "m48t86_nvram",
.word_size = 1,
.stride = 1,
.size = M48T86_NVRAM_LEN,
.reg_read = m48t86_nvram_read,
.reg_write = m48t86_nvram_write,
};
static int m48t86_rtc_probe(struct platform_device *pdev)
{
struct m48t86_rtc_info *info;
struct resource *res;
unsigned char reg;
int err;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@ -254,25 +259,25 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
return -ENODEV;
}
info->rtc = devm_rtc_device_register(&pdev->dev, "m48t86",
&m48t86_rtc_ops, THIS_MODULE);
info->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(info->rtc))
return PTR_ERR(info->rtc);
info->rtc->ops = &m48t86_rtc_ops;
m48t86_nvmem_cfg.priv = &pdev->dev;
info->rtc->nvmem_config = &m48t86_nvmem_cfg;
info->rtc->nvram_old_abi = true;
err = rtc_register_device(info->rtc);
if (err)
return err;
/* read battery status */
reg = m48t86_readb(&pdev->dev, M48T86_D);
dev_info(&pdev->dev, "battery %s\n",
(reg & M48T86_D_VRT) ? "ok" : "exhausted");
if (device_create_bin_file(&pdev->dev, &bin_attr_nvram))
dev_err(&pdev->dev, "failed to create nvram sysfs entry\n");
return 0;
}
static int m48t86_rtc_remove(struct platform_device *pdev)
{
device_remove_bin_file(&pdev->dev, &bin_attr_nvram);
return 0;
}
@ -281,7 +286,6 @@ static struct platform_driver m48t86_rtc_platform_driver = {
.name = "rtc-m48t86",
},
.probe = m48t86_rtc_probe,
.remove = m48t86_rtc_remove,
};
module_platform_driver(m48t86_rtc_platform_driver);

422
drivers/rtc/rtc-mt7622.c Normal file
View File

@ -0,0 +1,422 @@
/*
* Driver for MediaTek SoC based RTC
*
* Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#define MTK_RTC_DEV KBUILD_MODNAME
#define MTK_RTC_PWRCHK1 0x4
#define RTC_PWRCHK1_MAGIC 0xc6
#define MTK_RTC_PWRCHK2 0x8
#define RTC_PWRCHK2_MAGIC 0x9a
#define MTK_RTC_KEY 0xc
#define RTC_KEY_MAGIC 0x59
#define MTK_RTC_PROT1 0x10
#define RTC_PROT1_MAGIC 0xa3
#define MTK_RTC_PROT2 0x14
#define RTC_PROT2_MAGIC 0x57
#define MTK_RTC_PROT3 0x18
#define RTC_PROT3_MAGIC 0x67
#define MTK_RTC_PROT4 0x1c
#define RTC_PROT4_MAGIC 0xd2
#define MTK_RTC_CTL 0x20
#define RTC_RC_STOP BIT(0)
#define MTK_RTC_DEBNCE 0x2c
#define RTC_DEBNCE_MASK GENMASK(2, 0)
#define MTK_RTC_INT 0x30
#define RTC_INT_AL_STA BIT(4)
/*
* Ranges from 0x40 to 0x78 provide RTC time setup for year, month,
* day of month, day of week, hour, minute and second.
*/
#define MTK_RTC_TREG(_t, _f) (0x40 + (0x4 * (_f)) + ((_t) * 0x20))
#define MTK_RTC_AL_CTL 0x7c
#define RTC_AL_EN BIT(0)
#define RTC_AL_ALL GENMASK(7, 0)
/*
* The offset is used in the translation for the year between in struct
* rtc_time and in hardware register MTK_RTC_TREG(x,MTK_YEA)
*/
#define MTK_RTC_TM_YR_OFFSET 100
/*
* The lowest value for the valid tm_year. RTC hardware would take incorrectly
* tm_year 100 as not a leap year and thus it is also required being excluded
* from the valid options.
*/
#define MTK_RTC_TM_YR_L (MTK_RTC_TM_YR_OFFSET + 1)
/*
* The most year the RTC can hold is 99 and the next to 99 in year register
* would be wraparound to 0, for MT7622.
*/
#define MTK_RTC_HW_YR_LIMIT 99
/* The highest value for the valid tm_year */
#define MTK_RTC_TM_YR_H (MTK_RTC_TM_YR_OFFSET + MTK_RTC_HW_YR_LIMIT)
/* Simple macro helps to check whether the hardware supports the tm_year */
#define MTK_RTC_TM_YR_VALID(_y) ((_y) >= MTK_RTC_TM_YR_L && \
(_y) <= MTK_RTC_TM_YR_H)
/* Types of the function the RTC provides are time counter and alarm. */
enum {
MTK_TC,
MTK_AL,
};
/* Indexes are used for the pointer to relevant registers in MTK_RTC_TREG */
enum {
MTK_YEA,
MTK_MON,
MTK_DOM,
MTK_DOW,
MTK_HOU,
MTK_MIN,
MTK_SEC
};
struct mtk_rtc {
struct rtc_device *rtc;
void __iomem *base;
int irq;
struct clk *clk;
};
static void mtk_w32(struct mtk_rtc *rtc, u32 reg, u32 val)
{
writel_relaxed(val, rtc->base + reg);
}
static u32 mtk_r32(struct mtk_rtc *rtc, u32 reg)
{
return readl_relaxed(rtc->base + reg);
}
static void mtk_rmw(struct mtk_rtc *rtc, u32 reg, u32 mask, u32 set)
{
u32 val;
val = mtk_r32(rtc, reg);
val &= ~mask;
val |= set;
mtk_w32(rtc, reg, val);
}
static void mtk_set(struct mtk_rtc *rtc, u32 reg, u32 val)
{
mtk_rmw(rtc, reg, 0, val);
}
static void mtk_clr(struct mtk_rtc *rtc, u32 reg, u32 val)
{
mtk_rmw(rtc, reg, val, 0);
}
static void mtk_rtc_hw_init(struct mtk_rtc *hw)
{
/* The setup of the init sequence is for allowing RTC got to work */
mtk_w32(hw, MTK_RTC_PWRCHK1, RTC_PWRCHK1_MAGIC);
mtk_w32(hw, MTK_RTC_PWRCHK2, RTC_PWRCHK2_MAGIC);
mtk_w32(hw, MTK_RTC_KEY, RTC_KEY_MAGIC);
mtk_w32(hw, MTK_RTC_PROT1, RTC_PROT1_MAGIC);
mtk_w32(hw, MTK_RTC_PROT2, RTC_PROT2_MAGIC);
mtk_w32(hw, MTK_RTC_PROT3, RTC_PROT3_MAGIC);
mtk_w32(hw, MTK_RTC_PROT4, RTC_PROT4_MAGIC);
mtk_rmw(hw, MTK_RTC_DEBNCE, RTC_DEBNCE_MASK, 0);
mtk_clr(hw, MTK_RTC_CTL, RTC_RC_STOP);
}
static void mtk_rtc_get_alarm_or_time(struct mtk_rtc *hw, struct rtc_time *tm,
int time_alarm)
{
u32 year, mon, mday, wday, hour, min, sec;
/*
* Read again until the field of the second is not changed which
* ensures all fields in the consistent state. Note that MTK_SEC must
* be read first. In this way, it guarantees the others remain not
* changed when the results for two MTK_SEC consecutive reads are same.
*/
do {
sec = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC));
min = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MIN));
hour = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_HOU));
wday = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOW));
mday = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOM));
mon = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MON));
year = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_YEA));
} while (sec != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC)));
tm->tm_sec = sec;
tm->tm_min = min;
tm->tm_hour = hour;
tm->tm_wday = wday;
tm->tm_mday = mday;
tm->tm_mon = mon - 1;
/* Rebase to the absolute year which userspace queries */
tm->tm_year = year + MTK_RTC_TM_YR_OFFSET;
}
static void mtk_rtc_set_alarm_or_time(struct mtk_rtc *hw, struct rtc_time *tm,
int time_alarm)
{
u32 year;
/* Rebase to the relative year which RTC hardware requires */
year = tm->tm_year - MTK_RTC_TM_YR_OFFSET;
mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_YEA), year);
mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_MON), tm->tm_mon + 1);
mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_DOW), tm->tm_wday);
mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_DOM), tm->tm_mday);
mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_HOU), tm->tm_hour);
mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_MIN), tm->tm_min);
mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC), tm->tm_sec);
}
static irqreturn_t mtk_rtc_alarmirq(int irq, void *id)
{
struct mtk_rtc *hw = (struct mtk_rtc *)id;
u32 irq_sta;
irq_sta = mtk_r32(hw, MTK_RTC_INT);
if (irq_sta & RTC_INT_AL_STA) {
/* Stop alarm also implicitly disables the alarm interrupt */
mtk_w32(hw, MTK_RTC_AL_CTL, 0);
rtc_update_irq(hw->rtc, 1, RTC_IRQF | RTC_AF);
/* Ack alarm interrupt status */
mtk_w32(hw, MTK_RTC_INT, RTC_INT_AL_STA);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int mtk_rtc_gettime(struct device *dev, struct rtc_time *tm)
{
struct mtk_rtc *hw = dev_get_drvdata(dev);
mtk_rtc_get_alarm_or_time(hw, tm, MTK_TC);
return rtc_valid_tm(tm);
}
static int mtk_rtc_settime(struct device *dev, struct rtc_time *tm)
{
struct mtk_rtc *hw = dev_get_drvdata(dev);
if (!MTK_RTC_TM_YR_VALID(tm->tm_year))
return -EINVAL;
/* Stop time counter before setting a new one*/
mtk_set(hw, MTK_RTC_CTL, RTC_RC_STOP);
mtk_rtc_set_alarm_or_time(hw, tm, MTK_TC);
/* Restart the time counter */
mtk_clr(hw, MTK_RTC_CTL, RTC_RC_STOP);
return 0;
}
static int mtk_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
struct mtk_rtc *hw = dev_get_drvdata(dev);
struct rtc_time *alrm_tm = &wkalrm->time;
mtk_rtc_get_alarm_or_time(hw, alrm_tm, MTK_AL);
wkalrm->enabled = !!(mtk_r32(hw, MTK_RTC_AL_CTL) & RTC_AL_EN);
wkalrm->pending = !!(mtk_r32(hw, MTK_RTC_INT) & RTC_INT_AL_STA);
return 0;
}
static int mtk_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
struct mtk_rtc *hw = dev_get_drvdata(dev);
struct rtc_time *alrm_tm = &wkalrm->time;
if (!MTK_RTC_TM_YR_VALID(alrm_tm->tm_year))
return -EINVAL;
/*
* Stop the alarm also implicitly including disables interrupt before
* setting a new one.
*/
mtk_clr(hw, MTK_RTC_AL_CTL, RTC_AL_EN);
/*
* Avoid contention between mtk_rtc_setalarm and IRQ handler so that
* disabling the interrupt and awaiting for pending IRQ handler to
* complete.
*/
synchronize_irq(hw->irq);
mtk_rtc_set_alarm_or_time(hw, alrm_tm, MTK_AL);
/* Restart the alarm with the new setup */
mtk_w32(hw, MTK_RTC_AL_CTL, RTC_AL_ALL);
return 0;
}
static const struct rtc_class_ops mtk_rtc_ops = {
.read_time = mtk_rtc_gettime,
.set_time = mtk_rtc_settime,
.read_alarm = mtk_rtc_getalarm,
.set_alarm = mtk_rtc_setalarm,
};
static const struct of_device_id mtk_rtc_match[] = {
{ .compatible = "mediatek,mt7622-rtc" },
{ .compatible = "mediatek,soc-rtc" },
{},
};
static int mtk_rtc_probe(struct platform_device *pdev)
{
struct mtk_rtc *hw;
struct resource *res;
int ret;
hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
if (!hw)
return -ENOMEM;
platform_set_drvdata(pdev, hw);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hw->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->base))
return PTR_ERR(hw->base);
hw->clk = devm_clk_get(&pdev->dev, "rtc");
if (IS_ERR(hw->clk)) {
dev_err(&pdev->dev, "No clock\n");
return PTR_ERR(hw->clk);
}
ret = clk_prepare_enable(hw->clk);
if (ret)
return ret;
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq < 0) {
dev_err(&pdev->dev, "No IRQ resource\n");
ret = hw->irq;
goto err;
}
ret = devm_request_irq(&pdev->dev, hw->irq, mtk_rtc_alarmirq,
0, dev_name(&pdev->dev), hw);
if (ret) {
dev_err(&pdev->dev, "Can't request IRQ\n");
goto err;
}
mtk_rtc_hw_init(hw);
device_init_wakeup(&pdev->dev, true);
hw->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&mtk_rtc_ops, THIS_MODULE);
if (IS_ERR(hw->rtc)) {
ret = PTR_ERR(hw->rtc);
dev_err(&pdev->dev, "Unable to register device\n");
goto err;
}
return 0;
err:
clk_disable_unprepare(hw->clk);
return ret;
}
static int mtk_rtc_remove(struct platform_device *pdev)
{
struct mtk_rtc *hw = platform_get_drvdata(pdev);
clk_disable_unprepare(hw->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int mtk_rtc_suspend(struct device *dev)
{
struct mtk_rtc *hw = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(hw->irq);
return 0;
}
static int mtk_rtc_resume(struct device *dev)
{
struct mtk_rtc *hw = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(hw->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(mtk_rtc_pm_ops, mtk_rtc_suspend, mtk_rtc_resume);
#define MTK_RTC_PM_OPS (&mtk_rtc_pm_ops)
#else /* CONFIG_PM */
#define MTK_RTC_PM_OPS NULL
#endif /* CONFIG_PM */
static struct platform_driver mtk_rtc_driver = {
.probe = mtk_rtc_probe,
.remove = mtk_rtc_remove,
.driver = {
.name = MTK_RTC_DEV,
.of_match_table = mtk_rtc_match,
.pm = MTK_RTC_PM_OPS,
},
};
module_platform_driver(mtk_rtc_driver);
MODULE_DESCRIPTION("MediaTek SoC based RTC Driver");
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_LICENSE("GPL");

View File

@ -70,6 +70,10 @@
#define OMAP_RTC_COMP_MSB_REG 0x50
#define OMAP_RTC_OSC_REG 0x54
#define OMAP_RTC_SCRATCH0_REG 0x60
#define OMAP_RTC_SCRATCH1_REG 0x64
#define OMAP_RTC_SCRATCH2_REG 0x68
#define OMAP_RTC_KICK0_REG 0x6c
#define OMAP_RTC_KICK1_REG 0x70
@ -667,6 +671,45 @@ static struct pinctrl_desc rtc_pinctrl_desc = {
.owner = THIS_MODULE,
};
static int omap_rtc_scratch_read(void *priv, unsigned int offset, void *_val,
size_t bytes)
{
struct omap_rtc *rtc = priv;
u32 *val = _val;
int i;
for (i = 0; i < bytes / 4; i++)
val[i] = rtc_readl(rtc,
OMAP_RTC_SCRATCH0_REG + offset + (i * 4));
return 0;
}
static int omap_rtc_scratch_write(void *priv, unsigned int offset, void *_val,
size_t bytes)
{
struct omap_rtc *rtc = priv;
u32 *val = _val;
int i;
rtc->type->unlock(rtc);
for (i = 0; i < bytes / 4; i++)
rtc_writel(rtc,
OMAP_RTC_SCRATCH0_REG + offset + (i * 4), val[i]);
rtc->type->lock(rtc);
return 0;
}
static struct nvmem_config omap_rtc_nvmem_config = {
.name = "omap_rtc_scratch",
.word_size = 4,
.stride = 4,
.size = OMAP_RTC_KICK0_REG - OMAP_RTC_SCRATCH0_REG,
.reg_read = omap_rtc_scratch_read,
.reg_write = omap_rtc_scratch_write,
};
static int omap_rtc_probe(struct platform_device *pdev)
{
struct omap_rtc *rtc;
@ -797,13 +840,16 @@ static int omap_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, true);
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&omap_rtc_ops, THIS_MODULE);
rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc->rtc)) {
ret = PTR_ERR(rtc->rtc);
goto err;
}
rtc->rtc->ops = &omap_rtc_ops;
omap_rtc_nvmem_config.priv = rtc;
rtc->rtc->nvmem_config = &omap_rtc_nvmem_config;
/* handle periodic and alarm irqs */
ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0,
dev_name(&rtc->rtc->dev), rtc);
@ -830,9 +876,14 @@ static int omap_rtc_probe(struct platform_device *pdev)
rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc);
if (IS_ERR(rtc->pctldev)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
return PTR_ERR(rtc->pctldev);
ret = PTR_ERR(rtc->pctldev);
goto err;
}
ret = rtc_register_device(rtc->rtc);
if (ret)
goto err;
return 0;
err:

View File

@ -35,6 +35,9 @@
#define REG_MONTHS 0x08
#define REG_YEARS 0x09
#define REG_OFFSET 0x0e
#define REG_OFFSET_MODE BIT(7)
struct pcf8523 {
struct rtc_device *rtc;
};
@ -272,10 +275,47 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
#define pcf8523_rtc_ioctl NULL
#endif
static int pcf8523_rtc_read_offset(struct device *dev, long *offset)
{
struct i2c_client *client = to_i2c_client(dev);
int err;
u8 value;
s8 val;
err = pcf8523_read(client, REG_OFFSET, &value);
if (err < 0)
return err;
/* sign extend the 7-bit offset value */
val = value << 1;
*offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1);
return 0;
}
static int pcf8523_rtc_set_offset(struct device *dev, long offset)
{
struct i2c_client *client = to_i2c_client(dev);
long reg_m0, reg_m1;
u8 value;
reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L);
reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L);
if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset))
value = reg_m0 & 0x7f;
else
value = (reg_m1 & 0x7f) | REG_OFFSET_MODE;
return pcf8523_write(client, REG_OFFSET, value);
}
static const struct rtc_class_ops pcf8523_rtc_ops = {
.read_time = pcf8523_rtc_read_time,
.set_time = pcf8523_rtc_set_time,
.ioctl = pcf8523_rtc_ioctl,
.read_offset = pcf8523_rtc_read_offset,
.set_offset = pcf8523_rtc_set_offset,
};
static int pcf8523_probe(struct i2c_client *client,

220
drivers/rtc/rtc-pcf85363.c Normal file
View File

@ -0,0 +1,220 @@
/*
* drivers/rtc/rtc-pcf85363.c
*
* Driver for NXP PCF85363 real-time clock.
*
* Copyright (C) 2017 Eric Nelson
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Based loosely on rtc-8583 by Russell King, Wolfram Sang and Juergen Beisert
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/bcd.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
/*
* Date/Time registers
*/
#define DT_100THS 0x00
#define DT_SECS 0x01
#define DT_MINUTES 0x02
#define DT_HOURS 0x03
#define DT_DAYS 0x04
#define DT_WEEKDAYS 0x05
#define DT_MONTHS 0x06
#define DT_YEARS 0x07
/*
* Alarm registers
*/
#define DT_SECOND_ALM1 0x08
#define DT_MINUTE_ALM1 0x09
#define DT_HOUR_ALM1 0x0a
#define DT_DAY_ALM1 0x0b
#define DT_MONTH_ALM1 0x0c
#define DT_MINUTE_ALM2 0x0d
#define DT_HOUR_ALM2 0x0e
#define DT_WEEKDAY_ALM2 0x0f
#define DT_ALARM_EN 0x10
/*
* Time stamp registers
*/
#define DT_TIMESTAMP1 0x11
#define DT_TIMESTAMP2 0x17
#define DT_TIMESTAMP3 0x1d
#define DT_TS_MODE 0x23
/*
* control registers
*/
#define CTRL_OFFSET 0x24
#define CTRL_OSCILLATOR 0x25
#define CTRL_BATTERY 0x26
#define CTRL_PIN_IO 0x27
#define CTRL_FUNCTION 0x28
#define CTRL_INTA_EN 0x29
#define CTRL_INTB_EN 0x2a
#define CTRL_FLAGS 0x2b
#define CTRL_RAMBYTE 0x2c
#define CTRL_WDOG 0x2d
#define CTRL_STOP_EN 0x2e
#define CTRL_RESETS 0x2f
#define CTRL_RAM 0x40
#define NVRAM_SIZE 0x40
static struct i2c_driver pcf85363_driver;
struct pcf85363 {
struct device *dev;
struct rtc_device *rtc;
struct nvmem_config nvmem_cfg;
struct regmap *regmap;
};
static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
unsigned char buf[DT_YEARS + 1];
int ret, len = sizeof(buf);
/* read the RTC date and time registers all at once */
ret = regmap_bulk_read(pcf85363->regmap, DT_100THS, buf, len);
if (ret) {
dev_err(dev, "%s: error %d\n", __func__, ret);
return ret;
}
tm->tm_year = bcd2bin(buf[DT_YEARS]);
/* adjust for 1900 base of rtc_time */
tm->tm_year += 100;
tm->tm_wday = buf[DT_WEEKDAYS] & 7;
buf[DT_SECS] &= 0x7F;
tm->tm_sec = bcd2bin(buf[DT_SECS]);
buf[DT_MINUTES] &= 0x7F;
tm->tm_min = bcd2bin(buf[DT_MINUTES]);
tm->tm_hour = bcd2bin(buf[DT_HOURS]);
tm->tm_mday = bcd2bin(buf[DT_DAYS]);
tm->tm_mon = bcd2bin(buf[DT_MONTHS]) - 1;
return 0;
}
static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
unsigned char buf[DT_YEARS + 1];
int len = sizeof(buf);
buf[DT_100THS] = 0;
buf[DT_SECS] = bin2bcd(tm->tm_sec);
buf[DT_MINUTES] = bin2bcd(tm->tm_min);
buf[DT_HOURS] = bin2bcd(tm->tm_hour);
buf[DT_DAYS] = bin2bcd(tm->tm_mday);
buf[DT_WEEKDAYS] = tm->tm_wday;
buf[DT_MONTHS] = bin2bcd(tm->tm_mon + 1);
buf[DT_YEARS] = bin2bcd(tm->tm_year % 100);
return regmap_bulk_write(pcf85363->regmap, DT_100THS,
buf, len);
}
static const struct rtc_class_ops rtc_ops = {
.read_time = pcf85363_rtc_read_time,
.set_time = pcf85363_rtc_set_time,
};
static int pcf85363_nvram_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct pcf85363 *pcf85363 = priv;
return regmap_bulk_read(pcf85363->regmap, CTRL_RAM + offset,
val, bytes);
}
static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct pcf85363 *pcf85363 = priv;
return regmap_bulk_write(pcf85363->regmap, CTRL_RAM + offset,
val, bytes);
}
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int pcf85363_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pcf85363 *pcf85363;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
pcf85363 = devm_kzalloc(&client->dev, sizeof(struct pcf85363),
GFP_KERNEL);
if (!pcf85363)
return -ENOMEM;
pcf85363->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(pcf85363->regmap)) {
dev_err(&client->dev, "regmap allocation failed\n");
return PTR_ERR(pcf85363->regmap);
}
pcf85363->dev = &client->dev;
i2c_set_clientdata(client, pcf85363);
pcf85363->rtc = devm_rtc_allocate_device(pcf85363->dev);
if (IS_ERR(pcf85363->rtc))
return PTR_ERR(pcf85363->rtc);
pcf85363->nvmem_cfg.name = "pcf85363-";
pcf85363->nvmem_cfg.word_size = 1;
pcf85363->nvmem_cfg.stride = 1;
pcf85363->nvmem_cfg.size = NVRAM_SIZE;
pcf85363->nvmem_cfg.reg_read = pcf85363_nvram_read;
pcf85363->nvmem_cfg.reg_write = pcf85363_nvram_write;
pcf85363->nvmem_cfg.priv = pcf85363;
pcf85363->rtc->nvmem_config = &pcf85363->nvmem_cfg;
pcf85363->rtc->ops = &rtc_ops;
return rtc_register_device(pcf85363->rtc);
}
static const struct of_device_id dev_ids[] = {
{ .compatible = "nxp,pcf85363" },
{}
};
MODULE_DEVICE_TABLE(of, dev_ids);
static struct i2c_driver pcf85363_driver = {
.driver = {
.name = "pcf85363",
.of_match_table = of_match_ptr(dev_ids),
},
.probe = pcf85363_probe,
};
module_i2c_driver(pcf85363_driver);
MODULE_AUTHOR("Eric Nelson");
MODULE_DESCRIPTION("pcf85363 I2C RTC driver");
MODULE_LICENSE("GPL");

View File

@ -387,7 +387,7 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
if (err)
return err;
return pcf8563_set_alarm_mode(client, 1);
return pcf8563_set_alarm_mode(client, !!tm->enabled);
}
static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
@ -422,7 +422,7 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
return 0;
buf &= PCF8563_REG_CLKO_F_MASK;
return clkout_rates[ret];
return clkout_rates[buf];
}
static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,

View File

@ -308,10 +308,9 @@ static int pl031_remove(struct amba_device *adev)
dev_pm_clear_wake_irq(&adev->dev);
device_init_wakeup(&adev->dev, false);
if (adev->irq[0])
free_irq(adev->irq[0], ldata);
rtc_device_unregister(ldata->rtc);
iounmap(ldata->base);
kfree(ldata);
amba_release_regions(adev);
return 0;
@ -322,25 +321,28 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
int ret;
struct pl031_local *ldata;
struct pl031_vendor_data *vendor = id->data;
struct rtc_class_ops *ops = &vendor->ops;
struct rtc_class_ops *ops;
unsigned long time, data;
ret = amba_request_regions(adev, NULL);
if (ret)
goto err_req;
ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
if (!ldata) {
ldata = devm_kzalloc(&adev->dev, sizeof(struct pl031_local),
GFP_KERNEL);
ops = devm_kmemdup(&adev->dev, &vendor->ops, sizeof(vendor->ops),
GFP_KERNEL);
if (!ldata || !ops) {
ret = -ENOMEM;
goto out;
}
ldata->vendor = vendor;
ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
ldata->base = devm_ioremap(&adev->dev, adev->res.start,
resource_size(&adev->res));
if (!ldata->base) {
ret = -ENOMEM;
goto out_no_remap;
goto out;
}
amba_set_drvdata(adev, ldata);
@ -373,28 +375,32 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
}
}
if (!adev->irq[0]) {
/* When there's no interrupt, no point in exposing the alarm */
ops->read_alarm = NULL;
ops->set_alarm = NULL;
ops->alarm_irq_enable = NULL;
}
device_init_wakeup(&adev->dev, true);
ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
THIS_MODULE);
if (IS_ERR(ldata->rtc)) {
ret = PTR_ERR(ldata->rtc);
goto out_no_rtc;
goto out;
}
if (request_irq(adev->irq[0], pl031_interrupt,
vendor->irqflags, "rtc-pl031", ldata)) {
ret = -EIO;
if (adev->irq[0]) {
ret = request_irq(adev->irq[0], pl031_interrupt,
vendor->irqflags, "rtc-pl031", ldata);
if (ret)
goto out_no_irq;
}
dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
}
return 0;
out_no_irq:
rtc_device_unregister(ldata->rtc);
out_no_rtc:
iounmap(ldata->base);
out_no_remap:
kfree(ldata);
out:
amba_release_regions(adev);
err_req:
@ -446,7 +452,7 @@ static struct pl031_vendor_data stv2_pl031 = {
.irqflags = IRQF_SHARED | IRQF_COND_SUSPEND,
};
static struct amba_id pl031_ids[] = {
static const struct amba_id pl031_ids[] = {
{
.id = 0x00041031,
.mask = 0x000fffff,

View File

@ -282,13 +282,13 @@ static int rv3029_eeprom_read(struct device *dev, u8 reg,
static int rv3029_eeprom_write(struct device *dev, u8 reg,
u8 const buf[], size_t len)
{
int ret, err;
int ret;
size_t i;
u8 tmp;
err = rv3029_eeprom_enter(dev);
if (err < 0)
return err;
ret = rv3029_eeprom_enter(dev);
if (ret < 0)
return ret;
for (i = 0; i < len; i++, reg++) {
ret = rv3029_read_regs(dev, reg, &tmp, 1);
@ -304,11 +304,11 @@ static int rv3029_eeprom_write(struct device *dev, u8 reg,
break;
}
err = rv3029_eeprom_exit(dev);
if (err < 0)
return err;
ret = rv3029_eeprom_exit(dev);
if (ret < 0)
return ret;
return 0;
}
static int rv3029_eeprom_update_bits(struct device *dev,
@ -876,6 +876,8 @@ static const struct i2c_device_id rv3029_id[] = {
MODULE_DEVICE_TABLE(i2c, rv3029_id);
static const struct of_device_id rv3029_of_match[] = {
{ .compatible = "microcrystal,rv3029" },
/* Backward compatibility only, do not use compatibles below: */
{ .compatible = "rv3029" },
{ .compatible = "rv3029c2" },
{ .compatible = "mc,rv3029c2" },

View File

@ -24,7 +24,6 @@
#define RX8010_MDAY 0x14
#define RX8010_MONTH 0x15
#define RX8010_YEAR 0x16
#define RX8010_YEAR 0x16
#define RX8010_RESV17 0x17
#define RX8010_ALMIN 0x18
#define RX8010_ALHOUR 0x19
@ -36,7 +35,7 @@
#define RX8010_CTRL 0x1F
/* 0x20 to 0x2F are user registers */
#define RX8010_RESV30 0x30
#define RX8010_RESV31 0x32
#define RX8010_RESV31 0x31
#define RX8010_IRQ 0x32
#define RX8010_EXT_WADA BIT(3)
@ -248,7 +247,7 @@ static int rx8010_init_client(struct i2c_client *client)
rx8010->ctrlreg = (ctrl[1] & ~RX8010_CTRL_TEST);
return err;
return 0;
}
static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
@ -277,7 +276,7 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);
t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;
return err;
return 0;
}
static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t)

662
drivers/rtc/rtc-sc27xx.c Normal file
View File

@ -0,0 +1,662 @@
/*
* Copyright (C) 2017 Spreadtrum Communications Inc.
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#define SPRD_RTC_SEC_CNT_VALUE 0x0
#define SPRD_RTC_MIN_CNT_VALUE 0x4
#define SPRD_RTC_HOUR_CNT_VALUE 0x8
#define SPRD_RTC_DAY_CNT_VALUE 0xc
#define SPRD_RTC_SEC_CNT_UPD 0x10
#define SPRD_RTC_MIN_CNT_UPD 0x14
#define SPRD_RTC_HOUR_CNT_UPD 0x18
#define SPRD_RTC_DAY_CNT_UPD 0x1c
#define SPRD_RTC_SEC_ALM_UPD 0x20
#define SPRD_RTC_MIN_ALM_UPD 0x24
#define SPRD_RTC_HOUR_ALM_UPD 0x28
#define SPRD_RTC_DAY_ALM_UPD 0x2c
#define SPRD_RTC_INT_EN 0x30
#define SPRD_RTC_INT_RAW_STS 0x34
#define SPRD_RTC_INT_CLR 0x38
#define SPRD_RTC_INT_MASK_STS 0x3C
#define SPRD_RTC_SEC_ALM_VALUE 0x40
#define SPRD_RTC_MIN_ALM_VALUE 0x44
#define SPRD_RTC_HOUR_ALM_VALUE 0x48
#define SPRD_RTC_DAY_ALM_VALUE 0x4c
#define SPRD_RTC_SPG_VALUE 0x50
#define SPRD_RTC_SPG_UPD 0x54
#define SPRD_RTC_SEC_AUXALM_UPD 0x60
#define SPRD_RTC_MIN_AUXALM_UPD 0x64
#define SPRD_RTC_HOUR_AUXALM_UPD 0x68
#define SPRD_RTC_DAY_AUXALM_UPD 0x6c
/* BIT & MASK definition for SPRD_RTC_INT_* registers */
#define SPRD_RTC_SEC_EN BIT(0)
#define SPRD_RTC_MIN_EN BIT(1)
#define SPRD_RTC_HOUR_EN BIT(2)
#define SPRD_RTC_DAY_EN BIT(3)
#define SPRD_RTC_ALARM_EN BIT(4)
#define SPRD_RTC_HRS_FORMAT_EN BIT(5)
#define SPRD_RTC_AUXALM_EN BIT(6)
#define SPRD_RTC_SPG_UPD_EN BIT(7)
#define SPRD_RTC_SEC_UPD_EN BIT(8)
#define SPRD_RTC_MIN_UPD_EN BIT(9)
#define SPRD_RTC_HOUR_UPD_EN BIT(10)
#define SPRD_RTC_DAY_UPD_EN BIT(11)
#define SPRD_RTC_ALMSEC_UPD_EN BIT(12)
#define SPRD_RTC_ALMMIN_UPD_EN BIT(13)
#define SPRD_RTC_ALMHOUR_UPD_EN BIT(14)
#define SPRD_RTC_ALMDAY_UPD_EN BIT(15)
#define SPRD_RTC_INT_MASK GENMASK(15, 0)
#define SPRD_RTC_TIME_INT_MASK \
(SPRD_RTC_SEC_UPD_EN | SPRD_RTC_MIN_UPD_EN | \
SPRD_RTC_HOUR_UPD_EN | SPRD_RTC_DAY_UPD_EN)
#define SPRD_RTC_ALMTIME_INT_MASK \
(SPRD_RTC_ALMSEC_UPD_EN | SPRD_RTC_ALMMIN_UPD_EN | \
SPRD_RTC_ALMHOUR_UPD_EN | SPRD_RTC_ALMDAY_UPD_EN)
#define SPRD_RTC_ALM_INT_MASK \
(SPRD_RTC_SEC_EN | SPRD_RTC_MIN_EN | \
SPRD_RTC_HOUR_EN | SPRD_RTC_DAY_EN | \
SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN)
/* second/minute/hour/day values mask definition */
#define SPRD_RTC_SEC_MASK GENMASK(5, 0)
#define SPRD_RTC_MIN_MASK GENMASK(5, 0)
#define SPRD_RTC_HOUR_MASK GENMASK(4, 0)
#define SPRD_RTC_DAY_MASK GENMASK(15, 0)
/* alarm lock definition for SPRD_RTC_SPG_UPD register */
#define SPRD_RTC_ALMLOCK_MASK GENMASK(7, 0)
#define SPRD_RTC_ALM_UNLOCK 0xa5
#define SPRD_RTC_ALM_LOCK (~SPRD_RTC_ALM_UNLOCK & \
SPRD_RTC_ALMLOCK_MASK)
/* SPG values definition for SPRD_RTC_SPG_UPD register */
#define SPRD_RTC_POWEROFF_ALM_FLAG BIT(8)
#define SPRD_RTC_POWER_RESET_FLAG BIT(9)
/* timeout of synchronizing time and alarm registers (us) */
#define SPRD_RTC_POLL_TIMEOUT 200000
#define SPRD_RTC_POLL_DELAY_US 20000
struct sprd_rtc {
struct rtc_device *rtc;
struct regmap *regmap;
struct device *dev;
u32 base;
int irq;
bool valid;
};
/*
* The Spreadtrum RTC controller has 3 groups registers, including time, normal
* alarm and auxiliary alarm. The time group registers are used to set RTC time,
* the normal alarm registers are used to set normal alarm, and the auxiliary
* alarm registers are used to set auxiliary alarm. Both alarm event and
* auxiliary alarm event can wake up system from deep sleep, but only alarm
* event can power up system from power down status.
*/
enum sprd_rtc_reg_types {
SPRD_RTC_TIME,
SPRD_RTC_ALARM,
SPRD_RTC_AUX_ALARM,
};
static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc)
{
return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
SPRD_RTC_ALM_INT_MASK);
}
static int sprd_rtc_disable_ints(struct sprd_rtc *rtc)
{
int ret;
ret = regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
SPRD_RTC_INT_MASK, 0);
if (ret)
return ret;
return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
SPRD_RTC_INT_MASK);
}
static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
{
int ret;
u32 val;
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
if (ret)
return ret;
val &= ~(SPRD_RTC_ALMLOCK_MASK | SPRD_RTC_POWEROFF_ALM_FLAG);
if (lock)
val |= SPRD_RTC_ALM_LOCK;
else
val |= SPRD_RTC_ALM_UNLOCK | SPRD_RTC_POWEROFF_ALM_FLAG;
ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_SPG_UPD, val);
if (ret)
return ret;
/* wait until the SPG value is updated successfully */
ret = regmap_read_poll_timeout(rtc->regmap,
rtc->base + SPRD_RTC_INT_RAW_STS, val,
(val & SPRD_RTC_SPG_UPD_EN),
SPRD_RTC_POLL_DELAY_US,
SPRD_RTC_POLL_TIMEOUT);
if (ret) {
dev_err(rtc->dev, "failed to update SPG value:%d\n", ret);
return ret;
}
return 0;
}
static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
time64_t *secs)
{
u32 sec_reg, min_reg, hour_reg, day_reg;
u32 val, sec, min, hour, day;
int ret;
switch (type) {
case SPRD_RTC_TIME:
sec_reg = SPRD_RTC_SEC_CNT_VALUE;
min_reg = SPRD_RTC_MIN_CNT_VALUE;
hour_reg = SPRD_RTC_HOUR_CNT_VALUE;
day_reg = SPRD_RTC_DAY_CNT_VALUE;
break;
case SPRD_RTC_ALARM:
sec_reg = SPRD_RTC_SEC_ALM_VALUE;
min_reg = SPRD_RTC_MIN_ALM_VALUE;
hour_reg = SPRD_RTC_HOUR_ALM_VALUE;
day_reg = SPRD_RTC_DAY_ALM_VALUE;
break;
case SPRD_RTC_AUX_ALARM:
sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
min_reg = SPRD_RTC_MIN_AUXALM_UPD;
hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
day_reg = SPRD_RTC_DAY_AUXALM_UPD;
break;
default:
return -EINVAL;
}
ret = regmap_read(rtc->regmap, rtc->base + sec_reg, &val);
if (ret)
return ret;
sec = val & SPRD_RTC_SEC_MASK;
ret = regmap_read(rtc->regmap, rtc->base + min_reg, &val);
if (ret)
return ret;
min = val & SPRD_RTC_MIN_MASK;
ret = regmap_read(rtc->regmap, rtc->base + hour_reg, &val);
if (ret)
return ret;
hour = val & SPRD_RTC_HOUR_MASK;
ret = regmap_read(rtc->regmap, rtc->base + day_reg, &val);
if (ret)
return ret;
day = val & SPRD_RTC_DAY_MASK;
*secs = (((time64_t)(day * 24) + hour) * 60 + min) * 60 + sec;
return 0;
}
static int sprd_rtc_set_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
time64_t secs)
{
u32 sec_reg, min_reg, hour_reg, day_reg, sts_mask;
u32 sec, min, hour, day, val;
int ret, rem;
/* convert seconds to RTC time format */
day = div_s64_rem(secs, 86400, &rem);
hour = rem / 3600;
rem -= hour * 3600;
min = rem / 60;
sec = rem - min * 60;
switch (type) {
case SPRD_RTC_TIME:
sec_reg = SPRD_RTC_SEC_CNT_UPD;
min_reg = SPRD_RTC_MIN_CNT_UPD;
hour_reg = SPRD_RTC_HOUR_CNT_UPD;
day_reg = SPRD_RTC_DAY_CNT_UPD;
sts_mask = SPRD_RTC_TIME_INT_MASK;
break;
case SPRD_RTC_ALARM:
sec_reg = SPRD_RTC_SEC_ALM_UPD;
min_reg = SPRD_RTC_MIN_ALM_UPD;
hour_reg = SPRD_RTC_HOUR_ALM_UPD;
day_reg = SPRD_RTC_DAY_ALM_UPD;
sts_mask = SPRD_RTC_ALMTIME_INT_MASK;
break;
case SPRD_RTC_AUX_ALARM:
sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
min_reg = SPRD_RTC_MIN_AUXALM_UPD;
hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
day_reg = SPRD_RTC_DAY_AUXALM_UPD;
sts_mask = 0;
break;
default:
return -EINVAL;
}
ret = regmap_write(rtc->regmap, rtc->base + sec_reg, sec);
if (ret)
return ret;
ret = regmap_write(rtc->regmap, rtc->base + min_reg, min);
if (ret)
return ret;
ret = regmap_write(rtc->regmap, rtc->base + hour_reg, hour);
if (ret)
return ret;
ret = regmap_write(rtc->regmap, rtc->base + day_reg, day);
if (ret)
return ret;
if (type == SPRD_RTC_AUX_ALARM)
return 0;
/*
* Since the time and normal alarm registers are put in always-power-on
* region supplied by VDDRTC, then these registers changing time will
* be very long, about 125ms. Thus here we should wait until all
* values are updated successfully.
*/
ret = regmap_read_poll_timeout(rtc->regmap,
rtc->base + SPRD_RTC_INT_RAW_STS, val,
((val & sts_mask) == sts_mask),
SPRD_RTC_POLL_DELAY_US,
SPRD_RTC_POLL_TIMEOUT);
if (ret < 0) {
dev_err(rtc->dev, "set time/alarm values timeout\n");
return ret;
}
return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
sts_mask);
}
static int sprd_rtc_read_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct sprd_rtc *rtc = dev_get_drvdata(dev);
time64_t secs;
u32 val;
int ret;
ret = sprd_rtc_get_secs(rtc, SPRD_RTC_AUX_ALARM, &secs);
if (ret)
return ret;
rtc_time64_to_tm(secs, &alrm->time);
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
if (ret)
return ret;
alrm->enabled = !!(val & SPRD_RTC_AUXALM_EN);
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
if (ret)
return ret;
alrm->pending = !!(val & SPRD_RTC_AUXALM_EN);
return 0;
}
static int sprd_rtc_set_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct sprd_rtc *rtc = dev_get_drvdata(dev);
time64_t secs = rtc_tm_to_time64(&alrm->time);
int ret;
/* clear the auxiliary alarm interrupt status */
ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
SPRD_RTC_AUXALM_EN);
if (ret)
return ret;
ret = sprd_rtc_set_secs(rtc, SPRD_RTC_AUX_ALARM, secs);
if (ret)
return ret;
if (alrm->enabled) {
ret = regmap_update_bits(rtc->regmap,
rtc->base + SPRD_RTC_INT_EN,
SPRD_RTC_AUXALM_EN,
SPRD_RTC_AUXALM_EN);
} else {
ret = regmap_update_bits(rtc->regmap,
rtc->base + SPRD_RTC_INT_EN,
SPRD_RTC_AUXALM_EN, 0);
}
return ret;
}
static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct sprd_rtc *rtc = dev_get_drvdata(dev);
time64_t secs;
int ret;
if (!rtc->valid) {
dev_warn(dev, "RTC values are invalid\n");
return -EINVAL;
}
ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs);
if (ret)
return ret;
rtc_time64_to_tm(secs, tm);
return rtc_valid_tm(tm);
}
static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct sprd_rtc *rtc = dev_get_drvdata(dev);
time64_t secs = rtc_tm_to_time64(tm);
u32 val;
int ret;
ret = sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
if (ret)
return ret;
if (!rtc->valid) {
/*
* Set SPRD_RTC_POWER_RESET_FLAG to indicate now RTC has valid
* time values.
*/
ret = regmap_update_bits(rtc->regmap,
rtc->base + SPRD_RTC_SPG_UPD,
SPRD_RTC_POWER_RESET_FLAG,
SPRD_RTC_POWER_RESET_FLAG);
if (ret)
return ret;
ret = regmap_read_poll_timeout(rtc->regmap,
rtc->base + SPRD_RTC_INT_RAW_STS,
val, (val & SPRD_RTC_SPG_UPD_EN),
SPRD_RTC_POLL_DELAY_US,
SPRD_RTC_POLL_TIMEOUT);
if (ret) {
dev_err(rtc->dev, "failed to update SPG value:%d\n",
ret);
return ret;
}
rtc->valid = true;
}
return 0;
}
static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct sprd_rtc *rtc = dev_get_drvdata(dev);
time64_t secs;
int ret;
u32 val;
/*
* If aie_timer is enabled, we should get the normal alarm time.
* Otherwise we should get auxiliary alarm time.
*/
if (rtc->rtc && rtc->rtc->aie_timer.enabled == 0)
return sprd_rtc_read_aux_alarm(dev, alrm);
ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs);
if (ret)
return ret;
rtc_time64_to_tm(secs, &alrm->time);
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
if (ret)
return ret;
alrm->enabled = !!(val & SPRD_RTC_ALARM_EN);
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
if (ret)
return ret;
alrm->pending = !!(val & SPRD_RTC_ALARM_EN);
return 0;
}
static int sprd_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct sprd_rtc *rtc = dev_get_drvdata(dev);
time64_t secs = rtc_tm_to_time64(&alrm->time);
struct rtc_time aie_time =
rtc_ktime_to_tm(rtc->rtc->aie_timer.node.expires);
int ret;
/*
* We have 2 groups alarms: normal alarm and auxiliary alarm. Since
* both normal alarm event and auxiliary alarm event can wake up system
* from deep sleep, but only alarm event can power up system from power
* down status. Moreover we do not need to poll about 125ms when
* updating auxiliary alarm registers. Thus we usually set auxiliary
* alarm when wake up system from deep sleep, and for other scenarios,
* we should set normal alarm with polling status.
*
* So here we check if the alarm time is set by aie_timer, if yes, we
* should set normal alarm, if not, we should set auxiliary alarm which
* means it is just a wake event.
*/
if (!rtc->rtc->aie_timer.enabled || rtc_tm_sub(&aie_time, &alrm->time))
return sprd_rtc_set_aux_alarm(dev, alrm);
/* clear the alarm interrupt status firstly */
ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
SPRD_RTC_ALARM_EN);
if (ret)
return ret;
ret = sprd_rtc_set_secs(rtc, SPRD_RTC_ALARM, secs);
if (ret)
return ret;
if (alrm->enabled) {
ret = regmap_update_bits(rtc->regmap,
rtc->base + SPRD_RTC_INT_EN,
SPRD_RTC_ALARM_EN,
SPRD_RTC_ALARM_EN);
if (ret)
return ret;
/* unlock the alarm to enable the alarm function. */
ret = sprd_rtc_lock_alarm(rtc, false);
} else {
regmap_update_bits(rtc->regmap,
rtc->base + SPRD_RTC_INT_EN,
SPRD_RTC_ALARM_EN, 0);
/*
* Lock the alarm function in case fake alarm event will power
* up systems.
*/
ret = sprd_rtc_lock_alarm(rtc, true);
}
return ret;
}
static int sprd_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct sprd_rtc *rtc = dev_get_drvdata(dev);
int ret;
if (enabled) {
ret = regmap_update_bits(rtc->regmap,
rtc->base + SPRD_RTC_INT_EN,
SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN,
SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN);
if (ret)
return ret;
ret = sprd_rtc_lock_alarm(rtc, false);
} else {
regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN, 0);
ret = sprd_rtc_lock_alarm(rtc, true);
}
return ret;
}
static const struct rtc_class_ops sprd_rtc_ops = {
.read_time = sprd_rtc_read_time,
.set_time = sprd_rtc_set_time,
.read_alarm = sprd_rtc_read_alarm,
.set_alarm = sprd_rtc_set_alarm,
.alarm_irq_enable = sprd_rtc_alarm_irq_enable,
};
static irqreturn_t sprd_rtc_handler(int irq, void *dev_id)
{
struct sprd_rtc *rtc = dev_id;
int ret;
ret = sprd_rtc_clear_alarm_ints(rtc);
if (ret)
return IRQ_RETVAL(ret);
rtc_update_irq(rtc->rtc, 1, RTC_AF | RTC_IRQF);
return IRQ_HANDLED;
}
static int sprd_rtc_check_power_down(struct sprd_rtc *rtc)
{
u32 val;
int ret;
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
if (ret)
return ret;
/*
* If the SPRD_RTC_POWER_RESET_FLAG was not set, which means the RTC has
* been powered down, so the RTC time values are invalid.
*/
rtc->valid = (val & SPRD_RTC_POWER_RESET_FLAG) ? true : false;
return 0;
}
static int sprd_rtc_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct sprd_rtc *rtc;
int ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!rtc->regmap)
return -ENODEV;
ret = of_property_read_u32(node, "reg", &rtc->base);
if (ret) {
dev_err(&pdev->dev, "failed to get RTC base address\n");
return ret;
}
rtc->irq = platform_get_irq(pdev, 0);
if (rtc->irq < 0) {
dev_err(&pdev->dev, "failed to get RTC irq number\n");
return rtc->irq;
}
rtc->dev = &pdev->dev;
platform_set_drvdata(pdev, rtc);
/* clear all RTC interrupts and disable all RTC interrupts */
ret = sprd_rtc_disable_ints(rtc);
if (ret) {
dev_err(&pdev->dev, "failed to disable RTC interrupts\n");
return ret;
}
/* check if RTC time values are valid */
ret = sprd_rtc_check_power_down(rtc);
if (ret) {
dev_err(&pdev->dev, "failed to check RTC time values\n");
return ret;
}
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
sprd_rtc_handler,
IRQF_ONESHOT | IRQF_EARLY_RESUME,
pdev->name, rtc);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request RTC irq\n");
return ret;
}
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&sprd_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc))
return PTR_ERR(rtc->rtc);
device_init_wakeup(&pdev->dev, 1);
return 0;
}
static int sprd_rtc_remove(struct platform_device *pdev)
{
device_init_wakeup(&pdev->dev, 0);
return 0;
}
static const struct of_device_id sprd_rtc_of_match[] = {
{ .compatible = "sprd,sc2731-rtc", },
{ },
};
MODULE_DEVICE_TABLE(of, sprd_rtc_of_match);
static struct platform_driver sprd_rtc_driver = {
.driver = {
.name = "sprd-rtc",
.of_match_table = sprd_rtc_of_match,
},
.probe = sprd_rtc_probe,
.remove = sprd_rtc_remove,
};
module_platform_driver(sprd_rtc_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Spreadtrum RTC Device Driver");
MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");

View File

@ -72,9 +72,10 @@ since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf)
retval = rtc_read_time(to_rtc_device(dev), &tm);
if (retval == 0) {
unsigned long time;
rtc_tm_to_time(&tm, &time);
retval = sprintf(buf, "%lu\n", time);
time64_t time;
time = rtc_tm_to_time64(&tm);
retval = sprintf(buf, "%lld\n", time);
}
return retval;
@ -132,7 +133,7 @@ static ssize_t
wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
unsigned long alarm;
time64_t alarm;
struct rtc_wkalrm alm;
/* Don't show disabled alarms. For uniformity, RTC alarms are
@ -145,8 +146,8 @@ wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
*/
retval = rtc_read_alarm(to_rtc_device(dev), &alm);
if (retval == 0 && alm.enabled) {
rtc_tm_to_time(&alm.time, &alarm);
retval = sprintf(buf, "%lu\n", alarm);
alarm = rtc_tm_to_time64(&alm.time);
retval = sprintf(buf, "%lld\n", alarm);
}
return retval;
@ -157,8 +158,8 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t n)
{
ssize_t retval;
unsigned long now, alarm;
unsigned long push = 0;
time64_t now, alarm;
time64_t push = 0;
struct rtc_wkalrm alm;
struct rtc_device *rtc = to_rtc_device(dev);
const char *buf_ptr;
@ -170,7 +171,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
retval = rtc_read_time(rtc, &alm.time);
if (retval < 0)
return retval;
rtc_tm_to_time(&alm.time, &now);
now = rtc_tm_to_time64(&alm.time);
buf_ptr = buf;
if (*buf_ptr == '+') {
@ -181,7 +182,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
} else
adjust = 1;
}
retval = kstrtoul(buf_ptr, 0, &alarm);
retval = kstrtos64(buf_ptr, 0, &alarm);
if (retval)
return retval;
if (adjust) {
@ -197,7 +198,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
return retval;
if (alm.enabled) {
if (push) {
rtc_tm_to_time(&alm.time, &push);
push = rtc_tm_to_time64(&alm.time);
alarm += push;
} else
return -EBUSY;
@ -212,7 +213,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
*/
alarm = now + 300;
}
rtc_time_to_tm(alarm, &alm.time);
rtc_time64_to_tm(alarm, &alm.time);
retval = rtc_set_alarm(rtc, &alm);
return (retval < 0) ? retval : n;

View File

@ -52,6 +52,7 @@ struct xgene_rtc_dev {
void __iomem *csr_base;
struct clk *clk;
unsigned int irq_wake;
unsigned int irq_enabled;
};
static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm)
@ -104,15 +105,19 @@ static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled)
return 0;
}
static int xgene_rtc_alarm_irq_enabled(struct device *dev)
{
struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
return readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE ? 1 : 0;
}
static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
unsigned long rtc_time;
unsigned long alarm_time;
rtc_time = readl(pdata->csr_base + RTC_CCVR);
rtc_tm_to_time(&alrm->time, &alarm_time);
pdata->alarm_time = alarm_time;
writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR);
@ -180,12 +185,18 @@ static int xgene_rtc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Couldn't get the clock for RTC\n");
return -ENODEV;
}
clk_prepare_enable(pdata->clk);
ret = clk_prepare_enable(pdata->clk);
if (ret)
return ret;
/* Turn on the clock and the crystal */
writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR);
device_init_wakeup(&pdev->dev, 1);
ret = device_init_wakeup(&pdev->dev, 1);
if (ret) {
clk_disable_unprepare(pdata->clk);
return ret;
}
pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&xgene_rtc_ops, THIS_MODULE);
@ -210,45 +221,55 @@ static int xgene_rtc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int xgene_rtc_suspend(struct device *dev)
static int __maybe_unused xgene_rtc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
int irq;
irq = platform_get_irq(pdev, 0);
/*
* If this RTC alarm will be used for waking the system up,
* don't disable it of course. Else we just disable the alarm
* and await suspension.
*/
if (device_may_wakeup(&pdev->dev)) {
if (!enable_irq_wake(irq))
pdata->irq_wake = 1;
} else {
pdata->irq_enabled = xgene_rtc_alarm_irq_enabled(dev);
xgene_rtc_alarm_irq_enable(dev, 0);
clk_disable(pdata->clk);
clk_disable_unprepare(pdata->clk);
}
return 0;
}
static int xgene_rtc_resume(struct device *dev)
static int __maybe_unused xgene_rtc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
int irq;
int rc;
irq = platform_get_irq(pdev, 0);
if (device_may_wakeup(&pdev->dev)) {
if (pdata->irq_wake) {
disable_irq_wake(irq);
pdata->irq_wake = 0;
}
} else {
clk_enable(pdata->clk);
xgene_rtc_alarm_irq_enable(dev, 1);
rc = clk_prepare_enable(pdata->clk);
if (rc) {
dev_err(dev, "Unable to enable clock error %d\n", rc);
return rc;
}
xgene_rtc_alarm_irq_enable(dev, pdata->irq_enabled);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume);