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.8 269 lines 6.4 kB view raw
1/* 2 * Copyright 2012 Freescale Semiconductor, Inc. 3 * Copyright (C) 2012 Marek Vasut <marex@denx.de> 4 * on behalf of DENX Software Engineering GmbH 5 * 6 * The code contained herein is licensed under the GNU General Public 7 * License. You may obtain a copy of the GNU General Public License 8 * Version 2 or later at the following locations: 9 * 10 * http://www.opensource.org/licenses/gpl-license.html 11 * http://www.gnu.org/copyleft/gpl.html 12 */ 13 14#include <linux/module.h> 15#include <linux/of_platform.h> 16#include <linux/of_gpio.h> 17#include <linux/platform_device.h> 18#include <linux/pm_runtime.h> 19#include <linux/dma-mapping.h> 20#include <linux/usb/chipidea.h> 21#include <linux/clk.h> 22#include <linux/regulator/consumer.h> 23#include <linux/pinctrl/consumer.h> 24 25#include "ci.h" 26#include "ci13xxx_imx.h" 27 28#define pdev_to_phy(pdev) \ 29 ((struct usb_phy *)platform_get_drvdata(pdev)) 30 31struct ci13xxx_imx_data { 32 struct device_node *phy_np; 33 struct usb_phy *phy; 34 struct platform_device *ci_pdev; 35 struct clk *clk; 36 struct regulator *reg_vbus; 37}; 38 39static const struct usbmisc_ops *usbmisc_ops; 40 41/* Common functions shared by usbmisc drivers */ 42 43int usbmisc_set_ops(const struct usbmisc_ops *ops) 44{ 45 if (usbmisc_ops) 46 return -EBUSY; 47 48 usbmisc_ops = ops; 49 50 return 0; 51} 52EXPORT_SYMBOL_GPL(usbmisc_set_ops); 53 54void usbmisc_unset_ops(const struct usbmisc_ops *ops) 55{ 56 usbmisc_ops = NULL; 57} 58EXPORT_SYMBOL_GPL(usbmisc_unset_ops); 59 60int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) 61{ 62 struct device_node *np = dev->of_node; 63 struct of_phandle_args args; 64 int ret; 65 66 usbdev->dev = dev; 67 68 ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", 69 0, &args); 70 if (ret) { 71 dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", 72 ret); 73 memset(usbdev, 0, sizeof(*usbdev)); 74 return ret; 75 } 76 usbdev->index = args.args[0]; 77 of_node_put(args.np); 78 79 if (of_find_property(np, "disable-over-current", NULL)) 80 usbdev->disable_oc = 1; 81 82 return 0; 83} 84EXPORT_SYMBOL_GPL(usbmisc_get_init_data); 85 86/* End of common functions shared by usbmisc drivers*/ 87 88static struct ci13xxx_platform_data ci13xxx_imx_platdata = { 89 .name = "ci13xxx_imx", 90 .flags = CI13XXX_REQUIRE_TRANSCEIVER | 91 CI13XXX_PULLUP_ON_VBUS | 92 CI13XXX_DISABLE_STREAMING, 93 .capoffset = DEF_CAPOFFSET, 94}; 95 96static int ci13xxx_imx_probe(struct platform_device *pdev) 97{ 98 struct ci13xxx_imx_data *data; 99 struct platform_device *plat_ci, *phy_pdev; 100 struct device_node *phy_np; 101 struct resource *res; 102 struct regulator *reg_vbus; 103 struct pinctrl *pinctrl; 104 int ret; 105 106 if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL) 107 && !usbmisc_ops) 108 return -EPROBE_DEFER; 109 110 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 111 if (!data) { 112 dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n"); 113 return -ENOMEM; 114 } 115 116 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 117 if (!res) { 118 dev_err(&pdev->dev, "Can't get device resources!\n"); 119 return -ENOENT; 120 } 121 122 pinctrl = devm_pinctrl_get_select_default(&pdev->dev); 123 if (IS_ERR(pinctrl)) 124 dev_warn(&pdev->dev, "pinctrl get/select failed, err=%ld\n", 125 PTR_ERR(pinctrl)); 126 127 data->clk = devm_clk_get(&pdev->dev, NULL); 128 if (IS_ERR(data->clk)) { 129 dev_err(&pdev->dev, 130 "Failed to get clock, err=%ld\n", PTR_ERR(data->clk)); 131 return PTR_ERR(data->clk); 132 } 133 134 ret = clk_prepare_enable(data->clk); 135 if (ret) { 136 dev_err(&pdev->dev, 137 "Failed to prepare or enable clock, err=%d\n", ret); 138 return ret; 139 } 140 141 phy_np = of_parse_phandle(pdev->dev.of_node, "fsl,usbphy", 0); 142 if (phy_np) { 143 data->phy_np = phy_np; 144 phy_pdev = of_find_device_by_node(phy_np); 145 if (phy_pdev) { 146 struct usb_phy *phy; 147 phy = pdev_to_phy(phy_pdev); 148 if (phy && 149 try_module_get(phy_pdev->dev.driver->owner)) { 150 usb_phy_init(phy); 151 data->phy = phy; 152 } 153 } 154 } 155 156 /* we only support host now, so enable vbus here */ 157 reg_vbus = devm_regulator_get(&pdev->dev, "vbus"); 158 if (!IS_ERR(reg_vbus)) { 159 ret = regulator_enable(reg_vbus); 160 if (ret) { 161 dev_err(&pdev->dev, 162 "Failed to enable vbus regulator, err=%d\n", 163 ret); 164 goto put_np; 165 } 166 data->reg_vbus = reg_vbus; 167 } else { 168 reg_vbus = NULL; 169 } 170 171 ci13xxx_imx_platdata.phy = data->phy; 172 173 if (!pdev->dev.dma_mask) { 174 pdev->dev.dma_mask = devm_kzalloc(&pdev->dev, 175 sizeof(*pdev->dev.dma_mask), GFP_KERNEL); 176 if (!pdev->dev.dma_mask) { 177 ret = -ENOMEM; 178 dev_err(&pdev->dev, "Failed to alloc dma_mask!\n"); 179 goto err; 180 } 181 *pdev->dev.dma_mask = DMA_BIT_MASK(32); 182 dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask); 183 } 184 185 if (usbmisc_ops && usbmisc_ops->init) { 186 ret = usbmisc_ops->init(&pdev->dev); 187 if (ret) { 188 dev_err(&pdev->dev, 189 "usbmisc init failed, ret=%d\n", ret); 190 goto err; 191 } 192 } 193 194 plat_ci = ci13xxx_add_device(&pdev->dev, 195 pdev->resource, pdev->num_resources, 196 &ci13xxx_imx_platdata); 197 if (IS_ERR(plat_ci)) { 198 ret = PTR_ERR(plat_ci); 199 dev_err(&pdev->dev, 200 "Can't register ci_hdrc platform device, err=%d\n", 201 ret); 202 goto err; 203 } 204 205 data->ci_pdev = plat_ci; 206 platform_set_drvdata(pdev, data); 207 208 pm_runtime_no_callbacks(&pdev->dev); 209 pm_runtime_enable(&pdev->dev); 210 211 return 0; 212 213err: 214 if (reg_vbus) 215 regulator_disable(reg_vbus); 216put_np: 217 if (phy_np) 218 of_node_put(phy_np); 219 clk_disable_unprepare(data->clk); 220 return ret; 221} 222 223static int ci13xxx_imx_remove(struct platform_device *pdev) 224{ 225 struct ci13xxx_imx_data *data = platform_get_drvdata(pdev); 226 227 pm_runtime_disable(&pdev->dev); 228 ci13xxx_remove_device(data->ci_pdev); 229 230 if (data->reg_vbus) 231 regulator_disable(data->reg_vbus); 232 233 if (data->phy) { 234 usb_phy_shutdown(data->phy); 235 module_put(data->phy->dev->driver->owner); 236 } 237 238 of_node_put(data->phy_np); 239 240 clk_disable_unprepare(data->clk); 241 242 platform_set_drvdata(pdev, NULL); 243 244 return 0; 245} 246 247static const struct of_device_id ci13xxx_imx_dt_ids[] = { 248 { .compatible = "fsl,imx27-usb", }, 249 { /* sentinel */ } 250}; 251MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids); 252 253static struct platform_driver ci13xxx_imx_driver = { 254 .probe = ci13xxx_imx_probe, 255 .remove = ci13xxx_imx_remove, 256 .driver = { 257 .name = "imx_usb", 258 .owner = THIS_MODULE, 259 .of_match_table = ci13xxx_imx_dt_ids, 260 }, 261}; 262 263module_platform_driver(ci13xxx_imx_driver); 264 265MODULE_ALIAS("platform:imx-usb"); 266MODULE_LICENSE("GPL v2"); 267MODULE_DESCRIPTION("CI13xxx i.MX USB binding"); 268MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); 269MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");