18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * UniPhier eFuse driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Socionext Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 128c2ecf20Sopenharmony_ci#include <linux/nvmem-provider.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct uniphier_efuse_priv { 168c2ecf20Sopenharmony_ci void __iomem *base; 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int uniphier_reg_read(void *context, 208c2ecf20Sopenharmony_ci unsigned int reg, void *_val, size_t bytes) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct uniphier_efuse_priv *priv = context; 238c2ecf20Sopenharmony_ci u8 *val = _val; 248c2ecf20Sopenharmony_ci int offs; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci for (offs = 0; offs < bytes; offs += sizeof(u8)) 278c2ecf20Sopenharmony_ci *val++ = readb(priv->base + reg + offs); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci return 0; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int uniphier_efuse_probe(struct platform_device *pdev) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 358c2ecf20Sopenharmony_ci struct resource *res; 368c2ecf20Sopenharmony_ci struct nvmem_device *nvmem; 378c2ecf20Sopenharmony_ci struct nvmem_config econfig = {}; 388c2ecf20Sopenharmony_ci struct uniphier_efuse_priv *priv; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 418c2ecf20Sopenharmony_ci if (!priv) 428c2ecf20Sopenharmony_ci return -ENOMEM; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 458c2ecf20Sopenharmony_ci priv->base = devm_ioremap_resource(dev, res); 468c2ecf20Sopenharmony_ci if (IS_ERR(priv->base)) 478c2ecf20Sopenharmony_ci return PTR_ERR(priv->base); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci econfig.stride = 1; 508c2ecf20Sopenharmony_ci econfig.word_size = 1; 518c2ecf20Sopenharmony_ci econfig.read_only = true; 528c2ecf20Sopenharmony_ci econfig.reg_read = uniphier_reg_read; 538c2ecf20Sopenharmony_ci econfig.size = resource_size(res); 548c2ecf20Sopenharmony_ci econfig.priv = priv; 558c2ecf20Sopenharmony_ci econfig.dev = dev; 568c2ecf20Sopenharmony_ci nvmem = devm_nvmem_register(dev, &econfig); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(nvmem); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct of_device_id uniphier_efuse_of_match[] = { 628c2ecf20Sopenharmony_ci { .compatible = "socionext,uniphier-efuse",}, 638c2ecf20Sopenharmony_ci {/* sentinel */}, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, uniphier_efuse_of_match); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct platform_driver uniphier_efuse_driver = { 688c2ecf20Sopenharmony_ci .probe = uniphier_efuse_probe, 698c2ecf20Sopenharmony_ci .driver = { 708c2ecf20Sopenharmony_ci .name = "uniphier-efuse", 718c2ecf20Sopenharmony_ci .of_match_table = uniphier_efuse_of_match, 728c2ecf20Sopenharmony_ci }, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_cimodule_platform_driver(uniphier_efuse_driver); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Keiji Hayashibara <hayashibara.keiji@socionext.com>"); 778c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UniPhier eFuse driver"); 788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 79