1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2016 NVIDIA CORPORATION, All Rights Reserved. 4 */ 5#include <linux/module.h> 6#include <linux/clk.h> 7#include <linux/of_device.h> 8#include <linux/of_irq.h> 9#include <linux/irqchip/arm-gic.h> 10#include <linux/platform_device.h> 11#include <linux/pm_runtime.h> 12#include <linux/slab.h> 13 14struct gic_clk_data { 15 unsigned int num_clocks; 16 const char *const *clocks; 17}; 18 19struct gic_chip_pm { 20 struct gic_chip_data *chip_data; 21 const struct gic_clk_data *clk_data; 22 struct clk_bulk_data *clks; 23}; 24 25static int gic_runtime_resume(struct device *dev) 26{ 27 struct gic_chip_pm *chip_pm = dev_get_drvdata(dev); 28 struct gic_chip_data *gic = chip_pm->chip_data; 29 const struct gic_clk_data *data = chip_pm->clk_data; 30 int ret; 31 32 ret = clk_bulk_prepare_enable(data->num_clocks, chip_pm->clks); 33 if (ret) { 34 dev_err(dev, "clk_enable failed: %d\n", ret); 35 return ret; 36 } 37 38 /* 39 * On the very first resume, the pointer to chip_pm->chip_data 40 * will be NULL and this is intentional, because we do not 41 * want to restore the GIC on the very first resume. So if 42 * the pointer is not valid just return. 43 */ 44 if (!gic) 45 return 0; 46 47 gic_dist_restore(gic); 48 gic_cpu_restore(gic); 49 50 return 0; 51} 52 53static int gic_runtime_suspend(struct device *dev) 54{ 55 struct gic_chip_pm *chip_pm = dev_get_drvdata(dev); 56 struct gic_chip_data *gic = chip_pm->chip_data; 57 const struct gic_clk_data *data = chip_pm->clk_data; 58 59 gic_dist_save(gic); 60 gic_cpu_save(gic); 61 62 clk_bulk_disable_unprepare(data->num_clocks, chip_pm->clks); 63 64 return 0; 65} 66 67static int gic_probe(struct platform_device *pdev) 68{ 69 struct device *dev = &pdev->dev; 70 const struct gic_clk_data *data; 71 struct gic_chip_pm *chip_pm; 72 int ret, irq, i; 73 74 data = of_device_get_match_data(&pdev->dev); 75 if (!data) { 76 dev_err(&pdev->dev, "no device match found\n"); 77 return -ENODEV; 78 } 79 80 chip_pm = devm_kzalloc(dev, sizeof(*chip_pm), GFP_KERNEL); 81 if (!chip_pm) 82 return -ENOMEM; 83 84 irq = irq_of_parse_and_map(dev->of_node, 0); 85 if (!irq) { 86 dev_err(dev, "no parent interrupt found!\n"); 87 return -EINVAL; 88 } 89 90 chip_pm->clks = devm_kcalloc(dev, data->num_clocks, 91 sizeof(*chip_pm->clks), GFP_KERNEL); 92 if (!chip_pm->clks) 93 return -ENOMEM; 94 95 for (i = 0; i < data->num_clocks; i++) 96 chip_pm->clks[i].id = data->clocks[i]; 97 98 ret = devm_clk_bulk_get(dev, data->num_clocks, chip_pm->clks); 99 if (ret) 100 goto irq_dispose; 101 102 chip_pm->clk_data = data; 103 dev_set_drvdata(dev, chip_pm); 104 105 pm_runtime_enable(dev); 106 107 ret = pm_runtime_resume_and_get(dev); 108 if (ret < 0) 109 goto rpm_disable; 110 111 ret = gic_of_init_child(dev, &chip_pm->chip_data, irq); 112 if (ret) 113 goto rpm_put; 114 115 pm_runtime_put(dev); 116 117 dev_info(dev, "GIC IRQ controller registered\n"); 118 119 return 0; 120 121rpm_put: 122 pm_runtime_put_sync(dev); 123rpm_disable: 124 pm_runtime_disable(dev); 125irq_dispose: 126 irq_dispose_mapping(irq); 127 128 return ret; 129} 130 131static const struct dev_pm_ops gic_pm_ops = { 132 SET_RUNTIME_PM_OPS(gic_runtime_suspend, 133 gic_runtime_resume, NULL) 134 SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 135 pm_runtime_force_resume) 136}; 137 138static const char * const gic400_clocks[] = { 139 "clk", 140}; 141 142static const struct gic_clk_data gic400_data = { 143 .num_clocks = ARRAY_SIZE(gic400_clocks), 144 .clocks = gic400_clocks, 145}; 146 147static const struct of_device_id gic_match[] = { 148 { .compatible = "nvidia,tegra210-agic", .data = &gic400_data }, 149 {}, 150}; 151MODULE_DEVICE_TABLE(of, gic_match); 152 153static struct platform_driver gic_driver = { 154 .probe = gic_probe, 155 .driver = { 156 .name = "gic", 157 .of_match_table = gic_match, 158 .pm = &gic_pm_ops, 159 } 160}; 161 162builtin_platform_driver(gic_driver); 163