xref: /linux/drivers/nvmem/airoha-smc-efuses.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1*b7846af2SChristian Marangi // SPDX-License-Identifier: GPL-2.0
2*b7846af2SChristian Marangi /*
3*b7846af2SChristian Marangi  *  Author: Christian Marangi <ansuelsmth@gmail.com>
4*b7846af2SChristian Marangi  */
5*b7846af2SChristian Marangi 
6*b7846af2SChristian Marangi #include <linux/arm-smccc.h>
7*b7846af2SChristian Marangi #include <linux/mod_devicetable.h>
8*b7846af2SChristian Marangi #include <linux/module.h>
9*b7846af2SChristian Marangi #include <linux/nvmem-provider.h>
10*b7846af2SChristian Marangi #include <linux/platform_device.h>
11*b7846af2SChristian Marangi #include <linux/of.h>
12*b7846af2SChristian Marangi #include <linux/regmap.h>
13*b7846af2SChristian Marangi 
14*b7846af2SChristian Marangi #define AIROHA_SMC_EFUSE_FID		0x82000001
15*b7846af2SChristian Marangi #define AIROHA_SMC_EFUSE_SUB_ID_READ	0x44414552
16*b7846af2SChristian Marangi 
17*b7846af2SChristian Marangi #define AIROHA_EFUSE_CELLS		64
18*b7846af2SChristian Marangi 
19*b7846af2SChristian Marangi struct airoha_efuse_bank_priv {
20*b7846af2SChristian Marangi 	u32 bank_index;
21*b7846af2SChristian Marangi };
22*b7846af2SChristian Marangi 
23*b7846af2SChristian Marangi static int airoha_efuse_read(void *context, unsigned int offset,
24*b7846af2SChristian Marangi 			     void *val, size_t bytes)
25*b7846af2SChristian Marangi {
26*b7846af2SChristian Marangi 	struct regmap *regmap = context;
27*b7846af2SChristian Marangi 
28*b7846af2SChristian Marangi 	return regmap_bulk_read(regmap, offset,
29*b7846af2SChristian Marangi 				val, bytes / sizeof(u32));
30*b7846af2SChristian Marangi }
31*b7846af2SChristian Marangi 
32*b7846af2SChristian Marangi static int airoha_efuse_reg_read(void *context, unsigned int offset,
33*b7846af2SChristian Marangi 				 unsigned int *val)
34*b7846af2SChristian Marangi {
35*b7846af2SChristian Marangi 	struct airoha_efuse_bank_priv *priv = context;
36*b7846af2SChristian Marangi 	struct arm_smccc_res res;
37*b7846af2SChristian Marangi 
38*b7846af2SChristian Marangi 	arm_smccc_1_1_invoke(AIROHA_SMC_EFUSE_FID,
39*b7846af2SChristian Marangi 			     AIROHA_SMC_EFUSE_SUB_ID_READ,
40*b7846af2SChristian Marangi 			     priv->bank_index, offset, 0, 0, 0, 0, &res);
41*b7846af2SChristian Marangi 
42*b7846af2SChristian Marangi 	/* check if SMC reported an error */
43*b7846af2SChristian Marangi 	if (res.a0)
44*b7846af2SChristian Marangi 		return -EIO;
45*b7846af2SChristian Marangi 
46*b7846af2SChristian Marangi 	*val = res.a1;
47*b7846af2SChristian Marangi 	return 0;
48*b7846af2SChristian Marangi }
49*b7846af2SChristian Marangi 
50*b7846af2SChristian Marangi static int airoha_efuse_probe(struct platform_device *pdev)
51*b7846af2SChristian Marangi {
52*b7846af2SChristian Marangi 	struct device *dev = &pdev->dev;
53*b7846af2SChristian Marangi 	int ret;
54*b7846af2SChristian Marangi 
55*b7846af2SChristian Marangi 	for_each_child_of_node_scoped(dev->of_node, child) {
56*b7846af2SChristian Marangi 		struct nvmem_config nvmem_config = {
57*b7846af2SChristian Marangi 			.size = AIROHA_EFUSE_CELLS * sizeof(u32),
58*b7846af2SChristian Marangi 			.stride = sizeof(u32),
59*b7846af2SChristian Marangi 			.word_size = sizeof(u32),
60*b7846af2SChristian Marangi 			.reg_read = airoha_efuse_read,
61*b7846af2SChristian Marangi 		};
62*b7846af2SChristian Marangi 		struct regmap_config regmap_config = {
63*b7846af2SChristian Marangi 			.reg_read = airoha_efuse_reg_read,
64*b7846af2SChristian Marangi 			.reg_bits = 32,
65*b7846af2SChristian Marangi 			.val_bits = 32,
66*b7846af2SChristian Marangi 			.reg_stride = 4,
67*b7846af2SChristian Marangi 		};
68*b7846af2SChristian Marangi 		struct airoha_efuse_bank_priv *priv;
69*b7846af2SChristian Marangi 		struct nvmem_device *nvmem;
70*b7846af2SChristian Marangi 		struct regmap *regmap;
71*b7846af2SChristian Marangi 		const char *name;
72*b7846af2SChristian Marangi 		u32 bank;
73*b7846af2SChristian Marangi 
74*b7846af2SChristian Marangi 		ret = of_property_read_u32(child, "reg", &bank);
75*b7846af2SChristian Marangi 		if (ret)
76*b7846af2SChristian Marangi 			return ret;
77*b7846af2SChristian Marangi 
78*b7846af2SChristian Marangi 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
79*b7846af2SChristian Marangi 		if (!priv)
80*b7846af2SChristian Marangi 			return -ENOMEM;
81*b7846af2SChristian Marangi 
82*b7846af2SChristian Marangi 		name = devm_kasprintf(dev, GFP_KERNEL, "airoha-efuse-%u",
83*b7846af2SChristian Marangi 				      bank);
84*b7846af2SChristian Marangi 		if (!name)
85*b7846af2SChristian Marangi 			return -ENOMEM;
86*b7846af2SChristian Marangi 
87*b7846af2SChristian Marangi 		priv->bank_index = bank;
88*b7846af2SChristian Marangi 
89*b7846af2SChristian Marangi 		regmap_config.name = name;
90*b7846af2SChristian Marangi 		regmap = devm_regmap_init(dev, NULL, priv,
91*b7846af2SChristian Marangi 					  &regmap_config);
92*b7846af2SChristian Marangi 		if (IS_ERR(regmap))
93*b7846af2SChristian Marangi 			return PTR_ERR(regmap);
94*b7846af2SChristian Marangi 
95*b7846af2SChristian Marangi 		nvmem_config.name = name;
96*b7846af2SChristian Marangi 		nvmem_config.priv = regmap;
97*b7846af2SChristian Marangi 		nvmem_config.dev = dev;
98*b7846af2SChristian Marangi 		nvmem_config.id = bank;
99*b7846af2SChristian Marangi 		nvmem_config.of_node = child;
100*b7846af2SChristian Marangi 		nvmem = devm_nvmem_register(dev, &nvmem_config);
101*b7846af2SChristian Marangi 		if (IS_ERR(nvmem))
102*b7846af2SChristian Marangi 			return PTR_ERR(nvmem);
103*b7846af2SChristian Marangi 	}
104*b7846af2SChristian Marangi 
105*b7846af2SChristian Marangi 	return 0;
106*b7846af2SChristian Marangi }
107*b7846af2SChristian Marangi 
108*b7846af2SChristian Marangi static const struct of_device_id airoha_efuse_of_match[] = {
109*b7846af2SChristian Marangi 	{ .compatible = "airoha,an7581-efuses", },
110*b7846af2SChristian Marangi 	{ /* sentinel */ }
111*b7846af2SChristian Marangi };
112*b7846af2SChristian Marangi MODULE_DEVICE_TABLE(of, airoha_efuse_of_match);
113*b7846af2SChristian Marangi 
114*b7846af2SChristian Marangi static struct platform_driver airoha_efuse_driver = {
115*b7846af2SChristian Marangi 	.probe = airoha_efuse_probe,
116*b7846af2SChristian Marangi 	.driver = {
117*b7846af2SChristian Marangi 		.name = "airoha-efuse",
118*b7846af2SChristian Marangi 		.of_match_table = airoha_efuse_of_match,
119*b7846af2SChristian Marangi 	},
120*b7846af2SChristian Marangi };
121*b7846af2SChristian Marangi module_platform_driver(airoha_efuse_driver);
122*b7846af2SChristian Marangi 
123*b7846af2SChristian Marangi MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
124*b7846af2SChristian Marangi MODULE_DESCRIPTION("Driver for Airoha SMC eFUSEs");
125*b7846af2SChristian Marangi MODULE_LICENSE("GPL");
126