Received: by 2002:a05:6a10:9848:0:0:0:0 with SMTP id x8csp3164031pxf; Sun, 28 Mar 2021 14:33:16 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxyKKiA/VqXt2LM8nynQzvt23r/SuZF9cdmfrE0VTzcj5VpzS1xWof9rn3FNuiQrq5HBdZj X-Received: by 2002:a17:906:c102:: with SMTP id do2mr25737361ejc.305.1616967196490; Sun, 28 Mar 2021 14:33:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1616967196; cv=none; d=google.com; s=arc-20160816; b=pH9wkcYt3H9+rx6rongsXGiGPQG/zSDNqkalP5nyHv5d9PUOtLxQs9709Pb/z+wxI6 iw/Qll2MLPyg12QsUpKlcmuNxomiz7hHjtIU9oie1kwFAYEbsL4BXpt9xDANFXGrFrO8 gTae6X2WCB57mKpRBauqwRx7WkrWnb2ljohNICtk0nISobv6/1ZU3S1GjWX7BJ0ZYOrw y4sXbDTHVPNz7Y1JgUKPtZcwBOyv+ldgB8Sywko/b6LW20JDVjU6yZeGLSbuoxCFQkDt oFjwKFht2QEsf80HeQaT2aC8HO0RhP34KvTTY50eFUhcQPXVkpBtHYg/L4AjjwSue50w fy9A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from; bh=EZjU+sKTq5IQrLKyCycojMN3CuG6T7PyOJmKZVsCrNA=; b=y5VNqzQoH6b91AYeO42ou0u3Gc4KH5wwpu47TIfo1jGu88sohkafXjZSBGSdy+0L7L ejEN/x40DTBY4leVz5U5m3IZus1/gT2wQC9d6dxhKJz7Zg8UjukB/ZmlSflDZe87F9Qf cvWB0Jh8aIRL6R3aoAdXnX8VioqANP0xTqmOZRPxuWNlMr5cksa1BvZ5KYyqZL5Vjv0X j1mCt/CQwbeCPpl0i5FwJoNf+rnO6ujsgidkLIOoRwdVy38GDnh0jgWcW76UxIfVHiiG WqCZr8HMpcr8tN62aPY3CWoZXTBiZHA8SEYNOfwRNlrxk3HCYlZ+Z6eX+9tAUZhaVxFX E+DA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id rl3si12093352ejb.86.2021.03.28.14.32.53; Sun, 28 Mar 2021 14:33:16 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231579AbhC1V3i (ORCPT + 99 others); Sun, 28 Mar 2021 17:29:38 -0400 Received: from clab.compulab.co.il ([66.147.238.35]:44336 "EHLO clab.compulab.co.il" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231349AbhC1V33 (ORCPT ); Sun, 28 Mar 2021 17:29:29 -0400 Received: from [37.142.126.90] (port=46500 helo=zimbra01.compulab.co.il) by clab.compulab.co.il with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94) (envelope-from ) id 1lQcYh-0033P1-1w; Sun, 28 Mar 2021 17:02:55 -0400 Received: from localhost (localhost [127.0.0.1]) by zimbra01.compulab.co.il (Postfix) with ESMTP id D6D0AE81CB017; Mon, 29 Mar 2021 00:02:53 +0300 (IDT) Received: from zimbra01.compulab.co.il ([127.0.0.1]) by localhost (zimbra01.compulab.co.il [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id Iwfr1OyVmwMC; Mon, 29 Mar 2021 00:02:53 +0300 (IDT) Received: from localhost (localhost [127.0.0.1]) by zimbra01.compulab.co.il (Postfix) with ESMTP id 89B52E81CB001; Mon, 29 Mar 2021 00:02:53 +0300 (IDT) X-Virus-Scanned: amavisd-new at zimbra01.compulab.co.il Received: from zimbra01.compulab.co.il ([127.0.0.1]) by localhost (zimbra01.compulab.co.il [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id ZQH0TALIweh9; Mon, 29 Mar 2021 00:02:53 +0300 (IDT) Received: from kkk.compulab.local (lifshitz-linux.compulab.local [192.168.11.10]) by zimbra01.compulab.co.il (Postfix) with ESMTP id 7818FE81CB017; Mon, 29 Mar 2021 00:02:53 +0300 (IDT) From: Kirill Kapranov To: a.zummo@towertech.it, alexandre.belloni@bootlin.com, phdm@macqel.be, linux-rtc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Kirill Kapranov Subject: [PATCH 4/4] rtc:abx80x: Enable xt digital calibration Date: Mon, 29 Mar 2021 00:02:32 +0300 Message-Id: <20210328210232.10395-5-kirill.kapranov@compulab.co.il> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20210328210232.10395-1-kirill.kapranov@compulab.co.il> References: <20210328210232.10395-1-kirill.kapranov@compulab.co.il> X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - clab.compulab.co.il X-AntiAbuse: Original Domain - vger.kernel.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - compulab.co.il X-Get-Message-Sender-Via: clab.compulab.co.il: mailgid no entry from get_recent_authed_mail_ips_entry X-Authenticated-Sender: clab.compulab.co.il: X-Source: X-Source-Args: X-Source-Dir: Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The XT digital calibration feature allows to improve the RTC accuracy, using a Distributed Digital Calibration function. See ch. 5.9.1 of AB08XX Series Ultra Low Power RTC IC User's Guide https://abracon.com/realtimeclock/AB08XX-Application-Manual.pdf Signed-off-by: Kirill Kapranov --- drivers/rtc/rtc-abx80x.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 153d89b56da9..e13fa88e87a5 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -54,6 +54,9 @@ #define ABX8XX_REG_SQW 0x13 #define ABX8XX_SQW_MODE_BITS 5 +#define ABX8XX_REG_CAL_XT 0x14 +#define ABX8XX_CAL_XT_OFFSETX_MASK GENMASK(6, 0) + #define ABX8XX_REG_CD_TIMER_CTL 0x18 #define ABX8XX_REG_OSC 0x1c @@ -120,6 +123,22 @@ struct abx80x_priv { struct watchdog_device wdog; }; +union abx8xx_reg_cal_xt { + struct { + int offsetx:7; + unsigned int cmdx:1; + }; + int val; +} __packed; + +union abx8xx_reg_oss { + struct { + int:6; + unsigned int xtcal:2; + }; + int val; +} __packed; + union abx8xx_reg_sqw { struct { unsigned int sqws:5; @@ -498,6 +517,123 @@ static ssize_t oscillator_show(struct device *dev, static DEVICE_ATTR_RW(oscillator); +static const int xt_freq_nom = 32768000; //Nominal XT frequency 32 kHz in mHz + +static int xt_frequency_set(struct i2c_client *client, u32 xt_freq) +{ + int retval; + long Adj; + union abx8xx_reg_cal_xt reg_cal_xt; + union abx8xx_reg_oss reg_oss; + + retval = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); + if (retval < 0) + goto err; + reg_oss.val = retval; + + Adj = (xt_freq_nom - (int)xt_freq) * 16 / 1000; + if (Adj < -320) { + dev_err(&client->dev, + "The XT oscillator is too fast to be adjusted\n"); + return -ERANGE; + } else if (Adj < -256) { + reg_oss.xtcal = 3; + reg_cal_xt.cmdx = 1; + reg_cal_xt.offsetx = (Adj + 192) / 2; + } else if (Adj < -192) { + reg_oss.xtcal = 3; + reg_cal_xt.cmdx = 0; + reg_cal_xt.offsetx = Adj + 192; + } else if (Adj < -128) { + reg_oss.xtcal = 2; + reg_cal_xt.cmdx = 0; + reg_cal_xt.offsetx = Adj + 128; + } else if (Adj < -64) { + reg_oss.xtcal = 1; + reg_cal_xt.cmdx = 0; + reg_cal_xt.offsetx = Adj + 64; + } else if (Adj < 64) { + reg_oss.xtcal = 0; + reg_cal_xt.cmdx = 0; + reg_cal_xt.offsetx = Adj; + } else if (Adj < 128) { + reg_oss.xtcal = 0; + reg_cal_xt.cmdx = 1; + reg_cal_xt.offsetx = Adj / 2; + } else { + dev_err(&client->dev, + "The XT oscillator is too slow to be adjusted\n"); + return -ERANGE; + } + + retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSS, + reg_oss.val); + if (retval < 0) + goto err; + + retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_CAL_XT, + reg_cal_xt.val); + if (retval < 0) + goto err; + + return 0; +err: + dev_err(&client->dev, "Failed to access calibration data\n"); + return retval; +} + +static ssize_t xt_frequency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + unsigned long xt_freq; + + retval = kstrtoul(buf, 10, &xt_freq); + if (retval < 0) { + dev_err(dev, "Invalid value of oscillator frequency\n"); + return -EINVAL; + } + + dev_info(dev, "Computed xt osc drift is %li ppm\n", + 1000000l * ((long)xt_freq - xt_freq_nom) / xt_freq_nom); + + retval = xt_frequency_set(to_i2c_client(dev->parent), xt_freq); + if (retval) + return retval; + return count; +} + +static DEVICE_ATTR_WO(xt_frequency); + +static ssize_t xt_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int retval; + union abx8xx_reg_cal_xt reg_cal_xt; + union abx8xx_reg_oss reg_oss; + struct i2c_client *client = to_i2c_client(dev->parent); + + retval = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); + if (retval < 0) + goto err; + reg_oss.val = retval; + + retval = i2c_smbus_read_byte_data(client, ABX8XX_REG_CAL_XT); + if (retval < 0) + goto err; + reg_cal_xt.val = retval; + + return sprintf(buf, "XTCAL %x\nCMDX %x\nOFFSETX %i = 0x%lx\n", + reg_oss.xtcal, reg_cal_xt.cmdx, reg_cal_xt.offsetx, + reg_cal_xt.offsetx & ABX8XX_CAL_XT_OFFSETX_MASK); +err: + dev_err(dev, "Failed to read calibration data\n"); + sprintf(buf, "\n"); + return retval; +} +static DEVICE_ATTR_RO(xt_calibration); + #define SQFS_COUNT (1 << ABX8XX_SQW_MODE_BITS) /* The index of the array is the value to be written to the 'Square Wave Function * Select' register to make the RTC generate the required square wave. @@ -611,6 +747,8 @@ static struct attribute *rtc_calib_attrs[] = { &dev_attr_autocalibration.attr, &dev_attr_oscillator.attr, &dev_attr_sqw.attr, + &dev_attr_xt_calibration.attr, + &dev_attr_xt_frequency.attr, NULL, }; @@ -809,6 +947,7 @@ static int abx80x_probe(struct i2c_client *client, unsigned int wafer; unsigned int uid; const char *sqw_mode_name; + unsigned int xt_freq; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -923,6 +1062,12 @@ static int abx80x_probe(struct i2c_client *client, abx80x_enable_trickle_charger(client, trickle_cfg); } + if (!of_property_read_u32(np, "xt-frequency", &xt_freq)) { + dev_info(&client->dev, "Calibrate XT %d mHz:\n", + xt_freq); + xt_frequency_set(client, xt_freq); + } + if (!of_property_read_string(np, "sqw", &sqw_mode_name)) sqw_set(client, sqw_mode_name); -- 2.11.0