linux/drivers/power/reset/syscon-reboot-mode.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13#include <linux/of.h>
  14#include <linux/platform_device.h>
  15#include <linux/reboot.h>
  16#include <linux/regmap.h>
  17#include <linux/mfd/syscon.h>
  18#include "reboot-mode.h"
  19
  20struct syscon_reboot_mode {
  21        struct regmap *map;
  22        struct reboot_mode_driver reboot;
  23        u32 offset;
  24        u32 mask;
  25};
  26
  27static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot,
  28                                    unsigned int magic)
  29{
  30        struct syscon_reboot_mode *syscon_rbm;
  31        int ret;
  32
  33        syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot);
  34
  35        ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset,
  36                                 syscon_rbm->mask, magic);
  37        if (ret < 0)
  38                dev_err(reboot->dev, "update reboot mode bits failed\n");
  39
  40        return ret;
  41}
  42
  43static int syscon_reboot_mode_probe(struct platform_device *pdev)
  44{
  45        int ret;
  46        struct syscon_reboot_mode *syscon_rbm;
  47
  48        syscon_rbm = devm_kzalloc(&pdev->dev, sizeof(*syscon_rbm), GFP_KERNEL);
  49        if (!syscon_rbm)
  50                return -ENOMEM;
  51
  52        syscon_rbm->reboot.dev = &pdev->dev;
  53        syscon_rbm->reboot.write = syscon_reboot_mode_write;
  54        syscon_rbm->mask = 0xffffffff;
  55
  56        syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
  57        if (IS_ERR(syscon_rbm->map))
  58                return PTR_ERR(syscon_rbm->map);
  59
  60        if (of_property_read_u32(pdev->dev.of_node, "offset",
  61            &syscon_rbm->offset))
  62                return -EINVAL;
  63
  64        of_property_read_u32(pdev->dev.of_node, "mask", &syscon_rbm->mask);
  65
  66        ret = devm_reboot_mode_register(&pdev->dev, &syscon_rbm->reboot);
  67        if (ret)
  68                dev_err(&pdev->dev, "can't register reboot mode\n");
  69
  70        return ret;
  71}
  72
  73static const struct of_device_id syscon_reboot_mode_of_match[] = {
  74        { .compatible = "syscon-reboot-mode" },
  75        {}
  76};
  77
  78static struct platform_driver syscon_reboot_mode_driver = {
  79        .probe = syscon_reboot_mode_probe,
  80        .driver = {
  81                .name = "syscon-reboot-mode",
  82                .of_match_table = syscon_reboot_mode_of_match,
  83        },
  84};
  85module_platform_driver(syscon_reboot_mode_driver);
  86
  87MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
  88MODULE_DESCRIPTION("SYSCON reboot mode driver");
  89MODULE_LICENSE("GPL v2");
  90