1 /* 2 * Copyright (C) 2010 ST-Ericsson AB 3 * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> 4 * 5 * Based on omap2430.c 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 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 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22 #include <linux/module.h> 23 #include <linux/kernel.h> 24 #include <linux/init.h> 25 #include <linux/clk.h> 26 #include <linux/err.h> 27 #include <linux/io.h> 28 #include <linux/platform_device.h> 29 30 #include "musb_core.h" 31 32 struct ux500_glue { 33 struct device *dev; 34 struct platform_device *musb; 35 struct clk *clk; 36 }; 37 #define glue_to_musb(g) platform_get_drvdata(g->musb) 38 39 static int ux500_musb_init(struct musb *musb) 40 { 41 musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); 42 if (IS_ERR_OR_NULL(musb->xceiv)) { 43 pr_err("HS USB OTG: no transceiver configured\n"); 44 return -ENODEV; 45 } 46 47 return 0; 48 } 49 50 static int ux500_musb_exit(struct musb *musb) 51 { 52 usb_put_phy(musb->xceiv); 53 54 return 0; 55 } 56 57 static const struct musb_platform_ops ux500_ops = { 58 .init = ux500_musb_init, 59 .exit = ux500_musb_exit, 60 }; 61 62 static int __devinit ux500_probe(struct platform_device *pdev) 63 { 64 struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; 65 struct platform_device *musb; 66 struct ux500_glue *glue; 67 struct clk *clk; 68 int musbid; 69 int ret = -ENOMEM; 70 71 glue = kzalloc(sizeof(*glue), GFP_KERNEL); 72 if (!glue) { 73 dev_err(&pdev->dev, "failed to allocate glue context\n"); 74 goto err0; 75 } 76 77 /* get the musb id */ 78 musbid = musb_get_id(&pdev->dev, GFP_KERNEL); 79 if (musbid < 0) { 80 dev_err(&pdev->dev, "failed to allocate musb id\n"); 81 ret = -ENOMEM; 82 goto err1; 83 } 84 85 musb = platform_device_alloc("musb-hdrc", musbid); 86 if (!musb) { 87 dev_err(&pdev->dev, "failed to allocate musb device\n"); 88 goto err2; 89 } 90 91 clk = clk_get(&pdev->dev, "usb"); 92 if (IS_ERR(clk)) { 93 dev_err(&pdev->dev, "failed to get clock\n"); 94 ret = PTR_ERR(clk); 95 goto err3; 96 } 97 98 ret = clk_enable(clk); 99 if (ret) { 100 dev_err(&pdev->dev, "failed to enable clock\n"); 101 goto err4; 102 } 103 104 musb->id = musbid; 105 musb->dev.parent = &pdev->dev; 106 musb->dev.dma_mask = pdev->dev.dma_mask; 107 musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; 108 109 glue->dev = &pdev->dev; 110 glue->musb = musb; 111 glue->clk = clk; 112 113 pdata->platform_ops = &ux500_ops; 114 115 platform_set_drvdata(pdev, glue); 116 117 ret = platform_device_add_resources(musb, pdev->resource, 118 pdev->num_resources); 119 if (ret) { 120 dev_err(&pdev->dev, "failed to add resources\n"); 121 goto err5; 122 } 123 124 ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); 125 if (ret) { 126 dev_err(&pdev->dev, "failed to add platform_data\n"); 127 goto err5; 128 } 129 130 ret = platform_device_add(musb); 131 if (ret) { 132 dev_err(&pdev->dev, "failed to register musb device\n"); 133 goto err5; 134 } 135 136 return 0; 137 138 err5: 139 clk_disable(clk); 140 141 err4: 142 clk_put(clk); 143 144 err3: 145 platform_device_put(musb); 146 147 err2: 148 musb_put_id(&pdev->dev, musbid); 149 150 err1: 151 kfree(glue); 152 153 err0: 154 return ret; 155 } 156 157 static int __devexit ux500_remove(struct platform_device *pdev) 158 { 159 struct ux500_glue *glue = platform_get_drvdata(pdev); 160 161 musb_put_id(&pdev->dev, glue->musb->id); 162 platform_device_del(glue->musb); 163 platform_device_put(glue->musb); 164 clk_disable(glue->clk); 165 clk_put(glue->clk); 166 kfree(glue); 167 168 return 0; 169 } 170 171 #ifdef CONFIG_PM 172 static int ux500_suspend(struct device *dev) 173 { 174 struct ux500_glue *glue = dev_get_drvdata(dev); 175 struct musb *musb = glue_to_musb(glue); 176 177 usb_phy_set_suspend(musb->xceiv, 1); 178 clk_disable(glue->clk); 179 180 return 0; 181 } 182 183 static int ux500_resume(struct device *dev) 184 { 185 struct ux500_glue *glue = dev_get_drvdata(dev); 186 struct musb *musb = glue_to_musb(glue); 187 int ret; 188 189 ret = clk_enable(glue->clk); 190 if (ret) { 191 dev_err(dev, "failed to enable clock\n"); 192 return ret; 193 } 194 195 usb_phy_set_suspend(musb->xceiv, 0); 196 197 return 0; 198 } 199 200 static const struct dev_pm_ops ux500_pm_ops = { 201 .suspend = ux500_suspend, 202 .resume = ux500_resume, 203 }; 204 205 #define DEV_PM_OPS (&ux500_pm_ops) 206 #else 207 #define DEV_PM_OPS NULL 208 #endif 209 210 static struct platform_driver ux500_driver = { 211 .probe = ux500_probe, 212 .remove = __devexit_p(ux500_remove), 213 .driver = { 214 .name = "musb-ux500", 215 .pm = DEV_PM_OPS, 216 }, 217 }; 218 219 MODULE_DESCRIPTION("UX500 MUSB Glue Layer"); 220 MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>"); 221 MODULE_LICENSE("GPL v2"); 222 223 static int __init ux500_init(void) 224 { 225 return platform_driver_register(&ux500_driver); 226 } 227 module_init(ux500_init); 228 229 static void __exit ux500_exit(void) 230 { 231 platform_driver_unregister(&ux500_driver); 232 } 233 module_exit(ux500_exit); 234