1*1802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 24c7e4fe3SAndrew-CT Chen /* 34c7e4fe3SAndrew-CT Chen * Copyright (c) 2015 MediaTek Inc. 44c7e4fe3SAndrew-CT Chen * Author: Andrew-CT Chen <andrew-ct.chen@mediatek.com> 54c7e4fe3SAndrew-CT Chen */ 64c7e4fe3SAndrew-CT Chen 74c7e4fe3SAndrew-CT Chen #include <linux/device.h> 84c7e4fe3SAndrew-CT Chen #include <linux/module.h> 9ac316725SRandy Dunlap #include <linux/mod_devicetable.h> 10ba360fd0SSrinivas Kandagatla #include <linux/io.h> 114c7e4fe3SAndrew-CT Chen #include <linux/nvmem-provider.h> 124c7e4fe3SAndrew-CT Chen #include <linux/platform_device.h> 134c7e4fe3SAndrew-CT Chen 14a48f1fffSMasahiro Yamada struct mtk_efuse_priv { 15a48f1fffSMasahiro Yamada void __iomem *base; 16a48f1fffSMasahiro Yamada }; 17a48f1fffSMasahiro Yamada 18ba360fd0SSrinivas Kandagatla static int mtk_reg_read(void *context, 19ba360fd0SSrinivas Kandagatla unsigned int reg, void *_val, size_t bytes) 20ba360fd0SSrinivas Kandagatla { 21a48f1fffSMasahiro Yamada struct mtk_efuse_priv *priv = context; 22ba360fd0SSrinivas Kandagatla u32 *val = _val; 23ba360fd0SSrinivas Kandagatla int i = 0, words = bytes / 4; 24ba360fd0SSrinivas Kandagatla 25ba360fd0SSrinivas Kandagatla while (words--) 26a48f1fffSMasahiro Yamada *val++ = readl(priv->base + reg + (i++ * 4)); 27ba360fd0SSrinivas Kandagatla 28ba360fd0SSrinivas Kandagatla return 0; 29ba360fd0SSrinivas Kandagatla } 30ba360fd0SSrinivas Kandagatla 31ba360fd0SSrinivas Kandagatla static int mtk_reg_write(void *context, 32ba360fd0SSrinivas Kandagatla unsigned int reg, void *_val, size_t bytes) 33ba360fd0SSrinivas Kandagatla { 34a48f1fffSMasahiro Yamada struct mtk_efuse_priv *priv = context; 35ba360fd0SSrinivas Kandagatla u32 *val = _val; 36ba360fd0SSrinivas Kandagatla int i = 0, words = bytes / 4; 37ba360fd0SSrinivas Kandagatla 38ba360fd0SSrinivas Kandagatla while (words--) 39a48f1fffSMasahiro Yamada writel(*val++, priv->base + reg + (i++ * 4)); 40ba360fd0SSrinivas Kandagatla 41ba360fd0SSrinivas Kandagatla return 0; 42ba360fd0SSrinivas Kandagatla } 434c7e4fe3SAndrew-CT Chen 444c7e4fe3SAndrew-CT Chen static int mtk_efuse_probe(struct platform_device *pdev) 454c7e4fe3SAndrew-CT Chen { 464c7e4fe3SAndrew-CT Chen struct device *dev = &pdev->dev; 474c7e4fe3SAndrew-CT Chen struct resource *res; 484c7e4fe3SAndrew-CT Chen struct nvmem_device *nvmem; 494dd5f60eSMasahiro Yamada struct nvmem_config econfig = {}; 50a48f1fffSMasahiro Yamada struct mtk_efuse_priv *priv; 51a48f1fffSMasahiro Yamada 52a48f1fffSMasahiro Yamada priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 53a48f1fffSMasahiro Yamada if (!priv) 54a48f1fffSMasahiro Yamada return -ENOMEM; 554c7e4fe3SAndrew-CT Chen 564c7e4fe3SAndrew-CT Chen res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 57a48f1fffSMasahiro Yamada priv->base = devm_ioremap_resource(dev, res); 58a48f1fffSMasahiro Yamada if (IS_ERR(priv->base)) 59a48f1fffSMasahiro Yamada return PTR_ERR(priv->base); 604c7e4fe3SAndrew-CT Chen 614dd5f60eSMasahiro Yamada econfig.stride = 4; 624dd5f60eSMasahiro Yamada econfig.word_size = 4; 634dd5f60eSMasahiro Yamada econfig.reg_read = mtk_reg_read; 644dd5f60eSMasahiro Yamada econfig.reg_write = mtk_reg_write; 654dd5f60eSMasahiro Yamada econfig.size = resource_size(res); 66a48f1fffSMasahiro Yamada econfig.priv = priv; 674dd5f60eSMasahiro Yamada econfig.dev = dev; 687e68a645SAndrey Smirnov nvmem = devm_nvmem_register(dev, &econfig); 694c7e4fe3SAndrew-CT Chen 707e68a645SAndrey Smirnov return PTR_ERR_OR_ZERO(nvmem); 714c7e4fe3SAndrew-CT Chen } 724c7e4fe3SAndrew-CT Chen 734c7e4fe3SAndrew-CT Chen static const struct of_device_id mtk_efuse_of_match[] = { 744c7e4fe3SAndrew-CT Chen { .compatible = "mediatek,mt8173-efuse",}, 754c7e4fe3SAndrew-CT Chen { .compatible = "mediatek,efuse",}, 764c7e4fe3SAndrew-CT Chen {/* sentinel */}, 774c7e4fe3SAndrew-CT Chen }; 784c7e4fe3SAndrew-CT Chen MODULE_DEVICE_TABLE(of, mtk_efuse_of_match); 794c7e4fe3SAndrew-CT Chen 804c7e4fe3SAndrew-CT Chen static struct platform_driver mtk_efuse_driver = { 814c7e4fe3SAndrew-CT Chen .probe = mtk_efuse_probe, 824c7e4fe3SAndrew-CT Chen .driver = { 834c7e4fe3SAndrew-CT Chen .name = "mediatek,efuse", 844c7e4fe3SAndrew-CT Chen .of_match_table = mtk_efuse_of_match, 854c7e4fe3SAndrew-CT Chen }, 864c7e4fe3SAndrew-CT Chen }; 87564e7f87SAndrew-CT Chen 88564e7f87SAndrew-CT Chen static int __init mtk_efuse_init(void) 89564e7f87SAndrew-CT Chen { 90564e7f87SAndrew-CT Chen int ret; 91564e7f87SAndrew-CT Chen 92564e7f87SAndrew-CT Chen ret = platform_driver_register(&mtk_efuse_driver); 93564e7f87SAndrew-CT Chen if (ret) { 94564e7f87SAndrew-CT Chen pr_err("Failed to register efuse driver\n"); 95564e7f87SAndrew-CT Chen return ret; 96564e7f87SAndrew-CT Chen } 97564e7f87SAndrew-CT Chen 98564e7f87SAndrew-CT Chen return 0; 99564e7f87SAndrew-CT Chen } 100564e7f87SAndrew-CT Chen 101564e7f87SAndrew-CT Chen static void __exit mtk_efuse_exit(void) 102564e7f87SAndrew-CT Chen { 103564e7f87SAndrew-CT Chen return platform_driver_unregister(&mtk_efuse_driver); 104564e7f87SAndrew-CT Chen } 105564e7f87SAndrew-CT Chen 106564e7f87SAndrew-CT Chen subsys_initcall(mtk_efuse_init); 107564e7f87SAndrew-CT Chen module_exit(mtk_efuse_exit); 108564e7f87SAndrew-CT Chen 1094c7e4fe3SAndrew-CT Chen MODULE_AUTHOR("Andrew-CT Chen <andrew-ct.chen@mediatek.com>"); 1104c7e4fe3SAndrew-CT Chen MODULE_DESCRIPTION("Mediatek EFUSE driver"); 1114c7e4fe3SAndrew-CT Chen MODULE_LICENSE("GPL v2"); 112