2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-04-22 14:03:54 +04:00
/*
2018-05-25 07:40:34 +03:00
* PTP 1588 clock for Freescale QorIQ 1588 timer
2011-04-22 14:03:54 +04:00
*
* Copyright ( C ) 2010 OMICRON electronics GmbH
*/
2013-04-13 23:03:18 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2011-04-22 14:03:54 +04:00
# include <linux/device.h>
# include <linux/hrtimer.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_platform.h>
# include <linux/timex.h>
2018-05-25 07:40:34 +03:00
# include <linux/slab.h>
2018-08-01 13:05:54 +03:00
# include <linux/clk.h>
2011-04-22 14:03:54 +04:00
2018-05-25 07:40:35 +03:00
# include <linux/fsl/ptp_qoriq.h>
2018-05-25 07:40:34 +03:00
2011-04-22 14:03:54 +04:00
/*
* Register access functions
*/
2019-02-12 07:23:56 +03:00
/* Caller must hold ptp_qoriq->lock. */
static u64 tmr_cnt_read ( struct ptp_qoriq * ptp_qoriq )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2011-04-22 14:03:54 +04:00
u64 ns ;
u32 lo , hi ;
2019-02-12 07:23:59 +03:00
lo = ptp_qoriq - > read ( & regs - > ctrl_regs - > tmr_cnt_l ) ;
hi = ptp_qoriq - > read ( & regs - > ctrl_regs - > tmr_cnt_h ) ;
2011-04-22 14:03:54 +04:00
ns = ( ( u64 ) hi ) < < 32 ;
ns | = lo ;
return ns ;
}
2019-02-12 07:23:56 +03:00
/* Caller must hold ptp_qoriq->lock. */
static void tmr_cnt_write ( struct ptp_qoriq * ptp_qoriq , u64 ns )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2011-04-22 14:03:54 +04:00
u32 hi = ns > > 32 ;
u32 lo = ns & 0xffffffff ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_cnt_l , lo ) ;
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_cnt_h , hi ) ;
2011-04-22 14:03:54 +04:00
}
2019-02-12 07:23:56 +03:00
/* Caller must hold ptp_qoriq->lock. */
static void set_alarm ( struct ptp_qoriq * ptp_qoriq )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2011-04-22 14:03:54 +04:00
u64 ns ;
u32 lo , hi ;
2019-02-12 07:23:56 +03:00
ns = tmr_cnt_read ( ptp_qoriq ) + 1500000000ULL ;
2011-04-22 14:03:54 +04:00
ns = div_u64 ( ns , 1000000000UL ) * 1000000000ULL ;
2019-02-12 07:23:56 +03:00
ns - = ptp_qoriq - > tclk_period ;
2011-04-22 14:03:54 +04:00
hi = ns > > 32 ;
lo = ns & 0xffffffff ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > alarm_regs - > tmr_alarm1_l , lo ) ;
ptp_qoriq - > write ( & regs - > alarm_regs - > tmr_alarm1_h , hi ) ;
2011-04-22 14:03:54 +04:00
}
2019-02-12 07:23:56 +03:00
/* Caller must hold ptp_qoriq->lock. */
static void set_fipers ( struct ptp_qoriq * ptp_qoriq )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2018-06-25 15:37:08 +03:00
2019-02-12 07:23:56 +03:00
set_alarm ( ptp_qoriq ) ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > fiper_regs - > tmr_fiper1 , ptp_qoriq - > tmr_fiper1 ) ;
ptp_qoriq - > write ( & regs - > fiper_regs - > tmr_fiper2 , ptp_qoriq - > tmr_fiper2 ) ;
2020-09-18 12:48:01 +03:00
if ( ptp_qoriq - > fiper3_support )
ptp_qoriq - > write ( & regs - > fiper_regs - > tmr_fiper3 ,
ptp_qoriq - > tmr_fiper3 ) ;
2011-04-22 14:03:54 +04:00
}
2019-12-12 13:08:05 +03:00
int extts_clean_up ( struct ptp_qoriq * ptp_qoriq , int index , bool update_event )
2019-01-21 13:41:39 +03:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2019-01-21 13:41:39 +03:00
struct ptp_clock_event event ;
void __iomem * reg_etts_l ;
void __iomem * reg_etts_h ;
2019-12-12 13:08:04 +03:00
u32 valid , lo , hi ;
2019-01-21 13:41:39 +03:00
switch ( index ) {
case 0 :
valid = ETS1_VLD ;
reg_etts_l = & regs - > etts_regs - > tmr_etts1_l ;
reg_etts_h = & regs - > etts_regs - > tmr_etts1_h ;
break ;
case 1 :
valid = ETS2_VLD ;
reg_etts_l = & regs - > etts_regs - > tmr_etts2_l ;
reg_etts_h = & regs - > etts_regs - > tmr_etts2_h ;
break ;
default :
return - EINVAL ;
}
event . type = PTP_CLOCK_EXTTS ;
event . index = index ;
2019-12-12 13:08:04 +03:00
if ( ptp_qoriq - > extts_fifo_support )
if ( ! ( ptp_qoriq - > read ( & regs - > ctrl_regs - > tmr_stat ) & valid ) )
return 0 ;
2019-01-21 13:41:39 +03:00
do {
2019-02-12 07:23:59 +03:00
lo = ptp_qoriq - > read ( reg_etts_l ) ;
hi = ptp_qoriq - > read ( reg_etts_h ) ;
2019-01-21 13:41:39 +03:00
if ( update_event ) {
event . timestamp = ( ( u64 ) hi ) < < 32 ;
event . timestamp | = lo ;
2019-02-12 07:23:56 +03:00
ptp_clock_event ( ptp_qoriq - > clock , & event ) ;
2019-01-21 13:41:39 +03:00
}
2019-12-12 13:08:04 +03:00
if ( ! ptp_qoriq - > extts_fifo_support )
break ;
} while ( ptp_qoriq - > read ( & regs - > ctrl_regs - > tmr_stat ) & valid ) ;
2019-01-21 13:41:39 +03:00
return 0 ;
}
2019-12-12 13:08:05 +03:00
EXPORT_SYMBOL_GPL ( extts_clean_up ) ;
2019-01-21 13:41:39 +03:00
2011-04-22 14:03:54 +04:00
/*
* Interrupt service routine
*/
2019-02-12 07:23:57 +03:00
irqreturn_t ptp_qoriq_isr ( int irq , void * priv )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq * ptp_qoriq = priv ;
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2011-04-22 14:03:54 +04:00
struct ptp_clock_event event ;
2020-02-11 07:52:49 +03:00
u32 ack = 0 , mask , val , irqs ;
2019-01-21 13:41:38 +03:00
2019-02-12 07:23:56 +03:00
spin_lock ( & ptp_qoriq - > lock ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:59 +03:00
val = ptp_qoriq - > read ( & regs - > ctrl_regs - > tmr_tevent ) ;
mask = ptp_qoriq - > read ( & regs - > ctrl_regs - > tmr_temask ) ;
2019-01-21 13:41:38 +03:00
2019-02-12 07:23:56 +03:00
spin_unlock ( & ptp_qoriq - > lock ) ;
2019-01-21 13:41:38 +03:00
irqs = val & mask ;
2011-04-22 14:03:54 +04:00
2019-01-21 13:41:38 +03:00
if ( irqs & ETS1 ) {
2011-04-22 14:03:54 +04:00
ack | = ETS1 ;
2019-02-12 07:23:56 +03:00
extts_clean_up ( ptp_qoriq , 0 , true ) ;
2011-04-22 14:03:54 +04:00
}
2019-01-21 13:41:38 +03:00
if ( irqs & ETS2 ) {
2011-04-22 14:03:54 +04:00
ack | = ETS2 ;
2019-02-12 07:23:56 +03:00
extts_clean_up ( ptp_qoriq , 1 , true ) ;
2011-04-22 14:03:54 +04:00
}
2019-01-21 13:41:38 +03:00
if ( irqs & PP1 ) {
2011-04-22 14:03:54 +04:00
ack | = PP1 ;
event . type = PTP_CLOCK_PPS ;
2019-02-12 07:23:56 +03:00
ptp_clock_event ( ptp_qoriq - > clock , & event ) ;
2011-04-22 14:03:54 +04:00
}
if ( ack ) {
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_tevent , ack ) ;
2011-04-22 14:03:54 +04:00
return IRQ_HANDLED ;
} else
return IRQ_NONE ;
}
2019-02-12 07:23:57 +03:00
EXPORT_SYMBOL_GPL ( ptp_qoriq_isr ) ;
2011-04-22 14:03:54 +04:00
/*
* PTP clock operations
*/
2019-02-12 07:23:57 +03:00
int ptp_qoriq_adjfine ( struct ptp_clock_info * ptp , long scaled_ppm )
2011-04-22 14:03:54 +04:00
{
2016-11-23 23:11:04 +03:00
u64 adj , diff ;
u32 tmr_add ;
2011-04-22 14:03:54 +04:00
int neg_adj = 0 ;
2019-02-12 07:23:56 +03:00
struct ptp_qoriq * ptp_qoriq = container_of ( ptp , struct ptp_qoriq , caps ) ;
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2011-04-22 14:03:54 +04:00
2016-11-23 23:11:04 +03:00
if ( scaled_ppm < 0 ) {
2011-04-22 14:03:54 +04:00
neg_adj = 1 ;
2016-11-23 23:11:04 +03:00
scaled_ppm = - scaled_ppm ;
2011-04-22 14:03:54 +04:00
}
2019-02-12 07:23:56 +03:00
tmr_add = ptp_qoriq - > tmr_add ;
2011-04-22 14:03:54 +04:00
adj = tmr_add ;
2016-11-23 23:11:04 +03:00
/* calculate diff as adj*(scaled_ppm/65536)/1000000
* and round ( ) to the nearest integer
*/
adj * = scaled_ppm ;
diff = div_u64 ( adj , 8000000 ) ;
diff = ( diff > > 13 ) + ( ( diff > > 12 ) & 1 ) ;
2011-04-22 14:03:54 +04:00
tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_add , tmr_add ) ;
2011-04-22 14:03:54 +04:00
return 0 ;
}
2019-02-12 07:23:57 +03:00
EXPORT_SYMBOL_GPL ( ptp_qoriq_adjfine ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:57 +03:00
int ptp_qoriq_adjtime ( struct ptp_clock_info * ptp , s64 delta )
2011-04-22 14:03:54 +04:00
{
s64 now ;
unsigned long flags ;
2019-02-12 07:23:56 +03:00
struct ptp_qoriq * ptp_qoriq = container_of ( ptp , struct ptp_qoriq , caps ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_lock_irqsave ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
now = tmr_cnt_read ( ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
now + = delta ;
2019-02-12 07:23:56 +03:00
tmr_cnt_write ( ptp_qoriq , now ) ;
set_fipers ( ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_unlock_irqrestore ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
return 0 ;
}
2019-02-12 07:23:57 +03:00
EXPORT_SYMBOL_GPL ( ptp_qoriq_adjtime ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:57 +03:00
int ptp_qoriq_gettime ( struct ptp_clock_info * ptp , struct timespec64 * ts )
2011-04-22 14:03:54 +04:00
{
u64 ns ;
unsigned long flags ;
2019-02-12 07:23:56 +03:00
struct ptp_qoriq * ptp_qoriq = container_of ( ptp , struct ptp_qoriq , caps ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_lock_irqsave ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
ns = tmr_cnt_read ( ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_unlock_irqrestore ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
2015-04-01 00:08:10 +03:00
* ts = ns_to_timespec64 ( ns ) ;
2011-04-22 14:03:54 +04:00
return 0 ;
}
2019-02-12 07:23:57 +03:00
EXPORT_SYMBOL_GPL ( ptp_qoriq_gettime ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:57 +03:00
int ptp_qoriq_settime ( struct ptp_clock_info * ptp ,
const struct timespec64 * ts )
2011-04-22 14:03:54 +04:00
{
u64 ns ;
unsigned long flags ;
2019-02-12 07:23:56 +03:00
struct ptp_qoriq * ptp_qoriq = container_of ( ptp , struct ptp_qoriq , caps ) ;
2011-04-22 14:03:54 +04:00
2015-04-01 00:08:10 +03:00
ns = timespec64_to_ns ( ts ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_lock_irqsave ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
tmr_cnt_write ( ptp_qoriq , ns ) ;
set_fipers ( ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_unlock_irqrestore ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
return 0 ;
}
2019-02-12 07:23:57 +03:00
EXPORT_SYMBOL_GPL ( ptp_qoriq_settime ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:57 +03:00
int ptp_qoriq_enable ( struct ptp_clock_info * ptp ,
struct ptp_clock_request * rq , int on )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq * ptp_qoriq = container_of ( ptp , struct ptp_qoriq , caps ) ;
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2011-04-22 14:03:54 +04:00
unsigned long flags ;
2019-01-21 13:41:38 +03:00
u32 bit , mask = 0 ;
2011-04-22 14:03:54 +04:00
switch ( rq - > type ) {
case PTP_CLK_REQ_EXTTS :
switch ( rq - > extts . index ) {
case 0 :
bit = ETS1EN ;
break ;
case 1 :
bit = ETS2EN ;
break ;
default :
return - EINVAL ;
}
2019-01-21 13:41:39 +03:00
if ( on )
2019-02-12 07:23:56 +03:00
extts_clean_up ( ptp_qoriq , rq - > extts . index , false ) ;
2019-01-21 13:41:39 +03:00
2019-01-21 13:41:38 +03:00
break ;
2011-04-22 14:03:54 +04:00
case PTP_CLK_REQ_PPS :
2019-01-21 13:41:38 +03:00
bit = PP1EN ;
2011-04-22 14:03:54 +04:00
break ;
2019-01-21 13:41:38 +03:00
default :
return - EOPNOTSUPP ;
}
2019-02-12 07:23:56 +03:00
spin_lock_irqsave ( & ptp_qoriq - > lock , flags ) ;
2019-01-21 13:41:38 +03:00
2019-02-12 07:23:59 +03:00
mask = ptp_qoriq - > read ( & regs - > ctrl_regs - > tmr_temask ) ;
2019-01-21 13:41:38 +03:00
if ( on ) {
mask | = bit ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_tevent , bit ) ;
2019-01-21 13:41:38 +03:00
} else {
mask & = ~ bit ;
2011-04-22 14:03:54 +04:00
}
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_temask , mask ) ;
2019-01-21 13:41:38 +03:00
2019-02-12 07:23:56 +03:00
spin_unlock_irqrestore ( & ptp_qoriq - > lock , flags ) ;
2019-01-21 13:41:38 +03:00
return 0 ;
2011-04-22 14:03:54 +04:00
}
2019-02-12 07:23:57 +03:00
EXPORT_SYMBOL_GPL ( ptp_qoriq_enable ) ;
2011-04-22 14:03:54 +04:00
2018-05-25 07:40:34 +03:00
static const struct ptp_clock_info ptp_qoriq_caps = {
2011-04-22 14:03:54 +04:00
. owner = THIS_MODULE ,
2018-05-25 07:40:34 +03:00
. name = " qoriq ptp clock " ,
2011-04-22 14:03:54 +04:00
. max_adj = 512000 ,
2013-04-22 23:42:16 +04:00
. n_alarm = 0 ,
2011-04-22 14:03:54 +04:00
. n_ext_ts = N_EXT_TS ,
. n_per_out = 0 ,
2014-03-21 01:21:55 +04:00
. n_pins = 0 ,
2011-04-22 14:03:54 +04:00
. pps = 1 ,
2018-05-25 07:40:34 +03:00
. adjfine = ptp_qoriq_adjfine ,
. adjtime = ptp_qoriq_adjtime ,
. gettime64 = ptp_qoriq_gettime ,
. settime64 = ptp_qoriq_settime ,
. enable = ptp_qoriq_enable ,
2011-04-22 14:03:54 +04:00
} ;
2018-08-01 13:05:54 +03:00
/**
2019-02-12 07:23:56 +03:00
* ptp_qoriq_nominal_freq - calculate nominal frequency according to
2018-08-01 13:05:54 +03:00
* reference clock frequency
*
* @ clk_src : reference clock frequency
*
* The nominal frequency is the desired clock frequency .
* It should be less than the reference clock frequency .
* It should be a factor of 1000 MHz .
*
* Return the nominal frequency
*/
2019-02-12 07:23:56 +03:00
static u32 ptp_qoriq_nominal_freq ( u32 clk_src )
2018-08-01 13:05:54 +03:00
{
u32 remainder = 0 ;
clk_src / = 1000000 ;
remainder = clk_src % 100 ;
if ( remainder ) {
clk_src - = remainder ;
clk_src + = 100 ;
}
do {
clk_src - = 100 ;
} while ( 1000 % clk_src ) ;
return clk_src * 1000000 ;
}
/**
2019-02-12 07:23:56 +03:00
* ptp_qoriq_auto_config - calculate a set of default configurations
2018-08-01 13:05:54 +03:00
*
2019-02-12 07:23:56 +03:00
* @ ptp_qoriq : pointer to ptp_qoriq
2018-08-01 13:05:54 +03:00
* @ node : pointer to device_node
*
* If below dts properties are not provided , this function will be
* called to calculate a set of default configurations for them .
* " fsl,tclk-period "
* " fsl,tmr-prsc "
* " fsl,tmr-add "
* " fsl,tmr-fiper1 "
* " fsl,tmr-fiper2 "
2020-09-18 12:48:01 +03:00
* " fsl,tmr-fiper3 " ( required only for DPAA2 and ENETC hardware )
2018-08-01 13:05:54 +03:00
* " fsl,max-adj "
*
* Return 0 if success
*/
2019-02-12 07:23:56 +03:00
static int ptp_qoriq_auto_config ( struct ptp_qoriq * ptp_qoriq ,
2018-08-01 13:05:54 +03:00
struct device_node * node )
{
struct clk * clk ;
u64 freq_comp ;
u64 max_adj ;
u32 nominal_freq ;
2018-08-06 07:39:11 +03:00
u32 remainder = 0 ;
2018-08-01 13:05:54 +03:00
u32 clk_src = 0 ;
2019-02-12 07:23:56 +03:00
ptp_qoriq - > cksel = DEFAULT_CKSEL ;
2018-08-01 13:05:54 +03:00
clk = of_clk_get ( node , 0 ) ;
if ( ! IS_ERR ( clk ) ) {
clk_src = clk_get_rate ( clk ) ;
clk_put ( clk ) ;
}
if ( clk_src < = 100000000UL ) {
pr_err ( " error reference clock value, or lower than 100MHz \n " ) ;
return - EINVAL ;
}
2019-02-12 07:23:56 +03:00
nominal_freq = ptp_qoriq_nominal_freq ( clk_src ) ;
2018-08-01 13:05:54 +03:00
if ( ! nominal_freq )
return - EINVAL ;
2019-02-12 07:23:56 +03:00
ptp_qoriq - > tclk_period = 1000000000UL / nominal_freq ;
ptp_qoriq - > tmr_prsc = DEFAULT_TMR_PRSC ;
2018-08-01 13:05:54 +03:00
/* Calculate initial frequency compensation value for TMR_ADD register.
* freq_comp = ceil ( 2 ^ 32 / freq_ratio )
* freq_ratio = reference_clock_freq / nominal_freq
*/
freq_comp = ( ( u64 ) 1 < < 32 ) * nominal_freq ;
2018-08-06 07:39:11 +03:00
freq_comp = div_u64_rem ( freq_comp , clk_src , & remainder ) ;
if ( remainder )
2018-08-01 13:05:54 +03:00
freq_comp + + ;
2019-02-12 07:23:56 +03:00
ptp_qoriq - > tmr_add = freq_comp ;
ptp_qoriq - > tmr_fiper1 = DEFAULT_FIPER1_PERIOD - ptp_qoriq - > tclk_period ;
ptp_qoriq - > tmr_fiper2 = DEFAULT_FIPER2_PERIOD - ptp_qoriq - > tclk_period ;
2020-09-18 12:48:01 +03:00
ptp_qoriq - > tmr_fiper3 = DEFAULT_FIPER3_PERIOD - ptp_qoriq - > tclk_period ;
2018-08-01 13:05:54 +03:00
/* max_adj = 1000000000 * (freq_ratio - 1.0) - 1
* freq_ratio = reference_clock_freq / nominal_freq
*/
max_adj = 1000000000ULL * ( clk_src - nominal_freq ) ;
2018-08-06 07:39:11 +03:00
max_adj = div_u64 ( max_adj , nominal_freq ) - 1 ;
2019-02-12 07:23:56 +03:00
ptp_qoriq - > caps . max_adj = max_adj ;
2018-08-01 13:05:54 +03:00
return 0 ;
}
2019-02-12 07:23:58 +03:00
int ptp_qoriq_init ( struct ptp_qoriq * ptp_qoriq , void __iomem * base ,
2019-02-19 17:21:20 +03:00
const struct ptp_clock_info * caps )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:58 +03:00
struct device_node * node = ptp_qoriq - > dev - > of_node ;
2019-02-12 07:23:56 +03:00
struct ptp_qoriq_registers * regs ;
2015-03-30 00:11:59 +03:00
struct timespec64 now ;
2011-04-22 14:03:54 +04:00
unsigned long flags ;
2019-02-12 07:23:58 +03:00
u32 tmr_ctrl ;
2011-04-22 14:03:54 +04:00
2019-05-09 06:07:12 +03:00
if ( ! node )
return - ENODEV ;
2019-02-12 07:23:58 +03:00
ptp_qoriq - > base = base ;
2019-02-19 17:21:20 +03:00
ptp_qoriq - > caps = * caps ;
2013-09-27 17:40:27 +04:00
2019-02-12 07:23:56 +03:00
if ( of_property_read_u32 ( node , " fsl,cksel " , & ptp_qoriq - > cksel ) )
ptp_qoriq - > cksel = DEFAULT_CKSEL ;
2011-04-22 14:03:54 +04:00
2019-01-21 13:41:39 +03:00
if ( of_property_read_bool ( node , " fsl,extts-fifo " ) )
2019-02-12 07:23:56 +03:00
ptp_qoriq - > extts_fifo_support = true ;
2019-01-21 13:41:39 +03:00
else
2019-02-12 07:23:56 +03:00
ptp_qoriq - > extts_fifo_support = false ;
2019-01-21 13:41:39 +03:00
2020-09-18 12:48:01 +03:00
if ( of_device_is_compatible ( node , " fsl,dpaa2-ptp " ) | |
of_device_is_compatible ( node , " fsl,enetc-ptp " ) )
ptp_qoriq - > fiper3_support = true ;
2016-02-24 12:26:55 +03:00
if ( of_property_read_u32 ( node ,
2019-02-12 07:23:56 +03:00
" fsl,tclk-period " , & ptp_qoriq - > tclk_period ) | |
2016-02-24 12:26:55 +03:00
of_property_read_u32 ( node ,
2019-02-12 07:23:56 +03:00
" fsl,tmr-prsc " , & ptp_qoriq - > tmr_prsc ) | |
2016-02-24 12:26:55 +03:00
of_property_read_u32 ( node ,
2019-02-12 07:23:56 +03:00
" fsl,tmr-add " , & ptp_qoriq - > tmr_add ) | |
2016-02-24 12:26:55 +03:00
of_property_read_u32 ( node ,
2019-02-12 07:23:56 +03:00
" fsl,tmr-fiper1 " , & ptp_qoriq - > tmr_fiper1 ) | |
2016-02-24 12:26:55 +03:00
of_property_read_u32 ( node ,
2019-02-12 07:23:56 +03:00
" fsl,tmr-fiper2 " , & ptp_qoriq - > tmr_fiper2 ) | |
2016-02-24 12:26:55 +03:00
of_property_read_u32 ( node ,
2020-09-18 12:48:01 +03:00
" fsl,max-adj " , & ptp_qoriq - > caps . max_adj ) | |
( ptp_qoriq - > fiper3_support & &
of_property_read_u32 ( node , " fsl,tmr-fiper3 " ,
& ptp_qoriq - > tmr_fiper3 ) ) ) {
2018-08-01 13:05:54 +03:00
pr_warn ( " device tree node missing required elements, try automatic configuration \n " ) ;
2019-02-12 07:23:56 +03:00
if ( ptp_qoriq_auto_config ( ptp_qoriq , node ) )
2019-02-12 07:23:58 +03:00
return - ENODEV ;
2011-04-22 14:03:54 +04:00
}
2019-02-12 07:23:59 +03:00
if ( of_property_read_bool ( node , " little-endian " ) ) {
ptp_qoriq - > read = qoriq_read_le ;
ptp_qoriq - > write = qoriq_write_le ;
} else {
ptp_qoriq - > read = qoriq_read_be ;
ptp_qoriq - > write = qoriq_write_be ;
}
2019-02-12 07:24:01 +03:00
/* The eTSEC uses differnt memory map with DPAA/ENETC */
if ( of_device_is_compatible ( node , " fsl,etsec-ptp " ) ) {
ptp_qoriq - > regs . ctrl_regs = base + ETSEC_CTRL_REGS_OFFSET ;
ptp_qoriq - > regs . alarm_regs = base + ETSEC_ALARM_REGS_OFFSET ;
ptp_qoriq - > regs . fiper_regs = base + ETSEC_FIPER_REGS_OFFSET ;
ptp_qoriq - > regs . etts_regs = base + ETSEC_ETTS_REGS_OFFSET ;
2018-06-25 15:37:08 +03:00
} else {
2019-02-12 07:23:56 +03:00
ptp_qoriq - > regs . ctrl_regs = base + CTRL_REGS_OFFSET ;
ptp_qoriq - > regs . alarm_regs = base + ALARM_REGS_OFFSET ;
ptp_qoriq - > regs . fiper_regs = base + FIPER_REGS_OFFSET ;
ptp_qoriq - > regs . etts_regs = base + ETTS_REGS_OFFSET ;
2018-06-25 15:37:08 +03:00
}
2019-10-01 22:07:01 +03:00
spin_lock_init ( & ptp_qoriq - > lock ) ;
2018-06-18 17:20:39 +03:00
ktime_get_real_ts64 ( & now ) ;
2019-02-12 07:23:56 +03:00
ptp_qoriq_settime ( & ptp_qoriq - > caps , & now ) ;
2011-04-22 14:03:54 +04:00
tmr_ctrl =
2019-02-12 07:23:56 +03:00
( ptp_qoriq - > tclk_period & TCLK_PERIOD_MASK ) < < TCLK_PERIOD_SHIFT |
( ptp_qoriq - > cksel & CKSEL_MASK ) < < CKSEL_SHIFT ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_lock_irqsave ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
regs = & ptp_qoriq - > regs ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_ctrl , tmr_ctrl ) ;
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_add , ptp_qoriq - > tmr_add ) ;
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_prsc , ptp_qoriq - > tmr_prsc ) ;
ptp_qoriq - > write ( & regs - > fiper_regs - > tmr_fiper1 , ptp_qoriq - > tmr_fiper1 ) ;
ptp_qoriq - > write ( & regs - > fiper_regs - > tmr_fiper2 , ptp_qoriq - > tmr_fiper2 ) ;
2020-09-18 12:48:01 +03:00
if ( ptp_qoriq - > fiper3_support )
ptp_qoriq - > write ( & regs - > fiper_regs - > tmr_fiper3 ,
ptp_qoriq - > tmr_fiper3 ) ;
2019-02-12 07:23:56 +03:00
set_alarm ( ptp_qoriq ) ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_ctrl ,
tmr_ctrl | FIPERST | RTPE | TE | FRD ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
spin_unlock_irqrestore ( & ptp_qoriq - > lock , flags ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:58 +03:00
ptp_qoriq - > clock = ptp_clock_register ( & ptp_qoriq - > caps , ptp_qoriq - > dev ) ;
if ( IS_ERR ( ptp_qoriq - > clock ) )
return PTR_ERR ( ptp_qoriq - > clock ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:58 +03:00
ptp_qoriq - > phc_index = ptp_clock_index ( ptp_qoriq - > clock ) ;
2019-02-12 07:23:56 +03:00
ptp_qoriq_create_debugfs ( ptp_qoriq ) ;
2019-02-12 07:23:58 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( ptp_qoriq_init ) ;
void ptp_qoriq_free ( struct ptp_qoriq * ptp_qoriq )
{
struct ptp_qoriq_registers * regs = & ptp_qoriq - > regs ;
2019-02-12 07:23:59 +03:00
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_temask , 0 ) ;
ptp_qoriq - > write ( & regs - > ctrl_regs - > tmr_ctrl , 0 ) ;
2019-02-12 07:23:58 +03:00
ptp_qoriq_remove_debugfs ( ptp_qoriq ) ;
ptp_clock_unregister ( ptp_qoriq - > clock ) ;
iounmap ( ptp_qoriq - > base ) ;
free_irq ( ptp_qoriq - > irq , ptp_qoriq ) ;
}
EXPORT_SYMBOL_GPL ( ptp_qoriq_free ) ;
static int ptp_qoriq_probe ( struct platform_device * dev )
{
struct ptp_qoriq * ptp_qoriq ;
int err = - ENOMEM ;
void __iomem * base ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:58 +03:00
ptp_qoriq = kzalloc ( sizeof ( * ptp_qoriq ) , GFP_KERNEL ) ;
if ( ! ptp_qoriq )
goto no_memory ;
ptp_qoriq - > dev = & dev - > dev ;
err = - ENODEV ;
ptp_qoriq - > irq = platform_get_irq ( dev , 0 ) ;
if ( ptp_qoriq - > irq < 0 ) {
pr_err ( " irq not in device tree \n " ) ;
goto no_node ;
}
if ( request_irq ( ptp_qoriq - > irq , ptp_qoriq_isr , IRQF_SHARED ,
DRIVER , ptp_qoriq ) ) {
pr_err ( " request_irq failed \n " ) ;
goto no_node ;
}
ptp_qoriq - > rsrc = platform_get_resource ( dev , IORESOURCE_MEM , 0 ) ;
if ( ! ptp_qoriq - > rsrc ) {
pr_err ( " no resource \n " ) ;
goto no_resource ;
}
if ( request_resource ( & iomem_resource , ptp_qoriq - > rsrc ) ) {
pr_err ( " resource busy \n " ) ;
goto no_resource ;
}
base = ioremap ( ptp_qoriq - > rsrc - > start ,
resource_size ( ptp_qoriq - > rsrc ) ) ;
if ( ! base ) {
pr_err ( " ioremap ptp registers failed \n " ) ;
goto no_ioremap ;
}
2019-02-19 17:21:20 +03:00
err = ptp_qoriq_init ( ptp_qoriq , base , & ptp_qoriq_caps ) ;
2019-02-12 07:23:58 +03:00
if ( err )
goto no_clock ;
platform_set_drvdata ( dev , ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
return 0 ;
no_clock :
2019-02-12 07:23:56 +03:00
iounmap ( ptp_qoriq - > base ) ;
2011-04-22 14:03:54 +04:00
no_ioremap :
2019-02-12 07:23:56 +03:00
release_resource ( ptp_qoriq - > rsrc ) ;
2011-04-22 14:03:54 +04:00
no_resource :
2019-02-12 07:23:56 +03:00
free_irq ( ptp_qoriq - > irq , ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
no_node :
2019-02-12 07:23:56 +03:00
kfree ( ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
no_memory :
return err ;
}
2019-02-12 07:23:56 +03:00
static int ptp_qoriq_remove ( struct platform_device * dev )
2011-04-22 14:03:54 +04:00
{
2019-02-12 07:23:56 +03:00
struct ptp_qoriq * ptp_qoriq = platform_get_drvdata ( dev ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:58 +03:00
ptp_qoriq_free ( ptp_qoriq ) ;
2019-02-12 07:23:56 +03:00
release_resource ( ptp_qoriq - > rsrc ) ;
kfree ( ptp_qoriq ) ;
2011-04-22 14:03:54 +04:00
return 0 ;
}
2015-03-17 21:37:34 +03:00
static const struct of_device_id match_table [ ] = {
2011-04-22 14:03:54 +04:00
{ . compatible = " fsl,etsec-ptp " } ,
2018-06-25 15:37:08 +03:00
{ . compatible = " fsl,fman-ptp-timer " } ,
2011-04-22 14:03:54 +04:00
{ } ,
} ;
2015-09-18 18:55:27 +03:00
MODULE_DEVICE_TABLE ( of , match_table ) ;
2011-04-22 14:03:54 +04:00
2019-02-12 07:23:56 +03:00
static struct platform_driver ptp_qoriq_driver = {
2011-04-22 14:03:54 +04:00
. driver = {
2018-05-25 07:40:34 +03:00
. name = " ptp_qoriq " ,
2011-04-22 14:03:54 +04:00
. of_match_table = match_table ,
} ,
2019-02-12 07:23:56 +03:00
. probe = ptp_qoriq_probe ,
. remove = ptp_qoriq_remove ,
2011-04-22 14:03:54 +04:00
} ;
2019-02-12 07:23:56 +03:00
module_platform_driver ( ptp_qoriq_driver ) ;
2011-04-22 14:03:54 +04:00
2012-03-17 02:39:29 +04:00
MODULE_AUTHOR ( " Richard Cochran <richardcochran@gmail.com> " ) ;
2018-05-25 07:40:34 +03:00
MODULE_DESCRIPTION ( " PTP clock for Freescale QorIQ 1588 timer " ) ;
2011-04-22 14:03:54 +04:00
MODULE_LICENSE ( " GPL " ) ;