diff options
Diffstat (limited to 'arch/arm/mach-imx/mx31moboard-marxbot.c')
-rw-r--r-- | arch/arm/mach-imx/mx31moboard-marxbot.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/mx31moboard-marxbot.c b/arch/arm/mach-imx/mx31moboard-marxbot.c new file mode 100644 index 000000000000..bb639cbda4e5 --- /dev/null +++ b/arch/arm/mach-imx/mx31moboard-marxbot.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/gpio.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/spi/spi.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | #include <linux/usb/otg.h> | ||
26 | |||
27 | #include <mach/common.h> | ||
28 | #include <mach/hardware.h> | ||
29 | #include <mach/iomux-mx3.h> | ||
30 | #include <mach/ulpi.h> | ||
31 | |||
32 | #include <media/soc_camera.h> | ||
33 | |||
34 | #include "devices-imx31.h" | ||
35 | |||
36 | static unsigned int marxbot_pins[] = { | ||
37 | /* SDHC2 */ | ||
38 | MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2, | ||
39 | MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0, | ||
40 | MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD, | ||
41 | MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29, | ||
42 | /* CSI */ | ||
43 | MX31_PIN_CSI_D6__CSI_D6, MX31_PIN_CSI_D7__CSI_D7, | ||
44 | MX31_PIN_CSI_D8__CSI_D8, MX31_PIN_CSI_D9__CSI_D9, | ||
45 | MX31_PIN_CSI_D10__CSI_D10, MX31_PIN_CSI_D11__CSI_D11, | ||
46 | MX31_PIN_CSI_D12__CSI_D12, MX31_PIN_CSI_D13__CSI_D13, | ||
47 | MX31_PIN_CSI_D14__CSI_D14, MX31_PIN_CSI_D15__CSI_D15, | ||
48 | MX31_PIN_CSI_HSYNC__CSI_HSYNC, MX31_PIN_CSI_MCLK__CSI_MCLK, | ||
49 | MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, MX31_PIN_CSI_VSYNC__CSI_VSYNC, | ||
50 | MX31_PIN_CSI_D4__GPIO3_4, MX31_PIN_CSI_D5__GPIO3_5, | ||
51 | MX31_PIN_GPIO3_0__GPIO3_0, MX31_PIN_GPIO3_1__GPIO3_1, | ||
52 | MX31_PIN_TXD2__GPIO1_28, | ||
53 | /* dsPIC resets */ | ||
54 | MX31_PIN_STXD5__GPIO1_21, MX31_PIN_SRXD5__GPIO1_22, | ||
55 | /*battery detection */ | ||
56 | MX31_PIN_LCS0__GPIO3_23, | ||
57 | /* USB H1 */ | ||
58 | MX31_PIN_CSPI1_MISO__USBH1_RXDP, MX31_PIN_CSPI1_MOSI__USBH1_RXDM, | ||
59 | MX31_PIN_CSPI1_SS0__USBH1_TXDM, MX31_PIN_CSPI1_SS1__USBH1_TXDP, | ||
60 | MX31_PIN_CSPI1_SS2__USBH1_RCV, MX31_PIN_CSPI1_SCLK__USBH1_OEB, | ||
61 | MX31_PIN_CSPI1_SPI_RDY__USBH1_FS, MX31_PIN_SFS6__USBH1_SUSPEND, | ||
62 | MX31_PIN_NFRE_B__GPIO1_11, MX31_PIN_NFALE__GPIO1_12, | ||
63 | /* SEL */ | ||
64 | MX31_PIN_DTR_DCE1__GPIO2_8, MX31_PIN_DSR_DCE1__GPIO2_9, | ||
65 | MX31_PIN_RI_DCE1__GPIO2_10, MX31_PIN_DCD_DCE1__GPIO2_11, | ||
66 | }; | ||
67 | |||
68 | #define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR) | ||
69 | #define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW) | ||
70 | |||
71 | static int marxbot_sdhc2_get_ro(struct device *dev) | ||
72 | { | ||
73 | return !gpio_get_value(SDHC2_WP); | ||
74 | } | ||
75 | |||
76 | static int marxbot_sdhc2_init(struct device *dev, irq_handler_t detect_irq, | ||
77 | void *data) | ||
78 | { | ||
79 | int ret; | ||
80 | |||
81 | ret = gpio_request(SDHC2_CD, "sdhc-detect"); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | |||
85 | gpio_direction_input(SDHC2_CD); | ||
86 | |||
87 | ret = gpio_request(SDHC2_WP, "sdhc-wp"); | ||
88 | if (ret) | ||
89 | goto err_gpio_free; | ||
90 | gpio_direction_input(SDHC2_WP); | ||
91 | |||
92 | ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq, | ||
93 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
94 | "sdhc2-card-detect", data); | ||
95 | if (ret) | ||
96 | goto err_gpio_free_2; | ||
97 | |||
98 | return 0; | ||
99 | |||
100 | err_gpio_free_2: | ||
101 | gpio_free(SDHC2_WP); | ||
102 | err_gpio_free: | ||
103 | gpio_free(SDHC2_CD); | ||
104 | |||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | static void marxbot_sdhc2_exit(struct device *dev, void *data) | ||
109 | { | ||
110 | free_irq(gpio_to_irq(SDHC2_CD), data); | ||
111 | gpio_free(SDHC2_WP); | ||
112 | gpio_free(SDHC2_CD); | ||
113 | } | ||
114 | |||
115 | static const struct imxmmc_platform_data sdhc2_pdata __initconst = { | ||
116 | .get_ro = marxbot_sdhc2_get_ro, | ||
117 | .init = marxbot_sdhc2_init, | ||
118 | .exit = marxbot_sdhc2_exit, | ||
119 | }; | ||
120 | |||
121 | #define TRSLAT_RST_B IOMUX_TO_GPIO(MX31_PIN_STXD5) | ||
122 | #define DSPICS_RST_B IOMUX_TO_GPIO(MX31_PIN_SRXD5) | ||
123 | |||
124 | static void dspics_resets_init(void) | ||
125 | { | ||
126 | if (!gpio_request(TRSLAT_RST_B, "translator-rst")) { | ||
127 | gpio_direction_output(TRSLAT_RST_B, 0); | ||
128 | gpio_export(TRSLAT_RST_B, false); | ||
129 | } | ||
130 | |||
131 | if (!gpio_request(DSPICS_RST_B, "dspics-rst")) { | ||
132 | gpio_direction_output(DSPICS_RST_B, 0); | ||
133 | gpio_export(DSPICS_RST_B, false); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static struct spi_board_info marxbot_spi_board_info[] __initdata = { | ||
138 | { | ||
139 | .modalias = "spidev", | ||
140 | .max_speed_hz = 300000, | ||
141 | .bus_num = 1, | ||
142 | .chip_select = 1, /* according spi1_cs[] ! */ | ||
143 | }, | ||
144 | }; | ||
145 | |||
146 | #define TURRETCAM_POWER IOMUX_TO_GPIO(MX31_PIN_GPIO3_1) | ||
147 | #define BASECAM_POWER IOMUX_TO_GPIO(MX31_PIN_CSI_D5) | ||
148 | #define TURRETCAM_RST_B IOMUX_TO_GPIO(MX31_PIN_GPIO3_0) | ||
149 | #define BASECAM_RST_B IOMUX_TO_GPIO(MX31_PIN_CSI_D4) | ||
150 | #define CAM_CHOICE IOMUX_TO_GPIO(MX31_PIN_TXD2) | ||
151 | |||
152 | static int marxbot_basecam_power(struct device *dev, int on) | ||
153 | { | ||
154 | gpio_set_value(BASECAM_POWER, !on); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int marxbot_basecam_reset(struct device *dev) | ||
159 | { | ||
160 | gpio_set_value(BASECAM_RST_B, 0); | ||
161 | udelay(100); | ||
162 | gpio_set_value(BASECAM_RST_B, 1); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static struct i2c_board_info marxbot_i2c_devices[] = { | ||
167 | { | ||
168 | I2C_BOARD_INFO("mt9t031", 0x5d), | ||
169 | }, | ||
170 | }; | ||
171 | |||
172 | static struct soc_camera_link base_iclink = { | ||
173 | .bus_id = 0, /* Must match with the camera ID */ | ||
174 | .power = marxbot_basecam_power, | ||
175 | .reset = marxbot_basecam_reset, | ||
176 | .board_info = &marxbot_i2c_devices[0], | ||
177 | .i2c_adapter_id = 0, | ||
178 | }; | ||
179 | |||
180 | static struct platform_device marxbot_camera[] = { | ||
181 | { | ||
182 | .name = "soc-camera-pdrv", | ||
183 | .id = 0, | ||
184 | .dev = { | ||
185 | .platform_data = &base_iclink, | ||
186 | }, | ||
187 | }, | ||
188 | }; | ||
189 | |||
190 | static struct platform_device *marxbot_cameras[] __initdata = { | ||
191 | &marxbot_camera[0], | ||
192 | }; | ||
193 | |||
194 | static int __init marxbot_cam_init(void) | ||
195 | { | ||
196 | int ret = gpio_request(CAM_CHOICE, "cam-choice"); | ||
197 | if (ret) | ||
198 | return ret; | ||
199 | gpio_direction_output(CAM_CHOICE, 0); | ||
200 | |||
201 | ret = gpio_request(BASECAM_RST_B, "basecam-reset"); | ||
202 | if (ret) | ||
203 | return ret; | ||
204 | gpio_direction_output(BASECAM_RST_B, 1); | ||
205 | ret = gpio_request(BASECAM_POWER, "basecam-standby"); | ||
206 | if (ret) | ||
207 | return ret; | ||
208 | gpio_direction_output(BASECAM_POWER, 0); | ||
209 | |||
210 | ret = gpio_request(TURRETCAM_RST_B, "turretcam-reset"); | ||
211 | if (ret) | ||
212 | return ret; | ||
213 | gpio_direction_output(TURRETCAM_RST_B, 1); | ||
214 | ret = gpio_request(TURRETCAM_POWER, "turretcam-standby"); | ||
215 | if (ret) | ||
216 | return ret; | ||
217 | gpio_direction_output(TURRETCAM_POWER, 0); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | #define SEL0 IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1) | ||
223 | #define SEL1 IOMUX_TO_GPIO(MX31_PIN_DSR_DCE1) | ||
224 | #define SEL2 IOMUX_TO_GPIO(MX31_PIN_RI_DCE1) | ||
225 | #define SEL3 IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1) | ||
226 | |||
227 | static void marxbot_init_sel_gpios(void) | ||
228 | { | ||
229 | if (!gpio_request(SEL0, "sel0")) { | ||
230 | gpio_direction_input(SEL0); | ||
231 | gpio_export(SEL0, true); | ||
232 | } | ||
233 | |||
234 | if (!gpio_request(SEL1, "sel1")) { | ||
235 | gpio_direction_input(SEL1); | ||
236 | gpio_export(SEL1, true); | ||
237 | } | ||
238 | |||
239 | if (!gpio_request(SEL2, "sel2")) { | ||
240 | gpio_direction_input(SEL2); | ||
241 | gpio_export(SEL2, true); | ||
242 | } | ||
243 | |||
244 | if (!gpio_request(SEL3, "sel3")) { | ||
245 | gpio_direction_input(SEL3); | ||
246 | gpio_export(SEL3, true); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | #define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ | ||
251 | PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) | ||
252 | |||
253 | static int marxbot_usbh1_hw_init(struct platform_device *pdev) | ||
254 | { | ||
255 | mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true); | ||
256 | |||
257 | mxc_iomux_set_pad(MX31_PIN_CSPI1_MISO, USB_PAD_CFG); | ||
258 | mxc_iomux_set_pad(MX31_PIN_CSPI1_MOSI, USB_PAD_CFG); | ||
259 | mxc_iomux_set_pad(MX31_PIN_CSPI1_SS0, USB_PAD_CFG); | ||
260 | mxc_iomux_set_pad(MX31_PIN_CSPI1_SS1, USB_PAD_CFG); | ||
261 | mxc_iomux_set_pad(MX31_PIN_CSPI1_SS2, USB_PAD_CFG); | ||
262 | mxc_iomux_set_pad(MX31_PIN_CSPI1_SCLK, USB_PAD_CFG); | ||
263 | mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG); | ||
264 | mxc_iomux_set_pad(MX31_PIN_SFS6, USB_PAD_CFG); | ||
265 | |||
266 | mdelay(10); | ||
267 | |||
268 | return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED | | ||
269 | MXC_EHCI_INTERFACE_SINGLE_UNI); | ||
270 | } | ||
271 | |||
272 | #define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B) | ||
273 | #define USBH1_MODE IOMUX_TO_GPIO(MX31_PIN_NFALE) | ||
274 | |||
275 | static int marxbot_isp1105_init(struct otg_transceiver *otg) | ||
276 | { | ||
277 | int ret = gpio_request(USBH1_MODE, "usbh1-mode"); | ||
278 | if (ret) | ||
279 | return ret; | ||
280 | /* single ended */ | ||
281 | gpio_direction_output(USBH1_MODE, 0); | ||
282 | |||
283 | ret = gpio_request(USBH1_VBUSEN_B, "usbh1-vbusen"); | ||
284 | if (ret) { | ||
285 | gpio_free(USBH1_MODE); | ||
286 | return ret; | ||
287 | } | ||
288 | gpio_direction_output(USBH1_VBUSEN_B, 1); | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | |||
294 | static int marxbot_isp1105_set_vbus(struct otg_transceiver *otg, bool on) | ||
295 | { | ||
296 | if (on) | ||
297 | gpio_set_value(USBH1_VBUSEN_B, 0); | ||
298 | else | ||
299 | gpio_set_value(USBH1_VBUSEN_B, 1); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static struct mxc_usbh_platform_data usbh1_pdata __initdata = { | ||
305 | .init = marxbot_usbh1_hw_init, | ||
306 | .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL, | ||
307 | }; | ||
308 | |||
309 | static int __init marxbot_usbh1_init(void) | ||
310 | { | ||
311 | struct otg_transceiver *otg; | ||
312 | struct platform_device *pdev; | ||
313 | |||
314 | otg = kzalloc(sizeof(*otg), GFP_KERNEL); | ||
315 | if (!otg) | ||
316 | return -ENOMEM; | ||
317 | |||
318 | otg->label = "ISP1105"; | ||
319 | otg->init = marxbot_isp1105_init; | ||
320 | otg->set_vbus = marxbot_isp1105_set_vbus; | ||
321 | |||
322 | usbh1_pdata.otg = otg; | ||
323 | |||
324 | pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata); | ||
325 | if (IS_ERR(pdev)) | ||
326 | return PTR_ERR(pdev); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static const struct fsl_usb2_platform_data usb_pdata __initconst = { | ||
332 | .operating_mode = FSL_USB2_DR_DEVICE, | ||
333 | .phy_mode = FSL_USB2_PHY_ULPI, | ||
334 | }; | ||
335 | |||
336 | /* | ||
337 | * system init for baseboard usage. Will be called by mx31moboard init. | ||
338 | */ | ||
339 | void __init mx31moboard_marxbot_init(void) | ||
340 | { | ||
341 | printk(KERN_INFO "Initializing mx31marxbot peripherals\n"); | ||
342 | |||
343 | mxc_iomux_setup_multiple_pins(marxbot_pins, ARRAY_SIZE(marxbot_pins), | ||
344 | "marxbot"); | ||
345 | |||
346 | marxbot_init_sel_gpios(); | ||
347 | |||
348 | dspics_resets_init(); | ||
349 | |||
350 | imx31_add_mxc_mmc(1, &sdhc2_pdata); | ||
351 | |||
352 | spi_register_board_info(marxbot_spi_board_info, | ||
353 | ARRAY_SIZE(marxbot_spi_board_info)); | ||
354 | |||
355 | marxbot_cam_init(); | ||
356 | platform_add_devices(marxbot_cameras, ARRAY_SIZE(marxbot_cameras)); | ||
357 | |||
358 | /* battery present pin */ | ||
359 | gpio_request(IOMUX_TO_GPIO(MX31_PIN_LCS0), "bat-present"); | ||
360 | gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_LCS0)); | ||
361 | gpio_export(IOMUX_TO_GPIO(MX31_PIN_LCS0), false); | ||
362 | |||
363 | imx31_add_fsl_usb2_udc(&usb_pdata); | ||
364 | |||
365 | marxbot_usbh1_init(); | ||
366 | } | ||