1 /* 2 * Copyright (C) 2016 NVIDIA CORPORATION, All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 #include <linux/module.h> 17 #include <linux/clk.h> 18 #include <linux/of_device.h> 19 #include <linux/of_irq.h> 20 #include <linux/irqchip/arm-gic.h> 21 #include <linux/platform_device.h> 22 #include <linux/pm_clock.h> 23 #include <linux/pm_runtime.h> 24 #include <linux/slab.h> 25 26 struct gic_clk_data { 27 unsigned int num_clocks; 28 const char *const *clocks; 29 }; 30 31 static int gic_runtime_resume(struct device *dev) 32 { 33 struct gic_chip_data *gic = dev_get_drvdata(dev); 34 int ret; 35 36 ret = pm_clk_resume(dev); 37 if (ret) 38 return ret; 39 40 /* 41 * On the very first resume, the pointer to the driver data 42 * will be NULL and this is intentional, because we do not 43 * want to restore the GIC on the very first resume. So if 44 * the pointer is not valid just return. 45 */ 46 if (!gic) 47 return 0; 48 49 gic_dist_restore(gic); 50 gic_cpu_restore(gic); 51 52 return 0; 53 } 54 55 static int gic_runtime_suspend(struct device *dev) 56 { 57 struct gic_chip_data *gic = dev_get_drvdata(dev); 58 59 gic_dist_save(gic); 60 gic_cpu_save(gic); 61 62 return pm_clk_suspend(dev); 63 } 64 65 static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data) 66 { 67 unsigned int i; 68 int ret; 69 70 if (!dev || !data) 71 return -EINVAL; 72 73 ret = pm_clk_create(dev); 74 if (ret) 75 return ret; 76 77 for (i = 0; i < data->num_clocks; i++) { 78 ret = of_pm_clk_add_clk(dev, data->clocks[i]); 79 if (ret) { 80 dev_err(dev, "failed to add clock %s\n", 81 data->clocks[i]); 82 pm_clk_destroy(dev); 83 return ret; 84 } 85 } 86 87 return 0; 88 } 89 90 static int gic_probe(struct platform_device *pdev) 91 { 92 struct device *dev = &pdev->dev; 93 const struct gic_clk_data *data; 94 struct gic_chip_data *gic; 95 int ret, irq; 96 97 data = of_device_get_match_data(&pdev->dev); 98 if (!data) { 99 dev_err(&pdev->dev, "no device match found\n"); 100 return -ENODEV; 101 } 102 103 irq = irq_of_parse_and_map(dev->of_node, 0); 104 if (!irq) { 105 dev_err(dev, "no parent interrupt found!\n"); 106 return -EINVAL; 107 } 108 109 ret = gic_get_clocks(dev, data); 110 if (ret) 111 goto irq_dispose; 112 113 pm_runtime_enable(dev); 114 115 ret = pm_runtime_get_sync(dev); 116 if (ret < 0) 117 goto rpm_disable; 118 119 ret = gic_of_init_child(dev, &gic, irq); 120 if (ret) 121 goto rpm_put; 122 123 platform_set_drvdata(pdev, gic); 124 125 pm_runtime_put(dev); 126 127 dev_info(dev, "GIC IRQ controller registered\n"); 128 129 return 0; 130 131 rpm_put: 132 pm_runtime_put_sync(dev); 133 rpm_disable: 134 pm_runtime_disable(dev); 135 pm_clk_destroy(dev); 136 irq_dispose: 137 irq_dispose_mapping(irq); 138 139 return ret; 140 } 141 142 static const struct dev_pm_ops gic_pm_ops = { 143 SET_RUNTIME_PM_OPS(gic_runtime_suspend, 144 gic_runtime_resume, NULL) 145 }; 146 147 static const char * const gic400_clocks[] = { 148 "clk", 149 }; 150 151 static const struct gic_clk_data gic400_data = { 152 .num_clocks = ARRAY_SIZE(gic400_clocks), 153 .clocks = gic400_clocks, 154 }; 155 156 static const struct of_device_id gic_match[] = { 157 { .compatible = "nvidia,tegra210-agic", .data = &gic400_data }, 158 {}, 159 }; 160 MODULE_DEVICE_TABLE(of, gic_match); 161 162 static struct platform_driver gic_driver = { 163 .probe = gic_probe, 164 .driver = { 165 .name = "gic", 166 .of_match_table = gic_match, 167 .pm = &gic_pm_ops, 168 } 169 }; 170 171 builtin_platform_driver(gic_driver); 172