Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Texas Instrument's System Control Interface (TI-SCI) reset driver
0004  *
0005  * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
0006  *  Andrew F. Davis <afd@ti.com>
0007  */
0008 
0009 #include <linux/idr.h>
0010 #include <linux/module.h>
0011 #include <linux/mutex.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/reset-controller.h>
0015 #include <linux/soc/ti/ti_sci_protocol.h>
0016 
0017 /**
0018  * struct ti_sci_reset_control - reset control structure
0019  * @dev_id: SoC-specific device identifier
0020  * @reset_mask: reset mask to use for toggling reset
0021  * @lock: synchronize reset_mask read-modify-writes
0022  */
0023 struct ti_sci_reset_control {
0024     u32 dev_id;
0025     u32 reset_mask;
0026     struct mutex lock;
0027 };
0028 
0029 /**
0030  * struct ti_sci_reset_data - reset controller information structure
0031  * @rcdev: reset controller entity
0032  * @dev: reset controller device pointer
0033  * @sci: TI SCI handle used for communication with system controller
0034  * @idr: idr structure for mapping ids to reset control structures
0035  */
0036 struct ti_sci_reset_data {
0037     struct reset_controller_dev rcdev;
0038     struct device *dev;
0039     const struct ti_sci_handle *sci;
0040     struct idr idr;
0041 };
0042 
0043 #define to_ti_sci_reset_data(p) \
0044     container_of((p), struct ti_sci_reset_data, rcdev)
0045 
0046 /**
0047  * ti_sci_reset_set() - program a device's reset
0048  * @rcdev: reset controller entity
0049  * @id: ID of the reset to toggle
0050  * @assert: boolean flag to indicate assert or deassert
0051  *
0052  * This is a common internal function used to assert or deassert a device's
0053  * reset using the TI SCI protocol. The device's reset is asserted if the
0054  * @assert argument is true, or deasserted if @assert argument is false.
0055  * The mechanism itself is a read-modify-write procedure, the current device
0056  * reset register is read using a TI SCI device operation, the new value is
0057  * set or un-set using the reset's mask, and the new reset value written by
0058  * using another TI SCI device operation.
0059  *
0060  * Return: 0 for successful request, else a corresponding error value
0061  */
0062 static int ti_sci_reset_set(struct reset_controller_dev *rcdev,
0063                 unsigned long id, bool assert)
0064 {
0065     struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
0066     const struct ti_sci_handle *sci = data->sci;
0067     const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
0068     struct ti_sci_reset_control *control;
0069     u32 reset_state;
0070     int ret;
0071 
0072     control = idr_find(&data->idr, id);
0073     if (!control)
0074         return -EINVAL;
0075 
0076     mutex_lock(&control->lock);
0077 
0078     ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
0079     if (ret)
0080         goto out;
0081 
0082     if (assert)
0083         reset_state |= control->reset_mask;
0084     else
0085         reset_state &= ~control->reset_mask;
0086 
0087     ret = dev_ops->set_device_resets(sci, control->dev_id, reset_state);
0088 out:
0089     mutex_unlock(&control->lock);
0090 
0091     return ret;
0092 }
0093 
0094 /**
0095  * ti_sci_reset_assert() - assert device reset
0096  * @rcdev: reset controller entity
0097  * @id: ID of the reset to be asserted
0098  *
0099  * This function implements the reset driver op to assert a device's reset
0100  * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
0101  * with the corresponding parameters as passed in, but with the @assert
0102  * argument set to true for asserting the reset.
0103  *
0104  * Return: 0 for successful request, else a corresponding error value
0105  */
0106 static int ti_sci_reset_assert(struct reset_controller_dev *rcdev,
0107                    unsigned long id)
0108 {
0109     return ti_sci_reset_set(rcdev, id, true);
0110 }
0111 
0112 /**
0113  * ti_sci_reset_deassert() - deassert device reset
0114  * @rcdev: reset controller entity
0115  * @id: ID of the reset to be deasserted
0116  *
0117  * This function implements the reset driver op to deassert a device's reset
0118  * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
0119  * with the corresponding parameters as passed in, but with the @assert
0120  * argument set to false for deasserting the reset.
0121  *
0122  * Return: 0 for successful request, else a corresponding error value
0123  */
0124 static int ti_sci_reset_deassert(struct reset_controller_dev *rcdev,
0125                  unsigned long id)
0126 {
0127     return ti_sci_reset_set(rcdev, id, false);
0128 }
0129 
0130 /**
0131  * ti_sci_reset_status() - check device reset status
0132  * @rcdev: reset controller entity
0133  * @id: ID of reset to be checked
0134  *
0135  * This function implements the reset driver op to return the status of a
0136  * device's reset using the TI SCI protocol. The reset register value is read
0137  * by invoking the TI SCI device operation .get_device_resets(), and the
0138  * status of the specific reset is extracted and returned using this reset's
0139  * reset mask.
0140  *
0141  * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted
0142  */
0143 static int ti_sci_reset_status(struct reset_controller_dev *rcdev,
0144                    unsigned long id)
0145 {
0146     struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
0147     const struct ti_sci_handle *sci = data->sci;
0148     const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
0149     struct ti_sci_reset_control *control;
0150     u32 reset_state;
0151     int ret;
0152 
0153     control = idr_find(&data->idr, id);
0154     if (!control)
0155         return -EINVAL;
0156 
0157     ret = dev_ops->get_device_resets(sci, control->dev_id, &reset_state);
0158     if (ret)
0159         return ret;
0160 
0161     return reset_state & control->reset_mask;
0162 }
0163 
0164 static const struct reset_control_ops ti_sci_reset_ops = {
0165     .assert     = ti_sci_reset_assert,
0166     .deassert   = ti_sci_reset_deassert,
0167     .status     = ti_sci_reset_status,
0168 };
0169 
0170 /**
0171  * ti_sci_reset_of_xlate() - translate a set of OF arguments to a reset ID
0172  * @rcdev: reset controller entity
0173  * @reset_spec: OF reset argument specifier
0174  *
0175  * This function performs the translation of the reset argument specifier
0176  * values defined in a reset consumer device node. The function allocates a
0177  * reset control structure for that device reset, and will be used by the
0178  * driver for performing any reset functions on that reset. An idr structure
0179  * is allocated and used to map to the reset control structure. This idr
0180  * is used by the driver to do reset lookups.
0181  *
0182  * Return: 0 for successful request, else a corresponding error value
0183  */
0184 static int ti_sci_reset_of_xlate(struct reset_controller_dev *rcdev,
0185                  const struct of_phandle_args *reset_spec)
0186 {
0187     struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
0188     struct ti_sci_reset_control *control;
0189 
0190     if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
0191         return -EINVAL;
0192 
0193     control = devm_kzalloc(data->dev, sizeof(*control), GFP_KERNEL);
0194     if (!control)
0195         return -ENOMEM;
0196 
0197     control->dev_id = reset_spec->args[0];
0198     control->reset_mask = reset_spec->args[1];
0199     mutex_init(&control->lock);
0200 
0201     return idr_alloc(&data->idr, control, 0, 0, GFP_KERNEL);
0202 }
0203 
0204 static const struct of_device_id ti_sci_reset_of_match[] = {
0205     { .compatible = "ti,sci-reset", },
0206     { /* sentinel */ },
0207 };
0208 MODULE_DEVICE_TABLE(of, ti_sci_reset_of_match);
0209 
0210 static int ti_sci_reset_probe(struct platform_device *pdev)
0211 {
0212     struct ti_sci_reset_data *data;
0213 
0214     if (!pdev->dev.of_node)
0215         return -ENODEV;
0216 
0217     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0218     if (!data)
0219         return -ENOMEM;
0220 
0221     data->sci = devm_ti_sci_get_handle(&pdev->dev);
0222     if (IS_ERR(data->sci))
0223         return PTR_ERR(data->sci);
0224 
0225     data->rcdev.ops = &ti_sci_reset_ops;
0226     data->rcdev.owner = THIS_MODULE;
0227     data->rcdev.of_node = pdev->dev.of_node;
0228     data->rcdev.of_reset_n_cells = 2;
0229     data->rcdev.of_xlate = ti_sci_reset_of_xlate;
0230     data->dev = &pdev->dev;
0231     idr_init(&data->idr);
0232 
0233     platform_set_drvdata(pdev, data);
0234 
0235     return reset_controller_register(&data->rcdev);
0236 }
0237 
0238 static int ti_sci_reset_remove(struct platform_device *pdev)
0239 {
0240     struct ti_sci_reset_data *data = platform_get_drvdata(pdev);
0241 
0242     reset_controller_unregister(&data->rcdev);
0243 
0244     idr_destroy(&data->idr);
0245 
0246     return 0;
0247 }
0248 
0249 static struct platform_driver ti_sci_reset_driver = {
0250     .probe = ti_sci_reset_probe,
0251     .remove = ti_sci_reset_remove,
0252     .driver = {
0253         .name = "ti-sci-reset",
0254         .of_match_table = ti_sci_reset_of_match,
0255     },
0256 };
0257 module_platform_driver(ti_sci_reset_driver);
0258 
0259 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
0260 MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver");
0261 MODULE_LICENSE("GPL v2");