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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.7 100 lines 2.2 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Generic Syscon Poweroff Driver 4 * 5 * Copyright (c) 2015, National Instruments Corp. 6 * Author: Moritz Fischer <moritz.fischer@ettus.com> 7 */ 8 9#include <linux/delay.h> 10#include <linux/io.h> 11#include <linux/notifier.h> 12#include <linux/mfd/syscon.h> 13#include <linux/of.h> 14#include <linux/platform_device.h> 15#include <linux/pm.h> 16#include <linux/regmap.h> 17 18static struct regmap *map; 19static u32 offset; 20static u32 value; 21static u32 mask; 22 23static void syscon_poweroff(void) 24{ 25 /* Issue the poweroff */ 26 regmap_update_bits(map, offset, mask, value); 27 28 mdelay(1000); 29 30 pr_emerg("Unable to poweroff system\n"); 31} 32 33static int syscon_poweroff_probe(struct platform_device *pdev) 34{ 35 struct device *dev = &pdev->dev; 36 int mask_err, value_err; 37 38 map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); 39 if (IS_ERR(map)) { 40 map = syscon_node_to_regmap(dev->parent->of_node); 41 if (IS_ERR(map)) { 42 dev_err(dev, "unable to get syscon"); 43 return PTR_ERR(map); 44 } 45 } 46 47 if (of_property_read_u32(dev->of_node, "offset", &offset)) { 48 dev_err(dev, "unable to read 'offset'"); 49 return -EINVAL; 50 } 51 52 value_err = of_property_read_u32(dev->of_node, "value", &value); 53 mask_err = of_property_read_u32(dev->of_node, "mask", &mask); 54 if (value_err && mask_err) { 55 dev_err(dev, "unable to read 'value' and 'mask'"); 56 return -EINVAL; 57 } 58 59 if (value_err) { 60 /* support old binding */ 61 value = mask; 62 mask = 0xFFFFFFFF; 63 } else if (mask_err) { 64 /* support value without mask*/ 65 mask = 0xFFFFFFFF; 66 } 67 68 if (pm_power_off) { 69 dev_err(dev, "pm_power_off already claimed for %ps", 70 pm_power_off); 71 return -EBUSY; 72 } 73 74 pm_power_off = syscon_poweroff; 75 76 return 0; 77} 78 79static int syscon_poweroff_remove(struct platform_device *pdev) 80{ 81 if (pm_power_off == syscon_poweroff) 82 pm_power_off = NULL; 83 84 return 0; 85} 86 87static const struct of_device_id syscon_poweroff_of_match[] = { 88 { .compatible = "syscon-poweroff" }, 89 {} 90}; 91 92static struct platform_driver syscon_poweroff_driver = { 93 .probe = syscon_poweroff_probe, 94 .remove = syscon_poweroff_remove, 95 .driver = { 96 .name = "syscon-poweroff", 97 .of_match_table = syscon_poweroff_of_match, 98 }, 99}; 100builtin_platform_driver(syscon_poweroff_driver);