1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/module.h> 7 #include <linux/platform_device.h> 8 #include <linux/reset-controller.h> 9 #include <linux/delay.h> 10 #include <linux/io.h> 11 #include <linux/of.h> 12 #include <dt-bindings/reset/qcom,sdm845-aoss.h> 13 14 struct qcom_aoss_reset_map { 15 unsigned int reg; 16 }; 17 18 struct qcom_aoss_desc { 19 const struct qcom_aoss_reset_map *resets; 20 size_t num_resets; 21 }; 22 23 struct qcom_aoss_reset_data { 24 struct reset_controller_dev rcdev; 25 void __iomem *base; 26 const struct qcom_aoss_desc *desc; 27 }; 28 29 static const struct qcom_aoss_reset_map sdm845_aoss_resets[] = { 30 [AOSS_CC_MSS_RESTART] = {0x10000}, 31 [AOSS_CC_CAMSS_RESTART] = {0x11000}, 32 [AOSS_CC_VENUS_RESTART] = {0x12000}, 33 [AOSS_CC_GPU_RESTART] = {0x13000}, 34 [AOSS_CC_DISPSS_RESTART] = {0x14000}, 35 [AOSS_CC_WCSS_RESTART] = {0x20000}, 36 [AOSS_CC_LPASS_RESTART] = {0x30000}, 37 }; 38 39 static const struct qcom_aoss_desc sdm845_aoss_desc = { 40 .resets = sdm845_aoss_resets, 41 .num_resets = ARRAY_SIZE(sdm845_aoss_resets), 42 }; 43 44 static inline struct qcom_aoss_reset_data *to_qcom_aoss_reset_data( 45 struct reset_controller_dev *rcdev) 46 { 47 return container_of(rcdev, struct qcom_aoss_reset_data, rcdev); 48 } 49 50 static int qcom_aoss_control_assert(struct reset_controller_dev *rcdev, 51 unsigned long idx) 52 { 53 struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev); 54 const struct qcom_aoss_reset_map *map = &data->desc->resets[idx]; 55 56 writel(1, data->base + map->reg); 57 /* Wait 6 32kHz sleep cycles for reset */ 58 usleep_range(200, 300); 59 return 0; 60 } 61 62 static int qcom_aoss_control_deassert(struct reset_controller_dev *rcdev, 63 unsigned long idx) 64 { 65 struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev); 66 const struct qcom_aoss_reset_map *map = &data->desc->resets[idx]; 67 68 writel(0, data->base + map->reg); 69 /* Wait 6 32kHz sleep cycles for reset */ 70 usleep_range(200, 300); 71 return 0; 72 } 73 74 static int qcom_aoss_control_reset(struct reset_controller_dev *rcdev, 75 unsigned long idx) 76 { 77 qcom_aoss_control_assert(rcdev, idx); 78 79 return qcom_aoss_control_deassert(rcdev, idx); 80 } 81 82 static const struct reset_control_ops qcom_aoss_reset_ops = { 83 .reset = qcom_aoss_control_reset, 84 .assert = qcom_aoss_control_assert, 85 .deassert = qcom_aoss_control_deassert, 86 }; 87 88 static int qcom_aoss_reset_probe(struct platform_device *pdev) 89 { 90 struct qcom_aoss_reset_data *data; 91 struct device *dev = &pdev->dev; 92 const struct qcom_aoss_desc *desc; 93 94 desc = of_device_get_match_data(dev); 95 if (!desc) 96 return -EINVAL; 97 98 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 99 if (!data) 100 return -ENOMEM; 101 102 data->desc = desc; 103 data->base = devm_platform_ioremap_resource(pdev, 0); 104 if (IS_ERR(data->base)) 105 return PTR_ERR(data->base); 106 107 data->rcdev.owner = THIS_MODULE; 108 data->rcdev.ops = &qcom_aoss_reset_ops; 109 data->rcdev.nr_resets = desc->num_resets; 110 data->rcdev.of_node = dev->of_node; 111 112 return devm_reset_controller_register(dev, &data->rcdev); 113 } 114 115 static const struct of_device_id qcom_aoss_reset_of_match[] = { 116 { .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc }, 117 {} 118 }; 119 MODULE_DEVICE_TABLE(of, qcom_aoss_reset_of_match); 120 121 static struct platform_driver qcom_aoss_reset_driver = { 122 .probe = qcom_aoss_reset_probe, 123 .driver = { 124 .name = "qcom_aoss_reset", 125 .of_match_table = qcom_aoss_reset_of_match, 126 }, 127 }; 128 129 module_platform_driver(qcom_aoss_reset_driver); 130 131 MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver"); 132 MODULE_LICENSE("GPL v2"); 133