Merge "common: add dma_mmap_from_coherent() function" into msm-3.4
diff --git a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
index c58e073..31c3bc2 100644
--- a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
+++ b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
@@ -94,7 +94,7 @@
QPNP_PIN_OUT_STRENGTH_MED = 2, (GPIO)
QPNP_PIN_OUT_STRENGTH_HIGH = 3, (GPIO)
- - qcom,select: select a function for the pin. Certain pins
+ - qcom,src-select: select a function for the pin. Certain pins
can be paired (shorted) with each other. Some gpio pins
can act as alternate functions.
In the context of gpio, this acts as a source select.
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 2e7f9c3..46b39ec 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -2,38 +2,93 @@
The qpnp-power-on is a driver which supports the power-on(PON)
peripheral on Qualcomm PMICs. The supported functionality includes
-power on/off reason, power-key press/release detection and other PON
-features. This peripheral is connected to the host processor via the SPMI
-interface.
+power on/off reason, key press/release detection, PMIC reset configurations
+and other PON specifc features. The PON module supports multiple physical
+power-on (KPDPWR_N, CBLPWR) and reset (KPDPWR_N, RESIN, KPDPWR+RESIN) sources.
+This peripheral is connected to the host processor via the SPMI interface.
Required properties:
- compatible: Must be "qcom,qpnp-power-on"
- reg: Specifies the SPMI address and size for this PON (power-on) peripheral
-- interrupts: Specifies the interrupt associated with the power-key.
+- interrupts: Specifies the interrupt associated with PON.
Optional properties:
-- qcom,pon-key-enable: Enable power-key detection. It enables monitoring
- of the KPDPWR_N line (connected to the power-key).
-- qcom,pon-key-dbc-delay: The debouce delay for the power-key interrupt
+- qcom,pon-dbc-delay: The debouce delay for the power-key interrupt
specifed in us. The value ranges from 2 seconds
to 1/64 of a second. Possible values are -
- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
- Intermediate value is rounded down to the
nearest valid value.
-- qcom,pon-key-pull-up: The intial state of the KPDPWR_N pin
- (connected to the power-key)
+- qcom,pon_1 ...pon_n These represent the child nodes which describe
+ the properties (reset, key) for each of the pon
+ reset source. All the child nodes are optional,
+ if none of them are specified the driver fails
+ to register.
+
+All the below properties are in the sub-node section (properties of the child
+node).
+
+- qcom,pull-up: The initial state of the reset pin under
+ consideration.
0 = No pull-up
1 = pull-up enabled
-
-If any of the above optional property is not defined, the driver will continue
-with the default hardware state.
+ This property is optional and is set to '0'
+ if not specified.
+- qcom,pon-type The type of PON/RESET source. The driver
+ currently supports KPDPWR(0) and RESIN(1)
+ pon/reset sources. This property must be
+ specified.
+- qcom,support-reset Indicates if this PON source supports
+ reset functionality.
+ 0 = Not supported
+ 1 = Supported
+ This property is optional and is set to '0'
+ if not specified.
+- qcom,s1-timer The debouce timer for the BARK interrupt for
+ that reset source. Value is specified in ms.
+ Supported values are -
+ - 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
+ 1352, 2048, 3072, 4480, 6720, 10256
+ This property must be specified only if
+ 'support-reset' is set to 1.
+- qcom,s2-timer The debouce timer for the S2 reset specified
+ in ms. On the expiry of this timer, the PMIC
+ executes the reset sequence. Supoprted values -
+ - 0, 10, 50, 100, 250, 500, 1000, 2000
+ This property is required only if
+ 'support-reset' is set to 1.
+- qcom,s2-type The type of reset associated with this source.
+ The supported resets are -
+ SOFT(0), WARM(1), SHUTDOWN(4), HARD(7)
+ This property is required only if
+ 'support-reset' is set to 1.
+- linux,code The input key-code associated with the reset source.
+ The reset source in its default configuration can be
+ used to support standard keys. This property is optional.
Example:
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
- interrupts = <0x0 0x8 0x1>;
- qcom,pon-key-enable= <true>;
- qcom,pon-key-pull-up = <true>;
- qcom,pon-key-dbc-delay = <15625>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>;
+ interrupt-names = "kpdpwr", "resin", "resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,support-reset = <1>;
+ qcom,pull-up = <1>;
+ qcom,s1-timer = <3072>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <1>;
+ linux,code = <114>;
+ };
}
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ee0a264..84bc68b 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -25,11 +25,27 @@
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
- interrupts = <0x0 0x8 0x0>;
- interrupt-names = "power-key";
- qcom,pon-key-enable = <1>;
- qcom,pon-key-dbc-delay = <15625>;
- qcom,pon-key-pull-up = <1>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>;
+ interrupt-names = "kpdpwr", "resin", "resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,support-reset = <1>;
+ qcom,pull-up = <1>;
+ qcom,s1-timer = <0>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <1>;
+ linux,code = <114>;
+ };
};
pm8941_gpios {
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index 323fac4..5d93fa3 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -25,14 +25,26 @@
};
gpio@c200 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
gpio@c300 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
gpio@c400 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c5b53d7..0431af8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -85,7 +85,8 @@
usb@f9a55000 {
compatible = "qcom,hsusb-otg";
reg = <0xf9a55000 0x400>;
- interrupts = <0 134 0>;
+ interrupts = <0 134 0 0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
HSUSB_VDDCX-supply = <&pm8841_s2>;
HSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_3p3-supply = <&pm8941_l24>;
@@ -788,6 +789,37 @@
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
};
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
};
/include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
index 42425ed..041b4dd 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -76,4 +76,26 @@
interrupts = <0 247 0>;
interrupt-names = "bam_irq";
};
+
+ spi@f9928000 {
+ compatible = "qcom,spi-qup-v2";
+ reg = <0xf9928000 0x1000>;
+ interrupts = <0 100 0>;
+ spi-max-frequency = <24000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 23 0>, /* CLK */
+ <&msmgpio 21 0>, /* MISO */
+ <&msmgpio 20 0>; /* MOSI */
+
+ cs-gpios = <&msmgpio 69 0>;
+
+ ethernet-switch@0 {
+ compatible = "simtec,ks8851";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <75 0>;
+ spi-max-frequency = <5000000>;
+ };
+ };
};
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 3854403..3fad6b7 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -59,7 +59,7 @@
CONFIG_MACH_MPQ8064_HRD=y
CONFIG_MACH_MPQ8064_DTV=y
# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 06501ba..cd79e98 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -58,7 +58,7 @@
CONFIG_MACH_MPQ8064_HRD=y
CONFIG_MACH_MPQ8064_DTV=y
# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c73c62e..0405d1b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -55,6 +55,7 @@
CONFIG_MSM_OCMEM_DEBUG=y
CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
@@ -125,6 +126,7 @@
# CONFIG_MSM_RMNET is not set
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 9094db7..446734f 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -56,9 +56,28 @@
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_MSM_NAND is not set
CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
# CONFIG_ANDROID_PMEM is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
@@ -70,6 +89,9 @@
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_HW_RANDOM=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 43c627d..23d310d 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -208,11 +208,11 @@
unsigned long ctrl;
ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
- ctrl |= ARCH_TIMER_CTRL_ENABLE;
- ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
-
+ ctrl &= ~(ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK);
arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
arch_specific_timer->reg_write(ARCH_TIMER_REG_TVAL, evt);
+ ctrl |= ARCH_TIMER_CTRL_ENABLE;
+ arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
return 0;
}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5331f2c..145375d 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -890,12 +890,15 @@
default "0x40200000" if ARCH_MSM8X60
default "0x10000000"
-config KERNEL_PMEM_EBI_REGION
- bool "Enable in-kernel PMEM region for EBI"
+config KERNEL_MSM_CONTIG_MEM_REGION
+ bool "Enable in-kernel contiguous memory region"
default y if ARCH_MSM8X60
depends on ANDROID_PMEM && (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974)
help
- Enable the in-kernel PMEM allocator to use EBI memory.
+ Enable the in-kernel contiguous memory allocator. Sets up a
+ region of physically contiguous memory. This memory is
+ reserved during initialization, and can be used
+ generically.
config KERNEL_PMEM_SMI_REGION
bool "Enable in-kernel PMEM region for SMI"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 7fea137..83e559f 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -287,7 +287,7 @@
obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
-obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-dt.o board-8974-regulator.o board-8974-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-dt.o board-8974-gpiomux.o
obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index b35e949..04e751a 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -47,16 +47,29 @@
#define BAM_MUX_HDR_CMD_STATUS 3 /* unused */
#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC 4
-#define POLLING_MIN_SLEEP 950 /* 0.95 ms */
-#define POLLING_MAX_SLEEP 1050 /* 1.05 ms */
-#define POLLING_INACTIVITY 40 /* cycles before switch to intr mode */
#define LOW_WATERMARK 2
#define HIGH_WATERMARK 4
+#define DEFAULT_POLLING_MIN_SLEEP (950)
+#define MAX_POLLING_SLEEP (6050)
+#define MIN_POLLING_SLEEP (950)
static int msm_bam_dmux_debug_enable;
module_param_named(debug_enable, msm_bam_dmux_debug_enable,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MIN_SLEEP = 950;
+module_param_named(min_sleep, POLLING_MIN_SLEEP,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MAX_SLEEP = 1050;
+module_param_named(max_sleep, POLLING_MAX_SLEEP,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_INACTIVITY = 40;
+module_param_named(inactivity, POLLING_INACTIVITY,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int bam_adaptive_timer_enabled = 1;
+module_param_named(adaptive_timer_enabled,
+ bam_adaptive_timer_enabled,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
#if defined(DEBUG)
static uint32_t bam_dmux_read_cnt;
@@ -177,6 +190,7 @@
static int bam_mux_initialized;
static int polling_mode;
+static unsigned long rx_timer_interval;
static LIST_HEAD(bam_rx_pool);
static DEFINE_MUTEX(bam_rx_pool_mutexlock);
@@ -1116,6 +1130,7 @@
struct rx_pkt_info *info;
int inactive_cycles = 0;
int ret;
+ u32 buffs_unused, buffs_used;
while (bam_connection_is_active) { /* timer loop */
++inactive_cycles;
@@ -1162,12 +1177,47 @@
handle_bam_mux_cmd(&info->work);
}
- if (inactive_cycles == POLLING_INACTIVITY) {
+ if (inactive_cycles >= POLLING_INACTIVITY) {
rx_switch_to_interrupt_mode();
break;
}
- usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+ if (bam_adaptive_timer_enabled) {
+ usleep_range(rx_timer_interval, rx_timer_interval + 50);
+
+ ret = sps_get_unused_desc_num(bam_rx_pipe,
+ &buffs_unused);
+
+ if (ret) {
+ pr_err("%s: error getting num buffers unused after sleep\n",
+ __func__);
+
+ break;
+ }
+
+ buffs_used = NUM_BUFFERS - buffs_unused;
+
+ if (buffs_unused == 0) {
+ rx_timer_interval = MIN_POLLING_SLEEP;
+ } else {
+ if (buffs_used > 0) {
+ rx_timer_interval =
+ (2 * NUM_BUFFERS *
+ rx_timer_interval)/
+ (3 * buffs_used);
+ } else {
+ rx_timer_interval =
+ MAX_POLLING_SLEEP;
+ }
+ }
+
+ if (rx_timer_interval > MAX_POLLING_SLEEP)
+ rx_timer_interval = MAX_POLLING_SLEEP;
+ else if (rx_timer_interval < MIN_POLLING_SLEEP)
+ rx_timer_interval = MIN_POLLING_SLEEP;
+ } else {
+ usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+ }
}
}
@@ -2379,6 +2429,8 @@
bam_dmux_state_logging_disabled = 1;
}
+ rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
+
subsys_notif_register_notifier("modem", &restart_notifier);
return platform_driver_register(&bam_dmux_driver);
}
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index da0fd31..5780ca1 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -236,18 +236,9 @@
.name = "mdp",
};
-static int mdp_core_clk_rate_table[] = {
- 59080000,
- 128000000,
- 160000000,
- 200000000,
-};
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
- .mdp_core_clk_rate = 59080000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
.mdp_rev = MDP_REV_44,
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -1026,8 +1017,6 @@
*/
static void set_mdp_clocks_for_wuxga(void)
{
- int i;
-
mdp_ui_vectors[0].ab = 2000000000;
mdp_ui_vectors[0].ib = 2000000000;
mdp_vga_vectors[0].ab = 2000000000;
@@ -1037,11 +1026,6 @@
mdp_1080p_vectors[0].ab = 2000000000;
mdp_1080p_vectors[0].ib = 2000000000;
- mdp_pdata.mdp_core_clk_rate = 200000000;
-
- for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
- mdp_core_clk_rate_table[i] = 200000000;
-
if (apq8064_hdmi_as_primary_selected()) {
dtv_bus_def_vectors[0].ab = 2000000000;
dtv_bus_def_vectors[0].ib = 2000000000;
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index e77e7c0..1f39d3f 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -389,11 +389,12 @@
static struct pm8921_bms_platform_data
apq8064_pm8921_bms_pdata __devinitdata = {
- .battery_type = BATT_UNKNOWN,
+ .battery_type = BATT_UNKNOWN,
.r_sense = 10,
- .i_test = 2500,
- .v_failure = 3000,
+ .v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+ .shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 37bd16b..68a85c0 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -95,7 +95,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000
#define MSM_ION_SF_SIZE 0
@@ -111,7 +111,7 @@
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#else
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_CONTIG_MEM_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
#endif
@@ -133,14 +133,14 @@
#define PCIE_PWR_EN_PMIC_GPIO 13
#define PCIE_RST_N_PMIC_MPP 1
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
{
- pmem_kernel_ebi1_size = memparse(p, NULL);
+ msm_contig_mem_size = memparse(p, NULL);
return 0;
}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
#ifdef CONFIG_ANDROID_PMEM
@@ -263,7 +263,7 @@
reserve_memory_for(&android_pmem_pdata);
reserve_memory_for(&android_pmem_audio_pdata);
#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
- apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+ apq8064_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
#endif /*CONFIG_ANDROID_PMEM*/
}
@@ -2292,6 +2292,7 @@
&apq8064_iommu_domain_device,
&msm_tsens_device,
&apq8064_cache_dump_device,
+ &msm_8064_device_tspp,
};
static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index d975997..2a8e918 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -413,31 +413,9 @@
#endif
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static int mdp_core_clk_rate_table[] = {
- 200000000,
- 200000000,
- 200000000,
- 200000000,
-};
-#else
-static int mdp_core_clk_rate_table[] = {
- 85330000,
- 128000000,
- 160000000,
- 200000000,
-};
-#endif
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- .mdp_core_clk_rate = 200000000,
-#else
- .mdp_core_clk_rate = 85330000,
-#endif
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
#ifdef CONFIG_MSM_BUS_SCALING
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index a1a4b7c..c16f55d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -340,11 +340,12 @@
};
static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
- .battery_type = BATT_UNKNOWN,
+ .battery_type = BATT_UNKNOWN,
.r_sense = 10,
- .i_test = 2500,
- .v_failure = 3000,
+ .v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+ .shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 4fce029..d5014bd 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -141,7 +141,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
@@ -168,18 +168,18 @@
#define MSM8930_FW_START MSM8930_FIXED_AREA_START
#else
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_CONTIG_MEM_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
#endif
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
{
- pmem_kernel_ebi1_size = memparse(p, NULL);
+ msm_contig_mem_size = memparse(p, NULL);
return 0;
}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
#ifdef CONFIG_ANDROID_PMEM
@@ -322,7 +322,7 @@
reserve_memory_for(&android_pmem_pdata);
reserve_memory_for(&android_pmem_audio_pdata);
#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
- msm8930_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+ msm8930_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
#endif /*CONFIG_ANDROID_PMEM*/
}
@@ -2297,6 +2297,7 @@
&msm_cpudai_incall_record_rx,
&msm_cpudai_incall_record_tx,
&msm_pcm_hostless,
+ &msm_multi_ch_pcm,
};
static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index ddeba32..f993ed8 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -573,18 +573,9 @@
#endif
-static int mdp_core_clk_rate_table[] = {
- 85330000,
- 128000000,
- 160000000,
- 200000000,
-};
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
- .mdp_core_clk_rate = 85330000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
#ifdef CONFIG_MSM_BUS_SCALING
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
@@ -1043,8 +1034,6 @@
*/
static void set_mdp_clocks_for_wuxga(void)
{
- int i;
-
mdp_ui_vectors[0].ab = 2000000000;
mdp_ui_vectors[0].ib = 2000000000;
mdp_vga_vectors[0].ab = 2000000000;
@@ -1054,11 +1043,6 @@
mdp_1080p_vectors[0].ab = 2000000000;
mdp_1080p_vectors[0].ib = 2000000000;
- mdp_pdata.mdp_core_clk_rate = 200000000;
-
- for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
- mdp_core_clk_rate_table[i] = 200000000;
-
if (hdmi_is_primary) {
dtv_bus_def_vectors[0].ab = 2000000000;
dtv_bus_def_vectors[0].ib = 2000000000;
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 5950026..46d317b 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -420,12 +420,13 @@
};
static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
- .battery_type = BATT_UNKNOWN,
+ .battery_type = BATT_UNKNOWN,
.r_sense = 10,
- .i_test = 2500,
- .v_failure = 3000,
+ .v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.rconn_mohm = 18,
+ .shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 541bf85..22a5021 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -145,7 +145,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
@@ -173,18 +173,18 @@
static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
#else
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_CONTIG_MEM_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
#endif
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
{
- pmem_kernel_ebi1_size = memparse(p, NULL);
+ msm_contig_mem_size = memparse(p, NULL);
return 0;
}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
#ifdef CONFIG_ANDROID_PMEM
@@ -336,7 +336,7 @@
reserve_memory_for(&android_pmem_pdata);
reserve_memory_for(&android_pmem_audio_pdata);
#endif
- msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+ msm8960_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
#endif
}
diff --git a/arch/arm/mach-msm/board-8974-regulator.c b/arch/arm/mach-msm/board-8974-regulator.c
deleted file mode 100644
index 1a41f09..0000000
--- a/arch/arm/mach-msm/board-8974-regulator.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/platform_device.h>
-#include <linux/regulator/stub-regulator.h>
-
-#define VREG_CONSUMERS(_name) \
- static struct regulator_consumer_supply vreg_consumers_##_name[]
-
-/*
- * Consumer specific regulator names:
- * regulator name consumer dev_name
- */
-VREG_CONSUMERS(K0) = {
- REGULATOR_SUPPLY("krait0", "f9000000.qcom,acpuclk"),
-};
-VREG_CONSUMERS(K1) = {
- REGULATOR_SUPPLY("krait1", "f9000000.qcom,acpuclk"),
-};
-VREG_CONSUMERS(K2) = {
- REGULATOR_SUPPLY("krait2", "f9000000.qcom,acpuclk"),
-};
-VREG_CONSUMERS(K3) = {
- REGULATOR_SUPPLY("krait3", "f9000000.qcom,acpuclk"),
-};
-
-#define PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
- _always_on, _supply_regulator, _hpm_min, _system_uA) \
- struct stub_regulator_pdata vreg_dev_##_id##_pdata __devinitdata = { \
- .init_data = { \
- .constraints = { \
- .valid_modes_mask = _modes, \
- .valid_ops_mask = _ops, \
- .min_uV = _min_uV, \
- .max_uV = _max_uV, \
- .input_uV = _max_uV, \
- .apply_uV = 0, \
- .always_on = _always_on, \
- .name = _name, \
- }, \
- .num_consumer_supplies = \
- ARRAY_SIZE(vreg_consumers_##_id), \
- .consumer_supplies = vreg_consumers_##_id, \
- .supply_regulator = _supply_regulator, \
- }, \
- .hpm_min_load = _hpm_min, \
- .system_uA = _system_uA, \
- }
-
-#define KRAIT_PWR(_id, _name, _always_on, _min_uV, _max_uV, \
- _supply_regulator, _hpm_min, _system_uA) \
- PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
- | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
- REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
- REGULATOR_CHANGE_DRMS, _always_on, \
- _supply_regulator, _hpm_min, _system_uA)
-
-/* ID name a_on min_uV max_uV supply hpm_min sys_uA */
-KRAIT_PWR(K0, "krait0", 0, 850000, 1100000, NULL, 100000, 0);
-KRAIT_PWR(K1, "krait1", 0, 850000, 1100000, NULL, 100000, 0);
-KRAIT_PWR(K2, "krait2", 0, 850000, 1100000, NULL, 100000, 0);
-KRAIT_PWR(K3, "krait3", 0, 850000, 1100000, NULL, 100000, 0);
-
-#define VREG_DEVICE(_name, _devid) \
- static struct platform_device vreg_device_##_name __devinitdata = \
- { \
- .name = STUB_REGULATOR_DRIVER_NAME, \
- .id = _devid, \
- .dev = { .platform_data = &vreg_dev_##_name##_pdata }, \
- }
-
-VREG_DEVICE(K0, 0);
-VREG_DEVICE(K1, 1);
-VREG_DEVICE(K2, 2);
-VREG_DEVICE(K3, 3);
-
-struct platform_device *msm_8974_stub_regulator_devices[] __devinitdata = {
- &vreg_device_K0,
- &vreg_device_K1,
- &vreg_device_K2,
- &vreg_device_K3,
-};
-
-int msm_8974_stub_regulator_devices_len __devinitdata =
- ARRAY_SIZE(msm_8974_stub_regulator_devices);
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 3a3e208..388307b 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -24,8 +24,8 @@
#ifdef CONFIG_ANDROID_PMEM
#include <linux/android_pmem.h>
#endif
-#include <linux/regulator/stub-regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/krait-regulator.h>
#include <linux/msm_thermal.h>
#include <asm/mach/map.h>
#include <asm/hardware/gic.h>
@@ -413,8 +413,6 @@
{
platform_device_register(&msm_device_smd_8974);
platform_device_register(&android_usb_device);
- platform_add_devices(msm_8974_stub_regulator_devices,
- msm_8974_stub_regulator_devices_len);
}
/*
@@ -431,7 +429,7 @@
msm_lpmrs_module_init();
rpm_regulator_smd_driver_init();
msm_spm_device_init();
- regulator_stub_init();
+ krait_power_init();
if (machine_is_msm8974_rumi())
msm_clock_init(&msm8974_rumi_clock_init_data);
else
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index e28c734..2919f06 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -24,6 +24,18 @@
.dir = GPIOMUX_OUT_HIGH,
};
+static struct gpiomux_setting gpio_spi_cs_config = {
+ .func = GPIOMUX_FUNC_9,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
.gpio = 45, /* BLSP1 UART TX */
@@ -37,6 +49,31 @@
[GPIOMUX_SUSPENDED] = &gpio_uart_config,
},
},
+ {
+ .gpio = 69, /* BLSP6 QUP SPI_CS_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
+ {
+ .gpio = 20, /* BLSP6 QUP SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 21, /* BLSP6 QUP SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 23, /* BLSP6 QUP SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+
};
void __init msm9625_init_gpiomux(void)
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 4a9bbcd..e7ef1a9 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -46,8 +46,8 @@
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
CLK_DUMMY("mem_clk", NULL, NULL, 0),
- CLK_DUMMY("core_clk", NULL, "spi_qsd.1", OFF),
- CLK_DUMMY("iface_clk", NULL, "spi_qsd.1", OFF),
+ CLK_DUMMY("core_clk", SPI_CLK, "spi_qsd.1", OFF),
+ CLK_DUMMY("iface_clk", SPI_P_CLK, "spi_qsd.1", OFF),
CLK_DUMMY("core_clk", NULL, "f9966000.i2c", 0),
CLK_DUMMY("iface_clk", NULL, "f9966000.i2c", 0),
CLK_DUMMY("core_clk", NULL, "fe12f000.slim", OFF),
@@ -72,6 +72,8 @@
static struct of_dev_auxdata msm9625_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
+ OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9928000, \
+ "spi_qsd.1", NULL),
{}
};
@@ -94,6 +96,8 @@
{
if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
+
+ msm9625_init_gpiomux();
msm_clock_init(&msm_dummy_clock_init_data);
of_platform_populate(NULL, of_default_bus_match_table,
msm9625_auxdata_lookup, NULL);
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 8adfdab..4524f43 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -4539,19 +4539,10 @@
.mddi_client_power = msm_fb_mddi_client_power,
};
-int mdp_core_clk_rate_table[] = {
- 122880000,
- 122880000,
- 192000000,
- 192000000,
-};
-
static struct msm_panel_common_pdata mdp_pdata = {
.hw_revision_addr = 0xac001270,
.gpio = 30,
- .mdp_core_clk_rate = 122880000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 192000000,
.mdp_rev = MDP_REV_40,
.mem_hid = MEMTYPE_EBI0,
};
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 7ddf88e..47d847e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -9651,27 +9651,9 @@
}
#endif
-#ifdef CONFIG_FB_MSM_MIPI_DSI
-int mdp_core_clk_rate_table[] = {
- 85330000,
- 128000000,
- 160000000,
- 200000000,
-};
-#else
-int mdp_core_clk_rate_table[] = {
- 59080000,
- 128000000,
- 128000000,
- 200000000,
-};
-#endif
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
- .mdp_core_clk_rate = 59080000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
#ifdef CONFIG_MSM_BUS_SCALING
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
@@ -9764,9 +9746,7 @@
static void __init msm_fb_add_devices(void)
{
#ifdef CONFIG_FB_MSM_LCDC_DSUB
- mdp_pdata.mdp_core_clk_table = NULL;
- mdp_pdata.num_mdp_clk = 0;
- mdp_pdata.mdp_core_clk_rate = 200000000;
+ mdp_pdata.mdp_max_clk = 200000000;
#endif
msm_fb_register_device("mdp", &mdp_pdata);
@@ -9790,8 +9770,6 @@
*/
static void set_mdp_clocks_for_wuxga(void)
{
- int i;
-
mdp_sd_smi_vectors[0].ab = 2000000000;
mdp_sd_smi_vectors[0].ib = 2000000000;
mdp_sd_smi_vectors[1].ab = 2000000000;
@@ -9817,10 +9795,7 @@
mdp_1080p_vectors[1].ab = 2000000000;
mdp_1080p_vectors[1].ib = 2000000000;
- mdp_pdata.mdp_core_clk_rate = 200000000;
-
- for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
- mdp_core_clk_rate_table[i] = 200000000;
+ mdp_pdata.mdp_max_clk = 200000000;
}
#if (defined(CONFIG_MARIMBA_CORE)) && \
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 8ac1c88..e4bcfa9 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -23,6 +23,7 @@
#include <mach/clk.h>
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -615,13 +616,16 @@
#define RPM_BUS_CLK_TYPE 0x316b6c63
#define RPM_MEM_CLK_TYPE 0x326b6c63
-#define CXO_ID 0x0
-#define QDSS_ID 0x1
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+
+#define CXO_ID 0x0
+#define QDSS_ID 0x1
+#define RPM_SCALING_ENABLE_ID 0x2
#define PNOC_ID 0x0
#define SNOC_ID 0x1
#define CNOC_ID 0x2
-#define MMSSNOC_AHB_ID 0x4
+#define MMSSNOC_AHB_ID 0x3
#define BIMC_ID 0x0
#define OCMEM_ID 0x1
@@ -766,6 +770,7 @@
static DEFINE_CLK_VOTER(ocmemgx_gfx3d_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
@@ -4532,6 +4537,16 @@
{&camss_vfe_vfe_ahb_clk.c, MMSS_BASE, 0x003c},
{&camss_vfe_vfe_axi_clk.c, MMSS_BASE, 0x003d},
{&camss_vfe_vfe_ocmemnoc_clk.c, MMSS_BASE, 0x003e},
+ {&oxilicx_axi_clk.c, MMSS_BASE, 0x000b},
+ {&oxilicx_ahb_clk.c, MMSS_BASE, 0x000c},
+ {&ocmemcx_ocmemnoc_clk.c, MMSS_BASE, 0x0009},
+ {&oxili_gfx3d_clk.c, MMSS_BASE, 0x000d},
+ {&venus0_axi_clk.c, MMSS_BASE, 0x000f},
+ {&venus0_ocmemnoc_clk.c, MMSS_BASE, 0x0010},
+ {&venus0_ahb_clk.c, MMSS_BASE, 0x0011},
+ {&venus0_vcodec0_clk.c, MMSS_BASE, 0x000e},
+ {&mmss_s0_axi_clk.c, MMSS_BASE, 0x0005},
+ {&mmssnoc_ahb_clk.c, MMSS_BASE, 0x0001},
{&mdss_ahb_clk.c, MMSS_BASE, 0x0022},
{&mdss_hdmi_clk.c, MMSS_BASE, 0x001d},
{&mdss_mdp_clk.c, MMSS_BASE, 0x0014},
@@ -4992,6 +5007,8 @@
CLK_LOOKUP("core_clk", oxilicx_axi_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("alt_core_clk", oxili_gfx3d_clk.c, "fdb10000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem"),
+ CLK_LOOKUP("iface_clk", ocmemcx_ocmemnoc_clk.c, "fdd00000.qcom,ocmem"),
CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
CLK_LOOKUP("alt_core_clk", venus0_vcodec0_clk.c, "fdc84000.qcom,iommu"),
CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
@@ -5432,6 +5449,24 @@
#define APCS_GCC_CC_PHYS 0xF9011000
#define APCS_GCC_CC_SIZE SZ_4K
+static void __init enable_rpm_scaling(void)
+{
+ int rc, value = 0x1;
+ struct msm_rpm_kvp kvp = {
+ .key = RPM_SMD_KEY_ENABLE,
+ .data = (void *)&value,
+ .length = sizeof(value),
+ };
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (sleep set) did not enable!\n");
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (active set) did not enable!\n");
+}
+
static void __init msm8974_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -5469,6 +5504,8 @@
vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
rpm_regulator_enable(vdd_dig_reg);
+ enable_rpm_scaling();
+
reg_init();
}
diff --git a/arch/arm/mach-msm/dal_axi.c b/arch/arm/mach-msm/dal_axi.c
index 739b7dc..1d873ca 100644
--- a/arch/arm/mach-msm/dal_axi.c
+++ b/arch/arm/mach-msm/dal_axi.c
@@ -17,6 +17,8 @@
#define DALRPC_PORT_NAME "DAL00"
enum {
+ DALRPC_AXI_ALLOCATE = DALDEVICE_FIRST_DEVICE_API_IDX + 1,
+ DALRPC_AXI_FREE = DALDEVICE_FIRST_DEVICE_API_IDX + 2,
DALRPC_AXI_CONFIGURE_BRIDGE = DALDEVICE_FIRST_DEVICE_API_IDX + 11
};
@@ -38,6 +40,67 @@
};
+static void *cam_dev_handle;
+static int __axi_free(int mode)
+{
+ int rc = 0;
+
+ if (!cam_dev_handle)
+ return rc;
+
+ rc = dalrpc_fcn_0(DALRPC_AXI_FREE, cam_dev_handle, mode);
+ if (rc) {
+ printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+ __func__, rc);
+ goto fail_dal_fcn_0;
+ }
+
+ /* close device handle */
+ rc = daldevice_detach(cam_dev_handle);
+ if (rc) {
+ printk(KERN_ERR "%s: failed to detach AXI bus device (%d)\n",
+ __func__, rc);
+ goto fail_dal_attach_detach;
+ }
+ cam_dev_handle = NULL;
+ return 0;
+
+fail_dal_fcn_0:
+ (void)daldevice_detach(cam_dev_handle);
+ cam_dev_handle = NULL;
+fail_dal_attach_detach:
+ return rc;
+}
+
+static int __axi_allocate(int mode)
+{
+ int rc;
+
+ /* get device handle */
+ rc = daldevice_attach(DALDEVICEID_AXI, DALRPC_PORT_NAME,
+ DALRPC_DEST_MODEM, &cam_dev_handle);
+ if (rc) {
+ printk(KERN_ERR "%s: failed to attach AXI bus device (%d)\n",
+ __func__, rc);
+ goto fail_dal_attach_detach;
+ }
+
+ rc = dalrpc_fcn_0(DALRPC_AXI_ALLOCATE, cam_dev_handle, mode);
+ if (rc) {
+ printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+ __func__, rc);
+ goto fail_dal_fcn_0;
+ }
+
+ return 0;
+
+fail_dal_fcn_0:
+ (void)daldevice_detach(cam_dev_handle);
+ cam_dev_handle = NULL;
+fail_dal_attach_detach:
+ return rc;
+}
+
static int axi_configure_bridge_grfx_sync_mode(int bridge_mode)
{
int rc;
@@ -82,7 +145,15 @@
return rc;
}
+int axi_free(mode)
+{
+ return __axi_free(mode);
+}
+int axi_allocate(mode)
+{
+ return __axi_allocate(mode);
+}
int set_grp2d_async(void)
{
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 0d05df9..e5261b0 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -29,6 +29,7 @@
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_tsif.h>
+#include <mach/msm_tspp.h>
#include <mach/msm_bus_board.h>
#include <mach/rpm.h>
#include <mach/mdm2.h>
@@ -583,6 +584,67 @@
}
};
+#define MSM_TSPP_PHYS (0x18202000)
+#define MSM_TSPP_SIZE (0x1000)
+#define MSM_TSPP_BAM_PHYS (0x18204000)
+#define MSM_TSPP_BAM_SIZE (0x2000)
+
+static const struct msm_gpio tspp_gpios[] = {
+ { .gpio_cfg = TSIF_0_CLK, .label = "tsif_clk", },
+ { .gpio_cfg = TSIF_0_EN, .label = "tsif_en", },
+ { .gpio_cfg = TSIF_0_DATA, .label = "tsif_data", },
+ { .gpio_cfg = TSIF_0_SYNC, .label = "tsif_sync", },
+ { .gpio_cfg = TSIF_1_CLK, .label = "tsif_clk", },
+ { .gpio_cfg = TSIF_1_EN, .label = "tsif_en", },
+ { .gpio_cfg = TSIF_1_DATA, .label = "tsif_data", },
+ { .gpio_cfg = TSIF_1_SYNC, .label = "tsif_sync", },
+};
+
+static struct resource tspp_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ .start = TSIF_TSPP_IRQ,
+ .end = TSIF1_IRQ,
+ },
+ [1] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF0_PHYS,
+ .end = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [2] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF1_PHYS,
+ .end = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [3] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_PHYS,
+ .end = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
+ },
+ [4] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_BAM_PHYS,
+ .end = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
+ },
+};
+
+static struct msm_tspp_platform_data tspp_platform_data = {
+ .num_gpios = ARRAY_SIZE(tspp_gpios),
+ .gpios = tspp_gpios,
+ .tsif_pclk = "iface_clk",
+ .tsif_ref_clk = "ref_clk",
+};
+
+struct platform_device msm_8064_device_tspp = {
+ .name = "msm_tspp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tspp_resources),
+ .resource = tspp_resources,
+ .dev = {
+ .platform_data = &tspp_platform_data
+ },
+};
+
/*
* Machine specific data for AUX PCM Interface
* which the driver will be unware of.
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 4e08465..55c1e03 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -190,6 +190,7 @@
extern struct platform_device msm_device_tsif[2];
extern struct platform_device msm_8064_device_tsif[2];
+extern struct platform_device msm_8064_device_tspp;
extern struct platform_device msm_device_ssbi_pmic1;
extern struct platform_device msm_device_ssbi_pmic2;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 1770b97..f529522 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -391,9 +391,7 @@
void (*panel_config_gpio)(int);
int (*vga_switch)(int select_vga);
int *gpio_num;
- int mdp_core_clk_rate;
- unsigned num_mdp_clk;
- int *mdp_core_clk_table;
+ u32 mdp_max_clk;
#ifdef CONFIG_MSM_BUS_SCALING
struct msm_bus_scale_pdata *mdp_bus_scale_table;
#endif
@@ -583,6 +581,7 @@
void msm_8974_reserve(void);
void msm_8974_very_early(void);
void msm_8974_init_gpiomux(void);
+void msm9625_init_gpiomux(void);
struct mmc_platform_data;
int msm_add_sdcc(unsigned int controller,
diff --git a/arch/arm/mach-msm/include/mach/dal_axi.h b/arch/arm/mach-msm/include/mach/dal_axi.h
index 4e32aa3..84cd37f 100644
--- a/arch/arm/mach-msm/include/mach/dal_axi.h
+++ b/arch/arm/mach-msm/include/mach/dal_axi.h
@@ -17,5 +17,7 @@
int set_grp2d_async(void);
int set_grp3d_async(void);
int set_grp_xbar_async(void);
-
+int axi_allocate(int mode);
+int axi_free(int mode);
+#define AXI_FLOW_VIEWFINDER_HI 243
#endif /* _DAL_AXI_H */
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 49e283d..a5b0275 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -17,6 +17,7 @@
* Client drivers should use wrappers available in ocmem.h
**/
#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <asm/io.h>
#include <mach/msm_iomap.h>
#include "ocmem.h"
@@ -36,6 +37,7 @@
};
struct ocmem_zone {
+ bool active;
int owner;
int active_regions;
int max_regions;
@@ -73,6 +75,8 @@
void __iomem *vbase;
unsigned long size;
unsigned long base;
+ struct clk *core_clk;
+ struct clk *iface_clk;
struct ocmem_partition *parts;
int nr_parts;
void __iomem *reg_base;
@@ -178,6 +182,7 @@
}
struct ocmem_zone *get_zone(unsigned);
+int zone_active(int);
unsigned long offset_to_phys(unsigned long);
unsigned long phys_to_offset(unsigned long);
unsigned long allocate_head(struct ocmem_zone *, unsigned long);
@@ -206,4 +211,8 @@
unsigned long process_quota(int);
int ocmem_memory_off(int, unsigned long, unsigned long);
int ocmem_memory_on(int, unsigned long, unsigned long);
+int ocmem_enable_core_clock(void);
+int ocmem_enable_iface_clock(void);
+void ocmem_disable_core_clock(void);
+void ocmem_disable_iface_clock(void);
#endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index e6e9acc..96c4809 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -67,10 +67,10 @@
#define LOAD_PER_PHASE 3200000
-#define CORE_VOLTAGE_MIN 500000
+#define CORE_VOLTAGE_MIN 900000
#define KRAIT_LDO_VOLTAGE_MIN 465000
-#define KRAIT_LDO_VOLTAGE_OFFSET 460000
+#define KRAIT_LDO_VOLTAGE_OFFSET 465000
#define KRAIT_LDO_STEP 5000
#define BHS_SETTLING_DELAY_US 1
@@ -734,6 +734,22 @@
module_exit(krait_power_exit);
+void secondary_cpu_hs_init(void *base_ptr)
+{
+ /* 605mV retention and 705mV operational voltage */
+ writel_relaxed(0x1C30, base_ptr + APC_LDO_VREF_SET);
+ writel_relaxed(0x430000, base_ptr + 0x20);
+ writel_relaxed(0x21, base_ptr + 0x1C);
+
+ /* Turn on the BHS, turn off LDO Bypass and power down LDO */
+ writel_relaxed(0x403F007F, base_ptr + APC_PWR_GATE_CTL);
+ mb();
+ udelay(1);
+
+ /* Finally turn on the bypass so that BHS supplies power */
+ writel_relaxed(0x403F3F7F, base_ptr + APC_PWR_GATE_CTL);
+}
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KRAIT POWER regulator driver");
MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index e035e35..9dcd51f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -139,7 +139,7 @@
for (i = 0; i < fabric->pdata->len; i++) {
struct msm_bus_inode_info *info;
- int ctx;
+ int ctx, j;
info = kzalloc(sizeof(struct msm_bus_inode_info), GFP_KERNEL);
if (info == NULL) {
@@ -189,11 +189,17 @@
if (fabric->fabdev.hw_algo.node_init == NULL)
continue;
+ for (j = 0; j < NUM_CTX; j++)
+ clk_prepare_enable(fabric->info.nodeclk[j].clk);
+
fabric->fabdev.hw_algo.node_init(fabric->hw_data, info);
if (ret) {
MSM_BUS_ERR("Unable to init node info, ret: %d\n", ret);
kfree(info);
}
+
+ for (j = 0; j < NUM_CTX; j++)
+ clk_disable_unprepare(fabric->info.nodeclk[j].clk);
}
MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
@@ -337,6 +343,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
+ int i;
/* Temporarily stub out arbitration settings for msm8974 */
if (machine_is_msm8974())
@@ -354,8 +361,14 @@
return;
}
+ for (i = 0; i < NUM_CTX; i++)
+ clk_prepare_enable(fabric->info.nodeclk[i].clk);
+
fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
master_tiers, add_bw);
+ for (i = 0; i < NUM_CTX; i++)
+ clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+
fabric->arb_dirty = true;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index 2597e27..e6ec722 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -388,7 +388,8 @@
(struct msm_bus_noc_info *)hw_data;
if (!IS_SLAVE(info->node_info->priv_id))
- msm_bus_noc_mas_init(ninfo, info);
+ if (info->node_info->hw_sel != MSM_BUS_RPM)
+ msm_bus_noc_mas_init(ninfo, info);
}
static int msm_bus_noc_allocate_commit_data(struct msm_bus_fabric_registration
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index a9c3f4c..82fe2f8 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -103,7 +103,7 @@
const char *get_name(int id)
{
if (!check_id(id))
- return NULL;
+ return "Unknown";
return client_names[id];
}
@@ -126,6 +126,15 @@
return offset + ocmem_pdata->base;
}
+inline int zone_active(int id)
+{
+ struct ocmem_zone *z = get_zone(id);
+ if (z)
+ return z->active == true ? 1 : 0;
+ else
+ return 0;
+}
+
static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
{
struct ocmem_plat_data *pdata = NULL;
@@ -287,6 +296,44 @@
}
#endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
+/* Core Clock Operations */
+int ocmem_enable_core_clock(void)
+{
+ int ret;
+ ret = clk_prepare_enable(ocmem_pdata->core_clk);
+ if (ret) {
+ pr_err("ocmem: Failed to enable core clock\n");
+ return ret;
+ }
+ pr_debug("ocmem: Enabled core clock\n");
+ return 0;
+}
+
+void ocmem_disable_core_clock(void)
+{
+ clk_disable_unprepare(ocmem_pdata->core_clk);
+ pr_debug("ocmem: Disabled core clock\n");
+}
+
+/* Branch Clock Operations */
+int ocmem_enable_iface_clock(void)
+{
+ int ret;
+ ret = clk_prepare_enable(ocmem_pdata->iface_clk);
+ if (ret) {
+ pr_err("ocmem: Failed to disable branch clock\n");
+ return ret;
+ }
+ pr_debug("ocmem: Enabled iface clock\n");
+ return 0;
+}
+
+void ocmem_disable_iface_clock(void)
+{
+ clk_disable_unprepare(ocmem_pdata->iface_clk);
+ pr_debug("ocmem: Disabled iface clock\n");
+}
+
static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -444,6 +491,7 @@
for (i = 0; i < pdata->nr_parts; i++) {
struct ocmem_partition *part = &pdata->parts[i];
zone = get_zone(part->id);
+ zone->active = false;
dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
i, part->p_start, part->p_size,
@@ -501,6 +549,7 @@
z_ops->allocate = allocate_head;
z_ops->free = free_head;
}
+ zone->active = true;
active_zones++;
if (active_zones == 1)
@@ -515,10 +564,34 @@
return 0;
}
+/* Enable the ocmem graphics mpU as a workaround */
+/* This will be programmed by TZ after TZ support is integrated */
+static int ocmem_init_gfx_mpu(struct platform_device *pdev)
+{
+ int rc;
+ struct device *dev = &pdev->dev;
+ void __iomem *ocmem_region_vbase = NULL;
+
+ ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
+ OCMEM_REGION_CTL_SIZE);
+ if (!ocmem_region_vbase)
+ return -EBUSY;
+
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0)
+ return rc;
+
+ writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
+ ocmem_disable_core_clock();
+ return 0;
+}
+
static int __devinit msm_ocmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- void *ocmem_region_vbase = NULL;
+ struct clk *ocmem_core_clk = NULL;
+ struct clk *ocmem_iface_clk = NULL;
if (!pdev->dev.of_node) {
dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -537,6 +610,29 @@
dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
+ ocmem_core_clk = devm_clk_get(dev, "core_clk");
+
+ if (IS_ERR(ocmem_core_clk)) {
+ dev_err(dev, "Unable to get the core clock\n");
+ return PTR_ERR(ocmem_core_clk);
+ }
+
+ /* The core clock is synchronous with graphics */
+ if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
+ dev_err(dev, "Set rate failed on the core clock\n");
+ return -EBUSY;
+ }
+
+ ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
+
+ if (IS_ERR(ocmem_iface_clk)) {
+ dev_err(dev, "Unable to get the memory interface clock\n");
+ return PTR_ERR(ocmem_core_clk);
+ };
+
+ ocmem_pdata->core_clk = ocmem_core_clk;
+ ocmem_pdata->iface_clk = ocmem_iface_clk;
+
platform_set_drvdata(pdev, ocmem_pdata);
if (ocmem_core_init(pdev))
@@ -551,18 +647,14 @@
if (ocmem_sched_init())
return -EBUSY;
- ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
- OCMEM_REGION_CTL_SIZE);
- if (!ocmem_region_vbase)
- return -EBUSY;
-
- /* Enable the ocmem graphics mpU as a workaround in Virtio */
- /* This will be programmed by TZ after TZ support is integrated */
- writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
-
if (ocmem_rdm_init(pdev))
return -EBUSY;
+ if (ocmem_init_gfx_mpu(pdev)) {
+ dev_err(dev, "Unable to initialize Graphics mPU\n");
+ return -EBUSY;
+ }
+
dev_dbg(dev, "initialized successfully\n");
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index a5aed5e..2604d47 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -110,6 +110,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (size < OCMEM_MIN_ALLOC) {
pr_err("ocmem: requested size %lx must be at least %x\n",
size, OCMEM_MIN_ALLOC);
@@ -136,6 +142,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (size < OCMEM_MIN_ALLOC) {
pr_err("ocmem: requested size %lx must be at least %x\n",
size, OCMEM_MIN_ALLOC);
@@ -162,6 +174,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
/* Asynchronous API requires notifier registration */
if (!check_notifier(client_id)) {
pr_err("ocmem: No notifier registered for client %d\n",
@@ -202,6 +220,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (size < OCMEM_MIN_ALLOC) {
pr_err("ocmem: requested size %lx must be at least %x\n",
size, OCMEM_MIN_ALLOC);
@@ -226,6 +250,12 @@
return -EINVAL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
if (!buffer) {
pr_err("ocmem: Invalid buffer\n");
return -EINVAL;
@@ -240,6 +270,13 @@
return -EINVAL;
if (len >= buffer->len)
return -EINVAL;
+
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
return __ocmem_shrink(client_id, buffer, len);
}
@@ -282,6 +319,12 @@
return -EINVAL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
/* Asynchronous API requires notifier registration */
if (!check_notifier(client_id)) {
pr_err("ocmem: No notifier registered for client %d\n",
@@ -320,6 +363,12 @@
return -EINVAL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
/* Asynchronous API requires notifier registration */
if (!check_notifier(client_id)) {
pr_err("ocmem: No notifier registered for client %d\n",
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index d8cfefc..c7cc57e 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -384,6 +384,22 @@
}
#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
+static int ocmem_core_set_default_state(void)
+{
+ int rc = 0;
+
+ /* The OCMEM core clock and branch clocks are always turned ON */
+ rc = ocmem_enable_core_clock();
+ if (rc < 0)
+ return rc;
+
+ rc = ocmem_enable_iface_clock();
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
/* Initializes a region to be turned ON in wide mode */
static int ocmem_region_set_default_state(unsigned int r_num)
{
@@ -408,6 +424,11 @@
{
return 0;
}
+
+static int ocmem_core_set_default_state(void)
+{
+ return 0;
+}
#endif
#if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
@@ -535,6 +556,7 @@
unsigned start_m = num_banks;
unsigned end_m = num_banks;
unsigned long region_offset = 0;
+ int rc = 0;
if (offset < 0)
return -EINVAL;
@@ -555,6 +577,14 @@
(region_end >= num_regions))
return -EINVAL;
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0) {
+ pr_err("ocmem: Power transistion request for client %s (id: %d) failed\n",
+ get_name(id), id);
+ return rc;
+ }
+
mutex_lock(®ion_ctrl_lock);
for (i = region_start; i <= region_end; i++) {
@@ -605,9 +635,11 @@
}
mutex_unlock(®ion_ctrl_lock);
+ ocmem_disable_core_clock();
return 0;
invalid_transition:
mutex_unlock(®ion_ctrl_lock);
+ ocmem_disable_core_clock();
pr_err("ocmem_core: Invalid state transition detected for %d\n", id);
pr_err("ocmem_core: Offset %lx Len %lx curr_state %x new_state %x\n",
offset, len, curr_state, new_state);
@@ -640,10 +672,16 @@
bool interleaved;
unsigned i, j, k;
unsigned rsc_type = 0;
+ int rc = 0;
pdata = platform_get_drvdata(pdev);
ocmem_base = pdata->reg_base;
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0)
+ return rc;
+
hw_ver = ocmem_read(ocmem_base + OC_HW_PROFILE);
if (pdata->nr_regions != OCMEM_V1_REGIONS) {
@@ -684,8 +722,7 @@
* num_regions, GFP_KERNEL);
if (!region_ctrl) {
- pr_err("ocmem: Unable to allocate memory\n");
- return -EINVAL;
+ goto err_no_mem;
}
mutex_init(®ion_ctrl_lock);
@@ -702,8 +739,7 @@
sizeof(struct ocmem_hw_macro) *
num_banks, GFP_KERNEL);
if (!region->macro) {
- pr_err("ocmem: Unable to allocate memory\n");
- return -EINVAL;
+ goto err_no_mem;
}
for (j = 0; j < num_banks; j++) {
@@ -722,7 +758,7 @@
if (!req) {
pr_err("Unable to create RPM request\n");
- return -EINVAL;
+ goto region_init_error;
}
pr_debug("rpm request type %x (rsc: %d) with %d elements\n",
@@ -733,16 +769,28 @@
if (ocmem_region_toggle(i)) {
pr_err("Failed to verify region %d\n", i);
- goto hw_not_supported;
+ goto region_init_error;
}
if (ocmem_region_set_default_state(i)) {
pr_err("Failed to initialize region %d\n", i);
- goto hw_not_supported;
+ goto region_init_error;
}
}
+
+ rc = ocmem_core_set_default_state();
+
+ if (rc < 0)
+ return rc;
+
+ ocmem_disable_core_clock();
return 0;
+
+err_no_mem:
+ pr_err("ocmem: Unable to allocate memory\n");
+region_init_error:
hw_not_supported:
pr_err("Unsupported OCMEM h/w configuration %x\n", hw_ver);
+ ocmem_disable_core_clock();
return -EINVAL;
}
diff --git a/arch/arm/mach-msm/ocmem_notifier.c b/arch/arm/mach-msm/ocmem_notifier.c
index 9fbcd73..644c809 100644
--- a/arch/arm/mach-msm/ocmem_notifier.c
+++ b/arch/arm/mach-msm/ocmem_notifier.c
@@ -82,6 +82,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (!nb) {
pr_err("ocmem: Invalid Notifier Block\n");
return NULL;
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 5649021..ccbef9b 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -142,6 +142,15 @@
int i = 0;
int j = 0;
int status = 0;
+ int rc = 0;
+
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0) {
+ pr_err("RDM transfer failed for client %s (id: %d)\n",
+ get_name(id), id);
+ return rc;
+ }
for (i = 0, j = slot; i < num_chunks; i++, j++) {
@@ -196,6 +205,7 @@
wait_event_interruptible(dm_wq,
atomic_read(&dm_pending) == 0);
+ ocmem_disable_core_clock();
return 0;
}
@@ -218,8 +228,16 @@
return -EINVAL;
}
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0) {
+ pr_err("RDM initialization failed\n");
+ return rc;
+ }
+
init_waitqueue_head(&dm_wq);
/* enable dm interrupts */
ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
+ ocmem_disable_core_clock();
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 70e6860..3ac8e0a 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -116,7 +116,7 @@
int hw_interconnect;
} ocmem_client_table[OCMEM_CLIENT_MAX] = {
{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
- {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+ {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_PORT},
{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
@@ -511,18 +511,48 @@
return 0;
}
-/* process map is a wrapper where power control will be added later */
static int process_map(struct ocmem_req *req, unsigned long start,
unsigned long end)
{
+ int rc = 0;
+
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0)
+ goto core_clock_fail;
+
+ rc = ocmem_enable_iface_clock();
+
+ if (rc < 0)
+ goto process_map_fail;
+
return do_map(req);
+
+process_map_fail:
+ ocmem_disable_core_clock();
+core_clock_fail:
+ pr_err("ocmem: Failed to map ocmem request\n");
+ return rc;
}
-/* process unmap is a wrapper where power control will be added later */
static int process_unmap(struct ocmem_req *req, unsigned long start,
unsigned long end)
{
- return do_unmap(req);
+ int rc = 0;
+
+ rc = do_unmap(req);
+
+ if (rc < 0)
+ goto process_unmap_fail;
+
+ ocmem_disable_iface_clock();
+ ocmem_disable_core_clock();
+
+ return 0;
+
+process_unmap_fail:
+ pr_err("ocmem: Failed to unmap ocmem request\n");
+ return rc;
}
static int __sched_grow(struct ocmem_req *req, bool can_block)
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 2d1fa80..3040a31 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -228,18 +228,6 @@
static int pil_riva_shutdown(struct pil_desc *pil)
{
- struct riva_data *drv = dev_get_drvdata(pil->dev);
- u32 reg;
-
- /* Put cCPU and cCPU clock into reset */
- reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
- reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
- writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
- reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
- reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
- writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
- mb();
-
/* Assert reset to Riva */
writel_relaxed(1, RIVA_RESET);
mb();
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 28b7748..b2d3dfa 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/regulator/krait-regulator.h>
#include <asm/hardware/gic.h>
#include <asm/cacheflush.h>
@@ -126,6 +127,8 @@
if (!base_ptr)
return -ENODEV;
+ secondary_cpu_hs_init(base_ptr);
+
writel_relaxed(0x021, base_ptr+0x04);
mb();
udelay(2);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 0faafc8..1225fec 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -64,7 +64,8 @@
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
#define INV_HDR "resource does not exist"
#define ERR "err\0"
-#define MAX_ERR_BUFFER_SIZE 60
+#define MAX_ERR_BUFFER_SIZE 128
+#define INIT_ERROR 1
static ATOMIC_NOTIFIER_HEAD(msm_rpm_sleep_notifier);
static bool standalone;
@@ -388,6 +389,7 @@
init_completion(&data->ack);
data->ack_recd = false;
data->msg_id = msg_id;
+ data->errno = INIT_ERROR;
spin_lock_irqsave(&msm_rpm_list_lock, flags);
list_add(&data->list, &msm_rpm_wait_list);
spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
@@ -463,7 +465,7 @@
return rc;
}
-static void msm_rpm_read_smd_data(char *buf)
+static int msm_rpm_read_smd_data(char *buf)
{
int pkt_sz;
int bytes_read = 0;
@@ -473,7 +475,7 @@
BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
- return;
+ return -EAGAIN;
BUG_ON(pkt_sz == 0);
@@ -487,6 +489,8 @@
} while (pkt_sz > 0);
BUG_ON(pkt_sz < 0);
+
+ return 0;
}
static void msm_rpm_smd_work(struct work_struct *work)
@@ -498,11 +502,15 @@
while (smd_is_pkt_avail(msm_rpm_data.ch_info) && !irq_process) {
spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
- msm_rpm_read_smd_data(buf);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
+ if (msm_rpm_read_smd_data(buf)) {
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read,
+ flags);
+ break;
+ }
msg_id = msm_rpm_get_msg_id_from_ack(buf);
errno = msm_rpm_get_error_from_ack(buf);
msm_rpm_process_ack(msg_id, errno);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
}
}
@@ -814,6 +822,12 @@
*/
goto wait_ack_cleanup;
+ if (elem->errno != INIT_ERROR) {
+ rc = elem->errno;
+ msm_rpm_free_list_entry(elem);
+ goto wait_ack_cleanup;
+ }
+
while ((id != msg_id) && (count++ < 10)) {
if (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
int errno;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index decee95..e82e44b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -2264,13 +2264,17 @@
int smd_is_pkt_avail(smd_channel_t *ch)
{
+ unsigned long flags;
+
if (!ch || !ch->is_pkt_ch)
return -EINVAL;
if (ch->current_packet)
return 1;
+ spin_lock_irqsave(&smd_lock, flags);
update_packet_state(ch);
+ spin_unlock_irqrestore(&smd_lock, flags);
return ch->current_packet ? 1 : 0;
}
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 65da903..fdde328 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -59,7 +59,7 @@
char wlname[64];
struct work_struct work;
spinlock_t restart_lock;
- bool restarting;
+ int restart_count;
void *notify;
@@ -406,8 +406,9 @@
out:
spin_lock_irqsave(&dev->restart_lock, flags);
- wake_unlock(&dev->wake_lock);
- dev->restarting = false;
+ dev->restart_count--;
+ if (!dev->restart_count)
+ wake_unlock(&dev->wake_lock);
spin_unlock_irqrestore(&dev->restart_lock, flags);
}
@@ -416,16 +417,21 @@
struct subsys_desc *desc = dev->desc;
unsigned long flags;
- spin_lock_irqsave(&dev->restart_lock, flags);
- if (!dev->restarting) {
- pr_debug("Restarting %s [level=%d]!\n", desc->name,
- restart_level);
+ pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
- dev->restarting = true;
+ spin_lock_irqsave(&dev->restart_lock, flags);
+ if (!dev->restart_count)
wake_lock(&dev->wake_lock);
- queue_work(ssr_wq, &dev->work);
- }
+ dev->restart_count++;
spin_unlock_irqrestore(&dev->restart_lock, flags);
+
+ if (!queue_work(ssr_wq, &dev->work)) {
+ spin_lock_irqsave(&dev->restart_lock, flags);
+ dev->restart_count--;
+ if (!dev->restart_count)
+ wake_unlock(&dev->wake_lock);
+ spin_unlock_irqrestore(&dev->restart_lock, flags);
+ }
}
int subsystem_restart_dev(struct subsys_device *dev)
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 318523b..cbf1d72 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -180,8 +180,13 @@
static void riva_crash_shutdown(const struct subsys_desc *subsys)
{
pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
- if (riva_crash != true)
+ if (riva_crash != true) {
smsm_riva_reset();
+ /* give sufficient time for wcnss to finish it's error
+ * fatal routine */
+ msleep(3000);
+ }
+
}
static struct subsys_desc riva_8960 = {
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 95d2f17..b5d38d5 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1010,8 +1010,16 @@
int dpm_suspend_end(pm_message_t state)
{
int error = dpm_suspend_late(state);
+ if (error)
+ return error;
- return error ? : dpm_suspend_noirq(state);
+ error = dpm_suspend_noirq(state);
+ if (error) {
+ dpm_resume_early(state);
+ return error;
+ }
+
+ return 0;
}
EXPORT_SYMBOL_GPL(dpm_suspend_end);
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index b117309..cfcacff 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -44,7 +44,7 @@
#include "hci_uart.h"
-unsigned int enableuartsleep;
+unsigned int enableuartsleep = 1;
module_param(enableuartsleep, uint, 0644);
/*
* Global variables
@@ -110,9 +110,9 @@
int status = 0;
if (test_bit(BT_TXEXPIRED, &flags)) {
printk(KERN_INFO "wakeup device\n");
- gpio_set_value(bsi->ext_wake, 1);
- msleep(20);
gpio_set_value(bsi->ext_wake, 0);
+ msleep(20);
+ gpio_set_value(bsi->ext_wake, 1);
}
modify_timer_task();
return status;
@@ -353,7 +353,7 @@
gpio_free(bsi->ext_wake);
goto free_bt_host_wake;
}
- gpio_set_value(bsi->ext_wake, 0);
+ gpio_set_value(bsi->ext_wake, 1);
bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake");
if (bsi->host_wake_irq < 0) {
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
index e0b01cd..26716a0 100644
--- a/drivers/gpio/gpio-msm-v3.c
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -141,7 +141,7 @@
void __msm_gpio_set_intr_status(unsigned gpio)
{
- __raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
+ __raw_writel(0, GPIO_INTR_STATUS(gpio));
}
unsigned __msm_gpio_get_intr_config(unsigned gpio)
@@ -167,15 +167,12 @@
{
unsigned cfg;
- cfg = __raw_readl(GPIO_INTR_CFG(gpio));
-
/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
* internal circuitry of TLMM, toggling the RAW_STATUS
* could cause the INTR_STATUS to be set for EDGE interrupts.
*/
- cfg |= (INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS);
+ cfg = INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS;
__raw_writel(cfg, GPIO_INTR_CFG(gpio));
- cfg = __raw_readl(GPIO_INTR_CFG(gpio));
cfg &= ~INTR_DECT_CTL_MASK;
if (type == IRQ_TYPE_EDGE_RISING)
cfg |= INTR_DECT_CTL_POS_EDGE;
@@ -186,10 +183,10 @@
else
cfg |= INTR_DECT_CTL_LEVEL;
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
- cfg |= INTR_POL_CTL_HI;
- else
+ if (type & IRQ_TYPE_LEVEL_LOW)
cfg &= ~INTR_POL_CTL_HI;
+ else
+ cfg |= INTR_POL_CTL_HI;
__raw_writel(cfg, GPIO_INTR_CFG(gpio));
/* Sometimes it might take a little while to update
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index ccbbd67..6511c95 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -39,17 +39,17 @@
/* gpio peripheral type and subtype values */
#define Q_GPIO_TYPE 0x10
-#define Q_GPIO_SUBTYPE_GPIO_4CH 0x0
-#define Q_GPIO_SUBTYPE_GPIOC_4CH 0x2
-#define Q_GPIO_SUBTYPE_GPIO_8CH 0x4
-#define Q_GPIO_SUBTYPE_GPIOC_8CH 0x6
+#define Q_GPIO_SUBTYPE_GPIO_4CH 0x1
+#define Q_GPIO_SUBTYPE_GPIOC_4CH 0x5
+#define Q_GPIO_SUBTYPE_GPIO_8CH 0x9
+#define Q_GPIO_SUBTYPE_GPIOC_8CH 0xD
/* mpp peripheral type and subtype values */
#define Q_MPP_TYPE 0x11
#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3
#define Q_MPP_SUBTYPE_4CH_NO_SINK 0x5
-#define Q_MPP_SUBTYPE_4CH_FULL_FUNC 0x2
-#define Q_MPP_SUBTYPE_8CH_FULL_FUNC 0x4
+#define Q_MPP_SUBTYPE_4CH_FULL_FUNC 0x7
+#define Q_MPP_SUBTYPE_8CH_FULL_FUNC 0xF
/* control register base address offsets */
#define Q_REG_MODE_CTL 0x40
@@ -129,7 +129,8 @@
#define Q_NUM_PARAMS Q_PIN_CFG_INVALID
/* param error checking */
-#define QPNP_PIN_MODE_INVALID 3
+#define QPNP_PIN_GPIO_MODE_INVALID 3
+#define QPNP_PIN_MPP_MODE_INVALID 7
#define QPNP_PIN_INVERT_INVALID 2
#define QPNP_PIN_OUT_BUF_INVALID 3
#define QPNP_PIN_VIN_4CH_INVALID 5
@@ -225,8 +226,12 @@
{
switch (idx) {
case Q_PIN_CFG_MODE:
- if (val >= QPNP_PIN_MODE_INVALID)
- return -EINVAL;
+ if (q_spec->type == Q_GPIO_TYPE &&
+ val >= QPNP_PIN_GPIO_MODE_INVALID)
+ return -EINVAL;
+ else if (q_spec->type == Q_MPP_TYPE &&
+ val >= QPNP_PIN_MPP_MODE_INVALID)
+ return -EINVAL;
break;
case Q_PIN_CFG_OUTPUT_TYPE:
if (q_spec->type != Q_GPIO_TYPE)
@@ -327,29 +332,40 @@
name = (q_spec->type == Q_GPIO_TYPE) ? "gpio" : "mpp";
if (Q_CHK_INVALID(Q_PIN_CFG_MODE, q_spec, param->mode))
- pr_err("invalid direction for %s %d\n", name, pin);
+ pr_err("invalid direction value %d for %s %d\n",
+ param->mode, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_INVERT, q_spec, param->invert))
- pr_err("invalid invert polarity for %s %d\n", name, pin);
+ pr_err("invalid invert polarity value %d for %s %d\n",
+ param->invert, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_SELECT, q_spec, param->select))
- pr_err("invalid source select for %s %d\n", name, pin);
+ pr_err("invalid source select value %d for %s %d\n",
+ param->select, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_OUT_STRENGTH,
q_spec, param->out_strength))
- pr_err("invalid out strength for %s %d\n", name, pin);
+ pr_err("invalid out strength value %d for %s %d\n",
+ param->out_strength, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_OUTPUT_TYPE,
q_spec, param->output_type))
- pr_err("invalid out type for %s %d\n", name, pin);
+ pr_err("invalid out type value %d for %s %d\n",
+ param->output_type, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
- pr_err("invalid vin select value for %s %d\n", name, pin);
+ pr_err("invalid vin select %d value for %s %d\n",
+ param->vin_sel, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_PULL, q_spec, param->pull))
- pr_err("invalid pull value for pin %s %d\n", name, pin);
+ pr_err("invalid pull value %d for pin %s %d\n",
+ param->pull, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
- pr_err("invalid master_en value for %s %d\n", name, pin);
+ pr_err("invalid master_en value %d for %s %d\n",
+ param->master_en, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
- pr_err("invalid aout_reg value for %s %d\n", name, pin);
+ pr_err("invalid aout_reg value %d for %s %d\n",
+ param->aout_ref, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
- pr_err("invalid ain_route value for %s %d\n", name, pin);
+ pr_err("invalid ain_route value %d for %s %d\n",
+ param->ain_route, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
- pr_err("invalid cs_out value for %s %d\n", name, pin);
+ pr_err("invalid cs_out value %d for %s %d\n",
+ param->cs_out, name, pin);
else
return 0;
@@ -532,7 +548,7 @@
return 0;
gpio_cfg:
- dev_err(dev, "%s: unable to set default config for pmic gpio %d\n",
+ dev_err(dev, "%s: unable to set default config for pmic pin %d\n",
__func__, q_spec->pmic_pin);
return rc;
@@ -688,7 +704,7 @@
if (!q_chip || !q_spec)
return -EINVAL;
- if (mode >= QPNP_PIN_MODE_INVALID) {
+ if (qpnp_pin_check_config(Q_PIN_CFG_MODE, q_spec, mode)) {
pr_err("invalid mode specification %d\n", mode);
return -EINVAL;
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6a894c8..3d1fbc8 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -111,7 +111,7 @@
.gmem_size = SZ_256K,
.pfp_fw = NULL,
.pm4_fw = NULL,
- .wait_timeout = 10000, /* in milliseconds */
+ .wait_timeout = 0, /* in milliseconds, 0 means disabled */
.ib_check_level = 0,
};
@@ -1481,7 +1481,7 @@
* them to pass */
adreno_ringbuffer_restore(rb, rec_data->bad_rb_buffer,
rec_data->bad_rb_size);
- idle_ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ idle_ret = adreno_idle(device);
if (idle_ret) {
ret = adreno_stop(device);
if (ret) {
@@ -1524,7 +1524,7 @@
if (ret || !rec_data->bad_rb_size) {
adreno_ringbuffer_restore(rb, rec_data->rb_buffer,
rec_data->rb_size);
- ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ ret = adreno_idle(device);
if (ret) {
/* If we fail here we can try to invalidate another
* context and try recovering again */
@@ -1806,61 +1806,74 @@
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)
+static int adreno_ringbuffer_drain(struct kgsl_device *device,
+ unsigned int *regs)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ unsigned long wait;
+ unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+
+ if (!(rb->flags & KGSL_FLAGS_STARTED))
+ return 0;
+
+ /*
+ * The first time into the loop, wait for 100 msecs and kick wptr again
+ * to ensure that the hardware has updated correctly. After that, kick
+ * it periodically every KGSL_TIMEOUT_PART msecs until the timeout
+ * expires
+ */
+
+ wait = jiffies + msecs_to_jiffies(100);
+
+ adreno_poke(device);
+
+ do {
+ if (time_after(jiffies, wait)) {
+ adreno_poke(device);
+
+ /* Check to see if the core is hung */
+ if (adreno_hang_detect(device, regs))
+ return -ETIMEDOUT;
+
+ wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+ }
+ GSL_RB_GET_READPTR(rb, &rb->rptr);
+
+ if (time_after(jiffies, timeout)) {
+ KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
+ rb->rptr, rb->wptr);
+ return -ETIMEDOUT;
+ }
+ } while (rb->rptr != rb->wptr);
+
+ return 0;
+}
+
+/* Caller must hold the device mutex. */
+int adreno_idle(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int rbbm_status;
- unsigned long wait_timeout =
- msecs_to_jiffies(adreno_dev->wait_timeout);
unsigned long wait_time;
unsigned long wait_time_part;
- unsigned int msecs;
- unsigned int msecs_first;
- unsigned int msecs_part = KGSL_TIMEOUT_PART;
unsigned int prev_reg_val[hang_detect_regs_count];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
- /* Restrict timeout value between adreno_dev->wait_timeout and 0 */
- if ((timeout == 0) || (timeout > adreno_dev->wait_timeout))
- msecs = adreno_dev->wait_timeout;
- else
- msecs = timeout;
-
kgsl_cffdump_regpoll(device->id,
adreno_dev->gpudev->reg_rbbm_status << 2,
0x00000000, 0x80000000);
- /* first, wait until the CP has consumed all the commands in
- * the ring buffer
- */
+
retry:
- if (rb->flags & KGSL_FLAGS_STARTED) {
- msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
- wait_time = jiffies + wait_timeout;
- wait_time_part = jiffies + msecs_to_jiffies(msecs_first);
- adreno_poke(device);
- do {
- if (time_after(jiffies, wait_time_part)) {
- adreno_poke(device);
- wait_time_part = jiffies +
- msecs_to_jiffies(msecs_part);
- if ((adreno_hang_detect(device, prev_reg_val)))
- goto err;
- }
- GSL_RB_GET_READPTR(rb, &rb->rptr);
- if (time_after(jiffies, wait_time)) {
- KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
- rb->rptr, rb->wptr);
- goto err;
- }
- } while (rb->rptr != rb->wptr);
- }
+ /* First, wait for the ringbuffer to drain */
+ if (adreno_ringbuffer_drain(device, prev_reg_val))
+ goto err;
/* now, wait for the GPU to finish its operations */
- wait_time = jiffies + wait_timeout;
- wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
+ wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+ wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+
while (time_before(jiffies, wait_time)) {
adreno_regread(device, adreno_dev->gpudev->reg_rbbm_status,
&rbbm_status);
@@ -1876,7 +1889,7 @@
*/
if (time_after(jiffies, wait_time_part)) {
wait_time_part = jiffies +
- msecs_to_jiffies(msecs_part);
+ msecs_to_jiffies(KGSL_TIMEOUT_PART);
if ((adreno_hang_detect(device, prev_reg_val)))
goto err;
}
@@ -1887,7 +1900,7 @@
KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
if (KGSL_STATE_DUMP_AND_RECOVER != device->state &&
!adreno_dump_and_recover(device)) {
- wait_time = jiffies + wait_timeout;
+ wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
goto retry;
}
return -ETIMEDOUT;
@@ -1934,7 +1947,7 @@
/* switch to NULL ctxt */
if (adreno_dev->drawctxt_active != NULL) {
adreno_drawctxt_switch(adreno_dev, NULL, 0);
- status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ status = adreno_idle(device);
}
return status;
@@ -2184,12 +2197,11 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int retries = 0;
- unsigned int msecs_first;
- unsigned int msecs_part = KGSL_TIMEOUT_PART;
unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
unsigned int time_elapsed = 0;
unsigned int prev_reg_val[hang_detect_regs_count];
+ unsigned int wait;
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -2207,11 +2219,18 @@
goto done;
}
- /* Keep the first timeout as 100msecs before rewriting
- * the WPTR. Less visible impact if the WPTR has not
- * been updated properly.
+ /*
+ * Make the first timeout interval 100 msecs and then try to kick the
+ * wptr again. This helps to ensure the wptr is updated properly. If
+ * the requested timeout is less than 100 msecs, then wait 20msecs which
+ * is the minimum amount of time we can safely wait at 100HZ
*/
- msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
+
+ if (msecs == 0 || msecs >= 100)
+ wait = 100;
+ else
+ wait = 20;
+
do {
/*
* If the context ID is invalid, we are in a race with
@@ -2250,8 +2269,8 @@
device->wait_queue,
kgsl_check_interrupt_timestamp(device,
context, timestamp),
- msecs_to_jiffies(retries ?
- msecs_part : msecs_first), io);
+ msecs_to_jiffies(wait), io);
+
mutex_lock(&device->mutex);
if (status > 0) {
@@ -2264,11 +2283,12 @@
}
/*this wait timed out*/
- time_elapsed = time_elapsed +
- (retries ? msecs_part : msecs_first);
+ time_elapsed += wait;
+ wait = KGSL_TIMEOUT_PART;
+
retries++;
- } while (time_elapsed < msecs);
+ } while (!msecs || time_elapsed < msecs);
hang_dump:
/*
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index b923049e..26d5eaa 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -55,6 +55,12 @@
#define ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW 50
+/* One cannot wait forever for the core to idle, so set an upper limit to the
+ * amount of time to wait for the core to go idle
+ */
+
+#define ADRENO_IDLE_TIMEOUT (20 * 1000)
+
enum adreno_gpurev {
ADRENO_REV_UNKNOWN = 0,
ADRENO_REV_A200 = 200,
@@ -162,7 +168,7 @@
extern const unsigned int hang_detect_regs_count;
-int adreno_idle(struct kgsl_device *device, unsigned int timeout);
+int adreno_idle(struct kgsl_device *device);
void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
unsigned int *value);
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2dbfd8f..205c9ff 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2290,9 +2290,6 @@
build_quad_vtxbuff(drawctxt, &drawctxt->context_gmem_shadow,
&tmp_ctx.cmd);
- /* Dow we need to idle? */
- /* adreno_idle(&adreno_dev->dev, KGSL_TIMEOUT_DEFAULT); */
-
tmp_ctx.cmd = build_gmem2sys_cmds(adreno_dev, drawctxt,
&drawctxt->context_gmem_shadow);
tmp_ctx.cmd = build_sys2gmem_cmds(adreno_dev, drawctxt,
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 6c74dfa..bd22233 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -224,7 +224,7 @@
adreno_drawctxt_switch(adreno_dev, NULL, 0);
}
- adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ adreno_idle(device);
kgsl_sharedmem_free(&drawctxt->gpustate);
kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ca9e335..ad9007f 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -52,11 +52,9 @@
unsigned int freecmds;
unsigned int *cmds;
uint cmds_gpu;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
- unsigned long wait_timeout = msecs_to_jiffies(adreno_dev->wait_timeout);
unsigned long wait_time;
+ unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
unsigned long wait_time_part;
- unsigned int msecs_part = KGSL_TIMEOUT_PART;
unsigned int prev_reg_val[hang_detect_regs_count];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -87,7 +85,7 @@
}
wait_time = jiffies + wait_timeout;
- wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
+ wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
/* wait for space in ringbuffer */
while (1) {
GSL_RB_GET_READPTR(rb, &rb->rptr);
@@ -101,7 +99,7 @@
*/
if (time_after(jiffies, wait_time_part)) {
wait_time_part = jiffies +
- msecs_to_jiffies(msecs_part);
+ msecs_to_jiffies(KGSL_TIMEOUT_PART);
if ((adreno_hang_detect(rb->device,
prev_reg_val))){
KGSL_DRV_ERR(rb->device,
@@ -393,7 +391,7 @@
adreno_dev->gpudev->rb_init(adreno_dev, rb);
/* idle device to validate ME INIT */
- status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ status = adreno_idle(device);
if (status == 0)
rb->flags |= KGSL_FLAGS_STARTED;
@@ -961,7 +959,7 @@
* this is conservative but works reliably and is ok
* even for performance simulations
*/
- adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ adreno_idle(device);
#endif
/* If context hung and recovered then return error so that the
* application may handle it */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 3d83508..e7a1c13 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -559,7 +559,7 @@
break;
case KGSL_STATE_ACTIVE:
/* Wait for the device to become idle */
- device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
+ device->ftbl->idle(device);
case KGSL_STATE_NAP:
case KGSL_STATE_SLEEP:
/* Get the completion ready to be waited upon. */
@@ -2605,7 +2605,7 @@
}
if (device->state == KGSL_STATE_ACTIVE)
- kgsl_idle(device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(device);
}
KGSL_LOG_DUMP(device, "|%s| Dump Started\n", device->name);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index d0932ef..2a2e916 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -67,7 +67,7 @@
unsigned int offsetwords, unsigned int *value);
void (*regwrite) (struct kgsl_device *device,
unsigned int offsetwords, unsigned int value);
- int (*idle) (struct kgsl_device *device, unsigned int timeout);
+ int (*idle) (struct kgsl_device *device);
unsigned int (*isidle) (struct kgsl_device *device);
int (*suspend_context) (struct kgsl_device *device);
int (*start) (struct kgsl_device *device, unsigned int init_ram);
@@ -287,9 +287,9 @@
device->ftbl->regwrite(device, offsetwords, value);
}
-static inline int kgsl_idle(struct kgsl_device *device, unsigned int timeout)
+static inline int kgsl_idle(struct kgsl_device *device)
{
- return device->ftbl->idle(device, timeout);
+ return device->ftbl->idle(device);
}
static inline unsigned int kgsl_gpuid(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index d8472f2..8cf00ea 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -472,7 +472,7 @@
return;
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
- kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(mmu->device);
gpummu_pt = mmu->hwpagetable->priv;
kgsl_regwrite(mmu->device, MH_MMU_PT_BASE,
gpummu_pt->base.gpuaddr);
@@ -552,7 +552,7 @@
kgsl_regwrite(device, MH_MMU_CONFIG, mmu->config);
/* idle device */
- kgsl_idle(device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(device);
/* enable axi interrupts */
kgsl_regwrite(device, MH_INTERRUPT_MASK,
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e858651..1eb671f 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -966,7 +966,7 @@
/* Mask off the lsb of the pt base address since lsb will not change */
pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
- kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(mmu->device);
for (i = 0; i < iommu->unit_count; i++) {
/* get the lsb value which should not change when
* changing ttbr0 */
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 8e6c5c0..0426339 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -560,7 +560,7 @@
struct kgsl_mh *mh = &device->mh;
/* force mmu off to for now*/
kgsl_regwrite(device, MH_MMU_CONFIG, 0);
- kgsl_idle(device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(device);
/* define physical memory range accessible by the core */
kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base);
@@ -824,3 +824,13 @@
kgsl_mmu_type = KGSL_MMU_TYPE_NONE;
}
EXPORT_SYMBOL(kgsl_mmu_set_mmutype);
+
+int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+{
+ if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
+ return 1;
+ return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
+ (gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+}
+EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range);
+
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 5293d66..8221b80 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -205,6 +205,7 @@
void kgsl_mmu_set_mmutype(char *mmutype);
enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
unsigned int kgsl_mmu_get_ptsize(void);
+int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr);
/*
* Static inline functions of MMU that simply call the SMMU specific
@@ -293,12 +294,6 @@
mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid);
}
-static inline int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
-{
- return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
- (gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
-}
-
static inline unsigned int kgsl_mmu_get_int_mask(void)
{
/* Dont enable gpummu interrupts, if iommu is enabled */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 4b5021d..e4d7141 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -80,8 +80,8 @@
* Idle the gpu core before changing the clock freq.
*/
if (pwr->idle_needed == true)
- device->ftbl->idle(device,
- KGSL_TIMEOUT_DEFAULT);
+ device->ftbl->idle(device);
+
/* Don't shift by more than one level at a time to
* avoid glitches.
*/
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 9037f3c..8ddc991 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -358,7 +358,7 @@
return ts_diff < Z180_PACKET_COUNT;
}
-static int z180_idle(struct kgsl_device *device, unsigned int timeout)
+static int z180_idle(struct kgsl_device *device)
{
int status = 0;
struct z180_device *z180_dev = Z180_DEVICE(device);
@@ -366,7 +366,8 @@
if (timestamp_cmp(z180_dev->current_timestamp,
z180_dev->timestamp) > 0)
status = z180_wait(device, NULL,
- z180_dev->current_timestamp, timeout);
+ z180_dev->current_timestamp,
+ Z180_IDLE_TIMEOUT);
if (status)
KGSL_DRV_ERR(device, "z180_waittimestamp() timed out\n");
@@ -583,7 +584,7 @@
static int z180_stop(struct kgsl_device *device)
{
device->ftbl->irqctrl(device, 0);
- z180_idle(device, KGSL_TIMEOUT_DEFAULT);
+ z180_idle(device);
del_timer_sync(&device->idle_timer);
@@ -852,7 +853,7 @@
{
struct z180_device *z180_dev = Z180_DEVICE(device);
- z180_idle(device, KGSL_TIMEOUT_DEFAULT);
+ z180_idle(device);
if (z180_dev->ringbuffer.prevctx == context->id) {
z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index 6e81a9d..a8973d2 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -28,6 +28,9 @@
#define Z180_DEFAULT_PWRSCALE_POLICY NULL
+/* Wait a maximum of 10 seconds when trying to idle the core */
+#define Z180_IDLE_TIMEOUT (10 * 1000)
+
struct z180_ringbuffer {
unsigned int prevctx;
struct kgsl_memdesc cmdbufdesc;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 297afa7..c1617bff 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1339,8 +1339,10 @@
}
free_irq(dev->err_irq, dev);
} else {
- if (dev->dev->of_node)
+ if (dev->dev->of_node) {
+ dev->adapter.dev.of_node = pdev->dev.of_node;
of_i2c_register_devices(&dev->adapter);
+ }
return 0;
}
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1c70527..49a081e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -36,7 +36,9 @@
/* Family ID */
#define MXT224_ID 0x80
#define MXT224E_ID 0x81
+#define MXT336S_ID 0x82
#define MXT1386_ID 0xA0
+#define MXT1664S_ID 0xA2
/* Version */
#define MXT_VER_20 20
@@ -94,6 +96,7 @@
#define MXT_TOUCH_PROXKEY_T52 52
#define MXT_PROCI_GRIPFACE_T20 20
#define MXT_PROCG_NOISE_T22 22
+#define MXT_PROCG_NOISE_T62 62
#define MXT_PROCI_ONETOUCH_T24 24
#define MXT_PROCI_TWOTOUCH_T27 27
#define MXT_PROCI_GRIP_T40 40
@@ -102,6 +105,7 @@
#define MXT_PROCI_STYLUS_T47 47
#define MXT_PROCI_ADAPTIVETHRESHOLD_T55 55
#define MXT_PROCI_SHIELDLESS_T56 56
+#define MXT_PROCI_EXTRATSDATA_T57 57
#define MXT_PROCG_NOISESUPPRESSION_T48 48
#define MXT_SPT_COMMSCONFIG_T18 18
#define MXT_SPT_GPIOPWM_T19 19
@@ -111,6 +115,7 @@
#define MXT_SPT_DIGITIZER_T43 43
#define MXT_SPT_MESSAGECOUNT_T44 44
#define MXT_SPT_CTECONFIG_T46 46
+#define MXT_SPT_TIMER_T61 61
/* MXT_GEN_COMMAND_T6 field */
#define MXT_COMMAND_RESET 0
@@ -231,6 +236,8 @@
#define MXT224_RESET_TIME 65 /* msec */
#define MXT224E_RESET_TIME 150 /* msec */
#define MXT1386_RESET_TIME 250 /* msec */
+#define MXT336S_RESET_TIME 25 /* msec */
+#define MXT1664S_RESET_TIME 65 /* msec */
#define MXT_RESET_TIME 250 /* msec */
#define MXT_RESET_NOCHGREAD 400 /* msec */
@@ -372,6 +379,7 @@
case MXT_TOUCH_PROXKEY_T52:
case MXT_PROCI_GRIPFACE_T20:
case MXT_PROCG_NOISE_T22:
+ case MXT_PROCG_NOISE_T62:
case MXT_PROCI_ONETOUCH_T24:
case MXT_PROCI_TWOTOUCH_T27:
case MXT_PROCI_GRIP_T40:
@@ -379,6 +387,7 @@
case MXT_PROCI_TOUCHSUPPRESSION_T42:
case MXT_PROCI_STYLUS_T47:
case MXT_PROCI_SHIELDLESS_T56:
+ case MXT_PROCI_EXTRATSDATA_T57:
case MXT_PROCG_NOISESUPPRESSION_T48:
case MXT_SPT_COMMSCONFIG_T18:
case MXT_SPT_GPIOPWM_T19:
@@ -387,6 +396,7 @@
case MXT_SPT_USERDATA_T38:
case MXT_SPT_DIGITIZER_T43:
case MXT_SPT_CTECONFIG_T46:
+ case MXT_SPT_TIMER_T61:
case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
return true;
default:
@@ -406,6 +416,7 @@
case MXT_TOUCH_PROXKEY_T52:
case MXT_PROCI_GRIPFACE_T20:
case MXT_PROCG_NOISE_T22:
+ case MXT_PROCG_NOISE_T62:
case MXT_PROCI_ONETOUCH_T24:
case MXT_PROCI_TWOTOUCH_T27:
case MXT_PROCI_GRIP_T40:
@@ -413,6 +424,7 @@
case MXT_PROCI_TOUCHSUPPRESSION_T42:
case MXT_PROCI_STYLUS_T47:
case MXT_PROCI_SHIELDLESS_T56:
+ case MXT_PROCI_EXTRATSDATA_T57:
case MXT_PROCG_NOISESUPPRESSION_T48:
case MXT_SPT_COMMSCONFIG_T18:
case MXT_SPT_GPIOPWM_T19:
@@ -421,6 +433,7 @@
case MXT_SPT_USERDATA_T38:
case MXT_SPT_DIGITIZER_T43:
case MXT_SPT_CTECONFIG_T46:
+ case MXT_SPT_TIMER_T61:
case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
return true;
default:
@@ -1293,8 +1306,12 @@
case MXT224E_ID:
msleep(MXT224E_RESET_TIME);
break;
+ case MXT336S_ID:
+ msleep(MXT336S_RESET_TIME);
case MXT1386_ID:
msleep(MXT1386_RESET_TIME);
+ case MXT1664S_ID:
+ msleep(MXT1664S_RESET_TIME);
break;
default:
msleep(MXT_RESET_TIME);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 372c612..c1d1462 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -65,6 +65,11 @@
/* Channel timeout in msec */
#define TSPP_CHANNEL_TIMEOUT 16
+/* module parameters for load time configuration */
+static int tsif0_mode = TSPP_TSIF_MODE_2;
+static int tsif1_mode = TSPP_TSIF_MODE_2;
+module_param(tsif0_mode, int, S_IRUGO);
+module_param(tsif1_mode, int, S_IRUGO);
/*
* Work scheduled each time TSPP notifies dmx
@@ -273,14 +278,17 @@
int ret;
int channel_id;
int *channel_ref_count;
+ enum tspp_tsif_mode mode;
/* determine the TSIF we are reading from */
if (mpq_demux->source == DMX_SOURCE_FRONT0) {
tsif = 0;
tspp_source = TSPP_SOURCE_TSIF0;
+ mode = (enum tspp_tsif_mode)tsif0_mode;
} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
tsif = 1;
tspp_source = TSPP_SOURCE_TSIF1;
+ mode = (enum tspp_tsif_mode)tsif1_mode;
} else {
/* invalid source */
MPQ_DVB_ERR_PRINT(
@@ -333,7 +341,7 @@
}
/* set TSPP source */
- ret = tspp_open_stream(0, channel_id, tspp_source);
+ ret = tspp_open_stream(0, channel_id, tspp_source, mode);
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: tspp_select_source(%d,%d) failed (%d)\n",
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index c0a35f9..1894465 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2347,37 +2347,6 @@
int retval;
radio->region = req_region;
- switch (radio->region) {
- case IRIS_REGION_US:
- radio->recv_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_EU:
- radio->recv_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_STANDARD_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_STANDARD_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN_WIDE:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_WIDE_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_WIDE_BAND_HIGH;
- break;
- default:
- /* The user specifies the value.
- So nothing needs to be done */
- break;
- }
-
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
@@ -2391,34 +2360,6 @@
int retval;
radio->region = req_region;
- switch (radio->region) {
- case IRIS_REGION_US:
- radio->trans_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_EU:
- radio->trans_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN:
- radio->trans_conf.band_low_limit =
- REGION_JAPAN_STANDARD_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_JAPAN_STANDARD_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN_WIDE:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_WIDE_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_WIDE_BAND_HIGH;
- default:
- break;
- }
-
retval = hci_set_fm_trans_conf(
&radio->trans_conf,
radio->fm_hdev);
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
index 96a6e04..effae8b 100644
--- a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
@@ -100,7 +100,7 @@
}
rc = e_ctrl->func_tbl.eeprom_get_info(e_ctrl,
&cdata.cfg.get_info);
-
+ cdata.is_eeprom_supported = 1;
if (copy_to_user((void *)argp,
&cdata,
sizeof(struct msm_eeprom_cfg_data)))
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 7e80145..9549dcc 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -21,7 +21,7 @@
#include <mach/clk.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
-
+#include <mach/dal_axi.h>
#define MSM_AXI_QOS_PREVIEW 200000
#define MSM_AXI_QOS_SNAPSHOT 200000
@@ -142,6 +142,7 @@
break;
case S_PREVIEW:
update_axi_qos(MSM_AXI_QOS_PREVIEW);
+ axi_allocate(AXI_FLOW_VIEWFINDER_HI);
break;
case S_VIDEO:
update_axi_qos(MSM_AXI_QOS_RECORDING);
@@ -153,6 +154,7 @@
update_axi_qos(PM_QOS_DEFAULT_VALUE);
break;
case S_EXIT:
+ axi_free(AXI_FLOW_VIEWFINDER_HI);
release_axi_qos();
break;
default:
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index b7f6b08..d876f12 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -341,7 +341,6 @@
case MSM_CAM_IOCTL_EEPROM_IO_CFG: {
struct msm_eeprom_cfg_data eeprom_data;
if (p_mctl->eeprom_sdev) {
- eeprom_data.is_eeprom_supported = 1;
rc = v4l2_subdev_call(p_mctl->eeprom_sdev,
core, ioctl, VIDIOC_MSM_EEPROM_CFG, argp);
} else {
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 7d58091..0919799 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1542,7 +1542,6 @@
case NOTIFY_VFE_MSG_STATS:
case NOTIFY_VFE_MSG_COMP_STATS:
case NOTIFY_VFE_CAMIF_ERROR:
- case NOTIFY_VFE_IRQ:
default:
interface = PIX_0;
break;
@@ -1593,11 +1592,10 @@
case NOTIFY_VFE_IRQ:{
struct msm_vfe_cfg_cmd cfg_cmd;
struct msm_camvfe_params vfe_params;
- p_mctl = msm_cam_server_get_mctl(mctl_handle);
cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
vfe_params.vfe_cfg = &cfg_cmd;
vfe_params.data = arg;
- rc = v4l2_subdev_call(p_mctl->isp_sdev->sd,
+ rc = v4l2_subdev_call(sd,
core, ioctl, 0, &vfe_params);
}
break;
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 3e01437..c8d22d4 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -4359,7 +4359,7 @@
VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
if (stat_interrupt)
vfe32_ctrl->simultaneous_sof_stat = 1;
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
}
@@ -4367,25 +4367,25 @@
/* interrupt to be processed, *qcmd has the payload. */
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_REG_UPDATE_MASK)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_RDI0_REG_UPDATE);
if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_RDI1_REG_UPDATE);
if (qcmd->vfeInterruptStatus1 &
VFE_IMASK_WHILE_STOPPING_1)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IMASK_WHILE_STOPPING_1);
@@ -4410,7 +4410,7 @@
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
CDBG("Stats composite irq occured.\n");
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)qcmd->vfeInterruptStatus0);
}
@@ -4418,60 +4418,60 @@
/* process individual stats interrupt. */
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AEC_BG)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_AEC_BG);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AWB)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_AWB);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AF_BF)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_AF_BF);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_SK_BHIST)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_SK_BHIST);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_IHIST)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_IHIST);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_RS)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_RS);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_CS)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_CS);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_SYNC_TIMER0)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_SYNC_TIMER0);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_SYNC_TIMER1)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_SYNC_TIMER1);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_SYNC_TIMER2)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_SYNC_TIMER2);
}
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index e1d8b48..460eb07 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -696,7 +696,6 @@
switch (id) {
case MSG_SNAPSHOT:
- msm_camio_set_perf_lvl(S_PREVIEW);
while (vfe2x_ctrl->snap.frame_cnt <
vfe2x_ctrl->num_snap) {
vfe_7x_ops(driver_data, MSG_OUTPUT_S, len,
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index cf1ebbb..4d02cff 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -505,6 +505,13 @@
return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
}
+static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *enc)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_encoder_cmd((void *)vidc_inst, enc);
+}
+
static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -524,6 +531,7 @@
.vidioc_subscribe_event = msm_v4l2_subscribe_event,
.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+ .vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
};
static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index c87211a..a838a12 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -648,6 +648,11 @@
pr_err("Failed to set scratch buffers: %d\n", rc);
goto fail_start;
}
+ rc = msm_comm_set_persist_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set persist buffers: %d\n", rc);
+ goto fail_start;
+ }
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
pr_err("Failed to move inst: %p to start done state\n",
@@ -717,11 +722,13 @@
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
- rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ rc = msm_comm_try_state(inst,
+ MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
- rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ rc = msm_comm_try_state(inst,
+ MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
default:
pr_err("Q-type is not supported: %d\n", q->type);
@@ -730,7 +737,7 @@
}
if (rc)
pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
- inst, q->type, MSM_VIDC_CLOSE_DONE);
+ inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
return rc;
}
@@ -742,6 +749,74 @@
pr_err("Failed to queue buffer: %d\n", rc);
}
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
+{
+ int rc = 0;
+ bool ip_flush = false,
+ op_flush = false;
+
+ switch (dec->cmd) {
+ case V4L2_DEC_QCOM_CMD_FLUSH:
+ mutex_lock(&inst->sync_lock);
+ ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
+ op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
+ /* Only support flush on decoder (for now)*/
+ if (inst->session_type == MSM_VIDC_ENCODER) {
+ pr_err("Buffer flushing not supported for encoder\n");
+ rc = -ENOTSUPP;
+ mutex_unlock(&inst->sync_lock);
+ break;
+ }
+
+ /* Certain types of flushes aren't supported such as: */
+ /* 1) Input only flush */
+ if (ip_flush && !op_flush) {
+ pr_err("Input only flush not supported\n");
+ rc = -ENOTSUPP;
+ mutex_unlock(&inst->sync_lock);
+ break;
+ }
+
+ /* 2) Output only flush when in reconfig */
+ if (!ip_flush && op_flush && !inst->in_reconfig) {
+ pr_err("Output only flush only supported when reconfiguring\n");
+ rc = -ENOTSUPP;
+ mutex_unlock(&inst->sync_lock);
+ break;
+ }
+
+ /* Finally flush */
+ if (op_flush && ip_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_ALL);
+ else if (ip_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_INPUT);
+ else if (op_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_OUTPUT);
+ mutex_unlock(&inst->sync_lock);
+ break;
+ case V4L2_DEC_CMD_STOP:
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ if (rc)
+ pr_err("Failed to close instance\n");
+ break;
+ default:
+ pr_err("Unknown Decoder Command\n");
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ if (rc) {
+ pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
+ goto exit;
+ }
+exit:
+ return rc;
+}
+
+
static const struct vb2_ops msm_vdec_vb2q_ops = {
.queue_setup = msm_vdec_queue_setup,
.start_streaming = msm_vdec_start_streaming,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 1242fb4..b8326d8 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -31,6 +31,7 @@
int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
struct vb2_ops *msm_vdec_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 14baf79..10c7321 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -26,9 +26,9 @@
#define MAX_BIT_RATE 160000
#define DEFAULT_BIT_RATE 64
#define BIT_RATE_STEP 1
-#define MIN_FRAME_RATE 1
-#define MAX_FRAME_RATE 240
-#define DEFAULT_FRAME_RATE 30
+#define MIN_FRAME_RATE 65536
+#define MAX_FRAME_RATE 15728640
+#define DEFAULT_FRAME_RATE 1966080
#define DEFAULT_IR_MBS 30
#define MAX_SLICE_BYTE_SIZE 1024
#define MIN_SLICE_BYTE_SIZE 1024
@@ -621,11 +621,21 @@
unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get Buffer Requirements : %d\n", rc);
+ goto fail_start;
+ }
rc = msm_comm_set_scratch_buffers(inst);
if (rc) {
pr_err("Failed to set scratch buffers: %d\n", rc);
goto fail_start;
}
+ rc = msm_comm_set_persist_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set persist buffers: %d\n", rc);
+ goto fail_start;
+ }
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
pr_err("Failed to move inst: %p to start done state\n",
@@ -696,7 +706,7 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
default:
pr_err("Q-type is not supported: %d\n", q->type);
@@ -752,7 +762,12 @@
void *pdata;
struct msm_vidc_inst *inst = container_of(ctrl->handler,
struct msm_vidc_inst, ctrl_handler);
-
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto failed_open_done;
+ }
control.id = ctrl->id;
control.value = ctrl->val;
@@ -1172,6 +1187,7 @@
}
if (rc)
pr_err("Failed to set hal property for framesize\n");
+failed_open_done:
return rc;
}
static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -1214,6 +1230,15 @@
return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
}
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc)
+{
+ int rc = 0;
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ if (rc)
+ pr_err("Failed to close instance\n");
+ return rc;
+}
+
int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
{
if (!inst || !cap) {
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index 4a156dd..83610b3 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -30,6 +30,7 @@
int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
struct vb2_ops *msm_venc_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 4d4cec5..7c9b6db 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,11 +29,6 @@
struct vb2_buffer *out_vb = NULL;
struct vb2_buffer *cap_vb = NULL;
unsigned long flags;
- if (!outq->streaming && !capq->streaming) {
- pr_err("Returning POLLERR from here: %d, %d\n",
- outq->streaming, capq->streaming);
- return POLLERR;
- }
poll_wait(filp, &inst->event_handler.wait, wait);
poll_wait(filp, &capq->done_wq, wait);
poll_wait(filp, &outq->done_wq, wait);
@@ -140,6 +135,22 @@
return -EINVAL;
}
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_cmd(instance, enc);
+ return -EINVAL;
+}
+
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_cmd(instance, dec);
+ return -EINVAL;
+}
+
int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
@@ -243,6 +254,7 @@
inst->session_type = session_type;
INIT_LIST_HEAD(&inst->pendingq);
INIT_LIST_HEAD(&inst->internalbufs);
+ INIT_LIST_HEAD(&inst->persistbufs);
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
@@ -316,6 +328,15 @@
kfree(buf);
}
}
+ if (!list_empty(&inst->persistbufs)) {
+ list_for_each_safe(ptr, next, &inst->persistbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
if (inst->extradata_handle)
msm_smem_free(inst->mem_client, inst->extradata_handle);
spin_unlock_irqrestore(&inst->lock, flags);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index b07c63b..4fce805 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -1421,67 +1421,6 @@
return rc;
}
-int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
-{
- int rc = 0;
- struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
- bool ip_flush = false,
- op_flush = false;
-
- mutex_lock(&inst->sync_lock);
-
- switch (dec->cmd) {
- case V4L2_DEC_QCOM_CMD_FLUSH:
- ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
- op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
- /* Only support flush on decoder (for now)*/
- if (inst->session_type == MSM_VIDC_ENCODER) {
- pr_err("Buffer flushing not supported for encoder\n");
- rc = -ENOTSUPP;
- break;
- }
-
- /* Certain types of flushes aren't supported such as: */
- /* 1) Input only flush */
- if (ip_flush && !op_flush) {
- pr_err("Input only flush not supported\n");
- rc = -ENOTSUPP;
- break;
- }
-
- /* 2) Output only flush when in reconfig */
- if (!ip_flush && op_flush && !inst->in_reconfig) {
- pr_err("Output only flush only supported when reconfiguring\n");
- rc = -ENOTSUPP;
- break;
- }
-
- /* Finally flush */
- if (op_flush && ip_flush)
- rc = vidc_hal_session_flush(inst->session,
- HAL_FLUSH_ALL);
- else if (ip_flush)
- rc = vidc_hal_session_flush(inst->session,
- HAL_FLUSH_INPUT);
- else if (op_flush)
- rc = vidc_hal_session_flush(inst->session,
- HAL_FLUSH_OUTPUT);
-
- break;
- default:
- rc = -ENOTSUPP;
- goto exit;
- }
-
- if (rc) {
- pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
- goto exit;
- }
-exit:
- mutex_unlock(&inst->sync_lock);
- return rc;
-}
-
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
@@ -1549,3 +1488,62 @@
err_no_mem:
return rc;
}
+
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ struct vidc_buffer_addr_info buffer_info;
+ unsigned long flags;
+ struct hal_buffer_requirements *persist_buf =
+ &inst->buff_req.buffer[HAL_BUFFER_INTERNAL_PERSIST];
+ int i;
+ pr_debug("persist: num = %d, size = %d\n",
+ persist_buf->buffer_count_actual,
+ persist_buf->buffer_size);
+ if (!list_empty(&inst->persistbufs)) {
+ pr_err("Persist buffers already allocated\n");
+ return rc;
+ }
+
+ if (persist_buf->buffer_size) {
+ for (i = 0; i < persist_buf->buffer_count_actual; i++) {
+ handle = msm_smem_alloc(inst->mem_client,
+ persist_buf->buffer_size, 1, 0,
+ inst->core->resources.io_map[NS_MAP].domain, 0);
+ if (!handle) {
+ pr_err("Failed to allocate persist memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Out of memory\n");
+ rc = -ENOMEM;
+ goto fail_kzalloc;
+ }
+ binfo->handle = handle;
+ buffer_info.buffer_size = persist_buf->buffer_size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_set_buffers(
+ (void *) inst->session, &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ goto fail_set_buffers;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->persistbufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ }
+ }
+ return rc;
+fail_set_buffers:
+ kfree(binfo);
+fail_kzalloc:
+ msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 2009ca6..9430d5f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -28,6 +28,7 @@
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
int msm_comm_scale_clocks(struct msm_vidc_core *core);
#define IS_PRIV_CTRL(idx) (\
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 8c11de8..630f383 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -207,6 +207,7 @@
spinlock_t lock;
struct list_head pendingq;
struct list_head internalbufs;
+ struct list_head persistbufs;
struct buffer_requirements buff_req;
void *mem_client;
struct v4l2_ctrl_handler ctrl_handler;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index d8bb884..0119ebe 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -16,141 +16,635 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/spmi.h>
+#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/log2.h>
+/* PON common register addresses */
#define QPNP_PON_RT_STS(base) (base + 0x10)
#define QPNP_PON_PULL_CTL(base) (base + 0x70)
#define QPNP_PON_DBC_CTL(base) (base + 0x71)
-#define QPNP_PON_CNTL_PULL_UP BIT(1)
-#define QPNP_PON_CNTL_TRIG_DELAY_MASK (0x7)
+/* PON/RESET sources register addresses */
+#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
+#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
+#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
+#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
+#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
+#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
+
+#define QPNP_PON_RESIN_PULL_UP BIT(0)
+#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
+#define QPNP_PON_S2_CNTL_EN BIT(7)
+#define QPNP_PON_S2_RESET_ENABLE BIT(7)
+
+#define QPNP_PON_S1_TIMER_MASK (0xF)
+#define QPNP_PON_S2_TIMER_MASK (0x7)
+#define QPNP_PON_S2_CNTL_TYPE_MASK (0xF)
+
+#define QPNP_PON_DBC_DELAY_MASK (0x7)
#define QPNP_PON_KPDPWR_N_SET BIT(0)
+#define QPNP_PON_RESIN_N_SET BIT(1)
+#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
+
+/* Ranges */
+#define QPNP_PON_S1_TIMER_MAX 10256
+#define QPNP_PON_S2_TIMER_MAX 2000
+#define QPNP_PON_RESET_TYPE_MAX 0xF
+#define PON_S1_COUNT_MAX 0xF
+
+#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(500)
+
+enum pon_type {
+ PON_KPDPWR,
+ PON_RESIN,
+};
+
+struct qpnp_pon_config {
+ u32 pon_type;
+ u32 support_reset;
+ u32 key_code;
+ u32 s1_timer;
+ u32 s2_timer;
+ u32 s2_type;
+ u32 pull_up;
+ u32 state_irq;
+ u32 bark_irq;
+};
struct qpnp_pon {
struct spmi_device *spmi;
struct input_dev *pon_input;
- u32 key_status_irq;
+ struct qpnp_pon_config *pon_cfg;
+ int num_pon_config;
u16 base;
+ struct delayed_work bark_work;
};
-static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
-{
- u8 pon_rt_sts;
- int rc;
- struct qpnp_pon *pon = _pon;
+static u32 s1_delay[PON_S1_COUNT_MAX + 1] = {
+ 0 , 32, 56, 80, 138, 184, 272, 408, 608, 904, 1352, 2048,
+ 3072, 4480, 6720, 10256
+};
+static int
+qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ addr, ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read from addr=%x, rc(%d)\n", addr, rc);
+ return rc;
+ }
+
+ reg &= ~mask;
+ reg |= val & mask;
+ rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+ addr, ®, 1);
+ if (rc)
+ dev_err(&pon->spmi->dev,
+ "Unable to write to addr=%x, rc(%d)\n", addr, rc);
+ return rc;
+}
+
+static struct qpnp_pon_config *
+qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
+{
+ int i;
+
+ for (i = 0; i < pon->num_pon_config; i++) {
+ if (pon_type == pon->pon_cfg[i].pon_type)
+ return &pon->pon_cfg[i];
+ }
+
+ return NULL;
+}
+
+static int
+qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
+{
+ int rc;
+ struct qpnp_pon_config *cfg = NULL;
+ u8 pon_rt_sts = 0, pon_rt_bit = 0;
+
+ cfg = qpnp_get_cfg(pon, pon_type);
+ if (!cfg)
+ return -EINVAL;
+
+ /* Check if key reporting is supported */
+ if (!cfg->key_code)
+ return 0;
+
+ /* check the RT status to get the current status of the line */
rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
- return IRQ_HANDLED;
+ return rc;
}
- input_report_key(pon->pon_input, KEY_POWER,
- !(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ pon_rt_bit = QPNP_PON_KPDPWR_N_SET;
+ break;
+ case PON_RESIN:
+ pon_rt_bit = QPNP_PON_RESIN_N_SET;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ input_report_key(pon->pon_input, cfg->key_code,
+ (pon_rt_sts & pon_rt_bit));
input_sync(pon->pon_input);
+ return 0;
+}
+
+static irqreturn_t qpnp_kpdpwr_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_KPDPWR);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
return IRQ_HANDLED;
}
-static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
+static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_resin_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_RESIN);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+ return IRQ_HANDLED;
+}
+
+static void bark_work_func(struct work_struct *work)
+{
+ int rc;
+ u8 pon_rt_sts = 0;
+ struct qpnp_pon_config *cfg;
+ struct qpnp_pon *pon =
+ container_of(work, struct qpnp_pon, bark_work.work);
+
+ /* enable reset */
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+ QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ goto err_return;
+ }
+ /* bark RT status update delay */
+ msleep(100);
+ /* read the bark RT status */
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
+ goto err_return;
+ }
+
+ if (!(pon_rt_sts & QPNP_PON_RESIN_BARK_N_SET)) {
+ cfg = qpnp_get_cfg(pon, PON_RESIN);
+ if (!cfg) {
+ dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+ goto err_return;
+ }
+ /* report the key event and enable the bark IRQ */
+ input_report_key(pon->pon_input, cfg->key_code, 0);
+ input_sync(pon->pon_input);
+ enable_irq(cfg->bark_irq);
+ } else {
+ /* disable reset */
+ rc = qpnp_pon_masked_write(pon,
+ QPNP_PON_RESIN_S2_CNTL(pon->base),
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to configure S2 enable\n");
+ goto err_return;
+ }
+ /* re-arm the work */
+ schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+ }
+
+err_return:
+ return;
+}
+
+static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+ struct qpnp_pon_config *cfg;
+
+ /* disable the bark interrupt */
+ disable_irq_nosync(irq);
+
+ /* disable reset */
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ goto err_exit;
+ }
+
+ cfg = qpnp_get_cfg(pon, PON_RESIN);
+ if (!cfg) {
+ dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+ goto err_exit;
+ }
+
+ /* report the key event */
+ input_report_key(pon->pon_input, cfg->key_code, 1);
+ input_sync(pon->pon_input);
+ /* schedule work to check the bark status for key-release */
+ schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+err_exit:
+ return IRQ_HANDLED;
+}
+
+static int __devinit
+qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ int rc;
+ u8 pull_bit;
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ pull_bit = QPNP_PON_KPDPWR_PULL_UP;
+ break;
+ case PON_RESIN:
+ pull_bit = QPNP_PON_RESIN_PULL_UP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon->base),
+ pull_bit, cfg->pull_up ? pull_bit : 0);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+
+ return rc;
+}
+
+static int __devinit
+qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ int rc;
+ u8 i;
+ u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
+ s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
+ s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+ break;
+ case PON_RESIN:
+ s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
+ s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
+ s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* disable S2 reset */
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ return rc;
+ }
+
+ usleep(100);
+
+ /* configure s1 timer, s2 timer and reset type */
+ for (i = 0; i < PON_S1_COUNT_MAX + 1; i++) {
+ if (cfg->s1_timer <= s1_delay[i])
+ break;
+ }
+ rc = qpnp_pon_masked_write(pon, s1_timer_addr,
+ QPNP_PON_S1_TIMER_MASK, i);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S1 timer\n");
+ return rc;
+ }
+
+ i = 0;
+ if (cfg->s2_timer) {
+ i = cfg->s2_timer / 10;
+ i = ilog2(i + 1);
+ }
+
+ rc = qpnp_pon_masked_write(pon, s2_timer_addr,
+ QPNP_PON_S2_TIMER_MASK, i);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 timer\n");
+ return rc;
+ }
+
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
+ return rc;
+ }
+
+ /* enable S2 reset */
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __devinit
+qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
{
int rc = 0;
- u32 pullup, delay;
- u8 pon_cntl;
- pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
- NULL, "power-key");
- if (pon->key_status_irq < 0) {
- dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
- return -ENXIO;
- }
-
- rc = of_property_read_u32(pon->spmi->dev.of_node,
- "qcom,pon-key-dbc-delay", &delay);
- if (rc) {
- delay = (delay << 6) / USEC_PER_SEC;
- delay = ilog2(delay);
-
- rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
- QPNP_PON_DBC_CTL(pon->base));
- return rc;
- }
- pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
- pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
- rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
- QPNP_PON_DBC_CTL(pon->base));
- return rc;
- }
- }
-
- rc = of_property_read_u32(pon->spmi->dev.of_node,
- "qcom,pon-key-pull-up", &pullup);
- if (!rc) {
- rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
- QPNP_PON_PULL_CTL(pon->base));
- return rc;
- }
- if (pullup)
- pon_cntl |= QPNP_PON_CNTL_PULL_UP;
- else
- pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
-
- rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
- QPNP_PON_PULL_CTL(pon->base));
- return rc;
- }
- }
-
- pon->pon_input = input_allocate_device();
- if (!pon->pon_input) {
- dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
- return -ENOMEM;
- }
-
- input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
- pon->pon_input->name = "qpnp_pon_key";
- pon->pon_input->phys = "qpnp_pon_key/input0";
-
- rc = input_register_device(pon->pon_input);
- if (rc) {
- dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
- goto free_input_dev;
- }
-
- rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_kpdpwr_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "qpnp_pon_key_status", pon);
- if (rc < 0) {
- dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
- pon->key_status_irq, rc);
- goto unreg_input_dev;
+ "qpnp_kpdpwr_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ if (cfg->support_reset) {
+ rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+ qpnp_kpdpwr_bark_irq,
+ IRQF_TRIGGER_RISING,
+ "qpnp_kpdpwr_bark", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev,
+ "Can't request %d IRQ\n",
+ cfg->bark_irq);
+ return rc;
+ }
+ }
+ break;
+ case PON_RESIN:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_resin_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "qpnp_resin_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ if (cfg->support_reset) {
+ rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+ qpnp_resin_bark_irq,
+ IRQF_TRIGGER_RISING,
+ "qpnp_resin_bark", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev,
+ "Can't request %d IRQ\n",
+ cfg->bark_irq);
+ return rc;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int __devinit
+qpnp_pon_config_input(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ if (!pon->pon_input) {
+ pon->pon_input = input_allocate_device();
+ if (!pon->pon_input) {
+ dev_err(&pon->spmi->dev,
+ "Can't allocate pon input device\n");
+ return -ENOMEM;
+ }
+ pon->pon_input->name = "qpnp_pon";
+ pon->pon_input->phys = "qpnp_pon/input0";
+ }
+
+ input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
+
+ return 0;
+}
+
+static int __devinit qpnp_pon_config_init(struct qpnp_pon *pon)
+{
+ int rc = 0, i = 0;
+ struct device_node *pp = NULL;
+ struct qpnp_pon_config *cfg;
+
+ /* iterate through the list of pon configs */
+ while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
+
+ cfg = &pon->pon_cfg[i++];
+
+ rc = of_property_read_u32(pp, "qcom,pon-type", &cfg->pon_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "PON type not specified\n");
+ return rc;
+ }
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "kpdpwr");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get kpdpwr irq\n");
+ return cfg->state_irq;
+ }
+
+ rc = of_property_read_u32(pp, "qcom,support-reset",
+ &cfg->support_reset);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read 'support-reset'\n");
+ return rc;
+ }
+
+ if (cfg->support_reset) {
+ cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "kpdpwr-bark");
+ if (cfg->bark_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get kpdpwr-bark irq\n");
+ return cfg->bark_irq;
+ }
+ }
+ break;
+ case PON_RESIN:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "resin");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get resin irq\n");
+ return cfg->bark_irq;
+ }
+
+ rc = of_property_read_u32(pp, "qcom,support-reset",
+ &cfg->support_reset);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read 'support-reset'\n");
+ return rc;
+ }
+
+ if (cfg->support_reset) {
+ cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "resin-bark");
+ if (cfg->bark_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get resin-bark irq\n");
+ return cfg->bark_irq;
+ }
+ }
+ break;
+ default:
+ dev_err(&pon->spmi->dev, "PON RESET %d not supported",
+ cfg->pon_type);
+ return -EINVAL;
+ }
+
+ if (cfg->support_reset) {
+ /*
+ * Get the reset parameters (bark debounce time and
+ * reset debounce time) for the reset line.
+ */
+ rc = of_property_read_u32(pp, "qcom,s1-timer",
+ &cfg->s1_timer);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s1-timer\n");
+ return rc;
+ }
+ if (cfg->s1_timer > QPNP_PON_S1_TIMER_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect S1 debounce time\n");
+ return -EINVAL;
+ }
+ rc = of_property_read_u32(pp, "qcom,s2-timer",
+ &cfg->s2_timer);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s2-timer\n");
+ return rc;
+ }
+ if (cfg->s2_timer > QPNP_PON_S2_TIMER_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect S2 debounce time\n");
+ return -EINVAL;
+ }
+ rc = of_property_read_u32(pp, "qcom,s2-type",
+ &cfg->s2_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s2-type\n");
+ return rc;
+ }
+ if (cfg->s2_type > QPNP_PON_RESET_TYPE_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect reset type specified\n");
+ return -EINVAL;
+ }
+ }
+ /*
+ * Get the standard-key parameters. This might not be
+ * specified if there is no key mapping on the reset line.
+ */
+ rc = of_property_read_u32(pp, "linux,code", &cfg->key_code);
+ if (rc && rc == -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read key-code\n");
+ return rc;
+ }
+ /* Register key configuration */
+ if (cfg->key_code) {
+ rc = qpnp_pon_config_input(pon, cfg);
+ if (rc < 0)
+ return rc;
+ }
+ /* get the pull-up configuration */
+ rc = of_property_read_u32(pp, "qcom,pull-up", &cfg->pull_up);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev, "Unable to read pull-up\n");
+ return rc;
+ }
+ }
+
+ /* register the input device */
+ if (pon->pon_input) {
+ rc = input_register_device(pon->pon_input);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Can't register pon key: %d\n", rc);
+ goto free_input_dev;
+ }
+ }
+
+ for (i = 0; i < pon->num_pon_config; i++) {
+ cfg = &pon->pon_cfg[i];
+ /* Configure the pull-up */
+ rc = qpnp_config_pull(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+ goto unreg_input_dev;
+ }
+ /* Configure the reset-configuration */
+ if (cfg->support_reset) {
+ rc = qpnp_config_reset(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to config pon reset\n");
+ goto unreg_input_dev;
+ }
+ }
+ rc = qpnp_pon_request_irqs(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
+ goto unreg_input_dev;
+ }
}
device_init_wakeup(&pon->spmi->dev, 1);
- enable_irq_wake(pon->key_status_irq);
return rc;
unreg_input_dev:
- input_unregister_device(pon->pon_input);
+ if (pon->pon_input)
+ input_unregister_device(pon->pon_input);
free_input_dev:
- input_free_device(pon->pon_input);
+ if (pon->pon_input)
+ input_free_device(pon->pon_input);
return rc;
}
@@ -158,7 +652,8 @@
{
struct qpnp_pon *pon;
struct resource *pon_resource;
- u32 pon_key_enable = 0;
+ struct device_node *itr = NULL;
+ u32 delay = 0;
int rc = 0;
pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
@@ -170,6 +665,20 @@
pon->spmi = spmi;
+ /* get the total number of pon configurations */
+ while ((itr = of_get_next_child(spmi->dev.of_node, itr)))
+ pon->num_pon_config++;
+
+ if (!pon->num_pon_config) {
+ /* No PON config., do not register the driver */
+ dev_err(&spmi->dev, "No PON config. specified\n");
+ return -EINVAL;
+ }
+
+ pon->pon_cfg = devm_kzalloc(&spmi->dev,
+ sizeof(struct qpnp_pon_config) * pon->num_pon_config,
+ GFP_KERNEL);
+
pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
if (!pon_resource) {
dev_err(&spmi->dev, "Unable to get PON base address\n");
@@ -177,36 +686,45 @@
}
pon->base = pon_resource->start;
- dev_set_drvdata(&spmi->dev, pon);
-
- /* pon-key-enable property must be set to register pon key */
- rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
- &pon_key_enable);
+ rc = of_property_read_u32(pon->spmi->dev.of_node,
+ "qcom,pon-dbc-delay", &delay);
if (rc && rc != -EINVAL) {
- dev_err(&spmi->dev,
- "Error reading 'pon-key-enable' property (%d)", rc);
+ dev_err(&spmi->dev, "Unable to read debounce delay\n");
return rc;
- }
-
- if (pon_key_enable) {
- rc = qpnp_pon_key_init(pon);
- if (rc < 0) {
- dev_err(&spmi->dev, "Failed to register pon-key\n");
+ } else {
+ delay = (delay << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
+ QPNP_PON_DBC_DELAY_MASK, delay);
+ if (rc) {
+ dev_err(&spmi->dev, "Unable to set PON debounce\n");
return rc;
}
}
- return 0;
+ dev_set_drvdata(&spmi->dev, pon);
+
+ INIT_DELAYED_WORK(&pon->bark_work, bark_work_func);
+
+ /* register the PON configurations */
+ rc = qpnp_pon_config_init(pon);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "Unable to intialize PON configurations\n");
+ return rc;
+ }
+
+ return rc;
}
static int qpnp_pon_remove(struct spmi_device *spmi)
{
struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
- if (pon->pon_input) {
- free_irq(pon->key_status_irq, pon);
+ cancel_delayed_work_sync(&pon->bark_work);
+
+ if (pon->pon_input)
input_unregister_device(pon->pon_input);
- }
return 0;
}
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 304dc6b..88e0948 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -20,6 +20,7 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
@@ -27,6 +28,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/rtc.h>
#define BMS_CONTROL 0x224
#define BMS_S1_DELAY 0x225
@@ -49,6 +51,9 @@
#define TEMP_SOC_STORAGE 0x107
+#define TEMP_IAVG_STORAGE 0x105
+#define TEMP_IAVG_STORAGE_USE_MASK 0x0F
+
enum pmic_bms_interrupts {
PM8921_BMS_SBI_WRITE_OK,
PM8921_BMS_CC_THR,
@@ -67,16 +72,6 @@
int last_good_ocv_uv;
};
-struct pm8921_rbatt_params {
- uint16_t ocv_for_rbatt_raw;
- uint16_t vsense_for_rbatt_raw;
- uint16_t vbatt_for_rbatt_raw;
-
- int ocv_for_rbatt_uv;
- int vsense_for_rbatt_uv;
- int vbatt_for_rbatt_uv;
-};
-
/**
* struct pm8921_bms_chip -
* @bms_output_lock: lock to prevent concurrent bms reads
@@ -92,8 +87,7 @@
struct device *dev;
struct dentry *dent;
unsigned int r_sense;
- unsigned int i_test;
- unsigned int v_failure;
+ unsigned int v_cutoff;
unsigned int fcc;
struct single_row_lut *fcc_temp_lut;
struct single_row_lut *fcc_sf_lut;
@@ -102,6 +96,8 @@
struct sf_lut *rbatt_sf_lut;
int delta_rbatt_mohm;
struct work_struct calib_hkadc_work;
+ struct delayed_work calib_hkadc_delayed_work;
+ struct mutex calib_mutex;
unsigned int revision;
unsigned int xoadc_v0625_usb_present;
unsigned int xoadc_v0625_usb_absent;
@@ -119,29 +115,42 @@
unsigned int charging_began;
unsigned int start_percent;
unsigned int end_percent;
+ int charge_time_us;
+ int catch_up_time_us;
enum battery_type batt_type;
uint16_t ocv_reading_at_100;
int cc_reading_at_100;
int max_voltage_uv;
- int batt_temp_suspend;
- int soc_rbatt_suspend;
int default_rbatt_mohm;
int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
unsigned int rconn_mohm;
struct mutex last_ocv_uv_mutex;
int last_ocv_uv;
+ int pon_ocv_uv;
int last_cc_uah;
- struct timeval t;
- int last_uuc_uah;
+ unsigned long tm_sec;
int enable_fcc_learning;
int shutdown_soc;
- int timer_uuc_expired;
- struct delayed_work uuc_timer_work;
- int uuc_uah_iavg_prev;
+ int shutdown_iavg_ua;
+ int shutdown_soc_timer_expired;
+ struct delayed_work shutdown_soc_work;
+ struct delayed_work calculate_soc_delayed_work;
+ struct timespec t_soc_queried;
+ int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int prev_iavg_ua;
+ int prev_uuc_iavg_ma;
+ int prev_pc_unusable;
+ int adjust_soc_low_threshold;
};
+/*
+ * protects against simultaneous adjustment of ocv based on shutdown soc and
+ * invalidating the shutdown soc
+ */
+static DEFINE_MUTEX(soc_invalidation_mutex);
static int shutdown_soc_invalid;
static struct pm8921_bms_chip *the_chip;
@@ -157,7 +166,7 @@
module_param(last_chargecycles, int, 0644);
module_param(last_charge_increase, int, 0644);
-static int last_rbatt = -EINVAL;
+static int calculated_soc = -EINVAL;
static int last_soc = -EINVAL;
static int last_real_fcc_mah = -EINVAL;
static int last_real_fcc_batt_temp = -EINVAL;
@@ -175,7 +184,6 @@
.get = param_get_int,
};
-module_param_cb(last_rbatt, &bms_param_ops, &last_rbatt, 0644);
module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
/*
@@ -337,19 +345,13 @@
static int usb_chg_plugged_in(void)
{
- union power_supply_propval ret = {0,};
- static struct power_supply *psy;
+ int val = pm8921_is_usb_chg_plugged_in();
- if (psy == NULL) {
- psy = power_supply_get_by_name("usb");
- if (psy == NULL)
- return 0;
- }
+ /* treat as if usb is not present in case of error */
+ if (val == -EINVAL)
+ val = 0;
- if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
- return 0;
-
- return ret.intval;
+ return val;
}
#define HOLD_OREG_DATA BIT(1)
@@ -483,8 +485,8 @@
return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
}
-#define CC_READING_TICKS 55
-#define SLEEP_CLK_HZ 32768
+#define CC_READING_TICKS 56
+#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
/**
* ccmicrovolt_to_nvh -
@@ -732,6 +734,82 @@
return 0;
}
+/* get ocv given a soc -- reverse lookup */
+static int interpolate_ocv(struct pm8921_bms_chip *chip,
+ int batt_temp_degc, int pc)
+{
+ int i, ocvrow1, ocvrow2, ocv;
+ int rows, cols;
+ int row1 = 0;
+ int row2 = 0;
+
+ rows = chip->pc_temp_ocv_lut->rows;
+ cols = chip->pc_temp_ocv_lut->cols;
+ if (pc > chip->pc_temp_ocv_lut->percent[0]) {
+ pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+ row1 = 0;
+ row2 = 0;
+ }
+ if (pc < chip->pc_temp_ocv_lut->percent[rows - 1]) {
+ pr_debug("pc %d less than known pc ranges for sf\n", pc);
+ row1 = rows - 1;
+ row2 = rows - 1;
+ }
+ for (i = 0; i < rows; i++) {
+ if (pc == chip->pc_temp_ocv_lut->percent[i]) {
+ row1 = i;
+ row2 = i;
+ break;
+ }
+ if (pc > chip->pc_temp_ocv_lut->percent[i]) {
+ row1 = i - 1;
+ row2 = i;
+ break;
+ }
+ }
+
+ if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0])
+ batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
+ if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1])
+ batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
+
+ for (i = 0; i < cols; i++)
+ if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[i])
+ break;
+ if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[i]) {
+ ocv = linear_interpolate(
+ chip->pc_temp_ocv_lut->ocv[row1][i],
+ chip->pc_temp_ocv_lut->percent[row1],
+ chip->pc_temp_ocv_lut->ocv[row2][i],
+ chip->pc_temp_ocv_lut->percent[row2],
+ pc);
+ return ocv;
+ }
+
+ ocvrow1 = linear_interpolate(
+ chip->pc_temp_ocv_lut->ocv[row1][i - 1],
+ chip->pc_temp_ocv_lut->temp[i - 1],
+ chip->pc_temp_ocv_lut->ocv[row1][i],
+ chip->pc_temp_ocv_lut->temp[i],
+ batt_temp_degc);
+
+ ocvrow2 = linear_interpolate(
+ chip->pc_temp_ocv_lut->ocv[row2][i - 1],
+ chip->pc_temp_ocv_lut->temp[i - 1],
+ chip->pc_temp_ocv_lut->ocv[row2][i],
+ chip->pc_temp_ocv_lut->temp[i],
+ batt_temp_degc);
+
+ ocv = linear_interpolate(
+ ocvrow1,
+ chip->pc_temp_ocv_lut->percent[row1],
+ ocvrow2,
+ chip->pc_temp_ocv_lut->percent[row2],
+ pc);
+
+ return ocv;
+}
+
static int interpolate_pc(struct pm8921_bms_chip *chip,
int batt_temp, int ocv)
{
@@ -836,7 +914,7 @@
#define BMS_MODE_BIT BIT(6)
#define EN_VBAT_BIT BIT(5)
#define OVERRIDE_MODE_DELAY_MS 20
-int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+int override_mode_simultaneous_battery_voltage_and_current(int *ibat_ua,
int *vbat_uv)
{
int16_t vsense_raw;
@@ -844,11 +922,6 @@
int vsense_uv;
int usb_chg;
- if (the_chip == NULL) {
- pr_err("Called to early\n");
- return -EINVAL;
- }
-
mutex_lock(&the_chip->bms_output_lock);
pm8xxx_writeb(the_chip->dev->parent, BMS_S1_DELAY, 0x00);
@@ -880,42 +953,6 @@
*ibat_ua, *vbat_uv);
return 0;
}
-EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
-
-static int read_rbatt_params_raw(struct pm8921_bms_chip *chip,
- struct pm8921_rbatt_params *raw)
-{
- int usb_chg;
-
- mutex_lock(&chip->bms_output_lock);
- pm_bms_lock_output_data(chip);
-
- pm_bms_read_output_data(chip,
- OCV_FOR_RBATT, &raw->ocv_for_rbatt_raw);
- pm_bms_read_output_data(chip,
- VBATT_FOR_RBATT, &raw->vbatt_for_rbatt_raw);
- pm_bms_read_output_data(chip,
- VSENSE_FOR_RBATT, &raw->vsense_for_rbatt_raw);
-
- pm_bms_unlock_output_data(chip);
- mutex_unlock(&chip->bms_output_lock);
-
- usb_chg = usb_chg_plugged_in();
- convert_vbatt_raw_to_uv(chip, usb_chg,
- raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
- convert_vbatt_raw_to_uv(chip, usb_chg,
- raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
- convert_vsense_to_uv(chip, raw->vsense_for_rbatt_raw,
- &raw->vsense_for_rbatt_uv);
-
- pr_debug("vbatt_for_rbatt_raw = 0x%x, vbatt_for_rbatt= %duV\n",
- raw->vbatt_for_rbatt_raw, raw->vbatt_for_rbatt_uv);
- pr_debug("ocv_for_rbatt_raw = 0x%x, ocv_for_rbatt= %duV\n",
- raw->ocv_for_rbatt_raw, raw->ocv_for_rbatt_uv);
- pr_debug("vsense_for_rbatt_raw = 0x%x, vsense_for_rbatt= %duV\n",
- raw->vsense_for_rbatt_raw, raw->vsense_for_rbatt_uv);
- return 0;
-}
#define MBG_TRANSIENT_ERROR_RAW 51
static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
@@ -953,6 +990,7 @@
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
+ pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
convert_vbatt_raw_to_uv(chip, usb_chg,
@@ -988,7 +1026,7 @@
{
int rbatt, scalefactor;
- rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+ rbatt = chip->default_rbatt_mohm;
pr_debug("rbatt before scaling = %d\n", rbatt);
if (chip->rbatt_sf_lut == NULL) {
pr_debug("RBATT = %d\n", rbatt);
@@ -1017,27 +1055,6 @@
return rbatt;
}
-static int calculate_rbatt_resume(struct pm8921_bms_chip *chip,
- struct pm8921_rbatt_params *raw)
-{
- unsigned int r_batt;
-
- if (raw->ocv_for_rbatt_uv <= 0
- || raw->ocv_for_rbatt_uv <= raw->vbatt_for_rbatt_uv
- || raw->vsense_for_rbatt_raw <= 0) {
- pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
- "vsen = %d\n",
- raw->ocv_for_rbatt_uv,
- raw->vbatt_for_rbatt_uv,
- raw->vsense_for_rbatt_raw);
- return -EINVAL;
- }
- r_batt = ((raw->ocv_for_rbatt_uv - raw->vbatt_for_rbatt_uv)
- * chip->r_sense) / raw->vsense_for_rbatt_uv;
- pr_debug("r_batt = %umilliOhms", r_batt);
- return r_batt;
-}
-
static int calculate_fcc_uah(struct pm8921_bms_chip *chip, int batt_temp,
int chargecycles)
{
@@ -1090,7 +1107,7 @@
return rc;
}
- rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+ rbatt = chip->default_rbatt_mohm;
*ocv = vbatt + (ibatt_ua * rbatt)/1000;
return 0;
}
@@ -1141,185 +1158,230 @@
*val = cc_uah;
}
-static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+static int calculate_termination_uuc(struct pm8921_bms_chip *chip,
int batt_temp, int chargecycles,
- int rbatt, int fcc_uah, int i_ma)
+ int fcc_uah, int i_ma,
+ int *ret_pc_unusable)
{
int unusable_uv, pc_unusable, uuc;
+ int i = 0;
+ int ocv_mv;
+ int batt_temp_degc = batt_temp / 10;
+ int rbatt_mohm;
+ int delta_uv;
+ int prev_delta_uv = 0;
+ int prev_rbatt_mohm = 0;
+ int prev_ocv_mv = 0;
+ int uuc_rbatt_uv;
- /* calculate unusable charge with itest */
- unusable_uv = (rbatt * i_ma) + (chip->v_failure * 1000);
+ for (i = 0; i <= 100; i++) {
+ ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+ rbatt_mohm = get_rbatt(chip, i, batt_temp);
+ unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
+ delta_uv = ocv_mv * 1000 - unusable_uv;
+
+ pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
+ i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
+
+ if (delta_uv > 0)
+ break;
+
+ prev_delta_uv = delta_uv;
+ prev_rbatt_mohm = rbatt_mohm;
+ prev_ocv_mv = ocv_mv;
+ }
+
+ uuc_rbatt_uv = linear_interpolate(rbatt_mohm, delta_uv,
+ prev_rbatt_mohm, prev_delta_uv,
+ 0);
+
+ unusable_uv = (uuc_rbatt_uv * i_ma) + (chip->v_cutoff * 1000);
+
pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
uuc = (fcc_uah * pc_unusable) / 100;
- pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
- i_ma, unusable_uv, pc_unusable, uuc);
+ pr_debug("For i_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+ i_ma, uuc_rbatt_uv, unusable_uv,
+ pc_unusable, uuc);
+ *ret_pc_unusable = pc_unusable;
return uuc;
}
-#define SOC_RBATT_CHG 70
-#define SOC_RBATT_DISCHG 20
-
-static int uuc_iavg_div = 150;
-module_param(uuc_iavg_div, int, 0644);
-
-static int uuc_min_step_size = 120;
-module_param(uuc_min_step_size, int, 0644);
-
-static int uuc_multiplier = 1000;
-module_param(uuc_multiplier, int, 0644);
-
-#define UUC_TIMER_MS 120000
-
-static void uuc_timer_work(struct work_struct *work)
+static int adjust_uuc(struct pm8921_bms_chip *chip, int fcc_uah,
+ int new_pc_unusable,
+ int new_uuc,
+ int batt_temp,
+ int rbatt,
+ int *iavg_ma)
{
- struct pm8921_bms_chip *chip = container_of(work,
- struct pm8921_bms_chip, uuc_timer_work.work);
+ int new_unusable_mv;
+ int batt_temp_degc = batt_temp / 10;
- pr_debug("UUC Timer expired\n");
- /* indicates the system is done with the high load during bootup */
- chip->timer_uuc_expired = 1;
+ if (chip->prev_pc_unusable == -EINVAL
+ || abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+ chip->prev_pc_unusable = new_pc_unusable;
+ return new_uuc;
+ }
+
+ /* the uuc is trying to change more than 1% restrict it */
+ if (new_pc_unusable > chip->prev_pc_unusable)
+ chip->prev_pc_unusable++;
+ else
+ chip->prev_pc_unusable--;
+
+ new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
+
+ /* also find update the iavg_ma accordingly */
+ new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
+ chip->prev_pc_unusable);
+ if (new_unusable_mv < chip->v_cutoff)
+ new_unusable_mv = chip->v_cutoff;
+
+ *iavg_ma = (new_unusable_mv - chip->v_cutoff) * 1000 / rbatt;
+ if (*iavg_ma == 0)
+ *iavg_ma = 1;
+ pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+ new_uuc, chip->prev_pc_unusable,
+ new_unusable_mv, *iavg_ma);
+
+ return new_uuc;
}
static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
- int *iavg_ua, int *delta_time_us)
+ int *iavg_ua, int *delta_time_s)
{
int delta_cc_uah;
- struct timeval now;
+ struct rtc_time tm;
+ struct rtc_device *rtc;
+ unsigned long now_tm_sec = 0;
+ int rc = 0;
- delta_cc_uah = cc_uah - chip->last_cc_uah;
- do_gettimeofday(&now);
- if (chip->t.tv_sec != 0) {
- *delta_time_us = (now.tv_sec - chip->t.tv_sec) * USEC_PER_SEC
- + now.tv_usec - chip->t.tv_usec;
- } else {
- /* calculation for the first time */
- *delta_time_us = 0;
+ /* if anything fails report the previous iavg_ua */
+ *iavg_ua = chip->prev_iavg_ua;
+
+ rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+ if (rtc == NULL) {
+ pr_err("%s: unable to open rtc device (%s)\n",
+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+ goto out;
}
- if (*delta_time_us != 0)
- *iavg_ua = div_s64((s64)delta_cc_uah * 3600 * 1000000,
- *delta_time_us);
- else
- *iavg_ua = 0;
+ rc = rtc_read_time(rtc, &tm);
+ if (rc) {
+ pr_err("Error reading rtc device (%s) : %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
- pr_debug("t.tv_sec = %d, now.tv_sec = %d delta_us = %d iavg_ua = %d\n",
- (int)chip->t.tv_sec, (int)now.tv_sec,
- *delta_time_us, (int)*iavg_ua);
+ rc = rtc_valid_tm(&tm);
+ if (rc) {
+ pr_err("Invalid RTC time (%s): %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
+ rtc_tm_to_time(&tm, &now_tm_sec);
+
+ if (chip->tm_sec == 0) {
+ *delta_time_s = 0;
+ pm8921_bms_get_battery_current(iavg_ua);
+ goto out;
+ }
+
+ *delta_time_s = (now_tm_sec - chip->tm_sec);
+
+ /* use the previous iavg if called within 15 seconds */
+ if (*delta_time_s < 15) {
+ *iavg_ua = chip->prev_iavg_ua;
+ goto out;
+ }
+
+ delta_cc_uah = cc_uah - chip->last_cc_uah;
+
+ *iavg_ua = div_s64((s64)delta_cc_uah * 3600, *delta_time_s);
+
+ pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d delta_cc = %d iavg_ua = %d\n",
+ chip->tm_sec, now_tm_sec,
+ *delta_time_s, delta_cc_uah, (int)*iavg_ua);
+
+out:
+ /* remember the iavg */
+ chip->prev_iavg_ua = *iavg_ua;
+
/* remember cc_uah */
chip->last_cc_uah = cc_uah;
/* remember this time */
- chip->t = now;
+ chip->tm_sec = now_tm_sec;
}
-#define UUC_IAVG_THRESHOLD_UAH 50000
-static int scale_unusable_charge_uah(struct pm8921_bms_chip *chip,
- bool charging, int uuc_uah_iavg, int uuc_uah_itest,
- int uuc_uah_iavg_prev)
-{
- int stepsize = 0;
- int delta_uuc = 0;
- int uuc_reported = 0;
-
- if (charging) {
- stepsize = max(uuc_min_step_size,
- uuc_multiplier * (SOC_RBATT_CHG - last_soc));
- /*
- * set the delta only if uuc is decreasing. If it has increased
- * simply report the last uuc since we don't want to report a
- * higher uuc as charging progresses
- */
- if (chip->last_uuc_uah > uuc_uah_iavg)
- delta_uuc = (chip->last_uuc_uah - uuc_uah_iavg)
- / stepsize;
- uuc_reported = chip->last_uuc_uah - delta_uuc;
- } else {
- stepsize = max(uuc_min_step_size,
- uuc_multiplier * (last_soc - SOC_RBATT_DISCHG));
- if (uuc_uah_itest > uuc_uah_iavg) {
- if ((uuc_uah_iavg > uuc_uah_iavg_prev
- + UUC_IAVG_THRESHOLD_UAH)
- && chip->timer_uuc_expired)
- /*
- * there is a big jump in iavg current way past
- * the bootup increase uuc to this high iavg
- * based uuc in steps
- */
- delta_uuc = (uuc_uah_iavg - uuc_uah_iavg_prev)
- / uuc_iavg_div;
- else
- /* increase uuc towards itest based uuc */
- delta_uuc = (uuc_uah_itest - uuc_uah_iavg)
- / stepsize;
- } else {
- /*
- * the iavg based uuc was higher than itest based
- * uuc. This means that iavg > itest. Itest represents
- * the max current drawn from the device at anytime.
- * If we find iavg > itest, ignore iavg and simply step
- * up the uuc based on itest
- */
- delta_uuc = uuc_uah_itest / stepsize;
- }
- uuc_reported = min(uuc_uah_itest,
- chip->last_uuc_uah + delta_uuc);
- }
- pr_debug("uuc_prev = %d stepsize = %d d_uuc = %d uuc_reported = %d\n",
- chip->last_uuc_uah, (int)stepsize, delta_uuc,
- uuc_reported);
- return uuc_reported;
-}
-
+#define IAVG_SAMPLES 16
+#define CHARGING_IAVG_MA 250
+#define MIN_SECONDS_FOR_VALID_SAMPLE 20
static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
int rbatt, int fcc_uah, int cc_uah,
int soc_rbatt, int batt_temp, int chargecycles,
- int iavg_ua)
+ int iavg_ua, int delta_time_s)
{
- int uuc_uah_itest, uuc_uah_iavg, uuc_reported;
- static int firsttime = 1;
+ int uuc_uah_iavg;
+ int i;
int iavg_ma = iavg_ua / 1000;
+ static int iavg_samples[IAVG_SAMPLES];
+ static int iavg_index;
+ static int iavg_num_samples;
+ static int firsttime = 1;
+ int pc_unusable;
- /* calculate unusable charge with itest */
- uuc_uah_itest = calculate_uuc_uah_at_given_current(chip,
+ /*
+ * if we are called first time fill all the
+ * samples with the the shutdown_iavg_ua
+ */
+ if (firsttime && chip->shutdown_iavg_ua != 0) {
+ pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
+ chip->shutdown_iavg_ua);
+ for (i = 0; i < IAVG_SAMPLES; i++)
+ iavg_samples[i] = chip->shutdown_iavg_ua;
+
+ iavg_index = 0;
+ iavg_num_samples = IAVG_SAMPLES;
+ }
+
+ /*
+ * if we are charging use a nominal avg current so that we keep
+ * a reasonable UUC while charging
+ */
+ if (iavg_ma < 0)
+ iavg_ma = CHARGING_IAVG_MA;
+ iavg_samples[iavg_index] = iavg_ma;
+ iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
+ iavg_num_samples++;
+ if (iavg_num_samples >= IAVG_SAMPLES)
+ iavg_num_samples = IAVG_SAMPLES;
+
+ /* now that this sample is added calcualte the average */
+ iavg_ma = 0;
+ if (iavg_num_samples != 0) {
+ for (i = 0; i < iavg_num_samples; i++) {
+ pr_debug("iavg_samples[%d] = %d\n", i, iavg_samples[i]);
+ iavg_ma += iavg_samples[i];
+ }
+
+ iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
+ }
+
+ uuc_uah_iavg = calculate_termination_uuc(chip,
batt_temp, chargecycles,
- rbatt, fcc_uah, chip->i_test);
-
- pr_debug("itest = %d uuc_itest = %d\n", chip->i_test, uuc_uah_itest);
-
- /* calculate unusable charge with iavg */
- iavg_ma = max(0, iavg_ma);
- uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
- batt_temp, chargecycles,
- rbatt, fcc_uah, iavg_ma);
+ fcc_uah, iavg_ma,
+ &pc_unusable);
pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
- if (firsttime) {
- chip->uuc_uah_iavg_prev = uuc_uah_iavg;
+ /* restrict the uuc such that it can increase only by one percent */
+ uuc_uah_iavg = adjust_uuc(chip, fcc_uah, pc_unusable, uuc_uah_iavg,
+ batt_temp, rbatt, &iavg_ma);
- if (cc_uah < chip->last_cc_uah)
- chip->last_uuc_uah = uuc_uah_itest;
- else
- chip->last_uuc_uah = uuc_uah_iavg;
- pr_debug("firsttime uuc_prev = %d\n", chip->last_uuc_uah);
- }
+ /* find out what the avg current should be for this uuc */
+ chip->prev_uuc_iavg_ma = iavg_ma;
- uuc_reported = scale_unusable_charge_uah(chip,
- cc_uah < chip->last_cc_uah,
- uuc_uah_iavg, uuc_uah_itest,
- chip->uuc_uah_iavg_prev);
-
- /* remember the last uuc_uah_iavg */
- chip->uuc_uah_iavg_prev = uuc_uah_iavg;
-
- /* remember the reported uuc */
- chip->last_uuc_uah = uuc_reported;
-
- if (firsttime == 1) {
- /* uuc calculation for the first time is done */
- firsttime = 0;
- }
-
- return uuc_reported;
+ firsttime = 0;
+ return uuc_uah_iavg;
}
/* calculate remainging charge at the time of ocv */
@@ -1345,7 +1407,7 @@
int *cc_uah,
int *rbatt,
int *iavg_ua,
- int *delta_time_us)
+ int *delta_time_s)
{
int soc_rbatt;
@@ -1371,11 +1433,12 @@
soc_rbatt = 0;
*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
- calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_us);
+ calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_s);
*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
*fcc_uah, *cc_uah, soc_rbatt,
- batt_temp, chargecycles, *iavg_ua);
+ batt_temp, chargecycles, *iavg_ua,
+ *delta_time_s);
pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
}
@@ -1390,7 +1453,7 @@
int real_fcc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1399,7 +1462,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
real_fcc_uah = remaining_charge_uah - cc_uah;
*ret_fcc_uah = fcc_uah;
@@ -1408,6 +1471,38 @@
return real_fcc_uah;
}
+int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+ int *vbat_uv)
+{
+ int rc;
+
+ if (the_chip == NULL) {
+ pr_err("Called too early\n");
+ return -EINVAL;
+ }
+
+ if (pm8921_is_batfet_closed()) {
+ return override_mode_simultaneous_battery_voltage_and_current(
+ ibat_ua,
+ vbat_uv);
+ } else {
+ pr_debug("batfet is open using separate vbat and ibat meas\n");
+ rc = get_battery_uvolts(the_chip, vbat_uv);
+ if (rc < 0) {
+ pr_err("adc vbat failed err = %d\n", rc);
+ return rc;
+ }
+ rc = pm8921_bms_get_battery_current(ibat_ua);
+ if (rc < 0) {
+ pr_err("bms ibat failed err = %d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+
static int bound_soc(int soc)
{
soc = max(0, soc);
@@ -1427,12 +1522,23 @@
int pc_new = 0;
int soc_new = 0;
int m = 0;
+ int rc = 0;
+ int delta_ocv_uv_limit = 0;
- pm8921_bms_get_simultaneous_battery_voltage_and_current(&ibat_ua,
- &vbat_uv);
+ rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+ &ibat_ua,
+ &vbat_uv);
+ if (rc < 0) {
+ pr_err("simultaneous vbat ibat failed err = %d\n", rc);
+ goto out;
+ }
+
if (ibat_ua < 0)
goto out;
+
+ delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
+
ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
@@ -1440,10 +1546,19 @@
soc_est = bound_soc(soc_est);
/*
- * do not adjust if soc_est is between 45 and 25 OR soc_est is
- * same as what bms calculated
+ * do not adjust
+ * if soc is same as what bms calculated
+ * if soc_est is between 45 and 25, this is the flat portion of the
+ * curve where soc_est is not so accurate. We generally don't want to
+ * adjust when soc_est is inaccurate except for the cases when soc is
+ * way far off (higher than 50 or lesser than 20).
+ * Also don't adjust soc if it is above 90 becuase we might pull it low
+ * and cause a bad user experience
*/
- if (is_between(45, 25, soc_est) || soc_est == soc)
+ if (soc_est == soc
+ || (is_between(45, chip->adjust_soc_low_threshold, soc_est)
+ && is_between(50, chip->adjust_soc_low_threshold - 5, soc))
+ || soc >= 90)
goto out;
if (last_soc_est == -EINVAL)
@@ -1477,6 +1592,18 @@
delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
n * (pc - pc_new));
+
+ if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
+ pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+ delta_ocv_uv_limit);
+
+ if (delta_ocv_uv > 0)
+ delta_ocv_uv = delta_ocv_uv_limit;
+ else
+ delta_ocv_uv = -1 * delta_ocv_uv_limit;
+ pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+ }
+
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1509,71 +1636,229 @@
return soc;
}
-#define MAX_SHUTDOWN_ADJUST_SECONDS 1800
-static int adjust_for_shutdown_soc(struct pm8921_bms_chip *chip, int soc)
+#define IGNORE_SOC_TEMP_DECIDEG 50
+#define IAVG_STEP_SIZE_MA 50
+#define IAVG_START 600
+#define SOC_ZERO 0xFF
+static void backup_soc_and_iavg(struct pm8921_bms_chip *chip, int batt_temp,
+ int soc)
{
- struct timespec uptime;
- int val;
+ u8 temp;
+ int iavg_ma = chip->prev_uuc_iavg_ma;
- /* value of zero means the shutdown soc should not be used */
- if (chip->shutdown_soc == 0)
- return soc;
+ if (iavg_ma > IAVG_START)
+ temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+ else
+ temp = 0;
- if (shutdown_soc_invalid) {
- chip->shutdown_soc = 0;
- return soc;
- }
+ pm_bms_masked_write(chip, TEMP_IAVG_STORAGE,
+ TEMP_IAVG_STORAGE_USE_MASK, temp);
- do_posix_clock_monotonic_gettime(&uptime);
+ /* since only 6 bits are available for SOC, we store half the soc */
+ if (soc == 0)
+ temp = SOC_ZERO;
+ else
+ temp = soc;
- if (uptime.tv_sec >= MAX_SHUTDOWN_ADJUST_SECONDS) {
- /*
- * adjusted for a long time now, switch to reporting the
- * calculated soc
- */
- chip->shutdown_soc = 0;
- return soc;
- }
-
- val = ((MAX_SHUTDOWN_ADJUST_SECONDS - uptime.tv_sec)
- * chip->shutdown_soc
- + uptime.tv_sec * soc);
- val /= MAX_SHUTDOWN_ADJUST_SECONDS;
- pr_debug("shutdown_soc = %d, adj soc = %d, calc soc = %d\n",
- chip->shutdown_soc, val, soc);
-
- return val;
+ /* don't store soc if temperature is below 5degC */
+ if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+ pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, temp);
}
-static void backup_soc(struct pm8921_bms_chip *chip, int last_soc)
-{
- /* TODO: if 0x107 is free for all variants 8917, 8038 etc */
- pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, last_soc);
-}
-
-static void read_shutdown_soc(struct pm8921_bms_chip *chip)
+static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
{
int rc;
u8 temp;
+ rc = pm8xxx_readb(chip->dev->parent, TEMP_IAVG_STORAGE, &temp);
+ if (rc) {
+ pr_err("failed to read addr = %d %d assuming %d\n",
+ TEMP_IAVG_STORAGE, rc, IAVG_START);
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ temp &= TEMP_IAVG_STORAGE_USE_MASK;
+
+ if (temp == 0) {
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ chip->shutdown_iavg_ua = IAVG_START
+ + IAVG_STEP_SIZE_MA * (temp + 1);
+ }
+ }
+
rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
- if (rc)
+ if (rc) {
pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
- else
+ } else {
chip->shutdown_soc = temp;
- pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
+ if (chip->shutdown_soc == 0) {
+ pr_debug("No shutdown soc available\n");
+ shutdown_soc_invalid = 1;
+ chip->shutdown_iavg_ua = 0;
+ } else if (chip->shutdown_soc == SOC_ZERO) {
+ chip->shutdown_soc = 0;
+ }
+ }
+
+ if (chip->ignore_shutdown_soc) {
+ shutdown_soc_invalid = 1;
+ chip->shutdown_soc = 0;
+ chip->shutdown_iavg_ua = 0;
+ }
+
+ pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+ chip->shutdown_soc,
+ chip->shutdown_iavg_ua,
+ shutdown_soc_invalid);
}
-void pm8921_bms_invalidate_shutdown_soc(void)
+static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
+ int batt_temp,
+ int chargecycles,
+ int fcc_uah,
+ int uuc_uah,
+ int cc_uah,
+ int shutdown_soc,
+ int *rc_uah,
+ int *ocv_uv)
{
- pr_debug("Invalidating shutdown soc - the battery was removed\n");
- shutdown_soc_invalid = 1;
- if (the_chip)
- the_chip->shutdown_soc = 0;
-}
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+ s64 rc;
+ int pc, new_pc;
+ int batt_temp_degc = batt_temp / 10;
+ int ocv;
+ rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
+ rc = div_s64(rc, 100) + cc_uah + uuc_uah;
+ pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
+ pc = clamp(pc, 0, 100);
+
+ ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+
+ pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
+ shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
+ new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+
+ while (abs(new_pc - pc) > 1) {
+ int delta_mv = 5;
+
+ if (new_pc > pc)
+ delta_mv = -1 * delta_mv;
+
+ ocv = ocv + delta_mv;
+ new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+ }
+
+ *ocv_uv = ocv * 1000;
+ *rc_uah = (int)rc;
+}
+
+static void adjust_rc_and_uuc_for_specific_soc(
+ struct pm8921_bms_chip *chip,
+ int batt_temp,
+ int chargecycles,
+ int soc,
+ int fcc_uah,
+ int uuc_uah,
+ int cc_uah,
+ int rc_uah,
+ int rbatt,
+ int *ret_ocv,
+ int *ret_rc,
+ int *ret_uuc,
+ int *ret_rbatt)
+{
+ int ocv_uv;
+
+ find_ocv_for_soc(chip, batt_temp, chargecycles,
+ fcc_uah, uuc_uah, cc_uah,
+ soc,
+ &rc_uah, &ocv_uv);
+
+ *ret_ocv = ocv_uv;
+ *ret_rbatt = rbatt;
+ *ret_rc = rc_uah;
+ *ret_uuc = uuc_uah;
+}
+
+#define SOC_CATCHUP_SEC_MAX 600
+#define SOC_CATCHUP_SEC_PER_PERCENT 60
+#define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
+static int scale_soc_while_chg(struct pm8921_bms_chip *chip,
+ int delta_time_us, int new_soc, int prev_soc)
+{
+ int chg_time_sec;
+ int catch_up_sec;
+ int scaled_soc;
+ int numerator;
+
+ /*
+ * The device must be charging for reporting a higher soc, if
+ * not ignore this soc and continue reporting the prev_soc.
+ * Also don't report a high value immediately slowly scale the
+ * value from prev_soc to the new soc based on a charge time
+ * weighted average
+ */
+
+ /* if we are not charging return last soc */
+ if (the_chip->start_percent == -EINVAL)
+ return prev_soc;
+
+ /* if soc is called in quick succession return the last soc */
+ if (delta_time_us < USEC_PER_SEC)
+ return prev_soc;
+
+ chg_time_sec = DIV_ROUND_UP(the_chip->charge_time_us, USEC_PER_SEC);
+ catch_up_sec = DIV_ROUND_UP(the_chip->catch_up_time_us, USEC_PER_SEC);
+ pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
+
+ /*
+ * if we have been charging for more than catch_up time simply return
+ * new soc
+ */
+ if (chg_time_sec > catch_up_sec)
+ return new_soc;
+
+ numerator = (catch_up_sec - chg_time_sec) * prev_soc
+ + chg_time_sec * new_soc;
+ scaled_soc = numerator / catch_up_sec;
+
+ pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
+ chg_time_sec, new_soc, prev_soc, scaled_soc);
+
+ return scaled_soc;
+}
+
+#define SHOW_SHUTDOWN_SOC_MS 30000
+static void shutdown_soc_work(struct work_struct *work)
+{
+ struct pm8921_bms_chip *chip = container_of(work,
+ struct pm8921_bms_chip, shutdown_soc_work.work);
+
+ pr_debug("not forcing shutdown soc anymore\n");
+ /* it has been 30 seconds since init, no need to show shutdown soc */
+ chip->shutdown_soc_timer_expired = 1;
+}
+
+static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
+{
+ if (shutdown_soc_invalid) {
+ pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
+ return 0;
+ }
+
+ if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
+ pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
+ chip->shutdown_soc, soc,
+ chip->shutdown_soc_valid_limit);
+ shutdown_soc_invalid = 1;
+ return 0;
+ }
+
+ return 1;
+}
/*
* Remaining Usable Charge = remaining_charge (charge at ocv instance)
* - coloumb counter charge
@@ -1588,9 +1873,14 @@
int remaining_charge_uah, soc;
int cc_uah;
int rbatt;
- int shutdown_adjusted_soc;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
+ int new_ocv;
+ int new_rc_uah;
+ int new_ucc_uah;
+ int new_rbatt;
+ int shutdown_soc;
+ static int firsttime = 1;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1599,7 +1889,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
/* calculate remaining usable charge */
remaining_usable_charge_uah = remaining_charge_uah
@@ -1612,13 +1902,43 @@
fcc_uah, unusable_charge_uah);
soc = 0;
} else {
- soc = (remaining_usable_charge_uah * 100)
- / (fcc_uah - unusable_charge_uah);
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+ }
+
+ if (firsttime && soc < 0) {
+ /*
+ * first time calcualtion and the pon ocv is too low resulting
+ * in a bad soc. Adjust ocv such that we get 0 soc
+ */
+ pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
+ adjust_rc_and_uuc_for_specific_soc(
+ chip,
+ batt_temp, chargecycles,
+ 0,
+ fcc_uah, unusable_charge_uah,
+ cc_uah, remaining_charge_uah,
+ rbatt,
+ &new_ocv,
+ &new_rc_uah, &new_ucc_uah,
+ &new_rbatt);
+ chip->last_ocv_uv = new_ocv;
+ remaining_charge_uah = new_rc_uah;
+ unusable_charge_uah = new_ucc_uah;
+ rbatt = new_rbatt;
+
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+ pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
+ soc, chip->last_ocv_uv);
}
if (soc > 100)
soc = 100;
- pr_debug("SOC = %u%%\n", soc);
if (bms_fake_battery != -EINVAL) {
pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
@@ -1640,30 +1960,221 @@
soc = 0;
}
- soc = adjust_soc(chip, soc, batt_temp, rbatt,
- fcc_uah, unusable_charge_uah, cc_uah);
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc = chip->shutdown_soc;
- if (last_soc == -EINVAL || soc <= last_soc) {
- last_soc = soc;
- } else {
+ if (firsttime && soc != shutdown_soc
+ && is_shutdown_soc_within_limits(chip, soc)) {
/*
- * soc > last_soc
- * the device must be charging for reporting a higher soc, if
- * not ignore this soc and continue reporting the last_soc
+ * soc for the first time - use shutdown soc
+ * to adjust pon ocv since it is a small percent away from
+ * the real soc
*/
- if (the_chip->start_percent != -EINVAL)
- last_soc = soc;
- else
- pr_debug("soc = %d reporting last_soc = %d\n", soc,
- last_soc);
+ pr_debug("soc = %d before forcing shutdown_soc = %d\n",
+ soc, shutdown_soc);
+ adjust_rc_and_uuc_for_specific_soc(
+ chip,
+ batt_temp, chargecycles,
+ shutdown_soc,
+ fcc_uah, unusable_charge_uah,
+ cc_uah, remaining_charge_uah,
+ rbatt,
+ &new_ocv,
+ &new_rc_uah, &new_ucc_uah,
+ &new_rbatt);
+
+ chip->pon_ocv_uv = chip->last_ocv_uv;
+ chip->last_ocv_uv = new_ocv;
+ remaining_charge_uah = new_rc_uah;
+ unusable_charge_uah = new_ucc_uah;
+ rbatt = new_rbatt;
+
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+
+ pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
+ shutdown_soc, soc, chip->last_ocv_uv);
+ }
+ mutex_unlock(&soc_invalidation_mutex);
+
+ calculated_soc = adjust_soc(chip, soc, batt_temp,
+ rbatt, fcc_uah, unusable_charge_uah, cc_uah);
+
+ pr_debug("calculated SOC = %d\n", calculated_soc);
+ firsttime = 0;
+ return calculated_soc;
+}
+
+#define CALCULATE_SOC_MS 20000
+static void calculate_soc_work(struct work_struct *work)
+{
+ struct pm8921_bms_chip *chip = container_of(work,
+ struct pm8921_bms_chip,
+ calculate_soc_delayed_work.work);
+ int batt_temp, rc;
+ struct pm8xxx_adc_chan_result result;
+ struct pm8921_soc_params raw;
+ int soc;
+
+ rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ chip->batt_temp_channel, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+
+ soc = calculate_state_of_charge(chip, &raw,
+ batt_temp, last_chargecycles);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+
+ schedule_delayed_work(&chip->calculate_soc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (CALCULATE_SOC_MS)));
+}
+
+static int report_state_of_charge(struct pm8921_bms_chip *chip)
+{
+ int soc = calculated_soc;
+ int delta_time_us;
+ struct timespec now;
+ struct pm8xxx_adc_chan_result result;
+ int batt_temp;
+ int rc;
+
+ rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ the_chip->batt_temp_channel, rc);
+ return rc;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ do_posix_clock_monotonic_gettime(&now);
+ if (chip->t_soc_queried.tv_sec != 0) {
+ delta_time_us
+ = (now.tv_sec - chip->t_soc_queried.tv_sec) * USEC_PER_SEC
+ + (now.tv_nsec - chip->t_soc_queried.tv_nsec) / 1000;
+ } else {
+ /* calculation for the first time */
+ delta_time_us = 0;
}
- shutdown_adjusted_soc = adjust_for_shutdown_soc(chip, last_soc);
- backup_soc(chip, shutdown_adjusted_soc);
+ /*
+ * account for charge time - limit it to SOC_CATCHUP_SEC to
+ * avoid overflows when charging continues for extended periods
+ */
+ if (the_chip->start_percent != -EINVAL) {
+ if (the_chip->charge_time_us == 0) {
+ /*
+ * calculating soc for the first time
+ * after start of chg. Initialize catchup time
+ */
+ if (abs(soc - last_soc) < MAX_CATCHUP_SOC)
+ the_chip->catch_up_time_us =
+ (soc - last_soc) * SOC_CATCHUP_SEC_PER_PERCENT
+ * USEC_PER_SEC;
+ else
+ the_chip->catch_up_time_us =
+ SOC_CATCHUP_SEC_MAX * USEC_PER_SEC;
- return shutdown_adjusted_soc;
+ if (the_chip->catch_up_time_us < 0)
+ the_chip->catch_up_time_us = 0;
+ }
+
+ /* add charge time */
+ if (the_chip->charge_time_us
+ < SOC_CATCHUP_SEC_MAX * USEC_PER_SEC)
+ chip->charge_time_us += delta_time_us;
+
+ /* end catchup if calculated soc and last soc are same */
+ if (last_soc == soc)
+ the_chip->catch_up_time_us = 0;
+ }
+
+ /* last_soc < soc ... scale and catch up */
+ if (last_soc != -EINVAL && last_soc < soc && soc != 100)
+ soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+
+ if (chip->shutdown_soc != 0
+ && !shutdown_soc_invalid
+ && !chip->shutdown_soc_timer_expired) {
+ /*
+ * force shutdown soc if it is valid and the shutdown soc show
+ * timer has not expired
+ */
+ soc = chip->shutdown_soc;
+
+ pr_debug("Forcing SHUTDOWN_SOC = %d\n", soc);
+ }
+
+ last_soc = soc;
+ backup_soc_and_iavg(chip, batt_temp, last_soc);
+ pr_debug("Reported SOC = %d\n", last_soc);
+ chip->t_soc_queried = now;
+
+ return last_soc;
}
+void pm8921_bms_invalidate_shutdown_soc(void)
+{
+ int calculate_soc = 0;
+ struct pm8921_bms_chip *chip = the_chip;
+ int batt_temp, rc;
+ struct pm8xxx_adc_chan_result result;
+ struct pm8921_soc_params raw;
+ int soc;
+
+ pr_debug("Invalidating shutdown soc - the battery was removed\n");
+ if (shutdown_soc_invalid)
+ return;
+
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc_invalid = 1;
+ last_soc = -EINVAL;
+ if (the_chip) {
+ /* reset to pon ocv undoing what the adjusting did */
+ if (the_chip->pon_ocv_uv) {
+ the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
+ calculate_soc = 1;
+ pr_debug("resetting ocv to pon_ocv = %d\n",
+ the_chip->pon_ocv_uv);
+ }
+ }
+ mutex_unlock(&soc_invalidation_mutex);
+ if (!calculate_soc)
+ return;
+
+ rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ chip->batt_temp_channel, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+
+ soc = calculate_state_of_charge(chip, &raw,
+ batt_temp, last_chargecycles);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+
#define MIN_DELTA_625_UV 1000
static void calib_hkadc(struct pm8921_bms_chip *chip)
{
@@ -1672,10 +2183,11 @@
int usb_chg;
int this_delta;
+ mutex_lock(&chip->calib_mutex);
rc = pm8xxx_adc_read(the_chip->ref1p25v_channel, &result);
if (rc) {
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
- return;
+ goto out;
}
voltage = xoadc_reading_to_microvolt(result.adc_code);
@@ -1687,7 +2199,7 @@
rc = pm8xxx_adc_read(the_chip->ref625mv_channel, &result);
if (rc) {
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
- return;
+ goto out;
}
voltage = xoadc_reading_to_microvolt(result.adc_code);
@@ -1714,6 +2226,8 @@
chip->xoadc_v0625_usb_absent,
last_usb_cal_delta_uv);
}
+out:
+ mutex_unlock(&chip->calib_mutex);
}
static void calibrate_hkadc_work(struct work_struct *work)
@@ -1729,6 +2243,19 @@
schedule_work(&the_chip->calib_hkadc_work);
}
+#define HKADC_CALIB_DELAY_MS 600000
+static void calibrate_hkadc_delayed_work(struct work_struct *work)
+{
+ struct pm8921_bms_chip *chip = container_of(work,
+ struct pm8921_bms_chip,
+ calib_hkadc_delayed_work.work);
+
+ calib_hkadc(chip);
+ schedule_delayed_work(&chip->calib_hkadc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (HKADC_CALIB_DELAY_MS)));
+}
+
int pm8921_bms_get_vsense_avg(int *result)
{
int rc = -EINVAL;
@@ -1774,33 +2301,12 @@
int pm8921_bms_get_percent_charge(void)
{
- int batt_temp, rc;
- struct pm8xxx_adc_chan_result result;
- struct pm8921_soc_params raw;
- int soc;
-
if (!the_chip) {
pr_err("called before initialization\n");
return -EINVAL;
}
- rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
- if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
- the_chip->batt_temp_channel, rc);
- return rc;
- }
- pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
- result.measurement);
- batt_temp = (int)result.physical;
-
- mutex_lock(&the_chip->last_ocv_uv_mutex);
- read_soc_params_raw(the_chip, &raw);
-
- soc = calculate_state_of_charge(the_chip, &raw,
- batt_temp, last_chargecycles);
- mutex_unlock(&the_chip->last_ocv_uv_mutex);
- return soc;
+ return report_state_of_charge(the_chip);
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
@@ -1815,7 +2321,7 @@
int cc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
if (!the_chip) {
pr_err("called before initialization\n");
@@ -1843,7 +2349,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
return rbatt;
@@ -1881,32 +2387,21 @@
#define OCV_TOL_NO_OCV 0x00
void pm8921_bms_charging_began(void)
{
- int batt_temp, rc;
- struct pm8xxx_adc_chan_result result;
struct pm8921_soc_params raw;
- rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
- if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
- the_chip->batt_temp_channel, rc);
- return;
- }
- pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
- result.measurement);
- batt_temp = (int)result.physical;
-
mutex_lock(&the_chip->last_ocv_uv_mutex);
read_soc_params_raw(the_chip, &raw);
-
- the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
- batt_temp, last_chargecycles);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
+ the_chip->start_percent = report_state_of_charge(the_chip);
+
bms_start_percent = the_chip->start_percent;
bms_start_ocv_uv = raw.last_good_ocv_uv;
calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
pm_bms_masked_write(the_chip, BMS_TOLERANCES,
IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
+ the_chip->charge_time_us = 0;
+ the_chip->catch_up_time_us = 0;
pr_debug("start_percent = %u%%\n", the_chip->start_percent);
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -1971,7 +2466,6 @@
last_real_fcc_mah = new_fcc_uah/1000;
last_real_fcc_batt_temp = batt_temp;
readjust_fcc_table();
-
}
if (is_battery_full) {
@@ -1985,7 +2479,7 @@
* forget the old cc value
*/
the_chip->last_cc_uah = 0;
- pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
+ pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
the_chip->ocv_reading_at_100,
the_chip->cc_reading_at_100);
}
@@ -2011,6 +2505,8 @@
last_chargecycles);
the_chip->start_percent = -EINVAL;
the_chip->end_percent = -EINVAL;
+ the_chip->charge_time_us = 0;
+ the_chip->catch_up_time_us = 0;
pm_bms_masked_write(the_chip, BMS_TOLERANCES,
IBAT_TOL_MASK, IBAT_TOL_NOCHG);
}
@@ -2157,94 +2653,6 @@
return -EINVAL;
}
-static int pm8921_bms_suspend(struct device *dev)
-{
- int rc;
- struct pm8xxx_adc_chan_result result;
- struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
- struct pm8921_soc_params raw;
- int fcc_uah;
- int remaining_charge_uah;
- int cc_uah;
-
- chip->batt_temp_suspend = 0;
- rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
- if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
- chip->batt_temp_channel, rc);
- }
- chip->batt_temp_suspend = (int)result.physical;
-
- mutex_lock(&chip->last_ocv_uv_mutex);
- read_soc_params_raw(chip, &raw);
-
- fcc_uah = calculate_fcc_uah(chip,
- chip->batt_temp_suspend, last_chargecycles);
- pr_debug("FCC = %uuAh batt_temp = %d, cycles = %d\n",
- fcc_uah, chip->batt_temp_suspend, last_chargecycles);
- /* calculate remainging charge */
- remaining_charge_uah = calculate_remaining_charge_uah(chip, &raw,
- fcc_uah, chip->batt_temp_suspend,
- last_chargecycles);
- pr_debug("RC = %uuAh\n", remaining_charge_uah);
-
- /* calculate cc micro_volt_hour */
- calculate_cc_uah(chip, raw.cc, &cc_uah);
- pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
- cc_uah, raw.cc,
- (int64_t)raw.cc - chip->cc_reading_at_100,
- chip->cc_reading_at_100);
- chip->soc_rbatt_suspend = ((remaining_charge_uah - cc_uah) * 100)
- / fcc_uah;
- mutex_unlock(&chip->last_ocv_uv_mutex);
-
- return 0;
-}
-
-#define DELTA_RBATT_PERCENT 10
-static int pm8921_bms_resume(struct device *dev)
-{
- struct pm8921_rbatt_params raw;
- struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
- int rbatt;
- int expected_rbatt;
- int scalefactor;
- int delta_rbatt;
-
- read_rbatt_params_raw(chip, &raw);
- rbatt = calculate_rbatt_resume(chip, &raw);
-
- if (rbatt < 0)
- return 0;
-
- expected_rbatt
- = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
-
- if (chip->rbatt_sf_lut) {
- scalefactor = interpolate_scalingfactor(chip,
- chip->rbatt_sf_lut,
- chip->batt_temp_suspend / 10,
- chip->soc_rbatt_suspend);
- rbatt = rbatt * 100 / scalefactor;
- }
-
- delta_rbatt = expected_rbatt - rbatt;
- if (delta_rbatt)
- delta_rbatt = -delta_rbatt;
- /*
- * only update last_rbatt if rbatt is within some
- * percent of expected_rbatt
- */
- if (delta_rbatt * 100 <= DELTA_RBATT_PERCENT * expected_rbatt)
- last_rbatt = rbatt;
-
- return 0;
-}
-
-static const struct dev_pm_ops pm8921_pm_ops = {
- .suspend = pm8921_bms_suspend,
- .resume = pm8921_bms_resume,
-};
#define EN_BMS_BIT BIT(7)
#define EN_PON_HS_BIT BIT(0)
static int __devinit pm8921_bms_hw_init(struct pm8921_bms_chip *chip)
@@ -2359,7 +2767,6 @@
}
enum bms_request_operation {
- CALC_RBATT,
CALC_FCC,
CALC_PC,
CALC_SOC,
@@ -2420,18 +2827,13 @@
int ret = 0;
int ibat_ua, vbat_uv;
struct pm8921_soc_params raw;
- struct pm8921_rbatt_params rraw;
read_soc_params_raw(the_chip, &raw);
- read_rbatt_params_raw(the_chip, &rraw);
*val = 0;
/* global irq number passed in via data */
switch (param) {
- case CALC_RBATT:
- *val = calculate_rbatt_resume(the_chip, &rraw);
- break;
case CALC_FCC:
*val = calculate_fcc_uah(the_chip, test_batt_temp,
test_chargecycle);
@@ -2490,10 +2892,8 @@
int param = (int)data;
int ret = 0;
struct pm8921_soc_params raw;
- struct pm8921_rbatt_params rraw;
read_soc_params_raw(the_chip, &raw);
- read_rbatt_params_raw(the_chip, &rraw);
*val = 0;
@@ -2505,15 +2905,6 @@
case LAST_GOOD_OCV_VALUE:
*val = raw.last_good_ocv_uv;
break;
- case VBATT_FOR_RBATT:
- *val = rraw.vbatt_for_rbatt_uv;
- break;
- case VSENSE_FOR_RBATT:
- *val = rraw.vsense_for_rbatt_uv;
- break;
- case OCV_FOR_RBATT:
- *val = rraw.ocv_for_rbatt_uv;
- break;
case VSENSE_AVG:
read_vsense_avg(the_chip, (uint *)val);
break;
@@ -2609,8 +3000,6 @@
debugfs_create_file("read_vsense_avg", 0644, chip->dent,
(void *)VSENSE_AVG, &reading_fops);
- debugfs_create_file("show_rbatt", 0644, chip->dent,
- (void *)CALC_RBATT, &calc_fops);
debugfs_create_file("show_fcc", 0644, chip->dent,
(void *)CALC_FCC, &calc_fops);
debugfs_create_file("show_pc", 0644, chip->dent,
@@ -2716,13 +3105,20 @@
mutex_init(&chip->last_ocv_uv_mutex);
chip->dev = &pdev->dev;
chip->r_sense = pdata->r_sense;
- chip->i_test = pdata->i_test;
- chip->v_failure = pdata->v_failure;
+ chip->v_cutoff = pdata->v_cutoff;
chip->max_voltage_uv = pdata->max_voltage_uv;
chip->batt_type = pdata->battery_type;
chip->rconn_mohm = pdata->rconn_mohm;
chip->start_percent = -EINVAL;
chip->end_percent = -EINVAL;
+ chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
+ chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+ if (chip->adjust_soc_low_threshold >= 45)
+ chip->adjust_soc_low_threshold = 45;
+
+ chip->prev_pc_unusable = -EINVAL;
+
+ chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
rc = set_battery_data(chip);
if (rc) {
pr_err("%s bad battery data %d\n", __func__, rc);
@@ -2746,7 +3142,14 @@
chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
chip->revision = pm8xxx_get_revision(chip->dev->parent);
chip->enable_fcc_learning = pdata->enable_fcc_learning;
+
+ mutex_init(&chip->calib_mutex);
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
+ INIT_DELAYED_WORK(&chip->calib_hkadc_delayed_work,
+ calibrate_hkadc_delayed_work);
+
+ INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
+ calculate_soc_work);
rc = request_irqs(chip, pdev);
if (rc) {
@@ -2760,7 +3163,7 @@
goto free_irqs;
}
- read_shutdown_soc(chip);
+ read_shutdown_soc_and_iavg(chip);
platform_set_drvdata(pdev, chip);
the_chip = chip;
@@ -2773,20 +3176,25 @@
}
check_initial_ocv(chip);
- /* initial hkadc calibration */
- schedule_work(&chip->calib_hkadc_work);
+ /* start periodic hkadc calibration */
+ schedule_delayed_work(&chip->calib_hkadc_delayed_work, 0);
+
/* enable the vbatt reading interrupts for scheduling hkadc calib */
pm8921_bms_enable_irq(chip, PM8921_BMS_GOOD_OCV);
pm8921_bms_enable_irq(chip, PM8921_BMS_OCV_FOR_R);
- INIT_DELAYED_WORK(&chip->uuc_timer_work, uuc_timer_work);
- schedule_delayed_work(&chip->uuc_timer_work,
- msecs_to_jiffies(UUC_TIMER_MS));
+ calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
get_battery_uvolts(chip, &vbatt);
pr_info("OK battery_capacity_at_boot=%d volt = %d ocv = %d\n",
pm8921_bms_get_percent_charge(),
vbatt, chip->last_ocv_uv);
+
+ INIT_DELAYED_WORK(&chip->shutdown_soc_work, shutdown_soc_work);
+ schedule_delayed_work(&chip->shutdown_soc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (SHOW_SHUTDOWN_SOC_MS)));
+
return 0;
free_irqs:
@@ -2814,7 +3222,6 @@
.driver = {
.name = PM8921_BMS_DEV_NAME,
.owner = THIS_MODULE,
- .pm = &pm8921_pm_ops
},
};
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 85b653d..6330883 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -271,6 +271,7 @@
enum pm8921_chg_led_src_config led_src_config;
bool host_mode;
u8 active_path;
+ int recent_reported_soc;
};
/* user space parameter to limit usb current */
@@ -327,6 +328,10 @@
return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
}
+static int is_batfet_closed(struct pm8921_chg_chip *chip)
+{
+ return pm_chg_get_rt_status(chip, BATFET_IRQ);
+}
#define CAPTURE_FSM_STATE_CMD 0xC2
#define READ_BANK_7 0x70
#define READ_BANK_4 0x40
@@ -1400,6 +1405,7 @@
if (percent_soc <= 10)
pr_warn("low battery charge = %d%%\n", percent_soc);
+ chip->recent_reported_soc = percent_soc;
return percent_soc;
}
@@ -1741,6 +1747,15 @@
}
EXPORT_SYMBOL(pm8921_is_battery_present);
+int pm8921_is_batfet_closed(void)
+{
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+ return is_batfet_closed(the_chip);
+}
+EXPORT_SYMBOL(pm8921_is_batfet_closed);
/*
* Disabling the charge current limit causes current
* current limits to have no monitoring. An adequate charger
@@ -2768,6 +2783,7 @@
* per update_time minutes
*
*/
+#define LOW_SOC_HEARTBEAT_MS 20000
static void update_heartbeat(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -2776,7 +2792,12 @@
pm_chg_failed_clear(chip, 1);
power_supply_changed(&chip->batt_psy);
- schedule_delayed_work(&chip->update_heartbeat_work,
+ if (chip->recent_reported_soc <= 20)
+ schedule_delayed_work(&chip->update_heartbeat_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (LOW_SOC_HEARTBEAT_MS)));
+ else
+ schedule_delayed_work(&chip->update_heartbeat_work,
round_jiffies_relative(msecs_to_jiffies
(chip->update_time)));
}
@@ -2787,6 +2808,8 @@
static int ichg_threshold_ua = -400000;
module_param(ichg_threshold_ua, int, 0644);
+
+#define PM8921_CHG_VDDMAX_RES_MV 10
static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
{
int ichg_meas_ua, vbat_uv;
@@ -2846,9 +2869,11 @@
return;
}
+ adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
+ * PM8921_CHG_VDDMAX_RES_MV;
+
if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
-
pr_debug("adjusting vdd_max_mv to %d to make "
"vbat_batt_termial_uv = %d to %d\n",
adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 861bac8..e48257a 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -685,13 +685,13 @@
goto free_chip;
}
- INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
- schedule_delayed_work(&chip->calib_ccadc_work, 0);
disable_irq_nosync(chip->eoc_irq);
platform_set_drvdata(pdev, chip);
the_chip = chip;
+ INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
+ schedule_delayed_work(&chip->calib_ccadc_work, 0);
create_debugfs_entries(chip);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 2dd698a..3366bba 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -60,19 +60,40 @@
#define TSENS2_POINT1_MASK 0x3f00000
#define TSENS3_POINT1_MASK 0xfc000000
#define TSENS4_POINT1_MASK 0x3f
-#define TSENS5_POINT1_MASK 0xfc00
+#define TSENS5_POINT1_MASK 0xfc0
#define TSENS6_POINT1_MASK 0x3f000
#define TSENS7_POINT1_MASK 0xfc0000
#define TSENS8_POINT1_MASK 0x3f000000
#define TSENS9_POINT1_MASK 0x3f
#define TSENS10_POINT1_MASK 0xfc00
#define TSENS_CAL_SEL_0_1 0xc0000000
-#define TSENS_CAL_SEL_2 BIT(30)
+#define TSENS_CAL_SEL_2 0x40000000
#define TSENS_CAL_SEL_SHIFT 30
#define TSENS_CAL_SEL_SHIFT_2 28
-#define TSENS_ONE_POINT_CALIB 0x3
+#define TSENS_ONE_POINT_CALIB 0x1
#define TSENS_TWO_POINT_CALIB 0x2
+#define TSENS0_POINT1_SHIFT 8
+#define TSENS1_POINT1_SHIFT 14
+#define TSENS2_POINT1_SHIFT 20
+#define TSENS3_POINT1_SHIFT 26
+#define TSENS5_POINT1_SHIFT 6
+#define TSENS6_POINT1_SHIFT 12
+#define TSENS7_POINT1_SHIFT 18
+#define TSENS8_POINT1_SHIFT 24
+#define TSENS10_POINT1_SHIFT 6
+
+#define TSENS_POINT2_BASE_SHIFT 12
+#define TSENS0_POINT2_SHIFT 20
+#define TSENS1_POINT2_SHIFT 26
+#define TSENS3_POINT2_SHIFT 6
+#define TSENS4_POINT2_SHIFT 12
+#define TSENS5_POINT2_SHIFT 18
+#define TSENS6_POINT2_SHIFT 24
+#define TSENS8_POINT2_SHIFT 6
+#define TSENS9_POINT2_SHIFT 12
+#define TSENS10_POINT2_SHIFT 18
+
#define TSENS_BASE2_MASK 0xff000
#define TSENS0_POINT2_MASK 0x3f00000
#define TSENS1_POINT2_MASK 0xfc000000
@@ -97,7 +118,7 @@
#define TSENS_THRESHOLD_MAX_CODE 0x3ff
#define TSENS_THRESHOLD_MIN_CODE 0x0
-#define TSENS_CTRL_INIT_DATA1 0x3fffff9
+#define TSENS_CTRL_INIT_DATA1 0x1cfff9
#define TSENS_GLOBAL_INIT_DATA 0x302f16c
#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
@@ -141,27 +162,26 @@
static int tsens_tz_code_to_degc(int adc_code, int sensor_num)
{
int degcbeforefactor, degc;
- degcbeforefactor = (adc_code *
- tmdev->sensor[sensor_num].slope_mul_tsens_factor
- + tmdev->sensor[sensor_num].offset);
+ degcbeforefactor = ((adc_code * tmdev->tsens_factor) -
+ tmdev->sensor[sensor_num].offset)/
+ tmdev->sensor[sensor_num].slope_mul_tsens_factor;
if (degcbeforefactor == 0)
degc = degcbeforefactor;
else if (degcbeforefactor > 0)
- degc = (degcbeforefactor + tmdev->tsens_factor/2)
- / tmdev->tsens_factor;
+ degc = ((degcbeforefactor * tmdev->tsens_factor) +
+ tmdev->tsens_factor/2)/tmdev->tsens_factor;
else
- degc = (degcbeforefactor - tmdev->tsens_factor/2)
- / tmdev->tsens_factor;
+ degc = ((degcbeforefactor * tmdev->tsens_factor) -
+ tmdev->tsens_factor/2)/tmdev->tsens_factor;
+
return degc;
}
static int tsens_tz_degc_to_code(int degc, int sensor_num)
{
- int code = (degc * tmdev->tsens_factor -
- tmdev->sensor[sensor_num].offset
- + tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
- / tmdev->sensor[sensor_num].slope_mul_tsens_factor;
+ int code = ((degc * tmdev->sensor[sensor_num].slope_mul_tsens_factor)
+ + tmdev->sensor[sensor_num].offset)/tmdev->tsens_factor;
if (code > TSENS_THRESHOLD_MAX_CODE)
code = TSENS_THRESHOLD_MAX_CODE;
@@ -482,60 +502,80 @@
int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
int tsens9_point2 = 0, tsens10_point2 = 0;
- int tsens_base2_data = 0, tsens_calibration_mode = 0, temp;
+ int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
uint32_t calib_data[5];
for (i = 0; i < 5; i++)
calib_data[i] = readl_relaxed(tmdev->tsens_calib_addr
+ (i * TSENS_SN_ADDR_OFFSET));
- tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1
- >> TSENS_CAL_SEL_SHIFT);
- temp = (calib_data[3] & TSENS_CAL_SEL_2
- >> TSENS_CAL_SEL_SHIFT_2);
+ tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
+ >> TSENS_CAL_SEL_SHIFT;
+ temp = (calib_data[3] & TSENS_CAL_SEL_2)
+ >> TSENS_CAL_SEL_SHIFT_2;
tsens_calibration_mode |= temp;
- if (!tsens_calibration_mode) {
+ if (tsens_calibration_mode == 0) {
pr_debug("TSENS is calibrationless mode\n");
for (i = 0; i < tmdev->tsens_num_sensor; i++) {
- tmdev->sensor[i].calib_data_point2 = 78000;
- tmdev->sensor[i].calib_data_point1 = 49200;
- goto compute_intercept_slope;
+ tmdev->sensor[i].calib_data_point2 = 780;
+ tmdev->sensor[i].calib_data_point1 = 492;
}
+ goto compute_intercept_slope;
} else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
TSENS_TWO_POINT_CALIB) {
- tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
- tsens0_point1 = calib_data[0] & TSENS0_POINT1_MASK;
- tsens1_point1 = calib_data[0] & TSENS1_POINT1_MASK;
- tsens2_point1 = calib_data[0] & TSENS2_POINT1_MASK;
- tsens3_point1 = calib_data[0] & TSENS3_POINT1_MASK;
- tsens4_point1 = calib_data[1] & TSENS4_POINT1_MASK;
- tsens5_point1 = calib_data[1] & TSENS5_POINT1_MASK;
- tsens6_point1 = calib_data[1] & TSENS6_POINT1_MASK;
- tsens7_point1 = calib_data[1] & TSENS7_POINT1_MASK;
- tsens8_point1 = calib_data[1] & TSENS8_POINT1_MASK;
- tsens9_point1 = calib_data[2] & TSENS9_POINT1_MASK;
- tsens10_point1 = calib_data[2] & TSENS10_POINT1_MASK;
+ tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
+ tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
+ TSENS0_POINT1_SHIFT;
+ tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
+ TSENS1_POINT1_SHIFT;
+ tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
+ TSENS2_POINT1_SHIFT;
+ tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
+ TSENS3_POINT1_SHIFT;
+ tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
+ tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
+ TSENS5_POINT1_SHIFT;
+ tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
+ TSENS6_POINT1_SHIFT;
+ tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
+ TSENS7_POINT1_SHIFT;
+ tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
+ TSENS8_POINT1_SHIFT;
+ tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
+ tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK) >>
+ TSENS10_POINT1_SHIFT;
} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
- tsens_base2_data = calib_data[2] & TSENS_BASE2_MASK;
- tsens0_point2 = calib_data[2] & TSENS0_POINT2_MASK;
- tsens1_point2 = calib_data[2] & TSENS1_POINT2_MASK;
- tsens2_point2 = calib_data[3] & TSENS2_POINT2_MASK;
- tsens3_point2 = calib_data[3] & TSENS3_POINT2_MASK;
- tsens4_point2 = calib_data[3] & TSENS4_POINT2_MASK;
- tsens5_point2 = calib_data[3] & TSENS5_POINT2_MASK;
- tsens6_point2 = calib_data[3] & TSENS6_POINT2_MASK;
- tsens7_point2 = calib_data[4] & TSENS7_POINT2_MASK;
- tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
- tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
- tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
+ tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
+ TSENS_POINT2_BASE_SHIFT;
+ tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
+ TSENS0_POINT2_SHIFT;
+ tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
+ TSENS1_POINT2_SHIFT;
+ tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
+ tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
+ TSENS3_POINT2_SHIFT;
+ tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
+ TSENS4_POINT2_SHIFT;
+ tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
+ TSENS5_POINT2_SHIFT;
+ tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
+ TSENS6_POINT2_SHIFT;
+ tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
+ tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
+ TSENS8_POINT2_SHIFT;
+ tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
+ TSENS9_POINT2_SHIFT;
+ tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK) >>
+ TSENS10_POINT2_SHIFT;
} else {
pr_debug("Calibration mode is unknown: %d\n",
tsens_calibration_mode);
return -ENODEV;
}
- if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
+ if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
+ TSENS_TWO_POINT_CALIB) {
tmdev->sensor[0].calib_data_point1 =
(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
tmdev->sensor[1].calib_data_point1 =
@@ -580,7 +620,7 @@
tmdev->sensor[8].calib_data_point2 =
(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
tmdev->sensor[9].calib_data_point2 =
- (((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
+ (((tsens_base2_data + tsens9_point2) << 2) | TSENS_BIT_APPEND);
tmdev->sensor[10].calib_data_point2 =
(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
}
@@ -595,10 +635,9 @@
num *= tmdev->tsens_factor;
tmdev->sensor[i].slope_mul_tsens_factor = num/den;
}
- tmdev->sensor[i].offset = (TSENS_CAL_DEGC_POINT1 *
- tmdev->tsens_factor)
- - (tmdev->sensor[i].calib_data_point1 *
- tmdev->sensor[i].slope_mul_tsens_factor);
+ tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
+ tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
+ tmdev->sensor[i].slope_mul_tsens_factor);
INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
tmdev->prev_reading_avail = false;
}
@@ -747,6 +786,7 @@
goto fail;
tsens_hw_init();
+
tmdev->prev_reading_avail = true;
platform_set_drvdata(pdev, tmdev);
@@ -796,6 +836,7 @@
goto fail;
}
}
+
rc = request_irq(tmdev->tsens_irq, tsens_isr,
IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
if (rc < 0) {
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 6c9b7cd..ccbaa6d 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -418,6 +418,8 @@
int count;
char *char_buf;
unsigned char *flag_buf;
+ unsigned int left = 0;
+ unsigned int max_space;
count = head->commit - head->read;
if (!count) {
@@ -432,10 +434,33 @@
line discipline as we want to empty the queue */
if (test_bit(TTY_FLUSHPENDING, &tty->flags))
break;
+
+ /* update receive room */
+ spin_lock(&tty->read_lock);
+ if (tty->update_room_in_ldisc) {
+ if ((tty->read_cnt == N_TTY_BUF_SIZE - 1) &&
+ (tty->receive_room ==
+ N_TTY_BUF_SIZE - 1))
+ tty->rr_bug++;
+ left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+ }
+ spin_unlock(&tty->read_lock);
+
if (!tty->receive_room)
break;
- if (count > tty->receive_room)
- count = tty->receive_room;
+
+ if (tty->update_room_in_ldisc && !left) {
+ schedule_work(&tty->buf.work);
+ break;
+ }
+
+ if (tty->update_room_in_ldisc)
+ max_space = min(left, tty->receive_room);
+ else
+ max_space = tty->receive_room;
+
+ if (count > max_space)
+ count = max_space;
char_buf = head->char_buf_ptr + head->read;
flag_buf = head->flag_buf_ptr + head->read;
head->read += count;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 4dd6d68..eebda9e 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -47,6 +47,8 @@
#define USB_REG_START_OFFSET 0x90
#define USB_REG_END_OFFSET 0x250
+static struct workqueue_struct *ehci_wq;
+
struct msm_hsic_hcd {
struct ehci_hcd ehci;
struct device *dev;
@@ -66,6 +68,9 @@
uint32_t bus_perf_client;
uint32_t wakeup_int_cnt;
enum usb_vdd_type vdd_type;
+
+ struct work_struct bus_vote_w;
+ bool bus_vote;
};
struct msm_hsic_hcd *__mehci;
@@ -658,11 +663,8 @@
dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
if (mehci->bus_perf_client && debug_bus_voting_enabled) {
- ret = msm_bus_scale_client_update_request(
- mehci->bus_perf_client, 0);
- if (ret)
- dev_err(mehci->dev, "%s: Failed to dvote for "
- "bus bandwidth %d\n", __func__, ret);
+ mehci->bus_vote = false;
+ queue_work(ehci_wq, &mehci->bus_vote_w);
}
atomic_set(&mehci->in_lpm, 1);
@@ -697,11 +699,8 @@
}
if (mehci->bus_perf_client && debug_bus_voting_enabled) {
- ret = msm_bus_scale_client_update_request(
- mehci->bus_perf_client, 1);
- if (ret)
- dev_err(mehci->dev, "%s: Failed to vote for "
- "bus bandwidth %d\n", __func__, ret);
+ mehci->bus_vote = true;
+ queue_work(ehci_wq, &mehci->bus_vote_w);
}
min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
@@ -769,6 +768,19 @@
}
#endif
+static void ehci_hsic_bus_vote_w(struct work_struct *w)
+{
+ struct msm_hsic_hcd *mehci =
+ container_of(w, struct msm_hsic_hcd, bus_vote_w);
+ int ret;
+
+ ret = msm_bus_scale_client_update_request(mehci->bus_perf_client,
+ mehci->bus_vote);
+ if (ret)
+ dev_err(mehci->dev, "%s: Failed to vote for bus bandwidth %d\n",
+ __func__, ret);
+}
+
static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
{
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1294,6 +1306,15 @@
goto deinit_vddcx;
}
+ ehci_wq = create_singlethread_workqueue("ehci_wq");
+ if (!ehci_wq) {
+ dev_err(&pdev->dev, "unable to create workqueue\n");
+ ret = -ENOMEM;
+ goto deinit_vddcx;
+ }
+
+ INIT_WORK(&mehci->bus_vote_w, ehci_hsic_bus_vote_w);
+
ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
if (ret) {
dev_err(&pdev->dev, "unable to register HCD\n");
@@ -1339,11 +1360,8 @@
msm_bus_scale_register_client(pdata->bus_scale_table);
/* Configure BUS performance parameters for MAX bandwidth */
if (mehci->bus_perf_client) {
- ret = msm_bus_scale_client_update_request(
- mehci->bus_perf_client, 1);
- if (ret)
- dev_err(&pdev->dev, "%s: Failed to vote for "
- "bus bandwidth %d\n", __func__, ret);
+ mehci->bus_vote = true;
+ queue_work(ehci_wq, &mehci->bus_vote_w);
} else {
dev_err(&pdev->dev, "%s: Failed to register BUS "
"scaling client!!\n", __func__);
@@ -1369,6 +1387,7 @@
return 0;
unconfig_gpio:
+ destroy_workqueue(ehci_wq);
msm_hsic_config_gpios(mehci, 0);
deinit_vddcx:
msm_hsic_init_vddcx(mehci, 0);
@@ -1396,6 +1415,14 @@
free_irq(mehci->wakeup_irq, mehci);
}
+ /*
+ * If the update request is called after unregister, the request will
+ * fail. Results are undefined if unregister is called in the middle of
+ * update request.
+ */
+ mehci->bus_vote = false;
+ cancel_work_sync(&mehci->bus_vote_w);
+
if (mehci->bus_perf_client)
msm_bus_scale_unregister_client(mehci->bus_perf_client);
@@ -1403,6 +1430,8 @@
device_init_wakeup(&pdev->dev, 0);
pm_runtime_set_suspended(&pdev->dev);
+ destroy_workqueue(ehci_wq);
+
usb_remove_hcd(hcd);
msm_hsic_config_gpios(mehci, 0);
msm_hsic_init_vddcx(mehci, 0);
@@ -1436,12 +1465,26 @@
return ret;
}
+static int msm_hsic_pm_suspend_noirq(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+ if (mehci->async_int) {
+ dev_dbg(dev, "suspend_noirq: Aborting due to pending interrupt\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
static int msm_hsic_pm_resume(struct device *dev)
{
int ret;
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ dev_dbg(dev, "ehci-msm-hsic PM resume\n");
dbg_log_event(NULL, "PM Resume", 0);
if (device_may_wakeup(dev))
@@ -1495,6 +1538,7 @@
#ifdef CONFIG_PM
static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
+ .suspend_noirq = msm_hsic_pm_suspend_noirq,
SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
msm_hsic_runtime_idle)
};
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 355990a..4217ba0 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -879,6 +879,8 @@
if (device_may_wakeup(phy->dev)) {
enable_irq_wake(motg->irq);
+ if (motg->async_irq)
+ enable_irq_wake(motg->async_irq);
if (motg->pdata->pmic_id_irq)
enable_irq_wake(motg->pdata->pmic_id_irq);
if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -889,6 +891,9 @@
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
atomic_set(&motg->in_lpm, 1);
+ /* Enable ASYNC IRQ (if present) during LPM */
+ if (motg->async_irq)
+ enable_irq(motg->async_irq);
enable_irq(motg->irq);
wake_unlock(&motg->wlock);
@@ -979,6 +984,8 @@
skip_phy_resume:
if (device_may_wakeup(phy->dev)) {
disable_irq_wake(motg->irq);
+ if (motg->async_irq)
+ disable_irq_wake(motg->async_irq);
if (motg->pdata->pmic_id_irq)
disable_irq_wake(motg->pdata->pmic_id_irq);
if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -991,10 +998,15 @@
atomic_set(&motg->in_lpm, 0);
if (motg->async_int) {
+ /* Match the disable_irq call from ISR */
+ enable_irq(motg->async_int);
motg->async_int = 0;
- enable_irq(motg->irq);
}
+ /* If ASYNC IRQ is present then keep it enabled only during LPM */
+ if (motg->async_irq)
+ disable_irq(motg->async_irq);
+
dev_info(phy->dev, "USB exited from low power mode\n");
return 0;
@@ -2728,9 +2740,9 @@
irqreturn_t ret = IRQ_HANDLED;
if (atomic_read(&motg->in_lpm)) {
- pr_debug("OTG IRQ: in LPM\n");
+ pr_debug("OTG IRQ: %d in LPM\n", irq);
disable_irq_nosync(irq);
- motg->async_int = 1;
+ motg->async_int = irq;
if (atomic_read(&motg->pm_suspended)) {
motg->sm_work_pending = true;
if ((otg->phy->state == OTG_STATE_A_SUSPEND) ||
@@ -3397,7 +3409,7 @@
static int __init msm_otg_probe(struct platform_device *pdev)
{
- int ret = 0, disable_lpm = 0;
+ int ret = 0;
struct resource *res;
struct msm_otg *motg;
struct usb_phy *phy;
@@ -3415,8 +3427,6 @@
dev_err(&pdev->dev, "devices setup failed\n");
return ret;
}
- /* LPM not supported on targets using DT */
- disable_lpm = 1;
} else if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "No platform data given. Bailing out\n");
return -ENODEV;
@@ -3516,6 +3526,12 @@
goto free_regs;
}
+ motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
+ if (motg->async_irq < 0) {
+ dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
+ motg->async_irq = 0;
+ }
+
motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
if (IS_ERR(motg->xo_handle)) {
dev_err(&pdev->dev, "%s not able to get the handle "
@@ -3602,6 +3618,16 @@
goto destroy_wlock;
}
+ if (motg->async_irq) {
+ ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_SHARED,
+ "msm_otg", motg);
+ if (ret) {
+ dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+ goto free_irq;
+ }
+ disable_irq(motg->async_irq);
+ }
+
if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
@@ -3620,7 +3646,7 @@
ret = usb_set_transceiver(&motg->phy);
if (ret) {
dev_err(&pdev->dev, "usb_set_transceiver failed\n");
- goto free_irq;
+ goto free_async_irq;
}
if (motg->pdata->mode == USB_OTG &&
@@ -3672,8 +3698,7 @@
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
- if (!disable_lpm)
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
if (motg->pdata->bus_scale_table) {
motg->bus_perf_client =
@@ -3689,6 +3714,9 @@
remove_phy:
usb_set_transceiver(NULL);
+free_async_irq:
+ if (motg->async_irq)
+ free_irq(motg->async_irq, motg);
free_irq:
free_irq(motg->irq, motg);
destroy_wlock:
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 366df67..c3f741b 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -495,6 +495,7 @@
/* explicitly set the driver mode to raw */
tty->raw = 1;
tty->real_raw = 1;
+ tty->update_room_in_ldisc = 1;
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
dbg("%s", __func__);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index d911b62..6d14ec1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -50,6 +50,7 @@
static struct clk *mdp_lut_clk;
int mdp_rev;
int mdp_iommu_split_domain;
+u32 mdp_max_clk = 200000000;
static struct platform_device *mdp_init_pdev;
static struct regulator *footswitch;
@@ -2178,33 +2179,6 @@
__func__, mdp_hw_revision);
}
-#ifdef CONFIG_FB_MSM_MDP40
-static void configure_mdp_core_clk_table(uint32 min_clk_rate)
-{
- uint8 count;
- uint32 current_rate;
- if (mdp_clk && mdp_pdata && mdp_pdata->mdp_core_clk_table) {
- min_clk_rate = clk_round_rate(mdp_clk, min_clk_rate);
- if (clk_set_rate(mdp_clk, min_clk_rate) < 0)
- printk(KERN_ERR "%s: clk_set_rate failed\n",
- __func__);
- else {
- count = 0;
- current_rate = clk_get_rate(mdp_clk);
- while (count < mdp_pdata->num_mdp_clk) {
- if (mdp_pdata->mdp_core_clk_table[count]
- < current_rate) {
- mdp_pdata->
- mdp_core_clk_table[count] =
- current_rate;
- }
- count++;
- }
- }
- }
-}
-#endif
-
#ifdef CONFIG_MSM_BUS_SCALING
static uint32_t mdp_bus_scale_handle;
int mdp_bus_scale_update_request(uint32_t index)
@@ -2223,29 +2197,24 @@
}
#endif
DEFINE_MUTEX(mdp_clk_lock);
-int mdp_set_core_clk(uint16 perf_level)
+int mdp_set_core_clk(u32 rate)
{
int ret = -EINVAL;
- if (mdp_clk && mdp_pdata
- && mdp_pdata->mdp_core_clk_table) {
- if (perf_level > mdp_pdata->num_mdp_clk)
- printk(KERN_ERR "%s invalid perf level\n", __func__);
- else {
- mutex_lock(&mdp_clk_lock);
- ret = clk_set_rate(mdp_clk,
- mdp_pdata->
- mdp_core_clk_table[mdp_pdata->num_mdp_clk
- - perf_level]);
- mutex_unlock(&mdp_clk_lock);
- if (ret) {
- printk(KERN_ERR "%s unable to set mdp_core_clk rate\n",
- __func__);
- }
- }
- }
+ if (mdp_clk)
+ ret = clk_set_rate(mdp_clk, rate);
+ if (ret)
+ pr_err("%s unable to set mdp clk rate", __func__);
+ else
+ pr_debug("%s mdp clk rate to be set %d: actual rate %ld\n",
+ __func__, rate, clk_get_rate(mdp_clk));
return ret;
}
+int mdp_clk_round_rate(u32 rate)
+{
+ return clk_round_rate(mdp_clk, rate);
+}
+
unsigned long mdp_get_core_clk(void)
{
unsigned long clk_rate = 0;
@@ -2258,25 +2227,6 @@
return clk_rate;
}
-unsigned long mdp_perf_level2clk_rate(uint32 perf_level)
-{
- unsigned long clk_rate = 0;
-
- if (mdp_pdata && mdp_pdata->mdp_core_clk_table) {
- if (perf_level > mdp_pdata->num_mdp_clk) {
- printk(KERN_ERR "%s invalid perf level\n", __func__);
- clk_rate = mdp_get_core_clk();
- } else {
- clk_rate = mdp_pdata->
- mdp_core_clk_table[mdp_pdata->num_mdp_clk
- - perf_level];
- }
- } else
- clk_rate = mdp_get_core_clk();
-
- return clk_rate;
-}
-
static int mdp_irq_clk_setup(struct platform_device *pdev,
char cont_splashScreen)
{
@@ -2333,21 +2283,25 @@
}
#ifdef CONFIG_FB_MSM_MDP40
- /*
- * mdp_clk should greater than mdp_pclk always
- */
- if (mdp_pdata && mdp_pdata->mdp_core_clk_rate) {
- if (cont_splashScreen)
- mdp_clk_rate = clk_get_rate(mdp_clk);
- else
- mdp_clk_rate = mdp_pdata->mdp_core_clk_rate;
- mutex_lock(&mdp_clk_lock);
- clk_set_rate(mdp_clk, mdp_clk_rate);
- if (mdp_lut_clk != NULL)
- clk_set_rate(mdp_lut_clk, mdp_clk_rate);
- mutex_unlock(&mdp_clk_lock);
- }
+ if (mdp_pdata)
+ mdp_max_clk = mdp_pdata->mdp_max_clk;
+ else
+ pr_err("%s cannot get mdp max clk!\n", __func__);
+
+ if (!mdp_max_clk)
+ pr_err("%s mdp max clk is zero!\n", __func__);
+
+ if (cont_splashScreen)
+ mdp_clk_rate = clk_get_rate(mdp_clk);
+ else
+ mdp_clk_rate = mdp_max_clk;
+
+ mutex_lock(&mdp_clk_lock);
+ clk_set_rate(mdp_clk, mdp_clk_rate);
+ if (mdp_lut_clk != NULL)
+ clk_set_rate(mdp_lut_clk, mdp_clk_rate);
+ mutex_unlock(&mdp_clk_lock);
MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk));
#endif
@@ -2468,8 +2422,6 @@
mfd->ov1_wb_buf->size = 0;
mfd->mem_hid = 0;
}
- mfd->ov0_blt_state = 0;
- mfd->use_ov0_blt = 0 ;
/* initialize Post Processing data*/
mdp_hist_lut_init();
@@ -2568,7 +2520,6 @@
case MIPI_VIDEO_PANEL:
#ifndef CONFIG_FB_MSM_MDP303
mipi = &mfd->panel_info.mipi;
- configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 23 / 20);
mdp4_dsi_vsync_init(0);
mfd->hw_refresh = TRUE;
mfd->dma_fnc = mdp4_dsi_video_overlay;
@@ -2613,7 +2564,6 @@
#ifndef CONFIG_FB_MSM_MDP303
mfd->dma_fnc = mdp4_dsi_cmd_overlay;
mipi = &mfd->panel_info.mipi;
- configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 3 / 2);
mdp4_dsi_rdptr_init(0);
if (mfd->panel_info.pdest == DISPLAY_1) {
if_no = PRIMARY_INTF_SEL;
@@ -2698,8 +2648,6 @@
#ifdef CONFIG_FB_MSM_MDP40
mdp4_lcdc_vsync_init(0);
- configure_mdp_core_clk_table((mfd->panel_info.clk_rate)
- * 23 / 20);
if (mfd->panel.type == HDMI_PANEL) {
mfd->dma = &dma_e_data;
mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 76d06a0..293bd9b 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -812,7 +812,9 @@
void mdp_disable_irq_nosync(uint32 term);
int mdp_get_bytes_per_pixel(uint32_t format,
struct msm_fb_data_type *mfd);
-int mdp_set_core_clk(uint16 perf_level);
+int mdp_set_core_clk(u32 rate);
+int mdp_clk_round_rate(u32 rate);
+
unsigned long mdp_get_core_clk(void);
unsigned long mdp_perf_level2clk_rate(uint32 perf_level);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index cf8a9b2..cc4eae5 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -27,6 +27,7 @@
extern uint32 mdp4_extn_disp;
extern char *mmss_cc_base; /* mutimedia sub system clock control */
extern spinlock_t dsi_clk_lock;
+extern u32 mdp_max_clk;
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
@@ -361,6 +362,8 @@
uint32 blt_ov_done;
uint32 blt_dmap_koff;
uint32 blt_dmap_done;
+ uint32 req_clk;
+ uint32 req_bw;
uint32 luma_align_size;
struct mdp_overlay_pp_params pp_cfg;
struct mdp_overlay req_data;
@@ -610,9 +613,6 @@
void mdp4_lcdc_wait4vsync(int cndx, long long *vtime);
void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd);
-void mdp4_update_perf_level(u32 perf_level);
-void mdp4_set_perf_level(void);
void mdp4_mddi_overlay_dmas_restore(void);
#ifndef CONFIG_FB_MSM_MIPI_DSI
@@ -728,6 +728,12 @@
{
/* empty */
}
+static inline void mdp4_dsi_cmd_blt_start(struct msm_fb_data_type *mfd)
+{
+}
+static inline void mdp4_dsi_cmd_blt_stop(struct msm_fb_data_type *mfd)
+{
+}
#endif /* CONFIG_FB_MSM_MIPI_DSI */
void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -914,6 +920,11 @@
int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
unsigned long srcp0_addr, unsigned long srcp1_addr,
unsigned long srcp2_addr);
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+ struct msm_fb_data_type *mfd);
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *plist);
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag);
#ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
static inline void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index a6ffe82..89ae254 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -104,7 +104,21 @@
static DEFINE_MUTEX(iommu_mutex);
static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db;
-static int new_perf_level;
+
+struct mdp4_overlay_perf {
+ u32 mdp_clk_rate;
+ u32 use_ov0_blt;
+ u32 use_ov1_blt;
+ u32 mdp_bw;
+};
+
+struct mdp4_overlay_perf perf_request = {
+ .mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+struct mdp4_overlay_perf perf_current = {
+ .mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+
static struct ion_client *display_iclient;
@@ -2114,79 +2128,6 @@
}
-static int mdp4_overlay_validate_downscale(struct mdp_overlay *req,
- struct msm_fb_data_type *mfd, uint32 perf_level, uint32 pclk_rate)
-{
- __u32 panel_clk_khz, mdp_clk_khz;
- __u32 num_hsync_pix_clks, mdp_clks_per_hsync, src_wh;
- __u32 hsync_period_ps, mdp_period_ps, total_hsync_period_ps;
- unsigned long fill_rate_y_dir, fill_rate_x_dir;
- unsigned long fillratex100, mdp_pixels_produced;
- unsigned long mdp_clk_hz;
-
- pr_debug("%s: LCDC Mode Downscale validation with MDP Core"
- " Clk rate\n", __func__);
- pr_debug("src_w %u, src_h %u, dst_w %u, dst_h %u\n",
- req->src_rect.w, req->src_rect.h, req->dst_rect.w,
- req->dst_rect.h);
-
-
- panel_clk_khz = pclk_rate/1000;
- mdp_clk_hz = mdp_perf_level2clk_rate(perf_level);
-
- if (!mdp_clk_hz || !req->dst_rect.w || !req->dst_rect.h) {
- pr_debug("mdp_perf_level2clk_rate returned 0,"
- "or dst_rect height/width is 0,"
- "Downscale Validation incomplete\n");
- return 0;
- }
-
- mdp_clk_khz = mdp_clk_hz/1000;
-
- num_hsync_pix_clks = mfd->panel_info.lcdc.h_back_porch +
- mfd->panel_info.lcdc.h_front_porch +
- mfd->panel_info.lcdc.h_pulse_width +
- mfd->panel_info.xres;
-
- hsync_period_ps = 1000000000/panel_clk_khz;
- mdp_period_ps = 1000000000/mdp_clk_khz;
-
- total_hsync_period_ps = num_hsync_pix_clks * hsync_period_ps;
- mdp_clks_per_hsync = total_hsync_period_ps/mdp_period_ps;
-
- pr_debug("hsync_period_ps %u, mdp_period_ps %u,"
- "total_hsync_period_ps %u\n", hsync_period_ps,
- mdp_period_ps, total_hsync_period_ps);
-
- src_wh = req->src_rect.w * req->src_rect.h;
- if (src_wh % req->dst_rect.h)
- fill_rate_y_dir = (src_wh / req->dst_rect.h) + 1;
- else
- fill_rate_y_dir = (src_wh / req->dst_rect.h);
-
- fill_rate_x_dir = (mfd->panel_info.xres - req->dst_rect.w)
- + req->src_rect.w;
-
- if (fill_rate_y_dir >= fill_rate_x_dir)
- fillratex100 = 100 * fill_rate_y_dir / mfd->panel_info.xres;
- else
- fillratex100 = 100 * fill_rate_x_dir / mfd->panel_info.xres;
-
- pr_debug("mdp_clks_per_hsync %u, fill_rate_y_dir %lu,"
- "fill_rate_x_dir %lu\n", mdp_clks_per_hsync,
- fill_rate_y_dir, fill_rate_x_dir);
-
- mdp_pixels_produced = 100 * mdp_clks_per_hsync/fillratex100;
- pr_debug("fillratex100 %lu, mdp_pixels_produced %lu\n",
- fillratex100, mdp_pixels_produced);
- if (mdp_pixels_produced <= mfd->panel_info.xres) {
- mdp4_stat.err_underflow++;
- return -ERANGE;
- }
-
- return 0;
-}
-
static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer,
struct mdp4_overlay_pipe **ppipe,
struct msm_fb_data_type *mfd)
@@ -2428,11 +2369,451 @@
pipe->transp = req->transp_mask;
+ pipe->flags = req->flags;
+
*ppipe = pipe;
return 0;
}
+static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ u32 pclk;
+ u32 xscale, yscale;
+ u32 hsync = 0;
+ u32 shift = 16;
+ u64 rst;
+ int ret = -EINVAL;
+
+ if (!pipe) {
+ pr_err("%s: pipe is null!\n", __func__);
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ return ret;
+ }
+ if (!mfd) {
+ pr_err("%s: mfd is null!\n", __func__);
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ return ret;
+ }
+
+ /*
+ * Serveral special cases require the max mdp clk but cannot
+ * be explained by mdp clk equation.
+ */
+ if (pipe->flags & MDP_DEINTERLACE) {
+ pr_info("%s deinterlace requires max mdp clk.\n",
+ __func__);
+ pipe->req_clk = mdp_max_clk;
+ return 0;
+ }
+
+ pr_debug("%s: pipe sets: panel res(x,y)=(%d,%d)\n",
+ __func__, mfd->panel_info.xres, mfd->panel_info.yres);
+ pr_debug("%s: src(w,h)(%d,%d),src(x,y)(%d,%d)\n",
+ __func__, pipe->src_w, pipe->src_h, pipe->src_x, pipe->src_y);
+ pr_debug("%s: dst(w,h)(%d,%d),dst(x,y)(%d,%d)\n",
+ __func__, pipe->dst_w, pipe->dst_h, pipe->dst_x, pipe->dst_y);
+
+ pclk = (mfd->panel_info.type == MIPI_VIDEO_PANEL ||
+ mfd->panel_info.type == MIPI_CMD_PANEL) ?
+ mfd->panel_info.mipi.dsi_pclk_rate :
+ mfd->panel_info.clk_rate;
+ if (!pclk) {
+ pipe->req_clk = mdp_max_clk;
+ pr_err("%s panel pixel clk is zero!\n", __func__);
+ return ret;
+ }
+ pr_debug("%s: mdp panel pixel clk is %d.\n",
+ __func__, pclk);
+
+ if (!pipe->dst_h) {
+ pr_err("%s: pipe dst_h is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ if (!pipe->src_h) {
+ pr_err("%s: pipe src_h is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ if (!pipe->dst_w) {
+ pr_err("%s: pipe dst_w is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ if (!pipe->dst_h) {
+ pr_err("%s: pipe dst_h is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ /*
+ * For the scaling cases, make more margin by removing porch
+ * values and adding extra 20%.
+ */
+ if ((pipe->src_h != pipe->dst_h) ||
+ (pipe->src_w != pipe->dst_w)) {
+ hsync = mfd->panel_info.xres;
+ hsync *= 100;
+ hsync /= 120;
+ pr_debug("%s: panel hsync is %d. with scaling\n",
+ __func__, hsync);
+
+ } else {
+ hsync = mfd->panel_info.lcdc.h_back_porch +
+ mfd->panel_info.lcdc.h_front_porch +
+ mfd->panel_info.lcdc.h_pulse_width +
+ mfd->panel_info.xres;
+ pr_debug("%s: panel hsync is %d.\n",
+ __func__, hsync);
+ }
+
+ if (!hsync) {
+ pipe->req_clk = mdp_max_clk;
+ pr_err("%s: panel hsync is zero!\n", __func__);
+ return 0;
+ }
+
+ xscale = mfd->panel_info.xres;
+ xscale += pipe->src_w;
+
+ if (xscale < pipe->dst_w) {
+ pipe->req_clk = mdp_max_clk;
+ pr_err("%s: xres+src_w cannot be less than dst_w!\n",
+ __func__);
+ return ret;
+ }
+
+ xscale -= pipe->dst_w;
+ xscale <<= shift;
+ xscale /= hsync;
+ pr_debug("%s: the right %d shifted xscale is %d.\n",
+ __func__, shift, xscale);
+
+ if (pipe->src_h > pipe->dst_h) {
+ yscale = pipe->src_h;
+ yscale <<= shift;
+ yscale /= pipe->dst_h;
+ } else { /* upscale */
+ yscale = pipe->dst_h;
+ yscale <<= shift;
+ yscale /= pipe->src_h;
+ }
+
+ yscale *= pipe->src_w;
+ yscale /= hsync;
+
+ pr_debug("%s: the right %d shifted yscale is %d.\n",
+ __func__, shift, yscale);
+
+ rst = pclk;
+ if (yscale > xscale)
+ rst *= yscale;
+ else
+ rst *= xscale;
+
+ rst >>= shift;
+
+ /*
+ * If the calculated mdp clk is less than panel pixel clk,
+ * most likely due to upscaling, mdp clk rate will be set to
+ * greater than pclk. Now the driver uses 1.15 as the
+ * factor. Ideally this factor is passed from board file.
+ */
+ if (rst < pclk) {
+ rst = ((pclk >> shift) * 23 / 20) << shift;
+ pr_debug("%s calculated mdp clk is less than pclk.\n",
+ __func__);
+ }
+
+ pipe->req_clk = (u32) rst;
+
+ pr_debug("%s: required mdp clk %d mixer %d pipe ndx %d\n",
+ __func__, pipe->req_clk, pipe->mixer_num, pipe->pipe_ndx);
+
+ return 0;
+}
+
+#define OVERLAY_VGA_SIZE 0x04B000
+#define OVERLAY_720P_TILE_SIZE 0x0E6000
+#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
+
+#define OVERLAY_BUS_SCALE_TABLE_BASE 6
+
+
+static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ u32 res;
+ int ret = -EINVAL;
+
+ if (!pipe) {
+ pr_err("%s: pipe is null!\n", __func__);
+ return ret;
+ }
+ if (!mfd) {
+ pr_err("%s: mfd is null!\n", __func__);
+ return ret;
+ }
+
+ if (pipe->flags & MDP_DEINTERLACE) {
+ pr_info("%s deinterlace requires max mdp bw.\n",
+ __func__);
+ pipe->req_bw = OVERLAY_PERF_LEVEL1;
+ return 0;
+ }
+
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ return 0;
+ }
+
+ res = pipe->src_w * pipe->src_h;
+
+ if (res <= OVERLAY_WSVGA_SIZE)
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ else if (res <= OVERLAY_VGA_SIZE)
+ pipe->req_bw = OVERLAY_PERF_LEVEL3;
+ else if (res <= OVERLAY_720P_TILE_SIZE)
+ pipe->req_bw = OVERLAY_PERF_LEVEL2;
+ else
+ pipe->req_bw = OVERLAY_PERF_LEVEL1;
+
+ return 0;
+}
+
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *plist)
+{
+ u32 worst_mdp_clk = 0;
+ u32 worst_mdp_bw = OVERLAY_PERF_LEVEL4;
+ int i;
+ struct mdp4_overlay_perf *perf_req = &perf_request;
+ struct mdp4_overlay_pipe *pipe = plist;
+ u32 cnt = 0;
+ int ret = -EINVAL;
+
+ if (!mfd) {
+ pr_err("%s: mfd is null!\n", __func__);
+ return ret;
+ }
+
+ if (!plist) {
+ pr_err("%s: plist is null!\n", __func__);
+ return ret;
+ }
+
+ perf_req->use_ov0_blt = 0;
+ perf_req->use_ov1_blt = 0;
+
+ for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+
+ if (!pipe)
+ return ret;
+
+ if (!pipe->pipe_used)
+ continue;
+ cnt++;
+ if (worst_mdp_clk < pipe->req_clk)
+ worst_mdp_clk = pipe->req_clk;
+ if (pipe->req_clk > mdp_max_clk) {
+ if (pipe->mixer_num == MDP4_MIXER0)
+ perf_req->use_ov0_blt = 1;
+ if (pipe->mixer_num == MDP4_MIXER1)
+ perf_req->use_ov1_blt = 1;
+ }
+
+ if (!pipe->req_bw) {
+ pr_err("%s mdp pipe bw request should not be zero!\n",
+ __func__);
+ pr_debug("%s %d pid %d num %d idx %d mix %d bw %d\n",
+ __func__, __LINE__, current->pid,
+ pipe->pipe_num, pipe->pipe_ndx,
+ pipe->mixer_num, pipe->req_bw);
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ }
+
+ if (pipe->req_bw < worst_mdp_bw)
+ worst_mdp_bw = pipe->req_bw;
+
+ if (mfd->mdp_rev == MDP_REV_41) {
+ /*
+ * writeback (blt) mode to provide work around
+ * for dsi cmd mode interface hardware bug.
+ */
+ if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+ if (pipe->dst_x != 0)
+ perf_req->use_ov0_blt = 1;
+ }
+ if ((mfd->panel_info.xres > 1280) &&
+ (mfd->panel_info.type != DTV_PANEL)) {
+ perf_req->use_ov0_blt = 1;
+ }
+ }
+ }
+
+ perf_req->mdp_clk_rate = worst_mdp_clk;
+ if (perf_req->mdp_clk_rate > mdp_max_clk)
+ perf_req->mdp_clk_rate = mdp_max_clk;
+
+ perf_req->mdp_clk_rate = mdp_clk_round_rate(perf_req->mdp_clk_rate);
+
+ perf_req->mdp_bw = worst_mdp_bw;
+
+ if (cnt >= 3)
+ perf_req->mdp_bw = OVERLAY_PERF_LEVEL1;
+
+ pr_debug("%s %d pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d bw %d\n",
+ __func__, __LINE__, current->pid, cnt,
+ perf_req->mdp_clk_rate,
+ perf_req->use_ov0_blt,
+ perf_req->use_ov1_blt,
+ perf_req->mdp_bw);
+
+ return 0;
+}
+
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+ struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ if (mdp4_calc_pipe_mdp_clk(mfd, pipe)) {
+ pr_err("%s unable to calc mdp pipe clk rate ret=%d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
+ if (mdp4_calc_pipe_mdp_bw(mfd, pipe)) {
+ pr_err("%s unable to calc mdp pipe bandwidth ret=%d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd,
+ int flag)
+{
+ struct mdp4_overlay_perf *perf_req = &perf_request;
+ struct mdp4_overlay_perf *perf_cur = &perf_current;
+
+ pr_debug("%s %d: req mdp clk %d, cur mdp clk %d flag %d\n",
+ __func__, __LINE__,
+ perf_req->mdp_clk_rate,
+ perf_cur->mdp_clk_rate,
+ flag);
+
+ if (!mdp4_extn_disp)
+ perf_cur->use_ov1_blt = 0;
+
+ if (flag) {
+ if (perf_req->mdp_clk_rate > perf_cur->mdp_clk_rate) {
+ mdp_set_core_clk(perf_req->mdp_clk_rate);
+ pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_clk_rate,
+ perf_req->mdp_clk_rate);
+ perf_cur->mdp_clk_rate =
+ perf_req->mdp_clk_rate;
+ }
+ if (perf_req->mdp_bw < perf_cur->mdp_bw) {
+ mdp_bus_scale_update_request
+ (OVERLAY_BUS_SCALE_TABLE_BASE -
+ perf_req->mdp_bw);
+ pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_bw,
+ perf_req->mdp_bw);
+ perf_cur->mdp_bw = perf_req->mdp_bw;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_1 &&
+ perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) {
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+ if (mfd->panel_info.type == LCDC_PANEL ||
+ mfd->panel_info.type == LVDS_PANEL)
+ mdp4_lcdc_overlay_blt_start(mfd);
+ else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ mdp4_dsi_video_blt_start(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+ mdp4_dsi_cmd_blt_start(mfd);
+ pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov0_blt,
+ perf_req->use_ov0_blt);
+ perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_2 &&
+ perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) {
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+ mdp4_dtv_overlay_blt_start(mfd);
+ pr_info("%s mixer1 start blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov1_blt,
+ perf_req->use_ov1_blt);
+ perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+ }
+ } else {
+ if (perf_req->mdp_clk_rate < perf_cur->mdp_clk_rate) {
+ pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_clk_rate,
+ perf_req->mdp_clk_rate);
+ mdp_set_core_clk(perf_req->mdp_clk_rate);
+ perf_cur->mdp_clk_rate =
+ perf_req->mdp_clk_rate;
+ }
+ if (perf_req->mdp_bw > perf_cur->mdp_bw) {
+ pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_bw,
+ perf_req->mdp_bw);
+ mdp_bus_scale_update_request
+ (OVERLAY_BUS_SCALE_TABLE_BASE -
+ perf_req->mdp_bw);
+ perf_cur->mdp_bw = perf_req->mdp_bw;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_1 &&
+ !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) {
+ if (mfd->panel_info.type == LCDC_PANEL ||
+ mfd->panel_info.type == LVDS_PANEL)
+ mdp4_lcdc_overlay_blt_stop(mfd);
+ else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ mdp4_dsi_video_blt_stop(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+ mdp4_dsi_cmd_blt_stop(mfd);
+ mdp4_free_writeback_buf(mfd, MDP4_MIXER0);
+ pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov0_blt,
+ perf_req->use_ov0_blt);
+ perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_2 &&
+ !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) {
+ mdp4_dtv_overlay_blt_stop(mfd);
+ mdp4_free_writeback_buf(mfd, MDP4_MIXER1);
+ pr_info("%s mixer1 stop blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov1_blt,
+ perf_req->use_ov1_blt);
+ perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+ }
+ }
+ return;
+}
+
static int get_img(struct msmfb_data *img, struct fb_info *info,
struct mdp4_overlay_pipe *pipe, unsigned int plane,
unsigned long *start, unsigned long *len, struct file **srcp_file,
@@ -2555,154 +2936,10 @@
return 0;
}
-#define OVERLAY_VGA_SIZE 0x04B000
-#define OVERLAY_720P_TILE_SIZE 0x0E6000
-#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
-
-#define OVERLAY_BUS_SCALE_TABLE_BASE 6
-
-static int mdp4_overlay_is_rgb_type(int format)
-{
- switch (format) {
- case MDP_RGB_565:
- case MDP_RGB_888:
- case MDP_BGR_565:
- case MDP_XRGB_8888:
- case MDP_ARGB_8888:
- case MDP_RGBA_8888:
- case MDP_BGRA_8888:
- case MDP_RGBX_8888:
- return 1;
- default:
- return 0;
- }
-}
-
-static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
- struct msm_fb_data_type *mfd)
-{
- int is_fg = 0, i, cnt;
-
- if (req->is_fg && ((req->alpha & 0x0ff) == 0xff))
- is_fg = 1;
-
- if (mdp4_extn_disp)
- return OVERLAY_PERF_LEVEL1;
-
- if (req->flags & (MDP_DEINTERLACE | MDP_BACKEND_COMPOSITION))
- return OVERLAY_PERF_LEVEL1;
-
- for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) {
- if (ctrl->plist[i].pipe_used && ++cnt > 2)
- return OVERLAY_PERF_LEVEL1;
- }
-
- if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
- ((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
- return OVERLAY_PERF_LEVEL4;
- else if (mdp4_overlay_is_rgb_type(req->src.format))
- return OVERLAY_PERF_LEVEL1;
-
- if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE) {
- if (mfd->mdp_rev >= MDP_REV_42)
- return OVERLAY_PERF_LEVEL4;
- else
- return OVERLAY_PERF_LEVEL3;
-
- } else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) {
- u32 max, min;
- max = (req->dst_rect.h > req->dst_rect.w) ?
- req->dst_rect.h : req->dst_rect.w;
- min = (mfd->panel_info.yres > mfd->panel_info.xres) ?
- mfd->panel_info.xres : mfd->panel_info.yres;
- if (max > min) /* landscape mode */
- return OVERLAY_PERF_LEVEL3;
- else /* potrait mode */
- return OVERLAY_PERF_LEVEL2;
- }
- else
- return OVERLAY_PERF_LEVEL1;
-}
-
-void mdp4_update_perf_level(u32 perf_level)
-{
- static int first = 1;
-
- new_perf_level = perf_level;
-
- if (first) {
- first = 0;
- mdp4_set_perf_level();
- }
-}
-
-void mdp4_set_perf_level(void)
-{
- static int old_perf_level;
- int cur_perf_level;
-
- if (mdp4_extn_disp)
- cur_perf_level = OVERLAY_PERF_LEVEL1;
- else
- cur_perf_level = new_perf_level;
-
- if (old_perf_level != cur_perf_level) {
- mdp_set_core_clk(cur_perf_level);
- old_perf_level = cur_perf_level;
- mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
- - cur_perf_level);
- }
-}
-
-static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
- struct msm_fb_data_type *mfd, uint32 perf_level)
-{
- u32 clk_rate = mfd->panel_info.clk_rate;
- u32 blt_chq_req = 0, use_blt = 0;
-
- if ((mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
- (mfd->panel_info.type == MIPI_CMD_PANEL))
- clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
-
- if ((mfd->panel_info.type == LCDC_PANEL) ||
- (mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
- (mfd->panel_info.type == DTV_PANEL) ||
- (mfd->panel_info.type == MIPI_CMD_PANEL))
- blt_chq_req = 1;
-
- if (blt_chq_req && (req->src_rect.h > req->dst_rect.h ||
- req->src_rect.w > req->dst_rect.w)) {
- if (mdp4_overlay_validate_downscale(req, mfd, perf_level,
- clk_rate))
- use_blt = 1;
- }
-
- if (mfd->panel_info.type == MDDI_PANEL) {
- if ((req->src_rect.h/2) >= req->dst_rect.h ||
- (req->src_rect.w/2) >= req->dst_rect.w)
- use_blt = 1;
- }
-
- if (mfd->mdp_rev == MDP_REV_41) {
- /*
- * writeback (blt) mode to provide work around for
- * dsi cmd mode interface hardware bug.
- */
- if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
- if (req->dst_rect.x != 0)
- use_blt = 1;
- }
- if ((mfd->panel_info.xres > 1280) &&
- (mfd->panel_info.type != DTV_PANEL))
- use_blt = 1;
- }
- return use_blt;
-}
-
int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- int ret, mixer, perf_level;
+ int ret, mixer;
struct mdp4_overlay_pipe *pipe;
if (mfd == NULL) {
@@ -2732,20 +2969,10 @@
return ret;
}
- perf_level = mdp4_overlay_get_perf_level(req, mfd);
-
- if (mixer == MDP4_MIXER0) {
- u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
- mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
- mfd->use_ov0_blt |= (use_blt << (pipe->pipe_ndx-1));
- }
-
/* return id back to user */
req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */
pipe->req_data = *req; /* keep original req */
- pipe->flags = req->flags;
-
if (!IS_ERR_OR_NULL(mfd->iclient)) {
pr_debug("pipe->flags 0x%x\n", pipe->flags);
if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) {
@@ -2768,47 +2995,8 @@
__func__);
}
- if (ctrl->panel_mode & MDP4_PANEL_DTV &&
- pipe->mixer_num == MDP4_MIXER1) {
- u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
- if (hdmi_prim_display) {
- if (!mdp4_overlay_is_rgb_type(req->src.format) &&
- pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
- (req->src_rect.h > req->dst_rect.h ||
- req->src_rect.w > req->dst_rect.w))
- use_blt = 1;
- }
-
- mdp4_overlay_dtv_set(mfd, pipe);
- mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
- mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1));
- }
-
- if (new_perf_level != perf_level) {
- u32 old_level = new_perf_level;
- mdp4_update_perf_level(perf_level);
-
- /* change clck base on perf level */
- if (pipe->mixer_num == MDP4_MIXER0) {
- if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
- if (old_level > perf_level)
- mdp4_set_perf_level();
- } else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
- mdp4_set_perf_level();
- } else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
- if (old_level > perf_level)
- mdp4_set_perf_level();
- } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- mdp4_mddi_dma_busy_wait(mfd);
- mdp4_mddi_blt_dmap_busy_wait(mfd);
- mdp4_set_perf_level();
- }
- } else {
- if (ctrl->panel_mode & MDP4_PANEL_DTV)
- mdp4_overlay_dtv_set_perf(mfd);
- }
- }
mutex_unlock(&mfd->dma->ov_mutex);
return 0;
@@ -2864,7 +3052,6 @@
else {
/* mixer 0 */
ctrl->mixer0_played = 0;
-
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
if (mfd->panel_power_on)
mdp4_mddi_blt_dmap_busy_wait(mfd);
@@ -2879,13 +3066,9 @@
if (mfd->panel_power_on)
mdp4_mddi_overlay_restore();
}
-
- mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
} else { /* mixer1, DTV, ATV */
- if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+ if (ctrl->panel_mode & MDP4_PANEL_DTV)
mdp4_overlay_dtv_unset(mfd, pipe);
- mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
- }
}
mdp4_stat.overlay_unset[pipe->mixer_num]++;
@@ -3002,7 +3185,6 @@
pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,
(int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);
-
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
}
@@ -3036,6 +3218,7 @@
if (pipe->pipe_type == OVERLAY_TYPE_BF) {
mdp4_overlay_borderfill_stage_up(pipe);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
return 0;
}
@@ -3148,6 +3331,7 @@
}
}
+ mdp4_overlay_mdp_perf_req(mfd, ctrl->plist);
if (pipe->mixer_num == MDP4_MIXER2 ||
ctrl->panel_mode & MDP4_PANEL_MDDI)
@@ -3173,7 +3357,6 @@
return ret;
mddi:
-
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
} else {
@@ -3401,7 +3584,7 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
#ifdef V4L2_VSYNC
/*
* TODO: incorporate v4l2 into vsycn driven mechanism
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 753ff23..c133831 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -110,14 +110,13 @@
mdp4_overlay_dmae_xy(pipe); /* dma_e */
mdp4_overlay_dmae_cfg(mfd, 1);
-
mdp4_overlay_rgb_setup(pipe);
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
if (ret == 0)
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -183,10 +182,12 @@
} else {
pipe->srcp0_addr = (uint32)(buf + buf_offset);
}
+ mdp4_overlay_mdp_perf_req(pipe, mfd);
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_overlay_rgb_setup(pipe);
mdp4_overlay_reg_flush(pipe, 0);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
(int)pipe, pipe->pipe_ndx);
@@ -201,10 +202,7 @@
spin_unlock_irqrestore(&mdp_spin_lock, flag);
wait_for_completion_killable(&atv_pipe->comp);
mdp_disable_irq(MDP_OVERLAY1_TERM);
-
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
-
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
mdp4_stat.kickoff_atv++;
mutex_unlock(&mfd->dma->ov_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index e1fa02e..36a6b2a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -864,6 +864,7 @@
/* disable dsi trigger */
MDP_OUTP(MDP_BASE + 0x000a4, 0x00);
+
mdp4_overlay_setup_pipe_addr(mfd, pipe);
mdp4_overlay_rgb_setup(pipe);
@@ -878,6 +879,7 @@
mdp4_overlay_dmap_cfg(mfd, 0);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
mdp_clk_ctrl(0);
}
@@ -955,6 +957,7 @@
mdp4_overlay_dmap_cfg(mfd, 0);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -1098,18 +1101,12 @@
mdp4_dsi_cmd_pipe_queue(0, pipe);
}
- if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
-
- if (mfd->use_ov0_blt)
- mdp4_dsi_cmd_do_blt(mfd, 1);
- else
- mdp4_dsi_cmd_do_blt(mfd, 0);
-
- mfd->ov0_blt_state = mfd->use_ov0_blt;
- }
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_dsi_cmd_pipe_commit();
mdp4_dsi_cmd_wait4vsync(0, &xx);
vctrl->expire_tick = VSYNC_EXPIRE_TICK;
vctrl->clk_control = 1;
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 851a9ad..40ffac4 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -122,9 +122,6 @@
return;
}
- /* start timing generator & mmu if they are not started yet */
- mdp4_overlay_dsi_video_start();
-
vctrl = &vsync_ctrl_db[cndx];
if (atomic_read(&vctrl->suspend) > 0)
@@ -196,6 +193,8 @@
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
if (vctrl->blt_change) {
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -209,6 +208,7 @@
}
pipe = vp->plist;
+
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
if (pipe->pipe_used) {
cnt++;
@@ -224,6 +224,9 @@
mdp4_mixer_stage_commit(mixer);
+ /* start timing generator & mmu if they are not started yet */
+ mdp4_overlay_dsi_video_start();
+
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
@@ -539,6 +542,8 @@
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
atomic_set(&vctrl->suspend, 0);
mdp4_overlay_dmap_xy(pipe); /* dma_p */
@@ -548,8 +553,7 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/*
* DSI timing setting
*/
@@ -769,6 +773,8 @@
mdp4_mixer_stage_up(pipe);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
+
mb();
}
@@ -820,13 +826,6 @@
MDP_OUTP(MDP_BASE + 0x90008, addr);
}
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd)
-{
- /* change mdp clk while mdp is idle */
- mdp4_set_perf_level();
-}
-
-
/*
* mdp4_primary_vsync_dsi_video: called from isr
*/
@@ -928,8 +927,6 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
-
if (mfd->ov0_wb_buf->write_addr == 0) {
pr_info("%s: no blt_base assigned\n", __func__);
return;
@@ -1011,15 +1008,7 @@
mdp4_dsi_video_pipe_queue(0, pipe);
}
- if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
-
- if (mfd->use_ov0_blt)
- mdp4_dsi_video_do_blt(mfd, 1);
- else
- mdp4_dsi_video_do_blt(mfd, 0);
-
- mfd->ov0_blt_state = mfd->use_ov0_blt;
- }
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_dsi_video_pipe_commit();
@@ -1027,5 +1016,7 @@
mdp4_dsi_video_wait4ov(0);
else
mdp4_dsi_video_wait4dmap(0);
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index d0d4f40..128a3c6 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -141,9 +141,6 @@
return;
}
- /* start timing generator & mmu if they are not started yet */
- mdp4_overlay_dtv_start();
-
vctrl = &vsync_ctrl_db[cndx];
if (atomic_read(&vctrl->suspend) > 0)
@@ -210,6 +207,9 @@
}
mdp4_mixer_stage_commit(mixer);
+ /* start timing generator & mmu if they are not started yet */
+ mdp4_overlay_dtv_start();
+
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
@@ -647,8 +647,7 @@
void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd)
{
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
+
}
static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
@@ -701,12 +700,16 @@
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
+ pipe->dst_h = fbi->var.yres;
+ pipe->dst_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->srcp0_ystride = fbi->fix.line_length;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
ret = mdp4_overlay_format2pipe(pipe);
if (ret < 0)
pr_warn("%s: format2type failed\n", __func__);
@@ -721,7 +724,7 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
vctrl->base_pipe = pipe; /* keep it */
}
@@ -838,6 +841,7 @@
} else {
mdp4_overlay_dma_commit(MDP4_MIXER1);
}
+
vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
spin_unlock(&vctrl->spin_lock);
}
@@ -894,6 +898,7 @@
MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
mdp4_overlay_reg_flush(vctrl->base_pipe, 1);
mdp4_mixer_stage_up(vctrl->base_pipe);
+ mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index feba8b8..4a478cd 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -128,9 +128,6 @@
return;
}
- /* start timing generator & mmu if they are not started yet */
- mdp4_overlay_lcdc_start();
-
vctrl = &vsync_ctrl_db[cndx];
if (atomic_read(&vctrl->suspend) > 0)
@@ -201,6 +198,8 @@
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
if (vctrl->blt_change) {
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -229,6 +228,9 @@
mdp4_mixer_stage_commit(mixer);
+ /* start timing generator & mmu if they are not started yet */
+ mdp4_overlay_lcdc_start();
+
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
@@ -513,6 +515,8 @@
pipe->srcp0_ystride = fbi->fix.line_length;
pipe->bpp = bpp;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
atomic_set(&vctrl->suspend, 0);
mdp4_overlay_dmap_xy(pipe);
@@ -714,12 +718,6 @@
MDP_OUTP(MDP_BASE + 0x90008, addr);
}
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd)
-{
- /* change mdp clk while mdp is idle */
- mdp4_set_perf_level();
-}
-
/*
* mdp4_primary_vsync_lcdc: called from isr
*/
@@ -900,15 +898,7 @@
mdp4_lcdc_pipe_queue(0, pipe);
}
- if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
-
- if (mfd->use_ov0_blt)
- mdp4_lcdc_do_blt(mfd, 1);
- else
- mdp4_lcdc_do_blt(mfd, 0);
-
- mfd->ov0_blt_state = mfd->use_ov0_blt;
- }
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_lcdc_pipe_commit();
@@ -916,4 +906,6 @@
mdp4_lcdc_wait4ov(0);
else
mdp4_lcdc_wait4dmap(0);
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 103419e..e6ff9ef 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -243,7 +243,7 @@
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 0);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
mdp4_mddi_vsync_enable(mfd, pipe, 0);
/* MDP cmd block disable */
@@ -574,8 +574,6 @@
struct mdp4_overlay_pipe *pipe)
{
unsigned long flag;
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
mdp_enable_irq(MDP_OVERLAY0_TERM);
spin_lock_irqsave(&mdp_spin_lock, flag);
@@ -660,9 +658,6 @@
void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
-
mdp_enable_irq(MDP_DMA_S_TERM);
if (mddi_pipe->ov_blt_addr == 0)
@@ -698,9 +693,10 @@
if (mddi_pipe && mddi_pipe->ov_blt_addr)
mdp4_mddi_blt_dmap_busy_wait(mfd);
-
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
mdp4_overlay_update_lcd(mfd);
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
if (mdp_hw_revision < MDP4_REVISION_V2_1) {
/* dmas dmap switch */
if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num)
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 9c06992..940aea8 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -174,6 +174,8 @@
pipe->dst_y = 0;
pipe->dst_x = 0;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
if (mfd->display_iova)
pipe->srcp0_addr = mfd->display_iova + buf_offset;
else
@@ -182,7 +184,7 @@
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index e76b8ba..ca73a70 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -249,7 +249,7 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
+ mdp_bus_scale_update_request(5);
#ifdef MDP4_ERROR
/*
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 2f0a1f5..bc64d2e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -304,7 +304,7 @@
itp.h_back_porch = pinfo->lcdc.h_back_porch;
itp.h_front_porch = pinfo->lcdc.h_front_porch;
itp.v_back_porch = pinfo->lcdc.v_back_porch;
- itp.v_front_porch = pinfo->lcdc.h_front_porch;
+ itp.v_front_porch = pinfo->lcdc.v_front_porch;
itp.hsync_pulse_width = pinfo->lcdc.h_pulse_width;
itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index efe6160..ae5acf4 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -184,8 +184,6 @@
u32 ov_start;
u32 mem_hid;
u32 mdp_rev;
- u32 use_ov0_blt, ov0_blt_state;
- u32 use_ov1_blt, ov1_blt_state;
u32 writeback_state;
bool writeback_active_cnt;
int cont_splash_done;
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 7769950..c953613 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -112,7 +112,7 @@
#define EVENT_LAST_ID 0x08AD
#define MSG_SSID_0 0
-#define MSG_SSID_0_LAST 91
+#define MSG_SSID_0_LAST 93
#define MSG_SSID_1 500
#define MSG_SSID_1_LAST 506
#define MSG_SSID_2 1000
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index f1e2527..771cb35 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -154,6 +154,14 @@
return desc->status_use_accessors & IRQ_NO_BALANCING_MASK;
}
+static inline int irq_is_per_cpu(unsigned int irq)
+{
+ struct irq_desc *desc;
+
+ desc = irq_to_desc(irq);
+ return desc->status_use_accessors & IRQ_PER_CPU;
+}
+
static inline void
irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class)
{
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index bbd032d..d1438d1 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -116,7 +116,8 @@
* @r_sense: sense resistor value in (mOhms)
* @i_test: current at which the unusable charger cutoff is to be
* calculated or the peak system current (mA)
- * @v_failure: the voltage at which the battery is considered empty(mV)
+ * @v_cutoff: the loaded voltage at which the battery
+ * is considered empty(mV)
* @enable_fcc_learning: if set the driver will learn full charge
* capacity of the battery upon end of charge
*/
@@ -125,10 +126,13 @@
enum battery_type battery_type;
unsigned int r_sense;
unsigned int i_test;
- unsigned int v_failure;
+ unsigned int v_cutoff;
unsigned int max_voltage_uv;
unsigned int rconn_mohm;
int enable_fcc_learning;
+ int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int adjust_soc_low_threshold;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index b00e050..6bd4cb2 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -281,6 +281,13 @@
*
*/
int pm8921_usb_ovp_disable(int disable);
+/**
+ * pm8921_is_batfet_closed - battery fet status
+ *
+ * Returns 1 if batfet is closed 0 if open. On configurations without
+ * batfet this will return 0.
+ */
+int pm8921_is_batfet_closed(void);
#else
static inline void pm8921_charger_vbus_draw(unsigned int mA)
{
@@ -353,6 +360,10 @@
{
return -ENXIO;
}
+static inline int pm8921_is_batfet_closed(void)
+{
+ return 1;
+}
#endif
#endif
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index 1f85952..eb1c3fd 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -23,5 +23,6 @@
* success and error on failure.
*/
int __init krait_power_init(void);
+void secondary_cpu_hs_init(void *base_ptr);
#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6a0259d..6fcafa8 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -282,8 +282,10 @@
struct winsize winsize; /* termios mutex */
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
unsigned char low_latency:1, warned:1;
+ unsigned char update_room_in_ldisc:1;
unsigned char ctrl_status; /* ctrl_lock */
unsigned int receive_room; /* Bytes free for queue */
+ unsigned int rr_bug;
struct tty_struct *link;
struct fasync_struct *fasync;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e731f97..ffa542f 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -268,6 +268,7 @@
* @otg: USB OTG Transceiver structure.
* @pdata: otg device platform data.
* @irq: IRQ number assigned for HSUSB controller.
+ * @async_irq: IRQ number used by some controllers during low power state
* @clk: clock struct of alt_core_clk.
* @pclk: clock struct of iface_clk.
* @phy_reset_clk: clock struct of phy_clk.
@@ -276,7 +277,7 @@
* @inputs: OTG state machine inputs(Id, SessValid etc).
* @sm_work: OTG state machine work.
* @in_lpm: indicates low power mode (LPM) state.
- * @async_int: Async interrupt arrived.
+ * @async_int: IRQ line on which ASYNC interrupt arrived in LPM.
* @cur_power: The amount of mA available from downstream port.
* @chg_work: Charger detection work.
* @chg_state: The state of charger detection process.
@@ -298,6 +299,7 @@
struct usb_phy phy;
struct msm_otg_platform_data *pdata;
int irq;
+ int async_irq;
struct clk *clk;
struct clk *pclk;
struct clk *phy_reset_clk;
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index baa6a28..2efe31c 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -44,6 +44,7 @@
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc);
int msm_vidc_poll(void *instance, struct file *filp,
struct poll_table_struct *pt);
#endif
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index f4f55fa..32565bc 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -38,6 +38,8 @@
#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
+#define ADC_DMIC_SEL_ADC 0
+#define ADC_DMIC_SEL_DMIC 1
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
@@ -812,17 +814,106 @@
static const struct snd_kcontrol_new sb_tx1_mux =
SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *w = wlist->widgets[0];
+ struct snd_soc_codec *codec = w->codec;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int dec_mux, decimator;
+ char *dec_name = NULL;
+ char *widget_name = NULL;
+ char *temp;
+ u16 tx_mux_ctl_reg;
+ u8 adc_dmic_sel = 0x0;
+ int ret = 0;
+
+ if (ucontrol->value.enumerated.item[0] > e->max - 1)
+ return -EINVAL;
+
+ dec_mux = ucontrol->value.enumerated.item[0];
+
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+ temp = widget_name;
+
+ dec_name = strsep(&widget_name, " ");
+ widget_name = temp;
+ if (!dec_name) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
+ if (ret < 0) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
+ "dec_mux = %u\n", __func__, w->name, dec_name, decimator,
+ dec_mux);
+
+
+ switch (decimator) {
+ case 1:
+ case 2:
+ if ((dec_mux == 1) || (dec_mux == 6))
+ adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+ else
+ adc_dmic_sel = ADC_DMIC_SEL_ADC;
+ break;
+ case 3:
+ if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
+ adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+ else
+ adc_dmic_sel = ADC_DMIC_SEL_ADC;
+ break;
+ case 4:
+ if ((dec_mux == 1) || (dec_mux == 5)
+ || (dec_mux == 6) || (dec_mux == 7))
+ adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+ else
+ adc_dmic_sel = ADC_DMIC_SEL_ADC;
+ break;
+ default:
+ pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+out:
+ kfree(widget_name);
+ return ret;
+}
+
+#define WCD9304_DEC_ENUM(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_double, \
+ .put = wcd9304_put_dec_enum, \
+ .private_value = (unsigned long)&xenum }
+
static const struct snd_kcontrol_new dec1_mux =
- SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+ WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
static const struct snd_kcontrol_new dec2_mux =
- SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+ WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
static const struct snd_kcontrol_new dec3_mux =
- SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+ WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
static const struct snd_kcontrol_new dec4_mux =
- SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+ WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
static const struct snd_kcontrol_new iir1_inp1_mux =
SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
@@ -970,7 +1061,7 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- u16 tx_dmic_ctl_reg, tx_mux_ctl_reg;
+ u16 tx_dmic_ctl_reg;
u8 dmic_clk_sel, dmic_clk_en;
unsigned int dmic;
int ret;
@@ -1000,15 +1091,12 @@
return -EINVAL;
}
- tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
pr_debug("%s %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x01);
-
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
dmic_clk_sel, dmic_clk_sel);
@@ -1020,8 +1108,6 @@
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
dmic_clk_en, 0);
-
- snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x00);
break;
}
return 0;
@@ -1573,10 +1659,22 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x30, 0x20);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x0C, 0x08);
+ }
snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x30, 0x10);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x0C, 0x04);
+ }
break;
}
return 0;
@@ -2018,13 +2116,16 @@
{"HEADPHONE", NULL, "HPHL"},
{"HEADPHONE", NULL, "HPHR"},
+
{"HPHL DAC", NULL, "CP"},
{"HPHR DAC", NULL, "CP"},
{"HPHL", NULL, "HPHL DAC"},
- {"HPHL DAC", "NULL", "DAC4 MUX"},
+ {"HPHL DAC", "NULL", "RX2 CHAIN"},
+ {"RX2 CHAIN", NULL, "DAC4 MUX"},
{"HPHR", NULL, "HPHR DAC"},
- {"HPHR DAC", NULL, "RX3 MIX1"},
+ {"HPHR DAC", NULL, "RX3 CHAIN"},
+ {"RX3 CHAIN", NULL, "RX3 MIX1"},
{"DAC1 MUX", "RX1", "RX1 CHAIN"},
{"DAC2 MUX", "RX1", "RX1 CHAIN"},
@@ -2459,19 +2560,6 @@
return 0;
}
-static void sitar_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
- if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
- (wcd9xxx->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
- pm_runtime_put(wcd9xxx->dev->parent);
- }
- pr_debug("%s(): substream = %s stream = %d\n" , __func__,
- substream->name, substream->stream);
-}
-
int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
@@ -2767,7 +2855,6 @@
static struct snd_soc_dai_ops sitar_dai_ops = {
.startup = sitar_startup,
- .shutdown = sitar_shutdown,
.hw_params = sitar_hw_params,
.set_sysclk = sitar_set_dai_sysclk,
.set_fmt = sitar_set_dai_fmt,
@@ -2872,6 +2959,15 @@
return ret;
}
+static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
+{
+ if (sitar->dev != NULL &&
+ sitar->dev->parent != NULL) {
+ pm_runtime_mark_last_busy(sitar->dev->parent);
+ pm_runtime_put(sitar->dev->parent);
+ }
+}
+
static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -2881,9 +2977,14 @@
u32 j = 0, ret = 0;
codec->control_data = dev_get_drvdata(codec->dev->parent);
sitar = codec->control_data;
+
/* Execute the callback only if interface type is slimbus */
- if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+ sitar_codec_pm_runtime_put(sitar);
return 0;
+ }
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2922,6 +3023,8 @@
sitar_p->dai[j].ch_tot));
sitar_p->dai[j].ch_tot = 0;
ret = sitar_codec_enable_chmask(sitar_p, event, j);
+ if (sitar != NULL)
+ sitar_codec_pm_runtime_put(sitar);
}
}
return ret;
@@ -2940,8 +3043,12 @@
sitar = codec->control_data;
/* Execute the callback only if interface type is slimbus */
- if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+ sitar_codec_pm_runtime_put(sitar);
return 0;
+ }
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2980,6 +3087,8 @@
sitar_p->dai[j].ch_tot));
sitar_p->dai[j].ch_tot = 0;
ret = sitar_codec_enable_chmask(sitar_p, event, j);
+ if (sitar != NULL)
+ sitar_codec_pm_runtime_put(sitar);
}
}
return ret;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 3516022..f50b915 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -837,6 +837,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
},
+ /* Hostless PCM purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
{
.name = "MSM8974 Compr",
.stream_name = "COMPR",
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 756cb18..2e58e1b 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -586,25 +586,23 @@
sizeof(lb_cmd) - APR_HDR_SIZE);
lb_cmd.hdr.src_port = 0;
lb_cmd.hdr.dest_port = 0;
- lb_cmd.hdr.token = 0;
+ lb_cmd.hdr.token = index;
lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
lb_cmd.param.port_id = tx_port;
- lb_cmd.param.payload_size = (sizeof(lb_cmd) -
- sizeof(struct apr_hdr) -
- sizeof(struct afe_port_cmd_set_param_v2));
+ lb_cmd.param.payload_size = (sizeof(lb_cmd) - sizeof(struct apr_hdr) -
+ sizeof(struct afe_port_cmd_set_param_v2));
lb_cmd.param.payload_address_lsw = 0x00;
lb_cmd.param.payload_address_msw = 0x00;
lb_cmd.param.mem_map_handle = 0x00;
lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
- lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
- sizeof(struct afe_port_param_data_v2);
+ lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
+ sizeof(struct afe_port_param_data_v2);
lb_cmd.dst_port_id = rx_port;
lb_cmd.routing_mode = LB_MODE_DEFAULT;
lb_cmd.enable = (enable ? 1 : 0);
- lb_cmd.loopback_cfg_minor_version =
- AFE_API_VERSION_LOOPBACK_CONFIG;
+ lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
@@ -613,9 +611,10 @@
ret = -EINVAL;
goto done;
}
+ pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
@@ -667,26 +666,24 @@
set_param.hdr.pkt_size = sizeof(set_param);
set_param.hdr.src_port = 0;
set_param.hdr.dest_port = 0;
- set_param.hdr.token = 0;
+ set_param.hdr.token = index;
set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
- set_param.param.port_id = port_id;
- set_param.param.payload_size =
- (sizeof(struct afe_loopback_gain_per_path_param) -
- sizeof(struct apr_hdr) -
- sizeof(struct afe_port_cmd_set_param_v2));
+ set_param.param.port_id = port_id;
+ set_param.param.payload_size =
+ (sizeof(struct afe_loopback_gain_per_path_param) -
+ sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2));
set_param.param.payload_address_lsw = 0;
set_param.param.payload_address_msw = 0;
set_param.param.mem_map_handle = 0;
- set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
- set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
- set_param.pdata.param_size = (set_param.param.payload_size -
- sizeof(struct afe_port_param_data_v2));
+ set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
+ set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+ set_param.pdata.param_size =
+ (set_param.param.payload_size -
+ sizeof(struct afe_port_param_data_v2));
set_param.rx_port_id = port_id;
- set_param.gain = volume;
-
- set_param.hdr.token = index;
+ set_param.gain = volume;
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
@@ -698,8 +695,8 @@
}
ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
if (ret < 0) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;