brintos

brintos / linux-shallow public Read only

0
0
Text · 2.3 KiB · 203936f Raw
99 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Generic Syscon Poweroff Driver4 *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/reboot.h>17#include <linux/regmap.h>18 19struct syscon_poweroff_data {20	struct regmap *map;21	u32 offset;22	u32 value;23	u32 mask;24};25 26static int syscon_poweroff(struct sys_off_data *off_data)27{28	struct syscon_poweroff_data *data = off_data->cb_data;29 30	/* Issue the poweroff */31	regmap_update_bits(data->map, data->offset, data->mask, data->value);32 33	mdelay(1000);34 35	pr_emerg("Unable to poweroff system\n");36 37	return NOTIFY_DONE;38}39 40static int syscon_poweroff_probe(struct platform_device *pdev)41{42	struct device *dev = &pdev->dev;43	struct syscon_poweroff_data *data;44	int mask_err, value_err;45 46	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);47	if (!data)48		return -ENOMEM;49 50	data->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap");51	if (IS_ERR(data->map)) {52		data->map = syscon_node_to_regmap(dev->parent->of_node);53		if (IS_ERR(data->map)) {54			dev_err(dev, "unable to get syscon");55			return PTR_ERR(data->map);56		}57	}58 59	if (of_property_read_u32(dev->of_node, "offset", &data->offset)) {60		dev_err(dev, "unable to read 'offset'");61		return -EINVAL;62	}63 64	value_err = of_property_read_u32(dev->of_node, "value", &data->value);65	mask_err = of_property_read_u32(dev->of_node, "mask", &data->mask);66	if (value_err && mask_err) {67		dev_err(dev, "unable to read 'value' and 'mask'");68		return -EINVAL;69	}70 71	if (value_err) {72		/* support old binding */73		data->value = data->mask;74		data->mask = 0xFFFFFFFF;75	} else if (mask_err) {76		/* support value without mask*/77		data->mask = 0xFFFFFFFF;78	}79 80	return devm_register_sys_off_handler(&pdev->dev,81					     SYS_OFF_MODE_POWER_OFF,82					     SYS_OFF_PRIO_DEFAULT,83					     syscon_poweroff, data);84}85 86static const struct of_device_id syscon_poweroff_of_match[] = {87	{ .compatible = "syscon-poweroff" },88	{}89};90 91static struct platform_driver syscon_poweroff_driver = {92	.probe = syscon_poweroff_probe,93	.driver = {94		.name = "syscon-poweroff",95		.of_match_table = syscon_poweroff_of_match,96	},97};98builtin_platform_driver(syscon_poweroff_driver);99