/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "devices.h" #include "timer.h" #include "msm-keypad-devices.h" #include "acpuclock.h" #include "clock.h" #include "pm.h" #include "irq.h" #include "pm-boot.h" #ifdef CONFIG_USB_ANDROID #include #endif #define TOUCHPAD_SUSPEND 34 #define TOUCHPAD_IRQ 38 #define MSM_PMEM_SF_SIZE 0x1700000 #define SMEM_SPINLOCK_I2C "S:6" #define MSM_PMEM_ADSP_SIZE 0x2A05000 #define MSM_FB_SIZE 0x2EE000 #define MSM_AUDIO_SIZE 0x80000 #ifdef CONFIG_MSM_SOC_REV_A #define MSM_SMI_BASE 0xE0000000 #else #define MSM_SMI_BASE 0x00000000 #endif #define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000) #define MSM_PMEM_SMI_BASE (MSM_SMI_BASE + 0x02B00000) #define MSM_PMEM_SMI_SIZE 0x01500000 #define MSM_FB_BASE MSM_PMEM_SMI_BASE #define MSM_PMEM_SMIPOOL_BASE (MSM_FB_BASE + MSM_FB_SIZE) #define MSM_PMEM_SMIPOOL_SIZE (MSM_PMEM_SMI_SIZE - MSM_FB_SIZE) #define PMEM_KERNEL_EBI1_SIZE 0x28000 #define PMIC_VREG_WLAN_LEVEL 2600 #define PMIC_VREG_GP6_LEVEL 2900 #define FPGA_SDCC_STATUS 0x70000280 static struct resource smc91x_resources[] = { [0] = { .flags = IORESOURCE_MEM, }, [1] = { .flags = IORESOURCE_IRQ, }, }; #ifdef CONFIG_USB_FUNCTION static struct usb_mass_storage_platform_data usb_mass_storage_pdata = { .nluns = 0x02, .buf_size = 16384, .vendor = "GOOGLE", .product = "Mass storage", .release = 0xffff, }; static struct platform_device mass_storage_device = { .name = "usb_mass_storage", .id = -1, .dev = { .platform_data = &usb_mass_storage_pdata, }, }; #endif #ifdef CONFIG_USB_ANDROID static char *usb_functions_default[] = { "diag", "modem", "nmea", "rmnet", "usb_mass_storage", }; static char *usb_functions_default_adb[] = { "diag", "adb", "modem", "nmea", "rmnet", "usb_mass_storage", }; static char *usb_functions_rndis[] = { "rndis", }; static char *usb_functions_rndis_adb[] = { "rndis", "adb", }; static char *usb_functions_all[] = { #ifdef CONFIG_USB_ANDROID_RNDIS "rndis", #endif #ifdef CONFIG_USB_ANDROID_DIAG "diag", #endif "adb", #ifdef CONFIG_USB_F_SERIAL "modem", "nmea", #endif #ifdef CONFIG_USB_ANDROID_RMNET "rmnet", #endif "usb_mass_storage", #ifdef CONFIG_USB_ANDROID_ACM "acm", #endif }; static struct android_usb_product usb_products[] = { { .product_id = 0x9026, .num_functions = ARRAY_SIZE(usb_functions_default), .functions = usb_functions_default, }, { .product_id = 0x9025, .num_functions = ARRAY_SIZE(usb_functions_default_adb), .functions = usb_functions_default_adb, }, { .product_id = 0xf00e, .num_functions = ARRAY_SIZE(usb_functions_rndis), .functions = usb_functions_rndis, }, { .product_id = 0x9024, .num_functions = ARRAY_SIZE(usb_functions_rndis_adb), .functions = usb_functions_rndis_adb, }, }; static struct usb_mass_storage_platform_data mass_storage_pdata = { .nluns = 1, .vendor = "Qualcomm Incorporated", .product = "Mass storage", .release = 0x0100, }; static struct platform_device usb_mass_storage_device = { .name = "usb_mass_storage", .id = -1, .dev = { .platform_data = &mass_storage_pdata, }, }; static struct usb_ether_platform_data rndis_pdata = { /* ethaddr is filled by board_serialno_setup */ .vendorID = 0x05C6, .vendorDescr = "Qualcomm Incorporated", }; static struct platform_device rndis_device = { .name = "rndis", .id = -1, .dev = { .platform_data = &rndis_pdata, }, }; static struct android_usb_platform_data android_usb_pdata = { .vendor_id = 0x05C6, .product_id = 0x9026, .version = 0x0100, .product_name = "Qualcomm HSUSB Device", .manufacturer_name = "Qualcomm Incorporated", .num_products = ARRAY_SIZE(usb_products), .products = usb_products, .num_functions = ARRAY_SIZE(usb_functions_all), .functions = usb_functions_all, .serial_number = "1234567890ABCDEF", }; static struct platform_device android_usb_device = { .name = "android_usb", .id = -1, .dev = { .platform_data = &android_usb_pdata, }, }; static int __init board_serialno_setup(char *serialno) { int i; char *src = serialno; /* create a fake MAC address from our serial number. * first byte is 0x02 to signify locally administered. */ rndis_pdata.ethaddr[0] = 0x02; for (i = 0; *src; i++) { /* XOR the USB serial across the remaining bytes */ rndis_pdata.ethaddr[i % (ETH_ALEN - 1) + 1] ^= *src++; } android_usb_pdata.serial_number = serialno; return 1; } __setup("androidboot.serialno=", board_serialno_setup); #endif static struct platform_device smc91x_device = { .name = "smc91x", .id = 0, .num_resources = ARRAY_SIZE(smc91x_resources), .resource = smc91x_resources, }; #ifdef CONFIG_USB_FUNCTION static struct usb_function_map usb_functions_map[] = { {"diag", 0}, {"adb", 1}, {"modem", 2}, {"nmea", 3}, {"mass_storage", 4}, {"ethernet", 5}, }; /* dynamic composition */ static struct usb_composition usb_func_composition[] = { { .product_id = 0x9012, .functions = 0x5, /* 0101 */ }, { .product_id = 0x9013, .functions = 0x15, /* 10101 */ }, { .product_id = 0x9014, .functions = 0x30, /* 110000 */ }, { .product_id = 0x9015, .functions = 0x12, /* 10010 */ }, { .product_id = 0x9016, .functions = 0xD, /* 01101 */ }, { .product_id = 0x9017, .functions = 0x1D, /* 11101 */ }, { .product_id = 0xF000, .functions = 0x10, /* 10000 */ }, { .product_id = 0xF009, .functions = 0x20, /* 100000 */ }, { .product_id = 0x9018, .functions = 0x1F, /* 011111 */ }, { .product_id = 0x901A, .functions = 0x0F, /* 01111 */ }, }; #endif static struct msm_handset_platform_data hs_platform_data = { .hs_name = "8k_handset", .pwr_key_delay_ms = 500, /* 0 will disable end key */ }; static struct platform_device hs_device = { .name = "msm-handset", .id = -1, .dev = { .platform_data = &hs_platform_data, }, }; #ifdef CONFIG_USB_FS_HOST static struct msm_gpio fsusb_config[] = { { GPIO_CFG(139, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "fs_dat" }, { GPIO_CFG(140, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "fs_se0" }, { GPIO_CFG(141, 3, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "fs_oe_n" }, }; static int fsusb_gpio_init(void) { return msm_gpios_request(fsusb_config, ARRAY_SIZE(fsusb_config)); } static void msm_fsusb_setup_gpio(unsigned int enable) { if (enable) msm_gpios_enable(fsusb_config, ARRAY_SIZE(fsusb_config)); else msm_gpios_disable(fsusb_config, ARRAY_SIZE(fsusb_config)); } #endif #define MSM_USB_BASE ((unsigned)addr) static struct msm_hsusb_platform_data msm_hsusb_pdata = { #ifdef CONFIG_USB_FUNCTION .version = 0x0100, .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM), .vendor_id = 0x5c6, .product_name = "Qualcomm HSUSB Device", .serial_number = "1234567890ABCDEF", .manufacturer_name = "Qualcomm Incorporated", .compositions = usb_func_composition, .num_compositions = ARRAY_SIZE(usb_func_composition), .function_map = usb_functions_map, .num_functions = ARRAY_SIZE(usb_functions_map), .config_gpio = NULL, #endif }; static struct vreg *vreg_usb; static void msm_hsusb_vbus_power(unsigned phy_info, int on) { switch (PHY_TYPE(phy_info)) { case USB_PHY_INTEGRATED: if (on) msm_hsusb_vbus_powerup(); else msm_hsusb_vbus_shutdown(); break; case USB_PHY_SERIAL_PMIC: if (on) vreg_enable(vreg_usb); else vreg_disable(vreg_usb); break; default: pr_err("%s: undefined phy type ( %X ) \n", __func__, phy_info); } } static struct msm_usb_host_platform_data msm_usb_host_pdata = { .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM), }; #ifdef CONFIG_USB_FS_HOST static struct msm_usb_host_platform_data msm_usb_host2_pdata = { .phy_info = USB_PHY_SERIAL_PMIC, .config_gpio = msm_fsusb_setup_gpio, .vbus_power = msm_hsusb_vbus_power, }; #endif static struct android_pmem_platform_data android_pmem_kernel_ebi1_pdata = { .name = PMEM_KERNEL_EBI1_DATA_NAME, /* if no allocator_type, defaults to PMEM_ALLOCATORTYPE_BITMAP, * the only valid choice at this time. The board structure is * set to all zeros by the C runtime initialization and that is now * the enum value of PMEM_ALLOCATORTYPE_BITMAP, now forced to 0 in * include/linux/android_pmem.h. */ .cached = 0, }; #ifdef CONFIG_KERNEL_PMEM_SMI_REGION static struct android_pmem_platform_data android_pmem_kernel_smi_pdata = { .name = PMEM_KERNEL_SMI_DATA_NAME, /* if no allocator_type, defaults to PMEM_ALLOCATORTYPE_BITMAP, * the only valid choice at this time. The board structure is * set to all zeros by the C runtime initialization and that is now * the enum value of PMEM_ALLOCATORTYPE_BITMAP, now forced to 0 in * include/linux/android_pmem.h. */ .cached = 0, }; #endif static struct android_pmem_platform_data android_pmem_pdata = { .name = "pmem", .allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING, .cached = 1, }; static struct android_pmem_platform_data android_pmem_adsp_pdata = { .name = "pmem_adsp", .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, .cached = 0, }; static struct android_pmem_platform_data android_pmem_smipool_pdata = { .name = "pmem_smipool", .size = MSM_PMEM_SMIPOOL_SIZE, .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, .cached = 0, }; static struct platform_device android_pmem_device = { .name = "android_pmem", .id = 0, .dev = { .platform_data = &android_pmem_pdata }, }; static struct platform_device android_pmem_adsp_device = { .name = "android_pmem", .id = 1, .dev = { .platform_data = &android_pmem_adsp_pdata }, }; static struct platform_device android_pmem_smipool_device = { .name = "android_pmem", .id = 2, .dev = { .platform_data = &android_pmem_smipool_pdata }, }; static struct platform_device android_pmem_kernel_ebi1_device = { .name = "android_pmem", .id = 3, .dev = { .platform_data = &android_pmem_kernel_ebi1_pdata }, }; #ifdef CONFIG_KERNEL_PMEM_SMI_REGION static struct platform_device android_pmem_kernel_smi_device = { .name = "android_pmem", .id = 4, .dev = { .platform_data = &android_pmem_kernel_smi_pdata }, }; #endif static struct resource msm_fb_resources[] = { { .flags = IORESOURCE_DMA, } }; static int msm_fb_detect_panel(const char *name) { int ret = -EPERM; if (machine_is_qsd8x50_ffa()) { if (!strncmp(name, "mddi_toshiba_wvga_pt", 20)) ret = 0; else ret = -ENODEV; } else if ((machine_is_qsd8x50_surf()) && !strcmp(name, "lcdc_external")) ret = 0; return ret; } static struct msm_fb_platform_data msm_fb_pdata = { .detect_client = msm_fb_detect_panel, }; static struct platform_device msm_fb_device = { .name = "msm_fb", .id = 0, .num_resources = ARRAY_SIZE(msm_fb_resources), .resource = msm_fb_resources, .dev = { .platform_data = &msm_fb_pdata, } }; static struct msm_gpio bma_spi_gpio_config_data[] = { { GPIO_CFG(22, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "bma_irq" }, }; static int msm_bma_gpio_setup(struct device *dev) { int rc; rc = msm_gpios_request_enable(bma_spi_gpio_config_data, ARRAY_SIZE(bma_spi_gpio_config_data)); return rc; } static void msm_bma_gpio_teardown(struct device *dev) { msm_gpios_disable_free(bma_spi_gpio_config_data, ARRAY_SIZE(bma_spi_gpio_config_data)); } static struct bma150_platform_data bma_pdata = { .setup = msm_bma_gpio_setup, .teardown = msm_bma_gpio_teardown, }; static struct resource qsd_spi_resources[] = { { .name = "spi_irq_in", .start = INT_SPI_INPUT, .end = INT_SPI_INPUT, .flags = IORESOURCE_IRQ, }, { .name = "spi_irq_out", .start = INT_SPI_OUTPUT, .end = INT_SPI_OUTPUT, .flags = IORESOURCE_IRQ, }, { .name = "spi_irq_err", .start = INT_SPI_ERROR, .end = INT_SPI_ERROR, .flags = IORESOURCE_IRQ, }, { .name = "spi_base", .start = 0xA1200000, .end = 0xA1200000 + SZ_4K - 1, .flags = IORESOURCE_MEM, }, { .name = "spidm_channels", .flags = IORESOURCE_DMA, }, { .name = "spidm_crci", .flags = IORESOURCE_DMA, }, }; static struct platform_device qsd_device_spi = { .name = "spi_qsd", .id = 0, .num_resources = ARRAY_SIZE(qsd_spi_resources), .resource = qsd_spi_resources, }; static struct spi_board_info msm_spi_board_info[] __initdata = { { .modalias = "bma150", .mode = SPI_MODE_3, .irq = MSM_GPIO_TO_INT(22), .bus_num = 0, .chip_select = 0, .max_speed_hz = 10000000, .platform_data = &bma_pdata, }, }; #define CT_CSR_PHYS 0xA8700000 #define TCSR_SPI_MUX (ct_csr_base + 0x54) static int msm_qsd_spi_dma_config(void) { void __iomem *ct_csr_base = 0; u32 spi_mux; int ret = 0; ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE); if (!ct_csr_base) { pr_err("%s: Could not remap %x\n", __func__, CT_CSR_PHYS); return -1; } spi_mux = readl(TCSR_SPI_MUX); switch (spi_mux) { case (1): qsd_spi_resources[4].start = DMOV_HSUART1_RX_CHAN; qsd_spi_resources[4].end = DMOV_HSUART1_TX_CHAN; qsd_spi_resources[5].start = DMOV_HSUART1_RX_CRCI; qsd_spi_resources[5].end = DMOV_HSUART1_TX_CRCI; break; case (2): qsd_spi_resources[4].start = DMOV_HSUART2_RX_CHAN; qsd_spi_resources[4].end = DMOV_HSUART2_TX_CHAN; qsd_spi_resources[5].start = DMOV_HSUART2_RX_CRCI; qsd_spi_resources[5].end = DMOV_HSUART2_TX_CRCI; break; case (3): qsd_spi_resources[4].start = DMOV_CE_OUT_CHAN; qsd_spi_resources[4].end = DMOV_CE_IN_CHAN; qsd_spi_resources[5].start = DMOV_CE_OUT_CRCI; qsd_spi_resources[5].end = DMOV_CE_IN_CRCI; break; default: ret = -1; } iounmap(ct_csr_base); return ret; } static struct msm_gpio qsd_spi_gpio_config_data[] = { { GPIO_CFG(17, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_clk" }, { GPIO_CFG(18, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_mosi" }, { GPIO_CFG(19, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_miso" }, { GPIO_CFG(20, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_cs0" }, { GPIO_CFG(21, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_16MA), "spi_pwr" }, }; static int msm_qsd_spi_gpio_config(void) { int rc; rc = msm_gpios_request_enable(qsd_spi_gpio_config_data, ARRAY_SIZE(qsd_spi_gpio_config_data)); if (rc) return rc; /* Set direction for SPI_PWR */ gpio_direction_output(21, 1); return 0; } static void msm_qsd_spi_gpio_release(void) { msm_gpios_disable_free(qsd_spi_gpio_config_data, ARRAY_SIZE(qsd_spi_gpio_config_data)); } static struct msm_spi_platform_data qsd_spi_pdata = { .max_clock_speed = 19200000, .gpio_config = msm_qsd_spi_gpio_config, .gpio_release = msm_qsd_spi_gpio_release, .dma_config = msm_qsd_spi_dma_config, }; static void __init msm_qsd_spi_init(void) { qsd_device_spi.dev.platform_data = &qsd_spi_pdata; } static int mddi_toshiba_pmic_bl(int level) { int ret = -EPERM; if (machine_is_qsd8x50_ffa()) { ret = pmic_set_led_intensity(LED_LCD, level); if (ret) printk(KERN_WARNING "%s: can't set lcd backlight!\n", __func__); } return ret; } static struct msm_panel_common_pdata mddi_toshiba_pdata = { .pmic_backlight = mddi_toshiba_pmic_bl, }; static struct platform_device mddi_toshiba_device = { .name = "mddi_toshiba", .id = 0, .dev = { .platform_data = &mddi_toshiba_pdata, } }; static void msm_fb_vreg_config(const char *name, int on) { struct vreg *vreg; int ret = 0; vreg = vreg_get(NULL, name); if (IS_ERR(vreg)) { printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n", __func__, name, PTR_ERR(vreg)); return; } ret = (on) ? vreg_enable(vreg) : vreg_disable(vreg); if (ret) printk(KERN_ERR "%s: %s(%s) failed!\n", __func__, (on) ? "vreg_enable" : "vreg_disable", name); } #define MDDI_RST_OUT_GPIO 100 static int mddi_power_save_on; static int msm_fb_mddi_power_save(int on) { int flag_on = !!on; int ret = 0; if (mddi_power_save_on == flag_on) return ret; mddi_power_save_on = flag_on; if (!flag_on && machine_is_qsd8x50_ffa()) { gpio_set_value(MDDI_RST_OUT_GPIO, 0); mdelay(1); } ret = pmic_lp_mode_control(flag_on ? OFF_CMD : ON_CMD, PM_VREG_LP_MSME2_ID); if (ret) printk(KERN_ERR "%s: pmic_lp_mode_control failed!\n", __func__); msm_fb_vreg_config("gp5", flag_on); msm_fb_vreg_config("boost", flag_on); if (flag_on && machine_is_qsd8x50_ffa()) { gpio_set_value(MDDI_RST_OUT_GPIO, 0); mdelay(1); gpio_set_value(MDDI_RST_OUT_GPIO, 1); gpio_set_value(MDDI_RST_OUT_GPIO, 1); mdelay(1); } return ret; } static int msm_fb_mddi_sel_clk(u32 *clk_rate) { *clk_rate *= 2; return 0; } static struct mddi_platform_data mddi_pdata = { .mddi_power_save = msm_fb_mddi_power_save, .mddi_sel_clk = msm_fb_mddi_sel_clk, }; static struct msm_panel_common_pdata mdp_pdata = { .gpio = 98, .mdp_rev = MDP_REV_31, }; static void __init msm_fb_add_devices(void) { msm_fb_register_device("mdp", &mdp_pdata); msm_fb_register_device("pmdh", &mddi_pdata); msm_fb_register_device("emdh", &mddi_pdata); msm_fb_register_device("tvenc", 0); msm_fb_register_device("lcdc", 0); } static struct resource msm_audio_resources[] = { { .flags = IORESOURCE_DMA, }, { .name = "aux_pcm_dout", .start = 68, .end = 68, .flags = IORESOURCE_IO, }, { .name = "aux_pcm_din", .start = 69, .end = 69, .flags = IORESOURCE_IO, }, { .name = "aux_pcm_syncout", .start = 70, .end = 70, .flags = IORESOURCE_IO, }, { .name = "aux_pcm_clkin_a", .start = 71, .end = 71, .flags = IORESOURCE_IO, }, { .name = "sdac_din", .start = 144, .end = 144, .flags = IORESOURCE_IO, }, { .name = "sdac_dout", .start = 145, .end = 145, .flags = IORESOURCE_IO, }, { .name = "sdac_wsout", .start = 143, .end = 143, .flags = IORESOURCE_IO, }, { .name = "cc_i2s_clk", .start = 142, .end = 142, .flags = IORESOURCE_IO, }, { .name = "audio_master_clkout", .start = 146, .end = 146, .flags = IORESOURCE_IO, }, { .name = "audio_base_addr", .start = 0xa0700000, .end = 0xa0700000 + 4, .flags = IORESOURCE_MEM, }, }; static unsigned audio_gpio_on[] = { GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* PCM_DOUT */ GPIO_CFG(69, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* PCM_DIN */ GPIO_CFG(70, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* PCM_SYNC */ GPIO_CFG(71, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* PCM_CLK */ GPIO_CFG(142, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* CC_I2S_CLK */ GPIO_CFG(143, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* SADC_WSOUT */ GPIO_CFG(144, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* SADC_DIN */ GPIO_CFG(145, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* SDAC_DOUT */ GPIO_CFG(146, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* MA_CLK_OUT */ }; static void __init audio_gpio_init(void) { int pin, rc; for (pin = 0; pin < ARRAY_SIZE(audio_gpio_on); pin++) { rc = gpio_tlmm_config(audio_gpio_on[pin], GPIO_CFG_ENABLE); if (rc) { printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", __func__, audio_gpio_on[pin], rc); return; } } } static struct platform_device msm_audio_device = { .name = "msm_audio", .id = 0, .num_resources = ARRAY_SIZE(msm_audio_resources), .resource = msm_audio_resources, }; static struct resource bluesleep_resources[] = { { .name = "gpio_host_wake", .start = 21, .end = 21, .flags = IORESOURCE_IO, }, { .name = "gpio_ext_wake", .start = 19, .end = 19, .flags = IORESOURCE_IO, }, { .name = "host_wake", .start = MSM_GPIO_TO_INT(21), .end = MSM_GPIO_TO_INT(21), .flags = IORESOURCE_IRQ, }, }; static struct platform_device msm_bluesleep_device = { .name = "bluesleep", .id = -1, .num_resources = ARRAY_SIZE(bluesleep_resources), .resource = bluesleep_resources, }; #ifdef CONFIG_BT static struct platform_device msm_bt_power_device = { .name = "bt_power", }; enum { BT_SYSRST, BT_WAKE, BT_HOST_WAKE, BT_VDD_IO, BT_RFR, BT_CTS, BT_RX, BT_TX, BT_VDD_FREG }; static struct msm_gpio bt_config_power_off[] = { { GPIO_CFG(18, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "BT SYSRST" }, { GPIO_CFG(19, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "BT WAKE" }, { GPIO_CFG(21, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "HOST WAKE" }, { GPIO_CFG(22, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "BT VDD_IO" }, { GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART1DM_RFR" }, { GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART1DM_CTS" }, { GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART1DM_RX" }, { GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART1DM_TX" } }; static struct msm_gpio bt_config_power_on[] = { { GPIO_CFG(18, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "BT SYSRST" }, { GPIO_CFG(19, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "BT WAKE" }, { GPIO_CFG(21, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "HOST WAKE" }, { GPIO_CFG(22, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "BT VDD_IO" }, { GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "UART1DM_RFR" }, { GPIO_CFG(44, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "UART1DM_CTS" }, { GPIO_CFG(45, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "UART1DM_RX" }, { GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "UART1DM_TX" } }; static struct msm_gpio wlan_config_power_off[] = { { GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "SDC2_CLK" }, { GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "SDC2_CMD" }, { GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "SDC2_D3" }, { GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "SDC2_D2" }, { GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "SDC2_D1" }, { GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "SDC2_D0" }, { GPIO_CFG(113, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "VDD_WLAN" }, { GPIO_CFG(138, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "WLAN_PWD" } }; static struct msm_gpio wlan_config_power_on[] = { { GPIO_CFG(62, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "SDC2_CLK" }, { GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "SDC2_CMD" }, { GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "SDC2_D3" }, { GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "SDC2_D2" }, { GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "SDC2_D1" }, { GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "SDC2_D0" }, { GPIO_CFG(113, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "VDD_WLAN" }, { GPIO_CFG(138, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "WLAN_PWD" } }; static int bluetooth_power(int on) { int rc; struct vreg *vreg_wlan; vreg_wlan = vreg_get(NULL, "wlan"); if (IS_ERR(vreg_wlan)) { printk(KERN_ERR "%s: vreg get failed (%ld)\n", __func__, PTR_ERR(vreg_wlan)); return PTR_ERR(vreg_wlan); } if (on) { /* units of mV, steps of 50 mV */ rc = vreg_set_level(vreg_wlan, PMIC_VREG_WLAN_LEVEL); if (rc) { printk(KERN_ERR "%s: vreg wlan set level failed (%d)\n", __func__, rc); return -EIO; } rc = vreg_enable(vreg_wlan); if (rc) { printk(KERN_ERR "%s: vreg wlan enable failed (%d)\n", __func__, rc); return -EIO; } rc = msm_gpios_enable(bt_config_power_on, ARRAY_SIZE(bt_config_power_on)); if (rc < 0) { printk(KERN_ERR "%s: bt power on gpio config failed: %d\n", __func__, rc); return rc; } if (machine_is_qsd8x50_ffa()) { rc = msm_gpios_enable (wlan_config_power_on, ARRAY_SIZE(wlan_config_power_on)); if (rc < 0) { printk (KERN_ERR "%s: wlan power on gpio config failed: %d\n", __func__, rc); return rc; } } gpio_set_value(22, on); /* VDD_IO */ gpio_set_value(18, on); /* SYSRST */ if (machine_is_qsd8x50_ffa()) { gpio_set_value(138, 0); /* WLAN: CHIP_PWD */ gpio_set_value(113, on); /* WLAN */ } } else { if (machine_is_qsd8x50_ffa()) { gpio_set_value(138, on); /* WLAN: CHIP_PWD */ gpio_set_value(113, on); /* WLAN */ } gpio_set_value(18, on); /* SYSRST */ gpio_set_value(22, on); /* VDD_IO */ rc = vreg_disable(vreg_wlan); if (rc) { printk(KERN_ERR "%s: vreg wlan disable failed (%d)\n", __func__, rc); return -EIO; } rc = msm_gpios_enable(bt_config_power_off, ARRAY_SIZE(bt_config_power_off)); if (rc < 0) { printk(KERN_ERR "%s: bt power off gpio config failed: %d\n", __func__, rc); return rc; } if (machine_is_qsd8x50_ffa()) { rc = msm_gpios_enable (wlan_config_power_off, ARRAY_SIZE(wlan_config_power_off)); if (rc < 0) { printk (KERN_ERR "%s: wlan power off gpio config failed: %d\n", __func__, rc); return rc; } } } printk(KERN_DEBUG "Bluetooth power switch: %d\n", on); return 0; } static void __init bt_power_init(void) { struct vreg *vreg_bt; int rc; if (machine_is_qsd8x50_ffa()) { gpio_set_value(138, 0); /* WLAN: CHIP_PWD */ gpio_set_value(113, 0); /* WLAN */ } gpio_set_value(18, 0); /* SYSRST */ gpio_set_value(22, 0); /* VDD_IO */ /* do not have vreg bt defined, gp6 is the same */ /* vreg_get parameter 1 (struct device *) is ignored */ vreg_bt = vreg_get(NULL, "gp6"); if (IS_ERR(vreg_bt)) { printk(KERN_ERR "%s: vreg get failed (%ld)\n", __func__, PTR_ERR(vreg_bt)); goto exit; } /* units of mV, steps of 50 mV */ rc = vreg_set_level(vreg_bt, PMIC_VREG_GP6_LEVEL); if (rc) { printk(KERN_ERR "%s: vreg bt set level failed (%d)\n", __func__, rc); goto exit; } rc = vreg_enable(vreg_bt); if (rc) { printk(KERN_ERR "%s: vreg bt enable failed (%d)\n", __func__, rc); goto exit; } if (bluetooth_power(0)) goto exit; msm_bt_power_device.dev.platform_data = &bluetooth_power; printk(KERN_DEBUG "Bluetooth power switch: initialized\n"); exit: return; } #else #define bt_power_init(x) do {} while (0) #endif static struct platform_device msm_device_pmic_leds = { .name = "pmic-leds", .id = -1, }; /* TSIF begin */ #if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) #define TSIF_A_SYNC GPIO_CFG(106, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA) #define TSIF_A_DATA GPIO_CFG(107, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA) #define TSIF_A_EN GPIO_CFG(108, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA) #define TSIF_A_CLK GPIO_CFG(109, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA) static const struct msm_gpio tsif_gpios[] = { { .gpio_cfg = TSIF_A_CLK, .label = "tsif_clk", }, { .gpio_cfg = TSIF_A_EN, .label = "tsif_en", }, { .gpio_cfg = TSIF_A_DATA, .label = "tsif_data", }, { .gpio_cfg = TSIF_A_SYNC, .label = "tsif_sync", }, }; static struct msm_tsif_platform_data tsif_platform_data = { .num_gpios = ARRAY_SIZE(tsif_gpios), .gpios = tsif_gpios, .tsif_clk = "core_clk", .tsif_ref_clk = "ref_clk", }; #endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */ /* TSIF end */ static void touchpad_gpio_release(void) { gpio_free(TOUCHPAD_IRQ); gpio_free(TOUCHPAD_SUSPEND); } static int touchpad_gpio_setup(void) { int rc; int suspend_pin = TOUCHPAD_SUSPEND; int irq_pin = TOUCHPAD_IRQ; unsigned suspend_cfg = GPIO_CFG(suspend_pin, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA); unsigned irq_cfg = GPIO_CFG(irq_pin, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA); rc = gpio_request(irq_pin, "msm_touchpad_irq"); if (rc) { pr_err("gpio_request failed on pin %d (rc=%d)\n", irq_pin, rc); goto err_gpioconfig; } rc = gpio_request(suspend_pin, "msm_touchpad_suspend"); if (rc) { pr_err("gpio_request failed on pin %d (rc=%d)\n", suspend_pin, rc); goto err_gpioconfig; } rc = gpio_tlmm_config(suspend_cfg, GPIO_CFG_ENABLE); if (rc) { pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", suspend_pin, rc); goto err_gpioconfig; } rc = gpio_tlmm_config(irq_cfg, GPIO_CFG_ENABLE); if (rc) { pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", irq_pin, rc); goto err_gpioconfig; } return rc; err_gpioconfig: touchpad_gpio_release(); return rc; } static struct msm_touchpad_platform_data msm_touchpad_data = { .gpioirq = TOUCHPAD_IRQ, .gpiosuspend = TOUCHPAD_SUSPEND, .gpio_setup = touchpad_gpio_setup, .gpio_shutdown = touchpad_gpio_release }; #define KBD_RST 35 #define KBD_IRQ 36 static void kbd_gpio_release(void) { gpio_free(KBD_IRQ); gpio_free(KBD_RST); } static int kbd_gpio_setup(void) { int rc; int respin = KBD_RST; int irqpin = KBD_IRQ; unsigned rescfg = GPIO_CFG(respin, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA); unsigned irqcfg = GPIO_CFG(irqpin, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA); rc = gpio_request(irqpin, "gpio_keybd_irq"); if (rc) { pr_err("gpio_request failed on pin %d (rc=%d)\n", irqpin, rc); goto err_gpioconfig; } rc = gpio_request(respin, "gpio_keybd_reset"); if (rc) { pr_err("gpio_request failed on pin %d (rc=%d)\n", respin, rc); goto err_gpioconfig; } rc = gpio_tlmm_config(rescfg, GPIO_CFG_ENABLE); if (rc) { pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", respin, rc); goto err_gpioconfig; } rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE); if (rc) { pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", irqpin, rc); goto err_gpioconfig; } return rc; err_gpioconfig: kbd_gpio_release(); return rc; } /* use gpio output pin to toggle keyboard external reset pin */ static void kbd_hwreset(int kbd_mclrpin) { gpio_direction_output(kbd_mclrpin, 0); gpio_direction_output(kbd_mclrpin, 1); } static struct msm_i2ckbd_platform_data msm_kybd_data = { .hwrepeat = 0, .scanset1 = 1, .gpioreset = KBD_RST, .gpioirq = KBD_IRQ, .gpio_setup = kbd_gpio_setup, .gpio_shutdown = kbd_gpio_release, .hw_reset = kbd_hwreset, }; static struct i2c_board_info msm_i2c_board_info[] __initdata = { { I2C_BOARD_INFO("glidesensor", 0x2A), .irq = MSM_GPIO_TO_INT(TOUCHPAD_IRQ), .platform_data = &msm_touchpad_data }, { I2C_BOARD_INFO("msm-i2ckbd", 0x3A), .type = "msm-i2ckbd", .irq = MSM_GPIO_TO_INT(KBD_IRQ), .platform_data = &msm_kybd_data }, #if defined(CONFIG_SENSORS_MT9T013) { I2C_BOARD_INFO("mt9t013", 0x6C), }, #endif { I2C_BOARD_INFO("tps65023", 0x48), }, }; static u32 msm_calculate_batt_capacity(u32 current_voltage); static struct msm_psy_batt_pdata msm_psy_batt_data = { .voltage_min_design = 3200, .voltage_max_design = 4200, .avail_chg_sources = AC_CHG | USB_CHG , .batt_technology = POWER_SUPPLY_TECHNOLOGY_LION, .calculate_capacity = &msm_calculate_batt_capacity, }; static u32 msm_calculate_batt_capacity(u32 current_voltage) { u32 low_voltage = msm_psy_batt_data.voltage_min_design; u32 high_voltage = msm_psy_batt_data.voltage_max_design; return (current_voltage - low_voltage) * 100 / (high_voltage - low_voltage); } static struct platform_device msm_batt_device = { .name = "msm-battery", .id = -1, .dev.platform_data = &msm_psy_batt_data, }; static int hsusb_rpc_connect(int connect) { if (connect) return msm_hsusb_rpc_connect(); else return msm_hsusb_rpc_close(); } static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init) { int ret; if (init) { ret = msm_pm_app_rpc_init(callback); } else { msm_pm_app_rpc_deinit(callback); ret = 0; } return ret; } static int msm_hsusb_ldo_init(int init); static int msm_hsusb_ldo_enable(int enable); static struct msm_otg_platform_data msm_otg_pdata = { .rpc_connect = hsusb_rpc_connect, .pmic_vbus_notif_init = msm_hsusb_pmic_notif_init, .pemp_level = PRE_EMPHASIS_WITH_10_PERCENT, .cdr_autoreset = CDR_AUTO_RESET_DEFAULT, .drv_ampl = HS_DRV_AMPLITUDE_5_PERCENT, .vbus_power = msm_hsusb_vbus_power, .chg_vbus_draw = hsusb_chg_vbus_draw, .chg_connected = hsusb_chg_connected, .chg_init = hsusb_chg_init, .phy_can_powercollapse = 1, .ldo_init = msm_hsusb_ldo_init, .ldo_enable = msm_hsusb_ldo_enable, }; static struct msm_hsusb_gadget_platform_data msm_gadget_pdata; static struct platform_device *devices[] __initdata = { &msm_fb_device, &mddi_toshiba_device, &smc91x_device, &msm_device_smd, &msm_device_dmov, &android_pmem_kernel_ebi1_device, #ifdef CONFIG_KERNEL_PMEM_SMI_REGION &android_pmem_kernel_smi_device, #endif &android_pmem_device, &android_pmem_adsp_device, &android_pmem_smipool_device, &msm_device_nand, &msm_device_i2c, &qsd_device_spi, #ifdef CONFIG_USB_FUNCTION &mass_storage_device, #endif #ifdef CONFIG_USB_ANDROID &usb_mass_storage_device, &rndis_device, #ifdef CONFIG_USB_ANDROID_DIAG &usb_diag_device, #endif #ifdef CONFIG_USB_F_SERIAL &usb_gadget_fserial_device, #endif &android_usb_device, #endif &msm_device_tssc, &msm_audio_device, &msm_device_uart_dm1, &msm_bluesleep_device, #ifdef CONFIG_BT &msm_bt_power_device, #endif &msm_device_uart3, &msm_device_pmic_leds, &msm_kgsl_3d0, &hs_device, #if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) &msm_device_tsif, #endif &msm_batt_device, }; static void __init qsd8x50_init_irq(void) { msm_init_irq(); msm_init_sirc(); } static void usb_mpp_init(void) { unsigned rc; unsigned mpp_usb = 20; if (machine_is_qsd8x50_ffa()) { rc = mpp_config_digital_out(mpp_usb, MPP_CFG(MPP_DLOGIC_LVL_VDD, MPP_DLOGIC_OUT_CTRL_HIGH)); if (rc) pr_err("%s: configuring mpp pin" "to enable 3.3V LDO failed\n", __func__); } } /* TBD: 8x50 FFAs have internal 3p3 voltage regulator as opposed to * external 3p3 voltage regulator on Surf platform. There is no way * s/w can detect fi concerned regulator is internal or external to * to MSM. Internal 3p3 regulator is powered through boost voltage * regulator where as external 3p3 regulator is powered through VPH. * So for internal voltage regulator it is required to power on * boost voltage regulator first. Unfortunately some of the FFAs are * re-worked to install external 3p3 regulator. For now, assuming all * FFAs have 3p3 internal regulators and all SURFs have external 3p3 * regulator as there is no way s/w can determine if theregulator is * internal or external. May be, we can implement this flag as kernel * boot parameters so that we can change code behaviour dynamically */ static int regulator_3p3_is_internal; static struct vreg *vreg_5v; static struct vreg *vreg_3p3; static int msm_hsusb_ldo_init(int init) { if (init) { if (regulator_3p3_is_internal) { vreg_5v = vreg_get(NULL, "boost"); if (IS_ERR(vreg_5v)) return PTR_ERR(vreg_5v); vreg_set_level(vreg_5v, 5000); } vreg_3p3 = vreg_get(NULL, "usb"); if (IS_ERR(vreg_3p3)) return PTR_ERR(vreg_3p3); vreg_set_level(vreg_3p3, 3300); } else { if (regulator_3p3_is_internal) vreg_put(vreg_5v); vreg_put(vreg_3p3); } return 0; } static int msm_hsusb_ldo_enable(int enable) { static int ldo_status; int ret; if (ldo_status == enable) return 0; if (regulator_3p3_is_internal && (!vreg_5v || IS_ERR(vreg_5v))) return -ENODEV; if (!vreg_3p3 || IS_ERR(vreg_3p3)) return -ENODEV; ldo_status = enable; if (enable) { if (regulator_3p3_is_internal) { ret = vreg_enable(vreg_5v); if (ret) return ret; /* power supply to 3p3 regulator can vary from * USB VBUS or VREG 5V. If the power supply is * USB VBUS cable disconnection cannot be * deteted. Select power supply to VREG 5V */ /* TBD: comeup with a better name */ ret = pmic_vote_3p3_pwr_sel_switch(1); if (ret) return ret; } ret = vreg_enable(vreg_3p3); return ret; } else { if (regulator_3p3_is_internal) { ret = vreg_disable(vreg_5v); if (ret) return ret; ret = pmic_vote_3p3_pwr_sel_switch(0); if (ret) return ret; } ret = vreg_disable(vreg_3p3); return ret; } } static void __init qsd8x50_init_usb(void) { usb_mpp_init(); if (machine_is_qsd8x50_ffa()) regulator_3p3_is_internal = 1; #ifdef CONFIG_USB_FUNCTION_MSM_HSUSB platform_device_register(&msm_device_hsusb_peripheral); #endif if (machine_is_qsd8x50_ffa()) return; vreg_usb = vreg_get(NULL, "boost"); if (IS_ERR(vreg_usb)) { printk(KERN_ERR "%s: vreg get failed (%ld)\n", __func__, PTR_ERR(vreg_usb)); return; } platform_device_register(&msm_device_hsusb_otg); msm_add_host(0, &msm_usb_host_pdata); #ifdef CONFIG_USB_FS_HOST if (fsusb_gpio_init()) return; msm_add_host(1, &msm_usb_host2_pdata); #endif } static struct vreg *vreg_mmc; #if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\ || defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\ || defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\ || defined(CONFIG_MMC_MSM_SDC4_SUPPORT)) struct sdcc_gpio { struct msm_gpio *cfg_data; uint32_t size; }; static struct msm_gpio sdc1_cfg_data[] = { {GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_3"}, {GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_2"}, {GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_1"}, {GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_0"}, {GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_cmd"}, {GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc1_clk"}, }; static struct msm_gpio sdc2_cfg_data[] = { {GPIO_CFG(62, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc2_clk"}, {GPIO_CFG(63, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_cmd"}, {GPIO_CFG(64, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_3"}, {GPIO_CFG(65, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_2"}, {GPIO_CFG(66, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_1"}, {GPIO_CFG(67, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_0"}, }; static struct msm_gpio sdc3_cfg_data[] = { {GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc3_clk"}, {GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_cmd"}, {GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_3"}, {GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_2"}, {GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_1"}, {GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_0"}, #ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT {GPIO_CFG(158, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_4"}, {GPIO_CFG(159, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_5"}, {GPIO_CFG(160, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_6"}, {GPIO_CFG(161, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_7"}, #endif }; static struct msm_gpio sdc4_cfg_data[] = { {GPIO_CFG(142, 3, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc4_clk"}, {GPIO_CFG(143, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_cmd"}, {GPIO_CFG(144, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_0"}, {GPIO_CFG(145, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_1"}, {GPIO_CFG(146, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_2"}, {GPIO_CFG(147, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_3"}, }; static struct sdcc_gpio sdcc_cfg_data[] = { { .cfg_data = sdc1_cfg_data, .size = ARRAY_SIZE(sdc1_cfg_data), }, { .cfg_data = sdc2_cfg_data, .size = ARRAY_SIZE(sdc2_cfg_data), }, { .cfg_data = sdc3_cfg_data, .size = ARRAY_SIZE(sdc3_cfg_data), }, { .cfg_data = sdc4_cfg_data, .size = ARRAY_SIZE(sdc4_cfg_data), }, }; static unsigned long vreg_sts, gpio_sts; static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable) { int rc = 0; struct sdcc_gpio *curr; curr = &sdcc_cfg_data[dev_id - 1]; if (!(test_bit(dev_id, &gpio_sts)^enable)) return; if (enable) { set_bit(dev_id, &gpio_sts); rc = msm_gpios_request_enable(curr->cfg_data, curr->size); if (rc) printk(KERN_ERR "%s: Failed to turn on GPIOs for slot %d\n", __func__, dev_id); } else { clear_bit(dev_id, &gpio_sts); msm_gpios_disable_free(curr->cfg_data, curr->size); } } static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) { int rc = 0; struct platform_device *pdev; pdev = container_of(dv, struct platform_device, dev); msm_sdcc_setup_gpio(pdev->id, !!vdd); if (vdd == 0) { if (!vreg_sts) return 0; clear_bit(pdev->id, &vreg_sts); if (!vreg_sts) { rc = vreg_disable(vreg_mmc); if (rc) printk(KERN_ERR "%s: return val: %d \n", __func__, rc); } return 0; } if (!vreg_sts) { rc = vreg_set_level(vreg_mmc, PMIC_VREG_GP6_LEVEL); if (!rc) rc = vreg_enable(vreg_mmc); if (rc) printk(KERN_ERR "%s: return val: %d \n", __func__, rc); } set_bit(pdev->id, &vreg_sts); return 0; } #endif #if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\ || defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\ || defined(CONFIG_MMC_MSM_SDC4_SUPPORT)) static int msm_sdcc_get_wpswitch(struct device *dv) { void __iomem *wp_addr = 0; uint32_t ret = 0; struct platform_device *pdev; if (!machine_is_qsd8x50_surf()) return -1; pdev = container_of(dv, struct platform_device, dev); wp_addr = ioremap(FPGA_SDCC_STATUS, 4); if (!wp_addr) { pr_err("%s: Could not remap %x\n", __func__, FPGA_SDCC_STATUS); return -ENOMEM; } ret = (readl(wp_addr) >> ((pdev->id - 1) << 1)) & (0x03); pr_info("%s: WP/CD Status for Slot %d = 0x%x \n", __func__, pdev->id, ret); iounmap(wp_addr); return ((ret == 0x02) ? 1 : 0); } #endif #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT static struct mmc_platform_data qsd8x50_sdc1_data = { .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, .translate_vdd = msm_sdcc_setup_power, .mmc_bus_width = MMC_CAP_4_BIT_DATA, .wpswitch = msm_sdcc_get_wpswitch, .msmsdcc_fmin = 144000, .msmsdcc_fmid = 25000000, .msmsdcc_fmax = 49152000, .nonremovable = 0, }; #endif #ifdef CONFIG_MMC_MSM_SDC2_SUPPORT static struct mmc_platform_data qsd8x50_sdc2_data = { .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, .translate_vdd = msm_sdcc_setup_power, .mmc_bus_width = MMC_CAP_4_BIT_DATA, .wpswitch = msm_sdcc_get_wpswitch, .msmsdcc_fmin = 144000, .msmsdcc_fmid = 25000000, .msmsdcc_fmax = 49152000, .nonremovable = 1, }; #endif #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT static struct mmc_platform_data qsd8x50_sdc3_data = { .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, .translate_vdd = msm_sdcc_setup_power, #ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT .mmc_bus_width = MMC_CAP_8_BIT_DATA, #else .mmc_bus_width = MMC_CAP_4_BIT_DATA, #endif .msmsdcc_fmin = 144000, .msmsdcc_fmid = 25000000, .msmsdcc_fmax = 49152000, .nonremovable = 0, }; #endif #ifdef CONFIG_MMC_MSM_SDC4_SUPPORT static struct mmc_platform_data qsd8x50_sdc4_data = { .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, .translate_vdd = msm_sdcc_setup_power, .mmc_bus_width = MMC_CAP_4_BIT_DATA, .wpswitch = msm_sdcc_get_wpswitch, .msmsdcc_fmin = 144000, .msmsdcc_fmid = 25000000, .msmsdcc_fmax = 49152000, .nonremovable = 0, }; #endif static void __init qsd8x50_init_mmc(void) { if (machine_is_qsd8x50_ffa()) vreg_mmc = vreg_get(NULL, "gp6"); else vreg_mmc = vreg_get(NULL, "gp5"); if (IS_ERR(vreg_mmc)) { printk(KERN_ERR "%s: vreg get failed (%ld)\n", __func__, PTR_ERR(vreg_mmc)); return; } #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT msm_add_sdcc(1, &qsd8x50_sdc1_data); #endif if (machine_is_qsd8x50_surf()) { #ifdef CONFIG_MMC_MSM_SDC2_SUPPORT msm_add_sdcc(2, &qsd8x50_sdc2_data); #endif #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT msm_add_sdcc(3, &qsd8x50_sdc3_data); #endif #ifdef CONFIG_MMC_MSM_SDC4_SUPPORT msm_add_sdcc(4, &qsd8x50_sdc4_data); #endif } } static void __init qsd8x50_cfg_smc91x(void) { int rc = 0; if (machine_is_qsd8x50_surf()) { smc91x_resources[0].start = 0x70000300; smc91x_resources[0].end = 0x700003ff; smc91x_resources[1].start = MSM_GPIO_TO_INT(156); smc91x_resources[1].end = MSM_GPIO_TO_INT(156); } else if (machine_is_qsd8x50_ffa()) { smc91x_resources[0].start = 0x84000300; smc91x_resources[0].end = 0x840003ff; smc91x_resources[1].start = MSM_GPIO_TO_INT(87); smc91x_resources[1].end = MSM_GPIO_TO_INT(87); rc = gpio_tlmm_config(GPIO_CFG(87, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); if (rc) { printk(KERN_ERR "%s: gpio_tlmm_config=%d\n", __func__, rc); } } else printk(KERN_ERR "%s: invalid machine type\n", __func__); } static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = { .idle_supported = 1, .suspend_supported = 1, .idle_enabled = 1, .suspend_enabled = 1, .latency = 8594, .residency = 23740, }, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = { .idle_supported = 1, .suspend_supported = 1, .idle_enabled = 1, .suspend_enabled = 1, .latency = 4594, .residency = 23740, }, [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] = { .idle_supported = 1, .suspend_supported = 1, .idle_enabled = 0, .suspend_enabled = 1, .latency = 443, .residency = 1098, }, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = { .idle_supported = 1, .suspend_supported = 1, .idle_enabled = 1, .suspend_enabled = 1, .latency = 2, .residency = 0, }, }; static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = { .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT, .v_addr = (unsigned int *)PAGE_OFFSET, }; static void msm_i2c_gpio_config(int iface, int config_type) { int gpio_scl; int gpio_sda; if (iface) { gpio_scl = 60; gpio_sda = 61; } else { gpio_scl = 95; gpio_sda = 96; } if (config_type) { gpio_tlmm_config(GPIO_CFG(gpio_scl, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); gpio_tlmm_config(GPIO_CFG(gpio_sda, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); } else { gpio_tlmm_config(GPIO_CFG(gpio_scl, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); gpio_tlmm_config(GPIO_CFG(gpio_sda, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE); } } static struct msm_i2c_platform_data msm_i2c_pdata = { .clk_freq = 100000, .rsl_id = SMEM_SPINLOCK_I2C, .pri_clk = 95, .pri_dat = 96, .aux_clk = 60, .aux_dat = 61, .msm_i2c_config_gpio = msm_i2c_gpio_config, }; static void __init msm_device_i2c_init(void) { if (gpio_request(95, "i2c_pri_clk")) pr_err("failed to request gpio i2c_pri_clk\n"); if (gpio_request(96, "i2c_pri_dat")) pr_err("failed to request gpio i2c_pri_dat\n"); if (gpio_request(60, "i2c_sec_clk")) pr_err("failed to request gpio i2c_sec_clk\n"); if (gpio_request(61, "i2c_sec_dat")) pr_err("failed to request gpio i2c_sec_dat\n"); msm_i2c_pdata.rmutex = 1; msm_i2c_pdata.pm_lat = msm_pm_data[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] .latency; msm_device_i2c.dev.platform_data = &msm_i2c_pdata; } static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE; static int __init pmem_kernel_ebi1_size_setup(char *p) { pmem_kernel_ebi1_size = memparse(p, NULL); return 0; } early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); #ifdef CONFIG_KERNEL_PMEM_SMI_REGION static unsigned pmem_kernel_smi_size = MSM_PMEM_SMIPOOL_SIZE; static int __init pmem_kernel_smi_size_setup(char *p) { pmem_kernel_smi_size = memparse(p, NULL); /* Make sure that we don't allow more SMI memory then is available - the kernel mapping code has no way of knowing if it has gone over the edge */ if (pmem_kernel_smi_size > MSM_PMEM_SMIPOOL_SIZE) pmem_kernel_smi_size = MSM_PMEM_SMIPOOL_SIZE; return 0; } early_param("pmem_kernel_smi_size", pmem_kernel_smi_size_setup); #endif static unsigned pmem_sf_size = MSM_PMEM_SF_SIZE; static int __init pmem_sf_size_setup(char *p) { pmem_sf_size = memparse(p, NULL); return 0; } early_param("pmem_sf_size", pmem_sf_size_setup); static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE; static int __init pmem_adsp_size_setup(char *p) { pmem_adsp_size = memparse(p, NULL); return 0; } early_param("pmem_adsp_size", pmem_adsp_size_setup); static unsigned audio_size = MSM_AUDIO_SIZE; static int __init audio_size_setup(char *p) { audio_size = memparse(p, NULL); return 0; } early_param("audio_size", audio_size_setup); static void __init qsd8x50_init(void) { msm_clock_init(&qds8x50_clock_init_data); qsd8x50_cfg_smc91x(); platform_device_register(&msm8x50_device_acpuclk); msm_hsusb_pdata.swfi_latency = msm_pm_data [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency; msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata; msm_otg_pdata.swfi_latency = msm_pm_data [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency; msm_device_otg.dev.platform_data = &msm_otg_pdata; msm_device_gadget_peripheral.dev.platform_data = &msm_gadget_pdata; msm_gadget_pdata.is_phy_status_timer_on = 1; #if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) msm_device_tsif.dev.platform_data = &tsif_platform_data; #endif platform_add_devices(devices, ARRAY_SIZE(devices)); msm_fb_add_devices(); qsd8x50_init_usb(); qsd8x50_init_mmc(); bt_power_init(); audio_gpio_init(); msm_device_i2c_init(); msm_qsd_spi_init(); i2c_register_board_info(0, msm_i2c_board_info, ARRAY_SIZE(msm_i2c_board_info)); spi_register_board_info(msm_spi_board_info, ARRAY_SIZE(msm_spi_board_info)); msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data)); BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata)); msm_pm_register_irqs(); } static void __init qsd8x50_allocate_memory_regions(void) { void *addr; unsigned long size; size = pmem_kernel_ebi1_size; if (size) { addr = alloc_bootmem_align(size, 0x100000); android_pmem_kernel_ebi1_pdata.size = size; pr_info("allocating %lu bytes at %p (%lx physical) for kernel" " ebi1 pmem arena\n", size, addr, __pa(addr)); } #ifdef CONFIG_KERNEL_PMEM_SMI_REGION size = pmem_kernel_smi_size; if (size > MSM_PMEM_SMIPOOL_SIZE) { printk(KERN_ERR "pmem kernel smi arena size %lu is too big\n", size); size = MSM_PMEM_SMIPOOL_SIZE; } android_pmem_kernel_smi_pdata.size = size; pr_info("allocating %lu bytes at %lx (%lx physical)" "for pmem kernel smi arena\n", size, (long unsigned int) MSM_PMEM_SMIPOOL_BASE, __pa(MSM_PMEM_SMIPOOL_BASE)); #endif size = pmem_sf_size; if (size) { addr = alloc_bootmem(size); android_pmem_pdata.size = size; pr_info("allocating %lu bytes at %p (%lx physical) for sf " "pmem arena\n", size, addr, __pa(addr)); } size = pmem_adsp_size; if (size) { addr = alloc_bootmem(size); android_pmem_adsp_pdata.size = size; pr_info("allocating %lu bytes at %p (%lx physical) for adsp " "pmem arena\n", size, addr, __pa(addr)); } size = MSM_FB_SIZE; addr = (void *)MSM_FB_BASE; msm_fb_resources[0].start = (unsigned long)addr; msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; pr_info("using %lu bytes of SMI at %lx physical for fb\n", size, (unsigned long)addr); size = audio_size ? : MSM_AUDIO_SIZE; addr = alloc_bootmem(size); msm_audio_resources[0].start = __pa(addr); msm_audio_resources[0].end = msm_audio_resources[0].start + size - 1; pr_info("allocating %lu bytes at %p (%lx physical) for audio\n", size, addr, __pa(addr)); } static void __init qsd8x50_map_io(void) { msm_shared_ram_phys = MSM_SHARED_RAM_PHYS; msm_map_qsd8x50_io(); qsd8x50_allocate_memory_regions(); if (socinfo_init() < 0) printk(KERN_ERR "%s: socinfo_init() failed!\n", __func__); } static void __init qsd8x50_init_late(void) { smd_debugfs_init(); } MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") .atag_offset = 0x100, .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, .init_late = qsd8x50_init_late, .timer = &msm_timer, MACHINE_END MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA") .atag_offset = 0x100, .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, .init_late = qsd8x50_init_late, .timer = &msm_timer, MACHINE_END