0001
0002
0003
0004
0005
0006 #include <linux/module.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/reset-controller.h>
0009 #include <linux/delay.h>
0010 #include <linux/io.h>
0011 #include <linux/of_device.h>
0012 #include <dt-bindings/reset/qcom,sdm845-aoss.h>
0013
0014 struct qcom_aoss_reset_map {
0015 unsigned int reg;
0016 };
0017
0018 struct qcom_aoss_desc {
0019 const struct qcom_aoss_reset_map *resets;
0020 size_t num_resets;
0021 };
0022
0023 struct qcom_aoss_reset_data {
0024 struct reset_controller_dev rcdev;
0025 void __iomem *base;
0026 const struct qcom_aoss_desc *desc;
0027 };
0028
0029 static const struct qcom_aoss_reset_map sdm845_aoss_resets[] = {
0030 [AOSS_CC_MSS_RESTART] = {0x10000},
0031 [AOSS_CC_CAMSS_RESTART] = {0x11000},
0032 [AOSS_CC_VENUS_RESTART] = {0x12000},
0033 [AOSS_CC_GPU_RESTART] = {0x13000},
0034 [AOSS_CC_DISPSS_RESTART] = {0x14000},
0035 [AOSS_CC_WCSS_RESTART] = {0x20000},
0036 [AOSS_CC_LPASS_RESTART] = {0x30000},
0037 };
0038
0039 static const struct qcom_aoss_desc sdm845_aoss_desc = {
0040 .resets = sdm845_aoss_resets,
0041 .num_resets = ARRAY_SIZE(sdm845_aoss_resets),
0042 };
0043
0044 static inline struct qcom_aoss_reset_data *to_qcom_aoss_reset_data(
0045 struct reset_controller_dev *rcdev)
0046 {
0047 return container_of(rcdev, struct qcom_aoss_reset_data, rcdev);
0048 }
0049
0050 static int qcom_aoss_control_assert(struct reset_controller_dev *rcdev,
0051 unsigned long idx)
0052 {
0053 struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
0054 const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
0055
0056 writel(1, data->base + map->reg);
0057
0058 usleep_range(200, 300);
0059 return 0;
0060 }
0061
0062 static int qcom_aoss_control_deassert(struct reset_controller_dev *rcdev,
0063 unsigned long idx)
0064 {
0065 struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
0066 const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
0067
0068 writel(0, data->base + map->reg);
0069
0070 usleep_range(200, 300);
0071 return 0;
0072 }
0073
0074 static int qcom_aoss_control_reset(struct reset_controller_dev *rcdev,
0075 unsigned long idx)
0076 {
0077 qcom_aoss_control_assert(rcdev, idx);
0078
0079 return qcom_aoss_control_deassert(rcdev, idx);
0080 }
0081
0082 static const struct reset_control_ops qcom_aoss_reset_ops = {
0083 .reset = qcom_aoss_control_reset,
0084 .assert = qcom_aoss_control_assert,
0085 .deassert = qcom_aoss_control_deassert,
0086 };
0087
0088 static int qcom_aoss_reset_probe(struct platform_device *pdev)
0089 {
0090 struct qcom_aoss_reset_data *data;
0091 struct device *dev = &pdev->dev;
0092 const struct qcom_aoss_desc *desc;
0093 struct resource *res;
0094
0095 desc = of_device_get_match_data(dev);
0096 if (!desc)
0097 return -EINVAL;
0098
0099 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0100 if (!data)
0101 return -ENOMEM;
0102
0103 data->desc = desc;
0104 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0105 data->base = devm_ioremap_resource(dev, res);
0106 if (IS_ERR(data->base))
0107 return PTR_ERR(data->base);
0108
0109 data->rcdev.owner = THIS_MODULE;
0110 data->rcdev.ops = &qcom_aoss_reset_ops;
0111 data->rcdev.nr_resets = desc->num_resets;
0112 data->rcdev.of_node = dev->of_node;
0113
0114 return devm_reset_controller_register(dev, &data->rcdev);
0115 }
0116
0117 static const struct of_device_id qcom_aoss_reset_of_match[] = {
0118 { .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc },
0119 {}
0120 };
0121 MODULE_DEVICE_TABLE(of, qcom_aoss_reset_of_match);
0122
0123 static struct platform_driver qcom_aoss_reset_driver = {
0124 .probe = qcom_aoss_reset_probe,
0125 .driver = {
0126 .name = "qcom_aoss_reset",
0127 .of_match_table = qcom_aoss_reset_of_match,
0128 },
0129 };
0130
0131 module_platform_driver(qcom_aoss_reset_driver);
0132
0133 MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver");
0134 MODULE_LICENSE("GPL v2");