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 DECLARE_GLOBAL_DATA_PTR; 19 20 struct syscon_reboot_priv { 21 struct regmap *regmap; 22 unsigned int offset; 23 unsigned int mask; 24 }; 25 26 static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type) 27 { 28 struct syscon_reboot_priv *priv = dev_get_priv(dev); 29 30 regmap_write(priv->regmap, priv->offset, priv->mask); 31 32 return -EINPROGRESS; 33 } 34 35 static struct sysreset_ops syscon_reboot_ops = { 36 .request = syscon_reboot_request, 37 }; 38 39 int syscon_reboot_probe(struct udevice *dev) 40 { 41 struct udevice *syscon; 42 struct syscon_reboot_priv *priv = dev_get_priv(dev); 43 int err; 44 45 err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, 46 "regmap", &syscon); 47 if (err) { 48 error("unable to find syscon device\n"); 49 return err; 50 } 51 52 priv->regmap = syscon_get_regmap(syscon); 53 if (!priv->regmap) { 54 error("unable to find regmap\n"); 55 return -ENODEV; 56 } 57 58 priv->offset = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), 59 "offset", 0); 60 priv->mask = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), 61 "mask", 0); 62 63 return 0; 64 } 65 66 static const struct udevice_id syscon_reboot_ids[] = { 67 { .compatible = "syscon-reboot" }, 68 { /* sentinel */ } 69 }; 70 71 U_BOOT_DRIVER(syscon_reboot) = { 72 .name = "syscon_reboot", 73 .id = UCLASS_SYSRESET, 74 .of_match = syscon_reboot_ids, 75 .probe = syscon_reboot_probe, 76 .priv_auto_alloc_size = sizeof(struct syscon_reboot_priv), 77 .ops = &syscon_reboot_ops, 78 }; 79