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 struct clk *clk; 68 unsigned int i; 69 int ret; 70 71 if (!dev || !data) 72 return -EINVAL; 73 74 ret = pm_clk_create(dev); 75 if (ret) 76 return ret; 77 78 for (i = 0; i < data->num_clocks; i++) { 79 clk = of_clk_get_by_name(dev->of_node, data->clocks[i]); 80 if (IS_ERR(clk)) { 81 dev_err(dev, "failed to get clock %s\n", 82 data->clocks[i]); 83 ret = PTR_ERR(clk); 84 goto error; 85 } 86 87 ret = pm_clk_add_clk(dev, clk); 88 if (ret) { 89 dev_err(dev, "failed to add clock at index %d\n", i); 90 clk_put(clk); 91 goto error; 92 } 93 } 94 95 return 0; 96 97 error: 98 pm_clk_destroy(dev); 99 100 return ret; 101 } 102 103 static int gic_probe(struct platform_device *pdev) 104 { 105 struct device *dev = &pdev->dev; 106 const struct gic_clk_data *data; 107 struct gic_chip_data *gic; 108 int ret, irq; 109 110 data = of_device_get_match_data(&pdev->dev); 111 if (!data) { 112 dev_err(&pdev->dev, "no device match found\n"); 113 return -ENODEV; 114 } 115 116 irq = irq_of_parse_and_map(dev->of_node, 0); 117 if (!irq) { 118 dev_err(dev, "no parent interrupt found!\n"); 119 return -EINVAL; 120 } 121 122 ret = gic_get_clocks(dev, data); 123 if (ret) 124 goto irq_dispose; 125 126 pm_runtime_enable(dev); 127 128 ret = pm_runtime_get_sync(dev); 129 if (ret < 0) 130 goto rpm_disable; 131 132 ret = gic_of_init_child(dev, &gic, irq); 133 if (ret) 134 goto rpm_put; 135 136 platform_set_drvdata(pdev, gic); 137 138 pm_runtime_put(dev); 139 140 dev_info(dev, "GIC IRQ controller registered\n"); 141 142 return 0; 143 144 rpm_put: 145 pm_runtime_put_sync(dev); 146 rpm_disable: 147 pm_runtime_disable(dev); 148 pm_clk_destroy(dev); 149 irq_dispose: 150 irq_dispose_mapping(irq); 151 152 return ret; 153 } 154 155 static const struct dev_pm_ops gic_pm_ops = { 156 SET_RUNTIME_PM_OPS(gic_runtime_suspend, 157 gic_runtime_resume, NULL) 158 }; 159 160 static const char * const gic400_clocks[] = { 161 "clk", 162 }; 163 164 static const struct gic_clk_data gic400_data = { 165 .num_clocks = ARRAY_SIZE(gic400_clocks), 166 .clocks = gic400_clocks, 167 }; 168 169 static const struct of_device_id gic_match[] = { 170 { .compatible = "nvidia,tegra210-agic", .data = &gic400_data }, 171 {}, 172 }; 173 MODULE_DEVICE_TABLE(of, gic_match); 174 175 static struct platform_driver gic_driver = { 176 .probe = gic_probe, 177 .driver = { 178 .name = "gic", 179 .of_match_table = gic_match, 180 .pm = &gic_pm_ops, 181 } 182 }; 183 184 builtin_platform_driver(gic_driver); 185