@@ -491,9 +491,10 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
491491 int perout_pin = 0 ;
492492 unsigned int index = perout_request -> index ;
493493 struct lan743x_ptp_perout * perout = & ptp -> perout [index ];
494+ int ret = 0 ;
494495
495496 /* Reject requests with unsupported flags */
496- if (perout_request -> flags )
497+ if (perout_request -> flags & ~ PTP_PEROUT_DUTY_CYCLE )
497498 return - EOPNOTSUPP ;
498499
499500 if (on ) {
@@ -518,6 +519,7 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
518519 netif_warn (adapter , drv , adapter -> netdev ,
519520 "Failed to reserve event channel %d for PEROUT\n" ,
520521 index );
522+ ret = - EBUSY ;
521523 goto failed ;
522524 }
523525
@@ -529,6 +531,7 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
529531 netif_warn (adapter , drv , adapter -> netdev ,
530532 "Failed to reserve gpio %d for PEROUT\n" ,
531533 perout_pin );
534+ ret = - EBUSY ;
532535 goto failed ;
533536 }
534537
@@ -540,27 +543,93 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
540543 period_sec += perout_request -> period .nsec / 1000000000 ;
541544 period_nsec = perout_request -> period .nsec % 1000000000 ;
542545
543- if (period_sec == 0 ) {
544- if (period_nsec >= 400000000 ) {
546+ if (perout_request -> flags & PTP_PEROUT_DUTY_CYCLE ) {
547+ struct timespec64 ts_on , ts_period ;
548+ s64 wf_high , period64 , half ;
549+ s32 reminder ;
550+
551+ ts_on .tv_sec = perout_request -> on .sec ;
552+ ts_on .tv_nsec = perout_request -> on .nsec ;
553+ wf_high = timespec64_to_ns (& ts_on );
554+ ts_period .tv_sec = perout_request -> period .sec ;
555+ ts_period .tv_nsec = perout_request -> period .nsec ;
556+ period64 = timespec64_to_ns (& ts_period );
557+
558+ if (period64 < 200 ) {
559+ netif_warn (adapter , drv , adapter -> netdev ,
560+ "perout period too small, minimum is 200nS\n" );
561+ ret = - EOPNOTSUPP ;
562+ goto failed ;
563+ }
564+ if (wf_high >= period64 ) {
565+ netif_warn (adapter , drv , adapter -> netdev ,
566+ "pulse width must be smaller than period\n" );
567+ ret = - EINVAL ;
568+ goto failed ;
569+ }
570+
571+ /* Check if we can do 50% toggle on an even value of period.
572+ * If the period number is odd, then check if the requested
573+ * pulse width is the same as one of pre-defined width values.
574+ * Otherwise, return failure.
575+ */
576+ half = div_s64_rem (period64 , 2 , & reminder );
577+ if (!reminder ) {
578+ if (half == wf_high ) {
579+ /* It's 50% match. Use the toggle option */
580+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGGLE_ ;
581+ /* In this case, devide period value by 2 */
582+ ts_period = ns_to_timespec64 (div_s64 (period64 , 2 ));
583+ period_sec = ts_period .tv_sec ;
584+ period_nsec = ts_period .tv_nsec ;
585+
586+ goto program ;
587+ }
588+ }
589+ /* if we can't do toggle, then the width option needs to be the exact match */
590+ if (wf_high == 200000000 ) {
545591 pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_ ;
546- } else if (period_nsec >= 20000000 ) {
592+ } else if (wf_high == 10000000 ) {
547593 pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_ ;
548- } else if (period_nsec >= 2000000 ) {
594+ } else if (wf_high == 1000000 ) {
549595 pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_ ;
550- } else if (period_nsec >= 200000 ) {
596+ } else if (wf_high == 100000 ) {
551597 pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_ ;
552- } else if (period_nsec >= 20000 ) {
598+ } else if (wf_high == 10000 ) {
553599 pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_ ;
554- } else if (period_nsec >= 200 ) {
600+ } else if (wf_high == 100 ) {
555601 pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_ ;
556602 } else {
557603 netif_warn (adapter , drv , adapter -> netdev ,
558- "perout period too small, minimum is 200nS\n" );
604+ "duty cycle specified is not supported\n" );
605+ ret = - EOPNOTSUPP ;
559606 goto failed ;
560607 }
561608 } else {
562- pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_ ;
609+ if (period_sec == 0 ) {
610+ if (period_nsec >= 400000000 ) {
611+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_ ;
612+ } else if (period_nsec >= 20000000 ) {
613+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_ ;
614+ } else if (period_nsec >= 2000000 ) {
615+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_ ;
616+ } else if (period_nsec >= 200000 ) {
617+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_ ;
618+ } else if (period_nsec >= 20000 ) {
619+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_ ;
620+ } else if (period_nsec >= 200 ) {
621+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_ ;
622+ } else {
623+ netif_warn (adapter , drv , adapter -> netdev ,
624+ "perout period too small, minimum is 200nS\n" );
625+ ret = - EOPNOTSUPP ;
626+ goto failed ;
627+ }
628+ } else {
629+ pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_ ;
630+ }
563631 }
632+ program :
564633
565634 /* turn off by setting target far in future */
566635 lan743x_csr_write (adapter ,
@@ -599,7 +668,7 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on,
599668
600669failed :
601670 lan743x_ptp_perout_off (adapter , index );
602- return - ENODEV ;
671+ return ret ;
603672}
604673
605674static int lan743x_ptpci_enable (struct ptp_clock_info * ptpci ,
0 commit comments