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