2019-05-29 17:17:58 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-05-28 02:14:04 +03:00
/*
* Copyright ( c ) 2017 , Linaro Ltd
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/io.h>
# include <linux/slab.h>
# include <linux/of.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
2017-12-05 18:46:56 +03:00
# include <linux/regmap.h>
2017-05-28 02:14:04 +03:00
# include <linux/mailbox_controller.h>
# define QCOM_APCS_IPC_BITS 32
struct qcom_apcs_ipc {
struct mbox_controller mbox ;
struct mbox_chan mbox_chans [ QCOM_APCS_IPC_BITS ] ;
2017-12-05 18:46:56 +03:00
struct regmap * regmap ;
2017-05-28 02:14:04 +03:00
unsigned long offset ;
2017-12-05 18:46:57 +03:00
struct platform_device * clk ;
2017-05-28 02:14:04 +03:00
} ;
2020-06-08 12:37:26 +03:00
struct qcom_apcs_ipc_data {
int offset ;
char * clk_name ;
} ;
2020-06-08 12:37:27 +03:00
static const struct qcom_apcs_ipc_data ipq6018_apcs_data = {
. offset = 8 , . clk_name = " qcom,apss-ipq6018-clk "
} ;
2020-06-08 12:37:26 +03:00
static const struct qcom_apcs_ipc_data msm8916_apcs_data = {
. offset = 8 , . clk_name = " qcom-apcs-msm8916-clk "
} ;
2020-06-24 18:01:03 +03:00
static const struct qcom_apcs_ipc_data msm8994_apcs_data = {
. offset = 8 , . clk_name = NULL
} ;
2020-06-08 12:37:26 +03:00
static const struct qcom_apcs_ipc_data msm8996_apcs_data = {
. offset = 16 , . clk_name = NULL
} ;
static const struct qcom_apcs_ipc_data apps_shared_apcs_data = {
. offset = 12 , . clk_name = NULL
} ;
2021-01-18 07:11:53 +03:00
static const struct qcom_apcs_ipc_data sdx55_apcs_data = {
. offset = 0x1008 , . clk_name = " qcom-sdx55-acps-clk "
} ;
2017-12-05 18:46:56 +03:00
static const struct regmap_config apcs_regmap_config = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
2021-01-18 07:11:53 +03:00
. max_register = 0x1008 ,
2017-12-05 18:46:56 +03:00
. fast_io = true ,
} ;
2017-05-28 02:14:04 +03:00
static int qcom_apcs_ipc_send_data ( struct mbox_chan * chan , void * data )
{
struct qcom_apcs_ipc * apcs = container_of ( chan - > mbox ,
struct qcom_apcs_ipc , mbox ) ;
unsigned long idx = ( unsigned long ) chan - > con_priv ;
2017-12-05 18:46:56 +03:00
return regmap_write ( apcs - > regmap , apcs - > offset , BIT ( idx ) ) ;
2017-05-28 02:14:04 +03:00
}
static const struct mbox_chan_ops qcom_apcs_ipc_ops = {
. send_data = qcom_apcs_ipc_send_data ,
} ;
static int qcom_apcs_ipc_probe ( struct platform_device * pdev )
{
struct qcom_apcs_ipc * apcs ;
2020-06-08 12:37:26 +03:00
const struct qcom_apcs_ipc_data * apcs_data ;
2017-12-05 18:46:56 +03:00
struct regmap * regmap ;
2017-05-28 02:14:04 +03:00
void __iomem * base ;
unsigned long i ;
int ret ;
apcs = devm_kzalloc ( & pdev - > dev , sizeof ( * apcs ) , GFP_KERNEL ) ;
if ( ! apcs )
return - ENOMEM ;
2021-09-07 10:41:39 +03:00
base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2017-05-28 02:14:04 +03:00
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2017-12-05 18:46:56 +03:00
regmap = devm_regmap_init_mmio ( & pdev - > dev , base , & apcs_regmap_config ) ;
if ( IS_ERR ( regmap ) )
return PTR_ERR ( regmap ) ;
2020-06-08 12:37:26 +03:00
apcs_data = of_device_get_match_data ( & pdev - > dev ) ;
2017-05-28 02:14:04 +03:00
2017-12-05 18:46:56 +03:00
apcs - > regmap = regmap ;
2020-06-08 12:37:26 +03:00
apcs - > offset = apcs_data - > offset ;
2017-05-28 02:14:04 +03:00
/* Initialize channel identifiers */
for ( i = 0 ; i < ARRAY_SIZE ( apcs - > mbox_chans ) ; i + + )
apcs - > mbox_chans [ i ] . con_priv = ( void * ) i ;
apcs - > mbox . dev = & pdev - > dev ;
apcs - > mbox . ops = & qcom_apcs_ipc_ops ;
apcs - > mbox . chans = apcs - > mbox_chans ;
apcs - > mbox . num_chans = ARRAY_SIZE ( apcs - > mbox_chans ) ;
2018-12-20 20:19:59 +03:00
ret = devm_mbox_controller_register ( & pdev - > dev , & apcs - > mbox ) ;
2017-05-28 02:14:04 +03:00
if ( ret ) {
dev_err ( & pdev - > dev , " failed to register APCS IPC controller \n " ) ;
return ret ;
}
2020-06-08 12:37:26 +03:00
if ( apcs_data - > clk_name ) {
2017-12-05 18:46:57 +03:00
apcs - > clk = platform_device_register_data ( & pdev - > dev ,
2020-06-08 12:37:26 +03:00
apcs_data - > clk_name ,
2021-06-22 03:39:18 +03:00
PLATFORM_DEVID_AUTO ,
2019-08-29 11:27:59 +03:00
NULL , 0 ) ;
2017-12-05 18:46:57 +03:00
if ( IS_ERR ( apcs - > clk ) )
dev_err ( & pdev - > dev , " failed to register APCS clk \n " ) ;
}
2017-05-28 02:14:04 +03:00
platform_set_drvdata ( pdev , apcs ) ;
return 0 ;
}
static int qcom_apcs_ipc_remove ( struct platform_device * pdev )
{
struct qcom_apcs_ipc * apcs = platform_get_drvdata ( pdev ) ;
2017-12-05 18:46:57 +03:00
struct platform_device * clk = apcs - > clk ;
2017-05-28 02:14:04 +03:00
2017-12-05 18:46:57 +03:00
platform_device_unregister ( clk ) ;
2017-05-28 02:14:04 +03:00
return 0 ;
}
/* .data is the offset of the ipc register within the global block */
static const struct of_device_id qcom_apcs_ipc_of_match [ ] = {
2020-06-08 12:37:27 +03:00
{ . compatible = " qcom,ipq6018-apcs-apps-global " , . data = & ipq6018_apcs_data } ,
2021-09-14 04:40:48 +03:00
{ . compatible = " qcom,ipq8074-apcs-apps-global " , . data = & msm8994_apcs_data } ,
2020-06-08 12:37:26 +03:00
{ . compatible = " qcom,msm8916-apcs-kpss-global " , . data = & msm8916_apcs_data } ,
2021-06-22 03:39:19 +03:00
{ . compatible = " qcom,msm8939-apcs-kpss-global " , . data = & msm8916_apcs_data } ,
2021-08-10 19:44:33 +03:00
{ . compatible = " qcom,msm8953-apcs-kpss-global " , . data = & msm8994_apcs_data } ,
2022-03-07 22:17:23 +03:00
{ . compatible = " qcom,msm8976-apcs-kpss-global " , . data = & msm8994_apcs_data } ,
2020-06-24 18:01:03 +03:00
{ . compatible = " qcom,msm8994-apcs-kpss-global " , . data = & msm8994_apcs_data } ,
2020-06-08 12:37:26 +03:00
{ . compatible = " qcom,msm8996-apcs-hmss-global " , . data = & msm8996_apcs_data } ,
2021-09-14 04:40:48 +03:00
{ . compatible = " qcom,msm8998-apcs-hmss-global " , . data = & msm8994_apcs_data } ,
2021-09-14 04:40:50 +03:00
{ . compatible = " qcom,qcm2290-apcs-hmss-global " , . data = & msm8994_apcs_data } ,
2020-06-08 12:37:26 +03:00
{ . compatible = " qcom,qcs404-apcs-apps-global " , . data = & msm8916_apcs_data } ,
{ . compatible = " qcom,sc7180-apss-shared " , . data = & apps_shared_apcs_data } ,
2021-01-21 04:41:30 +03:00
{ . compatible = " qcom,sc8180x-apss-shared " , . data = & apps_shared_apcs_data } ,
2021-09-14 04:40:48 +03:00
{ . compatible = " qcom,sdm660-apcs-hmss-global " , . data = & msm8994_apcs_data } ,
2020-06-08 12:37:26 +03:00
{ . compatible = " qcom,sdm845-apss-shared " , . data = & apps_shared_apcs_data } ,
2021-09-14 04:40:48 +03:00
{ . compatible = " qcom,sm6125-apcs-hmss-global " , . data = & msm8994_apcs_data } ,
2020-06-08 12:37:26 +03:00
{ . compatible = " qcom,sm8150-apss-shared " , . data = & apps_shared_apcs_data } ,
2021-09-14 04:40:48 +03:00
{ . compatible = " qcom,sm6115-apcs-hmss-global " , . data = & msm8994_apcs_data } ,
2021-01-18 07:11:53 +03:00
{ . compatible = " qcom,sdx55-apcs-gcc " , . data = & sdx55_apcs_data } ,
2017-05-28 02:14:04 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , qcom_apcs_ipc_of_match ) ;
static struct platform_driver qcom_apcs_ipc_driver = {
. probe = qcom_apcs_ipc_probe ,
. remove = qcom_apcs_ipc_remove ,
. driver = {
. name = " qcom_apcs_ipc " ,
. of_match_table = qcom_apcs_ipc_of_match ,
} ,
} ;
static int __init qcom_apcs_ipc_init ( void )
{
return platform_driver_register ( & qcom_apcs_ipc_driver ) ;
}
postcore_initcall ( qcom_apcs_ipc_init ) ;
static void __exit qcom_apcs_ipc_exit ( void )
{
platform_driver_unregister ( & qcom_apcs_ipc_driver ) ;
}
module_exit ( qcom_apcs_ipc_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " Qualcomm APCS IPC driver " ) ;