Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Amlogic Meson GX eFuse Driver
0004  *
0005  * Copyright (c) 2016 Endless Computers, Inc.
0006  * Author: Carlo Caione <carlo@endlessm.com>
0007  */
0008 
0009 #include <linux/clk.h>
0010 #include <linux/module.h>
0011 #include <linux/nvmem-provider.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 
0015 #include <linux/firmware/meson/meson_sm.h>
0016 
0017 static int meson_efuse_read(void *context, unsigned int offset,
0018                 void *val, size_t bytes)
0019 {
0020     struct meson_sm_firmware *fw = context;
0021 
0022     return meson_sm_call_read(fw, (u8 *)val, bytes, SM_EFUSE_READ, offset,
0023                   bytes, 0, 0, 0);
0024 }
0025 
0026 static int meson_efuse_write(void *context, unsigned int offset,
0027                  void *val, size_t bytes)
0028 {
0029     struct meson_sm_firmware *fw = context;
0030 
0031     return meson_sm_call_write(fw, (u8 *)val, bytes, SM_EFUSE_WRITE, offset,
0032                    bytes, 0, 0, 0);
0033 }
0034 
0035 static const struct of_device_id meson_efuse_match[] = {
0036     { .compatible = "amlogic,meson-gxbb-efuse", },
0037     { /* sentinel */ },
0038 };
0039 MODULE_DEVICE_TABLE(of, meson_efuse_match);
0040 
0041 static int meson_efuse_probe(struct platform_device *pdev)
0042 {
0043     struct device *dev = &pdev->dev;
0044     struct meson_sm_firmware *fw;
0045     struct device_node *sm_np;
0046     struct nvmem_device *nvmem;
0047     struct nvmem_config *econfig;
0048     struct clk *clk;
0049     unsigned int size;
0050     int ret;
0051 
0052     sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
0053     if (!sm_np) {
0054         dev_err(&pdev->dev, "no secure-monitor node\n");
0055         return -ENODEV;
0056     }
0057 
0058     fw = meson_sm_get(sm_np);
0059     of_node_put(sm_np);
0060     if (!fw)
0061         return -EPROBE_DEFER;
0062 
0063     clk = devm_clk_get(dev, NULL);
0064     if (IS_ERR(clk)) {
0065         ret = PTR_ERR(clk);
0066         if (ret != -EPROBE_DEFER)
0067             dev_err(dev, "failed to get efuse gate");
0068         return ret;
0069     }
0070 
0071     ret = clk_prepare_enable(clk);
0072     if (ret) {
0073         dev_err(dev, "failed to enable gate");
0074         return ret;
0075     }
0076 
0077     ret = devm_add_action_or_reset(dev,
0078                        (void(*)(void *))clk_disable_unprepare,
0079                        clk);
0080     if (ret) {
0081         dev_err(dev, "failed to add disable callback");
0082         return ret;
0083     }
0084 
0085     if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
0086         dev_err(dev, "failed to get max user");
0087         return -EINVAL;
0088     }
0089 
0090     econfig = devm_kzalloc(dev, sizeof(*econfig), GFP_KERNEL);
0091     if (!econfig)
0092         return -ENOMEM;
0093 
0094     econfig->dev = dev;
0095     econfig->name = dev_name(dev);
0096     econfig->stride = 1;
0097     econfig->word_size = 1;
0098     econfig->reg_read = meson_efuse_read;
0099     econfig->reg_write = meson_efuse_write;
0100     econfig->size = size;
0101     econfig->priv = fw;
0102 
0103     nvmem = devm_nvmem_register(&pdev->dev, econfig);
0104 
0105     return PTR_ERR_OR_ZERO(nvmem);
0106 }
0107 
0108 static struct platform_driver meson_efuse_driver = {
0109     .probe = meson_efuse_probe,
0110     .driver = {
0111         .name = "meson-efuse",
0112         .of_match_table = meson_efuse_match,
0113     },
0114 };
0115 
0116 module_platform_driver(meson_efuse_driver);
0117 
0118 MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
0119 MODULE_DESCRIPTION("Amlogic Meson GX NVMEM driver");
0120 MODULE_LICENSE("GPL v2");