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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.13-rc1 361 lines 9.3 kB view raw
1/* 2 * omap-usb3 - USB PHY, talking to dwc3 controller in OMAP. 3 * 4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * Author: Kishon Vijay Abraham I <kishon@ti.com> 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 */ 18 19#include <linux/module.h> 20#include <linux/platform_device.h> 21#include <linux/slab.h> 22#include <linux/usb/omap_usb.h> 23#include <linux/of.h> 24#include <linux/clk.h> 25#include <linux/err.h> 26#include <linux/pm_runtime.h> 27#include <linux/delay.h> 28#include <linux/usb/omap_control_usb.h> 29#include <linux/of_platform.h> 30 31#define PLL_STATUS 0x00000004 32#define PLL_GO 0x00000008 33#define PLL_CONFIGURATION1 0x0000000C 34#define PLL_CONFIGURATION2 0x00000010 35#define PLL_CONFIGURATION3 0x00000014 36#define PLL_CONFIGURATION4 0x00000020 37 38#define PLL_REGM_MASK 0x001FFE00 39#define PLL_REGM_SHIFT 0x9 40#define PLL_REGM_F_MASK 0x0003FFFF 41#define PLL_REGM_F_SHIFT 0x0 42#define PLL_REGN_MASK 0x000001FE 43#define PLL_REGN_SHIFT 0x1 44#define PLL_SELFREQDCO_MASK 0x0000000E 45#define PLL_SELFREQDCO_SHIFT 0x1 46#define PLL_SD_MASK 0x0003FC00 47#define PLL_SD_SHIFT 0x9 48#define SET_PLL_GO 0x1 49#define PLL_TICOPWDN 0x10000 50#define PLL_LOCK 0x2 51#define PLL_IDLE 0x1 52 53/* 54 * This is an Empirical value that works, need to confirm the actual 55 * value required for the USB3PHY_PLL_CONFIGURATION2.PLL_IDLE status 56 * to be correctly reflected in the USB3PHY_PLL_STATUS register. 57 */ 58# define PLL_IDLE_TIME 100; 59 60struct usb_dpll_map { 61 unsigned long rate; 62 struct usb_dpll_params params; 63}; 64 65static struct usb_dpll_map dpll_map[] = { 66 {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */ 67 {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */ 68 {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */ 69 {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */ 70 {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */ 71 {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */ 72}; 73 74static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate) 75{ 76 int i; 77 78 for (i = 0; i < ARRAY_SIZE(dpll_map); i++) { 79 if (rate == dpll_map[i].rate) 80 return &dpll_map[i].params; 81 } 82 83 return NULL; 84} 85 86static int omap_usb3_suspend(struct usb_phy *x, int suspend) 87{ 88 struct omap_usb *phy = phy_to_omapusb(x); 89 int val; 90 int timeout = PLL_IDLE_TIME; 91 92 if (suspend && !phy->is_suspended) { 93 val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 94 val |= PLL_IDLE; 95 omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 96 97 do { 98 val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); 99 if (val & PLL_TICOPWDN) 100 break; 101 udelay(1); 102 } while (--timeout); 103 104 omap_control_usb_phy_power(phy->control_dev, 0); 105 106 phy->is_suspended = 1; 107 } else if (!suspend && phy->is_suspended) { 108 phy->is_suspended = 0; 109 110 val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 111 val &= ~PLL_IDLE; 112 omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 113 114 do { 115 val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); 116 if (!(val & PLL_TICOPWDN)) 117 break; 118 udelay(1); 119 } while (--timeout); 120 } 121 122 return 0; 123} 124 125static void omap_usb_dpll_relock(struct omap_usb *phy) 126{ 127 u32 val; 128 unsigned long timeout; 129 130 omap_usb_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO); 131 132 timeout = jiffies + msecs_to_jiffies(20); 133 do { 134 val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); 135 if (val & PLL_LOCK) 136 break; 137 } while (!WARN_ON(time_after(jiffies, timeout))); 138} 139 140static int omap_usb_dpll_lock(struct omap_usb *phy) 141{ 142 u32 val; 143 unsigned long rate; 144 struct usb_dpll_params *dpll_params; 145 146 rate = clk_get_rate(phy->sys_clk); 147 dpll_params = omap_usb3_get_dpll_params(rate); 148 if (!dpll_params) { 149 dev_err(phy->dev, 150 "No DPLL configuration for %lu Hz SYS CLK\n", rate); 151 return -EINVAL; 152 } 153 154 val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); 155 val &= ~PLL_REGN_MASK; 156 val |= dpll_params->n << PLL_REGN_SHIFT; 157 omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); 158 159 val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 160 val &= ~PLL_SELFREQDCO_MASK; 161 val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; 162 omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 163 164 val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); 165 val &= ~PLL_REGM_MASK; 166 val |= dpll_params->m << PLL_REGM_SHIFT; 167 omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); 168 169 val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); 170 val &= ~PLL_REGM_F_MASK; 171 val |= dpll_params->mf << PLL_REGM_F_SHIFT; 172 omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); 173 174 val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); 175 val &= ~PLL_SD_MASK; 176 val |= dpll_params->sd << PLL_SD_SHIFT; 177 omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); 178 179 omap_usb_dpll_relock(phy); 180 181 return 0; 182} 183 184static int omap_usb3_init(struct usb_phy *x) 185{ 186 struct omap_usb *phy = phy_to_omapusb(x); 187 int ret; 188 189 ret = omap_usb_dpll_lock(phy); 190 if (ret) 191 return ret; 192 193 omap_control_usb_phy_power(phy->control_dev, 1); 194 195 return 0; 196} 197 198static int omap_usb3_probe(struct platform_device *pdev) 199{ 200 struct omap_usb *phy; 201 struct resource *res; 202 struct device_node *node = pdev->dev.of_node; 203 struct device_node *control_node; 204 struct platform_device *control_pdev; 205 206 if (!node) 207 return -EINVAL; 208 209 phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); 210 if (!phy) { 211 dev_err(&pdev->dev, "unable to alloc mem for OMAP USB3 PHY\n"); 212 return -ENOMEM; 213 } 214 215 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); 216 phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); 217 if (IS_ERR(phy->pll_ctrl_base)) 218 return PTR_ERR(phy->pll_ctrl_base); 219 220 phy->dev = &pdev->dev; 221 222 phy->phy.dev = phy->dev; 223 phy->phy.label = "omap-usb3"; 224 phy->phy.init = omap_usb3_init; 225 phy->phy.set_suspend = omap_usb3_suspend; 226 phy->phy.type = USB_PHY_TYPE_USB3; 227 228 phy->is_suspended = 1; 229 phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); 230 if (IS_ERR(phy->wkupclk)) { 231 dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); 232 return PTR_ERR(phy->wkupclk); 233 } 234 clk_prepare(phy->wkupclk); 235 236 phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); 237 if (IS_ERR(phy->optclk)) { 238 dev_err(&pdev->dev, "unable to get usb_otg_ss_refclk960m\n"); 239 return PTR_ERR(phy->optclk); 240 } 241 clk_prepare(phy->optclk); 242 243 phy->sys_clk = devm_clk_get(phy->dev, "sys_clkin"); 244 if (IS_ERR(phy->sys_clk)) { 245 pr_err("%s: unable to get sys_clkin\n", __func__); 246 return -EINVAL; 247 } 248 249 control_node = of_parse_phandle(node, "ctrl-module", 0); 250 if (!control_node) { 251 dev_err(&pdev->dev, "Failed to get control device phandle\n"); 252 return -EINVAL; 253 } 254 control_pdev = of_find_device_by_node(control_node); 255 if (!control_pdev) { 256 dev_err(&pdev->dev, "Failed to get control device\n"); 257 return -EINVAL; 258 } 259 260 phy->control_dev = &control_pdev->dev; 261 262 omap_control_usb_phy_power(phy->control_dev, 0); 263 usb_add_phy_dev(&phy->phy); 264 265 platform_set_drvdata(pdev, phy); 266 267 pm_runtime_enable(phy->dev); 268 pm_runtime_get(&pdev->dev); 269 270 return 0; 271} 272 273static int omap_usb3_remove(struct platform_device *pdev) 274{ 275 struct omap_usb *phy = platform_get_drvdata(pdev); 276 277 clk_unprepare(phy->wkupclk); 278 clk_unprepare(phy->optclk); 279 usb_remove_phy(&phy->phy); 280 if (!pm_runtime_suspended(&pdev->dev)) 281 pm_runtime_put(&pdev->dev); 282 pm_runtime_disable(&pdev->dev); 283 284 return 0; 285} 286 287#ifdef CONFIG_PM_RUNTIME 288 289static int omap_usb3_runtime_suspend(struct device *dev) 290{ 291 struct platform_device *pdev = to_platform_device(dev); 292 struct omap_usb *phy = platform_get_drvdata(pdev); 293 294 clk_disable(phy->wkupclk); 295 clk_disable(phy->optclk); 296 297 return 0; 298} 299 300static int omap_usb3_runtime_resume(struct device *dev) 301{ 302 u32 ret = 0; 303 struct platform_device *pdev = to_platform_device(dev); 304 struct omap_usb *phy = platform_get_drvdata(pdev); 305 306 ret = clk_enable(phy->optclk); 307 if (ret) { 308 dev_err(phy->dev, "Failed to enable optclk %d\n", ret); 309 goto err1; 310 } 311 312 ret = clk_enable(phy->wkupclk); 313 if (ret) { 314 dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); 315 goto err2; 316 } 317 318 return 0; 319 320err2: 321 clk_disable(phy->optclk); 322 323err1: 324 return ret; 325} 326 327static const struct dev_pm_ops omap_usb3_pm_ops = { 328 SET_RUNTIME_PM_OPS(omap_usb3_runtime_suspend, omap_usb3_runtime_resume, 329 NULL) 330}; 331 332#define DEV_PM_OPS (&omap_usb3_pm_ops) 333#else 334#define DEV_PM_OPS NULL 335#endif 336 337#ifdef CONFIG_OF 338static const struct of_device_id omap_usb3_id_table[] = { 339 { .compatible = "ti,omap-usb3" }, 340 {} 341}; 342MODULE_DEVICE_TABLE(of, omap_usb3_id_table); 343#endif 344 345static struct platform_driver omap_usb3_driver = { 346 .probe = omap_usb3_probe, 347 .remove = omap_usb3_remove, 348 .driver = { 349 .name = "omap-usb3", 350 .owner = THIS_MODULE, 351 .pm = DEV_PM_OPS, 352 .of_match_table = of_match_ptr(omap_usb3_id_table), 353 }, 354}; 355 356module_platform_driver(omap_usb3_driver); 357 358MODULE_ALIAS("platform: omap_usb3"); 359MODULE_AUTHOR("Texas Instruments Inc."); 360MODULE_DESCRIPTION("OMAP USB3 phy driver"); 361MODULE_LICENSE("GPL v2");