Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (C) 2010 Maurus Cuelenaere
0004 
0005 #include <linux/delay.h>
0006 #include <linux/fb.h>
0007 #include <linux/gpio.h>
0008 #include <linux/gpio/machine.h>
0009 #include <linux/init.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/pwm.h>
0012 #include <linux/pwm_backlight.h>
0013 #include <linux/serial_core.h>
0014 #include <linux/serial_s3c.h>
0015 #include <linux/spi/spi_gpio.h>
0016 #include <linux/platform_data/s3c-hsotg.h>
0017 
0018 #include <asm/mach-types.h>
0019 #include <asm/mach/map.h>
0020 
0021 #include "map.h"
0022 #include "regs-gpio.h"
0023 #include "gpio-samsung.h"
0024 
0025 #include "cpu.h"
0026 #include "devs.h"
0027 #include <linux/platform_data/i2c-s3c2410.h>
0028 #include "gpio-cfg.h"
0029 #include <linux/platform_data/hwmon-s3c.h>
0030 #include <linux/platform_data/usb-ohci-s3c2410.h>
0031 #include "sdhci.h"
0032 #include <linux/platform_data/touchscreen-s3c2410.h>
0033 
0034 #include <video/platform_lcd.h>
0035 
0036 #include "s3c64xx.h"
0037 #include "mach-smartq.h"
0038 #include "regs-modem-s3c64xx.h"
0039 
0040 #define UCON S3C2410_UCON_DEFAULT
0041 #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
0042 #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
0043 
0044 static struct s3c2410_uartcfg smartq_uartcfgs[] __initdata = {
0045     [0] = {
0046         .hwport      = 0,
0047         .flags       = 0,
0048         .ucon        = UCON,
0049         .ulcon       = ULCON,
0050         .ufcon       = UFCON,
0051     },
0052     [1] = {
0053         .hwport      = 1,
0054         .flags       = 0,
0055         .ucon        = UCON,
0056         .ulcon       = ULCON,
0057         .ufcon       = UFCON,
0058     },
0059     [2] = {
0060         .hwport      = 2,
0061         .flags       = 0,
0062         .ucon        = UCON,
0063         .ulcon       = ULCON,
0064         .ufcon       = UFCON,
0065     },
0066 };
0067 
0068 static void smartq_usb_host_powercontrol(int port, int to)
0069 {
0070     pr_debug("%s(%d, %d)\n", __func__, port, to);
0071 
0072     if (port == 0) {
0073         gpio_set_value(S3C64XX_GPL(0), to);
0074         gpio_set_value(S3C64XX_GPL(1), to);
0075     }
0076 }
0077 
0078 static irqreturn_t smartq_usb_host_ocirq(int irq, void *pw)
0079 {
0080     struct s3c2410_hcd_info *info = pw;
0081 
0082     if (gpio_get_value(S3C64XX_GPL(10)) == 0) {
0083         pr_debug("%s: over-current irq (oc detected)\n", __func__);
0084         s3c2410_usb_report_oc(info, 3);
0085     } else {
0086         pr_debug("%s: over-current irq (oc cleared)\n", __func__);
0087         s3c2410_usb_report_oc(info, 0);
0088     }
0089 
0090     return IRQ_HANDLED;
0091 }
0092 
0093 static void smartq_usb_host_enableoc(struct s3c2410_hcd_info *info, int on)
0094 {
0095     int ret;
0096 
0097     /* This isn't present on a SmartQ 5 board */
0098     if (machine_is_smartq5())
0099         return;
0100 
0101     if (on) {
0102         ret = request_irq(gpio_to_irq(S3C64XX_GPL(10)),
0103                   smartq_usb_host_ocirq,
0104                   IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
0105                   "USB host overcurrent", info);
0106         if (ret != 0)
0107             pr_err("failed to request usb oc irq: %d\n", ret);
0108     } else {
0109         free_irq(gpio_to_irq(S3C64XX_GPL(10)), info);
0110     }
0111 }
0112 
0113 static struct s3c2410_hcd_info smartq_usb_host_info = {
0114     .port[0]    = {
0115         .flags  = S3C_HCDFLG_USED
0116     },
0117     .port[1]    = {
0118         .flags  = 0
0119     },
0120 
0121     .power_control  = smartq_usb_host_powercontrol,
0122     .enable_oc  = smartq_usb_host_enableoc,
0123 };
0124 
0125 static struct gpiod_lookup_table smartq_usb_otg_vbus_gpiod_table = {
0126     .dev_id = "gpio-vbus",
0127     .table = {
0128         GPIO_LOOKUP("GPL", 9, "vbus", GPIO_ACTIVE_LOW),
0129         { },
0130     },
0131 };
0132 
0133 static struct platform_device smartq_usb_otg_vbus_dev = {
0134     .name           = "gpio-vbus",
0135 };
0136 
0137 static struct pwm_lookup smartq_pwm_lookup[] = {
0138     PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL,
0139            1000000000 / (1000 * 20), PWM_POLARITY_NORMAL),
0140 };
0141 
0142 static int smartq_bl_init(struct device *dev)
0143 {
0144     s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
0145 
0146     return 0;
0147 }
0148 
0149 static struct platform_pwm_backlight_data smartq_backlight_data = {
0150     .max_brightness = 1000,
0151     .dft_brightness = 600,
0152     .init       = smartq_bl_init,
0153 };
0154 
0155 static struct platform_device smartq_backlight_device = {
0156     .name       = "pwm-backlight",
0157     .dev        = {
0158         .parent = &samsung_device_pwm.dev,
0159         .platform_data = &smartq_backlight_data,
0160     },
0161 };
0162 
0163 static struct s3c2410_ts_mach_info smartq_touchscreen_pdata __initdata = {
0164     .delay          = 65535,
0165     .presc          = 99,
0166     .oversampling_shift = 4,
0167 };
0168 
0169 static struct s3c_sdhci_platdata smartq_internal_hsmmc_pdata = {
0170     .max_width      = 4,
0171     .cd_type        = S3C_SDHCI_CD_PERMANENT,
0172 };
0173 
0174 static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = {
0175     /* Battery voltage (?-4.2V) */
0176     .in[0] = &(struct s3c_hwmon_chcfg) {
0177         .name       = "smartq:battery-voltage",
0178         .mult       = 3300,
0179         .div        = 2048,
0180     },
0181     /* Reference voltage (1.2V) */
0182     .in[1] = &(struct s3c_hwmon_chcfg) {
0183         .name       = "smartq:reference-voltage",
0184         .mult       = 3300,
0185         .div        = 4096,
0186     },
0187 };
0188 
0189 static struct dwc2_hsotg_plat smartq_hsotg_pdata;
0190 
0191 static int __init smartq_lcd_setup_gpio(void)
0192 {
0193     int ret;
0194 
0195     ret = gpio_request(S3C64XX_GPM(3), "LCD power");
0196     if (ret < 0)
0197         return ret;
0198 
0199     /* turn power off */
0200     gpio_direction_output(S3C64XX_GPM(3), 0);
0201 
0202     return 0;
0203 }
0204 
0205 /* GPM0 -> CS */
0206 static struct spi_gpio_platform_data smartq_lcd_control = {
0207     .num_chipselect = 1,
0208 };
0209 
0210 static struct platform_device smartq_lcd_control_device = {
0211     .name           = "spi_gpio",
0212     .id         = 1,
0213     .dev.platform_data  = &smartq_lcd_control,
0214 };
0215 
0216 static struct gpiod_lookup_table smartq_lcd_control_gpiod_table = {
0217     .dev_id         = "spi_gpio",
0218     .table          = {
0219         GPIO_LOOKUP("GPIOM", 1,
0220                 "sck", GPIO_ACTIVE_HIGH),
0221         GPIO_LOOKUP("GPIOM", 2,
0222                 "mosi", GPIO_ACTIVE_HIGH),
0223         GPIO_LOOKUP("GPIOM", 3,
0224                 "miso", GPIO_ACTIVE_HIGH),
0225         GPIO_LOOKUP("GPIOM", 0,
0226                 "cs", GPIO_ACTIVE_HIGH),
0227         { },
0228     },
0229 };
0230 
0231 static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power)
0232 {
0233     gpio_direction_output(S3C64XX_GPM(3), power);
0234 }
0235 
0236 static struct plat_lcd_data smartq_lcd_power_data = {
0237     .set_power  = smartq_lcd_power_set,
0238 };
0239 
0240 static struct platform_device smartq_lcd_power_device = {
0241     .name           = "platform-lcd",
0242     .dev.parent     = &s3c_device_fb.dev,
0243     .dev.platform_data  = &smartq_lcd_power_data,
0244 };
0245 
0246 static struct i2c_board_info smartq_i2c_devs[] __initdata = {
0247     { I2C_BOARD_INFO("wm8987", 0x1a), },
0248 };
0249 
0250 static struct platform_device *smartq_devices[] __initdata = {
0251     &s3c_device_hsmmc1, /* Init iNAND first, ... */
0252     &s3c_device_hsmmc0, /* ... then the external SD card */
0253     &s3c_device_hsmmc2,
0254     &s3c_device_adc,
0255     &s3c_device_fb,
0256     &s3c_device_hwmon,
0257     &s3c_device_i2c0,
0258     &s3c_device_ohci,
0259     &s3c_device_rtc,
0260     &samsung_device_pwm,
0261     &s3c_device_usb_hsotg,
0262     &s3c64xx_device_iis0,
0263     &smartq_backlight_device,
0264     &smartq_lcd_control_device,
0265     &smartq_lcd_power_device,
0266     &smartq_usb_otg_vbus_dev,
0267 };
0268 
0269 static void __init smartq_lcd_mode_set(void)
0270 {
0271     u32 tmp;
0272 
0273     /* set the LCD type */
0274     tmp = __raw_readl(S3C64XX_SPCON);
0275     tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
0276     tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
0277     __raw_writel(tmp, S3C64XX_SPCON);
0278 
0279     /* remove the LCD bypass */
0280     tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
0281     tmp &= ~MIFPCON_LCD_BYPASS;
0282     __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
0283 }
0284 
0285 static void smartq_power_off(void)
0286 {
0287     gpio_direction_output(S3C64XX_GPK(15), 1);
0288 }
0289 
0290 static int __init smartq_power_off_init(void)
0291 {
0292     int ret;
0293 
0294     ret = gpio_request(S3C64XX_GPK(15), "Power control");
0295     if (ret < 0) {
0296         pr_err("%s: failed to get GPK15\n", __func__);
0297         return ret;
0298     }
0299 
0300     /* leave power on */
0301     gpio_direction_output(S3C64XX_GPK(15), 0);
0302 
0303     pm_power_off = smartq_power_off;
0304 
0305     return ret;
0306 }
0307 
0308 static int __init smartq_usb_host_init(void)
0309 {
0310     int ret;
0311 
0312     ret = gpio_request(S3C64XX_GPL(0), "USB power control");
0313     if (ret < 0) {
0314         pr_err("%s: failed to get GPL0\n", __func__);
0315         return ret;
0316     }
0317 
0318     ret = gpio_request(S3C64XX_GPL(1), "USB host power control");
0319     if (ret < 0) {
0320         pr_err("%s: failed to get GPL1\n", __func__);
0321         goto err;
0322     }
0323 
0324     if (!machine_is_smartq5()) {
0325         /* This isn't present on a SmartQ 5 board */
0326         ret = gpio_request(S3C64XX_GPL(10), "USB host overcurrent");
0327         if (ret < 0) {
0328             pr_err("%s: failed to get GPL10\n", __func__);
0329             goto err2;
0330         }
0331     }
0332 
0333     /* turn power off */
0334     gpio_direction_output(S3C64XX_GPL(0), 0);
0335     gpio_direction_output(S3C64XX_GPL(1), 0);
0336     if (!machine_is_smartq5())
0337         gpio_direction_input(S3C64XX_GPL(10));
0338 
0339     s3c_device_ohci.dev.platform_data = &smartq_usb_host_info;
0340 
0341     return 0;
0342 
0343 err2:
0344     gpio_free(S3C64XX_GPL(1));
0345 err:
0346     gpio_free(S3C64XX_GPL(0));
0347     return ret;
0348 }
0349 
0350 static int __init smartq_wifi_init(void)
0351 {
0352     int ret;
0353 
0354     ret = gpio_request(S3C64XX_GPK(1), "wifi control");
0355     if (ret < 0) {
0356         pr_err("%s: failed to get GPK1\n", __func__);
0357         return ret;
0358     }
0359 
0360     ret = gpio_request(S3C64XX_GPK(2), "wifi reset");
0361     if (ret < 0) {
0362         pr_err("%s: failed to get GPK2\n", __func__);
0363         gpio_free(S3C64XX_GPK(1));
0364         return ret;
0365     }
0366 
0367     /* turn power on */
0368     gpio_direction_output(S3C64XX_GPK(1), 1);
0369 
0370     /* reset device */
0371     gpio_direction_output(S3C64XX_GPK(2), 0);
0372     mdelay(100);
0373     gpio_set_value(S3C64XX_GPK(2), 1);
0374     gpio_direction_input(S3C64XX_GPK(2));
0375 
0376     return 0;
0377 }
0378 
0379 static struct map_desc smartq_iodesc[] __initdata = {};
0380 void __init smartq_map_io(void)
0381 {
0382     s3c64xx_init_io(smartq_iodesc, ARRAY_SIZE(smartq_iodesc));
0383     s3c64xx_set_xtal_freq(12000000);
0384     s3c64xx_set_xusbxti_freq(12000000);
0385     s3c24xx_init_uarts(smartq_uartcfgs, ARRAY_SIZE(smartq_uartcfgs));
0386     s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4);
0387 
0388     smartq_lcd_mode_set();
0389 }
0390 
0391 static struct gpiod_lookup_table smartq_audio_gpios = {
0392     .dev_id = "smartq-audio",
0393     .table = {
0394         GPIO_LOOKUP("GPL", 12, "headphone detect", 0),
0395         GPIO_LOOKUP("GPK", 12, "amplifiers shutdown", 0),
0396         { },
0397     },
0398 };
0399 
0400 void __init smartq_machine_init(void)
0401 {
0402     s3c_i2c0_set_platdata(NULL);
0403     dwc2_hsotg_set_platdata(&smartq_hsotg_pdata);
0404     s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
0405     s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
0406     s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
0407     s3c64xx_ts_set_platdata(&smartq_touchscreen_pdata);
0408 
0409     i2c_register_board_info(0, smartq_i2c_devs,
0410                 ARRAY_SIZE(smartq_i2c_devs));
0411 
0412     WARN_ON(smartq_lcd_setup_gpio());
0413     WARN_ON(smartq_power_off_init());
0414     WARN_ON(smartq_usb_host_init());
0415     WARN_ON(smartq_wifi_init());
0416 
0417     pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup));
0418     gpiod_add_lookup_table(&smartq_lcd_control_gpiod_table);
0419     gpiod_add_lookup_table(&smartq_usb_otg_vbus_gpiod_table);
0420     platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
0421 
0422     gpiod_add_lookup_table(&smartq_audio_gpios);
0423     platform_device_register_simple("smartq-audio", -1, NULL, 0);
0424 }