2014-11-03 21:07:39 +03:00
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/fs.h>
# include <linux/slab.h>
# include <linux/clk.h>
# include <linux/coresight.h>
# include <linux/amba/bus.h>
# include "coresight-priv.h"
# define FUNNEL_FUNCTL 0x000
# define FUNNEL_PRICTL 0x004
# define FUNNEL_HOLDTIME_MASK 0xf00
# define FUNNEL_HOLDTIME_SHFT 0x8
# define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT)
/**
* struct funnel_drvdata - specifics associated to a funnel component
* @ base : memory mapped base address for this component .
* @ dev : the device entity associated to this component .
* @ csdev : component vitals needed by the framework .
* @ clk : the clock this component is associated to .
* @ priority : port selection order .
*/
struct funnel_drvdata {
void __iomem * base ;
struct device * dev ;
struct coresight_device * csdev ;
struct clk * clk ;
unsigned long priority ;
} ;
static void funnel_enable_hw ( struct funnel_drvdata * drvdata , int port )
{
u32 functl ;
CS_UNLOCK ( drvdata - > base ) ;
functl = readl_relaxed ( drvdata - > base + FUNNEL_FUNCTL ) ;
functl & = ~ FUNNEL_HOLDTIME_MASK ;
functl | = FUNNEL_HOLDTIME ;
functl | = ( 1 < < port ) ;
writel_relaxed ( functl , drvdata - > base + FUNNEL_FUNCTL ) ;
writel_relaxed ( drvdata - > priority , drvdata - > base + FUNNEL_PRICTL ) ;
CS_LOCK ( drvdata - > base ) ;
}
static int funnel_enable ( struct coresight_device * csdev , int inport ,
int outport )
{
struct funnel_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
int ret ;
ret = clk_prepare_enable ( drvdata - > clk ) ;
if ( ret )
return ret ;
funnel_enable_hw ( drvdata , inport ) ;
dev_info ( drvdata - > dev , " FUNNEL inport %d enabled \n " , inport ) ;
return 0 ;
}
static void funnel_disable_hw ( struct funnel_drvdata * drvdata , int inport )
{
u32 functl ;
CS_UNLOCK ( drvdata - > base ) ;
functl = readl_relaxed ( drvdata - > base + FUNNEL_FUNCTL ) ;
functl & = ~ ( 1 < < inport ) ;
writel_relaxed ( functl , drvdata - > base + FUNNEL_FUNCTL ) ;
CS_LOCK ( drvdata - > base ) ;
}
static void funnel_disable ( struct coresight_device * csdev , int inport ,
int outport )
{
struct funnel_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
funnel_disable_hw ( drvdata , inport ) ;
clk_disable_unprepare ( drvdata - > clk ) ;
dev_info ( drvdata - > dev , " FUNNEL inport %d disabled \n " , inport ) ;
}
static const struct coresight_ops_link funnel_link_ops = {
. enable = funnel_enable ,
. disable = funnel_disable ,
} ;
static const struct coresight_ops funnel_cs_ops = {
. link_ops = & funnel_link_ops ,
} ;
static ssize_t priority_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct funnel_drvdata * drvdata = dev_get_drvdata ( dev - > parent ) ;
unsigned long val = drvdata - > priority ;
return sprintf ( buf , " %#lx \n " , val ) ;
}
static ssize_t priority_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t size )
{
int ret ;
unsigned long val ;
struct funnel_drvdata * drvdata = dev_get_drvdata ( dev - > parent ) ;
ret = kstrtoul ( buf , 16 , & val ) ;
if ( ret )
return ret ;
drvdata - > priority = val ;
return size ;
}
static DEVICE_ATTR_RW ( priority ) ;
static u32 get_funnel_ctrl_hw ( struct funnel_drvdata * drvdata )
{
u32 functl ;
CS_UNLOCK ( drvdata - > base ) ;
functl = readl_relaxed ( drvdata - > base + FUNNEL_FUNCTL ) ;
CS_LOCK ( drvdata - > base ) ;
return functl ;
}
static ssize_t funnel_ctrl_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
int ret ;
u32 val ;
struct funnel_drvdata * drvdata = dev_get_drvdata ( dev - > parent ) ;
ret = clk_prepare_enable ( drvdata - > clk ) ;
if ( ret )
return ret ;
val = get_funnel_ctrl_hw ( drvdata ) ;
clk_disable_unprepare ( drvdata - > clk ) ;
return sprintf ( buf , " %#x \n " , val ) ;
}
static DEVICE_ATTR_RO ( funnel_ctrl ) ;
static struct attribute * coresight_funnel_attrs [ ] = {
& dev_attr_funnel_ctrl . attr ,
& dev_attr_priority . attr ,
NULL ,
} ;
ATTRIBUTE_GROUPS ( coresight_funnel ) ;
static int funnel_probe ( struct amba_device * adev , const struct amba_id * id )
{
void __iomem * base ;
struct device * dev = & adev - > dev ;
struct coresight_platform_data * pdata = NULL ;
struct funnel_drvdata * drvdata ;
struct resource * res = & adev - > res ;
struct coresight_desc * desc ;
struct device_node * np = adev - > dev . of_node ;
if ( np ) {
pdata = of_get_coresight_platform_data ( dev , np ) ;
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
adev - > dev . platform_data = pdata ;
}
drvdata = devm_kzalloc ( dev , sizeof ( * drvdata ) , GFP_KERNEL ) ;
if ( ! drvdata )
return - ENOMEM ;
drvdata - > dev = & adev - > dev ;
dev_set_drvdata ( dev , drvdata ) ;
/* Validity for the resource is already checked by the AMBA core */
base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
drvdata - > base = base ;
drvdata - > clk = adev - > pclk ;
desc = devm_kzalloc ( dev , sizeof ( * desc ) , GFP_KERNEL ) ;
if ( ! desc )
return - ENOMEM ;
desc - > type = CORESIGHT_DEV_TYPE_LINK ;
desc - > subtype . link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG ;
desc - > ops = & funnel_cs_ops ;
desc - > pdata = pdata ;
desc - > dev = dev ;
desc - > groups = coresight_funnel_groups ;
drvdata - > csdev = coresight_register ( desc ) ;
if ( IS_ERR ( drvdata - > csdev ) )
return PTR_ERR ( drvdata - > csdev ) ;
dev_info ( dev , " FUNNEL initialized \n " ) ;
return 0 ;
}
static int funnel_remove ( struct amba_device * adev )
{
struct funnel_drvdata * drvdata = amba_get_drvdata ( adev ) ;
coresight_unregister ( drvdata - > csdev ) ;
return 0 ;
}
static struct amba_id funnel_ids [ ] = {
{
. id = 0x0003b908 ,
. mask = 0x0003ffff ,
} ,
{ 0 , 0 } ,
} ;
static struct amba_driver funnel_driver = {
. drv = {
. name = " coresight-funnel " ,
. owner = THIS_MODULE ,
} ,
. probe = funnel_probe ,
. remove = funnel_remove ,
. id_table = funnel_ids ,
} ;
2015-01-10 02:57:14 +03:00
module_amba_driver ( funnel_driver ) ;
2014-11-03 21:07:39 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " CoreSight Funnel driver " ) ;