Received: by 2002:a05:6a10:1a4d:0:0:0:0 with SMTP id nk13csp5583871pxb; Mon, 14 Feb 2022 02:39:11 -0800 (PST) X-Google-Smtp-Source: ABdhPJzcLTPelKSRaVoYlHiWsDYESITbeO/53mqwisl5vvTz09NA00Fr0MLDeLrgs+SqBf4y7jSM X-Received: by 2002:a17:906:58d4:: with SMTP id e20mr3040810ejs.562.1644835150794; Mon, 14 Feb 2022 02:39:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1644835150; cv=none; d=google.com; s=arc-20160816; b=O/Atg366I9IRbg80COQGPJbCrnWq/q4Mt3H5uuh8RkFdEHul0pISAL5/PJmpL5uTr2 XpD8tsa0zHfaAJf4WW065ZUO6Cqb/yYHk6ex4s1LzzfEIHn1Cw3XtTzDQM+09v3V6rIZ jPsHW6kPAKegYdwtl7DO+WMPdAAGFqIaNSL0zwbhnBpSXrEr9AvuUIroxCyCYl7qnviM KbbiB+9iZqUBA8KAVBqYg/xeSLPNZO7x3fUvsRDmE8YZLkWspY8XYFun7mUPLPp2sVhO LqarXUpagxFdiwwJjKE7wmO/exnx6CcUnQndD2qxAkP2+3+271LI33Nt4lUgMADjTvKm eTeg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=iNrCMAFFSthPUstmBOhWy94WkkgMAEgNUtRLpanIPew=; b=jXiGVdw2ZeY6UFrAB9x2yw1b5hLj0IDSmIqsCfL93jSz1fCRkxZaMvdtADnrF1pm9c xcUaWq8e2SXPNKkb3DX7SzpjFqwNBlsNbiOLNlCil9QX4tiPBVg6kJmq2MV9Nfa6O1qJ HTFwEcJBGH11me5c8Nt1gz2yRvV30L2LPYNs5vJPVuAk0YHc+9e7VwsshNCQc836Ifhc 9ZL0TIJP5PH35rJf/pggRBRbCEcgsJmtbFI4ytewmNaRlYZXxxQu3oePVmpAPM2micJr lC8+OmatNRjPIWZN+o2j437yCgdwwwbSgF7zUZ+VBGMtp8AK5WQTyrpn4WTZ91sVUJm5 fijw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 26si19971482ejr.644.2022.02.14.02.38.46; Mon, 14 Feb 2022 02:39:10 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350026AbiBKM1H (ORCPT + 93 others); Fri, 11 Feb 2022 07:27:07 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:34316 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349994AbiBKM06 (ORCPT ); Fri, 11 Feb 2022 07:26:58 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7C22DF60; Fri, 11 Feb 2022 04:26:57 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4B0A112FC; Fri, 11 Feb 2022 04:26:57 -0800 (PST) Received: from donnerap.arm.com (donnerap.cambridge.arm.com [10.1.196.172]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8DF163F70D; Fri, 11 Feb 2022 04:26:55 -0800 (PST) From: Andre Przywara To: Maxime Ripard , Chen-Yu Tsai , Jernej Skrabec Cc: Rob Herring , Ondrej Jirman , Icenowy Zheng , Samuel Holland , linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Alessandro Zummo , Alexandre Belloni , linux-rtc@vger.kernel.org Subject: [PATCH v10 04/18] rtc: sun6i: Add support for linear day storage Date: Fri, 11 Feb 2022 12:26:29 +0000 Message-Id: <20220211122643.1343315-5-andre.przywara@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220211122643.1343315-1-andre.przywara@arm.com> References: <20220211122643.1343315-1-andre.przywara@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Newer versions of the Allwinner RTC, as for instance found in the H616 SoC, no longer store a broken-down day/month/year representation in the RTC_DAY_REG, but just a linear day number. The user manual does not give any indication about the expected epoch time of this day count, but the BSP kernel uses the UNIX epoch, which allows easy support due to existing conversion functions in the kernel. Allow tagging a compatible string with a flag, and use that to mark those new RTCs. Then convert between a UNIX day number (converted into seconds) and the broken-down day representation using mktime64() and time64_to_tm() in the set_time/get_time functions. That enables support for the RTC in those new chips. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec --- drivers/rtc/rtc-sun6i.c | 69 +++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index dc3ae851841c..996d05938839 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -111,6 +111,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: * @@ -134,12 +136,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; time64_t alarm; + unsigned long flags; struct clk_hw hw; struct clk_hw *int_osc; @@ -468,22 +473,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; } @@ -568,20 +581,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)) { @@ -714,6 +732,8 @@ static int sun6i_rtc_probe(struct platform_device *pdev) 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; @@ -760,7 +780,10 @@ 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) -- 2.25.1