From cf9610f9116d55c5a66ef9f1faecacabd93a9322 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 24 Aug 2026 08:46:03 -0700 Subject: Merge tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl Pull pin control updates from Linus Walleij: "Core changes: - Use the non-blocking mux_state_try_select() in the generic MUX pin control back-end - Free pin maps on pinctrl_generic_to_map() failure in the core helpers New hardware pin control: - Qualcomm Maili TLMM SoC, PMG1110 PMIC, and Eliza LPASS LPI TLMM SoC (this is for the low power audio, LPASS = Low Power Audio SubSystem portions) - Upboard support on top of the Intel pin controller - Apple T6030 and T6031 support (just compatible strings) - Samsung Exynos 8855 SoC - Mediatek MT6858 SoC - Rockchip RK3308B and RV1106 SoCs - Airoha EN7523 and AN7563 SoCs Improvements: - Qualcomm TLMM GPIOs are unconditionally marked as wakeup capable - Qualcomm improvements on top of the Qualcomm PDC (power domain controller) irqchip improvements from tglx:s tree - Qualcomm IPQ806x and IPQ9650 non-urgent pin grop fixups - The NPCM8xx driver has been put into shape fixing many pin and group definitions - Some non-urgent Tegra 264 pin assignments are fixed up - Some non-urgent fixups to Airoha AN7581 and AN7583 registers and pin assignments, missing features etc" * tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (130 commits) dt-bindings: pinctrl: Convert TI DA850 pupd to DT schema pinctrl: meson: sync some modify from A4 pinctrl: meson: a4: Add input enable pin configuration pinctrl: realtek: rtd1625: remove unused group name spdif_sel pinctrl: realtek: rtd1625: fix base_bit for VE4 GPIO 13 dt-bindings: pinctrl: microchip,pic32mzda-pinctrl: Convert to DT schema Revert "Merge branch 'ib-rsk7204' into devel" pinctrl: rockchip: Add RV1106 pinctrl support dt-bindings: pinctrl: rockchip: Add RV1106 compatible pinctrl: rockchip: Decode drive strength in the get function pinctrl: fix PINCTRL_GENERIC_MUX not always being selectable pinctrl: airoha: add support of an7563 SoC dt-bindings: pinctrl: airoha: add support of an7563 pin controller pinctrl: airoha: try to find chip scu node by phandle first pinctrl: airoha: add support of en7523 SoC dt-bindings: pinctrl: airoha: add support of en7523 pin controller pinctrl: airoha: an7583: add support for olt pinmux pinctrl: airoha: an7583: add support for pon_alt pinmux pinctrl: airoha: an7583: add support for npu_uart pinmux dt-bindings: pinctrl: airoha: an7583: add missed features ... --- drivers/rtc/rtc-ntxec.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 drivers/rtc/rtc-ntxec.c (limited to 'drivers/rtc/rtc-ntxec.c') diff --git a/drivers/rtc/rtc-ntxec.c b/drivers/rtc/rtc-ntxec.c new file mode 100644 index 000000000..d28ddb34e --- /dev/null +++ b/drivers/rtc/rtc-ntxec.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * The Netronix embedded controller is a microcontroller found in some + * e-book readers designed by the original design manufacturer Netronix, Inc. + * It contains RTC, battery monitoring, system power management, and PWM + * functionality. + * + * This driver implements access to the RTC time and date. + * + * Copyright 2020 Jonathan Neuschäfer + */ + +#include +#include +#include +#include +#include +#include + +struct ntxec_rtc { + struct device *dev; + struct ntxec *ec; +}; + +#define NTXEC_REG_WRITE_YEAR 0x10 +#define NTXEC_REG_WRITE_MONTH 0x11 +#define NTXEC_REG_WRITE_DAY 0x12 +#define NTXEC_REG_WRITE_HOUR 0x13 +#define NTXEC_REG_WRITE_MINUTE 0x14 +#define NTXEC_REG_WRITE_SECOND 0x15 + +#define NTXEC_REG_READ_YEAR_MONTH 0x20 +#define NTXEC_REG_READ_MDAY_HOUR 0x21 +#define NTXEC_REG_READ_MINUTE_SECOND 0x23 + +static int ntxec_read_time(struct device *dev, struct rtc_time *tm) +{ + struct ntxec_rtc *rtc = dev_get_drvdata(dev); + unsigned int value; + int res; + +retry: + res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MINUTE_SECOND, &value); + if (res < 0) + return res; + + tm->tm_min = value >> 8; + tm->tm_sec = value & 0xff; + + res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MDAY_HOUR, &value); + if (res < 0) + return res; + + tm->tm_mday = value >> 8; + tm->tm_hour = value & 0xff; + + res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_YEAR_MONTH, &value); + if (res < 0) + return res; + + tm->tm_year = (value >> 8) + 100; + tm->tm_mon = (value & 0xff) - 1; + + /* + * Read the minutes/seconds field again. If it changed since the first + * read, we can't assume that the values read so far are consistent, + * and should start from the beginning. + */ + res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MINUTE_SECOND, &value); + if (res < 0) + return res; + + if (tm->tm_min != value >> 8 || tm->tm_sec != (value & 0xff)) + goto retry; + + return 0; +} + +static int ntxec_set_time(struct device *dev, struct rtc_time *tm) +{ + struct ntxec_rtc *rtc = dev_get_drvdata(dev); + + /* + * To avoid time overflows while we're writing the full date/time, + * set the seconds field to zero before doing anything else. For the + * next 59 seconds (plus however long it takes until the RTC's next + * update of the second field), the seconds field will not overflow + * into the other fields. + */ + struct reg_sequence regs[] = { + { NTXEC_REG_WRITE_SECOND, ntxec_reg8(0) }, + { NTXEC_REG_WRITE_YEAR, ntxec_reg8(tm->tm_year - 100) }, + { NTXEC_REG_WRITE_MONTH, ntxec_reg8(tm->tm_mon + 1) }, + { NTXEC_REG_WRITE_DAY, ntxec_reg8(tm->tm_mday) }, + { NTXEC_REG_WRITE_HOUR, ntxec_reg8(tm->tm_hour) }, + { NTXEC_REG_WRITE_MINUTE, ntxec_reg8(tm->tm_min) }, + { NTXEC_REG_WRITE_SECOND, ntxec_reg8(tm->tm_sec) }, + }; + + return regmap_multi_reg_write(rtc->ec->regmap, regs, ARRAY_SIZE(regs)); +} + +static const struct rtc_class_ops ntxec_rtc_ops = { + .read_time = ntxec_read_time, + .set_time = ntxec_set_time, +}; + +static int ntxec_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *dev; + struct ntxec_rtc *rtc; + + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->dev = &pdev->dev; + rtc->ec = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, rtc); + + dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + dev->ops = &ntxec_rtc_ops; + dev->range_min = RTC_TIMESTAMP_BEGIN_2000; + dev->range_max = 9025257599LL; /* 2255-12-31 23:59:59 */ + + return devm_rtc_register_device(dev); +} + +static struct platform_driver ntxec_rtc_driver = { + .driver = { + .name = "ntxec-rtc", + }, + .probe = ntxec_rtc_probe, +}; +module_platform_driver(ntxec_rtc_driver); + +MODULE_AUTHOR("Jonathan Neuschäfer "); +MODULE_DESCRIPTION("RTC driver for Netronix EC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ntxec-rtc"); -- cgit v1.3.1