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/mod_devicetable.h> 10 #include <linux/module.h> 11 #include <linux/nvmem-provider.h> 12 #include <linux/platform_device.h> 13 14 struct apple_efuses_priv { 15 void __iomem *fuses; 16 }; 17 18 static int apple_efuses_read(void *context, unsigned int offset, void *val, 19 size_t bytes) 20 { 21 struct apple_efuses_priv *priv = context; 22 u32 *dst = val; 23 24 while (bytes >= sizeof(u32)) { 25 *dst++ = readl_relaxed(priv->fuses + offset); 26 bytes -= sizeof(u32); 27 offset += sizeof(u32); 28 } 29 30 return 0; 31 } 32 33 static int apple_efuses_probe(struct platform_device *pdev) 34 { 35 struct apple_efuses_priv *priv; 36 struct resource *res; 37 struct nvmem_config config = { 38 .dev = &pdev->dev, 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_LICENSE("GPL"); 81