1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/interconnect-provider.h> 4 #include <linux/device.h> 5 #include <linux/export.h> 6 7 /** 8 * of_icc_bulk_get() - get interconnect paths 9 * @dev: the device requesting the path 10 * @num_paths: the number of icc_bulk_data 11 * @paths: the table with the paths we want to get 12 * 13 * Returns 0 on success or negative errno otherwise. 14 */ 15 int __must_check of_icc_bulk_get(struct device *dev, int num_paths, 16 struct icc_bulk_data *paths) 17 { 18 int ret, i; 19 20 for (i = 0; i < num_paths; i++) { 21 paths[i].path = of_icc_get(dev, paths[i].name); 22 if (IS_ERR(paths[i].path)) { 23 ret = PTR_ERR(paths[i].path); 24 if (ret != -EPROBE_DEFER) 25 dev_err(dev, "of_icc_get() failed on path %s (%d)\n", 26 paths[i].name, ret); 27 paths[i].path = NULL; 28 goto err; 29 } 30 } 31 32 return 0; 33 34 err: 35 icc_bulk_put(i, paths); 36 37 return ret; 38 } 39 EXPORT_SYMBOL_GPL(of_icc_bulk_get); 40 41 /** 42 * icc_bulk_put() - put a list of interconnect paths 43 * @num_paths: the number of icc_bulk_data 44 * @paths: the icc_bulk_data table with the paths being put 45 */ 46 void icc_bulk_put(int num_paths, struct icc_bulk_data *paths) 47 { 48 while (--num_paths >= 0) { 49 icc_put(paths[num_paths].path); 50 paths[num_paths].path = NULL; 51 } 52 } 53 EXPORT_SYMBOL_GPL(icc_bulk_put); 54 55 /** 56 * icc_bulk_set_bw() - set bandwidth to a set of paths 57 * @num_paths: the number of icc_bulk_data 58 * @paths: the icc_bulk_data table containing the paths and bandwidth 59 * 60 * Returns 0 on success or negative errno otherwise. 61 */ 62 int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths) 63 { 64 int ret = 0; 65 int i; 66 67 for (i = 0; i < num_paths; i++) { 68 ret = icc_set_bw(paths[i].path, paths[i].avg_bw, paths[i].peak_bw); 69 if (ret) { 70 pr_err("icc_set_bw() failed on path %s (%d)\n", paths[i].name, ret); 71 return ret; 72 } 73 } 74 75 return ret; 76 } 77 EXPORT_SYMBOL_GPL(icc_bulk_set_bw); 78 79 /** 80 * icc_bulk_enable() - enable a previously disabled set of paths 81 * @num_paths: the number of icc_bulk_data 82 * @paths: the icc_bulk_data table containing the paths and bandwidth 83 * 84 * Returns 0 on success or negative errno otherwise. 85 */ 86 int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths) 87 { 88 int ret, i; 89 90 for (i = 0; i < num_paths; i++) { 91 ret = icc_enable(paths[i].path); 92 if (ret) { 93 pr_err("icc_enable() failed on path %s (%d)\n", paths[i].name, ret); 94 goto err; 95 } 96 } 97 98 return 0; 99 100 err: 101 icc_bulk_disable(i, paths); 102 103 return ret; 104 } 105 EXPORT_SYMBOL_GPL(icc_bulk_enable); 106 107 /** 108 * icc_bulk_disable() - disable a set of interconnect paths 109 * @num_paths: the number of icc_bulk_data 110 * @paths: the icc_bulk_data table containing the paths and bandwidth 111 */ 112 void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths) 113 { 114 while (--num_paths >= 0) 115 icc_disable(paths[num_paths].path); 116 } 117 EXPORT_SYMBOL_GPL(icc_bulk_disable); 118 119 struct icc_bulk_devres { 120 struct icc_bulk_data *paths; 121 int num_paths; 122 }; 123 124 static void devm_icc_bulk_release(struct device *dev, void *res) 125 { 126 struct icc_bulk_devres *devres = res; 127 128 icc_bulk_put(devres->num_paths, devres->paths); 129 } 130 131 /** 132 * devm_of_icc_bulk_get() - resource managed of_icc_bulk_get 133 * @dev: the device requesting the path 134 * @num_paths: the number of icc_bulk_data 135 * @paths: the table with the paths we want to get 136 * 137 * Returns 0 on success or negative errno otherwise. 138 */ 139 int devm_of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths) 140 { 141 struct icc_bulk_devres *devres; 142 int ret; 143 144 devres = devres_alloc(devm_icc_bulk_release, sizeof(*devres), GFP_KERNEL); 145 if (!devres) 146 return -ENOMEM; 147 148 ret = of_icc_bulk_get(dev, num_paths, paths); 149 if (!ret) { 150 devres->paths = paths; 151 devres->num_paths = num_paths; 152 devres_add(dev, devres); 153 } else { 154 devres_free(devres); 155 } 156 157 return ret; 158 } 159 EXPORT_SYMBOL_GPL(devm_of_icc_bulk_get); 160