Merge "input: synaptics_i2c_rmi4: Reinitialize list after freeing it"
diff --git a/Documentation/csdio.txt b/Documentation/csdio.txt
deleted file mode 100644
index 22d5e35..0000000
--- a/Documentation/csdio.txt
+++ /dev/null
@@ -1,189 +0,0 @@
-Introduction
-============
-The Char SDIO Device Driver is an interface which exposes an SDIO
-card/function from kernel space as a char device in user space.
-
-The driver doesn't interact with any HW directly. It relies on SDIO
-card/function interface provided as a part of Linux kernel.
-
-Hardware description
-====================
-Each SDIO device/card contains an SDIO client HW block.
-The host interacts with the device by sending byte sequences called
-command (CMD). Some commands can be followed by data blocks. The
-device sends back a byte sequence called response (R) and a data
-block if required. CMD3, CMD5 and CMD7 are used to initialize the
-device. CMD52 and CMD53 are used to access the device. Command
-format and properties are defined by SDIO Specification document
-published by SD Association:
- http://www.sdcard.org/developers/tech/sdio/.
-
-CMD52 and CMD53 can access up to 8 address spaces called Functions.
-Function 0 contains system information predefined by SD/SDIO
-standard and Functions 1-7 are defined by the SDIO device
-manufacturer.
-
-An SDIO device/card can send an interrupt to SDIO host. This
-interrupt is intercepted and handled by SDIO host.
-
-Software description
-====================
-Linux provides a framework for handling SDIO devices. It implements
-kind of plug-and-play model in which the Linux SDIO Host Driver is
-responsible for initializing an SDIO device upon insertion. It also
-reads device/card identification information and enumerates functions
-provided by the device and then looks up in the list of
-preregistered user SDIO drivers for a suitable one.
-
-During its lifecycle the user SDIO driver interacts with the Linux
-SDIO Host Driver in order to send/receive information to/from SDIO
-device/card. The user SDIO driver doesn't work with CMD52/CMD53
-directly. Instead it uses an abstraction provided by the Linux SDIO
-Host Driver.
-
-The Linux SDIO Host Driver is also in charge of handling SDIO
-interrupts. User SDIO driver can register its own callback in SDIO
-Host Driver and get a notification about interrupt event.
-
-The Char SDIO Device Driver follows the design guidelines mentioned
-above. It provides the following functionality:
-
- - Register itself in the user SDIO drivers list;
- - Handle Probe event upon insertion of supported card/device;
- - Creates and maintains a char device driver for each SDIO Function
- found in the card/device;
- - Translates read/write/ioctl calls to appropriate SDIO call
- sequences;
-
-In order to handle general SDIO configuration functionality and
-Function 0 the Char SDIO Device Driver provides additional
-simplified char device driver.
-
-The Manufacturer and Device IDs of handled SDIO device should be
-provided as parameters for kernel module or as configuration
-parameters in case of statically linked driver.
-
-Design
-======
-The main goal of the Char SDIO Device Driver is to expose an SDIO
-card/device from kernel space to user space as a char device driver.
-The driver should be generic and simple as far as possible.
-
-The biggest design tradeoff is maintaining a balance between the
-system call overhead required to initiate an SDIO transaction from
-user space and overall SDIO communication performance. But luckily,
-because of nature of SDIO protocol, this overhead is negligible
-comparing to time required to execute SDIO transaction itself. So,
-each CMD52 (read or write) consists from single ioctl system call.
-And each CMD53 invokes single ioctl system call followed by read or
-write system call.
-
-The Char SDIO Device Driver registers its own class of the devices
-called 'csdio'. This class will serve as a common roof for all SDIO
-devices served by different instances of the Char SDIO Device Driver.
-Additional benefit from maintaining its own class is the driver
-ability to overwrite default permissions of the dev nodes created by
-the driver.
-
-Power Management
-================
-None
-
-SMP/multi-core
-==============
-The driver does not anticipate any issues related to multi-core
-since it is expected to run on one core only.
-
-Security
-========
-None
-
-Performance
-===========
-None
-
-Interface
-=========
-The Char SDIO Device Driver has two char device interfaces:
- - Control Interface;
- - Function Interface.
-
-Char SDIO Device Driver Control Interface consists of:
- - open() - device node is /dev/csdio0;
- - close()
- - ioctl() - the following options are available:
- - CSDIO_IOC_ENABLE_HIGHSPEED_MODE;
- - CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS;
- - CSDIO_IOC_ENABLE_ISR;
- - CSDIO_IOC_DISABLE_ISR.
-
-Char SDIO Device Driver Function Interface consists of:
- - open() - device node is /dev/csdiofX, where X is Function Id;
- - close()
- - read() - send CMD53 read;
- - write() - send CMD53 write;
- - ioctl() - the following options are available:
- - CSDIO_IOC_SET_OP_CODE - 0 fixed adrress, 1 autoincrement.
- - CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE;
- - CSDIO_IOC_SET_BLOCK_MODE - 0 byte mode, 1 block mode;
- - CSDIO_IOC_CMD52 - execute CMD52, receives the
- following structure as a parameter:
- struct csdio_cmd52_ctrl_t {
- uint32_t m_write; // 0 - read, 1 -write
- uint32_t m_address;
- uint32_t m_data; // data to write or read data
- uint32_t m_ret; // command execution status
- }__attribute__ ((packed));
- - CSDIO_IOC_CMD53 - setup CMD53 data transfer, receives the
- following structure as a parameter:
- struct csdio_cmd53_ctrl_t {
- uint32_t m_block_mode;
- uint32_t m_op_code;
- uint32_t m_address;
- }__attribute__ ((packed));
- - CSDIO_IOC_CONNECT_ISR;
- - CSDIO_IOC_DISCONNECT_ISR;
- - CSDIO_IOC_GET_VDD;
- - CSDIO_IOC_SET_VDD.
-
-Additionally, user space application can use fcntl system call with
-parameters F_SETOWN and F_SETFL in order to set an asynchronous
-callback for SDIO interrupt.
-
-Driver parameters
-=================
-If the driver is compiled as a kernel module, the following
-parameters can be used in order to provide Manufacturer and Device IDs
-upon module download:
- - csdio_vendor_id;
- - csdio_device_id.
-If the driver is intended to work with specific SDIO host the
-host_name parameter should be added followed by the name of the MMC
-host platform device.
-
-Config options
-==============
-These are the kernel configuration options:
- - CONFIG_CSDIO_VENDOR_ID;
- - CONFIG_CSDIO_DEVICE_ID.
-
-Dependencies
-============
-The Char SDIO Device Driver depends on Linux SDIO Host Driver.
-
-User space utilities
-====================
-None
-
-Other
-=====
-None
-
-Known issues
-============
-None
-
-To do
-=====
-Provide mechanism to support a number of SDIO devices simultaneously
-connected to different SDIO hosts.
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 99de826..f724e60 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -198,16 +198,6 @@
- qti,cpr-uplift-speed-bin: The speed bin value corresponding to one type of processor which needs to apply the
pvs voltage uplift workaround.
This is required if cpr-fuse-uplift-disable-sel is present.
-- qti,cpr-quot-adjust-table: Array of 4-tuples in which each 4-tuple indicates the speed bin
- of the CPU, the frequency of the CPU, the quotient adjustment and the voltage corner to use.
- The 4 elements in one 4-tuple are:
- [0]: => the speed bin of the CPU;
- [1]: => the frequency in kHz of the CPU;
- [2]: => the quotient adjustment of the corresponding frequency;
- [3]: => the voltage corner to use.
- If the speed bin in a tuple is eqaul to the speed bin of the CPU, then the quotient
- adjustment would be subtracted from the quotient value of the voltage corner
- when the CPU is running at that frequency.
Example:
apc_vreg_corner: regulator@f9018000 {
@@ -270,9 +260,5 @@
qti,cpr-uplift-max-volt = <1350000>;
qti,cpr-uplift-speed-bin = <1>;
qti,speed-bin-fuse-sel = <22 0 3 0>;
- qti,cpr-quot-adjust-table = <1 998400 450 3>,
- <1 1094400 375 3>, <1 1190400 300 3>,
- <1 1305600 225 3>, <1 1344000 187 3>,
- <1 1401600 150 3>, <1 1497600 75 3>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index a77b5ff..6277054 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -4,23 +4,29 @@
Required properties:
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
* msm-pcm-low-latency
Required properties:
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
Optional properties
- - qcom,msm-pcm-low-latency : Flag indicating whether
+ - qti,msm-pcm-low-latency : Flag indicating whether
the device node is of type low latency.
+ - qti,latency-level : Flag indicating whether the device node
+ is of type regular low latency or ultra
+ low latency.
+ regular : regular low latency stream
+ ultra : ultra low latency stream
+
* msm-pcm-routing
Required properties:
@@ -226,16 +232,16 @@
Example:
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
- };
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ };
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 63da606..7db913a 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -91,13 +91,6 @@
qti,cpr-uplift-max-volt = <1350000>;
qti,cpr-uplift-speed-bin = <1>;
qti,speed-bin-fuse-sel = <22 0 3 0>;
- qti,cpr-quot-adjust-table = <1 300000 0 1>,
- <1 384000 0 1>, <1 600000 0 2>,
- <1 787200 0 2>, <1 998400 450 3>,
- <1 1094400 375 3>, <1 1190400 300 3>,
- <1 1305600 225 3>, <1 1344000 187 3>,
- <1 1401600 150 3>, <1 1497600 75 3>,
- <1 1593600 0 3>;
};
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index fc00411..baa81cc 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -429,19 +429,20 @@
qcom,tapan-codec-9302;
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "regular";
};
qcom,msm-pcm-lpa {
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 94a9db0..03ef738 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -615,15 +615,16 @@
qcom,model = "msm8x10-snd-card";
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "ultra";
};
qcom,msm-pcm-routing {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b4a3e55..a912da8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1628,15 +1628,16 @@
compatible = "qcom,msm-audio-ion";
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
- qcom,msm-pcm-low-latency {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <1>;
- qcom,msm-pcm-low-latency;
+ qti,msm-pcm-low-latency {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <1>;
+ qti,msm-pcm-low-latency;
+ qti,latency-level = "regular";
};
qcom,msm-pcm-routing {
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index fa313bf..6b62391 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -22,5 +22,5 @@
};
&sdhc_1 {
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 938a2cc..63cb68b 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -214,6 +214,9 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 18>, /* APCx_qgicQTmrSecPhysIrptReq */
+ <0xff 19>, /* APCx_qgicQTmrSecPhysIrptReq */
+ <0xff 25>, /* APCx_qgicExtFaultIrptReq */
<0xff 33>, /*l2_perf_mon*/
<0xff 34>, /* APCC_qgicL2ErrorIrptReq */
<0xff 35>, /* WDT_barkInt */
@@ -237,7 +240,10 @@
<0xff 105>, /* iommu_pmon_nonsecure_irq */
<0xff 109>, /* ocmem_dm_nonsec_irq */
<0xff 126>, /* bam_irq[0] */
+ <0xff 140>, /* uart_dm_intr */
<0xff 155>, /* sdcc_irq[0] */
+ <0xff 157>, /* sdcc_irq[0] */
+ <0xff 159>, /* sdcc_irq[0] */
<0xff 163>, /* usb30_ee1_irq */
<0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
@@ -270,6 +276,8 @@
<0xff 207>, /* rpm_ipc(27) */
<0xff 211>, /* usb_dwc3_otg */
<0xff 240>, /* summary_irq_kpss */
+ <0xff 253>, /* sdcc_pwr_cmd_irq */
+ <0xff 256>, /* sdcc_pwr_cmd_irq */
<0xff 268>, /* bam_irq[1] */
<0xff 270>, /* bam_irq[0] */
<0xff 271>; /* bam_irq[0] */
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 2c06c3c..2783ffd 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -60,6 +60,10 @@
vdd_cx-supply = <&pm8841_s2_corner>;
};
+&pm8841_s2_corner {
+ qcom,init-smps-mode = <0>; /* Allow AUTO mode for VDD_CX. */
+};
+
&krait_regulator_pmic {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index 71fbeae..c06ebf8 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -191,6 +191,10 @@
vdd_cx-supply = <&pma8084_s2_corner>;
};
+&pma8084_s2_corner {
+ qcom,init-smps-mode = <0>; /* Allow AUTO mode for VDD_CX. */
+};
+
&krait_regulator_pmic {
status = "ok";
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 0e7baf1..dee1f68 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -686,9 +686,9 @@
qcom,adsp-state = <2>;
};
- qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
- qcom,msm-pcm-dsp-id = <0>;
+ qti,msm-pcm {
+ compatible = "qti,msm-pcm-dsp";
+ qti,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 1cf2e41..9ee7333 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -25,7 +25,6 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <linux/cpufreq.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/cpr-regulator.h>
@@ -133,13 +132,6 @@
#define FLAGS_SET_MIN_VOLTAGE BIT(1)
#define FLAGS_UPLIFT_QUOT_VOLT BIT(2)
-#define FLAGS_QUOT_ADJUST_WITH_FREQ BIT(3)
-
-struct cpufreq_mapping_info {
- int freq;
- int quot_adjust;
- int corner;
-};
enum voltage_change_dir {
NO_CHANGE,
@@ -179,7 +171,6 @@
bool cpr_fuse_disable;
bool cpr_fuse_local;
int cpr_fuse_target_quot[CPR_CORNER_MAX];
- int cpr_fuse_original_quot[CPR_CORNER_MAX];
int cpr_fuse_ro_sel[CPR_CORNER_MAX];
int gcnt;
@@ -214,10 +205,6 @@
u32 vdd_apc_step_up_limit;
u32 vdd_apc_step_down_limit;
u32 flags;
- struct notifier_block freq_transition;
- unsigned int freq;
- struct cpufreq_mapping_info *cpufreq_mapping;
- u32 cpufreq_mapping_size;
};
#define CPR_DEBUG_MASK_IRQ BIT(0)
@@ -280,28 +267,6 @@
return efuse_bits;
}
-static int cpr_get_freq_corner(struct cpr_regulator *cpr_vreg, int freq)
-{
- int i;
-
- for (i = 0; i < cpr_vreg->cpufreq_mapping_size; i++) {
- if (freq == cpr_vreg->cpufreq_mapping[i].freq)
- return cpr_vreg->cpufreq_mapping[i].corner;
- }
-
- return -EINVAL;
-}
-
-static int cpr_get_freq_quot_adjust(struct cpr_regulator *cpr_vreg, int freq)
-{
- int i;
-
- for (i = 0; i < cpr_vreg->cpufreq_mapping_size; i++) {
- if (freq == cpr_vreg->cpufreq_mapping[i].freq)
- return cpr_vreg->cpufreq_mapping[i].quot_adjust;
- }
- return 0;
-}
static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
{
@@ -376,13 +341,6 @@
cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
}
-static bool cpr_ctl_is_enabled(struct cpr_regulator *cpr_vreg)
-{
- u32 val;
- val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- return ((val & RBCPR_CTL_LOOP_EN) == RBCPR_CTL_LOOP_EN);
-}
-
static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
{
int i, offset;
@@ -415,13 +373,6 @@
static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
{
u32 gcnt, ctl, irq, ro_sel;
- int adjust;
-
- if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ) {
- adjust = cpr_get_freq_quot_adjust(cpr_vreg, cpr_vreg->freq);
- cpr_vreg->cpr_fuse_target_quot[corner] =
- cpr_vreg->cpr_fuse_original_quot[corner] - adjust;
- }
ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
@@ -1250,78 +1201,6 @@
return rc;
}
-static int cpr_get_of_cprfreq_mappings(struct cpr_regulator *cpr_vreg,
- struct device *dev)
-{
- int rc = 0;
- int i, j, size, stripe_size, length;
- struct property *prop;
- u32 *tmp;
-
- prop = of_find_property(dev->of_node, "qti,cpr-quot-adjust-table",
- NULL);
- if (prop) {
- size = prop->length / sizeof(u32);
- tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- rc = of_property_read_u32_array(dev->of_node,
- "qti,cpr-quot-adjust-table", tmp, size);
- if (rc) {
- pr_err("qti,cpr-quot-adjust-table missing, rc = %d",
- rc);
- kfree(tmp);
- return rc;
- }
-
- length = 0;
- stripe_size = 1 + sizeof(struct cpufreq_mapping_info) /
- sizeof(int);
- for (i = 0; i < size; i += stripe_size) {
- if (tmp[i] == cpr_vreg->speed_bin)
- length++;
- }
- if (i != size) {
- pr_err("qti,cpr-quot-adjust-table data is not correct\n");
- kfree(tmp);
- return -EINVAL;
- }
-
- cpr_vreg->cpufreq_mapping_size = length;
- if (length) {
- cpr_vreg->cpufreq_mapping = devm_kzalloc(dev,
- sizeof(struct cpufreq_mapping_info) * length,
- GFP_KERNEL);
-
- if (!cpr_vreg->cpufreq_mapping) {
- kfree(tmp);
- return -ENOMEM;
- }
-
- cpr_vreg->flags |= FLAGS_QUOT_ADJUST_WITH_FREQ;
-
- for (i = 0, j = 0; i < size; i += stripe_size) {
- if (tmp[i] == cpr_vreg->speed_bin) {
- cpr_vreg->cpufreq_mapping[j].freq =
- tmp[i+1];
- cpr_vreg->cpufreq_mapping[j].quot_adjust
- = tmp[i+2];
- cpr_vreg->cpufreq_mapping[j].corner =
- tmp[i+3];
- ++j;
- }
-
- }
-
- }
-
- kfree(tmp);
- }
-
- return rc;
-}
-
static int __devinit cpr_init_cpr_efuse(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
@@ -1451,15 +1330,6 @@
}
}
- for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
- cpr_vreg->cpr_fuse_original_quot[i] =
- cpr_vreg->cpr_fuse_target_quot[i];
- }
-
- rc = cpr_get_of_cprfreq_mappings(cpr_vreg, &pdev->dev);
- if (rc)
- return rc;
-
cpr_vreg->cpr_fuse_bits = fuse_bits;
if (!cpr_vreg->cpr_fuse_bits) {
cpr_vreg->cpr_fuse_disable = 1;
@@ -1699,8 +1569,6 @@
pr_info("[row: %d]: 0x%llx, speed_bits = %d\n",
fuse_sel[0], fuse_bits, speed_bits);
cpr_vreg->speed_bin = speed_bits;
- } else {
- cpr_vreg->speed_bin = UINT_MAX;
}
}
@@ -1794,51 +1662,6 @@
return 0;
}
-static int cpr_freq_transition(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- int old_corner, new_corner;
- struct cpr_regulator *cpr_vreg = container_of(nb, struct cpr_regulator,
- freq_transition);
- struct cpufreq_freqs *freqs = data;
-
- mutex_lock(&cpr_vreg->cpr_mutex);
- switch (val) {
- case CPUFREQ_PRECHANGE:
- cpr_vreg->freq = freqs->new;
- if (freqs->new > freqs->old) {
- old_corner = cpr_get_freq_corner(cpr_vreg, freqs->old);
- new_corner = cpr_get_freq_corner(cpr_vreg, freqs->new);
- if (new_corner > 0 && old_corner == new_corner &&
- cpr_ctl_is_enabled(cpr_vreg)) {
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_clr(cpr_vreg);
- cpr_corner_restore(cpr_vreg, new_corner);
- cpr_ctl_enable(cpr_vreg, new_corner);
- }
- }
- break;
- case CPUFREQ_POSTCHANGE:
- if (freqs->new < freqs->old) {
- old_corner = cpr_get_freq_corner(cpr_vreg, freqs->old);
- new_corner = cpr_get_freq_corner(cpr_vreg, freqs->new);
- if (new_corner > 0 && old_corner == new_corner &&
- cpr_ctl_is_enabled(cpr_vreg)) {
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_clr(cpr_vreg);
- cpr_corner_restore(cpr_vreg, new_corner);
- cpr_ctl_enable(cpr_vreg, new_corner);
- }
- }
- break;
- default:
- break;
- }
- mutex_unlock(&cpr_vreg->cpr_mutex);
-
- return NOTIFY_OK;
-}
-
static int __devinit cpr_regulator_probe(struct platform_device *pdev)
{
struct cpr_regulator *cpr_vreg;
@@ -1922,10 +1745,6 @@
platform_set_drvdata(pdev, cpr_vreg);
the_cpr = cpr_vreg;
- cpr_vreg->freq_transition.notifier_call = cpr_freq_transition;
- if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ)
- cpufreq_register_notifier(&cpr_vreg->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
return 0;
@@ -1946,9 +1765,6 @@
cpr_irq_set(cpr_vreg, 0);
}
- if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ)
- cpufreq_unregister_notifier(&cpr_vreg->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
cpr_apc_exit(cpr_vreg);
regulator_unregister(cpr_vreg->rdev);
}
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
index 0a1cdd4..42cf6f9 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
@@ -45,7 +45,7 @@
};
void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id);
-void rtac_remove_adm_device(u32 port_id);
+void rtac_remove_adm_device(u32 port_id, u32 copp_id);
void rtac_remove_popp_from_adm_devices(u32 popp_id);
void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
u32 tx_afe_port, u32 session_id);
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index ce66531..6bb4011 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -434,7 +434,7 @@
unsigned int len)
{
struct sk_buff *temp;
- int offset = 0, buf_len = 0, copy_len;
+ unsigned int offset = 0, buf_len = 0, copy_len;
void *buf;
if (!skb_head) {
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index e6b1324..a18d0f3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -51,6 +51,11 @@
#define Y_IND 1
#define Z_IND 2
+/* Shared memory limits */
+/* max_buf_size = (port_size(65535*2) * port_num(8) * group_size(3) */
+#define USF_MAX_BUF_SIZE 3145680
+#define USF_MAX_BUF_NUM 32
+
/* Place for opreation result, received from QDSP6 */
#define APR_RESULT_IND 1
@@ -482,6 +487,15 @@
(config == NULL))
return -EINVAL;
+ if ((config->buf_size == 0) ||
+ (config->buf_size > USF_MAX_BUF_SIZE) ||
+ (config->buf_num == 0) ||
+ (config->buf_num > USF_MAX_BUF_NUM)) {
+ pr_err("%s: wrong params: buf_size=%d; buf_num=%d\n",
+ __func__, config->buf_size, config->buf_num);
+ return -EINVAL;
+ }
+
data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
min_map_size = min(data_map_size, config->port_cnt);
@@ -794,6 +808,7 @@
{
uint32_t timeout = 0;
struct us_detect_info_type detect_info;
+ struct usm_session_cmd_detect_info *p_allocated_memory = NULL;
struct usm_session_cmd_detect_info usm_detect_info;
struct usm_session_cmd_detect_info *p_usm_detect_info =
&usm_detect_info;
@@ -820,12 +835,13 @@
uint8_t *p_data = NULL;
detect_info_size += detect_info.params_data_size;
- p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
- if (p_usm_detect_info == NULL) {
+ p_allocated_memory = kzalloc(detect_info_size, GFP_KERNEL);
+ if (p_allocated_memory == NULL) {
pr_err("%s: detect_info[%d] allocation failed\n",
__func__, detect_info_size);
return -ENOMEM;
}
+ p_usm_detect_info = p_allocated_memory;
p_data = (uint8_t *)p_usm_detect_info +
sizeof(struct usm_session_cmd_detect_info);
@@ -835,7 +851,7 @@
if (rc) {
pr_err("%s: copy params from user; rc=%d\n",
__func__, rc);
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return -EFAULT;
}
p_usm_detect_info->algorithm_cfg_size =
@@ -852,9 +868,7 @@
p_usm_detect_info,
detect_info_size);
if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
- if (detect_info_size >
- sizeof(struct usm_session_cmd_detect_info))
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return rc;
}
@@ -874,25 +888,24 @@
USF_US_DETECT_UNDEF),
timeout);
/* In the case of timeout, "no US" is assumed */
- if (rc < 0) {
+ if (rc < 0)
pr_err("%s: Getting US detection failed rc[%d]\n",
__func__, rc);
- return rc;
+ else {
+ usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+ detect_info.is_us =
+ (usf_xx->us_detect_type == USF_US_DETECT_YES);
+ rc = copy_to_user((void __user *)arg,
+ &detect_info,
+ sizeof(detect_info));
+ if (rc) {
+ pr_err("%s: copy detect_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
}
- usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
- detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
- rc = copy_to_user((void __user *)arg,
- &detect_info,
- sizeof(detect_info));
- if (rc) {
- pr_err("%s: copy detect_info to user; rc=%d\n",
- __func__, rc);
- rc = -EFAULT;
- }
-
- if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
- kfree(p_usm_detect_info);
+ kfree(p_allocated_memory);
return rc;
} /* usf_set_us_detection */
@@ -993,16 +1006,14 @@
if (rc)
return rc;
- if (usf_xx->buffer_size && usf_xx->buffer_count) {
- rc = q6usm_us_client_buf_alloc(
- IN,
- usf_xx->usc,
- usf_xx->buffer_size,
- usf_xx->buffer_count);
- if (rc) {
- (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
- return rc;
- }
+ rc = q6usm_us_client_buf_alloc(
+ IN,
+ usf_xx->usc,
+ usf_xx->buffer_size,
+ usf_xx->buffer_count);
+ if (rc) {
+ (void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+ return rc;
}
rc = q6usm_dec_cfg_blk(usf_xx->usc,
@@ -1221,10 +1232,15 @@
return -EFAULT;
}
- /* version_info.buf is pointer to place for the version string */
+ if (version_info.buf_size < sizeof(DRV_VERSION)) {
+ pr_err("%s: buf_size (%d) < version string size (%d)\n",
+ __func__, version_info.buf_size, sizeof(DRV_VERSION));
+ return -EINVAL;
+ }
+
rc = copy_to_user(version_info.pbuf,
DRV_VERSION,
- version_info.buf_size);
+ sizeof(DRV_VERSION));
if (rc) {
pr_err("%s: copy to version_info.pbuf; rc=%d\n",
__func__, rc);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 97b1f39..a5748fb 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -658,13 +658,6 @@
applications DSP processor. Say M if you want to enable this
module.
-config MMC_GENERIC_CSDIO
- tristate "Generic sdio driver"
- default n
- help
- SDIO function driver that extends SDIO card as character device
- in user space.
-
config CSDIO_VENDOR_ID
hex "Card VendorId"
depends on MMC_GENERIC_CSDIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 7589946..292cc99 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -65,7 +65,6 @@
obj-$(CONFIG_TILE_SROM) += tile-srom.o
obj-$(CONFIG_MSM_ROTATOR) += msm_rotator.o
-obj-$(CONFIG_MMC_GENERIC_CSDIO) += csdio.o
obj-$(CONFIG_DIAG_CHAR) += diag/
obj-$(CONFIG_MSM_ADSPRPC) += adsprpc.o
obj-$(CONFIG_MSM_RDBG) += rdbg.o
diff --git a/drivers/char/csdio.c b/drivers/char/csdio.c
deleted file mode 100644
index 85306d3..0000000
--- a/drivers/char/csdio.c
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*
- * Copyright (c) 2010, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-/* Char device */
-#include <linux/cdev.h>
-#include <linux/fs.h>
-
-/* Sdio device */
-#include <linux/mmc/core.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-
-#include <linux/csdio.h>
-
-#define FALSE 0
-#define TRUE 1
-
-#define VERSION "0.5"
-#define CSDIO_NUM_OF_SDIO_FUNCTIONS 7
-#define CSDIO_DEV_NAME "csdio"
-#define TP_DEV_NAME CSDIO_DEV_NAME"f"
-#define CSDIO_DEV_PERMISSIONS 0666
-
-#define CSDIO_SDIO_BUFFER_SIZE (64*512)
-
-int csdio_major;
-int csdio_minor;
-int csdio_transport_nr_devs = CSDIO_NUM_OF_SDIO_FUNCTIONS;
-static uint csdio_vendor_id;
-static uint csdio_device_id;
-static char *host_name;
-
-static struct csdio_func_t {
- struct sdio_func *m_func;
- int m_enabled;
- struct cdev m_cdev; /* char device structure */
- struct device *m_device;
- u32 m_block_size;
-} *g_csdio_func_table[CSDIO_NUM_OF_SDIO_FUNCTIONS] = {0};
-
-struct csdio_t {
- struct cdev m_cdev;
- struct device *m_device;
- struct class *m_driver_class;
- struct fasync_struct *m_async_queue;
- unsigned char m_current_irq_mask; /* currently enabled irqs */
- struct mmc_host *m_host;
- unsigned int m_num_of_func;
-} g_csdio;
-
-struct csdio_file_descriptor {
- struct csdio_func_t *m_port;
- u32 m_block_mode;/* data tran. byte(0)/block(1) */
- u32 m_op_code; /* address auto increment flag */
- u32 m_address;
-};
-
-static void *g_sdio_buffer;
-
-/*
- * Open and release
- */
-static int csdio_transport_open(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_func_t *port = NULL; /* device information */
- struct sdio_func *func = NULL;
- struct csdio_file_descriptor *descriptor = NULL;
-
- port = container_of(inode->i_cdev, struct csdio_func_t, m_cdev);
- func = port->m_func;
- descriptor = kzalloc(sizeof(struct csdio_file_descriptor), GFP_KERNEL);
- if (!descriptor) {
- ret = -ENOMEM;
- goto exit;
- }
-
- pr_info(TP_DEV_NAME"%d: open: func=%p, port=%p\n",
- func->num, func, port);
- sdio_claim_host(func);
- ret = sdio_enable_func(func);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:Enable func failed (%d)\n",
- func->num, ret);
- ret = -EIO;
- goto free_descriptor;
- }
- descriptor->m_port = port;
- filp->private_data = descriptor;
- goto release_host;
-
-free_descriptor:
- kfree(descriptor);
-release_host:
- sdio_release_host(func);
-exit:
- return ret;
-}
-
-static int csdio_transport_release(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
-
- pr_info(TP_DEV_NAME"%d: release\n", func->num);
- sdio_claim_host(func);
- ret = sdio_disable_func(func);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:Disable func failed(%d)\n",
- func->num, ret);
- ret = -EIO;
- }
- sdio_release_host(func);
- kfree(descriptor);
- return ret;
-}
-
-/*
- * Data management: read and write
- */
-static ssize_t csdio_transport_read(struct file *filp,
- char __user *buf,
- size_t count,
- loff_t *f_pos)
-{
- ssize_t ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
- size_t t_count = count;
-
- if (descriptor->m_block_mode) {
- pr_info(TP_DEV_NAME "%d: CMD53 read, Md:%d, Addr:0x%04X,"
- " Un:%d (Bl:%d, BlSz:%d)\n", func->num,
- descriptor->m_block_mode,
- descriptor->m_address,
- count*port->m_block_size,
- count, port->m_block_size);
- /* recalculate size */
- count *= port->m_block_size;
- }
- sdio_claim_host(func);
- if (descriptor->m_op_code) {
- /* auto increment */
- ret = sdio_memcpy_fromio(func, g_sdio_buffer,
- descriptor->m_address, count);
- } else { /* FIFO */
- ret = sdio_readsb(func, g_sdio_buffer,
- descriptor->m_address, count);
- }
- sdio_release_host(func);
- if (!ret) {
- if (copy_to_user(buf, g_sdio_buffer, count))
- ret = -EFAULT;
- else
- ret = t_count;
- }
- if (ret < 0) {
- pr_err(TP_DEV_NAME "%d: CMD53 read failed (%d)"
- "(Md:%d, Addr:0x%04X, Sz:%d)\n",
- func->num, ret,
- descriptor->m_block_mode,
- descriptor->m_address, count);
- }
- return ret;
-}
-
-static ssize_t csdio_transport_write(struct file *filp,
- const char __user *buf,
- size_t count,
- loff_t *f_pos)
-{
- ssize_t ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
- size_t t_count = count;
-
- if (descriptor->m_block_mode)
- count *= port->m_block_size;
-
- if (copy_from_user(g_sdio_buffer, buf, count)) {
- pr_err(TP_DEV_NAME"%d:copy_from_user failed\n", func->num);
- ret = -EFAULT;
- } else {
- sdio_claim_host(func);
- if (descriptor->m_op_code) {
- /* auto increment */
- ret = sdio_memcpy_toio(func, descriptor->m_address,
- g_sdio_buffer, count);
- } else {
- /* FIFO */
- ret = sdio_writesb(func, descriptor->m_address,
- g_sdio_buffer, count);
- }
- sdio_release_host(func);
- if (!ret) {
- ret = t_count;
- } else {
- pr_err(TP_DEV_NAME "%d: CMD53 write failed (%d)"
- "(Md:%d, Addr:0x%04X, Sz:%d)\n",
- func->num, ret, descriptor->m_block_mode,
- descriptor->m_address, count);
- }
- }
- return ret;
-}
-
-/* disable interrupt for sdio client */
-static int disable_sdio_client_isr(struct sdio_func *func)
-{
- int ret;
-
- /* disable for all functions, to restore interrupts
- * use g_csdio.m_current_irq_mask */
- sdio_f0_writeb(func, 0, SDIO_CCCR_IENx, &ret);
- if (ret)
- pr_err(CSDIO_DEV_NAME" Can't sdio_f0_writeb (%d)\n", ret);
-
- return ret;
-}
-
-/*
- * This handles the interrupt from SDIO.
- */
-static void csdio_sdio_irq(struct sdio_func *func)
-{
- int ret;
-
- pr_info(CSDIO_DEV_NAME" csdio_sdio_irq: func=%d\n", func->num);
- ret = disable_sdio_client_isr(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME" Can't disable client isr(%d)\n", ret);
- return;
- }
- /* signal asynchronous readers */
- if (g_csdio.m_async_queue)
- kill_fasync(&g_csdio.m_async_queue, SIGIO, POLL_IN);
-}
-
-/*
- * The ioctl() implementation
- */
-static int csdio_transport_ioctl(struct inode *inode,
- struct file *filp,
- unsigned int cmd,
- unsigned long arg)
-{
- int err = 0;
- int ret = 0;
- struct csdio_file_descriptor *descriptor = filp->private_data;
- struct csdio_func_t *port = descriptor->m_port;
- struct sdio_func *func = port->m_func;
-
- /* extract the type and number bitfields
- sanity check: return ENOTTY (inappropriate ioctl) before
- access_ok()
- */
- if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
- (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
- pr_err(TP_DEV_NAME "Wrong ioctl command parameters\n");
- ret = -ENOTTY;
- goto exit;
- }
-
- /* the direction is a bitmask, and VERIFY_WRITE catches R/W
- * transfers. `Type' is user-oriented, while access_ok is
- kernel-oriented, so the concept of "read" and "write" is reversed
- */
- if (_IOC_DIR(cmd) & _IOC_READ) {
- err = !access_ok(VERIFY_WRITE, (void __user *)arg,
- _IOC_SIZE(cmd));
- } else {
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- err = !access_ok(VERIFY_READ, (void __user *)arg,
- _IOC_SIZE(cmd));
- }
- }
- if (err) {
- pr_err(TP_DEV_NAME "Wrong ioctl access direction\n");
- ret = -EFAULT;
- goto exit;
- }
-
- switch (cmd) {
- case CSDIO_IOC_SET_OP_CODE:
- {
- pr_info(TP_DEV_NAME"%d:SET_OP_CODE=%d\n",
- func->num, descriptor->m_op_code);
- ret = get_user(descriptor->m_op_code,
- (unsigned char __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_OP_CODE get data"
- " from user space failed(%d)\n",
- func->num, ret);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE:
- {
- unsigned block_size;
-
- ret = get_user(block_size, (unsigned __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE get data"
- " from user space failed(%d)\n",
- func->num, ret);
- ret = -ENOTTY;
- break;
- }
- pr_info(TP_DEV_NAME"%d:SET_BLOCK_SIZE=%d\n",
- func->num, block_size);
- sdio_claim_host(func);
- ret = sdio_set_block_size(func, block_size);
- if (!ret) {
- port->m_block_size = block_size;
- } else {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE set block"
- " size to %d failed (%d)\n",
- func->num, block_size, ret);
- ret = -ENOTTY;
- break;
- }
- sdio_release_host(func);
- }
- break;
- case CSDIO_IOC_SET_BLOCK_MODE:
- {
- pr_info(TP_DEV_NAME"%d:SET_BLOCK_MODE=%d\n",
- func->num, descriptor->m_block_mode);
- ret = get_user(descriptor->m_block_mode,
- (unsigned char __user *)arg);
- if (ret) {
- pr_err(TP_DEV_NAME"%d:SET_BLOCK_MODE get data"
- " from user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_CMD52:
- {
- struct csdio_cmd52_ctrl_t cmd52ctrl;
- int cmd52ret;
-
- if (copy_from_user(&cmd52ctrl,
- (const unsigned char __user *)arg,
- sizeof(cmd52ctrl))) {
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 get data"
- " from user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- sdio_claim_host(func);
- if (cmd52ctrl.m_write)
- sdio_writeb(func, cmd52ctrl.m_data,
- cmd52ctrl.m_address, &cmd52ret);
- else
- cmd52ctrl.m_data = sdio_readb(func,
- cmd52ctrl.m_address, &cmd52ret);
-
- cmd52ctrl.m_ret = cmd52ret;
- sdio_release_host(func);
- if (cmd52ctrl.m_ret)
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 failed (%d)\n",
- func->num, cmd52ctrl.m_ret);
-
- if (copy_to_user((unsigned char __user *)arg,
- &cmd52ctrl,
- sizeof(cmd52ctrl))) {
- pr_err(TP_DEV_NAME"%d:IOC_CMD52 put data"
- " to user space failed\n",
- func->num);
- ret = -ENOTTY;
- break;
- }
- }
- break;
- case CSDIO_IOC_CMD53:
- {
- struct csdio_cmd53_ctrl_t csdio_cmd53_ctrl;
-
- if (copy_from_user(&csdio_cmd53_ctrl,
- (const char __user *)arg,
- sizeof(csdio_cmd53_ctrl))) {
- ret = -EPERM;
- pr_err(TP_DEV_NAME"%d:"
- "Get data from user space failed\n",
- func->num);
- break;
- }
- descriptor->m_block_mode =
- csdio_cmd53_ctrl.m_block_mode;
- descriptor->m_op_code = csdio_cmd53_ctrl.m_op_code;
- descriptor->m_address = csdio_cmd53_ctrl.m_address;
- }
- break;
- case CSDIO_IOC_CONNECT_ISR:
- {
- pr_info(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
- " func=%d, csdio_sdio_irq=%x\n",
- func->num, (unsigned int)csdio_sdio_irq);
- sdio_claim_host(func);
- ret = sdio_claim_irq(func, csdio_sdio_irq);
- sdio_release_host(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
- " claim irq failed(%d)\n", ret);
- } else {
- /* update current irq mask for disable/enable */
- g_csdio.m_current_irq_mask |= (1 << func->num);
- }
- }
- break;
- case CSDIO_IOC_DISCONNECT_ISR:
- {
- pr_info(CSDIO_DEV_NAME " SDIO_DISCONNECT_ISR func=%d\n",
- func->num);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_release_host(func);
- /* update current irq mask for disable/enable */
- g_csdio.m_current_irq_mask &= ~(1 << func->num);
- }
- break;
- default: /* redundant, as cmd was checked against MAXNR */
- pr_warning(TP_DEV_NAME"%d: Redundant IOCTL\n",
- func->num);
- ret = -ENOTTY;
- }
-exit:
- return ret;
-}
-
-static const struct file_operations csdio_transport_fops = {
- .owner = THIS_MODULE,
- .read = csdio_transport_read,
- .write = csdio_transport_write,
- .ioctl = csdio_transport_ioctl,
- .open = csdio_transport_open,
- .release = csdio_transport_release,
-};
-
-static void csdio_transport_cleanup(struct csdio_func_t *port)
-{
- int devno = MKDEV(csdio_major, csdio_minor + port->m_func->num);
- device_destroy(g_csdio.m_driver_class, devno);
- port->m_device = NULL;
- cdev_del(&port->m_cdev);
-}
-
-#if defined(CONFIG_DEVTMPFS)
-static inline int csdio_cdev_update_permissions(
- const char *devname, int dev_minor)
-{
- return 0;
-}
-#else
-static int csdio_cdev_update_permissions(
- const char *devname, int dev_minor)
-{
- int ret = 0;
- mm_segment_t fs;
- struct file *file;
- struct inode *inode;
- struct iattr newattrs;
- int mode = CSDIO_DEV_PERMISSIONS;
- char dev_file[64];
-
- fs = get_fs();
- set_fs(get_ds());
-
- snprintf(dev_file, sizeof(dev_file), "/dev/%s%d",
- devname, dev_minor);
- file = filp_open(dev_file, O_RDWR, 0);
- if (IS_ERR(file)) {
- ret = -EFAULT;
- goto exit;
- }
-
- inode = file->f_path.dentry->d_inode;
-
- mutex_lock(&inode->i_mutex);
- newattrs.ia_mode =
- (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- ret = notify_change(file->f_path.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-
- filp_close(file, NULL);
-
-exit:
- set_fs(fs);
- return ret;
-}
-#endif
-
-static struct device *csdio_cdev_init(struct cdev *char_dev,
- const struct file_operations *file_op, int dev_minor,
- const char *devname, struct device *parent)
-{
- int ret = 0;
- struct device *new_device = NULL;
- dev_t devno = MKDEV(csdio_major, dev_minor);
-
- /* Initialize transport device */
- cdev_init(char_dev, file_op);
- char_dev->owner = THIS_MODULE;
- char_dev->ops = file_op;
- ret = cdev_add(char_dev, devno, 1);
-
- /* Fail gracefully if need be */
- if (ret) {
- pr_warning("Error %d adding CSDIO char device '%s%d'",
- ret, devname, dev_minor);
- goto exit;
- }
- pr_info("'%s%d' char driver registered\n", devname, dev_minor);
-
- /* create a /dev entry for transport drivers */
- new_device = device_create(g_csdio.m_driver_class, parent, devno, NULL,
- "%s%d", devname, dev_minor);
- if (!new_device) {
- pr_err("Can't create device node '/dev/%s%d'\n",
- devname, dev_minor);
- goto cleanup;
- }
- /* no irq attached */
- g_csdio.m_current_irq_mask = 0;
-
- if (csdio_cdev_update_permissions(devname, dev_minor)) {
- pr_warning("%s%d: Unable to update access permissions of the"
- " '/dev/%s%d'\n",
- devname, dev_minor, devname, dev_minor);
- }
-
- pr_info("%s%d: Device node '/dev/%s%d' created successfully\n",
- devname, dev_minor, devname, dev_minor);
- goto exit;
-cleanup:
- cdev_del(char_dev);
-exit:
- return new_device;
-}
-
-/* Looks for first non empty function, returns NULL otherwise */
-static struct sdio_func *get_active_func(void)
-{
- int i;
-
- for (i = 0; i < CSDIO_NUM_OF_SDIO_FUNCTIONS; i++) {
- if (g_csdio_func_table[i])
- return g_csdio_func_table[i]->m_func;
- }
- return NULL;
-}
-
-static ssize_t
-show_vdd(struct device *dev, struct device_attribute *attr, char *buf)
-{
- if (NULL == g_csdio.m_host)
- return snprintf(buf, PAGE_SIZE, "N/A\n");
- return snprintf(buf, PAGE_SIZE, "%d\n",
- g_csdio.m_host->ios.vdd);
-}
-
-static int
-set_vdd_helper(int value)
-{
- struct mmc_ios *ios = NULL;
-
- if (NULL == g_csdio.m_host) {
- pr_err("%s0: Set VDD, no MMC host assigned\n", CSDIO_DEV_NAME);
- return -ENXIO;
- }
-
- mmc_claim_host(g_csdio.m_host);
- ios = &g_csdio.m_host->ios;
- ios->vdd = value;
- g_csdio.m_host->ops->set_ios(g_csdio.m_host, ios);
- mmc_release_host(g_csdio.m_host);
- return 0;
-}
-
-static ssize_t
-set_vdd(struct device *dev, struct device_attribute *att,
- const char *buf, size_t count)
-{
- int value = 0;
-
- sscanf(buf, "%d", &value);
- if (set_vdd_helper(value))
- return -ENXIO;
- return count;
-}
-
-static DEVICE_ATTR(vdd, S_IRUGO | S_IWUSR,
- show_vdd, set_vdd);
-
-static struct attribute *dev_attrs[] = {
- &dev_attr_vdd.attr,
- NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
- .attrs = dev_attrs,
-};
-
-/*
- * The ioctl() implementation for control device
- */
-static int csdio_ctrl_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- int err = 0;
- int ret = 0;
-
- pr_info("CSDIO ctrl ioctl.\n");
-
- /* extract the type and number bitfields
- sanity check: return ENOTTY (inappropriate ioctl) before
- access_ok()
- */
- if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
- (_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
- pr_err(CSDIO_DEV_NAME "Wrong ioctl command parameters\n");
- ret = -ENOTTY;
- goto exit;
- }
-
- /* the direction is a bitmask, and VERIFY_WRITE catches R/W
- transfers. `Type' is user-oriented, while access_ok is
- kernel-oriented, so the concept of "read" and "write" is reversed
- */
- if (_IOC_DIR(cmd) & _IOC_READ) {
- err = !access_ok(VERIFY_WRITE, (void __user *)arg,
- _IOC_SIZE(cmd));
- } else {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- err = !access_ok(VERIFY_READ, (void __user *)arg,
- _IOC_SIZE(cmd));
- }
- if (err) {
- pr_err(CSDIO_DEV_NAME "Wrong ioctl access direction\n");
- ret = -EFAULT;
- goto exit;
- }
-
- switch (cmd) {
- case CSDIO_IOC_ENABLE_HIGHSPEED_MODE:
- pr_info(CSDIO_DEV_NAME" ENABLE_HIGHSPEED_MODE\n");
- break;
- case CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS:
- {
- struct mmc_host *host = g_csdio.m_host;
- struct mmc_ios *ios = NULL;
-
- if (NULL == host) {
- pr_err("%s0: "
- "CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS,"
- " no MMC host assigned\n",
- CSDIO_DEV_NAME);
- ret = -EFAULT;
- goto exit;
- }
- ios = &host->ios;
-
- mmc_claim_host(host);
- ret = get_user(host->ios.clock,
- (unsigned int __user *)arg);
- if (ret) {
- pr_err(CSDIO_DEV_NAME
- " get data from user space failed\n");
- } else {
- pr_err(CSDIO_DEV_NAME
- "SET_DATA_TRANSFER_CLOCKS(%d-%d)(%d)\n",
- host->f_min, host->f_max,
- host->ios.clock);
- host->ops->set_ios(host, ios);
- }
- mmc_release_host(host);
- }
- break;
- case CSDIO_IOC_ENABLE_ISR:
- {
- int ret;
- unsigned char reg;
- struct sdio_func *func = get_active_func();
-
- if (!func) {
- pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
- " no active sdio function\n");
- ret = -EFAULT;
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME
- " CSDIO_IOC_ENABLE_ISR func=%d\n",
- func->num);
- reg = g_csdio.m_current_irq_mask | 1;
-
- sdio_claim_host(func);
- sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret);
- sdio_release_host(func);
- if (ret) {
- pr_err(CSDIO_DEV_NAME
- " Can't sdio_f0_writeb (%d)\n",
- ret);
- goto exit;
- }
- }
- break;
- case CSDIO_IOC_DISABLE_ISR:
- {
- int ret;
- struct sdio_func *func = get_active_func();
- if (!func) {
- pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
- " no active sdio function\n");
- ret = -EFAULT;
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME
- " CSDIO_IOC_DISABLE_ISR func=%p\n",
- func);
-
- sdio_claim_host(func);
- ret = disable_sdio_client_isr(func);
- sdio_release_host(func);
- if (ret) {
- pr_err("%s0: Can't disable client isr (%d)\n",
- CSDIO_DEV_NAME, ret);
- goto exit;
- }
- }
- break;
- case CSDIO_IOC_SET_VDD:
- {
- unsigned int vdd = 0;
-
- ret = get_user(vdd, (unsigned int __user *)arg);
- if (ret) {
- pr_err("%s0: CSDIO_IOC_SET_VDD,"
- " get data from user space failed\n",
- CSDIO_DEV_NAME);
- goto exit;
- }
- pr_info(CSDIO_DEV_NAME" CSDIO_IOC_SET_VDD - %d\n", vdd);
-
- ret = set_vdd_helper(vdd);
- if (ret)
- goto exit;
- }
- break;
- case CSDIO_IOC_GET_VDD:
- {
- if (NULL == g_csdio.m_host) {
- pr_err("%s0: CSDIO_IOC_GET_VDD,"
- " no MMC host assigned\n",
- CSDIO_DEV_NAME);
- ret = -EFAULT;
- goto exit;
- }
- ret = put_user(g_csdio.m_host->ios.vdd,
- (unsigned short __user *)arg);
- if (ret) {
- pr_err("%s0: CSDIO_IOC_GET_VDD, put data"
- " to user space failed\n",
- CSDIO_DEV_NAME);
- goto exit;
- }
- }
- break;
- default: /* redundant, as cmd was checked against MAXNR */
- pr_warning(CSDIO_DEV_NAME" Redundant IOCTL\n");
- ret = -ENOTTY;
- }
-exit:
- return ret;
-}
-
-static int csdio_ctrl_fasync(int fd, struct file *filp, int mode)
-{
- pr_info(CSDIO_DEV_NAME
- " csdio_ctrl_fasync: fd=%d, filp=%p, mode=%d\n",
- fd, filp, mode);
- return fasync_helper(fd, filp, mode, &g_csdio.m_async_queue);
-}
-
-/*
- * Open and close
- */
-static int csdio_ctrl_open(struct inode *inode, struct file *filp)
-{
- int ret = 0;
- struct csdio_t *csdio_ctrl_drv = NULL; /* device information */
-
- pr_info("CSDIO ctrl open.\n");
- csdio_ctrl_drv = container_of(inode->i_cdev, struct csdio_t, m_cdev);
- filp->private_data = csdio_ctrl_drv; /* for other methods */
- return ret;
-}
-
-static int csdio_ctrl_release(struct inode *inode, struct file *filp)
-{
- pr_info("CSDIO ctrl release.\n");
- /* remove this filp from the asynchronously notified filp's */
- csdio_ctrl_fasync(-1, filp, 0);
- return 0;
-}
-
-static const struct file_operations csdio_ctrl_fops = {
- .owner = THIS_MODULE,
- .ioctl = csdio_ctrl_ioctl,
- .open = csdio_ctrl_open,
- .release = csdio_ctrl_release,
- .fasync = csdio_ctrl_fasync,
-};
-
-static int csdio_probe(struct sdio_func *func,
- const struct sdio_device_id *id)
-{
- struct csdio_func_t *port;
- int ret = 0;
- struct mmc_host *host = func->card->host;
-
- if (NULL != g_csdio.m_host && g_csdio.m_host != host) {
- pr_info("%s: Device is on unexpected host\n",
- CSDIO_DEV_NAME);
- ret = -ENODEV;
- goto exit;
- }
-
- /* enforce single instance policy */
- if (g_csdio_func_table[func->num-1]) {
- pr_err("%s - only single SDIO device supported",
- sdio_func_id(func));
- ret = -EEXIST;
- goto exit;
- }
-
- port = kzalloc(sizeof(struct csdio_func_t), GFP_KERNEL);
- if (!port) {
- pr_err("Can't allocate memory\n");
- ret = -ENOMEM;
- goto exit;
- }
-
- /* initialize SDIO side */
- port->m_func = func;
- sdio_set_drvdata(func, port);
-
- pr_info("%s - SDIO device found. Function %d\n",
- sdio_func_id(func), func->num);
-
- port->m_device = csdio_cdev_init(&port->m_cdev, &csdio_transport_fops,
- csdio_minor + port->m_func->num,
- TP_DEV_NAME, &port->m_func->dev);
-
- /* create appropriate char device */
- if (!port->m_device)
- goto free;
-
- if (0 == g_csdio.m_num_of_func && NULL == host_name)
- g_csdio.m_host = host;
- g_csdio.m_num_of_func++;
- g_csdio_func_table[func->num-1] = port;
- port->m_enabled = TRUE;
- goto exit;
-free:
- kfree(port);
-exit:
- return ret;
-}
-
-static void csdio_remove(struct sdio_func *func)
-{
- struct csdio_func_t *port = sdio_get_drvdata(func);
-
- csdio_transport_cleanup(port);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_disable_func(func);
- sdio_release_host(func);
- kfree(port);
- g_csdio_func_table[func->num-1] = NULL;
- g_csdio.m_num_of_func--;
- if (0 == g_csdio.m_num_of_func && NULL == host_name)
- g_csdio.m_host = NULL;
- pr_info("%s%d: Device removed (%s). Function %d\n",
- CSDIO_DEV_NAME, func->num, sdio_func_id(func), func->num);
-}
-
-/* CONFIG_CSDIO_VENDOR_ID and CONFIG_CSDIO_DEVICE_ID are defined in Kconfig.
- * Use kernel configuration to change the values or overwrite them through
- * module parameters */
-static struct sdio_device_id csdio_ids[] = {
- { SDIO_DEVICE(CONFIG_CSDIO_VENDOR_ID, CONFIG_CSDIO_DEVICE_ID) },
- { /* end: all zeroes */},
-};
-
-MODULE_DEVICE_TABLE(sdio, csdio_ids);
-
-static struct sdio_driver csdio_driver = {
- .probe = csdio_probe,
- .remove = csdio_remove,
- .name = "csdio",
- .id_table = csdio_ids,
-};
-
-static void __exit csdio_exit(void)
-{
- dev_t devno = MKDEV(csdio_major, csdio_minor);
-
- sdio_unregister_driver(&csdio_driver);
- sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
- kfree(g_sdio_buffer);
- device_destroy(g_csdio.m_driver_class, devno);
- cdev_del(&g_csdio.m_cdev);
- class_destroy(g_csdio.m_driver_class);
- unregister_chrdev_region(devno, csdio_transport_nr_devs);
- pr_info("%s: Exit driver module\n", CSDIO_DEV_NAME);
-}
-
-static char *csdio_devnode(struct device *dev, mode_t *mode)
-{
- *mode = CSDIO_DEV_PERMISSIONS;
- return NULL;
-}
-
-static int __init csdio_init(void)
-{
- int ret = 0;
- dev_t devno = 0;
-
- pr_info("Init CSDIO driver module.\n");
-
- /* Get a range of minor numbers to work with, asking for a dynamic */
- /* major unless directed otherwise at load time. */
- if (csdio_major) {
- devno = MKDEV(csdio_major, csdio_minor);
- ret = register_chrdev_region(devno, csdio_transport_nr_devs,
- CSDIO_DEV_NAME);
- } else {
- ret = alloc_chrdev_region(&devno, csdio_minor,
- csdio_transport_nr_devs, CSDIO_DEV_NAME);
- csdio_major = MAJOR(devno);
- }
- if (ret < 0) {
- pr_err("CSDIO: can't get major %d\n", csdio_major);
- goto exit;
- }
- pr_info("CSDIO char driver major number is %d\n", csdio_major);
-
- /* kernel module got parameters: overwrite vendor and device id's */
- if ((csdio_vendor_id != 0) && (csdio_device_id != 0)) {
- csdio_ids[0].vendor = (u16)csdio_vendor_id;
- csdio_ids[0].device = (u16)csdio_device_id;
- }
-
- /* prepare create /dev/... instance */
- g_csdio.m_driver_class = class_create(THIS_MODULE, CSDIO_DEV_NAME);
- if (IS_ERR(g_csdio.m_driver_class)) {
- ret = -ENOMEM;
- pr_err(CSDIO_DEV_NAME " class_create failed\n");
- goto unregister_region;
- }
- g_csdio.m_driver_class->devnode = csdio_devnode;
-
- /* create CSDIO ctrl driver */
- g_csdio.m_device = csdio_cdev_init(&g_csdio.m_cdev,
- &csdio_ctrl_fops, csdio_minor, CSDIO_DEV_NAME, NULL);
- if (!g_csdio.m_device) {
- pr_err("%s: Unable to create ctrl driver\n",
- CSDIO_DEV_NAME);
- goto destroy_class;
- }
-
- g_sdio_buffer = kmalloc(CSDIO_SDIO_BUFFER_SIZE, GFP_KERNEL);
- if (!g_sdio_buffer) {
- pr_err("Unable to allocate %d bytes\n", CSDIO_SDIO_BUFFER_SIZE);
- ret = -ENOMEM;
- goto destroy_cdev;
- }
-
- ret = sysfs_create_group(&g_csdio.m_device->kobj, &dev_attr_grp);
- if (ret) {
- pr_err("%s: Unable to create device attribute\n",
- CSDIO_DEV_NAME);
- goto free_sdio_buff;
- }
-
- g_csdio.m_num_of_func = 0;
- g_csdio.m_host = NULL;
-
- if (NULL != host_name) {
- struct device *dev = bus_find_device_by_name(&platform_bus_type,
- NULL, host_name);
- if (NULL != dev) {
- g_csdio.m_host = dev_get_drvdata(dev);
- } else {
- pr_err("%s: Host '%s' doesn't exist!\n", CSDIO_DEV_NAME,
- host_name);
- }
- }
-
- pr_info("%s: Match with VendorId=0x%X, DeviceId=0x%X, Host = %s\n",
- CSDIO_DEV_NAME, csdio_device_id, csdio_vendor_id,
- (NULL == host_name) ? "Any" : host_name);
-
- /* register sdio driver */
- ret = sdio_register_driver(&csdio_driver);
- if (ret) {
- pr_err("%s: Unable to register as SDIO driver\n",
- CSDIO_DEV_NAME);
- goto remove_group;
- }
-
- goto exit;
-
-remove_group:
- sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
-free_sdio_buff:
- kfree(g_sdio_buffer);
-destroy_cdev:
- cdev_del(&g_csdio.m_cdev);
-destroy_class:
- class_destroy(g_csdio.m_driver_class);
-unregister_region:
- unregister_chrdev_region(devno, csdio_transport_nr_devs);
-exit:
- return ret;
-}
-module_param(csdio_vendor_id, uint, S_IRUGO);
-module_param(csdio_device_id, uint, S_IRUGO);
-module_param(host_name, charp, S_IRUGO);
-
-module_init(csdio_init);
-module_exit(csdio_exit);
-
-MODULE_AUTHOR("The Linux Foundation");
-MODULE_DESCRIPTION("CSDIO device driver version " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 070b5ac..eba60ea 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2051,6 +2051,8 @@
device->reset_counter++;
+ set_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
return 0;
error_rb_stop:
@@ -2088,7 +2090,25 @@
set_user_nice(current, _wake_nice);
mutex_lock(&device->mutex);
- _status = _adreno_start(adreno_dev);
+ /*
+ * If adreno start is already called, no need to call it again
+ * it can lead to unpredictable behavior if we try to start
+ * the device that is already started.
+ * Below is the sequence of events that can go bad without the check
+ * 1) thread 1 calls adreno_start to be scheduled on high priority wq
+ * 2) thread 2 calls adreno_start with normal priority
+ * 3) thread 1 after checking the device to be in slumber state gives
+ * up mutex to be scheduled on high priority wq
+ * 4) thread 2 after checking the device to be in slumber state gets
+ * the mutex and finishes adreno_start before thread 1 is scheduled
+ * on high priority wq.
+ * 5) thread 1 gets scheduled on high priority wq and executes
+ * adreno_start again. This leads to unpredictable behavior.
+ */
+ if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv))
+ _status = _adreno_start(adreno_dev);
+ else
+ _status = 0;
mutex_unlock(&device->mutex);
}
@@ -2149,6 +2169,8 @@
kgsl_cffdump_close(device);
+ clear_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
return 0;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 1b538a7..800caf1 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -216,6 +216,7 @@
ADRENO_DEVICE_PWRON = 0,
ADRENO_DEVICE_PWRON_FIXUP = 1,
ADRENO_DEVICE_INITIALIZED = 2,
+ ADRENO_DEVICE_STARTED = 3,
};
#define PERFCOUNTER_FLAG_NONE 0x0
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 505be69..f0114ad 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -141,7 +141,7 @@
static inline void *kgsl_sg_alloc(unsigned int sglen)
{
- if (sglen >= ULONG_MAX / sizeof(struct scatterlist))
+ if ((sglen == 0) || (sglen >= ULONG_MAX / sizeof(struct scatterlist)))
return NULL;
if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index ceeb67b..5c89c0c 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -17,7 +17,6 @@
*/
#include <linux/delay.h>
-#include <linux/earlysuspend.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/sensors.h>
@@ -118,7 +117,6 @@
struct input_dev *ls_input_dev;
struct input_dev *ps_input_dev;
- struct early_suspend early_suspend;
struct i2c_client *i2c_client;
struct workqueue_struct *lp_wq;
@@ -1426,29 +1424,6 @@
return ret;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void cm36283_early_suspend(struct early_suspend *h)
-{
- struct cm36283_info *lpi = lp_info;
-
- D("[LS][CM36283] %s\n", __func__);
-
- if (lpi->als_enable)
- lightsensor_disable(lpi);
-
-}
-
-static void cm36283_late_resume(struct early_suspend *h)
-{
- struct cm36283_info *lpi = lp_info;
-
- D("[LS][CM36283] %s\n", __func__);
-
- if (!lpi->als_enable)
- lightsensor_enable(lpi);
-}
-#endif
-
static int cm36283_parse_dt(struct device *dev,
struct cm36283_platform_data *pdata)
{
@@ -1744,13 +1719,6 @@
if (ret)
goto err_create_ps_device_file;
-#ifdef CONFIG_HAS_EARLYSUSPEND
- lpi->early_suspend.level =
- EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- lpi->early_suspend.suspend = cm36283_early_suspend;
- lpi->early_suspend.resume = cm36283_late_resume;
- register_early_suspend(&lpi->early_suspend);
-#endif
ret = sensors_classdev_register(&client->dev, &sensors_light_cdev);
if (ret)
goto err_create_ps_device_file;
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 3b7bf5a..fab209e 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -325,32 +325,32 @@
{
struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
unsigned long val;
+ u32 enable;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
- sensor->enable = (u32)val == 0 ? 0 : 1;
- if (sensor->enable) {
+ enable = (u32)val == 0 ? 0 : 1;
+ if (enable && (!sensor->enable)) {
+ sensor->enable = enable;
pm_runtime_get_sync(sensor->dev);
- gpio_set_value(sensor->enable_gpio, 1);
if (sensor->use_poll)
schedule_delayed_work(&sensor->input_work,
msecs_to_jiffies(sensor->poll_interval));
- else {
- i2c_smbus_write_byte_data(sensor->client,
- MPU3050_INT_CFG,
- MPU3050_ACTIVE_LOW |
- MPU3050_OPEN_DRAIN |
- MPU3050_RAW_RDY_EN);
+ else
enable_irq(sensor->client->irq);
- }
- } else {
+ } else if (!enable && sensor->enable) {
if (sensor->use_poll)
cancel_delayed_work_sync(&sensor->input_work);
else
disable_irq(sensor->client->irq);
- gpio_set_value(sensor->enable_gpio, 0);
- pm_runtime_put(sensor->dev);
+ pm_runtime_put_sync(sensor->dev);
+ sensor->enable = enable;
+ } else {
+ dev_warn(&sensor->client->dev,
+ "ignore enable state change from %d to %d\n",
+ sensor->enable, enable);
}
+
return count;
}
@@ -485,54 +485,6 @@
}
/**
- * mpu3050_input_open - called on input event open
- * @input: input dev of opened device
- *
- * The input layer calls this function when input event is opened. The
- * function will push the device to resume. Then, the device is ready
- * to provide data.
- */
-static int mpu3050_input_open(struct input_dev *input)
-{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
- int error;
-
- pm_runtime_get_sync(sensor->dev);
-
- /* Enable interrupts */
- error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
- MPU3050_ACTIVE_LOW |
- MPU3050_OPEN_DRAIN |
- MPU3050_RAW_RDY_EN);
- if (error < 0) {
- pm_runtime_put(sensor->dev);
- return error;
- }
- if (sensor->use_poll)
- schedule_delayed_work(&sensor->input_work,
- msecs_to_jiffies(sensor->poll_interval));
-
- return 0;
-}
-
-/**
- * mpu3050_input_close - called on input event close
- * @input: input dev of closed device
- *
- * The input layer calls this function when input event is closed. The
- * function will push the device to suspend.
- */
-static void mpu3050_input_close(struct input_dev *input)
-{
- struct mpu3050_sensor *sensor = input_get_drvdata(input);
-
- if (sensor->use_poll)
- cancel_delayed_work_sync(&sensor->input_work);
-
- pm_runtime_put(sensor->dev);
-}
-
-/**
* mpu3050_interrupt_thread - handle an IRQ
* @irq: interrupt numner
* @data: the sensor
@@ -588,18 +540,12 @@
*
* Called during device probe; configures the sampling method.
*/
-static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
+static int mpu3050_hw_init(struct mpu3050_sensor *sensor)
{
struct i2c_client *client = sensor->client;
int ret;
u8 reg;
- /* Reset */
- ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM,
- MPU3050_PWR_MGM_RESET);
- if (ret < 0)
- return ret;
-
ret = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
if (ret < 0)
return ret;
@@ -624,6 +570,16 @@
if (ret < 0)
return ret;
+ /* Enable interrupts */
+ if (!sensor->use_poll) {
+ reg = MPU3050_ACTIVE_LOW;
+ reg |= MPU3050_OPEN_DRAIN;
+ reg |= MPU3050_RAW_RDY_EN;
+ ret = i2c_smbus_write_byte_data(client, MPU3050_INT_CFG, reg);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
#ifdef CONFIG_OF
@@ -750,9 +706,6 @@
idev->name = "MPU3050";
idev->id.bustype = BUS_I2C;
- idev->open = mpu3050_input_open;
- idev->close = mpu3050_input_close;
-
input_set_capability(idev, EV_ABS, ABS_MISC);
input_set_abs_params(idev, ABS_X,
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
@@ -813,6 +766,9 @@
disable_irq(client->irq);
}
+ sensor->enable = 0;
+ mpu3050_set_power_mode(client, 0);
+
error = input_register_device(idev);
if (error) {
dev_err(&client->dev, "failed to register input device\n");
@@ -893,10 +849,11 @@
struct i2c_client *client = to_i2c_client(dev);
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
- if (!sensor->use_poll)
- disable_irq(client->irq);
-
- mpu3050_set_power_mode(client, 0);
+ if (sensor->enable) {
+ if (!sensor->use_poll)
+ disable_irq(client->irq);
+ mpu3050_set_power_mode(client, 0);
+ }
return 0;
}
@@ -912,16 +869,64 @@
struct i2c_client *client = to_i2c_client(dev);
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
- mpu3050_set_power_mode(client, 1);
+ if (sensor->enable) {
+ mpu3050_set_power_mode(client, 1);
+ mpu3050_hw_init(sensor);
+ if (!sensor->use_poll)
+ enable_irq(client->irq);
+ }
- if (!sensor->use_poll)
- enable_irq(client->irq);
+ return 0;
+}
+
+/**
+ * mpu3050_runtime_suspend - called on device enters runtime suspend
+ * @dev: device being suspended
+ *
+ * Put the device into sleep mode.
+ */
+static int mpu3050_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (sensor->enable)
+ mpu3050_set_power_mode(client, 0);
+
+ return 0;
+}
+
+/**
+ * mpu3050_runtime_resume - called on device enters runtime resume
+ * @dev: device being resumed
+ *
+ * Put the device into powered mode.
+ */
+static int mpu3050_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (sensor->enable) {
+ mpu3050_set_power_mode(client, 1);
+ mpu3050_hw_init(sensor);
+ }
return 0;
}
#endif
-static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
+static const struct dev_pm_ops mpu3050_pm = {
+ .runtime_suspend = mpu3050_runtime_suspend,
+ .runtime_resume = mpu3050_runtime_resume,
+ .runtime_idle = NULL,
+ .suspend = mpu3050_suspend,
+ .resume = mpu3050_resume,
+ .freeze = mpu3050_suspend,
+ .thaw = mpu3050_resume,
+ .poweroff = mpu3050_suspend,
+ .restore = mpu3050_resume,
+};
static const struct i2c_device_id mpu3050_ids[] = {
{ "mpu3050", 0 },
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 7954296..e776dbb 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -713,7 +713,7 @@
duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
/*config pwm for brightness scaling*/
- rc = pwm_config(led->mpp_cfg->pwm_cfg->pwm_dev,
+ rc = pwm_config_us(led->mpp_cfg->pwm_cfg->pwm_dev,
duty_us,
led->mpp_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
@@ -1239,7 +1239,7 @@
if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / KPDBL_MAX_LEVEL;
- rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev,
+ rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev,
duty_us,
led->kpdbl_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
@@ -1261,7 +1261,7 @@
led->kpdbl_cfg->pwm_cfg->default_mode;
if (led->kpdbl_cfg->always_on) {
- rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
+ rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
led->kpdbl_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
@@ -1310,7 +1310,8 @@
if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
led->cdev.brightness) / LED_FULL;
- rc = pwm_config(led->rgb_cfg->pwm_cfg->pwm_dev, duty_us,
+ rc = pwm_config_us(led->rgb_cfg->pwm_cfg->pwm_dev,
+ duty_us,
led->rgb_cfg->pwm_cfg->pwm_period_us);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 7d26bef..588afc6 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -208,6 +208,12 @@
#define QPNP_PWM_SIZE_8_BIT 8
#define QPNP_PWM_SIZE_9_BIT 9
+/* Supported time levels */
+enum time_level {
+ LVL_NSEC,
+ LVL_USEC,
+};
+
/* LPG revisions */
enum qpnp_lpg_revision {
QPNP_LPG_REVISION_0 = 0x0,
@@ -305,8 +311,8 @@
bool in_use;
const char *lable;
int pwm_value;
- int pwm_period;
- int pwm_duty;
+ int pwm_period; /* in microseconds */
+ int pwm_duty; /* in microseconds */
struct pwm_period_config period;
int force_pwm_size;
};
@@ -425,8 +431,9 @@
* This is the formula to figure out m for the best pre-divide and clock:
* (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
*/
-static void qpnp_lpg_calc_period(unsigned int period_us,
- struct pwm_device *pwm)
+static void qpnp_lpg_calc_period(enum time_level tm_lvl,
+ unsigned int period_value,
+ struct pwm_device *pwm)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
@@ -443,14 +450,18 @@
else
n = 6;
- if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
- period_n = (period_us * NSEC_PER_USEC) >> n;
+ if (tm_lvl == LVL_USEC) {
+ if (period_value < ((unsigned)(-1) / NSEC_PER_USEC)) {
+ period_n = (period_value * NSEC_PER_USEC) >> n;
+ } else {
+ if (qpnp_check_gpled_lpg_channel(id))
+ n = 8;
+ else
+ n = 9;
+ period_n = (period_value >> n) * NSEC_PER_USEC;
+ }
} else {
- if (qpnp_check_gpled_lpg_channel(id))
- n = 8;
- else
- n = 9;
- period_n = (period_us >> n) * NSEC_PER_USEC;
+ period_n = period_value >> n;
}
if (force_pwm_size != 0) {
@@ -520,20 +531,20 @@
}
static void qpnp_lpg_calc_pwm_value(struct pwm_device *pwm,
- unsigned int period_us,
- unsigned int duty_us)
+ unsigned int period_value,
+ unsigned int duty_value)
{
unsigned int max_pwm_value, tmp;
struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
/* Figure out pwm_value with overflow handling */
tmp = 1 << (sizeof(tmp) * 8 - pwm_config->period.pwm_size);
- if (duty_us < tmp) {
- tmp = duty_us << pwm_config->period.pwm_size;
- pwm_config->pwm_value = tmp / period_us;
+ if (duty_value < tmp) {
+ tmp = duty_value << pwm_config->period.pwm_size;
+ pwm_config->pwm_value = tmp / period_value;
} else {
- tmp = period_us >> pwm_config->period.pwm_size;
- pwm_config->pwm_value = duty_us / tmp;
+ tmp = period_value >> pwm_config->period.pwm_size;
+ pwm_config->pwm_value = duty_value / tmp;
}
max_pwm_value = (1 << pwm_config->period.pwm_size) - 1;
if (pwm_config->pwm_value > max_pwm_value)
@@ -1083,25 +1094,36 @@
return rc;
}
-static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+static int _pwm_config(struct pwm_device *pwm,
+ enum time_level tm_lvl,
+ int duty_value, int period_value)
{
struct qpnp_pwm_config *pwm_config;
struct qpnp_lpg_chip *chip;
struct pwm_period_config *period;
- int rc;
+ int period_us, duty_us;
+ int rc;
chip = pwm->chip;
pwm_config = &pwm->pwm_config;
period = &pwm_config->period;
+ if (tm_lvl == LVL_USEC) {
+ period_us = period_value;
+ duty_us = duty_value;
+ } else {
+ period_us = period_value / NSEC_PER_USEC;
+ duty_us = duty_value / NSEC_PER_USEC;
+ }
+
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm);
+ qpnp_lpg_calc_period(tm_lvl, period_value, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
pwm_config->pwm_duty = duty_us;
- qpnp_lpg_calc_pwm_value(pwm, period_us, duty_us);
+ qpnp_lpg_calc_pwm_value(pwm, period_value, duty_value);
rc = qpnp_lpg_save_pwm_value(pwm);
if (rc) {
@@ -1124,8 +1146,9 @@
return rc;
}
- pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
+ pr_debug("duty/period=%u/%u %s: pwm_value=%d (of %d)\n",
(unsigned)duty_us, (unsigned)period_us,
+ (tm_lvl == LVL_USEC) ? "usec" : "nsec",
pwm_config->pwm_value, 1 << period->pwm_size);
return 0;
@@ -1151,7 +1174,7 @@
period = &pwm_config->period;
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm);
+ qpnp_lpg_calc_period(LVL_USEC, period_us, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
@@ -1302,10 +1325,41 @@
/**
* pwm_config - change a PWM device configuration
* @pwm: the PWM device
+ * @period_ns: period in nanoseconds
+ * @duty_ns: duty cycle in nanoseconds
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ int rc;
+ unsigned long flags;
+
+ if (pwm == NULL || IS_ERR(pwm) || duty_ns > period_ns ||
+ (unsigned)period_ns < PM_PWM_PERIOD_MIN * NSEC_PER_USEC) {
+ pr_err("Invalid pwm handle or parameters\n");
+ return -EINVAL;
+ }
+
+ if (!pwm->pwm_config.in_use)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
+ rc = _pwm_config(pwm, LVL_NSEC, duty_ns, period_ns);
+ spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
+
+ if (rc)
+ pr_err("Failed to configure PWM mode\n");
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/**
+ * pwm_config_us - change a PWM device configuration
+ * @pwm: the PWM device
* @period_us: period in microseconds
* @duty_us: duty cycle in microseconds
*/
-int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+int pwm_config_us(struct pwm_device *pwm, int duty_us, int period_us)
{
int rc;
unsigned long flags;
@@ -1322,7 +1376,7 @@
return -EINVAL;
spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
- rc = _pwm_config(pwm, duty_us, period_us);
+ rc = _pwm_config(pwm, LVL_USEC, duty_us, period_us);
spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
if (rc)
@@ -1330,7 +1384,7 @@
return rc;
}
-EXPORT_SYMBOL_GPL(pwm_config);
+EXPORT_SYMBOL_GPL(pwm_config_us);
/**
* pwm_enable - start a PWM output toggling
@@ -1627,7 +1681,8 @@
return rc;
}
- rc = _pwm_config(pwm_dev, pwm_dev->pwm_config.pwm_duty, period);
+ rc = _pwm_config(pwm_dev, LVL_USEC,
+ pwm_dev->pwm_config.pwm_duty, period);
return rc;
}
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index cf1801b..efb87a9 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1339,7 +1339,7 @@
{
u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
- u8 sensor_mask = 0;
+ u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0;
int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
uint32_t btm_chan_num = 0;
struct qpnp_adc_thr_client_info *client_info = NULL;
@@ -1368,6 +1368,20 @@
goto fail;
}
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ &adc_tm_low_thr_set);
+ if (rc) {
+ pr_err("adc-tm-tm read low thr failed with %d\n", rc);
+ goto fail;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ &adc_tm_high_thr_set);
+ if (rc) {
+ pr_err("adc-tm-tm read high thr failed with %d\n", rc);
+ goto fail;
+ }
+
/* Check which interrupt threshold is lower and measure against the
* enabled channel */
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
@@ -1378,7 +1392,9 @@
}
adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
+ adc_tm_low_enable &= adc_tm_low_thr_set;
adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
+ adc_tm_high_enable &= adc_tm_high_thr_set;
if (adc_tm_high_enable) {
sensor_notify_num = adc_tm_high_enable;
@@ -1886,7 +1902,7 @@
pr_debug("thermal node%x\n", btm_channel_num);
chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
chip->sensor[sen_idx].thermal_node = true;
- snprintf(name, sizeof(name),
+ snprintf(name, sizeof(name), "%s",
chip->adc->adc_channels[sen_idx].name);
chip->sensor[sen_idx].meas_interval =
QPNP_ADC_TM_MEAS_INTERVAL;
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 28997ec..f1f0455 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -26,6 +26,7 @@
#include "mdss_fb.h"
#define MDP_VSYNC_CLK_RATE 19200000
+#define KOFF_TIMEOUT msecs_to_jiffies(84)
enum {
MDP3_CLK_AHB,
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index a6fc20d..6fc6195 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -91,6 +91,36 @@
return bufq->count;
}
+void mdp3_ctrl_notifier_register(struct mdp3_session_data *ses,
+ struct notifier_block *notifier)
+{
+ blocking_notifier_chain_register(&ses->notifier_head, notifier);
+}
+
+void mdp3_ctrl_notifier_unregister(struct mdp3_session_data *ses,
+ struct notifier_block *notifier)
+{
+ blocking_notifier_chain_unregister(&ses->notifier_head, notifier);
+}
+
+int mdp3_ctrl_notify(struct mdp3_session_data *ses, int event)
+{
+ return blocking_notifier_call_chain(&ses->notifier_head, event, ses);
+}
+
+static void mdp3_dispatch_dma_done(struct work_struct *work)
+{
+ struct mdp3_session_data *session;
+
+ pr_debug("%s\n", __func__);
+ session = container_of(work, struct mdp3_session_data,
+ dma_done_work);
+ if (!session)
+ return;
+
+ mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+}
+
static void mdp3_dispatch_clk_off(struct work_struct *work)
{
struct mdp3_session_data *session;
@@ -121,6 +151,12 @@
sysfs_notify_dirent(session->vsync_event_sd);
}
+void dma_done_notify_handler(void *arg)
+{
+ struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+ schedule_work(&session->dma_done_work);
+}
+
void vsync_count_down(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
@@ -140,8 +176,8 @@
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
{
struct mdp3_session_data *mdp3_session;
- struct mdp3_vsync_notification vsync_client;
- struct mdp3_vsync_notification *arg = NULL;
+ struct mdp3_notification vsync_client;
+ struct mdp3_notification *arg = NULL;
pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -464,6 +500,7 @@
int frame_rate = mfd->panel_info->mipi.frame_rate;
int vbp, vfp, vspw;
int vtotal, vporch;
+ struct mdp3_notification dma_done_callback;
vbp = panel_info->lcdc.v_back_porch;
vfp = panel_info->lcdc.v_front_porch;
@@ -499,6 +536,13 @@
rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
else
rc = -EINVAL;
+
+ if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+ dma_done_callback.handler = dma_done_notify_handler;
+ dma_done_callback.arg = mfd->mdp.private1;
+ dma->dma_done_notifier(dma, &dma_done_callback);
+ }
+
return rc;
}
@@ -527,6 +571,8 @@
}
mdp3_batfet_ctrl(true);
+ mdp3_ctrl_notifier_register(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
if (rc) {
@@ -658,6 +704,8 @@
if (rc)
pr_err("fail to dettach MDP DMA SMMU\n");
+ mdp3_ctrl_notifier_unregister(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
mdp3_batfet_ctrl(false);
mdp3_session->vsync_enabled = 0;
atomic_set(&mdp3_session->vsync_countdown, 0);
@@ -677,7 +725,7 @@
struct mdp3_session_data *mdp3_session;
struct mdp3_dma *mdp3_dma;
struct mdss_panel_data *panel;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
pr_debug("mdp3_ctrl_reset_cmd\n");
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -727,7 +775,7 @@
struct mdp3_session_data *mdp3_session;
struct mdp3_dma *mdp3_dma;
struct mdss_panel_data *panel;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
pr_debug("mdp3_ctrl_reset\n");
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -969,13 +1017,27 @@
return -EPERM;
}
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
data = mdp3_bufq_pop(&mdp3_session->bufq_in);
if (data) {
mdp3_ctrl_reset_countdown(mdp3_session, mfd);
mdp3_ctrl_clk_enable(mfd, 1);
- mdp3_session->dma->update(mdp3_session->dma,
+ rc = mdp3_session->dma->update(mdp3_session->dma,
(void *)data->addr,
mdp3_session->intf);
+ /* This is for the previous frame */
+ if (rc < 0) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_TIMEOUT);
+ } else {
+ if (mdp3_ctrl_get_intf_type(mfd) ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_DONE);
+ }
+ }
+
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
mdp3_bufq_push(&mdp3_session->bufq_out, data);
}
@@ -998,7 +1060,7 @@
mdss_fb_update_notify_update(mfd);
- return rc;
+ return 0;
}
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
@@ -1008,6 +1070,7 @@
u32 offset;
int bpp;
struct mdss_panel_info *panel_info = mfd->panel_info;
+ int rc;
pr_debug("mdp3_ctrl_pan_display\n");
if (!mfd || !mfd->mdp.private1)
@@ -1044,10 +1107,23 @@
if (mfd->fbi->screen_base) {
mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
mdp3_ctrl_clk_enable(mfd, 1);
- mdp3_session->dma->update(mdp3_session->dma,
- (void *)mfd->iova + offset,
+ rc = mdp3_session->dma->update(mdp3_session->dma,
+ (void *)(mfd->iova + offset),
mdp3_session->intf);
+ /* This is for the previous frame */
+ if (rc < 0) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_TIMEOUT);
+ } else {
+ if (mdp3_ctrl_get_intf_type(mfd) ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ mdp3_ctrl_notify(mdp3_session,
+ MDP_NOTIFY_FRAME_DONE);
+ }
+ }
+ mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
} else {
pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
mdp3_clk_enable(1, 0);
@@ -1658,6 +1734,7 @@
memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
mutex_init(&mdp3_session->lock);
INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off);
+ INIT_WORK(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done);
atomic_set(&mdp3_session->vsync_countdown, 0);
mutex_init(&mdp3_session->histo_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
@@ -1693,6 +1770,7 @@
mdp3_bufq_init(&mdp3_session->bufq_out);
mdp3_session->histo_status = 0;
mdp3_session->lut_sel = 0;
+ BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head);
init_timer(&mdp3_session->vsync_timer);
mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
@@ -1721,8 +1799,11 @@
kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
- if (mdp3_get_cont_spash_en())
+ if (mdp3_get_cont_spash_en()) {
mdp3_session->clk_on = 1;
+ mdp3_ctrl_notifier_register(mdp3_session,
+ &mdp3_session->mfd->mdp_sync_pt_data.notifier);
+ }
if (splash_mismatch) {
pr_err("splash memory mismatch, stop splash\n");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index f2484ef..cfad1d3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -49,6 +49,7 @@
struct mdp3_buffer_queue bufq_in;
struct mdp3_buffer_queue bufq_out;
struct work_struct clk_off_work;
+ struct work_struct dma_done_work;
int histo_status;
struct mutex histo_lock;
int lut_sel;
@@ -56,6 +57,7 @@
bool vsync_before_commit;
bool first_commit;
int clk_on;
+ struct blocking_notifier_head notifier_head;
int vsync_enabled;
atomic_t vsync_countdown; /* Used to count down */
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index ae7598f..5cae2de 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -27,7 +27,7 @@
static void mdp3_vsync_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
unsigned int wait_for_next_vs;
pr_debug("mdp3_vsync_intr_handler\n");
@@ -49,10 +49,16 @@
static void mdp3_dma_done_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
+ struct mdp3_notification dma_client;
pr_debug("mdp3_dma_done_intr_handler\n");
+ spin_lock(&dma->dma_lock);
+ dma_client = dma->dma_notifier_client;
complete(&dma->dma_comp);
+ spin_unlock(&dma->dma_lock);
mdp3_irq_disable_nosync(type);
+ if (dma_client.handler)
+ dma_client.handler(dma_client.arg);
}
static void mdp3_hist_done_intr_handler(int type, void *arg)
@@ -195,7 +201,7 @@
}
static void mdp3_dma_vsync_enable(struct mdp3_dma *dma,
- struct mdp3_vsync_notification *vsync_client)
+ struct mdp3_notification *vsync_client)
{
unsigned long flag;
int updated = 0;
@@ -226,6 +232,21 @@
}
}
+static void mdp3_dma_done_notifier(struct mdp3_dma *dma,
+ struct mdp3_notification *dma_client)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dma->dma_lock, flag);
+ if (dma_client) {
+ dma->dma_notifier_client = *dma_client;
+ } else {
+ dma->dma_notifier_client.handler = NULL;
+ dma->dma_notifier_client.arg = NULL;
+ }
+ spin_unlock_irqrestore(&dma->dma_lock, flag);
+}
+
static void mdp3_dma_clk_auto_gating(struct mdp3_dma *dma, int enable)
{
u32 cgc;
@@ -552,13 +573,20 @@
{
unsigned long flag;
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+ int rc = 0;
pr_debug("mdp3_dmap_update\n");
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
- if (intf->active)
- wait_for_completion_killable(&dma->dma_comp);
+ if (intf->active) {
+ rc = wait_for_completion_timeout(&dma->dma_comp,
+ KOFF_TIMEOUT);
+ if (rc <= 0) {
+ WARN(1, "cmd kickoff timed out (%d)\n", rc);
+ rc = -1;
+ }
+ }
}
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
@@ -581,10 +609,14 @@
mdp3_dma_callback_enable(dma, cb_type);
pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
- if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
- wait_for_completion_killable(&dma->vsync_comp);
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+ rc = wait_for_completion_timeout(&dma->vsync_comp,
+ KOFF_TIMEOUT);
+ if (rc <= 0)
+ rc = -1;
+ }
pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
- return 0;
+ return rc;
}
static int mdp3_dmas_update(struct mdp3_dma *dma, void *buf,
@@ -878,6 +910,7 @@
dma->get_histo = mdp3_dmap_histo_get;
dma->histo_op = mdp3_dmap_histo_op;
dma->vsync_enable = mdp3_dma_vsync_enable;
+ dma->dma_done_notifier = mdp3_dma_done_notifier;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
dma->config_stride = mdp3_dma_stride_config;
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 6ad4c79..04955d4 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -14,6 +14,7 @@
#ifndef MDP3_DMA_H
#define MDP3_DMA_H
+#include <linux/notifier.h>
#include <linux/sched.h>
#define MDP_HISTOGRAM_BL_SCALE_MAX 1024
@@ -227,7 +228,7 @@
u32 extra[2];
};
-struct mdp3_vsync_notification {
+struct mdp3_notification {
void (*handler)(void *arg);
void *arg;
};
@@ -245,7 +246,8 @@
struct completion vsync_comp;
struct completion dma_comp;
struct completion histo_comp;
- struct mdp3_vsync_notification vsync_client;
+ struct mdp3_notification vsync_client;
+ struct mdp3_notification dma_notifier_client;
struct mdp3_dma_output_config output_config;
struct mdp3_dma_source source_config;
@@ -291,7 +293,10 @@
void (*config_stride)(struct mdp3_dma *dma, int stride);
void (*vsync_enable)(struct mdp3_dma *dma,
- struct mdp3_vsync_notification *vsync_client);
+ struct mdp3_notification *vsync_client);
+
+ void (*dma_done_notifier)(struct mdp3_dma *dma,
+ struct mdp3_notification *dma_client);
};
struct mdp3_video_intf_cfg {
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index f6256e7..3c7d17c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -19,7 +19,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/leds.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
#include <linux/err.h>
#include "mdss_dsi.h"
@@ -69,9 +69,9 @@
ctrl->pwm_enabled = 0;
}
- ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
+ ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period);
if (ret) {
- pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+ pr_err("%s: pwm_config_us() failed err=%d.\n", __func__, ret);
return;
}
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index bb27e6b..6dbca10 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -23,7 +23,7 @@
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/regulator/consumer.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
#include <linux/clk.h>
#include <linux/spinlock_types.h>
#include <linux/kthread.h>
@@ -210,11 +210,11 @@
if (bl_level > bl_max)
bl_level = bl_max;
- ret = pwm_config(edp_drv->bl_pwm,
+ ret = pwm_config_us(edp_drv->bl_pwm,
bl_level * edp_drv->pwm_period / bl_max,
edp_drv->pwm_period);
if (ret) {
- pr_err("%s: pwm_config() failed err=%d.\n", __func__,
+ pr_err("%s: pwm_config_us() failed err=%d.\n", __func__,
ret);
return;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 94b2cbd..54e3bc8 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1836,11 +1836,11 @@
int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
{
- int ret = -EINVAL;
+ int ret = 0;
if (req_state == mfd->dcm_state) {
- pr_warn("Already in correct DCM state");
- ret = 0;
+ pr_warn("Already in correct DCM/DTM state");
+ return ret;
}
switch (req_state) {
@@ -1856,11 +1856,12 @@
break;
case DCM_ENTER:
if (mfd->dcm_state == DCM_UNBLANK) {
- /* Keep unblank path available for only
- DCM operation */
+ /*
+ * Keep unblank path available for only
+ * DCM operation
+ */
mfd->panel_power_on = false;
mfd->dcm_state = DCM_ENTER;
- ret = 0;
}
break;
case DCM_EXIT:
@@ -1868,7 +1869,6 @@
/* Release the unblank path for exit */
mfd->panel_power_on = true;
mfd->dcm_state = DCM_EXIT;
- ret = 0;
}
break;
case DCM_BLANK:
@@ -1882,7 +1882,16 @@
}
}
break;
+ case DTM_ENTER:
+ if (mfd->dcm_state == DCM_UNINIT)
+ mfd->dcm_state = DTM_ENTER;
+ break;
+ case DTM_EXIT:
+ if (mfd->dcm_state == DTM_ENTER)
+ mfd->dcm_state = DCM_UNINIT;
+ break;
}
+
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index f73b583..d57e4fb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1913,8 +1913,10 @@
if (ctl->wait_pingpong)
ctl->wait_pingpong(ctl, NULL);
- /* postprocessing setup, including dspp */
- mdss_mdp_pp_setup_locked(ctl);
+ if (ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
+ /* postprocessing setup, including dspp */
+ mdss_mdp_pp_setup_locked(ctl);
+
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
if (sctl) {
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index b6f94d0..bcd3cf4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -108,7 +108,9 @@
MDSS_MDP_MAX_CTL
};
-#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
+#define MDSS_MDP_CTL_ADDRESS_OFFSET 0x100
+#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * \
+ MDSS_MDP_CTL_ADDRESS_OFFSET))
#define MDSS_MDP_REG_CTL_LAYER(lm) ((lm) * 0x004)
#define MDSS_MDP_REG_CTL_TOP 0x014
@@ -159,7 +161,10 @@
MDSS_MDP_CHROMA_420
};
-#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
+
+#define MDSS_MDP_SSPP_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * \
+ MDSS_MDP_SSPP_ADDRESS_OFFSET))
#define MDSS_MDP_REG_SSPP_SRC_SIZE 0x000
#define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE 0x004
@@ -175,6 +180,7 @@
#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C
#define MDSS_MDP_REG_SSPP_SRC_FORMAT 0x030
#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034
+#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR 0x03C
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0 0x050
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1 0x054
#define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2 0x058
@@ -280,8 +286,9 @@
MDSS_MDP_MAX_STAGE
};
-#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
-
+#define MDSS_MDP_LM_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * \
+ MDSS_MDP_LM_ADDRESS_OFFSET))
#define MDSS_MDP_REG_LM_OP_MODE 0x000
#define MDSS_MDP_REG_LM_OUT_SIZE 0x004
#define MDSS_MDP_REG_LM_BORDER_COLOR_0 0x008
@@ -423,7 +430,9 @@
MDSS_MDP_MAX_DSPP
};
-#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * 0x400))
+#define MDSS_MDP_DSPP_ADDRESS_OFFSET 0x400
+#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * \
+ MDSS_MDP_DSPP_ADDRESS_OFFSET))
#define MDSS_MDP_REG_DSPP_OP_MODE 0x000
#define MDSS_MDP_REG_DSPP_PCC_BASE 0x030
#define MDSS_MDP_REG_DSPP_DITHER_DEPTH 0x150
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index d0d2157..555974b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -173,6 +173,13 @@
GAMUT_T2_SIZE + GAMUT_T3_SIZE + GAMUT_T4_SIZE + \
GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
+#define MDSS_MDP_PA_SIZE 0xC
+#define MDSS_MDP_GC_SIZE 0x28
+#define MDSS_MDP_PCC_SIZE 0xB8
+#define MDSS_MDP_GAMUT_SIZE 0x5C
+#define MDSS_MDP_IGC_DSPP_COLORS 0x3
+#define TOTAL_BLEND_STAGES 0x4
+
#define PP_FLAGS_DIRTY_PA 0x1
#define PP_FLAGS_DIRTY_PCC 0x2
#define PP_FLAGS_DIRTY_IGC 0x4
@@ -1727,11 +1734,13 @@
if (mdss_pp_res == NULL) {
pr_err("%s mdss_pp_res allocation failed!", __func__);
ret = -ENOMEM;
- }
-
- for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
- mutex_init(&mdss_pp_res->dspp_hist[i].hist_mutex);
- spin_lock_init(&mdss_pp_res->dspp_hist[i].hist_lock);
+ } else {
+ for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
+ mutex_init(
+ &mdss_pp_res->dspp_hist[i].hist_mutex);
+ spin_lock_init(
+ &mdss_pp_res->dspp_hist[i].hist_lock);
+ }
}
}
if (mdata) {
@@ -4434,71 +4443,271 @@
return rc;
}
-static int is_valid_calib_addr(void *addr)
+static int is_valid_calib_ctrl_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ int stage = 0;
+ struct mdss_mdp_ctl *ctl;
+
+ /* Controller */
+ for (counter = 0; counter < mdss_res->nctl; counter++) {
+ ctl = mdss_res->ctl_off + counter;
+ base = ctl->base;
+
+ if (ptr == base + MDSS_MDP_REG_CTL_TOP) {
+ ret = MDP_PP_OPS_READ;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_CTL_FLUSH) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+
+ for (stage = 0; stage < mdss_res->nmixers_intf; stage++)
+ if (ptr == base + MDSS_MDP_REG_CTL_LAYER(stage)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ }
+ }
+
+End:
+ return ret;
+}
+
+static int is_valid_calib_dspp_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_mixer *mixer;
+
+ for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+ mixer = mdss_res->mixer_intf + counter;
+ base = mixer->dspp_base;
+
+ if (ptr == base) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PA range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_PA_BASE +
+ MDSS_MDP_PA_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PCC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PCC_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_PCC_BASE +
+ MDSS_MDP_PCC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Gamut range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GAMUT_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_GAMUT_BASE +
+ MDSS_MDP_GAMUT_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* GC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GC_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_DSPP_GC_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* Dither enable/disable */
+ } else if ((ptr == base + MDSS_MDP_REG_DSPP_DITHER_DEPTH)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_vig_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->nvig_pipes; counter++) {
+ pipe = mdss_res->vig_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if ((ptr == base + MDSS_MDP_REG_VIG_QSEED2_SHARP)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* PA range */
+ } else if ((ptr >= base + MDSS_MDP_REG_VIG_PA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_VIG_PA_BASE +
+ MDSS_MDP_PA_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_VIG_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_VIG_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_rgb_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->nrgb_pipes; counter++) {
+ pipe = mdss_res->rgb_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_RGB_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_RGB_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_dma_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ struct mdss_mdp_pipe *pipe;
+
+ for (counter = 0; counter < mdss_res->ndma_pipes; counter++) {
+ pipe = mdss_res->dma_pipes + counter;
+ base = pipe->base;
+
+ if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* IGC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_IGC_DMA_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_IGC_DMA_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int is_valid_calib_mixer_addr(char __iomem *ptr)
+{
+ char __iomem *base;
+ int ret = 0, counter = 0;
+ int stage = 0;
+ struct mdss_mdp_mixer *mixer;
+
+ for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+ mixer = mdss_res->mixer_intf + counter;
+ base = mixer->base;
+
+ if (ptr == base + MDSS_MDP_REG_LM_OP_MODE) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ /* GC range */
+ } else if ((ptr >= base + MDSS_MDP_REG_LM_GC_LUT_BASE) &&
+ (ptr <= base + MDSS_MDP_REG_LM_GC_LUT_BASE +
+ MDSS_MDP_GC_SIZE)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ break;
+ }
+
+ for (stage = 0; stage < TOTAL_BLEND_STAGES; stage++)
+ if (ptr == base + MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_OP) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ } else if (ptr == base +
+ MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_FG_ALPHA) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ } else if (ptr == base +
+ MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+ MDSS_MDP_REG_LM_BLEND_BG_ALPHA) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ goto End;
+ }
+ }
+
+End:
+ return ret;
+}
+
+static int is_valid_calib_addr(void *addr, u32 operation)
{
int ret = 0;
- unsigned int ptr;
- ptr = (unsigned int) addr;
- /* if request is outside the MDP reg-map or is not aligned 4 */
- if (ptr > 0x5138 || ptr % 0x4)
- goto end;
- if (ptr >= 0x100 && ptr <= 0x5138) {
- /* if ptr is in dspp range */
- if (ptr >= 0x4600 && ptr <= 0x5138) {
- /* if ptr is in dspp0 range*/
- if (ptr >= 0x4600 && ptr <= 0x4938)
- ptr -= 0x4600;
- /* if ptr is in dspp1 range */
- else if (ptr >= 0x4a00 && ptr <= 0x4d38)
- ptr -= 0x4a00;
- /* if ptr is in dspp2 range */
- else if (ptr >= 0x4e00 && ptr <= 0x5138)
- ptr -= 0x4e00;
- /* if ptr is in pcc plane rgb coeff.range */
- if (ptr >= 0x30 && ptr <= 0xe8)
- ret = 1;
- /* if ptr is in ARLUT red range */
- else if (ptr >= 0x2b0 && ptr <= 0x2b8)
- ret = 1;
- /* if ptr is in PA range */
- else if (ptr >= 0x238 && ptr <= 0x244)
- ret = 1;
- /* if ptr is in ARLUT green range */
- else if (ptr >= 0x2c0 && ptr <= 0x2c8)
- ret = 1;
- /* if ptr is in ARLUT blue range or
- gamut map table range */
- else if (ptr >= 0x2d0 && ptr <= 0x338)
- ret = 1;
- /* if ptr is dspp0,dspp1,dspp2 op mode
- register */
- else if (ptr == 0)
- ret = 1;
- } else if (ptr >= 0x600 && ptr <= 0x608)
- ret = 1;
- else if (ptr >= 0x400 && ptr <= 0x408)
- ret = 1;
- else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
- (ptr == 0x1430) || (ptr == 0x1e38))
- ret = 1;
- else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
- ret = 1;
- else if (ptr >= 0x3220 && ptr <= 0x3228)
- ret = 1;
- else if (ptr == 0x3200 || ptr == 0x100)
- ret = 1;
- else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
- ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
- ret = 1;
- else if (ptr == 0x618 || ptr == 0x718 || ptr == 0x818 ||
- ptr == 0x918 || ptr == 0xa18)
- ret = 1;
- else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
- ret = 1;
- } else if (ptr == 0x0)
- ret = 1;
-end:
- return ret;
+ char __iomem *ptr = addr;
+ char __iomem *mixer_base = mdss_res->mixer_intf->base;
+ char __iomem *rgb_base = mdss_res->rgb_pipes->base;
+ char __iomem *dma_base = mdss_res->dma_pipes->base;
+ char __iomem *vig_base = mdss_res->vig_pipes->base;
+ char __iomem *ctl_base = mdss_res->ctl_off->base;
+ char __iomem *dspp_base = mdss_res->mixer_intf->dspp_base;
+
+ if ((unsigned int)addr % 4) {
+ ret = 0;
+ } else if (ptr == (mdss_res->mdp_base + MDSS_MDP_REG_HW_VERSION) ||
+ ptr == (mdss_res->mdp_base + MDSS_MDP_REG_DISP_INTF_SEL)) {
+ ret = MDP_PP_OPS_READ;
+ } else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE) &&
+ ptr < (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
+ MDSS_MDP_IGC_DSPP_COLORS)) {
+ ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+ } else if (ptr >= dspp_base && ptr < (dspp_base +
+ (mdss_res->nmixers_intf * MDSS_MDP_DSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_dspp_addr(ptr);
+ } else if (ptr >= ctl_base && ptr < (ctl_base + (mdss_res->nctl
+ * MDSS_MDP_CTL_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_ctrl_addr(ptr);
+ } else if (ptr >= vig_base && ptr < (vig_base + (mdss_res->nvig_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_vig_addr(ptr);
+ } else if (ptr >= rgb_base && ptr < (rgb_base + (mdss_res->nrgb_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_rgb_addr(ptr);
+ } else if (ptr >= dma_base && ptr < (dma_base + (mdss_res->ndma_pipes
+ * MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_dma_addr(ptr);
+ } else if (ptr >= mixer_base && ptr < (mixer_base +
+ (mdss_res->nmixers_intf * MDSS_MDP_LM_ADDRESS_OFFSET))) {
+ ret = is_valid_calib_mixer_addr(ptr);
+ }
+
+ return ret & operation;
}
int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
@@ -4506,11 +4715,12 @@
int ret = -1;
void *ptr = (void *) cfg->addr;
- if (is_valid_calib_addr(ptr))
+ ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+ if (is_valid_calib_addr(ptr, cfg->ops))
ret = 0;
else
return ret;
- ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (cfg->ops & MDP_PP_OPS_READ) {
@@ -4545,65 +4755,50 @@
int i = 0;
if (!cfg) {
- pr_err("Invalid buffer pointer");
+ pr_err("Invalid buffer pointer\n");
return ret;
}
- if (cfg->size == 0 || cfg->size > PAGE_SIZE) {
- pr_err("Invalid buffer size %d", cfg->size);
+ if (cfg->size == 0) {
+ pr_err("Invalid buffer size\n");
return ret;
}
counter = cfg->size / (sizeof(uint32_t) * 2);
buff_org = buff = kzalloc(cfg->size, GFP_KERNEL);
if (buff == NULL) {
- pr_err("Allocation failed");
+ pr_err("Config buffer allocation failed\n");
return ret;
}
if (copy_from_user(buff, cfg->buffer, cfg->size)) {
kfree(buff);
- pr_err("Copy failed");
+ pr_err("config buffer copy failed\n");
return ret;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- if (cfg->ops & MDP_PP_OPS_READ) {
- for (i = 0 ; i < counter ; i++) {
- if (is_valid_calib_addr((void *) *buff)) {
- ret = 0;
- } else {
- ret = -1;
- pr_err("Address validation failed");
- break;
- }
+ for (i = 0; i < counter; i++) {
+ ptr = (void *) (((unsigned int) *buff) + mdss_res->mdp_base);
- ptr = (void *)(((unsigned int) *buff) +
- (mdss_res->mdp_base));
- buff++;
+ if (!is_valid_calib_addr(ptr, cfg->ops)) {
+ ret = -1;
+ pr_err("Address validation failed or access not permitted\n");
+ break;
+ }
+
+ buff++;
+ if (cfg->ops & MDP_PP_OPS_READ)
*buff = readl_relaxed(ptr);
- buff++;
- }
- if (!ret)
- ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
- *copyback = 1;
- } else if (cfg->ops & MDP_PP_OPS_WRITE) {
- for (i = 0 ; i < counter ; i++) {
- if (is_valid_calib_addr((void *) *buff)) {
- ret = 0;
- } else {
- ret = -1;
- pr_err("Address validation failed");
- break;
- }
-
- ptr = (void *)(((unsigned int) *buff) +
- (mdss_res->mdp_base));
- buff++;
+ else if (cfg->ops & MDP_PP_OPS_WRITE)
writel_relaxed(*buff, ptr);
- buff++;
- }
+ buff++;
+ }
+
+ if (ret & MDP_PP_OPS_READ) {
+ ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
+ *copyback = 1;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 329b58e..4640d3b 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -99,7 +99,6 @@
header-y += connector.h
header-y += const.h
header-y += cramfs_fs.h
-header-y += csdio.h
header-y += cuda.h
header-y += cyclades.h
header-y += cycx_cfm.h
diff --git a/include/linux/csdio.h b/include/linux/csdio.h
deleted file mode 100644
index 260c49d..0000000
--- a/include/linux/csdio.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef CSDIO_H
-#define CSDIO_H
-
-#include <linux/ioctl.h>
-
-#define CSDIO_IOC_MAGIC 'm'
-
-#define CSDIO_IOC_ENABLE_HIGHSPEED_MODE _IO(CSDIO_IOC_MAGIC, 0)
-#define CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS _IO(CSDIO_IOC_MAGIC, 1)
-#define CSDIO_IOC_SET_OP_CODE _IO(CSDIO_IOC_MAGIC, 2)
-#define CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE _IO(CSDIO_IOC_MAGIC, 3)
-#define CSDIO_IOC_SET_BLOCK_MODE _IO(CSDIO_IOC_MAGIC, 4)
-#define CSDIO_IOC_CONNECT_ISR _IO(CSDIO_IOC_MAGIC, 5)
-#define CSDIO_IOC_DISCONNECT_ISR _IO(CSDIO_IOC_MAGIC, 6)
-#define CSDIO_IOC_CMD52 _IO(CSDIO_IOC_MAGIC, 7)
-#define CSDIO_IOC_CMD53 _IO(CSDIO_IOC_MAGIC, 8)
-#define CSDIO_IOC_ENABLE_ISR _IO(CSDIO_IOC_MAGIC, 9)
-#define CSDIO_IOC_DISABLE_ISR _IO(CSDIO_IOC_MAGIC, 10)
-#define CSDIO_IOC_SET_VDD _IO(CSDIO_IOC_MAGIC, 11)
-#define CSDIO_IOC_GET_VDD _IO(CSDIO_IOC_MAGIC, 12)
-
-#define CSDIO_IOC_MAXNR 12
-
-struct csdio_cmd53_ctrl_t {
- uint32_t m_block_mode; /* data tran. byte(0)/block(1) mode */
- uint32_t m_op_code; /* address auto increment flag */
- uint32_t m_address;
-} __attribute__ ((packed));
-
-struct csdio_cmd52_ctrl_t {
- uint32_t m_write;
- uint32_t m_address;
- uint32_t m_data;
- uint32_t m_ret;
-} __attribute__ ((packed));
-
-#endif
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 4903939..0791545 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -800,6 +800,8 @@
DCM_ENTER,
DCM_EXIT,
DCM_BLANK,
+ DTM_ENTER,
+ DTM_EXIT,
};
#define MDSS_PP_SPLIT_LEFT_ONLY 0x10000000
diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h
index bf7908b..50fb2e5 100644
--- a/include/linux/qpnp/pwm.h
+++ b/include/linux/qpnp/pwm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -146,6 +146,12 @@
int pwm_lut_config(struct pwm_device *pwm, int period_us,
int duty_pct[], struct lut_params lut_params);
+/*
+ * support microsecond level configuration
+ */
+int pwm_config_us(struct pwm_device *pwm,
+ int duty_us, int period_us);
+
/* Standard APIs supported */
/*
* pwm_request - request a PWM device
@@ -161,8 +167,8 @@
/*
* pwm_config - change a PWM device configuration
* @pwm: the PWM device
- * @period_us: period in microsecond
- * @duty_us: duty cycle in microsecond
+ * @period_ns: period in nanosecond
+ * @duty_ns: duty cycle in nanosecond
*/
/*
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 6f121b3..5941f71 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -31,7 +31,7 @@
int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
int adm_open(int port, int path, int rate, int mode, int topology,
- bool perf_mode, uint16_t bits_per_sample);
+ int perf_mode, uint16_t bits_per_sample);
int adm_get_params(int port_id, uint32_t module_id, uint32_t param_id,
uint32_t params_length, char *params);
@@ -40,7 +40,7 @@
uint32_t params_length);
int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
- int topology, bool perf_mode, uint16_t bits_per_sample);
+ int topology, int perf_mode, uint16_t bits_per_sample);
int adm_unmap_cal_blocks(void);
@@ -53,10 +53,10 @@
int adm_memory_unmap_regions(int port_id);
-int adm_close(int port, bool perf_mode);
+int adm_close(int port, int perf_mode);
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id, bool perf_mode);
+ unsigned int *port_id, int copp_id, int perf_mode);
int adm_connect_afe_port(int mode, int session_id, int port_id);
@@ -64,6 +64,8 @@
int adm_get_copp_id(int port_id);
+int adm_get_lowlatency_copp_id(int port_id);
+
void adm_set_multi_ch_map(char *channel_map);
void adm_get_multi_ch_map(char *channel_map);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index b00cfc9..a78c333 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -175,7 +175,7 @@
struct audio_port_data port[2];
wait_queue_head_t cmd_wait;
wait_queue_head_t time_wait;
- bool perf_mode;
+ int perf_mode;
int stream_id;
/* audio cache operations fptr*/
int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
index fd6a490..8ac835c 100644
--- a/include/sound/q6audio-v2.h
+++ b/include/sound/q6audio-v2.h
@@ -15,6 +15,13 @@
#include <mach/qdsp6v2/apr.h>
+enum {
+ LEGACY_PCM_MODE = 0,
+ LOW_LATENCY_PCM_MODE,
+ ULTRA_LOW_LATENCY_PCM_MODE,
+};
+
+
int q6audio_get_port_index(u16 port_id);
int q6audio_convert_virtual_to_portid(u16 port_id);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index fa8a793..e174693 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -184,6 +184,36 @@
return ret;
}
+#ifdef ENABLE_VMALLOC_SAVING
+int is_vmalloc_addr(const void *x)
+{
+ struct rb_node *n;
+ struct vmap_area *va;
+ int ret = 0;
+
+ spin_lock(&vmap_area_lock);
+
+ for (n = rb_first(vmap_area_root); n; rb_next(n)) {
+ va = rb_entry(n, struct vmap_area, rb_node);
+ if (x >= va->va_start && x < va->va_end) {
+ ret = 1;
+ break;
+ }
+ }
+
+ spin_unlock(&vmap_area_lock);
+ return ret;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
int is_vmalloc_or_module_addr(const void *x)
{
/*
@@ -272,47 +302,6 @@
static unsigned long vmap_area_pcpu_hole;
-#ifdef CONFIG_ENABLE_VMALLOC_SAVING
-int is_vmalloc_addr(const void *x)
-{
- struct vmap_area *va;
- int ret = 0;
-
- spin_lock(&vmap_area_lock);
- list_for_each_entry(va, &vmap_area_list, list) {
- if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING))
- continue;
-
- if (!(va->flags & VM_VM_AREA))
- continue;
-
- if (va->vm == NULL)
- continue;
-
- if (va->vm->flags & VM_LOWMEM)
- continue;
-
- if ((unsigned long)x >= va->va_start &&
- (unsigned long)x < va->va_end) {
- ret = 1;
- break;
- }
- }
- spin_unlock(&vmap_area_lock);
- return ret;
-}
-#else
-int is_vmalloc_addr(const void *x)
-{
- unsigned long addr = (unsigned long)x;
-
- return addr >= VMALLOC_START && addr < VMALLOC_END;
-}
-#endif
-EXPORT_SYMBOL(is_vmalloc_addr);
-
-
-
static struct vmap_area *__find_vmap_area(unsigned long addr)
{
struct rb_node *n = vmap_area_root.rb_node;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bddb720..b094741 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1510,8 +1510,8 @@
if (wiphy_idx_valid(reg_request->wiphy_idx))
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
- if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER &&
- !wiphy) {
+ if ((reg_initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+ reg_initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) && !wiphy) {
kfree(reg_request);
return;
}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index c62f875..f874c43 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -3404,6 +3404,7 @@
TAIKO_A_TX_7_MBHC_EN, 0x80, 00);
ret |= taiko_codec_enable_anc(w, kcontrol, event);
}
+ break;
case SND_SOC_DAPM_POST_PMD:
ret = taiko_hph_pa_event(w, kcontrol, event);
break;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 69a6671..4c3a72e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2203,6 +2203,22 @@
.codec_name = "snd-soc-dummy",
},
{
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
+ .platform_name = "msm-pcm-voice",
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICE2,
+ },
+ {
.name = "INT_HFP_BT Hostless",
.stream_name = "INT_HFP_BT Hostless",
.cpu_dai_name = "INT_HFP_BT_HOSTLESS",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index f25f746..3ddc3e0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -25,6 +25,7 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/q6audio-v2.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/msm_audio_ion.h>
@@ -916,11 +917,12 @@
int rc;
int id;
struct msm_plat_data *pdata;
+ const char *latency_level;
rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-pcm-dsp-id", &id);
+ "qti,msm-pcm-dsp-id", &id);
if (rc) {
- dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
+ dev_err(&pdev->dev, "%s: qti,msm-pcm-dsp-id missing in DT node\n",
__func__);
return rc;
}
@@ -932,10 +934,17 @@
}
if (of_property_read_bool(pdev->dev.of_node,
- "qcom,msm-pcm-low-latency"))
- pdata->perf_mode = 1;
- else
- pdata->perf_mode = 0;
+ "qti,msm-pcm-low-latency")) {
+
+ pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+ rc = of_property_read_string(pdev->dev.of_node,
+ "qti,latency-level", &latency_level);
+ if (!rc) {
+ if (!strcmp(latency_level, "ultra"))
+ pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ }
+ } else
+ pdata->perf_mode = LEGACY_PCM_MODE;
dev_set_drvdata(&pdev->dev, pdata);
@@ -957,7 +966,7 @@
return 0;
}
static const struct of_device_id msm_pcm_dt_match[] = {
- {.compatible = "qcom,msm-pcm-dsp"},
+ {.compatible = "qti,msm-pcm-dsp"},
{}
};
MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 711291da..91c0744 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -290,7 +290,7 @@
/* Track performance mode of all front-end multimedia sessions.
* Performance mode is only valid when session is valid.
*/
-static bool fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
+static int fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
static uint8_t is_be_dai_extproc(int be_dai)
{
@@ -303,7 +303,7 @@
}
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
- int path_type, bool perf_mode)
+ int path_type, int perf_mode)
{
int i, port_type;
struct route_payload payload;
@@ -365,7 +365,7 @@
mutex_unlock(&routing_lock);
}
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
int dspst_id, int stream_type)
{
int i, session_type, path_type, port_type, port_id, topology;
@@ -437,7 +437,7 @@
port_id = srs_port_id = msm_bedais[i].port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (!perf_mode))
+ (perf_mode == LEGACY_PCM_MODE))
if (dolby_dap_init(port_id,
msm_bedais[i].channel) < 0)
pr_err("%s: Err init dolby dap\n",
@@ -494,7 +494,8 @@
adm_close(msm_bedais[i].port_id,
fe_dai_perf_mode[fedai_id][session_type]);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[fedai_id][session_type] == false))
+ (fe_dai_perf_mode[fedai_id][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(msm_bedais[i].port_id);
}
}
@@ -604,7 +605,8 @@
port_id = srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[val][session_type] == false))
+ (fe_dai_perf_mode[val][session_type] ==
+ LEGACY_PCM_MODE))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
@@ -621,7 +623,8 @@
adm_close(msm_bedais[reg].port_id,
fe_dai_perf_mode[val][session_type]);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[val][session_type] == false))
+ (fe_dai_perf_mode[val][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
fdai->strm_id, path_type,
@@ -3960,7 +3963,8 @@
fe_dai_perf_mode[i][session_type]);
srs_port_id = -1;
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[i][session_type] == false))
+ (fe_dai_perf_mode[i][session_type] ==
+ LEGACY_PCM_MODE))
dolby_dap_deinit(bedai->port_id);
}
}
@@ -4060,7 +4064,8 @@
port_id = srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
- (fe_dai_perf_mode[i][session_type] == false))
+ (fe_dai_perf_mode[i][session_type] ==
+ LEGACY_PCM_MODE))
if (dolby_dap_init(port_id, channels) < 0)
pr_err("%s: Err init dolby dap\n",
__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4f7c4e3..54f5e4a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -143,7 +143,7 @@
* dspst_id: DSP audio stream ID
* stream_type: playback or capture
*/
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id,
int stream_type);
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
int stream_type);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 6cb7ce1..54b1263 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -702,7 +702,8 @@
return;
}
-static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal,
+ int perf_mode)
{
s32 result = 0;
struct adm_cmd_set_pp_params_v5 adm_params;
@@ -731,7 +732,14 @@
adm_params.hdr.src_port = port_id;
adm_params.hdr.dest_svc = APR_SVC_ADM;
adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
- adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+
+ if (perf_mode == LEGACY_PCM_MODE)
+ adm_params.hdr.dest_port =
+ atomic_read(&this_adm.copp_id[index]);
+ else
+ adm_params.hdr.dest_port =
+ atomic_read(&this_adm.copp_low_latency_id[index]);
+
adm_params.hdr.token = port_id;
adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
adm_params.payload_addr_lsw = aud_cal->cal_paddr;
@@ -767,7 +775,7 @@
return result;
}
-static void send_adm_cal(int port_id, int path)
+static void send_adm_cal(int port_id, int path, int perf_mode)
{
int result = 0;
s32 acdb_path;
@@ -808,7 +816,7 @@
}
}
- if (!send_adm_cal_block(port_id, &aud_cal))
+ if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
pr_debug("%s: Audproc cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
@@ -842,7 +850,7 @@
}
}
- if (!send_adm_cal_block(port_id, &aud_cal))
+ if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
pr_debug("%s: Audvol cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
@@ -1048,7 +1056,7 @@
}
int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
- bool perf_mode, uint16_t bits_per_sample)
+ int perf_mode, uint16_t bits_per_sample)
{
struct adm_cmd_device_open_v5 open;
int ret = 0;
@@ -1079,7 +1087,7 @@
rtac_set_adm_handle(this_adm.apr);
}
- if (!perf_mode) {
+ if (perf_mode == LEGACY_PCM_MODE) {
atomic_set(&this_adm.copp_perf_mode[index], 0);
send_adm_custom_topology(port_id);
} else {
@@ -1087,8 +1095,9 @@
}
/* Create a COPP if port id are not enabled */
- if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
- (perf_mode &&
+ if ((perf_mode == LEGACY_PCM_MODE &&
+ (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+ (perf_mode != LEGACY_PCM_MODE &&
(atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
perf_mode);
@@ -1103,12 +1112,12 @@
open.hdr.dest_port = tmp_port;
open.hdr.token = port_id;
open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
- open.flags = 0x00;
- if (perf_mode) {
- open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
- } else {
- open.flags |= ADM_LEGACY_DEVICE_SESSION;
- }
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
+ open.flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
+ else if (perf_mode == LOW_LATENCY_PCM_MODE)
+ open.flags = ADM_LOW_LATENCY_DEVICE_SESSION;
+ else
+ open.flags = ADM_LEGACY_DEVICE_SESSION;
open.mode_of_operation = path;
open.endpoint_id_1 = tmp_port;
@@ -1125,7 +1134,7 @@
(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
rate = 16000;
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
open.topology_id = NULL_COPP_TOPOLOGY;
rate = ULL_SUPPORTED_SAMPLE_RATE;
if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
@@ -1133,7 +1142,8 @@
}
open.dev_num_channel = channel_mode & 0x00FF;
open.bit_width = bits_per_sample;
- WARN_ON(perf_mode && (rate != 48000));
+ WARN_ON(perf_mode == ULTRA_LOW_LATENCY_PCM_MODE &&
+ (rate != 48000));
open.sample_rate = rate;
memset(open.dev_channel_mapping, 0, 8);
@@ -1208,7 +1218,8 @@
goto fail_cmd;
}
}
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
atomic_inc(&this_adm.copp_low_latency_cnt[index]);
pr_debug("%s: index: %d coppid: %d", __func__, index,
atomic_read(&this_adm.copp_low_latency_id[index]));
@@ -1225,7 +1236,7 @@
}
int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
- int topology, bool perf_mode, uint16_t bits_per_sample)
+ int topology, int perf_mode, uint16_t bits_per_sample)
{
int ret = 0;
@@ -1236,7 +1247,7 @@
}
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id, bool perf_mode)
+ unsigned int *port_id, int copp_id, int perf_mode)
{
struct adm_cmd_matrix_map_routings_v5 *route;
struct adm_session_map_node_v5 *node;
@@ -1275,7 +1286,8 @@
route->hdr.src_port = copp_id;
route->hdr.dest_svc = APR_SVC_ADM;
route->hdr.dest_domain = APR_DOMAIN_ADSP;
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
route->hdr.dest_port =
atomic_read(&this_adm.copp_low_latency_id[index]);
} else {
@@ -1313,7 +1325,8 @@
if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
- if (perf_mode)
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE)
copps_list[i] =
atomic_read(&this_adm.copp_low_latency_id[tmp]);
else
@@ -1323,8 +1336,7 @@
else
continue;
pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
- __func__, i, port_id[i], tmp,
- atomic_read(&this_adm.copp_id[tmp]));
+ __func__, i, port_id[i], tmp, copps_list[i]);
}
atomic_set(&this_adm.copp_stat[index], 0);
@@ -1344,25 +1356,31 @@
ret = -EINVAL;
goto fail_cmd;
}
- if (!perf_mode) {
+
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
for (i = 0; i < num_copps; i++)
- send_adm_cal(port_id[i], path);
+ send_adm_cal(port_id[i], path, perf_mode);
for (i = 0; i < num_copps; i++) {
- int tmp;
+ int tmp, copp_id;
tmp = afe_get_port_index(port_id[i]);
if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ if (perf_mode == LEGACY_PCM_MODE)
+ copp_id = atomic_read(
+ &this_adm.copp_id[tmp]);
+ else
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[tmp]);
rtac_add_adm_device(port_id[i],
- atomic_read(&this_adm.copp_id[tmp]),
- path, session_id);
- pr_debug("%s, copp_id: %d\n", __func__,
- atomic_read(&this_adm.copp_id[tmp]));
- } else {
+ copp_id, path, session_id);
+ pr_debug("%s, copp_id: %d\n",
+ __func__, copp_id);
+ } else
pr_debug("%s: Invalid port index %d",
- __func__, tmp);
- }
+ __func__, tmp);
}
}
+
fail_cmd:
kfree(matrix_map);
return ret;
@@ -1514,8 +1532,26 @@
return ret;
}
+#ifdef CONFIG_RTAC
int adm_get_copp_id(int port_index)
{
+ int copp_id;
+ pr_debug("%s\n", __func__);
+
+ if (port_index < 0) {
+ pr_err("%s: invalid port_id = %d\n", __func__, port_index);
+ return -EINVAL;
+ }
+
+ copp_id = atomic_read(&this_adm.copp_id[port_index]);
+ if (copp_id == RESET_COPP_ID)
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[port_index]);
+ return copp_id;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
pr_debug("%s\n", __func__);
if (port_index < 0) {
@@ -1523,8 +1559,19 @@
return -EINVAL;
}
- return atomic_read(&this_adm.copp_id[port_index]);
+ return atomic_read(&this_adm.copp_low_latency_id[port_index]);
}
+#else
+int adm_get_copp_id(int port_index)
+{
+ return -EINVAL;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
+ return -EINVAL;
+}
+#endif /* #ifdef CONFIG_RTAC */
void adm_ec_ref_rx_id(int port_id)
{
@@ -1532,12 +1579,13 @@
pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
}
-int adm_close(int port_id, bool perf_mode)
+int adm_close(int port_id, int perf_mode)
{
struct apr_hdr close;
int ret = 0;
int index = 0;
+ int copp_id = RESET_COPP_ID;
port_id = q6audio_convert_virtual_to_portid(port_id);
@@ -1548,7 +1596,8 @@
pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
index, perf_mode);
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
pr_err("%s: copp count for port[%#x]is 0\n", __func__,
port_id);
@@ -1563,8 +1612,9 @@
}
atomic_dec(&this_adm.copp_cnt[index]);
}
- if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
- (perf_mode &&
+ if ((perf_mode == LEGACY_PCM_MODE &&
+ !(atomic_read(&this_adm.copp_cnt[index]))) ||
+ ((perf_mode != LEGACY_PCM_MODE) &&
!(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
@@ -1577,7 +1627,8 @@
close.src_port = port_id;
close.dest_svc = APR_SVC_ADM;
close.dest_domain = APR_DOMAIN_ADSP;
- if (perf_mode)
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE)
close.dest_port =
atomic_read(&this_adm.copp_low_latency_id[index]);
else
@@ -1587,18 +1638,23 @@
atomic_set(&this_adm.copp_stat[index], 0);
- if (perf_mode) {
+ if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+ perf_mode == LOW_LATENCY_PCM_MODE) {
+ copp_id = atomic_read(
+ &this_adm.copp_low_latency_id[index]);
pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
- __func__,
- atomic_read(&this_adm.copp_low_latency_id[index]),
- port_id, index,
- atomic_read(&this_adm.copp_low_latency_cnt[index]));
+ __func__,
+ copp_id,
+ port_id, index,
+ atomic_read(
+ &this_adm.copp_low_latency_cnt[index]));
atomic_set(&this_adm.copp_low_latency_id[index],
RESET_COPP_ID);
} else {
+ copp_id = atomic_read(&this_adm.copp_id[index]);
pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
__func__,
- atomic_read(&this_adm.copp_id[index]),
+ copp_id,
port_id, index,
atomic_read(&this_adm.copp_cnt[index]));
atomic_set(&this_adm.copp_id[index],
@@ -1623,9 +1679,9 @@
}
}
- if (!perf_mode) {
+ if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
pr_debug("%s: remove adm device from rtac\n", __func__);
- rtac_remove_adm_device(port_id);
+ rtac_remove_adm_device(port_id, copp_id);
}
fail_cmd:
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 631e9bd..24f5f3b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -39,6 +39,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>
+#include <sound/q6audio-v2.h>
#include "audio_acdb.h"
@@ -354,7 +355,7 @@
session[ac->session] = 0;
mutex_unlock(&session_lock);
ac->session = 0;
- ac->perf_mode = 0;
+ ac->perf_mode = LEGACY_PCM_MODE;
ac->fptr_cache_ops = NULL;
return;
}
@@ -810,7 +811,7 @@
ac->cb = cb;
ac->priv = priv;
ac->io_mode = SYNC_IO_MODE;
- ac->perf_mode = false;
+ ac->perf_mode = LEGACY_PCM_MODE;
ac->fptr_cache_ops = NULL;
ac->apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
@@ -1695,7 +1696,7 @@
open.bits_per_sample = bits_per_sample;
open.mode_flags = 0x0;
- if (ac->perf_mode) {
+ if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION <<
ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
} else {
@@ -1781,8 +1782,10 @@
open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
open.mode_flags = 0x00;
- if (ac->perf_mode)
+ if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
+ else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+ open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
else {
open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
if (is_gapless_mode)
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index f74dbe2..701dfef 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -556,7 +556,8 @@
/* Check if device already added */
if (rtac_adm_data.num_of_dev != 0) {
for (; i < rtac_adm_data.num_of_dev; i++) {
- if (rtac_adm_data.device[i].afe_port == port_id) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
add_popp(i, port_id, popp_id);
goto done;
}
@@ -609,7 +610,7 @@
}
}
-void rtac_remove_adm_device(u32 port_id)
+void rtac_remove_adm_device(u32 port_id, u32 copp_id)
{
s32 i;
pr_debug("%s: port_id = %d\n", __func__, port_id);
@@ -619,7 +620,8 @@
/* look for device */
for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
- if (rtac_adm_data.device[i].afe_port == port_id) {
+ if (rtac_adm_data.device[i].afe_port == port_id &&
+ rtac_adm_data.device[i].copp == copp_id) {
memset(&rtac_adm_data.device[i], 0,
sizeof(rtac_adm_data.device[i]));
rtac_adm_data.num_of_dev--;
@@ -870,6 +872,8 @@
for (port_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
if (adm_get_copp_id(port_index) == copp_id)
break;
+ if (adm_get_lowlatency_copp_id(port_index) == copp_id)
+ break;
}
if (port_index >= AFE_MAX_PORTS) {
pr_err("%s: Could not find port index for copp = %d\n",