Watch
1
Fork
You've already forked kernel_a52xq
0
mirror of https://github.com/a52xq-dev/kernel.git synced 2026-10-18 21:58:11 +07:00

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,
.size = DS1305_NVRAM_LEN,
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 @@ read_rtc:
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;
}
return 0;
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))
val = 1;
else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1))
val = ilog2(M41T80_SQW_MAX_FREQ) - val;
else
return -EINVAL;
}
if (rate >= M41T80_SQW_MAX_FREQ)
val = 1;
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)
return ret;
return -EINVAL;
if (!ret)
m41t80->freq = m41t80_decode_freq(val);
return ret;
}
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");

Some files were not shown because too many files have changed in this diff Show more