2018-04-23 11:55:00 +08:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2013 - 2016 Freescale Semiconductor Inc .
* Copyright 2016 - 2018 NXP
2020-09-18 17:07:59 +08:00
* Copyright 2020 NXP
2018-04-23 11:55:00 +08:00
*/
# include <linux/module.h>
2019-06-14 18:40:51 +08:00
# include <linux/of.h>
# include <linux/of_address.h>
2019-06-14 18:40:54 +08:00
# include <linux/msi.h>
2018-04-23 11:55:00 +08:00
# include <linux/fsl/mc.h>
2018-10-08 15:44:25 +08:00
# include "dpaa2-ptp.h"
2018-04-23 11:55:00 +08:00
2019-06-14 18:40:54 +08:00
static int dpaa2_ptp_enable ( struct ptp_clock_info * ptp ,
struct ptp_clock_request * rq , int on )
{
struct ptp_qoriq * ptp_qoriq = container_of ( ptp , struct ptp_qoriq , caps ) ;
struct fsl_mc_device * mc_dev ;
struct device * dev ;
u32 mask = 0 ;
u32 bit ;
int err ;
dev = ptp_qoriq - > dev ;
mc_dev = to_fsl_mc_device ( dev ) ;
switch ( rq - > type ) {
2019-12-12 18:08:06 +08:00
case PTP_CLK_REQ_EXTTS :
switch ( rq - > extts . index ) {
case 0 :
bit = DPRTC_EVENT_ETS1 ;
break ;
case 1 :
bit = DPRTC_EVENT_ETS2 ;
break ;
default :
return - EINVAL ;
}
if ( on )
extts_clean_up ( ptp_qoriq , rq - > extts . index , false ) ;
break ;
2019-06-14 18:40:54 +08:00
case PTP_CLK_REQ_PPS :
bit = DPRTC_EVENT_PPS ;
break ;
default :
return - EOPNOTSUPP ;
}
err = dprtc_get_irq_mask ( mc_dev - > mc_io , 0 , mc_dev - > mc_handle ,
DPRTC_IRQ_INDEX , & mask ) ;
if ( err < 0 ) {
dev_err ( dev , " dprtc_get_irq_mask(): %d \n " , err ) ;
return err ;
}
if ( on )
mask | = bit ;
else
mask & = ~ bit ;
err = dprtc_set_irq_mask ( mc_dev - > mc_io , 0 , mc_dev - > mc_handle ,
DPRTC_IRQ_INDEX , mask ) ;
if ( err < 0 ) {
dev_err ( dev , " dprtc_set_irq_mask(): %d \n " , err ) ;
return err ;
}
return 0 ;
}
2019-06-14 18:40:51 +08:00
static const struct ptp_clock_info dpaa2_ptp_caps = {
2018-04-23 11:55:00 +08:00
. owner = THIS_MODULE ,
. name = " DPAA2 PTP Clock " ,
. max_adj = 512000 ,
. n_alarm = 2 ,
. n_ext_ts = 2 ,
. n_per_out = 3 ,
. n_pins = 0 ,
. pps = 1 ,
2019-06-14 18:40:51 +08:00
. adjfine = ptp_qoriq_adjfine ,
. adjtime = ptp_qoriq_adjtime ,
. gettime64 = ptp_qoriq_gettime ,
. settime64 = ptp_qoriq_settime ,
2019-06-14 18:40:54 +08:00
. enable = dpaa2_ptp_enable ,
2018-04-23 11:55:00 +08:00
} ;
2019-06-14 18:40:54 +08:00
static irqreturn_t dpaa2_ptp_irq_handler_thread ( int irq , void * priv )
{
struct ptp_qoriq * ptp_qoriq = priv ;
struct ptp_clock_event event ;
struct fsl_mc_device * mc_dev ;
struct device * dev ;
u32 status = 0 ;
int err ;
dev = ptp_qoriq - > dev ;
mc_dev = to_fsl_mc_device ( dev ) ;
err = dprtc_get_irq_status ( mc_dev - > mc_io , 0 , mc_dev - > mc_handle ,
DPRTC_IRQ_INDEX , & status ) ;
if ( unlikely ( err ) ) {
dev_err ( dev , " dprtc_get_irq_status err %d \n " , err ) ;
return IRQ_NONE ;
}
if ( status & DPRTC_EVENT_PPS ) {
event . type = PTP_CLOCK_PPS ;
ptp_clock_event ( ptp_qoriq - > clock , & event ) ;
}
2019-12-12 18:08:06 +08:00
if ( status & DPRTC_EVENT_ETS1 )
extts_clean_up ( ptp_qoriq , 0 , true ) ;
if ( status & DPRTC_EVENT_ETS2 )
extts_clean_up ( ptp_qoriq , 1 , true ) ;
2019-06-14 18:40:54 +08:00
err = dprtc_clear_irq_status ( mc_dev - > mc_io , 0 , mc_dev - > mc_handle ,
DPRTC_IRQ_INDEX , status ) ;
if ( unlikely ( err ) ) {
dev_err ( dev , " dprtc_clear_irq_status err %d \n " , err ) ;
return IRQ_NONE ;
}
return IRQ_HANDLED ;
}
2018-10-08 15:44:28 +08:00
static int dpaa2_ptp_probe ( struct fsl_mc_device * mc_dev )
2018-04-23 11:55:00 +08:00
{
struct device * dev = & mc_dev - > dev ;
2019-06-14 18:40:54 +08:00
struct fsl_mc_device_irq * irq ;
2019-06-14 18:40:51 +08:00
struct ptp_qoriq * ptp_qoriq ;
struct device_node * node ;
void __iomem * base ;
2018-04-23 11:55:00 +08:00
int err ;
2019-06-14 18:40:51 +08:00
ptp_qoriq = devm_kzalloc ( dev , sizeof ( * ptp_qoriq ) , GFP_KERNEL ) ;
if ( ! ptp_qoriq )
2018-04-23 11:55:00 +08:00
return - ENOMEM ;
err = fsl_mc_portal_allocate ( mc_dev , 0 , & mc_dev - > mc_io ) ;
if ( err ) {
2018-11-09 15:26:46 +00:00
if ( err = = - ENXIO )
err = - EPROBE_DEFER ;
else
dev_err ( dev , " fsl_mc_portal_allocate err %d \n " , err ) ;
2018-04-23 11:55:00 +08:00
goto err_exit ;
}
err = dprtc_open ( mc_dev - > mc_io , 0 , mc_dev - > obj_desc . id ,
& mc_dev - > mc_handle ) ;
if ( err ) {
dev_err ( dev , " dprtc_open err %d \n " , err ) ;
goto err_free_mcp ;
}
2019-06-14 18:40:51 +08:00
ptp_qoriq - > dev = dev ;
2018-04-23 11:55:00 +08:00
2019-06-14 18:40:51 +08:00
node = of_find_compatible_node ( NULL , NULL , " fsl,dpaa2-ptp " ) ;
if ( ! node ) {
err = - ENODEV ;
2018-04-23 11:55:00 +08:00
goto err_close ;
}
2019-06-14 18:40:51 +08:00
dev - > of_node = node ;
2018-04-23 11:55:00 +08:00
2019-06-14 18:40:51 +08:00
base = of_iomap ( node , 0 ) ;
if ( ! base ) {
err = - ENOMEM ;
2018-04-23 11:55:00 +08:00
goto err_close ;
}
2019-06-14 18:40:54 +08:00
err = fsl_mc_allocate_irqs ( mc_dev ) ;
if ( err ) {
dev_err ( dev , " MC irqs allocation failed \n " ) ;
goto err_unmap ;
}
irq = mc_dev - > irqs [ 0 ] ;
ptp_qoriq - > irq = irq - > msi_desc - > irq ;
2019-12-16 17:32:30 +02:00
err = request_threaded_irq ( ptp_qoriq - > irq , NULL ,
dpaa2_ptp_irq_handler_thread ,
IRQF_NO_SUSPEND | IRQF_ONESHOT ,
dev_name ( dev ) , ptp_qoriq ) ;
2019-06-14 18:40:54 +08:00
if ( err < 0 ) {
dev_err ( dev , " devm_request_threaded_irq(): %d \n " , err ) ;
goto err_free_mc_irq ;
}
err = dprtc_set_irq_enable ( mc_dev - > mc_io , 0 , mc_dev - > mc_handle ,
DPRTC_IRQ_INDEX , 1 ) ;
if ( err < 0 ) {
dev_err ( dev , " dprtc_set_irq_enable(): %d \n " , err ) ;
2019-12-16 17:32:30 +02:00
goto err_free_threaded_irq ;
2019-06-14 18:40:54 +08:00
}
2019-06-14 18:40:51 +08:00
err = ptp_qoriq_init ( ptp_qoriq , base , & dpaa2_ptp_caps ) ;
if ( err )
2019-12-16 17:32:30 +02:00
goto err_free_threaded_irq ;
2018-04-23 11:55:00 +08:00
2019-06-14 18:40:51 +08:00
dpaa2_phc_index = ptp_qoriq - > phc_index ;
2020-09-18 17:07:59 +08:00
dpaa2_ptp = ptp_qoriq ;
2019-06-14 18:40:51 +08:00
dev_set_drvdata ( dev , ptp_qoriq ) ;
2018-04-23 11:55:00 +08:00
return 0 ;
2019-12-16 17:32:30 +02:00
err_free_threaded_irq :
free_irq ( ptp_qoriq - > irq , ptp_qoriq ) ;
2019-06-14 18:40:54 +08:00
err_free_mc_irq :
fsl_mc_free_irqs ( mc_dev ) ;
2019-06-14 18:40:51 +08:00
err_unmap :
iounmap ( base ) ;
2018-04-23 11:55:00 +08:00
err_close :
dprtc_close ( mc_dev - > mc_io , 0 , mc_dev - > mc_handle ) ;
err_free_mcp :
fsl_mc_portal_free ( mc_dev - > mc_io ) ;
err_exit :
return err ;
}
2018-10-08 15:44:28 +08:00
static int dpaa2_ptp_remove ( struct fsl_mc_device * mc_dev )
2018-04-23 11:55:00 +08:00
{
struct device * dev = & mc_dev - > dev ;
2019-06-14 18:40:51 +08:00
struct ptp_qoriq * ptp_qoriq ;
ptp_qoriq = dev_get_drvdata ( dev ) ;
2018-04-23 11:55:00 +08:00
2019-06-14 18:40:51 +08:00
dpaa2_phc_index = - 1 ;
ptp_qoriq_free ( ptp_qoriq ) ;
2018-04-23 11:55:00 +08:00
2019-06-14 18:40:54 +08:00
fsl_mc_free_irqs ( mc_dev ) ;
2018-04-23 11:55:00 +08:00
dprtc_close ( mc_dev - > mc_io , 0 , mc_dev - > mc_handle ) ;
fsl_mc_portal_free ( mc_dev - > mc_io ) ;
return 0 ;
}
2018-10-08 15:44:28 +08:00
static const struct fsl_mc_device_id dpaa2_ptp_match_id_table [ ] = {
2018-04-23 11:55:00 +08:00
{
. vendor = FSL_MC_VENDOR_FREESCALE ,
. obj_type = " dprtc " ,
} ,
{ }
} ;
2018-10-08 15:44:28 +08:00
MODULE_DEVICE_TABLE ( fslmc , dpaa2_ptp_match_id_table ) ;
2018-04-23 11:55:00 +08:00
2018-10-08 15:44:28 +08:00
static struct fsl_mc_driver dpaa2_ptp_drv = {
2018-04-23 11:55:00 +08:00
. driver = {
. name = KBUILD_MODNAME ,
. owner = THIS_MODULE ,
} ,
2018-10-08 15:44:28 +08:00
. probe = dpaa2_ptp_probe ,
. remove = dpaa2_ptp_remove ,
. match_id_table = dpaa2_ptp_match_id_table ,
2018-04-23 11:55:00 +08:00
} ;
2018-10-08 15:44:28 +08:00
module_fsl_mc_driver ( dpaa2_ptp_drv ) ;
2018-04-23 11:55:00 +08:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " DPAA2 PTP Clock Driver " ) ;