Merge "msm: camera: camera lens placed at mechanical infinity" into msm-3.0
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 66f5fa1..aa7adc5 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -134,7 +134,7 @@
compatible = "qcom,spi-qup-v2";
reg = <0xf9924000 0x1000>;
interrupts = <0 96 0>;
- spi-max-frequency = <24000000>;
+ spi-max-frequency = <25000000>;
};
slim@fe12f000 {
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 3431cd0..e873498 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -342,6 +342,12 @@
.pull = GPIOMUX_PULL_KEEPER,
};
+static struct gpiomux_setting mbhc_hs_detect = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct gpiomux_setting cdc_mclk = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_8MA,
@@ -730,6 +736,12 @@
static struct msm_gpiomux_config apq8064_audio_codec_configs[] __initdata = {
{
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mbhc_hs_detect,
+ },
+ },
+ {
.gpio = 39,
.settings = {
[GPIOMUX_SUSPENDED] = &cdc_mclk,
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 3d2dbaa..40222b8 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -549,7 +549,7 @@
* ID name always_on pd min_uV max_uV en_t supply
* system_uA reg_ID
*/
- PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 1),
/* ID name always_on pd en_t supply reg_ID */
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 6d228e4..d04e5e4 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2288,6 +2288,33 @@
.id = -1,
};
+static int rf4ce_gpio_init(void)
+{
+ if (!machine_is_mpq8064_cdp())
+ return -EINVAL;
+
+ /* CC2533 SRDY Input */
+ if (!gpio_request(SX150X_GPIO(4, 6), "rf4ce_srdy")) {
+ gpio_direction_input(SX150X_GPIO(4, 6));
+ gpio_export(SX150X_GPIO(4, 6), true);
+ }
+
+ /* CC2533 MRDY Output */
+ if (!gpio_request(SX150X_GPIO(4, 5), "rf4ce_mrdy")) {
+ gpio_direction_output(SX150X_GPIO(4, 5), 1);
+ gpio_export(SX150X_GPIO(4, 5), true);
+ }
+
+ /* CC2533 Reset Output */
+ if (!gpio_request(SX150X_GPIO(4, 7), "rf4ce_reset")) {
+ gpio_direction_output(SX150X_GPIO(4, 7), 0);
+ gpio_export(SX150X_GPIO(4, 7), true);
+ }
+
+ return 0;
+}
+late_initcall(rf4ce_gpio_init);
+
static struct platform_device *mpq_devices[] __initdata = {
&msm_device_sps_apq8064,
&mpq8064_device_qup_i2c_gsbi5,
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index efe6057..2f24c95 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -452,11 +452,11 @@
* ID name always_on pd min_uV max_uV en_t supply
* system_uA reg_ID
*/
- PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 375000, 1050000, 200, "8038_s3",
0, 0),
- PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 375000, 1050000, 200, "8038_s3",
0, 1),
- PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 375000, 1050000, 200, "8038_s3",
0, 2),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 5a96f98..0fff814 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -131,14 +131,15 @@
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
+#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */
#define MSM_ION_HEAP_NUM 7
#else
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_HEAP_NUM 8
#endif
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
-#define MSM_ION_QSECOM_SIZE 0x300000 /* (3MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 3923ecf..edb6f03 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -497,11 +497,11 @@
* ID name always_on pd min_uV max_uV en_t supply
* system_uA reg_ID
*/
- PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 1),
- PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 2),
- PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 3),
PM8XXX_LDO(L29, "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
0, 4),
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index cf24ef0..c28d172 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -406,6 +406,23 @@
.resource = tzlog_resources,
};
+#ifdef CONFIG_HW_RANDOM_MSM
+/* PRNG device */
+#define MSM_PRNG_PHYS 0xF9BFF000
+static struct resource rng_resources = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_PRNG_PHYS,
+ .end = MSM_PRNG_PHYS + SZ_512 - 1,
+};
+
+struct platform_device msm8974_device_rng = {
+ .name = "msm_rng",
+ .id = 0,
+ .num_resources = 1,
+ .resource = &rng_resources,
+};
+#endif
+
void __init msm_copper_add_devices(void)
{
@@ -417,6 +434,9 @@
platform_add_devices(msm_copper_stub_regulator_devices,
msm_copper_stub_regulator_devices_len);
platform_device_register(&apq_device_tz_log);
+#ifdef CONFIG_HW_RANDOM_MSM
+ platform_device_register(&msm8974_device_rng);
+#endif
}
/*
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 7e102ac..c0245a3 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -4910,6 +4910,7 @@
CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
+ CLK_DUMMY("core_clk", PRNG_CLK , "msm_rng.0", OFF),
/* TODO: Remove dummy clocks as soon as they become unnecessary */
CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 3629490..76d79a6 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -135,6 +135,8 @@
},
};
+#define MSM_HSUSB_RESUME_GPIO 79
+
static struct resource resources_hsusb[] = {
{
.start = MSM9615_HSUSB_PHYS,
@@ -146,6 +148,12 @@
.end = USB1_HS_IRQ,
.flags = IORESOURCE_IRQ,
},
+ {
+ .start = MSM_HSUSB_RESUME_GPIO,
+ .end = MSM_HSUSB_RESUME_GPIO,
+ .name = "USB_RESUME",
+ .flags = IORESOURCE_IO,
+ },
};
static struct resource resources_usb_bam[] = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index d476ca6..100d99a 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -398,3 +398,5 @@
extern struct platform_device msm8960_cache_dump_device;
extern struct platform_device apq_device_tz_log;
+
+extern struct platform_device msm8974_device_rng;
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index dfb100c..1a3a022 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -56,14 +56,28 @@
unsigned int domain_alloc_flags;
};
+
+struct msm_iova_partition {
+ unsigned long start;
+ unsigned long size;
+};
+
+struct msm_iova_layout {
+ struct msm_iova_partition *partitions;
+ int npartitions;
+ const char *client_name;
+ unsigned int domain_flags;
+};
+
#if defined(CONFIG_MSM_IOMMU)
extern struct iommu_domain *msm_get_iommu_domain(int domain_num);
-extern unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+extern int msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
- unsigned long align);
+ unsigned long align,
+ unsigned long *iova);
extern void msm_free_iova_address(unsigned long iova,
unsigned int iommu_domain,
@@ -97,16 +111,19 @@
unsigned int partition_no,
unsigned long size);
+extern int msm_register_domain(struct msm_iova_layout *layout);
+
#else
static inline struct iommu_domain
*msm_get_iommu_domain(int subsys_id) { return NULL; }
-static inline unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+static inline int msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
- unsigned long align) { return 0; }
+ unsigned long align,
+ unsigned long *iova) { return -ENOMEM; }
static inline void msm_free_iova_address(unsigned long iova,
unsigned int iommu_domain,
@@ -153,6 +170,11 @@
{
return;
}
+
+static inline int msm_register_domain(struct msm_iova_layout *layout)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 34c16d1..271e252b 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -10,27 +10,34 @@
* GNU General Public License for more details.
*/
-#include <mach/msm_subsystem_map.h>
-#include <linux/memory_alloc.h>
+#include <linux/init.h>
#include <linux/iommu.h>
+#include <linux/memory_alloc.h>
#include <linux/platform_device.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/sizes.h>
#include <asm/page.h>
-#include <linux/init.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
+#include <mach/msm_subsystem_map.h>
/* dummy 64K for overmapping */
char iommu_dummy[2*SZ_64K-4];
-struct msm_iommu_domain_state {
- struct msm_iommu_domain *domains;
- int ndomains;
+struct msm_iova_data {
+ struct rb_node node;
+ struct mem_pool *pools;
+ int npools;
+ struct iommu_domain *domain;
+ int domain_num;
};
-static struct msm_iommu_domain_state domain_state;
+static struct rb_root domain_root;
+DEFINE_MUTEX(domain_mutex);
+static atomic_t domain_nums = ATOMIC_INIT(-1);
int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
@@ -127,9 +134,10 @@
if (size & (align - 1))
return -EINVAL;
- iova = msm_allocate_iova_address(domain_no, partition_no, size, align);
+ ret = msm_allocate_iova_address(domain_no, partition_no, size, align,
+ &iova);
- if (!iova)
+ if (ret)
return -ENOMEM;
ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
@@ -152,73 +160,210 @@
msm_free_iova_address(iova, domain_no, partition_no, size);
}
+static struct msm_iova_data *find_domain(int domain_num)
+{
+ struct rb_root *root = &domain_root;
+ struct rb_node *p = root->rb_node;
+
+ mutex_lock(&domain_mutex);
+
+ while (p) {
+ struct msm_iova_data *node;
+
+ node = rb_entry(p, struct msm_iova_data, node);
+ if (domain_num < node->domain_num)
+ p = p->rb_left;
+ else if (domain_num > domain_num)
+ p = p->rb_right;
+ else {
+ mutex_unlock(&domain_mutex);
+ return node;
+ }
+ }
+ mutex_unlock(&domain_mutex);
+ return NULL;
+}
+
+static int add_domain(struct msm_iova_data *node)
+{
+ struct rb_root *root = &domain_root;
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+
+ mutex_lock(&domain_mutex);
+ while (*p) {
+ struct msm_iova_data *tmp;
+ parent = *p;
+
+ tmp = rb_entry(parent, struct msm_iova_data, node);
+
+ if (node->domain_num < tmp->domain_num)
+ p = &(*p)->rb_left;
+ else if (node->domain_num > tmp->domain_num)
+ p = &(*p)->rb_right;
+ else
+ BUG();
+ }
+ rb_link_node(&node->node, parent, p);
+ rb_insert_color(&node->node, root);
+ mutex_unlock(&domain_mutex);
+ return 0;
+}
+
struct iommu_domain *msm_get_iommu_domain(int domain_num)
{
- if (domain_num >= 0 && domain_num < domain_state.ndomains)
- return domain_state.domains[domain_num].domain;
+ struct msm_iova_data *data;
+
+ data = find_domain(domain_num);
+
+ if (data)
+ return data->domain;
else
return NULL;
}
-unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+int msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
- unsigned long align)
+ unsigned long align,
+ unsigned long *iova)
{
+ struct msm_iova_data *data;
struct mem_pool *pool;
- unsigned long iova;
+ unsigned long va;
- if (iommu_domain >= domain_state.ndomains)
- return 0;
+ data = find_domain(iommu_domain);
- if (partition_no >= domain_state.domains[iommu_domain].npools)
- return 0;
+ if (!data)
+ return -EINVAL;
- pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
+ if (partition_no >= data->npools)
+ return -EINVAL;
+
+ pool = &data->pools[partition_no];
if (!pool->gpool)
- return 0;
+ return -EINVAL;
- iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
- if (iova)
+ va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
+ if (va) {
pool->free -= size;
+ /* Offset because genpool can't handle 0 addresses */
+ if (pool->paddr == 0)
+ va -= SZ_4K;
+ *iova = va;
+ return 0;
+ }
- return iova;
+ return -ENOMEM;
}
void msm_free_iova_address(unsigned long iova,
- unsigned int iommu_domain,
- unsigned int partition_no,
- unsigned long size)
+ unsigned int iommu_domain,
+ unsigned int partition_no,
+ unsigned long size)
{
+ struct msm_iova_data *data;
struct mem_pool *pool;
- if (iommu_domain >= domain_state.ndomains) {
+ data = find_domain(iommu_domain);
+
+ if (!data) {
WARN(1, "Invalid domain %d\n", iommu_domain);
return;
}
- if (partition_no >= domain_state.domains[iommu_domain].npools) {
+ if (partition_no >= data->npools) {
WARN(1, "Invalid partition %d for domain %d\n",
partition_no, iommu_domain);
return;
}
- pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
+ pool = &data->pools[partition_no];
if (!pool)
return;
pool->free += size;
+
+ /* Offset because genpool can't handle 0 addresses */
+ if (pool->paddr == 0)
+ iova += SZ_4K;
+
gen_pool_free(pool->gpool, iova, size);
}
+int msm_register_domain(struct msm_iova_layout *layout)
+{
+ int i;
+ struct msm_iova_data *data;
+ struct mem_pool *pools;
+
+ if (!layout)
+ return -EINVAL;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+ if (!data)
+ return -ENOMEM;
+
+ pools = kmalloc(sizeof(struct mem_pool) * layout->npartitions,
+ GFP_KERNEL);
+
+ if (!pools)
+ goto out;
+
+ for (i = 0; i < layout->npartitions; i++) {
+ if (layout->partitions[i].size == 0)
+ continue;
+
+ pools[i].gpool = gen_pool_create(PAGE_SHIFT, -1);
+
+ if (!pools[i].gpool)
+ continue;
+
+ pools[i].paddr = layout->partitions[i].start;
+ pools[i].size = layout->partitions[i].size;
+
+ /*
+ * genalloc can't handle a pool starting at address 0.
+ * For now, solve this problem by offsetting the value
+ * put in by 4k.
+ * gen pool address = actual address + 4k
+ */
+ if (pools[i].paddr == 0)
+ layout->partitions[i].start += SZ_4K;
+
+ if (gen_pool_add(pools[i].gpool,
+ layout->partitions[i].start,
+ layout->partitions[i].size, -1)) {
+ gen_pool_destroy(pools[i].gpool);
+ pools[i].gpool = NULL;
+ continue;
+ }
+ }
+
+ data->pools = pools;
+ data->npools = layout->npartitions;
+ data->domain_num = atomic_inc_return(&domain_nums);
+ data->domain = iommu_domain_alloc(layout->domain_flags);
+
+ add_domain(data);
+
+ return data->domain_num;
+
+out:
+ kfree(data);
+
+ return -EINVAL;
+}
+
int msm_use_iommu()
{
/*
* If there are no domains, don't bother trying to use the iommu
*/
- return domain_state.ndomains && iommu_found();
+ return iommu_found();
}
static int __init iommu_domain_probe(struct platform_device *pdev)
@@ -229,64 +374,52 @@
if (!p)
return -ENODEV;
- domain_state.domains = p->domains;
- domain_state.ndomains = p->ndomains;
+ for (i = 0; i < p->ndomains; i++) {
+ struct msm_iova_layout l;
+ struct msm_iova_partition *part;
+ struct msm_iommu_domain *domains;
- for (i = 0; i < domain_state.ndomains; i++) {
- domain_state.domains[i].domain = iommu_domain_alloc(
- p->domain_alloc_flags);
- if (!domain_state.domains[i].domain)
+ domains = p->domains;
+ l.npartitions = domains[i].npools;
+ part = kmalloc(
+ sizeof(struct msm_iova_partition) * l.npartitions,
+ GFP_KERNEL);
+
+ if (!part) {
+ pr_info("%s: could not allocate space for domain %d",
+ __func__, i);
continue;
-
- for (j = 0; j < domain_state.domains[i].npools; j++) {
- struct mem_pool *pool = &domain_state.domains[i].
- iova_pools[j];
- mutex_init(&pool->pool_mutex);
- if (pool->size) {
- pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
-
- if (!pool->gpool) {
- pr_err("%s: could not allocate pool\n",
- __func__);
- pr_err("%s: domain %d iova space %d\n",
- __func__, i, j);
- continue;
- }
-
- if (gen_pool_add(pool->gpool, pool->paddr,
- pool->size, -1)) {
- pr_err("%s: could not add memory\n",
- __func__);
- pr_err("%s: domain %d pool %d\n",
- __func__, i, j);
- gen_pool_destroy(pool->gpool);
- pool->gpool = NULL;
- continue;
- }
- } else {
- pool->gpool = NULL;
- }
}
+
+ for (j = 0; j < l.npartitions; j++) {
+ part[j].start = p->domains[i].iova_pools[j].paddr;
+ part[j].size = p->domains[i].iova_pools[j].size;
+ }
+
+ l.partitions = part;
+
+ msm_register_domain(&l);
+
+ kfree(part);
}
for (i = 0; i < p->nnames; i++) {
- int domain_idx;
struct device *ctx = msm_iommu_get_ctx(
p->domain_names[i].name);
+ struct iommu_domain *domain;
if (!ctx)
continue;
- domain_idx = p->domain_names[i].domain;
+ domain = msm_get_iommu_domain(p->domain_names[i].domain);
- if (!domain_state.domains[domain_idx].domain)
+ if (!domain)
continue;
- if (iommu_attach_device(domain_state.domains[domain_idx].domain,
- ctx)) {
- WARN(1, "%s: could not attach domain %d to context %s."
+ if (iommu_attach_device(domain, ctx)) {
+ WARN(1, "%s: could not attach domain %p to context %s."
" iommu programming will not occur.\n",
- __func__, domain_idx,
+ __func__, domain,
p->domain_names[i].name);
continue;
}
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 7208a48..9d0ce0d 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -578,6 +578,10 @@
"invalid proxy voting. ignoring\n"))
((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
+ WARN(desc->ops->proxy_unvote && !desc->proxy_timeout,
+ "A proxy timeout of 0 ms was specified for %s. Specify one in "
+ "desc->proxy_timeout.\n", desc->name);
+
pil = kzalloc(sizeof(*pil), GFP_KERNEL);
if (!pil)
return ERR_PTR(-ENOMEM);
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 8446e42..131a74b 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -116,14 +116,9 @@
int err;
struct q6v4_data *drv = dev_get_drvdata(dev);
- err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+ err = regulator_set_voltage(drv->vreg, 375000, 375000);
if (err) {
- dev_err(dev, "Failed to set regulator's voltage.\n");
- return err;
- }
- err = regulator_set_optimum_mode(drv->vreg, 100000);
- if (err < 0) {
- dev_err(dev, "Failed to set regulator's mode.\n");
+ dev_err(dev, "Failed to set regulator's voltage step.\n");
return err;
}
err = regulator_enable(drv->vreg);
@@ -131,6 +126,18 @@
dev_err(dev, "Failed to enable regulator.\n");
return err;
}
+
+ /*
+ * Q6 hardware requires a two step voltage ramp-up.
+ * Delay between the steps.
+ */
+ udelay(100);
+
+ err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+ if (err) {
+ dev_err(dev, "Failed to set regulator's voltage.\n");
+ return err;
+ }
drv->vreg_enabled = true;
return 0;
}
@@ -411,6 +418,12 @@
if (IS_ERR(drv->vreg))
return PTR_ERR(drv->vreg);
+ ret = regulator_set_optimum_mode(drv->vreg, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
+ return ret;
+ }
+
drv->xo = devm_clk_get(&pdev->dev, "xo");
if (IS_ERR(drv->xo))
return PTR_ERR(drv->xo);
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index e5e176b..311f8a7 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -23,6 +23,7 @@
#include "pil-q6v5.h"
#define QDSP6SS_RST_EVB 0x010
+#define PROXY_TIMEOUT_MS 10000
static int pil_lpass_shutdown(struct pil_desc *pil)
{
@@ -93,6 +94,7 @@
desc->ops = &pil_lpass_ops;
desc->owner = THIS_MODULE;
+ desc->proxy_timeout = PROXY_TIMEOUT_MS;
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil))
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 3826b12..91f1133 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -170,6 +170,8 @@
{
unsigned long timeout;
+ preset_lpj = loops_per_jiffy;
+
if (cold_boot_done == false) {
if (msm8625_release_secondary()) {
pr_err("Failed to release secondary core\n");
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index abcd336..b9cba8c 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -40,7 +40,7 @@
#ifdef CONFIG_ARCH_FSM9XXX
#define NUM_SMD_PKT_PORTS 4
#else
-#define NUM_SMD_PKT_PORTS 14
+#define NUM_SMD_PKT_PORTS 15
#endif
#define LOOPBACK_INX (NUM_SMD_PKT_PORTS - 1)
@@ -677,6 +677,7 @@
"apr_apps2",
"smdcntl8",
"smd_sns_adsp",
+ "smd_cxm_qmi",
"smd_pkt_loopback",
};
@@ -694,6 +695,7 @@
"apr_apps2",
"DATA40_CNTL",
"SENSOR",
+ "CXM_QMI_PORT_8064",
"LOOPBACK",
};
@@ -711,6 +713,7 @@
SMD_APPS_QDSP,
SMD_APPS_MODEM,
SMD_APPS_QDSP,
+ SMD_APPS_WCNSS,
SMD_APPS_MODEM,
};
#endif
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index 4a1285b..916686f 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -375,12 +375,13 @@
partition_no = msm_subsystem_get_partition_no(
subsys_ids[i]);
- iova_start = msm_allocate_iova_address(domain_no,
+ ret = msm_allocate_iova_address(domain_no,
partition_no,
map_size,
- max(min_align, SZ_4K));
+ max(min_align, SZ_4K),
+ &iova_start);
- if (!iova_start) {
+ if (ret) {
pr_err("%s: could not allocate iova address\n",
__func__);
continue;
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 404538a..bacba58 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -159,6 +159,22 @@
tst r5, #FPSCR_IXE
bne process_exception
+#ifdef CONFIG_ARCH_MSM_KRAIT
+ @ Krait does not set FPEXC.DEX for unsupported short vector instructions
+ mrc p15, 0, r2, c0, c0, 0
+ ldr r4, =0xff00fc00
+ and r4, r2, r4
+ ldr r2, =0x51000400
+ cmp r2, r4
+ bne skip
+
+ tst r5, #FPSCR_LENGTH_MASK
+ beq skip
+ orr r1, r1, #FPEXC_DEX
+ b process_exception
+skip:
+#endif
+
@ Fall into hand on to next handler - appropriate coproc instr
@ not recognised by VFP
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 81a9fa7..6cd1806 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -45,6 +45,7 @@
#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
+#define MSM_ROTATOR_SW_RESET (MSM_ROTATOR_BASE+0x0074)
#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
@@ -906,8 +907,7 @@
break;
if (s == MAX_SESSIONS) {
- dev_dbg(msm_rotator_dev->device,
- "%s() : Attempt to use invalid session_id %d\n",
+ pr_err("%s() : Attempt to use invalid session_id %d\n",
__func__, s);
rc = -EINVAL;
goto do_rotate_unlock_mutex;
@@ -1129,11 +1129,13 @@
break;
default:
rc = -EINVAL;
+ pr_err("%s(): Unsupported format %u\n", __func__, format);
goto do_rotate_exit;
}
if (rc != 0) {
msm_rotator_dev->last_session_idx = INVALID_SESSION;
+ pr_err("%s(): Invalid session error\n", __func__);
goto do_rotate_exit;
}
@@ -1145,8 +1147,11 @@
wait_event(msm_rotator_dev->wq,
(msm_rotator_dev->processing == 0));
status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
- if ((status & 0x03) != 0x01)
+ if ((status & 0x03) != 0x01) {
+ pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
+ iowrite32(0x1, MSM_ROTATOR_SW_RESET);
rc = -EFAULT;
+ }
iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index bbb13f3..56f986d 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1674,12 +1674,158 @@
return size;
}
+/**
+ * Searches through a clients handles to find if the buffer is owned
+ * by this client. Used for debug output.
+ * @param client pointer to candidate owner of buffer
+ * @param buf pointer to buffer that we are trying to find the owner of
+ * @return 1 if found, 0 otherwise
+ */
+static int ion_debug_find_buffer_owner(const struct ion_client *client,
+ const struct ion_buffer *buf)
+{
+ struct rb_node *n;
+
+ for (n = rb_first(&client->handles); n; n = rb_next(n)) {
+ const struct ion_handle *handle = rb_entry(n,
+ const struct ion_handle,
+ node);
+ if (handle->buffer == buf)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Adds mem_map_data pointer to the tree of mem_map
+ * Used for debug output.
+ * @param mem_map The mem_map tree
+ * @param data The new data to add to the tree
+ */
+static void ion_debug_mem_map_add(struct rb_root *mem_map,
+ struct mem_map_data *data)
+{
+ struct rb_node **p = &mem_map->rb_node;
+ struct rb_node *parent = NULL;
+ struct mem_map_data *entry;
+
+ while (*p) {
+ parent = *p;
+ entry = rb_entry(parent, struct mem_map_data, node);
+
+ if (data->addr < entry->addr) {
+ p = &(*p)->rb_left;
+ } else if (data->addr > entry->addr) {
+ p = &(*p)->rb_right;
+ } else {
+ pr_err("%s: mem_map_data already found.", __func__);
+ BUG();
+ }
+ }
+ rb_link_node(&data->node, parent, p);
+ rb_insert_color(&data->node, mem_map);
+}
+
+/**
+ * Search for an owner of a buffer by iterating over all ION clients.
+ * @param dev ion device containing pointers to all the clients.
+ * @param buffer pointer to buffer we are trying to find the owner of.
+ * @return name of owner.
+ */
+const char *ion_debug_locate_owner(const struct ion_device *dev,
+ const struct ion_buffer *buffer)
+{
+ struct rb_node *j;
+ const char *client_name = NULL;
+
+ for (j = rb_first(&dev->user_clients); j && !client_name;
+ j = rb_next(j)) {
+ struct ion_client *client = rb_entry(j, struct ion_client,
+ node);
+ if (ion_debug_find_buffer_owner(client, buffer))
+ client_name = client->name;
+ }
+ for (j = rb_first(&dev->kernel_clients); j && !client_name;
+ j = rb_next(j)) {
+ struct ion_client *client = rb_entry(j, struct ion_client,
+ node);
+ if (ion_debug_find_buffer_owner(client, buffer))
+ client_name = client->name;
+ }
+ return client_name;
+}
+
+/**
+ * Create a mem_map of the heap.
+ * @param s seq_file to log error message to.
+ * @param heap The heap to create mem_map for.
+ * @param mem_map The mem map to be created.
+ */
+void ion_debug_mem_map_create(struct seq_file *s, struct ion_heap *heap,
+ struct rb_root *mem_map)
+{
+ struct ion_device *dev = heap->dev;
+ struct rb_node *n;
+
+ for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
+ struct ion_buffer *buffer =
+ rb_entry(n, struct ion_buffer, node);
+ if (buffer->heap->id == heap->id) {
+ struct mem_map_data *data =
+ kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ seq_printf(s, "ERROR: out of memory. "
+ "Part of memory map will not be logged\n");
+ break;
+ }
+ data->addr = buffer->priv_phys;
+ data->addr_end = buffer->priv_phys + buffer->size-1;
+ data->size = buffer->size;
+ data->client_name = ion_debug_locate_owner(dev, buffer);
+ ion_debug_mem_map_add(mem_map, data);
+ }
+ }
+}
+
+/**
+ * Free the memory allocated by ion_debug_mem_map_create
+ * @param mem_map The mem map to free.
+ */
+static void ion_debug_mem_map_destroy(struct rb_root *mem_map)
+{
+ if (mem_map) {
+ struct rb_node *n;
+ while ((n = rb_first(mem_map)) != 0) {
+ struct mem_map_data *data =
+ rb_entry(n, struct mem_map_data, node);
+ rb_erase(&data->node, mem_map);
+ kfree(data);
+ }
+ }
+}
+
+/**
+ * Print heap debug information.
+ * @param s seq_file to log message to.
+ * @param heap pointer to heap that we will print debug information for.
+ */
+static void ion_heap_print_debug(struct seq_file *s, struct ion_heap *heap)
+{
+ if (heap->ops->print_debug) {
+ struct rb_root mem_map = RB_ROOT;
+ ion_debug_mem_map_create(s, heap, &mem_map);
+ heap->ops->print_debug(heap, s, &mem_map);
+ ion_debug_mem_map_destroy(&mem_map);
+ }
+}
+
static int ion_debug_heap_show(struct seq_file *s, void *unused)
{
struct ion_heap *heap = s->private;
struct ion_device *dev = heap->dev;
struct rb_node *n;
+ mutex_lock(&dev->lock);
seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
for (n = rb_first(&dev->user_clients); n; n = rb_next(n)) {
struct ion_client *client = rb_entry(n, struct ion_client,
@@ -1703,8 +1849,8 @@
seq_printf(s, "%16.s %16u %16x\n", client->name, client->pid,
size);
}
- if (heap->ops->print_debug)
- heap->ops->print_debug(heap, s);
+ ion_heap_print_debug(s, heap);
+ mutex_unlock(&dev->lock);
return 0;
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index ca2380b..710583b 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -251,7 +251,8 @@
return 0;
}
-static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *mem_map)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
@@ -260,6 +261,44 @@
carveout_heap->allocated_bytes);
seq_printf(s, "total heap size: %lx\n", carveout_heap->total_size);
+ if (mem_map) {
+ unsigned long base = carveout_heap->base;
+ unsigned long size = carveout_heap->total_size;
+ unsigned long end = base+size;
+ unsigned long last_end = base;
+ struct rb_node *n;
+
+ seq_printf(s, "\nMemory Map\n");
+ seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+ "client", "start address", "end address",
+ "size (hex)");
+
+ for (n = rb_first(mem_map); n; n = rb_next(n)) {
+ struct mem_map_data *data =
+ rb_entry(n, struct mem_map_data, node);
+ const char *client_name = "(null)";
+
+ if (last_end < data->addr) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ "FREE", last_end, data->addr-1,
+ data->addr-last_end,
+ data->addr-last_end);
+ }
+
+ if (data->client_name)
+ client_name = data->client_name;
+
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ client_name, data->addr,
+ data->addr_end,
+ data->size, data->size);
+ last_end = data->addr_end+1;
+ }
+ if (last_end < end) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
+ last_end, end-1, end-last_end, end-last_end);
+ }
+ }
return 0;
}
@@ -287,13 +326,12 @@
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 052b778..fcbf1d4 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -563,7 +563,8 @@
return 0;
}
-static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *mem_map)
{
unsigned long total_alloc;
unsigned long total_size;
@@ -588,6 +589,45 @@
seq_printf(s, "heap protected: %s\n", heap_protected ? "Yes" : "No");
seq_printf(s, "reusable: %s\n", cp_heap->reusable ? "Yes" : "No");
+ if (mem_map) {
+ unsigned long base = cp_heap->base;
+ unsigned long size = cp_heap->total_size;
+ unsigned long end = base+size;
+ unsigned long last_end = base;
+ struct rb_node *n;
+
+ seq_printf(s, "\nMemory Map\n");
+ seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+ "client", "start address", "end address",
+ "size (hex)");
+
+ for (n = rb_first(mem_map); n; n = rb_next(n)) {
+ struct mem_map_data *data =
+ rb_entry(n, struct mem_map_data, node);
+ const char *client_name = "(null)";
+
+ if (last_end < data->addr) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ "FREE", last_end, data->addr-1,
+ data->addr-last_end,
+ data->addr-last_end);
+ }
+
+ if (data->client_name)
+ client_name = data->client_name;
+
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ client_name, data->addr,
+ data->addr_end,
+ data->size, data->size);
+ last_end = data->addr_end+1;
+ }
+ if (last_end < end) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
+ last_end, end-1, end-last_end, end-last_end);
+ }
+ }
+
return 0;
}
@@ -647,13 +687,15 @@
}
if (!ret_value && domain) {
unsigned long temp_phys = cp_heap->base;
- unsigned long temp_iova =
- msm_allocate_iova_address(domain_num, partition,
- virt_addr_len, SZ_64K);
- if (!temp_iova) {
+ unsigned long temp_iova;
+
+ ret_value = msm_allocate_iova_address(domain_num, partition,
+ virt_addr_len, SZ_64K,
+ &temp_iova);
+
+ if (ret_value) {
pr_err("%s: could not allocate iova from domain %lu, partition %d\n",
__func__, domain_num, partition);
- ret_value = -ENOMEM;
goto out;
}
cp_heap->iommu_iova[domain_num] = temp_iova;
@@ -742,13 +784,12 @@
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
@@ -918,6 +959,14 @@
cp_heap = NULL;
}
+void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
+ unsigned long *size) \
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+ *base = cp_heap->base;
+ *size = cp_heap->total_size;
+}
/* SCM related code for locking down memory for content protection */
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 312ca42..70bdc7f 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -190,13 +190,12 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (!data->iova_addr)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 98e11cf..00ce33f 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -155,7 +155,8 @@
unsigned long iova_length,
unsigned long flags);
void (*unmap_iommu)(struct ion_iommu_map *data);
- int (*print_debug)(struct ion_heap *heap, struct seq_file *s);
+ int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *mem_map);
int (*secure_heap)(struct ion_heap *heap);
int (*unsecure_heap)(struct ion_heap *heap);
};
@@ -185,7 +186,22 @@
const char *name;
};
-
+/**
+ * struct mem_map_data - represents information about the memory map for a heap
+ * @node: rb node used to store in the tree of mem_map_data
+ * @addr: start address of memory region.
+ * @addr: end address of memory region.
+ * @size: size of memory region
+ * @client_name: name of the client who owns this buffer.
+ *
+ */
+struct mem_map_data {
+ struct rb_node node;
+ unsigned long addr;
+ unsigned long addr_end;
+ unsigned long size;
+ const char *client_name;
+};
#define iommu_map_domain(__m) ((__m)->domain_info[1])
#define iommu_map_partition(__m) ((__m)->domain_info[0])
@@ -298,4 +314,9 @@
void *uaddr, unsigned long offset, unsigned long len,
unsigned int cmd);
+void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
+ unsigned long *size);
+
+void ion_mem_map_show(struct ion_heap *heap);
+
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index ed9ae27..26c6632 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -204,7 +204,8 @@
return 0;
}
-static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *unused)
{
seq_printf(s, "total bytes currently allocated: %lx\n",
(unsigned long) atomic_read(&system_heap_allocated));
@@ -240,13 +241,12 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
@@ -423,7 +423,8 @@
}
static int ion_system_contig_print_debug(struct ion_heap *heap,
- struct seq_file *s)
+ struct seq_file *s,
+ const struct rb_root *unused)
{
seq_printf(s, "total bytes currently allocated: %lx\n",
(unsigned long) atomic_read(&system_contig_heap_allocated));
@@ -458,13 +459,12 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 2242aa8..4f6c09d 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -498,7 +498,6 @@
if (rc)
WFD_MSG_ERR("Failed to free output buffer\n");
wfd_unregister_out_buf(inst, minfo);
- wfd_free_input_buffers(wfd_dev, inst);
}
static int mdp_output_thread(void *data)
@@ -1344,12 +1343,13 @@
inst = filp->private_data;
if (inst) {
wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- vb2_queue_release(&inst->vid_bufq);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_CLOSE, (void *)inst->mdp_inst);
if (rc)
WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
+ vb2_queue_release(&inst->vid_bufq);
+ wfd_free_input_buffers(wfd_dev, inst);
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
CLOSE, (void *)inst->venc_inst);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 9385087..8fce9a6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -464,6 +464,11 @@
ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
+ card->ext_csd.max_packed_writes =
+ ext_csd[EXT_CSD_MAX_PACKED_WRITES];
+ card->ext_csd.max_packed_reads =
+ ext_csd[EXT_CSD_MAX_PACKED_READS];
}
out:
@@ -1183,6 +1188,25 @@
card->ext_csd.cache_ctrl = err ? 0 : 1;
}
+ if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
+ (card->ext_csd.max_packed_writes > 0) &&
+ (card->ext_csd.max_packed_reads > 0)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_EXP_EVENTS_CTRL,
+ EXT_CSD_PACKED_EVENT_EN,
+ card->ext_csd.generic_cmd6_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warning("%s: Enabling packed event failed\n",
+ mmc_hostname(card->host));
+ card->ext_csd.packed_event_en = 0;
+ err = 0;
+ } else {
+ card->ext_csd.packed_event_en = 1;
+ }
+ }
+
if (!oldcard)
host->card = card;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index cc95fcd..ad9dc7d 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -45,7 +45,7 @@
int smd_channel_ready;
unsigned int serial_number;
int thermal_mitigation;
- void (*tm_notify)(int);
+ void (*tm_notify)(struct device *, int);
struct wcnss_wlan_config wlan_config;
struct delayed_work wcnss_work;
} *penv = NULL;
@@ -99,7 +99,7 @@
return -EINVAL;
penv->thermal_mitigation = value;
if (penv->tm_notify)
- (penv->tm_notify)(value);
+ (penv->tm_notify)(dev, value);
return count;
}
@@ -275,14 +275,16 @@
}
EXPORT_SYMBOL(wcnss_wlan_unregister_pm_ops);
-void wcnss_register_thermal_mitigation(void (*tm_notify)(int))
+void wcnss_register_thermal_mitigation(struct device *dev,
+ void (*tm_notify)(struct device *, int))
{
- if (penv && tm_notify)
+ if (penv && dev && tm_notify)
penv->tm_notify = tm_notify;
}
EXPORT_SYMBOL(wcnss_register_thermal_mitigation);
-void wcnss_unregister_thermal_mitigation(void (*tm_notify)(int))
+void wcnss_unregister_thermal_mitigation(
+ void (*tm_notify)(struct device *, int))
{
if (penv && tm_notify) {
if (tm_notify != penv->tm_notify)
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index fbb377e..78a1292 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -723,7 +723,8 @@
} else if (tmdev->hw_type == APQ_8064) {
reg_cntl |= TSENS_8960_SLP_CLK_ENA |
(TSENS_MEASURE_PERIOD << 18) |
- TSENS_8064_SENSORS_EN;
+ (((1 << tmdev->tsens_num_sensor) - 1)
+ << TSENS_SENSOR0_SHIFT);
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
reg_status_cntl |= TSENS_MIN_STATUS_MASK |
@@ -823,7 +824,8 @@
} else if (tmdev->hw_type == APQ_8064) {
reg_cntl |= TSENS_8960_SLP_CLK_ENA |
(TSENS_MEASURE_PERIOD << 18) |
- TSENS_8064_SENSORS_EN;
+ (((1 << tmdev->tsens_num_sensor) - 1)
+ << TSENS_SENSOR0_SHIFT);
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 863143b..7fd120f 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -16,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h>
+#include <mach/gpio.h>
#include "ci13xxx_udc.c"
@@ -24,7 +25,11 @@
struct ci13xxx_udc_context {
int irq;
void __iomem *regs;
+ int wake_gpio;
+ int wake_irq;
+ bool wake_irq_state;
};
+
static struct ci13xxx_udc_context _udc_ctxt;
static irqreturn_t msm_udc_irq(int irq, void *data)
@@ -32,22 +37,71 @@
return udc_irq();
}
+static void ci13xxx_msm_suspend(void)
+{
+ struct device *dev = _udc->gadget.dev.parent;
+ dev_dbg(dev, "ci13xxx_msm_suspend\n");
+
+ if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) {
+ enable_irq_wake(_udc_ctxt.wake_irq);
+ enable_irq(_udc_ctxt.wake_irq);
+ _udc_ctxt.wake_irq_state = true;
+ }
+}
+
+static void ci13xxx_msm_resume(void)
+{
+ struct device *dev = _udc->gadget.dev.parent;
+ dev_dbg(dev, "ci13xxx_msm_resume\n");
+
+ if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
+ disable_irq_wake(_udc_ctxt.wake_irq);
+ disable_irq(_udc_ctxt.wake_irq);
+ _udc_ctxt.wake_irq_state = false;
+ }
+}
+
static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
{
struct device *dev = udc->gadget.dev.parent;
switch (event) {
case CI13XXX_CONTROLLER_RESET_EVENT:
- dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+ dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel_relaxed(0x08, USB_AHBMODE);
break;
+ case CI13XXX_CONTROLLER_DISCONNECT_EVENT:
+ dev_info(dev, "CI13XXX_CONTROLLER_DISCONNECT_EVENT received\n");
+ ci13xxx_msm_resume();
+ break;
+ case CI13XXX_CONTROLLER_SUSPEND_EVENT:
+ dev_info(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
+ ci13xxx_msm_suspend();
+ break;
+ case CI13XXX_CONTROLLER_RESUME_EVENT:
+ dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
+ ci13xxx_msm_resume();
+ break;
+
default:
dev_dbg(dev, "unknown ci13xxx_udc event\n");
break;
}
}
+static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
+{
+ struct ci13xxx *udc = _udc;
+
+ if (udc->transceiver && udc->vbus_active && udc->suspended)
+ otg_set_suspend(udc->transceiver, 0);
+ else if (!udc->suspended)
+ ci13xxx_msm_resume();
+
+ return IRQ_HANDLED;
+}
+
static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
.name = "ci13xxx_msm",
.flags = CI13XXX_REGS_SHARED |
@@ -60,6 +114,52 @@
.notify_event = ci13xxx_msm_notify_event,
};
+static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
+ struct resource *res)
+{
+ int wake_irq;
+ int ret;
+
+ dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");
+
+ _udc_ctxt.wake_gpio = res->start;
+ gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
+ gpio_direction_input(_udc_ctxt.wake_gpio);
+ wake_irq = MSM_GPIO_TO_INT(_udc_ctxt.wake_gpio);
+ if (wake_irq < 0) {
+ dev_err(&pdev->dev, "could not register USB_RESUME GPIO.\n");
+ return -ENXIO;
+ }
+
+ dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n",
+ _udc_ctxt.wake_gpio, wake_irq);
+ ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "usb resume", NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n");
+ goto gpio_free;
+ }
+ disable_irq(wake_irq);
+ _udc_ctxt.wake_irq = wake_irq;
+
+ return 0;
+
+gpio_free:
+ gpio_free(_udc_ctxt.wake_gpio);
+ _udc_ctxt.wake_gpio = 0;
+ return ret;
+}
+
+static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
+{
+ dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");
+
+ if (_udc_ctxt.wake_gpio) {
+ gpio_free(_udc_ctxt.wake_gpio);
+ _udc_ctxt.wake_gpio = 0;
+ }
+}
+
static int ci13xxx_msm_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -92,11 +192,20 @@
goto udc_remove;
}
+ res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
+ if (res) {
+ ret = ci13xxx_msm_install_wake_gpio(pdev, res);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "gpio irq install failed\n");
+ goto udc_remove;
+ }
+ }
+
ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name,
pdev);
if (ret < 0) {
dev_err(&pdev->dev, "request_irq failed\n");
- goto udc_remove;
+ goto gpio_uninstall;
}
pm_runtime_no_callbacks(&pdev->dev);
@@ -104,6 +213,8 @@
return 0;
+gpio_uninstall:
+ ci13xxx_msm_uninstall_wake_gpio(pdev);
udc_remove:
udc_remove();
iounmap:
@@ -116,6 +227,7 @@
{
pm_runtime_disable(&pdev->dev);
free_irq(_udc_ctxt.irq, pdev);
+ ci13xxx_msm_uninstall_wake_gpio(pdev);
udc_remove();
iounmap(_udc_ctxt.regs);
return 0;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index fd341a7..b29ef82 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2015,6 +2015,9 @@
USB_SPEED_HIGH : USB_SPEED_FULL;
if (udc->suspended) {
spin_unlock(udc->lock);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_RESUME_EVENT);
if (udc->transceiver)
otg_set_suspend(udc->transceiver, 0);
udc->driver->resume(&udc->gadget);
@@ -2907,6 +2910,9 @@
} else {
hw_device_state(0);
_gadget_stop_activity(&udc->gadget);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_DISCONNECT_EVENT);
pm_runtime_put_sync(&_gadget->dev);
}
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 8e2b093..8cb62da 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -124,6 +124,8 @@
#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
#define CI13XXX_CONTROLLER_SUSPEND_EVENT 2
#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT 3
+#define CI13XXX_CONTROLLER_RESUME_EVENT 4
+#define CI13XXX_CONTROLLER_DISCONNECT_EVENT 5
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 2d8c064..311599d 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -668,12 +668,14 @@
case MDP_BGR_565:
case MDP_XRGB_8888:
case MDP_RGB_888:
+ case MDP_YCBCR_H1V1:
+ case MDP_YCRCB_H1V1:
*luma_off = pipe->src_x * pipe->bpp;
break;
default:
- pr_err("Source format %u not supported for x offset adjustment\n",
- pipe->src_format);
+ pr_err("%s: fmt %u not supported for adjustment\n",
+ __func__, pipe->src_format);
break;
}
}
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 2fba83d..342f565 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -273,6 +273,7 @@
if (node) {
list_del(&(node->active_entry));
node->state = IN_BUSY_QUEUE;
+ mfd->writeback_active_cnt++;
}
mutex_unlock(&mfd->writeback_mutex);
@@ -295,6 +296,7 @@
mutex_lock(&mfd->writeback_mutex);
list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
mutex_unlock(&mfd->writeback_mutex);
+ mfd->writeback_active_cnt--;
mutex_unlock(&mfd->unregister_mutex);
wake_up(&mfd->wait_q);
}
@@ -323,6 +325,7 @@
if (node) {
list_del(&(node->active_entry));
node->state = IN_BUSY_QUEUE;
+ mfd->writeback_active_cnt++;
}
mutex_unlock(&mfd->writeback_mutex);
@@ -367,6 +370,7 @@
mutex_lock(&mfd->writeback_mutex);
list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
+ mfd->writeback_active_cnt--;
mutex_unlock(&mfd->writeback_mutex);
wake_up(&mfd->wait_q);
fail_no_blt_addr:
@@ -523,13 +527,26 @@
return rc;
}
+static bool is_writeback_inactive(struct msm_fb_data_type *mfd)
+{
+ bool active;
+ mutex_lock(&mfd->writeback_mutex);
+ active = !mfd->writeback_active_cnt;
+ mutex_unlock(&mfd->writeback_mutex);
+ return active;
+}
int mdp4_writeback_stop(struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
mutex_lock(&mfd->writeback_mutex);
mfd->writeback_state = WB_STOPING;
mutex_unlock(&mfd->writeback_mutex);
+ /* Wait for all pending writebacks to finish */
+ wait_event_interruptible(mfd->wait_q, is_writeback_inactive(mfd));
+
+ /* Wake up dequeue thread in case of no UI update*/
wake_up(&mfd->wait_q);
+
return 0;
}
int mdp4_writeback_init(struct fb_info *info)
@@ -549,8 +566,19 @@
struct list_head *ptr, *next;
struct msmfb_writeback_data_list *temp;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int rc = 0;
+
mutex_lock(&mfd->unregister_mutex);
mutex_lock(&mfd->writeback_mutex);
+
+ if (mfd->writeback_state != WB_STOPING &&
+ mfd->writeback_state != WB_STOP) {
+ pr_err("%s called without stopping\n", __func__);
+ rc = -EPERM;
+ goto terminate_err;
+
+ }
+
if (!list_empty(&mfd->writeback_register_queue)) {
list_for_each_safe(ptr, next,
&mfd->writeback_register_queue) {
@@ -564,7 +592,10 @@
INIT_LIST_HEAD(&mfd->writeback_register_queue);
INIT_LIST_HEAD(&mfd->writeback_busy_queue);
INIT_LIST_HEAD(&mfd->writeback_free_queue);
+
+
+terminate_err:
mutex_unlock(&mfd->writeback_mutex);
mutex_unlock(&mfd->unregister_mutex);
- return 0;
+ return rc;
}
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 9f528af..87753b2 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -184,6 +184,7 @@
u32 use_ov0_blt, ov0_blt_state;
u32 use_ov1_blt, ov1_blt_state;
u32 writeback_state;
+ bool writeback_active_cnt;
int cont_splash_done;
};
diff --git a/include/linux/input.h b/include/linux/input.h
index 6e7d6d9..191f7d7 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -817,7 +817,8 @@
#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
#define SW_HPHL_OVERCURRENT 0x0d /* set = over current on left hph */
#define SW_HPHR_OVERCURRENT 0x0e /* set = over current on right hph */
-#define SW_MAX 0x0f
+#define SW_UNSUPPORT_INSERT 0x0f /* set = unsupported device inserted */
+#define SW_MAX 0x10
#define SW_CNT (SW_MAX+1)
/*
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index aa808dc..14f2d43 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -52,6 +52,9 @@
u8 part_config;
u8 cache_ctrl;
u8 rst_n_function;
+ u8 max_packed_writes;
+ u8 max_packed_reads;
+ u8 packed_event_en;
unsigned int part_time; /* Units: ms */
unsigned int sa_timeout; /* Units: 100ns */
unsigned int generic_cmd6_time; /* Units: 10ms */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index cbd4fbd..2489bb5 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -249,7 +249,11 @@
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
MMC_CAP2_HS200_1_2V_SDR)
-#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */
+#define MMC_CAP2_DETECT_ON_ERR (1 << 7) /* On I/O err check card removal */
+#define MMC_CAP2_PACKED_RD (1 << 10) /* Allow packed read */
+#define MMC_CAP2_PACKED_WR (1 << 11) /* Allow packed write */
+#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
+ MMC_CAP2_PACKED_WR) /* Allow packed commands */
mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type;
#define MMC_HOST_PW_NOTIFY_NONE 0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index e124fbe..06539dff 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -140,6 +140,7 @@
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
#define R1_APP_CMD (1 << 5) /* sr, c */
+#define R1_EXP_EVENT (1 << 6) /* sr, a */
#define R1_STATE_IDLE 0
#define R1_STATE_READY 1
@@ -275,6 +276,10 @@
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
+#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
+#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
+#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
+#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
@@ -314,6 +319,8 @@
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
+#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
+#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
@@ -426,6 +433,14 @@
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
+
+#define EXT_CSD_PACKED_EVENT_EN (1 << 3)
+
+#define EXT_CSD_PACKED_FAILURE (1 << 3)
+
+#define EXT_CSD_PACKED_GENERIC_ERROR (1 << 0)
+#define EXT_CSD_PACKED_INDEXED_ERROR (1 << 1)
+
/*
* MMC_SWITCH access modes
*/
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index cb394e8..b4e14d2 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -292,7 +292,7 @@
#define INPUT_DEVICE_ID_LED_MAX 0x0f
#define INPUT_DEVICE_ID_SND_MAX 0x07
#define INPUT_DEVICE_ID_FF_MAX 0x7f
-#define INPUT_DEVICE_ID_SW_MAX 0x0f
+#define INPUT_DEVICE_ID_SW_MAX 0x10
#define INPUT_DEVICE_ID_MATCH_BUS 1
#define INPUT_DEVICE_ID_MATCH_VENDOR 2
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 1c492f9..d7e65b0 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -35,8 +35,10 @@
const struct dev_pm_ops *pm_ops);
void wcnss_wlan_unregister_pm_ops(struct device *dev,
const struct dev_pm_ops *pm_ops);
-void wcnss_register_thermal_mitigation(void (*tm_notify)(int));
-void wcnss_unregister_thermal_mitigation(void (*tm_notify)(int));
+void wcnss_register_thermal_mitigation(struct device *dev,
+ void (*tm_notify)(struct device *dev, int));
+void wcnss_unregister_thermal_mitigation(
+ void (*tm_notify)(struct device *dev, int));
struct platform_device *wcnss_get_platform_device(void);
struct wcnss_wlan_config *wcnss_get_wlan_config(void);
int wcnss_wlan_power(struct device *dev,
diff --git a/include/sound/jack.h b/include/sound/jack.h
index ccdc341..1b13cbb 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -35,24 +35,26 @@
* sound/core/jack.c.
*/
enum snd_jack_types {
- SND_JACK_HEADPHONE = 0x0001,
- SND_JACK_MICROPHONE = 0x0002,
+ SND_JACK_HEADPHONE = 0x0000001,
+ SND_JACK_MICROPHONE = 0x0000002,
SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
- SND_JACK_LINEOUT = 0x0004,
- SND_JACK_MECHANICAL = 0x0008, /* If detected separately */
- SND_JACK_VIDEOOUT = 0x0010,
+ SND_JACK_LINEOUT = 0x0000004,
+ SND_JACK_MECHANICAL = 0x0000008, /* If detected separately */
+ SND_JACK_VIDEOOUT = 0x0000010,
SND_JACK_AVOUT = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT,
- SND_JACK_OC_HPHL = 0x0020,
- SND_JACK_OC_HPHR = 0x0040,
+ /* */
+ SND_JACK_OC_HPHL = 0x0000020,
+ SND_JACK_OC_HPHR = 0x0000040,
+ SND_JACK_UNSUPPORTED = 0x0000080,
/* Kept separate from switches to facilitate implementation */
- SND_JACK_BTN_0 = 0x4000,
- SND_JACK_BTN_1 = 0x2000,
- SND_JACK_BTN_2 = 0x1000,
- SND_JACK_BTN_3 = 0x0800,
- SND_JACK_BTN_4 = 0x0400,
- SND_JACK_BTN_5 = 0x0200,
- SND_JACK_BTN_6 = 0x0100,
- SND_JACK_BTN_7 = 0x0080,
+ SND_JACK_BTN_0 = 0x4000000,
+ SND_JACK_BTN_1 = 0x2000000,
+ SND_JACK_BTN_2 = 0x1000000,
+ SND_JACK_BTN_3 = 0x0800000,
+ SND_JACK_BTN_4 = 0x0400000,
+ SND_JACK_BTN_5 = 0x0200000,
+ SND_JACK_BTN_6 = 0x0100000,
+ SND_JACK_BTN_7 = 0x0080000,
};
struct snd_jack {
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 80453a9..675f45b 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -32,6 +32,7 @@
SW_VIDEOOUT_INSERT,
SW_HPHL_OVERCURRENT,
SW_HPHR_OVERCURRENT,
+ SW_UNSUPPORT_INSERT,
};
static int snd_jack_dev_free(struct snd_device *device)
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 7d7db08..ff83197 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1775,6 +1775,9 @@
{"HEADPHONE", NULL, "HPHL"},
{"HEADPHONE", NULL, "HPHR"},
+ {"HPHL DAC", NULL, "CP"},
+ {"HPHR DAC", NULL, "CP"},
+
{"HPHL", NULL, "HPHL DAC"},
{"HPHL DAC", "NULL", "DAC4 MUX"},
{"HPHR", NULL, "HPHR DAC"},
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index cad9907..5d77afd 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -3546,6 +3546,10 @@
if (tabla_is_digital_gain_register(reg))
return 1;
+ /* HPH status registers */
+ if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
+ return 1;
+
return 0;
}
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index d8df2fd..0c72880 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -58,6 +58,8 @@
#define TABLA_MBHC_DEF_BUTTONS 8
#define TABLA_MBHC_DEF_RLOADS 5
+#define JACK_DETECT_GPIO 38
+
/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
@@ -97,6 +99,15 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static int apq8064_hs_detect_use_gpio = -1;
+module_param(apq8064_hs_detect_use_gpio, int, 0444);
+MODULE_PARM_DESC(apq8064_hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool apq8064_hs_detect_use_firmware;
+module_param(apq8064_hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(apq8064_hs_detect_use_firmware, "Use firmware for headset "
+ "detection");
+
static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -108,7 +119,7 @@
.micbias = TABLA_MICBIAS2,
.mclk_cb_fn = msm_enable_codec_ext_clk,
.mclk_rate = TABLA_EXT_CLK_RATE,
- .gpio = 0, /* MBHC GPIO is not configured */
+ .gpio = 0,
.gpio_irq = 0,
.gpio_level_insert = 1,
};
@@ -1037,10 +1048,10 @@
return ret;
}
-
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
+ uint32_t revision;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1097,6 +1108,48 @@
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ /* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+ revision = socinfo_get_version();
+ if (apq8064_hs_detect_use_gpio != -1) {
+ if (apq8064_hs_detect_use_gpio == 1)
+ pr_debug("%s: MBHC mechanical is enabled by request\n",
+ __func__);
+ else if (apq8064_hs_detect_use_gpio == 0)
+ pr_debug("%s: MBHC mechanical is disabled by request\n",
+ __func__);
+ else
+ pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+ apq8064_hs_detect_use_gpio);
+ } else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+ pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+ SOCINFO_VERSION_MAJOR(revision),
+ SOCINFO_VERSION_MINOR(revision));
+ } else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+ SOCINFO_VERSION_MINOR(revision) >= 1 &&
+ (machine_is_apq8064_cdp() ||
+ machine_is_apq8064_liquid())) ||
+ SOCINFO_VERSION_MAJOR(revision) > 1) {
+ pr_debug("%s: MBHC mechanical switch available APQ8064 "
+ "detected\n", __func__);
+ apq8064_hs_detect_use_gpio = 1;
+ }
+
+ if (apq8064_hs_detect_use_gpio == 1) {
+ pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+ mbhc_cfg.gpio = JACK_DETECT_GPIO;
+ mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+ err = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+ if (err < 0) {
+ pr_err("%s: gpio_request %d failed %d\n", __func__,
+ mbhc_cfg.gpio, err);
+ return err;
+ }
+ gpio_direction_input(JACK_DETECT_GPIO);
+ } else
+ pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+ mbhc_cfg.read_fw_bin = apq8064_hs_detect_use_firmware;
+
err = tabla_hs_detect(codec, &mbhc_cfg);
return err;
@@ -1857,6 +1910,8 @@
}
msm_free_headset_mic_gpios();
platform_device_unregister(msm_snd_device);
+ if (mbhc_cfg.gpio)
+ gpio_free(mbhc_cfg.gpio);
kfree(mbhc_cfg.calibration);
}
module_exit(msm_audio_exit);
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index b31ed65..2762bd6 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -39,6 +39,7 @@
#define SPK_AMP_POS 0x1
#define SPK_AMP_NEG 0x2
#define SPKR_BOOST_GPIO 15
+#define DEFAULT_PMIC_SPK_GAIN 0x0D
#define SITAR_EXT_CLK_RATE 12288000
#define SITAR_MBHC_DEF_BUTTONS 3
@@ -47,6 +48,7 @@
static int msm8930_spk_control;
static int msm8930_slim_0_rx_ch = 1;
static int msm8930_slim_0_tx_ch = 1;
+static int msm8930_pmic_spk_gain = DEFAULT_PMIC_SPK_GAIN;
static int msm8930_ext_spk_pamp;
static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
@@ -431,6 +433,39 @@
return 0;
}
+static const char *pmic_spk_gain_text[] = {
+ "NEG_6_DB", "NEG_4_DB", "NEG_2_DB", "ZERO_DB", "POS_2_DB", "POS_4_DB",
+ "POS_6_DB", "POS_8_DB", "POS_10_DB", "POS_12_DB", "POS_14_DB",
+ "POS_16_DB", "POS_18_DB", "POS_20_DB", "POS_22_DB", "POS_24_DB"
+};
+
+static const struct soc_enum msm8960_pmic_spk_gain_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pmic_spk_gain_text),
+ pmic_spk_gain_text),
+};
+
+static int msm8930_pmic_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8930_pmic_spk_gain = %d\n", __func__,
+ msm8930_pmic_spk_gain);
+ ucontrol->value.integer.value[0] = msm8930_pmic_spk_gain;
+ return 0;
+}
+
+static int msm8930_pmic_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ msm8930_pmic_spk_gain = ucontrol->value.integer.value[0];
+ ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
+ pr_debug("%s: msm8930_pmic_spk_gain = %d"
+ " ucontrol->value.integer.value[0] = %d\n", __func__,
+ msm8930_pmic_spk_gain,
+ (int) ucontrol->value.integer.value[0]);
+ return ret;
+}
+
static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
msm8930_set_spk),
@@ -438,6 +473,8 @@
msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("PMIC SPK Gain", msm8960_pmic_spk_gain_enum[0],
+ msm8930_pmic_gain_get, msm8930_pmic_gain_put),
};
static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
@@ -642,6 +679,9 @@
mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
sitar_hs_detect(codec, &mbhc_cfg);
+ /* Initialize default PMIC speaker gain */
+ pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+
return 0;
}