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-jz4740.c | 275 +++++++++++++++++++++++------------------------------- 1 files changed, 119 insertions(+), 156 deletions(-) diff --git a/kernel/drivers/rtc/rtc-jz4740.c b/kernel/drivers/rtc/rtc-jz4740.c index d0a8917..9607e6b 100644 --- a/kernel/drivers/rtc/rtc-jz4740.c +++ b/kernel/drivers/rtc/rtc-jz4740.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> * Copyright (C) 2010, Paul Cercueil <paul@crapouillou.net> * JZ4740 SoC RTC driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * */ #include <linux/clk.h> @@ -20,6 +11,7 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/reboot.h> #include <linux/rtc.h> #include <linux/slab.h> @@ -54,6 +46,7 @@ enum jz4740_rtc_type { ID_JZ4740, + ID_JZ4760, ID_JZ4780, }; @@ -62,14 +55,8 @@ enum jz4740_rtc_type type; struct rtc_device *rtc; - struct clk *clk; - - int irq; spinlock_t lock; - - unsigned int min_wakeup_pin_assert_time; - unsigned int reset_pin_assert_time; }; static struct device *dev_for_power_off; @@ -114,7 +101,7 @@ { int ret = 0; - if (rtc->type >= ID_JZ4780) + if (rtc->type >= ID_JZ4760) ret = jz4780_rtc_enable_write(rtc); if (ret == 0) ret = jz4740_rtc_wait_write_ready(rtc); @@ -156,6 +143,9 @@ uint32_t secs, secs2; int timeout = 5; + if (jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD) != 0x12345678) + return -EINVAL; + /* If the seconds register is read while it is updated, it can contain a * bogus value. This can be avoided by making sure that two consecutive * reads have the same value. @@ -171,16 +161,21 @@ if (timeout == 0) return -EIO; - rtc_time_to_tm(secs, time); + rtc_time64_to_tm(secs, time); return 0; } -static int jz4740_rtc_set_mmss(struct device *dev, unsigned long secs) +static int jz4740_rtc_set_time(struct device *dev, struct rtc_time *time) { struct jz4740_rtc *rtc = dev_get_drvdata(dev); + int ret; - return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, secs); + ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, rtc_tm_to_time64(time)); + if (ret) + return ret; + + return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678); } static int jz4740_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -196,18 +191,16 @@ alrm->enabled = !!(ctrl & JZ_RTC_CTRL_AE); alrm->pending = !!(ctrl & JZ_RTC_CTRL_AF); - rtc_time_to_tm(secs, &alrm->time); + rtc_time64_to_tm(secs, &alrm->time); - return rtc_valid_tm(&alrm->time); + return 0; } static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { int ret; struct jz4740_rtc *rtc = dev_get_drvdata(dev); - unsigned long secs; - - rtc_tm_to_time(&alrm->time, &secs); + uint32_t secs = lower_32_bits(rtc_tm_to_time64(&alrm->time)); ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, secs); if (!ret) @@ -225,7 +218,7 @@ static const struct rtc_class_ops jz4740_rtc_ops = { .read_time = jz4740_rtc_read_time, - .set_mmss = jz4740_rtc_set_mmss, + .set_time = jz4740_rtc_set_time, .read_alarm = jz4740_rtc_read_alarm, .set_alarm = jz4740_rtc_set_alarm, .alarm_irq_enable = jz4740_rtc_alarm_irq_enable, @@ -260,187 +253,157 @@ static void jz4740_rtc_power_off(void) { - struct jz4740_rtc *rtc = dev_get_drvdata(dev_for_power_off); - unsigned long rtc_rate; - unsigned long wakeup_filter_ticks; - unsigned long reset_counter_ticks; - - clk_prepare_enable(rtc->clk); - - rtc_rate = clk_get_rate(rtc->clk); - - /* - * Set minimum wakeup pin assertion time: 100 ms. - * Range is 0 to 2 sec if RTC is clocked at 32 kHz. - */ - wakeup_filter_ticks = - (rtc->min_wakeup_pin_assert_time * rtc_rate) / 1000; - if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK) - wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; - else - wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK; - jz4740_rtc_reg_write(rtc, - JZ_REG_RTC_WAKEUP_FILTER, wakeup_filter_ticks); - - /* - * Set reset pin low-level assertion time after wakeup: 60 ms. - * Range is 0 to 125 ms if RTC is clocked at 32 kHz. - */ - reset_counter_ticks = (rtc->reset_pin_assert_time * rtc_rate) / 1000; - if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK) - reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK; - else - reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK; - jz4740_rtc_reg_write(rtc, - JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks); - jz4740_rtc_poweroff(dev_for_power_off); kernel_halt(); } +static void jz4740_rtc_clk_disable(void *data) +{ + clk_disable_unprepare(data); +} + static const struct of_device_id jz4740_rtc_of_match[] = { { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 }, + { .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 }, { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, {}, }; MODULE_DEVICE_TABLE(of, jz4740_rtc_of_match); +static void jz4740_rtc_set_wakeup_params(struct jz4740_rtc *rtc, + struct device_node *np, + unsigned long rate) +{ + unsigned long wakeup_ticks, reset_ticks; + unsigned int min_wakeup_pin_assert_time = 60; /* Default: 60ms */ + unsigned int reset_pin_assert_time = 100; /* Default: 100ms */ + + of_property_read_u32(np, "ingenic,reset-pin-assert-time-ms", + &reset_pin_assert_time); + of_property_read_u32(np, "ingenic,min-wakeup-pin-assert-time-ms", + &min_wakeup_pin_assert_time); + + /* + * Set minimum wakeup pin assertion time: 100 ms. + * Range is 0 to 2 sec if RTC is clocked at 32 kHz. + */ + wakeup_ticks = (min_wakeup_pin_assert_time * rate) / 1000; + if (wakeup_ticks < JZ_RTC_WAKEUP_FILTER_MASK) + wakeup_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; + else + wakeup_ticks = JZ_RTC_WAKEUP_FILTER_MASK; + jz4740_rtc_reg_write(rtc, JZ_REG_RTC_WAKEUP_FILTER, wakeup_ticks); + + /* + * Set reset pin low-level assertion time after wakeup: 60 ms. + * Range is 0 to 125 ms if RTC is clocked at 32 kHz. + */ + reset_ticks = (reset_pin_assert_time * rate) / 1000; + if (reset_ticks < JZ_RTC_RESET_COUNTER_MASK) + reset_ticks &= JZ_RTC_RESET_COUNTER_MASK; + else + reset_ticks = JZ_RTC_RESET_COUNTER_MASK; + jz4740_rtc_reg_write(rtc, JZ_REG_RTC_RESET_COUNTER, reset_ticks); +} + static int jz4740_rtc_probe(struct platform_device *pdev) { - int ret; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct jz4740_rtc *rtc; - uint32_t scratchpad; - struct resource *mem; - const struct platform_device_id *id = platform_get_device_id(pdev); - const struct of_device_id *of_id = of_match_device( - jz4740_rtc_of_match, &pdev->dev); - struct device_node *np = pdev->dev.of_node; + unsigned long rate; + struct clk *clk; + int ret, irq; - rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; - if (of_id) - rtc->type = (enum jz4740_rtc_type)of_id->data; - else - rtc->type = id->driver_data; + rtc->type = (enum jz4740_rtc_type)device_get_match_data(dev); - rtc->irq = platform_get_irq(pdev, 0); - if (rtc->irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq\n"); - return -ENOENT; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rtc->base = devm_ioremap_resource(&pdev->dev, mem); + rtc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rtc->base)) return PTR_ERR(rtc->base); - rtc->clk = devm_clk_get(&pdev->dev, "rtc"); - if (IS_ERR(rtc->clk)) { - dev_err(&pdev->dev, "Failed to get RTC clock\n"); - return PTR_ERR(rtc->clk); + clk = devm_clk_get(dev, "rtc"); + if (IS_ERR(clk)) { + dev_err(dev, "Failed to get RTC clock\n"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + + ret = devm_add_action_or_reset(dev, jz4740_rtc_clk_disable, clk); + if (ret) { + dev_err(dev, "Failed to register devm action\n"); + return ret; } spin_lock_init(&rtc->lock); platform_set_drvdata(pdev, rtc); - device_init_wakeup(&pdev->dev, 1); + device_init_wakeup(dev, 1); - rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &jz4740_rtc_ops, THIS_MODULE); + ret = dev_pm_set_wake_irq(dev, irq); + if (ret) { + dev_err(dev, "Failed to set wake irq: %d\n", ret); + return ret; + } + + rtc->rtc = devm_rtc_allocate_device(dev); if (IS_ERR(rtc->rtc)) { ret = PTR_ERR(rtc->rtc); - dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret); + dev_err(dev, "Failed to allocate rtc device: %d\n", ret); return ret; } - ret = devm_request_irq(&pdev->dev, rtc->irq, jz4740_rtc_irq, 0, - pdev->name, rtc); + rtc->rtc->ops = &jz4740_rtc_ops; + rtc->rtc->range_max = U32_MAX; + + rate = clk_get_rate(clk); + jz4740_rtc_set_wakeup_params(rtc, np, rate); + + /* Each 1 Hz pulse should happen after (rate) ticks */ + jz4740_rtc_reg_write(rtc, JZ_REG_RTC_REGULATOR, rate - 1); + + ret = rtc_register_device(rtc->rtc); + if (ret) + return ret; + + ret = devm_request_irq(dev, irq, jz4740_rtc_irq, 0, + pdev->name, rtc); if (ret) { - dev_err(&pdev->dev, "Failed to request rtc irq: %d\n", ret); + dev_err(dev, "Failed to request rtc irq: %d\n", ret); return ret; } - scratchpad = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD); - if (scratchpad != 0x12345678) { - ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678); - ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0); - if (ret) { - dev_err(&pdev->dev, "Could not write to RTC registers\n"); - return ret; - } - } + if (of_device_is_system_power_controller(np)) { + dev_for_power_off = dev; - if (np && of_device_is_system_power_controller(np)) { - if (!pm_power_off) { - /* Default: 60ms */ - rtc->reset_pin_assert_time = 60; - of_property_read_u32(np, "reset-pin-assert-time-ms", - &rtc->reset_pin_assert_time); - - /* Default: 100ms */ - rtc->min_wakeup_pin_assert_time = 100; - of_property_read_u32(np, - "min-wakeup-pin-assert-time-ms", - &rtc->min_wakeup_pin_assert_time); - - dev_for_power_off = &pdev->dev; + if (!pm_power_off) pm_power_off = jz4740_rtc_power_off; - } else { - dev_warn(&pdev->dev, - "Poweroff handler already present!\n"); - } + else + dev_warn(dev, "Poweroff handler already present!\n"); } return 0; } - -#ifdef CONFIG_PM -static int jz4740_rtc_suspend(struct device *dev) -{ - struct jz4740_rtc *rtc = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(rtc->irq); - return 0; -} - -static int jz4740_rtc_resume(struct device *dev) -{ - struct jz4740_rtc *rtc = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(rtc->irq); - return 0; -} - -static const struct dev_pm_ops jz4740_pm_ops = { - .suspend = jz4740_rtc_suspend, - .resume = jz4740_rtc_resume, -}; -#define JZ4740_RTC_PM_OPS (&jz4740_pm_ops) - -#else -#define JZ4740_RTC_PM_OPS NULL -#endif /* CONFIG_PM */ - -static const struct platform_device_id jz4740_rtc_ids[] = { - { "jz4740-rtc", ID_JZ4740 }, - { "jz4780-rtc", ID_JZ4780 }, - {} -}; -MODULE_DEVICE_TABLE(platform, jz4740_rtc_ids); static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, .driver = { .name = "jz4740-rtc", - .pm = JZ4740_RTC_PM_OPS, - .of_match_table = of_match_ptr(jz4740_rtc_of_match), + .of_match_table = jz4740_rtc_of_match, }, - .id_table = jz4740_rtc_ids, }; module_platform_driver(jz4740_rtc_driver); -- Gitblit v1.6.2