mach-smartq.c (9912B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// Copyright (C) 2010 Maurus Cuelenaere 4 5#include <linux/delay.h> 6#include <linux/fb.h> 7#include <linux/gpio.h> 8#include <linux/gpio/machine.h> 9#include <linux/init.h> 10#include <linux/platform_device.h> 11#include <linux/pwm.h> 12#include <linux/pwm_backlight.h> 13#include <linux/serial_core.h> 14#include <linux/serial_s3c.h> 15#include <linux/spi/spi_gpio.h> 16#include <linux/platform_data/s3c-hsotg.h> 17 18#include <asm/mach-types.h> 19#include <asm/mach/map.h> 20 21#include "map.h" 22#include "regs-gpio.h" 23#include "gpio-samsung.h" 24 25#include "cpu.h" 26#include "devs.h" 27#include <linux/platform_data/i2c-s3c2410.h> 28#include "gpio-cfg.h" 29#include <linux/platform_data/hwmon-s3c.h> 30#include <linux/platform_data/usb-ohci-s3c2410.h> 31#include "sdhci.h" 32#include <linux/platform_data/touchscreen-s3c2410.h> 33 34#include <video/platform_lcd.h> 35 36#include "s3c64xx.h" 37#include "mach-smartq.h" 38#include "regs-modem-s3c64xx.h" 39 40#define UCON S3C2410_UCON_DEFAULT 41#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE) 42#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) 43 44static struct s3c2410_uartcfg smartq_uartcfgs[] __initdata = { 45 [0] = { 46 .hwport = 0, 47 .flags = 0, 48 .ucon = UCON, 49 .ulcon = ULCON, 50 .ufcon = UFCON, 51 }, 52 [1] = { 53 .hwport = 1, 54 .flags = 0, 55 .ucon = UCON, 56 .ulcon = ULCON, 57 .ufcon = UFCON, 58 }, 59 [2] = { 60 .hwport = 2, 61 .flags = 0, 62 .ucon = UCON, 63 .ulcon = ULCON, 64 .ufcon = UFCON, 65 }, 66}; 67 68static void smartq_usb_host_powercontrol(int port, int to) 69{ 70 pr_debug("%s(%d, %d)\n", __func__, port, to); 71 72 if (port == 0) { 73 gpio_set_value(S3C64XX_GPL(0), to); 74 gpio_set_value(S3C64XX_GPL(1), to); 75 } 76} 77 78static irqreturn_t smartq_usb_host_ocirq(int irq, void *pw) 79{ 80 struct s3c2410_hcd_info *info = pw; 81 82 if (gpio_get_value(S3C64XX_GPL(10)) == 0) { 83 pr_debug("%s: over-current irq (oc detected)\n", __func__); 84 s3c2410_usb_report_oc(info, 3); 85 } else { 86 pr_debug("%s: over-current irq (oc cleared)\n", __func__); 87 s3c2410_usb_report_oc(info, 0); 88 } 89 90 return IRQ_HANDLED; 91} 92 93static void smartq_usb_host_enableoc(struct s3c2410_hcd_info *info, int on) 94{ 95 int ret; 96 97 /* This isn't present on a SmartQ 5 board */ 98 if (machine_is_smartq5()) 99 return; 100 101 if (on) { 102 ret = request_irq(gpio_to_irq(S3C64XX_GPL(10)), 103 smartq_usb_host_ocirq, 104 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 105 "USB host overcurrent", info); 106 if (ret != 0) 107 pr_err("failed to request usb oc irq: %d\n", ret); 108 } else { 109 free_irq(gpio_to_irq(S3C64XX_GPL(10)), info); 110 } 111} 112 113static struct s3c2410_hcd_info smartq_usb_host_info = { 114 .port[0] = { 115 .flags = S3C_HCDFLG_USED 116 }, 117 .port[1] = { 118 .flags = 0 119 }, 120 121 .power_control = smartq_usb_host_powercontrol, 122 .enable_oc = smartq_usb_host_enableoc, 123}; 124 125static struct gpiod_lookup_table smartq_usb_otg_vbus_gpiod_table = { 126 .dev_id = "gpio-vbus", 127 .table = { 128 GPIO_LOOKUP("GPL", 9, "vbus", GPIO_ACTIVE_LOW), 129 { }, 130 }, 131}; 132 133static struct platform_device smartq_usb_otg_vbus_dev = { 134 .name = "gpio-vbus", 135}; 136 137static struct pwm_lookup smartq_pwm_lookup[] = { 138 PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL, 139 1000000000 / (1000 * 20), PWM_POLARITY_NORMAL), 140}; 141 142static int smartq_bl_init(struct device *dev) 143{ 144 s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2)); 145 146 return 0; 147} 148 149static struct platform_pwm_backlight_data smartq_backlight_data = { 150 .max_brightness = 1000, 151 .dft_brightness = 600, 152 .init = smartq_bl_init, 153}; 154 155static struct platform_device smartq_backlight_device = { 156 .name = "pwm-backlight", 157 .dev = { 158 .parent = &samsung_device_pwm.dev, 159 .platform_data = &smartq_backlight_data, 160 }, 161}; 162 163static struct s3c2410_ts_mach_info smartq_touchscreen_pdata __initdata = { 164 .delay = 65535, 165 .presc = 99, 166 .oversampling_shift = 4, 167}; 168 169static struct s3c_sdhci_platdata smartq_internal_hsmmc_pdata = { 170 .max_width = 4, 171 .cd_type = S3C_SDHCI_CD_PERMANENT, 172}; 173 174static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = { 175 /* Battery voltage (?-4.2V) */ 176 .in[0] = &(struct s3c_hwmon_chcfg) { 177 .name = "smartq:battery-voltage", 178 .mult = 3300, 179 .div = 2048, 180 }, 181 /* Reference voltage (1.2V) */ 182 .in[1] = &(struct s3c_hwmon_chcfg) { 183 .name = "smartq:reference-voltage", 184 .mult = 3300, 185 .div = 4096, 186 }, 187}; 188 189static struct dwc2_hsotg_plat smartq_hsotg_pdata; 190 191static int __init smartq_lcd_setup_gpio(void) 192{ 193 int ret; 194 195 ret = gpio_request(S3C64XX_GPM(3), "LCD power"); 196 if (ret < 0) 197 return ret; 198 199 /* turn power off */ 200 gpio_direction_output(S3C64XX_GPM(3), 0); 201 202 return 0; 203} 204 205/* GPM0 -> CS */ 206static struct spi_gpio_platform_data smartq_lcd_control = { 207 .num_chipselect = 1, 208}; 209 210static struct platform_device smartq_lcd_control_device = { 211 .name = "spi_gpio", 212 .id = 1, 213 .dev.platform_data = &smartq_lcd_control, 214}; 215 216static struct gpiod_lookup_table smartq_lcd_control_gpiod_table = { 217 .dev_id = "spi_gpio", 218 .table = { 219 GPIO_LOOKUP("GPIOM", 1, 220 "sck", GPIO_ACTIVE_HIGH), 221 GPIO_LOOKUP("GPIOM", 2, 222 "mosi", GPIO_ACTIVE_HIGH), 223 GPIO_LOOKUP("GPIOM", 3, 224 "miso", GPIO_ACTIVE_HIGH), 225 GPIO_LOOKUP("GPIOM", 0, 226 "cs", GPIO_ACTIVE_HIGH), 227 { }, 228 }, 229}; 230 231static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power) 232{ 233 gpio_direction_output(S3C64XX_GPM(3), power); 234} 235 236static struct plat_lcd_data smartq_lcd_power_data = { 237 .set_power = smartq_lcd_power_set, 238}; 239 240static struct platform_device smartq_lcd_power_device = { 241 .name = "platform-lcd", 242 .dev.parent = &s3c_device_fb.dev, 243 .dev.platform_data = &smartq_lcd_power_data, 244}; 245 246static struct i2c_board_info smartq_i2c_devs[] __initdata = { 247 { I2C_BOARD_INFO("wm8987", 0x1a), }, 248}; 249 250static struct platform_device *smartq_devices[] __initdata = { 251 &s3c_device_hsmmc1, /* Init iNAND first, ... */ 252 &s3c_device_hsmmc0, /* ... then the external SD card */ 253 &s3c_device_hsmmc2, 254 &s3c_device_adc, 255 &s3c_device_fb, 256 &s3c_device_hwmon, 257 &s3c_device_i2c0, 258 &s3c_device_ohci, 259 &s3c_device_rtc, 260 &samsung_device_pwm, 261 &s3c_device_usb_hsotg, 262 &s3c64xx_device_iis0, 263 &smartq_backlight_device, 264 &smartq_lcd_control_device, 265 &smartq_lcd_power_device, 266 &smartq_usb_otg_vbus_dev, 267}; 268 269static void __init smartq_lcd_mode_set(void) 270{ 271 u32 tmp; 272 273 /* set the LCD type */ 274 tmp = __raw_readl(S3C64XX_SPCON); 275 tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; 276 tmp |= S3C64XX_SPCON_LCD_SEL_RGB; 277 __raw_writel(tmp, S3C64XX_SPCON); 278 279 /* remove the LCD bypass */ 280 tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); 281 tmp &= ~MIFPCON_LCD_BYPASS; 282 __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); 283} 284 285static void smartq_power_off(void) 286{ 287 gpio_direction_output(S3C64XX_GPK(15), 1); 288} 289 290static int __init smartq_power_off_init(void) 291{ 292 int ret; 293 294 ret = gpio_request(S3C64XX_GPK(15), "Power control"); 295 if (ret < 0) { 296 pr_err("%s: failed to get GPK15\n", __func__); 297 return ret; 298 } 299 300 /* leave power on */ 301 gpio_direction_output(S3C64XX_GPK(15), 0); 302 303 pm_power_off = smartq_power_off; 304 305 return ret; 306} 307 308static int __init smartq_usb_host_init(void) 309{ 310 int ret; 311 312 ret = gpio_request(S3C64XX_GPL(0), "USB power control"); 313 if (ret < 0) { 314 pr_err("%s: failed to get GPL0\n", __func__); 315 return ret; 316 } 317 318 ret = gpio_request(S3C64XX_GPL(1), "USB host power control"); 319 if (ret < 0) { 320 pr_err("%s: failed to get GPL1\n", __func__); 321 goto err; 322 } 323 324 if (!machine_is_smartq5()) { 325 /* This isn't present on a SmartQ 5 board */ 326 ret = gpio_request(S3C64XX_GPL(10), "USB host overcurrent"); 327 if (ret < 0) { 328 pr_err("%s: failed to get GPL10\n", __func__); 329 goto err2; 330 } 331 } 332 333 /* turn power off */ 334 gpio_direction_output(S3C64XX_GPL(0), 0); 335 gpio_direction_output(S3C64XX_GPL(1), 0); 336 if (!machine_is_smartq5()) 337 gpio_direction_input(S3C64XX_GPL(10)); 338 339 s3c_device_ohci.dev.platform_data = &smartq_usb_host_info; 340 341 return 0; 342 343err2: 344 gpio_free(S3C64XX_GPL(1)); 345err: 346 gpio_free(S3C64XX_GPL(0)); 347 return ret; 348} 349 350static int __init smartq_wifi_init(void) 351{ 352 int ret; 353 354 ret = gpio_request(S3C64XX_GPK(1), "wifi control"); 355 if (ret < 0) { 356 pr_err("%s: failed to get GPK1\n", __func__); 357 return ret; 358 } 359 360 ret = gpio_request(S3C64XX_GPK(2), "wifi reset"); 361 if (ret < 0) { 362 pr_err("%s: failed to get GPK2\n", __func__); 363 gpio_free(S3C64XX_GPK(1)); 364 return ret; 365 } 366 367 /* turn power on */ 368 gpio_direction_output(S3C64XX_GPK(1), 1); 369 370 /* reset device */ 371 gpio_direction_output(S3C64XX_GPK(2), 0); 372 mdelay(100); 373 gpio_set_value(S3C64XX_GPK(2), 1); 374 gpio_direction_input(S3C64XX_GPK(2)); 375 376 return 0; 377} 378 379static struct map_desc smartq_iodesc[] __initdata = {}; 380void __init smartq_map_io(void) 381{ 382 s3c64xx_init_io(smartq_iodesc, ARRAY_SIZE(smartq_iodesc)); 383 s3c64xx_set_xtal_freq(12000000); 384 s3c64xx_set_xusbxti_freq(12000000); 385 s3c24xx_init_uarts(smartq_uartcfgs, ARRAY_SIZE(smartq_uartcfgs)); 386 s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); 387 388 smartq_lcd_mode_set(); 389} 390 391static struct gpiod_lookup_table smartq_audio_gpios = { 392 .dev_id = "smartq-audio", 393 .table = { 394 GPIO_LOOKUP("GPL", 12, "headphone detect", 0), 395 GPIO_LOOKUP("GPK", 12, "amplifiers shutdown", 0), 396 { }, 397 }, 398}; 399 400void __init smartq_machine_init(void) 401{ 402 s3c_i2c0_set_platdata(NULL); 403 dwc2_hsotg_set_platdata(&smartq_hsotg_pdata); 404 s3c_hwmon_set_platdata(&smartq_hwmon_pdata); 405 s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata); 406 s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata); 407 s3c64xx_ts_set_platdata(&smartq_touchscreen_pdata); 408 409 i2c_register_board_info(0, smartq_i2c_devs, 410 ARRAY_SIZE(smartq_i2c_devs)); 411 412 WARN_ON(smartq_lcd_setup_gpio()); 413 WARN_ON(smartq_power_off_init()); 414 WARN_ON(smartq_usb_host_init()); 415 WARN_ON(smartq_wifi_init()); 416 417 pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup)); 418 gpiod_add_lookup_table(&smartq_lcd_control_gpiod_table); 419 gpiod_add_lookup_table(&smartq_usb_otg_vbus_gpiod_table); 420 platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices)); 421 422 gpiod_add_lookup_table(&smartq_audio_gpios); 423 platform_device_register_simple("smartq-audio", -1, NULL, 0); 424}