1*1802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 271c5dd50SKeiji Hayashibara /* 371c5dd50SKeiji Hayashibara * UniPhier eFuse driver 471c5dd50SKeiji Hayashibara * 571c5dd50SKeiji Hayashibara * Copyright (C) 2017 Socionext Inc. 671c5dd50SKeiji Hayashibara */ 771c5dd50SKeiji Hayashibara 871c5dd50SKeiji Hayashibara #include <linux/device.h> 971c5dd50SKeiji Hayashibara #include <linux/io.h> 1071c5dd50SKeiji Hayashibara #include <linux/module.h> 11ac316725SRandy Dunlap #include <linux/mod_devicetable.h> 1271c5dd50SKeiji Hayashibara #include <linux/nvmem-provider.h> 1371c5dd50SKeiji Hayashibara #include <linux/platform_device.h> 1471c5dd50SKeiji Hayashibara 1571c5dd50SKeiji Hayashibara struct uniphier_efuse_priv { 1671c5dd50SKeiji Hayashibara void __iomem *base; 1771c5dd50SKeiji Hayashibara }; 1871c5dd50SKeiji Hayashibara 1971c5dd50SKeiji Hayashibara static int uniphier_reg_read(void *context, 2071c5dd50SKeiji Hayashibara unsigned int reg, void *_val, size_t bytes) 2171c5dd50SKeiji Hayashibara { 2271c5dd50SKeiji Hayashibara struct uniphier_efuse_priv *priv = context; 23683618b0SKunihiko Hayashi u8 *val = _val; 2471c5dd50SKeiji Hayashibara int offs; 2571c5dd50SKeiji Hayashibara 26683618b0SKunihiko Hayashi for (offs = 0; offs < bytes; offs += sizeof(u8)) 27683618b0SKunihiko Hayashi *val++ = readb(priv->base + reg + offs); 2871c5dd50SKeiji Hayashibara 2971c5dd50SKeiji Hayashibara return 0; 3071c5dd50SKeiji Hayashibara } 3171c5dd50SKeiji Hayashibara 3271c5dd50SKeiji Hayashibara static int uniphier_efuse_probe(struct platform_device *pdev) 3371c5dd50SKeiji Hayashibara { 3471c5dd50SKeiji Hayashibara struct device *dev = &pdev->dev; 3571c5dd50SKeiji Hayashibara struct resource *res; 3671c5dd50SKeiji Hayashibara struct nvmem_device *nvmem; 3771c5dd50SKeiji Hayashibara struct nvmem_config econfig = {}; 3871c5dd50SKeiji Hayashibara struct uniphier_efuse_priv *priv; 3971c5dd50SKeiji Hayashibara 4071c5dd50SKeiji Hayashibara priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 4171c5dd50SKeiji Hayashibara if (!priv) 4271c5dd50SKeiji Hayashibara return -ENOMEM; 4371c5dd50SKeiji Hayashibara 4471c5dd50SKeiji Hayashibara res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4571c5dd50SKeiji Hayashibara priv->base = devm_ioremap_resource(dev, res); 4671c5dd50SKeiji Hayashibara if (IS_ERR(priv->base)) 4771c5dd50SKeiji Hayashibara return PTR_ERR(priv->base); 4871c5dd50SKeiji Hayashibara 49683618b0SKunihiko Hayashi econfig.stride = 1; 50683618b0SKunihiko Hayashi econfig.word_size = 1; 5171c5dd50SKeiji Hayashibara econfig.read_only = true; 5271c5dd50SKeiji Hayashibara econfig.reg_read = uniphier_reg_read; 5371c5dd50SKeiji Hayashibara econfig.size = resource_size(res); 5471c5dd50SKeiji Hayashibara econfig.priv = priv; 5571c5dd50SKeiji Hayashibara econfig.dev = dev; 5645ff8ef7SAndrey Smirnov nvmem = devm_nvmem_register(dev, &econfig); 5771c5dd50SKeiji Hayashibara 5845ff8ef7SAndrey Smirnov return PTR_ERR_OR_ZERO(nvmem); 5971c5dd50SKeiji Hayashibara } 6071c5dd50SKeiji Hayashibara 6171c5dd50SKeiji Hayashibara static const struct of_device_id uniphier_efuse_of_match[] = { 6271c5dd50SKeiji Hayashibara { .compatible = "socionext,uniphier-efuse",}, 6371c5dd50SKeiji Hayashibara {/* sentinel */}, 6471c5dd50SKeiji Hayashibara }; 6571c5dd50SKeiji Hayashibara MODULE_DEVICE_TABLE(of, uniphier_efuse_of_match); 6671c5dd50SKeiji Hayashibara 6771c5dd50SKeiji Hayashibara static struct platform_driver uniphier_efuse_driver = { 6871c5dd50SKeiji Hayashibara .probe = uniphier_efuse_probe, 6971c5dd50SKeiji Hayashibara .driver = { 7071c5dd50SKeiji Hayashibara .name = "uniphier-efuse", 7171c5dd50SKeiji Hayashibara .of_match_table = uniphier_efuse_of_match, 7271c5dd50SKeiji Hayashibara }, 7371c5dd50SKeiji Hayashibara }; 7471c5dd50SKeiji Hayashibara module_platform_driver(uniphier_efuse_driver); 7571c5dd50SKeiji Hayashibara 7671c5dd50SKeiji Hayashibara MODULE_AUTHOR("Keiji Hayashibara <hayashibara.keiji@socionext.com>"); 7771c5dd50SKeiji Hayashibara MODULE_DESCRIPTION("UniPhier eFuse driver"); 7871c5dd50SKeiji Hayashibara MODULE_LICENSE("GPL v2"); 79