Merge "[media] v4l2: add VIDIOC_(TRY_)DECODER_CMD" into msm-3.0
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index dabd390..745a3a4 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -8,6 +8,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <mach/gpio.h>
+#include <mach/msm_bus.h>
#define SDC_DAT1_DISABLE 0
#define SDC_DAT1_ENABLE 1
@@ -112,6 +113,12 @@
struct msm_mmc_pad_data *pad_data;
};
+struct msm_mmc_bus_voting_data {
+ struct msm_bus_scale_pdata *use_cases;
+ unsigned int *bw_vecs;
+ unsigned int bw_vecs_size;
+};
+
struct mmc_platform_data {
unsigned int ocr_mask; /* available voltages */
int built_in; /* built-in device flag */
@@ -153,6 +160,7 @@
bool disable_runtime_pm;
bool disable_cmd23;
u32 cpu_dma_latency;
+ struct msm_mmc_bus_voting_data *msm_bus_voting_data;
};
#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 4ecc3a4..83e6666 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -36,6 +36,7 @@
select QCACHE
select MSM_PM2 if PM
select MSM_RUN_QUEUE_STATS if MSM_SOC_REV_A
+ select DONT_MAP_HOLE_AFTER_MEMBANK0
config ARCH_MSM7X30
bool "MSM7x30"
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index b4e7d35..72126c8 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -23,6 +23,7 @@
#include <mach/gpiomux.h>
#include "devices.h"
#include "board-8064.h"
+#include "board-storage-common-a.h"
/* APQ8064 has 4 SDCC controllers */
@@ -219,6 +220,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.uhs_caps = MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
static struct mmc_platform_data *apq8064_sdc1_pdata = &sdc1_data;
#else
@@ -249,6 +251,7 @@
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
static struct mmc_platform_data *apq8064_sdc3_pdata = &sdc3_data;
#else
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index cd4aff8..936a798 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -94,6 +94,12 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting audio_spkr_boost = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct gpiomux_setting gpio_eth_config = {
.pull = GPIOMUX_PULL_NONE,
@@ -389,6 +395,16 @@
},
};
+static struct msm_gpiomux_config msm8960_audio_spkr_configs[] __initdata = {
+ {
+ .gpio = 15,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_spkr_boost,
+ },
+ },
+};
+
+
static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
{
.gpio = 63,
@@ -636,6 +652,9 @@
msm_gpiomux_install(msm8960_audio_mbhc_configs,
ARRAY_SIZE(msm8960_audio_mbhc_configs));
+ msm_gpiomux_install(msm8960_audio_spkr_configs,
+ ARRAY_SIZE(msm8960_audio_spkr_configs));
+
msm_gpiomux_install(msm8960_audio_auxpcm_configs,
ARRAY_SIZE(msm8960_audio_auxpcm_configs));
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 9171749..6dd7add 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -24,6 +24,7 @@
#include "devices.h"
#include "board-8930.h"
+#include "board-storage-common-a.h"
/* MSM8960 has 5 SDCC controllers */
enum sdcc_controllers {
@@ -235,6 +236,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.pin_data = &mmc_slot_pin_data[SDCC1],
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -273,6 +275,7 @@
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index df1d846..10a6903 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -17,12 +17,12 @@
#include <linux/bootmem.h>
#include <asm/mach-types.h>
#include <asm/mach/mmc.h>
-#include <mach/msm_bus_board.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
#include "devices.h"
#include "board-8960.h"
+#include "board-storage-common-a.h"
/* MSM8960 has 5 SDCC controllers */
enum sdcc_controllers {
@@ -299,6 +299,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.pin_data = &mmc_slot_pin_data[SDCC1],
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -316,6 +317,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC2],
.pin_data = &mmc_slot_pin_data[SDCC2],
.sdiowakeup_irq = MSM_GPIO_TO_INT(90),
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -342,6 +344,7 @@
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_600),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -359,6 +362,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC4],
.pin_data = &mmc_slot_pin_data[SDCC4],
.sdiowakeup_irq = MSM_GPIO_TO_INT(85),
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 0e18918..3df5000 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -251,6 +251,7 @@
.gpio = 16, /* GSBI5 I2C QUP SCL */
.settings = {
[GPIOMUX_SUSPENDED] = &gsbi5,
+ [GPIOMUX_ACTIVE] = &gsbi5,
},
},
{
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 8328501..0ece37c 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -79,6 +79,10 @@
REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla2x-slim"),
REGULATOR_SUPPLY("VDDD_CDC_D", "tabla-slim"),
REGULATOR_SUPPLY("VDDD_CDC_D", "tabla2x-slim"),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "0-000d"),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla top level"),
};
VREG_CONSUMERS(S3) = {
REGULATOR_SUPPLY("8018_s3", NULL),
@@ -91,6 +95,14 @@
REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla2x-slim"),
REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"),
REGULATOR_SUPPLY("VDDIO_CDC", "tabla2x-slim"),
+ REGULATOR_SUPPLY("VDDIO_CDC", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDD_CP", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDDA_RX", "tabla top level"),
+ REGULATOR_SUPPLY("VDDIO_CDC", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDD_CP", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDDA_TX", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDDA_RX", "0-000d"),
};
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8018_s4", NULL),
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
index 7580cc3..5bdeb94 100644
--- a/arch/arm/mach-msm/board-9615-storage.c
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -22,6 +22,7 @@
#include "devices.h"
#include "board-9615.h"
+#include "board-storage-common-a.h"
#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
@@ -187,6 +188,7 @@
.uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_MAX_CURRENT_400),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
#else
@@ -206,6 +208,7 @@
.pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC2],
.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
#else
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index da9ce67..3b99e6c 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -51,6 +51,7 @@
#include "pm.h"
#include "acpuclock.h"
#include "pm-boot.h"
+#include <mach/gpiomux.h>
#ifdef CONFIG_ION_MSM
#define MSM_ION_AUDIO_SIZE 0xAF000
@@ -295,6 +296,95 @@
#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+/*
+ * MDM9x15 I2S.
+ */
+static struct wcd9xxx_pdata wcd9xxx_i2c_platform_data = {
+ .irq = MSM_GPIO_TO_INT(85),
+ .irq_base = TABLA_INTERRUPT_BASE,
+ .num_irqs = NR_TABLA_IRQS,
+ .reset_gpio = 84,
+ .micbias = {
+ .ldoh_v = TABLA_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .cfilt3_mv = 1800,
+ .bias1_cfilt_sel = TABLA_CFILT1_SEL,
+ .bias2_cfilt_sel = TABLA_CFILT2_SEL,
+ .bias3_cfilt_sel = TABLA_CFILT3_SEL,
+ .bias4_cfilt_sel = TABLA_CFILT3_SEL,
+ },
+ .regulator = {
+ {
+ .name = "CDC_VDD_CP",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_RX",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_TX",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+ },
+ {
+ .name = "VDDIO_CDC",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+ },
+ {
+ .name = "VDDD_CDC_D",
+ .min_uV = 1225000,
+ .max_uV = 1225000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_A_1P2V",
+ .min_uV = 1225000,
+ .max_uV = 1225000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+ }
+ },
+};
+
+static struct i2c_board_info wcd9xxx_device_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+};
+
+static struct i2c_registry msm9615_i2c_devices[] __initdata = {
+ {
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_9615_GSBI5_QUP_I2C_BUS_ID,
+ wcd9xxx_device_info,
+ ARRAY_SIZE(wcd9xxx_device_info),
+ },
+};
+/*
+ * MDM9x15 I2S.
+ */
+
/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
* 4 micbiases are used to power various analog and digital
* microphones operating at 1800 mV. Technically, all micbiases
@@ -700,6 +790,8 @@
&msm_stub_codec,
&msm_voice,
&msm_voip,
+ &msm_i2s_cpudai0,
+ &msm_i2s_cpudai1,
&msm_pcm_hostless,
&msm_cpudai_afe_01_rx,
&msm_cpudai_afe_01_tx,
@@ -728,8 +820,27 @@
static void __init msm9615_i2c_init(void)
{
+ u8 mach_mask = 0;
+ int i;
+ /* Mask is hardcoded to SURF (CDP).
+ * works on MTP with same configuration.
+ */
+ mach_mask = I2C_SURF;
+ if (machine_is_msm9615_cdp())
+ mach_mask = I2C_SURF;
+ else if (machine_is_msm9615_mtp())
+ mach_mask = I2C_FFA;
+ else
+ pr_err("unmatched machine ID in register_i2c_devices\n");
msm9615_device_qup_i2c_gsbi5.dev.platform_data =
&msm9615_i2c_qup_gsbi5_pdata;
+ for (i = 0; i < ARRAY_SIZE(msm9615_i2c_devices); ++i) {
+ if (msm9615_i2c_devices[i].machs & mach_mask) {
+ i2c_register_board_info(msm9615_i2c_devices[i].bus,
+ msm9615_i2c_devices[i].info,
+ msm9615_i2c_devices[i].len);
+ }
+ }
}
static void __init msm9615_reserve(void)
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 7dd003f..80656b3 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -17,6 +17,34 @@
#include <linux/mfd/pm8xxx/pm8018.h>
#include <linux/regulator/gpio-regulator.h>
+/*
+ * MDM9x15 I2S.
+ */
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+ u8 machs;
+ int bus;
+ struct i2c_board_info *info;
+ int len;
+};
+#endif
+/* Tabla slave address for I2C */
+#define TABLA_I2C_SLAVE_ADDR 0x0d
+#define TABLA_ANALOG_I2C_SLAVE_ADDR 0x77
+#define TABLA_DIGITAL1_I2C_SLAVE_ADDR 0x66
+#define TABLA_DIGITAL2_I2C_SLAVE_ADDR 0x55
+#define MSM_9615_GSBI5_QUP_I2C_BUS_ID 0
+/*
+ * MDM9x15 I2S.
+ */
+
/* Macros assume PMIC GPIOs and MPPs start at 1 */
#define PM8018_GPIO_BASE NR_GPIO_IRQS
#define PM8018_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8018_GPIO_BASE)
@@ -36,7 +64,7 @@
#define GPIO_VREG_ID_EXT_2P95V 0
extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
-
+uint32_t msm9615_rpm_get_swfi_latency(void);
int msm9615_init_gpiomux(void);
void msm9615_init_mmc(void);
void mdm9615_allocate_fb_region(void);
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 14efac4..eb06b81 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -51,7 +51,7 @@
#else
#define MSM_ION_SF_SIZE 0x2800000 /* 40 Mbytes */
#endif
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_FW_SIZE 0xa00000 /* (10MB) */
#define MSM_ION_MM_SIZE 0x7800000 /* (120MB) */
#define MSM_ION_QSECOM_SIZE 0x100000 /* (1MB) */
#define MSM_ION_MFC_SIZE SZ_8K
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 329dcae..c069aab 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -86,8 +86,6 @@
{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_LOW, 5000},
{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_HIGH, 5000},
{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_LOW, 5000},
- {40, GPIOF_OUT_INIT_HIGH, 5000},
- {35, GPIOF_OUT_INIT_HIGH, 5000},
};
static struct msm_camera_gpio_conf gpio_conf_ov7692 = {
@@ -212,6 +210,7 @@
.sensor_name = "ov7692",
.sensor_reset_enable = 0,
.pmic_gpio_enable = 1,
+ .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU1_CAM_VGA_RESET_N,
.sensor_pwd = GPIO_SKU1_CAM_VGA_SHDN,
.pdata = &msm_camera_device_data_csi0[0],
@@ -255,6 +254,7 @@
.sensor_name = "ov5647",
.sensor_reset_enable = 1,
.pmic_gpio_enable = 1,
+ .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
.sensor_pwd = GPIO_SKU3_CAM_5MP_SHDN_N,
.pdata = &msm_camera_device_data_csi1[0],
@@ -1099,8 +1099,6 @@
GPIO_SKU7_CAM_VGA_SHDN;
ov7692_cam_gpio_set_tbl[0].gpio = GPIO_SKU7_CAM_VGA_SHDN;
ov7692_cam_gpio_set_tbl[1].gpio = GPIO_SKU7_CAM_VGA_SHDN;
- ov7692_cam_gpio_set_tbl[4].gpio = LCD_CAMERA_LDO_2V8 ;
- ov7692_cam_gpio_set_tbl[5].gpio = SKU7_LCD_CAMERA_LDO_1V8;
msm_camera_sensor_ov5647_data.sensor_pwd =
GPIO_SKU7_CAM_5MP_SHDN_N;
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index bfd9379..23df1cf 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -125,6 +125,11 @@
KEY_VOLUMEDOWN,
};
+static const unsigned short keymap_8625_evt[] = {
+ KEY_VOLUMEDOWN,
+ KEY_VOLUMEUP,
+};
+
static struct gpio_event_matrix_info kp_matrix_info_8625 = {
.info.func = gpio_event_matrix_func,
.keymap = keymap_8625,
@@ -853,7 +858,11 @@
#endif
/* keypad */
- if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ if (machine_is_msm8625_evt())
+ kp_matrix_info_8625.keymap = keymap_8625_evt;
+
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+ machine_is_msm8625_evt())
platform_device_register(&kp_pdev_8625);
else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
platform_device_register(&kp_pdev_sku3);
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index 413a28c..4357e01 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -103,6 +103,7 @@
#endif
void __init msm7627a_camera_init(void);
+int lcd_camera_power_onoff(int on);
void __init msm7627a_add_io_devices(void);
void __init qrd7627a_add_io_devices(void);
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index e5a31f2a..b0799c2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -102,6 +102,7 @@
#include "rpm_resources.h"
#include "acpuclock.h"
#include "pm-boot.h"
+#include "board-storage-common-a.h"
#include <linux/ion.h>
#include <mach/ion.h>
@@ -8356,6 +8357,7 @@
.msmsdcc_fmax = 48000000,
.nonremovable = 1,
.pclk_src_dfab = 1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8374,6 +8376,7 @@
#ifdef CONFIG_MSM_SDIO_AL
.is_sdio_al_client = 1,
#endif
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8395,6 +8398,7 @@
.nonremovable = 0,
.pclk_src_dfab = 1,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8409,6 +8413,7 @@
.nonremovable = 0,
.pclk_src_dfab = 1,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC4_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8427,6 +8432,7 @@
#ifdef CONFIG_MSM_SDIO_AL
.is_sdio_al_client = 1,
#endif
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
diff --git a/arch/arm/mach-msm/board-storage-common-a.h b/arch/arm/mach-msm/board-storage-common-a.h
new file mode 100644
index 0000000..7737819
--- /dev/null
+++ b/arch/arm/mach-msm/board-storage-common-a.h
@@ -0,0 +1,99 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#ifndef _BOARD_STORAGE_A_H
+#define _BOARD_STORAGE_A_H
+
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(num, _ib) \
+static struct msm_bus_vectors sps_to_ddr_perf_vectors_##num[] = { \
+ { \
+ .src = MSM_BUS_MASTER_SPS, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ib = (_ib), \
+ .ab = ((_ib) / 2), \
+ } \
+}
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(num) \
+ { \
+ ARRAY_SIZE(sps_to_ddr_perf_vectors_##num), \
+ sps_to_ddr_perf_vectors_##num, \
+ }
+
+/* no bandwidth required */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(0, 0);
+/*
+ * 13 MB/s bandwidth
+ * 4-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_UHS_SDR12
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(1, 13 * 1024 * 1024);
+/*
+ * 26 MB/s bandwidth
+ * 8-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_MMC_HS / MMC_TIMING_SD_HS /
+ * MMC_TIMING_UHS_SDR25
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(2, 26 * 1024 * 1024);
+/*
+ * 52 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS
+ * 4-bit MMC_TIMING_UHS_SDR50 / MMC_TIMING_UHS_DDR50
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(3, 52 * 1024 * 1024);
+/*
+ * 104 MB/s bandwidth
+ * 8-bit MMC_TIMING_UHS_DDR50
+ * 4-bit MMC_TIMING_UHS_SDR104 / MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(4, 104 * 1024 * 1024);
+/*
+ * 200 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(5, 200 * 1024 * 1024);
+/* max. possible bandwidth */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(6, UINT_MAX);
+
+static unsigned int sdcc_bw_vectors[] = {0, (13 * 1024 * 1024),
+ (26 * 1024 * 1024), (52 * 1024 * 1024),
+ (104 * 1024 * 1024), (200 * 1024 * 1024),
+ UINT_MAX};
+
+static struct msm_bus_paths sps_to_ddr_bus_scale_usecases[] = {
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(0),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(1),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(2),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(3),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(4),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(5),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(6),
+};
+
+static struct msm_bus_scale_pdata sps_to_ddr_bus_scale_data = {
+ sps_to_ddr_bus_scale_usecases,
+ ARRAY_SIZE(sps_to_ddr_bus_scale_usecases),
+ .name = "msm_sdcc",
+};
+
+static struct msm_mmc_bus_voting_data sps_to_ddr_bus_voting_data = {
+ .use_cases = &sps_to_ddr_bus_scale_data,
+ .bw_vecs = sdcc_bw_vectors,
+ .bw_vecs_size = sizeof(sdcc_bw_vectors),
+};
+
+#endif /* _BOARD_STORAGE_A_H */
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 1fd9b4d..a950e46 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1655,6 +1655,10 @@
"msm-dai-q6.1"),
CLK_LOOKUP("osr_clk", codec_i2s_mic_osr_clk.c,
"msm-dai-q6.1"),
+ CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
+ "msm-dai-q6.0"),
CLK_LOOKUP("bit_clk", spare_i2s_mic_bit_clk.c,
"msm-dai-q6.5"),
CLK_LOOKUP("osr_clk", spare_i2s_mic_osr_clk.c,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index c084d29..8eb1580 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -62,6 +62,9 @@
#define MSM_PMIC1_SSBI_CMD_PHYS 0x00500000
#define MSM_PMIC_SSBI_SIZE SZ_4K
+#define MSM_GPIO_I2C_CLK 16
+#define MSM_GPIO_I2C_SDA 17
+
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
.bark_time = 11000,
@@ -307,6 +310,19 @@
.end = GSBI5_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
+ {
+ .name = "i2c_clk",
+ .start = MSM_GPIO_I2C_CLK,
+ .end = MSM_GPIO_I2C_CLK,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "i2c_sda",
+ .start = MSM_GPIO_I2C_SDA,
+ .end = MSM_GPIO_I2C_SDA,
+ .flags = IORESOURCE_IO,
+
+ },
};
struct platform_device msm9615_device_qup_i2c_gsbi5 = {
@@ -472,6 +488,15 @@
.id = -1,
};
+struct platform_device msm_i2s_cpudai0 = {
+ .name = "msm-dai-q6",
+ .id = PRIMARY_I2S_RX,
+};
+
+struct platform_device msm_i2s_cpudai1 = {
+ .name = "msm-dai-q6",
+ .id = PRIMARY_I2S_TX,
+};
struct platform_device msm_voip = {
.name = "msm-voip-dsp",
.id = -1,
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 407554c..4184a86 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -32,4 +32,5 @@
int ar600x_wlan_power(bool on);
void __init msm8x25_spm_device_init(void);
void __init msm8x25_kgsl_3d0_init(void);
+void __iomem *core1_reset_base(void);
#endif
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 31142c1..8f42ede 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -223,6 +223,8 @@
extern struct platform_device msm_cpudai_incall_music_rx;
extern struct platform_device msm_cpudai_incall_record_rx;
extern struct platform_device msm_cpudai_incall_record_tx;
+extern struct platform_device msm_i2s_cpudai0;
+extern struct platform_device msm_i2s_cpudai1;
extern struct platform_device msm_pil_q6v3;
extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 644746e..56210d5 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -288,6 +288,7 @@
enum msm_sensor_type sensor_type;
struct msm_actuator_info *actuator_info;
int pmic_gpio_enable;
+ int (*sensor_lcd_gpio_onoff)(int on);
struct msm_eeprom_info *eeprom_info;
};
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 462543e..a90be23 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -138,7 +138,7 @@
struct msm_ipc_sock {
struct sock sk;
struct msm_ipc_port *port;
- void *modem_pil;
+ void *default_pil;
};
enum write_data_type {
@@ -206,4 +206,15 @@
int msm_ipc_router_init_sockets(void);
void msm_ipc_router_exit_sockets(void);
+#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
+extern void *msm_ipc_load_default_node(void);
+
+extern void msm_ipc_unload_default_node(void *pil);
+#else
+static inline void *msm_ipc_load_default_node(void)
+{ return NULL; }
+
+static inline void msm_ipc_unload_default_node(void *pil) { }
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 0cde393..307b6ae 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <mach/msm_smd.h>
+#include <mach/peripheral-loader.h>
#include "ipc_router.h"
#include "smd_private.h"
@@ -442,6 +443,31 @@
return 0;
}
+void *msm_ipc_load_default_node(void)
+{
+ void *pil = NULL;
+ const char *peripheral;
+
+ peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
+ if (peripheral && !strncmp(peripheral, "modem", 6)) {
+ pil = pil_get(peripheral);
+ if (IS_ERR(pil)) {
+ pr_err("%s: Failed to load %s\n",
+ __func__, peripheral);
+ pil = NULL;
+ }
+ }
+ return pil;
+}
+EXPORT_SYMBOL(msm_ipc_load_default_node);
+
+void msm_ipc_unload_default_node(void *pil)
+{
+ if (pil)
+ pil_put(pil);
+}
+EXPORT_SYMBOL(msm_ipc_unload_default_node);
+
static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
{
.probe = msm_ipc_router_smd_remote_probe,
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 085b87a..d82ffe5 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -30,14 +30,10 @@
#include <net/sock.h>
-#include <mach/peripheral-loader.h>
-#include <mach/socinfo.h>
-
#include "ipc_router.h"
#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
-#define MODEM_LOAD_TIMEOUT (10 * HZ)
static int sockets_enabled;
static struct proto msm_ipc_proto;
@@ -58,45 +54,6 @@
}
#endif
-static void msm_ipc_router_unload_modem(void *pil)
-{
- if (pil)
- pil_put(pil);
-}
-
-static void *msm_ipc_router_load_modem(void)
-{
- void *pil = NULL;
- int rc;
-
- /* Load GNSS for Standalone 8064 but not for Fusion 3 */
- if (cpu_is_apq8064()) {
- if (socinfo_get_platform_subtype() == 0x0)
- pil = pil_get("gss");
- } else {
- pil = pil_get("modem");
- }
-
- if (IS_ERR(pil) || !pil) {
- pr_debug("%s: modem load failed\n", __func__);
- pil = NULL;
- } else {
- rc = wait_for_completion_interruptible_timeout(
- &msm_ipc_remote_router_up,
- MODEM_LOAD_TIMEOUT);
- if (!rc)
- rc = -ETIMEDOUT;
- if (rc < 0) {
- pr_err("%s: wait for remote router failed %d\n",
- __func__, rc);
- msm_ipc_router_unload_modem(pil);
- pil = NULL;
- }
- }
-
- return pil;
-}
-
static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
struct iovec const *msg_sect,
size_t total_len)
@@ -268,9 +225,9 @@
sock_init_data(sock, sk);
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
- pil = msm_ipc_router_load_modem();
+ pil = msm_ipc_load_default_node();
msm_ipc_sk(sk)->port = port_ptr;
- msm_ipc_sk(sk)->modem_pil = pil;
+ msm_ipc_sk(sk)->default_pil = pil;
return 0;
}
@@ -519,12 +476,12 @@
{
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
- void *pil = msm_ipc_sk(sk)->modem_pil;
+ void *pil = msm_ipc_sk(sk)->default_pil;
int ret;
lock_sock(sk);
ret = msm_ipc_router_close_port(port_ptr);
- msm_ipc_router_unload_modem(pil);
+ msm_ipc_unload_default_node(pil);
release_sock(sk);
sock_put(sk);
sock->sk = NULL;
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 8d99c1c..f8e187d 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -39,6 +39,7 @@
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "mdm_private.h"
+#include "sysmon.h"
#define MDM_MODEM_TIMEOUT 6000
#define MDM_MODEM_DELTA 100
@@ -47,6 +48,7 @@
static int mdm_debug_on;
static struct workqueue_struct *mdm_queue;
+static struct workqueue_struct *mdm_sfr_queue;
#define EXTERNAL_MODEM "external_modem"
@@ -58,6 +60,36 @@
static int first_boot = 1;
+#define RD_BUF_SIZE 100
+#define SFR_MAX_RETRIES 10
+#define SFR_RETRY_INTERVAL 1000
+
+static void mdm_restart_reason_fn(struct work_struct *work)
+{
+ int ret, ntries = 0;
+ char sfr_buf[RD_BUF_SIZE];
+
+ do {
+ msleep(SFR_RETRY_INTERVAL);
+ ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+ sfr_buf, sizeof(sfr_buf));
+ if (ret) {
+ /*
+ * The sysmon device may not have been probed as yet
+ * after the restart.
+ */
+ pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
+ "%d/%d tries\n", __func__, ret,
+ ntries + 1, SFR_MAX_RETRIES);
+ } else {
+ pr_err("mdm restart reason: %s\n", sfr_buf);
+ break;
+ }
+ } while (++ntries < SFR_MAX_RETRIES);
+}
+
+static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
+
long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -253,8 +285,11 @@
msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
mdm_drv->mdm_boot_status = -ETIMEDOUT;
pr_info("%s: mdm modem restart timed out.\n", __func__);
- } else
+ } else {
pr_info("%s: mdm modem has been restarted\n", __func__);
+ /* Log the reason for the restart */
+ queue_work(mdm_sfr_queue, &sfr_reason_work);
+ }
INIT_COMPLETION(mdm_boot);
return mdm_drv->mdm_boot_status;
}
@@ -421,6 +456,16 @@
goto fatal_err;
}
+ mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+ if (!mdm_sfr_queue) {
+ pr_err("%s: could not create workqueue mdm_sfr_queue."
+ " All mdm functionality will be disabled\n",
+ __func__);
+ ret = -ENOMEM;
+ destroy_workqueue(mdm_queue);
+ goto fatal_err;
+ }
+
atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
mdm_debugfs_init();
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 393f1bd..3826b12 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -40,6 +40,7 @@
static bool cold_boot_done;
static uint32_t *msm8625_boot_vector;
+static void __iomem *reset_core1_base;
/*
* Write pen_release in a way that is guaranteed to be visible to all
@@ -155,11 +156,16 @@
__raw_writel(0x0, base_ptr);
mb();
- iounmap(base_ptr);
+ reset_core1_base = base_ptr;
return 0;
}
+void __iomem *core1_reset_base(void)
+{
+ return reset_core1_base;
+}
+
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index f4bfe23..6d8f2a2 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -65,7 +65,7 @@
#include "spm.h"
#include "sirc.h"
#include "pm-boot.h"
-#define MSM_CORE1_RESET 0xA8600590
+#include "devices-msm7x2xa.h"
/******************************************************************************
* Debug Definitions
@@ -455,30 +455,21 @@
static void msm_pm_config_hw_before_power_down(void)
{
if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
- __raw_writel(1, APPS_PWRDOWN);
- mb();
__raw_writel(4, APPS_SECOP);
- mb();
} else if (cpu_is_msm7x27()) {
__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
- mb();
- __raw_writel(1, APPS_PWRDOWN);
- mb();
} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
cpu_is_msm7x25ab()) {
__raw_writel(0x7, APPS_CLK_SLEEP_EN);
- mb();
- __raw_writel(1, APPS_PWRDOWN);
- mb();
- } else {
+ } else if (cpu_is_qsd8x50()) {
__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
mb();
- __raw_writel(1, APPS_PWRDOWN);
- mb();
__raw_writel(0, APPS_STANDBY_CTL);
- mb();
}
+ mb();
+ __raw_writel(1, APPS_PWRDOWN);
+ mb();
}
/*
@@ -490,7 +481,7 @@
void __iomem *base_ptr;
unsigned int value = 0;
- base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+ base_ptr = core1_reset_base();
if (!base_ptr)
return;
@@ -545,7 +536,6 @@
mb();
__raw_writel(0x0, base_ptr);
mb();
- iounmap(base_ptr);
}
/*
@@ -560,13 +550,11 @@
__raw_writel(0, APPS_PWRDOWN);
mb();
msm_spm_reinit();
- } else {
+ } else if (cpu_is_msm8625()) {
__raw_writel(0, APPS_PWRDOWN);
mb();
- __raw_writel(0, APPS_CLK_SLEEP_EN);
- mb();
- if (cpu_is_msm8625() && power_collapsed) {
+ if (power_collapsed) {
/*
* enable the SCU while coming out of power
* collapse.
@@ -577,6 +565,11 @@
*/
configure_top_csr();
}
+ } else {
+ __raw_writel(0, APPS_PWRDOWN);
+ mb();
+ __raw_writel(0, APPS_CLK_SLEEP_EN);
+ mb();
}
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index d811f71..b047cf4 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -218,7 +218,6 @@
/* 8064 IDs */
[109] = MSM_CPU_8064,
- [130] = MSM_CPU_8064,
/* 8930 IDs */
[116] = MSM_CPU_8930,
@@ -247,14 +246,17 @@
[128] = MSM_CPU_8625,
[129] = MSM_CPU_8625,
- /* 9625 IDs */
- [130] = MSM_CPU_9625,
+ /* 8064 MPQ ID */
+ [130] = MSM_CPU_8064,
/* 7x25AB IDs */
[131] = MSM_CPU_7X25AB,
[132] = MSM_CPU_7X25AB,
[133] = MSM_CPU_7X25AB,
+ /* 9625 IDs */
+ [134] = MSM_CPU_9625,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -625,7 +627,7 @@
strlcpy(dummy_socinfo.build_id, "copper - ",
sizeof(dummy_socinfo.build_id));
} else if (early_machine_is_msm9625()) {
- dummy_socinfo.id = 130;
+ dummy_socinfo.id = 134;
strlcpy(dummy_socinfo.build_id, "msm9625 - ",
sizeof(dummy_socinfo.build_id));
} else if (machine_is_msm8625_rumi3())
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 9597d18..bbb13f3 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -996,19 +996,41 @@
{
struct ion_client *client = s->private;
struct rb_node *n;
+ struct rb_node *n2;
- seq_printf(s, "%16.16s: %16.16s : %16.16s : %16.16s\n", "heap_name",
- "size_in_bytes", "handle refcount", "buffer");
+ seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
+ "heap_name", "size_in_bytes", "handle refcount",
+ "buffer", "physical", "[domain,partition] - virt");
+
mutex_lock(&client->lock);
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
node);
+ enum ion_heap_type type = handle->buffer->heap->type;
- seq_printf(s, "%16.16s: %16x : %16d : %16p\n",
+ seq_printf(s, "%16.16s: %16x : %16d : %12p",
handle->buffer->heap->name,
handle->buffer->size,
atomic_read(&handle->ref.refcount),
handle->buffer);
+
+ if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
+ type == ION_HEAP_TYPE_CARVEOUT ||
+ type == ION_HEAP_TYPE_CP)
+ seq_printf(s, " : %12lx", handle->buffer->priv_phys);
+ else
+ seq_printf(s, " : %12s", "N/A");
+
+ for (n2 = rb_first(&handle->buffer->iommu_maps); n2;
+ n2 = rb_next(n2)) {
+ struct ion_iommu_map *imap =
+ rb_entry(n2, struct ion_iommu_map, node);
+ seq_printf(s, " : [%d,%d] - %8lx",
+ imap->domain_info[DI_DOMAIN_NUM],
+ imap->domain_info[DI_PARTITION_NUM],
+ imap->iova_addr);
+ }
+ seq_printf(s, "\n");
}
seq_printf(s, "%16.16s %d\n", "client refcount:",
@@ -1063,7 +1085,13 @@
struct rb_node *parent = NULL;
struct ion_client *entry;
pid_t pid;
- unsigned int name_len = strnlen(name, 64);
+ unsigned int name_len;
+
+ if (!name) {
+ pr_err("%s: Name cannot be null\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+ name_len = strnlen(name, 64);
get_task_struct(current->group_leader);
task_lock(current->group_leader);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 2f83a40..c2d46e2 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -160,7 +160,7 @@
sizeof(struct kgsl_iommu_pt));
return NULL;
}
- iommu_pt->domain = iommu_domain_alloc(0);
+ iommu_pt->domain = iommu_domain_alloc(MSM_IOMMU_DOMAIN_PT_CACHEABLE);
if (!iommu_pt->domain) {
KGSL_CORE_ERR("Failed to create iommu domain\n");
kfree(iommu_pt);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 606d861..663ba0f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -453,10 +453,11 @@
*/
if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
(KGSL_MMU_GLOBAL_PT == name)) {
- pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
+ pagetable->kgsl_pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT,
+ -1);
if (pagetable->kgsl_pool == NULL) {
KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
- PAGE_SHIFT);
+ KGSL_MMU_ALIGN_SHIFT);
goto err_alloc;
}
if (gen_pool_add(pagetable->kgsl_pool,
@@ -467,9 +468,10 @@
}
}
- pagetable->pool = gen_pool_create(PAGE_SHIFT, -1);
+ pagetable->pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT, -1);
if (pagetable->pool == NULL) {
- KGSL_CORE_ERR("gen_pool_create(%d) failed\n", PAGE_SHIFT);
+ KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
+ KGSL_MMU_ALIGN_SHIFT);
goto err_kgsl_pool;
}
@@ -578,12 +580,22 @@
*/
}
+static inline struct gen_pool *
+_get_pool(struct kgsl_pagetable *pagetable, unsigned int flags)
+{
+ if (pagetable->kgsl_pool &&
+ (KGSL_MEMFLAGS_GLOBAL & flags))
+ return pagetable->kgsl_pool;
+ return pagetable->pool;
+}
+
int
kgsl_mmu_map(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc,
unsigned int protflags)
{
int ret;
+ struct gen_pool *pool;
if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
if (memdesc->sglen == 1) {
@@ -604,20 +616,14 @@
}
/* Allocate from kgsl pool if it exists for global mappings */
- if (pagetable->kgsl_pool &&
- (KGSL_MEMFLAGS_GLOBAL & memdesc->priv))
- memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->kgsl_pool,
- memdesc->size, KGSL_MMU_ALIGN_SHIFT);
- else
- memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->pool,
- memdesc->size, KGSL_MMU_ALIGN_SHIFT);
+ pool = _get_pool(pagetable, memdesc->priv);
+ memdesc->gpuaddr = gen_pool_alloc(pool, memdesc->size);
if (memdesc->gpuaddr == 0) {
KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
memdesc->size,
- ((pagetable->kgsl_pool &&
- (KGSL_MEMFLAGS_GLOBAL & memdesc->priv)) ?
- "kgsl_pool" : "general_pool"));
+ (pool == pagetable->kgsl_pool) ?
+ "kgsl_pool" : "general_pool");
KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
pagetable->name, pagetable->stats.mapped,
pagetable->stats.entries);
@@ -648,7 +654,7 @@
err_free_gpuaddr:
spin_unlock(&pagetable->lock);
- gen_pool_free(pagetable->pool, memdesc->gpuaddr, memdesc->size);
+ gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
memdesc->gpuaddr = 0;
return ret;
}
@@ -658,6 +664,7 @@
kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc)
{
+ struct gen_pool *pool;
if (memdesc->size == 0 || memdesc->gpuaddr == 0)
return 0;
@@ -676,15 +683,8 @@
spin_unlock(&pagetable->lock);
- if (pagetable->kgsl_pool &&
- (KGSL_MEMFLAGS_GLOBAL & memdesc->priv))
- gen_pool_free(pagetable->kgsl_pool,
- memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK,
- memdesc->size);
- else
- gen_pool_free(pagetable->pool,
- memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK,
- memdesc->size);
+ pool = _get_pool(pagetable, memdesc->priv);
+ gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
/*
* Don't clear the gpuaddr on global mappings because they
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3238d33..701160c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -777,7 +777,7 @@
input_report_abs(input_dev, ABS_MT_POSITION_Y,
finger[id].y);
input_report_abs(input_dev, ABS_MT_PRESSURE,
- finger[id].area);
+ finger[id].pressure);
} else {
finger[id].status = 0;
}
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index ebfed6c..b60f99f 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -13,6 +13,7 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
obj-$(CONFIG_MSM_CAMERA) += io/ eeprom/ sensors/ actuators/ csi/
+ obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 4447866..034cbc5 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -45,6 +45,10 @@
module_param(msm_camera_v4l2_nr, uint, 0644);
MODULE_PARM_DESC(msm_camera_v4l2_nr, "videoX start number, -1 is autodetect");
+static long msm_server_send_v4l2_evt(void *evt);
+static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
+ unsigned int notification, void *arg);
+
static void msm_queue_init(struct msm_device_queue *queue, const char *name)
{
D("%s\n", __func__);
@@ -178,10 +182,16 @@
return -EINVAL;
}
+ D("%s qid %d evtid %d %d\n", __func__, command->queue_idx,
+ command->evt_id,
+ g_server_dev.server_queue[command->queue_idx].evt_id);
g_server_dev.server_queue[command->queue_idx].ctrl = command;
if (command->evt_id !=
g_server_dev.server_queue[command->queue_idx].evt_id) {
- pr_err("Invalid event id from userspace\n");
+ pr_err("%s Invalid event id from userspace cmd id %d %d qid %d\n",
+ __func__, command->evt_id,
+ g_server_dev.server_queue[command->queue_idx].evt_id,
+ command->queue_idx);
return -EINVAL;
}
@@ -241,6 +251,8 @@
mutex_lock(&server_dev->server_queue_lock);
if (++server_dev->server_evt_id == 0)
server_dev->server_evt_id++;
+ D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+ server_dev->server_evt_id);
server_dev->server_queue[out->queue_idx].evt_id =
server_dev->server_evt_id;
@@ -317,7 +329,7 @@
{
int rc = 0;
struct msm_ctrl_cmd ctrlcmd;
- D("%s\n", __func__);
+ D("%s qid %d\n", __func__, pcam->server_queue_idx);
ctrlcmd.type = MSM_V4L2_OPEN;
ctrlcmd.timeout_ms = 10000;
ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -337,7 +349,7 @@
{
int rc = 0;
struct msm_ctrl_cmd ctrlcmd;
- D("%s\n", __func__);
+ D("%s qid %d\n", __func__, pcam->server_queue_idx);
ctrlcmd.type = MSM_V4L2_CLOSE;
ctrlcmd.timeout_ms = 10000;
ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -1432,7 +1444,7 @@
sub->type++;
D("sub->type while = 0x%x\n", sub->type);
} while (sub->type !=
- V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MAX);
+ V4L2_EVENT_PRIVATE_START + MSM_SVR_RESP_MAX);
} else {
D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type);
rc = v4l2_event_subscribe(fh, sub);
@@ -1555,6 +1567,150 @@
msm_mctl_free(pcam);
return rc;
}
+
+int msm_server_open_client(int *p_qidx)
+{
+ int rc = 0;
+ int server_q_idx = 0;
+ struct msm_cam_server_queue *queue = NULL;
+
+ mutex_lock(&g_server_dev.server_lock);
+ server_q_idx = msm_find_free_queue();
+ if (server_q_idx < 0) {
+ mutex_unlock(&g_server_dev.server_lock);
+ return server_q_idx;
+ }
+
+ *p_qidx = server_q_idx;
+ queue = &g_server_dev.server_queue[server_q_idx];
+ queue->ctrl = NULL;
+ queue->ctrl_data = kzalloc(sizeof(uint8_t) *
+ max_control_command_size, GFP_KERNEL);
+ msm_queue_init(&queue->ctrl_q, "control");
+ msm_queue_init(&queue->eventData_q, "eventdata");
+ queue->queue_active = 1;
+ mutex_unlock(&g_server_dev.server_lock);
+ return rc;
+}
+
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out,
+ int ctrl_id)
+{
+ int rc = 0;
+ void *value;
+ struct msm_queue_cmd *rcmd;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_ctrl_cmd *ctrlcmd;
+ struct msm_cam_server_dev *server_dev = &g_server_dev;
+ struct msm_device_queue *queue =
+ &server_dev->server_queue[out->queue_idx].ctrl_q;
+
+ struct v4l2_event v4l2_evt;
+ struct msm_isp_event_ctrl *isp_event;
+ isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+ if (!isp_event) {
+ pr_err("%s Insufficient memory. return", __func__);
+ return -ENOMEM;
+ }
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!event_qcmd) {
+ pr_err("%s Insufficient memory. return", __func__);
+ kfree(isp_event);
+ return -ENOMEM;
+ }
+
+ D("%s\n", __func__);
+ mutex_lock(&server_dev->server_queue_lock);
+ if (++server_dev->server_evt_id == 0)
+ server_dev->server_evt_id++;
+
+ D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+ server_dev->server_evt_id);
+ server_dev->server_queue[out->queue_idx].evt_id =
+ server_dev->server_evt_id;
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START + ctrl_id;
+ v4l2_evt.u.data[0] = out->queue_idx;
+ /* setup event object to transfer the command; */
+ isp_event->resptype = MSM_CAM_RESP_V4L2;
+ isp_event->isp_data.ctrl = *out;
+ isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = isp_event;
+
+ msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
+ &event_qcmd->list_eventdata);
+
+ /* now send command to config thread in userspace,
+ * and wait for results */
+ v4l2_event_queue(server_dev->server_command_queue.pvdev,
+ &v4l2_evt);
+ D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+ mutex_unlock(&server_dev->server_queue_lock);
+
+ /* wait for config return status */
+ D("Waiting for config status\n");
+ rc = wait_event_interruptible_timeout(queue->wait,
+ !list_empty_careful(&queue->list),
+ msecs_to_jiffies(out->timeout_ms));
+ D("Waiting is over for config status\n");
+ if (list_empty_careful(&queue->list)) {
+ if (!rc)
+ rc = -ETIMEDOUT;
+ if (rc < 0) {
+ kfree(isp_event);
+ pr_err("%s: wait_event error %d\n", __func__, rc);
+ return rc;
+ }
+ }
+
+ rcmd = msm_dequeue(queue, list_control);
+ BUG_ON(!rcmd);
+ D("%s Finished servicing ioctl\n", __func__);
+
+ ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
+ value = out->value;
+ if (ctrlcmd->length > 0)
+ memcpy(value, ctrlcmd->value, ctrlcmd->length);
+
+ memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
+ out->value = value;
+
+ kfree(ctrlcmd);
+ server_dev->server_queue[out->queue_idx].ctrl = NULL;
+
+ free_qcmd(rcmd);
+ kfree(isp_event);
+ D("%s: rc %d\n", __func__, rc);
+ /* rc is the time elapsed. */
+ if (rc >= 0) {
+ /* TODO: Refactor msm_ctrl_cmd::status field */
+ if (out->status == 0)
+ rc = -1;
+ else if (out->status == 1 || out->status == 4)
+ rc = 0;
+ else
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_server_close_client(int idx)
+{
+ int rc = 0;
+ struct msm_cam_server_queue *queue = NULL;
+ mutex_lock(&g_server_dev.server_lock);
+ queue = &g_server_dev.server_queue[idx];
+ queue->queue_active = 0;
+ kfree(queue->ctrl);
+ queue->ctrl = NULL;
+ kfree(queue->ctrl_data);
+ queue->ctrl_data = NULL;
+ msm_queue_drain(&queue->ctrl_q, list_control);
+ msm_drain_eventq(&queue->eventData_q);
+ mutex_unlock(&g_server_dev.server_lock);
+ return rc;
+}
/* v4l2_file_operations */
static int msm_open(struct file *f)
{
@@ -1610,7 +1766,10 @@
pcam_inst->my_index,
pcam->vnode_id, pcam->use_count);
pcam->use_count++;
+ D("%s use_count %d\n", __func__, pcam->use_count);
if (pcam->use_count == 1) {
+ struct msm_cam_server_queue *queue;
+ int ges_evt = MSM_V4L2_GES_CAM_OPEN;
pcam->server_queue_idx = server_q_idx;
queue = &g_server_dev.server_queue[server_q_idx];
queue->ctrl = NULL;
@@ -1620,6 +1779,10 @@
msm_queue_init(&queue->eventData_q, "eventdata");
queue->queue_active = 1;
+ pr_err("%s send gesture evt\n", __func__);
+ msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+ NOTIFY_GESTURE_CAM_EVT, &ges_evt);
+
rc = msm_cam_server_open_session(&g_server_dev, pcam);
if (rc < 0) {
pr_err("%s: cam_server_open_session failed %d\n",
@@ -1713,6 +1876,74 @@
}
mutex_unlock(&pcam->vid_lock);
kfree(pcam_inst);
+ pr_err("%s: error end", __func__);
+ return rc;
+}
+
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam)
+{
+ int rc = 0;
+ struct msm_cam_media_controller *pmctl = NULL;
+
+ pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ D("%s: invalid handle\n", __func__);
+ return -ENODEV;
+ }
+
+ if (pmctl->mctl_release) {
+ rc = pmctl->mctl_release(pmctl);
+ if (rc < 0)
+ pr_err("mctl_release fails %d\n", rc);
+ }
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ kref_put(&pmctl->refcount, msm_release_ion_client);
+#endif
+
+ rc = msm_cam_server_close_session(&g_server_dev, pcam);
+ if (rc < 0)
+ pr_err("msm_cam_server_close_session fails %d\n", rc);
+
+ return rc;
+}
+
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+ int *p_active)
+{
+ int rc = 0;
+ struct msm_cam_media_controller *pmctl = NULL;
+ D("%s: %p", __func__, g_server_dev.pcam_active);
+ *p_active = 0;
+ if (g_server_dev.pcam_active) {
+ D("%s: Active camera present return", __func__);
+ return 0;
+ }
+ rc = msm_cam_server_open_session(&g_server_dev, pcam);
+ if (rc < 0) {
+ pr_err("%s: cam_server_open_session failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ /* Should be set to sensor ops if any but right now its OK!! */
+ if (!pmctl->mctl_open) {
+ D("%s: media contoller is not inited\n",
+ __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+
+ D("%s: call mctl_open\n", __func__);
+ rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
+
+ if (rc < 0) {
+ pr_err("%s: HW open failed rc = 0x%x\n", __func__, rc);
+ return rc;
+ }
+ pmctl->pcam_ptr = pcam;
+ *p_active = 1;
return rc;
}
@@ -1839,6 +2070,7 @@
f->private_data = NULL;
if (pcam->use_count == 0) {
+ int ges_evt = MSM_V4L2_GES_CAM_CLOSE;
if (g_server_dev.use_count > 0) {
rc = msm_send_close_server(pcam);
if (rc < 0)
@@ -1866,6 +2098,9 @@
if (g_server_dev.use_count == 0)
mutex_unlock(&g_server_dev.server_lock);
+
+ msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+ NOTIFY_GESTURE_CAM_EVT, &ges_evt);
}
mutex_unlock(&pcam->vid_lock);
return rc;
@@ -2080,6 +2315,11 @@
rc = 0;
break;
}
+
+ case MSM_CAM_IOCTL_SEND_EVENT:
+ rc = msm_server_send_v4l2_evt(arg);
+ break;
+
default:
pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
break;
@@ -2119,6 +2359,7 @@
static int msm_close_server(struct file *fp)
{
+ struct v4l2_event_subscription sub;
D("%s\n", __func__);
mutex_lock(&g_server_dev.server_lock);
if (g_server_dev.use_count > 0)
@@ -2135,10 +2376,36 @@
v4l2_event_queue(
g_server_dev.pcam_active->pvdev, &v4l2_ev);
}
+ sub.type = V4L2_EVENT_ALL;
+ msm_server_v4l2_unsubscribe_event(
+ &g_server_dev.server_command_queue.eventHandle, &sub);
}
return 0;
}
+static long msm_server_send_v4l2_evt(void *evt)
+{
+ struct v4l2_event *v4l2_ev = (struct v4l2_event *)evt;
+ int rc = 0;
+
+ if (NULL == evt) {
+ pr_err("%s: evt is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ D("%s: evt type 0x%x\n", __func__, v4l2_ev->type);
+ if ((v4l2_ev->type >= MSM_GES_APP_EVT_MIN) &&
+ (v4l2_ev->type < MSM_GES_APP_EVT_MAX)) {
+ msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+ NOTIFY_GESTURE_EVT, v4l2_ev);
+ } else {
+ pr_err("%s: Invalid evt %d\n", __func__, v4l2_ev->type);
+ rc = -EINVAL;
+ }
+ D("%s: end\n", __func__);
+
+ return rc;
+}
static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
unsigned int cmd, unsigned long evt)
@@ -2631,6 +2898,14 @@
rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
break;
+ case NOTIFY_GESTURE_EVT:
+ rc = v4l2_subdev_call(g_server_dev.gesture_device,
+ core, ioctl, VIDIOC_MSM_GESTURE_EVT, arg);
+ break;
+ case NOTIFY_GESTURE_CAM_EVT:
+ rc = v4l2_subdev_call(g_server_dev.gesture_device,
+ core, ioctl, VIDIOC_MSM_GESTURE_CAM_EVT, arg);
+ break;
default:
break;
}
@@ -2670,6 +2945,8 @@
if (index >= MAX_NUM_AXI_DEV)
return -EINVAL;
g_server_dev.axi_device[index] = sd;
+ } else if (sdev_type == GESTURE_DEV) {
+ g_server_dev.gesture_device = sd;
}
err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 04e224c..6798cbb 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -32,6 +32,7 @@
#include <mach/camera.h>
#include <media/msm_isp.h>
#include <linux/ion.h>
+#include <media/msm_gestures.h>
#define MSM_V4L2_DIMENSION_SIZE 96
#define MAX_DEV_NAME_LEN 50
@@ -69,6 +70,7 @@
SENSOR_DEV,
ACTUATOR_DEV,
EEPROM_DEV,
+ GESTURE_DEV,
};
/* msm queue management APIs*/
@@ -150,6 +152,8 @@
NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
NOTIFY_VFE_IRQ,
NOTIFY_AXI_IRQ,
+ NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
+ NOTIFY_GESTURE_CAM_EVT, /* arg = int */
NOTIFY_INVALID
};
@@ -330,6 +334,8 @@
struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
struct mutex dev_lock;
+ int active;
+ int use_count;
};
/* abstract camera device for each sensor successfully probed*/
@@ -384,7 +390,8 @@
struct msm_mem_map_info mem_map;
};
-#define MAX_NUM_ACTIVE_CAMERA 2
+/* 2 for camera, 1 for gesture */
+#define MAX_NUM_ACTIVE_CAMERA 3
struct msm_cam_server_queue {
uint32_t queue_active;
@@ -444,6 +451,7 @@
struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];
struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
+ struct v4l2_subdev *gesture_device;
};
/* camera server related functions */
@@ -566,6 +574,12 @@
uint32_t msm_camera_get_mctl_handle(void);
struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle);
void msm_camera_free_mctl(uint32_t handle);
+int msm_server_open_client(int *p_qidx);
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
+int msm_server_close_client(int idx);
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+ int *p_active);
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
#endif /* __KERNEL__ */
#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
new file mode 100644
index 0000000..654594d
--- /dev/null
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -0,0 +1,497 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include <media/msm_camera.h>
+#include <media/msm_gestures.h>
+#include <media/v4l2-ctrls.h>
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_gesture: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+struct msm_gesture_ctrl {
+ int queue_id;
+ atomic_t active;
+ struct v4l2_ctrl_handler ctrl_handler;
+ int num_ctrls;
+ struct v4l2_fh *p_eventHandle;
+ struct v4l2_subdev *sd;
+ struct msm_ges_evt event;
+ int camera_opened;
+};
+
+static struct msm_gesture_ctrl g_gesture_ctrl;
+
+int msm_gesture_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ D("%s\n", __func__);
+ if (sub->type == V4L2_EVENT_ALL)
+ sub->type = MSM_GES_APP_NOTIFY_EVENT;
+ return v4l2_event_subscribe(fh, sub);
+}
+
+static int msm_gesture_send_ctrl(struct msm_gesture_ctrl *p_gesture_ctrl,
+ int type, void *value, int length, uint32_t timeout)
+{
+ int rc = 0;
+ struct msm_ctrl_cmd ctrlcmd;
+ D("%s qid %d\n", __func__, p_gesture_ctrl->queue_id);
+ ctrlcmd.type = type;
+ ctrlcmd.timeout_ms = timeout;
+ ctrlcmd.length = length;
+ ctrlcmd.value = value;
+ ctrlcmd.vnode_id = 0;
+ ctrlcmd.queue_idx = p_gesture_ctrl->queue_id;
+ ctrlcmd.config_ident = 0;
+
+ rc = msm_server_send_ctrl(&ctrlcmd, MSM_GES_RESP_V4L2);
+ return rc;
+}
+
+static int msm_gesture_proc_ctrl_cmd(struct msm_gesture_ctrl *p_gesture_ctrl,
+ struct v4l2_control *ctrl)
+{
+ int rc = 0;
+ struct msm_ctrl_cmd *tmp_cmd = NULL;
+ uint8_t *ctrl_data = NULL;
+ void __user *uptr_cmd;
+ void __user *uptr_value;
+ uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
+ uint32_t value_len;
+
+ tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
+ uptr_cmd = (void __user *)ctrl->value;
+ uptr_value = (void __user *)tmp_cmd->value;
+ value_len = tmp_cmd->length;
+
+ D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+ __func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
+ (uint32_t)uptr_value, tmp_cmd->length);
+
+ ctrl_data = kzalloc(value_len + cmd_len, GFP_KERNEL);
+ if (ctrl_data == 0) {
+ pr_err("%s could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+ tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
+ if (copy_from_user((void *)ctrl_data, uptr_cmd,
+ cmd_len)) {
+ pr_err("%s: copy_from_user failed.\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+ tmp_cmd->value = (void *)(ctrl_data + cmd_len);
+ if (uptr_value && tmp_cmd->length > 0) {
+ if (copy_from_user((void *)tmp_cmd->value, uptr_value,
+ value_len)) {
+ pr_err("%s: copy_from_user failed, size=%d\n",
+ __func__, value_len);
+ rc = -EINVAL;
+ goto end;
+ }
+ } else
+ tmp_cmd->value = NULL;
+
+ /* send command to config thread in usersspace, and get return value */
+ rc = msm_server_send_ctrl((struct msm_ctrl_cmd *)ctrl_data,
+ MSM_GES_RESP_V4L2);
+ D("%s: msm_server_control rc=%d\n", __func__, rc);
+ if (rc == 0) {
+ if (uptr_value && tmp_cmd->length > 0 &&
+ copy_to_user((void __user *)uptr_value,
+ (void *)(ctrl_data + cmd_len),
+ tmp_cmd->length)) {
+ pr_err("%s: copy_to_user failed, size=%d\n",
+ __func__, tmp_cmd->length);
+ rc = -EINVAL;
+ goto end;
+ }
+ tmp_cmd->value = uptr_value;
+ if (copy_to_user((void __user *)uptr_cmd,
+ (void *)tmp_cmd, cmd_len)) {
+ pr_err("%s: copy_to_user failed in cpy, size=%d\n",
+ __func__, cmd_len);
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+end:
+ D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
+ __func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
+ tmp_cmd->length, tmp_cmd->status, rc);
+ kfree(ctrl_data);
+ return rc;
+}
+
+static int msm_gesture_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ int rc = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s ctrl->id %d\n", __func__, ctrl->id);
+ rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, ctrl);
+ if (rc != 0) {
+ pr_err("%s set ctrl failed %d\n", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_gesture_s_ctrl_ops(struct v4l2_ctrl *ctrl)
+{
+ int rc = 0;
+ struct v4l2_control control;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ control.id = ctrl->id;
+ control.value = ctrl->val;
+ D("%s ctrl->id 0x%x\n", __func__, ctrl->id);
+ rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+ if (rc != 0) {
+ pr_err("%s proc ctrl failed %d\n", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_gesture_s_ctrl_ext(struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls)
+{
+ int rc = 0;
+ struct v4l2_control control;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ if ((ctrls->count < 1) || (NULL == ctrls->controls)) {
+ pr_err("%s invalid ctrl failed\n", __func__);
+ return -EINVAL;
+ }
+ control.id = ctrls->controls->id;
+ control.value = ctrls->controls->value;
+ D("%s ctrl->id %d\n", __func__, control.id);
+ rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+ if (rc != 0) {
+ pr_err("%s proc ctrl failed %d\n", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_gesture_handle_event(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+ int rc = 0;
+ struct v4l2_event *evt = (struct v4l2_event *)arg;
+ struct msm_ges_evt *p_ges_evt = NULL;
+ D("%s: Received gesture evt 0x%x ", __func__, evt->type);
+ p_gesture_ctrl->event.evt_len = 0;
+ p_gesture_ctrl->event.evt_data = NULL;
+ if (0 != evt->u.data[0]) {
+ p_ges_evt = (struct msm_ges_evt *)evt->u.data;
+ D("%s: event data %p len %d", __func__,
+ p_ges_evt->evt_data,
+ p_ges_evt->evt_len);
+
+ if (p_ges_evt->evt_len > 0) {
+ p_gesture_ctrl->event.evt_data =
+ kzalloc(p_ges_evt->evt_len, GFP_KERNEL);
+
+ if (NULL == p_gesture_ctrl->event.evt_data) {
+ pr_err("%s: cannot allocate event", __func__);
+ rc = -ENOMEM;
+ } else {
+ if (copy_from_user(
+ (void *)p_gesture_ctrl->event.evt_data,
+ (void __user *)p_ges_evt->evt_data,
+ p_ges_evt->evt_len)) {
+ pr_err("%s: copy_from_user failed",
+ __func__);
+ rc = -EFAULT;
+ } else {
+ D("%s: copied the event", __func__);
+ p_gesture_ctrl->event.evt_len =
+ p_ges_evt->evt_len;
+ }
+ }
+ }
+ }
+
+ if (rc == 0) {
+ ktime_get_ts(&evt->timestamp);
+ v4l2_event_queue(&sd->devnode, evt);
+ }
+ D("%s: exit rc %d ", __func__, rc);
+ return rc;
+}
+
+static int msm_gesture_get_evt_payload(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+ int rc = 0;
+ struct msm_ges_evt *p_ges_evt = (struct msm_ges_evt *)arg;
+ D("%s: enter ", __func__);
+ if (NULL != p_gesture_ctrl->event.evt_data) {
+ D("%s: event data %p len %d", __func__,
+ p_gesture_ctrl->event.evt_data,
+ p_gesture_ctrl->event.evt_len);
+
+ if (copy_to_user((void __user *)p_ges_evt->evt_data,
+ p_gesture_ctrl->event.evt_data,
+ p_gesture_ctrl->event.evt_len)) {
+ pr_err("%s: copy_to_user failed.\n", __func__);
+ rc = -EFAULT;
+ } else {
+ D("%s: copied the event", __func__);
+ p_ges_evt->evt_len = p_gesture_ctrl->event.evt_len;
+ }
+ }
+ D("%s: exit rc %d ", __func__, rc);
+ return rc;
+}
+
+static int msm_gesture_handle_cam_event(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl, int cam_evt)
+{
+ int rc = 0;
+ D("%s: cam_evt %d ", __func__, cam_evt);
+
+ if ((cam_evt != MSM_V4L2_GES_CAM_OPEN)
+ && (cam_evt != MSM_V4L2_GES_CAM_CLOSE)) {
+ pr_err("%s: error invalid event %d ", __func__, cam_evt);
+ return -EINVAL;
+ }
+
+ p_gesture_ctrl->camera_opened =
+ (cam_evt == MSM_V4L2_GES_CAM_OPEN);
+
+ if (atomic_read(&p_gesture_ctrl->active) == 0) {
+ D("%s gesture not active\n", __func__);
+ return 0;
+ }
+
+ rc = msm_gesture_send_ctrl(p_gesture_ctrl, cam_evt, NULL,
+ 0, 2000);
+ if (rc != 0) {
+ pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ }
+ D("%s exit rc %d\n", __func__, rc);
+ return rc;
+}
+
+long msm_gesture_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ int rc = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s\n", __func__);
+ switch (cmd) {
+ case MSM_GES_IOCTL_CTRL_COMMAND: {
+ struct v4l2_control *ctrl = (struct v4l2_control *)arg;
+ D("%s MSM_GES_IOCTL_CTRL_COMMAND arg %p size %d\n", __func__,
+ arg, sizeof(ctrl));
+ rc = msm_gesture_s_ctrl(sd, ctrl);
+ break;
+ }
+ case VIDIOC_MSM_GESTURE_EVT: {
+ rc = msm_gesture_handle_event(sd, p_gesture_ctrl, arg);
+ break;
+ }
+ case VIDIOC_MSM_GESTURE_CAM_EVT: {
+ int cam_evt = *((int *)arg);
+ rc = msm_gesture_handle_cam_event(sd, p_gesture_ctrl, cam_evt);
+ break;
+ }
+ case MSM_GES_GET_EVT_PAYLOAD: {
+ rc = msm_gesture_get_evt_payload(sd, p_gesture_ctrl, arg);
+ break;
+ }
+ default:
+ pr_err("%s: Invalid ioctl %d", __func__, cmd);
+ break;
+ }
+ D("%s exit rc %d\n", __func__, rc);
+ return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_gesture_ctrl_ops = {
+ .s_ctrl = msm_gesture_s_ctrl_ops,
+};
+
+static const struct v4l2_ctrl_config msm_gesture_ctrl_filter = {
+ .ops = &msm_gesture_ctrl_ops,
+ .id = MSM_GESTURE_CID_CTRL_CMD,
+ .name = "Gesture ctrl",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 0x7fffffff,
+ .step = 1,
+ .min = 0x80000000,
+};
+
+static int msm_gesture_init_ctrl(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl)
+{
+ int rc = 0;
+ p_gesture_ctrl->num_ctrls = 1;
+ p_gesture_ctrl->ctrl_handler.error = 0;
+ v4l2_ctrl_handler_init(&p_gesture_ctrl->ctrl_handler,
+ p_gesture_ctrl->num_ctrls);
+ v4l2_ctrl_new_custom(&p_gesture_ctrl->ctrl_handler,
+ &msm_gesture_ctrl_filter, p_gesture_ctrl);
+ if (p_gesture_ctrl->ctrl_handler.error) {
+ int err = p_gesture_ctrl->ctrl_handler.error;
+ D("%s: error adding control %d", __func__, err);
+ p_gesture_ctrl->ctrl_handler.error = 0;
+ }
+ sd->ctrl_handler = &p_gesture_ctrl->ctrl_handler;
+ return rc;
+}
+
+static int msm_gesture_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ int rc = 0, rc_err = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s\n", __func__);
+ if (atomic_read(&p_gesture_ctrl->active) != 0) {
+ pr_err("%s already opened\n", __func__);
+ return -EINVAL;
+ }
+ memset(&p_gesture_ctrl->event, 0x0, sizeof(struct msm_ges_evt));
+ rc = msm_server_open_client(&p_gesture_ctrl->queue_id);
+ if (rc != 0) {
+ pr_err("%s open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = msm_gesture_init_ctrl(sd, p_gesture_ctrl);
+ if (rc != 0) {
+ pr_err("%s init ctrl failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_OPEN, NULL,
+ 0, 10000);
+ if (rc != 0) {
+ pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ atomic_inc(&p_gesture_ctrl->active);
+
+ return rc;
+
+err:
+ rc_err = msm_server_close_client(p_gesture_ctrl->queue_id);
+ if (rc_err != 0)
+ pr_err("%s failed %d\n", __func__, rc);
+ return rc;
+}
+
+static int msm_gesture_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ int rc = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s\n", __func__);
+ if (atomic_read(&p_gesture_ctrl->active) == 0) {
+ pr_err("%s already closed\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_CLOSE, NULL,
+ 0, 10000);
+ if (rc != 0)
+ pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+
+ rc = msm_server_close_client(p_gesture_ctrl->queue_id);
+ if (rc != 0)
+ pr_err("%s failed %d\n", __func__, rc);
+
+ v4l2_ctrl_handler_free(&p_gesture_ctrl->ctrl_handler);
+ kfree(p_gesture_ctrl->event.evt_data);
+
+ atomic_dec(&p_gesture_ctrl->active);
+ g_gesture_ctrl.queue_id = -1;
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_gesture_core_ops = {
+ .s_ctrl = msm_gesture_s_ctrl,
+ .s_ext_ctrls = msm_gesture_s_ctrl_ext,
+ .ioctl = msm_gesture_ioctl,
+ .subscribe_event = msm_gesture_subscribe_event,
+};
+
+static struct v4l2_subdev_video_ops msm_gesture_video_ops;
+
+static struct v4l2_subdev_ops msm_gesture_subdev_ops = {
+ .core = &msm_gesture_core_ops,
+ .video = &msm_gesture_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_gesture_internal_ops = {
+ .open = msm_gesture_open,
+ .close = msm_gesture_close,
+};
+
+static int msm_gesture_node_register(void)
+{
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ struct v4l2_subdev *gesture_subdev =
+ kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ D("%s\n", __func__);
+ if (!gesture_subdev) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ };
+
+ v4l2_subdev_init(gesture_subdev, &msm_gesture_subdev_ops);
+ gesture_subdev->internal_ops = &msm_gesture_internal_ops;
+ gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(gesture_subdev->name,
+ sizeof(gesture_subdev->name), "gesture");
+
+ media_entity_init(&gesture_subdev->entity, 0, NULL, 0);
+ gesture_subdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ gesture_subdev->entity.group_id = GESTURE_DEV;
+ gesture_subdev->entity.name = gesture_subdev->name;
+
+ /* events */
+ gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+ gesture_subdev->nevents = MAX_GES_EVENTS;
+
+ msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+
+ gesture_subdev->entity.revision = gesture_subdev->devnode.num;
+
+ atomic_set(&p_gesture_ctrl->active, 0);
+ p_gesture_ctrl->queue_id = -1;
+ p_gesture_ctrl->event.evt_data = NULL;
+ p_gesture_ctrl->event.evt_len = 0;
+ return 0;
+}
+
+static int __init msm_gesture_init_module(void)
+{
+ return msm_gesture_node_register();
+}
+
+module_init(msm_gesture_init_module);
+MODULE_DESCRIPTION("MSM Gesture driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index e878063..e9eb68f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -923,7 +923,6 @@
struct msm_cam_v4l2_device *pcam = NULL;
struct msm_cam_v4l2_dev_inst *pcam_inst;
struct msm_cam_media_controller *pmctl;
- D("%s : E ", __func__);
if (f == NULL) {
pr_err("%s :: cannot open video driver data", __func__);
@@ -935,8 +934,8 @@
pr_err("%s NULL pointer passed in!\n", __func__);
return rc;
}
- pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ D("%s : E use_count %d", __func__, pcam->mctl_node.use_count);
mutex_lock(&pcam->mctl_node.dev_lock);
for (i = 0; i < MSM_DEV_INST_MAX; i++) {
if (pcam->mctl_node.dev_inst[i] == NULL)
@@ -960,6 +959,21 @@
D("%s pcam_inst %p my_index = %d\n", __func__,
pcam_inst, pcam_inst->my_index);
+ rc = msm_cam_server_open_mctl_session(pcam,
+ &pcam->mctl_node.active);
+ if (rc < 0) {
+ pr_err("%s: mctl session open failed %d", __func__, rc);
+ mutex_unlock(&pcam->mctl_node.dev_lock);
+ return rc;
+ }
+
+ pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ pr_err("%s mctl NULL!\n", __func__);
+ return rc;
+ }
+
+ D("%s active %d\n", __func__, pcam->mctl_node.active);
rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
pcam->mctl_node.pvdev);
if (rc < 0) {
@@ -973,6 +987,7 @@
D("f->private_data = 0x%x, pcam = 0x%x\n",
(u32)f->private_data, (u32)pcam_inst);
+ pcam->mctl_node.use_count++;
mutex_unlock(&pcam->mctl_node.dev_lock);
D("%s : X ", __func__);
return rc;
@@ -1030,6 +1045,17 @@
pmctl = msm_camera_get_mctl(pcam->mctl_handle);
mutex_lock(&pcam->mctl_node.dev_lock);
+ D("%s : active %d ", __func__, pcam->mctl_node.active);
+ if (pcam->mctl_node.active == 1) {
+ rc = msm_cam_server_close_mctl_session(pcam);
+ if (rc < 0) {
+ pr_err("%s: mctl session close failed %d",
+ __func__, rc);
+ mutex_unlock(&pcam->mctl_node.dev_lock);
+ return rc;
+ }
+ pmctl = NULL;
+ }
pcam_inst->streamon = 0;
pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] = NULL;
if (pcam_inst->vbqueue_initialized)
@@ -1040,10 +1066,14 @@
v4l2_fh_exit(&pcam_inst->eventHandle);
kfree(pcam_inst);
- kref_put(&pmctl->refcount, msm_release_ion_client);
+ if (NULL != pmctl) {
+ D("%s : release ion client", __func__);
+ kref_put(&pmctl->refcount, msm_release_ion_client);
+ }
f->private_data = NULL;
mutex_unlock(&pcam->mctl_node.dev_lock);
- D("%s : X ", __func__);
+ pcam->mctl_node.use_count--;
+ D("%s : use_count %d X ", __func__, pcam->mctl_node.use_count);
return rc;
}
@@ -1246,6 +1276,11 @@
pb->m.planes[i].data_offset;
pcam_inst->buf_offset[pb->index][i].addr_offset =
pb->m.planes[i].reserved[0];
+ pcam_inst->plane_info.plane[i].offset = 0;
+ D("%s, len %d user[%d] %p buf_len %d\n",
+ __func__, pb->length, i,
+ (void *)pb->m.planes[i].m.userptr,
+ pb->m.planes[i].length);
}
} else {
D("%s stored reserved info %d", __func__, pb->reserved);
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 5bc81a7..42d13a1 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -431,8 +431,8 @@
int pp_divert_type = 0, pp_type = 0;
msm_mctl_check_pp(p_mctl, image_mode, &pp_divert_type, &pp_type);
- D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x",
- __func__, pp_type, pp_divert_type, frame_id);
+ D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x image_mode %d",
+ __func__, pp_type, pp_divert_type, frame_id, image_mode);
if (pp_type || pp_divert_type)
rc = msm_mctl_do_pp_divert(p_mctl,
image_mode, fbuf, frame_id, pp_type);
@@ -440,9 +440,26 @@
idx = msm_mctl_img_mode_to_inst_index(
p_mctl, image_mode, 0);
if (idx < 0) {
- pr_err("%s Invalid instance, dropping buffer\n",
- __func__);
- return idx;
+ /* check mctl node */
+ if ((image_mode >= 0) &&
+ p_mctl->pcam_ptr->mctl_node.
+ dev_inst_map[image_mode]) {
+ int index = p_mctl->pcam_ptr->mctl_node.
+ dev_inst_map[image_mode]->my_index;
+ pcam_inst = p_mctl->pcam_ptr->mctl_node.
+ dev_inst[index];
+ D("%s: Mctl node index %d inst %p",
+ __func__, index, pcam_inst);
+ rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
+ image_mode, fbuf,
+ &frame_id, 1);
+ D("%s mctl node buf done %d\n", __func__, 0);
+ return -EINVAL;
+ } else {
+ pr_err("%s Invalid instance, dropping buffer\n",
+ __func__);
+ return idx;
+ }
}
pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
@@ -573,6 +590,10 @@
plane_offset =
mem->offset.sp_off.cbcr_off;
+ D("%s: data off %d plane off %d",
+ __func__,
+ pcam_inst->buf_offset[buf_idx][i].
+ data_offset, plane_offset);
free_buf->ch_paddr[i] = (uint32_t)
videobuf2_to_pmem_contig(&buf->vidbuf, i) +
pcam_inst->buf_offset[buf_idx][i].data_offset +
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index becdd95..3e8d3be 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -3056,7 +3056,7 @@
ch2_paddr = vfe32_get_ch_addr(ping_pong,
vfe32_ctrl->outpath.out1.ch2);
- pr_debug("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
__func__, ch0_paddr, ch1_paddr, ch2_paddr);
if (free_buf) {
/* Y channel */
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index d30d48b..48f1d5d 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -21,8 +21,6 @@
DEFINE_MUTEX(ov5647_mut);
-
-
static struct msm_camera_i2c_reg_conf ov5647_start_settings[] = {
{0x4202, 0x00}, /* streaming on */
};
@@ -159,6 +157,34 @@
{0x4004, 0x02},
};
+static struct msm_camera_i2c_reg_conf ov5647_zsl_settings[] = {
+ {0x3035, 0x21},
+ {0x3036, 0x2f},
+ {0x3821, 0x06},
+ {0x3820, 0x00},
+ {0x3612, 0x0b},
+ {0x3618, 0x04},
+ {0x380c, 0x0a},
+ {0x380d, 0x8c},
+ {0x380e, 0x07},
+ {0x380f, 0xb0},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3709, 0x12},
+ {0x3808, 0x0a},
+ {0x3809, 0x30},
+ {0x380a, 0x07},
+ {0x380b, 0xa0},
+ {0x3800, 0x00},
+ {0x3801, 0x04},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3b},
+ {0x3806, 0x07},
+ {0x3807, 0xa3},
+ {0x4004, 0x04},
+};
static struct msm_camera_i2c_reg_conf ov5647_recommend_settings[] = {
{0x3035, 0x11},
@@ -313,6 +339,8 @@
ARRAY_SIZE(ov5647_video_60fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
{&ov5647_video_90fps_settings[0],
ARRAY_SIZE(ov5647_video_90fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov5647_zsl_settings[0],
+ ARRAY_SIZE(ov5647_zsl_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
static struct msm_camera_csi_params ov5647_csi_params = {
@@ -370,6 +398,15 @@
.op_pixel_clk = 159408000,
.binning_factor = 0x0,
},
+ { /* For ZSL */
+ .x_output = 0xA30, /*2608*/ /*for 5Mp*/
+ .y_output = 0x7A0, /*1952*/
+ .line_length_pclk = 0xA8C,
+ .frame_length_lines = 0x7B0,
+ .vt_pixel_clk = 79704000,
+ .op_pixel_clk = 159408000,
+ .binning_factor = 0x0,
+ },
};
@@ -381,10 +418,11 @@
};
static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
- &ov5647_csi_params,
- &ov5647_csi_params,
- &ov5647_csi_params,
- &ov5647_csi_params,
+ &ov5647_csi_params, /* Snapshot */
+ &ov5647_csi_params, /* Preview */
+ &ov5647_csi_params, /* 60fps */
+ &ov5647_csi_params, /* 90fps */
+ &ov5647_csi_params, /* ZSL */
};
static struct msm_sensor_id_info_t ov5647_id_info = {
@@ -711,6 +749,8 @@
}
+static int32_t vfe_clk = 266667000;
+
int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res)
{
@@ -762,6 +802,10 @@
0x4800, 0x4,
MSM_CAMERA_I2C_BYTE_DATA);
msleep(266);
+ if (res == MSM_SENSOR_RES_4)
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_PCLK_CHANGE,
+ &vfe_clk);
s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
msleep(50);
}
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
index 2324495..e7970d5 100644
--- a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
@@ -247,7 +247,43 @@
.video = &ov7692_subdev_video_ops,
};
+int32_t ov7692_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ int32_t rc = 0;
+ struct msm_camera_sensor_info *info = NULL;
+ info = s_ctrl->sensordata;
+ if (info->pmic_gpio_enable) {
+ info->sensor_lcd_gpio_onoff(1);
+ usleep_range(5000, 5100);
+ }
+
+ rc = msm_sensor_power_up(s_ctrl);
+ if (rc < 0) {
+ CDBG("%s: msm_sensor_power_up failed\n", __func__);
+ return rc;
+ }
+
+ return rc;
+}
+
+int32_t ov7692_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ int32_t rc = 0;
+ struct msm_camera_sensor_info *info = NULL;
+
+ rc = msm_sensor_power_down(s_ctrl);
+ if (rc < 0)
+ CDBG("%s: msm_sensor_power_down failed\n", __func__);
+
+ info = s_ctrl->sensordata;
+ if (info->pmic_gpio_enable) {
+ info->pmic_gpio_enable = 0;
+ info->sensor_lcd_gpio_onoff(0);
+ usleep_range(5000, 5100);
+ }
+ return rc;
+}
static struct msm_sensor_fn_t ov7692_func_tbl = {
.sensor_start_stream = msm_sensor_start_stream,
@@ -257,8 +293,8 @@
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
.sensor_config = msm_sensor_config,
- .sensor_power_up = msm_sensor_power_up,
- .sensor_power_down = msm_sensor_power_down,
+ .sensor_power_up = ov7692_sensor_power_up,
+ .sensor_power_down = ov7692_sensor_power_down,
};
static struct msm_sensor_reg_t ov7692_regs = {
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index b7ae0f4..8cad387 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -191,7 +191,7 @@
}
vbuf->v4l2_buf.timestamp =
- ns_to_timeval(frame_data->time_stamp);
+ ns_to_timeval(frame_data->time_stamp * NSEC_PER_USEC);
WFD_MSG_DBG("bytes used %d, ts: %d.%d, frame type is %d\n",
frame_data->data_len,
@@ -1051,6 +1051,7 @@
struct v4l2_fract *frate = arg;
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_frame_rate vcd_frame_rate;
+ struct vcd_property_vop_timing_constant_delta vcd_delta;
int rc;
vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
vcd_property_hdr.sz =
@@ -1060,8 +1061,25 @@
vcd_frame_rate.fps_numerator = frate->denominator;
rc = vcd_set_property(client_ctx->vcd_handle,
&vcd_property_hdr, &vcd_frame_rate);
- if (rc)
+ if (rc) {
WFD_MSG_ERR("Failed to set frame rate, rc = %d\n", rc);
+ goto set_framerate_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_VOP_TIMING_CONSTANT_DELTA;
+ vcd_property_hdr.sz = sizeof(vcd_delta);
+
+ vcd_delta.constant_delta = (frate->numerator * USEC_PER_SEC) /
+ frate->denominator;
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_delta);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to set frame delta, rc = %d", rc);
+ goto set_framerate_fail;
+ }
+
+set_framerate_fail:
return rc;
}
@@ -1827,12 +1845,16 @@
struct venc_buf_info *venc_buf = arg;
struct mem_region *mregion = venc_buf->mregion;
struct vcd_frame_data vcd_input_buffer = {0};
+ int64_t ts = 0;
+
+ ts = venc_buf->timestamp;
+ do_div(ts, NSEC_PER_USEC);
vcd_input_buffer.virtual = mregion->kvaddr;
vcd_input_buffer.frm_clnt_data = (u32)mregion;
vcd_input_buffer.ip_frm_tag = (u32)mregion;
vcd_input_buffer.data_len = mregion->size;
- vcd_input_buffer.time_stamp = venc_buf->timestamp;
+ vcd_input_buffer.time_stamp = ts;
vcd_input_buffer.offset = 0;
rc = vcd_encode_frame(client_ctx->vcd_handle,
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 2a25089..76d38c1 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -41,7 +41,7 @@
};
struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_intf;
+static int wcd9xxx_intf = -1;
static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *dest, bool interface_reg)
@@ -331,17 +331,35 @@
pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
idbyte_0, idbyte_1, idbyte_2, idbyte_3);
- if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+ if (wcd9xxx->slim != NULL) {
+ if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+ if (TABLA_IS_1_X(wcd9xxx->version)) {
+ wcd9xxx_dev = tabla1x_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+ } else {
+ wcd9xxx_dev = tabla_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+ }
+ } else {
+ wcd9xxx_dev = sitar_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+ }
+ } else {
+ /* Need to add here check for Tabla.
+ * For now the read of version takes
+ * care of now only tabla.
+ */
+ pr_debug("%s : Read codec version using I2C\n", __func__);
if (TABLA_IS_1_X(wcd9xxx->version)) {
wcd9xxx_dev = tabla1x_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
- } else {
+ } else if (TABLA_IS_2_0(wcd9xxx->version)) {
wcd9xxx_dev = tabla_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+ } else {
+ wcd9xxx_dev = sitar_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
- } else {
- wcd9xxx_dev = sitar_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
ret = mfd_add_devices(wcd9xxx->dev, -1,
@@ -372,7 +390,8 @@
wake_lock_destroy(&wcd9xxx->wlock);
mutex_destroy(&wcd9xxx->io_lock);
mutex_destroy(&wcd9xxx->xfer_lock);
- slim_remove_device(wcd9xxx->slim_slave);
+ if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ slim_remove_device(wcd9xxx->slim_slave);
kfree(wcd9xxx);
}
@@ -478,12 +497,11 @@
};
#endif
-static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx,
+ struct wcd9xxx_pdata *pdata)
{
int ret;
int i;
- struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
-
wcd9xxx->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
ARRAY_SIZE(pdata->regulator),
GFP_KERNEL);
@@ -695,6 +713,10 @@
int ret = 0;
static int device_id;
+ if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ pr_info("tabla card is already detected in slimbus mode\n");
+ return -ENODEV;
+ }
if (device_id > 0) {
wcd9xxx_modules[device_id++].client = client;
pr_info("probe for other slaves devices of tabla\n");
@@ -721,8 +743,7 @@
dev_set_drvdata(&client->dev, wcd9xxx);
wcd9xxx->dev = &client->dev;
wcd9xxx->reset_gpio = pdata->reset_gpio;
-
- ret = wcd9xxx_enable_supplies(wcd9xxx);
+ ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
if (ret) {
pr_err("%s: Fail to enable Codec supplies\n", __func__);
goto err_codec;
@@ -809,7 +830,7 @@
wcd9xxx->reset_gpio = pdata->reset_gpio;
wcd9xxx->dev = &slim->dev;
- ret = wcd9xxx_enable_supplies(wcd9xxx);
+ ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
if (ret)
goto err_codec;
usleep_range(5, 5);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0d11dca..4967c4e 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -55,6 +55,7 @@
#include <mach/dma.h>
#include <mach/sdio_al.h>
#include <mach/mpm.h>
+#include <mach/msm_bus.h>
#include "msm_sdcc.h"
#include "msm_sdcc_dml.h"
@@ -72,6 +73,8 @@
/* Use SPS only if transfer size is more than this macro */
#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
+#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
+
#if defined(CONFIG_DEBUG_FS)
static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
static struct dentry *debugfs_dir;
@@ -1164,6 +1167,8 @@
if (data->flags & MMC_DATA_READ)
datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
+ else if (host->curr.use_wr_data_pend)
+ datactrl |= MCI_DATA_PEND;
clks = (unsigned long long)data->timeout_ns * host->clk_rate;
do_div(clks, 1000000000UL);
@@ -1639,13 +1644,11 @@
msmsdcc_request_end(host, cmd->mrq);
}
}
- } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
- if (cmd->data->flags & MMC_DATA_READ)
- msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
- else
- msmsdcc_request_start(host, host->curr.mrq);
} else if (cmd->data) {
- if (!(cmd->data->flags & MMC_DATA_READ))
+ if (cmd == host->curr.mrq->sbc)
+ msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
+ else if ((cmd->data->flags & MMC_DATA_WRITE) &&
+ !host->curr.use_wr_data_pend)
msmsdcc_start_data(host, cmd->data, NULL, 0);
}
}
@@ -1921,12 +1924,17 @@
static void
msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
{
- if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
+ if (mrq->data) {
/* Queue/read data, daisy-chain command when data starts */
- if (mrq->sbc)
- msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
+ if ((mrq->data->flags & MMC_DATA_READ) ||
+ host->curr.use_wr_data_pend)
+ msmsdcc_start_data(host, mrq->data,
+ mrq->sbc ? mrq->sbc : mrq->cmd,
+ 0);
else
- msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
+ msmsdcc_start_command(host,
+ mrq->sbc ? mrq->sbc : mrq->cmd,
+ 0);
} else {
msmsdcc_start_command(host, mrq->cmd, 0);
}
@@ -2022,20 +2030,18 @@
host->sdcc_version) {
host->curr.wait_for_auto_prog_done = 1;
}
+ if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
+ (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
+ host->curr.use_wr_data_pend = true;
}
if (mrq->data && mrq->sbc) {
mrq->sbc->mrq = mrq;
mrq->sbc->data = mrq->data;
- if (mrq->data->flags & MMC_DATA_WRITE) {
+ if (mrq->data->flags & MMC_DATA_WRITE)
host->curr.wait_for_auto_prog_done = 1;
- msmsdcc_start_command(host, mrq->sbc, 0);
- } else {
- msmsdcc_request_start(host, mrq);
- }
- } else {
- msmsdcc_request_start(host, mrq);
}
+ msmsdcc_request_start(host, mrq);
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -2614,6 +2620,179 @@
}
}
+/* Returns required bandwidth in Bytes per Sec */
+static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
+ struct mmc_ios *ios)
+{
+ unsigned int bw;
+
+ bw = host->clk_rate;
+ /*
+ * For DDR mode, SDCC controller clock will be at
+ * the double rate than the actual clock that goes to card.
+ */
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ bw /= 2;
+ else if (ios->bus_width == MMC_BUS_WIDTH_1)
+ bw /= 8;
+
+ return bw;
+}
+
+static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
+ unsigned int bw)
+{
+ unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
+ unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
+ int i;
+
+ if (host->msm_bus_vote.is_max_bw_needed && bw)
+ return host->msm_bus_vote.max_bw_vote;
+
+ for (i = 0; i < size; i++) {
+ if (bw <= table[i])
+ break;
+ }
+
+ if (i && (i == size))
+ i--;
+
+ return i;
+}
+
+static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
+{
+ int rc = 0;
+ struct msm_bus_scale_pdata *use_cases;
+
+ if (host->plat->msm_bus_voting_data &&
+ host->plat->msm_bus_voting_data->use_cases &&
+ host->plat->msm_bus_voting_data->bw_vecs &&
+ host->plat->msm_bus_voting_data->bw_vecs_size) {
+ use_cases = host->plat->msm_bus_voting_data->use_cases;
+ host->msm_bus_vote.client_handle =
+ msm_bus_scale_register_client(use_cases);
+ } else {
+ return 0;
+ }
+
+ if (!host->msm_bus_vote.client_handle) {
+ pr_err("%s: msm_bus_scale_register_client() failed\n",
+ mmc_hostname(host->mmc));
+ rc = -EFAULT;
+ } else {
+ /* cache the vote index for minimum and maximum bandwidth */
+ host->msm_bus_vote.min_bw_vote =
+ msmsdcc_msm_bus_get_vote_for_bw(host, 0);
+ host->msm_bus_vote.max_bw_vote =
+ msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
+ }
+
+ return rc;
+}
+
+static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
+{
+ if (host->msm_bus_vote.client_handle)
+ msm_bus_scale_unregister_client(
+ host->msm_bus_vote.client_handle);
+}
+
+/*
+ * This function must be called with host lock acquired.
+ * Caller of this function should also ensure that msm bus client
+ * handle is not null.
+ */
+static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
+ int vote,
+ unsigned long flags)
+{
+ int rc = 0;
+
+ if (vote != host->msm_bus_vote.curr_vote) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ rc = msm_bus_scale_client_update_request(
+ host->msm_bus_vote.client_handle, vote);
+ if (rc)
+ pr_err("%s: msm_bus_scale_client_update_request() failed."
+ " bus_client_handle=0x%x, vote=%d, err=%d\n",
+ mmc_hostname(host->mmc),
+ host->msm_bus_vote.client_handle, vote, rc);
+ spin_lock_irqsave(&host->lock, flags);
+ if (!rc)
+ host->msm_bus_vote.curr_vote = vote;
+ }
+
+ return rc;
+}
+
+/*
+ * Internal work. Work to set 0 bandwidth for msm bus.
+ */
+static void msmsdcc_msm_bus_work(struct work_struct *work)
+{
+ struct msmsdcc_host *host = container_of(work,
+ struct msmsdcc_host,
+ msm_bus_vote.vote_work.work);
+ unsigned long flags;
+
+ if (!host->msm_bus_vote.client_handle)
+ return;
+
+ spin_lock_irqsave(&host->lock, flags);
+ /* don't vote for 0 bandwidth if any request is in progress */
+ if (!host->curr.mrq)
+ msmsdcc_msm_bus_set_vote(host,
+ host->msm_bus_vote.min_bw_vote, flags);
+ else
+ pr_warning("%s: %s: SDCC transfer in progress. skipping"
+ " bus voting to 0 bandwidth\n",
+ mmc_hostname(host->mmc), __func__);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * This function cancels any scheduled delayed work
+ * and sets the bus vote based on ios argument.
+ * If "ios" argument is NULL, bandwidth required is 0 else
+ * calculate the bandwidth based on ios parameters.
+ */
+static void msmsdcc_msm_bus_cancel_work_and_set_vote(
+ struct msmsdcc_host *host,
+ struct mmc_ios *ios)
+{
+ unsigned long flags;
+ unsigned int bw;
+ int vote;
+
+ if (!host->msm_bus_vote.client_handle)
+ return;
+
+ bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
+
+ cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
+ spin_lock_irqsave(&host->lock, flags);
+ vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
+ msmsdcc_msm_bus_set_vote(host, vote, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/* This function queues a work which will set the bandwidth requiement to 0 */
+static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
+{
+ unsigned long flags;
+
+ if (!host->msm_bus_vote.client_handle)
+ return;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
+ queue_delayed_work(system_nrt_wq,
+ &host->msm_bus_vote.vote_work,
+ msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
static void
msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
{
@@ -2969,14 +3148,14 @@
msmsdcc_pm_qos_update_latency(host, 1);
if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ goto out;
if (host->sdcc_suspended && host->pending_resume &&
!pm_runtime_suspended(dev)) {
host->pending_resume = false;
pm_runtime_get_noresume(dev);
rc = msmsdcc_runtime_resume(dev);
- goto out;
+ goto skip_get_sync;
}
if (dev->power.runtime_status == RPM_SUSPENDING) {
@@ -2988,14 +3167,15 @@
rc = pm_runtime_get_sync(dev);
-out:
+skip_get_sync:
if (rc < 0) {
pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
__func__, rc);
msmsdcc_print_rpm_info(host);
return rc;
}
-
+out:
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3006,8 +3186,10 @@
msmsdcc_pm_qos_update_latency(host, 0);
- if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ if (mmc->card && mmc_card_sdio(mmc->card)) {
+ rc = 0;
+ goto out;
+ }
if (host->plat->disable_runtime_pm)
return -ENOTSUPP;
@@ -3027,7 +3209,9 @@
return rc;
}
- return 0;
+out:
+ msmsdcc_msm_bus_queue_work(host);
+ return rc;
}
#else
static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
@@ -3041,8 +3225,10 @@
msmsdcc_pm_qos_update_latency(host, 1);
- if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ if (mmc->card && mmc_card_sdio(mmc->card)) {
+ rc = 0;
+ goto out;
+ }
if (host->sdcc_suspended && host->pending_resume) {
host->pending_resume = false;
@@ -3067,7 +3253,7 @@
__func__, rc);
return rc;
}
-
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3079,7 +3265,7 @@
msmsdcc_pm_qos_update_latency(host, 0);
if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ goto out;
mutex_lock(&host->clk_mutex);
spin_lock_irqsave(&host->lock, flags);
@@ -3092,6 +3278,8 @@
spin_unlock_irqrestore(&host->lock, flags);
mutex_unlock(&host->clk_mutex);
+out:
+ msmsdcc_msm_bus_queue_work(host);
return 0;
}
#endif
@@ -4211,10 +4399,46 @@
static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
show_polling, set_polling);
+
+static ssize_t
+show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct msmsdcc_host *host = mmc_priv(mmc);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ host->msm_bus_vote.is_max_bw_needed);
+}
+
+static ssize_t
+set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ uint32_t value;
+ unsigned long flags;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ spin_lock_irqsave(&host->lock, flags);
+ host->msm_bus_vote.is_max_bw_needed = !!value;
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
+ show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
+
static struct attribute *dev_attrs[] = {
- &dev_attr_polling.attr,
+ &dev_attr_max_bus_bw.attr,
+ /* if polling is enabled, this will be filled with dev_attr_polling */
+ NULL,
NULL,
};
+
static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
@@ -4716,6 +4940,14 @@
pm_qos_add_request(&host->pm_qos_req_dma,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+ ret = msmsdcc_msm_bus_register(host);
+ if (ret)
+ goto pm_qos_remove;
+
+ if (host->msm_bus_vote.client_handle)
+ INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
+ msmsdcc_msm_bus_work);
+
ret = msmsdcc_vreg_init(host, true);
if (ret) {
pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
@@ -4965,11 +5197,12 @@
#if defined(CONFIG_DEBUG_FS)
msmsdcc_dbg_createhost(host);
#endif
- if (!plat->status_irq) {
- ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
- if (ret)
- goto platform_irq_free;
- }
+ if (!plat->status_irq)
+ dev_attrs[1] = &dev_attr_polling.attr;
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
+ if (ret)
+ goto platform_irq_free;
return 0;
platform_irq_free:
@@ -4999,6 +5232,8 @@
msmsdcc_vreg_init(host, false);
clk_disable:
clk_disable(host->clk);
+ msmsdcc_msm_bus_unregister(host);
+ pm_qos_remove:
if (host->cpu_dma_latency)
pm_qos_remove_request(&host->pm_qos_req_dma);
clk_put:
@@ -5076,6 +5311,11 @@
if (host->cpu_dma_latency)
pm_qos_remove_request(&host->pm_qos_req_dma);
+ if (host->msm_bus_vote.client_handle) {
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ msmsdcc_msm_bus_unregister(host);
+ }
+
msmsdcc_vreg_init(host, false);
if (host->is_dma_mode) {
@@ -5190,9 +5430,11 @@
int rc = 0;
unsigned long flags;
+ if (host->plat->is_sdio_al_client) {
+ rc = 0;
+ goto out;
+ }
- if (host->plat->is_sdio_al_client)
- return 0;
pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
if (mmc) {
host->sdcc_suspending = 1;
@@ -5247,6 +5489,9 @@
wake_unlock(&host->sdio_suspend_wlock);
}
pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
+out:
+ /* set bus bandwidth to 0 immediately */
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
return rc;
}
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index e6bd16c..78c12c1 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -78,6 +78,7 @@
#define MCI_DPSM_DIRECTION (1 << 1)
#define MCI_DPSM_MODE (1 << 2)
#define MCI_DPSM_DMAENABLE (1 << 3)
+#define MCI_DATA_PEND (1 << 17)
#define MCI_AUTO_PROG_DONE (1 << 19)
#define MCI_RX_DATA_PEND (1 << 20)
@@ -294,6 +295,7 @@
int got_dataend;
int wait_for_auto_prog_done;
int got_auto_prog_done;
+ bool use_wr_data_pend;
int user_pages;
};
@@ -319,6 +321,15 @@
struct tasklet_struct tlet;
};
+struct msmsdcc_msm_bus_vote {
+ uint32_t client_handle;
+ uint32_t curr_vote;
+ int min_bw_vote;
+ int max_bw_vote;
+ bool is_max_bw_needed;
+ struct delayed_work vote_work;
+};
+
struct msmsdcc_host {
struct resource *core_irqres;
struct resource *bam_irqres;
@@ -398,6 +409,7 @@
bool sdio_wakeupirq_disabled;
struct mutex clk_mutex;
bool pending_resume;
+ struct msmsdcc_msm_bus_vote msm_bus_vote;
};
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/video/msm/logo.c b/drivers/video/msm/logo.c
index c061e86..1b5d7c5 100644
--- a/drivers/video/msm/logo.c
+++ b/drivers/video/msm/logo.c
@@ -76,6 +76,12 @@
max = fb_width(info) * fb_height(info);
ptr = data;
+ if (info->node == 1 || info->node == 2) {
+ err = -EPERM;
+ pr_err("%s:%d no info->creen_base on fb%d!\n",
+ __func__, __LINE__, info->node);
+ goto err_logo_free_data;
+ }
bits = (unsigned short *)(info->screen_base);
while (count > 3) {
unsigned n = ptr[0];
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b4d8db0..ce8744b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1179,18 +1179,26 @@
if (!remainder_mode2)
remainder_mode2 = PAGE_SIZE;
- /* calculate smem_len based on max size of two supplied modes */
- fix->smem_len = MAX((msm_fb_line_length(mfd->index, panel_info->xres,
- bpp) *
- panel_info->yres + PAGE_SIZE -
- remainder) * mfd->fb_page,
- (msm_fb_line_length(mfd->index,
- panel_info->mode2_xres,
- bpp) *
- panel_info->mode2_yres + PAGE_SIZE -
- remainder_mode2) * mfd->fb_page);
-
-
+ /*
+ * calculate smem_len based on max size of two supplied modes.
+ * Only fb0 has mem. fb1 and fb2 don't have mem.
+ */
+ if (mfd->index == 0)
+ fix->smem_len = MAX((msm_fb_line_length(mfd->index,
+ panel_info->xres,
+ bpp) *
+ panel_info->yres + PAGE_SIZE -
+ remainder) * mfd->fb_page,
+ (msm_fb_line_length(mfd->index,
+ panel_info->mode2_xres,
+ bpp) *
+ panel_info->mode2_yres + PAGE_SIZE -
+ remainder_mode2) * mfd->fb_page);
+ else if (mfd->index == 1 || mfd->index == 2) {
+ pr_debug("%s:%d no memory is allocated for fb%d!\n",
+ __func__, __LINE__, mfd->index);
+ fix->smem_len = 0;
+ }
mfd->var_xres = panel_info->xres;
mfd->var_yres = panel_info->yres;
@@ -1294,10 +1302,11 @@
fbram_phys += fbram_offset;
fbram_size -= fbram_offset;
- if (fbram_size < fix->smem_len) {
- printk(KERN_ERR "error: no more framebuffer memory!\n");
- return -ENOMEM;
- }
+ if (mfd->index == 0)
+ if (fbram_size < fix->smem_len) {
+ pr_err("error: no more framebuffer memory!\n");
+ return -ENOMEM;
+ }
fbi->screen_base = fbram;
fbi->fix.smem_start = (unsigned long)fbram_phys;
@@ -1311,8 +1320,8 @@
fbi->fix.smem_start, mfd->map_buffer->iova[0],
mfd->map_buffer->iova[1]);
}
-
- memset(fbi->screen_base, 0x0, fix->smem_len);
+ if (mfd->index == 0)
+ memset(fbi->screen_base, 0x0, fix->smem_len);
mfd->op_enable = TRUE;
mfd->panel_power_on = FALSE;
@@ -1517,7 +1526,11 @@
}
if (!mfd->ref_cnt) {
- mdp_set_dma_pan_info(info, NULL, TRUE);
+ if ((info->node != 1) && (info->node != 2)) {
+ mdp_set_dma_pan_info(info, NULL, TRUE);
+ } else
+ pr_debug("%s:%d no mdp_set_dma_pan_info %d\n",
+ __func__, __LINE__, info->node);
if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
printk(KERN_ERR "msm_fb_open: can't turn on display!\n");
@@ -1565,6 +1578,15 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct msm_fb_panel_data *pdata;
+ /*
+ * If framebuffer is 1 or 2, io pen display is not allowed.
+ */
+ if (info->node == 1 || info->node == 2) {
+ pr_err("%s: no pan display for fb%d!",
+ __func__, info->node);
+ return -EPERM;
+ }
+
if (info->node != 0 || mfd->cont_splash_done) /* primary */
if ((!mfd->op_enable) || (!mfd->panel_power_on))
return -EPERM;
@@ -1585,6 +1607,7 @@
/* "UPDT" */
if (var->reserved[0] == 0x54445055) {
+
dirty.xoffset = var->reserved[1] & 0xffff;
dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
@@ -1738,9 +1761,12 @@
if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
return -EINVAL;
- if (info->fix.smem_len <
- (var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8)))
- return -EINVAL;
+ if ((info->node != 1) && (info->node != 2))
+ if (info->fix.smem_len <
+ (var->xres_virtual*
+ var->yres_virtual*
+ (var->bits_per_pixel/8)))
+ return -EINVAL;
if ((var->xres == 0) || (var->yres == 0))
return -EINVAL;
@@ -2593,7 +2619,11 @@
struct mdp_blit_req_list req_list_header;
int count, i, req_list_count;
-
+ if (info->node == 1 || info->node == 2) {
+ pr_err("%s: no pan display for fb%d.",
+ __func__, info->node);
+ return -EPERM;
+ }
/* Get the count size for the total BLIT request. */
if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
return -EFAULT;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 0d5ba9c..5019d31 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -502,7 +502,12 @@
}
rc = ddl_set_property(cctxt->ddl_handle, prop_hdr, prop_val);
- VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+ if (rc) {
+ /* Some properties aren't known to ddl that we can handle */
+ if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+ VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+ }
+
switch (prop_hdr->prop_id) {
case VCD_I_META_BUFFER_MODE:
{
@@ -537,16 +542,30 @@
break;
}
case VCD_I_INTRA_PERIOD:
- {
- struct vcd_property_i_period *iperiod =
- (struct vcd_property_i_period *)prop_val;
- cctxt->bframe = iperiod->b_frames;
- break;
- }
+ {
+ struct vcd_property_i_period *iperiod =
+ (struct vcd_property_i_period *)prop_val;
+ cctxt->bframe = iperiod->b_frames;
+ break;
+ }
case VCD_REQ_PERF_LEVEL:
rc = vcd_req_perf_level(cctxt,
- (struct vcd_property_perf_level *)prop_val);
+ (struct vcd_property_perf_level *)prop_val);
break;
+ case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+ {
+ struct vcd_property_vop_timing_constant_delta *delta =
+ prop_val;
+
+ if (delta->constant_delta > 0) {
+ cctxt->time_frame_delta = delta->constant_delta;
+ rc = VCD_S_SUCCESS;
+ } else {
+ VCD_MSG_ERROR("Frame delta must be positive");
+ rc = VCD_ERR_ILLEGAL_PARM;
+ }
+ break;
+ }
default:
{
break;
@@ -559,6 +578,7 @@
(struct vcd_clnt_ctxt *cctxt,
struct vcd_property_hdr *prop_hdr, void *prop_val)
{
+ int rc;
VCD_MSG_LOW("vcd_get_property_cmn in %d:", cctxt->clnt_state.state);
VCD_MSG_LOW("property Id = %d", prop_hdr->prop_id);
if (!prop_hdr->sz || !prop_hdr->prop_id) {
@@ -566,7 +586,24 @@
return VCD_ERR_ILLEGAL_PARM;
}
- return ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+ rc = ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+ if (rc) {
+ /* Some properties aren't known to ddl that we can handle */
+ if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+ VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+ }
+
+ switch (prop_hdr->prop_id) {
+ case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+ {
+ struct vcd_property_vop_timing_constant_delta *delta =
+ (struct vcd_property_vop_timing_constant_delta *)
+ prop_val;
+ delta->constant_delta = cctxt->time_frame_delta;
+ rc = VCD_S_SUCCESS;
+ }
+ }
+ return rc;
}
static u32 vcd_set_buffer_requirements_cmn
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index d228146..7ae4f45 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -191,6 +191,7 @@
u32 frm_p_units;
u32 reqd_perf_lvl;
u32 time_resoln;
+ u32 time_frame_delta;
struct vcd_buffer_pool in_buf_pool;
struct vcd_buffer_pool out_buf_pool;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 2df7144..6358a0e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -3052,13 +3052,15 @@
u32 frm_delta;
u64 temp, max = ~((u64)0);
- if (frame->time_stamp >= cctxt->status.prev_ts)
+ if (cctxt->time_frame_delta)
+ temp = cctxt->time_frame_delta;
+ else if (frame->time_stamp >= cctxt->status.prev_ts)
temp = frame->time_stamp - cctxt->status.prev_ts;
else
temp = (max - cctxt->status.prev_ts) +
frame->time_stamp;
- VCD_MSG_LOW("Curr_ts=%lld Prev_ts=%lld Diff=%llu",
+ VCD_MSG_LOW("Curr_ts=%lld Prev_ts=%lld Diff=%llu\n",
frame->time_stamp, cctxt->status.prev_ts, temp);
temp *= cctxt->time_resoln;
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 8dfb0fc..03951ce 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -4,4 +4,4 @@
header-y += vcap_fmt.h
header-y += msm_isp.h
header-y += msm_gemini.h
-header-y += msm_v4l2_overlay.h
+header-y += msm_gestures.h
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 32a1759..c93b696 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -66,7 +66,7 @@
u32 alloc_len;
u32 data_len;
u32 offset;
- s64 time_stamp;
+ s64 time_stamp; /* in usecs*/
u32 flags;
u32 frm_clnt_data;
struct vcd_property_dec_output_buffer dec_op_prop;
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index e776d41..cd00800 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -53,6 +53,7 @@
#define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
#define VCD_REQ_PERF_LEVEL (VCD_START_BASE + 0x26)
#define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
+#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
@@ -300,6 +301,10 @@
u32 vop_time_resolution;
};
+struct vcd_property_vop_timing_constant_delta {
+ u32 constant_delta; /*In usecs */
+};
+
struct vcd_property_short_header {
u32 short_header;
};
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 3f647dc..d4cf1d2 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1433,6 +1433,9 @@
#define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t *)
+#define MSM_CAM_IOCTL_SEND_EVENT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
+
struct msm_camera_v4l2_ioctl_t {
void __user *ioctl_ptr;
};
diff --git a/include/media/msm_gestures.h b/include/media/msm_gestures.h
new file mode 100644
index 0000000..c9af034
--- /dev/null
+++ b/include/media/msm_gestures.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+#ifndef __LINUX_MSM_GESTURES_H
+#define __LINUX_MSM_GESTURES_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <media/msm_camera.h>
+
+#define MSM_GES_IOCTL_CTRL_COMMAND \
+ _IOW('V', BASE_VIDIOC_PRIVATE + 20, struct v4l2_control)
+
+#define VIDIOC_MSM_GESTURE_EVT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 21, struct v4l2_event)
+
+#define MSM_GES_GET_EVT_PAYLOAD \
+ _IOW('V', BASE_VIDIOC_PRIVATE + 22, struct msm_ges_evt)
+
+#define VIDIOC_MSM_GESTURE_CAM_EVT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 23, int)
+
+#define MSM_GES_RESP_V4L2 MSM_CAM_RESP_MAX
+#define MSM_GES_RESP_MAX (MSM_GES_RESP_V4L2 + 1)
+
+#define MSM_SVR_RESP_MAX MSM_GES_RESP_MAX
+
+
+#define MSM_V4L2_GES_BASE 100
+#define MSM_V4L2_GES_OPEN (MSM_V4L2_GES_BASE + 0)
+#define MSM_V4L2_GES_CLOSE (MSM_V4L2_GES_BASE + 1)
+#define MSM_V4L2_GES_CAM_OPEN (MSM_V4L2_GES_BASE + 2)
+#define MSM_V4L2_GES_CAM_CLOSE (MSM_V4L2_GES_BASE + 3)
+
+#define MSM_GES_APP_EVT_MIN (V4L2_EVENT_PRIVATE_START + 0x14)
+#define MSM_GES_APP_NOTIFY_EVENT (MSM_GES_APP_EVT_MIN + 0)
+#define MSM_GES_APP_NOTIFY_ERROR_EVENT (MSM_GES_APP_EVT_MIN + 1)
+#define MSM_GES_APP_EVT_MAX (MSM_GES_APP_EVT_MIN + 2)
+
+#define MSM_GESTURE_CID_CTRL_CMD V4L2_CID_BRIGHTNESS
+
+#define MAX_GES_EVENTS 25
+
+struct msm_ges_ctrl_cmd {
+ int type;
+ void *value;
+ int len;
+ int fd;
+ uint32_t cookie;
+};
+
+struct msm_ges_evt {
+ void *evt_data;
+ int evt_len;
+};
+
+#endif /*__LINUX_MSM_GESTURES_H*/
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index f02a7ef..7060677 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -16,6 +16,7 @@
#include <linux/mfd/pm8xxx/pm8018.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -26,6 +27,7 @@
#include <mach/socinfo.h>
#include "msm-pcm-routing.h"
#include "../codecs/wcd9310.h"
+#include <mach/gpiomux.h>
/* 9615 machine driver */
@@ -56,8 +58,189 @@
#define TABLA_MBHC_DEF_BUTTONS 8
#define TABLA_MBHC_DEF_RLOADS 5
-static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(18);
-static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(19);
+/*
+ * Added for I2S
+ */
+#define GPIO_SPKR_I2S_MCLK 24
+#define GPIO_PRIM_I2S_SCK 20
+#define GPIO_PRIM_I2S_DOUT 23
+#define GPIO_PRIM_I2S_WS 21
+#define GPIO_PRIM_I2S_DIN 22
+#define GPIO_SEC_I2S_SCK 25
+#define GPIO_SEC_I2S_WS 26
+#define GPIO_SEC_I2S_DOUT 28
+#define GPIO_SEC_I2S_DIN 27
+
+static struct gpiomux_setting cdc_i2s_mclk = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_sclk = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_dout = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_ws = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_din = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm9615_audio_prim_i2s_codec_configs[] = {
+ {
+ .gpio = GPIO_SPKR_I2S_MCLK,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_SCK,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_sclk,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_DOUT,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_dout,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_WS,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_ws,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_DIN,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_din,
+ },
+ },
+};
+
+/* Physical address for LPA CSR
+ * LPA SIF mux registers. These are
+ * ioremap( ) for Virtual address.
+ */
+#define LPASS_CSR_BASE 0x28000000
+#define LPA_IF_BASE 0x28100000
+#define SIF_MUX_REG_BASE (LPASS_CSR_BASE + 0x00000000)
+#define LPA_IF_REG_BASE (LPA_IF_BASE + 0x00000000)
+#define LPASS_SIF_MUX_ADDR (SIF_MUX_REG_BASE + 0x00004000)
+#define LPAIF_SPARE_ADDR (LPA_IF_REG_BASE + 0x00000070)
+/* SIF & SPARE MUX Values */
+#define MSM_SIF_FUNC_PCM 0
+#define MSM_SIF_FUNC_I2S_MIC 1
+#define MSM_SIF_FUNC_I2S_SPKR 2
+#define MSM_LPAIF_SPARE_DISABLE 0x0
+#define MSM_LPAIF_SPARE_BOTH_ENABLE 0x3
+
+/* I2S INTF CTL */
+#define MSM_INTF_PRIM 0
+#define MSM_INTF_SECN 1
+#define MSM_INTF_BOTH 2
+
+/* I2S Dir CTL */
+#define MSM_DIR_RX 0
+#define MSM_DIR_TX 1
+#define MSM_DIR_BOTH 2
+#define MSM_DIR_MAX 3
+
+/* I2S HW Params */
+#define NO_OF_BITS_PER_SAMPLE 16
+#define I2S_MIC_SCLK_RATE 1536000
+static int msm9615_i2s_rx_ch = 1;
+static int msm9615_i2s_tx_ch = 1;
+static int msm9615_i2s_spk_control;
+/* SIF mux bit mask & shift */
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK 0x30000
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT 0x10
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK 0x3
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT 0x0
+
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK 0x3
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT 0x2
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK 0x3
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT 0x0
+
+static u32 spare_shadow;
+static u32 sif_shadow;
+
+
+struct msm_i2s_mux_ctl {
+ const u8 sifconfig;
+ const u8 spareconfig;
+};
+struct msm_clk {
+ struct clk *osr_clk;
+ struct clk *bit_clk;
+ int clk_enable;
+};
+struct msm_i2s_clk {
+ struct msm_clk rx_clk;
+ struct msm_clk tx_clk;
+};
+struct msm_i2s_ctl {
+ struct msm_i2s_clk prim_clk;
+ struct msm_i2s_clk sec_clk;
+ struct msm_i2s_mux_ctl mux_ctl[MSM_DIR_MAX];
+ u8 intf_status[MSM_INTF_BOTH][MSM_DIR_BOTH];
+ void *sif_virt_addr;
+ void *spare_virt_addr;
+};
+static struct msm_i2s_ctl msm9x15_i2s_ctl = {
+ {{NULL, NULL, 0}, {NULL, NULL, 0} }, /* prim_clk */
+ {{NULL, NULL, 0}, {NULL, NULL, 0} }, /* sec_clk */
+ /* mux_ctl */
+ {
+ /* Rx path only */
+ { MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_DISABLE },
+ /* Tx path only */
+ { MSM_SIF_FUNC_I2S_MIC, MSM_LPAIF_SPARE_DISABLE },
+ /* Rx + Tx path only */
+ { MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_BOTH_ENABLE },
+ },
+ /* intf_status */
+ {
+ /* Prim I2S */
+ {0, 0},
+ /* Sec I2S */
+ {0, 0}
+ },
+ /* sif_virt_addr */
+ NULL,
+ /* spare_virt_addr */
+ NULL,
+};
+
+enum msm9x15_set_i2s_clk {
+ MSM_I2S_CLK_SET_FALSE,
+ MSM_I2S_CLK_SET_TRUE,
+ MSM_I2S_CLK_SET_RATE0,
+};
+/*
+ * Added for I2S
+ */
+
+static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(3);
+static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
static int mdm9615_spk_control;
static int mdm9615_ext_bottom_spk_pamp;
static int mdm9615_ext_top_spk_pamp;
@@ -318,16 +501,15 @@
pr_debug("%s: clk_users = %d\n", __func__, clk_users);
if (clk_users != 1)
return 0;
+ if (IS_ERR(codec_clk)) {
- if (codec_clk) {
- clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
- clk_prepare_enable(codec_clk);
- tabla_mclk_enable(codec, 1, dapm);
- } else {
pr_err("%s: Error setting Tabla MCLK\n", __func__);
clk_users--;
return -EINVAL;
}
+ clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ tabla_mclk_enable(codec, 1, dapm);
} else {
pr_debug("%s: clk_users = %d\n", __func__, clk_users);
if (clk_users == 0)
@@ -651,6 +833,20 @@
return tabla_cal;
}
+static int msm9615_i2s_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm9615_i2s_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm9615_i2s_spk_control = ucontrol->value.integer.value[0];
+ mdm9615_ext_control(codec);
+ return 1;
+}
+
static int mdm9615_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -704,13 +900,567 @@
__func__);
goto end;
}
-
-
}
end:
return ret;
}
+static int msm9615_i2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
+ msm9615_i2s_rx_ch);
+ ucontrol->value.integer.value[0] = msm9615_i2s_rx_ch - 1;
+ return 0;
+}
+
+static int msm9615_i2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm9615_i2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
+ msm9615_i2s_rx_ch);
+ return 1;
+}
+
+static int msm9615_i2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
+ msm9615_i2s_tx_ch);
+ ucontrol->value.integer.value[0] = msm9615_i2s_tx_ch - 1;
+ return 0;
+}
+
+static int msm9615_i2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm9615_i2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
+ msm9615_i2s_tx_ch);
+ return 1;
+}
+
+static int msm9615_i2s_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm9615_spk_control = %d", __func__, mdm9615_spk_control);
+ ucontrol->value.integer.value[0] = msm9615_i2s_spk_control;
+ return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm9615_i2s_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], msm9615_i2s_get_spk,
+ msm9615_i2s_set_spk),
+ SOC_ENUM_EXT("PRI_RX Channels", mdm9615_enum[1],
+ msm9615_i2s_rx_ch_get, msm9615_i2s_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TX Channels", mdm9615_enum[2],
+ msm9615_i2s_tx_ch_get, msm9615_i2s_tx_ch_put),
+};
+
+static int msm9615_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ err = snd_soc_add_controls(codec, tabla_msm9615_i2s_controls,
+ ARRAY_SIZE(tabla_msm9615_i2s_controls));
+ if (err < 0) {
+ pr_err("returning loc 1 err = %d\n", err);
+ return err;
+ }
+
+ snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
+ ARRAY_SIZE(mdm9615_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, common_audio_map,
+ ARRAY_SIZE(common_audio_map));
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+ snd_soc_dapm_sync(dapm);
+
+ err = snd_soc_jack_new(codec, "Headset Jack",
+ (SND_JACK_HEADSET | SND_JACK_OC_HPHL|
+ SND_JACK_OC_HPHR), &hs_jack);
+ if (err) {
+ pr_err("failed to create new jack\n");
+ return err;
+ }
+ err = snd_soc_jack_new(codec, "Button Jack",
+ TABLA_JACK_BUTTON_MASK, &button_jack);
+ if (err) {
+ pr_err("failed to create new jack\n");
+ return err;
+ }
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ err = tabla_hs_detect(codec, &mbhc_cfg);
+ return err;
+}
+
+static int msm9615_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm9615_i2s_rx_ch;
+
+ return 0;
+}
+
+static int msm9615_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ rate->min = rate->max = 48000;
+
+ channels->min = channels->max = msm9615_i2s_tx_ch;
+
+ return 0;
+}
+
+static int mdm9615_i2s_free_gpios(u8 i2s_intf, u8 i2s_dir)
+{
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ if (i2s_intf == MSM_INTF_PRIM) {
+ if (i2s_dir == MSM_DIR_RX)
+ gpio_free(GPIO_PRIM_I2S_DOUT);
+ if (i2s_dir == MSM_DIR_TX)
+ gpio_free(GPIO_PRIM_I2S_DIN);
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ gpio_free(GPIO_PRIM_I2S_SCK);
+ gpio_free(GPIO_PRIM_I2S_WS);
+ }
+ } else if (i2s_intf == MSM_INTF_SECN) {
+ if (i2s_dir == MSM_DIR_RX)
+ gpio_free(GPIO_SEC_I2S_DOUT);
+ if (i2s_dir == MSM_DIR_TX)
+ gpio_free(GPIO_SEC_I2S_DIN);
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ gpio_free(GPIO_SEC_I2S_WS);
+ gpio_free(GPIO_SEC_I2S_SCK);
+ }
+ }
+ return 0;
+}
+
+int msm9615_i2s_intf_dir_sel(const char *cpu_dai_name,
+ u8 *i2s_intf, u8 *i2s_dir)
+{
+ int ret = 0;
+ if (i2s_intf == NULL || i2s_dir == NULL || cpu_dai_name == NULL) {
+ ret = 1;
+ goto err;
+ }
+ if (!strncmp(cpu_dai_name, "msm-dai-q6.0", 12)) {
+ *i2s_intf = MSM_INTF_PRIM;
+ *i2s_dir = MSM_DIR_RX;
+ } else if (!strncmp(cpu_dai_name, "msm-dai-q6.1", 12)) {
+ *i2s_intf = MSM_INTF_PRIM;
+ *i2s_dir = MSM_DIR_TX;
+ } else if (!strncmp(cpu_dai_name, "msm-dai-q6.4", 12)) {
+ *i2s_intf = MSM_INTF_SECN;
+ *i2s_dir = MSM_DIR_RX;
+ } else if (!strncmp(cpu_dai_name, "msm-dai-q6.5", 12)) {
+ *i2s_intf = MSM_INTF_SECN;
+ *i2s_dir = MSM_DIR_TX;
+ } else {
+ pr_err("Error in I2S cpu dai name\n");
+ ret = 1;
+ }
+err:
+ return ret;
+}
+
+int msm9615_enable_i2s_gpio(u8 i2s_intf, u8 i2s_dir)
+{
+ u8 ret = 0;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ if (i2s_intf == MSM_INTF_PRIM) {
+ if (i2s_dir == MSM_DIR_TX) {
+ ret = gpio_request(GPIO_PRIM_I2S_DIN, "I2S_PRIM_DIN");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_DIN);
+ goto err;
+ }
+ } else if (i2s_dir == MSM_DIR_RX) {
+ ret = gpio_request(GPIO_PRIM_I2S_DOUT,
+ "I2S_PRIM_DOUT");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_DOUT);
+ goto err;
+ }
+ } else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ ret = gpio_request(GPIO_PRIM_I2S_SCK, "I2S_PRIM_SCK");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_SCK);
+ goto err;
+ }
+ ret = gpio_request(GPIO_PRIM_I2S_WS, "I2S_PRIM_WS");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_WS);
+ goto err;
+ }
+ }
+ } else if (i2s_intf == MSM_INTF_SECN) {
+ if (i2s_dir == MSM_DIR_RX) {
+ ret = gpio_request(GPIO_SEC_I2S_DOUT, "I2S_SEC_DOUT");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_DOUT);
+ goto err;
+ }
+ } else if (i2s_dir == MSM_DIR_TX) {
+ ret = gpio_request(GPIO_SEC_I2S_DIN, "I2S_SEC_DIN");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_DIN);
+ goto err;
+ }
+ } else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ ret = gpio_request(GPIO_SEC_I2S_SCK, "I2S_SEC_SCK");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_SCK);
+ goto err;
+ }
+ ret = gpio_request(GPIO_SEC_I2S_WS, "I2S_SEC_WS");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_WS);
+ goto err;
+ }
+ }
+ }
+err:
+ return ret;
+}
+
+static int msm9615_set_i2s_osr_bit_clk(struct snd_soc_dai *cpu_dai,
+ u8 i2s_intf, u8 i2s_dir,
+ enum msm9x15_set_i2s_clk enable)
+{
+
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ struct msm_i2s_clk *pclk = &pintf->prim_clk;
+ struct msm_clk *clk_ctl = &pclk->rx_clk;
+ u8 ret = 0;
+ pr_debug("Dev name %s Intf =%d, Dir = %d, Enable=%d\n",
+ cpu_dai->name, i2s_intf, i2s_dir, enable);
+ if (i2s_intf == MSM_INTF_PRIM)
+ pclk = &pintf->prim_clk;
+ else if (i2s_intf == MSM_INTF_SECN)
+ pclk = &pintf->sec_clk;
+
+ if (i2s_dir == MSM_DIR_TX)
+ clk_ctl = &pclk->tx_clk;
+ else if (i2s_dir == MSM_DIR_RX)
+ clk_ctl = &pclk->rx_clk;
+
+ if (enable == MSM_I2S_CLK_SET_TRUE ||
+ enable == MSM_I2S_CLK_SET_RATE0) {
+ if (clk_ctl->clk_enable != 0) {
+ pr_info("%s: I2S Clk is already enabled"
+ "clk users %d\n", __func__,
+ clk_ctl->clk_enable);
+ ret = 0;
+ goto err;
+ }
+ clk_ctl->osr_clk = clk_get(cpu_dai->dev, "osr_clk");
+ if (IS_ERR(clk_ctl->osr_clk)) {
+ pr_err("%s: Fail to get OSR CLK\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = clk_prepare(clk_ctl->osr_clk);
+ if (ret != 0) {
+ pr_err("Unable to prepare i2s_spkr_osr_clk\n");
+ goto err;
+ }
+ clk_set_rate(clk_ctl->osr_clk, TABLA_EXT_CLK_RATE);
+ ret = clk_enable(clk_ctl->osr_clk);
+ if (ret != 0) {
+ pr_err("Fail to enable i2s_spkr_osr_clk\n");
+ clk_unprepare(clk_ctl->osr_clk);
+ goto err;
+ }
+ clk_ctl->bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+ if (IS_ERR(clk_ctl->bit_clk)) {
+ pr_err("Fail to get i2s_spkr_bit_clk\n");
+ clk_disable(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_put(clk_ctl->osr_clk);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = clk_prepare(clk_ctl->bit_clk);
+ if (ret != 0) {
+ clk_disable(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_put(clk_ctl->osr_clk);
+ pr_err("Fail to prepare i2s_spkr_osr_clk\n");
+ goto err;
+ }
+ if (enable == MSM_I2S_CLK_SET_RATE0)
+ clk_set_rate(clk_ctl->bit_clk, 0);
+ else
+ clk_set_rate(clk_ctl->bit_clk, 8);
+ ret = clk_enable(clk_ctl->bit_clk);
+ if (ret != 0) {
+ clk_disable(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_put(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->bit_clk);
+ pr_err("Unable to enable i2s_spkr_osr_clk\n");
+ goto err;
+ }
+ clk_ctl->clk_enable++;
+ } else if (enable == MSM_I2S_CLK_SET_FALSE &&
+ clk_ctl->clk_enable != 0) {
+ clk_disable(clk_ctl->osr_clk);
+ clk_disable(clk_ctl->bit_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->bit_clk);
+ clk_put(clk_ctl->bit_clk);
+ clk_put(clk_ctl->osr_clk);
+ clk_ctl->bit_clk = NULL;
+ clk_ctl->osr_clk = NULL;
+ clk_ctl->clk_enable--;
+ ret = 0;
+ }
+err:
+ return ret;
+}
+
+void msm9615_config_i2s_sif_mux(u8 value)
+{
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ sif_shadow = 0x00000;
+ sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
+ (value << LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT);
+ iowrite32(sif_shadow, pintf->sif_virt_addr);
+ /* Dont read SIF register. Device crashes. */
+ pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
+}
+
+void msm9615_config_i2s_spare_mux(u8 value, u8 i2s_intf)
+{
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ if (i2s_intf == MSM_INTF_PRIM) {
+ /* Configure Primary SIF */
+ spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK
+ ) | (value << LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT);
+ }
+ if (i2s_intf == MSM_INTF_SECN) {
+ /*Secondary interface configuration*/
+ spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK
+ ) | (value << LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT);
+ }
+ iowrite32(spare_shadow, pintf->spare_virt_addr);
+ /* Dont read SPARE register. Device crashes. */
+ pr_debug("%s( ): SPARE Reg =0x%x\n", __func__, spare_shadow);
+}
+
+static int msm9615_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int rate = params_rate(params);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ struct msm_i2s_clk *pclk = &pintf->prim_clk;
+ struct msm_clk *clk_ctl = &pclk->rx_clk;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int bit_clk_set = 0;
+ u8 i2s_intf, i2s_dir;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!msm9615_i2s_intf_dir_sel(cpu_dai->name,
+ &i2s_intf, &i2s_dir)) {
+ bit_clk_set = TABLA_EXT_CLK_RATE /
+ (rate * 2 * NO_OF_BITS_PER_SAMPLE);
+ if (bit_clk_set != 8) {
+ if (i2s_intf == MSM_INTF_PRIM)
+ pclk = &pintf->prim_clk;
+ else if (i2s_intf == MSM_INTF_SECN)
+ pclk = &pintf->sec_clk;
+ clk_ctl = &pclk->rx_clk;
+ pr_debug("%s( ): New rate = %d",
+ __func__, bit_clk_set);
+ clk_set_rate(clk_ctl->bit_clk, bit_clk_set);
+ }
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ bit_clk_set = I2S_MIC_SCLK_RATE / (rate * 2 *
+ NO_OF_BITS_PER_SAMPLE);
+ /* Not required to modify TX rate.
+ * Speaker clock are looped back
+ * to Mic.
+ */
+ }
+ return 1;
+}
+
+static int msm9615_i2s_startup(struct snd_pcm_substream *substream)
+{
+ u8 ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ u8 i2s_intf, i2s_dir;
+ if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+ pr_debug("%s( ): cpu name = %s intf =%d dir = %d\n",
+ __func__, cpu_dai->name, i2s_intf, i2s_dir);
+ pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+ pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+ msm9615_enable_i2s_gpio(i2s_intf, i2s_dir);
+ if (i2s_dir == MSM_DIR_TX) {
+ if (pintf->intf_status[i2s_intf][MSM_DIR_RX] > 0) {
+ /* This means that Rx is enabled before */
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+ i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_RATE0);
+ if (ret != 0) {
+ pr_err("%s: Fail enable I2S clock\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_i2s_sif_mux(
+ pintf->mux_ctl[MSM_DIR_BOTH].sifconfig);
+ msm9615_config_i2s_spare_mux(
+ pintf->mux_ctl[MSM_DIR_BOTH].spareconfig,
+ i2s_intf);
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt codec dai failed\n");
+ } else if (pintf->intf_status[i2s_intf][i2s_dir] == 0) {
+ /* This means that Rx is
+ * not enabled before.
+ * only Tx will be used.
+ */
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+ i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_TRUE);
+ if (ret != 0) {
+ pr_err("%s: Fail Tx I2S clock\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_i2s_sif_mux(
+ pintf->mux_ctl[MSM_DIR_TX].sifconfig);
+ msm9615_config_i2s_spare_mux(
+ pintf->mux_ctl[MSM_DIR_TX].spareconfig,
+ i2s_intf);
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt codec dai failed\n");
+ }
+ } else if (i2s_dir == MSM_DIR_RX) {
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0) {
+ pr_err("%s: Error shutdown Tx first\n",
+ __func__);
+ return -EINVAL;
+ } else if (pintf->intf_status[i2s_intf][i2s_dir]
+ == 0) {
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+ i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_TRUE);
+ if (ret != 0) {
+ pr_err("%s: Fail Rx I2S clock\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_i2s_sif_mux(
+ pintf->mux_ctl[MSM_DIR_RX].sifconfig);
+ msm9615_config_i2s_spare_mux(
+ pintf->mux_ctl[MSM_DIR_RX].spareconfig,
+ i2s_intf);
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt codec dai failed\n");
+ }
+ }
+ pintf->intf_status[i2s_intf][i2s_dir]++;
+ } else {
+ pr_err("%s: Err in i2s_intf_dir_sel\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("Exit %s() Enable status Rx =%d Tx = %d\n", __func__,
+ pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+ return ret;
+}
+
+static void msm9615_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ u8 i2s_intf = 0, i2s_dir = 0, ret = 0;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ pr_debug("%s( ): Enable status Rx =%d Tx = %d\n",
+ __func__, pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+ if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+ pr_debug("%s( ): intf =%d dir = %d\n", __func__,
+ i2s_intf, i2s_dir);
+ if (i2s_dir == MSM_DIR_RX)
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0)
+ pr_err("%s: Shutdown Tx First then by RX\n",
+ __func__);
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai, i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_FALSE);
+ if (ret != 0)
+ pr_err("%s: Cannot disable I2S clock\n",
+ __func__);
+ pintf->intf_status[i2s_intf][i2s_dir]--;
+ mdm9615_i2s_free_gpios(i2s_intf, i2s_dir);
+ }
+ pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+ pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+}
+
+static struct snd_soc_ops msm9615_i2s_be_ops = {
+ .startup = msm9615_i2s_startup,
+ .shutdown = msm9615_i2s_shutdown,
+ .hw_params = msm9615_i2s_hw_params,
+};
+
static int mdm9615_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -896,6 +1646,7 @@
return 0;
}
+
static int mdm9615_startup(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -1107,8 +1858,37 @@
};
-static struct snd_soc_dai_link mdm9615_dai_delta_tabla[] = {
- /* Backend DAI Links */
+static struct snd_soc_dai_link mdm9615_dai_i2s_tabla[] = {
+ /* Backend I2S DAI Links */
+ {
+ .name = LPASS_BE_PRI_I2S_RX,
+ .stream_name = "Primary I2S Playback",
+ .cpu_dai_name = "msm-dai-q6.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_i2s_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
+ .init = &msm9615_i2s_audrx_init,
+ .be_hw_params_fixup = msm9615_i2s_rx_be_hw_params_fixup,
+ .ops = &msm9615_i2s_be_ops,
+ },
+ {
+ .name = LPASS_BE_PRI_I2S_TX,
+ .stream_name = "Primary I2S Capture",
+ .cpu_dai_name = "msm-dai-q6.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_i2s_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
+ .be_hw_params_fixup = msm9615_i2s_tx_be_hw_params_fixup,
+ .ops = &msm9615_i2s_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link mdm9615_dai_slimbus_tabla[] = {
+ /* Backend SlimBus DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
.stream_name = "Slimbus Playback",
@@ -1136,14 +1916,17 @@
},
};
-static struct snd_soc_dai_link mdm9615_dai[
+static struct snd_soc_dai_link mdm9615_i2s_dai[
ARRAY_SIZE(mdm9615_dai_common) +
- ARRAY_SIZE(mdm9615_dai_delta_tabla)];
+ ARRAY_SIZE(mdm9615_dai_i2s_tabla)];
+
+static struct snd_soc_dai_link mdm9615_slimbus_dai[
+ ARRAY_SIZE(mdm9615_dai_common) +
+ ARRAY_SIZE(mdm9615_dai_slimbus_tabla)];
+
static struct snd_soc_card snd_soc_card_mdm9615 = {
.name = "mdm9615-tabla-snd-card",
- .dai_link = mdm9615_dai,
- .num_links = ARRAY_SIZE(mdm9615_dai),
};
static struct platform_device *mdm9615_snd_device;
@@ -1199,6 +1982,11 @@
}
}
+void __init install_codec_i2s_gpio(void)
+{
+ msm_gpiomux_install(msm9615_audio_prim_i2s_codec_configs,
+ ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
+}
static int __init mdm9615_audio_init(void)
{
int ret;
@@ -1220,11 +2008,28 @@
kfree(mbhc_cfg.calibration);
return -ENOMEM;
}
-
- memcpy(mdm9615_dai, mdm9615_dai_common, sizeof(mdm9615_dai_common));
- memcpy(mdm9615_dai + ARRAY_SIZE(mdm9615_dai_common),
- mdm9615_dai_delta_tabla, sizeof(mdm9615_dai_delta_tabla));
-
+ pr_err("%s: Interface Type = %d\n", __func__,
+ wcd9xxx_get_intf_type());
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ memcpy(mdm9615_slimbus_dai, mdm9615_dai_common,
+ sizeof(mdm9615_dai_common));
+ memcpy(mdm9615_slimbus_dai + ARRAY_SIZE(mdm9615_dai_common),
+ mdm9615_dai_slimbus_tabla,
+ sizeof(mdm9615_dai_slimbus_tabla));
+ snd_soc_card_mdm9615.dai_link = mdm9615_slimbus_dai;
+ snd_soc_card_mdm9615.num_links =
+ ARRAY_SIZE(mdm9615_slimbus_dai);
+ } else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+ install_codec_i2s_gpio();
+ memcpy(mdm9615_i2s_dai, mdm9615_dai_common,
+ sizeof(mdm9615_dai_common));
+ memcpy(mdm9615_i2s_dai + ARRAY_SIZE(mdm9615_dai_common),
+ mdm9615_dai_i2s_tabla,
+ sizeof(mdm9615_dai_i2s_tabla));
+ snd_soc_card_mdm9615.dai_link = mdm9615_i2s_dai;
+ snd_soc_card_mdm9615.num_links =
+ ARRAY_SIZE(mdm9615_i2s_dai);
+ }
platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
ret = platform_device_add(mdm9615_snd_device);
if (ret) {
@@ -1232,13 +2037,15 @@
kfree(mbhc_cfg.calibration);
return ret;
}
-
if (mdm9615_configure_headset_mic_gpios()) {
pr_err("%s Fail to configure headset mic gpios\n", __func__);
mdm9615_headset_gpios_configured = 0;
} else
mdm9615_headset_gpios_configured = 1;
+ msm9x15_i2s_ctl.sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
+ msm9x15_i2s_ctl.spare_virt_addr = ioremap(LPAIF_SPARE_ADDR, 4);
+
return ret;
}
@@ -1253,6 +2060,9 @@
mdm9615_free_headset_mic_gpios();
platform_device_unregister(mdm9615_snd_device);
kfree(mbhc_cfg.calibration);
+ iounmap(msm9x15_i2s_ctl.sif_virt_addr);
+ iounmap(msm9x15_i2s_ctl.spare_virt_addr);
+
}
module_exit(mdm9615_audio_exit);
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 3f7e399..b31ed65 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -38,6 +38,7 @@
#define SPK_AMP_POS 0x1
#define SPK_AMP_NEG 0x2
+#define SPKR_BOOST_GPIO 15
#define SITAR_EXT_CLK_RATE 12288000
#define SITAR_MBHC_DEF_BUTTONS 3
@@ -116,6 +117,8 @@
static void msm8960_ext_spk_power_amp_on(u32 spk)
{
+ int ret = 0;
+
if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
(msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
@@ -130,6 +133,23 @@
if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
(msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+ if (machine_is_msm8930_mtp()
+ || machine_is_msm8930_fluid()) {
+ pr_debug("%s: Configure Speaker Boost GPIO %u",
+ __func__, SPKR_BOOST_GPIO);
+ ret = gpio_request(SPKR_BOOST_GPIO,
+ "SPKR_BOOST_EN");
+ if (ret) {
+ pr_err("%s: Failed to configure speaker boost "
+ "gpio %u\n", __func__, SPKR_BOOST_GPIO);
+ return;
+ }
+
+ pr_debug("%s: Enable Speaker boost gpio %u\n",
+ __func__, SPKR_BOOST_GPIO);
+ gpio_direction_output(SPKR_BOOST_GPIO, 1);
+ }
+
pm8xxx_spk_enable(MSM8930_SPK_ON);
pr_debug("%s: slepping 4 ms after turning on external "
" Left Speaker Ampl\n", __func__);
@@ -149,6 +169,13 @@
if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
if (!msm8930_ext_spk_pamp)
return;
+ if (machine_is_msm8930_mtp()
+ || machine_is_msm8930_fluid()) {
+ pr_debug("%s: Free speaker boost gpio %u\n",
+ __func__, SPKR_BOOST_GPIO);
+ gpio_direction_output(SPKR_BOOST_GPIO, 0);
+ gpio_free(SPKR_BOOST_GPIO);
+ }
pm8xxx_spk_enable(MSM8930_SPK_OFF);
msm8930_ext_spk_pamp = 0;