1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> 4 * 5 * Derived from linux/drivers/power/reset/syscon-reboot.c: 6 * Copyright (C) 2013, Applied Micro Circuits Corporation 7 * Author: Feng Kan <fkan@apm.com> 8 */ 9 10 #include <common.h> 11 #include <dm.h> 12 #include <errno.h> 13 #include <regmap.h> 14 #include <sysreset.h> 15 #include <syscon.h> 16 17 struct syscon_reboot_priv { 18 struct regmap *regmap; 19 unsigned int offset; 20 unsigned int mask; 21 }; 22 23 static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type) 24 { 25 struct syscon_reboot_priv *priv = dev_get_priv(dev); 26 27 regmap_write(priv->regmap, priv->offset, priv->mask); 28 29 return -EINPROGRESS; 30 } 31 32 static struct sysreset_ops syscon_reboot_ops = { 33 .request = syscon_reboot_request, 34 }; 35 36 int syscon_reboot_probe(struct udevice *dev) 37 { 38 struct udevice *syscon; 39 struct syscon_reboot_priv *priv = dev_get_priv(dev); 40 int err; 41 42 err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, 43 "regmap", &syscon); 44 if (err) { 45 pr_err("unable to find syscon device\n"); 46 return err; 47 } 48 49 priv->regmap = syscon_get_regmap(syscon); 50 if (!priv->regmap) { 51 pr_err("unable to find regmap\n"); 52 return -ENODEV; 53 } 54 55 priv->offset = dev_read_u32_default(dev, "offset", 0); 56 priv->mask = dev_read_u32_default(dev, "mask", 0); 57 58 return 0; 59 } 60 61 static const struct udevice_id syscon_reboot_ids[] = { 62 { .compatible = "syscon-reboot" }, 63 { /* sentinel */ } 64 }; 65 66 U_BOOT_DRIVER(syscon_reboot) = { 67 .name = "syscon_reboot", 68 .id = UCLASS_SYSRESET, 69 .of_match = syscon_reboot_ids, 70 .probe = syscon_reboot_probe, 71 .priv_auto_alloc_size = sizeof(struct syscon_reboot_priv), 72 .ops = &syscon_reboot_ops, 73 }; 74