17
17
#include <linux/timekeeping.h>
18
18
#include <linux/interrupt.h>
19
19
#include <linux/of_irq.h>
20
+ #include <linux/workqueue.h>
20
21
21
22
#include "icss_iep.h"
22
23
@@ -121,6 +122,7 @@ struct icss_iep {
121
122
int cap_cmp_irq ;
122
123
u64 period ;
123
124
u32 latch_enable ;
125
+ struct work_struct work ;
124
126
};
125
127
126
128
/**
@@ -563,6 +565,57 @@ static int icss_iep_perout_enable(struct icss_iep *iep,
563
565
return ret ;
564
566
}
565
567
568
+ static void icss_iep_cap_cmp_work (struct work_struct * work )
569
+ {
570
+ struct icss_iep * iep = container_of (work , struct icss_iep , work );
571
+ const u32 * reg_offs = iep -> plat_data -> reg_offs ;
572
+ struct ptp_clock_event pevent ;
573
+ unsigned int val ;
574
+ u64 ns , ns_next ;
575
+
576
+ mutex_lock (& iep -> ptp_clk_mutex );
577
+
578
+ ns = readl (iep -> base + reg_offs [ICSS_IEP_CMP1_REG0 ]);
579
+ if (iep -> plat_data -> flags & ICSS_IEP_64BIT_COUNTER_SUPPORT ) {
580
+ val = readl (iep -> base + reg_offs [ICSS_IEP_CMP1_REG1 ]);
581
+ ns |= (u64 )val << 32 ;
582
+ }
583
+ /* set next event */
584
+ ns_next = ns + iep -> period ;
585
+ writel (lower_32_bits (ns_next ),
586
+ iep -> base + reg_offs [ICSS_IEP_CMP1_REG0 ]);
587
+ if (iep -> plat_data -> flags & ICSS_IEP_64BIT_COUNTER_SUPPORT )
588
+ writel (upper_32_bits (ns_next ),
589
+ iep -> base + reg_offs [ICSS_IEP_CMP1_REG1 ]);
590
+
591
+ pevent .pps_times .ts_real = ns_to_timespec64 (ns );
592
+ pevent .type = PTP_CLOCK_PPSUSR ;
593
+ pevent .index = 0 ;
594
+ ptp_clock_event (iep -> ptp_clock , & pevent );
595
+ dev_dbg (iep -> dev , "IEP:pps ts: %llu next:%llu:\n" , ns , ns_next );
596
+
597
+ mutex_unlock (& iep -> ptp_clk_mutex );
598
+ }
599
+
600
+ static irqreturn_t icss_iep_cap_cmp_irq (int irq , void * dev_id )
601
+ {
602
+ struct icss_iep * iep = (struct icss_iep * )dev_id ;
603
+ const u32 * reg_offs = iep -> plat_data -> reg_offs ;
604
+ unsigned int val ;
605
+
606
+ val = readl (iep -> base + reg_offs [ICSS_IEP_CMP_STAT_REG ]);
607
+ /* The driver only enables CMP1 */
608
+ if (val & BIT (1 )) {
609
+ /* Clear the event */
610
+ writel (BIT (1 ), iep -> base + reg_offs [ICSS_IEP_CMP_STAT_REG ]);
611
+ if (iep -> pps_enabled || iep -> perout_enabled )
612
+ schedule_work (& iep -> work );
613
+ return IRQ_HANDLED ;
614
+ }
615
+
616
+ return IRQ_NONE ;
617
+ }
618
+
566
619
static int icss_iep_pps_enable (struct icss_iep * iep , int on )
567
620
{
568
621
struct ptp_clock_request rq ;
@@ -591,6 +644,8 @@ static int icss_iep_pps_enable(struct icss_iep *iep, int on)
591
644
ret = icss_iep_perout_enable_hw (iep , & rq .perout , on );
592
645
} else {
593
646
ret = icss_iep_perout_enable_hw (iep , & rq .perout , on );
647
+ if (iep -> cap_cmp_irq )
648
+ cancel_work_sync (& iep -> work );
594
649
}
595
650
596
651
if (!ret )
@@ -764,6 +819,8 @@ int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops,
764
819
if (iep -> ops && iep -> ops -> perout_enable ) {
765
820
iep -> ptp_info .n_per_out = 1 ;
766
821
iep -> ptp_info .pps = 1 ;
822
+ } else if (iep -> cap_cmp_irq ) {
823
+ iep -> ptp_info .pps = 1 ;
767
824
}
768
825
769
826
if (iep -> ops && iep -> ops -> extts_enable )
@@ -804,6 +861,7 @@ static int icss_iep_probe(struct platform_device *pdev)
804
861
struct device * dev = & pdev -> dev ;
805
862
struct icss_iep * iep ;
806
863
struct clk * iep_clk ;
864
+ int ret , irq ;
807
865
808
866
iep = devm_kzalloc (dev , sizeof (* iep ), GFP_KERNEL );
809
867
if (!iep )
@@ -814,6 +872,22 @@ static int icss_iep_probe(struct platform_device *pdev)
814
872
if (IS_ERR (iep -> base ))
815
873
return - ENODEV ;
816
874
875
+ irq = platform_get_irq_byname_optional (pdev , "iep_cap_cmp" );
876
+ if (irq == - EPROBE_DEFER )
877
+ return irq ;
878
+
879
+ if (irq > 0 ) {
880
+ ret = devm_request_irq (dev , irq , icss_iep_cap_cmp_irq ,
881
+ IRQF_TRIGGER_HIGH , "iep_cap_cmp" , iep );
882
+ if (ret ) {
883
+ dev_info (iep -> dev , "cap_cmp irq request failed: %x\n" ,
884
+ ret );
885
+ } else {
886
+ iep -> cap_cmp_irq = irq ;
887
+ INIT_WORK (& iep -> work , icss_iep_cap_cmp_work );
888
+ }
889
+ }
890
+
817
891
iep_clk = devm_clk_get (dev , NULL );
818
892
if (IS_ERR (iep_clk ))
819
893
return PTR_ERR (iep_clk );
0 commit comments