Merge "radio-tavarua: Add private IOCTLs to poke threshold values." into msm-3.0
diff --git a/Documentation/genlock.txt b/Documentation/genlock.txt
new file mode 100644
index 0000000..d3a44e2
--- /dev/null
+++ b/Documentation/genlock.txt
@@ -0,0 +1,161 @@
+Introduction
+
+'genlock' is an in-kernel API and optional userspace interface for a generic
+cross-process locking mechanism. The API is designed for situations where
+multiple user space processes and/or kernel drivers need to coordinate access
+to a shared resource, such as a graphics buffer. The API was designed with
+graphics buffers in mind, but is sufficiently generic to allow it to be
+independently used with different types of resources. The chief advantage
+of genlock over other cross-process locking mechanisms is that the resources
+can be accessed by both userspace and kernel drivers which allows resources
+to be locked or unlocked by asynchronous events in the kernel without the
+intervention of user space.
+
+As an example, consider a graphics buffer that is shared between a rendering
+application and a compositing window manager. The application renders into a
+buffer. That buffer is reused by the compositing window manager as a texture.
+To avoid corruption, access to the buffer needs to be restricted so that one
+is not drawing on the surface while the other is reading. Locks can be
+explicitly added between the rendering stages in the processes, but explicit
+locks require that the application wait for rendering and purposely release the
+lock. An implicit release triggered by an asynchronous event from the GPU
+kernel driver, however, will let execution continue without requiring the
+intercession of user space.
+
+SW Goals
+
+The genlock API implements exclusive write locks and shared read locks meaning
+that there can only be one writer at a time, but multiple readers. Processes
+that are unable to acquire a lock can be optionally blocked until the resource
+becomes available.
+
+Locks are shared between processes. Each process will have its own private
+instance for a lock known as a handle. Handles can be shared between user
+space and kernel space to allow a kernel driver to unlock or lock a buffer
+on behalf of a user process.
+
+Kernel API
+
+Access to the genlock API can either be via the in-kernel API or via an
+optional character device (/dev/genlock). The character device is primarily
+to be used for legacy resource sharing APIs that cannot be easily changed.
+New resource sharing APIs from this point should implement a scheme specific
+wrapper for locking.
+
+To create or attach to an existing lock, a process or kernel driver must first
+create a handle. Each handle is linked to a single lock at any time. An entityi
+may have multiple handles, each associated with a different lock. Once a handle
+has been created, the owner may create a new lock or attach an existing lock
+that has been exported from a different handle.
+
+Once the handle has a lock attached, the owning process may attempt to lock the
+buffer for read or write. Write locks are exclusive, meaning that only one
+process may acquire it at any given time. Read locks are shared, meaning that
+multiple readers can hold the lock at the same time. Attempts to acquire a read
+lock with a writer active or a write lock with one or more readers or writers
+active will typically cause the process to block until the lock is acquired.
+When the lock is released, all waiting processes will be woken up. Ownership
+of the lock is reference counted, meaning that any one owner can "lock"
+multiple times. The lock will only be released from the owner when all the
+references to the lock are released via unlock.
+
+The owner of a write lock may atomically convert the lock into a read lock
+(which will wake up other processes waiting for a read lock) without first
+releasing the lock. The owner would simply issue a new request for a read lock.
+However, the owner of a read lock cannot convert it into a write lock in the
+same manner. To switch from a read lock to a write lock, the owner must
+release the lock and then try to reacquire it.
+
+These are the in-kernel API calls that drivers can use to create and
+manipulate handles and locks. Handles can either be created and managed
+completely inside of kernel space, or shared from user space via a file
+descriptor.
+
+* struct genlock_handle *genlock_get_handle(void)
+Create a new handle.
+
+* struct genlock_handle * genlock_get_handle_fd(int fd)
+Given a valid file descriptor, return the handle associated with that
+descriptor.
+
+* void genlock_put_handle(struct genlock_handle *)
+Release a handle.
+
+* struct genlock * genlock_create_lock(struct genlock_handle *)
+Create a new lock and attach it to the handle.
+
+* struct genlock * genlock_attach_lock(struct genlock_handle *handle, int fd)
+Given a valid file descriptor, get the lock associated with it and attach it to
+the handle.
+
+* void genlock_release_lock(struct genlock_handle *)
+Release a lock attached to a handle.
+
+* int genlock_lock(struct genlock_handle *, int op, int flags, u32 timeout)
+Lock or unlock the lock attached to the handle. A zero timeout value will
+be treated just like if the GENOCK_NOBLOCK flag is passed; if the lock
+can be acquired without blocking then do so otherwise return -EAGAIN.
+Function returns -ETIMEDOUT if the timeout expired or 0 if the lock was
+acquired.
+
+* int genlock_wait(struct genloc_handle *, u32 timeout)
+Wait for a lock held by the handle to go to the unlocked state. A non-zero
+timeout value must be passed. Returns -ETIMEDOUT if the timeout expired or
+0 if the lock is in an unlocked state.
+
+Character Device
+
+Opening an instance to the /dev/genlock character device will automatically
+create a new handle. All ioctl functions with the exception of NEW and
+RELEASE use the following parameter structure:
+
+struct genlock_lock {
+ int fd; /* Returned by EXPORT, used by ATTACH */
+ int op; /* Used by LOCK */
+ int flags; /* used by LOCK */
+ u32 timeout; /* Used by LOCK and WAIT */
+}
+
+*GENLOCK_IOC_NEW
+Create a new lock and attaches it to the handle. Returns -EINVAL if the handle
+already has a lock attached (use GENLOCK_IOC_RELEASE to remove it). Returns
+-ENOMEM if the memory for the lock can not be allocated. No data is passed
+from the user for this ioctl.
+
+*GENLOCK_IOC_EXPORT
+Export the currently attached lock to a file descriptor. The file descriptor
+is returned in genlock_lock.fd.
+
+*GENLOCK_IOC_ATTACH
+Attach an exported lock file descriptor to the current handle. Return -EINVAL
+if the handle already has a lock attached (use GENLOCK_IOC_RELEASE to remove
+it). Pass the file descriptor in genlock_lock.fd.
+
+*GENLOCK_IOC_LOCK
+Lock or unlock the attached lock. Pass the desired operation in
+genlock_lock.op:
+ * GENLOCK_WRLOCK - write lock
+ * GENLOCK_RDLOCK - read lock
+ * GENLOCK_UNLOCK - unlock an existing lock
+
+Pass flags in genlock_lock.flags:
+ * GENLOCK_NOBLOCK - Do not block if the lock is already taken
+
+Pass a timeout value in milliseconds in genlock_lock.timeout.
+genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
+Returns -EINVAL if no lock is attached, -EAGAIN if the lock is taken and
+NOBLOCK is specified or if the timeout value is zero, -ETIMEDOUT if the timeout
+expires or 0 if the lock was successful.
+
+* GENLOCK_IOC_WAIT
+Wait for the lock attached to the handle to be released (i.e. goes to unlock).
+This is mainly used for a thread that needs to wait for a peer to release a
+lock on the same shared handle. A non-zero timeout value in milliseconds is
+passed in genlock_lock.timeout. Returns 0 when the lock has been released,
+-EINVAL if a zero timeout is passed, or -ETIMEDOUT if the timeout expires.
+
+* GENLOCK_IOC_RELEASE
+Use this to release an existing lock. This is useful if you wish to attach a
+different lock to the same handle. You do not need to call this under normal
+circumstances; when the handle is closed the reference to the lock is released.
+No data is passed from the user for this ioctl.
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 6c50ae9..3e754fc 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -32,6 +32,7 @@
CONFIG_ARCH_MSMCOPPER=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_DEBUG_MSMCOPPER_UART=y
CONFIG_CPU_HAS_L2_PMU=y
# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
@@ -98,6 +99,14 @@
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_MSM_PMIC is not set
@@ -133,6 +142,8 @@
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
CONFIG_KEYS=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_CBC=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 5e0cd9f..dccefd8 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -25,6 +25,7 @@
# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -421,12 +422,10 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_STACKTRACE is not set
CONFIG_DEBUG_INFO=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index d63a018..8689712 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -93,7 +93,7 @@
CONFIG_MISC_DEVICES=y
# CONFIG_ANDROID_PMEM is not set
CONFIG_NETDEVICES=y
-CONFIG_HOSTAP=m
+CONFIG_HOSTAP=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
# CONFIG_INPUT_MOUSEDEV is not set
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 7ef3a30..7dac1d4 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -211,7 +211,8 @@
for (iter = 0; iter < (mi)->nr_banks; iter++)
#define bank_pfn_start(bank) __phys_to_pfn((bank)->start)
-#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
+#define bank_pfn_end(bank) (__phys_to_pfn((bank)->start) + \
+ __phys_to_pfn((bank)->size))
#define bank_pfn_size(bank) ((bank)->size >> PAGE_SHIFT)
#define bank_phys_start(bank) (bank)->start
#define bank_phys_end(bank) ((bank)->start + (bank)->size)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 604989d..e4f88ec 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -149,7 +149,7 @@
obj-$(CONFIG_ARCH_MSM7X01A) += pm.o
obj-y += pm-boot.o
else
- obj-y += no-pm.o
+ obj-y += no-pm.o hotplug.o
endif
obj-$(CONFIG_MSM_SPM_V1) += spm.o
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index e6206dd..1f112f6 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -56,7 +56,6 @@
};
static struct src_clock clocks[NUM_SRC] = {
- [SRC_CXO].name = "cxo",
[SRC_PLL0].name = "pll0",
[SRC_PLL8].name = "pll8",
[SRC_PLL9].name = "pll9",
@@ -320,7 +319,7 @@
for (i = 0; i < NUM_SRC; i++) {
if (clocks[i].name) {
- clocks[i].clk = clk_get_sys(NULL, clocks[i].name);
+ clocks[i].clk = clk_get_sys("acpu", clocks[i].name);
BUG_ON(IS_ERR(clocks[i].clk));
}
}
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 5e2d311..c70e1b5 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -292,6 +292,17 @@
queue_rx();
return;
}
+
+ if (rx_hdr->ch_id >= BAM_DMUX_NUM_CHANNELS) {
+ pr_err("%s: dropping invalid LCID %d reserved %d cmd %d"
+ " pad %d ch %d len %d\n", __func__,
+ rx_hdr->ch_id, rx_hdr->reserved, rx_hdr->cmd,
+ rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+ dev_kfree_skb_any(rx_skb);
+ queue_rx();
+ return;
+ }
+
switch (rx_hdr->cmd) {
case BAM_MUX_HDR_CMD_DATA:
DBG_INC_READ_CNT(rx_hdr->pkt_len);
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index eddd4ed..44b78d1 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -623,11 +623,63 @@
.src_clk_rate = 24000000,
};
+#define USB_5V_EN 3
+#define PM_USB_5V_EN PM8018_GPIO_PM_TO_SYS(USB_5V_EN)
+
+static void msm_hsusb_vbus_power(bool on)
+{
+ int rc;
+ static bool vbus_is_on;
+ struct pm_gpio usb_vbus = {
+ .direction = PM_GPIO_DIR_OUT,
+ .pull = PM_GPIO_PULL_NO,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 0,
+ .vin_sel = 2,
+ .out_strength = PM_GPIO_STRENGTH_HIGH,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 0,
+ };
+
+ if (vbus_is_on == on)
+ return;
+
+ if (on) {
+ rc = pm8xxx_gpio_config(PM_USB_5V_EN, &usb_vbus);
+ if (rc) {
+ pr_err("failed to config usb_5v_en gpio\n");
+ return;
+ }
+
+ rc = gpio_request(PM_USB_5V_EN,
+ "usb_5v_en");
+ if (rc < 0) {
+ pr_err("failed to request usb_5v_en gpio\n");
+ return;
+ }
+
+ rc = gpio_direction_output(PM_USB_5V_EN, 1);
+ if (rc) {
+ pr_err("%s: unable to set_direction for gpio [%d]\n",
+ __func__, PM_USB_5V_EN);
+ goto free_usb_5v_en;
+ }
+
+ vbus_is_on = true;
+ return;
+ }
+ gpio_set_value(PM_USB_5V_EN, 0);
+free_usb_5v_en:
+ gpio_free(PM_USB_5V_EN);
+ vbus_is_on = false;
+}
+
static struct msm_otg_platform_data msm_otg_pdata = {
- .mode = USB_PERIPHERAL,
- .otg_control = OTG_NO_CONTROL,
+ .mode = USB_OTG,
+ .otg_control = OTG_PHY_CONTROL,
.phy_type = SNPS_28NM_INTEGRATED_PHY,
- .pclk_src_name = "dfab_usb_hs_clk",
+ .pclk_src_name = "dfab_usb_hs_clk",
+ .vbus_power = msm_hsusb_vbus_power,
};
static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
@@ -662,6 +714,7 @@
&msm_device_smd,
&msm_device_otg,
&msm_device_gadget_peripheral,
+ &msm_device_hsusb_host,
&android_usb_device,
&msm9615_device_uart_gsbi4,
&msm9615_device_ext_2p95v_vreg,
diff --git a/arch/arm/mach-msm/board-apq8064.c b/arch/arm/mach-msm/board-apq8064.c
index b131989..00886c6 100644
--- a/arch/arm/mach-msm/board-apq8064.c
+++ b/arch/arm/mach-msm/board-apq8064.c
@@ -18,6 +18,8 @@
#include <linux/slimbus/slimbus.h>
#include <linux/msm_ssbi.h>
#include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -37,6 +39,7 @@
#include <mach/msm_memtypes.h>
#include <linux/bootmem.h>
#include <asm/setup.h>
+#include <mach/dma.h>
#include "msm_watchdog.h"
#include "board-apq8064.h"
@@ -429,12 +432,14 @@
{
if ((machine_is_apq8064_rumi3()) || machine_is_apq8064_sim()) {
if (apq8064_sdc1_pdata) {
- apq8064_sdc1_pdata->disable_bam = true;
+ if (machine_is_apq8064_sim())
+ apq8064_sdc1_pdata->disable_bam = true;
apq8064_sdc1_pdata->disable_runtime_pm = true;
apq8064_sdc1_pdata->disable_cmd23 = true;
}
if (apq8064_sdc3_pdata) {
- apq8064_sdc3_pdata->disable_bam = true;
+ if (machine_is_apq8064_sim())
+ apq8064_sdc3_pdata->disable_bam = true;
apq8064_sdc3_pdata->disable_runtime_pm = true;
apq8064_sdc3_pdata->disable_cmd23 = true;
}
@@ -443,6 +448,118 @@
apq8064_add_sdcc(3, apq8064_sdc3_pdata);
}
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE 0x10000
+#define QCE_0_BASE 0x11000000
+
+#define QCE_HW_KEY_SUPPORT 0
+#define QCE_SHA_HMAC_SUPPORT 1
+#define QCE_SHARE_CE_RESOURCE 3
+#define QCE_CE_SHARED 0
+
+static struct resource qcrypto_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV8064_CE_IN_CHAN,
+ .end = DMOV8064_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV8064_CE_IN_CRCI,
+ .end = DMOV8064_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV8064_CE_OUT_CRCI,
+ .end = DMOV8064_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource qcedev_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV8064_CE_IN_CHAN,
+ .end = DMOV8064_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV8064_CE_IN_CRCI,
+ .end = DMOV8064_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV8064_CE_OUT_CRCI,
+ .end = DMOV8064_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcrypto_device = {
+ .name = "qcrypto",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcrypto_resources),
+ .resource = qcrypto_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcrypto_ce_hw_suppport,
+ },
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+ .name = "qce",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcedev_resources),
+ .resource = qcedev_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcedev_ce_hw_suppport,
+ },
+};
+#endif
+
+
#define MSM_SHARED_RAM_PHYS 0x80000000
static void __init apq8064_map_io(void)
{
@@ -526,6 +643,15 @@
&msm8064_device_saw_regulator_core1,
&msm8064_device_saw_regulator_core2,
&msm8064_device_saw_regulator_core3,
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+ &qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+ &qcedev_device,
+#endif
};
static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 9813715..fece76d 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -744,6 +744,7 @@
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
};
static struct gpiomux_setting hsic_hub_act_cfg = {
@@ -4288,7 +4289,7 @@
.update_time = 60000,
.max_voltage = 4200,
.min_voltage = 3200,
- .resume_voltage = 4100,
+ .resume_voltage_delta = 100,
.term_current = 100,
.cool_temp = 10,
.warm_temp = 40,
@@ -4378,6 +4379,10 @@
.num_configs = ARRAY_SIZE(pm8921_led_configs),
};
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+ .r_sense = 10,
+};
+
static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
.irq_pdata = &pm8xxx_irq_pdata,
.gpio_pdata = &pm8xxx_gpio_pdata,
@@ -4391,6 +4396,7 @@
.bms_pdata = &pm8921_bms_pdata,
.adc_pdata = &pm8921_adc_pdata,
.leds_pdata = &pm8xxx_leds_pdata,
+ .ccadc_pdata = &pm8xxx_ccadc_pdata,
};
static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 95b69e6..85de532 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -26,6 +26,7 @@
#include <linux/power_supply.h>
#include <linux/input/rmi_platformdata.h>
#include <linux/input/rmi_i2c.h>
+#include <linux/regulator/consumer.h>
#include <asm/mach/mmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -52,6 +53,7 @@
#include "pm.h"
#include "timer.h"
#include "pm-boot.h"
+#include "board-msm7x27a-regulator.h"
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x5B000
@@ -2505,10 +2507,27 @@
},
};
+static struct platform_device msm_proccomm_regulator_dev = {
+ .name = PROCCOMM_REGULATOR_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &msm7x27a_proccomm_regulator_data
+ }
+};
+
+static void __init msm7627a_init_regulators(void)
+{
+ int rc = platform_device_register(&msm_proccomm_regulator_dev);
+ if (rc)
+ pr_err("%s: could not register regulator device: %d\n",
+ __func__, rc);
+}
+
#define UART1DM_RX_GPIO 45
static void __init msm_qrd1_init(void)
{
msm7x2x_misc_init();
+ msm7627a_init_regulators();
msm_device_i2c_init();
msm7627a_init_mmc();
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index aaf6c83..c16c2ee 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5158,8 +5158,14 @@
CLK_LOOKUP("usb_fs_sys_clk", usb_fs1_sys_clk.c, NULL),
CLK_LOOKUP("iface_clk", ce1_p_clk.c, NULL),
CLK_LOOKUP("core_clk", ce1_core_clk.c, NULL),
- CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, NULL),
+ CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, NULL),
CLK_LOOKUP("cfg_clk", sata_phy_cfg_clk.c, NULL),
+ CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qce.0"),
+ CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qcrypto.0"),
+ CLK_LOOKUP("core_clk", ce3_core_clk.c, "qce.0"),
+ CLK_LOOKUP("core_clk", ce3_core_clk.c, "qcrypto.0"),
+ CLK_LOOKUP("ce3_core_src_clk", ce3_src_clk.c, "qce.0"),
+ CLK_LOOKUP("ce3_core_src_clk", ce3_src_clk.c, "qcrypto.0"),
CLK_LOOKUP("dma_bam_pclk", dma_bam_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, NULL),
@@ -5178,9 +5184,6 @@
CLK_LOOKUP("iface_clk", sdc3_p_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", sdc4_p_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("iface_clk", pcie_p_clk.c, NULL),
- CLK_LOOKUP("core_src_clk", ce3_src_clk.c, NULL),
- CLK_LOOKUP("core_clk", ce3_core_clk.c, NULL),
- CLK_LOOKUP("iface_clk", ce3_p_clk.c, NULL),
CLK_LOOKUP("core_clk", adm0_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", adm0_p_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", pmic_arb0_p_clk.c, NULL),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 7e163df..78da29c 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -249,19 +249,83 @@
},
};
+static DEFINE_SPINLOCK(soft_vote_lock);
+
+static int pll_acpu_vote_clk_enable(struct clk *clk)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+ spin_lock_irqsave(&soft_vote_lock, flags);
+
+ if (!*pll->soft_vote)
+ ret = pll_vote_clk_enable(clk);
+ if (ret == 0)
+ *pll->soft_vote |= (pll->soft_vote_mask);
+
+ spin_unlock_irqrestore(&soft_vote_lock, flags);
+ return ret;
+}
+
+static void pll_acpu_vote_clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+ struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+ spin_lock_irqsave(&soft_vote_lock, flags);
+
+ *pll->soft_vote &= ~(pll->soft_vote_mask);
+ if (!*pll->soft_vote)
+ pll_vote_clk_disable(clk);
+
+ spin_unlock_irqrestore(&soft_vote_lock, flags);
+}
+
+static struct clk_ops clk_ops_pll_acpu_vote = {
+ .enable = pll_acpu_vote_clk_enable,
+ .disable = pll_acpu_vote_clk_disable,
+ .auto_off = pll_acpu_vote_clk_disable,
+ .is_enabled = pll_vote_clk_is_enabled,
+ .get_rate = pll_vote_clk_get_rate,
+ .get_parent = pll_vote_clk_get_parent,
+ .is_local = local_clk_is_local,
+};
+
+#define PLL_SOFT_VOTE_PRIMARY BIT(0)
+#define PLL_SOFT_VOTE_ACPU BIT(1)
+
+static unsigned int soft_vote_pll0;
+
static struct pll_vote_clk pll0_clk = {
.rate = 276000000,
.en_reg = BB_PLL_ENA_SC0_REG,
.en_mask = BIT(0),
.status_reg = BB_PLL0_STATUS_REG,
.parent = &cxo_clk.c,
+ .soft_vote = &soft_vote_pll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
.c = {
.dbg_name = "pll0_clk",
- .ops = &clk_ops_pll_vote,
+ .ops = &clk_ops_pll_acpu_vote,
CLK_INIT(pll0_clk.c),
},
};
+static struct pll_vote_clk pll0_acpu_clk = {
+ .rate = 276000000,
+ .en_reg = BB_PLL_ENA_SC0_REG,
+ .en_mask = BIT(0),
+ .status_reg = BB_PLL0_STATUS_REG,
+ .soft_vote = &soft_vote_pll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .c = {
+ .dbg_name = "pll0_acpu_clk",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(pll0_acpu_clk.c),
+ },
+};
+
static struct pll_vote_clk pll4_clk = {
.rate = 393216000,
.en_reg = BB_PLL_ENA_SC0_REG,
@@ -275,32 +339,68 @@
},
};
+static unsigned int soft_vote_pll8;
+
static struct pll_vote_clk pll8_clk = {
.rate = 384000000,
.en_reg = BB_PLL_ENA_SC0_REG,
.en_mask = BIT(8),
.status_reg = BB_PLL8_STATUS_REG,
.parent = &cxo_clk.c,
+ .soft_vote = &soft_vote_pll8,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
.c = {
.dbg_name = "pll8_clk",
- .ops = &clk_ops_pll_vote,
+ .ops = &clk_ops_pll_acpu_vote,
CLK_INIT(pll8_clk.c),
},
};
+static struct pll_vote_clk pll8_acpu_clk = {
+ .rate = 384000000,
+ .en_reg = BB_PLL_ENA_SC0_REG,
+ .en_mask = BIT(8),
+ .status_reg = BB_PLL8_STATUS_REG,
+ .soft_vote = &soft_vote_pll8,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .c = {
+ .dbg_name = "pll8_acpu_clk",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(pll8_acpu_clk.c),
+ },
+};
+
+static unsigned int soft_vote_pll9;
+
static struct pll_vote_clk pll9_clk = {
.rate = 440000000,
.en_reg = BB_PLL_ENA_SC0_REG,
.en_mask = BIT(9),
.status_reg = SC_PLL0_STATUS_REG,
.parent = &cxo_clk.c,
+ .soft_vote = &soft_vote_pll9,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
.c = {
.dbg_name = "pll9_clk",
- .ops = &clk_ops_pll_vote,
+ .ops = &clk_ops_pll_acpu_vote,
CLK_INIT(pll9_clk.c),
},
};
+static struct pll_vote_clk pll9_acpu_clk = {
+ .rate = 440000000,
+ .en_reg = BB_PLL_ENA_SC0_REG,
+ .en_mask = BIT(9),
+ .soft_vote = &soft_vote_pll9,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .status_reg = SC_PLL0_STATUS_REG,
+ .c = {
+ .dbg_name = "pll9_acpu_clk",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(pll9_acpu_clk.c),
+ },
+};
+
static struct pll_vote_clk pll14_clk = {
.rate = 480000000,
.en_reg = BB_PLL_ENA_SC0_REG,
@@ -1557,6 +1657,11 @@
CLK_LOOKUP("pll8", pll8_clk.c, NULL),
CLK_LOOKUP("pll9", pll9_clk.c, NULL),
CLK_LOOKUP("pll14", pll14_clk.c, NULL),
+
+ CLK_LOOKUP("pll0", pll0_acpu_clk.c, "acpu"),
+ CLK_LOOKUP("pll8", pll8_acpu_clk.c, "acpu"),
+ CLK_LOOKUP("pll9", pll9_acpu_clk.c, "acpu"),
+
CLK_LOOKUP("measure", measure_clk.c, "debug"),
CLK_LOOKUP("cfpb_clk", cfpb_clk.c, NULL),
@@ -1772,6 +1877,19 @@
/* Enable PLL4 source on the LPASS Primary PLL Mux */
regval = readl_relaxed(LCC_PRI_PLL_CLK_CTL_REG);
writel_relaxed(regval | BIT(0), LCC_PRI_PLL_CLK_CTL_REG);
+
+ /* Disable hardware clock gating on certain clocks */
+ regval = readl_relaxed(USB_HSIC_HCLK_CTL_REG);
+ regval &= ~BIT(6);
+ writel_relaxed(regval, USB_HSIC_HCLK_CTL_REG);
+
+ regval = readl_relaxed(CE1_CORE_CLK_CTL_REG);
+ regval &= ~BIT(6);
+ writel_relaxed(regval, CE1_CORE_CLK_CTL_REG);
+
+ regval = readl_relaxed(USB_HS1_HCLK_CTL_REG);
+ regval &= ~BIT(6);
+ writel_relaxed(regval, USB_HS1_HCLK_CTL_REG);
}
/* Local clock driver initialization. */
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index c1cfb55..2391f84 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -641,7 +641,7 @@
return 1;
}
-static int pll_vote_clk_enable(struct clk *clk)
+int pll_vote_clk_enable(struct clk *clk)
{
u32 ena;
unsigned long flags;
@@ -660,7 +660,7 @@
return 0;
}
-static void pll_vote_clk_disable(struct clk *clk)
+void pll_vote_clk_disable(struct clk *clk)
{
u32 ena;
unsigned long flags;
@@ -673,19 +673,19 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
-static unsigned long pll_vote_clk_get_rate(struct clk *clk)
+unsigned long pll_vote_clk_get_rate(struct clk *clk)
{
struct pll_vote_clk *pll = to_pll_vote_clk(clk);
return pll->rate;
}
-static struct clk *pll_vote_clk_get_parent(struct clk *clk)
+struct clk *pll_vote_clk_get_parent(struct clk *clk)
{
struct pll_vote_clk *pll = to_pll_vote_clk(clk);
return pll->parent;
}
-static int pll_vote_clk_is_enabled(struct clk *clk)
+int pll_vote_clk_is_enabled(struct clk *clk)
{
struct pll_vote_clk *pll = to_pll_vote_clk(clk);
return !!(readl_relaxed(pll->status_reg) & BIT(16));
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 16a9955..2107567 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -177,6 +177,8 @@
/**
* struct pll_vote_clk - phase locked loop (HW voteable)
* @rate: output rate
+ * @soft_vote: soft voting variable for multiple PLL software instances
+ * @soft_vote_mask: soft voting mask for multiple PLL software instances
* @en_reg: enable register
* @en_mask: ORed with @en_reg to enable the clock
* @status_reg: status register
@@ -186,6 +188,8 @@
struct pll_vote_clk {
unsigned long rate;
+ u32 *soft_vote;
+ const u32 soft_vote_mask;
void __iomem *const en_reg;
const u32 en_mask;
@@ -288,6 +292,15 @@
bool local_clk_is_local(struct clk *clk);
/*
+ * PLL vote clock APIs
+ */
+int pll_vote_clk_enable(struct clk *clk);
+void pll_vote_clk_disable(struct clk *clk);
+unsigned long pll_vote_clk_get_rate(struct clk *clk);
+struct clk *pll_vote_clk_get_parent(struct clk *clk);
+int pll_vote_clk_is_enabled(struct clk *clk);
+
+/*
* Generic set-rate implementations
*/
void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 9b8d5ac..afc2649 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -761,6 +761,12 @@
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
CLK_DUMMY("mem_clk", EBI1_ADM_CLK, "msm_dmov", 0),
+ CLK_DUMMY("ce3_core_src_clk", CE3_SRC_CLK, "qce.0", OFF),
+ CLK_DUMMY("ce3_core_src_clk", CE3_SRC_CLK, "qcrypto.0", OFF),
+ CLK_DUMMY("core_clk", CE3_CORE_CLK, "qce.0", OFF),
+ CLK_DUMMY("core_clk", CE3_CORE_CLK, "qcrypto.0", OFF),
+ CLK_DUMMY("iface_clk", CE3_P_CLK, "qce0.0", OFF),
+ CLK_DUMMY("iface_clk", CE3_P_CLK, "qcrypto.0", OFF),
};
struct clock_init_data apq8064_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 47e33d0..012eb85 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -145,6 +145,31 @@
},
};
+static struct resource resources_hsusb_host[] = {
+ {
+ .start = MSM9615_HSUSB_PHYS,
+ .end = MSM9615_HSUSB_PHYS + MSM9615_HSUSB_PHYS - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = USB1_HS_IRQ,
+ .end = USB1_HS_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_hsusb_host = {
+ .name = "msm_hsusb_host",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_hsusb_host),
+ .resource = resources_hsusb_host,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
static struct resource resources_uart_gsbi4[] = {
{
.start = GSBI4_UARTDM_IRQ,
@@ -668,53 +693,47 @@
};
static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] = {
- [1] = MSM_GPIO_TO_INT(46),
- [2] = MSM_GPIO_TO_INT(150),
- [4] = MSM_GPIO_TO_INT(103),
- [5] = MSM_GPIO_TO_INT(104),
- [6] = MSM_GPIO_TO_INT(105),
- [7] = MSM_GPIO_TO_INT(106),
- [8] = MSM_GPIO_TO_INT(107),
- [9] = MSM_GPIO_TO_INT(7),
- [10] = MSM_GPIO_TO_INT(11),
- [11] = MSM_GPIO_TO_INT(15),
- [12] = MSM_GPIO_TO_INT(19),
- [13] = MSM_GPIO_TO_INT(23),
- [14] = MSM_GPIO_TO_INT(27),
- [15] = MSM_GPIO_TO_INT(31),
- [16] = MSM_GPIO_TO_INT(35),
- [19] = MSM_GPIO_TO_INT(90),
- [20] = MSM_GPIO_TO_INT(92),
- [23] = MSM_GPIO_TO_INT(85),
- [24] = MSM_GPIO_TO_INT(83),
+ [4] = MSM_GPIO_TO_INT(30),
+ [5] = MSM_GPIO_TO_INT(59),
+ [6] = MSM_GPIO_TO_INT(81),
+ [7] = MSM_GPIO_TO_INT(87),
+ [8] = MSM_GPIO_TO_INT(86),
+ [9] = MSM_GPIO_TO_INT(2),
+ [10] = MSM_GPIO_TO_INT(6),
+ [11] = MSM_GPIO_TO_INT(10),
+ [12] = MSM_GPIO_TO_INT(14),
+ [13] = MSM_GPIO_TO_INT(18),
+ [14] = MSM_GPIO_TO_INT(7),
+ [15] = MSM_GPIO_TO_INT(11),
+ [16] = MSM_GPIO_TO_INT(15),
+ [19] = MSM_GPIO_TO_INT(26),
+ [20] = MSM_GPIO_TO_INT(28),
+ [23] = MSM_GPIO_TO_INT(19),
+ [24] = MSM_GPIO_TO_INT(23),
[25] = USB1_HS_IRQ,
- /*[27] = HDMI_IRQ,*/
- [29] = MSM_GPIO_TO_INT(10),
- [30] = MSM_GPIO_TO_INT(102),
- [31] = MSM_GPIO_TO_INT(81),
- [32] = MSM_GPIO_TO_INT(78),
- [33] = MSM_GPIO_TO_INT(94),
- [34] = MSM_GPIO_TO_INT(72),
- [35] = MSM_GPIO_TO_INT(39),
- [36] = MSM_GPIO_TO_INT(43),
- [37] = MSM_GPIO_TO_INT(61),
- [38] = MSM_GPIO_TO_INT(50),
- [39] = MSM_GPIO_TO_INT(42),
- [41] = MSM_GPIO_TO_INT(62),
- [42] = MSM_GPIO_TO_INT(76),
- [43] = MSM_GPIO_TO_INT(75),
- [44] = MSM_GPIO_TO_INT(70),
- [45] = MSM_GPIO_TO_INT(69),
- [46] = MSM_GPIO_TO_INT(67),
- [47] = MSM_GPIO_TO_INT(65),
- [48] = MSM_GPIO_TO_INT(58),
- [49] = MSM_GPIO_TO_INT(54),
- [50] = MSM_GPIO_TO_INT(52),
- [51] = MSM_GPIO_TO_INT(49),
- [52] = MSM_GPIO_TO_INT(40),
- [53] = MSM_GPIO_TO_INT(37),
- [54] = MSM_GPIO_TO_INT(24),
- [55] = MSM_GPIO_TO_INT(14),
+ [26] = MSM_GPIO_TO_INT(3),
+ [27] = MSM_GPIO_TO_INT(68),
+ [29] = MSM_GPIO_TO_INT(78),
+ [31] = MSM_GPIO_TO_INT(0),
+ [32] = MSM_GPIO_TO_INT(4),
+ [33] = MSM_GPIO_TO_INT(22),
+ [34] = MSM_GPIO_TO_INT(17),
+ [37] = MSM_GPIO_TO_INT(20),
+ [39] = MSM_GPIO_TO_INT(84),
+ [42] = MSM_GPIO_TO_INT(24),
+ [43] = MSM_GPIO_TO_INT(79),
+ [44] = MSM_GPIO_TO_INT(80),
+ [45] = MSM_GPIO_TO_INT(82),
+ [46] = MSM_GPIO_TO_INT(85),
+ [47] = MSM_GPIO_TO_INT(45),
+ [48] = MSM_GPIO_TO_INT(50),
+ [49] = MSM_GPIO_TO_INT(51),
+ [50] = MSM_GPIO_TO_INT(69),
+ [51] = MSM_GPIO_TO_INT(77),
+ [52] = MSM_GPIO_TO_INT(1),
+ [53] = MSM_GPIO_TO_INT(5),
+ [54] = MSM_GPIO_TO_INT(40),
+ [55] = MSM_GPIO_TO_INT(27),
};
static uint16_t msm_mpm_bypassed_apps_irqs[] = {
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 5a31f70..e8aa38e 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -12,6 +12,7 @@
#include <asm/cacheflush.h>
+#ifdef CONFIG_SMP
extern volatile int pen_release;
static inline void cpu_enter_lowpower(void)
@@ -55,6 +56,7 @@
pr_debug("CPU%u: spurious wakeup call\n", cpu);
}
}
+#endif
int platform_cpu_kill(unsigned int cpu)
{
@@ -68,6 +70,7 @@
*/
void platform_cpu_die(unsigned int cpu)
{
+#ifdef CONFIG_SMP
/*
* we're ready for shutdown now, so do it
*/
@@ -79,6 +82,7 @@
* coherency, and then restore interrupts
*/
cpu_leave_lowpower();
+#endif
}
int platform_cpu_disable(unsigned int cpu)
diff --git a/arch/arm/mach-msm/include/mach/barriers.h b/arch/arm/mach-msm/include/mach/barriers.h
index 919186b..2d4792c 100644
--- a/arch/arm/mach-msm/include/mach/barriers.h
+++ b/arch/arm/mach-msm/include/mach/barriers.h
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*
*/
+#include <mach/memory.h>
+
#define mb() do \
{ \
dsb();\
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 1474fcb..3cb79b7 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -245,6 +245,13 @@
#define DMOV_HSUART2_RX_CRCI 15
#endif
+/* channels for APQ8064 */
+#define DMOV8064_CE_IN_CHAN 2
+#define DMOV8064_CE_IN_CRCI 14
+
+#define DMOV8064_CE_OUT_CHAN 3
+#define DMOV8064_CE_OUT_CRCI 15
+
/* no client rate control ifc (eg, ram) */
#define DMOV_NONE_CRCI 0
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index e34abb1..d6cdbe7 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -25,16 +25,3 @@
void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-
-int platform_cpu_disable(unsigned int cpu)
-{
- return -ENOSYS;
-}
-
-int platform_cpu_kill(unsigned int cpu)
-{
- return -ENOSYS;
-}
-
-void platform_cpu_die(unsigned int cpu)
-{ }
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 65a2c54..f9445d8 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -661,6 +661,7 @@
q6asm_audio_client_free(audio->ac);
mutex_unlock(&audio->lock);
kfree(audio->enc_cfg);
+ kfree(audio->codec_cfg);
kfree(audio);
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
index 16258eb..f978554 100644
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -43,7 +43,7 @@
struct lpa_if {
struct mutex lock;
struct msm_audio_config cfg;
- struct audio_buffer audio_buf[2];
+ struct audio_buffer audio_buf[6];
int cpu_buf; /* next buffer the CPU will touch */
int dma_buf; /* next buffer the DMA will touch */
u8 *buffer;
@@ -52,6 +52,7 @@
wait_queue_head_t wait;
u32 config;
u32 dma_period_sz;
+ unsigned int num_periods;
};
static struct lpa_if *lpa_if_ptr;
@@ -85,9 +86,11 @@
pr_debug("dma_buf %d used %d\n", lpa_if->dma_buf,
lpa_if->audio_buf[lpa_if->dma_buf].used);
+ lpa_if->dma_buf++;
+ lpa_if->dma_buf = lpa_if->dma_buf % lpa_if->cfg.buffer_count;
- lpa_if->dma_buf ^= 1;
-
+ if (lpa_if->dma_buf == lpa_if->cpu_buf)
+ pr_err("Err:both dma_buf and cpu_buf are on same index\n");
wake_up(&lpa_if->wait);
}
return IRQ_HANDLED;
@@ -114,7 +117,7 @@
dma_params.src_start = lpa_if->buffer_phys;
dma_params.buffer = lpa_if->buffer;
- dma_params.buffer_size = lpa_if->dma_period_sz * 2;
+ dma_params.buffer_size = lpa_if->dma_period_sz * lpa_if->num_periods;
dma_params.period_size = lpa_if->dma_period_sz;
dma_params.channels = 2;
@@ -143,7 +146,7 @@
{
struct lpa_if *lpa_if = file->private_data;
int rc = 0;
-
+ unsigned int i;
pr_debug("cmd %u\n", cmd);
mutex_lock(&lpa_if->lock);
@@ -188,25 +191,28 @@
pr_debug("%s:failed to copy from user\n", __func__);
rc = -EFAULT;
}
- if ((lpa_if->dma_period_sz * 2) > DMA_ALLOC_BUF_SZ) {
+ if ((lpa_if->dma_period_sz * lpa_if->num_periods) >
+ DMA_ALLOC_BUF_SZ) {
pr_err("Dma buffer size greater than allocated size\n");
return -EINVAL;
}
pr_debug("Dma_period_sz %d\n", lpa_if->dma_period_sz);
- lpa_if->cfg.buffer_count = 2;
- lpa_if->cfg.buffer_size = lpa_if->dma_period_sz * 2;
+ if (lpa_if->dma_period_sz < (2 * SZ_4K))
+ lpa_if->num_periods = 6;
+ pr_debug("No. of Periods %d\n", lpa_if->num_periods);
- lpa_if->audio_buf[0].phys = lpa_if->buffer_phys;
- lpa_if->audio_buf[0].data = lpa_if->buffer;
- lpa_if->audio_buf[0].size = lpa_if->dma_period_sz;
- lpa_if->audio_buf[0].used = 0;
+ lpa_if->cfg.buffer_count = lpa_if->num_periods;
+ lpa_if->cfg.buffer_size = lpa_if->dma_period_sz *
+ lpa_if->num_periods;
- lpa_if->audio_buf[1].phys =
- lpa_if->buffer_phys + lpa_if->dma_period_sz;
- lpa_if->audio_buf[1].data =
- lpa_if->buffer + lpa_if->dma_period_sz;
- lpa_if->audio_buf[1].size = lpa_if->dma_period_sz;
- lpa_if->audio_buf[1].used = 0;
+ for (i = 0; i < lpa_if->cfg.buffer_count; i++) {
+ lpa_if->audio_buf[i].phys =
+ lpa_if->buffer_phys + i * lpa_if->dma_period_sz;
+ lpa_if->audio_buf[i].data =
+ lpa_if->buffer + i * lpa_if->dma_period_sz;
+ lpa_if->audio_buf[i].size = lpa_if->dma_period_sz;
+ lpa_if->audio_buf[i].used = 0;
+ }
break;
default:
pr_err("UnKnown Ioctl\n");
@@ -225,8 +231,9 @@
file->private_data = lpa_if_ptr;
dma_buf_index = 0;
- lpa_if_ptr->cpu_buf = 0;
+ lpa_if_ptr->cpu_buf = 2;
lpa_if_ptr->dma_buf = 0;
+ lpa_if_ptr->num_periods = 4;
core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
mb();
@@ -234,6 +241,17 @@
return 0;
}
+static inline int rt_policy(int policy)
+{
+ if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+ return 1;
+ return 0;
+}
+
+static inline int task_has_rt_policy(struct task_struct *p)
+{
+ return rt_policy(p->policy);
+}
static ssize_t lpa_if_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
@@ -241,7 +259,19 @@
struct audio_buffer *ab;
const char __user *start = buf;
int xfer, rc;
+ struct sched_param s = { .sched_priority = 1 };
+ int old_prio = current->rt_priority;
+ int old_policy = current->policy;
+ int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
+ /* just for this write, set us real-time */
+ if (!task_has_rt_policy(current)) {
+ struct cred *new = prepare_creds();
+ cap_raise(new->cap_effective, CAP_SYS_NICE);
+ commit_creds(new);
+ if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
+ pr_err("sched_setscheduler failed\n");
+ }
mutex_lock(&lpa_if->lock);
if (dma_buf_index < 2) {
@@ -299,12 +329,23 @@
pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
xfer, ab->size, ab->used, lpa_if->cpu_buf);
-
- lpa_if->cpu_buf ^= 1;
+ lpa_if->cpu_buf++;
+ lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count;
}
rc = buf - start;
end:
mutex_unlock(&lpa_if->lock);
+ /* restore old scheduling policy */
+ if (!rt_policy(old_policy)) {
+ struct sched_param v = { .sched_priority = old_prio };
+ if ((sched_setscheduler(current, old_policy, &v)) < 0)
+ pr_err("sched_setscheduler failed\n");
+ if (likely(!cap_nice)) {
+ struct cred *new = prepare_creds();
+ cap_lower(new->cap_effective, CAP_SYS_NICE);
+ commit_creds(new);
+ }
+ }
return rc;
}
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 7c7a822..4744f1f 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -63,7 +63,6 @@
int i;
int blocking_write;
- int needed_space;
int is_open;
unsigned ch_size;
uint open_modem_wait;
@@ -155,7 +154,7 @@
smd_pkt_devp->is_open = 0;
wake_up(&smd_pkt_devp->ch_read_wait_queue);
- wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+ wake_up(&smd_pkt_devp->ch_write_wait_queue);
wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
}
@@ -305,7 +304,7 @@
size_t count,
loff_t *ppos)
{
- int r = 0;
+ int r = 0, bytes_written;
struct smd_pkt_dev *smd_pkt_devp;
DEFINE_WAIT(write_wait);
@@ -317,84 +316,56 @@
if (!smd_pkt_devp || !smd_pkt_devp->ch)
return -EINVAL;
- if (count > smd_pkt_devp->ch_size)
- return -EINVAL;
-
if (smd_pkt_devp->do_reset_notification) {
/* notify client that a reset occurred */
return notify_reset(smd_pkt_devp);
}
- if (smd_pkt_devp->blocking_write) {
- for (;;) {
- mutex_lock(&smd_pkt_devp->tx_lock);
- if (smd_pkt_devp->has_reset) {
- smd_disable_read_intr(smd_pkt_devp->ch);
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return notify_reset(smd_pkt_devp);
- }
- if (signal_pending(current)) {
- smd_disable_read_intr(smd_pkt_devp->ch);
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return -ERESTARTSYS;
- }
-
- prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
- &write_wait, TASK_INTERRUPTIBLE);
- smd_enable_read_intr(smd_pkt_devp->ch);
- if (smd_write_avail(smd_pkt_devp->ch) < count) {
- if (!smd_pkt_devp->needed_space ||
- count < smd_pkt_devp->needed_space)
- smd_pkt_devp->needed_space = count;
- mutex_unlock(&smd_pkt_devp->tx_lock);
- schedule();
- } else
- break;
- }
- finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
- smd_disable_read_intr(smd_pkt_devp->ch);
- if (smd_pkt_devp->has_reset) {
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return notify_reset(smd_pkt_devp);
- }
- if (signal_pending(current)) {
- mutex_unlock(&smd_pkt_devp->tx_lock);
- return -ERESTARTSYS;
- }
- } else {
- if (smd_pkt_devp->has_reset)
- return notify_reset(smd_pkt_devp);
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- mutex_lock(&smd_pkt_devp->tx_lock);
+ mutex_lock(&smd_pkt_devp->tx_lock);
+ if (!smd_pkt_devp->blocking_write) {
if (smd_write_avail(smd_pkt_devp->ch) < count) {
D(KERN_ERR "%s: Not enough space to write\n",
- __func__);
+ __func__);
mutex_unlock(&smd_pkt_devp->tx_lock);
return -ENOMEM;
}
}
- D_DUMP_BUFFER("write: ", count, buf);
-
- smd_pkt_devp->needed_space = 0;
-
- r = smd_write_user_buffer(smd_pkt_devp->ch, buf, count);
- if (r != count) {
+ r = smd_write_start(smd_pkt_devp->ch, count);
+ if (r < 0) {
mutex_unlock(&smd_pkt_devp->tx_lock);
- if (smd_pkt_devp->has_reset)
- return notify_reset(smd_pkt_devp);
-
- printk(KERN_ERR "ERROR:%s:%i:%s: "
- "smd_write(ch,buf,count = %i) ret %i.\n",
- __FILE__,
- __LINE__,
- __func__,
- count,
- r);
+ pr_err("%s: Error %d @ smd_write_start\n", __func__, r);
return r;
}
+
+ bytes_written = 0;
+ do {
+ prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
+ &write_wait, TASK_UNINTERRUPTIBLE);
+ if (!smd_write_avail(smd_pkt_devp->ch) &&
+ !smd_pkt_devp->has_reset) {
+ smd_enable_read_intr(smd_pkt_devp->ch);
+ schedule();
+ }
+ finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
+ smd_disable_read_intr(smd_pkt_devp->ch);
+
+ if (smd_pkt_devp->has_reset) {
+ mutex_unlock(&smd_pkt_devp->tx_lock);
+ return notify_reset(smd_pkt_devp);
+ } else {
+ r = smd_write_segment(smd_pkt_devp->ch,
+ (void *)(buf + bytes_written),
+ (count - bytes_written), 1);
+ if (r < 0) {
+ mutex_unlock(&smd_pkt_devp->tx_lock);
+ if (smd_pkt_devp->has_reset)
+ return notify_reset(smd_pkt_devp);
+ }
+ bytes_written += r;
+ }
+ } while (bytes_written != count);
+ smd_write_end(smd_pkt_devp->ch);
mutex_unlock(&smd_pkt_devp->tx_lock);
D(KERN_ERR "%s: just wrote %i bytes\n",
@@ -451,11 +422,11 @@
return;
sz = smd_write_avail(smd_pkt_devp->ch);
- if (sz >= smd_pkt_devp->needed_space) {
+ if (sz) {
D(KERN_ERR "%s: %d bytes Write Space available\n",
__func__, sz);
smd_disable_read_intr(smd_pkt_devp->ch);
- wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+ wake_up(&smd_pkt_devp->ch_write_wait_queue);
}
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 96a4563..c4bc76c 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -31,6 +31,7 @@
HW_PLATFORM_FLUID = 3,
HW_PLATFORM_SVLTE_FFA = 4,
HW_PLATFORM_SVLTE_SURF = 5,
+ HW_PLATFORM_LIQUID = 9,
/* Dragonboard platform id is assigned as 10 in CDT */
HW_PLATFORM_DRAGON = 10,
HW_PLATFORM_INVALID
@@ -41,6 +42,7 @@
[HW_PLATFORM_SURF] = "Surf",
[HW_PLATFORM_FFA] = "FFA",
[HW_PLATFORM_FLUID] = "Fluid",
+ [HW_PLATFORM_LIQUID] = "Liquid",
[HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
[HW_PLATFORM_DRAGON] = "Dragon"
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 2ef5c61..18b7334 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -21,6 +21,7 @@
#include <mach/scm.h>
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
+#include <mach/peripheral-loader.h>
#include "smd_private.h"
#include "ramdump.h"
@@ -35,10 +36,14 @@
static void *riva_ramdump_dev;
static int riva_crash;
static int ss_restart_inprogress;
+static int enable_riva_ssr;
static void riva_smsm_cb_fn(struct work_struct *work)
{
- panic(MODULE_NAME ": SMSM reset request received from Riva");
+ if (!enable_riva_ssr)
+ panic(MODULE_NAME ": SMSM reset request received from Riva");
+ else
+ subsystem_restart("riva");
}
static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
@@ -74,13 +79,13 @@
/* Subsystem handlers */
static int riva_shutdown(const struct subsys_data *subsys)
{
- /* TODO for phase 3 */
+ pil_force_shutdown("wcnss");
return 0;
}
static int riva_powerup(const struct subsys_data *subsys)
{
- /* TODO for phase 3 */
+ pil_force_boot("wcnss");
return 0;
}
@@ -118,6 +123,23 @@
.crash_shutdown = riva_crash_shutdown
};
+static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_int(val, kp);
+ if (ret)
+ return ret;
+
+ if (enable_riva_ssr)
+ pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
+
+ return 0;
+}
+
+module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
+ &enable_riva_ssr, S_IRUGO | S_IWUSR);
+
static int __init riva_restart_init(void)
{
return ssr_register_subsystem(&riva_8960);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 2c6957d..baf3170 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1131,3 +1131,4 @@
msm7625a_surf MACH_MSM7625A_SURF MSM7625A_SURF 3772
msm8627_cdp MACH_MSM8627_CDP MSM8627_CDP 3861
msm8627_mtp MACH_MSM8627_MTP MSM8627_MTP 3862
+msm8625_rumi3 MACH_MSM8625_RUMI3 MSM8625_RUMI3 3871
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d57e8d0..12f5c47 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -168,4 +168,18 @@
bool
default n
+config GENLOCK
+ bool "Enable a generic cross-process locking mechanism"
+ depends on ANON_INODES
+ help
+ Enable a generic cross-process locking API to provide protection
+ for shared memory objects such as graphics buffers.
+
+config GENLOCK_MISCDEVICE
+ bool "Enable a misc-device for userspace to access the genlock engine"
+ depends on GENLOCK
+ help
+ Create a miscdevice for the purposes of allowing userspace to create
+ and interact with locks created using genlock.
+
endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 4c5701c..d3e2ec1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -8,6 +8,7 @@
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
+obj-$(CONFIG_GENLOCK) += genlock.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
new file mode 100644
index 0000000..40b9575
--- /dev/null
+++ b/drivers/base/genlock.c
@@ -0,0 +1,620 @@
+/* Copyright (c) 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.
+ */
+
+#include <linux/fb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/file.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/anon_inodes.h>
+#include <linux/miscdevice.h>
+#include <linux/genlock.h>
+
+/* Lock states - can either be unlocked, held as an exclusive write lock or a
+ * shared read lock
+ */
+
+#define _UNLOCKED 0
+#define _RDLOCK GENLOCK_RDLOCK
+#define _WRLOCK GENLOCK_WRLOCK
+
+struct genlock {
+ struct list_head active; /* List of handles holding lock */
+ spinlock_t lock; /* Spinlock to protect the lock internals */
+ wait_queue_head_t queue; /* Holding pen for processes pending lock */
+ struct file *file; /* File structure for exported lock */
+ int state; /* Current state of the lock */
+};
+
+struct genlock_handle {
+ struct genlock *lock; /* Lock currently attached to the handle */
+ struct list_head entry; /* List node for attaching to a lock */
+ struct file *file; /* File structure associated with handle */
+ int active; /* Number of times the active lock has been
+ taken */
+};
+
+/*
+ * Release the genlock object. Called when all the references to
+ * the genlock file descriptor are released
+ */
+
+static int genlock_release(struct inode *inodep, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations genlock_fops = {
+ .release = genlock_release,
+};
+
+/**
+ * genlock_create_lock - Create a new lock
+ * @handle - genlock handle to attach the lock to
+ *
+ * Returns: a pointer to the genlock
+ */
+
+struct genlock *genlock_create_lock(struct genlock_handle *handle)
+{
+ struct genlock *lock;
+
+ if (handle->lock != NULL)
+ return ERR_PTR(-EINVAL);
+
+ lock = kzalloc(sizeof(*lock), GFP_KERNEL);
+ if (lock == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&lock->active);
+ init_waitqueue_head(&lock->queue);
+ spin_lock_init(&lock->lock);
+
+ lock->state = _UNLOCKED;
+
+ /*
+ * Create an anonyonmous inode for the object that can exported to
+ * other processes
+ */
+
+ lock->file = anon_inode_getfile("genlock", &genlock_fops,
+ lock, O_RDWR);
+
+ /* Attach the new lock to the handle */
+ handle->lock = lock;
+
+ return lock;
+}
+EXPORT_SYMBOL(genlock_create_lock);
+
+/*
+ * Get a file descriptor reference to a lock suitable for sharing with
+ * other processes
+ */
+
+static int genlock_get_fd(struct genlock *lock)
+{
+ int ret;
+
+ if (!lock->file)
+ return -EINVAL;
+
+ ret = get_unused_fd_flags(0);
+ if (ret < 0)
+ return ret;
+ fd_install(ret, lock->file);
+ return ret;
+}
+
+/**
+ * genlock_attach_lock - Attach an existing lock to a handle
+ * @handle - Pointer to a genlock handle to attach the lock to
+ * @fd - file descriptor for the exported lock
+ *
+ * Returns: A pointer to the attached lock structure
+ */
+
+struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
+{
+ struct file *file;
+
+ if (handle->lock != NULL)
+ return ERR_PTR(-EINVAL);
+
+ file = fget(fd);
+ if (file == NULL)
+ return ERR_PTR(-EBADF);
+
+ handle->lock = file->private_data;
+
+ return handle->lock;
+}
+EXPORT_SYMBOL(genlock_attach_lock);
+
+/* Helper function that returns 1 if the specified handle holds the lock */
+
+static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
+{
+ struct genlock_handle *h;
+
+ list_for_each_entry(h, &lock->active, entry) {
+ if (h == handle)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* If the lock just became available, signal the next entity waiting for it */
+
+static void _genlock_signal(struct genlock *lock)
+{
+ if (list_empty(&lock->active)) {
+ /* If the list is empty, then the lock is free */
+ lock->state = _UNLOCKED;
+ /* Wake up the first process sitting in the queue */
+ wake_up(&lock->queue);
+ }
+}
+
+/* Attempt to release the handle's ownership of the lock */
+
+static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
+{
+ int ret = -EINVAL;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ if (lock->state == _UNLOCKED)
+ goto done;
+
+ /* Make sure this handle is an owner of the lock */
+ if (!handle_has_lock(lock, handle))
+ goto done;
+
+ /* If the handle holds no more references to the lock then
+ release it (maybe) */
+
+ if (--handle->active == 0) {
+ list_del(&handle->entry);
+ _genlock_signal(lock);
+ }
+
+ ret = 0;
+
+done:
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+ return ret;
+}
+
+/* Attempt to acquire the lock for the handle */
+
+static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
+ int op, int flags, uint32_t timeout)
+{
+ unsigned long irqflags;
+ int ret = 0;
+ unsigned int ticks = msecs_to_jiffies(timeout);
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ /* Sanity check - no blocking locks in a debug context. Even if it
+ * succeed to not block, the mere idea is too dangerous to continue
+ */
+
+ if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
+ BUG();
+
+ /* Fast path - the lock is unlocked, so go do the needful */
+
+ if (lock->state == _UNLOCKED)
+ goto dolock;
+
+ if (handle_has_lock(lock, handle)) {
+
+ /*
+ * If the handle already holds the lock and the type matches,
+ * then just increment the active pointer. This allows the
+ * handle to do recursive locks
+ */
+
+ if (lock->state == op) {
+ handle->active++;
+ goto done;
+ }
+
+ /*
+ * If the handle holds a write lock then the owner can switch
+ * to a read lock if they want. Do the transition atomically
+ * then wake up any pending waiters in case they want a read
+ * lock too.
+ */
+
+ if (op == _RDLOCK && handle->active == 1) {
+ lock->state = _RDLOCK;
+ wake_up(&lock->queue);
+ goto done;
+ }
+
+ /*
+ * Otherwise the user tried to turn a read into a write, and we
+ * don't allow that.
+ */
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * If we request a read and the lock is held by a read, then go
+ * ahead and share the lock
+ */
+
+ if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
+ goto dolock;
+
+ /* Treat timeout 0 just like a NOBLOCK flag and return if the
+ lock cannot be aquired without blocking */
+
+ if (flags & GENLOCK_NOBLOCK || timeout == 0) {
+ ret = -EAGAIN;
+ goto done;
+ }
+
+ /* Wait while the lock remains in an incompatible state */
+
+ while (lock->state != _UNLOCKED) {
+ unsigned int elapsed;
+
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+
+ elapsed = wait_event_interruptible_timeout(lock->queue,
+ lock->state == _UNLOCKED, ticks);
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ if (elapsed <= 0) {
+ ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
+ goto done;
+ }
+
+ ticks = elapsed;
+ }
+
+dolock:
+ /* We can now get the lock, add ourselves to the list of owners */
+
+ list_add_tail(&handle->entry, &lock->active);
+ lock->state = op;
+ handle->active = 1;
+
+done:
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+ return ret;
+
+}
+
+/**
+ * genlock_lock - Acquire or release a lock
+ * @handle - pointer to the genlock handle that is requesting the lock
+ * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
+ * @flags - flags to control the operation
+ * @timeout - optional timeout to wait for the lock to come free
+ *
+ * Returns: 0 on success or error code on failure
+ */
+
+int genlock_lock(struct genlock_handle *handle, int op, int flags,
+ uint32_t timeout)
+{
+ struct genlock *lock = handle->lock;
+ int ret = 0;
+
+ if (lock == NULL)
+ return -EINVAL;
+
+ switch (op) {
+ case GENLOCK_UNLOCK:
+ ret = _genlock_unlock(lock, handle);
+ break;
+ case GENLOCK_RDLOCK:
+ case GENLOCK_WRLOCK:
+ ret = _genlock_lock(lock, handle, op, flags, timeout);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(genlock_lock);
+
+/**
+ * genlock_wait - Wait for the lock to be released
+ * @handle - pointer to the genlock handle that is waiting for the lock
+ * @timeout - optional timeout to wait for the lock to get released
+ */
+
+int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
+{
+ struct genlock *lock = handle->lock;
+ unsigned long irqflags;
+ int ret = 0;
+ unsigned int ticks = msecs_to_jiffies(timeout);
+
+ if (lock == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ /*
+ * if timeout is 0 and the lock is already unlocked, then success
+ * otherwise return -EAGAIN
+ */
+
+ if (timeout == 0) {
+ ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
+ goto done;
+ }
+
+ while (lock->state != _UNLOCKED) {
+ unsigned int elapsed;
+
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+
+ elapsed = wait_event_interruptible_timeout(lock->queue,
+ lock->state == _UNLOCKED, ticks);
+
+ spin_lock_irqsave(&lock->lock, irqflags);
+
+ if (elapsed <= 0) {
+ ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
+ break;
+ }
+
+ ticks = elapsed;
+ }
+
+done:
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+ return ret;
+}
+
+/**
+ * genlock_release_lock - Release a lock attached to a handle
+ * @handle - Pointer to the handle holding the lock
+ */
+
+void genlock_release_lock(struct genlock_handle *handle)
+{
+ unsigned long flags;
+
+ if (handle == NULL || handle->lock == NULL)
+ return;
+
+ spin_lock_irqsave(&handle->lock->lock, flags);
+
+ /* If the handle is holding the lock, then force it closed */
+
+ if (handle_has_lock(handle->lock, handle)) {
+ list_del(&handle->entry);
+ _genlock_signal(handle->lock);
+ }
+ spin_unlock_irqrestore(&handle->lock->lock, flags);
+
+ fput(handle->lock->file);
+ handle->lock = NULL;
+ handle->active = 0;
+}
+EXPORT_SYMBOL(genlock_release_lock);
+
+/*
+ * Release function called when all references to a handle are released
+ */
+
+static int genlock_handle_release(struct inode *inodep, struct file *file)
+{
+ struct genlock_handle *handle = file->private_data;
+
+ genlock_release_lock(handle);
+ kfree(handle);
+
+ return 0;
+}
+
+static const struct file_operations genlock_handle_fops = {
+ .release = genlock_handle_release
+};
+
+/*
+ * Allocate a new genlock handle
+ */
+
+static struct genlock_handle *_genlock_get_handle(void)
+{
+ struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (handle == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ return handle;
+}
+
+/**
+ * genlock_get_handle - Create a new genlock handle
+ *
+ * Returns: A pointer to a new genlock handle
+ */
+
+struct genlock_handle *genlock_get_handle(void)
+{
+ struct genlock_handle *handle = _genlock_get_handle();
+ if (IS_ERR(handle))
+ return handle;
+
+ handle->file = anon_inode_getfile("genlock-handle",
+ &genlock_handle_fops, handle, O_RDWR);
+
+ return handle;
+}
+EXPORT_SYMBOL(genlock_get_handle);
+
+/**
+ * genlock_put_handle - release a reference to a genlock handle
+ * @handle - A pointer to the handle to release
+ */
+
+void genlock_put_handle(struct genlock_handle *handle)
+{
+ if (handle)
+ fput(handle->file);
+}
+EXPORT_SYMBOL(genlock_put_handle);
+
+/**
+ * genlock_get_handle_fd - Get a handle reference from a file descriptor
+ * @fd - The file descriptor for a genlock handle
+ */
+
+struct genlock_handle *genlock_get_handle_fd(int fd)
+{
+ struct file *file = fget(fd);
+
+ if (file == NULL)
+ return ERR_PTR(-EINVAL);
+
+ return file->private_data;
+}
+EXPORT_SYMBOL(genlock_get_handle_fd);
+
+#ifdef CONFIG_GENLOCK_MISCDEVICE
+
+static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ struct genlock_lock param;
+ struct genlock_handle *handle = filep->private_data;
+ struct genlock *lock;
+ int ret;
+
+ switch (cmd) {
+ case GENLOCK_IOC_NEW: {
+ lock = genlock_create_lock(handle);
+ if (IS_ERR(lock))
+ return PTR_ERR(lock);
+
+ return 0;
+ }
+ case GENLOCK_IOC_EXPORT: {
+ if (handle->lock == NULL)
+ return -EINVAL;
+
+ ret = genlock_get_fd(handle->lock);
+ if (ret < 0)
+ return ret;
+
+ param.fd = ret;
+
+ if (copy_to_user((void __user *) arg, ¶m,
+ sizeof(param)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case GENLOCK_IOC_ATTACH: {
+ if (copy_from_user(¶m, (void __user *) arg,
+ sizeof(param)))
+ return -EFAULT;
+
+ lock = genlock_attach_lock(handle, param.fd);
+ if (IS_ERR(lock))
+ return PTR_ERR(lock);
+
+ return 0;
+ }
+ case GENLOCK_IOC_LOCK: {
+ if (copy_from_user(¶m, (void __user *) arg,
+ sizeof(param)))
+ return -EFAULT;
+
+ return genlock_lock(handle, param.op, param.flags,
+ param.timeout);
+ }
+ case GENLOCK_IOC_WAIT: {
+ if (copy_from_user(¶m, (void __user *) arg,
+ sizeof(param)))
+ return -EFAULT;
+
+ return genlock_wait(handle, param.timeout);
+ }
+ case GENLOCK_IOC_RELEASE: {
+ genlock_release_lock(handle);
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int genlock_dev_release(struct inode *inodep, struct file *file)
+{
+ struct genlock_handle *handle = file->private_data;
+
+ genlock_put_handle(handle);
+
+ return 0;
+}
+
+static int genlock_dev_open(struct inode *inodep, struct file *file)
+{
+ struct genlock_handle *handle = _genlock_get_handle();
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ handle->file = file;
+ file->private_data = handle;
+ return 0;
+}
+
+static const struct file_operations genlock_dev_fops = {
+ .open = genlock_dev_open,
+ .release = genlock_dev_release,
+ .unlocked_ioctl = genlock_dev_ioctl,
+};
+
+static struct miscdevice genlock_dev;
+
+static int genlock_dev_init(void)
+{
+ genlock_dev.minor = MISC_DYNAMIC_MINOR;
+ genlock_dev.name = "genlock";
+ genlock_dev.fops = &genlock_dev_fops;
+ genlock_dev.parent = NULL;
+
+ return misc_register(&genlock_dev);
+}
+
+static void genlock_dev_close(void)
+{
+ misc_deregister(&genlock_dev);
+}
+
+module_init(genlock_dev_init);
+module_exit(genlock_dev_close);
+
+#endif
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index e2f7271..bddc80f 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -125,14 +125,6 @@
#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-static int get_loadavg(void)
-{
- unsigned long this = this_cpu_load();
-
-
- return LOAD_INT(this) * 10 + LOAD_FRAC(this) / 10;
-}
-
static inline int which_bucket(unsigned int duration)
{
int bucket = 0;
@@ -170,15 +162,6 @@
{
int mult = 1;
- /* for higher loadavg, we are more reluctant */
-
- /*
- * this doesn't work as intended - it is almost always 0, but can
- * sometimes, depending on workload, spike very high into the hundreds
- * even when the average cpu load is under 10%.
- */
- /* mult += 2 * get_loadavg(); */
-
/* for IO wait tasks (per cpu!) we add 5x each */
mult += 10 * nr_iowait_cpu(smp_processor_id());
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 893933b..d725851 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -58,8 +58,9 @@
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
- struct clk *ce_core_clk; /* Handle to CE clk */
- struct clk *ce_clk; /* Handle to CE clk */
+ struct clk *ce_core_src_clk; /* Handle to CE src clk*/
+ struct clk *ce_core_clk; /* Handle to CE clk */
+ struct clk *ce_clk; /* Handle to CE clk */
qce_comp_func_ptr_t qce_cb; /* qce callback function pointer */
@@ -207,6 +208,7 @@
static int _init_ce_engine(struct qce_device *pce_dev)
{
+ int status;
/* Reset ce */
clk_reset(pce_dev->ce_core_clk, CLK_RESET_ASSERT);
clk_reset(pce_dev->ce_core_clk, CLK_RESET_DEASSERT);
@@ -223,6 +225,11 @@
config_ce_engine(pce_dev);
/*
+ * Clear ACCESS_VIOL bit in CRYPTO_STATUS REGISTER
+ */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+ *((uint32_t *)(pce_dev->ce_dm.buffer.status)) = status & (~0x40000);
+ /*
* Ensure ce configuration is completed.
*/
mb();
@@ -473,12 +480,20 @@
}
}
- if (creq->mode == QCE_MODE_CCM)
+ switch (creq->mode) {
+ case QCE_MODE_CCM:
pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
- cmdptrlist->aead_ce_out;
- else
+ cmdptrlist->aead_ce_out;
+ break;
+ case QCE_MODE_ECB:
pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
- cmdptrlist->cipher_ce_out;
+ cmdptrlist->cipher_ce_out;
+ break;
+ default:
+ pce_dev->ce_dm.chan_ce_out_cmd->cmdptr =
+ cmdptrlist->cipher_ce_out_get_iv;
+ break;
+ }
return 0;
}
@@ -1329,21 +1344,6 @@
pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
pscmd++;
- pce_dev->ce_dm.cmdlist.get_cipher_aes_iv = pscmd;
- pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
- CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
- pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
- pscmd->len = CRYPTO_REG_SIZE * 4;
- pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
- pscmd++;
-
- pce_dev->ce_dm.cmdlist.get_cipher_aes_xts_iv = pscmd;
- pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
- pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
- pscmd->len = CRYPTO_REG_SIZE * 4;
- pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
- pscmd++;
-
pce_dev->ce_dm.cmdlist.set_cipher_des_iv = pscmd;
pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
@@ -1352,11 +1352,11 @@
pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
pscmd++;
- pce_dev->ce_dm.cmdlist.get_cipher_des_iv = pscmd;
+ pce_dev->ce_dm.cmdlist.get_cipher_iv = pscmd;
pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES |
CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE;
pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase);
- pscmd->len = CRYPTO_REG_SIZE * 2;
+ pscmd->len = CRYPTO_REG_SIZE * 4;
pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv);
pscmd++;
@@ -1612,6 +1612,14 @@
pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
pscmd++;
+ /* CLEAR STATUS COMMAND LIST */
+ pce_dev->ce_dm.cmdlist.clear_status = pscmd;
+ pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCU;
+ pscmd->dst = (unsigned) (CRYPTO_STATUS_REG + pce_dev->phy_iobase);
+ pscmd->len = CRYPTO_REG_SIZE;
+ pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
+ pscmd++;
+
/* SET GO_PROC REGISTERS COMMAND LIST */
pce_dev->ce_dm.cmdlist.set_go_proc = pscmd;
pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
@@ -1692,8 +1700,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_256_cbc_ctr = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1705,8 +1712,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_128_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1742,8 +1748,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_256_xts = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1757,8 +1762,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_des_cbc = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1769,8 +1773,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1791,8 +1794,7 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
- *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in);
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_3des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
@@ -1809,6 +1811,14 @@
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out);
*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
+
+ cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
+ cmdptrlist->cipher_ce_out_get_iv = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
+
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_cipher_iv);
+ *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
+
*pvaddr = (unsigned char *) cmd_ptr_vaddr;
return 0;
@@ -2007,6 +2017,7 @@
cmdptrlist->probe_ce_hw = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_hw_version);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status);
*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
*pvaddr = (unsigned char *) cmd_ptr_vaddr;
@@ -2391,6 +2402,8 @@
struct resource *resource;
struct clk *ce_core_clk;
struct clk *ce_clk;
+ struct clk *ce_core_src_clk;
+ int ret = 0;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -2461,10 +2474,26 @@
goto err;
}
+ /* Get CE3 src core clk. */
+ ce_core_src_clk = clk_get(pce_dev->pdev, "ce3_core_src_clk");
+ if (!IS_ERR(ce_core_src_clk)) {
+ pce_dev->ce_core_src_clk = ce_core_src_clk;
+
+ /* Set the core src clk @100Mhz */
+ ret = clk_set_rate(pce_dev->ce_core_src_clk, 100000000);
+ if (ret) {
+ clk_put(pce_dev->ce_core_src_clk);
+ goto err;
+ }
+ } else
+ pce_dev->ce_core_src_clk = NULL;
+
/* Get CE core clk */
ce_core_clk = clk_get(pce_dev->pdev, "core_clk");
if (IS_ERR(ce_core_clk)) {
*rc = PTR_ERR(ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
goto err;
}
pce_dev->ce_core_clk = ce_core_clk;
@@ -2472,6 +2501,8 @@
ce_clk = clk_get(pce_dev->pdev, "iface_clk");
if (IS_ERR(ce_clk)) {
*rc = PTR_ERR(ce_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
goto err;
}
@@ -2480,6 +2511,8 @@
/* Enable CE core clk */
*rc = clk_enable(pce_dev->ce_core_clk);
if (*rc) {
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
clk_put(pce_dev->ce_clk);
goto err;
@@ -2488,6 +2521,8 @@
*rc = clk_enable(pce_dev->ce_clk);
if (*rc) {
clk_disable(pce_dev->ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
clk_put(pce_dev->ce_clk);
goto err;
@@ -2539,6 +2574,9 @@
clk_disable(pce_dev->ce_clk);
clk_disable(pce_dev->ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
+
clk_put(pce_dev->ce_clk);
clk_put(pce_dev->ce_core_clk);
@@ -2571,4 +2609,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.13");
+MODULE_VERSION("2.14");
diff --git a/drivers/crypto/msm/qce40.h b/drivers/crypto/msm/qce40.h
index c9fbb17..809ba7f 100644
--- a/drivers/crypto/msm/qce40.h
+++ b/drivers/crypto/msm/qce40.h
@@ -117,6 +117,7 @@
/* CE Command lists */
struct ce_cmdlists {
dmov_s *get_hw_version;
+ dmov_s *clear_status;
dmov_s *get_status_ocu;
dmov_s *set_cipher_cfg;
@@ -132,10 +133,8 @@
dmov_s *set_cipher_aes_iv;
dmov_s *set_cipher_aes_xts_iv;
- dmov_s *get_cipher_aes_iv;
- dmov_s *get_cipher_aes_xts_iv;
dmov_s *set_cipher_des_iv;
- dmov_s *get_cipher_des_iv;
+ dmov_s *get_cipher_iv;
dmov_s *set_cipher_mask;
@@ -195,6 +194,7 @@
uint32_t aead_aes_256_ccm;
uint32_t cipher_ce_out;
+ uint32_t cipher_ce_out_get_iv;
uint32_t aead_ce_out;
};
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 4138e06..06c4d90 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -837,6 +837,12 @@
return status;
}
+static inline void adreno_poke(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ adreno_regwrite(device, REG_CP_RB_WPTR, adreno_dev->ringbuffer.wptr);
+}
+
/* Caller must hold the device mutex. */
int adreno_idle(struct kgsl_device *device, unsigned int timeout)
{
@@ -855,6 +861,7 @@
retry:
if (rb->flags & KGSL_FLAGS_STARTED) {
do {
+ adreno_poke(device);
GSL_RB_GET_READPTR(rb, &rb->rptr);
if (time_after(jiffies, wait_time)) {
KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
@@ -1083,6 +1090,9 @@
static uint io_cnt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ int retries;
+ unsigned int msecs_first;
+ unsigned int msecs_part;
/* Don't wait forever, set a max value for now */
if (msecs == -1)
@@ -1097,43 +1107,59 @@
status = -EINVAL;
goto done;
}
- if (!kgsl_check_timestamp(device, timestamp)) {
- io_cnt = (io_cnt + 1) % 100;
- if (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
- io = 0;
- mutex_unlock(&device->mutex);
- /* We need to make sure that the process is placed in wait-q
- * before its condition is called */
- status = kgsl_wait_event_interruptible_timeout(
- device->wait_queue,
- kgsl_check_interrupt_timestamp(device,
- timestamp),
- msecs_to_jiffies(msecs), io);
- mutex_lock(&device->mutex);
- if (status > 0)
- status = 0;
- else if (status == 0) {
- if (!kgsl_check_timestamp(device, timestamp)) {
- status = -ETIMEDOUT;
- KGSL_DRV_ERR(device,
- "Device hang detected while waiting "
- "for timestamp: %x, last "
- "submitted(rb->timestamp): %x, wptr: "
- "%x\n", timestamp,
- adreno_dev->ringbuffer.timestamp,
- adreno_dev->ringbuffer.wptr);
- if (!adreno_dump_and_recover(device)) {
- /* wait for idle after recovery as the
- * timestamp that this process wanted
- * to wait on may be invalid */
- if (!adreno_idle(device,
- KGSL_TIMEOUT_DEFAULT))
- status = 0;
- }
+ /* Keep the first timeout as 100msecs before rewriting
+ * the WPTR. Less visible impact if the WPTR has not
+ * been updated properly.
+ */
+ msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
+ msecs_part = (msecs - msecs_first + 3) / 4;
+ for (retries = 0; retries < 5; retries++) {
+ if (!kgsl_check_timestamp(device, timestamp)) {
+ adreno_poke(device);
+ io_cnt = (io_cnt + 1) % 100;
+ if (io_cnt <
+ pwr->pwrlevels[pwr->active_pwrlevel].
+ io_fraction)
+ io = 0;
+ mutex_unlock(&device->mutex);
+ /* We need to make sure that the process is
+ * placed in wait-q before its condition is called
+ */
+ status = kgsl_wait_event_interruptible_timeout(
+ device->wait_queue,
+ kgsl_check_interrupt_timestamp(device,
+ timestamp),
+ msecs_to_jiffies(retries ?
+ msecs_part : msecs_first), io);
+ mutex_lock(&device->mutex);
+
+ if (status > 0) {
+ status = 0;
+ goto done;
}
}
}
+ if (!kgsl_check_timestamp(device, timestamp)) {
+ status = -ETIMEDOUT;
+ KGSL_DRV_ERR(device,
+ "Device hang detected while waiting "
+ "for timestamp: %x, last "
+ "submitted(rb->timestamp): %x, wptr: "
+ "%x\n", timestamp,
+ adreno_dev->ringbuffer.timestamp,
+ adreno_dev->ringbuffer.wptr);
+ if (!adreno_dump_and_recover(device)) {
+ /* wait for idle after recovery as the
+ * timestamp that this process wanted
+ * to wait on may be invalid */
+ if (!adreno_idle(device,
+ KGSL_TIMEOUT_DEFAULT))
+ status = 0;
+ }
+ } else {
+ status = 0;
+ }
done:
return (int)status;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e84d473..a0a4056 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -24,6 +24,7 @@
#include <linux/ashmem.h>
#include <linux/major.h>
#include <linux/ion.h>
+#include <mach/socinfo.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -1939,8 +1940,8 @@
kgsl_cffdump_close(device->id);
kgsl_pwrctrl_uninit_sysfs(device);
- wake_lock_destroy(&device->idle_wakelock);
- pm_qos_remove_request(&device->pm_qos_req_dma);
+ if (cpu_is_msm8x60())
+ wake_lock_destroy(&device->idle_wakelock);
idr_destroy(&device->context_idr);
@@ -2031,9 +2032,9 @@
if (ret != 0)
goto err_close_mmu;
- wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
- pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ if (cpu_is_msm8x60())
+ wake_lock_init(&device->idle_wakelock,
+ WAKE_LOCK_IDLE, device->name);
idr_init(&device->context_idr);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6ae9258..fd203ef 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -15,7 +15,6 @@
#include <linux/idr.h>
#include <linux/wakelock.h>
-#include <linux/pm_qos_params.h>
#include <linux/earlysuspend.h>
#include "kgsl.h"
@@ -165,7 +164,6 @@
struct wake_lock idle_wakelock;
struct kgsl_pwrscale pwrscale;
struct kobject pwrscale_kobj;
- struct pm_qos_request_list pm_qos_req_dma;
struct work_struct ts_expired_ws;
};
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8ec9572..7034fd8 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
+#include <mach/socinfo.h>
#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -23,7 +24,6 @@
#define KGSL_PWRFLAGS_AXI_ON 2
#define KGSL_PWRFLAGS_IRQ_ON 3
-#define GPU_SWFI_LATENCY 3
#define UPDATE_BUSY_VAL 1000000
#define UPDATE_BUSY 50
@@ -697,6 +697,8 @@
goto slumber;
}
} else if (device->requested_state == KGSL_STATE_SLUMBER) {
+ if (device->state == KGSL_STATE_INIT)
+ return 0;
if (device->ftbl->isidle(device))
goto slumber;
}
@@ -729,9 +731,8 @@
device->state = device->requested_state;
device->requested_state = KGSL_STATE_NONE;
- wake_unlock(&device->idle_wakelock);
- pm_qos_update_request(&device->pm_qos_req_dma,
- PM_QOS_DEFAULT_VALUE);
+ if (device->idle_wakelock.name)
+ wake_unlock(&device->idle_wakelock);
KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n",
device->state, device->id);
@@ -761,7 +762,7 @@
/* Caller must hold the device mutex. */
void kgsl_pwrctrl_wake(struct kgsl_device *device)
{
- if (device->state == KGSL_STATE_SUSPEND)
+ if (device->state & (KGSL_STATE_SUSPEND | KGSL_STATE_INIT))
return;
if (device->state == KGSL_STATE_SLUMBER)
@@ -784,8 +785,9 @@
mod_timer(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
- wake_lock(&device->idle_wakelock);
- pm_qos_update_request(&device->pm_qos_req_dma, GPU_SWFI_LATENCY);
+ if (device->idle_wakelock.name)
+ wake_lock(&device->idle_wakelock);
+
KGSL_PWR_INFO(device, "wake return for device %d\n", device->id);
}
EXPORT_SYMBOL(kgsl_pwrctrl_wake);
diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c
index d2bd4df..35507e1 100644
--- a/drivers/input/touchscreen/atmel_maxtouch.c
+++ b/drivers/input/touchscreen/atmel_maxtouch.c
@@ -939,6 +939,7 @@
input_mt_sync(mxt->input);
}
}
+ input_report_key(mxt->input, BTN_TOUCH, !!active_touches);
if (active_touches == 0)
input_mt_sync(mxt->input);
input_sync(mxt->input);
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index f267f80..e01d2c7 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -12,7 +12,6 @@
*/
#include "msm_actuator.h"
-#include "msm_logging.h"
#include "msm_camera_i2c.h"
#define IMX074_TOTAL_STEPS_NEAR_TO_FAR 41
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index 7f570e6..f0023d7 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -11,10 +11,6 @@
*/
#include "msm_actuator.h"
-#include "msm_logging.h"
-
-LDECVAR(a_profstarttime);
-LDECVAR(a_profendtime);
int32_t msm_actuator_write_focus(
struct msm_actuator_ctrl_t *a_ctrl,
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index d612dad..6fad8dd 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -18,6 +18,24 @@
#include <media/msm_camera.h>
#include "msm_camera_i2c.h"
+#ifdef LERROR
+#undef LERROR
+#endif
+
+#ifdef LINFO
+#undef LINFO
+#endif
+
+#define LERROR(fmt, args...) pr_err(fmt, ##args)
+
+#define CONFIG_MSM_CAMERA_ACT_DBG 0
+
+#if CONFIG_MSM_CAMERA_ACT_DBG
+#define LINFO(fmt, args...) printk(fmt, ##args)
+#else
+#define LINFO(fmt, args...) CDBG(fmt, ##args)
+#endif
+
struct msm_actuator_ctrl_t;
struct region_params_t {
diff --git a/drivers/media/video/msm/msm_logging.h b/drivers/media/video/msm/msm_logging.h
deleted file mode 100644
index 5e1547c..0000000
--- a/drivers/media/video/msm/msm_logging.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Copyright (c) 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 __MSM_LOGGING_H
-#define __MSM_LOGGING_H
-
-#include <linux/time.h>
-
-#ifdef MSM_LOG_LEVEL_ERROR
-#undef MSM_LOG_LEVEL_ERROR
-#endif
-
-#ifdef MSM_LOG_LEVEL_PROFILE
-#undef MSM_LOG_LEVEL_PROFILE
-#endif
-
-#ifdef MSM_LOG_LEVEL_ALL
-#undef MSM_LOG_LEVEL_ALL
-#endif
-
-/* MSM_LOG_LEVEL_ERROR - prints only error logs
- * MSM_LOG_LEVEL_PROFILE - prints all profile and error logs
- * MSM_LOG_LEVEL_ALL - prints all logs */
-
-#define MSM_LOG_LEVEL_ERROR
-/* #define MSM_LOG_LEVEL_PROFILE */
-/* #define MSM_LOG_LEVEL_ALL */
-
-#ifdef LINFO
-#undef LINFO
-#endif
-
-#ifdef LERROR
-#undef LERROR
-#endif
-
-#ifdef LPROFSTART
-#undef LPROFSTART
-#endif
-
-#ifdef LPROFEND
-#undef LPROFEND
-#endif
-
-#if defined(MSM_LOG_LEVEL_ERROR)
-#define LDECVAR(VAR)
-#define LINFO(fmt, args...) pr_debug(fmt, ##args)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) do {} while (0)
-#define LPROFEND(START, END) do {} while (0)
-#elif defined(MSM_LOG_LEVEL_PROFILE)
-#define LDECVAR(VAR) \
- static struct timespec VAR
-#define LINFO(fmt, args...) do {} while (0)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) \
- START = current_kernel_time()
-#define LPROFEND(START, END) \
- do { \
- END = current_kernel_time(); \
- pr_info("profile start time in ns: %lu\n", \
- (START.tv_sec * NSEC_PER_SEC) + \
- START.tv_nsec); \
- pr_info("profile end time in ns: %lu\n", \
- (END.tv_sec * NSEC_PER_SEC) + \
- END.tv_nsec); \
- pr_info("profile diff time in ns: %lu\n", \
- ((END.tv_sec - START.tv_sec) * NSEC_PER_SEC) + \
- (END.tv_nsec - START.tv_nsec)); \
- START = END; \
- } while (0)
-
-#elif defined(MSM_LOG_LEVEL_ALL)
-#define LDECVAR(VAR) \
- static struct timespec VAR
-#define LINFO(fmt, args...) pr_debug(fmt, ##args)
-#define LERROR(fmt, args...) pr_err(fmt, ##args)
-#define LPROFSTART(START) \
- START = current_kernel_time()
-#define LPROFEND(START, END) \
- do { \
- END = current_kernel_time(); \
- pr_info("profile start time in ns: %lu\n", \
- (START.tv_sec * NSEC_PER_SEC) + \
- START.tv_nsec); \
- pr_info("profile end time in ns: %lu\n", \
- (END.tv_sec * NSEC_PER_SEC) + \
- END.tv_nsec); \
- pr_info("profile diff time in ns: %lu\n", \
- ((END.tv_sec - START.tv_sec) * NSEC_PER_SEC) + \
- (END.tv_nsec - START.tv_nsec)); \
- START = END; \
- } while (0)
-#else
-#define LDECVAR(VAR)
-#define LINFO(fmt, args...) do {} while (0)
-#define LERROR(fmt, args...) do {} while (0)
-#define LPROFSTART(START) do {} while (0)
-#define LPROFEND(START, END) do {} while (0)
-#endif
-#endif
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index 528f232..8d89568 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -29,6 +29,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
+#define REG_IRQ_BASE 0x1BB
#define REG_RTC_BASE 0x11D
@@ -237,6 +238,7 @@
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8018_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index ed29785..8a556bd 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -26,6 +26,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
+#define REG_IRQ_BASE 0x1BB
#define PM8821_VERSION_MASK 0xFFF0
#define PM8821_VERSION_VALUE 0x07F0
@@ -150,6 +151,7 @@
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8821_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 742d8dd..d225dfa 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -27,6 +27,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
+#define REG_IRQ_BASE 0x1BB
#define REG_TEMP_ALARM_CTRL 0x1B
#define REG_TEMP_ALARM_PWM 0x9B
@@ -270,7 +271,6 @@
SINGLE_IRQ_RESOURCE("PM8921_BMS_OCV_FOR_R", PM8921_BMS_OCV_FOR_R),
SINGLE_IRQ_RESOURCE("PM8921_BMS_GOOD_OCV", PM8921_BMS_GOOD_OCV),
SINGLE_IRQ_RESOURCE("PM8921_BMS_VSENSE_AVG", PM8921_BMS_VSENSE_AVG),
- SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
};
static struct mfd_cell charger_cell __devinitdata = {
@@ -342,6 +342,17 @@
.pdata_size = sizeof(struct pm8xxx_batt_alarm_core_data),
};
+static const struct resource ccadc_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
+};
+
+static struct mfd_cell ccadc_cell __devinitdata = {
+ .name = PM8XXX_CCADC_DEV_NAME,
+ .id = -1,
+ .resources = ccadc_cell_resources,
+ .num_resources = ARRAY_SIZE(ccadc_cell_resources),
+};
+
static struct mfd_cell vibrator_cell __devinitdata = {
.name = PM8XXX_VIBRATOR_DEV_NAME,
.id = -1,
@@ -358,6 +369,7 @@
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
@@ -566,6 +578,19 @@
}
}
+ if (pdata->ccadc_pdata) {
+ ccadc_cell.platform_data = pdata->ccadc_pdata;
+ ccadc_cell.pdata_size =
+ sizeof(struct pm8xxx_ccadc_platform_data);
+
+ ret = mfd_add_devices(pmic->dev, 0, &ccadc_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add ccadc subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
return 0;
bail:
if (pmic->irq_chip) {
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index c6221b8..5864b85 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -24,17 +24,15 @@
/* PMIC8xxx IRQ */
-#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
-
-#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
-#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
-#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
-#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
-#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
-#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
-#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
-#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
-#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
+#define SSBI_REG_ADDR_IRQ_ROOT(base) (base + 0)
+#define SSBI_REG_ADDR_IRQ_M_STATUS1(base) (base + 1)
+#define SSBI_REG_ADDR_IRQ_M_STATUS2(base) (base + 2)
+#define SSBI_REG_ADDR_IRQ_M_STATUS3(base) (base + 3)
+#define SSBI_REG_ADDR_IRQ_M_STATUS4(base) (base + 4)
+#define SSBI_REG_ADDR_IRQ_BLK_SEL(base) (base + 5)
+#define SSBI_REG_ADDR_IRQ_IT_STATUS(base) (base + 6)
+#define SSBI_REG_ADDR_IRQ_CONFIG(base) (base + 7)
+#define SSBI_REG_ADDR_IRQ_RT_STATUS(base) (base + 8)
#define PM_IRQF_LVL_SEL 0x01 /* level select */
#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */
@@ -50,6 +48,7 @@
struct pm_irq_chip {
struct device *dev;
spinlock_t pm_irq_lock;
+ unsigned int base_addr;
unsigned int devirq;
unsigned int irq_base;
unsigned int num_irqs;
@@ -60,13 +59,14 @@
static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
{
- return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
+ return pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_ROOT(chip->base_addr), rp);
}
static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
{
return pm8xxx_readb(chip->dev,
- SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
+ SSBI_REG_ADDR_IRQ_M_STATUS1(chip->base_addr) + m, bp);
}
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
@@ -74,13 +74,15 @@
int rc;
spin_lock(&chip->pm_irq_lock);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
- rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_IT_STATUS(chip->base_addr), ip);
if (rc)
pr_err("Failed Reading Status rc=%d\n", rc);
bail:
@@ -93,17 +95,20 @@
int rc;
spin_lock(&chip->pm_irq_lock);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
if (rc)
pr_err("Failed Configuring IRQ rc=%d\n", rc);
- rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, r);
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), r);
if (rc)
pr_err("Failed reading IRQ rc=%d\n", rc);
bail:
@@ -116,14 +121,16 @@
int rc;
spin_lock(&chip->pm_irq_lock);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
cp |= PM_IRQF_WRITE;
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
if (rc)
pr_err("Failed Configuring IRQ rc=%d\n", rc);
bail:
@@ -335,14 +342,16 @@
spin_lock_irqsave(&chip->pm_irq_lock, flags);
- rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
+ rc = pm8xxx_writeb(chip->dev,
+ SSBI_REG_ADDR_IRQ_BLK_SEL(chip->base_addr), block);
if (rc) {
pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
goto bail_out;
}
- rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_RT_STATUS(chip->base_addr), &bits);
if (rc) {
pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
@@ -388,6 +397,7 @@
chip->devirq = devirq;
chip->irq_base = pdata->irq_base;
chip->num_irqs = pdata->irq_cdata.nirqs;
+ chip->base_addr = pdata->irq_cdata.base_addr;
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
spin_lock_init(&chip->pm_irq_lock);
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index 77e393e..ae721e4 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -25,6 +25,7 @@
#include <linux/msm_adc.h>
#define REG_MPP_BASE 0x50
+#define REG_IRQ_BASE 0x1BB
/* PMIC8058 Revision */
#define PM8058_REG_REV 0x002 /* PMIC4 revision */
@@ -901,6 +902,7 @@
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8058_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
index 8eca7aa..aabc2cc 100644
--- a/drivers/mfd/wcd9310-core.c
+++ b/drivers/mfd/wcd9310-core.c
@@ -22,10 +22,25 @@
#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 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)
{
@@ -566,6 +581,214 @@
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)
+{
+ pr_debug("exit\n");
+ return 0;
+}
+
static int tabla_slim_probe(struct slim_device *slim)
{
struct tabla *tabla;
@@ -600,7 +823,7 @@
ret = tabla_enable_supplies(tabla);
if (ret) {
- pr_info("%s: Fail to enable Tabla supplies\n", __func__);
+ pr_err("%s: Fail to enable Tabla supplies\n", __func__);
goto err_tabla;
}
usleep_range(5, 5);
@@ -661,6 +884,7 @@
break;
}
tabla_inf_la = tabla->slim_slave->laddr;
+ tabla_intf = TABLA_INTERFACE_TYPE_SLIMBUS;
ret = tabla_device_init(tabla, tabla->irq);
if (ret) {
@@ -744,9 +968,33 @@
.id_table = slimtest2x_id,
};
+#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),
+};
+
static int __init tabla_init(void)
{
- int ret1, ret2;
+ int ret1, ret2, ret3;
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
@@ -756,7 +1004,11 @@
if (ret2 != 0)
pr_err("Failed to register tabla2x SB driver: %d\n", ret2);
- return (ret1 && ret2) ? -1 : 0;
+ 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);
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
index bc7841e..9cc4761 100644
--- a/drivers/mfd/wcd9310-irq.c
+++ b/drivers/mfd/wcd9310-irq.c
@@ -110,11 +110,19 @@
(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;
}
diff --git a/drivers/net/msm_rmnet_bam.c b/drivers/net/msm_rmnet_bam.c
index 3b3758e..bb20a3f 100644
--- a/drivers/net/msm_rmnet_bam.c
+++ b/drivers/net/msm_rmnet_bam.c
@@ -308,6 +308,7 @@
}
dev->trans_start = jiffies;
+ /* if write() succeeds, skb access is unsafe in this process */
bam_ret = msm_bam_dmux_write(p->ch_id, skb);
if (bam_ret != 0) {
@@ -316,16 +317,6 @@
goto xmit_out;
}
- if (count_this_packet(skb->data, skb->len)) {
- p->stats.tx_packets++;
- p->stats.tx_bytes += skb->len;
-#ifdef CONFIG_MSM_RMNET_DEBUG
- p->wakeups_xmit += rmnet_cause_wakeup(p);
-#endif
- }
- DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
- dev->name, p->stats.tx_packets, skb->len, skb->mark);
-
return 0;
xmit_out:
/* data xmited, safe to release skb */
@@ -335,7 +326,21 @@
static void bam_write_done(void *dev, struct sk_buff *skb)
{
+ struct rmnet_private *p = netdev_priv(dev);
+ u32 opmode = p->operation_mode;
+
DBG1("%s: write complete\n", __func__);
+ if (RMNET_IS_MODE_IP(opmode) ||
+ count_this_packet(skb->data, skb->len)) {
+ p->stats.tx_packets++;
+ p->stats.tx_bytes += skb->len;
+#ifdef CONFIG_MSM_RMNET_DEBUG
+ p->wakeups_xmit += rmnet_cause_wakeup(p);
+#endif
+ }
+ DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+ ((struct net_device *)(dev))->name, p->stats.tx_packets,
+ skb->len, skb->mark);
dev_kfree_skb_any(skb);
netif_wake_queue(dev);
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3590e6d..7c8dfea 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -332,7 +332,14 @@
help
Say Y here to enable support for pm8921 chip charger subdevice
+config PM8XXX_CCADC
+ tristate "PM8XXX battery current adc driver"
+ depends on MFD_PM8921_CORE
+ help
+ Say Y here to enable support for pm8921 chip bms subdevice
+
config PM8921_BMS
+ select PM8XXX_CCADC
tristate "PM8921 Battery Monitoring System driver"
depends on MFD_PM8921_CORE
help
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index f61c88a..e168590 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -45,5 +45,6 @@
obj-$(CONFIG_BATTERY_BQ27520) += bq27520_fuelgauger.o
obj-$(CONFIG_BATTERY_BQ27541) += bq27541_fuelgauger.o
obj-$(CONFIG_SMB137B_CHARGER) += smb137b.o
+obj-$(CONFIG_PM8XXX_CCADC) += pm8xxx-ccadc.o
obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index d7cf3a8..143d9b5 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -19,6 +19,7 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
@@ -29,15 +30,6 @@
#define BMS_OUTPUT0 0x230
#define BMS_OUTPUT1 0x231
#define BMS_TEST1 0x237
-#define CCADC_ANA_PARAM 0x240
-#define CCADC_DIG_PARAM 0x241
-#define CCADC_RSV 0x242
-#define CCADC_DATA0 0x244
-#define CCADC_DATA1 0x245
-#define CCADC_OFFSET_TRIM1 0x34A
-#define CCADC_OFFSET_TRIM0 0x34B
-#define CCADC_FULLSCALE_TRIM1 0x34C
-#define CCADC_FULLSCALE_TRIM0 0x34D
#define ADC_ARB_SECP_CNTRL 0x190
#define ADC_ARB_SECP_AMUX_CNTRL 0x191
@@ -57,7 +49,6 @@
PM8921_BMS_OCV_FOR_R,
PM8921_BMS_GOOD_OCV,
PM8921_BMS_VSENSE_AVG,
- PM8921_BMS_CCADC_EOC,
PM_BMS_MAX_INTS,
};
@@ -75,8 +66,6 @@
struct work_struct calib_hkadc_work;
struct delayed_work calib_ccadc_work;
unsigned int calib_delay_ms;
- int ccadc_gain_uv;
- u16 ccadc_result_offset;
unsigned int revision;
unsigned int xoadc_v0625;
unsigned int xoadc_v125;
@@ -400,56 +389,6 @@
cc_to_microvolt_v2((s64)cc);
}
-#define CCADC_READING_RESOLUTION_N_V1 1085069
-#define CCADC_READING_RESOLUTION_D_V1 100000
-#define CCADC_READING_RESOLUTION_N_V2 542535
-#define CCADC_READING_RESOLUTION_D_V2 100000
-static s64 ccadc_reading_to_microvolt_v1(s64 cc)
-{
- return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
- CCADC_READING_RESOLUTION_D_V1);
-}
-
-static s64 ccadc_reading_to_microvolt_v2(s64 cc)
-{
- return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
- CCADC_READING_RESOLUTION_D_V2);
-}
-
-static s64 ccadc_reading_to_microvolt(struct pm8921_bms_chip *chip, s64 cc)
-{
- /*
- * resolution (the value of a single bit) was changed after revision 2.0
- * for more accurate readings
- */
- return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
- ccadc_reading_to_microvolt_v1((s64)cc) :
- ccadc_reading_to_microvolt_v2((s64)cc);
-}
-
-static s64 microvolt_to_ccadc_reading_v1(s64 uv)
-{
- return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
- CCADC_READING_RESOLUTION_N_V1);
-}
-
-static s64 microvolt_to_ccadc_reading_v2(s64 uv)
-{
- return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
- CCADC_READING_RESOLUTION_N_V2);
-}
-
-static s64 microvolt_to_ccadc_reading(struct pm8921_bms_chip *chip, s64 cc)
-{
- /*
- * resolution (the value of a single bit) was changed after revision 2.0
- * for more accurate readings
- */
- return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
- microvolt_to_ccadc_reading_v1((s64)cc) :
- microvolt_to_ccadc_reading_v2((s64)cc);
-}
-
#define CC_READING_TICKS 55
#define SLEEP_CLK_HZ 32768
#define SECONDS_PER_HOUR 3600
@@ -459,19 +398,6 @@
SLEEP_CLK_HZ * SECONDS_PER_HOUR);
}
-#define GAIN_REFERENCE_UV 25000
-/*
- * gain compensation for ccadc readings - common for vsense based and
- * couloumb counter based readings
- */
-static s64 cc_adjust_for_gain(struct pm8921_bms_chip *chip, s64 cc)
-{
- if (chip->ccadc_gain_uv == 0)
- return cc;
-
- return div_s64(cc * GAIN_REFERENCE_UV, chip->ccadc_gain_uv);
-}
-
/* returns the signed value read from the hardware */
static int read_cc(struct pm8921_bms_chip *chip, int *result)
{
@@ -559,9 +485,9 @@
pr_err("fail to read VSENSE_FOR_RBATT rc = %d\n", rc);
return rc;
}
- *result = ccadc_reading_to_microvolt(chip, reading);
+ *result = pm8xxx_ccadc_reading_to_microvolt(chip->revision, reading);
pr_debug("raw = %04x vsense_for_r_uV = %u\n", reading, *result);
- *result = cc_adjust_for_gain(chip, *result);
+ *result = pm8xxx_cc_adjust_for_gain(*result);
pr_debug("after adj vsense_for_r_uV = %u\n", *result);
return 0;
}
@@ -593,9 +519,10 @@
pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
return rc;
}
- *result = ccadc_reading_to_microvolt(chip, reading);
+ *result = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ reading);
pr_debug("raw = %04x vsense = %d\n", reading, *result);
- *result = cc_adjust_for_gain(the_chip, (s64)*result);
+ *result = pm8xxx_cc_adjust_for_gain((s64)*result);
pr_debug("after adj vsense = %d\n", *result);
return 0;
}
@@ -976,7 +903,7 @@
rc = read_cc(the_chip, coulumb_counter);
cc_voltage_uv = (int64_t)*coulumb_counter;
cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
- cc_voltage_uv = cc_adjust_for_gain(chip, cc_voltage_uv);
+ cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
cc_uvh = ccmicrovolt_to_uvh(cc_voltage_uv);
pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh);
@@ -1224,386 +1151,12 @@
calib_hkadc(chip);
}
-#define START_CONV_BIT BIT(7)
-#define EOC_CONV_BIT BIT(6)
-#define SEL_CCADC_BIT BIT(1)
-#define EN_ARB_BIT BIT(0)
-
-#define CCADC_CALIB_DIG_PARAM 0xE3
-#define CCADC_CALIB_RSV_GND 0x40
-#define CCADC_CALIB_RSV_25MV 0x80
-#define CCADC_CALIB_ANA_PARAM 0x1B
-#define SAMPLE_COUNT 16
-#define ADC_WAIT_COUNT 10
-
-#define CCADC_MAX_25MV 30000
-#define CCADC_MIN_25MV 20000
-#define CCADC_MAX_0UV -4000
-#define CCADC_MIN_0UV -7000
-
-#define CCADC_INTRINSIC_OFFSET 0xC000
-
-#define REG_SBI_CONFIG 0x04F
-#define PAGE3_ENABLE_MASK 0x6
-
-static int calib_ccadc_enable_trim_access(struct pm8921_bms_chip *chip,
- u8 *sbi_config)
-{
- u8 reg;
- int rc;
-
- rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
- if (rc) {
- pr_err("error = %d reading sbi config reg\n", rc);
- return rc;
- }
-
- reg = *sbi_config | PAGE3_ENABLE_MASK;
- return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
-}
-
-static int calib_ccadc_restore_trim_access(struct pm8921_bms_chip *chip,
- u8 sbi_config)
-{
- return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
-}
-
-static int calib_ccadc_enable_arbiter(struct pm8921_bms_chip *chip)
-{
- int rc;
-
- /* enable Arbiter, must be sent twice */
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for offset\n", rc);
- return rc;
- }
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
- if (rc < 0) {
- pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
- return rc;
- }
- return 0;
-}
-
-static int calib_start_conv(struct pm8921_bms_chip *chip,
- u16 *result)
-{
- int rc, i;
- u8 data_msb, data_lsb, reg;
-
- /* Start conversion */
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- START_CONV_BIT, START_CONV_BIT);
- if (rc < 0) {
- pr_err("error = %d starting offset meas\n", rc);
- return rc;
- }
-
- /* Wait for End of conversion */
- for (i = 0; i < ADC_WAIT_COUNT; i++) {
- rc = pm8xxx_readb(chip->dev->parent,
- ADC_ARB_SECP_CNTRL, ®);
- if (rc < 0) {
- pr_err("error = %d read eoc for offset\n", rc);
- return rc;
- }
- if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
- msleep(60);
- else
- break;
- }
- if (i == ADC_WAIT_COUNT) {
- pr_err("waited too long for offset eoc\n");
- return rc;
- }
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
- if (rc < 0) {
- pr_err("error = %d reading offset lsb\n", rc);
- return rc;
- }
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
- if (rc < 0) {
- pr_err("error = %d reading offset msb\n", rc);
- return rc;
- }
-
- *result = (data_msb << 8) | data_lsb;
- return 0;
-}
-
-static int calib_ccadc_read_trim(struct pm8921_bms_chip *chip,
- int addr, u8 *data_msb, u8 *data_lsb)
-{
- int rc;
- u8 sbi_config;
-
- calib_ccadc_enable_trim_access(chip, &sbi_config);
- rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
- if (rc < 0) {
- pr_err("error = %d read msb\n", rc);
- return rc;
- }
- rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
- if (rc < 0) {
- pr_err("error = %d read lsb\n", rc);
- return rc;
- }
- calib_ccadc_restore_trim_access(chip, sbi_config);
- return 0;
-}
-
-static int calib_ccadc_read_gain_uv(struct pm8921_bms_chip *chip)
-{
- s8 data_msb;
- u8 data_lsb;
- int rc, gain, offset;
-
- rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
- &data_msb, &data_lsb);
- gain = (data_msb << 8) | data_lsb;
-
- rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
- &data_msb, &data_lsb);
- offset = (data_msb << 8) | data_lsb;
-
- pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", gain, offset);
- gain = ccadc_reading_to_microvolt(chip, (s64)gain - offset);
- return gain;
-}
-
-#define CCADC_PROGRAM_TRIM_COUNT 2
-#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
-#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
-#define BMS_CONV_IN_PROGRESS 0x2
-
-static int calib_ccadc_program_trim(struct pm8921_bms_chip *chip,
- int addr, u8 data_msb, u8 data_lsb,
- int wait)
-{
- int i, rc, loop;
- u8 cntrl, sbi_config;
- bool in_progress = 0;
-
- loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
-
- calib_ccadc_enable_trim_access(chip, &sbi_config);
-
- for (i = 0; i < loop; i++) {
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
- if (rc < 0) {
- pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
- return rc;
- }
-
- /* break if a ccadc conversion is not happening */
- in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
- & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
-
- if (!in_progress)
- break;
- }
-
- if (in_progress) {
- pr_debug("conv in progress cannot write trim,returing EBUSY\n");
- return -EBUSY;
- }
-
- rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
- if (rc < 0) {
- pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
- return rc;
- }
- rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
- if (rc < 0) {
- pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
- return rc;
- }
- calib_ccadc_restore_trim_access(chip, sbi_config);
- return 0;
-}
-
-static void calib_ccadc(struct pm8921_bms_chip *chip)
-{
- u8 data_msb, data_lsb, sec_cntrl;
- int result_offset, voltage_offset, result_gain;
- u16 result;
- int i, rc;
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_CNTRL, &sec_cntrl);
- if (rc < 0) {
- pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
- return;
- }
-
- rc = calib_ccadc_enable_arbiter(chip);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for offset\n", rc);
- goto bail;
- }
-
- /*
- * Set decimation ratio to 4k, lower ratio may be used in order to speed
- * up, pending verification through bench
- */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
- CCADC_CALIB_DIG_PARAM);
- if (rc < 0) {
- pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
- goto bail;
- }
-
- result_offset = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- /* Short analog inputs to CCADC internally to ground */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_RSV,
- CCADC_CALIB_RSV_GND);
- if (rc < 0) {
- pr_err("error = %d selecting gnd voltage\n", rc);
- goto bail;
- }
-
- /* Enable CCADC */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
- CCADC_CALIB_ANA_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling ccadc\n", rc);
- goto bail;
- }
-
- rc = calib_start_conv(chip, &result);
- if (rc < 0) {
- pr_err("error = %d for zero volt measurement\n", rc);
- goto bail;
- }
-
- result_offset += result;
- }
-
- result_offset = result_offset / SAMPLE_COUNT;
-
- voltage_offset = ccadc_reading_to_microvolt(chip,
- ((s64)result_offset - CCADC_INTRINSIC_OFFSET));
-
- pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
- result_offset, voltage_offset);
-
- /* Sanity Check */
- if (voltage_offset > CCADC_MAX_0UV) {
- pr_err("offset voltage = %d is huge limiting to %d\n",
- voltage_offset, CCADC_MAX_0UV);
- result_offset = CCADC_INTRINSIC_OFFSET
- + microvolt_to_ccadc_reading(chip, (s64)CCADC_MAX_0UV);
- } else if (voltage_offset < CCADC_MIN_0UV) {
- pr_err("offset voltage = %d is too low limiting to %d\n",
- voltage_offset, CCADC_MIN_0UV);
- result_offset = CCADC_INTRINSIC_OFFSET
- + microvolt_to_ccadc_reading(chip, (s64)CCADC_MIN_0UV);
- }
-
- chip->ccadc_result_offset = result_offset;
- data_msb = chip->ccadc_result_offset >> 8;
- data_lsb = chip->ccadc_result_offset;
-
- rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
- data_msb, data_lsb, 1);
- if (rc) {
- pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
- rc, data_msb, data_lsb);
- /* enable the interrupt and write it when it fires */
- pm8921_bms_enable_irq(chip, PM8921_BMS_CCADC_EOC);
- }
-
- rc = calib_ccadc_enable_arbiter(chip);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for gain\n", rc);
- goto bail;
- }
-
- /*
- * Set decimation ratio to 4k, lower ratio may be used in order to speed
- * up, pending verification through bench
- */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
- CCADC_CALIB_DIG_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling decimation ration for gain\n", rc);
- goto bail;
- }
-
- result_gain = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- rc = pm8xxx_writeb(chip->dev->parent,
- ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
- if (rc < 0) {
- pr_err("error = %d selecting 25mV for gain\n", rc);
- goto bail;
- }
-
- /* Enable CCADC */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
- CCADC_CALIB_ANA_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling ccadc\n", rc);
- goto bail;
- }
-
- rc = calib_start_conv(chip, &result);
- if (rc < 0) {
- pr_err("error = %d for adc reading 25mV\n", rc);
- goto bail;
- }
-
- result_gain += result;
- }
- result_gain = result_gain / SAMPLE_COUNT;
-
- /*
- * result_offset includes INTRINSIC OFFSET
- * chip->ccadc_gain_uv will be the actual voltage
- * measured for 25000UV
- */
- chip->ccadc_gain_uv = ccadc_reading_to_microvolt(chip,
- ((s64)result_gain - result_offset));
-
- pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
- result_gain,
- chip->ccadc_gain_uv);
- /* Sanity Check */
- if (chip->ccadc_gain_uv > CCADC_MAX_25MV) {
- pr_err("gain voltage = %d is huge limiting to %d\n",
- chip->ccadc_gain_uv, CCADC_MAX_25MV);
- chip->ccadc_gain_uv = CCADC_MAX_25MV;
- result_gain = result_offset +
- microvolt_to_ccadc_reading(chip, CCADC_MAX_25MV);
- } else if (chip->ccadc_gain_uv < CCADC_MIN_25MV) {
- pr_err("gain voltage = %d is too low limiting to %d\n",
- chip->ccadc_gain_uv, CCADC_MIN_25MV);
- chip->ccadc_gain_uv = CCADC_MIN_25MV;
- result_gain = result_offset +
- microvolt_to_ccadc_reading(chip, CCADC_MIN_25MV);
- }
-
- data_msb = result_gain >> 8;
- data_lsb = result_gain;
- rc = calib_ccadc_program_trim(chip, CCADC_FULLSCALE_TRIM1,
- data_msb, data_lsb, 0);
- if (rc)
- pr_debug("error = %d programming gain trim\n", rc);
-bail:
- pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
-}
-
static void calibrate_ccadc_work(struct work_struct *work)
{
struct pm8921_bms_chip *chip = container_of(work,
struct pm8921_bms_chip, calib_ccadc_work.work);
- calib_ccadc(chip);
+ pm8xxx_calib_ccadc();
schedule_delayed_work(&chip->calib_ccadc_work,
round_jiffies_relative(msecs_to_jiffies
(chip->calib_delay_ms)));
@@ -1810,23 +1363,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
-{
- u8 data_msb, data_lsb;
- struct pm8921_bms_chip *chip = data;
- int rc;
-
- pr_debug("irq = %d triggered\n", irq);
- data_msb = chip->ccadc_result_offset >> 8;
- data_lsb = chip->ccadc_result_offset;
-
- rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
- data_msb, data_lsb, 0);
- pm8921_bms_disable_irq(chip, PM8921_BMS_CCADC_EOC);
-
- return IRQ_HANDLED;
-}
-
struct pm_bms_irq_init_data {
unsigned int irq_id;
char *name;
@@ -1857,8 +1393,6 @@
pm8921_bms_good_ocv_handler),
BMS_IRQ(PM8921_BMS_VSENSE_AVG, IRQF_TRIGGER_RISING,
pm8921_bms_vsense_avg_handler),
- BMS_IRQ(PM8921_BMS_CCADC_EOC, IRQF_TRIGGER_RISING,
- pm8921_bms_ccadc_eoc_handler),
};
static void free_irqs(struct pm8921_bms_chip *chip)
@@ -2076,7 +1610,7 @@
case CALIB_CCADC:
/* reading this will trigger calibration */
*val = 0;
- calib_ccadc(the_chip);
+ pm8xxx_calib_ccadc();
break;
default:
ret = -EINVAL;
@@ -2169,7 +1703,7 @@
{
int i;
- chip->dent = debugfs_create_dir("pm8921_bms", NULL);
+ chip->dent = debugfs_create_dir("pm8921-bms", NULL);
if (IS_ERR(chip->dent)) {
pr_err("pmic bms couldnt create debugfs dir\n");
@@ -2184,20 +1718,6 @@
(void *)BMS_OUTPUT1, ®_fops);
debugfs_create_file("BMS_TEST1", 0644, chip->dent,
(void *)BMS_TEST1, ®_fops);
- debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
- (void *)CCADC_ANA_PARAM, ®_fops);
- debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
- (void *)CCADC_DIG_PARAM, ®_fops);
- debugfs_create_file("CCADC_RSV", 0644, chip->dent,
- (void *)CCADC_RSV, ®_fops);
- debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
- (void *)CCADC_DATA0, ®_fops);
- debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
- (void *)CCADC_DATA1, ®_fops);
- debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
- (void *)CCADC_OFFSET_TRIM1, ®_fops);
- debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
- (void *)CCADC_OFFSET_TRIM0, ®_fops);
debugfs_create_file("test_batt_temp", 0644, chip->dent,
(void *)TEST_BATT_TEMP, &temp_fops);
@@ -2296,7 +1816,6 @@
create_debugfs_entries(chip);
check_initial_ocv(chip);
- chip->ccadc_gain_uv = calib_ccadc_read_gain_uv(chip);
INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
/* begin calibration only on chips > 2.0 */
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 148a5e5..e517146 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -19,6 +19,7 @@
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/interrupt.h>
#include <linux/power_supply.h>
@@ -201,8 +202,8 @@
* @update_time: how frequently the userland needs to be updated
* @max_voltage: the max volts the batt should be charged up to
* @min_voltage: the min battery voltage before turning the FETon
- * @resume_voltage: the voltage at which the battery should resume
- * charging
+ * @resume_voltage_delta: the voltage delta from vdd max at which the
+ * battery should resume charging
* @term_current: The charging based term current
*
*/
@@ -225,7 +226,9 @@
unsigned int warm_bat_chg_current;
unsigned int cool_bat_voltage;
unsigned int warm_bat_voltage;
- unsigned int resume_voltage;
+ unsigned int is_bat_cool;
+ unsigned int is_bat_warm;
+ unsigned int resume_voltage_delta;
unsigned int term_current;
unsigned int vbat_channel;
unsigned int batt_temp_channel;
@@ -935,10 +938,28 @@
return (int)result.physical;
}
+static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
+{
+ unsigned int current_voltage = get_prop_battery_mvolts(chip);
+ unsigned int low_voltage = chip->min_voltage;
+ unsigned int high_voltage = chip->max_voltage;
+
+ if (current_voltage <= low_voltage)
+ return 0;
+ else if (current_voltage >= high_voltage)
+ return 100;
+ else
+ return (current_voltage - low_voltage) * 100
+ / (high_voltage - low_voltage);
+}
+
static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
{
int percent_soc = pm8921_bms_get_percent_charge();
+ if (percent_soc == -ENXIO)
+ percent_soc = voltage_based_capacity(chip);
+
if (percent_soc <= 10)
pr_warn("low battery charge = %d%%\n", percent_soc);
@@ -950,6 +971,10 @@
int result_ma, rc;
rc = pm8921_bms_get_battery_current(&result_ma);
+ if (rc == -ENXIO) {
+ rc = pm8xxx_ccadc_get_battery_current(&result_ma);
+ }
+
if (rc) {
pr_err("unable to get batt current rc = %d\n", rc);
return rc;
@@ -1898,11 +1923,17 @@
the_chip->cool_temp + TEMP_HYSTERISIS_DEGC;
pm_chg_ibatmax_set(the_chip, the_chip->cool_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->cool_bat_voltage
+ - the_chip->resume_voltage_delta);
} else {
btm_config.low_thr_temp = the_chip->cool_temp;
pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->max_voltage - the_chip->resume_voltage_delta);
}
+ the_chip->is_bat_cool = enter;
schedule_work(&btm_config_work);
}
@@ -1914,11 +1945,17 @@
the_chip->warm_temp - TEMP_HYSTERISIS_DEGC;
pm_chg_ibatmax_set(the_chip, the_chip->warm_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->warm_bat_voltage
+ - the_chip->resume_voltage_delta);
} else {
btm_config.high_thr_temp = the_chip->warm_temp;
pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->max_voltage - the_chip->resume_voltage_delta);
}
+ the_chip->is_bat_warm = enter;
schedule_work(&btm_config_work);
}
@@ -2211,10 +2248,11 @@
chip->max_voltage, rc);
return rc;
}
- rc = pm_chg_vbatdet_set(chip, chip->resume_voltage);
+ rc = pm_chg_vbatdet_set(chip,
+ chip->max_voltage - chip->resume_voltage_delta);
if (rc) {
pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
- chip->resume_voltage, rc);
+ chip->max_voltage - chip->resume_voltage_delta, rc);
return rc;
}
@@ -2458,6 +2496,24 @@
}
DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+enum {
+ BAT_WARM_ZONE,
+ BAT_COOL_ZONE,
+};
+static int get_warm_cool(void *data, u64 * val)
+{
+ if (!the_chip) {
+ pr_err("%s called before init\n", __func__);
+ return -EINVAL;
+ }
+ if ((int)data == BAT_WARM_ZONE)
+ *val = the_chip->is_bat_warm;
+ if ((int)data == BAT_COOL_ZONE)
+ *val = the_chip->is_bat_cool;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
+
static void create_debugfs_entries(struct pm8921_chg_chip *chip)
{
int i;
@@ -2524,6 +2580,11 @@
debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
®_loop_fops);
+ debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
+ (void *)BAT_WARM_ZONE, &warm_cool_fops);
+ debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
+ (void *)BAT_COOL_ZONE, &warm_cool_fops);
+
for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
debugfs_create_file(chg_irq_data[i].name, 0444,
@@ -2558,7 +2619,7 @@
chip->update_time = pdata->update_time;
chip->max_voltage = pdata->max_voltage;
chip->min_voltage = pdata->min_voltage;
- chip->resume_voltage = pdata->resume_voltage;
+ chip->resume_voltage_delta = pdata->resume_voltage_delta;
chip->term_current = pdata->term_current;
chip->vbat_channel = pdata->charger_cdata.vbat_channel;
chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
new file mode 100644
index 0000000..1245045
--- /dev/null
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -0,0 +1,761 @@
+/* Copyright (c) 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.
+ *
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#define CCADC_ANA_PARAM 0x240
+#define CCADC_DIG_PARAM 0x241
+#define CCADC_RSV 0x242
+#define CCADC_DATA0 0x244
+#define CCADC_DATA1 0x245
+#define CCADC_OFFSET_TRIM1 0x34A
+#define CCADC_OFFSET_TRIM0 0x34B
+#define CCADC_FULLSCALE_TRIM1 0x34C
+#define CCADC_FULLSCALE_TRIM0 0x34D
+
+/* note : TRIM1 is the msb and TRIM0 is the lsb */
+#define ADC_ARB_SECP_CNTRL 0x190
+#define ADC_ARB_SECP_AMUX_CNTRL 0x191
+#define ADC_ARB_SECP_ANA_PARAM 0x192
+#define ADC_ARB_SECP_DIG_PARAM 0x193
+#define ADC_ARB_SECP_RSV 0x194
+#define ADC_ARB_SECP_DATA1 0x195
+#define ADC_ARB_SECP_DATA0 0x196
+
+#define ADC_ARB_BMS_CNTRL 0x18D
+
+#define START_CONV_BIT BIT(7)
+#define EOC_CONV_BIT BIT(6)
+#define SEL_CCADC_BIT BIT(1)
+#define EN_ARB_BIT BIT(0)
+
+#define CCADC_CALIB_DIG_PARAM 0xE3
+#define CCADC_CALIB_RSV_GND 0x40
+#define CCADC_CALIB_RSV_25MV 0x80
+#define CCADC_CALIB_ANA_PARAM 0x1B
+#define SAMPLE_COUNT 16
+#define ADC_WAIT_COUNT 10
+
+#define CCADC_MAX_25MV 30000
+#define CCADC_MIN_25MV 20000
+#define CCADC_MAX_0UV -4000
+#define CCADC_MIN_0UV -7000
+
+#define CCADC_INTRINSIC_OFFSET 0xC000
+
+struct pm8xxx_ccadc_chip {
+ struct device *dev;
+ struct dentry *dent;
+ u16 ccadc_offset;
+ int ccadc_gain_uv;
+ unsigned int revision;
+ int eoc_irq;
+ int r_sense;
+};
+
+static struct pm8xxx_ccadc_chip *the_chip;
+
+static s64 microvolt_to_ccadc_reading_v1(s64 uv)
+{
+ return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
+ CCADC_READING_RESOLUTION_N_V1);
+}
+
+static s64 microvolt_to_ccadc_reading_v2(s64 uv)
+{
+ return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
+ CCADC_READING_RESOLUTION_N_V2);
+}
+
+static s64 microvolt_to_ccadc_reading(struct pm8xxx_ccadc_chip *chip, s64 cc)
+{
+ /*
+ * resolution (the value of a single bit) was changed after revision 2.0
+ * for more accurate readings
+ */
+ return (the_chip->revision < PM8XXX_REVISION_8921_2p0) ?
+ microvolt_to_ccadc_reading_v1((s64)cc) :
+ microvolt_to_ccadc_reading_v2((s64)cc);
+}
+
+static int cc_adjust_for_offset(u16 raw)
+{
+ /* this has the intrinsic offset */
+ return (int)raw - the_chip->ccadc_offset;
+}
+
+#define GAIN_REFERENCE_UV 25000
+/*
+ * gain compensation for ccadc readings - common for vsense based and
+ * couloumb counter based readings
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+ if (the_chip == NULL || the_chip->ccadc_gain_uv == 0)
+ return uv;
+
+ return div_s64(uv * GAIN_REFERENCE_UV, the_chip->ccadc_gain_uv);
+}
+EXPORT_SYMBOL(pm8xxx_cc_adjust_for_gain);
+
+static int pm_ccadc_masked_write(struct pm8xxx_ccadc_chip *chip, u16 addr,
+ u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = pm8xxx_readb(chip->dev->parent, addr, ®);
+ if (rc) {
+ pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+ reg &= ~mask;
+ reg |= val & mask;
+ rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+ if (rc) {
+ pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+ return 0;
+}
+
+#define REG_SBI_CONFIG 0x04F
+#define PAGE3_ENABLE_MASK 0x6
+static int calib_ccadc_enable_trim_access(struct pm8xxx_ccadc_chip *chip,
+ u8 *sbi_config)
+{
+ u8 reg;
+ int rc;
+
+ rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+ if (rc) {
+ pr_err("error = %d reading sbi config reg\n", rc);
+ return rc;
+ }
+
+ reg = *sbi_config | PAGE3_ENABLE_MASK;
+ return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
+}
+
+static int calib_ccadc_restore_trim_access(struct pm8xxx_ccadc_chip *chip,
+ u8 sbi_config)
+{
+ return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+}
+
+static int calib_ccadc_enable_arbiter(struct pm8xxx_ccadc_chip *chip)
+{
+ int rc;
+
+ /* enable Arbiter, must be sent twice */
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ return rc;
+ }
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
+ return rc;
+ }
+ return 0;
+}
+
+static int calib_start_conv(struct pm8xxx_ccadc_chip *chip,
+ u16 *result)
+{
+ int rc, i;
+ u8 data_msb, data_lsb, reg;
+
+ /* Start conversion */
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ START_CONV_BIT, START_CONV_BIT);
+ if (rc < 0) {
+ pr_err("error = %d starting offset meas\n", rc);
+ return rc;
+ }
+
+ /* Wait for End of conversion */
+ for (i = 0; i < ADC_WAIT_COUNT; i++) {
+ rc = pm8xxx_readb(chip->dev->parent,
+ ADC_ARB_SECP_CNTRL, ®);
+ if (rc < 0) {
+ pr_err("error = %d read eoc for offset\n", rc);
+ return rc;
+ }
+ if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
+ msleep(60);
+ else
+ break;
+ }
+ if (i == ADC_WAIT_COUNT) {
+ pr_err("waited too long for offset eoc\n");
+ return rc;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d reading offset lsb\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
+ if (rc < 0) {
+ pr_err("error = %d reading offset msb\n", rc);
+ return rc;
+ }
+
+ *result = (data_msb << 8) | data_lsb;
+ return 0;
+}
+
+static int calib_ccadc_read_trim(struct pm8xxx_ccadc_chip *chip,
+ int addr, u8 *data_msb, u8 *data_lsb)
+{
+ int rc;
+ u8 sbi_config;
+
+ calib_ccadc_enable_trim_access(chip, &sbi_config);
+ rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
+ if (rc < 0) {
+ pr_err("error = %d read msb\n", rc);
+ return rc;
+ }
+ rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d read lsb\n", rc);
+ return rc;
+ }
+ calib_ccadc_restore_trim_access(chip, sbi_config);
+ return 0;
+}
+
+static void calib_ccadc_read_offset_and_gain(struct pm8xxx_ccadc_chip *chip,
+ int *gain, u16 *offset)
+{
+ s8 data_msb;
+ u8 data_lsb;
+ int rc;
+
+ rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
+ &data_msb, &data_lsb);
+ *gain = (data_msb << 8) | data_lsb;
+
+ rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
+ &data_msb, &data_lsb);
+ *offset = (data_msb << 8) | data_lsb;
+
+ pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", *gain, *offset);
+ *gain = pm8xxx_ccadc_reading_to_microvolt(chip->revision,
+ (s64)*gain - *offset);
+ pr_debug("gain uv = %duV offset=0x%x\n", *gain, *offset);
+}
+
+#define CCADC_PROGRAM_TRIM_COUNT 2
+#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
+#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
+#define BMS_CONV_IN_PROGRESS 0x2
+
+static int calib_ccadc_program_trim(struct pm8xxx_ccadc_chip *chip,
+ int addr, u8 data_msb, u8 data_lsb,
+ int wait)
+{
+ int i, rc, loop;
+ u8 cntrl, sbi_config;
+ bool in_progress = 0;
+
+ loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
+
+ calib_ccadc_enable_trim_access(chip, &sbi_config);
+
+ for (i = 0; i < loop; i++) {
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
+ if (rc < 0) {
+ pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
+ return rc;
+ }
+
+ /* break if a ccadc conversion is not happening */
+ in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
+ & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
+
+ if (!in_progress)
+ break;
+ }
+
+ if (in_progress) {
+ pr_debug("conv in progress cannot write trim,returing EBUSY\n");
+ return -EBUSY;
+ }
+
+ rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
+ if (rc < 0) {
+ pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
+ return rc;
+ }
+ rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
+ return rc;
+ }
+ calib_ccadc_restore_trim_access(chip, sbi_config);
+ return 0;
+}
+
+void pm8xxx_calib_ccadc(void)
+{
+ u8 data_msb, data_lsb, sec_cntrl;
+ int result_offset, voltage_offset, result_gain;
+ u16 result;
+ int i, rc;
+
+ rc = pm8xxx_readb(the_chip->dev->parent,
+ ADC_ARB_SECP_CNTRL, &sec_cntrl);
+ if (rc < 0) {
+ pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
+ return;
+ }
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ goto bail;
+ }
+
+ /*
+ * Set decimation ratio to 4k, lower ratio may be used in order to speed
+ * up, pending verification through bench
+ */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_CALIB_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+ goto bail;
+ }
+
+ result_offset = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ /* Short analog inputs to CCADC internally to ground */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+ CCADC_CALIB_RSV_GND);
+ if (rc < 0) {
+ pr_err("error = %d selecting gnd voltage\n", rc);
+ goto bail;
+ }
+
+ /* Enable CCADC */
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ goto bail;
+ }
+
+ rc = calib_start_conv(the_chip, &result);
+ if (rc < 0) {
+ pr_err("error = %d for zero volt measurement\n", rc);
+ goto bail;
+ }
+
+ result_offset += result;
+ }
+
+ result_offset = result_offset / SAMPLE_COUNT;
+
+ voltage_offset = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ ((s64)result_offset - CCADC_INTRINSIC_OFFSET));
+
+ pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
+ result_offset, voltage_offset);
+
+ /* Sanity Check */
+ if (voltage_offset > CCADC_MAX_0UV) {
+ pr_err("offset voltage = %d is huge limiting to %d\n",
+ voltage_offset, CCADC_MAX_0UV);
+ result_offset = CCADC_INTRINSIC_OFFSET
+ + microvolt_to_ccadc_reading(the_chip,
+ (s64)CCADC_MAX_0UV);
+ } else if (voltage_offset < CCADC_MIN_0UV) {
+ pr_err("offset voltage = %d is too low limiting to %d\n",
+ voltage_offset, CCADC_MIN_0UV);
+ result_offset = CCADC_INTRINSIC_OFFSET
+ + microvolt_to_ccadc_reading(the_chip,
+ (s64)CCADC_MIN_0UV);
+ }
+
+ the_chip->ccadc_offset = result_offset;
+ data_msb = the_chip->ccadc_offset >> 8;
+ data_lsb = the_chip->ccadc_offset;
+
+ rc = calib_ccadc_program_trim(the_chip, CCADC_OFFSET_TRIM1,
+ data_msb, data_lsb, 1);
+ if (rc) {
+ pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
+ rc, data_msb, data_lsb);
+ /* enable the interrupt and write it when it fires */
+ enable_irq(the_chip->eoc_irq);
+ }
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for gain\n", rc);
+ goto bail;
+ }
+
+ /*
+ * Set decimation ratio to 4k, lower ratio may be used in order to speed
+ * up, pending verification through bench
+ */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_CALIB_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling decimation ration for gain\n", rc);
+ goto bail;
+ }
+
+ result_gain = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
+ if (rc < 0) {
+ pr_err("error = %d selecting 25mV for gain\n", rc);
+ goto bail;
+ }
+
+ /* Enable CCADC */
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ goto bail;
+ }
+
+ rc = calib_start_conv(the_chip, &result);
+ if (rc < 0) {
+ pr_err("error = %d for adc reading 25mV\n", rc);
+ goto bail;
+ }
+
+ result_gain += result;
+ }
+ result_gain = result_gain / SAMPLE_COUNT;
+
+ /*
+ * result_offset includes INTRINSIC OFFSET
+ * the_chip->ccadc_gain_uv will be the actual voltage
+ * measured for 25000UV
+ */
+ the_chip->ccadc_gain_uv = pm8xxx_ccadc_reading_to_microvolt(
+ the_chip->revision,
+ ((s64)result_gain - result_offset));
+
+ pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
+ result_gain, the_chip->ccadc_gain_uv);
+ /* Sanity Check */
+ if (the_chip->ccadc_gain_uv > CCADC_MAX_25MV) {
+ pr_err("gain voltage = %d is huge limiting to %d\n",
+ the_chip->ccadc_gain_uv,
+ CCADC_MAX_25MV);
+ the_chip->ccadc_gain_uv = CCADC_MAX_25MV;
+ result_gain = result_offset +
+ microvolt_to_ccadc_reading(the_chip, CCADC_MAX_25MV);
+ } else if (the_chip->ccadc_gain_uv < CCADC_MIN_25MV) {
+ pr_err("gain voltage = %d is too low limiting to %d\n",
+ the_chip->ccadc_gain_uv,
+ CCADC_MIN_25MV);
+ the_chip->ccadc_gain_uv = CCADC_MIN_25MV;
+ result_gain = result_offset +
+ microvolt_to_ccadc_reading(the_chip, CCADC_MIN_25MV);
+ }
+
+ data_msb = result_gain >> 8;
+ data_lsb = result_gain;
+ rc = calib_ccadc_program_trim(the_chip, CCADC_FULLSCALE_TRIM1,
+ data_msb, data_lsb, 0);
+ if (rc)
+ pr_debug("error = %d programming gain trim\n", rc);
+bail:
+ pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
+}
+EXPORT_SYMBOL(pm8xxx_calib_ccadc);
+
+static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
+{
+ u8 data_msb, data_lsb;
+ struct pm8xxx_ccadc_chip *chip = data;
+ int rc;
+
+ pr_debug("irq = %d triggered\n", irq);
+ data_msb = chip->ccadc_offset >> 8;
+ data_lsb = chip->ccadc_offset;
+
+ rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
+ data_msb, data_lsb, 0);
+ disable_irq_nosync(chip->eoc_irq);
+
+ return IRQ_HANDLED;
+}
+
+#define CCADC_IBAT_DIG_PARAM 0xA3
+#define CCADC_IBAT_RSV 0x10
+#define CCADC_IBAT_ANA_PARAM 0x1A
+static int ccadc_get_rsense_voltage(int *voltage_uv)
+{
+ u16 raw;
+ int result;
+ int rc = 0;
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_IBAT_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+ CCADC_IBAT_RSV);
+ if (rc < 0) {
+ pr_err("error = %d selecting rsense\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_IBAT_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ return rc;
+ }
+
+ rc = calib_start_conv(the_chip, &raw);
+ if (rc < 0) {
+ pr_err("error = %d for zero volt measurement\n", rc);
+ return rc;
+ }
+
+ pr_debug("Vsense raw = 0x%x\n", raw);
+ result = cc_adjust_for_offset(raw);
+ pr_debug("Vsense after offset raw = 0x%x offset=0x%x\n",
+ result,
+ the_chip->ccadc_offset);
+ *voltage_uv = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ ((s64)result));
+ pr_debug("Vsense before gain = %d uV\n", *voltage_uv);
+ *voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
+
+ pr_debug("Vsense = %d uV\n", *voltage_uv);
+ return 0;
+}
+
+int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+ int voltage_uv, rc;
+
+ rc = ccadc_get_rsense_voltage(&voltage_uv);
+ if (rc) {
+ pr_err("cant get voltage across rsense rc = %d\n", rc);
+ return rc;
+ }
+
+ *bat_current = voltage_uv/the_chip->r_sense;
+ /*
+ * ccadc reads +ve current when the battery is charging
+ * We need to return -ve if the battery is charging
+ */
+ *bat_current = -1 * (*bat_current);
+ pr_debug("bat current = %d ma\n", *bat_current);
+ return 0;
+}
+EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
+
+static int get_reg(void *data, u64 * val)
+{
+ int addr = (int)data;
+ int ret;
+ u8 temp;
+
+ ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
+ if (ret) {
+ pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
+ addr, temp, ret);
+ return -EAGAIN;
+ }
+ *val = temp;
+ return 0;
+}
+
+static int set_reg(void *data, u64 val)
+{
+ int addr = (int)data;
+ int ret;
+ u8 temp;
+
+ temp = (u8) val;
+ ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
+ if (ret) {
+ pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
+ addr, temp, ret);
+ return -EAGAIN;
+ }
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+
+static int get_calc(void *data, u64 * val)
+{
+ int ibat, rc;
+
+ rc = pm8xxx_ccadc_get_battery_current(&ibat);
+ *val = ibat;
+ return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%lld\n");
+
+static void create_debugfs_entries(struct pm8xxx_ccadc_chip *chip)
+{
+ chip->dent = debugfs_create_dir("pm8xxx-ccadc", NULL);
+
+ if (IS_ERR(chip->dent)) {
+ pr_err("ccadc couldnt create debugfs dir\n");
+ return;
+ }
+
+ debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
+ (void *)CCADC_ANA_PARAM, ®_fops);
+ debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
+ (void *)CCADC_DIG_PARAM, ®_fops);
+ debugfs_create_file("CCADC_RSV", 0644, chip->dent,
+ (void *)CCADC_RSV, ®_fops);
+ debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
+ (void *)CCADC_DATA0, ®_fops);
+ debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
+ (void *)CCADC_DATA1, ®_fops);
+ debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
+ (void *)CCADC_OFFSET_TRIM1, ®_fops);
+ debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
+ (void *)CCADC_OFFSET_TRIM0, ®_fops);
+ debugfs_create_file("CCADC_FULLSCALE_TRIM1", 0644, chip->dent,
+ (void *)CCADC_FULLSCALE_TRIM1, ®_fops);
+ debugfs_create_file("CCADC_FULLSCALE_TRIM0", 0644, chip->dent,
+ (void *)CCADC_FULLSCALE_TRIM0, ®_fops);
+
+ debugfs_create_file("show_ibatt", 0644, chip->dent,
+ (void *)0, &calc_fops);
+}
+
+static int __devinit pm8xxx_ccadc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct pm8xxx_ccadc_chip *chip;
+ struct resource *res;
+ const struct pm8xxx_ccadc_platform_data *pdata
+ = pdev->dev.platform_data;
+
+ if (!pdata) {
+ pr_err("missing platform data\n");
+ return -EINVAL;
+ }
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "PM8921_BMS_CCADC_EOC");
+ if (!res) {
+ pr_err("failed to get irq\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(struct pm8xxx_ccadc_chip), GFP_KERNEL);
+ if (!chip) {
+ pr_err("Cannot allocate pm_bms_chip\n");
+ return -ENOMEM;
+ }
+ chip->dev = &pdev->dev;
+ chip->revision = pm8xxx_get_revision(chip->dev->parent);
+ chip->eoc_irq = res->start;
+ chip->r_sense = pdata->r_sense;
+
+ rc = request_irq(chip->eoc_irq,
+ pm8921_bms_ccadc_eoc_handler, IRQF_TRIGGER_RISING,
+ "bms_eoc_ccadc", chip);
+ if (rc) {
+ pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
+ goto free_chip;
+ }
+
+ platform_set_drvdata(pdev, chip);
+ the_chip = chip;
+
+ create_debugfs_entries(chip);
+
+ calib_ccadc_read_offset_and_gain(chip,
+ &chip->ccadc_gain_uv,
+ &chip->ccadc_offset);
+ return 0;
+
+free_chip:
+ kfree(chip);
+ return rc;
+}
+
+static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_ccadc_chip *chip = platform_get_drvdata(pdev);
+
+ debugfs_remove_recursive(chip->dent);
+ the_chip = NULL;
+ kfree(chip);
+ return 0;
+}
+
+static struct platform_driver pm8xxx_ccadc_driver = {
+ .probe = pm8xxx_ccadc_probe,
+ .remove = __devexit_p(pm8xxx_ccadc_remove),
+ .driver = {
+ .name = PM8XXX_CCADC_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8xxx_ccadc_init(void)
+{
+ return platform_driver_register(&pm8xxx_ccadc_driver);
+}
+
+static void __exit pm8xxx_ccadc_exit(void)
+{
+ platform_driver_unregister(&pm8xxx_ccadc_driver);
+}
+
+module_init(pm8xxx_ccadc_init);
+module_exit(pm8xxx_ccadc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC8XXX ccadc driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_CCADC_DEV_NAME);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4622725..f8b320f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -567,6 +567,7 @@
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
bool session_active;
+ u32 phy_ctrl_val = 0;
if (atomic_read(&motg->in_lpm))
return 0;
@@ -638,8 +639,13 @@
writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
if (motg->caps & ALLOW_PHY_RETENTION && !session_active) {
- writel_relaxed(readl_relaxed(USB_PHY_CTRL) & ~PHY_RETEN,
- USB_PHY_CTRL);
+ phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ /* Enable PHY HV interrupts to wake MPM/Link */
+ phy_ctrl_val |=
+ (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+
+ writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
motg->lpm_flags |= PHY_RETENTIONED;
}
@@ -688,6 +694,7 @@
struct usb_bus *bus = otg->host;
int cnt = 0;
unsigned temp;
+ u32 phy_ctrl_val = 0;
if (!atomic_read(&motg->in_lpm))
return 0;
@@ -711,8 +718,13 @@
if (motg->lpm_flags & PHY_RETENTIONED) {
msm_hsusb_mhl_switch_enable(motg, 1);
msm_hsusb_config_vddcx(1);
- writel_relaxed(readl_relaxed(USB_PHY_CTRL) | PHY_RETEN,
- USB_PHY_CTRL);
+ phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+ phy_ctrl_val |= PHY_RETEN;
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ /* Disable PHY HV interrupts */
+ phy_ctrl_val &=
+ ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+ writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
motg->lpm_flags &= ~PHY_RETENTIONED;
}
@@ -2362,13 +2374,17 @@
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
- if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
- motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+ if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
+ if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
motg->pdata->pmic_id_irq)
- motg->caps = ALLOW_PHY_POWER_COLLAPSE |
+ motg->caps = ALLOW_PHY_POWER_COLLAPSE |
ALLOW_PHY_RETENTION |
ALLOW_PHY_COMP_DISABLE;
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ motg->caps = ALLOW_PHY_RETENTION;
+ }
+
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 4ef0da6..3467e0d 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -3384,35 +3384,35 @@
}
-static uint8 hdmi_msm_avi_iframe_lut[][15] = {
-/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50
- 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9*/
- {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
- {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x18, 0x28}, /*01*/
- {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x88, 0x04}, /*02*/
- {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
- 0x14, 0x20, 0x22, 0x21, 0x01, 0x03}, /*03*/
- {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/
- {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
- 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1}, /*07*/
- {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x01, 0x01}, /*08*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/
- {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1}, /*11*/
- {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x02, 0x02} /*12*/
+static uint8 hdmi_msm_avi_iframe_lut[][16] = {
+/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50
+ 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9 576p50_4_3 */
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
+ {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/
+ {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x88, 0x04, 0x04}, /*02*/
+ {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
+ 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/
+ {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/
+ {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
+ 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41}, /*07*/
+ {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02}, /*08*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/
+ {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1}, /*11*/
+ {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/
};
static void hdmi_msm_avi_info_frame(void)
@@ -3471,6 +3471,9 @@
case HDMI_VFRMT_720x480p60_16_9:
mode = 14;
break;
+ case HDMI_VFRMT_720x576p50_4_3:
+ mode = 15;
+ break;
default:
DEV_INFO("%s: mode %d not supported\n", __func__,
external_common_state->video_resolution);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index ad7fc04..a511e3c 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -35,6 +35,10 @@
#define MDP4_RGB_BASE 0x40000
#define MDP4_RGB_OFF 0x10000
+/* chip select controller */
+#define CS_CONTROLLER_0 0x0707ffff
+#define CS_CONTROLLER_1 0x03073f3f
+
enum {
OVERLAY_PERF_LEVEL1 = 1,
OVERLAY_PERF_LEVEL2,
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 1b80d4c..383a16d 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -43,11 +43,13 @@
struct mdp4_overlay_ctrl {
struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
+ uint32 cs_controller;
uint32 panel_3d;
uint32 panel_mode;
uint32 mixer0_played;
uint32 mixer1_played;
} mdp4_overlay_db = {
+ .cs_controller = CS_CONTROLLER_0,
.plist = {
{
.pipe_type = OVERLAY_TYPE_RGB,
@@ -484,6 +486,7 @@
char *vg_base;
uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
uint32 format, pattern, luma_offset, chroma_offset;
+ uint32 mask;
int pnum, ptype;
pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -574,6 +577,24 @@
1));
}
+ if (mdp_rev > MDP_REV_41) {
+ /* mdp chip select controller */
+ mask = 0;
+ if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+ mask = 0x020; /* bit 5 */
+ else if (pipe->pipe_num == OVERLAY_PIPE_VG2)
+ mask = 0x02000; /* bit 13 */
+ if (mask) {
+ if (pipe->op_mode & MDP4_OP_SCALEY_MN_PHASE)
+ ctrl->cs_controller &= ~mask;
+ else
+ ctrl->cs_controller |= mask;
+ /* NOT double buffered */
+ outpdw(MDP_BASE + 0x00c0, ctrl->cs_controller);
+ }
+ }
+
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp4_stat.pipe[pipe->pipe_num]++;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 143df46..770424a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -615,10 +615,21 @@
void mdp4_dsi_cmd_kickoff_video(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
+ /*
+ * a video kickoff may happen before UI kickoff after
+ * blt enabled. mdp4_overlay_update_dsi_cmd() need
+ * to be called before kickoff.
+ * vice versa for blt disabled.
+ */
if (dsi_pipe->blt_addr && dsi_pipe->blt_cnt == 0)
- mdp4_overlay_update_dsi_cmd(mfd);
+ mdp4_overlay_update_dsi_cmd(mfd); /* first time */
+ else if (dsi_pipe->blt_addr == 0 && dsi_pipe->blt_cnt) {
+ mdp4_overlay_update_dsi_cmd(mfd); /* last time */
+ dsi_pipe->blt_cnt = 0;
+ }
- pr_debug("%s: pid=%d\n", __func__, current->pid);
+ pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
+ __func__, (int)dsi_pipe->blt_addr, dsi_pipe->blt_cnt);
if (dsi_pipe->blt_addr)
mdp4_dsi_blt_dmap_busy_wait(dsi_mfd);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 8370208..f96c7ea 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -258,6 +258,12 @@
mdp4_sw_reset(0x17);
#endif
+ if (mdp_rev > MDP_REV_41) {
+ /* mdp chip select controller */
+ outpdw(MDP_BASE + 0x00c0, CS_CONTROLLER_0);
+ outpdw(MDP_BASE + 0x00c4, CS_CONTROLLER_1);
+ }
+
mdp4_clear_lcdc();
mdp4_mixer_blend_init(0);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 2252c8b..1a606b5 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -428,3 +428,4 @@
header-y += tzcom.h
header-y += qcedev.h
header-y += idle_stats_device.h
+header-y += genlock.h
diff --git a/include/linux/genlock.h b/include/linux/genlock.h
new file mode 100644
index 0000000..2e9f9d6
--- /dev/null
+++ b/include/linux/genlock.h
@@ -0,0 +1,45 @@
+#ifndef _GENLOCK_H_
+#define _GENLOCK_H_
+
+#ifdef __KERNEL__
+
+struct genlock;
+struct genlock_handle;
+
+struct genlock_handle *genlock_get_handle(void);
+struct genlock_handle *genlock_get_handle_fd(int fd);
+void genlock_put_handle(struct genlock_handle *handle);
+struct genlock *genlock_create_lock(struct genlock_handle *);
+struct genlock *genlock_attach_lock(struct genlock_handle *, int fd);
+int genlock_wait(struct genlock_handle *handle, u32 timeout);
+void genlock_release_lock(struct genlock_handle *);
+int genlock_lock(struct genlock_handle *handle, int op, int flags,
+ u32 timeout);
+#endif
+
+#define GENLOCK_UNLOCK 0
+#define GENLOCK_WRLOCK 1
+#define GENLOCK_RDLOCK 2
+
+#define GENLOCK_NOBLOCK (1 << 0)
+
+struct genlock_lock {
+ int fd;
+ int op;
+ int flags;
+ int timeout;
+};
+
+#define GENLOCK_IOC_MAGIC 'G'
+
+#define GENLOCK_IOC_NEW _IO(GENLOCK_IOC_MAGIC, 0)
+#define GENLOCK_IOC_EXPORT _IOR(GENLOCK_IOC_MAGIC, 1, \
+ struct genlock_lock)
+#define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \
+ struct genlock_lock)
+#define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \
+ struct genlock_lock)
+#define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4)
+#define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \
+ struct genlock_lock)
+#endif
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
new file mode 100644
index 0000000..6f6cb39
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -0,0 +1,100 @@
+/* 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 __PMIC8XXX_CCADC_H__
+#define __PMIC8XXX_CCADC_H__
+
+#include <linux/mfd/pm8xxx/core.h>
+
+#define PM8XXX_CCADC_DEV_NAME "pm8xxx-ccadc"
+
+/**
+ * struct pm8xxx_ccadc_platform_data -
+ * @r_sense: sense resistor value in (mOhms)
+ */
+struct pm8xxx_ccadc_platform_data {
+ int r_sense;
+};
+
+#define CCADC_READING_RESOLUTION_N_V1 1085069
+#define CCADC_READING_RESOLUTION_D_V1 100000
+#define CCADC_READING_RESOLUTION_N_V2 542535
+#define CCADC_READING_RESOLUTION_D_V2 100000
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v1(s64 cc)
+{
+ return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
+ CCADC_READING_RESOLUTION_D_V1);
+}
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v2(s64 cc)
+{
+ return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
+ CCADC_READING_RESOLUTION_D_V2);
+}
+
+static inline s64 pm8xxx_ccadc_reading_to_microvolt(int revision, s64 cc)
+{
+ /*
+ * resolution (the value of a single bit) was changed after revision 2.0
+ * for more accurate readings
+ */
+ return (revision < PM8XXX_REVISION_8921_2p0) ?
+ pm8xxx_ccadc_reading_to_microvolt_v1((s64)cc) :
+ pm8xxx_ccadc_reading_to_microvolt_v2((s64)cc);
+}
+
+#if defined(CONFIG_PM8XXX_CCADC) || defined(CONFIG_PM8XXX_CCADC_MODULE)
+/**
+ * pm8xxx_cc_adjust_for_gain - the function to adjust the voltage read from
+ * ccadc for gain compensation
+ * @v: the voltage which needs to be gain compensated in microVolts
+ *
+ *
+ * RETURNS: gain compensated voltage
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv);
+
+/**
+ * pm8xxx_calib_ccadc - calibration for ccadc. This will calculate gain
+ * and offset and reprogram them in the appropriate
+ * registers
+ */
+void pm8xxx_calib_ccadc(void);
+
+/**
+ * pm8xxx_ccadc_get_battery_current - return the battery current based on vsense
+ * resitor in milliamperes
+ * @result: The pointer where the voltage will be updated. A -ve
+ * result means that the current is flowing in
+ * the battery - during battery charging
+ *
+ * RETURNS: Error code if there was a problem reading vsense, Zero otherwise
+ * The result won't be updated in case of an error.
+ *
+ */
+int pm8xxx_ccadc_get_battery_current(int *bat_current);
+#else
+static inline s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+ return -ENXIO;
+}
+static inline void pm8xxx_calib_ccadc(void)
+{
+}
+static inline int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+ return -ENXIO;
+}
+#endif
+
+#endif /* __PMIC8XXX_CCADC_H__ */
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
index 4e2570c..1e1fe6c 100644
--- a/include/linux/mfd/pm8xxx/irq.h
+++ b/include/linux/mfd/pm8xxx/irq.h
@@ -24,6 +24,7 @@
struct pm8xxx_irq_core_data {
u32 rev;
int nirqs;
+ unsigned int base_addr;
};
struct pm8xxx_irq_platform_data {
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 73067b7..f39c00f 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -44,8 +44,8 @@
* @min_voltage: the voltage (mV) where charging method switches from
* trickle to fast. This is also the minimum voltage the
* system operates at
- * @resume_voltage: the voltage (mV) to wait for before resume charging
- * after the battery has been fully charged
+ * @resume_voltage_delta: the (mV) drop to wait for before resume charging
+ * after the battery has been fully charged
* @term_current: the charger current (mA) at which EOC happens
* @cool_temp: the temperature (degC) at which the battery is
* considered cool charging current and voltage is reduced
@@ -91,7 +91,7 @@
unsigned int update_time;
unsigned int max_voltage;
unsigned int min_voltage;
- unsigned int resume_voltage;
+ unsigned int resume_voltage_delta;
unsigned int term_current;
unsigned int cool_temp;
unsigned int warm_temp;
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 64bdab1..2c931b6 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -35,6 +35,7 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/leds-pm8xxx.h>
#include <linux/mfd/pm8xxx/vibrator.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#define PM8921_NR_IRQS 256
@@ -128,6 +129,7 @@
struct pm8921_adc_platform_data *adc_pdata;
struct pm8xxx_led_platform_data *leds_pdata;
struct pm8xxx_vibrator_platform_data *vibrator_pdata;
+ struct pm8xxx_ccadc_platform_data *ccadc_pdata;
};
#endif
diff --git a/include/linux/mfd/wcd9310/core.h b/include/linux/mfd/wcd9310/core.h
index 2d03c95..0eb875c 100644
--- a/include/linux/mfd/wcd9310/core.h
+++ b/include/linux/mfd/wcd9310/core.h
@@ -19,6 +19,9 @@
#define TABLA_SLIM_NUM_PORT_REG 3
+#define TABLA_INTERFACE_TYPE_SLIMBUS 0x00
+#define TABLA_INTERFACE_TYPE_I2C 0x01
+
enum {
TABLA_IRQ_SLIMBUS = 0,
TABLA_IRQ_MBHC_REMOVAL,
@@ -82,6 +85,7 @@
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);
static inline int tabla_request_irq(struct tabla *tabla, int irq,
irq_handler_t handler, const char *name,
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 9cb8356..fcd91da 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -51,6 +51,8 @@
#define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */
#define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */
#define PHY_RETEN (1 << 1) /* PHY retention enable/disable */
+#define PHY_IDHV_INTEN (1 << 8) /* PHY ID HV interrupt */
+#define PHY_OTGSESSVLDHV_INTEN (1 << 9) /* PHY Session Valid HV int. */
/* OTG definitions */
#define OTGSC_INTSTS_MASK (0x7f << 16)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b7bbe02..a27358f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -612,6 +612,8 @@
static int hci_dev_do_close(struct hci_dev *hdev)
{
+ unsigned long keepflags = 0;
+
BT_DBG("%s %p", hdev->name, hdev);
hci_req_cancel(hdev, ENODEV);
@@ -669,8 +671,15 @@
if (hdev->dev_type == HCI_BREDR)
mgmt_powered(hdev->id, 0);
- /* Clear flags */
- hdev->flags = 0;
+ /* Clear only non-persistent flags */
+ if (test_bit(HCI_MGMT, &hdev->flags))
+ set_bit(HCI_MGMT, &keepflags);
+ if (test_bit(HCI_LINK_KEYS, &hdev->flags))
+ set_bit(HCI_LINK_KEYS, &keepflags);
+ if (test_bit(HCI_DEBUG_KEYS, &hdev->flags))
+ set_bit(HCI_DEBUG_KEYS, &keepflags);
+
+ hdev->flags = keepflags;
hci_req_unlock(hdev);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 16bb5ea..c4b9950 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1203,6 +1203,7 @@
if (list_empty(&s->dlcs)) {
s->state = BT_DISCONN;
rfcomm_send_disc(s, 0);
+ rfcomm_session_clear_timer(s);
}
break;
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 97c08c0..cbe2eae 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -54,7 +54,6 @@
"inode.c:72",
"inode.c:73",
"inode.c:74",
- "menu.c:128",
"msm_sdcc.c:126",
"msm_sdcc.c:128",
"nf_conntrack_netlink.c:790",
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 7f7bdc9..d330f7a 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -14,12 +14,15 @@
#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/wcd9310/core.h>
#include <linux/mfd/wcd9310/registers.h>
#include <linux/mfd/wcd9310/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -39,6 +42,8 @@
#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
+#define TABLA_I2S_MASTER_MODE_MASK 0x08
+
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);
@@ -87,6 +92,9 @@
u8 cfilt_k_value;
bool mbhc_micbias_switched;
+ /*track tabla 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
@@ -1426,6 +1434,12 @@
break;
}
}
+static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
+ 0, NULL, 0),
+};
static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
/*RX stuff */
@@ -1438,6 +1452,8 @@
SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ 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),
/* Headphone */
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
@@ -1701,6 +1717,19 @@
SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
};
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+ {"RX_I2S_CLK", NULL, "CDC_CONN"},
+ {"SLIM RX1", NULL, "RX_I2S_CLK"},
+ {"SLIM RX2", NULL, "RX_I2S_CLK"},
+ {"SLIM RX3", NULL, "RX_I2S_CLK"},
+ {"SLIM RX4", NULL, "RX_I2S_CLK"},
+
+ {"SLIM TX7", NULL, "TX_I2S_CLK"},
+ {"SLIM TX8", NULL, "TX_I2S_CLK"},
+ {"SLIM TX9", NULL, "TX_I2S_CLK"},
+ {"SLIM TX10", NULL, "TX_I2S_CLK"},
+};
+
static const struct snd_soc_dapm_route audio_map[] = {
/* SLIMBUS Connections */
@@ -1814,45 +1843,73 @@
{"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"},
{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX4 MIX1 INP1", "IIR1", "IIR1"},
{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX4 MIX1 INP2", "IIR1", "IIR1"},
{"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX5 MIX1 INP1", "IIR1", "IIR1"},
{"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX5 MIX1 INP2", "IIR1", "IIR1"},
{"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX6 MIX1 INP1", "IIR1", "IIR1"},
{"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX6 MIX1 INP2", "IIR1", "IIR1"},
{"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX7 MIX1 INP1", "IIR1", "IIR1"},
{"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX7 MIX1 INP2", "IIR1", "IIR1"},
/* Decimator Inputs */
@@ -2191,7 +2248,39 @@
static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
+ u8 val = 0;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
+
pr_debug("%s\n", __func__);
+ 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 (dai->id == TABLA_TX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL,
+ TABLA_I2S_MASTER_MODE_MASK, 0);
+ else if (dai->id == TABLA_RX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL,
+ TABLA_I2S_MASTER_MODE_MASK, 0);
+ }
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* CPU is slave */
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ val = TABLA_I2S_MASTER_MODE_MASK;
+ if (dai->id == TABLA_TX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
+ else if (dai->id == TABLA_RX_DAI_ID)
+ snd_soc_update_bits(dai->codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -2200,6 +2289,7 @@
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
+ struct tabla_priv *tabla = 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;
@@ -2255,6 +2345,25 @@
0x03, tx_fs_rate);
}
}
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
+ 0x03, tx_fs_rate);
+ }
}
/**
@@ -2281,6 +2390,25 @@
0xE0, rx_fs_rate);
}
}
+ if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
+ 0x03, (rx_fs_rate >> 0x05));
+ }
}
return 0;
@@ -2324,6 +2452,37 @@
.ops = &tabla_dai_ops,
},
};
+
+static struct snd_soc_dai_driver tabla_i2s_dai[] = {
+ {
+ .name = "tabla_i2s_rx1",
+ .id = 1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9310_RATES,
+ .formats = TABLA_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &tabla_dai_ops,
+ },
+ {
+ .name = "tabla_i2s_tx1",
+ .id = 2,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD9310_RATES,
+ .formats = TABLA_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &tabla_dai_ops,
+ },
+};
static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
{
u8 bias_msb, bias_lsb;
@@ -3186,6 +3345,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_update_reg_defaults(codec);
tabla_codec_init_reg(codec);
@@ -3204,6 +3364,12 @@
ARRAY_SIZE(tabla_snd_controls));
snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
ARRAY_SIZE(tabla_dapm_widgets));
+ if (tabla->intf_type == TABLA_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,
+ ARRAY_SIZE(audio_i2s_map));
+ }
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_sync(dapm);
@@ -3362,13 +3528,19 @@
static int __devinit tabla_probe(struct platform_device *pdev)
{
+ int ret = 0;
#ifdef CONFIG_DEBUG_FS
debugfs_poke = debugfs_create_file("TRRS",
S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
#endif
- return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
- tabla_dai, ARRAY_SIZE(tabla_dai));
+ if (tabla_get_intf_type() == TABLA_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)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
+ tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
+ return ret;
}
static int __devexit tabla_remove(struct platform_device *pdev)
{