2018-08-29 22:12:11 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2018 The Linux Foundation . All rights reserved .
*/
# include <linux/module.h>
2023-07-14 20:49:37 +03:00
# include <linux/of.h>
2018-08-29 22:12:11 +03:00
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/reset-controller.h>
# include <dt-bindings/reset/qcom,sdm845-pdc.h>
2021-04-29 13:51:04 +03:00
# define RPMH_SDM845_PDC_SYNC_RESET 0x100
# define RPMH_SC7280_PDC_SYNC_RESET 0x1000
2018-08-29 22:12:11 +03:00
struct qcom_pdc_reset_map {
u8 bit ;
} ;
2021-04-29 13:51:04 +03:00
struct qcom_pdc_reset_desc {
const struct qcom_pdc_reset_map * resets ;
size_t num_resets ;
unsigned int offset ;
} ;
2018-08-29 22:12:11 +03:00
struct qcom_pdc_reset_data {
struct reset_controller_dev rcdev ;
struct regmap * regmap ;
2021-04-29 13:51:04 +03:00
const struct qcom_pdc_reset_desc * desc ;
2018-08-29 22:12:11 +03:00
} ;
2021-04-29 13:51:04 +03:00
static const struct regmap_config pdc_regmap_config = {
2018-08-29 22:12:11 +03:00
. name = " pdc-reset " ,
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
. max_register = 0x20000 ,
. fast_io = true ,
} ;
static const struct qcom_pdc_reset_map sdm845_pdc_resets [ ] = {
[ PDC_APPS_SYNC_RESET ] = { 0 } ,
[ PDC_SP_SYNC_RESET ] = { 1 } ,
[ PDC_AUDIO_SYNC_RESET ] = { 2 } ,
[ PDC_SENSORS_SYNC_RESET ] = { 3 } ,
[ PDC_AOP_SYNC_RESET ] = { 4 } ,
[ PDC_DEBUG_SYNC_RESET ] = { 5 } ,
[ PDC_GPU_SYNC_RESET ] = { 6 } ,
[ PDC_DISPLAY_SYNC_RESET ] = { 7 } ,
[ PDC_COMPUTE_SYNC_RESET ] = { 8 } ,
[ PDC_MODEM_SYNC_RESET ] = { 9 } ,
} ;
2021-04-29 13:51:04 +03:00
static const struct qcom_pdc_reset_desc sdm845_pdc_reset_desc = {
. resets = sdm845_pdc_resets ,
. num_resets = ARRAY_SIZE ( sdm845_pdc_resets ) ,
. offset = RPMH_SDM845_PDC_SYNC_RESET ,
} ;
static const struct qcom_pdc_reset_map sc7280_pdc_resets [ ] = {
[ PDC_APPS_SYNC_RESET ] = { 0 } ,
[ PDC_SP_SYNC_RESET ] = { 1 } ,
[ PDC_AUDIO_SYNC_RESET ] = { 2 } ,
[ PDC_SENSORS_SYNC_RESET ] = { 3 } ,
[ PDC_AOP_SYNC_RESET ] = { 4 } ,
[ PDC_DEBUG_SYNC_RESET ] = { 5 } ,
[ PDC_GPU_SYNC_RESET ] = { 6 } ,
[ PDC_DISPLAY_SYNC_RESET ] = { 7 } ,
[ PDC_COMPUTE_SYNC_RESET ] = { 8 } ,
[ PDC_MODEM_SYNC_RESET ] = { 9 } ,
[ PDC_WLAN_RF_SYNC_RESET ] = { 10 } ,
[ PDC_WPSS_SYNC_RESET ] = { 11 } ,
} ;
static const struct qcom_pdc_reset_desc sc7280_pdc_reset_desc = {
. resets = sc7280_pdc_resets ,
. num_resets = ARRAY_SIZE ( sc7280_pdc_resets ) ,
. offset = RPMH_SC7280_PDC_SYNC_RESET ,
} ;
2018-08-29 22:12:11 +03:00
static inline struct qcom_pdc_reset_data * to_qcom_pdc_reset_data (
struct reset_controller_dev * rcdev )
{
return container_of ( rcdev , struct qcom_pdc_reset_data , rcdev ) ;
}
static int qcom_pdc_control_assert ( struct reset_controller_dev * rcdev ,
unsigned long idx )
{
struct qcom_pdc_reset_data * data = to_qcom_pdc_reset_data ( rcdev ) ;
2021-04-29 13:51:04 +03:00
u32 mask = BIT ( data - > desc - > resets [ idx ] . bit ) ;
2018-08-29 22:12:11 +03:00
2021-04-29 13:51:04 +03:00
return regmap_update_bits ( data - > regmap , data - > desc - > offset , mask , mask ) ;
2018-08-29 22:12:11 +03:00
}
static int qcom_pdc_control_deassert ( struct reset_controller_dev * rcdev ,
unsigned long idx )
{
struct qcom_pdc_reset_data * data = to_qcom_pdc_reset_data ( rcdev ) ;
2021-04-29 13:51:04 +03:00
u32 mask = BIT ( data - > desc - > resets [ idx ] . bit ) ;
2018-08-29 22:12:11 +03:00
2021-04-29 13:51:04 +03:00
return regmap_update_bits ( data - > regmap , data - > desc - > offset , mask , 0 ) ;
2018-08-29 22:12:11 +03:00
}
static const struct reset_control_ops qcom_pdc_reset_ops = {
. assert = qcom_pdc_control_assert ,
. deassert = qcom_pdc_control_deassert ,
} ;
static int qcom_pdc_reset_probe ( struct platform_device * pdev )
{
2021-04-29 13:51:04 +03:00
const struct qcom_pdc_reset_desc * desc ;
2018-08-29 22:12:11 +03:00
struct qcom_pdc_reset_data * data ;
struct device * dev = & pdev - > dev ;
void __iomem * base ;
struct resource * res ;
2021-04-29 13:51:04 +03:00
desc = device_get_match_data ( & pdev - > dev ) ;
if ( ! desc )
return - EINVAL ;
2018-08-29 22:12:11 +03:00
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2021-04-29 13:51:04 +03:00
data - > desc = desc ;
2018-08-29 22:12:11 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2021-04-29 13:51:04 +03:00
data - > regmap = devm_regmap_init_mmio ( dev , base , & pdc_regmap_config ) ;
2018-08-29 22:12:11 +03:00
if ( IS_ERR ( data - > regmap ) ) {
dev_err ( dev , " Unable to initialize regmap \n " ) ;
return PTR_ERR ( data - > regmap ) ;
}
data - > rcdev . owner = THIS_MODULE ;
data - > rcdev . ops = & qcom_pdc_reset_ops ;
2021-04-29 13:51:04 +03:00
data - > rcdev . nr_resets = desc - > num_resets ;
2018-08-29 22:12:11 +03:00
data - > rcdev . of_node = dev - > of_node ;
return devm_reset_controller_register ( dev , & data - > rcdev ) ;
}
static const struct of_device_id qcom_pdc_reset_of_match [ ] = {
2021-04-29 13:51:04 +03:00
{ . compatible = " qcom,sc7280-pdc-global " , . data = & sc7280_pdc_reset_desc } ,
{ . compatible = " qcom,sdm845-pdc-global " , . data = & sdm845_pdc_reset_desc } ,
2018-08-29 22:12:11 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , qcom_pdc_reset_of_match ) ;
static struct platform_driver qcom_pdc_reset_driver = {
. probe = qcom_pdc_reset_probe ,
. driver = {
. name = " qcom_pdc_reset " ,
. of_match_table = qcom_pdc_reset_of_match ,
} ,
} ;
module_platform_driver ( qcom_pdc_reset_driver ) ;
MODULE_DESCRIPTION ( " Qualcomm PDC Reset Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;