0001
0002
0003
0004
0005
0006 #include <linux/device.h>
0007 #include <linux/module.h>
0008 #include <linux/of.h>
0009 #include <linux/of_platform.h>
0010 #include <linux/nvmem-provider.h>
0011 #include <linux/regmap.h>
0012
0013 #define SDAM_MEM_START 0x40
0014 #define REGISTER_MAP_ID 0x40
0015 #define REGISTER_MAP_VERSION 0x41
0016 #define SDAM_SIZE 0x44
0017 #define SDAM_PBS_TRIG_SET 0xE5
0018 #define SDAM_PBS_TRIG_CLR 0xE6
0019
0020 struct sdam_chip {
0021 struct regmap *regmap;
0022 struct nvmem_config sdam_config;
0023 unsigned int base;
0024 unsigned int size;
0025 };
0026
0027
0028 static const u8 sdam_ro_map[] = {
0029 REGISTER_MAP_ID,
0030 REGISTER_MAP_VERSION,
0031 SDAM_SIZE
0032 };
0033
0034 static bool sdam_is_valid(struct sdam_chip *sdam, unsigned int offset,
0035 size_t len)
0036 {
0037 unsigned int sdam_mem_end = SDAM_MEM_START + sdam->size - 1;
0038
0039 if (!len)
0040 return false;
0041
0042 if (offset >= SDAM_MEM_START && offset <= sdam_mem_end
0043 && (offset + len - 1) <= sdam_mem_end)
0044 return true;
0045 else if ((offset == SDAM_PBS_TRIG_SET || offset == SDAM_PBS_TRIG_CLR)
0046 && (len == 1))
0047 return true;
0048
0049 return false;
0050 }
0051
0052 static bool sdam_is_ro(unsigned int offset, size_t len)
0053 {
0054 int i;
0055
0056 for (i = 0; i < ARRAY_SIZE(sdam_ro_map); i++)
0057 if (offset <= sdam_ro_map[i] && (offset + len) > sdam_ro_map[i])
0058 return true;
0059
0060 return false;
0061 }
0062
0063 static int sdam_read(void *priv, unsigned int offset, void *val,
0064 size_t bytes)
0065 {
0066 struct sdam_chip *sdam = priv;
0067 struct device *dev = sdam->sdam_config.dev;
0068 int rc;
0069
0070 if (!sdam_is_valid(sdam, offset, bytes)) {
0071 dev_err(dev, "Invalid SDAM offset %#x len=%zd\n",
0072 offset, bytes);
0073 return -EINVAL;
0074 }
0075
0076 rc = regmap_bulk_read(sdam->regmap, sdam->base + offset, val, bytes);
0077 if (rc < 0)
0078 dev_err(dev, "Failed to read SDAM offset %#x len=%zd, rc=%d\n",
0079 offset, bytes, rc);
0080
0081 return rc;
0082 }
0083
0084 static int sdam_write(void *priv, unsigned int offset, void *val,
0085 size_t bytes)
0086 {
0087 struct sdam_chip *sdam = priv;
0088 struct device *dev = sdam->sdam_config.dev;
0089 int rc;
0090
0091 if (!sdam_is_valid(sdam, offset, bytes)) {
0092 dev_err(dev, "Invalid SDAM offset %#x len=%zd\n",
0093 offset, bytes);
0094 return -EINVAL;
0095 }
0096
0097 if (sdam_is_ro(offset, bytes)) {
0098 dev_err(dev, "Invalid write offset %#x len=%zd\n",
0099 offset, bytes);
0100 return -EINVAL;
0101 }
0102
0103 rc = regmap_bulk_write(sdam->regmap, sdam->base + offset, val, bytes);
0104 if (rc < 0)
0105 dev_err(dev, "Failed to write SDAM offset %#x len=%zd, rc=%d\n",
0106 offset, bytes, rc);
0107
0108 return rc;
0109 }
0110
0111 static int sdam_probe(struct platform_device *pdev)
0112 {
0113 struct sdam_chip *sdam;
0114 struct nvmem_device *nvmem;
0115 unsigned int val;
0116 int rc;
0117
0118 sdam = devm_kzalloc(&pdev->dev, sizeof(*sdam), GFP_KERNEL);
0119 if (!sdam)
0120 return -ENOMEM;
0121
0122 sdam->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0123 if (!sdam->regmap) {
0124 dev_err(&pdev->dev, "Failed to get regmap handle\n");
0125 return -ENXIO;
0126 }
0127
0128 rc = of_property_read_u32(pdev->dev.of_node, "reg", &sdam->base);
0129 if (rc < 0) {
0130 dev_err(&pdev->dev, "Failed to get SDAM base, rc=%d\n", rc);
0131 return -EINVAL;
0132 }
0133
0134 rc = regmap_read(sdam->regmap, sdam->base + SDAM_SIZE, &val);
0135 if (rc < 0) {
0136 dev_err(&pdev->dev, "Failed to read SDAM_SIZE rc=%d\n", rc);
0137 return -EINVAL;
0138 }
0139 sdam->size = val * 32;
0140
0141 sdam->sdam_config.dev = &pdev->dev;
0142 sdam->sdam_config.name = "spmi_sdam";
0143 sdam->sdam_config.id = NVMEM_DEVID_AUTO;
0144 sdam->sdam_config.owner = THIS_MODULE;
0145 sdam->sdam_config.stride = 1;
0146 sdam->sdam_config.word_size = 1;
0147 sdam->sdam_config.reg_read = sdam_read;
0148 sdam->sdam_config.reg_write = sdam_write;
0149 sdam->sdam_config.priv = sdam;
0150
0151 nvmem = devm_nvmem_register(&pdev->dev, &sdam->sdam_config);
0152 if (IS_ERR(nvmem)) {
0153 dev_err(&pdev->dev,
0154 "Failed to register SDAM nvmem device rc=%ld\n",
0155 PTR_ERR(nvmem));
0156 return -ENXIO;
0157 }
0158 dev_dbg(&pdev->dev,
0159 "SDAM base=%#x size=%u registered successfully\n",
0160 sdam->base, sdam->size);
0161
0162 return 0;
0163 }
0164
0165 static const struct of_device_id sdam_match_table[] = {
0166 { .compatible = "qcom,spmi-sdam" },
0167 {},
0168 };
0169
0170 static struct platform_driver sdam_driver = {
0171 .driver = {
0172 .name = "qcom,spmi-sdam",
0173 .of_match_table = sdam_match_table,
0174 },
0175 .probe = sdam_probe,
0176 };
0177
0178 static int __init sdam_init(void)
0179 {
0180 return platform_driver_register(&sdam_driver);
0181 }
0182 subsys_initcall(sdam_init);
0183
0184 static void __exit sdam_exit(void)
0185 {
0186 return platform_driver_unregister(&sdam_driver);
0187 }
0188 module_exit(sdam_exit);
0189
0190 MODULE_DESCRIPTION("QCOM SPMI SDAM driver");
0191 MODULE_LICENSE("GPL v2");