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