diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-23 07:58:23 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-23 07:58:23 +0100 |
commit | 1b8c5cd890e274781a8ef61585ae03614be9ccd8 (patch) | |
tree | cf8a6735bd8970f311daee3c6874a4fdc7de0356 | |
parent | Merge tag 'for-linus-20171120' of git://git.infradead.org/linux-mtd (diff) | |
parent | dt-bindings: rtc: imxdi: Improve the bindings text (diff) | |
download | linux-1b8c5cd890e274781a8ef61585ae03614be9ccd8.tar.xz linux-1b8c5cd890e274781a8ef61585ae03614be9ccd8.zip |
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
...
30 files changed, 1891 insertions, 283 deletions
diff --git a/Documentation/devicetree/bindings/rtc/imxdi-rtc.txt b/Documentation/devicetree/bindings/rtc/imxdi-rtc.txt index 323cf26374cb..c797bc9d77d2 100644 --- a/Documentation/devicetree/bindings/rtc/imxdi-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/imxdi-rtc.txt @@ -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>; }; diff --git a/Documentation/devicetree/bindings/rtc/pcf85363.txt b/Documentation/devicetree/bindings/rtc/pcf85363.txt new file mode 100644 index 000000000000..76fdabc59742 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/pcf85363.txt @@ -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>; +}; + diff --git a/Documentation/devicetree/bindings/rtc/rtc-mt7622.txt b/Documentation/devicetree/bindings/rtc/rtc-mt7622.txt new file mode 100644 index 000000000000..09fe8f51476f --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-mt7622.txt @@ -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"; +}; diff --git a/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt b/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt new file mode 100644 index 000000000000..7c170da0d4b7 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt @@ -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>; + }; + }; diff --git a/Documentation/devicetree/bindings/trivial-devices.txt b/Documentation/devicetree/bindings/trivial-devices.txt index 678039d4d5e5..5f3143f97098 100644 --- a/Documentation/devicetree/bindings/trivial-devices.txt +++ b/Documentation/devicetree/bindings/trivial-devices.txt @@ -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 diff --git a/MAINTAINERS b/MAINTAINERS index 44512c346206..aa71ab52fd76 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e0e58f3b1420..b59a31b079a5 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -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" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 0bf1fc02b82c..f2f50c11dc38 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -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 diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8cec9a02c0b8..672b192f8153 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -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 diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index fea9a60b06cf..b033bc556f5d 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -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; } diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 21f355c37eab..1e4978c96ffd 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -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 = { diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index e221b78b6f10..de81ecedd571 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -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; diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 72b22935eb62..d8df2e9e14ad 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -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); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e7d9215c9201..923dde912f60 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -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); diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index aa0d2c6f1edc..4d5b007d7fc6 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -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, }; diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 1b2dcb58c0ab..1e95312a6f2e 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -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", }, diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 64989afffa3d..ff65a7d2b9c9 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -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; } } diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index f4c070ea8384..c90fba3ed861 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -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); diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 02af045305dd..d9aea9b6d9cd 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -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); diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c new file mode 100644 index 000000000000..d79b9ae4d237 --- /dev/null +++ b/drivers/rtc/rtc-mt7622.c @@ -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"); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 13f7cd11c07e..1d666ac9ef70 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -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: diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 28c48b3c1946..c312af0db729 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -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, diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c new file mode 100644 index 000000000000..ea04e9f0930b --- /dev/null +++ b/drivers/rtc/rtc-pcf85363.c @@ -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, ®map_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"); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index cea6ea4df970..3efc86c25d27 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -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, diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index e1687e19c59f..82eb7da2c478 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -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); - free_irq(adev->irq[0], ldata); + 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->vendor = vendor; + 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; - goto out_no_irq; + 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]); } - 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, diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index aa09771de04f..3d6174eb32f6 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -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 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" }, diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 1ed3403ff8ac..5c5938ab3d86 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -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) diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c new file mode 100644 index 000000000000..d544d5268757 --- /dev/null +++ b/drivers/rtc/rtc-sc27xx.c @@ -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>"); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index e364550eb9a7..92ff2edb86a6 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -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; diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c index 65b432a096fe..0c34d3b81279 100644 --- a/drivers/rtc/rtc-xgene.c +++ b/drivers/rtc/rtc-xgene.c @@ -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); |