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

usb: chipidea: imx: refine clock operations to adapt for all platforms

Some i.mx platforms need three clocks to let controller work, but
others only need one, refine clock operation to adapt for all
platforms, it fixes a regression found at i.mx27.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
Tested-by: Fabio Estevam <fabio.estevam@freescale.com>
Cc: <stable@vger.kernel.org> #v4.1+

+114 -19
+114 -19
drivers/usb/chipidea/ci_hdrc_imx.c
··· 84 84 struct imx_usbmisc_data *usbmisc_data; 85 85 bool supports_runtime_pm; 86 86 bool in_lpm; 87 + /* SoC before i.mx6 (except imx23/imx28) needs three clks */ 88 + bool need_three_clks; 89 + struct clk *clk_ipg; 90 + struct clk *clk_ahb; 91 + struct clk *clk_per; 92 + /* --------------------------------- */ 87 93 }; 88 94 89 95 /* Common functions shared by usbmisc drivers */ ··· 141 135 } 142 136 143 137 /* End of common functions shared by usbmisc drivers*/ 138 + static int imx_get_clks(struct device *dev) 139 + { 140 + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 141 + int ret = 0; 142 + 143 + data->clk_ipg = devm_clk_get(dev, "ipg"); 144 + if (IS_ERR(data->clk_ipg)) { 145 + /* If the platform only needs one clocks */ 146 + data->clk = devm_clk_get(dev, NULL); 147 + if (IS_ERR(data->clk)) { 148 + ret = PTR_ERR(data->clk); 149 + dev_err(dev, 150 + "Failed to get clks, err=%ld,%ld\n", 151 + PTR_ERR(data->clk), PTR_ERR(data->clk_ipg)); 152 + return ret; 153 + } 154 + return ret; 155 + } 156 + 157 + data->clk_ahb = devm_clk_get(dev, "ahb"); 158 + if (IS_ERR(data->clk_ahb)) { 159 + ret = PTR_ERR(data->clk_ahb); 160 + dev_err(dev, 161 + "Failed to get ahb clock, err=%d\n", ret); 162 + return ret; 163 + } 164 + 165 + data->clk_per = devm_clk_get(dev, "per"); 166 + if (IS_ERR(data->clk_per)) { 167 + ret = PTR_ERR(data->clk_per); 168 + dev_err(dev, 169 + "Failed to get per clock, err=%d\n", ret); 170 + return ret; 171 + } 172 + 173 + data->need_three_clks = true; 174 + return ret; 175 + } 176 + 177 + static int imx_prepare_enable_clks(struct device *dev) 178 + { 179 + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 180 + int ret = 0; 181 + 182 + if (data->need_three_clks) { 183 + ret = clk_prepare_enable(data->clk_ipg); 184 + if (ret) { 185 + dev_err(dev, 186 + "Failed to prepare/enable ipg clk, err=%d\n", 187 + ret); 188 + return ret; 189 + } 190 + 191 + ret = clk_prepare_enable(data->clk_ahb); 192 + if (ret) { 193 + dev_err(dev, 194 + "Failed to prepare/enable ahb clk, err=%d\n", 195 + ret); 196 + clk_disable_unprepare(data->clk_ipg); 197 + return ret; 198 + } 199 + 200 + ret = clk_prepare_enable(data->clk_per); 201 + if (ret) { 202 + dev_err(dev, 203 + "Failed to prepare/enable per clk, err=%d\n", 204 + ret); 205 + clk_disable_unprepare(data->clk_ahb); 206 + clk_disable_unprepare(data->clk_ipg); 207 + return ret; 208 + } 209 + } else { 210 + ret = clk_prepare_enable(data->clk); 211 + if (ret) { 212 + dev_err(dev, 213 + "Failed to prepare/enable clk, err=%d\n", 214 + ret); 215 + return ret; 216 + } 217 + } 218 + 219 + return ret; 220 + } 221 + 222 + static void imx_disable_unprepare_clks(struct device *dev) 223 + { 224 + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 225 + 226 + if (data->need_three_clks) { 227 + clk_disable_unprepare(data->clk_per); 228 + clk_disable_unprepare(data->clk_ahb); 229 + clk_disable_unprepare(data->clk_ipg); 230 + } else { 231 + clk_disable_unprepare(data->clk); 232 + } 233 + } 144 234 145 235 static int ci_hdrc_imx_probe(struct platform_device *pdev) 146 236 { ··· 255 153 if (!data) 256 154 return -ENOMEM; 257 155 156 + platform_set_drvdata(pdev, data); 258 157 data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); 259 158 if (IS_ERR(data->usbmisc_data)) 260 159 return PTR_ERR(data->usbmisc_data); 261 160 262 - data->clk = devm_clk_get(&pdev->dev, NULL); 263 - if (IS_ERR(data->clk)) { 264 - dev_err(&pdev->dev, 265 - "Failed to get clock, err=%ld\n", PTR_ERR(data->clk)); 266 - return PTR_ERR(data->clk); 267 - } 268 - 269 - ret = clk_prepare_enable(data->clk); 270 - if (ret) { 271 - dev_err(&pdev->dev, 272 - "Failed to prepare or enable clock, err=%d\n", ret); 161 + ret = imx_get_clks(&pdev->dev); 162 + if (ret) 273 163 return ret; 274 - } 164 + 165 + ret = imx_prepare_enable_clks(&pdev->dev); 166 + if (ret) 167 + return ret; 275 168 276 169 data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0); 277 170 if (IS_ERR(data->phy)) { ··· 309 212 goto disable_device; 310 213 } 311 214 312 - platform_set_drvdata(pdev, data); 313 - 314 215 if (data->supports_runtime_pm) { 315 216 pm_runtime_set_active(&pdev->dev); 316 217 pm_runtime_enable(&pdev->dev); ··· 321 226 disable_device: 322 227 ci_hdrc_remove_device(data->ci_pdev); 323 228 err_clk: 324 - clk_disable_unprepare(data->clk); 229 + imx_disable_unprepare_clks(&pdev->dev); 325 230 return ret; 326 231 } 327 232 ··· 335 240 pm_runtime_put_noidle(&pdev->dev); 336 241 } 337 242 ci_hdrc_remove_device(data->ci_pdev); 338 - clk_disable_unprepare(data->clk); 243 + imx_disable_unprepare_clks(&pdev->dev); 339 244 340 245 return 0; 341 246 } ··· 347 252 348 253 dev_dbg(dev, "at %s\n", __func__); 349 254 350 - clk_disable_unprepare(data->clk); 255 + imx_disable_unprepare_clks(dev); 351 256 data->in_lpm = true; 352 257 353 258 return 0; ··· 365 270 return 0; 366 271 } 367 272 368 - ret = clk_prepare_enable(data->clk); 273 + ret = imx_prepare_enable_clks(dev); 369 274 if (ret) 370 275 return ret; 371 276 ··· 380 285 return 0; 381 286 382 287 clk_disable: 383 - clk_disable_unprepare(data->clk); 288 + imx_disable_unprepare_clks(dev); 384 289 return ret; 385 290 } 386 291