#define DBG(stuff...) do {} while (0)
#endif
-struct tegra_otg_data {
+struct tegra_otg {
struct platform_device *pdev;
struct tegra_usb_otg_data *pdata;
struct usb_phy phy;
struct extcon_dev *vbus_extcon_dev;
};
-static struct tegra_otg_data *tegra_clone;
+static struct tegra_otg *tegra_clone;
static struct notifier_block otg_vbus_nb;
static struct notifier_block otg_id_nb;
struct extcon_specific_cable_nb *extcondev;
static int otg_notifications(struct notifier_block *nb,
unsigned long event, void *unused)
{
- struct tegra_otg_data *tegra = tegra_clone;
+ struct tegra_otg *tegra = tegra_clone;
unsigned long flags;
DBG("%s(%d) Begin\n", __func__, __LINE__);
return NOTIFY_DONE;
}
-void check_host_cable_connection(struct tegra_otg_data *tegra)
+void check_host_cable_connection(struct tegra_otg *tegra)
{
unsigned long flags;
bool id_present;
static irqreturn_t tegra_otg_id_detect_gpio_thr(int irq, void *data)
{
- struct tegra_otg_data *tegra = data;
+ struct tegra_otg *tegra = data;
check_host_cable_connection(tegra);
return IRQ_HANDLED;
}
-static inline unsigned long otg_readl(struct tegra_otg_data *tegra,
+static inline unsigned long otg_readl(struct tegra_otg *tegra,
unsigned int offset)
{
return readl(tegra->regs + offset);
}
-static inline void otg_writel(struct tegra_otg_data *tegra, unsigned long val,
+static inline void otg_writel(struct tegra_otg *tegra, unsigned long val,
unsigned int offset)
{
writel(val, tegra->regs + offset);
}
}
-static unsigned long enable_interrupt(struct tegra_otg_data *tegra, bool en)
+static unsigned long enable_interrupt(struct tegra_otg *tegra, bool en)
{
unsigned long val;
return val;
}
-static void tegra_start_host(struct tegra_otg_data *tegra)
+static void tegra_start_host(struct tegra_otg *tegra)
{
struct tegra_usb_otg_data *pdata = tegra->pdata;
struct platform_device *pdev, *ehci_device = pdata->ehci_device;
tegra->pdev = NULL;
}
-static void tegra_stop_host(struct tegra_otg_data *tegra)
+static void tegra_stop_host(struct tegra_otg *tegra)
{
struct platform_device *pdev = tegra->pdev;
DBG("%s(%d) End\n", __func__, __LINE__);
}
-static void tegra_otg_notify_event(struct tegra_otg_data *tegra, int event)
+static void tegra_otg_notify_event(struct tegra_otg *tegra, int event)
{
tegra->phy.last_event = event;
atomic_notifier_call_chain(&tegra->phy.notifier, event, tegra->phy.otg->gadget);
}
-static void tegra_change_otg_state(struct tegra_otg_data *tegra,
+static void tegra_change_otg_state(struct tegra_otg *tegra,
enum usb_otg_state to)
{
struct usb_otg *otg = tegra->phy.otg;
static void irq_work(struct work_struct *work)
{
- struct tegra_otg_data *tegra =
- container_of(work, struct tegra_otg_data, work);
+ struct tegra_otg *tegra =
+ container_of(work, struct tegra_otg, work);
struct usb_otg *otg = tegra->phy.otg;
enum usb_otg_state from;
enum usb_otg_state to = OTG_STATE_UNDEFINED;
static irqreturn_t tegra_otg_irq(int irq, void *data)
{
- struct tegra_otg_data *tegra = data;
+ struct tegra_otg *tegra = data;
unsigned long flags;
unsigned long val;
static int tegra_otg_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
- struct tegra_otg_data *tegra;
+ struct tegra_otg *tegra;
unsigned long val;
DBG("%s(%d) BEGIN\n", __func__, __LINE__);
- tegra = (struct tegra_otg_data *)container_of(otg->phy, struct tegra_otg_data, phy);
+ tegra = (struct tegra_otg *)container_of(otg->phy, struct tegra_otg, phy);
otg->gadget = gadget;
val = enable_interrupt(tegra, true);
static int tegra_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct tegra_otg_data *tegra = container_of(otg->phy, struct tegra_otg_data, phy);
+ struct tegra_otg *tegra = container_of(otg->phy, struct tegra_otg, phy);
unsigned long val;
DBG("%s(%d) BEGIN\n", __func__, __LINE__);
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
- struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ struct tegra_otg *tegra = platform_get_drvdata(pdev);
*buf = tegra->interrupt_mode ? '0': '1';
strcat(buf, "\n");
const char *buf, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
- struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ struct tegra_otg *tegra = platform_get_drvdata(pdev);
int host;
if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1)
return 0;
}
-void tegra_otg_set_id_detection_type(struct tegra_otg_data *tegra)
+void tegra_otg_set_id_detection_type(struct tegra_otg *tegra)
{
switch (tegra->pdata->ehci_pdata->id_det_type) {
case TEGRA_USB_ID:
tegra->support_usb_id = false;
break;
default:
- pr_info("otg detection method is unknown\n");
+ pr_info("otg usb id detection type is unknown\n");
break;
}
}
-static int tegra_otg_probe(struct platform_device *pdev)
+static int tegra_otg_conf(struct platform_device *pdev)
{
- struct tegra_otg_data *tegra;
- struct resource *res;
struct tegra_usb_otg_data *pdata = dev_get_platdata(&pdev->dev);
+ struct tegra_otg *tegra;
int err;
- tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_otg_data), GFP_KERNEL);
- if (!tegra)
+ if (!pdata) {
+ dev_err(&pdev->dev, "unable to get platform data\n");
+ return -ENODEV;
+ }
+
+ tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_otg), GFP_KERNEL);
+ if (!tegra) {
+ dev_err(&pdev->dev, "unable to allocate tegra_otg\n");
return -ENOMEM;
+ }
tegra->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), GFP_KERNEL);
if (!tegra->phy.otg) {
spin_lock_init(&tegra->lock);
mutex_init(&tegra->irq_work_mutex);
- if (pdata) {
- tegra->support_pmu_vbus = pdata->ehci_pdata->support_pmu_vbus;
- tegra->id_det_gpio = pdata->id_det_gpio ?
- pdata->id_det_gpio : -1;
- tegra->pdata = pdata;
- tegra_otg_set_id_detection_type(tegra);
- }
+ INIT_WORK(&tegra->work, irq_work);
platform_set_drvdata(pdev, tegra);
tegra_clone = tegra;
+
tegra->interrupt_mode = true;
tegra->suspended = false;
+ tegra->support_pmu_vbus = pdata->ehci_pdata->support_pmu_vbus;
+ tegra->id_det_gpio = pdata->id_det_gpio ? pdata->id_det_gpio : -1;
+ tegra->pdata = pdata;
+ tegra_otg_set_id_detection_type(tegra);
+
+ tegra->phy.dev = &pdev->dev;
+ tegra->phy.label = "tegra-otg";
+ tegra->phy.set_suspend = tegra_otg_set_suspend;
+ tegra->phy.set_power = tegra_otg_set_power;
+ tegra->phy.state = OTG_STATE_A_SUSPEND;
+ tegra->phy.otg->phy = &tegra->phy;
+ tegra->phy.otg->set_host = tegra_otg_set_host;
+ tegra->phy.otg->set_peripheral = tegra_otg_set_peripheral;
+
+ if (tegra->support_pmu_vbus) {
+ if (!pdata->vbus_extcon_dev_name) {
+ dev_err(&pdev->dev, "Missing vbus_extcon_dev_name!\n");
+ err = -EINVAL;
+ goto err_vbus_extcon;
+ }
+ tegra->vbus_extcon_dev =
+ extcon_get_extcon_dev(pdata->vbus_extcon_dev_name);
+ if (!tegra->vbus_extcon_dev) {
+ dev_err(&pdev->dev, "Cannot get the %s extcon dev\n",
+ pdata->vbus_extcon_dev_name);
+ err = -ENODEV;
+ goto err_vbus_extcon;
+ }
+ otg_vbus_nb.notifier_call = otg_notifications;
+ extcon_register_notifier(tegra->vbus_extcon_dev, &otg_vbus_nb);
+ }
+
+ if (tegra->support_pmu_id) {
+ if (!pdata->id_extcon_dev_name) {
+ dev_err(&pdev->dev, "Missing id_extcon_dev_name!\n");
+ err = -EINVAL;
+ goto err_id_extcon;
+ }
+ tegra->id_extcon_dev =
+ extcon_get_extcon_dev(pdata->id_extcon_dev_name);
+ if (!tegra->id_extcon_dev) {
+ dev_err(&pdev->dev, "Cannot get the %s extcon dev\n",
+ pdata->id_extcon_dev_name);
+ err = -ENODEV;
+ goto err_id_extcon;
+ }
+ otg_id_nb.notifier_call = otg_notifications;
+ extcon_register_notifier(tegra->id_extcon_dev, &otg_id_nb);
+ }
+
+ err = usb_add_phy(&tegra->phy, USB_PHY_TYPE_USB2);
+ if (err) {
+ dev_err(&pdev->dev, "usb_set_transceiver failed\n");
+ goto err_set_trans;
+ }
+
+ return 0;
+err_set_trans:
+ if (tegra->support_pmu_id)
+ extcon_unregister_notifier(tegra->id_extcon_dev,
+ &otg_id_nb);
+err_id_extcon:
+ if (tegra->support_pmu_vbus)
+ extcon_unregister_notifier(tegra->vbus_extcon_dev,
+ &otg_vbus_nb);
+err_vbus_extcon:
+ return err;
+}
+static int tegra_otg_start(struct platform_device *pdev)
+{
+ struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
+ struct tegra_otg *tegra;
+ struct resource *res;
+ int err;
+
+ tegra = container_of(otg_trans, struct tegra_otg, phy);
tegra->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(tegra->clk)) {
- dev_err(&pdev->dev, "Can't get otg clock\n");
+ dev_err(&pdev->dev, "Failed to get otg clock\n");
err = PTR_ERR(tegra->clk);
goto err_clk;
}
err = -ENXIO;
goto err_io;
}
+
tegra->regs = ioremap(res->start, resource_size(res));
if (!tegra->regs) {
err = -ENOMEM;
err = -ENXIO;
goto err_irq;
}
+
tegra->irq = res->start;
err = devm_request_threaded_irq(&pdev->dev, tegra->irq, tegra_otg_irq,
NULL,
goto err_irq;
}
+ err = enable_irq_wake(tegra->irq);
+ if (err < 0) {
+ dev_warn(&pdev->dev,
+ "Couldn't enable USB otg mode wakeup, irq=%d, error=%d\n",
+ tegra->irq, err);
+ err = 0;
+ }
+
if (tegra->support_gpio_id && gpio_is_valid(tegra->id_det_gpio)) {
err = gpio_request(tegra->id_det_gpio, "id_det_gpio");
if (err) {
dev_err(&pdev->dev,
"failed to allocate id_det_gpio\n");
+ goto err_id_gpio_req;
}
gpio_direction_input(tegra->id_det_gpio);
IRQF_TRIGGER_RISING, "tegra-otg", tegra);
if (err) {
dev_err(&pdev->dev, "request irq error\n");
- goto err_id_irq_req;
+ goto err_id_gpio_irq;
}
err = enable_irq_wake(gpio_to_irq(tegra->id_det_gpio));
if (err < 0)
- dev_err(&pdev->dev,
+ dev_warn(&pdev->dev,
"ID wake-up event failed with error %d\n", err);
}
- err = enable_irq_wake(tegra->irq);
- if (err < 0) {
- dev_warn(&pdev->dev,
- "Couldn't enable USB otg mode wakeup, irq=%d, error=%d\n",
- tegra->irq, err);
- err = 0;
- }
+ return 0;
+err_id_gpio_irq:
+ if (gpio_is_valid(tegra->id_det_gpio))
+ gpio_free(tegra->id_det_gpio);
+err_id_gpio_req:
+err_irq:
+ iounmap(tegra->regs);
+err_io:
+ clk_put(tegra->clk);
+err_clk:
+ return err;
+}
- INIT_WORK(&tegra->work, irq_work);
+static int tegra_otg_probe(struct platform_device *pdev)
+{
+ struct tegra_otg *tegra;
+ int err = 0;
- tegra->phy.dev = &pdev->dev;
- tegra->phy.label = "tegra-otg";
- tegra->phy.otg->set_host = tegra_otg_set_host;
- tegra->phy.otg->set_peripheral = tegra_otg_set_peripheral;
- tegra->phy.set_suspend = tegra_otg_set_suspend;
- tegra->phy.set_power = tegra_otg_set_power;
- tegra->phy.state = OTG_STATE_A_SUSPEND;
- tegra->phy.otg->phy = &tegra->phy;
+ err = tegra_otg_conf(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "otg configuration failed\n");
+ goto err;
+ }
- err = usb_add_phy(&tegra->phy, USB_PHY_TYPE_USB2);
+ err = tegra_otg_start(pdev);
if (err) {
- dev_err(&pdev->dev, "usb_set_transceiver failed\n");
- goto err_clk;
+ dev_err(&pdev->dev, "otg start failed\n");
+ goto err;
}
+ tegra = tegra_clone;
if (!tegra->support_usb_id && !tegra->support_pmu_id
&& !tegra->support_gpio_id) {
err = device_create_file(&pdev->dev, &dev_attr_enable_host);
if (err) {
dev_warn(&pdev->dev, "Can't register sysfs attribute\n");
- goto err_irq;
- }
- }
-
- if (tegra->support_pmu_vbus) {
- if (!pdata->vbus_extcon_dev_name) {
- dev_err(&pdev->dev, "Missing vbus_extcon_dev_name!\n");
- err = -EINVAL;
- goto err_vbus_extcon;
- }
- tegra->vbus_extcon_dev =
- extcon_get_extcon_dev(pdata->vbus_extcon_dev_name);
- if (!tegra->vbus_extcon_dev) {
- dev_err(&pdev->dev, "Cannot get the %s extcon dev\n",
- pdata->vbus_extcon_dev_name);
- err = -ENODEV;
- goto err_vbus_extcon;
- }
- otg_vbus_nb.notifier_call = otg_notifications;
- extcon_register_notifier(tegra->vbus_extcon_dev, &otg_vbus_nb);
- }
-
- if (tegra->support_pmu_id) {
- if (!pdata->id_extcon_dev_name) {
- dev_err(&pdev->dev, "Missing id_extcon_dev_name!\n");
- err = -EINVAL;
- goto err_id_extcon;
- }
- tegra->id_extcon_dev =
- extcon_get_extcon_dev(pdata->id_extcon_dev_name);
- if (!tegra->id_extcon_dev) {
- dev_err(&pdev->dev, "Cannot get the %s extcon dev\n",
- pdata->id_extcon_dev_name);
- err = -ENODEV;
- goto err_id_extcon;
+ goto err;
}
- otg_id_nb.notifier_call = otg_notifications;
- extcon_register_notifier(tegra->id_extcon_dev, &otg_id_nb);
}
tegra_pd_add_device(tegra->phy.dev);
pm_runtime_enable(tegra->phy.dev);
dev_info(&pdev->dev, "otg transceiver registered\n");
- return 0;
-
-err_id_extcon:
- if (tegra->support_pmu_vbus)
- extcon_unregister_notifier(tegra->vbus_extcon_dev,
- &otg_vbus_nb);
-err_vbus_extcon:
-err_irq:
- usb_remove_phy(&tegra->phy);
- iounmap(tegra->regs);
-err_io:
- clk_put(tegra->clk);
-err_id_irq_req:
- if (gpio_is_valid(tegra->id_det_gpio))
- gpio_free(tegra->id_det_gpio);
-err_clk:
- if (gpio_is_valid(tegra->id_det_gpio))
- free_irq(gpio_to_irq(tegra->id_det_gpio), tegra);
+err:
return err;
}
static int __exit tegra_otg_remove(struct platform_device *pdev)
{
- struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ struct tegra_otg *tegra = platform_get_drvdata(pdev);
if (tegra->support_gpio_id && gpio_is_valid(tegra->id_det_gpio)) {
free_irq(gpio_to_irq(tegra->id_det_gpio), tegra);
static int tegra_otg_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ struct tegra_otg *tegra = platform_get_drvdata(pdev);
struct usb_phy *phy = &tegra->phy;
enum usb_otg_state from = phy->otg->phy->state;
unsigned int val;
static void tegra_otg_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
+ struct tegra_otg *tegra = platform_get_drvdata(pdev);
int val;
unsigned long flags;