2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-12-07 13:58:11 +03:00
/*
* Copyright ( c ) 2015 MediaTek Inc .
* Author : Andrew - CT Chen < andrew - ct . chen @ mediatek . com >
*/
# include <linux/device.h>
# include <linux/module.h>
2018-06-20 08:47:28 +03:00
# include <linux/mod_devicetable.h>
2016-05-02 21:36:13 +03:00
# include <linux/io.h>
2015-12-07 13:58:11 +03:00
# include <linux/nvmem-provider.h>
# include <linux/platform_device.h>
2023-04-04 20:21:35 +03:00
# include <linux/property.h>
struct mtk_efuse_pdata {
bool uses_post_processing ;
} ;
2015-12-07 13:58:11 +03:00
2017-10-20 19:57:40 +03:00
struct mtk_efuse_priv {
void __iomem * base ;
} ;
2016-05-02 21:36:13 +03:00
static int mtk_reg_read ( void * context ,
unsigned int reg , void * _val , size_t bytes )
{
2017-10-20 19:57:40 +03:00
struct mtk_efuse_priv * priv = context ;
2021-12-09 20:42:34 +03:00
void __iomem * addr = priv - > base + reg ;
u8 * val = _val ;
int i ;
2016-05-02 21:36:13 +03:00
2021-12-09 20:42:34 +03:00
for ( i = 0 ; i < bytes ; i + + , val + + )
* val = readb ( addr + i ) ;
2016-05-02 21:36:13 +03:00
return 0 ;
}
2023-04-04 20:21:35 +03:00
static int mtk_efuse_gpu_speedbin_pp ( void * context , const char * id , int index ,
unsigned int offset , void * data , size_t bytes )
{
u8 * val = data ;
if ( val [ 0 ] < 8 )
val [ 0 ] = BIT ( val [ 0 ] ) ;
return 0 ;
}
2023-12-15 14:15:31 +03:00
static void mtk_efuse_fixup_dt_cell_info ( struct nvmem_device * nvmem ,
struct nvmem_cell_info * cell )
2023-04-04 20:21:35 +03:00
{
size_t sz = strlen ( cell - > name ) ;
/*
* On some SoCs , the GPU speedbin is not read as bitmask but as
* a number with range [ 0 - 7 ] ( max 3 bits ) : post process to use
* it in OPP tables to describe supported - hw .
*/
if ( cell - > nbits < = 3 & &
strncmp ( cell - > name , " gpu-speedbin " , min ( sz , strlen ( " gpu-speedbin " ) ) ) = = 0 )
cell - > read_post_process = mtk_efuse_gpu_speedbin_pp ;
}
2015-12-07 13:58:11 +03:00
static int mtk_efuse_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct resource * res ;
struct nvmem_device * nvmem ;
2017-10-20 19:57:39 +03:00
struct nvmem_config econfig = { } ;
2017-10-20 19:57:40 +03:00
struct mtk_efuse_priv * priv ;
2023-04-04 20:21:35 +03:00
const struct mtk_efuse_pdata * pdata ;
2017-10-20 19:57:40 +03:00
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2015-12-07 13:58:11 +03:00
2022-07-06 13:06:27 +03:00
priv - > base = devm_platform_get_and_ioremap_resource ( pdev , 0 , & res ) ;
2017-10-20 19:57:40 +03:00
if ( IS_ERR ( priv - > base ) )
return PTR_ERR ( priv - > base ) ;
2015-12-07 13:58:11 +03:00
2023-04-04 20:21:35 +03:00
pdata = device_get_match_data ( dev ) ;
2023-10-20 13:55:41 +03:00
econfig . add_legacy_fixed_of_cells = true ;
2021-12-09 20:42:34 +03:00
econfig . stride = 1 ;
econfig . word_size = 1 ;
2017-10-20 19:57:39 +03:00
econfig . reg_read = mtk_reg_read ;
econfig . size = resource_size ( res ) ;
2017-10-20 19:57:40 +03:00
econfig . priv = priv ;
2017-10-20 19:57:39 +03:00
econfig . dev = dev ;
2023-04-04 20:21:35 +03:00
if ( pdata - > uses_post_processing )
2023-12-15 14:15:31 +03:00
econfig . fixup_dt_cell_info = & mtk_efuse_fixup_dt_cell_info ;
2018-03-09 17:47:03 +03:00
nvmem = devm_nvmem_register ( dev , & econfig ) ;
2015-12-07 13:58:11 +03:00
2018-03-09 17:47:03 +03:00
return PTR_ERR_OR_ZERO ( nvmem ) ;
2015-12-07 13:58:11 +03:00
}
2023-04-04 20:21:35 +03:00
static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = {
. uses_post_processing = true ,
} ;
static const struct mtk_efuse_pdata mtk_efuse_pdata = {
. uses_post_processing = false ,
} ;
2015-12-07 13:58:11 +03:00
static const struct of_device_id mtk_efuse_of_match [ ] = {
2023-04-04 20:21:35 +03:00
{ . compatible = " mediatek,mt8173-efuse " , . data = & mtk_efuse_pdata } ,
{ . compatible = " mediatek,mt8186-efuse " , . data = & mtk_mt8186_efuse_pdata } ,
{ . compatible = " mediatek,efuse " , . data = & mtk_efuse_pdata } ,
2015-12-07 13:58:11 +03:00
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , mtk_efuse_of_match ) ;
static struct platform_driver mtk_efuse_driver = {
. probe = mtk_efuse_probe ,
. driver = {
. name = " mediatek,efuse " ,
. of_match_table = mtk_efuse_of_match ,
} ,
} ;
2016-02-22 14:24:05 +03:00
static int __init mtk_efuse_init ( void )
{
int ret ;
ret = platform_driver_register ( & mtk_efuse_driver ) ;
if ( ret ) {
pr_err ( " Failed to register efuse driver \n " ) ;
return ret ;
}
return 0 ;
}
static void __exit mtk_efuse_exit ( void )
{
return platform_driver_unregister ( & mtk_efuse_driver ) ;
}
subsys_initcall ( mtk_efuse_init ) ;
module_exit ( mtk_efuse_exit ) ;
2015-12-07 13:58:11 +03:00
MODULE_AUTHOR ( " Andrew-CT Chen <andrew-ct.chen@mediatek.com> " ) ;
MODULE_DESCRIPTION ( " Mediatek EFUSE driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;