* [PATCH] rtc: zynqmp: Add calibration set and get support
@ 2021-07-14 8:08 Srinivas Neeli
2021-08-09 10:05 ` Srinivas Neeli
0 siblings, 1 reply; 6+ messages in thread
From: Srinivas Neeli @ 2021-07-14 8:08 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, michal.simek, sgoud, shubhraj
Cc: linux-rtc, linux-arm-kernel, linux-kernel, git, Srinivas Neeli
Zynqmp RTC controller has a calibration feature to compensate
time deviation due to input clock inaccuracy.
Set and get calibration API's are used for setting and getting
calibration value from the controller calibration register.
Signed-off-by: Srinivas Neeli <srinivas.neeli@xilinx.com>
---
drivers/rtc/rtc-zynqmp.c | 101 ++++++++++++++++++++++++++++++++-------
1 file changed, 84 insertions(+), 17 deletions(-)
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index f440bb52be92..718f60d42760 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -36,10 +36,16 @@
#define RTC_OSC_EN BIT(24)
#define RTC_BATT_EN BIT(31)
-#define RTC_CALIB_DEF 0x198233
+#define RTC_CALIB_DEF 0x8000
#define RTC_CALIB_MASK 0x1FFFFF
#define RTC_ALRM_MASK BIT(1)
#define RTC_MSEC 1000
+#define RTC_FR_MASK 0xF0000
+#define RTC_SEC_MAX_VAL 0xFFFFFFFF
+#define RTC_FR_MAX_TICKS 16
+#define RTC_OFFSET_MAX 150000
+#define RTC_OFFSET_MIN -150000
+#define RTC_PPB 1000000000LL
struct xlnx_rtc_dev {
struct rtc_device *rtc;
@@ -61,13 +67,6 @@ static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
*/
new_time = rtc_tm_to_time64(tm) + 1;
- /*
- * Writing into calibration register will clear the Tick Counter and
- * force the next second to be signaled exactly in 1 second period
- */
- xrtcdev->calibval &= RTC_CALIB_MASK;
- writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
-
writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR);
/*
@@ -174,14 +173,76 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
rtc_ctrl |= RTC_BATT_EN;
writel(rtc_ctrl, xrtcdev->reg_base + RTC_CTRL);
- /*
- * Based on crystal freq of 33.330 KHz
- * set the seconds counter and enable, set fractions counter
- * to default value suggested as per design spec
- * to correct RTC delay in frequency over period of time.
+ /* Update calibvalue */
+ xrtcdev->calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
+}
+
+static int xlnx_rtc_read_offset(struct device *dev, long *offset)
+{
+ struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
+ long offset_val = 0;
+ unsigned int tick_mult = RTC_PPB / (xrtcdev->calibval & RTC_TICK_MASK);
+
+ /* Offset with seconds ticks */
+ offset_val = xrtcdev->calibval & RTC_TICK_MASK;
+ offset_val = offset_val - RTC_CALIB_DEF;
+ offset_val = offset_val * tick_mult;
+
+ /* Offset with fractional ticks */
+ if (xrtcdev->calibval & RTC_FR_EN)
+ offset_val += ((xrtcdev->calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
+ * (tick_mult / RTC_FR_MAX_TICKS);
+ *offset = offset_val;
+
+ return 0;
+}
+
+static int xlnx_rtc_set_offset(struct device *dev, long offset)
+{
+ struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
+ short int max_tick;
+ unsigned char fract_tick = 0;
+ unsigned int calibval;
+ int fract_offset;
+ unsigned int tick_mult = RTC_PPB / (xrtcdev->calibval & RTC_TICK_MASK);
+
+ /* Make sure offset value is within supported range */
+ if (offset < RTC_OFFSET_MIN || offset > RTC_OFFSET_MAX)
+ return -ERANGE;
+
+ /* Number ticks for given offset */
+ max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
+
+ /* Number fractional ticks for given offset */
+ if (fract_offset) {
+ if (fract_offset < 0) {
+ fract_offset = fract_offset + tick_mult;
+ max_tick--;
+ }
+ if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
+ for (fract_tick = 1; fract_tick < 16; fract_tick++) {
+ if (fract_offset <=
+ (fract_tick *
+ (tick_mult / RTC_FR_MAX_TICKS)))
+ break;
+ }
+ }
+ }
+
+ /* Zynqmp RTC uses second and fractional tick
+ * counters for compensation
*/
- xrtcdev->calibval &= RTC_CALIB_MASK;
- writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
+ calibval = max_tick + RTC_CALIB_DEF;
+
+ if (fract_tick)
+ calibval |= RTC_FR_EN;
+
+ calibval |= (fract_tick << RTC_FR_DATSHIFT);
+
+ writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
+ xrtcdev->calibval = calibval;
+
+ return 0;
}
static const struct rtc_class_ops xlnx_rtc_ops = {
@@ -190,6 +251,8 @@ static const struct rtc_class_ops xlnx_rtc_ops = {
.read_alarm = xlnx_rtc_read_alarm,
.set_alarm = xlnx_rtc_set_alarm,
.alarm_irq_enable = xlnx_rtc_alarm_irq_enable,
+ .read_offset = xlnx_rtc_read_offset,
+ .set_offset = xlnx_rtc_set_offset,
};
static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
@@ -215,6 +278,7 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
{
struct xlnx_rtc_dev *xrtcdev;
int ret;
+ unsigned int calibval;
xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
if (!xrtcdev)
@@ -256,9 +320,12 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(pdev->dev.of_node, "calibration",
- &xrtcdev->calibval);
+ &calibval);
if (ret)
- xrtcdev->calibval = RTC_CALIB_DEF;
+ calibval = RTC_CALIB_DEF;
+ ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
+ if (!ret)
+ writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
xlnx_init_rtc(xrtcdev);
--
2.31.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* RE: [PATCH] rtc: zynqmp: Add calibration set and get support
2021-07-14 8:08 [PATCH] rtc: zynqmp: Add calibration set and get support Srinivas Neeli
@ 2021-08-09 10:05 ` Srinivas Neeli
0 siblings, 0 replies; 6+ messages in thread
From: Srinivas Neeli @ 2021-08-09 10:05 UTC (permalink / raw)
To: Srinivas Neeli, a.zummo, alexandre.belloni, Michal Simek,
Srinivas Goud, Shubhrajyoti Datta
Cc: linux-rtc, linux-arm-kernel, linux-kernel, git
Hi,
Is this patch fine?
Thanks
Srinivas Neeli
> -----Original Message-----
> From: Srinivas Neeli <srinivas.neeli@xilinx.com>
> Sent: Wednesday, July 14, 2021 1:38 PM
> To: a.zummo@towertech.it; alexandre.belloni@bootlin.com; Michal Simek
> <michals@xilinx.com>; Srinivas Goud <sgoud@xilinx.com>; Shubhrajyoti
> Datta <shubhraj@xilinx.com>
> Cc: linux-rtc@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-
> kernel@vger.kernel.org; git <git@xilinx.com>; Srinivas Neeli
> <sneeli@xilinx.com>
> Subject: [PATCH] rtc: zynqmp: Add calibration set and get support
>
> Zynqmp RTC controller has a calibration feature to compensate time
> deviation due to input clock inaccuracy.
> Set and get calibration API's are used for setting and getting calibration value
> from the controller calibration register.
>
> Signed-off-by: Srinivas Neeli <srinivas.neeli@xilinx.com>
> ---
> drivers/rtc/rtc-zynqmp.c | 101 ++++++++++++++++++++++++++++++++----
> ---
> 1 file changed, 84 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
> f440bb52be92..718f60d42760 100644
> --- a/drivers/rtc/rtc-zynqmp.c
> +++ b/drivers/rtc/rtc-zynqmp.c
> @@ -36,10 +36,16 @@
> #define RTC_OSC_EN BIT(24)
> #define RTC_BATT_EN BIT(31)
>
> -#define RTC_CALIB_DEF 0x198233
> +#define RTC_CALIB_DEF 0x8000
> #define RTC_CALIB_MASK 0x1FFFFF
> #define RTC_ALRM_MASK BIT(1)
> #define RTC_MSEC 1000
> +#define RTC_FR_MASK 0xF0000
> +#define RTC_SEC_MAX_VAL 0xFFFFFFFF
> +#define RTC_FR_MAX_TICKS 16
> +#define RTC_OFFSET_MAX 150000
> +#define RTC_OFFSET_MIN -150000
> +#define RTC_PPB 1000000000LL
>
> struct xlnx_rtc_dev {
> struct rtc_device *rtc;
> @@ -61,13 +67,6 @@ static int xlnx_rtc_set_time(struct device *dev, struct
> rtc_time *tm)
> */
> new_time = rtc_tm_to_time64(tm) + 1;
>
> - /*
> - * Writing into calibration register will clear the Tick Counter and
> - * force the next second to be signaled exactly in 1 second period
> - */
> - xrtcdev->calibval &= RTC_CALIB_MASK;
> - writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> -
> writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR);
>
> /*
> @@ -174,14 +173,76 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev
> *xrtcdev)
> rtc_ctrl |= RTC_BATT_EN;
> writel(rtc_ctrl, xrtcdev->reg_base + RTC_CTRL);
>
> - /*
> - * Based on crystal freq of 33.330 KHz
> - * set the seconds counter and enable, set fractions counter
> - * to default value suggested as per design spec
> - * to correct RTC delay in frequency over period of time.
> + /* Update calibvalue */
> + xrtcdev->calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD); }
> +
> +static int xlnx_rtc_read_offset(struct device *dev, long *offset) {
> + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> + long offset_val = 0;
> + unsigned int tick_mult = RTC_PPB / (xrtcdev->calibval &
> +RTC_TICK_MASK);
> +
> + /* Offset with seconds ticks */
> + offset_val = xrtcdev->calibval & RTC_TICK_MASK;
> + offset_val = offset_val - RTC_CALIB_DEF;
> + offset_val = offset_val * tick_mult;
> +
> + /* Offset with fractional ticks */
> + if (xrtcdev->calibval & RTC_FR_EN)
> + offset_val += ((xrtcdev->calibval & RTC_FR_MASK) >>
> RTC_FR_DATSHIFT)
> + * (tick_mult / RTC_FR_MAX_TICKS);
> + *offset = offset_val;
> +
> + return 0;
> +}
> +
> +static int xlnx_rtc_set_offset(struct device *dev, long offset) {
> + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> + short int max_tick;
> + unsigned char fract_tick = 0;
> + unsigned int calibval;
> + int fract_offset;
> + unsigned int tick_mult = RTC_PPB / (xrtcdev->calibval &
> +RTC_TICK_MASK);
> +
> + /* Make sure offset value is within supported range */
> + if (offset < RTC_OFFSET_MIN || offset > RTC_OFFSET_MAX)
> + return -ERANGE;
> +
> + /* Number ticks for given offset */
> + max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
> +
> + /* Number fractional ticks for given offset */
> + if (fract_offset) {
> + if (fract_offset < 0) {
> + fract_offset = fract_offset + tick_mult;
> + max_tick--;
> + }
> + if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
> + for (fract_tick = 1; fract_tick < 16; fract_tick++) {
> + if (fract_offset <=
> + (fract_tick *
> + (tick_mult / RTC_FR_MAX_TICKS)))
> + break;
> + }
> + }
> + }
> +
> + /* Zynqmp RTC uses second and fractional tick
> + * counters for compensation
> */
> - xrtcdev->calibval &= RTC_CALIB_MASK;
> - writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> + calibval = max_tick + RTC_CALIB_DEF;
> +
> + if (fract_tick)
> + calibval |= RTC_FR_EN;
> +
> + calibval |= (fract_tick << RTC_FR_DATSHIFT);
> +
> + writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> + xrtcdev->calibval = calibval;
> +
> + return 0;
> }
>
> static const struct rtc_class_ops xlnx_rtc_ops = { @@ -190,6 +251,8 @@
> static const struct rtc_class_ops xlnx_rtc_ops = {
> .read_alarm = xlnx_rtc_read_alarm,
> .set_alarm = xlnx_rtc_set_alarm,
> .alarm_irq_enable = xlnx_rtc_alarm_irq_enable,
> + .read_offset = xlnx_rtc_read_offset,
> + .set_offset = xlnx_rtc_set_offset,
> };
>
> static irqreturn_t xlnx_rtc_interrupt(int irq, void *id) @@ -215,6 +278,7 @@
> static int xlnx_rtc_probe(struct platform_device *pdev) {
> struct xlnx_rtc_dev *xrtcdev;
> int ret;
> + unsigned int calibval;
>
> xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev),
> GFP_KERNEL);
> if (!xrtcdev)
> @@ -256,9 +320,12 @@ static int xlnx_rtc_probe(struct platform_device
> *pdev)
> }
>
> ret = of_property_read_u32(pdev->dev.of_node, "calibration",
> - &xrtcdev->calibval);
> + &calibval);
> if (ret)
> - xrtcdev->calibval = RTC_CALIB_DEF;
> + calibval = RTC_CALIB_DEF;
> + ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
> + if (!ret)
> + writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
>
> xlnx_init_rtc(xrtcdev);
>
> --
> 2.31.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] rtc: zynqmp: Add calibration set and get support
2020-02-20 9:31 Srinivas Neeli
2020-02-24 11:16 ` Michal Simek
2020-02-25 1:19 ` kbuild test robot
@ 2020-02-27 11:45 ` Alexandre Belloni
2 siblings, 0 replies; 6+ messages in thread
From: Alexandre Belloni @ 2020-02-27 11:45 UTC (permalink / raw)
To: Srinivas Neeli
Cc: a.zummo, michal.simek, sgoud, shubhraj, linux-rtc,
linux-arm-kernel, linux-kernel, git, Srinivas Goud
Hi,
On 20/02/2020 15:01:46+0530, Srinivas Neeli wrote:
> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
> index 4b1077e2f826..b4118e9e4fcc 100644
> --- a/drivers/rtc/rtc-zynqmp.c
> +++ b/drivers/rtc/rtc-zynqmp.c
> @@ -40,6 +40,12 @@
> #define RTC_CALIB_MASK 0x1FFFFF
> #define RTC_ALRM_MASK BIT(1)
> #define RTC_MSEC 1000
> +#define RTC_FR_MASK 0xF0000
> +#define RTC_SEC_MAX_VAL 0xFFFFFFFF
This value is not used
> +#define RTC_FR_MAX_TICKS 16
> +#define RTC_OFFSET_MAX 150000
> +#define RTC_OFFSET_MIN -150000
> +#define RTC_PPB 1000000000LL
>
> struct xlnx_rtc_dev {
> struct rtc_device *rtc;
> @@ -184,12 +190,84 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
> writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> }
>
> +static int xlnx_rtc_read_offset(struct device *dev, long *offset)
> +{
> + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> + long offset_val;
> + unsigned int reg;
> + unsigned int tick_mult = RTC_PPB / xrtcdev->calibval;
> +
I don't get why you are not simply reusing xrtcdev->calibval. Using
.set_offset has to take precedence on any value that would have been set
using DT. Ideally, the DT binding should be removed too.
Currently, the calibration value is overwritten using the DT value
every time .set_time is called because xrtcdev->calibval is never
updated.
> + reg = readl(xrtcdev->reg_base + RTC_CALIB_RD);
> +
> + /* Offset with seconds ticks */
> + offset_val = reg & RTC_TICK_MASK;
> + offset_val = offset_val - xrtcdev->calibval;
> + offset_val = offset_val * tick_mult;
> +
> + /* Offset with fractional ticks */
> + if (reg & RTC_FR_EN)
> + offset_val += ((reg & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
> + * (tick_mult / RTC_FR_MAX_TICKS);
> + *offset = offset_val;
> +
> + return 0;
> +}
> +
> +static int xlnx_rtc_set_offset(struct device *dev, long offset)
> +{
> + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> + short int max_tick;
> + unsigned char fract_tick = 0;
> + unsigned int calibval;
> + int fract_offset;
> + unsigned int tick_mult = RTC_PPB / xrtcdev->calibval;
> +
> + /* Make sure offset value is within supported range */
> + if (offset < RTC_OFFSET_MIN || offset > RTC_OFFSET_MAX)
> + return -ERANGE;
> +
> + /* Number ticks for given offset */
> + max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
> +
> + /* Number fractional ticks for given offset */
> + if (fract_offset) {
> + if (fract_offset < 0) {
> + fract_offset = fract_offset + tick_mult;
> + max_tick--;
> + }
> + if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
> + for (fract_tick = 1; fract_tick < 16; fract_tick++) {
> + if (fract_offset <=
> + (fract_tick *
> + (tick_mult / RTC_FR_MAX_TICKS)))
> + break;
> + }
> + }
> + }
> +
> + /* Zynqmp RTC uses second and fractional tick
> + * counters for compensation
> + */
> + calibval = max_tick + xrtcdev->calibval;
> +
> + if (fract_tick)
> + calibval |= RTC_FR_EN;
> +
> + calibval |= (fract_tick << RTC_FR_DATSHIFT);
> +
> + writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> +
> + return 0;
> +}
> +
> static const struct rtc_class_ops xlnx_rtc_ops = {
> .set_time = xlnx_rtc_set_time,
> .read_time = xlnx_rtc_read_time,
> .read_alarm = xlnx_rtc_read_alarm,
> .set_alarm = xlnx_rtc_set_alarm,
> .alarm_irq_enable = xlnx_rtc_alarm_irq_enable,
> + .read_offset = xlnx_rtc_read_offset,
> + .set_offset = xlnx_rtc_set_offset,
> };
>
> static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
> --
> 2.7.4
>
--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] rtc: zynqmp: Add calibration set and get support
2020-02-20 9:31 Srinivas Neeli
2020-02-24 11:16 ` Michal Simek
@ 2020-02-25 1:19 ` kbuild test robot
2020-02-27 11:45 ` Alexandre Belloni
2 siblings, 0 replies; 6+ messages in thread
From: kbuild test robot @ 2020-02-25 1:19 UTC (permalink / raw)
To: Srinivas Neeli
Cc: kbuild-all, a.zummo, alexandre.belloni, michal.simek, sgoud,
shubhraj, linux-rtc, linux-arm-kernel, linux-kernel, git,
Srinivas Neeli, Srinivas Goud
[-- Attachment #1: Type: text/plain, Size: 2462 bytes --]
Hi Srinivas,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on abelloni/rtc-next]
[also build test ERROR on next-20200224]
[cannot apply to v5.6-rc3]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Srinivas-Neeli/rtc-zynqmp-Add-calibration-set-and-get-support/20200222-053755
base: https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git rtc-next
config: c6x-randconfig-a001-20200225 (attached as .config)
compiler: c6x-elf-gcc (GCC) 7.5.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.5.0 make.cross ARCH=c6x
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
drivers/rtc/rtc-zynqmp.o: In function `xlnx_rtc_read_offset':
>> drivers/rtc/rtc-zynqmp.c:198: undefined reference to `__c6xabi_divlli'
>> drivers/rtc/rtc-zynqmp.c:198: undefined reference to `__c6xabi_divlli'
drivers/rtc/rtc-zynqmp.o: In function `xlnx_rtc_set_offset':
drivers/rtc/rtc-zynqmp.c:223: undefined reference to `__c6xabi_divlli'
drivers/rtc/rtc-zynqmp.c:223: undefined reference to `__c6xabi_divlli'
vim +198 drivers/rtc/rtc-zynqmp.c
192
193 static int xlnx_rtc_read_offset(struct device *dev, long *offset)
194 {
195 struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
196 long offset_val;
197 unsigned int reg;
> 198 unsigned int tick_mult = RTC_PPB / xrtcdev->calibval;
199
200 reg = readl(xrtcdev->reg_base + RTC_CALIB_RD);
201
202 /* Offset with seconds ticks */
203 offset_val = reg & RTC_TICK_MASK;
204 offset_val = offset_val - xrtcdev->calibval;
205 offset_val = offset_val * tick_mult;
206
207 /* Offset with fractional ticks */
208 if (reg & RTC_FR_EN)
209 offset_val += ((reg & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
210 * (tick_mult / RTC_FR_MAX_TICKS);
211 *offset = offset_val;
212
213 return 0;
214 }
215
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 25953 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] rtc: zynqmp: Add calibration set and get support
2020-02-20 9:31 Srinivas Neeli
@ 2020-02-24 11:16 ` Michal Simek
2020-02-25 1:19 ` kbuild test robot
2020-02-27 11:45 ` Alexandre Belloni
2 siblings, 0 replies; 6+ messages in thread
From: Michal Simek @ 2020-02-24 11:16 UTC (permalink / raw)
To: Srinivas Neeli, a.zummo, alexandre.belloni, michal.simek, sgoud,
shubhraj
Cc: linux-rtc, linux-arm-kernel, linux-kernel, git, Srinivas Goud
On 20. 02. 20 10:31, Srinivas Neeli wrote:
> ZynqMp RTC controller has a calibration feature to compensate
> time deviation due to input clock inaccuracy.
> Set and get calibration API's are used for setting and getting
> calibration value from the controller calibration register.
>
> Signed-off-by: Srinivas Goud <srinivas.goud@xilinx.com>
> Signed-off-by: Srinivas Neeli <srinivas.neeli@xilinx.com>
> ---
> drivers/rtc/rtc-zynqmp.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 78 insertions(+)
>
> diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
> index 4b1077e2f826..b4118e9e4fcc 100644
> --- a/drivers/rtc/rtc-zynqmp.c
> +++ b/drivers/rtc/rtc-zynqmp.c
> @@ -40,6 +40,12 @@
> #define RTC_CALIB_MASK 0x1FFFFF
> #define RTC_ALRM_MASK BIT(1)
> #define RTC_MSEC 1000
> +#define RTC_FR_MASK 0xF0000
> +#define RTC_SEC_MAX_VAL 0xFFFFFFFF
> +#define RTC_FR_MAX_TICKS 16
> +#define RTC_OFFSET_MAX 150000
> +#define RTC_OFFSET_MIN -150000
> +#define RTC_PPB 1000000000LL
>
please use tabs here.
> struct xlnx_rtc_dev {
> struct rtc_device *rtc;
> @@ -184,12 +190,84 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
> writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> }
>
> +static int xlnx_rtc_read_offset(struct device *dev, long *offset)
> +{
> + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> + long offset_val;
> + unsigned int reg;
> + unsigned int tick_mult = RTC_PPB / xrtcdev->calibval;
> +
> + reg = readl(xrtcdev->reg_base + RTC_CALIB_RD);
> +
> + /* Offset with seconds ticks */
> + offset_val = reg & RTC_TICK_MASK;
> + offset_val = offset_val - xrtcdev->calibval;
> + offset_val = offset_val * tick_mult;
> +
> + /* Offset with fractional ticks */
> + if (reg & RTC_FR_EN)
> + offset_val += ((reg & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
> + * (tick_mult / RTC_FR_MAX_TICKS);
> + *offset = offset_val;
> +
> + return 0;
> +}
> +
> +static int xlnx_rtc_set_offset(struct device *dev, long offset)
> +{
> + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
> + short int max_tick;
> + unsigned char fract_tick = 0;
> + unsigned int calibval;
double space.
> + int fract_offset;
> + unsigned int tick_mult = RTC_PPB / xrtcdev->calibval;
> +
> + /* Make sure offset value is within supported range */
> + if (offset < RTC_OFFSET_MIN || offset > RTC_OFFSET_MAX)
> + return -ERANGE;
> +
> + /* Number ticks for given offset */
> + max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
> +
> + /* Number fractional ticks for given offset */
> + if (fract_offset) {
> + if (fract_offset < 0) {
> + fract_offset = fract_offset + tick_mult;
> + max_tick--;
> + }
> + if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
> + for (fract_tick = 1; fract_tick < 16; fract_tick++) {
> + if (fract_offset <=
> + (fract_tick *
> + (tick_mult / RTC_FR_MAX_TICKS)))
> + break;
> + }
> + }
> + }
> +
> + /* Zynqmp RTC uses second and fractional tick
> + * counters for compensation
> + */
> + calibval = max_tick + xrtcdev->calibval;
> +
> + if (fract_tick)
> + calibval |= RTC_FR_EN;
> +
> + calibval |= (fract_tick << RTC_FR_DATSHIFT);
here is double space.
> +
> + writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
> +
> + return 0;
> +}
> +
> static const struct rtc_class_ops xlnx_rtc_ops = {
> .set_time = xlnx_rtc_set_time,
> .read_time = xlnx_rtc_read_time,
> .read_alarm = xlnx_rtc_read_alarm,
> .set_alarm = xlnx_rtc_set_alarm,
> .alarm_irq_enable = xlnx_rtc_alarm_irq_enable,
> + .read_offset = xlnx_rtc_read_offset,
> + .set_offset = xlnx_rtc_set_offset,
use tabs as is done above.
> };
>
> static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
>
The rest looks good.
Thanks,
Michal
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] rtc: zynqmp: Add calibration set and get support
@ 2020-02-20 9:31 Srinivas Neeli
2020-02-24 11:16 ` Michal Simek
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Srinivas Neeli @ 2020-02-20 9:31 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, michal.simek, sgoud, shubhraj
Cc: linux-rtc, linux-arm-kernel, linux-kernel, git, Srinivas Neeli,
Srinivas Goud
ZynqMp RTC controller has a calibration feature to compensate
time deviation due to input clock inaccuracy.
Set and get calibration API's are used for setting and getting
calibration value from the controller calibration register.
Signed-off-by: Srinivas Goud <srinivas.goud@xilinx.com>
Signed-off-by: Srinivas Neeli <srinivas.neeli@xilinx.com>
---
drivers/rtc/rtc-zynqmp.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index 4b1077e2f826..b4118e9e4fcc 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -40,6 +40,12 @@
#define RTC_CALIB_MASK 0x1FFFFF
#define RTC_ALRM_MASK BIT(1)
#define RTC_MSEC 1000
+#define RTC_FR_MASK 0xF0000
+#define RTC_SEC_MAX_VAL 0xFFFFFFFF
+#define RTC_FR_MAX_TICKS 16
+#define RTC_OFFSET_MAX 150000
+#define RTC_OFFSET_MIN -150000
+#define RTC_PPB 1000000000LL
struct xlnx_rtc_dev {
struct rtc_device *rtc;
@@ -184,12 +190,84 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
}
+static int xlnx_rtc_read_offset(struct device *dev, long *offset)
+{
+ struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
+ long offset_val;
+ unsigned int reg;
+ unsigned int tick_mult = RTC_PPB / xrtcdev->calibval;
+
+ reg = readl(xrtcdev->reg_base + RTC_CALIB_RD);
+
+ /* Offset with seconds ticks */
+ offset_val = reg & RTC_TICK_MASK;
+ offset_val = offset_val - xrtcdev->calibval;
+ offset_val = offset_val * tick_mult;
+
+ /* Offset with fractional ticks */
+ if (reg & RTC_FR_EN)
+ offset_val += ((reg & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
+ * (tick_mult / RTC_FR_MAX_TICKS);
+ *offset = offset_val;
+
+ return 0;
+}
+
+static int xlnx_rtc_set_offset(struct device *dev, long offset)
+{
+ struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
+ short int max_tick;
+ unsigned char fract_tick = 0;
+ unsigned int calibval;
+ int fract_offset;
+ unsigned int tick_mult = RTC_PPB / xrtcdev->calibval;
+
+ /* Make sure offset value is within supported range */
+ if (offset < RTC_OFFSET_MIN || offset > RTC_OFFSET_MAX)
+ return -ERANGE;
+
+ /* Number ticks for given offset */
+ max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
+
+ /* Number fractional ticks for given offset */
+ if (fract_offset) {
+ if (fract_offset < 0) {
+ fract_offset = fract_offset + tick_mult;
+ max_tick--;
+ }
+ if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
+ for (fract_tick = 1; fract_tick < 16; fract_tick++) {
+ if (fract_offset <=
+ (fract_tick *
+ (tick_mult / RTC_FR_MAX_TICKS)))
+ break;
+ }
+ }
+ }
+
+ /* Zynqmp RTC uses second and fractional tick
+ * counters for compensation
+ */
+ calibval = max_tick + xrtcdev->calibval;
+
+ if (fract_tick)
+ calibval |= RTC_FR_EN;
+
+ calibval |= (fract_tick << RTC_FR_DATSHIFT);
+
+ writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
+
+ return 0;
+}
+
static const struct rtc_class_ops xlnx_rtc_ops = {
.set_time = xlnx_rtc_set_time,
.read_time = xlnx_rtc_read_time,
.read_alarm = xlnx_rtc_read_alarm,
.set_alarm = xlnx_rtc_set_alarm,
.alarm_irq_enable = xlnx_rtc_alarm_irq_enable,
+ .read_offset = xlnx_rtc_read_offset,
+ .set_offset = xlnx_rtc_set_offset,
};
static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
--
2.7.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2021-08-09 10:05 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-14 8:08 [PATCH] rtc: zynqmp: Add calibration set and get support Srinivas Neeli
2021-08-09 10:05 ` Srinivas Neeli
-- strict thread matches above, loose matches on Subject: below --
2020-02-20 9:31 Srinivas Neeli
2020-02-24 11:16 ` Michal Simek
2020-02-25 1:19 ` kbuild test robot
2020-02-27 11:45 ` Alexandre Belloni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).