1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Apple SoC eFuse driver 4 * 5 * Copyright (C) The Asahi Linux Contributors 6 */ 7 8 #include <linux/io.h> 9 #include <linux/module.h> 10 #include <linux/nvmem-provider.h> 11 #include <linux/platform_device.h> 12 13 struct apple_efuses_priv { 14 void __iomem *fuses; 15 }; 16 17 static int apple_efuses_read(void *context, unsigned int offset, void *val, 18 size_t bytes) 19 { 20 struct apple_efuses_priv *priv = context; 21 u32 *dst = val; 22 23 while (bytes >= sizeof(u32)) { 24 *dst++ = readl_relaxed(priv->fuses + offset); 25 bytes -= sizeof(u32); 26 offset += sizeof(u32); 27 } 28 29 return 0; 30 } 31 32 static int apple_efuses_probe(struct platform_device *pdev) 33 { 34 struct apple_efuses_priv *priv; 35 struct resource *res; 36 struct nvmem_config config = { 37 .dev = &pdev->dev, 38 .add_legacy_fixed_of_cells = true, 39 .read_only = true, 40 .reg_read = apple_efuses_read, 41 .stride = sizeof(u32), 42 .word_size = sizeof(u32), 43 .name = "apple_efuses_nvmem", 44 .id = NVMEM_DEVID_AUTO, 45 .root_only = true, 46 }; 47 48 priv = devm_kzalloc(config.dev, sizeof(*priv), GFP_KERNEL); 49 if (!priv) 50 return -ENOMEM; 51 52 priv->fuses = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 53 if (IS_ERR(priv->fuses)) 54 return PTR_ERR(priv->fuses); 55 56 config.priv = priv; 57 config.size = resource_size(res); 58 59 return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); 60 } 61 62 static const struct of_device_id apple_efuses_of_match[] = { 63 { .compatible = "apple,efuses", }, 64 {} 65 }; 66 67 MODULE_DEVICE_TABLE(of, apple_efuses_of_match); 68 69 static struct platform_driver apple_efuses_driver = { 70 .driver = { 71 .name = "apple_efuses", 72 .of_match_table = apple_efuses_of_match, 73 }, 74 .probe = apple_efuses_probe, 75 }; 76 77 module_platform_driver(apple_efuses_driver); 78 79 MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); 80 MODULE_DESCRIPTION("Apple SoC eFuse driver"); 81 MODULE_LICENSE("GPL"); 82