// SPDX-License-Identifier: GPL-2.0 /* * Author: Christian Marangi */ #include #include #include #include #include #include #include #define AIROHA_SMC_EFUSE_FID 0x82000001 #define AIROHA_SMC_EFUSE_SUB_ID_READ 0x44414552 #define AIROHA_EFUSE_CELLS 64 struct airoha_efuse_bank_priv { u32 bank_index; }; static int airoha_efuse_read(void *context, unsigned int offset, void *val, size_t bytes) { struct regmap *regmap = context; return regmap_bulk_read(regmap, offset, val, bytes / sizeof(u32)); } static int airoha_efuse_reg_read(void *context, unsigned int offset, unsigned int *val) { struct airoha_efuse_bank_priv *priv = context; struct arm_smccc_res res; arm_smccc_1_1_invoke(AIROHA_SMC_EFUSE_FID, AIROHA_SMC_EFUSE_SUB_ID_READ, priv->bank_index, offset, 0, 0, 0, 0, &res); /* check if SMC reported an error */ if (res.a0) return -EIO; *val = res.a1; return 0; } static int airoha_efuse_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int ret; for_each_child_of_node_scoped(dev->of_node, child) { struct nvmem_config nvmem_config = { .size = AIROHA_EFUSE_CELLS * sizeof(u32), .stride = sizeof(u32), .word_size = sizeof(u32), .reg_read = airoha_efuse_read, }; struct regmap_config regmap_config = { .reg_read = airoha_efuse_reg_read, .reg_bits = 32, .val_bits = 32, .reg_stride = 4, }; struct airoha_efuse_bank_priv *priv; struct nvmem_device *nvmem; struct regmap *regmap; const char *name; u32 bank; ret = of_property_read_u32(child, "reg", &bank); if (ret) return ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; name = devm_kasprintf(dev, GFP_KERNEL, "airoha-efuse-%u", bank); if (!name) return -ENOMEM; priv->bank_index = bank; regmap_config.name = name; regmap = devm_regmap_init(dev, NULL, priv, ®map_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); nvmem_config.name = name; nvmem_config.priv = regmap; nvmem_config.dev = dev; nvmem_config.id = bank; nvmem_config.of_node = child; nvmem = devm_nvmem_register(dev, &nvmem_config); if (IS_ERR(nvmem)) return PTR_ERR(nvmem); } return 0; } static const struct of_device_id airoha_efuse_of_match[] = { { .compatible = "airoha,an7581-efuses", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, airoha_efuse_of_match); static struct platform_driver airoha_efuse_driver = { .probe = airoha_efuse_probe, .driver = { .name = "airoha-efuse", .of_match_table = airoha_efuse_of_match, }, }; module_platform_driver(airoha_efuse_driver); MODULE_AUTHOR("Christian Marangi "); MODULE_DESCRIPTION("Driver for Airoha SMC eFUSEs"); MODULE_LICENSE("GPL");