diff options
26 files changed, 620 insertions, 108 deletions
diff --git a/Documentation/devicetree/bindings/rtc/cirrus,ep9301-rtc.yaml b/Documentation/devicetree/bindings/rtc/cirrus,ep9301-rtc.yaml new file mode 100644 index 000000000000..a95f6af2b1c0 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/cirrus,ep9301-rtc.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/cirrus,ep9301-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus EP93xx Real Time Clock controller + +maintainers: + - Hartley Sweeten <hsweeten@visionengravers.com> + - Alexander Sverdlin <alexander.sverdlin@gmail.com> + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + oneOf: + - const: cirrus,ep9301-rtc + - items: + - enum: + - cirrus,ep9302-rtc + - cirrus,ep9307-rtc + - cirrus,ep9312-rtc + - cirrus,ep9315-rtc + - const: cirrus,ep9301-rtc + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + rtc@80920000 { + compatible = "cirrus,ep9301-rtc"; + reg = <0x80920000 0x100>; + }; diff --git a/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt b/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt deleted file mode 100644 index 5f9df3f1467c..000000000000 --- a/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt +++ /dev/null @@ -1,16 +0,0 @@ -EPSON TOYOCOM RTC-7301SF/DG - -Required properties: - -- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg" -- reg: Specifies base physical address and size of the registers. -- interrupts: A single interrupt specifier. - -Example: - -rtc: rtc@44a00000 { - compatible = "epson,rtc7301dg"; - reg = <0x44a00000 0x10000>; - interrupt-parent = <&axi_intc_0>; - interrupts = <3 2>; -}; diff --git a/Documentation/devicetree/bindings/rtc/epson,rtc7301.yaml b/Documentation/devicetree/bindings/rtc/epson,rtc7301.yaml new file mode 100644 index 000000000000..bdb5cadb31cc --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/epson,rtc7301.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/epson,rtc7301.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Epson Toyocom RTC-7301SF/DG + +description: + The only difference between the two variants is the packaging. + The DG variant is a DIL package, and the SF variant is a flat + package. + +maintainers: + - Akinobu Mita <akinobu.mita@gmail.com> + +properties: + compatible: + enum: + - epson,rtc7301dg + - epson,rtc7301sf + + reg: + maxItems: 1 + + reg-io-width: + description: + The size (in bytes) of the IO accesses that should be performed + on the device. + enum: [1, 4] + default: 4 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + rtc: rtc@44a00000 { + compatible = "epson,rtc7301dg"; + reg = <0x44a00000 0x10000>; + reg-io-width = <4>; + interrupt-parent = <&axi_intc_0>; + interrupts = <3 2>; + }; diff --git a/Documentation/devicetree/bindings/rtc/maxim,mcp795.txt b/Documentation/devicetree/bindings/rtc/maxim,mcp795.txt deleted file mode 100644 index a59fdd8c236d..000000000000 --- a/Documentation/devicetree/bindings/rtc/maxim,mcp795.txt +++ /dev/null @@ -1,11 +0,0 @@ -* Maxim MCP795 SPI Serial Real-Time Clock - -Required properties: -- compatible: Should contain "maxim,mcp795". -- reg: SPI address for chip - -Example: - mcp795: rtc@0 { - compatible = "maxim,mcp795"; - reg = <0>; - }; diff --git a/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml b/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml index 27a9de10f0af..7680089d1d92 100644 --- a/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml +++ b/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml @@ -38,6 +38,8 @@ properties: - 3000 - 4400 + wakeup-source: true + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/rtc/mstar,ssd202d-rtc.yaml b/Documentation/devicetree/bindings/rtc/mstar,ssd202d-rtc.yaml new file mode 100644 index 000000000000..4c1f22ef5a2c --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/mstar,ssd202d-rtc.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/mstar,ssd202d-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mstar SSD202D Real Time Clock + +maintainers: + - Daniel Palmer <daniel@0x0f.com> + - Romain Perier <romain.perier@gmail.com> + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + enum: + - mstar,ssd202d-rtc + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + rtc@6800 { + compatible = "mstar,ssd202d-rtc"; + reg = <0x6800 0x200>; + }; +... diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf2123.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf2123.yaml new file mode 100644 index 000000000000..96e377a4d1bc --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf2123.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/nxp,pcf2123.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCF2123 SPI Real Time Clock + +maintainers: + - Javier Carrasco <javier.carrasco.cruz@gmail.com> + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - $ref: rtc.yaml# + +properties: + compatible: + enum: + - nxp,pcf2123 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + + rtc@3 { + compatible = "nxp,pcf2123"; + reg = <3>; + interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_LOW>; + spi-cs-high; + }; + }; +... diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt b/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt deleted file mode 100644 index 0b1080c60f63..000000000000 --- a/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt +++ /dev/null @@ -1,18 +0,0 @@ -* NXP PCF8523 Real Time Clock - -Required properties: -- compatible: Should contain "nxp,pcf8523". -- reg: I2C address for chip. - -Optional property: -- quartz-load-femtofarads: The capacitive load of the quartz(x-tal), - expressed in femto Farad (fF). Valid values are 7000 and 12500. - Default value (if no value is specified) is 12500fF. - -Example: - -pcf8523: rtc@68 { - compatible = "nxp,pcf8523"; - reg = <0x68>; - quartz-load-femtofarads = <7000>; -}; diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf8523.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf8523.yaml new file mode 100644 index 000000000000..d11c8bc16bc0 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf8523.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/nxp,pcf8523.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCF8523 Real Time Clock + +maintainers: + - Sam Ravnborg <sam@ravnborg.org> + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + const: nxp,pcf8523 + + reg: + maxItems: 1 + + quartz-load-femtofarads: + description: + The capacitive load of the crystal, expressed in femto Farad (fF). + enum: [ 7000, 12500 ] + default: 12500 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rtc@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + quartz-load-femtofarads = <7000>; + }; + }; diff --git a/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt b/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt deleted file mode 100644 index 7371f525a687..000000000000 --- a/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt +++ /dev/null @@ -1,17 +0,0 @@ -NXP PCF2123 SPI Real Time Clock - -Required properties: -- compatible: should be: "nxp,pcf2123" - or "microcrystal,rv2123" -- reg: should be the SPI slave chipselect address - -Optional properties: -- spi-cs-high: PCF2123 needs chipselect high - -Example: - -pcf2123: rtc@3 { - compatible = "nxp,pcf2123" - reg = <3> - spi-cs-high; -}; diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index 2a65f31ac5a0..c9e3c5262c21 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -45,6 +45,8 @@ properties: - isil,isl1208 # Intersil ISL1218 Low Power RTC with Battery Backed SRAM - isil,isl1218 + # SPI-BUS INTERFACE REAL TIME CLOCK MODULE + - maxim,mcp795 # Real Time Clock Module with I2C-Bus - microcrystal,rv3029 # Real Time Clock diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d7502433c78a..3814e0845e77 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1351,7 +1351,7 @@ config RTC_DRV_DIGICOLOR config RTC_DRV_IMXDI tristate "Freescale IMX DryIce Real Time Clock" - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST depends on OF help Support for Freescale IMX DryIce RTC @@ -1984,4 +1984,15 @@ config RTC_DRV_POLARFIRE_SOC This driver can also be built as a module, if so, the module will be called "rtc-mpfs". +config RTC_DRV_SSD202D + tristate "SigmaStar SSD202D RTC" + depends on ARCH_MSTARV7 || COMPILE_TEST + default ARCH_MSTARV7 + help + If you say yes here you get support for the SigmaStar SSD202D On-Chip + Real Time Clock. + + This driver can also be built as a module, if so, the module + will be called "rtc-ssd20xd". + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index fd209883ee2e..7b03c3abfd78 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MSC313) += rtc-msc313.o +obj-$(CONFIG_RTC_DRV_SSD202D) += rtc-ssd202d.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MT2712) += rtc-mt2712.o obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index add4f71d7b3b..c16fe711a0d9 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -558,7 +558,7 @@ err_clk: /* * Disable and remove the RTC driver */ -static int __exit at91_rtc_remove(struct platform_device *pdev) +static void __exit at91_rtc_remove(struct platform_device *pdev) { /* Disable all interrupts */ at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM | @@ -566,8 +566,6 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) AT91_RTC_CALEV); clk_disable_unprepare(sclk); - - return 0; } static void at91_rtc_shutdown(struct platform_device *pdev) @@ -635,8 +633,14 @@ static int at91_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); -static struct platform_driver at91_rtc_driver = { - .remove = __exit_p(at91_rtc_remove), +/* + * at91_rtc_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver at91_rtc_driver __refdata = { + .remove_new = __exit_p(at91_rtc_remove), .shutdown = at91_rtc_shutdown, .driver = { .name = "at91_rtc", diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index 3cdc015692ca..1a65a4e0dc00 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright © 2014-2017 Broadcom + * Copyright © 2014-2023 Broadcom */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -34,6 +34,7 @@ struct brcmstb_waketmr { u32 rate; unsigned long rtc_alarm; bool alarm_en; + bool alarm_expired; }; #define BRCMSTB_WKTMR_EVENT 0x00 @@ -64,6 +65,11 @@ static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM); writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT); (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); + if (timer->alarm_expired) { + timer->alarm_expired = false; + /* maintain call balance */ + enable_irq(timer->alarm_irq); + } } static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer, @@ -105,10 +111,17 @@ static irqreturn_t brcmstb_alarm_irq(int irq, void *data) return IRQ_HANDLED; if (timer->alarm_en) { - if (!device_may_wakeup(timer->dev)) + if (device_may_wakeup(timer->dev)) { + disable_irq_nosync(irq); + timer->alarm_expired = true; + } else { writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT); + } rtc_update_irq(timer->rtc, 1, RTC_IRQF | RTC_AF); + } else { + writel_relaxed(WKTMR_ALARM_EVENT, + timer->base + BRCMSTB_WKTMR_EVENT); } return IRQ_HANDLED; @@ -221,8 +234,14 @@ static int brcmstb_waketmr_alarm_enable(struct device *dev, !brcmstb_waketmr_is_pending(timer)) return -EINVAL; timer->alarm_en = true; - if (timer->alarm_irq) + if (timer->alarm_irq) { + if (timer->alarm_expired) { + timer->alarm_expired = false; + /* maintain call balance */ + enable_irq(timer->alarm_irq); + } enable_irq(timer->alarm_irq); + } } else if (!enabled && timer->alarm_en) { if (timer->alarm_irq) disable_irq(timer->alarm_irq); @@ -352,6 +371,17 @@ static int brcmstb_waketmr_suspend(struct device *dev) return brcmstb_waketmr_prepare_suspend(timer); } +static int brcmstb_waketmr_suspend_noirq(struct device *dev) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + + /* Catch any alarms occurring prior to noirq */ + if (timer->alarm_expired && device_may_wakeup(dev)) + return -EBUSY; + + return 0; +} + static int brcmstb_waketmr_resume(struct device *dev) { struct brcmstb_waketmr *timer = dev_get_drvdata(dev); @@ -368,10 +398,17 @@ static int brcmstb_waketmr_resume(struct device *dev) return ret; } +#else +#define brcmstb_waketmr_suspend NULL +#define brcmstb_waketmr_suspend_noirq NULL +#define brcmstb_waketmr_resume NULL #endif /* CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops, - brcmstb_waketmr_suspend, brcmstb_waketmr_resume); +static const struct dev_pm_ops brcmstb_waketmr_pm_ops = { + .suspend = brcmstb_waketmr_suspend, + .suspend_noirq = brcmstb_waketmr_suspend_noirq, + .resume = brcmstb_waketmr_resume, +}; static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = { { .compatible = "brcm,brcmstb-waketimer" }, diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index dc6b0f4a54e2..fa8bf82df948 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -227,7 +227,7 @@ static int efi_procfs(struct device *dev, struct seq_file *seq) enabled == 1 ? "yes" : "no", pending == 1 ? "yes" : "no"); - if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) + if (alm.timezone == EFI_UNSPECIFIED_TIMEZONE) seq_puts(seq, "Timezone\t: unspecified\n"); else /* XXX fixme: convert to string? */ diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index acae7f16808f..1fdd20d01560 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -7,6 +7,7 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/io.h> @@ -148,9 +149,16 @@ static int ep93xx_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(ep93xx_rtc->rtc); } +static const struct of_device_id ep93xx_rtc_of_ids[] = { + { .compatible = "cirrus,ep9301-rtc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ep93xx_rtc_of_ids); + static struct platform_driver ep93xx_rtc_driver = { .driver = { .name = "ep93xx-rtc", + .of_match_table = ep93xx_rtc_of_ids, }, .probe = ep93xx_rtc_probe, }; diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 4b712e5ab08a..284011c419db 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -830,7 +830,7 @@ err: return rc; } -static int __exit dryice_rtc_remove(struct platform_device *pdev) +static void __exit dryice_rtc_remove(struct platform_device *pdev) { struct imxdi_dev *imxdi = platform_get_drvdata(pdev); @@ -840,8 +840,6 @@ static int __exit dryice_rtc_remove(struct platform_device *pdev) writel(0, imxdi->ioaddr + DIER); clk_disable_unprepare(imxdi->clk); - - return 0; } static const struct of_device_id dryice_dt_ids[] = { @@ -851,12 +849,18 @@ static const struct of_device_id dryice_dt_ids[] = { MODULE_DEVICE_TABLE(of, dryice_dt_ids); -static struct platform_driver dryice_rtc_driver = { +/* + * dryice_rtc_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver dryice_rtc_driver __refdata = { .driver = { .name = "imxdi_rtc", .of_match_table = dryice_dt_ids, }, - .remove = __exit_p(dryice_rtc_remove), + .remove_new = __exit_p(dryice_rtc_remove), }; module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe); diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index 6c526e2ec56d..db31da56bfa7 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -282,7 +282,7 @@ out: return ret; } -static int __exit mv_rtc_remove(struct platform_device *pdev) +static void __exit mv_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); @@ -291,8 +291,6 @@ static int __exit mv_rtc_remove(struct platform_device *pdev) if (!IS_ERR(pdata->clk)) clk_disable_unprepare(pdata->clk); - - return 0; } #ifdef CONFIG_OF @@ -303,8 +301,14 @@ static const struct of_device_id rtc_mv_of_match_table[] = { MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table); #endif -static struct platform_driver mv_rtc_driver = { - .remove = __exit_p(mv_rtc_remove), +/* + * mv_rtc_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver mv_rtc_driver __refdata = { + .remove_new = __exit_p(mv_rtc_remove), .driver = { .name = "rtc-mv", .of_match_table = of_match_ptr(rtc_mv_of_match_table), diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 5b10ab06cd2e..c6155c48a4ac 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -18,12 +18,12 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/rtc.h> #include <linux/rtc/rtc-omap.h> @@ -729,16 +729,14 @@ static int omap_rtc_probe(struct platform_device *pdev) struct omap_rtc *rtc; u8 reg, mask, new_ctrl; const struct platform_device_id *id_entry; - const struct of_device_id *of_id; int ret; rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; - of_id = of_match_device(omap_rtc_of_match, &pdev->dev); - if (of_id) { - rtc->type = of_id->data; + rtc->type = device_get_match_data(&pdev->dev); + if (rtc->type) { rtc->is_pmic_controller = rtc->type->has_pmic_mode && of_device_is_system_power_controller(pdev->dev.of_node); } else { diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index 8c7a98a5452c..d6651611a0c6 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -166,13 +166,7 @@ static int __init pcap_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(pcap_rtc->rtc); } -static int __exit pcap_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver pcap_rtc_driver = { - .remove = __exit_p(pcap_rtc_remove), .driver = { .name = "pcap-rtc", }, diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index 06194674d71c..540042b9eec8 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -438,7 +438,7 @@ static int pcf85363_probe(struct i2c_client *client) if (client->irq > 0 || wakeup_source) { regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, - PIN_IO_INTA_OUT, PIN_IO_INTAPM); + PIN_IO_INTAPM, PIN_IO_INTA_OUT); } if (client->irq > 0) { diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index e400c78252e8..cdb39fc4cab5 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -365,12 +365,11 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit pxa_rtc_remove(struct platform_device *pdev) +static void __exit pxa_rtc_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; pxa_rtc_release(dev); - return 0; } #ifdef CONFIG_OF @@ -403,8 +402,14 @@ static int pxa_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pxa_rtc_pm_ops, pxa_rtc_suspend, pxa_rtc_resume); -static struct platform_driver pxa_rtc_driver = { - .remove = __exit_p(pxa_rtc_remove), +/* + * pxa_rtc_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver pxa_rtc_driver __refdata = { + .remove_new = __exit_p(pxa_rtc_remove), .driver = { .name = "pxa-rtc", .of_match_table = of_match_ptr(pxa_rtc_dt_ids), diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c index 5dbaeb7af648..ef913cf8593f 100644 --- a/drivers/rtc/rtc-r7301.c +++ b/drivers/rtc/rtc-r7301.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/delay.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/platform_device.h> #include <linux/rtc.h> @@ -55,12 +56,23 @@ struct rtc7301_priv { u8 bank; }; -static const struct regmap_config rtc7301_regmap_config = { +/* + * When the device is memory-mapped, some platforms pack the registers into + * 32-bit access using the lower 8 bits at each 4-byte stride, while others + * expose them as simply consecutive bytes. + */ +static const struct regmap_config rtc7301_regmap_32_config = { .reg_bits = 32, .val_bits = 8, .reg_stride = 4, }; +static const struct regmap_config rtc7301_regmap_8_config = { + .reg_bits = 8, + .val_bits = 8, + .reg_stride = 1, +}; + static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg) { int reg_stride = regmap_get_reg_stride(priv->regmap); @@ -356,7 +368,9 @@ static int __init rtc7301_rtc_probe(struct platform_device *dev) void __iomem *regs; struct rtc7301_priv *priv; struct rtc_device *rtc; + static const struct regmap_config *mapconf; int ret; + u32 val; priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -366,8 +380,25 @@ static int __init rtc7301_rtc_probe(struct platform_device *dev) if (IS_ERR(regs)) return PTR_ERR(regs); + ret = device_property_read_u32(&dev->dev, "reg-io-width", &val); + if (ret) + /* Default to 32bit accesses */ + val = 4; + + switch (val) { + case 1: + mapconf = &rtc7301_regmap_8_config; + break; + case 4: + mapconf = &rtc7301_regmap_32_config; + break; + default: + dev_err(&dev->dev, "invalid reg-io-width %d\n", val); + return -EINVAL; + } + priv->regmap = devm_regmap_init_mmio(&dev->dev, regs, - &rtc7301_regmap_config); + mapconf); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index cd146b574143..27a191fa3704 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -469,7 +469,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev) { struct sh_rtc *rtc; struct resource *res; - char clk_name[6]; + char clk_name[14]; int clk_id, ret; rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); @@ -620,7 +620,7 @@ err_unmap: return ret; } -static int __exit sh_rtc_remove(struct platform_device *pdev) +static void __exit sh_rtc_remove(struct platform_device *pdev) { struct sh_rtc *rtc = platform_get_drvdata(pdev); @@ -628,8 +628,6 @@ static int __exit sh_rtc_remove(struct platform_device *pdev) sh_rtc_setcie(&pdev->dev, 0); clk_disable(rtc->clk); - - return 0; } static void sh_rtc_set_irq_wake(struct device *dev, int enabled) @@ -668,13 +666,19 @@ static const struct of_device_id sh_rtc_of_match[] = { }; MODULE_DEVICE_TABLE(of, sh_rtc_of_match); -static struct platform_driver sh_rtc_platform_driver = { +/* + * sh_rtc_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver sh_rtc_platform_driver __refdata = { .driver = { .name = DRV_NAME, .pm = &sh_rtc_pm_ops, .of_match_table = sh_rtc_of_match, }, - .remove = __exit_p(sh_rtc_remove), + .remove_new = __exit_p(sh_rtc_remove), }; module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe); diff --git a/drivers/rtc/rtc-ssd202d.c b/drivers/rtc/rtc-ssd202d.c new file mode 100644 index 000000000000..ed6493260096 --- /dev/null +++ b/drivers/rtc/rtc-ssd202d.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Real time clocks driver for MStar/SigmaStar SSD202D SoCs. + * + * (C) 2021 Daniel Palmer + * (C) 2023 Romain Perier + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/regmap.h> +#include <linux/pm.h> + +#define REG_CTRL 0x0 +#define REG_CTRL1 0x4 +#define REG_ISO_CTRL 0xc +#define REG_WRDATA_L 0x10 +#define REG_WRDATA_H 0x14 +#define REG_ISOACK 0x20 +#define REG_RDDATA_L 0x24 +#define REG_RDDATA_H 0x28 +#define REG_RDCNT_L 0x30 +#define REG_RDCNT_H 0x34 +#define REG_CNT_TRIG 0x38 +#define REG_PWRCTRL 0x3c +#define REG_RTC_TEST 0x54 + +#define CNT_RD_TRIG_BIT BIT(0) +#define CNT_RD_BIT BIT(0) +#define BASE_WR_BIT BIT(1) +#define BASE_RD_BIT BIT(2) +#define CNT_RST_BIT BIT(3) +#define ISO_CTRL_ACK_MASK BIT(3) +#define ISO_CTRL_ACK_SHIFT 3 +#define SW0_WR_BIT BIT(5) +#define SW1_WR_BIT BIT(6) +#define SW0_RD_BIT BIT(7) +#define SW1_RD_BIT BIT(8) + +#define ISO_CTRL_MASK GENMASK(2, 0) + +struct ssd202d_rtc { + struct rtc_device *rtc_dev; + void __iomem *base; +}; + +static u8 read_iso_en(void __iomem *base) +{ + return readb(base + REG_RTC_TEST) & 0x1; +} + +static u8 read_iso_ctrl_ack(void __iomem *base) +{ + return (readb(base + REG_ISOACK) & ISO_CTRL_ACK_MASK) >> ISO_CTRL_ACK_SHIFT; +} + +static int ssd202d_rtc_isoctrl(struct ssd202d_rtc *priv) +{ + static const unsigned int sequence[] = { 0x0, 0x1, 0x3, 0x7, 0x5, 0x1, 0x0 }; + unsigned int val; + struct device *dev = &priv->rtc_dev->dev; + int i, ret; + + /* + * This gates iso_en by writing a special sequence of bytes to iso_ctrl + * and ensuring that it has been correctly applied by reading iso_ctrl_ack + */ + for (i = 0; i < ARRAY_SIZE(sequence); i++) { + writeb(sequence[i] & ISO_CTRL_MASK, priv->base + REG_ISO_CTRL); + + ret = read_poll_timeout(read_iso_ctrl_ack, val, val == (i % 2), 100, + 20 * 100, true, priv->base); + if (ret) { + dev_dbg(dev, "Timeout waiting for ack byte %i (%x) of sequence\n", i, + sequence[i]); + return ret; + } + } + + /* + * At this point iso_en should be raised for 1ms + */ + ret = read_poll_timeout(read_iso_en, val, val, 100, 22 * 100, true, priv->base); + if (ret) + dev_dbg(dev, "Timeout waiting for iso_en\n"); + mdelay(2); + return 0; +} + +static void ssd202d_rtc_read_reg(struct ssd202d_rtc *priv, unsigned int reg, + unsigned int field, unsigned int *base) +{ + unsigned int l, h; + u16 val; + + /* Ask for the content of an RTC value into RDDATA by gating iso_en, + * then iso_en is gated and the content of RDDATA can be read + */ + val = readw(priv->base + reg); + writew(val | field, priv->base + reg); + ssd202d_rtc_isoctrl(priv); + writew(val & ~field, priv->base + reg); + + l = readw(priv->base + REG_RDDATA_L); + h = readw(priv->base + REG_RDDATA_H); + + *base = (h << 16) | l; +} + +static void ssd202d_rtc_write_reg(struct ssd202d_rtc *priv, unsigned int reg, + unsigned int field, u32 base) +{ + u16 val; + + /* Set the content of an RTC value from WRDATA by gating iso_en */ + val = readw(priv->base + reg); + writew(val | field, priv->base + reg); + writew(base, priv->base + REG_WRDATA_L); + writew(base >> 16, priv->base + REG_WRDATA_H); + ssd202d_rtc_isoctrl(priv); + writew(val & ~field, priv->base + reg); +} + +static int ssd202d_rtc_read_counter(struct ssd202d_rtc *priv, unsigned int *counter) +{ + unsigned int l, h; + u16 val; + + val = readw(priv->base + REG_CTRL1); + writew(val | CNT_RD_BIT, priv->base + REG_CTRL1); + ssd202d_rtc_isoctrl(priv); + writew(val & ~CNT_RD_BIT, priv->base + REG_CTRL1); + + val = readw(priv->base + REG_CTRL1); + writew(val | CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG); + writew(val & ~CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG); + + l = readw(priv->base + REG_RDCNT_L); + h = readw(priv->base + REG_RDCNT_H); + + *counter = (h << 16) | l; + + return 0; +} + +static int ssd202d_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct ssd202d_rtc *priv = dev_get_drvdata(dev); + unsigned int sw0, base, counter; + u32 seconds; + int ret; + + /* Check that RTC is enabled by SW */ + ssd202d_rtc_read_reg(priv, REG_CTRL, SW0_RD_BIT, &sw0); + if (sw0 != 1) + return -EINVAL; + + /* Get RTC base value from RDDATA */ + ssd202d_rtc_read_reg(priv, REG_CTRL, BASE_RD_BIT, &base); + /* Get RTC counter value from RDDATA */ + ret = ssd202d_rtc_read_counter(priv, &counter); + if (ret) + return ret; + + seconds = base + counter; + + rtc_time64_to_tm(seconds, tm); + + return 0; +} + +static int ssd202d_rtc_reset_counter(struct ssd202d_rtc *priv) +{ + u16 val; + + val = readw(priv->base + REG_CTRL); + writew(val | CNT_RST_BIT, priv->base + REG_CTRL); + ssd202d_rtc_isoctrl(priv); + writew(val & ~CNT_RST_BIT, priv->base + REG_CTRL); + ssd202d_rtc_isoctrl(priv); + + return 0; +} + +static int ssd202d_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct ssd202d_rtc *priv = dev_get_drvdata(dev); + unsigned long seconds = rtc_tm_to_time64(tm); + + ssd202d_rtc_write_reg(priv, REG_CTRL, BASE_WR_BIT, seconds); + ssd202d_rtc_reset_counter(priv); + ssd202d_rtc_write_reg(priv, REG_CTRL, SW0_WR_BIT, 1); + + return 0; +} + +static const struct rtc_class_ops ssd202d_rtc_ops = { + .read_time = ssd202d_rtc_read_time, + .set_time = ssd202d_rtc_set_time, +}; + +static int ssd202d_rtc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ssd202d_rtc *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct ssd202d_rtc), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->rtc_dev = devm_rtc_allocate_device(dev); + if (IS_ERR(priv->rtc_dev)) + return PTR_ERR(priv->rtc_dev); + + priv->rtc_dev->ops = &ssd202d_rtc_ops; + priv->rtc_dev->range_max = U32_MAX; + + platform_set_drvdata(pdev, priv); + + return devm_rtc_register_device(priv->rtc_dev); +} + +static const struct of_device_id ssd202d_rtc_of_match_table[] = { + { .compatible = "mstar,ssd202d-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, ssd202d_rtc_of_match_table); + +static struct platform_driver ssd202d_rtc_driver = { + .probe = ssd202d_rtc_probe, + .driver = { + .name = "ssd202d-rtc", + .of_match_table = ssd202d_rtc_of_match_table, + }, +}; +module_platform_driver(ssd202d_rtc_driver); + +MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>"); +MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>"); +MODULE_DESCRIPTION("MStar SSD202D RTC Driver"); +MODULE_LICENSE("GPL"); |