linux/drivers/reset/reset-qcom-aoss.c
<<
>>
Prefs
   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");
 135