2018-12-06 15:47:34 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* ARM PL353 SMC driver
*
* Copyright ( C ) 2012 - 2018 Xilinx , Inc
* Author : Punnaiah Choudary Kalluri < punnaiah @ xilinx . com >
* Author : Naga Sureshkumar Relli < nagasure @ xilinx . com >
*/
# include <linux/clk.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <linux/amba/bus.h>
/**
* struct pl353_smc_data - Private smc driver structure
* @ memclk : Pointer to the peripheral clock
2021-06-10 11:20:35 +03:00
* @ aclk : Pointer to the AXI peripheral clock
2018-12-06 15:47:34 +03:00
*/
struct pl353_smc_data {
struct clk * memclk ;
struct clk * aclk ;
} ;
static int __maybe_unused pl353_smc_suspend ( struct device * dev )
{
struct pl353_smc_data * pl353_smc = dev_get_drvdata ( dev ) ;
clk_disable ( pl353_smc - > memclk ) ;
clk_disable ( pl353_smc - > aclk ) ;
return 0 ;
}
static int __maybe_unused pl353_smc_resume ( struct device * dev )
{
struct pl353_smc_data * pl353_smc = dev_get_drvdata ( dev ) ;
2021-06-10 11:20:36 +03:00
int ret ;
2018-12-06 15:47:34 +03:00
ret = clk_enable ( pl353_smc - > aclk ) ;
if ( ret ) {
dev_err ( dev , " Cannot enable axi domain clock. \n " ) ;
return ret ;
}
ret = clk_enable ( pl353_smc - > memclk ) ;
if ( ret ) {
dev_err ( dev , " Cannot enable memory clock. \n " ) ;
clk_disable ( pl353_smc - > aclk ) ;
return ret ;
}
return ret ;
}
static SIMPLE_DEV_PM_OPS ( pl353_smc_dev_pm_ops , pl353_smc_suspend ,
pl353_smc_resume ) ;
static const struct of_device_id pl353_smc_supported_children [ ] = {
{
. compatible = " cfi-flash "
} ,
{
. compatible = " arm,pl353-nand-r2p1 " ,
} ,
{ }
} ;
static int pl353_smc_probe ( struct amba_device * adev , const struct amba_id * id )
{
2021-06-10 11:20:36 +03:00
struct device_node * of_node = adev - > dev . of_node ;
const struct of_device_id * match = NULL ;
2018-12-06 15:47:34 +03:00
struct pl353_smc_data * pl353_smc ;
struct device_node * child ;
int err ;
pl353_smc = devm_kzalloc ( & adev - > dev , sizeof ( * pl353_smc ) , GFP_KERNEL ) ;
if ( ! pl353_smc )
return - ENOMEM ;
pl353_smc - > aclk = devm_clk_get ( & adev - > dev , " apb_pclk " ) ;
if ( IS_ERR ( pl353_smc - > aclk ) ) {
dev_err ( & adev - > dev , " aclk clock not found. \n " ) ;
return PTR_ERR ( pl353_smc - > aclk ) ;
}
pl353_smc - > memclk = devm_clk_get ( & adev - > dev , " memclk " ) ;
if ( IS_ERR ( pl353_smc - > memclk ) ) {
dev_err ( & adev - > dev , " memclk clock not found. \n " ) ;
return PTR_ERR ( pl353_smc - > memclk ) ;
}
err = clk_prepare_enable ( pl353_smc - > aclk ) ;
if ( err ) {
dev_err ( & adev - > dev , " Unable to enable AXI clock. \n " ) ;
return err ;
}
err = clk_prepare_enable ( pl353_smc - > memclk ) ;
if ( err ) {
dev_err ( & adev - > dev , " Unable to enable memory clock. \n " ) ;
2021-06-10 11:20:33 +03:00
goto disable_axi_clk ;
2018-12-06 15:47:34 +03:00
}
amba_set_drvdata ( adev , pl353_smc ) ;
/* Find compatible children. Only a single child is supported */
for_each_available_child_of_node ( of_node , child ) {
match = of_match_node ( pl353_smc_supported_children , child ) ;
if ( ! match ) {
dev_warn ( & adev - > dev , " unsupported child node \n " ) ;
continue ;
}
break ;
}
if ( ! match ) {
2021-05-15 07:00:04 +03:00
err = - ENODEV ;
2018-12-06 15:47:34 +03:00
dev_err ( & adev - > dev , " no matching children \n " ) ;
2021-06-10 11:20:33 +03:00
goto disable_mem_clk ;
2018-12-06 15:47:34 +03:00
}
of_platform_device_create ( child , NULL , & adev - > dev ) ;
2022-07-16 06:13:24 +03:00
of_node_put ( child ) ;
2018-12-06 15:47:34 +03:00
return 0 ;
2021-06-10 11:20:33 +03:00
disable_mem_clk :
2018-12-06 15:47:34 +03:00
clk_disable_unprepare ( pl353_smc - > memclk ) ;
2021-06-10 11:20:33 +03:00
disable_axi_clk :
2018-12-06 15:47:34 +03:00
clk_disable_unprepare ( pl353_smc - > aclk ) ;
return err ;
}
2021-01-26 19:58:34 +03:00
static void pl353_smc_remove ( struct amba_device * adev )
2018-12-06 15:47:34 +03:00
{
struct pl353_smc_data * pl353_smc = amba_get_drvdata ( adev ) ;
clk_disable_unprepare ( pl353_smc - > memclk ) ;
clk_disable_unprepare ( pl353_smc - > aclk ) ;
}
static const struct amba_id pl353_ids [ ] = {
{
2021-06-10 11:20:32 +03:00
. id = 0x00041353 ,
. mask = 0x000fffff ,
2018-12-06 15:47:34 +03:00
} ,
{ 0 , 0 } ,
} ;
MODULE_DEVICE_TABLE ( amba , pl353_ids ) ;
static struct amba_driver pl353_smc_driver = {
. drv = {
. owner = THIS_MODULE ,
. name = " pl353-smc " ,
. pm = & pl353_smc_dev_pm_ops ,
} ,
. id_table = pl353_ids ,
. probe = pl353_smc_probe ,
. remove = pl353_smc_remove ,
} ;
module_amba_driver ( pl353_smc_driver ) ;
MODULE_AUTHOR ( " Xilinx, Inc. " ) ;
MODULE_DESCRIPTION ( " ARM PL353 SMC Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;