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