0001
0002
0003
0004
0005
0006
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 { },
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");