30
30
#define RS5C372_REG_TRIM 7
31
31
# define RS5C372_TRIM_XSL 0x80
32
32
# define RS5C372_TRIM_MASK 0x7F
33
+ # define R2221TL_TRIM_DEV (1 << 7) /* only if R2221TL */
34
+ # define RS5C372_TRIM_DECR (1 << 6)
33
35
34
36
#define RS5C_REG_ALARM_A_MIN 8 /* or ALARM_W */
35
37
#define RS5C_REG_ALARM_A_HOURS 9
@@ -539,6 +541,122 @@ static int rs5c372_ioctl(struct device *dev, unsigned int cmd, unsigned long arg
539
541
#define rs5c372_ioctl NULL
540
542
#endif
541
543
544
+ static int rs5c372_read_offset (struct device * dev , long * offset )
545
+ {
546
+ struct rs5c372 * rs5c = i2c_get_clientdata (to_i2c_client (dev ));
547
+ u8 val = rs5c -> regs [RS5C372_REG_TRIM ];
548
+ long ppb_per_step = 0 ;
549
+ bool decr = val & RS5C372_TRIM_DECR ;
550
+
551
+ switch (rs5c -> type ) {
552
+ case rtc_r2221tl :
553
+ ppb_per_step = val & R2221TL_TRIM_DEV ? 1017 : 3051 ;
554
+ break ;
555
+ case rtc_rs5c372a :
556
+ case rtc_rs5c372b :
557
+ ppb_per_step = val & RS5C372_TRIM_XSL ? 3125 : 3051 ;
558
+ break ;
559
+ default :
560
+ ppb_per_step = 3051 ;
561
+ break ;
562
+ }
563
+
564
+ /* Only bits[0:5] repsents the time counts */
565
+ val &= 0x3F ;
566
+
567
+ /* If bits[1:5] are all 0, it means no increment or decrement */
568
+ if (!(val & 0x3E )) {
569
+ * offset = 0 ;
570
+ } else {
571
+ if (decr )
572
+ * offset = - (((~val ) & 0x3F ) + 1 ) * ppb_per_step ;
573
+ else
574
+ * offset = (val - 1 ) * ppb_per_step ;
575
+ }
576
+
577
+ return 0 ;
578
+ }
579
+
580
+ static int rs5c372_set_offset (struct device * dev , long offset )
581
+ {
582
+ struct rs5c372 * rs5c = i2c_get_clientdata (to_i2c_client (dev ));
583
+ int addr = RS5C_ADDR (RS5C372_REG_TRIM );
584
+ u8 val = 0 ;
585
+ u8 tmp = 0 ;
586
+ long ppb_per_step = 3051 ;
587
+ long steps = LONG_MIN ;
588
+
589
+ switch (rs5c -> type ) {
590
+ case rtc_rs5c372a :
591
+ case rtc_rs5c372b :
592
+ tmp = rs5c -> regs [RS5C372_REG_TRIM ];
593
+ if (tmp & RS5C372_TRIM_XSL ) {
594
+ ppb_per_step = 3125 ;
595
+ val |= RS5C372_TRIM_XSL ;
596
+ }
597
+ break ;
598
+ case rtc_r2221tl :
599
+ /*
600
+ * Check if it is possible to use high resolution mode (DEV=1).
601
+ * In this mode, the minimum resolution is 2 / (32768 * 20 * 3),
602
+ * which is about 1017 ppb.
603
+ */
604
+ steps = DIV_ROUND_CLOSEST (offset , 1017 );
605
+ if (steps >= -0x3E && steps <= 0x3E ) {
606
+ ppb_per_step = 1017 ;
607
+ val |= R2221TL_TRIM_DEV ;
608
+ } else {
609
+ /*
610
+ * offset is out of the range of high resolution mode.
611
+ * Try to use low resolution mode (DEV=0). In this mode,
612
+ * the minimum resolution is 2 / (32768 * 20), which is
613
+ * about 3051 ppb.
614
+ */
615
+ steps = LONG_MIN ;
616
+ }
617
+ break ;
618
+ default :
619
+ break ;
620
+ }
621
+
622
+ if (steps == LONG_MIN ) {
623
+ steps = DIV_ROUND_CLOSEST (offset , ppb_per_step );
624
+ if (steps > 0x3E || steps < -0x3E )
625
+ return - ERANGE ;
626
+ }
627
+
628
+ if (steps > 0 ) {
629
+ val |= steps + 1 ;
630
+ } else {
631
+ val |= RS5C372_TRIM_DECR ;
632
+ val |= (~(- steps - 1 )) & 0x3F ;
633
+ }
634
+
635
+ if (!steps || !(val & 0x3E )) {
636
+ /*
637
+ * if offset is too small, set oscillation adjustment register
638
+ * or time trimming register with its default value whic means
639
+ * no increment or decrement. But for rs5c372[a|b], the XSL bit
640
+ * should be kept unchanged.
641
+ */
642
+ if (rs5c -> type == rtc_rs5c372a || rs5c -> type == rtc_rs5c372b )
643
+ val &= RS5C372_TRIM_XSL ;
644
+ else
645
+ val = 0 ;
646
+ }
647
+
648
+ dev_dbg (& rs5c -> client -> dev , "write 0x%x for offset %ld\n" , val , offset );
649
+
650
+ if (i2c_smbus_write_byte_data (rs5c -> client , addr , val ) < 0 ) {
651
+ dev_err (& rs5c -> client -> dev , "failed to write 0x%x to reg %d\n" , val , addr );
652
+ return - EIO ;
653
+ }
654
+
655
+ rs5c -> regs [RS5C372_REG_TRIM ] = val ;
656
+
657
+ return 0 ;
658
+ }
659
+
542
660
static const struct rtc_class_ops rs5c372_rtc_ops = {
543
661
.proc = rs5c372_rtc_proc ,
544
662
.read_time = rs5c372_rtc_read_time ,
@@ -547,6 +665,8 @@ static const struct rtc_class_ops rs5c372_rtc_ops = {
547
665
.set_alarm = rs5c_set_alarm ,
548
666
.alarm_irq_enable = rs5c_rtc_alarm_irq_enable ,
549
667
.ioctl = rs5c372_ioctl ,
668
+ .read_offset = rs5c372_read_offset ,
669
+ .set_offset = rs5c372_set_offset ,
550
670
};
551
671
552
672
#if IS_ENABLED (CONFIG_RTC_INTF_SYSFS )
0 commit comments