Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
host.c
Go to the documentation of this file.
1 /*
2  * host.c - ChipIdea USB host controller driver
3  *
4  * Copyright (c) 2012 Intel Corporation
5  *
6  * Author: Alexander Shishkin
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
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/kernel.h>
23 #include <linux/usb.h>
24 #include <linux/usb/hcd.h>
25 #include <linux/usb/chipidea.h>
26 
27 #define CHIPIDEA_EHCI
28 #include "../host/ehci-hcd.c"
29 
30 #include "ci.h"
31 #include "bits.h"
32 #include "host.h"
33 
34 static int ci_ehci_setup(struct usb_hcd *hcd)
35 {
36  struct ehci_hcd *ehci = hcd_to_ehci(hcd);
37  int ret;
38 
39  hcd->has_tt = 1;
40 
41  ret = ehci_setup(hcd);
42  if (ret)
43  return ret;
44 
45  ehci_port_power(ehci, 0);
46 
47  return ret;
48 }
49 
50 static const struct hc_driver ci_ehci_hc_driver = {
51  .description = "ehci_hcd",
52  .product_desc = "ChipIdea HDRC EHCI",
53  .hcd_priv_size = sizeof(struct ehci_hcd),
54 
55  /*
56  * generic hardware linkage
57  */
58  .irq = ehci_irq,
59  .flags = HCD_MEMORY | HCD_USB2,
60 
61  /*
62  * basic lifecycle operations
63  */
64  .reset = ci_ehci_setup,
65  .start = ehci_run,
66  .stop = ehci_stop,
67  .shutdown = ehci_shutdown,
68 
69  /*
70  * managing i/o requests and associated device resources
71  */
72  .urb_enqueue = ehci_urb_enqueue,
73  .urb_dequeue = ehci_urb_dequeue,
74  .endpoint_disable = ehci_endpoint_disable,
75  .endpoint_reset = ehci_endpoint_reset,
76 
77  /*
78  * scheduling support
79  */
80  .get_frame_number = ehci_get_frame,
81 
82  /*
83  * root hub support
84  */
85  .hub_status_data = ehci_hub_status_data,
86  .hub_control = ehci_hub_control,
87  .bus_suspend = ehci_bus_suspend,
88  .bus_resume = ehci_bus_resume,
89  .relinquish_port = ehci_relinquish_port,
90  .port_handed_over = ehci_port_handed_over,
91 
92  .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
93 };
94 
95 static irqreturn_t host_irq(struct ci13xxx *ci)
96 {
97  return usb_hcd_irq(ci->irq, ci->hcd);
98 }
99 
100 static int host_start(struct ci13xxx *ci)
101 {
102  struct usb_hcd *hcd;
103  struct ehci_hcd *ehci;
104  int ret;
105 
106  if (usb_disabled())
107  return -ENODEV;
108 
109  hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
110  if (!hcd)
111  return -ENOMEM;
112 
113  dev_set_drvdata(ci->dev, ci);
114  hcd->rsrc_start = ci->hw_bank.phys;
115  hcd->rsrc_len = ci->hw_bank.size;
116  hcd->regs = ci->hw_bank.abs;
117  hcd->has_tt = 1;
118 
119  hcd->power_budget = ci->platdata->power_budget;
120  hcd->phy = ci->transceiver;
121 
122  ehci = hcd_to_ehci(hcd);
123  ehci->caps = ci->hw_bank.cap;
124  ehci->has_hostpc = ci->hw_bank.lpm;
125 
126  ret = usb_add_hcd(hcd, 0, 0);
127  if (ret)
128  usb_put_hcd(hcd);
129  else
130  ci->hcd = hcd;
131 
132  return ret;
133 }
134 
135 static void host_stop(struct ci13xxx *ci)
136 {
137  struct usb_hcd *hcd = ci->hcd;
138 
139  usb_remove_hcd(hcd);
140  usb_put_hcd(hcd);
141 }
142 
143 int ci_hdrc_host_init(struct ci13xxx *ci)
144 {
145  struct ci_role_driver *rdrv;
146 
147  if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC))
148  return -ENXIO;
149 
150  rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
151  if (!rdrv)
152  return -ENOMEM;
153 
154  rdrv->start = host_start;
155  rdrv->stop = host_stop;
156  rdrv->irq = host_irq;
157  rdrv->name = "host";
158  ci->roles[CI_ROLE_HOST] = rdrv;
159 
160  return 0;
161 }