reset-qcom-aoss.c (3579B)
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_device.h> 12#include <dt-bindings/reset/qcom,sdm845-aoss.h> 13 14struct qcom_aoss_reset_map { 15 unsigned int reg; 16}; 17 18struct qcom_aoss_desc { 19 const struct qcom_aoss_reset_map *resets; 20 size_t num_resets; 21}; 22 23struct qcom_aoss_reset_data { 24 struct reset_controller_dev rcdev; 25 void __iomem *base; 26 const struct qcom_aoss_desc *desc; 27}; 28 29static 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 39static const struct qcom_aoss_desc sdm845_aoss_desc = { 40 .resets = sdm845_aoss_resets, 41 .num_resets = ARRAY_SIZE(sdm845_aoss_resets), 42}; 43 44static 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 50static 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 62static 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 74static 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 82static 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 88static 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 struct resource *res; 94 95 desc = of_device_get_match_data(dev); 96 if (!desc) 97 return -EINVAL; 98 99 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 100 if (!data) 101 return -ENOMEM; 102 103 data->desc = desc; 104 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 105 data->base = devm_ioremap_resource(dev, res); 106 if (IS_ERR(data->base)) 107 return PTR_ERR(data->base); 108 109 data->rcdev.owner = THIS_MODULE; 110 data->rcdev.ops = &qcom_aoss_reset_ops; 111 data->rcdev.nr_resets = desc->num_resets; 112 data->rcdev.of_node = dev->of_node; 113 114 return devm_reset_controller_register(dev, &data->rcdev); 115} 116 117static const struct of_device_id qcom_aoss_reset_of_match[] = { 118 { .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc }, 119 {} 120}; 121MODULE_DEVICE_TABLE(of, qcom_aoss_reset_of_match); 122 123static struct platform_driver qcom_aoss_reset_driver = { 124 .probe = qcom_aoss_reset_probe, 125 .driver = { 126 .name = "qcom_aoss_reset", 127 .of_match_table = qcom_aoss_reset_of_match, 128 }, 129}; 130 131module_platform_driver(qcom_aoss_reset_driver); 132 133MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver"); 134MODULE_LICENSE("GPL v2");