1eea2926bSSibi Sankar // SPDX-License-Identifier: GPL-2.0
2eea2926bSSibi Sankar /*
3eea2926bSSibi Sankar * Copyright (C) 2018 The Linux Foundation. All rights reserved.
4eea2926bSSibi Sankar */
5eea2926bSSibi Sankar
6eea2926bSSibi Sankar #include <linux/module.h>
7*bad8a8afSRob Herring #include <linux/of.h>
8eea2926bSSibi Sankar #include <linux/platform_device.h>
9eea2926bSSibi Sankar #include <linux/regmap.h>
10eea2926bSSibi Sankar #include <linux/reset-controller.h>
11eea2926bSSibi Sankar
12eea2926bSSibi Sankar #include <dt-bindings/reset/qcom,sdm845-pdc.h>
13eea2926bSSibi Sankar
1408218a08SSibi Sankar #define RPMH_SDM845_PDC_SYNC_RESET 0x100
1508218a08SSibi Sankar #define RPMH_SC7280_PDC_SYNC_RESET 0x1000
16eea2926bSSibi Sankar
17eea2926bSSibi Sankar struct qcom_pdc_reset_map {
18eea2926bSSibi Sankar u8 bit;
19eea2926bSSibi Sankar };
20eea2926bSSibi Sankar
2108218a08SSibi Sankar struct qcom_pdc_reset_desc {
2208218a08SSibi Sankar const struct qcom_pdc_reset_map *resets;
2308218a08SSibi Sankar size_t num_resets;
2408218a08SSibi Sankar unsigned int offset;
2508218a08SSibi Sankar };
2608218a08SSibi Sankar
27eea2926bSSibi Sankar struct qcom_pdc_reset_data {
28eea2926bSSibi Sankar struct reset_controller_dev rcdev;
29eea2926bSSibi Sankar struct regmap *regmap;
3008218a08SSibi Sankar const struct qcom_pdc_reset_desc *desc;
31eea2926bSSibi Sankar };
32eea2926bSSibi Sankar
3308218a08SSibi Sankar static const struct regmap_config pdc_regmap_config = {
34eea2926bSSibi Sankar .name = "pdc-reset",
35eea2926bSSibi Sankar .reg_bits = 32,
36eea2926bSSibi Sankar .reg_stride = 4,
37eea2926bSSibi Sankar .val_bits = 32,
38eea2926bSSibi Sankar .max_register = 0x20000,
39eea2926bSSibi Sankar .fast_io = true,
40eea2926bSSibi Sankar };
41eea2926bSSibi Sankar
42eea2926bSSibi Sankar static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = {
43eea2926bSSibi Sankar [PDC_APPS_SYNC_RESET] = {0},
44eea2926bSSibi Sankar [PDC_SP_SYNC_RESET] = {1},
45eea2926bSSibi Sankar [PDC_AUDIO_SYNC_RESET] = {2},
46eea2926bSSibi Sankar [PDC_SENSORS_SYNC_RESET] = {3},
47eea2926bSSibi Sankar [PDC_AOP_SYNC_RESET] = {4},
48eea2926bSSibi Sankar [PDC_DEBUG_SYNC_RESET] = {5},
49eea2926bSSibi Sankar [PDC_GPU_SYNC_RESET] = {6},
50eea2926bSSibi Sankar [PDC_DISPLAY_SYNC_RESET] = {7},
51eea2926bSSibi Sankar [PDC_COMPUTE_SYNC_RESET] = {8},
52eea2926bSSibi Sankar [PDC_MODEM_SYNC_RESET] = {9},
53eea2926bSSibi Sankar };
54eea2926bSSibi Sankar
5508218a08SSibi Sankar static const struct qcom_pdc_reset_desc sdm845_pdc_reset_desc = {
5608218a08SSibi Sankar .resets = sdm845_pdc_resets,
5708218a08SSibi Sankar .num_resets = ARRAY_SIZE(sdm845_pdc_resets),
5808218a08SSibi Sankar .offset = RPMH_SDM845_PDC_SYNC_RESET,
5908218a08SSibi Sankar };
6008218a08SSibi Sankar
6108218a08SSibi Sankar static const struct qcom_pdc_reset_map sc7280_pdc_resets[] = {
6208218a08SSibi Sankar [PDC_APPS_SYNC_RESET] = {0},
6308218a08SSibi Sankar [PDC_SP_SYNC_RESET] = {1},
6408218a08SSibi Sankar [PDC_AUDIO_SYNC_RESET] = {2},
6508218a08SSibi Sankar [PDC_SENSORS_SYNC_RESET] = {3},
6608218a08SSibi Sankar [PDC_AOP_SYNC_RESET] = {4},
6708218a08SSibi Sankar [PDC_DEBUG_SYNC_RESET] = {5},
6808218a08SSibi Sankar [PDC_GPU_SYNC_RESET] = {6},
6908218a08SSibi Sankar [PDC_DISPLAY_SYNC_RESET] = {7},
7008218a08SSibi Sankar [PDC_COMPUTE_SYNC_RESET] = {8},
7108218a08SSibi Sankar [PDC_MODEM_SYNC_RESET] = {9},
7208218a08SSibi Sankar [PDC_WLAN_RF_SYNC_RESET] = {10},
7308218a08SSibi Sankar [PDC_WPSS_SYNC_RESET] = {11},
7408218a08SSibi Sankar };
7508218a08SSibi Sankar
7608218a08SSibi Sankar static const struct qcom_pdc_reset_desc sc7280_pdc_reset_desc = {
7708218a08SSibi Sankar .resets = sc7280_pdc_resets,
7808218a08SSibi Sankar .num_resets = ARRAY_SIZE(sc7280_pdc_resets),
7908218a08SSibi Sankar .offset = RPMH_SC7280_PDC_SYNC_RESET,
8008218a08SSibi Sankar };
8108218a08SSibi Sankar
to_qcom_pdc_reset_data(struct reset_controller_dev * rcdev)82eea2926bSSibi Sankar static inline struct qcom_pdc_reset_data *to_qcom_pdc_reset_data(
83eea2926bSSibi Sankar struct reset_controller_dev *rcdev)
84eea2926bSSibi Sankar {
85eea2926bSSibi Sankar return container_of(rcdev, struct qcom_pdc_reset_data, rcdev);
86eea2926bSSibi Sankar }
87eea2926bSSibi Sankar
qcom_pdc_control_assert(struct reset_controller_dev * rcdev,unsigned long idx)88eea2926bSSibi Sankar static int qcom_pdc_control_assert(struct reset_controller_dev *rcdev,
89eea2926bSSibi Sankar unsigned long idx)
90eea2926bSSibi Sankar {
91eea2926bSSibi Sankar struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
9208218a08SSibi Sankar u32 mask = BIT(data->desc->resets[idx].bit);
93eea2926bSSibi Sankar
9408218a08SSibi Sankar return regmap_update_bits(data->regmap, data->desc->offset, mask, mask);
95eea2926bSSibi Sankar }
96eea2926bSSibi Sankar
qcom_pdc_control_deassert(struct reset_controller_dev * rcdev,unsigned long idx)97eea2926bSSibi Sankar static int qcom_pdc_control_deassert(struct reset_controller_dev *rcdev,
98eea2926bSSibi Sankar unsigned long idx)
99eea2926bSSibi Sankar {
100eea2926bSSibi Sankar struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
10108218a08SSibi Sankar u32 mask = BIT(data->desc->resets[idx].bit);
102eea2926bSSibi Sankar
10308218a08SSibi Sankar return regmap_update_bits(data->regmap, data->desc->offset, mask, 0);
104eea2926bSSibi Sankar }
105eea2926bSSibi Sankar
106eea2926bSSibi Sankar static const struct reset_control_ops qcom_pdc_reset_ops = {
107eea2926bSSibi Sankar .assert = qcom_pdc_control_assert,
108eea2926bSSibi Sankar .deassert = qcom_pdc_control_deassert,
109eea2926bSSibi Sankar };
110eea2926bSSibi Sankar
qcom_pdc_reset_probe(struct platform_device * pdev)111eea2926bSSibi Sankar static int qcom_pdc_reset_probe(struct platform_device *pdev)
112eea2926bSSibi Sankar {
11308218a08SSibi Sankar const struct qcom_pdc_reset_desc *desc;
114eea2926bSSibi Sankar struct qcom_pdc_reset_data *data;
115eea2926bSSibi Sankar struct device *dev = &pdev->dev;
116eea2926bSSibi Sankar void __iomem *base;
117eea2926bSSibi Sankar struct resource *res;
118eea2926bSSibi Sankar
11908218a08SSibi Sankar desc = device_get_match_data(&pdev->dev);
12008218a08SSibi Sankar if (!desc)
12108218a08SSibi Sankar return -EINVAL;
12208218a08SSibi Sankar
123eea2926bSSibi Sankar data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
124eea2926bSSibi Sankar if (!data)
125eea2926bSSibi Sankar return -ENOMEM;
126eea2926bSSibi Sankar
12708218a08SSibi Sankar data->desc = desc;
128eea2926bSSibi Sankar res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
129eea2926bSSibi Sankar base = devm_ioremap_resource(dev, res);
130eea2926bSSibi Sankar if (IS_ERR(base))
131eea2926bSSibi Sankar return PTR_ERR(base);
132eea2926bSSibi Sankar
13308218a08SSibi Sankar data->regmap = devm_regmap_init_mmio(dev, base, &pdc_regmap_config);
134eea2926bSSibi Sankar if (IS_ERR(data->regmap)) {
135eea2926bSSibi Sankar dev_err(dev, "Unable to initialize regmap\n");
136eea2926bSSibi Sankar return PTR_ERR(data->regmap);
137eea2926bSSibi Sankar }
138eea2926bSSibi Sankar
139eea2926bSSibi Sankar data->rcdev.owner = THIS_MODULE;
140eea2926bSSibi Sankar data->rcdev.ops = &qcom_pdc_reset_ops;
14108218a08SSibi Sankar data->rcdev.nr_resets = desc->num_resets;
142eea2926bSSibi Sankar data->rcdev.of_node = dev->of_node;
143eea2926bSSibi Sankar
144eea2926bSSibi Sankar return devm_reset_controller_register(dev, &data->rcdev);
145eea2926bSSibi Sankar }
146eea2926bSSibi Sankar
147eea2926bSSibi Sankar static const struct of_device_id qcom_pdc_reset_of_match[] = {
14808218a08SSibi Sankar { .compatible = "qcom,sc7280-pdc-global", .data = &sc7280_pdc_reset_desc },
14908218a08SSibi Sankar { .compatible = "qcom,sdm845-pdc-global", .data = &sdm845_pdc_reset_desc },
150eea2926bSSibi Sankar {}
151eea2926bSSibi Sankar };
152eea2926bSSibi Sankar MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match);
153eea2926bSSibi Sankar
154eea2926bSSibi Sankar static struct platform_driver qcom_pdc_reset_driver = {
155eea2926bSSibi Sankar .probe = qcom_pdc_reset_probe,
156eea2926bSSibi Sankar .driver = {
157eea2926bSSibi Sankar .name = "qcom_pdc_reset",
158eea2926bSSibi Sankar .of_match_table = qcom_pdc_reset_of_match,
159eea2926bSSibi Sankar },
160eea2926bSSibi Sankar };
161eea2926bSSibi Sankar module_platform_driver(qcom_pdc_reset_driver);
162eea2926bSSibi Sankar
163eea2926bSSibi Sankar MODULE_DESCRIPTION("Qualcomm PDC Reset Driver");
164eea2926bSSibi Sankar MODULE_LICENSE("GPL v2");
165