From 61598093bbdd283a7edc367d900f223070ead8d2 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:03 +0000 Subject: [PATCH] add ax88772C AX88772C_eeprom_tools --- kernel/drivers/rtc/rtc-snvs.c | 167 +++++++++++++++++++++++++++++++++---------------------- 1 files changed, 100 insertions(+), 67 deletions(-) diff --git a/kernel/drivers/rtc/rtc-snvs.c b/kernel/drivers/rtc/rtc-snvs.c index 3cf011e..cc7f6c4 100644 --- a/kernel/drivers/rtc/rtc-snvs.c +++ b/kernel/drivers/rtc/rtc-snvs.c @@ -7,8 +7,8 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/rtc.h> #include <linux/clk.h> #include <linux/mfd/syscon.h> @@ -31,6 +31,14 @@ #define SNVS_LPPGDR_INIT 0x41736166 #define CNTR_TO_SECS_SH 15 + +/* The maximum RTC clock cycles that are allowed to pass between two + * consecutive clock counter register reads. If the values are corrupted a + * bigger difference is expected. The RTC frequency is 32kHz. With 320 cycles + * we end at 10ms which should be enough for most cases. If it once takes + * longer than expected we do a retry. + */ +#define MAX_RTC_READ_DIFF_CYCLES 320 struct snvs_rtc_data { struct rtc_device *rtc; @@ -56,6 +64,7 @@ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) { u64 read1, read2; + s64 diff; unsigned int timeout = 100; /* As expected, the registers might update between the read of the LSB @@ -66,7 +75,8 @@ do { read2 = read1; read1 = rtc_read_lpsrt(data); - } while (read1 != read2 && --timeout); + diff = read1 - read2; + } while (((diff < 0) || (diff > MAX_RTC_READ_DIFF_CYCLES)) && --timeout); if (!timeout) dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); @@ -78,13 +88,15 @@ static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb) { u32 count1, count2; + s32 diff; unsigned int timeout = 100; regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); do { count2 = count1; regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); - } while (count1 != count2 && --timeout); + diff = count1 - count2; + } while (((diff < 0) || (diff > MAX_RTC_READ_DIFF_CYCLES)) && --timeout); if (!timeout) { dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); return -ETIMEDOUT; @@ -148,9 +160,20 @@ static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); - unsigned long time = rtc_read_lp_counter(data); + unsigned long time; + int ret; - rtc_time_to_tm(time, tm); + if (data->clk) { + ret = clk_enable(data->clk); + if (ret) + return ret; + } + + time = rtc_read_lp_counter(data); + rtc_time64_to_tm(time, tm); + + if (data->clk) + clk_disable(data->clk); return 0; } @@ -158,10 +181,14 @@ static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); - unsigned long time; + unsigned long time = rtc_tm_to_time64(tm); int ret; - rtc_tm_to_time(tm, &time); + if (data->clk) { + ret = clk_enable(data->clk); + if (ret) + return ret; + } /* Disable RTC first */ ret = snvs_rtc_enable(data, false); @@ -175,6 +202,9 @@ /* Enable RTC again */ ret = snvs_rtc_enable(data, true); + if (data->clk) + clk_disable(data->clk); + return ret; } @@ -182,12 +212,22 @@ { struct snvs_rtc_data *data = dev_get_drvdata(dev); u32 lptar, lpsr; + int ret; + + if (data->clk) { + ret = clk_enable(data->clk); + if (ret) + return ret; + } regmap_read(data->regmap, data->offset + SNVS_LPTAR, &lptar); - rtc_time_to_tm(lptar, &alrm->time); + rtc_time64_to_tm(lptar, &alrm->time); regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0; + + if (data->clk) + clk_disable(data->clk); return 0; } @@ -195,22 +235,37 @@ static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { struct snvs_rtc_data *data = dev_get_drvdata(dev); + int ret; + + if (data->clk) { + ret = clk_enable(data->clk); + if (ret) + return ret; + } regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN), enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0); - return rtc_write_sync_lp(data); + ret = rtc_write_sync_lp(data); + + if (data->clk) + clk_disable(data->clk); + + return ret; } static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); - struct rtc_time *alrm_tm = &alrm->time; - unsigned long time; + unsigned long time = rtc_tm_to_time64(&alrm->time); int ret; - rtc_tm_to_time(alrm_tm, &time); + if (data->clk) { + ret = clk_enable(data->clk); + if (ret) + return ret; + } regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); ret = rtc_write_sync_lp(data); @@ -220,6 +275,9 @@ /* Clear alarm interrupt status bit */ regmap_write(data->regmap, data->offset + SNVS_LPSR, SNVS_LPSR_LPTA); + + if (data->clk) + clk_disable(data->clk); return snvs_rtc_alarm_irq_enable(dev, alrm->enabled); } @@ -239,6 +297,9 @@ u32 lpsr; u32 events = 0; + if (data->clk) + clk_enable(data->clk); + regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); if (lpsr & SNVS_LPSR_LPTA) { @@ -253,6 +314,9 @@ /* clear interrupt status */ regmap_write(data->regmap, data->offset + SNVS_LPSR, lpsr); + if (data->clk) + clk_disable(data->clk); + return events ? IRQ_HANDLED : IRQ_NONE; } @@ -262,10 +326,15 @@ .reg_stride = 4, }; +static void snvs_rtc_action(void *data) +{ + if (data) + clk_disable_unprepare(data); +} + static int snvs_rtc_probe(struct platform_device *pdev) { struct snvs_rtc_data *data; - struct resource *res; int ret; void __iomem *mmio; @@ -281,9 +350,8 @@ if (IS_ERR(data->regmap)) { dev_warn(&pdev->dev, "snvs rtc: you use old dts file, please update it\n"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio = devm_ioremap_resource(&pdev->dev, res); + mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mmio)) return PTR_ERR(mmio); @@ -314,6 +382,10 @@ } } + ret = devm_add_action_or_reset(&pdev->dev, snvs_rtc_action, data->clk); + if (ret) + return ret; + platform_set_drvdata(pdev, data); /* Initialize glitch detect */ @@ -326,90 +398,51 @@ ret = snvs_rtc_enable(data, true); if (ret) { dev_err(&pdev->dev, "failed to enable rtc %d\n", ret); - goto error_rtc_device_register; + return ret; } device_init_wakeup(&pdev->dev, true); + ret = dev_pm_set_wake_irq(&pdev->dev, data->irq); + if (ret) + dev_err(&pdev->dev, "failed to enable irq wake\n"); ret = devm_request_irq(&pdev->dev, data->irq, snvs_rtc_irq_handler, IRQF_SHARED, "rtc alarm", &pdev->dev); if (ret) { dev_err(&pdev->dev, "failed to request irq %d: %d\n", data->irq, ret); - goto error_rtc_device_register; + return ret; } data->rtc->ops = &snvs_rtc_ops; - ret = rtc_register_device(data->rtc); - if (ret) { - dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); - goto error_rtc_device_register; - } + data->rtc->range_max = U32_MAX; - return 0; - -error_rtc_device_register: - if (data->clk) - clk_disable_unprepare(data->clk); - - return ret; + return rtc_register_device(data->rtc); } -#ifdef CONFIG_PM_SLEEP -static int snvs_rtc_suspend(struct device *dev) -{ - struct snvs_rtc_data *data = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - return enable_irq_wake(data->irq); - - return 0; -} - -static int snvs_rtc_suspend_noirq(struct device *dev) +static int __maybe_unused snvs_rtc_suspend_noirq(struct device *dev) { struct snvs_rtc_data *data = dev_get_drvdata(dev); if (data->clk) - clk_disable_unprepare(data->clk); + clk_disable(data->clk); return 0; } -static int snvs_rtc_resume(struct device *dev) -{ - struct snvs_rtc_data *data = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - return disable_irq_wake(data->irq); - - return 0; -} - -static int snvs_rtc_resume_noirq(struct device *dev) +static int __maybe_unused snvs_rtc_resume_noirq(struct device *dev) { struct snvs_rtc_data *data = dev_get_drvdata(dev); if (data->clk) - return clk_prepare_enable(data->clk); + return clk_enable(data->clk); return 0; } static const struct dev_pm_ops snvs_rtc_pm_ops = { - .suspend = snvs_rtc_suspend, - .suspend_noirq = snvs_rtc_suspend_noirq, - .resume = snvs_rtc_resume, - .resume_noirq = snvs_rtc_resume_noirq, + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(snvs_rtc_suspend_noirq, snvs_rtc_resume_noirq) }; - -#define SNVS_RTC_PM_OPS (&snvs_rtc_pm_ops) - -#else - -#define SNVS_RTC_PM_OPS NULL - -#endif static const struct of_device_id snvs_dt_ids[] = { { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, @@ -420,7 +453,7 @@ static struct platform_driver snvs_rtc_driver = { .driver = { .name = "snvs_rtc", - .pm = SNVS_RTC_PM_OPS, + .pm = &snvs_rtc_pm_ops, .of_match_table = snvs_dt_ids, }, .probe = snvs_rtc_probe, -- Gitblit v1.6.2