| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | | -/** |
|---|
| 2 | +/* |
|---|
| 3 | 3 | * dwc3-of-simple.c - OF glue layer for simple integrations |
|---|
| 4 | 4 | * |
|---|
| 5 | | - * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com |
|---|
| 5 | + * Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com |
|---|
| 6 | 6 | * |
|---|
| 7 | 7 | * Author: Felipe Balbi <balbi@ti.com> |
|---|
| 8 | 8 | * |
|---|
| .. | .. |
|---|
| 24 | 24 | |
|---|
| 25 | 25 | struct dwc3_of_simple { |
|---|
| 26 | 26 | struct device *dev; |
|---|
| 27 | | - struct clk **clks; |
|---|
| 27 | + struct clk_bulk_data *clks; |
|---|
| 28 | 28 | int num_clocks; |
|---|
| 29 | 29 | struct reset_control *resets; |
|---|
| 30 | | - bool pulse_resets; |
|---|
| 31 | 30 | bool need_reset; |
|---|
| 32 | 31 | }; |
|---|
| 33 | | - |
|---|
| 34 | | -static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count) |
|---|
| 35 | | -{ |
|---|
| 36 | | - struct device *dev = simple->dev; |
|---|
| 37 | | - struct device_node *np = dev->of_node; |
|---|
| 38 | | - int i; |
|---|
| 39 | | - |
|---|
| 40 | | - simple->num_clocks = count; |
|---|
| 41 | | - |
|---|
| 42 | | - if (!count) |
|---|
| 43 | | - return 0; |
|---|
| 44 | | - |
|---|
| 45 | | - simple->clks = devm_kcalloc(dev, simple->num_clocks, |
|---|
| 46 | | - sizeof(struct clk *), GFP_KERNEL); |
|---|
| 47 | | - if (!simple->clks) |
|---|
| 48 | | - return -ENOMEM; |
|---|
| 49 | | - |
|---|
| 50 | | - for (i = 0; i < simple->num_clocks; i++) { |
|---|
| 51 | | - struct clk *clk; |
|---|
| 52 | | - int ret; |
|---|
| 53 | | - |
|---|
| 54 | | - clk = of_clk_get(np, i); |
|---|
| 55 | | - if (IS_ERR(clk)) { |
|---|
| 56 | | - while (--i >= 0) { |
|---|
| 57 | | - clk_disable_unprepare(simple->clks[i]); |
|---|
| 58 | | - clk_put(simple->clks[i]); |
|---|
| 59 | | - } |
|---|
| 60 | | - return PTR_ERR(clk); |
|---|
| 61 | | - } |
|---|
| 62 | | - |
|---|
| 63 | | - ret = clk_prepare_enable(clk); |
|---|
| 64 | | - if (ret < 0) { |
|---|
| 65 | | - while (--i >= 0) { |
|---|
| 66 | | - clk_disable_unprepare(simple->clks[i]); |
|---|
| 67 | | - clk_put(simple->clks[i]); |
|---|
| 68 | | - } |
|---|
| 69 | | - clk_put(clk); |
|---|
| 70 | | - |
|---|
| 71 | | - return ret; |
|---|
| 72 | | - } |
|---|
| 73 | | - |
|---|
| 74 | | - simple->clks[i] = clk; |
|---|
| 75 | | - } |
|---|
| 76 | | - |
|---|
| 77 | | - return 0; |
|---|
| 78 | | -} |
|---|
| 79 | 32 | |
|---|
| 80 | 33 | static int dwc3_of_simple_probe(struct platform_device *pdev) |
|---|
| 81 | 34 | { |
|---|
| .. | .. |
|---|
| 84 | 37 | struct device_node *np = dev->of_node; |
|---|
| 85 | 38 | |
|---|
| 86 | 39 | int ret; |
|---|
| 87 | | - int i; |
|---|
| 88 | | - bool shared_resets = false; |
|---|
| 89 | 40 | |
|---|
| 90 | 41 | simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); |
|---|
| 91 | 42 | if (!simple) |
|---|
| .. | .. |
|---|
| 101 | 52 | if (of_device_is_compatible(np, "rockchip,rk3399-dwc3")) |
|---|
| 102 | 53 | simple->need_reset = true; |
|---|
| 103 | 54 | |
|---|
| 104 | | - if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") || |
|---|
| 105 | | - of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) { |
|---|
| 106 | | - shared_resets = true; |
|---|
| 107 | | - simple->pulse_resets = true; |
|---|
| 108 | | - } |
|---|
| 109 | | - |
|---|
| 110 | | - simple->resets = of_reset_control_array_get(np, shared_resets, true); |
|---|
| 55 | + simple->resets = of_reset_control_array_get(np, false, true, |
|---|
| 56 | + true); |
|---|
| 111 | 57 | if (IS_ERR(simple->resets)) { |
|---|
| 112 | 58 | ret = PTR_ERR(simple->resets); |
|---|
| 113 | 59 | dev_err(dev, "failed to get device resets, err=%d\n", ret); |
|---|
| 114 | 60 | return ret; |
|---|
| 115 | 61 | } |
|---|
| 116 | 62 | |
|---|
| 117 | | - if (simple->pulse_resets) { |
|---|
| 118 | | - ret = reset_control_reset(simple->resets); |
|---|
| 119 | | - if (ret) |
|---|
| 120 | | - goto err_resetc_put; |
|---|
| 121 | | - } else { |
|---|
| 122 | | - ret = reset_control_deassert(simple->resets); |
|---|
| 123 | | - if (ret) |
|---|
| 124 | | - goto err_resetc_put; |
|---|
| 125 | | - } |
|---|
| 63 | + ret = reset_control_deassert(simple->resets); |
|---|
| 64 | + if (ret) |
|---|
| 65 | + goto err_resetc_put; |
|---|
| 126 | 66 | |
|---|
| 127 | | - ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np, |
|---|
| 128 | | - "clocks", "#clock-cells")); |
|---|
| 67 | + ret = clk_bulk_get_all(simple->dev, &simple->clks); |
|---|
| 68 | + if (ret < 0) |
|---|
| 69 | + goto err_resetc_assert; |
|---|
| 70 | + |
|---|
| 71 | + simple->num_clocks = ret; |
|---|
| 72 | + ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); |
|---|
| 129 | 73 | if (ret) |
|---|
| 130 | 74 | goto err_resetc_assert; |
|---|
| 131 | 75 | |
|---|
| 132 | 76 | ret = of_platform_populate(np, NULL, NULL, dev); |
|---|
| 133 | | - if (ret) { |
|---|
| 134 | | - for (i = 0; i < simple->num_clocks; i++) { |
|---|
| 135 | | - clk_disable_unprepare(simple->clks[i]); |
|---|
| 136 | | - clk_put(simple->clks[i]); |
|---|
| 137 | | - } |
|---|
| 138 | | - |
|---|
| 139 | | - goto err_resetc_assert; |
|---|
| 140 | | - } |
|---|
| 77 | + if (ret) |
|---|
| 78 | + goto err_clk_put; |
|---|
| 141 | 79 | |
|---|
| 142 | 80 | pm_runtime_set_active(dev); |
|---|
| 143 | 81 | pm_runtime_enable(dev); |
|---|
| .. | .. |
|---|
| 145 | 83 | |
|---|
| 146 | 84 | return 0; |
|---|
| 147 | 85 | |
|---|
| 86 | +err_clk_put: |
|---|
| 87 | + clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); |
|---|
| 88 | + clk_bulk_put_all(simple->num_clocks, simple->clks); |
|---|
| 89 | + |
|---|
| 148 | 90 | err_resetc_assert: |
|---|
| 149 | | - if (!simple->pulse_resets) |
|---|
| 150 | | - reset_control_assert(simple->resets); |
|---|
| 91 | + reset_control_assert(simple->resets); |
|---|
| 151 | 92 | |
|---|
| 152 | 93 | err_resetc_put: |
|---|
| 153 | 94 | reset_control_put(simple->resets); |
|---|
| 154 | 95 | return ret; |
|---|
| 155 | 96 | } |
|---|
| 156 | 97 | |
|---|
| 157 | | -static int dwc3_of_simple_remove(struct platform_device *pdev) |
|---|
| 98 | +static void __dwc3_of_simple_teardown(struct dwc3_of_simple *simple) |
|---|
| 158 | 99 | { |
|---|
| 159 | | - struct dwc3_of_simple *simple = platform_get_drvdata(pdev); |
|---|
| 160 | | - struct device *dev = &pdev->dev; |
|---|
| 161 | | - int i; |
|---|
| 100 | + of_platform_depopulate(simple->dev); |
|---|
| 162 | 101 | |
|---|
| 163 | | - of_platform_depopulate(dev); |
|---|
| 164 | | - |
|---|
| 165 | | - for (i = 0; i < simple->num_clocks; i++) { |
|---|
| 166 | | - clk_disable_unprepare(simple->clks[i]); |
|---|
| 167 | | - clk_put(simple->clks[i]); |
|---|
| 168 | | - } |
|---|
| 102 | + clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); |
|---|
| 103 | + clk_bulk_put_all(simple->num_clocks, simple->clks); |
|---|
| 169 | 104 | simple->num_clocks = 0; |
|---|
| 170 | 105 | |
|---|
| 171 | | - if (!simple->pulse_resets) |
|---|
| 172 | | - reset_control_assert(simple->resets); |
|---|
| 106 | + reset_control_assert(simple->resets); |
|---|
| 173 | 107 | |
|---|
| 174 | 108 | reset_control_put(simple->resets); |
|---|
| 175 | 109 | |
|---|
| 176 | | - pm_runtime_disable(dev); |
|---|
| 177 | | - pm_runtime_put_noidle(dev); |
|---|
| 178 | | - pm_runtime_set_suspended(dev); |
|---|
| 110 | + pm_runtime_disable(simple->dev); |
|---|
| 111 | + pm_runtime_put_noidle(simple->dev); |
|---|
| 112 | + pm_runtime_set_suspended(simple->dev); |
|---|
| 113 | +} |
|---|
| 114 | + |
|---|
| 115 | +static int dwc3_of_simple_remove(struct platform_device *pdev) |
|---|
| 116 | +{ |
|---|
| 117 | + struct dwc3_of_simple *simple = platform_get_drvdata(pdev); |
|---|
| 118 | + |
|---|
| 119 | + __dwc3_of_simple_teardown(simple); |
|---|
| 179 | 120 | |
|---|
| 180 | 121 | return 0; |
|---|
| 122 | +} |
|---|
| 123 | + |
|---|
| 124 | +static void dwc3_of_simple_shutdown(struct platform_device *pdev) |
|---|
| 125 | +{ |
|---|
| 126 | + struct dwc3_of_simple *simple = platform_get_drvdata(pdev); |
|---|
| 127 | + |
|---|
| 128 | + __dwc3_of_simple_teardown(simple); |
|---|
| 181 | 129 | } |
|---|
| 182 | 130 | |
|---|
| 183 | 131 | static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev) |
|---|
| 184 | 132 | { |
|---|
| 185 | 133 | struct dwc3_of_simple *simple = dev_get_drvdata(dev); |
|---|
| 186 | | - int i; |
|---|
| 187 | 134 | |
|---|
| 188 | | - for (i = 0; i < simple->num_clocks; i++) |
|---|
| 189 | | - clk_disable(simple->clks[i]); |
|---|
| 135 | + clk_bulk_disable(simple->num_clocks, simple->clks); |
|---|
| 190 | 136 | |
|---|
| 191 | 137 | return 0; |
|---|
| 192 | 138 | } |
|---|
| .. | .. |
|---|
| 194 | 140 | static int __maybe_unused dwc3_of_simple_runtime_resume(struct device *dev) |
|---|
| 195 | 141 | { |
|---|
| 196 | 142 | struct dwc3_of_simple *simple = dev_get_drvdata(dev); |
|---|
| 197 | | - int ret; |
|---|
| 198 | | - int i; |
|---|
| 199 | 143 | |
|---|
| 200 | | - for (i = 0; i < simple->num_clocks; i++) { |
|---|
| 201 | | - ret = clk_enable(simple->clks[i]); |
|---|
| 202 | | - if (ret < 0) { |
|---|
| 203 | | - while (--i >= 0) |
|---|
| 204 | | - clk_disable(simple->clks[i]); |
|---|
| 205 | | - return ret; |
|---|
| 206 | | - } |
|---|
| 207 | | - } |
|---|
| 208 | | - |
|---|
| 209 | | - return 0; |
|---|
| 144 | + return clk_bulk_enable(simple->num_clocks, simple->clks); |
|---|
| 210 | 145 | } |
|---|
| 211 | 146 | |
|---|
| 212 | 147 | static int __maybe_unused dwc3_of_simple_suspend(struct device *dev) |
|---|
| .. | .. |
|---|
| 240 | 175 | { .compatible = "xlnx,zynqmp-dwc3" }, |
|---|
| 241 | 176 | { .compatible = "cavium,octeon-7130-usb-uctl" }, |
|---|
| 242 | 177 | { .compatible = "sprd,sc9860-dwc3" }, |
|---|
| 243 | | - { .compatible = "amlogic,meson-axg-dwc3" }, |
|---|
| 244 | | - { .compatible = "amlogic,meson-gxl-dwc3" }, |
|---|
| 245 | 178 | { .compatible = "allwinner,sun50i-h6-dwc3" }, |
|---|
| 246 | 179 | { .compatible = "hisilicon,hi3670-dwc3" }, |
|---|
| 180 | + { .compatible = "intel,keembay-dwc3" }, |
|---|
| 247 | 181 | { /* Sentinel */ } |
|---|
| 248 | 182 | }; |
|---|
| 249 | 183 | MODULE_DEVICE_TABLE(of, of_dwc3_simple_match); |
|---|
| .. | .. |
|---|
| 251 | 185 | static struct platform_driver dwc3_of_simple_driver = { |
|---|
| 252 | 186 | .probe = dwc3_of_simple_probe, |
|---|
| 253 | 187 | .remove = dwc3_of_simple_remove, |
|---|
| 188 | + .shutdown = dwc3_of_simple_shutdown, |
|---|
| 254 | 189 | .driver = { |
|---|
| 255 | 190 | .name = "dwc3-of-simple", |
|---|
| 256 | 191 | .of_match_table = of_dwc3_simple_match, |
|---|