2019-08-13 17:08:19 +02:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2019 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com/
2020-12-07 19:54:57 +01:00
* Copyright ( c ) 2020 Krzysztof Kozlowski < krzk @ kernel . org >
2019-08-13 17:08:19 +02:00
*
2020-01-04 16:20:52 +01:00
* Exynos - CHIP ID support
2019-08-13 17:08:19 +02:00
* Author : Pankaj Dubey < pankaj . dubey @ samsung . com >
* Author : Bartlomiej Zolnierkiewicz < b . zolnierkie @ samsung . com >
2020-12-07 19:54:57 +01:00
* Author : Krzysztof Kozlowski < krzk @ kernel . org >
*
* Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support
2019-08-13 17:08:19 +02:00
*/
2020-12-07 19:54:57 +01:00
# include <linux/device.h>
# include <linux/errno.h>
2019-08-13 17:08:20 +02:00
# include <linux/mfd/syscon.h>
2019-08-13 17:08:19 +02:00
# include <linux/of.h>
2020-12-07 19:54:57 +01:00
# include <linux/platform_device.h>
2019-08-13 17:08:20 +02:00
# include <linux/regmap.h>
2019-08-13 17:08:19 +02:00
# include <linux/slab.h>
2019-08-13 17:08:20 +02:00
# include <linux/soc/samsung/exynos-chipid.h>
2019-08-13 17:08:19 +02:00
# include <linux/sys_soc.h>
2020-12-07 19:54:57 +01:00
# include "exynos-asv.h"
2019-08-13 17:08:19 +02:00
static const struct exynos_soc_id {
const char * name ;
unsigned int id ;
} soc_ids [ ] = {
2020-12-02 21:59:54 +02:00
/* List ordered by SoC name */
2019-08-13 17:08:19 +02:00
{ " EXYNOS3250 " , 0xE3472000 } ,
{ " EXYNOS4210 " , 0x43200000 } , /* EVT0 revision */
{ " EXYNOS4210 " , 0x43210000 } ,
{ " EXYNOS4212 " , 0x43220000 } ,
{ " EXYNOS4412 " , 0xE4412000 } ,
{ " EXYNOS5250 " , 0x43520000 } ,
{ " EXYNOS5260 " , 0xE5260000 } ,
{ " EXYNOS5410 " , 0xE5410000 } ,
{ " EXYNOS5420 " , 0xE5420000 } ,
2020-12-02 21:59:54 +02:00
{ " EXYNOS5433 " , 0xE5433000 } ,
2019-08-13 17:08:19 +02:00
{ " EXYNOS5440 " , 0xE5440000 } ,
{ " EXYNOS5800 " , 0xE5422000 } ,
{ " EXYNOS7420 " , 0xE7420000 } ,
} ;
2021-01-05 18:44:40 +01:00
static const char * product_id_to_soc_id ( unsigned int product_id )
2019-08-13 17:08:19 +02:00
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( soc_ids ) ; i + + )
if ( ( product_id & EXYNOS_MASK ) = = soc_ids [ i ] . id )
return soc_ids [ i ] . name ;
return NULL ;
}
2020-12-07 19:54:57 +01:00
static int exynos_chipid_probe ( struct platform_device * pdev )
2019-08-13 17:08:19 +02:00
{
struct soc_device_attribute * soc_dev_attr ;
struct soc_device * soc_dev ;
struct device_node * root ;
2019-08-13 17:08:20 +02:00
struct regmap * regmap ;
2019-08-13 17:08:19 +02:00
u32 product_id ;
u32 revision ;
2019-08-13 17:08:20 +02:00
int ret ;
2019-08-13 17:08:19 +02:00
2020-12-07 19:54:57 +01:00
regmap = device_node_to_regmap ( pdev - > dev . of_node ) ;
2019-08-21 17:05:39 +02:00
if ( IS_ERR ( regmap ) )
2019-08-13 17:08:20 +02:00
return PTR_ERR ( regmap ) ;
2019-08-13 17:08:19 +02:00
2019-08-13 17:08:20 +02:00
ret = regmap_read ( regmap , EXYNOS_CHIPID_REG_PRO_ID , & product_id ) ;
if ( ret < 0 )
return ret ;
2019-08-13 17:08:19 +02:00
revision = product_id & EXYNOS_REV_MASK ;
2020-12-07 19:54:57 +01:00
soc_dev_attr = devm_kzalloc ( & pdev - > dev , sizeof ( * soc_dev_attr ) ,
GFP_KERNEL ) ;
2019-08-13 17:08:19 +02:00
if ( ! soc_dev_attr )
return - ENOMEM ;
soc_dev_attr - > family = " Samsung Exynos " ;
root = of_find_node_by_path ( " / " ) ;
of_property_read_string ( root , " model " , & soc_dev_attr - > machine ) ;
of_node_put ( root ) ;
2020-12-07 19:54:57 +01:00
soc_dev_attr - > revision = devm_kasprintf ( & pdev - > dev , GFP_KERNEL ,
" %x " , revision ) ;
2019-08-13 17:08:19 +02:00
soc_dev_attr - > soc_id = product_id_to_soc_id ( product_id ) ;
if ( ! soc_dev_attr - > soc_id ) {
pr_err ( " Unknown SoC \n " ) ;
2020-12-07 19:54:57 +01:00
return - ENODEV ;
2019-08-13 17:08:19 +02:00
}
/* please note that the actual registration will be deferred */
soc_dev = soc_device_register ( soc_dev_attr ) ;
2020-12-07 19:54:57 +01:00
if ( IS_ERR ( soc_dev ) )
return PTR_ERR ( soc_dev ) ;
ret = exynos_asv_init ( & pdev - > dev , regmap ) ;
if ( ret )
2019-08-16 23:21:51 +01:00
goto err ;
2020-12-07 19:54:57 +01:00
platform_set_drvdata ( pdev , soc_dev ) ;
2019-08-13 17:08:19 +02:00
2020-12-02 21:59:55 +02:00
dev_info ( soc_device_to_device ( soc_dev ) ,
" Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected \n " ,
soc_dev_attr - > soc_id , product_id , revision ) ;
2019-08-13 17:08:19 +02:00
return 0 ;
2019-08-16 23:21:51 +01:00
err :
2020-12-07 19:54:57 +01:00
soc_device_unregister ( soc_dev ) ;
2019-08-16 23:21:51 +01:00
return ret ;
2019-08-13 17:08:19 +02:00
}
2019-08-16 23:21:51 +01:00
2020-12-07 19:54:57 +01:00
static int exynos_chipid_remove ( struct platform_device * pdev )
{
struct soc_device * soc_dev = platform_get_drvdata ( pdev ) ;
soc_device_unregister ( soc_dev ) ;
return 0 ;
}
static const struct of_device_id exynos_chipid_of_device_ids [ ] = {
{ . compatible = " samsung,exynos4210-chipid " } ,
{ }
} ;
static struct platform_driver exynos_chipid_driver = {
. driver = {
. name = " exynos-chipid " ,
. of_match_table = exynos_chipid_of_device_ids ,
} ,
. probe = exynos_chipid_probe ,
. remove = exynos_chipid_remove ,
} ;
builtin_platform_driver ( exynos_chipid_driver ) ;