2020-02-21 15:03:51 -05:00
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2018 Integrated Device Technology, Inc
//
# define pr_fmt(fmt) "IDT_82p33xxx: " fmt
# include <linux/firmware.h>
2022-03-08 09:10:51 -05:00
# include <linux/platform_device.h>
2020-02-21 15:03:51 -05:00
# include <linux/module.h>
# include <linux/ptp_clock_kernel.h>
# include <linux/delay.h>
2022-03-08 09:10:51 -05:00
# include <linux/jiffies.h>
2020-02-21 15:03:51 -05:00
# include <linux/kernel.h>
# include <linux/timekeeping.h>
# include <linux/bitops.h>
2022-03-08 09:10:51 -05:00
# include <linux/of.h>
# include <linux/mfd/rsmu.h>
# include <linux/mfd/idt82p33_reg.h>
2020-02-21 15:03:51 -05:00
# include "ptp_private.h"
# include "ptp_idt82p33.h"
MODULE_DESCRIPTION ( " Driver for IDT 82p33xxx clock devices " ) ;
MODULE_AUTHOR ( " IDT support-1588 <IDT-support-1588@lm.renesas.com> " ) ;
MODULE_VERSION ( " 1.0 " ) ;
MODULE_LICENSE ( " GPL " ) ;
2020-11-05 22:52:07 -05:00
MODULE_FIRMWARE ( FW_FILENAME ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
# define EXTTS_PERIOD_MS (95)
2020-02-21 15:03:51 -05:00
/* Module Parameters */
2020-04-18 10:01:49 +08:00
static u32 phase_snap_threshold = SNAP_THRESHOLD_NS ;
2020-02-21 15:03:51 -05:00
module_param ( phase_snap_threshold , uint , 0 ) ;
MODULE_PARM_DESC ( phase_snap_threshold ,
2022-03-08 09:10:51 -05:00
" threshold (10000ns by default) below which adjtime would use double dco " ) ;
static char * firmware ;
module_param ( firmware , charp , 0 ) ;
2022-11-23 14:52:06 -05:00
static struct ptp_pin_desc pin_config [ MAX_PHC_PLL ] [ MAX_TRIG_CLK ] ;
2022-03-08 09:10:51 -05:00
static inline int idt82p33_read ( struct idt82p33 * idt82p33 , u16 regaddr ,
u8 * buf , u16 count )
{
return regmap_bulk_read ( idt82p33 - > regmap , regaddr , buf , count ) ;
}
static inline int idt82p33_write ( struct idt82p33 * idt82p33 , u16 regaddr ,
u8 * buf , u16 count )
{
return regmap_bulk_write ( idt82p33 - > regmap , regaddr , buf , count ) ;
}
2020-02-21 15:03:51 -05:00
static void idt82p33_byte_array_to_timespec ( struct timespec64 * ts ,
u8 buf [ TOD_BYTE_COUNT ] )
{
time64_t sec ;
s32 nsec ;
u8 i ;
nsec = buf [ 3 ] ;
for ( i = 0 ; i < 3 ; i + + ) {
nsec < < = 8 ;
nsec | = buf [ 2 - i ] ;
}
sec = buf [ 9 ] ;
for ( i = 0 ; i < 5 ; i + + ) {
sec < < = 8 ;
sec | = buf [ 8 - i ] ;
}
ts - > tv_sec = sec ;
ts - > tv_nsec = nsec ;
}
static void idt82p33_timespec_to_byte_array ( struct timespec64 const * ts ,
u8 buf [ TOD_BYTE_COUNT ] )
{
time64_t sec ;
s32 nsec ;
u8 i ;
nsec = ts - > tv_nsec ;
sec = ts - > tv_sec ;
for ( i = 0 ; i < 4 ; i + + ) {
buf [ i ] = nsec & 0xff ;
nsec > > = 8 ;
}
for ( i = 4 ; i < TOD_BYTE_COUNT ; i + + ) {
buf [ i ] = sec & 0xff ;
sec > > = 8 ;
}
}
static int idt82p33_dpll_set_mode ( struct idt82p33_channel * channel ,
enum pll_mode mode )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
u8 dpll_mode ;
int err ;
if ( channel - > pll_mode = = mode )
return 0 ;
err = idt82p33_read ( idt82p33 , channel - > dpll_mode_cnfg ,
& dpll_mode , sizeof ( dpll_mode ) ) ;
if ( err )
return err ;
dpll_mode & = ~ ( PLL_MODE_MASK < < PLL_MODE_SHIFT ) ;
dpll_mode | = ( mode < < PLL_MODE_SHIFT ) ;
err = idt82p33_write ( idt82p33 , channel - > dpll_mode_cnfg ,
& dpll_mode , sizeof ( dpll_mode ) ) ;
if ( err )
return err ;
2022-03-08 09:10:51 -05:00
channel - > pll_mode = mode ;
2020-02-21 15:03:51 -05:00
return 0 ;
}
2022-11-23 14:52:06 -05:00
static int idt82p33_set_tod_trigger ( struct idt82p33_channel * channel ,
u8 trigger , bool write )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
int err ;
u8 cfg ;
if ( trigger > WR_TRIG_SEL_MAX )
return - EINVAL ;
err = idt82p33_read ( idt82p33 , channel - > dpll_tod_trigger ,
& cfg , sizeof ( cfg ) ) ;
if ( err )
return err ;
if ( write = = true )
trigger = ( trigger < < WRITE_TRIGGER_SHIFT ) |
( cfg & READ_TRIGGER_MASK ) ;
else
trigger = ( trigger < < READ_TRIGGER_SHIFT ) |
( cfg & WRITE_TRIGGER_MASK ) ;
return idt82p33_write ( idt82p33 , channel - > dpll_tod_trigger ,
& trigger , sizeof ( trigger ) ) ;
}
static int idt82p33_get_extts ( struct idt82p33_channel * channel ,
struct timespec64 * ts )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
u8 buf [ TOD_BYTE_COUNT ] ;
int err ;
err = idt82p33_read ( idt82p33 , channel - > dpll_tod_sts , buf , sizeof ( buf ) ) ;
if ( err )
return err ;
/* Since trigger is not self clearing itself, we have to poll tod_sts */
if ( memcmp ( buf , channel - > extts_tod_sts , TOD_BYTE_COUNT ) = = 0 )
return - EAGAIN ;
memcpy ( channel - > extts_tod_sts , buf , TOD_BYTE_COUNT ) ;
idt82p33_byte_array_to_timespec ( ts , buf ) ;
if ( channel - > discard_next_extts ) {
channel - > discard_next_extts = false ;
return - EAGAIN ;
}
return 0 ;
}
static int map_ref_to_tod_trig_sel ( int ref , u8 * trigger )
{
int err = 0 ;
switch ( ref ) {
case 0 :
* trigger = HW_TOD_TRIG_SEL_IN12 ;
break ;
case 1 :
* trigger = HW_TOD_TRIG_SEL_IN13 ;
break ;
case 2 :
* trigger = HW_TOD_TRIG_SEL_IN14 ;
break ;
default :
err = - EINVAL ;
}
return err ;
}
static bool is_one_shot ( u8 mask )
{
/* Treat single bit PLL masks as continuous trigger */
if ( ( mask = = 1 ) | | ( mask = = 2 ) )
return false ;
else
return true ;
}
static int arm_tod_read_with_trigger ( struct idt82p33_channel * channel , u8 trigger )
2020-02-21 15:03:51 -05:00
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
u8 buf [ TOD_BYTE_COUNT ] ;
2022-11-23 14:52:06 -05:00
int err ;
/* Remember the current tod_sts before setting the trigger */
err = idt82p33_read ( idt82p33 , channel - > dpll_tod_sts , buf , sizeof ( buf ) ) ;
if ( err )
return err ;
memcpy ( channel - > extts_tod_sts , buf , TOD_BYTE_COUNT ) ;
err = idt82p33_set_tod_trigger ( channel , trigger , false ) ;
if ( err )
dev_err ( idt82p33 - > dev , " %s: err = %d " , __func__ , err ) ;
return err ;
}
static int idt82p33_extts_enable ( struct idt82p33_channel * channel ,
struct ptp_clock_request * rq , int on )
{
u8 index = rq - > extts . index ;
struct idt82p33 * idt82p33 ;
u8 mask = 1 < < index ;
int err = 0 ;
u8 old_mask ;
2020-02-21 15:03:51 -05:00
u8 trigger ;
2022-11-23 14:52:06 -05:00
int ref ;
idt82p33 = channel - > idt82p33 ;
old_mask = idt82p33 - > extts_mask ;
/* Reject requests with unsupported flags */
if ( rq - > extts . flags & ~ ( PTP_ENABLE_FEATURE |
PTP_RISING_EDGE |
PTP_FALLING_EDGE |
PTP_STRICT_FLAGS ) )
return - EOPNOTSUPP ;
/* Reject requests to enable time stamping on falling edge */
if ( ( rq - > extts . flags & PTP_ENABLE_FEATURE ) & &
( rq - > extts . flags & PTP_FALLING_EDGE ) )
return - EOPNOTSUPP ;
if ( index > = MAX_PHC_PLL )
return - EINVAL ;
if ( on ) {
/* Return if it was already enabled */
if ( idt82p33 - > extts_mask & mask )
return 0 ;
/* Use the pin configured for the channel */
ref = ptp_find_pin ( channel - > ptp_clock , PTP_PF_EXTTS , channel - > plln ) ;
if ( ref < 0 ) {
dev_err ( idt82p33 - > dev , " %s: No valid pin found for Pll%d! \n " ,
__func__ , channel - > plln ) ;
return - EBUSY ;
}
err = map_ref_to_tod_trig_sel ( ref , & trigger ) ;
if ( err ) {
dev_err ( idt82p33 - > dev ,
" %s: Unsupported ref %d! \n " , __func__ , ref ) ;
return err ;
}
err = arm_tod_read_with_trigger ( & idt82p33 - > channel [ index ] , trigger ) ;
if ( err = = 0 ) {
idt82p33 - > extts_mask | = mask ;
idt82p33 - > channel [ index ] . tod_trigger = trigger ;
idt82p33 - > event_channel [ index ] = channel ;
idt82p33 - > extts_single_shot = is_one_shot ( idt82p33 - > extts_mask ) ;
if ( old_mask )
return 0 ;
schedule_delayed_work ( & idt82p33 - > extts_work ,
msecs_to_jiffies ( EXTTS_PERIOD_MS ) ) ;
}
} else {
idt82p33 - > extts_mask & = ~ mask ;
idt82p33 - > extts_single_shot = is_one_shot ( idt82p33 - > extts_mask ) ;
if ( idt82p33 - > extts_mask = = 0 )
cancel_delayed_work ( & idt82p33 - > extts_work ) ;
}
return err ;
}
static int idt82p33_extts_check_channel ( struct idt82p33 * idt82p33 , u8 todn )
{
struct idt82p33_channel * event_channel ;
struct ptp_clock_event event ;
struct timespec64 ts ;
int err ;
err = idt82p33_get_extts ( & idt82p33 - > channel [ todn ] , & ts ) ;
if ( err = = 0 ) {
event_channel = idt82p33 - > event_channel [ todn ] ;
event . type = PTP_CLOCK_EXTTS ;
event . index = todn ;
event . timestamp = timespec64_to_ns ( & ts ) ;
ptp_clock_event ( event_channel - > ptp_clock ,
& event ) ;
}
return err ;
}
static u8 idt82p33_extts_enable_mask ( struct idt82p33_channel * channel ,
u8 extts_mask , bool enable )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
u8 trigger = channel - > tod_trigger ;
u8 mask ;
2020-02-21 15:03:51 -05:00
int err ;
2022-11-23 14:52:06 -05:00
int i ;
if ( extts_mask = = 0 )
return 0 ;
if ( enable = = false )
cancel_delayed_work_sync ( & idt82p33 - > extts_work ) ;
for ( i = 0 ; i < MAX_PHC_PLL ; i + + ) {
mask = 1 < < i ;
if ( ( extts_mask & mask ) = = 0 )
continue ;
if ( enable ) {
err = arm_tod_read_with_trigger ( & idt82p33 - > channel [ i ] , trigger ) ;
if ( err )
dev_err ( idt82p33 - > dev ,
" %s: Arm ToD read trigger failed, err = %d " ,
__func__ , err ) ;
} else {
err = idt82p33_extts_check_channel ( idt82p33 , i ) ;
if ( err = = 0 & & idt82p33 - > extts_single_shot )
/* trigger happened so we won't re-enable it */
extts_mask & = ~ mask ;
}
}
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
if ( enable )
schedule_delayed_work ( & idt82p33 - > extts_work ,
msecs_to_jiffies ( EXTTS_PERIOD_MS ) ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
return extts_mask ;
}
static int _idt82p33_gettime ( struct idt82p33_channel * channel ,
struct timespec64 * ts )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
u8 old_mask = idt82p33 - > extts_mask ;
u8 buf [ TOD_BYTE_COUNT ] ;
u8 new_mask = 0 ;
int err ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
/* Disable extts */
if ( old_mask )
new_mask = idt82p33_extts_enable_mask ( channel , old_mask , false ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
err = idt82p33_set_tod_trigger ( channel , HW_TOD_RD_TRIG_SEL_LSB_TOD_STS ,
false ) ;
2020-02-21 15:03:51 -05:00
if ( err )
return err ;
2022-11-23 14:52:06 -05:00
channel - > discard_next_extts = true ;
2020-02-21 15:03:51 -05:00
if ( idt82p33 - > calculate_overhead_flag )
idt82p33 - > start_time = ktime_get_raw ( ) ;
err = idt82p33_read ( idt82p33 , channel - > dpll_tod_sts , buf , sizeof ( buf ) ) ;
if ( err )
return err ;
2022-11-23 14:52:06 -05:00
/* Re-enable extts */
if ( new_mask )
idt82p33_extts_enable_mask ( channel , new_mask , true ) ;
2020-02-21 15:03:51 -05:00
idt82p33_byte_array_to_timespec ( ts , buf ) ;
return 0 ;
}
/*
* TOD Trigger :
* Bits [ 7 : 4 ] Write 0x9 , MSB write
* Bits [ 3 : 0 ] Read 0x9 , LSB read
*/
static int _idt82p33_settime ( struct idt82p33_channel * channel ,
struct timespec64 const * ts )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
struct timespec64 local_ts = * ts ;
char buf [ TOD_BYTE_COUNT ] ;
s64 dynamic_overhead_ns ;
int err ;
u8 i ;
2022-11-23 14:52:06 -05:00
err = idt82p33_set_tod_trigger ( channel , HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG ,
true ) ;
2020-02-21 15:03:51 -05:00
if ( err )
return err ;
2022-11-23 14:52:06 -05:00
channel - > discard_next_extts = true ;
2020-02-21 15:03:51 -05:00
if ( idt82p33 - > calculate_overhead_flag ) {
dynamic_overhead_ns = ktime_to_ns ( ktime_get_raw ( ) )
- ktime_to_ns ( idt82p33 - > start_time ) ;
timespec64_add_ns ( & local_ts , dynamic_overhead_ns ) ;
idt82p33 - > calculate_overhead_flag = 0 ;
}
idt82p33_timespec_to_byte_array ( & local_ts , buf ) ;
/*
* Store the new time value .
*/
for ( i = 0 ; i < TOD_BYTE_COUNT ; i + + ) {
err = idt82p33_write ( idt82p33 , channel - > dpll_tod_cnfg + i ,
& buf [ i ] , sizeof ( buf [ i ] ) ) ;
if ( err )
return err ;
}
return err ;
}
2022-11-23 14:52:06 -05:00
static int _idt82p33_adjtime_immediate ( struct idt82p33_channel * channel ,
s64 delta_ns )
2020-02-21 15:03:51 -05:00
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
struct timespec64 ts ;
s64 now_ns ;
int err ;
idt82p33 - > calculate_overhead_flag = 1 ;
err = _idt82p33_gettime ( channel , & ts ) ;
if ( err )
return err ;
now_ns = timespec64_to_ns ( & ts ) ;
now_ns + = delta_ns + idt82p33 - > tod_write_overhead_ns ;
ts = ns_to_timespec64 ( now_ns ) ;
err = _idt82p33_settime ( channel , & ts ) ;
return err ;
}
2022-11-23 14:52:06 -05:00
static int _idt82p33_adjtime_internal_triggered ( struct idt82p33_channel * channel ,
s64 delta_ns )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
char buf [ TOD_BYTE_COUNT ] ;
struct timespec64 ts ;
const u8 delay_ns = 32 ;
s32 remainder ;
s64 ns ;
int err ;
err = _idt82p33_gettime ( channel , & ts ) ;
if ( err )
return err ;
if ( ts . tv_nsec > ( NSEC_PER_SEC - 5 * NSEC_PER_MSEC ) ) {
/* Too close to miss next trigger, so skip it */
mdelay ( 6 ) ;
ns = ( ts . tv_sec + 2 ) * NSEC_PER_SEC + delta_ns + delay_ns ;
} else
ns = ( ts . tv_sec + 1 ) * NSEC_PER_SEC + delta_ns + delay_ns ;
ts = ns_to_timespec64 ( ns ) ;
idt82p33_timespec_to_byte_array ( & ts , buf ) ;
/*
* Store the new time value .
*/
err = idt82p33_write ( idt82p33 , channel - > dpll_tod_cnfg , buf , sizeof ( buf ) ) ;
if ( err )
return err ;
/* Schedule to implement the workaround in one second */
( void ) div_s64_rem ( delta_ns , NSEC_PER_SEC , & remainder ) ;
if ( remainder ! = 0 )
schedule_delayed_work ( & channel - > adjtime_work , HZ ) ;
return idt82p33_set_tod_trigger ( channel , HW_TOD_TRIG_SEL_TOD_PPS , true ) ;
}
static void idt82p33_adjtime_workaround ( struct work_struct * work )
{
struct idt82p33_channel * channel = container_of ( work ,
struct idt82p33_channel ,
adjtime_work . work ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
mutex_lock ( idt82p33 - > lock ) ;
/* Workaround for TOD-to-output alignment issue */
_idt82p33_adjtime_internal_triggered ( channel , 0 ) ;
mutex_unlock ( idt82p33 - > lock ) ;
}
2020-02-21 15:03:51 -05:00
static int _idt82p33_adjfine ( struct idt82p33_channel * channel , long scaled_ppm )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
unsigned char buf [ 5 ] = { 0 } ;
int err , i ;
s64 fcw ;
/*
2022-11-23 14:52:06 -05:00
* Frequency Control Word unit is : 1.6861512 * 10 ^ - 10 ppm
2020-02-21 15:03:51 -05:00
*
* adjfreq :
2022-11-23 14:52:06 -05:00
* ppb * 10 ^ 14
* FCW = - - - - - - - - - - -
* 16861512
2020-02-21 15:03:51 -05:00
*
* adjfine :
2022-11-23 14:52:06 -05:00
* scaled_ppm * 5 ^ 12 * 10 ^ 5
* FCW = - - - - - - - - - - - - - - - - - - - - - - - -
* 16861512 * 2 ^ 4
2020-02-21 15:03:51 -05:00
*/
2022-11-23 14:52:06 -05:00
fcw = scaled_ppm * 762939453125ULL ;
fcw = div_s64 ( fcw , 8430756LL ) ;
2020-02-21 15:03:51 -05:00
for ( i = 0 ; i < 5 ; i + + ) {
buf [ i ] = fcw & 0xff ;
fcw > > = 8 ;
}
err = idt82p33_dpll_set_mode ( channel , PLL_MODE_DCO ) ;
if ( err )
return err ;
err = idt82p33_write ( idt82p33 , channel - > dpll_freq_cnfg ,
buf , sizeof ( buf ) ) ;
return err ;
}
2022-11-23 14:52:06 -05:00
/* ppb = scaled_ppm * 125 / 2^13 */
static s32 idt82p33_ddco_scaled_ppm ( long current_ppm , s32 ddco_ppb )
{
s64 scaled_ppm = div_s64 ( ( ( s64 ) ddco_ppb < < 13 ) , 125 ) ;
s64 max_scaled_ppm = div_s64 ( ( ( s64 ) DCO_MAX_PPB < < 13 ) , 125 ) ;
current_ppm + = scaled_ppm ;
if ( current_ppm > max_scaled_ppm )
current_ppm = max_scaled_ppm ;
else if ( current_ppm < - max_scaled_ppm )
current_ppm = - max_scaled_ppm ;
return ( s32 ) current_ppm ;
}
static int idt82p33_stop_ddco ( struct idt82p33_channel * channel )
{
int err ;
err = _idt82p33_adjfine ( channel , channel - > current_freq ) ;
if ( err )
return err ;
channel - > ddco = false ;
return 0 ;
}
static int idt82p33_start_ddco ( struct idt82p33_channel * channel , s32 delta_ns )
{
s32 current_ppm = channel - > current_freq ;
u32 duration_ms = MSEC_PER_SEC ;
s32 ppb ;
int err ;
/* If the ToD correction is less than 5 nanoseconds, then skip it.
* The error introduced by the ToD adjustment procedure would be bigger
* than the required ToD correction
*/
if ( abs ( delta_ns ) < DDCO_THRESHOLD_NS )
return 0 ;
/* For most cases, keep ddco duration 1 second */
ppb = delta_ns ;
while ( abs ( ppb ) > DCO_MAX_PPB ) {
duration_ms * = 2 ;
ppb / = 2 ;
}
err = _idt82p33_adjfine ( channel ,
idt82p33_ddco_scaled_ppm ( current_ppm , ppb ) ) ;
if ( err )
return err ;
/* schedule the worker to cancel ddco */
ptp_schedule_worker ( channel - > ptp_clock ,
msecs_to_jiffies ( duration_ms ) - 1 ) ;
channel - > ddco = true ;
return 0 ;
}
2020-02-21 15:03:51 -05:00
static int idt82p33_measure_one_byte_write_overhead (
struct idt82p33_channel * channel , s64 * overhead_ns )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
ktime_t start , stop ;
2022-11-23 14:52:06 -05:00
u8 trigger = 0 ;
2020-02-21 15:03:51 -05:00
s64 total_ns ;
int err ;
u8 i ;
total_ns = 0 ;
* overhead_ns = 0 ;
for ( i = 0 ; i < MAX_MEASURMENT_COUNT ; i + + ) {
start = ktime_get_raw ( ) ;
err = idt82p33_write ( idt82p33 , channel - > dpll_tod_trigger ,
& trigger , sizeof ( trigger ) ) ;
stop = ktime_get_raw ( ) ;
if ( err )
return err ;
total_ns + = ktime_to_ns ( stop ) - ktime_to_ns ( start ) ;
}
* overhead_ns = div_s64 ( total_ns , MAX_MEASURMENT_COUNT ) ;
return err ;
}
2022-11-23 14:52:06 -05:00
static int idt82p33_measure_one_byte_read_overhead (
struct idt82p33_channel * channel , s64 * overhead_ns )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
ktime_t start , stop ;
u8 trigger = 0 ;
s64 total_ns ;
int err ;
u8 i ;
total_ns = 0 ;
* overhead_ns = 0 ;
for ( i = 0 ; i < MAX_MEASURMENT_COUNT ; i + + ) {
start = ktime_get_raw ( ) ;
err = idt82p33_read ( idt82p33 , channel - > dpll_tod_trigger ,
& trigger , sizeof ( trigger ) ) ;
stop = ktime_get_raw ( ) ;
if ( err )
return err ;
total_ns + = ktime_to_ns ( stop ) - ktime_to_ns ( start ) ;
}
* overhead_ns = div_s64 ( total_ns , MAX_MEASURMENT_COUNT ) ;
return err ;
}
2020-02-21 15:03:51 -05:00
static int idt82p33_measure_tod_write_9_byte_overhead (
2022-11-23 14:52:06 -05:00
struct idt82p33_channel * channel )
2020-02-21 15:03:51 -05:00
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
u8 buf [ TOD_BYTE_COUNT ] ;
ktime_t start , stop ;
s64 total_ns ;
int err = 0 ;
u8 i , j ;
total_ns = 0 ;
idt82p33 - > tod_write_overhead_ns = 0 ;
for ( i = 0 ; i < MAX_MEASURMENT_COUNT ; i + + ) {
start = ktime_get_raw ( ) ;
/* Need one less byte for applicable overhead */
for ( j = 0 ; j < ( TOD_BYTE_COUNT - 1 ) ; j + + ) {
err = idt82p33_write ( idt82p33 ,
channel - > dpll_tod_cnfg + i ,
& buf [ i ] , sizeof ( buf [ i ] ) ) ;
if ( err )
return err ;
}
stop = ktime_get_raw ( ) ;
total_ns + = ktime_to_ns ( stop ) - ktime_to_ns ( start ) ;
}
idt82p33 - > tod_write_overhead_ns = div_s64 ( total_ns ,
MAX_MEASURMENT_COUNT ) ;
return err ;
}
static int idt82p33_measure_settime_gettime_gap_overhead (
struct idt82p33_channel * channel , s64 * overhead_ns )
{
struct timespec64 ts1 = { 0 , 0 } ;
struct timespec64 ts2 ;
int err ;
* overhead_ns = 0 ;
err = _idt82p33_settime ( channel , & ts1 ) ;
if ( err )
return err ;
err = _idt82p33_gettime ( channel , & ts2 ) ;
if ( ! err )
* overhead_ns = timespec64_to_ns ( & ts2 ) - timespec64_to_ns ( & ts1 ) ;
return err ;
}
static int idt82p33_measure_tod_write_overhead ( struct idt82p33_channel * channel )
{
2022-11-23 14:52:06 -05:00
s64 trailing_overhead_ns , one_byte_write_ns , gap_ns , one_byte_read_ns ;
2020-02-21 15:03:51 -05:00
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
int err ;
idt82p33 - > tod_write_overhead_ns = 0 ;
err = idt82p33_measure_settime_gettime_gap_overhead ( channel , & gap_ns ) ;
2020-11-05 22:52:07 -05:00
if ( err ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
2020-11-05 22:52:07 -05:00
}
2020-02-21 15:03:51 -05:00
err = idt82p33_measure_one_byte_write_overhead ( channel ,
& one_byte_write_ns ) ;
if ( err )
return err ;
2022-11-23 14:52:06 -05:00
err = idt82p33_measure_one_byte_read_overhead ( channel ,
& one_byte_read_ns ) ;
if ( err )
return err ;
2020-02-21 15:03:51 -05:00
err = idt82p33_measure_tod_write_9_byte_overhead ( channel ) ;
if ( err )
return err ;
2022-11-23 14:52:06 -05:00
trailing_overhead_ns = gap_ns - 2 * one_byte_write_ns
- one_byte_read_ns ;
2020-02-21 15:03:51 -05:00
idt82p33 - > tod_write_overhead_ns - = trailing_overhead_ns ;
return err ;
}
static int idt82p33_check_and_set_masks ( struct idt82p33 * idt82p33 ,
u8 page ,
u8 offset ,
u8 val )
{
int err = 0 ;
if ( page = = PLLMASK_ADDR_HI & & offset = = PLLMASK_ADDR_LO ) {
if ( ( val & 0xfc ) | | ! ( val & 0x3 ) ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
" Invalid PLL mask 0x%x \n " , val ) ;
2020-02-21 15:03:51 -05:00
err = - EINVAL ;
} else {
idt82p33 - > pll_mask = val ;
}
} else if ( page = = PLL0_OUTMASK_ADDR_HI & &
offset = = PLL0_OUTMASK_ADDR_LO ) {
idt82p33 - > channel [ 0 ] . output_mask = val ;
} else if ( page = = PLL1_OUTMASK_ADDR_HI & &
offset = = PLL1_OUTMASK_ADDR_LO ) {
idt82p33 - > channel [ 1 ] . output_mask = val ;
}
return err ;
}
static void idt82p33_display_masks ( struct idt82p33 * idt82p33 )
{
u8 mask , i ;
2022-03-08 09:10:51 -05:00
dev_info ( idt82p33 - > dev ,
2020-02-21 15:03:51 -05:00
" pllmask = 0x%02x \n " , idt82p33 - > pll_mask ) ;
for ( i = 0 ; i < MAX_PHC_PLL ; i + + ) {
mask = 1 < < i ;
if ( mask & idt82p33 - > pll_mask )
2022-03-08 09:10:51 -05:00
dev_info ( idt82p33 - > dev ,
2020-02-21 15:03:51 -05:00
" PLL%d output_mask = 0x%04x \n " ,
i , idt82p33 - > channel [ i ] . output_mask ) ;
}
}
static int idt82p33_sync_tod ( struct idt82p33_channel * channel , bool enable )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
u8 sync_cnfg ;
int err ;
err = idt82p33_read ( idt82p33 , channel - > dpll_sync_cnfg ,
& sync_cnfg , sizeof ( sync_cnfg ) ) ;
if ( err )
return err ;
sync_cnfg & = ~ SYNC_TOD ;
if ( enable )
sync_cnfg | = SYNC_TOD ;
2020-11-05 22:52:07 -05:00
return idt82p33_write ( idt82p33 , channel - > dpll_sync_cnfg ,
& sync_cnfg , sizeof ( sync_cnfg ) ) ;
2020-02-21 15:03:51 -05:00
}
2022-11-23 14:52:06 -05:00
static long idt82p33_work_handler ( struct ptp_clock_info * ptp )
{
struct idt82p33_channel * channel =
container_of ( ptp , struct idt82p33_channel , caps ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
mutex_lock ( idt82p33 - > lock ) ;
( void ) idt82p33_stop_ddco ( channel ) ;
mutex_unlock ( idt82p33 - > lock ) ;
/* Return a negative value here to not reschedule */
return - 1 ;
}
2020-11-05 22:52:07 -05:00
static int idt82p33_output_enable ( struct idt82p33_channel * channel ,
bool enable , unsigned int outn )
2020-02-21 15:03:51 -05:00
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
int err ;
2020-11-05 22:52:07 -05:00
u8 val ;
err = idt82p33_read ( idt82p33 , OUT_MUX_CNFG ( outn ) , & val , sizeof ( val ) ) ;
if ( err )
return err ;
if ( enable )
val & = ~ SQUELCH_ENABLE ;
else
val | = SQUELCH_ENABLE ;
return idt82p33_write ( idt82p33 , OUT_MUX_CNFG ( outn ) , & val , sizeof ( val ) ) ;
}
static int idt82p33_perout_enable ( struct idt82p33_channel * channel ,
bool enable ,
struct ptp_perout_request * perout )
{
/* Enable/disable individual output instead */
return idt82p33_output_enable ( channel , enable , perout - > index ) ;
}
2020-02-21 15:03:51 -05:00
static int idt82p33_enable_tod ( struct idt82p33_channel * channel )
{
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
struct timespec64 ts = { 0 , 0 } ;
int err ;
err = idt82p33_measure_tod_write_overhead ( channel ) ;
2020-11-05 22:52:07 -05:00
if ( err ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
2020-11-05 22:52:07 -05:00
}
2020-02-21 15:03:51 -05:00
err = _idt82p33_settime ( channel , & ts ) ;
if ( err )
return err ;
return idt82p33_sync_tod ( channel , true ) ;
}
static void idt82p33_ptp_clock_unregister_all ( struct idt82p33 * idt82p33 )
{
struct idt82p33_channel * channel ;
u8 i ;
for ( i = 0 ; i < MAX_PHC_PLL ; i + + ) {
channel = & idt82p33 - > channel [ i ] ;
2022-11-23 14:52:06 -05:00
cancel_delayed_work_sync ( & channel - > adjtime_work ) ;
2020-11-05 22:52:07 -05:00
if ( channel - > ptp_clock )
2020-02-21 15:03:51 -05:00
ptp_clock_unregister ( channel - > ptp_clock ) ;
}
}
2022-11-23 14:52:06 -05:00
2020-02-21 15:03:51 -05:00
static int idt82p33_enable ( struct ptp_clock_info * ptp ,
2022-03-08 09:10:51 -05:00
struct ptp_clock_request * rq , int on )
2020-02-21 15:03:51 -05:00
{
struct idt82p33_channel * channel =
container_of ( ptp , struct idt82p33_channel , caps ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
2022-03-08 09:10:51 -05:00
int err = - EOPNOTSUPP ;
2020-02-21 15:03:51 -05:00
2022-03-08 09:10:51 -05:00
mutex_lock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
switch ( rq - > type ) {
case PTP_CLK_REQ_PEROUT :
2020-02-21 15:03:51 -05:00
if ( ! on )
2020-11-05 22:52:07 -05:00
err = idt82p33_perout_enable ( channel , false ,
& rq - > perout ) ;
2020-02-21 15:03:51 -05:00
/* Only accept a 1-PPS aligned to the second. */
else if ( rq - > perout . start . nsec | | rq - > perout . period . sec ! = 1 | |
2022-03-08 09:10:51 -05:00
rq - > perout . period . nsec )
2020-02-21 15:03:51 -05:00
err = - ERANGE ;
2022-03-08 09:10:51 -05:00
else
2020-11-05 22:52:07 -05:00
err = idt82p33_perout_enable ( channel , true ,
& rq - > perout ) ;
2022-11-23 14:52:06 -05:00
break ;
case PTP_CLK_REQ_EXTTS :
err = idt82p33_extts_enable ( channel , rq , on ) ;
break ;
default :
break ;
2020-02-21 15:03:51 -05:00
}
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
2022-03-08 09:10:51 -05:00
if ( err )
dev_err ( idt82p33 - > dev ,
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
}
2023-06-12 14:14:59 -07:00
static s32 idt82p33_getmaxphase ( __always_unused struct ptp_clock_info * ptp )
{
return WRITE_PHASE_OFFSET_LIMIT ;
}
2020-11-05 22:52:07 -05:00
static int idt82p33_adjwritephase ( struct ptp_clock_info * ptp , s32 offset_ns )
{
struct idt82p33_channel * channel =
container_of ( ptp , struct idt82p33_channel , caps ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
2023-06-12 14:14:59 -07:00
s64 offset_regval ;
2020-11-05 22:52:07 -05:00
u8 val [ 4 ] = { 0 } ;
int err ;
/* Convert from phaseoffset_fs to register value */
2023-06-12 14:14:59 -07:00
offset_regval = div_s64 ( ( s64 ) ( - offset_ns ) * 1000000000ll ,
IDT_T0DPLL_PHASE_RESOL ) ;
2020-11-05 22:52:07 -05:00
val [ 0 ] = offset_regval & 0xFF ;
val [ 1 ] = ( offset_regval > > 8 ) & 0xFF ;
val [ 2 ] = ( offset_regval > > 16 ) & 0xFF ;
val [ 3 ] = ( offset_regval > > 24 ) & 0x1F ;
val [ 3 ] | = PH_OFFSET_EN ;
2022-03-08 09:10:51 -05:00
mutex_lock ( idt82p33 - > lock ) ;
2020-11-05 22:52:07 -05:00
err = idt82p33_dpll_set_mode ( channel , PLL_MODE_WPH ) ;
if ( err ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Failed in %s with err %d! \n " , __func__ , err ) ;
goto out ;
}
err = idt82p33_write ( idt82p33 , channel - > dpll_phase_cnfg , val ,
sizeof ( val ) ) ;
out :
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2020-11-05 22:52:07 -05:00
return err ;
}
2020-02-21 15:03:51 -05:00
static int idt82p33_adjfine ( struct ptp_clock_info * ptp , long scaled_ppm )
{
struct idt82p33_channel * channel =
container_of ( ptp , struct idt82p33_channel , caps ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
int err ;
2022-11-23 14:52:06 -05:00
if ( channel - > ddco = = true )
return 0 ;
if ( scaled_ppm = = channel - > current_freq )
return 0 ;
2022-03-08 09:10:51 -05:00
mutex_lock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
err = _idt82p33_adjfine ( channel , scaled_ppm ) ;
2022-11-23 14:52:06 -05:00
if ( err = = 0 )
channel - > current_freq = scaled_ppm ;
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2022-11-23 14:52:06 -05:00
2020-11-05 22:52:07 -05:00
if ( err )
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
}
static int idt82p33_adjtime ( struct ptp_clock_info * ptp , s64 delta_ns )
{
struct idt82p33_channel * channel =
container_of ( ptp , struct idt82p33_channel , caps ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
int err ;
2022-11-23 14:52:06 -05:00
if ( channel - > ddco = = true )
return - EBUSY ;
2022-03-08 09:10:51 -05:00
mutex_lock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
if ( abs ( delta_ns ) < phase_snap_threshold ) {
2022-11-23 14:52:06 -05:00
err = idt82p33_start_ddco ( channel , delta_ns ) ;
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2022-11-23 14:52:06 -05:00
return err ;
2020-02-21 15:03:51 -05:00
}
2022-11-23 14:52:06 -05:00
/* Use more accurate internal 1pps triggered write first */
err = _idt82p33_adjtime_internal_triggered ( channel , delta_ns ) ;
if ( err & & delta_ns > IMMEDIATE_SNAP_THRESHOLD_NS )
err = _idt82p33_adjtime_immediate ( channel , delta_ns ) ;
2020-02-21 15:03:51 -05:00
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
2020-11-05 22:52:07 -05:00
if ( err )
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
}
static int idt82p33_gettime ( struct ptp_clock_info * ptp , struct timespec64 * ts )
{
struct idt82p33_channel * channel =
container_of ( ptp , struct idt82p33_channel , caps ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
int err ;
2022-03-08 09:10:51 -05:00
mutex_lock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
err = _idt82p33_gettime ( channel , ts ) ;
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2020-11-05 22:52:07 -05:00
if ( err )
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
}
static int idt82p33_settime ( struct ptp_clock_info * ptp ,
2022-03-08 09:10:51 -05:00
const struct timespec64 * ts )
2020-02-21 15:03:51 -05:00
{
struct idt82p33_channel * channel =
container_of ( ptp , struct idt82p33_channel , caps ) ;
struct idt82p33 * idt82p33 = channel - > idt82p33 ;
int err ;
2022-03-08 09:10:51 -05:00
mutex_lock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
err = _idt82p33_settime ( channel , ts ) ;
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2020-11-05 22:52:07 -05:00
if ( err )
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
}
2022-11-23 14:52:06 -05:00
static int idt82p33_channel_init ( struct idt82p33 * idt82p33 , u32 index )
2020-02-21 15:03:51 -05:00
{
2022-11-23 14:52:06 -05:00
struct idt82p33_channel * channel = & idt82p33 - > channel [ index ] ;
2020-02-21 15:03:51 -05:00
switch ( index ) {
case 0 :
channel - > dpll_tod_cnfg = DPLL1_TOD_CNFG ;
channel - > dpll_tod_trigger = DPLL1_TOD_TRIGGER ;
channel - > dpll_tod_sts = DPLL1_TOD_STS ;
channel - > dpll_mode_cnfg = DPLL1_OPERATING_MODE_CNFG ;
channel - > dpll_freq_cnfg = DPLL1_HOLDOVER_FREQ_CNFG ;
channel - > dpll_phase_cnfg = DPLL1_PHASE_OFFSET_CNFG ;
channel - > dpll_sync_cnfg = DPLL1_SYNC_EDGE_CNFG ;
channel - > dpll_input_mode_cnfg = DPLL1_INPUT_MODE_CNFG ;
break ;
case 1 :
channel - > dpll_tod_cnfg = DPLL2_TOD_CNFG ;
channel - > dpll_tod_trigger = DPLL2_TOD_TRIGGER ;
channel - > dpll_tod_sts = DPLL2_TOD_STS ;
channel - > dpll_mode_cnfg = DPLL2_OPERATING_MODE_CNFG ;
channel - > dpll_freq_cnfg = DPLL2_HOLDOVER_FREQ_CNFG ;
channel - > dpll_phase_cnfg = DPLL2_PHASE_OFFSET_CNFG ;
channel - > dpll_sync_cnfg = DPLL2_SYNC_EDGE_CNFG ;
channel - > dpll_input_mode_cnfg = DPLL2_INPUT_MODE_CNFG ;
break ;
default :
return - EINVAL ;
}
2022-11-23 14:52:06 -05:00
channel - > plln = index ;
channel - > current_freq = 0 ;
channel - > idt82p33 = idt82p33 ;
INIT_DELAYED_WORK ( & channel - > adjtime_work , idt82p33_adjtime_workaround ) ;
return 0 ;
}
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
static int idt82p33_verify_pin ( struct ptp_clock_info * ptp , unsigned int pin ,
enum ptp_pin_function func , unsigned int chan )
{
switch ( func ) {
case PTP_PF_NONE :
case PTP_PF_EXTTS :
break ;
case PTP_PF_PEROUT :
case PTP_PF_PHYSYNC :
return - 1 ;
}
2020-02-21 15:03:51 -05:00
return 0 ;
}
2022-11-23 14:52:06 -05:00
static void idt82p33_caps_init ( u32 index , struct ptp_clock_info * caps ,
struct ptp_pin_desc * pin_cfg , u8 max_pins )
2020-02-21 15:03:51 -05:00
{
2022-11-23 14:52:06 -05:00
struct ptp_pin_desc * ppd ;
int i ;
2020-02-21 15:03:51 -05:00
caps - > owner = THIS_MODULE ;
2022-03-08 09:10:51 -05:00
caps - > max_adj = DCO_MAX_PPB ;
2022-11-23 14:52:06 -05:00
caps - > n_per_out = MAX_PER_OUT ;
caps - > n_ext_ts = MAX_PHC_PLL ,
caps - > n_pins = max_pins ,
caps - > adjphase = idt82p33_adjwritephase ,
2023-06-12 14:14:59 -07:00
caps - > getmaxphase = idt82p33_getmaxphase ,
2020-02-21 15:03:51 -05:00
caps - > adjfine = idt82p33_adjfine ;
caps - > adjtime = idt82p33_adjtime ;
caps - > gettime64 = idt82p33_gettime ;
caps - > settime64 = idt82p33_settime ;
caps - > enable = idt82p33_enable ;
2022-11-23 14:52:06 -05:00
caps - > verify = idt82p33_verify_pin ;
caps - > do_aux_work = idt82p33_work_handler ;
snprintf ( caps - > name , sizeof ( caps - > name ) , " IDT 82P33 PLL%u " , index ) ;
caps - > pin_config = pin_cfg ;
for ( i = 0 ; i < max_pins ; + + i ) {
ppd = & pin_cfg [ i ] ;
ppd - > index = i ;
ppd - > func = PTP_PF_NONE ;
ppd - > chan = index ;
snprintf ( ppd - > name , sizeof ( ppd - > name ) , " in%d " , 12 + i ) ;
}
2020-02-21 15:03:51 -05:00
}
static int idt82p33_enable_channel ( struct idt82p33 * idt82p33 , u32 index )
{
struct idt82p33_channel * channel ;
int err ;
if ( ! ( index < MAX_PHC_PLL ) )
return - EINVAL ;
channel = & idt82p33 - > channel [ index ] ;
2022-11-23 14:52:06 -05:00
err = idt82p33_channel_init ( idt82p33 , index ) ;
2020-11-05 22:52:07 -05:00
if ( err ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Channel_init failed in %s with err %d! \n " ,
__func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
2020-11-05 22:52:07 -05:00
}
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
idt82p33_caps_init ( index , & channel - > caps ,
pin_config [ index ] , MAX_TRIG_CLK ) ;
2020-02-21 15:03:51 -05:00
channel - > ptp_clock = ptp_clock_register ( & channel - > caps , NULL ) ;
if ( IS_ERR ( channel - > ptp_clock ) ) {
err = PTR_ERR ( channel - > ptp_clock ) ;
channel - > ptp_clock = NULL ;
return err ;
}
if ( ! channel - > ptp_clock )
return - ENOTSUPP ;
2020-11-05 22:52:07 -05:00
err = idt82p33_dpll_set_mode ( channel , PLL_MODE_DCO ) ;
if ( err ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Dpll_set_mode failed in %s with err %d! \n " ,
__func__ , err ) ;
return err ;
}
err = idt82p33_enable_tod ( channel ) ;
if ( err ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Enable_tod failed in %s with err %d! \n " ,
__func__ , err ) ;
return err ;
}
2022-03-08 09:10:51 -05:00
dev_info ( idt82p33 - > dev , " PLL%d registered as ptp%d \n " ,
2020-02-21 15:03:51 -05:00
index , channel - > ptp_clock - > index ) ;
return 0 ;
}
2022-11-23 14:52:06 -05:00
static int idt82p33_reset ( struct idt82p33 * idt82p33 , bool cold )
{
int err ;
u8 cfg = SOFT_RESET_EN ;
if ( cold = = true )
goto cold_reset ;
err = idt82p33_read ( idt82p33 , REG_SOFT_RESET , & cfg , sizeof ( cfg ) ) ;
if ( err ) {
dev_err ( idt82p33 - > dev ,
" Soft reset failed with err %d! \n " , err ) ;
return err ;
}
cfg | = SOFT_RESET_EN ;
cold_reset :
err = idt82p33_write ( idt82p33 , REG_SOFT_RESET , & cfg , sizeof ( cfg ) ) ;
if ( err )
dev_err ( idt82p33 - > dev ,
" Cold reset failed with err %d! \n " , err ) ;
return err ;
}
2020-02-21 15:03:51 -05:00
static int idt82p33_load_firmware ( struct idt82p33 * idt82p33 )
{
2022-11-23 14:52:06 -05:00
char fname [ 128 ] = FW_FILENAME ;
2020-02-21 15:03:51 -05:00
const struct firmware * fw ;
struct idt82p33_fwrc * rec ;
u8 loaddr , page , val ;
int err ;
s32 len ;
2022-11-23 14:52:06 -05:00
if ( firmware ) /* module parameter */
snprintf ( fname , sizeof ( fname ) , " %s " , firmware ) ;
dev_info ( idt82p33 - > dev , " requesting firmware '%s' \n " , fname ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
err = request_firmware ( & fw , fname , idt82p33 - > dev ) ;
2020-02-21 15:03:51 -05:00
2020-11-05 22:52:07 -05:00
if ( err ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-11-05 22:52:07 -05:00
" Failed in %s with err %d! \n " , __func__ , err ) ;
2020-02-21 15:03:51 -05:00
return err ;
2020-11-05 22:52:07 -05:00
}
2020-02-21 15:03:51 -05:00
2022-03-08 09:10:51 -05:00
dev_dbg ( idt82p33 - > dev , " firmware size %zu bytes \n " , fw - > size ) ;
2020-02-21 15:03:51 -05:00
rec = ( struct idt82p33_fwrc * ) fw - > data ;
for ( len = fw - > size ; len > 0 ; len - = sizeof ( * rec ) ) {
if ( rec - > reserved ) {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-02-21 15:03:51 -05:00
" bad firmware, reserved field non-zero \n " ) ;
err = - EINVAL ;
} else {
val = rec - > value ;
loaddr = rec - > loaddr ;
page = rec - > hiaddr ;
rec + + ;
err = idt82p33_check_and_set_masks ( idt82p33 , page ,
loaddr , val ) ;
}
if ( err = = 0 ) {
/* Page size 128, last 4 bytes of page skipped */
2022-03-08 09:10:51 -05:00
if ( loaddr > 0x7b )
2020-02-21 15:03:51 -05:00
continue ;
2022-03-08 09:10:51 -05:00
err = idt82p33_write ( idt82p33 , REG_ADDR ( page , loaddr ) ,
2020-02-21 15:03:51 -05:00
& val , sizeof ( val ) ) ;
}
if ( err )
goto out ;
}
idt82p33_display_masks ( idt82p33 ) ;
out :
release_firmware ( fw ) ;
return err ;
}
2022-11-23 14:52:06 -05:00
static void idt82p33_extts_check ( struct work_struct * work )
{
struct idt82p33 * idt82p33 = container_of ( work , struct idt82p33 ,
extts_work . work ) ;
struct idt82p33_channel * channel ;
int err ;
u8 mask ;
int i ;
if ( idt82p33 - > extts_mask = = 0 )
return ;
mutex_lock ( idt82p33 - > lock ) ;
for ( i = 0 ; i < MAX_PHC_PLL ; i + + ) {
mask = 1 < < i ;
if ( ( idt82p33 - > extts_mask & mask ) = = 0 )
continue ;
err = idt82p33_extts_check_channel ( idt82p33 , i ) ;
if ( err = = 0 ) {
/* trigger clears itself, so clear the mask */
if ( idt82p33 - > extts_single_shot ) {
idt82p33 - > extts_mask & = ~ mask ;
} else {
/* Re-arm */
channel = & idt82p33 - > channel [ i ] ;
arm_tod_read_with_trigger ( channel , channel - > tod_trigger ) ;
}
}
}
if ( idt82p33 - > extts_mask )
schedule_delayed_work ( & idt82p33 - > extts_work ,
msecs_to_jiffies ( EXTTS_PERIOD_MS ) ) ;
mutex_unlock ( idt82p33 - > lock ) ;
}
2020-02-21 15:03:51 -05:00
2022-03-08 09:10:51 -05:00
static int idt82p33_probe ( struct platform_device * pdev )
2020-02-21 15:03:51 -05:00
{
2022-03-08 09:10:51 -05:00
struct rsmu_ddata * ddata = dev_get_drvdata ( pdev - > dev . parent ) ;
2020-02-21 15:03:51 -05:00
struct idt82p33 * idt82p33 ;
int err ;
u8 i ;
2022-03-08 09:10:51 -05:00
idt82p33 = devm_kzalloc ( & pdev - > dev ,
2020-02-21 15:03:51 -05:00
sizeof ( struct idt82p33 ) , GFP_KERNEL ) ;
if ( ! idt82p33 )
return - ENOMEM ;
2022-03-08 09:10:51 -05:00
idt82p33 - > dev = & pdev - > dev ;
idt82p33 - > mfd = pdev - > dev . parent ;
idt82p33 - > lock = & ddata - > lock ;
idt82p33 - > regmap = ddata - > regmap ;
2020-02-21 15:03:51 -05:00
idt82p33 - > tod_write_overhead_ns = 0 ;
idt82p33 - > calculate_overhead_flag = 0 ;
idt82p33 - > pll_mask = DEFAULT_PLL_MASK ;
idt82p33 - > channel [ 0 ] . output_mask = DEFAULT_OUTPUT_MASK_PLL0 ;
idt82p33 - > channel [ 1 ] . output_mask = DEFAULT_OUTPUT_MASK_PLL1 ;
2022-11-23 14:52:06 -05:00
idt82p33 - > extts_mask = 0 ;
INIT_DELAYED_WORK ( & idt82p33 - > extts_work , idt82p33_extts_check ) ;
2020-02-21 15:03:51 -05:00
2022-03-08 09:10:51 -05:00
mutex_lock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
/* cold reset before loading firmware */
idt82p33_reset ( idt82p33 , true ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
err = idt82p33_load_firmware ( idt82p33 ) ;
2020-02-21 15:03:51 -05:00
if ( err )
2022-03-08 09:10:51 -05:00
dev_warn ( idt82p33 - > dev ,
2020-02-21 15:03:51 -05:00
" loading firmware failed with %d \n " , err ) ;
2022-11-23 14:52:06 -05:00
/* soft reset after loading firmware */
idt82p33_reset ( idt82p33 , false ) ;
2020-02-21 15:03:51 -05:00
if ( idt82p33 - > pll_mask ) {
for ( i = 0 ; i < MAX_PHC_PLL ; i + + ) {
2022-11-23 14:52:06 -05:00
if ( idt82p33 - > pll_mask & ( 1 < < i ) )
2020-02-21 15:03:51 -05:00
err = idt82p33_enable_channel ( idt82p33 , i ) ;
2022-11-23 14:52:06 -05:00
else
err = idt82p33_channel_init ( idt82p33 , i ) ;
if ( err ) {
dev_err ( idt82p33 - > dev ,
" Failed in %s with err %d! \n " ,
__func__ , err ) ;
break ;
2020-02-21 15:03:51 -05:00
}
}
} else {
2022-03-08 09:10:51 -05:00
dev_err ( idt82p33 - > dev ,
2020-02-21 15:03:51 -05:00
" no PLLs flagged as PHCs, nothing to do \n " ) ;
err = - ENODEV ;
}
2022-03-08 09:10:51 -05:00
mutex_unlock ( idt82p33 - > lock ) ;
2020-02-21 15:03:51 -05:00
if ( err ) {
idt82p33_ptp_clock_unregister_all ( idt82p33 ) ;
return err ;
}
2022-03-08 09:10:51 -05:00
platform_set_drvdata ( pdev , idt82p33 ) ;
2020-02-21 15:03:51 -05:00
return 0 ;
}
2022-03-08 09:10:51 -05:00
static int idt82p33_remove ( struct platform_device * pdev )
2020-02-21 15:03:51 -05:00
{
2022-03-08 09:10:51 -05:00
struct idt82p33 * idt82p33 = platform_get_drvdata ( pdev ) ;
2020-02-21 15:03:51 -05:00
2022-11-23 14:52:06 -05:00
cancel_delayed_work_sync ( & idt82p33 - > extts_work ) ;
2020-02-21 15:03:51 -05:00
idt82p33_ptp_clock_unregister_all ( idt82p33 ) ;
return 0 ;
}
2022-03-08 09:10:51 -05:00
static struct platform_driver idt82p33_driver = {
2020-02-21 15:03:51 -05:00
. driver = {
2022-03-08 09:10:51 -05:00
. name = " 82p33x1x-phc " ,
2020-02-21 15:03:51 -05:00
} ,
2022-03-08 09:10:51 -05:00
. probe = idt82p33_probe ,
. remove = idt82p33_remove ,
2020-02-21 15:03:51 -05:00
} ;
2022-03-08 09:10:51 -05:00
module_platform_driver ( idt82p33_driver ) ;