linux/drivers/reset/reset-zynqmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Xilinx, Inc.
   4 *
   5 */
   6
   7#include <linux/err.h>
   8#include <linux/of.h>
   9#include <linux/platform_device.h>
  10#include <linux/reset-controller.h>
  11#include <linux/firmware/xlnx-zynqmp.h>
  12#include <linux/of_device.h>
  13
  14#define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START)
  15#define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START
  16#define VERSAL_NR_RESETS        95
  17
  18struct zynqmp_reset_soc_data {
  19        u32 reset_id;
  20        u32 num_resets;
  21};
  22
  23struct zynqmp_reset_data {
  24        struct reset_controller_dev rcdev;
  25        const struct zynqmp_reset_soc_data *data;
  26};
  27
  28static inline struct zynqmp_reset_data *
  29to_zynqmp_reset_data(struct reset_controller_dev *rcdev)
  30{
  31        return container_of(rcdev, struct zynqmp_reset_data, rcdev);
  32}
  33
  34static int zynqmp_reset_assert(struct reset_controller_dev *rcdev,
  35                               unsigned long id)
  36{
  37        struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
  38
  39        return zynqmp_pm_reset_assert(priv->data->reset_id + id,
  40                                      PM_RESET_ACTION_ASSERT);
  41}
  42
  43static int zynqmp_reset_deassert(struct reset_controller_dev *rcdev,
  44                                 unsigned long id)
  45{
  46        struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
  47
  48        return zynqmp_pm_reset_assert(priv->data->reset_id + id,
  49                                      PM_RESET_ACTION_RELEASE);
  50}
  51
  52static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
  53                               unsigned long id)
  54{
  55        struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
  56        int err;
  57        u32 val;
  58
  59        err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val);
  60        if (err)
  61                return err;
  62
  63        return val;
  64}
  65
  66static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
  67                              unsigned long id)
  68{
  69        struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
  70
  71        return zynqmp_pm_reset_assert(priv->data->reset_id + id,
  72                                      PM_RESET_ACTION_PULSE);
  73}
  74
  75static int zynqmp_reset_of_xlate(struct reset_controller_dev *rcdev,
  76                                 const struct of_phandle_args *reset_spec)
  77{
  78        return reset_spec->args[0];
  79}
  80
  81static const struct zynqmp_reset_soc_data zynqmp_reset_data = {
  82        .reset_id = ZYNQMP_RESET_ID,
  83        .num_resets = ZYNQMP_NR_RESETS,
  84};
  85
  86static const struct zynqmp_reset_soc_data versal_reset_data = {
  87        .reset_id = 0,
  88        .num_resets = VERSAL_NR_RESETS,
  89};
  90
  91static const struct reset_control_ops zynqmp_reset_ops = {
  92        .reset = zynqmp_reset_reset,
  93        .assert = zynqmp_reset_assert,
  94        .deassert = zynqmp_reset_deassert,
  95        .status = zynqmp_reset_status,
  96};
  97
  98static int zynqmp_reset_probe(struct platform_device *pdev)
  99{
 100        struct zynqmp_reset_data *priv;
 101
 102        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 103        if (!priv)
 104                return -ENOMEM;
 105
 106        priv->data = of_device_get_match_data(&pdev->dev);
 107        if (!priv->data)
 108                return -EINVAL;
 109
 110        platform_set_drvdata(pdev, priv);
 111
 112        priv->rcdev.ops = &zynqmp_reset_ops;
 113        priv->rcdev.owner = THIS_MODULE;
 114        priv->rcdev.of_node = pdev->dev.of_node;
 115        priv->rcdev.nr_resets = priv->data->num_resets;
 116        priv->rcdev.of_reset_n_cells = 1;
 117        priv->rcdev.of_xlate = zynqmp_reset_of_xlate;
 118
 119        return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
 120}
 121
 122static const struct of_device_id zynqmp_reset_dt_ids[] = {
 123        { .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, },
 124        { .compatible = "xlnx,versal-reset", .data = &versal_reset_data, },
 125        { /* sentinel */ },
 126};
 127
 128static struct platform_driver zynqmp_reset_driver = {
 129        .probe  = zynqmp_reset_probe,
 130        .driver = {
 131                .name           = KBUILD_MODNAME,
 132                .of_match_table = zynqmp_reset_dt_ids,
 133        },
 134};
 135
 136static int __init zynqmp_reset_init(void)
 137{
 138        return platform_driver_register(&zynqmp_reset_driver);
 139}
 140
 141arch_initcall(zynqmp_reset_init);
 142