Skip to content

Commit 9f7f0dc

Browse files
marcanjannau
authored andcommitted
nvmem: Add spmi-mfd-nvmem driver
This driver exposes part of an SPMI MFD device as an NVMEM device. It is intended to be used with e.g. PMUs/PMICs that are used to hold power-management configuration, such as used on Apple Silicon Macs. Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent 2cbc8b4 commit 9f7f0dc

3 files changed

Lines changed: 113 additions & 0 deletions

File tree

drivers/nvmem/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,19 @@ config NVMEM_SNVS_LPGPR
299299
This driver can also be built as a module. If so, the module
300300
will be called nvmem-snvs-lpgpr.
301301

302+
config NVMEM_SPMI_MFD
303+
tristate "Generic SPMI MFD NVMEM"
304+
depends on MFD_SIMPLE_MFD_SPMI || COMPILE_TEST
305+
default ARCH_APPLE
306+
help
307+
Say y here to build a generic driver to expose an SPMI MFD device
308+
as a NVMEM provider. This can be used for PMIC/PMU devices which
309+
are used to store power and RTC-related settings on certain
310+
platforms, such as Apple Silicon Macs.
311+
312+
This driver can also be built as a module. If so, the module
313+
will be called nvmem-spmi-mfd.
314+
302315
config NVMEM_SPMI_SDAM
303316
tristate "SPMI SDAM Support"
304317
depends on SPMI

drivers/nvmem/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ obj-$(CONFIG_NVMEM_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o
6262
nvmem-sc27xx-efuse-y := sc27xx-efuse.o
6363
obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o
6464
nvmem_snvs_lpgpr-y := snvs_lpgpr.o
65+
obj-$(CONFIG_NVMEM_SPMI_MFD) += nvmem_spmi_mfd.o
66+
nvmem_spmi_mfd-y := spmi-mfd-nvmem.o
6567
obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o
6668
nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o
6769
obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o

drivers/nvmem/spmi-mfd-nvmem.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// SPDX-License-Identifier: GPL-2.0-only OR MIT
2+
/*
3+
* Generic SPMI MFD NVMEM driver
4+
*
5+
* Copyright The Asahi Linux Contributors
6+
*/
7+
8+
#include <linux/kernel.h>
9+
#include <linux/module.h>
10+
#include <linux/nvmem-provider.h>
11+
#include <linux/of.h>
12+
#include <linux/platform_device.h>
13+
#include <linux/regmap.h>
14+
15+
struct spmi_mfd_nvmem {
16+
struct regmap *regmap;
17+
unsigned int base;
18+
};
19+
20+
static int spmi_mfd_nvmem_read(void *priv, unsigned int offset,
21+
void *val, size_t bytes)
22+
{
23+
struct spmi_mfd_nvmem *nvmem = priv;
24+
25+
return regmap_bulk_read(nvmem->regmap, nvmem->base + offset, val, bytes);
26+
}
27+
28+
static int spmi_mfd_nvmem_write(void *priv, unsigned int offset,
29+
void *val, size_t bytes)
30+
{
31+
struct spmi_mfd_nvmem *nvmem = priv;
32+
33+
return regmap_bulk_write(nvmem->regmap, nvmem->base + offset, val, bytes);
34+
}
35+
36+
static int spmi_mfd_nvmem_probe(struct platform_device *pdev)
37+
{
38+
struct spmi_mfd_nvmem *nvmem;
39+
const __be32 *addr;
40+
int len;
41+
struct nvmem_config nvmem_cfg = {
42+
.dev = &pdev->dev,
43+
.name = "spmi_mfd_nvmem",
44+
.id = NVMEM_DEVID_AUTO,
45+
.word_size = 1,
46+
.stride = 1,
47+
.reg_read = spmi_mfd_nvmem_read,
48+
.reg_write = spmi_mfd_nvmem_write,
49+
};
50+
51+
nvmem = devm_kzalloc(&pdev->dev, sizeof(*nvmem), GFP_KERNEL);
52+
if (!nvmem)
53+
return -ENOMEM;
54+
55+
nvmem_cfg.priv = nvmem;
56+
57+
nvmem->regmap = dev_get_regmap(pdev->dev.parent, NULL);
58+
if (!nvmem->regmap) {
59+
dev_err(&pdev->dev, "Parent regmap unavailable.\n");
60+
return -ENXIO;
61+
}
62+
63+
addr = of_get_property(pdev->dev.of_node, "reg", &len);
64+
if (!addr) {
65+
dev_err(&pdev->dev, "no reg property\n");
66+
return -EINVAL;
67+
}
68+
if (len != 2 * sizeof(u32)) {
69+
dev_err(&pdev->dev, "invalid reg property\n");
70+
return -EINVAL;
71+
}
72+
73+
nvmem->base = be32_to_cpup(&addr[0]);
74+
nvmem_cfg.size = be32_to_cpup(&addr[1]);
75+
76+
return PTR_ERR_OR_ZERO(devm_nvmem_register(&pdev->dev, &nvmem_cfg));
77+
}
78+
79+
static const struct of_device_id spmi_mfd_nvmem_id_table[] = {
80+
{ .compatible = "apple,spmi-pmu-nvmem" },
81+
{ .compatible = "spmi-mfd-nvmem" },
82+
{ },
83+
};
84+
MODULE_DEVICE_TABLE(of, spmi_mfd_nvmem_id_table);
85+
86+
static struct platform_driver spmi_mfd_nvmem_driver = {
87+
.probe = spmi_mfd_nvmem_probe,
88+
.driver = {
89+
.name = "spmi-mfd-nvmem",
90+
.of_match_table = spmi_mfd_nvmem_id_table,
91+
},
92+
};
93+
94+
module_platform_driver(spmi_mfd_nvmem_driver);
95+
96+
MODULE_LICENSE("Dual MIT/GPL");
97+
MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
98+
MODULE_DESCRIPTION("SPMI MFD NVMEM driver");

0 commit comments

Comments
 (0)