0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/mfd/syscon.h>
0009 #include <linux/module.h>
0010 #include <linux/nvmem-provider.h>
0011 #include <linux/random.h>
0012 #include <linux/of.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/regmap.h>
0016
0017 #define SFR_SN0 0x4c
0018 #define SFR_SN_SIZE 8
0019
0020 struct atmel_sfr_priv {
0021 struct regmap *regmap;
0022 };
0023
0024 static int atmel_sfr_read(void *context, unsigned int offset,
0025 void *buf, size_t bytes)
0026 {
0027 struct atmel_sfr_priv *priv = context;
0028
0029 return regmap_bulk_read(priv->regmap, SFR_SN0 + offset,
0030 buf, bytes / 4);
0031 }
0032
0033 static struct nvmem_config atmel_sfr_nvmem_config = {
0034 .name = "atmel-sfr",
0035 .read_only = true,
0036 .word_size = 4,
0037 .stride = 4,
0038 .size = SFR_SN_SIZE,
0039 .reg_read = atmel_sfr_read,
0040 };
0041
0042 static int atmel_sfr_probe(struct platform_device *pdev)
0043 {
0044 struct device *dev = &pdev->dev;
0045 struct device_node *np = dev->of_node;
0046 struct nvmem_device *nvmem;
0047 struct atmel_sfr_priv *priv;
0048 u8 sn[SFR_SN_SIZE];
0049 int ret;
0050
0051 priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
0052 if (!priv)
0053 return -ENOMEM;
0054
0055 priv->regmap = syscon_node_to_regmap(np);
0056 if (IS_ERR(priv->regmap)) {
0057 dev_err(dev, "cannot get parent's regmap\n");
0058 return PTR_ERR(priv->regmap);
0059 }
0060
0061 atmel_sfr_nvmem_config.dev = dev;
0062 atmel_sfr_nvmem_config.priv = priv;
0063
0064 nvmem = devm_nvmem_register(dev, &atmel_sfr_nvmem_config);
0065 if (IS_ERR(nvmem)) {
0066 dev_err(dev, "error registering nvmem config\n");
0067 return PTR_ERR(nvmem);
0068 }
0069
0070 ret = atmel_sfr_read(priv, 0, sn, SFR_SN_SIZE);
0071 if (ret == 0)
0072 add_device_randomness(sn, SFR_SN_SIZE);
0073
0074 return ret;
0075 }
0076
0077 static const struct of_device_id atmel_sfr_dt_ids[] = {
0078 {
0079 .compatible = "atmel,sama5d2-sfr",
0080 }, {
0081 .compatible = "atmel,sama5d4-sfr",
0082 }, {
0083
0084 },
0085 };
0086 MODULE_DEVICE_TABLE(of, atmel_sfr_dt_ids);
0087
0088 static struct platform_driver atmel_sfr_driver = {
0089 .probe = atmel_sfr_probe,
0090 .driver = {
0091 .name = "atmel-sfr",
0092 .of_match_table = atmel_sfr_dt_ids,
0093 },
0094 };
0095 module_platform_driver(atmel_sfr_driver);
0096
0097 MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
0098 MODULE_DESCRIPTION("Atmel SFR SN driver for SAMA5D2/4 SoC family");
0099 MODULE_LICENSE("GPL v2");