diff options
Diffstat (limited to 'arch/arm/mach-s3c64xx/mach-smartq.c')
-rw-r--r-- | arch/arm/mach-s3c64xx/mach-smartq.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c new file mode 100644 index 000000000000..028d080dcd35 --- /dev/null +++ b/arch/arm/mach-s3c64xx/mach-smartq.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-s3c64xx/mach-smartq.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Maurus Cuelenaere | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/fb.h> | ||
14 | #include <linux/gpio.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/pwm_backlight.h> | ||
18 | #include <linux/serial_core.h> | ||
19 | #include <linux/usb/gpio_vbus.h> | ||
20 | |||
21 | #include <asm/mach-types.h> | ||
22 | #include <asm/mach/map.h> | ||
23 | |||
24 | #include <mach/map.h> | ||
25 | #include <mach/regs-gpio.h> | ||
26 | #include <mach/regs-modem.h> | ||
27 | |||
28 | #include <plat/clock.h> | ||
29 | #include <plat/cpu.h> | ||
30 | #include <plat/devs.h> | ||
31 | #include <plat/iic.h> | ||
32 | #include <plat/gpio-cfg.h> | ||
33 | #include <plat/hwmon.h> | ||
34 | #include <plat/regs-serial.h> | ||
35 | #include <plat/udc-hs.h> | ||
36 | #include <plat/usb-control.h> | ||
37 | #include <plat/sdhci.h> | ||
38 | #include <plat/ts.h> | ||
39 | |||
40 | #include <video/platform_lcd.h> | ||
41 | |||
42 | #define UCON S3C2410_UCON_DEFAULT | ||
43 | #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE) | ||
44 | #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) | ||
45 | |||
46 | static struct s3c2410_uartcfg smartq_uartcfgs[] __initdata = { | ||
47 | [0] = { | ||
48 | .hwport = 0, | ||
49 | .flags = 0, | ||
50 | .ucon = UCON, | ||
51 | .ulcon = ULCON, | ||
52 | .ufcon = UFCON, | ||
53 | }, | ||
54 | [1] = { | ||
55 | .hwport = 1, | ||
56 | .flags = 0, | ||
57 | .ucon = UCON, | ||
58 | .ulcon = ULCON, | ||
59 | .ufcon = UFCON, | ||
60 | }, | ||
61 | [2] = { | ||
62 | .hwport = 2, | ||
63 | .flags = 0, | ||
64 | .ucon = UCON, | ||
65 | .ulcon = ULCON, | ||
66 | .ufcon = UFCON, | ||
67 | }, | ||
68 | }; | ||
69 | |||
70 | static void smartq_usb_host_powercontrol(int port, int to) | ||
71 | { | ||
72 | pr_debug("%s(%d, %d)\n", __func__, port, to); | ||
73 | |||
74 | if (port == 0) { | ||
75 | gpio_set_value(S3C64XX_GPL(0), to); | ||
76 | gpio_set_value(S3C64XX_GPL(1), to); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static irqreturn_t smartq_usb_host_ocirq(int irq, void *pw) | ||
81 | { | ||
82 | struct s3c2410_hcd_info *info = pw; | ||
83 | |||
84 | if (gpio_get_value(S3C64XX_GPL(10)) == 0) { | ||
85 | pr_debug("%s: over-current irq (oc detected)\n", __func__); | ||
86 | s3c2410_usb_report_oc(info, 3); | ||
87 | } else { | ||
88 | pr_debug("%s: over-current irq (oc cleared)\n", __func__); | ||
89 | s3c2410_usb_report_oc(info, 0); | ||
90 | } | ||
91 | |||
92 | return IRQ_HANDLED; | ||
93 | } | ||
94 | |||
95 | static void smartq_usb_host_enableoc(struct s3c2410_hcd_info *info, int on) | ||
96 | { | ||
97 | int ret; | ||
98 | |||
99 | /* This isn't present on a SmartQ 5 board */ | ||
100 | if (machine_is_smartq5()) | ||
101 | return; | ||
102 | |||
103 | if (on) { | ||
104 | ret = request_irq(gpio_to_irq(S3C64XX_GPL(10)), | ||
105 | smartq_usb_host_ocirq, IRQF_DISABLED | | ||
106 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
107 | "USB host overcurrent", info); | ||
108 | if (ret != 0) | ||
109 | pr_err("failed to request usb oc irq: %d\n", ret); | ||
110 | } else { | ||
111 | free_irq(gpio_to_irq(S3C64XX_GPL(10)), info); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static struct s3c2410_hcd_info smartq_usb_host_info = { | ||
116 | .port[0] = { | ||
117 | .flags = S3C_HCDFLG_USED | ||
118 | }, | ||
119 | .port[1] = { | ||
120 | .flags = 0 | ||
121 | }, | ||
122 | |||
123 | .power_control = smartq_usb_host_powercontrol, | ||
124 | .enable_oc = smartq_usb_host_enableoc, | ||
125 | }; | ||
126 | |||
127 | static struct gpio_vbus_mach_info smartq_usb_otg_vbus_pdata = { | ||
128 | .gpio_vbus = S3C64XX_GPL(9), | ||
129 | .gpio_pullup = -1, | ||
130 | .gpio_vbus_inverted = true, | ||
131 | }; | ||
132 | |||
133 | static struct platform_device smartq_usb_otg_vbus_dev = { | ||
134 | .name = "gpio-vbus", | ||
135 | .dev.platform_data = &smartq_usb_otg_vbus_pdata, | ||
136 | }; | ||
137 | |||
138 | static int __init smartq_bl_init(struct device *dev) | ||
139 | { | ||
140 | s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2)); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static struct platform_pwm_backlight_data smartq_backlight_data = { | ||
146 | .pwm_id = 1, | ||
147 | .max_brightness = 1000, | ||
148 | .dft_brightness = 600, | ||
149 | .pwm_period_ns = 1000000000 / (1000 * 20), | ||
150 | .init = smartq_bl_init, | ||
151 | }; | ||
152 | |||
153 | static struct platform_device smartq_backlight_device = { | ||
154 | .name = "pwm-backlight", | ||
155 | .dev = { | ||
156 | .parent = &s3c_device_timer[1].dev, | ||
157 | .platform_data = &smartq_backlight_data, | ||
158 | }, | ||
159 | }; | ||
160 | |||
161 | static struct s3c2410_ts_mach_info smartq_touchscreen_pdata __initdata = { | ||
162 | .delay = 65535, | ||
163 | .presc = 99, | ||
164 | .oversampling_shift = 4, | ||
165 | }; | ||
166 | |||
167 | static struct s3c_sdhci_platdata smartq_internal_hsmmc_pdata = { | ||
168 | .max_width = 4, | ||
169 | /*.broken_card_detection = true,*/ | ||
170 | }; | ||
171 | |||
172 | static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = { | ||
173 | /* Battery voltage (?-4.2V) */ | ||
174 | .in[0] = &(struct s3c_hwmon_chcfg) { | ||
175 | .name = "smartq:battery-voltage", | ||
176 | .mult = 3300, | ||
177 | .div = 2048, | ||
178 | }, | ||
179 | /* Reference voltage (1.2V) */ | ||
180 | .in[1] = &(struct s3c_hwmon_chcfg) { | ||
181 | .name = "smartq:reference-voltage", | ||
182 | .mult = 3300, | ||
183 | .div = 4096, | ||
184 | }, | ||
185 | }; | ||
186 | |||
187 | static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power) | ||
188 | { | ||
189 | gpio_direction_output(S3C64XX_GPM(3), power); | ||
190 | } | ||
191 | |||
192 | static struct plat_lcd_data smartq_lcd_power_data = { | ||
193 | .set_power = smartq_lcd_power_set, | ||
194 | }; | ||
195 | |||
196 | static struct platform_device smartq_lcd_power_device = { | ||
197 | .name = "platform-lcd", | ||
198 | .dev.parent = &s3c_device_fb.dev, | ||
199 | .dev.platform_data = &smartq_lcd_power_data, | ||
200 | }; | ||
201 | |||
202 | |||
203 | static struct platform_device *smartq_devices[] __initdata = { | ||
204 | &s3c_device_hsmmc1, /* Init iNAND first, ... */ | ||
205 | &s3c_device_hsmmc0, /* ... then the external SD card */ | ||
206 | &s3c_device_hsmmc2, | ||
207 | &s3c_device_adc, | ||
208 | &s3c_device_fb, | ||
209 | &s3c_device_hwmon, | ||
210 | &s3c_device_i2c0, | ||
211 | &s3c_device_ohci, | ||
212 | &s3c_device_rtc, | ||
213 | &s3c_device_timer[1], | ||
214 | &s3c_device_ts, | ||
215 | &s3c_device_usb_hsotg, | ||
216 | &smartq_backlight_device, | ||
217 | &smartq_lcd_power_device, | ||
218 | &smartq_usb_otg_vbus_dev, | ||
219 | }; | ||
220 | |||
221 | static void __init smartq_lcd_mode_set(void) | ||
222 | { | ||
223 | u32 tmp; | ||
224 | |||
225 | /* set the LCD type */ | ||
226 | tmp = __raw_readl(S3C64XX_SPCON); | ||
227 | tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; | ||
228 | tmp |= S3C64XX_SPCON_LCD_SEL_RGB; | ||
229 | __raw_writel(tmp, S3C64XX_SPCON); | ||
230 | |||
231 | /* remove the LCD bypass */ | ||
232 | tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); | ||
233 | tmp &= ~MIFPCON_LCD_BYPASS; | ||
234 | __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); | ||
235 | } | ||
236 | |||
237 | static void smartq_power_off(void) | ||
238 | { | ||
239 | gpio_direction_output(S3C64XX_GPK(15), 1); | ||
240 | } | ||
241 | |||
242 | static int __init smartq_power_off_init(void) | ||
243 | { | ||
244 | int ret; | ||
245 | |||
246 | ret = gpio_request(S3C64XX_GPK(15), "Power control"); | ||
247 | if (ret < 0) { | ||
248 | pr_err("%s: failed to get GPK15\n", __func__); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | /* leave power on */ | ||
253 | gpio_direction_output(S3C64XX_GPK(15), 0); | ||
254 | |||
255 | |||
256 | pm_power_off = smartq_power_off; | ||
257 | |||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | static int __init smartq_usb_host_init(void) | ||
262 | { | ||
263 | int ret; | ||
264 | |||
265 | ret = gpio_request(S3C64XX_GPL(0), "USB power control"); | ||
266 | if (ret < 0) { | ||
267 | pr_err("%s: failed to get GPL0\n", __func__); | ||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | ret = gpio_request(S3C64XX_GPL(1), "USB host power control"); | ||
272 | if (ret < 0) { | ||
273 | pr_err("%s: failed to get GPL1\n", __func__); | ||
274 | goto err; | ||
275 | } | ||
276 | |||
277 | if (!machine_is_smartq5()) { | ||
278 | /* This isn't present on a SmartQ 5 board */ | ||
279 | ret = gpio_request(S3C64XX_GPL(10), "USB host overcurrent"); | ||
280 | if (ret < 0) { | ||
281 | pr_err("%s: failed to get GPL10\n", __func__); | ||
282 | goto err2; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | /* turn power off */ | ||
287 | gpio_direction_output(S3C64XX_GPL(0), 0); | ||
288 | gpio_direction_output(S3C64XX_GPL(1), 0); | ||
289 | if (!machine_is_smartq5()) | ||
290 | gpio_direction_input(S3C64XX_GPL(10)); | ||
291 | |||
292 | s3c_device_ohci.dev.platform_data = &smartq_usb_host_info; | ||
293 | |||
294 | return 0; | ||
295 | |||
296 | err2: | ||
297 | gpio_free(S3C64XX_GPL(1)); | ||
298 | err: | ||
299 | gpio_free(S3C64XX_GPL(0)); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static int __init smartq_usb_otg_init(void) | ||
304 | { | ||
305 | clk_xusbxti.rate = 12000000; | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int __init smartq_wifi_init(void) | ||
311 | { | ||
312 | int ret; | ||
313 | |||
314 | ret = gpio_request(S3C64XX_GPK(1), "wifi control"); | ||
315 | if (ret < 0) { | ||
316 | pr_err("%s: failed to get GPK1\n", __func__); | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | ret = gpio_request(S3C64XX_GPK(2), "wifi reset"); | ||
321 | if (ret < 0) { | ||
322 | pr_err("%s: failed to get GPK2\n", __func__); | ||
323 | gpio_free(S3C64XX_GPK(1)); | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | /* turn power on */ | ||
328 | gpio_direction_output(S3C64XX_GPK(1), 1); | ||
329 | |||
330 | /* reset device */ | ||
331 | gpio_direction_output(S3C64XX_GPK(2), 0); | ||
332 | mdelay(100); | ||
333 | gpio_set_value(S3C64XX_GPK(2), 1); | ||
334 | gpio_direction_input(S3C64XX_GPK(2)); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static struct map_desc smartq_iodesc[] __initdata = {}; | ||
340 | void __init smartq_map_io(void) | ||
341 | { | ||
342 | s3c64xx_init_io(smartq_iodesc, ARRAY_SIZE(smartq_iodesc)); | ||
343 | s3c24xx_init_clocks(12000000); | ||
344 | s3c24xx_init_uarts(smartq_uartcfgs, ARRAY_SIZE(smartq_uartcfgs)); | ||
345 | |||
346 | smartq_lcd_mode_set(); | ||
347 | } | ||
348 | |||
349 | void __init smartq_machine_init(void) | ||
350 | { | ||
351 | s3c_i2c0_set_platdata(NULL); | ||
352 | s3c_hwmon_set_platdata(&smartq_hwmon_pdata); | ||
353 | s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata); | ||
354 | s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata); | ||
355 | s3c24xx_ts_set_platdata(&smartq_touchscreen_pdata); | ||
356 | |||
357 | WARN_ON(smartq_power_off_init()); | ||
358 | WARN_ON(smartq_usb_host_init()); | ||
359 | WARN_ON(smartq_usb_otg_init()); | ||
360 | WARN_ON(smartq_wifi_init()); | ||
361 | |||
362 | platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices)); | ||
363 | } | ||