1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2015 MediaTek Inc.
4 * Author: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
7 #include <linux/device.h>
8 #include <linux/module.h>
9 #include <linux/mod_devicetable.h>
11 #include <linux/nvmem-provider.h>
12 #include <linux/platform_device.h>
13 #include <linux/property.h>
15 struct mtk_efuse_pdata
{
16 bool uses_post_processing
;
19 struct mtk_efuse_priv
{
23 static int mtk_reg_read(void *context
,
24 unsigned int reg
, void *_val
, size_t bytes
)
26 struct mtk_efuse_priv
*priv
= context
;
27 void __iomem
*addr
= priv
->base
+ reg
;
31 for (i
= 0; i
< bytes
; i
++, val
++)
32 *val
= readb(addr
+ i
);
37 static int mtk_efuse_gpu_speedbin_pp(void *context
, const char *id
, int index
,
38 unsigned int offset
, void *data
, size_t bytes
)
48 static void mtk_efuse_fixup_dt_cell_info(struct nvmem_device
*nvmem
,
49 struct nvmem_cell_info
*cell
)
51 size_t sz
= strlen(cell
->name
);
54 * On some SoCs, the GPU speedbin is not read as bitmask but as
55 * a number with range [0-7] (max 3 bits): post process to use
56 * it in OPP tables to describe supported-hw.
58 if (cell
->nbits
<= 3 &&
59 strncmp(cell
->name
, "gpu-speedbin", min(sz
, strlen("gpu-speedbin"))) == 0)
60 cell
->read_post_process
= mtk_efuse_gpu_speedbin_pp
;
63 static int mtk_efuse_probe(struct platform_device
*pdev
)
65 struct device
*dev
= &pdev
->dev
;
67 struct nvmem_device
*nvmem
;
68 struct nvmem_config econfig
= {};
69 struct mtk_efuse_priv
*priv
;
70 const struct mtk_efuse_pdata
*pdata
;
71 struct platform_device
*socinfo
;
73 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
77 priv
->base
= devm_platform_get_and_ioremap_resource(pdev
, 0, &res
);
78 if (IS_ERR(priv
->base
))
79 return PTR_ERR(priv
->base
);
81 pdata
= device_get_match_data(dev
);
82 econfig
.add_legacy_fixed_of_cells
= true;
84 econfig
.word_size
= 1;
85 econfig
.reg_read
= mtk_reg_read
;
86 econfig
.size
= resource_size(res
);
89 if (pdata
->uses_post_processing
)
90 econfig
.fixup_dt_cell_info
= &mtk_efuse_fixup_dt_cell_info
;
91 nvmem
= devm_nvmem_register(dev
, &econfig
);
93 return PTR_ERR(nvmem
);
95 socinfo
= platform_device_register_data(&pdev
->dev
, "mtk-socinfo",
96 PLATFORM_DEVID_AUTO
, NULL
, 0);
98 dev_info(dev
, "MediaTek SoC Information will be unavailable\n");
100 platform_set_drvdata(pdev
, socinfo
);
104 static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata
= {
105 .uses_post_processing
= true,
108 static const struct mtk_efuse_pdata mtk_efuse_pdata
= {
109 .uses_post_processing
= false,
112 static const struct of_device_id mtk_efuse_of_match
[] = {
113 { .compatible
= "mediatek,mt8173-efuse", .data
= &mtk_efuse_pdata
},
114 { .compatible
= "mediatek,mt8186-efuse", .data
= &mtk_mt8186_efuse_pdata
},
115 { .compatible
= "mediatek,efuse", .data
= &mtk_efuse_pdata
},
118 MODULE_DEVICE_TABLE(of
, mtk_efuse_of_match
);
120 static void mtk_efuse_remove(struct platform_device
*pdev
)
122 struct platform_device
*socinfo
= platform_get_drvdata(pdev
);
124 if (!IS_ERR_OR_NULL(socinfo
))
125 platform_device_unregister(socinfo
);
128 static struct platform_driver mtk_efuse_driver
= {
129 .probe
= mtk_efuse_probe
,
130 .remove
= mtk_efuse_remove
,
132 .name
= "mediatek,efuse",
133 .of_match_table
= mtk_efuse_of_match
,
137 static int __init
mtk_efuse_init(void)
141 ret
= platform_driver_register(&mtk_efuse_driver
);
143 pr_err("Failed to register efuse driver\n");
150 static void __exit
mtk_efuse_exit(void)
152 return platform_driver_unregister(&mtk_efuse_driver
);
155 subsys_initcall(mtk_efuse_init
);
156 module_exit(mtk_efuse_exit
);
158 MODULE_AUTHOR("Andrew-CT Chen <andrew-ct.chen@mediatek.com>");
159 MODULE_DESCRIPTION("Mediatek EFUSE driver");
160 MODULE_LICENSE("GPL v2");