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/io.h> 27 #include <linux/platform_device.h> 28 29 #include "musb_core.h" 30 31 struct ux500_glue { 32 struct device *dev; 33 struct platform_device *musb; 34 struct clk *clk; 35 }; 36 #define glue_to_musb(g) platform_get_drvdata(g->musb) 37 38 static int ux500_musb_init(struct musb *musb) 39 { 40 musb->xceiv = otg_get_transceiver(); 41 if (!musb->xceiv) { 42 pr_err("HS USB OTG: no transceiver configured\n"); 43 return -ENODEV; 44 } 45 46 return 0; 47 } 48 49 static int ux500_musb_exit(struct musb *musb) 50 { 51 otg_put_transceiver(musb->xceiv); 52 53 return 0; 54 } 55 56 static const struct musb_platform_ops ux500_ops = { 57 .init = ux500_musb_init, 58 .exit = ux500_musb_exit, 59 }; 60 61 static int __init ux500_probe(struct platform_device *pdev) 62 { 63 struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; 64 struct platform_device *musb; 65 struct ux500_glue *glue; 66 struct clk *clk; 67 68 int ret = -ENOMEM; 69 70 glue = kzalloc(sizeof(*glue), GFP_KERNEL); 71 if (!glue) { 72 dev_err(&pdev->dev, "failed to allocate glue context\n"); 73 goto err0; 74 } 75 76 musb = platform_device_alloc("musb-hdrc", -1); 77 if (!musb) { 78 dev_err(&pdev->dev, "failed to allocate musb device\n"); 79 goto err1; 80 } 81 82 clk = clk_get(&pdev->dev, "usb"); 83 if (IS_ERR(clk)) { 84 dev_err(&pdev->dev, "failed to get clock\n"); 85 ret = PTR_ERR(clk); 86 goto err2; 87 } 88 89 ret = clk_enable(clk); 90 if (ret) { 91 dev_err(&pdev->dev, "failed to enable clock\n"); 92 goto err3; 93 } 94 95 musb->dev.parent = &pdev->dev; 96 97 glue->dev = &pdev->dev; 98 glue->musb = musb; 99 glue->clk = clk; 100 101 pdata->platform_ops = &ux500_ops; 102 103 platform_set_drvdata(pdev, glue); 104 105 ret = platform_device_add_resources(musb, pdev->resource, 106 pdev->num_resources); 107 if (ret) { 108 dev_err(&pdev->dev, "failed to add resources\n"); 109 goto err4; 110 } 111 112 ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); 113 if (ret) { 114 dev_err(&pdev->dev, "failed to add platform_data\n"); 115 goto err4; 116 } 117 118 ret = platform_device_add(musb); 119 if (ret) { 120 dev_err(&pdev->dev, "failed to register musb device\n"); 121 goto err4; 122 } 123 124 return 0; 125 126 err4: 127 clk_disable(clk); 128 129 err3: 130 clk_put(clk); 131 132 err2: 133 platform_device_put(musb); 134 135 err1: 136 kfree(glue); 137 138 err0: 139 return ret; 140 } 141 142 static int __exit ux500_remove(struct platform_device *pdev) 143 { 144 struct ux500_glue *glue = platform_get_drvdata(pdev); 145 146 platform_device_del(glue->musb); 147 platform_device_put(glue->musb); 148 clk_disable(glue->clk); 149 clk_put(glue->clk); 150 kfree(glue); 151 152 return 0; 153 } 154 155 #ifdef CONFIG_PM 156 static int ux500_suspend(struct device *dev) 157 { 158 struct ux500_glue *glue = dev_get_drvdata(dev); 159 struct musb *musb = glue_to_musb(glue); 160 161 otg_set_suspend(musb->xceiv, 1); 162 clk_disable(glue->clk); 163 164 return 0; 165 } 166 167 static int ux500_resume(struct device *dev) 168 { 169 struct ux500_glue *glue = dev_get_drvdata(dev); 170 struct musb *musb = glue_to_musb(glue); 171 int ret; 172 173 ret = clk_enable(glue->clk); 174 if (ret) { 175 dev_err(dev, "failed to enable clock\n"); 176 return ret; 177 } 178 179 otg_set_suspend(musb->xceiv, 0); 180 181 return 0; 182 } 183 184 static const struct dev_pm_ops ux500_pm_ops = { 185 .suspend = ux500_suspend, 186 .resume = ux500_resume, 187 }; 188 189 #define DEV_PM_OPS (&ux500_pm_ops) 190 #else 191 #define DEV_PM_OPS NULL 192 #endif 193 194 static struct platform_driver ux500_driver = { 195 .remove = __exit_p(ux500_remove), 196 .driver = { 197 .name = "musb-ux500", 198 .pm = DEV_PM_OPS, 199 }, 200 }; 201 202 MODULE_DESCRIPTION("UX500 MUSB Glue Layer"); 203 MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>"); 204 MODULE_LICENSE("GPL v2"); 205 206 static int __init ux500_init(void) 207 { 208 return platform_driver_probe(&ux500_driver, ux500_probe); 209 } 210 subsys_initcall(ux500_init); 211 212 static void __exit ux500_exit(void) 213 { 214 platform_driver_unregister(&ux500_driver); 215 } 216 module_exit(ux500_exit); 217