linux/drivers/reset/reset-scmi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ARM System Control and Management Interface (ARM SCMI) reset driver
   4 *
   5 * Copyright (C) 2019-2021 ARM Ltd.
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/of.h>
  10#include <linux/device.h>
  11#include <linux/reset-controller.h>
  12#include <linux/scmi_protocol.h>
  13
  14static const struct scmi_reset_proto_ops *reset_ops;
  15
  16/**
  17 * struct scmi_reset_data - reset controller information structure
  18 * @rcdev: reset controller entity
  19 * @ph: ARM SCMI protocol handle used for communication with system controller
  20 */
  21struct scmi_reset_data {
  22        struct reset_controller_dev rcdev;
  23        const struct scmi_protocol_handle *ph;
  24};
  25
  26#define to_scmi_reset_data(p)   container_of((p), struct scmi_reset_data, rcdev)
  27#define to_scmi_handle(p)       (to_scmi_reset_data(p)->ph)
  28
  29/**
  30 * scmi_reset_assert() - assert device reset
  31 * @rcdev: reset controller entity
  32 * @id: ID of the reset to be asserted
  33 *
  34 * This function implements the reset driver op to assert a device's reset
  35 * using the ARM SCMI protocol.
  36 *
  37 * Return: 0 for successful request, else a corresponding error value
  38 */
  39static int
  40scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
  41{
  42        const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
  43
  44        return reset_ops->assert(ph, id);
  45}
  46
  47/**
  48 * scmi_reset_deassert() - deassert device reset
  49 * @rcdev: reset controller entity
  50 * @id: ID of the reset to be deasserted
  51 *
  52 * This function implements the reset driver op to deassert a device's reset
  53 * using the ARM SCMI protocol.
  54 *
  55 * Return: 0 for successful request, else a corresponding error value
  56 */
  57static int
  58scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
  59{
  60        const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
  61
  62        return reset_ops->deassert(ph, id);
  63}
  64
  65/**
  66 * scmi_reset_reset() - reset the device
  67 * @rcdev: reset controller entity
  68 * @id: ID of the reset signal to be reset(assert + deassert)
  69 *
  70 * This function implements the reset driver op to trigger a device's
  71 * reset signal using the ARM SCMI protocol.
  72 *
  73 * Return: 0 for successful request, else a corresponding error value
  74 */
  75static int
  76scmi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
  77{
  78        const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev);
  79
  80        return reset_ops->reset(ph, id);
  81}
  82
  83static const struct reset_control_ops scmi_reset_ops = {
  84        .assert         = scmi_reset_assert,
  85        .deassert       = scmi_reset_deassert,
  86        .reset          = scmi_reset_reset,
  87};
  88
  89static int scmi_reset_probe(struct scmi_device *sdev)
  90{
  91        struct scmi_reset_data *data;
  92        struct device *dev = &sdev->dev;
  93        struct device_node *np = dev->of_node;
  94        const struct scmi_handle *handle = sdev->handle;
  95        struct scmi_protocol_handle *ph;
  96
  97        if (!handle)
  98                return -ENODEV;
  99
 100        reset_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_RESET, &ph);
 101        if (IS_ERR(reset_ops))
 102                return PTR_ERR(reset_ops);
 103
 104        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 105        if (!data)
 106                return -ENOMEM;
 107
 108        data->rcdev.ops = &scmi_reset_ops;
 109        data->rcdev.owner = THIS_MODULE;
 110        data->rcdev.of_node = np;
 111        data->rcdev.nr_resets = reset_ops->num_domains_get(ph);
 112        data->ph = ph;
 113
 114        return devm_reset_controller_register(dev, &data->rcdev);
 115}
 116
 117static const struct scmi_device_id scmi_id_table[] = {
 118        { SCMI_PROTOCOL_RESET, "reset" },
 119        { },
 120};
 121MODULE_DEVICE_TABLE(scmi, scmi_id_table);
 122
 123static struct scmi_driver scmi_reset_driver = {
 124        .name = "scmi-reset",
 125        .probe = scmi_reset_probe,
 126        .id_table = scmi_id_table,
 127};
 128module_scmi_driver(scmi_reset_driver);
 129
 130MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
 131MODULE_DESCRIPTION("ARM SCMI reset controller driver");
 132MODULE_LICENSE("GPL v2");
 133