Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: dwc3: exynos: Rework clock handling and prepare for new variants

Add per-variant list of clocks and manage them all together in
the single array. This is a preparation for adding new variants
of Exynos SoCs. No functional changes for existing Exynos SoCs.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>

authored by

Marek Szyprowski and committed by
Felipe Balbi
9f216836 1e041b6f

+82 -50
+82 -50
drivers/usb/dwc3/dwc3-exynos.c
··· 17 17 #include <linux/of_platform.h> 18 18 #include <linux/regulator/consumer.h> 19 19 20 + #define DWC3_EXYNOS_MAX_CLOCKS 4 21 + 22 + struct dwc3_exynos_driverdata { 23 + const char *clk_names[DWC3_EXYNOS_MAX_CLOCKS]; 24 + int num_clks; 25 + int suspend_clk_idx; 26 + }; 27 + 20 28 struct dwc3_exynos { 21 29 struct device *dev; 22 30 23 - struct clk *clk; 24 - struct clk *susp_clk; 25 - struct clk *axius_clk; 31 + const char **clk_names; 32 + struct clk *clks[DWC3_EXYNOS_MAX_CLOCKS]; 33 + int num_clks; 34 + int suspend_clk_idx; 26 35 27 36 struct regulator *vdd33; 28 37 struct regulator *vdd10; ··· 51 42 struct dwc3_exynos *exynos; 52 43 struct device *dev = &pdev->dev; 53 44 struct device_node *node = dev->of_node; 54 - 55 - int ret; 45 + const struct dwc3_exynos_driverdata *driver_data; 46 + int i, ret; 56 47 57 48 exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); 58 49 if (!exynos) 59 50 return -ENOMEM; 60 51 52 + driver_data = of_device_get_match_data(dev); 53 + exynos->dev = dev; 54 + exynos->num_clks = driver_data->num_clks; 55 + exynos->clk_names = (const char **)driver_data->clk_names; 56 + exynos->suspend_clk_idx = driver_data->suspend_clk_idx; 57 + 61 58 platform_set_drvdata(pdev, exynos); 62 59 63 - exynos->dev = dev; 64 - 65 - exynos->clk = devm_clk_get(dev, "usbdrd30"); 66 - if (IS_ERR(exynos->clk)) { 67 - dev_err(dev, "couldn't get clock\n"); 68 - return -EINVAL; 69 - } 70 - ret = clk_prepare_enable(exynos->clk); 71 - if (ret) 72 - return ret; 73 - 74 - exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); 75 - if (IS_ERR(exynos->susp_clk)) 76 - exynos->susp_clk = NULL; 77 - ret = clk_prepare_enable(exynos->susp_clk); 78 - if (ret) 79 - goto susp_clk_err; 80 - 81 - if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) { 82 - exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk"); 83 - if (IS_ERR(exynos->axius_clk)) { 84 - dev_err(dev, "no AXI UpScaler clk specified\n"); 85 - ret = -ENODEV; 86 - goto axius_clk_err; 60 + for (i = 0; i < exynos->num_clks; i++) { 61 + exynos->clks[i] = devm_clk_get(dev, exynos->clk_names[i]); 62 + if (IS_ERR(exynos->clks[i])) { 63 + dev_err(dev, "failed to get clock: %s\n", 64 + exynos->clk_names[i]); 65 + return PTR_ERR(exynos->clks[i]); 87 66 } 88 - ret = clk_prepare_enable(exynos->axius_clk); 89 - if (ret) 90 - goto axius_clk_err; 91 - } else { 92 - exynos->axius_clk = NULL; 93 67 } 68 + 69 + for (i = 0; i < exynos->num_clks; i++) { 70 + ret = clk_prepare_enable(exynos->clks[i]); 71 + if (ret) { 72 + while (--i > 0) 73 + clk_disable_unprepare(exynos->clks[i]); 74 + return ret; 75 + } 76 + } 77 + 78 + if (exynos->suspend_clk_idx >= 0) 79 + clk_prepare_enable(exynos->clks[exynos->suspend_clk_idx]); 94 80 95 81 exynos->vdd33 = devm_regulator_get(dev, "vdd33"); 96 82 if (IS_ERR(exynos->vdd33)) { ··· 128 124 vdd10_err: 129 125 regulator_disable(exynos->vdd33); 130 126 vdd33_err: 131 - clk_disable_unprepare(exynos->axius_clk); 132 - axius_clk_err: 133 - clk_disable_unprepare(exynos->susp_clk); 134 - susp_clk_err: 135 - clk_disable_unprepare(exynos->clk); 127 + for (i = exynos->num_clks - 1; i >= 0; i--) 128 + clk_disable_unprepare(exynos->clks[i]); 129 + 130 + if (exynos->suspend_clk_idx >= 0) 131 + clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]); 132 + 136 133 return ret; 137 134 } 138 135 139 136 static int dwc3_exynos_remove(struct platform_device *pdev) 140 137 { 141 138 struct dwc3_exynos *exynos = platform_get_drvdata(pdev); 139 + int i; 142 140 143 141 device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); 144 142 145 - clk_disable_unprepare(exynos->axius_clk); 146 - clk_disable_unprepare(exynos->susp_clk); 147 - clk_disable_unprepare(exynos->clk); 143 + for (i = exynos->num_clks - 1; i >= 0; i--) 144 + clk_disable_unprepare(exynos->clks[i]); 145 + 146 + if (exynos->suspend_clk_idx >= 0) 147 + clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]); 148 148 149 149 regulator_disable(exynos->vdd33); 150 150 regulator_disable(exynos->vdd10); ··· 156 148 return 0; 157 149 } 158 150 151 + static const struct dwc3_exynos_driverdata exynos5250_drvdata = { 152 + .clk_names = { "usbdrd30" }, 153 + .num_clks = 1, 154 + .suspend_clk_idx = -1, 155 + }; 156 + 157 + static const struct dwc3_exynos_driverdata exynos7_drvdata = { 158 + .clk_names = { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" }, 159 + .num_clks = 3, 160 + .suspend_clk_idx = 1, 161 + }; 162 + 159 163 static const struct of_device_id exynos_dwc3_match[] = { 160 - { .compatible = "samsung,exynos5250-dwusb3" }, 161 - { .compatible = "samsung,exynos7-dwusb3" }, 162 - {}, 164 + { 165 + .compatible = "samsung,exynos5250-dwusb3", 166 + .data = &exynos5250_drvdata, 167 + }, { 168 + .compatible = "samsung,exynos7-dwusb3", 169 + .data = &exynos7_drvdata, 170 + }, { 171 + } 163 172 }; 164 173 MODULE_DEVICE_TABLE(of, exynos_dwc3_match); 165 174 ··· 184 159 static int dwc3_exynos_suspend(struct device *dev) 185 160 { 186 161 struct dwc3_exynos *exynos = dev_get_drvdata(dev); 162 + int i; 187 163 188 - clk_disable(exynos->axius_clk); 189 - clk_disable(exynos->clk); 164 + for (i = exynos->num_clks - 1; i >= 0; i--) 165 + clk_disable_unprepare(exynos->clks[i]); 190 166 191 167 regulator_disable(exynos->vdd33); 192 168 regulator_disable(exynos->vdd10); ··· 198 172 static int dwc3_exynos_resume(struct device *dev) 199 173 { 200 174 struct dwc3_exynos *exynos = dev_get_drvdata(dev); 201 - int ret; 175 + int i, ret; 202 176 203 177 ret = regulator_enable(exynos->vdd33); 204 178 if (ret) { ··· 211 185 return ret; 212 186 } 213 187 214 - clk_enable(exynos->clk); 215 - clk_enable(exynos->axius_clk); 188 + for (i = 0; i < exynos->num_clks; i++) { 189 + ret = clk_prepare_enable(exynos->clks[i]); 190 + if (ret) { 191 + while (--i > 0) 192 + clk_disable_unprepare(exynos->clks[i]); 193 + return ret; 194 + } 195 + } 216 196 217 197 return 0; 218 198 }