root/drivers/power/reset/syscon-poweroff.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. syscon_poweroff
  2. syscon_poweroff_probe
  3. syscon_poweroff_remove
  4. syscon_poweroff_register

   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/kallsyms.h>
  10 #include <linux/delay.h>
  11 #include <linux/io.h>
  12 #include <linux/notifier.h>
  13 #include <linux/mfd/syscon.h>
  14 #include <linux/of_address.h>
  15 #include <linux/of_device.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/pm.h>
  18 #include <linux/regmap.h>
  19 
  20 static struct regmap *map;
  21 static u32 offset;
  22 static u32 value;
  23 static u32 mask;
  24 
  25 static void syscon_poweroff(void)
  26 {
  27         /* Issue the poweroff */
  28         regmap_update_bits(map, offset, mask, value);
  29 
  30         mdelay(1000);
  31 
  32         pr_emerg("Unable to poweroff system\n");
  33 }
  34 
  35 static int syscon_poweroff_probe(struct platform_device *pdev)
  36 {
  37         char symname[KSYM_NAME_LEN];
  38         int mask_err, value_err;
  39 
  40         map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap");
  41         if (IS_ERR(map)) {
  42                 dev_err(&pdev->dev, "unable to get syscon");
  43                 return PTR_ERR(map);
  44         }
  45 
  46         if (of_property_read_u32(pdev->dev.of_node, "offset", &offset)) {
  47                 dev_err(&pdev->dev, "unable to read 'offset'");
  48                 return -EINVAL;
  49         }
  50 
  51         value_err = of_property_read_u32(pdev->dev.of_node, "value", &value);
  52         mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &mask);
  53         if (value_err && mask_err) {
  54                 dev_err(&pdev->dev, "unable to read 'value' and 'mask'");
  55                 return -EINVAL;
  56         }
  57 
  58         if (value_err) {
  59                 /* support old binding */
  60                 value = mask;
  61                 mask = 0xFFFFFFFF;
  62         } else if (mask_err) {
  63                 /* support value without mask*/
  64                 mask = 0xFFFFFFFF;
  65         }
  66 
  67         if (pm_power_off) {
  68                 lookup_symbol_name((ulong)pm_power_off, symname);
  69                 dev_err(&pdev->dev,
  70                 "pm_power_off already claimed %p %s",
  71                 pm_power_off, symname);
  72                 return -EBUSY;
  73         }
  74 
  75         pm_power_off = syscon_poweroff;
  76 
  77         return 0;
  78 }
  79 
  80 static int syscon_poweroff_remove(struct platform_device *pdev)
  81 {
  82         if (pm_power_off == syscon_poweroff)
  83                 pm_power_off = NULL;
  84 
  85         return 0;
  86 }
  87 
  88 static const struct of_device_id syscon_poweroff_of_match[] = {
  89         { .compatible = "syscon-poweroff" },
  90         {}
  91 };
  92 
  93 static struct platform_driver syscon_poweroff_driver = {
  94         .probe = syscon_poweroff_probe,
  95         .remove = syscon_poweroff_remove,
  96         .driver = {
  97                 .name = "syscon-poweroff",
  98                 .of_match_table = syscon_poweroff_of_match,
  99         },
 100 };
 101 
 102 static int __init syscon_poweroff_register(void)
 103 {
 104         return platform_driver_register(&syscon_poweroff_driver);
 105 }
 106 device_initcall(syscon_poweroff_register);

/* [<][>][^][v][top][bottom][index][help] */