Merge changes I26521f28,I89a932d4,I381df397 into msm-3.0
* changes:
msm: iommu: Switch to the new clock APIs
msm: iommu: Convert spinlocks to mutexes
msm: iommu: Use threaded IRQ handler for page faults
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 50db52c..cc94b69 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -17,7 +17,7 @@
ifeq "$(KERNEL_USE_OF)" "y"
KERNEL_ZIMG = $(KERNEL_OUT)/arch/arm/boot/zImage
DTB_FILE = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH).dtb
-DTS_FILE = $(KERNEL_OUT)/../../../../../../kernel/arch/arm/boot/dts/$(MSM_ARCH).dts
+DTS_FILE = $(TOP)/kernel/arch/arm/boot/dts/$(MSM_ARCH).dts
FULL_KERNEL = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH)-zImage
DTC = $(KERNEL_OUT)/scripts/dtc/dtc
diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index 93dd7a7..a9ba672 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -4,3 +4,5 @@
- info on SD and MMC device attributes
mmc-dev-parts.txt
- info on SD and MMC device partitions
+mmc-async-req.txt
+ - info on mmc asynchronous requests
diff --git a/Documentation/mmc/mmc-async-req.txt b/Documentation/mmc/mmc-async-req.txt
new file mode 100644
index 0000000..ae1907b
--- /dev/null
+++ b/Documentation/mmc/mmc-async-req.txt
@@ -0,0 +1,87 @@
+Rationale
+=========
+
+How significant is the cache maintenance overhead?
+It depends. Fast eMMC and multiple cache levels with speculative cache
+pre-fetch makes the cache overhead relatively significant. If the DMA
+preparations for the next request are done in parallel with the current
+transfer, the DMA preparation overhead would not affect the MMC performance.
+The intention of non-blocking (asynchronous) MMC requests is to minimize the
+time between when an MMC request ends and another MMC request begins.
+Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
+dma_unmap_sg are processing. Using non-blocking MMC requests makes it
+possible to prepare the caches for next job in parallel with an active
+MMC request.
+
+MMC block driver
+================
+
+The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
+The increase in throughput is proportional to the time it takes to
+prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
+a request and how fast the memory is. The faster the MMC/SD is the
+more significant the prepare request time becomes. Roughly the expected
+performance gain is 5% for large writes and 10% on large reads on a L2 cache
+platform. In power save mode, when clocks run on a lower frequency, the DMA
+preparation may cost even more. As long as these slower preparations are run
+in parallel with the transfer performance won't be affected.
+
+Details on measurements from IOZone and mmc_test
+================================================
+
+https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
+
+MMC core API extension
+======================
+
+There is one new public function mmc_start_req().
+It starts a new MMC command request for a host. The function isn't
+truly non-blocking. If there is an ongoing async request it waits
+for completion of that request and starts the new one and returns. It
+doesn't wait for the new request to complete. If there is no ongoing
+request it starts the new request and returns immediately.
+
+MMC host extensions
+===================
+
+There are two optional members in the mmc_host_ops -- pre_req() and
+post_req() -- that the host driver may implement in order to move work
+to before and after the actual mmc_host_ops.request() function is called.
+In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
+descriptor, and post_req() runs the dma_unmap_sg().
+
+Optimize for the first request
+==============================
+
+The first request in a series of requests can't be prepared in parallel
+with the previous transfer, since there is no previous request.
+The argument is_first_req in pre_req() indicates that there is no previous
+request. The host driver may optimize for this scenario to minimize
+the performance loss. A way to optimize for this is to split the current
+request in two chunks, prepare the first chunk and start the request,
+and finally prepare the second chunk and start the transfer.
+
+Pseudocode to handle is_first_req scenario with minimal prepare overhead:
+
+if (is_first_req && req->size > threshold)
+ /* start MMC transfer for the complete transfer size */
+ mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
+
+ /*
+ * Begin to prepare DMA while cmd is being processed by MMC.
+ * The first chunk of the request should take the same time
+ * to prepare as the "MMC process command time".
+ * If prepare time exceeds MMC cmd time
+ * the transfer is delayed, guesstimate max 4k as first chunk size.
+ */
+ prepare_1st_chunk_for_dma(req);
+ /* flush pending desc to the DMAC (dmaengine.h) */
+ dma_issue_pending(req->dma_desc);
+
+ prepare_2nd_chunk_for_dma(req);
+ /*
+ * The second issue_pending should be called before MMC runs out
+ * of the first chunk. If the MMC runs out of the first data chunk
+ * before this call, the transfer is delayed.
+ */
+ dma_issue_pending(req->dma_desc);
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 8a505cc..58aece2 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -168,3 +168,13 @@
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_SMD_TTY=y
+CONFIG_MSM_N_WAY_SMD=y
+CONFIG_MSM_N_WAY_SMSM=y
+CONFIG_MSM_SMD_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index dd8cb16..446423d 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -49,6 +49,7 @@
CONFIG_BT_MSM_PINTEST=y
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 199b91f..642d843 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -50,6 +50,7 @@
CONFIG_BT_MSM_PINTEST=y
CONFIG_MSM_RPC_VIBRATOR=y
CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f1b1fa5..152cb86 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -301,6 +301,7 @@
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
CONFIG_REGULATOR_PM8XXX=y
CONFIG_REGULATOR_GPIO=y
@@ -319,6 +320,7 @@
CONFIG_OV2720=y
CONFIG_S5K3L1YX=y
CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
@@ -336,8 +338,9 @@
CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
-CONFIG_FB_MSM_HDMI_MSM_PANEL=y
CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
+CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_SOUND=y
@@ -351,7 +354,6 @@
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_EHCI_HCD=y
@@ -374,6 +376,7 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_QCOM_DIAG_BRIDGE=y
CONFIG_USB_QCOM_MDM_BRIDGE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index e58b94b..a326de6 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -297,12 +297,11 @@
CONFIG_SENSORS_PM8XXX_ADC=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
-CONFIG_THERMAL_PM8XXX=y
-CONFIG_THERMAL_MONITOR=y
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
CONFIG_REGULATOR_PM8XXX=y
CONFIG_REGULATOR_GPIO=y
@@ -353,7 +352,6 @@
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
-CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_EHCI_HCD=y
@@ -376,6 +374,7 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_QCOM_DIAG_BRIDGE=y
CONFIG_USB_QCOM_MDM_BRIDGE=y
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 7ad3f65..5a21407 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -187,7 +187,7 @@
{ 0, 61440, ACPU_PLL_1, 1, 3, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 1, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -217,7 +217,7 @@
{ 0, 61440, ACPU_PLL_1, 1, 3, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 1, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -232,7 +232,7 @@
{ 0, 65536, ACPU_PLL_1, 1, 3, 8192, 3, 1, 49152 },
{ 1, 98304, ACPU_PLL_1, 1, 1, 12288, 3, 2, 49152 },
{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -247,7 +247,7 @@
{ 0, 61440, ACPU_PLL_1, 1, 3, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 1, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -261,7 +261,7 @@
{ 0, 61440, ACPU_PLL_1, 1, 11, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 5, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -291,7 +291,7 @@
{ 0, 61440, ACPU_PLL_1, 1, 11, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 5, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -300,13 +300,13 @@
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
-/* 7x27aa PLL4 @ 1008MHz with CDMA capable modem */
+/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_1008[] = {
{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
{ 0, 65536, ACPU_PLL_1, 1, 8, 8192, 3, 1, 49152 },
{ 1, 98304, ACPU_PLL_1, 1, 5, 12288, 3, 2, 49152 },
{ 1, 196608, ACPU_PLL_1, 1, 2, 24576, 3, 3, 98304 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -315,13 +315,13 @@
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
-/* 7x25a PLL2 @ 1200MHz with GSM capable modem */
+/* 7625a PLL2 @ 1200MHz with GSM capable modem */
static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_25a[] = {
{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
{ 0, 61440, ACPU_PLL_1, 1, 11, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 5, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
- { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 0a56dd2..5bef079 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -65,6 +65,9 @@
static uint32_t bam_dmux_write_cpy_bytes;
static uint32_t bam_dmux_tx_sps_failure_cnt;
static uint32_t bam_dmux_tx_stall_cnt;
+static atomic_t bam_dmux_ack_out_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_ack_in_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_a2_pwr_cntl_in_cnt = ATOMIC_INIT(0);
#define DBG(x...) do { \
if (msm_bam_dmux_debug_enable) \
@@ -102,6 +105,14 @@
bam_dmux_tx_stall_cnt++; \
} while (0)
+#define DBG_INC_ACK_OUT_CNT() \
+ atomic_inc(&bam_dmux_ack_out_cnt)
+
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+ atomic_inc(&bam_dmux_a2_pwr_cntl_in_cnt)
+
+#define DBG_INC_ACK_IN_CNT() \
+ atomic_inc(&bam_dmux_ack_in_cnt)
#else
#define DBG(x...) do { } while (0)
#define DBG_INC_READ_CNT(x...) do { } while (0)
@@ -109,6 +120,10 @@
#define DBG_INC_WRITE_CPY(x...) do { } while (0)
#define DBG_INC_TX_SPS_FAILURE_CNT() do { } while (0)
#define DBG_INC_TX_STALL_CNT() do { } while (0)
+#define DBG_INC_ACK_OUT_CNT() do { } while (0)
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+ do { } while (0)
+#define DBG_INC_ACK_IN_CNT() do { } while (0)
#endif
struct bam_ch_info {
@@ -208,7 +223,7 @@
static struct delayed_work ul_timeout_work;
static int ul_packet_written;
static atomic_t ul_ondemand_vote = ATOMIC_INIT(0);
-static struct clk *dfab_clk;
+static struct clk *dfab_clk, *xo_clk;
static DEFINE_RWLOCK(ul_wakeup_lock);
static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
static int bam_connection_is_active;
@@ -1200,14 +1215,20 @@
"skb copy bytes: %u\n"
"sps tx failures: %u\n"
"sps tx stalls: %u\n"
- "rx queue len: %d\n",
+ "rx queue len: %d\n"
+ "a2 ack out cnt: %d\n"
+ "a2 ack in cnt: %d\n"
+ "a2 pwr cntl in: %d\n",
bam_dmux_read_cnt,
bam_dmux_write_cnt,
bam_dmux_write_cpy_cnt,
bam_dmux_write_cpy_bytes,
bam_dmux_tx_sps_failure_cnt,
bam_dmux_tx_stall_cnt,
- bam_rx_pool_len
+ bam_rx_pool_len,
+ atomic_read(&bam_dmux_ack_out_cnt),
+ atomic_read(&bam_dmux_ack_in_cnt),
+ atomic_read(&bam_dmux_a2_pwr_cntl_in_cnt)
);
return i;
@@ -1512,21 +1533,11 @@
static int ssrestart_check(void)
{
- /*
- * if the restart level is RESET_SOC, SSR is not on
- * so the crashed modem will end up crashing the system
- * anyways, so use BUG() to report the error
- * else prepare for the restart event which should
- * happen soon
- */
- DMUX_LOG_KERR("%s: modem timeout\n", __func__);
- if (get_restart_level() <= RESET_SOC) {
- BUG();
- return 0;
- } else {
- in_global_reset = 1;
- return 1;
- }
+ DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
+ in_global_reset = 1;
+ if (get_restart_level() <= RESET_SOC)
+ DMUX_LOG_KERR("%s: ssrestart not enabled\n", __func__);
+ return 1;
}
static void ul_wakeup(void)
@@ -1690,6 +1701,9 @@
rc = clk_prepare_enable(dfab_clk);
if (rc)
DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
+ rc = clk_prepare_enable(xo_clk);
+ if (rc)
+ DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n", rc);
dfab_is_on = 1;
mutex_unlock(&dfab_status_lock);
}
@@ -1705,6 +1719,7 @@
return;
}
clk_disable_unprepare(dfab_clk);
+ clk_disable_unprepare(xo_clk);
dfab_is_on = 0;
mutex_unlock(&dfab_status_lock);
}
@@ -2043,11 +2058,13 @@
clear_bit & SMSM_A2_POWER_CONTROL_ACK,
~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
clear_bit = ~clear_bit;
+ DBG_INC_ACK_OUT_CNT();
}
static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
{
bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
+ DBG_INC_A2_POWER_CONTROL_IN_CNT();
bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
new_state);
@@ -2086,6 +2103,7 @@
static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
uint32_t new_state)
{
+ DBG_INC_ACK_IN_CNT();
bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
new_state);
complete_all(&ul_wakeup_ack_completion);
@@ -2099,6 +2117,11 @@
if (bam_mux_initialized)
return 0;
+ xo_clk = clk_get(&pdev->dev, "xo");
+ if (IS_ERR(xo_clk)) {
+ pr_err("%s: did not get xo clock\n", __func__);
+ return PTR_ERR(xo_clk);
+ }
dfab_clk = clk_get(&pdev->dev, "bus_clk");
if (IS_ERR(dfab_clk)) {
pr_err("%s: did not get dfab clock\n", __func__);
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 4287153..ea2a9f6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -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
@@ -12,19 +12,19 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
-static struct single_row_lut fcc_temp = {
+static struct single_row_lut palladium_1500_fcc_temp = {
.x = {-30, -20, -10, 0, 10, 25, 40, 60},
.y = {1103, 1179, 1284, 1330, 1420, 1511, 1541, 1571},
.cols = 8,
};
-static struct single_row_lut fcc_sf = {
+static struct single_row_lut palladium_1500_fcc_sf = {
.x = {100, 200, 300, 400, 500},
.y = {97, 93, 93, 90, 87},
.cols = 5,
};
-static struct pc_sf_lut pc_sf = {
+static struct pc_sf_lut palladium_1500_pc_sf = {
.rows = 10,
.cols = 5,
.cycles = {100, 200, 300, 400, 500},
@@ -43,7 +43,7 @@
},
};
-static struct pc_temp_ocv_lut pc_temp_ocv = {
+static struct pc_temp_ocv_lut palladium_1500_pc_temp_ocv = {
.rows = 29,
.cols = 8,
.temp = {-30, -20, -10, 0, 10, 25, 40, 60},
@@ -84,10 +84,81 @@
},
};
-struct pm8921_bms_battery_data palladium_1500_data = {
+struct pm8921_bms_battery_data palladium_1500_data = {
.fcc = 1500,
- .fcc_temp_lut = &fcc_temp,
- .fcc_sf_lut = &fcc_sf,
- .pc_temp_ocv_lut = &pc_temp_ocv,
- .pc_sf_lut = &pc_sf,
+ .fcc_temp_lut = &palladium_1500_fcc_temp,
+ .fcc_sf_lut = &palladium_1500_fcc_sf,
+ .pc_temp_ocv_lut = &palladium_1500_pc_temp_ocv,
+ .pc_sf_lut = &palladium_1500_pc_sf,
+};
+
+static struct single_row_lut desay_5200_fcc_temp = {
+ .x = {-20, 0, 25, 40},
+ .y = {5690, 5722, 5722, 5727},
+ .cols = 4
+};
+
+static struct single_row_lut desay_5200_fcc_sf = {
+ .x = {0},
+ .y = {100},
+ .cols = 1
+};
+
+static struct pc_temp_ocv_lut desay_5200_pc_temp_ocv = {
+ .rows = 29,
+ .cols = 4,
+ .temp = {-20, 0, 25, 40},
+ .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
+ 50, 45, 40, 35, 30, 25, 20, 15, 10, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0
+ },
+ .ocv = {
+ {4185, 4184, 4181, 4178},
+ {4103, 4117, 4120, 4119},
+ {4044, 4067, 4074, 4073},
+ {3987, 4019, 4031, 4030},
+ {3941, 3974, 3992, 3992},
+ {3902, 3936, 3958, 3957},
+ {3866, 3901, 3926, 3926},
+ {3835, 3870, 3891, 3896},
+ {3811, 3842, 3855, 3858},
+ {3792, 3818, 3827, 3827},
+ {3776, 3795, 3806, 3806},
+ {3762, 3778, 3789, 3790},
+ {3748, 3765, 3777, 3777},
+ {3735, 3752, 3767, 3765},
+ {3720, 3739, 3756, 3754},
+ {3704, 3726, 3743, 3736},
+ {3685, 3712, 3723, 3716},
+ {3664, 3697, 3695, 3689},
+ {3623, 3672, 3669, 3664},
+ {3611, 3666, 3666, 3661},
+ {3597, 3659, 3662, 3658},
+ {3579, 3648, 3657, 3653},
+ {3559, 3630, 3644, 3639},
+ {3532, 3600, 3612, 3606},
+ {3497, 3558, 3565, 3559},
+ {3450, 3500, 3504, 3498},
+ {3380, 3417, 3421, 3416},
+ {3265, 3287, 3296, 3293},
+ {3000, 3000, 3000, 3000}
+ },
+};
+
+static struct pc_sf_lut desay_5200_pc_sf = {
+ .rows = 1,
+ .cols = 1,
+ .cycles = {0},
+ .percent = {100},
+ .sf = {
+ {100}
+ },
+};
+
+struct pm8921_bms_battery_data desay_5200_data = {
+ .fcc = 5200,
+ .fcc_temp_lut = &desay_5200_fcc_temp,
+ .fcc_sf_lut = &desay_5200_fcc_sf,
+ .pc_temp_ocv_lut = &desay_5200_pc_temp_ocv,
+ .pc_sf_lut = &desay_5200_pc_sf,
};
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 109ed2c..486ebd3 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -332,17 +332,15 @@
};
static struct camera_vreg_t apq_8064_back_cam_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vio", REG_VS, 0, 0, 0},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+ {"cam_vio", REG_VS, 0, 0, 0},
+ {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
};
static struct camera_vreg_t apq_8064_front_cam_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vio", REG_VS, 0, 0, 0},
+ {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
};
@@ -403,13 +401,23 @@
.i2c_mux_mode = MODE_L,
};
+static struct i2c_board_info imx074_actuator_i2c_info = {
+ I2C_BOARD_INFO("imx074_act", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+ .board_info = &imx074_actuator_i2c_info,
+ .bus_id = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
static struct msm_camera_i2c_conf apq8064_front_cam_i2c_conf = {
.use_i2c_mux = 1,
.mux_dev = &msm8960_device_i2c_mux_gsbi4,
.i2c_mux_mode = MODE_L,
};
-#ifdef CONFIG_IMX074
static struct msm_camera_sensor_flash_data flash_imx074 = {
.flash_type = MSM_CAMERA_FLASH_NONE,
};
@@ -429,10 +437,37 @@
.sensor_platform_info = &sensor_board_info_imx074,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .actuator_info = &imx074_actuator_info
};
-#endif
-#ifdef CONFIG_OV2720
+static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
+ {"cam_vio", REG_VS, 0, 0, 0},
+ {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+ {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+ {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+ .mount_angle = 90,
+ .cam_vreg = apq_8064_mt9m114_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_mt9m114_vreg),
+ .gpio_conf = &apq8064_front_cam_gpio_conf,
+ .i2c_conf = &apq8064_front_cam_i2c_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+ .sensor_name = "mt9m114",
+ .pdata = &msm_camera_csi_device_data[1],
+ .flash_data = &flash_mt9m114,
+ .sensor_platform_info = &sensor_board_info_mt9m114,
+ .csi_if = 1,
+ .camera_type = FRONT_CAMERA_2D,
+};
+
static struct msm_camera_sensor_flash_data flash_ov2720 = {
.flash_type = MSM_CAMERA_FLASH_NONE,
};
@@ -453,8 +488,6 @@
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
};
-#endif
-
void __init apq8064_init_cam(void)
{
@@ -473,18 +506,18 @@
#ifdef CONFIG_I2C
static struct i2c_board_info apq8064_camera_i2c_boardinfo[] = {
-#ifdef CONFIG_IMX074
{
I2C_BOARD_INFO("imx074", 0x1A),
.platform_data = &msm_camera_sensor_imx074_data,
},
-#endif
-#ifdef CONFIG_OV2720
+ {
+ I2C_BOARD_INFO("mt9m114", 0x48),
+ .platform_data = &msm_camera_sensor_mt9m114_data,
+ },
{
I2C_BOARD_INFO("ov2720", 0x6C),
.platform_data = &msm_camera_sensor_ov2720_data,
},
-#endif
};
struct msm_camera_board_info apq8064_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 9b6c253..206bebd 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -499,7 +499,29 @@
.settings = {
[GPIOMUX_SUSPENDED] = &ap2mdm_pon_reset_n_cfg,
}
- }
+ },
+};
+
+static struct gpiomux_setting gpio_rotate_key_act_config = {
+ .pull = GPIOMUX_PULL_UP,
+ .drv = GPIOMUX_DRV_8MA,
+ .func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct gpiomux_setting gpio_rotate_key_sus_config = {
+ .pull = GPIOMUX_PULL_NONE,
+ .drv = GPIOMUX_DRV_2MA,
+ .func = GPIOMUX_FUNC_GPIO,
+};
+
+struct msm_gpiomux_config apq8064_rotate_key_config[] = {
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_rotate_key_sus_config,
+ [GPIOMUX_ACTIVE] = &gpio_rotate_key_act_config,
+ }
+ },
};
static struct msm_gpiomux_config apq8064_mxt_configs[] __initdata = {
@@ -599,11 +621,16 @@
ARRAY_SIZE(cyts_gpio_configs));
#ifdef CONFIG_USB_EHCI_MSM_HSIC
- msm_gpiomux_install(apq8064_hsic_configs,
- ARRAY_SIZE(apq8064_hsic_configs));
+ if (machine_is_apq8064_mtp())
+ msm_gpiomux_install(apq8064_hsic_configs,
+ ARRAY_SIZE(apq8064_hsic_configs));
#endif
if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
msm_gpiomux_install(apq8064_mxt_configs,
ARRAY_SIZE(apq8064_mxt_configs));
+
+ if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+ msm_gpiomux_install(apq8064_rotate_key_config,
+ ARRAY_SIZE(apq8064_rotate_key_config));
}
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 0357c40..213215e 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -122,6 +122,31 @@
},
};
+static const char *kgsl_3d0_iommu0_ctx_names[] = {
+ "gfx3d_user",
+ /* priv_ctx goes here */
+};
+
+static const char *kgsl_3d0_iommu1_ctx_names[] = {
+ "gfx3d1_user",
+ /* priv_ctx goes here */
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+ {
+ .iommu_ctx_names = kgsl_3d0_iommu0_ctx_names,
+ .iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctx_names),
+ .physstart = 0x07C00000,
+ .physend = 0x07C00000 + SZ_1M - 1,
+ },
+ {
+ .iommu_ctx_names = kgsl_3d0_iommu1_ctx_names,
+ .iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu1_ctx_names),
+ .physstart = 0x07D00000,
+ .physend = 0x07D00000 + SZ_1M - 1,
+ },
+};
+
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
.pwrlevel = {
{
@@ -154,8 +179,8 @@
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp3d_bus_scale_pdata,
#endif
- .iommu_user_ctx_name = "gfx3d_user",
- .iommu_priv_ctx_name = NULL,
+ .iommu_data = kgsl_3d0_iommu_data,
+ .iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
};
struct platform_device device_kgsl_3d0 = {
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 4c386e9..bd5f703 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -120,6 +120,19 @@
PM8921_GPIO_OUTPUT_FUNC(44, 0, PM_GPIO_FUNC_2),
PM8921_GPIO_OUTPUT(33, 0, HIGH),
PM8921_GPIO_OUTPUT(20, 0, HIGH),
+ PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_1P5),
+ PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_1P5),
+ /* TABLA CODEC RESET */
+ PM8921_GPIO_OUTPUT(34, 1, MED),
+};
+
+static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
+ PM8921_GPIO_INPUT(3, PM_GPIO_PULL_UP_1P5),
+ PM8921_GPIO_INPUT(4, PM_GPIO_PULL_UP_1P5),
+};
+
+static struct pm8xxx_gpio_init pm8921_cdp_kp_gpios[] __initdata = {
+ PM8921_GPIO_INPUT(37, PM_GPIO_PULL_UP_1P5),
};
/* Initial PM8XXX MPP configurations */
@@ -143,6 +156,28 @@
}
}
+ if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+ for (i = 0; i < ARRAY_SIZE(pm8921_cdp_kp_gpios); i++) {
+ rc = pm8xxx_gpio_config(pm8921_cdp_kp_gpios[i].gpio,
+ &pm8921_cdp_kp_gpios[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+
+ if (machine_is_apq8064_mtp())
+ for (i = 0; i < ARRAY_SIZE(pm8921_mtp_kp_gpios); i++) {
+ rc = pm8xxx_gpio_config(pm8921_mtp_kp_gpios[i].gpio,
+ &pm8921_mtp_kp_gpios[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(pm8xxx_mpps); i++) {
rc = pm8xxx_mpp_config(pm8xxx_mpps[i].mpp,
&pm8xxx_mpps[i].config);
@@ -321,6 +356,7 @@
static struct pm8921_bms_platform_data
apq8064_pm8921_bms_pdata __devinitdata = {
+ .battery_type = BATT_UNKNOWN,
.r_sense = 10,
.i_test = 2500,
.v_failure = 3000,
@@ -393,5 +429,9 @@
if (machine_is_apq8064_rumi3()) {
apq8064_pm8921_irq_pdata.devirq = 0;
apq8064_pm8821_irq_pdata.devirq = 0;
+ } else if (machine_is_apq8064_mtp()) {
+ apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+ } else if (machine_is_apq8064_liquid()) {
+ apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
}
}
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index caee8ba..247b230 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -27,8 +27,9 @@
};
VREG_CONSUMERS(L2) = {
REGULATOR_SUPPLY("8921_l2", NULL),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-001a"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-006c"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.1"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"),
REGULATOR_SUPPLY("lvds_pll_vdda", "lvds.0"),
REGULATOR_SUPPLY("dsi1_pll_vdda", "mipi_dsi.1"),
};
@@ -41,8 +42,6 @@
VREG_CONSUMERS(L4) = {
REGULATOR_SUPPLY("8921_l4", NULL),
REGULATOR_SUPPLY("HSUSB_1p8", "msm_otg"),
- REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.0"),
- REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.1"),
REGULATOR_SUPPLY("iris_vddxo", "wcnss_wlan.0"),
};
VREG_CONSUMERS(L5) = {
@@ -60,6 +59,7 @@
VREG_CONSUMERS(L8) = {
REGULATOR_SUPPLY("8921_l8", NULL),
REGULATOR_SUPPLY("cam_vana", "4-001a"),
+ REGULATOR_SUPPLY("cam_vana", "4-0048"),
REGULATOR_SUPPLY("cam_vana", "4-006c"),
};
VREG_CONSUMERS(L9) = {
@@ -76,6 +76,7 @@
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("cam_vdig", "4-001a"),
+ REGULATOR_SUPPLY("cam_vdig", "4-0048"),
REGULATOR_SUPPLY("cam_vdig", "4-006c"),
REGULATOR_SUPPLY("8921_l12", NULL),
};
@@ -88,6 +89,7 @@
VREG_CONSUMERS(L16) = {
REGULATOR_SUPPLY("8921_l16", NULL),
REGULATOR_SUPPLY("cam_vaf", "4-001a"),
+ REGULATOR_SUPPLY("cam_vaf", "4-0048"),
REGULATOR_SUPPLY("cam_vaf", "4-006c"),
};
VREG_CONSUMERS(L17) = {
@@ -103,7 +105,8 @@
REGULATOR_SUPPLY("8921_l23", NULL),
REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
-
+ REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.0"),
+ REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.1"),
};
VREG_CONSUMERS(L24) = {
REGULATOR_SUPPLY("8921_l24", NULL),
@@ -187,6 +190,7 @@
VREG_CONSUMERS(LVS5) = {
REGULATOR_SUPPLY("8921_lvs5", NULL),
REGULATOR_SUPPLY("cam_vio", "4-001a"),
+ REGULATOR_SUPPLY("cam_vio", "4-0048"),
REGULATOR_SUPPLY("cam_vio", "4-006c"),
};
VREG_CONSUMERS(LVS6) = {
@@ -218,6 +222,7 @@
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
+ REGULATOR_SUPPLY("vbus", "msm_ehci_host.0"),
};
VREG_CONSUMERS(EXT_MPP8) = {
REGULATOR_SUPPLY("ext_mpp8", NULL),
@@ -507,7 +512,7 @@
RPM_LDO(L6, 0, 1, 0, 2950000, 2950000, NULL, 0, 0),
RPM_LDO(L7, 0, 1, 0, 1850000, 2950000, NULL, 0, 0),
RPM_LDO(L8, 0, 1, 0, 2800000, 2800000, NULL, 0, 0),
- RPM_LDO(L9, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
+ RPM_LDO(L9, 0, 1, 0, 3000000, 3000000, NULL, 0, 0),
RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL, 0, 0),
RPM_LDO(L11, 0, 1, 0, 3000000, 3000000, NULL, 0, 0),
RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 9069039..41be3e7 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -51,7 +51,7 @@
.name = "sdc_vdd",
.high_vol_level = 2950000,
.low_vol_level = 2950000,
- .hpm_uA = 600000, /* 600mA */
+ .hpm_uA = 800000, /* 800mA */
}
};
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 12cee78..3848262 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -16,8 +16,8 @@
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/msm_ssbi.h>
#include <linux/spi/spi.h>
@@ -28,6 +28,7 @@
#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/cyttsp.h>
#include <linux/i2c/isa1200.h>
+#include <linux/gpio_keys.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -474,6 +475,19 @@
.power_budget = 750,
};
+static struct msm_usb_host_platform_data msm_ehci_host_pdata = {
+ .power_budget = 500,
+};
+
+static void __init apq8064_ehci_host_init(void)
+{
+ if (machine_is_apq8064_liquid()) {
+ apq8064_device_ehci_host3.dev.platform_data =
+ &msm_ehci_host_pdata;
+ platform_device_register(&apq8064_device_ehci_host3);
+ }
+}
+
#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
@@ -485,14 +499,14 @@
* does not need to be as high as 2.85V. It is choosen for
* microphone sensitivity purpose.
*/
-static struct tabla_pdata apq8064_tabla_platform_data = {
+static struct wcd9xxx_pdata apq8064_tabla_platform_data = {
.slimbus_slave_device = {
.name = "tabla-slave",
.e_addr = {0, 0, 0x10, 0, 0x17, 2},
},
.irq = MSM_GPIO_TO_INT(42),
.irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
+ .num_irqs = NR_WCD9XXX_IRQS,
.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
.micbias = {
.ldoh_v = TABLA_LDOH_2P85_V,
@@ -503,7 +517,45 @@
.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 slim_device apq8064_slim_tabla = {
@@ -514,14 +566,14 @@
},
};
-static struct tabla_pdata apq8064_tabla20_platform_data = {
+static struct wcd9xxx_pdata apq8064_tabla20_platform_data = {
.slimbus_slave_device = {
.name = "tabla-slave",
.e_addr = {0, 0, 0x60, 0, 0x17, 2},
},
.irq = MSM_GPIO_TO_INT(42),
.irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
+ .num_irqs = NR_WCD9XXX_IRQS,
.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
.micbias = {
.ldoh_v = TABLA_LDOH_2P85_V,
@@ -532,7 +584,45 @@
.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 slim_device apq8064_slim_tabla20 = {
@@ -628,7 +718,7 @@
/* T6 Object */
0, 0, 0, 0, 0, 0,
/* T38 Object */
- 14, 0, 0, 24, 1, 12, 0, 0, 0, 0,
+ 14, 1, 0, 22, 2, 12, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -636,14 +726,14 @@
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
/* T7 Object */
- 100, 16, 50,
+ 100, 10, 50,
/* T8 Object */
- 25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
+ 25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
/* T9 Object */
131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
- 85, 5, 10, 10, 10, 10, 135, 55, 70, 40,
- 10, 5, 0, 0, 0,
+ 85, 5, 0, 5, 9, 5, 12, 35, 70, 40,
+ 20, 5, 0, 0, 0,
/* T18 Object */
0, 0,
/* T24 Object */
@@ -661,14 +751,14 @@
0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
16,
/* T46 Object */
- 64, 0, 20, 20, 0, 0, 0, 0, 0,
+ 68, 0, 16, 16, 0, 0, 0, 0, 0,
/* T47 Object */
0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
/* T48 Object */
31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
- 48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
+ 32, 40, 0, 10, 10, 0, 0, 100, 10, 90,
+ 0, 0, 0, 0, 0, 0, 0, 10, 1, 10,
+ 52, 10, 12, 0, 33, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
/* T56 Object */
@@ -676,8 +766,8 @@
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 99, 33, 0, 149, 24, 193, 255, 255, 255,
- 255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
};
#define MXT_TS_GPIO_IRQ 6
@@ -1476,7 +1566,6 @@
&apq8064_device_otg,
&apq8064_device_gadget_peripheral,
&apq8064_device_hsusb_host,
- &apq8064_device_hsic_host,
&android_usb_device,
&msm_device_wcnss_wlan,
#ifdef CONFIG_ANDROID_PMEM
@@ -1648,6 +1737,116 @@
}
#endif
+#define GPIO_KEY_HOME PM8921_GPIO_PM_TO_SYS(27)
+#define GPIO_KEY_VOLUME_UP PM8921_GPIO_PM_TO_SYS(35)
+#define GPIO_KEY_VOLUME_DOWN PM8921_GPIO_PM_TO_SYS(38)
+#define GPIO_KEY_CAM_FOCUS PM8921_GPIO_PM_TO_SYS(3)
+#define GPIO_KEY_CAM_SNAP PM8921_GPIO_PM_TO_SYS(4)
+#define GPIO_KEY_ROTATION 46
+
+static struct gpio_keys_button cdp_keys[] = {
+ {
+ .code = KEY_HOME,
+ .gpio = GPIO_KEY_HOME,
+ .desc = "home_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = GPIO_KEY_VOLUME_UP,
+ .desc = "volume_up_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = GPIO_KEY_VOLUME_DOWN,
+ .desc = "volume_down_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = SW_ROTATE_LOCK,
+ .gpio = GPIO_KEY_ROTATION,
+ .desc = "rotate_key",
+ .active_low = 1,
+ .type = EV_SW,
+ .debounce_interval = 15,
+ },
+};
+
+static struct gpio_keys_platform_data cdp_keys_data = {
+ .buttons = cdp_keys,
+ .nbuttons = ARRAY_SIZE(cdp_keys),
+};
+
+static struct platform_device cdp_kp_pdev = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &cdp_keys_data,
+ },
+};
+
+static struct gpio_keys_button mtp_keys[] = {
+ {
+ .code = KEY_CAMERA_FOCUS,
+ .gpio = GPIO_KEY_CAM_FOCUS,
+ .desc = "cam_focus_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = GPIO_KEY_VOLUME_UP,
+ .desc = "volume_up_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = GPIO_KEY_VOLUME_DOWN,
+ .desc = "volume_down_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_CAMERA_SNAPSHOT,
+ .gpio = GPIO_KEY_CAM_SNAP,
+ .desc = "cam_snap_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .debounce_interval = 15,
+ },
+};
+
+static struct gpio_keys_platform_data mtp_keys_data = {
+ .buttons = mtp_keys,
+ .nbuttons = ARRAY_SIZE(mtp_keys),
+};
+
+static struct platform_device mtp_kp_pdev = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &mtp_keys_data,
+ },
+};
+
+
static void __init apq8064_clock_init(void)
{
if (machine_is_apq8064_rumi3())
@@ -1751,9 +1950,13 @@
if (machine_is_apq8064_liquid())
msm_otg_pdata.mhl_enable = true;
apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
- apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+ apq8064_ehci_host_init();
apq8064_init_buses();
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ if (machine_is_apq8064_mtp()) {
+ apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+ device_initialize(&apq8064_device_hsic_host.dev);
+ }
apq8064_pm8xxx_gpio_mpp_init();
apq8064_init_mmc();
@@ -1810,9 +2013,14 @@
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
apq8064_init_fb();
apq8064_init_gpu();
- platform_add_devices(msm_footswitch_devices,
- msm_num_footswitch_devices);
+ platform_add_devices(apq8064_fs_devices, apq8064_num_fs_devices);
apq8064_init_cam();
+
+ if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+ platform_device_register(&cdp_kp_pdev);
+
+ if (machine_is_apq8064_mtp())
+ platform_device_register(&mtp_kp_pdev);
}
MACHINE_START(APQ8064_SIM, "QCT APQ8064 SIMULATOR")
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 47a381a..1d743d8 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -349,7 +349,6 @@
};
static struct camera_vreg_t msm_8930_back_cam_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -357,7 +356,6 @@
};
static struct camera_vreg_t msm_8930_front_cam_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
@@ -446,7 +444,6 @@
};
static struct camera_vreg_t msm_8930_mt9m114_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -461,16 +458,16 @@
.mount_angle = 90,
.cam_vreg = msm_8930_mt9m114_vreg,
.num_vreg = ARRAY_SIZE(msm_8930_mt9m114_vreg),
- .gpio_conf = &msm_8930_back_cam_gpio_conf,
+ .gpio_conf = &msm_8930_front_cam_gpio_conf,
};
static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
.sensor_name = "mt9m114",
- .pdata = &msm_camera_csi_device_data[0],
+ .pdata = &msm_camera_csi_device_data[1],
.flash_data = &flash_mt9m114,
.sensor_platform_info = &sensor_board_info_mt9m114,
.csi_if = 1,
- .camera_type = BACK_CAMERA_2D,
+ .camera_type = FRONT_CAMERA_2D,
};
static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -494,7 +491,6 @@
};
static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index e6b342f..a840877 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -623,9 +623,15 @@
if (on == prev_on)
return 0;
- if (!reg_ext_5v)
- reg_ext_5v = regulator_get(&hdmi_msm_device.dev,
- "hdmi_mvs");
+ if (!reg_ext_5v) {
+ reg_ext_5v = regulator_get(&hdmi_msm_device.dev, "hdmi_mvs");
+ if (IS_ERR(reg_ext_5v)) {
+ pr_err("'%s' regulator not found, rc=%ld\n",
+ "hdmi_mvs", IS_ERR(reg_ext_5v));
+ reg_ext_5v = NULL;
+ return -ENODEV;
+ }
+ }
if (on) {
rc = regulator_enable(reg_ext_5v);
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 3f9f976..e19cde0 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -273,6 +273,7 @@
};
static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+ .battery_type = BATT_UNKNOWN,
.r_sense = 10,
.i_test = 2500,
.v_failure = 3000,
@@ -310,4 +311,8 @@
&msm8930_ssbi_pm8038_pdata;
pm8038_platform_data.num_regulators
= msm8930_pm8038_regulator_pdata_len;
+ if (machine_is_apq8064_mtp())
+ pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+ else if (machine_is_apq8064_liquid())
+ pm8921_bms_pdata.battery_type = BATT_DESAY;
}
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 2f9fdcd..3a6a30d 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -30,10 +30,9 @@
REGULATOR_SUPPLY("8038_l2", NULL),
REGULATOR_SUPPLY("iris_vdddig", "wcnss_wlan.0"),
REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-001a"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-006c"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-0048"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-0020"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.1"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"),
};
VREG_CONSUMERS(L3) = {
REGULATOR_SUPPLY("8038_l3", NULL),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a094ba5..278c08c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -42,6 +42,10 @@
#include <linux/gpio_keys.h>
#include <linux/memory.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/setup.h>
@@ -68,12 +72,6 @@
#include <mach/msm_xo.h>
#include <mach/restart.h>
-#ifdef CONFIG_WCD9310_CODEC
-#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
-#endif
-
#include <linux/ion.h>
#include <mach/ion.h>
#include <mach/mdm2.h>
@@ -518,9 +516,9 @@
msm8930_allocate_fb_region();
}
-#ifdef CONFIG_WCD9310_CODEC
+#ifdef CONFIG_WCD9304_CODEC
-#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+#define SITAR_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
* 4 micbiases are used to power various analog and digital
@@ -531,82 +529,77 @@
* does not need to be as high as 2.85V. It is choosen for
* microphone sensitivity purpose.
*/
-static struct tabla_pdata tabla_platform_data = {
- .slimbus_slave_device = {
- .name = "tabla-slave",
- .e_addr = {0, 0, 0x10, 0, 0x17, 2},
+static struct wcd9xxx_pdata sitar_platform_data = {
+ .slimbus_slave_device = {
+ .name = "sitar-slave",
+ .e_addr = {0, 0, 0x00, 0, 0x17, 2},
},
.irq = MSM_GPIO_TO_INT(62),
- .irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
-
-/*TODO: Replace this with right PM8038 gpio */
-#ifndef MSM8930_PHASE_2
- .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
-#endif
+ .irq_base = SITAR_INTERRUPT_BASE,
+ .num_irqs = NR_WCD9XXX_IRQS,
+ .reset_gpio = 42,
.micbias = {
- .ldoh_v = TABLA_LDOH_2P85_V,
+ .ldoh_v = SITAR_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,
- }
-};
-
-static struct slim_device msm_slim_tabla = {
- .name = "tabla-slim",
- .e_addr = {0, 1, 0x10, 0, 0x17, 2},
- .dev = {
- .platform_data = &tabla_platform_data,
+ .bias1_cfilt_sel = SITAR_CFILT1_SEL,
+ .bias2_cfilt_sel = SITAR_CFILT2_SEL,
+ },
+ .regulator = {
+ {
+ .name = "CDC_VDD_CP",
+ .min_uV = 2200000,
+ .max_uV = 2200000,
+ .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 = 1200000,
+ .max_uV = 1200000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_A_1P2V",
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+ },
},
};
-static struct tabla_pdata tabla20_platform_data = {
- .slimbus_slave_device = {
- .name = "tabla-slave",
- .e_addr = {0, 0, 0x60, 0, 0x17, 2},
- },
- .irq = MSM_GPIO_TO_INT(62),
- .irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
-
-/*TODO: Replace this with right PM8038 gpio */
-#ifndef MSM8930_PHASE_2
- .reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
-#endif
- .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,
- }
-};
-
-static struct slim_device msm_slim_tabla20 = {
- .name = "tabla2x-slim",
- .e_addr = {0, 1, 0x60, 0, 0x17, 2},
+static struct slim_device msm_slim_sitar = {
+ .name = "sitar-slim",
+ .e_addr = {0, 1, 0x00, 0, 0x17, 2},
.dev = {
- .platform_data = &tabla20_platform_data,
+ .platform_data = &sitar_platform_data,
},
};
#endif
+
static struct slim_boardinfo msm_slim_devices[] = {
-#ifdef CONFIG_WCD9310_CODEC
+#ifdef CONFIG_WCD9304_CODEC
{
.bus_num = 1,
- .slim_slave = &msm_slim_tabla,
- },
- {
- .bus_num = 1,
- .slim_slave = &msm_slim_tabla20,
+ .slim_slave = &msm_slim_sitar,
},
#endif
/* add more slimbus slaves as needed */
@@ -971,12 +964,54 @@
#ifdef CONFIG_USB_MSM_OTG_72K
static struct msm_otg_platform_data msm_otg_pdata;
#else
+#ifdef CONFIG_MSM_BUS_SCALING
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors usb_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors usb_max_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 60000000, /* At least 480Mbps on bus. */
+ .ib = 960000000, /* MAX bursts rate */
+ },
+};
+
+static struct msm_bus_paths usb_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(usb_init_vectors),
+ usb_init_vectors,
+ },
+ {
+ ARRAY_SIZE(usb_max_vectors),
+ usb_max_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata usb_bus_scale_pdata = {
+ usb_bus_scale_usecases,
+ ARRAY_SIZE(usb_bus_scale_usecases),
+ .name = "usb",
+};
+#endif
+
static struct msm_otg_platform_data msm_otg_pdata = {
.mode = USB_OTG,
.otg_control = OTG_PMIC_CONTROL,
.phy_type = SNPS_28NM_INTEGRATED_PHY,
.pmic_id_irq = PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE),
.power_budget = 750,
+#ifdef CONFIG_MSM_BUS_SCALING
+ .bus_scale_table = &usb_bus_scale_pdata,
+#endif
};
#endif
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 87cb105..3a697bf 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -420,7 +420,6 @@
};
static struct camera_vreg_t msm_8960_back_cam_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vio", REG_VS, 0, 0, 0},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -428,7 +427,6 @@
};
static struct camera_vreg_t msm_8960_front_cam_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vio", REG_VS, 0, 0, 0},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
@@ -517,7 +515,6 @@
};
static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vio", REG_VS, 0, 0, 0},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -532,16 +529,16 @@
.mount_angle = 90,
.cam_vreg = msm_8960_mt9m114_vreg,
.num_vreg = ARRAY_SIZE(msm_8960_mt9m114_vreg),
- .gpio_conf = &msm_8960_back_cam_gpio_conf,
+ .gpio_conf = &msm_8960_front_cam_gpio_conf,
};
static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
.sensor_name = "mt9m114",
- .pdata = &msm_camera_csi_device_data[0],
+ .pdata = &msm_camera_csi_device_data[1],
.flash_data = &flash_mt9m114,
.sensor_platform_info = &sensor_board_info_mt9m114,
.csi_if = 1,
- .camera_type = BACK_CAMERA_2D,
+ .camera_type = FRONT_CAMERA_2D,
};
static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -565,7 +562,6 @@
};
static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
- {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vio", REG_VS, 0, 0, 0},
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 9a98058..37a988a 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -879,9 +879,16 @@
if (on == prev_on)
return 0;
- if (!reg_8921_hdmi_mvs)
+ if (!reg_8921_hdmi_mvs) {
reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
- "hdmi_mvs");
+ "hdmi_mvs");
+ if (IS_ERR(reg_8921_hdmi_mvs)) {
+ pr_err("'%s' regulator not found, rc=%ld\n",
+ "hdmi_mvs", IS_ERR(reg_8921_hdmi_mvs));
+ reg_8921_hdmi_mvs = NULL;
+ return -ENODEV;
+ }
+ }
if (on) {
rc = regulator_enable(reg_8921_hdmi_mvs);
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 744709c..e3646ed 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -88,6 +88,12 @@
PM_GPIO_STRENGTH_HIGH, \
PM_GPIO_FUNC_NORMAL, 0, 0)
+#define PM8XXX_GPIO_OUTPUT_STRENGTH(_gpio, _val, _out_strength) \
+ PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+ _out_strength, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
/* Initial PM8921 GPIO configurations */
static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
PM8XXX_GPIO_OUTPUT_VIN(6, 1, PM_GPIO_VIN_VPH), /* MHL power EN_N */
@@ -104,6 +110,8 @@
PM8XXX_GPIO_INPUT(26, PM_GPIO_PULL_UP_30), /* SD_CARD_DET_N */
PM8XXX_GPIO_OUTPUT(43, PM_GPIO_PULL_UP_30), /* DISP_RESET_N */
PM8XXX_GPIO_OUTPUT(42, 0), /* USB 5V reg enable */
+ /* TABLA CODEC RESET */
+ PM8XXX_GPIO_OUTPUT_STRENGTH(34, 1, PM_GPIO_STRENGTH_MED)
};
/* Initial PM8921 MPP configurations */
@@ -431,6 +439,7 @@
};
static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+ .battery_type = BATT_UNKNOWN,
.r_sense = 10,
.i_test = 2500,
.v_failure = 3000,
@@ -593,5 +602,8 @@
if (machine_is_msm8960_liquid()) {
pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
pm8921_platform_data.leds_pdata = &pm8xxx_leds_pdata_liquid;
+ pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
+ } else if (machine_is_msm8960_mtp()) {
+ pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
}
}
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 0f05af5..d98ae56 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -30,10 +30,9 @@
VREG_CONSUMERS(L2) = {
REGULATOR_SUPPLY("8921_l2", NULL),
REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-001a"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-006c"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-0048"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "4-0020"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.1"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"),
};
VREG_CONSUMERS(L3) = {
REGULATOR_SUPPLY("8921_l3", NULL),
@@ -527,7 +526,7 @@
RPM_LDO(L6, 0, 1, 0, 2950000, 2950000, NULL, 0, 0),
RPM_LDO(L7, 1, 1, 0, 1850000, 2950000, NULL, 10000, 10000),
RPM_LDO(L8, 0, 1, 0, 2800000, 3000000, NULL, 0, 0),
- RPM_LDO(L9, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
+ RPM_LDO(L9, 0, 1, 0, 3000000, 3000000, NULL, 0, 0),
RPM_LDO(L10, 0, 1, 0, 3000000, 3000000, NULL, 0, 0),
RPM_LDO(L11, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index b99ce8a..7fd6820 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -70,9 +70,8 @@
#include <mach/restart.h>
#ifdef CONFIG_WCD9310_CODEC
-#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
#endif
#include <linux/ion.h>
@@ -664,14 +663,14 @@
* does not need to be as high as 2.85V. It is choosen for
* microphone sensitivity purpose.
*/
-static struct tabla_pdata tabla_platform_data = {
+static struct wcd9xxx_pdata tabla_platform_data = {
.slimbus_slave_device = {
.name = "tabla-slave",
.e_addr = {0, 0, 0x10, 0, 0x17, 2},
},
.irq = MSM_GPIO_TO_INT(62),
.irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
+ .num_irqs = NR_WCD9XXX_IRQS,
.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
.micbias = {
.ldoh_v = TABLA_LDOH_2P85_V,
@@ -682,7 +681,45 @@
.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 slim_device msm_slim_tabla = {
@@ -693,14 +730,14 @@
},
};
-static struct tabla_pdata tabla20_platform_data = {
+static struct wcd9xxx_pdata tabla20_platform_data = {
.slimbus_slave_device = {
.name = "tabla-slave",
.e_addr = {0, 0, 0x60, 0, 0x17, 2},
},
.irq = MSM_GPIO_TO_INT(62),
.irq_base = TABLA_INTERRUPT_BASE,
- .num_irqs = NR_TABLA_IRQS,
+ .num_irqs = NR_WCD9XXX_IRQS,
.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
.micbias = {
.ldoh_v = TABLA_LDOH_2P85_V,
@@ -711,7 +748,45 @@
.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 slim_device msm_slim_tabla20 = {
@@ -1716,6 +1791,63 @@
255,
};
+/* configuration data for mxt1386e on 3D SKU using V2.1 firmware */
+static const u8 mxt1386e_config_data_3d[] = {
+ /* T6 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T38 Object */
+ 13, 1, 0, 23, 2, 12, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T7 Object */
+ 100, 10, 50,
+ /* T8 Object */
+ 25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
+ /* T9 Object */
+ 131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+ 0, 5, 5, 0, 10, 30, 10, 10, 175, 4,
+ 127, 7, 26, 21, 17, 19, 143, 35, 207, 40,
+ 20, 5, 54, 49, 0,
+ /* T18 Object */
+ 0, 0,
+ /* T24 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T25 Object */
+ 0, 0, 72, 113, 168, 97,
+ /* T27 Object */
+ 0, 0, 0, 0, 0, 0, 0,
+ /* T40 Object */
+ 0, 0, 0, 0, 0,
+ /* T42 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T43 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ /* T46 Object */
+ 68, 0, 16, 16, 0, 0, 0, 0, 0,
+ /* T47 Object */
+ 0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
+ /* T48 Object */
+ 31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+ 32, 50, 0, 10, 10, 0, 0, 100, 10, 90,
+ 0, 0, 0, 0, 0, 0, 0, 10, 1, 30,
+ 52, 10, 5, 0, 33, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T56 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
#define MXT_TS_GPIO_IRQ 11
#define MXT_TS_LDO_EN_GPIO 50
#define MXT_TS_RESET_GPIO 52
@@ -1744,7 +1876,7 @@
gpio_free(MXT_TS_LDO_EN_GPIO);
}
-static struct mxt_config_info mxt_config_array[] = {
+static struct mxt_config_info mxt_config_array_2d[] = {
{
.config = mxt1386_config_data,
.config_length = ARRAY_SIZE(mxt1386_config_data),
@@ -1771,9 +1903,9 @@
},
};
-static struct mxt_platform_data mxt_platform_data = {
- .config_array = mxt_config_array,
- .config_array_size = ARRAY_SIZE(mxt_config_array),
+static struct mxt_platform_data mxt_platform_data_2d = {
+ .config_array = mxt_config_array_2d,
+ .config_array_size = ARRAY_SIZE(mxt_config_array_2d),
.x_size = 1365,
.y_size = 767,
.irqflags = IRQF_TRIGGER_FALLING,
@@ -1782,10 +1914,31 @@
.irq_gpio = MXT_TS_GPIO_IRQ,
};
+static struct mxt_config_info mxt_config_array_3d[] = {
+ {
+ .config = mxt1386e_config_data_3d,
+ .config_length = ARRAY_SIZE(mxt1386e_config_data_3d),
+ .family_id = 0xA0,
+ .variant_id = 0x7,
+ .version = 0x21,
+ .build = 0xAA,
+ },
+};
+
+static struct mxt_platform_data mxt_platform_data_3d = {
+ .config_array = mxt_config_array_3d,
+ .config_array_size = ARRAY_SIZE(mxt_config_array_3d),
+ .x_size = 1919,
+ .y_size = 1199,
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .i2c_pull_up = true,
+ .reset_gpio = MXT_TS_RESET_GPIO,
+ .irq_gpio = MXT_TS_GPIO_IRQ,
+};
+
static struct i2c_board_info mxt_device_info[] __initdata = {
{
I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
- .platform_data = &mxt_platform_data,
.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
},
};
@@ -2188,62 +2341,62 @@
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
- 100, 8000, 100000, 1,
+ 100, 650, 801, 200,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
- 2000, 6000, 60100000, 3000,
+ 2000, 200, 576000, 2000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
false,
- 4200, 5000, 60350000, 3500,
+ 8500, 51, 1122000, 8500,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
false,
- 6300, 4500, 65350000, 4800,
+ 9000, 51, 1130300, 9000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
false,
- 7000, 3500, 66600000, 5150,
+ 10000, 51, 1130300, 10000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
false,
- 11700, 2500, 67850000, 5500,
+ 12000, 14, 2205900, 12000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
false,
- 13800, 2000, 71850000, 6800,
+ 18000, 12, 2364250, 18000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
false,
- 29700, 500, 75850000, 8800,
+ 23500, 10, 2667000, 23500,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
false,
- 29700, 0, 76350000, 9800,
+ 29700, 5, 2867000, 30000,
},
};
@@ -2463,6 +2616,15 @@
else
pr_err("unmatched machine ID in register_i2c_devices\n");
+ if (machine_is_msm8960_liquid()) {
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_platform_version()) == 3)
+ mxt_device_info[0].platform_data =
+ &mxt_platform_data_3d;
+ else
+ mxt_device_info[0].platform_data =
+ &mxt_platform_data_2d;
+ }
+
/* Run the array and install devices as appropriate */
for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
if (msm8960_i2c_devices[i].machs & mach_mask)
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 4b6716e..dc26d72 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -380,6 +380,7 @@
CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
CLK_DUMMY("alt_core_clk", NULL, "msm_otg", OFF),
CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
+ CLK_DUMMY("xo", NULL, "msm_otg", OFF),
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
CLK_DUMMY("mem_clk", NULL, NULL, 0),
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 77af5e2..06fbb7b 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -603,7 +603,7 @@
.pmic_gpio_enable = 1,
.sensor_pwd = GPIO_SKU3_CAM_5MP_SHDN_N,
.vcm_pwd = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
- .vcm_enable = 0,
+ .vcm_enable = 1,
.pdata = &msm_camera_device_data_rear,
.flash_data = &flash_ov5647,
.sensor_platform_info = &ov5647_sensor_7627a_info,
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index a10d81a..88a519d 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -26,6 +26,7 @@
|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
+#define MAX_SDCC_CONTROLLER 4
static unsigned long vreg_sts, gpio_sts;
struct sdcc_gpio {
@@ -152,7 +153,7 @@
gpio_sdc1_hw_det = 42;
}
-static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
+static struct regulator *sdcc_vreg_data[MAX_SDCC_CONTROLLER];
static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
{
int rc = 0;
@@ -377,14 +378,14 @@
#endif
/* SDIO WLAN slot */
#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
- if (mmc_regulator_init(2, "mmc", 2850000))
+ if (mmc_regulator_init(2, "smps3", 1800000))
return;
msm_add_sdcc(2, &sdc2_plat_data);
#endif
/* Not Used */
#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
- if (mmc_regulator_init(4, "mmc", 2850000))
+ if (mmc_regulator_init(4, "smps3", 1800000))
return;
msm_add_sdcc(4, &sdc4_plat_data);
#endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d5d8edc..34ae4c8 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -92,6 +92,7 @@
#define PMEM_KERNEL_EBI1_SIZE 0x1C000
#endif
+#define ADSP_RPC_PROG 0x3000000a
static struct resource smc91x_resources[] = {
[0] = {
@@ -1731,6 +1732,25 @@
}
}
+static void msm_adsp_add_pdev(void)
+{
+ int rc = 0;
+ struct rpc_board_dev *rpc_adsp_pdev;
+
+ rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+ if (rpc_adsp_pdev == NULL) {
+ pr_err("%s: Memory Allocation failure\n", __func__);
+ return;
+ }
+ rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+ rpc_adsp_pdev->pdev = msm_adsp_device;
+ rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+ if (rc < 0) {
+ pr_err("%s: return val: %d\n", __func__, rc);
+ kfree(rpc_adsp_pdev);
+ }
+}
+
static void __init msm7x2x_init(void)
{
@@ -1797,6 +1817,7 @@
#ifdef CONFIG_MSM_CAMERA
config_camera_off_gpios(); /* might not be necessary */
#endif
+ msm_adsp_add_pdev();
msm_device_i2c_init();
i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index a6b29dc..d059b8d 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -60,6 +60,7 @@
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x5B000
+#define ADSP_RPC_PROG 0x3000000a
#if defined(CONFIG_GPIO_SX150X)
enum {
@@ -1115,6 +1116,44 @@
}
};
+static void msm_adsp_add_pdev(void)
+{
+ int rc = 0;
+ struct rpc_board_dev *rpc_adsp_pdev;
+
+ rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+ if (rpc_adsp_pdev == NULL) {
+ pr_err("%s: Memory Allocation failure\n", __func__);
+ return;
+ }
+ rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+ rpc_adsp_pdev->pdev = msm_adsp_device;
+ rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+ if (rc < 0) {
+ pr_err("%s: return val: %d\n", __func__, rc);
+ kfree(rpc_adsp_pdev);
+ }
+}
+
+static void msm_adsp_8625_add_pdev(void)
+{
+ int rc = 0;
+ struct rpc_board_dev *rpc_adsp_pdev;
+
+ rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+ if (rpc_adsp_pdev == NULL) {
+ pr_err("%s: Memory Allocation failure\n", __func__);
+ return;
+ }
+ rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+ rpc_adsp_pdev->pdev = msm8625_device_adsp;
+ rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+ if (rc < 0) {
+ pr_err("%s: return val: %d\n", __func__, rc);
+ kfree(rpc_adsp_pdev);
+ }
+}
+
static void __init msm7627a_rumi3_init(void)
{
msm7x27a_init_ebi2();
@@ -1125,6 +1164,7 @@
static void __init msm8625_rumi3_init(void)
{
msm7x2x_misc_init();
+ msm_adsp_8625_add_pdev();
msm_device_i2c_init();
platform_add_devices(msm8625_rumi3_devices,
ARRAY_SIZE(msm8625_rumi3_devices));
@@ -1159,6 +1199,7 @@
msm7x27a_init_regulators();
/* Common functions for SURF/FFA/RUMI3 */
+ msm_adsp_add_pdev();
msm_device_i2c_init();
msm7x27a_init_ebi2();
msm7x27a_cfg_uart2dm_serial();
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 47a4605..260c880 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -118,6 +118,7 @@
#define OPTNAV_I2C_SLAVE_ADDR (0xB0 >> 1)
#define OPTNAV_IRQ 20
#define OPTNAV_CHIP_SELECT 19
+#define PMIC_GPIO_SDC4_PWR_EN_N 24 /* PMIC GPIO Number 25 */
/* Macros assume PMIC GPIOs start at 0 */
#define PM8058_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio + NR_GPIO_IRQS)
@@ -167,6 +168,19 @@
},
};
+ struct pm8xxx_gpio_init_info sdc4_pwr_en = {
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+ {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM8058_GPIO_VIN_L5,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ .out_strength = PM_GPIO_STRENGTH_LOW,
+ .output_value = 0,
+ },
+ };
+
struct pm8xxx_gpio_init_info haptics_enable = {
PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
{
@@ -294,6 +308,23 @@
}
gpio_set_value_cansleep(sdc4_en.gpio, 0);
}
+ /* FFA -> gpio_25 controls vdd of sdcc4 */
+ else {
+ /* SCD4 gpio_25 */
+ rc = pm8xxx_gpio_config(sdc4_pwr_en.gpio, &sdc4_pwr_en.config);
+ if (rc) {
+ pr_err("%s PMIC_GPIO_SDC4_PWR_EN_N config failed: %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = gpio_request(sdc4_pwr_en.gpio, "sdc4_pwr_en");
+ if (rc) {
+ pr_err("PMIC_GPIO_SDC4_PWR_EN_N gpio_req failed: %d\n",
+ rc);
+ return rc;
+ }
+ }
return 0;
}
@@ -5478,9 +5509,24 @@
if (test_bit(dev_id, &vreg_sts) == enable)
return rc;
- if (!enable || enabled_once[dev_id - 1])
- return 0;
+ if (dev_id == 4) {
+ if (enable) {
+ pr_debug("Enable Vdd dev_%d\n", dev_id);
+ gpio_set_value_cansleep(
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+ 0);
+ set_bit(dev_id, &vreg_sts);
+ } else {
+ pr_debug("Disable Vdd dev_%d\n", dev_id);
+ gpio_set_value_cansleep(
+ PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+ 1);
+ clear_bit(dev_id, &vreg_sts);
+ }
+ }
+ if (!enable || enabled_once[dev_id - 1])
+ return 0;
if (!curr)
return -ENODEV;
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index c31e6d9..e3fc97f 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2707,10 +2707,11 @@
#define MSM_ION_MM_SIZE 0x3600000 /* (54MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_WB_SIZE 0x600000 /* 6MB */
+#define MSM_ION_QSECOM_SIZE 0x300000 /* (3MB) */
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_ION_HEAP_NUM 8
+#define MSM_ION_HEAP_NUM 9
#else
#define MSM_ION_HEAP_NUM 1
#endif
@@ -5352,6 +5353,14 @@
.extra_data = (void *) &cp_wb_ion_pdata,
},
{
+ .id = ION_QSECOM_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_QSECOM_HEAP_NAME,
+ .size = MSM_ION_QSECOM_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
+ },
+ {
.id = ION_AUDIO_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_AUDIO_HEAP_NAME,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 8188e08..5996388 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4887,6 +4887,7 @@
CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
CLK_LOOKUP("xo", cxo_clk.c, "pil_gss"),
+ CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("pll2", pll2_clk.c, NULL),
CLK_LOOKUP("pll8", pll8_clk.c, NULL),
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
@@ -4981,6 +4982,7 @@
CLK_LOOKUP("mem_clk", rpm_msg_ram_p_clk.c, ""),
CLK_LOOKUP("core_clk", amp_clk.c, ""),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-001a"),
+ CLK_LOOKUP("cam_clk", cam1_clk.c, "4-0048"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-006c"),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
CLK_LOOKUP("csi_src_clk", csi1_src_clk.c, "msm_csid.1"),
@@ -5034,6 +5036,7 @@
CLK_LOOKUP("lut_clk", lut_mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("core_clk", rot_clk.c, "msm_rotator.0"),
CLK_LOOKUP("core_clk", rot_clk.c, "footswitch-8x60.6"),
+ CLK_LOOKUP("tv_src_clk", tv_src_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("tv_src_clk", tv_src_clk.c, ""),
CLK_LOOKUP("tv_src_div_clk", tv_src_div_clk.c, ""),
CLK_LOOKUP("core_clk", vcodec_clk.c, "msm_vidc.0"),
@@ -5080,7 +5083,7 @@
CLK_LOOKUP("vfe_pclk", vfe_p_clk.c, "msm_vfe.0"),
CLK_LOOKUP("iface_clk", vfe_p_clk.c, "footswitch-8x60.8"),
CLK_LOOKUP("vpe_pclk", vpe_p_clk.c, ""),
- CLK_LOOKUP("iface_pclk", vpe_p_clk.c, "footswitch-8x60.9"),
+ CLK_LOOKUP("iface_clk", vpe_p_clk.c, "footswitch-8x60.9"),
CLK_LOOKUP("bit_clk", mi2s_bit_clk.c, "msm-dai-q6.6"),
CLK_LOOKUP("osr_clk", mi2s_osr_clk.c, "msm-dai-q6.6"),
@@ -5161,6 +5164,7 @@
CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
+ CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("pll2", pll2_clk.c, NULL),
CLK_LOOKUP("pll8", pll8_clk.c, NULL),
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index df9c152..9e4268f 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -663,7 +663,7 @@
.c = { \
.dbg_name = #name, \
.ops = &clk_ops_rcg_9615, \
- VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000), \
+ VDD_DIG_FMAX_MAP2(LOW, 26000000, NOMINAL, 52000000), \
CLK_INIT(name.c), \
}, \
}
@@ -682,7 +682,10 @@
F_SDC( 17070000, pll8, 1, 2, 45),
F_SDC( 20210000, pll8, 1, 1, 19),
F_SDC( 24000000, pll8, 4, 1, 4),
+ F_SDC( 38400000, pll8, 2, 1, 5),
F_SDC( 48000000, pll8, 4, 1, 2),
+ F_SDC( 64000000, pll8, 3, 1, 2),
+ F_SDC( 76800000, pll8, 1, 1, 5),
F_END
};
@@ -1622,6 +1625,7 @@
static struct clk_lookup msm_clocks_9615[] = {
CLK_LOOKUP("xo", cxo_clk.c, "msm_otg"),
+ CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("pll0", pll0_clk.c, NULL),
CLK_LOOKUP("pll8", pll8_clk.c, NULL),
CLK_LOOKUP("pll14", pll14_clk.c, NULL),
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index fc2e83f..ae87bb7 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -187,12 +187,6 @@
return false;
}
-static unsigned long rpm_branch_clk_get_rate(struct clk *clk)
-{
- struct rpm_clk *r = to_rpm_clk(clk);
- return r->last_set_khz * 1000;
-}
-
struct clk_ops clk_ops_rpm = {
.enable = rpm_clk_enable,
.disable = rpm_clk_disable,
@@ -207,5 +201,4 @@
.enable = rpm_clk_enable,
.disable = rpm_clk_disable,
.is_local = rpm_clk_is_local,
- .get_rate = rpm_branch_clk_get_rate,
};
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 27afd6f..2f4a17c 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -80,6 +80,7 @@
.ops = &clk_ops_rpm_branch, \
.flags = CLKFLAG_SKIP_AUTO_OFF, \
.dbg_name = #name, \
+ .rate = (rate), \
CLK_INIT(name.c), \
}, \
}; \
@@ -94,6 +95,7 @@
.ops = &clk_ops_rpm_branch, \
.flags = CLKFLAG_SKIP_AUTO_OFF, \
.dbg_name = #active, \
+ .rate = (rate), \
CLK_INIT(active.c), \
}, \
};
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 56778e2..107598a 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -50,21 +50,13 @@
static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
-static int override_cpu;
-
static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
{
int ret = 0;
struct cpufreq_freqs freqs;
freqs.old = policy->cur;
- if (override_cpu) {
- if (policy->cur == policy->max)
- return 0;
- else
- freqs.new = policy->max;
- } else
- freqs.new = new_freq;
+ freqs.new = new_freq;
freqs.cpu = policy->cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
@@ -268,25 +260,6 @@
}
}
-static ssize_t store_mfreq(struct sysdev_class *class,
- struct sysdev_class_attribute *attr,
- const char *buf, size_t count)
-{
- u64 val;
-
- if (strict_strtoull(buf, 0, &val) < 0) {
- pr_err("Invalid parameter to mfreq\n");
- return 0;
- }
- if (val)
- override_cpu = 1;
- else
- override_cpu = 0;
- return count;
-}
-
-static SYSDEV_CLASS_ATTR(mfreq, 0200, NULL, store_mfreq);
-
static struct freq_attr *msm_freq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
@@ -310,11 +283,6 @@
{
int cpu;
- int err = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
- &attr_mfreq.attr);
- if (err)
- pr_err("Failed to create sysfs mfreq\n");
-
for_each_possible_cpu(cpu) {
mutex_init(&(per_cpu(cpufreq_suspend, cpu).suspend_mutex));
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 6b79fab..ca85a0a 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -31,6 +31,7 @@
#include <linux/ion.h>
#include "clock.h"
#include "devices.h"
+#include "footswitch.h"
#include "msm_watchdog.h"
#include "rpm_stats.h"
#include "rpm_log.h"
@@ -67,6 +68,10 @@
#define MSM_HSUSB1_PHYS 0x12500000
#define MSM_HSUSB1_SIZE SZ_4K
+/* Address of HS USB3 */
+#define MSM_HSUSB3_PHYS 0x12520000
+#define MSM_HSUSB3_SIZE SZ_4K
+
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
.bark_time = 11000,
@@ -649,6 +654,30 @@
},
};
+static struct resource resources_ehci_host3[] = {
+{
+ .start = MSM_HSUSB3_PHYS,
+ .end = MSM_HSUSB3_PHYS + MSM_HSUSB3_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = USB3_HS_IRQ,
+ .end = USB3_HS_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device apq8064_device_ehci_host3 = {
+ .name = "msm_ehci_host",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(resources_ehci_host3),
+ .resource = resources_ehci_host3,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
/* MSM Video core device */
#ifdef CONFIG_MSM_BUS_SCALING
static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -1230,6 +1259,17 @@
.resource = msm_gss_resources,
};
+struct platform_device *apq8064_fs_devices[] = {
+ FS_8X60(FS_ROT, "fs_rot"),
+ FS_8X60(FS_IJPEG, "fs_ijpeg"),
+ FS_8X60(FS_VFE, "fs_vfe"),
+ FS_8X60(FS_VPE, "fs_vpe"),
+ FS_8X60(FS_GFX3D, "fs_gfx3d"),
+ FS_8X60(FS_VED, "fs_ved"),
+ FS_8X60(FS_VCAP, "fs_vcap"),
+};
+unsigned apq8064_num_fs_devices = ARRAY_SIZE(apq8064_fs_devices);
+
static struct clk_lookup msm_clocks_8064_dummy[] = {
CLK_DUMMY("pll2", PLL2, NULL, 0),
CLK_DUMMY("pll8", PLL8, NULL, 0),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 4d4b88f..19a8db7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2291,6 +2291,20 @@
},
};
+static const char *kgsl_3d0_iommu_ctx_names[] = {
+ "gfx3d_user",
+ /* priv_ctx goes here */
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+ {
+ .iommu_ctx_names = kgsl_3d0_iommu_ctx_names,
+ .iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu_ctx_names),
+ .physstart = 0x07C00000,
+ .physend = 0x07C00000 + SZ_1M - 1,
+ },
+};
+
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
.pwrlevel = {
{
@@ -2327,8 +2341,8 @@
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp3d_bus_scale_pdata,
#endif
- .iommu_user_ctx_name = "gfx3d_user",
- .iommu_priv_ctx_name = NULL,
+ .iommu_data = kgsl_3d0_iommu_data,
+ .iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
};
struct platform_device msm_kgsl_3d0 = {
@@ -2356,6 +2370,19 @@
},
};
+static const char *kgsl_2d0_iommu_ctx_names[] = {
+ "gfx2d0_2d0",
+};
+
+static struct kgsl_device_iommu_data kgsl_2d0_iommu_data[] = {
+ {
+ .iommu_ctx_names = kgsl_2d0_iommu_ctx_names,
+ .iommu_ctx_count = ARRAY_SIZE(kgsl_2d0_iommu_ctx_names),
+ .physstart = 0x07D00000,
+ .physend = 0x07D00000 + SZ_1M - 1,
+ },
+};
+
static struct kgsl_device_platform_data kgsl_2d0_pdata = {
.pwrlevel = {
{
@@ -2380,8 +2407,8 @@
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp2d0_bus_scale_pdata,
#endif
- .iommu_user_ctx_name = "gfx2d0_2d0",
- .iommu_priv_ctx_name = NULL,
+ .iommu_data = kgsl_2d0_iommu_data,
+ .iommu_count = ARRAY_SIZE(kgsl_2d0_iommu_data),
};
struct platform_device msm_kgsl_2d0 = {
@@ -2394,6 +2421,19 @@
},
};
+static const char *kgsl_2d1_iommu_ctx_names[] = {
+ "gfx2d1_2d1",
+};
+
+static struct kgsl_device_iommu_data kgsl_2d1_iommu_data[] = {
+ {
+ .iommu_ctx_names = kgsl_2d1_iommu_ctx_names,
+ .iommu_ctx_count = ARRAY_SIZE(kgsl_2d1_iommu_ctx_names),
+ .physstart = 0x07E00000,
+ .physend = 0x07E00000 + SZ_1M - 1,
+ },
+};
+
static struct resource kgsl_2d1_resources[] = {
{
.name = KGSL_2D1_REG_MEMORY,
@@ -2433,8 +2473,8 @@
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp2d1_bus_scale_pdata,
#endif
- .iommu_user_ctx_name = "gfx2d1_2d1",
- .iommu_priv_ctx_name = NULL,
+ .iommu_data = kgsl_2d1_iommu_data,
+ .iommu_count = ARRAY_SIZE(kgsl_2d1_iommu_data),
};
struct platform_device msm_kgsl_2d1 = {
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index b895870..26f246d 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -76,6 +76,21 @@
.resource = resources_uart2,
};
+static struct resource resources_adsp[] = {
+ {
+ .start = INT_ADSP_A9_A11,
+ .end = INT_ADSP_A9_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_adsp_device = {
+ .name = "msm_adsp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_adsp),
+ .resource = resources_adsp,
+};
+
#define MSM_UART1DM_PHYS 0xA0200000
#define MSM_UART2DM_PHYS 0xA0300000
static struct resource msm_uart1_dm_resources[] = {
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 15d4ae6..cc1e7c5 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -178,17 +178,6 @@
&msm_device_hsusb_host,
};
-int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
-{
- struct platform_device *pdev;
-
- pdev = msm_host_devices[host];
- if (!pdev)
- return -ENODEV;
- pdev->dev.platform_data = plat;
- return platform_device_register(pdev);
-}
-
static struct resource msm_dmov_resource[] = {
{
.start = INT_ADM_AARM,
@@ -221,6 +210,21 @@
.id = -1,
};
+static struct resource resources_adsp[] = {
+ {
+ .start = INT_ADSP_A9_A11,
+ .end = INT_ADSP_A9_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_adsp_device = {
+ .name = "msm_adsp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_adsp),
+ .resource = resources_adsp,
+};
+
static struct resource resources_uart1[] = {
{
.start = INT_UART1,
@@ -513,18 +517,6 @@
&msm_device_sdc4,
};
-int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
-{
- struct platform_device *pdev;
-
- if (controller < 1 || controller > 4)
- return -EINVAL;
-
- pdev = msm_sdcc_devices[controller-1];
- pdev->dev.platform_data = plat;
- return platform_device_register(pdev);
-}
-
#ifdef CONFIG_MSM_CAMERA_V4L2
static struct resource msm_csic0_resources[] = {
{
@@ -715,17 +707,6 @@
__func__, ret);
}
-void __init msm_fb_register_device(char *name, void *data)
-{
- if (!strncmp(name, "mdp", 3))
- msm_register_device(&msm_mdp_device, data);
- else if (!strncmp(name, "mipi_dsi", 8))
- msm_register_device(&msm_mipi_dsi_device, data);
- else if (!strncmp(name, "lcdc", 4))
- msm_register_device(&msm_lcdc_device, data);
- else
- printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
-}
#define PERPH_WEB_BLOCK_ADDR (0xA9D00040)
#define PDM0_CTL_OFFSET (0x04)
@@ -815,6 +796,83 @@
.resource = msm8625_resources_uart1,
};
+static struct resource msm8625_uart1_dm_resources[] = {
+ {
+ .start = MSM_UART1DM_PHYS,
+ .end = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_UART1DM_IRQ,
+ .end = MSM8625_INT_UART1DM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM8625_INT_UART1DM_RX,
+ .end = MSM8625_INT_UART1DM_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = DMOV_HSUART1_TX_CHAN,
+ .end = DMOV_HSUART1_RX_CHAN,
+ .name = "uartdm_channels",
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DMOV_HSUART1_TX_CRCI,
+ .end = DMOV_HSUART1_RX_CRCI,
+ .name = "uartdm_crci",
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device msm8625_device_uart_dm1 = {
+ .name = "msm_serial_hs",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm8625_uart1_dm_resources),
+ .resource = msm8625_uart1_dm_resources,
+ .dev = {
+ .dma_mask = &msm_uart_dm1_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource msm8625_uart2dm_resources[] = {
+ {
+ .start = MSM_UART2DM_PHYS,
+ .end = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_UART2DM_IRQ,
+ .end = MSM8625_INT_UART2DM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm8625_device_uart_dm2 = {
+ .name = "msm_serial_hsl",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm8625_uart2dm_resources),
+ .resource = msm8625_uart2dm_resources,
+};
+
+static struct resource msm8625_resources_adsp[] = {
+ {
+ .start = MSM8625_INT_ADSP_A9_A11,
+ .end = MSM8625_INT_ADSP_A9_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm8625_device_adsp = {
+ .name = "msm_adsp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm8625_resources_adsp),
+ .resource = msm8625_resources_adsp,
+};
+
static struct resource msm8625_dmov_resource[] = {
{
.start = MSM8625_INT_ADM_AARM,
@@ -913,6 +971,391 @@
.num_resources = ARRAY_SIZE(msm8625_gpio_resources),
};
+static struct resource msm8625_resources_sdc1[] = {
+ {
+ .start = MSM_SDC1_BASE,
+ .end = MSM_SDC1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_SDC1_0,
+ .end = MSM8625_INT_SDC1_1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "sdcc_dma_chnl",
+ .start = DMOV_SDC1_CHAN,
+ .end = DMOV_SDC1_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "sdcc_dma_crci",
+ .start = DMOV_SDC1_CRCI,
+ .end = DMOV_SDC1_CRCI,
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+static struct resource msm8625_resources_sdc2[] = {
+ {
+ .start = MSM_SDC2_BASE,
+ .end = MSM_SDC2_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_SDC2_0,
+ .end = MSM8625_INT_SDC2_1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "sdcc_dma_chnl",
+ .start = DMOV_SDC2_CHAN,
+ .end = DMOV_SDC2_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "sdcc_dma_crci",
+ .start = DMOV_SDC2_CRCI,
+ .end = DMOV_SDC2_CRCI,
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+static struct resource msm8625_resources_sdc3[] = {
+ {
+ .start = MSM_SDC3_BASE,
+ .end = MSM_SDC3_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_SDC3_0,
+ .end = MSM8625_INT_SDC3_1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "sdcc_dma_chnl",
+ .start = DMOV_SDC3_CHAN,
+ .end = DMOV_SDC3_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "sdcc_dma_crci",
+ .start = DMOV_SDC3_CRCI,
+ .end = DMOV_SDC3_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource msm8625_resources_sdc4[] = {
+ {
+ .start = MSM_SDC4_BASE,
+ .end = MSM_SDC4_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_SDC4_0,
+ .end = MSM8625_INT_SDC4_1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "sdcc_dma_chnl",
+ .start = DMOV_SDC4_CHAN,
+ .end = DMOV_SDC4_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "sdcc_dma_crci",
+ .start = DMOV_SDC4_CRCI,
+ .end = DMOV_SDC4_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device msm8625_device_sdc1 = {
+ .name = "msm_sdcc",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(msm8625_resources_sdc1),
+ .resource = msm8625_resources_sdc1,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+struct platform_device msm8625_device_sdc2 = {
+ .name = "msm_sdcc",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(msm8625_resources_sdc2),
+ .resource = msm8625_resources_sdc2,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+struct platform_device msm8625_device_sdc3 = {
+ .name = "msm_sdcc",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(msm8625_resources_sdc3),
+ .resource = msm8625_resources_sdc3,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+struct platform_device msm8625_device_sdc4 = {
+ .name = "msm_sdcc",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(msm8625_resources_sdc4),
+ .resource = msm8625_resources_sdc4,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+static struct platform_device *msm8625_sdcc_devices[] __initdata = {
+ &msm8625_device_sdc1,
+ &msm8625_device_sdc2,
+ &msm8625_device_sdc3,
+ &msm8625_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+ struct platform_device *pdev;
+
+ if (controller < 1 || controller > 4)
+ return -EINVAL;
+
+ if (cpu_is_msm8625())
+ pdev = msm8625_sdcc_devices[controller-1];
+ else
+ pdev = msm_sdcc_devices[controller-1];
+
+ pdev->dev.platform_data = plat;
+ return platform_device_register(pdev);
+}
+
+static struct resource msm8625_resources_hsusb_otg[] = {
+ {
+ .start = MSM_HSUSB_PHYS,
+ .end = MSM_HSUSB_PHYS + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_USB_HS,
+ .end = MSM8625_INT_USB_HS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm8625_device_otg = {
+ .name = "msm_otg",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm8625_resources_hsusb_otg),
+ .resource = msm8625_resources_hsusb_otg,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffffULL,
+ },
+};
+
+static struct resource msm8625_resources_gadget_peripheral[] = {
+ {
+ .start = MSM_HSUSB_PHYS,
+ .end = MSM_HSUSB_PHYS + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_USB_HS,
+ .end = MSM8625_INT_USB_HS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm8625_device_gadget_peripheral = {
+ .name = "msm_hsusb",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm8625_resources_gadget_peripheral),
+ .resource = msm8625_resources_gadget_peripheral,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffffULL,
+ },
+};
+
+static struct resource msm8625_resources_hsusb_host[] = {
+ {
+ .start = MSM_HSUSB_PHYS,
+ .end = MSM_HSUSB_PHYS + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_USB_HS,
+ .end = MSM8625_INT_USB_HS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm8625_device_hsusb_host = {
+ .name = "msm_hsusb_host",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm8625_resources_hsusb_host),
+ .resource = msm8625_resources_hsusb_host,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffffULL,
+ },
+};
+
+static struct platform_device *msm8625_host_devices[] = {
+ &msm8625_device_hsusb_host,
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+ struct platform_device *pdev;
+
+ if (cpu_is_msm8625())
+ pdev = msm8625_host_devices[host];
+ else
+ pdev = msm_host_devices[host];
+ if (!pdev)
+ return -ENODEV;
+ pdev->dev.platform_data = plat;
+ return platform_device_register(pdev);
+}
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm8625_csic0_resources[] = {
+ {
+ .name = "csic",
+ .start = 0xA0F00000,
+ .end = 0xA0F00000 + 0x00100000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "csic",
+ .start = MSM8625_INT_CSI_IRQ_0,
+ .end = MSM8625_INT_CSI_IRQ_0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource msm8625_csic1_resources[] = {
+ {
+ .name = "csic",
+ .start = 0xA1000000,
+ .end = 0xA1000000 + 0x00100000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "csic",
+ .start = MSM8625_INT_CSI_IRQ_1,
+ .end = MSM8625_INT_CSI_IRQ_1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm8625_device_csic0 = {
+ .name = "msm_csic",
+ .id = 0,
+ .resource = msm8625_csic0_resources,
+ .num_resources = ARRAY_SIZE(msm8625_csic0_resources),
+};
+
+struct platform_device msm8625_device_csic1 = {
+ .name = "msm_csic",
+ .id = 1,
+ .resource = msm8625_csic1_resources,
+ .num_resources = ARRAY_SIZE(msm8625_csic1_resources),
+};
+#endif
+
+static struct resource msm8625_mipi_dsi_resources[] = {
+ {
+ .name = "mipi_dsi",
+ .start = MIPI_DSI_HW_BASE,
+ .end = MIPI_DSI_HW_BASE + 0x000F0000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_DSI_IRQ,
+ .end = MSM8625_INT_DSI_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device msm8625_mipi_dsi_device = {
+ .name = "mipi_dsi",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(msm8625_mipi_dsi_resources),
+ .resource = msm8625_mipi_dsi_resources,
+};
+
+static struct resource msm8625_mdp_resources[] = {
+ {
+ .name = "mdp",
+ .start = MDP_BASE,
+ .end = MDP_BASE + 0x000F1008 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM8625_INT_MDP,
+ .end = MSM8625_INT_MDP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device msm8625_mdp_device = {
+ .name = "mdp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm8625_mdp_resources),
+ .resource = msm8625_mdp_resources,
+};
+
+void __init msm_fb_register_device(char *name, void *data)
+{
+ if (!strncmp(name, "mdp", 3)) {
+ if (cpu_is_msm8625())
+ msm_register_device(&msm8625_mdp_device, data);
+ else
+ msm_register_device(&msm_mdp_device, data);
+ } else if (!strncmp(name, "mipi_dsi", 8)) {
+ if (cpu_is_msm8625())
+ msm_register_device(&msm8625_mipi_dsi_device, data);
+ else
+ msm_register_device(&msm_mipi_dsi_device, data);
+ } else if (!strncmp(name, "lcdc", 4)) {
+ msm_register_device(&msm_lcdc_device, data);
+ } else {
+ printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+ }
+}
+
+static struct resource msm8625_kgsl_3d0_resources[] = {
+ {
+ .name = KGSL_3D0_REG_MEMORY,
+ .start = 0xA0000000,
+ .end = 0xA001ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = KGSL_3D0_IRQ,
+ .start = MSM8625_INT_GRAPHICS,
+ .end = MSM8625_INT_GRAPHICS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm8625_kgsl_3d0 = {
+ .name = "kgsl-3d0",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm8625_kgsl_3d0_resources),
+ .resource = msm8625_kgsl_3d0_resources,
+ .dev = {
+ .platform_data = &kgsl_3d0_pdata,
+ },
+};
+
static struct clk_lookup msm_clock_8625_dummy[] = {
CLK_DUMMY("core_clk", adm_clk.c, "msm_dmov", 0),
CLK_DUMMY("adsp_clk", adsp_clk.c, NULL, 0),
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index be6a645..c2383c6 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -23,6 +23,10 @@
extern struct platform_device msm7x27a_device_csic0;
extern struct platform_device msm7x27a_device_csic1;
extern struct platform_device msm7x27a_device_clkctl;
+
+extern struct platform_device msm8625_device_csic0;
+extern struct platform_device msm8625_device_csic1;
+
void __init msm8625_init_irq(void);
void __init msm8625_map_io(void);
int ar600x_wlan_power(bool on);
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index c86d051..ed48659 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -38,6 +38,7 @@
extern struct platform_device msm_ebi0_thermal;
extern struct platform_device msm_ebi1_thermal;
+extern struct platform_device msm_adsp_device;
extern struct platform_device msm_device_uart1;
extern struct platform_device msm_device_uart2;
extern struct platform_device msm_device_uart3;
@@ -110,6 +111,7 @@
extern struct platform_device apq8064_device_gadget_peripheral;
extern struct platform_device apq8064_device_hsusb_host;
extern struct platform_device apq8064_device_hsic_host;
+extern struct platform_device apq8064_device_ehci_host3;
extern struct platform_device msm_device_i2c;
@@ -128,6 +130,17 @@
extern struct platform_device msm8625_device_qup_i2c_gsbi0;
extern struct platform_device msm8625_device_qup_i2c_gsbi1;
+extern struct platform_device msm8625_device_uart_dm1;
+extern struct platform_device msm8625_device_uart_dm2;
+extern struct platform_device msm8625_device_sdc1;
+extern struct platform_device msm8625_device_sdc2;
+extern struct platform_device msm8625_device_sdc3;
+extern struct platform_device msm8625_device_sdc4;
+extern struct platform_device msm8625_device_gadget_peripheral;
+extern struct platform_device msm8625_device_hsusb_host;
+extern struct platform_device msm8625_device_otg;
+extern struct platform_device msm8625_kgsl_3d0;
+extern struct platform_device msm8625_device_adsp;
extern struct platform_device msm_slim_ctrl;
extern struct platform_device msm_device_sps;
@@ -231,6 +244,8 @@
extern struct platform_device *msm_footswitch_devices[];
extern unsigned msm_num_footswitch_devices;
+extern struct platform_device *apq8064_fs_devices[];
+extern unsigned apq8064_num_fs_devices;
extern struct platform_device fsm_qfp_fuse_device;
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 5c10463..4609a4b 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -99,8 +99,8 @@
clock->reset_rate : DEFAULT_RATE;
rc = clk_set_rate(clock->clk, rate);
if (rc && rc != -ENOSYS) {
- pr_err("Failed to set %s rate to %lu Hz.\n",
- clock->name, clock->rate);
+ pr_err("Failed to set %s %s rate to %lu Hz.\n",
+ fs->desc.name, clock->name, clock->rate);
for (clock--; clock >= fs->clk_data; clock--) {
if (clock->enabled)
clk_disable_unprepare(
@@ -131,8 +131,8 @@
if (clock->enabled)
clk_disable_unprepare(clock->clk);
if (clock->rate && clk_set_rate(clock->clk, clock->rate))
- pr_err("Failed to restore %s rate to %lu Hz.\n",
- clock->name, clock->rate);
+ pr_err("Failed to restore %s %s rate to %lu Hz.\n",
+ fs->desc.name, clock->name, clock->rate);
}
}
@@ -167,14 +167,14 @@
if (fs->bus_port0) {
rc = msm_bus_axi_portunhalt(fs->bus_port0);
if (rc) {
- pr_err("Port 0 unhalt failed.\n");
+ pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
goto err;
}
}
if (fs->bus_port1) {
rc = msm_bus_axi_portunhalt(fs->bus_port1);
if (rc) {
- pr_err("Port 1 unhalt failed.\n");
+ pr_err("%s port 1 unhalt failed.\n", fs->desc.name);
goto err_port2_halt;
}
}
@@ -252,14 +252,14 @@
if (fs->bus_port0) {
rc = msm_bus_axi_porthalt(fs->bus_port0);
if (rc) {
- pr_err("Port 0 halt failed.\n");
+ pr_err("%s port 0 halt failed.\n", fs->desc.name);
goto err;
}
}
if (fs->bus_port1) {
rc = msm_bus_axi_porthalt(fs->bus_port1);
if (rc) {
- pr_err("Port 1 halt failed.\n");
+ pr_err("%s port 1 halt failed.\n", fs->desc.name);
goto err_port2_halt;
}
}
@@ -329,7 +329,7 @@
if (fs->bus_port0) {
rc = msm_bus_axi_portunhalt(fs->bus_port0);
if (rc) {
- pr_err("Port 0 unhalt failed.\n");
+ pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
goto err;
}
}
@@ -404,7 +404,7 @@
if (fs->bus_port0) {
rc = msm_bus_axi_porthalt(fs->bus_port0);
if (rc) {
- pr_err("Port 0 halt failed.\n");
+ pr_err("%s port 0 halt failed.\n", fs->desc.name);
goto err;
}
}
@@ -635,7 +635,8 @@
clock->clk = clk_get(&pdev->dev, clock->name);
if (IS_ERR(clock->clk)) {
rc = PTR_ERR(clock->clk);
- pr_err("clk_get(%s) failed\n", clock->name);
+ pr_err("%s clk_get(%s) failed\n", fs->desc.name,
+ clock->name);
goto err;
}
if (!strncmp(clock->name, "core_clk", 8))
diff --git a/arch/arm/mach-msm/footswitch-pcom.c b/arch/arm/mach-msm/footswitch-pcom.c
index 340f19b..f8e84fc 100644
--- a/arch/arm/mach-msm/footswitch-pcom.c
+++ b/arch/arm/mach-msm/footswitch-pcom.c
@@ -205,14 +205,14 @@
fs->src_clk = clk_get(dev, "core_clk");
}
if (IS_ERR(fs->src_clk)) {
- pr_err("clk_get(src_clk) failed\n");
+ pr_err("%s clk_get(src_clk) failed\n", fs->desc.name);
rc = PTR_ERR(fs->src_clk);
goto err_src_clk;
}
fs->core_clk = clk_get(dev, "core_clk");
if (IS_ERR(fs->core_clk)) {
- pr_err("clk_get(core_clk) failed\n");
+ pr_err("%s clk_get(core_clk) failed\n", fs->desc.name);
rc = PTR_ERR(fs->core_clk);
goto err_core_clk;
}
@@ -220,7 +220,7 @@
if (fs->has_ahb_clk) {
fs->ahb_clk = clk_get(dev, "iface_clk");
if (IS_ERR(fs->ahb_clk)) {
- pr_err("clk_get(iface_clk) failed\n");
+ pr_err("%s clk_get(iface_clk) failed\n", fs->desc.name);
rc = PTR_ERR(fs->ahb_clk);
goto err_ahb_clk;
}
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 954b673..1ae7454 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -42,10 +42,11 @@
#define NR_GPIO_IRQS 152
#define NR_PM8921_IRQS 256
#define NR_PM8821_IRQS 64
-#define NR_TABLA_IRQS 49
+#define NR_WCD9XXX_IRQS 49
+#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
#define NR_GPIO_EXPANDER_IRQS 8
#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
- NR_TABLA_IRQS + NR_GPIO_EXPANDER_IRQS)
+ NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
#define NR_MSM_GPIOS NR_GPIO_IRQS
diff --git a/arch/arm/mach-msm/include/mach/msm_adsp.h b/arch/arm/mach-msm/include/mach/msm_adsp.h
index bbae6c1..e40c07d 100644
--- a/arch/arm/mach-msm/include/mach/msm_adsp.h
+++ b/arch/arm/mach-msm/include/mach/msm_adsp.h
@@ -1,7 +1,7 @@
/* include/asm-arm/arch-msm/msm_adsp.h
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, 2012 Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -52,6 +52,14 @@
unsigned queue_id,
void *data, size_t len);
+/*Explicitly gererate adsp event */
+int msm_adsp_generate_event(void *data,
+ struct msm_adsp_module *mod,
+ unsigned event_id,
+ unsigned event_length,
+ unsigned event_size,
+ void *msg);
+
#define ADSP_MESSAGE_ID 0xFFFF
/* Command Queue Indexes */
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
index a75ab91..5eea63f 100644
--- a/arch/arm/mach-msm/include/mach/msm_rtb.h
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -13,13 +13,18 @@
#ifndef __MSM_RTB_H__
#define __MSM_RTB_H__
+/*
+ * These numbers are used from the kernel command line and sysfs
+ * to control filtering. Remove items from here with extreme caution
+ */
enum logk_event_type {
LOGK_NONE = 0,
- LOGK_READL,
- LOGK_WRITEL,
- LOGK_LOGBUF,
- LOGK_HOTPLUG,
- LOGK_OTHER,
+ LOGK_READL = 1,
+ LOGK_WRITEL = 2,
+ LOGK_LOGBUF = 3,
+ LOGK_HOTPLUG = 4,
+ LOGK_CTXID = 5,
+ LOGK_OTHER = 31,
};
struct msm_rtb_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/qpnp.h b/arch/arm/mach-msm/include/mach/qpnp.h
new file mode 100644
index 0000000..1d2e440
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qpnp.h
@@ -0,0 +1,19 @@
+ /* 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 <linux/spmi.h>
+
+struct resource *qpnp_get_resource(struct spmi_device *dev,
+ unsigned int node_idx, unsigned int type,
+ unsigned int res_num);
+int qpnp_get_irq(struct spmi_device *dev, unsigned int node_idx,
+ unsigned int res_num);
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index e1d4459..215fdb3 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -103,7 +103,7 @@
static inline int cpu_is_msm7x27(void)
{
-#ifdef CONFIG_ARCH_MSM7X27
+#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)
enum msm_cpu cpu = socinfo_get_msm_cpu();
BUG_ON(cpu == MSM_CPU_UNKNOWN);
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index dcf9f12..8e74238 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -43,7 +43,7 @@
*/
unsigned int msm_shared_ram_phys = 0x00100000;
-static void msm_map_io(struct map_desc *io_desc, int size)
+static void __init msm_map_io(struct map_desc *io_desc, int size)
{
int i;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 15ea8ba..538dbbe 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -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
@@ -756,7 +756,7 @@
pkt->length = pkt_size;
mutex_lock(&xprt_info->tx_lock);
- ret = xprt_info->xprt->write(pkt, pkt_size, 0);
+ ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
mutex_unlock(&xprt_info->tx_lock);
release_pkt(pkt);
@@ -933,7 +933,8 @@
list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
mutex_lock(&fwd_xprt_info->tx_lock);
if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
- fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+ fwd_xprt_info->xprt->write(pkt, pkt->length,
+ fwd_xprt_info->xprt);
mutex_unlock(&fwd_xprt_info->tx_lock);
}
mutex_unlock(&xprt_info_list_lock);
@@ -984,7 +985,7 @@
pr_err("%s: DST in the same cluster\n", __func__);
return 0;
}
- fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+ fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
mutex_unlock(&fwd_xprt_info->tx_lock);
mutex_unlock(&rt_entry->lock);
mutex_unlock(&routing_table_lock);
@@ -1713,7 +1714,7 @@
mutex_lock(&rt_entry->lock);
xprt_info = rt_entry->xprt_info;
mutex_lock(&xprt_info->tx_lock);
- ret = xprt_info->xprt->write(pkt, pkt->length, 0);
+ ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
mutex_unlock(&xprt_info->tx_lock);
mutex_unlock(&rt_entry->lock);
mutex_unlock(&routing_table_lock);
@@ -2070,7 +2071,7 @@
mutex_lock(&xprt_info_list_lock);
list_for_each_entry_safe(xprt_info, tmp_xprt_info,
&xprt_info_list, list) {
- xprt_info->xprt->close();
+ xprt_info->xprt->close(xprt_info->xprt);
list_del(&xprt_info->list);
kfree(xprt_info);
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index b125185..bd10ea7 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.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
@@ -150,11 +150,13 @@
uint32_t link_id;
void *priv;
- int (*read_avail)(void);
- int (*read)(void *data, uint32_t len);
- int (*write_avail)(void);
- int (*write)(void *data, uint32_t len, enum write_data_type type);
- int (*close)(void);
+ int (*read_avail)(struct msm_ipc_router_xprt *xprt);
+ int (*read)(void *data, uint32_t len,
+ struct msm_ipc_router_xprt *xprt);
+ int (*write_avail)(struct msm_ipc_router_xprt *xprt);
+ int (*write)(void *data, uint32_t len,
+ struct msm_ipc_router_xprt *xprt);
+ int (*close)(struct msm_ipc_router_xprt *xprt);
};
extern struct completion msm_ipc_remote_router_up;
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 997d4b5..6960d2e 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -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
@@ -38,14 +38,21 @@
#define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
+#define NUM_SMD_XPRTS 2
+#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
+
struct msm_ipc_router_smd_xprt {
struct msm_ipc_router_xprt xprt;
-
smd_channel_t *channel;
+ struct workqueue_struct *smd_xprt_wq;
+ wait_queue_head_t write_avail_wait_q;
+ struct rr_packet *in_pkt;
+ int is_partial_in_pkt;
+ struct delayed_work read_work;
+ spinlock_t ss_reset_lock; /*Subsystem reset lock*/
+ int ss_reset;
};
-static struct msm_ipc_router_smd_xprt smd_remote_xprt;
-
struct msm_ipc_router_smd_xprt_work {
struct msm_ipc_router_xprt *xprt;
struct work_struct work;
@@ -54,24 +61,45 @@
static void smd_xprt_read_data(struct work_struct *work);
static void smd_xprt_open_event(struct work_struct *work);
static void smd_xprt_close_event(struct work_struct *work);
-static DECLARE_DELAYED_WORK(work_read_data, smd_xprt_read_data);
-static struct workqueue_struct *smd_xprt_workqueue;
-static wait_queue_head_t write_avail_wait_q;
-static struct rr_packet *in_pkt;
-static int is_partial_in_pkt;
+struct msm_ipc_router_smd_xprt_config {
+ char ch_name[SMD_MAX_CH_NAME_LEN];
+ char xprt_name[XPRT_NAME_LEN];
+ uint32_t edge;
+ uint32_t link_id;
+};
-static DEFINE_SPINLOCK(modem_reset_lock);
-static int modem_reset;
+struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
+ {"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
+ {"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
+};
-static int msm_ipc_router_smd_remote_write_avail(void)
+static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
+
+static int find_smd_xprt_cfg(const char *name)
{
- return smd_write_avail(smd_remote_xprt.channel);
+ int i;
+
+ for (i = 0; i < NUM_SMD_XPRTS; i++) {
+ if (!strncmp(name, smd_xprt_cfg[i].ch_name, 20))
+ return i;
+ }
+
+ return -ENODEV;
+}
+
+static int msm_ipc_router_smd_remote_write_avail(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_smd_xprt *smd_xprtp =
+ container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+ return smd_write_avail(smd_xprtp->channel);
}
static int msm_ipc_router_smd_remote_write(void *data,
uint32_t len,
- uint32_t type)
+ struct msm_ipc_router_xprt *xprt)
{
struct rr_packet *pkt = (struct rr_packet *)data;
struct sk_buff *ipc_rtr_pkt;
@@ -79,6 +107,8 @@
int offset, sz_written = 0;
int ret, num_retries = 0;
unsigned long flags;
+ struct msm_ipc_router_smd_xprt *smd_xprtp =
+ container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
if (!pkt)
return -EINVAL;
@@ -87,81 +117,92 @@
return -EINVAL;
align_sz = ALIGN_SIZE(pkt->length);
- while ((ret = smd_write_start(smd_remote_xprt.channel,
+ while ((ret = smd_write_start(smd_xprtp->channel,
(len + align_sz))) < 0) {
- spin_lock_irqsave(&modem_reset_lock, flags);
- if (modem_reset) {
- spin_unlock_irqrestore(&modem_reset_lock, flags);
- pr_err("%s: Modem reset\n", __func__);
+ spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+ if (smd_xprtp->ss_reset) {
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+ flags);
+ pr_err("%s: %s chnl reset\n", __func__, xprt->name);
return -ENETRESET;
}
- spin_unlock_irqrestore(&modem_reset_lock, flags);
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
if (num_retries >= 5) {
- pr_err("%s: Error %d @ smd_write_start\n",
- __func__, ret);
+ pr_err("%s: Error %d @smd_write_start for %s\n",
+ __func__, ret, xprt->name);
return ret;
}
msleep(50);
+ num_retries++;
}
D("%s: Ready to write\n", __func__);
skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
offset = 0;
while (offset < ipc_rtr_pkt->len) {
- if (!smd_write_avail(smd_remote_xprt.channel))
- smd_enable_read_intr(smd_remote_xprt.channel);
+ if (!smd_write_avail(smd_xprtp->channel))
+ smd_enable_read_intr(smd_xprtp->channel);
- wait_event(write_avail_wait_q,
- (smd_write_avail(smd_remote_xprt.channel) ||
- modem_reset));
- smd_disable_read_intr(smd_remote_xprt.channel);
- spin_lock_irqsave(&modem_reset_lock, flags);
- if (modem_reset) {
- spin_unlock_irqrestore(&modem_reset_lock,
- flags);
- pr_err("%s: Modem reset\n", __func__);
+ wait_event(smd_xprtp->write_avail_wait_q,
+ (smd_write_avail(smd_xprtp->channel) ||
+ smd_xprtp->ss_reset));
+ smd_disable_read_intr(smd_xprtp->channel);
+ spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+ if (smd_xprtp->ss_reset) {
+ spin_unlock_irqrestore(
+ &smd_xprtp->ss_reset_lock, flags);
+ pr_err("%s: %s chnl reset\n",
+ __func__, xprt->name);
return -ENETRESET;
}
- spin_unlock_irqrestore(&modem_reset_lock, flags);
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+ flags);
- sz_written = smd_write_segment(smd_remote_xprt.channel,
- ipc_rtr_pkt->data + offset,
- (ipc_rtr_pkt->len - offset), 0);
+ sz_written = smd_write_segment(smd_xprtp->channel,
+ ipc_rtr_pkt->data + offset,
+ (ipc_rtr_pkt->len - offset), 0);
offset += sz_written;
sz_written = 0;
}
- D("%s: Wrote %d bytes\n", __func__, offset);
+ D("%s: Wrote %d bytes over %s\n",
+ __func__, offset, xprt->name);
}
if (align_sz) {
- if (smd_write_avail(smd_remote_xprt.channel) < align_sz)
- smd_enable_read_intr(smd_remote_xprt.channel);
+ if (smd_write_avail(smd_xprtp->channel) < align_sz)
+ smd_enable_read_intr(smd_xprtp->channel);
- wait_event(write_avail_wait_q,
- ((smd_write_avail(smd_remote_xprt.channel) >=
- align_sz) || modem_reset));
- smd_disable_read_intr(smd_remote_xprt.channel);
- spin_lock_irqsave(&modem_reset_lock, flags);
- if (modem_reset) {
- spin_unlock_irqrestore(&modem_reset_lock, flags);
- pr_err("%s: Modem reset\n", __func__);
+ wait_event(smd_xprtp->write_avail_wait_q,
+ ((smd_write_avail(smd_xprtp->channel) >=
+ align_sz) || smd_xprtp->ss_reset));
+ smd_disable_read_intr(smd_xprtp->channel);
+ spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+ if (smd_xprtp->ss_reset) {
+ spin_unlock_irqrestore(
+ &smd_xprtp->ss_reset_lock, flags);
+ pr_err("%s: %s chnl reset\n",
+ __func__, xprt->name);
return -ENETRESET;
}
- spin_unlock_irqrestore(&modem_reset_lock, flags);
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+ flags);
- smd_write_segment(smd_remote_xprt.channel,
+ smd_write_segment(smd_xprtp->channel,
&align_data, align_sz, 0);
- D("%s: Wrote %d align bytes\n", __func__, align_sz);
+ D("%s: Wrote %d align bytes over %s\n",
+ __func__, align_sz, xprt->name);
}
- if (!smd_write_end(smd_remote_xprt.channel))
+ if (!smd_write_end(smd_xprtp->channel))
D("%s: Finished writing\n", __func__);
return len;
}
-static int msm_ipc_router_smd_remote_close(void)
+static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
{
- smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
- return smd_close(smd_remote_xprt.channel);
+ struct msm_ipc_router_smd_xprt *smd_xprtp =
+ container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+ return smd_close(smd_xprtp->channel);
}
static void smd_xprt_read_data(struct work_struct *work)
@@ -170,90 +211,97 @@
struct sk_buff *ipc_rtr_pkt;
void *data;
unsigned long flags;
+ struct delayed_work *rwork = to_delayed_work(work);
+ struct msm_ipc_router_smd_xprt *smd_xprtp =
+ container_of(rwork, struct msm_ipc_router_smd_xprt, read_work);
- spin_lock_irqsave(&modem_reset_lock, flags);
- if (modem_reset) {
- spin_unlock_irqrestore(&modem_reset_lock, flags);
- release_pkt(in_pkt);
- is_partial_in_pkt = 0;
- pr_err("%s: Modem reset\n", __func__);
+ spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+ if (smd_xprtp->ss_reset) {
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+ if (smd_xprtp->in_pkt)
+ release_pkt(smd_xprtp->in_pkt);
+ smd_xprtp->is_partial_in_pkt = 0;
+ pr_err("%s: %s channel reset\n",
+ __func__, smd_xprtp->xprt.name);
return;
}
- spin_unlock_irqrestore(&modem_reset_lock, flags);
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
D("%s pkt_size: %d, read_avail: %d\n", __func__,
- smd_cur_packet_size(smd_remote_xprt.channel),
- smd_read_avail(smd_remote_xprt.channel));
- while ((pkt_size = smd_cur_packet_size(smd_remote_xprt.channel)) &&
- smd_read_avail(smd_remote_xprt.channel)) {
- if (!is_partial_in_pkt) {
- in_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
- if (!in_pkt) {
+ smd_cur_packet_size(smd_xprtp->channel),
+ smd_read_avail(smd_xprtp->channel));
+ while ((pkt_size = smd_cur_packet_size(smd_xprtp->channel)) &&
+ smd_read_avail(smd_xprtp->channel)) {
+ if (!smd_xprtp->is_partial_in_pkt) {
+ smd_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+ GFP_KERNEL);
+ if (!smd_xprtp->in_pkt) {
pr_err("%s: Couldn't alloc rr_packet\n",
__func__);
return;
}
- in_pkt->pkt_fragment_q = kmalloc(
- sizeof(struct sk_buff_head),
- GFP_KERNEL);
- if (!in_pkt->pkt_fragment_q) {
+ smd_xprtp->in_pkt->pkt_fragment_q =
+ kmalloc(sizeof(struct sk_buff_head),
+ GFP_KERNEL);
+ if (!smd_xprtp->in_pkt->pkt_fragment_q) {
pr_err("%s: Couldn't alloc pkt_fragment_q\n",
__func__);
- kfree(in_pkt);
+ kfree(smd_xprtp->in_pkt);
return;
}
- skb_queue_head_init(in_pkt->pkt_fragment_q);
- is_partial_in_pkt = 1;
+ skb_queue_head_init(smd_xprtp->in_pkt->pkt_fragment_q);
+ smd_xprtp->is_partial_in_pkt = 1;
D("%s: Allocated rr_packet\n", __func__);
}
if (((pkt_size >= MIN_FRAG_SZ) &&
- (smd_read_avail(smd_remote_xprt.channel) < MIN_FRAG_SZ)) ||
+ (smd_read_avail(smd_xprtp->channel) < MIN_FRAG_SZ)) ||
((pkt_size < MIN_FRAG_SZ) &&
- (smd_read_avail(smd_remote_xprt.channel) < pkt_size)))
+ (smd_read_avail(smd_xprtp->channel) < pkt_size)))
return;
- sz = smd_read_avail(smd_remote_xprt.channel);
+ sz = smd_read_avail(smd_xprtp->channel);
do {
ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
if (!ipc_rtr_pkt) {
if (sz <= (PAGE_SIZE/2)) {
- queue_delayed_work(smd_xprt_workqueue,
- &work_read_data,
- msecs_to_jiffies(100));
+ queue_delayed_work(
+ smd_xprtp->smd_xprt_wq,
+ &smd_xprtp->read_work,
+ msecs_to_jiffies(100));
return;
}
sz = sz / 2;
}
} while (!ipc_rtr_pkt);
- D("%s: Allocated the sk_buff of size %d\n",
- __func__, sz);
+ D("%s: Allocated the sk_buff of size %d\n", __func__, sz);
data = skb_put(ipc_rtr_pkt, sz);
- sz_read = smd_read(smd_remote_xprt.channel, data, sz);
+ sz_read = smd_read(smd_xprtp->channel, data, sz);
if (sz_read != sz) {
- pr_err("%s: Couldn't read completely\n", __func__);
+ pr_err("%s: Couldn't read %s completely\n",
+ __func__, smd_xprtp->xprt.name);
kfree_skb(ipc_rtr_pkt);
- release_pkt(in_pkt);
- is_partial_in_pkt = 0;
+ release_pkt(smd_xprtp->in_pkt);
+ smd_xprtp->is_partial_in_pkt = 0;
return;
}
- skb_queue_tail(in_pkt->pkt_fragment_q, ipc_rtr_pkt);
- in_pkt->length += sz_read;
+ skb_queue_tail(smd_xprtp->in_pkt->pkt_fragment_q, ipc_rtr_pkt);
+ smd_xprtp->in_pkt->length += sz_read;
if (sz_read != pkt_size)
- is_partial_in_pkt = 1;
+ smd_xprtp->is_partial_in_pkt = 1;
else
- is_partial_in_pkt = 0;
+ smd_xprtp->is_partial_in_pkt = 0;
- if (!is_partial_in_pkt) {
+ if (!smd_xprtp->is_partial_in_pkt) {
D("%s: Packet size read %d\n",
- __func__, in_pkt->length);
- msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
- IPC_ROUTER_XPRT_EVENT_DATA,
- (void *)in_pkt);
- release_pkt(in_pkt);
- in_pkt = NULL;
+ __func__, smd_xprtp->in_pkt->length);
+ msm_ipc_router_xprt_notify(&smd_xprtp->xprt,
+ IPC_ROUTER_XPRT_EVENT_DATA,
+ (void *)smd_xprtp->in_pkt);
+ release_pkt(smd_xprtp->in_pkt);
+ smd_xprtp->in_pkt = NULL;
}
}
}
@@ -265,7 +313,8 @@
msm_ipc_router_xprt_notify(xprt_work->xprt,
IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
- D("%s: Notified IPC Router of OPEN Event\n", __func__);
+ D("%s: Notified IPC Router of %s OPEN\n",
+ __func__, xprt_work->xprt->name);
kfree(xprt_work);
}
@@ -276,28 +325,34 @@
msm_ipc_router_xprt_notify(xprt_work->xprt,
IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
- D("%s: Notified IPC Router of CLOSE Event\n", __func__);
+ D("%s: Notified IPC Router of %s CLOSE\n",
+ __func__, xprt_work->xprt->name);
kfree(xprt_work);
}
static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
{
unsigned long flags;
+ struct msm_ipc_router_smd_xprt *smd_xprtp;
struct msm_ipc_router_smd_xprt_work *xprt_work;
+ smd_xprtp = (struct msm_ipc_router_smd_xprt *)_dev;
+ if (!smd_xprtp)
+ return;
+
switch (event) {
case SMD_EVENT_DATA:
- if (smd_read_avail(smd_remote_xprt.channel))
- queue_delayed_work(smd_xprt_workqueue,
- &work_read_data, 0);
- if (smd_write_avail(smd_remote_xprt.channel))
- wake_up(&write_avail_wait_q);
+ if (smd_read_avail(smd_xprtp->channel))
+ queue_delayed_work(smd_xprtp->smd_xprt_wq,
+ &smd_xprtp->read_work, 0);
+ if (smd_write_avail(smd_xprtp->channel))
+ wake_up(&smd_xprtp->write_avail_wait_q);
break;
case SMD_EVENT_OPEN:
- spin_lock_irqsave(&modem_reset_lock, flags);
- modem_reset = 0;
- spin_unlock_irqrestore(&modem_reset_lock, flags);
+ spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+ smd_xprtp->ss_reset = 0;
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
GFP_ATOMIC);
if (!xprt_work) {
@@ -305,16 +360,16 @@
__func__, event);
return;
}
- xprt_work->xprt = &smd_remote_xprt.xprt;
+ xprt_work->xprt = &smd_xprtp->xprt;
INIT_WORK(&xprt_work->work, smd_xprt_open_event);
- queue_work(smd_xprt_workqueue, &xprt_work->work);
+ queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
break;
case SMD_EVENT_CLOSE:
- spin_lock_irqsave(&modem_reset_lock, flags);
- modem_reset = 1;
- spin_unlock_irqrestore(&modem_reset_lock, flags);
- wake_up(&write_avail_wait_q);
+ spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+ smd_xprtp->ss_reset = 1;
+ spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+ wake_up(&smd_xprtp->write_avail_wait_q);
xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
GFP_ATOMIC);
if (!xprt_work) {
@@ -322,9 +377,9 @@
__func__, event);
return;
}
- xprt_work->xprt = &smd_remote_xprt.xprt;
+ xprt_work->xprt = &smd_xprtp->xprt;
INIT_WORK(&xprt_work->work, smd_xprt_close_event);
- queue_work(smd_xprt_workqueue, &xprt_work->work);
+ queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
break;
}
}
@@ -332,50 +387,93 @@
static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
{
int rc;
+ int id; /*Index into the smd_xprt_cfg table*/
- smd_xprt_workqueue = create_singlethread_workqueue("smd_xprt");
- if (!smd_xprt_workqueue)
- return -ENOMEM;
+ id = find_smd_xprt_cfg(pdev->name);
+ if (id < 0) {
+ pr_err("%s: called for unknown ch %s\n",
+ __func__, pdev->name);
+ return id;
+ }
- smd_remote_xprt.xprt.name = "msm_ipc_router_smd_xprt";
- smd_remote_xprt.xprt.link_id = 1;
- smd_remote_xprt.xprt.read_avail = NULL;
- smd_remote_xprt.xprt.read = NULL;
- smd_remote_xprt.xprt.write_avail =
+ smd_remote_xprt[id].smd_xprt_wq =
+ create_singlethread_workqueue(pdev->name);
+ if (!smd_remote_xprt[id].smd_xprt_wq) {
+ pr_err("%s: WQ creation failed for %s\n",
+ __func__, pdev->name);
+ return -EFAULT;
+ }
+
+ smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
+ smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+ smd_remote_xprt[id].xprt.read_avail = NULL;
+ smd_remote_xprt[id].xprt.read = NULL;
+ smd_remote_xprt[id].xprt.write_avail =
msm_ipc_router_smd_remote_write_avail;
- smd_remote_xprt.xprt.write = msm_ipc_router_smd_remote_write;
- smd_remote_xprt.xprt.close = msm_ipc_router_smd_remote_close;
- smd_remote_xprt.xprt.priv = NULL;
+ smd_remote_xprt[id].xprt.write = msm_ipc_router_smd_remote_write;
+ smd_remote_xprt[id].xprt.close = msm_ipc_router_smd_remote_close;
+ smd_remote_xprt[id].xprt.priv = NULL;
- init_waitqueue_head(&write_avail_wait_q);
+ init_waitqueue_head(&smd_remote_xprt[id].write_avail_wait_q);
+ smd_remote_xprt[id].in_pkt = NULL;
+ smd_remote_xprt[id].is_partial_in_pkt = 0;
+ INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
+ spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
+ smd_remote_xprt[id].ss_reset = 0;
- rc = smd_open("RPCRPY_CNTL", &smd_remote_xprt.channel, NULL,
- msm_ipc_router_smd_remote_notify);
+ rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
+ smd_xprt_cfg[id].edge,
+ &smd_remote_xprt[id].channel,
+ &smd_remote_xprt[id],
+ msm_ipc_router_smd_remote_notify);
if (rc < 0) {
- destroy_workqueue(smd_xprt_workqueue);
+ pr_err("%s: Channel open failed for %s\n",
+ __func__, smd_xprt_cfg[id].ch_name);
+ destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
return rc;
}
- smd_disable_read_intr(smd_remote_xprt.channel);
+ smd_disable_read_intr(smd_remote_xprt[id].channel);
smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
return 0;
}
-static struct platform_driver msm_ipc_router_smd_remote_driver = {
- .probe = msm_ipc_router_smd_remote_probe,
- .driver = {
- .name = "RPCRPY_CNTL",
- .owner = THIS_MODULE,
+static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
+ {
+ .probe = msm_ipc_router_smd_remote_probe,
+ .driver = {
+ .name = "RPCRPY_CNTL",
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .probe = msm_ipc_router_smd_remote_probe,
+ .driver = {
+ .name = "IPCRTR",
+ .owner = THIS_MODULE,
+ },
},
};
static int __init msm_ipc_router_smd_init(void)
{
- return platform_driver_register(&msm_ipc_router_smd_remote_driver);
+ int i, ret, rc = 0;
+ BUG_ON(ARRAY_SIZE(msm_ipc_router_smd_remote_driver) != NUM_SMD_XPRTS);
+ BUG_ON(ARRAY_SIZE(smd_xprt_cfg) != NUM_SMD_XPRTS);
+ for (i = 0; i < NUM_SMD_XPRTS; i++) {
+ ret = platform_driver_register(
+ &msm_ipc_router_smd_remote_driver[i]);
+ if (ret) {
+ pr_err("%s: Failed to register platform driver for"
+ " xprt%d. Continuing...\n", __func__, i);
+ rc = ret;
+ }
+ }
+ return rc;
}
module_init(msm_ipc_router_smd_init);
-MODULE_DESCRIPTION("RPC Router SMD XPRT");
+MODULE_DESCRIPTION("IPC Router SMD XPRT");
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index b75fb38..a2ec89b 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -33,6 +33,9 @@
#define CPMR_ETMCLKEN (0x8)
+uint32_t msm_jtag_save_cntr[NR_CPUS];
+uint32_t msm_jtag_restore_cntr[NR_CPUS];
+
struct dbg_ctx {
uint8_t arch;
bool arch_supported;
@@ -1015,6 +1018,10 @@
cpu = raw_smp_processor_id();
+ msm_jtag_save_cntr[cpu]++;
+ /* ensure counter is updated before moving forward */
+ mb();
+
if (dbg.arch_supported)
dbg_save_state(cpu);
if (etm.arch_supported)
@@ -1027,6 +1034,10 @@
cpu = raw_smp_processor_id();
+ msm_jtag_restore_cntr[cpu]++;
+ /* ensure counter is updated before moving forward */
+ mb();
+
if (dbg.arch_supported)
dbg_restore_state(cpu);
if (etm.arch_supported)
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 34bc415..7e538b4 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -48,7 +48,7 @@
static int mdm_debug_on;
static int first_power_on = 1;
-static int hsic_peripheral_status = 1;
+static int hsic_peripheral_status;
static DEFINE_MUTEX(hsic_status_lock);
static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index 6e79dfe..3f56d1a 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -54,6 +54,7 @@
int nentries;
int size;
int enabled;
+ int initialized;
uint32_t filter;
int step_size;
};
@@ -66,6 +67,7 @@
struct msm_rtb_state msm_rtb = {
.filter = 1 << LOGK_LOGBUF,
+ .enabled = 1,
};
module_param_named(filter, msm_rtb.filter, uint, 0644);
@@ -73,7 +75,7 @@
int msm_rtb_event_should_log(enum logk_event_type log_type)
{
- return msm_rtb.enabled &&
+ return msm_rtb.initialized && msm_rtb.enabled &&
((1 << log_type) & msm_rtb.filter);
}
EXPORT_SYMBOL(msm_rtb_event_should_log);
@@ -217,7 +219,7 @@
#endif
- msm_rtb.enabled = 1;
+ msm_rtb.initialized = 1;
return 0;
}
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 2b4dae1..26b97fa 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -43,14 +43,8 @@
#define GSS_CLAMP_ENA (MSM_CLK_CTL_BASE + 0x2C68)
#define GSS_CXO_SRC_CTL (MSM_CLK_CTL_BASE + 0x2C74)
-#define PLL5_MODE (MSM_CLK_CTL_BASE + 0x30E0)
-#define PLL5_L_VAL (MSM_CLK_CTL_BASE + 0x30E4)
-#define PLL5_M_VAL (MSM_CLK_CTL_BASE + 0x30E8)
-#define PLL5_N_VAL (MSM_CLK_CTL_BASE + 0x30EC)
-#define PLL5_CONFIG (MSM_CLK_CTL_BASE + 0x30F4)
#define PLL5_STATUS (MSM_CLK_CTL_BASE + 0x30F8)
#define PLL_ENA_GSS (MSM_CLK_CTL_BASE + 0x3480)
-#define PLL_ENA_RPM (MSM_CLK_CTL_BASE + 0x34A0)
#define PLL5_VOTE BIT(5)
#define PLL_STATUS BIT(16)
@@ -273,10 +267,18 @@
struct gss_data *drv = dev_get_drvdata(pil->dev);
int ret;
- ret = pas_shutdown(PAS_GSS);
- if (ret)
+ /*
+ * CXO is used in the secure shutdown code to configure the processor
+ * for low power mode.
+ */
+ ret = clk_prepare_enable(drv->xo);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable XO\n");
return ret;
+ }
+ ret = pas_shutdown(PAS_GSS);
+ clk_disable_unprepare(drv->xo);
remove_gss_proxy_votes_now(drv);
return ret;
@@ -322,63 +324,6 @@
.shutdown = pil_gss_shutdown_trusted,
};
-static void configure_gss_pll(struct gss_data *drv)
-{
- u32 regval, is_pll_enabled;
-
- /* Check if PLL5 is enabled by FSM. */
- is_pll_enabled = readl_relaxed(PLL5_STATUS) & PLL_STATUS;
- if (!is_pll_enabled) {
- /* Enable XO reference for PLL5 */
- clk_prepare_enable(drv->xo);
-
- /*
- * Assert a vote to hold PLL5 on in RPM register until other
- * voters are in place.
- */
- regval = readl_relaxed(PLL_ENA_RPM);
- regval |= PLL5_VOTE;
- writel_relaxed(regval, PLL_ENA_RPM);
-
- /* Ref clk = 27MHz and program pll5 to 288MHz */
- writel_relaxed(0xF, PLL5_L_VAL);
- writel_relaxed(0x0, PLL5_M_VAL);
- writel_relaxed(0x1, PLL5_N_VAL);
-
- regval = readl_relaxed(PLL5_CONFIG);
- /* Disable the MN accumulator and enable the main output. */
- regval &= ~BIT(22);
- regval |= BIT(23);
-
- /* Set pre-divider and post-divider values to 1 and 1 */
- regval &= ~BIT(19);
- regval &= ~(BIT(21)|BIT(20));
-
- /* Set VCO frequency */
- regval &= ~(BIT(17)|BIT(16));
- writel_relaxed(regval, PLL5_CONFIG);
-
- regval = readl_relaxed(PLL5_MODE);
- /* De-assert reset to FSM */
- regval &= ~BIT(21);
- writel_relaxed(regval, PLL5_MODE);
-
- /* Program bias count */
- regval &= ~(0x3F << 14);
- regval |= (0x1 << 14);
- writel_relaxed(regval, PLL5_MODE);
-
- /* Program lock count */
- regval &= ~(0x3F << 8);
- regval |= (0x8 << 8);
- writel_relaxed(regval, PLL5_MODE);
-
- /* Enable PLL FSM voting */
- regval |= BIT(20);
- writel_relaxed(regval, PLL5_MODE);
- }
-}
-
static int __devinit pil_gss_probe(struct platform_device *pdev)
{
struct gss_data *drv;
@@ -429,9 +374,6 @@
INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
- /* FIXME: Remove when PLL is configured by bootloaders. */
- configure_gss_pll(drv);
-
ret = msm_pil_register(desc);
if (ret) {
flush_delayed_work_sync(&drv->work);
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 534fc0e..8081b45 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -28,6 +28,8 @@
#include "pm.h"
#define MSM_CORE1_RESET 0xA8600590
+#define MSM_CORE1_STATUS_MSK 0x02800000
+
/*
* control for which core is the next to come out of the secondary
* boot "holding pen"
@@ -80,20 +82,53 @@
spin_unlock(&boot_lock);
}
+static int __cpuinit msm8625_release_secondary(void)
+{
+ void __iomem *base_ptr;
+ int value = 0;
+ unsigned long timeout;
+
+ /*
+ * loop to ensure that the GHS_STATUS_CORE1 bit in the
+ * MPA5_STATUS_REG(0x3c) is set. The timeout for the while
+ * loop can be set as 20us as of now
+ */
+ timeout = jiffies + usecs_to_jiffies(20);
+ while (time_before(jiffies, timeout)) {
+ value = __raw_readl(MSM_CFG_CTL_BASE + 0x3c);
+ if ((value & MSM_CORE1_STATUS_MSK) ==
+ MSM_CORE1_STATUS_MSK)
+ break;
+ udelay(1);
+ }
+
+ if (!value) {
+ pr_err("Core 1 cannot be brought out of Reset!!!\n");
+ return -ENODEV;
+ }
+
+ base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+ if (!base_ptr)
+ return -ENODEV;
+ /* Reset core 1 out of reset */
+ __raw_writel(0x0, base_ptr);
+ mb();
+
+ iounmap(base_ptr);
+
+ return 0;
+}
+
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
- void __iomem *base_ptr;
if (cold_boot_done == false) {
- base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
- if (!base_ptr)
+ if (msm8625_release_secondary()) {
+ pr_err("Failed to release secondary core\n");
return -ENODEV;
- /* Reset core 1 out of reset */
- __raw_writel(0x0, base_ptr);
- mb();
+ }
cold_boot_done = true;
- iounmap(base_ptr);
}
/*
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index b3c6d1e..ad235de 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -655,6 +655,10 @@
void *entry;
bool collapsed = 0;
int ret;
+ unsigned int saved_gic_cpu_ctrl;
+
+ saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+ mb();
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
pr_info("CPU%u: %s: notify_rpm %d\n",
@@ -686,7 +690,9 @@
#endif
cpu_init();
writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
- writel(1, MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+ writel_relaxed(saved_gic_cpu_ctrl,
+ MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+ mb();
local_fiq_enable();
}
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 81d4e5b..1f82468 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -14,24 +14,28 @@
#include <asm/pmu.h>
#include <mach/irqs.h>
-static struct resource cpu_pmu_resource = {
- .start = INT_ARMQC_PERFMON,
- .end = INT_ARMQC_PERFMON,
- .flags = IORESOURCE_IRQ,
+static struct resource cpu_pmu_resource[] = {
+ {
+ .start = INT_ARMQC_PERFMON,
+ .end = INT_ARMQC_PERFMON,
+ .flags = IORESOURCE_IRQ,
+ },
};
#ifdef CONFIG_CPU_HAS_L2_PMU
-static struct resource l2_pmu_resource = {
- .start = SC_SICL2PERFMONIRPTREQ,
- .end = SC_SICL2PERFMONIRPTREQ,
- .flags = IORESOURCE_IRQ,
+static struct resource l2_pmu_resource[] = {
+ {
+ .start = SC_SICL2PERFMONIRPTREQ,
+ .end = SC_SICL2PERFMONIRPTREQ,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct platform_device l2_pmu_device = {
.name = "l2-arm-pmu",
.id = ARM_PMU_DEVICE_L2,
- .resource = &l2_pmu_resource,
- .num_resources = 1,
+ .resource = l2_pmu_resource,
+ .num_resources = ARRAY_SIZE(l2_pmu_resource),
};
#endif
@@ -39,8 +43,8 @@
static struct platform_device cpu_pmu_device = {
.name = "cpu-arm-pmu",
.id = ARM_PMU_DEVICE_CPU,
- .resource = &cpu_pmu_resource,
- .num_resources = 1,
+ .resource = cpu_pmu_resource,
+ .num_resources = ARRAY_SIZE(cpu_pmu_resource),
};
static struct platform_device *pmu_devices[] = {
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 33c5a53..31a54b7 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -3,7 +3,7 @@
* Register/Interrupt access for userspace aDSP library.
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
* Author: Iliyan Malchev <ibm@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -58,8 +58,6 @@
#include <mach/msm_adsp.h>
#include "adsp.h"
-#define INT_ADSP INT_ADSP_A9_A11
-
static struct adsp_info adsp_info;
static struct msm_rpc_endpoint *rpc_cb_server_client;
static struct msm_adsp_module *adsp_modules;
@@ -280,6 +278,7 @@
int rc = 0;
static uint32_t init_info_cmd_sent;
+ mutex_lock(&adsp_info.lock);
if (!init_info_cmd_sent) {
init_waitqueue_head(&adsp_info.init_info_wait);
msm_get_init_info();
@@ -288,10 +287,13 @@
5 * HZ);
if (!rc) {
MM_ERR("INIT_INFO failed\n");
+ mutex_unlock(&adsp_info.lock);
return -ETIMEDOUT;
+
}
init_info_cmd_sent++;
}
+ mutex_unlock(&adsp_info.lock);
module = find_adsp_module_by_name(&adsp_info, name);
if (!module)
@@ -1016,16 +1018,49 @@
int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
{
+ if (!module)
+ return -EINVAL;
+
if (module->clk && clk_rate)
return clk_set_rate(module->clk, clk_rate);
return -EINVAL;
}
+int msm_adsp_generate_event(void *data,
+ struct msm_adsp_module *mod,
+ unsigned event_id,
+ unsigned event_length,
+ unsigned event_size,
+ void *msg)
+{
+ unsigned long flags;
+ void (*func)(void *, size_t);
+
+ if (!mod)
+ return -EINVAL;
+
+ if (event_size == sizeof(uint32_t))
+ func = read_event_32;
+ else if (event_size == sizeof(uint16_t))
+ func = read_event_16;
+ else
+ return -EINVAL;
+
+ spin_lock_irqsave(&adsp_cmd_lock, flags);
+ read_event_addr = msg;
+ mod->ops->event(data, event_id, event_length, func);
+ spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+ return 0;
+}
+
int msm_adsp_enable(struct msm_adsp_module *module)
{
int rc = 0;
+ if (!module)
+ return -EINVAL;
+
MM_INFO("enable '%s'state[%d] id[%d]\n",
module->name, module->state, module->id);
@@ -1053,7 +1088,7 @@
mutex_lock(&adsp_open_lock);
if (adsp_open_count++ == 0) {
- enable_irq(INT_ADSP);
+ enable_irq(adsp_info.int_adsp);
prevent_suspend();
}
mutex_unlock(&adsp_open_lock);
@@ -1078,6 +1113,9 @@
{
int rc = 0;
+ if (!module)
+ return -EINVAL;
+
mutex_lock(&module->lock);
rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
@@ -1092,6 +1130,9 @@
{
int rc = 0;
+ if (!module)
+ return -EINVAL;
+
switch (module->state) {
case ADSP_STATE_DISABLED:
MM_DBG("module '%s' already disabled\n", module->name);
@@ -1105,7 +1146,7 @@
clk_disable(module->clk);
mutex_lock(&adsp_open_lock);
if (--adsp_open_count == 0) {
- disable_irq(INT_ADSP);
+ disable_irq(adsp_info.int_adsp);
allow_suspend();
MM_DBG("disable interrupt\n");
}
@@ -1117,6 +1158,10 @@
int msm_adsp_disable(struct msm_adsp_module *module)
{
int rc;
+
+ if (!module)
+ return -EINVAL;
+
MM_INFO("disable '%s'\n", module->name);
mutex_lock(&module->lock);
rc = msm_adsp_disable_locked(module);
@@ -1130,8 +1175,11 @@
unsigned count;
int rc, i;
- if (pdev->id != (rpc_adsp_rtos_atom_vers & RPC_VERSION_MAJOR_MASK))
- return -EINVAL;
+ adsp_info.int_adsp = platform_get_irq(pdev, 0);
+ if (adsp_info.int_adsp < 0) {
+ MM_ERR("no irq resource?\n");
+ return -ENODEV;
+ }
wake_lock_init(&adsp_wake_lock, WAKE_LOCK_SUSPEND, "adsp");
adsp_info.init_info_ptr = kzalloc(
@@ -1157,12 +1205,13 @@
spin_lock_init(&adsp_cmd_lock);
spin_lock_init(&adsp_write_lock);
+ mutex_init(&adsp_info.lock);
- rc = request_irq(INT_ADSP, adsp_irq_handler, IRQF_TRIGGER_RISING,
- "adsp", 0);
+ rc = request_irq(adsp_info.int_adsp, adsp_irq_handler,
+ IRQF_TRIGGER_RISING, "adsp", 0);
if (rc < 0)
goto fail_request_irq;
- disable_irq(INT_ADSP);
+ disable_irq(adsp_info.int_adsp);
rpc_cb_server_client = msm_rpc_open();
if (IS_ERR(rpc_cb_server_client)) {
@@ -1214,8 +1263,8 @@
msm_rpc_close(rpc_cb_server_client);
rpc_cb_server_client = NULL;
fail_rpc_open:
- enable_irq(INT_ADSP);
- free_irq(INT_ADSP, 0);
+ enable_irq(adsp_info.int_adsp);
+ free_irq(adsp_info.int_adsp, 0);
fail_request_irq:
kfree(adsp_modules);
kfree(adsp_info.init_info_ptr);
@@ -1344,7 +1393,7 @@
},
};
-static char msm_adsp_driver_name[] = "rs00000000";
+static const char msm_adsp_driver_name[] = "msm_adsp";
#ifdef CONFIG_DEBUG_FS
static const struct file_operations adsp_debug_fops = {
@@ -1383,9 +1432,6 @@
rpc_adsp_rtos_mtoa_vers_comp = 0x00030001;
#endif
- snprintf(msm_adsp_driver_name, sizeof(msm_adsp_driver_name),
- "rs%08x",
- rpc_adsp_rtos_atom_prog);
msm_adsp_driver.driver.name = msm_adsp_driver_name;
rc = platform_driver_register(&msm_adsp_driver);
MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 0ef27b9..0f16111 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/qdsp5/adsp.h
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. All rights reserved.
* Author: Iliyan Malchev <ibm@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -117,6 +117,10 @@
struct adsp_rtos_mp_mtoa_init_info_type *init_info_ptr;
wait_queue_head_t init_info_wait;
unsigned init_info_state;
+ struct mutex lock;
+
+ /* Interrupt value */
+ int int_adsp;
};
#define RPC_ADSP_RTOS_ATOM_NULL_PROC 0
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 5e1e655..de756eb 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -298,6 +298,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -672,24 +673,31 @@
static void audio_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->reserved = 0;
audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
static void audio_flush_pcm_buf(struct audio *audio)
{
uint8_t index;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static int audaac_validate_usr_config(struct msm_audio_aac_config *config)
@@ -990,7 +998,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audio_disable(audio);
- audio->stopped = 1;
audio_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index c9e60d8..456a8ff 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -2,7 +2,7 @@
*
* aac audio input device
*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_aac_in.c,
* Copyright (C) 2008 Google, Inc.
@@ -320,9 +320,10 @@
audaac_in_dsp_enable(audio, 0);
- wake_up(&audio->wait);
wait_event_interruptible_timeout(audio->wait_enable,
audio->running == 0, 1*HZ);
+ audio->stopped = 1;
+ wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
msm_adsp_disable(audio->audpre);
@@ -697,21 +698,23 @@
* sleep and knowing that system is not able
* to process io request at the moment
*/
- wake_up(&audio->write_wait);
- mutex_lock(&audio->write_lock);
- audaac_in_flush(audio);
- mutex_unlock(&audio->write_lock);
wake_up(&audio->wait);
mutex_lock(&audio->read_lock);
- audaac_out_flush(audio);
+ audaac_in_flush(audio);
mutex_unlock(&audio->read_lock);
+ wake_up(&audio->write_wait);
+ mutex_lock(&audio->write_lock);
+ audaac_out_flush(audio);
+ mutex_unlock(&audio->write_lock);
}
static void audaac_in_flush(struct audio_aac_in *audio)
{
int i;
+ unsigned long flags;
audio->dsp_cnt = 0;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->in_head = 0;
audio->in_tail = 0;
audio->in_count = 0;
@@ -720,6 +723,7 @@
audio->in[i].size = 0;
audio->in[i].read = 0;
}
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
atomic_set(&audio->in_bytes, 0);
@@ -729,15 +733,18 @@
static void audaac_out_flush(struct audio_aac_in *audio)
{
int i;
+ unsigned long flags;
audio->out_head = 0;
- audio->out_tail = 0;
audio->out_count = 0;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ audio->out_tail = 0;
for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
audio->out[i].size = 0;
audio->out[i].read = 0;
audio->out[i].used = 0;
}
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
/* ------------------- device --------------------- */
@@ -777,7 +784,6 @@
}
case AUDIO_STOP: {
rc = audaac_in_disable(audio);
- audio->stopped = 1;
break;
}
case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 476a63d..d66a270 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -2,7 +2,7 @@
*
* amrnb audio decoder device
*
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
*
* Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
*
@@ -302,6 +302,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -628,24 +629,31 @@
static void audamrnb_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
static void audamrnb_flush_pcm_buf(struct audio *audio)
{
uint8_t index;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audamrnb_ioport_reset(struct audio *audio)
@@ -876,7 +884,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audamrnb_disable(audio);
- audio->stopped = 1;
audamrnb_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index e811731..b566c60 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -6,7 +6,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
*
* All source code in this file is licensed under the following license except
* where indicated.
@@ -299,6 +299,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -616,25 +617,32 @@
static void audamrwb_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->reserved = 0;
audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
static void audamrwb_flush_pcm_buf(struct audio *audio)
{
uint8_t index;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audamrwb_ioport_reset(struct audio *audio)
@@ -865,7 +873,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audamrwb_disable(audio);
- audio->stopped = 1;
audamrwb_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 3c39b6d..86035db 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -1,6 +1,6 @@
/* arch/arm/mach-msm/audio_evrc.c
*
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
*
* This code also borrows from audio_aac.c, which is
* Copyright (C) 2008 Google, Inc.
@@ -291,6 +291,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -615,24 +616,30 @@
static void audevrc_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
static void audevrc_flush_pcm_buf(struct audio *audio)
{
uint8_t index;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
-
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audevrc_ioport_reset(struct audio *audio)
@@ -863,7 +870,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audevrc_disable(audio);
- audio->stopped = 1;
audevrc_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 7a5536a..0bdbf5d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -2,7 +2,7 @@
*
* evrc audio input device
*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c,
* Copyright (C) 2008 Google, Inc.
@@ -281,6 +281,8 @@
wake_up(&audio->wait);
wait_event_interruptible_timeout(audio->wait_enable,
audio->running == 0, 1*HZ);
+ audio->stopped = 1;
+ wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
msm_adsp_disable(audio->audpre);
@@ -655,21 +657,23 @@
* sleep and knowing that system is not able
* to process io request at the moment
*/
- wake_up(&audio->write_wait);
- mutex_lock(&audio->write_lock);
- audevrc_in_flush(audio);
- mutex_unlock(&audio->write_lock);
wake_up(&audio->wait);
mutex_lock(&audio->read_lock);
- audevrc_out_flush(audio);
+ audevrc_in_flush(audio);
mutex_unlock(&audio->read_lock);
+ wake_up(&audio->write_wait);
+ mutex_lock(&audio->write_lock);
+ audevrc_out_flush(audio);
+ mutex_unlock(&audio->write_lock);
}
static void audevrc_in_flush(struct audio_evrc_in *audio)
{
int i;
+ unsigned long flags;
audio->dsp_cnt = 0;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->in_head = 0;
audio->in_tail = 0;
audio->in_count = 0;
@@ -678,6 +682,7 @@
audio->in[i].size = 0;
audio->in[i].read = 0;
}
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
atomic_set(&audio->in_bytes, 0);
@@ -687,15 +692,18 @@
static void audevrc_out_flush(struct audio_evrc_in *audio)
{
int i;
+ unsigned long flags;
audio->out_head = 0;
- audio->out_tail = 0;
audio->out_count = 0;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ audio->out_tail = 0;
for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
audio->out[i].size = 0;
audio->out[i].read = 0;
audio->out[i].used = 0;
}
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
/* ------------------- device --------------------- */
@@ -735,7 +743,6 @@
}
case AUDIO_STOP: {
rc = audevrc_in_disable(audio);
- audio->stopped = 1;
break;
}
case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index c4b464a..f6fa62a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -368,6 +368,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -853,12 +854,16 @@
static void audio_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->reserved = 0;
audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
@@ -885,13 +890,15 @@
static void audio_flush_pcm_buf(struct audio *audio)
{
uint8_t index;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
-
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audio_ioport_reset(struct audio *audio)
@@ -1366,7 +1373,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audio_disable(audio);
- audio->stopped = 1;
audio_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 9c27485..5ccd18b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -25,7 +25,7 @@
#define MVS_PROG 0x30000014
#define MVS_VERS 0x00030001
-#define MVS_VERS_COMP_VER2 0x00020001
+#define MVS_VERS_COMP_VER2 0x00060001
#define MVS_VERS_COMP_VER3 0x00030001
@@ -67,6 +67,8 @@
#define MVS_FRAME_MODE_G711_DL 10
#define MVS_FRAME_MODE_PCM_UL 13
#define MVS_FRAME_MODE_PCM_DL 14
+#define MVS_FRAME_MODE_PCM_WB_UL 23
+#define MVS_FRAME_MODE_PCM_WB_DL 24
#define MVS_FRAME_MODE_G729A_UL 17
#define MVS_FRAME_MODE_G729A_DL 18
#define MVS_FRAME_MODE_G711A_UL 19
@@ -404,6 +406,11 @@
audio->frame_mode = MVS_FRAME_MODE_PCM_DL;
break;
}
+ case MVS_MODE_PCM_WB: {
+ audio->rate_type = MVS_AMR_MODE_UNDEF;
+ audio->frame_mode = MVS_FRAME_MODE_PCM_WB_DL;
+ break;
+ }
case MVS_MODE_IS127:
case MVS_MODE_IS733:
case MVS_MODE_4GV_NB:
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 7c56037..7d33e05 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -247,6 +247,7 @@
audpp_disable(-1, audio);
+ audio->stopped = 1;
wake_up(&audio->wait);
audmgr_disable(&audio->audmgr);
audio->out_needed = 0;
@@ -519,7 +520,6 @@
break;
case AUDIO_STOP:
rc = audio_disable(audio);
- audio->stopped = 1;
break;
case AUDIO_FLUSH:
if (audio->stopped) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 02103fc..6468e93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -1,7 +1,7 @@
/* audio_pcm.c - pcm audio decoder driver
*
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* Based on the mp3 decoder driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
*
@@ -336,6 +336,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
msm_adsp_disable(audio->audplay);
audpp_disable(audio->dec_id, audio);
@@ -639,12 +640,16 @@
static void audio_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->reserved = 0;
audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
@@ -1041,7 +1046,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audio_disable(audio);
- audio->stopped = 1;
audio_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 81813a0..16c70ce 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -218,6 +218,7 @@
audpcm_in_dsp_enable(audio, 0);
+ audio->stopped = 1;
wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
@@ -613,7 +614,6 @@
}
case AUDIO_STOP:
rc = audpcm_in_disable(audio);
- audio->stopped = 1;
break;
case AUDIO_FLUSH:
if (audio->stopped) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index b12e713..2be5144 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -2,7 +2,7 @@
*
* qcelp 13k audio decoder device
*
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
*
* This code is based in part on audio_mp3.c, which is
* Copyright (C) 2008 Google, Inc.
@@ -288,6 +288,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -612,23 +613,30 @@
static void audqcelp_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audqcelp_flush_pcm_buf(struct audio *audio)
{
uint8_t index;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audqcelp_ioport_reset(struct audio *audio)
@@ -859,7 +867,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audqcelp_disable(audio);
- audio->stopped = 1;
audqcelp_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index a339825..a79f721 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -2,7 +2,7 @@
*
* qcelp audio input device
*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
* Copyright (C) 2008 Google, Inc.
@@ -279,9 +279,10 @@
audqcelp_in_dsp_enable(audio, 0);
- wake_up(&audio->wait);
wait_event_interruptible_timeout(audio->wait_enable,
audio->running == 0, 1*HZ);
+ audio->stopped = 1;
+ wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
msm_adsp_disable(audio->audpre);
@@ -657,29 +658,32 @@
* sleep and knowing that system is not able
* to process io request at the moment
*/
- wake_up(&audio->write_wait);
- mutex_lock(&audio->write_lock);
- audqcelp_in_flush(audio);
- mutex_unlock(&audio->write_lock);
wake_up(&audio->wait);
mutex_lock(&audio->read_lock);
- audqcelp_out_flush(audio);
+ audqcelp_in_flush(audio);
mutex_unlock(&audio->read_lock);
+ wake_up(&audio->write_wait);
+ mutex_lock(&audio->write_lock);
+ audqcelp_out_flush(audio);
+ mutex_unlock(&audio->write_lock);
}
static void audqcelp_in_flush(struct audio_qcelp_in *audio)
{
int i;
+ unsigned long flags;
+ audio->eos_ack = 0;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->dsp_cnt = 0;
audio->in_head = 0;
audio->in_tail = 0;
audio->in_count = 0;
- audio->eos_ack = 0;
for (i = FRAME_NUM-1; i >= 0; i--) {
audio->in[i].size = 0;
audio->in[i].read = 0;
}
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
atomic_set(&audio->in_bytes, 0);
@@ -689,15 +693,18 @@
static void audqcelp_out_flush(struct audio_qcelp_in *audio)
{
int i;
+ unsigned long flags;
audio->out_head = 0;
- audio->out_tail = 0;
audio->out_count = 0;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ audio->out_tail = 0;
for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
audio->out[i].size = 0;
audio->out[i].read = 0;
audio->out[i].used = 0;
}
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
/* ------------------- device --------------------- */
@@ -737,7 +744,6 @@
}
case AUDIO_STOP: {
rc = audqcelp_in_disable(audio);
- audio->stopped = 1;
break;
}
case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index b7e8e1c..7a962b2 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -266,7 +266,9 @@
audio->in[index].used = 0;
audio->read_next = 0;
+ mutex_lock(&audio->dsp_lock);
audio->fill_next = 0;
+ mutex_unlock(&audio->dsp_lock);
}
static void audvoicememo_ioport_reset(struct audio_voicememo *audio)
@@ -387,6 +389,7 @@
rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
wait_event_timeout(audio->wait, audio->stopped == 0,
1 * HZ);
+ audio->stopped = 1;
wake_up(&audio->read_wait);
audmgr_disable(&audio->audmgr);
audio->enabled = 0;
@@ -536,12 +539,14 @@
callback time\n");
else if (rec_status == RPC_VOC_REC_STAT_AUTO_STOP) {
MM_DBG(" Voice Record AUTO STOP\n");
+ mutex_lock(&audio->lock);
+ audio->stopped = 1;
wake_up(&audio->read_wait);
audmgr_disable(&audio->audmgr);
- audio->stopped = 1;
audvoicememo_ioport_reset(audio);
audio->stopped = 0;
audio->enabled = 0;
+ mutex_unlock(&audio->lock);
}
break;
}
@@ -648,7 +653,6 @@
case AUDIO_STOP: {
MM_DBG("AUDIO_STOP\n");
rc = audvoicememo_disable(audio);
- audio->stopped = 1;
audvoicememo_ioport_reset(audio);
audio->stopped = 0;
MM_DBG("AUDIO_STOP rc %d\n", rc);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index cf2ade4..674ee4f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -1,6 +1,6 @@
/* audio_wma.c - wma audio decoder driver
*
- * Copyright (c) 2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012, Code Aurora Forum. All rights reserved.
*
* Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
*
@@ -306,6 +306,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -659,11 +660,15 @@
static void audio_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->reserved = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
@@ -671,11 +676,15 @@
{
uint8_t index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audio_ioport_reset(struct audio *audio)
@@ -905,7 +914,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audio_disable(audio);
- audio->stopped = 1;
audio_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index d9b384a..c2a0b93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* All source code in this file is licensed under the following license except
* where indicated.
@@ -301,6 +301,7 @@
rc = -EFAULT;
else
rc = 0;
+ audio->stopped = 1;
wake_up(&audio->write_wait);
wake_up(&audio->read_wait);
msm_adsp_disable(audio->audplay);
@@ -648,23 +649,30 @@
static void audio_flush(struct audio *audio)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
audio->out[0].used = 0;
audio->out[1].used = 0;
audio->out_head = 0;
audio->out_tail = 0;
audio->reserved = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
atomic_set(&audio->out_bytes, 0);
}
static void audio_flush_pcm_buf(struct audio *audio)
{
uint8_t index;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
audio->in[index].used = 0;
audio->buf_refresh = 0;
audio->read_next = 0;
audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audio_ioport_reset(struct audio *audio)
@@ -894,7 +902,6 @@
case AUDIO_STOP:
MM_DBG("AUDIO_STOP\n");
rc = audio_disable(audio);
- audio->stopped = 1;
audio_ioport_reset(audio);
audio->stopped = 0;
break;
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index 3e834d8..2dbb5dc0 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -4,7 +4,7 @@
* common code to deal with the AUDPP dsp task (audio postproc)
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, 2012 Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -124,6 +124,8 @@
uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
+ spinlock_t avsync_lock;
+
wait_queue_head_t event_wait;
};
@@ -237,13 +239,24 @@
}
}
+static void audpp_fake_event(struct audpp_state *audpp, int id,
+ unsigned event, unsigned arg)
+{
+ uint16_t msg[1];
+ msg[0] = arg;
+ audpp->func[id] (audpp->private[id], event, msg);
+}
+
static void audpp_dsp_event(void *data, unsigned id, size_t len,
void (*getevent) (void *ptr, size_t len))
{
struct audpp_state *audpp = data;
+ unsigned long flags;
uint16_t msg[8];
+ int cid = 0;
if (id == AUDPP_MSG_AVSYNC_MSG) {
+ spin_lock_irqsave(&audpp->avsync_lock, flags);
getevent(audpp->avsync, sizeof(audpp->avsync));
/* mask off any channels we're not watching to avoid
@@ -252,6 +265,7 @@
* we next read...
*/
audpp->avsync[0] &= audpp->avsync_mask;
+ spin_unlock_irqrestore(&audpp->avsync_lock, flags);
return;
}
@@ -278,13 +292,28 @@
case AUDPP_MSG_CFG_MSG:
if (msg[0] == AUDPP_MSG_ENA_ENA) {
MM_INFO("ENABLE\n");
- audpp->enabled = 1;
- audpp_broadcast(audpp, id, msg);
+ if (!audpp->enabled) {
+ audpp->enabled = 1;
+ audpp_broadcast(audpp, id, msg);
+ } else {
+ cid = msg[1];
+ audpp_fake_event(audpp, cid,
+ id, AUDPP_MSG_ENA_ENA);
+ }
+
} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
- MM_INFO("DISABLE\n");
- audpp->enabled = 0;
- wake_up(&audpp->event_wait);
- audpp_broadcast(audpp, id, msg);
+ if (audpp->open_count == 0) {
+ MM_INFO("DISABLE\n");
+ audpp->enabled = 0;
+ wake_up(&audpp->event_wait);
+ audpp_broadcast(audpp, id, msg);
+ } else {
+ cid = msg[1];
+ audpp_fake_event(audpp, cid,
+ id, AUDPP_MSG_ENA_DIS);
+ audpp->func[cid] = NULL;
+ audpp->private[cid] = NULL;
+ }
} else {
MM_ERR("invalid config msg %d\n", msg[0]);
}
@@ -307,17 +336,10 @@
.event = audpp_dsp_event,
};
-static void audpp_fake_event(struct audpp_state *audpp, int id,
- unsigned event, unsigned arg)
-{
- uint16_t msg[1];
- msg[0] = arg;
- audpp->func[id] (audpp->private[id], event, msg);
-}
-
int audpp_enable(int id, audpp_event_func func, void *private)
{
struct audpp_state *audpp = &the_audpp_state;
+ uint16_t msg[8];
int res = 0;
if (id < -1 || id > 4)
@@ -350,12 +372,15 @@
msm_adsp_enable(audpp->mod);
audpp_dsp_config(1);
} else {
- unsigned long flags;
- local_irq_save(flags);
- if (audpp->enabled)
- audpp_fake_event(audpp, id,
- AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
- local_irq_restore(flags);
+ if (audpp->enabled) {
+ msg[0] = AUDPP_MSG_ENA_ENA;
+ msg[1] = id;
+ res = msm_adsp_generate_event(audpp, audpp->mod,
+ AUDPP_MSG_CFG_MSG, sizeof(msg),
+ sizeof(uint16_t), (void *)msg);
+ if (res < 0)
+ goto out;
+ }
}
res = 0;
@@ -368,7 +393,7 @@
void audpp_disable(int id, void *private)
{
struct audpp_state *audpp = &the_audpp_state;
- unsigned long flags;
+ uint16_t msg[8];
int rc;
if (id < -1 || id > 4)
@@ -384,11 +409,13 @@
if (audpp->private[id] != private)
goto out;
- local_irq_save(flags);
- audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
- audpp->func[id] = NULL;
- audpp->private[id] = NULL;
- local_irq_restore(flags);
+ msg[0] = AUDPP_MSG_ENA_DIS;
+ msg[1] = id;
+ rc = msm_adsp_generate_event(audpp, audpp->mod,
+ AUDPP_MSG_CFG_MSG, sizeof(msg),
+ sizeof(uint16_t), (void *)msg);
+ if (rc < 0)
+ goto out;
if (--audpp->open_count == 0) {
MM_DBG("disable\n");
@@ -420,13 +447,13 @@
if (BAD_ID(id))
return;
- local_irq_save(flags);
+ spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
if (rate)
the_audpp_state.avsync_mask |= (1 << id);
else
the_audpp_state.avsync_mask &= (~(1 << id));
the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
cmd.cmd_id = AUDPP_CMD_AVSYNC;
cmd.object_number = id;
@@ -438,7 +465,8 @@
unsigned audpp_avsync_sample_count(int id)
{
- uint16_t *avsync = the_audpp_state.avsync;
+ struct audpp_state *audpp = &the_audpp_state;
+ uint16_t *avsync = audpp->avsync;
unsigned val;
unsigned long flags;
unsigned mask;
@@ -448,12 +476,12 @@
mask = 1 << id;
id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
- local_irq_save(flags);
+ spin_lock_irqsave(&audpp->avsync_lock, flags);
if (avsync[0] & mask)
val = (avsync[id] << 16) | avsync[id + 1];
else
val = 0;
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&audpp->avsync_lock, flags);
return val;
}
@@ -461,7 +489,8 @@
unsigned audpp_avsync_byte_count(int id)
{
- uint16_t *avsync = the_audpp_state.avsync;
+ struct audpp_state *audpp = &the_audpp_state;
+ uint16_t *avsync = audpp->avsync;
unsigned val;
unsigned long flags;
unsigned mask;
@@ -471,12 +500,12 @@
mask = 1 << id;
id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
- local_irq_save(flags);
+ spin_lock_irqsave(&audpp->avsync_lock, flags);
if (avsync[0] & mask)
val = (avsync[id] << 16) | avsync[id + 1];
else
val = 0;
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&audpp->avsync_lock, flags);
return val;
}
@@ -826,6 +855,8 @@
init_waitqueue_head(&audpp->event_wait);
+ spin_lock_init(&audpp->avsync_lock);
+
for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
audpp->dec_info_table[idx].codec = -1;
audpp->dec_info_table[idx].pid = 0;
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 747b585..e0d0dd8 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -190,10 +190,7 @@
static int __init scm_pas_init(void)
{
- /* TODO: Remove once bus scaling driver is in place */
- if (!cpu_is_apq8064())
- scm_perf_client = msm_bus_scale_register_client(
- &scm_pas_bus_pdata);
+ scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
if (!scm_perf_client)
pr_warn("unable to register bus client\n");
scm_bus_clk = clk_get_sys("scm", "bus_clk");
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index a1bf280..9b10ffd 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -604,7 +604,7 @@
arch_initcall(socinfo_init_sysdev);
-void *setup_dummy_socinfo(void)
+static void * __init setup_dummy_socinfo(void)
{
if (machine_is_msm8960_rumi3() || machine_is_msm8960_sim() ||
machine_is_msm8960_cdp())
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 4128e3a..0bc080c 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -66,6 +66,7 @@
DGT_CLK_CTL_DIV_3 = 2,
DGT_CLK_CTL_DIV_4 = 3,
};
+#define TIMER_STATUS 0x0088
#define TIMER_ENABLE_EN 1
#define TIMER_ENABLE_CLR_ON_MATCH_EN 2
@@ -112,6 +113,7 @@
uint32_t index;
void __iomem *global_counter;
void __iomem *local_counter;
+ uint32_t status_mask;
union {
struct clock_event_device *evt;
struct clock_event_device __percpu **percpu_evt;
@@ -1001,15 +1003,21 @@
dgt->regbase = MSM_TMR_BASE + 0x10;
} else if (cpu_is_fsm9xxx())
dgt->freq = 4800000;
- else if (cpu_is_msm7x30() || cpu_is_msm8x55())
+ else if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+ gpt->status_mask = BIT(10);
+ dgt->status_mask = BIT(2);
dgt->freq = 6144000;
- else if (cpu_is_msm8x60()) {
+ } else if (cpu_is_msm8x60()) {
global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+ gpt->status_mask = BIT(10);
+ dgt->status_mask = BIT(2);
dgt->freq = 6750000;
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
} else if (cpu_is_msm9615()) {
dgt->freq = 6750000;
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+ gpt->status_mask = BIT(10);
+ dgt->status_mask = BIT(2);
gpt->freq = 32765;
gpt_hz = 32765;
sclk_hz = 32765;
@@ -1019,6 +1027,8 @@
global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
dgt->freq = 6750000;
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+ gpt->status_mask = BIT(10);
+ dgt->status_mask = BIT(2);
gpt->freq = 32765;
gpt_hz = 32765;
sclk_hz = 32765;
@@ -1042,8 +1052,7 @@
struct clock_event_device *ce = &clock->clockevent;
struct clocksource *cs = &clock->clocksource;
__raw_writel(0, clock->regbase + TIMER_ENABLE);
- __raw_writel(1, clock->regbase + TIMER_CLEAR);
- __raw_writel(0, clock->regbase + TIMER_COUNT_VAL);
+ __raw_writel(0, clock->regbase + TIMER_CLEAR);
__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
if ((clock->freq << clock->shift) == gpt_hz) {
@@ -1105,6 +1114,11 @@
if (chip && chip->irq_mask)
chip->irq_mask(irq_get_irq_data(clock->irq));
+ if (clock->status_mask)
+ while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+ clock->status_mask)
+ ;
+
clockevents_register_device(ce);
}
msm_sched_clock_init();
@@ -1136,6 +1150,10 @@
__raw_writel(0, clock->regbase + TIMER_CLEAR);
__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
__get_cpu_var(first_boot) = false;
+ if (clock->status_mask)
+ while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+ clock->status_mask)
+ ;
}
evt->irq = clock->irq;
evt->name = "local_timer";
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 14536f6..946899d 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -17,6 +17,8 @@
#include <asm/thread_notify.h>
#include <asm/tlbflush.h>
+#include <mach/msm_rtb.h>
+
static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
unsigned int cpu_last_asid = ASID_FIRST_VERSION;
#ifdef CONFIG_SMP
@@ -25,6 +27,7 @@
static void write_contextidr(u32 contextidr)
{
+ uncached_logk(LOGK_CTXID, (void *)contextidr);
asm("mcr p15, 0, %0, c13, c0, 1" : : "r" (contextidr));
isb();
}
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 8dcce03..321abe8 100755
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1139,3 +1139,4 @@
mpq8064_hrd MACH_MPQ8064_HRD MPQ8064_HRD 3994
mpq8064_dtv MACH_MPQ8064_DTV MPQ8064_DTV 3995
msm7627a_qrd3 MACH_MSM7627A_QRD3 MSM7627A_QRD3 4005
+msm8625_surf MACH_MSM8625_SURF MSM8625_SURF 4037
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7d28604..371d319 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -52,8 +52,8 @@
#define MAX_EQUIP_ID 12
/* Maximum number of pkt reg supported at initialization*/
-extern unsigned int diag_max_registration;
-extern unsigned int diag_threshold_registration;
+extern unsigned int diag_max_reg;
+extern unsigned int diag_threshold_reg;
#define APPEND_DEBUG(ch) \
do { \
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index e24d896..efba92b 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -60,8 +60,8 @@
static unsigned int max_clients = 15;
static unsigned int threshold_client_limit = 30;
/* This is the maximum number of pkt registrations supported at initialization*/
-unsigned int diag_max_registration = 600;
-unsigned int diag_threshold_registration = 750;
+unsigned int diag_max_reg = 600;
+unsigned int diag_threshold_reg = 750;
/* Timer variables */
static struct timer_list drain_timer;
@@ -230,7 +230,7 @@
}
#endif /* DIAG over USB */
/* Delete the pkt response table entry for the exiting process */
- for (i = 0; i < diag_max_registration; i++)
+ for (i = 0; i < diag_max_reg; i++)
if (driver->table[i].process_id == current->tgid)
driver->table[i].process_id = 0;
@@ -286,13 +286,13 @@
mutex_lock(&driver->diagchar_mutex);
/* reset polling flag */
driver->polling_reg_flag = 0;
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
if (driver->table[i].client_id == proc_num) {
driver->table[i].process_id = 0;
}
}
/* re-scan the registration table */
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
if (diag_find_polling_reg(i) == 1) {
driver->polling_reg_flag = 1;
break;
@@ -335,7 +335,7 @@
struct bindpkt_params_per_process *pkt_params =
(struct bindpkt_params_per_process *) ioarg;
mutex_lock(&driver->diagchar_mutex);
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
if (driver->table[i].process_id == 0) {
diag_add_reg(i, pkt_params->params,
&success, &count_entries);
@@ -347,19 +347,20 @@
}
}
}
- if (i < diag_threshold_registration) {
+ if (i < diag_threshold_reg) {
/* Increase table size by amount required */
- diag_max_registration += pkt_params->count -
+ diag_max_reg += pkt_params->count -
count_entries;
/* Make sure size doesnt go beyond threshold */
- if (diag_max_registration > diag_threshold_registration)
- diag_max_registration =
- diag_threshold_registration;
+ if (diag_max_reg > diag_threshold_reg) {
+ diag_max_reg = diag_threshold_reg;
+ pr_info("diag: best case memory allocation\n");
+ }
temp_buf = krealloc(driver->table,
- diag_max_registration*sizeof(struct
+ diag_max_reg*sizeof(struct
diag_master_table), GFP_KERNEL);
if (!temp_buf) {
- diag_max_registration -= pkt_params->count -
+ diag_max_reg -= pkt_params->count -
count_entries;
pr_alert("diag: Insufficient memory for reg.");
mutex_unlock(&driver->diagchar_mutex);
@@ -367,7 +368,7 @@
} else {
driver->table = temp_buf;
}
- for (j = i; j < diag_max_registration; j++) {
+ for (j = i; j < diag_max_reg; j++) {
diag_add_reg(j, pkt_params->params,
&success, &count_entries);
if (pkt_params->count > count_entries) {
@@ -377,6 +378,7 @@
return success;
}
}
+ mutex_unlock(&driver->diagchar_mutex);
} else {
mutex_unlock(&driver->diagchar_mutex);
pr_err("Max size reached, Pkt Registration failed for"
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 079e04b..7f26856 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -598,7 +598,7 @@
}
pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
entry = driver->table[i];
if (entry.process_id != NO_PROCESS) {
if (entry.cmd_code == cmd_code && entry.subsys_id ==
@@ -1374,7 +1374,7 @@
, GFP_KERNEL)) == NULL)
goto err;
if (driver->table == NULL &&
- (driver->table = kzalloc(diag_max_registration*
+ (driver->table = kzalloc(diag_max_reg*
sizeof(struct diag_master_table),
GFP_KERNEL)) == NULL)
goto err;
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index f5367ef..d1a9fe6 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -122,19 +122,19 @@
"failed to enable clock in probe\n");
return -EPERM;
}
- val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET) &
- PRNG_LFSR_CFG_MASK;
- val |= PRNG_LFSR_CFG_MASK;
- writel_relaxed(val, msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
-
- /* The PRNG CONFIG register should be first written before reading */
- mb();
-
/* Enable PRNG h/w only if it is NOT ON */
val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET) &
PRNG_HW_ENABLE;
/* PRNG H/W is not ON */
if (val != PRNG_HW_ENABLE) {
+ val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET) &
+ PRNG_LFSR_CFG_MASK;
+ val |= PRNG_LFSR_CFG_MASK;
+ writel_relaxed(val, msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
+
+ /* The PRNG CONFIG register should be first written */
+ mb();
+
reg_val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET)
& PRNG_CONFIG_MASK;
reg_val |= PRNG_HW_ENABLE;
@@ -242,9 +242,6 @@
static int __init msm_rng_init(void)
{
- if (cpu_is_apq8064())
- return -ENODEV;
-
return platform_driver_register(&rng_driver);
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index ad0c7b1..347ab88 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -206,16 +206,13 @@
if (ion_carveout_request_region(carveout_heap))
return -EINVAL;
- if (ION_IS_CACHED(flags))
- ret_value = remap_pfn_range(vma, vma->vm_start,
- __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
- else
- ret_value = remap_pfn_range(vma, vma->vm_start,
- __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- pgprot_noncached(vma->vm_page_prot));
+ if (!ION_IS_CACHED(flags))
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ ret_value = remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
if (ret_value)
ion_carveout_release_region(carveout_heap);
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index a6b0cf6..ff561dc 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -450,18 +450,14 @@
return -EINVAL;
}
- if (ION_IS_CACHED(flags))
- ret_value = remap_pfn_range(vma, vma->vm_start,
- __phys_to_pfn(buffer->priv_phys) +
- vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
- else
- ret_value = remap_pfn_range(vma, vma->vm_start,
- __phys_to_pfn(buffer->priv_phys) +
- vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- pgprot_noncached(vma->vm_page_prot));
+ if (!ION_IS_CACHED(flags))
+ vma->vm_page_prot = pgprot_writecombine(
+ vma->vm_page_prot);
+
+ ret_value = remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
if (ret_value)
ion_cp_release_region(cp_heap);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index d37a811..2f9e80c 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -136,7 +136,7 @@
return -EINVAL;
if (!ION_IS_CACHED(flags))
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
for (i = 0; i < data->nrpages; i++)
if (vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 1806886..7e684c0 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -229,6 +229,19 @@
#define A3XX_VBIF_FIXED_SORT_EN 0x300C
#define A3XX_VBIF_FIXED_SORT_SEL0 0x300D
#define A3XX_VBIF_FIXED_SORT_SEL1 0x300E
+#define A3XX_VBIF_ABIT_SORT 0x301C
+#define A3XX_VBIF_ABIT_SORT_CONF 0x301D
+#define A3XX_VBIF_GATE_OFF_WRREQ_EN 0x302A
+#define A3XX_VBIF_IN_RD_LIM_CONF0 0x302C
+#define A3XX_VBIF_IN_RD_LIM_CONF1 0x302D
+#define A3XX_VBIF_IN_WR_LIM_CONF0 0x3030
+#define A3XX_VBIF_IN_WR_LIM_CONF1 0x3031
+#define A3XX_VBIF_OUT_RD_LIM_CONF0 0x3034
+#define A3XX_VBIF_OUT_WR_LIM_CONF0 0x3035
+#define A3XX_VBIF_DDR_OUT_MAX_BURST 0x3036
+#define A3XX_VBIF_ARB_CTL 0x303C
+#define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
+#define A3XX_VBIF_OUT_AXI_AOOO 0x305F
/* Bit flags for RBBM_CTL */
#define RBBM_RBBM_CTL_RESET_PWR_CTR1 (1 << 1)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 79a0e0b..73d00b3 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -581,6 +581,7 @@
device->ftbl->irqctrl(device, 0);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+ del_timer_sync(&device->idle_timer);
/* Power down the device */
kgsl_pwrctrl_disable(device);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index f68bc41..24e8efe 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -59,7 +59,9 @@
0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
- 0x2750, 0x2756, 0x2760, 0x2760,
+ 0x2750, 0x2756, 0x2760, 0x2760, 0x300C, 0x300E, 0x301C, 0x301D,
+ 0x302A, 0x302A, 0x302C, 0x302D, 0x3030, 0x3031, 0x3034, 0x3036,
+ 0x303C, 0x303C, 0x305E, 0x305F,
};
const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
@@ -130,7 +132,7 @@
/* Use shadow RAM */
#define HLSQ_SHADOW_BASE (0x10000+SSIZE*2)
-#define REG_TO_MEM_LOOP_COUNT_SHIFT 15
+#define REG_TO_MEM_LOOP_COUNT_SHIFT 18
#define BUILD_PC_DRAW_INITIATOR(prim_type, source_select, index_size, \
vis_cull_mode) \
@@ -1109,11 +1111,13 @@
/* Constant save */
cmd = rmw_regtomem(cmd, A3XX_SP_VS_CTRL_REG1, 0x000003ff,
- 17, (HLSQ_SHADOW_BASE + 0x2000) / 4,
+ 2 + REG_TO_MEM_LOOP_COUNT_SHIFT,
+ (HLSQ_SHADOW_BASE + 0x2000) / 4,
drawctxt->constant_save_commands[1].gpuaddr);
cmd = rmw_regtomem(cmd, A3XX_SP_FS_CTRL_REG1, 0x000003ff,
- 17, (HLSQ_SHADOW_BASE + 0x2000 + SSIZE) / 4,
+ 2 + REG_TO_MEM_LOOP_COUNT_SHIFT,
+ (HLSQ_SHADOW_BASE + 0x2000 + SSIZE) / 4,
drawctxt->constant_save_commands[2].gpuaddr);
cmd = rmw_regtomem(cmd, A3XX_SP_FS_OBJ_OFFSET_REG, 0x00ff0000,
@@ -2546,14 +2550,29 @@
0x00000001);
msleep(20);
- /*
- * enable fixed master AXI port of 0x0 for all clients to keep
- * traffic from going to random places
- */
+ /* Set up 16 deep read/write request queues */
- adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_EN, 0x0001003F);
- adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_SEL0, 0x00000000);
- adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_SEL1, 0x00000000);
+ adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
+ adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
+ adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
+ adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
+ adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000303);
+ adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
+ adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
+
+ /* Enable WR-REQ */
+ adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x000000FF);
+
+ /* Set up round robin arbitration between both AXI ports */
+ adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
+
+ /* Set up AOOO */
+ adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
+ adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+
+ /* Enable 1K sort */
+ adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x000000FF);
+ adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
/* Make all blocks contribute to the GPU BUSY perf counter */
adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index 1dffc32..f99462e 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -163,6 +163,13 @@
#define CP_LOAD_STATE 0x30 /* load high level sequencer command */
+/* Conditionally load a IB based on a flag */
+#define CP_COND_INDIRECT_BUFFER_PFE 0x3A /* prefetch enabled */
+#define CP_COND_INDIRECT_BUFFER_PFD 0x32 /* prefetch disabled */
+
+/* Load a buffer with pre-fetch enabled */
+#define CP_INDIRECT_BUFFER_PFE 0x3F
+
#define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
#define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
#define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 98e3810..7902f30 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -876,6 +876,7 @@
int adreno_postmortem_dump(struct kgsl_device *device, int manual)
{
+ bool saved_nap;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
BUG_ON(device == NULL);
@@ -907,17 +908,28 @@
KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
kgsl_get_clkrate(pwr->ebi1_clk));
- /*
- * Disable the irq, idle timer, and workqueue so we don't
- * get interrupted
- */
- kgsl_pwrctrl_stop_work(device);
+ /* Disable the idle timer so we don't get interrupted */
+ del_timer_sync(&device->idle_timer);
+ mutex_unlock(&device->mutex);
+ flush_workqueue(device->work_queue);
+ mutex_lock(&device->mutex);
+
+ /* Turn off napping to make sure we have the clocks full
+ attention through the following process */
+ saved_nap = device->pwrctrl.nap_allowed;
+ device->pwrctrl.nap_allowed = false;
/* Force on the clocks */
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+ kgsl_pwrctrl_wake(device);
+
+ /* Disable the irq */
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
adreno_dump(device);
+ /* Restore nap mode */
+ device->pwrctrl.nap_allowed = saved_nap;
+
/* On a manual trigger, turn on the interrupts and put
the clocks to sleep. They will recover themselves
on the next event. For a hang, leave things as they
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index cc3f3e7..a4899a2 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -45,11 +45,19 @@
int index;
void *ptr;
- /* Go through the list and see that object has already been seen */
+ /*
+ * Sometimes IBs can be reused in the same dump. Because we parse from
+ * oldest to newest, if we come across an IB that has already been used,
+ * assume that it has been reused and update the list with the newest
+ * size.
+ */
+
for (index = 0; index < objbufptr; index++) {
if (objbuf[index].gpuaddr == gpuaddr &&
- objbuf[index].ptbase == ptbase)
- return;
+ objbuf[index].ptbase == ptbase) {
+ objbuf[index].dwords = dwords;
+ return;
+ }
}
if (objbufptr == SNAPSHOT_OBJ_BUFSIZE) {
@@ -77,6 +85,34 @@
objbuf[objbufptr++].ptr = ptr;
}
+/*
+ * Return a 1 if the specified object is already on the list of buffers
+ * to be dumped
+ */
+
+static int find_object(int type, unsigned int gpuaddr, unsigned int ptbase)
+{
+ int index;
+
+ for (index = 0; index < objbufptr; index++) {
+ if (objbuf[index].gpuaddr == gpuaddr &&
+ objbuf[index].ptbase == ptbase &&
+ objbuf[index].type == type)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return 1 if the packet starting at ptr is an indirect buffer of any kind */
+static inline int packet_is_buffer(unsigned int *ptr)
+{
+ return (*ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2) ||
+ *ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2) ||
+ *ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFE, 2) ||
+ *ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFD, 2));
+}
+
/* Snapshot the istore memory */
static int snapshot_istore(struct kgsl_device *device, void *snapshot,
int remain, void *priv)
@@ -113,6 +149,7 @@
unsigned int rbbase, ptbase, rptr, *rbptr;
int start, stop, index;
int numitems, size;
+ int parse_ibs = 0, ib_parse_start;
/* Get the GPU address of the ringbuffer */
kgsl_regread(device, REG_CP_RB_BASE, &rbbase);
@@ -158,9 +195,53 @@
header->rbsize = rb->sizedwords;
header->count = numitems;
- index = start;
+ /*
+ * We can only reliably dump IBs from the beginning of the context,
+ * and it turns out that for the vast majority of the time we really
+ * only care about the current context when it comes to diagnosing
+ * a hang. So, with an eye to limiting the buffer dumping to what is
+ * really useful find the beginning of the context and only dump
+ * IBs from that point
+ */
+
+ index = rptr;
+ ib_parse_start = start;
rbptr = rb->buffer_desc.hostptr;
+ while (index != start) {
+ index--;
+
+ if (index < 0) {
+ /*
+ * The marker we are looking for is 2 dwords long, so
+ * when wrapping, go back 2 from the end so we don't
+ * access out of range in the if statement below
+ */
+ index = rb->sizedwords - 2;
+
+ /*
+ * Account for the possibility that start might be at
+ * rb->sizedwords - 1
+ */
+
+ if (start == rb->sizedwords - 1)
+ break;
+ }
+
+ /*
+ * Look for a NOP packet with the context switch identifier in
+ * the second dword
+ */
+
+ if (rbptr[index] == cp_nop_packet(1) &&
+ rbptr[index + 1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+ ib_parse_start = index;
+ break;
+ }
+ }
+
+ index = start;
+
/*
* Loop through the RB, copying the data and looking for indirect
* buffers and MMU pagetable changes
@@ -169,15 +250,18 @@
while (index != rb->wptr) {
*data = rbptr[index];
- if (rbptr[index] == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2))
+ /* Only parse IBs between the context start and the rptr */
+
+ if (index == ib_parse_start)
+ parse_ibs = 1;
+
+ if (index == rptr)
+ parse_ibs = 0;
+
+ if (parse_ibs && packet_is_buffer(&rbptr[index]))
push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
rbptr[index + 1], rbptr[index + 2]);
- /*
- * FIXME: Handle upcoming MMU pagetable changes, but only
- * between the rptr and the wptr
- */
-
index = index + 1;
if (index == rb->sizedwords)
@@ -228,10 +312,9 @@
*dst = *src;
/* If another IB is discovered, then push it on the list too */
- if (*src == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+ if (packet_is_buffer(src))
push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
*(src + 1), *(src + 2));
- }
src++;
dst++;
@@ -288,22 +371,45 @@
snapshot, remain, snapshot_rb, NULL);
/*
- * Make sure that the IBs described in the CP registers are on the
- * list of objects
+ * Make sure that the last IB1 that was being executed is dumped.
+ * Since this was the last IB1 that was processed, we should have
+ * already added it to the list during the ringbuffer parse but we
+ * want to be double plus sure.
*/
+
kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);
- if (ibsize)
+ /*
+ * The problem is that IB size from the register is the unprocessed size
+ * of the buffer not the original size, so if we didn't catch this
+ * buffer being directly used in the RB, then we might not be able to
+ * dump the whle thing. Print a warning message so we can try to
+ * figure how often this really happens.
+ */
+
+ if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
ibbase, ibsize);
+ KGSL_DRV_ERR(device, "CP_IB1_BASE not found in the ringbuffer. "
+ "Dumping %x dwords of the buffer.\n", ibsize);
+ }
kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);
- if (ibsize)
+ /*
+ * Add the last parsed IB2 to the list. The IB2 should be found as we
+ * parse the objects below, but we try to add it to the list first, so
+ * it too can be parsed. Don't print an error message in this case - if
+ * the IB2 is found during parsing, the list will be updated with the
+ * correct size.
+ */
+
+ if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
ibbase, ibsize);
+ }
/*
* Go through the list of found objects and dump each one. As the IBs
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 120b129..9333dca 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -391,6 +391,8 @@
wait_for_completion(&device->suspend_gate);
mutex_lock(&device->mutex);
}
+ /* Don't let the timer wake us during suspended sleep. */
+ del_timer_sync(&device->idle_timer);
switch (device->state) {
case KGSL_STATE_INIT:
break;
@@ -402,7 +404,6 @@
/* Get the completion ready to be waited upon. */
INIT_COMPLETION(device->hwaccess_gate);
device->ftbl->suspend_context(device);
- kgsl_pwrctrl_stop_work(device);
device->ftbl->stop(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
break;
@@ -485,7 +486,6 @@
struct kgsl_device, display_off);
KGSL_PWR_WARN(device, "early suspend start\n");
mutex_lock(&device->mutex);
- kgsl_pwrctrl_stop_work(device);
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
kgsl_pwrctrl_sleep(device);
mutex_unlock(&device->mutex);
@@ -632,7 +632,6 @@
device->open_count--;
if (device->open_count == 0) {
- kgsl_pwrctrl_stop_work(device);
result = device->ftbl->stop(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
}
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 1135adb..3e8aac3 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -199,7 +199,7 @@
if (ts_diff == 0)
return 0;
- return ((ts_diff > 0) || (ts_diff < -20000)) ? 1 : -1;
+ return ((ts_diff > 0) || (ts_diff < -25000)) ? 1 : -1;
}
static inline void
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index a16b954..97b5ef1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -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
@@ -398,11 +398,11 @@
enum kgsl_deviceid id)
{
unsigned int result = 0;
- struct kgsl_gpummu_pt *gpummu_pt = (struct kgsl_gpummu_pt *)
- pt->priv;
+ struct kgsl_gpummu_pt *gpummu_pt;
if (pt == NULL)
return 0;
+ gpummu_pt = pt->priv;
spin_lock(&pt->lock);
if (gpummu_pt->tlb_flags && (1<<id)) {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e4e561c..194067b 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -24,11 +24,23 @@
#include "kgsl_mmu.h"
#include "kgsl_sharedmem.h"
+/*
+ * On APQ8064, KGSL can control a maximum of 4 IOMMU devices: 2 user and 2
+ * priv domains, 1 each for each of the AXI ports attached to the GPU. 8660
+ * and 8960 have only one AXI port, so maximum allowable IOMMU devices for those
+ * chips is 2.
+ */
+
+#define KGSL_IOMMU_MAX_DEV 4
+
+struct kgsl_iommu_device {
+ struct device *dev;
+ int attached;
+};
+
struct kgsl_iommu {
- struct device *iommu_user_dev;
- int iommu_user_dev_attached;
- struct device *iommu_priv_dev;
- int iommu_priv_dev_attached;
+ struct kgsl_iommu_device dev[KGSL_IOMMU_MAX_DEV];
+ int dev_count;
};
static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
@@ -58,89 +70,101 @@
{
struct iommu_domain *domain;
struct kgsl_iommu *iommu = mmu->priv;
+ int i;
BUG_ON(mmu->hwpagetable == NULL);
BUG_ON(mmu->hwpagetable->priv == NULL);
domain = mmu->hwpagetable->priv;
- if (iommu->iommu_user_dev_attached) {
- iommu_detach_device(domain, iommu->iommu_user_dev);
- iommu->iommu_user_dev_attached = 0;
+ for (i = 0; i < iommu->dev_count; i++) {
+ iommu_detach_device(domain, iommu->dev[i].dev);
+ iommu->dev[i].attached = 0;
KGSL_MEM_INFO(mmu->device,
- "iommu %p detached from user dev of MMU: %p\n",
- domain, mmu);
- }
- if (iommu->iommu_priv_dev_attached) {
- iommu_detach_device(domain, iommu->iommu_priv_dev);
- iommu->iommu_priv_dev_attached = 0;
- KGSL_MEM_INFO(mmu->device,
- "iommu %p detached from priv dev of MMU: %p\n",
- domain, mmu);
+ "iommu %p detached from user dev of MMU: %p\n",
+ domain, mmu);
}
}
static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
{
struct iommu_domain *domain;
- int ret = 0;
struct kgsl_iommu *iommu = mmu->priv;
+ int i, ret = 0;
BUG_ON(mmu->hwpagetable == NULL);
BUG_ON(mmu->hwpagetable->priv == NULL);
domain = mmu->hwpagetable->priv;
- if (iommu->iommu_user_dev && !iommu->iommu_user_dev_attached) {
- ret = iommu_attach_device(domain, iommu->iommu_user_dev);
- if (ret) {
- KGSL_MEM_ERR(mmu->device,
- "Failed to attach device, err %d\n", ret);
- goto done;
- }
- iommu->iommu_user_dev_attached = 1;
- KGSL_MEM_INFO(mmu->device,
- "iommu %p attached to user dev of MMU: %p\n",
+ for (i = 0; i < iommu->dev_count; i++) {
+ if (iommu->dev[i].attached == 0) {
+ ret = iommu_attach_device(domain, iommu->dev[i].dev);
+ if (ret) {
+ KGSL_MEM_ERR(mmu->device,
+ "Failed to attach device, err %d\n",
+ ret);
+ goto done;
+ }
+
+ iommu->dev[i].attached = 1;
+ KGSL_MEM_INFO(mmu->device,
+ "iommu %p detached from user dev of MMU: %p\n",
domain, mmu);
- }
- if (iommu->iommu_priv_dev && !iommu->iommu_priv_dev_attached) {
- ret = iommu_attach_device(domain, iommu->iommu_priv_dev);
- if (ret) {
- KGSL_MEM_ERR(mmu->device,
- "Failed to attach device, err %d\n", ret);
- iommu_detach_device(domain, iommu->iommu_user_dev);
- iommu->iommu_user_dev_attached = 0;
- goto done;
}
- iommu->iommu_priv_dev_attached = 1;
- KGSL_MEM_INFO(mmu->device,
- "iommu %p attached to priv dev of MMU: %p\n",
- domain, mmu);
}
+
done:
return ret;
}
+static int _get_iommu_ctxs(struct kgsl_iommu *iommu, struct kgsl_device *device,
+ struct kgsl_device_iommu_data *data)
+{
+ int i;
+
+ for (i = 0; i < data->iommu_ctx_count; i++) {
+ if (iommu->dev_count >= KGSL_IOMMU_MAX_DEV) {
+ KGSL_CORE_ERR("Tried to attach too many IOMMU "
+ "devices\n");
+ return -ENOMEM;
+ }
+
+ if (!data->iommu_ctx_names[i])
+ continue;
+
+ iommu->dev[iommu->dev_count].dev =
+ msm_iommu_get_ctx(data->iommu_ctx_names[i]);
+ if (iommu->dev[iommu->dev_count].dev == NULL) {
+ KGSL_CORE_ERR("Failed to iommu dev handle for "
+ "device %s\n", data->iommu_ctx_names[i]);
+ return -EINVAL;
+ }
+
+ iommu->dev_count++;
+ }
+
+ return 0;
+}
+
static int kgsl_get_iommu_ctxt(struct kgsl_iommu *iommu,
struct kgsl_device *device)
{
- int status = 0;
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
- if (pdata_dev->iommu_user_ctx_name)
- iommu->iommu_user_dev = msm_iommu_get_ctx(
- pdata_dev->iommu_user_ctx_name);
- if (pdata_dev->iommu_priv_ctx_name)
- iommu->iommu_priv_dev = msm_iommu_get_ctx(
- pdata_dev->iommu_priv_ctx_name);
- if (!iommu->iommu_user_dev) {
- KGSL_CORE_ERR("Failed to get user iommu dev handle for "
- "device %s\n",
- pdata_dev->iommu_user_ctx_name);
- status = -EINVAL;
+ int i, ret = 0;
+
+ /* Go through the IOMMU data and attach all the domains */
+
+ for (i = 0; i < pdata_dev->iommu_count; i++) {
+ ret = _get_iommu_ctxs(iommu, device,
+ &pdata_dev->iommu_data[i]);
+ if (ret)
+ break;
}
- return status;
+
+ return ret;
}
static void kgsl_iommu_setstate(struct kgsl_device *device,
@@ -182,8 +206,6 @@
return -ENOMEM;
}
- iommu->iommu_priv_dev_attached = 0;
- iommu->iommu_user_dev_attached = 0;
status = kgsl_get_iommu_ctxt(iommu, device);
if (status) {
kfree(iommu);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index ae50183..b671f86 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -371,7 +371,6 @@
}
}
}
-EXPORT_SYMBOL(kgsl_pwrctrl_clk);
void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
{
@@ -880,16 +879,6 @@
}
EXPORT_SYMBOL(kgsl_pwrctrl_disable);
-void kgsl_pwrctrl_stop_work(struct kgsl_device *device)
-{
- del_timer_sync(&device->idle_timer);
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
- mutex_unlock(&device->mutex);
- flush_workqueue(device->work_queue);
- mutex_lock(&device->mutex);
-}
-EXPORT_SYMBOL(kgsl_pwrctrl_stop_work);
-
void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state)
{
trace_kgsl_pwr_set_state(device, state);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 99dbae9..f474c21 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, 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
@@ -59,7 +59,6 @@
};
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
-void kgsl_pwrctrl_clk(struct kgsl_device *device, int state);
int kgsl_pwrctrl_init(struct kgsl_device *device);
void kgsl_pwrctrl_close(struct kgsl_device *device);
void kgsl_timer(unsigned long data);
@@ -74,7 +73,6 @@
void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device);
void kgsl_pwrctrl_enable(struct kgsl_device *device);
void kgsl_pwrctrl_disable(struct kgsl_device *device);
-void kgsl_pwrctrl_stop_work(struct kgsl_device *device);
static inline unsigned long kgsl_get_clkrate(struct clk *clk)
{
return (clk != NULL) ? clk_get_rate(clk) : 0;
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 718fac9..cb3da90 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -584,6 +584,8 @@
device->ftbl->irqctrl(device, 0);
z180_idle(device, KGSL_TIMEOUT_DEFAULT);
+ del_timer_sync(&device->idle_timer);
+
kgsl_mmu_stop(device);
/* Disable the clocks before the power rail. */
diff --git a/drivers/hwmon/msm_adc.c b/drivers/hwmon/msm_adc.c
index b8d581e..39bfc3a 100644
--- a/drivers/hwmon/msm_adc.c
+++ b/drivers/hwmon/msm_adc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -1380,7 +1380,7 @@
},
};
-static int msm_adc_probe(struct platform_device *pdev)
+static int __devinit msm_adc_probe(struct platform_device *pdev)
{
struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
struct msm_adc_drv *msm_adc;
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 5f8faee..0902c61 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -165,6 +165,7 @@
};
static struct pm8xxx_adc *pmic_adc;
+static struct regulator *pa_therm;
static struct pm8xxx_adc_scale_fn adc_scale_fn[] = {
[ADC_SCALE_DEFAULT] = {pm8xxx_adc_scale_default},
@@ -238,26 +239,21 @@
static int32_t pm8xxx_adc_patherm_power(bool on)
{
- static struct regulator *pa_therm;
- struct pm8xxx_adc *adc_pmic = pmic_adc;
int rc = 0;
- if (on) {
- pa_therm = regulator_get(adc_pmic->dev,
- "pa_therm");
- if (IS_ERR(pa_therm)) {
- rc = PTR_ERR(pa_therm);
- pr_err("failed to request pa_therm vreg "
- "with error %d\n", rc);
- return rc;
- }
+ if (!pa_therm) {
+ pr_err("pm8xxx adc pa_therm not valid\n");
+ return -EINVAL;
+ }
+
+ if (on) {
rc = regulator_set_voltage(pa_therm,
PM8XXX_ADC_PA_THERM_VREG_UV_MIN,
PM8XXX_ADC_PA_THERM_VREG_UV_MAX);
if (rc < 0) {
pr_err("failed to set the voltage for "
"pa_therm with error %d\n", rc);
- goto fail;
+ return rc;
}
rc = regulator_set_optimum_mode(pa_therm,
@@ -265,25 +261,25 @@
if (rc < 0) {
pr_err("failed to set optimum mode for "
"pa_therm with error %d\n", rc);
- goto fail;
+ return rc;
}
- if (regulator_enable(pa_therm)) {
- pr_err("failed to enable pa_therm vreg with "
- "error %d\n", rc);
- goto fail;
+ rc = regulator_enable(pa_therm);
+ if (rc < 0) {
+ pr_err("failed to enable pa_therm vreg "
+ "with error %d\n", rc);
+ return rc;
}
} else {
- if (pa_therm != NULL) {
- regulator_disable(pa_therm);
- regulator_put(pa_therm);
+ rc = regulator_disable(pa_therm);
+ if (rc < 0) {
+ pr_err("failed to disable pa_therm vreg "
+ "with error %d\n", rc);
+ return rc;
}
}
return rc;
-fail:
- regulator_put(pa_therm);
- return rc;
}
static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
@@ -293,7 +289,7 @@
switch (channel)
case ADC_MPP_1_AMUX8:
- pm8xxx_adc_patherm_power(power_cntrl);
+ rc = pm8xxx_adc_patherm_power(power_cntrl);
return rc;
}
@@ -769,6 +765,9 @@
struct pm8xxx_adc *adc_pmic = pmic_adc;
int rc = 0;
+ if (!pm8xxx_adc_initialized)
+ return -ENODEV;
+
if (!adc_pmic->mpp_base) {
rc = -EINVAL;
pr_info("PM8xxx MPP base invalid with error %d\n", rc);
@@ -1138,6 +1137,10 @@
wake_lock_destroy(&adc_pmic->adc_wakelock);
platform_set_drvdata(pdev, NULL);
pmic_adc = NULL;
+ if (!pa_therm) {
+ regulator_put(pa_therm);
+ pa_therm = NULL;
+ }
for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
device_remove_file(adc_pmic->dev,
&adc_pmic->sens_attr[i].dev_attr);
@@ -1252,6 +1255,13 @@
dev_err(&pdev->dev, "failed to initialize pm8xxx hwmon adc\n");
}
adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
+
+ pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
+ if (IS_ERR(pa_therm)) {
+ rc = PTR_ERR(pa_therm);
+ pr_err("failed to request pa_therm vreg with error %d\n", rc);
+ pa_therm = NULL;
+ }
return 0;
}
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 476300c..793f063 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2609,7 +2609,7 @@
} else
retval = -EINVAL;
-
+ break;
case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
if (retval < 0) {
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 1c4f616..5ec2932 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -2582,6 +2582,7 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int retval = 0;
+ int cnt = 0;
unsigned char xfr_buf[XFR_REG_NUM];
signed char cRmssiThreshold;
signed char ioc;
@@ -2712,6 +2713,69 @@
ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
break;
+ case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
+ size = 0x04;
+ xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+ xfr_buf[1] = ON_CHANNEL_TH_MSB;
+ xfr_buf[2] = ON_CHANNEL_TH_LSB;
+ retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+ if (retval < 0) {
+ pr_err("%s: Failed to write\n", __func__);
+ return retval;
+ }
+ /*Wait for the XFR interrupt */
+ msleep(TAVARUA_DELAY*10);
+ retval = tavarua_read_registers(radio, XFRDAT0, 4);
+ if (retval < 0) {
+ pr_err("%s: On Ch. DET: Read failure\n", __func__);
+ return retval;
+ }
+ for (cnt = 0; cnt < 4; cnt++)
+ FMDBG("On-Channel data set is : 0x%x\t",
+ (int)radio->registers[XFRDAT0+cnt]);
+
+ ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
+ LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+ LSH_DATA(radio->registers[XFRDAT0+2], 8) |
+ (radio->registers[XFRDAT0+3]);
+ FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
+ break;
+ case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
+ size = 0x04;
+ xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+ xfr_buf[1] = OFF_CHANNEL_TH_MSB;
+ xfr_buf[2] = OFF_CHANNEL_TH_LSB;
+ retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+ if (retval < 0) {
+ pr_err("%s: Failed to write\n", __func__);
+ return retval;
+ }
+ /*Wait for the XFR interrupt */
+ msleep(TAVARUA_DELAY*10);
+ retval = tavarua_read_registers(radio, XFRDAT0, 4);
+ if (retval < 0) {
+ pr_err("%s: Off Ch. DET: Read failure\n", __func__);
+ return retval;
+ }
+ for (cnt = 0; cnt < 4; cnt++)
+ FMDBG("Off-channel data set is : 0x%x\t",
+ (int)radio->registers[XFRDAT0+cnt]);
+
+ ctrl->value = LSH_DATA(radio->registers[XFRDAT0], 24) |
+ LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+ LSH_DATA(radio->registers[XFRDAT0+2], 8) |
+ (radio->registers[XFRDAT0+3]);
+ FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
+ break;
+ /*
+ * These IOCTL's are place holders to keep the
+ * driver compatible with change in frame works for IRIS
+ */
+ case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+ case V4L2_CID_PRIVATE_SINR_SAMPLES:
+ case V4L2_CID_PRIVATE_IRIS_GET_SINR:
+ retval = 0;
+ break;
default:
retval = -EINVAL;
}
@@ -3090,7 +3154,7 @@
SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
break;
- case V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD:
+ case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
size = 0x04;
/* Poking the value of ON Channel Threshold value */
xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3110,39 +3174,13 @@
retval = tavarua_write_registers(radio, XFRCTRL,
xfr_buf, size+3);
if (retval < 0) {
- FMDBG("Failed to write\n");
- return retval;
- }
- /*Wait for the XFR interrupt */
- msleep(TAVARUA_DELAY*15);
-
- for (cnt = 0; cnt < 5; cnt++) {
- xfr_buf[cnt] = 0;
- radio->registers[XFRDAT0+cnt] = 0x0;
- }
-
- /* Peeking Regs 0x88C2-0x88C4 */
- size = 0x04;
- xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
- xfr_buf[1] = ON_CHANNEL_TH_MSB;
- xfr_buf[2] = ON_CHANNEL_TH_LSB;
- retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
- if (retval < 0) {
pr_err("%s: Failed to write\n", __func__);
return retval;
}
/*Wait for the XFR interrupt */
msleep(TAVARUA_DELAY*10);
- retval = tavarua_read_registers(radio, XFRDAT0, 4);
- if (retval < 0) {
- pr_err("%s: On Ch. DET: Read failure\n", __func__);
- return retval;
- }
- for (cnt = 0; cnt < 4; cnt++)
- FMDBG("On-Channel data set is : 0x%x\t",
- (int)radio->registers[XFRDAT0+cnt]);
break;
- case V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD:
+ case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
size = 0x04;
/* Poking the value of OFF Channel Threshold value */
xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3167,32 +3205,6 @@
}
/*Wait for the XFR interrupt */
msleep(TAVARUA_DELAY*10);
-
- for (cnt = 0; cnt < 5; cnt++) {
- xfr_buf[cnt] = 0;
- radio->registers[XFRDAT0+cnt] = 0x0;
- }
-
- /* Peeking Regs 0x88C2-0x88C4 */
- size = 0x04;
- xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
- xfr_buf[1] = OFF_CHANNEL_TH_MSB;
- xfr_buf[2] = OFF_CHANNEL_TH_LSB;
- retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
- if (retval < 0) {
- pr_err("%s: Failed to write\n", __func__);
- return retval;
- }
- /*Wait for the XFR interrupt */
- msleep(TAVARUA_DELAY*10);
- retval = tavarua_read_registers(radio, XFRDAT0, 4);
- if (retval < 0) {
- pr_err("%s: Off Ch. DET: Read failure\n", __func__);
- return retval;
- }
- for (cnt = 0; cnt < 4; cnt++)
- FMDBG("Off-channel data set is : 0x%x\t",
- (int)radio->registers[XFRDAT0+cnt]);
break;
/* TX Controls */
@@ -3264,6 +3276,8 @@
case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
+ case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+ case V4L2_CID_PRIVATE_SINR_SAMPLES:
retval = 0;
break;
default:
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index fab3a21..aa6f966 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -90,6 +90,42 @@
return rc;
}
+int32_t imx074_act_move_focus(
+ struct msm_actuator_ctrl_t *a_ctrl,
+ int dir,
+ int32_t num_steps)
+{
+ int32_t step_direction, dest_step_position, bit_mask;
+ int32_t rc = 0;
+
+ if (num_steps == 0)
+ return rc;
+
+ if (dir == MOVE_NEAR) {
+ step_direction = 1;
+ bit_mask = 0x80;
+ } else if (dir == MOVE_FAR) {
+ step_direction = -1;
+ bit_mask = 0x00;
+ } else {
+ CDBG("imx074_move_focus: Illegal focus direction");
+ return -EINVAL;
+ }
+ dest_step_position = a_ctrl->curr_step_pos +
+ (step_direction * num_steps);
+ if (dest_step_position < 0)
+ dest_step_position = 0;
+ else if (dest_step_position > IMX074_TOTAL_STEPS_NEAR_TO_FAR)
+ dest_step_position = IMX074_TOTAL_STEPS_NEAR_TO_FAR;
+
+ msm_camera_i2c_write(&a_ctrl->i2c_client,
+ 0x00,
+ ((num_steps * g_regions[0].code_per_step) | bit_mask),
+ MSM_CAMERA_I2C_BYTE_DATA);
+ a_ctrl->curr_step_pos = dest_step_position;
+ return rc;
+}
+
static int32_t imx074_set_default_focus(
struct msm_actuator_ctrl_t *a_ctrl)
{
@@ -228,7 +264,7 @@
.func_tbl = {
.actuator_init_table = msm_actuator_init_table,
- .actuator_move_focus = msm_actuator_move_focus,
+ .actuator_move_focus = imx074_act_move_focus,
.actuator_write_focus = imx074_act_write_focus,
.actuator_set_default_focus = imx074_set_default_focus,
.actuator_init_focus = imx074_act_init_focus,
@@ -244,6 +280,10 @@
.f_pix_den = 10,
.total_f_dist_num = 197681,
.total_f_dist_den = 1000,
+ .hor_view_angle_num = 548,
+ .hor_view_angle_den = 10,
+ .ver_view_angle_num = 425,
+ .ver_view_angle_den = 10,
},
/* Initialize scenario */
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 7a0ee4d..d247467 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -138,6 +138,10 @@
{"csi_pclk", -1},
};
+static struct camera_vreg_t csid_vreg_info[] = {
+ {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
+};
+
static int msm_csid_init(struct v4l2_subdev *sd, uint32_t *csid_version)
{
int rc = 0;
@@ -155,11 +159,25 @@
return rc;
}
+ rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+ ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
+ if (rc < 0) {
+ pr_err("%s: regulator on failed\n", __func__);
+ goto vreg_config_failed;
+ }
+
+ rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+ ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
+ if (rc < 0) {
+ pr_err("%s: regulator enable failed\n", __func__);
+ goto vreg_enable_failed;
+ }
+
rc = msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 1);
if (rc < 0) {
- iounmap(csid_dev->base);
- return rc;
+ pr_err("%s: regulator enable failed\n", __func__);
+ goto clk_enable_failed;
}
#if DBG_CSID
@@ -167,8 +185,17 @@
#endif
*csid_version = csid_dev->hw_version;
-
return 0;
+
+clk_enable_failed:
+ msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+ ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+vreg_enable_failed:
+ msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+ ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+vreg_config_failed:
+ iounmap(csid_dev->base);
+ return rc;
}
static int msm_csid_release(struct v4l2_subdev *sd)
@@ -183,6 +210,12 @@
msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
+ msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+ ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+
+ msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+ ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+
iounmap(csid_dev->base);
return 0;
}
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index f90abf2..105cd49 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -23,6 +23,7 @@
struct resource *mem;
struct resource *irq;
struct resource *io;
+ struct regulator *csi_vdd;
void __iomem *base;
struct mutex mutex;
uint32_t hw_version;
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index 0f0bd67..f035ad6 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -435,8 +435,11 @@
}
buf_cmd = buf_p->vbuf;
- msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
- &buf_p->handle);
+ if (pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ENCODE ||
+ pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ROTATION) {
+ msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
+ &buf_p->handle);
+ }
kfree(buf_p->subsystem_id);
kfree(buf_p);
@@ -484,16 +487,23 @@
kfree(buf_p);
return -ENOMEM;
}
+ if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+ buf_p->y_buffer_addr = buf_cmd.y_off;
+ } else {
buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
&buf_p->msm_buffer, buf_p->subsystem_id, &buf_p->handle)
+ buf_cmd.offset;
+ }
buf_p->y_len = buf_cmd.y_len;
buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
buf_p->cbcr_len = buf_cmd.cbcr_len;
buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+ GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
+ buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
+ buf_p->cbcr_len);
if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index ea969cf..9bfc239 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -117,7 +117,7 @@
case CAMIO_JPEG_CLK:
camio_jpeg_clk =
clk = clk_get(NULL, "ijpeg_clk");
- clk_set_rate(clk, 153600000);
+ clk_set_rate(clk, 228571000);
break;
case CAMIO_JPEG_PCLK:
@@ -191,6 +191,11 @@
if (rc < 0)
return rc;
rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
+ if (rc < 0)
+ return rc;
+ rc = msm_camio_clk_disable(CAMIO_IMEM_CLK);
+ if (rc < 0)
+ return rc;
if (fs_ijpeg) {
rc = regulator_disable(fs_ijpeg);
@@ -225,6 +230,10 @@
if (rc < 0)
return rc;
+ rc = msm_camio_clk_enable(CAMIO_IMEM_CLK);
+ if (rc < 0)
+ return rc;
+
CDBG("%s: exit %d\n", __func__, rc);
return rc;
}
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index fdd1f0e..a0ac70d 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -90,6 +90,7 @@
case VFE_OUTPUTS_MAIN_AND_VIDEO:
case VFE_OUTPUTS_MAIN_AND_THUMB:
case VFE_OUTPUTS_RAW:
+ case VFE_OUTPUTS_JPEG_AND_THUMB:
image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
break;
case VFE_OUTPUTS_THUMB_AND_MAIN:
@@ -123,6 +124,9 @@
case VFE_OUTPUTS_THUMB_AND_MAIN:
image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
break;
+ case VFE_OUTPUTS_JPEG_AND_THUMB:
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
+ break;
default:
image_mode = -1;
break;
@@ -200,16 +204,27 @@
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
break;
case VFE_MSG_V32_JPEG_CAPTURE:
+ D("%s:VFE_MSG_V32_JPEG_CAPTURE vdata->type %d\n", __func__,
+ vdata->type);
free_buf.num_planes = 1;
- free_buf.ch_paddr[0] = IMEM_Y_OFFSET;
- free_buf.ch_paddr[1] = IMEM_CBCR_OFFSET;
+ free_buf.ch_paddr[0] = IMEM_Y_PING_OFFSET;
+ free_buf.ch_paddr[1] = IMEM_CBCR_PING_OFFSET;
cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
vfe_params.data = (void *)&free_buf;
+ D("%s:VFE_MSG_V32_JPEG_CAPTURE y_ping=%x cbcr_ping=%x\n",
+ __func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
/* Write the same buffer into PONG */
+ free_buf.ch_paddr[0] = IMEM_Y_PONG_OFFSET;
+ free_buf.ch_paddr[1] = IMEM_CBCR_PONG_OFFSET;
cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
+ cfgcmd.value = &vfe_id;
+ vfe_params.vfe_cfg = &cfgcmd;
+ vfe_params.data = (void *)&free_buf;
+ D("%s:VFE_MSG_V32_JPEG_CAPTURE y_pong=%x cbcr_pong=%x\n",
+ __func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
break;
case VFE_MSG_OUTPUT_IRQ:
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index b539d19..e9201ea 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -868,6 +868,7 @@
irq_comp_mask = msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
if (vfe32_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
@@ -1297,8 +1298,6 @@
rc = vfe32_capture_raw(snapshot_cnt);
break;
case VFE_CMD_CAPTURE:
- CDBG("vfe32_proc_general: cmdID = %s op mode = %d\n",
- vfe32_general_cmd[cmd->id], vfe32_ctrl->operation_mode);
if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
sizeof(uint32_t))) {
rc = -EFAULT;
@@ -2960,13 +2959,14 @@
free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
VFE_MSG_OUTPUT_SECONDARY);
-
out_bool = ((vfe32_ctrl->operation_mode ==
VFE_OUTPUTS_THUMB_AND_MAIN ||
vfe32_ctrl->operation_mode ==
VFE_OUTPUTS_MAIN_AND_THUMB ||
vfe32_ctrl->operation_mode ==
- VFE_OUTPUTS_RAW) &&
+ VFE_OUTPUTS_RAW ||
+ vfe32_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB) &&
(vfe32_ctrl->vfe_capture_count <= 1)) || free_buf;
if (out_bool) {
@@ -3003,7 +3003,9 @@
vfe32_ctrl->operation_mode ==
VFE_OUTPUTS_MAIN_AND_THUMB ||
vfe32_ctrl->operation_mode ==
- VFE_OUTPUTS_RAW)
+ VFE_OUTPUTS_RAW ||
+ vfe32_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB)
vfe32_ctrl->outpath.out1.capture_cnt--;
vfe_send_outmsg(&vfe32_ctrl->subdev,
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 047226e..cfc0fe0 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -4,9 +4,9 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
obj-$(CONFIG_IMX074) += imx074_v4l2.o
-obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
obj-$(CONFIG_OV2720) += ov2720.o
+obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 954dd2f..af68601 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -123,7 +123,7 @@
{0x0344, 0x01}, /* x_addr_start */
{0x0345, 0x20}, /* x_addr_start */
{0x0346, 0x02}, /* y_addr_start */
- {0x0347, 0x23}, /* y_addr_start */
+ {0x0347, 0x24}, /* y_addr_start */
{0x0348, 0x0E}, /* x_addr_end */
{0x0349, 0xA0}, /* x_addr_end */
{0x034A, 0x09}, /* y_addr_end */
@@ -160,7 +160,7 @@
{0x0344, 0x01}, /* x_addr_start */
{0x0345, 0x20}, /* x_addr_start */
{0x0346, 0x02}, /* y_addr_start */
- {0x0347, 0x23}, /* y_addr_start */
+ {0x0347, 0x24}, /* y_addr_start */
{0x0348, 0x0E}, /* x_addr_end */
{0x0349, 0xA0}, /* x_addr_end */
{0x034A, 0x09}, /* y_addr_end */
@@ -197,7 +197,7 @@
{0x0344, 0x01}, /* x_addr_start */
{0x0345, 0x20}, /* x_addr_start */
{0x0346, 0x02}, /* y_addr_start */
- {0x0347, 0x23}, /* y_addr_start */
+ {0x0347, 0x24}, /* y_addr_start */
{0x0348, 0x0E}, /* x_addr_end */
{0x0349, 0xA0}, /* x_addr_end */
{0x034A, 0x09}, /* y_addr_end */
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 315705c..ce81746 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -35,6 +35,7 @@
#include "vsg-subdev.h"
#define WFD_VERSION KERNEL_VERSION(0, 0, 1)
+#define WFD_DEVICE_NUMBER 38
#define DEFAULT_WFD_WIDTH 640
#define DEFAULT_WFD_HEIGHT 480
#define VSG_SCRATCH_BUFFERS 1
@@ -1155,7 +1156,8 @@
wfd_dev->pvdev->fops = &g_wfd_fops;
wfd_dev->pvdev->ioctl_ops = &g_wfd_ioctl_ops;
- rc = video_register_device(wfd_dev->pvdev, VFL_TYPE_GRABBER, -1);
+ rc = video_register_device(wfd_dev->pvdev, VFL_TYPE_GRABBER,
+ WFD_DEVICE_NUMBER);
if (rc) {
WFD_MSG_ERR("Failed to register the device\n");
goto err_video_register_device;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 77ac845..54e1b9a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -879,6 +879,16 @@
voltage leaves the accepatable range which then calls a notifier call
chain.
+config WCD9304_CODEC
+ tristate "WCD9304 Codec"
+ select SLIMBUS
+ select MFD_CORE
+ default n
+ help
+ Enables the WCD9304 core driver. The core driver provides
+ read/write capability to registers which are part of the
+ WCD9304 core and gives the ability to use the WCD9304 codec.
+
config WCD9310_CODEC
tristate "WCD9310 Codec"
select SLIMBUS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c8fcf5f..fd887ea 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -69,7 +69,8 @@
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
-obj-$(CONFIG_WCD9310_CODEC) += wcd9310-core.o wcd9310-irq.o wcd9310-slimslave.o
+obj-$(CONFIG_WCD9310_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
+obj-$(CONFIG_WCD9304_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
ifeq ($(CONFIG_SA1100_ASSABET),y)
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 6be3f2d..8049975 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -427,9 +427,26 @@
NCP("8921_ncp", 0x090),
};
+/*
+ * PM8917 adds 6 LDOs and a boost regulator beyond those available on PM8921.
+ * It also replaces SMPS 3 with FTSMPS 3. PM8917 does not have an NCP.
+ */
+static struct pm8xxx_vreg pm8917_regulator_data[] = {
+ /* name pc_name ctrl test hpm_min */
+ PLDO("8917_l30", "8917_l30_pc", 0x0A3, 0x0A4, LDO_150),
+ PLDO("8917_l31", "8917_l31_pc", 0x0A5, 0x0A6, LDO_150),
+ PLDO("8917_l32", "8917_l32_pc", 0x0A7, 0x0A8, LDO_150),
+ PLDO("8917_l33", "8917_l33_pc", 0x0C6, 0x0C7, LDO_150),
+ PLDO("8917_l34", "8917_l34_pc", 0x0D2, 0x0D3, LDO_150),
+ PLDO("8917_l35", "8917_l35_pc", 0x0D4, 0x0D5, LDO_300),
+
+ /* name ctrl */
+ BOOST("8917_boost", 0x04B),
+};
+
#define MAX_NAME_COMPARISON_LEN 32
-static int __devinit match_regulator(
+static int __devinit match_regulator(enum pm8xxx_version version,
struct pm8xxx_regulator_core_platform_data *core_data, char *name)
{
int found = 0;
@@ -452,6 +469,25 @@
break;
}
}
+ if (version == PM8XXX_VERSION_8917) {
+ for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++) {
+ if (pm8917_regulator_data[i].rdesc.name
+ && strncmp(pm8917_regulator_data[i].rdesc.name,
+ name, MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = false;
+ core_data->vreg = &pm8917_regulator_data[i];
+ found = 1;
+ break;
+ } else if (pm8917_regulator_data[i].rdesc_pc.name
+ && strncmp(pm8917_regulator_data[i].rdesc_pc.name,
+ name, MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = true;
+ core_data->vreg = &pm8917_regulator_data[i];
+ found = 1;
+ break;
+ }
+ }
+ }
if (!found)
pr_err("could not find a match for regulator: %s\n", name);
@@ -466,8 +502,11 @@
int ret = 0;
struct mfd_cell *mfd_regulators;
struct pm8xxx_regulator_core_platform_data *cdata;
+ enum pm8xxx_version version;
int i;
+ version = pm8xxx_get_version(pmic->dev);
+
/* Add one device for each regulator used by the board. */
mfd_regulators = kzalloc(sizeof(struct mfd_cell)
* (pdata->num_regulators), GFP_KERNEL);
@@ -488,6 +527,8 @@
}
for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
mutex_init(®ulator_data[i].pc_lock);
+ for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+ mutex_init(&pm8917_regulator_data[i].pc_lock);
for (i = 0; i < pdata->num_regulators; i++) {
if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
@@ -495,7 +536,7 @@
ret = -EINVAL;
goto bail;
}
- if (!match_regulator(&cdata[i],
+ if (!match_regulator(version, &cdata[i],
pdata->regulator_pdatas[i].init_data.constraints.name)) {
ret = -ENODEV;
goto bail;
@@ -519,6 +560,8 @@
bail:
for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
mutex_destroy(®ulator_data[i].pc_lock);
+ for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+ mutex_destroy(&pm8917_regulator_data[i].pc_lock);
kfree(mfd_regulators);
kfree(cdata);
return ret;
@@ -908,6 +951,9 @@
if (pmic->mfd_regulators) {
for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
mutex_destroy(®ulator_data[i].pc_lock);
+ for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+ mutex_destroy(
+ &pm8917_regulator_data[i].pc_lock);
}
kfree(pmic->mfd_regulators);
kfree(pmic->regulator_cdata);
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index 14c9ec4..17b518e 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -102,6 +102,7 @@
goto bail;
}
+ cp &= ~PM_IRQF_WRITE;
rc = pm8xxx_writeb(chip->dev,
SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
if (rc)
@@ -127,7 +128,10 @@
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
-
+ /*
+ * Set the write bit here as this could be a unrequested irq
+ * whose PM_IRQF_WRITE bit is not set
+ */
cp |= PM_IRQF_WRITE;
rc = pm8xxx_writeb(chip->dev,
SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
@@ -222,7 +226,7 @@
irq_bit = pmirq % 8;
if (chip->config[pmirq] == 0) {
- pr_warn("masking rouge irq=%d pmirq=%d\n", d->irq, pmirq);
+ pr_warn("masking rogue irq=%d pmirq=%d\n", d->irq, pmirq);
chip->config[pmirq] = irq_bit << PM_IRQF_BITS_SHIFT;
}
@@ -242,7 +246,7 @@
irq_bit = pmirq % 8;
if (chip->config[pmirq] == 0) {
- pr_warn("mask acking rouge irq=%d pmirq=%d\n", d->irq, pmirq);
+ pr_warn("mask acking rogue irq=%d pmirq=%d\n", d->irq, pmirq);
chip->config[pmirq] = irq_bit << PM_IRQF_BITS_SHIFT;
}
@@ -295,6 +299,12 @@
chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
}
+ /*
+ * The PM_IRQF_WRITE flag serves as an indication that this interrupt
+ * been requested
+ */
+ chip->config[pmirq] |= PM_IRQF_WRITE;
+
config = chip->config[pmirq] | PM_IRQF_CLR;
return pm8xxx_write_config_irq(chip, block, config);
}
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
deleted file mode 100644
index 56774e9..0000000
--- a/drivers/mfd/wcd9310-core.c
+++ /dev/null
@@ -1,1166 +0,0 @@
-/* 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
- * 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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/wcd9310/pdata.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/debugfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/i2c.h>
-#include <sound/soc.h>
-
-#define TABLA_SLIM_GLA_MAX_RETRIES 5
-#define TABLA_REGISTER_START_OFFSET 0x800
-#define TABLA_SLIM_RW_MAX_TRIES 3
-
-#define MAX_TABLA_DEVICE 4
-#define TABLA_I2C_MODE 0x03
-
-struct tabla_i2c {
- struct i2c_client *client;
- struct i2c_msg xfer_msg[2];
- struct mutex xfer_lock;
- int mod_id;
-};
-
-struct tabla_i2c tabla_modules[MAX_TABLA_DEVICE];
-static int tabla_intf;
-
-static int tabla_read(struct tabla *tabla, unsigned short reg,
- int bytes, void *dest, bool interface_reg)
-{
- int ret;
- u8 *buf = dest;
-
- if (bytes <= 0) {
- dev_err(tabla->dev, "Invalid byte read length %d\n", bytes);
- return -EINVAL;
- }
-
- ret = tabla->read_dev(tabla, reg, bytes, dest, interface_reg);
- if (ret < 0) {
- dev_err(tabla->dev, "Tabla read failed\n");
- return ret;
- } else
- dev_dbg(tabla->dev, "Read 0x%02x from R%d(0x%x)\n",
- *buf, reg, reg);
-
- return 0;
-}
-int tabla_reg_read(struct tabla *tabla, unsigned short reg)
-{
- u8 val;
- int ret;
-
- mutex_lock(&tabla->io_lock);
- ret = tabla_read(tabla, reg, 1, &val, false);
- mutex_unlock(&tabla->io_lock);
-
- if (ret < 0)
- return ret;
- else
- return val;
-}
-EXPORT_SYMBOL_GPL(tabla_reg_read);
-
-static int tabla_write(struct tabla *tabla, unsigned short reg,
- int bytes, void *src, bool interface_reg)
-{
- u8 *buf = src;
-
- if (bytes <= 0) {
- pr_err("%s: Error, invalid write length\n", __func__);
- return -EINVAL;
- }
-
- dev_dbg(tabla->dev, "Write %02x to R%d(0x%x)\n",
- *buf, reg, reg);
-
- return tabla->write_dev(tabla, reg, bytes, src, interface_reg);
-}
-
-int tabla_reg_write(struct tabla *tabla, unsigned short reg,
- u8 val)
-{
- int ret;
-
- mutex_lock(&tabla->io_lock);
- ret = tabla_write(tabla, reg, 1, &val, false);
- mutex_unlock(&tabla->io_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_reg_write);
-
-static u8 tabla_pgd_la;
-static u8 tabla_inf_la;
-
-int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la)
-{
- *pgd_la = tabla_pgd_la;
- *inf_la = tabla_inf_la;
- return 0;
-
-}
-EXPORT_SYMBOL_GPL(tabla_get_logical_addresses);
-
-int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg)
-{
- u8 val;
- int ret;
-
- mutex_lock(&tabla->io_lock);
- ret = tabla_read(tabla, reg, 1, &val, true);
- mutex_unlock(&tabla->io_lock);
-
- if (ret < 0)
- return ret;
- else
- return val;
-}
-EXPORT_SYMBOL_GPL(tabla_interface_reg_read);
-
-int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg,
- u8 val)
-{
- int ret;
-
- mutex_lock(&tabla->io_lock);
- ret = tabla_write(tabla, reg, 1, &val, true);
- mutex_unlock(&tabla->io_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_interface_reg_write);
-
-int tabla_bulk_read(struct tabla *tabla, unsigned short reg,
- int count, u8 *buf)
-{
- int ret;
-
- mutex_lock(&tabla->io_lock);
-
- ret = tabla_read(tabla, reg, count, buf, false);
-
- mutex_unlock(&tabla->io_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_bulk_read);
-
-int tabla_bulk_write(struct tabla *tabla, unsigned short reg,
- int count, u8 *buf)
-{
- int ret;
-
- mutex_lock(&tabla->io_lock);
-
- ret = tabla_write(tabla, reg, count, buf, false);
-
- mutex_unlock(&tabla->io_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(tabla_bulk_write);
-
-static int tabla_slim_read_device(struct tabla *tabla, unsigned short reg,
- int bytes, void *dest, bool interface)
-{
- int ret;
- struct slim_ele_access msg;
- int slim_read_tries = TABLA_SLIM_RW_MAX_TRIES;
- msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
- msg.num_bytes = bytes;
- msg.comp = NULL;
-
- while (1) {
- mutex_lock(&tabla->xfer_lock);
- ret = slim_request_val_element(interface ?
- tabla->slim_slave : tabla->slim,
- &msg, dest, bytes);
- mutex_unlock(&tabla->xfer_lock);
- if (likely(ret == 0) || (--slim_read_tries == 0))
- break;
- usleep_range(5000, 5000);
- }
-
- if (ret)
- pr_err("%s: Error, Tabla read failed (%d)\n", __func__, ret);
-
- return ret;
-}
-/* Interface specifies whether the write is to the interface or general
- * registers.
- */
-static int tabla_slim_write_device(struct tabla *tabla, unsigned short reg,
- int bytes, void *src, bool interface)
-{
- int ret;
- struct slim_ele_access msg;
- int slim_write_tries = TABLA_SLIM_RW_MAX_TRIES;
- msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
- msg.num_bytes = bytes;
- msg.comp = NULL;
-
- while (1) {
- mutex_lock(&tabla->xfer_lock);
- ret = slim_change_val_element(interface ?
- tabla->slim_slave : tabla->slim,
- &msg, src, bytes);
- mutex_unlock(&tabla->xfer_lock);
- if (likely(ret == 0) || (--slim_write_tries == 0))
- break;
- usleep_range(5000, 5000);
- }
-
- if (ret)
- pr_err("%s: Error, Tabla write failed (%d)\n", __func__, ret);
-
- return ret;
-}
-
-static struct mfd_cell tabla_devs[] = {
- {
- .name = "tabla_codec",
- },
-};
-
-static struct mfd_cell tabla1x_devs[] = {
- {
- .name = "tabla1x_codec",
- },
-};
-
-static void tabla_bring_up(struct tabla *tabla)
-{
- tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x4);
- tabla_reg_write(tabla, TABLA_A_CDC_CTL, 0);
- usleep_range(5000, 5000);
- tabla_reg_write(tabla, TABLA_A_CDC_CTL, 3);
- tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 3);
-}
-
-static void tabla_bring_down(struct tabla *tabla)
-{
- tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x7);
- tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x6);
- tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0xe);
- tabla_reg_write(tabla, TABLA_A_LEAKAGE_CTL, 0x8);
-}
-
-static int tabla_reset(struct tabla *tabla)
-{
- int ret;
- struct pm_gpio param = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 1,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S4,
- .out_strength = PM_GPIO_STRENGTH_MED,
- .function = PM_GPIO_FUNC_NORMAL,
- };
-
- if (tabla->reset_gpio) {
- ret = gpio_request(tabla->reset_gpio, "CDC_RESET");
- if (ret) {
- pr_err("%s: Failed to request gpio %d\n", __func__,
- tabla->reset_gpio);
- tabla->reset_gpio = 0;
- return ret;
- }
-
- ret = pm8xxx_gpio_config(tabla->reset_gpio, ¶m);
- if (ret)
- pr_err("%s: Failed to configure gpio\n", __func__);
-
- gpio_direction_output(tabla->reset_gpio, 1);
- msleep(20);
- gpio_direction_output(tabla->reset_gpio, 0);
- msleep(20);
- gpio_direction_output(tabla->reset_gpio, 1);
- msleep(20);
- }
- return 0;
-}
-
-static void tabla_free_reset(struct tabla *tabla)
-{
- if (tabla->reset_gpio) {
- gpio_free(tabla->reset_gpio);
- tabla->reset_gpio = 0;
- }
-}
-
-struct tabla_regulator {
- const char *name;
- int min_uV;
- int max_uV;
- int optimum_uA;
- struct regulator *regulator;
-};
-
-
-/*
- * format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
- *
- * <POWER_SUPPLY_PIN_NAME> from Tabla objective spec
-*/
-
-#define TABLA_CDC_VDDA_CP_CUR_MAX 500000
-#define TABLA_CDC_VDDA_RX_CUR_MAX 20000
-#define TABLA_CDC_VDDA_TX_CUR_MAX 20000
-#define TABLA_VDDIO_CDC_CUR_MAX 5000
-
-#define TABLA_VDDD_CDC_D_CUR_MAX 5000
-#define TABLA_VDDD_CDC_A_CUR_MAX 5000
-
-static struct tabla_regulator tabla_regulators[] = {
- {
- .name = "CDC_VDD_CP",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .optimum_uA = TABLA_CDC_VDDA_CP_CUR_MAX,
- },
- {
- .name = "CDC_VDDA_RX",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .optimum_uA = TABLA_CDC_VDDA_RX_CUR_MAX,
- },
- {
- .name = "CDC_VDDA_TX",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .optimum_uA = TABLA_CDC_VDDA_TX_CUR_MAX,
- },
- {
- .name = "VDDIO_CDC",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .optimum_uA = TABLA_VDDIO_CDC_CUR_MAX,
- },
- {
- .name = "VDDD_CDC_D",
- .min_uV = 1225000,
- .max_uV = 1225000,
- .optimum_uA = TABLA_VDDD_CDC_D_CUR_MAX,
- },
- {
- .name = "CDC_VDDA_A_1P2V",
- .min_uV = 1225000,
- .max_uV = 1225000,
- .optimum_uA = TABLA_VDDD_CDC_A_CUR_MAX,
- },
-};
-
-static int tabla_device_init(struct tabla *tabla, int irq)
-{
- int ret;
- struct mfd_cell *tabla_dev;
- int tabla_dev_size;
-
- mutex_init(&tabla->io_lock);
- mutex_init(&tabla->xfer_lock);
-
- mutex_init(&tabla->pm_lock);
- tabla->wlock_holders = 0;
- tabla->pm_state = TABLA_PM_SLEEPABLE;
- init_waitqueue_head(&tabla->pm_wq);
- wake_lock_init(&tabla->wlock, WAKE_LOCK_IDLE, "wcd9310-irq");
-
- dev_set_drvdata(tabla->dev, tabla);
-
- tabla_bring_up(tabla);
-
- ret = tabla_irq_init(tabla);
- if (ret) {
- pr_err("IRQ initialization failed\n");
- goto err;
- }
- tabla->version = tabla_reg_read(tabla, TABLA_A_CHIP_VERSION) & 0x1F;
- pr_info("%s : Tabla version %u initialized\n",
- __func__, tabla->version);
-
- if (TABLA_IS_1_X(tabla->version)) {
- tabla_dev = tabla1x_devs;
- tabla_dev_size = ARRAY_SIZE(tabla1x_devs);
- } else {
- tabla_dev = tabla_devs;
- tabla_dev_size = ARRAY_SIZE(tabla_devs);
- }
- ret = mfd_add_devices(tabla->dev, -1,
- tabla_dev, tabla_dev_size,
- NULL, 0);
- if (ret != 0) {
- dev_err(tabla->dev, "Failed to add children: %d\n", ret);
- goto err_irq;
- }
-
- tabla->version = tabla_reg_read(tabla, TABLA_A_CHIP_VERSION) & 0x1F;
- pr_info("%s : Tabla version %u initialized\n",
- __func__, tabla->version);
-
- return ret;
-err_irq:
- tabla_irq_exit(tabla);
-err:
- tabla_bring_down(tabla);
- wake_lock_destroy(&tabla->wlock);
- mutex_destroy(&tabla->pm_lock);
- mutex_destroy(&tabla->io_lock);
- mutex_destroy(&tabla->xfer_lock);
- return ret;
-}
-
-static void tabla_device_exit(struct tabla *tabla)
-{
- tabla_irq_exit(tabla);
- tabla_bring_down(tabla);
- tabla_free_reset(tabla);
- mutex_destroy(&tabla->pm_lock);
- wake_lock_destroy(&tabla->wlock);
- mutex_destroy(&tabla->io_lock);
- mutex_destroy(&tabla->xfer_lock);
-}
-
-
-#ifdef CONFIG_DEBUG_FS
-struct tabla *debugTabla;
-
-static struct dentry *debugfs_tabla_dent;
-static struct dentry *debugfs_peek;
-static struct dentry *debugfs_poke;
-
-static unsigned char read_data;
-
-static int codec_debug_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static int get_parameters(char *buf, long int *param1, int num_of_par)
-{
- char *token;
- int base, cnt;
-
- token = strsep(&buf, " ");
-
- for (cnt = 0; cnt < num_of_par; cnt++) {
- if (token != NULL) {
- if ((token[1] == 'x') || (token[1] == 'X'))
- base = 16;
- else
- base = 10;
-
- if (strict_strtoul(token, base, ¶m1[cnt]) != 0)
- return -EINVAL;
-
- token = strsep(&buf, " ");
- } else
- return -EINVAL;
- }
- return 0;
-}
-
-static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- char lbuf[8];
-
- snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
- return simple_read_from_buffer(ubuf, count, ppos, lbuf,
- strnlen(lbuf, 7));
-}
-
-
-static ssize_t codec_debug_write(struct file *filp,
- const char __user *ubuf, size_t cnt, loff_t *ppos)
-{
- char *access_str = filp->private_data;
- char lbuf[32];
- int rc;
- long int param[5];
-
- if (cnt > sizeof(lbuf) - 1)
- return -EINVAL;
-
- rc = copy_from_user(lbuf, ubuf, cnt);
- if (rc)
- return -EFAULT;
-
- lbuf[cnt] = '\0';
-
- if (!strncmp(access_str, "poke", 6)) {
- /* write */
- rc = get_parameters(lbuf, param, 2);
- if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) &&
- (rc == 0))
- tabla_interface_reg_write(debugTabla, param[0],
- param[1]);
- else
- rc = -EINVAL;
- } else if (!strncmp(access_str, "peek", 6)) {
- /* read */
- rc = get_parameters(lbuf, param, 1);
- if ((param[0] <= 0x3FF) && (rc == 0))
- read_data = tabla_interface_reg_read(debugTabla,
- param[0]);
- else
- rc = -EINVAL;
- }
-
- if (rc == 0)
- rc = cnt;
- else
- pr_err("%s: rc = %d\n", __func__, rc);
-
- return rc;
-}
-
-static const struct file_operations codec_debug_ops = {
- .open = codec_debug_open,
- .write = codec_debug_write,
- .read = codec_debug_read
-};
-#endif
-
-static int tabla_enable_supplies(struct tabla *tabla)
-{
- int ret;
- int i;
-
- tabla->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
- ARRAY_SIZE(tabla_regulators),
- GFP_KERNEL);
- if (!tabla->supplies) {
- ret = -ENOMEM;
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++)
- tabla->supplies[i].supply = tabla_regulators[i].name;
-
- ret = regulator_bulk_get(tabla->dev, ARRAY_SIZE(tabla_regulators),
- tabla->supplies);
- if (ret != 0) {
- dev_err(tabla->dev, "Failed to get supplies: err = %d\n", ret);
- goto err_supplies;
- }
-
- for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
- ret = regulator_set_voltage(tabla->supplies[i].consumer,
- tabla_regulators[i].min_uV, tabla_regulators[i].max_uV);
- if (ret) {
- pr_err("%s: Setting regulator voltage failed for "
- "regulator %s err = %d\n", __func__,
- tabla->supplies[i].supply, ret);
- goto err_get;
- }
-
- ret = regulator_set_optimum_mode(tabla->supplies[i].consumer,
- tabla_regulators[i].optimum_uA);
- if (ret < 0) {
- pr_err("%s: Setting regulator optimum mode failed for "
- "regulator %s err = %d\n", __func__,
- tabla->supplies[i].supply, ret);
- goto err_get;
- }
- }
-
- ret = regulator_bulk_enable(ARRAY_SIZE(tabla_regulators),
- tabla->supplies);
- if (ret != 0) {
- dev_err(tabla->dev, "Failed to enable supplies: err = %d\n",
- ret);
- goto err_configure;
- }
- return ret;
-
-err_configure:
- for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
- regulator_set_voltage(tabla->supplies[i].consumer, 0,
- tabla_regulators[i].max_uV);
- regulator_set_optimum_mode(tabla->supplies[i].consumer, 0);
- }
-err_get:
- regulator_bulk_free(ARRAY_SIZE(tabla_regulators), tabla->supplies);
-err_supplies:
- kfree(tabla->supplies);
-err:
- return ret;
-}
-
-static void tabla_disable_supplies(struct tabla *tabla)
-{
- int i;
-
- regulator_bulk_disable(ARRAY_SIZE(tabla_regulators),
- tabla->supplies);
- for (i = 0; i < ARRAY_SIZE(tabla_regulators); i++) {
- regulator_set_voltage(tabla->supplies[i].consumer, 0,
- tabla_regulators[i].max_uV);
- regulator_set_optimum_mode(tabla->supplies[i].consumer, 0);
- }
- regulator_bulk_free(ARRAY_SIZE(tabla_regulators), tabla->supplies);
- kfree(tabla->supplies);
-}
-
-int tabla_get_intf_type(void)
-{
- return tabla_intf;
-}
-EXPORT_SYMBOL_GPL(tabla_get_intf_type);
-
-struct tabla_i2c *get_i2c_tabla_device_info(u16 reg)
-{
- u16 mask = 0x0f00;
- int value = 0;
- struct tabla_i2c *tabla = NULL;
- value = ((reg & mask) >> 8) & 0x000f;
- switch (value) {
- case 0:
- tabla = &tabla_modules[0];
- break;
- case 1:
- tabla = &tabla_modules[1];
- break;
- case 2:
- tabla = &tabla_modules[2];
- break;
- case 3:
- tabla = &tabla_modules[3];
- break;
- default:
- break;
- }
- return tabla;
-}
-
-int tabla_i2c_write_device(u16 reg, u8 *value,
- u32 bytes)
-{
-
- struct i2c_msg *msg;
- int ret = 0;
- u8 reg_addr = 0;
- u8 data[bytes + 1];
- struct tabla_i2c *tabla;
-
- tabla = get_i2c_tabla_device_info(reg);
- if (tabla->client == NULL) {
- pr_err("failed to get device info\n");
- return -ENODEV;
- }
- reg_addr = (u8)reg;
- msg = &tabla->xfer_msg[0];
- msg->addr = tabla->client->addr;
- msg->len = bytes + 1;
- msg->flags = 0;
- data[0] = reg;
- data[1] = *value;
- msg->buf = data;
- ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 1);
- /* Try again if the write fails */
- if (ret != 1) {
- ret = i2c_transfer(tabla->client->adapter,
- tabla->xfer_msg, 1);
- if (ret != 1) {
- pr_err("failed to write the device\n");
- return ret;
- }
- }
- pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
- return 0;
-}
-
-
-int tabla_i2c_read_device(unsigned short reg,
- int bytes, unsigned char *dest)
-{
- struct i2c_msg *msg;
- int ret = 0;
- u8 reg_addr = 0;
- struct tabla_i2c *tabla;
- u8 i = 0;
-
- tabla = get_i2c_tabla_device_info(reg);
- if (tabla->client == NULL) {
- pr_err("failed to get device info\n");
- return -ENODEV;
- }
- for (i = 0; i < bytes; i++) {
- reg_addr = (u8)reg++;
- msg = &tabla->xfer_msg[0];
- msg->addr = tabla->client->addr;
- msg->len = 1;
- msg->flags = 0;
- msg->buf = ®_addr;
-
- msg = &tabla->xfer_msg[1];
- msg->addr = tabla->client->addr;
- msg->len = 1;
- msg->flags = I2C_M_RD;
- msg->buf = dest++;
- ret = i2c_transfer(tabla->client->adapter, tabla->xfer_msg, 2);
-
- /* Try again if read fails first time */
- if (ret != 2) {
- ret = i2c_transfer(tabla->client->adapter,
- tabla->xfer_msg, 2);
- if (ret != 2) {
- pr_err("failed to read tabla register\n");
- return ret;
- }
- }
- }
- return 0;
-}
-
-int tabla_i2c_read(struct tabla *tabla, unsigned short reg,
- int bytes, void *dest, bool interface_reg)
-{
- return tabla_i2c_read_device(reg, bytes, dest);
-}
-
-int tabla_i2c_write(struct tabla *tabla, unsigned short reg,
- int bytes, void *src, bool interface_reg)
-{
- return tabla_i2c_write_device(reg, src, bytes);
-}
-
-static int __devinit tabla_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct tabla *tabla;
- struct tabla_pdata *pdata = client->dev.platform_data;
- int val = 0;
- int ret = 0;
- static int device_id;
-
- if (device_id > 0) {
- tabla_modules[device_id++].client = client;
- pr_info("probe for other slaves devices of tabla\n");
- return ret;
- }
-
- tabla = kzalloc(sizeof(struct tabla), GFP_KERNEL);
- if (tabla == NULL) {
- pr_err("%s: error, allocation failed\n", __func__);
- ret = -ENOMEM;
- goto fail;
- }
-
- if (!pdata) {
- dev_dbg(&client->dev, "no platform data?\n");
- ret = -EINVAL;
- goto fail;
- }
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
- dev_dbg(&client->dev, "can't talk I2C?\n");
- ret = -EIO;
- goto fail;
- }
- tabla->dev = &client->dev;
- tabla->reset_gpio = pdata->reset_gpio;
-
- ret = tabla_enable_supplies(tabla);
- if (ret) {
- pr_err("%s: Fail to enable Tabla supplies\n", __func__);
- goto err_tabla;
- }
-
- usleep_range(5, 5);
- ret = tabla_reset(tabla);
- if (ret) {
- pr_err("%s: Resetting Tabla failed\n", __func__);
- goto err_supplies;
- }
- tabla_modules[device_id++].client = client;
-
- tabla->read_dev = tabla_i2c_read;
- tabla->write_dev = tabla_i2c_write;
- tabla->irq = pdata->irq;
- tabla->irq_base = pdata->irq_base;
-
- /*read the tabla status before initializing the device type*/
- ret = tabla_read(tabla, TABLA_A_CHIP_STATUS, 1, &val, 0);
- if ((ret < 0) || (val != TABLA_I2C_MODE)) {
- pr_err("failed to read the tabla status\n");
- goto err_device_init;
- }
-
- ret = tabla_device_init(tabla, tabla->irq);
- if (ret) {
- pr_err("%s: error, initializing device failed\n", __func__);
- goto err_device_init;
- }
- tabla_intf = TABLA_INTERFACE_TYPE_I2C;
-
- return ret;
-err_device_init:
- tabla_free_reset(tabla);
-err_supplies:
- tabla_disable_supplies(tabla);
-err_tabla:
- kfree(tabla);
-fail:
- return ret;
-}
-
-static int __devexit tabla_i2c_remove(struct i2c_client *client)
-{
- struct tabla *tabla;
-
- pr_debug("exit\n");
- tabla = dev_get_drvdata(&client->dev);
- tabla_device_exit(tabla);
- tabla_disable_supplies(tabla);
- kfree(tabla);
- return 0;
-}
-
-static int tabla_slim_probe(struct slim_device *slim)
-{
- struct tabla *tabla;
- struct tabla_pdata *pdata;
- int ret = 0;
- int sgla_retry_cnt;
-
- dev_info(&slim->dev, "Initialized slim device %s\n", slim->name);
- pdata = slim->dev.platform_data;
-
- if (!pdata) {
- dev_err(&slim->dev, "Error, no platform data\n");
- ret = -EINVAL;
- goto err;
- }
-
- tabla = kzalloc(sizeof(struct tabla), GFP_KERNEL);
- if (tabla == NULL) {
- pr_err("%s: error, allocation failed\n", __func__);
- ret = -ENOMEM;
- goto err;
- }
- if (!slim->ctrl) {
- pr_err("Error, no SLIMBUS control data\n");
- ret = -EINVAL;
- goto err_tabla;
- }
- tabla->slim = slim;
- slim_set_clientdata(slim, tabla);
- tabla->reset_gpio = pdata->reset_gpio;
- tabla->dev = &slim->dev;
-
- ret = tabla_enable_supplies(tabla);
- if (ret) {
- pr_err("%s: Fail to enable Tabla supplies\n", __func__);
- goto err_tabla;
- }
- usleep_range(5, 5);
-
- ret = tabla_reset(tabla);
- if (ret) {
- pr_err("%s: Resetting Tabla failed\n", __func__);
- goto err_supplies;
- }
-
- ret = slim_get_logical_addr(tabla->slim, tabla->slim->e_addr,
- ARRAY_SIZE(tabla->slim->e_addr), &tabla->slim->laddr);
- if (ret) {
- pr_err("fail to get slimbus logical address %d\n", ret);
- goto err_reset;
- }
- tabla->read_dev = tabla_slim_read_device;
- tabla->write_dev = tabla_slim_write_device;
- tabla->irq = pdata->irq;
- tabla->irq_base = pdata->irq_base;
- tabla_pgd_la = tabla->slim->laddr;
-
- if (pdata->num_irqs < TABLA_NUM_IRQS) {
- pr_err("%s: Error, not enough interrupt lines allocated\n",
- __func__);
- goto err_reset;
- }
-
- tabla->slim_slave = &pdata->slimbus_slave_device;
-
- ret = slim_add_device(slim->ctrl, tabla->slim_slave);
- if (ret) {
- pr_err("%s: error, adding SLIMBUS device failed\n", __func__);
- goto err_reset;
- }
-
- sgla_retry_cnt = 0;
-
- while (1) {
- ret = slim_get_logical_addr(tabla->slim_slave,
- tabla->slim_slave->e_addr,
- ARRAY_SIZE(tabla->slim_slave->e_addr),
- &tabla->slim_slave->laddr);
- if (ret) {
- if (sgla_retry_cnt++ < TABLA_SLIM_GLA_MAX_RETRIES) {
- /* Give SLIMBUS slave time to report present
- and be ready.
- */
- usleep_range(1000, 1000);
- pr_debug("%s: retry slim_get_logical_addr()\n",
- __func__);
- continue;
- }
- pr_err("fail to get slimbus slave logical address"
- " %d\n", ret);
- goto err_slim_add;
- }
- break;
- }
- tabla_inf_la = tabla->slim_slave->laddr;
- tabla_intf = TABLA_INTERFACE_TYPE_SLIMBUS;
-
- ret = tabla_device_init(tabla, tabla->irq);
- if (ret) {
- pr_err("%s: error, initializing device failed\n", __func__);
- goto err_slim_add;
- }
- tabla_init_slimslave(tabla, tabla_pgd_la);
-#ifdef CONFIG_DEBUG_FS
- debugTabla = tabla;
-
- debugfs_tabla_dent = debugfs_create_dir
- ("wcd9310_slimbus_interface_device", 0);
- if (!IS_ERR(debugfs_tabla_dent)) {
- debugfs_peek = debugfs_create_file("peek",
- S_IFREG | S_IRUGO, debugfs_tabla_dent,
- (void *) "peek", &codec_debug_ops);
-
- debugfs_poke = debugfs_create_file("poke",
- S_IFREG | S_IRUGO, debugfs_tabla_dent,
- (void *) "poke", &codec_debug_ops);
- }
-#endif
-
- return ret;
-
-err_slim_add:
- slim_remove_device(tabla->slim_slave);
-err_reset:
- tabla_free_reset(tabla);
-err_supplies:
- tabla_disable_supplies(tabla);
-err_tabla:
- kfree(tabla);
-err:
- return ret;
-}
-
-static int tabla_slim_remove(struct slim_device *pdev)
-{
- struct tabla *tabla;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove(debugfs_peek);
- debugfs_remove(debugfs_poke);
- debugfs_remove(debugfs_tabla_dent);
-#endif
-
- tabla = slim_get_devicedata(pdev);
- tabla_deinit_slimslave(tabla);
- tabla_device_exit(tabla);
- tabla_disable_supplies(tabla);
- slim_remove_device(tabla->slim_slave);
- kfree(tabla);
-
- return 0;
-}
-
-static int tabla_resume(struct tabla *tabla)
-{
- int ret = 0;
-
- pr_debug("%s: enter\n", __func__);
- mutex_lock(&tabla->pm_lock);
- if (tabla->pm_state == TABLA_PM_ASLEEP) {
- pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
- tabla->pm_state, tabla->wlock_holders);
- tabla->pm_state = TABLA_PM_SLEEPABLE;
- } else {
- pr_warn("%s: system is already awake, state %d wlock %d\n",
- __func__, tabla->pm_state, tabla->wlock_holders);
- }
- mutex_unlock(&tabla->pm_lock);
- wake_up_all(&tabla->pm_wq);
-
- return ret;
-}
-
-static int tabla_slim_resume(struct slim_device *sldev)
-{
- struct tabla *tabla = slim_get_devicedata(sldev);
- return tabla_resume(tabla);
-}
-
-static int tabla_i2c_resume(struct i2c_client *i2cdev)
-{
- struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
- return tabla_resume(tabla);
-}
-
-static int tabla_suspend(struct tabla *tabla, pm_message_t pmesg)
-{
- int ret = 0;
-
- pr_debug("%s: enter\n", __func__);
- /* wake_lock() can be called after this suspend chain call started.
- * thus suspend can be called while wlock is being held */
- mutex_lock(&tabla->pm_lock);
- if (tabla->pm_state == TABLA_PM_SLEEPABLE) {
- pr_debug("%s: suspending system, state %d, wlock %d\n",
- __func__, tabla->pm_state, tabla->wlock_holders);
- tabla->pm_state = TABLA_PM_ASLEEP;
- } else if (tabla->pm_state == TABLA_PM_AWAKE) {
- /* unlock to wait for pm_state == TABLA_PM_SLEEPABLE
- * then set to TABLA_PM_ASLEEP */
- pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
- __func__, tabla->pm_state, tabla->wlock_holders);
- mutex_unlock(&tabla->pm_lock);
- if (!(wait_event_timeout(tabla->pm_wq,
- tabla_pm_cmpxchg(tabla,
- TABLA_PM_SLEEPABLE,
- TABLA_PM_ASLEEP) ==
- TABLA_PM_SLEEPABLE,
- HZ))) {
- pr_debug("%s: suspend failed state %d, wlock %d\n",
- __func__, tabla->pm_state,
- tabla->wlock_holders);
- ret = -EBUSY;
- } else {
- pr_debug("%s: done, state %d, wlock %d\n", __func__,
- tabla->pm_state, tabla->wlock_holders);
- }
- mutex_lock(&tabla->pm_lock);
- } else if (tabla->pm_state == TABLA_PM_ASLEEP) {
- pr_warn("%s: system is already suspended, state %d, wlock %dn",
- __func__, tabla->pm_state, tabla->wlock_holders);
- }
- mutex_unlock(&tabla->pm_lock);
-
- return ret;
-}
-
-static int tabla_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
-{
- struct tabla *tabla = slim_get_devicedata(sldev);
- return tabla_suspend(tabla, pmesg);
-}
-
-static int tabla_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
-{
- struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
- return tabla_suspend(tabla, pmesg);
-}
-
-static const struct slim_device_id slimtest_id[] = {
- {"tabla-slim", 0},
- {}
-};
-
-static struct slim_driver tabla_slim_driver = {
- .driver = {
- .name = "tabla-slim",
- .owner = THIS_MODULE,
- },
- .probe = tabla_slim_probe,
- .remove = tabla_slim_remove,
- .id_table = slimtest_id,
- .resume = tabla_slim_resume,
- .suspend = tabla_slim_suspend,
-};
-
-static const struct slim_device_id slimtest2x_id[] = {
- {"tabla2x-slim", 0},
- {}
-};
-
-static struct slim_driver tabla2x_slim_driver = {
- .driver = {
- .name = "tabla2x-slim",
- .owner = THIS_MODULE,
- },
- .probe = tabla_slim_probe,
- .remove = tabla_slim_remove,
- .id_table = slimtest2x_id,
- .resume = tabla_slim_resume,
- .suspend = tabla_slim_suspend,
-};
-
-#define TABLA_I2C_TOP_LEVEL 0
-#define TABLA_I2C_ANALOG 1
-#define TABLA_I2C_DIGITAL_1 2
-#define TABLA_I2C_DIGITAL_2 3
-
-static struct i2c_device_id tabla_id_table[] = {
- {"tabla top level", TABLA_I2C_TOP_LEVEL},
- {"tabla analog", TABLA_I2C_TOP_LEVEL},
- {"tabla digital1", TABLA_I2C_TOP_LEVEL},
- {"tabla digital2", TABLA_I2C_TOP_LEVEL},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, tabla_id_table);
-
-static struct i2c_driver tabla_i2c_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "tabla-i2c-core",
- },
- .id_table = tabla_id_table,
- .probe = tabla_i2c_probe,
- .remove = __devexit_p(tabla_i2c_remove),
- .resume = tabla_i2c_resume,
- .suspend = tabla_i2c_suspend,
-};
-
-static int __init tabla_init(void)
-{
- int ret1, ret2, ret3;
-
- ret1 = slim_driver_register(&tabla_slim_driver);
- if (ret1 != 0)
- pr_err("Failed to register tabla SB driver: %d\n", ret1);
-
- ret2 = slim_driver_register(&tabla2x_slim_driver);
- if (ret2 != 0)
- pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
-
- ret3 = i2c_add_driver(&tabla_i2c_driver);
- if (ret3 != 0)
- pr_err("failed to add the I2C driver\n");
-
- return (ret1 && ret2 && ret3) ? -1 : 0;
-}
-module_init(tabla_init);
-
-static void __exit tabla_exit(void)
-{
-}
-module_exit(tabla_exit);
-
-MODULE_DESCRIPTION("Tabla core driver");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
deleted file mode 100644
index c6a9c23..0000000
--- a/drivers/mfd/wcd9310-irq.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* 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
- * 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 <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/irq.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/interrupt.h>
-
-#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
-#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
-
-struct tabla_irq {
- bool level;
-};
-
-static struct tabla_irq tabla_irqs[TABLA_NUM_IRQS] = {
- [0] = { .level = 1},
-/* All other tabla interrupts are edge triggered */
-};
-
-static inline int irq_to_tabla_irq(struct tabla *tabla, int irq)
-{
- return irq - tabla->irq_base;
-}
-
-static void tabla_irq_lock(struct irq_data *data)
-{
- struct tabla *tabla = irq_data_get_irq_chip_data(data);
- mutex_lock(&tabla->irq_lock);
-}
-
-static void tabla_irq_sync_unlock(struct irq_data *data)
-{
- struct tabla *tabla = irq_data_get_irq_chip_data(data);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tabla->irq_masks_cur); i++) {
- /* If there's been a change in the mask write it back
- * to the hardware.
- */
- if (tabla->irq_masks_cur[i] != tabla->irq_masks_cache[i]) {
- tabla->irq_masks_cache[i] = tabla->irq_masks_cur[i];
- tabla_reg_write(tabla, TABLA_A_INTR_MASK0+i,
- tabla->irq_masks_cur[i]);
- }
- }
-
- mutex_unlock(&tabla->irq_lock);
-}
-
-static void tabla_irq_enable(struct irq_data *data)
-{
- struct tabla *tabla = irq_data_get_irq_chip_data(data);
- int tabla_irq = irq_to_tabla_irq(tabla, data->irq);
- tabla->irq_masks_cur[BIT_BYTE(tabla_irq)] &=
- ~(BYTE_BIT_MASK(tabla_irq));
-}
-
-static void tabla_irq_disable(struct irq_data *data)
-{
- struct tabla *tabla = irq_data_get_irq_chip_data(data);
- int tabla_irq = irq_to_tabla_irq(tabla, data->irq);
- tabla->irq_masks_cur[BIT_BYTE(tabla_irq)] |= BYTE_BIT_MASK(tabla_irq);
-}
-
-static struct irq_chip tabla_irq_chip = {
- .name = "tabla",
- .irq_bus_lock = tabla_irq_lock,
- .irq_bus_sync_unlock = tabla_irq_sync_unlock,
- .irq_disable = tabla_irq_disable,
- .irq_enable = tabla_irq_enable,
-};
-
-enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
- enum tabla_pm_state n)
-{
- enum tabla_pm_state old;
- mutex_lock(&tabla->pm_lock);
- old = tabla->pm_state;
- if (old == o)
- tabla->pm_state = n;
- mutex_unlock(&tabla->pm_lock);
- return old;
-}
-EXPORT_SYMBOL_GPL(tabla_pm_cmpxchg);
-
-void tabla_lock_sleep(struct tabla *tabla)
-{
- enum tabla_pm_state os;
-
- /* tabla_{lock/unlock}_sleep will be called by tabla_irq_thread
- * and its subroutines only motly.
- * but btn0_lpress_fn is not tabla_irq_thread's subroutine and
- * it can race with tabla_irq_thread.
- * so need to embrace wlock_holders with mutex.
- */
- mutex_lock(&tabla->pm_lock);
- if (tabla->wlock_holders++ == 0)
- wake_lock(&tabla->wlock);
- mutex_unlock(&tabla->pm_lock);
- while (!wait_event_timeout(tabla->pm_wq,
- ((os = tabla_pm_cmpxchg(tabla, TABLA_PM_SLEEPABLE,
- TABLA_PM_AWAKE)) ==
- TABLA_PM_SLEEPABLE ||
- (os == TABLA_PM_AWAKE)),
- 5 * HZ)) {
- pr_err("%s: system didn't resume within 5000ms, state %d, "
- "wlock %d\n", __func__, tabla->pm_state,
- tabla->wlock_holders);
- WARN_ON_ONCE(1);
- }
- wake_up_all(&tabla->pm_wq);
-}
-EXPORT_SYMBOL_GPL(tabla_lock_sleep);
-
-void tabla_unlock_sleep(struct tabla *tabla)
-{
- mutex_lock(&tabla->pm_lock);
- if (--tabla->wlock_holders == 0) {
- tabla->pm_state = TABLA_PM_SLEEPABLE;
- wake_unlock(&tabla->wlock);
- }
- mutex_unlock(&tabla->pm_lock);
- wake_up_all(&tabla->pm_wq);
-}
-EXPORT_SYMBOL_GPL(tabla_unlock_sleep);
-
-static irqreturn_t tabla_irq_thread(int irq, void *data)
-{
- int ret;
- struct tabla *tabla = data;
- u8 status[TABLA_NUM_IRQ_REGS];
- unsigned int i;
-
- tabla_lock_sleep(tabla);
- ret = tabla_bulk_read(tabla, TABLA_A_INTR_STATUS0,
- TABLA_NUM_IRQ_REGS, status);
- if (ret < 0) {
- dev_err(tabla->dev, "Failed to read interrupt status: %d\n",
- ret);
- tabla_unlock_sleep(tabla);
- return IRQ_NONE;
- }
- /* Apply masking */
- for (i = 0; i < TABLA_NUM_IRQ_REGS; i++)
- status[i] &= ~tabla->irq_masks_cur[i];
-
- /* Find out which interrupt was triggered and call that interrupt's
- * handler function
- */
- for (i = 0; i < TABLA_NUM_IRQS; i++) {
- if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
- if ((i <= TABLA_IRQ_MBHC_INSERTION) &&
- (i >= TABLA_IRQ_MBHC_REMOVAL)) {
- tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
- BIT_BYTE(i), BYTE_BIT_MASK(i));
- if (tabla_get_intf_type() ==
- TABLA_INTERFACE_TYPE_I2C)
- tabla_reg_write(tabla,
- TABLA_A_INTR_MODE, 0x02);
- handle_nested_irq(tabla->irq_base + i);
- } else {
- handle_nested_irq(tabla->irq_base + i);
- tabla_reg_write(tabla, TABLA_A_INTR_CLEAR0 +
- BIT_BYTE(i), BYTE_BIT_MASK(i));
- if (tabla_get_intf_type() ==
- TABLA_INTERFACE_TYPE_I2C)
- tabla_reg_write(tabla,
- TABLA_A_INTR_MODE, 0x02);
- }
- break;
- }
- }
- tabla_unlock_sleep(tabla);
-
- return IRQ_HANDLED;
-}
-
-int tabla_irq_init(struct tabla *tabla)
-{
- int ret;
- unsigned int i, cur_irq;
-
- mutex_init(&tabla->irq_lock);
-
- if (!tabla->irq) {
- dev_warn(tabla->dev,
- "No interrupt specified, no interrupts\n");
- tabla->irq_base = 0;
- return 0;
- }
-
- if (!tabla->irq_base) {
- dev_err(tabla->dev,
- "No interrupt base specified, no interrupts\n");
- return 0;
- }
- /* Mask the individual interrupt sources */
- for (i = 0, cur_irq = tabla->irq_base; i < TABLA_NUM_IRQS; i++,
- cur_irq++) {
-
- irq_set_chip_data(cur_irq, tabla);
-
- if (tabla_irqs[i].level)
- irq_set_chip_and_handler(cur_irq, &tabla_irq_chip,
- handle_level_irq);
- else
- irq_set_chip_and_handler(cur_irq, &tabla_irq_chip,
- handle_edge_irq);
-
- irq_set_nested_thread(cur_irq, 1);
-
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
- set_irq_flags(cur_irq, IRQF_VALID);
-#else
- set_irq_noprobe(cur_irq);
-#endif
-
- tabla->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
- tabla->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
- tabla->irq_level[BIT_BYTE(i)] |= tabla_irqs[i].level <<
- (i % BITS_PER_BYTE);
- }
- for (i = 0; i < TABLA_NUM_IRQ_REGS; i++) {
- /* Initialize interrupt mask and level registers */
- tabla_reg_write(tabla, TABLA_A_INTR_LEVEL0 + i,
- tabla->irq_level[i]);
- tabla_reg_write(tabla, TABLA_A_INTR_MASK0 + i,
- tabla->irq_masks_cur[i]);
- }
-
- ret = request_threaded_irq(tabla->irq, NULL, tabla_irq_thread,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
- "tabla", tabla);
- if (ret != 0)
- dev_err(tabla->dev, "Failed to request IRQ %d: %d\n",
- tabla->irq, ret);
- else {
- ret = enable_irq_wake(tabla->irq);
- if (ret == 0) {
- ret = device_init_wakeup(tabla->dev, 1);
- if (ret) {
- dev_err(tabla->dev, "Failed to init device"
- "wakeup : %d\n", ret);
- disable_irq_wake(tabla->irq);
- }
- } else
- dev_err(tabla->dev, "Failed to set wake interrupt on"
- " IRQ %d: %d\n", tabla->irq, ret);
- if (ret)
- free_irq(tabla->irq, tabla);
- }
-
- if (ret)
- mutex_destroy(&tabla->irq_lock);
-
- return ret;
-}
-
-void tabla_irq_exit(struct tabla *tabla)
-{
- if (tabla->irq) {
- disable_irq_wake(tabla->irq);
- free_irq(tabla->irq, tabla);
- device_init_wakeup(tabla->dev, 0);
- }
- mutex_destroy(&tabla->irq_lock);
-}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
new file mode 100644
index 0000000..59a4283
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -0,0 +1,1126 @@
+/* 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
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/i2c.h>
+#include <sound/soc.h>
+
+#define WCD9XXX_SLIM_GLA_MAX_RETRIES 5
+#define WCD9XXX_REGISTER_START_OFFSET 0x800
+#define WCD9XXX_SLIM_RW_MAX_TRIES 3
+
+#define MAX_WCD9XXX_DEVICE 4
+#define WCD9XXX_I2C_MODE 0x03
+
+struct wcd9xxx_i2c {
+ struct i2c_client *client;
+ struct i2c_msg xfer_msg[2];
+ struct mutex xfer_lock;
+ int mod_id;
+};
+
+struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
+static int wcd9xxx_intf;
+
+static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *dest, bool interface_reg)
+{
+ int ret;
+ u8 *buf = dest;
+
+ if (bytes <= 0) {
+ dev_err(wcd9xxx->dev, "Invalid byte read length %d\n", bytes);
+ return -EINVAL;
+ }
+
+ ret = wcd9xxx->read_dev(wcd9xxx, reg, bytes, dest, interface_reg);
+ if (ret < 0) {
+ dev_err(wcd9xxx->dev, "Codec read failed\n");
+ return ret;
+ } else
+ dev_dbg(wcd9xxx->dev, "Read 0x%02x from R%d(0x%x)\n",
+ *buf, reg, reg);
+
+ return 0;
+}
+int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+{
+ u8 val;
+ int ret;
+
+ mutex_lock(&wcd9xxx->io_lock);
+ ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, false);
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ if (ret < 0)
+ return ret;
+ else
+ return val;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_reg_read);
+
+static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *src, bool interface_reg)
+{
+ u8 *buf = src;
+
+ if (bytes <= 0) {
+ pr_err("%s: Error, invalid write length\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(wcd9xxx->dev, "Write %02x to R%d(0x%x)\n",
+ *buf, reg, reg);
+
+ return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
+}
+
+int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ u8 val)
+{
+ int ret;
+
+ mutex_lock(&wcd9xxx->io_lock);
+ ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, false);
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_reg_write);
+
+static u8 wcd9xxx_pgd_la;
+static u8 wcd9xxx_inf_la;
+
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+{
+ u8 val;
+ int ret;
+
+ mutex_lock(&wcd9xxx->io_lock);
+ ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, true);
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ if (ret < 0)
+ return ret;
+ else
+ return val;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_read);
+
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ u8 val)
+{
+ int ret;
+
+ mutex_lock(&wcd9xxx->io_lock);
+ ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, true);
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_write);
+
+int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int count, u8 *buf)
+{
+ int ret;
+
+ mutex_lock(&wcd9xxx->io_lock);
+
+ ret = wcd9xxx_read(wcd9xxx, reg, count, buf, false);
+
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_bulk_read);
+
+int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int count, u8 *buf)
+{
+ int ret;
+
+ mutex_lock(&wcd9xxx->io_lock);
+
+ ret = wcd9xxx_write(wcd9xxx, reg, count, buf, false);
+
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_bulk_write);
+
+static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *dest, bool interface)
+{
+ int ret;
+ struct slim_ele_access msg;
+ int slim_read_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+ msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+ msg.num_bytes = bytes;
+ msg.comp = NULL;
+
+ while (1) {
+ mutex_lock(&wcd9xxx->xfer_lock);
+ ret = slim_request_val_element(interface ?
+ wcd9xxx->slim_slave : wcd9xxx->slim,
+ &msg, dest, bytes);
+ mutex_unlock(&wcd9xxx->xfer_lock);
+ if (likely(ret == 0) || (--slim_read_tries == 0))
+ break;
+ usleep_range(5000, 5000);
+ }
+
+ if (ret)
+ pr_err("%s: Error, Codec read failed (%d)\n", __func__, ret);
+
+ return ret;
+}
+/* Interface specifies whether the write is to the interface or general
+ * registers.
+ */
+static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx,
+ unsigned short reg, int bytes, void *src, bool interface)
+{
+ int ret;
+ struct slim_ele_access msg;
+ int slim_write_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+ msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+ msg.num_bytes = bytes;
+ msg.comp = NULL;
+
+ while (1) {
+ mutex_lock(&wcd9xxx->xfer_lock);
+ ret = slim_change_val_element(interface ?
+ wcd9xxx->slim_slave : wcd9xxx->slim,
+ &msg, src, bytes);
+ mutex_unlock(&wcd9xxx->xfer_lock);
+ if (likely(ret == 0) || (--slim_write_tries == 0))
+ break;
+ usleep_range(5000, 5000);
+ }
+
+ if (ret)
+ pr_err("%s: Error, Codec write failed (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static struct mfd_cell tabla1x_devs[] = {
+ {
+ .name = "tabla1x_codec",
+ },
+};
+
+static struct mfd_cell tabla_devs[] = {
+ {
+ .name = "tabla_codec",
+ },
+};
+
+static struct mfd_cell sitar_devs[] = {
+ {
+ .name = "sitar_codec",
+ },
+};
+
+static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
+{
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
+ usleep_range(5000, 5000);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
+}
+
+static void wcd9xxx_bring_down(struct wcd9xxx *wcd9xxx)
+{
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
+}
+
+static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
+{
+ int ret;
+
+ if (wcd9xxx->reset_gpio) {
+ ret = gpio_request(wcd9xxx->reset_gpio, "CDC_RESET");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n", __func__,
+ wcd9xxx->reset_gpio);
+ wcd9xxx->reset_gpio = 0;
+ return ret;
+ }
+
+ gpio_direction_output(wcd9xxx->reset_gpio, 1);
+ msleep(20);
+ gpio_direction_output(wcd9xxx->reset_gpio, 0);
+ msleep(20);
+ gpio_direction_output(wcd9xxx->reset_gpio, 1);
+ msleep(20);
+ }
+ return 0;
+}
+
+static void wcd9xxx_free_reset(struct wcd9xxx *wcd9xxx)
+{
+ if (wcd9xxx->reset_gpio) {
+ gpio_free(wcd9xxx->reset_gpio);
+ wcd9xxx->reset_gpio = 0;
+ }
+}
+
+static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
+{
+ int ret;
+ u8 idbyte_0, idbyte_1, idbyte_2, idbyte_3;
+ struct mfd_cell *wcd9xxx_dev = NULL;
+ int wcd9xxx_dev_size = 0;
+
+ mutex_init(&wcd9xxx->io_lock);
+ mutex_init(&wcd9xxx->xfer_lock);
+
+ mutex_init(&wcd9xxx->pm_lock);
+ wcd9xxx->wlock_holders = 0;
+ wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+ init_waitqueue_head(&wcd9xxx->pm_wq);
+ wake_lock_init(&wcd9xxx->wlock, WAKE_LOCK_IDLE, "wcd9310-irq");
+
+ dev_set_drvdata(wcd9xxx->dev, wcd9xxx);
+
+ wcd9xxx_bring_up(wcd9xxx);
+
+ ret = wcd9xxx_irq_init(wcd9xxx);
+ if (ret) {
+ pr_err("IRQ initialization failed\n");
+ goto err;
+ }
+
+ idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
+ idbyte_1 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_1);
+ idbyte_2 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2);
+ idbyte_3 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_3);
+
+ wcd9xxx->version = wcd9xxx_reg_read(wcd9xxx,
+ WCD9XXX_A_CHIP_VERSION) & 0x1F;
+ pr_info("%s : Codec version %u initialized\n",
+ __func__, wcd9xxx->version);
+ 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 (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);
+ }
+
+ ret = mfd_add_devices(wcd9xxx->dev, -1,
+ wcd9xxx_dev, wcd9xxx_dev_size,
+ NULL, 0);
+ if (ret != 0) {
+ dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
+ goto err_irq;
+ }
+ return ret;
+err_irq:
+ wcd9xxx_irq_exit(wcd9xxx);
+err:
+ wcd9xxx_bring_down(wcd9xxx);
+ wake_lock_destroy(&wcd9xxx->wlock);
+ mutex_destroy(&wcd9xxx->pm_lock);
+ mutex_destroy(&wcd9xxx->io_lock);
+ mutex_destroy(&wcd9xxx->xfer_lock);
+ return ret;
+}
+
+static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
+{
+ wcd9xxx_irq_exit(wcd9xxx);
+ wcd9xxx_bring_down(wcd9xxx);
+ wcd9xxx_free_reset(wcd9xxx);
+ mutex_destroy(&wcd9xxx->pm_lock);
+ wake_lock_destroy(&wcd9xxx->wlock);
+ mutex_destroy(&wcd9xxx->io_lock);
+ mutex_destroy(&wcd9xxx->xfer_lock);
+ slim_remove_device(wcd9xxx->slim_slave);
+ kfree(wcd9xxx);
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+struct wcd9xxx *debugCodec;
+
+static struct dentry *debugfs_wcd9xxx_dent;
+static struct dentry *debugfs_peek;
+static struct dentry *debugfs_poke;
+
+static unsigned char read_data;
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+ char *token;
+ int base, cnt;
+
+ token = strsep(&buf, " ");
+
+ for (cnt = 0; cnt < num_of_par; cnt++) {
+ if (token != NULL) {
+ if ((token[1] == 'x') || (token[1] == 'X'))
+ base = 16;
+ else
+ base = 10;
+
+ if (strict_strtoul(token, base, ¶m1[cnt]) != 0)
+ return -EINVAL;
+
+ token = strsep(&buf, " ");
+ } else
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[8];
+
+ snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
+ return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+ strnlen(lbuf, 7));
+}
+
+
+static ssize_t codec_debug_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char *access_str = filp->private_data;
+ char lbuf[32];
+ int rc;
+ long int param[5];
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+
+ if (!strncmp(access_str, "poke", 6)) {
+ /* write */
+ rc = get_parameters(lbuf, param, 2);
+ if ((param[0] <= 0x3FF) && (param[1] <= 0xFF) &&
+ (rc == 0))
+ wcd9xxx_interface_reg_write(debugCodec, param[0],
+ param[1]);
+ else
+ rc = -EINVAL;
+ } else if (!strncmp(access_str, "peek", 6)) {
+ /* read */
+ rc = get_parameters(lbuf, param, 1);
+ if ((param[0] <= 0x3FF) && (rc == 0))
+ read_data = wcd9xxx_interface_reg_read(debugCodec,
+ param[0]);
+ else
+ rc = -EINVAL;
+ }
+
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+ .open = codec_debug_open,
+ .write = codec_debug_write,
+ .read = codec_debug_read
+};
+#endif
+
+static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx)
+{
+ 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);
+ if (!wcd9xxx->supplies) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++)
+ wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
+
+ ret = regulator_bulk_get(wcd9xxx->dev, ARRAY_SIZE(pdata->regulator),
+ wcd9xxx->supplies);
+ if (ret != 0) {
+ dev_err(wcd9xxx->dev, "Failed to get supplies: err = %d\n",
+ ret);
+ goto err_supplies;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ ret = regulator_set_voltage(wcd9xxx->supplies[i].consumer,
+ pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+ if (ret) {
+ pr_err("%s: Setting regulator voltage failed for "
+ "regulator %s err = %d\n", __func__,
+ wcd9xxx->supplies[i].supply, ret);
+ goto err_get;
+ }
+
+ ret = regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer,
+ pdata->regulator[i].optimum_uA);
+ if (ret < 0) {
+ pr_err("%s: Setting regulator optimum mode failed for "
+ "regulator %s err = %d\n", __func__,
+ wcd9xxx->supplies[i].supply, ret);
+ goto err_get;
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(pdata->regulator),
+ wcd9xxx->supplies);
+ if (ret != 0) {
+ dev_err(wcd9xxx->dev, "Failed to enable supplies: err = %d\n",
+ ret);
+ goto err_configure;
+ }
+ return ret;
+
+err_configure:
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
+ }
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+err_supplies:
+ kfree(wcd9xxx->supplies);
+err:
+ return ret;
+}
+
+static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx)
+{
+ int i;
+ struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
+
+ regulator_bulk_disable(ARRAY_SIZE(pdata->regulator),
+ wcd9xxx->supplies);
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
+ }
+ regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+ kfree(wcd9xxx->supplies);
+}
+
+int wcd9xxx_get_intf_type(void)
+{
+ return wcd9xxx_intf;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
+
+struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
+{
+ u16 mask = 0x0f00;
+ int value = 0;
+ struct wcd9xxx_i2c *wcd9xxx = NULL;
+ value = ((reg & mask) >> 8) & 0x000f;
+ switch (value) {
+ case 0:
+ wcd9xxx = &wcd9xxx_modules[0];
+ break;
+ case 1:
+ wcd9xxx = &wcd9xxx_modules[1];
+ break;
+ case 2:
+ wcd9xxx = &wcd9xxx_modules[2];
+ break;
+ case 3:
+ wcd9xxx = &wcd9xxx_modules[3];
+ break;
+ default:
+ break;
+ }
+ return wcd9xxx;
+}
+
+int wcd9xxx_i2c_write_device(u16 reg, u8 *value,
+ u32 bytes)
+{
+
+ struct i2c_msg *msg;
+ int ret = 0;
+ u8 reg_addr = 0;
+ u8 data[bytes + 1];
+ struct wcd9xxx_i2c *wcd9xxx;
+
+ wcd9xxx = get_i2c_wcd9xxx_device_info(reg);
+ if (wcd9xxx == NULL || wcd9xxx->client == NULL) {
+ pr_err("failed to get device info\n");
+ return -ENODEV;
+ }
+ reg_addr = (u8)reg;
+ msg = &wcd9xxx->xfer_msg[0];
+ msg->addr = wcd9xxx->client->addr;
+ msg->len = bytes + 1;
+ msg->flags = 0;
+ data[0] = reg;
+ data[1] = *value;
+ msg->buf = data;
+ ret = i2c_transfer(wcd9xxx->client->adapter, wcd9xxx->xfer_msg, 1);
+ /* Try again if the write fails */
+ if (ret != 1) {
+ ret = i2c_transfer(wcd9xxx->client->adapter,
+ wcd9xxx->xfer_msg, 1);
+ if (ret != 1) {
+ pr_err("failed to write the device\n");
+ return ret;
+ }
+ }
+ pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
+ return 0;
+}
+
+
+int wcd9xxx_i2c_read_device(unsigned short reg,
+ int bytes, unsigned char *dest)
+{
+ struct i2c_msg *msg;
+ int ret = 0;
+ u8 reg_addr = 0;
+ struct wcd9xxx_i2c *wcd9xxx;
+ u8 i = 0;
+
+ wcd9xxx = get_i2c_wcd9xxx_device_info(reg);
+ if (wcd9xxx == NULL || wcd9xxx->client == NULL) {
+ pr_err("failed to get device info\n");
+ return -ENODEV;
+ }
+ for (i = 0; i < bytes; i++) {
+ reg_addr = (u8)reg++;
+ msg = &wcd9xxx->xfer_msg[0];
+ msg->addr = wcd9xxx->client->addr;
+ msg->len = 1;
+ msg->flags = 0;
+ msg->buf = ®_addr;
+
+ msg = &wcd9xxx->xfer_msg[1];
+ msg->addr = wcd9xxx->client->addr;
+ msg->len = 1;
+ msg->flags = I2C_M_RD;
+ msg->buf = dest++;
+ ret = i2c_transfer(wcd9xxx->client->adapter,
+ wcd9xxx->xfer_msg, 2);
+
+ /* Try again if read fails first time */
+ if (ret != 2) {
+ ret = i2c_transfer(wcd9xxx->client->adapter,
+ wcd9xxx->xfer_msg, 2);
+ if (ret != 2) {
+ pr_err("failed to read wcd9xxx register\n");
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+int wcd9xxx_i2c_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *dest, bool interface_reg)
+{
+ return wcd9xxx_i2c_read_device(reg, bytes, dest);
+}
+
+int wcd9xxx_i2c_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *src, bool interface_reg)
+{
+ return wcd9xxx_i2c_write_device(reg, src, bytes);
+}
+
+static int __devinit wcd9xxx_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wcd9xxx *wcd9xxx;
+ struct wcd9xxx_pdata *pdata = client->dev.platform_data;
+ int val = 0;
+ int ret = 0;
+ static int device_id;
+
+ if (device_id > 0) {
+ wcd9xxx_modules[device_id++].client = client;
+ pr_info("probe for other slaves devices of tabla\n");
+ return ret;
+ }
+
+ wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+ if (wcd9xxx == NULL) {
+ pr_err("%s: error, allocation failed\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (!pdata) {
+ dev_dbg(&client->dev, "no platform data?\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+ dev_dbg(&client->dev, "can't talk I2C?\n");
+ ret = -EIO;
+ goto fail;
+ }
+ dev_set_drvdata(&client->dev, wcd9xxx);
+ wcd9xxx->dev = &client->dev;
+ wcd9xxx->reset_gpio = pdata->reset_gpio;
+
+ ret = wcd9xxx_enable_supplies(wcd9xxx);
+ if (ret) {
+ pr_err("%s: Fail to enable Codec supplies\n", __func__);
+ goto err_codec;
+ }
+
+ usleep_range(5, 5);
+ ret = wcd9xxx_reset(wcd9xxx);
+ if (ret) {
+ pr_err("%s: Resetting Codec failed\n", __func__);
+ goto err_supplies;
+ }
+ wcd9xxx_modules[device_id++].client = client;
+
+ wcd9xxx->read_dev = wcd9xxx_i2c_read;
+ wcd9xxx->write_dev = wcd9xxx_i2c_write;
+ wcd9xxx->irq = pdata->irq;
+ wcd9xxx->irq_base = pdata->irq_base;
+
+ /*read the tabla status before initializing the device type*/
+ ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+ if ((ret < 0) || (val != WCD9XXX_I2C_MODE)) {
+ pr_err("failed to read the wcd9xxx status\n");
+ goto err_device_init;
+ }
+
+ ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+ if (ret) {
+ pr_err("%s: error, initializing device failed\n", __func__);
+ goto err_device_init;
+ }
+ wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
+
+ return ret;
+err_device_init:
+ wcd9xxx_free_reset(wcd9xxx);
+err_supplies:
+ wcd9xxx_disable_supplies(wcd9xxx);
+err_codec:
+ kfree(wcd9xxx);
+fail:
+ return ret;
+}
+
+static int __devexit wcd9xxx_i2c_remove(struct i2c_client *client)
+{
+ struct wcd9xxx *wcd9xxx;
+
+ pr_debug("exit\n");
+ wcd9xxx = dev_get_drvdata(&client->dev);
+ wcd9xxx_disable_supplies(wcd9xxx);
+ wcd9xxx_device_exit(wcd9xxx);
+ return 0;
+}
+
+static int wcd9xxx_slim_probe(struct slim_device *slim)
+{
+ struct wcd9xxx *wcd9xxx;
+ struct wcd9xxx_pdata *pdata;
+ int ret = 0;
+ int sgla_retry_cnt;
+
+ dev_info(&slim->dev, "Initialized slim device %s\n", slim->name);
+ pdata = slim->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&slim->dev, "Error, no platform data\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+ if (wcd9xxx == NULL) {
+ pr_err("%s: error, allocation failed\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (!slim->ctrl) {
+ pr_err("Error, no SLIMBUS control data\n");
+ ret = -EINVAL;
+ goto err_codec;
+ }
+ wcd9xxx->slim = slim;
+ slim_set_clientdata(slim, wcd9xxx);
+ wcd9xxx->reset_gpio = pdata->reset_gpio;
+ wcd9xxx->dev = &slim->dev;
+
+ ret = wcd9xxx_enable_supplies(wcd9xxx);
+ if (ret)
+ goto err_codec;
+ usleep_range(5, 5);
+
+ ret = wcd9xxx_reset(wcd9xxx);
+ if (ret) {
+ pr_err("%s: Resetting Codec failed\n", __func__);
+ goto err_supplies;
+ }
+
+ ret = slim_get_logical_addr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
+ ARRAY_SIZE(wcd9xxx->slim->e_addr), &wcd9xxx->slim->laddr);
+ if (ret) {
+ pr_err("fail to get slimbus logical address %d\n", ret);
+ goto err_reset;
+ }
+ wcd9xxx->read_dev = wcd9xxx_slim_read_device;
+ wcd9xxx->write_dev = wcd9xxx_slim_write_device;
+ wcd9xxx->irq = pdata->irq;
+ wcd9xxx->irq_base = pdata->irq_base;
+ wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
+
+ if (pdata->num_irqs < TABLA_NUM_IRQS) {
+ pr_err("%s: Error, not enough interrupt lines allocated\n",
+ __func__);
+ goto err_reset;
+ }
+
+ wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
+
+ ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
+ if (ret) {
+ pr_err("%s: error, adding SLIMBUS device failed\n", __func__);
+ goto err_reset;
+ }
+
+ sgla_retry_cnt = 0;
+
+ while (1) {
+ ret = slim_get_logical_addr(wcd9xxx->slim_slave,
+ wcd9xxx->slim_slave->e_addr,
+ ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
+ &wcd9xxx->slim_slave->laddr);
+ if (ret) {
+ if (sgla_retry_cnt++ < WCD9XXX_SLIM_GLA_MAX_RETRIES) {
+ /* Give SLIMBUS slave time to report present
+ and be ready.
+ */
+ usleep_range(1000, 1000);
+ pr_debug("%s: retry slim_get_logical_addr()\n",
+ __func__);
+ continue;
+ }
+ pr_err("fail to get slimbus slave logical address"
+ " %d\n", ret);
+ goto err_slim_add;
+ }
+ break;
+ }
+ wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
+ wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
+
+ ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+ if (ret) {
+ pr_err("%s: error, initializing device failed\n", __func__);
+ goto err_slim_add;
+ }
+ wcd9xxx_init_slimslave(wcd9xxx, wcd9xxx_pgd_la);
+#ifdef CONFIG_DEBUG_FS
+ debugCodec = wcd9xxx;
+
+ debugfs_wcd9xxx_dent = debugfs_create_dir
+ ("wcd9310_slimbus_interface_device", 0);
+ if (!IS_ERR(debugfs_wcd9xxx_dent)) {
+ debugfs_peek = debugfs_create_file("peek",
+ S_IFREG | S_IRUGO, debugfs_wcd9xxx_dent,
+ (void *) "peek", &codec_debug_ops);
+
+ debugfs_poke = debugfs_create_file("poke",
+ S_IFREG | S_IRUGO, debugfs_wcd9xxx_dent,
+ (void *) "poke", &codec_debug_ops);
+ }
+#endif
+
+ return ret;
+
+err_slim_add:
+ slim_remove_device(wcd9xxx->slim_slave);
+err_reset:
+ wcd9xxx_free_reset(wcd9xxx);
+err_supplies:
+ wcd9xxx_disable_supplies(wcd9xxx);
+err_codec:
+ kfree(wcd9xxx);
+err:
+ return ret;
+}
+static int wcd9xxx_slim_remove(struct slim_device *pdev)
+{
+ struct wcd9xxx *wcd9xxx;
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(debugfs_peek);
+ debugfs_remove(debugfs_poke);
+ debugfs_remove(debugfs_wcd9xxx_dent);
+#endif
+ wcd9xxx = slim_get_devicedata(pdev);
+ wcd9xxx_deinit_slimslave(wcd9xxx);
+ slim_remove_device(wcd9xxx->slim_slave);
+ wcd9xxx_disable_supplies(wcd9xxx);
+ wcd9xxx_device_exit(wcd9xxx);
+ return 0;
+}
+
+static int wcd9xxx_resume(struct wcd9xxx *wcd9xxx)
+{
+ int ret = 0;
+
+ pr_debug("%s: enter\n", __func__);
+ mutex_lock(&wcd9xxx->pm_lock);
+ if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
+ pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+ wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+ wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+ } else {
+ pr_warn("%s: system is already awake, state %d wlock %d\n",
+ __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+ }
+ mutex_unlock(&wcd9xxx->pm_lock);
+ wake_up_all(&wcd9xxx->pm_wq);
+
+ return ret;
+}
+
+static int wcd9xxx_slim_resume(struct slim_device *sldev)
+{
+ struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+ return wcd9xxx_resume(wcd9xxx);
+}
+
+static int wcd9xxx_i2c_resume(struct i2c_client *i2cdev)
+{
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
+ if (wcd9xxx)
+ return wcd9xxx_resume(wcd9xxx);
+ else
+ return 0;
+}
+
+static int wcd9xxx_suspend(struct wcd9xxx *wcd9xxx, pm_message_t pmesg)
+{
+ int ret = 0;
+
+ pr_debug("%s: enter\n", __func__);
+ /* wake_lock() can be called after this suspend chain call started.
+ * thus suspend can be called while wlock is being held */
+ mutex_lock(&wcd9xxx->pm_lock);
+ if (wcd9xxx->pm_state == WCD9XXX_PM_SLEEPABLE) {
+ pr_debug("%s: suspending system, state %d, wlock %d\n",
+ __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+ wcd9xxx->pm_state = WCD9XXX_PM_ASLEEP;
+ } else if (wcd9xxx->pm_state == WCD9XXX_PM_AWAKE) {
+ /* unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+ * then set to WCD9XXX_PM_ASLEEP */
+ pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+ __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+ mutex_unlock(&wcd9xxx->pm_lock);
+ if (!(wait_event_timeout(wcd9xxx->pm_wq,
+ wcd9xxx_pm_cmpxchg(wcd9xxx,
+ WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_ASLEEP) ==
+ WCD9XXX_PM_SLEEPABLE,
+ HZ))) {
+ pr_debug("%s: suspend failed state %d, wlock %d\n",
+ __func__, wcd9xxx->pm_state,
+ wcd9xxx->wlock_holders);
+ ret = -EBUSY;
+ } else {
+ pr_debug("%s: done, state %d, wlock %d\n", __func__,
+ wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+ }
+ mutex_lock(&wcd9xxx->pm_lock);
+ } else if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
+ pr_warn("%s: system is already suspended, state %d, wlock %dn",
+ __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
+ }
+ mutex_unlock(&wcd9xxx->pm_lock);
+
+ return ret;
+}
+
+static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
+{
+ struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+ return wcd9xxx_suspend(wcd9xxx, pmesg);
+}
+
+static int wcd9xxx_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
+{
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
+ if (wcd9xxx)
+ return wcd9xxx_suspend(wcd9xxx, pmesg);
+ else
+ return 0;
+}
+
+static const struct slim_device_id sitar_slimtest_id[] = {
+ {"sitar-slim", 0},
+ {}
+};
+static struct slim_driver sitar_slim_driver = {
+ .driver = {
+ .name = "sitar-slim",
+ .owner = THIS_MODULE,
+ },
+ .probe = wcd9xxx_slim_probe,
+ .remove = wcd9xxx_slim_remove,
+ .id_table = sitar_slimtest_id,
+ .resume = wcd9xxx_slim_resume,
+ .suspend = wcd9xxx_slim_suspend,
+};
+
+static const struct slim_device_id slimtest_id[] = {
+ {"tabla-slim", 0},
+ {}
+};
+
+static struct slim_driver tabla_slim_driver = {
+ .driver = {
+ .name = "tabla-slim",
+ .owner = THIS_MODULE,
+ },
+ .probe = wcd9xxx_slim_probe,
+ .remove = wcd9xxx_slim_remove,
+ .id_table = slimtest_id,
+ .resume = wcd9xxx_slim_resume,
+ .suspend = wcd9xxx_slim_suspend,
+};
+
+static const struct slim_device_id slimtest2x_id[] = {
+ {"tabla2x-slim", 0},
+ {}
+};
+
+static struct slim_driver tabla2x_slim_driver = {
+ .driver = {
+ .name = "tabla2x-slim",
+ .owner = THIS_MODULE,
+ },
+ .probe = wcd9xxx_slim_probe,
+ .remove = wcd9xxx_slim_remove,
+ .id_table = slimtest2x_id,
+ .resume = wcd9xxx_slim_resume,
+ .suspend = wcd9xxx_slim_suspend,
+};
+
+#define TABLA_I2C_TOP_LEVEL 0
+#define TABLA_I2C_ANALOG 1
+#define TABLA_I2C_DIGITAL_1 2
+#define TABLA_I2C_DIGITAL_2 3
+
+static struct i2c_device_id tabla_id_table[] = {
+ {"tabla top level", TABLA_I2C_TOP_LEVEL},
+ {"tabla analog", TABLA_I2C_TOP_LEVEL},
+ {"tabla digital1", TABLA_I2C_TOP_LEVEL},
+ {"tabla digital2", TABLA_I2C_TOP_LEVEL},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static struct i2c_driver tabla_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tabla-i2c-core",
+ },
+ .id_table = tabla_id_table,
+ .probe = wcd9xxx_i2c_probe,
+ .remove = __devexit_p(wcd9xxx_i2c_remove),
+ .resume = wcd9xxx_i2c_resume,
+ .suspend = wcd9xxx_i2c_suspend,
+};
+
+static int __init wcd9xxx_init(void)
+{
+ int ret1, ret2, ret3, ret4;
+
+ ret1 = slim_driver_register(&tabla_slim_driver);
+ if (ret1 != 0)
+ pr_err("Failed to register tabla SB driver: %d\n", ret1);
+
+ ret2 = slim_driver_register(&tabla2x_slim_driver);
+ if (ret2 != 0)
+ pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
+
+ ret3 = i2c_add_driver(&tabla_i2c_driver);
+ if (ret3 != 0)
+ pr_err("failed to add the I2C driver\n");
+
+ ret4 = slim_driver_register(&sitar_slim_driver);
+ if (ret1 != 0)
+ pr_err("Failed to register sitar SB driver: %d\n", ret4);
+
+ return (ret1 && ret2 && ret3 && ret4) ? -1 : 0;
+}
+module_init(wcd9xxx_init);
+
+static void __exit wcd9xxx_exit(void)
+{
+}
+module_exit(wcd9xxx_exit);
+
+MODULE_DESCRIPTION("Codec core driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
new file mode 100644
index 0000000..86c01ee
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -0,0 +1,286 @@
+/* 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
+ * 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 <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/interrupt.h>
+
+#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
+#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
+
+struct wcd9xxx_irq {
+ bool level;
+};
+
+static struct wcd9xxx_irq wcd9xxx_irqs[TABLA_NUM_IRQS] = {
+ [0] = { .level = 1},
+/* All other wcd9xxx interrupts are edge triggered */
+};
+
+static inline int irq_to_wcd9xxx_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ return irq - wcd9xxx->irq_base;
+}
+
+static void wcd9xxx_irq_lock(struct irq_data *data)
+{
+ struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+ mutex_lock(&wcd9xxx->irq_lock);
+}
+
+static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
+{
+ struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
+ /* If there's been a change in the mask write it back
+ * to the hardware.
+ */
+ if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
+ wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
+ wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0+i,
+ wcd9xxx->irq_masks_cur[i]);
+ }
+ }
+
+ mutex_unlock(&wcd9xxx->irq_lock);
+}
+
+static void wcd9xxx_irq_enable(struct irq_data *data)
+{
+ struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+ int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+ wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
+ ~(BYTE_BIT_MASK(wcd9xxx_irq));
+}
+
+static void wcd9xxx_irq_disable(struct irq_data *data)
+{
+ struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+ int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+ wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
+ |= BYTE_BIT_MASK(wcd9xxx_irq);
+}
+
+static struct irq_chip wcd9xxx_irq_chip = {
+ .name = "wcd9xxx",
+ .irq_bus_lock = wcd9xxx_irq_lock,
+ .irq_bus_sync_unlock = wcd9xxx_irq_sync_unlock,
+ .irq_disable = wcd9xxx_irq_disable,
+ .irq_enable = wcd9xxx_irq_enable,
+};
+
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
+ enum wcd9xxx_pm_state o,
+ enum wcd9xxx_pm_state n)
+{
+ enum wcd9xxx_pm_state old;
+ mutex_lock(&wcd9xxx->pm_lock);
+ old = wcd9xxx->pm_state;
+ if (old == o)
+ wcd9xxx->pm_state = n;
+ mutex_unlock(&wcd9xxx->pm_lock);
+ return old;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_pm_cmpxchg);
+
+void wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx)
+{
+ enum wcd9xxx_pm_state os;
+
+ /* wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+ * and its subroutines only motly.
+ * but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
+ * it can race with wcd9xxx_irq_thread.
+ * so need to embrace wlock_holders with mutex.
+ */
+ mutex_lock(&wcd9xxx->pm_lock);
+ if (wcd9xxx->wlock_holders++ == 0)
+ wake_lock(&wcd9xxx->wlock);
+ mutex_unlock(&wcd9xxx->pm_lock);
+ while (!wait_event_timeout(wcd9xxx->pm_wq,
+ ((os = wcd9xxx_pm_cmpxchg(wcd9xxx, WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_AWAKE)) ==
+ WCD9XXX_PM_SLEEPABLE ||
+ (os == WCD9XXX_PM_AWAKE)),
+ 5 * HZ)) {
+ pr_err("%s: system didn't resume within 5000ms, state %d, "
+ "wlock %d\n", __func__, wcd9xxx->pm_state,
+ wcd9xxx->wlock_holders);
+ WARN_ON_ONCE(1);
+ }
+ wake_up_all(&wcd9xxx->pm_wq);
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_lock_sleep);
+
+void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx)
+{
+ mutex_lock(&wcd9xxx->pm_lock);
+ if (--wcd9xxx->wlock_holders == 0) {
+ wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
+ wake_unlock(&wcd9xxx->wlock);
+ }
+ mutex_unlock(&wcd9xxx->pm_lock);
+ wake_up_all(&wcd9xxx->pm_wq);
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep);
+
+static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
+{
+ int ret;
+ struct wcd9xxx *wcd9xxx = data;
+ u8 status[WCD9XXX_NUM_IRQ_REGS];
+ unsigned int i;
+
+ wcd9xxx_lock_sleep(wcd9xxx);
+ ret = wcd9xxx_bulk_read(wcd9xxx, TABLA_A_INTR_STATUS0,
+ WCD9XXX_NUM_IRQ_REGS, status);
+ if (ret < 0) {
+ dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
+ ret);
+ wcd9xxx_unlock_sleep(wcd9xxx);
+ return IRQ_NONE;
+ }
+ /* Apply masking */
+ for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++)
+ status[i] &= ~wcd9xxx->irq_masks_cur[i];
+
+ /* Find out which interrupt was triggered and call that interrupt's
+ * handler function
+ */
+ for (i = 0; i < TABLA_NUM_IRQS; i++) {
+ if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
+ if ((i <= TABLA_IRQ_MBHC_INSERTION) &&
+ (i >= TABLA_IRQ_MBHC_REMOVAL)) {
+ wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
+ BIT_BYTE(i), BYTE_BIT_MASK(i));
+ if (wcd9xxx_get_intf_type() ==
+ WCD9XXX_INTERFACE_TYPE_I2C)
+ wcd9xxx_reg_write(wcd9xxx,
+ TABLA_A_INTR_MODE, 0x02);
+ handle_nested_irq(wcd9xxx->irq_base + i);
+ } else {
+ handle_nested_irq(wcd9xxx->irq_base + i);
+ wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
+ BIT_BYTE(i), BYTE_BIT_MASK(i));
+ if (wcd9xxx_get_intf_type() ==
+ WCD9XXX_INTERFACE_TYPE_I2C)
+ wcd9xxx_reg_write(wcd9xxx,
+ TABLA_A_INTR_MODE, 0x02);
+ }
+ break;
+ }
+ }
+ wcd9xxx_unlock_sleep(wcd9xxx);
+
+ return IRQ_HANDLED;
+}
+
+int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
+{
+ int ret;
+ unsigned int i, cur_irq;
+
+ mutex_init(&wcd9xxx->irq_lock);
+
+ if (!wcd9xxx->irq) {
+ dev_warn(wcd9xxx->dev,
+ "No interrupt specified, no interrupts\n");
+ wcd9xxx->irq_base = 0;
+ return 0;
+ }
+
+ if (!wcd9xxx->irq_base) {
+ dev_err(wcd9xxx->dev,
+ "No interrupt base specified, no interrupts\n");
+ return 0;
+ }
+ /* Mask the individual interrupt sources */
+ for (i = 0, cur_irq = wcd9xxx->irq_base; i < TABLA_NUM_IRQS; i++,
+ cur_irq++) {
+
+ irq_set_chip_data(cur_irq, wcd9xxx);
+
+ if (wcd9xxx_irqs[i].level)
+ irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
+ handle_level_irq);
+ else
+ irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
+ handle_edge_irq);
+
+ irq_set_nested_thread(cur_irq, 1);
+
+ /* ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+ set_irq_flags(cur_irq, IRQF_VALID);
+#else
+ set_irq_noprobe(cur_irq);
+#endif
+
+ wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+ wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+ wcd9xxx->irq_level[BIT_BYTE(i)] |= wcd9xxx_irqs[i].level <<
+ (i % BITS_PER_BYTE);
+ }
+ for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++) {
+ /* Initialize interrupt mask and level registers */
+ wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_LEVEL0 + i,
+ wcd9xxx->irq_level[i]);
+ wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0 + i,
+ wcd9xxx->irq_masks_cur[i]);
+ }
+
+ ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "wcd9xxx", wcd9xxx);
+ if (ret != 0)
+ dev_err(wcd9xxx->dev, "Failed to request IRQ %d: %d\n",
+ wcd9xxx->irq, ret);
+ else {
+ ret = enable_irq_wake(wcd9xxx->irq);
+ if (ret == 0) {
+ ret = device_init_wakeup(wcd9xxx->dev, 1);
+ if (ret) {
+ dev_err(wcd9xxx->dev, "Failed to init device"
+ "wakeup : %d\n", ret);
+ disable_irq_wake(wcd9xxx->irq);
+ }
+ } else
+ dev_err(wcd9xxx->dev, "Failed to set wake interrupt on"
+ " IRQ %d: %d\n", wcd9xxx->irq, ret);
+ if (ret)
+ free_irq(wcd9xxx->irq, wcd9xxx);
+ }
+
+ if (ret)
+ mutex_destroy(&wcd9xxx->irq_lock);
+
+ return ret;
+}
+
+void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
+{
+ if (wcd9xxx->irq) {
+ disable_irq_wake(wcd9xxx->irq);
+ free_irq(wcd9xxx->irq, wcd9xxx);
+ device_init_wakeup(wcd9xxx->dev, 0);
+ }
+ mutex_destroy(&wcd9xxx->irq_lock);
+}
diff --git a/drivers/mfd/wcd9310-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
similarity index 71%
rename from drivers/mfd/wcd9310-slimslave.c
rename to drivers/mfd/wcd9xxx-slimslave.c
index dd586fa..acef55e 100644
--- a/drivers/mfd/wcd9310-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -11,45 +11,47 @@
*/
#include <linux/slab.h>
#include <linux/mutex.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
-struct tabla_slim_sch_rx {
+struct wcd9xxx_slim_sch_rx {
u32 sph;
u32 ch_num;
u16 ch_h;
u16 grph;
};
-struct tabla_slim_sch_tx {
+struct wcd9xxx_slim_sch_tx {
u32 sph;
u32 ch_num;
u16 ch_h;
u16 grph;
};
-struct tabla_slim_sch {
- struct tabla_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
- struct tabla_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
+struct wcd9xxx_slim_sch {
+ struct wcd9xxx_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
+ struct wcd9xxx_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
};
-static struct tabla_slim_sch sh_ch;
+static struct wcd9xxx_slim_sch sh_ch;
-static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la);
-static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la);
-static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab);
-static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab);
+static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
+ u8 wcd9xxx_pgd_la);
+static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
+ u8 wcd9xxx_pgd_la);
+static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx);
+static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx);
-int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la)
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la)
{
int ret = 0;
- ret = tabla_alloc_slim_sh_ch_rx(tabla, tabla_pgd_la);
+ ret = wcd9xxx_alloc_slim_sh_ch_rx(wcd9xxx, wcd9xxx_pgd_la);
if (ret) {
pr_err("%s: Failed to alloc rx slimbus shared channels\n",
__func__);
goto rx_err;
}
- ret = tabla_alloc_slim_sh_ch_tx(tabla, tabla_pgd_la);
+ ret = wcd9xxx_alloc_slim_sh_ch_tx(wcd9xxx, wcd9xxx_pgd_la);
if (ret) {
pr_err("%s: Failed to alloc tx slimbus shared channels\n",
__func__);
@@ -57,21 +59,21 @@
}
return 0;
tx_err:
- tabla_dealloc_slim_sh_ch_rx(tabla);
+ wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
rx_err:
return ret;
}
-int tabla_deinit_slimslave(struct tabla *tabla)
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
- ret = tabla_dealloc_slim_sh_ch_rx(tabla);
+ ret = wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
if (ret < 0) {
pr_err("%s: fail to dealloc rx slim ports\n", __func__);
goto err;
}
- ret = tabla_dealloc_slim_sh_ch_tx(tabla);
+ ret = wcd9xxx_dealloc_slim_sh_ch_tx(wcd9xxx);
if (ret < 0) {
pr_err("%s: fail to dealloc tx slim ports\n", __func__);
goto err;
@@ -80,13 +82,13 @@
return ret;
}
-int tabla_get_channel(struct tabla *tabla,
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
unsigned int *rx_ch,
unsigned int *tx_ch)
{
int ch_idx = 0;
- struct tabla_slim_sch_rx *rx = sh_ch.rx;
- struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+ struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++)
rx_ch[ch_idx] = rx[ch_idx].ch_num;
@@ -95,23 +97,23 @@
return 0;
}
-static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la)
+static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
+ u8 wcd9xxx_pgd_la)
{
int ret = 0;
u8 ch_idx ;
u16 slave_port_id = 0;
- struct tabla_slim_sch_rx *rx = sh_ch.rx;
+ struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
- /* DSP requires channel number to be between 128 and 255. For RX port
- * use channel numbers from 138 to 144, for TX port
- * use channel numbers from 128 to 137
+ /*
+ * DSP requires channel number to be between 128 and 255.
*/
- pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+ pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++) {
slave_port_id = (ch_idx + 1 +
SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
- ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+ ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
&rx[ch_idx].sph, SLIM_SINK);
if (ret < 0) {
pr_err("%s: slave port failure id[%d] ret[%d]\n",
@@ -119,7 +121,7 @@
goto err;
}
- ret = slim_query_ch(tabla->slim, rx[ch_idx].ch_num,
+ ret = slim_query_ch(wcd9xxx->slim, rx[ch_idx].ch_num,
&rx[ch_idx].ch_h);
if (ret < 0) {
pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
@@ -131,14 +133,15 @@
return ret;
}
-static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la)
+static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
+ u8 wcd9xxx_pgd_la)
{
int ret = 0;
u8 ch_idx ;
- struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
u16 slave_port_id = 0;
- pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+ pr_err("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
/* DSP requires channel number to be between 128 and 255. For RX port
* use channel numbers from 138 to 144, for TX port
* use channel numbers from 128 to 137
@@ -146,14 +149,14 @@
for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++) {
slave_port_id = ch_idx;
tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
- ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+ ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
&tx[ch_idx].sph, SLIM_SRC);
if (ret < 0) {
pr_err("%s: slave port failure id[%d] ret[%d]\n",
__func__, slave_port_id, ret);
goto err;
}
- ret = slim_query_ch(tabla->slim, tx[ch_idx].ch_num,
+ ret = slim_query_ch(wcd9xxx->slim, tx[ch_idx].ch_num,
&tx[ch_idx].ch_h);
if (ret < 0) {
pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
@@ -165,14 +168,14 @@
return ret;
}
-static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab)
+static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx)
{
int idx = 0;
int ret = 0;
- struct tabla_slim_sch_rx *rx = sh_ch.rx;
+ struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
/* slim_dealloc_ch */
for (idx = 0; idx < SLIM_MAX_RX_PORTS; idx++) {
- ret = slim_dealloc_ch(tab->slim, rx[idx].ch_h);
+ ret = slim_dealloc_ch(wcd9xxx->slim, rx[idx].ch_h);
if (ret < 0) {
pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
__func__, ret, rx[idx].ch_h);
@@ -182,14 +185,14 @@
return ret;
}
-static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab)
+static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx)
{
int idx = 0;
int ret = 0;
- struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
/* slim_dealloc_ch */
for (idx = 0; idx < SLIM_MAX_TX_PORTS; idx++) {
- ret = slim_dealloc_ch(tab->slim, tx[idx].ch_h);
+ ret = slim_dealloc_ch(wcd9xxx->slim, tx[idx].ch_h);
if (ret < 0) {
pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
__func__, ret, tx[idx].ch_h);
@@ -200,7 +203,7 @@
}
/* Enable slimbus slave device for RX path */
-int tabla_cfg_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int ch_cnt, unsigned int rate)
{
u8 i = 0;
@@ -211,15 +214,15 @@
u8 payload_rx = 0, wm_payload = 0;
int ret, idx = 0;
unsigned short multi_chan_cfg_reg_addr;
- struct tabla_slim_sch_rx *rx = sh_ch.rx;
+ struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
struct slim_ch prop;
/* Configure slave interface device */
- pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
+ pr_err("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM -
- SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+ SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
ch_h[i] = rx[idx].ch_h;
sph[i] = rx[idx].sph;
slave_port_id = idx + 1;
@@ -236,7 +239,7 @@
*/
if ((slave_port_id >
SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) &&
- (slave_port_id <
+ (slave_port_id <=
SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID)) {
payload_rx = payload_rx |
(1 <<
@@ -249,7 +252,8 @@
multi_chan_cfg_reg_addr =
SB_PGD_RX_PORT_MULTI_CHANNEL_0(slave_port_id);
/* write to interface device */
- ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ multi_chan_cfg_reg_addr,
payload_rx);
if (ret < 0) {
pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -262,7 +266,7 @@
wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
SLAVE_PORT_WATER_MARK_SHIFT) +
SLAVE_PORT_ENABLE;
- ret = tabla_interface_reg_write(tab,
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
wm_payload);
if (ret < 0) {
@@ -279,7 +283,7 @@
prop.ratem = (rate/4000);
prop.sampleszbits = 16;
- ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+ ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
true, &grph);
if (ret < 0) {
pr_err("%s: slim_define_ch failed ret[%d]\n",
@@ -287,7 +291,7 @@
goto err;
}
for (i = 0; i < ch_cnt; i++) {
- ret = slim_connect_sink(tab->slim, &sph[i],
+ ret = slim_connect_sink(wcd9xxx->slim, &sph[i],
1, ch_h[i]);
if (ret < 0) {
pr_err("%s: slim_connect_sink failed ret[%d]\n",
@@ -296,7 +300,7 @@
}
}
/* slim_control_ch */
- ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+ ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
true);
if (ret < 0) {
pr_err("%s: slim_control_ch failed ret[%d]\n",
@@ -312,14 +316,14 @@
err_close_slim_sch:
/* release all acquired handles */
- tabla_close_slim_sch_rx(tab, ch_num, ch_cnt);
+ wcd9xxx_close_slim_sch_rx(wcd9xxx, ch_num, ch_cnt);
err:
return ret;
}
-EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_rx);
+EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_rx);
/* Enable slimbus slave device for RX path */
-int tabla_cfg_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int ch_cnt, unsigned int rate)
{
u8 i = 0;
@@ -331,7 +335,7 @@
int ret = 0;
unsigned short multi_chan_cfg_reg_addr;
- struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
struct slim_ch prop;
pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
@@ -366,7 +370,8 @@
multi_chan_cfg_reg_addr =
SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
/* write to interface device */
- ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ multi_chan_cfg_reg_addr,
payload_tx_0);
if (ret < 0) {
pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -378,7 +383,8 @@
multi_chan_cfg_reg_addr =
SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
/* ports 8,9 */
- ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ multi_chan_cfg_reg_addr,
payload_tx_1);
if (ret < 0) {
pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
@@ -391,7 +397,7 @@
wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
SLAVE_PORT_WATER_MARK_SHIFT) +
SLAVE_PORT_ENABLE;
- ret = tabla_interface_reg_write(tab,
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
wm_payload);
if (ret < 0) {
@@ -408,7 +414,7 @@
prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
prop.ratem = (rate/4000);
prop.sampleszbits = 16;
- ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+ ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
true, &grph);
if (ret < 0) {
pr_err("%s: slim_define_ch failed ret[%d]\n",
@@ -416,7 +422,7 @@
goto err;
}
for (i = 0; i < ch_cnt; i++) {
- ret = slim_connect_src(tab->slim, sph[i],
+ ret = slim_connect_src(wcd9xxx->slim, sph[i],
ch_h[i]);
if (ret < 0) {
pr_err("%s: slim_connect_src failed ret[%d]\n",
@@ -425,7 +431,7 @@
}
}
/* slim_control_ch */
- ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+ ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
true);
if (ret < 0) {
pr_err("%s: slim_control_ch failed ret[%d]\n",
@@ -439,21 +445,21 @@
return 0;
err:
/* release all acquired handles */
- tabla_close_slim_sch_tx(tab, ch_num, ch_cnt);
+ wcd9xxx_close_slim_sch_tx(wcd9xxx, ch_num, ch_cnt);
return ret;
}
-EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_tx);
+EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_tx);
-int tabla_close_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int ch_cnt)
{
u16 grph = 0;
u32 sph[SLIM_MAX_RX_PORTS] = {0};
int i = 0 , idx = 0;
int ret = 0;
- struct tabla_slim_sch_rx *rx = sh_ch.rx;
+ struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
- pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+ pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM -
SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
@@ -462,13 +468,13 @@
}
/* slim_disconnect_port */
- ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+ ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
if (ret < 0) {
pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
__func__, ret);
}
/* slim_control_ch (REMOVE) */
- ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+ ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
if (ret < 0) {
pr_err("%s: slim_control_ch failed ret[%d]\n",
__func__, ret);
@@ -482,31 +488,31 @@
err:
return ret;
}
-EXPORT_SYMBOL_GPL(tabla_close_slim_sch_rx);
+EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
-int tabla_close_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int ch_cnt)
{
u16 grph = 0;
u32 sph[SLIM_MAX_TX_PORTS] = {0};
int ret = 0;
int i = 0 , idx = 0;
- struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
- pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+ pr_err("%s: ch_cnt[%d]\n", __func__, ch_cnt);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM);
sph[i] = tx[idx].sph;
grph = tx[idx].grph;
}
/* slim_disconnect_port */
- ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+ ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
if (ret < 0) {
pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
__func__, ret);
}
/* slim_control_ch (REMOVE) */
- ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+ ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
if (ret < 0) {
pr_err("%s: slim_control_ch failed ret[%d]\n",
__func__, ret);
@@ -519,4 +525,4 @@
err:
return ret;
}
-EXPORT_SYMBOL_GPL(tabla_close_slim_sch_tx);
+EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_tx);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 43eb169..0066cd8 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -627,6 +627,13 @@
TrustZone Operating Environment (TZBSP) using Secure Channel
Manager (SCM) interface.
+config QSEECOM
+ tristate "Qualcomm Secure Execution Communicator driver"
+ help
+ Provides a communication interface between userspace and
+ Qualcomm Secure Execution Environment (QSEE) using Secure Channel
+ Manager (SCM) interface.
+
config QFP_FUSE
tristate "QFPROM Fuse Read/Write support"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6b5fdcc..fb78f4e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -64,4 +64,5 @@
+= msm_migrate_pages.o
obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
obj-$(CONFIG_TZCOM) += tzcom.o
+obj-$(CONFIG_QSEECOM) += qseecom.o
obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
new file mode 100644
index 0000000..e4c3152
--- /dev/null
+++ b/drivers/misc/qseecom.c
@@ -0,0 +1,1490 @@
+/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/qseecom.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include "qseecom_legacy.h"
+
+#define QSEECOM_DEV "qseecom"
+#define QSEOS_VERSION_13 0x13
+#define QSEOS_VERSION_14 0x14
+#define QSEOS_CHECK_VERSION_CMD 0x00001803;
+
+enum qseecom_command_scm_resp_type {
+ QSEOS_APP_ID = 0xEE01,
+ QSEOS_LISTENER_ID
+};
+
+enum qseecom_qceos_cmd_id {
+ QSEOS_APP_START_COMMAND = 0x01,
+ QSEOS_APP_SHUTDOWN_COMMAND,
+ QSEOS_APP_LOOKUP_COMMAND,
+ QSEOS_REGISTER_LISTENER,
+ QSEOS_DEREGISTER_LISTENER,
+ QSEOS_CLIENT_SEND_DATA_COMMAND,
+ QSEOS_LISTENER_DATA_RSP_COMMAND,
+ QSEOS_CMD_MAX = 0xEFFFFFFF
+};
+
+enum qseecom_qceos_cmd_status {
+ QSEOS_RESULT_SUCCESS = 0,
+ QSEOS_RESULT_INCOMPLETE,
+ QSEOS_RESULT_FAILURE = 0xFFFFFFFF
+};
+
+__packed struct qseecom_check_app_ireq {
+ uint32_t qsee_cmd_id;
+ char app_name[MAX_APP_NAME_SIZE];
+};
+
+__packed struct qseecom_load_app_ireq {
+ uint32_t qsee_cmd_id;
+ uint32_t mdt_len; /* Length of the mdt file */
+ uint32_t img_len; /* Length of .bxx and .mdt files */
+ uint32_t phy_addr; /* phy addr of the start of image */
+ char app_name[MAX_APP_NAME_SIZE]; /* application name*/
+};
+
+__packed struct qseecom_unload_app_ireq {
+ uint32_t qsee_cmd_id;
+ uint32_t app_id;
+};
+
+__packed struct qseecom_register_listener_ireq {
+ uint32_t qsee_cmd_id;
+ uint32_t listener_id;
+ void *sb_ptr;
+ uint32_t sb_len;
+};
+
+__packed struct qseecom_unregister_listener_ireq {
+ uint32_t qsee_cmd_id;
+ uint32_t listener_id;
+};
+
+__packed struct qseecom_client_send_data_ireq {
+ uint32_t qsee_cmd_id;
+ uint32_t app_id;
+ void *req_ptr;
+ uint32_t req_len;
+ void *rsp_ptr; /* First 4 bytes should always be the return status */
+ uint32_t rsp_len;
+};
+
+/* send_data resp */
+__packed struct qseecom_client_listener_data_irsp {
+ uint32_t qsee_cmd_id;
+ uint32_t listener_id;
+};
+
+/*
+ * struct qseecom_command_scm_resp - qseecom response buffer
+ * @cmd_status: value from enum tz_sched_cmd_status
+ * @sb_in_rsp_addr: points to physical location of response
+ * buffer
+ * @sb_in_rsp_len: length of command response
+ */
+__packed struct qseecom_command_scm_resp {
+ uint32_t result;
+ enum qseecom_command_scm_resp_type resp_type;
+ unsigned int data;
+};
+
+static struct class *driver_class;
+static dev_t qseecom_device_no;
+static struct cdev qseecom_cdev;
+
+/* Data structures used in legacy support */
+static void *pil;
+static uint32_t pil_ref_cnt;
+static DEFINE_MUTEX(pil_access_lock);
+
+static DEFINE_MUTEX(send_msg_lock);
+static DEFINE_MUTEX(qsee_bw_mutex);
+static DEFINE_MUTEX(app_access_lock);
+
+static int qsee_bw_count;
+static struct clk *qseecom_bus_clk;
+static uint32_t qsee_perf_client;
+
+struct qseecom_registered_listener_list {
+ struct list_head list;
+ struct qseecom_register_listener_req svc;
+ u8 *sb_reg_req;
+ u8 *sb_virt;
+ s32 sb_phys;
+ size_t sb_length;
+ struct ion_handle *ihandle; /* Retrieve phy addr */
+
+ wait_queue_head_t rcv_req_wq;
+ int rcv_req_flag;
+};
+
+struct qseecom_registered_app_list {
+ struct list_head list;
+ u32 app_id;
+ u32 ref_cnt;
+};
+
+struct qseecom_control {
+ struct ion_client *ion_clnt; /* Ion client */
+ struct list_head registered_listener_list_head;
+ spinlock_t registered_listener_list_lock;
+
+ struct list_head registered_app_list_head;
+ spinlock_t registered_app_list_lock;
+
+ wait_queue_head_t send_resp_wq;
+ int send_resp_flag;
+
+ uint32_t qseos_version;
+};
+
+struct qseecom_client_handle {
+ u32 app_id;
+ u8 *sb_virt;
+ s32 sb_phys;
+ uint32_t user_virt_sb_base;
+ size_t sb_length;
+ struct ion_handle *ihandle; /* Retrieve phy addr */
+};
+
+struct qseecom_listener_handle {
+ u32 id;
+};
+
+static struct qseecom_control qseecom;
+
+struct qseecom_dev_handle {
+ bool service;
+ union {
+ struct qseecom_client_handle client;
+ struct qseecom_listener_handle listener;
+ };
+ bool released;
+ int abort;
+ wait_queue_head_t abort_wq;
+ atomic_t ioctl_count;
+};
+
+static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
+ struct qseecom_register_listener_req svc)
+{
+ struct qseecom_registered_listener_list *ptr;
+ int unique = 1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+ list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
+ if (ptr->svc.listener_id == svc.listener_id) {
+ pr_err("Service id: %u is already registered\n",
+ ptr->svc.listener_id);
+ unique = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+ return unique;
+}
+
+static struct qseecom_registered_listener_list *__qseecom_find_svc(
+ int32_t listener_id)
+{
+ struct qseecom_registered_listener_list *entry = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+ list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
+ {
+ if (entry->svc.listener_id == listener_id)
+ break;
+ }
+ spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+ return entry;
+}
+
+static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
+ struct qseecom_dev_handle *handle,
+ struct qseecom_register_listener_req *listener)
+{
+ int ret = 0;
+ unsigned int flags = 0;
+ struct qseecom_register_listener_ireq req;
+ struct qseecom_command_scm_resp resp;
+ ion_phys_addr_t pa;
+
+ /* Get the handle of the shared fd */
+ svc->ihandle = ion_import_fd(qseecom.ion_clnt, listener->ifd_data_fd);
+ if (svc->ihandle == NULL) {
+ pr_err("Ion client could not retrieve the handle\n");
+ return -ENOMEM;
+ }
+
+ /* Get the physical address of the ION BUF */
+ ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
+
+ /* Populate the structure for sending scm call to load image */
+ svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
+ svc->ihandle, flags);
+ svc->sb_phys = pa;
+
+ if (qseecom.qseos_version == QSEOS_VERSION_14) {
+ req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
+ req.listener_id = svc->svc.listener_id;
+ req.sb_len = svc->sb_length;
+ req.sb_ptr = (void *)svc->sb_phys;
+
+ resp.result = QSEOS_RESULT_INCOMPLETE;
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ sizeof(req), &resp, sizeof(resp));
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return -EINVAL;
+ }
+
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("Error SB registration req: resp.result = %d\n",
+ resp.result);
+ return -EPERM;
+ }
+ } else {
+ struct qseecom_command cmd;
+ struct qseecom_response resp;
+ struct qse_pr_init_sb_req_s sb_init_req;
+ struct qse_pr_init_sb_rsp_s sb_init_rsp;
+
+ svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
+ sizeof(sb_init_rsp)), GFP_KERNEL);
+
+ sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
+ sb_init_req.listener_id = svc->svc.listener_id;
+ sb_init_req.sb_len = svc->sb_length;
+ sb_init_req.sb_ptr = svc->sb_phys;
+
+ memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
+
+ /* It will always be a new cmd from this method */
+ cmd.cmd_type = TZ_SCHED_CMD_NEW;
+ cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
+ cmd.sb_in_cmd_len = sizeof(sb_init_req);
+
+ resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
+ , &resp, sizeof(resp));
+
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return -EINVAL;
+ }
+
+ if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+ pr_err("SB registration fail resp.cmd_status %d\n",
+ resp.cmd_status);
+ return -EINVAL;
+ }
+ memset(svc->sb_virt, 0, svc->sb_length);
+ }
+ return 0;
+}
+
+static int qseecom_register_listener(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct qseecom_register_listener_req rcvd_lstnr;
+ struct qseecom_registered_listener_list *new_entry;
+
+ ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
+ if (ret) {
+ pr_err("copy_from_user failed\n");
+ return ret;
+ }
+
+ if (!__qseecom_is_svc_unique(data, rcvd_lstnr)) {
+ pr_err("Service is not unique and is already registered\n");
+ return ret;
+ }
+
+ ret = copy_to_user(argp, &rcvd_lstnr, sizeof(rcvd_lstnr));
+ if (ret) {
+ pr_err("copy_to_user failed\n");
+ return ret;
+ }
+
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
+ if (!new_entry) {
+ pr_err("kmalloc failed\n");
+ return -ENOMEM;
+ }
+ memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
+ new_entry->rcv_req_flag = 0;
+
+ new_entry->svc.listener_id = rcvd_lstnr.listener_id;
+ new_entry->sb_length = rcvd_lstnr.sb_size;
+ if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
+ pr_err("qseecom_set_sb_memoryfailed\n");
+ kzfree(new_entry);
+ return -ENOMEM;
+ }
+ data->listener.id = rcvd_lstnr.listener_id;
+ data->service = true;
+ init_waitqueue_head(&new_entry->rcv_req_wq);
+
+ spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+ list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
+ spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+ return ret;
+}
+
+static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+{
+ int ret = 0;
+ unsigned long flags;
+ uint32_t unmap_mem = 0;
+ struct qseecom_register_listener_ireq req;
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct qseecom_command_scm_resp resp;
+ struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
+
+ if (qseecom.qseos_version == QSEOS_VERSION_14) {
+ req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
+ req.listener_id = data->listener.id;
+ resp.result = QSEOS_RESULT_INCOMPLETE;
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ sizeof(req), &resp, sizeof(resp));
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return ret;
+ }
+
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("SB deregistartion: result=%d\n", resp.result);
+ return -EPERM;
+ }
+ } else {
+ struct qse_pr_init_sb_req_s sb_init_req;
+ struct qseecom_command cmd;
+ struct qseecom_response resp;
+ struct qseecom_registered_listener_list *svc;
+
+ svc = __qseecom_find_svc(data->listener.id);
+ sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
+ sb_init_req.listener_id = data->listener.id;
+ sb_init_req.sb_len = 0;
+ sb_init_req.sb_ptr = 0;
+
+ memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
+
+ /* It will always be a new cmd from this method */
+ cmd.cmd_type = TZ_SCHED_CMD_NEW;
+ cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
+ cmd.sb_in_cmd_len = sizeof(sb_init_req);
+ resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
+ &resp, sizeof(resp));
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return ret;
+ }
+ kzfree(svc->sb_reg_req);
+ if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+ pr_err("Error with SB initialization\n");
+ return -EPERM;
+ }
+ }
+ data->abort = 1;
+ spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+ list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
+ list) {
+ if (ptr_svc->svc.listener_id == data->listener.id) {
+ wake_up_all(&ptr_svc->rcv_req_wq);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+ while (atomic_read(&data->ioctl_count) > 1) {
+ if (wait_event_interruptible(data->abort_wq,
+ atomic_read(&data->ioctl_count) <= 1)) {
+ pr_err("Interrupted from abort\n");
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+
+ spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+ list_for_each_entry(ptr_svc,
+ &qseecom.registered_listener_list_head,
+ list)
+ {
+ if (ptr_svc->svc.listener_id == data->listener.id) {
+ if (ptr_svc->sb_virt) {
+ unmap_mem = 1;
+ ihandle = ptr_svc->ihandle;
+ }
+ list_del(&ptr_svc->list);
+ kzfree(ptr_svc);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+ /* Unmap the memory */
+ if (unmap_mem) {
+ if (!IS_ERR_OR_NULL(ihandle)) {
+ ion_unmap_kernel(qseecom.ion_clnt, ihandle);
+ ion_free(qseecom.ion_clnt, ihandle);
+ }
+ }
+ data->released = true;
+ return ret;
+}
+
+static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ ion_phys_addr_t pa;
+ int32_t ret;
+ unsigned int flags = 0;
+ struct qseecom_set_sb_mem_param_req req;
+ uint32_t len;
+
+ /* Copy the relevant information needed for loading the image */
+ if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
+ return -EFAULT;
+
+ if (qseecom.qseos_version == QSEOS_VERSION_13) {
+ long pil_error;
+ mutex_lock(&pil_access_lock);
+ if (pil_ref_cnt == 0) {
+ pil = pil_get("tzapps");
+ if (IS_ERR(pil)) {
+ pr_err("Playready PIL image load failed\n");
+ pil_error = PTR_ERR(pil);
+ pil = NULL;
+ pr_debug("tzapps image load FAILED\n");
+ mutex_unlock(&pil_access_lock);
+ return pil_error;
+ }
+ }
+ pil_ref_cnt++;
+ mutex_unlock(&pil_access_lock);
+ }
+ /* Get the handle of the shared fd */
+ data->client.ihandle = ion_import_fd(qseecom.ion_clnt, req.ifd_data_fd);
+ if (IS_ERR_OR_NULL(data->client.ihandle)) {
+ pr_err("Ion client could not retrieve the handle\n");
+ return -ENOMEM;
+ }
+ /* Get the physical address of the ION BUF */
+ ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+ /* Populate the structure for sending scm call to load image */
+ data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
+ data->client.ihandle,
+ flags);
+ data->client.sb_phys = pa;
+ data->client.sb_length = req.sb_len;
+ data->client.user_virt_sb_base = req.virt_sb_base;
+ return 0;
+}
+
+
+static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
+{
+ int ret;
+ ret = (qseecom.send_resp_flag != 0);
+ return ret || data->abort;
+}
+
+static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
+ struct qseecom_command_scm_resp *resp)
+{
+ int ret = 0;
+ uint32_t lstnr;
+ unsigned long flags;
+ struct qseecom_client_listener_data_irsp send_data_rsp;
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+
+
+ while (resp->result == QSEOS_RESULT_INCOMPLETE) {
+ lstnr = resp->data;
+ /*
+ * Wake up blocking lsitener service with the lstnr id
+ */
+ spin_lock_irqsave(&qseecom.registered_listener_list_lock,
+ flags);
+ list_for_each_entry(ptr_svc,
+ &qseecom.registered_listener_list_head, list) {
+ if (ptr_svc->svc.listener_id == lstnr) {
+ ptr_svc->rcv_req_flag = 1;
+ wake_up_interruptible(&ptr_svc->rcv_req_wq);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
+ flags);
+ if (ptr_svc->svc.listener_id != lstnr) {
+ pr_warning("Service requested for does on exist\n");
+ return -ERESTARTSYS;
+ }
+ pr_debug("waking up rcv_req_wq and "
+ "waiting for send_resp_wq\n");
+ if (wait_event_interruptible(qseecom.send_resp_wq,
+ __qseecom_listener_has_sent_rsp(data))) {
+ pr_warning("Interrupted: exiting send_cmd loop\n");
+ return -ERESTARTSYS;
+ }
+
+ if (data->abort) {
+ pr_err("Aborting driver\n");
+ return -ENODEV;
+ }
+ qseecom.send_resp_flag = 0;
+ send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
+ send_data_rsp.listener_id = lstnr ;
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
+ (const void *)&send_data_rsp,
+ sizeof(send_data_rsp), resp,
+ sizeof(*resp));
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
+{
+ struct qseecom_registered_app_list *entry = NULL;
+ unsigned long flags = 0;
+ u32 app_id = 0;
+ struct ion_handle *ihandle; /* Ion handle */
+ struct qseecom_load_img_req load_img_req;
+ int32_t ret;
+ ion_phys_addr_t pa = 0;
+ uint32_t len;
+ struct qseecom_command_scm_resp resp;
+ struct qseecom_check_app_ireq req;
+ /* Copy the relevant information needed for loading the image */
+ if (__copy_from_user(&load_img_req,
+ (void __user *)argp,
+ sizeof(struct qseecom_load_img_req))) {
+ pr_err("copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+ memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
+
+ /* SCM_CALL to check if app_id for the mentioned app exists */
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ sizeof(struct qseecom_check_app_ireq),
+ &resp, sizeof(resp));
+
+ if (resp.result == QSEOS_RESULT_FAILURE)
+ app_id = 0;
+ else
+ app_id = resp.data;
+
+ if (app_id) {
+ pr_warn("App id already exists\n");
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+ list_for_each_entry(entry,
+ &qseecom.registered_app_list_head, list){
+ if (entry->app_id == app_id) {
+ entry->ref_cnt++;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(
+ &qseecom.registered_app_list_lock, flags);
+ } else {
+ struct qseecom_load_app_ireq load_req;
+
+ pr_warn("App id does not exist\n");
+ /* Get the handle of the shared fd */
+ ihandle = ion_import_fd(qseecom.ion_clnt,
+ load_img_req.ifd_data_fd);
+ if (IS_ERR_OR_NULL(ihandle)) {
+ pr_err("Ion client could not retrieve the handle\n");
+ return -ENOMEM;
+ }
+
+ /* Get the physical address of the ION BUF */
+ ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
+
+ /* Populate the structure for sending scm call to load image */
+ load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
+ load_req.mdt_len = load_img_req.mdt_len;
+ load_req.img_len = load_img_req.img_len;
+ load_req.phy_addr = pa;
+
+ /* SCM_CALL to load the app and get the app_id back */
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
+ sizeof(struct qseecom_load_app_ireq),
+ &resp, sizeof(resp));
+
+ if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret) {
+ pr_err("process_incomplete_cmd failed err: %d\n",
+ ret);
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+ return ret;
+ }
+ }
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("scm_call failed resp.result != QSEOS_RESULT_SUCCESS\n");
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+ return -EFAULT;
+ }
+
+ app_id = resp.data;
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ pr_err("kmalloc failed\n");
+ return -ENOMEM;
+ }
+ entry->app_id = app_id;
+ entry->ref_cnt = 1;
+
+ /* Deallocate the handle */
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+ list_add_tail(&entry->list, &qseecom.registered_app_list_head);
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+ flags);
+ }
+ data->client.app_id = app_id;
+ load_img_req.app_id = app_id;
+ if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
+ pr_err("copy_to_user failed\n");
+ kzfree(entry);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
+{
+ wake_up_all(&qseecom.send_resp_wq);
+ while (atomic_read(&data->ioctl_count) > 1) {
+ if (wait_event_interruptible(data->abort_wq,
+ atomic_read(&data->ioctl_count) <= 1)) {
+ pr_err("Interrupted from abort\n");
+ return -ERESTARTSYS;
+ break;
+ }
+ }
+ /* Set unload app */
+ return 1;
+}
+
+static int qseecom_unload_app(struct qseecom_dev_handle *data)
+{
+ unsigned long flags;
+ int ret = 0;
+ struct qseecom_command_scm_resp resp;
+ struct qseecom_registered_app_list *ptr_app;
+ uint32_t unload = 0;
+
+ if (qseecom.qseos_version == QSEOS_VERSION_14) {
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+ list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
+ list) {
+ if (ptr_app->app_id == data->client.app_id) {
+ if (ptr_app->ref_cnt == 1) {
+ unload = __qseecom_cleanup_app(data);
+ list_del(&ptr_app->list);
+ kzfree(ptr_app);
+ break;
+ } else {
+ ptr_app->ref_cnt--;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+ flags);
+ }
+ if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+ ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+ ion_free(qseecom.ion_clnt, data->client.ihandle);
+ }
+
+ if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
+ struct qseecom_unload_app_ireq req;
+
+ /* Populate the structure for sending scm call to load image */
+ req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
+ req.app_id = data->client.app_id;
+
+ /* SCM_CALL to unload the app */
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ sizeof(struct qseecom_unload_app_ireq),
+ &resp, sizeof(resp));
+ if (ret) {
+ pr_err("Fail to unload APP\n");
+ return -EFAULT;
+ }
+ if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret) {
+ pr_err("process_incomplete_cmd fail err: %d\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ if (qseecom.qseos_version == QSEOS_VERSION_13) {
+ data->abort = 1;
+ wake_up_all(&qseecom.send_resp_wq);
+ while (atomic_read(&data->ioctl_count) > 0) {
+ if (wait_event_interruptible(data->abort_wq,
+ atomic_read(&data->ioctl_count) <= 0)) {
+ pr_err("Interrupted from abort\n");
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ mutex_lock(&pil_access_lock);
+ if (pil_ref_cnt == 1)
+ pil_put(pil);
+ pil_ref_cnt--;
+ mutex_unlock(&pil_access_lock);
+ }
+ data->released = true;
+ return ret;
+}
+
+static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
+ uint32_t virt)
+{
+ return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
+}
+
+static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
+ struct qseecom_send_cmd_req *req)
+{
+ int ret = 0;
+ unsigned long flags;
+ u32 reqd_len_sb_in = 0;
+ struct qseecom_command cmd;
+ struct qseecom_response resp;
+
+
+ if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+ pr_err("cmd buffer or response buffer is null\n");
+ return -EINVAL;
+ }
+
+ if (req->cmd_req_len <= 0 ||
+ req->resp_len <= 0 ||
+ req->cmd_req_len > data->client.sb_length ||
+ req->resp_len > data->client.sb_length) {
+ pr_err("cmd buffer length or "
+ "response buffer length not valid\n");
+ return -EINVAL;
+ }
+
+ reqd_len_sb_in = req->cmd_req_len + req->resp_len;
+ if (reqd_len_sb_in > data->client.sb_length) {
+ pr_debug("Not enough memory to fit cmd_buf and "
+ "resp_buf. Required: %u, Available: %u\n",
+ reqd_len_sb_in, data->client.sb_length);
+ return -ENOMEM;
+ }
+ cmd.cmd_type = TZ_SCHED_CMD_NEW;
+ cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
+ cmd.sb_in_cmd_len = req->cmd_req_len;
+
+ resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+ resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
+ resp.sb_in_rsp_len = req->resp_len;
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
+ sizeof(cmd), &resp, sizeof(resp));
+
+ if (ret) {
+ pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
+ return ret;
+ }
+
+ while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+ /*
+ * If cmd is incomplete, get the callback cmd out from SB out
+ * and put it on the list
+ */
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ /*
+ * We don't know which service can handle the command. so we
+ * wake up all blocking services and let them figure out if
+ * they can handle the given command.
+ */
+ spin_lock_irqsave(&qseecom.registered_listener_list_lock,
+ flags);
+ list_for_each_entry(ptr_svc,
+ &qseecom.registered_listener_list_head, list) {
+ ptr_svc->rcv_req_flag = 1;
+ wake_up_interruptible(&ptr_svc->rcv_req_wq);
+ }
+ spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
+ flags);
+
+ pr_debug("waking up rcv_req_wq and "
+ "waiting for send_resp_wq\n");
+ if (wait_event_interruptible(qseecom.send_resp_wq,
+ __qseecom_listener_has_sent_rsp(data))) {
+ pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
+ return -ERESTARTSYS;
+ }
+
+ if (data->abort) {
+ pr_err("Aborting driver\n");
+ return -ENODEV;
+ }
+ qseecom.send_resp_flag = 0;
+ cmd.cmd_type = TZ_SCHED_CMD_PENDING;
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
+ sizeof(cmd), &resp, sizeof(resp));
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
+ struct qseecom_send_cmd_req *req)
+{
+ int ret = 0;
+ u32 reqd_len_sb_in = 0;
+ struct qseecom_client_send_data_ireq send_data_req;
+ struct qseecom_command_scm_resp resp;
+
+ if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+ pr_err("cmd buffer or response buffer is null\n");
+ return -EINVAL;
+ }
+
+ if (req->cmd_req_len <= 0 ||
+ req->resp_len <= 0 ||
+ req->cmd_req_len > data->client.sb_length ||
+ req->resp_len > data->client.sb_length) {
+ pr_err("cmd buffer length or "
+ "response buffer length not valid\n");
+ return -EINVAL;
+ }
+
+ reqd_len_sb_in = req->cmd_req_len + req->resp_len;
+ if (reqd_len_sb_in > data->client.sb_length) {
+ pr_debug("Not enough memory to fit cmd_buf and "
+ "resp_buf. Required: %u, Available: %u\n",
+ reqd_len_sb_in, data->client.sb_length);
+ return -ENOMEM;
+ }
+
+ send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
+ send_data_req.app_id = data->client.app_id;
+ send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
+ (uint32_t)req->cmd_req_buf));
+ send_data_req.req_len = req->cmd_req_len;
+ send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
+ (uint32_t)req->resp_buf));
+ send_data_req.rsp_len = req->resp_len;
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
+ sizeof(send_data_req),
+ &resp, sizeof(resp));
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return ret;
+ }
+
+ if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret) {
+ pr_err("process_incomplete_cmd failed err: %d\n", ret);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+
+static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
+{
+ int ret = 0;
+ struct qseecom_send_cmd_req req;
+
+ ret = copy_from_user(&req, argp, sizeof(req));
+ if (ret) {
+ pr_err("copy_from_user failed\n");
+ return ret;
+ }
+ if (qseecom.qseos_version == QSEOS_VERSION_14)
+ ret = __qseecom_send_cmd(data, &req);
+ else
+ ret = __qseecom_send_cmd_legacy(data, &req);
+ if (ret)
+ return ret;
+
+ pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+ req.resp_len, req.resp_buf);
+ return ret;
+}
+
+static int __qseecom_send_cmd_req_clean_up(
+ struct qseecom_send_modfd_cmd_req *req)
+{
+ char *field;
+ uint32_t *update;
+ int ret = 0;
+ int i = 0;
+
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (req->ifd_data[i].fd != 0) {
+ field = (char *)req->cmd_req_buf +
+ req->ifd_data[i].cmd_buf_offset;
+ update = (uint32_t *) field;
+ *update = 0;
+ }
+ }
+ return ret;
+}
+
+static int __qseecom_update_with_phy_addr(
+ struct qseecom_send_modfd_cmd_req *req)
+{
+ struct ion_handle *ihandle;
+ char *field;
+ uint32_t *update;
+ ion_phys_addr_t pa;
+ int ret = 0;
+ int i = 0;
+ uint32_t length;
+
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (req->ifd_data[i].fd != 0) {
+ /* Get the handle of the shared fd */
+ ihandle = ion_import_fd(qseecom.ion_clnt,
+ req->ifd_data[i].fd);
+ if (IS_ERR_OR_NULL(ihandle)) {
+ pr_err("Ion client can't retrieve the handle\n");
+ return -ENOMEM;
+ }
+ field = (char *) req->cmd_req_buf +
+ req->ifd_data[i].cmd_buf_offset;
+ update = (uint32_t *) field;
+
+ /* Populate the cmd data structure with the phys_addr */
+ ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &length);
+ if (ret)
+ return -ENOMEM;
+
+ *update = (uint32_t)pa;
+ /* Deallocate the handle */
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+ }
+ }
+ return ret;
+}
+
+static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ int ret = 0;
+ struct qseecom_send_modfd_cmd_req req;
+ struct qseecom_send_cmd_req send_cmd_req;
+
+ ret = copy_from_user(&req, argp, sizeof(req));
+ if (ret) {
+ pr_err("copy_from_user failed\n");
+ return ret;
+ }
+ send_cmd_req.cmd_req_buf = req.cmd_req_buf;
+ send_cmd_req.cmd_req_len = req.cmd_req_len;
+ send_cmd_req.resp_buf = req.resp_buf;
+ send_cmd_req.resp_len = req.resp_len;
+
+ ret = __qseecom_update_with_phy_addr(&req);
+ if (ret)
+ return ret;
+ if (qseecom.qseos_version == QSEOS_VERSION_14)
+ ret = __qseecom_send_cmd(data, &send_cmd_req);
+ else
+ ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
+ __qseecom_send_cmd_req_clean_up(&req);
+
+ if (ret)
+ return ret;
+
+ pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+ req.resp_len, req.resp_buf);
+ return ret;
+}
+
+static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
+ struct qseecom_registered_listener_list *svc)
+{
+ int ret;
+ ret = (svc->rcv_req_flag != 0);
+ return ret || data->abort;
+}
+
+static int qseecom_receive_req(struct qseecom_dev_handle *data)
+{
+ int ret = 0;
+ struct qseecom_registered_listener_list *this_lstnr;
+
+ this_lstnr = __qseecom_find_svc(data->listener.id);
+ while (1) {
+ if (wait_event_interruptible(this_lstnr->rcv_req_wq,
+ __qseecom_listener_has_rcvd_req(data,
+ this_lstnr))) {
+ pr_warning("Interrupted: exiting wait_rcv_req loop\n");
+ /* woken up for different reason */
+ return -ERESTARTSYS;
+ }
+
+ if (data->abort) {
+ pr_err("Aborting driver!\n");
+ return -ENODEV;
+ }
+ this_lstnr->rcv_req_flag = 0;
+ if (qseecom.qseos_version == QSEOS_VERSION_13) {
+ if (*((uint32_t *)this_lstnr->sb_virt) != 0)
+ break;
+ } else {
+ break;
+ }
+ }
+ return ret;
+}
+
+static int qseecom_send_resp(void)
+{
+ qseecom.send_resp_flag = 1;
+ wake_up_interruptible(&qseecom.send_resp_wq);
+ return 0;
+}
+
+static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ struct qseecom_qseos_version_req req;
+
+ if (copy_from_user(&req, argp, sizeof(req))) {
+ pr_err("copy_from_user failed");
+ return -EINVAL;
+ }
+ req.qseos_version = qseecom.qseos_version;
+ if (copy_to_user(argp, &req, sizeof(req))) {
+ pr_err("copy_to_user failed");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int qsee_vote_for_clock(void)
+{
+ int ret = 0;
+
+ if (!qsee_perf_client)
+ return -EINVAL;
+
+ mutex_lock(&qsee_bw_mutex);
+ if (!qsee_bw_count) {
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 1);
+ if (ret) {
+ pr_err("Bandwidth request failed (%d)\n", ret);
+ } else {
+ ret = clk_enable(qseecom_bus_clk);
+ if (ret)
+ pr_err("Clock enable failed\n");
+ }
+ }
+ if (ret)
+ msm_bus_scale_client_update_request(qsee_perf_client, 0);
+ else
+ qsee_bw_count++;
+
+ mutex_unlock(&qsee_bw_mutex);
+ return ret;
+}
+
+static void qsee_disable_clock_vote(void)
+{
+ if (!qsee_perf_client)
+ return ;
+
+ mutex_lock(&qsee_bw_mutex);
+ if (qsee_bw_count > 0) {
+ if (qsee_bw_count-- == 1) {
+ msm_bus_scale_client_update_request(qsee_perf_client,
+ 0);
+ clk_disable(qseecom_bus_clk);
+ }
+ }
+ mutex_unlock(&qsee_bw_mutex);
+}
+
+
+static long qseecom_ioctl(struct file *file, unsigned cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+ struct qseecom_dev_handle *data = file->private_data;
+ void __user *argp = (void __user *) arg;
+
+ if (data->abort) {
+ pr_err("Aborting qseecom driver\n");
+ return -ENODEV;
+ }
+
+ switch (cmd) {
+ case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
+ pr_debug("ioctl register_listener_req()\n");
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_register_listener(data, argp);
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ if (ret)
+ pr_err("failed qseecom_register_listener: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
+ pr_debug("ioctl unregister_listener_req()\n");
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_unregister_listener(data);
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ if (ret)
+ pr_err("failed qseecom_unregister_listener: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_SEND_CMD_REQ: {
+ /* Only one client allowed here at a time */
+ mutex_lock(&send_msg_lock);
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_send_cmd(data, argp);
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ mutex_unlock(&send_msg_lock);
+ if (ret)
+ pr_err("failed qseecom_send_cmd: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+ /* Only one client allowed here at a time */
+ mutex_lock(&send_msg_lock);
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_send_modfd_cmd(data, argp);
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ mutex_unlock(&send_msg_lock);
+ if (ret)
+ pr_err("failed qseecom_send_cmd: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_RECEIVE_REQ: {
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_receive_req(data);
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ if (ret)
+ pr_err("failed qseecom_receive_req: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_SEND_RESP_REQ: {
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_send_resp();
+ atomic_dec(&data->ioctl_count);
+ wake_up_all(&data->abort_wq);
+ if (ret)
+ pr_err("failed qseecom_send_resp: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
+ ret = qseecom_set_client_mem_param(data, argp);
+ if (ret)
+ pr_err("failed Qqseecom_set_mem_param request: %d\n",
+ ret);
+ break;
+ }
+ case QSEECOM_IOCTL_LOAD_APP_REQ: {
+ mutex_lock(&app_access_lock);
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_load_app(data, argp);
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
+ if (ret)
+ pr_err("failed load_app request: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
+ mutex_lock(&app_access_lock);
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_unload_app(data);
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
+ if (ret)
+ pr_err("failed unload_app request: %d\n", ret);
+ break;
+ }
+ case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_get_qseos_version(data, argp);
+ if (ret)
+ pr_err("qseecom_get_qseos_version: %d\n", ret);
+ atomic_dec(&data->ioctl_count);
+ break;
+ }
+ case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
+ atomic_inc(&data->ioctl_count);
+ ret = qsee_vote_for_clock();
+ if (ret)
+ pr_err("Failed to vote for clock%d\n", ret);
+ atomic_dec(&data->ioctl_count);
+ break;
+ }
+ case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
+ atomic_inc(&data->ioctl_count);
+ qsee_disable_clock_vote();
+ atomic_dec(&data->ioctl_count);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static int qseecom_open(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+ struct qseecom_dev_handle *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ pr_err("kmalloc failed\n");
+ return -ENOMEM;
+ }
+ file->private_data = data;
+ data->abort = 0;
+ data->service = false;
+ data->released = false;
+ init_waitqueue_head(&data->abort_wq);
+ atomic_set(&data->ioctl_count, 0);
+ return ret;
+}
+
+static int qseecom_release(struct inode *inode, struct file *file)
+{
+ struct qseecom_dev_handle *data = file->private_data;
+ int ret = 0;
+
+ if (data->released == false) {
+ pr_warn("data->released == false\n");
+ if (data->service)
+ ret = qseecom_unregister_listener(data);
+ else
+ ret = qseecom_unload_app(data);
+ if (ret) {
+ pr_err("Close failed\n");
+ return ret;
+ }
+ }
+ kfree(data);
+ return ret;
+}
+
+/* qseecom bus scaling */
+static struct msm_bus_paths qsee_bw_table[] = {
+ {
+ .vectors = (struct msm_bus_vectors[]){
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ },
+ },
+ .num_paths = 1,
+ },
+ {
+ .vectors = (struct msm_bus_vectors[]){
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ },
+ .num_paths = 1,
+ },
+};
+
+static struct msm_bus_scale_pdata qsee_bus_pdata = {
+ .usecase = qsee_bw_table,
+ .num_usecases = ARRAY_SIZE(qsee_bw_table),
+ .name = "qsee",
+};
+
+static const struct file_operations qseecom_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = qseecom_ioctl,
+ .open = qseecom_open,
+ .release = qseecom_release
+};
+
+static int __init qseecom_init(void)
+{
+ int rc;
+ int ret = 0;
+ struct device *class_dev;
+ char qsee_not_legacy = 0;
+ uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
+
+ rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
+ if (rc < 0) {
+ pr_err("alloc_chrdev_region failed %d\n", rc);
+ return rc;
+ }
+
+ driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
+ if (IS_ERR(driver_class)) {
+ rc = -ENOMEM;
+ pr_err("class_create failed %d\n", rc);
+ goto unregister_chrdev_region;
+ }
+
+ class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
+ QSEECOM_DEV);
+ if (!class_dev) {
+ pr_err("class_device_create failed %d\n", rc);
+ rc = -ENOMEM;
+ goto class_destroy;
+ }
+
+ cdev_init(&qseecom_cdev, &qseecom_fops);
+ qseecom_cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
+ if (rc < 0) {
+ pr_err("cdev_add failed %d\n", rc);
+ goto err;
+ }
+
+ INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
+ spin_lock_init(&qseecom.registered_listener_list_lock);
+ INIT_LIST_HEAD(&qseecom.registered_app_list_head);
+ spin_lock_init(&qseecom.registered_app_list_lock);
+ init_waitqueue_head(&qseecom.send_resp_wq);
+ qseecom.send_resp_flag = 0;
+
+ rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
+ &qsee_not_legacy, sizeof(qsee_not_legacy));
+ if (rc) {
+ pr_err("Failed to retrieve QSEE version information %d\n", rc);
+ goto err;
+ }
+ if (qsee_not_legacy)
+ qseecom.qseos_version = QSEOS_VERSION_14;
+ else {
+ qseecom.qseos_version = QSEOS_VERSION_13;
+ pil = NULL;
+ pil_ref_cnt = 0;
+ }
+ /* Create ION msm client */
+ qseecom.ion_clnt = msm_ion_client_create(0x03, "qseecom-kernel");
+ if (qseecom.ion_clnt == NULL) {
+ pr_err("Ion client cannot be created\n");
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ /* register client for bus scaling */
+ qsee_perf_client = msm_bus_scale_register_client(&qsee_bus_pdata);
+ if (!qsee_perf_client)
+ pr_err("Unable to register bus client\n");
+
+ qseecom_bus_clk = clk_get_sys("scm", "bus_clk");
+ if (!IS_ERR(qseecom_bus_clk)) {
+ ret = clk_set_rate(qseecom_bus_clk, 64000000);
+ if (ret) {
+ qseecom_bus_clk = NULL;
+ pr_err("Unable to set clock rate\n");
+ }
+ } else {
+ qseecom_bus_clk = NULL;
+ pr_warn("Unable to get bus clk\n");
+ }
+ return 0;
+err:
+ device_destroy(driver_class, qseecom_device_no);
+class_destroy:
+ class_destroy(driver_class);
+unregister_chrdev_region:
+ unregister_chrdev_region(qseecom_device_no, 1);
+ return rc;
+}
+
+static void __exit qseecom_exit(void)
+{
+ device_destroy(driver_class, qseecom_device_no);
+ class_destroy(driver_class);
+ unregister_chrdev_region(qseecom_device_no, 1);
+ ion_client_destroy(qseecom.ion_clnt);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
+
+module_init(qseecom_init);
+module_exit(qseecom_exit);
diff --git a/drivers/misc/qseecom_legacy.h b/drivers/misc/qseecom_legacy.h
new file mode 100644
index 0000000..66f87e9
--- /dev/null
+++ b/drivers/misc/qseecom_legacy.h
@@ -0,0 +1,79 @@
+/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+ *
+ * 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 __QSEECOM_LEGACY_H_
+#define __QSEECOM_LEGACY_H_
+
+#include <linux/types.h>
+
+#define TZ_SCHED_CMD_ID_REGISTER_LISTENER 0x04
+
+enum tz_sched_cmd_type {
+ TZ_SCHED_CMD_INVALID = 0,
+ TZ_SCHED_CMD_NEW, /* New TZ Scheduler Command */
+ TZ_SCHED_CMD_PENDING, /* Pending cmd...sched will restore stack */
+ TZ_SCHED_CMD_COMPLETE, /* TZ sched command is complete */
+ TZ_SCHED_CMD_MAX = 0x7FFFFFFF
+};
+
+enum tz_sched_cmd_status {
+ TZ_SCHED_STATUS_INCOMPLETE = 0,
+ TZ_SCHED_STATUS_COMPLETE,
+ TZ_SCHED_STATUS_MAX = 0x7FFFFFFF
+};
+/* Command structure for initializing shared buffers */
+__packed struct qse_pr_init_sb_req_s {
+ /* First 4 bytes should always be command id */
+ uint32_t pr_cmd;
+ /* Pointer to the physical location of sb buffer */
+ uint32_t sb_ptr;
+ /* length of shared buffer */
+ uint32_t sb_len;
+ uint32_t listener_id;
+};
+
+__packed struct qse_pr_init_sb_rsp_s {
+ /* First 4 bytes should always be command id */
+ uint32_t pr_cmd;
+ /* Return code, 0 for success, Approp error code otherwise */
+ int32_t ret;
+};
+
+/*
+ * struct QSEECom_command - QSECom command buffer
+ * @cmd_type: value from enum tz_sched_cmd_type
+ * @sb_in_cmd_addr: points to physical location of command
+ * buffer
+ * @sb_in_cmd_len: length of command buffer
+ */
+__packed struct qseecom_command {
+ uint32_t cmd_type;
+ uint8_t *sb_in_cmd_addr;
+ uint32_t sb_in_cmd_len;
+};
+
+/*
+ * struct QSEECom_response - QSECom response buffer
+ * @cmd_status: value from enum tz_sched_cmd_status
+ * @sb_in_rsp_addr: points to physical location of response
+ * buffer
+ * @sb_in_rsp_len: length of command response
+ */
+__packed struct qseecom_response {
+ uint32_t cmd_status;
+ uint8_t *sb_in_rsp_addr;
+ uint32_t sb_in_rsp_len;
+};
+
+#endif /* __QSEECOM_LEGACY_H_ */
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 48f3f2d..4634e75 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -94,6 +94,11 @@
unsigned int read_only;
unsigned int part_type;
unsigned int name_idx;
+ unsigned int reset_done;
+#define MMC_BLK_READ BIT(0)
+#define MMC_BLK_WRITE BIT(1)
+#define MMC_BLK_DISCARD BIT(2)
+#define MMC_BLK_SECDISCARD BIT(3)
/*
* Only set in main mmc_blk_data associated
@@ -106,6 +111,16 @@
static DEFINE_MUTEX(open_lock);
+enum mmc_blk_status {
+ MMC_BLK_SUCCESS = 0,
+ MMC_BLK_PARTIAL,
+ MMC_BLK_CMD_ERR,
+ MMC_BLK_RETRY,
+ MMC_BLK_ABORT,
+ MMC_BLK_DATA_ERR,
+ MMC_BLK_ECC_ERR,
+};
+
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
@@ -277,7 +292,7 @@
struct mmc_card *card;
struct mmc_command cmd = {0};
struct mmc_data data = {0};
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct scatterlist sg;
int err;
@@ -423,32 +438,29 @@
#endif
};
-struct mmc_blk_request {
- struct mmc_request mrq;
- struct mmc_command sbc;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_data data;
-};
-
static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md)
{
int ret;
struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+
if (main_md->part_curr == md->part_type)
return 0;
if (mmc_card_mmc(card)) {
- card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
- card->ext_csd.part_config |= md->part_type;
+ u8 part_config = card->ext_csd.part_config;
+
+ part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+ part_config |= md->part_type;
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+ EXT_CSD_PART_CONFIG, part_config,
card->ext_csd.part_time);
if (ret)
return ret;
-}
+
+ card->ext_csd.part_config = part_config;
+ }
main_md->part_curr = md->part_type;
return 0;
@@ -460,7 +472,7 @@
u32 result;
__be32 *blocks;
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
unsigned int timeout_us;
@@ -615,7 +627,7 @@
* Otherwise we don't understand what happened, so abort.
*/
static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
- struct mmc_blk_request *brq)
+ struct mmc_blk_request *brq, int *ecc_err)
{
bool prev_cmd_status_valid = true;
u32 status, stop_status = 0;
@@ -647,6 +659,12 @@
return ERR_ABORT;
}
+ /* Flag ECC errors */
+ if ((status & R1_CARD_ECC_FAILED) ||
+ (brq->stop.resp[0] & R1_CARD_ECC_FAILED) ||
+ (brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
+ *ecc_err = 1;
+
/*
* Check the current card state. If it is in some data transfer
* mode, tell it to stop (and hopefully transition back to TRAN.)
@@ -664,6 +682,8 @@
*/
if (err)
return ERR_ABORT;
+ if (stop_status & R1_CARD_ECC_FAILED)
+ *ecc_err = 1;
}
/* Check for set block count errors */
@@ -676,6 +696,10 @@
return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
prev_cmd_status_valid, status);
+ /* Data errors */
+ if (!brq->stop.error)
+ return ERR_CONTINUE;
+
/* Now for stop errors. These aren't fatal to the transfer. */
pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
req->rq_disk->disk_name, brq->stop.error,
@@ -692,12 +716,45 @@
return ERR_CONTINUE;
}
+static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
+ int type)
+{
+ int err;
+
+ if (md->reset_done & type)
+ return -EEXIST;
+
+ md->reset_done |= type;
+ err = mmc_hw_reset(host);
+ /* Ensure we switch back to the correct partition */
+ if (err != -EOPNOTSUPP) {
+ struct mmc_blk_data *main_md = mmc_get_drvdata(host->card);
+ int part_err;
+
+ main_md->part_curr = main_md->part_type;
+ part_err = mmc_blk_part_switch(host->card, md);
+ if (part_err) {
+ /*
+ * We have failed to get back into the correct
+ * partition, so we need to abort the whole request.
+ */
+ return -ENODEV;
+ }
+ }
+ return err;
+}
+
+static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
+{
+ md->reset_done &= ~type;
+}
+
static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg;
- int err = 0;
+ int err = 0, type = MMC_BLK_DISCARD;
if (!mmc_can_erase(card)) {
err = -EOPNOTSUPP;
@@ -707,11 +764,13 @@
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
- if (mmc_can_trim(card))
+ if (mmc_can_discard(card))
+ arg = MMC_DISCARD_ARG;
+ else if (mmc_can_trim(card))
arg = MMC_TRIM_ARG;
else
arg = MMC_ERASE_ARG;
-
+retry:
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
INAND_CMD38_ARG_EXT_CSD,
@@ -724,6 +783,10 @@
}
err = mmc_erase(card, from, nr, arg);
out:
+ if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+ goto retry;
+ if (!err)
+ mmc_blk_reset_success(md, type);
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
@@ -737,13 +800,20 @@
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg;
- int err = 0;
+ int err = 0, type = MMC_BLK_SECDISCARD;
- if (!mmc_can_secure_erase_trim(card)) {
+ if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
err = -EOPNOTSUPP;
goto out;
}
+ /* The sanitize operation is supported at v4.5 only */
+ if (mmc_can_sanitize(card)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_SANITIZE_START, 1, 0);
+ goto out;
+ }
+
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
@@ -751,7 +821,7 @@
arg = MMC_SECURE_TRIM1_ARG;
else
arg = MMC_SECURE_ERASE_ARG;
-
+retry:
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
INAND_CMD38_ARG_EXT_CSD,
@@ -775,6 +845,10 @@
err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
}
out:
+ if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+ goto retry;
+ if (!err)
+ mmc_blk_reset_success(md, type);
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
@@ -785,16 +859,18 @@
static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
+ struct mmc_card *card = md->queue.card;
+ int ret = 0;
- /*
- * No-op, only service this because we need REQ_FUA for reliable
- * writes.
- */
+ ret = mmc_flush_cache(card);
+ if (ret)
+ ret = -EIO;
+
spin_lock_irq(&md->lock);
- __blk_end_request_all(req, 0);
+ __blk_end_request_all(req, ret);
spin_unlock_irq(&md->lock);
- return 1;
+ return ret ? 0 : 1;
}
/*
@@ -828,12 +904,106 @@
R1_CC_ERROR | /* Card controller error */ \
R1_ERROR) /* General/unknown error */
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+static int mmc_blk_err_check(struct mmc_card *card,
+ struct mmc_async_req *areq)
{
+ struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
+ mmc_active);
+ struct mmc_blk_request *brq = &mq_mrq->brq;
+ struct request *req = mq_mrq->req;
+ int ecc_err = 0;
+
+ /*
+ * sbc.error indicates a problem with the set block count
+ * command. No data will have been transferred.
+ *
+ * cmd.error indicates a problem with the r/w command. No
+ * data will have been transferred.
+ *
+ * stop.error indicates a problem with the stop command. Data
+ * may have been transferred, or may still be transferring.
+ */
+ if (brq->sbc.error || brq->cmd.error || brq->stop.error ||
+ brq->data.error) {
+ switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) {
+ case ERR_RETRY:
+ return MMC_BLK_RETRY;
+ case ERR_ABORT:
+ case ERR_NOMEDIUM:
+ return MMC_BLK_ABORT;
+ case ERR_CONTINUE:
+ break;
+ }
+ }
+
+ /*
+ * Check for errors relating to the execution of the
+ * initial command - such as address errors. No data
+ * has been transferred.
+ */
+ if (brq->cmd.resp[0] & CMD_ERRORS) {
+ pr_err("%s: r/w command failed, status = %#x\n",
+ req->rq_disk->disk_name, brq->cmd.resp[0]);
+ return MMC_BLK_ABORT;
+ }
+
+ /*
+ * Everything else is either success, or a data error of some
+ * kind. If it was a write, we may have transitioned to
+ * program mode, which we have to wait for it to complete.
+ */
+ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+ u32 status;
+ do {
+ int err = get_card_status(card, &status, 5);
+ if (err) {
+ printk(KERN_ERR "%s: error %d requesting status\n",
+ req->rq_disk->disk_name, err);
+ return MMC_BLK_CMD_ERR;
+ }
+ /*
+ * Some cards mishandle the status bits,
+ * so make sure to check both the busy
+ * indication and the card state.
+ */
+ } while (!(status & R1_READY_FOR_DATA) ||
+ (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+ }
+
+ if (brq->data.error) {
+ pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
+ req->rq_disk->disk_name, brq->data.error,
+ (unsigned)blk_rq_pos(req),
+ (unsigned)blk_rq_sectors(req),
+ brq->cmd.resp[0], brq->stop.resp[0]);
+
+ if (rq_data_dir(req) == READ) {
+ if (ecc_err)
+ return MMC_BLK_ECC_ERR;
+ return MMC_BLK_DATA_ERR;
+ } else {
+ return MMC_BLK_CMD_ERR;
+ }
+ }
+
+ if (!brq->data.bytes_xfered)
+ return MMC_BLK_RETRY;
+
+ if (blk_rq_bytes(req) != brq->data.bytes_xfered)
+ return MMC_BLK_PARTIAL;
+
+ return MMC_BLK_SUCCESS;
+}
+
+static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_card *card,
+ int disable_multi,
+ struct mmc_queue *mq)
+{
+ u32 readcmd, writecmd;
+ struct mmc_blk_request *brq = &mqrq->brq;
+ struct request *req = mqrq->req;
struct mmc_blk_data *md = mq->data;
- struct mmc_card *card = md->queue.card;
- struct mmc_blk_request brq;
- int ret = 1, disable_multi = 0, retry = 0;
/*
* Reliable writes are used to implement Forced Unit Access and
@@ -844,225 +1014,135 @@
(rq_data_dir(req) == WRITE) &&
(md->flags & MMC_BLK_REL_WR);
- do {
- u32 readcmd, writecmd;
+ memset(brq, 0, sizeof(struct mmc_blk_request));
+ brq->mrq.cmd = &brq->cmd;
+ brq->mrq.data = &brq->data;
- memset(&brq, 0, sizeof(struct mmc_blk_request));
- brq.mrq.cmd = &brq.cmd;
- brq.mrq.data = &brq.data;
+ brq->cmd.arg = blk_rq_pos(req);
+ if (!mmc_card_blockaddr(card))
+ brq->cmd.arg <<= 9;
+ brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ brq->data.blksz = 512;
+ brq->stop.opcode = MMC_STOP_TRANSMISSION;
+ brq->stop.arg = 0;
+ brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ brq->data.blocks = blk_rq_sectors(req);
- brq.cmd.arg = blk_rq_pos(req);
- if (!mmc_card_blockaddr(card))
- brq.cmd.arg <<= 9;
- brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq.data.blksz = 512;
- brq.stop.opcode = MMC_STOP_TRANSMISSION;
- brq.stop.arg = 0;
- brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- brq.data.blocks = blk_rq_sectors(req);
+ /*
+ * The block layer doesn't support all sector count
+ * restrictions, so we need to be prepared for too big
+ * requests.
+ */
+ if (brq->data.blocks > card->host->max_blk_count)
+ brq->data.blocks = card->host->max_blk_count;
+ if (brq->data.blocks > 1) {
/*
- * The block layer doesn't support all sector count
- * restrictions, so we need to be prepared for too big
- * requests.
+ * After a read error, we redo the request one sector
+ * at a time in order to accurately determine which
+ * sectors can be read successfully.
*/
- if (brq.data.blocks > card->host->max_blk_count)
- brq.data.blocks = card->host->max_blk_count;
+ if (disable_multi)
+ brq->data.blocks = 1;
- /*
- * After a read error, we redo the request one sector at a time
- * in order to accurately determine which sectors can be read
- * successfully.
+ /* Some controllers can't do multiblock reads due to hw bugs */
+ if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
+ rq_data_dir(req) == READ)
+ brq->data.blocks = 1;
+ }
+
+ if (brq->data.blocks > 1 || do_rel_wr) {
+ /* SPI multiblock writes terminate using a special
+ * token, not a STOP_TRANSMISSION request.
*/
- if (disable_multi && brq.data.blocks > 1)
- brq.data.blocks = 1;
+ if (!mmc_host_is_spi(card->host) ||
+ rq_data_dir(req) == READ)
+ brq->mrq.stop = &brq->stop;
+ readcmd = MMC_READ_MULTIPLE_BLOCK;
+ writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+ } else {
+ brq->mrq.stop = NULL;
+ readcmd = MMC_READ_SINGLE_BLOCK;
+ writecmd = MMC_WRITE_BLOCK;
+ }
+ if (rq_data_dir(req) == READ) {
+ brq->cmd.opcode = readcmd;
+ brq->data.flags |= MMC_DATA_READ;
+ } else {
+ brq->cmd.opcode = writecmd;
+ brq->data.flags |= MMC_DATA_WRITE;
+ }
- if (brq.data.blocks > 1 || do_rel_wr) {
- /* SPI multiblock writes terminate using a special
- * token, not a STOP_TRANSMISSION request.
- */
- if (!mmc_host_is_spi(card->host) ||
- rq_data_dir(req) == READ)
- brq.mrq.stop = &brq.stop;
- readcmd = MMC_READ_MULTIPLE_BLOCK;
- writecmd = MMC_WRITE_MULTIPLE_BLOCK;
- } else {
- brq.mrq.stop = NULL;
- readcmd = MMC_READ_SINGLE_BLOCK;
- writecmd = MMC_WRITE_BLOCK;
- }
- if (rq_data_dir(req) == READ) {
- brq.cmd.opcode = readcmd;
- brq.data.flags |= MMC_DATA_READ;
- } else {
- brq.cmd.opcode = writecmd;
- brq.data.flags |= MMC_DATA_WRITE;
- }
+ if (do_rel_wr)
+ mmc_apply_rel_rw(brq, card, req);
- if (do_rel_wr)
- mmc_apply_rel_rw(&brq, card, req);
+ /*
+ * Pre-defined multi-block transfers are preferable to
+ * open ended-ones (and necessary for reliable writes).
+ * However, it is not sufficient to just send CMD23,
+ * and avoid the final CMD12, as on an error condition
+ * CMD12 (stop) needs to be sent anyway. This, coupled
+ * with Auto-CMD23 enhancements provided by some
+ * hosts, means that the complexity of dealing
+ * with this is best left to the host. If CMD23 is
+ * supported by card and host, we'll fill sbc in and let
+ * the host deal with handling it correctly. This means
+ * that for hosts that don't expose MMC_CAP_CMD23, no
+ * change of behavior will be observed.
+ *
+ * N.B: Some MMC cards experience perf degradation.
+ * We'll avoid using CMD23-bounded multiblock writes for
+ * these, while retaining features like reliable writes.
+ */
- /*
- * Pre-defined multi-block transfers are preferable to
- * open ended-ones (and necessary for reliable writes).
- * However, it is not sufficient to just send CMD23,
- * and avoid the final CMD12, as on an error condition
- * CMD12 (stop) needs to be sent anyway. This, coupled
- * with Auto-CMD23 enhancements provided by some
- * hosts, means that the complexity of dealing
- * with this is best left to the host. If CMD23 is
- * supported by card and host, we'll fill sbc in and let
- * the host deal with handling it correctly. This means
- * that for hosts that don't expose MMC_CAP_CMD23, no
- * change of behavior will be observed.
- *
- * N.B: Some MMC cards experience perf degradation.
- * We'll avoid using CMD23-bounded multiblock writes for
- * these, while retaining features like reliable writes.
- */
+ if ((md->flags & MMC_BLK_CMD23) &&
+ mmc_op_multi(brq->cmd.opcode) &&
+ (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+ brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+ brq->sbc.arg = brq->data.blocks |
+ (do_rel_wr ? (1 << 31) : 0);
+ brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ brq->mrq.sbc = &brq->sbc;
+ }
- if ((md->flags & MMC_BLK_CMD23) &&
- mmc_op_multi(brq.cmd.opcode) &&
- (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
- brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
- brq.sbc.arg = brq.data.blocks |
- (do_rel_wr ? (1 << 31) : 0);
- brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
- brq.mrq.sbc = &brq.sbc;
- }
+ mmc_set_data_timeout(&brq->data, card);
- mmc_set_data_timeout(&brq.data, card);
+ brq->data.sg = mqrq->sg;
+ brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
- brq.data.sg = mq->sg;
- brq.data.sg_len = mmc_queue_map_sg(mq);
+ /*
+ * Adjust the sg list so it is the same size as the
+ * request.
+ */
+ if (brq->data.blocks != blk_rq_sectors(req)) {
+ int i, data_size = brq->data.blocks << 9;
+ struct scatterlist *sg;
- /*
- * Adjust the sg list so it is the same size as the
- * request.
- */
- if (brq.data.blocks != blk_rq_sectors(req)) {
- int i, data_size = brq.data.blocks << 9;
- struct scatterlist *sg;
-
- for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
- data_size -= sg->length;
- if (data_size <= 0) {
- sg->length += data_size;
- i++;
- break;
- }
- }
- brq.data.sg_len = i;
- }
-
- mmc_queue_bounce_pre(mq);
-
- mmc_wait_for_req(card->host, &brq.mrq);
-
- mmc_queue_bounce_post(mq);
-
- /*
- * sbc.error indicates a problem with the set block count
- * command. No data will have been transferred.
- *
- * cmd.error indicates a problem with the r/w command. No
- * data will have been transferred.
- *
- * stop.error indicates a problem with the stop command. Data
- * may have been transferred, or may still be transferring.
- */
- if (brq.sbc.error || brq.cmd.error || brq.stop.error) {
- switch (mmc_blk_cmd_recovery(card, req, &brq)) {
- case ERR_RETRY:
- if (retry++ < 5)
- continue;
- case ERR_ABORT:
- case ERR_NOMEDIUM:
- goto cmd_abort;
- case ERR_CONTINUE:
+ for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
+ data_size -= sg->length;
+ if (data_size <= 0) {
+ sg->length += data_size;
+ i++;
break;
}
}
+ brq->data.sg_len = i;
+ }
- /*
- * Check for errors relating to the execution of the
- * initial command - such as address errors. No data
- * has been transferred.
- */
- if (brq.cmd.resp[0] & CMD_ERRORS) {
- pr_err("%s: r/w command failed, status = %#x\n",
- req->rq_disk->disk_name, brq.cmd.resp[0]);
- goto cmd_abort;
- }
+ mqrq->mmc_active.mrq = &brq->mrq;
+ mqrq->mmc_active.err_check = mmc_blk_err_check;
- /*
- * Everything else is either success, or a data error of some
- * kind. If it was a write, we may have transitioned to
- * program mode, which we have to wait for it to complete.
- */
- if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
- u32 status;
- do {
- int err = get_card_status(card, &status, 5);
- if (err) {
- printk(KERN_ERR "%s: error %d requesting status\n",
- req->rq_disk->disk_name, err);
- goto cmd_err;
- }
- /*
- * Some cards mishandle the status bits,
- * so make sure to check both the busy
- * indication and the card state.
- */
- } while (!(status & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(status) == R1_STATE_PRG));
- }
+ mmc_queue_bounce_pre(mqrq);
+}
- if (brq.data.error) {
- pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq.data.error,
- (unsigned)blk_rq_pos(req),
- (unsigned)blk_rq_sectors(req),
- brq.cmd.resp[0], brq.stop.resp[0]);
-
- if (rq_data_dir(req) == READ) {
- if (brq.data.blocks > 1) {
- /* Redo read one sector at a time */
- pr_warning("%s: retrying using single block read\n",
- req->rq_disk->disk_name);
- disable_multi = 1;
- continue;
- }
-
- /*
- * After an error, we redo I/O one sector at a
- * time, so we only reach here after trying to
- * read a single sector.
- */
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, -EIO, brq.data.blksz);
- spin_unlock_irq(&md->lock);
- continue;
- } else {
- goto cmd_err;
- }
- }
-
- /*
- * A block was successfully transferred.
- */
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
- spin_unlock_irq(&md->lock);
- } while (ret);
-
- return 1;
-
- cmd_err:
- /*
- * If this is an SD card and we're writing, we can first
- * mark the known good sectors as ok.
- *
+static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
+ struct mmc_blk_request *brq, struct request *req,
+ int ret)
+{
+ /*
+ * If this is an SD card and we're writing, we can first
+ * mark the known good sectors as ok.
+ *
* If the card is not SD, we can still ok written sectors
* as reported by the controller (which might be less than
* the real number of written sectors, but never more).
@@ -1078,9 +1158,122 @@
}
} else {
spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
+ ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
}
+ return ret;
+}
+
+static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+{
+ struct mmc_blk_data *md = mq->data;
+ struct mmc_card *card = md->queue.card;
+ struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
+ int ret = 1, disable_multi = 0, retry = 0, type;
+ enum mmc_blk_status status;
+ struct mmc_queue_req *mq_rq;
+ struct request *req;
+ struct mmc_async_req *areq;
+
+ if (!rqc && !mq->mqrq_prev->req)
+ return 0;
+
+ do {
+ if (rqc) {
+ mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+ areq = &mq->mqrq_cur->mmc_active;
+ } else
+ areq = NULL;
+ areq = mmc_start_req(card->host, areq, (int *) &status);
+ if (!areq)
+ return 0;
+
+ mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
+ brq = &mq_rq->brq;
+ req = mq_rq->req;
+ type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+ mmc_queue_bounce_post(mq_rq);
+
+ switch (status) {
+ case MMC_BLK_SUCCESS:
+ case MMC_BLK_PARTIAL:
+ /*
+ * A block was successfully transferred.
+ */
+ mmc_blk_reset_success(md, type);
+ spin_lock_irq(&md->lock);
+ ret = __blk_end_request(req, 0,
+ brq->data.bytes_xfered);
+ spin_unlock_irq(&md->lock);
+ /*
+ * If the blk_end_request function returns non-zero even
+ * though all data has been transferred and no errors
+ * were returned by the host controller, it's a bug.
+ */
+ if (status == MMC_BLK_SUCCESS && ret) {
+ printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n",
+ __func__, blk_rq_bytes(req),
+ brq->data.bytes_xfered);
+ rqc = NULL;
+ goto cmd_abort;
+ }
+ break;
+ case MMC_BLK_CMD_ERR:
+ ret = mmc_blk_cmd_err(md, card, brq, req, ret);
+ if (!mmc_blk_reset(md, card->host, type))
+ break;
+ goto cmd_abort;
+ case MMC_BLK_RETRY:
+ if (retry++ < 5)
+ break;
+ /* Fall through */
+ case MMC_BLK_ABORT:
+ if (!mmc_blk_reset(md, card->host, type))
+ break;
+ goto cmd_abort;
+ case MMC_BLK_DATA_ERR: {
+ int err;
+
+ err = mmc_blk_reset(md, card->host, type);
+ if (!err)
+ break;
+ if (err == -ENODEV)
+ goto cmd_abort;
+ /* Fall through */
+ }
+ case MMC_BLK_ECC_ERR:
+ if (brq->data.blocks > 1) {
+ /* Redo read one sector at a time */
+ pr_warning("%s: retrying using single block read\n",
+ req->rq_disk->disk_name);
+ disable_multi = 1;
+ break;
+ }
+ /*
+ * After an error, we redo I/O one sector at a
+ * time, so we only reach here after trying to
+ * read a single sector.
+ */
+ spin_lock_irq(&md->lock);
+ ret = __blk_end_request(req, -EIO,
+ brq->data.blksz);
+ spin_unlock_irq(&md->lock);
+ if (!ret)
+ goto start_new_req;
+ break;
+ }
+
+ if (ret) {
+ /*
+ * In case of a incomplete request
+ * prepare it again and resend.
+ */
+ mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
+ mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
+ }
+ } while (ret);
+
+ return 1;
cmd_abort:
spin_lock_irq(&md->lock);
@@ -1090,6 +1283,12 @@
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
spin_unlock_irq(&md->lock);
+ start_new_req:
+ if (rqc) {
+ mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+ mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
+ }
+
return 0;
}
@@ -1109,26 +1308,42 @@
}
#endif
- mmc_claim_host(card->host);
+ if (req && !mq->mqrq_prev->req)
+ /* claim host only for the first request */
+ mmc_claim_host(card->host);
+
ret = mmc_blk_part_switch(card, md);
if (ret) {
+ if (req) {
+ spin_lock_irq(&md->lock);
+ __blk_end_request_all(req, -EIO);
+ spin_unlock_irq(&md->lock);
+ }
ret = 0;
goto out;
}
- if (req->cmd_flags & REQ_DISCARD) {
+ if (req && req->cmd_flags & REQ_DISCARD) {
+ /* complete ongoing async transfer before issuing discard */
+ if (card->host->areq)
+ mmc_blk_issue_rw_rq(mq, NULL);
if (req->cmd_flags & REQ_SECURE)
ret = mmc_blk_issue_secdiscard_rq(mq, req);
else
ret = mmc_blk_issue_discard_rq(mq, req);
- } else if (req->cmd_flags & REQ_FLUSH) {
+ } else if (req && req->cmd_flags & REQ_FLUSH) {
+ /* complete ongoing async transfer before issuing flush */
+ if (card->host->areq)
+ mmc_blk_issue_rw_rq(mq, NULL);
ret = mmc_blk_issue_flush(mq, req);
} else {
ret = mmc_blk_issue_rw_rq(mq, req);
}
out:
- mmc_release_host(card->host);
+ if (!req)
+ /* release host only when there are no more requests */
+ mmc_release_host(card->host);
return ret;
}
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 233cdfa..a2b005e 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -22,6 +22,7 @@
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/seq_file.h>
+#include <linux/module.h>
#define RESULT_OK 0
#define RESULT_FAIL 1
@@ -148,6 +149,27 @@
struct mmc_test_general_result *gr;
};
+enum mmc_test_prep_media {
+ MMC_TEST_PREP_NONE = 0,
+ MMC_TEST_PREP_WRITE_FULL = 1 << 0,
+ MMC_TEST_PREP_ERASE = 1 << 1,
+};
+
+struct mmc_test_multiple_rw {
+ unsigned int *sg_len;
+ unsigned int *bs;
+ unsigned int len;
+ unsigned int size;
+ bool do_write;
+ bool do_nonblock_req;
+ enum mmc_test_prep_media prepare;
+};
+
+struct mmc_test_async_req {
+ struct mmc_async_req areq;
+ struct mmc_test_card *test;
+};
+
/*******************************************************************/
/* General helper functions */
/*******************************************************************/
@@ -203,7 +225,7 @@
static int mmc_test_busy(struct mmc_command *cmd)
{
return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(cmd->resp[0]) == 7);
+ (R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
}
/*
@@ -367,21 +389,26 @@
* Map memory into a scatterlist. Optionally allow the same memory to be
* mapped more than once.
*/
-static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
+static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
struct scatterlist *sglist, int repeat,
unsigned int max_segs, unsigned int max_seg_sz,
- unsigned int *sg_len)
+ unsigned int *sg_len, int min_sg_len)
{
struct scatterlist *sg = NULL;
unsigned int i;
+ unsigned long sz = size;
sg_init_table(sglist, max_segs);
+ if (min_sg_len > max_segs)
+ min_sg_len = max_segs;
*sg_len = 0;
do {
for (i = 0; i < mem->cnt; i++) {
unsigned long len = PAGE_SIZE << mem->arr[i].order;
+ if (min_sg_len && (size / min_sg_len < len))
+ len = ALIGN(size / min_sg_len, 512);
if (len > sz)
len = sz;
if (len > max_seg_sz)
@@ -554,11 +581,12 @@
printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
"%lu.%09lu seconds (%u kB/s, %u KiB/s, "
- "%u.%02u IOPS)\n",
+ "%u.%02u IOPS, sg_len %d)\n",
mmc_hostname(test->card->host), count, sectors, count,
sectors >> 1, (sectors & 1 ? ".5" : ""),
(unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
- rate / 1000, rate / 1024, iops / 100, iops % 100);
+ rate / 1000, rate / 1024, iops / 100, iops % 100,
+ test->area.sg_len);
mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
}
@@ -661,7 +689,7 @@
* Checks that a normal transfer didn't have any errors
*/
static int mmc_test_check_result(struct mmc_test_card *test,
- struct mmc_request *mrq)
+ struct mmc_request *mrq)
{
int ret;
@@ -685,6 +713,17 @@
return ret;
}
+static int mmc_test_check_result_async(struct mmc_card *card,
+ struct mmc_async_req *areq)
+{
+ struct mmc_test_async_req *test_async =
+ container_of(areq, struct mmc_test_async_req, areq);
+
+ mmc_test_wait_busy(test_async->test);
+
+ return mmc_test_check_result(test_async->test, areq->mrq);
+}
+
/*
* Checks that a "short transfer" behaved as expected
*/
@@ -720,6 +759,85 @@
}
/*
+ * Tests nonblock transfer with certain parameters
+ */
+static void mmc_test_nonblock_reset(struct mmc_request *mrq,
+ struct mmc_command *cmd,
+ struct mmc_command *stop,
+ struct mmc_data *data)
+{
+ memset(mrq, 0, sizeof(struct mmc_request));
+ memset(cmd, 0, sizeof(struct mmc_command));
+ memset(data, 0, sizeof(struct mmc_data));
+ memset(stop, 0, sizeof(struct mmc_command));
+
+ mrq->cmd = cmd;
+ mrq->data = data;
+ mrq->stop = stop;
+}
+static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
+ struct scatterlist *sg, unsigned sg_len,
+ unsigned dev_addr, unsigned blocks,
+ unsigned blksz, int write, int count)
+{
+ struct mmc_request mrq1;
+ struct mmc_command cmd1;
+ struct mmc_command stop1;
+ struct mmc_data data1;
+
+ struct mmc_request mrq2;
+ struct mmc_command cmd2;
+ struct mmc_command stop2;
+ struct mmc_data data2;
+
+ struct mmc_test_async_req test_areq[2];
+ struct mmc_async_req *done_areq;
+ struct mmc_async_req *cur_areq = &test_areq[0].areq;
+ struct mmc_async_req *other_areq = &test_areq[1].areq;
+ int i;
+ int ret;
+
+ test_areq[0].test = test;
+ test_areq[1].test = test;
+
+ mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+ mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+
+ cur_areq->mrq = &mrq1;
+ cur_areq->err_check = mmc_test_check_result_async;
+ other_areq->mrq = &mrq2;
+ other_areq->err_check = mmc_test_check_result_async;
+
+ for (i = 0; i < count; i++) {
+ mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
+ blocks, blksz, write);
+ done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
+
+ if (ret || (!done_areq && i > 0))
+ goto err;
+
+ if (done_areq) {
+ if (done_areq->mrq == &mrq2)
+ mmc_test_nonblock_reset(&mrq2, &cmd2,
+ &stop2, &data2);
+ else
+ mmc_test_nonblock_reset(&mrq1, &cmd1,
+ &stop1, &data1);
+ }
+ done_areq = cur_areq;
+ cur_areq = other_areq;
+ other_areq = done_areq;
+ dev_addr += blocks;
+ }
+
+ done_areq = mmc_start_req(test->card->host, NULL, &ret);
+
+ return ret;
+err:
+ return ret;
+}
+
+/*
* Tests a basic transfer with certain parameters
*/
static int mmc_test_simple_transfer(struct mmc_test_card *test,
@@ -1302,7 +1420,7 @@
* Map sz bytes so that it can be transferred.
*/
static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
- int max_scatter)
+ int max_scatter, int min_sg_len)
{
struct mmc_test_area *t = &test->area;
int err;
@@ -1315,7 +1433,7 @@
&t->sg_len);
} else {
err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
- t->max_seg_sz, &t->sg_len);
+ t->max_seg_sz, &t->sg_len, min_sg_len);
}
if (err)
printk(KERN_INFO "%s: Failed to map sg list\n",
@@ -1336,14 +1454,17 @@
}
/*
- * Map and transfer bytes.
+ * Map and transfer bytes for multiple transfers.
*/
-static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
- unsigned int dev_addr, int write, int max_scatter,
- int timed)
+static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
+ unsigned int dev_addr, int write,
+ int max_scatter, int timed, int count,
+ bool nonblock, int min_sg_len)
{
struct timespec ts1, ts2;
- int ret;
+ int ret = 0;
+ int i;
+ struct mmc_test_area *t = &test->area;
/*
* In the case of a maximally scattered transfer, the maximum transfer
@@ -1361,14 +1482,21 @@
sz = max_tfr;
}
- ret = mmc_test_area_map(test, sz, max_scatter);
+ ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len);
if (ret)
return ret;
if (timed)
getnstimeofday(&ts1);
+ if (nonblock)
+ ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
+ dev_addr, t->blocks, 512, write, count);
+ else
+ for (i = 0; i < count && ret == 0; i++) {
+ ret = mmc_test_area_transfer(test, dev_addr, write);
+ dev_addr += sz >> 9;
+ }
- ret = mmc_test_area_transfer(test, dev_addr, write);
if (ret)
return ret;
@@ -1376,11 +1504,19 @@
getnstimeofday(&ts2);
if (timed)
- mmc_test_print_rate(test, sz, &ts1, &ts2);
+ mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
return 0;
}
+static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
+ unsigned int dev_addr, int write, int max_scatter,
+ int timed)
+{
+ return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
+ timed, 1, false, 0);
+}
+
/*
* Write the test area entirely.
*/
@@ -1954,6 +2090,270 @@
return mmc_test_large_seq_perf(test, 1);
}
+static int mmc_test_rw_multiple(struct mmc_test_card *test,
+ struct mmc_test_multiple_rw *tdata,
+ unsigned int reqsize, unsigned int size,
+ int min_sg_len)
+{
+ unsigned int dev_addr;
+ struct mmc_test_area *t = &test->area;
+ int ret = 0;
+
+ /* Set up test area */
+ if (size > mmc_test_capacity(test->card) / 2 * 512)
+ size = mmc_test_capacity(test->card) / 2 * 512;
+ if (reqsize > t->max_tfr)
+ reqsize = t->max_tfr;
+ dev_addr = mmc_test_capacity(test->card) / 4;
+ if ((dev_addr & 0xffff0000))
+ dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
+ else
+ dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
+ if (!dev_addr)
+ goto err;
+
+ if (reqsize > size)
+ return 0;
+
+ /* prepare test area */
+ if (mmc_can_erase(test->card) &&
+ tdata->prepare & MMC_TEST_PREP_ERASE) {
+ ret = mmc_erase(test->card, dev_addr,
+ size / 512, MMC_SECURE_ERASE_ARG);
+ if (ret)
+ ret = mmc_erase(test->card, dev_addr,
+ size / 512, MMC_ERASE_ARG);
+ if (ret)
+ goto err;
+ }
+
+ /* Run test */
+ ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
+ tdata->do_write, 0, 1, size / reqsize,
+ tdata->do_nonblock_req, min_sg_len);
+ if (ret)
+ goto err;
+
+ return ret;
+ err:
+ printk(KERN_INFO "[%s] error\n", __func__);
+ return ret;
+}
+
+static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
+ struct mmc_test_multiple_rw *rw)
+{
+ int ret = 0;
+ int i;
+ void *pre_req = test->card->host->ops->pre_req;
+ void *post_req = test->card->host->ops->post_req;
+
+ if (rw->do_nonblock_req &&
+ ((!pre_req && post_req) || (pre_req && !post_req))) {
+ printk(KERN_INFO "error: only one of pre/post is defined\n");
+ return -EINVAL;
+ }
+
+ for (i = 0 ; i < rw->len && ret == 0; i++) {
+ ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
+ struct mmc_test_multiple_rw *rw)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0 ; i < rw->len && ret == 0; i++) {
+ ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
+ rw->sg_len[i]);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Multiple blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
+{
+ unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+ 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+ struct mmc_test_multiple_rw test_data = {
+ .bs = bs,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(bs),
+ .do_write = true,
+ .do_nonblock_req = false,
+ .prepare = MMC_TEST_PREP_ERASE,
+ };
+
+ return mmc_test_rw_multiple_size(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
+{
+ unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+ 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+ struct mmc_test_multiple_rw test_data = {
+ .bs = bs,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(bs),
+ .do_write = true,
+ .do_nonblock_req = true,
+ .prepare = MMC_TEST_PREP_ERASE,
+ };
+
+ return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
+{
+ unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+ 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+ struct mmc_test_multiple_rw test_data = {
+ .bs = bs,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(bs),
+ .do_write = false,
+ .do_nonblock_req = false,
+ .prepare = MMC_TEST_PREP_NONE,
+ };
+
+ return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
+{
+ unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+ 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+ struct mmc_test_multiple_rw test_data = {
+ .bs = bs,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(bs),
+ .do_write = false,
+ .do_nonblock_req = true,
+ .prepare = MMC_TEST_PREP_NONE,
+ };
+
+ return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
+{
+ unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+ 1 << 7, 1 << 8, 1 << 9};
+ struct mmc_test_multiple_rw test_data = {
+ .sg_len = sg_len,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(sg_len),
+ .do_write = true,
+ .do_nonblock_req = false,
+ .prepare = MMC_TEST_PREP_ERASE,
+ };
+
+ return mmc_test_rw_multiple_sg_len(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
+{
+ unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+ 1 << 7, 1 << 8, 1 << 9};
+ struct mmc_test_multiple_rw test_data = {
+ .sg_len = sg_len,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(sg_len),
+ .do_write = true,
+ .do_nonblock_req = true,
+ .prepare = MMC_TEST_PREP_ERASE,
+ };
+
+ return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
+{
+ unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+ 1 << 7, 1 << 8, 1 << 9};
+ struct mmc_test_multiple_rw test_data = {
+ .sg_len = sg_len,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(sg_len),
+ .do_write = false,
+ .do_nonblock_req = false,
+ .prepare = MMC_TEST_PREP_NONE,
+ };
+
+ return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
+{
+ unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+ 1 << 7, 1 << 8, 1 << 9};
+ struct mmc_test_multiple_rw test_data = {
+ .sg_len = sg_len,
+ .size = TEST_AREA_MAX_SIZE,
+ .len = ARRAY_SIZE(sg_len),
+ .do_write = false,
+ .do_nonblock_req = true,
+ .prepare = MMC_TEST_PREP_NONE,
+ };
+
+ return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * eMMC hardware reset.
+ */
+static int mmc_test_hw_reset(struct mmc_test_card *test)
+{
+ struct mmc_card *card = test->card;
+ struct mmc_host *host = card->host;
+ int err;
+
+ err = mmc_hw_reset_check(host);
+ if (!err)
+ return RESULT_OK;
+
+ if (err == -ENOSYS)
+ return RESULT_FAIL;
+
+ if (err != -EOPNOTSUPP)
+ return err;
+
+ if (!mmc_can_reset(card))
+ return RESULT_UNSUP_CARD;
+
+ return RESULT_UNSUP_HOST;
+}
+
static const struct mmc_test_case mmc_test_cases[] = {
{
.name = "Basic write (no data verification)",
@@ -2221,6 +2621,66 @@
.cleanup = mmc_test_area_cleanup,
},
+ {
+ .name = "Write performance with blocking req 4k to 4MB",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_mult_write_blocking_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "Write performance with non-blocking req 4k to 4MB",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_mult_write_nonblock_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "Read performance with blocking req 4k to 4MB",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_mult_read_blocking_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "Read performance with non-blocking req 4k to 4MB",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_mult_read_nonblock_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "Write performance blocking req 1 to 512 sg elems",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_sglen_wr_blocking_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "Write performance non-blocking req 1 to 512 sg elems",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_sglen_wr_nonblock_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "Read performance blocking req 1 to 512 sg elems",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_sglen_r_blocking_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "Read performance non-blocking req 1 to 512 sg elems",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_profile_sglen_r_nonblock_perf,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+ {
+ .name = "eMMC hardware reset",
+ .run = mmc_test_hw_reset,
+ },
};
static DEFINE_MUTEX(mmc_test_lock);
@@ -2445,6 +2905,32 @@
.release = single_release,
};
+static int mtf_testlist_show(struct seq_file *sf, void *data)
+{
+ int i;
+
+ mutex_lock(&mmc_test_lock);
+
+ for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
+ seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
+
+ mutex_unlock(&mmc_test_lock);
+
+ return 0;
+}
+
+static int mtf_testlist_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mtf_testlist_show, inode->i_private);
+}
+
+static const struct file_operations mmc_test_fops_testlist = {
+ .open = mtf_testlist_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void mmc_test_free_file_test(struct mmc_card *card)
{
struct mmc_test_dbgfs_file *df, *dfs;
@@ -2476,7 +2962,18 @@
if (IS_ERR_OR_NULL(file)) {
dev_err(&card->dev,
- "Can't create file. Perhaps debugfs is disabled.\n");
+ "Can't create test. Perhaps debugfs is disabled.\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (card->debugfs_root)
+ file = debugfs_create_file("testlist", S_IRUGO,
+ card->debugfs_root, card, &mmc_test_fops_testlist);
+
+ if (IS_ERR_OR_NULL(file)) {
+ dev_err(&card->dev,
+ "Can't create testlist. Perhaps debugfs is disabled.\n");
ret = -ENODEV;
goto err;
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b2fb161..73f63c9 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -53,26 +53,23 @@
struct request_queue *q = mq->queue;
struct request *req;
-#ifdef CONFIG_MMC_PERF_PROFILING
- ktime_t start, diff;
- struct mmc_host *host = mq->card->host;
- unsigned long bytes_xfer;
-#endif
-
-
current->flags |= PF_MEMALLOC;
down(&mq->thread_sem);
do {
+ struct mmc_queue_req *tmp;
req = NULL; /* Must be set to NULL at each iteration */
spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE);
req = blk_fetch_request(q);
- mq->req = req;
+ mq->mqrq_cur->req = req;
spin_unlock_irq(q->queue_lock);
- if (!req) {
+ if (req || mq->mqrq_prev->req) {
+ set_current_state(TASK_RUNNING);
+ mq->issue_fn(mq, req);
+ } else {
if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
break;
@@ -80,30 +77,14 @@
up(&mq->thread_sem);
schedule();
down(&mq->thread_sem);
- continue;
}
- set_current_state(TASK_RUNNING);
-#ifdef CONFIG_MMC_PERF_PROFILING
- bytes_xfer = blk_rq_bytes(req);
- if (rq_data_dir(req) == READ) {
- start = ktime_get();
- mq->issue_fn(mq, req);
- diff = ktime_sub(ktime_get(), start);
- host->perf.rbytes_mmcq += bytes_xfer;
- host->perf.rtime_mmcq =
- ktime_add(host->perf.rtime_mmcq, diff);
- } else {
- start = ktime_get();
- mq->issue_fn(mq, req);
- diff = ktime_sub(ktime_get(), start);
- host->perf.wbytes_mmcq += bytes_xfer;
- host->perf.wtime_mmcq =
- ktime_add(host->perf.wtime_mmcq, diff);
- }
-#else
- mq->issue_fn(mq, req);
-#endif
+ /* Current request becomes previous request and vice versa. */
+ mq->mqrq_prev->brq.mrq.data = NULL;
+ mq->mqrq_prev->req = NULL;
+ tmp = mq->mqrq_prev;
+ mq->mqrq_prev = mq->mqrq_cur;
+ mq->mqrq_cur = tmp;
} while (1);
up(&mq->thread_sem);
@@ -129,10 +110,46 @@
return;
}
- if (!mq->req)
+ if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
wake_up_process(mq->thread);
}
+struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
+{
+ struct scatterlist *sg;
+
+ sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
+ if (!sg)
+ *err = -ENOMEM;
+ else {
+ *err = 0;
+ sg_init_table(sg, sg_len);
+ }
+
+ return sg;
+}
+
+static void mmc_queue_setup_discard(struct request_queue *q,
+ struct mmc_card *card)
+{
+ unsigned max_discard;
+
+ max_discard = mmc_calc_max_discard(card);
+ if (!max_discard)
+ return;
+
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+ q->limits.max_discard_sectors = max_discard;
+ if (card->erased_byte == 0)
+ q->limits.discard_zeroes_data = 1;
+ q->limits.discard_granularity = card->pref_erase << 9;
+ /* granularity must not be greater than max. discard */
+ if (card->pref_erase > max_discard)
+ q->limits.discard_granularity = 0;
+ if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+ queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+}
+
/**
* mmc_init_queue - initialise a queue structure.
* @mq: mmc queue
@@ -148,6 +165,8 @@
struct mmc_host *host = card->host;
u64 limit = BLK_BOUNCE_HIGH;
int ret;
+ struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+ struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = *mmc_dev(host)->dma_mask;
@@ -157,21 +176,16 @@
if (!mq->queue)
return -ENOMEM;
+ memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+ memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+ mq->mqrq_cur = mqrq_cur;
+ mq->mqrq_prev = mqrq_prev;
mq->queue->queuedata = mq;
- mq->req = NULL;
blk_queue_prep_rq(mq->queue, mmc_prep_request);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
- if (mmc_can_erase(card)) {
- queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
- mq->queue->limits.max_discard_sectors = UINT_MAX;
- if (card->erased_byte == 0)
- mq->queue->limits.discard_zeroes_data = 1;
- mq->queue->limits.discard_granularity = card->pref_erase << 9;
- if (mmc_can_secure_erase_trim(card))
- queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD,
- mq->queue);
- }
+ if (mmc_can_erase(card))
+ mmc_queue_setup_discard(mq->queue, card);
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_segs == 1) {
@@ -187,53 +201,64 @@
bouncesz = host->max_blk_count * 512;
if (bouncesz > 512) {
- mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
- if (!mq->bounce_buf) {
+ mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+ if (!mqrq_cur->bounce_buf) {
printk(KERN_WARNING "%s: unable to "
- "allocate bounce buffer\n",
+ "allocate bounce cur buffer\n",
mmc_card_name(card));
}
+ mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+ if (!mqrq_prev->bounce_buf) {
+ printk(KERN_WARNING "%s: unable to "
+ "allocate bounce prev buffer\n",
+ mmc_card_name(card));
+ kfree(mqrq_cur->bounce_buf);
+ mqrq_cur->bounce_buf = NULL;
+ }
}
- if (mq->bounce_buf) {
+ if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
blk_queue_max_segments(mq->queue, bouncesz / 512);
blk_queue_max_segment_size(mq->queue, bouncesz);
- mq->sg = kmalloc(sizeof(struct scatterlist),
- GFP_KERNEL);
- if (!mq->sg) {
- ret = -ENOMEM;
+ mqrq_cur->sg = mmc_alloc_sg(1, &ret);
+ if (ret)
goto cleanup_queue;
- }
- sg_init_table(mq->sg, 1);
- mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
- bouncesz / 512, GFP_KERNEL);
- if (!mq->bounce_sg) {
- ret = -ENOMEM;
+ mqrq_cur->bounce_sg =
+ mmc_alloc_sg(bouncesz / 512, &ret);
+ if (ret)
goto cleanup_queue;
- }
- sg_init_table(mq->bounce_sg, bouncesz / 512);
+
+ mqrq_prev->sg = mmc_alloc_sg(1, &ret);
+ if (ret)
+ goto cleanup_queue;
+
+ mqrq_prev->bounce_sg =
+ mmc_alloc_sg(bouncesz / 512, &ret);
+ if (ret)
+ goto cleanup_queue;
}
}
#endif
- if (!mq->bounce_buf) {
+ if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
- mq->sg = kmalloc(sizeof(struct scatterlist) *
- host->max_segs, GFP_KERNEL);
- if (!mq->sg) {
- ret = -ENOMEM;
+ mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
+ if (ret)
goto cleanup_queue;
- }
- sg_init_table(mq->sg, host->max_segs);
+
+
+ mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
+ if (ret)
+ goto cleanup_queue;
}
sema_init(&mq->thread_sem, 1);
@@ -248,16 +273,22 @@
return 0;
free_bounce_sg:
- if (mq->bounce_sg)
- kfree(mq->bounce_sg);
- mq->bounce_sg = NULL;
+ kfree(mqrq_cur->bounce_sg);
+ mqrq_cur->bounce_sg = NULL;
+ kfree(mqrq_prev->bounce_sg);
+ mqrq_prev->bounce_sg = NULL;
+
cleanup_queue:
- if (mq->sg)
- kfree(mq->sg);
- mq->sg = NULL;
- if (mq->bounce_buf)
- kfree(mq->bounce_buf);
- mq->bounce_buf = NULL;
+ kfree(mqrq_cur->sg);
+ mqrq_cur->sg = NULL;
+ kfree(mqrq_cur->bounce_buf);
+ mqrq_cur->bounce_buf = NULL;
+
+ kfree(mqrq_prev->sg);
+ mqrq_prev->sg = NULL;
+ kfree(mqrq_prev->bounce_buf);
+ mqrq_prev->bounce_buf = NULL;
+
blk_cleanup_queue(mq->queue);
return ret;
}
@@ -266,6 +297,8 @@
{
struct request_queue *q = mq->queue;
unsigned long flags;
+ struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+ struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
/* Make sure the queue isn't suspended, as that will deadlock */
mmc_queue_resume(mq);
@@ -279,16 +312,23 @@
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
- if (mq->bounce_sg)
- kfree(mq->bounce_sg);
- mq->bounce_sg = NULL;
+ kfree(mqrq_cur->bounce_sg);
+ mqrq_cur->bounce_sg = NULL;
- kfree(mq->sg);
- mq->sg = NULL;
+ kfree(mqrq_cur->sg);
+ mqrq_cur->sg = NULL;
- if (mq->bounce_buf)
- kfree(mq->bounce_buf);
- mq->bounce_buf = NULL;
+ kfree(mqrq_cur->bounce_buf);
+ mqrq_cur->bounce_buf = NULL;
+
+ kfree(mqrq_prev->bounce_sg);
+ mqrq_prev->bounce_sg = NULL;
+
+ kfree(mqrq_prev->sg);
+ mqrq_prev->sg = NULL;
+
+ kfree(mqrq_prev->bounce_buf);
+ mqrq_prev->bounce_buf = NULL;
mq->card = NULL;
}
@@ -341,27 +381,27 @@
/*
* Prepare the sg list(s) to be handed of to the host driver
*/
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
+unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
{
unsigned int sg_len;
size_t buflen;
struct scatterlist *sg;
int i;
- if (!mq->bounce_buf)
- return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
+ if (!mqrq->bounce_buf)
+ return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
- BUG_ON(!mq->bounce_sg);
+ BUG_ON(!mqrq->bounce_sg);
- sg_len = blk_rq_map_sg(mq->queue, mq->req, mq->bounce_sg);
+ sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
- mq->bounce_sg_len = sg_len;
+ mqrq->bounce_sg_len = sg_len;
buflen = 0;
- for_each_sg(mq->bounce_sg, sg, sg_len, i)
+ for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
buflen += sg->length;
- sg_init_one(mq->sg, mq->bounce_buf, buflen);
+ sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
return 1;
}
@@ -370,31 +410,30 @@
* If writing, bounce the data to the buffer before the request
* is sent to the host driver
*/
-void mmc_queue_bounce_pre(struct mmc_queue *mq)
+void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
{
- if (!mq->bounce_buf)
+ if (!mqrq->bounce_buf)
return;
- if (rq_data_dir(mq->req) != WRITE)
+ if (rq_data_dir(mqrq->req) != WRITE)
return;
- sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
- mq->bounce_buf, mq->sg[0].length);
+ sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+ mqrq->bounce_buf, mqrq->sg[0].length);
}
/*
* If reading, bounce the data from the buffer after the request
* has been handled by the host driver
*/
-void mmc_queue_bounce_post(struct mmc_queue *mq)
+void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
{
- if (!mq->bounce_buf)
+ if (!mqrq->bounce_buf)
return;
- if (rq_data_dir(mq->req) != READ)
+ if (rq_data_dir(mqrq->req) != READ)
return;
- sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
- mq->bounce_buf, mq->sg[0].length);
+ sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+ mqrq->bounce_buf, mqrq->sg[0].length);
}
-
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 6223ef8..d2a1eb4 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -4,19 +4,35 @@
struct request;
struct task_struct;
+struct mmc_blk_request {
+ struct mmc_request mrq;
+ struct mmc_command sbc;
+ struct mmc_command cmd;
+ struct mmc_command stop;
+ struct mmc_data data;
+};
+
+struct mmc_queue_req {
+ struct request *req;
+ struct mmc_blk_request brq;
+ struct scatterlist *sg;
+ char *bounce_buf;
+ struct scatterlist *bounce_sg;
+ unsigned int bounce_sg_len;
+ struct mmc_async_req mmc_active;
+};
+
struct mmc_queue {
struct mmc_card *card;
struct task_struct *thread;
struct semaphore thread_sem;
unsigned int flags;
- struct request *req;
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
struct request_queue *queue;
- struct scatterlist *sg;
- char *bounce_buf;
- struct scatterlist *bounce_sg;
- unsigned int bounce_sg_len;
+ struct mmc_queue_req mqrq[2];
+ struct mmc_queue_req *mqrq_cur;
+ struct mmc_queue_req *mqrq_prev;
};
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -25,8 +41,9 @@
extern void mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);
-extern unsigned int mmc_queue_map_sg(struct mmc_queue *);
-extern void mmc_queue_bounce_pre(struct mmc_queue *);
-extern void mmc_queue_bounce_post(struct mmc_queue *);
+extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
+ struct mmc_queue_req *);
+extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
+extern void mmc_queue_bounce_post(struct mmc_queue_req *);
#endif
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 51434b6..1eb9d5f 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -106,12 +106,12 @@
}
if (err && cmd->retries && !mmc_card_removed(host->card)) {
- pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
- mmc_hostname(host), cmd->opcode, err);
-
- cmd->retries--;
- cmd->error = 0;
- host->ops->request(host, mrq);
+ /*
+ * Request starter must handle retries - see
+ * mmc_wait_for_req_done().
+ */
+ if (mrq->done)
+ mrq->done(mrq);
} else {
led_trigger_event(host->led, LED_OFF);
@@ -220,9 +220,123 @@
static void mmc_wait_done(struct mmc_request *mrq)
{
- complete(mrq->done_data);
+ complete(&mrq->completion);
}
+static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ init_completion(&mrq->completion);
+ mrq->done = mmc_wait_done;
+ mmc_start_request(host, mrq);
+}
+
+static void mmc_wait_for_req_done(struct mmc_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_command *cmd;
+
+ while (1) {
+ wait_for_completion(&mrq->completion);
+
+ cmd = mrq->cmd;
+ if (!cmd->error || !cmd->retries)
+ break;
+
+ pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+ mmc_hostname(host), cmd->opcode, cmd->error);
+ cmd->retries--;
+ cmd->error = 0;
+ host->ops->request(host, mrq);
+ }
+}
+
+/**
+ * mmc_pre_req - Prepare for a new request
+ * @host: MMC host to prepare command
+ * @mrq: MMC request to prepare for
+ * @is_first_req: true if there is no previous started request
+ * that may run in parellel to this call, otherwise false
+ *
+ * mmc_pre_req() is called in prior to mmc_start_req() to let
+ * host prepare for the new request. Preparation of a request may be
+ * performed while another request is running on the host.
+ */
+static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+ bool is_first_req)
+{
+ if (host->ops->pre_req)
+ host->ops->pre_req(host, mrq, is_first_req);
+}
+
+/**
+ * mmc_post_req - Post process a completed request
+ * @host: MMC host to post process command
+ * @mrq: MMC request to post process for
+ * @err: Error, if non zero, clean up any resources made in pre_req
+ *
+ * Let the host post process a completed request. Post processing of
+ * a request may be performed while another reuqest is running.
+ */
+static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+ int err)
+{
+ if (host->ops->post_req)
+ host->ops->post_req(host, mrq, err);
+}
+
+/**
+ * mmc_start_req - start a non-blocking request
+ * @host: MMC host to start command
+ * @areq: async request to start
+ * @error: out parameter returns 0 for success, otherwise non zero
+ *
+ * Start a new MMC custom command request for a host.
+ * If there is on ongoing async request wait for completion
+ * of that request and start the new one and return.
+ * Does not wait for the new request to complete.
+ *
+ * Returns the completed request, NULL in case of none completed.
+ * Wait for the an ongoing request (previoulsy started) to complete and
+ * return the completed request. If there is no ongoing request, NULL
+ * is returned without waiting. NULL is not an error condition.
+ */
+struct mmc_async_req *mmc_start_req(struct mmc_host *host,
+ struct mmc_async_req *areq, int *error)
+{
+ int err = 0;
+ struct mmc_async_req *data = host->areq;
+
+ /* Prepare a new request */
+ if (areq)
+ mmc_pre_req(host, areq->mrq, !host->areq);
+
+ if (host->areq) {
+ mmc_wait_for_req_done(host, host->areq->mrq);
+ err = host->areq->err_check(host->card, host->areq);
+ if (err) {
+ mmc_post_req(host, host->areq->mrq, 0);
+ if (areq)
+ mmc_post_req(host, areq->mrq, -EINVAL);
+
+ host->areq = NULL;
+ goto out;
+ }
+ }
+
+ if (areq)
+ __mmc_start_req(host, areq->mrq);
+
+ if (host->areq)
+ mmc_post_req(host, host->areq->mrq, 0);
+
+ host->areq = areq;
+ out:
+ if (error)
+ *error = err;
+ return data;
+}
+EXPORT_SYMBOL(mmc_start_req);
+
/**
* mmc_wait_for_req - start a request and wait for completion
* @host: MMC host to start command
@@ -234,21 +348,67 @@
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
- DECLARE_COMPLETION_ONSTACK(complete);
+ __mmc_start_req(host, mrq);
+ mmc_wait_for_req_done(host, mrq);
+}
+EXPORT_SYMBOL(mmc_wait_for_req);
- mrq->done_data = &complete;
- mrq->done = mmc_wait_done;
- if (mmc_card_removed(host->card)) {
- mrq->cmd->error = -ENOMEDIUM;
- return;
+/**
+ * mmc_interrupt_hpi - Issue for High priority Interrupt
+ * @card: the MMC card associated with the HPI transfer
+ *
+ * Issued High Priority Interrupt, and check for card status
+ * util out-of prg-state.
+ */
+int mmc_interrupt_hpi(struct mmc_card *card)
+{
+ int err;
+ u32 status;
+
+ BUG_ON(!card);
+
+ if (!card->ext_csd.hpi_en) {
+ pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
+ return 1;
}
- mmc_start_request(host, mrq);
+ mmc_claim_host(card->host);
+ err = mmc_send_status(card, &status);
+ if (err) {
+ pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
+ goto out;
+ }
- wait_for_completion_io(&complete);
+ /*
+ * If the card status is in PRG-state, we can send the HPI command.
+ */
+ if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
+ do {
+ /*
+ * We don't know when the HPI command will finish
+ * processing, so we need to resend HPI until out
+ * of prg-state, and keep checking the card status
+ * with SEND_STATUS. If a timeout error occurs when
+ * sending the HPI command, we are already out of
+ * prg-state.
+ */
+ err = mmc_send_hpi_cmd(card, &status);
+ if (err)
+ pr_debug("%s: abort HPI (%d error)\n",
+ mmc_hostname(card->host), err);
+
+ err = mmc_send_status(card, &status);
+ if (err)
+ break;
+ } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+ } else
+ pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+
+out:
+ mmc_release_host(card->host);
+ return err;
}
-
-EXPORT_SYMBOL(mmc_wait_for_req);
+EXPORT_SYMBOL(mmc_interrupt_hpi);
/**
* mmc_wait_for_cmd - start a command and wait for completion
@@ -262,7 +422,7 @@
*/
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
WARN_ON(!host->claimed);
@@ -1035,6 +1195,46 @@
mmc_host_clk_release(host);
}
+static void mmc_poweroff_notify(struct mmc_host *host)
+{
+ struct mmc_card *card;
+ unsigned int timeout;
+ unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
+ int err = 0;
+
+ card = host->card;
+
+ /*
+ * Send power notify command only if card
+ * is mmc and notify state is powered ON
+ */
+ if (card && mmc_card_mmc(card) &&
+ (card->poweroff_notify_state == MMC_POWERED_ON)) {
+
+ if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
+ notify_type = EXT_CSD_POWER_OFF_SHORT;
+ timeout = card->ext_csd.generic_cmd6_time;
+ card->poweroff_notify_state = MMC_POWEROFF_SHORT;
+ } else {
+ notify_type = EXT_CSD_POWER_OFF_LONG;
+ timeout = card->ext_csd.power_off_longtime;
+ card->poweroff_notify_state = MMC_POWEROFF_LONG;
+ }
+
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_POWER_OFF_NOTIFICATION,
+ notify_type, timeout);
+
+ if (err && err != -EBADMSG)
+ pr_err("Device failed to respond within %d poweroff "
+ "time. Forcefully powering down the device\n",
+ timeout);
+
+ /* Set the card state to no notification after the poweroff */
+ card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
+ }
+}
+
/*
* Apply power to the MMC stack. This is a two-stage process.
* First, we enable power to the card without the clock running.
@@ -1091,13 +1291,15 @@
mmc_host_clk_release(host);
}
-static void mmc_power_off(struct mmc_host *host)
+void mmc_power_off(struct mmc_host *host)
{
mmc_host_clk_hold(host);
host->ios.clock = 0;
host->ios.vdd = 0;
+ mmc_poweroff_notify(host);
+
/*
* Reset ocr mask to be the highest possible voltage supported for
* this mmc host. This value will be used at next power up.
@@ -1452,7 +1654,7 @@
if (err) {
printk(KERN_ERR "mmc_erase: group start error %d, "
"status %#x\n", err, cmd.resp[0]);
- err = -EINVAL;
+ err = -EIO;
goto out;
}
@@ -1467,7 +1669,7 @@
if (err) {
printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n",
err, cmd.resp[0]);
- err = -EINVAL;
+ err = -EIO;
goto out;
}
@@ -1501,7 +1703,7 @@
goto out;
}
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- R1_CURRENT_STATE(cmd.resp[0]) == 7);
+ R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
out:
return err;
}
@@ -1586,10 +1788,32 @@
{
if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
return 1;
+ if (mmc_can_discard(card))
+ return 1;
return 0;
}
EXPORT_SYMBOL(mmc_can_trim);
+int mmc_can_discard(struct mmc_card *card)
+{
+ /*
+ * As there's no way to detect the discard support bit at v4.5
+ * use the s/w feature support filed.
+ */
+ if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE)
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL(mmc_can_discard);
+
+int mmc_can_sanitize(struct mmc_card *card)
+{
+ if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL(mmc_can_sanitize);
+
int mmc_can_secure_erase_trim(struct mmc_card *card)
{
if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
@@ -1609,6 +1833,82 @@
}
EXPORT_SYMBOL(mmc_erase_group_aligned);
+static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
+ unsigned int arg)
+{
+ struct mmc_host *host = card->host;
+ unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
+ unsigned int last_timeout = 0;
+
+ if (card->erase_shift)
+ max_qty = UINT_MAX >> card->erase_shift;
+ else if (mmc_card_sd(card))
+ max_qty = UINT_MAX;
+ else
+ max_qty = UINT_MAX / card->erase_size;
+
+ /* Find the largest qty with an OK timeout */
+ do {
+ y = 0;
+ for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
+ timeout = mmc_erase_timeout(card, arg, qty + x);
+ if (timeout > host->max_discard_to)
+ break;
+ if (timeout < last_timeout)
+ break;
+ last_timeout = timeout;
+ y = x;
+ }
+ qty += y;
+ } while (y);
+
+ if (!qty)
+ return 0;
+
+ if (qty == 1)
+ return 1;
+
+ /* Convert qty to sectors */
+ if (card->erase_shift)
+ max_discard = --qty << card->erase_shift;
+ else if (mmc_card_sd(card))
+ max_discard = qty;
+ else
+ max_discard = --qty * card->erase_size;
+
+ return max_discard;
+}
+
+unsigned int mmc_calc_max_discard(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ unsigned int max_discard, max_trim;
+
+ if (!host->max_discard_to)
+ return UINT_MAX;
+
+ /*
+ * Without erase_group_def set, MMC erase timeout depends on clock
+ * frequence which can change. In that case, the best choice is
+ * just the preferred erase size.
+ */
+ if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
+ return card->pref_erase;
+
+ max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
+ if (mmc_can_trim(card)) {
+ max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
+ if (max_trim < max_discard)
+ max_discard = max_trim;
+ } else if (max_discard < card->erase_size) {
+ max_discard = 0;
+ }
+ pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
+ mmc_hostname(host), max_discard, host->max_discard_to);
+ return max_discard;
+}
+EXPORT_SYMBOL(mmc_calc_max_discard);
+
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
struct mmc_command cmd = {0};
@@ -1623,6 +1923,94 @@
}
EXPORT_SYMBOL(mmc_set_blocklen);
+static void mmc_hw_reset_for_init(struct mmc_host *host)
+{
+ if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+ return;
+ mmc_host_clk_hold(host);
+ host->ops->hw_reset(host);
+ mmc_host_clk_release(host);
+}
+
+int mmc_can_reset(struct mmc_card *card)
+{
+ u8 rst_n_function;
+
+ if (!mmc_card_mmc(card))
+ return 0;
+ rst_n_function = card->ext_csd.rst_n_function;
+ if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
+ return 0;
+ return 1;
+}
+EXPORT_SYMBOL(mmc_can_reset);
+
+static int mmc_do_hw_reset(struct mmc_host *host, int check)
+{
+ struct mmc_card *card = host->card;
+
+ if (!host->bus_ops->power_restore)
+ return -EOPNOTSUPP;
+
+ if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+ return -EOPNOTSUPP;
+
+ if (!card)
+ return -EINVAL;
+
+ if (!mmc_can_reset(card))
+ return -EOPNOTSUPP;
+
+ mmc_host_clk_hold(host);
+ mmc_set_clock(host, host->f_init);
+
+ host->ops->hw_reset(host);
+
+ /* If the reset has happened, then a status command will fail */
+ if (check) {
+ struct mmc_command cmd = {0};
+ int err;
+
+ cmd.opcode = MMC_SEND_STATUS;
+ if (!mmc_host_is_spi(card->host))
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (!err) {
+ mmc_host_clk_release(host);
+ return -ENOSYS;
+ }
+ }
+
+ host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
+ if (mmc_host_is_spi(host)) {
+ host->ios.chip_select = MMC_CS_HIGH;
+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+ } else {
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ }
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+ mmc_set_ios(host);
+
+ mmc_host_clk_release(host);
+
+ return host->bus_ops->power_restore(host);
+}
+
+int mmc_hw_reset(struct mmc_host *host)
+{
+ return mmc_do_hw_reset(host, 0);
+}
+EXPORT_SYMBOL(mmc_hw_reset);
+
+int mmc_hw_reset_check(struct mmc_host *host)
+{
+ return mmc_do_hw_reset(host, 1);
+}
+EXPORT_SYMBOL(mmc_hw_reset_check);
+
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
@@ -1634,6 +2022,12 @@
mmc_power_up(host);
/*
+ * Some eMMCs (with VCCQ always on) may not be reset after power up, so
+ * do a hardware reset if possible.
+ */
+ mmc_hw_reset_for_init(host);
+
+ /*
* sdio_reset sends CMD52 to reset card. Since we do not know
* if the card is being re-initialized, just send it. CMD52
* should be ignored by SD/eMMC cards.
@@ -1870,7 +2264,7 @@
mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+ if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
err = host->bus_ops->sleep(host);
mmc_bus_put(host);
@@ -1889,6 +2283,65 @@
}
EXPORT_SYMBOL(mmc_card_can_sleep);
+/*
+ * Flush the cache to the non-volatile storage.
+ */
+int mmc_flush_cache(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ int err = 0;
+
+ if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
+ return err;
+
+ if (mmc_card_mmc(card) &&
+ (card->ext_csd.cache_size > 0) &&
+ (card->ext_csd.cache_ctrl & 1)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_FLUSH_CACHE, 1, 0);
+ if (err)
+ pr_err("%s: cache flush error %d\n",
+ mmc_hostname(card->host), err);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(mmc_flush_cache);
+
+/*
+ * Turn the cache ON/OFF.
+ * Turning the cache OFF shall trigger flushing of the data
+ * to the non-volatile storage.
+ */
+int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
+{
+ struct mmc_card *card = host->card;
+ int err = 0;
+
+ if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
+ mmc_card_is_removable(host))
+ return err;
+
+ if (card && mmc_card_mmc(card) &&
+ (card->ext_csd.cache_size > 0)) {
+ enable = !!enable;
+
+ if (card->ext_csd.cache_ctrl ^ enable)
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_CACHE_CTRL, enable, 0);
+ if (err)
+ pr_err("%s: cache %s error %d\n",
+ mmc_hostname(card->host),
+ enable ? "on" : "off",
+ err);
+ else
+ card->ext_csd.cache_ctrl = enable;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(mmc_cache_ctrl);
+
#ifdef CONFIG_PM
/**
@@ -1907,6 +2360,9 @@
if (cancel_delayed_work(&host->detect))
wake_unlock(&host->detect_wake_lock);
mmc_flush_scheduled_work();
+ err = mmc_cache_ctrl(host, 0);
+ if (err)
+ goto out;
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
@@ -1928,8 +2384,15 @@
err = -EBUSY;
if (!err) {
- if (host->bus_ops->suspend)
+ if (host->bus_ops->suspend) {
+ /*
+ * For eMMC 4.5 device send notify command
+ * before sleep, because in sleep state eMMC 4.5
+ * devices respond to only RESET and AWAKE cmd
+ */
+ mmc_poweroff_notify(host);
err = host->bus_ops->suspend(host);
+ }
if (!(host->card && mmc_card_sdio(host->card)))
mmc_do_release_host(host);
@@ -1954,6 +2417,7 @@
if (!err && !mmc_card_keep_power(host))
mmc_power_off(host);
+out:
return err;
}
@@ -2029,6 +2493,7 @@
break;
}
host->rescan_disable = 1;
+ host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
spin_unlock_irqrestore(&host->lock, flags);
if (cancel_delayed_work_sync(&host->detect))
wake_unlock(&host->detect_wake_lock);
@@ -2056,6 +2521,7 @@
break;
}
host->rescan_disable = 0;
+ host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
spin_unlock_irqrestore(&host->lock, flags);
mmc_detect_change(host, 0);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 79d6e97..0c70d4a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -259,7 +259,7 @@
}
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
- if (card->ext_csd.rev > 5) {
+ if (card->ext_csd.rev > 6) {
printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
mmc_hostname(card->host), card->ext_csd.rev);
err = -EINVAL;
@@ -359,6 +359,7 @@
* card has the Enhanced area enabled. If so, export enhanced
* area offset and size to user by adding sysfs interface.
*/
+ card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
(ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
u8 hc_erase_grp_sz =
@@ -402,14 +403,48 @@
ext_csd[EXT_CSD_TRIM_MULT];
}
- if (card->ext_csd.rev >= 5)
- card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+ if (card->ext_csd.rev >= 5) {
+ /* check whether the eMMC card supports HPI */
+ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+ card->ext_csd.hpi = 1;
+ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
+ card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
+ else
+ card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
+ /*
+ * Indicate the maximum timeout to close
+ * a command interrupted by HPI
+ */
+ card->ext_csd.out_of_int_time =
+ ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
+ }
+ card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+ card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+ }
+
+ card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
card->erased_byte = 0xFF;
else
card->erased_byte = 0x0;
+ /* eMMC v4.5 or later */
+ if (card->ext_csd.rev >= 6) {
+ card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
+
+ card->ext_csd.generic_cmd6_time = 10 *
+ ext_csd[EXT_CSD_GENERIC_CMD6_TIME];
+ card->ext_csd.power_off_longtime = 10 *
+ ext_csd[EXT_CSD_POWER_OFF_LONG_TIME];
+
+ card->ext_csd.cache_size =
+ ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
+ ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
+ ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
+ ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+ }
+
out:
return err;
}
@@ -530,6 +565,86 @@
};
/*
+ * Select the PowerClass for the current bus width
+ * If power class is defined for 4/8 bit bus in the
+ * extended CSD register, select it by executing the
+ * mmc_switch command.
+ */
+static int mmc_select_powerclass(struct mmc_card *card,
+ unsigned int bus_width, u8 *ext_csd)
+{
+ int err = 0;
+ unsigned int pwrclass_val;
+ unsigned int index = 0;
+ struct mmc_host *host;
+
+ BUG_ON(!card);
+
+ host = card->host;
+ BUG_ON(!host);
+
+ if (ext_csd == NULL)
+ return 0;
+
+ /* Power class selection is supported for versions >= 4.0 */
+ if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+ return 0;
+
+ /* Power class values are defined only for 4/8 bit bus */
+ if (bus_width == EXT_CSD_BUS_WIDTH_1)
+ return 0;
+
+ switch (1 << host->ios.vdd) {
+ case MMC_VDD_165_195:
+ if (host->ios.clock <= 26000000)
+ index = EXT_CSD_PWR_CL_26_195;
+ else if (host->ios.clock <= 52000000)
+ index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+ EXT_CSD_PWR_CL_52_195 :
+ EXT_CSD_PWR_CL_DDR_52_195;
+ else if (host->ios.clock <= 200000000)
+ index = EXT_CSD_PWR_CL_200_195;
+ break;
+ case MMC_VDD_32_33:
+ case MMC_VDD_33_34:
+ case MMC_VDD_34_35:
+ case MMC_VDD_35_36:
+ if (host->ios.clock <= 26000000)
+ index = EXT_CSD_PWR_CL_26_360;
+ else if (host->ios.clock <= 52000000)
+ index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+ EXT_CSD_PWR_CL_52_360 :
+ EXT_CSD_PWR_CL_DDR_52_360;
+ else if (host->ios.clock <= 200000000)
+ index = EXT_CSD_PWR_CL_200_360;
+ break;
+ default:
+ pr_warning("%s: Voltage range not supported "
+ "for power class.\n", mmc_hostname(host));
+ return -EINVAL;
+ }
+
+ pwrclass_val = ext_csd[index];
+
+ if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
+ pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
+ EXT_CSD_PWR_CL_8BIT_SHIFT;
+ else
+ pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
+ EXT_CSD_PWR_CL_4BIT_SHIFT;
+
+ /* If the power class is different from the default value */
+ if (pwrclass_val > 0) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_POWER_CLASS,
+ pwrclass_val,
+ card->ext_csd.generic_cmd6_time);
+ }
+
+ return err;
+}
+
+/*
* Handle the detection and initialisation of a card.
*
* In the case of a resume, "oldcard" will contain the card
@@ -671,7 +786,8 @@
*/
if (card->ext_csd.enhanced_area_en) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_ERASE_GROUP_DEF, 1, 0);
+ EXT_CSD_ERASE_GROUP_DEF, 1,
+ card->ext_csd.generic_cmd6_time);
if (err && err != -EBADMSG)
goto free_card;
@@ -709,12 +825,34 @@
}
/*
+ * If the host supports the power_off_notify capability then
+ * set the notification byte in the ext_csd register of device
+ */
+ if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
+ (card->ext_csd.rev >= 6)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_POWER_OFF_NOTIFICATION,
+ EXT_CSD_POWER_ON,
+ card->ext_csd.generic_cmd6_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+
+ /*
+ * The err can be -EBADMSG or 0,
+ * so check for success and update the flag
+ */
+ if (!err)
+ card->poweroff_notify_state = MMC_POWERED_ON;
+ }
+
+ /*
* Activate high speed (if supported)
*/
if ((card->ext_csd.hs_max_dtr != 0) &&
(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HS_TIMING, 1, 0);
+ EXT_CSD_HS_TIMING, 1,
+ card->ext_csd.generic_cmd6_time);
if (err && err != -EBADMSG)
goto free_card;
@@ -729,6 +867,22 @@
}
/*
+ * Enable HPI feature (if supported)
+ */
+ if (card->ext_csd.hpi) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HPI_MGMT, 1, 0);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warning("%s: Enabling HPI failed\n",
+ mmc_hostname(card->host));
+ err = 0;
+ } else
+ card->ext_csd.hpi_en = 1;
+ }
+
+ /*
* Compute bus speed.
*/
max_dtr = (unsigned int)-1;
@@ -783,10 +937,18 @@
bus_width = bus_widths[idx];
if (bus_width == MMC_BUS_WIDTH_1)
ddr = 0; /* no DDR for 1-bit width */
+ err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
+ ext_csd);
+ if (err)
+ pr_err("%s: power class selection to "
+ "bus width %d failed\n",
+ mmc_hostname(card->host),
+ 1 << bus_width);
+
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx][0],
- 0);
+ card->ext_csd.generic_cmd6_time);
if (!err) {
mmc_set_bus_width(card->host, bus_width);
@@ -806,10 +968,18 @@
}
if (!err && ddr) {
+ err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
+ ext_csd);
+ if (err)
+ pr_err("%s: power class selection to "
+ "bus width %d ddr %d failed\n",
+ mmc_hostname(card->host),
+ 1 << bus_width, ddr);
+
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx][1],
- 0);
+ card->ext_csd.generic_cmd6_time);
}
if (err) {
printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
@@ -843,6 +1013,23 @@
}
}
+ /*
+ * If cache size is higher than 0, this indicates
+ * the existence of cache and it can be turned on.
+ */
+ if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
+ card->ext_csd.cache_size > 0) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_CACHE_CTRL, 1, 0);
+ if (err && err != -EBADMSG)
+ goto free_card;
+
+ /*
+ * Only if no error, cache is turned on successfully.
+ */
+ card->ext_csd.cache_ctrl = err ? 0 : 1;
+ }
+
if (!oldcard)
host->card = card;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 2e39d2c..2438176 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -233,7 +233,7 @@
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
u32 opcode, void *buf, unsigned len)
{
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
@@ -408,7 +408,7 @@
break;
if (mmc_host_is_spi(card->host))
break;
- } while (R1_CURRENT_STATE(status) == 7);
+ } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
if (mmc_host_is_spi(card->host)) {
if (status & R1_SPI_ILLEGAL_COMMAND)
@@ -455,7 +455,7 @@
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
{
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
@@ -551,3 +551,34 @@
err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
return err;
}
+
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
+{
+ struct mmc_command cmd = {0};
+ unsigned int opcode;
+ unsigned int flags;
+ int err;
+
+ opcode = card->ext_csd.hpi_cmd;
+ if (opcode == MMC_STOP_TRANSMISSION)
+ flags = MMC_RSP_R1 | MMC_CMD_AC;
+ else if (opcode == MMC_SEND_STATUS)
+ flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ cmd.opcode = opcode;
+ cmd.arg = card->rca << 16 | 1;
+ cmd.flags = flags;
+ cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (err) {
+ pr_warn("%s: error %d interrupting operation. "
+ "HPI command response %#x\n", mmc_hostname(card->host),
+ err, cmd.resp[0]);
+ return err;
+ }
+ if (status)
+ *status = cmd.resp[0];
+
+ return 0;
+}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 9276946..3dd8941 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -26,6 +26,7 @@
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_card_sleepawake(struct mmc_host *host, int sleep);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
#endif
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed1..46a7854 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -67,7 +67,7 @@
int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
int i, err;
@@ -244,7 +244,7 @@
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
{
int err;
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
@@ -303,7 +303,7 @@
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp)
{
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
@@ -348,7 +348,7 @@
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
int err;
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index f087d87..4addbe9 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -121,7 +121,7 @@
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
- struct mmc_request mrq = {0};
+ struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7c1e16a..92946b8 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -27,6 +27,7 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <linux/bio.h>
#include <linux/dma-mapping.h>
#include <linux/crc7.h>
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index d513d47..99b449d 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -37,6 +37,7 @@
#include <linux/mmc/sdio.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
+#include <linux/module.h>
#include <mach/mxs.h>
#include <mach/common.h>
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index ba40d6d..6be0a24 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include <linux/mmc/host.h>
#include "sdhci-of.h"
#include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 68ddb75..aaea044 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -20,6 +20,7 @@
*/
#include <linux/delay.h>
+#include <linux/module.h>
#include <linux/mmc/host.h>
#include "sdhci-of.h"
#include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 936bbca..67c8709 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/highmem.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 60a4c97..a152b5c 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/highmem.h>
+#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 343c97e..bb1ae46 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -20,6 +20,7 @@
#include <linux/gpio.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/module.h>
#include <mach/gpio.h>
#include <mach/sdhci.h>
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aad27c8..9cf813e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/highmem.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
@@ -2558,6 +2559,15 @@
if (caps[1] & SDHCI_DRIVER_TYPE_D)
mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
+ /*
+ * If Power Off Notify capability is enabled by the host,
+ * set notify to short power off notify timeout value.
+ */
+ if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
+ mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
+ else
+ mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
+
/* Initial value for re-tuning timer count */
host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
SDHCI_RETUNING_TIMER_COUNT_SHIFT;
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index 496b7ef..7009f17 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -26,6 +26,7 @@
*/
#include <linux/delay.h>
#include <linux/highmem.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/scatterlist.h>
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 14f8edb..51b68cc 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
+#include <linux/module.h>
#define DRIVER_NAME "sh_mmcif"
#define DRIVER_VERSION "2010-04-28"
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index ce500f0..f5ce77b 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mobile_sdhi.h>
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 457c26e..90c6b1b 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -16,6 +16,7 @@
#include <linux/mmc/host.h>
#include <linux/highmem.h>
#include <linux/scatterlist.h>
+#include <linux/module.h>
#include <asm/io.h>
#define DRIVER_NAME "tifm_sd"
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 4dfe2c0..faf3594 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -9,6 +9,7 @@
*/
#include <linux/pci.h>
+#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/delay.h>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 93de829..709583a 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -29,6 +29,7 @@
#define BMS_CONTROL 0x224
#define BMS_OUTPUT0 0x230
#define BMS_OUTPUT1 0x231
+#define BMS_TOLERANCES 0x232
#define BMS_TEST1 0x237
#define ADC_ARB_SECP_CNTRL 0x190
@@ -102,7 +103,7 @@
unsigned int charging_began;
unsigned int start_percent;
unsigned int end_percent;
-
+ enum battery_type batt_type;
uint16_t ocv_reading_at_100;
int cc_reading_at_100;
int max_voltage_uv;
@@ -1268,6 +1269,10 @@
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
+#define IBAT_TOL_MASK 0x0F
+#define OCV_TOL_MASK 0xF0
+#define IBAT_TOL_DEFAULT 0x03
+#define IBAT_TOL_NOCHG 0x0F
void pm8921_bms_charging_began(void)
{
int batt_temp, rc;
@@ -1291,7 +1296,8 @@
bms_start_percent = the_chip->start_percent;
bms_start_ocv_uv = raw.last_good_ocv_uv;
calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
-
+ pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+ IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
pr_debug("start_percent = %u%%\n", the_chip->start_percent);
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -1373,6 +1379,8 @@
last_chargecycles);
the_chip->start_percent = -EINVAL;
the_chip->end_percent = -EINVAL;
+ pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+ IBAT_TOL_MASK, IBAT_TOL_NOCHG);
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
@@ -1514,6 +1522,9 @@
BMS_CONTROL, rc);
}
+ /* The charger will call start charge later if usb is present */
+ pm_bms_masked_write(chip, BMS_TOLERANCES,
+ IBAT_TOL_MASK, IBAT_TOL_NOCHG);
return 0;
}
@@ -1554,38 +1565,60 @@
}
pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
result.measurement);
- return result.physical;
+ return result.adc_code;
}
-#define PALLADIUM_ID_MIN 2500
-#define PALLADIUM_ID_MAX 4000
+#define PALLADIUM_ID_MIN 0x7F40
+#define PALLADIUM_ID_MAX 0x7F5A
+#define DESAY_5200_ID_MIN 0x7F7F
+#define DESAY_5200_ID_MAX 0x802F
static int set_battery_data(struct pm8921_bms_chip *chip)
{
int64_t battery_id;
- battery_id = read_battery_id(chip);
+ if (chip->batt_type == BATT_DESAY)
+ goto desay;
+ else if (chip->batt_type == BATT_PALLADIUM)
+ goto palladium;
+ battery_id = read_battery_id(chip);
if (battery_id < 0) {
pr_err("cannot read battery id err = %lld\n", battery_id);
return battery_id;
}
if (is_between(PALLADIUM_ID_MIN, PALLADIUM_ID_MAX, battery_id)) {
- chip->fcc = palladium_1500_data.fcc;
- chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
- chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
- chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
- chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
- return 0;
+ goto palladium;
+ } else if (is_between(DESAY_5200_ID_MIN, DESAY_5200_ID_MAX,
+ battery_id)) {
+ goto desay;
} else {
- pr_warn("invalid battery id, palladium 1500 assumed\n");
+ goto unknown;
+ }
+
+palladium:
chip->fcc = palladium_1500_data.fcc;
chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
return 0;
- }
+desay:
+ chip->fcc = desay_5200_data.fcc;
+ chip->fcc_temp_lut = desay_5200_data.fcc_temp_lut;
+ chip->fcc_sf_lut = desay_5200_data.fcc_sf_lut;
+ chip->pc_temp_ocv_lut = desay_5200_data.pc_temp_ocv_lut;
+ chip->pc_sf_lut = desay_5200_data.pc_sf_lut;
+ return 0;
+unknown:
+ pr_warn("invalid battery id, palladium 1500 assumed batt_id %llx\n",
+ battery_id);
+ chip->fcc = palladium_1500_data.fcc;
+ chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
+ chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
+ chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
+ chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
+ return 0;
}
enum {
@@ -1856,6 +1889,7 @@
chip->v_failure = pdata->v_failure;
chip->calib_delay_ms = pdata->calib_delay_ms;
chip->max_voltage_uv = pdata->max_voltage_uv;
+ chip->batt_type = pdata->battery_type;
chip->start_percent = -EINVAL;
chip->end_percent = -EINVAL;
rc = set_battery_data(chip);
diff --git a/drivers/regulator/pm8xxx-regulator.c b/drivers/regulator/pm8xxx-regulator.c
index 94b028d..fa17449 100644
--- a/drivers/regulator/pm8xxx-regulator.c
+++ b/drivers/regulator/pm8xxx-regulator.c
@@ -401,6 +401,19 @@
#define NCP_SET_POINTS ((NCP_UV_MAX - NCP_UV_MIN) \
/ NCP_UV_STEP + 1)
+/* Boost masks and values */
+#define BOOST_ENABLE_MASK 0x80
+#define BOOST_DISABLE 0x00
+#define BOOST_ENABLE 0x80
+#define BOOST_VPROG_MASK 0x1F
+
+#define BOOST_UV_MIN 4000000
+#define BOOST_UV_MAX 5550000
+#define BOOST_UV_STEP 50000
+
+#define BOOST_SET_POINTS ((BOOST_UV_MAX - BOOST_UV_MIN) \
+ / BOOST_UV_STEP + 1)
+
#define vreg_err(vreg, fmt, ...) \
pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
@@ -1424,6 +1437,64 @@
return rc;
}
+static int pm8xxx_boost_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ u8 vprog;
+
+ vprog = vreg->ctrl_reg & BOOST_VPROG_MASK;
+
+ return BOOST_UV_STEP * vprog + BOOST_UV_MIN;
+}
+
+static int pm8xxx_boost_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector >= BOOST_SET_POINTS)
+ return 0;
+
+ return selector * BOOST_UV_STEP + BOOST_UV_MIN;
+}
+
+static int pm8xxx_boost_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+ int uV = min_uV;
+ u8 val;
+
+ if (uV < BOOST_UV_MIN && max_uV >= BOOST_UV_MIN)
+ uV = BOOST_UV_MIN;
+
+ if (uV < BOOST_UV_MIN || uV > BOOST_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, BOOST_UV_MIN, BOOST_UV_MAX);
+ return -EINVAL;
+ }
+
+ val = (uV - BOOST_UV_MIN + BOOST_UV_STEP - 1) / BOOST_UV_STEP;
+ uV = val * BOOST_UV_STEP + BOOST_UV_MIN;
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ /* voltage setting */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+ BOOST_VPROG_MASK, &vreg->ctrl_reg);
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+ return rc;
+}
+
static unsigned int pm8xxx_ldo_get_mode(struct regulator_dev *rdev)
{
struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
@@ -2066,6 +2137,38 @@
return rc;
}
+static int pm8xxx_boost_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, BOOST_ENABLE,
+ BOOST_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_boost_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, BOOST_DISABLE,
+ BOOST_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
static int pm8xxx_ldo_pin_control_enable(struct regulator_dev *rdev)
{
struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
@@ -2506,6 +2609,11 @@
pr_info("%s %-9s: %s, v=%7d uV\n",
action_label, vreg->rdesc.name, enable_label, uV);
break;
+ case PM8XXX_REGULATOR_TYPE_BOOST:
+ uV = pm8xxx_boost_get_voltage(rdev);
+ pr_info("%s %-9s: %s, v=%7d uV\n",
+ action_label, vreg->rdesc.name, enable_label, uV);
+ break;
default:
break;
}
@@ -2601,6 +2709,16 @@
.enable_time = pm8xxx_enable_time,
};
+static struct regulator_ops pm8xxx_boost_ops = {
+ .enable = pm8xxx_boost_enable,
+ .disable = pm8xxx_boost_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .set_voltage = pm8xxx_boost_set_voltage,
+ .get_voltage = pm8xxx_boost_get_voltage,
+ .list_voltage = pm8xxx_boost_list_voltage,
+ .enable_time = pm8xxx_enable_time,
+};
+
/* Pin control regulator operations. */
static struct regulator_ops pm8xxx_ldo_pc_ops = {
.enable = pm8xxx_ldo_pin_control_enable,
@@ -2629,6 +2747,7 @@
[PM8XXX_REGULATOR_TYPE_VS] = &pm8xxx_vs_ops,
[PM8XXX_REGULATOR_TYPE_VS300] = &pm8xxx_vs300_ops,
[PM8XXX_REGULATOR_TYPE_NCP] = &pm8xxx_ncp_ops,
+ [PM8XXX_REGULATOR_TYPE_BOOST] = &pm8xxx_boost_ops,
};
static struct regulator_ops *pm8xxx_reg_pc_ops[PM8XXX_REGULATOR_TYPE_MAX] = {
@@ -2647,6 +2766,7 @@
[PM8XXX_REGULATOR_TYPE_VS] = 0,
[PM8XXX_REGULATOR_TYPE_VS300] = 0,
[PM8XXX_REGULATOR_TYPE_NCP] = NCP_SET_POINTS,
+ [PM8XXX_REGULATOR_TYPE_BOOST] = BOOST_SET_POINTS,
};
static int pm8xxx_init_ldo(struct pm8xxx_vreg *vreg, bool is_real)
@@ -2937,6 +3057,20 @@
return rc;
}
+static int pm8xxx_init_boost(struct pm8xxx_vreg *vreg)
+{
+ int rc;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc) {
+ vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static int __devinit pm8xxx_vreg_probe(struct platform_device *pdev)
{
struct pm8xxx_regulator_core_platform_data *core_data;
@@ -3058,6 +3192,9 @@
case PM8XXX_REGULATOR_TYPE_NCP:
rc = pm8xxx_init_ncp(vreg);
break;
+ case PM8XXX_REGULATOR_TYPE_BOOST:
+ rc = pm8xxx_init_boost(vreg);
+ break;
default:
break;
}
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index d053cd6..22297be 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1171,6 +1171,27 @@
}
slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
sat->satcl.laddr = laddr;
+ /*
+ * Since capability message is already sent, present
+ * message will indicate subsystem hosting this
+ * satellite has restarted.
+ * Remove all active channels of this satellite
+ * when this is detected
+ */
+ if (sat->sent_capability) {
+ for (i = 0; i < sat->nsatch; i++) {
+ enum slim_ch_state chs =
+ slim_get_ch_state(&sat->satcl,
+ sat->satch[i].chanh);
+ pr_err("Slim-SSR, sat:%d, rm chan:%d",
+ laddr,
+ sat->satch[i].chan);
+ if (chs == SLIM_CH_ACTIVE)
+ slim_control_ch(&sat->satcl,
+ sat->satch[i].chanh,
+ SLIM_CH_REMOVE, true);
+ }
+ }
} else if (mt != SLIM_MSG_MT_CORE &&
mc != SLIM_MSG_MC_REPORT_PRESENT) {
satv = msm_slim_get_ctrl(dev);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 6733396..cc008ab 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2730,15 +2730,19 @@
* -EXFULL is returned if there is no space in TDM to reserve the bandwidth.
* -EISCONN/-ENOTCONN is returned if the channel is already connected or not
* yet defined.
+ * -EINVAL is returned if individual control of a grouped-channel is attempted.
*/
int slim_control_ch(struct slim_device *sb, u16 chanh,
enum slim_ch_control chctrl, bool commit)
{
struct slim_controller *ctrl = sb->ctrl;
- struct slim_ich *slc;
int ret = 0;
/* Get rid of the group flag in MSB if any */
u8 chan = SLIM_HDL_TO_CHIDX(chanh);
+ struct slim_ich *slc = &ctrl->chans[chan];
+ if (!(slc->nextgrp & SLIM_START_GRP))
+ return -EINVAL;
+
mutex_lock(&sb->sldev_reconf);
mutex_lock(&ctrl->m_ctrl);
do {
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 648d2e9..7768eed 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -19,4 +19,11 @@
This is required for communicating with Qualcomm PMICs and
other devices that have the SPMI interface.
+config MSM_QPNP
+ depends on ARCH_MSMCOPPER
+ depends on OF_SPMI
+ bool "MSM QPNP"
+ help
+ Say 'y' here to include support for the Qualcomm QPNP
+ support. QPNP is a SPMI based PMIC implementation.
endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 8406134..659e886 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_SPMI) += spmi.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
+obj-$(CONFIG_MSM_QPNP) += qpnp.o
diff --git a/drivers/spmi/qpnp.c b/drivers/spmi/qpnp.c
new file mode 100644
index 0000000..ddf9000
--- /dev/null
+++ b/drivers/spmi/qpnp.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ * 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.
+ *
+ * Resource handling based on platform.c.
+ */
+
+#include <mach/qpnp.h>
+
+/**
+ * qpnp_get_resource - get a resource for a device
+ * @dev: qpnp device
+ * @type: resource type
+ * @num: resource index
+ */
+struct resource *qpnp_get_resource(struct spmi_device *dev,
+ unsigned int node_idx, unsigned int type,
+ unsigned int res_num)
+{
+ int i;
+
+ for (i = 0; i < dev->dev_node[node_idx].num_resources; i++) {
+ struct resource *r = &dev->dev_node[node_idx].resource[i];
+
+ if (type == resource_type(r) && res_num-- == 0)
+ return r;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(qpnp_get_resource);
+
+/**
+ * qpnp_get_irq - get an IRQ for a device
+ * @dev: qpnp device
+ * @num: IRQ number index
+ */
+int qpnp_get_irq(struct spmi_device *dev, unsigned int node_idx,
+ unsigned int res_num)
+{
+ struct resource *r = qpnp_get_resource(dev, node_idx,
+ IORESOURCE_IRQ, res_num);
+
+ return r ? r->start : -ENXIO;
+}
+EXPORT_SYMBOL_GPL(qpnp_get_irq);
+
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index cb42d89..93730ae 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -155,7 +155,7 @@
ram_console.flags &= ~CON_ENABLED;
}
-static void __init
+static void __devinit
ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo,
char *dest)
{
@@ -239,7 +239,7 @@
}
}
-static int __init ram_console_init(struct ram_console_buffer *buffer,
+static int __devinit ram_console_init(struct ram_console_buffer *buffer,
size_t buffer_size, const char *bootinfo,
char *old_buf)
{
@@ -336,7 +336,7 @@
ram_console_old_log_init_buffer);
}
#else
-static int ram_console_driver_probe(struct platform_device *pdev)
+static int __devinit ram_console_driver_probe(struct platform_device *pdev)
{
struct resource *res = pdev->resource;
size_t start;
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 0e279b8..c38b279 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -920,7 +920,7 @@
}
for (i = 0; i < tmdev->tsens_num_sensor; i++) {
- char name[17];
+ char name[18];
snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
tmdev->sensor[i].sensor_num = i;
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index c893889..8ea4632 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -47,7 +47,6 @@
.flags = CI13XXX_REGS_SHARED |
CI13XXX_REQUIRE_TRANSCEIVER |
CI13XXX_PULLUP_ON_VBUS |
- CI13XXX_DISABLE_STREAMING |
CI13XXX_ZERO_ITC,
.notify_event = ci13xxx_msm_notify_event,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index dc11eaf..97b0a2e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1274,6 +1274,7 @@
#ifdef CONFIG_USB_EHCI_MSM
#include "ehci-msm.c"
+#include "ehci-msm2.c"
#define PLATFORM_DRIVER_PRESENT
#endif
@@ -1391,7 +1392,11 @@
#endif
#ifdef CONFIG_USB_EHCI_MSM_HSIC
- &ehci_msm_hsic_driver
+ &ehci_msm_hsic_driver,
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM
+ &ehci_msm2_driver,
#endif
};
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d64f223..dd3ec34 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -712,10 +712,12 @@
return 0;
put_clocks:
- clk_disable_unprepare(mehci->core_clk);
- clk_disable_unprepare(mehci->phy_clk);
- clk_disable_unprepare(mehci->cal_clk);
- clk_disable_unprepare(mehci->ahb_clk);
+ if (!atomic_read(&mehci->in_lpm)) {
+ clk_disable_unprepare(mehci->core_clk);
+ clk_disable_unprepare(mehci->phy_clk);
+ clk_disable_unprepare(mehci->cal_clk);
+ clk_disable_unprepare(mehci->ahb_clk);
+ }
clk_put(mehci->ahb_clk);
put_cal_clk:
clk_put(mehci->cal_clk);
@@ -893,7 +895,6 @@
free_irq(mehci->peripheral_status_irq, mehci);
device_init_wakeup(&pdev->dev, 0);
- pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
new file mode 100644
index 0000000..4f6fe3e
--- /dev/null
+++ b/drivers/usb/host/ehci-msm2.c
@@ -0,0 +1,1003 @@
+/* ehci-msm2.c - HSUSB Host Controller Driver Implementation
+ *
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Partly derived from ehci-fsl.c and ehci-hcd.c
+ * Copyright (c) 2000-2004 by David Brownell
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/usb/ulpi.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/msm_hsusb.h>
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+
+#define MSM_USB_BASE (hcd->regs)
+
+struct msm_hcd {
+ struct ehci_hcd ehci;
+ struct device *dev;
+ struct clk *iface_clk;
+ struct clk *core_clk;
+ struct clk *alt_core_clk;
+ struct regulator *hsusb_vddcx;
+ struct regulator *hsusb_3p3;
+ struct regulator *hsusb_1p8;
+ struct regulator *vbus;
+ bool async_int;
+ atomic_t in_lpm;
+ struct wake_lock wlock;
+};
+
+static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
+{
+ return (struct msm_hcd *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *mhcd_to_hcd(struct msm_hcd *mhcd)
+{
+ return container_of((void *) mhcd, struct usb_hcd, hcd_priv);
+}
+
+#define HSUSB_PHY_3P3_VOL_MIN 3050000 /* uV */
+#define HSUSB_PHY_3P3_VOL_MAX 3300000 /* uV */
+#define HSUSB_PHY_3P3_HPM_LOAD 50000 /* uA */
+
+#define HSUSB_PHY_1P8_VOL_MIN 1800000 /* uV */
+#define HSUSB_PHY_1P8_VOL_MAX 1800000 /* uV */
+#define HSUSB_PHY_1P8_HPM_LOAD 50000 /* uA */
+
+#define HSUSB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
+#define HSUSB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
+#define HSUSB_PHY_VDD_DIG_LOAD 49360 /* uA */
+
+static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
+{
+ int ret = 0;
+
+ if (!init)
+ goto disable_reg;
+
+ mhcd->hsusb_vddcx = regulator_get(mhcd->dev, "HSUSB_VDDCX");
+ if (IS_ERR(mhcd->hsusb_vddcx)) {
+ dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+ return PTR_ERR(mhcd->hsusb_vddcx);
+ }
+
+ ret = regulator_set_voltage(mhcd->hsusb_vddcx,
+ HSUSB_PHY_VDD_DIG_VOL_MIN,
+ HSUSB_PHY_VDD_DIG_VOL_MAX);
+ if (ret) {
+ dev_err(mhcd->dev, "unable to set the voltage"
+ "for ehci vddcx\n");
+ goto reg_set_voltage_err;
+ }
+
+ ret = regulator_set_optimum_mode(mhcd->hsusb_vddcx,
+ HSUSB_PHY_VDD_DIG_LOAD);
+ if (ret < 0) {
+ dev_err(mhcd->dev, "%s: Unable to set optimum mode of the"
+ " regulator: VDDCX\n", __func__);
+ goto reg_optimum_mode_err;
+ }
+
+ ret = regulator_enable(mhcd->hsusb_vddcx);
+ if (ret) {
+ dev_err(mhcd->dev, "unable to enable ehci vddcx\n");
+ goto reg_enable_err;
+ }
+
+ return 0;
+
+disable_reg:
+ regulator_disable(mhcd->hsusb_vddcx);
+reg_enable_err:
+ regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
+reg_optimum_mode_err:
+ regulator_set_voltage(mhcd->hsusb_vddcx, 0,
+ HSUSB_PHY_VDD_DIG_VOL_MIN);
+reg_set_voltage_err:
+ regulator_put(mhcd->hsusb_vddcx);
+
+ return ret;
+
+}
+
+static int msm_ehci_ldo_init(struct msm_hcd *mhcd, int init)
+{
+ int rc = 0;
+
+ if (!init)
+ goto put_1p8;
+
+ mhcd->hsusb_3p3 = regulator_get(mhcd->dev, "HSUSB_3p3");
+ if (IS_ERR(mhcd->hsusb_3p3)) {
+ dev_err(mhcd->dev, "unable to get hsusb 3p3\n");
+ return PTR_ERR(mhcd->hsusb_3p3);
+ }
+
+ rc = regulator_set_voltage(mhcd->hsusb_3p3,
+ HSUSB_PHY_3P3_VOL_MIN, HSUSB_PHY_3P3_VOL_MAX);
+ if (rc) {
+ dev_err(mhcd->dev, "unable to set voltage level for"
+ "hsusb 3p3\n");
+ goto put_3p3;
+ }
+ mhcd->hsusb_1p8 = regulator_get(mhcd->dev, "HSUSB_1p8");
+ if (IS_ERR(mhcd->hsusb_1p8)) {
+ dev_err(mhcd->dev, "unable to get hsusb 1p8\n");
+ rc = PTR_ERR(mhcd->hsusb_1p8);
+ goto put_3p3_lpm;
+ }
+ rc = regulator_set_voltage(mhcd->hsusb_1p8,
+ HSUSB_PHY_1P8_VOL_MIN, HSUSB_PHY_1P8_VOL_MAX);
+ if (rc) {
+ dev_err(mhcd->dev, "unable to set voltage level for"
+ "hsusb 1p8\n");
+ goto put_1p8;
+ }
+
+ return 0;
+
+put_1p8:
+ regulator_set_voltage(mhcd->hsusb_1p8, 0, HSUSB_PHY_1P8_VOL_MAX);
+ regulator_put(mhcd->hsusb_1p8);
+put_3p3_lpm:
+ regulator_set_voltage(mhcd->hsusb_3p3, 0, HSUSB_PHY_3P3_VOL_MAX);
+put_3p3:
+ regulator_put(mhcd->hsusb_3p3);
+
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+#define HSUSB_PHY_SUSP_DIG_VOL 500000
+static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
+{
+ int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
+ int min_vol;
+ int ret;
+
+ if (high)
+ min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+ else
+ min_vol = HSUSB_PHY_SUSP_DIG_VOL;
+
+ ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
+ if (ret) {
+ dev_err(mhcd->dev, "%s: unable to set the voltage of regulator"
+ " HSUSB_VDDCX\n", __func__);
+ return ret;
+ }
+
+ dev_dbg(mhcd->dev, "%s: min_vol:%d max_vol:%d\n", __func__, min_vol,
+ max_vol);
+
+ return ret;
+}
+#else
+static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
+{
+ return 0;
+}
+#endif
+
+static int msm_ehci_init_vbus(struct msm_hcd *mhcd, int init)
+{
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ struct msm_usb_host_platform_data *pdata;
+
+ if (!init) {
+ regulator_put(mhcd->vbus);
+ return 0;
+ }
+
+ mhcd->vbus = regulator_get(mhcd->dev, "vbus");
+ if (IS_ERR(mhcd->vbus)) {
+ pr_err("Unable to get vbus\n");
+ return -ENODEV;
+ }
+
+ pdata = mhcd->dev->platform_data;
+ if (pdata)
+ hcd->power_budget = pdata->power_budget;
+
+ return 0;
+}
+
+static void msm_ehci_vbus_power(struct msm_hcd *mhcd, bool on)
+{
+ int ret;
+
+ if (!mhcd->vbus) {
+ pr_err("vbus is NULL.");
+ return;
+ }
+ if (on) {
+ ret = regulator_enable(mhcd->vbus);
+ if (ret) {
+ pr_err("unable to enable vbus\n");
+ return;
+ }
+ } else {
+ ret = regulator_disable(mhcd->vbus);
+ if (ret) {
+ pr_err("unable to disable vbus\n");
+ return;
+ }
+ }
+}
+
+static int msm_ehci_ldo_enable(struct msm_hcd *mhcd, int on)
+{
+ int ret = 0;
+
+ if (IS_ERR(mhcd->hsusb_1p8)) {
+ dev_err(mhcd->dev, "%s: HSUSB_1p8 is not initialized\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (IS_ERR(mhcd->hsusb_3p3)) {
+ dev_err(mhcd->dev, "%s: HSUSB_3p3 is not initialized\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (on) {
+ ret = regulator_set_optimum_mode(mhcd->hsusb_1p8,
+ HSUSB_PHY_1P8_HPM_LOAD);
+ if (ret < 0) {
+ dev_err(mhcd->dev, "%s: Unable to set HPM of the"
+ " regulator: HSUSB_1p8\n", __func__);
+ return ret;
+ }
+
+ ret = regulator_enable(mhcd->hsusb_1p8);
+ if (ret) {
+ dev_err(mhcd->dev, "%s: unable to enable the hsusb"
+ " 1p8\n", __func__);
+ regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(mhcd->hsusb_3p3,
+ HSUSB_PHY_3P3_HPM_LOAD);
+ if (ret < 0) {
+ dev_err(mhcd->dev, "%s: Unable to set HPM of the "
+ "regulator: HSUSB_3p3\n", __func__);
+ regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+ regulator_disable(mhcd->hsusb_1p8);
+ return ret;
+ }
+
+ ret = regulator_enable(mhcd->hsusb_3p3);
+ if (ret) {
+ dev_err(mhcd->dev, "%s: unable to enable the "
+ "hsusb 3p3\n", __func__);
+ regulator_set_optimum_mode(mhcd->hsusb_3p3, 0);
+ regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+ regulator_disable(mhcd->hsusb_1p8);
+ return ret;
+ }
+
+ } else {
+ ret = regulator_disable(mhcd->hsusb_1p8);
+ if (ret) {
+ dev_err(mhcd->dev, "%s: unable to disable the "
+ "hsusb 1p8\n", __func__);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+ if (ret < 0)
+ dev_err(mhcd->dev, "%s: Unable to set LPM of the "
+ "regulator: HSUSB_1p8\n", __func__);
+
+ ret = regulator_disable(mhcd->hsusb_3p3);
+ if (ret) {
+ dev_err(mhcd->dev, "%s: unable to disable the "
+ "hsusb 3p3\n", __func__);
+ return ret;
+ }
+ ret = regulator_set_optimum_mode(mhcd->hsusb_3p3, 0);
+ if (ret < 0)
+ dev_err(mhcd->dev, "%s: Unable to set LPM of the "
+ "regulator: HSUSB_3p3\n", __func__);
+ }
+
+ dev_dbg(mhcd->dev, "reg (%s)\n", on ? "HPM" : "LPM");
+
+ return ret < 0 ? ret : 0;
+}
+
+
+#define ULPI_IO_TIMEOUT_USECS (10 * 1000)
+static int msm_ulpi_read(struct msm_hcd *mhcd, u32 reg)
+{
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ unsigned long timeout;
+
+ /* initiate read operation */
+ writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USECS);
+ while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(mhcd->dev, "msm_ulpi_read: timeout %08x\n",
+ readl_relaxed(USB_ULPI_VIEWPORT));
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
+}
+
+
+static int msm_ulpi_write(struct msm_hcd *mhcd, u32 val, u32 reg)
+{
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ unsigned long timeout;
+
+ /* initiate write operation */
+ writel_relaxed(ULPI_RUN | ULPI_WRITE |
+ ULPI_ADDR(reg) | ULPI_DATA(val),
+ USB_ULPI_VIEWPORT);
+
+ /* wait for completion */
+ timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USECS);
+ while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(mhcd->dev, "msm_ulpi_write: timeout\n");
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static int msm_ehci_link_clk_reset(struct msm_hcd *mhcd, bool assert)
+{
+ int ret;
+
+ if (assert) {
+ ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_ASSERT);
+ if (ret)
+ dev_err(mhcd->dev, "usb alt_core_clk assert failed\n");
+ } else {
+ ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_DEASSERT);
+ if (ret)
+ dev_err(mhcd->dev, "usb alt_core_clk deassert failed\n");
+ }
+
+ return ret;
+}
+
+static int msm_ehci_phy_reset(struct msm_hcd *mhcd)
+{
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ u32 val;
+ int ret;
+ int retries;
+
+ ret = msm_ehci_link_clk_reset(mhcd, 1);
+ if (ret)
+ return ret;
+
+ udelay(1);
+
+ ret = msm_ehci_link_clk_reset(mhcd, 0);
+ if (ret)
+ return ret;
+
+ val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
+ writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+ for (retries = 3; retries > 0; retries--) {
+ ret = msm_ulpi_write(mhcd, ULPI_FUNC_CTRL_SUSPENDM,
+ ULPI_CLR(ULPI_FUNC_CTRL));
+ if (!ret)
+ break;
+ }
+ if (!retries)
+ return -ETIMEDOUT;
+
+ /* Wakeup the PHY with a reg-access for calibration */
+ for (retries = 3; retries > 0; retries--) {
+ ret = msm_ulpi_read(mhcd, ULPI_DEBUG);
+ if (ret != -ETIMEDOUT)
+ break;
+ }
+ if (!retries)
+ return -ETIMEDOUT;
+
+ dev_info(mhcd->dev, "phy_reset: success\n");
+
+ return 0;
+}
+
+#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
+static int msm_hsusb_reset(struct msm_hcd *mhcd)
+{
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ unsigned long timeout;
+ int ret;
+
+ clk_prepare_enable(mhcd->alt_core_clk);
+ ret = msm_ehci_phy_reset(mhcd);
+ if (ret) {
+ dev_err(mhcd->dev, "phy_reset failed\n");
+ return ret;
+ }
+
+ writel_relaxed(USBCMD_RESET, USB_USBCMD);
+
+ timeout = jiffies + usecs_to_jiffies(LINK_RESET_TIMEOUT_USEC);
+ while (readl_relaxed(USB_USBCMD) & USBCMD_RESET) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ udelay(1);
+ }
+
+ /* select ULPI phy */
+ writel_relaxed(0x80000000, USB_PORTSC);
+
+ msleep(100);
+
+ writel_relaxed(0x0, USB_AHBBURST);
+ writel_relaxed(0x00, USB_AHBMODE);
+
+ /* Ensure that RESET operation is completed before turning off clock */
+ mb();
+ clk_disable_unprepare(mhcd->alt_core_clk);
+
+ /*rising edge interrupts with Dp rise and fall enabled*/
+ msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_RISE);
+ msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_FALL);
+
+ /*Clear the PHY interrupts by reading the PHY interrupt latch register*/
+ msm_ulpi_read(mhcd, ULPI_USB_INT_LATCH);
+
+ return 0;
+}
+
+#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
+#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_ehci_suspend(struct msm_hcd *mhcd)
+{
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ unsigned long timeout;
+ u32 portsc;
+
+ if (atomic_read(&mhcd->in_lpm)) {
+ dev_dbg(mhcd->dev, "%s called in lpm\n", __func__);
+ return 0;
+ }
+
+ disable_irq(hcd->irq);
+
+ /* Set the PHCD bit, only if it is not set by the controller.
+ * PHY may take some time or even fail to enter into low power
+ * mode (LPM). Hence poll for 500 msec and reset the PHY and link
+ * in failure case.
+ */
+ portsc = readl_relaxed(USB_PORTSC);
+ if (!(portsc & PORTSC_PHCD)) {
+ writel_relaxed(portsc | PORTSC_PHCD,
+ USB_PORTSC);
+
+ timeout = jiffies + usecs_to_jiffies(PHY_SUSPEND_TIMEOUT_USEC);
+ while (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD)) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(mhcd->dev, "Unable to suspend PHY\n");
+ msm_hsusb_reset(mhcd);
+ break;
+ }
+ udelay(1);
+ }
+ }
+
+ /*
+ * PHY has capability to generate interrupt asynchronously in low
+ * power mode (LPM). This interrupt is level triggered. So USB IRQ
+ * line must be disabled till async interrupt enable bit is cleared
+ * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+ * block data communication from PHY.
+ */
+ writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
+ ULPI_STP_CTRL, USB_USBCMD);
+
+ /*
+ * Ensure that hardware is put in low power mode before
+ * clocks are turned OFF and VDD is allowed to minimize.
+ */
+ mb();
+
+ clk_disable_unprepare(mhcd->iface_clk);
+ clk_disable_unprepare(mhcd->core_clk);
+
+ msm_ehci_config_vddcx(mhcd, 0);
+
+ atomic_set(&mhcd->in_lpm, 1);
+ enable_irq(hcd->irq);
+ wake_unlock(&mhcd->wlock);
+
+ dev_info(mhcd->dev, "EHCI USB in low power mode\n");
+
+ return 0;
+}
+
+static int msm_ehci_resume(struct msm_hcd *mhcd)
+{
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ unsigned long timeout;
+ unsigned temp;
+
+ if (!atomic_read(&mhcd->in_lpm)) {
+ dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
+ return 0;
+ }
+
+ wake_lock(&mhcd->wlock);
+
+ clk_prepare_enable(mhcd->core_clk);
+ clk_prepare_enable(mhcd->iface_clk);
+
+ msm_ehci_config_vddcx(mhcd, 1);
+
+ temp = readl_relaxed(USB_USBCMD);
+ temp &= ~ASYNC_INTR_CTRL;
+ temp &= ~ULPI_STP_CTRL;
+ writel_relaxed(temp, USB_USBCMD);
+
+ if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+ goto skip_phy_resume;
+
+ temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
+ writel_relaxed(temp, USB_PORTSC);
+
+ timeout = jiffies + usecs_to_jiffies(PHY_RESUME_TIMEOUT_USEC);
+ while ((readl_relaxed(USB_PORTSC) & PORTSC_PHCD) ||
+ !(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE)) {
+ if (time_after(jiffies, timeout)) {
+ /*This is a fatal error. Reset the link and PHY*/
+ dev_err(mhcd->dev, "Unable to resume USB. Resetting the h/w\n");
+ msm_hsusb_reset(mhcd);
+ break;
+ }
+ udelay(1);
+ }
+
+skip_phy_resume:
+
+ atomic_set(&mhcd->in_lpm, 0);
+
+ if (mhcd->async_int) {
+ mhcd->async_int = false;
+ pm_runtime_put_noidle(mhcd->dev);
+ enable_irq(hcd->irq);
+ }
+
+ dev_info(mhcd->dev, "EHCI USB exited from low power mode\n");
+
+ return 0;
+}
+#endif
+
+static irqreturn_t msm_ehci_irq(struct usb_hcd *hcd)
+{
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+ if (atomic_read(&mhcd->in_lpm)) {
+ disable_irq_nosync(hcd->irq);
+ mhcd->async_int = true;
+ pm_runtime_get(mhcd->dev);
+ return IRQ_HANDLED;
+ }
+
+ return ehci_irq(hcd);
+}
+
+static int msm_ehci_reset(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ ehci->caps = USB_CAPLENGTH;
+ ehci->regs = USB_CAPLENGTH +
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ /* cache the data to minimize the chip reads*/
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ hcd->has_tt = 1;
+ ehci->sbrn = HCD_USB2;
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ /* data structure init */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ retval = ehci_reset(ehci);
+ if (retval)
+ return retval;
+
+ /* bursts of unspecified length. */
+ writel_relaxed(0, USB_AHBBURST);
+ /* Use the AHB transactor */
+ writel_relaxed(0, USB_AHBMODE);
+ /* Disable streaming mode and select host mode */
+ writel_relaxed(0x13, USB_USBMODE);
+
+ ehci_port_power(ehci, 1);
+ return 0;
+}
+
+static struct hc_driver msm_hc2_driver = {
+ .description = hcd_name,
+ .product_desc = "Qualcomm EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct msm_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = msm_ehci_irq,
+ .flags = HCD_USB2 | HCD_MEMORY,
+
+ .reset = msm_ehci_reset,
+ .start = ehci_run,
+
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ /*
+ * PM support
+ */
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+};
+
+static int msm_ehci_init_clocks(struct msm_hcd *mhcd, u32 init)
+{
+ int ret = 0;
+
+ if (!init)
+ goto put_clocks;
+
+ /* 60MHz alt_core_clk is for LINK to be used during PHY RESET */
+ mhcd->alt_core_clk = clk_get(mhcd->dev, "alt_core_clk");
+ if (IS_ERR(mhcd->alt_core_clk)) {
+ dev_err(mhcd->dev, "failed to get alt_core_clk\n");
+ ret = PTR_ERR(mhcd->alt_core_clk);
+ return ret;
+ }
+ clk_set_rate(mhcd->alt_core_clk, 60000000);
+
+ /* iface_clk is required for data transfers */
+ mhcd->iface_clk = clk_get(mhcd->dev, "iface_clk");
+ if (IS_ERR(mhcd->iface_clk)) {
+ dev_err(mhcd->dev, "failed to get iface_clk\n");
+ ret = PTR_ERR(mhcd->iface_clk);
+ goto put_alt_core_clk;
+ }
+
+ /* Link's protocol engine is based on pclk which must
+ * be running >55Mhz and frequency should also not change.
+ * Hence, vote for maximum clk frequency on its source
+ */
+ mhcd->core_clk = clk_get(mhcd->dev, "core_clk");
+ if (IS_ERR(mhcd->core_clk)) {
+ dev_err(mhcd->dev, "failed to get core_clk\n");
+ ret = PTR_ERR(mhcd->core_clk);
+ goto put_iface_clk;
+ }
+ clk_set_rate(mhcd->core_clk, INT_MAX);
+
+ clk_prepare_enable(mhcd->core_clk);
+ clk_prepare_enable(mhcd->iface_clk);
+
+ return 0;
+
+put_clocks:
+ clk_disable_unprepare(mhcd->iface_clk);
+ clk_disable_unprepare(mhcd->core_clk);
+ clk_put(mhcd->core_clk);
+put_iface_clk:
+ clk_put(mhcd->iface_clk);
+put_alt_core_clk:
+ clk_put(mhcd->alt_core_clk);
+
+ return ret;
+}
+
+static int __devinit ehci_msm2_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ struct msm_hcd *mhcd;
+ int ret;
+
+ dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
+
+ hcd = usb_create_hcd(&msm_hc2_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd) {
+ dev_err(&pdev->dev, "Unable to create HCD\n");
+ return -ENOMEM;
+ }
+
+ hcd->irq = platform_get_irq(pdev, 0);
+ if (hcd->irq < 0) {
+ dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+ ret = hcd->irq;
+ goto put_hcd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get memory resource\n");
+ ret = -ENODEV;
+ goto put_hcd;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto put_hcd;
+ }
+
+ mhcd = hcd_to_mhcd(hcd);
+ mhcd->dev = &pdev->dev;
+
+ ret = msm_ehci_init_clocks(mhcd, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to initialize clocks\n");
+ ret = -ENODEV;
+ goto unmap;
+ }
+
+ ret = msm_ehci_init_vddcx(mhcd, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to initialize VDDCX\n");
+ ret = -ENODEV;
+ goto deinit_clocks;
+ }
+
+ ret = msm_ehci_config_vddcx(mhcd, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
+ goto deinit_vddcx;
+ }
+
+ ret = msm_ehci_ldo_init(mhcd, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
+ goto deinit_vddcx;
+ }
+
+ ret = msm_ehci_ldo_enable(mhcd, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "hsusb vreg enable failed\n");
+ goto deinit_ldo;
+ }
+
+ ret = msm_ehci_init_vbus(mhcd, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get vbus\n");
+ goto disable_ldo;
+ }
+
+ ret = msm_hsusb_reset(mhcd);
+ if (ret) {
+ dev_err(&pdev->dev, "hsusb PHY initialization failed\n");
+ goto vbus_deinit;
+ }
+
+ ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to register HCD\n");
+ goto vbus_deinit;
+ }
+
+ /*TBD:for now enable vbus here*/
+ msm_ehci_vbus_power(mhcd, 1);
+
+ device_init_wakeup(&pdev->dev, 1);
+ wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
+ wake_lock(&mhcd->wlock);
+ /*
+ * This pdev->dev is assigned parent of root-hub by USB core,
+ * hence, runtime framework automatically calls this driver's
+ * runtime APIs based on root-hub's state.
+ */
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+vbus_deinit:
+ msm_ehci_init_vbus(mhcd, 0);
+disable_ldo:
+ msm_ehci_ldo_enable(mhcd, 0);
+deinit_ldo:
+ msm_ehci_ldo_init(mhcd, 0);
+deinit_vddcx:
+ msm_ehci_init_vddcx(mhcd, 0);
+deinit_clocks:
+ msm_ehci_init_clocks(mhcd, 0);
+unmap:
+ iounmap(hcd->regs);
+put_hcd:
+ usb_put_hcd(hcd);
+
+ return ret;
+}
+
+static int __devexit ehci_msm2_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+ device_init_wakeup(&pdev->dev, 0);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ usb_remove_hcd(hcd);
+ msm_ehci_vbus_power(mhcd, 0);
+ msm_ehci_init_vbus(mhcd, 0);
+ msm_ehci_ldo_enable(mhcd, 0);
+ msm_ehci_ldo_init(mhcd, 0);
+ msm_ehci_init_vddcx(mhcd, 0);
+
+ msm_ehci_init_clocks(mhcd, 0);
+ wake_lock_destroy(&mhcd->wlock);
+ iounmap(hcd->regs);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ehci_msm2_pm_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+ dev_dbg(dev, "ehci-msm2 PM suspend\n");
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(hcd->irq);
+
+ return msm_ehci_suspend(mhcd);
+
+}
+
+static int ehci_msm2_pm_resume(struct device *dev)
+{
+ int ret;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+ dev_dbg(dev, "ehci-msm2 PM resume\n");
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(hcd->irq);
+
+ ret = msm_ehci_resume(mhcd);
+ if (ret)
+ return ret;
+
+ /* Bring the device to full powered state upon system resume */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int ehci_msm2_runtime_idle(struct device *dev)
+{
+ dev_dbg(dev, "EHCI runtime idle\n");
+
+ return 0;
+}
+
+static int ehci_msm2_runtime_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+ dev_dbg(dev, "EHCI runtime suspend\n");
+ return msm_ehci_suspend(mhcd);
+}
+
+static int ehci_msm2_runtime_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+ dev_dbg(dev, "EHCI runtime resume\n");
+ return msm_ehci_resume(mhcd);
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops ehci_msm2_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ehci_msm2_pm_suspend, ehci_msm2_pm_resume)
+ SET_RUNTIME_PM_OPS(ehci_msm2_runtime_suspend, ehci_msm2_runtime_resume,
+ ehci_msm2_runtime_idle)
+};
+#endif
+
+static struct platform_driver ehci_msm2_driver = {
+ .probe = ehci_msm2_probe,
+ .remove = __devexit_p(ehci_msm2_remove),
+ .driver = {
+ .name = "msm_ehci_host",
+#ifdef CONFIG_PM
+ .pm = &ehci_msm2_dev_pm_ops,
+#endif
+ },
+};
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index b71e309..caa5fda 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -651,6 +651,15 @@
To compile this driver as a module, choose M here: the
module will be called ssu100.
+config USB_SERIAL_CSVT
+ tristate "USB serial driver for Circuit-Switched Video Telephony"
+ help
+ Say Y here if you want to use usb serial driver for Circuit-Switched
+ Video Telephony
+
+ To compile this driver as a module, choose M here: the
+ module will be called csvt.
+
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 9e536ee..2d085b2 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -60,3 +60,4 @@
obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o
obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o
+obj-$(CONFIG_USB_SERIAL_CSVT) += csvt.o
diff --git a/drivers/usb/serial/csvt.c b/drivers/usb/serial/csvt.c
new file mode 100644
index 0000000..5bfb2dc
--- /dev/null
+++ b/drivers/usb/serial/csvt.c
@@ -0,0 +1,446 @@
+/* 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 <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/serial.h>
+#include <asm/unaligned.h>
+
+
+/* output control lines*/
+#define CSVT_CTRL_DTR 0x01
+#define CSVT_CTRL_RTS 0x02
+
+/* input control lines*/
+#define CSVT_CTRL_CTS 0x01
+#define CSVT_CTRL_DSR 0x02
+#define CSVT_CTRL_RI 0x04
+#define CSVT_CTRL_CD 0x08
+
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+struct csvt_ctrl_dev {
+ struct mutex dev_lock;
+
+ /* input control lines (DSR, CTS, CD, RI) */
+ unsigned int cbits_tolocal;
+
+ /* output control lines (DTR, RTS) */
+ unsigned int cbits_tomdm;
+};
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0x00, 0xff)},
+ {}, /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver csvt_driver = {
+ .name = "qc_csvt",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
+ .supports_autosuspend = true,
+};
+
+#define CSVT_IFC_NUM 4
+
+static int csvt_probe(struct usb_serial *serial, const struct usb_device_id *id)
+{
+ struct usb_host_interface *intf =
+ serial->interface->cur_altsetting;
+
+ pr_debug("%s:\n", __func__);
+
+ if (intf->desc.bInterfaceNumber != CSVT_IFC_NUM)
+ return -ENODEV;
+
+ usb_enable_autosuspend(serial->dev);
+
+ return 0;
+}
+
+static int csvt_ctrl_write_cmd(struct csvt_ctrl_dev *dev,
+ struct usb_serial_port *port)
+{
+ struct usb_device *udev = port->serial->dev;
+ struct usb_interface *iface = port->serial->interface;
+ unsigned int iface_num;
+ int retval = 0;
+
+ retval = usb_autopm_get_interface(iface);
+ if (retval < 0) {
+ dev_err(&port->dev, "%s: Unable to resume interface: %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ dev_dbg(&port->dev, "%s: cbits to mdm 0x%x\n", __func__,
+ dev->cbits_tomdm);
+
+ iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
+ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_CDC_REQ_SET_CONTROL_LINE_STATE,
+ (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
+ dev->cbits_tomdm,
+ iface_num,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ usb_autopm_put_interface(iface);
+
+ return retval;
+}
+
+static void csvt_ctrl_dtr_rts(struct usb_serial_port *port, int on)
+{
+ struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
+
+ if (!dev)
+ return;
+
+ dev_dbg(&port->dev, "%s", __func__);
+
+ mutex_lock(&dev->dev_lock);
+ if (on) {
+ dev->cbits_tomdm |= CSVT_CTRL_DTR;
+ dev->cbits_tomdm |= CSVT_CTRL_RTS;
+ } else {
+ dev->cbits_tomdm &= ~CSVT_CTRL_DTR;
+ dev->cbits_tomdm &= ~CSVT_CTRL_RTS;
+ }
+ mutex_unlock(&dev->dev_lock);
+
+ csvt_ctrl_write_cmd(dev, port);
+}
+
+static int get_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.line = port->serial->minor;
+ tmp.port = port->number;
+ tmp.baud_base = tty_get_baud_rate(port->port.tty);
+ tmp.close_delay = port->port.close_delay / 10;
+ tmp.closing_wait =
+ port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE :
+ port->port.closing_wait / 10;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *newinfo)
+{
+ struct serial_struct new_serial;
+ unsigned int closing_wait;
+ unsigned int close_delay;
+ int retval = 0;
+
+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+ return -EFAULT;
+
+ close_delay = new_serial.close_delay * 10;
+ closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+ mutex_lock(&port->port.mutex);
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((close_delay != port->port.close_delay) ||
+ (closing_wait != port->port.closing_wait))
+ retval = -EPERM;
+ else
+ retval = -EOPNOTSUPP;
+ } else {
+ port->port.close_delay = close_delay;
+ port->port.closing_wait = closing_wait;
+ }
+
+ mutex_unlock(&port->port.mutex);
+ return retval;
+}
+
+static int csvt_ctrl_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ dev_dbg(&port->dev, "%s cmd 0x%04x", __func__, cmd);
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(port,
+ (struct serial_struct __user *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(port,
+ (struct serial_struct __user *) arg);
+ default:
+ break;
+ }
+
+ dev_err(&port->dev, "%s arg not supported", __func__);
+
+ return -ENOIOCTLCMD;
+}
+
+static int csvt_ctrl_tiocmget(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
+ unsigned int control_state = 0;
+
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->dev_lock);
+ control_state = (dev->cbits_tomdm & CSVT_CTRL_DTR ? TIOCM_DTR : 0) |
+ (dev->cbits_tomdm & CSVT_CTRL_RTS ? TIOCM_RTS : 0) |
+ (dev->cbits_tolocal & CSVT_CTRL_DSR ? TIOCM_DSR : 0) |
+ (dev->cbits_tolocal & CSVT_CTRL_RI ? TIOCM_RI : 0) |
+ (dev->cbits_tolocal & CSVT_CTRL_CD ? TIOCM_CD : 0) |
+ (dev->cbits_tolocal & CSVT_CTRL_CTS ? TIOCM_CTS : 0);
+ mutex_unlock(&dev->dev_lock);
+
+ dev_dbg(&port->dev, "%s -- %x", __func__, control_state);
+
+ return control_state;
+}
+
+static int csvt_ctrl_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
+
+ if (!dev)
+ return -ENODEV;
+
+ dev_dbg(&port->dev, "%s\n", __func__);
+
+ mutex_lock(&dev->dev_lock);
+ if (set & CSVT_CTRL_DTR)
+ dev->cbits_tomdm |= TIOCM_DTR;
+ if (set & CSVT_CTRL_RTS)
+ dev->cbits_tomdm |= TIOCM_RTS;
+
+ if (clear & CSVT_CTRL_DTR)
+ dev->cbits_tomdm &= ~TIOCM_DTR;
+ if (clear & CSVT_CTRL_RTS)
+ dev->cbits_tomdm &= ~TIOCM_RTS;
+ mutex_unlock(&dev->dev_lock);
+
+ return csvt_ctrl_write_cmd(dev, port);
+}
+
+static void csvt_ctrl_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
+
+ if (!dev)
+ return;
+
+ dev_dbg(&port->dev, "%s", __func__);
+
+ /* Doesn't support option setting */
+ tty_termios_copy_hw(tty->termios, old_termios);
+
+ csvt_ctrl_write_cmd(dev, port);
+}
+
+static void csvt_ctrl_int_cb(struct urb *urb)
+{
+ int status;
+ struct usb_cdc_notification *ctrl;
+ struct usb_serial_port *port = urb->context;
+ struct csvt_ctrl_dev *dev;
+ unsigned int ctrl_bits;
+ unsigned char *data;
+
+ switch (urb->status) {
+ case 0:
+ /*success*/
+ break;
+ case -ESHUTDOWN:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPROTO:
+ /* unplug */
+ return;
+ case -EPIPE:
+ dev_err(&port->dev, "%s: stall on int endpoint\n", __func__);
+ /* TBD : halt to be cleared in work */
+ case -EOVERFLOW:
+ default:
+ pr_debug_ratelimited("%s: non zero urb status = %d\n",
+ __func__, urb->status);
+ goto resubmit_int_urb;
+ }
+
+ dev = usb_get_serial_port_data(port);
+ if (!dev)
+ return;
+
+ ctrl = urb->transfer_buffer;
+ data = (unsigned char *)(ctrl + 1);
+
+ usb_serial_debug_data(debug, &port->dev, __func__,
+ urb->actual_length, data);
+
+ switch (ctrl->bNotificationType) {
+ case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+ dev_dbg(&port->dev, "%s network\n", ctrl->wValue ?
+ "connected to" : "disconnected from");
+ break;
+ case USB_CDC_NOTIFY_SERIAL_STATE:
+ ctrl_bits = get_unaligned_le16(data);
+ dev_dbg(&port->dev, "serial state: %d\n", ctrl_bits);
+ dev->cbits_tolocal = ctrl_bits;
+ break;
+ default:
+ dev_err(&port->dev, "%s: unknown notification %d received:"
+ "index %d len %d data0 %d data1 %d",
+ __func__, ctrl->bNotificationType, ctrl->wIndex,
+ ctrl->wLength, data[0], data[1]);
+ }
+
+resubmit_int_urb:
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&port->dev, "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
+
+}
+
+static int csvt_ctrl_open(struct tty_struct *tty,
+ struct usb_serial_port *port)
+{
+ int retval;
+
+ dev_dbg(&port->dev, "%s port %d", __func__, port->number);
+
+ retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
+ return retval;
+ }
+
+ retval = usb_serial_generic_open(tty, port);
+ if (retval)
+ usb_kill_urb(port->interrupt_in_urb);
+
+ return retval;
+}
+
+static void csvt_ctrl_close(struct usb_serial_port *port)
+{
+ dev_dbg(&port->dev, "%s port %d", __func__, port->number);
+
+ usb_serial_generic_close(port);
+ usb_kill_urb(port->interrupt_in_urb);
+}
+
+static int csvt_ctrl_attach(struct usb_serial *serial)
+{
+ struct csvt_ctrl_dev *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ mutex_init(&dev->dev_lock);
+ usb_set_serial_port_data(serial->port[0], dev);
+
+ return 0;
+}
+
+static void csvt_ctrl_release(struct usb_serial *serial)
+{
+ struct usb_serial_port *port = serial->port[0];
+ struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
+
+ dev_dbg(&port->dev, "%s", __func__);
+
+ kfree(dev);
+ usb_set_serial_port_data(port, NULL);
+}
+
+static struct usb_serial_driver csvt_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "qc_csvt",
+ },
+ .description = "qc_csvt",
+ .id_table = id_table,
+ .usb_driver = &csvt_driver,
+ .num_ports = 1,
+ .open = csvt_ctrl_open,
+ .close = csvt_ctrl_close,
+ .probe = csvt_probe,
+ .dtr_rts = csvt_ctrl_dtr_rts,
+ .tiocmget = csvt_ctrl_tiocmget,
+ .tiocmset = csvt_ctrl_tiocmset,
+ .ioctl = csvt_ctrl_ioctl,
+ .set_termios = csvt_ctrl_set_termios,
+ .read_int_callback = csvt_ctrl_int_cb,
+ .attach = csvt_ctrl_attach,
+ .release = csvt_ctrl_release,
+};
+
+static int __init csvt_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&csvt_device);
+ if (retval) {
+ err("%s: usb serial register failed\n", __func__);
+ return retval;
+ }
+
+ retval = usb_register(&csvt_driver);
+ if (retval) {
+ usb_serial_deregister(&csvt_device);
+ err("%s: usb register failed\n", __func__);
+ return retval;
+ }
+
+ return 0;
+}
+
+static void __exit csvt_exit(void)
+{
+ usb_deregister(&csvt_driver);
+ usb_serial_deregister(&csvt_device);
+}
+
+module_init(csvt_init);
+module_exit(csvt_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/adv7520.c b/drivers/video/msm/adv7520.c
index b3b34bb..7386983 100644
--- a/drivers/video/msm/adv7520.c
+++ b/drivers/video/msm/adv7520.c
@@ -874,7 +874,11 @@
} else
DEV_ERR("adv7520_probe: failed to add fb device\n");
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+ external_common_state->sdev.name = "hdmi_as_primary";
+#else
external_common_state->sdev.name = "hdmi";
+#endif
if (switch_dev_register(&external_common_state->sdev) < 0)
DEV_ERR("Hdmi switch registration failed\n");
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index a0665ac..ef357db 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -4062,6 +4062,11 @@
static void hdmi_msm_hpd_off(void)
{
+ if (!hdmi_msm_state->hpd_initialized) {
+ DEV_DBG("%s: HPD is already OFF, returning\n", __func__);
+ return;
+ }
+
DEV_DBG("%s: (timer, clk, 5V, core, IRQ off)\n", __func__);
del_timer(&hdmi_msm_state->hpd_state_timer);
disable_irq(hdmi_msm_state->irq);
@@ -4087,6 +4092,12 @@
static int hdmi_msm_hpd_on(bool trigger_handler)
{
static int phy_reset_done;
+ uint32 hpd_ctrl;
+
+ if (hdmi_msm_state->hpd_initialized) {
+ DEV_DBG("%s: HPD is already ON, returning\n", __func__);
+ return 0;
+ }
hdmi_msm_clk(1);
hdmi_msm_state->pd->core_power(1, 1);
@@ -4104,36 +4115,34 @@
HDMI_OUTP(0x0208, 0x0001001B);
/* Check HPD State */
- if (!hdmi_msm_state->hpd_initialized) {
- uint32 hpd_ctrl;
- enable_irq(hdmi_msm_state->irq);
+ enable_irq(hdmi_msm_state->irq);
- /* set timeout to 4.1ms (max) for hardware debounce */
- hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
+ /* set timeout to 4.1ms (max) for hardware debounce */
+ hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
- /* Toggle HPD circuit to trigger HPD sense */
- HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
- HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
+ /* Toggle HPD circuit to trigger HPD sense */
+ HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
+ HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
- DEV_DBG("%s: (clk, 5V, core, IRQ on) <trigger:%s>\n", __func__,
- trigger_handler ? "true" : "false");
+ DEV_DBG("%s: (clk, 5V, core, IRQ on) <trigger:%s>\n", __func__,
+ trigger_handler ? "true" : "false");
- if (trigger_handler) {
- /* Set HPD state machine: ensure at least 2 readouts */
- mutex_lock(&hdmi_msm_state_mutex);
- hdmi_msm_state->hpd_stable = 0;
- hdmi_msm_state->hpd_prev_state = TRUE;
- mutex_lock(&external_common_state_hpd_mutex);
- external_common_state->hpd_state = FALSE;
- mutex_unlock(&external_common_state_hpd_mutex);
- hdmi_msm_state->hpd_cable_chg_detected = TRUE;
- mutex_unlock(&hdmi_msm_state_mutex);
- mod_timer(&hdmi_msm_state->hpd_state_timer,
- jiffies + HZ/2);
- }
-
- hdmi_msm_state->hpd_initialized = TRUE;
+ if (trigger_handler) {
+ /* Set HPD state machine: ensure at least 2 readouts */
+ mutex_lock(&hdmi_msm_state_mutex);
+ hdmi_msm_state->hpd_stable = 0;
+ hdmi_msm_state->hpd_prev_state = TRUE;
+ mutex_lock(&external_common_state_hpd_mutex);
+ external_common_state->hpd_state = FALSE;
+ mutex_unlock(&external_common_state_hpd_mutex);
+ hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+ mutex_unlock(&hdmi_msm_state_mutex);
+ mod_timer(&hdmi_msm_state->hpd_state_timer,
+ jiffies + HZ/2);
}
+
+ hdmi_msm_state->hpd_initialized = TRUE;
+
hdmi_msm_set_mode(TRUE);
return 0;
@@ -4398,7 +4407,11 @@
queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_read_work);
/* Initialize hdmi node and register with switch driver */
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+ external_common_state->sdev.name = "hdmi_as_primary";
+#else
external_common_state->sdev.name = "hdmi";
+#endif
if (switch_dev_register(&external_common_state->sdev) < 0)
DEV_ERR("Hdmi switch registration failed\n");
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index e43f729..de91ade 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -86,6 +86,9 @@
struct workqueue_struct *mdp_dma_wq; /*mdp dma wq */
struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */
+struct workqueue_struct *mdp_hist_wq; /*mdp histogram wq */
+struct work_struct mdp_histogram_worker;
+
static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
static struct delayed_work mdp_pipe_ctrl_worker;
@@ -142,6 +145,315 @@
static uint32 mdp_prim_panel_type = NO_PANEL;
#ifndef CONFIG_FB_MSM_MDP22
+
+struct list_head mdp_hist_lut_list;
+DEFINE_MUTEX(mdp_hist_lut_list_mutex);
+
+uint32_t mdp_block2base(uint32_t block)
+{
+ uint32_t base = 0x0;
+ switch (block) {
+ case MDP_BLOCK_DMA_P:
+ base = 0x90000;
+ break;
+ case MDP_BLOCK_DMA_S:
+ base = 0xA0000;
+ break;
+ case MDP_BLOCK_VG_1:
+ base = 0x20000;
+ break;
+ case MDP_BLOCK_VG_2:
+ base = 0x30000;
+ break;
+ case MDP_BLOCK_RGB_1:
+ base = 0x40000;
+ break;
+ case MDP_BLOCK_RGB_2:
+ base = 0x50000;
+ break;
+ default:
+ break;
+ }
+ return base;
+}
+
+static uint32_t mdp_pp_block2hist_lut(uint32_t block)
+{
+ uint32_t valid = 0;
+ switch (block) {
+ case MDP_BLOCK_DMA_P:
+ valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+ break;
+ case MDP_BLOCK_DMA_S:
+ valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+ break;
+ case MDP_BLOCK_VG_1:
+ valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+ break;
+ case MDP_BLOCK_VG_2:
+ valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+ return valid;
+}
+
+static void mdp_hist_lut_init_mgmt(struct mdp_hist_lut_mgmt *mgmt,
+ uint32_t block)
+{
+ mutex_init(&mgmt->lock);
+ mgmt->block = block;
+
+ mutex_lock(&mdp_hist_lut_list_mutex);
+ list_add(&mgmt->list, &mdp_hist_lut_list);
+ mutex_unlock(&mdp_hist_lut_list_mutex);
+}
+
+static int mdp_hist_lut_init(void)
+{
+ struct mdp_hist_lut_mgmt *temp;
+ struct list_head *pos, *q;
+ INIT_LIST_HEAD(&mdp_hist_lut_list);
+
+ if (mdp_rev >= MDP_REV_30) {
+ temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit;
+ mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_P);
+ }
+
+ if (mdp_rev >= MDP_REV_40) {
+ temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit_list;
+ mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_1);
+
+ temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit_list;
+ mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_2);
+ }
+
+ if (mdp_rev > MDP_REV_42) {
+ temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit_list;
+ mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_S);
+ }
+ return 0;
+
+exit_list:
+ mutex_lock(&mdp_hist_lut_list_mutex);
+ list_for_each_safe(pos, q, &mdp_hist_lut_list) {
+ temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
+ list_del(pos);
+ kfree(temp);
+ }
+ mutex_unlock(&mdp_hist_lut_list_mutex);
+exit:
+ pr_err("Failed initializing histogram LUT memory\n");
+ return -ENOMEM;
+}
+
+static int mdp_hist_lut_block2mgmt(uint32_t block,
+ struct mdp_hist_lut_mgmt **mgmt)
+{
+ struct mdp_hist_lut_mgmt *temp, *output;
+ int ret = 0;
+
+ output = NULL;
+
+ mutex_lock(&mdp_hist_lut_list_mutex);
+ list_for_each_entry(temp, &mdp_hist_lut_list, list) {
+ if (temp->block == block)
+ output = temp;
+ }
+ mutex_unlock(&mdp_hist_lut_list_mutex);
+
+ if (output == NULL)
+ ret = -EINVAL;
+ else
+ *mgmt = output;
+
+ return ret;
+}
+
+#define MDP_HIST_LUT_SIZE (256)
+static int mdp_hist_lut_write_off(struct mdp_hist_lut_data *data,
+ struct mdp_hist_lut_info *info, uint32_t offset)
+{
+ int i;
+ uint32_t element[MDP_HIST_LUT_SIZE];
+ uint32_t base = mdp_block2base(info->block);
+ uint32_t sel = info->bank_sel;
+
+
+ if (data->len != MDP_HIST_LUT_SIZE) {
+ pr_err("%s: data->len != %d", __func__, MDP_HIST_LUT_SIZE);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&element, data->data,
+ MDP_HIST_LUT_SIZE * sizeof(uint32_t))) {
+ pr_err("%s: Error copying histogram data", __func__);
+ return -ENOMEM;
+ }
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ for (i = 0; i < MDP_HIST_LUT_SIZE; i++)
+ MDP_OUTP(MDP_BASE + base + offset + (0x400*(sel)) + (4*i),
+ element[i]);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ return 0;
+}
+
+static int mdp_hist_lut_write(struct mdp_hist_lut_data *data,
+ struct mdp_hist_lut_info *info)
+{
+ int ret = 0;
+
+ if (data->block != info->block) {
+ ret = -1;
+ pr_err("%s, data/info mdp_block mismatch! %d != %d\n",
+ __func__, data->block, info->block);
+ goto error;
+ }
+
+ switch (data->block) {
+ case MDP_BLOCK_VG_1:
+ case MDP_BLOCK_VG_2:
+ ret = mdp_hist_lut_write_off(data, info, 0x3400);
+ break;
+ case MDP_BLOCK_DMA_P:
+ case MDP_BLOCK_DMA_S:
+ ret = mdp_hist_lut_write_off(data, info, 0x4800);
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+#define MDP_HIST_LUT_VG_EN_MASK (0x20000)
+#define MDP_HIST_LUT_VG_EN_SHIFT (17)
+#define MDP_HIST_LUT_VG_EN_OFFSET (0x0058)
+#define MDP_HIST_LUT_VG_SEL_OFFSET (0x0064)
+static void mdp_hist_lut_commit_vg(struct mdp_hist_lut_info *info)
+{
+ uint32_t out_en, temp_en;
+ uint32_t base = mdp_block2base(info->block);
+ temp_en = (info->is_enabled) ? (1 << MDP_HIST_LUT_VG_EN_SHIFT) : 0x0;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ out_en = inpdw(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET) &
+ ~MDP_HIST_LUT_VG_EN_MASK;
+ MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET, out_en | temp_en);
+
+ if (info->has_sel_update)
+ MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_SEL_OFFSET,
+ info->bank_sel);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+#define MDP_HIST_LUT_DMA_EN_MASK (0x7)
+#define MDP_HIST_LUT_DMA_SEL_MASK (0x400)
+#define MDP_HIST_LUT_DMA_SEL_SHIFT (10)
+#define MDP_HIST_LUT_DMA_P_OFFSET (0x0070)
+#define MDP_HIST_LUT_DMA_S_OFFSET (0x0028)
+static void mdp_hist_lut_commit_dma(struct mdp_hist_lut_info *info)
+{
+ uint32_t out, temp, mask;
+ uint32_t base = mdp_block2base(info->block);
+ uint32_t offset = (info->block == MDP_BLOCK_DMA_P) ?
+ MDP_HIST_LUT_DMA_P_OFFSET : MDP_HIST_LUT_DMA_S_OFFSET;
+
+ mask = MDP_HIST_LUT_DMA_EN_MASK;
+ temp = (info->is_enabled) ? 0x7 : 0x0;
+
+ if (info->has_sel_update) {
+ mask |= MDP_HIST_LUT_DMA_SEL_MASK;
+ temp |= ((info->bank_sel & 0x1) << MDP_HIST_LUT_DMA_SEL_SHIFT);
+ }
+
+ out = inpdw(MDP_BASE + base + offset) & ~mask;
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ MDP_OUTP(MDP_BASE + base + offset, out | temp);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+static void mdp_hist_lut_commit_info(struct mdp_hist_lut_info *info)
+{
+ switch (info->block) {
+ case MDP_BLOCK_VG_1:
+ case MDP_BLOCK_VG_2:
+ mdp_hist_lut_commit_vg(info);
+ break;
+ case MDP_BLOCK_DMA_P:
+ case MDP_BLOCK_DMA_S:
+ mdp_hist_lut_commit_dma(info);
+ break;
+ default:
+ goto error;
+ }
+
+error:
+ return;
+}
+
+static void mdp_hist_lut_update_info(struct mdp_hist_lut_info *info, int ops)
+{
+ info->bank_sel = (ops & 0x8) >> 3;
+ info->is_enabled = (ops & 0x1) ? TRUE : FALSE;
+ info->has_sel_update = (ops & 0x10) ? TRUE : FALSE;
+}
+
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data)
+{
+ struct mdp_hist_lut_mgmt *mgmt = NULL;
+ struct mdp_hist_lut_info info;
+ int ret = 0;
+
+ if (!mdp_pp_block2hist_lut(data->block)) {
+ ret = -ENOTTY;
+ goto error;
+ }
+
+ ret = mdp_hist_lut_block2mgmt(data->block, &mgmt);
+ if (ret)
+ goto error;
+
+ mutex_lock(&mgmt->lock);
+
+ info.block = mgmt->block;
+
+ mdp_hist_lut_update_info(&info, data->ops);
+
+ switch ((data->ops & 0x6) >> 1) {
+ case 0x1:
+ pr_info("%s: histogram LUT read not supported\n", __func__);
+ break;
+ case 0x2:
+ ret = mdp_hist_lut_write(data, &info);
+ if (ret)
+ goto error_lock;
+ break;
+ default:
+ break;
+ }
+
+ mdp_hist_lut_commit_info(&info);
+
+error_lock:
+ mutex_unlock(&mgmt->lock);
+error:
+ return ret;
+}
+
+
DEFINE_MUTEX(mdp_lut_push_sem);
static int mdp_lut_i;
static int mdp_lut_hw_update(struct fb_cmap *cmap)
@@ -211,8 +523,8 @@
}
/*mask off non LUT select bits*/
- out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
- MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | out);
+ out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
+ MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_lut_i = (mdp_lut_i + 1)%2;
@@ -225,9 +537,9 @@
if (mdp_lut_push) {
mutex_lock(&mdp_lut_push_sem);
mdp_lut_push = 0;
- out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
+ out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
MDP_OUTP(MDP_BASE + 0x90070,
- (mdp_lut_push_i << 10) | out);
+ (mdp_lut_push_i << 10) | 0x7 | out);
mutex_unlock(&mdp_lut_push_sem);
}
}
@@ -237,20 +549,112 @@
#ifdef CONFIG_FB_MSM_MDP40
unsigned int mdp_hist_frame_cnt;
-struct completion mdp_hist_comp;
-boolean mdp_is_hist_start = FALSE;
#else
static unsigned int mdp_hist_frame_cnt;
-static struct completion mdp_hist_comp;
-static boolean mdp_is_hist_start = FALSE;
#endif
+struct completion mdp_hist_comp;
static DEFINE_MUTEX(mdp_hist_mutex);
static boolean mdp_is_hist_data = FALSE;
+static boolean mdp_is_hist_start = FALSE;
+boolean mdp_is_hist_valid = FALSE;
+static boolean mdp_is_hist_init = FALSE;
+static uint32 mdp_hist_r[128];
+static uint32 mdp_hist_g[128];
+static uint32 mdp_hist_b[128];
+
+void __mdp_histogram_kickoff()
+{
+ char *mdp_hist_base;
+
+ if (mdp_rev >= MDP_REV_40)
+ mdp_hist_base = MDP_BASE + 0x95000;
+ else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
+ mdp_hist_base = MDP_BASE + 0x94000;
+ else {
+ pr_err("%s(): Unsupported MDP rev. %u\n", __func__, mdp_rev);
+ return ;
+ }
+
+ if (mdp_is_hist_data == TRUE) {
+ MDP_OUTP(mdp_hist_base + 0x004, mdp_hist_frame_cnt);
+ MDP_OUTP(mdp_hist_base, 1);
+ }
+}
+
+void __mdp_histogram_reset()
+{
+ char *mdp_hist_base;
+
+ if (mdp_rev >= MDP_REV_40)
+ mdp_hist_base = MDP_BASE + 0x95000;
+ else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
+ mdp_hist_base = MDP_BASE + 0x94000;
+ else {
+ pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
+ return ;
+ }
+
+ MDP_OUTP(mdp_hist_base + 0x00C, 1);
+}
+
+static void mdp_hist_read_work(struct work_struct *data)
+{
+ char *mdp_hist_base;
+ uint32 r_data_offset = 0x100, g_data_offset = 0x200;
+ uint32 b_data_offset = 0x300;
+ int num_bins, i = 0;
+
+ if (mdp_rev >= MDP_REV_42) {
+ mdp_hist_base = MDP_BASE + 0x95000;
+ r_data_offset = 0x400;
+ g_data_offset = 0x800;
+ b_data_offset = 0xc00;
+ num_bins = 128;
+ } else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_41) {
+ mdp_hist_base = MDP_BASE + 0x95000;
+ num_bins = 32;
+ } else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31) {
+ mdp_hist_base = MDP_BASE + 0x94000;
+ num_bins = 32;
+ } else {
+ pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
+ return ;
+ }
+
+ mutex_lock(&mdp_hist_mutex);
+ if (mdp_is_hist_data == FALSE) {
+ pr_debug("%s, Histogram disabled before read.\n", __func__);
+ goto error;
+ }
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ for (i = 0; i < num_bins; i++) {
+ mdp_hist_r[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
+ mdp_hist_g[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
+ mdp_hist_b[i] = inpdw(mdp_hist_base + b_data_offset + (4*i));
+ }
+
+ __mdp_histogram_kickoff();
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ /* if read was triggered by an underrun, don't wake up readers*/
+ if (mdp_is_hist_valid && mdp_is_hist_init) {
+ complete(&mdp_hist_comp);
+ } else {
+ if (mdp_is_hist_valid == FALSE)
+ mdp_is_hist_valid = TRUE;
+
+ if (mdp_is_hist_init == FALSE)
+ mdp_is_hist_init = TRUE;
+ }
+error:
+ mutex_unlock(&mdp_hist_mutex);
+}
/*should hold mdp_hist_mutex before calling this function*/
int _mdp_histogram_ctrl(boolean en)
{
- unsigned long flag;
unsigned long hist_base;
uint32_t status;
@@ -266,34 +670,40 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_hist_frame_cnt = 1;
mdp_enable_irq(MDP_HISTOGRAM_TERM);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (mdp_rev >= MDP_REV_40) {
- MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
- MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE);
- }
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- MDP_OUTP(MDP_BASE + hist_base + 0x4, mdp_hist_frame_cnt);
- MDP_OUTP(MDP_BASE + hist_base, 1);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ INIT_COMPLETION(mdp_hist_comp);
+
+ /*Clear the interrupts before enabling them*/
+ MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
+ INTR_HIST_RESET_SEQ_DONE);
+ MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
+ MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE |
+ INTR_HIST_RESET_SEQ_DONE);
+
mdp_is_hist_data = TRUE;
+ mdp_is_hist_valid = TRUE;
+ mdp_is_hist_init = FALSE;
+
+ __mdp_histogram_reset();
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
} else {
if (!mdp_is_hist_data)
return -EINVAL;
mdp_is_hist_data = FALSE;
+ mdp_is_hist_valid = FALSE;
+ mdp_is_hist_init = FALSE;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ status = inpdw(MDP_BASE + hist_base + 0x1C);
+ status &= ~(INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+ MDP_OUTP(MDP_BASE + hist_base + 0x1C, status);
+ MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
+ INTR_HIST_RESET_SEQ_DONE);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
complete(&mdp_hist_comp);
- if (mdp_rev >= MDP_REV_40) {
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- status = inpdw(MDP_BASE + hist_base + 0x1C);
- status &= ~INTR_HIST_DONE;
- MDP_OUTP(MDP_BASE + hist_base + 0x1C, status);
-
- MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
- FALSE);
- }
-
mdp_disable_irq(MDP_HISTOGRAM_TERM);
}
@@ -307,6 +717,10 @@
if (mdp_is_hist_start)
ret = _mdp_histogram_ctrl(en);
mutex_unlock(&mdp_hist_mutex);
+
+ if (en == false)
+ flush_workqueue(mdp_hist_wq);
+
return ret;
}
@@ -361,6 +775,10 @@
ret = _mdp_histogram_ctrl(FALSE);
+ mutex_unlock(&mdp_hist_mutex);
+ flush_workqueue(mdp_hist_wq);
+ return ret;
+
mdp_hist_stop_err:
mutex_unlock(&mdp_hist_mutex);
return ret;
@@ -369,55 +787,26 @@
/*call from within mdp_hist_mutex*/
static int _mdp_copy_hist_data(struct mdp_histogram *hist)
{
- char *mdp_hist_base;
- uint32 r_data_offset = 0x100, g_data_offset = 0x200;
- uint32 b_data_offset = 0x300;
int ret = 0;
- if (mdp_rev >= MDP_REV_42) {
- mdp_hist_base = MDP_BASE + 0x95000;
- r_data_offset = 0x400;
- g_data_offset = 0x800;
- b_data_offset = 0xc00;
- } else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_41) {
- mdp_hist_base = MDP_BASE + 0x95000;
- } else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31) {
- mdp_hist_base = MDP_BASE + 0x94000;
- } else {
- pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
- return -EPERM;
- }
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
if (hist->r) {
- ret = copy_to_user(hist->r, mdp_hist_base + r_data_offset,
- hist->bin_cnt * 4);
+ ret = copy_to_user(hist->r, mdp_hist_r, hist->bin_cnt * 4);
if (ret)
goto hist_err;
}
if (hist->g) {
- ret = copy_to_user(hist->g, mdp_hist_base + g_data_offset,
- hist->bin_cnt * 4);
+ ret = copy_to_user(hist->g, mdp_hist_g, hist->bin_cnt * 4);
if (ret)
goto hist_err;
}
if (hist->b) {
- ret = copy_to_user(hist->b, mdp_hist_base + b_data_offset,
- hist->bin_cnt * 4);
+ ret = copy_to_user(hist->b, mdp_hist_b, hist->bin_cnt * 4);
if (ret)
goto hist_err;
}
-
- if (mdp_is_hist_start == TRUE) {
- MDP_OUTP(mdp_hist_base + 0x004,
- mdp_hist_frame_cnt);
- MDP_OUTP(mdp_hist_base, 1);
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return 0;
-
hist_err:
- printk(KERN_ERR "%s: invalid hist buffer\n", __func__);
+ pr_err("%s: invalid hist buffer\n", __func__);
return ret;
}
@@ -435,17 +824,17 @@
mutex_lock(&mdp_hist_mutex);
if (!mdp_is_hist_data) {
- ret = -EINVAL;
- goto error;
- }
-
- if (!mdp_is_hist_start) {
- printk(KERN_ERR "%s histogram not started\n", __func__);
+ pr_err("%s - histogram not ready\n", __func__);
ret = -EPERM;
goto error;
}
- INIT_COMPLETION(mdp_hist_comp);
+ if (!mdp_is_hist_start) {
+ pr_err("%s histogram not started\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+
mdp_hist_frame_cnt = hist->frame_cnt;
mutex_unlock(&mdp_hist_mutex);
@@ -455,8 +844,9 @@
}
mutex_lock(&mdp_hist_mutex);
- if (mdp_is_hist_data)
+ if (mdp_is_hist_data && mdp_is_hist_init)
ret = _mdp_copy_hist_data(hist);
+
error:
mutex_unlock(&mdp_hist_mutex);
return ret;
@@ -818,7 +1208,7 @@
#ifndef CONFIG_FB_MSM_MDP40
irqreturn_t mdp_isr(int irq, void *ptr)
{
- uint32 mdp_interrupt = 0;
+ uint32 hist_interrupt, mdp_interrupt = 0;
struct mdp_dma_data *dma;
unsigned long flag;
@@ -853,24 +1243,34 @@
}
#ifndef CONFIG_FB_MSM_MDP22
if (mdp_interrupt & MDP_HIST_DONE) {
+ hist_interrupt = inp32(MDP_DMA_P_HIST_INTR_STATUS);
outp32(MDP_BASE + 0x94018, 0x3);
outp32(MDP_INTR_CLEAR, MDP_HIST_DONE);
- complete(&mdp_hist_comp);
+ if (hist_interrupt & INTR_HIST_RESET_SEQ_DONE)
+ __mdp_histogram_kickoff();
+
+ if (hist_interrupt & INTR_HIST_DONE) {
+ if (waitqueue_active(&mdp_hist_comp.wait)) {
+ if (!queue_work(mdp_hist_wq,
+ &mdp_histogram_worker)) {
+ pr_err("%s: can't queue hist_read\n",
+ __func__);
+ }
+ } else
+ __mdp_histogram_reset();
+ }
}
/* LCDC UnderFlow */
if (mdp_interrupt & LCDC_UNDERFLOW) {
mdp_lcdc_underflow_cnt++;
/*when underflow happens HW resets all the histogram
- registers that were set before so restore them back
- to normal.*/
+ registers that were set before so restore them back
+ to normal.*/
MDP_OUTP(MDP_BASE + 0x94010, 1);
- MDP_OUTP(MDP_BASE + 0x9401c, 2);
- if (mdp_is_hist_start == TRUE) {
- MDP_OUTP(MDP_BASE + 0x94004,
- mdp_hist_frame_cnt);
- MDP_OUTP(MDP_BASE + 0x94000, 1);
- }
+ MDP_OUTP(MDP_BASE + 0x9401c, INTR_HIST_DONE);
+ mdp_is_hist_valid = FALSE;
+ __mdp_histogram_reset();
}
/* LCDC Frame Start */
@@ -969,6 +1369,8 @@
spin_lock_init(&mdp_spin_lock);
mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
+ mdp_hist_wq = create_singlethread_workqueue("mdp_hist_wq");
+ INIT_WORK(&mdp_histogram_worker, mdp_hist_read_work);
mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
mdp_pipe_ctrl_workqueue_handler);
@@ -1009,8 +1411,6 @@
mutex_init(&dma_wb_data.ov_mutex);
#endif
-
-
#ifndef CONFIG_FB_MSM_MDP22
init_completion(&mdp_hist_comp);
#endif
@@ -1128,7 +1528,6 @@
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
#endif
- mdp_histogram_ctrl(TRUE);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
ret = panel_next_on(pdev);
@@ -1141,6 +1540,7 @@
mdp4_mddi_overlay_restore();
#endif
+ mdp_histogram_ctrl(TRUE);
return ret;
}
@@ -1444,6 +1844,9 @@
mfd->ov0_blt_state = 0;
mfd->use_ov0_blt = 0 ;
+ /* initialize Post Processing data*/
+ mdp_hist_lut_init();
+
/* add panel data */
if (platform_device_add_data
(msm_fb_dev, pdev->dev.platform_data,
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 35a1453..6c5a9f9 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,6 +44,10 @@
extern int mdp_rev;
extern struct mdp_csc_cfg mdp_csc_convert[4];
+extern struct workqueue_struct *mdp_hist_wq;
+extern struct work_struct mdp_histogram_worker;
+extern boolean mdp_is_hist_valid;
+
#define MDP4_REVISION_V1 0
#define MDP4_REVISION_V2 1
#define MDP4_REVISION_V2_1 2
@@ -221,6 +225,20 @@
struct completion dmap_comp;
};
+extern struct list_head mdp_hist_lut_list;
+extern struct mutex mdp_hist_lut_list_mutex;
+struct mdp_hist_lut_mgmt {
+ uint32_t block;
+ struct mutex lock;
+ struct list_head list;
+};
+
+struct mdp_hist_lut_info {
+ uint32_t block;
+ boolean is_enabled, has_sel_update;
+ int bank_sel;
+};
+
#define MDP_CMD_DEBUG_ACCESS_BASE (MDP_BASE+0x10000)
#define MDP_DMA2_TERM 0x1
@@ -606,6 +624,10 @@
#define MDP_EBI2_LCD0 (msm_mdp_base + 0x003c)
#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0040)
#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x005c)
+
+#define MDP_DMA_P_HIST_INTR_STATUS (msm_mdp_base + 0x94014)
+#define MDP_DMA_P_HIST_INTR_CLEAR (msm_mdp_base + 0x94018)
+#define MDP_DMA_P_HIST_INTR_ENABLE (msm_mdp_base + 0x9401C)
#endif
#define MDP_FULL_BYPASS_WORD43 (msm_mdp_base + 0x101ac)
@@ -733,6 +755,8 @@
int mdp_start_histogram(struct fb_info *info);
int mdp_stop_histogram(struct fb_info *info);
int mdp_histogram_ctrl(boolean en);
+void __mdp_histogram_kickoff(void);
+void __mdp_histogram_reset(void);
void mdp_footswitch_ctrl(boolean on);
#ifdef CONFIG_FB_MSM_MDP303
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 155bc54..f7f48e4 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -20,7 +20,6 @@
extern struct mdp_dma_data dma_wb_data;
extern unsigned int mdp_hist_frame_cnt;
extern struct completion mdp_hist_comp;
-extern boolean mdp_is_hist_start;
extern boolean mdp_is_in_isr;
extern uint32 mdp_intr_mask;
extern spinlock_t mdp_spin_lock;
@@ -708,14 +707,20 @@
int mdp4_writeback_init(struct fb_info *info);
int mdp4_writeback_terminate(struct fb_info *info);
+uint32_t mdp_block2base(uint32_t block);
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data);
+
void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl);
void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe);
int mdp4_csc_config(struct mdp_csc_cfg_data *config);
void mdp4_csc_write(struct mdp_csc_cfg *data, uint32_t base);
int mdp4_csc_enable(struct mdp_csc_cfg_data *config);
+int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr);
+int mdp4_pgc_cfg(struct mdp_pgc_lut_data *pgc_ptr);
u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 4f8be7e..4c89629 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -277,6 +277,7 @@
void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc)
{
uint32 dma2_cfg_reg;
+ uint32 mask, curr;
dma2_cfg_reg = DMA_DITHER_EN;
#ifdef BLT_RGB565
@@ -309,6 +310,9 @@
#endif
/* dma2 config register */
+ curr = inpdw(MDP_BASE + 0x90000);
+ mask = 0xBFFFFFFF;
+ dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -442,6 +446,7 @@
char *rgb_base;
uint32 src_size, src_xy, dst_size, dst_xy;
uint32 format, pattern;
+ uint32 curr, mask;
uint32 offset = 0;
int pnum;
@@ -473,6 +478,12 @@
mdp4_scale_setup(pipe);
+ /* Ensure proper covert matrix loaded when color space swaps */
+ curr = inpdw(rgb_base + 0x0058);
+ /* Don't touch bits you don't want to configure*/
+ mask = 0xFFFEFFFF;
+ pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */
@@ -558,7 +569,7 @@
char *vg_base;
uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
uint32 format, pattern, luma_offset, chroma_offset;
- uint32 mask, curr;
+ uint32 mask, curr, addr;
int pnum, ptype;
pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -625,13 +636,20 @@
/* Ensure proper covert matrix loaded when color space swaps */
curr = inpdw(vg_base + 0x0058);
mask = 0x600;
+
if ((curr & mask) != (pipe->op_mode & mask)) {
- curr = ((uint32_t)vg_base) + 0x4000;
+ addr = ((uint32_t)vg_base) + 0x4000;
if (ptype != OVERLAY_TYPE_RGB)
- mdp4_csc_write(&(mdp_csc_convert[1]), curr);
+ mdp4_csc_write(&(mdp_csc_convert[1]), addr);
else
- mdp4_csc_write(&(mdp_csc_convert[0]), curr);
+ mdp4_csc_write(&(mdp_csc_convert[0]), addr);
+
+ mask = 0xFFFCFFFF;
+ } else {
+ /* Don't touch bits you don't want to configure*/
+ mask = 0xFFFCF1FF;
}
+ pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
/* luma component plane */
outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset);
@@ -1304,6 +1322,11 @@
u32 data = 0, stage, flush_bits = 0, pipe_cnt = 0, pull_mode = 0;
u32 cfg[MDP4_MIXER_MAX];
+ if (mixer == MDP4_MIXER0)
+ flush_bits |= 0x1;
+ else if (mixer == MDP4_MIXER1)
+ flush_bits |= 0x2;
+
for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++) {
cfg[i] = 0;
for (j = MDP4_MIXER_STAGE_BASE; j < MDP4_MIXER_STAGE_MAX; j++) {
@@ -2032,7 +2055,8 @@
}
}
-static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req)
+static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
+ struct msm_fb_data_type *mfd)
{
int is_fg;
@@ -2056,9 +2080,18 @@
return OVERLAY_PERF_LEVEL1;
if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE)
- return OVERLAY_PERF_LEVEL3;
- else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE)
- return OVERLAY_PERF_LEVEL2;
+ return OVERLAY_PERF_LEVEL4;
+ else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) {
+ u32 max, min;
+ max = (req->dst_rect.h > req->dst_rect.w) ?
+ req->dst_rect.h : req->dst_rect.w;
+ min = (mfd->panel_info.yres > mfd->panel_info.xres) ?
+ mfd->panel_info.xres : mfd->panel_info.yres;
+ if (max > min) /* landscape mode */
+ return OVERLAY_PERF_LEVEL3;
+ else /* potrait mode */
+ return OVERLAY_PERF_LEVEL2;
+ }
else
return OVERLAY_PERF_LEVEL1;
}
@@ -2164,7 +2197,7 @@
return -EINTR;
}
- perf_level = mdp4_overlay_get_perf_level(req);
+ perf_level = mdp4_overlay_get_perf_level(req, mfd);
mixer = mfd->panel_info.pdest; /* DISPLAY_1 or DISPLAY_2 */
@@ -2311,6 +2344,11 @@
if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
if (mfd->panel_power_on)
mdp4_dsi_cmd_overlay_restore();
+ } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+ if (mfd->panel_power_on)
+ mdp4_overlay_dsi_video_vsync_push(mfd,
+ pipe);
}
#else
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
@@ -2321,6 +2359,11 @@
mdp4_mddi_overlay_restore();
}
#endif
+ else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+ if (mfd->panel_power_on)
+ mdp4_overlay_lcdc_vsync_push(mfd, pipe);
+ }
mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
mdp4_overlay_update_blt_mode(mfd);
if (!mfd->use_ov0_blt)
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 590ad65..635b104 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -369,6 +369,9 @@
{
int result = 0;
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+ mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+
if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE &&
pipe->pipe_type == OVERLAY_TYPE_RGB) {
result = mdp4_dtv_stop(mfd);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index d82672e..b69a2fc 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -24,6 +24,7 @@
#include <linux/debugfs.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
+#include <linux/msm_mdp.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
@@ -295,12 +296,6 @@
bits = mdp_intr_mask;
outpdw(MDP_BASE + 0x0050, bits);/* enable specififed interrupts */
- /* histogram */
- MDP_OUTP(MDP_BASE + 0x95010, 1); /* auto clear HIST */
-
- /* enable histogram interrupts */
- outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
-
/* For the max read pending cmd config below, if the MDP clock */
/* is less than the AXI clock, then we must use 3 pending */
/* pending requests. Otherwise, we should use 8 pending requests. */
@@ -385,11 +380,8 @@
that histogram works.*/
MDP_OUTP(MDP_BASE + 0x95010, 1);
outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
- if (mdp_is_hist_start == TRUE) {
- MDP_OUTP(MDP_BASE + 0x95004,
- mdp_hist_frame_cnt);
- MDP_OUTP(MDP_BASE + 0x95000, 1);
- }
+ mdp_is_hist_valid = FALSE;
+ __mdp_histogram_reset();
}
if (isr & INTR_EXTERNAL_INTF_UDERRUN)
@@ -568,16 +560,18 @@
outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr);
mb();
isr &= mask;
+ if (isr & INTR_HIST_RESET_SEQ_DONE)
+ __mdp_histogram_kickoff();
+
if (isr & INTR_HIST_DONE) {
- if (waitqueue_active(&(mdp_hist_comp.wait))) {
- complete(&mdp_hist_comp);
- } else {
- if (mdp_is_hist_start == TRUE) {
- MDP_OUTP(MDP_BASE + 0x95004,
- mdp_hist_frame_cnt);
- MDP_OUTP(MDP_BASE + 0x95000, 1);
+ if (waitqueue_active(&mdp_hist_comp.wait)) {
+ if (!queue_work(mdp_hist_wq,
+ &mdp_histogram_worker)) {
+ pr_err("%s - can't queue hist_read\n",
+ __func__);
}
- }
+ } else
+ __mdp_histogram_reset();
}
}
@@ -2617,3 +2611,522 @@
}
buf->phys_addr = 0;
}
+
+static int mdp4_update_pcc_regs(uint32_t offset,
+ struct mdp_pcc_cfg_data *cfg_ptr)
+{
+ int ret = -1;
+
+ if (offset && cfg_ptr) {
+
+ outpdw(offset, cfg_ptr->r.c);
+ outpdw(offset + 0x30, cfg_ptr->g.c);
+ outpdw(offset + 0x60, cfg_ptr->b.c);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.r);
+ outpdw(offset + 0x30, cfg_ptr->g.r);
+ outpdw(offset + 0x60, cfg_ptr->b.r);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.g);
+ outpdw(offset + 0x30, cfg_ptr->g.g);
+ outpdw(offset + 0x60, cfg_ptr->b.g);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.b);
+ outpdw(offset + 0x30, cfg_ptr->g.b);
+ outpdw(offset + 0x60, cfg_ptr->b.b);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.rr);
+ outpdw(offset + 0x30, cfg_ptr->g.rr);
+ outpdw(offset + 0x60, cfg_ptr->b.rr);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.gg);
+ outpdw(offset + 0x30, cfg_ptr->g.gg);
+ outpdw(offset + 0x60, cfg_ptr->b.gg);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.bb);
+ outpdw(offset + 0x30, cfg_ptr->g.bb);
+ outpdw(offset + 0x60, cfg_ptr->b.bb);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.rg);
+ outpdw(offset + 0x30, cfg_ptr->g.rg);
+ outpdw(offset + 0x60, cfg_ptr->b.rg);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.gb);
+ outpdw(offset + 0x30, cfg_ptr->g.gb);
+ outpdw(offset + 0x60, cfg_ptr->b.gb);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.rb);
+ outpdw(offset + 0x30, cfg_ptr->g.rb);
+ outpdw(offset + 0x60, cfg_ptr->b.rb);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.rgb_0);
+ outpdw(offset + 0x30, cfg_ptr->g.rgb_0);
+ outpdw(offset + 0x60, cfg_ptr->b.rgb_0);
+ offset += 4;
+
+ outpdw(offset, cfg_ptr->r.rgb_1);
+ outpdw(offset + 0x30, cfg_ptr->g.rgb_1);
+ outpdw(offset + 0x60, cfg_ptr->b.rgb_1);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int mdp4_read_pcc_regs(uint32_t offset,
+ struct mdp_pcc_cfg_data *cfg_ptr)
+{
+ int ret = -1;
+
+ if (offset && cfg_ptr) {
+ cfg_ptr->r.c = inpdw(offset);
+ cfg_ptr->g.c = inpdw(offset + 0x30);
+ cfg_ptr->b.c = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.r = inpdw(offset);
+ cfg_ptr->g.r = inpdw(offset + 0x30);
+ cfg_ptr->b.r = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.g = inpdw(offset);
+ cfg_ptr->g.g = inpdw(offset + 0x30);
+ cfg_ptr->b.g = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.b = inpdw(offset);
+ cfg_ptr->g.b = inpdw(offset + 0x30);
+ cfg_ptr->b.b = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.rr = inpdw(offset);
+ cfg_ptr->g.rr = inpdw(offset + 0x30);
+ cfg_ptr->b.rr = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.gg = inpdw(offset);
+ cfg_ptr->g.gg = inpdw(offset + 0x30);
+ cfg_ptr->b.gg = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.bb = inpdw(offset);
+ cfg_ptr->g.bb = inpdw(offset + 0x30);
+ cfg_ptr->b.bb = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.rg = inpdw(offset);
+ cfg_ptr->g.rg = inpdw(offset + 0x30);
+ cfg_ptr->b.rg = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.gb = inpdw(offset);
+ cfg_ptr->g.gb = inpdw(offset + 0x30);
+ cfg_ptr->b.gb = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.rb = inpdw(offset);
+ cfg_ptr->g.rb = inpdw(offset + 0x30);
+ cfg_ptr->b.rb = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.rgb_0 = inpdw(offset);
+ cfg_ptr->g.rgb_0 = inpdw(offset + 0x30);
+ cfg_ptr->b.rgb_0 = inpdw(offset + 0x60);
+ offset += 4;
+
+ cfg_ptr->r.rgb_1 = inpdw(offset);
+ cfg_ptr->g.rgb_1 = inpdw(offset + 0x30);
+ cfg_ptr->b.rgb_1 = inpdw(offset + 0x60);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+#define MDP_DMA_P_BASE 0x90000
+#define MDP_DMA_S_BASE 0xA0000
+
+#define MDP_PCC_OFFSET 0xA000
+
+#define MDP_DMA_P_OP_MODE_OFFSET 0x70
+#define MDP_DMA_S_OP_MODE_OFFSET 0x28
+
+
+#define DMA_PCC_R2_OFFSET 0x100
+
+int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr)
+{
+ int ret = -1;
+ uint32_t pcc_offset = 0, mdp_cfg_offset = 0;
+ uint32_t mdp_dma_op_mode = 0;
+
+ switch (cfg_ptr->block) {
+ case MDP_BLOCK_DMA_P:
+ pcc_offset = (uint32_t) (MDP_BASE + MDP_DMA_P_BASE \
+ + MDP_PCC_OFFSET);
+ mdp_cfg_offset = (uint32_t)(MDP_BASE + MDP_DMA_P_BASE);
+ mdp_dma_op_mode = (uint32_t)(MDP_BASE + MDP_DMA_P_BASE \
+ + MDP_DMA_P_OP_MODE_OFFSET);
+ break;
+
+ case MDP_BLOCK_DMA_S:
+ pcc_offset = (uint32_t)(MDP_BASE + MDP_DMA_S_BASE \
+ + MDP_PCC_OFFSET);
+ mdp_cfg_offset = (uint32_t)(MDP_BASE + MDP_DMA_S_BASE);
+ mdp_dma_op_mode = (uint32_t)(MDP_BASE + MDP_DMA_S_BASE \
+ + MDP_DMA_S_OP_MODE_OFFSET);
+ break;
+
+ default:
+ break;
+ }
+
+ if (0x8 & cfg_ptr->ops)
+ pcc_offset += DMA_PCC_R2_OFFSET;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ switch ((0x6 & cfg_ptr->ops)>>1) {
+ case 0x1:
+ ret = mdp4_read_pcc_regs(pcc_offset, cfg_ptr);
+ break;
+
+ case 0x2:
+ ret = mdp4_update_pcc_regs(pcc_offset, cfg_ptr);
+ break;
+
+ default:
+ break;
+ }
+
+ if (0x8 & cfg_ptr->ops)
+ outpdw(mdp_dma_op_mode,
+ (inpdw(mdp_dma_op_mode)|((0x8&cfg_ptr->ops)<<10)));
+
+ outpdw(mdp_cfg_offset,
+ (inpdw(mdp_cfg_offset)|((cfg_ptr->ops&0x1)<<29)));
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ return ret;
+}
+
+#define MDP_DMA_GC_OFFSET 0x8800
+
+#define MDP_LM_0_BASE 0x10004
+#define MDP_LM_1_BASE 0x18004
+#define MDP_LM_GC_OFFSET 0x47ec
+
+#define MDP_LM_OP_MODE_OFFSET 0x10
+
+#define MDP_DMA_P_CONFIG_OFFSET MDP_DMA_P_BASE
+#define MDP_DMA_S_CONFIG_OFFSET MDP_DMA_S_BASE
+#define MDP_LM_0_OP_MODE_OFFSET (MDP_LM_0_BASE + MDP_LM_OP_MODE_OFFSET)
+#define MDP_LM_1_OP_MODE_OFFSET (MDP_LM_1_BASE + MDP_LM_OP_MODE_OFFSET)
+
+#define MDP_GC_COLOR_OFFSET 0x100
+#define MDP_GC_PARMS_OFFSET 0x80
+
+#define MDP_AR_GC_MAX_STAGES 16
+
+static int update_ar_gc_lut(uint32_t *offset, struct mdp_pgc_lut_data *lut_data)
+{
+ int ret = -1, count = 0;
+
+ uint32_t *c0_offset = offset;
+ uint32_t *c0_params_offset = (uint32_t *)((uint32_t)c0_offset
+ + MDP_GC_PARMS_OFFSET);
+
+ uint32_t *c1_offset = (uint32_t *)((uint32_t)offset
+ + MDP_GC_COLOR_OFFSET);
+
+ uint32_t *c1_params_offset = (uint32_t *)((uint32_t)c1_offset
+ + MDP_GC_PARMS_OFFSET);
+
+ uint32_t *c2_offset = (uint32_t *)((uint32_t)offset
+ + 2*MDP_GC_COLOR_OFFSET);
+
+ uint32_t *c2_params_offset = (uint32_t *)((uint32_t)c2_offset
+ +MDP_GC_PARMS_OFFSET);
+
+
+ for (count = 0; count < MDP_AR_GC_MAX_STAGES; count++) {
+ if (count < lut_data->num_r_stages) {
+ outpdw(c0_offset+count,
+ ((0xfff & lut_data->r_data[count].x_start)
+ | 0x10000));
+
+ outpdw(c0_params_offset+count,
+ ((0x7fff & lut_data->r_data[count].slope)
+ | ((0xffff
+ & lut_data->r_data[count].offset)
+ << 16)));
+ } else
+ outpdw(c0_offset+count, 0);
+
+ if (count < lut_data->num_b_stages) {
+ outpdw(c1_offset+count,
+ ((0xfff & lut_data->b_data[count].x_start)
+ | 0x10000));
+
+ outpdw(c1_params_offset+count,
+ ((0x7fff & lut_data->b_data[count].slope)
+ | ((0xffff
+ & lut_data->b_data[count].offset)
+ << 16)));
+ } else
+ outpdw(c1_offset+count, 0);
+
+ if (count < lut_data->num_g_stages) {
+ outpdw(c2_offset+count,
+ ((0xfff & lut_data->g_data[count].x_start)
+ | 0x10000));
+
+ outpdw(c2_params_offset+count,
+ ((0x7fff & lut_data->g_data[count].slope)
+ | ((0xffff
+ & lut_data->g_data[count].offset)
+ << 16)));
+ } else
+ outpdw(c2_offset+count, 0);
+ }
+
+ ret = 0;
+
+ return ret;
+}
+
+int mdp4_pgc_cfg(struct mdp_pgc_lut_data *pgc_ptr)
+{
+ int ret = 0;
+ uint32_t *offset = 0, *pgc_enable_offset = 0, lshift_bits = 0;
+ struct mdp_ar_gc_lut_data r[MDP_AR_GC_MAX_STAGES];
+ struct mdp_ar_gc_lut_data g[MDP_AR_GC_MAX_STAGES];
+ struct mdp_ar_gc_lut_data b[MDP_AR_GC_MAX_STAGES];
+
+ ret = copy_from_user(&r[0], pgc_ptr->r_data,
+ pgc_ptr->num_r_stages*sizeof(struct mdp_ar_gc_lut_data));
+ if (!ret) {
+ ret = copy_from_user(&g[0],
+ pgc_ptr->g_data,
+ pgc_ptr->num_g_stages
+ * sizeof(struct mdp_ar_gc_lut_data));
+ if (!ret)
+ ret = copy_from_user(&b[0],
+ pgc_ptr->b_data,
+ pgc_ptr->num_b_stages
+ * sizeof(struct mdp_ar_gc_lut_data));
+ }
+
+ if (ret)
+ return ret;
+
+ pgc_ptr->r_data = &r[0];
+ pgc_ptr->g_data = &g[0];
+ pgc_ptr->b_data = &b[0];
+
+ switch (pgc_ptr->block) {
+ case MDP_BLOCK_DMA_P:
+ offset = (uint32_t *)(MDP_BASE + MDP_DMA_P_BASE
+ + MDP_DMA_GC_OFFSET);
+ pgc_enable_offset = (uint32_t *)(MDP_BASE
+ + MDP_DMA_P_CONFIG_OFFSET);
+ lshift_bits = 28;
+ break;
+
+ case MDP_BLOCK_DMA_S:
+ offset = (uint32_t *)(MDP_BASE + MDP_DMA_S_BASE
+ + MDP_DMA_GC_OFFSET);
+ pgc_enable_offset = (uint32_t *)(MDP_BASE
+ + MDP_DMA_S_CONFIG_OFFSET);
+ lshift_bits = 28;
+ break;
+
+ case MDP_BLOCK_OVERLAY_0:
+ offset = (uint32_t *)(MDP_BASE + MDP_LM_0_BASE
+ + MDP_LM_GC_OFFSET);
+ pgc_enable_offset = (uint32_t *)(MDP_BASE
+ + MDP_LM_0_OP_MODE_OFFSET);
+ lshift_bits = 2;
+ break;
+
+ case MDP_BLOCK_OVERLAY_1:
+ offset = (uint32_t *)(MDP_BASE + MDP_LM_1_BASE
+ + MDP_LM_GC_OFFSET);
+ pgc_enable_offset = (uint32_t *)(MDP_BASE
+ + MDP_LM_0_OP_MODE_OFFSET);
+ lshift_bits = 2;
+ break;
+
+ default:
+ ret = -1;
+ break;
+ }
+
+ if (!ret) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ ret = update_ar_gc_lut(offset, pgc_ptr);
+ if (!ret)
+ outpdw(pgc_enable_offset, (inpdw(pgc_enable_offset)
+ |(1<<lshift_bits)));
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ }
+
+ return ret;
+}
+
+static uint32_t mdp4_pp_block2igc(uint32_t block)
+{
+ uint32_t valid = 0;
+ switch (block) {
+ case MDP_BLOCK_VG_1:
+ valid = 0x1;
+ break;
+ case MDP_BLOCK_VG_2:
+ valid = 0x1;
+ break;
+ case MDP_BLOCK_RGB_1:
+ valid = 0x1;
+ break;
+ case MDP_BLOCK_RGB_2:
+ valid = 0x1;
+ break;
+ case MDP_BLOCK_DMA_P:
+ valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+ break;
+ case MDP_BLOCK_DMA_S:
+ valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+ return valid;
+}
+
+static int mdp4_igc_lut_write(struct mdp_igc_lut_data *cfg, uint32_t en_off,
+ uint32_t lut_off)
+{
+ int i;
+ uint32_t base, *off_low, *off_high;
+ uint32_t low[cfg->len];
+ uint32_t high[cfg->len];
+
+ base = mdp_block2base(cfg->block);
+
+ if (cfg->len != 256)
+ return -EINVAL;
+
+ off_low = (uint32_t *)(MDP_BASE + base + lut_off);
+ off_high = (uint32_t *)(MDP_BASE + base + lut_off + 0x800);
+ if (copy_from_user(&low, cfg->c0_c1_data, cfg->len * sizeof(uint32_t)))
+ return -EFAULT;
+ if (copy_from_user(&high, cfg->c2_data, cfg->len * sizeof(uint32_t)))
+ return -EFAULT;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ for (i = 0; i < cfg->len; i++) {
+ MDP_OUTP(off_low++, low[i]);
+ /*low address write should occur before high address write*/
+ wmb();
+ MDP_OUTP(off_high++, high[i]);
+ }
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ return 0;
+}
+
+static int mdp4_igc_lut_ctrl(struct mdp_igc_lut_data *cfg)
+{
+ uint32_t mask, out;
+ uint32_t base = mdp_block2base(cfg->block);
+ int8_t shift = 0;
+
+ switch (cfg->block) {
+ case MDP_BLOCK_DMA_P:
+ case MDP_BLOCK_DMA_S:
+ base = base;
+ shift = 30;
+ break;
+ case MDP_BLOCK_VG_1:
+ case MDP_BLOCK_VG_2:
+ case MDP_BLOCK_RGB_1:
+ case MDP_BLOCK_RGB_2:
+ base += 0x58;
+ shift = 16;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ out = 1<<shift;
+ mask = ~out;
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ out = inpdw(MDP_BASE + base) & mask;
+ MDP_OUTP(MDP_BASE + base, out | ((cfg->ops & 0x1)<<shift));
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ return 0;
+}
+
+static int mdp4_igc_lut_write_cfg(struct mdp_igc_lut_data *cfg)
+{
+ int ret = 0;
+
+ switch (cfg->block) {
+ case MDP_BLOCK_DMA_P:
+ case MDP_BLOCK_DMA_S:
+ ret = mdp4_igc_lut_write(cfg, 0x00, 0x9000);
+ break;
+ case MDP_BLOCK_VG_1:
+ case MDP_BLOCK_VG_2:
+ case MDP_BLOCK_RGB_1:
+ case MDP_BLOCK_RGB_2:
+ ret = mdp4_igc_lut_write(cfg, 0x58, 0x5000);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg)
+{
+ int ret = 0;
+
+ if (!mdp4_pp_block2igc(cfg->block)) {
+ ret = -ENOTTY;
+ goto error;
+ }
+
+ switch ((cfg->ops & 0x6) >> 1) {
+ case 0x1:
+ pr_info("%s: IGC LUT read not supported\n", __func__);
+ break;
+ case 0x2:
+ ret = mdp4_igc_lut_write_cfg(cfg);
+ if (ret)
+ goto error;
+ break;
+ default:
+ break;
+ }
+
+ ret = mdp4_igc_lut_ctrl(cfg);
+
+error:
+ return ret;
+}
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 0e76a07..3c89d8b 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -75,6 +75,7 @@
struct msm_fb_data_type *mfd;
struct msm_panel_info *panel_info;
int ret;
+ uint32 mask, curr;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
panel_info = &mfd->panel_info;
@@ -163,6 +164,9 @@
MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x10, 0);
/* dma config */
+ curr = inpdw(MDP_BASE + 0x90000);
+ mask = 0xBFFFFFFF;
+ dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
MDP_OUTP(MDP_BASE + DMA_P_BASE, dma2_cfg_reg);
/*
diff --git a/drivers/video/msm/mdp_hw_init.c b/drivers/video/msm/mdp_hw_init.c
index 8f8b4d3..ff3ad41 100644
--- a/drivers/video/msm/mdp_hw_init.c
+++ b/drivers/video/msm/mdp_hw_init.c
@@ -635,8 +635,6 @@
MDP_OUTP(MDP_BASE + 0xE0000, 0);
MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
MDP_OUTP(MDP_BASE + 0x90070, 0);
- MDP_OUTP(MDP_BASE + 0x94010, 1);
- MDP_OUTP(MDP_BASE + 0x9401c, 2);
#endif
/*
diff --git a/drivers/video/msm/mipi_chimei_wuxga.c b/drivers/video/msm/mipi_chimei_wuxga.c
index c63df46..7abb0d4 100644
--- a/drivers/video/msm/mipi_chimei_wuxga.c
+++ b/drivers/video/msm/mipi_chimei_wuxga.c
@@ -55,12 +55,12 @@
/* DSIPHY_TIMING_CTRL */
.timing = { 0xC9, 0x92, 0x29, /* panel specific */
0, /* DSIPHY_TIMING_CTRL_3 = 0 */
- 0x2E, 0x9B, 0x2C, 0x94, 0x2E, 0x03, 0x04}, /* panel specific */
+ 0x2D, 0x9B, 0x2B, 0x94, 0x2D, 0x03, 0x04}, /* panel specific */
/* DSIPHY_PLL_CTRL */
.pll = { 0x00, /* common 8960 */
/* VCO */
- 0x32, (0x01 | 0x30) , (0x19 | 0xC0), /* panel specific */
+ 0x30, (0x01 | 0x30) , (0x19 | 0xC0), /* panel specific */
0x00, 0x50, 0x48, 0x63,
0x77, 0x88, 0x99, /* Auto update by dsi-mipi driver */
0x00, 0x14, 0x03, 0x00, 0x02, /* common 8960 */
@@ -104,19 +104,19 @@
* LVDS-CLK = DSI-CLK/4 , 320 MHZ/4= 80 MHZ.
*/
- pinfo->clk_rate = 640 * MHZ ; /* bitclk Calculated */
+ pinfo->clk_rate = 635 * MHZ ; /* bitclk Calculated */
/*
* this panel is operated by DE,
* vsycn and hsync are ignored
*/
- pinfo->lcdc.h_front_porch = 16; /* thfp */
- pinfo->lcdc.h_back_porch = 160; /* thb */
+ pinfo->lcdc.h_front_porch = 160-48-32; /* thfp */
+ pinfo->lcdc.h_back_porch = 48; /* thb */
pinfo->lcdc.h_pulse_width = 32; /* thpw */
- pinfo->lcdc.v_front_porch = 0; /* tvfp */
- pinfo->lcdc.v_back_porch = 26; /* tvb */
+ pinfo->lcdc.v_front_porch = 26-3-6; /* tvfp */
+ pinfo->lcdc.v_back_porch = 3; /* tvb */
pinfo->lcdc.v_pulse_width = 6; /* tvpw */
pinfo->lcdc.border_clr = 0; /* black */
@@ -138,7 +138,7 @@
pinfo->mipi.dsi_phy_db = &dsi_video_mode_phy_db;
/* Four lanes are recomended for 1920x1200 at 60 frames per second */
- pinfo->mipi.frame_rate = 45; /* 45 frames per second */
+ pinfo->mipi.frame_rate = 60;
pinfo->mipi.data_lane0 = true;
pinfo->mipi.data_lane1 = true;
pinfo->mipi.data_lane2 = true;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 019acce..593f10b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -2932,6 +2932,56 @@
return 0;
}
+static int msmfb_handle_pp_ioctl(struct msmfb_mdp_pp *pp_ptr)
+{
+ int ret = -1;
+
+ if (!pp_ptr)
+ return ret;
+
+ switch (pp_ptr->op) {
+#ifdef CONFIG_FB_MSM_MDP40
+ case mdp_op_csc_cfg:
+ ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data));
+ break;
+
+ case mdp_op_pcc_cfg:
+ ret = mdp4_pcc_cfg(&(pp_ptr->data.pcc_cfg_data));
+ break;
+
+ case mdp_op_lut_cfg:
+ switch (pp_ptr->data.lut_cfg_data.lut_type) {
+ case mdp_lut_igc:
+ ret = mdp4_igc_lut_config(
+ (struct mdp_igc_lut_data *)
+ &pp_ptr->data.lut_cfg_data.data);
+ break;
+
+ case mdp_lut_pgc:
+ ret = mdp4_pgc_cfg(
+ &pp_ptr->data.lut_cfg_data.data.pgc_lut_data);
+ break;
+
+ case mdp_lut_hist:
+ ret = mdp_hist_lut_config(
+ (struct mdp_hist_lut_data *)
+ &pp_ptr->data.lut_cfg_data.data);
+ break;
+
+ default:
+ break;
+ }
+ break;
+#endif
+ default:
+ pr_warn("Unsupported request to MDP_PP IOCTL.\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -3225,28 +3275,15 @@
ret = -EINVAL;
#endif
break;
+
case MSMFB_MDP_PP:
ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
if (ret)
return ret;
- switch (mdp_pp.op) { /*Add PCC and LUT op handling here*/
-#ifdef CONFIG_FB_MSM_MDP40
- case mdp_op_csc_cfg:
- ret = mdp4_csc_config((struct mdp_csc_cfg_data *)
- &(mdp_pp.data));
- break;
- case mdp_op_pcc_cfg:
- case mdp_op_lut_cfg:
-#endif
- default:
- pr_warn("%s: Only CSC supported by MDP_PP IOCTL.\n",
- __func__);
- ret = -EINVAL;
- break;
- }
-
+ ret = msmfb_handle_pp_ioctl(&mdp_pp);
break;
+
default:
MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
ret = -EINVAL;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
index 51a0d13..433dad4 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -14,8 +14,8 @@
#ifndef _VCD_DDL_API_H_
#define _VCD_DDL_API_H_
+#include <media/msm/vcd_api.h>
#include "vidc.h"
-#include "vcd_api.h"
#define VCD_EVT_RESP_DDL_BASE 0x3000
#define VCD_EVT_RESP_DEVICE_INIT (VCD_EVT_RESP_DDL_BASE + 0x1)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index 42a991c..10b3404 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -15,7 +15,7 @@
#define _VCD_DDL_UTILS_H_
#include <linux/delay.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
extern u32 vidc_msg_pmem;
extern u32 vidc_msg_timing;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index c32ac81..8851b52 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -21,9 +21,9 @@
#include <linux/interrupt.h>
#include <linux/memory_alloc.h>
#include <asm/sizes.h>
+#include <media/msm/vidc_init.h>
#include "vidc.h"
#include "vcd_res_tracker.h"
-#include "vidc_init.h"
static unsigned int vidc_clk_table[3] = {
48000000, 133330000, 200000000
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
index 7c68d63..02b2369 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
#include "vcd_res_tracker_api.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
index eb08b7e..ac5bce9 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
index 25aa6bc..965c3aa 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_firmware.h"
#include "vcd_ddl_utils.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
index 7952dfb..a136de8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -12,7 +12,7 @@
*/
#ifndef _VCD_DDL_FIRMWARE_H_
#define _VCD_DDL_FIRMWARE_H_
-#include "vcd_property.h"
+#include <media/msm/vcd_property.h>
#define VCD_FW_BIG_ENDIAN 0x0
#define VCD_FW_LITTLE_ENDIAN 0x1
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
index f09bd71..6a69955 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
index 2ec8419..15adf21 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
DDL_INLINE struct ddl_context *ddl_get_context(void)
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
index 00c00cd..9dc495b 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -12,7 +12,7 @@
*/
#ifndef _VCD_DDL_INTERNAL_PROPERTY_H_
#define _VCD_DDL_INTERNAL_PROPERTY_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
#define VCD_EVT_RESP_DDL_BASE 0x3000
#define VCD_EVT_RESP_DEVICE_INIT (VCD_EVT_RESP_DDL_BASE + 0x1)
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
index ece4c30..fe71dc1 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vidc.h"
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
index 376ea6d..2a74da8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
index 6d3c666..3aebdaf 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index c8ea83f..17dedb8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
#include <linux/memory_alloc.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#if DEBUG
diff --git a/drivers/video/msm/vidc/720p/ddl/vidc.c b/drivers/video/msm/vidc/720p/ddl/vidc.c
index 0f5932a..de6cbbb 100644
--- a/drivers/video/msm/vidc/720p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/720p/ddl/vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -12,8 +12,8 @@
*/
#include <linux/unistd.h>
+#include <media/msm/vidc_type.h>
#include "vidc.h"
-#include "vidc_type.h"
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index 522ff16..86bf397 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -16,9 +16,9 @@
#include <linux/regulator/consumer.h>
#include <mach/clk.h>
#include <linux/interrupt.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_init.h>
+#include <media/msm/vidc_type.h>
#include "vcd_res_tracker.h"
-#include "vidc_init.h"
#define MSM_AXI_QOS_NAME "msm_vidc_reg"
#define AXI_CLK_SCALING
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index dee4da7..bfaac82 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -29,11 +29,11 @@
#include <linux/clk.h>
#include <linux/timer.h>
#include <mach/msm_subsystem_map.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
#include "vcd_res_tracker_api.h"
-#include "vidc_type.h"
-#include "vcd_api.h"
#include "vdec_internal.h"
-#include "vidc_init.h"
diff --git a/drivers/video/msm/vidc/common/dec/vdec_internal.h b/drivers/video/msm/vidc/common/dec/vdec_internal.h
index f310e25..89da9a2 100644
--- a/drivers/video/msm/vidc/common/dec/vdec_internal.h
+++ b/drivers/video/msm/vidc/common/dec/vdec_internal.h
@@ -16,7 +16,7 @@
#include <linux/msm_vidc_dec.h>
#include <linux/cdev.h>
-#include "vidc_init.h"
+#include <media/msm/vidc_init.h>
#define NUM_OF_DRIVER_NODES 2
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index cc6606c..6d6dcdc 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -27,11 +27,11 @@
#include <linux/workqueue.h>
#include <linux/android_pmem.h>
#include <linux/clk.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
-#include "vidc_type.h"
-#include "vcd_api.h"
#include "venc_internal.h"
-#include "vidc_init.h"
#include "vcd_res_tracker_api.h"
#define VID_ENC_NAME "msm_vidc_enc"
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index e3bb9db..f362f7b 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -28,10 +28,10 @@
#include <linux/android_pmem.h>
#include <linux/clk.h>
#include <mach/msm_subsystem_map.h>
-#include "vidc_type.h"
-#include "vcd_api.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
#include "venc_internal.h"
-#include "vidc_init.h"
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index 2b5a532..a07f7ab 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -16,8 +16,7 @@
#include <linux/msm_vidc_enc.h>
#include <linux/cdev.h>
-
-#include "vidc_init.h"
+#include <media/msm/vidc_init.h>
#define VID_ENC_MAX_NUM_OF_BUFF 100
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index f799a6c..0ea64d4 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -31,9 +31,9 @@
#include <mach/clk.h>
#include <linux/pm_runtime.h>
#include <mach/msm_subsystem_map.h>
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
#include "vidc_init_internal.h"
-#include "vidc_init.h"
#include "vcd_res_tracker_api.h"
#if DEBUG
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.h b/drivers/video/msm/vidc/common/init/vidc_init.h
deleted file mode 100644
index a67329c..0000000
--- a/drivers/video/msm/vidc/common/init/vidc_init.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (c) 2010-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 VIDC_INIT_H
-#define VIDC_INIT_H
-#include <linux/ion.h>
-#include "vidc_type.h"
-
-#define VIDC_MAX_NUM_CLIENTS 4
-#define MAX_VIDEO_NUM_OF_BUFF 100
-
-enum buffer_dir {
- BUFFER_TYPE_INPUT,
- BUFFER_TYPE_OUTPUT
-};
-
-struct buf_addr_table {
- unsigned long user_vaddr;
- unsigned long kernel_vaddr;
- unsigned long phy_addr;
- unsigned long buff_ion_flag;
- struct ion_handle *buff_ion_handle;
- int pmem_fd;
- struct file *file;
- unsigned long dev_addr;
- void *client_data;
-};
-
-struct video_client_ctx {
- void *vcd_handle;
- u32 num_of_input_buffers;
- u32 num_of_output_buffers;
- struct buf_addr_table input_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
- struct buf_addr_table output_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
- struct list_head msg_queue;
- struct mutex msg_queue_lock;
- struct mutex enrty_queue_lock;
- wait_queue_head_t msg_wait;
- struct completion event;
- struct vcd_property_h264_mv_buffer vcd_h264_mv_buffer;
- struct vcd_property_enc_recon_buffer recon_buffer[4];
- u32 event_status;
- u32 seq_header_set;
- u32 stop_msg;
- u32 stop_called;
- u32 stop_sync_cb;
- struct ion_client *user_ion_client;
- struct ion_handle *seq_hdr_ion_handle;
- struct ion_handle *h264_mv_ion_handle;
- struct ion_handle *recon_buffer_ion_handle[4];
- u32 dmx_disable;
-};
-
-void __iomem *vidc_get_ioaddr(void);
-int vidc_load_firmware(void);
-void vidc_release_firmware(void);
-u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
- enum buffer_dir buffer, int pmem_fd,
- unsigned long kvaddr, int index);
-u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
- enum buffer_dir buffer, u32 search_with_user_vaddr,
- unsigned long *user_vaddr, unsigned long *kernel_vaddr,
- unsigned long *phy_addr, int *pmem_fd, struct file **file,
- s32 *buffer_index);
-u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx,
- enum buffer_dir buffer, unsigned long user_vaddr,
- unsigned long *kernel_vaddr, int pmem_fd,
- unsigned long buffer_addr_offset,
- unsigned int max_num_buffers, unsigned long length);
-u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
- enum buffer_dir buffer, unsigned long user_vaddr,
- unsigned long *kernel_vaddr);
-void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
- enum buffer_dir buffer);
-
-u32 vidc_timer_create(void (*timer_handler)(void *),
- void *user_data, void **timer_handle);
-void vidc_timer_release(void *timer_handle);
-void vidc_timer_start(void *timer_handle, u32 time_out);
-void vidc_timer_stop(void *timer_handle);
-
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index b557752..9fc76d8 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -13,10 +13,10 @@
#ifndef _VCD_H_
#define _VCD_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
+#include "vcd_util.h"
#include "vcd_ddl_api.h"
#include "vcd_res_tracker_api.h"
-#include "vcd_util.h"
#include "vcd_client_sm.h"
#include "vcd_core.h"
#include "vcd_device_sm.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.c b/drivers/video/msm/vidc/common/vcd/vcd_api.c
index 5e9fd55..e0ef3af 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.c
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd.h"
u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle)
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.h b/drivers/video/msm/vidc/common/vcd/vcd_api.h
deleted file mode 100644
index 9580ece..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Copyright (c) 2010-2011, 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 _VCD_API_H_
-#define _VCD_API_H_
-#include "vcd_property.h"
-#include "vcd_status.h"
-
-#define VCD_FRAME_FLAG_EOS 0x00000001
-#define VCD_FRAME_FLAG_DECODEONLY 0x00000004
-#define VCD_FRAME_FLAG_DATACORRUPT 0x00000008
-#define VCD_FRAME_FLAG_ENDOFFRAME 0x00000010
-#define VCD_FRAME_FLAG_SYNCFRAME 0x00000020
-#define VCD_FRAME_FLAG_EXTRADATA 0x00000040
-#define VCD_FRAME_FLAG_CODECCONFIG 0x00000080
-#define VCD_FRAME_FLAG_BFRAME 0x00100000
-#define VCD_FRAME_FLAG_EOSEQ 0x00200000
-
-#define VCD_FLUSH_INPUT 0x0001
-#define VCD_FLUSH_OUTPUT 0x0002
-#define VCD_FLUSH_ALL 0x0003
-
-#define VCD_FRAMETAG_INVALID 0xffffffff
-
-struct vcd_handle_container {
- void *handle;
-};
-struct vcd_flush_cmd {
- u32 mode;
-};
-
-enum vcd_frame {
- VCD_FRAME_YUV = 1,
- VCD_FRAME_I,
- VCD_FRAME_P,
- VCD_FRAME_B,
- VCD_FRAME_NOTCODED,
- VCD_FRAME_IDR,
- VCD_FRAME_32BIT = 0x7fffffff
-};
-
-enum vcd_power_state {
- VCD_PWR_STATE_ON = 1,
- VCD_PWR_STATE_SLEEP,
-};
-
-struct vcd_frame_data {
- u8 *virtual;
- u8 *physical;
- u32 ion_flag;
- u32 alloc_len;
- u32 data_len;
- u32 offset;
- s64 time_stamp;
- u32 flags;
- u32 frm_clnt_data;
- struct vcd_property_dec_output_buffer dec_op_prop;
- u32 interlaced;
- enum vcd_frame frame;
- u32 ip_frm_tag;
- u32 intrlcd_ip_frm_tag;
- u8 *desc_buf;
- u32 desc_size;
-};
-
-struct vcd_sequence_hdr {
- u8 *sequence_header;
- u32 sequence_header_len;
-
-};
-
-enum vcd_buffer_type {
- VCD_BUFFER_INPUT = 0x1,
- VCD_BUFFER_OUTPUT = 0x2,
- VCD_BUFFER_INVALID = 0x3,
- VCD_BUFFER_32BIT = 0x7FFFFFFF
-};
-
-struct vcd_buffer_requirement {
- u32 min_count;
- u32 actual_count;
- u32 max_count;
- size_t sz;
- u32 align;
- u32 buf_pool_id;
-};
-
-struct vcd_init_config {
- void *device_name;
- void *(*map_dev_base_addr) (void *device_name);
- void (*un_map_dev_base_addr) (void);
- void (*interrupt_clr) (void);
- void (*register_isr) (void *device_name);
- void (*deregister_isr) (void);
- u32 (*timer_create) (void (*timer_handler)(void *),
- void *user_data, void **timer_handle);
- void (*timer_release) (void *timer_handle);
- void (*timer_start) (void *timer_handle, u32 time_out);
- void (*timer_stop) (void *timer_handle);
-};
-
-u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle);
-u32 vcd_term(s32 driver_handle);
-u32 vcd_open(s32 driver_handle, u32 decoding,
- void (*callback) (u32 event, u32 status, void *info, size_t sz,
- void *handle, void *const client_data), void *client_data);
-u32 vcd_close(void *handle);
-u32 vcd_encode_start(void *handle);
-u32 vcd_encode_frame(void *handle, struct vcd_frame_data *input_frame);
-u32 vcd_decode_start(void *handle, struct vcd_sequence_hdr *seq_hdr);
-u32 vcd_decode_frame(void *handle, struct vcd_frame_data *input_frame);
-u32 vcd_pause(void *handle);
-u32 vcd_resume(void *handle);
-u32 vcd_flush(void *handle, u32 mode);
-u32 vcd_stop(void *handle);
-u32 vcd_set_property(void *handle, struct vcd_property_hdr *prop_hdr,
- void *prop_val);
-u32 vcd_get_property(void *handle, struct vcd_property_hdr *prop_hdr,
- void *prop_val);
-u32 vcd_set_buffer_requirements(void *handle, enum vcd_buffer_type buffer,
- struct vcd_buffer_requirement *buffer_req);
-u32 vcd_get_buffer_requirements(void *handle, enum vcd_buffer_type buffer,
- struct vcd_buffer_requirement *buffer_req);
-u32 vcd_set_buffer(void *handle, enum vcd_buffer_type buffer_type,
- u8 *buffer, u32 buf_size);
-u32 vcd_allocate_buffer(void *handle, enum vcd_buffer_type buffer,
- u32 buf_size, u8 **vir_buf_addr, u8 **phy_buf_addr);
-
-u32 vcd_free_buffer(void *handle, enum vcd_buffer_type buffer_type, u8 *buffer);
-u32 vcd_fill_output_buffer(void *handle, struct vcd_frame_data *buffer);
-u32 vcd_set_device_power(s32 driver_handle,
- enum vcd_power_state pwr_state);
-void vcd_read_and_clear_interrupt(void);
-void vcd_response_handler(void);
-u8 vcd_get_num_of_clients(void);
-u32 vcd_get_ion_status(void);
-struct ion_client *vcd_get_ion_client(void);
-#endif
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 e00e85f..9376900 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd.h"
static const struct vcd_clnt_state_table *vcd_clnt_state_table[];
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
index e9ab41c..9f2d63d 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -12,7 +12,7 @@
*/
#ifndef _VCD_CLIENT_SM_H_
#define _VCD_CLIENT_SM_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
#include "vcd_ddl_api.h"
struct vcd_clnt_state_table;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index 64dec2d..1f844e8 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -14,7 +14,7 @@
#define _VCD_CORE_H_
#include <linux/ion.h>
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
#include "vcd_ddl_api.h"
#include "vcd_util.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 4c477cb..9576387 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd.h"
static const struct vcd_dev_state_table *vcd_dev_state_table[];
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
index 8245966..2443c33 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -13,7 +13,7 @@
#ifndef _VCD_DEVICE_SM_H_
#define _VCD_DEVICE_SM_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
#include "vcd_ddl_api.h"
#include "vcd_core.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
index 6a1cc80..01bd931 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd_power_sm.h"
#include "vcd_core.h"
#include "vcd.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_property.h b/drivers/video/msm/vidc/common/vcd/vcd_property.h
deleted file mode 100644
index a3069e3..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_property.h
+++ /dev/null
@@ -1,350 +0,0 @@
-/* Copyright (c) 2010-2011, 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 _VCD_DRIVER_PROPERTY_H_
-#define _VCD_DRIVER_PROPERTY_H_
-
-#define VCD_START_BASE 0x0
-#define VCD_I_LIVE (VCD_START_BASE + 0x1)
-#define VCD_I_CODEC (VCD_START_BASE + 0x2)
-#define VCD_I_FRAME_SIZE (VCD_START_BASE + 0x3)
-#define VCD_I_METADATA_ENABLE (VCD_START_BASE + 0x4)
-#define VCD_I_METADATA_HEADER (VCD_START_BASE + 0x5)
-#define VCD_I_PROFILE (VCD_START_BASE + 0x6)
-#define VCD_I_LEVEL (VCD_START_BASE + 0x7)
-#define VCD_I_BUFFER_FORMAT (VCD_START_BASE + 0x8)
-#define VCD_I_FRAME_RATE (VCD_START_BASE + 0x9)
-#define VCD_I_TARGET_BITRATE (VCD_START_BASE + 0xA)
-#define VCD_I_MULTI_SLICE (VCD_START_BASE + 0xB)
-#define VCD_I_ENTROPY_CTRL (VCD_START_BASE + 0xC)
-#define VCD_I_DEBLOCKING (VCD_START_BASE + 0xD)
-#define VCD_I_RATE_CONTROL (VCD_START_BASE + 0xE)
-#define VCD_I_QP_RANGE (VCD_START_BASE + 0xF)
-#define VCD_I_SESSION_QP (VCD_START_BASE + 0x10)
-#define VCD_I_INTRA_PERIOD (VCD_START_BASE + 0x11)
-#define VCD_I_VOP_TIMING (VCD_START_BASE + 0x12)
-#define VCD_I_SHORT_HEADER (VCD_START_BASE + 0x13)
-#define VCD_I_SEQ_HEADER (VCD_START_BASE + 0x14)
-#define VCD_I_HEADER_EXTENSION (VCD_START_BASE + 0x15)
-#define VCD_I_INTRA_REFRESH (VCD_START_BASE + 0x16)
-#define VCD_I_POST_FILTER (VCD_START_BASE + 0x17)
-#define VCD_I_PROGRESSIVE_ONLY (VCD_START_BASE + 0x18)
-#define VCD_I_OUTPUT_ORDER (VCD_START_BASE + 0x19)
-#define VCD_I_RECON_BUFFERS (VCD_START_BASE + 0x1A)
-#define VCD_I_FREE_RECON_BUFFERS (VCD_START_BASE + 0x1B)
-#define VCD_I_GET_RECON_BUFFER_SIZE (VCD_START_BASE + 0x1C)
-#define VCD_I_H264_MV_BUFFER (VCD_START_BASE + 0x1D)
-#define VCD_I_FREE_H264_MV_BUFFER (VCD_START_BASE + 0x1E)
-#define VCD_I_GET_H264_MV_SIZE (VCD_START_BASE + 0x1F)
-#define VCD_I_DEC_PICTYPE (VCD_START_BASE + 0x20)
-#define VCD_I_CONT_ON_RECONFIG (VCD_START_BASE + 0x21)
-#define VCD_I_META_BUFFER_MODE (VCD_START_BASE + 0x22)
-#define VCD_I_DISABLE_DMX (VCD_START_BASE + 0x23)
-#define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
-
-#define VCD_START_REQ (VCD_START_BASE + 0x1000)
-#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
-
-#define VCD_I_RESERVED_BASE (VCD_START_BASE + 0x10000)
-
-struct vcd_property_hdr {
- u32 prop_id;
- size_t sz;
-};
-
-struct vcd_property_live {
- u32 live;
-};
-
-enum vcd_codec {
- VCD_CODEC_H264 = 0x1,
- VCD_CODEC_H263 = 0x2,
- VCD_CODEC_MPEG1 = 0x3,
- VCD_CODEC_MPEG2 = 0x4,
- VCD_CODEC_MPEG4 = 0x5,
- VCD_CODEC_DIVX_3 = 0x6,
- VCD_CODEC_DIVX_4 = 0x7,
- VCD_CODEC_DIVX_5 = 0x8,
- VCD_CODEC_DIVX_6 = 0x9,
- VCD_CODEC_XVID = 0xA,
- VCD_CODEC_VC1 = 0xB,
- VCD_CODEC_VC1_RCV = 0xC
-};
-
-struct vcd_property_codec {
- enum vcd_codec codec;
-};
-
-struct vcd_property_frame_size {
- u32 width;
- u32 height;
- u32 stride;
- u32 scan_lines;
-};
-
-
-#define VCD_METADATA_DATANONE 0x001
-#define VCD_METADATA_QCOMFILLER 0x002
-#define VCD_METADATA_QPARRAY 0x004
-#define VCD_METADATA_CONCEALMB 0x008
-#define VCD_METADATA_SEI 0x010
-#define VCD_METADATA_VUI 0x020
-#define VCD_METADATA_VC1 0x040
-#define VCD_METADATA_PASSTHROUGH 0x080
-#define VCD_METADATA_ENC_SLICE 0x100
-
-struct vcd_property_meta_data_enable {
- u32 meta_data_enable_flag;
-};
-
-struct vcd_property_metadata_hdr {
- u32 meta_data_id;
- u32 version;
- u32 port_index;
- u32 type;
-};
-
-struct vcd_property_frame_rate {
- u32 fps_denominator;
- u32 fps_numerator;
-};
-
-struct vcd_property_target_bitrate {
- u32 target_bitrate;
-};
-
-enum vcd_yuv_buffer_format {
- VCD_BUFFER_FORMAT_NV12 = 0x1,
- VCD_BUFFER_FORMAT_TILE_4x2 = 0x2,
- VCD_BUFFER_FORMAT_NV12_16M2KA = 0x3,
- VCD_BUFFER_FORMAT_TILE_1x1 = 0x4
-};
-
-struct vcd_property_buffer_format {
- enum vcd_yuv_buffer_format buffer_format;
-};
-
-struct vcd_property_post_filter {
- u32 post_filter;
-};
-
-enum vcd_codec_profile {
- VCD_PROFILE_UNKNOWN = 0x0,
- VCD_PROFILE_MPEG4_SP = 0x1,
- VCD_PROFILE_MPEG4_ASP = 0x2,
- VCD_PROFILE_H264_BASELINE = 0x3,
- VCD_PROFILE_H264_MAIN = 0x4,
- VCD_PROFILE_H264_HIGH = 0x5,
- VCD_PROFILE_H263_BASELINE = 0x6,
- VCD_PROFILE_VC1_SIMPLE = 0x7,
- VCD_PROFILE_VC1_MAIN = 0x8,
- VCD_PROFILE_VC1_ADVANCE = 0x9,
- VCD_PROFILE_MPEG2_MAIN = 0xA,
- VCD_PROFILE_MPEG2_SIMPLE = 0xB
-};
-
-struct vcd_property_profile {
- enum vcd_codec_profile profile;
-};
-
-enum vcd_codec_level {
- VCD_LEVEL_UNKNOWN = 0x0,
- VCD_LEVEL_MPEG4_0 = 0x1,
- VCD_LEVEL_MPEG4_0b = 0x2,
- VCD_LEVEL_MPEG4_1 = 0x3,
- VCD_LEVEL_MPEG4_2 = 0x4,
- VCD_LEVEL_MPEG4_3 = 0x5,
- VCD_LEVEL_MPEG4_3b = 0x6,
- VCD_LEVEL_MPEG4_4 = 0x7,
- VCD_LEVEL_MPEG4_4a = 0x8,
- VCD_LEVEL_MPEG4_5 = 0x9,
- VCD_LEVEL_MPEG4_6 = 0xA,
- VCD_LEVEL_MPEG4_7 = 0xB,
- VCD_LEVEL_MPEG4_X = 0xC,
- VCD_LEVEL_H264_1 = 0x10,
- VCD_LEVEL_H264_1b = 0x11,
- VCD_LEVEL_H264_1p1 = 0x12,
- VCD_LEVEL_H264_1p2 = 0x13,
- VCD_LEVEL_H264_1p3 = 0x14,
- VCD_LEVEL_H264_2 = 0x15,
- VCD_LEVEL_H264_2p1 = 0x16,
- VCD_LEVEL_H264_2p2 = 0x17,
- VCD_LEVEL_H264_3 = 0x18,
- VCD_LEVEL_H264_3p1 = 0x19,
- VCD_LEVEL_H264_3p2 = 0x1A,
- VCD_LEVEL_H264_4 = 0x1B,
- VCD_LEVEL_H264_4p1 = 0x1C,
- VCD_LEVEL_H264_4p2 = 0x1D,
- VCD_LEVEL_H264_5 = 0x1E,
- VCD_LEVEL_H264_5p1 = 0x1F,
- VCD_LEVEL_H263_10 = 0x20,
- VCD_LEVEL_H263_20 = 0x21,
- VCD_LEVEL_H263_30 = 0x22,
- VCD_LEVEL_H263_40 = 0x23,
- VCD_LEVEL_H263_45 = 0x24,
- VCD_LEVEL_H263_50 = 0x25,
- VCD_LEVEL_H263_60 = 0x26,
- VCD_LEVEL_H263_70 = 0x27,
- VCD_LEVEL_H263_X = 0x28,
- VCD_LEVEL_MPEG2_LOW = 0x30,
- VCD_LEVEL_MPEG2_MAIN = 0x31,
- VCD_LEVEL_MPEG2_HIGH_14 = 0x32,
- VCD_LEVEL_MPEG2_HIGH = 0x33,
- VCD_LEVEL_MPEG2_X = 0x34,
- VCD_LEVEL_VC1_S_LOW = 0x40,
- VCD_LEVEL_VC1_S_MEDIUM = 0x41,
- VCD_LEVEL_VC1_M_LOW = 0x42,
- VCD_LEVEL_VC1_M_MEDIUM = 0x43,
- VCD_LEVEL_VC1_M_HIGH = 0x44,
- VCD_LEVEL_VC1_A_0 = 0x45,
- VCD_LEVEL_VC1_A_1 = 0x46,
- VCD_LEVEL_VC1_A_2 = 0x47,
- VCD_LEVEL_VC1_A_3 = 0x48,
- VCD_LEVEL_VC1_A_4 = 0x49,
- VCD_LEVEL_VC1_X = 0x4A
-};
-
-struct vcd_property_level {
- enum vcd_codec_level level;
-};
-
-enum vcd_m_slice_sel {
- VCD_MSLICE_OFF = 0x1,
- VCD_MSLICE_BY_MB_COUNT = 0x2,
- VCD_MSLICE_BY_BYTE_COUNT = 0x3,
- VCD_MSLICE_BY_GOB = 0x4
-};
-
-struct vcd_property_multi_slice {
- enum vcd_m_slice_sel m_slice_sel;
- u32 m_slice_size;
-};
-
-enum vcd_entropy_sel {
- VCD_ENTROPY_SEL_CAVLC = 0x1,
- VCD_ENTROPY_SEL_CABAC = 0x2
-};
-
-enum vcd_cabac_model {
- VCD_CABAC_MODEL_NUMBER_0 = 0x1,
- VCD_CABAC_MODEL_NUMBER_1 = 0x2,
- VCD_CABAC_MODEL_NUMBER_2 = 0x3
-};
-
-struct vcd_property_entropy_control {
- enum vcd_entropy_sel entropy_sel;
- enum vcd_cabac_model cabac_model;
-};
-
-enum vcd_db_config {
- VCD_DB_ALL_BLOCKING_BOUNDARY = 0x1,
- VCD_DB_DISABLE = 0x2,
- VCD_DB_SKIP_SLICE_BOUNDARY = 0x3
-};
-struct vcd_property_db_config {
- enum vcd_db_config db_config;
- u32 slice_alpha_offset;
- u32 slice_beta_offset;
-};
-
-enum vcd_rate_control {
- VCD_RATE_CONTROL_OFF = 0x1,
- VCD_RATE_CONTROL_VBR_VFR = 0x2,
- VCD_RATE_CONTROL_VBR_CFR = 0x3,
- VCD_RATE_CONTROL_CBR_VFR = 0x4,
- VCD_RATE_CONTROL_CBR_CFR = 0x5
-};
-
-struct vcd_property_rate_control {
- enum vcd_rate_control rate_control;
-};
-
-struct vcd_property_qp_range {
- u32 max_qp;
- u32 min_qp;
-};
-
-struct vcd_property_session_qp {
- u32 i_frame_qp;
- u32 p_frame_qp;
- u32 b_frame_qp;
-};
-
-struct vcd_property_i_period {
- u32 p_frames;
- u32 b_frames;
-};
-
-struct vcd_property_vop_timing {
- u32 vop_time_resolution;
-};
-
-struct vcd_property_short_header {
- u32 short_header;
-};
-
-struct vcd_property_intra_refresh_mb_number {
- u32 cir_mb_number;
-};
-
-struct vcd_property_req_i_frame {
- u32 req_i_frame;
-};
-
-struct vcd_frame_rect{
- u32 left;
- u32 top;
- u32 right;
- u32 bottom;
-};
-
-struct vcd_property_dec_output_buffer {
- struct vcd_frame_rect disp_frm;
- struct vcd_property_frame_size frm_size;
-};
-
-enum vcd_output_order {
- VCD_DEC_ORDER_DISPLAY = 0x0,
- VCD_DEC_ORDER_DECODE = 0x1
-};
-
-struct vcd_property_enc_recon_buffer{
- u8 *user_virtual_addr;
- u8 *kernel_virtual_addr;
- u8 *physical_addr;
- u8 *dev_addr;
- u32 buffer_size;
- u32 ysize;
- int pmem_fd;
- u32 offset;
- void *client_data;
-};
-
-struct vcd_property_h264_mv_buffer{
- u8 *kernel_virtual_addr;
- u8 *physical_addr;
- u32 size;
- u32 count;
- int pmem_fd;
- u32 offset;
- u8 *dev_addr;
- void *client_data;
-};
-
-struct vcd_property_buffer_size{
- int width;
- int height;
- int size;
- int alignment;
-};
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
index 34a3445..dec9b4e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,7 +11,7 @@
*
*/
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd.h"
#define NORMALIZATION_FACTOR 3600
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_status.h b/drivers/video/msm/vidc/common/vcd/vcd_status.h
deleted file mode 100644
index 1a36167..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_status.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (c) 2010-2011, 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 _VCD_ERR_STATUS_H_
-#define _VCD_ERR_STATUS_H_
-
-#define VCD_EVT_RESP_BASE 0x1000
-#define VCD_EVT_RESP_OPEN (VCD_EVT_RESP_BASE + 0x1)
-#define VCD_EVT_RESP_START (VCD_EVT_RESP_BASE + 0x2)
-#define VCD_EVT_RESP_STOP (VCD_EVT_RESP_BASE + 0x3)
-#define VCD_EVT_RESP_PAUSE (VCD_EVT_RESP_BASE + 0x4)
-#define VCD_EVT_RESP_FLUSH_INPUT_DONE (VCD_EVT_RESP_BASE + 0x5)
-#define VCD_EVT_RESP_FLUSH_OUTPUT_DONE (VCD_EVT_RESP_BASE + 0x6)
-#define VCD_EVT_RESP_INPUT_FLUSHED (VCD_EVT_RESP_BASE + 0x7)
-#define VCD_EVT_RESP_OUTPUT_FLUSHED (VCD_EVT_RESP_BASE + 0x8)
-#define VCD_EVT_RESP_INPUT_DONE (VCD_EVT_RESP_BASE + 0x9)
-#define VCD_EVT_RESP_OUTPUT_DONE (VCD_EVT_RESP_BASE + 0xa)
-
-#define VCD_EVT_IND_BASE 0x2000
-#define VCD_EVT_IND_INPUT_RECONFIG (VCD_EVT_IND_BASE + 0x1)
-#define VCD_EVT_IND_OUTPUT_RECONFIG (VCD_EVT_IND_BASE + 0x2)
-#define VCD_EVT_IND_HWERRFATAL (VCD_EVT_IND_BASE + 0x3)
-#define VCD_EVT_IND_RESOURCES_LOST (VCD_EVT_IND_BASE + 0x4)
-#define VCD_EVT_IND_INFO_OUTPUT_RECONFIG (VCD_EVT_IND_BASE + 0x5)
-#define VCD_EVT_IND_INFO_FIELD_DROPPED (VCD_EVT_IND_BASE + 0x6)
-
-#define VCD_S_SUCCESS 0x0
-
-#define VCD_S_ERR_BASE 0x80000000
-#define VCD_ERR_FAIL (VCD_S_ERR_BASE + 0x01)
-#define VCD_ERR_ALLOC_FAIL (VCD_S_ERR_BASE + 0x02)
-#define VCD_ERR_ILLEGAL_OP (VCD_S_ERR_BASE + 0x03)
-#define VCD_ERR_ILLEGAL_PARM (VCD_S_ERR_BASE + 0x04)
-#define VCD_ERR_BAD_POINTER (VCD_S_ERR_BASE + 0x05)
-#define VCD_ERR_BAD_HANDLE (VCD_S_ERR_BASE + 0x06)
-#define VCD_ERR_NOT_SUPPORTED (VCD_S_ERR_BASE + 0x07)
-#define VCD_ERR_BAD_STATE (VCD_S_ERR_BASE + 0x08)
-#define VCD_ERR_BUSY (VCD_S_ERR_BASE + 0x09)
-#define VCD_ERR_MAX_CLIENT (VCD_S_ERR_BASE + 0x0a)
-#define VCD_ERR_IFRAME_EXPECTED (VCD_S_ERR_BASE + 0x0b)
-#define VCD_ERR_INTRLCD_FIELD_DROP (VCD_S_ERR_BASE + 0x0c)
-#define VCD_ERR_HW_FATAL (VCD_S_ERR_BASE + 0x0d)
-#define VCD_ERR_BITSTREAM_ERR (VCD_S_ERR_BASE + 0x0e)
-#define VCD_ERR_QEMPTY (VCD_S_ERR_BASE + 0x0f)
-#define VCD_ERR_SEQHDR_PARSE_FAIL (VCD_S_ERR_BASE + 0x10)
-#define VCD_ERR_INPUT_NOT_PROCESSED (VCD_S_ERR_BASE + 0x11)
-#define VCD_ERR_INDEX_NOMORE (VCD_S_ERR_BASE + 0x12)
-
-#define VCD_FAILED(rc) ((rc > VCD_S_ERR_BASE) ? true : false)
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 509b897..ebc30fd 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -13,7 +13,7 @@
#include <linux/memory_alloc.h>
#include <mach/msm_subsystem_map.h>
#include <asm/div64.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
#include "vcd.h"
#include "vdec_internal.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_util.h b/drivers/video/msm/vidc/common/vcd/vcd_util.h
index 07ad651..7164029 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_util.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -12,8 +12,8 @@
*/
#ifndef _VCD_UTIL_H_
#define _VCD_UTIL_H_
-#include "vidc_type.h"
-#include "vcd_api.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
#if DEBUG
diff --git a/drivers/video/msm/vidc/common/vcd/vidc_type.h b/drivers/video/msm/vidc/common/vcd/vidc_type.h
deleted file mode 100644
index bd87c0d..0000000
--- a/drivers/video/msm/vidc/common/vcd/vidc_type.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (c) 2010-2011, 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 VIDC_TYPE_H
-#define VIDC_TYPE_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/time.h>
-#include <linux/dma-mapping.h>
-#include <linux/android_pmem.h>
-
-#define DEBUG 0
-#define VIDC_ENABLE_DBGFS
-
-#define USE_RES_TRACKER
-#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 9c43f56..79f7874 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -428,6 +428,7 @@
header-y += msm_ipc.h
header-y += msm_charm.h
header-y += tzcom.h
+header-y += qseecom.h
header-y += qcedev.h
header-y += idle_stats_device.h
header-y += genlock.h
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 3256fba..caed2a2 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -570,6 +570,7 @@
struct ion_handle *handle, int domain_num,
int partition_num, unsigned long align,
unsigned long iova_length, unsigned long *iova,
+ unsigned long *buffer_size,
unsigned long flags)
{
return -ENODEV;
diff --git a/include/linux/mfd/Kbuild b/include/linux/mfd/Kbuild
index 1acc78f..bba647c 100644
--- a/include/linux/mfd/Kbuild
+++ b/include/linux/mfd/Kbuild
@@ -1,3 +1,3 @@
header-y += timpani-audio.h
header-y += msm-adie-codec.h
-header-y += wcd9310/
+header-y += wcd9xxx/
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 82db9a4..e2d4d93 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.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
@@ -95,8 +95,15 @@
unsigned int batt_id_channel;
};
+enum battery_type {
+ BATT_UNKNOWN = 0,
+ BATT_PALLADIUM,
+ BATT_DESAY,
+};
+
/**
* struct pm8921_bms_platform_data -
+ * @batt_type: allows to force chose battery calibration data
* @r_sense: sense resistor value in (mOhms)
* @i_test: current at which the unusable charger cutoff is to be
* calculated or the peak system current (mA)
@@ -105,6 +112,7 @@
*/
struct pm8921_bms_platform_data {
struct pm8xxx_bms_core_data bms_cdata;
+ enum battery_type battery_type;
unsigned int r_sense;
unsigned int i_test;
unsigned int v_failure;
@@ -114,6 +122,7 @@
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
extern struct pm8921_bms_battery_data palladium_1500_data;
+extern struct pm8921_bms_battery_data desay_5200_data;
/**
* pm8921_bms_get_vsense_avg - return the voltage across the sense
* resitor in microvolts
diff --git a/include/linux/mfd/pm8xxx/regulator.h b/include/linux/mfd/pm8xxx/regulator.h
index 9e0ce86..83492d2 100644
--- a/include/linux/mfd/pm8xxx/regulator.h
+++ b/include/linux/mfd/pm8xxx/regulator.h
@@ -30,6 +30,7 @@
* %PM8XXX_REGULATOR_TYPE_VS: voltage switch capable of sourcing 100mA
* %PM8XXX_REGULATOR_TYPE_VS300: voltage switch capable of sourcing 300mA
* %PM8XXX_REGULATOR_TYPE_NCP: negative charge pump
+ * %PM8XXX_REGULATOR_TYPE_BOOST: boost regulator
* %PM8XXX_REGULATOR_TYPE_MAX: used internally for error checking; not
* a valid regulator type.
*
@@ -44,6 +45,7 @@
PM8XXX_REGULATOR_TYPE_VS,
PM8XXX_REGULATOR_TYPE_VS300,
PM8XXX_REGULATOR_TYPE_NCP,
+ PM8XXX_REGULATOR_TYPE_BOOST,
PM8XXX_REGULATOR_TYPE_MAX,
};
@@ -257,4 +259,13 @@
.prev_write_count = -1, \
}
+#define BOOST(_name, _ctrl_addr) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_BOOST, \
+ .ctrl_addr = _ctrl_addr, \
+ .rdesc.name = _name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
#endif
diff --git a/include/linux/mfd/wcd9310/Kbuild b/include/linux/mfd/wcd9310/Kbuild
deleted file mode 100644
index 2702ec6..0000000
--- a/include/linux/mfd/wcd9310/Kbuild
+++ /dev/null
@@ -1 +0,0 @@
-header-y += registers.h
diff --git a/include/linux/mfd/wcd9310/core.h b/include/linux/mfd/wcd9310/core.h
deleted file mode 100644
index 8605ac6..0000000
--- a/include/linux/mfd/wcd9310/core.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* 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
- * 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 __MFD_TABLA_CORE_H__
-#define __MFD_TABLA_CORE_H__
-
-#include <linux/interrupt.h>
-#include <linux/wakelock.h>
-
-#define TABLA_NUM_IRQ_REGS 3
-
-#define TABLA_SLIM_NUM_PORT_REG 3
-
-#define TABLA_INTERFACE_TYPE_SLIMBUS 0x00
-#define TABLA_INTERFACE_TYPE_I2C 0x01
-
-#define TABLA_VERSION_1_0 0
-#define TABLA_VERSION_1_1 1
-#define TABLA_VERSION_2_0 2
-#define TABLA_IS_1_X(ver) \
- (((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
-#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
-
-enum {
- TABLA_IRQ_SLIMBUS = 0,
- TABLA_IRQ_MBHC_REMOVAL,
- TABLA_IRQ_MBHC_SHORT_TERM,
- TABLA_IRQ_MBHC_PRESS,
- TABLA_IRQ_MBHC_RELEASE,
- TABLA_IRQ_MBHC_POTENTIAL,
- TABLA_IRQ_MBHC_INSERTION,
- TABLA_IRQ_BG_PRECHARGE,
- TABLA_IRQ_PA1_STARTUP,
- TABLA_IRQ_PA2_STARTUP,
- TABLA_IRQ_PA3_STARTUP,
- TABLA_IRQ_PA4_STARTUP,
- TABLA_IRQ_PA5_STARTUP,
- TABLA_IRQ_MICBIAS1_PRECHARGE,
- TABLA_IRQ_MICBIAS2_PRECHARGE,
- TABLA_IRQ_MICBIAS3_PRECHARGE,
- TABLA_IRQ_HPH_PA_OCPL_FAULT,
- TABLA_IRQ_HPH_PA_OCPR_FAULT,
- TABLA_IRQ_EAR_PA_OCPL_FAULT,
- TABLA_IRQ_HPH_L_PA_STARTUP,
- TABLA_IRQ_HPH_R_PA_STARTUP,
- TABLA_IRQ_EAR_PA_STARTUP,
- TABLA_NUM_IRQS,
-};
-
-enum tabla_pm_state {
- TABLA_PM_SLEEPABLE,
- TABLA_PM_AWAKE,
- TABLA_PM_ASLEEP,
-};
-
-struct tabla {
- struct device *dev;
- struct slim_device *slim;
- struct slim_device *slim_slave;
- struct mutex io_lock;
- struct mutex xfer_lock;
- struct mutex irq_lock;
- u8 version;
-
- unsigned int irq_base;
- unsigned int irq;
- u8 irq_masks_cur[TABLA_NUM_IRQ_REGS];
- u8 irq_masks_cache[TABLA_NUM_IRQ_REGS];
- u8 irq_level[TABLA_NUM_IRQ_REGS];
-
- int reset_gpio;
-
- int (*read_dev)(struct tabla *tabla, unsigned short reg,
- int bytes, void *dest, bool interface_reg);
- int (*write_dev)(struct tabla *tabla, unsigned short reg,
- int bytes, void *src, bool interface_reg);
-
- struct regulator_bulk_data *supplies;
-
- enum tabla_pm_state pm_state;
- struct mutex pm_lock;
- /* pm_wq notifies change of pm_state */
- wait_queue_head_t pm_wq;
- struct wake_lock wlock;
- int wlock_holders;
-};
-
-int tabla_reg_read(struct tabla *tabla, unsigned short reg);
-int tabla_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
-int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg);
-int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
-int tabla_bulk_read(struct tabla *tabla, unsigned short reg, int count,
- u8 *buf);
-int tabla_bulk_write(struct tabla *tabla, unsigned short reg, int count,
- u8 *buf);
-int tabla_irq_init(struct tabla *tabla);
-void tabla_irq_exit(struct tabla *tabla);
-int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-int tabla_get_intf_type(void);
-
-void tabla_lock_sleep(struct tabla *tabla);
-void tabla_unlock_sleep(struct tabla *tabla);
-enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
- enum tabla_pm_state n);
-
-static inline int tabla_request_irq(struct tabla *tabla, int irq,
- irq_handler_t handler, const char *name,
- void *data)
-{
- if (!tabla->irq_base)
- return -EINVAL;
- return request_threaded_irq(tabla->irq_base + irq, NULL, handler,
- IRQF_TRIGGER_RISING, name,
- data);
-}
-static inline void tabla_free_irq(struct tabla *tabla, int irq, void *data)
-{
- if (!tabla->irq_base)
- return;
- free_irq(tabla->irq_base + irq, data);
-}
-static inline void tabla_enable_irq(struct tabla *tabla, int irq)
-{
- if (!tabla->irq_base)
- return;
- enable_irq(tabla->irq_base + irq);
-}
-static inline void tabla_disable_irq(struct tabla *tabla, int irq)
-{
- if (!tabla->irq_base)
- return;
- disable_irq_nosync(tabla->irq_base + irq);
-}
-
-#endif
diff --git a/include/linux/mfd/wcd9xxx/Kbuild b/include/linux/mfd/wcd9xxx/Kbuild
new file mode 100644
index 0000000..acfab6e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/Kbuild
@@ -0,0 +1,2 @@
+header-y += wcd9xxx_registers.h
+header-y += wcd9310_registers.h
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
new file mode 100644
index 0000000..0d99e37
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -0,0 +1,177 @@
+/* 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
+ * 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 __MFD_TABLA_CORE_H__
+#define __MFD_TABLA_CORE_H__
+
+#include <linux/interrupt.h>
+#include <linux/wakelock.h>
+
+#define WCD9XXX_NUM_IRQ_REGS 3
+
+#define WCD9XXX_SLIM_NUM_PORT_REG 3
+
+#define WCD9XXX_INTERFACE_TYPE_SLIMBUS 0x00
+#define WCD9XXX_INTERFACE_TYPE_I2C 0x01
+
+#define TABLA_VERSION_1_0 0
+#define TABLA_VERSION_1_1 1
+#define TABLA_VERSION_2_0 2
+#define TABLA_IS_1_X(ver) \
+ (((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
+#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
+
+enum {
+ TABLA_IRQ_SLIMBUS = 0,
+ TABLA_IRQ_MBHC_REMOVAL,
+ TABLA_IRQ_MBHC_SHORT_TERM,
+ TABLA_IRQ_MBHC_PRESS,
+ TABLA_IRQ_MBHC_RELEASE,
+ TABLA_IRQ_MBHC_POTENTIAL,
+ TABLA_IRQ_MBHC_INSERTION,
+ TABLA_IRQ_BG_PRECHARGE,
+ TABLA_IRQ_PA1_STARTUP,
+ TABLA_IRQ_PA2_STARTUP,
+ TABLA_IRQ_PA3_STARTUP,
+ TABLA_IRQ_PA4_STARTUP,
+ TABLA_IRQ_PA5_STARTUP,
+ TABLA_IRQ_MICBIAS1_PRECHARGE,
+ TABLA_IRQ_MICBIAS2_PRECHARGE,
+ TABLA_IRQ_MICBIAS3_PRECHARGE,
+ TABLA_IRQ_HPH_PA_OCPL_FAULT,
+ TABLA_IRQ_HPH_PA_OCPR_FAULT,
+ TABLA_IRQ_EAR_PA_OCPL_FAULT,
+ TABLA_IRQ_HPH_L_PA_STARTUP,
+ TABLA_IRQ_HPH_R_PA_STARTUP,
+ TABLA_IRQ_EAR_PA_STARTUP,
+ TABLA_NUM_IRQS,
+};
+
+enum {
+ SITAR_IRQ_SLIMBUS = 0,
+ SITAR_IRQ_MBHC_REMOVAL,
+ SITAR_IRQ_MBHC_SHORT_TERM,
+ SITAR_IRQ_MBHC_PRESS,
+ SITAR_IRQ_MBHC_RELEASE,
+ SITAR_IRQ_MBHC_POTENTIAL,
+ SITAR_IRQ_MBHC_INSERTION,
+ SITAR_IRQ_BG_PRECHARGE,
+ SITAR_IRQ_PA1_STARTUP,
+ SITAR_IRQ_PA2_STARTUP,
+ SITAR_IRQ_PA3_STARTUP,
+ SITAR_IRQ_PA4_STARTUP,
+ SITAR_IRQ_PA5_STARTUP,
+ SITAR_IRQ_MICBIAS1_PRECHARGE,
+ SITAR_IRQ_MICBIAS2_PRECHARGE,
+ SITAR_IRQ_MICBIAS3_PRECHARGE,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT,
+ SITAR_IRQ_HPH_PA_OCPR_FAULT,
+ SITAR_IRQ_EAR_PA_OCPL_FAULT,
+ SITAR_IRQ_HPH_L_PA_STARTUP,
+ SITAR_IRQ_HPH_R_PA_STARTUP,
+ SITAR_IRQ_EAR_PA_STARTUP,
+ SITAR_NUM_IRQS,
+};
+
+
+enum wcd9xxx_pm_state {
+ WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_AWAKE,
+ WCD9XXX_PM_ASLEEP,
+};
+
+struct wcd9xxx {
+ struct device *dev;
+ struct slim_device *slim;
+ struct slim_device *slim_slave;
+ struct mutex io_lock;
+ struct mutex xfer_lock;
+ struct mutex irq_lock;
+ u8 version;
+
+ unsigned int irq_base;
+ unsigned int irq;
+ u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
+ u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
+ u8 irq_level[WCD9XXX_NUM_IRQ_REGS];
+
+ int reset_gpio;
+
+ int (*read_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *dest, bool interface_reg);
+ int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *src, bool interface_reg);
+
+ struct regulator_bulk_data *supplies;
+
+ enum wcd9xxx_pm_state pm_state;
+ struct mutex pm_lock;
+ /* pm_wq notifies change of pm_state */
+ wait_queue_head_t pm_wq;
+ struct wake_lock wlock;
+ int wlock_holders;
+ int num_rx_port;
+ int num_tx_port;
+};
+
+int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
+int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ u8 val);
+int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
+int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ u8 val);
+int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int count, u8 *buf);
+int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int count, u8 *buf);
+int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
+int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
+int wcd9xxx_get_intf_type(void);
+
+void wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
+ enum wcd9xxx_pm_state o,
+ enum wcd9xxx_pm_state n);
+
+static inline int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
+ irq_handler_t handler, const char *name,
+ void *data)
+{
+ if (!wcd9xxx->irq_base)
+ return -EINVAL;
+ return request_threaded_irq(wcd9xxx->irq_base + irq, NULL, handler,
+ IRQF_TRIGGER_RISING, name,
+ data);
+}
+static inline void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx,
+ int irq, void *data)
+{
+ if (!wcd9xxx->irq_base)
+ return;
+ free_irq(wcd9xxx->irq_base + irq, data);
+}
+static inline void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ if (!wcd9xxx->irq_base)
+ return;
+ enable_irq(wcd9xxx->irq_base + irq);
+}
+static inline void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ if (!wcd9xxx->irq_base)
+ return;
+ disable_irq_nosync(wcd9xxx->irq_base + irq);
+}
+
+#endif
diff --git a/include/linux/mfd/wcd9310/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
similarity index 71%
rename from include/linux/mfd/wcd9310/pdata.h
rename to include/linux/mfd/wcd9xxx/pdata.h
index af801f0..db76294 100644
--- a/include/linux/mfd/wcd9310/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.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
@@ -16,6 +16,15 @@
#include <linux/slimbus/slimbus.h>
+#define SITAR_LDOH_1P95_V 0x0
+#define SITAR_LDOH_2P35_V 0x1
+#define SITAR_LDOH_2P75_V 0x2
+#define SITAR_LDOH_2P85_V 0x3
+
+#define SITAR_CFILT1_SEL 0x0
+#define SITAR_CFILT2_SEL 0x1
+#define SITAR_CFILT3_SEL 0x2
+
#define TABLA_LDOH_1P95_V 0x0
#define TABLA_LDOH_2P35_V 0x1
#define TABLA_LDOH_2P75_V 0x2
@@ -51,7 +60,7 @@
#define TABLA_DCYCLE_3839 0xE
#define TABLA_DCYCLE_4095 0xF
-struct tabla_amic {
+struct wcd9xxx_amic {
/*legacy mode, txfe_enable and txfe_buff take 7 input
* each bit represent the channel / TXFE number
* and numbered as below
@@ -75,7 +84,7 @@
* If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
*/
-struct tabla_micbias_setting {
+struct wcd9xxx_micbias_setting {
u8 ldoh_v;
u32 cfilt1_mv; /* in mv */
u32 cfilt2_mv; /* in mv */
@@ -86,7 +95,7 @@
u8 bias4_cfilt_sel;
};
-struct tabla_ocp_setting {
+struct wcd9xxx_ocp_setting {
unsigned int use_pdata:1; /* 0 - use sys default as recommended */
unsigned int num_attempts:4; /* up to 15 attempts */
unsigned int run_time:4; /* in duty cycle */
@@ -94,15 +103,39 @@
unsigned int hph_ocp_limit:3; /* Headphone OCP current limit */
};
-struct tabla_pdata {
+#define MAX_REGULATOR 6
+/*
+ * format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
+ *
+ * <POWER_SUPPLY_PIN_NAME> from Tabla objective spec
+*/
+
+#define WCD9XXX_CDC_VDDA_CP_CUR_MAX 500000
+#define WCD9XXX_CDC_VDDA_RX_CUR_MAX 20000
+#define WCD9XXX_CDC_VDDA_TX_CUR_MAX 20000
+#define WCD9XXX_VDDIO_CDC_CUR_MAX 5000
+
+#define WCD9XXX_VDDD_CDC_D_CUR_MAX 5000
+#define WCD9XXX_VDDD_CDC_A_CUR_MAX 5000
+
+struct wcd9xxx_regulator {
+ const char *name;
+ int min_uV;
+ int max_uV;
+ int optimum_uA;
+ struct regulator *regulator;
+};
+
+struct wcd9xxx_pdata {
int irq;
int irq_base;
int num_irqs;
int reset_gpio;
- struct tabla_amic amic_settings;
+ struct wcd9xxx_amic amic_settings;
struct slim_device slimbus_slave_device;
- struct tabla_micbias_setting micbias;
- struct tabla_ocp_setting ocp;
+ struct wcd9xxx_micbias_setting micbias;
+ struct wcd9xxx_ocp_setting ocp;
+ struct wcd9xxx_regulator regulator[MAX_REGULATOR];
};
#endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
new file mode 100644
index 0000000..df54e02
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
@@ -0,0 +1,742 @@
+/* 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 SITAR_CODEC_DIGITAL_H
+#define SITAR_CODEC_DIGITAL_H
+
+#define SITAR_A_PIN_CTL_OE0 (0x10)
+#define SITAR_A_PIN_CTL_OE0__POR (0x00000000)
+#define SITAR_A_PIN_CTL_OE1 (0x11)
+#define SITAR_A_PIN_CTL_OE1__POR (0x00000000)
+#define SITAR_A_PIN_CTL_DATA0 (0x12)
+#define SITAR_A_PIN_CTL_DATA0__POR (0x00000000)
+#define SITAR_A_PIN_CTL_DATA1 (0x13)
+#define SITAR_A_PIN_CTL_DATA1__POR (0x00000000)
+#define SITAR_A_HDRIVE_GENERIC (0x18)
+#define SITAR_A_HDRIVE_GENERIC__POR (0x00000000)
+#define SITAR_A_HDRIVE_OVERRIDE (0x19)
+#define SITAR_A_HDRIVE_OVERRIDE__POR (0x00000008)
+#define SITAR_A_ANA_CSR_WAIT_STATE (0x20)
+#define SITAR_A_ANA_CSR_WAIT_STATE__POR (0x00000044)
+#define SITAR_A_PROCESS_MONITOR_CTL0 (0x40)
+#define SITAR_A_PROCESS_MONITOR_CTL0__POR (0x00000080)
+#define SITAR_A_PROCESS_MONITOR_CTL1 (0x41)
+#define SITAR_A_PROCESS_MONITOR_CTL1__POR (0x00000000)
+#define SITAR_A_PROCESS_MONITOR_CTL2 (0x42)
+#define SITAR_A_PROCESS_MONITOR_CTL2__POR (0x00000000)
+#define SITAR_A_PROCESS_MONITOR_CTL3 (0x43)
+#define SITAR_A_PROCESS_MONITOR_CTL3__POR (0x00000001)
+#define SITAR_A_QFUSE_CTL (0x48)
+#define SITAR_A_QFUSE_CTL__POR (0x00000000)
+#define SITAR_A_QFUSE_STATUS (0x49)
+#define SITAR_A_QFUSE_STATUS__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT0 (0x4A)
+#define SITAR_A_QFUSE_DATA_OUT0__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT1 (0x4B)
+#define SITAR_A_QFUSE_DATA_OUT1__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT2 (0x4C)
+#define SITAR_A_QFUSE_DATA_OUT2__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT3 (0x4D)
+#define SITAR_A_QFUSE_DATA_OUT3__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT4 (0x4E)
+#define SITAR_A_QFUSE_DATA_OUT4__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT5 (0x4F)
+#define SITAR_A_QFUSE_DATA_OUT5__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT6 (0x50)
+#define SITAR_A_QFUSE_DATA_OUT6__POR (0x00000000)
+#define SITAR_A_QFUSE_DATA_OUT7 (0x51)
+#define SITAR_A_QFUSE_DATA_OUT7__POR (0x00000000)
+#define SITAR_A_CDC_CTL (0x80)
+#define SITAR_A_CDC_CTL__POR (0x00000000)
+#define SITAR_A_LEAKAGE_CTL (0x88)
+#define SITAR_A_LEAKAGE_CTL__POR (0x00000004)
+#define SITAR_A_INTR_MODE (0x90)
+#define SITAR_A_INTR_MODE__POR (0x00000000)
+#define SITAR_A_INTR_MASK0 (0x94)
+#define SITAR_A_INTR_MASK0__POR (0x000000ff)
+#define SITAR_A_INTR_MASK1 (0x95)
+#define SITAR_A_INTR_MASK1__POR (0x000000ff)
+#define SITAR_A_INTR_MASK2 (0x96)
+#define SITAR_A_INTR_MASK2__POR (0x000000ff)
+#define SITAR_A_INTR_STATUS0 (0x98)
+#define SITAR_A_INTR_STATUS0__POR (0x00000000)
+#define SITAR_A_INTR_STATUS1 (0x99)
+#define SITAR_A_INTR_STATUS1__POR (0x00000000)
+#define SITAR_A_INTR_STATUS2 (0x9A)
+#define SITAR_A_INTR_STATUS2__POR (0x00000000)
+#define SITAR_A_INTR_CLEAR0 (0x9C)
+#define SITAR_A_INTR_CLEAR0__POR (0x00000000)
+#define SITAR_A_INTR_CLEAR1 (0x9D)
+#define SITAR_A_INTR_CLEAR1__POR (0x00000000)
+#define SITAR_A_INTR_CLEAR2 (0x9E)
+#define SITAR_A_INTR_CLEAR2__POR (0x00000000)
+#define SITAR_A_INTR_LEVEL0 (0xA0)
+#define SITAR_A_INTR_LEVEL0__POR (0x00000001)
+#define SITAR_A_INTR_LEVEL1 (0xA1)
+#define SITAR_A_INTR_LEVEL1__POR (0x00000000)
+#define SITAR_A_INTR_LEVEL2 (0xA2)
+#define SITAR_A_INTR_LEVEL2__POR (0x00000000)
+#define SITAR_A_INTR_TEST0 (0xA4)
+#define SITAR_A_INTR_TEST0__POR (0x00000000)
+#define SITAR_A_INTR_TEST1 (0xA5)
+#define SITAR_A_INTR_TEST1__POR (0x00000000)
+#define SITAR_A_INTR_TEST2 (0xA6)
+#define SITAR_A_INTR_TEST2__POR (0x00000000)
+#define SITAR_A_INTR_SET0 (0xA8)
+#define SITAR_A_INTR_SET0__POR (0x00000000)
+#define SITAR_A_INTR_SET1 (0xA9)
+#define SITAR_A_INTR_SET1__POR (0x00000000)
+#define SITAR_A_INTR_SET2 (0xAA)
+#define SITAR_A_INTR_SET2__POR (0x00000000)
+#define SITAR_A_CDC_TX_I2S_SCK_MODE (0xC0)
+#define SITAR_A_CDC_TX_I2S_SCK_MODE__POR (0x00000000)
+#define SITAR_A_CDC_TX_I2S_WS_MODE (0xC1)
+#define SITAR_A_CDC_TX_I2S_WS_MODE__POR (0x00000000)
+#define SITAR_A_CDC_DMIC_DATA0_MODE (0xC4)
+#define SITAR_A_CDC_DMIC_DATA0_MODE__POR (0x00000000)
+#define SITAR_A_CDC_DMIC_CLK0_MODE (0xC5)
+#define SITAR_A_CDC_DMIC_CLK0_MODE__POR (0x00000000)
+#define SITAR_A_CDC_DMIC_DATA1_MODE (0xC6)
+#define SITAR_A_CDC_DMIC_DATA1_MODE__POR (0x00000000)
+#define SITAR_A_CDC_DMIC_CLK1_MODE (0xC7)
+#define SITAR_A_CDC_DMIC_CLK1_MODE__POR (0x00000000)
+#define SITAR_A_CDC_TX_I2S_SD0_MODE (0xC8)
+#define SITAR_A_CDC_TX_I2S_SD0_MODE__POR (0x00000000)
+#define SITAR_A_CDC_INTR_MODE (0xC9)
+#define SITAR_A_CDC_INTR_MODE__POR (0x00000000)
+#define SITAR_A_CDC_RX_I2S_SD0_MODE (0xCA)
+#define SITAR_A_CDC_RX_I2S_SD0_MODE__POR (0x00000000)
+#define SITAR_A_CDC_RX_I2S_SD1_MODE (0xCB)
+#define SITAR_A_CDC_RX_I2S_SD1_MODE__POR (0x00000000)
+#define SITAR_A_BIAS_REF_CTL (0x100)
+#define SITAR_A_BIAS_REF_CTL__POR (0x0000001c)
+#define SITAR_A_BIAS_CENTRAL_BG_CTL (0x101)
+#define SITAR_A_BIAS_CENTRAL_BG_CTL__POR (0x00000050)
+#define SITAR_A_BIAS_PRECHRG_CTL (0x102)
+#define SITAR_A_BIAS_PRECHRG_CTL__POR (0x00000007)
+#define SITAR_A_BIAS_CURR_CTL_1 (0x103)
+#define SITAR_A_BIAS_CURR_CTL_1__POR (0x00000052)
+#define SITAR_A_BIAS_CURR_CTL_2 (0x104)
+#define SITAR_A_BIAS_CURR_CTL_2__POR (0x00000000)
+#define SITAR_A_BIAS_OSC_BG_CTL (0x105)
+#define SITAR_A_BIAS_OSC_BG_CTL__POR (0x00000016)
+#define SITAR_A_CLK_BUFF_EN1 (0x108)
+#define SITAR_A_CLK_BUFF_EN1__POR (0x00000004)
+#define SITAR_A_CLK_BUFF_EN2 (0x109)
+#define SITAR_A_CLK_BUFF_EN2__POR (0x00000002)
+#define SITAR_A_LDO_H_MODE_1 (0x110)
+#define SITAR_A_LDO_H_MODE_1__POR (0x00000065)
+#define SITAR_A_LDO_H_MODE_2 (0x111)
+#define SITAR_A_LDO_H_MODE_2__POR (0x000000a8)
+#define SITAR_A_LDO_H_LOOP_CTL (0x112)
+#define SITAR_A_LDO_H_LOOP_CTL__POR (0x0000006b)
+#define SITAR_A_LDO_H_COMP_1 (0x113)
+#define SITAR_A_LDO_H_COMP_1__POR (0x00000084)
+#define SITAR_A_LDO_H_COMP_2 (0x114)
+#define SITAR_A_LDO_H_COMP_2__POR (0x000000e0)
+#define SITAR_A_LDO_H_BIAS_1 (0x115)
+#define SITAR_A_LDO_H_BIAS_1__POR (0x0000006d)
+#define SITAR_A_LDO_H_BIAS_2 (0x116)
+#define SITAR_A_LDO_H_BIAS_2__POR (0x000000a5)
+#define SITAR_A_LDO_H_BIAS_3 (0x117)
+#define SITAR_A_LDO_H_BIAS_3__POR (0x00000060)
+#define SITAR_A_MICB_CFILT_1_CTL (0x128)
+#define SITAR_A_MICB_CFILT_1_CTL__POR (0x00000040)
+#define SITAR_A_MICB_CFILT_1_VAL (0x129)
+#define SITAR_A_MICB_CFILT_1_VAL__POR (0x00000080)
+#define SITAR_A_MICB_CFILT_1_PRECHRG (0x12A)
+#define SITAR_A_MICB_CFILT_1_PRECHRG__POR (0x00000038)
+#define SITAR_A_MICB_1_CTL (0x12B)
+#define SITAR_A_MICB_1_CTL__POR (0x00000016)
+#define SITAR_A_MICB_1_INT_RBIAS (0x12C)
+#define SITAR_A_MICB_1_INT_RBIAS__POR (0x00000024)
+#define SITAR_A_MICB_1_MBHC (0x12D)
+#define SITAR_A_MICB_1_MBHC__POR (0x00000001)
+#define SITAR_A_MICB_CFILT_2_CTL (0x12E)
+#define SITAR_A_MICB_CFILT_2_CTL__POR (0x00000040)
+#define SITAR_A_MICB_CFILT_2_VAL (0x12F)
+#define SITAR_A_MICB_CFILT_2_VAL__POR (0x00000080)
+#define SITAR_A_MICB_CFILT_2_PRECHRG (0x130)
+#define SITAR_A_MICB_CFILT_2_PRECHRG__POR (0x00000038)
+#define SITAR_A_MICB_2_CTL (0x131)
+#define SITAR_A_MICB_2_CTL__POR (0x00000016)
+#define SITAR_A_MICB_2_INT_RBIAS (0x132)
+#define SITAR_A_MICB_2_INT_RBIAS__POR (0x00000024)
+#define SITAR_A_MICB_2_MBHC (0x133)
+#define SITAR_A_MICB_2_MBHC__POR (0x00000002)
+#define SITAR_A_TX_COM_BIAS (0x14C)
+#define SITAR_A_TX_COM_BIAS__POR (0x000000e0)
+#define SITAR_A_MBHC_SCALING_MUX_1 (0x14E)
+#define SITAR_A_MBHC_SCALING_MUX_1__POR (0x00000000)
+#define SITAR_A_MBHC_SCALING_MUX_2 (0x14F)
+#define SITAR_A_MBHC_SCALING_MUX_2__POR (0x00000080)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_1 (0x151)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_1__POR (0x00000000)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_2 (0x152)
+#define SITAR_A_TX_SUP_SWITCH_CTRL_2__POR (0x00000080)
+#define SITAR_A_TX_1_2_EN (0x153)
+#define SITAR_A_TX_1_2_EN__POR (0x00000000)
+#define SITAR_A_TX_1_2_TEST_EN (0x154)
+#define SITAR_A_TX_1_2_TEST_EN__POR (0x000000cc)
+#define SITAR_A_TX_1_2_ADC_CH1 (0x155)
+#define SITAR_A_TX_1_2_ADC_CH1__POR (0x00000044)
+#define SITAR_A_TX_1_2_ADC_CH2 (0x156)
+#define SITAR_A_TX_1_2_ADC_CH2__POR (0x00000044)
+#define SITAR_A_TX_1_2_ATEST_REFCTRL (0x157)
+#define SITAR_A_TX_1_2_ATEST_REFCTRL__POR (0x00000000)
+#define SITAR_A_TX_1_2_TEST_CTL (0x158)
+#define SITAR_A_TX_1_2_TEST_CTL__POR (0x00000038)
+#define SITAR_A_TX_1_2_TEST_BLOCK_EN (0x159)
+#define SITAR_A_TX_1_2_TEST_BLOCK_EN__POR (0x000000fc)
+#define SITAR_A_TX_1_2_TXFE_CLKDIV (0x15A)
+#define SITAR_A_TX_1_2_TXFE_CLKDIV__POR (0x000000ee)
+#define SITAR_A_TX_1_2_SAR_ERR_CH1 (0x15B)
+#define SITAR_A_TX_1_2_SAR_ERR_CH1__POR (0x00000000)
+#define SITAR_A_TX_1_2_SAR_ERR_CH2 (0x15C)
+#define SITAR_A_TX_1_2_SAR_ERR_CH2__POR (0x00000000)
+#define SITAR_A_TX_3_EN (0x15D)
+#define SITAR_A_TX_3_EN__POR (0x00000000)
+#define SITAR_A_TX_3_TEST_EN (0x15E)
+#define SITAR_A_TX_3_TEST_EN__POR (0x000000cc)
+#define SITAR_A_TX_3_ADC (0x15F)
+#define SITAR_A_TX_3_ADC__POR (0x00000044)
+#define SITAR_A_TX_3_MBHC_ATEST_REFCTRL (0x161)
+#define SITAR_A_TX_3_MBHC_ATEST_REFCTRL__POR (0x00000000)
+#define SITAR_A_TX_3_TEST_CTL (0x162)
+#define SITAR_A_TX_3_TEST_CTL__POR (0x00000038)
+#define SITAR_A_TX_3_TEST_BLOCK_EN (0x163)
+#define SITAR_A_TX_3_TEST_BLOCK_EN__POR (0x000000fc)
+#define SITAR_A_TX_3_TXFE_CKDIV (0x164)
+#define SITAR_A_TX_3_TXFE_CKDIV__POR (0x000000ee)
+#define SITAR_A_TX_3_SAR_ERR (0x165)
+#define SITAR_A_TX_3_SAR_ERR__POR (0x00000000)
+#define SITAR_A_TX_4_MBHC_EN (0x171)
+#define SITAR_A_TX_4_MBHC_EN__POR (0x0000000c)
+#define SITAR_A_TX_4_MBHC_ADC (0x173)
+#define SITAR_A_TX_4_MBHC_ADC__POR (0x00000044)
+#define SITAR_A_TX_4_MBHC_TEST_CTL (0x174)
+#define SITAR_A_TX_4_MBHC_TEST_CTL__POR (0x00000038)
+#define SITAR_A_TX_4_MBHC_SAR_ERR (0x175)
+#define SITAR_A_TX_4_MBHC_SAR_ERR__POR (0x00000000)
+#define SITAR_A_TX_4_TXFE_CLKDIV (0x176)
+#define SITAR_A_TX_4_TXFE_CLKDIV__POR (0x0000001c)
+#define SITAR_A_AUX_COM_CTL (0x180)
+#define SITAR_A_AUX_COM_CTL__POR (0x00000034)
+#define SITAR_A_AUX_COM_ATEST (0x181)
+#define SITAR_A_AUX_COM_ATEST__POR (0x00000000)
+#define SITAR_A_AUX_L_EN (0x182)
+#define SITAR_A_AUX_L_EN__POR (0x00000000)
+#define SITAR_A_AUX_L_GAIN (0x183)
+#define SITAR_A_AUX_L_GAIN__POR (0x0000001f)
+#define SITAR_A_AUX_L_PA_CONN (0x184)
+#define SITAR_A_AUX_L_PA_CONN__POR (0x00000000)
+#define SITAR_A_AUX_L_PA_CONN_INV (0x185)
+#define SITAR_A_AUX_L_PA_CONN_INV__POR (0x00000000)
+#define SITAR_A_AUX_R_EN (0x186)
+#define SITAR_A_AUX_R_EN__POR (0x00000000)
+#define SITAR_A_AUX_R_GAIN (0x187)
+#define SITAR_A_AUX_R_GAIN__POR (0x0000001f)
+#define SITAR_A_AUX_R_PA_CONN (0x188)
+#define SITAR_A_AUX_R_PA_CONN__POR (0x00000000)
+#define SITAR_A_AUX_R_PA_CONN_INV (0x189)
+#define SITAR_A_AUX_R_PA_CONN_INV__POR (0x00000000)
+#define SITAR_A_CP_EN (0x192)
+#define SITAR_A_CP_EN__POR (0x000000e6)
+#define SITAR_A_CP_CLK (0x193)
+#define SITAR_A_CP_CLK__POR (0x00000029)
+#define SITAR_A_CP_STATIC (0x194)
+#define SITAR_A_CP_STATIC__POR (0x00000010)
+#define SITAR_A_CP_DCC1 (0x195)
+#define SITAR_A_CP_DCC1__POR (0x00000052)
+#define SITAR_A_CP_DCC3 (0x196)
+#define SITAR_A_CP_DCC3__POR (0x00000001)
+#define SITAR_A_CP_ATEST (0x197)
+#define SITAR_A_CP_ATEST__POR (0x00000000)
+#define SITAR_A_CP_DTEST (0x198)
+#define SITAR_A_CP_DTEST__POR (0x00000000)
+#define SITAR_A_RX_COM_TIMER_DIV (0x19E)
+#define SITAR_A_RX_COM_TIMER_DIV__POR (0x000000e8)
+#define SITAR_A_RX_COM_OCP_CTL (0x19F)
+#define SITAR_A_RX_COM_OCP_CTL__POR (0x0000001f)
+#define SITAR_A_RX_COM_OCP_COUNT (0x1A0)
+#define SITAR_A_RX_COM_OCP_COUNT__POR (0x00000077)
+#define SITAR_A_RX_COM_DAC_CTL (0x1A1)
+#define SITAR_A_RX_COM_DAC_CTL__POR (0x00000000)
+#define SITAR_A_RX_COM_BIAS (0x1A2)
+#define SITAR_A_RX_COM_BIAS__POR (0x00000000)
+#define SITAR_A_RX_HPH_BIAS_PA (0x1A6)
+#define SITAR_A_RX_HPH_BIAS_PA__POR (0x00000057)
+#define SITAR_A_RX_HPH_BIAS_LDO (0x1A7)
+#define SITAR_A_RX_HPH_BIAS_LDO__POR (0x00000056)
+#define SITAR_A_RX_HPH_BIAS_CNP (0x1A8)
+#define SITAR_A_RX_HPH_BIAS_CNP__POR (0x0000008a)
+#define SITAR_A_RX_HPH_BIAS_WG (0x1A9)
+#define SITAR_A_RX_HPH_BIAS_WG__POR (0x00000060)
+#define SITAR_A_RX_HPH_OCP_CTL (0x1AA)
+#define SITAR_A_RX_HPH_OCP_CTL__POR (0x000000e8)
+#define SITAR_A_RX_HPH_CNP_EN (0x1AB)
+#define SITAR_A_RX_HPH_CNP_EN__POR (0x00000080)
+#define SITAR_A_RX_HPH_CNP_WG_CTL (0x1AC)
+#define SITAR_A_RX_HPH_CNP_WG_CTL__POR (0x000000dc)
+#define SITAR_A_RX_HPH_CNP_WG_TIME (0x1AD)
+#define SITAR_A_RX_HPH_CNP_WG_TIME__POR (0x00000028)
+#define SITAR_A_RX_HPH_L_GAIN (0x1AE)
+#define SITAR_A_RX_HPH_L_GAIN__POR (0x00000000)
+#define SITAR_A_RX_HPH_L_TEST (0x1AF)
+#define SITAR_A_RX_HPH_L_TEST__POR (0x00000001)
+#define SITAR_A_RX_HPH_L_PA_CTL (0x1B0)
+#define SITAR_A_RX_HPH_L_PA_CTL__POR (0x00000040)
+#define SITAR_A_RX_HPH_L_DAC_CTL (0x1B1)
+#define SITAR_A_RX_HPH_L_DAC_CTL__POR (0x00000000)
+#define SITAR_A_RX_HPH_L_ATEST (0x1B2)
+#define SITAR_A_RX_HPH_L_ATEST__POR (0x00000000)
+#define SITAR_A_RX_HPH_L_STATUS (0x1B3)
+#define SITAR_A_RX_HPH_L_STATUS__POR (0x00000004)
+#define SITAR_A_RX_HPH_R_GAIN (0x1B4)
+#define SITAR_A_RX_HPH_R_GAIN__POR (0x00000000)
+#define SITAR_A_RX_HPH_R_TEST (0x1B5)
+#define SITAR_A_RX_HPH_R_TEST__POR (0x00000001)
+#define SITAR_A_RX_HPH_R_PA_CTL (0x1B6)
+#define SITAR_A_RX_HPH_R_PA_CTL__POR (0x00000040)
+#define SITAR_A_RX_HPH_R_DAC_CTL (0x1B7)
+#define SITAR_A_RX_HPH_R_DAC_CTL__POR (0x00000000)
+#define SITAR_A_RX_HPH_R_ATEST (0x1B8)
+#define SITAR_A_RX_HPH_R_ATEST__POR (0x00000000)
+#define SITAR_A_RX_HPH_R_STATUS (0x1B9)
+#define SITAR_A_RX_HPH_R_STATUS__POR (0x00000004)
+#define SITAR_A_RX_EAR_BIAS_PA (0x1BA)
+#define SITAR_A_RX_EAR_BIAS_PA__POR (0x000000a6)
+#define SITAR_A_RX_EAR_BIAS_CMBUFF (0x1BB)
+#define SITAR_A_RX_EAR_BIAS_CMBUFF__POR (0x000000a0)
+#define SITAR_A_RX_EAR_EN (0x1BC)
+#define SITAR_A_RX_EAR_EN__POR (0x00000000)
+#define SITAR_A_RX_EAR_GAIN (0x1BD)
+#define SITAR_A_RX_EAR_GAIN__POR (0x00000002)
+#define SITAR_A_RX_EAR_CMBUFF (0x1BE)
+#define SITAR_A_RX_EAR_CMBUFF__POR (0x00000004)
+#define SITAR_A_RX_EAR_ICTL (0x1BF)
+#define SITAR_A_RX_EAR_ICTL__POR (0x00000040)
+#define SITAR_A_RX_EAR_CCOMP (0x1C0)
+#define SITAR_A_RX_EAR_CCOMP__POR (0x00000008)
+#define SITAR_A_RX_EAR_VCM (0x1C1)
+#define SITAR_A_RX_EAR_VCM__POR (0x00000003)
+#define SITAR_A_RX_EAR_CNP (0x1C2)
+#define SITAR_A_RX_EAR_CNP__POR (0x000000f2)
+#define SITAR_A_RX_EAR_ATEST (0x1C3)
+#define SITAR_A_RX_EAR_ATEST__POR (0x00000000)
+#define SITAR_A_RX_EAR_STATUS (0x1C5)
+#define SITAR_A_RX_EAR_STATUS__POR (0x00000004)
+#define SITAR_A_RX_LINE_BIAS_PA (0x1C6)
+#define SITAR_A_RX_LINE_BIAS_PA__POR (0x000000aa)
+#define SITAR_A_RX_LINE_BIAS_LDO (0x1C7)
+#define SITAR_A_RX_LINE_BIAS_LDO__POR (0x00000086)
+#define SITAR_A_RX_LINE_BIAS_CNP1 (0x1C8)
+#define SITAR_A_RX_LINE_BIAS_CNP1__POR (0x00000060)
+#define SITAR_A_RX_LINE_COM (0x1C9)
+#define SITAR_A_RX_LINE_COM__POR (0x00000000)
+#define SITAR_A_RX_LINE_CNP_EN (0x1CA)
+#define SITAR_A_RX_LINE_CNP_EN__POR (0x00000080)
+#define SITAR_A_RX_LINE_CNP_WG_CTL (0x1CB)
+#define SITAR_A_RX_LINE_CNP_WG_CTL__POR (0x000000dc)
+#define SITAR_A_RX_LINE_CNP_WG_TIME (0x1CC)
+#define SITAR_A_RX_LINE_CNP_WG_TIME__POR (0x00000028)
+#define SITAR_A_RX_LINE_1_GAIN (0x1CD)
+#define SITAR_A_RX_LINE_1_GAIN__POR (0x00000000)
+#define SITAR_A_RX_LINE_1_TEST (0x1CE)
+#define SITAR_A_RX_LINE_1_TEST__POR (0x00000001)
+#define SITAR_A_RX_LINE_1_DAC_CTL (0x1CF)
+#define SITAR_A_RX_LINE_1_DAC_CTL__POR (0x00000000)
+#define SITAR_A_RX_LINE_1_STATUS (0x1D0)
+#define SITAR_A_RX_LINE_1_STATUS__POR (0x00000004)
+#define SITAR_A_RX_LINE_2_GAIN (0x1D1)
+#define SITAR_A_RX_LINE_2_GAIN__POR (0x00000000)
+#define SITAR_A_RX_LINE_2_TEST (0x1D2)
+#define SITAR_A_RX_LINE_2_TEST__POR (0x00000001)
+#define SITAR_A_RX_LINE_2_DAC_CTL (0x1D3)
+#define SITAR_A_RX_LINE_2_DAC_CTL__POR (0x00000000)
+#define SITAR_A_RX_LINE_2_STATUS (0x1D4)
+#define SITAR_A_RX_LINE_2_STATUS__POR (0x00000004)
+#define SITAR_A_RX_LINE_BIAS_CNP2 (0x1E1)
+#define SITAR_A_RX_LINE_BIAS_CNP2__POR (0x0000008a)
+#define SITAR_A_RX_LINE_OCP_CTL (0x1E2)
+#define SITAR_A_RX_LINE_OCP_CTL__POR (0x000000e8)
+#define SITAR_A_RX_LINE_1_PA_CTL (0x1E3)
+#define SITAR_A_RX_LINE_1_PA_CTL__POR (0x00000040)
+#define SITAR_A_RX_LINE_2_PA_CTL (0x1E4)
+#define SITAR_A_RX_LINE_2_PA_CTL__POR (0x00000040)
+#define SITAR_A_RX_LINE_CNP_DBG (0x1EC)
+#define SITAR_A_RX_LINE_CNP_DBG__POR (0x00000000)
+#define SITAR_A_MBHC_HPH (0x1ED)
+#define SITAR_A_MBHC_HPH__POR (0x00000048)
+#define SITAR_A_RC_OSC_FREQ (0x1F7)
+#define SITAR_A_RC_OSC_FREQ__POR (0x00000046)
+#define SITAR_A_RC_OSC_TEST (0x1F8)
+#define SITAR_A_RC_OSC_TEST__POR (0x0000000a)
+#define SITAR_A_RC_OSC_STATUS (0x1F9)
+#define SITAR_A_RC_OSC_STATUS__POR (0x0000001c)
+#define SITAR_A_RC_OSC_TUNER (0x1FA)
+#define SITAR_A_RC_OSC_TUNER__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_CTL (0x200)
+#define SITAR_A_CDC_ANC1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_SHIFT (0x201)
+#define SITAR_A_CDC_ANC1_SHIFT__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B1_CTL (0x202)
+#define SITAR_A_CDC_ANC1_IIR_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B2_CTL (0x203)
+#define SITAR_A_CDC_ANC1_IIR_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B3_CTL (0x204)
+#define SITAR_A_CDC_ANC1_IIR_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_IIR_B4_CTL (0x205)
+#define SITAR_A_CDC_ANC1_IIR_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B1_CTL (0x206)
+#define SITAR_A_CDC_ANC1_LPF_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B2_CTL (0x207)
+#define SITAR_A_CDC_ANC1_LPF_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_LPF_B3_CTL (0x208)
+#define SITAR_A_CDC_ANC1_LPF_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_SPARE (0x209)
+#define SITAR_A_CDC_ANC1_SPARE__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_SMLPF_CTL (0x20A)
+#define SITAR_A_CDC_ANC1_SMLPF_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC1_DCFLT_CTL (0x20B)
+#define SITAR_A_CDC_ANC1_DCFLT_CTL__POR (0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER (0x220)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR (0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN (0x221)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG (0x222)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX1_MUX_CTL (0x223)
+#define SITAR_A_CDC_TX1_MUX_CTL__POR (0x00000008)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL (0x224)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR (0x00000003)
+#define SITAR_A_CDC_TX1_DMIC_CTL (0x225)
+#define SITAR_A_CDC_TX1_DMIC_CTL__POR (0x00000000)
+#define SITAR_A_CDC_SRC1_PDA_CFG (0x2A0)
+#define SITAR_A_CDC_SRC1_PDA_CFG__POR (0x00000000)
+#define SITAR_A_CDC_SRC1_FS_CTL (0x2A1)
+#define SITAR_A_CDC_SRC1_FS_CTL__POR (0x0000001b)
+
+#define SITAR_A_CDC_RX1_B1_CTL (0x000002B0)
+#define SITAR_A_CDC_RX1_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B1_CTL (0x000002B8)
+#define SITAR_A_CDC_RX2_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B1_CTL (0x000002C0)
+#define SITAR_A_CDC_RX3_B1_CTL__POR (0x00000000)
+
+#define SITAR_A_CDC_RX1_B2_CTL (0x000002B1)
+#define SITAR_A_CDC_RX1_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B2_CTL (0x000002B9)
+#define SITAR_A_CDC_RX2_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B2_CTL (0x000002C1)
+#define SITAR_A_CDC_RX3_B2_CTL__POR (0x00000000)
+
+#define SITAR_A_CDC_RX1_B3_CTL (0x000002B2)
+#define SITAR_A_CDC_RX1_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B3_CTL (0x000002BA)
+#define SITAR_A_CDC_RX2_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B3_CTL (0x000002C2)
+#define SITAR_A_CDC_RX3_B3_CTL__POR (0x00000000)
+
+#define SITAR_A_CDC_RX1_B4_CTL (0x000002B3)
+#define SITAR_A_CDC_RX1_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B4_CTL (0x000002BB)
+#define SITAR_A_CDC_RX2_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B4_CTL (0x000002C3)
+#define SITAR_A_CDC_RX3_B4_CTL__POR (0x00000000)
+
+#define SITAR_A_CDC_RX1_B5_CTL (0x000002B4)
+#define SITAR_A_CDC_RX1_B5_CTL__POR (0x00000060)
+#define SITAR_A_CDC_RX2_B5_CTL (0x000002BC)
+#define SITAR_A_CDC_RX2_B5_CTL__POR (0x00000060)
+#define SITAR_A_CDC_RX3_B5_CTL (0x000002C4)
+#define SITAR_A_CDC_RX3_B5_CTL__POR (0x00000060)
+
+#define SITAR_A_CDC_RX1_B6_CTL (0x000002B5)
+#define SITAR_A_CDC_RX1_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B6_CTL (0x000002BD)
+#define SITAR_A_CDC_RX2_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B6_CTL (0x000002C5)
+#define SITAR_A_CDC_RX3_B6_CTL__POR (0x00000000)
+
+
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL (0x2B6)
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL (0x2B7)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL (0x300)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL (0x301)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL (0x302)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL (0x303)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_DMIC_CTL (0x304)
+#define SITAR_A_CDC_CLK_DMIC_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_RX_I2S_CTL (0x305)
+#define SITAR_A_CDC_CLK_RX_I2S_CTL__POR (0x00000003)
+#define SITAR_A_CDC_CLK_TX_I2S_CTL (0x306)
+#define SITAR_A_CDC_CLK_TX_I2S_CTL__POR (0x00000003)
+#define SITAR_A_CDC_CLK_OTHR_RESET_CTL (0x307)
+#define SITAR_A_CDC_CLK_OTHR_RESET_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL (0x308)
+#define SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_OTHR_CTL (0x30A)
+#define SITAR_A_CDC_CLK_OTHR_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL (0x30B)
+#define SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_ANC_CLK_EN_CTL (0x30C)
+#define SITAR_A_CDC_CLK_ANC_CLK_EN_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_RX_B1_CTL (0x30D)
+#define SITAR_A_CDC_CLK_RX_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_RX_B2_CTL (0x30E)
+#define SITAR_A_CDC_CLK_RX_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_MCLK_CTL (0x30F)
+#define SITAR_A_CDC_CLK_MCLK_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_PDM_CTL (0x310)
+#define SITAR_A_CDC_CLK_PDM_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_SD_CTL (0x311)
+#define SITAR_A_CDC_CLK_SD_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_LP_CTL (0x312)
+#define SITAR_A_CDC_CLK_LP_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL (0x320)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR (0x00000007)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL (0x321)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR (0x00000013)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL (0x322)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR (0x0000001b)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL (0x323)
+#define SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR (0x0000007f)
+#define SITAR_A_CDC_CLSG_GAIN_THRESH_CTL (0x324)
+#define SITAR_A_CDC_CLSG_GAIN_THRESH_CTL__POR (0x00000026)
+#define SITAR_A_CDC_CLSG_TIMER_B1_CFG (0x325)
+#define SITAR_A_CDC_CLSG_TIMER_B1_CFG__POR (0x0000000a)
+#define SITAR_A_CDC_CLSG_TIMER_B2_CFG (0x326)
+#define SITAR_A_CDC_CLSG_TIMER_B2_CFG__POR (0x00000000)
+#define SITAR_A_CDC_CLSG_CTL (0x327)
+#define SITAR_A_CDC_CLSG_CTL__POR (0x00000013)
+#define SITAR_A_CDC_IIR1_GAIN_B1_CTL (0x340)
+#define SITAR_A_CDC_IIR1_GAIN_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B2_CTL (0x341)
+#define SITAR_A_CDC_IIR1_GAIN_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B3_CTL (0x342)
+#define SITAR_A_CDC_IIR1_GAIN_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B4_CTL (0x343)
+#define SITAR_A_CDC_IIR1_GAIN_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B5_CTL (0x344)
+#define SITAR_A_CDC_IIR1_GAIN_B5_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B6_CTL (0x345)
+#define SITAR_A_CDC_IIR1_GAIN_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B7_CTL (0x346)
+#define SITAR_A_CDC_IIR1_GAIN_B7_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_GAIN_B8_CTL (0x347)
+#define SITAR_A_CDC_IIR1_GAIN_B8_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_CTL (0x348)
+#define SITAR_A_CDC_IIR1_CTL__POR (0x00000040)
+#define SITAR_A_CDC_IIR1_GAIN_TIMER_CTL (0x349)
+#define SITAR_A_CDC_IIR1_GAIN_TIMER_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B1_CTL (0x34A)
+#define SITAR_A_CDC_IIR1_COEF_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B2_CTL (0x34B)
+#define SITAR_A_CDC_IIR1_COEF_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B3_CTL (0x34C)
+#define SITAR_A_CDC_IIR1_COEF_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B4_CTL (0x34D)
+#define SITAR_A_CDC_IIR1_COEF_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_IIR1_COEF_B5_CTL (0x34E)
+#define SITAR_A_CDC_IIR1_COEF_B5_CTL__POR (0x00000000)
+#define SITAR_A_CDC_TOP_GAIN_UPDATE (0x360)
+#define SITAR_A_CDC_TOP_GAIN_UPDATE__POR (0x00000000)
+#define SITAR_A_CDC_TOP_RDAC_DOUT_CTL (0x361)
+#define SITAR_A_CDC_TOP_RDAC_DOUT_CTL__POR (0x00000000)
+#define SITAR_A_CDC_DEBUG_B1_CTL (0x368)
+#define SITAR_A_CDC_DEBUG_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_DEBUG_B2_CTL (0x369)
+#define SITAR_A_CDC_DEBUG_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_DEBUG_B3_CTL (0x36A)
+#define SITAR_A_CDC_DEBUG_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_DEBUG_B4_CTL (0x36B)
+#define SITAR_A_CDC_DEBUG_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_DEBUG_B5_CTL (0x36C)
+#define SITAR_A_CDC_DEBUG_B5_CTL__POR (0x00000000)
+#define SITAR_A_CDC_DEBUG_B6_CTL (0x36D)
+#define SITAR_A_CDC_DEBUG_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_DEBUG_B7_CTL (0x36E)
+#define SITAR_A_CDC_DEBUG_B7_CTL__POR (0x00000000)
+#define SITAR_A_CDC_COMP1_B1_CTL (0x370)
+#define SITAR_A_CDC_COMP1_B1_CTL__POR (0x00000030)
+#define SITAR_A_CDC_COMP1_B2_CTL (0x371)
+#define SITAR_A_CDC_COMP1_B2_CTL__POR (0x000000b5)
+#define SITAR_A_CDC_COMP1_B3_CTL (0x372)
+#define SITAR_A_CDC_COMP1_B3_CTL__POR (0x00000028)
+#define SITAR_A_CDC_COMP1_B4_CTL (0x373)
+#define SITAR_A_CDC_COMP1_B4_CTL__POR (0x0000003c)
+#define SITAR_A_CDC_COMP1_B5_CTL (0x374)
+#define SITAR_A_CDC_COMP1_B5_CTL__POR (0x0000001f)
+#define SITAR_A_CDC_COMP1_B6_CTL (0x375)
+#define SITAR_A_CDC_COMP1_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS (0x376)
+#define SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x00000003)
+#define SITAR_A_CDC_COMP1_FS_CFG (0x377)
+#define SITAR_A_CDC_COMP1_FS_CFG__POR (0x0000001b)
+#define SITAR_A_CDC_CONN_RX1_B1_CTL (0x380)
+#define SITAR_A_CDC_CONN_RX1_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX1_B2_CTL (0x381)
+#define SITAR_A_CDC_CONN_RX1_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX1_B3_CTL (0x382)
+#define SITAR_A_CDC_CONN_RX1_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B1_CTL (0x383)
+#define SITAR_A_CDC_CONN_RX2_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B2_CTL (0x384)
+#define SITAR_A_CDC_CONN_RX2_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX2_B3_CTL (0x385)
+#define SITAR_A_CDC_CONN_RX2_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B1_CTL (0x386)
+#define SITAR_A_CDC_CONN_RX3_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B2_CTL (0x387)
+#define SITAR_A_CDC_CONN_RX3_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX3_B3_CTL (0x388)
+#define SITAR_A_CDC_CONN_RX3_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_ANC_B1_CTL (0x391)
+#define SITAR_A_CDC_CONN_ANC_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_ANC_B2_CTL (0x392)
+#define SITAR_A_CDC_CONN_ANC_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_TX_B1_CTL (0x393)
+#define SITAR_A_CDC_CONN_TX_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_TX_B2_CTL (0x394)
+#define SITAR_A_CDC_CONN_TX_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B1_CTL (0x397)
+#define SITAR_A_CDC_CONN_EQ1_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B2_CTL (0x398)
+#define SITAR_A_CDC_CONN_EQ1_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B3_CTL (0x399)
+#define SITAR_A_CDC_CONN_EQ1_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ1_B4_CTL (0x39A)
+#define SITAR_A_CDC_CONN_EQ1_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B1_CTL (0x39B)
+#define SITAR_A_CDC_CONN_EQ2_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B2_CTL (0x39C)
+#define SITAR_A_CDC_CONN_EQ2_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B3_CTL (0x39D)
+#define SITAR_A_CDC_CONN_EQ2_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_EQ2_B4_CTL (0x39E)
+#define SITAR_A_CDC_CONN_EQ2_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_SRC1_B1_CTL (0x39F)
+#define SITAR_A_CDC_CONN_SRC1_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_SRC1_B2_CTL (0x3A0)
+#define SITAR_A_CDC_CONN_SRC1_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_SRC2_B1_CTL (0x3A1)
+#define SITAR_A_CDC_CONN_SRC2_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_SRC2_B2_CTL (0x3A2)
+#define SITAR_A_CDC_CONN_SRC2_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B1_CTL (0x3A3)
+#define SITAR_A_CDC_CONN_TX_SB_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B2_CTL (0x3A4)
+#define SITAR_A_CDC_CONN_TX_SB_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B3_CTL (0x3A5)
+#define SITAR_A_CDC_CONN_TX_SB_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B4_CTL (0x3A6)
+#define SITAR_A_CDC_CONN_TX_SB_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_TX_SB_B5_CTL (0x3A7)
+#define SITAR_A_CDC_CONN_TX_SB_B5_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX_SB_B1_CTL (0x3AE)
+#define SITAR_A_CDC_CONN_RX_SB_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_RX_SB_B2_CTL (0x3AF)
+#define SITAR_A_CDC_CONN_RX_SB_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_CLSG_CTL (0x3B0)
+#define SITAR_A_CDC_CONN_CLSG_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CONN_SPARE (0x3B1)
+#define SITAR_A_CDC_CONN_SPARE__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_EN_CTL (0x3C0)
+#define SITAR_A_CDC_MBHC_EN_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_FIR_B1_CFG (0x3C1)
+#define SITAR_A_CDC_MBHC_FIR_B1_CFG__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_FIR_B2_CFG (0x3C2)
+#define SITAR_A_CDC_MBHC_FIR_B2_CFG__POR (0x00000006)
+#define SITAR_A_CDC_MBHC_TIMER_B1_CTL (0x3C3)
+#define SITAR_A_CDC_MBHC_TIMER_B1_CTL__POR (0x00000003)
+#define SITAR_A_CDC_MBHC_TIMER_B2_CTL (0x3C4)
+#define SITAR_A_CDC_MBHC_TIMER_B2_CTL__POR (0x00000009)
+#define SITAR_A_CDC_MBHC_TIMER_B3_CTL (0x3C5)
+#define SITAR_A_CDC_MBHC_TIMER_B3_CTL__POR (0x0000001e)
+#define SITAR_A_CDC_MBHC_TIMER_B4_CTL (0x3C6)
+#define SITAR_A_CDC_MBHC_TIMER_B4_CTL__POR (0x00000045)
+#define SITAR_A_CDC_MBHC_TIMER_B5_CTL (0x3C7)
+#define SITAR_A_CDC_MBHC_TIMER_B5_CTL__POR (0x00000004)
+#define SITAR_A_CDC_MBHC_TIMER_B6_CTL (0x3C8)
+#define SITAR_A_CDC_MBHC_TIMER_B6_CTL__POR (0x00000078)
+#define SITAR_A_CDC_MBHC_B1_STATUS (0x3C9)
+#define SITAR_A_CDC_MBHC_B1_STATUS__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_B2_STATUS (0x3CA)
+#define SITAR_A_CDC_MBHC_B2_STATUS__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_B3_STATUS (0x3CB)
+#define SITAR_A_CDC_MBHC_B3_STATUS__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_B4_STATUS (0x3CC)
+#define SITAR_A_CDC_MBHC_B4_STATUS__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_B5_STATUS (0x3CD)
+#define SITAR_A_CDC_MBHC_B5_STATUS__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_B1_CTL (0x3CE)
+#define SITAR_A_CDC_MBHC_B1_CTL__POR (0x000000c0)
+#define SITAR_A_CDC_MBHC_B2_CTL (0x3CF)
+#define SITAR_A_CDC_MBHC_B2_CTL__POR (0x0000005d)
+#define SITAR_A_CDC_MBHC_VOLT_B1_CTL (0x3D0)
+#define SITAR_A_CDC_MBHC_VOLT_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B2_CTL (0x3D1)
+#define SITAR_A_CDC_MBHC_VOLT_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B3_CTL (0x3D2)
+#define SITAR_A_CDC_MBHC_VOLT_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B4_CTL (0x3D3)
+#define SITAR_A_CDC_MBHC_VOLT_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B5_CTL (0x3D4)
+#define SITAR_A_CDC_MBHC_VOLT_B5_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B6_CTL (0x3D5)
+#define SITAR_A_CDC_MBHC_VOLT_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B7_CTL (0x3D6)
+#define SITAR_A_CDC_MBHC_VOLT_B7_CTL__POR (0x000000ff)
+#define SITAR_A_CDC_MBHC_VOLT_B8_CTL (0x3D7)
+#define SITAR_A_CDC_MBHC_VOLT_B8_CTL__POR (0x00000007)
+#define SITAR_A_CDC_MBHC_VOLT_B9_CTL (0x3D8)
+#define SITAR_A_CDC_MBHC_VOLT_B9_CTL__POR (0x000000ff)
+#define SITAR_A_CDC_MBHC_VOLT_B10_CTL (0x3D9)
+#define SITAR_A_CDC_MBHC_VOLT_B10_CTL__POR (0x0000007f)
+#define SITAR_A_CDC_MBHC_VOLT_B11_CTL (0x3DA)
+#define SITAR_A_CDC_MBHC_VOLT_B11_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_VOLT_B12_CTL (0x3DB)
+#define SITAR_A_CDC_MBHC_VOLT_B12_CTL__POR (0x00000080)
+#define SITAR_A_CDC_MBHC_CLK_CTL (0x3DC)
+#define SITAR_A_CDC_MBHC_CLK_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_INT_CTL (0x3DD)
+#define SITAR_A_CDC_MBHC_INT_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_DEBUG_CTL (0x3DE)
+#define SITAR_A_CDC_MBHC_DEBUG_CTL__POR (0x00000000)
+#define SITAR_A_CDC_MBHC_SPARE (0x3DF)
+#define SITAR_A_CDC_MBHC_SPARE__POR (0x00000000)
+/* SLIMBUS Slave Registers */
+#define SITAR_SLIM_PGD_PORT_INT_EN0 (0x30)
+#define SITAR_SLIM_PGD_PORT_INT_STATUS0 (0x34)
+#define SITAR_SLIM_PGD_PORT_INT_CLR0 (0x38)
+#define SITAR_SLIM_PGD_PORT_INT_SOURCE0 (0x60)
+
+/* Macros for Packing Register Writes into a U32 */
+#define SITAR_PACKED_REG_SIZE sizeof(u32)
+
+#define SITAR_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\
+ ((mask & 0xff) << 8)|((reg & 0xffff) << 16))
+
+#define SITAR_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+ do { \
+ ((reg) = ((packed >> 16) & (0xffff))); \
+ ((mask) = ((packed >> 8) & (0xff))); \
+ ((val) = ((packed) & (0xff))); \
+ } while (0);
+#endif
diff --git a/include/linux/mfd/wcd9310/registers.h b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
similarity index 95%
rename from include/linux/mfd/wcd9310/registers.h
rename to include/linux/mfd/wcd9xxx/wcd9310_registers.h
index ef27c08..d2736ea 100644
--- a/include/linux/mfd/wcd9310/registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
@@ -1,29 +1,41 @@
+/* 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 TABLA_CODEC_DIGITAL_H
#define TABLA_CODEC_DIGITAL_H
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-#define TABLA_A_CHIP_CTL (0x00)
-#define TABLA_A_CHIP_CTL__POR (0x00000000)
-#define TABLA_A_CHIP_STATUS (0x01)
-#define TABLA_A_CHIP_STATUS__POR (0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_0 (0x04)
-#define TABLA_A_CHIP_ID_BYTE_0__POR (0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_1 (0x05)
-#define TABLA_A_CHIP_ID_BYTE_1__POR (0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_2 (0x06)
-#define TABLA_A_CHIP_ID_BYTE_2__POR (0x00000000)
-#define TABLA_A_CHIP_ID_BYTE_3 (0x07)
-#define TABLA_A_CHIP_ID_BYTE_3__POR (0x00000001)
-#define TABLA_A_CHIP_VERSION (0x08)
-#define TABLA_A_CHIP_VERSION__POR (0x00000020)
-#define TABLA_A_SB_VERSION (0x09)
-#define TABLA_A_SB_VERSION__POR (0x00000010)
-#define TABLA_A_SLAVE_ID_1 (0x0C)
-#define TABLA_A_SLAVE_ID_1__POR (0x00000077)
-#define TABLA_A_SLAVE_ID_2 (0x0D)
-#define TABLA_A_SLAVE_ID_2__POR (0x00000066)
-#define TABLA_A_SLAVE_ID_3 (0x0E)
-#define TABLA_A_SLAVE_ID_3__POR (0x00000055)
+#define TABLA_A_CHIP_CTL WCD9XXX_A_CHIP_CTL
+#define TABLA_A_CHIP_CTL__POR WCD9XXX_A_CHIP_CTL__POR
+#define TABLA_A_CHIP_STATUS WCD9XXX_A_CHIP_STATUS
+#define TABLA_A_CHIP_STATUS__POR WCD9XXX_A_CHIP_STATUS__POR
+#define TABLA_A_CHIP_ID_BYTE_0 WCD9XXX_A_CHIP_ID_BYTE_0
+#define TABLA_A_CHIP_ID_BYTE_0__POR WCD9XXX_A_CHIP_ID_BYTE_0__POR
+#define TABLA_A_CHIP_ID_BYTE_1 WCD9XXX_A_CHIP_ID_BYTE_1
+#define TABLA_A_CHIP_ID_BYTE_1__POR WCD9XXX_A_CHIP_ID_BYTE_1__POR
+#define TABLA_A_CHIP_ID_BYTE_2 WCD9XXX_A_CHIP_ID_BYTE_2
+#define TABLA_A_CHIP_ID_BYTE_2__POR WCD9XXX_A_CHIP_ID_BYTE_2__POR
+#define TABLA_A_CHIP_ID_BYTE_3 WCD9XXX_A_CHIP_ID_BYTE_3
+#define TABLA_A_CHIP_ID_BYTE_3__POR WCD9XXX_A_CHIP_ID_BYTE_3__POR
+#define TABLA_A_CHIP_VERSION WCD9XXX_A_CHIP_VERSION
+#define TABLA_A_CHIP_VERSION__POR WCD9XXX_A_CHIP_VERSION__POR
+#define TABLA_A_SB_VERSION WCD9XXX_A_SB_VERSION
+#define TABLA_A_SB_VERSION__POR WCD9XXX_A_SB_VERSION__POR
+#define TABLA_A_SLAVE_ID_1 WCD9XXX_A_SLAVE_ID_1
+#define TABLA_A_SLAVE_ID_1__POR WCD9XXX_A_SLAVE_ID_1__POR
+#define TABLA_A_SLAVE_ID_2 WCD9XXX_A_SLAVE_ID_2
+#define TABLA_A_SLAVE_ID_2__POR WCD9XXX_A_SLAVE_ID_2__POR
+#define TABLA_A_SLAVE_ID_3 WCD9XXX_A_SLAVE_ID_3
+#define TABLA_A_SLAVE_ID_3__POR WCD9XXX_A_SLAVE_ID_3__POR
#define TABLA_A_PIN_CTL_OE0 (0x10)
#define TABLA_A_PIN_CTL_OE0__POR (0x00000000)
#define TABLA_A_PIN_CTL_OE1 (0x11)
@@ -58,10 +70,10 @@
#define TABLA_A_QFUSE_DATA_OUT2__POR (0x00000000)
#define TABLA_A_QFUSE_DATA_OUT3 (0x4D)
#define TABLA_A_QFUSE_DATA_OUT3__POR (0x00000000)
-#define TABLA_A_CDC_CTL (0x80)
-#define TABLA_A_CDC_CTL__POR (0x00000000)
-#define TABLA_A_LEAKAGE_CTL (0x88)
-#define TABLA_A_LEAKAGE_CTL__POR (0x00000004)
+#define TABLA_A_CDC_CTL WCD9XXX_A_CDC_CTL
+#define TABLA_A_CDC_CTL__POR WCD9XXX_A_CDC_CTL__POR
+#define TABLA_A_LEAKAGE_CTL WCD9XXX_A_LEAKAGE_CTL
+#define TABLA_A_LEAKAGE_CTL__POR WCD9XXX_A_LEAKAGE_CTL__POR
#define TABLA_A_INTR_MODE (0x90)
#define TABLA_A_INTR_MODE__POR (0x00000000)
#define TABLA_A_INTR_MASK0 (0x94)
diff --git a/include/linux/mfd/wcd9310/wcd9310-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
similarity index 84%
rename from include/linux/mfd/wcd9310/wcd9310-slimslave.h
rename to include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 0bbf96f..fcd3bd3 100644
--- a/include/linux/mfd/wcd9310/wcd9310-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -14,7 +14,7 @@
#define __WCD9310_SLIMSLAVE_H_
#include <linux/slimbus/slimbus.h>
-#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
/* Local to the core only */
#define SLIM_MAX_RX_PORTS 7
@@ -84,19 +84,19 @@
#define BASE_CH_NUM 128
-int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la);
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la);
-int tabla_deinit_slimslave(struct tabla *tabla);
+int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx);
-int tabla_cfg_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int tot_ch, unsigned int rate);
-int tabla_cfg_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int tot_ch, unsigned int rate);
-int tabla_close_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int tot_ch);
-int tabla_close_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
unsigned int tot_ch);
-int tabla_get_channel(struct tabla *tabla,
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
unsigned int *rx_ch,
unsigned int *tx_ch);
#endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
new file mode 100644
index 0000000..c66e953
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -0,0 +1,42 @@
+/* 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 WCD9XXX_CODEC_DIGITAL_H
+
+#define WCD9XXX_CODEC_DIGITAL_H
+
+#define WCD9XXX_A_CHIP_CTL (0x00)
+#define WCD9XXX_A_CHIP_CTL__POR (0x00000000)
+#define WCD9XXX_A_CHIP_STATUS (0x01)
+#define WCD9XXX_A_CHIP_STATUS__POR (0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_0 (0x04)
+#define WCD9XXX_A_CHIP_ID_BYTE_0__POR (0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_1 (0x05)
+#define WCD9XXX_A_CHIP_ID_BYTE_1__POR (0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_2 (0x06)
+#define WCD9XXX_A_CHIP_ID_BYTE_2__POR (0x00000000)
+#define WCD9XXX_A_CHIP_ID_BYTE_3 (0x07)
+#define WCD9XXX_A_CHIP_ID_BYTE_3__POR (0x00000001)
+#define WCD9XXX_A_CHIP_VERSION (0x08)
+#define WCD9XXX_A_CHIP_VERSION__POR (0x00000020)
+#define WCD9XXX_A_SB_VERSION (0x09)
+#define WCD9XXX_A_SB_VERSION__POR (0x00000010)
+#define WCD9XXX_A_SLAVE_ID_1 (0x0C)
+#define WCD9XXX_A_SLAVE_ID_1__POR (0x00000077)
+#define WCD9XXX_A_SLAVE_ID_2 (0x0D)
+#define WCD9XXX_A_SLAVE_ID_2__POR (0x00000066)
+#define WCD9XXX_A_SLAVE_ID_3 (0x0E)
+#define WCD9XXX_A_SLAVE_ID_3__POR (0x00000055)
+#define WCD9XXX_A_CDC_CTL (0x80)
+#define WCD9XXX_A_CDC_CTL__POR (0x00000000)
+#define WCD9XXX_A_LEAKAGE_CTL (0x88)
+#define WCD9XXX_A_LEAKAGE_CTL__POR (0x00000004)
+#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9e82abf8..ff53742 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -50,8 +50,12 @@
u8 rel_sectors;
u8 rel_param;
u8 part_config;
+ u8 cache_ctrl;
+ u8 rst_n_function;
unsigned int part_time; /* Units: ms */
unsigned int sa_timeout; /* Units: 100ns */
+ unsigned int generic_cmd6_time; /* Units: 10ms */
+ unsigned int power_off_longtime; /* Units: ms */
unsigned int hs_max_dtr;
unsigned int sectors;
unsigned int card_type;
@@ -64,10 +68,15 @@
unsigned long long enhanced_area_offset; /* Units: Byte */
unsigned int enhanced_area_size; /* Units: KB */
unsigned int boot_size; /* in bytes */
+ unsigned int cache_size; /* Units: KB */
+ bool hpi_en; /* HPI enablebit */
+ bool hpi; /* HPI support bit */
+ unsigned int hpi_cmd; /* cmd used as HPI */
u8 raw_partition_support; /* 160 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
+ u8 out_of_int_time; /* 198 */
u8 raw_s_a_timeout; /* 217 */
u8 raw_hc_erase_gap_size; /* 221 */
u8 raw_erase_timeout_mult; /* 223 */
@@ -77,6 +86,9 @@
u8 raw_sec_feature_support;/* 231 */
u8 raw_trim_mult; /* 232 */
u8 raw_sectors[4]; /* 212 - 4 bytes */
+
+ unsigned int feature_support;
+#define MMC_DISCARD_FEATURE BIT(0) /* CMD38 feature */
};
struct sd_scr {
@@ -189,6 +201,11 @@
#define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */
#define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */
#define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */
+ unsigned int poweroff_notify_state; /* eMMC4.5 notify feature */
+#define MMC_NO_POWER_NOTIFICATION 0
+#define MMC_POWERED_ON 1
+#define MMC_POWEROFF_SHORT 2
+#define MMC_POWEROFF_LONG 3
unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 279c023..05c126c 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -117,6 +117,7 @@
unsigned int sg_len; /* size of scatter list */
struct scatterlist *sg; /* I/O scatter list */
+ s32 host_cookie; /* host private data */
};
struct mmc_request {
@@ -125,13 +126,17 @@
struct mmc_data *data;
struct mmc_command *stop;
- void *done_data; /* completion data */
+ struct completion completion;
void (*done)(struct mmc_request *);/* completion function */
};
struct mmc_host;
struct mmc_card;
+struct mmc_async_req;
+extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
+ struct mmc_async_req *, int *);
+extern int mmc_interrupt_hpi(struct mmc_card *);
extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
@@ -142,6 +147,7 @@
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
#define MMC_TRIM_ARG 0x00000001
+#define MMC_DISCARD_ARG 0x00000003
#define MMC_SECURE_TRIM1_ARG 0x80000001
#define MMC_SECURE_TRIM2_ARG 0x80008000
@@ -152,11 +158,17 @@
unsigned int arg);
extern int mmc_can_erase(struct mmc_card *card);
extern int mmc_can_trim(struct mmc_card *card);
+extern int mmc_can_discard(struct mmc_card *card);
+extern int mmc_can_sanitize(struct mmc_card *card);
extern int mmc_can_secure_erase_trim(struct mmc_card *card);
extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
unsigned int nr);
+extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+extern int mmc_hw_reset(struct mmc_host *host);
+extern int mmc_hw_reset_check(struct mmc_host *host);
+extern int mmc_can_reset(struct mmc_card *card);
extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
@@ -167,6 +179,7 @@
extern int mmc_try_claim_host(struct mmc_host *host);
extern int mmc_detect_card_removed(struct mmc_host *host);
+extern int mmc_flush_cache(struct mmc_card *);
/**
* mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d90c779..35137d6 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -107,6 +107,15 @@
*/
int (*enable)(struct mmc_host *host);
int (*disable)(struct mmc_host *host, int lazy);
+ /*
+ * It is optional for the host to implement pre_req and post_req in
+ * order to support double buffering of requests (prepare one
+ * request while another request is active).
+ */
+ void (*post_req)(struct mmc_host *host, struct mmc_request *req,
+ int err);
+ void (*pre_req)(struct mmc_host *host, struct mmc_request *req,
+ bool is_first_req);
void (*request)(struct mmc_host *host, struct mmc_request *req);
/*
* Avoid calling these three functions too often or in a "fast path",
@@ -140,11 +149,22 @@
int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
int (*execute_tuning)(struct mmc_host *host);
void (*enable_preset_value)(struct mmc_host *host, bool enable);
+ void (*hw_reset)(struct mmc_host *host);
};
struct mmc_card;
struct device;
+struct mmc_async_req {
+ /* active mmc request */
+ struct mmc_request *mrq;
+ /*
+ * Check error status of completed mmc request.
+ * Returns 0 if success otherwise non zero.
+ */
+ int (*err_check) (struct mmc_card *, struct mmc_async_req *);
+};
+
struct mmc_host {
struct device *parent;
struct device class_dev;
@@ -212,8 +232,19 @@
#define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */
#define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
+#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
+
+ unsigned int caps2; /* More host capabilities */
+
+#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */
+#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff supported */
+#define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */
mmc_pm_flag_t pm_caps; /* supported pm features */
+ unsigned int power_notify_type;
+#define MMC_HOST_PW_NOTIFY_NONE 0
+#define MMC_HOST_PW_NOTIFY_SHORT 1
+#define MMC_HOST_PW_NOTIFY_LONG 2
#ifdef CONFIG_MMC_CLKGATE
int clk_requests; /* internal reference counter */
@@ -234,6 +265,7 @@
unsigned int max_req_size; /* maximum number of bytes in one req */
unsigned int max_blk_size; /* maximum size of one mmc block */
unsigned int max_blk_count; /* maximum number of blocks in one req */
+ unsigned int max_discard_to; /* max. discard timeout in ms */
/* private data */
spinlock_t lock; /* lock for claim and bus ops */
@@ -314,6 +346,9 @@
ktime_t start;
} perf;
#endif
+
+ struct mmc_async_req *areq; /* active async req */
+
unsigned long private[0] ____cacheline_aligned;
};
@@ -362,6 +397,8 @@
extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
+extern int mmc_cache_ctrl(struct mmc_host *, u8);
+
static inline void mmc_signal_sdio_irq(struct mmc_host *host)
{
host->ops->enable_sdio_irq(host, 0);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 53013f9..0a72bf8 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -271,18 +271,30 @@
* EXT_CSD fields
*/
+#define EXT_CSD_FLUSH_CACHE 32 /* W */
+#define EXT_CSD_CACHE_CTRL 33 /* R/W */
+#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
+#define EXT_CSD_HPI_MGMT 161 /* R/W */
+#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
+#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
+#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
+#define EXT_CSD_PWR_CL_52_195 200 /* RO */
+#define EXT_CSD_PWR_CL_26_195 201 /* RO */
+#define EXT_CSD_PWR_CL_52_360 202 /* RO */
+#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
@@ -294,6 +306,14 @@
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_TRIM_MULT 232 /* RO */
+#define EXT_CSD_PWR_CL_200_195 236 /* RO */
+#define EXT_CSD_PWR_CL_200_360 237 /* RO */
+#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
+#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
+#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
+#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
+#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
+#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
* EXT_CSD field definitions
@@ -328,7 +348,20 @@
#define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2)
#define EXT_CSD_SEC_GB_CL_EN BIT(4)
+#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */
+#define EXT_CSD_RST_N_EN_MASK 0x3
+#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
+
+#define EXT_CSD_NO_POWER_NOTIFICATION 0
+#define EXT_CSD_POWER_ON 1
+#define EXT_CSD_POWER_OFF_SHORT 2
+#define EXT_CSD_POWER_OFF_LONG 3
+
+#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
+#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
/*
* MMC_SWITCH access modes
*/
diff --git a/include/linux/msm_audio_mvs.h b/include/linux/msm_audio_mvs.h
index 2813c8f..8ec9796 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -24,7 +24,7 @@
#define MVS_MODE_G729A 0xE
#define MVS_MODE_G711A 0xF
#define MVS_MODE_G722 0x10
-#define MVS_MODE_PCM_WB 0x80000000
+#define MVS_MODE_PCM_WB 0x12
enum msm_audio_amr_mode {
MVS_AMR_MODE_0475, /* AMR 4.75 kbps */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 37b9d35..5e39f89 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -140,6 +140,13 @@
#define KGSL_2D1_REG_MEMORY "kgsl_2d1_reg_memory"
#define KGSL_2D1_IRQ "kgsl_2d1_irq"
+struct kgsl_device_iommu_data {
+ const char **iommu_ctx_names;
+ int iommu_ctx_count;
+ unsigned int physstart;
+ unsigned int physend;
+};
+
struct kgsl_device_platform_data {
struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
int init_level;
@@ -150,8 +157,8 @@
unsigned int clk_map;
unsigned int idle_needed;
struct msm_bus_scale_pdata *bus_scale_table;
- const char *iommu_user_ctx_name;
- const char *iommu_priv_ctx_name;
+ struct kgsl_device_iommu_data *iommu_data;
+ int iommu_count;
};
#endif
diff --git a/include/linux/of.h b/include/linux/of.h
index 6a1272c..f904bf4 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -241,6 +241,16 @@
return false;
}
+#define for_each_child_of_node(parent, child) \
+ while (0)
+
+static inline struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp)
+{
+ return NULL;
+}
+
static inline int of_property_read_u32_array(const struct device_node *np,
char *propname, u32 *out_values, size_t sz)
{
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3118623..01b925a 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -4,6 +4,7 @@
#include <linux/errno.h>
#include <linux/of.h>
+#ifdef CONFIG_OF_ADDRESS
extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
@@ -25,12 +26,37 @@
#define pci_address_to_pio pci_address_to_pio
#endif
-#ifdef CONFIG_PCI
+#else /* CONFIG_OF_ADDRESS */
+static inline int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r)
+{
+ return -EINVAL;
+}
+static inline struct device_node *of_find_matching_node_by_address(
+ struct device_node *from,
+ const struct of_device_id *matches,
+ u64 base_address)
+{
+ return NULL;
+}
+static inline void __iomem *of_iomap(struct device_node *device, int index)
+{
+ return NULL;
+}
+static inline const u32 *of_get_address(struct device_node *dev, int index,
+ u64 *size, unsigned int *flags)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF_ADDRESS */
+
+
+#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)
extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no,
u64 *size, unsigned int *flags);
extern int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r);
-#else /* CONFIG_PCI */
+#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */
static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r)
{
@@ -42,8 +68,7 @@
{
return NULL;
}
-#endif /* CONFIG_PCI */
-
+#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */
#endif /* __OF_ADDRESS_H */
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
new file mode 100644
index 0000000..6d39026
--- /dev/null
+++ b/include/linux/qseecom.h
@@ -0,0 +1,149 @@
+#ifndef __QSEECOM_H_
+#define __QSEECOM_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define MAX_ION_FD 4
+#define MAX_APP_NAME_SIZE 32
+
+/*
+ * struct qseecom_register_listener_req -
+ * for register listener ioctl request
+ * @listener_id - service id (shared between userspace and QSE)
+ * @ifd_data_fd - ion handle
+ * @virt_sb_base - shared buffer base in user space
+ * @sb_size - shared buffer size
+ */
+struct qseecom_register_listener_req {
+ uint32_t listener_id; /* in */
+ int32_t ifd_data_fd; /* in */
+ uint32_t virt_sb_base; /* in */
+ uint32_t sb_size; /* in */
+};
+
+/*
+ * struct qseecom_send_cmd_req - for send command ioctl request
+ * @cmd_req_len - command buffer length
+ * @cmd_req_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ */
+struct qseecom_send_cmd_req {
+ void *cmd_req_buf; /* in */
+ unsigned int cmd_req_len; /* in */
+ void *resp_buf; /* in/out */
+ unsigned int resp_len; /* in/out */
+};
+
+
+/*
+ * struct qseecom_ion_fd_info - ion fd handle data information
+ * @fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_ion_fd_info {
+ int32_t fd;
+ uint32_t cmd_buf_offset;
+};
+/*
+ * struct qseecom_send_modfd_cmd_req - for send command ioctl request
+ * @cmd_req_len - command buffer length
+ * @cmd_req_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ * @ifd_data_fd - ion handle to memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_send_modfd_cmd_req {
+ void *cmd_req_buf; /* in */
+ unsigned int cmd_req_len; /* in */
+ void *resp_buf; /* in/out */
+ unsigned int resp_len; /* in/out */
+ struct qseecom_ion_fd_info ifd_data[MAX_ION_FD];
+};
+/*
+ * struct qseecom_listener_send_resp_req - signal to continue the send_cmd req.
+ * Used as a trigger from HLOS service to notify QSEECOM that it's done with its
+ * operation and provide the response for QSEECOM can continue the incomplete
+ * command execution
+ * @resp_len - Length of the response
+ * @resp_buf - Response buffer where the response of the cmd should go.
+ */
+struct qseecom_send_resp_req {
+ void *resp_buf; /* in */
+ unsigned int resp_len; /* in */
+};
+
+/*
+ * struct qseecom_load_img_data - for sending image length information and
+ * ion file descriptor to the qseecom driver. ion file descriptor is used
+ * for retrieving the ion file handle and in turn the physical address of
+ * the image location.
+ * @mdt_len - Length of the .mdt file in bytes.
+ * @img_len - Length of the .mdt + .b00 +..+.bxx images files in bytes
+ * @ion_fd - Ion file descriptor used when allocating memory.
+ * @img_name - Name of the image.
+*/
+struct qseecom_load_img_req {
+ uint32_t mdt_len; /* in */
+ uint32_t img_len; /* in */
+ int32_t ifd_data_fd; /* in */
+ char img_name[MAX_APP_NAME_SIZE]; /* in */
+ int app_id; /* out*/
+};
+
+struct qseecom_set_sb_mem_param_req {
+ int32_t ifd_data_fd; /* in */
+ uint32_t virt_sb_base; /* in */
+ uint32_t sb_len; /* in */
+};
+
+/*
+ * struct qseecom_qseos_version_req - get qseos version
+ * @qseos_version - version number
+ */
+struct qseecom_qseos_version_req {
+ unsigned int qseos_version; /* in */
+};
+
+#define QSEECOM_IOC_MAGIC 0x97
+
+
+#define QSEECOM_IOCTL_REGISTER_LISTENER_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 1, struct qseecom_register_listener_req)
+
+#define QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ \
+ _IO(QSEECOM_IOC_MAGIC, 2)
+
+#define QSEECOM_IOCTL_SEND_CMD_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 3, struct qseecom_send_cmd_req)
+
+#define QSEECOM_IOCTL_SEND_MODFD_CMD_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 4, struct qseecom_send_modfd_cmd_req)
+
+#define QSEECOM_IOCTL_RECEIVE_REQ \
+ _IO(QSEECOM_IOC_MAGIC, 5)
+
+#define QSEECOM_IOCTL_SEND_RESP_REQ \
+ _IO(QSEECOM_IOC_MAGIC, 6)
+
+#define QSEECOM_IOCTL_LOAD_APP_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 7, struct qseecom_load_img_req)
+
+#define QSEECOM_IOCTL_SET_MEM_PARAM_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 8, struct qseecom_set_sb_mem_param_req)
+
+#define QSEECOM_IOCTL_UNLOAD_APP_REQ \
+ _IO(QSEECOM_IOC_MAGIC, 9)
+
+#define QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 10, struct qseecom_qseos_version_req)
+
+#define QSEECOM_IOCTL_PERF_ENABLE_REQ \
+ _IO(QSEECOM_IOC_MAGIC, 11)
+
+#define QSEECOM_IOCTL_PERF_DISABLE_REQ \
+ _IO(QSEECOM_IOC_MAGIC, 12)
+
+#endif /* __QSEECOM_H_ */
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 448d9ab..75b132b 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -877,6 +877,7 @@
* -EXFULL is returned if there is no space in TDM to reserve the bandwidth.
* -EISCONN/-ENOTCONN is returned if the channel is already connected or not
* yet defined.
+ * -EINVAL is returned if individual control of a grouped-channel is attempted.
*/
extern int slim_control_ch(struct slim_device *sb, u16 grpchanh,
enum slim_ch_control chctrl, bool commit);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 037cfe7..79fb177 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -277,6 +277,10 @@
unsigned hub_reset;
};
+struct msm_usb_host_platform_data {
+ unsigned int power_budget;
+};
+
struct usb_bam_pipe_connect {
u32 src_phy_addr;
int src_pipe_index;
diff --git a/include/linux/usb/ulpi.h b/include/linux/usb/ulpi.h
index 9595796..540a74c 100644
--- a/include/linux/usb/ulpi.h
+++ b/include/linux/usb/ulpi.h
@@ -145,6 +145,7 @@
#define ULPI_INT_SESS_VALID (1 << 2)
#define ULPI_INT_SESS_END (1 << 3)
#define ULPI_INT_IDGRD (1 << 4)
+#define ULPI_INT_DP (1 << 7)
/* Debug */
#define ULPI_DEBUG_LINESTATE0 (1 << 0)
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 1cd8448..8bb2558 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -56,6 +56,7 @@
struct vcd_frame_data {
u8 *virtual;
u8 *physical;
+ u32 ion_flag;
u32 alloc_len;
u32 data_len;
u32 offset;
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
index 60cc35f..4e28c74 100644
--- a/include/media/msm/vidc_init.h
+++ b/include/media/msm/vidc_init.h
@@ -14,7 +14,8 @@
#ifndef VIDC_INIT_H
#define VIDC_INIT_H
#include <linux/ion.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_property.h>
#define VIDC_MAX_NUM_CLIENTS 4
#define MAX_VIDEO_NUM_OF_BUFF 100
@@ -28,6 +29,7 @@
unsigned long user_vaddr;
unsigned long kernel_vaddr;
unsigned long phy_addr;
+ unsigned long buff_ion_flag;
struct ion_handle *buff_ion_handle;
int pmem_fd;
struct file *file;
@@ -63,6 +65,9 @@
void __iomem *vidc_get_ioaddr(void);
int vidc_load_firmware(void);
void vidc_release_firmware(void);
+u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer, int pmem_fd,
+ unsigned long kvaddr, int index);
u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
enum buffer_dir buffer, u32 search_with_user_vaddr,
unsigned long *user_vaddr, unsigned long *kernel_vaddr,
@@ -76,6 +81,8 @@
u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
enum buffer_dir buffer, unsigned long user_vaddr,
unsigned long *kernel_vaddr);
+void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer);
u32 vidc_timer_create(void (*timer_handler)(void *),
void *user_data, void **timer_handle);
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index e0a04dc..867bd8a 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1137,6 +1137,10 @@
uint32_t f_pix_den;
uint32_t total_f_dist_num;
uint32_t total_f_dist_den;
+ uint32_t hor_view_angle_num;
+ uint32_t hor_view_angle_den;
+ uint32_t ver_view_angle_num;
+ uint32_t ver_view_angle_den;
};
struct msm_actuator_cfg_data {
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 07784e2..e02597a 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -241,8 +241,17 @@
#define VPE_SCALER_CONFIG_LEN 260
#define VPE_DIS_OFFSET_CFG_LEN 12
-#define IMEM_Y_OFFSET 0x2E000000
-#define IMEM_CBCR_OFFSET 0x2E00FA00
+
+#define CAPTURE_WIDTH 1280
+#define IMEM_Y_SIZE (CAPTURE_WIDTH*16)
+#define IMEM_CBCR_SIZE (CAPTURE_WIDTH*8)
+
+#define IMEM_Y_PING_OFFSET 0x2E000000
+#define IMEM_CBCR_PING_OFFSET (IMEM_Y_PING_OFFSET + IMEM_Y_SIZE)
+
+#define IMEM_Y_PONG_OFFSET (IMEM_CBCR_PING_OFFSET + IMEM_CBCR_SIZE)
+#define IMEM_CBCR_PONG_OFFSET (IMEM_Y_PONG_OFFSET + IMEM_Y_SIZE)
+
struct msm_vpe_op_mode_cfg {
uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN];
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 34a21bd..de2b356 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -675,7 +675,7 @@
/* Band limits */
#define REGION_US_EU_BAND_LOW 87500
-#define REGION_US_EU_BAND_HIGH 107900
+#define REGION_US_EU_BAND_HIGH 108000
#define REGION_JAPAN_STANDARD_BAND_LOW 76000
#define REGION_JAPAN_STANDARD_BAND_HIGH 90000
#define REGION_JAPAN_WIDE_BAND_LOW 90000
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index bedfc7c..211d146 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -152,7 +152,7 @@
* Here we have IOCTl's that are specific to IRIS
* (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28)
*/
- V4L2_CID_PRIVATE_SOFT_MUTE, /* 0x800001E*/
+ V4L2_CID_PRIVATE_SOFT_MUTE,/* 0x800001E*/
V4L2_CID_PRIVATE_RIVA_ACCS_ADDR,
V4L2_CID_PRIVATE_RIVA_ACCS_LEN,
V4L2_CID_PRIVATE_RIVA_PEEK,
@@ -162,16 +162,16 @@
V4L2_CID_PRIVATE_SSBI_POKE,
V4L2_CID_PRIVATE_TX_TONE,
V4L2_CID_PRIVATE_RDS_GRP_COUNTERS,
- V4L2_CID_PRIVATE_SET_NOTCH_FILTER, /* 0x8000028 */
+ V4L2_CID_PRIVATE_SET_NOTCH_FILTER,/* 0x8000028 */
- V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, /* 0x8000029 */
- V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION, /* 0x800002A : IRIS command */
- V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, /* 0x800002B */
-
- V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD =
- V4L2_CTRL_CLASS_USER + 0x92B,
- V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD =
- V4L2_CTRL_CLASS_USER + 0x92C
+ V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,/* 0x8000029 */
+ V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION,/* 0x800002A : IRIS */
+ V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,/* 0x800002B */
+ V4L2_CID_PRIVATE_IRIS_GET_SINR, /* 0x800002C : IRIS */
+ V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, /* 0x800002D */
+ V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */
+ V4L2_CID_PRIVATE_SINR_THRESHOLD, /* 0x800002F : IRIS */
+ V4L2_CID_PRIVATE_SINR_SAMPLES, /* 0x8000030 : IRIS */
};
@@ -349,6 +349,7 @@
(reg = (reg & ~mask) | (((val) << offset) & mask))
#define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset)
#define RSH_DATA(val, offset) ((val) >> (offset))
+#define LSH_DATA(val, offset) ((val) << (offset))
#define GET_ABS_VAL(val) ((val) & (0xFF))
enum radio_state_t {
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 0104f1a..d3d393d 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -44,6 +44,8 @@
"alignment.c:720",
"async.c:122",
"async.c:270",
+ "block.c:835",
+ "block.c:836",
"dir.c:43",
"dm.c:1053",
"dm.c:1080",
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b923a25..88181a6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -250,6 +250,9 @@
config SND_SOC_UDA1380
tristate
+config SND_SOC_WCD9304
+ tristate
+
config SND_SOC_WCD9310
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 78740ab..0bd7255 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -38,6 +38,7 @@
snd-soc-twl6040-objs := twl6040.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
+snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
snd-soc-wl1273-objs := wl1273.o
snd-soc-wm1250-ev1-objs := wm1250-ev1.o
@@ -132,6 +133,7 @@
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WCD9304) += snd-soc-wcd9304.o
obj-$(CONFIG_SND_SOC_WCD9310) += snd-soc-wcd9310.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd9304-tables.c b/sound/soc/codecs/wcd9304-tables.c
new file mode 100644
index 0000000..823f926
--- /dev/null
+++ b/sound/soc/codecs/wcd9304-tables.c
@@ -0,0 +1,720 @@
+/* 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 <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
+#include "wcd9304.h"
+
+const u8 sitar_reg_defaults[SITAR_CACHE_SIZE] = {
+ [WCD9XXX_A_CHIP_CTL] = WCD9XXX_A_CHIP_CTL__POR,
+ [WCD9XXX_A_CHIP_STATUS] = WCD9XXX_A_CHIP_STATUS__POR,
+ [WCD9XXX_A_CHIP_ID_BYTE_0] = WCD9XXX_A_CHIP_ID_BYTE_0__POR,
+ [WCD9XXX_A_CHIP_ID_BYTE_1] = WCD9XXX_A_CHIP_ID_BYTE_1__POR,
+ [WCD9XXX_A_CHIP_ID_BYTE_2] = WCD9XXX_A_CHIP_ID_BYTE_2__POR,
+ [WCD9XXX_A_CHIP_ID_BYTE_3] = WCD9XXX_A_CHIP_ID_BYTE_3__POR,
+ [WCD9XXX_A_CHIP_VERSION] = WCD9XXX_A_CHIP_VERSION__POR,
+ [WCD9XXX_A_SB_VERSION] = WCD9XXX_A_SB_VERSION__POR,
+ [WCD9XXX_A_SLAVE_ID_1] = WCD9XXX_A_SLAVE_ID_1__POR,
+ [WCD9XXX_A_SLAVE_ID_2] = WCD9XXX_A_SLAVE_ID_2__POR,
+ [WCD9XXX_A_SLAVE_ID_3] = WCD9XXX_A_SLAVE_ID_3__POR,
+ [SITAR_A_PIN_CTL_OE0] = SITAR_A_PIN_CTL_OE0__POR,
+ [SITAR_A_PIN_CTL_OE1] = SITAR_A_PIN_CTL_OE1__POR,
+ [SITAR_A_PIN_CTL_DATA0] = SITAR_A_PIN_CTL_DATA0__POR,
+ [SITAR_A_PIN_CTL_DATA1] = SITAR_A_PIN_CTL_DATA1__POR,
+ [SITAR_A_HDRIVE_GENERIC] = SITAR_A_HDRIVE_GENERIC__POR,
+ [SITAR_A_HDRIVE_OVERRIDE] = SITAR_A_HDRIVE_OVERRIDE__POR,
+ [SITAR_A_ANA_CSR_WAIT_STATE] = SITAR_A_ANA_CSR_WAIT_STATE__POR,
+ [SITAR_A_PROCESS_MONITOR_CTL0] = SITAR_A_PROCESS_MONITOR_CTL0__POR,
+ [SITAR_A_PROCESS_MONITOR_CTL1] = SITAR_A_PROCESS_MONITOR_CTL1__POR,
+ [SITAR_A_PROCESS_MONITOR_CTL2] = SITAR_A_PROCESS_MONITOR_CTL2__POR,
+ [SITAR_A_PROCESS_MONITOR_CTL3] = SITAR_A_PROCESS_MONITOR_CTL3__POR,
+ [SITAR_A_QFUSE_CTL] = SITAR_A_QFUSE_CTL__POR,
+ [SITAR_A_QFUSE_STATUS] = SITAR_A_QFUSE_STATUS__POR,
+ [SITAR_A_QFUSE_DATA_OUT0] = SITAR_A_QFUSE_DATA_OUT0__POR,
+ [SITAR_A_QFUSE_DATA_OUT1] = SITAR_A_QFUSE_DATA_OUT1__POR,
+ [SITAR_A_QFUSE_DATA_OUT2] = SITAR_A_QFUSE_DATA_OUT2__POR,
+ [SITAR_A_QFUSE_DATA_OUT3] = SITAR_A_QFUSE_DATA_OUT3__POR,
+ [SITAR_A_CDC_CTL] = SITAR_A_CDC_CTL__POR,
+ [SITAR_A_LEAKAGE_CTL] = SITAR_A_LEAKAGE_CTL__POR,
+ [SITAR_A_INTR_MODE] = SITAR_A_INTR_MODE__POR,
+ [SITAR_A_INTR_MASK0] = SITAR_A_INTR_MASK0__POR,
+ [SITAR_A_INTR_MASK1] = SITAR_A_INTR_MASK1__POR,
+ [SITAR_A_INTR_MASK2] = SITAR_A_INTR_MASK2__POR,
+ [SITAR_A_INTR_STATUS0] = SITAR_A_INTR_STATUS0__POR,
+ [SITAR_A_INTR_STATUS1] = SITAR_A_INTR_STATUS1__POR,
+ [SITAR_A_INTR_STATUS2] = SITAR_A_INTR_STATUS2__POR,
+ [SITAR_A_INTR_CLEAR0] = SITAR_A_INTR_CLEAR0__POR,
+ [SITAR_A_INTR_CLEAR1] = SITAR_A_INTR_CLEAR1__POR,
+ [SITAR_A_INTR_CLEAR2] = SITAR_A_INTR_CLEAR2__POR,
+ [SITAR_A_INTR_LEVEL0] = SITAR_A_INTR_LEVEL0__POR,
+ [SITAR_A_INTR_LEVEL1] = SITAR_A_INTR_LEVEL1__POR,
+ [SITAR_A_INTR_LEVEL2] = SITAR_A_INTR_LEVEL2__POR,
+ [SITAR_A_INTR_TEST0] = SITAR_A_INTR_TEST0__POR,
+ [SITAR_A_INTR_TEST1] = SITAR_A_INTR_TEST1__POR,
+ [SITAR_A_INTR_TEST2] = SITAR_A_INTR_TEST2__POR,
+ [SITAR_A_INTR_SET0] = SITAR_A_INTR_SET0__POR,
+ [SITAR_A_INTR_SET1] = SITAR_A_INTR_SET1__POR,
+ [SITAR_A_INTR_SET2] = SITAR_A_INTR_SET2__POR,
+ [SITAR_A_CDC_TX_I2S_SCK_MODE] = SITAR_A_CDC_TX_I2S_SCK_MODE__POR,
+ [SITAR_A_CDC_TX_I2S_WS_MODE] = SITAR_A_CDC_TX_I2S_WS_MODE__POR,
+ [SITAR_A_CDC_DMIC_DATA0_MODE] = SITAR_A_CDC_DMIC_DATA0_MODE__POR,
+ [SITAR_A_CDC_DMIC_CLK0_MODE] = SITAR_A_CDC_DMIC_CLK0_MODE__POR,
+ [SITAR_A_CDC_DMIC_DATA1_MODE] = SITAR_A_CDC_DMIC_DATA1_MODE__POR,
+ [SITAR_A_CDC_DMIC_CLK1_MODE] = SITAR_A_CDC_DMIC_CLK1_MODE__POR,
+ [SITAR_A_CDC_TX_I2S_SD0_MODE] = SITAR_A_CDC_TX_I2S_SD0_MODE__POR,
+ [SITAR_A_CDC_INTR_MODE] = SITAR_A_CDC_INTR_MODE__POR,
+ [SITAR_A_CDC_RX_I2S_SD0_MODE] = SITAR_A_CDC_RX_I2S_SD0_MODE__POR,
+ [SITAR_A_CDC_RX_I2S_SD1_MODE] = SITAR_A_CDC_RX_I2S_SD1_MODE__POR,
+ [SITAR_A_BIAS_REF_CTL] = SITAR_A_BIAS_REF_CTL__POR,
+ [SITAR_A_BIAS_CENTRAL_BG_CTL] = SITAR_A_BIAS_CENTRAL_BG_CTL__POR,
+ [SITAR_A_BIAS_PRECHRG_CTL] = SITAR_A_BIAS_PRECHRG_CTL__POR,
+ [SITAR_A_BIAS_CURR_CTL_1] = SITAR_A_BIAS_CURR_CTL_1__POR,
+ [SITAR_A_BIAS_CURR_CTL_2] = SITAR_A_BIAS_CURR_CTL_2__POR,
+ [SITAR_A_BIAS_OSC_BG_CTL] = SITAR_A_BIAS_OSC_BG_CTL__POR,
+ [SITAR_A_CLK_BUFF_EN1] = SITAR_A_CLK_BUFF_EN1__POR,
+ [SITAR_A_CLK_BUFF_EN2] = SITAR_A_CLK_BUFF_EN2__POR,
+ [SITAR_A_LDO_H_MODE_1] = SITAR_A_LDO_H_MODE_1__POR,
+ [SITAR_A_LDO_H_MODE_2] = SITAR_A_LDO_H_MODE_2__POR,
+ [SITAR_A_LDO_H_LOOP_CTL] = SITAR_A_LDO_H_LOOP_CTL__POR,
+ [SITAR_A_LDO_H_COMP_1] = SITAR_A_LDO_H_COMP_1__POR,
+ [SITAR_A_LDO_H_COMP_2] = SITAR_A_LDO_H_COMP_2__POR,
+ [SITAR_A_LDO_H_BIAS_1] = SITAR_A_LDO_H_BIAS_1__POR,
+ [SITAR_A_LDO_H_BIAS_2] = SITAR_A_LDO_H_BIAS_2__POR,
+ [SITAR_A_LDO_H_BIAS_3] = SITAR_A_LDO_H_BIAS_3__POR,
+ [SITAR_A_MICB_CFILT_1_CTL] = SITAR_A_MICB_CFILT_1_CTL__POR,
+ [SITAR_A_MICB_CFILT_1_VAL] = SITAR_A_MICB_CFILT_1_VAL__POR,
+ [SITAR_A_MICB_CFILT_1_PRECHRG] = SITAR_A_MICB_CFILT_1_PRECHRG__POR,
+ [SITAR_A_MICB_1_CTL] = SITAR_A_MICB_1_CTL__POR,
+ [SITAR_A_MICB_1_INT_RBIAS] = SITAR_A_MICB_1_INT_RBIAS__POR,
+ [SITAR_A_MICB_1_MBHC] = SITAR_A_MICB_1_MBHC__POR,
+ [SITAR_A_MICB_CFILT_2_CTL] = SITAR_A_MICB_CFILT_2_CTL__POR,
+ [SITAR_A_MICB_CFILT_2_VAL] = SITAR_A_MICB_CFILT_2_VAL__POR,
+ [SITAR_A_MICB_CFILT_2_PRECHRG] = SITAR_A_MICB_CFILT_2_PRECHRG__POR,
+ [SITAR_A_MICB_2_CTL] = SITAR_A_MICB_2_CTL__POR,
+ [SITAR_A_MICB_2_INT_RBIAS] = SITAR_A_MICB_2_INT_RBIAS__POR,
+ [SITAR_A_MICB_2_MBHC] = SITAR_A_MICB_2_MBHC__POR,
+ [SITAR_A_TX_COM_BIAS] = SITAR_A_TX_COM_BIAS__POR,
+ [SITAR_A_MBHC_SCALING_MUX_1] = SITAR_A_MBHC_SCALING_MUX_1__POR,
+ [SITAR_A_MBHC_SCALING_MUX_2] = SITAR_A_MBHC_SCALING_MUX_2__POR,
+ [SITAR_A_TX_SUP_SWITCH_CTRL_1] = SITAR_A_TX_SUP_SWITCH_CTRL_1__POR,
+ [SITAR_A_TX_SUP_SWITCH_CTRL_2] = SITAR_A_TX_SUP_SWITCH_CTRL_2__POR,
+ [SITAR_A_TX_1_2_EN] = SITAR_A_TX_1_2_EN__POR,
+ [SITAR_A_TX_1_2_TEST_EN] = SITAR_A_TX_1_2_TEST_EN__POR,
+ [SITAR_A_TX_1_2_ADC_CH1] = SITAR_A_TX_1_2_ADC_CH1__POR,
+ [SITAR_A_TX_1_2_ADC_CH2] = SITAR_A_TX_1_2_ADC_CH2__POR,
+ [SITAR_A_TX_1_2_ATEST_REFCTRL] = SITAR_A_TX_1_2_ATEST_REFCTRL__POR,
+ [SITAR_A_TX_1_2_TEST_CTL] = SITAR_A_TX_1_2_TEST_CTL__POR,
+ [SITAR_A_TX_1_2_TEST_BLOCK_EN] = SITAR_A_TX_1_2_TEST_BLOCK_EN__POR,
+ [SITAR_A_TX_1_2_TXFE_CLKDIV] = SITAR_A_TX_1_2_TXFE_CLKDIV__POR,
+ [SITAR_A_TX_1_2_SAR_ERR_CH1] = SITAR_A_TX_1_2_SAR_ERR_CH1__POR,
+ [SITAR_A_TX_1_2_SAR_ERR_CH2] = SITAR_A_TX_1_2_SAR_ERR_CH2__POR,
+ [SITAR_A_TX_3_EN] = SITAR_A_TX_3_EN__POR,
+ [SITAR_A_TX_3_TEST_EN] = SITAR_A_TX_3_TEST_EN__POR,
+ [SITAR_A_TX_3_ADC] = SITAR_A_TX_3_ADC__POR,
+ [SITAR_A_TX_3_MBHC_ATEST_REFCTRL] =
+ SITAR_A_TX_3_MBHC_ATEST_REFCTRL__POR,
+ [SITAR_A_TX_3_TEST_CTL] = SITAR_A_TX_3_TEST_CTL__POR,
+ [SITAR_A_TX_3_TEST_BLOCK_EN] = SITAR_A_TX_3_TEST_BLOCK_EN__POR,
+ [SITAR_A_TX_3_TXFE_CKDIV] = SITAR_A_TX_3_TXFE_CKDIV__POR,
+ [SITAR_A_TX_3_SAR_ERR] = SITAR_A_TX_3_SAR_ERR__POR,
+ [SITAR_A_TX_4_MBHC_EN] = SITAR_A_TX_4_MBHC_EN__POR,
+ [SITAR_A_TX_4_MBHC_ADC] = SITAR_A_TX_4_MBHC_ADC__POR,
+ [SITAR_A_TX_4_MBHC_TEST_CTL] = SITAR_A_TX_4_MBHC_TEST_CTL__POR,
+ [SITAR_A_TX_4_MBHC_SAR_ERR] = SITAR_A_TX_4_MBHC_SAR_ERR__POR,
+ [SITAR_A_TX_4_TXFE_CLKDIV] = SITAR_A_TX_4_TXFE_CLKDIV__POR,
+ [SITAR_A_AUX_COM_CTL] = SITAR_A_AUX_COM_CTL__POR,
+ [SITAR_A_AUX_COM_ATEST] = SITAR_A_AUX_COM_ATEST__POR,
+ [SITAR_A_AUX_L_EN] = SITAR_A_AUX_L_EN__POR,
+ [SITAR_A_AUX_L_GAIN] = SITAR_A_AUX_L_GAIN__POR,
+ [SITAR_A_AUX_L_PA_CONN] = SITAR_A_AUX_L_PA_CONN__POR,
+ [SITAR_A_AUX_L_PA_CONN_INV] = SITAR_A_AUX_L_PA_CONN_INV__POR,
+ [SITAR_A_AUX_R_EN] = SITAR_A_AUX_R_EN__POR,
+ [SITAR_A_AUX_R_GAIN] = SITAR_A_AUX_R_GAIN__POR,
+ [SITAR_A_AUX_R_PA_CONN] = SITAR_A_AUX_R_PA_CONN__POR,
+ [SITAR_A_AUX_R_PA_CONN_INV] = SITAR_A_AUX_R_PA_CONN_INV__POR,
+ [SITAR_A_CP_EN] = SITAR_A_CP_EN__POR,
+ [SITAR_A_CP_CLK] = SITAR_A_CP_CLK__POR,
+ [SITAR_A_CP_STATIC] = SITAR_A_CP_STATIC__POR,
+ [SITAR_A_CP_DCC1] = SITAR_A_CP_DCC1__POR,
+ [SITAR_A_CP_DCC3] = SITAR_A_CP_DCC3__POR,
+ [SITAR_A_CP_ATEST] = SITAR_A_CP_ATEST__POR,
+ [SITAR_A_CP_DTEST] = SITAR_A_CP_DTEST__POR,
+ [SITAR_A_RX_COM_TIMER_DIV] = SITAR_A_RX_COM_TIMER_DIV__POR,
+ [SITAR_A_RX_COM_OCP_CTL] = SITAR_A_RX_COM_OCP_CTL__POR,
+ [SITAR_A_RX_COM_OCP_COUNT] = SITAR_A_RX_COM_OCP_COUNT__POR,
+ [SITAR_A_RX_COM_DAC_CTL] = SITAR_A_RX_COM_DAC_CTL__POR,
+ [SITAR_A_RX_COM_BIAS] = SITAR_A_RX_COM_BIAS__POR,
+ [SITAR_A_RX_HPH_BIAS_PA] = SITAR_A_RX_HPH_BIAS_PA__POR,
+ [SITAR_A_RX_HPH_BIAS_LDO] = SITAR_A_RX_HPH_BIAS_LDO__POR,
+ [SITAR_A_RX_HPH_BIAS_CNP] = SITAR_A_RX_HPH_BIAS_CNP__POR,
+ [SITAR_A_RX_HPH_BIAS_WG] = SITAR_A_RX_HPH_BIAS_WG__POR,
+ [SITAR_A_RX_HPH_OCP_CTL] = SITAR_A_RX_HPH_OCP_CTL__POR,
+ [SITAR_A_RX_HPH_CNP_EN] = SITAR_A_RX_HPH_CNP_EN__POR,
+ [SITAR_A_RX_HPH_CNP_WG_CTL] = SITAR_A_RX_HPH_CNP_WG_CTL__POR,
+ [SITAR_A_RX_HPH_CNP_WG_TIME] = SITAR_A_RX_HPH_CNP_WG_TIME__POR,
+ [SITAR_A_RX_HPH_L_GAIN] = SITAR_A_RX_HPH_L_GAIN__POR,
+ [SITAR_A_RX_HPH_L_TEST] = SITAR_A_RX_HPH_L_TEST__POR,
+ [SITAR_A_RX_HPH_L_PA_CTL] = SITAR_A_RX_HPH_L_PA_CTL__POR,
+ [SITAR_A_RX_HPH_L_DAC_CTL] = SITAR_A_RX_HPH_L_DAC_CTL__POR,
+ [SITAR_A_RX_HPH_L_ATEST] = SITAR_A_RX_HPH_L_ATEST__POR,
+ [SITAR_A_RX_HPH_L_STATUS] = SITAR_A_RX_HPH_L_STATUS__POR,
+ [SITAR_A_RX_HPH_R_GAIN] = SITAR_A_RX_HPH_R_GAIN__POR,
+ [SITAR_A_RX_HPH_R_TEST] = SITAR_A_RX_HPH_R_TEST__POR,
+ [SITAR_A_RX_HPH_R_PA_CTL] = SITAR_A_RX_HPH_R_PA_CTL__POR,
+ [SITAR_A_RX_HPH_R_DAC_CTL] = SITAR_A_RX_HPH_R_DAC_CTL__POR,
+ [SITAR_A_RX_HPH_R_ATEST] = SITAR_A_RX_HPH_R_ATEST__POR,
+ [SITAR_A_RX_HPH_R_STATUS] = SITAR_A_RX_HPH_R_STATUS__POR,
+ [SITAR_A_RX_EAR_BIAS_PA] = SITAR_A_RX_EAR_BIAS_PA__POR,
+ [SITAR_A_RX_EAR_BIAS_CMBUFF] = SITAR_A_RX_EAR_BIAS_CMBUFF__POR,
+ [SITAR_A_RX_EAR_EN] = SITAR_A_RX_EAR_EN__POR,
+ [SITAR_A_RX_EAR_GAIN] = SITAR_A_RX_EAR_GAIN__POR,
+ [SITAR_A_RX_EAR_CMBUFF] = SITAR_A_RX_EAR_CMBUFF__POR,
+ [SITAR_A_RX_EAR_ICTL] = SITAR_A_RX_EAR_ICTL__POR,
+ [SITAR_A_RX_EAR_CCOMP] = SITAR_A_RX_EAR_CCOMP__POR,
+ [SITAR_A_RX_EAR_VCM] = SITAR_A_RX_EAR_VCM__POR,
+ [SITAR_A_RX_EAR_CNP] = SITAR_A_RX_EAR_CNP__POR,
+ [SITAR_A_RX_EAR_ATEST] = SITAR_A_RX_EAR_ATEST__POR,
+ [SITAR_A_RX_EAR_STATUS] = SITAR_A_RX_EAR_STATUS__POR,
+ [SITAR_A_RX_LINE_BIAS_PA] = SITAR_A_RX_LINE_BIAS_PA__POR,
+ [SITAR_A_RX_LINE_BIAS_LDO] = SITAR_A_RX_LINE_BIAS_LDO__POR,
+ [SITAR_A_RX_LINE_BIAS_CNP1] = SITAR_A_RX_LINE_BIAS_CNP1__POR,
+ [SITAR_A_RX_LINE_COM] = SITAR_A_RX_LINE_COM__POR,
+ [SITAR_A_RX_LINE_CNP_EN] = SITAR_A_RX_LINE_CNP_EN__POR,
+ [SITAR_A_RX_LINE_CNP_WG_CTL] = SITAR_A_RX_LINE_CNP_WG_CTL__POR,
+ [SITAR_A_RX_LINE_CNP_WG_TIME] = SITAR_A_RX_LINE_CNP_WG_TIME__POR,
+ [SITAR_A_RX_LINE_1_GAIN] = SITAR_A_RX_LINE_1_GAIN__POR,
+ [SITAR_A_RX_LINE_1_TEST] = SITAR_A_RX_LINE_1_TEST__POR,
+ [SITAR_A_RX_LINE_1_DAC_CTL] = SITAR_A_RX_LINE_1_DAC_CTL__POR,
+ [SITAR_A_RX_LINE_1_STATUS] = SITAR_A_RX_LINE_1_STATUS__POR,
+ [SITAR_A_RX_LINE_2_GAIN] = SITAR_A_RX_LINE_2_GAIN__POR,
+ [SITAR_A_RX_LINE_2_TEST] = SITAR_A_RX_LINE_2_TEST__POR,
+ [SITAR_A_RX_LINE_2_DAC_CTL] = SITAR_A_RX_LINE_2_DAC_CTL__POR,
+ [SITAR_A_RX_LINE_2_STATUS] = SITAR_A_RX_LINE_2_STATUS__POR,
+ [SITAR_A_RX_LINE_BIAS_CNP2] = SITAR_A_RX_LINE_BIAS_CNP2__POR,
+ [SITAR_A_RX_LINE_OCP_CTL] = SITAR_A_RX_LINE_OCP_CTL__POR,
+ [SITAR_A_RX_LINE_1_PA_CTL] = SITAR_A_RX_LINE_1_PA_CTL__POR,
+ [SITAR_A_RX_LINE_2_PA_CTL] = SITAR_A_RX_LINE_2_PA_CTL__POR,
+ [SITAR_A_RX_LINE_CNP_DBG] = SITAR_A_RX_LINE_CNP_DBG__POR,
+ [SITAR_A_MBHC_HPH] = SITAR_A_MBHC_HPH__POR,
+ [SITAR_A_RC_OSC_FREQ] = SITAR_A_RC_OSC_FREQ__POR,
+ [SITAR_A_RC_OSC_TEST] = SITAR_A_RC_OSC_TEST__POR,
+ [SITAR_A_RC_OSC_STATUS] = SITAR_A_RC_OSC_STATUS__POR,
+ [SITAR_A_RC_OSC_TUNER] = SITAR_A_RC_OSC_TUNER__POR,
+ [SITAR_A_CDC_ANC1_CTL] = SITAR_A_CDC_ANC1_CTL__POR,
+ [SITAR_A_CDC_ANC1_SHIFT] = SITAR_A_CDC_ANC1_SHIFT__POR,
+ [SITAR_A_CDC_ANC1_IIR_B1_CTL] = SITAR_A_CDC_ANC1_IIR_B1_CTL__POR,
+ [SITAR_A_CDC_ANC1_IIR_B2_CTL] = SITAR_A_CDC_ANC1_IIR_B2_CTL__POR,
+ [SITAR_A_CDC_ANC1_IIR_B3_CTL] = SITAR_A_CDC_ANC1_IIR_B3_CTL__POR,
+ [SITAR_A_CDC_ANC1_IIR_B4_CTL] = SITAR_A_CDC_ANC1_IIR_B4_CTL__POR,
+ [SITAR_A_CDC_ANC1_LPF_B1_CTL] = SITAR_A_CDC_ANC1_LPF_B1_CTL__POR,
+ [SITAR_A_CDC_ANC1_LPF_B2_CTL] = SITAR_A_CDC_ANC1_LPF_B2_CTL__POR,
+ [SITAR_A_CDC_ANC1_LPF_B3_CTL] = SITAR_A_CDC_ANC1_LPF_B3_CTL__POR,
+ [SITAR_A_CDC_ANC1_SPARE] = SITAR_A_CDC_ANC1_SPARE__POR,
+ [SITAR_A_CDC_ANC1_SMLPF_CTL] = SITAR_A_CDC_ANC1_SMLPF_CTL__POR,
+ [SITAR_A_CDC_ANC1_DCFLT_CTL] = SITAR_A_CDC_ANC1_DCFLT_CTL__POR,
+ [SITAR_A_CDC_TX1_VOL_CTL_TIMER] = SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR,
+ [SITAR_A_CDC_TX1_VOL_CTL_GAIN] = SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR,
+ [SITAR_A_CDC_TX1_VOL_CTL_CFG] = SITAR_A_CDC_TX1_VOL_CTL_CFG__POR,
+ [SITAR_A_CDC_TX1_MUX_CTL] = SITAR_A_CDC_TX1_MUX_CTL__POR,
+ [SITAR_A_CDC_TX1_CLK_FS_CTL] = SITAR_A_CDC_TX1_CLK_FS_CTL__POR,
+ [SITAR_A_CDC_TX1_DMIC_CTL] = SITAR_A_CDC_TX1_DMIC_CTL__POR,
+ [SITAR_A_CDC_SRC1_PDA_CFG] = SITAR_A_CDC_SRC1_PDA_CFG__POR,
+ [SITAR_A_CDC_SRC1_FS_CTL] = SITAR_A_CDC_SRC1_FS_CTL__POR,
+ [SITAR_A_CDC_RX1_B1_CTL] = SITAR_A_CDC_RX1_B1_CTL__POR,
+ [SITAR_A_CDC_RX1_B2_CTL] = SITAR_A_CDC_RX1_B2_CTL__POR,
+ [SITAR_A_CDC_RX1_B3_CTL] = SITAR_A_CDC_RX1_B3_CTL__POR,
+ [SITAR_A_CDC_RX1_B4_CTL] = SITAR_A_CDC_RX1_B4_CTL__POR,
+ [SITAR_A_CDC_RX1_B5_CTL] = SITAR_A_CDC_RX1_B5_CTL__POR,
+ [SITAR_A_CDC_RX1_B6_CTL] = SITAR_A_CDC_RX1_B6_CTL__POR,
+ [SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
+ [SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
+ [SITAR_A_CDC_CLK_ANC_RESET_CTL] = SITAR_A_CDC_CLK_ANC_RESET_CTL__POR,
+ [SITAR_A_CDC_CLK_RX_RESET_CTL] = SITAR_A_CDC_CLK_RX_RESET_CTL__POR,
+ [SITAR_A_CDC_CLK_TX_RESET_B1_CTL] =
+ SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR,
+ [SITAR_A_CDC_CLK_TX_RESET_B2_CTL] =
+ SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR,
+ [SITAR_A_CDC_CLK_DMIC_CTL] = SITAR_A_CDC_CLK_DMIC_CTL__POR,
+ [SITAR_A_CDC_CLK_RX_I2S_CTL] = SITAR_A_CDC_CLK_RX_I2S_CTL__POR,
+ [SITAR_A_CDC_CLK_TX_I2S_CTL] = SITAR_A_CDC_CLK_TX_I2S_CTL__POR,
+ [SITAR_A_CDC_CLK_OTHR_RESET_CTL] = SITAR_A_CDC_CLK_OTHR_RESET_CTL__POR,
+ [SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
+ SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
+ [SITAR_A_CDC_CLK_OTHR_CTL] = SITAR_A_CDC_CLK_OTHR_CTL__POR,
+ [SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL] =
+ SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL__POR,
+ [SITAR_A_CDC_CLK_ANC_CLK_EN_CTL] = SITAR_A_CDC_CLK_ANC_CLK_EN_CTL__POR,
+ [SITAR_A_CDC_CLK_RX_B1_CTL] = SITAR_A_CDC_CLK_RX_B1_CTL__POR,
+ [SITAR_A_CDC_CLK_RX_B2_CTL] = SITAR_A_CDC_CLK_RX_B2_CTL__POR,
+ [SITAR_A_CDC_CLK_MCLK_CTL] = SITAR_A_CDC_CLK_MCLK_CTL__POR,
+ [SITAR_A_CDC_CLK_PDM_CTL] = SITAR_A_CDC_CLK_PDM_CTL__POR,
+ [SITAR_A_CDC_CLK_SD_CTL] = SITAR_A_CDC_CLK_SD_CTL__POR,
+ [SITAR_A_CDC_CLK_LP_CTL] = SITAR_A_CDC_CLK_LP_CTL__POR,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL] =
+ SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL__POR,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL] =
+ SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL__POR,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL] =
+ SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL__POR,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL] =
+ SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL__POR,
+ [SITAR_A_CDC_CLSG_GAIN_THRESH_CTL] =
+ SITAR_A_CDC_CLSG_GAIN_THRESH_CTL__POR,
+ [SITAR_A_CDC_CLSG_TIMER_B1_CFG] = SITAR_A_CDC_CLSG_TIMER_B1_CFG__POR,
+ [SITAR_A_CDC_CLSG_TIMER_B2_CFG] = SITAR_A_CDC_CLSG_TIMER_B2_CFG__POR,
+ [SITAR_A_CDC_CLSG_CTL] = SITAR_A_CDC_CLSG_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B1_CTL] = SITAR_A_CDC_IIR1_GAIN_B1_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B2_CTL] = SITAR_A_CDC_IIR1_GAIN_B2_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B3_CTL] = SITAR_A_CDC_IIR1_GAIN_B3_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B4_CTL] = SITAR_A_CDC_IIR1_GAIN_B4_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B5_CTL] = SITAR_A_CDC_IIR1_GAIN_B5_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B6_CTL] = SITAR_A_CDC_IIR1_GAIN_B6_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B7_CTL] = SITAR_A_CDC_IIR1_GAIN_B7_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_B8_CTL] = SITAR_A_CDC_IIR1_GAIN_B8_CTL__POR,
+ [SITAR_A_CDC_IIR1_CTL] = SITAR_A_CDC_IIR1_CTL__POR,
+ [SITAR_A_CDC_IIR1_GAIN_TIMER_CTL] =
+ SITAR_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
+ [SITAR_A_CDC_IIR1_COEF_B1_CTL] = SITAR_A_CDC_IIR1_COEF_B1_CTL__POR,
+ [SITAR_A_CDC_IIR1_COEF_B2_CTL] = SITAR_A_CDC_IIR1_COEF_B2_CTL__POR,
+ [SITAR_A_CDC_IIR1_COEF_B3_CTL] = SITAR_A_CDC_IIR1_COEF_B3_CTL__POR,
+ [SITAR_A_CDC_IIR1_COEF_B4_CTL] = SITAR_A_CDC_IIR1_COEF_B4_CTL__POR,
+ [SITAR_A_CDC_IIR1_COEF_B5_CTL] = SITAR_A_CDC_IIR1_COEF_B5_CTL__POR,
+ [SITAR_A_CDC_TOP_GAIN_UPDATE] = SITAR_A_CDC_TOP_GAIN_UPDATE__POR,
+ [SITAR_A_CDC_TOP_RDAC_DOUT_CTL] = SITAR_A_CDC_TOP_RDAC_DOUT_CTL__POR,
+ [SITAR_A_CDC_DEBUG_B1_CTL] = SITAR_A_CDC_DEBUG_B1_CTL__POR,
+ [SITAR_A_CDC_DEBUG_B2_CTL] = SITAR_A_CDC_DEBUG_B2_CTL__POR,
+ [SITAR_A_CDC_DEBUG_B3_CTL] = SITAR_A_CDC_DEBUG_B3_CTL__POR,
+ [SITAR_A_CDC_DEBUG_B4_CTL] = SITAR_A_CDC_DEBUG_B4_CTL__POR,
+ [SITAR_A_CDC_DEBUG_B5_CTL] = SITAR_A_CDC_DEBUG_B5_CTL__POR,
+ [SITAR_A_CDC_DEBUG_B6_CTL] = SITAR_A_CDC_DEBUG_B6_CTL__POR,
+ [SITAR_A_CDC_DEBUG_B7_CTL] = SITAR_A_CDC_DEBUG_B7_CTL__POR,
+ [SITAR_A_CDC_COMP1_B1_CTL] = SITAR_A_CDC_COMP1_B1_CTL__POR,
+ [SITAR_A_CDC_COMP1_B2_CTL] = SITAR_A_CDC_COMP1_B2_CTL__POR,
+ [SITAR_A_CDC_COMP1_B3_CTL] = SITAR_A_CDC_COMP1_B3_CTL__POR,
+ [SITAR_A_CDC_COMP1_B4_CTL] = SITAR_A_CDC_COMP1_B4_CTL__POR,
+ [SITAR_A_CDC_COMP1_B5_CTL] = SITAR_A_CDC_COMP1_B5_CTL__POR,
+ [SITAR_A_CDC_COMP1_B6_CTL] = SITAR_A_CDC_COMP1_B6_CTL__POR,
+ [SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+ SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+ [SITAR_A_CDC_COMP1_FS_CFG] = SITAR_A_CDC_COMP1_FS_CFG__POR,
+ [SITAR_A_CDC_CONN_RX1_B1_CTL] = SITAR_A_CDC_CONN_RX1_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_RX1_B2_CTL] = SITAR_A_CDC_CONN_RX1_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_RX1_B3_CTL] = SITAR_A_CDC_CONN_RX1_B3_CTL__POR,
+ [SITAR_A_CDC_CONN_RX2_B1_CTL] = SITAR_A_CDC_CONN_RX2_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_RX2_B2_CTL] = SITAR_A_CDC_CONN_RX2_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_RX2_B3_CTL] = SITAR_A_CDC_CONN_RX2_B3_CTL__POR,
+ [SITAR_A_CDC_CONN_RX3_B1_CTL] = SITAR_A_CDC_CONN_RX3_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_RX3_B2_CTL] = SITAR_A_CDC_CONN_RX3_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_RX3_B3_CTL] = SITAR_A_CDC_CONN_RX3_B3_CTL__POR,
+ [SITAR_A_CDC_CONN_ANC_B1_CTL] = SITAR_A_CDC_CONN_ANC_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_ANC_B2_CTL] = SITAR_A_CDC_CONN_ANC_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_TX_B1_CTL] = SITAR_A_CDC_CONN_TX_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_TX_B2_CTL] = SITAR_A_CDC_CONN_TX_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ1_B1_CTL] = SITAR_A_CDC_CONN_EQ1_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ1_B2_CTL] = SITAR_A_CDC_CONN_EQ1_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ1_B3_CTL] = SITAR_A_CDC_CONN_EQ1_B3_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ1_B4_CTL] = SITAR_A_CDC_CONN_EQ1_B4_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ2_B1_CTL] = SITAR_A_CDC_CONN_EQ2_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ2_B2_CTL] = SITAR_A_CDC_CONN_EQ2_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ2_B3_CTL] = SITAR_A_CDC_CONN_EQ2_B3_CTL__POR,
+ [SITAR_A_CDC_CONN_EQ2_B4_CTL] = SITAR_A_CDC_CONN_EQ2_B4_CTL__POR,
+ [SITAR_A_CDC_CONN_SRC1_B1_CTL] = SITAR_A_CDC_CONN_SRC1_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_SRC1_B2_CTL] = SITAR_A_CDC_CONN_SRC1_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_SRC2_B1_CTL] = SITAR_A_CDC_CONN_SRC2_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_SRC2_B2_CTL] = SITAR_A_CDC_CONN_SRC2_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_TX_SB_B1_CTL] = SITAR_A_CDC_CONN_TX_SB_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_TX_SB_B2_CTL] = SITAR_A_CDC_CONN_TX_SB_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_TX_SB_B3_CTL] = SITAR_A_CDC_CONN_TX_SB_B3_CTL__POR,
+ [SITAR_A_CDC_CONN_TX_SB_B4_CTL] = SITAR_A_CDC_CONN_TX_SB_B4_CTL__POR,
+ [SITAR_A_CDC_CONN_TX_SB_B5_CTL] = SITAR_A_CDC_CONN_TX_SB_B5_CTL__POR,
+ [SITAR_A_CDC_CONN_RX_SB_B1_CTL] = SITAR_A_CDC_CONN_RX_SB_B1_CTL__POR,
+ [SITAR_A_CDC_CONN_RX_SB_B2_CTL] = SITAR_A_CDC_CONN_RX_SB_B2_CTL__POR,
+ [SITAR_A_CDC_CONN_CLSG_CTL] = SITAR_A_CDC_CONN_CLSG_CTL__POR,
+ [SITAR_A_CDC_CONN_SPARE] = SITAR_A_CDC_CONN_SPARE__POR,
+ [SITAR_A_CDC_MBHC_EN_CTL] = SITAR_A_CDC_MBHC_EN_CTL__POR,
+ [SITAR_A_CDC_MBHC_FIR_B1_CFG] = SITAR_A_CDC_MBHC_FIR_B1_CFG__POR,
+ [SITAR_A_CDC_MBHC_FIR_B2_CFG] = SITAR_A_CDC_MBHC_FIR_B2_CFG__POR,
+ [SITAR_A_CDC_MBHC_TIMER_B1_CTL] = SITAR_A_CDC_MBHC_TIMER_B1_CTL__POR,
+ [SITAR_A_CDC_MBHC_TIMER_B2_CTL] = SITAR_A_CDC_MBHC_TIMER_B2_CTL__POR,
+ [SITAR_A_CDC_MBHC_TIMER_B3_CTL] = SITAR_A_CDC_MBHC_TIMER_B3_CTL__POR,
+ [SITAR_A_CDC_MBHC_TIMER_B4_CTL] = SITAR_A_CDC_MBHC_TIMER_B4_CTL__POR,
+ [SITAR_A_CDC_MBHC_TIMER_B5_CTL] = SITAR_A_CDC_MBHC_TIMER_B5_CTL__POR,
+ [SITAR_A_CDC_MBHC_TIMER_B6_CTL] = SITAR_A_CDC_MBHC_TIMER_B6_CTL__POR,
+ [SITAR_A_CDC_MBHC_B1_STATUS] = SITAR_A_CDC_MBHC_B1_STATUS__POR,
+ [SITAR_A_CDC_MBHC_B2_STATUS] = SITAR_A_CDC_MBHC_B2_STATUS__POR,
+ [SITAR_A_CDC_MBHC_B3_STATUS] = SITAR_A_CDC_MBHC_B3_STATUS__POR,
+ [SITAR_A_CDC_MBHC_B4_STATUS] = SITAR_A_CDC_MBHC_B4_STATUS__POR,
+ [SITAR_A_CDC_MBHC_B5_STATUS] = SITAR_A_CDC_MBHC_B5_STATUS__POR,
+ [SITAR_A_CDC_MBHC_B1_CTL] = SITAR_A_CDC_MBHC_B1_CTL__POR,
+ [SITAR_A_CDC_MBHC_B2_CTL] = SITAR_A_CDC_MBHC_B2_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B1_CTL] = SITAR_A_CDC_MBHC_VOLT_B1_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B2_CTL] = SITAR_A_CDC_MBHC_VOLT_B2_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B3_CTL] = SITAR_A_CDC_MBHC_VOLT_B3_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B4_CTL] = SITAR_A_CDC_MBHC_VOLT_B4_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B5_CTL] = SITAR_A_CDC_MBHC_VOLT_B5_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B6_CTL] = SITAR_A_CDC_MBHC_VOLT_B6_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B7_CTL] = SITAR_A_CDC_MBHC_VOLT_B7_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B8_CTL] = SITAR_A_CDC_MBHC_VOLT_B8_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B9_CTL] = SITAR_A_CDC_MBHC_VOLT_B9_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B10_CTL] = SITAR_A_CDC_MBHC_VOLT_B10_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B11_CTL] = SITAR_A_CDC_MBHC_VOLT_B11_CTL__POR,
+ [SITAR_A_CDC_MBHC_VOLT_B12_CTL] = SITAR_A_CDC_MBHC_VOLT_B12_CTL__POR,
+ [SITAR_A_CDC_MBHC_CLK_CTL] = SITAR_A_CDC_MBHC_CLK_CTL__POR,
+ [SITAR_A_CDC_MBHC_INT_CTL] = SITAR_A_CDC_MBHC_INT_CTL__POR,
+ [SITAR_A_CDC_MBHC_DEBUG_CTL] = SITAR_A_CDC_MBHC_DEBUG_CTL__POR,
+ [SITAR_A_CDC_MBHC_SPARE] = SITAR_A_CDC_MBHC_SPARE__POR,
+};
+
+const u8 sitar_reg_readable[SITAR_CACHE_SIZE] = {
+ [WCD9XXX_A_CHIP_CTL] = 1,
+ [WCD9XXX_A_CHIP_STATUS] = 1,
+ [WCD9XXX_A_CHIP_ID_BYTE_0] = 1,
+ [WCD9XXX_A_CHIP_ID_BYTE_1] = 1,
+ [WCD9XXX_A_CHIP_ID_BYTE_2] = 1,
+ [WCD9XXX_A_CHIP_ID_BYTE_3] = 1,
+ [WCD9XXX_A_CHIP_VERSION] = 1,
+ [WCD9XXX_A_SB_VERSION] = 1,
+ [WCD9XXX_A_SLAVE_ID_1] = 1,
+ [WCD9XXX_A_SLAVE_ID_2] = 1,
+ [WCD9XXX_A_SLAVE_ID_3] = 1,
+ [SITAR_A_PIN_CTL_OE0] = 1,
+ [SITAR_A_PIN_CTL_OE1] = 1,
+ [SITAR_A_PIN_CTL_DATA0] = 1,
+ [SITAR_A_PIN_CTL_DATA1] = 1,
+ [SITAR_A_HDRIVE_GENERIC] = 1,
+ [SITAR_A_HDRIVE_OVERRIDE] = 1,
+ [SITAR_A_ANA_CSR_WAIT_STATE] = 1,
+ [SITAR_A_PROCESS_MONITOR_CTL0] = 1,
+ [SITAR_A_PROCESS_MONITOR_CTL1] = 1,
+ [SITAR_A_PROCESS_MONITOR_CTL2] = 1,
+ [SITAR_A_PROCESS_MONITOR_CTL3] = 1,
+ [SITAR_A_QFUSE_CTL] = 1,
+ [SITAR_A_QFUSE_STATUS] = 1,
+ [SITAR_A_QFUSE_DATA_OUT0] = 1,
+ [SITAR_A_QFUSE_DATA_OUT1] = 1,
+ [SITAR_A_QFUSE_DATA_OUT2] = 1,
+ [SITAR_A_QFUSE_DATA_OUT3] = 1,
+ [SITAR_A_CDC_CTL] = 1,
+ [SITAR_A_LEAKAGE_CTL] = 1,
+ [SITAR_A_INTR_MODE] = 1,
+ [SITAR_A_INTR_MASK0] = 1,
+ [SITAR_A_INTR_MASK1] = 1,
+ [SITAR_A_INTR_MASK2] = 1,
+ [SITAR_A_INTR_STATUS0] = 1,
+ [SITAR_A_INTR_STATUS1] = 1,
+ [SITAR_A_INTR_STATUS2] = 1,
+ [SITAR_A_INTR_LEVEL0] = 1,
+ [SITAR_A_INTR_LEVEL1] = 1,
+ [SITAR_A_INTR_LEVEL2] = 1,
+ [SITAR_A_INTR_TEST0] = 1,
+ [SITAR_A_INTR_TEST1] = 1,
+ [SITAR_A_INTR_TEST2] = 1,
+ [SITAR_A_INTR_SET0] = 1,
+ [SITAR_A_INTR_SET1] = 1,
+ [SITAR_A_INTR_SET2] = 1,
+ [SITAR_A_CDC_TX_I2S_SCK_MODE] = 1,
+ [SITAR_A_CDC_TX_I2S_WS_MODE] = 1,
+ [SITAR_A_CDC_DMIC_DATA0_MODE] = 1,
+ [SITAR_A_CDC_DMIC_CLK0_MODE] = 1,
+ [SITAR_A_CDC_DMIC_DATA1_MODE] = 1,
+ [SITAR_A_CDC_DMIC_CLK1_MODE] = 1,
+ [SITAR_A_CDC_TX_I2S_SD0_MODE] = 1,
+ [SITAR_A_CDC_INTR_MODE] = 1,
+ [SITAR_A_CDC_RX_I2S_SD0_MODE] = 1,
+ [SITAR_A_CDC_RX_I2S_SD1_MODE] = 1,
+ [SITAR_A_BIAS_REF_CTL] = 1,
+ [SITAR_A_BIAS_CENTRAL_BG_CTL] = 1,
+ [SITAR_A_BIAS_PRECHRG_CTL] = 1,
+ [SITAR_A_BIAS_CURR_CTL_1] = 1,
+ [SITAR_A_BIAS_CURR_CTL_2] = 1,
+ [SITAR_A_BIAS_OSC_BG_CTL] = 1,
+ [SITAR_A_CLK_BUFF_EN1] = 1,
+ [SITAR_A_CLK_BUFF_EN2] = 1,
+ [SITAR_A_LDO_H_MODE_1] = 1,
+ [SITAR_A_LDO_H_MODE_2] = 1,
+ [SITAR_A_LDO_H_LOOP_CTL] = 1,
+ [SITAR_A_LDO_H_COMP_1] = 1,
+ [SITAR_A_LDO_H_COMP_2] = 1,
+ [SITAR_A_LDO_H_BIAS_1] = 1,
+ [SITAR_A_LDO_H_BIAS_2] = 1,
+ [SITAR_A_LDO_H_BIAS_3] = 1,
+ [SITAR_A_MICB_CFILT_1_CTL] = 1,
+ [SITAR_A_MICB_CFILT_1_VAL] = 1,
+ [SITAR_A_MICB_CFILT_1_PRECHRG] = 1,
+ [SITAR_A_MICB_1_CTL] = 1,
+ [SITAR_A_MICB_1_INT_RBIAS] = 1,
+ [SITAR_A_MICB_1_MBHC] = 1,
+ [SITAR_A_MICB_CFILT_2_CTL] = 1,
+ [SITAR_A_MICB_CFILT_2_VAL] = 1,
+ [SITAR_A_MICB_CFILT_2_PRECHRG] = 1,
+ [SITAR_A_MICB_2_CTL] = 1,
+ [SITAR_A_MICB_2_INT_RBIAS] = 1,
+ [SITAR_A_MICB_2_MBHC] = 1,
+ [SITAR_A_TX_COM_BIAS] = 1,
+ [SITAR_A_MBHC_SCALING_MUX_1] = 1,
+ [SITAR_A_MBHC_SCALING_MUX_2] = 1,
+ [SITAR_A_TX_SUP_SWITCH_CTRL_1] = 1,
+ [SITAR_A_TX_SUP_SWITCH_CTRL_2] = 1,
+ [SITAR_A_TX_1_2_EN] = 1,
+ [SITAR_A_TX_1_2_TEST_EN] = 1,
+ [SITAR_A_TX_1_2_ADC_CH1] = 1,
+ [SITAR_A_TX_1_2_ADC_CH2] = 1,
+ [SITAR_A_TX_1_2_ATEST_REFCTRL] = 1,
+ [SITAR_A_TX_1_2_TEST_CTL] = 1,
+ [SITAR_A_TX_1_2_TEST_BLOCK_EN] = 1,
+ [SITAR_A_TX_1_2_TXFE_CLKDIV] = 1,
+ [SITAR_A_TX_1_2_SAR_ERR_CH1] = 1,
+ [SITAR_A_TX_1_2_SAR_ERR_CH2] = 1,
+ [SITAR_A_TX_3_EN] = 1,
+ [SITAR_A_TX_3_TEST_EN] = 1,
+ [SITAR_A_TX_3_ADC] = 1,
+ [SITAR_A_TX_3_MBHC_ATEST_REFCTRL] = 1,
+ [SITAR_A_TX_3_TEST_CTL] = 1,
+ [SITAR_A_TX_3_TEST_BLOCK_EN] = 1,
+ [SITAR_A_TX_3_TXFE_CKDIV] = 1,
+ [SITAR_A_TX_3_SAR_ERR] = 1,
+ [SITAR_A_TX_4_MBHC_EN] = 1,
+ [SITAR_A_TX_4_MBHC_ADC] = 1,
+ [SITAR_A_TX_4_MBHC_TEST_CTL] = 1,
+ [SITAR_A_TX_4_MBHC_SAR_ERR] = 1,
+ [SITAR_A_TX_4_TXFE_CLKDIV] = 1,
+ [SITAR_A_AUX_COM_CTL] = 1,
+ [SITAR_A_AUX_COM_ATEST] = 1,
+ [SITAR_A_AUX_L_EN] = 1,
+ [SITAR_A_AUX_L_GAIN] = 1,
+ [SITAR_A_AUX_L_PA_CONN] = 1,
+ [SITAR_A_AUX_L_PA_CONN_INV] = 1,
+ [SITAR_A_AUX_R_EN] = 1,
+ [SITAR_A_AUX_R_GAIN] = 1,
+ [SITAR_A_AUX_R_PA_CONN] = 1,
+ [SITAR_A_AUX_R_PA_CONN_INV] = 1,
+ [SITAR_A_CP_EN] = 1,
+ [SITAR_A_CP_CLK] = 1,
+ [SITAR_A_CP_STATIC] = 1,
+ [SITAR_A_CP_DCC1] = 1,
+ [SITAR_A_CP_DCC3] = 1,
+ [SITAR_A_CP_ATEST] = 1,
+ [SITAR_A_CP_DTEST] = 1,
+ [SITAR_A_RX_COM_TIMER_DIV] = 1,
+ [SITAR_A_RX_COM_OCP_CTL] = 1,
+ [SITAR_A_RX_COM_OCP_COUNT] = 1,
+ [SITAR_A_RX_COM_DAC_CTL] = 1,
+ [SITAR_A_RX_COM_BIAS] = 1,
+ [SITAR_A_RX_HPH_BIAS_PA] = 1,
+ [SITAR_A_RX_HPH_BIAS_LDO] = 1,
+ [SITAR_A_RX_HPH_BIAS_CNP] = 1,
+ [SITAR_A_RX_HPH_BIAS_WG] = 1,
+ [SITAR_A_RX_HPH_OCP_CTL] = 1,
+ [SITAR_A_RX_HPH_CNP_EN] = 1,
+ [SITAR_A_RX_HPH_CNP_WG_CTL] = 1,
+ [SITAR_A_RX_HPH_CNP_WG_TIME] = 1,
+ [SITAR_A_RX_HPH_L_GAIN] = 1,
+ [SITAR_A_RX_HPH_L_TEST] = 1,
+ [SITAR_A_RX_HPH_L_PA_CTL] = 1,
+ [SITAR_A_RX_HPH_L_DAC_CTL] = 1,
+ [SITAR_A_RX_HPH_L_ATEST] = 1,
+ [SITAR_A_RX_HPH_L_STATUS] = 1,
+ [SITAR_A_RX_HPH_R_GAIN] = 1,
+ [SITAR_A_RX_HPH_R_TEST] = 1,
+ [SITAR_A_RX_HPH_R_PA_CTL] = 1,
+ [SITAR_A_RX_HPH_R_DAC_CTL] = 1,
+ [SITAR_A_RX_HPH_R_ATEST] = 1,
+ [SITAR_A_RX_HPH_R_STATUS] = 1,
+ [SITAR_A_RX_EAR_BIAS_PA] = 1,
+ [SITAR_A_RX_EAR_BIAS_CMBUFF] = 1,
+ [SITAR_A_RX_EAR_EN] = 1,
+ [SITAR_A_RX_EAR_GAIN] = 1,
+ [SITAR_A_RX_EAR_CMBUFF] = 1,
+ [SITAR_A_RX_EAR_ICTL] = 1,
+ [SITAR_A_RX_EAR_CCOMP] = 1,
+ [SITAR_A_RX_EAR_VCM] = 1,
+ [SITAR_A_RX_EAR_CNP] = 1,
+ [SITAR_A_RX_EAR_ATEST] = 1,
+ [SITAR_A_RX_EAR_STATUS] = 1,
+ [SITAR_A_RX_LINE_BIAS_PA] = 1,
+ [SITAR_A_RX_LINE_BIAS_LDO] = 1,
+ [SITAR_A_RX_LINE_BIAS_CNP1] = 1,
+ [SITAR_A_RX_LINE_COM] = 1,
+ [SITAR_A_RX_LINE_CNP_EN] = 1,
+ [SITAR_A_RX_LINE_CNP_WG_CTL] = 1,
+ [SITAR_A_RX_LINE_CNP_WG_TIME] = 1,
+ [SITAR_A_RX_LINE_1_GAIN] = 1,
+ [SITAR_A_RX_LINE_1_TEST] = 1,
+ [SITAR_A_RX_LINE_1_DAC_CTL] = 1,
+ [SITAR_A_RX_LINE_1_STATUS] = 1,
+ [SITAR_A_RX_LINE_2_GAIN] = 1,
+ [SITAR_A_RX_LINE_2_TEST] = 1,
+ [SITAR_A_RX_LINE_2_DAC_CTL] = 1,
+ [SITAR_A_RX_LINE_2_STATUS] = 1,
+ [SITAR_A_RX_LINE_BIAS_CNP2] = 1,
+ [SITAR_A_RX_LINE_OCP_CTL] = 1,
+ [SITAR_A_RX_LINE_1_PA_CTL] = 1,
+ [SITAR_A_RX_LINE_2_PA_CTL] = 1,
+ [SITAR_A_RX_LINE_CNP_DBG] = 1,
+ [SITAR_A_MBHC_HPH] = 1,
+ [SITAR_A_RC_OSC_FREQ] = 1,
+ [SITAR_A_RC_OSC_TEST] = 1,
+ [SITAR_A_RC_OSC_STATUS] = 1,
+ [SITAR_A_RC_OSC_TUNER] = 1,
+ [SITAR_A_CDC_ANC1_CTL] = 1,
+ [SITAR_A_CDC_ANC1_SHIFT] = 1,
+ [SITAR_A_CDC_ANC1_IIR_B1_CTL] = 1,
+ [SITAR_A_CDC_ANC1_IIR_B2_CTL] = 1,
+ [SITAR_A_CDC_ANC1_IIR_B3_CTL] = 1,
+ [SITAR_A_CDC_ANC1_IIR_B4_CTL] = 1,
+ [SITAR_A_CDC_ANC1_LPF_B1_CTL] = 1,
+ [SITAR_A_CDC_ANC1_LPF_B2_CTL] = 1,
+ [SITAR_A_CDC_ANC1_LPF_B3_CTL] = 1,
+ [SITAR_A_CDC_ANC1_SPARE] = 1,
+ [SITAR_A_CDC_ANC1_SMLPF_CTL] = 1,
+ [SITAR_A_CDC_ANC1_DCFLT_CTL] = 1,
+ [SITAR_A_CDC_TX1_VOL_CTL_TIMER] = 1,
+ [SITAR_A_CDC_TX1_VOL_CTL_GAIN] = 1,
+ [SITAR_A_CDC_TX1_VOL_CTL_CFG] = 1,
+ [SITAR_A_CDC_TX1_MUX_CTL] = 1,
+ [SITAR_A_CDC_TX1_CLK_FS_CTL] = 1,
+ [SITAR_A_CDC_TX1_DMIC_CTL] = 1,
+ [SITAR_A_CDC_SRC1_PDA_CFG] = 1,
+ [SITAR_A_CDC_SRC1_FS_CTL] = 1,
+ [SITAR_A_CDC_RX1_B1_CTL] = 1,
+ [SITAR_A_CDC_RX1_B2_CTL] = 1,
+ [SITAR_A_CDC_RX1_B3_CTL] = 1,
+ [SITAR_A_CDC_RX1_B4_CTL] = 1,
+ [SITAR_A_CDC_RX1_B5_CTL] = 1,
+ [SITAR_A_CDC_RX1_B6_CTL] = 1,
+ [SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
+ [SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
+ [SITAR_A_CDC_CLK_ANC_RESET_CTL] = 1,
+ [SITAR_A_CDC_CLK_RX_RESET_CTL] = 1,
+ [SITAR_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
+ [SITAR_A_CDC_CLK_TX_RESET_B2_CTL] = 1,
+ [SITAR_A_CDC_CLK_DMIC_CTL] = 1,
+ [SITAR_A_CDC_CLK_RX_I2S_CTL] = 1,
+ [SITAR_A_CDC_CLK_TX_I2S_CTL] = 1,
+ [SITAR_A_CDC_CLK_OTHR_RESET_CTL] = 1,
+ [SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
+ [SITAR_A_CDC_CLK_OTHR_CTL] = 1,
+ [SITAR_A_CDC_CLK_RDAC_CLK_EN_CTL] = 1,
+ [SITAR_A_CDC_CLK_ANC_CLK_EN_CTL] = 1,
+ [SITAR_A_CDC_CLK_RX_B1_CTL] = 1,
+ [SITAR_A_CDC_CLK_RX_B2_CTL] = 1,
+ [SITAR_A_CDC_CLK_MCLK_CTL] = 1,
+ [SITAR_A_CDC_CLK_PDM_CTL] = 1,
+ [SITAR_A_CDC_CLK_SD_CTL] = 1,
+ [SITAR_A_CDC_CLK_LP_CTL] = 1,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B1_CTL] = 1,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B2_CTL] = 1,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL] = 1,
+ [SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL] = 1,
+ [SITAR_A_CDC_CLSG_GAIN_THRESH_CTL] = 1,
+ [SITAR_A_CDC_CLSG_TIMER_B1_CFG] = 1,
+ [SITAR_A_CDC_CLSG_TIMER_B2_CFG] = 1,
+ [SITAR_A_CDC_CLSG_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B1_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B2_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B3_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B4_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B5_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B6_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B7_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_B8_CTL] = 1,
+ [SITAR_A_CDC_IIR1_CTL] = 1,
+ [SITAR_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
+ [SITAR_A_CDC_IIR1_COEF_B1_CTL] = 1,
+ [SITAR_A_CDC_IIR1_COEF_B2_CTL] = 1,
+ [SITAR_A_CDC_IIR1_COEF_B3_CTL] = 1,
+ [SITAR_A_CDC_IIR1_COEF_B4_CTL] = 1,
+ [SITAR_A_CDC_IIR1_COEF_B5_CTL] = 1,
+ [SITAR_A_CDC_TOP_GAIN_UPDATE] = 1,
+ [SITAR_A_CDC_TOP_RDAC_DOUT_CTL] = 1,
+ [SITAR_A_CDC_DEBUG_B1_CTL] = 1,
+ [SITAR_A_CDC_DEBUG_B2_CTL] = 1,
+ [SITAR_A_CDC_DEBUG_B3_CTL] = 1,
+ [SITAR_A_CDC_DEBUG_B4_CTL] = 1,
+ [SITAR_A_CDC_DEBUG_B5_CTL] = 1,
+ [SITAR_A_CDC_DEBUG_B6_CTL] = 1,
+ [SITAR_A_CDC_DEBUG_B7_CTL] = 1,
+ [SITAR_A_CDC_COMP1_B1_CTL] = 1,
+ [SITAR_A_CDC_COMP1_B2_CTL] = 1,
+ [SITAR_A_CDC_COMP1_B3_CTL] = 1,
+ [SITAR_A_CDC_COMP1_B4_CTL] = 1,
+ [SITAR_A_CDC_COMP1_B5_CTL] = 1,
+ [SITAR_A_CDC_COMP1_B6_CTL] = 1,
+ [SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
+ [SITAR_A_CDC_COMP1_FS_CFG] = 1,
+ [SITAR_A_CDC_CONN_RX1_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX1_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX1_B3_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX2_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX2_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX2_B3_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX3_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX3_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX3_B3_CTL] = 1,
+ [SITAR_A_CDC_CONN_ANC_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_ANC_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_TX_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_TX_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ1_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ1_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ1_B3_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ1_B4_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ2_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ2_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ2_B3_CTL] = 1,
+ [SITAR_A_CDC_CONN_EQ2_B4_CTL] = 1,
+ [SITAR_A_CDC_CONN_SRC1_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_SRC1_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_SRC2_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_SRC2_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_TX_SB_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_TX_SB_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_TX_SB_B3_CTL] = 1,
+ [SITAR_A_CDC_CONN_TX_SB_B4_CTL] = 1,
+ [SITAR_A_CDC_CONN_TX_SB_B5_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX_SB_B1_CTL] = 1,
+ [SITAR_A_CDC_CONN_RX_SB_B2_CTL] = 1,
+ [SITAR_A_CDC_CONN_CLSG_CTL] = 1,
+ [SITAR_A_CDC_CONN_SPARE] = 1,
+ [SITAR_A_CDC_MBHC_EN_CTL] = 1,
+ [SITAR_A_CDC_MBHC_FIR_B1_CFG] = 1,
+ [SITAR_A_CDC_MBHC_FIR_B2_CFG] = 1,
+ [SITAR_A_CDC_MBHC_TIMER_B1_CTL] = 1,
+ [SITAR_A_CDC_MBHC_TIMER_B2_CTL] = 1,
+ [SITAR_A_CDC_MBHC_TIMER_B3_CTL] = 1,
+ [SITAR_A_CDC_MBHC_TIMER_B4_CTL] = 1,
+ [SITAR_A_CDC_MBHC_TIMER_B5_CTL] = 1,
+ [SITAR_A_CDC_MBHC_TIMER_B6_CTL] = 1,
+ [SITAR_A_CDC_MBHC_B1_STATUS] = 1,
+ [SITAR_A_CDC_MBHC_B2_STATUS] = 1,
+ [SITAR_A_CDC_MBHC_B3_STATUS] = 1,
+ [SITAR_A_CDC_MBHC_B4_STATUS] = 1,
+ [SITAR_A_CDC_MBHC_B5_STATUS] = 1,
+ [SITAR_A_CDC_MBHC_B1_CTL] = 1,
+ [SITAR_A_CDC_MBHC_B2_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B1_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B2_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B3_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B4_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B5_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B6_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B7_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B8_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B9_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B10_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B11_CTL] = 1,
+ [SITAR_A_CDC_MBHC_VOLT_B12_CTL] = 1,
+ [SITAR_A_CDC_MBHC_CLK_CTL] = 1,
+ [SITAR_A_CDC_MBHC_INT_CTL] = 1,
+ [SITAR_A_CDC_MBHC_DEBUG_CTL] = 1,
+ [SITAR_A_CDC_MBHC_SPARE] = 1,
+};
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
new file mode 100644
index 0000000..1d93d7a
--- /dev/null
+++ b/sound/soc/codecs/wcd9304.c
@@ -0,0 +1,3593 @@
+/* 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include "wcd9304.h"
+
+#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
+ SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
+
+#define NUM_DECIMATORS 4
+#define NUM_INTERPOLATORS 3
+#define BITS_PER_REG 8
+#define AIF1_PB 1
+#define AIF1_CAP 2
+#define NUM_CODEC_DAIS 2
+
+struct sitar_codec_dai_data {
+ u32 rate;
+ u32 *ch_num;
+ u32 ch_act;
+ u32 ch_tot;
+};
+#define SITAR_CFILT_FAST_MODE 0x00
+#define SITAR_CFILT_SLOW_MODE 0x40
+
+
+#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
+
+#define SITAR_I2S_MASTER_MODE_MASK 0x08
+
+#define SITAR_OCP_ATTEMPT 1
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver sitar_dai[];
+static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+enum sitar_bandgap_type {
+ SITAR_BANDGAP_OFF = 0,
+ SITAR_BANDGAP_AUDIO_MODE,
+ SITAR_BANDGAP_MBHC_MODE,
+};
+
+struct mbhc_micbias_regs {
+ u16 cfilt_val;
+ u16 cfilt_ctl;
+ u16 mbhc_reg;
+ u16 int_rbias;
+ u16 ctl_reg;
+ u8 cfilt_sel;
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+ IIR1 = 0,
+ IIR2,
+ IIR_MAX,
+};
+/* Codec supports 5 bands */
+enum {
+ BAND1 = 0,
+ BAND2,
+ BAND3,
+ BAND4,
+ BAND5,
+ BAND_MAX,
+};
+
+/* Flags to track of PA and DAC state.
+ * PA and DAC should be tracked separately as AUXPGA loopback requires
+ * only PA to be turned on without DAC being on. */
+enum sitar_priv_ack_flags {
+ SITAR_HPHL_PA_OFF_ACK = 0,
+ SITAR_HPHR_PA_OFF_ACK,
+ SITAR_HPHL_DAC_OFF_ACK,
+ SITAR_HPHR_DAC_OFF_ACK
+};
+
+struct sitar_priv {
+ struct snd_soc_codec *codec;
+ u32 adc_count;
+ u32 cfilt1_cnt;
+ u32 cfilt2_cnt;
+ u32 cfilt3_cnt;
+ u32 rx_bias_count;
+ enum sitar_bandgap_type bandgap_type;
+ bool mclk_enabled;
+ bool clock_active;
+ bool config_mode_active;
+ bool mbhc_polling_active;
+ bool fake_insert_context;
+ int buttons_pressed;
+
+ struct sitar_mbhc_calibration *calibration;
+
+ struct snd_soc_jack *headset_jack;
+ struct snd_soc_jack *button_jack;
+
+ struct wcd9xxx_pdata *pdata;
+ u32 anc_slot;
+
+ bool no_mic_headset_override;
+ /* Delayed work to report long button press */
+ struct delayed_work btn0_dwork;
+
+ struct mbhc_micbias_regs mbhc_bias_regs;
+ u8 cfilt_k_value;
+ bool mbhc_micbias_switched;
+
+ /* track PA/DAC state */
+ unsigned long hph_pa_dac_state;
+
+ /*track sitar interface type*/
+ u8 intf_type;
+
+ u32 hph_status; /* track headhpone status */
+ /* define separate work for left and right headphone OCP to avoid
+ * additional checking on which OCP event to report so no locking
+ * to ensure synchronization is required
+ */
+ struct work_struct hphlocp_work; /* reporting left hph ocp off */
+ struct work_struct hphrocp_work; /* reporting right hph ocp off */
+
+ /* pm_cnt holds number of sleep lock holders + 1
+ * so if pm_cnt is 1 system is sleep-able. */
+ atomic_t pm_cnt;
+ wait_queue_head_t pm_wq;
+
+ u8 hphlocp_cnt; /* headphone left ocp retry */
+ u8 hphrocp_cnt; /* headphone right ocp retry */
+ /* num of slim ports required */
+ struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
+};
+
+#ifdef CONFIG_DEBUG_FS
+struct sitar_priv *debug_sitar_priv;
+#endif
+
+
+static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
+
+ ear_pa_gain = ear_pa_gain >> 5;
+
+ if (ear_pa_gain == 0x00) {
+ ucontrol->value.integer.value[0] = 0;
+ } else if (ear_pa_gain == 0x04) {
+ ucontrol->value.integer.value[0] = 1;
+ } else {
+ pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+ __func__, ear_pa_gain);
+ return -EINVAL;
+ }
+
+ pr_err("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+
+ return 0;
+}
+
+static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ ear_pa_gain = 0x00;
+ break;
+ case 1:
+ ear_pa_gain = 0x80;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, SITAR_A_RX_EAR_GAIN, ear_pa_gain);
+ return 0;
+}
+
+static int sitar_get_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx);
+
+ pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int sitar_put_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ /* Mask first 5 bits, 6-8 are reserved */
+ snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
+ (1 << band_idx), (value << band_idx));
+
+ pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx, value);
+ return 0;
+}
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ int coeff_idx)
+{
+ /* Address does not automatically update if reading */
+ snd_soc_update_bits(codec,
+ (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ 0x1F, band_idx * BAND_MAX + coeff_idx);
+
+ /* Mask bits top 2 bits since they are reserved */
+ return ((snd_soc_read(codec,
+ (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
+ (snd_soc_read(codec,
+ (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
+ (snd_soc_read(codec,
+ (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
+ (snd_soc_read(codec,
+ (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
+ 0x3FFFFFFF;
+}
+
+static int sitar_get_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+ ucontrol->value.integer.value[1] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+ ucontrol->value.integer.value[2] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+ ucontrol->value.integer.value[3] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+ ucontrol->value.integer.value[4] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+ pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[1],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[2],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[3],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[4]);
+ return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ int coeff_idx, uint32_t value)
+{
+ /* Mask top 3 bits, 6-8 are reserved */
+ /* Update address manually each time */
+ snd_soc_update_bits(codec,
+ (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ 0x1F, band_idx * BAND_MAX + coeff_idx);
+
+ /* Mask top 2 bits, 7-8 are reserved */
+ snd_soc_update_bits(codec,
+ (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ 0x3F, (value >> 24) & 0x3F);
+
+ /* Isolate 8bits at a time */
+ snd_soc_update_bits(codec,
+ (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
+ 0xFF, (value >> 16) & 0xFF);
+
+ snd_soc_update_bits(codec,
+ (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
+ 0xFF, (value >> 8) & 0xFF);
+
+ snd_soc_update_bits(codec,
+ (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
+ 0xFF, value & 0xFF);
+}
+
+static int sitar_put_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+ ucontrol->value.integer.value[0]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+ ucontrol->value.integer.value[1]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+ ucontrol->value.integer.value[2]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+ ucontrol->value.integer.value[3]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+ ucontrol->value.integer.value[4]);
+
+ pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+ return 0;
+}
+
+static const char *sitar_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
+static const struct soc_enum sitar_ear_pa_gain_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, sitar_ear_pa_gain_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char *cf_text[] = {
+ "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_dec1_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_rxmix1_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+
+static const struct snd_kcontrol_new sitar_snd_controls[] = {
+
+ SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
+ sitar_pa_gain_get, sitar_pa_gain_put),
+
+ SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
+ line_gain),
+
+ SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+
+ SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+
+ SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
+ SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
+
+ SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+
+ SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
+
+ SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
+
+ SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+
+ SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+ sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
+
+ SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+ sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+};
+
+static const char *rx_mix1_text[] = {
+ "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
+ "RX5"
+};
+
+static const char *rx_dac1_text[] = {
+ "ZERO", "RX1", "RX2"
+};
+
+static const char *rx_dac2_text[] = {
+ "ZERO", "RX1",
+};
+
+static const char *rx_dac3_text[] = {
+ "ZERO", "RX1", "RX1_INV", "RX2"
+};
+
+static const char *rx_dac4_text[] = {
+ "ZERO", "ON"
+};
+
+static const char *sb_tx1_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC1"
+};
+
+static const char *sb_tx2_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC2"
+};
+
+static const char *sb_tx3_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC3"
+};
+
+static const char *sb_tx5_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC5"
+};
+
+static const char *dec1_mux_text[] = {
+ "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANCFB1",
+};
+
+static const char *dec2_mux_text[] = {
+ "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANCFB2",
+};
+
+static const char *dec3_mux_text[] = {
+ "ZERO", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3", "MBADC",
+};
+
+static const char *dec4_mux_text[] = {
+ "ZERO", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3",
+};
+
+static const char *iir1_inp1_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
+ "ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
+};
+
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
+
+static const struct soc_enum rx_dac1_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
+
+static const struct soc_enum rx_dac2_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
+
+static const struct soc_enum rx_dac3_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
+
+static const struct soc_enum rx_dac4_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
+
+static const struct soc_enum sb_tx3_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
+
+static const struct soc_enum sb_tx2_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
+
+static const struct soc_enum sb_tx1_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
+
+static const struct soc_enum dec1_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 2, 8, dec2_mux_text);
+
+static const struct soc_enum dec3_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 4, 8, dec3_mux_text);
+
+static const struct soc_enum dec4_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 6, 8, dec4_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_dac1_mux =
+ SOC_DAPM_ENUM("RX1 DAC Mux", rx_dac1_enum);
+
+static const struct snd_kcontrol_new rx_dac2_mux =
+ SOC_DAPM_ENUM("RX2 DAC Mux", rx_dac2_enum);
+
+static const struct snd_kcontrol_new rx_dac3_mux =
+ SOC_DAPM_ENUM("RX3 DAC Mux", rx_dac3_enum);
+
+static const struct snd_kcontrol_new rx_dac4_mux =
+ SOC_DAPM_ENUM("RX4 DAC Mux", rx_dac4_enum);
+
+static const struct snd_kcontrol_new sb_tx5_mux =
+ SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx3_mux =
+ SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx2_mux =
+ SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx1_mux =
+ SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+
+static const struct snd_kcontrol_new dec1_mux =
+ SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+ SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new dec3_mux =
+ SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+
+static const struct snd_kcontrol_new dec4_mux =
+ SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+ SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new dac1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new hphl_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SITAR_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
+};
+
+static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
+ int enable)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ pr_err("%s %d\n", __func__, enable);
+
+ if (enable) {
+ sitar->adc_count++;
+ snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
+
+ } else {
+ sitar->adc_count--;
+ if (!sitar->adc_count) {
+ if (!sitar->mbhc_polling_active)
+ snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS,
+ 0xE0, 0x0);
+ }
+ }
+}
+
+static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 adc_reg;
+
+ pr_err("%s %d\n", __func__, event);
+
+ if (w->reg == SITAR_A_TX_1_2_EN)
+ adc_reg = SITAR_A_TX_1_2_TEST_CTL;
+ else {
+ pr_err("%s: Error, invalid adc register\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ sitar_codec_enable_adc_block(codec, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
+ 1 << w->shift);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, adc_reg, 0x08, 0x08);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ sitar_codec_enable_adc_block(codec, 0);
+ break;
+ }
+ return 0;
+}
+
+static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 lineout_gain_reg;
+
+ pr_err("%s %d %s\n", __func__, event, w->name);
+
+ switch (w->shift) {
+ case 0:
+ lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
+ break;
+ case 1:
+ lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
+ break;
+ default:
+ pr_err("%s: Error, incorrect lineout register value\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ pr_err("%s: sleeping 16 ms after %s PA turn on\n",
+ __func__, w->name);
+ usleep_range(16000, 16000);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
+ u8 dmic_clk_sel, dmic_clk_en;
+ unsigned int dmic;
+ int ret;
+
+ ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
+ if (ret < 0) {
+ pr_err("%s: Invalid DMIC line on the codec\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (dmic) {
+ case 1:
+ case 2:
+ dmic_clk_sel = 0x02;
+ dmic_clk_en = 0x01;
+ break;
+ case 3:
+ case 4:
+ dmic_clk_sel = 0x08;
+ dmic_clk_en = 0x04;
+ break;
+
+ break;
+
+ default:
+ pr_err("%s: Invalid DMIC Selection\n", __func__);
+ return -EINVAL;
+ }
+
+ tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
+ tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
+
+ pr_err("%s %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+ dmic_clk_sel, dmic_clk_sel);
+
+ snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+ dmic_clk_en, dmic_clk_en);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
+ dmic_clk_en, 0);
+ break;
+ }
+ return 0;
+}
+
+
+static void sitar_codec_disable_button_presses(struct snd_soc_codec *codec)
+{
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
+}
+
+static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+ wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+ if (!sitar->no_mic_headset_override) {
+ wcd9xxx_enable_irq(codec->control_data,
+ SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data,
+ SITAR_IRQ_MBHC_RELEASE);
+ } else {
+ sitar_codec_disable_button_presses(codec);
+ }
+}
+
+static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+ if (!sitar->no_mic_headset_override) {
+ wcd9xxx_disable_irq(codec->control_data,
+ SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data,
+ SITAR_IRQ_MBHC_RELEASE);
+ }
+}
+
+static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
+ int mode)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u8 reg_mode_val, cur_mode_val;
+ bool mbhc_was_polling = false;
+
+ if (mode)
+ reg_mode_val = SITAR_CFILT_FAST_MODE;
+ else
+ reg_mode_val = SITAR_CFILT_SLOW_MODE;
+
+ cur_mode_val = snd_soc_read(codec,
+ sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
+
+ if (cur_mode_val != reg_mode_val) {
+ if (sitar->mbhc_polling_active) {
+ sitar_codec_pause_hs_polling(codec);
+ mbhc_was_polling = true;
+ }
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
+ if (mbhc_was_polling)
+ sitar_codec_start_hs_polling(codec);
+ pr_err("%s: CFILT mode change (%x to %x)\n", __func__,
+ cur_mode_val, reg_mode_val);
+ } else {
+ pr_err("%s: CFILT Value is already %x\n",
+ __func__, cur_mode_val);
+ }
+}
+
+static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
+ u8 cfilt_sel, int inc)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u32 *cfilt_cnt_ptr = NULL;
+ u16 micb_cfilt_reg;
+
+ switch (cfilt_sel) {
+ case SITAR_CFILT1_SEL:
+ cfilt_cnt_ptr = &sitar->cfilt1_cnt;
+ micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
+ break;
+ case SITAR_CFILT2_SEL:
+ cfilt_cnt_ptr = &sitar->cfilt2_cnt;
+ micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
+ break;
+ default:
+ return; /* should not happen */
+ }
+
+ if (inc) {
+ if (!(*cfilt_cnt_ptr)++) {
+ /* Switch CFILT to slow mode if MBHC CFILT being used */
+ if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
+ sitar_codec_switch_cfilt_mode(codec, 0);
+
+ snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
+ }
+ } else {
+ /* check if count not zero, decrement
+ * then check if zero, go ahead disable cfilter
+ */
+ if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
+ snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
+
+ /* Switch CFILT to fast mode if MBHC CFILT being used */
+ if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
+ sitar_codec_switch_cfilt_mode(codec, 1);
+ }
+ }
+}
+
+static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
+{
+ int rc = -EINVAL;
+ unsigned min_mv, max_mv;
+
+ switch (ldoh_v) {
+ case SITAR_LDOH_1P95_V:
+ min_mv = 160;
+ max_mv = 1800;
+ break;
+ case SITAR_LDOH_2P35_V:
+ min_mv = 200;
+ max_mv = 2200;
+ break;
+ case SITAR_LDOH_2P75_V:
+ min_mv = 240;
+ max_mv = 2600;
+ break;
+ case SITAR_LDOH_2P85_V:
+ min_mv = 250;
+ max_mv = 2700;
+ break;
+ default:
+ goto done;
+ }
+
+ if (cfilt_mv < min_mv || cfilt_mv > max_mv)
+ goto done;
+
+ for (rc = 4; rc <= 44; rc++) {
+ min_mv = max_mv * (rc) / 44;
+ if (min_mv >= cfilt_mv) {
+ rc -= 4;
+ break;
+ }
+ }
+done:
+ return rc;
+}
+
+static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
+{
+ u8 hph_reg_val = 0;
+ hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
+
+ return (hph_reg_val & 0x30) ? true : false;
+}
+
+static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
+{
+ u8 hph_reg_val = 0;
+ if (left)
+ hph_reg_val = snd_soc_read(codec,
+ SITAR_A_RX_HPH_L_DAC_CTL);
+ else
+ hph_reg_val = snd_soc_read(codec,
+ SITAR_A_RX_HPH_R_DAC_CTL);
+
+ return (hph_reg_val & 0xC0) ? true : false;
+}
+
+static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
+ int vddio_switch)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ int cfilt_k_val;
+ bool mbhc_was_polling = false;
+
+ switch (vddio_switch) {
+ case 1:
+ if (sitar->mbhc_polling_active) {
+
+ sitar_codec_pause_hs_polling(codec);
+ /* Enable Mic Bias switch to VDDIO */
+ sitar->cfilt_k_value = snd_soc_read(codec,
+ sitar->mbhc_bias_regs.cfilt_val);
+ cfilt_k_val = sitar_find_k_value(
+ sitar->pdata->micbias.ldoh_v, 1800);
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.cfilt_val,
+ 0xFC, (cfilt_k_val << 2));
+
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
+ sitar_codec_start_hs_polling(codec);
+
+ sitar->mbhc_micbias_switched = true;
+ pr_err("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
+ __func__);
+ }
+ break;
+
+ case 0:
+ if (sitar->mbhc_micbias_switched) {
+ if (sitar->mbhc_polling_active) {
+ sitar_codec_pause_hs_polling(codec);
+ mbhc_was_polling = true;
+ }
+ /* Disable Mic Bias switch to VDDIO */
+ if (sitar->cfilt_k_value != 0)
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.cfilt_val, 0XFC,
+ sitar->cfilt_k_value);
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
+
+ if (mbhc_was_polling)
+ sitar_codec_start_hs_polling(codec);
+
+ sitar->mbhc_micbias_switched = false;
+ pr_err("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
+ __func__);
+ }
+ break;
+ }
+}
+
+static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u16 micb_int_reg;
+ int micb_line;
+ u8 cfilt_sel_val = 0;
+ char *internal1_text = "Internal1";
+ char *internal2_text = "Internal2";
+
+ pr_err("%s %d\n", __func__, event);
+ switch (w->reg) {
+ case SITAR_A_MICB_1_CTL:
+ micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
+ cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
+ micb_line = SITAR_MICBIAS1;
+ break;
+ case SITAR_A_MICB_2_CTL:
+ micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
+ cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
+ micb_line = SITAR_MICBIAS2;
+ break;
+ default:
+ pr_err("%s: Error, invalid micbias register\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Decide whether to switch the micbias for MBHC */
+ if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
+ && sitar->mbhc_micbias_switched)
+ sitar_codec_switch_micbias(codec, 0);
+
+ snd_soc_update_bits(codec, w->reg, 0x1E, 0x0A);
+ sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
+
+ if (strnstr(w->name, internal1_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
+ else if (strnstr(w->name, internal2_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (sitar->mbhc_polling_active &&
+ (sitar->calibration->bias == micb_line)) {
+ sitar_codec_pause_hs_polling(codec);
+ sitar_codec_start_hs_polling(codec);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+
+ if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
+ && sitar_is_hph_pa_on(codec))
+ sitar_codec_switch_micbias(codec, 1);
+
+ if (strnstr(w->name, internal1_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
+ else if (strnstr(w->name, internal2_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
+ sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 dec_reset_reg;
+
+ pr_err("%s %d\n", __func__, event);
+
+ if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
+ dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
+ else {
+ pr_err("%s: Error, incorrect dec\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+ 1 << w->shift);
+ snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+ break;
+ }
+ return 0;
+}
+
+static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_err("%s %d %s\n", __func__, event, w->name);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
+ 1 << w->shift, 1 << w->shift);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
+ 1 << w->shift, 0x0);
+ break;
+ }
+ return 0;
+}
+
+static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(1000, 1000);
+ pr_debug("LDO_H\n");
+ break;
+ }
+ return 0;
+}
+
+static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ if (enable) {
+ sitar->rx_bias_count++;
+ if (sitar->rx_bias_count == 1)
+ snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
+ 0x80, 0x80);
+ } else {
+ sitar->rx_bias_count--;
+ if (!sitar->rx_bias_count)
+ snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
+ 0x80, 0x00);
+ }
+}
+
+static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_err("%s %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ sitar_enable_rx_bias(codec, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ sitar_enable_rx_bias(codec, 0);
+ break;
+ }
+ return 0;
+}
+static int sitar_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_err("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
+ struct snd_soc_jack *jack, int status,
+ int mask)
+{
+ /* XXX: wake_lock_timeout()? */
+ snd_soc_jack_report(jack, status, mask);
+}
+
+static void hphocp_off_report(struct sitar_priv *sitar,
+ u32 jack_status, int irq)
+{
+ struct snd_soc_codec *codec;
+
+ if (sitar) {
+ pr_info("%s: clear ocp status %x\n", __func__, jack_status);
+ codec = sitar->codec;
+ sitar->hph_status &= ~jack_status;
+ if (sitar->headset_jack)
+ sitar_snd_soc_jack_report(sitar, sitar->headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ /* reset retry counter as PA is turned off signifying
+ * start of new OCP detection session
+ */
+ if (SITAR_IRQ_HPH_PA_OCPL_FAULT)
+ sitar->hphlocp_cnt = 0;
+ else
+ sitar->hphrocp_cnt = 0;
+ wcd9xxx_enable_irq(codec->control_data, irq);
+ } else {
+ pr_err("%s: Bad sitar private data\n", __func__);
+ }
+}
+
+static void hphlocp_off_report(struct work_struct *work)
+{
+ struct sitar_priv *sitar = container_of(work, struct sitar_priv,
+ hphlocp_work);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHL, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+}
+
+static void hphrocp_off_report(struct work_struct *work)
+{
+ struct sitar_priv *sitar = container_of(work, struct sitar_priv,
+ hphrocp_work);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHR, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+}
+
+static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u8 mbhc_micb_ctl_val;
+ pr_err("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mbhc_micb_ctl_val = snd_soc_read(codec,
+ sitar->mbhc_bias_regs.ctl_reg);
+
+ if (!(mbhc_micb_ctl_val & 0x80)
+ && !sitar->mbhc_micbias_switched)
+ sitar_codec_switch_micbias(codec, 1);
+
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ /* schedule work is required because at the time HPH PA DAPM
+ * event callback is called by DAPM framework, CODEC dapm mutex
+ * would have been locked while snd_soc_jack_report also
+ * attempts to acquire same lock.
+ */
+ if (w->shift == 5) {
+ clear_bit(SITAR_HPHL_PA_OFF_ACK,
+ &sitar->hph_pa_dac_state);
+ clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+ &sitar->hph_pa_dac_state);
+ if (sitar->hph_status & SND_JACK_OC_HPHL)
+ schedule_work(&sitar->hphlocp_work);
+ } else if (w->shift == 4) {
+ clear_bit(SITAR_HPHR_PA_OFF_ACK,
+ &sitar->hph_pa_dac_state);
+ clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+ &sitar->hph_pa_dac_state);
+ if (sitar->hph_status & SND_JACK_OC_HPHR)
+ schedule_work(&sitar->hphrocp_work);
+ }
+
+ if (sitar->mbhc_micbias_switched)
+ sitar_codec_switch_micbias(codec, 0);
+
+ pr_err("%s: sleep 10 ms after %s PA disable.\n", __func__,
+ w->name);
+ usleep_range(10000, 10000);
+
+ break;
+ }
+ return 0;
+}
+
+static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
+ struct mbhc_micbias_regs *micbias_regs)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct sitar_mbhc_calibration *calibration = sitar->calibration;
+ unsigned int cfilt;
+
+ switch (calibration->bias) {
+ case SITAR_MICBIAS1:
+ cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
+ micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
+ micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
+ micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
+ break;
+ case SITAR_MICBIAS2:
+ cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
+ micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
+ micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
+ micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
+ break;
+ default:
+ /* Should never reach here */
+ pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
+ return;
+ }
+
+ micbias_regs->cfilt_sel = cfilt;
+
+ switch (cfilt) {
+ case SITAR_CFILT1_SEL:
+ micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
+ micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
+ break;
+ case SITAR_CFILT2_SEL:
+ micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
+ micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
+ break;
+ }
+}
+
+static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_err("%s %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
+ 0x01);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
+ usleep_range(200, 200);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
+ 0x10);
+ usleep_range(20, 20);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
+ 0x00);
+ snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
+ 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
+ /*RX stuff */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+
+ SND_SOC_DAPM_PGA("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
+ ARRAY_SIZE(dac1_switch)),
+ SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+ 0, sitar_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+ 0, sitar_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM RX5", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Headphone */
+ SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+ SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+ sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("HPHL DAC", SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
+ hphl_switch, ARRAY_SIZE(hphl_switch)),
+
+ SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+ sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
+ sitar_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Speaker */
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+
+ SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
+ 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
+ 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+ 0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+ 0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+ 0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac1_mux),
+ SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac2_mux),
+ SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac3_mux),
+ SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac4_mux),
+
+ SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp2_mux),
+
+ SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
+ sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+ sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
+ sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+ /* TX */
+ SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+ 0),
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
+ sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
+ sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
+ sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
+ sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
+ sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
+ sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
+ sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC1 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+ &dec1_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
+ SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
+ SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, sitar_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, sitar_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, sitar_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+ &dec2_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+ &dec3_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+ &dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ /* Digital Mic Inputs */
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+ sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+ sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+ sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* Sidetone */
+ SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+ SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Earpiece (RX MIX1) */
+ {"EAR", NULL, "EAR PA"},
+ {"EAR PA", "NULL", "DAC1"},
+ {"DAC1", "Switch", "DAC1 MUX"},
+ {"DAC1", NULL, "CP"},
+ {"DAC1", NULL, "EAR DRIVER"},
+
+ {"LINEOUT1", NULL, "CP"},
+ {"LINEOUT2", NULL, "CP"},
+
+ {"LINEOUT2", NULL, "LINEOUT2 PA"},
+ {"LINEOUT2 PA", "NULL", "DAC3 MUX"},
+
+ {"LINEOUT1", NULL, "LINEOUT1 PA"},
+ {"LINEOUT1 PA", "NULL", "DAC2 MUX"},
+
+ /* Headset (RX MIX1 and RX MIX2) */
+ {"HEADPHONE", NULL, "HPHL"},
+ {"HEADPHONE", NULL, "HPHR"},
+
+ {"HPHL", NULL, "HPHL DAC"},
+ {"HPHL DAC", NULL, "DAC4 MUX"},
+ {"HPHR", NULL, "HPHR DAC"},
+ {"HPHL DAC", NULL, "RX3 MIX1"},
+
+ {"DAC1 MUX", "RX1", "RX1 CHAIN"},
+ {"DAC2 MUX", "RX1", "RX1 CHAIN"},
+ {"DAC3 MUX", "RX1", "RX1 CHAIN"},
+ {"DAC3 MUX", "RX1_INV", "RX1 CHAIN"},
+ {"DAC3 MUX", "RX2", "RX2 MIX1"},
+ {"DAC4 MUX", "ON", "RX2 MIX1"},
+
+ {"RX1 CHAIN", NULL, "RX1 MIX1"},
+
+ {"CP", NULL, "RX_BIAS"},
+
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+ {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+ {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+
+ /* SLIMBUS Connections */
+
+ /* Slimbus port 5 is non functional in Sitar 1.0 */
+ {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX2 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX2 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX3 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX3 MIX1 INP2", "IIR1", "IIR1"},
+
+
+ /* TX */
+ {"SLIM TX1", NULL, "SLIM TX1 MUX"},
+ {"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
+
+ {"SLIM TX2", NULL, "SLIM TX2 MUX"},
+ {"MIC BIAS2 Internal1", NULL, "DEC1 MUX"},
+
+ {"SLIM TX1", NULL, "SLIM TX1 MUX"},
+ {"SLIM TX2", NULL, "SLIM TX2 MUX"},
+ {"SLIM TX3", NULL, "SLIM TX3 MUX"},
+
+ {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
+
+ /* Decimator Inputs */
+ {"DEC1 MUX", "DMIC1", "DMIC1"},
+ {"DEC1 MUX", "DMIC4", "DMIC4"},
+ {"DEC1 MUX", "ADC1", "ADC1"},
+ {"DEC1 MUX", "ADC2", "ADC2"},
+
+ {"DEC2 MUX", "DMIC2", "DMIC2"},
+ {"DEC2 MUX", "DMIC3", "DMIC3"},
+ {"DEC2 MUX", "ADC1", "ADC1"},
+ {"DEC2 MUX", "ADC2", "ADC2"},
+
+ {"DEC3 MUX", "DMIC3", "DMIC3"},
+ {"DEC3 MUX", "ADC1", "ADC1"},
+ {"DEC3 MUX", "ADC2", "ADC2"},
+ {"DEC3 MUX", "DMIC2", "DMIC2"},
+ {"DEC3 MUX", "DMIC3", "DMIC4"},
+
+ {"DEC4 MUX", "DMIC4", "DMIC4"},
+ {"DEC4 MUX", "ADC1", "ADC1"},
+ {"DEC4 MUX", "ADC2", "ADC2"},
+ {"DEC4 MUX", "DMIC3", "DMIC3"},
+ {"DEC4 MUX", "DMIC2", "DMIC2"},
+ {"DEC4 MUX", "DMIC1", "DMIC1"},
+
+ /* ADC Connections */
+ {"ADC1", NULL, "AMIC1"},
+ {"ADC2", NULL, "AMIC2"},
+
+ /* IIR */
+ {"IIR1", NULL, "IIR1 INP1 MUX"},
+ {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+ {"MIC BIAS1 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS1 External", NULL, "LDO_H"},
+ {"MIC BIAS2 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS2 External", NULL, "LDO_H"},
+};
+
+static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
+{
+ return sitar_reg_readable[reg];
+}
+
+static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+{
+ /* Registers lower than 0x100 are top level registers which can be
+ * written by the Sitar core driver.
+ */
+
+ if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
+ return 1;
+
+ /* IIR Coeff registers are not cacheable */
+ if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
+ (reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
+ return 1;
+
+ return 0;
+}
+
+#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ int ret;
+
+ BUG_ON(reg > SITAR_MAX_REGISTER);
+
+ if (!sitar_volatile(codec, reg)) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret != 0)
+ dev_err(codec->dev, "Cache write to %x failed: %d\n",
+ reg, ret);
+ }
+
+ return wcd9xxx_reg_write(codec->control_data, reg, value);
+}
+static unsigned int sitar_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ unsigned int val;
+ int ret;
+
+ BUG_ON(reg > SITAR_MAX_REGISTER);
+
+ if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret >= 0) {
+ return val;
+ } else
+ dev_err(codec->dev, "Cache read from %x failed: %d\n",
+ reg, ret);
+ }
+
+ val = wcd9xxx_reg_read(codec->control_data, reg);
+ return val;
+}
+
+static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
+{
+
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x61);
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+ usleep_range(1000, 1000);
+ snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
+ 0x04);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
+ 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x00);
+}
+
+static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
+ enum sitar_bandgap_type choice)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ /* TODO lock resources accessed by audio streams and threaded
+ * interrupt handlers
+ */
+
+ pr_err("%s, choice is %d, current is %d\n", __func__, choice,
+ sitar->bandgap_type);
+
+ if (sitar->bandgap_type == choice)
+ return;
+
+ if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
+ (choice == SITAR_BANDGAP_AUDIO_MODE)) {
+ sitar_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == SITAR_BANDGAP_MBHC_MODE) {
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
+ 0x2);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
+ 0x4);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
+ 0x1);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x00);
+ } else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
+ (choice == SITAR_BANDGAP_AUDIO_MODE)) {
+ snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ usleep_range(100, 100);
+ sitar_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == SITAR_BANDGAP_OFF) {
+ snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ } else {
+ pr_err("%s: Error, Invalid bandgap settings\n", __func__);
+ }
+ sitar->bandgap_type = choice;
+}
+
+
+static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
+ int config_mode)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ pr_err("%s\n", __func__);
+
+ if (config_mode) {
+ snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
+ snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
+ snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
+ usleep_range(1000, 1000);
+ } else
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
+
+
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
+ usleep_range(50, 50);
+ sitar->clock_active = true;
+ return 0;
+}
+static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ pr_err("%s\n", __func__);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x04, 0x04);
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
+ ndelay(160);
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
+ sitar->clock_active = false;
+}
+
+static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+{
+ /* TODO store register values in calibration */
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
+
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
+
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
+
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 3);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL, 9);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL, 30);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 120);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_B2_CTL, 11);
+}
+
+static int sitar_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ pr_err("%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
+
+ return 0;
+}
+
+static void sitar_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ pr_err("%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
+}
+
+int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ pr_err("%s() mclk_enable = %u\n", __func__, mclk_enable);
+
+ if (mclk_enable) {
+ sitar->mclk_enabled = true;
+
+ if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
+ sitar_codec_pause_hs_polling(codec);
+ sitar_codec_enable_bandgap(codec,
+ SITAR_BANDGAP_AUDIO_MODE);
+ sitar_codec_enable_clock_block(codec, 0);
+ sitar_codec_calibrate_hs_polling(codec);
+ sitar_codec_start_hs_polling(codec);
+ } else {
+ sitar_codec_enable_bandgap(codec,
+ SITAR_BANDGAP_AUDIO_MODE);
+ sitar_codec_enable_clock_block(codec, 0);
+ }
+ } else {
+
+ if (!sitar->mclk_enabled) {
+ pr_err("Error, MCLK already diabled\n");
+ return -EINVAL;
+ }
+ sitar->mclk_enabled = false;
+
+ if (sitar->mbhc_polling_active) {
+ if (!sitar->mclk_enabled) {
+ sitar_codec_pause_hs_polling(codec);
+ sitar_codec_enable_bandgap(codec,
+ SITAR_BANDGAP_MBHC_MODE);
+ sitar_enable_rx_bias(codec, 1);
+ sitar_codec_enable_clock_block(codec, 1);
+ sitar_codec_calibrate_hs_polling(codec);
+ sitar_codec_start_hs_polling(codec);
+ }
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
+ 0x05, 0x01);
+ } else {
+ sitar_codec_disable_clock_block(codec);
+ sitar_codec_enable_bandgap(codec,
+ SITAR_BANDGAP_OFF);
+ }
+ }
+ return 0;
+}
+
+static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ pr_err("%s\n", __func__);
+ return 0;
+}
+
+static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ u8 val = 0;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+
+ pr_err("%s\n", __func__);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ if (dai->id == AIF1_CAP)
+ snd_soc_update_bits(dai->codec,
+ SITAR_A_CDC_CLK_TX_I2S_CTL,
+ SITAR_I2S_MASTER_MODE_MASK, 0);
+ else if (dai->id == AIF1_PB)
+ snd_soc_update_bits(dai->codec,
+ SITAR_A_CDC_CLK_RX_I2S_CTL,
+ SITAR_I2S_MASTER_MODE_MASK, 0);
+ }
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* CPU is slave */
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ val = SITAR_I2S_MASTER_MODE_MASK;
+ if (dai->id == AIF1_CAP)
+ snd_soc_update_bits(dai->codec,
+ SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
+ else if (dai->id == AIF1_PB)
+ snd_soc_update_bits(dai->codec,
+ SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+static int sitar_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+ u32 i = 0;
+ if (!tx_slot && !rx_slot) {
+ pr_err("%s: Invalid\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
+
+ if (dai->id == AIF1_PB) {
+ for (i = 0; i < rx_num; i++) {
+ sitar->dai[dai->id - 1].ch_num[i] = rx_slot[i];
+ sitar->dai[dai->id - 1].ch_act = 0;
+ sitar->dai[dai->id - 1].ch_tot = rx_num;
+ }
+ } else if (dai->id == AIF1_CAP) {
+ for (i = 0; i < tx_num; i++) {
+ sitar->dai[dai->id - 1].ch_num[i] = tx_slot[i];
+ sitar->dai[dai->id - 1].ch_act = 0;
+ sitar->dai[dai->id - 1].ch_tot = tx_num;
+ }
+ }
+ return 0;
+}
+
+static int sitar_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+ struct wcd9xxx *sitar = dev_get_drvdata(dai->codec->control_data);
+
+ u32 cnt = 0;
+ u32 tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch[SLIM_MAX_RX_PORTS];
+
+ if (!rx_slot && !tx_slot) {
+ pr_err("%s: Invalid\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
+ /* for virtual port, codec driver needs to do
+ * housekeeping, for now should be ok
+ */
+ wcd9xxx_get_channel(sitar, rx_ch, tx_ch);
+ if (dai->id == AIF1_PB) {
+ *rx_num = sitar_dai[dai->id - 1].playback.channels_max;
+ while (cnt < *rx_num) {
+ rx_slot[cnt] = rx_ch[cnt];
+ cnt++;
+ }
+ } else if (dai->id == AIF1_CAP) {
+ *tx_num = sitar_dai[dai->id - 1].capture.channels_max;
+ while (cnt < *tx_num) {
+ tx_slot[cnt] = tx_ch[6 + cnt];
+ cnt++;
+ }
+ }
+ return 0;
+}
+
+static int sitar_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
+ u8 path, shift;
+ u16 tx_fs_reg, rx_fs_reg;
+ u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+
+ pr_err("%s: DAI-ID %x\n", __func__, dai->id);
+
+ switch (params_rate(params)) {
+ case 8000:
+ tx_fs_rate = 0x00;
+ rx_fs_rate = 0x00;
+ break;
+ case 16000:
+ tx_fs_rate = 0x01;
+ rx_fs_rate = 0x20;
+ break;
+ case 32000:
+ tx_fs_rate = 0x02;
+ rx_fs_rate = 0x40;
+ break;
+ case 48000:
+ tx_fs_rate = 0x03;
+ rx_fs_rate = 0x60;
+ break;
+ default:
+ pr_err("%s: Invalid sampling rate %d\n", __func__,
+ params_rate(params));
+ return -EINVAL;
+ }
+
+
+ /**
+ * If current dai is a tx dai, set sample rate to
+ * all the txfe paths that are currently not active
+ */
+ if (dai->id == AIF1_CAP) {
+
+ tx_state = snd_soc_read(codec,
+ SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
+
+ for (path = 1, shift = 0;
+ path <= NUM_DECIMATORS; path++, shift++) {
+
+ if (!(tx_state & (1 << shift))) {
+ tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
+ + (BITS_PER_REG*(path-1));
+ snd_soc_update_bits(codec, tx_fs_reg,
+ 0x03, tx_fs_rate);
+ }
+ }
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
+ 0x03, tx_fs_rate);
+ }
+ } else {
+ sitar->dai[dai->id - 1].rate = params_rate(params);
+ }
+
+ /**
+ * TODO: Need to handle case where same RX chain takes 2 or more inputs
+ * with varying sample rates
+ */
+
+ /**
+ * If current dai is a rx dai, set sample rate to
+ * all the rx paths that are currently not active
+ */
+ if (dai->id == AIF1_PB) {
+
+ rx_state = snd_soc_read(codec,
+ SITAR_A_CDC_CLK_RX_B1_CTL);
+
+ for (path = 1, shift = 0;
+ path <= NUM_INTERPOLATORS; path++, shift++) {
+
+ if (!(rx_state & (1 << shift))) {
+ rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
+ + (BITS_PER_REG*(path-1));
+ snd_soc_update_bits(codec, rx_fs_reg,
+ 0xE0, rx_fs_rate);
+ }
+ }
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
+ 0x03, (rx_fs_rate >> 0x05));
+ }
+ } else {
+ sitar->dai[dai->id - 1].rate = params_rate(params);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops sitar_dai_ops = {
+ .startup = sitar_startup,
+ .shutdown = sitar_shutdown,
+ .hw_params = sitar_hw_params,
+ .set_sysclk = sitar_set_dai_sysclk,
+ .set_fmt = sitar_set_dai_fmt,
+ .set_channel_map = sitar_set_channel_map,
+ .get_channel_map = sitar_get_channel_map,
+};
+
+static struct snd_soc_dai_driver sitar_dai[] = {
+ {
+ .name = "sitar_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9304_RATES,
+ .formats = SITAR_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &sitar_dai_ops,
+ },
+ {
+ .name = "sitar_tx1",
+ .id = AIF1_CAP,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD9304_RATES,
+ .formats = SITAR_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &sitar_dai_ops,
+ },
+};
+
+static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct wcd9xxx *sitar;
+ struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+ u32 j = 0;
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ sitar = codec->control_data;
+ /* Execute the callback only if interface type is slimbus */
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ return 0;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+ if (sitar_dai[j].id == AIF1_CAP)
+ continue;
+ if (!strncmp(w->sname,
+ sitar_dai[j].playback.stream_name, 13)) {
+ ++sitar_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
+ wcd9xxx_cfg_slim_sch_rx(sitar,
+ sitar_p->dai[j].ch_num,
+ sitar_p->dai[j].ch_tot,
+ sitar_p->dai[j].rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+ if (sitar_dai[j].id == AIF1_CAP)
+ continue;
+ if (!strncmp(w->sname,
+ sitar_dai[j].playback.stream_name, 13)) {
+ --sitar_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (!sitar_p->dai[j].ch_act) {
+ wcd9xxx_close_slim_sch_rx(sitar,
+ sitar_p->dai[j].ch_num,
+ sitar_p->dai[j].ch_tot);
+ sitar_p->dai[j].rate = 0;
+ memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
+ sitar_p->dai[j].ch_tot));
+ sitar_p->dai[j].ch_tot = 0;
+ }
+ }
+ return 0;
+}
+
+static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct wcd9xxx *sitar;
+ struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+ /* index to the DAI ID, for now hardcoding */
+ u32 j = 0;
+
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ sitar = codec->control_data;
+
+ /* Execute the callback only if interface type is slimbus */
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ return 0;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+ if (sitar_dai[j].id == AIF1_PB)
+ continue;
+ if (!strncmp(w->sname,
+ sitar_dai[j].capture.stream_name, 13)) {
+ ++sitar_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
+ wcd9xxx_cfg_slim_sch_tx(sitar,
+ sitar_p->dai[j].ch_num,
+ sitar_p->dai[j].ch_tot,
+ sitar_p->dai[j].rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
+ if (sitar_dai[j].id == AIF1_PB)
+ continue;
+ if (!strncmp(w->sname,
+ sitar_dai[j].capture.stream_name, 13)) {
+ --sitar_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (!sitar_p->dai[j].ch_act) {
+ wcd9xxx_close_slim_sch_tx(sitar,
+ sitar_p->dai[j].ch_num,
+ sitar_p->dai[j].ch_tot);
+ sitar_p->dai[j].rate = 0;
+ memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
+ sitar_p->dai[j].ch_tot));
+ sitar_p->dai[j].ch_tot = 0;
+ }
+ }
+ return 0;
+}
+
+
+static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
+{
+ u8 bias_msb, bias_lsb;
+ short bias_value;
+
+ bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
+ bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
+ bias_value = (bias_msb << 8) | bias_lsb;
+ return bias_value;
+}
+
+static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
+{
+ u8 bias_msb, bias_lsb;
+ short bias_value;
+
+ bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
+ bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
+ bias_value = (bias_msb << 8) | bias_lsb;
+ return bias_value;
+}
+
+static short sitar_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
+ int dce)
+{
+ short bias_value;
+
+ if (dce) {
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
+ usleep_range(60000, 60000);
+ bias_value = sitar_codec_read_dce_result(codec);
+ } else {
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ usleep_range(5000, 5000);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
+ usleep_range(50, 50);
+ bias_value = sitar_codec_read_sta_result(codec);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
+ }
+
+ pr_err("read microphone bias value %x\n", bias_value);
+ return bias_value;
+}
+
+static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct sitar_mbhc_calibration *calibration = sitar->calibration;
+ short bias_value;
+ u8 cfilt_mode;
+
+ if (!calibration) {
+ pr_err("Error, no sitar calibration\n");
+ return -ENODEV;
+ }
+
+ sitar->mbhc_polling_active = true;
+
+ if (!sitar->mclk_enabled) {
+ sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
+ sitar_enable_rx_bias(codec, 1);
+ sitar_codec_enable_clock_block(codec, 1);
+ }
+
+ snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
+
+ snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
+
+ /* Make sure CFILT is in fast mode, save current mode */
+ cfilt_mode = snd_soc_read(codec,
+ sitar->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
+ 0x70, 0x00);
+
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+
+ sitar_codec_calibrate_hs_polling(codec);
+
+ bias_value = sitar_codec_measure_micbias_voltage(codec, 0);
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
+
+ return bias_value;
+}
+
+static int sitar_codec_enable_hs_detect(struct snd_soc_codec *codec,
+ int insertion)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct sitar_mbhc_calibration *calibration = sitar->calibration;
+ int central_bias_enabled = 0;
+ u8 wg_time;
+
+ if (!calibration) {
+ pr_err("Error, no sitar calibration\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0);
+
+ if (insertion) {
+ /* Make sure mic bias and Mic line schmitt trigger
+ * are turned OFF
+ */
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
+ 0x81, 0x01);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+ 0x90, 0x00);
+ wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
+ wg_time += 1;
+
+ /* Enable HPH Schmitt Trigger */
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x11, 0x11);
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x0C,
+ calibration->hph_current << 2);
+
+ /* Turn off HPH PAs and DAC's during insertion detection to
+ * avoid false insertion interrupts
+ */
+ if (sitar->mbhc_micbias_switched)
+ sitar_codec_switch_micbias(codec, 0);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0x00);
+ usleep_range(wg_time * 1000, wg_time * 1000);
+
+ /* setup for insetion detection */
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x02, 0x02);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
+ } else {
+ /* Make sure the HPH schmitt trigger is OFF */
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
+
+ /* enable the mic line schmitt trigger */
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x60,
+ calibration->mic_current << 5);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ usleep_range(calibration->mic_pid, calibration->mic_pid);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x10);
+
+ /* Setup for low power removal detection */
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
+ }
+
+ if (snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_CTL) & 0x4) {
+ if (!(sitar->clock_active)) {
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
+ 0x06, 0);
+ usleep_range(calibration->shutdown_plug_removal,
+ calibration->shutdown_plug_removal);
+ } else
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
+ 0x06, 0);
+ }
+
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.int_rbias, 0x80, 0);
+
+ /* If central bandgap disabled */
+ if (!(snd_soc_read(codec, SITAR_A_PIN_CTL_OE1) & 1)) {
+ snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x3, 0x3);
+ usleep_range(calibration->bg_fast_settle,
+ calibration->bg_fast_settle);
+ central_bias_enabled = 1;
+ }
+
+ /* If LDO_H disabled */
+ if (snd_soc_read(codec, SITAR_A_PIN_CTL_OE0) & 0x80) {
+ snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x10, 0);
+ snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0x80);
+ usleep_range(calibration->tldoh, calibration->tldoh);
+ snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0);
+
+ if (central_bias_enabled)
+ snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x1, 0);
+ }
+
+ wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+ return 0;
+}
+
+
+static void sitar_lock_sleep(struct sitar_priv *sitar)
+{
+ int ret;
+ while (!(ret = wait_event_timeout(sitar->pm_wq,
+ atomic_inc_not_zero(&sitar->pm_cnt),
+ 2 * HZ))) {
+ pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
+ __func__, ret, atomic_read(&sitar->pm_cnt));
+ WARN_ON_ONCE(1);
+ }
+}
+
+static void sitar_unlock_sleep(struct sitar_priv *sitar)
+{
+ atomic_dec(&sitar->pm_cnt);
+ wake_up(&sitar->pm_wq);
+}
+
+
+static void btn0_lpress_fn(struct work_struct *work)
+{
+ struct delayed_work *delayed_work;
+ struct sitar_priv *sitar;
+
+ pr_err("%s:\n", __func__);
+
+ delayed_work = to_delayed_work(work);
+ sitar = container_of(delayed_work, struct sitar_priv, btn0_dwork);
+
+ if (sitar) {
+ if (sitar->button_jack) {
+ pr_err("%s: Reporting long button press event\n",
+ __func__);
+ sitar_snd_soc_jack_report(sitar, sitar->button_jack,
+ SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
+ }
+ } else {
+ pr_err("%s: Bad sitar private data\n", __func__);
+ }
+
+ sitar_unlock_sleep(sitar);
+}
+
+int sitar_hs_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
+ struct sitar_mbhc_calibration *calibration)
+{
+ struct sitar_priv *sitar;
+ int rc;
+
+ if (!codec || !calibration) {
+ pr_err("Error: no codec or calibration\n");
+ return -EINVAL;
+ }
+ sitar = snd_soc_codec_get_drvdata(codec);
+ sitar->headset_jack = headset_jack;
+ sitar->button_jack = button_jack;
+ sitar->calibration = calibration;
+ sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
+
+ /* Put CFILT in fast mode by default */
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
+ 0x40, SITAR_CFILT_FAST_MODE);
+
+ INIT_DELAYED_WORK(&sitar->btn0_dwork, btn0_lpress_fn);
+ INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
+ INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
+ rc = sitar_codec_enable_hs_detect(codec, 1);
+
+ if (!IS_ERR_VALUE(rc)) {
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ wcd9xxx_enable_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_enable_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(sitar_hs_detect);
+
+static irqreturn_t sitar_dce_handler(int irq, void *data)
+{
+ struct sitar_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+ short bias_value;
+
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ sitar_lock_sleep(priv);
+
+ bias_value = sitar_codec_read_dce_result(codec);
+ pr_err("%s: button press interrupt, bias value(DCE Read)=%d\n",
+ __func__, bias_value);
+
+ bias_value = sitar_codec_read_sta_result(codec);
+ pr_err("%s: button press interrupt, bias value(STA Read)=%d\n",
+ __func__, bias_value);
+ /*
+ * TODO: If button pressed is not button 0,
+ * report the button press event immediately.
+ */
+ priv->buttons_pressed |= SND_JACK_BTN_0;
+
+ msleep(100);
+
+ if (schedule_delayed_work(&priv->btn0_dwork,
+ msecs_to_jiffies(400)) == 0) {
+ WARN(1, "Button pressed twice without release event\n");
+ sitar_unlock_sleep(priv);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_release_handler(int irq, void *data)
+{
+ struct sitar_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+ int ret, mic_voltage;
+
+ pr_err("%s\n", __func__);
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
+ sitar_lock_sleep(priv);
+
+ mic_voltage = sitar_codec_read_dce_result(codec);
+ pr_err("%s: Microphone Voltage on release(DCE Read) = %d\n",
+ __func__, mic_voltage);
+
+ if (priv->buttons_pressed & SND_JACK_BTN_0) {
+ ret = cancel_delayed_work(&priv->btn0_dwork);
+
+ if (ret == 0) {
+
+ pr_err("%s: Reporting long button release event\n",
+ __func__);
+ if (priv->button_jack) {
+ sitar_snd_soc_jack_report(priv,
+ priv->button_jack, 0,
+ SND_JACK_BTN_0);
+ }
+
+ } else {
+ /* if scheduled btn0_dwork is canceled from here,
+ * we have to unlock from here instead btn0_work */
+ sitar_unlock_sleep(priv);
+ mic_voltage =
+ sitar_codec_measure_micbias_voltage(codec, 0);
+ pr_err("%s: Mic Voltage on release(new STA) = %d\n",
+ __func__, mic_voltage);
+
+ if (mic_voltage < -2000 || mic_voltage > -670) {
+ pr_err("%s: Fake buttton press interrupt\n",
+ __func__);
+ } else {
+
+ if (priv->button_jack) {
+ pr_err("%s:reporting short button press and release\n",
+ __func__);
+
+ sitar_snd_soc_jack_report(priv,
+ priv->button_jack,
+ SND_JACK_BTN_0, SND_JACK_BTN_0);
+ sitar_snd_soc_jack_report(priv,
+ priv->button_jack,
+ 0, SND_JACK_BTN_0);
+ }
+ }
+ }
+
+ priv->buttons_pressed &= ~SND_JACK_BTN_0;
+ }
+
+ sitar_codec_start_hs_polling(codec);
+ sitar_unlock_sleep(priv);
+ return IRQ_HANDLED;
+}
+
+static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct sitar_mbhc_calibration *calibration = sitar->calibration;
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
+
+ snd_soc_update_bits(codec,
+ sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+ usleep_range(calibration->shutdown_plug_removal,
+ calibration->shutdown_plug_removal);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
+
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
+}
+
+static void sitar_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ sitar_codec_shutdown_hs_removal_detect(codec);
+
+ if (!sitar->mclk_enabled) {
+ snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0x00);
+ sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_AUDIO_MODE);
+ sitar_codec_enable_clock_block(codec, 0);
+ }
+
+ sitar->mbhc_polling_active = false;
+}
+
+static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
+{
+ struct sitar_priv *sitar = data;
+ struct snd_soc_codec *codec;
+
+ pr_info("%s: received HPHL OCP irq\n", __func__);
+
+ if (sitar) {
+ codec = sitar->codec;
+ if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
+ pr_info("%s: retry\n", __func__);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ } else {
+ wcd9xxx_disable_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ sitar->hphlocp_cnt = 0;
+ sitar->hph_status |= SND_JACK_OC_HPHL;
+ if (sitar->headset_jack)
+ sitar_snd_soc_jack_report(sitar,
+ sitar->headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
+ }
+ } else {
+ pr_err("%s: Bad sitar private data\n", __func__);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
+{
+ struct sitar_priv *sitar = data;
+ struct snd_soc_codec *codec;
+
+ pr_info("%s: received HPHR OCP irq\n", __func__);
+
+ if (sitar) {
+ codec = sitar->codec;
+ if (sitar->hphrocp_cnt++ < SITAR_OCP_ATTEMPT) {
+ pr_info("%s: retry\n", __func__);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ } else {
+ wcd9xxx_disable_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ sitar->hphrocp_cnt = 0;
+ sitar->hph_status |= SND_JACK_OC_HPHR;
+ if (sitar->headset_jack)
+ sitar_snd_soc_jack_report(sitar,
+ sitar->headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
+ }
+ } else {
+ pr_err("%s: Bad sitar private data\n", __func__);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void sitar_sync_hph_state(struct sitar_priv *sitar)
+{
+ if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_err("%s: HPHR clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
+ 1 << 4);
+ }
+ if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_err("%s: HPHL clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
+ 1 << 5);
+ }
+
+ if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_err("%s: HPHR clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+ if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_err("%s: HPHL clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+}
+
+static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
+{
+ struct sitar_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+ int ldo_h_on, micb_cfilt_on;
+ short mic_voltage;
+ short threshold_no_mic = 0xF7F6;
+ short threshold_fake_insert = 0xFD30;
+ u8 is_removal;
+
+ pr_err("%s\n", __func__);
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+ sitar_lock_sleep(priv);
+
+ is_removal = snd_soc_read(codec, SITAR_A_CDC_MBHC_INT_CTL) & 0x02;
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
+
+ /* Turn off both HPH and MIC line schmitt triggers */
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+ 0x90, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
+
+ if (priv->fake_insert_context) {
+ pr_err("%s: fake context interrupt, reset insertion\n",
+ __func__);
+ priv->fake_insert_context = false;
+ sitar_codec_shutdown_hs_polling(codec);
+ sitar_codec_enable_hs_detect(codec, 1);
+ return IRQ_HANDLED;
+ }
+
+
+ ldo_h_on = snd_soc_read(codec, SITAR_A_LDO_H_MODE_1) & 0x80;
+ micb_cfilt_on = snd_soc_read(codec,
+ priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
+
+ if (!ldo_h_on)
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+ if (!micb_cfilt_on)
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
+ 0x80, 0x80);
+
+ usleep_range(priv->calibration->setup_plug_removal_delay,
+ priv->calibration->setup_plug_removal_delay);
+
+ if (!ldo_h_on)
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x0);
+ if (!micb_cfilt_on)
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
+ 0x80, 0x0);
+
+ if (is_removal) {
+ /*
+ * If headphone is removed while playback is in progress,
+ * it is possible that micbias will be switched to VDDIO.
+ */
+ if (priv->mbhc_micbias_switched)
+ sitar_codec_switch_micbias(codec, 0);
+ priv->hph_status &= ~SND_JACK_HEADPHONE;
+
+ /* If headphone PA is on, check if userspace receives
+ * removal event to sync-up PA's state */
+ if (sitar_is_hph_pa_on(codec)) {
+ set_bit(SITAR_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
+ set_bit(SITAR_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
+ }
+
+ if (sitar_is_hph_dac_on(codec, 1))
+ set_bit(SITAR_HPHL_DAC_OFF_ACK,
+ &priv->hph_pa_dac_state);
+ if (sitar_is_hph_dac_on(codec, 0))
+ set_bit(SITAR_HPHR_DAC_OFF_ACK,
+ &priv->hph_pa_dac_state);
+
+ if (priv->headset_jack) {
+ pr_err("%s: Reporting removal\n", __func__);
+ sitar_snd_soc_jack_report(priv, priv->headset_jack,
+ priv->hph_status,
+ SITAR_JACK_MASK);
+ }
+ sitar_codec_shutdown_hs_removal_detect(codec);
+ sitar_codec_enable_hs_detect(codec, 1);
+ sitar_unlock_sleep(priv);
+ return IRQ_HANDLED;
+ }
+
+ mic_voltage = sitar_codec_setup_hs_polling(codec);
+
+ if (mic_voltage > threshold_fake_insert) {
+ pr_err("%s: Fake insertion interrupt, mic_voltage = %x\n",
+ __func__, mic_voltage);
+
+ /* Disable HPH trigger and enable MIC line trigger */
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
+
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
+ priv->calibration->mic_current << 5);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ usleep_range(priv->calibration->mic_pid,
+ priv->calibration->mic_pid);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x10);
+
+ /* Setup for insertion detection */
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
+ priv->fake_insert_context = true;
+ wcd9xxx_enable_irq(codec->control_data,
+ SITAR_IRQ_MBHC_INSERTION);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+
+ } else if (mic_voltage < threshold_no_mic) {
+ pr_err("%s: Headphone Detected, mic_voltage = %x\n",
+ __func__, mic_voltage);
+ priv->hph_status |= SND_JACK_HEADPHONE;
+ if (priv->headset_jack) {
+ pr_err("%s: Reporting insertion %d\n", __func__,
+ SND_JACK_HEADPHONE);
+ sitar_snd_soc_jack_report(priv, priv->headset_jack,
+ priv->hph_status,
+ SITAR_JACK_MASK);
+ }
+ sitar_codec_shutdown_hs_polling(codec);
+ sitar_codec_enable_hs_detect(codec, 0);
+ sitar_sync_hph_state(priv);
+ } else {
+ pr_err("%s: Headset detected, mic_voltage = %x\n",
+ __func__, mic_voltage);
+ priv->hph_status |= SND_JACK_HEADSET;
+ if (priv->headset_jack) {
+ pr_err("%s: Reporting insertion %d\n", __func__,
+ SND_JACK_HEADSET);
+ sitar_snd_soc_jack_report(priv, priv->headset_jack,
+ priv->hph_status,
+ SITAR_JACK_MASK);
+ }
+ sitar_codec_start_hs_polling(codec);
+ sitar_sync_hph_state(priv);
+ }
+
+ sitar_unlock_sleep(priv);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
+{
+ struct sitar_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+ short bias_value;
+
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
+ sitar_lock_sleep(priv);
+
+ usleep_range(priv->calibration->shutdown_plug_removal,
+ priv->calibration->shutdown_plug_removal);
+
+ bias_value = sitar_codec_measure_micbias_voltage(codec, 1);
+ pr_err("removal interrupt, bias value is %d\n", bias_value);
+
+ if (bias_value < -90) {
+ pr_err("False alarm, headset not actually removed\n");
+ sitar_codec_start_hs_polling(codec);
+ } else {
+ /*
+ * If this removal is not false, first check the micbias
+ * switch status and switch it to LDOH if it is already
+ * switched to VDDIO.
+ */
+ if (priv->mbhc_micbias_switched)
+ sitar_codec_switch_micbias(codec, 0);
+ priv->hph_status &= ~SND_JACK_HEADSET;
+ if (priv->headset_jack) {
+ pr_err("%s: Reporting removal\n", __func__);
+ sitar_snd_soc_jack_report(priv, priv->headset_jack, 0,
+ SITAR_JACK_MASK);
+ }
+ sitar_codec_shutdown_hs_polling(codec);
+
+ sitar_codec_enable_hs_detect(codec, 1);
+ }
+
+ sitar_unlock_sleep(priv);
+ return IRQ_HANDLED;
+}
+
+
+static unsigned long slimbus_value;
+
+static irqreturn_t sitar_slimbus_irq(int irq, void *data)
+{
+ struct sitar_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+ int i, j;
+ u8 val;
+
+ sitar_lock_sleep(priv);
+
+ for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
+ slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
+ SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
+ for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
+ val = wcd9xxx_interface_reg_read(codec->control_data,
+ SITAR_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
+ if (val & 0x1)
+ pr_err_ratelimited("overflow error on port %x,"
+ " value %x\n", i*8 + j, val);
+ if (val & 0x2)
+ pr_err_ratelimited("underflow error on port %x,"
+ " value %x\n", i*8 + j, val);
+ }
+ wcd9xxx_interface_reg_write(codec->control_data,
+ SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
+ }
+
+ sitar_unlock_sleep(priv);
+ return IRQ_HANDLED;
+}
+
+
+static int sitar_handle_pdata(struct sitar_priv *sitar)
+{
+ struct snd_soc_codec *codec = sitar->codec;
+ struct wcd9xxx_pdata *pdata = sitar->pdata;
+ int k1, k2, rc = 0;
+ u8 leg_mode = pdata->amic_settings.legacy_mode;
+ u8 txfe_bypass = pdata->amic_settings.txfe_enable;
+ u8 txfe_buff = pdata->amic_settings.txfe_buff;
+ u8 flag = pdata->amic_settings.use_pdata;
+ u8 i = 0, j = 0;
+ u8 val_txfe = 0, value = 0;
+
+ if (!pdata) {
+ rc = -ENODEV;
+ goto done;
+ }
+
+ /* Make sure settings are correct */
+ if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
+ (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
+ (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
+ rc = -EINVAL;
+ goto done;
+ }
+
+ /* figure out k value */
+ k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
+ pdata->micbias.cfilt1_mv);
+ k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
+ pdata->micbias.cfilt2_mv);
+
+ if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
+ rc = -EINVAL;
+ goto done;
+ }
+
+ /* Set voltage level and always use LDO */
+
+ snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
+ (k1 << 2));
+ snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
+ (k2 << 2));
+
+ snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
+ (pdata->micbias.bias1_cfilt_sel << 5));
+ snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
+ (pdata->micbias.bias2_cfilt_sel << 5));
+
+ for (i = 0; i < 6; j++, i += 2) {
+ if (flag & (0x01 << i)) {
+ value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
+ val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
+ val_txfe = val_txfe |
+ ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
+ snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
+ 0x10, value);
+ snd_soc_update_bits(codec,
+ SITAR_A_TX_1_2_TEST_EN + j * 10,
+ 0x30, val_txfe);
+ }
+ if (flag & (0x01 << (i + 1))) {
+ value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
+ val_txfe = (txfe_bypass &
+ (0x01 << (i + 1))) ? 0x02 : 0x00;
+ val_txfe |= (txfe_buff &
+ (0x01 << (i + 1))) ? 0x01 : 0x00;
+ snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
+ 0x01, value);
+ snd_soc_update_bits(codec,
+ SITAR_A_TX_1_2_TEST_EN + j * 10,
+ 0x03, val_txfe);
+ }
+ }
+
+ if (pdata->ocp.use_pdata) {
+ /* not defined in CODEC specification */
+ if (pdata->ocp.hph_ocp_limit == 1 ||
+ pdata->ocp.hph_ocp_limit == 5) {
+ rc = -EINVAL;
+ goto done;
+ }
+ snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
+ 0x0F, pdata->ocp.num_attempts);
+ snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
+ ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
+ 0xE0, (pdata->ocp.hph_ocp_limit << 5));
+ }
+done:
+ return rc;
+}
+
+static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
+
+ /* Sitar 1.1 MICBIAS changes */
+ SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
+ SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
+
+ /* Sitar 1.1 HPH changes */
+ SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
+ SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
+
+ /* Sitar 1.1 EAR PA changes */
+ SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
+ SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
+ SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
+
+ /* Sitar 1.1 RX Changes */
+ SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
+
+ /* Sitar 1.1 RX1 and RX2 Changes */
+ SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
+
+ SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
+
+};
+
+static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
+{
+ u32 i;
+ for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
+ snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
+ sitar_1_1_reg_defaults[i].val);
+
+}
+static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
+ /* Initialize current threshold to 350MA
+ * number of wait and run cycles to 4096
+ */
+ {SITAR_A_RX_HPH_OCP_CTL, 0xF8, 0x60},
+ {SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+
+ {SITAR_A_QFUSE_CTL, 0xFF, 0x03},
+
+ /* Initialize gain registers to use register gain */
+ {SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
+ {SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
+ {SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
+ {SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
+
+ /* Initialize mic biases to differential mode */
+ {SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
+ {SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
+
+ {SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
+
+ /* Use 16 bit sample size for TX1 to TX6 */
+ {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x28},
+ {SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
+ {SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
+ {SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
+ {SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
+
+ /* Use 16 bit sample size for RX */
+ {SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
+ {SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
+
+ /*enable HPF filter for TX paths */
+ {SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
+};
+
+static void sitar_codec_init_reg(struct snd_soc_codec *codec)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
+ snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
+ sitar_codec_reg_init_val[i].mask,
+ sitar_codec_reg_init_val[i].val);
+}
+
+static int sitar_codec_probe(struct snd_soc_codec *codec)
+{
+ struct sitar *control;
+ struct sitar_priv *sitar;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret = 0;
+ int i;
+ u8 sitar_version;
+ int ch_cnt;
+
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ control = codec->control_data;
+
+ sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
+ if (!sitar) {
+ dev_err(codec->dev, "Failed to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ /* Make sure mbhc micbias register addresses are zeroed out */
+ memset(&sitar->mbhc_bias_regs, 0,
+ sizeof(struct mbhc_micbias_regs));
+ sitar->cfilt_k_value = 0;
+ sitar->mbhc_micbias_switched = false;
+
+ snd_soc_codec_set_drvdata(codec, sitar);
+
+ sitar->mclk_enabled = false;
+ sitar->bandgap_type = SITAR_BANDGAP_OFF;
+ sitar->clock_active = false;
+ sitar->config_mode_active = false;
+ sitar->mbhc_polling_active = false;
+ sitar->fake_insert_context = false;
+ sitar->no_mic_headset_override = false;
+ sitar->codec = codec;
+ sitar->pdata = dev_get_platdata(codec->dev->parent);
+ atomic_set(&sitar->pm_cnt, 1);
+ init_waitqueue_head(&sitar->pm_wq);
+
+ sitar_update_reg_defaults(codec);
+ sitar_codec_init_reg(codec);
+
+ ret = sitar_handle_pdata(sitar);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: bad pdata\n", __func__);
+ goto err_pdata;
+ }
+
+ snd_soc_add_controls(codec, sitar_snd_controls,
+ ARRAY_SIZE(sitar_snd_controls));
+ snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
+ ARRAY_SIZE(sitar_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+ sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
+ pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
+
+ sitar_version &= 0x1F;
+ pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
+
+ snd_soc_dapm_sync(dapm);
+
+
+ ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION,
+ sitar_hs_insert_irq, "Headset insert detect", sitar);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ SITAR_IRQ_MBHC_INSERTION);
+ goto err_insert_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+
+ ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL,
+ sitar_hs_remove_irq, "Headset remove detect", sitar);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ SITAR_IRQ_MBHC_REMOVAL);
+ goto err_remove_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
+
+ ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
+ sitar_dce_handler, "DC Estimation detect", sitar);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ SITAR_IRQ_MBHC_POTENTIAL);
+ goto err_potential_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+
+ ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
+ sitar_release_handler, "Button Release detect", sitar);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ SITAR_IRQ_MBHC_RELEASE);
+ goto err_release_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
+
+ ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
+ sitar_slimbus_irq, "SLIMBUS Slave", sitar);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ SITAR_IRQ_SLIMBUS);
+ goto err_slimbus_irq;
+ }
+
+ for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+ wcd9xxx_interface_reg_write(codec->control_data,
+ SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+
+
+ ret = wcd9xxx_request_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar_hphl_ocp_irq,
+ "HPH_L OCP detect", sitar);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ goto err_hphl_ocp_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+
+ ret = wcd9xxx_request_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPR_FAULT, sitar_hphr_ocp_irq,
+ "HPH_R OCP detect", sitar);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ goto err_hphr_ocp_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+
+ for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
+ switch (sitar_dai[i].id) {
+ case AIF1_PB:
+ ch_cnt = sitar_dai[i].playback.channels_max;
+ break;
+ case AIF1_CAP:
+ ch_cnt = sitar_dai[i].capture.channels_max;
+ break;
+ default:
+ continue;
+ }
+ sitar->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
+ ch_cnt), GFP_KERNEL);
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ debug_sitar_priv = sitar;
+#endif
+
+ return ret;
+
+err_hphr_ocp_irq:
+ wcd9xxx_free_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar);
+err_hphl_ocp_irq:
+ wcd9xxx_free_irq(codec->control_data,
+ SITAR_IRQ_SLIMBUS, sitar);
+err_slimbus_irq:
+ wcd9xxx_free_irq(codec->control_data,
+ SITAR_IRQ_MBHC_RELEASE, sitar);
+err_release_irq:
+ wcd9xxx_free_irq(codec->control_data,
+ SITAR_IRQ_MBHC_POTENTIAL, sitar);
+err_potential_irq:
+ wcd9xxx_free_irq(codec->control_data,
+ SITAR_IRQ_MBHC_REMOVAL, sitar);
+err_remove_irq:
+ wcd9xxx_free_irq(codec->control_data,
+ SITAR_IRQ_MBHC_INSERTION, sitar);
+err_insert_irq:
+err_pdata:
+ kfree(sitar);
+ return ret;
+}
+static int sitar_codec_remove(struct snd_soc_codec *codec)
+{
+ int i;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_SLIMBUS, sitar);
+ wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE, sitar);
+ wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
+ sitar_codec_disable_clock_block(codec);
+ sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
+ for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
+ kfree(sitar->dai[i].ch_num);
+ kfree(sitar);
+ return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_sitar = {
+ .probe = sitar_codec_probe,
+ .remove = sitar_codec_remove,
+ .read = sitar_read,
+ .write = sitar_write,
+
+ .readable_register = sitar_readable,
+ .volatile_register = sitar_volatile,
+
+ .reg_cache_size = SITAR_CACHE_SIZE,
+ .reg_cache_default = sitar_reg_defaults,
+ .reg_word_size = 1,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_poke;
+
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t codec_debug_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[32];
+ char *buf;
+ int rc;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ buf = (char *)lbuf;
+ debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
+ ? false : true;
+
+ return rc;
+}
+
+static const struct file_operations codec_debug_ops = {
+ .open = codec_debug_open,
+ .write = codec_debug_write,
+};
+#endif
+
+#ifdef CONFIG_PM
+static int sitar_suspend(struct device *dev)
+{
+ int ret = 0, cnt;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sitar_priv *sitar = platform_get_drvdata(pdev);
+
+ cnt = atomic_read(&sitar->pm_cnt);
+ if (cnt > 0) {
+ if (wait_event_timeout(sitar->pm_wq,
+ (atomic_cmpxchg(&sitar->pm_cnt, 1, 0)
+ == 1), 5 * HZ)) {
+ dev_dbg(dev, "system suspend pm_cnt %d\n",
+ atomic_read(&sitar->pm_cnt));
+ } else {
+ dev_err(dev, "%s timed out pm_cnt = %d\n",
+ __func__, atomic_read(&sitar->pm_cnt));
+ WARN_ON_ONCE(1);
+ ret = -EBUSY;
+ }
+ } else if (cnt == 0)
+ dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
+ atomic_read(&sitar->pm_cnt));
+ else {
+ WARN(1, "unexpected pm_cnt %d\n", cnt);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static int sitar_resume(struct device *dev)
+{
+ int ret = 0, cnt;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sitar_priv *sitar = platform_get_drvdata(pdev);
+
+ cnt = atomic_cmpxchg(&sitar->pm_cnt, 0, 1);
+ if (cnt == 0) {
+ dev_dbg(dev, "system resume, pm_cnt %d\n",
+ atomic_read(&sitar->pm_cnt));
+ wake_up_all(&sitar->pm_wq);
+ } else if (cnt > 0)
+ dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
+ else {
+ WARN(1, "unexpected pm_cnt %d\n", cnt);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static const struct dev_pm_ops sitar_pm_ops = {
+ .suspend = sitar_suspend,
+ .resume = sitar_resume,
+};
+#endif
+
+static int __devinit sitar_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ pr_err("%s\n", __func__);
+#ifdef CONFIG_DEBUG_FS
+ debugfs_poke = debugfs_create_file("TRRS",
+ S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
+
+#endif
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+ sitar_dai, ARRAY_SIZE(sitar_dai));
+ return ret;
+}
+static int __devexit sitar_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(debugfs_poke);
+#endif
+ return 0;
+}
+static struct platform_driver sitar_codec_driver = {
+ .probe = sitar_probe,
+ .remove = sitar_remove,
+ .driver = {
+ .name = "sitar_codec",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &sitar_pm_ops,
+#endif
+ },
+};
+
+static int __init sitar_codec_init(void)
+{
+ return platform_driver_register(&sitar_codec_driver);
+}
+
+static void __exit sitar_codec_exit(void)
+{
+ platform_driver_unregister(&sitar_codec_driver);
+}
+
+module_init(sitar_codec_init);
+module_exit(sitar_codec_exit);
+
+MODULE_DESCRIPTION("Sitar codec driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9304.h b/sound/soc/codecs/wcd9304.h
new file mode 100644
index 0000000..07a1ca0
--- /dev/null
+++ b/sound/soc/codecs/wcd9304.h
@@ -0,0 +1,72 @@
+/* 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 <sound/soc.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+
+#define SITAR_VERSION_1_0 0x00
+
+#define SITAR_NUM_REGISTERS 0x3E0
+#define SITAR_MAX_REGISTER (SITAR_NUM_REGISTERS-1)
+#define SITAR_CACHE_SIZE SITAR_NUM_REGISTERS
+
+#define SITAR_REG_VAL(reg, val) {reg, 0, val}
+
+/* Local to the core only */
+#define SITAR_SLIM_MAX_RX_PORTS 5
+#define SITAR_SLIM_MAX_TX_PORTS 5
+
+extern const u8 sitar_reg_readable[SITAR_CACHE_SIZE];
+extern const u8 sitar_reg_defaults[SITAR_CACHE_SIZE];
+
+enum sitar_micbias_num {
+ SITAR_MICBIAS1,
+ SITAR_MICBIAS2,
+};
+
+enum sitar_pid_current {
+ SITAR_PID_MIC_2P5_UA,
+ SITAR_PID_MIC_5_UA,
+ SITAR_PID_MIC_10_UA,
+ SITAR_PID_MIC_20_UA,
+};
+
+struct sitar_mbhc_calibration {
+ enum sitar_micbias_num bias;
+ int tldoh;
+ int bg_fast_settle;
+ enum sitar_pid_current mic_current;
+ int mic_pid;
+ enum sitar_pid_current hph_current;
+ int setup_plug_removal_delay;
+ int shutdown_plug_removal;
+};
+
+struct sitar_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+extern int sitar_hs_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
+ struct sitar_mbhc_calibration *calibration);
+
+#ifndef anc_header_dec
+struct anc_header {
+ u32 reserved[3];
+ u32 num_anc_slots;
+};
+#define anc_header_dec
+#endif
+
+extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
index c681771..e0ad541 100644
--- a/sound/soc/codecs/wcd9310-tables.c
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mfd/wcd9310/registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
#include "wcd9310.h"
const u8 tabla_reg_readable[TABLA_CACHE_SIZE] = {
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 46f6461..a5427ed 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -18,9 +18,10 @@
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
-#include <linux/mfd/wcd9310/core.h>
-#include <linux/mfd/wcd9310/registers.h>
-#include <linux/mfd/wcd9310/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -171,7 +172,7 @@
struct snd_soc_jack *headset_jack;
struct snd_soc_jack *button_jack;
- struct tabla_pdata *pdata;
+ struct wcd9xxx_pdata *pdata;
u32 anc_slot;
bool no_mic_headset_override;
@@ -1319,10 +1320,12 @@
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
- tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+ wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
if (!tabla->no_mic_headset_override) {
- tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
- tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+ wcd9xxx_enable_irq(codec->control_data,
+ TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data,
+ TABLA_IRQ_MBHC_RELEASE);
} else {
tabla_codec_disable_button_presses(codec);
}
@@ -1336,11 +1339,12 @@
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
if (!tabla->no_mic_headset_override) {
- tabla_disable_irq(codec->control_data,
+ wcd9xxx_disable_irq(codec->control_data,
TABLA_IRQ_MBHC_POTENTIAL);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+ wcd9xxx_disable_irq(codec->control_data,
+ TABLA_IRQ_MBHC_RELEASE);
}
}
@@ -1767,7 +1771,7 @@
tabla->hphlocp_cnt = 0;
else
tabla->hphrocp_cnt = 0;
- tabla_enable_irq(codec->control_data, irq);
+ wcd9xxx_enable_irq(codec->control_data, irq);
} else {
pr_err("%s: Bad tabla private data\n", __func__);
}
@@ -1925,16 +1929,16 @@
static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
- 0, tabla_codec_enable_micbias,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ 0, tabla_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
- 0, tabla_codec_enable_micbias,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ 0, tabla_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route audio_i2s_map[] = {
@@ -2284,7 +2288,7 @@
static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
{
int i;
- struct tabla *tabla_core = dev_get_drvdata(ssc->dev->parent);
+ struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
if (TABLA_IS_1_X(tabla_core->version)) {
for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
@@ -2333,7 +2337,7 @@
reg, ret);
}
- return tabla_reg_write(codec->control_data, reg, value);
+ return wcd9xxx_reg_write(codec->control_data, reg, value);
}
static unsigned int tabla_read(struct snd_soc_codec *codec,
unsigned int reg)
@@ -2353,7 +2357,7 @@
reg, ret);
}
- val = tabla_reg_read(codec->control_data, reg);
+ val = wcd9xxx_reg_read(codec->control_data, reg);
return val;
}
@@ -2622,7 +2626,7 @@
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* CPU is master */
- if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
if (dai->id == AIF1_CAP)
snd_soc_update_bits(dai->codec,
TABLA_A_CDC_CLK_TX_I2S_CTL,
@@ -2635,7 +2639,7 @@
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* CPU is slave */
- if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
val = TABLA_I2S_MASTER_MODE_MASK;
if (dai->id == AIF1_CAP)
snd_soc_update_bits(dai->codec,
@@ -2685,7 +2689,7 @@
unsigned int *rx_num, unsigned int *rx_slot)
{
- struct tabla *tabla = dev_get_drvdata(dai->codec->control_data);
+ struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
u32 cnt = 0;
u32 tx_ch[SLIM_MAX_TX_PORTS];
@@ -2699,7 +2703,7 @@
/* for virtual port, codec driver needs to do
* housekeeping, for now should be ok
*/
- tabla_get_channel(tabla, rx_ch, tx_ch);
+ wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
if (dai->id == AIF1_PB) {
*rx_num = tabla_dai[dai->id - 1].playback.channels_max;
while (cnt < *rx_num) {
@@ -2784,7 +2788,7 @@
0x03, tx_fs_rate);
}
}
- if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
snd_soc_update_bits(codec,
@@ -2830,7 +2834,7 @@
0xE0, rx_fs_rate);
}
}
- if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
snd_soc_update_bits(codec,
@@ -2945,7 +2949,7 @@
static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct tabla *tabla;
+ struct wcd9xxx *tabla;
struct snd_soc_codec *codec = w->codec;
struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
u32 j = 0;
@@ -2953,7 +2957,7 @@
codec->control_data = dev_get_drvdata(codec->dev->parent);
tabla = codec->control_data;
/* Execute the callback only if interface type is slimbus */
- if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+ if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
return 0;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -2967,10 +2971,10 @@
}
}
if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
- ret = tabla_cfg_slim_sch_rx(tabla,
- tabla_p->dai[j].ch_num,
- tabla_p->dai[j].ch_tot,
- tabla_p->dai[j].rate);
+ ret = wcd9xxx_cfg_slim_sch_rx(tabla,
+ tabla_p->dai[j].ch_num,
+ tabla_p->dai[j].ch_tot,
+ tabla_p->dai[j].rate);
break;
case SND_SOC_DAPM_POST_PMD:
for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
@@ -2983,12 +2987,12 @@
}
}
if (!tabla_p->dai[j].ch_act) {
- ret = tabla_close_slim_sch_rx(tabla,
+ ret = wcd9xxx_close_slim_sch_rx(tabla,
tabla_p->dai[j].ch_num,
tabla_p->dai[j].ch_tot);
tabla_p->dai[j].rate = 0;
memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
- tabla_p->dai[j].ch_tot));
+ tabla_p->dai[j].ch_tot));
tabla_p->dai[j].ch_tot = 0;
}
}
@@ -2998,7 +3002,7 @@
static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct tabla *tabla;
+ struct wcd9xxx *tabla;
struct snd_soc_codec *codec = w->codec;
struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
/* index to the DAI ID, for now hardcoding */
@@ -3009,7 +3013,7 @@
tabla = codec->control_data;
/* Execute the callback only if interface type is slimbus */
- if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+ if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
return 0;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -3024,7 +3028,7 @@
}
}
if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
- ret = tabla_cfg_slim_sch_tx(tabla,
+ ret = wcd9xxx_cfg_slim_sch_tx(tabla,
tabla_p->dai[j].ch_num,
tabla_p->dai[j].ch_tot,
tabla_p->dai[j].rate);
@@ -3041,12 +3045,12 @@
}
}
if (!tabla_p->dai[j].ch_act) {
- ret = tabla_close_slim_sch_tx(tabla,
+ ret = wcd9xxx_close_slim_sch_tx(tabla,
tabla_p->dai[j].ch_num,
tabla_p->dai[j].ch_tot);
tabla_p->dai[j].rate = 0;
memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
- tabla_p->dai[j].ch_tot));
+ tabla_p->dai[j].ch_tot));
tabla_p->dai[j].ch_tot = 0;
}
}
@@ -3584,7 +3588,7 @@
snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
tabla->micbias);
- tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
return 0;
}
@@ -3655,10 +3659,10 @@
if (tabla->button_jack) {
bias_value = tabla_codec_read_sta_result(tabla->codec);
sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
- bias_value);
+ bias_value);
bias_value = tabla_codec_read_dce_result(tabla->codec);
dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
- bias_value);
+ bias_value);
pr_debug("%s: Reporting long button press event"
" STA: %d, DCE: %d\n", __func__,
sta_mv, dce_mv);
@@ -3670,7 +3674,6 @@
pr_err("%s: Bad tabla private data\n", __func__);
}
- tabla_unlock_sleep(core);
}
void tabla_mbhc_cal(struct snd_soc_codec *codec)
@@ -3850,7 +3853,7 @@
struct tabla_mbhc_btn_detect_cfg *btn_det;
int n;
u8 *n_cic, *gain;
- struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+ struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
tabla = snd_soc_codec_get_drvdata(codec);
generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
@@ -3998,7 +4001,7 @@
if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
pr_err("Error: clock rate %dHz is not yet supported\n",
- mclk_rate);
+ mclk_rate);
else
pr_err("Error: unsupported clock rate %d\n", mclk_rate);
return -EINVAL;
@@ -4037,9 +4040,9 @@
if (!IS_ERR_VALUE(rc)) {
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
0x10);
- tabla_enable_irq(codec->control_data,
+ wcd9xxx_enable_irq(codec->control_data,
TABLA_IRQ_HPH_PA_OCPL_FAULT);
- tabla_enable_irq(codec->control_data,
+ wcd9xxx_enable_irq(codec->control_data,
TABLA_IRQ_HPH_PA_OCPR_FAULT);
}
@@ -4057,7 +4060,7 @@
btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
- TABLA_BTN_DET_V_BTN_HIGH);
+ TABLA_BTN_DET_V_BTN_HIGH);
for (i = 0; i < btn_det->num_btn; i++) {
if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
btn = i;
@@ -4115,10 +4118,10 @@
TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
short btnmeas[d->n_btn_meas + 1];
struct snd_soc_codec *codec = priv->codec;
- struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
+ struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
bias_value_dce = tabla_codec_read_dce_result(codec);
bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
@@ -4164,12 +4167,12 @@
/* XXX: assuming button 0 has the lowest micbias voltage */
if (btn == 0) {
- tabla_lock_sleep(core);
+ wcd9xxx_lock_sleep(core);
if (schedule_delayed_work(&priv->btn0_dwork,
msecs_to_jiffies(400)) == 0) {
WARN(1, "Button pressed twice without release"
"event\n");
- tabla_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core);
}
} else {
pr_debug("%s: Reporting short button %d(0x%x) press\n",
@@ -4191,10 +4194,10 @@
short mb_v;
struct tabla_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
+ struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
pr_debug("%s: enter\n", __func__);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
if (priv->buttons_pressed & SND_JACK_BTN_0) {
ret = cancel_delayed_work(&priv->btn0_dwork);
@@ -4208,7 +4211,7 @@
} else {
/* if scheduled btn0_dwork is canceled from here,
* we have to unlock from here instead btn0_work */
- tabla_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core);
mb_v = tabla_codec_sta_dce(codec, 0);
pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
__func__, mb_v,
@@ -4304,7 +4307,7 @@
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
0x10);
} else {
- tabla_disable_irq(codec->control_data,
+ wcd9xxx_disable_irq(codec->control_data,
TABLA_IRQ_HPH_PA_OCPL_FAULT);
tabla->hphlocp_cnt = 0;
tabla->hph_status |= SND_JACK_OC_HPHL;
@@ -4337,7 +4340,7 @@
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
0x10);
} else {
- tabla_disable_irq(codec->control_data,
+ wcd9xxx_disable_irq(codec->control_data,
TABLA_IRQ_HPH_PA_OCPR_FAULT);
tabla->hphrocp_cnt = 0;
tabla->hph_status |= SND_JACK_OC_HPHR;
@@ -4357,26 +4360,26 @@
static void tabla_sync_hph_state(struct tabla_priv *tabla)
{
if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
- &tabla->hph_pa_dac_state)) {
+ &tabla->hph_pa_dac_state)) {
pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
1 << 4);
}
if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
- &tabla->hph_pa_dac_state)) {
+ &tabla->hph_pa_dac_state)) {
pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
1 << 5);
}
if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
- &tabla->hph_pa_dac_state)) {
+ &tabla->hph_pa_dac_state)) {
pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
0xC0, 0xC0);
}
if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
- &tabla->hph_pa_dac_state)) {
+ &tabla->hph_pa_dac_state)) {
pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
0xC0, 0xC0);
@@ -4395,7 +4398,7 @@
int mic_mv;
pr_debug("%s: enter\n", __func__);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
@@ -4406,7 +4409,7 @@
if (priv->mbhc_fake_ins_start &&
time_after(jiffies, priv->mbhc_fake_ins_start +
- msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
+ msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
pr_debug("%s: fake context interrupt, reset insertion\n",
__func__);
priv->mbhc_fake_ins_start = 0;
@@ -4482,8 +4485,8 @@
0),
mb_v, mic_mv);
if (time_after(jiffies,
- priv->mbhc_fake_ins_start +
- msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
+ priv->mbhc_fake_ins_start +
+ msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
/* Disable HPH trigger and enable MIC line trigger */
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
0x00);
@@ -4509,7 +4512,8 @@
}
/* Setup for insertion detection */
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
- tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_enable_irq(codec->control_data,
+ TABLA_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
} else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
@@ -4559,9 +4563,9 @@
int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
pr_debug("%s: enter, removal interrupt\n", __func__);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
usleep_range(generic->t_shutdown_plug_rem,
generic->t_shutdown_plug_rem);
@@ -4611,11 +4615,11 @@
int i, j;
u8 val;
- for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
- slimbus_value = tabla_interface_reg_read(codec->control_data,
+ for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
+ slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
- val = tabla_interface_reg_read(codec->control_data,
+ val = wcd9xxx_interface_reg_read(codec->control_data,
TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
if (val & 0x1)
pr_err_ratelimited("overflow error on port %x,"
@@ -4624,7 +4628,7 @@
pr_err_ratelimited("underflow error on port %x,"
" value %x\n", i*8 + j, val);
}
- tabla_interface_reg_write(codec->control_data,
+ wcd9xxx_interface_reg_write(codec->control_data,
TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
}
@@ -4635,7 +4639,7 @@
static int tabla_handle_pdata(struct tabla_priv *tabla)
{
struct snd_soc_codec *codec = tabla->codec;
- struct tabla_pdata *pdata = tabla->pdata;
+ struct wcd9xxx_pdata *pdata = tabla->pdata;
int k1, k2, k3, rc = 0;
u8 leg_mode = pdata->amic_settings.legacy_mode;
u8 txfe_bypass = pdata->amic_settings.txfe_enable;
@@ -4802,7 +4806,7 @@
static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
{
u32 i;
- struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+ struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
@@ -4894,7 +4898,7 @@
static void tabla_codec_init_reg(struct snd_soc_codec *codec)
{
u32 i;
- struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
+ struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
@@ -4918,7 +4922,7 @@
static void tabla_update_reg_address(struct tabla_priv *priv)
{
- struct tabla *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
+ struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
struct tabla_reg_address *reg_addr = &priv->reg_addr;
if (TABLA_IS_1_X(tabla_core->version)) {
@@ -4934,7 +4938,7 @@
static int tabla_codec_probe(struct snd_soc_codec *codec)
{
- struct tabla *control;
+ struct wcd9xxx *control;
struct tabla_priv *tabla;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
@@ -4973,7 +4977,7 @@
tabla->no_mic_headset_override = false;
tabla->codec = codec;
tabla->pdata = dev_get_platdata(codec->dev->parent);
- tabla->intf_type = tabla_get_intf_type();
+ tabla->intf_type = wcd9xxx_get_intf_type();
tabla_update_reg_address(tabla);
tabla_update_reg_defaults(codec);
@@ -5002,7 +5006,7 @@
snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
ARRAY_SIZE(tabla_2_higher_dapm_widgets));
- if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
ARRAY_SIZE(tabla_dapm_i2s_widgets));
snd_soc_dapm_add_routes(dapm, audio_i2s_map,
@@ -5018,49 +5022,49 @@
ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
} else {
pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
- __func__, control->version);
+ __func__, control->version);
goto err_pdata;
}
snd_soc_dapm_sync(dapm);
- ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
+ ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
tabla_hs_insert_irq, "Headset insert detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
TABLA_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
- ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
+ ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
tabla_hs_remove_irq, "Headset remove detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
TABLA_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
- ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
+ ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
tabla_dce_handler, "DC Estimation detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
TABLA_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
- ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
+ ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
tabla_release_handler, "Button Release detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
TABLA_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
- ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
+ ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
tabla_slimbus_irq, "SLIMBUS Slave", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
@@ -5068,11 +5072,11 @@
goto err_slimbus_irq;
}
- for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
- tabla_interface_reg_write(codec->control_data,
+ for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+ wcd9xxx_interface_reg_write(codec->control_data,
TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
- ret = tabla_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(codec->control_data,
TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
"HPH_L OCP detect", tabla);
if (ret) {
@@ -5080,9 +5084,9 @@
TABLA_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
- ret = tabla_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(codec->control_data,
TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
"HPH_R OCP detect", tabla);
if (ret) {
@@ -5090,7 +5094,7 @@
TABLA_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
switch (tabla_dai[i].id) {
case AIF1_PB:
@@ -5116,17 +5120,18 @@
return ret;
err_hphr_ocp_irq:
- tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
+ wcd9xxx_free_irq(codec->control_data,
+ TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
err_hphl_ocp_irq:
- tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
err_slimbus_irq:
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
err_release_irq:
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
err_potential_irq:
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
err_remove_irq:
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
err_insert_irq:
err_pdata:
kfree(tabla);
@@ -5136,11 +5141,11 @@
{
int i;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
- tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
if (tabla->mbhc_fw)
@@ -5227,10 +5232,10 @@
S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
#endif
- if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
tabla_dai, ARRAY_SIZE(tabla_dai));
- else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
+ else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
return ret;
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 9c430b9..d1d0c17 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -11,7 +11,7 @@
*/
#include <sound/soc.h>
#include <sound/jack.h>
-#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#define TABLA_NUM_REGISTERS 0x400
#define TABLA_MAX_REGISTER (TABLA_NUM_REGISTERS-1)
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 1ed5f74..3a2687e 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -126,6 +126,7 @@
select SND_SOC_QDSP6
select SND_SOC_MSM_STUB
select SND_SOC_WCD9310
+ select SND_SOC_WCD9304
select SND_SOC_MSM_HOSTLESS_PCM
select SND_SOC_MSM_QDSP6_HDMI_AUDIO
default n
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 6f2d651..2aef4bd 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -62,7 +62,7 @@
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
-snd-soc-msm8960-objs := msm8960.o apq8064.o
+snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o
obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
# Generic MSM drivers
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index 6907ded..3333344 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -14,10 +14,8 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <linux/mfd/wcd9310/core.h>
#include <linux/bitops.h>
#include <linux/slab.h>
-#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -25,7 +23,6 @@
#include <sound/q6afe.h>
#include <sound/q6adm.h>
#include <sound/msm-dai-q6.h>
-#include <mach/clk.h>
#include <mach/msm_hdmi_audio.h>
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index f23a6a0..0430f7b 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -14,7 +14,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <linux/mfd/wcd9310/core.h>
+#include <linux/mfd/wcd9xxx/core.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/clk.h>
@@ -100,6 +100,7 @@
break;
}
}
+ dai_data->rate = params_rate(params);
/* Q6 only supports 16 as now */
dai_data->port_config.mi2s.bitwidth = 16;
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index 01b8463..a176118 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.c
@@ -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
@@ -149,6 +149,8 @@
}
case AFE_EVENT_RTPORT_STOP:
pr_debug("%s: event!=0\n", __func__);
+ prtd->start = 0;
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
break;
case AFE_EVENT_RTPORT_LOW_WM:
pr_debug("%s: Underrun\n", __func__);
@@ -213,6 +215,8 @@
}
case AFE_EVENT_RTPORT_STOP:
pr_debug("%s: event!=0\n", __func__);
+ prtd->start = 0;
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
break;
case AFE_EVENT_RTPORT_LOW_WM:
pr_debug("%s: Underrun\n", __func__);
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 83fd691..0b7cc78 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -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
@@ -27,6 +27,9 @@
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/android_pmem.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
#include "msm-pcm-q6.h"
#include "msm-pcm-routing.h"
@@ -459,7 +462,8 @@
return -ENOMEM;
}
buf = prtd->audio_client->port[dir].buf;
- if (!buf && !buf[0].data)
+
+ if (buf == NULL || buf[0].data == NULL)
return -ENOMEM;
pr_debug("%s:buf = %p\n", __func__, buf);
@@ -482,8 +486,37 @@
int rc = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
+ uint64_t timestamp;
+ uint64_t temp;
switch (cmd) {
+ case SNDRV_COMPRESS_TSTAMP: {
+ struct snd_compr_tstamp tstamp;
+ pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+
+ memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
+ timestamp = q6asm_get_session_time(prtd->audio_client);
+ if (timestamp < 0) {
+ pr_err("%s: Get Session Time return value =%lld\n",
+ __func__, timestamp);
+ return -EAGAIN;
+ }
+ temp = (timestamp * 2 * runtime->channels);
+ temp = temp * (runtime->rate/1000);
+ temp = div_u64(temp, 1000);
+ tstamp.sampling_rate = runtime->rate;
+ tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
+ tstamp.decoded = (size_t)((temp >> 32) & 0xFFFFFFFF);
+ tstamp.timestamp = timestamp;
+ pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+ "timestamp = %lld,\n",
+ __func__, tstamp.rendered, tstamp.decoded,
+ tstamp.timestamp);
+ if (copy_to_user((void *) arg, &tstamp,
+ sizeof(struct snd_compr_tstamp)))
+ return -EFAULT;
+ return 0;
+ }
case SNDRV_PCM_IOCTL1_RESET:
prtd->cmd_ack = 0;
rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index eafe0f9..471284b 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -129,7 +129,7 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_voice *prtd = runtime->private_data;
- int ret;
+ int ret = 0;
mutex_lock(&prtd->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/msm/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index 56b4cf5..2301472 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -108,6 +108,7 @@
uint32_t mode;
uint32_t rate_type;
uint32_t rate;
+ uint32_t dtx_mode;
uint8_t capture_start;
uint8_t playback_start;
@@ -200,6 +201,31 @@
return 0;
}
+static int msm_voip_dtx_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ voip_info.dtx_mode = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: dtx: %d\n", __func__, voip_info.dtx_mode);
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+static int msm_voip_dtx_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ ucontrol->value.integer.value[0] = voip_info.dtx_mode;
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
static struct snd_kcontrol_new msm_voip_controls[] = {
SOC_SINGLE_EXT("Voip Tx Mute", SND_SOC_NOPM, 0, 1, 0,
msm_voip_mute_get, msm_voip_mute_put),
@@ -208,6 +234,8 @@
SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
0, 2, msm_voip_mode_rate_config_get,
msm_voip_mode_rate_config_put),
+ SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
+ msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
};
static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
@@ -713,11 +741,13 @@
if ((prtd->play_samp_rate == 8000) &&
(prtd->cap_samp_rate == 8000))
voc_config_vocoder(media_type, rate_type,
- VSS_NETWORK_ID_VOIP_NB);
+ VSS_NETWORK_ID_VOIP_NB,
+ voip_info.dtx_mode);
else if ((prtd->play_samp_rate == 16000) &&
(prtd->cap_samp_rate == 16000))
voc_config_vocoder(media_type, rate_type,
- VSS_NETWORK_ID_VOIP_WB);
+ VSS_NETWORK_ID_VOIP_WB,
+ voip_info.dtx_mode);
else {
pr_debug("%s: Invalid rate playback %d, capture %d\n",
__func__, prtd->play_samp_rate,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
new file mode 100644
index 0000000..a081253
--- /dev/null
+++ b/sound/soc/msm/msm8930.c
@@ -0,0 +1,1083 @@
+/* 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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dsp.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9304.h"
+
+/* 8930 machine driver */
+
+#define PM8921_GPIO_BASE NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8930_SPK_ON 1
+#define MSM8930_SPK_OFF 0
+
+#define msm8930_SLIM_0_RX_MAX_CHANNELS 2
+#define msm8930_SLIM_0_TX_MAX_CHANNELS 4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS 0x1
+#define BOTTOM_SPK_AMP_NEG 0x2
+#define TOP_SPK_AMP_POS 0x4
+#define TOP_SPK_AMP_NEG 0x8
+
+#define GPIO_AUX_PCM_DOUT 63
+#define GPIO_AUX_PCM_DIN 64
+#define GPIO_AUX_PCM_SYNC 65
+#define GPIO_AUX_PCM_CLK 66
+
+#define SITAR_EXT_CLK_RATE 12288000
+
+#define SITAR_MBHC_DEF_BUTTONS 3
+#define SITAR_MBHC_DEF_RLOADS 5
+
+static int msm8930_spk_control;
+static int msm8930_slim_0_rx_ch = 1;
+static int msm8930_slim_0_tx_ch = 1;
+
+static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm8930_btsco_ch = 1;
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static int msm8930_headset_gpios_configured;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+struct sitar_mbhc_calibration sitar_calib = {
+ .bias = SITAR_MICBIAS2,
+ .tldoh = 100,
+ .bg_fast_settle = 100,
+ .mic_current = SITAR_PID_MIC_5_UA,
+ .mic_pid = 100,
+ .hph_current = SITAR_PID_MIC_5_UA,
+ .setup_plug_removal_delay = 1000000,
+ .shutdown_plug_removal = 100000,
+};
+
+static void msm8930_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
+ if (msm8930_spk_control == MSM8930_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Right Pos");
+ }
+
+ snd_soc_dapm_sync(dapm);
+}
+
+static int msm8930_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
+ ucontrol->value.integer.value[0] = msm8930_spk_control;
+ return 0;
+}
+static int msm8930_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 (msm8930_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm8930_spk_control = ucontrol->value.integer.value[0];
+ msm8930_ext_control(codec);
+ return 1;
+}
+
+static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+ /* TODO: add external speaker power amps support */
+ return 0;
+}
+int msm8930_enable_codec_ext_clk(
+ struct snd_soc_codec *codec, int enable)
+{
+ pr_debug("%s: enable = %d\n", __func__, enable);
+ if (enable) {
+ clk_users++;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users != 1)
+ return 0;
+
+ if (codec_clk) {
+ clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
+ clk_enable(codec_clk);
+ sitar_mclk_enable(codec, 1);
+ } else {
+ pr_err("%s: Error setting Tabla MCLK\n", __func__);
+ clk_users--;
+ return -EINVAL;
+ }
+ } else {
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users == 0)
+ return 0;
+ clk_users--;
+ if (!clk_users) {
+ pr_debug("%s: disabling MCLK. clk_users = %d\n",
+ __func__, clk_users);
+ clk_disable(codec_clk);
+ sitar_mclk_enable(codec, 0);
+ }
+ }
+ return 0;
+}
+
+static int msm8930_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm8930_enable_codec_ext_clk(w->codec, 1);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm8930_enable_codec_ext_clk(w->codec, 0);
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8930_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Right Pos", msm8930_spkramp_event),
+
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+
+};
+
+static const struct snd_soc_dapm_route common_audio_map[] = {
+
+ {"RX_BIAS", NULL, "MCLK"},
+ {"LDO_H", NULL, "MCLK"},
+
+ {"MIC BIAS1 Internal1", NULL, "MCLK"},
+ {"MIC BIAS2 Internal1", NULL, "MCLK"},
+
+ /* Speaker path */
+ {"Ext Spk Left Pos", NULL, "LINEOUT1"},
+ {"Ext Spk Right Pos", NULL, "LINEOUT2"},
+
+
+ {"AMIC2", NULL, "MIC BIAS2 Internal1"},
+ {"MIC BIAS2 Internal1", NULL, "Headset Mic"},
+
+ /* Microphone path */
+ {"AMIC1", NULL, "MIC BIAS1 Internal1"},
+ {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
+
+ {"HEADPHONE", NULL, "LDO_H"},
+
+ /**
+ * The digital Mic routes are setup considering
+ * fluid as default device.
+ */
+
+ /**
+ * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
+ * Digital Mic GM5 on CDP mainboard.
+ * Conncted to DMIC2 Input on Tabla codec.
+ */
+ {"DMIC1", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+ /**
+ * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
+ * Digital Mic GM6 on CDP mainboard.
+ * Conncted to DMIC1 Input on Tabla codec.
+ */
+ {"DMIC2", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic2"},
+ /**
+ * Digital Mic3. Back Bottom Digital Mic on Fluid.
+ * Digital Mic GM1 on CDP mainboard.
+ * Conncted to DMIC4 Input on Tabla codec.
+ */
+ {"DMIC3", NULL, "MIC BIAS2 External"},
+ {"MIC BIAS2 External", NULL, "Digital Mic3"},
+
+ /**
+ * Digital Mic4. Back top Digital Mic on Fluid.
+ * Digital Mic GM2 on CDP mainboard.
+ * Conncted to DMIC3 Input on Tabla codec.
+ */
+ {"DMIC4", NULL, "MIC BIAS2 External"},
+ {"MIC BIAS2 External", NULL, "Digital Mic4"},
+
+
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *slim0_rx_ch_text[] = {"One", "Two"};
+static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm8930_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+};
+
+static const char *btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm8930_btsco_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm8930_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
+ msm8930_slim_0_rx_ch);
+ ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
+ return 0;
+}
+
+static int msm8930_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
+ msm8930_slim_0_rx_ch);
+ return 1;
+}
+
+static int msm8930_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
+ msm8930_slim_0_tx_ch);
+ ucontrol->value.integer.value[0] = msm8930_slim_0_tx_ch - 1;
+ return 0;
+}
+
+static int msm8930_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm8930_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
+ msm8930_slim_0_tx_ch);
+ return 1;
+}
+
+static int msm8930_btsco_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8930_btsco_rate = %d", __func__, msm8930_btsco_rate);
+ ucontrol->value.integer.value[0] = msm8930_btsco_rate;
+ return 0;
+}
+
+static int msm8930_btsco_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ case 1:
+ msm8930_btsco_rate = BTSCO_RATE_16KHZ;
+ break;
+ default:
+ msm8930_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: msm8930_btsco_rate = %d\n", __func__, msm8930_btsco_rate);
+ return 0;
+}
+
+static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
+ msm8930_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", msm8930_enum[1],
+ msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
+ msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
+};
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
+ msm8930_btsco_rate_get, msm8930_btsco_rate_put),
+};
+
+static int msm8930_btsco_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err = 0;
+ struct snd_soc_platform *platform = rtd->platform;
+
+ err = snd_soc_add_platform_controls(platform,
+ int_btsco_rate_mixer_controls,
+ ARRAY_SIZE(int_btsco_rate_mixer_controls));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int msm8930_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+ pr_debug("%s: ch=%d\n", __func__,
+ msm8930_slim_0_rx_ch);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm8930_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ msm8930_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ msm8930_slim_0_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ msm8930_slim_0_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+
+ }
+end:
+ return ret;
+}
+
+static int msm8930_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;
+
+ pr_debug("%s()\n", __func__);
+
+
+ rtd->pmdown_time = 0;
+
+ err = snd_soc_add_controls(codec, sitar_msm8930_controls,
+ ARRAY_SIZE(sitar_msm8930_controls));
+ if (err < 0)
+ return err;
+
+ snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
+ ARRAY_SIZE(msm8930_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, common_audio_map,
+ ARRAY_SIZE(common_audio_map));
+
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
+
+ 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",
+ SND_JACK_BTN_0, &button_jack);
+ if (err) {
+ pr_err("failed to create new jack\n");
+ return err;
+ }
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ sitar_hs_detect(codec, &hs_jack, &button_jack, &sitar_calib);
+ return 0;
+}
+
+static struct snd_soc_dsp_link lpa_fe_media = {
+ .playback = true,
+ .trigger = {
+ SND_SOC_DSP_TRIGGER_POST,
+ SND_SOC_DSP_TRIGGER_POST
+ },
+};
+
+static struct snd_soc_dsp_link fe_media = {
+ .playback = true,
+ .capture = true,
+ .trigger = {
+ SND_SOC_DSP_TRIGGER_POST,
+ SND_SOC_DSP_TRIGGER_POST
+ },
+};
+
+static struct snd_soc_dsp_link slimbus0_hl_media = {
+ .playback = true,
+ .capture = true,
+ .trigger = {
+ SND_SOC_DSP_TRIGGER_POST,
+ SND_SOC_DSP_TRIGGER_POST
+ },
+};
+
+static struct snd_soc_dsp_link int_fm_hl_media = {
+ .playback = true,
+ .capture = true,
+ .trigger = {
+ SND_SOC_DSP_TRIGGER_POST,
+ SND_SOC_DSP_TRIGGER_POST
+ },
+};
+
+/* bi-directional media definition for hostless PCM device */
+static struct snd_soc_dsp_link bidir_hl_media = {
+ .playback = true,
+ .capture = true,
+ .trigger = {
+ SND_SOC_DSP_TRIGGER_POST,
+ SND_SOC_DSP_TRIGGER_POST
+ },
+};
+
+static struct snd_soc_dsp_link hdmi_rx_hl = {
+ .playback = true,
+ .trigger = {
+ SND_SOC_DSP_TRIGGER_POST,
+ SND_SOC_DSP_TRIGGER_POST
+ },
+};
+
+static int msm8930_slim_0_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);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm8930_slim_0_rx_ch;
+
+ return 0;
+}
+
+static int msm8930_slim_0_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);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm8930_slim_0_tx_ch;
+
+ return 0;
+}
+
+static int msm8930_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);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
+static int msm8930_hdmi_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 = 2;
+
+ return 0;
+}
+
+static int msm8930_btsco_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 = msm8930_btsco_rate;
+ channels->min = channels->max = msm8930_btsco_ch;
+
+ return 0;
+}
+static int msm8930_auxpcm_be_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);
+
+ /* PCM only supports mono output with 8khz sample rate */
+ rate->min = rate->max = 8000;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+static int msm8930_aux_pcm_get_gpios(void)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+ __func__, GPIO_AUX_PCM_DOUT);
+ goto fail_dout;
+ }
+
+ ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+ __func__, GPIO_AUX_PCM_DIN);
+ goto fail_din;
+ }
+
+ ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+ __func__, GPIO_AUX_PCM_SYNC);
+ goto fail_sync;
+ }
+ ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+ __func__, GPIO_AUX_PCM_CLK);
+ goto fail_clk;
+ }
+
+ return 0;
+
+fail_clk:
+ gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+ gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+ gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+ return ret;
+}
+
+static int msm8930_aux_pcm_free_gpios(void)
+{
+ gpio_free(GPIO_AUX_PCM_DIN);
+ gpio_free(GPIO_AUX_PCM_DOUT);
+ gpio_free(GPIO_AUX_PCM_SYNC);
+ gpio_free(GPIO_AUX_PCM_CLK);
+
+ return 0;
+}
+static int msm8930_startup(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ return 0;
+}
+
+static int msm8930_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ ret = msm8930_aux_pcm_get_gpios();
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ msm8930_aux_pcm_free_gpios();
+}
+
+static void msm8930_shutdown(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+}
+
+static struct snd_soc_ops msm8930_be_ops = {
+ .startup = msm8930_startup,
+ .hw_params = msm8930_hw_params,
+ .shutdown = msm8930_shutdown,
+};
+
+static struct snd_soc_ops msm8930_auxpcm_be_ops = {
+ .startup = msm8930_auxpcm_startup,
+ .shutdown = msm8930_auxpcm_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm8930_dai[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSM8930 Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp",
+ .dynamic = 1,
+ .dsp_link = &fe_media,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {
+ .name = "MSM8930 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp",
+ .dynamic = 1,
+ .dsp_link = &fe_media,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dsp_link = &fe_media,
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dsp_link = &fe_media,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
+ .name = "MSM8930 LPA",
+ .stream_name = "LPA",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-lpa",
+ .dynamic = 1,
+ .dsp_link = &lpa_fe_media,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PMC purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &slimbus0_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* .be_id = do not care */
+ },
+ {
+ .name = "INT_FM Hostless",
+ .stream_name = "INT_FM Hostless",
+ .cpu_dai_name = "INT_FM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &int_fm_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* .be_id = do not care */
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM8930 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .dsp_link = &lpa_fe_media,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &bidir_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &hdmi_rx_hl,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .no_codec = 1,
+ .ignore_suspend = 1,
+ },
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "sitar_codec",
+ .codec_dai_name = "sitar_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm8930_audrx_init,
+ .be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm8930_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "sitar_codec",
+ .codec_dai_name = "sitar_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
+ .ops = &msm8930_be_ops,
+ },
+ /* Backend BT/FM DAI Links */
+ {
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6.12288",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .init = &msm8930_btsco_init,
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6.12289",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
+ },
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6.12292",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_RX,
+ .be_hw_params_fixup = msm8930_be_hw_params_fixup,
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6.12293",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_TX,
+ .be_hw_params_fixup = msm8930_be_hw_params_fixup,
+ },
+ /* HDMI BACK END DAI Link */
+ {
+ .name = LPASS_BE_HDMI,
+ .stream_name = "HDMI Playback",
+ .cpu_dai_name = "msm-dai-q6-hdmi.8",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
+ },
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_codec = 1,
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_codec = 1,
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ },
+ /* AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+ .ops = &msm8930_auxpcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm8930_be_hw_params_fixup,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm8930_be_hw_params_fixup,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm8930_be_hw_params_fixup,
+ },
+};
+
+struct snd_soc_card snd_soc_card_msm8930 = {
+ .name = "msm8930-sitar-snd-card",
+ .dai_link = msm8930_dai,
+ .num_links = ARRAY_SIZE(msm8930_dai),
+};
+
+static struct platform_device *msm8930_snd_device;
+
+static int msm8930_configure_headset_mic_gpios(void)
+{
+ int ret;
+ ret = gpio_request(80, "US_EURO_SWITCH");
+ if (ret) {
+ pr_err("%s: Failed to request gpio 80\n", __func__);
+ return ret;
+ }
+ ret = gpio_direction_output(80, 0);
+ if (ret) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ gpio_free(80);
+ }
+ msm8930_headset_gpios_configured = 0;
+ return 0;
+}
+static void msm8930_free_headset_mic_gpios(void)
+{
+ if (msm8930_headset_gpios_configured)
+ gpio_free(80);
+}
+
+static int __init msm8930_audio_init(void)
+{
+ int ret;
+
+ if (!cpu_is_msm8930()) {
+ pr_err("%s: Not the right machine type\n", __func__);
+ return -ENODEV ;
+ }
+
+ msm8930_snd_device = platform_device_alloc("soc-audio", 0);
+ if (!msm8930_snd_device) {
+ pr_err("Platform device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
+ ret = platform_device_add(msm8930_snd_device);
+ if (ret) {
+ platform_device_put(msm8930_snd_device);
+ return ret;
+ }
+
+ if (msm8930_configure_headset_mic_gpios()) {
+ pr_err("%s Fail to configure headset mic gpios\n", __func__);
+ msm8930_headset_gpios_configured = 0;
+ } else
+ msm8930_headset_gpios_configured = 1;
+
+ return ret;
+
+}
+module_init(msm8930_audio_init);
+
+static void __exit msm8930_audio_exit(void)
+{
+ if (!cpu_is_msm8930()) {
+ pr_err("%s: Not the right machine type\n", __func__);
+ return ;
+ }
+ msm8930_free_headset_mic_gpios();
+ platform_device_unregister(msm8930_snd_device);
+}
+module_exit(msm8930_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MSM8930");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index eb363e7..0854dff 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1391,7 +1391,7 @@
{
int ret;
- if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
+ if (!cpu_is_msm8960()) {
pr_err("%s: Not the right machine type\n", __func__);
return -ENODEV ;
}
@@ -1455,7 +1455,7 @@
static void __exit msm8960_audio_exit(void)
{
- if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
+ if (!cpu_is_msm8960()) {
pr_err("%s: Not the right machine type\n", __func__);
return ;
}
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index dc49f12..d822af5 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -3211,7 +3211,7 @@
{
pr_debug("%s\n", __func__);
- if (session_id < 0) {
+ if (session_id < 0 || session_id > SESSION_MAX) {
pr_err("%s: invalid session_id = %d\n", __func__, session_id);
return -EINVAL;
}
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 532d92b..f0f833c 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -662,6 +662,59 @@
return -EINVAL;
}
+static int voice_set_dtx(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* Set DTX */
+ cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+ cvs_set_dtx.hdr.src_port = v->session_id;
+ cvs_set_dtx.hdr.dest_port = cvs_handle;
+ cvs_set_dtx.hdr.token = 0;
+ cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+ cvs_set_dtx.dtx_mode.enable = common.mvs_info.dtx_mode;
+
+ pr_debug("%s: Setting DTX %d\n", __func__, common.mvs_info.dtx_mode);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_DTX\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int voice_config_cvs_vocoder(struct voice_data *v)
{
int ret = 0;
@@ -753,7 +806,6 @@
}
case VSS_MEDIA_ID_AMR_NB_MODEM: {
struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
- struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
pr_debug("Setting AMR rate\n");
@@ -785,40 +837,15 @@
pr_err("%s: wait_event timeout\n", __func__);
goto fail;
}
- /* Disable DTX */
- pr_debug("Disabling DTX\n");
- cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_dtx) - APR_HDR_SIZE);
- cvs_set_dtx.hdr.src_port = v->session_id;
- cvs_set_dtx.hdr.dest_port = cvs_handle;
- cvs_set_dtx.hdr.token = 0;
- cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
- cvs_set_dtx.dtx_mode.enable = 0;
-
- v->cvs_state = CMD_STATUS_FAIL;
-
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_DTX\n",
- __func__, ret);
+ ret = voice_set_dtx(v);
+ if (ret < 0)
goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
+
break;
}
case VSS_MEDIA_ID_AMR_WB_MODEM: {
struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
- struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
pr_debug("Setting AMR WB rate\n");
@@ -851,70 +878,18 @@
pr_err("%s: wait_event timeout\n", __func__);
goto fail;
}
- /* Disable DTX */
- pr_debug("Disabling DTX\n");
- cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_dtx) - APR_HDR_SIZE);
- cvs_set_dtx.hdr.src_port = v->session_id;
- cvs_set_dtx.hdr.dest_port = cvs_handle;
- cvs_set_dtx.hdr.token = 0;
- cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
- cvs_set_dtx.dtx_mode.enable = 0;
-
- v->cvs_state = CMD_STATUS_FAIL;
-
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_DTX\n",
- __func__, ret);
+ ret = voice_set_dtx(v);
+ if (ret < 0)
goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
+
break;
}
case VSS_MEDIA_ID_G729:
case VSS_MEDIA_ID_G711_ALAW:
case VSS_MEDIA_ID_G711_MULAW: {
- struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
- /* Disable DTX */
- pr_debug("Disabling DTX\n");
+ ret = voice_set_dtx(v);
- cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_dtx) - APR_HDR_SIZE);
- cvs_set_dtx.hdr.src_port = v->session_id;
- cvs_set_dtx.hdr.dest_port = cvs_handle;
- cvs_set_dtx.hdr.token = 0;
- cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
- cvs_set_dtx.dtx_mode.enable = 0;
-
- v->cvs_state = CMD_STATUS_FAIL;
-
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_DTX\n",
- __func__, ret);
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
break;
}
default:
@@ -3236,11 +3211,13 @@
void voc_config_vocoder(uint32_t media_type,
uint32_t rate,
- uint32_t network_type)
+ uint32_t network_type,
+ uint32_t dtx_mode)
{
common.mvs_info.media_type = media_type;
common.mvs_info.rate = rate;
common.mvs_info.network_type = network_type;
+ common.mvs_info.dtx_mode = dtx_mode;
}
static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 2dc08d6..1a24b9c 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -785,6 +785,7 @@
uint32_t media_type;
uint32_t rate;
uint32_t network_type;
+ uint32_t dtx_mode;
ul_cb_fn ul_cb;
dl_cb_fn dl_cb;
void *private_data;
@@ -876,7 +877,8 @@
void voc_config_vocoder(uint32_t media_type,
uint32_t rate,
- uint32_t network_type);
+ uint32_t network_type,
+ uint32_t dtx_mode);
enum {
DEV_RX = 0,
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c03f7ca7..3063f3e 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1318,7 +1318,7 @@
/* Do we need to apply any queued changes? */
if (sort[w->id] != cur_sort || w->reg != cur_reg ||
w->dapm != cur_dapm || w->subseq != cur_subseq) {
- if (!list_empty(&pending))
+ if (cur_dapm && !list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending);
if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1378,7 +1378,7 @@
"Failed to apply widget power: %d\n", ret);
}
- if (!list_empty(&pending))
+ if (cur_dapm && !list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending);
if (cur_dapm && cur_dapm->seq_notifier) {
diff --git a/tools/perf/builtin-periodic.c b/tools/perf/builtin-periodic.c
index 70a0e2b..060e909 100644
--- a/tools/perf/builtin-periodic.c
+++ b/tools/perf/builtin-periodic.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -194,6 +194,8 @@
if (p == NULL)
return PERF_PERIODIC_ERROR;
for (cpu = 0; cpu < cpus->nr; cpu++) {
+ if (((1 << cpu) & cpumask) == 0)
+ continue;
p->perf_fd[cpu] = sys_perf_event_open(p->attr, target_pid, cpu,
-1, 0);
if (p->perf_fd[cpu] < 0)