|
@@ -549,6 +549,37 @@ static void fec_time_keep(struct work_struct *work)
|
|
|
schedule_delayed_work(&fep->time_keep, HZ);
|
|
|
}
|
|
|
|
|
|
+/* This function checks the pps event and reloads the timer compare counter. */
|
|
|
+static irqreturn_t fec_pps_interrupt(int irq, void *dev_id)
|
|
|
+{
|
|
|
+ struct net_device *ndev = dev_id;
|
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
|
+ u32 val;
|
|
|
+ u8 channel = fep->pps_channel;
|
|
|
+ struct ptp_clock_event event;
|
|
|
+
|
|
|
+ val = readl(fep->hwp + FEC_TCSR(channel));
|
|
|
+ if (val & FEC_T_TF_MASK) {
|
|
|
+ /* Write the next next compare(not the next according the spec)
|
|
|
+ * value to the register
|
|
|
+ */
|
|
|
+ writel(fep->next_counter, fep->hwp + FEC_TCCR(channel));
|
|
|
+ do {
|
|
|
+ writel(val, fep->hwp + FEC_TCSR(channel));
|
|
|
+ } while (readl(fep->hwp + FEC_TCSR(channel)) & FEC_T_TF_MASK);
|
|
|
+
|
|
|
+ /* Update the counter; */
|
|
|
+ fep->next_counter = (fep->next_counter + fep->reload_period) &
|
|
|
+ fep->cc.mask;
|
|
|
+
|
|
|
+ event.type = PTP_CLOCK_PPS;
|
|
|
+ ptp_clock_event(fep->ptp_clock, &event);
|
|
|
+ return IRQ_HANDLED;
|
|
|
+ }
|
|
|
+
|
|
|
+ return IRQ_NONE;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* fec_ptp_init
|
|
|
* @ndev: The FEC network adapter
|
|
@@ -558,10 +589,12 @@ static void fec_time_keep(struct work_struct *work)
|
|
|
* cyclecounter init routine and exits.
|
|
|
*/
|
|
|
|
|
|
-void fec_ptp_init(struct platform_device *pdev)
|
|
|
+void fec_ptp_init(struct platform_device *pdev, int irq_idx)
|
|
|
{
|
|
|
struct net_device *ndev = platform_get_drvdata(pdev);
|
|
|
struct fec_enet_private *fep = netdev_priv(ndev);
|
|
|
+ int irq;
|
|
|
+ int ret;
|
|
|
|
|
|
fep->ptp_caps.owner = THIS_MODULE;
|
|
|
snprintf(fep->ptp_caps.name, 16, "fec ptp");
|
|
@@ -587,6 +620,20 @@ void fec_ptp_init(struct platform_device *pdev)
|
|
|
|
|
|
INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep);
|
|
|
|
|
|
+ irq = platform_get_irq_byname(pdev, "pps");
|
|
|
+ if (irq < 0)
|
|
|
+ irq = platform_get_irq(pdev, irq_idx);
|
|
|
+ /* Failure to get an irq is not fatal,
|
|
|
+ * only the PTP_CLOCK_PPS clock events should stop
|
|
|
+ */
|
|
|
+ if (irq >= 0) {
|
|
|
+ ret = devm_request_irq(&pdev->dev, irq, fec_pps_interrupt,
|
|
|
+ 0, pdev->name, ndev);
|
|
|
+ if (ret < 0)
|
|
|
+ dev_warn(&pdev->dev, "request for pps irq failed(%d)\n",
|
|
|
+ ret);
|
|
|
+ }
|
|
|
+
|
|
|
fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev);
|
|
|
if (IS_ERR(fep->ptp_clock)) {
|
|
|
fep->ptp_clock = NULL;
|
|
@@ -605,36 +652,3 @@ void fec_ptp_stop(struct platform_device *pdev)
|
|
|
if (fep->ptp_clock)
|
|
|
ptp_clock_unregister(fep->ptp_clock);
|
|
|
}
|
|
|
-
|
|
|
-/**
|
|
|
- * fec_ptp_check_pps_event
|
|
|
- * @fep: the fec_enet_private structure handle
|
|
|
- *
|
|
|
- * This function check the pps event and reload the timer compare counter.
|
|
|
- */
|
|
|
-uint fec_ptp_check_pps_event(struct fec_enet_private *fep)
|
|
|
-{
|
|
|
- u32 val;
|
|
|
- u8 channel = fep->pps_channel;
|
|
|
- struct ptp_clock_event event;
|
|
|
-
|
|
|
- val = readl(fep->hwp + FEC_TCSR(channel));
|
|
|
- if (val & FEC_T_TF_MASK) {
|
|
|
- /* Write the next next compare(not the next according the spec)
|
|
|
- * value to the register
|
|
|
- */
|
|
|
- writel(fep->next_counter, fep->hwp + FEC_TCCR(channel));
|
|
|
- do {
|
|
|
- writel(val, fep->hwp + FEC_TCSR(channel));
|
|
|
- } while (readl(fep->hwp + FEC_TCSR(channel)) & FEC_T_TF_MASK);
|
|
|
-
|
|
|
- /* Update the counter; */
|
|
|
- fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask;
|
|
|
-
|
|
|
- event.type = PTP_CLOCK_PPS;
|
|
|
- ptp_clock_event(fep->ptp_clock, &event);
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|