static int __devexit usbhs_remove(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback; dev_dbg(&pdev->dev, "usb remove\n"); dfunc->notify_hotplug = NULL; /* power off */ if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) usbhsc_power_ctrl(priv, 0); pm_runtime_disable(&pdev->dev); usbhs_platform_call(priv, hardware_exit, pdev); usbhs_mod_remove(priv); usbhs_fifo_remove(priv); usbhs_pipe_remove(priv); iounmap(priv->base); kfree(priv); return 0; }
/* * platform functions */ static int usbhs_probe(struct platform_device *pdev) { struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev); struct renesas_usbhs_driver_callback *dfunc; struct usbhs_priv *priv; struct resource *res, *irq_res; int ret; /* check platform information */ if (!info) { dev_err(&pdev->dev, "no platform information\n"); return -EINVAL; } /* platform data */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res || !irq_res) { dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n"); return -ENODEV; } /* usb private data */ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "Could not allocate priv\n"); return -ENOMEM; } priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); /* * care platform info */ memcpy(&priv->dparam, &info->driver_param, sizeof(struct renesas_usbhs_driver_param)); switch (priv->dparam.type) { case USBHS_TYPE_R8A7790: case USBHS_TYPE_R8A7791: priv->pfunc = usbhs_rcar2_ops; if (!priv->dparam.pipe_type) { priv->dparam.pipe_type = usbhsc_new_pipe_type; priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe_type); } break; default: if (!info->platform_callback.get_id) { dev_err(&pdev->dev, "no platform callbacks"); return -EINVAL; } memcpy(&priv->pfunc, &info->platform_callback, sizeof(struct renesas_usbhs_platform_callback)); break; } /* set driver callback functions for platform */ dfunc = &info->driver_callback; dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug; /* set default param if platform doesn't have */ if (!priv->dparam.pipe_type) { priv->dparam.pipe_type = usbhsc_default_pipe_type; priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); } if (!priv->dparam.pio_dma_border) priv->dparam.pio_dma_border = 64; /* 64byte */ /* FIXME */ /* runtime power control ? */ if (priv->pfunc.get_vbus) usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL); /* * priv settings */ priv->irq = irq_res->start; if (irq_res->flags & IORESOURCE_IRQ_SHAREABLE) priv->irqflags = IRQF_SHARED; priv->pdev = pdev; INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); spin_lock_init(usbhs_priv_to_lock(priv)); /* call pipe and module init */ ret = usbhs_pipe_probe(priv); if (ret < 0) return ret; ret = usbhs_fifo_probe(priv); if (ret < 0) goto probe_end_pipe_exit; ret = usbhs_mod_probe(priv); if (ret < 0) goto probe_end_fifo_exit; /* dev_set_drvdata should be called after usbhs_mod_init */ platform_set_drvdata(pdev, priv); /* * deviece reset here because * USB device might be used in boot loader. */ usbhs_sys_clock_ctrl(priv, 0); /* check GPIO determining if USB function should be enabled */ if (priv->dparam.enable_gpio) { gpio_request_one(priv->dparam.enable_gpio, GPIOF_IN, NULL); ret = !gpio_get_value(priv->dparam.enable_gpio); gpio_free(priv->dparam.enable_gpio); if (ret) { dev_warn(&pdev->dev, "USB function not selected (GPIO %d)\n", priv->dparam.enable_gpio); ret = -ENOTSUPP; goto probe_end_mod_exit; } } /* * platform call * * USB phy setup might depend on CPU/Board. * If platform has its callback functions, * call it here. */ ret = usbhs_platform_call(priv, hardware_init, pdev); if (ret < 0) { dev_err(&pdev->dev, "platform prove failed.\n"); goto probe_end_mod_exit; } /* reset phy for connection */ usbhs_platform_call(priv, phy_reset, pdev); /* power control */ pm_runtime_enable(&pdev->dev); if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) { usbhsc_power_ctrl(priv, 1); usbhs_mod_autonomy_mode(priv); } /* * manual call notify_hotplug for cold plug */ ret = usbhsc_drvcllbck_notify_hotplug(pdev); if (ret < 0) goto probe_end_call_remove; dev_info(&pdev->dev, "probed\n"); return ret; probe_end_call_remove: usbhs_platform_call(priv, hardware_exit, pdev); probe_end_mod_exit: usbhs_mod_remove(priv); probe_end_fifo_exit: usbhs_fifo_remove(priv); probe_end_pipe_exit: usbhs_pipe_remove(priv); dev_info(&pdev->dev, "probe failed\n"); return ret; }
/* * platform functions */ static int __devinit usbhs_probe(struct platform_device *pdev) { struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; struct renesas_usbhs_driver_callback *dfunc; struct usbhs_priv *priv; struct resource *res; unsigned int irq; int ret; /* check platform information */ if (!info || !info->platform_callback.get_id) { dev_err(&pdev->dev, "no platform information\n"); return -EINVAL; } /* platform data */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!res || (int)irq <= 0) { dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n"); return -ENODEV; } /* usb private data */ priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "Could not allocate priv\n"); return -ENOMEM; } priv->base = ioremap_nocache(res->start, resource_size(res)); if (!priv->base) { dev_err(&pdev->dev, "ioremap error.\n"); ret = -ENOMEM; goto probe_end_kfree; } /* * care platform info */ priv->pfunc = &info->platform_callback; priv->dparam = &info->driver_param; /* set driver callback functions for platform */ dfunc = &info->driver_callback; dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug; /* set default param if platform doesn't have */ if (!priv->dparam->pipe_type) { priv->dparam->pipe_type = usbhsc_default_pipe_type; priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); } if (!priv->dparam->pio_dma_border) priv->dparam->pio_dma_border = 64; /* 64byte */ /* FIXME */ /* runtime power control ? */ if (priv->pfunc->get_vbus) usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL); /* * priv settings */ priv->irq = irq; priv->pdev = pdev; INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); spin_lock_init(usbhs_priv_to_lock(priv)); /* call pipe and module init */ ret = usbhs_pipe_probe(priv); if (ret < 0) goto probe_end_iounmap; ret = usbhs_fifo_probe(priv); if (ret < 0) goto probe_end_pipe_exit; ret = usbhs_mod_probe(priv); if (ret < 0) goto probe_end_fifo_exit; /* dev_set_drvdata should be called after usbhs_mod_init */ dev_set_drvdata(&pdev->dev, priv); /* * deviece reset here because * USB device might be used in boot loader. */ usbhs_sys_clock_ctrl(priv, 0); /* * platform call * * USB phy setup might depend on CPU/Board. * If platform has its callback functions, * call it here. */ ret = usbhs_platform_call(priv, hardware_init, pdev); if (ret < 0) { dev_err(&pdev->dev, "platform prove failed.\n"); goto probe_end_mod_exit; } /* reset phy for connection */ usbhs_platform_call(priv, phy_reset, pdev); /* power control */ pm_runtime_enable(&pdev->dev); if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) { usbhsc_power_ctrl(priv, 1); usbhs_mod_autonomy_mode(priv); } /* * manual call notify_hotplug for cold plug */ ret = usbhsc_drvcllbck_notify_hotplug(pdev); if (ret < 0) goto probe_end_call_remove; dev_info(&pdev->dev, "probed\n"); return ret; probe_end_call_remove: usbhs_platform_call(priv, hardware_exit, pdev); probe_end_mod_exit: usbhs_mod_remove(priv); probe_end_fifo_exit: usbhs_fifo_remove(priv); probe_end_pipe_exit: usbhs_pipe_remove(priv); probe_end_iounmap: iounmap(priv->base); probe_end_kfree: kfree(priv); dev_info(&pdev->dev, "probe failed\n"); return ret; }