Skip to content

Commit f18ad40

Browse files
diogo-ivodavem330
authored andcommitted
net: ti: icss-iep: Enable compare events
The IEP module supports compare events, in which a value is written to a hardware register and when the IEP counter reaches the written value an interrupt is generated. Add handling for this interrupt in order to support PPS events. Reviewed-by: Wojciech Drewek <[email protected]> Reviewed-by: Jacob Keller <[email protected]> Signed-off-by: Diogo Ivo <[email protected]> Reviewed-by: Simon Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5056860 commit f18ad40

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

drivers/net/ethernet/ti/icssg/icss_iep.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/timekeeping.h>
1818
#include <linux/interrupt.h>
1919
#include <linux/of_irq.h>
20+
#include <linux/workqueue.h>
2021

2122
#include "icss_iep.h"
2223

@@ -121,6 +122,7 @@ struct icss_iep {
121122
int cap_cmp_irq;
122123
u64 period;
123124
u32 latch_enable;
125+
struct work_struct work;
124126
};
125127

126128
/**
@@ -563,6 +565,57 @@ static int icss_iep_perout_enable(struct icss_iep *iep,
563565
return ret;
564566
}
565567

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+
566619
static int icss_iep_pps_enable(struct icss_iep *iep, int on)
567620
{
568621
struct ptp_clock_request rq;
@@ -591,6 +644,8 @@ static int icss_iep_pps_enable(struct icss_iep *iep, int on)
591644
ret = icss_iep_perout_enable_hw(iep, &rq.perout, on);
592645
} else {
593646
ret = icss_iep_perout_enable_hw(iep, &rq.perout, on);
647+
if (iep->cap_cmp_irq)
648+
cancel_work_sync(&iep->work);
594649
}
595650

596651
if (!ret)
@@ -764,6 +819,8 @@ int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops,
764819
if (iep->ops && iep->ops->perout_enable) {
765820
iep->ptp_info.n_per_out = 1;
766821
iep->ptp_info.pps = 1;
822+
} else if (iep->cap_cmp_irq) {
823+
iep->ptp_info.pps = 1;
767824
}
768825

769826
if (iep->ops && iep->ops->extts_enable)
@@ -804,6 +861,7 @@ static int icss_iep_probe(struct platform_device *pdev)
804861
struct device *dev = &pdev->dev;
805862
struct icss_iep *iep;
806863
struct clk *iep_clk;
864+
int ret, irq;
807865

808866
iep = devm_kzalloc(dev, sizeof(*iep), GFP_KERNEL);
809867
if (!iep)
@@ -814,6 +872,22 @@ static int icss_iep_probe(struct platform_device *pdev)
814872
if (IS_ERR(iep->base))
815873
return -ENODEV;
816874

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+
817891
iep_clk = devm_clk_get(dev, NULL);
818892
if (IS_ERR(iep_clk))
819893
return PTR_ERR(iep_clk);

0 commit comments

Comments
 (0)