Commit | Line | Data |
---|---|---|
5b9974b1 MK |
1 | /* |
2 | * platform.c - DesignWare HS OTG Controller platform driver | |
3 | * | |
4 | * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl> | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions, and the following disclaimer, | |
11 | * without modification. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. The names of the above-listed copyright holders may not be used | |
16 | * to endorse or promote products derived from this software without | |
17 | * specific prior written permission. | |
18 | * | |
19 | * ALTERNATIVELY, this software may be distributed under the terms of the | |
20 | * GNU General Public License ("GPL") as published by the Free Software | |
21 | * Foundation; either version 2 of the License, or (at your option) any | |
22 | * later version. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
25 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
26 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
27 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
28 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
29 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
30 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
31 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
32 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
35 | */ | |
36 | ||
37 | #include <linux/kernel.h> | |
38 | #include <linux/module.h> | |
39 | #include <linux/slab.h> | |
40 | #include <linux/device.h> | |
41 | #include <linux/dma-mapping.h> | |
831eae69 | 42 | #include <linux/of_device.h> |
5b9974b1 MK |
43 | #include <linux/platform_device.h> |
44 | ||
45 | #include "core.h" | |
46 | #include "hcd.h" | |
47 | ||
48 | static const char dwc2_driver_name[] = "dwc2"; | |
49 | ||
831eae69 SW |
50 | static const struct dwc2_core_params params_bcm2835 = { |
51 | .otg_cap = 0, /* HNP/SRP capable */ | |
52 | .otg_ver = 0, /* 1.3 */ | |
53 | .dma_enable = 1, | |
54 | .dma_desc_enable = 0, | |
55 | .speed = 0, /* High Speed */ | |
56 | .enable_dynamic_fifo = 1, | |
57 | .en_multiple_tx_fifo = 1, | |
58 | .host_rx_fifo_size = 774, /* 774 DWORDs */ | |
59 | .host_nperio_tx_fifo_size = 256, /* 256 DWORDs */ | |
60 | .host_perio_tx_fifo_size = 512, /* 512 DWORDs */ | |
61 | .max_transfer_size = 65535, | |
62 | .max_packet_count = 511, | |
63 | .host_channels = 8, | |
64 | .phy_type = 1, /* UTMI */ | |
65 | .phy_utmi_width = 8, /* 8 bits */ | |
66 | .phy_ulpi_ddr = 0, /* Single */ | |
67 | .phy_ulpi_ext_vbus = 0, | |
68 | .i2c_enable = 0, | |
69 | .ulpi_fs_ls = 0, | |
70 | .host_support_fs_ls_low_power = 0, | |
71 | .host_ls_low_power_phy_clk = 0, /* 48 MHz */ | |
72 | .ts_dline = 0, | |
73 | .reload_ctl = 0, | |
74 | .ahbcfg = 0x10, | |
58b179dc | 75 | .uframe_sched = 0, |
831eae69 SW |
76 | }; |
77 | ||
5b9974b1 MK |
78 | /** |
79 | * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the | |
80 | * DWC_otg driver | |
81 | * | |
82 | * @dev: Platform device | |
83 | * | |
84 | * This routine is called, for example, when the rmmod command is executed. The | |
85 | * device may or may not be electrically present. If it is present, the driver | |
86 | * stops device processing. Any resources used on behalf of this device are | |
87 | * freed. | |
88 | */ | |
89 | static int dwc2_driver_remove(struct platform_device *dev) | |
90 | { | |
91 | struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); | |
92 | ||
93 | dwc2_hcd_remove(hsotg); | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
831eae69 SW |
98 | static const struct of_device_id dwc2_of_match_table[] = { |
99 | { .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 }, | |
100 | { .compatible = "snps,dwc2", .data = NULL }, | |
101 | {}, | |
102 | }; | |
103 | MODULE_DEVICE_TABLE(of, dwc2_of_match_table); | |
104 | ||
5b9974b1 MK |
105 | /** |
106 | * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg | |
107 | * driver | |
108 | * | |
109 | * @dev: Platform device | |
110 | * | |
111 | * This routine creates the driver components required to control the device | |
112 | * (core, HCD, and PCD) and initializes the device. The driver components are | |
113 | * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved | |
114 | * in the device private data. This allows the driver to access the dwc2_hsotg | |
115 | * structure on subsequent calls to driver methods for this device. | |
116 | */ | |
117 | static int dwc2_driver_probe(struct platform_device *dev) | |
118 | { | |
831eae69 SW |
119 | const struct of_device_id *match; |
120 | const struct dwc2_core_params *params; | |
121 | struct dwc2_core_params defparams; | |
5b9974b1 MK |
122 | struct dwc2_hsotg *hsotg; |
123 | struct resource *res; | |
124 | int retval; | |
125 | int irq; | |
5b9974b1 | 126 | |
861e0f5b AH |
127 | if (usb_disabled()) |
128 | return -ENODEV; | |
129 | ||
831eae69 SW |
130 | match = of_match_device(dwc2_of_match_table, &dev->dev); |
131 | if (match && match->data) { | |
132 | params = match->data; | |
133 | } else { | |
134 | /* Default all params to autodetect */ | |
135 | dwc2_set_all_params(&defparams, -1); | |
136 | params = &defparams; | |
137 | } | |
5b9974b1 MK |
138 | |
139 | hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL); | |
140 | if (!hsotg) | |
141 | return -ENOMEM; | |
142 | ||
143 | hsotg->dev = &dev->dev; | |
144 | ||
642f2ecc MK |
145 | /* |
146 | * Use reasonable defaults so platforms don't have to provide these. | |
147 | */ | |
148 | if (!dev->dev.dma_mask) | |
149 | dev->dev.dma_mask = &dev->dev.coherent_dma_mask; | |
4cdbb4ff RK |
150 | retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32)); |
151 | if (retval) | |
152 | return retval; | |
642f2ecc | 153 | |
5b9974b1 MK |
154 | irq = platform_get_irq(dev, 0); |
155 | if (irq < 0) { | |
156 | dev_err(&dev->dev, "missing IRQ resource\n"); | |
097f2612 | 157 | return irq; |
5b9974b1 MK |
158 | } |
159 | ||
160 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | |
5b9974b1 MK |
161 | hsotg->regs = devm_ioremap_resource(&dev->dev, res); |
162 | if (IS_ERR(hsotg->regs)) | |
163 | return PTR_ERR(hsotg->regs); | |
164 | ||
165 | dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n", | |
166 | (unsigned long)res->start, hsotg->regs); | |
167 | ||
831eae69 | 168 | retval = dwc2_hcd_init(hsotg, irq, params); |
5b9974b1 MK |
169 | if (retval) |
170 | return retval; | |
171 | ||
172 | platform_set_drvdata(dev, hsotg); | |
173 | ||
174 | return retval; | |
175 | } | |
176 | ||
5b9974b1 MK |
177 | static struct platform_driver dwc2_platform_driver = { |
178 | .driver = { | |
1c126bc6 | 179 | .name = dwc2_driver_name, |
5b9974b1 MK |
180 | .of_match_table = dwc2_of_match_table, |
181 | }, | |
182 | .probe = dwc2_driver_probe, | |
183 | .remove = dwc2_driver_remove, | |
184 | }; | |
185 | ||
186 | module_platform_driver(dwc2_platform_driver); | |
187 | ||
188 | MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue"); | |
189 | MODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>"); | |
190 | MODULE_LICENSE("Dual BSD/GPL"); |