Merge "msm: clock-8610: add clocks for mobicore driver"
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
index 3d70a9b..2b25fcb 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
@@ -32,6 +32,10 @@
- qcom,enable-time: Time in us to delay after enabling the regulator
- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load
which requires the regulator to be in high power mode.
+- qcom,apps-only: Flag which indicates that the regulator only has
+ consumers on the application processor. If this flag
+ is specified, then voltage and current updates are
+ only sent to the RPM if the regulator is enabled.
[Second Level Nodes]
@@ -84,6 +88,7 @@
current updates are only sent if the given
regulator has also been enabled by a Linux
consumer.
+
The following properties specify initial values for parameters to be sent to the
RPM in regulator requests.
- qcom,init-enable: 0 = regulator disabled
diff --git a/Documentation/devicetree/bindings/input/misc/hbtp_input.txt b/Documentation/devicetree/bindings/input/misc/hbtp_input.txt
new file mode 100644
index 0000000..54643c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/hbtp_input.txt
@@ -0,0 +1,14 @@
+Platform device for Host Based Touch Processing (hbtp)
+
+Required properties:
+
+ - compatible : should be "qcom,hbtp"
+ - vcc_ana-supply : Analog power supply needed to power device
+
+Example:
+ &soc {
+ hbtp {
+ compatible = "qcom,hbtp";
+ vcc_ana-supply = <&pm8941_l18>;
+ };
+ };
diff --git a/arch/arm/boot/dts/msm8926-v2.dtsi b/arch/arm/boot/dts/msm8926-v2.dtsi
index b8f7e2a..55f4608 100644
--- a/arch/arm/boot/dts/msm8926-v2.dtsi
+++ b/arch/arm/boot/dts/msm8926-v2.dtsi
@@ -16,3 +16,52 @@
qcom,msm-id = <200 0x20000>,
<224 0x20000>;
};
+
+&msm_gpu {
+ /* Updated chip ID */
+ qcom,chipid = <0x03000512>;
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>, <89 604 0 0>,
+ <26 512 0 1800000>, <89 604 0 3200000>,
+ <26 512 0 3600000>, <89 604 0 5120000>,
+ <26 512 0 4800000>, <89 604 0 6400000>;
+
+ /* Power levels */
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <500000000>;
+ qcom,bus-freq = <3>;
+ qcom,io-fraction = <0>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <320000000>;
+ qcom,bus-freq = <2>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <200000000>;
+ qcom,bus-freq = <1>;
+ qcom,io-fraction = <100>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <19000000>;
+ qcom,bus-freq = <0>;
+ qcom,io-fraction = <0>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
new file mode 100644
index 0000000..f4f7968
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
@@ -0,0 +1,42 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974pro-ab-pm8941.dtsi"
+/include/ "msm8974-fluid.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974Pro-AA/AB FLUID";
+ compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
+ qcom,board-id = <3 1>;
+};
+
+&soc {
+ spi@f9966000 { /* BLSP2 QUP4 */
+ /* Leave the SPI bus for QDSP to use */
+ status = "disabled";
+ };
+
+ hbtp {
+ compatible = "qcom,hbtp";
+ vcc_ana-supply = <&pm8941_l18>;
+ };
+};
+
+&i2c_0 {
+ /* mhl-sii8334 is on i2c_0 and uses gpio 12 as mhl-pwr-gpio.
+ * Display panel needs gpio 12 as TE gpio in command mode.
+ * Disabling the bus to make sure that display gets the gpio.
+ */
+ status = "disabled";
+};
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 5904aea..915b1c3 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -295,6 +295,7 @@
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_UINPUT=y
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 1f7eb49..f1c285d 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -301,6 +301,7 @@
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_UINPUT=y
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index e9f4b01..c0e9efc 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -69,6 +69,7 @@
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-cdp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-fluid-hbtp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ac-pm8941-cdp.dtb
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index 7995e9a..c7e9e75 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -163,6 +163,7 @@
struct mutex mlock;
unsigned long flags;
bool sleep_request_sent;
+ bool apps_only;
struct msm_rpm_request *handle_active;
struct msm_rpm_request *handle_sleep;
};
@@ -241,6 +242,16 @@
& BIT(RPM_REGULATOR_PARAM_ENABLE)));
}
+static inline bool rpm_vreg_shared_active_or_sleep_enabled_valid
+ (struct rpm_vreg *rpm_vreg)
+{
+ return !rpm_vreg->apps_only &&
+ ((rpm_vreg->aggr_req_active.valid
+ & BIT(RPM_REGULATOR_PARAM_ENABLE))
+ || (rpm_vreg->aggr_req_sleep.valid
+ & BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
/*
* This is used when voting for LPM or HPM by subtracting or adding to the
* hpm_min_load of a regulator. It has units of uA.
@@ -660,7 +671,8 @@
* if the regulator has been configured to always send voltage updates.
*/
if (reg->always_send_voltage
- || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+ || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+ || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
rc = rpm_vreg_aggregate_requests(reg);
if (rc) {
@@ -719,7 +731,8 @@
* updates.
*/
if (reg->always_send_voltage
- || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+ || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+ || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
rc = rpm_vreg_aggregate_requests(reg);
if (rc) {
@@ -774,7 +787,8 @@
* voltage updates.
*/
if (reg->always_send_voltage
- || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+ || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+ || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
rc = rpm_vreg_aggregate_requests(reg);
if (rc) {
@@ -829,7 +843,8 @@
* current updates.
*/
if (reg->always_send_current
- || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+ || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+ || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
rc = rpm_vreg_aggregate_requests(reg);
if (rc) {
@@ -1579,6 +1594,7 @@
of_property_read_u32(node, "qcom,enable-time", &rpm_vreg->enable_time);
of_property_read_u32(node, "qcom,hpm-min-load",
&rpm_vreg->hpm_min_load);
+ rpm_vreg->apps_only = of_property_read_bool(node, "qcom,apps-only");
rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE,
resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 10eaf4e..0d88689 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2336,15 +2336,33 @@
const char *buf, size_t count)
{
struct adreno_device *adreno_dev = _get_adreno_dev(dev);
- int ret;
+ int ret = 0;
+ unsigned int policy = 0;
if (adreno_dev == NULL)
return 0;
mutex_lock(&adreno_dev->dev.mutex);
- ret = _ft_sysfs_store(buf, count, &adreno_dev->ft_pf_policy);
+
+ /* MMU option changed call function to reset MMU options */
+ if (count != _ft_sysfs_store(buf, count, &policy))
+ ret = -EINVAL;
+
+ if (!ret) {
+ policy &= (KGSL_FT_PAGEFAULT_INT_ENABLE |
+ KGSL_FT_PAGEFAULT_GPUHALT_ENABLE |
+ KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE |
+ KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT);
+ ret = kgsl_mmu_set_pagefault_policy(&(adreno_dev->dev.mmu),
+ adreno_dev->ft_pf_policy);
+ if (!ret)
+ adreno_dev->ft_pf_policy = policy;
+ }
mutex_unlock(&adreno_dev->dev.mutex);
- return ret;
+ if (!ret)
+ return count;
+ else
+ return 0;
}
/**
@@ -2635,12 +2653,56 @@
return status;
}
-static int adreno_setproperty(struct kgsl_device *device,
+static int adreno_set_constraint(struct kgsl_device *device,
+ struct kgsl_context *context,
+ struct kgsl_device_constraint *constraint)
+{
+ int status = 0;
+
+ switch (constraint->type) {
+ case KGSL_CONSTRAINT_PWRLEVEL: {
+ struct kgsl_device_constraint_pwrlevel pwr;
+
+ if (constraint->size != sizeof(pwr)) {
+ status = -EINVAL;
+ break;
+ }
+
+ if (copy_from_user(&pwr,
+ (void __user *)constraint->data,
+ sizeof(pwr))) {
+ status = -EFAULT;
+ break;
+ }
+ if (pwr.level >= KGSL_CONSTRAINT_PWR_MAXLEVELS) {
+ status = -EINVAL;
+ break;
+ }
+
+ context->pwr_constraint.type =
+ KGSL_CONSTRAINT_PWRLEVEL;
+ context->pwr_constraint.sub_type = pwr.level;
+ }
+ break;
+ case KGSL_CONSTRAINT_NONE:
+ context->pwr_constraint.type = KGSL_CONSTRAINT_NONE;
+ break;
+
+ default:
+ status = -EINVAL;
+ break;
+ }
+
+ return status;
+}
+
+static int adreno_setproperty(struct kgsl_device_private *dev_priv,
enum kgsl_property_type type,
void *value,
unsigned int sizebytes)
{
int status = -EINVAL;
+ struct kgsl_device *device = dev_priv->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
switch (type) {
@@ -2678,6 +2740,28 @@
status = 0;
}
break;
+ case KGSL_PROP_PWR_CONSTRAINT: {
+ struct kgsl_device_constraint constraint;
+ struct kgsl_context *context;
+
+ if (sizebytes != sizeof(constraint))
+ break;
+
+ if (copy_from_user(&constraint, value,
+ sizeof(constraint))) {
+ status = -EFAULT;
+ break;
+ }
+
+ context = kgsl_context_get_owner(dev_priv,
+ constraint.context_id);
+ if (context == NULL)
+ break;
+ status = adreno_set_constraint(device, context,
+ &constraint);
+ kgsl_context_put(context);
+ }
+ break;
default:
break;
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 1b5573f..4db045a 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -271,15 +271,13 @@
}
static int _check_global_timestamp(struct kgsl_device *device,
- unsigned int timestamp)
+ struct adreno_context *drawctxt, unsigned int timestamp)
{
- int ret;
+ /* Stop waiting if the context is invalidated */
+ if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
+ return 1;
- mutex_lock(&device->mutex);
- ret = kgsl_check_timestamp(device, NULL, timestamp);
- mutex_unlock(&device->mutex);
-
- return ret;
+ return kgsl_check_timestamp(device, NULL, timestamp);
}
int adreno_drawctxt_wait_global(struct adreno_device *adreno_dev,
@@ -288,7 +286,7 @@
{
struct kgsl_device *device = &adreno_dev->dev;
struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
- int ret;
+ int ret = 0;
/* Needs to hold the device mutex */
BUG_ON(!mutex_is_locked(&device->mutex));
@@ -298,6 +296,15 @@
goto done;
}
+ /*
+ * If the context is invalid then return immediately - we may end up
+ * waiting for a timestamp that will never come
+ */
+ if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
+ kgsl_context_put(context);
+ goto done;
+ }
+
trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp);
ret = kgsl_add_event(device, KGSL_MEMSTORE_GLOBAL, timestamp,
@@ -311,7 +318,7 @@
if (timeout) {
ret = (int) wait_event_timeout(drawctxt->waiting,
- _check_global_timestamp(device, timestamp),
+ _check_global_timestamp(device, drawctxt, timestamp),
msecs_to_jiffies(timeout));
if (ret == 0)
@@ -320,7 +327,7 @@
ret = 0;
} else {
wait_event(drawctxt->waiting,
- _check_global_timestamp(device, timestamp));
+ _check_global_timestamp(device, drawctxt, timestamp));
}
mutex_lock(&device->mutex);
@@ -425,7 +432,8 @@
KGSL_CONTEXT_PER_CONTEXT_TS |
KGSL_CONTEXT_USER_GENERATED_TS |
KGSL_CONTEXT_NO_FAULT_TOLERANCE |
- KGSL_CONTEXT_TYPE_MASK);
+ KGSL_CONTEXT_TYPE_MASK |
+ KGSL_CONTEXT_PWR_CONSTRAINT);
/* Always enable per-context timestamps */
drawctxt->base.flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index b23d3ab..8d7b803 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1132,6 +1132,65 @@
return ret;
}
+unsigned int adreno_ringbuffer_get_constraint(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ unsigned int pwrlevel = device->pwrctrl.active_pwrlevel;
+
+ switch (context->pwr_constraint.type) {
+ case KGSL_CONSTRAINT_PWRLEVEL: {
+ switch (context->pwr_constraint.sub_type) {
+ case KGSL_CONSTRAINT_PWR_MAX:
+ pwrlevel = device->pwrctrl.max_pwrlevel;
+ break;
+ case KGSL_CONSTRAINT_PWR_MIN:
+ pwrlevel = device->pwrctrl.min_pwrlevel;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ }
+
+ return pwrlevel;
+}
+
+void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch)
+{
+ unsigned int constraint;
+ struct kgsl_context *context = cmdbatch->context;
+ /*
+ * Check if the context has a constraint and constraint flags are
+ * set.
+ */
+ if (context->pwr_constraint.type &&
+ ((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
+ (cmdbatch->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) {
+
+ constraint = adreno_ringbuffer_get_constraint(device, context);
+
+ /*
+ * If a constraint is already set, set a new
+ * constraint only if it is faster
+ */
+ if ((device->pwrctrl.constraint.type ==
+ KGSL_CONSTRAINT_NONE) || (constraint <
+ device->pwrctrl.constraint.hint.pwrlevel.level)) {
+
+ kgsl_pwrctrl_pwrlevel_change(device, constraint);
+ device->pwrctrl.constraint.type =
+ context->pwr_constraint.type;
+ device->pwrctrl.constraint.hint.
+ pwrlevel.level = constraint;
+ }
+
+ }
+
+}
+
/* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */
int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
struct kgsl_cmdbatch *cmdbatch)
@@ -1242,6 +1301,9 @@
test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
+ /* Set the constraints before adding to ringbuffer */
+ adreno_ringbuffer_set_constraint(device, cmdbatch);
+
ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
flags,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 1743e4a..11b7429 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1379,8 +1379,8 @@
if (dev_priv->device->ftbl->setproperty)
result = dev_priv->device->ftbl->setproperty(
- dev_priv->device, param->type,
- param->value, param->sizebytes);
+ dev_priv, param->type, param->value,
+ param->sizebytes);
return result;
}
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7fc6fae..7d009ce 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -129,7 +129,7 @@
void (*drawctxt_destroy) (struct kgsl_context *context);
long (*ioctl) (struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
- int (*setproperty) (struct kgsl_device *device,
+ int (*setproperty) (struct kgsl_device_private *dev_priv,
enum kgsl_property_type type, void *value,
unsigned int sizebytes);
int (*postmortem_dump) (struct kgsl_device *device, int manual);
@@ -349,6 +349,7 @@
* @pagefault_ts: global timestamp of the pagefault, if KGSL_CONTEXT_PAGEFAULT
* is set.
* @flags: flags from userspace controlling the behavior of this context
+ * @pwr_constraint: power constraint from userspace for this context
*/
struct kgsl_context {
struct kref refcount;
@@ -366,6 +367,7 @@
struct list_head events_list;
unsigned int pagefault_ts;
unsigned int flags;
+ struct kgsl_pwr_constraint pwr_constraint;
};
/**
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 8f65705..0a7ba30 100755
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -2103,6 +2103,72 @@
return iommu->unit_count;
}
+/*
+ * kgsl_iommu_set_pf_policy() - Set the pagefault policy for IOMMU
+ * @mmu: Pointer to mmu structure
+ * @pf_policy: The pagefault polict to set
+ *
+ * Check if the new policy indicated by pf_policy is same as current
+ * policy, if same then return else set the policy
+ */
+static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu,
+ unsigned int pf_policy)
+{
+ int i, j;
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(mmu->device);
+ int ret = 0;
+ unsigned int sctlr_val;
+
+ if ((adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) ==
+ (pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE))
+ return ret;
+ if (msm_soc_version_supports_iommu_v0())
+ return ret;
+
+ ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+
+ if (ret) {
+ KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+ return ret;
+ }
+ ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
+
+ if (ret) {
+ KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+ kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+ return ret;
+ }
+ /* Need to idle device before changing options */
+ ret = mmu->device->ftbl->idle(mmu->device);
+ if (ret) {
+ kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+ return ret;
+ }
+
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++) {
+ sctlr_val = KGSL_IOMMU_GET_CTX_REG(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ SCTLR);
+ if (pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+ sctlr_val &= ~(0x1 <<
+ KGSL_IOMMU_SCTLR_HUPCF_SHIFT);
+ else
+ sctlr_val |= (0x1 <<
+ KGSL_IOMMU_SCTLR_HUPCF_SHIFT);
+ KGSL_IOMMU_SET_CTX_REG(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ SCTLR, sctlr_val);
+ }
+ }
+ kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+ return ret;
+}
+
struct kgsl_mmu_ops iommu_ops = {
.mmu_init = kgsl_iommu_init,
.mmu_close = kgsl_iommu_close,
@@ -2128,6 +2194,7 @@
.mmu_cleanup_pt = NULL,
.mmu_sync_lock = kgsl_iommu_sync_lock,
.mmu_sync_unlock = kgsl_iommu_sync_unlock,
+ .mmu_set_pf_policy = kgsl_iommu_set_pf_policy,
};
struct kgsl_mmu_pt_ops iommu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 8bc9962..040a3a7 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -173,6 +173,7 @@
unsigned int (*mmu_sync_unlock)
(struct kgsl_mmu *mmu, unsigned int *cmds);
int (*mmu_hw_halt_supported)(struct kgsl_mmu *mmu, int iommu_unit_num);
+ int (*mmu_set_pf_policy)(struct kgsl_mmu *mmu, unsigned int pf_policy);
};
struct kgsl_mmu_pt_ops {
@@ -477,4 +478,13 @@
return 0;
}
+static inline int kgsl_mmu_set_pagefault_policy(struct kgsl_mmu *mmu,
+ unsigned int pf_policy)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_set_pf_policy)
+ return mmu->mmu_ops->mmu_set_pf_policy(mmu, pf_policy);
+ else
+ return 0;
+}
+
#endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 6ec809d..c811b78 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -27,6 +27,9 @@
#define KGSL_MAX_CLKS 6
+/* Only two supported levels, min & max */
+#define KGSL_CONSTRAINT_PWR_MAXLEVELS 2
+
struct platform_device;
struct kgsl_clk_stats {
@@ -40,6 +43,16 @@
unsigned int elapsed_old;
};
+struct kgsl_pwr_constraint {
+ unsigned int type;
+ unsigned int sub_type;
+ union {
+ struct {
+ unsigned int level;
+ } pwrlevel;
+ } hint;
+};
+
/**
* struct kgsl_pwrctrl - Power control settings for a KGSL device
* @interrupt_num - The interrupt number for the device
@@ -67,6 +80,7 @@
* @bus_control - true if the bus calculation is independent
* @bus_index - default bus index into the bus_ib table
* @bus_ib - the set of unique ib requests needed for the bus calculation
+ * @constraint - currently active power constraint
*/
struct kgsl_pwrctrl {
@@ -98,6 +112,7 @@
int bus_mod;
unsigned int bus_index[KGSL_MAX_PWRLEVELS];
uint64_t bus_ib[KGSL_MAX_PWRLEVELS];
+ struct kgsl_pwr_constraint constraint;
};
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 52732cf..acee4d4 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -228,6 +228,10 @@
}
kgsl_pwrctrl_pwrlevel_change(device, level);
+
+ /*Invalidate the constraint set */
+ pwr->constraint.type = KGSL_CONSTRAINT_NONE;
+
*freq = kgsl_pwrctrl_active_freq(pwr);
mutex_unlock(&device->mutex);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 716ea0d..0c22694 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -73,6 +73,16 @@
To compile this driver as a module, choose M here: the
module will be called bma150.
+config INPUT_HBTP_INPUT
+ tristate "HBTP input driver support"
+ help
+ Say Y to enable HBTP input driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hbtp_input.
+
+endif
+
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@@ -714,4 +724,3 @@
To compile this driver as a module, choose M here: the
module will be called CM36283.
-endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index c927e0e..c9a65fc 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -26,6 +26,7 @@
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
obj-$(CONFIG_INPUT_GPIO) += gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o
+obj-$(CONFIG_INPUT_HBTP_INPUT) += hbtp_input.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
obj-$(CONFIG_INPUT_KEYCHORD) += keychord.o
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
new file mode 100644
index 0000000..83ba652
--- /dev/null
+++ b/drivers/input/misc/hbtp_input.c
@@ -0,0 +1,477 @@
+
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/hbtp_input.h>
+#include <linux/input/mt.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include "../input-compat.h"
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#endif
+
+#define HBTP_INPUT_NAME "hbtp_input"
+#define HBTP_AFE_LOAD_UA 150000
+#define HBTP_AFE_VTG_MIN_UV 2700000
+#define HBTP_AFE_VTG_MAX_UV 3300000
+
+struct hbtp_data {
+ struct platform_device *pdev;
+ struct input_dev *input_dev;
+ s32 count;
+ bool touch_status[HBTP_MAX_FINGER];
+#if defined(CONFIG_FB)
+ struct notifier_block fb_notif;
+#endif
+ struct regulator *vcc_ana;
+};
+
+static struct hbtp_data *hbtp;
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ int blank;
+ struct fb_event *evdata = data;
+ struct hbtp_data *hbtp_data =
+ container_of(self, struct hbtp_data, fb_notif);
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+ hbtp_data && hbtp_data->input_dev) {
+ blank = *(int *)(evdata->data);
+ if (blank == FB_BLANK_UNBLANK)
+ kobject_uevent(&hbtp_data->input_dev->dev.kobj,
+ KOBJ_ONLINE);
+ else if (blank == FB_BLANK_POWERDOWN)
+ kobject_uevent(&hbtp_data->input_dev->dev.kobj,
+ KOBJ_OFFLINE);
+ }
+
+ return 0;
+}
+#endif
+
+static int hbtp_input_open(struct inode *inode, struct file *file)
+{
+ if (hbtp->count) {
+ pr_err("%s is busy\n", HBTP_INPUT_NAME);
+ return -EBUSY;
+ }
+ hbtp->count++;
+
+ return 0;
+}
+
+static int hbtp_input_release(struct inode *inode, struct file *file)
+{
+ if (!hbtp->count) {
+ pr_err("%s wasn't opened\n", HBTP_INPUT_NAME);
+ return -ENOTTY;
+ }
+ hbtp->count--;
+
+ return 0;
+}
+
+static int hbtp_input_create_input_dev(struct hbtp_input_absinfo *absinfo)
+{
+ struct input_dev *input_dev;
+ struct hbtp_input_absinfo *abs;
+ int error;
+ int i;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ pr_err("%s: input_allocate_device failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ kfree(input_dev->name);
+ input_dev->name = kstrndup(HBTP_INPUT_NAME, sizeof(HBTP_INPUT_NAME),
+ GFP_KERNEL);
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+ /* For multi touch */
+ input_mt_init_slots(input_dev, HBTP_MAX_FINGER);
+ for (i = 0; i <= ABS_MT_LAST - ABS_MT_FIRST; i++) {
+ abs = absinfo + i;
+ if (abs->active)
+ input_set_abs_params(input_dev, abs->code,
+ abs->minimum, abs->maximum, 0, 0);
+ }
+
+ error = input_register_device(input_dev);
+ if (error) {
+ pr_err("%s: input_register_device failed\n", __func__);
+ goto err_input_reg_dev;
+ }
+
+ hbtp->input_dev = input_dev;
+ return 0;
+
+err_input_reg_dev:
+ input_free_device(input_dev);
+
+ return error;
+}
+
+static int hbtp_input_report_events(struct hbtp_data *hbtp_data,
+ struct hbtp_input_mt *mt_data)
+{
+ int i;
+ struct hbtp_input_touch *tch;
+
+ for (i = 0; i < HBTP_MAX_FINGER; i++) {
+ tch = &(mt_data->touches[i]);
+ if (tch->active || hbtp_data->touch_status[i]) {
+ input_mt_slot(hbtp_data->input_dev, i);
+ input_mt_report_slot_state(hbtp_data->input_dev,
+ MT_TOOL_FINGER, tch->active);
+
+ if (tch->active) {
+ input_report_abs(hbtp_data->input_dev,
+ ABS_MT_TOOL_TYPE,
+ tch->tool);
+ input_report_abs(hbtp_data->input_dev,
+ ABS_MT_TOUCH_MAJOR,
+ tch->major);
+ input_report_abs(hbtp_data->input_dev,
+ ABS_MT_TOUCH_MINOR,
+ tch->minor);
+ input_report_abs(hbtp_data->input_dev,
+ ABS_MT_ORIENTATION,
+ tch->orientation);
+ input_report_abs(hbtp_data->input_dev,
+ ABS_MT_PRESSURE,
+ tch->pressure);
+ input_report_abs(hbtp_data->input_dev,
+ ABS_MT_POSITION_X,
+ tch->x);
+ input_report_abs(hbtp_data->input_dev,
+ ABS_MT_POSITION_Y,
+ tch->y);
+ }
+ hbtp_data->touch_status[i] = tch->active;
+ }
+ }
+
+ input_report_key(hbtp->input_dev, BTN_TOUCH, mt_data->num_touches > 0);
+ input_sync(hbtp->input_dev);
+
+ return 0;
+}
+
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
+{
+ return (regulator_count_voltages(reg) > 0) ?
+ regulator_set_optimum_mode(reg, load_uA) : 0;
+}
+
+static int hbtp_pdev_power_on(struct hbtp_data *hbtp, bool on)
+{
+ int ret, error;
+
+ if (!hbtp->vcc_ana) {
+ pr_err("%s: regulator is not available\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!on)
+ goto reg_off;
+
+ ret = reg_set_optimum_mode_check(hbtp->vcc_ana, HBTP_AFE_LOAD_UA);
+ if (ret < 0) {
+ pr_err("%s: Regulator vcc_ana set_opt failed rc=%d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = regulator_enable(hbtp->vcc_ana);
+ if (ret) {
+ pr_err("%s: Regulator vcc_ana enable failed rc=%d\n",
+ __func__, ret);
+ error = -EINVAL;
+ goto error_reg_en_vcc_ana;
+ }
+
+ return 0;
+
+error_reg_en_vcc_ana:
+ reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
+ return error;
+
+reg_off:
+ reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
+ regulator_disable(hbtp->vcc_ana);
+ return 0;
+}
+
+static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd,
+ unsigned long arg, void __user *p)
+{
+ int error;
+ struct hbtp_input_mt mt_data;
+ struct hbtp_input_absinfo absinfo[ABS_MT_LAST - ABS_MT_FIRST + 1];
+ enum hbtp_afe_power_cmd power_cmd;
+
+ switch (cmd) {
+ case HBTP_SET_ABSPARAM:
+ if (hbtp && hbtp->input_dev) {
+ pr_err("%s: The input device is already created\n",
+ __func__);
+ return 0;
+ }
+
+ if (copy_from_user(absinfo, (void *)arg,
+ sizeof(struct hbtp_input_absinfo) *
+ (ABS_MT_LAST - ABS_MT_FIRST + 1))) {
+ pr_err("%s: Error copying data for ABS param\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ error = hbtp_input_create_input_dev(absinfo);
+ if (error)
+ pr_err("%s, hbtp_input_create_input_dev failed (%d)\n",
+ __func__, error);
+ break;
+
+ case HBTP_SET_TOUCHDATA:
+ if (!hbtp || !hbtp->input_dev) {
+ pr_err("%s: The input device hasn't been created\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&mt_data, (void *)arg,
+ sizeof(struct hbtp_input_mt))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+
+ hbtp_input_report_events(hbtp, &mt_data);
+ error = 0;
+ break;
+
+ case HBTP_SET_POWERSTATE:
+ if (!hbtp || !hbtp->input_dev) {
+ pr_err("%s: The input device hasn't been created\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&power_cmd, (void *)arg,
+ sizeof(enum hbtp_afe_power_cmd))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+
+ switch (power_cmd) {
+ case HBTP_AFE_POWER_ON:
+ error = hbtp_pdev_power_on(hbtp, true);
+ if (error)
+ pr_err("%s: failed to power on\n", __func__);
+ break;
+ case HBTP_AFE_POWER_OFF:
+ error = hbtp_pdev_power_on(hbtp, false);
+ if (error)
+ pr_err("%s: failed to power off\n", __func__);
+ break;
+ default:
+ pr_err("%s: Unsupported command for power state, %d\n",
+ __func__, power_cmd);
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd);
+ error = -EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+static long hbtp_input_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return hbtp_input_ioctl_handler(file, cmd, arg, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long hbtp_input_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return hbtp_input_ioctl_handler(file, cmd, arg, compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations hbtp_input_fops = {
+ .owner = THIS_MODULE,
+ .open = hbtp_input_open,
+ .release = hbtp_input_release,
+ .unlocked_ioctl = hbtp_input_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hbtp_input_compat_ioctl,
+#endif
+};
+
+static struct miscdevice hbtp_input_misc = {
+ .fops = &hbtp_input_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = HBTP_INPUT_NAME,
+};
+MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR);
+MODULE_ALIAS("devname:" HBTP_INPUT_NAME);
+
+static int __devinit hbtp_pdev_probe(struct platform_device *pdev)
+{
+ int ret, error;
+ struct regulator *vcc_ana;
+
+ vcc_ana = regulator_get(&pdev->dev, "vcc_ana");
+ if (IS_ERR(vcc_ana)) {
+ ret = PTR_ERR(vcc_ana);
+ pr_err("%s: Regulator get failed vcc_ana rc=%d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ if (regulator_count_voltages(vcc_ana) > 0) {
+ ret = regulator_set_voltage(vcc_ana,
+ HBTP_AFE_VTG_MIN_UV, HBTP_AFE_VTG_MAX_UV);
+ if (ret) {
+ pr_err("%s: regulator set_vtg failed rc=%d\n",
+ __func__, ret);
+ error = -EINVAL;
+ goto error_set_vtg_vcc_ana;
+ }
+ }
+
+ hbtp->vcc_ana = vcc_ana;
+ hbtp->pdev = pdev;
+ return 0;
+
+error_set_vtg_vcc_ana:
+ regulator_put(vcc_ana);
+
+ return error;
+};
+
+static int __devexit hbtp_pdev_remove(struct platform_device *pdev)
+{
+ if (hbtp->vcc_ana) {
+ hbtp_pdev_power_on(hbtp, false);
+ regulator_put(hbtp->vcc_ana);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id hbtp_match_table[] = {
+ { .compatible = "qcom,hbtp",},
+ { },
+};
+#else
+#define hbtp_match_table NULL
+#endif
+
+static struct platform_driver hbtp_pdev_driver = {
+ .probe = hbtp_pdev_probe,
+ .remove = __devexit_p(hbtp_pdev_remove),
+ .driver = {
+ .name = "hbtp",
+ .owner = THIS_MODULE,
+ .of_match_table = hbtp_match_table,
+ },
+};
+
+static int __init hbtp_init(void)
+{
+ int error;
+
+ hbtp = kzalloc(sizeof(struct hbtp_data), GFP_KERNEL);
+ if (!hbtp)
+ return -ENOMEM;
+
+ error = misc_register(&hbtp_input_misc);
+ if (error) {
+ pr_err("%s: misc_register failed\n", HBTP_INPUT_NAME);
+ goto err_misc_reg;
+ }
+
+#if defined(CONFIG_FB)
+ hbtp->fb_notif.notifier_call = fb_notifier_callback;
+ error = fb_register_client(&hbtp->fb_notif);
+ if (error) {
+ pr_err("%s: Unable to register fb_notifier: %d\n",
+ HBTP_INPUT_NAME, error);
+ goto err_fb_reg;
+ }
+#endif
+
+ error = platform_driver_register(&hbtp_pdev_driver);
+ if (error) {
+ pr_err("Failed to register platform driver: %d\n", error);
+ goto err_platform_drv_reg;
+ }
+
+ return 0;
+
+err_platform_drv_reg:
+#if defined(CONFIG_FB)
+ fb_unregister_client(&hbtp->fb_notif);
+err_fb_reg:
+#endif
+ misc_deregister(&hbtp_input_misc);
+err_misc_reg:
+ kfree(hbtp);
+
+ return error;
+}
+
+static void __exit hbtp_exit(void)
+{
+ misc_deregister(&hbtp_input_misc);
+ if (hbtp->input_dev)
+ input_unregister_device(hbtp->input_dev);
+
+#if defined(CONFIG_FB)
+ fb_unregister_client(&hbtp->fb_notif);
+#endif
+
+ platform_driver_unregister(&hbtp_pdev_driver);
+
+ kfree(hbtp);
+}
+
+MODULE_DESCRIPTION("Kernel driver to support host based touch processing");
+MODULE_LICENSE("GPLv2");
+
+module_init(hbtp_init);
+module_exit(hbtp_exit);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 4640d3b..6d18d0f 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -146,6 +146,7 @@
header-y += genetlink.h
header-y += gfs2_ondisk.h
header-y += gigaset_dev.h
+header-y += hbtp_input.h
header-y += hdlc.h
header-y += hdlcdrv.h
header-y += hdreg.h
diff --git a/include/linux/hbtp_input.h b/include/linux/hbtp_input.h
new file mode 100644
index 0000000..2c3798e
--- /dev/null
+++ b/include/linux/hbtp_input.h
@@ -0,0 +1,46 @@
+#ifndef _HBTP_INPUT_H
+#define _HBTP_INPUT_H
+
+#include <linux/input.h>
+
+#define HBTP_MAX_FINGER 10
+
+struct hbtp_input_touch {
+ bool active;
+ __s32 tool;
+ __s32 x;
+ __s32 y;
+ __s32 pressure;
+ __s32 major;
+ __s32 minor;
+ __s32 orientation;
+};
+
+struct hbtp_input_mt {
+ __s32 num_touches;
+ struct hbtp_input_touch touches[HBTP_MAX_FINGER];
+};
+
+struct hbtp_input_absinfo {
+ bool active;
+ __u16 code;
+ __s32 minimum;
+ __s32 maximum;
+};
+
+enum hbtp_afe_power_cmd {
+ HBTP_AFE_POWER_ON,
+ HBTP_AFE_POWER_OFF,
+};
+
+/* ioctl */
+#define HBTP_INPUT_IOCTL_BASE 'T'
+#define HBTP_SET_ABSPARAM _IOW(HBTP_INPUT_IOCTL_BASE, 201, \
+ struct hbtp_input_absinfo *)
+#define HBTP_SET_TOUCHDATA _IOW(HBTP_INPUT_IOCTL_BASE, 202, \
+ struct hbtp_input_mt)
+#define HBTP_SET_POWERSTATE _IOW(HBTP_INPUT_IOCTL_BASE, 203, \
+ enum hbtp_afe_power_cmd)
+
+#endif /* _HBTP_INPUT_H */
+
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index f74fcbe..17986b5 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -24,6 +24,7 @@
#define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
#define KGSL_CONTEXT_SYNC 0x00000400
+#define KGSL_CONTEXT_PWR_CONSTRAINT 0x00000800
/* bits [12:15] are reserved for future use */
#define KGSL_CONTEXT_TYPE_MASK 0x01F00000
#define KGSL_CONTEXT_TYPE_SHIFT 20
@@ -197,6 +198,7 @@
KGSL_PROP_VERSION = 0x00000008,
KGSL_PROP_GPU_RESET_STAT = 0x00000009,
KGSL_PROP_PWRCTRL = 0x0000000E,
+ KGSL_PROP_PWR_CONSTRAINT = 0x00000012,
};
struct kgsl_shadowprop {
@@ -882,6 +884,34 @@
#define IOCTL_KGSL_SUBMIT_COMMANDS \
_IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands)
+/**
+ * struct kgsl_device_constraint - device constraint argument
+ * @context_id: KGSL context ID
+ * @type: type of constraint i.e pwrlevel/none
+ * @data: constraint data
+ * @size: size of the constraint data
+ */
+struct kgsl_device_constraint {
+ unsigned int type;
+ unsigned int context_id;
+ void __user *data;
+ size_t size;
+};
+
+/* Constraint Type*/
+#define KGSL_CONSTRAINT_NONE 0
+#define KGSL_CONSTRAINT_PWRLEVEL 1
+
+/* PWRLEVEL constraint level*/
+/* set to min frequency */
+#define KGSL_CONSTRAINT_PWR_MIN 0
+/* set to max frequency */
+#define KGSL_CONSTRAINT_PWR_MAX 1
+
+struct kgsl_device_constraint_pwrlevel {
+ unsigned int level;
+};
+
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 97c7b5d..e3c8944 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -86,6 +86,10 @@
struct voip_frame_hdr {
uint32_t timestamp;
union {
+ /*
+ * Bits 0-15: Frame type
+ * Bits 16-31: Frame rate
+ */
uint32_t frame_type;
uint32_t packet_rate;
};
@@ -162,8 +166,6 @@
struct snd_ctl_elem_value *ucontrol);
static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
-static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
@@ -277,7 +279,7 @@
SOC_SINGLE_EXT("Voip Mode Config", SND_SOC_NOPM, 0, VOIP_MODE_MAX, 0,
msm_voip_mode_config_get, msm_voip_mode_config_put),
SOC_SINGLE_EXT("Voip Rate Config", SND_SOC_NOPM, 0, VOIP_RATE_MAX, 0,
- msm_voip_rate_config_get, msm_voip_rate_config_put),
+ NULL, msm_voip_rate_config_put),
SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
0, VOC_1_RATE, 0, 2, msm_voip_evrc_min_max_rate_config_get,
msm_voip_evrc_min_max_rate_config_put),
@@ -385,6 +387,8 @@
struct voip_buf_node *buf_node = NULL;
struct voip_drv_info *prtd = private_data;
unsigned long dsp_flags;
+ uint32_t rate_type;
+ uint32_t frame_rate;
if (prtd->playback_substream == NULL)
return;
@@ -408,7 +412,19 @@
* Bits 4-7: Frame type
*/
*voc_pkt = ((buf_node->frame.frm_hdr.frame_type &
- 0x0F) << 4) | (prtd->rate_type & 0x0F);
+ 0x0F) << 4);
+ frame_rate = (buf_node->frame.frm_hdr.frame_type &
+ 0xFFFF0000) >> 16;
+ if (frame_rate) {
+ if (voip_get_rate_type(prtd->mode, frame_rate,
+ &rate_type)) {
+ pr_err("%s(): fail at getting rate_type \n",
+ __func__);
+ } else
+ prtd->rate_type = rate_type;
+ }
+ *voc_pkt |= prtd->rate_type & 0x0F;
+
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
memcpy(voc_pkt,
&buf_node->frame.voc_pkt[0],
@@ -1087,30 +1103,43 @@
return 0;
}
-static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- mutex_lock(&voip_info.lock);
-
- ucontrol->value.integer.value[0] = voip_info.rate;
-
- mutex_unlock(&voip_info.lock);
-
- return 0;
-}
-
static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ int ret = 0;
+ int rate = ucontrol->value.integer.value[0];
+
mutex_lock(&voip_info.lock);
- voip_info.rate = ucontrol->value.integer.value[0];
+ if (voip_info.rate != rate) {
+ voip_info.rate = rate;
+ pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
- pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
+ if (voip_info.state == VOIP_STARTED &&
+ (voip_info.mode == MODE_AMR ||
+ voip_info.mode == MODE_AMR_WB)) {
+ ret = voip_config_vocoder(
+ voip_info.capture_substream);
+ if (ret) {
+ pr_err("%s:Failed to configure vocoder, ret=%d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ret = voc_update_amr_vocoder_rate(
+ voc_get_session_id(VOIP_SESSION_NAME));
+ if (ret) {
+ pr_err("%s:Failed to update AMR rate, ret=%d\n",
+ __func__, ret);
+ }
+ }
+ }
+
+done:
mutex_unlock(&voip_info.lock);
- return 0;
+ return ret;
}
static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 5580dc7..06ee692 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1494,6 +1494,77 @@
return ret;
}
+static int voice_config_cvs_vocoder_amr_rate(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ pr_debug("%s: Setting AMR rate. Media Type: %d\n", __func__,
+ common.mvs_info.media_type);
+
+ cvs_set_amr_rate.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+ cvs_set_amr_rate.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+ cvs_set_amr_rate.hdr.token = 0;
+
+ if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_NB_MODEM)
+ cvs_set_amr_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+ else if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_WB_MODEM)
+ cvs_set_amr_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+
+ cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_AMR_RATE\n",
+ __func__, ret);
+
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ return 0;
+done:
+ return ret;
+}
+
static int voice_config_cvs_vocoder(struct voice_data *v)
{
int ret = 0;
@@ -1598,80 +1669,13 @@
break;
}
- case VSS_MEDIA_ID_AMR_NB_MODEM: {
- struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
-
- pr_debug("Setting AMR rate\n");
-
- cvs_set_amr_rate.hdr.hdr_field =
- APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
- cvs_set_amr_rate.hdr.src_port =
- voice_get_idx_for_session(v->session_id);
- cvs_set_amr_rate.hdr.dest_port = cvs_handle;
- cvs_set_amr_rate.hdr.token = 0;
- cvs_set_amr_rate.hdr.opcode =
- VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
- cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
-
- v->cvs_state = CMD_STATUS_FAIL;
-
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_AMR_RATE\n",
- __func__, ret);
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
-
- ret = voice_set_dtx(v);
- if (ret < 0)
- goto fail;
-
- break;
- }
+ case VSS_MEDIA_ID_AMR_NB_MODEM:
case VSS_MEDIA_ID_AMR_WB_MODEM: {
- struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
-
- pr_debug("Setting AMR WB rate\n");
-
- cvs_set_amrwb_rate.hdr.hdr_field =
- APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_amrwb_rate) -
- APR_HDR_SIZE);
- cvs_set_amrwb_rate.hdr.src_port =
- voice_get_idx_for_session(v->session_id);
- cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
- cvs_set_amrwb_rate.hdr.token = 0;
- cvs_set_amrwb_rate.hdr.opcode =
- VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
- cvs_set_amrwb_rate.amrwb_rate.mode = common.mvs_info.rate;
-
- v->cvs_state = CMD_STATUS_FAIL;
-
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amrwb_rate);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_AMRWB_RATE\n",
+ ret = voice_config_cvs_vocoder_amr_rate(v);
+ if (ret) {
+ pr_err("%s: Failed to update vocoder rate. %d\n",
__func__, ret);
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
+
goto fail;
}
@@ -1698,6 +1702,31 @@
return -EINVAL;
}
+int voc_update_amr_vocoder_rate(uint32_t session_id)
+{
+ int ret = 0;
+ struct voice_data *v;
+
+ pr_debug("%s: session_id:%d", __func__, session_id);
+
+ v = voice_get_session(session_id);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL, session_id:%d\n", __func__,
+ session_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&v->lock);
+ ret = voice_config_cvs_vocoder_amr_rate(v);
+ mutex_unlock(&v->lock);
+
+done:
+ return ret;
+}
+
static int voice_send_start_voice_cmd(struct voice_data *v)
{
struct apr_hdr mvm_start_voice_cmd;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 5c0cf21..9efc9fc 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1465,5 +1465,6 @@
int voc_start_record(uint32_t port_id, uint32_t set, uint32_t session_id);
int voice_get_idx_for_session(u32 session_id);
int voc_set_ext_ec_ref(uint16_t port_id, bool state);
+int voc_update_amr_vocoder_rate(uint32_t session_id);
#endif