diff options
author | 2022-08-02 10:06:12 -0700 | |
---|---|---|
committer | 2022-08-02 10:06:12 -0700 | |
commit | 8bb5e7f4dcd9b9ef22a3ea25c9066a8a968f12dd (patch) | |
tree | 0f1383880607a227142f9388a066959926233ff1 /drivers/rtc | |
parent | Input: document the units for resolution of size axes (diff) | |
parent | Input: adc-joystick - fix ordering in adc_joystick_probe() (diff) | |
download | wireguard-linux-8bb5e7f4dcd9b9ef22a3ea25c9066a8a968f12dd.tar.xz wireguard-linux-8bb5e7f4dcd9b9ef22a3ea25c9066a8a968f12dd.zip |
Merge branch 'next' into for-linus
Prepare input updates for 5.20 (or 6.0) merge window.
Diffstat (limited to 'drivers/rtc')
37 files changed, 1183 insertions, 271 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d85a3c31347c..a00f901b5c1d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -375,7 +375,7 @@ config RTC_DRV_MAX8997 config RTC_DRV_MAX77686 tristate "Maxim MAX77686" - depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST + depends on MFD_MAX77686 || MFD_MAX77620 || MFD_MAX77714 || COMPILE_TEST help If you say yes here you will get support for the RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC. @@ -1293,6 +1293,16 @@ config RTC_DRV_OPAL This driver can also be built as a module. If so, the module will be called rtc-opal. +config RTC_DRV_OPTEE + tristate "OP-TEE based RTC driver" + depends on OPTEE + help + Select this to get support for OP-TEE based RTC control on SoCs where + RTC are not accessible to the normal world (Linux). + + This driver can also be built as a module. If so, the module + will be called rtc-optee. + config RTC_DRV_ZYNQMP tristate "Xilinx Zynq Ultrascale+ MPSoC RTC" depends on OF && HAS_IOMEM @@ -1538,6 +1548,13 @@ config RTC_DRV_RS5C313 help If you say yes here you get support for the Ricoh RS5C313 RTC chips. +config RTC_DRV_RZN1 + tristate "Renesas RZ/N1 RTC" + depends on ARCH_RZN1 || COMPILE_TEST + depends on OF && HAS_IOMEM + help + If you say yes here you get support for the Renesas RZ/N1 RTC. + config RTC_DRV_GENERIC tristate "Generic RTC support" # Please consider writing a new RTC driver instead of using the generic diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e92f3e943245..fb04467b652d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_RTC_DRV_GAMECUBE) += rtc-gamecube.o obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o +obj-$(CONFIG_RTC_DRV_OPTEE) += rtc-optee.o obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o @@ -150,6 +151,7 @@ obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o +obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 4b460c61f1d8..3c8eec2218df 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -26,6 +26,15 @@ struct class *rtc_class; static void rtc_device_release(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); + struct timerqueue_head *head = &rtc->timerqueue; + struct timerqueue_node *node; + + mutex_lock(&rtc->ops_lock); + while ((node = timerqueue_getnext(head))) + timerqueue_del(head, node); + mutex_unlock(&rtc->ops_lock); + + cancel_work_sync(&rtc->irqwork); ida_simple_remove(&rtc_ida, rtc->id); mutex_destroy(&rtc->ops_lock); @@ -390,9 +399,6 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc) if (!rtc->ops->set_alarm) clear_bit(RTC_FEATURE_ALARM, rtc->features); - if (rtc->uie_unsupported) - clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); - if (rtc->ops->set_offset) set_bit(RTC_FEATURE_CORRECTION, rtc->features); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d8e835798153..9edd662c69ac 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -804,9 +804,13 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); struct rtc_time tm; ktime_t now; + int err; + + err = __rtc_read_time(rtc, &tm); + if (err) + return err; timer->enabled = 1; - __rtc_read_time(rtc, &tm); now = rtc_tm_to_ktime(tm); /* Skip over expired timers */ @@ -820,7 +824,6 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) trace_rtc_timer_enqueue(timer); if (!next || ktime_before(timer->node.expires, next->expires)) { struct rtc_wkalrm alarm; - int err; alarm.time = rtc_ktime_to_tm(timer->node.expires); alarm.enabled = 1; diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 2f83adef966e..6d66ab5a8b17 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -185,10 +185,9 @@ static int ds1302_probe(struct spi_device *spi) return 0; } -static int ds1302_remove(struct spi_device *spi) +static void ds1302_remove(struct spi_device *spi) { spi_set_drvdata(spi, NULL); - return 0; } #ifdef CONFIG_OF diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 9ef107b99b65..ed9360486953 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -720,7 +720,7 @@ static int ds1305_probe(struct spi_device *spi) return 0; } -static int ds1305_remove(struct spi_device *spi) +static void ds1305_remove(struct spi_device *spi) { struct ds1305 *ds1305 = spi_get_drvdata(spi); @@ -730,8 +730,6 @@ static int ds1305_remove(struct spi_device *spi) devm_free_irq(&spi->dev, spi->irq, ds1305); cancel_work_sync(&ds1305->work); } - - return 0; } static struct spi_driver ds1305_driver = { diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 336cb9aa5e33..d51565bcc189 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1955,7 +1955,7 @@ static int ds1307_probe(struct i2c_client *client, dev_info(ds1307->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n"); /* We cannot support UIE mode if we do not have an IRQ line */ - ds1307->rtc->uie_unsupported = 1; + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, ds1307->rtc->features); } if (want_irq) { diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c index f14ed6c96437..ed5a6ba89a3e 100644 --- a/drivers/rtc/rtc-ds1343.c +++ b/drivers/rtc/rtc-ds1343.c @@ -434,11 +434,9 @@ static int ds1343_probe(struct spi_device *spi) return 0; } -static int ds1343_remove(struct spi_device *spi) +static void ds1343_remove(struct spi_device *spi) { dev_pm_clear_wake_irq(&spi->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 75db7ab654a5..a24331ba8a5f 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1273,7 +1273,7 @@ ds1685_rtc_probe(struct platform_device *pdev) /* See if the platform doesn't support UIE. */ if (pdata->uie_unsupported) - rtc_dev->uie_unsupported = 1; + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc_dev->features); rtc->dev = rtc_dev; @@ -1285,13 +1285,10 @@ ds1685_rtc_probe(struct platform_device *pdev) * there won't be an automatic way of notifying the kernel about it, * unless ctrlc is explicitly polled. */ - if (!pdata->no_irq) { - ret = platform_get_irq(pdev, 0); - if (ret <= 0) - return ret; - - rtc->irq_num = ret; - + rtc->irq_num = platform_get_irq(pdev, 0); + if (rtc->irq_num <= 0) { + clear_bit(RTC_FEATURE_ALARM, rtc_dev->features); + } else { /* Request an IRQ. */ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_num, NULL, ds1685_rtc_irq_handler, @@ -1305,7 +1302,6 @@ ds1685_rtc_probe(struct platform_device *pdev) rtc->irq_num = 0; } } - rtc->no_irq = pdata->no_irq; /* Setup complete. */ ds1685_rtc_switch_to_bank0(rtc); @@ -1394,7 +1390,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev) * have been taken care of by the shutdown scripts and this * is the final function call. */ - if (!rtc->no_irq) + if (rtc->irq_num) disable_irq_nosync(rtc->irq_num); /* Oscillator must be on and the countdown chain enabled. */ diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 138c5e0046c8..11850c2880ad 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -261,15 +261,17 @@ static int __init efi_rtc_probe(struct platform_device *dev) if (efi.get_time(&eft, &cap) != EFI_SUCCESS) return -ENODEV; - rtc = devm_rtc_device_register(&dev->dev, "rtc-efi", &efi_rtc_ops, - THIS_MODULE); + rtc = devm_rtc_allocate_device(&dev->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); - rtc->uie_unsupported = 1; platform_set_drvdata(dev, rtc); - return 0; + rtc->ops = &efi_rtc_ops; + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); + set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features); + + return devm_rtc_register_device(rtc); } static struct platform_driver efi_rtc_driver = { diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c index 53bb08fe1cd4..25c6e7d9570f 100644 --- a/drivers/rtc/rtc-ftrtc010.c +++ b/drivers/rtc/rtc-ftrtc010.c @@ -137,26 +137,34 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev) ret = clk_prepare_enable(rtc->extclk); if (ret) { dev_err(dev, "failed to enable EXTCLK\n"); - return ret; + goto err_disable_pclk; } } rtc->rtc_irq = platform_get_irq(pdev, 0); - if (rtc->rtc_irq < 0) - return rtc->rtc_irq; + if (rtc->rtc_irq < 0) { + ret = rtc->rtc_irq; + goto err_disable_extclk; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; + if (!res) { + ret = -ENODEV; + goto err_disable_extclk; + } rtc->rtc_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!rtc->rtc_base) - return -ENOMEM; + if (!rtc->rtc_base) { + ret = -ENOMEM; + goto err_disable_extclk; + } rtc->rtc_dev = devm_rtc_allocate_device(dev); - if (IS_ERR(rtc->rtc_dev)) - return PTR_ERR(rtc->rtc_dev); + if (IS_ERR(rtc->rtc_dev)) { + ret = PTR_ERR(rtc->rtc_dev); + goto err_disable_extclk; + } rtc->rtc_dev->ops = &ftrtc010_rtc_ops; @@ -172,9 +180,15 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev) ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt, IRQF_SHARED, pdev->name, dev); if (unlikely(ret)) - return ret; + goto err_disable_extclk; return devm_rtc_register_device(rtc->rtc_dev); + +err_disable_extclk: + clk_disable_unprepare(rtc->extclk); +err_disable_pclk: + clk_disable_unprepare(rtc->pclk); + return ret; } static int ftrtc010_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-gamecube.c b/drivers/rtc/rtc-gamecube.c index f717b36f4738..c2717bb52b2b 100644 --- a/drivers/rtc/rtc-gamecube.c +++ b/drivers/rtc/rtc-gamecube.c @@ -235,6 +235,7 @@ static int gamecube_rtc_read_offset_from_sram(struct priv *d) } ret = of_address_to_resource(np, 0, &res); + of_node_put(np); if (ret) { pr_err("no io memory range found\n"); return -1; @@ -266,6 +267,7 @@ static int gamecube_rtc_read_offset_from_sram(struct priv *d) ret = regmap_read(d->regmap, RTC_SRAM_BIAS, &d->rtc_bias); if (ret) { pr_err("failed to get the RTC bias\n"); + iounmap(hw_srnprot); return -1; } diff --git a/drivers/rtc/rtc-goldfish.c b/drivers/rtc/rtc-goldfish.c index 7ab95d052644..59c0f38cc08d 100644 --- a/drivers/rtc/rtc-goldfish.c +++ b/drivers/rtc/rtc-goldfish.c @@ -10,18 +10,8 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/rtc.h> - -#define TIMER_TIME_LOW 0x00 /* get low bits of current time */ - /* and update TIMER_TIME_HIGH */ -#define TIMER_TIME_HIGH 0x04 /* get high bits of time at last */ - /* TIMER_TIME_LOW read */ -#define TIMER_ALARM_LOW 0x08 /* set low bits of alarm and */ - /* activate it */ -#define TIMER_ALARM_HIGH 0x0c /* set high bits of next alarm */ -#define TIMER_IRQ_ENABLED 0x10 -#define TIMER_CLEAR_ALARM 0x14 -#define TIMER_ALARM_STATUS 0x18 -#define TIMER_CLEAR_INTERRUPT 0x1c +#include <linux/goldfish.h> +#include <clocksource/timer-goldfish.h> struct goldfish_rtc { void __iomem *base; @@ -41,8 +31,8 @@ static int goldfish_rtc_read_alarm(struct device *dev, rtcdrv = dev_get_drvdata(dev); base = rtcdrv->base; - rtc_alarm_low = readl(base + TIMER_ALARM_LOW); - rtc_alarm_high = readl(base + TIMER_ALARM_HIGH); + rtc_alarm_low = gf_ioread32(base + TIMER_ALARM_LOW); + rtc_alarm_high = gf_ioread32(base + TIMER_ALARM_HIGH); rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low; do_div(rtc_alarm, NSEC_PER_SEC); @@ -50,7 +40,7 @@ static int goldfish_rtc_read_alarm(struct device *dev, rtc_time64_to_tm(rtc_alarm, &alrm->time); - if (readl(base + TIMER_ALARM_STATUS)) + if (gf_ioread32(base + TIMER_ALARM_STATUS)) alrm->enabled = 1; else alrm->enabled = 0; @@ -71,18 +61,18 @@ static int goldfish_rtc_set_alarm(struct device *dev, if (alrm->enabled) { rtc_alarm64 = rtc_tm_to_time64(&alrm->time) * NSEC_PER_SEC; - writel((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH); - writel(rtc_alarm64, base + TIMER_ALARM_LOW); - writel(1, base + TIMER_IRQ_ENABLED); + gf_iowrite32((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH); + gf_iowrite32(rtc_alarm64, base + TIMER_ALARM_LOW); + gf_iowrite32(1, base + TIMER_IRQ_ENABLED); } else { /* * if this function was called with enabled=0 * then it could mean that the application is * trying to cancel an ongoing alarm */ - rtc_status_reg = readl(base + TIMER_ALARM_STATUS); + rtc_status_reg = gf_ioread32(base + TIMER_ALARM_STATUS); if (rtc_status_reg) - writel(1, base + TIMER_CLEAR_ALARM); + gf_iowrite32(1, base + TIMER_CLEAR_ALARM); } return 0; @@ -98,9 +88,9 @@ static int goldfish_rtc_alarm_irq_enable(struct device *dev, base = rtcdrv->base; if (enabled) - writel(1, base + TIMER_IRQ_ENABLED); + gf_iowrite32(1, base + TIMER_IRQ_ENABLED); else - writel(0, base + TIMER_IRQ_ENABLED); + gf_iowrite32(0, base + TIMER_IRQ_ENABLED); return 0; } @@ -110,7 +100,7 @@ static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id) struct goldfish_rtc *rtcdrv = dev_id; void __iomem *base = rtcdrv->base; - writel(1, base + TIMER_CLEAR_INTERRUPT); + gf_iowrite32(1, base + TIMER_CLEAR_INTERRUPT); rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF); @@ -128,8 +118,8 @@ static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm) rtcdrv = dev_get_drvdata(dev); base = rtcdrv->base; - time_low = readl(base + TIMER_TIME_LOW); - time_high = readl(base + TIMER_TIME_HIGH); + time_low = gf_ioread32(base + TIMER_TIME_LOW); + time_high = gf_ioread32(base + TIMER_TIME_HIGH); time = (time_high << 32) | time_low; do_div(time, NSEC_PER_SEC); @@ -149,8 +139,8 @@ static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm) base = rtcdrv->base; now64 = rtc_tm_to_time64(tm) * NSEC_PER_SEC; - writel((now64 >> 32), base + TIMER_TIME_HIGH); - writel(now64, base + TIMER_TIME_LOW); + gf_iowrite32((now64 >> 32), base + TIMER_TIME_HIGH); + gf_iowrite32(now64, base + TIMER_TIME_LOW); return 0; } diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index 0751cae27285..90e602e99d03 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -220,24 +220,6 @@ static int hym8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) u8 buf[4]; int ret; - /* - * The alarm has no seconds so deal with it - */ - if (alm_tm->tm_sec) { - alm_tm->tm_sec = 0; - alm_tm->tm_min++; - if (alm_tm->tm_min >= 60) { - alm_tm->tm_min = 0; - alm_tm->tm_hour++; - if (alm_tm->tm_hour >= 24) { - alm_tm->tm_hour = 0; - alm_tm->tm_mday++; - if (alm_tm->tm_mday > 31) - alm_tm->tm_mday = 0; - } - } - } - ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); if (ret < 0) return ret; @@ -523,6 +505,10 @@ static int hym8563_probe(struct i2c_client *client, if (!hym8563) return -ENOMEM; + hym8563->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(hym8563->rtc)) + return PTR_ERR(hym8563->rtc); + hym8563->client = client; i2c_set_clientdata(client, hym8563); @@ -557,19 +543,15 @@ static int hym8563_probe(struct i2c_client *client, dev_dbg(&client->dev, "rtc information is %s\n", (ret & HYM8563_SEC_VL) ? "invalid" : "valid"); - hym8563->rtc = devm_rtc_device_register(&client->dev, client->name, - &hym8563_rtc_ops, THIS_MODULE); - if (IS_ERR(hym8563->rtc)) - return PTR_ERR(hym8563->rtc); - - /* the hym8563 alarm only supports a minute accuracy */ - hym8563->rtc->uie_unsupported = 1; + hym8563->rtc->ops = &hym8563_rtc_ops; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, hym8563->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, hym8563->rtc->features); #ifdef CONFIG_COMMON_CLK hym8563_clkout_register_clk(hym8563); #endif - return 0; + return devm_rtc_register_device(hym8563->rtc); } static const struct i2c_device_id hym8563_id[] = { diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 6d383b629d20..d868458cd40e 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -932,10 +932,8 @@ static int m41t80_probe(struct i2c_client *client, m41t80_data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; m41t80_data->rtc->range_max = RTC_TIMESTAMP_END_2099; - if (client->irq <= 0) { - /* We cannot support UIE mode if we do not have an IRQ line */ - m41t80_data->rtc->uie_unsupported = 1; - } + if (client->irq <= 0) + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, m41t80_data->rtc->features); /* Make sure HT (Halt Update) bit is cleared */ rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index eae7cb9faf1e..b0250d91fb00 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -19,6 +19,7 @@ #define MAX77686_I2C_ADDR_RTC (0x0C >> 1) #define MAX77620_I2C_ADDR_RTC 0x68 +#define MAX77714_I2C_ADDR_RTC 0x48 #define MAX77686_INVALID_I2C_ADDR (-1) /* Define non existing register */ @@ -34,9 +35,6 @@ #define RTC_UDR_MASK BIT(RTC_UDR_SHIFT) #define RTC_RBUDR_SHIFT 4 #define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT) -/* RTC Hour register */ -#define HOUR_PM_SHIFT 6 -#define HOUR_PM_MASK BIT(HOUR_PM_SHIFT) /* RTC Alarm Enable */ #define ALARM_ENABLE_SHIFT 7 #define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT) @@ -57,28 +55,31 @@ enum { RTC_WEEKDAY, RTC_MONTH, RTC_YEAR, - RTC_DATE, + RTC_MONTHDAY, RTC_NR_TIME }; +/** + * struct max77686_rtc_driver_data - model-specific configuration + * @delay: Minimum usecs needed for a RTC update + * @mask: Mask used to read RTC registers value + * @map: Registers offset to I2C addresses map + * @alarm_enable_reg: Has a separate alarm enable register? + * @rtc_i2c_addr: I2C address for RTC block + * @rtc_irq_from_platform: RTC interrupt via platform resource + * @alarm_pending_status_reg: Pending alarm status register + * @rtc_irq_chip: RTC IRQ CHIP for regmap + * @regmap_config: regmap configuration for the chip + */ struct max77686_rtc_driver_data { - /* Minimum usecs needed for a RTC update */ unsigned long delay; - /* Mask used to read RTC registers value */ u8 mask; - /* Registers offset to I2C addresses map */ const unsigned int *map; - /* Has a separate alarm enable register? */ bool alarm_enable_reg; - /* I2C address for RTC block */ int rtc_i2c_addr; - /* RTC interrupt via platform resource */ bool rtc_irq_from_platform; - /* Pending alarm status register */ int alarm_pending_status_reg; - /* RTC IRQ CHIP for regmap */ const struct regmap_irq_chip *rtc_irq_chip; - /* regmap configuration for the chip */ const struct regmap_config *regmap_config; }; @@ -96,7 +97,6 @@ struct max77686_rtc_info { int rtc_irq; int virq; - int rtc_24hr_mode; }; enum MAX77686_RTC_OP { @@ -116,7 +116,7 @@ enum max77686_rtc_reg_offset { REG_RTC_WEEKDAY, REG_RTC_MONTH, REG_RTC_YEAR, - REG_RTC_DATE, + REG_RTC_MONTHDAY, REG_ALARM1_SEC, REG_ALARM1_MIN, REG_ALARM1_HOUR, @@ -147,7 +147,7 @@ static const unsigned int max77686_map[REG_RTC_END] = { [REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY, [REG_RTC_MONTH] = MAX77686_RTC_MONTH, [REG_RTC_YEAR] = MAX77686_RTC_YEAR, - [REG_RTC_DATE] = MAX77686_RTC_DATE, + [REG_RTC_MONTHDAY] = MAX77686_RTC_MONTHDAY, [REG_ALARM1_SEC] = MAX77686_ALARM1_SEC, [REG_ALARM1_MIN] = MAX77686_ALARM1_MIN, [REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR, @@ -201,6 +201,28 @@ static const struct max77686_rtc_driver_data max77686_drv_data = { .regmap_config = &max77686_rtc_regmap_config, }; +static const struct regmap_irq_chip max77714_rtc_irq_chip = { + .name = "max77714-rtc", + .status_base = MAX77686_RTC_INT, + .mask_base = MAX77686_RTC_INTM, + .num_regs = 1, + .irqs = max77686_rtc_irqs, + .num_irqs = ARRAY_SIZE(max77686_rtc_irqs) - 1, /* no WTSR on 77714 */ +}; + +static const struct max77686_rtc_driver_data max77714_drv_data = { + .delay = 16000, + .mask = 0x7f, + .map = max77686_map, + .alarm_enable_reg = false, + .rtc_irq_from_platform = false, + /* On MAX77714 RTCA1 is BIT 1 of RTCINT (0x00). Not supported by this driver. */ + .alarm_pending_status_reg = MAX77686_INVALID_REG, + .rtc_i2c_addr = MAX77714_I2C_ADDR_RTC, + .rtc_irq_chip = &max77714_rtc_irq_chip, + .regmap_config = &max77686_rtc_regmap_config, +}; + static const struct regmap_config max77620_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -230,7 +252,7 @@ static const unsigned int max77802_map[REG_RTC_END] = { [REG_RTC_WEEKDAY] = MAX77802_RTC_WEEKDAY, [REG_RTC_MONTH] = MAX77802_RTC_MONTH, [REG_RTC_YEAR] = MAX77802_RTC_YEAR, - [REG_RTC_DATE] = MAX77802_RTC_DATE, + [REG_RTC_MONTHDAY] = MAX77802_RTC_MONTHDAY, [REG_ALARM1_SEC] = MAX77802_ALARM1_SEC, [REG_ALARM1_MIN] = MAX77802_ALARM1_MIN, [REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR, @@ -275,17 +297,11 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, tm->tm_sec = data[RTC_SEC] & mask; tm->tm_min = data[RTC_MIN] & mask; - if (info->rtc_24hr_mode) { - tm->tm_hour = data[RTC_HOUR] & 0x1f; - } else { - tm->tm_hour = data[RTC_HOUR] & 0x0f; - if (data[RTC_HOUR] & HOUR_PM_MASK) - tm->tm_hour += 12; - } + tm->tm_hour = data[RTC_HOUR] & 0x1f; /* Only a single bit is set in data[], so fls() would be equivalent */ tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1; - tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mday = data[RTC_MONTHDAY] & 0x1f; tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; tm->tm_year = data[RTC_YEAR] & mask; tm->tm_yday = 0; @@ -306,7 +322,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data, data[RTC_MIN] = tm->tm_min; data[RTC_HOUR] = tm->tm_hour; data[RTC_WEEKDAY] = 1 << tm->tm_wday; - data[RTC_DATE] = tm->tm_mday; + data[RTC_MONTHDAY] = tm->tm_mday; data[RTC_MONTH] = tm->tm_mon + 1; if (info->drv_data->alarm_enable_reg) { @@ -562,8 +578,8 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); if (data[RTC_YEAR] & info->drv_data->mask) data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); - if (data[RTC_DATE] & 0x1f) - data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_MONTHDAY] & 0x1f) + data[RTC_MONTHDAY] |= (1 << ALARM_ENABLE_SHIFT); ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC], data, ARRAY_SIZE(data)); @@ -659,8 +675,6 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); - info->rtc_24hr_mode = 1; - ret = regmap_bulk_write(info->rtc_regmap, info->drv_data->map[REG_RTC_CONTROLM], data, ARRAY_SIZE(data)); @@ -852,6 +866,7 @@ static const struct platform_device_id rtc_id[] = { { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, }, { "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, }, { "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data, }, + { "max77714-rtc", .driver_data = (kernel_ulong_t)&max77714_drv_data, }, {}, }; MODULE_DEVICE_TABLE(platform, rtc_id); diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index ae9f131b43c0..522449b25921 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -176,6 +176,17 @@ int mc146818_get_time(struct rtc_time *time) } EXPORT_SYMBOL_GPL(mc146818_get_time); +/* AMD systems don't allow access to AltCentury with DV1 */ +static bool apply_amd_register_a_behavior(void) +{ +#ifdef CONFIG_X86 + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD || + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) + return true; +#endif + return false; +} + /* Set the current date and time in the real time clock. */ int mc146818_set_time(struct rtc_time *time) { @@ -232,8 +243,10 @@ int mc146818_set_time(struct rtc_time *time) if (yrs >= 100) yrs -= 100; - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { + spin_lock_irqsave(&rtc_lock, flags); + save_control = CMOS_READ(RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { sec = bin2bcd(sec); min = bin2bcd(min); hrs = bin2bcd(hrs); @@ -247,7 +260,10 @@ int mc146818_set_time(struct rtc_time *time) save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + if (apply_amd_register_a_behavior()) + CMOS_WRITE((save_freq_select & ~RTC_AMD_BANK_SELECT), RTC_FREQ_SELECT); + else + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); #ifdef CONFIG_MACH_DECSTATION CMOS_WRITE(real_yrs, RTC_DEC_YEAR); diff --git a/drivers/rtc/rtc-meson.c b/drivers/rtc/rtc-meson.c index 44bdc8b4a90d..db1d626edca5 100644 --- a/drivers/rtc/rtc-meson.c +++ b/drivers/rtc/rtc-meson.c @@ -399,7 +399,7 @@ static struct platform_driver meson_rtc_driver = { module_platform_driver(meson_rtc_driver); MODULE_DESCRIPTION("Amlogic Meson RTC Driver"); -MODULE_AUTHOR("Ben Dooks <ben.doosk@codethink.co.uk>"); +MODULE_AUTHOR("Ben Dooks <ben.dooks@codethink.co.uk>"); MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:meson-rtc"); diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index bb2ea9bc56f2..6d7656a75cae 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -210,20 +210,6 @@ static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); struct mpc5121_rtc_regs __iomem *regs = rtc->regs; - /* - * the alarm has no seconds so deal with it - */ - if (alarm->time.tm_sec) { - alarm->time.tm_sec = 0; - alarm->time.tm_min++; - if (alarm->time.tm_min >= 60) { - alarm->time.tm_min = 0; - alarm->time.tm_hour++; - if (alarm->time.tm_hour >= 24) - alarm->time.tm_hour = 0; - } - } - alarm->time.tm_mday = -1; alarm->time.tm_mon = -1; alarm->time.tm_year = -1; @@ -349,7 +335,8 @@ static int mpc5121_rtc_probe(struct platform_device *op) } rtc->rtc->ops = &mpc5200_rtc_ops; - rtc->rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc->features); rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_0000; rtc->rtc->range_max = 65733206399ULL; /* 4052-12-31 23:59:59 */ diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 80dc479a6ff0..1d297af80f87 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -269,6 +269,8 @@ static int mtk_rtc_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; rtc->addr_base = res->start; rtc->data = of_device_get_match_data(&pdev->dev); diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 0f08f22df869..53d4e253e81f 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -311,7 +311,7 @@ static int mxc_rtc_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; - pdata->devtype = (enum imx_rtc_type)of_device_get_match_data(&pdev->dev); + pdata->devtype = (uintptr_t)of_device_get_match_data(&pdev->dev); pdata->ioaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pdata->ioaddr)) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index f8f49a969c23..ad41aaf8a17f 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -250,7 +250,7 @@ static int opal_rtc_probe(struct platform_device *pdev) rtc->ops = &opal_rtc_ops; rtc->range_min = RTC_TIMESTAMP_BEGIN_0000; rtc->range_max = RTC_TIMESTAMP_END_9999; - rtc->uie_unsupported = 1; + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); return devm_rtc_register_device(rtc); } diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c new file mode 100644 index 000000000000..9f8b5d4a8f6b --- /dev/null +++ b/drivers/rtc/rtc-optee.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Microchip. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/tee_drv.h> + +#define RTC_INFO_VERSION 0x1 + +#define TA_CMD_RTC_GET_INFO 0x0 +#define TA_CMD_RTC_GET_TIME 0x1 +#define TA_CMD_RTC_SET_TIME 0x2 +#define TA_CMD_RTC_GET_OFFSET 0x3 +#define TA_CMD_RTC_SET_OFFSET 0x4 + +#define TA_RTC_FEATURE_CORRECTION BIT(0) + +struct optee_rtc_time { + u32 tm_sec; + u32 tm_min; + u32 tm_hour; + u32 tm_mday; + u32 tm_mon; + u32 tm_year; + u32 tm_wday; +}; + +struct optee_rtc_info { + u64 version; + u64 features; + struct optee_rtc_time range_min; + struct optee_rtc_time range_max; +}; + +/** + * struct optee_rtc - OP-TEE RTC private data + * @dev: OP-TEE based RTC device. + * @ctx: OP-TEE context handler. + * @session_id: RTC TA session identifier. + * @shm: Memory pool shared with RTC device. + * @features: Bitfield of RTC features + */ +struct optee_rtc { + struct device *dev; + struct tee_context *ctx; + u32 session_id; + struct tee_shm *shm; + u64 features; +}; + +static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct optee_rtc_time *optee_tm; + struct tee_param param[4] = {0}; + int ret; + + inv_arg.func = TA_CMD_RTC_GET_TIME; + inv_arg.session = priv->session_id; + inv_arg.num_params = 4; + + /* Fill invoke cmd params */ + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + param[0].u.memref.shm = priv->shm; + param[0].u.memref.size = sizeof(struct optee_rtc_time); + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + optee_tm = tee_shm_get_va(priv->shm, 0); + if (IS_ERR(optee_tm)) + return PTR_ERR(optee_tm); + + if (param[0].u.memref.size != sizeof(*optee_tm)) + return -EPROTO; + + tm->tm_sec = optee_tm->tm_sec; + tm->tm_min = optee_tm->tm_min; + tm->tm_hour = optee_tm->tm_hour; + tm->tm_mday = optee_tm->tm_mday; + tm->tm_mon = optee_tm->tm_mon; + tm->tm_year = optee_tm->tm_year - 1900; + tm->tm_wday = optee_tm->tm_wday; + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); + + return 0; +} + +static int optee_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[4] = {0}; + struct optee_rtc_time optee_tm; + void *rtc_data; + int ret; + + optee_tm.tm_sec = tm->tm_sec; + optee_tm.tm_min = tm->tm_min; + optee_tm.tm_hour = tm->tm_hour; + optee_tm.tm_mday = tm->tm_mday; + optee_tm.tm_mon = tm->tm_mon; + optee_tm.tm_year = tm->tm_year + 1900; + optee_tm.tm_wday = tm->tm_wday; + + inv_arg.func = TA_CMD_RTC_SET_TIME; + inv_arg.session = priv->session_id; + inv_arg.num_params = 4; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + param[0].u.memref.shm = priv->shm; + param[0].u.memref.size = sizeof(struct optee_rtc_time); + + rtc_data = tee_shm_get_va(priv->shm, 0); + if (IS_ERR(rtc_data)) + return PTR_ERR(rtc_data); + + memcpy(rtc_data, &optee_tm, sizeof(struct optee_rtc_time)); + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + return 0; +} + +static int optee_rtc_readoffset(struct device *dev, long *offset) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[4] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) + return -EOPNOTSUPP; + + inv_arg.func = TA_CMD_RTC_GET_OFFSET; + inv_arg.session = priv->session_id; + inv_arg.num_params = 4; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + *offset = param[0].u.value.a; + + return 0; +} + +static int optee_rtc_setoffset(struct device *dev, long offset) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[4] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) + return -EOPNOTSUPP; + + inv_arg.func = TA_CMD_RTC_SET_OFFSET; + inv_arg.session = priv->session_id; + inv_arg.num_params = 4; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + param[0].u.value.a = offset; + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + return 0; +} + +static const struct rtc_class_ops optee_rtc_ops = { + .read_time = optee_rtc_readtime, + .set_time = optee_rtc_settime, + .set_offset = optee_rtc_setoffset, + .read_offset = optee_rtc_readoffset, +}; + +static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc, + u64 *features) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[4] = {0}; + struct optee_rtc_info *info; + struct optee_rtc_time *tm; + int ret; + + inv_arg.func = TA_CMD_RTC_GET_INFO; + inv_arg.session = priv->session_id; + inv_arg.num_params = 4; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + param[0].u.memref.shm = priv->shm; + param[0].u.memref.size = sizeof(*info); + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + info = tee_shm_get_va(priv->shm, 0); + if (IS_ERR(info)) + return PTR_ERR(info); + + if (param[0].u.memref.size != sizeof(*info)) + return -EPROTO; + + if (info->version != RTC_INFO_VERSION) + return -EPROTO; + + *features = info->features; + + tm = &info->range_min; + rtc->range_min = mktime64(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + tm = &info->range_max; + rtc->range_max = mktime64(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + return 0; +} + +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) +{ + if (ver->impl_id == TEE_IMPL_ID_OPTEE) + return 1; + else + return 0; +} + +static int optee_rtc_probe(struct device *dev) +{ + struct tee_client_device *rtc_device = to_tee_client_device(dev); + struct tee_ioctl_open_session_arg sess_arg; + struct optee_rtc *priv; + struct rtc_device *rtc; + struct tee_shm *shm; + int ret, err; + + memset(&sess_arg, 0, sizeof(sess_arg)); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + /* Open context with TEE driver */ + priv->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); + if (IS_ERR(priv->ctx)) + return -ENODEV; + + /* Open session with rtc Trusted App */ + export_uuid(sess_arg.uuid, &rtc_device->id.uuid); + sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL; + + ret = tee_client_open_session(priv->ctx, &sess_arg, NULL); + if (ret < 0 || sess_arg.ret != 0) { + dev_err(dev, "tee_client_open_session failed, err: %x\n", sess_arg.ret); + err = -EINVAL; + goto out_ctx; + } + priv->session_id = sess_arg.session; + + shm = tee_shm_alloc_kernel_buf(priv->ctx, sizeof(struct optee_rtc_info)); + if (IS_ERR(shm)) { + dev_err(priv->dev, "tee_shm_alloc_kernel_buf failed\n"); + err = PTR_ERR(shm); + goto out_sess; + } + + priv->shm = shm; + priv->dev = dev; + dev_set_drvdata(dev, priv); + + rtc->ops = &optee_rtc_ops; + + err = optee_rtc_read_info(dev, rtc, &priv->features); + if (err) { + dev_err(dev, "Failed to get RTC features from OP-TEE\n"); + goto out_shm; + } + + err = devm_rtc_register_device(rtc); + if (err) + goto out_shm; + + /* + * We must clear this bit after registering because rtc_register_device + * will set it if it sees that .set_offset is provided. + */ + if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) + clear_bit(RTC_FEATURE_CORRECTION, rtc->features); + + return 0; + +out_shm: + tee_shm_free(priv->shm); +out_sess: + tee_client_close_session(priv->ctx, priv->session_id); +out_ctx: + tee_client_close_context(priv->ctx); + + return err; +} + +static int optee_rtc_remove(struct device *dev) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + + tee_client_close_session(priv->ctx, priv->session_id); + tee_client_close_context(priv->ctx); + + return 0; +} + +static const struct tee_client_device_id optee_rtc_id_table[] = { + {UUID_INIT(0xf389f8c8, 0x845f, 0x496c, + 0x8b, 0xbe, 0xd6, 0x4b, 0xd2, 0x4c, 0x92, 0xfd)}, + {} +}; + +MODULE_DEVICE_TABLE(tee, optee_rtc_id_table); + +static struct tee_client_driver optee_rtc_driver = { + .id_table = optee_rtc_id_table, + .driver = { + .name = "optee_rtc", + .bus = &tee_bus_type, + .probe = optee_rtc_probe, + .remove = optee_rtc_remove, + }, +}; + +static int __init optee_rtc_mod_init(void) +{ + return driver_register(&optee_rtc_driver.driver); +} + +static void __exit optee_rtc_mod_exit(void) +{ + driver_unregister(&optee_rtc_driver.driver); +} + +module_init(optee_rtc_mod_init); +module_exit(optee_rtc_mod_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>"); +MODULE_DESCRIPTION("OP-TEE based RTC driver"); diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 7473e6c8a183..e13b5e695d06 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -427,7 +427,8 @@ static int pcf2123_probe(struct spi_device *spi) * support to this driver to generate interrupts more than once * per minute. */ - rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); rtc->ops = &pcf2123_rtc_ops; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_max = RTC_TIMESTAMP_END_2099; diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 81a5b1f2e68c..63b275b014bd 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -374,7 +374,8 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned int buf[5], ctrl2; + u8 buf[5]; + unsigned int ctrl2; int ret; ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); @@ -655,13 +656,25 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */ - pcf2127->rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features); clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); if (alarm_irq > 0) { + unsigned long flags; + + /* + * If flags = 0, devm_request_threaded_irq() will use IRQ flags + * obtained from device tree. + */ + if (dev_fwnode(dev)) + flags = 0; + else + flags = IRQF_TRIGGER_LOW; + ret = devm_request_threaded_irq(dev, alarm_irq, NULL, pcf2127_rtc_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + flags | IRQF_ONESHOT, dev_name(dev), dev); if (ret) { dev_err(dev, "failed to request alarm irq\n"); diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index df2b072c394d..095891999da1 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -616,7 +616,8 @@ static int pcf85063_probe(struct i2c_client *client) pcf85063->rtc->ops = &pcf85063_rtc_ops; pcf85063->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf85063->rtc->range_max = RTC_TIMESTAMP_END_2099; - pcf85063->rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_2S, pcf85063->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features); clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features); if (config->has_alarms && client->irq > 0) { @@ -649,6 +650,7 @@ static int pcf85063_probe(struct i2c_client *client) } static const struct i2c_device_id pcf85063_ids[] = { + { "pca85073a", PCF85063A }, { "pcf85063", PCF85063 }, { "pcf85063tp", PCF85063TP }, { "pcf85063a", PCF85063A }, @@ -659,6 +661,7 @@ MODULE_DEVICE_TABLE(i2c, pcf85063_ids); #ifdef CONFIG_OF static const struct of_device_id pcf85063_of_match[] = { + { .compatible = "nxp,pca85073a", .data = &pcf85063_cfg[PCF85063A] }, { .compatible = "nxp,pcf85063", .data = &pcf85063_cfg[PCF85063] }, { .compatible = "nxp,pcf85063tp", .data = &pcf85063_cfg[PCF85063TP] }, { .compatible = "nxp,pcf85063a", .data = &pcf85063_cfg[PCF85063A] }, diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index c93acade7205..b1b1943de844 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -212,14 +212,6 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) if (err < 0) return err; - /* The alarm has no seconds, round up to nearest minute */ - if (tm->time.tm_sec) { - time64_t alarm_time = rtc_tm_to_time64(&tm->time); - - alarm_time += 60 - tm->time.tm_sec; - rtc_time64_to_tm(alarm_time, &tm->time); - } - regs[0] = bin2bcd(tm->time.tm_min); regs[1] = bin2bcd(tm->time.tm_hour); regs[2] = bin2bcd(tm->time.tm_mday); @@ -240,9 +232,9 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param) { struct pcf8523 *pcf8523 = dev_get_drvdata(dev); int ret; + u32 value; switch(param->param) { - u32 value; case RTC_PARAM_BACKUP_SWITCH_MODE: ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); @@ -279,9 +271,9 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param) static int pcf8523_param_set(struct device *dev, struct rtc_param *param) { struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + u8 mode; switch(param->param) { - u8 mode; case RTC_PARAM_BACKUP_SWITCH_MODE: switch (param->uvalue) { case RTC_BSM_DISABLED: @@ -450,7 +442,8 @@ static int pcf8523_probe(struct i2c_client *client, rtc->ops = &pcf8523_rtc_ops; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_max = RTC_TIMESTAMP_END_2099; - rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); if (client->irq > 0) { err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index c8bddfb94129..9d06813e2e6d 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -330,19 +330,6 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) unsigned char buf[4]; int err; - /* The alarm has no seconds, round up to nearest minute */ - if (tm->time.tm_sec) { - time64_t alarm_time = rtc_tm_to_time64(&tm->time); - - alarm_time += 60 - tm->time.tm_sec; - rtc_time64_to_tm(alarm_time, &tm->time); - } - - dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d " - "enabled=%d pending=%d\n", __func__, - tm->time.tm_min, tm->time.tm_hour, tm->time.tm_wday, - tm->time.tm_mday, tm->enabled, tm->pending); - buf[0] = bin2bcd(tm->time.tm_min); buf[1] = bin2bcd(tm->time.tm_hour); buf[2] = bin2bcd(tm->time.tm_mday); @@ -565,7 +552,8 @@ static int pcf8563_probe(struct i2c_client *client, pcf8563->rtc->ops = &pcf8563_rtc_ops; /* the pcf8563 alarm only supports a minute accuracy */ - pcf8563->rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, pcf8563->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf8563->rtc->features); pcf8563->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf8563->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf8563->rtc->set_start_time = true; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index e38ee8848385..bad6a5d9c683 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -350,9 +350,6 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) } } - if (!adev->irq[0]) - clear_bit(RTC_FEATURE_ALARM, ldata->rtc->features); - device_init_wakeup(&adev->dev, true); ldata->rtc = devm_rtc_allocate_device(&adev->dev); if (IS_ERR(ldata->rtc)) { @@ -360,6 +357,9 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) goto out; } + if (!adev->irq[0]) + clear_bit(RTC_FEATURE_ALARM, ldata->rtc->features); + ldata->rtc->ops = ops; ldata->rtc->range_min = vendor->range_min; ldata->rtc->range_max = vendor->range_max; diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 29a1c65661e9..dc6d1476baa5 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -7,6 +7,7 @@ #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/pm.h> +#include <linux/pm_wakeirq.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -83,7 +84,7 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; if (!rtc_dd->allow_set_time) - return -EACCES; + return -ENODEV; secs = rtc_tm_to_time64(tm); @@ -527,40 +528,28 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) return rc; } - return devm_rtc_register_device(rtc_dd->rtc); -} - -#ifdef CONFIG_PM_SLEEP -static int pm8xxx_rtc_resume(struct device *dev) -{ - struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); + rc = devm_rtc_register_device(rtc_dd->rtc); + if (rc) + return rc; - if (device_may_wakeup(dev)) - disable_irq_wake(rtc_dd->rtc_alarm_irq); + rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->rtc_alarm_irq); + if (rc) + return rc; return 0; } -static int pm8xxx_rtc_suspend(struct device *dev) +static int pm8xxx_remove(struct platform_device *pdev) { - struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(rtc_dd->rtc_alarm_irq); - + dev_pm_clear_wake_irq(&pdev->dev); return 0; } -#endif - -static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, - pm8xxx_rtc_suspend, - pm8xxx_rtc_resume); static struct platform_driver pm8xxx_rtc_driver = { .probe = pm8xxx_rtc_probe, + .remove = pm8xxx_remove, .driver = { .name = "rtc-pm8xxx", - .pm = &pm8xxx_rtc_pm_ops, .of_match_table = pm8xxx_id_table, }, }; diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index cf8119b6d320..eeacf480cf36 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -16,8 +16,6 @@ #include <linux/of.h> #include <linux/of_device.h> -#include <mach/hardware.h> - #include "rtc-sa1100.h" #define RTC_DEF_DIVIDER (32768 - 1) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 5bfdd34a72ff..b32117ccd74b 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -436,7 +436,6 @@ static int rx8025_set_offset(struct device *dev, long offset) { struct i2c_client *client = to_i2c_client(dev); u8 digoff; - int err; offset /= RX8025_ADJ_RESOLUTION; if (offset > RX8025_ADJ_DATA_MAX) @@ -449,11 +448,7 @@ static int rx8025_set_offset(struct device *dev, long offset) offset += 128; digoff = offset; - err = rx8025_write_reg(client, RX8025_REG_DIGOFF, digoff); - if (err) - return err; - - return 0; + return rx8025_write_reg(client, RX8025_REG_DIGOFF, digoff); } static const struct rtc_class_ops rx8025_rtc_ops = { diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c new file mode 100644 index 000000000000..ac788799c8e3 --- /dev/null +++ b/drivers/rtc/rtc-rzn1.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Renesas RZ/N1 Real Time Clock interface for Linux + * + * Copyright: + * - 2014 Renesas Electronics Europe Limited + * - 2022 Schneider Electric + * + * Authors: + * - Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com> + * - Miquel Raynal <miquel.raynal@bootlin.com> + */ + +#include <linux/bcd.h> +#include <linux/init.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/rtc.h> + +#define RZN1_RTC_CTL0 0x00 +#define RZN1_RTC_CTL0_SLSB_SUBU 0 +#define RZN1_RTC_CTL0_SLSB_SCMP BIT(4) +#define RZN1_RTC_CTL0_AMPM BIT(5) +#define RZN1_RTC_CTL0_CE BIT(7) + +#define RZN1_RTC_CTL1 0x04 +#define RZN1_RTC_CTL1_ALME BIT(4) + +#define RZN1_RTC_CTL2 0x08 +#define RZN1_RTC_CTL2_WAIT BIT(0) +#define RZN1_RTC_CTL2_WST BIT(1) +#define RZN1_RTC_CTL2_WUST BIT(5) +#define RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST) + +#define RZN1_RTC_SEC 0x14 +#define RZN1_RTC_MIN 0x18 +#define RZN1_RTC_HOUR 0x1c +#define RZN1_RTC_WEEK 0x20 +#define RZN1_RTC_DAY 0x24 +#define RZN1_RTC_MONTH 0x28 +#define RZN1_RTC_YEAR 0x2c + +#define RZN1_RTC_SUBU 0x38 +#define RZN1_RTC_SUBU_DEV BIT(7) +#define RZN1_RTC_SUBU_DECR BIT(6) + +#define RZN1_RTC_ALM 0x40 +#define RZN1_RTC_ALH 0x44 +#define RZN1_RTC_ALW 0x48 + +#define RZN1_RTC_SECC 0x4c +#define RZN1_RTC_MINC 0x50 +#define RZN1_RTC_HOURC 0x54 +#define RZN1_RTC_WEEKC 0x58 +#define RZN1_RTC_DAYC 0x5c +#define RZN1_RTC_MONTHC 0x60 +#define RZN1_RTC_YEARC 0x64 + +struct rzn1_rtc { + struct rtc_device *rtcdev; + void __iomem *base; +}; + +static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm) +{ + tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC); + tm->tm_min = readl(rtc->base + RZN1_RTC_MINC); + tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC); + tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC); + tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC); + tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC); + tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC); +} + +static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm) +{ + time64_t time; + unsigned int days; + u32 secs; + + time = rtc_tm_to_time64(tm); + days = div_s64_rem(time, 86400, &secs); + + /* day of the week, 1970-01-01 was a Thursday */ + return (days + 4) % 7; +} + +static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rzn1_rtc *rtc = dev_get_drvdata(dev); + u32 val, secs; + + /* + * The RTC was not started or is stopped and thus does not carry the + * proper time/date. + */ + val = readl(rtc->base + RZN1_RTC_CTL2); + if (val & RZN1_RTC_CTL2_STOPPED) + return -EINVAL; + + rzn1_rtc_get_time_snapshot(rtc, tm); + secs = readl(rtc->base + RZN1_RTC_SECC); + if (tm->tm_sec != secs) + rzn1_rtc_get_time_snapshot(rtc, tm); + + tm->tm_sec = bcd2bin(tm->tm_sec); + tm->tm_min = bcd2bin(tm->tm_min); + tm->tm_hour = bcd2bin(tm->tm_hour); + tm->tm_wday = bcd2bin(tm->tm_wday); + tm->tm_mday = bcd2bin(tm->tm_mday); + tm->tm_mon = bcd2bin(tm->tm_mon); + tm->tm_year = bcd2bin(tm->tm_year); + + return 0; +} + +static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rzn1_rtc *rtc = dev_get_drvdata(dev); + u32 val; + int ret; + + tm->tm_sec = bin2bcd(tm->tm_sec); + tm->tm_min = bin2bcd(tm->tm_min); + tm->tm_hour = bin2bcd(tm->tm_hour); + tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm)); + tm->tm_mday = bin2bcd(tm->tm_mday); + tm->tm_mon = bin2bcd(tm->tm_mon); + tm->tm_year = bin2bcd(tm->tm_year); + + val = readl(rtc->base + RZN1_RTC_CTL2); + if (!(val & RZN1_RTC_CTL2_STOPPED)) { + /* Hold the counter if it was counting up */ + writel(RZN1_RTC_CTL2_WAIT, rtc->base + RZN1_RTC_CTL2); + + /* Wait for the counter to stop: two 32k clock cycles */ + usleep_range(61, 100); + ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, val, + val & RZN1_RTC_CTL2_WST, 0, 100); + if (ret) + return ret; + } + + writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC); + writel(tm->tm_min, rtc->base + RZN1_RTC_MIN); + writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR); + writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK); + writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY); + writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH); + writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR); + writel(0, rtc->base + RZN1_RTC_CTL2); + + return 0; +} + +static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id) +{ + struct rzn1_rtc *rtc = dev_id; + + rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF); + + return IRQ_HANDLED; +} + +static int rzn1_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct rzn1_rtc *rtc = dev_get_drvdata(dev); + u32 ctl1 = readl(rtc->base + RZN1_RTC_CTL1); + + if (enable) + ctl1 |= RZN1_RTC_CTL1_ALME; + else + ctl1 &= ~RZN1_RTC_CTL1_ALME; + + writel(ctl1, rtc->base + RZN1_RTC_CTL1); + + return 0; +} + +static int rzn1_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rzn1_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + unsigned int min, hour, wday, delta_days; + time64_t alarm; + u32 ctl1; + int ret; + + ret = rzn1_rtc_read_time(dev, tm); + if (ret) + return ret; + + min = readl(rtc->base + RZN1_RTC_ALM); + hour = readl(rtc->base + RZN1_RTC_ALH); + wday = readl(rtc->base + RZN1_RTC_ALW); + + tm->tm_sec = 0; + tm->tm_min = bcd2bin(min); + tm->tm_hour = bcd2bin(hour); + delta_days = ((fls(wday) - 1) - tm->tm_wday + 7) % 7; + tm->tm_wday = fls(wday) - 1; + + if (delta_days) { + alarm = rtc_tm_to_time64(tm) + (delta_days * 86400); + rtc_time64_to_tm(alarm, tm); + } + + ctl1 = readl(rtc->base + RZN1_RTC_CTL1); + alrm->enabled = !!(ctl1 & RZN1_RTC_CTL1_ALME); + + return 0; +} + +static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rzn1_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time, tm_now; + unsigned long alarm, farest; + unsigned int days_ahead, wday; + int ret; + + ret = rzn1_rtc_read_time(dev, &tm_now); + if (ret) + return ret; + + /* We cannot set alarms more than one week ahead */ + farest = rtc_tm_to_time64(&tm_now) + (7 * 86400); + alarm = rtc_tm_to_time64(tm); + if (time_after(alarm, farest)) + return -ERANGE; + + /* Convert alarm day into week day */ + days_ahead = tm->tm_mday - tm_now.tm_mday; + wday = (tm_now.tm_wday + days_ahead) % 7; + + writel(bin2bcd(tm->tm_min), rtc->base + RZN1_RTC_ALM); + writel(bin2bcd(tm->tm_hour), rtc->base + RZN1_RTC_ALH); + writel(BIT(wday), rtc->base + RZN1_RTC_ALW); + + rzn1_rtc_alarm_irq_enable(dev, alrm->enabled); + + return 0; +} + +static int rzn1_rtc_read_offset(struct device *dev, long *offset) +{ + struct rzn1_rtc *rtc = dev_get_drvdata(dev); + unsigned int ppb_per_step; + bool subtract; + u32 val; + + val = readl(rtc->base + RZN1_RTC_SUBU); + ppb_per_step = val & RZN1_RTC_SUBU_DEV ? 1017 : 3051; + subtract = val & RZN1_RTC_SUBU_DECR; + val &= 0x3F; + + if (!val) + *offset = 0; + else if (subtract) + *offset = -(((~val) & 0x3F) + 1) * ppb_per_step; + else + *offset = (val - 1) * ppb_per_step; + + return 0; +} + +static int rzn1_rtc_set_offset(struct device *dev, long offset) +{ + struct rzn1_rtc *rtc = dev_get_drvdata(dev); + int stepsh, stepsl, steps; + u32 subu = 0, ctl2; + int ret; + + /* + * Check which resolution mode (every 20 or 60s) can be used. + * Between 2 and 124 clock pulses can be added or substracted. + * + * In 20s mode, the minimum resolution is 2 / (32768 * 20) which is + * close to 3051 ppb. In 60s mode, the resolution is closer to 1017. + */ + stepsh = DIV_ROUND_CLOSEST(offset, 1017); + stepsl = DIV_ROUND_CLOSEST(offset, 3051); + + if (stepsh >= -0x3E && stepsh <= 0x3E) { + /* 1017 ppb per step */ + steps = stepsh; + subu |= RZN1_RTC_SUBU_DEV; + } else if (stepsl >= -0x3E && stepsl <= 0x3E) { + /* 3051 ppb per step */ + steps = stepsl; + } else { + return -ERANGE; + } + + if (!steps) + return 0; + + if (steps > 0) { + subu |= steps + 1; + } else { + subu |= RZN1_RTC_SUBU_DECR; + subu |= (~(-steps - 1)) & 0x3F; + } + + ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, ctl2, + !(ctl2 & RZN1_RTC_CTL2_WUST), 100, 2000000); + if (ret) + return ret; + + writel(subu, rtc->base + RZN1_RTC_SUBU); + + return 0; +} + +static const struct rtc_class_ops rzn1_rtc_ops = { + .read_time = rzn1_rtc_read_time, + .set_time = rzn1_rtc_set_time, + .read_alarm = rzn1_rtc_read_alarm, + .set_alarm = rzn1_rtc_set_alarm, + .alarm_irq_enable = rzn1_rtc_alarm_irq_enable, + .read_offset = rzn1_rtc_read_offset, + .set_offset = rzn1_rtc_set_offset, +}; + +static int rzn1_rtc_probe(struct platform_device *pdev) +{ + struct rzn1_rtc *rtc; + int alarm_irq; + int ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + platform_set_drvdata(pdev, rtc); + + rtc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rtc->base)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->base), "Missing reg\n"); + + alarm_irq = platform_get_irq(pdev, 0); + if (alarm_irq < 0) + return alarm_irq; + + rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtcdev)) + return PTR_ERR(rtc->rtcdev); + + rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099; + rtc->rtcdev->ops = &rzn1_rtc_ops; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features); + + devm_pm_runtime_enable(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; + + /* + * Ensure the clock counter is enabled. + * Set 24-hour mode and possible oscillator offset compensation in SUBU mode. + */ + writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU, + rtc->base + RZN1_RTC_CTL0); + + /* Disable all interrupts */ + writel(0, rtc->base + RZN1_RTC_CTL1); + + ret = devm_request_irq(&pdev->dev, alarm_irq, rzn1_rtc_alarm_irq, 0, + dev_name(&pdev->dev), rtc); + if (ret) { + dev_err(&pdev->dev, "RTC timer interrupt not available\n"); + goto dis_runtime_pm; + } + + ret = devm_rtc_register_device(rtc->rtcdev); + if (ret) + goto dis_runtime_pm; + + return 0; + +dis_runtime_pm: + pm_runtime_put(&pdev->dev); + + return ret; +} + +static int rzn1_rtc_remove(struct platform_device *pdev) +{ + pm_runtime_put(&pdev->dev); + + return 0; +} + +static const struct of_device_id rzn1_rtc_of_match[] = { + { .compatible = "renesas,rzn1-rtc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match); + +static struct platform_driver rzn1_rtc_driver = { + .probe = rzn1_rtc_probe, + .remove = rzn1_rtc_remove, + .driver = { + .name = "rzn1-rtc", + .of_match_table = rzn1_rtc_of_match, + }, +}; +module_platform_driver(rzn1_rtc_driver); + +MODULE_AUTHOR("Michel Pollet <Michel.Pollet@bp.renesas.com"); +MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com"); +MODULE_DESCRIPTION("RZ/N1 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index b4a520056b1a..d4777b01ab22 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -204,8 +204,10 @@ static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm) /* we don't report wday/yday/isdst ... */ rtc_wait_not_busy(config); - time = readl(config->ioaddr + TIME_REG); - date = readl(config->ioaddr + DATE_REG); + do { + time = readl(config->ioaddr + TIME_REG); + date = readl(config->ioaddr + DATE_REG); + } while (time == readl(config->ioaddr + TIME_REG)); tm->tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK; tm->tm_min = (time >> MINUTE_SHIFT) & MIN_MASK; tm->tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK; @@ -352,6 +354,10 @@ static int spear_rtc_probe(struct platform_device *pdev) if (!config) return -ENOMEM; + config->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(config->rtc)) + return PTR_ERR(config->rtc); + /* alarm irqs */ irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -380,16 +386,13 @@ static int spear_rtc_probe(struct platform_device *pdev) spin_lock_init(&config->lock); platform_set_drvdata(pdev, config); - config->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &spear_rtc_ops, THIS_MODULE); - if (IS_ERR(config->rtc)) { - dev_err(&pdev->dev, "can't register RTC device, err %ld\n", - PTR_ERR(config->rtc)); - status = PTR_ERR(config->rtc); - goto err_disable_clock; - } + config->rtc->ops = &spear_rtc_ops; + config->rtc->range_min = RTC_TIMESTAMP_BEGIN_0000; + config->rtc->range_min = RTC_TIMESTAMP_END_9999; - config->rtc->uie_unsupported = 1; + status = devm_rtc_register_device(config->rtc); + if (status) + goto err_disable_clock; if (!device_can_wakeup(&pdev->dev)) device_init_wakeup(&pdev->dev, 1); diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 711832c758ae..57540727ce1c 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/clk/sunxi-ng.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/fs.h> @@ -48,7 +49,8 @@ /* Alarm 0 (counter) */ #define SUN6I_ALRM_COUNTER 0x0020 -#define SUN6I_ALRM_CUR_VAL 0x0024 +/* This holds the remaining alarm seconds on older SoCs (current value) */ +#define SUN6I_ALRM_COUNTER_HMS 0x0024 #define SUN6I_ALRM_EN 0x0028 #define SUN6I_ALRM_EN_CNT_EN BIT(0) #define SUN6I_ALRM_IRQ_EN 0x002c @@ -69,6 +71,10 @@ #define SUN6I_LOSC_OUT_GATING 0x0060 #define SUN6I_LOSC_OUT_GATING_EN_OFFSET 0 +/* General-purpose data */ +#define SUN6I_GP_DATA 0x0100 +#define SUN6I_GP_DATA_SIZE 0x20 + /* * Get date values */ @@ -110,6 +116,8 @@ #define SUN6I_YEAR_MIN 1970 #define SUN6I_YEAR_OFF (SUN6I_YEAR_MIN - 1900) +#define SECS_PER_DAY (24 * 3600ULL) + /* * There are other differences between models, including: * @@ -133,12 +141,15 @@ struct sun6i_rtc_clk_data { unsigned int has_auto_swt : 1; }; +#define RTC_LINEAR_DAY BIT(0) + struct sun6i_rtc_dev { struct rtc_device *rtc; const struct sun6i_rtc_clk_data *data; void __iomem *base; int irq; - unsigned long alarm; + time64_t alarm; + unsigned long flags; struct clk_hw hw; struct clk_hw *int_osc; @@ -467,22 +478,30 @@ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) } while ((date != readl(chip->base + SUN6I_RTC_YMD)) || (time != readl(chip->base + SUN6I_RTC_HMS))); + if (chip->flags & RTC_LINEAR_DAY) { + /* + * Newer chips store a linear day number, the manual + * does not mandate any epoch base. The BSP driver uses + * the UNIX epoch, let's just copy that, as it's the + * easiest anyway. + */ + rtc_time64_to_tm((date & 0xffff) * SECS_PER_DAY, rtc_tm); + } else { + rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date); + rtc_tm->tm_mon = SUN6I_DATE_GET_MON_VALUE(date) - 1; + rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date); + + /* + * switch from (data_year->min)-relative offset to + * a (1900)-relative one + */ + rtc_tm->tm_year += SUN6I_YEAR_OFF; + } + rtc_tm->tm_sec = SUN6I_TIME_GET_SEC_VALUE(time); rtc_tm->tm_min = SUN6I_TIME_GET_MIN_VALUE(time); rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time); - rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date); - rtc_tm->tm_mon = SUN6I_DATE_GET_MON_VALUE(date); - rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date); - - rtc_tm->tm_mon -= 1; - - /* - * switch from (data_year->min)-relative offset to - * a (1900)-relative one - */ - rtc_tm->tm_year += SUN6I_YEAR_OFF; - return 0; } @@ -510,36 +529,54 @@ static int sun6i_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); struct rtc_time *alrm_tm = &wkalrm->time; struct rtc_time tm_now; - unsigned long time_now = 0; - unsigned long time_set = 0; - unsigned long time_gap = 0; - int ret = 0; - - ret = sun6i_rtc_gettime(dev, &tm_now); - if (ret < 0) { - dev_err(dev, "Error in getting time\n"); - return -EINVAL; - } + time64_t time_set; + u32 counter_val, counter_val_hms; + int ret; time_set = rtc_tm_to_time64(alrm_tm); - time_now = rtc_tm_to_time64(&tm_now); - if (time_set <= time_now) { - dev_err(dev, "Date to set in the past\n"); - return -EINVAL; - } - - time_gap = time_set - time_now; - if (time_gap > U32_MAX) { - dev_err(dev, "Date too far in the future\n"); - return -EINVAL; + if (chip->flags & RTC_LINEAR_DAY) { + /* + * The alarm registers hold the actual alarm time, encoded + * in the same way (linear day + HMS) as the current time. + */ + counter_val_hms = SUN6I_TIME_SET_SEC_VALUE(alrm_tm->tm_sec) | + SUN6I_TIME_SET_MIN_VALUE(alrm_tm->tm_min) | + SUN6I_TIME_SET_HOUR_VALUE(alrm_tm->tm_hour); + /* The division will cut off the H:M:S part of alrm_tm. */ + counter_val = div_u64(rtc_tm_to_time64(alrm_tm), SECS_PER_DAY); + } else { + /* The alarm register holds the number of seconds left. */ + time64_t time_now; + + ret = sun6i_rtc_gettime(dev, &tm_now); + if (ret < 0) { + dev_err(dev, "Error in getting time\n"); + return -EINVAL; + } + + time_now = rtc_tm_to_time64(&tm_now); + if (time_set <= time_now) { + dev_err(dev, "Date to set in the past\n"); + return -EINVAL; + } + if ((time_set - time_now) > U32_MAX) { + dev_err(dev, "Date too far in the future\n"); + return -EINVAL; + } + + counter_val = time_set - time_now; } sun6i_rtc_setaie(0, chip); writel(0, chip->base + SUN6I_ALRM_COUNTER); + if (chip->flags & RTC_LINEAR_DAY) + writel(0, chip->base + SUN6I_ALRM_COUNTER_HMS); usleep_range(100, 300); - writel(time_gap, chip->base + SUN6I_ALRM_COUNTER); + writel(counter_val, chip->base + SUN6I_ALRM_COUNTER); + if (chip->flags & RTC_LINEAR_DAY) + writel(counter_val_hms, chip->base + SUN6I_ALRM_COUNTER_HMS); chip->alarm = time_set; sun6i_rtc_setaie(wkalrm->enabled, chip); @@ -571,20 +608,25 @@ static int sun6i_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) u32 date = 0; u32 time = 0; - rtc_tm->tm_year -= SUN6I_YEAR_OFF; - rtc_tm->tm_mon += 1; - - date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | - SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | - SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year); - - if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN)) - date |= SUN6I_LEAP_SET_VALUE(1); - time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | SUN6I_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); + if (chip->flags & RTC_LINEAR_DAY) { + /* The division will cut off the H:M:S part of rtc_tm. */ + date = div_u64(rtc_tm_to_time64(rtc_tm), SECS_PER_DAY); + } else { + rtc_tm->tm_year -= SUN6I_YEAR_OFF; + rtc_tm->tm_mon += 1; + + date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | + SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | + SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year); + + if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN)) + date |= SUN6I_LEAP_SET_VALUE(1); + } + /* Check whether registers are writable */ if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL, SUN6I_LOSC_CTRL_ACC_MASK, 50)) { @@ -641,6 +683,39 @@ static const struct rtc_class_ops sun6i_rtc_ops = { .alarm_irq_enable = sun6i_rtc_alarm_irq_enable }; +static int sun6i_rtc_nvmem_read(void *priv, unsigned int offset, void *_val, size_t bytes) +{ + struct sun6i_rtc_dev *chip = priv; + u32 *val = _val; + int i; + + for (i = 0; i < bytes / 4; ++i) + val[i] = readl(chip->base + SUN6I_GP_DATA + offset + 4 * i); + + return 0; +} + +static int sun6i_rtc_nvmem_write(void *priv, unsigned int offset, void *_val, size_t bytes) +{ + struct sun6i_rtc_dev *chip = priv; + u32 *val = _val; + int i; + + for (i = 0; i < bytes / 4; ++i) + writel(val[i], chip->base + SUN6I_GP_DATA + offset + 4 * i); + + return 0; +} + +static struct nvmem_config sun6i_rtc_nvmem_cfg = { + .type = NVMEM_TYPE_BATTERY_BACKED, + .reg_read = sun6i_rtc_nvmem_read, + .reg_write = sun6i_rtc_nvmem_write, + .size = SUN6I_GP_DATA_SIZE, + .word_size = 4, + .stride = 4, +}; + #ifdef CONFIG_PM_SLEEP /* Enable IRQ wake on suspend, to wake up from RTC. */ static int sun6i_rtc_suspend(struct device *dev) @@ -668,11 +743,35 @@ static int sun6i_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(sun6i_rtc_pm_ops, sun6i_rtc_suspend, sun6i_rtc_resume); +static void sun6i_rtc_bus_clk_cleanup(void *data) +{ + struct clk *bus_clk = data; + + clk_disable_unprepare(bus_clk); +} + static int sun6i_rtc_probe(struct platform_device *pdev) { struct sun6i_rtc_dev *chip = sun6i_rtc; + struct device *dev = &pdev->dev; + struct clk *bus_clk; int ret; + bus_clk = devm_clk_get_optional(dev, "bus"); + if (IS_ERR(bus_clk)) + return PTR_ERR(bus_clk); + + if (bus_clk) { + ret = clk_prepare_enable(bus_clk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, sun6i_rtc_bus_clk_cleanup, + bus_clk); + if (ret) + return ret; + } + if (!chip) { chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -683,10 +782,18 @@ static int sun6i_rtc_probe(struct platform_device *pdev) chip->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->base)) return PTR_ERR(chip->base); + + if (IS_REACHABLE(CONFIG_SUN6I_RTC_CCU)) { + ret = sun6i_rtc_ccu_probe(dev, chip->base); + if (ret) + return ret; + } } platform_set_drvdata(pdev, chip); + chip->flags = (unsigned long)of_device_get_match_data(&pdev->dev); + chip->irq = platform_get_irq(pdev, 0); if (chip->irq < 0) return chip->irq; @@ -733,12 +840,20 @@ static int sun6i_rtc_probe(struct platform_device *pdev) return PTR_ERR(chip->rtc); chip->rtc->ops = &sun6i_rtc_ops; - chip->rtc->range_max = 2019686399LL; /* 2033-12-31 23:59:59 */ + if (chip->flags & RTC_LINEAR_DAY) + chip->rtc->range_max = (65536 * SECS_PER_DAY) - 1; + else + chip->rtc->range_max = 2019686399LL; /* 2033-12-31 23:59:59 */ ret = devm_rtc_register_device(chip->rtc); if (ret) return ret; + sun6i_rtc_nvmem_cfg.priv = chip; + ret = devm_rtc_nvmem_register(chip->rtc, &sun6i_rtc_nvmem_cfg); + if (ret) + return ret; + dev_info(&pdev->dev, "RTC enabled\n"); return 0; @@ -758,6 +873,8 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = { { .compatible = "allwinner,sun8i-v3-rtc" }, { .compatible = "allwinner,sun50i-h5-rtc" }, { .compatible = "allwinner,sun50i-h6-rtc" }, + { .compatible = "allwinner,sun50i-h616-rtc", + .data = (void *)RTC_LINEAR_DAY }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids); diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 2018614f258f..6eaa9321c074 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -432,14 +432,21 @@ static int wm8350_rtc_probe(struct platform_device *pdev) return ret; } - wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, + ret = wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350_rtc_update_handler, 0, "RTC Seconds", wm8350); + if (ret) + return ret; + wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); - wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM, + ret = wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350_rtc_alarm_handler, 0, "RTC Alarm", wm8350); + if (ret) { + wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350); + return ret; + } return 0; } diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c index cf68a9b1c9eb..d3d0054e21fd 100644 --- a/drivers/rtc/rtc-xgene.c +++ b/drivers/rtc/rtc-xgene.c @@ -180,8 +180,6 @@ static int xgene_rtc_probe(struct platform_device *pdev) return ret; } - /* HW does not support update faster than 1 seconds */ - pdata->rtc->uie_unsupported = 1; pdata->rtc->ops = &xgene_rtc_ops; pdata->rtc->range_max = U32_MAX; |