linux/drivers/reset/reset-gemini.c
<<
>>
Prefs
   1/*
   2 * Cortina Gemini Reset controller driver
   3 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9
  10#include <linux/err.h>
  11#include <linux/init.h>
  12#include <linux/mfd/syscon.h>
  13#include <linux/regmap.h>
  14#include <linux/of.h>
  15#include <linux/platform_device.h>
  16#include <linux/reset-controller.h>
  17#include <dt-bindings/reset/cortina,gemini-reset.h>
  18
  19/**
  20 * struct gemini_reset - gemini reset controller
  21 * @map: regmap to access the containing system controller
  22 * @rcdev: reset controller device
  23 */
  24struct gemini_reset {
  25        struct regmap *map;
  26        struct reset_controller_dev rcdev;
  27};
  28
  29#define GEMINI_GLOBAL_SOFT_RESET 0x0c
  30
  31#define to_gemini_reset(p) \
  32        container_of((p), struct gemini_reset, rcdev)
  33
  34/*
  35 * This is a self-deasserting reset controller.
  36 */
  37static int gemini_reset(struct reset_controller_dev *rcdev,
  38                        unsigned long id)
  39{
  40        struct gemini_reset *gr = to_gemini_reset(rcdev);
  41
  42        /* Manual says to always set BIT 30 (CPU1) to 1 */
  43        return regmap_write(gr->map,
  44                            GEMINI_GLOBAL_SOFT_RESET,
  45                            BIT(GEMINI_RESET_CPU1) | BIT(id));
  46}
  47
  48static int gemini_reset_status(struct reset_controller_dev *rcdev,
  49                             unsigned long id)
  50{
  51        struct gemini_reset *gr = to_gemini_reset(rcdev);
  52        u32 val;
  53        int ret;
  54
  55        ret = regmap_read(gr->map, GEMINI_GLOBAL_SOFT_RESET, &val);
  56        if (ret)
  57                return ret;
  58
  59        return !!(val & BIT(id));
  60}
  61
  62static const struct reset_control_ops gemini_reset_ops = {
  63        .reset = gemini_reset,
  64        .status = gemini_reset_status,
  65};
  66
  67static int gemini_reset_probe(struct platform_device *pdev)
  68{
  69        struct gemini_reset *gr;
  70        struct device *dev = &pdev->dev;
  71        struct device_node *np = dev->of_node;
  72        int ret;
  73
  74        gr = devm_kzalloc(dev, sizeof(*gr), GFP_KERNEL);
  75        if (!gr)
  76                return -ENOMEM;
  77
  78        gr->map = syscon_node_to_regmap(np);
  79        if (IS_ERR(gr->map)) {
  80                ret = PTR_ERR(gr->map);
  81                dev_err(dev, "unable to get regmap (%d)", ret);
  82                return ret;
  83        }
  84        gr->rcdev.owner = THIS_MODULE;
  85        gr->rcdev.nr_resets = 32;
  86        gr->rcdev.ops = &gemini_reset_ops;
  87        gr->rcdev.of_node = pdev->dev.of_node;
  88
  89        ret = devm_reset_controller_register(&pdev->dev, &gr->rcdev);
  90        if (ret)
  91                return ret;
  92
  93        dev_info(dev, "registered Gemini reset controller\n");
  94        return 0;
  95}
  96
  97static const struct of_device_id gemini_reset_dt_ids[] = {
  98        { .compatible = "cortina,gemini-syscon", },
  99        { /* sentinel */ },
 100};
 101
 102static struct platform_driver gemini_reset_driver = {
 103        .probe  = gemini_reset_probe,
 104        .driver = {
 105                .name           = "gemini-reset",
 106                .of_match_table = gemini_reset_dt_ids,
 107                .suppress_bind_attrs = true,
 108        },
 109};
 110builtin_platform_driver(gemini_reset_driver);
 111