linux/arch/arm/mach-s3c/mach-smartq.c
<<
>>
Prefs
   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}
 425