18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ARM System Control and Management Interface (ARM SCMI) reset driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 ARM Ltd. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 128c2ecf20Sopenharmony_ci#include <linux/scmi_protocol.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/** 158c2ecf20Sopenharmony_ci * struct scmi_reset_data - reset controller information structure 168c2ecf20Sopenharmony_ci * @rcdev: reset controller entity 178c2ecf20Sopenharmony_ci * @handle: ARM SCMI handle used for communication with system controller 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistruct scmi_reset_data { 208c2ecf20Sopenharmony_ci struct reset_controller_dev rcdev; 218c2ecf20Sopenharmony_ci const struct scmi_handle *handle; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define to_scmi_reset_data(p) container_of((p), struct scmi_reset_data, rcdev) 258c2ecf20Sopenharmony_ci#define to_scmi_handle(p) (to_scmi_reset_data(p)->handle) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/** 288c2ecf20Sopenharmony_ci * scmi_reset_assert() - assert device reset 298c2ecf20Sopenharmony_ci * @rcdev: reset controller entity 308c2ecf20Sopenharmony_ci * @id: ID of the reset to be asserted 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * This function implements the reset driver op to assert a device's reset 338c2ecf20Sopenharmony_ci * using the ARM SCMI protocol. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Return: 0 for successful request, else a corresponding error value 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic int 388c2ecf20Sopenharmony_ciscmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci const struct scmi_handle *handle = to_scmi_handle(rcdev); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return handle->reset_ops->assert(handle, id); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/** 468c2ecf20Sopenharmony_ci * scmi_reset_deassert() - deassert device reset 478c2ecf20Sopenharmony_ci * @rcdev: reset controller entity 488c2ecf20Sopenharmony_ci * @id: ID of the reset to be deasserted 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * This function implements the reset driver op to deassert a device's reset 518c2ecf20Sopenharmony_ci * using the ARM SCMI protocol. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Return: 0 for successful request, else a corresponding error value 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic int 568c2ecf20Sopenharmony_ciscmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci const struct scmi_handle *handle = to_scmi_handle(rcdev); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return handle->reset_ops->deassert(handle, id); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * scmi_reset_reset() - reset the device 658c2ecf20Sopenharmony_ci * @rcdev: reset controller entity 668c2ecf20Sopenharmony_ci * @id: ID of the reset signal to be reset(assert + deassert) 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * This function implements the reset driver op to trigger a device's 698c2ecf20Sopenharmony_ci * reset signal using the ARM SCMI protocol. 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * Return: 0 for successful request, else a corresponding error value 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_cistatic int 748c2ecf20Sopenharmony_ciscmi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci const struct scmi_handle *handle = to_scmi_handle(rcdev); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return handle->reset_ops->reset(handle, id); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const struct reset_control_ops scmi_reset_ops = { 828c2ecf20Sopenharmony_ci .assert = scmi_reset_assert, 838c2ecf20Sopenharmony_ci .deassert = scmi_reset_deassert, 848c2ecf20Sopenharmony_ci .reset = scmi_reset_reset, 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int scmi_reset_probe(struct scmi_device *sdev) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct scmi_reset_data *data; 908c2ecf20Sopenharmony_ci struct device *dev = &sdev->dev; 918c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 928c2ecf20Sopenharmony_ci const struct scmi_handle *handle = sdev->handle; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (!handle || !handle->reset_ops) 958c2ecf20Sopenharmony_ci return -ENODEV; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 988c2ecf20Sopenharmony_ci if (!data) 998c2ecf20Sopenharmony_ci return -ENOMEM; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci data->rcdev.ops = &scmi_reset_ops; 1028c2ecf20Sopenharmony_ci data->rcdev.owner = THIS_MODULE; 1038c2ecf20Sopenharmony_ci data->rcdev.of_node = np; 1048c2ecf20Sopenharmony_ci data->rcdev.nr_resets = handle->reset_ops->num_domains_get(handle); 1058c2ecf20Sopenharmony_ci data->handle = handle; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return devm_reset_controller_register(dev, &data->rcdev); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic const struct scmi_device_id scmi_id_table[] = { 1118c2ecf20Sopenharmony_ci { SCMI_PROTOCOL_RESET, "reset" }, 1128c2ecf20Sopenharmony_ci { }, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(scmi, scmi_id_table); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic struct scmi_driver scmi_reset_driver = { 1178c2ecf20Sopenharmony_ci .name = "scmi-reset", 1188c2ecf20Sopenharmony_ci .probe = scmi_reset_probe, 1198c2ecf20Sopenharmony_ci .id_table = scmi_id_table, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_cimodule_scmi_driver(scmi_reset_driver); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); 1248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ARM SCMI reset controller driver"); 1258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 126