Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: syscon: Add of_syscon_register_regmap() API

The of_syscon_register_regmap() API allows an externally created regmap
to be registered with syscon. This regmap can then be returned to client
drivers using the syscon_regmap_lookup_by_phandle() APIs.

The API is used by platforms where mmio access to the syscon registers is
not possible, and a underlying soc driver like exynos-pmu provides a SoC
specific regmap that can issue a SMC or hypervisor call to write the
register.

This approach keeps the SoC complexities out of syscon, but allows common
drivers such as syscon-poweroff, syscon-reboot and friends that are used
by many SoCs already to be re-used.

Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Sam Protsenko <semen.protsenko@linaro.org>
Tested-by: Will McVicker <willmcvicker@google.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20240621115544.1655458-2-peter.griffin@linaro.org
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Peter Griffin and committed by
Lee Jones
769cb631 1613e604

+56
+48
drivers/mfd/syscon.c
··· 192 192 return syscon->regmap; 193 193 } 194 194 195 + /** 196 + * of_syscon_register_regmap() - Register regmap for specified device node 197 + * @np: Device tree node 198 + * @regmap: Pointer to regmap object 199 + * 200 + * Register an externally created regmap object with syscon for the specified 201 + * device tree node. This regmap will then be returned to client drivers using 202 + * the syscon_regmap_lookup_by_phandle() API. 203 + * 204 + * Return: 0 on success, negative error code on failure. 205 + */ 206 + int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) 207 + { 208 + struct syscon *entry, *syscon = NULL; 209 + int ret; 210 + 211 + if (!np || !regmap) 212 + return -EINVAL; 213 + 214 + syscon = kzalloc(sizeof(*syscon), GFP_KERNEL); 215 + if (!syscon) 216 + return -ENOMEM; 217 + 218 + /* check if syscon entry already exists */ 219 + spin_lock(&syscon_list_slock); 220 + 221 + list_for_each_entry(entry, &syscon_list, list) 222 + if (entry->np == np) { 223 + ret = -EEXIST; 224 + goto err_unlock; 225 + } 226 + 227 + syscon->regmap = regmap; 228 + syscon->np = np; 229 + 230 + /* register the regmap in syscon list */ 231 + list_add_tail(&syscon->list, &syscon_list); 232 + spin_unlock(&syscon_list_slock); 233 + 234 + return 0; 235 + 236 + err_unlock: 237 + spin_unlock(&syscon_list_slock); 238 + kfree(syscon); 239 + return ret; 240 + } 241 + EXPORT_SYMBOL_GPL(of_syscon_register_regmap); 242 + 195 243 struct regmap *device_node_to_regmap(struct device_node *np) 196 244 { 197 245 return device_node_get_regmap(np, false);
+8
include/linux/mfd/syscon.h
··· 28 28 unsigned int *out_args); 29 29 struct regmap *syscon_regmap_lookup_by_phandle_optional(struct device_node *np, 30 30 const char *property); 31 + int of_syscon_register_regmap(struct device_node *np, 32 + struct regmap *regmap); 31 33 #else 32 34 static inline struct regmap *device_node_to_regmap(struct device_node *np) 33 35 { ··· 67 65 const char *property) 68 66 { 69 67 return NULL; 68 + } 69 + 70 + static inline int of_syscon_register_regmap(struct device_node *np, 71 + struct regmap *regmap) 72 + { 73 + return -EOPNOTSUPP; 70 74 } 71 75 72 76 #endif