Merge "msm: rpm: RPM stubs to return success on 8064" into msm-3.0
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
new file mode 100644
index 0000000..9b4b82a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -0,0 +1,59 @@
+* ARM Generic Interrupt Controller
+
+ARM SMP cores are often associated with a GIC, providing per processor
+interrupts (PPI), shared processor interrupts (SPI) and software
+generated interrupts (SGI).
+
+Primary GIC is attached directly to the CPU and typically has PPIs and SGIs.
+Secondary GICs are cascaded into the upward interrupt controller and do not
+have PPIs or SGIs.
+
+Main node required properties:
+
+- compatible : should be one of:
+ "arm,cortex-a9-gic"
+ "arm,arm11mp-gic"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The type shall be a <u32> and the value shall be 3.
+
+ The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+ interrupts.
+
+ The 2nd cell contains the interrupt number for the interrupt type.
+ SPI interrupts are in the range [0-987]. PPI interrupts are in the
+ range [0-15].
+
+ The 3rd cell is the flags, encoded as follows:
+ bits[3:0] trigger type and level flags.
+ 1 = low-to-high edge triggered
+ 2 = high-to-low edge triggered
+ 4 = active high level-sensitive
+ 8 = active low level-sensitive
+ bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of
+ the 8 possible cpus attached to the GIC. A bit set to '1' indicated
+ the interrupt is wired to that CPU. Only valid for PPI interrupts.
+
+- reg : Specifies base physical address(s) and size of the GIC registers. The
+ first region is the GIC distributor register base and size. The 2nd region is
+ the GIC cpu interface register base and size.
+
+Optional
+- interrupts : Interrupt source of the parent interrupt controller. Only
+ present on secondary GICs.
+
+- cpu-offset : per-cpu offset within the distributor and cpu interface
+ regions, used when the GIC doesn't have banked registers. The offset is
+ cpu-offset * cpu-nr.
+
+Example:
+
+ intc: interrupt-controller@fff11000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0xfff11000 0x1000>,
+ <0xfff10100 0x100>;
+ };
+
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index ad180b2..64877d1 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -1,7 +1,11 @@
config ARM_GIC
+ select IRQ_DOMAIN
bool
select MSM_SHOW_RESUME_IRQ
+config GIC_NON_BANKED
+ bool
+
config ARM_VIC
bool
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index fea7044..a6b5d0b 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -24,17 +24,58 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
#include <linux/list.h>
#include <linux/smp.h>
#include <linux/cpu_pm.h>
#include <linux/cpumask.h>
#include <linux/io.h>
#include <linux/syscore_ops.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
#include <asm/irq.h>
+#include <asm/exception.h>
#include <asm/mach/irq.h>
#include <asm/hardware/gic.h>
#include <asm/system.h>
+#include <asm/localtimer.h>
+
+union gic_base {
+ void __iomem *common_base;
+ void __percpu __iomem **percpu_base;
+};
+
+struct gic_chip_data {
+ unsigned int irq_offset;
+ union gic_base dist_base;
+ union gic_base cpu_base;
+ unsigned int max_irq;
+#ifdef CONFIG_PM
+ unsigned int wakeup_irqs[32];
+ unsigned int enabled_irqs[32];
+#endif
+#ifdef CONFIG_CPU_PM
+ u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+ u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
+ u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
+ u32 __percpu *saved_ppi_enable;
+ u32 __percpu *saved_ppi_conf;
+#endif
+#ifdef CONFIG_IRQ_DOMAIN
+ struct irq_domain domain;
+#endif
+ unsigned int gic_irqs;
+#ifdef CONFIG_GIC_NON_BANKED
+ void __iomem *(*get_base)(union gic_base *);
+#endif
+};
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -61,22 +102,53 @@
static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
+#ifdef CONFIG_GIC_NON_BANKED
+static void __iomem *gic_get_percpu_base(union gic_base *base)
+{
+ return *__this_cpu_ptr(base->percpu_base);
+}
+
+static void __iomem *gic_get_common_base(union gic_base *base)
+{
+ return base->common_base;
+}
+
+static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
+{
+ return data->get_base(&data->dist_base);
+}
+
+static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
+{
+ return data->get_base(&data->cpu_base);
+}
+
+static inline void gic_set_base_accessor(struct gic_chip_data *data,
+ void __iomem *(*f)(union gic_base *))
+{
+ data->get_base = f;
+}
+#else
+#define gic_data_dist_base(d) ((d)->dist_base.common_base)
+#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
+#define gic_set_base_accessor(d,f)
+#endif
+
static inline void __iomem *gic_dist_base(struct irq_data *d)
{
struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
- return gic_data->dist_base;
+ return gic_data_dist_base(gic_data);
}
static inline void __iomem *gic_cpu_base(struct irq_data *d)
{
struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
- return gic_data->cpu_base;
+ return gic_data_cpu_base(gic_data);
}
static inline unsigned int gic_irq(struct irq_data *d)
{
- struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
- return d->irq - gic_data->irq_offset;
+ return d->hwirq;
}
/*
@@ -84,7 +156,7 @@
*/
static void gic_mask_irq(struct irq_data *d)
{
- u32 mask = 1 << (d->irq % 32);
+ u32 mask = 1 << (gic_irq(d) % 32);
raw_spin_lock(&irq_controller_lock);
writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
@@ -95,7 +167,7 @@
static void gic_unmask_irq(struct irq_data *d)
{
- u32 mask = 1 << (d->irq % 32);
+ u32 mask = 1 << (gic_irq(d) % 32);
raw_spin_lock(&irq_controller_lock);
if (gic_arch_extn.irq_unmask)
@@ -114,7 +186,7 @@
static int gic_suspend_one(struct gic_chip_data *gic)
{
unsigned int i;
- void __iomem *base = gic->dist_base;
+ void __iomem *base = gic_data_dist_base(gic);
for (i = 0; i * 32 < gic->max_irq; i++) {
gic->enabled_irqs[i]
@@ -144,7 +216,7 @@
unsigned int i;
u32 enabled;
unsigned long pending[32];
- void __iomem *base = gic->dist_base;
+ void __iomem *base = gic_data_dist_base(gic);
if (!msm_show_resume_irq_mask)
return;
@@ -168,7 +240,7 @@
static void gic_resume_one(struct gic_chip_data *gic)
{
unsigned int i;
- void __iomem *base = gic->dist_base;
+ void __iomem *base = gic_data_dist_base(gic);
gic_show_resume_irq(gic);
for (i = 0; i * 32 < gic->max_irq; i++) {
@@ -275,7 +347,7 @@
bool force)
{
void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
- unsigned int shift = (d->irq % 4) * 8;
+ unsigned int shift = (gic_irq(d) % 4) * 8;
unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
u32 val, mask, bit;
@@ -326,6 +398,32 @@
}
#endif
+asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+{
+ u32 irqstat, irqnr;
+ struct gic_chip_data *gic = &gic_data[0];
+ void __iomem *cpu_base = gic_data_cpu_base(gic);
+
+ do {
+ irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+ irqnr = irqstat & ~0x1c00;
+
+ if (likely(irqnr > 15 && irqnr < 1021)) {
+ irqnr = irq_domain_to_irq(&gic->domain, irqnr);
+ handle_IRQ(irqnr, regs);
+ continue;
+ }
+ if (irqnr < 16) {
+ writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+#ifdef CONFIG_SMP
+ handle_IPI(irqnr, regs);
+#endif
+ continue;
+ }
+ break;
+ } while (1);
+}
+
static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
{
struct gic_chip_data *chip_data = irq_get_handler_data(irq);
@@ -336,14 +434,14 @@
chained_irq_enter(chip, desc);
raw_spin_lock(&irq_controller_lock);
- status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK);
+ status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
raw_spin_unlock(&irq_controller_lock);
gic_irq = (status & 0x3ff);
if (gic_irq == 1023)
goto out;
- cascade_irq = gic_irq + chip_data->irq_offset;
+ cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
do_bad_IRQ(cascade_irq, desc);
else
@@ -376,12 +474,13 @@
irq_set_chained_handler(irq, gic_handle_cascade_irq);
}
-static void __init gic_dist_init(struct gic_chip_data *gic,
- unsigned int irq_start)
+static void __init gic_dist_init(struct gic_chip_data *gic)
{
- unsigned int gic_irqs, irq_limit, i;
+ unsigned int i, irq;
u32 cpumask;
- void __iomem *base = gic->dist_base;
+ unsigned int gic_irqs = gic->gic_irqs;
+ struct irq_domain *domain = &gic->domain;
+ void __iomem *base = gic_data_dist_base(gic);
u32 cpu = 0;
#ifdef CONFIG_SMP
@@ -395,17 +494,6 @@
writel_relaxed(0, base + GIC_DIST_CTRL);
/*
- * Find out how many interrupts are supported.
- * The GIC only supports up to 1020 interrupt sources.
- */
- gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f;
- gic_irqs = (gic_irqs + 1) * 32;
- if (gic_irqs > 1020)
- gic_irqs = 1020;
-
- gic->gic_irqs = gic_irqs;
-
- /*
* Set all global interrupts to be level triggered, active low.
*/
for (i = 32; i < gic_irqs; i += 16)
@@ -431,19 +519,20 @@
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
/*
- * Limit number of interrupts registered to the platform maximum
- */
- irq_limit = gic->irq_offset + gic_irqs;
- if (WARN_ON(irq_limit > NR_IRQS))
- irq_limit = NR_IRQS;
-
- /*
* Setup the Linux IRQ subsystem.
*/
- for (i = irq_start; i < irq_limit; i++) {
- irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
- irq_set_chip_data(i, gic);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ irq_domain_for_each_irq(domain, i, irq) {
+ if (i < 32) {
+ irq_set_percpu_devid(irq);
+ irq_set_chip_and_handler(irq, &gic_chip,
+ handle_percpu_devid_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+ } else {
+ irq_set_chip_and_handler(irq, &gic_chip,
+ handle_fasteoi_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ irq_set_chip_data(irq, gic);
}
gic->max_irq = gic_irqs;
@@ -454,8 +543,8 @@
static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
{
- void __iomem *dist_base = gic->dist_base;
- void __iomem *base = gic->cpu_base;
+ void __iomem *dist_base = gic_data_dist_base(gic);
+ void __iomem *base = gic_data_cpu_base(gic);
int i;
/*
@@ -493,7 +582,7 @@
BUG();
gic_irqs = gic_data[gic_nr].gic_irqs;
- dist_base = gic_data[gic_nr].dist_base;
+ dist_base = gic_data_dist_base(&gic_data[gic_nr]);
if (!dist_base)
return;
@@ -528,7 +617,7 @@
BUG();
gic_irqs = gic_data[gic_nr].gic_irqs;
- dist_base = gic_data[gic_nr].dist_base;
+ dist_base = gic_data_dist_base(&gic_data[gic_nr]);
if (!dist_base)
return;
@@ -564,8 +653,8 @@
if (gic_nr >= MAX_GIC_NR)
BUG();
- dist_base = gic_data[gic_nr].dist_base;
- cpu_base = gic_data[gic_nr].cpu_base;
+ dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+ cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
if (!dist_base || !cpu_base)
return;
@@ -590,8 +679,8 @@
if (gic_nr >= MAX_GIC_NR)
BUG();
- dist_base = gic_data[gic_nr].dist_base;
- cpu_base = gic_data[gic_nr].cpu_base;
+ dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+ cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
if (!dist_base || !cpu_base)
return;
@@ -616,6 +705,11 @@
int i;
for (i = 0; i < MAX_GIC_NR; i++) {
+#ifdef CONFIG_GIC_NON_BANKED
+ /* Skip over unused GICs */
+ if (!gic_data[i].get_base)
+ continue;
+#endif
switch (cmd) {
case CPU_PM_ENTER:
gic_cpu_save(i);
@@ -659,23 +753,114 @@
}
#endif
-void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
- void __iomem *dist_base, void __iomem *cpu_base)
+#ifdef CONFIG_OF
+static int gic_irq_domain_dt_translate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ if (d->of_node != controller)
+ return -EINVAL;
+ if (intsize < 3)
+ return -EINVAL;
+
+ /* Get the interrupt number and add 16 to skip over SGIs */
+ *out_hwirq = intspec[1] + 16;
+
+ /* For SPIs, we need to add 16 more to get the GIC irq ID number */
+ if (!intspec[0])
+ *out_hwirq += 16;
+
+ *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+ return 0;
+}
+#endif
+
+const struct irq_domain_ops gic_irq_domain_ops = {
+#ifdef CONFIG_OF
+ .dt_translate = gic_irq_domain_dt_translate,
+#endif
+};
+
+void __init gic_init_bases(unsigned int gic_nr, int irq_start,
+ void __iomem *dist_base, void __iomem *cpu_base,
+ u32 percpu_offset)
{
struct gic_chip_data *gic;
+ struct irq_domain *domain;
+ int gic_irqs;
BUG_ON(gic_nr >= MAX_GIC_NR);
gic = &gic_data[gic_nr];
- gic->dist_base = dist_base;
- gic->cpu_base = cpu_base;
- gic->irq_offset = (irq_start - 1) & ~31;
+ domain = &gic->domain;
+#ifdef CONFIG_GIC_NON_BANKED
+ if (percpu_offset) { /* Frankein-GIC without banked registers... */
+ unsigned int cpu;
- if (gic_nr == 0)
+ gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
+ gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
+ if (WARN_ON(!gic->dist_base.percpu_base ||
+ !gic->cpu_base.percpu_base)) {
+ free_percpu(gic->dist_base.percpu_base);
+ free_percpu(gic->cpu_base.percpu_base);
+ return;
+ }
+
+ for_each_possible_cpu(cpu) {
+ unsigned long offset = percpu_offset * cpu_logical_map(cpu);
+ *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
+ *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
+ }
+
+ gic_set_base_accessor(gic, gic_get_percpu_base);
+ } else
+#endif
+ { /* Normal, sane GIC... */
+ WARN(percpu_offset,
+ "GIC_NON_BANKED not enabled, ignoring %08x offset!",
+ percpu_offset);
+ gic->dist_base.common_base = dist_base;
+ gic->cpu_base.common_base = cpu_base;
+ gic_set_base_accessor(gic, gic_get_common_base);
+ }
+
+ /*
+ * For primary GICs, skip over SGIs.
+ * For secondary GICs, skip over PPIs, too.
+ */
+ if (gic_nr == 0) {
gic_cpu_base_addr = cpu_base;
+ domain->hwirq_base = 16;
+ if (irq_start > 0)
+ irq_start = (irq_start & ~31) + 16;
+ } else
+ domain->hwirq_base = 32;
+
+ /*
+ * Find out how many interrupts are supported.
+ * The GIC only supports up to 1020 interrupt sources.
+ */
+ gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
+ gic_irqs = (gic_irqs + 1) * 32;
+ if (gic_irqs > 1020)
+ gic_irqs = 1020;
+ gic->gic_irqs = gic_irqs;
+
+ domain->nr_irq = gic_irqs - domain->hwirq_base;
+ domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
+ numa_node_id());
+ if (IS_ERR_VALUE(domain->irq_base)) {
+ WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
+ irq_start);
+ domain->irq_base = irq_start;
+ }
+ domain->priv = gic;
+ domain->ops = &gic_irq_domain_ops;
+ irq_domain_add(domain);
gic_chip.flags |= gic_arch_extn.flags;
- gic_dist_init(gic, irq_start);
+ gic_dist_init(gic);
gic_cpu_init(gic);
gic_pm_init(gic);
}
@@ -687,16 +872,6 @@
gic_cpu_init(&gic_data[gic_nr]);
}
-void __cpuinit gic_enable_ppi(unsigned int irq)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- irq_set_status_flags(irq, IRQ_NOPROBE);
- gic_unmask_irq(irq_get_irq_data(irq));
- local_irq_restore(flags);
-}
-
#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
@@ -714,7 +889,7 @@
dsb();
/* this always happens on GIC0 */
- writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
+ writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
mb();
}
#endif
@@ -759,3 +934,38 @@
GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
raw_spin_unlock(&irq_controller_lock);
}
+#ifdef CONFIG_OF
+static int gic_cnt __initdata = 0;
+
+int __init gic_of_init(struct device_node *node, struct device_node *parent)
+{
+ void __iomem *cpu_base;
+ void __iomem *dist_base;
+ u32 percpu_offset;
+ int irq;
+ struct irq_domain *domain = &gic_data[gic_cnt].domain;
+
+ if (WARN_ON(!node))
+ return -ENODEV;
+
+ dist_base = of_iomap(node, 0);
+ WARN(!dist_base, "unable to map gic dist registers\n");
+
+ cpu_base = of_iomap(node, 1);
+ WARN(!cpu_base, "unable to map gic cpu registers\n");
+
+ if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
+ percpu_offset = 0;
+
+ domain->of_node = of_node_get(node);
+
+ gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
+
+ if (parent) {
+ irq = irq_of_parse_and_map(node, 0);
+ gic_cascade_irq(gic_cnt, irq);
+ }
+ gic_cnt++;
+ return 0;
+}
+#endif
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 4d4c27f..1379334 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -32,19 +32,19 @@
CONFIG_ARCH_MSMCOPPER=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_DEBUG_MSMCOPPER_UART=y
CONFIG_CPU_HAS_L2_PMU=y
-# CONFIG_MSM_JTAG_V7 is not set
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
# CONFIG_MSM_DALRPC is not set
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+# CONFIG_MSM_JTAG_V7 is not set
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
# CONFIG_SMP_ON_UP is not set
CONFIG_ARM_ARCH_TIMER=y
+CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
@@ -56,7 +56,6 @@
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_SUSPEND is not set
-CONFIG_HOTPLUG_CPU=y
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_INET=y
@@ -111,7 +110,6 @@
CONFIG_MMC_MSM=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
-# CONFIG_LEDS_MSM_PMIC is not set
CONFIG_SWITCH=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
@@ -133,6 +131,7 @@
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
diff --git a/arch/arm/configs/msm7627-perf_defconfig b/arch/arm/configs/msm7627-perf_defconfig
index 0f2ffc1..ea5c7c9 100644
--- a/arch/arm/configs/msm7627-perf_defconfig
+++ b/arch/arm/configs/msm7627-perf_defconfig
@@ -110,6 +110,8 @@
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -151,6 +153,8 @@
# CONFIG_WIRELESS_EXT_SYSFS is not set
CONFIG_RFKILL=y
# CONFIG_RFKILL_PM is not set
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_MTD=y
CONFIG_MTD_TESTS=m
CONFIG_MTD_CMDLINE_PARTS=y
diff --git a/arch/arm/configs/msm7627_defconfig b/arch/arm/configs/msm7627_defconfig
index d1d0e66..0841f7e 100644
--- a/arch/arm/configs/msm7627_defconfig
+++ b/arch/arm/configs/msm7627_defconfig
@@ -110,6 +110,8 @@
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -151,6 +153,8 @@
# CONFIG_WIRELESS_EXT_SYSFS is not set
CONFIG_RFKILL=y
# CONFIG_RFKILL_PM is not set
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_MTD=y
CONFIG_MTD_TESTS=m
CONFIG_MTD_CMDLINE_PARTS=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 45b6e60..ca974b2 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -124,6 +124,8 @@
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -249,6 +251,7 @@
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
+CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
CONFIG_USB=y
@@ -305,6 +308,7 @@
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 7e91971..eb9cd7c 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -122,6 +122,8 @@
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -248,6 +250,7 @@
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_MSM_SOC=y
+CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
CONFIG_USB=y
@@ -300,6 +303,7 @@
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index e5fec35..e319f0d 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -120,6 +120,8 @@
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -352,6 +354,7 @@
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 6e3290b..388bb69 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -119,6 +119,8 @@
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -337,6 +339,7 @@
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 3346397..84cd633 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -62,7 +62,9 @@
CONFIG_MSM_RMT_STORAGE_CLIENT=y
CONFIG_MSM_SDIO_SMEM=y
# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_MODEM=y
CONFIG_MSM_PIL_QDSP6V3=y
+CONFIG_MSM_PIL_TZAPPS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
@@ -156,6 +158,8 @@
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -418,6 +422,7 @@
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
@@ -441,3 +446,6 @@
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 654edb53..3763bc1 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -54,7 +54,9 @@
# CONFIG_MSM_RPCSERVER_HANDSET is not set
CONFIG_MSM_RMT_STORAGE_CLIENT=y
# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_MODEM=y
CONFIG_MSM_PIL_QDSP6V3=y
+CONFIG_MSM_PIL_TZAPPS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
@@ -146,6 +148,8 @@
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -403,6 +407,7 @@
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
new file mode 100644
index 0000000..9feca99
--- /dev/null
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -0,0 +1,432 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8960=y
+CONFIG_ARCH_MSM8930=y
+CONFIG_ARCH_APQ8064=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MACH_MSM8960_SIM=y
+CONFIG_MACH_MSM8960_RUMI3=y
+CONFIG_MACH_MSM8960_CDP=y
+CONFIG_MACH_MSM8960_MTP=y
+CONFIG_MACH_MSM8960_FLUID=y
+CONFIG_MACH_MSM8960_LIQUID=y
+CONFIG_MACH_MSM8930_CDP=y
+CONFIG_MACH_MSM8930_MTP=y
+CONFIG_MACH_MSM8930_FLUID=y
+CONFIG_MACH_MSM8627_CDP=y
+CONFIG_MACH_MSM8627_MTP=y
+CONFIG_MACH_APQ8064_SIM=y
+CONFIG_MACH_APQ8064_RUMI3=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_KERNEL_PMEM_EBI_REGION=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_DSPS=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_RIVA=y
+CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_MODEM_8960=y
+CONFIG_MSM_LPASS_8960=y
+CONFIG_MSM_WCNSS_SSR_8960=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
+CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_QDSS=y
+CONFIG_MSM_SLEEP_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_TZCOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMC91X=y
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+CONFIG_KS8851=m
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WCNSS_CORE=y
+CONFIG_USB_USBNET=y
+CONFIG_MSM_RMNET_USB=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_PMIC8XXX=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_CYTTSP_I2C=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_HS=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_ISL9519_CHARGER=y
+CONFIG_PM8921_CHARGER=y
+CONFIG_PM8921_BMS=y
+CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8960=y
+CONFIG_THERMAL_PM8XXX=y
+CONFIG_MFD_PM8921_CORE=y
+CONFIG_MFD_PM8821_CORE=y
+CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_PM8XXX=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MT9M114=y
+CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_GEMINI=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
+CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8960=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_QCOM_DIAG_BRIDGE=y
+CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
+# CONFIG_MMC_MSM_SDC2_SUPPORT is not set
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_WP_SUPPORT=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_PM8XXX=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_CIFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 2abe7e9..bb81a33 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -61,6 +61,8 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_RIVA=y
+CONFIG_MSM_PIL_TZAPPS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_MODEM_8960=y
CONFIG_MSM_LPASS_8960=y
@@ -83,6 +85,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -156,6 +159,8 @@
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -236,6 +241,7 @@
# CONFIG_NETDEV_10000 is not set
CONFIG_WCNSS_CORE=y
CONFIG_USB_USBNET=y
+CONFIG_MSM_RMNET_USB=y
CONFIG_SLIP=y
CONFIG_SLIP_COMPRESSED=y
CONFIG_SLIP_MODE_SLIP6=y
@@ -284,6 +290,7 @@
CONFIG_MFD_PM8038_CORE=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_PM8XXX=y
CONFIG_REGULATOR_GPIO=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
@@ -322,6 +329,7 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8960=y
+CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
CONFIG_USB=y
@@ -392,6 +400,7 @@
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
@@ -410,7 +419,8 @@
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
-CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
@@ -418,6 +428,11 @@
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAILSLAB=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index ed9a45b..31bde4d 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -139,7 +139,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
CONFIG_MFD_PM8018_CORE=y
-CONFIG_REGULATOR=y
+CONFIG_REGULATOR_PM8XXX=y
CONFIG_REGULATOR_GPIO=y
# CONFIG_HID_SUPPORT is not set
CONFIG_USB=y
diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S
index 2f1e209..88d6181 100644
--- a/arch/arm/include/asm/entry-macro-multi.S
+++ b/arch/arm/include/asm/entry-macro-multi.S
@@ -25,13 +25,6 @@
movne r1, sp
adrne lr, BSYM(1b)
bne do_IPI
-
-#ifdef CONFIG_LOCAL_TIMERS
- test_for_ltirq r0, r2, r6, lr
- movne r0, sp
- adrne lr, BSYM(1b)
- bne do_local_timer
-#endif
#endif
9997:
.endm
diff --git a/arch/arm/include/asm/exception.h b/arch/arm/include/asm/exception.h
new file mode 100644
index 0000000..5abaf5b
--- /dev/null
+++ b/arch/arm/include/asm/exception.h
@@ -0,0 +1,19 @@
+/*
+ * Annotations for marking C functions as exception handlers.
+ *
+ * These should only be used for C functions that are called from the low
+ * level exception entry code and not any intervening C code.
+ */
+#ifndef __ASM_ARM_EXCEPTION_H
+#define __ASM_ARM_EXCEPTION_H
+
+#include <linux/ftrace.h>
+
+#define __exception __attribute__((section(".exception.text")))
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#define __exception_irq_entry __irq_entry
+#else
+#define __exception_irq_entry __exception
+#endif
+
+#endif /* __ASM_ARM_EXCEPTION_H */
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index 41c8c06..bb0d03d 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -9,9 +9,6 @@
typedef struct {
unsigned int __softirq_pending;
-#ifdef CONFIG_LOCAL_TIMERS
- unsigned int local_timer_irqs;
-#endif
#ifdef CONFIG_SMP
unsigned int ipi_irqs[NR_IPI];
#endif
diff --git a/arch/arm/include/asm/hardware/entry-macro-gic.S b/arch/arm/include/asm/hardware/entry-macro-gic.S
index c115b82..74ebc80 100644
--- a/arch/arm/include/asm/hardware/entry-macro-gic.S
+++ b/arch/arm/include/asm/hardware/entry-macro-gic.S
@@ -22,15 +22,11 @@
* interrupt controller spec. To wit:
*
* Interrupts 0-15 are IPI
- * 16-28 are reserved
- * 29-31 are local. We allow 30 to be used for the watchdog.
+ * 16-31 are local. We allow 30 to be used for the watchdog.
* 32-1020 are global
* 1021-1022 are reserved
* 1023 is "spurious" (no interrupt)
*
- * For now, we ignore all local interrupts so only return an interrupt if it's
- * between 30 and 1020. The test_for_ipi routine below will pick up on IPIs.
- *
* A simple read from the controller will tell us the number of the highest
* priority enabled interrupt. We then just need to check whether it is in the
* valid range for an IRQ (30-1020 inclusive).
@@ -43,7 +39,7 @@
ldr \tmp, =1021
bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #29
+ cmp \irqnr, #15
cmpcc \irqnr, \irqnr
cmpne \irqnr, \tmp
cmpcs \irqnr, \irqnr
@@ -62,14 +58,3 @@
strcc \irqstat, [\base, #GIC_CPU_EOI]
cmpcs \irqnr, \irqnr
.endm
-
-/* As above, this assumes that irqstat and base are preserved.. */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- bic \irqnr, \irqstat, #0x1c00
- mov \tmp, #0
- cmp \irqnr, #29
- moveq \tmp, #1
- streq \irqstat, [\base, #GIC_CPU_EOI]
- cmp \tmp, #0
- .endm
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 9491ab3..8bfbcfa 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -33,35 +33,29 @@
#define GIC_DIST_SOFTINT 0xf00
#ifndef __ASSEMBLY__
+#include <linux/irqdomain.h>
+struct device_node;
+
extern void __iomem *gic_cpu_base_addr;
extern struct irq_chip gic_arch_extn;
-void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
+void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
+ u32 offset);
+int gic_of_init(struct device_node *node, struct device_node *parent);
void gic_secondary_init(unsigned int);
+void gic_handle_irq(struct pt_regs *regs);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
void gic_enable_ppi(unsigned int);
bool gic_is_spi_pending(unsigned int irq);
void gic_clear_spi_pending(unsigned int irq);
-struct gic_chip_data {
- unsigned int irq_offset;
- void __iomem *dist_base;
- void __iomem *cpu_base;
- unsigned int max_irq;
-#ifdef CONFIG_PM
- unsigned int wakeup_irqs[32];
- unsigned int enabled_irqs[32];
-#endif
-#ifdef CONFIG_CPU_PM
- u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
- u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
- u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
- u32 __percpu *saved_ppi_enable;
- u32 __percpu *saved_ppi_conf;
-#endif
- unsigned int gic_irqs;
-};
+static inline void gic_init(unsigned int nr, int start,
+ void __iomem *dist , void __iomem *cpu)
+{
+ gic_init_bases(nr, start, dist, cpu, 0);
+}
+
#endif
#endif
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index 080d74f..f5e1cec 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -10,6 +10,8 @@
#ifndef __ASM_ARM_LOCALTIMER_H
#define __ASM_ARM_LOCALTIMER_H
+#include <linux/interrupt.h>
+
struct clock_event_device;
/*
@@ -17,27 +19,20 @@
*/
void percpu_timer_setup(void);
-/*
- * Called from assembly, this is the local timer IRQ handler
- */
-asmlinkage void do_local_timer(struct pt_regs *);
-
-
#ifdef CONFIG_LOCAL_TIMERS
#ifdef CONFIG_HAVE_ARM_TWD
#include "smp_twd.h"
-#define local_timer_ack() twd_timer_ack()
+#define local_timer_stop(c) twd_timer_stop((c))
#else
/*
- * Platform provides this to acknowledge a local timer IRQ.
- * Returns true if the local timer IRQ is to be processed.
+ * Stop the local timer
*/
-int local_timer_ack(void);
+void local_timer_stop(struct clock_event_device *);
#endif
@@ -52,6 +47,10 @@
{
return -ENXIO;
}
+
+static inline void local_timer_stop(struct clock_event_device *evt)
+{
+}
#endif
#endif
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index c86fad9..75ec143 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -130,6 +130,8 @@
void (*sdio_lpm_gpio_setup)(struct device *, unsigned int);
unsigned int status_irq;
unsigned int status_gpio;
+ /* Indicates the polarity of the GPIO line when card is inserted */
+ bool is_status_gpio_active_low;
unsigned int sdiowakeup_irq;
unsigned long irq_flags;
unsigned long mmc_bus_width;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 8145184..f5a72b0 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -99,11 +99,5 @@
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-/*
- * show local interrupt info
- */
-extern void show_local_irqs(struct seq_file *, int);
-
extern void smp_send_all_cpu_backtrace(void);
-
#endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index fed9981..ef9ffba9 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -22,7 +22,7 @@
extern void __iomem *twd_base;
-int twd_timer_ack(void);
void twd_timer_setup(struct clock_event_device *);
+void twd_timer_stop(struct clock_event_device *);
#endif
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index d3808b5..4dccb04 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -62,13 +62,6 @@
#include <asm/outercache.h>
-#define __exception __attribute__((section(".exception.text")))
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-#define __exception_irq_entry __irq_entry
-#else
-#define __exception_irq_entry __exception
-#endif
-
void cpu_idle_wait(void);
struct thread_info;
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 0cd27bc..5070470 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -25,7 +25,6 @@
#include <asm/sched_clock.h>
#include <asm/hardware/gic.h>
-static struct irqaction arch_irqaction[2];
static unsigned long arch_timer_rate;
static int arch_timer_ppi;
static int arch_timer_ppi2;
@@ -151,9 +150,9 @@
clockevents_config_and_register(clk, arch_timer_rate,
0xf, 0x7fffffff);
- gic_enable_ppi(arch_timer_ppi);
+ enable_percpu_irq(arch_timer_ppi, 0);
if (arch_timer_ppi2 > 0)
- gic_enable_ppi(arch_timer_ppi2);
+ enable_percpu_irq(arch_timer_ppi2, 0);
}
/* Is the optional system timer available? */
@@ -256,11 +255,9 @@
struct clock_event_device *clk = data;
pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
clk->irq, smp_processor_id());
- if (!smp_processor_id()) {
- remove_irq(arch_timer_ppi, &arch_irqaction[0]);
- if (arch_timer_ppi2 > 0)
- remove_irq(arch_timer_ppi2, &arch_irqaction[1]);
- }
+ disable_percpu_irq(arch_timer_ppi);
+ if (arch_timer_ppi2 > 0)
+ disable_percpu_irq(arch_timer_ppi2);
arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
}
@@ -291,8 +288,6 @@
int __init arch_timer_register(struct resource *res, int res_nr)
{
- struct irqaction *irqa;
- unsigned int cpu = smp_processor_id();
int err;
if (!res_nr || res[0].start < 0 || !(res[0].flags & IORESOURCE_IRQ))
@@ -319,34 +314,24 @@
set_delay_fn(read_current_timer_delay_loop);
#endif
- irqa = &arch_irqaction[0];
- irqa->name = "arch_sys_timer";
- irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
- irqa->handler = arch_timer_handler;
- irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
- irqa->irq = arch_timer_ppi;
- err = setup_irq(arch_timer_ppi, irqa);
+ err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
+ "arch_sys_timer", arch_timer_evt);
if (err) {
pr_err("%s: can't register interrupt %d (%d)\n",
- irqa->name, irqa->irq, err);
+ "arch_sys_timer", arch_timer_ppi, err);
return err;
}
if (arch_timer_ppi2 > 0) {
- irqa = &arch_irqaction[1];
- irqa->name = "arch_sys_timer";
- irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
- irqa->handler = arch_timer_handler;
- irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
- irqa->irq = arch_timer_ppi2;
- err = setup_irq(arch_timer_ppi2, irqa);
+ err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
+ "arch_sys_timer", arch_timer_evt);
if (err)
pr_warn("%s: can't register interrupt %d (%d)\n",
- irqa->name, irqa->irq, err);
+ "arch_sys_timer", arch_timer_ppi2, err);
}
/* Immediately configure the timer on the boot CPU */
- arch_timer_setup(per_cpu_ptr(arch_timer_evt, cpu));
+ arch_timer_setup(per_cpu_ptr(arch_timer_evt, smp_processor_id()));
register_cpu_notifier(&arch_timer_cpu_nb);
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 5bd484f..44681532 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -35,8 +35,8 @@
#include <linux/list.h>
#include <linux/kallsyms.h>
#include <linux/proc_fs.h>
-#include <linux/ftrace.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
@@ -61,9 +61,6 @@
#ifdef CONFIG_SMP
show_ipi_list(p, prec);
#endif
-#ifdef CONFIG_LOCAL_TIMERS
- show_local_irqs(p, prec);
-#endif
seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
return 0;
}
@@ -114,7 +111,7 @@
{
unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
- if (irq >= nr_irqs) {
+ if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
return;
}
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
index 8fa2f30..e37d2a7 100644
--- a/arch/arm/kernel/perf_event_msm.c
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -474,24 +474,31 @@
{
u32 venum_new_val;
u32 fp_new_val;
+ u32 v_orig_val;
+ u32 f_orig_val;
- /* CPACR Enable CP10 access*/
- venum_orig_val = get_copro_access();
- venum_new_val = venum_orig_val | CPACC_SVC(10);
+ /* CPACR Enable CP10 access */
+ v_orig_val = get_copro_access();
+ venum_new_val = v_orig_val | CPACC_SVC(10);
set_copro_access(venum_new_val);
+ /* Store orig venum val */
+ __get_cpu_var(venum_orig_val) = v_orig_val;
+
/* Enable FPEXC */
- fp_orig_val = fmrx(FPEXC);
- fp_new_val = fp_orig_val | FPEXC_EN;
+ f_orig_val = fmrx(FPEXC);
+ fp_new_val = f_orig_val | FPEXC_EN;
fmxr(FPEXC, fp_new_val);
+ /* Store orig fp val */
+ __get_cpu_var(fp_orig_val) = f_orig_val;
}
static void scorpion_post_vlpm(void)
{
- /* Restore FPEXC*/
- fmxr(FPEXC, fp_orig_val);
+ /* Restore FPEXC */
+ fmxr(FPEXC, __get_cpu_var(fp_orig_val));
isb();
- /* Restore CPACR*/
- set_copro_access(venum_orig_val);
+ /* Restore CPACR */
+ set_copro_access(__get_cpu_var(venum_orig_val));
}
struct scorpion_access_funcs {
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9fe0964..0faa7ea 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -16,7 +16,6 @@
#include <linux/cache.h>
#include <linux/profile.h>
#include <linux/errno.h>
-#include <linux/ftrace.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/cpu.h>
@@ -31,6 +30,8 @@
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
+#include <asm/exception.h>
+#include <asm/topology.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -449,10 +450,6 @@
for (i = 0; i < NR_IPI; i++)
sum += __get_irq_stat(cpu, ipi_irqs[i]);
-#ifdef CONFIG_LOCAL_TIMERS
- sum += __get_irq_stat(cpu, local_timer_irqs);
-#endif
-
return sum;
}
@@ -469,33 +466,6 @@
irq_exit();
}
-#ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
-{
- struct pt_regs *old_regs = set_irq_regs(regs);
- int cpu = smp_processor_id();
-
- if (local_timer_ack()) {
- __inc_irq_stat(cpu, local_timer_irqs);
- ipi_timer();
- }
-
- set_irq_regs(old_regs);
-}
-
-void show_local_irqs(struct seq_file *p, int prec)
-{
- unsigned int cpu;
-
- seq_printf(p, "%*s: ", prec, "LOC");
-
- for_each_present_cpu(cpu)
- seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
-
- seq_printf(p, " Local timer interrupts\n");
-}
-#endif
-
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
static void smp_timer_broadcast(const struct cpumask *mask)
{
@@ -546,7 +516,7 @@
unsigned int cpu = smp_processor_id();
struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
- evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+ local_timer_stop(evt);
}
#endif
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index f62743c..d4c8c36 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
#include <asm/hardware/gic.h>
/* set up by the platform code */
@@ -26,6 +27,8 @@
static unsigned long twd_timer_rate;
+static struct clock_event_device __percpu **twd_evt;
+
static void twd_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
@@ -80,6 +83,12 @@
return 0;
}
+void twd_timer_stop(struct clock_event_device *clk)
+{
+ twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+ disable_percpu_irq(clk->irq);
+}
+
static void __cpuinit twd_calibrate_rate(void)
{
unsigned long count;
@@ -119,11 +128,43 @@
}
}
+static irqreturn_t twd_handler(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+
+ if (twd_timer_ack()) {
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
/*
* Setup the local clock events for a CPU.
*/
void __cpuinit twd_timer_setup(struct clock_event_device *clk)
{
+ struct clock_event_device **this_cpu_clk;
+
+ if (!twd_evt) {
+ int err;
+
+ twd_evt = alloc_percpu(struct clock_event_device *);
+ if (!twd_evt) {
+ pr_err("twd: can't allocate memory\n");
+ return;
+ }
+
+ err = request_percpu_irq(clk->irq, twd_handler,
+ "twd", twd_evt);
+ if (err) {
+ pr_err("twd: can't register interrupt %d (%d)\n",
+ clk->irq, err);
+ return;
+ }
+ }
+
twd_calibrate_rate();
clk->name = "local_timer";
@@ -136,8 +177,10 @@
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
- /* Make sure our local interrupt controller has this enabled */
- gic_enable_ppi(clk->irq);
+ this_cpu_clk = __this_cpu_ptr(twd_evt);
+ *this_cpu_clk = clk;
clockevents_register_device(clk);
+
+ enable_percpu_irq(clk->irq, 0);
}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index ef37557..76f86d7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -28,6 +28,7 @@
#include <asm/atomic.h>
#include <asm/cacheflush.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/unistd.h>
#include <asm/traps.h>
diff --git a/arch/arm/mach-exynos4/include/mach/entry-macro.S b/arch/arm/mach-exynos4/include/mach/entry-macro.S
index d8f38c2..9be072f 100644
--- a/arch/arm/mach-exynos4/include/mach/entry-macro.S
+++ b/arch/arm/mach-exynos4/include/mach/entry-macro.S
@@ -50,7 +50,7 @@
bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #29
+ cmp \irqnr, #15
cmpcc \irqnr, \irqnr
cmpne \irqnr, \tmp
cmpcs \irqnr, \irqnr
@@ -71,14 +71,3 @@
strcc \irqstat, [\base, #GIC_CPU_EOI]
cmpcs \irqnr, \irqnr
.endm
-
- /* As above, this assumes that irqstat and base are preserved.. */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- bic \irqnr, \irqstat, #0x1c00
- mov \tmp, #0
- cmp \irqnr, #29
- moveq \tmp, #1
- streq \irqstat, [\base, #GIC_CPU_EOI]
- cmp \tmp, #0
- .endm
diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c
index 14ac10b..09fea21 100644
--- a/arch/arm/mach-exynos4/mct.c
+++ b/arch/arm/mach-exynos4/mct.c
@@ -380,11 +380,13 @@
if (cpu == 0) {
mct_tick0_event_irq.dev_id = &mct_tick[cpu];
+ evt->irq = IRQ_MCT_L0;
setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
} else {
mct_tick1_event_irq.dev_id = &mct_tick[cpu];
- irq_set_affinity(IRQ_MCT1, cpumask_of(1));
+ evt->irq = IRQ_MCT_L1;
setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
+ irq_set_affinity(IRQ_MCT1, cpumask_of(1));
}
}
@@ -394,9 +396,10 @@
exynos4_mct_tick_init(evt);
}
-int local_timer_ack(void)
+void local_timer_stop(struct clock_event_device *evt)
{
- return 0;
+ evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+ disable_irq(evt->irq);
}
#endif /* CONFIG_LOCAL_TIMERS */
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a0cf8ca..2c4edb8 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -75,9 +75,9 @@
select ARCH_REQUIRE_GPIOLIB
select MSM_ADM3
select REGULATOR
+ select MSM_RPM_REGULATOR
select MSM_V2_TLMM
select MSM_PIL
- select MSM_SCM
select ARCH_HAS_CPU_IDLE_WAIT
select MSM_DIRECT_SCLK_ACCESS
select MSM_RPM
@@ -117,6 +117,8 @@
select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
select CPU_HAS_L2_PMU
select MSM_SPM_V1
+ select MSM_SCM if SMP
+ select MULTI_IRQ_HANDLER
config ARCH_MSM8960
bool "MSM8960"
@@ -128,6 +130,7 @@
select MSM_SCM if SMP
select MSM_DIRECT_SCLK_ACCESS
select REGULATOR
+ select MSM_RPM_REGULATOR
select MSM_RPM
select MSM_XO
select MSM_QDSP6_APR
@@ -153,6 +156,8 @@
select FIX_MOVABLE_ZONE
select CLEANCACHE
select QCACHE
+ select MSM_MULTIMEDIA_USE_ION
+ select MULTI_IRQ_HANDLER
config ARCH_MSM8930
bool "MSM8930"
@@ -187,6 +192,7 @@
select ARCH_MEMORY_REMOVE
select FIX_MOVABLE_ZONE
select MSM_ULTRASOUND
+ select MULTI_IRQ_HANDLER
config ARCH_APQ8064
bool "APQ8064"
@@ -201,6 +207,7 @@
select MSM_PIL
select MSM_QDSP6_APR
select MSM_AUDIO_QDSP6 if SND_SOC
+ select MULTI_IRQ_HANDLER
config ARCH_MSMCOPPER
bool "MSM Copper"
@@ -210,6 +217,7 @@
select CPU_V7
select MSM_SCM if SMP
select MSM_GPIOMUX
+ select MULTI_IRQ_HANDLER
config ARCH_FSM9XXX
bool "FSM9XXX"
@@ -218,6 +226,8 @@
select CPU_V7
select MSM_REMOTE_SPINLOCK_LDREX
select FSM9XXX_TLMM
+ select MULTI_IRQ_HANDLER
+ select MSM_DALRPC
config ARCH_MSM9615
bool "MSM9615"
@@ -229,6 +239,10 @@
select MSM_RPM
select MSM_SPM_V2
select MSM_NATIVE_RESTART
+ select REGULATOR
+ select MSM_RPM_REGULATOR
+ select MULTI_IRQ_HANDLER
+
endmenu
choice
@@ -279,8 +293,10 @@
bool
config ARCH_MSM_CORTEX_A5
- bool
+ select PERF_EVENTS
+ select HAVE_HW_BREAKPOINT
select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
+ bool
config ARCH_MSM7X27A
bool
@@ -1296,8 +1312,7 @@
config MSM_DALRPC
bool "DAL RPC support"
- depends on ARCH_MSM_SCORPION || ARCH_MSM_KRAIT
- default y
+ default n
help
Supports RPC calls to DAL devices on remote processor cores.
@@ -1571,6 +1586,14 @@
for idle power collapse, wait the number of microseconds in case
Modem becomes ready soon.
+config MSM_RPM_REGULATOR
+ bool "RPM regulator driver"
+ depends on MSM_RPM && REGULATOR
+ help
+ Compile in support for the RPM regulator driver, used for setting
+ voltages and other parameters of the various power rails supplied
+ by some Qualcomm PMICs.
+
config MSM_PIL
bool "Peripheral image loading"
select FW_LOADER
@@ -1582,6 +1605,12 @@
Say yes to support these devices.
+config MSM_PIL_MODEM
+ tristate "Modem (ARM11) Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down ARM11 Modem processors.
+
config MSM_PIL_QDSP6V3
tristate "QDSP6v3 (Hexagon) Boot Support"
depends on MSM_PIL
@@ -1597,6 +1626,24 @@
The QDSP6 is a low power DSP used in audio, modem firmware, and modem
software applications.
+config MSM_PIL_RIVA
+ tristate "RIVA (WCNSS) Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down the RIVA processor (WCNSS).
+ Riva is the wireless subsystem processor used in bluetooth, wireless
+ LAN, and FM software applications.
+
+config MSM_PIL_TZAPPS
+ tristate "TZApps Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down TZApps.
+
+ TZApps is an image that runs in the secure processor state. It is
+ used to decrypt data and perform secure operations on the behalf of
+ the kernel.
+
config MSM_SCM
bool "Secure Channel Manager (SCM) support"
default n
@@ -1833,7 +1880,8 @@
config MSM_SHOW_RESUME_IRQ
bool "Enable logging of interrupts that could have caused resume"
- depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSMCOPPER)
+ depends on (ARM_GIC || PMIC8058)
+ default y if PMIC8058
default n
help
This option logs wake up interrupts that have triggered just before
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index ee15313..95f2535 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -39,6 +39,7 @@
endif
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_MSM_CPU_AVS) += avs.o
obj-$(CONFIG_MSM_AVS_HW) += avs_hw.o
@@ -73,6 +74,9 @@
endif
obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
+obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
+obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
+obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o
obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
@@ -154,7 +158,7 @@
obj-$(CONFIG_ARCH_MSM7X01A) += pm.o
obj-y += pm-boot.o
else
- obj-y += no-pm.o hotplug.o
+ obj-y += no-pm.o
endif
obj-$(CONFIG_MSM_SPM_V1) += spm.o
@@ -174,9 +178,15 @@
obj-$(CONFIG_ARCH_MSM8X60) += devices-msm8x60.o clock-local.o clock-8x60.o acpuclock-8x60.o
obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
-obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator.o rpm-regulator-8660.o
obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
+ifdef CONFIG_MSM_RPM_REGULATOR
+obj-y += rpm-regulator.o
+obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator-8660.o
+obj-$(CONFIG_ARCH_MSM8960) += rpm-regulator-8960.o
+obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator-9615.o
+endif
+
ifdef CONFIG_MSM_SUBSYSTEM_RESTART
obj-y += subsystem_notif.o
obj-y += subsystem_restart.o
@@ -215,10 +225,10 @@
obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o devices-msm7x27.o
obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o
-obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o
-obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o
-obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o
obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o
obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
@@ -227,7 +237,7 @@
obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
-obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o rpm-regulator.o rpm-regulator-8960.o
+obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
@@ -238,15 +248,14 @@
obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_MTP) += board-8960-all.o board-8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_FLUID) += board-8960-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator.o
obj-$(CONFIG_ARCH_MSM8960) += bms-batterydata.o
obj-$(CONFIG_MACH_APQ8064_SIM) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_RUMI3) += board-8064-all.o board-8064-regulator.o
-obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o
+obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
-obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator.o rpm-regulator-9615.o
obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 0338d53..2fece29 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -2,7 +2,7 @@
* MSM architecture clock driver
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
* Author: San Mehat <san@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -33,7 +33,6 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
-#include "proc_comm.h"
#include "smd_private.h"
#include "acpuclock.h"
@@ -76,7 +75,6 @@
struct clkctl_acpu_speed *current_speed;
struct mutex lock;
uint32_t max_speed_delta_khz;
- unsigned long max_axi_khz;
struct clk *ebi1_clk;
};
@@ -127,62 +125,6 @@
* largest frequency jump that's less than max_speed_delta_khz on each PLL.
*/
-/* 7x01/7x25 normal with GSM capable modem */
-static struct clkctl_acpu_speed pll0_245_pll1_768_pll2_1056_pll4_0[] = {
- { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
- { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 },
- { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 61440 },
- { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440 },
- { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440 },
- { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 },
- { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000 },
- { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 },
- { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
-/* 7x01/7x25 normal with CDMA-only modem */
-static struct clkctl_acpu_speed pll0_196_pll1_768_pll2_1056_pll4_0[] = {
- { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
- { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 3, 24576 },
- { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 24576 },
- { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 24576 },
- { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 24576 },
- { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 },
- { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000 },
- { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 },
- { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
-/* 7x01/7x25 turbo with GSM capable modem */
-static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1056_pll4_0[] = {
- { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
- { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 61440 },
- { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 },
- { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440 },
- { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440 },
- { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 },
- { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 120000 },
- { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 },
- { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 122880 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
-/* 7x01/7x25 turbo with CDMA-only modem */
-static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1056_pll4_0[] = {
- { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
- { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 3, 24576 },
- { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 24576 },
- { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 24576 },
- { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 24576 },
- { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 },
- { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 120000 },
- { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 },
- { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 120000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
/* 7x27 normal with GSM capable modem */
static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1200_pll4_0[] = {
{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
@@ -190,10 +132,10 @@
{ 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 },
{ 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 61440 },
{ 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 4, 61440 },
- { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 122880 },
- { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 },
- { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 },
+ { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 160000 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+ { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -204,10 +146,10 @@
{ 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 49152 },
{ 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 98304 },
{ 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 98304 },
- { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 120000 },
- { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 },
- { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 120000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 },
+ { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 160000 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+ { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -218,10 +160,10 @@
{ 1, 122880, ACPU_PLL_1, 1, 1, 61440, 1, 3, 61440 },
{ 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4, 61440 },
- { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 122880 },
- { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 },
- { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -232,10 +174,10 @@
{ 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 3, 49152 },
{ 1, 196608, ACPU_PLL_1, 1, 0, 65536, 2, 4, 98304 },
{ 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 98304 },
- { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 120000 },
- { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 },
- { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 120000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -246,10 +188,10 @@
{ 1, 122880, ACPU_PLL_1, 1, 1, 61440, 1, 3, 61440 },
{ 0, 200000, ACPU_PLL_2, 2, 3, 66667, 2, 4, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4, 61440 },
- { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 122880 },
- { 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 122880 },
- { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 122880 },
- { 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 122880 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+ { 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+ { 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -260,10 +202,10 @@
{ 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 3, 49152 },
{ 1, 196608, ACPU_PLL_1, 1, 0, 65536, 2, 4, 98304 },
{ 0, 200000, ACPU_PLL_2, 2, 3, 66667, 2, 4, 98304 },
- { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 120000 },
- { 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 120000 },
- { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 120000 },
- { 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 120000 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+ { 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+ { 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -328,14 +270,14 @@
};
/* 7x25a pll2 at 1200mhz with GSM capable modem */
-static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_800_25a[] = {
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_25a[] = {
{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
{ 0, 61440, ACPU_PLL_1, 1, 3, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 1, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
- { 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
@@ -402,14 +344,14 @@
};
/* 7x25a pll2 at 1200mhz with GSM capable modem */
-static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_800_25a[] = {
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_25a[] = {
{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
{ 0, 61440, ACPU_PLL_1, 1, 11, 7680, 3, 1, 61440 },
{ 1, 122880, ACPU_PLL_1, 1, 5, 15360, 3, 2, 61440 },
{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
- { 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
@@ -418,14 +360,11 @@
#define PLL_0_MHZ 0
#define PLL_196_MHZ 10
#define PLL_245_MHZ 12
-#define PLL_491_MHZ 25
#define PLL_589_MHZ 30
#define PLL_737_MHZ 38
-#define PLL_768_MHZ 40
#define PLL_800_MHZ 41
#define PLL_960_MHZ 50
#define PLL_1008_MHZ 52
-#define PLL_1056_MHZ 55
#define PLL_1200_MHZ 62
#define PLL_CONFIG(m0, m1, m2, m4) { \
@@ -442,10 +381,6 @@
};
static struct pll_freq_tbl_map acpu_freq_tbl_list[] = {
- PLL_CONFIG(196, 768, 1056, 0),
- PLL_CONFIG(245, 768, 1056, 0),
- PLL_CONFIG(196, 960, 1056, 0),
- PLL_CONFIG(245, 960, 1056, 0),
PLL_CONFIG(196, 960, 1200, 0),
PLL_CONFIG(245, 960, 1200, 0),
PLL_CONFIG(960, 196, 1200, 0),
@@ -523,30 +458,22 @@
if (id >= ACPU_PLL_END)
return -EINVAL;
- if (pll_control) {
- remote_spin_lock(&pll_lock);
- if (on) {
- pll_control->pll[PLL_BASE + id].votes |= 2;
- if (!pll_control->pll[PLL_BASE + id].on) {
- pll_enable(soc_pll[id].mod_reg, 1);
- pll_control->pll[PLL_BASE + id].on = 1;
- }
- } else {
- pll_control->pll[PLL_BASE + id].votes &= ~2;
- if (pll_control->pll[PLL_BASE + id].on
- && !pll_control->pll[PLL_BASE + id].votes) {
- pll_enable(soc_pll[id].mod_reg, 0);
- pll_control->pll[PLL_BASE + id].on = 0;
- }
+ remote_spin_lock(&pll_lock);
+ if (on) {
+ pll_control->pll[PLL_BASE + id].votes |= 2;
+ if (!pll_control->pll[PLL_BASE + id].on) {
+ pll_enable(soc_pll[id].mod_reg, 1);
+ pll_control->pll[PLL_BASE + id].on = 1;
}
- remote_spin_unlock(&pll_lock);
} else {
- res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on);
- if (res < 0)
- return res;
- else if ((int) id < 0)
- return -EINVAL;
+ pll_control->pll[PLL_BASE + id].votes &= ~2;
+ if (pll_control->pll[PLL_BASE + id].on
+ && !pll_control->pll[PLL_BASE + id].votes) {
+ pll_enable(soc_pll[id].mod_reg, 0);
+ pll_control->pll[PLL_BASE + id].on = 0;
+ }
}
+ remote_spin_unlock(&pll_lock);
if (on)
pr_debug("PLL enabled\n");
@@ -556,21 +483,16 @@
return res;
}
-
-/*----------------------------------------------------------------------------
- * ARM11 'owned' clock control
- *---------------------------------------------------------------------------*/
-
static int acpuclk_set_vdd_level(int vdd)
{
uint32_t current_vdd;
/*
- * NOTE: v1.0 of 7x27a/7x25a chip doesn't have working
- * VDD switching support.
- */
+ * NOTE: v1.0 of 7x27a/7x25a chip doesn't have working
+ * VDD switching support.
+ */
if ((cpu_is_msm7x27a() || cpu_is_msm7x25a()) &&
- (SOCINFO_VERSION_MINOR(socinfo_get_version()) < 1))
+ (SOCINFO_VERSION_MINOR(socinfo_get_version()) < 1))
return 0;
current_vdd = readl_relaxed(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07;
@@ -635,7 +557,7 @@
}
}
-static int acpuclk_7201_set_rate(int cpu, unsigned long rate,
+static int acpuclk_7627_set_rate(int cpu, unsigned long rate,
enum setrate_reason reason)
{
uint32_t reg_clkctl;
@@ -712,9 +634,9 @@
while (cur_s != tgt_s) {
/*
- * Always jump to target freq if within 256mhz, regulardless of
- * PLL. If differnece is greater, use the predefinied
- * steppings in the table.
+ * Always jump to target freq if within max_speed_delta_khz,
+ * regardless of PLL. If differnece is greater, use the
+ * predefined steppings in the table.
*/
int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz));
if (d > drv_state.max_speed_delta_khz) {
@@ -834,11 +756,6 @@
div = readl_relaxed(A11S_CLK_CNTL_ADDR) & 0x0f;
}
- /* Accomodate bootloaders that might not be implementing the
- * workaround for the h/w bug in 7x25. */
- if (cpu_is_msm7x25() && sel == 2)
- sel = 3;
-
for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) {
if (speed->a11clk_src_sel == sel
&& (speed->a11clk_src_div == div))
@@ -872,7 +789,7 @@
pr_info("ACPU running at %d KHz\n", speed->a11clk_khz);
}
-static unsigned long acpuclk_7201_get_rate(int cpu)
+static unsigned long acpuclk_7627_get_rate(int cpu)
{
WARN_ONCE(drv_state.current_speed == NULL,
"%s: not initialized\n", __func__);
@@ -886,17 +803,10 @@
* Clock driver initialization
*---------------------------------------------------------------------------*/
-#define DIV2REG(n) ((n)-1)
-#define REG2DIV(n) ((n)+1)
-#define SLOWER_BY(div, factor) div = DIV2REG(REG2DIV(div) * factor)
-
static void __init acpu_freq_tbl_fixup(void)
{
unsigned long pll0_l, pll1_l, pll2_l, pll4_l;
- int axi_160mhz = 0, axi_200mhz = 0;
struct pll_freq_tbl_map *lst;
- struct clkctl_acpu_speed *t;
- unsigned int pll0_needs_fixup = 0;
/* Wait for the PLLs to be initialized and then read their frequency.
*/
@@ -934,23 +844,14 @@
pll4_l = 0;
}
- /* Some configurations run PLL0 twice as fast. Instead of having
- * separate tables for this case, we simply fix up the ACPU clock
- * source divider since it's a simple fix up.
- */
- if (pll0_l == PLL_491_MHZ) {
- pll0_l = PLL_245_MHZ;
- pll0_needs_fixup = 1;
- }
-
/* Fix the tables for 7x25a variant to not conflict with 7x27 ones */
if (cpu_is_msm7x25a()) {
if (pll1_l == PLL_245_MHZ) {
acpu_freq_tbl =
- pll0_960_pll1_245_pll2_1200_pll4_800_25a;
+ pll0_960_pll1_245_pll2_1200_25a;
} else if (pll1_l == PLL_737_MHZ) {
acpu_freq_tbl =
- pll0_960_pll1_737_pll2_1200_pll4_800_25a;
+ pll0_960_pll1_737_pll2_1200_25a;
}
} else {
/* Select the right table to use. */
@@ -969,38 +870,11 @@
BUG();
}
- /* Fix up PLL0 source divider if necessary. Also, fix up the AXI to
- * the max that's supported by the board (RAM used in board).
- */
- axi_160mhz = (pll0_l == PLL_960_MHZ || pll1_l == PLL_960_MHZ);
- axi_200mhz = (pll2_l == PLL_1200_MHZ || pll2_l == PLL_800_MHZ);
- for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) {
-
- if (pll0_needs_fixup && t->pll == ACPU_PLL_0)
- SLOWER_BY(t->a11clk_src_div, 2);
- if (axi_160mhz && drv_state.max_axi_khz >= 160000
- && t->ahbclk_khz > 128000)
- t->axiclk_khz = 160000;
- if (axi_200mhz && drv_state.max_axi_khz >= 200000
- && t->ahbclk_khz > 160000)
- t->axiclk_khz = 200000;
- }
-
- t--;
- drv_state.max_axi_khz = t->axiclk_khz;
-
/* The default 7x27 ACPU clock plan supports running the AXI bus at
* 200 MHz. So we don't classify it as Turbo mode.
*/
if (cpu_is_msm7x27())
return;
-
- if (!axi_160mhz)
- pr_info("Turbo mode not supported.\n");
- else if (t->axiclk_khz == 160000)
- pr_info("Turbo mode supported and enabled.\n");
- else
- pr_info("Turbo mode supported but not enabled.\n");
}
/*
@@ -1102,51 +976,42 @@
}
}
-static void msm7x25_acpu_pll_hw_bug_fix(void)
-{
- unsigned int n;
-
- /* The 7625 has a hardware bug and in order to select PLL2 we
- * must program PLL3. Use the same table, and just fix up the
- * numbers on this target. */
- for (n = 0; acpu_freq_tbl[n].a11clk_khz != 0; n++)
- if (acpu_freq_tbl[n].pll == ACPU_PLL_2)
- acpu_freq_tbl[n].a11clk_src_sel = 3;
-}
-
static void shared_pll_control_init(void)
{
#define PLL_REMOTE_SPINLOCK_ID "S:7"
unsigned smem_size;
+
remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
- if (!pll_control)
- pr_warning("Can't find shared PLL control data structure!\n");
+ if (!pll_control) {
+ pr_err("Can't find shared PLL control data structure!\n");
+ BUG();
/* There might be more PLLs than what the application processor knows
* about. But the index used for each PLL is guaranteed to remain the
* same. */
- else if (smem_size < sizeof(struct shared_pll_control))
- pr_warning("Shared PLL control data structure too small!\n");
- else if (pll_control->version != 0xCCEE0001)
- pr_warning("Shared PLL control version mismatch!\n");
- else {
+ } else if (smem_size < sizeof(struct shared_pll_control)) {
+ pr_err("Shared PLL control data"
+ "structure too small!\n");
+ BUG();
+ } else if (pll_control->version != 0xCCEE0001) {
+ pr_err("Shared PLL control version mismatch!\n");
+ BUG();
+ } else {
pr_info("Shared PLL control available.\n");
return;
}
- pll_control = NULL;
- pr_warning("Falling back to proc_comm PLL control.\n");
}
-static struct acpuclk_data acpuclk_7201_data = {
- .set_rate = acpuclk_7201_set_rate,
- .get_rate = acpuclk_7201_get_rate,
+static struct acpuclk_data acpuclk_7627_data = {
+ .set_rate = acpuclk_7627_set_rate,
+ .get_rate = acpuclk_7627_get_rate,
.power_collapse_khz = POWER_COLLAPSE_KHZ,
.switch_time_us = 50,
};
-static int __init acpuclk_7201_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_7627_init(struct acpuclk_soc_data *soc_data)
{
pr_info("%s()\n", __func__);
@@ -1156,16 +1021,13 @@
mutex_init(&drv_state.lock);
shared_pll_control_init();
drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
- drv_state.max_axi_khz = soc_data->max_axi_khz;
acpu_freq_tbl_fixup();
- acpuclk_7201_data.wait_for_irq_khz = find_wait_for_irq_khz();
+ acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
precompute_stepping();
- if (cpu_is_msm7x25())
- msm7x25_acpu_pll_hw_bug_fix();
acpuclk_hw_init();
lpj_init();
print_acpu_freq_tbl();
- acpuclk_register(&acpuclk_7201_data);
+ acpuclk_register(&acpuclk_7627_data);
#ifdef CONFIG_CPU_FREQ_MSM
cpufreq_table_init();
@@ -1174,26 +1036,17 @@
return 0;
}
-struct acpuclk_soc_data acpuclk_7201_soc_data __initdata = {
- .max_speed_delta_khz = 400000,
- .max_axi_khz = 160000,
- .init = acpuclk_7201_init,
-};
-
struct acpuclk_soc_data acpuclk_7x27_soc_data __initdata = {
.max_speed_delta_khz = 400000,
- .max_axi_khz = 200000,
- .init = acpuclk_7201_init,
+ .init = acpuclk_7627_init,
};
struct acpuclk_soc_data acpuclk_7x27a_soc_data __initdata = {
.max_speed_delta_khz = 400000,
- .max_axi_khz = 200000,
- .init = acpuclk_7201_init,
+ .init = acpuclk_7627_init,
};
struct acpuclk_soc_data acpuclk_7x27aa_soc_data __initdata = {
.max_speed_delta_khz = 504000,
- .max_axi_khz = 200000,
- .init = acpuclk_7201_init,
+ .init = acpuclk_7627_init,
};
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index c9ca339..4cf75b6 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -295,6 +295,57 @@
},
};
+/*TODO: Update the rpm vreg id when the rpm driver is ready */
+static struct scalable scalable_8627[] = {
+ [CPU0] = {
+ .hfpll_base = MSM_HFPLL_BASE + 0x200,
+ .aux_clk_sel = MSM_ACC0_BASE + 0x014,
+ .l2cpmr_iaddr = L2CPUCPMR_IADDR,
+ .vreg[VREG_CORE] = { "krait0", 1300000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8921_L24 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8921_S3 },
+ .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8921_S8 },
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8921_L23 },
+ },
+ [CPU1] = {
+ .hfpll_base = MSM_HFPLL_BASE + 0x300,
+ .aux_clk_sel = MSM_ACC1_BASE + 0x014,
+ .l2cpmr_iaddr = L2CPUCPMR_IADDR,
+ .vreg[VREG_CORE] = { "krait1", 1300000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8921_L24 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8921_S3 },
+ .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8921_S8 },
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8921_L23 },
+ },
+ [L2] = {
+ .hfpll_base = MSM_HFPLL_BASE + 0x400,
+ .aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
+ .l2cpmr_iaddr = L2CPMR_IADDR,
+ .vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+ RPM_VREG_VOTER6,
+ RPM_VREG_ID_PM8921_S8 },
+ .vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+ RPM_VREG_VOTER6,
+ RPM_VREG_ID_PM8921_L23 },
+ },
+};
+
static struct scalable *scalable;
static struct l2_level *l2_freq_tbl;
static struct acpu_level *acpu_freq_tbl;
@@ -422,17 +473,17 @@
{ 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
{ 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
{ 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1300000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1300000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1300000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1300000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1300000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1300000 },
- { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1300000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1300000 },
- { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1300000 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1300000 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1300000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1100000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1100000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1137500 },
+ { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1150000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1175000 },
+ { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1225000 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1250000 },
{ 0, { 0 } }
};
@@ -449,17 +500,17 @@
{ 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1012500 },
{ 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
{ 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1300000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1300000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1300000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1300000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1300000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1300000 },
- { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1300000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1300000 },
- { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1300000 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1300000 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1300000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1100000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1100000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1137500 },
+ { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1150000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1175000 },
+ { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1225000 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1250000 },
{ 0, { 0 } }
};
@@ -557,6 +608,43 @@
{ 0, { 0 } }
};
+/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
+#undef L2
+#define L2(x) (&l2_freq_tbl_8627[(x)])
+static struct l2_level l2_freq_tbl_8627[] = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
+ [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+ [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
+ [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
+ [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
+ [5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+ [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
+ [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 3 },
+ [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 3 },
+ [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
+ [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+ [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 4 },
+ [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 4 },
+};
+
+/* TODO: Update core voltages when data is available. */
+static struct acpu_level acpu_freq_tbl_8627[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 925000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 925000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 937500 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 962500 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(9), 987500 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(9), 1000000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(9), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(9), 1062500 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(12), 1062500 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(12), 1087500 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(12), 1100000 },
+ { 0, { 0 } }
+};
+
static unsigned long acpuclk_8960_get_rate(int cpu)
{
return scalable[cpu].current_speed->khz;
@@ -623,7 +711,7 @@
{
int rc;
- if (cpu_is_msm8960() || cpu_is_msm8930()) {
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8627()) {
rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 2100000,
sc->vreg[VREG_HFPLL_A].max_vdd, 0);
@@ -670,7 +758,7 @@
*/
writel_relaxed(0, sc->hfpll_base + HFPLL_MODE);
- if (cpu_is_msm8960() || cpu_is_msm8930()) {
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8627()) {
rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 0,
0, 0);
@@ -1192,7 +1280,7 @@
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
if (WARN_ON(!prev_khz[cpu]))
- prev_khz[cpu] = acpu_freq_tbl->speed.khz;
+ return NOTIFY_BAD;
acpuclk_8960_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
break;
case CPU_STARTING:
@@ -1266,6 +1354,11 @@
acpu_freq_tbl = acpu_freq_tbl_8064;
l2_freq_tbl = l2_freq_tbl_8064;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
+ } else if (cpu_is_msm8627()) {
+ scalable = scalable_8627;
+ acpu_freq_tbl = acpu_freq_tbl_8627;
+ l2_freq_tbl = l2_freq_tbl_8627;
+ l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8627);
} else if (cpu_is_msm8930()) {
scalable = scalable_8930;
acpu_freq_tbl = acpu_freq_tbl_8930;
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 6bc841b..7339a4c 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -845,7 +845,7 @@
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
if (WARN_ON(!prev_khz[cpu]))
- prev_khz[cpu] = acpu_freq_tbl->acpuclk_khz;
+ return NOTIFY_BAD;
acpuclk_8x60_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
break;
default:
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index b12258f..6ea691b 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -102,7 +102,6 @@
extern struct acpuclk_soc_data acpuclk_7x27_soc_data;
extern struct acpuclk_soc_data acpuclk_7x27a_soc_data;
extern struct acpuclk_soc_data acpuclk_7x27aa_soc_data;
-extern struct acpuclk_soc_data acpuclk_7201_soc_data;
extern struct acpuclk_soc_data acpuclk_7x30_soc_data;
extern struct acpuclk_soc_data acpuclk_8x50_soc_data;
extern struct acpuclk_soc_data acpuclk_8x60_soc_data;
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 644a666..e52884f 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -416,17 +416,31 @@
struct sk_buff *skb;
struct bam_mux_hdr *hdr;
struct tx_pkt_info *info;
+ struct tx_pkt_info *info_expected;
unsigned long event_data;
- struct list_head *node;
unsigned long flags;
if (in_global_reset)
return;
- spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
- node = bam_tx_pool.next;
- list_del(node);
- spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
info = container_of(work, struct tx_pkt_info, work);
+
+ spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+ info_expected = list_first_entry(&bam_tx_pool,
+ struct tx_pkt_info, list_node);
+ if (unlikely(info != info_expected)) {
+ struct list_head *node;
+
+ pr_err("%s: bam_tx_pool mismatch .next=%p, list_node=%p\n",
+ __func__, bam_tx_pool.next, &info->list_node);
+ list_for_each(node, &bam_tx_pool)
+ pr_err("%s: node=%p\n", __func__, node);
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+ BUG();
+ }
+ list_del(&info->list_node);
+ spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
if (info->is_cmd) {
kfree(info->skb);
kfree(info);
@@ -733,78 +747,105 @@
return ret;
}
+static void rx_switch_to_interrupt_mode(void)
+{
+ struct sps_connect cur_rx_conn;
+ struct sps_iovec iov;
+ struct rx_pkt_info *info;
+ int ret;
+
+ /*
+ * Attempt to enable interrupts - if this fails,
+ * continue polling and we will retry later.
+ */
+ ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+ if (ret) {
+ pr_err("%s: sps_get_config() failed %d\n", __func__, ret);
+ goto fail;
+ }
+
+ rx_register_event.options = SPS_O_EOT;
+ ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+ if (ret) {
+ pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
+ goto fail;
+ }
+
+ cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+ SPS_O_EOT | SPS_O_ACK_TRANSFERS;
+ ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+ if (ret) {
+ pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
+ goto fail;
+ }
+ polling_mode = 0;
+
+ /* handle any rx packets before interrupt was enabled */
+ while (bam_connection_is_active && !polling_mode) {
+ ret = sps_get_iovec(bam_rx_pipe, &iov);
+ if (ret) {
+ pr_err("%s: sps_get_iovec failed %d\n",
+ __func__, ret);
+ break;
+ }
+ if (iov.addr == 0)
+ break;
+
+ mutex_lock(&bam_rx_pool_mutexlock);
+ if (unlikely(list_empty(&bam_rx_pool))) {
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ continue;
+ }
+ info = list_first_entry(&bam_rx_pool, struct rx_pkt_info,
+ list_node);
+ list_del(&info->list_node);
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ handle_bam_mux_cmd(&info->work);
+ }
+ return;
+
+fail:
+ pr_err("%s: reverting to polling\n", __func__);
+ queue_work(bam_mux_rx_workqueue, &rx_timer_work);
+}
+
static void rx_timer_work_func(struct work_struct *work)
{
struct sps_iovec iov;
- struct list_head *node;
struct rx_pkt_info *info;
int inactive_cycles = 0;
int ret;
- struct sps_connect cur_rx_conn;
- while (1) { /* timer loop */
+ while (bam_connection_is_active) { /* timer loop */
++inactive_cycles;
- while (1) { /* deplete queue loop */
+ while (bam_connection_is_active) { /* deplete queue loop */
if (in_global_reset)
return;
- sps_get_iovec(bam_rx_pipe, &iov);
+
+ ret = sps_get_iovec(bam_rx_pipe, &iov);
+ if (ret) {
+ pr_err("%s: sps_get_iovec failed %d\n",
+ __func__, ret);
+ break;
+ }
if (iov.addr == 0)
break;
inactive_cycles = 0;
mutex_lock(&bam_rx_pool_mutexlock);
- node = bam_rx_pool.next;
- list_del(node);
+ if (unlikely(list_empty(&bam_rx_pool))) {
+ mutex_unlock(&bam_rx_pool_mutexlock);
+ continue;
+ }
+ info = list_first_entry(&bam_rx_pool,
+ struct rx_pkt_info, list_node);
+ list_del(&info->list_node);
mutex_unlock(&bam_rx_pool_mutexlock);
- info = container_of(node, struct rx_pkt_info,
- list_node);
handle_bam_mux_cmd(&info->work);
}
if (inactive_cycles == POLLING_INACTIVITY) {
- /*
- * attempt to enable interrupts in this pipe
- * if enabling interrupts fails, continue polling
- */
- ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
- if (ret) {
- pr_err("%s: sps_get_config() failed, interrupts"
- " not enabled\n", __func__);
- queue_work(bam_mux_rx_workqueue,
- &rx_timer_work);
- return;
- } else {
- rx_register_event.options = SPS_O_EOT;
- /* should check return value */
- sps_register_event(bam_rx_pipe,
- &rx_register_event);
- cur_rx_conn.options = SPS_O_AUTO_ENABLE |
- SPS_O_EOT | SPS_O_ACK_TRANSFERS;
- ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
- if (ret) {
- pr_err("%s: sps_set_config() failed, "
- "interrupts not enabled\n",
- __func__);
- queue_work(bam_mux_rx_workqueue,
- &rx_timer_work);
- return;
- }
- polling_mode = 0;
- }
- if (in_global_reset)
- return;
- /* handle race condition - missed packet? */
- sps_get_iovec(bam_rx_pipe, &iov);
- if (iov.addr == 0)
- return;
- inactive_cycles = 0;
- mutex_lock(&bam_rx_pool_mutexlock);
- node = bam_rx_pool.next;
- list_del(node);
- mutex_unlock(&bam_rx_pool_mutexlock);
- info = container_of(node, struct rx_pkt_info,
- list_node);
- handle_bam_mux_cmd(&info->work);
- return;
+ rx_switch_to_interrupt_mode();
+ break;
}
usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
@@ -855,16 +896,16 @@
if (!polling_mode) {
ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
if (ret) {
- pr_err("%s: sps_get_config() failed, interrupts"
- " not disabled\n", __func__);
+ pr_err("%s: sps_get_config() failed %d, interrupts"
+ " not disabled\n", __func__, ret);
break;
}
cur_rx_conn.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
if (ret) {
- pr_err("%s: sps_set_config() failed, interrupts"
- " not disabled\n", __func__);
+ pr_err("%s: sps_set_config() failed %d, interrupts"
+ " not disabled\n", __func__, ret);
break;
}
polling_mode = 1;
@@ -999,10 +1040,12 @@
return;
}
if (ul_packet_written) {
+ pr_info("%s: packet written\n", __func__);
ul_packet_written = 0;
schedule_delayed_work(&ul_timeout_work,
msecs_to_jiffies(UL_TIMEOUT_DELAY));
} else {
+ pr_info("%s: powerdown\n", __func__);
wait_for_ack = 1;
INIT_COMPLETION(ul_wakeup_ack_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
@@ -1020,6 +1063,7 @@
mutex_unlock(&wakeup_lock);
return;
}
+ pr_info("%s\n", __func__);
/*
* must wait for the previous power down request to have been acked
* chances are it already came in and this will just fall through
@@ -1066,10 +1110,16 @@
i = sps_register_event(bam_rx_pipe, &rx_register_event);
if (i)
pr_err("%s: rx event reg failed rc = %d\n", __func__, i);
+
+ bam_connection_is_active = 1;
+
+ if (polling_mode)
+ rx_switch_to_interrupt_mode();
+
for (i = 0; i < NUM_BUFFERS; ++i)
queue_rx();
+
toggle_apps_ack();
- bam_connection_is_active = 1;
complete_all(&bam_connection_completion);
}
@@ -1085,6 +1135,8 @@
unvote_dfab();
__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
+
+ mutex_lock(&bam_rx_pool_mutexlock);
while (!list_empty(&bam_rx_pool)) {
node = bam_rx_pool.next;
list_del(node);
@@ -1094,6 +1146,7 @@
dev_kfree_skb_any(info->skb);
kfree(info);
}
+ mutex_unlock(&bam_rx_pool_mutexlock);
}
static void vote_dfab(void)
@@ -1325,6 +1378,7 @@
static void toggle_apps_ack(void)
{
static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
+ pr_info("%s: clear bit: %d\n", __func__, clear_bit);
smsm_change_state(SMSM_APPS_STATE,
clear_bit & SMSM_A2_POWER_CONTROL_ACK,
~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
@@ -1333,15 +1387,19 @@
static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
{
- DBG("%s: smsm activity\n", __func__);
+ pr_info("%s: smsm activity 0x%08x -> 0x%08x\n", __func__, old_state,
+ new_state);
if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
+ pr_info("%s: reconnect\n", __func__);
wake_lock(&bam_wakelock);
reconnect_to_bam();
} else if (bam_mux_initialized &&
!(new_state & SMSM_A2_POWER_CONTROL)) {
+ pr_info("%s: disconnect\n", __func__);
disconnect_to_bam();
wake_unlock(&bam_wakelock);
} else if (new_state & SMSM_A2_POWER_CONTROL) {
+ pr_info("%s: init\n", __func__);
wake_lock(&bam_wakelock);
bam_init();
} else {
@@ -1353,6 +1411,7 @@
static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
uint32_t new_state)
{
+ pr_info("%s: 0x%08x -> 0x%08x\n", __func__, old_state, new_state);
complete_all(&ul_wakeup_ack_completion);
}
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 4873258..47b20e4 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-#include <linux/regulator/pm8921-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
#include "board-8064.h"
@@ -171,9 +171,9 @@
REGULATOR_SUPPLY("8821_s1", NULL),
};
-#define PM8921_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
- _pull_down, _always_on, _supply_regulator, \
- _system_uA, _enable_time) \
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+ _apply_uV, _pull_down, _always_on, _supply_regulator, \
+ _system_uA, _enable_time, _reg_id) \
{ \
.init_data = { \
.constraints = { \
@@ -184,81 +184,86 @@
.input_uV = _max_uV, \
.apply_uV = _apply_uV, \
.always_on = _always_on, \
+ .name = _name, \
}, \
.num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id), \
.consumer_supplies = vreg_consumers_##_id, \
.supply_regulator = _supply_regulator, \
}, \
- .id = PM8921_VREG_ID_##_id, \
+ .id = _reg_id, \
.pull_down_enable = _pull_down, \
.system_uA = _system_uA, \
.enable_time = _enable_time, \
}
-#define PM8921_VREG_INIT_LDO(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_NLDO1200(_id, _always_on, _pull_down, _min_uV, \
- _max_uV, _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+ _max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_SMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_FTSMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_VS(_id, _always_on, _pull_down, _enable_time, \
- _supply_regulator) \
- PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
- _always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+ _pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+ _reg_id)
-#define PM8921_VREG_INIT_VS300(_id, _always_on, _pull_down, _enable_time, \
- _supply_regulator) \
- PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
- _always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+ _pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+ _reg_id)
-#define PM8921_VREG_INIT_NCP(_id, _always_on, _min_uV, _max_uV, _enable_time, \
- _supply_regulator) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE | \
- REGULATOR_CHANGE_STATUS, 0, 0, _always_on, _supply_regulator, \
- 0, _enable_time)
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+ _always_on, _supply_regulator, 0, _enable_time, _reg_id)
/* Pin control initialization */
-#define PM8921_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+ _supply_regulator, _reg_id) \
{ \
.init_data = { \
.constraints = { \
.valid_ops_mask = REGULATOR_CHANGE_STATUS, \
.always_on = _always_on, \
+ .name = _name, \
}, \
.num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id##_PC), \
.consumer_supplies = vreg_consumers_##_id##_PC, \
.supply_regulator = _supply_regulator, \
}, \
- .id = PM8921_VREG_ID_##_id##_PC, \
- .pin_fn = PM8921_VREG_PIN_FN_##_pin_fn, \
- .pin_ctrl = _pin_ctrl, \
+ .id = _reg_id, \
+ .pin_fn = PM8XXX_VREG_PIN_FN_##_pin_fn, \
+ .pin_ctrl = _pin_ctrl, \
}
#define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
@@ -287,59 +292,70 @@
SAW_VREG_INIT(8821_S1, "8821_s1", 950000, 1150000);
/* PM8921 regulator constraints */
-struct pm8921_regulator_platform_data
+struct pm8xxx_regulator_platform_data
msm8064_pm8921_regulator_pdata[] __devinitdata = {
- /* ID a_on pd min_uV max_uV en_t supply sys_uA */
- PM8921_VREG_INIT_SMPS(S1, 1, 1, 1225000, 1225000, 500, NULL, 100000),
- PM8921_VREG_INIT_SMPS(S2, 0, 1, 1300000, 1300000, 500, NULL, 0),
- PM8921_VREG_INIT_SMPS(S3, 1, 1, 1150000, 1150000, 500, NULL, 100000),
- PM8921_VREG_INIT_SMPS(S4, 1, 1, 1800000, 1800000, 500, NULL, 100000),
- PM8921_VREG_INIT_SMPS(S7, 0, 1, 1200000, 1200000, 500, NULL, 100000),
+ /*
+ * ID name always_on pd min_uV max_uV en_t supply
+ * system_uA reg_ID
+ */
+ PM8XXX_SMPS(S1, "8921_s1", 1, 1, 1225000, 1225000, 500, NULL, 100000,
+ 1),
+ PM8XXX_SMPS(S2, "8921_s2", 0, 1, 1300000, 1300000, 500, NULL, 0, 2),
+ PM8XXX_SMPS(S3, "8921_s3", 1, 1, 1150000, 1150000, 500, NULL, 100000,
+ 3),
+ PM8XXX_SMPS(S4, "8921_s4", 1, 1, 1800000, 1800000, 500, NULL, 100000,
+ 4),
+ PM8XXX_SMPS(S7, "8921_s7", 0, 1, 1200000, 1200000, 500, NULL, 100000,
+ 5),
- PM8921_VREG_INIT_LDO(L1, 1, 1, 1100000, 1100000, 200, "8921_s4", 0),
- PM8921_VREG_INIT_LDO(L2, 0, 1, 1200000, 1200000, 200, "8921_s4", 0),
- PM8921_VREG_INIT_LDO(L3, 0, 1, 3075000, 3075000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L4, 1, 1, 1800000, 1800000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L5, 0, 1, 2950000, 2950000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L6, 0, 1, 2950000, 2950000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L7, 1, 1, 1850000, 2950000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L8, 0, 1, 2800000, 2800000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L9, 0, 1, 2850000, 2850000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L10, 0, 1, 2900000, 2900000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L11, 0, 1, 3000000, 3000000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L12, 0, 1, 1200000, 1200000, 200, "8921_s4", 0),
- PM8921_VREG_INIT_LDO(L14, 0, 1, 1800000, 1800000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L15, 0, 1, 1800000, 2950000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L16, 0, 1, 2800000, 2800000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L17, 0, 1, 2000000, 2000000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L18, 0, 1, 1300000, 1800000, 200, "8921_s4", 0),
- PM8921_VREG_INIT_LDO(L22, 0, 1, 2600000, 2600000, 200, NULL, 0),
- PM8921_VREG_INIT_LDO(L23, 0, 1, 1800000, 1800000, 200, NULL, 0),
- PM8921_VREG_INIT_NLDO1200(L24, 1, 1, 1150000, 1150000, 200, "8921_s1",
- 10000),
- PM8921_VREG_INIT_NLDO1200(L25, 1, 1, 1225000, 1225000, 200, "8921_s1",
- 0),
- PM8921_VREG_INIT_NLDO1200(L26, 0, 1, 1050000, 1050000, 200, "8921_s7",
- 0),
- PM8921_VREG_INIT_NLDO1200(L27, 0, 1, 1000000, 1000000, 200, "8921_s7",
- 0),
- PM8921_VREG_INIT_NLDO1200(L28, 0, 1, 1050000, 1050000, 200, "8921_s7",
- 0),
+ PM8XXX_LDO(L1, "8921_l1", 1, 1, 1100000, 1100000, 200, "8921_s4", 0,
+ 6),
+ PM8XXX_LDO(L2, "8921_l2", 0, 1, 1200000, 1200000, 200, "8921_s4", 0,
+ 7),
+ PM8XXX_LDO(L3, "8921_l3", 0, 1, 3075000, 3075000, 200, NULL, 0, 8),
+ PM8XXX_LDO(L4, "8921_l4", 1, 1, 1800000, 1800000, 200, NULL, 0, 9),
+ PM8XXX_LDO(L5, "8921_l5", 0, 1, 2950000, 2950000, 200, NULL, 0, 10),
+ PM8XXX_LDO(L6, "8921_l6", 0, 1, 2950000, 2950000, 200, NULL, 0, 11),
+ PM8XXX_LDO(L7, "8921_l7", 1, 1, 1850000, 2950000, 200, NULL, 0, 12),
+ PM8XXX_LDO(L8, "8921_l8", 0, 1, 2800000, 2800000, 200, NULL, 0, 13),
+ PM8XXX_LDO(L9, "8921_l9", 0, 1, 2850000, 2850000, 200, NULL, 0, 14),
+ PM8XXX_LDO(L10, "8921_l10", 0, 1, 2900000, 2900000, 200, NULL, 0, 15),
+ PM8XXX_LDO(L11, "8921_l11", 0, 1, 3000000, 3000000, 200, NULL, 0, 16),
+ PM8XXX_LDO(L12, "8921_l12", 0, 1, 1200000, 1200000, 200, "8921_s4", 0,
+ 17),
+ PM8XXX_LDO(L14, "8921_l14", 0, 1, 1800000, 1800000, 200, NULL, 0, 18),
+ PM8XXX_LDO(L15, "8921_l15", 0, 1, 1800000, 2950000, 200, NULL, 0, 19),
+ PM8XXX_LDO(L16, "8921_l16", 0, 1, 2800000, 2800000, 200, NULL, 0, 20),
+ PM8XXX_LDO(L17, "8921_l17", 0, 1, 2000000, 2000000, 200, NULL, 0, 21),
+ PM8XXX_LDO(L18, "8921_l18", 0, 1, 1300000, 1800000, 200, "8921_s4", 0,
+ 22),
+ PM8XXX_LDO(L22, "8921_l22", 0, 1, 2600000, 2600000, 200, NULL, 0, 23),
+ PM8XXX_LDO(L23, "8921_l23", 0, 1, 1800000, 1800000, 200, NULL, 0, 24),
+ PM8XXX_NLDO1200(L24, "8921_l24", 1, 1, 1150000, 1150000, 200, "8921_s1",
+ 10000, 25),
+ PM8XXX_NLDO1200(L25, "8921_l25", 1, 1, 1225000, 1225000, 200, "8921_s1",
+ 0, 26),
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ 0, 27),
+ PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1000000, 1000000, 200, "8921_s7",
+ 0, 28),
+ PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ 0, 29),
- /* ID always_on pd en_t supply */
- PM8921_VREG_INIT_VS(LVS1, 0, 1, 0, "8921_s4"),
- PM8921_VREG_INIT_VS300(LVS2, 0, 1, 0, "8921_s1"),
- PM8921_VREG_INIT_VS(LVS3, 0, 1, 0, "8921_s4"),
- PM8921_VREG_INIT_VS(LVS4, 0, 1, 0, "8921_s4"),
- PM8921_VREG_INIT_VS(LVS5, 0, 1, 0, "8921_s4"),
- PM8921_VREG_INIT_VS(LVS6, 0, 1, 0, "8921_s4"),
- PM8921_VREG_INIT_VS(LVS7, 1, 1, 0, "8921_s4"),
+ /* ID name always_on pd en_t supply reg_ID */
+ PM8XXX_VS(LVS1, "8921_lvs1", 0, 1, 0, "8921_s4", 30),
+ PM8XXX_VS300(LVS2, "8921_lvs2", 0, 1, 0, "8921_s1", 31),
+ PM8XXX_VS(LVS3, "8921_lvs3", 0, 1, 0, "8921_s4", 32),
+ PM8XXX_VS(LVS4, "8921_lvs4", 0, 1, 0, "8921_s4", 33),
+ PM8XXX_VS(LVS5, "8921_lvs5", 0, 1, 0, "8921_s4", 34),
+ PM8XXX_VS(LVS6, "8921_lvs6", 0, 1, 0, "8921_s4", 35),
+ PM8XXX_VS(LVS7, "8921_lvs7", 1, 1, 0, "8921_s4", 36),
- PM8921_VREG_INIT_VS300(USB_OTG, 0, 1, 0, NULL),
- PM8921_VREG_INIT_VS300(HDMI_MVS, 0, 1, 0, NULL),
+ PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 1, 0, NULL, 37),
+ PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0, NULL, 38),
- /* ID always_on min_uV max_uV en_t supply */
- PM8921_VREG_INIT_NCP(NCP, 0, 1800000, 1800000, 200, "8921_l6"),
+ /* ID name always_on min_uV max_uV en_t supply reg_ID */
+ PM8XXX_NCP(NCP, "8921_ncp", 0, 1800000, 1800000, 200, "8921_l6", 39),
};
int msm8064_pm8921_regulator_pdata_len __devinitdata =
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index b13a48c..d6532d5 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -333,6 +333,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
static struct platform_device qcrypto_device = {
@@ -355,6 +356,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
static struct platform_device qcedev_device = {
@@ -381,7 +383,6 @@
static void __init apq8064_init_irq(void)
{
- unsigned int i;
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
(void *)MSM_QGIC_CPU_BASE);
@@ -390,16 +391,6 @@
writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
mb();
-
- /*
- * FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
}
static struct platform_device msm8064_device_saw_regulator_core0 = {
@@ -498,10 +489,6 @@
static struct platform_device *rumi3_devices[] __initdata = {
&apq8064_device_uart_gsbi1,
&msm_device_sps_apq8064,
- &msm_cpudai_bt_rx,
- &msm_cpudai_bt_tx,
- &msm_cpudai_fm_rx,
- &msm_cpudai_fm_tx,
};
static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
@@ -609,6 +596,7 @@
.map_io = apq8064_map_io,
.reserve = apq8064_reserve,
.init_irq = apq8064_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = apq8064_sim_init,
MACHINE_END
@@ -617,6 +605,7 @@
.map_io = apq8064_map_io,
.reserve = apq8064_reserve,
.init_irq = apq8064_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = apq8064_rumi3_init,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 4a48897..98f453b 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -27,7 +27,7 @@
#define PM8821_MPP_PM_TO_SYS(pm_mpp) (pm_mpp - 1 + PM8821_MPP_BASE)
#define PM8821_IRQ_BASE (PM8921_IRQ_BASE + PM8921_NR_IRQS)
-extern struct pm8921_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
msm8064_pm8921_regulator_pdata[] __devinitdata;
extern int msm8064_pm8921_regulator_pdata_len __devinitdata;
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 9161fbf..6b5f917 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -11,8 +11,6 @@
*
*/
-#include <linux/i2c.h>
-#include <linux/i2c/sx150x.h>
#include <asm/mach-types.h>
#include <mach/board.h>
#include <mach/msm_bus_board.h>
@@ -402,14 +400,29 @@
.actuator_info = &imx074_actuator_info
#endif
};
+#endif
-static struct platform_device msm8960_camera_sensor_imx074 = {
- .name = "msm_camera_imx074",
- .dev = {
- .platform_data = &msm_camera_sensor_imx074_data,
- },
+#ifdef CONFIG_MT9M114
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+ .mount_angle = 90,
+ .sensor_reset = 107,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+ .sensor_name = "mt9m114",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_mt9m114,
+ .sensor_platform_info = &sensor_board_info_mt9m114,
+ .gpio_conf = &gpio_conf,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
};
#endif
+
#ifdef CONFIG_OV2720
static struct msm_camera_sensor_flash_data flash_ov2720 = {
.flash_type = MSM_CAMERA_FLASH_NONE,
@@ -432,33 +445,13 @@
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
};
-
-static struct platform_device msm8960_camera_sensor_ov2720 = {
- .name = "msm_camera_ov2720",
- .dev = {
- .platform_data = &msm_camera_sensor_ov2720_data,
- },
-};
#endif
void __init msm8930_init_cam(void)
{
- int i;
- struct platform_device *cam_dev[] = {
- &msm8960_camera_sensor_imx074,
- &msm8960_camera_sensor_ov2720,
- };
-
msm_gpiomux_install(msm8960_cam_common_configs,
ARRAY_SIZE(msm8960_cam_common_configs));
- for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
- struct msm_camera_sensor_info *s_info;
- s_info = cam_dev[i]->dev.platform_data;
- msm_get_cam_resources(s_info);
- platform_device_register(cam_dev[i]);
- }
-
platform_device_register(&msm8960_device_csiphy0);
platform_device_register(&msm8960_device_csiphy1);
platform_device_register(&msm8960_device_csid0);
@@ -467,4 +460,35 @@
platform_device_register(&msm8960_device_vfe);
platform_device_register(&msm8960_device_vpe);
}
+
+#ifdef CONFIG_I2C
+struct i2c_board_info msm8930_camera_i2c_boardinfo[] = {
+#ifdef CONFIG_IMX074
+ {
+ I2C_BOARD_INFO("imx074", 0x1A),
+ .platform_data = &msm_camera_sensor_imx074_data,
+ },
+#endif
+#ifdef CONFIG_OV2720
+ {
+ I2C_BOARD_INFO("ov2720", 0x6C),
+ .platform_data = &msm_camera_sensor_ov2720_data,
+ },
+#endif
+ {
+ I2C_BOARD_INFO("mt9m114", 0x48),
+ .platform_data = &msm_camera_sensor_mt9m114_data,
+ },
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+ {
+ I2C_BOARD_INFO("sc628a", 0x6E),
+ },
+#endif
+};
+
+struct msm_camera_board_info msm8930_camera_board_info = {
+ .board_info = msm8930_camera_i2c_boardinfo,
+ .num_i2c_board_info = ARRAY_SIZE(msm8930_camera_i2c_boardinfo),
+};
+#endif
#endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 2fb6153..c1b880c 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -17,6 +17,7 @@
#include <linux/bootmem.h>
#include <asm/mach-types.h>
#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
@@ -46,25 +47,26 @@
#define MSM_FB_EXT_BUF_SIZE 0
#endif
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
-/* width x height x 3 bpp x 2 frame buffer */
-#define MSM_FB_WRITEBACK_SIZE (1376 * 768 * 3 * 2)
-#define MSM_FB_WRITEBACK_OFFSET \
- (MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
-#else
-#define MSM_FB_WRITEBACK_SIZE 0
-#define MSM_FB_WRITEBACK_OFFSET 0
-#endif
-
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
/* 4 bpp x 2 page HDMI case */
#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
#else
/* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
- MSM_FB_WRITEBACK_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
#endif
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
+#endif /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
+
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
+
#define MDP_VSYNC_GPIO 0
#define PANEL_NAME_MAX_LEN 30
@@ -77,11 +79,6 @@
#define HDMI_PANEL_NAME "hdmi_msm"
#define TVOUT_PANEL_NAME "tvout_msm"
-static int writeback_offset(void)
-{
- return MSM_FB_WRITEBACK_OFFSET;
-}
-
static struct resource msm_fb_resources[] = {
{
.flags = IORESOURCE_DMA,
@@ -438,9 +435,21 @@
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
.mdp_rev = MDP_REV_42,
- .writeback_offset = writeback_offset,
+ .mdp_writeback_memtype = MEMTYPE_EBI1,
+ .mdp_writeback_phys = NULL,
};
+void __init msm8930_mdp_writeback(struct memtype_reserve* reserve_table)
+{
+ mdp_pdata.mdp_writeback_size_ov0 = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+ mdp_pdata.mdp_writeback_size_ov1 = MSM_FB_OVERLAY1_WRITEBACK_SIZE;
+
+ reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+ mdp_pdata.mdp_writeback_size_ov0;
+ reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+ mdp_pdata.mdp_writeback_size_ov1;
+}
+
#define LPM_CHANNEL0 0
static int toshiba_gpio[] = {LPM_CHANNEL0};
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index e872d64..476ab93 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -120,42 +120,70 @@
.pull = GPIOMUX_PULL_DOWN,
};
-static struct gpiomux_setting cyts_resout_sus_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting cyts_resout_act_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting cyts_sleep_sus_cfg = {
+static struct gpiomux_setting atmel_resout_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_DOWN,
};
-static struct gpiomux_setting cyts_sleep_act_cfg = {
+static struct gpiomux_setting atmel_resout_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_ldo_en_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_DOWN,
};
-static struct gpiomux_setting cyts_int_act_cfg = {
+static struct gpiomux_setting atmel_ldo_en_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_int_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
.pull = GPIOMUX_PULL_UP,
};
-static struct gpiomux_setting cyts_int_sus_cfg = {
+static struct gpiomux_setting atmel_int_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
};
+#ifdef MSM8930_PHASE_2
+static struct gpiomux_setting hsusb_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+static struct gpiomux_setting hsusb_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+static struct msm_gpiomux_config msm8930_hsusb_configs[] = {
+ {
+ .gpio = 63, /* HSUSB_EXTERNAL_5V_LDO_EN */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsusb_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
+ },
+ },
+ {
+ .gpio = 97, /* HSUSB_5V_EN */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsusb_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
+ },
+ },
+};
+#endif
#ifdef CONFIG_USB_EHCI_MSM_HSIC
static struct gpiomux_setting hsic_act_cfg = {
.func = GPIOMUX_FUNC_1,
@@ -455,26 +483,26 @@
},
};
-static struct msm_gpiomux_config msm8960_cyts_configs[] __initdata = {
+static struct msm_gpiomux_config msm8960_atmel_configs[] __initdata = {
{ /* TS INTERRUPT */
.gpio = 11,
.settings = {
- [GPIOMUX_ACTIVE] = &cyts_int_act_cfg,
- [GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+ [GPIOMUX_ACTIVE] = &atmel_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
},
},
- { /* TS SLEEP */
+ { /* TS LDO ENABLE */
.gpio = 50,
.settings = {
- [GPIOMUX_ACTIVE] = &cyts_sleep_act_cfg,
- [GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+ [GPIOMUX_ACTIVE] = &atmel_ldo_en_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_ldo_en_sus_cfg,
},
},
{ /* TS RESOUT */
.gpio = 52,
.settings = {
- [GPIOMUX_ACTIVE] = &cyts_resout_act_cfg,
- [GPIOMUX_SUSPENDED] = &cyts_resout_sus_cfg,
+ [GPIOMUX_ACTIVE] = &atmel_resout_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_resout_sus_cfg,
},
},
};
@@ -619,8 +647,8 @@
msm_gpiomux_install(msm8960_gsbi_configs,
ARRAY_SIZE(msm8960_gsbi_configs));
- msm_gpiomux_install(msm8960_cyts_configs,
- ARRAY_SIZE(msm8960_cyts_configs));
+ msm_gpiomux_install(msm8960_atmel_configs,
+ ARRAY_SIZE(msm8960_atmel_configs));
msm_gpiomux_install(msm8960_slimbus_config,
ARRAY_SIZE(msm8960_slimbus_config));
@@ -635,9 +663,14 @@
ARRAY_SIZE(wcnss_5wire_interface));
if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid() ||
- machine_is_msm8930_cdp())
+ machine_is_msm8930_cdp()) {
msm_gpiomux_install(hap_lvl_shft_config,
ARRAY_SIZE(hap_lvl_shft_config));
+#ifdef MSM8930_PHASE_2
+ msm_gpiomux_install(msm8930_hsusb_configs,
+ ARRAY_SIZE(msm8930_hsusb_configs));
+#endif
+ }
if (PLATFORM_IS_CHARM25())
msm_gpiomux_install(mdm_configs,
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 283493d..fcff6ed 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -155,6 +155,7 @@
.rtc_pdata = &pm8xxx_rtc_pdata,
.pwrkey_pdata = &pm8xxx_pwrkey_pdata,
.misc_pdata = &pm8xxx_misc_pdata,
+ .regulator_pdatas = msm8930_pm8038_regulator_pdata,
};
static struct msm_ssbi_platform_data msm8930_ssbi_pm8038_pdata __devinitdata = {
@@ -170,4 +171,6 @@
pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
msm8960_device_ssbi_pmic.dev.platform_data =
&msm8930_ssbi_pm8038_pdata;
+ pm8038_platform_data.num_regulators
+ = msm8930_pm8038_regulator_pdata_len;
}
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
new file mode 100644
index 0000000..ff4c808
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/regulator/pm8xxx-regulator.h>
+
+#include "board-8930.h"
+
+#define VREG_CONSUMERS(_id) \
+ static struct regulator_consumer_supply vreg_consumers_##_id[]
+
+/*
+ * Consumer specific regulator names:
+ * regulator name consumer dev_name
+ */
+VREG_CONSUMERS(L1) = {
+ REGULATOR_SUPPLY("8038_l1", NULL),
+};
+VREG_CONSUMERS(L2) = {
+ REGULATOR_SUPPLY("8038_l2", NULL),
+};
+VREG_CONSUMERS(L3) = {
+ REGULATOR_SUPPLY("8038_l3", NULL),
+ REGULATOR_SUPPLY("HSUSB_3p3", "msm_otg"),
+};
+VREG_CONSUMERS(L4) = {
+ REGULATOR_SUPPLY("8038_l4", NULL),
+ REGULATOR_SUPPLY("HSUSB_1p8", "msm_otg"),
+};
+VREG_CONSUMERS(L5) = {
+ REGULATOR_SUPPLY("8038_l5", NULL),
+};
+VREG_CONSUMERS(L6) = {
+ REGULATOR_SUPPLY("8038_l6", NULL),
+};
+VREG_CONSUMERS(L7) = {
+ REGULATOR_SUPPLY("8038_l7", NULL),
+};
+VREG_CONSUMERS(L8) = {
+ REGULATOR_SUPPLY("8038_l8", NULL),
+};
+VREG_CONSUMERS(L9) = {
+ REGULATOR_SUPPLY("8038_l9", NULL),
+};
+VREG_CONSUMERS(L10) = {
+ REGULATOR_SUPPLY("8038_l10", NULL),
+};
+VREG_CONSUMERS(L11) = {
+ REGULATOR_SUPPLY("8038_l11", NULL),
+};
+VREG_CONSUMERS(L12) = {
+ REGULATOR_SUPPLY("8038_l12", NULL),
+};
+VREG_CONSUMERS(L14) = {
+ REGULATOR_SUPPLY("8038_l14", NULL),
+};
+VREG_CONSUMERS(L15) = {
+ REGULATOR_SUPPLY("8038_l15", NULL),
+};
+VREG_CONSUMERS(L16) = {
+ REGULATOR_SUPPLY("8038_l16", NULL),
+};
+VREG_CONSUMERS(L17) = {
+ REGULATOR_SUPPLY("8038_l17", NULL),
+};
+VREG_CONSUMERS(L18) = {
+ REGULATOR_SUPPLY("8038_l18", NULL),
+};
+VREG_CONSUMERS(L19) = {
+ REGULATOR_SUPPLY("8038_l19", NULL),
+};
+VREG_CONSUMERS(L20) = {
+ REGULATOR_SUPPLY("8038_l20", NULL),
+};
+VREG_CONSUMERS(L21) = {
+ REGULATOR_SUPPLY("8038_l21", NULL),
+};
+VREG_CONSUMERS(L22) = {
+ REGULATOR_SUPPLY("8038_l22", NULL),
+};
+VREG_CONSUMERS(L23) = {
+ REGULATOR_SUPPLY("8038_l23", NULL),
+};
+VREG_CONSUMERS(L24) = {
+ REGULATOR_SUPPLY("8038_l24", NULL),
+};
+VREG_CONSUMERS(L26) = {
+ REGULATOR_SUPPLY("8038_l26", NULL),
+};
+VREG_CONSUMERS(L27) = {
+ REGULATOR_SUPPLY("8038_l27", NULL),
+};
+VREG_CONSUMERS(S1) = {
+ REGULATOR_SUPPLY("8038_s1", NULL),
+ REGULATOR_SUPPLY("HSUSB_VDDCX", "msm_otg"),
+};
+VREG_CONSUMERS(S2) = {
+ REGULATOR_SUPPLY("8038_s2", NULL),
+};
+VREG_CONSUMERS(S3) = {
+ REGULATOR_SUPPLY("8038_s3", NULL),
+};
+VREG_CONSUMERS(S4) = {
+ REGULATOR_SUPPLY("8038_s4", NULL),
+};
+VREG_CONSUMERS(S5) = {
+ REGULATOR_SUPPLY("8038_s5", NULL),
+};
+VREG_CONSUMERS(S6) = {
+ REGULATOR_SUPPLY("8038_s6", NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+ REGULATOR_SUPPLY("8038_lvs1", NULL),
+};
+VREG_CONSUMERS(LVS2) = {
+ REGULATOR_SUPPLY("8038_lvs2", NULL),
+};
+VREG_CONSUMERS(EXT_5V) = {
+ REGULATOR_SUPPLY("ext_5v", NULL),
+};
+VREG_CONSUMERS(EXT_OTG_SW) = {
+ REGULATOR_SUPPLY("ext_otg_sw", NULL),
+ REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
+};
+
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+ _apply_uV, _pull_down, _always_on, _supply_regulator, \
+ _system_uA, _enable_time, _reg_id) \
+ { \
+ .init_data = { \
+ .constraints = { \
+ .valid_modes_mask = _modes, \
+ .valid_ops_mask = _ops, \
+ .min_uV = _min_uV, \
+ .max_uV = _max_uV, \
+ .input_uV = _max_uV, \
+ .apply_uV = _apply_uV, \
+ .always_on = _always_on, \
+ .name = _name, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(vreg_consumers_##_id), \
+ .consumer_supplies = vreg_consumers_##_id, \
+ .supply_regulator = _supply_regulator, \
+ }, \
+ .id = _reg_id, \
+ .pull_down_enable = _pull_down, \
+ .system_uA = _system_uA, \
+ .enable_time = _enable_time, \
+ }
+
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+ | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+ REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+ _max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+ | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+ REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+ | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+ REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
+ | REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+ _pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+ _reg_id)
+
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+ _pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+ _reg_id)
+
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+ _always_on, _supply_regulator, 0, _enable_time, _reg_id)
+
+/* Pin control initialization */
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+ _supply_regulator, _reg_id) \
+ { \
+ .init_data = { \
+ .constraints = { \
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+ .always_on = _always_on, \
+ .name = _name, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+ .consumer_supplies = vreg_consumers_##_id##_PC, \
+ .supply_regulator = _supply_regulator, \
+ }, \
+ .id = _reg_id, \
+ .pin_fn = PM8XXX_VREG_PIN_FN_##_pin_fn, \
+ .pin_ctrl = _pin_ctrl, \
+ }
+
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
+ [MSM8930_GPIO_VREG_ID_##_id] = { \
+ .init_data = { \
+ .constraints = { \
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(vreg_consumers_##_id), \
+ .consumer_supplies = vreg_consumers_##_id, \
+ .supply_regulator = _supply_regulator, \
+ }, \
+ .regulator_name = _reg_name, \
+ .gpio_label = _gpio_label, \
+ .gpio = _gpio, \
+ }
+
+/* GPIO regulator constraints */
+struct gpio_regulator_platform_data
+msm8930_gpio_regulator_pdata[] __devinitdata = {
+ /* ID vreg_name gpio_label gpio supply */
+ GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", 63, NULL),
+ GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
+};
+
+/* PM8038 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm8930_pm8038_regulator_pdata[] __devinitdata = {
+ /*
+ * ID name always_on pd min_uV max_uV en_t supply
+ * system_uA reg_ID
+ */
+ PM8XXX_SMPS(S1, "8038_s1", 1, 1, 1150000, 1150000, 500, NULL, 100000,
+ 26),
+ PM8XXX_SMPS(S2, "8038_s2", 1, 1, 1400000, 1400000, 500, NULL, 100000,
+ 27),
+ PM8XXX_SMPS(S3, "8038_s3", 0, 1, 1150000, 1150000, 500, NULL, 0, 28),
+ PM8XXX_SMPS(S4, "8038_s4", 1, 1, 2200000, 2200000, 500, NULL, 100000,
+ 29),
+
+ PM8XXX_FTSMPS(S5, "8038_s5", 0, 1, 950000, 1150000, 500, NULL, 0, 30),
+ PM8XXX_FTSMPS(S6, "8038_s6", 0, 1, 950000, 1150000, 500, NULL, 0, 31),
+
+ PM8XXX_NLDO1200(L1, "8038_l1", 0, 1, 1300000, 1300000, 200, "8038_s2",
+ 0, 1),
+ PM8XXX_LDO(L2, "8038_l2", 0, 1, 1200000, 1200000, 200, "8038_s2", 0,
+ 2),
+ PM8XXX_LDO(L3, "8038_l3", 0, 1, 3075000, 3075000, 200, NULL, 0, 3),
+ PM8XXX_LDO(L4, "8038_l4", 1, 1, 1800000, 1800000, 200, NULL, 10000,
+ 4),
+ PM8XXX_LDO(L5, "8038_l5", 0, 1, 2950000, 2950000, 200, NULL, 0, 5),
+ PM8XXX_LDO(L6, "8038_l6", 0, 1, 2950000, 2950000, 200, NULL, 0, 6),
+ PM8XXX_LDO(L7, "8038_l7", 0, 1, 2050000, 2050000, 200, "8038_s4", 0,
+ 7),
+ PM8XXX_LDO(L8, "8038_l8", 0, 1, 2800000, 2800000, 200, NULL, 0, 8),
+ PM8XXX_LDO(L9, "8038_l9", 0, 1, 2850000, 2850000, 200, NULL, 0, 9),
+ PM8XXX_LDO(L10, "8038_l10", 0, 1, 2900000, 2900000, 200, NULL, 0, 10),
+ PM8XXX_LDO(L11, "8038_l11", 1, 1, 1800000, 1800000, 200, "8038_s4",
+ 10000, 11),
+ PM8XXX_LDO(L12, "8038_l12", 0, 1, 1200000, 1200000, 200, "8038_s2", 0,
+ 12),
+ PM8XXX_LDO(L14, "8038_l14", 0, 1, 1800000, 1800000, 200, NULL, 0, 13),
+ PM8XXX_LDO(L15, "8038_l15", 0, 1, 1800000, 2950000, 200, NULL, 0, 14),
+ PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ 0, 15),
+ PM8XXX_LDO(L17, "8038_l17", 0, 1, 1800000, 2950000, 200, NULL, 0, 16),
+ PM8XXX_LDO(L18, "8038_l18", 0, 1, 1800000, 1800000, 200, NULL, 0, 17),
+ PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ 0, 18),
+ PM8XXX_NLDO1200(L20, "8038_l20", 1, 1, 1200000, 1200000, 200, "8038_s2",
+ 10000, 19),
+ PM8XXX_LDO(L21, "8038_l21", 0, 1, 1900000, 1900000, 200, "8038_s4", 0,
+ 20),
+ PM8XXX_LDO(L22, "8038_l22", 1, 1, 2950000, 2950000, 200, NULL, 10000,
+ 21),
+ PM8XXX_LDO(L23, "8038_l23", 0, 1, 1800000, 1800000, 200, "8038_s4", 0,
+ 22),
+ PM8XXX_NLDO1200(L24, "8038_l24", 1, 1, 1150000, 1150000, 200, "8038_s2",
+ 10000, 23),
+ PM8XXX_LDO(L26, "8038_l26", 1, 1, 1050000, 1050000, 200, "8038_s2",
+ 10000, 24),
+ PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ 0, 25),
+
+ /* ID name always_on pd en_t supply reg_ID */
+ PM8XXX_VS(LVS1, "8038_lvs1", 0, 1, 0, "8038_l11", 32),
+ PM8XXX_VS(LVS2, "8038_lvs2", 0, 1, 0, "8038_l11", 33),
+
+};
+
+int msm8930_pm8038_regulator_pdata_len __devinitdata =
+ ARRAY_SIZE(msm8930_pm8038_regulator_pdata);
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 620716a..d39f64e 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -326,11 +326,18 @@
msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_ADSP_SIZE;
#endif
}
+
+static void __init reserve_mdp_memory(void)
+{
+ msm8930_mdp_writeback(msm8930_reserve_table);
+}
+
static void __init msm8930_calculate_reserve_sizes(void)
{
size_pmem_devices();
reserve_pmem_memory();
reserve_ion_memory();
+ reserve_mdp_memory();
}
static struct reserve_info msm8930_reserve_info __initdata = {
@@ -731,8 +738,6 @@
static void __init msm8930_init_irq(void)
{
- unsigned int i;
-
msm_mpm_irq_extn_init();
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
(void *)MSM_QGIC_CPU_BASE);
@@ -742,15 +747,6 @@
writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
mb();
-
- /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
}
static void __init msm8930_init_buses(void)
@@ -776,71 +772,12 @@
#ifdef CONFIG_USB_MSM_OTG_72K
static struct msm_otg_platform_data msm_otg_pdata;
#else
-#define USB_5V_EN 42
-static void msm_hsusb_vbus_power(bool on)
-{
- int rc;
- static bool vbus_is_on;
- static struct regulator *mvs_otg_switch;
-
- if (vbus_is_on == on)
- return;
-
- if (on) {
- mvs_otg_switch = regulator_get(&msm8960_device_otg.dev,
- "vbus_otg");
- if (IS_ERR(mvs_otg_switch)) {
- pr_err("Unable to get mvs_otg_switch\n");
- return;
- }
- /* TODO: Replace this with appropriate PM8038 alternative */
-#ifndef MSM8930_PHASE_2
- rc = gpio_request(PM8921_GPIO_PM_TO_SYS(USB_5V_EN),
- "usb_5v_en");
-#endif
- if (rc < 0) {
- pr_err("failed to request usb_5v_en gpio\n");
- goto put_mvs_otg;
- }
-
- /* TODO: Replace this with appropriate PM8038 alternative */
-#ifndef MSM8930_PHASE_2
- rc = gpio_direction_output(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 1);
- if (rc) {
- pr_err("%s: unable to set_direction for gpio [%d]\n",
- __func__, PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
- goto free_usb_5v_en;
- }
-#endif
- if (regulator_enable(mvs_otg_switch)) {
- pr_err("unable to enable mvs_otg_switch\n");
- goto err_ldo_gpio_set_dir;
- }
-
- vbus_is_on = true;
- return;
- }
- regulator_disable(mvs_otg_switch);
-
-/* TODO: Replace this with appropriate PM8038 alternative */
-#ifndef MSM8930_PHASE_2
-err_ldo_gpio_set_dir:
- gpio_set_value(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 0);
-free_usb_5v_en:
- gpio_free(PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
-#endif
-put_mvs_otg:
- regulator_put(mvs_otg_switch);
- vbus_is_on = false;
-}
-
static struct msm_otg_platform_data msm_otg_pdata = {
.mode = USB_OTG,
.otg_control = OTG_PMIC_CONTROL,
.phy_type = SNPS_28NM_INTEGRATED_PHY,
.pclk_src_name = "dfab_usb_hs_clk",
.pmic_id_irq = PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE),
- .vbus_power = msm_hsusb_vbus_power,
.power_budget = 750,
};
#endif
@@ -1294,98 +1231,136 @@
},
};
-/* configuration data */
-static const u8 mxt_config_data[] = {
+#define MXT_TS_GPIO_IRQ 11
+#define MXT_TS_RESET_GPIO 52
+
+static const u8 mxt_config_data_8930[] = {
/* T6 Object */
- 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
/* T38 Object */
- 11, 2, 0, 11, 11, 11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
+ 15, 1, 0, 15, 12, 11, 0, 0,
/* T7 Object */
- 100, 16, 50,
+ 48, 255, 25,
/* T8 Object */
- 8, 0, 0, 0, 0, 0, 8, 14, 50, 215,
+ 27, 0, 5, 1, 0, 0, 8, 8, 0, 0,
/* T9 Object */
- 131, 0, 0, 26, 42, 0, 32, 63, 3, 5,
- 0, 2, 1, 113, 10, 10, 8, 10, 255, 2,
- 85, 5, 0, 0, 20, 20, 75, 25, 202, 29,
- 10, 10, 45, 46,
+ 131, 0, 0, 19, 11, 0, 16, 35, 1, 3,
+ 10, 15, 1, 11, 4, 5, 40, 10, 54, 2,
+ 43, 4, 0, 0, 0, 0, 143, 40, 143, 80,
+ 18, 15, 50, 50, 2,
/* T15 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- /* T22 Object */
- 5, 0, 0, 0, 0, 0, 0, 0, 30, 0,
- 0, 0, 5, 8, 10, 13, 0,
- /* T24 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ /* T18 Object */
+ 0, 0,
+ /* T19 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ /* T23 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
/* T25 Object */
- 3, 0, 188, 52, 52, 33, 0, 0, 0, 0,
- 0, 0, 0, 0,
- /* T27 Object */
- 0, 0, 0, 0, 0, 0, 0,
- /* T28 Object */
- 0, 0, 0, 8, 12, 60,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
/* T40 Object */
- 0, 0, 0, 0, 0,
- /* T41 Object */
- 0, 0, 0, 0, 0, 0,
- /* T43 Object */
- 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* T42 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T46 Object */
+ 0, 3, 16, 48, 0, 0, 1, 0, 0,
+ /* T47 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T48 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
};
-#define MXT_TS_GPIO_IRQ 11
-#define MXT_TS_LDO_EN_GPIO 50
-#define MXT_TS_RESET_GPIO 52
+static ssize_t mxt224e_vkeys_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 200,
+ __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":65:938:90:90"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":208:938:90:90"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":348:938:90:90"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":490:938:90:90"
+ "\n");
+}
-static struct mxt_platform_data mxt_platform_data = {
- .config = mxt_config_data,
- .config_length = ARRAY_SIZE(mxt_config_data),
- .x_size = 1365,
- .y_size = 767,
+static struct kobj_attribute mxt224e_vkeys_attr = {
+ .attr = {
+ .mode = S_IRUGO,
+ },
+ .show = &mxt224e_vkeys_show,
+};
+
+static struct attribute *mxt224e_properties_attrs[] = {
+ &mxt224e_vkeys_attr.attr,
+ NULL
+};
+
+static struct attribute_group mxt224e_properties_attr_group = {
+ .attrs = mxt224e_properties_attrs,
+};
+
+static void mxt_init_vkeys_8930(void)
+{
+ int rc;
+ static struct kobject *mxt224e_properties_kobj;
+
+ mxt224e_vkeys_attr.attr.name = "virtualkeys.atmel_mxt_ts";
+ mxt224e_properties_kobj = kobject_create_and_add("board_properties",
+ NULL);
+ if (mxt224e_properties_kobj)
+ rc = sysfs_create_group(mxt224e_properties_kobj,
+ &mxt224e_properties_attr_group);
+ if (!mxt224e_properties_kobj || rc)
+ pr_err("%s: failed to create board_properties\n",
+ __func__);
+
+ return;
+}
+
+static struct mxt_platform_data mxt_platform_data_8930 = {
+ .config = mxt_config_data_8930,
+ .config_length = ARRAY_SIZE(mxt_config_data_8930),
+ .x_size = 1067,
+ .y_size = 566,
.irqflags = IRQF_TRIGGER_FALLING,
.i2c_pull_up = true,
+ .reset_gpio = MXT_TS_RESET_GPIO,
+ .irq_gpio = MXT_TS_GPIO_IRQ,
};
-static struct i2c_board_info mxt_device_info[] __initdata = {
+static struct i2c_board_info mxt_device_info_8930[] __initdata = {
{
- I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
- .platform_data = &mxt_platform_data,
+ I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
+ .platform_data = &mxt_platform_data_8930,
.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
},
};
-static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
-{
-}
-
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_rpm_platform_data msm_rpm_data = {
@@ -1478,21 +1453,14 @@
};
#endif
+#ifndef MSM8930_PHASE_2
+
+/* 8930 Phase 1 */
static struct platform_device msm8930_device_ext_5v_vreg __devinitdata = {
.name = GPIO_REGULATOR_DEV_NAME,
-/* TODO: Replace this with right MPP for 8038 */
-#ifndef MSM8930_PHASE_2
.id = PM8921_MPP_PM_TO_SYS(7),
-#endif
.dev = {
- /*
- * TODO: When physical 8930/PM8038 hardware becomes
- * available, replace msm_gpio_regulator_pdata
- * with 8930 gpio regulator object.
- */
-#if !defined(MSM8930_PHASE_2)
.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
-#endif
},
};
@@ -1500,17 +1468,33 @@
.name = GPIO_REGULATOR_DEV_NAME,
.id = 91,
.dev = {
- /*
- * TODO: When physical 8930/PM8038 hardware becomes
- * available, replace msm_gpio_regulator_pdata
- * with 8930 gpio regulator object.
- */
-#if !defined(MSM8930_PHASE_2)
.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2],
-#endif
},
};
+#else
+
+/* 8930 Phase 2 */
+static struct platform_device msm8930_device_ext_5v_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 63,
+ .dev = {
+ .platform_data =
+ &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_5V],
+ },
+};
+
+static struct platform_device msm8930_device_ext_otg_sw_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 97,
+ .dev = {
+ .platform_data =
+ &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
+ },
+};
+
+#endif
+
static struct platform_device msm8930_device_rpm_regulator __devinitdata = {
.name = "rpm-regulator",
.id = -1,
@@ -1554,8 +1538,18 @@
&msm_device_saw_core0,
&msm_device_saw_core1,
&msm8930_device_ext_5v_vreg,
+#ifndef MSM8930_PHASE_2
&msm8930_device_ext_l2_vreg,
+#endif
&msm8960_device_ssbi_pmic,
+#ifdef MSM8930_PHASE_2
+ &msm8930_device_ext_otg_sw_vreg,
+#endif
+ &msm_8960_q6_lpass,
+ &msm_8960_q6_mss_fw,
+ &msm_8960_q6_mss_sw,
+ &msm_8960_riva,
+ &msm_pil_tzapps,
&msm8960_device_qup_spi_gsbi1,
&msm8960_device_qup_i2c_gsbi3,
&msm8960_device_qup_i2c_gsbi4,
@@ -1646,6 +1640,10 @@
&msm_cpudai_afe_02_rx,
&msm_cpudai_afe_02_tx,
&msm_pcm_afe,
+ &msm_compr_dsp,
+ &msm_cpudai_incall_music_rx,
+ &msm_cpudai_incall_record_rx,
+ &msm_cpudai_incall_record_tx,
&msm_pcm_hostless,
&msm_bus_apps_fabric,
&msm_bus_sys_fabric,
@@ -1825,26 +1823,6 @@
int len;
};
-#ifdef CONFIG_MSM_CAMERA
-static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
-#ifdef CONFIG_IMX074
- {
- I2C_BOARD_INFO("imx074", 0x1A),
- },
-#endif
-#ifdef CONFIG_OV2720
- {
- I2C_BOARD_INFO("ov2720", 0x6C),
- },
-#endif
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
- {
- I2C_BOARD_INFO("sc628a", 0x6E),
- },
-#endif
-};
-#endif
-
static void __init msm8930_init_hsic(void)
{
#ifdef CONFIG_USB_EHCI_MSM_HSIC
@@ -1884,14 +1862,6 @@
#endif /* CONFIG_ISL9519_CHARGER */
static struct i2c_registry msm8960_i2c_devices[] __initdata = {
-#ifdef CONFIG_MSM_CAMERA
- {
- I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
- MSM_8930_GSBI4_QUP_I2C_BUS_ID,
- msm_camera_boardinfo,
- ARRAY_SIZE(msm_camera_boardinfo),
- },
-#endif
#ifdef CONFIG_ISL9519_CHARGER
{
I2C_LIQUID,
@@ -1908,16 +1878,16 @@
},
{
I2C_LIQUID,
- MSM_8930_GSBI3_QUP_I2C_BUS_ID,
- mxt_device_info,
- ARRAY_SIZE(mxt_device_info),
- },
- {
- I2C_LIQUID,
MSM_8930_GSBI10_QUP_I2C_BUS_ID,
msm_isa1200_board_info,
ARRAY_SIZE(msm_isa1200_board_info),
},
+ {
+ I2C_SURF,
+ MSM_8930_GSBI3_QUP_I2C_BUS_ID,
+ mxt_device_info_8930,
+ ARRAY_SIZE(mxt_device_info_8930),
+ },
};
#endif /* CONFIG_I2C */
@@ -1926,6 +1896,14 @@
#ifdef CONFIG_I2C
u8 mach_mask = 0;
int i;
+#ifdef CONFIG_MSM_CAMERA
+ struct i2c_registry msm8930_camera_i2c_devices = {
+ I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+ MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+ msm8930_camera_board_info.board_info,
+ msm8930_camera_board_info.num_i2c_board_info,
+ };
+#endif
/* Build the matching 'supported_machs' bitmask */
if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
@@ -1944,6 +1922,12 @@
msm8960_i2c_devices[i].info,
msm8960_i2c_devices[i].len);
}
+#ifdef CONFIG_MSM_CAMERA
+ if (msm8930_camera_i2c_devices.machs & mach_mask)
+ i2c_register_board_info(msm8930_camera_i2c_devices.bus,
+ msm8930_camera_i2c_devices.info,
+ msm8930_camera_i2c_devices.len);
+#endif
#endif
}
@@ -2001,6 +1985,8 @@
msm8930_init_cam();
msm8930_init_mmc();
acpuclk_init(&acpuclk_8930_soc_data);
+ if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
+ mxt_init_vkeys_8930();
register_i2c_devices();
msm8930_init_fb();
slim_register_board_info(msm_slim_devices,
@@ -2020,6 +2006,7 @@
.map_io = msm8930_map_io,
.reserve = msm8930_reserve,
.init_irq = msm8930_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8930_cdp_init,
.init_early = msm8930_allocate_memory_regions,
@@ -2030,6 +2017,7 @@
.map_io = msm8930_map_io,
.reserve = msm8930_reserve,
.init_irq = msm8930_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8930_cdp_init,
.init_early = msm8930_allocate_memory_regions,
@@ -2040,6 +2028,7 @@
.map_io = msm8930_map_io,
.reserve = msm8930_reserve,
.init_irq = msm8930_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8930_cdp_init,
.init_early = msm8930_allocate_memory_regions,
@@ -2050,6 +2039,7 @@
.map_io = msm8930_map_io,
.reserve = msm8930_reserve,
.init_irq = msm8930_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8930_cdp_init,
.init_early = msm8930_allocate_memory_regions,
@@ -2060,6 +2050,7 @@
.map_io = msm8930_map_io,
.reserve = msm8930_reserve,
.init_irq = msm8930_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8930_cdp_init,
.init_early = msm8930_allocate_memory_regions,
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index ec0b867..d6d3b49 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -15,9 +15,11 @@
#include <linux/regulator/gpio-regulator.h>
#include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/i2c.h>
#include <linux/i2c/sx150x.h>
#include <mach/irqs.h>
#include <mach/rpm-regulator.h>
+#include <mach/msm_memtypes.h>
/*
* TODO: When physical 8930/PM8038 hardware becomes
@@ -47,7 +49,7 @@
extern struct regulator_init_data msm_saw_regulator_pdata_s5;
extern struct regulator_init_data msm_saw_regulator_pdata_s6;
-extern struct pm8921_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
msm_pm8921_regulator_pdata[] __devinitdata;
extern int msm_pm8921_regulator_pdata_len __devinitdata;
@@ -56,12 +58,22 @@
msm_gpio_regulator_pdata[] __devinitdata;
extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata;
-#endif
#define GPIO_VREG_ID_EXT_5V 0
#define GPIO_VREG_ID_EXT_L2 1
#define GPIO_VREG_ID_EXT_3P3V 2
+#endif
+extern struct pm8xxx_regulator_platform_data
+ msm8930_pm8038_regulator_pdata[] __devinitdata;
+
+extern int msm8930_pm8038_regulator_pdata_len __devinitdata;
+
+#define MSM8930_GPIO_VREG_ID_EXT_5V 0
+#define MSM8930_GPIO_VREG_ID_EXT_OTG_SW 1
+
+extern struct gpio_regulator_platform_data
+ msm8930_gpio_regulator_pdata[] __devinitdata;
#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
enum {
@@ -88,6 +100,7 @@
#endif
extern struct sx150x_platform_data msm8930_sx150x_data[];
+extern struct msm_camera_board_info msm8930_camera_board_info;
void msm8930_init_cam(void);
void msm8930_init_fb(void);
void msm8930_init_pmic(void);
@@ -106,6 +119,7 @@
int msm8930_init_gpiomux(void);
void msm8930_allocate_fb_region(void);
void msm8930_pm8038_gpio_mpp_init(void);
+void msm8930_mdp_writeback(struct memtype_reserve *reserve_table);
#define PLATFORM_IS_CHARM25() \
(machine_is_msm8930_cdp() && \
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index f84944b..4466872 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -11,8 +11,6 @@
*
*/
-#include <linux/i2c.h>
-#include <linux/i2c/sx150x.h>
#include <asm/mach-types.h>
#include <mach/board.h>
#include <mach/msm_bus_board.h>
@@ -407,13 +405,6 @@
.actuator_info = &imx074_actuator_info
#endif
};
-
-static struct platform_device msm8960_camera_sensor_imx074 = {
- .name = "msm_camera_imx074",
- .dev = {
- .platform_data = &msm_camera_sensor_imx074_data,
- },
-};
#endif
#ifdef CONFIG_MT9M114
@@ -435,13 +426,6 @@
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
};
-
-struct platform_device msm8960_camera_sensor_mt9m114 = {
- .name = "msm_camera_mt9m114",
- .dev = {
- .platform_data = &msm_camera_sensor_mt9m114_data,
- },
-};
#endif
#ifdef CONFIG_OV2720
@@ -466,13 +450,6 @@
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
};
-
-static struct platform_device msm8960_camera_sensor_ov2720 = {
- .name = "msm_camera_ov2720",
- .dev = {
- .platform_data = &msm_camera_sensor_ov2720_data,
- },
-};
#endif
static struct msm8960_privacy_light_cfg privacy_light_info = {
@@ -481,15 +458,6 @@
void __init msm8960_init_cam(void)
{
- int i;
- struct platform_device *cam_dev[] = {
- &msm8960_camera_sensor_imx074,
-#ifdef CONFIG_MT9M114
- &msm8960_camera_sensor_mt9m114,
-#endif
- &msm8960_camera_sensor_ov2720,
- };
-
msm_gpiomux_install(msm8960_cam_common_configs,
ARRAY_SIZE(msm8960_cam_common_configs));
@@ -509,21 +477,14 @@
if (machine_is_msm8960_liquid()) {
struct msm_camera_sensor_info *s_info;
- s_info = msm8960_camera_sensor_imx074.dev.platform_data;
+ s_info = &msm_camera_sensor_imx074_data;
s_info->sensor_platform_info->mount_angle = 180;
- s_info = msm8960_camera_sensor_ov2720.dev.platform_data;
+ s_info = &msm_camera_sensor_ov2720_data;
s_info->sensor_platform_info->privacy_light = 1;
s_info->sensor_platform_info->privacy_light_info =
&privacy_light_info;
}
- for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
- struct msm_camera_sensor_info *s_info;
- s_info = cam_dev[i]->dev.platform_data;
- msm_get_cam_resources(s_info);
- platform_device_register(cam_dev[i]);
- }
-
platform_device_register(&msm8960_device_csiphy0);
platform_device_register(&msm8960_device_csiphy1);
platform_device_register(&msm8960_device_csid0);
@@ -532,4 +493,35 @@
platform_device_register(&msm8960_device_vfe);
platform_device_register(&msm8960_device_vpe);
}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info msm8960_camera_i2c_boardinfo[] = {
+#ifdef CONFIG_IMX074
+ {
+ I2C_BOARD_INFO("imx074", 0x1A),
+ .platform_data = &msm_camera_sensor_imx074_data,
+ },
+#endif
+#ifdef CONFIG_OV2720
+ {
+ I2C_BOARD_INFO("ov2720", 0x6C),
+ .platform_data = &msm_camera_sensor_ov2720_data,
+ },
+#endif
+ {
+ I2C_BOARD_INFO("mt9m114", 0x48),
+ .platform_data = &msm_camera_sensor_mt9m114_data,
+ },
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+ {
+ I2C_BOARD_INFO("sc628a", 0x6E),
+ },
+#endif
+};
+
+struct msm_camera_board_info msm8960_camera_board_info = {
+ .board_info = msm8960_camera_i2c_boardinfo,
+ .num_i2c_board_info = ARRAY_SIZE(msm8960_camera_i2c_boardinfo),
+};
+#endif
#endif
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 63c51ea..3bc9f0f 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -17,6 +17,7 @@
#include <linux/bootmem.h>
#include <asm/mach-types.h>
#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
@@ -24,9 +25,9 @@
#include "board-8960.h"
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
-#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 3) /* 4 bpp x 3 pages */
+#define MSM_FB_PRIM_BUF_SIZE (1920 * 1200 * 4 * 3) /* 4 bpp x 3 pages */
#else
-#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 2) /* 4 bpp x 2 pages */
+#define MSM_FB_PRIM_BUF_SIZE (1920 * 1200 * 4 * 2) /* 4 bpp x 2 pages */
#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
@@ -37,25 +38,26 @@
#define MSM_FB_EXT_BUF_SIZE 0
#endif
-#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
-/* width x height x 3 bpp x 2 frame buffer */
-#define MSM_FB_WRITEBACK_SIZE (1376 * 768 * 3 * 2)
-#define MSM_FB_WRITEBACK_OFFSET \
- (MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
-#else
-#define MSM_FB_WRITEBACK_SIZE 0
-#define MSM_FB_WRITEBACK_OFFSET 0
-#endif
-
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
/* 4 bpp x 2 page HDMI case */
#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
#else
/* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
- MSM_FB_WRITEBACK_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
#endif
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1920 * 1200 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
+#endif /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
+
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
+
#define MDP_VSYNC_GPIO 0
#define PANEL_NAME_MAX_LEN 30
@@ -68,11 +70,6 @@
#define HDMI_PANEL_NAME "hdmi_msm"
#define TVOUT_PANEL_NAME "tvout_msm"
-static int writeback_offset(void)
-{
- return MSM_FB_WRITEBACK_OFFSET;
-}
-
static struct resource msm_fb_resources[] = {
{
.flags = IORESOURCE_DMA,
@@ -553,9 +550,21 @@
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
.mdp_rev = MDP_REV_42,
- .writeback_offset = writeback_offset,
+ .mdp_writeback_memtype = MEMTYPE_EBI1,
+ .mdp_writeback_phys = NULL,
};
+void __init msm8960_mdp_writeback(struct memtype_reserve* reserve_table)
+{
+ mdp_pdata.mdp_writeback_size_ov0 = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+ mdp_pdata.mdp_writeback_size_ov1 = MSM_FB_OVERLAY1_WRITEBACK_SIZE;
+
+ reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+ mdp_pdata.mdp_writeback_size_ov0;
+ reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+ mdp_pdata.mdp_writeback_size_ov1;
+}
+
static struct platform_device mipi_dsi_renesas_panel_device = {
.name = "mipi_renesas",
.id = 0,
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c5d47f4..c7e32c0 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -90,7 +90,7 @@
/* Initial PM8921 GPIO configurations */
static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
- PM8XXX_GPIO_DISABLE(6), /* Disable unused */
+ PM8XXX_GPIO_OUTPUT_VIN(6, 1, PM_GPIO_VIN_VPH), /* MHL power EN_N */
PM8XXX_GPIO_DISABLE(7), /* Disable NFC */
PM8XXX_GPIO_INPUT(16, PM_GPIO_PULL_UP_30), /* SD_CARD_WP */
/* External regulator shared by display and touchscreen on LiQUID */
@@ -436,6 +436,7 @@
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
+#define PM8921_LC_LED_LOW_CURRENT 1 /* I = 1mA */
#define PM8XXX_LED_PWM_PERIOD 1000
#define PM8XXX_LED_PWM_DUTY_MS 20
/**
@@ -444,6 +445,50 @@
*/
#define PM8XXX_PWM_CHANNEL_NONE -1
+static struct led_info pm8921_led_info_liquid[] = {
+ {
+ .name = "led:red",
+ .flags = PM8XXX_ID_LED_0,
+ },
+ {
+ .name = "led:green",
+ .flags = PM8XXX_ID_LED_0,
+ },
+ {
+ .name = "led:blue",
+ .flags = PM8XXX_ID_LED_2,
+ },
+};
+
+static struct pm8xxx_led_config pm8921_led_configs_liquid[] = {
+ [0] = {
+ .id = PM8XXX_ID_LED_0,
+ .mode = PM8XXX_LED_MODE_MANUAL,
+ .max_current = PM8921_LC_LED_MAX_CURRENT,
+ },
+ [1] = {
+ .id = PM8XXX_ID_LED_1,
+ .mode = PM8XXX_LED_MODE_MANUAL,
+ .max_current = PM8921_LC_LED_LOW_CURRENT,
+ },
+ [2] = {
+ .id = PM8XXX_ID_LED_2,
+ .mode = PM8XXX_LED_MODE_MANUAL,
+ .max_current = PM8921_LC_LED_MAX_CURRENT,
+ },
+};
+
+static struct led_platform_data pm8xxx_leds_core_liquid = {
+ .num_leds = ARRAY_SIZE(pm8921_led_info_liquid),
+ .leds = pm8921_led_info_liquid,
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata_liquid = {
+ .led_core = &pm8xxx_leds_core_liquid,
+ .configs = pm8921_led_configs_liquid,
+ .num_configs = ARRAY_SIZE(pm8921_led_configs_liquid),
+};
+
static struct led_info pm8921_led_info[] = {
[0] = {
.name = "led:battery_charging",
@@ -539,6 +584,8 @@
if (machine_is_msm8960_sim())
pm8921_platform_data.keypad_pdata = &keypad_data_sim;
- if (machine_is_msm8960_liquid())
+ if (machine_is_msm8960_liquid()) {
pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
+ pm8921_platform_data.leds_pdata = &pm8xxx_leds_pdata_liquid;
+ }
}
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index de4a6d6..f6212af 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-#include <linux/regulator/pm8921-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
#include <linux/regulator/gpio-regulator.h>
#include <mach/rpm-regulator.h>
@@ -30,9 +30,9 @@
VREG_CONSUMERS(L2) = {
REGULATOR_SUPPLY("8921_l2", NULL),
REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "msm_camera_imx074.0"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("mipi_csi_vdd", "msm_camera_mt9m114.0"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "4-001a"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "4-006c"),
+ REGULATOR_SUPPLY("mipi_csi_vdd", "4-0048"),
};
VREG_CONSUMERS(L3) = {
REGULATOR_SUPPLY("8921_l3", NULL),
@@ -62,6 +62,7 @@
VREG_CONSUMERS(L9) = {
REGULATOR_SUPPLY("8921_l9", NULL),
REGULATOR_SUPPLY("vdd", "3-0024"),
+ REGULATOR_SUPPLY("vdd_ana", "3-004a"),
};
VREG_CONSUMERS(L10) = {
REGULATOR_SUPPLY("8921_l10", NULL),
@@ -70,15 +71,15 @@
};
VREG_CONSUMERS(L11) = {
REGULATOR_SUPPLY("8921_l11", NULL),
- REGULATOR_SUPPLY("cam_vana", "msm_camera_imx074.0"),
- REGULATOR_SUPPLY("cam_vana", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vana", "msm_camera_mt9m114.0"),
+ REGULATOR_SUPPLY("cam_vana", "4-001a"),
+ REGULATOR_SUPPLY("cam_vana", "4-006c"),
+ REGULATOR_SUPPLY("cam_vana", "4-0048"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8921_l12", NULL),
- REGULATOR_SUPPLY("cam_vdig", "msm_camera_imx074.0"),
- REGULATOR_SUPPLY("cam_vdig", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vdig", "msm_camera_mt9m114.0"),
+ REGULATOR_SUPPLY("cam_vdig", "4-001a"),
+ REGULATOR_SUPPLY("cam_vdig", "4-006c"),
+ REGULATOR_SUPPLY("cam_vdig", "4-0048"),
};
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8921_l14", NULL),
@@ -89,9 +90,9 @@
};
VREG_CONSUMERS(L16) = {
REGULATOR_SUPPLY("8921_l16", NULL),
- REGULATOR_SUPPLY("cam_vaf", "msm_camera_imx074.0"),
- REGULATOR_SUPPLY("cam_vaf", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vaf", "msm_camera_mt9m114.0"),
+ REGULATOR_SUPPLY("cam_vaf", "4-001a"),
+ REGULATOR_SUPPLY("cam_vaf", "4-006c"),
+ REGULATOR_SUPPLY("cam_vaf", "4-0048"),
};
VREG_CONSUMERS(L17) = {
REGULATOR_SUPPLY("8921_l17", NULL),
@@ -196,12 +197,13 @@
VREG_CONSUMERS(LVS4) = {
REGULATOR_SUPPLY("8921_lvs4", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
+ REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
};
VREG_CONSUMERS(LVS5) = {
REGULATOR_SUPPLY("8921_lvs5", NULL),
- REGULATOR_SUPPLY("cam_vio", "msm_camera_imx074.0"),
- REGULATOR_SUPPLY("cam_vio", "msm_camera_ov2720.0"),
- REGULATOR_SUPPLY("cam_vio", "msm_camera_mt9m114.0"),
+ REGULATOR_SUPPLY("cam_vio", "4-001a"),
+ REGULATOR_SUPPLY("cam_vio", "4-006c"),
+ REGULATOR_SUPPLY("cam_vio", "4-0048"),
};
VREG_CONSUMERS(LVS6) = {
REGULATOR_SUPPLY("8921_lvs6", NULL),
@@ -212,7 +214,6 @@
};
VREG_CONSUMERS(USB_OTG) = {
REGULATOR_SUPPLY("8921_usb_otg", NULL),
- REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
};
VREG_CONSUMERS(HDMI_MVS) = {
REGULATOR_SUPPLY("8921_hdmi_mvs", NULL),
@@ -230,14 +231,18 @@
};
VREG_CONSUMERS(EXT_3P3V) = {
REGULATOR_SUPPLY("ext_3p3v", NULL),
- REGULATOR_SUPPLY("vdd", "3-005b"),
+ REGULATOR_SUPPLY("vdd_ana", "3-005b"),
REGULATOR_SUPPLY("vdd_lvds_3p3v", "mipi_dsi.1"),
REGULATOR_SUPPLY("mhl_ext_3p3v", "msm_otg"),
};
+VREG_CONSUMERS(EXT_OTG_SW) = {
+ REGULATOR_SUPPLY("ext_otg_sw", NULL),
+ REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
+};
-#define PM8921_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
- _pull_down, _always_on, _supply_regulator, \
- _system_uA, _enable_time) \
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+ _apply_uV, _pull_down, _always_on, _supply_regulator, \
+ _system_uA, _enable_time, _reg_id) \
{ \
.init_data = { \
.constraints = { \
@@ -248,84 +253,89 @@
.input_uV = _max_uV, \
.apply_uV = _apply_uV, \
.always_on = _always_on, \
+ .name = _name, \
}, \
.num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id), \
.consumer_supplies = vreg_consumers_##_id, \
.supply_regulator = _supply_regulator, \
}, \
- .id = PM8921_VREG_ID_##_id, \
+ .id = _reg_id, \
.pull_down_enable = _pull_down, \
.system_uA = _system_uA, \
.enable_time = _enable_time, \
}
-#define PM8921_VREG_INIT_LDO(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_NLDO1200(_id, _always_on, _pull_down, _min_uV, \
- _max_uV, _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+ _max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_SMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_FTSMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8921_VREG_INIT_VS(_id, _always_on, _pull_down, _enable_time, \
- _supply_regulator) \
- PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
- _always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+ _pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+ _reg_id)
-#define PM8921_VREG_INIT_VS300(_id, _always_on, _pull_down, _enable_time, \
- _supply_regulator) \
- PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
- _always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+ _pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+ _reg_id)
-#define PM8921_VREG_INIT_NCP(_id, _always_on, _min_uV, _max_uV, _enable_time, \
- _supply_regulator) \
- PM8921_VREG_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE | \
- REGULATOR_CHANGE_STATUS, 0, 0, _always_on, _supply_regulator, \
- 0, _enable_time)
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+ _always_on, _supply_regulator, 0, _enable_time, _reg_id)
/* Pin control initialization */
-#define PM8921_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+ _supply_regulator, _reg_id) \
{ \
.init_data = { \
.constraints = { \
.valid_ops_mask = REGULATOR_CHANGE_STATUS, \
.always_on = _always_on, \
+ .name = _name, \
}, \
.num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id##_PC), \
.consumer_supplies = vreg_consumers_##_id##_PC, \
.supply_regulator = _supply_regulator, \
}, \
- .id = PM8921_VREG_ID_##_id##_PC, \
- .pin_fn = PM8921_VREG_PIN_FN_##_pin_fn, \
- .pin_ctrl = _pin_ctrl, \
+ .id = _reg_id, \
+ .pin_fn = PM8XXX_VREG_PIN_FN_##_pin_fn, \
+ .pin_ctrl = _pin_ctrl, \
}
-#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio) \
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
[GPIO_VREG_ID_##_id] = { \
.init_data = { \
.constraints = { \
@@ -334,6 +344,7 @@
.num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id), \
.consumer_supplies = vreg_consumers_##_id, \
+ .supply_regulator = _supply_regulator, \
}, \
.regulator_name = _reg_name, \
.gpio_label = _gpio_label, \
@@ -445,10 +456,13 @@
/* GPIO regulator constraints */
struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] __devinitdata = {
- GPIO_VREG_INIT(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7)),
- GPIO_VREG_INIT(EXT_L2, "ext_l2", "ext_l2_en", 91),
- GPIO_VREG_INIT(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
- PM8921_GPIO_PM_TO_SYS(17)),
+ /* ID vreg_name gpio_label gpio supply */
+ GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7), NULL),
+ GPIO_VREG(EXT_L2, "ext_l2", "ext_l2_en", 91, NULL),
+ GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
+ PM8921_GPIO_PM_TO_SYS(17), NULL),
+ GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en",
+ PM8921_GPIO_PM_TO_SYS(42), "8921_usb_otg"),
};
/* SAW regulator constraints */
@@ -459,24 +473,24 @@
SAW_VREG_INIT(S6, "8921_s6", 850000, 1300000);
/* PM8921 regulator constraints */
-struct pm8921_regulator_platform_data
+struct pm8xxx_regulator_platform_data
msm_pm8921_regulator_pdata[] __devinitdata = {
/*
- * ID a_on pd min_uV max_uV en_t supply
- * system_uA
+ * ID name always_on pd min_uV max_uV en_t supply
+ * system_uA reg_ID
*/
- PM8921_VREG_INIT_NLDO1200(L26, 0, 1, 1050000, 1050000, 200, "8921_s7",
- 0),
- PM8921_VREG_INIT_NLDO1200(L27, 0, 1, 1050000, 1050000, 200, "8921_s7",
- 0),
- PM8921_VREG_INIT_NLDO1200(L28, 0, 1, 1050000, 1050000, 200, "8921_s7",
- 0),
- PM8921_VREG_INIT_LDO(L29, 0, 1, 2050000, 2100000, 200, "8921_s8",
- 0),
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ 0, 1),
+ PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ 0, 2),
+ PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ 0, 3),
+ PM8XXX_LDO(L29, "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
+ 0, 4),
- /* ID always_on pd enable_time supply */
- PM8921_VREG_INIT_VS300(USB_OTG, 0, 1, 0, "ext_5v"),
- PM8921_VREG_INIT_VS300(HDMI_MVS, 0, 1, 0, "ext_5v"),
+ /* ID name always_on pd en_t supply reg_ID */
+ PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 1, 0, "ext_5v", 5),
+ PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0, "ext_5v", 6),
};
static struct rpm_regulator_init_data
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index dfcafd4..8b43d38 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -211,7 +211,7 @@
};
static unsigned int sdc3_sup_clk_rates[] = {
- 400000, 24000000, 48000000, 96000000
+ 400000, 24000000, 48000000, 96000000, 192000000
};
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
@@ -247,11 +247,12 @@
.status_gpio = PM8921_GPIO_PM_TO_SYS(26),
.status_irq = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
.irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ .is_status_gpio_active_low = true,
#endif
.xpc_cap = 1,
.uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
- MMC_CAP_MAX_CURRENT_600)
+ MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_600),
};
#endif
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 3ef7dea..a9424d6 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -78,6 +78,7 @@
#include <linux/ion.h>
#include <mach/ion.h>
#include <mach/mdm2.h>
+#include <mach/mdm-peripheral.h>
#include <linux/fmem.h>
@@ -134,7 +135,7 @@
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#else
-#define MSM_PMEM_SIZE 0x1C00000 /* 28 Mbytes */
+#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
#endif
#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
@@ -377,12 +378,19 @@
msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_ADSP_SIZE;
#endif
}
+
+static void __init reserve_mdp_memory(void)
+{
+ msm8960_mdp_writeback(msm8960_reserve_table);
+}
+
static void __init msm8960_calculate_reserve_sizes(void)
{
size_pmem_devices();
reserve_pmem_memory();
reserve_ion_memory();
reserve_fmem_memory();
+ reserve_mdp_memory();
}
static struct reserve_info msm8960_reserve_info __initdata = {
@@ -598,6 +606,55 @@
#define QCE_SHARE_CE_RESOURCE 1
#define QCE_CE_SHARED 0
+/* Begin Bus scaling definitions */
+static struct msm_bus_vectors crypto_hw_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT1,
+ .dst = MSM_BUS_SLAVE_GSBI1_UART,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors crypto_hw_active_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 70000000UL,
+ .ib = 70000000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT1,
+ .dst = MSM_BUS_SLAVE_GSBI1_UART,
+ .ab = 2480000000UL,
+ .ib = 2480000000UL,
+ },
+};
+
+static struct msm_bus_paths crypto_hw_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(crypto_hw_init_vectors),
+ crypto_hw_init_vectors,
+ },
+ {
+ ARRAY_SIZE(crypto_hw_active_vectors),
+ crypto_hw_active_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata crypto_hw_bus_scale_pdata = {
+ crypto_hw_bus_scale_usecases,
+ ARRAY_SIZE(crypto_hw_bus_scale_usecases),
+ .name = "cryptohw",
+};
+/* End Bus Scaling Definitions*/
+
static struct resource qcrypto_resources[] = {
[0] = {
.start = QCE_0_BASE,
@@ -660,6 +717,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = &crypto_hw_bus_scale_pdata,
};
static struct platform_device qcrypto_device = {
@@ -682,6 +740,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = &crypto_hw_bus_scale_pdata,
};
static struct platform_device qcedev_device = {
@@ -773,8 +832,6 @@
static void __init msm8960_init_irq(void)
{
- unsigned int i;
-
msm_mpm_irq_extn_init();
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
(void *)MSM_QGIC_CPU_BASE);
@@ -784,15 +841,6 @@
writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
mb();
-
- /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
}
static void __init msm8960_init_buses(void)
@@ -818,56 +866,6 @@
#ifdef CONFIG_USB_MSM_OTG_72K
static struct msm_otg_platform_data msm_otg_pdata;
#else
-#define USB_5V_EN 42
-static void msm_hsusb_vbus_power(bool on)
-{
- int rc;
- static bool vbus_is_on;
- static struct regulator *mvs_otg_switch;
-
- if (vbus_is_on == on)
- return;
-
- if (on) {
- mvs_otg_switch = regulator_get(&msm8960_device_otg.dev,
- "vbus_otg");
- if (IS_ERR(mvs_otg_switch)) {
- pr_err("Unable to get mvs_otg_switch\n");
- return;
- }
-
- rc = gpio_request(PM8921_GPIO_PM_TO_SYS(USB_5V_EN),
- "usb_5v_en");
- if (rc < 0) {
- pr_err("failed to request usb_5v_en gpio\n");
- goto put_mvs_otg;
- }
-
- rc = gpio_direction_output(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 1);
- if (rc) {
- pr_err("%s: unable to set_direction for gpio [%d]\n",
- __func__, PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
- goto free_usb_5v_en;
- }
-
- if (regulator_enable(mvs_otg_switch)) {
- pr_err("unable to enable mvs_otg_switch\n");
- goto err_ldo_gpio_set_dir;
- }
-
- vbus_is_on = true;
- return;
- }
- regulator_disable(mvs_otg_switch);
-err_ldo_gpio_set_dir:
- gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 0);
-free_usb_5v_en:
- gpio_free(PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
-put_mvs_otg:
- regulator_put(mvs_otg_switch);
- vbus_is_on = false;
-}
-
static int wr_phy_init_seq[] = {
0x44, 0x80, /* set VBUS valid threshold
and disconnect valid threshold */
@@ -890,7 +888,6 @@
.phy_type = SNPS_28NM_INTEGRATED_PHY,
.pclk_src_name = "dfab_usb_hs_clk",
.pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
- .vbus_power = msm_hsusb_vbus_power,
.power_budget = 750,
};
#endif
@@ -1383,66 +1380,32 @@
0, 0, 0, 0, 0, 0,
};
-#define MXT_TS_GPIO_IRQ 11
-#define MXT_TS_LDO_EN_GPIO 50
-#define MXT_TS_RESET_GPIO 52
+#define MXT_TS_GPIO_IRQ 11
+#define MXT_TS_LDO_EN_GPIO 50
+#define MXT_TS_RESET_GPIO 52
static void mxt_init_hw_liquid(void)
{
int rc;
- rc = gpio_request(MXT_TS_GPIO_IRQ, "mxt_ts_irq_gpio");
- if (rc) {
- pr_err("%s: unable to request mxt_ts_irq gpio [%d]\n",
- __func__, MXT_TS_GPIO_IRQ);
- return;
- }
-
- rc = gpio_direction_input(MXT_TS_GPIO_IRQ);
- if (rc) {
- pr_err("%s: unable to set_direction for mxt_ts_irq gpio [%d]\n",
- __func__, MXT_TS_GPIO_IRQ);
- goto err_irq_gpio_req;
- }
-
rc = gpio_request(MXT_TS_LDO_EN_GPIO, "mxt_ldo_en_gpio");
if (rc) {
- pr_err("%s: unable to request mxt_ldo_en gpio [%d]\n",
- __func__, MXT_TS_LDO_EN_GPIO);
- goto err_irq_gpio_req;
+ pr_err("%s: unable to request mxt_ldo_en_gpio [%d]\n",
+ __func__, MXT_TS_LDO_EN_GPIO);
+ return;
}
rc = gpio_direction_output(MXT_TS_LDO_EN_GPIO, 1);
if (rc) {
- pr_err("%s: unable to set_direction for mxt_ldo_en gpio [%d]\n",
- __func__, MXT_TS_LDO_EN_GPIO);
+ pr_err("%s: unable to set_direction for mxt_ldo_en_gpio [%d]\n",
+ __func__, MXT_TS_LDO_EN_GPIO);
goto err_ldo_gpio_req;
}
- rc = gpio_request(MXT_TS_RESET_GPIO, "mxt_reset_gpio");
- if (rc) {
- pr_err("%s: unable to request mxt_reset gpio [%d]\n",
- __func__, MXT_TS_RESET_GPIO);
- goto err_ldo_gpio_set_dir;
- }
-
- rc = gpio_direction_output(MXT_TS_RESET_GPIO, 1);
- if (rc) {
- pr_err("%s: unable to set_direction for mxt_reset gpio [%d]\n",
- __func__, MXT_TS_RESET_GPIO);
- goto err_reset_gpio_req;
- }
-
return;
-err_reset_gpio_req:
- gpio_free(MXT_TS_RESET_GPIO);
-err_ldo_gpio_set_dir:
- gpio_set_value(MXT_TS_LDO_EN_GPIO, 0);
err_ldo_gpio_req:
gpio_free(MXT_TS_LDO_EN_GPIO);
-err_irq_gpio_req:
- gpio_free(MXT_TS_GPIO_IRQ);
}
static struct mxt_platform_data mxt_platform_data = {
@@ -1452,6 +1415,8 @@
.y_size = 767,
.irqflags = IRQF_TRIGGER_FALLING,
.i2c_pull_up = true,
+ .reset_gpio = MXT_TS_RESET_GPIO,
+ .irq_gpio = MXT_TS_GPIO_IRQ,
};
static struct i2c_board_info mxt_device_info[] __initdata = {
@@ -1470,32 +1435,24 @@
},
};
-static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
-{
-}
-
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
- .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
static struct msm_rpm_platform_data msm_rpm_data = {
@@ -1599,6 +1556,15 @@
},
};
+static struct platform_device msm8960_device_ext_otg_sw_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = PM8921_GPIO_PM_TO_SYS(42),
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_OTG_SW],
+ },
+};
+
static struct platform_device msm8960_device_rpm_regulator __devinitdata = {
.name = "rpm-regulator",
.id = -1,
@@ -1635,6 +1601,7 @@
&msm_device_saw_core1,
&msm8960_device_ext_5v_vreg,
&msm8960_device_ssbi_pmic,
+ &msm8960_device_ext_otg_sw_vreg,
&msm8960_device_qup_spi_gsbi1,
&msm8960_device_qup_i2c_gsbi3,
&msm8960_device_qup_i2c_gsbi4,
@@ -1723,6 +1690,9 @@
&msm_voip,
&msm_lpa_pcm,
&msm_compr_dsp,
+ &msm_cpudai_incall_music_rx,
+ &msm_cpudai_incall_record_rx,
+ &msm_cpudai_incall_record_tx,
#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
@@ -1748,6 +1718,8 @@
&msm_8960_q6_lpass,
&msm_8960_q6_mss_fw,
&msm_8960_q6_mss_sw,
+ &msm_8960_riva,
+ &msm_pil_tzapps,
&msm8960_device_otg,
&msm8960_device_gadget_peripheral,
&msm_device_hsusb_host,
@@ -1782,6 +1754,9 @@
&msm_cpudai_afe_02_tx,
&msm_pcm_afe,
&msm_compr_dsp,
+ &msm_cpudai_incall_music_rx,
+ &msm_cpudai_incall_record_rx,
+ &msm_cpudai_incall_record_tx,
&msm_pcm_hostless,
&msm_bus_apps_fabric,
&msm_bus_sys_fabric,
@@ -1961,31 +1936,6 @@
int len;
};
-#ifdef CONFIG_MSM_CAMERA
-static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
-#ifdef CONFIG_IMX074
- {
- I2C_BOARD_INFO("imx074", 0x1A),
- },
-#endif
-#ifdef CONFIG_OV2720
- {
- I2C_BOARD_INFO("ov2720", 0x6C),
- },
-#endif
-#ifdef CONFIG_MT9M114
- {
- I2C_BOARD_INFO("mt9m114", 0x48),
- },
-#endif
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
- {
- I2C_BOARD_INFO("sc628a", 0x6E),
- },
-#endif
-};
-#endif
-
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
#define DSPS_PIL_GENERIC_NAME "dsps"
@@ -2004,6 +1954,33 @@
#endif /* CONFIG_MSM_DSPS */
}
+static int hsic_peripheral_status = 1;
+static DEFINE_MUTEX(hsic_status_lock);
+
+void peripheral_connect()
+{
+ mutex_lock(&hsic_status_lock);
+ if (hsic_peripheral_status)
+ goto out;
+ platform_device_add(&msm_device_hsic_host);
+ hsic_peripheral_status = 1;
+out:
+ mutex_unlock(&hsic_status_lock);
+}
+EXPORT_SYMBOL(peripheral_connect);
+
+void peripheral_disconnect()
+{
+ mutex_lock(&hsic_status_lock);
+ if (!hsic_peripheral_status)
+ goto out;
+ platform_device_del(&msm_device_hsic_host);
+ hsic_peripheral_status = 0;
+out:
+ mutex_unlock(&hsic_status_lock);
+}
+EXPORT_SYMBOL(peripheral_disconnect);
+
static void __init msm8960_init_hsic(void)
{
#ifdef CONFIG_USB_EHCI_MSM_HSIC
@@ -2045,14 +2022,6 @@
};
static struct i2c_registry msm8960_i2c_devices[] __initdata = {
-#ifdef CONFIG_MSM_CAMERA
- {
- I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
- MSM_8960_GSBI4_QUP_I2C_BUS_ID,
- msm_camera_boardinfo,
- ARRAY_SIZE(msm_camera_boardinfo),
- },
-#endif
#ifdef CONFIG_ISL9519_CHARGER
{
I2C_LIQUID,
@@ -2099,6 +2068,14 @@
#ifdef CONFIG_I2C
u8 mach_mask = 0;
int i;
+#ifdef CONFIG_MSM_CAMERA
+ struct i2c_registry msm8960_camera_i2c_devices = {
+ I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+ MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+ msm8960_camera_board_info.board_info,
+ msm8960_camera_board_info.num_i2c_board_info,
+ };
+#endif
/* Build the matching 'supported_machs' bitmask */
if (machine_is_msm8960_cdp())
@@ -2123,6 +2100,12 @@
msm8960_i2c_devices[i].info,
msm8960_i2c_devices[i].len);
}
+#ifdef CONFIG_MSM_CAMERA
+ if (msm8960_camera_i2c_devices.machs & mach_mask)
+ i2c_register_board_info(msm8960_camera_i2c_devices.bus,
+ msm8960_camera_i2c_devices.info,
+ msm8960_camera_i2c_devices.len);
+#endif
#endif
}
@@ -2278,6 +2261,7 @@
.map_io = msm8960_map_io,
.reserve = msm8960_reserve,
.init_irq = msm8960_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8960_sim_init,
.init_early = msm8960_allocate_memory_regions,
@@ -2288,6 +2272,7 @@
.map_io = msm8960_map_io,
.reserve = msm8960_reserve,
.init_irq = msm8960_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8960_rumi3_init,
.init_early = msm8960_allocate_memory_regions,
@@ -2298,6 +2283,7 @@
.map_io = msm8960_map_io,
.reserve = msm8960_reserve,
.init_irq = msm8960_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8960_cdp_init,
.init_early = msm8960_allocate_memory_regions,
@@ -2308,6 +2294,7 @@
.map_io = msm8960_map_io,
.reserve = msm8960_reserve,
.init_irq = msm8960_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8960_cdp_init,
.init_early = msm8960_allocate_memory_regions,
@@ -2318,6 +2305,7 @@
.map_io = msm8960_map_io,
.reserve = msm8960_reserve,
.init_irq = msm8960_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8960_cdp_init,
.init_early = msm8960_allocate_memory_regions,
@@ -2328,6 +2316,7 @@
.map_io = msm8960_map_io,
.reserve = msm8960_reserve,
.init_irq = msm8960_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm8960_cdp_init,
.init_early = msm8960_allocate_memory_regions,
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index e22868f..5f4f3a0 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -15,9 +15,11 @@
#include <linux/regulator/gpio-regulator.h>
#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/i2c.h>
#include <linux/i2c/sx150x.h>
#include <mach/irqs.h>
#include <mach/rpm-regulator.h>
+#include <mach/msm_memtypes.h>
/* Macros assume PMIC GPIOs and MPPs start at 1 */
#define PM8921_GPIO_BASE NR_GPIO_IRQS
@@ -26,7 +28,7 @@
#define PM8921_MPP_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_MPP_BASE)
#define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
-extern struct pm8921_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
msm_pm8921_regulator_pdata[] __devinitdata;
extern int msm_pm8921_regulator_pdata_len __devinitdata;
@@ -34,6 +36,7 @@
#define GPIO_VREG_ID_EXT_5V 0
#define GPIO_VREG_ID_EXT_L2 1
#define GPIO_VREG_ID_EXT_3P3V 2
+#define GPIO_VREG_ID_EXT_OTG_SW 3
extern struct gpio_regulator_platform_data
msm_gpio_regulator_pdata[] __devinitdata;
@@ -69,6 +72,7 @@
#endif
extern struct sx150x_platform_data msm8960_sx150x_data[];
+extern struct msm_camera_board_info msm8960_camera_board_info;
void msm8960_init_cam(void);
void msm8960_init_fb(void);
void msm8960_init_pmic(void);
@@ -76,7 +80,7 @@
int msm8960_init_gpiomux(void);
void msm8960_allocate_fb_region(void);
void msm8960_pm8921_gpio_mpp_init(void);
-
+void msm8960_mdp_writeback(struct memtype_reserve *reserve_table);
#define PLATFORM_IS_CHARM25() \
(machine_is_msm8960_cdp() && \
(socinfo_get_platform_subtype() == 1) \
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
new file mode 100644
index 0000000..4baa851
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -0,0 +1,252 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <mach/gpiomux.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include "board-9615.h"
+
+static struct gpiomux_setting ps_hold = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi4 = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi5 = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi3 = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi3_cs1_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct gpiomux_setting ltc4088_chg_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_suspend_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
+ {
+ /* SDC2_DATA_0 */
+ .gpio = 25,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* SDC2_DATA_1 */
+ .gpio = 26,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_cmd_data_0_3_actv_cfg,
+ },
+ },
+ {
+ /* SDC2_DATA_2 */
+ .gpio = 27,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* SDC2_DATA_3 */
+ .gpio = 28,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* SDC2_CMD */
+ .gpio = 29,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* SDC2_CLK */
+ .gpio = 30,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_clk_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+};
+
+struct msm_gpiomux_config msm9615_ps_hold_config[] __initdata = {
+ {
+ .gpio = 83,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ps_hold,
+ },
+ },
+};
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct msm_gpiomux_config
+ msm9615_ltc4088_charger_config[] __initdata = {
+ {
+ .gpio = 4,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
+ },
+ },
+ {
+ .gpio = 6,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
+ },
+ },
+ {
+ .gpio = 7,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
+ },
+ },
+};
+#endif
+
+struct msm_gpiomux_config msm9615_gsbi_configs[] __initdata = {
+ {
+ .gpio = 8, /* GSBI3 QUP SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3,
+ },
+ },
+ {
+ .gpio = 9, /* GSBI3 QUP SPI_CS_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3,
+ },
+ },
+ {
+ .gpio = 10, /* GSBI3 QUP SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3,
+ },
+ },
+ {
+ .gpio = 11, /* GSBI3 QUP SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3,
+ },
+ },
+ {
+ .gpio = 12, /* GSBI4 UART */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi4,
+ },
+ },
+ {
+ .gpio = 13, /* GSBI4 UART */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi4,
+ },
+ },
+ {
+ .gpio = 14, /* GSBI4 UART */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi4,
+ },
+ },
+ {
+ .gpio = 15, /* GSBI4 UART */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi4,
+ },
+ },
+ {
+ .gpio = 16, /* GSBI5 I2C QUP SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ .gpio = 17, /* GSBI5 I2C QUP SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi5,
+ },
+ },
+ {
+ /* GPIO 19 can be used for I2C/UART on GSBI5 */
+ .gpio = 19, /* GSBI3 QUP SPI_CS_1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi3_cs1_config,
+ },
+ },
+};
+
+int __init msm9615_init_gpiomux(void)
+{
+ int rc;
+
+ rc = msm_gpiomux_init(NR_GPIO_IRQS);
+ if (rc) {
+ pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+ return rc;
+ }
+ msm_gpiomux_install(msm9615_gsbi_configs,
+ ARRAY_SIZE(msm9615_gsbi_configs));
+
+ msm_gpiomux_install(msm9615_ps_hold_config,
+ ARRAY_SIZE(msm9615_ps_hold_config));
+ msm_gpiomux_install(msm9615_sdcc2_configs,
+ ARRAY_SIZE(msm9615_sdcc2_configs));
+#ifdef CONFIG_LTC4088_CHARGER
+ msm_gpiomux_install(msm9615_ltc4088_charger_config,
+ ARRAY_SIZE(msm9615_ltc4088_charger_config));
+#endif
+
+ return 0;
+}
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 7cf4a8c..14e84a6 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-#include <linux/regulator/pm8018-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
#include <linux/regulator/gpio-regulator.h>
#include <mach/rpm-regulator.h>
@@ -91,9 +91,9 @@
REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.1"),
};
-#define PM8018_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
- _pull_down, _always_on, _supply_regulator, \
- _system_uA, _enable_time) \
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+ _apply_uV, _pull_down, _always_on, _supply_regulator, \
+ _system_uA, _enable_time, _reg_id) \
{ \
.init_data = { \
.constraints = { \
@@ -104,63 +104,67 @@
.input_uV = _max_uV, \
.apply_uV = _apply_uV, \
.always_on = _always_on, \
+ .name = _name, \
}, \
.num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id), \
.consumer_supplies = vreg_consumers_##_id, \
.supply_regulator = _supply_regulator, \
}, \
- .id = PM8018_VREG_ID_##_id, \
+ .id = _reg_id, \
.pull_down_enable = _pull_down, \
.system_uA = _system_uA, \
.enable_time = _enable_time, \
}
-#define PM8018_VREG_INIT_LDO(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8018_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8018_VREG_INIT_NLDO1200(_id, _always_on, _pull_down, _min_uV, \
- _max_uV, _enable_time, _supply_regulator, _system_uA) \
- PM8018_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+ _max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8018_VREG_INIT_SMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
- _enable_time, _supply_regulator, _system_uA) \
- PM8018_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+ _enable_time, _supply_regulator, _system_uA, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
-#define PM8018_VREG_INIT_VS(_id, _always_on, _pull_down, _enable_time, \
- _supply_regulator) \
- PM8018_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
- _always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+ _pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+ _reg_id)
/* Pin control initialization */
-#define PM8018_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+ _supply_regulator, _reg_id) \
{ \
.init_data = { \
.constraints = { \
.valid_ops_mask = REGULATOR_CHANGE_STATUS, \
.always_on = _always_on, \
+ .name = _name, \
}, \
.num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id##_PC), \
.consumer_supplies = vreg_consumers_##_id##_PC, \
.supply_regulator = _supply_regulator, \
}, \
- .id = PM8018_VREG_ID_##_id##_PC, \
- .pin_fn = PM8018_VREG_PIN_FN_##_pin_fn, \
- .pin_ctrl = _pin_ctrl, \
+ .id = _reg_id, \
+ .pin_fn = PM8XXX_VREG_PIN_FN_##_pin_fn, \
+ .pin_ctrl = _pin_ctrl, \
}
#define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
@@ -266,7 +270,7 @@
};
/* PM8018 regulator constraints */
-struct pm8018_regulator_platform_data
+struct pm8xxx_regulator_platform_data
msm_pm8018_regulator_pdata[] __devinitdata = {
};
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
new file mode 100644
index 0000000..95c87bf
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -0,0 +1,228 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
+ || defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
+
+#define GPIO_SDC1_HW_DET 80
+#define GPIO_SDC2_DAT1_WAKEUP 26
+
+/* MDM9x15 has 2 SDCC controllers */
+enum sdcc_controllers {
+ SDCC1,
+ SDCC2,
+ MAX_SDCC_CONTROLLER
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+/* All SDCC controllers requires VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : External card slot connected */
+ [SDCC1] = {
+ .name = "sdc_vdd",
+ /*
+ * This is a gpio-regulator and does not support
+ * regulator_set_voltage and regulator_set_optimum_mode
+ */
+ .high_vol_level = 2950000,
+ .low_vol_level = 2950000,
+ .hpm_uA = 600000, /* 600mA */
+ }
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : External card slot connected */
+ [SDCC1] = {
+ .name = "sdc_vddp",
+ .high_vol_level = 2950000,
+ .low_vol_level = 1850000,
+ .always_on = true,
+ .lpm_sup = true,
+ /* Max. Active current required is 16 mA */
+ .hpm_uA = 16000,
+ /*
+ * Sleep current required is ~300 uA. But min. vote can be
+ * in terms of mA (min. 1 mA). So let's vote for 2 mA
+ * during sleep.
+ */
+ .lpm_uA = 2000,
+ }
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : External card slot connected */
+ [SDCC1] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC1],
+ .vddp_data = &mmc_vddp_reg_data[SDCC1],
+ }
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+ {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+ {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+ {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_pull_on_cfg,
+ .off = sdc1_pad_pull_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .on = sdc1_pad_drv_on_cfg,
+ .off = sdc1_pad_drv_off_cfg,
+ .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+ },
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC1] = {
+ .pull = &mmc_pad_pull_data[SDCC1],
+ .drv = &mmc_pad_drv_data[SDCC1]
+ },
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+
+static struct msm_mmc_gpio sdc2_gpio_cfg[] = {
+ {25, "sdc2_dat_0"},
+ {26, "sdc2_dat_1"},
+ {27, "sdc2_dat_2"},
+ {28, "sdc2_dat_3"},
+ {29, "sdc2_cmd"},
+ {30, "sdc2_clk"},
+};
+
+static struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC2] = {
+ .gpio = sdc2_gpio_cfg,
+ .size = ARRAY_SIZE(sdc2_gpio_cfg),
+ },
+};
+#endif
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ [SDCC1] = {
+ .is_gpio = 0,
+ .pad_data = &mmc_pad_data[SDCC1],
+ },
+#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ [SDCC2] = {
+ .is_gpio = 1,
+ .gpio_data = &mmc_gpio_data[SDCC2],
+ },
+#endif
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static unsigned int sdc1_sup_clk_rates[] = {
+ 400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc1_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+ .sup_clk_table = sdc1_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
+ .pclk_src_dfab = true,
+ .vreg_data = &mmc_slot_vreg_data[SDCC1],
+ .pin_data = &mmc_slot_pin_data[SDCC1],
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+ .status_gpio = GPIO_SDC1_HW_DET,
+ .status_irq = MSM_GPIO_TO_INT(GPIO_SDC1_HW_DET),
+ .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+ .xpc_cap = 1,
+ .uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_MAX_CURRENT_400)
+};
+static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
+#else
+static struct mmc_platform_data *msm9615_sdc1_pdata;
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+ 400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc2_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .mmc_bus_width = MMC_CAP_4_BIT_DATA,
+ .sup_clk_table = sdc2_sup_clk_rates,
+ .sup_clk_cnt = ARRAY_SIZE(sdc2_sup_clk_rates),
+ .pclk_src_dfab = 1,
+ .pin_data = &mmc_slot_pin_data[SDCC2],
+#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
+ .sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
+#endif
+};
+static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
+#else
+static struct mmc_platform_data *msm9615_sdc2_pdata;
+#endif
+
+void __init msm9615_init_mmc(void)
+{
+ if (msm9615_sdc1_pdata) {
+ /* SDC1: External card slot for SD/MMC cards */
+ msm_add_sdcc(1, msm9615_sdc1_pdata);
+ }
+
+ if (msm9615_sdc2_pdata) {
+ /* SDC2: External card slot used for WLAN */
+ msm_add_sdcc(2, msm9615_sdc2_pdata);
+ }
+}
+#else
+void __init msm9615_init_mmc(void)
+{
+}
+#endif
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index f5bd44d..ec2a71d 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -15,19 +15,19 @@
#include <linux/i2c.h>
#include <linux/msm_ssbi.h>
#include <linux/memblock.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/mmc.h>
-#include <mach/board.h>
-#include <mach/msm_iomap.h>
-#include <mach/gpio.h>
-#include <mach/gpiomux.h>
-#include <mach/msm_spi.h>
#include <linux/usb/android.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/leds.h>
#include <linux/leds-pm8xxx.h>
+#include <linux/power/ltc4088-charger.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/gpio.h>
+#include <mach/msm_spi.h>
#include <mach/msm_bus_board.h>
#include "timer.h"
#include "devices.h"
@@ -35,7 +35,6 @@
#include "cpuidle.h"
#include "pm.h"
#include "acpuclock.h"
-#include <linux/power/ltc4088-charger.h>
#include "pm-boot.h"
static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
@@ -181,423 +180,6 @@
},
};
-static struct gpiomux_setting ps_hold = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi4 = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi5 = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi3 = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi3_cs1_config = {
- .func = GPIOMUX_FUNC_4,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-#ifdef CONFIG_LTC4088_CHARGER
-static struct gpiomux_setting ltc4088_chg_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-#endif
-
-struct msm_gpiomux_config msm9615_ps_hold_config[] __initdata = {
- {
- .gpio = 83,
- .settings = {
- [GPIOMUX_SUSPENDED] = &ps_hold,
- },
- },
-};
-
-#ifdef CONFIG_LTC4088_CHARGER
-static struct msm_gpiomux_config
- msm9615_ltc4088_charger_config[] __initdata = {
- {
- .gpio = 4,
- .settings = {
- [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
- },
- },
- {
- .gpio = 6,
- .settings = {
- [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
- },
- },
- {
- .gpio = 7,
- .settings = {
- [GPIOMUX_SUSPENDED] = <c4088_chg_cfg,
- },
- },
-};
-#endif
-
-struct msm_gpiomux_config msm9615_gsbi_configs[] __initdata = {
- {
- .gpio = 8, /* GSBI3 QUP SPI_CLK */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi3,
- },
- },
- {
- .gpio = 9, /* GSBI3 QUP SPI_CS_N */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi3,
- },
- },
- {
- .gpio = 10, /* GSBI3 QUP SPI_DATA_MISO */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi3,
- },
- },
- {
- .gpio = 11, /* GSBI3 QUP SPI_DATA_MOSI */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi3,
- },
- },
- {
- .gpio = 12, /* GSBI4 UART */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi4,
- },
- },
- {
- .gpio = 13, /* GSBI4 UART */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi4,
- },
- },
- {
- .gpio = 14, /* GSBI4 UART */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi4,
- },
- },
- {
- .gpio = 15, /* GSBI4 UART */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi4,
- },
- },
- {
- .gpio = 16, /* GSBI5 I2C QUP SCL */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 17, /* GSBI5 I2C QUP SDA */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- /* GPIO 19 can be used for I2C/UART on GSBI5 */
- .gpio = 19, /* GSBI3 QUP SPI_CS_1 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi3_cs1_config,
- },
- },
-};
-
-#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
- || defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
-
-#define GPIO_SDC1_HW_DET 80
-#define GPIO_SDC2_DAT1_WAKEUP 26
-
-/* MDM9x15 has 2 SDCC controllers */
-enum sdcc_controllers {
- SDCC1,
- SDCC2,
- MAX_SDCC_CONTROLLER
-};
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-/* All SDCC controllers requires VDD/VCC voltage */
-static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC1 : External card slot connected */
- [SDCC1] = {
- .name = "sdc_vdd",
- /*
- * This is a gpio-regulator and does not support
- * regulator_set_voltage and regulator_set_optimum_mode
- */
- .high_vol_level = 2950000,
- .low_vol_level = 2950000,
- .hpm_uA = 600000, /* 600mA */
- }
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC1 : External card slot connected */
- [SDCC1] = {
- .name = "sdc_vddp",
- .high_vol_level = 2950000,
- .low_vol_level = 1850000,
- .always_on = true,
- .lpm_sup = true,
- /* Max. Active current required is 16 mA */
- .hpm_uA = 16000,
- /*
- * Sleep current required is ~300 uA. But min. vote can be
- * in terms of mA (min. 1 mA). So let's vote for 2 mA
- * during sleep.
- */
- .lpm_uA = 2000,
- }
-};
-
-static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
- /* SDCC1 : External card slot connected */
- [SDCC1] = {
- .vdd_data = &mmc_vdd_reg_data[SDCC1],
- .vddp_data = &mmc_vddp_reg_data[SDCC1],
- }
-};
-
-/* SDC1 pad data */
-static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
- {TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
- {TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
- {TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
-};
-
-static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
- {TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
- {TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
- {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
- {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
- {TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
- {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
-};
-
-static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .on = sdc1_pad_pull_on_cfg,
- .off = sdc1_pad_pull_off_cfg,
- .size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
- },
-};
-
-static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .on = sdc1_pad_drv_on_cfg,
- .off = sdc1_pad_drv_off_cfg,
- .size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
- },
-};
-
-static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
- [SDCC1] = {
- .pull = &mmc_pad_pull_data[SDCC1],
- .drv = &mmc_pad_drv_data[SDCC1]
- },
-};
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-static struct gpiomux_setting sdcc2_clk_actv_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_16MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting sdcc2_suspend_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
- {
- /* SDC2_DATA_0 */
- .gpio = 25,
- .settings = {
- [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
- [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
- },
- },
- {
- /* SDC2_DATA_1 */
- .gpio = 26,
- .settings = {
- [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
- [GPIOMUX_SUSPENDED] = &sdcc2_cmd_data_0_3_actv_cfg,
- },
- },
- {
- /* SDC2_DATA_2 */
- .gpio = 27,
- .settings = {
- [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
- [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
- },
- },
- {
- /* SDC2_DATA_3 */
- .gpio = 28,
- .settings = {
- [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
- [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
- },
- },
- {
- /* SDC2_CMD */
- .gpio = 29,
- .settings = {
- [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
- [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
- },
- },
- {
- /* SDC2_CLK */
- .gpio = 30,
- .settings = {
- [GPIOMUX_ACTIVE] = &sdcc2_clk_actv_cfg,
- [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
- },
- },
-};
-
-static struct msm_mmc_gpio sdc2_gpio_cfg[] = {
- {25, "sdc2_dat_0"},
- {26, "sdc2_dat_1"},
- {27, "sdc2_dat_2"},
- {28, "sdc2_dat_3"},
- {29, "sdc2_cmd"},
- {30, "sdc2_clk"},
-};
-
-static struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
- [SDCC2] = {
- .gpio = sdc2_gpio_cfg,
- .size = ARRAY_SIZE(sdc2_gpio_cfg),
- },
-};
-#else
-static struct msm_gpiomux_config msm9615_sdcc2_configs[0];
-#endif
-
-static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
- [SDCC1] = {
- .is_gpio = 0,
- .pad_data = &mmc_pad_data[SDCC1],
- },
-#endif
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
- [SDCC2] = {
- .is_gpio = 1,
- .gpio_data = &mmc_gpio_data[SDCC2],
- },
-#endif
-};
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-static unsigned int sdc1_sup_clk_rates[] = {
- 400000, 24000000, 48000000
-};
-
-static struct mmc_platform_data sdc1_data = {
- .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
- .mmc_bus_width = MMC_CAP_4_BIT_DATA,
- .sup_clk_table = sdc1_sup_clk_rates,
- .sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
- .pclk_src_dfab = true,
- .vreg_data = &mmc_slot_vreg_data[SDCC1],
- .pin_data = &mmc_slot_pin_data[SDCC1],
-#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
- .status_gpio = GPIO_SDC1_HW_DET,
- .status_irq = MSM_GPIO_TO_INT(GPIO_SDC1_HW_DET),
- .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-#endif
- .xpc_cap = 1,
- .uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_MAX_CURRENT_400)
-};
-static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
-#else
-static struct mmc_platform_data *msm9615_sdc1_pdata;
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-static unsigned int sdc2_sup_clk_rates[] = {
- 400000, 24000000, 48000000
-};
-
-static struct mmc_platform_data sdc2_data = {
- .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
- .mmc_bus_width = MMC_CAP_4_BIT_DATA,
- .sup_clk_table = sdc2_sup_clk_rates,
- .sup_clk_cnt = ARRAY_SIZE(sdc2_sup_clk_rates),
- .pclk_src_dfab = 1,
- .pin_data = &mmc_slot_pin_data[SDCC2],
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
- .sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
-#endif
-};
-static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
-#else
-static struct mmc_platform_data *msm9615_sdc2_pdata;
-#endif
-
-static void __init msm9615_init_mmc(void)
-{
- if (msm9615_sdc1_pdata) {
- /* SDC1: External card slot for SD/MMC cards */
- msm_add_sdcc(1, msm9615_sdc1_pdata);
- }
-
- if (msm9615_sdc2_pdata) {
- msm_gpiomux_install(msm9615_sdcc2_configs,
- ARRAY_SIZE(msm9615_sdcc2_configs));
-
- /* SDC2: External card slot used for WLAN */
- msm_add_sdcc(2, msm9615_sdc2_pdata);
- }
-}
-#else
-static void __init msm9615_init_mmc(void) { }
-#endif
static struct msm_cpuidle_state msm_cstates[] __initdata = {
{0, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
@@ -634,27 +216,6 @@
.v_addr = MSM_APCS_GLB_BASE + 0x24,
};
-static int __init gpiomux_init(void)
-{
- int rc;
-
- rc = msm_gpiomux_init(NR_GPIO_IRQS);
- if (rc) {
- pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
- return rc;
- }
- msm_gpiomux_install(msm9615_gsbi_configs,
- ARRAY_SIZE(msm9615_gsbi_configs));
-
- msm_gpiomux_install(msm9615_ps_hold_config,
- ARRAY_SIZE(msm9615_ps_hold_config));
-#ifdef CONFIG_LTC4088_CHARGER
- msm_gpiomux_install(msm9615_ltc4088_charger_config,
- ARRAY_SIZE(msm9615_ltc4088_charger_config));
-#endif
- return 0;
-}
-
static void __init msm9615_init_buses(void)
{
#ifdef CONFIG_MSM_BUS_SCALING
@@ -865,7 +426,7 @@
static void __init msm9615_common_init(void)
{
msm9615_device_init();
- gpiomux_init();
+ msm9615_init_gpiomux();
msm9615_i2c_init();
regulator_suppress_info_printing();
platform_device_register(&msm9615_device_rpm_regulator);
@@ -908,6 +469,7 @@
MACHINE_START(MSM9615_CDP, "QCT MSM9615 CDP")
.map_io = msm9615_map_io,
.init_irq = msm9615_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm9615_cdp_init,
.reserve = msm9615_reserve,
@@ -916,6 +478,7 @@
MACHINE_START(MSM9615_MTP, "QCT MSM9615 MTP")
.map_io = msm9615_map_io,
.init_irq = msm9615_init_irq,
+ .handle_irq = gic_handle_irq,
.timer = &msm_timer,
.init_machine = msm9615_mtp_init,
.reserve = msm9615_reserve,
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 0f5adf0..4759f8c 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.h
@@ -25,7 +25,7 @@
#define PM8018_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
#define PM8018_MPP_IRQ_BASE (PM8018_IRQ_BASE + NR_GPIO_IRQS)
-extern struct pm8018_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
msm_pm8018_regulator_pdata[] __devinitdata;
extern int msm_pm8018_regulator_pdata_len __devinitdata;
@@ -37,4 +37,6 @@
extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
+int msm9615_init_gpiomux(void);
+void msm9615_init_mmc(void);
#endif
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 13d63d3..f4fcb75 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -50,8 +50,6 @@
void __init msm_copper_init_irq(void)
{
- unsigned int i;
-
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
(void *)MSM_QGIC_CPU_BASE);
@@ -61,14 +59,6 @@
writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
mb();
- /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
irq_domain_generate_simple(msm_copper_gic_match,
COPPER_QGIC_DIST_PHYS, GIC_SPI_START);
}
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index ebe884de..19f54cf 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
+#include <asm/hardware/gic.h>
#include <asm/arch_timer.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
@@ -54,9 +55,9 @@
return 0;
}
-int local_timer_ack(void)
+void local_timer_stop(void)
{
- return 1;
+ return;
}
static void __init msm_dt_init_irq(void)
@@ -94,6 +95,7 @@
.map_io = msm_dt_map_io,
.init_irq = msm_dt_init_irq,
.init_machine = msm_dt_init,
+ .handle_irq = gic_handle_irq,
.timer = &msm_dt_timer,
.dt_compat = msm_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 550e288..87fea3f 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -696,6 +696,7 @@
.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
struct platform_device qcrypto_device = {
@@ -746,6 +747,7 @@
.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
static struct platform_device qcedev_device = {
@@ -917,6 +919,7 @@
.boot_params = PHYS_OFFSET + 0x100,
.map_io = fsm9xxx_map_io,
.init_irq = fsm9xxx_init_irq,
+ .handle_irq = vic_handle_irq,
.init_machine = fsm9xxx_init,
.timer = &msm_timer,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
new file mode 100644
index 0000000..d4f06fa
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -0,0 +1,966 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/marimba.h>
+#include <linux/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/rpc_pmapp.h>
+
+#include "board-msm7627a.h"
+#include "devices-msm7x2xa.h"
+
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+
+
+static struct bt_vreg_info bt_vregs[] = {
+ {"msme1", 2, 1800000, 1800000, 0, NULL},
+ {"bt", 21, 2900000, 3300000, 1, NULL}
+};
+
+struct platform_device msm_bt_power_device = {
+ .name = "bt_power",
+};
+
+static unsigned bt_config_power_on[] = {
+ /*RFR*/
+ GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*CTS*/
+ GPIO_CFG(44, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*RX*/
+ GPIO_CFG(45, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*TX*/
+ GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+static unsigned bt_config_pcm_on[] = {
+ /*PCM_DOUT*/
+ GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*PCM_DIN*/
+ GPIO_CFG(69, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*PCM_SYNC*/
+ GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*PCM_CLK*/
+ GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+static unsigned bt_config_power_off[] = {
+ /*RFR*/
+ GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*CTS*/
+ GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*RX*/
+ GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*TX*/
+ GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+static unsigned bt_config_pcm_off[] = {
+ /*PCM_DOUT*/
+ GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*PCM_DIN*/
+ GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*PCM_SYNC*/
+ GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*PCM_CLK*/
+ GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static unsigned fm_i2s_config_power_on[] = {
+ /*FM_I2S_SD*/
+ GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*FM_I2S_WS*/
+ GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ /*FM_I2S_SCK*/
+ GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static unsigned fm_i2s_config_power_off[] = {
+ /*FM_I2S_SD*/
+ GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*FM_I2S_WS*/
+ GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ /*FM_I2S_SCK*/
+ GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+int gpio_bt_sys_rest_en = 133;
+static void gpio_bt_config(void)
+{
+ if (machine_is_msm7627a_qrd1())
+ gpio_bt_sys_rest_en = 114;
+}
+
+static int bt_set_gpio(int on)
+{
+ int rc = 0;
+ struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+
+ if (on) {
+ rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+ msleep(100);
+ } else {
+ if (!marimba_get_fm_status(&config) &&
+ !marimba_get_bt_status(&config)) {
+ gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
+ rc = gpio_direction_input(gpio_bt_sys_rest_en);
+ msleep(100);
+ }
+ }
+ if (rc)
+ pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
+
+ return rc;
+}
+
+static struct regulator *fm_regulator;
+static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
+{
+ int rc = 0;
+ const char *id = "FMPW";
+ uint32_t irqcfg;
+ struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+ u8 value;
+
+ /* Voting for 1.8V Regulator */
+ fm_regulator = regulator_get(NULL , "msme1");
+ if (IS_ERR(fm_regulator)) {
+ rc = PTR_ERR(fm_regulator);
+ pr_err("%s: could not get regulator: %d\n", __func__, rc);
+ goto out;
+ }
+
+ /* Set the voltage level to 1.8V */
+ rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
+ if (rc < 0) {
+ pr_err("%s: could not set voltage: %d\n", __func__, rc);
+ goto reg_free;
+ }
+
+ /* Enabling the 1.8V regulator */
+ rc = regulator_enable(fm_regulator);
+ if (rc) {
+ pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+ goto reg_free;
+ }
+
+ /* Voting for 19.2MHz clock */
+ rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+ PMAPP_CLOCK_VOTE_ON);
+ if (rc < 0) {
+ pr_err("%s: clock vote failed with :(%d)\n",
+ __func__, rc);
+ goto reg_disable;
+ }
+
+ rc = bt_set_gpio(1);
+ if (rc) {
+ pr_err("%s: bt_set_gpio = %d", __func__, rc);
+ goto gpio_deconfig;
+ }
+ /*re-write FM Slave Id, after reset*/
+ value = BAHAMA_SLAVE_ID_FM_ADDR;
+ rc = marimba_write_bit_mask(&config,
+ BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
+ if (rc < 0) {
+ pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
+ goto gpio_deconfig;
+ }
+ /* Configuring the FM GPIO */
+ irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA);
+
+ rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, irqcfg, rc);
+ goto gpio_deconfig;
+ }
+
+ return 0;
+
+gpio_deconfig:
+ pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+ PMAPP_CLOCK_VOTE_OFF);
+ bt_set_gpio(0);
+reg_disable:
+ regulator_disable(fm_regulator);
+reg_free:
+ regulator_put(fm_regulator);
+ fm_regulator = NULL;
+out:
+ return rc;
+};
+
+static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
+{
+ int rc;
+ const char *id = "FMPW";
+
+ /* Releasing the GPIO line used by FM */
+ uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT,
+ GPIO_CFG_PULL_UP, GPIO_CFG_2MA);
+
+ rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+ if (rc)
+ pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, irqcfg, rc);
+
+ /* Releasing the 1.8V Regulator */
+ if (!IS_ERR_OR_NULL(fm_regulator)) {
+ rc = regulator_disable(fm_regulator);
+ if (rc)
+ pr_err("%s: could not disable regulator: %d\n",
+ __func__, rc);
+ regulator_put(fm_regulator);
+ fm_regulator = NULL;
+ }
+
+ /* Voting off the clock */
+ rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+ PMAPP_CLOCK_VOTE_OFF);
+ if (rc < 0)
+ pr_err("%s: voting off failed with :(%d)\n",
+ __func__, rc);
+ rc = bt_set_gpio(0);
+ if (rc)
+ pr_err("%s: bt_set_gpio = %d", __func__, rc);
+}
+static int switch_pcm_i2s_reg_mode(int mode)
+{
+ unsigned char reg = 0;
+ int rc = -1;
+ unsigned char set = I2C_PIN_CTL; /*SET PIN CTL mode*/
+ unsigned char unset = I2C_NORMAL; /* UNSET PIN CTL MODE*/
+ struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+
+ if (mode == 0) {
+ /* as we need to switch path to FM we need to move
+ BT AUX PCM lines to PIN CONTROL mode then move
+ FM to normal mode.*/
+ for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
+ rc = marimba_write(&config, reg, &set, 1);
+ if (rc < 0) {
+ pr_err("pcm pinctl failed = %d", rc);
+ goto err_all;
+ }
+ }
+ for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
+ rc = marimba_write(&config, reg, &unset, 1);
+ if (rc < 0) {
+ pr_err("i2s normal failed = %d", rc);
+ goto err_all;
+ }
+ }
+ } else {
+ /* as we need to switch path to AUXPCM we need to move
+ FM I2S lines to PIN CONTROL mode then move
+ BT AUX_PCM to normal mode.*/
+ for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
+ rc = marimba_write(&config, reg, &set, 1);
+ if (rc < 0) {
+ pr_err("i2s pinctl failed = %d", rc);
+ goto err_all;
+ }
+ }
+ for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
+ rc = marimba_write(&config, reg, &unset, 1);
+ if (rc < 0) {
+ pr_err("pcm normal failed = %d", rc);
+ goto err_all;
+ }
+ }
+ }
+
+ return 0;
+
+err_all:
+ return rc;
+}
+
+
+static void config_pcm_i2s_mode(int mode)
+{
+ void __iomem *cfg_ptr;
+ u8 reg2;
+
+ cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
+
+ if (!cfg_ptr)
+ return;
+ if (mode) {
+ /*enable the pcm mode in FPGA*/
+ reg2 = readb_relaxed(cfg_ptr);
+ if (reg2 == 0) {
+ reg2 = 1;
+ writeb_relaxed(reg2, cfg_ptr);
+ }
+ } else {
+ /*enable i2s mode in FPGA*/
+ reg2 = readb_relaxed(cfg_ptr);
+ if (reg2 == 1) {
+ reg2 = 0;
+ writeb_relaxed(reg2, cfg_ptr);
+ }
+ }
+ iounmap(cfg_ptr);
+}
+
+static int config_i2s(int mode)
+{
+ int pin, rc = 0;
+
+ if (mode == FM_I2S_ON) {
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+ config_pcm_i2s_mode(0);
+ pr_err("%s mode = FM_I2S_ON", __func__);
+
+ rc = switch_pcm_i2s_reg_mode(0);
+ if (rc) {
+ pr_err("switch mode failed");
+ return rc;
+ }
+ for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
+ pin++) {
+ rc = gpio_tlmm_config(
+ fm_i2s_config_power_on[pin],
+ GPIO_CFG_ENABLE
+ );
+ if (rc < 0)
+ return rc;
+ }
+ } else if (mode == FM_I2S_OFF) {
+ pr_err("%s mode = FM_I2S_OFF", __func__);
+ rc = switch_pcm_i2s_reg_mode(1);
+ if (rc) {
+ pr_err("switch mode failed");
+ return rc;
+ }
+ for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
+ pin++) {
+ rc = gpio_tlmm_config(
+ fm_i2s_config_power_off[pin],
+ GPIO_CFG_ENABLE
+ );
+ if (rc < 0)
+ return rc;
+ }
+ }
+ return rc;
+}
+
+static int config_pcm(int mode)
+{
+ int pin, rc = 0;
+
+ if (mode == BT_PCM_ON) {
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+ config_pcm_i2s_mode(1);
+ pr_err("%s mode =BT_PCM_ON", __func__);
+ rc = switch_pcm_i2s_reg_mode(1);
+ if (rc) {
+ pr_err("switch mode failed");
+ return rc;
+ }
+ for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
+ pin++) {
+ rc = gpio_tlmm_config(bt_config_pcm_on[pin],
+ GPIO_CFG_ENABLE);
+ if (rc < 0)
+ return rc;
+ }
+ } else if (mode == BT_PCM_OFF) {
+ pr_err("%s mode =BT_PCM_OFF", __func__);
+ rc = switch_pcm_i2s_reg_mode(0);
+ if (rc) {
+ pr_err("switch mode failed");
+ return rc;
+ }
+ for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
+ pin++) {
+ rc = gpio_tlmm_config(bt_config_pcm_off[pin],
+ GPIO_CFG_ENABLE);
+ if (rc < 0)
+ return rc;
+ }
+
+ }
+
+ return rc;
+}
+
+static int msm_bahama_setup_pcm_i2s(int mode)
+{
+ int fm_state = 0, bt_state = 0;
+ int rc = 0;
+ struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+
+ fm_state = marimba_get_fm_status(&config);
+ bt_state = marimba_get_bt_status(&config);
+
+ switch (mode) {
+ case BT_PCM_ON:
+ case BT_PCM_OFF:
+ if (!fm_state)
+ rc = config_pcm(mode);
+ break;
+ case FM_I2S_ON:
+ rc = config_i2s(mode);
+ break;
+ case FM_I2S_OFF:
+ if (bt_state)
+ rc = config_pcm(BT_PCM_ON);
+ else
+ rc = config_i2s(mode);
+ break;
+ default:
+ rc = -EIO;
+ pr_err("%s:Unsupported mode", __func__);
+ }
+ return rc;
+}
+
+static int bahama_bt(int on)
+{
+ int rc = 0;
+ int i;
+
+ struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+
+ struct bahama_variant_register {
+ const size_t size;
+ const struct bahama_config_register *set;
+ };
+
+ const struct bahama_config_register *p;
+
+ u8 version;
+
+ const struct bahama_config_register v10_bt_on[] = {
+ { 0xE9, 0x00, 0xFF },
+ { 0xF4, 0x80, 0xFF },
+ { 0xE4, 0x00, 0xFF },
+ { 0xE5, 0x00, 0x0F },
+#ifdef CONFIG_WLAN
+ { 0xE6, 0x38, 0x7F },
+ { 0xE7, 0x06, 0xFF },
+#endif
+ { 0xE9, 0x21, 0xFF },
+ { 0x01, 0x0C, 0x1F },
+ { 0x01, 0x08, 0x1F },
+ };
+
+ const struct bahama_config_register v20_bt_on_fm_off[] = {
+ { 0x11, 0x0C, 0xFF },
+ { 0x13, 0x01, 0xFF },
+ { 0xF4, 0x80, 0xFF },
+ { 0xF0, 0x00, 0xFF },
+ { 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+ { 0x81, 0x00, 0x7F },
+ { 0x82, 0x00, 0xFF },
+ { 0xE6, 0x38, 0x7F },
+ { 0xE7, 0x06, 0xFF },
+#endif
+ { 0x8E, 0x15, 0xFF },
+ { 0x8F, 0x15, 0xFF },
+ { 0x90, 0x15, 0xFF },
+
+ { 0xE9, 0x21, 0xFF },
+ };
+
+ const struct bahama_config_register v20_bt_on_fm_on[] = {
+ { 0x11, 0x0C, 0xFF },
+ { 0x13, 0x01, 0xFF },
+ { 0xF4, 0x86, 0xFF },
+ { 0xF0, 0x06, 0xFF },
+ { 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+ { 0x81, 0x00, 0x7F },
+ { 0x82, 0x00, 0xFF },
+ { 0xE6, 0x38, 0x7F },
+ { 0xE7, 0x06, 0xFF },
+#endif
+ { 0xE9, 0x21, 0xFF },
+ };
+
+ const struct bahama_config_register v10_bt_off[] = {
+ { 0xE9, 0x00, 0xFF },
+ };
+
+ const struct bahama_config_register v20_bt_off_fm_off[] = {
+ { 0xF4, 0x84, 0xFF },
+ { 0xF0, 0x04, 0xFF },
+ { 0xE9, 0x00, 0xFF }
+ };
+
+ const struct bahama_config_register v20_bt_off_fm_on[] = {
+ { 0xF4, 0x86, 0xFF },
+ { 0xF0, 0x06, 0xFF },
+ { 0xE9, 0x00, 0xFF }
+ };
+
+ const struct bahama_variant_register bt_bahama[2][3] = {
+ {
+ { ARRAY_SIZE(v10_bt_off), v10_bt_off },
+ { ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
+ { ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
+ },
+ {
+ { ARRAY_SIZE(v10_bt_on), v10_bt_on },
+ { ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
+ { ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
+ }
+ };
+
+ u8 offset = 0; /* index into bahama configs */
+ on = on ? 1 : 0;
+ version = marimba_read_bahama_ver(&config);
+ if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
+ dev_err(&msm_bt_power_device.dev, "%s : Bahama "
+ "version read Error, version = %d\n",
+ __func__, version);
+ return -EIO;
+ }
+
+ if (version == BAHAMA_VER_2_0) {
+ if (marimba_get_fm_status(&config))
+ offset = 0x01;
+ }
+
+ p = bt_bahama[on][version + offset].set;
+
+ dev_info(&msm_bt_power_device.dev,
+ "%s: found version %d\n", __func__, version);
+
+ for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
+ u8 value = (p+i)->value;
+ rc = marimba_write_bit_mask(&config,
+ (p+i)->reg,
+ &value,
+ sizeof((p+i)->value),
+ (p+i)->mask);
+ if (rc < 0) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: reg %x write failed: %d\n",
+ __func__, (p+i)->reg, rc);
+ return rc;
+ }
+ dev_dbg(&msm_bt_power_device.dev,
+ "%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
+ __func__, (p+i)->reg,
+ value, (p+i)->mask);
+ value = 0;
+ rc = marimba_read_bit_mask(&config,
+ (p+i)->reg, &value,
+ sizeof((p+i)->value), (p+i)->mask);
+ if (rc < 0)
+ dev_err(&msm_bt_power_device.dev,
+ "%s marimba_read_bit_mask- error",
+ __func__);
+ dev_dbg(&msm_bt_power_device.dev,
+ "%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
+ __func__, (p+i)->reg,
+ value, (p+i)->mask);
+ }
+ /* Update BT Status */
+ if (on)
+ marimba_set_bt_status(&config, true);
+ else
+ marimba_set_bt_status(&config, false);
+ return rc;
+}
+
+static int bluetooth_switch_regulators(int on)
+{
+ int i, rc = 0;
+ const char *id = "BTPW";
+
+ for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
+ if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
+ rc = bt_vregs[i].reg ?
+ PTR_ERR(bt_vregs[i].reg) :
+ -ENODEV;
+ dev_err(&msm_bt_power_device.dev,
+ "%s: invalid regulator handle for %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto reg_disable;
+ }
+
+ rc = on ? regulator_set_voltage(bt_vregs[i].reg,
+ bt_vregs[i].min_level,
+ bt_vregs[i].max_level) : 0;
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: could not set voltage for %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto reg_disable;
+ }
+
+ rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: could not %sable regulator %s: %d\n",
+ __func__, "en", bt_vregs[i].name, rc);
+ goto reg_disable;
+ }
+
+ if (bt_vregs[i].is_pin_controlled) {
+ rc = pmapp_vreg_lpm_pincntrl_vote(id,
+ bt_vregs[i].pmapp_id,
+ PMAPP_CLOCK_ID_D1,
+ on ? PMAPP_CLOCK_VOTE_ON :
+ PMAPP_CLOCK_VOTE_OFF);
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: pin control failed for %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto pin_cnt_fail;
+ }
+ }
+ rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
+
+ if (rc) {
+ dev_err(&msm_bt_power_device.dev,
+ "%s: could not %sable regulator %s: %d\n",
+ __func__, "dis", bt_vregs[i].name, rc);
+ goto reg_disable;
+ }
+ }
+
+ return rc;
+pin_cnt_fail:
+ if (on)
+ regulator_disable(bt_vregs[i].reg);
+reg_disable:
+ while (i) {
+ if (on) {
+ i--;
+ regulator_disable(bt_vregs[i].reg);
+ regulator_put(bt_vregs[i].reg);
+ }
+ }
+ return rc;
+}
+
+static struct regulator *reg_s3;
+static unsigned int msm_bahama_setup_power(void)
+{
+ int rc = 0;
+
+ reg_s3 = regulator_get(NULL, "msme1");
+ if (IS_ERR(reg_s3)) {
+ rc = PTR_ERR(reg_s3);
+ pr_err("%s: could not get regulator: %d\n", __func__, rc);
+ goto out;
+ }
+
+ rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
+ if (rc < 0) {
+ pr_err("%s: could not set voltage: %d\n", __func__, rc);
+ goto reg_fail;
+ }
+
+ rc = regulator_enable(reg_s3);
+ if (rc < 0) {
+ pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+ goto reg_fail;
+ }
+ if (machine_is_msm7627a_qrd1())
+ gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+
+
+ /*setup Bahama_sys_reset_n*/
+ rc = gpio_request(gpio_bt_sys_rest_en, "bahama sys_rst_n");
+ if (rc < 0) {
+ pr_err("%s: gpio_request %d = %d\n", __func__,
+ gpio_bt_sys_rest_en, rc);
+ goto reg_disable;
+ }
+
+ rc = bt_set_gpio(1);
+ if (rc < 0) {
+ pr_err("%s: bt_set_gpio %d = %d\n", __func__,
+ gpio_bt_sys_rest_en, rc);
+ goto gpio_fail;
+ }
+
+ return rc;
+
+gpio_fail:
+ gpio_free(gpio_bt_sys_rest_en);
+reg_disable:
+ regulator_disable(reg_s3);
+reg_fail:
+ regulator_put(reg_s3);
+out:
+ reg_s3 = NULL;
+ return rc;
+}
+
+static unsigned int msm_bahama_shutdown_power(int value)
+{
+ int rc = 0;
+
+ if (IS_ERR_OR_NULL(reg_s3)) {
+ rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
+ goto out;
+ }
+
+ rc = regulator_disable(reg_s3);
+ if (rc) {
+ pr_err("%s: could not disable regulator: %d\n", __func__, rc);
+ goto out;
+ }
+
+ if (value == BAHAMA_ID) {
+ rc = bt_set_gpio(0);
+ if (rc) {
+ pr_err("%s: bt_set_gpio = %d\n",
+ __func__, rc);
+ goto reg_enable;
+ }
+ gpio_free(gpio_bt_sys_rest_en);
+ }
+
+ regulator_put(reg_s3);
+ reg_s3 = NULL;
+
+ return 0;
+
+reg_enable:
+ regulator_enable(reg_s3);
+out:
+ return rc;
+}
+
+static unsigned int msm_bahama_core_config(int type)
+{
+ int rc = 0;
+
+ if (type == BAHAMA_ID) {
+ int i;
+ struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+ const struct bahama_config_register v20_init[] = {
+ /* reg, value, mask */
+ { 0xF4, 0x84, 0xFF }, /* AREG */
+ { 0xF0, 0x04, 0xFF } /* DREG */
+ };
+ if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
+ for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
+ u8 value = v20_init[i].value;
+ rc = marimba_write_bit_mask(&config,
+ v20_init[i].reg,
+ &value,
+ sizeof(v20_init[i].value),
+ v20_init[i].mask);
+ if (rc < 0) {
+ pr_err("%s: reg %d write failed: %d\n",
+ __func__, v20_init[i].reg, rc);
+ return rc;
+ }
+ pr_debug("%s: reg 0x%02x value 0x%02x"
+ " mask 0x%02x\n",
+ __func__, v20_init[i].reg,
+ v20_init[i].value, v20_init[i].mask);
+ }
+ }
+ }
+ rc = bt_set_gpio(0);
+ if (rc) {
+ pr_err("%s: bt_set_gpio = %d\n",
+ __func__, rc);
+ }
+ pr_debug("core type: %d\n", type);
+ return rc;
+}
+
+static int bluetooth_power(int on)
+{
+ int pin, rc = 0;
+ const char *id = "BTPW";
+ int cid = 0;
+
+ cid = adie_get_detected_connectivity_type();
+ if (cid != BAHAMA_ID) {
+ pr_err("%s: unexpected adie connectivity type: %d\n",
+ __func__, cid);
+ return -ENODEV;
+ }
+ if (on) {
+ /*setup power for BT SOC*/
+ rc = bt_set_gpio(on);
+ if (rc) {
+ pr_err("%s: bt_set_gpio = %d\n",
+ __func__, rc);
+ goto exit;
+ }
+ rc = bluetooth_switch_regulators(on);
+ if (rc < 0) {
+ pr_err("%s: bluetooth_switch_regulators rc = %d",
+ __func__, rc);
+ goto exit;
+ }
+ /*setup BT GPIO lines*/
+ for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
+ pin++) {
+ rc = gpio_tlmm_config(bt_config_power_on[pin],
+ GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__,
+ bt_config_power_on[pin],
+ rc);
+ goto fail_power;
+ }
+ }
+ /*Setup BT clocks*/
+ rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+ PMAPP_CLOCK_VOTE_ON);
+ if (rc < 0) {
+ pr_err("Failed to vote for TCXO_D1 ON\n");
+ goto fail_clock;
+ }
+ msleep(20);
+
+ /*I2C config for Bahama*/
+ rc = bahama_bt(1);
+ if (rc < 0) {
+ pr_err("%s: bahama_bt rc = %d", __func__, rc);
+ goto fail_i2c;
+ }
+ msleep(20);
+
+ /*setup BT PCM lines*/
+ rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
+ if (rc < 0) {
+ pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
+ __func__, rc);
+ goto fail_power;
+ }
+ rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+ PMAPP_CLOCK_VOTE_PIN_CTRL);
+ if (rc < 0)
+ pr_err("%s:Pin Control Failed, rc = %d",
+ __func__, rc);
+
+ } else {
+ rc = bahama_bt(0);
+ if (rc < 0)
+ pr_err("%s: bahama_bt rc = %d", __func__, rc);
+
+ rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
+ if (rc < 0) {
+ pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
+ __func__, rc);
+ }
+ rc = bt_set_gpio(on);
+ if (rc) {
+ pr_err("%s: bt_set_gpio = %d\n",
+ __func__, rc);
+ }
+fail_i2c:
+ rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+ PMAPP_CLOCK_VOTE_OFF);
+ if (rc < 0)
+ pr_err("%s: Failed to vote Off D1\n", __func__);
+fail_clock:
+ for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
+ pin++) {
+ rc = gpio_tlmm_config(bt_config_power_off[pin],
+ GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("%s:"
+ " gpio_tlmm_config(%#x)=%d\n",
+ __func__,
+ bt_config_power_off[pin], rc);
+ }
+ }
+fail_power:
+ rc = bluetooth_switch_regulators(0);
+ if (rc < 0) {
+ pr_err("%s: switch_regulators : rc = %d",\
+ __func__, rc);
+ goto exit;
+ }
+ }
+ return rc;
+exit:
+ pr_err("%s: failed with rc = %d", __func__, rc);
+ return rc;
+}
+
+static struct marimba_fm_platform_data marimba_fm_pdata = {
+ .fm_setup = fm_radio_setup,
+ .fm_shutdown = fm_radio_shutdown,
+ .irq = MSM_GPIO_TO_INT(FM_GPIO),
+ .vreg_s2 = NULL,
+ .vreg_xo_out = NULL,
+ /* Configuring the FM SoC as I2S Master */
+ .is_fm_soc_i2s_master = true,
+ .config_i2s_gpio = msm_bahama_setup_pcm_i2s,
+};
+
+static struct marimba_platform_data marimba_pdata = {
+ .slave_id[SLAVE_ID_BAHAMA_FM] = BAHAMA_SLAVE_ID_FM_ADDR,
+ .slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
+ .bahama_setup = msm_bahama_setup_power,
+ .bahama_shutdown = msm_bahama_shutdown_power,
+ .bahama_core_config = msm_bahama_core_config,
+ .fm = &marimba_fm_pdata,
+};
+
+static struct i2c_board_info bahama_devices[] = {
+{
+ I2C_BOARD_INFO("marimba", 0xc),
+ .platform_data = &marimba_pdata,
+},
+};
+
+void __init msm7627a_bt_power_init(void)
+{
+ int i, rc = 0;
+ struct device *dev;
+
+ gpio_bt_config();
+
+ i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+ bahama_devices,
+ ARRAY_SIZE(bahama_devices));
+ dev = &msm_bt_power_device.dev;
+
+ for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
+ bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
+ if (IS_ERR(bt_vregs[i].reg)) {
+ rc = PTR_ERR(bt_vregs[i].reg);
+ dev_err(dev, "%s: could not get regulator %s: %d\n",
+ __func__, bt_vregs[i].name, rc);
+ goto reg_get_fail;
+ }
+ }
+
+ dev->platform_data = &bluetooth_power;
+
+ return;
+
+reg_get_fail:
+ while (i--) {
+ regulator_put(bt_vregs[i].reg);
+ bt_vregs[i].reg = NULL;
+ }
+ return;
+}
+#endif
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index 6b22c71..4680a31 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -15,4 +15,41 @@
void __init msm7627a_init_mmc(void);
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+
+#define FPGA_MSM_CNTRL_REG2 0x90008010
+#define BAHAMA_SLAVE_ID_FM_REG 0x02
+#define BAHAMA_SLAVE_ID_FM_ADDR 0x2A
+#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR 0x7B
+#define FM_GPIO 83
+#define BT_PCM_BCLK_MODE 0x88
+#define BT_PCM_DIN_MODE 0x89
+#define BT_PCM_DOUT_MODE 0x8A
+#define BT_PCM_SYNC_MODE 0x8B
+#define FM_I2S_SD_MODE 0x8E
+#define FM_I2S_WS_MODE 0x8F
+#define FM_I2S_SCK_MODE 0x90
+#define I2C_PIN_CTL 0x15
+#define I2C_NORMAL 0x40
+
+struct bahama_config_register {
+ u8 reg;
+ u8 value;
+ u8 mask;
+};
+
+struct bt_vreg_info {
+ const char *name;
+ unsigned int pmapp_id;
+ unsigned int min_level;
+ unsigned int max_level;
+ unsigned int is_pin_controlled;
+ struct regulator *reg;
+};
+
+extern struct platform_device msm_bt_power_device;
+
+void __init msm7627a_bt_power_init(void);
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d8efcfe..53ea8c1 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -1626,8 +1626,8 @@
};
static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
- .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
- .v_addr = (uint32_t *)PAGE_OFFSET,
+ .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+ .p_addr = 0,
};
static void
@@ -1757,10 +1757,7 @@
}
}
#endif
- if (cpu_is_msm7x27())
- acpuclk_init(&acpuclk_7x27_soc_data);
- else
- acpuclk_init(&acpuclk_7201_soc_data);
+ acpuclk_init(&acpuclk_7x27_soc_data);
usb_mpp_init();
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index dcb12bb3..389b071 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -42,7 +42,6 @@
#include <linux/power_supply.h>
#include <linux/regulator/consumer.h>
#include <mach/rpc_pmapp.h>
-
#include <mach/msm_battery.h>
#include <linux/smsc911x.h>
#include <linux/atmel_maxtouch.h>
@@ -58,19 +57,6 @@
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x5B000
-#define BAHAMA_SLAVE_ID_FM_ADDR 0x2A
-#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR 0x7B
-#define BAHAMA_SLAVE_ID_FM_REG 0x02
-#define FM_GPIO 83
-#define BT_PCM_BCLK_MODE 0x88
-#define BT_PCM_DIN_MODE 0x89
-#define BT_PCM_DOUT_MODE 0x8A
-#define BT_PCM_SYNC_MODE 0x8B
-#define FM_I2S_SD_MODE 0x8E
-#define FM_I2S_WS_MODE 0x8F
-#define FM_I2S_SCK_MODE 0x90
-#define I2C_PIN_CTL 0x15
-#define I2C_NORMAL 0x40
enum {
GPIO_EXPANDER_IRQ_BASE = NR_MSM_IRQS + NR_GPIO_IRQS,
@@ -131,930 +117,12 @@
};
#endif
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-
- /* FM Platform power and shutdown routines */
-#define FPGA_MSM_CNTRL_REG2 0x90008010
-static int switch_pcm_i2s_reg_mode(int mode)
-{
- unsigned char reg = 0;
- int rc = -1;
- unsigned char set = I2C_PIN_CTL; /*SET PIN CTL mode*/
- unsigned char unset = I2C_NORMAL; /* UNSET PIN CTL MODE*/
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
-
- if (mode == 0) {
- /* as we need to switch path to FM we need to move
- BT AUX PCM lines to PIN CONTROL mode then move
- FM to normal mode.*/
- for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
- rc = marimba_write(&config, reg, &set, 1);
- if (rc < 0) {
- pr_err("pcm pinctl failed = %d", rc);
- goto err_all;
- }
- }
- for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
- rc = marimba_write(&config, reg, &unset, 1);
- if (rc < 0) {
- pr_err("i2s normal failed = %d", rc);
- goto err_all;
- }
- }
- } else {
- /* as we need to switch path to AUXPCM we need to move
- FM I2S lines to PIN CONTROL mode then move
- BT AUX_PCM to normal mode.*/
- for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
- rc = marimba_write(&config, reg, &set, 1);
- if (rc < 0) {
- pr_err("i2s pinctl failed = %d", rc);
- goto err_all;
- }
- }
- for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
- rc = marimba_write(&config, reg, &unset, 1);
- if (rc < 0) {
- pr_err("pcm normal failed = %d", rc);
- goto err_all;
- }
- }
- }
-
- return 0;
-
-err_all:
- return rc;
-}
-
-static void config_pcm_i2s_mode(int mode)
-{
- void __iomem *cfg_ptr;
- u8 reg2;
-
- cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
-
- if (!cfg_ptr)
- return;
- if (mode) {
- /*enable the pcm mode in FPGA*/
- reg2 = readb_relaxed(cfg_ptr);
- if (reg2 == 0) {
- reg2 = 1;
- writeb_relaxed(reg2, cfg_ptr);
- }
- } else {
- /*enable i2s mode in FPGA*/
- reg2 = readb_relaxed(cfg_ptr);
- if (reg2 == 1) {
- reg2 = 0;
- writeb_relaxed(reg2, cfg_ptr);
- }
- }
- iounmap(cfg_ptr);
-}
-
-static unsigned fm_i2s_config_power_on[] = {
- /*FM_I2S_SD*/
- GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*FM_I2S_WS*/
- GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*FM_I2S_SCK*/
- GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-
-static unsigned fm_i2s_config_power_off[] = {
- /*FM_I2S_SD*/
- GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*FM_I2S_WS*/
- GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*FM_I2S_SCK*/
- GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static unsigned bt_config_power_on[] = {
- /*RFR*/
- GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*CTS*/
- GPIO_CFG(44, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*RX*/
- GPIO_CFG(45, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*TX*/
- GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_on[] = {
- /*PCM_DOUT*/
- GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*PCM_DIN*/
- GPIO_CFG(69, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*PCM_SYNC*/
- GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*PCM_CLK*/
- GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_power_off[] = {
- /*RFR*/
- GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*CTS*/
- GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*RX*/
- GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*TX*/
- GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_off[] = {
- /*PCM_DOUT*/
- GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*PCM_DIN*/
- GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*PCM_SYNC*/
- GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*PCM_CLK*/
- GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static int config_i2s(int mode)
-{
- int pin, rc = 0;
-
- if (mode == FM_I2S_ON) {
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
- config_pcm_i2s_mode(0);
- pr_err("%s mode = FM_I2S_ON", __func__);
-
- rc = switch_pcm_i2s_reg_mode(0);
- if (rc) {
- pr_err("switch mode failed");
- return rc;
- }
- for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
- pin++) {
- rc = gpio_tlmm_config(
- fm_i2s_config_power_on[pin],
- GPIO_CFG_ENABLE
- );
- if (rc < 0)
- return rc;
- }
- } else if (mode == FM_I2S_OFF) {
- pr_err("%s mode = FM_I2S_OFF", __func__);
- rc = switch_pcm_i2s_reg_mode(1);
- if (rc) {
- pr_err("switch mode failed");
- return rc;
- }
- for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
- pin++) {
- rc = gpio_tlmm_config(
- fm_i2s_config_power_off[pin],
- GPIO_CFG_ENABLE
- );
- if (rc < 0)
- return rc;
- }
- }
- return rc;
-}
-static int config_pcm(int mode)
-{
- int pin, rc = 0;
-
- if (mode == BT_PCM_ON) {
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
- config_pcm_i2s_mode(1);
- pr_err("%s mode =BT_PCM_ON", __func__);
- rc = switch_pcm_i2s_reg_mode(1);
- if (rc) {
- pr_err("switch mode failed");
- return rc;
- }
- for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
- pin++) {
- rc = gpio_tlmm_config(bt_config_pcm_on[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0)
- return rc;
- }
- } else if (mode == BT_PCM_OFF) {
- pr_err("%s mode =BT_PCM_OFF", __func__);
- rc = switch_pcm_i2s_reg_mode(0);
- if (rc) {
- pr_err("switch mode failed");
- return rc;
- }
- for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
- pin++) {
- rc = gpio_tlmm_config(bt_config_pcm_off[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0)
- return rc;
- }
-
- }
-
- return rc;
-}
-
-static int msm_bahama_setup_pcm_i2s(int mode)
-{
- int fm_state = 0, bt_state = 0;
- int rc = 0;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
-
- fm_state = marimba_get_fm_status(&config);
- bt_state = marimba_get_bt_status(&config);
-
- switch (mode) {
- case BT_PCM_ON:
- case BT_PCM_OFF:
- if (!fm_state)
- rc = config_pcm(mode);
- break;
- case FM_I2S_ON:
- rc = config_i2s(mode);
- break;
- case FM_I2S_OFF:
- if (bt_state)
- rc = config_pcm(BT_PCM_ON);
- else
- rc = config_i2s(mode);
- break;
- default:
- rc = -EIO;
- pr_err("%s:Unsupported mode", __func__);
- }
- return rc;
-}
-
-static int bt_set_gpio(int on)
-{
- int rc = 0;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
-
- if (on) {
- rc = gpio_direction_output(GPIO_BT_SYS_REST_EN, 1);
- msleep(100);
- } else {
- if (!marimba_get_fm_status(&config) &&
- !marimba_get_bt_status(&config)) {
- gpio_set_value_cansleep(GPIO_BT_SYS_REST_EN, 0);
- rc = gpio_direction_input(GPIO_BT_SYS_REST_EN);
- msleep(100);
- }
- }
- if (rc)
- pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
-
- return rc;
-}
-static struct regulator *fm_regulator;
-static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
-{
- int rc = 0;
- const char *id = "FMPW";
- uint32_t irqcfg;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
- u8 value;
-
- /* Voting for 1.8V Regulator */
- fm_regulator = regulator_get(NULL, "msme1");
- if (IS_ERR(fm_regulator)) {
- rc = PTR_ERR(fm_regulator);
- pr_err("%s: could not get regulator: %d\n", __func__, rc);
- goto out;
- }
-
- /* Set the voltage level to 1.8V */
- rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
- if (rc < 0) {
- pr_err("%s: could not set voltage: %d\n", __func__, rc);
- goto reg_free;
- }
-
- /* Enabling the 1.8V regulator */
- rc = regulator_enable(fm_regulator);
- if (rc) {
- pr_err("%s: could not enable regulator: %d\n", __func__, rc);
- goto reg_free;
- }
-
- /* Voting for 19.2MHz clock */
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_ON);
- if (rc < 0) {
- pr_err("%s: clock vote failed with :(%d)\n",
- __func__, rc);
- goto reg_disable;
- }
-
- rc = bt_set_gpio(1);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d", __func__, rc);
- goto gpio_deconfig;
- }
- /*re-write FM Slave Id, after reset*/
- value = BAHAMA_SLAVE_ID_FM_ADDR;
- rc = marimba_write_bit_mask(&config,
- BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
- if (rc < 0) {
- pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
- goto gpio_deconfig;
- }
- /* Configuring the FM GPIO */
- irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_2MA);
-
- rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, irqcfg, rc);
- goto gpio_deconfig;
- }
-
- return 0;
-
-gpio_deconfig:
- pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_OFF);
- bt_set_gpio(0);
-reg_disable:
- regulator_disable(fm_regulator);
-reg_free:
- regulator_put(fm_regulator);
- fm_regulator = NULL;
-out:
- return rc;
-};
-
-static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
-{
- int rc;
- const char *id = "FMPW";
-
- /* Releasing the GPIO line used by FM */
- uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_2MA);
-
- rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
- if (rc)
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, irqcfg, rc);
-
- /* Releasing the 1.8V Regulator */
- if (!IS_ERR_OR_NULL(fm_regulator)) {
- rc = regulator_disable(fm_regulator);
- if (rc)
- pr_err("%s: could not disable regulator: %d\n",
- __func__, rc);
- regulator_put(fm_regulator);
- fm_regulator = NULL;
- }
-
- /* Voting off the clock */
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_OFF);
- if (rc < 0)
- pr_err("%s: voting off failed with :(%d)\n",
- __func__, rc);
- rc = bt_set_gpio(0);
- if (rc)
- pr_err("%s: bt_set_gpio = %d", __func__, rc);
-}
-
-static struct marimba_fm_platform_data marimba_fm_pdata = {
- .fm_setup = fm_radio_setup,
- .fm_shutdown = fm_radio_shutdown,
- .irq = MSM_GPIO_TO_INT(FM_GPIO),
- .vreg_s2 = NULL,
- .vreg_xo_out = NULL,
- /* Configuring the FM SoC as I2S Master */
- .is_fm_soc_i2s_master = true,
- .config_i2s_gpio = msm_bahama_setup_pcm_i2s,
-};
static struct platform_device msm_wlan_ar6000_pm_device = {
.name = "wlan_ar6000_pm_dev",
.id = -1,
};
-static struct platform_device msm_bt_power_device = {
- .name = "bt_power",
-};
-struct bahama_config_register {
- u8 reg;
- u8 value;
- u8 mask;
-};
-struct bt_vreg_info {
- const char *name;
- unsigned int pmapp_id;
- unsigned int min_level;
- unsigned int max_level;
- unsigned int is_pin_controlled;
- struct regulator *reg;
-};
-static struct bt_vreg_info bt_vregs[] = {
- {"msme1", 2, 1800000, 1800000, 0, NULL},
- {"bt", 21, 2900000, 3300000, 1, NULL}
-};
-
-static int bahama_bt(int on)
-{
- int rc = 0;
- int i;
-
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
-
- struct bahama_variant_register {
- const size_t size;
- const struct bahama_config_register *set;
- };
-
- const struct bahama_config_register *p;
-
- u8 version;
-
- const struct bahama_config_register v10_bt_on[] = {
- { 0xE9, 0x00, 0xFF },
- { 0xF4, 0x80, 0xFF },
- { 0xE4, 0x00, 0xFF },
- { 0xE5, 0x00, 0x0F },
-#ifdef CONFIG_WLAN
- { 0xE6, 0x38, 0x7F },
- { 0xE7, 0x06, 0xFF },
-#endif
- { 0xE9, 0x21, 0xFF },
- { 0x01, 0x0C, 0x1F },
- { 0x01, 0x08, 0x1F },
- };
-
- const struct bahama_config_register v20_bt_on_fm_off[] = {
- { 0x11, 0x0C, 0xFF },
- { 0x13, 0x01, 0xFF },
- { 0xF4, 0x80, 0xFF },
- { 0xF0, 0x00, 0xFF },
- { 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
- { 0x81, 0x00, 0x7F },
- { 0x82, 0x00, 0xFF },
- { 0xE6, 0x38, 0x7F },
- { 0xE7, 0x06, 0xFF },
-#endif
- { 0x8E, 0x15, 0xFF },
- { 0x8F, 0x15, 0xFF },
- { 0x90, 0x15, 0xFF },
-
- { 0xE9, 0x21, 0xFF },
- };
-
- const struct bahama_config_register v20_bt_on_fm_on[] = {
- { 0x11, 0x0C, 0xFF },
- { 0x13, 0x01, 0xFF },
- { 0xF4, 0x86, 0xFF },
- { 0xF0, 0x06, 0xFF },
- { 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
- { 0x81, 0x00, 0x7F },
- { 0x82, 0x00, 0xFF },
- { 0xE6, 0x38, 0x7F },
- { 0xE7, 0x06, 0xFF },
-#endif
- { 0xE9, 0x21, 0xFF },
- };
-
- const struct bahama_config_register v10_bt_off[] = {
- { 0xE9, 0x00, 0xFF },
- };
-
- const struct bahama_config_register v20_bt_off_fm_off[] = {
- { 0xF4, 0x84, 0xFF },
- { 0xF0, 0x04, 0xFF },
- { 0xE9, 0x00, 0xFF }
- };
-
- const struct bahama_config_register v20_bt_off_fm_on[] = {
- { 0xF4, 0x86, 0xFF },
- { 0xF0, 0x06, 0xFF },
- { 0xE9, 0x00, 0xFF }
- };
- const struct bahama_variant_register bt_bahama[2][3] = {
- {
- { ARRAY_SIZE(v10_bt_off), v10_bt_off },
- { ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
- { ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
- },
- {
- { ARRAY_SIZE(v10_bt_on), v10_bt_on },
- { ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
- { ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
- }
- };
-
- u8 offset = 0; /* index into bahama configs */
- on = on ? 1 : 0;
- version = marimba_read_bahama_ver(&config);
- if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
- dev_err(&msm_bt_power_device.dev, "%s: Bahama \
- version read Error, version = %d \n",
- __func__, version);
- return -EIO;
- }
-
- if (version == BAHAMA_VER_2_0) {
- if (marimba_get_fm_status(&config))
- offset = 0x01;
- }
-
- p = bt_bahama[on][version + offset].set;
-
- dev_info(&msm_bt_power_device.dev,
- "%s: found version %d\n", __func__, version);
-
- for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
- u8 value = (p+i)->value;
- rc = marimba_write_bit_mask(&config,
- (p+i)->reg,
- &value,
- sizeof((p+i)->value),
- (p+i)->mask);
- if (rc < 0) {
- dev_err(&msm_bt_power_device.dev,
- "%s: reg %x write failed: %d\n",
- __func__, (p+i)->reg, rc);
- return rc;
- }
- dev_dbg(&msm_bt_power_device.dev,
- "%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
- __func__, (p+i)->reg,
- value, (p+i)->mask);
- value = 0;
- rc = marimba_read_bit_mask(&config,
- (p+i)->reg, &value,
- sizeof((p+i)->value), (p+i)->mask);
- if (rc < 0)
- dev_err(&msm_bt_power_device.dev, "%s marimba_read_bit_mask- error",
- __func__);
- dev_dbg(&msm_bt_power_device.dev,
- "%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
- __func__, (p+i)->reg,
- value, (p+i)->mask);
- }
- /* Update BT Status */
- if (on)
- marimba_set_bt_status(&config, true);
- else
- marimba_set_bt_status(&config, false);
- return rc;
-}
-static int bluetooth_switch_regulators(int on)
-{
- int i, rc = 0;
- const char *id = "BTPW";
-
- for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
- if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
- rc = bt_vregs[i].reg ?
- PTR_ERR(bt_vregs[i].reg) :
- -ENODEV;
- dev_err(&msm_bt_power_device.dev,
- "%s: invalid regulator handle for %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto reg_disable;
- }
-
- rc = on ? regulator_set_voltage(bt_vregs[i].reg,
- bt_vregs[i].min_level,
- bt_vregs[i].max_level) : 0;
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: could not set voltage for %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto reg_disable;
- }
-
- rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: could not %sable regulator %s: %d\n",
- __func__, "en", bt_vregs[i].name, rc);
- goto reg_disable;
- }
-
- if (bt_vregs[i].is_pin_controlled) {
- rc = pmapp_vreg_lpm_pincntrl_vote(id,
- bt_vregs[i].pmapp_id,
- PMAPP_CLOCK_ID_D1,
- on ? PMAPP_CLOCK_VOTE_ON :
- PMAPP_CLOCK_VOTE_OFF);
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: pin control failed for %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto pin_cnt_fail;
- }
- }
- rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
-
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: could not %sable regulator %s: %d\n",
- __func__, "dis", bt_vregs[i].name, rc);
- goto reg_disable;
- }
- }
-
- return rc;
-pin_cnt_fail:
- if (on)
- regulator_disable(bt_vregs[i].reg);
-reg_disable:
- while (i) {
- if (on) {
- i--;
- regulator_disable(bt_vregs[i].reg);
- regulator_put(bt_vregs[i].reg);
- }
- }
- return rc;
-}
-
-static struct regulator *reg_s3;
-static unsigned int msm_bahama_setup_power(void)
-{
- int rc = 0;
-
- reg_s3 = regulator_get(NULL, "msme1");
- if (IS_ERR(reg_s3)) {
- rc = PTR_ERR(reg_s3);
- pr_err("%s: could not get regulator: %d\n", __func__, rc);
- goto out;
- }
-
- rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
- if (rc) {
- pr_err("%s: could not set voltage: %d\n", __func__, rc);
- goto reg_fail;
- }
-
- rc = regulator_enable(reg_s3);
- if (rc < 0) {
- pr_err("%s: could not enable regulator: %d\n", __func__, rc);
- goto reg_fail;
- }
-
- /*setup Bahama_sys_reset_n*/
- rc = gpio_request(GPIO_BT_SYS_REST_EN, "bahama sys_rst_n");
- if (rc) {
- pr_err("%s: gpio_request %d = %d\n", __func__,
- GPIO_BT_SYS_REST_EN, rc);
- goto reg_disable;
- }
-
- rc = bt_set_gpio(1);
- if (rc) {
- pr_err("%s: bt_set_gpio %d = %d\n", __func__,
- GPIO_BT_SYS_REST_EN, rc);
- goto gpio_fail;
- }
-
- return rc;
-
-gpio_fail:
- gpio_free(GPIO_BT_SYS_REST_EN);
-reg_disable:
- regulator_disable(reg_s3);
-reg_fail:
- regulator_put(reg_s3);
-out:
- reg_s3 = NULL;
- return rc;
-}
-
-static unsigned int msm_bahama_shutdown_power(int value)
-{
- int rc = 0;
-
- if (IS_ERR_OR_NULL(reg_s3)) {
- rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
- goto out;
- }
-
- rc = regulator_disable(reg_s3);
- if (rc) {
- pr_err("%s: could not disable regulator: %d\n", __func__, rc);
- goto out;
- }
-
- if (value == BAHAMA_ID) {
- rc = bt_set_gpio(0);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- }
- gpio_free(GPIO_BT_SYS_REST_EN);
- }
-
- regulator_put(reg_s3);
- reg_s3 = NULL;
-
- return 0;
-
-out:
- return rc;
-}
-
-static unsigned int msm_bahama_core_config(int type)
-{
- int rc = 0;
-
- if (type == BAHAMA_ID) {
- int i;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
- const struct bahama_config_register v20_init[] = {
- /* reg, value, mask */
- { 0xF4, 0x84, 0xFF }, /* AREG */
- { 0xF0, 0x04, 0xFF } /* DREG */
- };
- if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
- for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
- u8 value = v20_init[i].value;
- rc = marimba_write_bit_mask(&config,
- v20_init[i].reg,
- &value,
- sizeof(v20_init[i].value),
- v20_init[i].mask);
- if (rc < 0) {
- pr_err("%s: reg %d write failed: %d\n",
- __func__, v20_init[i].reg, rc);
- return rc;
- }
- pr_debug("%s: reg 0x%02x value 0x%02x"
- " mask 0x%02x\n",
- __func__, v20_init[i].reg,
- v20_init[i].value, v20_init[i].mask);
- }
- }
- }
- rc = bt_set_gpio(0);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- }
- pr_debug("core type: %d\n", type);
- return rc;
-}
-
-static int bluetooth_power(int on)
-{
- int pin, rc = 0;
- const char *id = "BTPW";
- int cid = 0;
-
- cid = adie_get_detected_connectivity_type();
- if (cid != BAHAMA_ID) {
- pr_err("%s: unexpected adie connectivity type: %d\n",
- __func__, cid);
- return -ENODEV;
- }
- if (on) {
- /*setup power for BT SOC*/
- rc = bt_set_gpio(on);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- goto exit;
- }
- rc = bluetooth_switch_regulators(on);
- if (rc < 0) {
- pr_err("%s: bluetooth_switch_regulators rc = %d",
- __func__, rc);
- goto exit;
- }
- /*setup BT GPIO lines*/
- for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
- pin++) {
- rc = gpio_tlmm_config(bt_config_power_on[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__,
- bt_config_power_on[pin],
- rc);
- goto fail_power;
- }
- }
- /*Setup BT clocks*/
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_ON);
- if (rc < 0) {
- pr_err("Failed to vote for TCXO_D1 ON\n");
- goto fail_clock;
- }
- msleep(20);
-
- /*I2C config for Bahama*/
- rc = bahama_bt(1);
- if (rc < 0) {
- pr_err("%s: bahama_bt rc = %d", __func__, rc);
- goto fail_i2c;
- }
- msleep(20);
-
- /*setup BT PCM lines*/
- rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
- if (rc < 0) {
- pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
- __func__, rc);
- goto fail_power;
- }
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_PIN_CTRL);
- if (rc < 0)
- pr_err("%s:Pin Control Failed, rc = %d",
- __func__, rc);
-
- } else {
- rc = bahama_bt(0);
- if (rc < 0)
- pr_err("%s: bahama_bt rc = %d", __func__, rc);
-
- rc = bt_set_gpio(on);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- }
-fail_i2c:
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_OFF);
- if (rc < 0)
- pr_err("%s: Failed to vote Off D1\n", __func__);
-fail_clock:
- for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
- pin++) {
- rc = gpio_tlmm_config(bt_config_power_off[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, bt_config_power_off[pin], rc);
- }
- }
- rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
- if (rc < 0) {
- pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
- __func__, rc);
- }
-fail_power:
- rc = bluetooth_switch_regulators(0);
- if (rc < 0) {
- pr_err("%s: switch_regulators : rc = %d",\
- __func__, rc);
- goto exit;
- }
- }
- return rc;
-exit:
- pr_err("%s: failed with rc = %d", __func__, rc);
- return rc;
-}
-
-static int __init bt_power_init(void)
-{
- int i, rc = 0;
- struct device *dev = &msm_bt_power_device.dev;
-
- for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
- bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
- if (IS_ERR(bt_vregs[i].reg)) {
- rc = PTR_ERR(bt_vregs[i].reg);
- dev_err(dev, "%s: could not get regulator %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto reg_get_fail;
- }
- }
-
- dev->platform_data = &bluetooth_power;
-
- return rc;
-
-reg_get_fail:
- while (i--) {
- regulator_put(bt_vregs[i].reg);
- bt_vregs[i].reg = NULL;
- }
- return rc;
-}
-
-static struct marimba_platform_data marimba_pdata = {
- .slave_id[SLAVE_ID_BAHAMA_FM] = BAHAMA_SLAVE_ID_FM_ADDR,
- .slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
- .bahama_setup = msm_bahama_setup_power,
- .bahama_shutdown = msm_bahama_shutdown_power,
- .bahama_core_config = msm_bahama_core_config,
- .fm = &marimba_fm_pdata,
-};
-
-#endif
-
#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
static struct i2c_board_info core_exp_i2c_info[] __initdata = {
{
@@ -1068,14 +136,6 @@
},
};
#endif
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-static struct i2c_board_info bahama_devices[] = {
-{
- I2C_BOARD_INFO("marimba", 0xc),
- .platform_data = &marimba_pdata,
-},
-};
-#endif
#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
static void __init register_i2c_devices(void)
@@ -1094,11 +154,6 @@
i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
core_exp_i2c_info,
ARRAY_SIZE(core_exp_i2c_info));
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
- i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- bahama_devices,
- ARRAY_SIZE(bahama_devices));
-#endif
}
#endif
@@ -1163,7 +218,7 @@
#define MSM7x25A_MSM_FB_SIZE 0xE1000
#else
#define MSM_FB_SIZE 0x195000
-#define MSM7x25A_MSM_FB_SIZE 0xE1000
+#define MSM7x25A_MSM_FB_SIZE 0x96000
#endif
@@ -1366,8 +421,8 @@
};
static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
- .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
- .v_addr = (uint32_t *)PAGE_OFFSET,
+ .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+ .p_addr = 0,
};
static struct android_pmem_platform_data android_pmem_adsp_pdata = {
@@ -2959,7 +2014,7 @@
register_i2c_devices();
#endif
#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
- bt_power_init();
+ msm7627a_bt_power_init();
#endif
if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
atmel_ts_pdata.min_x = 0;
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 857c88a..883404f 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -3862,6 +3862,8 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ /* Bus Scaling declaration*/
+ .bus_scale_table = NULL,
};
static struct platform_device qcrypto_device = {
@@ -3884,6 +3886,8 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ /* Bus Scaling declaration*/
+ .bus_scale_table = NULL,
};
static struct platform_device qcedev_device = {
.name = "qce",
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 75c1b80..ba7e658 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -53,6 +53,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/setup.h>
+#include <asm/hardware/gic.h>
#include <mach/dma.h>
#include <mach/board.h>
@@ -602,6 +603,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
static struct platform_device qcrypto_device = {
@@ -624,6 +626,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
static struct platform_device qcedev_device = {
@@ -2627,23 +2630,12 @@
#define MSM_FB_EXT_BUFT_SIZE 0
#endif
-#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
-/* width x height x 3 bpp x 2 frame buffer */
-#define MSM_FB_WRITEBACK_SIZE (1024 * 600 * 3 * 2)
-#define MSM_FB_WRITEBACK_OFFSET \
- (MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
-#else
-#define MSM_FB_WRITEBACK_SIZE 0
-#define MSM_FB_WRITEBACK_OFFSET 0
-#endif
-
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
/* 4 bpp x 2 page HDMI case */
#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
#else
/* Note: must be multiple of 4096 */
#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
- MSM_FB_WRITEBACK_SIZE + \
MSM_FB_DSUB_PMEM_ADDER, 4096)
#endif
@@ -2653,10 +2645,17 @@
#define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
#endif
-static int writeback_offset(void)
-{
- return MSM_FB_WRITEBACK_OFFSET;
-}
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
+#endif /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
+
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x600000
#define MSM_PMEM_ADSP_SIZE 0x2000000
@@ -2861,36 +2860,39 @@
}, \
.num_paths = 1, \
}
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct msm_bus_paths pmem_smi_table[] = {
+
+static struct msm_bus_paths mem_smi_table[] = {
[0] = PMEM_BUS_WIDTH(0), /* Off */
[1] = PMEM_BUS_WIDTH(1), /* On */
};
static struct msm_bus_scale_pdata smi_client_pdata = {
- .usecase = pmem_smi_table,
- .num_usecases = ARRAY_SIZE(pmem_smi_table),
- .name = "pmem_smi",
+ .usecase = mem_smi_table,
+ .num_usecases = ARRAY_SIZE(mem_smi_table),
+ .name = "mem_smi",
};
-void request_smi_region(void *data)
+int request_smi_region(void *data)
{
int bus_id = (int) data;
msm_bus_scale_client_update_request(bus_id, 1);
+ return 0;
}
-void release_smi_region(void *data)
+int release_smi_region(void *data)
{
int bus_id = (int) data;
msm_bus_scale_client_update_request(bus_id, 0);
+ return 0;
}
void *setup_smi_region(void)
{
return (void *)msm_bus_scale_register_client(&smi_client_pdata);
}
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct android_pmem_platform_data android_pmem_smipool_pdata = {
.name = "pmem_smipool",
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -5087,6 +5089,8 @@
&msm_device_smd,
&msm_device_uart_dm12,
&msm_pil_q6v3,
+ &msm_pil_modem,
+ &msm_pil_tzapps,
#ifdef CONFIG_I2C_QUP
&msm_gsbi3_qup_i2c_device,
&msm_gsbi4_qup_i2c_device,
@@ -5268,6 +5272,9 @@
.name = ION_SMI_HEAP_NAME,
.size = MSM_ION_SMI_SIZE,
.memory_type = ION_SMI_TYPE,
+ .request_region = request_smi_region,
+ .release_region = release_smi_region,
+ .setup_region = setup_smi_region,
},
#endif
}
@@ -5347,13 +5354,14 @@
#endif
}
-
+static void __init reserve_mdp_memory(void);
static void __init msm8x60_calculate_reserve_sizes(void)
{
size_pmem_devices();
reserve_pmem_memory();
reserve_ion_memory();
+ reserve_mdp_memory();
}
static int msm8x60_paddr_to_memtype(unsigned int paddr)
@@ -9421,9 +9429,21 @@
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
.mdp_rev = MDP_REV_41,
- .writeback_offset = writeback_offset,
+ .mdp_writeback_memtype = MEMTYPE_EBI1,
+ .mdp_writeback_phys = NULL,
};
+static void __init reserve_mdp_memory(void)
+{
+ mdp_pdata.mdp_writeback_size_ov0 = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+ mdp_pdata.mdp_writeback_size_ov1 = MSM_FB_OVERLAY1_WRITEBACK_SIZE;
+
+ msm8x60_reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+ mdp_pdata.mdp_writeback_size_ov0;
+ msm8x60_reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+ mdp_pdata.mdp_writeback_size_ov1;
+}
+
#ifdef CONFIG_FB_MSM_TVOUT
#ifdef CONFIG_MSM_BUS_SCALING
@@ -10259,6 +10279,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_rumi3_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
@@ -10268,6 +10289,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_sim_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
@@ -10277,6 +10299,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_surf_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
@@ -10286,6 +10309,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_ffa_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
@@ -10295,6 +10319,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_fluid_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
@@ -10304,6 +10329,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_charm_surf_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
@@ -10313,6 +10339,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_charm_ffa_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
@@ -10322,6 +10349,7 @@
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
+ .handle_irq = gic_handle_irq,
.init_machine = msm8x60_dragon_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 889ac00..08ec05e 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -56,10 +56,17 @@
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x5B000
-#define BAHAMA_SLAVE_ID_FM_ADDR 0x2A
-#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR 0x7B
#define BAHAMA_SLAVE_ID_FM_REG 0x02
#define FM_GPIO 83
+#define BT_PCM_BCLK_MODE 0x88
+#define BT_PCM_DIN_MODE 0x89
+#define BT_PCM_DOUT_MODE 0x8A
+#define BT_PCM_SYNC_MODE 0x8B
+#define FM_I2S_SD_MODE 0x8E
+#define FM_I2S_WS_MODE 0x8F
+#define FM_I2S_SCK_MODE 0x90
+#define I2C_PIN_CTL 0x15
+#define I2C_NORMAL 0x40
enum {
GPIO_HOST_VBUS_EN = 107,
@@ -75,877 +82,11 @@
GPIO_CAM_GP_CAMIF_RESET,
};
- /* FM Platform power and shutdown routines */
-#define FPGA_MSM_CNTRL_REG2 0x90008010
-
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-static void config_pcm_i2s_mode(int mode)
-{
- void __iomem *cfg_ptr;
- u8 reg2;
-
- cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
-
- if (!cfg_ptr)
- return;
- if (mode) {
- /*enable the pcm mode in FPGA*/
- reg2 = readb_relaxed(cfg_ptr);
- if (reg2 == 0) {
- reg2 = 1;
- writeb_relaxed(reg2, cfg_ptr);
- }
- } else {
- /*enable i2s mode in FPGA*/
- reg2 = readb_relaxed(cfg_ptr);
- if (reg2 == 1) {
- reg2 = 0;
- writeb_relaxed(reg2, cfg_ptr);
- }
- }
- iounmap(cfg_ptr);
-}
-
-static unsigned fm_i2s_config_power_on[] = {
- /*FM_I2S_SD*/
- GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*FM_I2S_WS*/
- GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*FM_I2S_SCK*/
- GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-
-static unsigned fm_i2s_config_power_off[] = {
- /*FM_I2S_SD*/
- GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*FM_I2S_WS*/
- GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*FM_I2S_SCK*/
- GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static unsigned bt_config_power_on[] = {
- /*RFR*/
- GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*CTS*/
- GPIO_CFG(44, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*RX*/
- GPIO_CFG(45, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*TX*/
- GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_on[] = {
- /*PCM_DOUT*/
- GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*PCM_DIN*/
- GPIO_CFG(69, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*PCM_SYNC*/
- GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- /*PCM_CLK*/
- GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_power_off[] = {
- /*RFR*/
- GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*CTS*/
- GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*RX*/
- GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*TX*/
- GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_off[] = {
- /*PCM_DOUT*/
- GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*PCM_DIN*/
- GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*PCM_SYNC*/
- GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- /*PCM_CLK*/
- GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-
-static int config_i2s(int mode)
-{
- int pin, rc = 0;
-
- if (mode == FM_I2S_ON) {
- if (machine_is_msm7627a_qrd1())
- config_pcm_i2s_mode(0);
- pr_err("%s mode = FM_I2S_ON", __func__);
- for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
- pin++) {
- rc = gpio_tlmm_config(
- fm_i2s_config_power_on[pin],
- GPIO_CFG_ENABLE
- );
- if (rc < 0)
- return rc;
- }
- } else if (mode == FM_I2S_OFF) {
- pr_err("%s mode = FM_I2S_OFF", __func__);
- for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
- pin++) {
- rc = gpio_tlmm_config(
- fm_i2s_config_power_off[pin],
- GPIO_CFG_ENABLE
- );
- if (rc < 0)
- return rc;
- }
- }
- return rc;
-}
-static int config_pcm(int mode)
-{
- int pin, rc = 0;
-
- if (mode == BT_PCM_ON) {
- if (machine_is_msm7627a_qrd1())
- config_pcm_i2s_mode(1);
- pr_err("%s mode =BT_PCM_ON", __func__);
- for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
- pin++) {
- rc = gpio_tlmm_config(bt_config_pcm_on[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0)
- return rc;
- }
- } else if (mode == BT_PCM_OFF) {
- pr_err("%s mode =BT_PCM_OFF", __func__);
- for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
- pin++) {
- rc = gpio_tlmm_config(bt_config_pcm_off[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0)
- return rc;
- }
-
- }
-
- return rc;
-}
-
-static int msm_bahama_setup_pcm_i2s(int mode)
-{
- int fm_state = 0, bt_state = 0;
- int rc = 0;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
-
- fm_state = marimba_get_fm_status(&config);
- bt_state = marimba_get_bt_status(&config);
-
- switch (mode) {
- case BT_PCM_ON:
- case BT_PCM_OFF:
- if (!fm_state)
- rc = config_pcm(mode);
- break;
- case FM_I2S_ON:
- rc = config_i2s(mode);
- break;
- case FM_I2S_OFF:
- if (bt_state)
- rc = config_pcm(BT_PCM_ON);
- else
- rc = config_i2s(mode);
- break;
- default:
- rc = -EIO;
- pr_err("%s:Unsupported mode", __func__);
- }
- return rc;
-}
-
-static int bt_set_gpio(int on)
-{
- int rc = 0;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
-
- if (on) {
- rc = gpio_direction_output(GPIO_BT_SYS_REST_EN, 1);
- msleep(100);
- } else {
- if (!marimba_get_fm_status(&config) &&
- !marimba_get_bt_status(&config)) {
- gpio_set_value_cansleep(GPIO_BT_SYS_REST_EN, 0);
- rc = gpio_direction_input(GPIO_BT_SYS_REST_EN);
- msleep(100);
- }
- }
- if (rc)
- pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
-
- return rc;
-}
-static struct regulator *fm_regulator;
-static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
-{
- int rc = 0;
- const char *id = "FMPW";
- uint32_t irqcfg;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
- u8 value;
-
- /* Voting for 1.8V Regulator */
- fm_regulator = regulator_get(NULL , "msme1");
- if (IS_ERR(fm_regulator)) {
- rc = PTR_ERR(fm_regulator);
- pr_err("%s: could not get regulator: %d\n", __func__, rc);
- goto out;
- }
-
- /* Set the voltage level to 1.8V */
- rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
- if (rc < 0) {
- pr_err("%s: could not set voltage: %d\n", __func__, rc);
- goto reg_free;
- }
-
- /* Enabling the 1.8V regulator */
- rc = regulator_enable(fm_regulator);
- if (rc) {
- pr_err("%s: could not enable regulator: %d\n", __func__, rc);
- goto reg_free;
- }
-
- /* Voting for 19.2MHz clock */
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_ON);
- if (rc < 0) {
- pr_err("%s: clock vote failed with :(%d)\n",
- __func__, rc);
- goto reg_disable;
- }
-
- rc = bt_set_gpio(1);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d", __func__, rc);
- goto gpio_deconfig;
- }
- /*re-write FM Slave Id, after reset*/
- value = BAHAMA_SLAVE_ID_FM_ADDR;
- rc = marimba_write_bit_mask(&config,
- BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
- if (rc < 0) {
- pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
- goto gpio_deconfig;
- }
- /* Configuring the FM GPIO */
- irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_2MA);
-
- rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, irqcfg, rc);
- goto gpio_deconfig;
- }
-
- return 0;
-
-gpio_deconfig:
- pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_OFF);
- bt_set_gpio(0);
-reg_disable:
- regulator_disable(fm_regulator);
-reg_free:
- regulator_put(fm_regulator);
- fm_regulator = NULL;
-out:
- return rc;
-};
-
-static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
-{
- int rc;
- const char *id = "FMPW";
-
- /* Releasing the GPIO line used by FM */
- uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_2MA);
-
- rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
- if (rc)
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, irqcfg, rc);
-
- /* Releasing the 1.8V Regulator */
- if (!IS_ERR_OR_NULL(fm_regulator)) {
- rc = regulator_disable(fm_regulator);
- if (rc)
- pr_err("%s: could not disable regulator: %d\n",
- __func__, rc);
- regulator_put(fm_regulator);
- fm_regulator = NULL;
- }
-
- /* Voting off the clock */
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_OFF);
- if (rc < 0)
- pr_err("%s: voting off failed with :(%d)\n",
- __func__, rc);
- rc = bt_set_gpio(0);
- if (rc)
- pr_err("%s: bt_set_gpio = %d", __func__, rc);
-}
-
-static struct marimba_fm_platform_data marimba_fm_pdata = {
- .fm_setup = fm_radio_setup,
- .fm_shutdown = fm_radio_shutdown,
- .irq = MSM_GPIO_TO_INT(FM_GPIO),
- .vreg_s2 = NULL,
- .vreg_xo_out = NULL,
- /* Configuring the FM SoC as I2S Master */
- .is_fm_soc_i2s_master = true,
- .config_i2s_gpio = msm_bahama_setup_pcm_i2s,
-};
-#endif
-
static struct platform_device msm_wlan_ar6000_pm_device = {
.name = "wlan_ar6000_pm_dev",
.id = -1,
};
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-
-static struct platform_device msm_bt_power_device = {
- .name = "bt_power",
-};
-struct bahama_config_register {
- u8 reg;
- u8 value;
- u8 mask;
-};
-struct bt_vreg_info {
- const char *name;
- unsigned int pmapp_id;
- unsigned int min_level;
- unsigned int max_level;
- unsigned int is_pin_controlled;
- struct regulator *reg;
-};
-static struct bt_vreg_info bt_vregs[] = {
- {"msme1", 2, 1800000, 1800000, 0, NULL},
- {"bt", 21, 2900000, 3050000, 1, NULL}
-};
-
-static int bahama_bt(int on)
-{
- int rc = 0;
- int i;
-
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
-
- struct bahama_variant_register {
- const size_t size;
- const struct bahama_config_register *set;
- };
-
- const struct bahama_config_register *p;
-
- u8 version;
-
- const struct bahama_config_register v10_bt_on[] = {
- { 0xE9, 0x00, 0xFF },
- { 0xF4, 0x80, 0xFF },
- { 0xE4, 0x00, 0xFF },
- { 0xE5, 0x00, 0x0F },
-#ifdef CONFIG_WLAN
- { 0xE6, 0x38, 0x7F },
- { 0xE7, 0x06, 0xFF },
-#endif
- { 0xE9, 0x21, 0xFF },
- { 0x01, 0x0C, 0x1F },
- { 0x01, 0x08, 0x1F },
- };
-
- const struct bahama_config_register v20_bt_on_fm_off[] = {
- { 0x11, 0x0C, 0xFF },
- { 0x13, 0x01, 0xFF },
- { 0xF4, 0x80, 0xFF },
- { 0xF0, 0x00, 0xFF },
- { 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
- { 0x81, 0x00, 0x7F },
- { 0x82, 0x00, 0xFF },
- { 0xE6, 0x38, 0x7F },
- { 0xE7, 0x06, 0xFF },
-#endif
- { 0x8E, 0x15, 0xFF },
- { 0x8F, 0x15, 0xFF },
- { 0x90, 0x15, 0xFF },
-
- { 0xE9, 0x21, 0xFF },
- };
-
- const struct bahama_config_register v20_bt_on_fm_on[] = {
- { 0x11, 0x0C, 0xFF },
- { 0x13, 0x01, 0xFF },
- { 0xF4, 0x86, 0xFF },
- { 0xF0, 0x06, 0xFF },
- { 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
- { 0x81, 0x00, 0x7F },
- { 0x82, 0x00, 0xFF },
- { 0xE6, 0x38, 0x7F },
- { 0xE7, 0x06, 0xFF },
-#endif
- { 0xE9, 0x21, 0xFF },
- };
-
- const struct bahama_config_register v10_bt_off[] = {
- { 0xE9, 0x00, 0xFF },
- };
-
- const struct bahama_config_register v20_bt_off_fm_off[] = {
- { 0xF4, 0x84, 0xFF },
- { 0xF0, 0x04, 0xFF },
- { 0xE9, 0x00, 0xFF }
- };
-
- const struct bahama_config_register v20_bt_off_fm_on[] = {
- { 0xF4, 0x86, 0xFF },
- { 0xF0, 0x06, 0xFF },
- { 0xE9, 0x00, 0xFF }
- };
- const struct bahama_variant_register bt_bahama[2][3] = {
- {
- { ARRAY_SIZE(v10_bt_off), v10_bt_off },
- { ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
- { ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
- },
- {
- { ARRAY_SIZE(v10_bt_on), v10_bt_on },
- { ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
- { ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
- }
- };
-
- u8 offset = 0; /* index into bahama configs */
- on = on ? 1 : 0;
- version = marimba_read_bahama_ver(&config);
- if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
- dev_err(&msm_bt_power_device.dev, "%s: Bahama \
- version read Error, version = %d \n",
- __func__, version);
- return -EIO;
- }
-
- if (version == BAHAMA_VER_2_0) {
- if (marimba_get_fm_status(&config))
- offset = 0x01;
- }
-
- p = bt_bahama[on][version + offset].set;
-
- dev_info(&msm_bt_power_device.dev,
- "%s: found version %d\n", __func__, version);
-
- for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
- u8 value = (p+i)->value;
- rc = marimba_write_bit_mask(&config,
- (p+i)->reg,
- &value,
- sizeof((p+i)->value),
- (p+i)->mask);
- if (rc < 0) {
- dev_err(&msm_bt_power_device.dev,
- "%s: reg %x write failed: %d\n",
- __func__, (p+i)->reg, rc);
- return rc;
- }
- dev_dbg(&msm_bt_power_device.dev,
- "%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
- __func__, (p+i)->reg,
- value, (p+i)->mask);
- value = 0;
- rc = marimba_read_bit_mask(&config,
- (p+i)->reg, &value,
- sizeof((p+i)->value), (p+i)->mask);
- if (rc < 0)
- dev_err(&msm_bt_power_device.dev, "%s marimba_read_bit_mask- error",
- __func__);
- dev_dbg(&msm_bt_power_device.dev,
- "%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
- __func__, (p+i)->reg,
- value, (p+i)->mask);
- }
- /* Update BT Status */
- if (on)
- marimba_set_bt_status(&config, true);
- else
- marimba_set_bt_status(&config, false);
- return rc;
-}
-static int bluetooth_switch_regulators(int on)
-{
- int i, rc = 0;
- const char *id = "BTPW";
-
- for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
- if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
- rc = bt_vregs[i].reg ?
- PTR_ERR(bt_vregs[i].reg) :
- -ENODEV;
- dev_err(&msm_bt_power_device.dev,
- "%s: invalid regulator handle for %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto reg_disable;
- }
-
- rc = on ? regulator_set_voltage(bt_vregs[i].reg,
- bt_vregs[i].min_level,
- bt_vregs[i].max_level) : 0;
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: could not set voltage for %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto reg_disable;
- }
-
- rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: could not %sable regulator %s: %d\n",
- __func__, "en", bt_vregs[i].name, rc);
- goto reg_disable;
- }
-
- if (bt_vregs[i].is_pin_controlled) {
- rc = pmapp_vreg_lpm_pincntrl_vote(id,
- bt_vregs[i].pmapp_id,
- PMAPP_CLOCK_ID_D1,
- on ? PMAPP_CLOCK_VOTE_ON :
- PMAPP_CLOCK_VOTE_OFF);
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: pin control failed for %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto pin_cnt_fail;
- }
- }
- rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
-
- if (rc) {
- dev_err(&msm_bt_power_device.dev,
- "%s: could not %sable regulator %s: %d\n",
- __func__, "dis", bt_vregs[i].name, rc);
- goto reg_disable;
- }
- }
-
- return rc;
-pin_cnt_fail:
- if (on)
- regulator_disable(bt_vregs[i].reg);
-reg_disable:
- while (i) {
- if (on) {
- i--;
- regulator_disable(bt_vregs[i].reg);
- regulator_put(bt_vregs[i].reg);
- }
- }
- return rc;
-}
-
-static struct regulator *reg_s3;
-static unsigned int msm_bahama_setup_power(void)
-{
- int rc = 0;
-
- reg_s3 = regulator_get(NULL, "msme1");
- if (IS_ERR(reg_s3)) {
- rc = PTR_ERR(reg_s3);
- pr_err("%s: could not get regulator: %d\n", __func__, rc);
- goto out;
- }
-
- rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
- if (rc < 0) {
- pr_err("%s: could not set voltage: %d\n", __func__, rc);
- goto reg_fail;
- }
-
- rc = regulator_enable(reg_s3);
- if (rc < 0) {
- pr_err("%s: could not enable regulator: %d\n", __func__, rc);
- goto reg_fail;
- }
-
- gpio_tlmm_config(GPIO_CFG(GPIO_BT_SYS_REST_EN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-
- /*setup Bahama_sys_reset_n*/
- rc = gpio_request(GPIO_BT_SYS_REST_EN, "bahama sys_rst_n");
- if (rc < 0) {
- pr_err("%s: gpio_request %d = %d\n", __func__,
- GPIO_BT_SYS_REST_EN, rc);
- goto reg_disable;
- }
-
- rc = bt_set_gpio(1);
- if (rc < 0) {
- pr_err("%s: bt_set_gpio %d = %d\n", __func__,
- GPIO_BT_SYS_REST_EN, rc);
- goto gpio_fail;
- }
-
- return rc;
-
-gpio_fail:
- gpio_free(GPIO_BT_SYS_REST_EN);
-reg_disable:
- regulator_disable(reg_s3);
-reg_fail:
- regulator_put(reg_s3);
-out:
- reg_s3 = NULL;
- return rc;
-}
-
-static unsigned int msm_bahama_shutdown_power(int value)
-{
- int rc = 0;
-
- if (IS_ERR_OR_NULL(reg_s3)) {
- rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
- goto out;
- }
-
- rc = regulator_disable(reg_s3);
- if (rc) {
- pr_err("%s: could not disable regulator: %d\n", __func__, rc);
- goto out;
- }
-
- if (value == BAHAMA_ID) {
- rc = bt_set_gpio(0);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- goto reg_enable;
- }
- gpio_free(GPIO_BT_SYS_REST_EN);
- }
-
- regulator_put(reg_s3);
- reg_s3 = NULL;
-
- return 0;
-
-reg_enable:
- regulator_enable(reg_s3);
-out:
- return rc;
-}
-
-static unsigned int msm_bahama_core_config(int type)
-{
- int rc = 0;
-
- if (type == BAHAMA_ID) {
- int i;
- struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
- const struct bahama_config_register v20_init[] = {
- /* reg, value, mask */
- { 0xF4, 0x84, 0xFF }, /* AREG */
- { 0xF0, 0x04, 0xFF } /* DREG */
- };
- if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
- for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
- u8 value = v20_init[i].value;
- rc = marimba_write_bit_mask(&config,
- v20_init[i].reg,
- &value,
- sizeof(v20_init[i].value),
- v20_init[i].mask);
- if (rc < 0) {
- pr_err("%s: reg %d write failed: %d\n",
- __func__, v20_init[i].reg, rc);
- return rc;
- }
- pr_debug("%s: reg 0x%02x value 0x%02x"
- " mask 0x%02x\n",
- __func__, v20_init[i].reg,
- v20_init[i].value, v20_init[i].mask);
- }
- }
- }
- rc = bt_set_gpio(0);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- }
- pr_debug("core type: %d\n", type);
- return rc;
-}
-
-static int bluetooth_power(int on)
-{
- int pin, rc = 0;
- const char *id = "BTPW";
- int cid = 0;
-
- cid = adie_get_detected_connectivity_type();
- if (cid != BAHAMA_ID) {
- pr_err("%s: unexpected adie connectivity type: %d\n",
- __func__, cid);
- return -ENODEV;
- }
- if (on) {
- /*setup power for BT SOC*/
- rc = bt_set_gpio(on);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- goto exit;
- }
- rc = bluetooth_switch_regulators(on);
- if (rc < 0) {
- pr_err("%s: bluetooth_switch_regulators rc = %d",
- __func__, rc);
- goto exit;
- }
- /*setup BT GPIO lines*/
- for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
- pin++) {
- rc = gpio_tlmm_config(bt_config_power_on[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__,
- bt_config_power_on[pin],
- rc);
- goto fail_power;
- }
- }
- /*Setup BT clocks*/
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_ON);
- if (rc < 0) {
- pr_err("Failed to vote for TCXO_D1 ON\n");
- goto fail_clock;
- }
- msleep(20);
-
- /*I2C config for Bahama*/
- rc = bahama_bt(1);
- if (rc < 0) {
- pr_err("%s: bahama_bt rc = %d", __func__, rc);
- goto fail_i2c;
- }
- msleep(20);
-
- /*setup BT PCM lines*/
- rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
- if (rc < 0) {
- pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
- __func__, rc);
- goto fail_power;
- }
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_PIN_CTRL);
- if (rc < 0)
- pr_err("%s:Pin Control Failed, rc = %d",
- __func__, rc);
-
- } else {
- rc = bahama_bt(0);
- if (rc < 0)
- pr_err("%s: bahama_bt rc = %d", __func__, rc);
-
- rc = bt_set_gpio(on);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- }
-fail_i2c:
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
- PMAPP_CLOCK_VOTE_OFF);
- if (rc < 0)
- pr_err("%s: Failed to vote Off D1\n", __func__);
-fail_clock:
- for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
- pin++) {
- rc = gpio_tlmm_config(bt_config_power_off[pin],
- GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
- __func__, bt_config_power_off[pin], rc);
- }
- }
- rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
- if (rc < 0) {
- pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
- __func__, rc);
- }
-fail_power:
- rc = bluetooth_switch_regulators(0);
- if (rc < 0) {
- pr_err("%s: switch_regulators : rc = %d",\
- __func__, rc);
- goto exit;
- }
- }
- return rc;
-exit:
- pr_err("%s: failed with rc = %d", __func__, rc);
- return rc;
-}
-
-static int __init bt_power_init(void)
-{
- int i, rc = 0;
- struct device *dev = &msm_bt_power_device.dev;
-
- for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
- bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
- if (IS_ERR(bt_vregs[i].reg)) {
- rc = PTR_ERR(bt_vregs[i].reg);
- dev_err(dev, "%s: could not get regulator %s: %d\n",
- __func__, bt_vregs[i].name, rc);
- goto reg_get_fail;
- }
- }
-
- dev->platform_data = &bluetooth_power;
-
- return rc;
-
-reg_get_fail:
- while (i--) {
- regulator_put(bt_vregs[i].reg);
- bt_vregs[i].reg = NULL;
- }
- return rc;
-}
-
-static struct marimba_platform_data marimba_pdata = {
- .slave_id[SLAVE_ID_BAHAMA_FM] = BAHAMA_SLAVE_ID_FM_ADDR,
- .slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
- .bahama_setup = msm_bahama_setup_power,
- .bahama_shutdown = msm_bahama_shutdown_power,
- .bahama_core_config = msm_bahama_core_config,
- .fm = &marimba_fm_pdata,
-};
-
-#endif
-
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-static struct i2c_board_info bahama_devices[] = {
-{
- I2C_BOARD_INFO("marimba", 0xc),
- .platform_data = &marimba_pdata,
-},
-};
-#endif
-
static struct msm_gpio qup_i2c_gpios_io[] = {
{ GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
"qup_scl" },
@@ -1313,8 +454,8 @@
};
static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
- .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
- .v_addr = (uint32_t *)PAGE_OFFSET,
+ .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+ .p_addr = 0,
};
static struct android_pmem_platform_data android_pmem_adsp_pdata = {
@@ -2218,10 +1359,7 @@
msm_fb_add_devices();
#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
- i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- bahama_devices,
- ARRAY_SIZE(bahama_devices));
- bt_power_init();
+ msm7627a_bt_power_init();
#endif
msm_camera_vreg_init();
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index ed5f265..667ac62 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -742,6 +742,8 @@
.en_mask = BIT(23),
.hwcg_reg = MAXI_EN4_REG,
.hwcg_mask = BIT(22),
+ .reset_reg = SW_RESET_AXI_REG,
+ .reset_mask = BIT(4),
.halt_reg = DBG_BUS_VEC_I_REG,
.halt_bit = 25,
},
@@ -758,6 +760,8 @@
.en_mask = BIT(25),
.hwcg_reg = MAXI_EN4_REG,
.hwcg_mask = BIT(24),
+ .reset_reg = SW_RESET_AXI_REG,
+ .reset_mask = BIT(5),
.halt_reg = DBG_BUS_VEC_I_REG,
.halt_bit = 26,
},
@@ -776,7 +780,7 @@
.hwcg_reg = MAXI_EN_REG,
.hwcg_mask = BIT(13),
.reset_reg = SW_RESET_AXI_REG,
- .reset_mask = BIT(4)|BIT(5)|BIT(7),
+ .reset_mask = BIT(7),
.halt_reg = DBG_BUS_VEC_E_REG,
.halt_bit = 3,
},
@@ -4753,6 +4757,7 @@
static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
/*
@@ -5297,13 +5302,16 @@
CLK_LOOKUP("mdp_clk", mdp_clk.c, NULL),
CLK_LOOKUP("core_clk", mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("mdp_vsync_clk", mdp_vsync_clk.c, NULL),
+ CLK_LOOKUP("vsync_clk", mdp_vsync_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("lut_mdp", lut_mdp_clk.c, NULL),
+ CLK_LOOKUP("lut_clk", lut_mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("core_clk", rot_clk.c, "msm_rotator.0"),
CLK_LOOKUP("core_clk", rot_clk.c, "footswitch-8x60.6"),
CLK_DUMMY("tv_src_clk", TV_SRC_CLK, NULL, OFF),
CLK_LOOKUP("core_clk", vcodec_clk.c, "msm_vidc.0"),
CLK_LOOKUP("core_clk", vcodec_clk.c, "footswitch-8x60.7"),
CLK_DUMMY("mdp_tv_clk", MDP_TV_CLK, NULL, OFF),
+ CLK_DUMMY("tv_clk", MDP_TV_CLK, "footswitch-8x60.4", OFF),
CLK_DUMMY("hdmi_clk", HDMI_TV_CLK, NULL, OFF),
CLK_LOOKUP("core_clk", hdmi_app_clk.c, NULL),
CLK_LOOKUP("vpe_clk", vpe_clk.c, NULL),
@@ -5375,6 +5383,7 @@
CLK_DUMMY("bus_clk", DFAB_SDC3_CLK, NULL, 0),
CLK_DUMMY("bus_clk", DFAB_SDC4_CLK, NULL, 0),
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
+ CLK_DUMMY("bus_clk", DFAB_SCM_CLK, "scm", 0),
CLK_LOOKUP("usb_hsic_xcvr_fs_clk", usb_hsic_xcvr_fs_clk.c, NULL),
CLK_LOOKUP("usb_hsic_hsic_clk", usb_hsic_hsic_clk.c, NULL),
CLK_LOOKUP("usb_hsic_hsio_cal_clk", usb_hsic_hsio_cal_clk.c, NULL),
@@ -5494,11 +5503,9 @@
CLK_LOOKUP("core_clk", pmic_ssbi2_clk.c, NULL),
CLK_LOOKUP("mem_clk", rpm_msg_ram_p_clk.c, NULL),
CLK_LOOKUP("core_clk", amp_clk.c, NULL),
- CLK_LOOKUP("cam_clk", cam0_clk.c, NULL),
- CLK_LOOKUP("cam_clk", cam1_clk.c, NULL),
- CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_imx074.0"),
- CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_mt9m114.0"),
- CLK_LOOKUP("cam_clk", cam0_clk.c, "msm_camera_ov2720.0"),
+ CLK_LOOKUP("cam_clk", cam0_clk.c, "4-001a"),
+ CLK_LOOKUP("cam_clk", cam0_clk.c, "4-006c"),
+ CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0048"),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
CLK_LOOKUP("csi_src_clk", csi1_src_clk.c, "msm_csid.1"),
CLK_LOOKUP("csi_clk", csi0_clk.c, "msm_csid.0"),
@@ -5531,7 +5538,9 @@
CLK_LOOKUP("mdp_clk", mdp_clk.c, NULL),
CLK_LOOKUP("core_clk", mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("mdp_vsync_clk", mdp_vsync_clk.c, NULL),
+ CLK_LOOKUP("vsync_clk", mdp_vsync_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("lut_mdp", lut_mdp_clk.c, NULL),
+ CLK_LOOKUP("lut_clk", lut_mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("qdss_pclk", qdss_p_clk.c, NULL),
CLK_LOOKUP("qdss_at_clk", qdss_at_clk.c, NULL),
CLK_LOOKUP("qdss_pclkdbg_clk", qdss_pclkdbg_clk.c, NULL),
@@ -5541,11 +5550,13 @@
CLK_LOOKUP("core_clk", rot_clk.c, "msm_rotator.0"),
CLK_LOOKUP("core_clk", rot_clk.c, "footswitch-8x60.6"),
CLK_LOOKUP("tv_src_clk", tv_src_clk.c, NULL),
+ CLK_LOOKUP("tv_src_clk", tv_src_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("tv_enc_clk", tv_enc_clk.c, NULL),
CLK_LOOKUP("tv_dac_clk", tv_dac_clk.c, NULL),
CLK_LOOKUP("core_clk", vcodec_clk.c, "msm_vidc.0"),
CLK_LOOKUP("core_clk", vcodec_clk.c, "footswitch-8x60.7"),
CLK_LOOKUP("mdp_tv_clk", mdp_tv_clk.c, NULL),
+ CLK_LOOKUP("tv_clk", mdp_tv_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("hdmi_clk", hdmi_tv_clk.c, NULL),
CLK_LOOKUP("core_clk", hdmi_app_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("vpe_clk", vpe_clk.c, "msm_vpe.0"),
@@ -5625,6 +5636,7 @@
CLK_LOOKUP("bus_clk", dfab_sdc5_clk.c, "msm_sdcc.5"),
CLK_LOOKUP("dfab_clk", dfab_sps_clk.c, "msm_sps"),
CLK_LOOKUP("bus_clk", dfab_bam_dmux_clk.c, "BAM_RMNT"),
+ CLK_LOOKUP("bus_clk", dfab_scm_clk.c, "scm"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
@@ -5732,7 +5744,7 @@
SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
rmwreg(0x0003AFF9, MAXI_EN_REG, 0x0803FFFF);
rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
- rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ rmwreg(0x0167FCFF, MAXI_EN4_REG, 0x017FFFFF);
} else {
rmwreg(0x000007F9, MAXI_EN_REG, 0x0803FFFF);
rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
@@ -5996,7 +6008,7 @@
pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
BUG();
}
- xo_cxo = msm_xo_get(MSM_XO_TCXO_D0, "clock-8960");
+ xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8960");
if (IS_ERR(xo_cxo)) {
pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
BUG();
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 45094d9..9da8bb4 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3209,6 +3209,7 @@
static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
static DEFINE_CLK_VOTER(ebi1_adm0_clk, &ebi1_clk.c);
@@ -3703,8 +3704,11 @@
CLK_LOOKUP("mdp_clk", mdp_clk.c, NULL),
CLK_LOOKUP("core_clk", mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("mdp_vsync_clk", mdp_vsync_clk.c, NULL),
+ CLK_LOOKUP("vsync_clk", mdp_vsync_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("pixel_lcdc_clk", pixel_lcdc_clk.c, NULL),
+ CLK_LOOKUP("pixel_lcdc_clk", pixel_lcdc_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("pixel_mdp_clk", pixel_mdp_clk.c, NULL),
+ CLK_LOOKUP("pixel_mdp_clk", pixel_mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("core_clk", rot_clk.c, "msm_rotator.0"),
CLK_LOOKUP("core_clk", rot_clk.c, "footswitch-8x60.6"),
CLK_LOOKUP("tv_enc_clk", tv_enc_clk.c, NULL),
@@ -3712,8 +3716,10 @@
CLK_LOOKUP("core_clk", vcodec_clk.c, "msm_vidc.0"),
CLK_LOOKUP("core_clk", vcodec_clk.c, "footswitch-8x60.7"),
CLK_LOOKUP("mdp_tv_clk", mdp_tv_clk.c, NULL),
+ CLK_LOOKUP("tv_clk", mdp_tv_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("hdmi_clk", hdmi_tv_clk.c, NULL),
CLK_LOOKUP("tv_src_clk", tv_src_clk.c, NULL),
+ CLK_LOOKUP("tv_src_clk", tv_src_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("core_clk", hdmi_app_clk.c, "hdmi_msm.1"),
CLK_LOOKUP("vpe_clk", vpe_clk.c, NULL),
CLK_LOOKUP("core_clk", vpe_clk.c, "footswitch-8x60.9"),
@@ -3788,6 +3794,7 @@
CLK_LOOKUP("bus_clk", dfab_sdc3_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("bus_clk", dfab_sdc4_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("bus_clk", dfab_sdc5_clk.c, "msm_sdcc.5"),
+ CLK_LOOKUP("bus_clk", dfab_scm_clk.c, "scm"),
CLK_LOOKUP("mem_clk", ebi1_adm0_clk.c, "msm_dmov.0"),
CLK_LOOKUP("mem_clk", ebi1_adm1_clk.c, "msm_dmov.1"),
@@ -3903,7 +3910,7 @@
pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
BUG();
}
- xo_cxo = msm_xo_get(MSM_XO_TCXO_D1, "clock-8x60");
+ xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8x60");
if (IS_ERR(xo_cxo)) {
pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
BUG();
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 8c5f027..40a880e 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -729,6 +729,12 @@
F_END
};
+static struct clk_freq_tbl clk_tbl_usb_hsic_sys[] = {
+ F_USB( 0, gnd, 1, 0, 0),
+ F_USB(64000000, pll8, 1, 1, 6),
+ F_END
+};
+
static struct rcg_clk usb_hs1_xcvr_clk = {
.b = {
.ctl_reg = USB_HS1_XCVR_FS_CLK_NS_REG,
@@ -796,7 +802,7 @@
.c = {
.dbg_name = "usb_hsic_xcvr_clk",
.ops = &clk_ops_rcg_9615,
- VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+ VDD_DIG_FMAX_MAP1(LOW, 60000000),
CLK_INIT(usb_hsic_xcvr_clk.c),
},
};
@@ -815,19 +821,19 @@
.root_en_mask = BIT(11),
.ns_mask = (BM(23, 16) | BM(6, 0)),
.set_rate = set_rate_mnd,
- .freq_tbl = clk_tbl_usb,
+ .freq_tbl = clk_tbl_usb_hsic_sys,
.current_freq = &rcg_dummy_freq,
.c = {
.dbg_name = "usb_hsic_sys_clk",
.ops = &clk_ops_rcg_9615,
- VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+ VDD_DIG_FMAX_MAP1(LOW, 64000000),
CLK_INIT(usb_hsic_sys_clk.c),
},
};
static struct clk_freq_tbl clk_tbl_usb_hsic[] = {
F_USB( 0, gnd, 1, 0, 0),
- F_USB(480000000, pll14, 1, 0, 1),
+ F_USB(480000000, pll14, 1, 0, 0),
F_END
};
@@ -837,8 +843,7 @@
.en_mask = BIT(9),
.reset_reg = USB_HSIC_RESET_REG,
.reset_mask = BIT(0),
- .halt_reg = CLK_HALT_DFAB_STATE_REG,
- .halt_bit = 7,
+ .halt_check = DELAY,
},
.ns_reg = USB_HSIC_CLK_NS_REG,
.md_reg = USB_HSIC_CLK_MD_REG,
@@ -850,7 +855,7 @@
.c = {
.dbg_name = "usb_hsic_clk",
.ops = &clk_ops_rcg_9615,
- VDD_DIG_FMAX_MAP1(NOMINAL, 480000000),
+ VDD_DIG_FMAX_MAP1(LOW, 480000000),
CLK_INIT(usb_hsic_clk.c),
},
};
@@ -1448,6 +1453,7 @@
{ TEST_PER_HS(0x2A), &adm0_clk.c },
{ TEST_PER_HS(0x34), &ebi1_clk.c },
{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
+ { TEST_PER_HS(0x3E), &usb_hsic_clk.c },
{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
{ TEST_LPA(0x11), &codec_i2s_spkr_bit_clk.c },
@@ -1671,6 +1677,7 @@
CLK_LOOKUP("usb_hsic_hsio_cal_clk", usb_hsic_hsio_cal_clk.c, NULL),
CLK_LOOKUP("usb_hsic_sys_clk", usb_hsic_sys_clk.c, NULL),
CLK_LOOKUP("usb_hsic_p_clk", usb_hsic_p_clk.c, NULL),
+ CLK_LOOKUP("usb_hsic_clk", usb_hsic_clk.c, NULL),
CLK_LOOKUP("iface_clk", sdc1_p_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("iface_clk", sdc2_p_clk.c, "msm_sdcc.2"),
@@ -1852,7 +1859,7 @@
/* Local clock driver initialization. */
static void __init msm9615_clock_init(void)
{
- xo_cxo = msm_xo_get(MSM_XO_TCXO_D0, "clock-9615");
+ xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-9615");
if (IS_ERR(xo_cxo)) {
pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
BUG();
@@ -1871,8 +1878,8 @@
clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
clk_set_rate(&usb_hs1_sys_clk.c, 60000000);
clk_set_rate(&usb_hsic_xcvr_clk.c, 60000000);
- clk_set_rate(&usb_hsic_sys_clk.c, 60000000);
- clk_set_rate(&usb_hsic_clk.c, 48000000);
+ clk_set_rate(&usb_hsic_sys_clk.c, 64000000);
+ clk_set_rate(&usb_hsic_clk.c, 480000000);
/*
* The halt status bits for PDM may be incorrect at boot.
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 8c251ba..26bb7ae 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -172,6 +172,12 @@
.end = USB_HSIC_IRQ,
.flags = IORESOURCE_IRQ,
},
+ {
+ .start = MSM_GPIO_TO_INT(69),
+ .end = MSM_GPIO_TO_INT(69),
+ .name = "peripheral_status_irq",
+ .flags = IORESOURCE_IRQ,
+ },
};
struct platform_device msm_device_hsic_host = {
@@ -873,7 +879,7 @@
.strap_ahb_lower = 0x00000080,
.aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
.jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
- .xo_id = MSM_XO_TCXO_D0,
+ .xo_id = MSM_XO_CXO,
.name = "modem_fw",
.depends = "q6",
.pas_id = PAS_MODEM_FW,
@@ -911,7 +917,7 @@
.strap_ahb_lower = 0x00000080,
.aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
.jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
- .xo_id = MSM_XO_TCXO_D0,
+ .xo_id = MSM_XO_CXO,
.name = "modem",
.depends = "modem_fw",
.pas_id = PAS_MODEM_SW,
@@ -926,6 +932,26 @@
.dev.platform_data = &msm_8960_q6_mss_sw_data,
};
+static struct resource msm_8960_riva_resources[] = {
+ {
+ .start = 0x03204000,
+ .end = 0x03204000 + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm_8960_riva = {
+ .name = "pil_riva",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_8960_riva_resources),
+ .resource = msm_8960_riva_resources,
+};
+
+struct platform_device msm_pil_tzapps = {
+ .name = "pil_tzapps",
+ .id = -1,
+};
+
struct platform_device msm_device_smd = {
.name = "msm_smd",
.id = -1,
@@ -1405,6 +1431,21 @@
.id = 0x3005,
};
+struct platform_device msm_cpudai_incall_music_rx = {
+ .name = "msm-dai-q6",
+ .id = 0x8005,
+};
+
+struct platform_device msm_cpudai_incall_record_rx = {
+ .name = "msm-dai-q6",
+ .id = 0x8004,
+};
+
+struct platform_device msm_cpudai_incall_record_tx = {
+ .name = "msm-dai-q6",
+ .id = 0x8003,
+};
+
/*
* Machine specific data for AUX PCM Interface
* which the driver will be unware of.
@@ -1494,7 +1535,6 @@
};
struct platform_device *msm_footswitch_devices[] = {
- FS_8X60(FS_MDP, "fs_mdp"),
FS_8X60(FS_ROT, "fs_rot"),
FS_8X60(FS_IJPEG, "fs_ijpeg"),
FS_8X60(FS_VFE, "fs_vfe"),
@@ -2090,7 +2130,7 @@
},
};
-static struct msm_bus_vectors grp2d0_max_vectors[] = {
+static struct msm_bus_vectors grp2d0_nominal_vectors[] = {
{
.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
@@ -2099,12 +2139,25 @@
},
};
+static struct msm_bus_vectors grp2d0_max_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = KGSL_CONVERT_TO_MBPS(2048),
+ },
+};
+
static struct msm_bus_paths grp2d0_bus_scale_usecases[] = {
{
ARRAY_SIZE(grp2d0_init_vectors),
grp2d0_init_vectors,
},
{
+ ARRAY_SIZE(grp2d0_nominal_vectors),
+ grp2d0_nominal_vectors,
+ },
+ {
ARRAY_SIZE(grp2d0_max_vectors),
grp2d0_max_vectors,
},
@@ -2125,7 +2178,7 @@
},
};
-static struct msm_bus_vectors grp2d1_max_vectors[] = {
+static struct msm_bus_vectors grp2d1_nominal_vectors[] = {
{
.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
.dst = MSM_BUS_SLAVE_EBI_CH0,
@@ -2134,12 +2187,25 @@
},
};
+static struct msm_bus_vectors grp2d1_max_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = KGSL_CONVERT_TO_MBPS(2048),
+ },
+};
+
static struct msm_bus_paths grp2d1_bus_scale_usecases[] = {
{
ARRAY_SIZE(grp2d1_init_vectors),
grp2d1_init_vectors,
},
{
+ ARRAY_SIZE(grp2d1_nominal_vectors),
+ grp2d1_nominal_vectors,
+ },
+ {
ARRAY_SIZE(grp2d1_max_vectors),
grp2d1_max_vectors,
},
@@ -2236,17 +2302,21 @@
.pwrlevel = {
{
.gpu_freq = 200000000,
+ .bus_freq = 2,
+ },
+ {
+ .gpu_freq = 96000000,
.bus_freq = 1,
},
{
- .gpu_freq = 200000000,
+ .gpu_freq = 27000000,
.bus_freq = 0,
},
},
.init_level = 0,
- .num_levels = 2,
+ .num_levels = 3,
.set_grp_async = NULL,
- .idle_timeout = HZ/10,
+ .idle_timeout = HZ/5,
.nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
@@ -2285,17 +2355,21 @@
.pwrlevel = {
{
.gpu_freq = 200000000,
+ .bus_freq = 2,
+ },
+ {
+ .gpu_freq = 96000000,
.bus_freq = 1,
},
{
- .gpu_freq = 200000000,
+ .gpu_freq = 27000000,
.bus_freq = 0,
},
},
.init_level = 0,
- .num_levels = 2,
+ .num_levels = 3,
.set_grp_async = NULL,
- .idle_timeout = HZ/10,
+ .idle_timeout = HZ/5,
.nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
@@ -2419,8 +2493,9 @@
MSM_RPM_MAP(USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
MSM_RPM_MAP(HDMI_SWITCH, HDMI_SWITCH, 1),
MSM_RPM_MAP(DDR_DMM_0, DDR_DMM, 2),
-
+ MSM_RPM_MAP(QDSS_CLK, QDSS_CLK, 1),
};
+
unsigned int rpm_map_data_size = ARRAY_SIZE(rpm_map_data);
struct platform_device msm_rpm_device = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 63a86cb..0d3abb6 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -480,6 +480,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
struct platform_device msm9615_qcrypto_device = {
@@ -502,6 +503,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = NULL,
};
struct platform_device msm9615_qcedev_device = {
@@ -735,7 +737,6 @@
[20] = MSM_GPIO_TO_INT(28),
[23] = MSM_GPIO_TO_INT(19),
[24] = MSM_GPIO_TO_INT(23),
- [25] = USB1_HS_IRQ,
[26] = MSM_GPIO_TO_INT(3),
[27] = MSM_GPIO_TO_INT(68),
[29] = MSM_GPIO_TO_INT(78),
@@ -745,6 +746,7 @@
[34] = MSM_GPIO_TO_INT(17),
[37] = MSM_GPIO_TO_INT(20),
[39] = MSM_GPIO_TO_INT(84),
+ [40] = USB1_HS_IRQ,
[42] = MSM_GPIO_TO_INT(24),
[43] = MSM_GPIO_TO_INT(79),
[44] = MSM_GPIO_TO_INT(80),
@@ -767,10 +769,13 @@
RPM_APCC_CPU0_GP_MEDIUM_IRQ,
RPM_APCC_CPU0_GP_LOW_IRQ,
RPM_APCC_CPU0_WAKE_UP_IRQ,
+ MSS_TO_APPS_IRQ_0,
+ MSS_TO_APPS_IRQ_1,
LPASS_SCSS_GP_LOW_IRQ,
LPASS_SCSS_GP_MEDIUM_IRQ,
LPASS_SCSS_GP_HIGH_IRQ,
SPS_MTI_31,
+ A2_BAM_IRQ,
};
struct msm_mpm_device_data msm_mpm_dev_data = {
@@ -883,8 +888,6 @@
void __init msm9615_init_irq(void)
{
- unsigned int i;
-
msm_mpm_irq_extn_init();
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
(void *)MSM_QGIC_CPU_BASE);
@@ -894,16 +897,6 @@
writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
mb();
-
- /*
- * FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
}
struct platform_device msm_bus_9615_sys_fabric = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index aa9e380..8f1709b 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -170,22 +170,11 @@
void __init msm8x60_init_irq(void)
{
- unsigned int i;
-
msm_mpm_irq_extn_init();
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE);
/* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
-
- /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
}
#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
@@ -205,6 +194,28 @@
.resource = msm_8660_q6_resources,
};
+#define MSM_MSS_REGS_PHYS 0x10200000
+
+static struct resource msm_8660_modem_resources[] = {
+ {
+ .start = MSM_MSS_REGS_PHYS,
+ .end = MSM_MSS_REGS_PHYS + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm_pil_modem = {
+ .name = "pil_modem",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_8660_modem_resources),
+ .resource = msm_8660_modem_resources,
+};
+
+struct platform_device msm_pil_tzapps = {
+ .name = "pil_tzapps",
+ .id = -1,
+};
+
static struct resource msm_uart1_dm_resources[] = {
{
.start = MSM_UART1DM_PHYS,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 264e9a9..0de0694 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -173,11 +173,17 @@
extern struct platform_device msm_cpudai_afe_02_tx;
extern struct platform_device msm_pcm_afe;
extern struct platform_device msm_compr_dsp;
+extern struct platform_device msm_cpudai_incall_music_rx;
+extern struct platform_device msm_cpudai_incall_record_rx;
+extern struct platform_device msm_cpudai_incall_record_tx;
extern struct platform_device msm_pil_q6v3;
+extern struct platform_device msm_pil_modem;
+extern struct platform_device msm_pil_tzapps;
extern struct platform_device msm_8960_q6_lpass;
extern struct platform_device msm_8960_q6_mss_fw;
extern struct platform_device msm_8960_q6_mss_sw;
+extern struct platform_device msm_8960_riva;
extern struct platform_device apq_pcm;
extern struct platform_device apq_pcm_routing;
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 5006419..d8326e4 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -22,6 +24,7 @@
#include <mach/msm_bus_board.h>
#include <mach/msm_bus.h>
#include <mach/scm-io.h>
+#include <mach/socinfo.h>
#include "clock.h"
#include "footswitch.h"
@@ -49,8 +52,9 @@
#define RETENTION_BIT BIT(9)
#define RESET_DELAY_US 1
-/* Core clock rate to use if one has not previously been set. */
-#define DEFAULT_CLK_RATE 27000000
+/* Clock rate to use if one has not previously been set. */
+#define DEFAULT_RATE 27000000
+#define MAX_CLKS 10
/*
* Lock is only needed to protect against the first footswitch_enable()
@@ -58,72 +62,76 @@
*/
static DEFINE_MUTEX(claim_lock);
-struct clock_state {
- int ahb_clk_en;
- int axi_clk_en;
- int core_clk_rate;
+struct clk_data {
+ const char *name;
+ struct clk *clk;
+ unsigned long rate;
+ unsigned long reset_rate;
+ bool enabled;
};
struct footswitch {
struct regulator_dev *rdev;
struct regulator_desc desc;
void *gfs_ctl_reg;
- int bus_port1, bus_port2;
+ int bus_port0, bus_port1;
bool is_enabled;
bool is_claimed;
- const bool has_axi_clk;
+ struct clk_data *clk_data;
struct clk *core_clk;
- struct clk *ahb_clk;
- struct clk *axi_clk;
- unsigned int reset_rate;
- struct clock_state clk_state;
unsigned int gfs_delay_cnt:5;
};
static int setup_clocks(struct footswitch *fs)
{
int rc = 0;
+ struct clk_data *clock;
+ long rate;
/*
- * Enable all clocks in the power domain. If a core requires a
- * specific clock rate when being reset, apply it.
+ * Enable all clocks in the power domain. If a specific clock rate is
+ * required for reset timing, set that rate before enabling the clocks.
*/
- fs->clk_state.core_clk_rate = clk_get_rate(fs->core_clk);
- if (!fs->clk_state.core_clk_rate || fs->reset_rate) {
- int rate = fs->reset_rate ? fs->reset_rate : DEFAULT_CLK_RATE;
- rc = clk_set_rate(fs->core_clk, rate);
- if (rc) {
- pr_err("%s: Failed to set core_clk rate to %d Hz.\n",
- __func__, fs->reset_rate);
- return rc;
+ for (clock = fs->clk_data; clock->clk; clock++) {
+ clock->rate = clk_get_rate(clock->clk);
+ if (!clock->rate || clock->reset_rate) {
+ rate = clock->reset_rate ?
+ clock->reset_rate : DEFAULT_RATE;
+ rc = clk_set_rate(clock->clk, rate);
+ if (rc && rc != -ENOSYS) {
+ pr_err("Failed to set %s rate to %lu Hz.\n",
+ clock->name, clock->rate);
+ for (clock--; clock >= fs->clk_data; clock--) {
+ if (clock->enabled)
+ clk_disable(clock->clk);
+ clk_set_rate(clock->clk, clock->rate);
+ }
+ return rc;
+ }
}
+ /*
+ * Some clocks are for reset purposes only. These clocks will
+ * fail to enable. Ignore the failures but keep track of them so
+ * we don't try to disable them later and crash due to
+ * unbalanced calls.
+ */
+ clock->enabled = !clk_enable(clock->clk);
}
- clk_enable(fs->core_clk);
- /*
- * Some AHB and AXI clocks are for reset purposes only. These clocks
- * will fail to enable. Keep track of them so we don't try to disable
- * them later and crash.
- */
- fs->clk_state.ahb_clk_en = !clk_enable(fs->ahb_clk);
- if (fs->axi_clk)
- fs->clk_state.axi_clk_en = !clk_enable(fs->axi_clk);
-
- return rc;
+ return 0;
}
static void restore_clocks(struct footswitch *fs)
{
+ struct clk_data *clock;
+
/* Restore clocks to their orignal states before setup_clocks(). */
- if (fs->axi_clk && fs->clk_state.axi_clk_en)
- clk_disable(fs->axi_clk);
- if (fs->clk_state.ahb_clk_en)
- clk_disable(fs->ahb_clk);
- clk_disable(fs->core_clk);
- if (fs->clk_state.core_clk_rate) {
- if (clk_set_rate(fs->core_clk, fs->clk_state.core_clk_rate))
- pr_err("%s: Failed to restore core_clk rate.\n",
- __func__);
+ for (clock = fs->clk_data; clock->clk; clock++) {
+ if (clock->enabled)
+ clk_disable(clock->clk);
+ if (clock->rate && clk_set_rate(clock->clk, clock->rate))
+ pr_err("Failed to restore %s rate to %lu Hz.\n",
+ clock->name, clock->rate);
}
}
@@ -137,6 +145,7 @@
static int footswitch_enable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
+ struct clk_data *clock;
uint32_t regval, rc = 0;
mutex_lock(&claim_lock);
@@ -154,17 +163,17 @@
return rc;
/* Un-halt all bus ports in the power domain. */
- if (fs->bus_port1) {
- rc = msm_bus_axi_portunhalt(fs->bus_port1);
+ if (fs->bus_port0) {
+ rc = msm_bus_axi_portunhalt(fs->bus_port0);
if (rc) {
- pr_err("%s: Port 1 unhalt failed.\n", __func__);
+ pr_err("Port 0 unhalt failed.\n");
goto err;
}
}
- if (fs->bus_port2) {
- rc = msm_bus_axi_portunhalt(fs->bus_port2);
+ if (fs->bus_port1) {
+ rc = msm_bus_axi_portunhalt(fs->bus_port1);
if (rc) {
- pr_err("%s: Port 2 unhalt failed.\n", __func__);
+ pr_err("Port 1 unhalt failed.\n");
goto err_port2_halt;
}
}
@@ -174,10 +183,10 @@
* footswitch_enable() is first called before footswitch_disable()
* and resets should be asserted before power is restored.
*/
- if (fs->axi_clk)
- clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
- clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
- clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+ for (clock = fs->clk_data; clock->clk; clock++)
+ ; /* Do nothing */
+ for (clock--; clock >= fs->clk_data; clock--)
+ clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
udelay(RESET_DELAY_US);
@@ -193,10 +202,8 @@
writel_relaxed(regval, fs->gfs_ctl_reg);
/* Deassert resets for all clocks in the power domain. */
- clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
- clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
- if (fs->axi_clk)
- clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
+ for (clock = fs->clk_data; clock->clk; clock++)
+ clk_reset(clock->clk, CLK_RESET_DEASSERT);
/* Toggle core reset again after first power-on (required for GFX3D). */
if (fs->desc.id == FS_GFX3D) {
clk_reset(fs->core_clk, CLK_RESET_ASSERT);
@@ -212,7 +219,7 @@
return 0;
err_port2_halt:
- msm_bus_axi_porthalt(fs->bus_port1);
+ msm_bus_axi_porthalt(fs->bus_port0);
err:
restore_clocks(fs);
return rc;
@@ -221,6 +228,7 @@
static int footswitch_disable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
+ struct clk_data *clock;
uint32_t regval, rc = 0;
/* Return early if already disabled. */
@@ -234,17 +242,17 @@
return rc;
/* Halt all bus ports in the power domain. */
- if (fs->bus_port1) {
- rc = msm_bus_axi_porthalt(fs->bus_port1);
+ if (fs->bus_port0) {
+ rc = msm_bus_axi_porthalt(fs->bus_port0);
if (rc) {
- pr_err("%s: Port 1 halt failed.\n", __func__);
+ pr_err("Port 0 halt failed.\n");
goto err;
}
}
- if (fs->bus_port2) {
- rc = msm_bus_axi_porthalt(fs->bus_port2);
+ if (fs->bus_port1) {
+ rc = msm_bus_axi_porthalt(fs->bus_port1);
if (rc) {
- pr_err("%s: Port 1 halt failed.\n", __func__);
+ pr_err("Port 1 halt failed.\n");
goto err_port2_halt;
}
}
@@ -253,10 +261,10 @@
* Assert resets for all clocks in the clock domain so that
* outputs settle prior to clamping.
*/
- if (fs->axi_clk)
- clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
- clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
- clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+ for (clock = fs->clk_data; clock->clk; clock++)
+ ; /* Do nothing */
+ for (clock--; clock >= fs->clk_data; clock--)
+ clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
udelay(RESET_DELAY_US);
@@ -283,7 +291,7 @@
return 0;
err_port2_halt:
- msm_bus_axi_portunhalt(fs->bus_port1);
+ msm_bus_axi_portunhalt(fs->bus_port0);
err:
restore_clocks(fs);
return rc;
@@ -292,6 +300,7 @@
static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
+ struct clk_data *clock;
uint32_t regval, rc = 0;
mutex_lock(&claim_lock);
@@ -309,10 +318,10 @@
return rc;
/* Un-halt all bus ports in the power domain. */
- if (fs->bus_port1) {
- rc = msm_bus_axi_portunhalt(fs->bus_port1);
+ if (fs->bus_port0) {
+ rc = msm_bus_axi_portunhalt(fs->bus_port0);
if (rc) {
- pr_err("%s: Port 1 unhalt failed.\n", __func__);
+ pr_err("Port 0 unhalt failed.\n");
goto err;
}
}
@@ -325,12 +334,12 @@
* footswitch_enable() is first called before footswitch_disable()
* and resets should be asserted before power is restored.
*/
- if (fs->axi_clk)
- clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
- clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
- clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+ for (clock = fs->clk_data; clock->clk; clock++)
+ ; /* Do nothing */
+ for (clock--; clock >= fs->clk_data; clock--)
+ clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(20);
+ udelay(RESET_DELAY_US);
/* Enable the power rail at the footswitch. */
regval |= ENABLE_BIT;
@@ -343,11 +352,9 @@
writel_relaxed(regval, fs->gfs_ctl_reg);
/* Deassert resets for all clocks in the power domain. */
- if (fs->axi_clk)
- clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
- clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
- clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
- udelay(20);
+ for (clock = fs->clk_data; clock->clk; clock++)
+ clk_reset(clock->clk, CLK_RESET_DEASSERT);
+ udelay(RESET_DELAY_US);
/* Re-enable core clock. */
clk_enable(fs->core_clk);
@@ -366,6 +373,7 @@
static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
+ struct clk_data *clock;
uint32_t regval, rc = 0;
/* Return early if already disabled. */
@@ -379,10 +387,10 @@
return rc;
/* Halt all bus ports in the power domain. */
- if (fs->bus_port1) {
- rc = msm_bus_axi_porthalt(fs->bus_port1);
+ if (fs->bus_port0) {
+ rc = msm_bus_axi_porthalt(fs->bus_port0);
if (rc) {
- pr_err("%s: Port 1 halt failed.\n", __func__);
+ pr_err("Port 0 halt failed.\n");
goto err;
}
}
@@ -394,12 +402,12 @@
* Assert resets for all clocks in the clock domain so that
* outputs settle prior to clamping.
*/
- if (fs->axi_clk)
- clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
- clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
- clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+ for (clock = fs->clk_data; clock->clk; clock++)
+ ; /* Do nothing */
+ for (clock--; clock >= fs->clk_data; clock--)
+ clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(20);
+ udelay(5);
/*
* Clamp the I/O ports of the core to ensure the values
@@ -438,8 +446,111 @@
.disable = gfx2d_footswitch_disable,
};
-#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _axi_clk, \
- _reset_rate, _bp1, _bp2) \
+/*
+ * Lists of required clocks for the collapse and restore sequences.
+ *
+ * Order matters here. Clocks are listed in the same order as their
+ * resets will be de-asserted when the core is restored. Also, rate-
+ * settable clocks must be listed before any of the branches that
+ * are derived from them. Otherwise, the branches may fail to enable
+ * if their parent's rate is not yet set.
+ */
+
+static struct clk_data gfx2d0_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { 0 }
+};
+
+static struct clk_data gfx2d1_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { 0 }
+};
+
+static struct clk_data gfx3d_clks[] = {
+ { .name = "core_clk", .reset_rate = 27000000 },
+ { .name = "iface_clk" },
+ { 0 }
+};
+
+
+static struct clk_data ijpeg_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+};
+
+static struct clk_data mdp_8960_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { .name = "vsync_clk" },
+ { .name = "lut_clk" },
+ { .name = "tv_src_clk" },
+ { .name = "tv_clk" },
+ { 0 }
+};
+
+static struct clk_data mdp_8660_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { .name = "vsync_clk" },
+ { .name = "tv_src_clk" },
+ { .name = "tv_clk" },
+ { .name = "pixel_mdp_clk" },
+ { .name = "pixel_lcdc_clk" },
+ { 0 }
+};
+
+static struct clk_data rot_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+};
+
+static struct clk_data ved_8660_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+};
+
+static struct clk_data ved_8960_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { .name = "bus_a_clk" },
+ { .name = "bus_b_clk" },
+ { 0 }
+};
+
+static struct clk_data vfe_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+};
+
+static struct clk_data vpe_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+};
+
+static struct clk_data vcap_clks[] = {
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+};
+
+#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
+ _bp1, _bp2) \
[(_id)] = { \
.desc = { \
.id = (_id), \
@@ -450,43 +561,42 @@
}, \
.gfs_ctl_reg = (_gfs_ctl_reg), \
.gfs_delay_cnt = (_dc), \
- .bus_port1 = (_bp1), \
- .bus_port2 = (_bp2), \
- .has_axi_clk = (_axi_clk), \
- .reset_rate = (_reset_rate), \
+ .clk_data = (_clk_data), \
+ .bus_port0 = (_bp1), \
+ .bus_port1 = (_bp2), \
}
static struct footswitch footswitches[] = {
FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
- GFX2D0_GFS_CTL_REG, 31, false, 0,
+ GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
- GFX2D1_GFS_CTL_REG, 31, false, 0,
+ GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
- GFX3D_GFS_CTL_REG, 31, false, 27000000,
+ GFX3D_GFS_CTL_REG, 31, gfx3d_clks,
MSM_BUS_MASTER_GRAPHICS_3D, 0),
FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
- GEMINI_GFS_CTL_REG, 31, true, 0,
+ GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
MSM_BUS_MASTER_JPEG_ENC, 0),
FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
- MDP_GFS_CTL_REG, 31, true, 0,
+ MDP_GFS_CTL_REG, 31, NULL,
MSM_BUS_MASTER_MDP_PORT0,
MSM_BUS_MASTER_MDP_PORT1),
FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
- ROT_GFS_CTL_REG, 31, true, 0,
+ ROT_GFS_CTL_REG, 31, rot_clks,
MSM_BUS_MASTER_ROTATOR, 0),
FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
- VED_GFS_CTL_REG, 31, true, 0,
+ VED_GFS_CTL_REG, 31, NULL,
MSM_BUS_MASTER_HD_CODEC_PORT0,
MSM_BUS_MASTER_HD_CODEC_PORT1),
FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
- VFE_GFS_CTL_REG, 31, true, 0,
+ VFE_GFS_CTL_REG, 31, vfe_clks,
MSM_BUS_MASTER_VFE, 0),
FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
- VPE_GFS_CTL_REG, 31, true, 0,
+ VPE_GFS_CTL_REG, 31, vpe_clks,
MSM_BUS_MASTER_VPE, 0),
FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
- VCAP_GFS_CTL_REG, 31, true, 0,
+ VCAP_GFS_CTL_REG, 31, vcap_clks,
MSM_BUS_MASTER_VIDEO_CAP, 0),
};
@@ -494,6 +604,7 @@
{
struct footswitch *fs;
struct regulator_init_data *init_data;
+ struct clk_data *clock;
uint32_t regval, rc = 0;
if (pdev == NULL)
@@ -505,30 +616,32 @@
fs = &footswitches[pdev->id];
init_data = pdev->dev.platform_data;
- /* Setup core clock. */
- fs->core_clk = clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(fs->core_clk)) {
- pr_err("%s: clk_get(core_clk) failed\n", __func__);
- rc = PTR_ERR(fs->core_clk);
- goto err_core_clk;
+ if (pdev->id == FS_MDP) {
+ if (cpu_is_msm8960() || cpu_is_msm8930())
+ fs->clk_data = mdp_8960_clks;
+ else if (cpu_is_msm8x60())
+ fs->clk_data = mdp_8660_clks;
+ else
+ BUG();
+ }
+ if (pdev->id == FS_VED) {
+ if (cpu_is_msm8960() || cpu_is_msm8930())
+ fs->clk_data = ved_8960_clks;
+ else if (cpu_is_msm8x60())
+ fs->clk_data = ved_8660_clks;
+ else
+ BUG();
}
- /* Setup AHB clock. */
- fs->ahb_clk = clk_get(&pdev->dev, "iface_clk");
- if (IS_ERR(fs->ahb_clk)) {
- pr_err("%s: clk_get(iface_clk) failed\n", __func__);
- rc = PTR_ERR(fs->ahb_clk);
- goto err_ahb_clk;
- }
-
- /* Setup AXI clock. */
- if (fs->has_axi_clk) {
- fs->axi_clk = clk_get(&pdev->dev, "bus_clk");
- if (IS_ERR(fs->axi_clk)) {
- pr_err("%s: clk_get(bus_clk) failed\n", __func__);
- rc = PTR_ERR(fs->axi_clk);
- goto err_axi_clk;
+ for (clock = fs->clk_data; clock->name; clock++) {
+ clock->clk = clk_get(&pdev->dev, clock->name);
+ if (IS_ERR(clock->clk)) {
+ rc = PTR_ERR(clock->clk);
+ pr_err("clk_get(%s) failed\n", clock->name);
+ goto err;
}
+ if (!strncmp(clock->name, "core_clk", 8))
+ fs->core_clk = clock->clk;
}
/*
@@ -543,34 +656,28 @@
fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
if (IS_ERR(footswitches[pdev->id].rdev)) {
- pr_err("%s: regulator_register(\"%s\") failed\n",
- __func__, fs->desc.name);
+ pr_err("regulator_register(\"%s\") failed\n",
+ fs->desc.name);
rc = PTR_ERR(footswitches[pdev->id].rdev);
- goto err_register;
+ goto err;
}
return 0;
-err_register:
- if (fs->has_axi_clk)
- clk_put(fs->axi_clk);
-err_axi_clk:
- clk_put(fs->ahb_clk);
-err_ahb_clk:
- clk_put(fs->core_clk);
-err_core_clk:
+err:
+ for (clock = fs->clk_data; clock->clk; clock++)
+ clk_put(clock->clk);
+
return rc;
}
static int __devexit footswitch_remove(struct platform_device *pdev)
{
struct footswitch *fs = &footswitches[pdev->id];
+ struct clk_data *clock;
- clk_put(fs->core_clk);
- clk_put(fs->ahb_clk);
- if (fs->axi_clk)
- clk_put(fs->axi_clk);
-
+ for (clock = fs->clk_data; clock->clk; clock++)
+ clk_put(clock->clk);
regulator_unregister(fs->rdev);
return 0;
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
index 5ad62265..a942862 100644
--- a/arch/arm/mach-msm/gpio.c
+++ b/arch/arm/mach-msm/gpio.c
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
+#include <asm/mach/irq.h>
#include <mach/gpiomux.h>
#include "gpio_hw.h"
#include "proc_comm.h"
@@ -337,6 +338,9 @@
{
int i, j, mask;
unsigned val;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
@@ -353,7 +357,8 @@
msm_chip->chip.base + j);
}
}
- desc->irq_data.chip->irq_ack(&desc->irq_data);
+
+ chained_irq_exit(chip, desc);
}
static struct irq_chip msm_gpio_irq_chip = {
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index e8aa38e..86a2374 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -11,10 +11,22 @@
#include <linux/smp.h>
#include <asm/cacheflush.h>
+#include <asm/vfp.h>
-#ifdef CONFIG_SMP
+#include "qdss.h"
+#include "spm.h"
+#include "pm.h"
+
extern volatile int pen_release;
+struct msm_hotplug_device {
+ struct completion cpu_killed;
+ unsigned int warm_boot;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
+ msm_hotplug_devices);
+
static inline void cpu_enter_lowpower(void)
{
/* Just flush the cache. Changing the coherency is not yet
@@ -30,14 +42,8 @@
{
/* Just enter wfi for now. TODO: Properly shut off the cpu. */
for (;;) {
- /*
- * here's the WFI
- */
- asm("wfi"
- :
- :
- : "memory", "cc");
+ msm_pm_cpu_enter_lowpower(cpu);
if (pen_release == cpu) {
/*
* OK, proper wakeup, we're done
@@ -56,11 +62,13 @@
pr_debug("CPU%u: spurious wakeup call\n", cpu);
}
}
-#endif
int platform_cpu_kill(unsigned int cpu)
{
- return 1;
+ struct completion *killed =
+ &per_cpu(msm_hotplug_devices, cpu).cpu_killed;
+
+ return wait_for_completion_timeout(killed, HZ * 5);
}
/*
@@ -70,19 +78,20 @@
*/
void platform_cpu_die(unsigned int cpu)
{
-#ifdef CONFIG_SMP
+ if (unlikely(cpu != smp_processor_id())) {
+ pr_crit("%s: running on %u, should be %u\n",
+ __func__, smp_processor_id(), cpu);
+ BUG();
+ }
+ complete(&__get_cpu_var(msm_hotplug_devices).cpu_killed);
/*
* we're ready for shutdown now, so do it
*/
cpu_enter_lowpower();
platform_do_lowpower(cpu);
- /*
- * bring this CPU back into the world of cache
- * coherency, and then restore interrupts
- */
+ pr_notice("CPU%u: %s: normal wakeup\n", cpu, __func__);
cpu_leave_lowpower();
-#endif
}
int platform_cpu_disable(unsigned int cpu)
@@ -93,3 +102,23 @@
*/
return cpu == 0 ? -EPERM : 0;
}
+
+int msm_platform_secondary_init(unsigned int cpu)
+{
+ int ret;
+ struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
+
+ if (!dev->warm_boot) {
+ dev->warm_boot = 1;
+ init_completion(&dev->cpu_killed);
+ return 0;
+ }
+ etm_restore_reg_check();
+ msm_restore_jtag_debug();
+#ifdef CONFIG_VFP
+ vfp_reinit();
+#endif
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+
+ return ret;
+}
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 06a389e..ae68036 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -219,6 +219,11 @@
struct msm_actuator_info *actuator_info;
};
+struct msm_camera_board_info {
+ struct i2c_board_info *board_info;
+ uint8_t num_i2c_board_info;
+};
+
int msm_get_cam_resources(struct msm_camera_sensor_info *);
struct clk_lookup;
@@ -311,9 +316,14 @@
struct msm_bus_scale_pdata *mdp_bus_scale_table;
#endif
int mdp_rev;
- int (*writeback_offset)(void);
+ int mdp_writeback_memtype;
+ void *mdp_writeback_phys; /* writeback physical addr */
+ int mdp_writeback_size_ov0; /* overlay0 writeback size */
+ int mdp_writeback_size_ov1; /* overlay1 writeback size */
};
+
+
struct lcdc_platform_data {
int (*lcdc_gpio_config)(int on);
int (*lcdc_power_save)(int);
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index ae1f753..1dc6758 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -667,6 +667,8 @@
void msm_io_dump(void __iomem *addr, int size);
void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len);
void msm_camio_set_perf_lvl(enum msm_bus_perf_setting);
+void msm_camio_bus_scale_cfg(
+ struct msm_bus_scale_pdata *, enum msm_bus_perf_setting);
void *msm_isp_sync_alloc(int size, gfp_t gfp);
@@ -674,4 +676,7 @@
int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
struct clk **clk_ptr, int num_clk, int enable);
+
+int msm_sensor_probe_on(struct device *);
+int msm_sensor_probe_off(struct device *);
#endif
diff --git a/arch/arm/mach-msm/include/mach/diag_bridge.h b/arch/arm/mach-msm/include/mach/diag_bridge.h
index 281a1a6..a39ed25 100644
--- a/arch/arm/mach-msm/include/mach/diag_bridge.h
+++ b/arch/arm/mach-msm/include/mach/diag_bridge.h
@@ -16,27 +16,27 @@
struct diag_bridge_ops {
void *ctxt;
void (*read_complete_cb)(void *ctxt, char *buf,
- size_t buf_size, size_t actual);
+ int buf_size, int actual);
void (*write_complete_cb)(void *ctxt, char *buf,
- size_t buf_size, size_t actual);
+ int buf_size, int actual);
};
#if defined(CONFIG_USB_QCOM_DIAG_BRIDGE) \
|| defined(CONFIG_USB_QCOM_DIAG_BRIDGE_MODULE)
-extern int diag_bridge_read(char *data, size_t size);
-extern int diag_bridge_write(char *data, size_t size);
+extern int diag_bridge_read(char *data, int size);
+extern int diag_bridge_write(char *data, int size);
extern int diag_bridge_open(struct diag_bridge_ops *ops);
extern void diag_bridge_close(void);
#else
-static int __maybe_unused diag_bridge_read(char *data, size_t size)
+static int __maybe_unused diag_bridge_read(char *data, int size)
{
return -ENODEV;
}
-static int __maybe_unused diag_bridge_write(char *data, size_t size)
+static int __maybe_unused diag_bridge_write(char *data, int size)
{
return -ENODEV;
}
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
deleted file mode 100644
index 092e48e..0000000
--- a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Low-level IRQ helper macros
- *
- * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <mach/hardware.h>
-#include <asm/hardware/gic.h>
-
- .macro disable_fiq
- .endm
-
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =gic_cpu_base_addr
- ldr \base, [\base]
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
-
- /*
- * The interrupt numbering scheme is defined in the
- * interrupt controller spec. To wit:
- *
- * Migrated the code from ARM MP port to be more consistant
- * with interrupt processing , the following still holds true
- * however, all interrupts are treated the same regardless of
- * if they are local IPI or PPI
- *
- * Interrupts 0-15 are IPI
- * 16-31 are PPI
- * (16-18 are the timers)
- * 32-1020 are global
- * 1021-1022 are reserved
- * 1023 is "spurious" (no interrupt)
- *
- * A simple read from the controller will tell us the number of the
- * highest priority enabled interrupt. We then just need to check
- * whether it is in the valid range for an IRQ (0-1020 inclusive).
- *
- * Base ARM code assumes that the local (private) peripheral interrupts
- * are not valid, we treat them differently, in that the privates are
- * handled like normal shared interrupts with the exception that only
- * one processor can register the interrupt and the handler must be
- * the same for all processors.
- */
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-
- ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU,
- 9-0 =int # */
-
- bic \irqnr, \irqstat, #0x1c00 @mask src
-#ifdef CONFIG_REQUEST_IPI
- cmp \irqnr, #0
-#else
- cmp \irqnr, #15
-#endif
- ldr \tmp, =1021
- cmpcc \irqnr, \irqnr
- cmpne \irqnr, \tmp
- cmpcs \irqnr, \irqnr
-
- .endm
-
- /* We assume that irqstat (the raw value of the IRQ acknowledge
- * register) is preserved from the macro above.
- * If there is an IPI, we immediately signal end of interrupt on the
- * controller, since this requires the original irqstat value which
- * we won't easily be able to recreate later.
- */
- .macro test_for_ipi, irqnr, irqstat, base, tmp
-#ifndef CONFIG_REQUEST_IPI
- bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #16
- strcc \irqstat, [\base, #GIC_CPU_EOI]
- cmpcs \irqnr, \irqnr
-#endif
- .endm
-
- /* As above, this assumes that irqstat and base are preserved.. */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
-#ifndef CONFIG_REQUEST_IPI
- bic \irqnr, \irqstat, #0x1c00
- mov \tmp, #0
- cmp \irqnr, #16
- moveq \tmp, #1
- streq \irqstat, [\base, #GIC_CPU_EOI]
- cmp \tmp, #0
-#endif
- .endm
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-vic.S b/arch/arm/mach-msm/include/mach/entry-macro-vic.S
deleted file mode 100644
index 70563ed..0000000
--- a/arch/arm/mach-msm/include/mach/entry-macro-vic.S
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 <mach/msm_iomap.h>
-
- .macro disable_fiq
- .endm
-
- .macro get_irqnr_preamble, base, tmp
- @ enable imprecise aborts
- cpsie a
- mov \base, #MSM_VIC_BASE
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- @ 0xD0 has irq# or old irq# if the irq has been handled
- @ 0xD4 has irq# or -1 if none pending *but* if you just
- @ read 0xD4 you never get the first irq for some reason
- ldr \irqnr, [\base, #0xD0]
- ldr \irqnr, [\base, #0xD4]
- cmp \irqnr, #0xffffffff
- .endm
diff --git a/arch/arm/mach-msm/include/mach/entry-macro.S b/arch/arm/mach-msm/include/mach/entry-macro.S
index d384366..de696ca8 100644
--- a/arch/arm/mach-msm/include/mach/entry-macro.S
+++ b/arch/arm/mach-msm/include/mach/entry-macro.S
@@ -10,15 +10,27 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#if defined(CONFIG_MSM_VIC) && !defined(CONFIG_MULTI_IRQ_HANDLER)
-#include <mach/entry-macro-vic.S>
-#elif defined(CONFIG_ARM_GIC)
-#include <mach/entry-macro-qgic.S>
-#else
.macro disable_fiq
.endm
.macro arch_ret_to_user, tmp1, tmp2
.endm
+#if !defined(CONFIG_ARM_GIC) && !defined(CONFIG_MULTI_IRQ_HANDLER)
+#include <mach/msm_iomap.h>
+
+ .macro get_irqnr_preamble, base, tmp
+ @ enable imprecise aborts
+ cpsie a
+ mov \base, #MSM_VIC_BASE
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ @ 0xD0 has irq# or old irq# if the irq has been handled
+ @ 0xD4 has irq# or -1 if none pending *but* if you just
+ @ read 0xD4 you never get the first irq for some reason
+ ldr \irqnr, [\base, #0xD0]
+ ldr \irqnr, [\base, #0xD4]
+ cmp \irqnr, #0xffffffff
+ .endm
#endif
diff --git a/include/linux/rtc/rtc-pm8058.h b/arch/arm/mach-msm/include/mach/mdm-peripheral.h
similarity index 65%
rename from include/linux/rtc/rtc-pm8058.h
rename to arch/arm/mach-msm/include/mach/mdm-peripheral.h
index 340fb2d..0f3bd33 100644
--- a/include/linux/rtc/rtc-pm8058.h
+++ b/arch/arm/mach-msm/include/mach/mdm-peripheral.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -8,14 +8,12 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
-#ifndef __RTC_PM8058_H__
-#define __RTC_PM8058_H__
+#ifndef _ARCH_ARM_MACH_MSM_MDM_PERIPHERAL_H
+#define _ARCH_ARM_MACH_MSM_MDM_PERIPHERAL_H_
-struct pm8058_rtc_platform_data {
- bool rtc_alarm_powerup;
-};
+extern void peripheral_connect(void);
+extern void peripheral_disconnect(void);
-#endif /* __RTC_PM8058_H__ */
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_xo.h b/arch/arm/mach-msm/include/mach/msm_xo.h
index 30c3272..77606474 100644
--- a/arch/arm/mach-msm/include/mach/msm_xo.h
+++ b/arch/arm/mach-msm/include/mach/msm_xo.h
@@ -20,6 +20,7 @@
MSM_XO_TCXO_A2,
MSM_XO_CORE,
MSM_XO_PXO,
+ MSM_XO_CXO,
NUM_MSM_XO_IDS
};
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
index 444d7ad..487e814 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -124,17 +124,6 @@
} __packed;
#define USM_DATA_EVENT_READ_DONE 0x0001230F
-struct usm_data_event_read_done {
- u32 status;
- u32 buffer_add;
- u32 enc_frame_size;
- u32 offset;
- u32 msw_ts;
- u32 lsw_ts;
- u32 flags;
- u32 num_frames;
- u32 id;
-} __packed;
#define USM_DATA_CMD_WRITE 0x00011273
struct usm_stream_cmd_write {
@@ -148,9 +137,18 @@
} __packed;
#define USM_DATA_EVENT_WRITE_DONE 0x00011274
-struct usm_data_event_write_done {
- u32 buf_add;
- u32 status;
+
+/* Start/stop US signal detection */
+#define USM_SESSION_CMD_SIGNAL_DETECT_MODE 0x00012719
+
+struct usm_session_cmd_detect_info {
+ struct apr_hdr hdr;
+ u32 detect_mode;
+ u32 skip_interval;
+ u32 algorithm_cfg_size;
} __packed;
+/* US signal detection result */
+#define USM_SESSION_EVENT_SIGNAL_DETECT_RESULT 0x00012720
+
#endif /* __APR_US_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
index 1251e5b8..16751fe 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
@@ -16,8 +16,6 @@
#include <linux/msm_audio_acdb.h>
#include <sound/q6adm.h>
-#define NUM_AUDPROC_BUFFERS 6
-
enum {
RX_CAL,
TX_CAL,
@@ -35,12 +33,6 @@
struct acdb_cal_block *cal_blocks;
};
-struct audproc_buffer_data {
- uint32_t buf_size[NUM_AUDPROC_BUFFERS];
- uint32_t phys_addr[NUM_AUDPROC_BUFFERS];
-};
-
-
uint32_t get_voice_rx_topology(void);
uint32_t get_voice_tx_topology(void);
uint32_t get_adm_rx_topology(void);
@@ -52,7 +44,6 @@
void get_all_vocstrm_cal(struct acdb_cal_block *cal_block);
void get_all_vocvol_cal(struct acdb_cal_block *cal_block);
void get_anc_cal(struct acdb_cal_block *cal_block);
-void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers);
void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block);
void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block);
void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 346dc0d..884c5d0 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,12 +33,40 @@
#define US_STOP_TX _IO(USF_IOCTL_MAGIC, 6)
#define US_STOP_RX _IO(USF_IOCTL_MAGIC, 7)
+#define US_SET_DETECTION _IOWR(USF_IOCTL_MAGIC, 8, \
+ struct us_detect_info_type)
+
+/* Special timeout values */
+#define USF_NO_WAIT_TIMEOUT 0x00000000
+/* Infinitive */
+#define USF_INFINITIVE_TIMEOUT 0xffffffff
+/* Default value, used by the driver */
+#define USF_DEFAULT_TIMEOUT 0xfffffffe
+
+/* US detection place (HW|FW) */
+enum us_detect_place_enum {
+/* US is detected in HW */
+ US_DETECT_HW,
+/* US is detected in FW */
+ US_DETECT_FW
+};
+
+/* US detection mode */
+enum us_detect_mode_enum {
+/* US detection is disabled */
+ US_DETECT_DISABLED_MODE,
+/* US detection is enabled in continue mode */
+ US_DETECT_CONTINUE_MODE,
+/* US detection is enabled in one shot mode */
+ US_DETECT_SHOT_MODE
+};
/* Encoder (TX), decoder (RX) supported US data formats */
#define USF_POINT_EPOS_FORMAT 0
-#define USF_RAW_FORMAT 1
+#define USF_RAW_FORMAT 1
/* Types of events, produced by the calculators */
+#define USF_NO_EVENT 0
#define USF_TSC_EVENT 1
#define USF_MOUSE_EVENT 2
#define USF_KEYBOARD_EVENT 4
@@ -155,6 +183,10 @@
/* Pointer (read index) to the end of available region */
/* in the shared US data memory */
uint32_t free_region;
+/* Time (sec) to wait for data or special values: */
+/* USF_NO_WAIT_TIMEOUT, USF_INFINITIVE_TIMEOUT, USF_DEFAULT_TIMEOUT */
+ uint32_t timeout;
+
/* Input transparent data: */
/* Parameters size */
uint16_t params_data_size;
@@ -182,4 +214,22 @@
uint32_t free_region;
};
+struct us_detect_info_type {
+/* US detection place (HW|FW) */
+/* NA in the Active and OFF states */
+ enum us_detect_place_enum us_detector;
+/* US detection mode */
+ enum us_detect_mode_enum us_detect_mode;
+/* US data dropped during this time (msec) */
+ uint32_t skip_time;
+/* Transparent data size */
+ uint16_t params_data_size;
+/* Pointer to the transparent data */
+ uint8_t *params_data;
+/* Time (sec) to wait for US presence event */
+ uint32_t detect_timeout;
+/* Out parameter: US presence */
+ bool is_us;
+};
+
#endif /* __USF_H__ */
diff --git a/arch/arm/mach-msm/include/mach/rpm-8960.h b/arch/arm/mach-msm/include/mach/rpm-8960.h
index 11862ea..41b94ae 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8960.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8960.h
@@ -44,6 +44,7 @@
MSM_RPM_SEL_CXO_CLK = 5,
MSM_RPM_SEL_PXO_CLK = 6,
+ MSM_RPM_SEL_QDSS_CLK = 7,
MSM_RPM_SEL_APPS_FABRIC_CLK = 8,
MSM_RPM_SEL_SYSTEM_FABRIC_CLK = 9,
MSM_RPM_SEL_MM_FABRIC_CLK = 10,
@@ -281,8 +282,9 @@
MSM_RPM_ID_HDMI_SWITCH = 206,
MSM_RPM_ID_DDR_DMM_0 = 207,
MSM_RPM_ID_DDR_DMM_1 = 208,
+ MSM_RPM_ID_QDSS_CLK = 209,
- MSM_RPM_ID_LAST = MSM_RPM_ID_DDR_DMM_1
+ MSM_RPM_ID_LAST = MSM_RPM_ID_QDSS_CLK,
};
/* RPM resources RPM_ID aliases */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h b/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h
new file mode 100644
index 0000000..2006ad3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_COPPER_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_COPPER_H
+
+/**
+ * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ */
+enum rpm_vreg_id_copper {
+ RPM_VREG_ID_PM8941_S1,
+ RPM_VREG_ID_PM8941_S2,
+ RPM_VREG_ID_PM8941_L12,
+ RPM_VREG_ID_PM8941_MAX,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index f857ab8..1095078 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -20,6 +20,7 @@
#include <mach/rpm-regulator-8660.h>
#include <mach/rpm-regulator-8960.h>
#include <mach/rpm-regulator-9615.h>
+#include <mach/rpm-regulator-copper.h>
/**
* enum rpm_vreg_version - supported RPM regulator versions
@@ -136,6 +137,7 @@
RPM_VREG_VOTER_COUNT,
};
+#ifdef CONFIG_MSM_RPM_REGULATOR
/**
* rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
* @vreg: ID for regulator
@@ -172,4 +174,25 @@
*/
int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq);
+#else
+
+/*
+ * These stubs exist to allow consumers of these APIs to compile and run
+ * in absence of a real RPM regulator driver. It is assumed that they are
+ * aware of the state of their regulators and have either set them
+ * correctly by some other means or don't care about their state at all.
+ */
+static inline int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter,
+ int min_uV, int max_uV, int sleep_also)
+{
+ return 0;
+}
+
+static inline int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq)
+{
+ return 0;
+}
+
+#endif /* CONFIG_MSM_RPM_REGULATOR */
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/usb_bridge.h b/arch/arm/mach-msm/include/mach/usb_bridge.h
index 2b7e754..effa395 100644
--- a/arch/arm/mach-msm/include/mach/usb_bridge.h
+++ b/arch/arm/mach-msm/include/mach/usb_bridge.h
@@ -22,10 +22,6 @@
*/
#define MAX_BRIDGE_DEVICES 2
-/*PID 9001*/
-#define DUN_IFACE_NUM 2
-#define TETHERED_RMNET_IFACE_NUM 3
-
struct bridge_ops {
int (*send_pkt)(void *, void *, size_t actual);
void (*send_cbits)(void *, unsigned int);
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 16c0790..463d6c9 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -979,6 +979,12 @@
return 0;
}
+static phys_addr_t msm_iommu_get_pt_base_addr(struct iommu_domain *domain)
+{
+ struct msm_priv *priv = domain->priv;
+ return __pa(priv->pgtable);
+}
+
static struct iommu_ops msm_iommu_ops = {
.domain_init = msm_iommu_domain_init,
.domain_destroy = msm_iommu_domain_destroy,
@@ -989,7 +995,8 @@
.map_range = msm_iommu_map_range,
.unmap_range = msm_iommu_unmap_range,
.iova_to_phys = msm_iommu_iova_to_phys,
- .domain_has_cap = msm_iommu_domain_has_cap
+ .domain_has_cap = msm_iommu_domain_has_cap,
+ .get_pt_base_addr = msm_iommu_get_pt_base_addr
};
static int __init get_tex_class(int icp, int ocp, int mt, int nos)
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 8e9cc0f..15ea8ba 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1183,7 +1183,15 @@
}
temp_ptr = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_ptr) {
+ pr_err("%s: pkt_fragment_q is empty\n", __func__);
+ return -EINVAL;
+ }
hdr = (struct rr_header *)temp_ptr->data;
+ if (!hdr) {
+ pr_err("%s: No data inside the skb\n", __func__);
+ return -EINVAL;
+ }
msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
switch (msg->cmd) {
@@ -1595,6 +1603,10 @@
}
head_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!head_skb) {
+ pr_err("%s: pkt_fragment_q is empty\n", __func__);
+ return -EINVAL;
+ }
hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
if (!hdr) {
pr_err("%s: Prepend Header failed\n", __func__);
@@ -1642,6 +1654,10 @@
return -EINVAL;
head_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!head_skb) {
+ pr_err("%s: pkt_fragment_q is empty\n", __func__);
+ return -EINVAL;
+ }
hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
if (!hdr) {
pr_err("%s: Prepend Header failed\n", __func__);
diff --git a/arch/arm/mach-msm/irq-vic.c b/arch/arm/mach-msm/irq-vic.c
index 660d530..1bfa776 100644
--- a/arch/arm/mach-msm/irq-vic.c
+++ b/arch/arm/mach-msm/irq-vic.c
@@ -24,6 +24,7 @@
#include <asm/cacheflush.h>
#include <asm/io.h>
+#include <asm/exception.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index 01cc48a..cbdc92a 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -29,9 +29,9 @@
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/clk.h>
-#include <linux/mfd/pmic8058.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
+#include <linux/mfd/pm8xxx/misc.h>
#include <mach/mdm.h>
#include <mach/restart.h>
#include <mach/subsystem_notif.h>
@@ -120,7 +120,7 @@
CHARM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
__func__);
if (get_restart_level() == RESET_SOC)
- pm8058_stay_on();
+ pm8xxx_stay_on();
charm_disable_irqs();
gpio_set_value(AP2MDM_ERRFATAL, 1);
@@ -238,7 +238,7 @@
{
pr_info("Reseting the charm due to an errfatal\n");
if (get_restart_level() == RESET_SOC)
- pm8058_stay_on();
+ pm8xxx_stay_on();
subsystem_restart("external_modem");
}
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 0737a81..bf4e6a4 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -33,6 +33,7 @@
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <mach/mdm2.h>
+#include <mach/mdm-peripheral.h>
#include <mach/restart.h>
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
@@ -49,7 +50,6 @@
#define IFLINE_DOWN 0
static int mdm_debug_on;
-static int ifline_status = IFLINE_UP;
static struct mdm_callbacks mdm_cb;
#define MDM_DBG(...) do { if (mdm_debug_on) \
@@ -58,12 +58,7 @@
static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
{
- /* Remove hsic driver before powering on the modem. */
- if (ifline_status == IFLINE_UP) {
- MDM_DBG("%s: Removing hsic device\n", __func__);
- platform_device_del(&msm_device_hsic_host);
- ifline_status = IFLINE_DOWN;
- }
+ peripheral_disconnect();
/* Pull both ERR_FATAL and RESET low */
MDM_DBG("Pulling PWR and RESET gpio's low\n");
@@ -82,10 +77,7 @@
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
usleep(1000);
- /* Add back hsic device after modem power up */
- MDM_DBG("%s: Adding hsic device\n", __func__);
- platform_device_add(&msm_device_hsic_host);
- ifline_status = IFLINE_UP;
+ peripheral_connect();
msleep(200);
}
@@ -111,12 +103,8 @@
msleep(MDM_MODEM_DELTA);
}
}
- /* Also remove the hsic device on 9k power down. */
- MDM_DBG("%s: Removing hsic device\n", __func__);
- if (ifline_status == IFLINE_UP) {
- platform_device_del(&msm_device_hsic_host);
- ifline_status = IFLINE_DOWN;
- }
+
+ peripheral_disconnect();
}
static void normal_boot_done(struct mdm_modem_drv *mdm_drv)
@@ -128,6 +116,16 @@
mdm_debug_on = value;
}
+static void mdm_status_changed(int value)
+{
+ MDM_DBG("%s: value:%d\n", __func__, value);
+
+ if (value) {
+ peripheral_disconnect();
+ peripheral_connect();
+ }
+}
+
static int __init mdm_modem_probe(struct platform_device *pdev)
{
/* Instantiate driver object. */
@@ -135,6 +133,7 @@
mdm_cb.power_down_mdm_cb = power_down_mdm;
mdm_cb.normal_boot_done_cb = normal_boot_done;
mdm_cb.debug_state_changed_cb = debug_state_changed;
+ mdm_cb.status_cb = mdm_status_changed;
return mdm_common_create(pdev, &mdm_cb);
}
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 1262ce3..023df69 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -136,8 +136,18 @@
static void mdm_status_fn(struct work_struct *work)
{
- MDM_DBG("%s: Reseting the mdm because status changed\n", __func__);
- subsystem_restart(EXTERNAL_MODEM);
+ int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+
+ mdm_drv->status_cb(value);
+
+ MDM_DBG("%s: status:%d\n", __func__, value);
+
+ if ((value == 0) && mdm_drv->mdm_ready) {
+ MDM_DBG("%s: scheduling work now\n", __func__);
+ subsystem_restart(EXTERNAL_MODEM);
+ } else if (value == 1) {
+ MDM_DBG("%s: mdm is now ready\n", __func__);
+ }
}
static DECLARE_WORK(mdm_status_work, mdm_status_fn);
@@ -209,13 +219,9 @@
static irqreturn_t mdm_status_change(int irq, void *dev_id)
{
MDM_DBG("%s: mdm sent status change interrupt\n", __func__);
- if ((gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
- && mdm_drv->mdm_ready) {
- MDM_DBG("%s: scheduling work now\n", __func__);
- queue_work(mdm_queue, &mdm_status_work);
- } else if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1) {
- MDM_DBG("%s: mdm is now ready\n", __func__);
- }
+
+ queue_work(mdm_queue, &mdm_status_work);
+
return IRQ_HANDLED;
}
@@ -350,6 +356,7 @@
mdm_drv->power_down_mdm_cb = p_mdm_cb->power_down_mdm_cb;
mdm_drv->normal_boot_done_cb = p_mdm_cb->normal_boot_done_cb;
mdm_drv->debug_state_changed_cb = p_mdm_cb->debug_state_changed_cb;
+ mdm_drv->status_cb = p_mdm_cb->status_cb;
}
int mdm_common_create(struct platform_device *pdev,
@@ -432,8 +439,8 @@
}
ret = request_threaded_irq(irq, NULL, mdm_status_change,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "mdm status", NULL);
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
+ "mdm status", mdm_drv);
if (ret < 0) {
pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 701eb7a..bc8541e 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -38,6 +38,7 @@
void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
void (*debug_state_changed_cb)(int value);
+ void (*status_cb)(int value);
};
struct mdm_callbacks {
@@ -45,6 +46,7 @@
void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
void (*debug_state_changed_cb)(int value);
+ void (*status_cb)(int value);
};
int mdm_common_create(struct platform_device *pdev,
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 33db3fa..46695c4 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -37,6 +37,7 @@
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <../../mm/mm.h>
+#include <linux/fmem.h>
void *strongly_ordered_page;
char strongly_ordered_mem[PAGE_SIZE*2-4];
@@ -439,3 +440,13 @@
asm("mrc p15, 0, %0, c2, c0, 0\n"
: "=r" (msm_ttbr0));
}
+
+int request_fmem_c_region(void *unused)
+{
+ return fmem_set_state(FMEM_C_STATE);
+}
+
+int release_fmem_c_region(void *unused)
+{
+ return fmem_set_state(FMEM_T_STATE);
+}
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
index 19711a2..0b7b768 100644
--- a/arch/arm/mach-msm/modem-8660.c
+++ b/arch/arm/mach-msm/modem-8660.c
@@ -40,6 +40,7 @@
#if defined(SUBSYS_FATAL_DEBUG)
static void debug_crash_modem_fn(struct work_struct *);
static int reset_modem;
+static int ignore_smsm_ack;
static DECLARE_DELAYED_WORK(debug_crash_modem_work,
debug_crash_modem_fn);
@@ -129,26 +130,30 @@
void *_cmd)
{
if (code == MODEM_NOTIFIER_START_RESET) {
-
+ if (ignore_smsm_ack) {
+ ignore_smsm_ack = 0;
+ goto out;
+ }
pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
subsystem_restart("modem");
}
+out:
return NOTIFY_DONE;
}
static int modem_shutdown(const struct subsys_data *crashed_subsys)
{
void __iomem *modem_wdog_addr;
- int smsm_notif_unregistered = 0;
/* If the modem didn't already crash, setting SMSM_RESET
- * here will help flush caches etc. Unregister for SMSM
- * notifications to prevent unnecessary secondary calls to
- * subsystem_restart.
+ * here will help flush caches etc. The ignore_smsm_ack
+ * flag is set to ignore the SMSM_RESET notification
+ * that is generated due to the modem settings its own
+ * SMSM_RESET bit in response to the apps setting the
+ * apps SMSM_RESET bit.
*/
if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
- modem_unregister_notifier(&modem_notif_nb);
- smsm_notif_unregistered = 1;
+ ignore_smsm_ack = 1;
smsm_reset_modem(SMSM_RESET);
}
@@ -168,9 +173,6 @@
pil_force_shutdown("modem");
disable_irq_nosync(MARM_WDOG_EXPIRED);
- /* Re-register for SMSM notifications if necessary */
- if (smsm_notif_unregistered)
- modem_register_notifier(&modem_notif_nb);
return 0;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index c4c01e8..50afa81 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -24,13 +24,9 @@
#define MSM_BUS_DBG(msg, ...) \
printk(KERN_DEBUG "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
-#define MSM_FAB_DBG(msg, ...) \
- dev_dbg(&fabric->fabdev.dev, "AXI: %s(): " msg, __func__, ## \
- __VA_ARGS__)
#else
#define MSM_BUS_DBG(msg, ...) no_printk("AXI")
-#define MSM_FAB_DBG(msg, ...) no_printk("AXI")
#endif
#define MSM_BUS_ERR(msg, ...) \
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 02dfed6..b06e5dd 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -57,7 +57,7 @@
struct msm_bus_inode_info *info)
{
int status = -ENOMEM;
- MSM_FAB_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
+ MSM_BUS_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
info->node_info->priv_id, info->node_info->gateway);
status = radix_tree_preload(GFP_ATOMIC);
if (status)
@@ -96,7 +96,7 @@
struct msm_bus_inode_info *info)
{
struct msm_bus_fabnodeinfo *fabnodeinfo;
- MSM_FAB_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
+ MSM_BUS_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
info->node_info->priv_id, info->node_info->gateway);
fabnodeinfo = kzalloc(sizeof(struct msm_bus_fabnodeinfo), GFP_KERNEL);
if (fabnodeinfo == NULL) {
@@ -125,7 +125,7 @@
{
int i, ret = 0, err = 0;
- MSM_FAB_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
+ MSM_BUS_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
fabric->pdata->id, fabric->pdata->len);
for (i = 0; i < fabric->pdata->len; i++) {
@@ -179,12 +179,12 @@
fabric->rpm_data = allocate_rpm_data(fabric->pdata);
- MSM_FAB_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
+ MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
" ntieredslaves: %d, rpm_enabled: %d\n",
fabric->fabdev.id, fabric->pdata->nmasters,
fabric->pdata->nslaves, fabric->pdata->ntieredslaves,
fabric->pdata->rpm_enabled);
- MSM_FAB_DBG("msm_bus_register_fabric_info i: %d\n", i);
+ MSM_BUS_DBG("msm_bus_register_fabric_info i: %d\n", i);
fabric->num_nodes = fabric->pdata->len;
error:
fabric->num_nodes = i;
@@ -238,7 +238,7 @@
info->link_info.sel_clk = &info->link_info.clk[ctx];
max_pclk = max(max_pclk, *info->link_info.sel_clk);
}
- MSM_FAB_DBG("max_pclk from gateways: %lu\n", max_pclk);
+ MSM_BUS_DBG("max_pclk from gateways: %lu\n", max_pclk);
/* Maximum of all slave clocks. */
@@ -255,7 +255,7 @@
}
- MSM_FAB_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
+ MSM_BUS_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
fabric->info.link_info.sel_clk =
&fabric->info.link_info.clk[ctx];
pclk = fabric->info.link_info.sel_clk;
@@ -325,7 +325,7 @@
/* If it's an ahb fabric, don't calculate arb values */
if (fabric->ahb) {
- MSM_FAB_DBG("AHB fabric, skipping bw calculation\n");
+ MSM_BUS_DBG("AHB fabric, skipping bw calculation\n");
return;
}
if (!add_bw) {
@@ -486,9 +486,9 @@
rpm_data[1].id = haltid + 1;
rpm_data[1].value = hvector.haltmask;
- MSM_FAB_DBG("ctx: %d, id: %d, value: %d\n",
+ MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
MSM_RPM_CTX_SET_0, rpm_data[0].id, rpm_data[0].value);
- MSM_FAB_DBG("ctx: %d, id: %d, value: %d\n",
+ MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
MSM_RPM_CTX_SET_0, rpm_data[1].id, rpm_data[1].value);
if (fabric->pdata->rpm_enabled)
@@ -529,9 +529,9 @@
rpm_data[1].id = haltid + 1;
rpm_data[1].value = hvector.haltmask;
- MSM_FAB_DBG("unalt: ctx: %d, id: %d, value: %d\n",
+ MSM_BUS_DBG("unalt: ctx: %d, id: %d, value: %d\n",
MSM_RPM_CTX_SET_SLEEP, rpm_data[0].id, rpm_data[0].value);
- MSM_FAB_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
+ MSM_BUS_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
MSM_RPM_CTX_SET_SLEEP, rpm_data[1].id, rpm_data[1].value);
if (fabric->pdata->rpm_enabled)
@@ -582,7 +582,7 @@
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
info = radix_tree_lookup(&fabric->fab_tree, id);
if (!info)
- MSM_FAB_DBG("Null info found for id %d\n", id);
+ MSM_BUS_ERR("Null info found for id %d\n", id);
return info;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
index 84e2da5..a8dc7c8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
@@ -540,14 +540,14 @@
*cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
if (!*cdata) {
- MSM_FAB_DBG("Couldn't alloc mem for cdata\n");
+ MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
goto cdata_err;
}
(*cd)->bwsum = kzalloc((sizeof(uint16_t) * fab_pdata->nslaves),
GFP_KERNEL);
if (!(*cd)->bwsum) {
- MSM_FAB_DBG("Couldn't alloc mem for slaves\n");
+ MSM_BUS_DBG("Couldn't alloc mem for slaves\n");
goto bwsum_err;
}
@@ -556,7 +556,7 @@
(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
GFP_KERNEL);
if (!(*cd)->arb[i]) {
- MSM_FAB_DBG("Couldn't alloc memory for"
+ MSM_BUS_DBG("Couldn't alloc memory for"
" slaves\n");
goto arb_err;
}
@@ -565,7 +565,7 @@
(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
GFP_KERNEL);
if (!(*cd)->actarb[i]) {
- MSM_FAB_DBG("Couldn't alloc memory for"
+ MSM_BUS_DBG("Couldn't alloc memory for"
" slaves\n");
kfree((*cd)->arb[i]);
goto arb_err;
@@ -691,11 +691,11 @@
MSM_BUS_DBG("rpm data for fab: %d\n", fab_pdata->id);
for (i = 0; i < count; i++)
- MSM_FAB_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
+ MSM_BUS_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
MSM_BUS_DBG("Commit Data: Fab: %d BWSum:\n", fab_pdata->id);
for (i = 0; i < fab_pdata->nslaves; i++)
- MSM_FAB_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
+ MSM_BUS_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
MSM_BUS_DBG("Commit Data: Fab: %d Arb:\n", fab_pdata->id);
for (k = 0; k < NUM_TIERS; k++) {
MSM_BUS_DBG("Tier: %d\n", k);
@@ -708,7 +708,7 @@
}
}
- MSM_FAB_DBG("calling msm_rpm_set: %d\n", status);
+ MSM_BUS_DBG("calling msm_rpm_set: %d\n", status);
msm_bus_dbg_commit_data(fab_pdata->name, (void *)cd, fab_pdata->
nmasters, fab_pdata->nslaves, fab_pdata->ntieredslaves,
MSM_BUS_DBG_OP);
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 5419087..4e487a7f 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -103,7 +103,7 @@
pr_err("%s: fail to load DSPS firmware %s.\n", __func__, name);
return -ENODEV;
}
-
+ msleep(20);
return 0;
}
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index da7fb51..492612f 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -95,10 +95,7 @@
static ssize_t show_def_timer_ms(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- int64_t diff_ms;
- diff_ms = ktime_to_ns(ktime_get()) - rq_info.def_start_time;
- do_div(diff_ms, 1000 * 1000);
- return snprintf(buf, MAX_LONG_SIZE, "%lld\n", diff_ms);
+ return snprintf(buf, MAX_LONG_SIZE, "%u\n", rq_info.def_interval);
}
static ssize_t store_def_timer_ms(struct kobject *kobj,
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index a1316b7..5877fbf 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -21,6 +21,7 @@
#include <linux/mfd/pmic8058.h>
#include <linux/jiffies.h>
#include <linux/suspend.h>
+#include <linux/percpu.h>
#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
#include <asm/mach-types.h>
@@ -35,6 +36,7 @@
#define WDT0_RST 0x38
#define WDT0_EN 0x40
+#define WDT0_STS 0x44
#define WDT0_BARK_TIME 0x4C
#define WDT0_BITE_TIME 0x5C
@@ -86,6 +88,8 @@
/* Area for context dump in secure mode */
static void *scm_regsave;
+static struct msm_watchdog_pdata __percpu **percpu_pdata;
+
static void pet_watchdog_work(struct work_struct *work);
static void init_watchdog_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
@@ -157,7 +161,9 @@
if (!old_val) {
__raw_writel(0, msm_tmr0_base + WDT0_EN);
mb();
- free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+ disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+ free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
+ free_percpu(percpu_pdata);
enable = 0;
atomic_notifier_chain_unregister(&panic_notifier_list,
&panic_blk);
@@ -180,10 +186,26 @@
return ret;
}
+unsigned min_slack_ticks = UINT_MAX;
+unsigned long long min_slack_ns = ULLONG_MAX;
+
void pet_watchdog(void)
{
+ int slack;
+ unsigned long long time_ns;
+ unsigned long long slack_ns;
+ unsigned long long bark_time_ns = bark_time * 1000000ULL;
+
+ slack = __raw_readl(msm_tmr0_base + WDT0_STS) >> 3;
+ slack = ((bark_time*WDT_HZ)/1000) - slack;
+ if (slack < min_slack_ticks)
+ min_slack_ticks = slack;
__raw_writel(1, msm_tmr0_base + WDT0_RST);
- last_pet = sched_clock();
+ time_ns = sched_clock();
+ slack_ns = (last_pet + bark_time_ns) - time_ns;
+ if (slack_ns < min_slack_ns)
+ min_slack_ns = slack_ns;
+ last_pet = time_ns;
}
static void pet_watchdog_work(struct work_struct *work)
@@ -199,7 +221,9 @@
if (enable) {
__raw_writel(0, msm_tmr0_base + WDT0_EN);
mb();
- free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+ disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+ free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
+ free_percpu(percpu_pdata);
enable = 0;
/* In case we got suspended mid-exit */
__raw_writel(0, msm_tmr0_base + WDT0_EN);
@@ -314,11 +338,23 @@
msm_tmr0_base = msm_timer_get_timer0_base();
+ percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+ if (!percpu_pdata) {
+ pr_err("%s: memory allocation failed for percpu data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ *__this_cpu_ptr(percpu_pdata) = pdata;
/* Must request irq before sending scm command */
- ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
- "apps_wdog_bark", NULL);
- if (ret)
- return -EINVAL;
+ ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler,
+ "apps_wdog_bark", percpu_pdata);
+ if (ret) {
+ free_percpu(percpu_pdata);
+ return ret;
+ }
+
+ enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, 0);
/*
* This is only temporary till SBLs turn on the XPUs
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 29cb1a8..802ee2a 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -83,6 +83,7 @@
msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_A2], "TCXO A2");
msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CORE], "TCXO Core");
msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_PXO], "PXO during sleep");
+ msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CXO], "CXO");
spin_unlock_irqrestore(&msm_xo_lock, flags);
return 0;
@@ -137,6 +138,10 @@
cmd.id = MSM_RPM_ID_PXO_CLK;
cmd.value = msm_xo_sources[MSM_XO_PXO].mode ? 1 : 0;
ret = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &cmd, 1);
+ } else if (xo == &msm_xo_sources[MSM_XO_CXO]) {
+ cmd.id = MSM_RPM_ID_CXO_CLK;
+ cmd.value = msm_xo_sources[MSM_XO_CXO].mode ? 1 : 0;
+ ret = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &cmd, 1);
} else {
cmd.id = MSM_RPM_ID_CXO_BUFFERS;
cmd.value = (msm_xo_sources[MSM_XO_TCXO_D0].mode << 0) |
@@ -223,10 +228,10 @@
/*
* TODO: Remove early return for 8064 once RPM XO voting support
- * is available. Remove early return for 8960 TCXO_D0 once all
- * voters for it are in place.
+ * is available. Remove early return for 8960 CXO once all voters
+ * for it are in place.
*/
- if (cpu_is_apq8064() || (cpu_is_msm8960() && xo_id == MSM_XO_TCXO_D0))
+ if (cpu_is_apq8064() || (cpu_is_msm8960() && xo_id == MSM_XO_CXO))
return NULL;
if (xo_id >= NUM_MSM_XO_IDS) {
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d6cdbe7..366b282 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -23,5 +23,13 @@
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count)
{ }
+void msm_pm_cpu_enter_lowpower(unsigned cpu)
+{
+ asm("wfi"
+ :
+ :
+ : "memory", "cc");
+}
+
void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
diff --git a/arch/arm/mach-msm/peripheral-reset-8960.c b/arch/arm/mach-msm/peripheral-reset-8960.c
index fa22e4e..6fd8464 100644
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ b/arch/arm/mach-msm/peripheral-reset-8960.c
@@ -17,7 +17,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <asm/mach-types.h>
@@ -28,195 +27,15 @@
#include "peripheral-loader.h"
#include "scm-pas.h"
-#define MSM_RIVA_PHYS 0x03204000
-#define RIVA_PMU_A2XB_CFG (msm_riva_base + 0xB8)
-#define RIVA_PMU_A2XB_CFG_EN BIT(0)
-
-#define RIVA_PMU_CFG (msm_riva_base + 0x28)
-#define RIVA_PMU_CFG_WARM_BOOT BIT(0)
-#define RIVA_PMU_CFG_IRIS_XO_MODE 0x6
-#define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
-
-#define RIVA_PMU_OVRD_VAL (msm_riva_base + 0x30)
-#define RIVA_PMU_OVRD_VAL_CCPU_RESET BIT(0)
-#define RIVA_PMU_OVRD_VAL_CCPU_CLK BIT(1)
-
-#define RIVA_PMU_CCPU_CTL (msm_riva_base + 0x9C)
-#define RIVA_PMU_CCPU_CTL_HIGH_IVT BIT(0)
-#define RIVA_PMU_CCPU_CTL_REMAP_EN BIT(2)
-
-#define RIVA_PMU_CCPU_BOOT_REMAP_ADDR (msm_riva_base + 0xA0)
-
-#define RIVA_PLL_MODE (MSM_CLK_CTL_BASE + 0x31A0)
-#define PLL_MODE_OUTCTRL BIT(0)
-#define PLL_MODE_BYPASSNL BIT(1)
-#define PLL_MODE_RESET_N BIT(2)
-#define PLL_MODE_REF_XO_SEL 0x30
-#define PLL_MODE_REF_XO_SEL_CXO (2 << 4)
-#define PLL_MODE_REF_XO_SEL_RF (3 << 4)
-#define RIVA_PLL_L_VAL (MSM_CLK_CTL_BASE + 0x31A4)
-#define RIVA_PLL_M_VAL (MSM_CLK_CTL_BASE + 0x31A8)
-#define RIVA_PLL_N_VAL (MSM_CLK_CTL_BASE + 0x31Ac)
-#define RIVA_PLL_CONFIG (MSM_CLK_CTL_BASE + 0x31B4)
-#define RIVA_PLL_STATUS (MSM_CLK_CTL_BASE + 0x31B8)
-
-#define RIVA_PMU_ROOT_CLK_SEL (msm_riva_base + 0xC8)
-#define RIVA_PMU_ROOT_CLK_SEL_3 BIT(2)
-
-#define RIVA_PMU_CLK_ROOT3 (msm_riva_base + 0x78)
-#define RIVA_PMU_CLK_ROOT3_ENA BIT(0)
-#define RIVA_PMU_CLK_ROOT3_SRC0_DIV 0x3C
-#define RIVA_PMU_CLK_ROOT3_SRC0_DIV_2 (1 << 2)
-#define RIVA_PMU_CLK_ROOT3_SRC0_SEL 0x1C0
-#define RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA (1 << 6)
-#define RIVA_PMU_CLK_ROOT3_SRC1_DIV 0x1E00
-#define RIVA_PMU_CLK_ROOT3_SRC1_DIV_2 (1 << 9)
-#define RIVA_PMU_CLK_ROOT3_SRC1_SEL 0xE000
-#define RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA (1 << 13)
-
#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
#define PPSS_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2580)
-static void __iomem *msm_riva_base;
-static unsigned long riva_start;
-
static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
{
return 0;
}
-static int init_image_riva_untrusted(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- riva_start = ehdr->e_entry;
- return 0;
-}
-
-static int reset_riva_untrusted(struct pil_desc *pil)
-{
- u32 reg;
- bool xo;
-
- /* Enable A2XB bridge */
- reg = readl_relaxed(RIVA_PMU_A2XB_CFG);
- reg |= RIVA_PMU_A2XB_CFG_EN;
- writel_relaxed(reg, RIVA_PMU_A2XB_CFG);
-
- /* Determine which XO to use */
- reg = readl_relaxed(RIVA_PMU_CFG);
- xo = (reg & RIVA_PMU_CFG_IRIS_XO_MODE) == RIVA_PMU_CFG_IRIS_XO_MODE_48;
-
- /* Program PLL 13 to 960 MHz */
- reg = readl_relaxed(RIVA_PLL_MODE);
- reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
- writel_relaxed(reg, RIVA_PLL_MODE);
-
- if (xo)
- writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
- else
- writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
- writel_relaxed(0, RIVA_PLL_M_VAL);
- writel_relaxed(1, RIVA_PLL_N_VAL);
- writel_relaxed(0x01495227, RIVA_PLL_CONFIG);
-
- reg = readl_relaxed(RIVA_PLL_MODE);
- reg &= ~(PLL_MODE_REF_XO_SEL);
- reg |= xo ? PLL_MODE_REF_XO_SEL_RF : PLL_MODE_REF_XO_SEL_CXO;
- writel_relaxed(reg, RIVA_PLL_MODE);
-
- /* Enable PLL 13 */
- reg |= PLL_MODE_BYPASSNL;
- writel_relaxed(reg, RIVA_PLL_MODE);
-
- /*
- * H/W requires a 5us delay between disabling the bypass and
- * de-asserting the reset. Delay 10us just to be safe.
- */
- mb();
- usleep_range(10, 20);
-
- reg |= PLL_MODE_RESET_N;
- writel_relaxed(reg, RIVA_PLL_MODE);
- reg |= PLL_MODE_OUTCTRL;
- writel_relaxed(reg, RIVA_PLL_MODE);
-
- /* Wait for PLL to settle */
- mb();
- usleep_range(50, 100);
-
- /* Configure cCPU for 240 MHz */
- reg = readl_relaxed(RIVA_PMU_CLK_ROOT3);
- if (readl_relaxed(RIVA_PMU_ROOT_CLK_SEL) & RIVA_PMU_ROOT_CLK_SEL_3) {
- reg &= ~(RIVA_PMU_CLK_ROOT3_SRC0_SEL |
- RIVA_PMU_CLK_ROOT3_SRC0_DIV);
- reg |= RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA |
- RIVA_PMU_CLK_ROOT3_SRC0_DIV_2;
- } else {
- reg &= ~(RIVA_PMU_CLK_ROOT3_SRC1_SEL |
- RIVA_PMU_CLK_ROOT3_SRC1_DIV);
- reg |= RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA |
- RIVA_PMU_CLK_ROOT3_SRC1_DIV_2;
- }
- writel_relaxed(reg, RIVA_PMU_CLK_ROOT3);
- reg |= RIVA_PMU_CLK_ROOT3_ENA;
- writel_relaxed(reg, RIVA_PMU_CLK_ROOT3);
- reg = readl_relaxed(RIVA_PMU_ROOT_CLK_SEL);
- reg ^= RIVA_PMU_ROOT_CLK_SEL_3;
- writel_relaxed(reg, RIVA_PMU_ROOT_CLK_SEL);
-
- /* Use the high vector table */
- reg = readl_relaxed(RIVA_PMU_CCPU_CTL);
- reg |= RIVA_PMU_CCPU_CTL_HIGH_IVT | RIVA_PMU_CCPU_CTL_REMAP_EN;
- writel_relaxed(reg, RIVA_PMU_CCPU_CTL);
-
- /* Set base memory address */
- writel_relaxed(riva_start >> 16, RIVA_PMU_CCPU_BOOT_REMAP_ADDR);
-
- /* Clear warmboot bit indicating this is a cold boot */
- reg = readl_relaxed(RIVA_PMU_CFG);
- reg &= ~(RIVA_PMU_CFG_WARM_BOOT);
- writel_relaxed(reg, RIVA_PMU_CFG);
-
- /* Enable the cCPU clock */
- reg = readl_relaxed(RIVA_PMU_OVRD_VAL);
- reg |= RIVA_PMU_OVRD_VAL_CCPU_CLK;
- writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
-
- /* Take cCPU out of reset */
- reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
- writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
-
- return 0;
-}
-
-static int shutdown_riva_untrusted(struct pil_desc *pil)
-{
- u32 reg;
- /* Put riva into reset */
- reg = readl_relaxed(RIVA_PMU_OVRD_VAL);
- reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
- writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
- return 0;
-}
-
-static int init_image_riva_trusted(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- return pas_init_image(PAS_RIVA, metadata, size);
-}
-
-static int reset_riva_trusted(struct pil_desc *pil)
-{
- return pas_auth_and_reset(PAS_RIVA);
-}
-
-static int shutdown_riva_trusted(struct pil_desc *pil)
-{
- return pas_shutdown(PAS_RIVA);
-}
-
static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
@@ -236,7 +55,7 @@
static int shutdown_dsps_untrusted(struct pil_desc *pil)
{
- writel_relaxed(0x2, PPSS_RESET);
+ writel_relaxed(0x3, PPSS_RESET);
writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
return 0;
}
@@ -257,29 +76,6 @@
return pas_shutdown(PAS_DSPS);
}
-static int init_image_tzapps(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- return pas_init_image(PAS_TZAPPS, metadata, size);
-}
-
-static int reset_tzapps(struct pil_desc *pil)
-{
- return pas_auth_and_reset(PAS_TZAPPS);
-}
-
-static int shutdown_tzapps(struct pil_desc *pil)
-{
- return pas_shutdown(PAS_TZAPPS);
-}
-
-static struct pil_reset_ops pil_riva_ops = {
- .init_image = init_image_riva_untrusted,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_riva_untrusted,
- .shutdown = shutdown_riva_untrusted,
-};
-
struct pil_reset_ops pil_dsps_ops = {
.init_image = init_image_dsps_untrusted,
.verify_blob = verify_blob,
@@ -287,23 +83,6 @@
.shutdown = shutdown_dsps_untrusted,
};
-struct pil_reset_ops pil_tzapps_ops = {
- .init_image = init_image_tzapps,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_tzapps,
- .shutdown = shutdown_tzapps,
-};
-
-static struct platform_device pil_riva = {
- .name = "pil_riva",
-};
-
-static struct pil_desc pil_riva_desc = {
- .name = "wcnss",
- .dev = &pil_riva.dev,
- .ops = &pil_riva_ops,
-};
-
static struct platform_device pil_dsps = {
.name = "pil_dsps",
};
@@ -314,16 +93,6 @@
.ops = &pil_dsps_ops,
};
-static struct platform_device pil_tzapps = {
- .name = "pil_tzapps",
-};
-
-static struct pil_desc pil_tzapps_desc = {
- .name = "tzapps",
- .dev = &pil_tzapps.dev,
- .ops = &pil_tzapps_ops,
-};
-
static void __init use_secure_pil(void)
{
if (pas_supported(PAS_DSPS) > 0) {
@@ -331,12 +100,6 @@
pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
pil_dsps_ops.shutdown = shutdown_dsps_trusted;
}
-
- if (pas_supported(PAS_RIVA) > 0) {
- pil_riva_ops.init_image = init_image_riva_trusted;
- pil_riva_ops.auth_and_reset = reset_riva_trusted;
- pil_riva_ops.shutdown = shutdown_riva_trusted;
- }
}
static int __init msm_peripheral_reset_init(void)
@@ -352,14 +115,6 @@
BUG_ON(platform_device_register(&pil_dsps));
BUG_ON(msm_pil_register(&pil_dsps_desc));
- BUG_ON(platform_device_register(&pil_tzapps));
- BUG_ON(msm_pil_register(&pil_tzapps_desc));
-
- msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
- if (!msm_riva_base)
- return -ENOMEM;
- BUG_ON(platform_device_register(&pil_riva));
- BUG_ON(msm_pil_register(&pil_riva_desc));
return 0;
}
diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c
index 2d60a7e..88b07a5 100644
--- a/arch/arm/mach-msm/peripheral-reset.c
+++ b/arch/arm/mach-msm/peripheral-reset.c
@@ -26,57 +26,15 @@
#include <mach/scm.h>
#include <mach/msm_iomap.h>
-#include <mach/msm_xo.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
-#define PROXY_VOTE_TIMEOUT 10000
-
-#define MSM_MMS_REGS_BASE 0x10200000
-
-#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4)
-#define MARM_BOOT_CONTROL (msm_mms_regs_base + 0x0010)
-#define MAHB0_SFAB_PORT_RESET (MSM_CLK_CTL_BASE + 0x2304)
-#define MARM_CLK_BRANCH_ENA_VOTE (MSM_CLK_CTL_BASE + 0x3000)
-#define MARM_CLK_SRC0_NS (MSM_CLK_CTL_BASE + 0x2BC0)
-#define MARM_CLK_SRC1_NS (MSM_CLK_CTL_BASE + 0x2BC4)
-#define MARM_CLK_SRC_CTL (MSM_CLK_CTL_BASE + 0x2BC8)
-#define MARM_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BCC)
-#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
-#define MSS_MODEM_CXO_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C44)
-#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
-#define MSS_MARM_SYS_REF_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C64)
-#define MAHB0_CLK_CTL (MSM_CLK_CTL_BASE + 0x2300)
-#define MAHB1_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BE4)
-#define MAHB2_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C20)
-#define MAHB1_NS (MSM_CLK_CTL_BASE + 0x2BE0)
-#define MARM_CLK_FS (MSM_CLK_CTL_BASE + 0x2BD0)
-#define MAHB2_CLK_FS (MSM_CLK_CTL_BASE + 0x2C24)
-#define PLL_ENA_MARM (MSM_CLK_CTL_BASE + 0x3500)
-#define PLL8_STATUS (MSM_CLK_CTL_BASE + 0x3158)
-#define CLK_HALT_MSS_SMPSS_MISC_STATE (MSM_CLK_CTL_BASE + 0x2FDC)
-
#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
-static int modem_start, dsps_start;
-static void __iomem *msm_mms_regs_base;
-
-static int init_image_modem_trusted(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- return pas_init_image(PAS_MODEM, metadata, size);
-}
-
-static int init_image_modem_untrusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
-{
- struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- modem_start = ehdr->e_entry;
- return 0;
-}
+static int dsps_start;
static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
size_t size)
@@ -100,176 +58,6 @@
return 0;
}
-static struct msm_xo_voter *pxo;
-static void remove_modem_proxy_votes(unsigned long data)
-{
- msm_xo_mode_vote(pxo, MSM_XO_MODE_OFF);
-}
-static DEFINE_TIMER(modem_timer, remove_modem_proxy_votes, 0, 0);
-
-static void make_modem_proxy_votes(void)
-{
- /* Make proxy votes for modem and set up timer to disable it. */
- msm_xo_mode_vote(pxo, MSM_XO_MODE_ON);
- mod_timer(&modem_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
-}
-
-static void remove_modem_proxy_votes_now(void)
-{
- /*
- * If the modem proxy vote hasn't been removed yet, them remove the
- * votes immediately.
- */
- if (del_timer(&modem_timer))
- remove_modem_proxy_votes(0);
-}
-
-static int reset_modem_untrusted(struct pil_desc *pil)
-{
- u32 reg;
-
- make_modem_proxy_votes();
-
- /* Put modem AHB0,1,2 clocks into reset */
- __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
- __raw_writel(BIT(7), MAHB1_CLK_CTL);
- __raw_writel(BIT(7), MAHB2_CLK_CTL);
-
- /* Vote for pll8 on behalf of the modem */
- reg = __raw_readl(PLL_ENA_MARM);
- reg |= BIT(8);
- __raw_writel(reg, PLL_ENA_MARM);
-
- /* Wait for PLL8 to enable */
- while (!(__raw_readl(PLL8_STATUS) & BIT(16)))
- cpu_relax();
-
- /* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
- __raw_writel(0x4, MAHB1_NS);
-
- /* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
- reg = __raw_readl(MARM_CLK_BRANCH_ENA_VOTE);
- reg |= BIT(0) | BIT(1);
- __raw_writel(reg, MARM_CLK_BRANCH_ENA_VOTE);
-
- /* Source marm_clk off of PLL8 */
- reg = __raw_readl(MARM_CLK_SRC_CTL);
- if ((reg & 0x1) == 0) {
- __raw_writel(0x3, MARM_CLK_SRC1_NS);
- reg |= 0x1;
- } else {
- __raw_writel(0x3, MARM_CLK_SRC0_NS);
- reg &= ~0x1;
- }
- __raw_writel(reg | 0x2, MARM_CLK_SRC_CTL);
-
- /*
- * Force core on and periph on signals to remain active during halt
- * for marm_clk and mahb2_clk
- */
- __raw_writel(0x6F, MARM_CLK_FS);
- __raw_writel(0x6F, MAHB2_CLK_FS);
-
- /*
- * Enable all of the marm_clk branches, cxo sourced marm branches,
- * and sleep clock branches
- */
- __raw_writel(0x10, MARM_CLK_CTL);
- __raw_writel(0x10, MAHB0_CLK_CTL);
- __raw_writel(0x10, SFAB_MSS_S_HCLK_CTL);
- __raw_writel(0x10, MSS_MODEM_CXO_CLK_CTL);
- __raw_writel(0x10, MSS_SLP_CLK_CTL);
- __raw_writel(0x10, MSS_MARM_SYS_REF_CLK_CTL);
-
- /* Wait for above clocks to be turned on */
- while (__raw_readl(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
- BIT(9) | BIT(10) | BIT(4) | BIT(6)))
- cpu_relax();
-
- /* Take MAHB0,1,2 clocks out of reset */
- __raw_writel(0x0, MAHB2_CLK_CTL);
- __raw_writel(0x0, MAHB1_CLK_CTL);
- __raw_writel(0x0, MAHB0_SFAB_PORT_RESET);
-
- /* Setup exception vector table base address */
- __raw_writel(modem_start | 0x1, MARM_BOOT_CONTROL);
-
- /* Wait for vector table to be setup */
- mb();
-
- /* Bring modem out of reset */
- __raw_writel(0x0, MARM_RESET);
-
- return 0;
-}
-
-static int reset_modem_trusted(struct pil_desc *pil)
-{
- int ret;
-
- make_modem_proxy_votes();
-
- ret = pas_auth_and_reset(PAS_MODEM);
- if (ret)
- remove_modem_proxy_votes_now();
-
- return ret;
-}
-
-static int shutdown_modem_untrusted(struct pil_desc *pil)
-{
- u32 reg;
-
- /* Put modem into reset */
- __raw_writel(0x1, MARM_RESET);
- mb();
-
- /* Put modem AHB0,1,2 clocks into reset */
- __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
- __raw_writel(BIT(7), MAHB1_CLK_CTL);
- __raw_writel(BIT(7), MAHB2_CLK_CTL);
- mb();
-
- /*
- * Disable all of the marm_clk branches, cxo sourced marm branches,
- * and sleep clock branches
- */
- __raw_writel(0x0, MARM_CLK_CTL);
- __raw_writel(0x0, MAHB0_CLK_CTL);
- __raw_writel(0x0, SFAB_MSS_S_HCLK_CTL);
- __raw_writel(0x0, MSS_MODEM_CXO_CLK_CTL);
- __raw_writel(0x0, MSS_SLP_CLK_CTL);
- __raw_writel(0x0, MSS_MARM_SYS_REF_CLK_CTL);
-
- /* Disable marm_clk */
- reg = __raw_readl(MARM_CLK_SRC_CTL);
- reg &= ~0x2;
- __raw_writel(reg, MARM_CLK_SRC_CTL);
-
- /* Clear modem's votes for ahb clocks */
- __raw_writel(0x0, MARM_CLK_BRANCH_ENA_VOTE);
-
- /* Clear modem's votes for PLLs */
- __raw_writel(0x0, PLL_ENA_MARM);
-
- remove_modem_proxy_votes_now();
-
- return 0;
-}
-
-static int shutdown_modem_trusted(struct pil_desc *pil)
-{
- int ret;
-
- ret = pas_shutdown(PAS_MODEM);
- if (ret)
- return ret;
-
- remove_modem_proxy_votes_now();
-
- return 0;
-}
-
static int reset_dsps_untrusted(struct pil_desc *pil)
{
__raw_writel(0x10, PPSS_PROC_CLK_CTL);
@@ -293,34 +81,11 @@
static int shutdown_dsps_untrusted(struct pil_desc *pil)
{
- __raw_writel(0x2, PPSS_RESET);
+ __raw_writel(0x3, PPSS_RESET);
__raw_writel(0x0, PPSS_PROC_CLK_CTL);
return 0;
}
-static int init_image_playready(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- return pas_init_image(PAS_PLAYREADY, metadata, size);
-}
-
-static int reset_playready(struct pil_desc *pil)
-{
- return pas_auth_and_reset(PAS_PLAYREADY);
-}
-
-static int shutdown_playready(struct pil_desc *pil)
-{
- return pas_shutdown(PAS_PLAYREADY);
-}
-
-struct pil_reset_ops pil_modem_ops = {
- .init_image = init_image_modem_untrusted,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_modem_untrusted,
- .shutdown = shutdown_modem_untrusted,
-};
-
struct pil_reset_ops pil_dsps_ops = {
.init_image = init_image_dsps_untrusted,
.verify_blob = verify_blob,
@@ -328,34 +93,6 @@
.shutdown = shutdown_dsps_untrusted,
};
-struct pil_reset_ops pil_playready_ops = {
- .init_image = init_image_playready,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_playready,
- .shutdown = shutdown_playready,
-};
-
-static struct platform_device pil_modem = {
- .name = "pil_modem",
-};
-
-static struct pil_desc pil_modem_desc = {
- .name = "modem",
- .depends_on = "q6",
- .dev = &pil_modem.dev,
- .ops = &pil_modem_ops,
-};
-
-static struct platform_device pil_playready = {
- .name = "pil_playready",
-};
-
-static struct pil_desc pil_playready_desc = {
- .name = "tzapps",
- .dev = &pil_playready.dev,
- .ops = &pil_playready_ops,
-};
-
static struct platform_device pil_dsps = {
.name = "pil_dsps",
};
@@ -368,51 +105,21 @@
static int __init msm_peripheral_reset_init(void)
{
- msm_mms_regs_base = ioremap(MSM_MMS_REGS_BASE, SZ_256);
- if (!msm_mms_regs_base)
- goto err;
-
- pxo = msm_xo_get(MSM_XO_PXO, "pil");
- if (IS_ERR(pxo))
- goto err_pxo;
-
- if (pas_supported(PAS_MODEM) > 0) {
- pil_modem_ops.init_image = init_image_modem_trusted;
- pil_modem_ops.auth_and_reset = reset_modem_trusted;
- pil_modem_ops.shutdown = shutdown_modem_trusted;
- }
-
if (pas_supported(PAS_DSPS) > 0) {
pil_dsps_ops.init_image = init_image_dsps_trusted;
pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
pil_dsps_ops.shutdown = shutdown_dsps_trusted;
}
- BUG_ON(platform_device_register(&pil_modem));
- BUG_ON(msm_pil_register(&pil_modem_desc));
- BUG_ON(platform_device_register(&pil_playready));
- BUG_ON(msm_pil_register(&pil_playready_desc));
-
if (machine_is_msm8x60_fluid())
pil_dsps_desc.name = "dsps_fluid";
BUG_ON(platform_device_register(&pil_dsps));
BUG_ON(msm_pil_register(&pil_dsps_desc));
return 0;
-
-err_pxo:
- iounmap(msm_mms_regs_base);
-err:
- return -ENOMEM;
-}
-
-static void __exit msm_peripheral_reset_exit(void)
-{
- iounmap(msm_mms_regs_base);
}
arch_initcall(msm_peripheral_reset_init);
-module_exit(msm_peripheral_reset_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Validate and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
new file mode 100644
index 0000000..5aa38345
--- /dev/null
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -0,0 +1,344 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define MARM_BOOT_CONTROL 0x0010
+#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4)
+#define MAHB0_SFAB_PORT_RESET (MSM_CLK_CTL_BASE + 0x2304)
+#define MARM_CLK_BRANCH_ENA_VOTE (MSM_CLK_CTL_BASE + 0x3000)
+#define MARM_CLK_SRC0_NS (MSM_CLK_CTL_BASE + 0x2BC0)
+#define MARM_CLK_SRC1_NS (MSM_CLK_CTL_BASE + 0x2BC4)
+#define MARM_CLK_SRC_CTL (MSM_CLK_CTL_BASE + 0x2BC8)
+#define MARM_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BCC)
+#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_MODEM_CXO_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C44)
+#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
+#define MSS_MARM_SYS_REF_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C64)
+#define MAHB0_CLK_CTL (MSM_CLK_CTL_BASE + 0x2300)
+#define MAHB1_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BE4)
+#define MAHB2_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C20)
+#define MAHB1_NS (MSM_CLK_CTL_BASE + 0x2BE0)
+#define MARM_CLK_FS (MSM_CLK_CTL_BASE + 0x2BD0)
+#define MAHB2_CLK_FS (MSM_CLK_CTL_BASE + 0x2C24)
+#define PLL_ENA_MARM (MSM_CLK_CTL_BASE + 0x3500)
+#define PLL8_STATUS (MSM_CLK_CTL_BASE + 0x3158)
+#define CLK_HALT_MSS_SMPSS_MISC_STATE (MSM_CLK_CTL_BASE + 0x2FDC)
+
+#define PROXY_VOTE_TIMEOUT 10000
+
+struct modem_data {
+ void __iomem *base;
+ unsigned long start_addr;
+ struct msm_xo_voter *pxo;
+ struct timer_list timer;
+};
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+ return 0;
+}
+
+static void remove_proxy_votes(unsigned long data)
+{
+ struct modem_data *drv = (struct modem_data *)data;
+ msm_xo_mode_vote(drv->pxo, MSM_XO_MODE_OFF);
+}
+
+static void make_modem_proxy_votes(struct device *dev)
+{
+ int ret;
+ struct modem_data *drv = dev_get_drvdata(dev);
+
+ ret = msm_xo_mode_vote(drv->pxo, MSM_XO_MODE_ON);
+ if (ret)
+ dev_err(dev, "Failed to enable PXO\n");
+ mod_timer(&drv->timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+}
+
+static void remove_modem_proxy_votes_now(struct modem_data *drv)
+{
+ /* If the proxy vote hasn't been removed yet, remove it immediately. */
+ if (del_timer(&drv->timer))
+ remove_proxy_votes((unsigned long)drv);
+}
+
+static int modem_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+ struct modem_data *drv = dev_get_drvdata(pil->dev);
+ drv->start_addr = ehdr->e_entry;
+ return 0;
+}
+
+static int modem_reset(struct pil_desc *pil)
+{
+ u32 reg;
+ const struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+ make_modem_proxy_votes(pil->dev);
+
+ /* Put modem AHB0,1,2 clocks into reset */
+ writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
+ writel_relaxed(BIT(7), MAHB1_CLK_CTL);
+ writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+
+ /* Vote for pll8 on behalf of the modem */
+ reg = readl_relaxed(PLL_ENA_MARM);
+ reg |= BIT(8);
+ writel_relaxed(reg, PLL_ENA_MARM);
+
+ /* Wait for PLL8 to enable */
+ while (!(readl_relaxed(PLL8_STATUS) & BIT(16)))
+ cpu_relax();
+
+ /* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
+ writel_relaxed(0x4, MAHB1_NS);
+
+ /* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
+ reg = readl_relaxed(MARM_CLK_BRANCH_ENA_VOTE);
+ reg |= BIT(0) | BIT(1);
+ writel_relaxed(reg, MARM_CLK_BRANCH_ENA_VOTE);
+
+ /* Source marm_clk off of PLL8 */
+ reg = readl_relaxed(MARM_CLK_SRC_CTL);
+ if ((reg & 0x1) == 0) {
+ writel_relaxed(0x3, MARM_CLK_SRC1_NS);
+ reg |= 0x1;
+ } else {
+ writel_relaxed(0x3, MARM_CLK_SRC0_NS);
+ reg &= ~0x1;
+ }
+ writel_relaxed(reg | 0x2, MARM_CLK_SRC_CTL);
+
+ /*
+ * Force core on and periph on signals to remain active during halt
+ * for marm_clk and mahb2_clk
+ */
+ writel_relaxed(0x6F, MARM_CLK_FS);
+ writel_relaxed(0x6F, MAHB2_CLK_FS);
+
+ /*
+ * Enable all of the marm_clk branches, cxo sourced marm branches,
+ * and sleep clock branches
+ */
+ writel_relaxed(0x10, MARM_CLK_CTL);
+ writel_relaxed(0x10, MAHB0_CLK_CTL);
+ writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+ writel_relaxed(0x10, MSS_MODEM_CXO_CLK_CTL);
+ writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+ writel_relaxed(0x10, MSS_MARM_SYS_REF_CLK_CTL);
+
+ /* Wait for above clocks to be turned on */
+ while (readl_relaxed(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
+ BIT(9) | BIT(10) | BIT(4) | BIT(6)))
+ cpu_relax();
+
+ /* Take MAHB0,1,2 clocks out of reset */
+ writel_relaxed(0x0, MAHB2_CLK_CTL);
+ writel_relaxed(0x0, MAHB1_CLK_CTL);
+ writel_relaxed(0x0, MAHB0_SFAB_PORT_RESET);
+ mb();
+
+ /* Setup exception vector table base address */
+ writel_relaxed(drv->start_addr | 0x1, drv->base + MARM_BOOT_CONTROL);
+
+ /* Wait for vector table to be setup */
+ mb();
+
+ /* Bring modem out of reset */
+ writel_relaxed(0x0, MARM_RESET);
+
+ return 0;
+}
+
+static int modem_shutdown(struct pil_desc *pil)
+{
+ u32 reg;
+ struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+ /* Put modem into reset */
+ writel_relaxed(0x1, MARM_RESET);
+ mb();
+
+ /* Put modem AHB0,1,2 clocks into reset */
+ writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
+ writel_relaxed(BIT(7), MAHB1_CLK_CTL);
+ writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+ mb();
+
+ /*
+ * Disable all of the marm_clk branches, cxo sourced marm branches,
+ * and sleep clock branches
+ */
+ writel_relaxed(0x0, MARM_CLK_CTL);
+ writel_relaxed(0x0, MAHB0_CLK_CTL);
+ writel_relaxed(0x0, SFAB_MSS_S_HCLK_CTL);
+ writel_relaxed(0x0, MSS_MODEM_CXO_CLK_CTL);
+ writel_relaxed(0x0, MSS_SLP_CLK_CTL);
+ writel_relaxed(0x0, MSS_MARM_SYS_REF_CLK_CTL);
+
+ /* Disable marm_clk */
+ reg = readl_relaxed(MARM_CLK_SRC_CTL);
+ reg &= ~0x2;
+ writel_relaxed(reg, MARM_CLK_SRC_CTL);
+
+ /* Clear modem's votes for ahb clocks */
+ writel_relaxed(0x0, MARM_CLK_BRANCH_ENA_VOTE);
+
+ /* Clear modem's votes for PLLs */
+ writel_relaxed(0x0, PLL_ENA_MARM);
+
+ remove_modem_proxy_votes_now(drv);
+
+ return 0;
+}
+
+static struct pil_reset_ops pil_modem_ops = {
+ .init_image = modem_init_image,
+ .verify_blob = nop_verify_blob,
+ .auth_and_reset = modem_reset,
+ .shutdown = modem_shutdown,
+};
+
+static int modem_init_image_trusted(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ return pas_init_image(PAS_MODEM, metadata, size);
+}
+
+static int modem_reset_trusted(struct pil_desc *pil)
+{
+ int ret;
+ struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+ make_modem_proxy_votes(pil->dev);
+
+ ret = pas_auth_and_reset(PAS_MODEM);
+ if (ret)
+ remove_modem_proxy_votes_now(drv);
+
+ return ret;
+}
+
+static int modem_shutdown_trusted(struct pil_desc *pil)
+{
+ int ret;
+ struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+ ret = pas_shutdown(PAS_MODEM);
+ if (ret)
+ return ret;
+
+ remove_modem_proxy_votes_now(drv);
+ return 0;
+}
+
+static struct pil_reset_ops pil_modem_ops_trusted = {
+ .init_image = modem_init_image_trusted,
+ .verify_blob = nop_verify_blob,
+ .auth_and_reset = modem_reset_trusted,
+ .shutdown = modem_shutdown_trusted,
+};
+
+static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
+{
+ struct modem_data *drv;
+ struct resource *res;
+ struct pil_desc *desc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->base)
+ return -ENOMEM;
+
+ drv->pxo = msm_xo_get(MSM_XO_PXO, dev_name(&pdev->dev));
+ if (IS_ERR(drv->pxo))
+ return PTR_ERR(drv->pxo);
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ setup_timer(&drv->timer, remove_proxy_votes, (unsigned long)drv);
+ desc->name = "modem";
+ desc->depends_on = "q6";
+ desc->dev = &pdev->dev;
+
+ if (pas_supported(PAS_MODEM) > 0) {
+ desc->ops = &pil_modem_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_modem_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+
+ if (msm_pil_register(desc)) {
+ msm_xo_put(drv->pxo);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
+{
+ struct modem_data *drv = platform_get_drvdata(pdev);
+ del_timer_sync(&drv->timer);
+ msm_xo_put(drv->pxo);
+ return 0;
+}
+
+static struct platform_driver pil_modem_driver = {
+ .probe = pil_modem_driver_probe,
+ .remove = __devexit_p(pil_modem_driver_exit),
+ .driver = {
+ .name = "pil_modem",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_modem_init(void)
+{
+ return platform_driver_register(&pil_modem_driver);
+}
+module_init(pil_modem_init);
+
+static void __exit pil_modem_exit(void)
+{
+ platform_driver_unregister(&pil_modem_driver);
+}
+module_exit(pil_modem_exit);
+
+MODULE_DESCRIPTION("Support for booting modem processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 24c479c..d8ebab5 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -28,7 +28,7 @@
#include "pil-q6v4.h"
#include "scm-pas.h"
-#define PROXY_VOTE_TIMEOUT 10000
+#define PROXY_VOTE_TIMEOUT 40000
#define QDSP6SS_RST_EVB 0x0
#define QDSP6SS_RESET 0x04
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
new file mode 100644
index 0000000..de61041
--- /dev/null
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -0,0 +1,352 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define PROXY_VOTE_TIMEOUT 10000
+
+#define RIVA_PMU_A2XB_CFG 0xB8
+#define RIVA_PMU_A2XB_CFG_EN BIT(0)
+
+#define RIVA_PMU_CFG 0x28
+#define RIVA_PMU_CFG_WARM_BOOT BIT(0)
+#define RIVA_PMU_CFG_IRIS_XO_MODE 0x6
+#define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
+
+#define RIVA_PMU_OVRD_VAL 0x30
+#define RIVA_PMU_OVRD_VAL_CCPU_RESET BIT(0)
+#define RIVA_PMU_OVRD_VAL_CCPU_CLK BIT(1)
+
+#define RIVA_PMU_CCPU_CTL 0x9C
+#define RIVA_PMU_CCPU_CTL_HIGH_IVT BIT(0)
+#define RIVA_PMU_CCPU_CTL_REMAP_EN BIT(2)
+
+#define RIVA_PMU_CCPU_BOOT_REMAP_ADDR 0xA0
+
+#define RIVA_PLL_MODE (MSM_CLK_CTL_BASE + 0x31A0)
+#define PLL_MODE_OUTCTRL BIT(0)
+#define PLL_MODE_BYPASSNL BIT(1)
+#define PLL_MODE_RESET_N BIT(2)
+#define PLL_MODE_REF_XO_SEL 0x30
+#define PLL_MODE_REF_XO_SEL_CXO (2 << 4)
+#define PLL_MODE_REF_XO_SEL_RF (3 << 4)
+#define RIVA_PLL_L_VAL (MSM_CLK_CTL_BASE + 0x31A4)
+#define RIVA_PLL_M_VAL (MSM_CLK_CTL_BASE + 0x31A8)
+#define RIVA_PLL_N_VAL (MSM_CLK_CTL_BASE + 0x31Ac)
+#define RIVA_PLL_CONFIG (MSM_CLK_CTL_BASE + 0x31B4)
+#define RIVA_PLL_STATUS (MSM_CLK_CTL_BASE + 0x31B8)
+
+#define RIVA_PMU_ROOT_CLK_SEL 0xC8
+#define RIVA_PMU_ROOT_CLK_SEL_3 BIT(2)
+
+#define RIVA_PMU_CLK_ROOT3 0x78
+#define RIVA_PMU_CLK_ROOT3_ENA BIT(0)
+#define RIVA_PMU_CLK_ROOT3_SRC0_DIV 0x3C
+#define RIVA_PMU_CLK_ROOT3_SRC0_DIV_2 (1 << 2)
+#define RIVA_PMU_CLK_ROOT3_SRC0_SEL 0x1C0
+#define RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA (1 << 6)
+#define RIVA_PMU_CLK_ROOT3_SRC1_DIV 0x1E00
+#define RIVA_PMU_CLK_ROOT3_SRC1_DIV_2 (1 << 9)
+#define RIVA_PMU_CLK_ROOT3_SRC1_SEL 0xE000
+#define RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA (1 << 13)
+
+struct riva_data {
+ void __iomem *base;
+ unsigned long start_addr;
+ struct msm_xo_voter *xo;
+ struct timer_list xo_timer;
+};
+
+static void pil_riva_make_xo_proxy_votes(struct device *dev)
+{
+ struct riva_data *drv = dev_get_drvdata(dev);
+
+ msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
+ mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+}
+
+static void pil_riva_remove_xo_proxy_votes(unsigned long data)
+{
+ struct riva_data *drv = (struct riva_data *)data;
+
+ msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
+}
+
+static void pil_riva_remove_xo_proxy_votes_now(struct device *dev)
+{
+ struct riva_data *drv = dev_get_drvdata(dev);
+
+ if (del_timer(&drv->xo_timer))
+ pil_riva_remove_xo_proxy_votes((unsigned long)drv);
+}
+
+static bool cxo_is_needed(struct riva_data *drv)
+{
+ u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
+ return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
+ != RIVA_PMU_CFG_IRIS_XO_MODE_48;
+}
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+ return 0;
+}
+
+static int pil_riva_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+ struct riva_data *drv = dev_get_drvdata(pil->dev);
+ drv->start_addr = ehdr->e_entry;
+ return 0;
+}
+
+static int pil_riva_reset(struct pil_desc *pil)
+{
+ u32 reg, sel;
+ bool use_cxo;
+ struct riva_data *drv = dev_get_drvdata(pil->dev);
+ void __iomem *base = drv->base;
+ unsigned long start_addr = drv->start_addr;
+
+ /* Enable A2XB bridge */
+ reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
+ reg |= RIVA_PMU_A2XB_CFG_EN;
+ writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
+
+ /* Proxy-vote for CXO if it's needed */
+ use_cxo = cxo_is_needed(drv);
+ if (use_cxo)
+ pil_riva_make_xo_proxy_votes(pil->dev);
+
+ /* Program PLL 13 to 960 MHz */
+ reg = readl_relaxed(RIVA_PLL_MODE);
+ reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
+ writel_relaxed(reg, RIVA_PLL_MODE);
+
+ if (use_cxo)
+ writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
+ else
+ writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
+ writel_relaxed(0, RIVA_PLL_M_VAL);
+ writel_relaxed(1, RIVA_PLL_N_VAL);
+ writel_relaxed(0x01495227, RIVA_PLL_CONFIG);
+
+ reg = readl_relaxed(RIVA_PLL_MODE);
+ reg &= ~(PLL_MODE_REF_XO_SEL);
+ reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
+ writel_relaxed(reg, RIVA_PLL_MODE);
+
+ /* Enable PLL 13 */
+ reg |= PLL_MODE_BYPASSNL;
+ writel_relaxed(reg, RIVA_PLL_MODE);
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ mb();
+ usleep_range(10, 20);
+
+ reg |= PLL_MODE_RESET_N;
+ writel_relaxed(reg, RIVA_PLL_MODE);
+ reg |= PLL_MODE_OUTCTRL;
+ writel_relaxed(reg, RIVA_PLL_MODE);
+
+ /* Wait for PLL to settle */
+ mb();
+ usleep_range(50, 100);
+
+ /* Configure cCPU for 240 MHz */
+ sel = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
+ reg = readl_relaxed(base + RIVA_PMU_CLK_ROOT3);
+ if (sel & RIVA_PMU_ROOT_CLK_SEL_3) {
+ reg &= ~(RIVA_PMU_CLK_ROOT3_SRC0_SEL |
+ RIVA_PMU_CLK_ROOT3_SRC0_DIV);
+ reg |= RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA |
+ RIVA_PMU_CLK_ROOT3_SRC0_DIV_2;
+ } else {
+ reg &= ~(RIVA_PMU_CLK_ROOT3_SRC1_SEL |
+ RIVA_PMU_CLK_ROOT3_SRC1_DIV);
+ reg |= RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA |
+ RIVA_PMU_CLK_ROOT3_SRC1_DIV_2;
+ }
+ writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
+ reg |= RIVA_PMU_CLK_ROOT3_ENA;
+ writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
+ reg = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
+ reg ^= RIVA_PMU_ROOT_CLK_SEL_3;
+ writel_relaxed(reg, base + RIVA_PMU_ROOT_CLK_SEL);
+
+ /* Use the high vector table */
+ reg = readl_relaxed(base + RIVA_PMU_CCPU_CTL);
+ reg |= RIVA_PMU_CCPU_CTL_HIGH_IVT | RIVA_PMU_CCPU_CTL_REMAP_EN;
+ writel_relaxed(reg, base + RIVA_PMU_CCPU_CTL);
+
+ /* Set base memory address */
+ writel_relaxed(start_addr >> 16, base + RIVA_PMU_CCPU_BOOT_REMAP_ADDR);
+
+ /* Clear warmboot bit indicating this is a cold boot */
+ reg = readl_relaxed(base + RIVA_PMU_CFG);
+ reg &= ~(RIVA_PMU_CFG_WARM_BOOT);
+ writel_relaxed(reg, base + RIVA_PMU_CFG);
+
+ /* Enable the cCPU clock */
+ reg = readl_relaxed(base + RIVA_PMU_OVRD_VAL);
+ reg |= RIVA_PMU_OVRD_VAL_CCPU_CLK;
+ writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+
+ /* Take cCPU out of reset */
+ reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
+ writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+
+ return 0;
+}
+
+static int pil_riva_shutdown(struct pil_desc *pil)
+{
+ struct riva_data *drv = dev_get_drvdata(pil->dev);
+ u32 reg;
+
+ reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
+ reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
+ writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
+
+ pil_riva_remove_xo_proxy_votes_now(pil->dev);
+
+ return 0;
+}
+
+static struct pil_reset_ops pil_riva_ops = {
+ .init_image = pil_riva_init_image,
+ .verify_blob = nop_verify_blob,
+ .auth_and_reset = pil_riva_reset,
+ .shutdown = pil_riva_shutdown,
+};
+
+static int pil_riva_init_image_trusted(struct pil_desc *pil,
+ const u8 *metadata, size_t size)
+{
+ return pas_init_image(PAS_RIVA, metadata, size);
+}
+
+static int pil_riva_reset_trusted(struct pil_desc *pil)
+{
+ struct riva_data *drv = dev_get_drvdata(pil->dev);
+
+ /* Proxy-vote for CXO if it's needed */
+ if (cxo_is_needed(drv))
+ pil_riva_make_xo_proxy_votes(pil->dev);
+
+ return pas_auth_and_reset(PAS_RIVA);
+}
+
+static int pil_riva_shutdown_trusted(struct pil_desc *pil)
+{
+ int ret = pas_shutdown(PAS_RIVA);
+
+ pil_riva_remove_xo_proxy_votes_now(pil->dev);
+
+ return ret;
+}
+
+static struct pil_reset_ops pil_riva_ops_trusted = {
+ .init_image = pil_riva_init_image_trusted,
+ .verify_blob = nop_verify_blob,
+ .auth_and_reset = pil_riva_reset_trusted,
+ .shutdown = pil_riva_shutdown_trusted,
+};
+
+static int __devinit pil_riva_probe(struct platform_device *pdev)
+{
+ struct riva_data *drv;
+ struct resource *res;
+ struct pil_desc *desc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->base)
+ return -ENOMEM;
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->name = "wcnss";
+ desc->dev = &pdev->dev;
+
+ if (pas_supported(PAS_RIVA) > 0) {
+ desc->ops = &pil_riva_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_riva_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+
+ setup_timer(&drv->xo_timer, pil_riva_remove_xo_proxy_votes,
+ (unsigned long)drv);
+ drv->xo = msm_xo_get(MSM_XO_CXO, desc->name);
+ if (IS_ERR(drv->xo))
+ return PTR_ERR(drv->xo);
+
+ return msm_pil_register(desc);
+}
+
+static int __devexit pil_riva_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver pil_riva_driver = {
+ .probe = pil_riva_probe,
+ .remove = __devexit_p(pil_riva_remove),
+ .driver = {
+ .name = "pil_riva",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_riva_init(void)
+{
+ return platform_driver_register(&pil_riva_driver);
+}
+module_init(pil_riva_init);
+
+static void __exit pil_riva_exit(void)
+{
+ platform_driver_unregister(&pil_riva_driver);
+}
+module_exit(pil_riva_exit);
+
+MODULE_DESCRIPTION("Support for booting RIVA (WCNSS) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
new file mode 100644
index 0000000..90ac1d9
--- /dev/null
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+ return 0;
+}
+
+static int pil_tzapps_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ return pas_init_image(PAS_TZAPPS, metadata, size);
+}
+
+static int pil_tzapps_reset(struct pil_desc *pil)
+{
+ return pas_auth_and_reset(PAS_TZAPPS);
+}
+
+static int pil_tzapps_shutdown(struct pil_desc *pil)
+{
+ return pas_shutdown(PAS_TZAPPS);
+}
+
+static struct pil_reset_ops pil_tzapps_ops = {
+ .init_image = pil_tzapps_init_image,
+ .verify_blob = nop_verify_blob,
+ .auth_and_reset = pil_tzapps_reset,
+ .shutdown = pil_tzapps_shutdown,
+};
+
+static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
+{
+ struct pil_desc *desc;
+
+ if (pas_supported(PAS_TZAPPS) < 0)
+ return -ENOSYS;
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->name = "tzapps";
+ desc->dev = &pdev->dev;
+ desc->ops = &pil_tzapps_ops;
+ if (msm_pil_register(desc))
+ return -EINVAL;
+ return 0;
+}
+
+static int __devexit pil_tzapps_driver_exit(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver pil_tzapps_driver = {
+ .probe = pil_tzapps_driver_probe,
+ .remove = __devexit_p(pil_tzapps_driver_exit),
+ .driver = {
+ .name = "pil_tzapps",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_tzapps_init(void)
+{
+ return platform_driver_register(&pil_tzapps_driver);
+}
+module_init(pil_tzapps_init);
+
+static void __exit pil_tzapps_exit(void)
+{
+ platform_driver_unregister(&pil_tzapps_driver);
+}
+module_exit(pil_tzapps_exit);
+
+MODULE_DESCRIPTION("Support for booting TZApps images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 3f40a12..0838c2c 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
@@ -56,12 +57,14 @@
/* KraitMP or ScorpionMP ? */
if ((read_cpuid_id() & 0xFF0) >> 4 != 0x2D) {
- base_ptr = ioremap_nocache(0x02098000, SZ_4K);
+ base_ptr = ioremap_nocache(0x02088000 + (cpu * 0x10000), SZ_4K);
if (base_ptr) {
if (machine_is_msm8960_sim() ||
machine_is_msm8960_rumi3()) {
writel_relaxed(0x10, base_ptr+0x04);
writel_relaxed(0x80, base_ptr+0x04);
+ } else if (machine_is_apq8064_sim()) {
+ writel_relaxed(0xf0000, base_ptr+0x04);
} else if (get_core_count() == 2) {
writel_relaxed(0x109, base_ptr+0x04);
writel_relaxed(0x101, base_ptr+0x04);
@@ -95,6 +98,12 @@
}
DEFINE_PER_CPU(int, cold_boot_done);
+static int cold_boot_flags[] = {
+ 0,
+ SCM_FLAG_COLDBOOT_CPU1,
+ SCM_FLAG_COLDBOOT_CPU2,
+ SCM_FLAG_COLDBOOT_CPU3,
+};
/* Executed by primary CPU, brings other CPUs out of reset. Called at boot
as well as when a CPU is coming out of shutdown induced by echo 0 >
@@ -104,16 +113,22 @@
{
int cnt = 0;
int ret;
+ int flag = 0;
pr_debug("Starting secondary CPU %d\n", cpu);
/* Set preset_lpj to avoid subsequent lpj recalculations */
preset_lpj = loops_per_jiffy;
+ if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags))
+ flag = cold_boot_flags[cpu];
+ else
+ __WARN();
+
if (per_cpu(cold_boot_done, cpu) == false) {
ret = scm_set_boot_addr((void *)
virt_to_phys(msm_secondary_startup),
- SCM_FLAG_COLDBOOT_CPU1);
+ flag);
if (ret == 0)
release_secondary(cpu);
else
@@ -151,9 +166,7 @@
{
pr_debug("CPU%u: Booted secondary processor\n", cpu);
-#ifdef CONFIG_HOTPLUG_CPU
- WARN_ON(msm_pm_platform_secondary_init(cpu));
-#endif
+ WARN_ON(msm_platform_secondary_init(cpu));
trace_hardirqs_off();
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index f479dafb..adf5471 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -620,15 +620,6 @@
*
*****************************************************************************/
-struct msm_pm_device {
- unsigned int cpu;
-#ifdef CONFIG_HOTPLUG_CPU
- struct completion cpu_killed;
- unsigned int warm_boot;
-#endif
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_pm_device, msm_pm_devices);
static struct msm_rpmrs_limits *msm_pm_idle_rs_limits;
static void msm_pm_swfi(void)
@@ -656,7 +647,7 @@
#endif
static bool msm_pm_spm_power_collapse(
- struct msm_pm_device *dev, bool from_idle, bool notify_rpm)
+ unsigned int cpu, bool from_idle, bool notify_rpm)
{
void *entry;
bool collapsed = 0;
@@ -664,19 +655,19 @@
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
pr_info("CPU%u: %s: notify_rpm %d\n",
- dev->cpu, __func__, (int) notify_rpm);
+ cpu, __func__, (int) notify_rpm);
ret = msm_spm_set_low_power_mode(
MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
WARN_ON(ret);
- entry = (!dev->cpu || from_idle) ?
+ entry = (!cpu || from_idle) ?
msm_pm_collapse_exit : msm_secondary_startup;
- msm_pm_boot_config_before_pc(dev->cpu, virt_to_phys(entry));
+ msm_pm_boot_config_before_pc(cpu, virt_to_phys(entry));
if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
pr_info("CPU%u: %s: program vector to %p\n",
- dev->cpu, __func__, entry);
+ cpu, __func__, entry);
#ifdef CONFIG_VFP
vfp_flush_context();
@@ -684,7 +675,7 @@
collapsed = msm_pm_l2x0_power_collapse();
- msm_pm_boot_config_after_pc(dev->cpu);
+ msm_pm_boot_config_after_pc(cpu);
if (collapsed) {
#ifdef CONFIG_VFP
@@ -698,7 +689,7 @@
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
- dev->cpu, __func__, collapsed);
+ cpu, __func__, collapsed);
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
WARN_ON(ret);
@@ -707,60 +698,60 @@
static bool msm_pm_power_collapse_standalone(bool from_idle)
{
- struct msm_pm_device *dev = &__get_cpu_var(msm_pm_devices);
+ unsigned int cpu = smp_processor_id();
unsigned int avsdscr_setting;
bool collapsed;
avsdscr_setting = avs_get_avsdscr();
avs_disable();
- collapsed = msm_pm_spm_power_collapse(dev, from_idle, false);
+ collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
avs_reset_delays(avsdscr_setting);
return collapsed;
}
static bool msm_pm_power_collapse(bool from_idle)
{
- struct msm_pm_device *dev = &__get_cpu_var(msm_pm_devices);
+ unsigned int cpu = smp_processor_id();
unsigned long saved_acpuclk_rate;
unsigned int avsdscr_setting;
bool collapsed;
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
pr_info("CPU%u: %s: idle %d\n",
- dev->cpu, __func__, (int)from_idle);
+ cpu, __func__, (int)from_idle);
msm_pm_config_hw_before_power_down();
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: pre power down\n", dev->cpu, __func__);
+ pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
avsdscr_setting = avs_get_avsdscr();
avs_disable();
- if (cpu_online(dev->cpu))
+ if (cpu_online(cpu))
saved_acpuclk_rate = acpuclk_power_collapse();
else
saved_acpuclk_rate = 0;
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
- dev->cpu, __func__, saved_acpuclk_rate);
+ cpu, __func__, saved_acpuclk_rate);
- collapsed = msm_pm_spm_power_collapse(dev, from_idle, true);
+ collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: restore clock rate to %lu\n",
- dev->cpu, __func__, saved_acpuclk_rate);
- if (acpuclk_set_rate(dev->cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+ cpu, __func__, saved_acpuclk_rate);
+ if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
- dev->cpu, __func__, saved_acpuclk_rate);
+ cpu, __func__, saved_acpuclk_rate);
avs_reset_delays(avsdscr_setting);
msm_pm_config_hw_after_power_up();
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: post power up\n", dev->cpu, __func__);
+ pr_info("CPU%u: %s: post power up\n", cpu, __func__);
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: return\n", dev->cpu, __func__);
+ pr_info("CPU%u: %s: return\n", cpu, __func__);
return collapsed;
}
@@ -962,6 +953,31 @@
return 0;
}
+void msm_pm_cpu_enter_lowpower(unsigned int cpu)
+{
+ int i;
+ bool allow[MSM_PM_SLEEP_MODE_NR];
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ struct msm_pm_platform_data *mode;
+
+ mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
+ allow[i] = mode->suspend_supported && mode->suspend_enabled;
+ }
+
+ if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
+ pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+ msm_pm_power_collapse(false);
+ else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
+ msm_pm_power_collapse_standalone(false);
+ else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
+ msm_pm_swfi();
+
+
+}
+
static int msm_pm_enter(suspend_state_t state)
{
bool allow[MSM_PM_SLEEP_MODE_NR];
@@ -1069,79 +1085,6 @@
.valid = suspend_valid_only_mem,
};
-#ifdef CONFIG_HOTPLUG_CPU
-int platform_cpu_disable(unsigned int cpu)
-{
- return cpu == 0 ? -EPERM : 0;
-}
-
-int platform_cpu_kill(unsigned int cpu)
-{
- struct completion *killed = &per_cpu(msm_pm_devices, cpu).cpu_killed;
- return wait_for_completion_timeout(killed, HZ * 5);
-}
-
-void platform_cpu_die(unsigned int cpu)
-{
- bool allow[MSM_PM_SLEEP_MODE_NR];
- int i;
-
- if (unlikely(cpu != smp_processor_id())) {
- pr_crit("%s: running on %u, should be %u\n",
- __func__, smp_processor_id(), cpu);
- BUG();
- }
-
- for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
- struct msm_pm_platform_data *mode;
-
- mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
- allow[i] = mode->suspend_supported && mode->suspend_enabled;
- }
-
- if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
- pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
- complete(&__get_cpu_var(msm_pm_devices).cpu_killed);
-
- flush_cache_all();
-
- for (;;) {
- if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
- msm_pm_power_collapse(false);
- else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
- msm_pm_power_collapse_standalone(false);
- else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
- msm_pm_swfi();
-
- if (pen_release == cpu) {
- /* OK, proper wakeup, we're done */
- break;
- }
- }
-
- pen_release = -1;
- pr_notice("CPU%u: %s: normal wakeup\n", cpu, __func__);
-}
-
-int msm_pm_platform_secondary_init(unsigned int cpu)
-{
- int ret;
- struct msm_pm_device *dev = &__get_cpu_var(msm_pm_devices);
-
- if (!dev->warm_boot) {
- dev->warm_boot = 1;
- return 0;
- }
- etm_restore_reg_check();
- msm_restore_jtag_debug();
-#ifdef CONFIG_VFP
- vfp_reinit();
-#endif
- ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
-
- return ret;
-}
-#endif /* CONFIG_HOTPLUG_CPU */
/******************************************************************************
* Initialization routine
@@ -1197,15 +1140,6 @@
return ret;
}
- for_each_possible_cpu(cpu) {
- struct msm_pm_device *dev = &per_cpu(msm_pm_devices, cpu);
-
- dev->cpu = cpu;
-#ifdef CONFIG_HOTPLUG_CPU
- init_completion(&dev->cpu_killed);
-#endif
- }
-
#ifdef CONFIG_MSM_IDLE_STATS
for_each_possible_cpu(cpu) {
struct msm_pm_time_stats *stats =
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index 6b92d1e..ce09f9f 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -36,6 +36,9 @@
flag = SCM_FLAG_WARMBOOT_CPU0;
else if (num_possible_cpus() == 2)
flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1;
+ else if (num_possible_cpus() == 4)
+ flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1 |
+ SCM_FLAG_WARMBOOT_CPU2 | SCM_FLAG_WARMBOOT_CPU3;
else
__WARN();
@@ -106,8 +109,6 @@
msm_pm_boot_after_pc = NULL;
break;
case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
- if (!pdata->p_addr)
- return -ENODEV;
pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
/* Fall through */
case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 8a7238a..185d542 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,7 @@
int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata);
#else
static inline int __init msm_pm_boot_init(
- struct msm_pm_boot_platform_data *pdata);
+ struct msm_pm_boot_platform_data *pdata)
{
return 0;
}
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index ad0bc7d..813ece1 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -22,7 +22,6 @@
#include <linux/cpuidle.h>
#ifdef CONFIG_SMP
-extern int pen_release;
extern void msm_secondary_startup(void);
#else
#define msm_secondary_startup NULL
@@ -55,13 +54,17 @@
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
int msm_pm_idle_prepare(struct cpuidle_device *dev);
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
+void msm_pm_cpu_enter_lowpower(unsigned int cpu);
#ifdef CONFIG_PM
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
-int msm_pm_platform_secondary_init(unsigned int cpu);
#else
static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
-static inline int msm_pm_platform_secondary_init(unsigned int cpu)
-{ return -ENOSYS; }
+#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+int msm_platform_secondary_init(unsigned int cpu);
+#else
+static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; }
#endif
#endif /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pmic8058-gpio.c b/arch/arm/mach-msm/pmic8058-gpio.c
deleted file mode 100644
index 63a26de..0000000
--- a/arch/arm/mach-msm/pmic8058-gpio.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-/*
- * Qualcomm PMIC8058 GPIO driver
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-
-#ifndef CONFIG_GPIOLIB
-#include "gpio_chip.h"
-#endif
-
-/* GPIO registers */
-#define SSBI_REG_ADDR_GPIO_BASE 0x150
-#define SSBI_REG_ADDR_GPIO(n) (SSBI_REG_ADDR_GPIO_BASE + n)
-
-/* GPIO */
-#define PM8058_GPIO_BANK_MASK 0x70
-#define PM8058_GPIO_BANK_SHIFT 4
-#define PM8058_GPIO_WRITE 0x80
-
-/* Bank 0 */
-#define PM8058_GPIO_VIN_MASK 0x0E
-#define PM8058_GPIO_VIN_SHIFT 1
-#define PM8058_GPIO_MODE_ENABLE 0x01
-
-/* Bank 1 */
-#define PM8058_GPIO_MODE_MASK 0x0C
-#define PM8058_GPIO_MODE_SHIFT 2
-#define PM8058_GPIO_OUT_BUFFER 0x02
-#define PM8058_GPIO_OUT_INVERT 0x01
-
-#define PM8058_GPIO_MODE_OFF 3
-#define PM8058_GPIO_MODE_OUTPUT 2
-#define PM8058_GPIO_MODE_INPUT 0
-#define PM8058_GPIO_MODE_BOTH 1
-
-/* Bank 2 */
-#define PM8058_GPIO_PULL_MASK 0x0E
-#define PM8058_GPIO_PULL_SHIFT 1
-
-/* Bank 3 */
-#define PM8058_GPIO_OUT_STRENGTH_MASK 0x0C
-#define PM8058_GPIO_OUT_STRENGTH_SHIFT 2
-#define PM8058_GPIO_PIN_ENABLE 0x00
-#define PM8058_GPIO_PIN_DISABLE 0x01
-
-/* Bank 4 */
-#define PM8058_GPIO_FUNC_MASK 0x0E
-#define PM8058_GPIO_FUNC_SHIFT 1
-
-/* Bank 5 */
-#define PM8058_GPIO_NON_INT_POL_INV 0x08
-#define PM8058_GPIO_BANKS 6
-
-struct pm8058_gpio_chip {
- struct gpio_chip gpio_chip;
- struct pm8058_chip *pm_chip;
- struct mutex pm_lock;
- u8 bank1[PM8058_GPIOS];
-};
-
-static int pm8058_gpio_get(struct pm8058_gpio_chip *chip, unsigned gpio)
-{
- struct pm8058_gpio_platform_data *pdata;
- int mode;
-
- if (gpio >= PM8058_GPIOS || chip == NULL)
- return -EINVAL;
-
- pdata = chip->gpio_chip.dev->platform_data;
-
- /* Get gpio value from config bank 1 if output gpio.
- Get gpio value from IRQ RT status register for all other gpio modes.
- */
- mode = (chip->bank1[gpio] & PM8058_GPIO_MODE_MASK) >>
- PM8058_GPIO_MODE_SHIFT;
- if (mode == PM8058_GPIO_MODE_OUTPUT)
- return chip->bank1[gpio] & PM8058_GPIO_OUT_INVERT;
- else
- return pm8058_irq_get_rt_status(chip->pm_chip,
- pdata->irq_base + gpio);
-}
-
-static int pm8058_gpio_set(struct pm8058_gpio_chip *chip,
- unsigned gpio, int value)
-{
- int rc;
- u8 bank1;
-
- if (gpio >= PM8058_GPIOS || chip == NULL)
- return -EINVAL;
-
- mutex_lock(&chip->pm_lock);
- bank1 = chip->bank1[gpio] & ~PM8058_GPIO_OUT_INVERT;
-
- if (value)
- bank1 |= PM8058_GPIO_OUT_INVERT;
-
- chip->bank1[gpio] = bank1;
- rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_GPIO(gpio), &bank1, 1);
- mutex_unlock(&chip->pm_lock);
-
- if (rc)
- pr_err("%s: FAIL pm8058_write(): rc=%d. "
- "(gpio=%d, value=%d)\n",
- __func__, rc, gpio, value);
-
- return rc;
-}
-
-static int pm8058_gpio_set_direction(struct pm8058_gpio_chip *chip,
- unsigned gpio, int direction)
-{
- int rc;
- u8 bank1;
- static int dir_map[] = {
- PM8058_GPIO_MODE_OFF,
- PM8058_GPIO_MODE_OUTPUT,
- PM8058_GPIO_MODE_INPUT,
- PM8058_GPIO_MODE_BOTH,
- };
-
- if (!direction || chip == NULL)
- return -EINVAL;
-
- mutex_lock(&chip->pm_lock);
- bank1 = chip->bank1[gpio] & ~PM8058_GPIO_MODE_MASK;
-
- bank1 |= ((dir_map[direction] << PM8058_GPIO_MODE_SHIFT)
- & PM8058_GPIO_MODE_MASK);
-
- chip->bank1[gpio] = bank1;
- rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_GPIO(gpio), &bank1, 1);
- mutex_unlock(&chip->pm_lock);
-
- if (rc)
- pr_err("%s: Failed on pm8058_write(): rc=%d (GPIO config)\n",
- __func__, rc);
-
- return rc;
-}
-
-static int pm8058_gpio_init_bank1(struct pm8058_gpio_chip *chip)
-{
- int i, rc;
- u8 bank;
-
- for (i = 0; i < PM8058_GPIOS; i++) {
- bank = 1 << PM8058_GPIO_BANK_SHIFT;
- rc = pm8058_write(chip->pm_chip,
- SSBI_REG_ADDR_GPIO(i),
- &bank, 1);
- if (rc) {
- pr_err("%s: error setting bank\n", __func__);
- return rc;
- }
-
- rc = pm8058_read(chip->pm_chip,
- SSBI_REG_ADDR_GPIO(i),
- &chip->bank1[i], 1);
- if (rc) {
- pr_err("%s: error reading bank 1\n", __func__);
- return rc;
- }
- }
- return 0;
-}
-
-#ifndef CONFIG_GPIOLIB
-static int pm8058_gpio_configure(struct gpio_chip *chip,
- unsigned int gpio,
- unsigned long flags)
-{
- int rc = 0, direction;
- struct pm8058_gpio_chip *gpio_chip;
-
- gpio -= chip->start;
-
- if (flags & (GPIOF_INPUT | GPIOF_DRIVE_OUTPUT)) {
- direction = 0;
- if (flags & GPIOF_INPUT)
- direction |= PM_GPIO_DIR_IN;
- if (flags & GPIOF_DRIVE_OUTPUT)
- direction |= PM_GPIO_DIR_OUT;
-
- gpio_chip = dev_get_drvdata(chip->dev);
-
- if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) {
- if (flags & GPIOF_OUTPUT_HIGH)
- rc = pm8058_gpio_set(gpio_chip,
- gpio, 1);
- else
- rc = pm8058_gpio_set(gpio_chip,
- gpio, 0);
-
- if (rc) {
- pr_err("%s: FAIL pm8058_gpio_set(): rc=%d.\n",
- __func__, rc);
- goto bail_out;
- }
- }
-
- rc = pm8058_gpio_set_direction(gpio_chip,
- gpio, direction);
- if (rc)
- pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n",
- __func__, rc);
- }
-
-bail_out:
- return rc;
-}
-
-static int pm8058_gpio_get_irq_num(struct gpio_chip *chip,
- unsigned int gpio,
- unsigned int *irqp,
- unsigned long *irqnumflagsp)
-{
- struct pm8058_gpio_platform_data *pdata;
-
- pdata = chip->dev->platform_data;
- gpio -= chip->start;
- *irqp = pdata->irq_base + gpio;
- if (irqnumflagsp)
- *irqnumflagsp = 0;
- return 0;
-}
-
-static int pm8058_gpio_read(struct gpio_chip *chip, unsigned n)
-{
- struct pm8058_gpio_chip *gpio_chip;
-
- n -= chip->start;
- gpio_chip = dev_get_drvdata(chip->dev);
- return pm8058_gpio_get(gpio_chip, n);
-}
-
-static int pm8058_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
-{
- struct pm8058_gpio_chip *gpio_chip;
-
- n -= chip->start;
- gpio_chip = dev_get_drvdata(chip->dev);
- return pm8058_gpio_set(gpio_chip, n, on);
-}
-
-static struct pm8058_gpio_chip pm8058_gpio_chip = {
- .gpio_chip = {
- .configure = pm8058_gpio_configure,
- .get_irq_num = pm8058_gpio_get_irq_num,
- .read = pm8058_gpio_read,
- .write = pm8058_gpio_write,
- },
-};
-
-static int __devinit pm8058_gpio_probe(struct platform_device *pdev)
-{
- int rc = 0;
- struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
- mutex_init(&pm8058_gpio_chip.pm_lock);
- pm8058_gpio_chip.gpio_chip.dev = &pdev->dev;
- pm8058_gpio_chip.gpio_chip.start = pdata->gpio_base;
- pm8058_gpio_chip.gpio_chip.end = pdata->gpio_base +
- PM8058_GPIOS - 1;
- pm8058_gpio_chip.pm_chip = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, &pm8058_gpio_chip);
-
- rc = register_gpio_chip(&pm8058_gpio_chip.gpio_chip);
- if (!rc)
- goto bail;
-
- rc = pm8058_gpio_init_bank1(&pm8058_gpio_chip);
- if (rc)
- goto bail;
-
- if (pdata->init)
- rc = pdata->init();
-
-bail:
- if (rc)
- platform_set_drvdata(pdev, pm8058_gpio_chip.pm_chip);
-
- pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc);
- return rc;
-}
-
-static int __devexit pm8058_gpio_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-#else
-
-static int pm8058_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct pm8058_gpio_platform_data *pdata;
- pdata = chip->dev->platform_data;
- return pdata->irq_base + offset;
-}
-
-static int pm8058_gpio_read(struct gpio_chip *chip, unsigned offset)
-{
- struct pm8058_gpio_chip *gpio_chip;
- gpio_chip = dev_get_drvdata(chip->dev);
- return pm8058_gpio_get(gpio_chip, offset);
-}
-
-static void pm8058_gpio_write(struct gpio_chip *chip,
- unsigned offset, int val)
-{
- struct pm8058_gpio_chip *gpio_chip;
- gpio_chip = dev_get_drvdata(chip->dev);
- pm8058_gpio_set(gpio_chip, offset, val);
-}
-
-static int pm8058_gpio_direction_input(struct gpio_chip *chip,
- unsigned offset)
-{
- struct pm8058_gpio_chip *gpio_chip;
- gpio_chip = dev_get_drvdata(chip->dev);
- return pm8058_gpio_set_direction(gpio_chip, offset, PM_GPIO_DIR_IN);
-}
-
-static int pm8058_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset,
- int val)
-{
- struct pm8058_gpio_chip *gpio_chip;
- int ret;
-
- gpio_chip = dev_get_drvdata(chip->dev);
- ret = pm8058_gpio_set_direction(gpio_chip, offset, PM_GPIO_DIR_OUT);
- if (!ret)
- ret = pm8058_gpio_set(gpio_chip, offset, val);
-
- return ret;
-}
-
-static void pm8058_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
- static const char *cmode[] = { "in", "in/out", "out", "off" };
- struct pm8058_gpio_chip *gpio_chip = dev_get_drvdata(chip->dev);
- u8 mode, state, bank;
- const char *label;
- int i, j;
-
- for (i = 0; i < PM8058_GPIOS; i++) {
- label = gpiochip_is_requested(chip, i);
- mode = (gpio_chip->bank1[i] & PM8058_GPIO_MODE_MASK) >>
- PM8058_GPIO_MODE_SHIFT;
- state = pm8058_gpio_get(gpio_chip, i);
- seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
- " %s",
- chip->base + i,
- label ? label : "--",
- cmode[mode],
- state ? "hi" : "lo");
- for (j = 0; j < PM8058_GPIO_BANKS; j++) {
- bank = j << PM8058_GPIO_BANK_SHIFT;
- pm8058_write(gpio_chip->pm_chip,
- SSBI_REG_ADDR_GPIO(i),
- &bank, 1);
- pm8058_read(gpio_chip->pm_chip,
- SSBI_REG_ADDR_GPIO(i),
- &bank, 1);
- seq_printf(s, " 0x%02x", bank);
- }
- seq_printf(s, "\n");
- }
-}
-
-static struct pm8058_gpio_chip pm8058_gpio_chip = {
- .gpio_chip = {
- .label = "pm8058-gpio",
- .direction_input = pm8058_gpio_direction_input,
- .direction_output = pm8058_gpio_direction_output,
- .to_irq = pm8058_gpio_to_irq,
- .get = pm8058_gpio_read,
- .set = pm8058_gpio_write,
- .dbg_show = pm8058_gpio_dbg_show,
- .ngpio = PM8058_GPIOS,
- .can_sleep = 1,
- },
-};
-
-static int __devinit pm8058_gpio_probe(struct platform_device *pdev)
-{
- int ret;
- struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
- mutex_init(&pm8058_gpio_chip.pm_lock);
- pm8058_gpio_chip.gpio_chip.dev = &pdev->dev;
- pm8058_gpio_chip.gpio_chip.base = pdata->gpio_base;
- pm8058_gpio_chip.pm_chip = dev_get_drvdata(pdev->dev.parent);
- platform_set_drvdata(pdev, &pm8058_gpio_chip);
-
- ret = gpiochip_add(&pm8058_gpio_chip.gpio_chip);
- if (ret)
- goto unset_drvdata;
-
- ret = pm8058_gpio_init_bank1(&pm8058_gpio_chip);
- if (ret)
- goto remove_chip;
-
- if (pdata->init)
- ret = pdata->init();
- if (!ret)
- goto ok;
-
-remove_chip:
- if (gpiochip_remove(&pm8058_gpio_chip.gpio_chip))
- pr_err("%s: failed to remove gpio chip\n", __func__);
-unset_drvdata:
- platform_set_drvdata(pdev, pm8058_gpio_chip.pm_chip);
-ok:
- pr_info("%s: gpiochip_add(): rc=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int __devexit pm8058_gpio_remove(struct platform_device *pdev)
-{
- return gpiochip_remove(&pm8058_gpio_chip.gpio_chip);
-}
-
-#endif
-
-int pm8058_gpio_config(int gpio, struct pm8058_gpio *param)
-{
- int rc;
- u8 bank[8];
- static int dir_map[] = {
- PM8058_GPIO_MODE_OFF,
- PM8058_GPIO_MODE_OUTPUT,
- PM8058_GPIO_MODE_INPUT,
- PM8058_GPIO_MODE_BOTH,
- };
-
- if (param == NULL)
- return -EINVAL;
-
- /* Select banks and configure the gpio */
- bank[0] = PM8058_GPIO_WRITE |
- ((param->vin_sel << PM8058_GPIO_VIN_SHIFT) &
- PM8058_GPIO_VIN_MASK) |
- PM8058_GPIO_MODE_ENABLE;
- bank[1] = PM8058_GPIO_WRITE |
- ((1 << PM8058_GPIO_BANK_SHIFT) &
- PM8058_GPIO_BANK_MASK) |
- ((dir_map[param->direction] <<
- PM8058_GPIO_MODE_SHIFT) &
- PM8058_GPIO_MODE_MASK) |
- ((param->direction & PM_GPIO_DIR_OUT) ?
- ((param->output_buffer & 1) ?
- PM8058_GPIO_OUT_BUFFER : 0) : 0) |
- ((param->direction & PM_GPIO_DIR_OUT) ?
- param->output_value & 0x01 : 0);
- bank[2] = PM8058_GPIO_WRITE |
- ((2 << PM8058_GPIO_BANK_SHIFT) &
- PM8058_GPIO_BANK_MASK) |
- ((param->pull << PM8058_GPIO_PULL_SHIFT) &
- PM8058_GPIO_PULL_MASK);
- bank[3] = PM8058_GPIO_WRITE |
- ((3 << PM8058_GPIO_BANK_SHIFT) &
- PM8058_GPIO_BANK_MASK) |
- ((param->out_strength <<
- PM8058_GPIO_OUT_STRENGTH_SHIFT) &
- PM8058_GPIO_OUT_STRENGTH_MASK) |
- (param->disable_pin ?
- PM8058_GPIO_PIN_DISABLE : PM8058_GPIO_PIN_ENABLE);
- bank[4] = PM8058_GPIO_WRITE |
- ((4 << PM8058_GPIO_BANK_SHIFT) &
- PM8058_GPIO_BANK_MASK) |
- ((param->function << PM8058_GPIO_FUNC_SHIFT) &
- PM8058_GPIO_FUNC_MASK);
- bank[5] = PM8058_GPIO_WRITE |
- ((5 << PM8058_GPIO_BANK_SHIFT) & PM8058_GPIO_BANK_MASK) |
- (param->inv_int_pol ? 0 : PM8058_GPIO_NON_INT_POL_INV);
-
- mutex_lock(&pm8058_gpio_chip.pm_lock);
- /* Remember bank1 for later use */
- pm8058_gpio_chip.bank1[gpio] = bank[1];
- rc = pm8058_write(pm8058_gpio_chip.pm_chip,
- SSBI_REG_ADDR_GPIO(gpio), bank, 6);
- mutex_unlock(&pm8058_gpio_chip.pm_lock);
-
- if (rc)
- pr_err("%s: Failed on pm8058_write(): rc=%d (GPIO config)\n",
- __func__, rc);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8058_gpio_config);
-
-static struct platform_driver pm8058_gpio_driver = {
- .probe = pm8058_gpio_probe,
- .remove = __devexit_p(pm8058_gpio_remove),
- .driver = {
- .name = "pm8058-gpio",
- .owner = THIS_MODULE,
- },
-};
-
-#if defined(CONFIG_DEBUG_FS)
-
-#define DEBUG_MAX_RW_BUF 128
-#define DEBUG_MAX_FNAME 8
-
-static struct dentry *debug_dent;
-
-static char debug_read_buf[DEBUG_MAX_RW_BUF];
-static char debug_write_buf[DEBUG_MAX_RW_BUF];
-
-static int debug_gpios[PM8058_GPIOS];
-
-static int debug_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static int debug_read_gpio_bank(int gpio, int bank, u8 *data)
-{
- int rc;
-
- mutex_lock(&pm8058_gpio_chip.pm_lock);
-
- *data = bank << PM8058_GPIO_BANK_SHIFT;
- rc = pm8058_write(pm8058_gpio_chip.pm_chip,
- SSBI_REG_ADDR_GPIO(gpio), data, 1);
- if (rc)
- goto bail_out;
-
- *data = bank << PM8058_GPIO_BANK_SHIFT;
- rc = pm8058_read(pm8058_gpio_chip.pm_chip,
- SSBI_REG_ADDR_GPIO(gpio), data, 1);
-
-bail_out:
- mutex_unlock(&pm8058_gpio_chip.pm_lock);
-
- return rc;
-}
-
-static ssize_t debug_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int gpio = *((int *) file->private_data);
- int len = 0;
- int rc = -EINVAL;
- u8 bank[PM8058_GPIO_BANKS];
- int val = -1;
- int mode;
- int i;
-
- for (i = 0; i < PM8058_GPIO_BANKS; i++) {
- rc = debug_read_gpio_bank(gpio, i, &bank[i]);
- if (rc)
- pr_err("pmic failed to read bank %d\n", i);
- }
-
- if (rc) {
- len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1, "-1\n");
- goto bail_out;
- }
-
- val = pm8058_gpio_get(&pm8058_gpio_chip, gpio);
-
- /* print the mode and the value */
- mode = (bank[1] & PM8058_GPIO_MODE_MASK) >> PM8058_GPIO_MODE_SHIFT;
- if (mode == PM8058_GPIO_MODE_BOTH)
- len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "BOTH %d ", val);
- else if (mode == PM8058_GPIO_MODE_INPUT)
- len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "IN %d ", val);
- else if (mode == PM8058_GPIO_MODE_OUTPUT)
- len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "OUT %d ", val);
- else
- len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "OFF %d ", val);
-
- /* print the control register values */
- len += snprintf(debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- "[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n",
- bank[0], bank[1], bank[2], bank[3], bank[4], bank[5]);
-
-bail_out:
- rc = simple_read_from_buffer((void __user *) buf, len,
- ppos, (void *) debug_read_buf, len);
-
- return rc;
-}
-
-static ssize_t debug_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- int gpio = *((int *) file->private_data);
- unsigned long val;
- int mode, rc;
-
- mode = (pm8058_gpio_chip.bank1[gpio] & PM8058_GPIO_MODE_MASK) >>
- PM8058_GPIO_MODE_SHIFT;
- if (mode == PM8058_GPIO_MODE_OFF || mode == PM8058_GPIO_MODE_INPUT)
- return count;
-
- if (count > sizeof(debug_write_buf))
- return -EFAULT;
-
- if (copy_from_user(debug_write_buf, buf, count)) {
- pr_err("failed to copy from user\n");
- return -EFAULT;
- }
- debug_write_buf[count] = '\0';
-
- rc = strict_strtoul(debug_write_buf, 10, &val);
- if (rc)
- return rc;
-
- if (pm8058_gpio_set(&pm8058_gpio_chip, gpio, val)) {
- pr_err("gpio write failed\n");
- return -EINVAL;
- }
-
- return count;
-}
-
-static const struct file_operations debug_ops = {
- .open = debug_open,
- .read = debug_read,
- .write = debug_write,
-};
-
-static void debug_init(void)
-{
- int i;
- char name[DEBUG_MAX_FNAME];
-
- debug_dent = debugfs_create_dir("pm_gpio", NULL);
- if (IS_ERR(debug_dent)) {
- pr_err("pmic8058 debugfs_create_dir fail, error %ld\n",
- PTR_ERR(debug_dent));
- return;
- }
-
- for (i = 0; i < PM8058_GPIOS; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "%d", i+1);
- debug_gpios[i] = i;
- if (debugfs_create_file(name, 0644, debug_dent,
- &debug_gpios[i], &debug_ops) == NULL) {
- pr_err("pmic8058 debugfs_create_file %s failed\n",
- name);
- }
- }
-}
-
-static void debug_exit(void)
-{
- debugfs_remove_recursive(debug_dent);
-}
-
-#else
-static void debug_init(void) { }
-static void debug_exit(void) { }
-#endif
-
-static int __init pm8058_gpio_init(void)
-{
- int rc = platform_driver_register(&pm8058_gpio_driver);
- if (!rc)
- debug_init();
- return rc;
-}
-
-static void __exit pm8058_gpio_exit(void)
-{
- platform_driver_unregister(&pm8058_gpio_driver);
- debug_exit();
-}
-
-subsys_initcall(pm8058_gpio_init);
-module_exit(pm8058_gpio_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 GPIO driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8058-gpio");
diff --git a/arch/arm/mach-msm/pmic8058-mpp.c b/arch/arm/mach-msm/pmic8058-mpp.c
deleted file mode 100644
index 78a132a5..0000000
--- a/arch/arm/mach-msm/pmic8058-mpp.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-/*
- * Qualcomm PMIC8058 MPP driver
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/mfd/pmic8058.h>
-#include <mach/mpp.h>
-#include <linux/seq_file.h>
-
-#ifndef CONFIG_GPIOLIB
-#include "gpio_chip.h"
-#endif
-
-/* MPP Control Registers */
-#define SSBI_MPP_CNTRL_BASE 0x50
-#define SSBI_MPP_CNTRL(n) (SSBI_MPP_CNTRL_BASE + (n))
-
-/* MPP Type */
-#define PM8058_MPP_TYPE_MASK 0xE0
-#define PM8058_MPP_TYPE_SHIFT 5
-
-/* MPP Config Level */
-#define PM8058_MPP_CONFIG_LVL_MASK 0x1C
-#define PM8058_MPP_CONFIG_LVL_SHIFT 2
-
-/* MPP Config Control */
-#define PM8058_MPP_CONFIG_CTL_MASK 0x03
-
-static int pm8058_mpp_get(struct gpio_chip *chip, unsigned mpp)
-{
- struct pm8058_gpio_platform_data *pdata;
- struct pm8058_chip *pm_chip;
-
- if (mpp >= PM8058_MPPS || chip == NULL)
- return -EINVAL;
-
- pdata = chip->dev->platform_data;
- pm_chip = dev_get_drvdata(chip->dev->parent);
-
- return pm8058_irq_get_rt_status(pm_chip,
- pdata->irq_base + mpp);
-}
-
-#ifndef CONFIG_GPIOLIB
-static int pm8058_mpp_get_irq_num(struct gpio_chip *chip,
- unsigned int gpio,
- unsigned int *irqp,
- unsigned long *irqnumflagsp)
-{
- struct pm8058_gpio_platform_data *pdata;
-
- pdata = chip->dev->platform_data;
- gpio -= chip->start;
- *irqp = pdata->irq_base + gpio;
- if (irqnumflagsp)
- *irqnumflagsp = 0;
- return 0;
-}
-
-static int pm8058_mpp_read(struct gpio_chip *chip, unsigned n)
-{
- n -= chip->start;
- return pm8058_mpp_get(chip, n);
-}
-
-struct msm_gpio_chip pm8058_mpp_chip = {
- .chip = {
- .get_irq_num = pm8058_mpp_get_irq_num,
- .read = pm8058_mpp_read,
- }
-};
-
-int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
- unsigned control)
-{
- u8 config;
- int rc;
- struct pm8058_chip *pm_chip;
-
- if (mpp >= PM8058_MPPS)
- return -EINVAL;
-
- pm_chip = dev_get_drvdata(pm8058_mpp_chip->dev->parent);
-
- config = (type << PM8058_MPP_TYPE_SHIFT) & PM8058_MPP_TYPE_MASK;
- config |= (level << PM8058_MPP_CONFIG_LVL_SHIFT) &
- PM8058_MPP_CONFIG_LVL_MASK;
- config |= control & PM8058_MPP_CONFIG_CTL_MASK;
-
- rc = pm8058_write(pm_chip, SSBI_MPP_CNTRL(mpp), &config, 1);
- if (rc)
- pr_err("%s: pm8058_write(): rc=%d\n", __func__, rc);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8058_mpp_config);
-
-static int __devinit pm8058_mpp_probe(struct platform_device *pdev)
-{
- int rc;
- struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
- pm8058_mpp_chip.chip.dev = &pdev->dev;
- pm8058_mpp_chip.chip.start = pdata->gpio_base;
- pm8058_mpp_chip.chip.end = pdata->gpio_base + PM8058_MPPS - 1;
- rc = register_gpio_chip(&pm8058_mpp_chip.chip);
- if (!rc) {
- if (pdata->init)
- ret = pdata->init();
- }
- pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static int __devexit pm8058_mpp_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-#else
-
-static int pm8058_mpp_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct pm8058_gpio_platform_data *pdata;
- pdata = chip->dev->platform_data;
- return pdata->irq_base + offset;
-}
-
-static int pm8058_mpp_read(struct gpio_chip *chip, unsigned offset)
-{
- return pm8058_mpp_get(chip, offset);
-}
-
-static void pm8058_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
- static const char *ctype[] = { "d_in", "d_out", "bi_dir", "a_in",
- "a_out", "sink", "dtest_sink", "dtest_out" };
- struct pm8058_chip *pm_chip = dev_get_drvdata(chip->dev->parent);
- u8 type, state, ctrl;
- const char *label;
- int i;
-
- for (i = 0; i < PM8058_MPPS; i++) {
- pm8058_read(pm_chip, SSBI_MPP_CNTRL(i), &ctrl, 1);
- label = gpiochip_is_requested(chip, i);
- type = (ctrl & PM8058_MPP_TYPE_MASK) >>
- PM8058_MPP_TYPE_SHIFT;
- state = pm8058_mpp_get(chip, i);
- seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
- " %s 0x%02x\n",
- chip->base + i,
- label ? label : "--",
- ctype[type],
- state ? "hi" : "lo",
- ctrl);
- }
-}
-
-static struct gpio_chip pm8058_mpp_chip = {
- .label = "pm8058-mpp",
- .to_irq = pm8058_mpp_to_irq,
- .get = pm8058_mpp_read,
- .dbg_show = pm8058_mpp_dbg_show,
- .ngpio = PM8058_MPPS,
- .can_sleep = 1,
-};
-
-int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
- unsigned control)
-{
- u8 config;
- int rc;
- struct pm8058_chip *pm_chip;
-
- if (mpp >= PM8058_MPPS)
- return -EINVAL;
-
- pm_chip = dev_get_drvdata(pm8058_mpp_chip.dev->parent);
-
- config = (type << PM8058_MPP_TYPE_SHIFT) & PM8058_MPP_TYPE_MASK;
- config |= (level << PM8058_MPP_CONFIG_LVL_SHIFT) &
- PM8058_MPP_CONFIG_LVL_MASK;
- config |= control & PM8058_MPP_CONFIG_CTL_MASK;
-
- rc = pm8058_write(pm_chip, SSBI_MPP_CNTRL(mpp), &config, 1);
- if (rc)
- pr_err("%s: pm8058_write(): rc=%d\n", __func__, rc);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8058_mpp_config);
-
-static int __devinit pm8058_mpp_probe(struct platform_device *pdev)
-{
- int ret;
- struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
- pm8058_mpp_chip.dev = &pdev->dev;
- pm8058_mpp_chip.base = pdata->gpio_base;
- ret = gpiochip_add(&pm8058_mpp_chip);
- if (!ret) {
- if (pdata->init)
- ret = pdata->init();
- }
-
- pr_info("%s: gpiochip_add(): ret=%d\n", __func__, ret);
- return ret;
-}
-
-static int __devexit pm8058_mpp_remove(struct platform_device *pdev)
-{
- return gpiochip_remove(&pm8058_mpp_chip);
-}
-
-#endif
-
-static struct platform_driver pm8058_mpp_driver = {
- .probe = pm8058_mpp_probe,
- .remove = __devexit_p(pm8058_mpp_remove),
- .driver = {
- .name = "pm8058-mpp",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8058_mpp_init(void)
-{
- return platform_driver_register(&pm8058_mpp_driver);
-}
-
-static void __exit pm8058_mpp_exit(void)
-{
- platform_driver_unregister(&pm8058_mpp_driver);
-}
-
-subsys_initcall(pm8058_mpp_init);
-module_exit(pm8058_mpp_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 MPP driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8058-mpp");
-
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
index 6166de2..60b5c20 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
@@ -372,10 +372,8 @@
memset(&cmd, 0, sizeof(cmd));
if (audio->build_id[17] == '1') {
cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
- MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
} else {
cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
- MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
}
cmd.stream_id = audio->enc_id;
@@ -950,7 +948,7 @@
goto evt_error;
}
audio->build_id = socinfo_get_build_id();
- MM_ERR("build id used is = %s\n", audio->build_id);
+ MM_DBG("Modem build id = %s\n", audio->build_id);
file->private_data = audio;
audio->opened = 1;
rc = 0;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
index da77140..010fd90 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
@@ -575,7 +575,6 @@
{
struct audpreproc_audrec_cmd_enc_cfg cmd;
memset(&cmd, 0, sizeof(cmd));
- MM_ERR("build_id[17] = %c", audio->build_id[17]);
if (audio->build_id[17] == '1') {
cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
@@ -1412,9 +1411,8 @@
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
- MM_ERR("trying to get the build id\n");
audio->build_id = socinfo_get_build_id();
- MM_ERR("build id used is = %s\n", audio->build_id);
+ MM_DBG("Modem build id = %s\n", audio->build_id);
/* Initialize buffer */
audio->out[0].data = audio->out_data + 0;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
index ec275b4..90373f9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
@@ -3288,7 +3288,6 @@
result = acdb_initialize_data();
if (result)
goto done;
- MM_ERR("acdb_data.build_id[17] = %c\n", acdb_data.build_id[17]);
if (acdb_data.build_id[17] != '0') {
result = initialize_modem_acdb();
if (result < 0)
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index e1af44f..bdb5bb1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -863,7 +863,7 @@
goto evt_error;
}
audio->build_id = socinfo_get_build_id();
- MM_ERR("build id used is = %s\n", audio->build_id);
+ MM_DBG("Modem build id = %s\n", audio->build_id);
file->private_data = audio;
audio->opened = 1;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index c086153..50621c9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -1470,7 +1470,7 @@
audio->opened = 1;
audio->out_frame_cnt++;
audio->build_id = socinfo_get_build_id();
- MM_ERR("build id used is = %s\n", audio->build_id);
+ MM_DBG("Modem build id = %s\n", audio->build_id);
done:
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
index 43f3d26..a5a9bd2 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -638,7 +638,6 @@
rc = -EFAULT;
break;
}
- MM_ERR("build_id[17] = %c\n", audio->build_id[17]);
if (audio->build_id[17] == '1') {
audio->enc_type = ENC_TYPE_EXT_WAV | audio->mode;
if (cfg.channel_count == 1) {
@@ -683,7 +682,6 @@
MM_ERR("wrong build_id = %s\n", audio->build_id);
return -ENODEV;
}
- MM_ERR("buffer size configured is = %d\n", audio->buffer_size);
audio->samp_rate = cfg.sample_rate;
audio->channel_mode = cfg.channel_count;
break;
@@ -941,7 +939,7 @@
audio->opened = 1;
rc = 0;
audio->build_id = socinfo_get_build_id();
- MM_ERR("build id used is = %s\n", audio->build_id);
+ MM_DBG("Modem build id = %s\n", audio->build_id);
done:
mutex_unlock(&audio->lock);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index 11599f8..d34499d 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -1475,7 +1475,7 @@
audio->opened = 1;
audio->out_frame_cnt++;
audio->build_id = socinfo_get_build_id();
- MM_ERR("build id used is = %s\n", audio->build_id);
+ MM_DBG("Modem build id = %s\n", audio->build_id);
done:
mutex_unlock(&audio->lock);
return rc;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index 196808e..2ad7f86 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -21,8 +21,6 @@
#define MAX_NETWORKS 12
-#define ACDB_BLOCK_SIZE 4096
-#define NUM_VOCPROC_BLOCKS (3 * MAX_NETWORKS)
struct acdb_data {
struct mutex acdb_mutex;
@@ -200,26 +198,6 @@
return;
}
-void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers)
-{
- int i;
- pr_debug("%s\n", __func__);
-
- if (cal_buffers == NULL) {
- pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
- goto done;
- }
-
- for (i = 0; i < NUM_AUDPROC_BUFFERS; i++) {
- cal_buffers->phys_addr[i] = (uint32_t)
- (acdb_data.paddr +
- (NUM_VOCPROC_BLOCKS + i) * ACDB_BLOCK_SIZE);
- cal_buffers->buf_size[i] = ACDB_BLOCK_SIZE;
- }
-done:
- return;
-}
-
void store_audproc_cal(int32_t path, struct cal_block *cal_block)
{
pr_debug("%s, path = %d\n", __func__, path);
@@ -612,12 +590,9 @@
static int deregister_pmem(void)
{
int result;
- struct audproc_buffer_data buffer;
- get_audproc_buffer_data(&buffer);
-
- result = adm_memory_unmap_regions(buffer.phys_addr,
- buffer.buf_size, NUM_AUDPROC_BUFFERS);
+ result = adm_memory_unmap_regions((uint32_t *)&acdb_data.paddr,
+ (uint32_t *)&acdb_data.pmem_len, 1);
if (result < 0)
pr_err("Audcal unmap did not work!\n");
@@ -632,7 +607,6 @@
static int register_pmem(void)
{
int result;
- struct audproc_buffer_data buffer;
result = get_pmem_file(acdb_data.pmem_fd, &acdb_data.paddr,
&acdb_data.kvaddr, &acdb_data.pmem_len,
@@ -646,10 +620,8 @@
pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
"kvaddr = 0x%lx, len = x%lx\n", acdb_data.paddr,
acdb_data.kvaddr, acdb_data.pmem_len);
- get_audproc_buffer_data(&buffer);
- result = adm_memory_map_regions(buffer.phys_addr, 0,
- buffer.buf_size,
- NUM_AUDPROC_BUFFERS);
+ result = adm_memory_map_regions((uint32_t *)&acdb_data.paddr, 0,
+ (uint32_t *)&acdb_data.pmem_len, 1);
if (result < 0)
pr_err("Audcal mmap did not work!\n");
goto done;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
index d48df06..b60140e 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
#include "q6usm.h"
/* The driver version*/
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
#define SESSION_MAX 0x02 /* aDSP:USM limit */
@@ -40,9 +40,6 @@
/* Standard timeout in the asynchronous ops */
#define Q6USM_TIMEOUT_JIFFIES (3*HZ) /* 3 sec */
-/* cyclic buffer with 1 gap support */
-#define USM_MIN_BUF_CNT 3
-
static DEFINE_MUTEX(session_lock);
static struct us_client *session[SESSION_MAX];
@@ -236,8 +233,7 @@
if ((usc == NULL) ||
((dir != IN) && (dir != OUT)) || (size == 0) ||
- (usc->session <= 0 || usc->session > SESSION_MAX) ||
- (bufcnt < USM_MIN_BUF_CNT)) {
+ (usc->session <= 0 || usc->session > SESSION_MAX)) {
pr_err("%s: wrong parameters: size=%d; bufcnt=%d\n",
__func__, size, bufcnt);
return -EINVAL;
@@ -345,6 +341,7 @@
case USM_STREAM_CMD_OPEN_WRITE:
case USM_STREAM_CMD_SET_ENC_PARAM:
case USM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+ case USM_SESSION_CMD_SIGNAL_DETECT_MODE:
if (atomic_read(&usc->cmd_state)) {
atomic_set(&usc->cmd_state, 0);
wake_up(&usc->cmd_wait);
@@ -449,6 +446,14 @@
break;
} /* case USM_DATA_EVENT_WRITE_DONE */
+ case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT: {
+ pr_debug("%s: US detect result: result=%d",
+ __func__,
+ payload[0]);
+
+ break;
+ } /* case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT */
+
default:
pr_debug("%s: not supported code [0x%x]",
__func__, data->opcode);
@@ -1147,6 +1152,46 @@
return rc;
}
+int q6usm_set_us_detection(struct us_client *usc,
+ struct usm_session_cmd_detect_info *detect_info,
+ uint16_t detect_info_size)
+{
+ int rc = 0;
+
+ if ((usc == NULL) ||
+ (detect_info_size == 0) ||
+ (detect_info == NULL)) {
+ pr_err("%s: wrong input: usc=0x%p, inf_size=%d; info=0x%p",
+ __func__,
+ usc,
+ detect_info_size,
+ detect_info);
+ return -EINVAL;
+ }
+
+ q6usm_add_hdr(usc, &detect_info->hdr,
+ detect_info_size - APR_HDR_SIZE, true);
+
+ detect_info->hdr.opcode = USM_SESSION_CMD_SIGNAL_DETECT_MODE;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *)detect_info);
+ if (rc < 0) {
+ pr_err("%s:Comamnd signal detect failed\n", __func__);
+ return -EINVAL;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: CMD_SIGNAL_DETECT_MODE: timeout=%d\n",
+ __func__, Q6USM_TIMEOUT_JIFFIES);
+ } else
+ rc = 0;
+
+ return rc;
+}
+
static int __init q6usm_init(void)
{
pr_debug("%s\n", __func__);
@@ -1159,4 +1204,3 @@
MODULE_DESCRIPTION("Interface with QDSP6:USM");
MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index fe12ee1..1338e86 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,9 @@
#include <mach/qdsp6v2/apr_us.h>
+/* cyclic buffer with 1 gap support */
+#define USM_MIN_BUF_CNT 3
+
#define FORMAT_USPS_EPOS 0x00000000
#define FORMAT_USRAW 0x00000001
#define INVALID_FORMAT 0xffffffff
@@ -106,4 +109,8 @@
int q6usm_write(struct us_client *usc, uint32_t write_ind);
bool q6usm_is_write_buf_full(struct us_client *usc, uint32_t* free_region);
+int q6usm_set_us_detection(struct us_client *usc,
+ struct usm_session_cmd_detect_info *detect_info,
+ uint16_t detect_info_size);
+
#endif /* __Q6_USM_H__ */
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index bfe0006..bc0706e 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,7 +26,7 @@
#include "q6usm.h"
/* The driver version*/
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1.1"
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (3*HZ) /* 3 sec */
@@ -37,6 +37,9 @@
/* RX memory mapping flag */
#define USF_VM_WRITE 2
+/* Number of events, copied from the user space to kernel one */
+#define USF_EVENTS_PORTION_SIZE 20
+
/* The driver states */
enum usf_state_type {
USF_IDLE_STATE,
@@ -46,6 +49,13 @@
USF_ERROR_STATE
};
+/* The US detection status upon FW/HW based US detection results */
+enum usf_us_detect_type {
+ USF_US_DETECT_UNDEF,
+ USF_US_DETECT_YES,
+ USF_US_DETECT_NO
+};
+
struct usf_xx_type {
/* Name of the client - event calculator */
char client_name[USF_MAX_CLIENT_NAME_SIZE];
@@ -66,6 +76,8 @@
uint32_t prev_region;
/* Q6:USM's events handler */
void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
+ /* US detection result */
+ enum usf_us_detect_type us_detect_type;
/* User's update info isn't acceptable */
u8 user_upd_info_na;
};
@@ -127,6 +139,14 @@
wake_up(&usf_xx->wait);
break;
+ case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT:
+ usf_xx->us_detect_type = (payload[0]) ?
+ USF_US_DETECT_YES :
+ USF_US_DETECT_NO;
+
+ wake_up(&usf_xx->wait);
+ break;
+
case APR_BASIC_RSP_RESULT:
if (payload[1]) {
usf_xx->usf_state = USF_ERROR_STATE;
@@ -250,7 +270,7 @@
__func__);
kfree(usf_xx->encdec_cfg.params);
usf_xx->encdec_cfg.params = NULL;
- return -EINVAL;
+ return -EFAULT;
}
pr_debug("%s: params_size[%d]; params[%d,%d,%d,%d, %d]\n",
__func__,
@@ -330,7 +350,9 @@
input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_RIGHT) |
BIT_MASK(BTN_MIDDLE);
- input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ input_dev->relbit[0] = BIT_MASK(REL_X) |
+ BIT_MASK(REL_Y) |
+ BIT_MASK(REL_Z);
}
if (input_info->event_types & USF_KEYBOARD_EVENT) {
@@ -386,6 +408,7 @@
input_report_rel(input_if, REL_X, me->rels[0]);
input_report_rel(input_if, REL_Y, me->rels[1]);
+ input_report_rel(input_if, REL_Z, me->rels[2]);
input_report_key(input_if, BTN_LEFT,
me->buttons_states & USF_BUTTON_LEFT_MASK);
@@ -423,6 +446,9 @@
{
struct input_dev *input_if = NULL;
uint16_t ind = 0;
+ uint16_t events_num = 0;
+ struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
+ int rc = 0;
if ((usf_info == NULL) || (usf_info->input_if == NULL) ||
(event == NULL) || (!event_counter)) {
@@ -431,40 +457,49 @@
input_if = usf_info->input_if;
- for (ind = 0; ind < event_counter; ++ind) {
- event += ind;
- if (event->event_type & usf_info->event_types) {
- /* the event is supported */
- if (event->event_type & USF_TSC_EVENT) {
+ while (event_counter > 0) {
+ if (event_counter > USF_EVENTS_PORTION_SIZE) {
+ events_num = USF_EVENTS_PORTION_SIZE;
+ event_counter -= USF_EVENTS_PORTION_SIZE;
+ } else {
+ events_num = event_counter;
+ event_counter = 0;
+ }
+ rc = copy_from_user(usf_events,
+ event,
+ events_num * sizeof(struct usf_event_type));
+ if (rc) {
+ pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+ __func__, rc);
+ return;
+ }
+ for (ind = 0; ind < events_num; ++ind) {
+ struct usf_event_type *p_event = &usf_events[ind];
+ if (p_event->event_type & USF_TSC_EVENT) {
struct point_event_type *pe =
- &(event->event_data.point_event);
+ &(p_event->event_data.point_event);
if (pe->coordinates_type ==
- USF_PIX_COORDINATE) {
+ USF_PIX_COORDINATE)
notify_tsc_event(input_if,
- pe->coordinates[0],
- pe->coordinates[1],
- pe->pressure);
- } else
- pr_debug("%s: wrong coord type:%d\n",
- __func__,
- pe->coordinates_type);
-
+ pe->coordinates[0],
+ pe->coordinates[1],
+ pe->pressure);
+ else
+ pr_debug("%s: wrong coord type: %d",
+ __func__,
+ pe->coordinates_type);
continue;
}
-
- if (event->event_type & USF_MOUSE_EVENT) {
+ if (p_event->event_type & USF_MOUSE_EVENT) {
notify_mouse_event(input_if,
- &(event->event_data.mouse_event));
+ &(p_event->event_data.mouse_event));
continue;
}
-
- if (event->event_type & USF_KEYBOARD_EVENT) {
+ if (event->event_type & USF_KEYBOARD_EVENT)
notify_key_event(input_if,
&(event->event_data.key_event));
- continue;
- }
- } /* the event is supported */
- }
+ } /* loop in the portion */
+ } /* all events loop */
}
static int usf_start_tx(struct usf_xx_type *usf_xx)
@@ -473,16 +508,20 @@
pr_debug("%s: tx: q6usm_run; rc=%d\n", __func__, rc);
if (!rc) {
- /* supply all buffers */
- rc = q6usm_read(usf_xx->usc,
- usf_xx->buffer_count);
- pr_debug("%s: q6usm_read[%d]\n",
- __func__, rc);
+ if (usf_xx->buffer_count >= USM_MIN_BUF_CNT) {
+ /* supply all buffers */
+ rc = q6usm_read(usf_xx->usc,
+ usf_xx->buffer_count);
+ pr_debug("%s: q6usm_read[%d]\n",
+ __func__, rc);
- if (rc)
- pr_err("%s: buf read failed",
- __func__);
- else
+ if (rc)
+ pr_err("%s: buf read failed",
+ __func__);
+ else
+ usf_xx->usf_state =
+ USF_WORK_STATE;
+ } else
usf_xx->usf_state =
USF_WORK_STATE;
}
@@ -502,6 +541,109 @@
return rc;
} /* usf_start_rx */
+static int usf_set_us_detection(struct usf_type *usf, unsigned long arg)
+{
+ uint32_t timeout = 0;
+ struct us_detect_info_type detect_info;
+ struct usm_session_cmd_detect_info usm_detect_info;
+ struct usm_session_cmd_detect_info *p_usm_detect_info =
+ &usm_detect_info;
+ uint32_t detect_info_size = sizeof(struct usm_session_cmd_detect_info);
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+ int rc = copy_from_user(&detect_info,
+ (void *) arg,
+ sizeof(detect_info));
+
+ if (rc) {
+ pr_err("%s: copy detect_info from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
+ }
+
+ if (detect_info.us_detector != US_DETECT_FW) {
+ pr_err("%s: unsupported detector: %d\n",
+ __func__, detect_info.us_detector);
+ return -EINVAL;
+ }
+
+ if ((detect_info.params_data_size != 0) &&
+ (detect_info.params_data != NULL)) {
+ 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) {
+ pr_err("%s: detect_info[%d] allocation failed\n",
+ __func__, detect_info_size);
+ return -ENOMEM;
+ }
+ p_data = (uint8_t *)p_usm_detect_info +
+ sizeof(struct usm_session_cmd_detect_info);
+
+ rc = copy_from_user(p_data,
+ (void *)detect_info.params_data,
+ detect_info.params_data_size);
+ if (rc) {
+ pr_err("%s: copy params from user; rc=%d\n",
+ __func__, rc);
+ kfree(p_usm_detect_info);
+ return -EFAULT;
+ }
+ p_usm_detect_info->algorithm_cfg_size = detect_info_size;
+ } else
+ usm_detect_info.algorithm_cfg_size = 0;
+
+ p_usm_detect_info->detect_mode = detect_info.us_detect_mode;
+ p_usm_detect_info->skip_interval = detect_info.skip_time;
+
+ usf_xx->us_detect_type = USF_US_DETECT_UNDEF;
+
+ rc = q6usm_set_us_detection(usf_xx->usc,
+ 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);
+ return rc;
+ }
+
+ /* Get US detection result */
+ if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
+ wait_event(usf_xx->wait,
+ (usf_xx->us_detect_type !=
+ USF_US_DETECT_UNDEF));
+ } else {
+ if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
+ timeout = USF_TIMEOUT_JIFFIES;
+ else
+ timeout = detect_info.detect_timeout * HZ;
+
+ rc = wait_event_timeout(usf_xx->wait,
+ (usf_xx->us_detect_type !=
+ USF_US_DETECT_UNDEF),
+ timeout);
+ /* In the case of timeout, "no US" is assumed */
+ }
+
+ 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);
+
+ return rc;
+} /* usf_set_us_detection */
+
static int usf_set_tx_info(struct usf_type *usf, unsigned long arg)
{
struct us_tx_info_type config_tx;
@@ -512,9 +654,9 @@
sizeof(config_tx));
if (rc) {
- pr_err("%s: copy error[%d]\n",
+ pr_err("%s: copy config_tx from user; rc=%d\n",
__func__, rc);
- return -EINVAL;
+ return -EFAULT;
}
name = config_tx.us_xx_info.client_name;
@@ -554,13 +696,15 @@
rc = q6usm_enc_cfg_blk(usf_xx->usc,
&usf_xx->encdec_cfg);
- if (!rc) {
+ if (!rc &&
+ (config_tx.input_info.event_types != USF_NO_EVENT)) {
rc = register_input_device(usf,
&config_tx.input_info);
- if (!rc)
- usf_xx->usf_state = USF_CONFIGURED_STATE;
}
+ if (!rc)
+ usf_xx->usf_state = USF_CONFIGURED_STATE;
+
return rc;
} /* usf_set_tx_info */
@@ -573,9 +717,9 @@
sizeof(config_rx));
if (rc) {
- pr_err("%s: copy_from_user() failed[%d]\n",
+ pr_err("%s: copy config_rx from user; rc=%d\n",
__func__, rc);
- return -EINVAL;
+ return -EFAULT;
}
usf_xx->new_region = USM_UNDEF_TOKEN;
@@ -617,14 +761,15 @@
{
struct us_tx_update_info_type upd_tx_info;
unsigned long prev_jiffies = 0;
+ uint32_t timeout = 0;
struct usf_xx_type *usf_xx = &usf->usf_tx;
int rc = copy_from_user(&upd_tx_info, (void *) arg,
sizeof(upd_tx_info));
if (rc) {
- pr_err("%s: get_update: copy_from_user() failed[%d]\n",
- __func__, rc);
- return -EINVAL;
+ pr_err("%s: copy upd_tx_info from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
}
if (!usf_xx->user_upd_info_na) {
@@ -641,27 +786,43 @@
usf_xx->user_upd_info_na = 0;
/* Get data ready regions */
- prev_jiffies = jiffies;
- rc = wait_event_timeout(usf_xx->wait,
- (usf_xx->prev_region !=
- usf_xx->new_region) ||
- (usf_xx->usf_state !=
- USF_WORK_STATE),
- USF_TIMEOUT_JIFFIES);
+ if (upd_tx_info.timeout == USF_INFINITIVE_TIMEOUT) {
+ wait_event(usf_xx->wait,
+ (usf_xx->prev_region !=
+ usf_xx->new_region) ||
+ (usf_xx->usf_state !=
+ USF_WORK_STATE));
+ } else {
+ if (upd_tx_info.timeout == USF_NO_WAIT_TIMEOUT)
+ rc = (usf_xx->prev_region != usf_xx->new_region);
+ else {
+ if (upd_tx_info.timeout == USF_DEFAULT_TIMEOUT)
+ timeout = USF_TIMEOUT_JIFFIES;
+ else
+ timeout = upd_tx_info.timeout * HZ;
- if (!rc) {
- pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
- __func__, prev_jiffies, jiffies);
- pr_debug("%s: timeout. prev=%d; new=%d\n",
- __func__, usf_xx->prev_region,
- usf_xx->new_region);
- pr_debug("%s: timeout. free_region=%d;\n",
- __func__, upd_tx_info.free_region);
- if (usf_xx->prev_region ==
- usf_xx->new_region) {
- pr_err("%s:read data: timeout\n",
- __func__);
- return -ETIME;
+ prev_jiffies = jiffies;
+ rc = wait_event_timeout(usf_xx->wait,
+ (usf_xx->prev_region !=
+ usf_xx->new_region) ||
+ (usf_xx->usf_state !=
+ USF_WORK_STATE),
+ timeout);
+ }
+ if (!rc) {
+ pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
+ __func__, prev_jiffies, jiffies);
+ pr_debug("%s: timeout. prev=%d; new=%d\n",
+ __func__, usf_xx->prev_region,
+ usf_xx->new_region);
+ pr_debug("%s: timeout. free_region=%d;\n",
+ __func__, upd_tx_info.free_region);
+ if (usf_xx->prev_region ==
+ usf_xx->new_region) {
+ pr_err("%s:read data: timeout\n",
+ __func__);
+ return -ETIME;
+ }
}
}
@@ -672,14 +833,21 @@
}
upd_tx_info.ready_region = usf_xx->new_region;
- rc = copy_to_user((void __user *)arg, &upd_tx_info,
- sizeof(upd_tx_info));
+ usf_xx->prev_region = upd_tx_info.ready_region;
+
if (upd_tx_info.ready_region == USM_WRONG_TOKEN) {
pr_err("%s: TX path corrupted; prev=%d\n",
__func__, usf_xx->prev_region);
- rc = -EIO;
+ return -EIO;
}
- usf_xx->prev_region = upd_tx_info.ready_region;
+
+ rc = copy_to_user((void __user *)arg, &upd_tx_info,
+ sizeof(upd_tx_info));
+ if (rc) {
+ pr_err("%s: copy upd_tx_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
return rc;
} /* usf_get_tx_update */
@@ -691,9 +859,9 @@
sizeof(upd_rx_info));
if (rc) {
- pr_err("%s: get_update: copy_from_user() failed[%d]\n",
- __func__, rc);
- return -EINVAL;
+ pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+ __func__, rc);
+ return -EFAULT;
}
/* Send available data regions */
@@ -726,11 +894,17 @@
__func__,
usf_xx->usf_state);
rc = -EINTR;
- } else
+ } else {
rc = copy_to_user(
(void __user *)arg,
&upd_rx_info,
sizeof(upd_rx_info));
+ if (rc) {
+ pr_err("%s: copy rx_info to user; rc=%d\n",
+ __func__, rc);
+ rc = -EFAULT;
+ }
+ }
}
return rc;
@@ -863,6 +1037,19 @@
break;
} /* US_STOP_RX */
+ case US_SET_DETECTION: {
+ struct usf_xx_type *usf_xx = &usf->usf_tx;
+ if (usf_xx->usf_state == USF_WORK_STATE)
+ rc = usf_set_us_detection(usf, arg);
+ else {
+ pr_err("%s: set us detection: wrong state[%d]\n",
+ __func__,
+ usf_xx->usf_state);
+ rc = -EBADFD;
+ }
+ break;
+ } /* US_GET_TX_UPDATE */
+
default:
rc = -EINVAL;
break;
@@ -936,6 +1123,9 @@
usf->usf_tx.usf_state = USF_OPENED_STATE;
usf->usf_rx.usf_state = USF_OPENED_STATE;
+ usf->usf_tx.us_detect_type = USF_US_DETECT_UNDEF;
+ usf->usf_rx.us_detect_type = USF_US_DETECT_UNDEF;
+
pr_info("%s:usf in open\n", __func__);
return 0;
}
@@ -1003,4 +1193,3 @@
MODULE_DESCRIPTION("Ultrasound framework driver");
MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index c2c473b..b14c968 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -12,10 +12,14 @@
#ifndef __MACH_SCM_BOOT_H
#define __MACH_SCM_BOOT_H
-#define SCM_BOOT_ADDR 0x1
-#define SCM_FLAG_COLDBOOT_CPU1 0x1
-#define SCM_FLAG_WARMBOOT_CPU1 0x2
-#define SCM_FLAG_WARMBOOT_CPU0 0x4
+#define SCM_BOOT_ADDR 0x1
+#define SCM_FLAG_COLDBOOT_CPU1 0x01
+#define SCM_FLAG_COLDBOOT_CPU2 0x08
+#define SCM_FLAG_COLDBOOT_CPU3 0x20
+#define SCM_FLAG_WARMBOOT_CPU1 0x02
+#define SCM_FLAG_WARMBOOT_CPU0 0x04
+#define SCM_FLAG_WARMBOOT_CPU2 0x10
+#define SCM_FLAG_WARMBOOT_CPU3 0x40
int scm_set_boot_addr(void *addr, int flags);
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 5bbffd3..0a9b27c 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -10,12 +10,17 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "scm-pas: " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/clk.h>
#include <mach/scm.h>
#include <mach/socinfo.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include "scm-pas.h"
#define PAS_INIT_IMAGE_CMD 1
@@ -50,15 +55,89 @@
}
EXPORT_SYMBOL(pas_init_image);
+static struct msm_bus_paths scm_pas_bw_tbl[] = {
+ {
+ .vectors = (struct msm_bus_vectors[]){
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ },
+ },
+ .num_paths = 1,
+ },
+ {
+ .vectors = (struct msm_bus_vectors[]){
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ib = 492 * 8 * 1000000UL,
+ .ab = 492 * 8 * 100000UL,
+ },
+ },
+ .num_paths = 1,
+ },
+};
+
+static struct msm_bus_scale_pdata scm_pas_bus_pdata = {
+ .usecase = scm_pas_bw_tbl,
+ .num_usecases = ARRAY_SIZE(scm_pas_bw_tbl),
+ .name = "scm_pas",
+};
+
+static uint32_t scm_perf_client;
+static struct clk *scm_bus_clk;
+
+static DEFINE_MUTEX(scm_pas_bw_mutex);
+static int scm_pas_bw_count;
+
+static int scm_pas_enable_bw(void)
+{
+ int ret = 0;
+
+ if (!scm_perf_client || scm_bus_clk)
+ return -EINVAL;
+
+ mutex_lock(&scm_pas_bw_mutex);
+ if (!scm_pas_bw_count) {
+ ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
+ if (ret) {
+ pr_err("bandwidth request failed (%d)\n", ret);
+ } else {
+ ret = clk_enable(scm_bus_clk);
+ if (ret)
+ pr_err("clock enable failed\n");
+ }
+ }
+ if (ret)
+ msm_bus_scale_client_update_request(scm_perf_client, 0);
+ else
+ scm_pas_bw_count++;
+ mutex_unlock(&scm_pas_bw_mutex);
+ return ret;
+}
+
+static void scm_pas_disable_bw(void)
+{
+ mutex_lock(&scm_pas_bw_mutex);
+ if (scm_pas_bw_count-- == 1) {
+ msm_bus_scale_client_update_request(scm_perf_client, 0);
+ clk_disable(scm_bus_clk);
+ }
+ mutex_unlock(&scm_pas_bw_mutex);
+}
+
int pas_auth_and_reset(enum pas_id id)
{
- int ret;
+ int ret, bus_ret;
u32 proc = id, scm_ret = 0;
+ bus_ret = scm_pas_enable_bw();
ret = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &proc,
sizeof(proc), &scm_ret, sizeof(scm_ret));
if (ret)
- return ret;
+ scm_ret = ret;
+ if (!bus_ret)
+ scm_pas_disable_bw();
return scm_ret;
}
@@ -108,3 +187,22 @@
return ret_val;
}
EXPORT_SYMBOL(pas_supported);
+
+static int __init scm_pas_init(void)
+{
+ /* TODO: Remove once bus scaling driver is in place */
+ if (!cpu_is_apq8064())
+ scm_perf_client = msm_bus_scale_register_client(
+ &scm_pas_bus_pdata);
+ if (!scm_perf_client)
+ pr_warn("unable to register bus client\n");
+ scm_bus_clk = clk_get_sys("scm", "bus_clk");
+ if (!IS_ERR(scm_bus_clk)) {
+ clk_set_rate(scm_bus_clk, 64000000);
+ } else {
+ scm_bus_clk = NULL;
+ pr_warn("unable to get bus clock\n");
+ }
+ return 0;
+}
+module_init(scm_pas_init);
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
index 4a3f4c5..67a0992 100644
--- a/arch/arm/mach-msm/scm-pas.h
+++ b/arch/arm/mach-msm/scm-pas.h
@@ -16,14 +16,12 @@
PAS_MODEM,
PAS_Q6,
PAS_DSPS,
- PAS_PLAYREADY,
+ PAS_TZAPPS,
PAS_MODEM_SW,
PAS_MODEM_FW,
PAS_RIVA,
};
-#define PAS_TZAPPS PAS_PLAYREADY
-
extern int pas_init_image(enum pas_id id, const u8 *metadata, size_t size);
extern int pas_auth_and_reset(enum pas_id id);
extern int pas_shutdown(enum pas_id id);
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
index e249d06..2aaa41ea 100644
--- a/arch/arm/mach-msm/sdio_tty.c
+++ b/arch/arm/mach-msm/sdio_tty.c
@@ -18,6 +18,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
+#include <linux/debugfs.h>
#include <mach/sdio_al.h>
#define INPUT_SPEED 4800
@@ -77,10 +78,17 @@
enum sdio_tty_state sdio_tty_state;
int is_sdio_open;
int tty_open_count;
+ int total_rx;
+ int total_tx;
};
static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS];
+#ifdef CONFIG_DEBUG_FS
+struct dentry *sdio_tty_debug_root;
+struct dentry *sdio_tty_debug_info;
+#endif
+
#define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x)
/*
@@ -183,10 +191,11 @@
}
tty_flip_buffer_push(sdio_tty_drv->tty_str);
+ sdio_tty_drv->total_rx += read_avail;
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: End of read %d bytes for dev %s",
- __func__, read_avail,
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Rx: %d, "
+ "Total Rx = %d bytes for dev %s", __func__,
+ read_avail, sdio_tty_drv->total_rx,
sdio_tty_drv->tty_dev_name);
}
}
@@ -302,10 +311,11 @@
return 0;
}
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: End of function, "
- "dev=%s, len=%d bytes\n", __func__,
- sdio_tty_drv->tty_dev_name, len);
+ sdio_tty_drv->total_tx += len;
+ DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Tx: %d, "
+ "Total Tx = %d for dev %s", __func__, len,
+ sdio_tty_drv->total_tx, sdio_tty_drv->tty_dev_name);
return len;
}
@@ -407,8 +417,8 @@
return ret;
}
- pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) opened "
- "\n", __func__, sdio_tty_drv->sdio_ch_name);
+ pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) "
+ "opened\n", __func__, sdio_tty_drv->sdio_ch_name);
sdio_tty_drv->is_sdio_open = 1;
} else {
@@ -748,6 +758,39 @@
},
};
+#ifdef CONFIG_DEBUG_FS
+void sdio_tty_print_info(void)
+{
+ int i = 0;
+
+ for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+ if (sdio_tty[i] == NULL)
+ continue;
+ pr_info(SDIO_TTY_MODULE_NAME ": %s: Total Rx=%d, Tx = %d "
+ "for dev %s", __func__, sdio_tty[i]->total_rx,
+ sdio_tty[i]->total_tx, sdio_tty[i]->tty_dev_name);
+ }
+}
+
+static int tty_debug_info_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t tty_debug_info_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ sdio_tty_print_info();
+ return count;
+}
+
+const struct file_operations tty_debug_info_ops = {
+ .open = tty_debug_info_open,
+ .write = tty_debug_info_write,
+};
+#endif
+
/*
* Module Init.
*
@@ -763,6 +806,19 @@
pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register "
"failed", __func__);
}
+#ifdef CONFIG_DEBUG_FS
+ else {
+ sdio_tty_debug_root = debugfs_create_dir("sdio_tty", NULL);
+ if (sdio_tty_debug_root) {
+ sdio_tty_debug_info = debugfs_create_file(
+ "sdio_tty_debug",
+ S_IRUGO | S_IWUGO,
+ sdio_tty_debug_root,
+ NULL,
+ &tty_debug_info_ops);
+ }
+ }
+#endif
return ret;
};
@@ -774,6 +830,10 @@
*/
static void __exit sdio_tty_exit(void)
{
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(sdio_tty_debug_info);
+ debugfs_remove(sdio_tty_debug_root);
+#endif
platform_driver_unregister(&sdio_tty_pdrv);
}
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 691dad2..b31550a 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -31,6 +31,7 @@
#include <linux/ctype.h>
#include <linux/remote_spinlock.h>
#include <linux/uaccess.h>
+#include <linux/kfifo.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
#include <mach/system.h>
@@ -61,6 +62,7 @@
#define MODULE_NAME "msm_smd"
#define SMEM_VERSION 0x000B
#define SMD_VERSION 0x00020000
+#define SMSM_SNAPSHOT_CNT 64
uint32_t SMSM_NUM_ENTRIES = 8;
uint32_t SMSM_NUM_HOSTS = 3;
@@ -79,6 +81,7 @@
};
static struct smsm_shared_info smsm_info;
+struct kfifo smsm_snapshot_fifo;
struct smsm_size_info_type {
uint32_t num_hosts;
@@ -239,6 +242,7 @@
static LIST_HEAD(smd_ch_list_loopback);
static irqreturn_t smsm_irq_handler(int irq, void *data);
static void smd_fake_irq_handler(unsigned long arg);
+static void smsm_cb_snapshot(void);
static void notify_smsm_cb_clients_worker(struct work_struct *work);
static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
@@ -308,7 +312,7 @@
MSM_TRIG_A2DSPS_SMSM_INT;
}
- schedule_work(&smsm_cb_work);
+ smsm_cb_snapshot();
}
static inline void notify_modem_smd(void)
@@ -1955,6 +1959,14 @@
SMSM_NUM_HOSTS = smsm_size_info->num_hosts;
}
+ i = kfifo_alloc(&smsm_snapshot_fifo,
+ sizeof(uint32_t) * SMSM_NUM_ENTRIES * SMSM_SNAPSHOT_CNT,
+ GFP_KERNEL);
+ if (i) {
+ pr_err("%s: SMSM state fifo alloc failed %d\n", __func__, i);
+ return i;
+ }
+
if (!smsm_info.state) {
smsm_info.state = smem_alloc2(ID_SHARED_STATE,
SMSM_NUM_ENTRIES *
@@ -2024,6 +2036,31 @@
}
EXPORT_SYMBOL(smsm_reset_modem_cont);
+static void smsm_cb_snapshot(void)
+{
+ int n;
+ uint32_t new_state;
+ int ret;
+
+ ret = kfifo_avail(&smsm_snapshot_fifo);
+ if (ret < (SMSM_NUM_ENTRIES * 4)) {
+ pr_err("%s: SMSM snapshot full %d\n", __func__, ret);
+ return;
+ }
+
+ for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+ new_state = __raw_readl(SMSM_STATE_ADDR(n));
+
+ ret = kfifo_in(&smsm_snapshot_fifo,
+ &new_state, sizeof(new_state));
+ if (ret != sizeof(new_state)) {
+ pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+ return;
+ }
+ }
+ schedule_work(&smsm_cb_work);
+}
+
static irqreturn_t smsm_irq_handler(int irq, void *data)
{
unsigned long flags;
@@ -2039,7 +2076,9 @@
prev_smem_q6_apps_smsm = mux_val;
}
- schedule_work(&smsm_cb_work);
+ spin_lock_irqsave(&smem_lock, flags);
+ smsm_cb_snapshot();
+ spin_unlock_irqrestore(&smem_lock, flags);
return IRQ_HANDLED;
}
@@ -2097,7 +2136,7 @@
notify_other_smsm(SMSM_APPS_STATE, (old_apps ^ apps));
}
- schedule_work(&smsm_cb_work);
+ smsm_cb_snapshot();
}
spin_unlock_irqrestore(&smem_lock, flags);
return IRQ_HANDLED;
@@ -2212,35 +2251,41 @@
int n;
uint32_t new_state;
uint32_t state_changes;
+ int ret;
+ int snapshot_size = SMSM_NUM_ENTRIES * sizeof(uint32_t);
- mutex_lock(&smsm_lock);
-
- if (!smsm_states) {
- /* smsm not yet initialized */
- mutex_unlock(&smsm_lock);
+ if (!smd_initialized)
return;
- }
- for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
- state_info = &smsm_states[n];
- new_state = __raw_readl(SMSM_STATE_ADDR(n));
+ while (kfifo_len(&smsm_snapshot_fifo) >= snapshot_size) {
+ mutex_lock(&smsm_lock);
+ for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+ state_info = &smsm_states[n];
- if (new_state != state_info->last_value) {
- state_changes = state_info->last_value ^ new_state;
-
- list_for_each_entry(cb_info,
- &state_info->callbacks, cb_list) {
-
- if (cb_info->mask & state_changes)
- cb_info->notify(cb_info->data,
- state_info->last_value,
- new_state);
+ ret = kfifo_out(&smsm_snapshot_fifo, &new_state,
+ sizeof(new_state));
+ if (ret != sizeof(new_state)) {
+ pr_err("%s: snapshot underflow %d\n",
+ __func__, ret);
+ mutex_unlock(&smsm_lock);
+ return;
}
- state_info->last_value = new_state;
- }
- }
- mutex_unlock(&smsm_lock);
+ state_changes = state_info->last_value ^ new_state;
+ if (state_changes) {
+ list_for_each_entry(cb_info,
+ &state_info->callbacks, cb_list) {
+
+ if (cb_info->mask & state_changes)
+ cb_info->notify(cb_info->data,
+ state_info->last_value,
+ new_state);
+ }
+ state_info->last_value = new_state;
+ }
+ }
+ mutex_unlock(&smsm_lock);
+ }
}
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index d7602f2..b95a35c 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd_debug.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -18,6 +18,7 @@
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/ctype.h>
+#include <linux/jiffies.h>
#include <mach/msm_iomap.h>
@@ -246,6 +247,7 @@
uint32_t new_state;
};
static struct SMSM_CB_DATA smsm_cb_data;
+static struct completion smsm_cb_completion;
static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
{
@@ -253,6 +255,7 @@
smsm_cb_data.old_state = old_state;
smsm_cb_data.new_state = new_state;
smsm_cb_data.data = data;
+ complete_all(&smsm_cb_completion);
}
#define UT_EQ_INT(a, b) \
@@ -265,6 +268,16 @@
} \
do {} while (0)
+#define UT_GT_INT(a, b) \
+ if ((a) <= (b)) { \
+ i += scnprintf(buf + i, max - i, \
+ "%s:%d " #a "(%d) > " #b "(%d)\n", \
+ __func__, __LINE__, \
+ a, b); \
+ break; \
+ } \
+ do {} while (0)
+
#define SMSM_CB_TEST_INIT() \
do { \
smsm_cb_data.cb_count = 0; \
@@ -290,16 +303,21 @@
/* de-assert SMSM_SMD_INIT to trigger state update */
UT_EQ_INT(smsm_cb_data.cb_count, 0);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 1);
- UT_EQ_INT(smsm_cb_data.cb_count, 1);
UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, SMSM_SMDINIT);
UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, 0x0);
UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
/* re-assert SMSM_SMD_INIT to trigger state update */
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 2);
UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, 0x0);
UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, SMSM_SMDINIT);
@@ -310,8 +328,11 @@
UT_EQ_INT(ret, 2);
/* make sure state change doesn't cause any more callbacks */
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+ UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 2);
i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
@@ -329,28 +350,49 @@
UT_EQ_INT(ret, 1);
/* verify both callback bits work */
+ INIT_COMPLETION(smsm_cb_completion);
UT_EQ_INT(smsm_cb_data.cb_count, 0);
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 1);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 2);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 3);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 4);
/* deregister 1st callback */
ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_SMDINIT,
smsm_state_cb, (void *)0x1234);
UT_EQ_INT(ret, 1);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+ UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 4);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 5);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 6);
/* deregister 2nd callback */
@@ -359,8 +401,11 @@
UT_EQ_INT(ret, 2);
/* make sure state change doesn't cause any more callbacks */
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+ UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 6);
i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
@@ -378,12 +423,18 @@
UT_EQ_INT(ret, 0);
/* verify both callbacks work */
+ INIT_COMPLETION(smsm_cb_completion);
UT_EQ_INT(smsm_cb_data.cb_count, 0);
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 1);
UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
+ INIT_COMPLETION(smsm_cb_completion);
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+ UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+ msecs_to_jiffies(20)), 0);
UT_EQ_INT(smsm_cb_data.cb_count, 2);
UT_EQ_INT((int)smsm_cb_data.data, 0x3456);
@@ -599,7 +650,12 @@
size_t count, loff_t *ppos)
{
int (*fill)(char *buf, int max) = file->private_data;
- int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+ int bsize;
+
+ if (*ppos != 0)
+ return 0;
+
+ bsize = fill(debug_buffer, DEBUG_BUFMAX);
return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
}
@@ -659,6 +715,8 @@
debug_create("version", 0444, dent, debug_read_smem_version);
debug_create("smsm_test", 0444, dent, debug_test_smsm);
+ init_completion(&smsm_cb_completion);
+
return 0;
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 87b6d3f..0c2d4f7 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -31,6 +31,7 @@
HW_PLATFORM_FLUID = 3,
HW_PLATFORM_SVLTE_FFA = 4,
HW_PLATFORM_SVLTE_SURF = 5,
+ HW_PLATFORM_MTP = 8,
HW_PLATFORM_LIQUID = 9,
/* Dragonboard platform id is assigned as 10 in CDT */
HW_PLATFORM_DRAGON = 10,
@@ -42,9 +43,10 @@
[HW_PLATFORM_SURF] = "Surf",
[HW_PLATFORM_FFA] = "FFA",
[HW_PLATFORM_FLUID] = "Fluid",
- [HW_PLATFORM_LIQUID] = "Liquid",
[HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
+ [HW_PLATFORM_MTP] = "MTP",
+ [HW_PLATFORM_LIQUID] = "Liquid",
[HW_PLATFORM_DRAGON] = "Dragon"
};
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 7e61e8b..6f04470 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -102,7 +102,7 @@
struct msm_clock {
struct clock_event_device clockevent;
struct clocksource clocksource;
- struct irqaction irq;
+ unsigned int irq;
void __iomem *regbase;
uint32_t freq;
uint32_t shift;
@@ -110,6 +110,12 @@
uint32_t write_delay;
uint32_t rollover_offset;
uint32_t index;
+ void __iomem *global_counter;
+ void __iomem *local_counter;
+ union {
+ struct clock_event_device *evt;
+ struct clock_event_device __percpu **percpu_evt;
+ };
};
enum {
@@ -117,7 +123,6 @@
MSM_CLOCK_DGT,
};
-
struct msm_clock_percpu_data {
uint32_t last_set;
uint32_t sleep_offset;
@@ -155,14 +160,7 @@
.shift = 17,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
},
- .irq = {
- .name = "gp_timer",
- .flags = IRQF_DISABLED | IRQF_TIMER |
- IRQF_TRIGGER_RISING,
- .handler = msm_timer_interrupt,
- .dev_id = &msm_clocks[0].clockevent,
- .irq = INT_GP_TIMER_EXP
- },
+ .irq = INT_GP_TIMER_EXP,
.regbase = MSM_TMR_BASE + 0x4,
.freq = 32768,
.index = MSM_CLOCK_GPT,
@@ -185,22 +183,13 @@
.shift = 24,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
},
- .irq = {
- .name = "dg_timer",
- .flags = IRQF_DISABLED | IRQF_TIMER |
- IRQF_TRIGGER_RISING,
- .handler = msm_timer_interrupt,
- .dev_id = &msm_clocks[1].clockevent,
- .irq = INT_DEBUG_TIMER_EXP
- },
+ .irq = INT_DEBUG_TIMER_EXP,
.regbase = MSM_TMR_BASE + 0x24,
.index = MSM_CLOCK_DGT,
.write_delay = 9,
}
};
-static DEFINE_PER_CPU(struct clock_event_device*, local_clock_event);
-
static DEFINE_PER_CPU(struct msm_clock_percpu_data[NR_TIMERS],
msm_clocks_percpu);
@@ -208,9 +197,7 @@
static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
{
- struct clock_event_device *evt = dev_id;
- if (smp_processor_id() != 0)
- evt = __get_cpu_var(local_clock_event);
+ struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
if (evt->event_handler == NULL)
return IRQ_HANDLED;
evt->event_handler(evt);
@@ -356,9 +343,9 @@
get_cpu_var(msm_active_clock) = clock;
put_cpu_var(msm_active_clock);
__raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
- chip = irq_get_chip(clock->irq.irq);
+ chip = irq_get_chip(clock->irq);
if (chip && chip->irq_unmask)
- chip->irq_unmask(irq_get_irq_data(clock->irq.irq));
+ chip->irq_unmask(irq_get_irq_data(clock->irq));
if (clock != &msm_clocks[MSM_CLOCK_GPT])
__raw_writel(TIMER_ENABLE_EN,
msm_clocks[MSM_CLOCK_GPT].regbase +
@@ -374,9 +361,9 @@
msm_read_timer_count(clock, LOCAL_TIMER) +
clock_state->sleep_offset;
__raw_writel(0, clock->regbase + TIMER_MATCH_VAL);
- chip = irq_get_chip(clock->irq.irq);
+ chip = irq_get_chip(clock->irq);
if (chip && chip->irq_mask)
- chip->irq_mask(irq_get_irq_data(clock->irq.irq));
+ chip->irq_mask(irq_get_irq_data(clock->irq));
if (!is_smp() || clock != &msm_clocks[MSM_CLOCK_DGT]
|| smp_processor_id())
@@ -1073,14 +1060,35 @@
printk(KERN_ERR "msm_timer_init: clocksource_register "
"failed for %s\n", cs->name);
- res = setup_irq(clock->irq.irq, &clock->irq);
- if (res)
- printk(KERN_ERR "msm_timer_init: setup_irq "
- "failed for %s\n", cs->name);
+ ce->irq = clock->irq;
+ if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+ cpu_is_msm8930() || cpu_is_msm9615()) {
+ clock->percpu_evt = alloc_percpu(struct clock_event_device *);
+ if (!clock->percpu_evt) {
+ pr_err("msm_timer_init: memory allocation "
+ "failed for %s\n", ce->name);
+ continue;
+ }
- chip = irq_get_chip(clock->irq.irq);
+ *__this_cpu_ptr(clock->percpu_evt) = ce;
+ res = request_percpu_irq(ce->irq, msm_timer_interrupt,
+ ce->name, clock->percpu_evt);
+ if (!res)
+ enable_percpu_irq(ce->irq, 0);
+ } else {
+ clock->evt = ce;
+ res = request_irq(ce->irq, msm_timer_interrupt,
+ IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+ ce->name, &clock->evt);
+ }
+
+ if (res)
+ pr_err("msm_timer_init: request_irq failed for %s\n",
+ ce->name);
+
+ chip = irq_get_chip(clock->irq);
if (chip && chip->irq_mask)
- chip->irq_mask(irq_get_irq_data(clock->irq.irq));
+ chip->irq_mask(irq_get_irq_data(clock->irq));
clockevents_register_device(ce);
}
@@ -1097,7 +1105,6 @@
int __cpuinit local_timer_setup(struct clock_event_device *evt)
{
- unsigned long flags;
static DEFINE_PER_CPU(bool, first_boot) = true;
struct msm_clock *clock = &msm_clocks[msm_global_timer];
@@ -1115,7 +1122,7 @@
__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
__get_cpu_var(first_boot) = false;
}
- evt->irq = clock->irq.irq;
+ evt->irq = clock->irq;
evt->name = "local_timer";
evt->features = CLOCK_EVT_FEAT_ONESHOT;
evt->rating = clock->clockevent.rating;
@@ -1127,21 +1134,18 @@
clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
evt->min_delta_ns = clockevent_delta2ns(4, evt);
- __get_cpu_var(local_clock_event) = evt;
-
- local_irq_save(flags);
- gic_clear_spi_pending(clock->irq.irq);
- local_irq_restore(flags);
- gic_enable_ppi(clock->irq.irq);
+ *__this_cpu_ptr(clock->percpu_evt) = evt;
clockevents_register_device(evt);
+ enable_percpu_irq(evt->irq, 0);
return 0;
}
-int local_timer_ack(void)
+void local_timer_stop(struct clock_event_device *evt)
{
- return 1;
+ evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+ disable_percpu_irq(evt->irq);
}
#endif
diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
index a48690b..22d86ef 100644
--- a/arch/arm/mach-omap2/include/mach/entry-macro.S
+++ b/arch/arm/mach-omap2/include/mach/entry-macro.S
@@ -78,7 +78,7 @@
4401: ldr \irqstat, [\base, #GIC_CPU_INTACK]
ldr \tmp, =1021
bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #29
+ cmp \irqnr, #15
cmpcc \irqnr, \irqnr
cmpne \irqnr, \tmp
cmpcs \irqnr, \irqnr
@@ -101,18 +101,6 @@
it cs
cmpcs \irqnr, \irqnr
.endm
-
- /* As above, this assumes that irqstat and base are preserved */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- bic \irqnr, \irqstat, #0x1c00
- mov \tmp, #0
- cmp \irqnr, #29
- itt eq
- moveq \tmp, #1
- streq \irqstat, [\base, #GIC_CPU_EOI]
- cmp \tmp, #0
- .endm
#endif /* CONFIG_SMP */
#else /* MULTI_OMAP2 */
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 32ed551..85df15c 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -19,6 +19,8 @@
#include <linux/io.h>
#include <linux/irq.h>
+#include <asm/exception.h>
+
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/gpio.h>
diff --git a/arch/arm/mach-shmobile/entry-intc.S b/arch/arm/mach-shmobile/entry-intc.S
index cac0a7a..1a1c00c 100644
--- a/arch/arm/mach-shmobile/entry-intc.S
+++ b/arch/arm/mach-shmobile/entry-intc.S
@@ -51,7 +51,4 @@
.macro test_for_ipi, irqnr, irqstat, base, tmp
.endm
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- .endm
-
arch_irq_handler shmobile_handle_irq_intc
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 7475c2e..d7561bb 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -20,6 +20,7 @@
#include <linux/highmem.h>
#include <linux/perf_event.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index db80bd3..da31deb3 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -329,11 +329,12 @@
#else
static void arm_memory_present(void)
{
- struct memblock_region *reg;
-
- for_each_memblock(memory, reg)
- memory_present(0, memblock_region_memory_base_pfn(reg),
- memblock_region_memory_end_pfn(reg));
+ struct meminfo *mi = &meminfo;
+ int i;
+ for_each_bank(i, mi) {
+ memory_present(0, bank_pfn_start(&mi->bank[i]),
+ bank_pfn_end(&mi->bank[i]));
+ }
}
#endif
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 6d589e2..7f15e65 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -796,13 +796,8 @@
int i, j, highmem = 0;
#if (defined CONFIG_HIGHMEM) && (defined CONFIG_FIX_MOVABLE_ZONE)
- void *v_movable_start;
- if (movable_reserved_size) {
- v_movable_start = __va(movable_reserved_start);
-
- if (vmalloc_min > v_movable_start)
- vmalloc_min = v_movable_start;
- }
+ if (movable_reserved_size && __pa(vmalloc_min) > movable_reserved_start)
+ vmalloc_min = __va(movable_reserved_start);
#endif
for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
struct membank *bank = &meminfo.bank[j];
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index e98f5c5..c5ebe6f 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -11,6 +11,7 @@
default y
select ARM_VIC if !ARCH_EXYNOS4
select ARM_GIC if ARCH_EXYNOS4
+ select GIC_NON_BANKED if ARCH_EXYNOS4
select NO_IOPORT
select ARCH_REQUIRE_GPIOLIB
select S3C_GPIO_TRACK
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index baf3170..b4ca325 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1132,3 +1132,7 @@
msm8627_cdp MACH_MSM8627_CDP MSM8627_CDP 3861
msm8627_mtp MACH_MSM8627_MTP MSM8627_MTP 3862
msm8625_rumi3 MACH_MSM8625_RUMI3 MSM8625_RUMI3 3871
+msm7627a_evb MACH_MSM7627A_EVB MSM7627A_EVB 3934
+apq8064_cdp MACH_APQ8064_CDP APQ8064_CDP 3948
+apq8064_mtp MACH_APQ8064_MTP APQ8064_MTP 3949
+apq8064_liquid MACH_APQ8064_LIQUID APQ8064_LIQUID 3951
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index 41bbd3a..7e25684 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -31,6 +31,9 @@
#define _RDLOCK GENLOCK_RDLOCK
#define _WRLOCK GENLOCK_WRLOCK
+#define GENLOCK_LOG_ERR(fmt, args...) \
+pr_err("genlock: %s: " fmt, __func__, ##args)
+
struct genlock {
struct list_head active; /* List of handles holding lock */
spinlock_t lock; /* Spinlock to protect the lock internals */
@@ -48,11 +51,28 @@
taken */
};
+/*
+ * Create a spinlock to protect against a race condition when a lock gets
+ * released while another process tries to attach it
+ */
+
+static DEFINE_SPINLOCK(genlock_file_lock);
+
static void genlock_destroy(struct kref *kref)
{
struct genlock *lock = container_of(kref, struct genlock,
refcount);
+ /*
+ * Clear the private data for the file descriptor in case the fd is
+ * still active after the lock gets released
+ */
+
+ spin_lock(&genlock_file_lock);
+ if (lock->file)
+ lock->file->private_data = NULL;
+ spin_unlock(&genlock_file_lock);
+
kfree(lock);
}
@@ -63,6 +83,15 @@
static int genlock_release(struct inode *inodep, struct file *file)
{
+ struct genlock *lock = file->private_data;
+ /*
+ * Clear the refrence back to this file structure to avoid
+ * somehow reusing the lock after the file has been destroyed
+ */
+
+ if (lock)
+ lock->file = NULL;
+
return 0;
}
@@ -81,12 +110,16 @@
{
struct genlock *lock;
- if (handle->lock != NULL)
+ if (handle->lock != NULL) {
+ GENLOCK_LOG_ERR("Handle already has a lock attached\n");
return ERR_PTR(-EINVAL);
+ }
lock = kzalloc(sizeof(*lock), GFP_KERNEL);
- if (lock == NULL)
+ if (lock == NULL) {
+ GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
return ERR_PTR(-ENOMEM);
+ }
INIT_LIST_HEAD(&lock->active);
init_waitqueue_head(&lock->queue);
@@ -119,8 +152,10 @@
{
int ret;
- if (!lock->file)
+ if (!lock->file) {
+ GENLOCK_LOG_ERR("No file attached to the lock\n");
return -EINVAL;
+ }
ret = get_unused_fd_flags(0);
if (ret < 0)
@@ -142,19 +177,32 @@
struct file *file;
struct genlock *lock;
- if (handle->lock != NULL)
+ if (handle->lock != NULL) {
+ GENLOCK_LOG_ERR("Handle already has a lock attached\n");
return ERR_PTR(-EINVAL);
+ }
file = fget(fd);
- if (file == NULL)
+ if (file == NULL) {
+ GENLOCK_LOG_ERR("Bad file descriptor\n");
return ERR_PTR(-EBADF);
+ }
+ /*
+ * take a spinlock to avoid a race condition if the lock is
+ * released and then attached
+ */
+
+ spin_lock(&genlock_file_lock);
lock = file->private_data;
+ spin_unlock(&genlock_file_lock);
fput(file);
- if (lock == NULL)
+ if (lock == NULL) {
+ GENLOCK_LOG_ERR("File descriptor is invalid\n");
return ERR_PTR(-EINVAL);
+ }
handle->lock = lock;
kref_get(&lock->refcount);
@@ -198,13 +246,16 @@
spin_lock_irqsave(&lock->lock, irqflags);
- if (lock->state == _UNLOCKED)
+ if (lock->state == _UNLOCKED) {
+ GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\n");
goto done;
+ }
/* Make sure this handle is an owner of the lock */
- if (!handle_has_lock(lock, handle))
+ if (!handle_has_lock(lock, handle)) {
+ GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
goto done;
-
+ }
/* If the handle holds no more references to the lock then
release it (maybe) */
@@ -273,7 +324,8 @@
* Otherwise the user tried to turn a read into a write, and we
* don't allow that.
*/
-
+ GENLOCK_LOG_ERR("Trying to upgrade a read lock to a write"
+ "lock\n");
ret = -EINVAL;
goto done;
}
@@ -343,8 +395,10 @@
struct genlock *lock = handle->lock;
int ret = 0;
- if (lock == NULL)
+ if (lock == NULL) {
+ GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
return -EINVAL;
+ }
switch (op) {
case GENLOCK_UNLOCK:
@@ -355,6 +409,7 @@
ret = _genlock_lock(lock, handle, op, flags, timeout);
break;
default:
+ GENLOCK_LOG_ERR("Invalid lock operation\n");
ret = -EINVAL;
break;
}
@@ -376,8 +431,10 @@
int ret = 0;
unsigned int ticks = msecs_to_jiffies(timeout);
- if (lock == NULL)
+ if (lock == NULL) {
+ GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
return -EINVAL;
+ }
spin_lock_irqsave(&lock->lock, irqflags);
@@ -467,8 +524,10 @@
static struct genlock_handle *_genlock_get_handle(void)
{
struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
- if (handle == NULL)
+ if (handle == NULL) {
+ GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
return ERR_PTR(-ENOMEM);
+ }
return handle;
}
@@ -539,8 +598,11 @@
return 0;
}
case GENLOCK_IOC_EXPORT: {
- if (handle->lock == NULL)
+ if (handle->lock == NULL) {
+ GENLOCK_LOG_ERR("Handle does not have a lock"
+ "attached\n");
return -EINVAL;
+ }
ret = genlock_get_fd(handle->lock);
if (ret < 0)
@@ -585,6 +647,7 @@
return 0;
}
default:
+ GENLOCK_LOG_ERR("Invalid ioctl\n");
return -EINVAL;
}
}
diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c
index 6507d8b..ea2a1df6 100644
--- a/drivers/base/iommu.c
+++ b/drivers/base/iommu.c
@@ -171,3 +171,12 @@
return iommu_ops->unmap_range(domain, iova, len);
}
EXPORT_SYMBOL_GPL(iommu_unmap_range);
+
+phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain)
+{
+ if (!iommu_found())
+ return 0;
+
+ return iommu_ops->get_pt_base_addr(domain);
+}
+EXPORT_SYMBOL_GPL(iommu_get_pt_base_addr);
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 3c4aa8f..101697f 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -419,6 +419,7 @@
if (rc < 0) {
BT_ERR("Cannot open the command channel");
hci_free_dev(hdev);
+ hdev = NULL;
return -ENODEV;
}
@@ -427,6 +428,7 @@
if (rc < 0) {
BT_ERR("Failed to open the Data channel");
hci_free_dev(hdev);
+ hdev = NULL;
return -ENODEV;
}
@@ -443,6 +445,15 @@
static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
{
+ if (hsmd->hdev) {
+ if (hci_unregister_dev(hsmd->hdev) < 0)
+ BT_ERR("Can't unregister HCI device %s",
+ hsmd->hdev->name);
+
+ hci_free_dev(hsmd->hdev);
+ hsmd->hdev = NULL;
+ }
+
smd_close(hs.event_channel);
smd_close(hs.data_channel);
@@ -452,13 +463,14 @@
wake_unlock(&hs.wake_lock_tx);
/*Destroy the timer used to monitor the Rx queue for emptiness */
- del_timer_sync(&hs.rx_q_timer);
+ if (hs.rx_q_timer.function) {
+ del_timer_sync(&hs.rx_q_timer);
+ hs.rx_q_timer.function = NULL;
+ hs.rx_q_timer.data = 0;
+ }
+
tasklet_kill(&hs.hci_event_task);
tasklet_kill(&hs.hci_data_task);
- if (hci_unregister_dev(hsmd->hdev) < 0)
- BT_ERR("Can't unregister HCI device %s", hsmd->hdev->name);
-
- hci_free_dev(hsmd->hdev);
}
static int hcismd_set_enable(const char *val, struct kernel_param *kp)
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index eb0b21e..53df29b 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -29,3 +29,13 @@
help
SDIO Transport Layer for DIAG Router
endmenu
+
+menu "HSIC support for DIAG"
+
+config DIAG_HSIC_PIPE
+ depends on USB_QCOM_DIAG_BRIDGE
+ default y
+ bool "Enable 9K DIAG traffic over HSIC"
+ help
+ HSIC Transport Layer for DIAG Router
+endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 52ab2b9..c62b7fd 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_DIAG_CHAR) := diagchar.o
obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
+obj-$(CONFIG_DIAG_HSIC_PIPE) += diagfwd_hsic.o
diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 292fbc3..f493f79 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,7 @@
#define APPS_DATA 3
#define SDIO_DATA 4
#define WCNSS_DATA 5
+#define HSIC_DATA 6
#define MODEM_PROC 0
#define APPS_PROC 1
#define QDSP_PROC 2
@@ -214,11 +215,30 @@
struct work_struct diag_read_mdm_work;
struct workqueue_struct *diag_sdio_wq;
struct work_struct diag_read_sdio_work;
- struct work_struct diag_remove_sdio_work;
struct work_struct diag_close_sdio_work;
struct diag_request *usb_read_mdm_ptr;
struct diag_request *write_ptr_mdm;
#endif
+#ifdef CONFIG_DIAG_HSIC_PIPE
+ unsigned char *buf_in_hsic;
+ unsigned char *usb_buf_mdm_out;
+ int hsic_initialized;
+ int hsic_ch;
+ int hsic_device_enabled;
+ int hsic_device_opened;
+ int read_len_mdm;
+ int in_busy_hsic_read_on_mdm;
+ int in_busy_hsic_write_on_mdm;
+ int in_busy_hsic_write;
+ int in_busy_hsic_read;
+ int usb_mdm_connected;
+ struct usb_diag_ch *mdm_ch;
+ struct workqueue_struct *diag_hsic_wq;
+ struct work_struct diag_read_mdm_work;
+ struct work_struct diag_read_hsic_work;
+ struct diag_request *usb_read_mdm_ptr;
+ struct diag_request *write_ptr_mdm;
+#endif
};
extern struct diagchar_dev *driver;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0729753..799be72 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,6 +31,9 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
#include "diagfwd_sdio.h"
#endif
+#ifdef CONFIG_DIAG_HSIC_PIPE
+#include "diagfwd_hsic.h"
+#endif
#include <linux/timer.h>
MODULE_DESCRIPTION("Diag Char Driver");
@@ -377,6 +380,9 @@
driver->in_busy_qdsp_1 = 1;
driver->in_busy_qdsp_2 = 1;
driver->in_busy_wcnss = 1;
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ driver->in_busy_sdio = 1;
+#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
driver->in_busy_1 = 0;
@@ -394,6 +400,13 @@
if (driver->ch_wcnss)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_wcnss_work));
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ driver->in_busy_sdio = 0;
+ /* Poll SDIO channel to check for data */
+ if (driver->sdio_ch)
+ queue_work(driver->diag_sdio_wq,
+ &(driver->diag_read_sdio_work));
+#endif
}
#ifdef CONFIG_DIAG_OVER_USB
else if (temp == USB_MODE && driver->logging_mode
@@ -420,9 +433,16 @@
if (driver->ch_wcnss)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_wcnss_work));
- } else if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
- == USB_MODE)
- diagfwd_connect();
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ driver->in_busy_sdio = 0;
+ /* Poll SDIO channel to check for data */
+ if (driver->sdio_ch)
+ queue_work(driver->diag_sdio_wq,
+ &(driver->diag_read_sdio_work));
+#endif
+ } else if (temp == MEMORY_DEVICE_MODE &&
+ driver->logging_mode == USB_MODE)
+ diagfwd_connect();
#endif /* DIAG over USB */
success = 1;
}
@@ -553,6 +573,20 @@
driver->write_ptr_wcnss->length);
driver->in_busy_wcnss = 0;
}
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ /* copy 9K data over SDIO */
+ if (driver->in_busy_sdio == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (driver->write_ptr_mdm->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(driver->buf_in_sdio),
+ driver->write_ptr_mdm->length);
+ driver->in_busy_sdio = 0;
+ }
+#endif
/* copy number of data fields */
COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
ret -= 4;
@@ -566,6 +600,11 @@
if (driver->ch_wcnss)
queue_work(driver->diag_wq,
&(driver->diag_read_smd_wcnss_work));
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ if (driver->sdio_ch)
+ queue_work(driver->diag_sdio_wq,
+ &(driver->diag_read_sdio_work));
+#endif
APPEND_DEBUG('n');
goto exit;
} else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
@@ -655,7 +694,7 @@
payload_size);
/* Check masks for On-Device logging */
if (pkt_type == USER_SPACE_LOG_TYPE) {
- if (!mask_request_validate((unsigned char *)buf)) {
+ if (!mask_request_validate(driver->user_space_data)) {
pr_alert("diag: mask request Invalid\n");
return -EFAULT;
}
@@ -664,8 +703,21 @@
#ifdef DIAG_DEBUG
pr_debug("diag: user space data %d\n", payload_size);
for (i = 0; i < payload_size; i++)
- printk(KERN_DEBUG "\t %x", *(((unsigned char *)buf)+i));
+ pr_debug("\t %x", *((driver->user_space_data)+i));
#endif
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ /* send masks to 9k too */
+ if (driver->sdio_ch) {
+ wait_event_interruptible(driver->wait_q,
+ (sdio_write_avail(driver->sdio_ch) >=
+ payload_size));
+ if (driver->sdio_ch && (payload_size > 0)) {
+ sdio_write(driver->sdio_ch, (void *)
+ (driver->user_space_data), payload_size);
+ }
+ }
+#endif
+ /* send masks to modem now */
diag_process_hdlc((void *)(driver->user_space_data),
payload_size);
return 0;
@@ -803,11 +855,11 @@
uint8_t subsys_id;
uint16_t ss_cmd;
- packet_id = mask_buf[4];
+ packet_id = mask_buf[0];
if (packet_id == 0x4B) {
- subsys_id = mask_buf[5];
- ss_cmd = *(uint16_t *)(mask_buf + 6);
+ subsys_id = mask_buf[1];
+ ss_cmd = *(uint16_t *)(mask_buf + 2);
/* Packets with SSID which are allowed */
switch (subsys_id) {
case 0x04: /* DIAG_SUBSYS_WCDMA */
@@ -933,6 +985,18 @@
inline void diag_sdio_fn(int type) {}
#endif
+#ifdef CONFIG_DIAG_HSIC_PIPE
+void diag_hsic_fn(int type)
+{
+ if (type == INIT)
+ diagfwd_hsic_init();
+ else if (type == EXIT)
+ diagfwd_hsic_exit();
+}
+#else
+inline void diag_hsic_fn(int type) {}
+#endif
+
static int __init diagchar_init(void)
{
dev_t dev;
@@ -971,6 +1035,7 @@
diagfwd_init();
diagfwd_cntl_init();
diag_sdio_fn(INIT);
+ diag_hsic_fn(INIT);
pr_debug("diagchar initializing ..\n");
driver->num = 1;
driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
@@ -1003,6 +1068,7 @@
diagfwd_exit();
diagfwd_cntl_exit();
diag_sdio_fn(EXIT);
+ diag_hsic_fn(EXIT);
return -1;
}
@@ -1015,6 +1081,7 @@
diagfwd_exit();
diagfwd_cntl_exit();
diag_sdio_fn(EXIT);
+ diag_hsic_fn(EXIT);
diagchar_cleanup();
printk(KERN_INFO "done diagchar exit\n");
}
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index c8555cd..6853654 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -43,7 +42,7 @@
unsigned char diag_debug_buf[1024];
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
-smd_channel_t *ch_temp;
+smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
@@ -72,6 +71,10 @@
int chk_config_get_id(void)
{
+ /* For all Fusion targets, Modem will always be present */
+ if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
+ return 0;
+
switch (socinfo_get_id()) {
case APQ8060_MACHINE_ID:
case MSM8660_MACHINE_ID:
@@ -80,6 +83,8 @@
return AO8960_TOOLS_ID;
case APQ8064_MACHINE_ID:
return APQ8064_TOOLS_ID;
+ case MSM8930_MACHINE_ID:
+ return MSM8930_TOOLS_ID;
default:
return 0;
}
@@ -94,6 +99,12 @@
switch (socinfo_get_id()) {
case AO8960_MACHINE_ID:
case APQ8064_MACHINE_ID:
+ case MSM8930_MACHINE_ID:
+ case MSM8630_MACHINE_ID:
+ case MSM8230_MACHINE_ID:
+ case APQ8030_MACHINE_ID:
+ case MSM8627_MACHINE_ID:
+ case MSM8227_MACHINE_ID:
return 1;
default:
return 0;
@@ -191,6 +202,13 @@
queue_work(driver->diag_wq, &(driver->
diag_read_smd_wcnss_work));
}
+#ifdef CONFIG_DIAG_SDIO_PIPE
+ else if (proc_num == SDIO_DATA) {
+ driver->in_busy_sdio = 0;
+ queue_work(driver->diag_sdio_wq,
+ &(driver->diag_read_sdio_work));
+ }
+#endif
err = -1;
}
#ifdef CONFIG_DIAG_OVER_USB
@@ -226,11 +244,22 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
else if (proc_num == SDIO_DATA) {
if (machine_is_msm8x60_fusion() ||
- machine_is_msm8x60_fusn_ffa()) {
+ machine_is_msm8x60_fusn_ffa()) {
write_ptr->buf = buf;
err = usb_diag_write(driver->mdm_ch, write_ptr);
} else
- pr_err("diag: Incorrect data while USB write");
+ pr_err("diag: Incorrect sdio data "
+ "while USB write\n");
+ }
+#endif
+#ifdef CONFIG_DIAG_HSIC_PIPE
+ else if (proc_num == HSIC_DATA) {
+ if (driver->hsic_device_enabled) {
+ write_ptr->buf = buf;
+ err = usb_diag_write(driver->mdm_ch, write_ptr);
+ } else
+ pr_err("diag: Incorrect hsic data "
+ "while USB write\n");
}
#endif
APPEND_DEBUG('d');
@@ -885,6 +914,11 @@
void diag_send_error_rsp(int index)
{
int i;
+
+ if (index > 490) {
+ pr_err("diag: error response too huge, aborting\n");
+ return;
+ }
driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
for (i = 0; i < index; i++)
driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
@@ -1051,7 +1085,7 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
else if (buf == (void *)driver->buf_in_sdio)
if (machine_is_msm8x60_fusion() ||
- machine_is_msm8x60_fusn_ffa())
+ machine_is_msm8x60_fusn_ffa())
diagfwd_write_complete_sdio();
else
pr_err("diag: Incorrect buffer pointer while WRITE");
@@ -1093,7 +1127,7 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
else if (buf == (void *)driver->usb_buf_mdm_out) {
if (machine_is_msm8x60_fusion() ||
- machine_is_msm8x60_fusn_ffa()) {
+ machine_is_msm8x60_fusn_ffa()) {
driver->read_len_mdm = diag_read_ptr->actual;
diagfwd_read_complete_sdio();
} else
@@ -1163,12 +1197,28 @@
#if defined(CONFIG_MSM_N_WAY_SMD)
static void diag_smd_qdsp_notify(void *ctxt, unsigned event)
{
+ if (event == SMD_EVENT_CLOSE) {
+ pr_info("diag: clean lpass registration\n");
+ diag_clear_reg(QDSP_PROC);
+ driver->chqdsp = 0;
+ return;
+ } else if (event == SMD_EVENT_OPEN) {
+ driver->chqdsp = chqdsp_temp;
+ }
queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
}
#endif
static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
{
+ if (event == SMD_EVENT_CLOSE) {
+ pr_info("diag: clean wcnss registration\n");
+ diag_clear_reg(WCNSS_PROC);
+ driver->ch_wcnss = 0;
+ return;
+ } else if (event == SMD_EVENT_OPEN) {
+ driver->ch_wcnss = ch_wcnss_temp;
+ }
queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
}
@@ -1181,13 +1231,17 @@
ch_temp = driver->ch;
}
#if defined(CONFIG_MSM_N_WAY_SMD)
- if (pdev->id == SMD_APPS_QDSP)
+ if (pdev->id == SMD_APPS_QDSP) {
r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP
, &driver->chqdsp, driver, diag_smd_qdsp_notify);
+ chqdsp_temp = driver->chqdsp;
+ }
#endif
- if (pdev->id == SMD_APPS_WCNSS)
+ if (pdev->id == SMD_APPS_WCNSS) {
r = smd_named_open_on_edge("APPS_RIVA_DATA", SMD_APPS_WCNSS
, &driver->ch_wcnss, driver, diag_smd_wcnss_notify);
+ ch_wcnss_temp = driver->ch_wcnss;
+ }
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
new file mode 100644
index 0000000..ac5722f
--- /dev/null
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -0,0 +1,530 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/diagchar.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <asm/current.h>
+#ifdef CONFIG_DIAG_OVER_USB
+#include <mach/usbdiag.h>
+#endif
+#include "diagchar_hdlc.h"
+#include "diagmem.h"
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_hsic.h"
+
+static void diag_read_hsic_work_fn(struct work_struct *work)
+{
+ if (!driver->hsic_ch) {
+ pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ return;
+ }
+
+ /*
+ * If there is no hsic data being read from the hsic and there
+ * is no hsic data being written to the usb mdm channel
+ */
+ if (!driver->in_busy_hsic_read && !driver->in_busy_hsic_write_on_mdm) {
+ /*
+ * Initiate the read from the hsic. The hsic read is
+ * asynchronous. Once the read is complete the read
+ * callback function will be called.
+ */
+ int err;
+ driver->in_busy_hsic_read = 1;
+ APPEND_DEBUG('i');
+ err = diag_bridge_read((char *)driver->buf_in_hsic,
+ IN_BUF_SIZE);
+ if (err) {
+ pr_err("DIAG: Error initiating HSIC read, err: %d\n",
+ err);
+ /*
+ * If the error is recoverable, then clear
+ * the read flag, so we will resubmit a
+ * read on the next frame. Otherwise, don't
+ * resubmit a read on the next frame.
+ */
+ if ((-ESHUTDOWN) != err)
+ driver->in_busy_hsic_read = 0;
+ }
+ }
+
+ /*
+ * If for some reason there was no hsic data, set up
+ * the next read
+ */
+ if (!driver->in_busy_hsic_read)
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+}
+
+static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
+ int buf_size, int actual_size)
+{
+ /* The read of the data from the HSIC bridge is complete */
+ driver->in_busy_hsic_read = 0;
+
+ if (!driver->hsic_ch) {
+ pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ return;
+ }
+
+ APPEND_DEBUG('j');
+ if (actual_size > 0) {
+ if (!buf) {
+ pr_err("Out of diagmem for HSIC\n");
+ } else {
+ driver->write_ptr_mdm->length = actual_size;
+ /*
+ * Set flag to denote hsic data is currently
+ * being written to the usb mdm channel.
+ * driver->buf_in_hsic was given to
+ * diag_bridge_read(), so buf here should be
+ * driver->buf_in_hsic
+ */
+ driver->in_busy_hsic_write_on_mdm = 1;
+ diag_device_write((void *)buf, HSIC_DATA,
+ driver->write_ptr_mdm);
+ }
+ } else {
+ pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
+ }
+
+ /*
+ * If for some reason there was no hsic data to write to the
+ * mdm channel, set up another read
+ */
+ if (!driver->in_busy_hsic_write_on_mdm)
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+}
+
+static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
+ int buf_size, int actual_size)
+{
+ /* The write of the data to the HSIC bridge is complete */
+ driver->in_busy_hsic_write = 0;
+
+ if (!driver->hsic_ch) {
+ pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ return;
+ }
+
+ if (actual_size < 0)
+ pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
+
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+}
+
+static struct diag_bridge_ops hsic_diag_bridge_ops = {
+ .ctxt = NULL,
+ .read_complete_cb = diag_hsic_read_complete_callback,
+ .write_complete_cb = diag_hsic_write_complete_callback,
+};
+
+static int diag_hsic_close(void)
+{
+ if (driver->hsic_device_enabled) {
+ driver->hsic_ch = 0;
+ if (driver->hsic_device_opened) {
+ driver->hsic_device_opened = 0;
+ diag_bridge_close();
+ }
+ pr_debug("DIAG in %s: closed successfully\n", __func__);
+ } else {
+ pr_debug("DIAG in %s: already closed\n", __func__);
+ }
+
+ return 0;
+}
+
+/* diagfwd_connect_hsic is called when the USB mdm channel is connected */
+static int diagfwd_connect_hsic(void)
+{
+ int err;
+
+ pr_debug("DIAG in %s\n", __func__);
+
+ err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE, N_MDM_READ);
+ if (err)
+ pr_err("DIAG: unable to alloc USB req on mdm ch err:%d\n", err);
+
+ driver->usb_mdm_connected = 1;
+ driver->in_busy_hsic_write_on_mdm = 0;
+ driver->in_busy_hsic_read_on_mdm = 0;
+ driver->in_busy_hsic_write = 0;
+ driver->in_busy_hsic_read = 0;
+
+ /* If the hsic (diag_bridge) platform device is not open */
+ if (driver->hsic_device_enabled) {
+ if (!driver->hsic_device_opened) {
+ err = diag_bridge_open(&hsic_diag_bridge_ops);
+ if (err) {
+ pr_err("DIAG: HSIC channel open error: %d\n",
+ err);
+ } else {
+ pr_info("DIAG: opened HSIC channel\n");
+ driver->hsic_device_opened = 1;
+ }
+ } else {
+ pr_info("DIAG: HSIC channel already open\n");
+ }
+
+ /*
+ * Turn on communication over usb mdm and hsic, if the hsic
+ * device driver is enabled and opened
+ */
+ if (driver->hsic_device_opened)
+ driver->hsic_ch = 1;
+
+ /* Poll USB mdm channel to check for data */
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+
+ /* Poll HSIC channel to check for data */
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ } else {
+ /* The hsic device driver has not yet been enabled */
+ pr_info("DIAG: HSIC channel not yet enabled\n");
+ }
+
+ return 0;
+}
+
+/*
+ * diagfwd_disconnect_hsic is called when the USB mdm channel
+ * is disconnected
+ */
+static int diagfwd_disconnect_hsic(void)
+{
+ pr_debug("DIAG in %s\n", __func__);
+
+ driver->usb_mdm_connected = 0;
+ usb_diag_free_req(driver->mdm_ch);
+ driver->in_busy_hsic_write_on_mdm = 1;
+ driver->in_busy_hsic_read_on_mdm = 1;
+ driver->in_busy_hsic_write = 1;
+ driver->in_busy_hsic_read = 1;
+
+ /* Turn off communication over usb mdm and hsic */
+ driver->hsic_ch = 0;
+
+ return 0;
+}
+
+/*
+ * diagfwd_write_complete_hsic is called after the asynchronous
+ * usb_diag_write() on mdm channel is complete
+ */
+static int diagfwd_write_complete_hsic(void)
+{
+ /*
+ * Clear flag to denote that the write of the hsic data on the
+ * usb mdm channel is complete
+ */
+ driver->in_busy_hsic_write_on_mdm = 0;
+
+ if (!driver->hsic_ch) {
+ pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ return 0;
+ }
+
+ APPEND_DEBUG('q');
+
+ /* Read data from the hsic */
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+
+ return 0;
+}
+
+/* Called after the asychronous usb_diag_read() on mdm channel is complete */
+static int diagfwd_read_complete_hsic(struct diag_request *diag_read_ptr)
+{
+ /* The read of the usb driver on the mdm (not hsic) has completed */
+ driver->in_busy_hsic_read_on_mdm = 0;
+ driver->read_len_mdm = diag_read_ptr->actual;
+
+ if (!driver->hsic_ch) {
+ pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ return 0;
+ }
+
+ /*
+ * The read of the usb driver on the mdm channel has completed.
+ * If there is no write on the hsic in progress, check if the
+ * read has data to pass on to the hsic. If so, pass the usb
+ * mdm data on to the hsic.
+ */
+ if (!driver->in_busy_hsic_write && driver->usb_buf_mdm_out &&
+ (driver->read_len_mdm > 0)) {
+
+ /*
+ * Initiate the hsic write. The hsic write is
+ * asynchronous. When complete the write
+ * complete callback function will be called
+ */
+ int err;
+ driver->in_busy_hsic_write = 1;
+ err = diag_bridge_write(driver->usb_buf_mdm_out,
+ driver->read_len_mdm);
+ if (err) {
+ pr_err("DIAG: mdm data on hsic write err: %d\n", err);
+ /*
+ * If the error is recoverable, then clear
+ * the write flag, so we will resubmit a
+ * write on the next frame. Otherwise, don't
+ * resubmit a write on the next frame.
+ */
+ if ((-ESHUTDOWN) != err)
+ driver->in_busy_hsic_write = 0;
+ }
+ }
+
+ /*
+ * If there is no write of the usb mdm data on the
+ * hsic channel
+ */
+ if (!driver->in_busy_hsic_write)
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+
+ return 0;
+}
+
+static void diagfwd_hsic_notifier(void *priv, unsigned event,
+ struct diag_request *d_req)
+{
+ switch (event) {
+ case USB_DIAG_CONNECT:
+ diagfwd_connect_hsic();
+ break;
+ case USB_DIAG_DISCONNECT:
+ diagfwd_disconnect_hsic();
+ break;
+ case USB_DIAG_READ_DONE:
+ diagfwd_read_complete_hsic(d_req);
+ break;
+ case USB_DIAG_WRITE_DONE:
+ diagfwd_write_complete_hsic();
+ break;
+ default:
+ pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
+ __func__, event);
+ break;
+ }
+}
+
+static void diag_read_mdm_work_fn(struct work_struct *work)
+{
+ if (!driver->hsic_ch) {
+ pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ return;
+ }
+
+ /*
+ * If there is no data being read from the usb mdm channel
+ * and there is no mdm channel data currently being written
+ * to the hsic
+ */
+ if (!driver->in_busy_hsic_read_on_mdm && !driver->in_busy_hsic_write) {
+ APPEND_DEBUG('x');
+
+ /* Setup the next read from usb mdm channel */
+ driver->in_busy_hsic_read_on_mdm = 1;
+ driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
+ driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
+ usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+ APPEND_DEBUG('y');
+ }
+
+ /*
+ * If for some reason there was no mdm channel read initiated,
+ * queue up the reading of data from the mdm channel
+ */
+ if (!driver->in_busy_hsic_read_on_mdm)
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+}
+
+int diag_hsic_enable(void)
+{
+ pr_debug("DIAG in %s\n", __func__);
+
+ driver->read_len_mdm = 0;
+ if (driver->buf_in_hsic == NULL)
+ driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_hsic == NULL)
+ goto err;
+ if (driver->usb_buf_mdm_out == NULL)
+ driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF, GFP_KERNEL);
+ if (driver->usb_buf_mdm_out == NULL)
+ goto err;
+ if (driver->write_ptr_mdm == NULL)
+ driver->write_ptr_mdm = kzalloc(
+ sizeof(struct diag_request), GFP_KERNEL);
+ if (driver->write_ptr_mdm == NULL)
+ goto err;
+ if (driver->usb_read_mdm_ptr == NULL)
+ driver->usb_read_mdm_ptr = kzalloc(
+ sizeof(struct diag_request), GFP_KERNEL);
+ if (driver->usb_read_mdm_ptr == NULL)
+ goto err;
+ driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+#ifdef CONFIG_DIAG_OVER_USB
+ INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
+#endif
+ INIT_WORK(&(driver->diag_read_hsic_work), diag_read_hsic_work_fn);
+
+ driver->hsic_device_enabled = 1;
+
+ return 0;
+err:
+ pr_err("DIAG could not initialize buf for HSIC\n");
+ kfree(driver->buf_in_hsic);
+ kfree(driver->usb_buf_mdm_out);
+ kfree(driver->write_ptr_mdm);
+ kfree(driver->usb_read_mdm_ptr);
+ if (driver->diag_hsic_wq)
+ destroy_workqueue(driver->diag_hsic_wq);
+
+ return -ENOMEM;
+}
+
+static int diag_hsic_probe(struct platform_device *pdev)
+{
+ int err;
+
+ if (!driver->hsic_device_enabled) {
+ err = diag_hsic_enable();
+ if (err) {
+ pr_err("DIAG could not enable HSIC, err: %d\n", err);
+ return err;
+ }
+ }
+
+ /* The hsic (diag_bridge) platform device driver is enabled */
+ err = diag_bridge_open(&hsic_diag_bridge_ops);
+ if (err) {
+ pr_err("DIAG could not open HSIC channel, err: %d\n", err);
+ driver->hsic_device_opened = 0;
+ return err;
+ }
+
+ pr_info("DIAG opened HSIC channel\n");
+ driver->hsic_device_opened = 1;
+
+ /*
+ * The probe function was called after the usb was connected
+ * on the legacy channel. Communication over usb mdm and hsic
+ * needs to be turned on.
+ */
+ if (driver->usb_connected) {
+ driver->hsic_ch = 1;
+ driver->in_busy_hsic_write_on_mdm = 0;
+ driver->in_busy_hsic_read_on_mdm = 0;
+ driver->in_busy_hsic_write = 0;
+ driver->in_busy_hsic_read = 0;
+
+ /* Poll USB mdm channel to check for data */
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+
+ /* Poll HSIC channel to check for data */
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ }
+
+ return err;
+}
+
+static int diag_hsic_remove(struct platform_device *pdev)
+{
+ pr_info("DIAG: %s called\n", __func__);
+ diag_hsic_close();
+ return 0;
+}
+
+static int diagfwd_hsic_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: suspending...\n");
+ return 0;
+}
+
+static int diagfwd_hsic_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: resuming...\n");
+ return 0;
+}
+
+static const struct dev_pm_ops diagfwd_hsic_dev_pm_ops = {
+ .runtime_suspend = diagfwd_hsic_runtime_suspend,
+ .runtime_resume = diagfwd_hsic_runtime_resume,
+};
+
+static struct platform_driver msm_hsic_ch_driver = {
+ .probe = diag_hsic_probe,
+ .remove = diag_hsic_remove,
+ .driver = {
+ .name = "diag_bridge",
+ .owner = THIS_MODULE,
+ .pm = &diagfwd_hsic_dev_pm_ops,
+ },
+};
+
+
+void __init diagfwd_hsic_init(void)
+{
+ int ret;
+
+ pr_debug("DIAG in %s\n", __func__);
+
+#ifdef CONFIG_DIAG_OVER_USB
+ driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
+ if (IS_ERR(driver->mdm_ch)) {
+ pr_err("DIAG Unable to open USB diag MDM channel\n");
+ goto err;
+ }
+#endif
+ ret = platform_driver_register(&msm_hsic_ch_driver);
+ if (ret)
+ pr_err("DIAG could not register HSIC device, ret: %d\n", ret);
+ else
+ driver->hsic_initialized = 1;
+
+ return;
+err:
+ pr_err("DIAG could not initialize for HSIC execution\n");
+}
+
+void __exit diagfwd_hsic_exit(void)
+{
+ pr_debug("DIAG in %s\n", __func__);
+
+ if (driver->hsic_initialized)
+ diag_hsic_close();
+
+#ifdef CONFIG_DIAG_OVER_USB
+ if (driver->usb_mdm_connected)
+ usb_diag_free_req(driver->mdm_ch);
+#endif
+ platform_driver_unregister(&msm_hsic_ch_driver);
+#ifdef CONFIG_DIAG_OVER_USB
+ usb_diag_close(driver->mdm_ch);
+#endif
+ kfree(driver->buf_in_hsic);
+ kfree(driver->usb_buf_mdm_out);
+ kfree(driver->write_ptr_mdm);
+ kfree(driver->usb_read_mdm_ptr);
+ destroy_workqueue(driver->diag_hsic_wq);
+
+ driver->hsic_device_enabled = 0;
+}
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
new file mode 100644
index 0000000..6769052
--- /dev/null
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAGFWD_HSIC_H
+#define DIAGFWD_HSIC_H
+
+#include <mach/diag_bridge.h>
+#define N_MDM_WRITE 1 /* Upgrade to 2 with ping pong buffer */
+#define N_MDM_READ 1
+
+void __init diagfwd_hsic_init(void);
+void __exit diagfwd_hsic_exit(void);
+
+#endif
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index f3873aa..a145c06 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -54,6 +54,13 @@
else {
APPEND_DEBUG('i');
sdio_read(driver->sdio_ch, buf, r);
+ if (((!driver->usb_connected) && (driver->
+ logging_mode == USB_MODE)) || (driver->
+ logging_mode == NO_LOGGING_MODE)) {
+ /* Drop the diag payload */
+ driver->in_busy_sdio = 0;
+ return;
+ }
APPEND_DEBUG('j');
driver->write_ptr_mdm->length = r;
driver->in_busy_sdio = 1;
@@ -149,8 +156,13 @@
void diag_read_mdm_work_fn(struct work_struct *work)
{
if (driver->sdio_ch) {
- wait_event_interruptible(driver->wait_q, (sdio_write_avail
- (driver->sdio_ch) >= driver->read_len_mdm));
+ wait_event_interruptible(driver->wait_q, ((sdio_write_avail
+ (driver->sdio_ch) >= driver->read_len_mdm) ||
+ !(driver->sdio_ch)));
+ if (!(driver->sdio_ch)) {
+ pr_alert("diag: sdio channel not valid");
+ return;
+ }
if (driver->sdio_ch && driver->usb_buf_mdm_out &&
(driver->read_len_mdm > 0))
sdio_write(driver->sdio_ch, driver->usb_buf_mdm_out,
@@ -181,15 +193,10 @@
static int diag_sdio_remove(struct platform_device *pdev)
{
- queue_work(driver->diag_sdio_wq, &(driver->diag_remove_sdio_work));
- return 0;
-}
-
-static void diag_remove_sdio_work_fn(struct work_struct *work)
-{
- pr_debug("diag: sdio remove called\n");
- /*Disable SDIO channel to prevent further read/write */
+ pr_debug("\n diag: sdio remove called");
+ /* Disable SDIO channel to prevent further read/write */
driver->sdio_ch = NULL;
+ return 0;
}
static int diagfwd_sdio_runtime_suspend(struct device *dev)
@@ -253,7 +260,6 @@
INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
#endif
INIT_WORK(&(driver->diag_read_sdio_work), diag_read_sdio_work_fn);
- INIT_WORK(&(driver->diag_remove_sdio_work), diag_remove_sdio_work_fn);
INIT_WORK(&(driver->diag_close_sdio_work), diag_close_sdio_work_fn);
ret = platform_driver_register(&msm_sdio_ch_driver);
if (ret)
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index edf5c27..7b77fa3 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -82,6 +82,7 @@
#define MAX_SESSIONS 16
#define INVALID_SESSION -1
#define VERSION_KEY_MASK 0xFFFFFF00
+#define MAX_DOWNSCALE_RATIO 3
struct tile_parm {
unsigned int width; /* tile's width */
@@ -428,7 +429,9 @@
}
iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
(ROTATIONS_TO_BITMASK(info->rotations) << 9) |
- 1 << 8, /* ROT_EN */
+ 1 << 8 | /* ROT_EN */
+ info->downscale_ratio << 2 | /* downscale v ratio */
+ info->downscale_ratio, /* downscale h ratio */
MSM_ROTATOR_SUB_BLOCK_CFG);
iowrite32(0 << 29 | /* frame format 0 = linear */
(use_imem ? 0 : 1) << 22 | /* tile size */
@@ -480,6 +483,11 @@
if (info->dst.format != dst_format)
return -EINVAL;
+ /* rotator expects YCbCr for planar input format */
+ if (info->src.format == MDP_Y_CR_CB_H2V2 ||
+ info->src.format == MDP_Y_CR_CB_GH2V2)
+ swap(in_chroma_paddr, in_chroma2_paddr);
+
iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
@@ -528,7 +536,9 @@
}
iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
(ROTATIONS_TO_BITMASK(info->rotations) << 9) |
- 1 << 8, /* ROT_EN */
+ 1 << 8 | /* ROT_EN */
+ info->downscale_ratio << 2 | /* downscale v ratio */
+ info->downscale_ratio, /* downscale h ratio */
MSM_ROTATOR_SUB_BLOCK_CFG);
iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
@@ -579,7 +589,9 @@
MSM_ROTATOR_OUT_PACK_PATTERN1);
iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
(ROTATIONS_TO_BITMASK(info->rotations) << 9) |
- 1 << 8, /* ROT_EN */
+ 1 << 8 | /* ROT_EN */
+ info->downscale_ratio << 2 | /* downscale v ratio */
+ info->downscale_ratio, /* downscale h ratio */
MSM_ROTATOR_SUB_BLOCK_CFG);
iowrite32(0 << 29 | /* frame format 0 = linear */
(use_imem ? 0 : 1) << 22 | /* tile size */
@@ -624,7 +636,9 @@
iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
iowrite32((0 << 18) | /* chroma sampling 0=rgb */
(ROTATIONS_TO_BITMASK(info->rotations) << 9) |
- 1 << 8, /* ROT_EN */
+ 1 << 8 | /* ROT_EN */
+ info->downscale_ratio << 2 | /* downscale v ratio */
+ info->downscale_ratio, /* downscale h ratio */
MSM_ROTATOR_SUB_BLOCK_CFG);
switch (info->src.format) {
case MDP_RGB_565:
@@ -1068,24 +1082,31 @@
if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
return -EFAULT;
- if (info.rotations & MDP_ROT_90) {
- dst_w = info.src_rect.h;
- dst_h = info.src_rect.w;
- } else {
- dst_w = info.src_rect.w;
- dst_h = info.src_rect.h;
- }
-
if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
(info.src.height > MSM_ROTATOR_MAX_H) ||
(info.src.width > MSM_ROTATOR_MAX_W) ||
(info.dst.height > MSM_ROTATOR_MAX_H) ||
(info.dst.width > MSM_ROTATOR_MAX_W) ||
- checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
+ (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
+ pr_err("%s: Invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (info.rotations & MDP_ROT_90) {
+ dst_w = info.src_rect.h >> info.downscale_ratio;
+ dst_h = info.src_rect.w >> info.downscale_ratio;
+ } else {
+ dst_w = info.src_rect.w >> info.downscale_ratio;
+ dst_h = info.src_rect.h >> info.downscale_ratio;
+ }
+
+ if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
checkoffset(info.dst_x, dst_w, info.dst.width) ||
- checkoffset(info.dst_y, dst_h, info.dst.height))
- return -EINVAL;
+ checkoffset(info.dst_y, dst_h, info.dst.height)) {
+ pr_err("%s: Invalid src or dst rect\n", __func__);
+ return -ERANGE;
+ }
switch (info.src.format) {
case MDP_RGB_565:
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 3ae1647..c1a65fc 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -31,6 +31,7 @@
#include <crypto/hash.h>
#include <linux/platform_data/qcom_crypto_device.h>
#include <mach/scm.h>
+#include <mach/msm_bus.h>
#include <linux/qcedev.h>
#include "qce.h"
@@ -97,7 +98,7 @@
};
static DEFINE_MUTEX(send_cmd_lock);
-
+static DEFINE_MUTEX(sent_bw_req);
/**********************************************************************
* Register ourselves as a misc device to be able to access the dev driver
* from userspace. */
@@ -111,9 +112,13 @@
struct msm_ce_hw_support platform_support;
uint32_t ce_lock_count;
+ uint32_t high_bw_req_count;
+
/* CE features/algorithms supported by HW engine*/
struct ce_hw_support ce_support;
+ uint32_t bus_scale_handle;
+
/* misc device */
struct miscdevice miscdevice;
@@ -167,6 +172,29 @@
#endif
}
+static int qcedev_ce_high_bw_req(struct qcedev_control *podev,
+ bool high_bw_req)
+{
+ int ret = 0;
+
+ mutex_lock(&sent_bw_req);
+ if (high_bw_req) {
+ if (podev->high_bw_req_count == 0)
+ msm_bus_scale_client_update_request(
+ podev->bus_scale_handle, 1);
+ podev->high_bw_req_count++;
+ } else {
+ if (podev->high_bw_req_count == 1)
+ msm_bus_scale_client_update_request(
+ podev->bus_scale_handle, 0);
+ podev->high_bw_req_count--;
+ }
+ mutex_unlock(&sent_bw_req);
+
+ return ret;
+}
+
+
static int qcedev_unlock_ce(struct qcedev_control *podev)
{
int ret = 0;
@@ -302,7 +330,8 @@
handle->cntl = podev;
file->private_data = handle;
-
+ if (podev->platform_support.bus_scale_table != NULL)
+ return qcedev_ce_high_bw_req(podev, true);
return 0;
}
@@ -319,7 +348,8 @@
}
kzfree(handle);
file->private_data = NULL;
-
+ if (podev->platform_support.bus_scale_table != NULL)
+ return qcedev_ce_high_bw_req(podev, false);
return 0;
}
@@ -1992,7 +2022,10 @@
platform_support->shared_ce_resource;
podev->platform_support.hw_key_support =
platform_support->hw_key_support;
+ podev->platform_support.bus_scale_table =
+ platform_support->bus_scale_table;
podev->ce_lock_count = 0;
+ podev->high_bw_req_count = 0;
INIT_LIST_HEAD(&podev->ready_commands);
podev->active_command = NULL;
@@ -2011,10 +2044,28 @@
podev->pdev = pdev;
platform_set_drvdata(pdev, podev);
qce_hw_support(podev->qce, &podev->ce_support);
+
+ if (podev->platform_support.bus_scale_table != NULL) {
+ podev->bus_scale_handle =
+ msm_bus_scale_register_client(
+ (struct msm_bus_scale_pdata *)
+ podev->platform_support.bus_scale_table);
+ if (!podev->bus_scale_handle) {
+ printk(KERN_ERR "%s not able to get bus scale\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err;
+ }
+ }
rc = misc_register(&podev->miscdevice);
if (rc >= 0)
return 0;
+ else
+ if (podev->platform_support.bus_scale_table != NULL)
+ msm_bus_scale_unregister_client(
+ podev->bus_scale_handle);
+err:
if (handle)
qce_close(handle);
@@ -2034,6 +2085,9 @@
if (podev->qce)
qce_close(podev->qce);
+ if (podev->platform_support.bus_scale_table != NULL)
+ msm_bus_scale_unregister_client(podev->bus_scale_handle);
+
if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
misc_deregister(&podev->miscdevice);
tasklet_kill(&podev->done_tasklet);
@@ -2164,7 +2218,7 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.24");
+MODULE_VERSION("1.25");
module_init(qcedev_init);
module_exit(qcedev_exit);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 67301877..3fff05c 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -37,6 +37,7 @@
#include <mach/scm.h>
#include <linux/platform_data/qcom_crypto_device.h>
+#include <mach/msm_bus.h>
#include "qce.h"
@@ -80,6 +81,8 @@
/* CE features/algorithms supported by HW engine*/
struct ce_hw_support ce_support;
+
+ uint32_t bus_scale_handle;
/* the lock protects queue and req*/
spinlock_t lock;
@@ -100,6 +103,7 @@
struct crypto_queue queue;
uint32_t ce_lock_count;
+ uint32_t high_bw_req_count;
struct work_struct unlock_ce_ws;
@@ -116,6 +120,8 @@
#define NUM_RETRY 1000
#define CE_BUSY 55
+static DEFINE_MUTEX(sent_bw_req);
+
static int qcrypto_scm_cmd(int resource, int cmd, int *response)
{
#ifdef CONFIG_MSM_SCM
@@ -323,6 +329,27 @@
}
}
+static int qcrypto_ce_high_bw_req(struct crypto_priv *cp, bool high_bw_req)
+{
+ int ret = 0;
+
+ mutex_lock(&sent_bw_req);
+ if (high_bw_req) {
+ if (cp->high_bw_req_count == 0)
+ ret = msm_bus_scale_client_update_request(
+ cp->bus_scale_handle, 1);
+ cp->high_bw_req_count++;
+ } else {
+ if (cp->high_bw_req_count == 1)
+ ret = msm_bus_scale_client_update_request(
+ cp->bus_scale_handle, 0);
+ cp->high_bw_req_count--;
+ }
+ mutex_unlock(&sent_bw_req);
+
+ return ret;
+}
+
static void _start_qcrypto_process(struct crypto_priv *cp);
static struct qcrypto_alg *_qcrypto_sha_alg_alloc(struct crypto_priv *cp,
@@ -375,6 +402,8 @@
/* random first IV */
get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
+ if (ctx->cp->platform_support.bus_scale_table != NULL)
+ return qcrypto_ce_high_bw_req(ctx->cp, true);
return 0;
};
@@ -410,6 +439,9 @@
}
sha_ctx->ahash_req = NULL;
+ if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
+ return qcrypto_ce_high_bw_req(sha_ctx->cp, true);
+
return 0;
};
@@ -429,6 +461,8 @@
ahash_request_free(sha_ctx->ahash_req);
sha_ctx->ahash_req = NULL;
}
+ if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
+ qcrypto_ce_high_bw_req(sha_ctx->cp, false);
};
@@ -458,6 +492,9 @@
&sha_ctx->ahash_req_complete);
crypto_ahash_clear_flags(ahash, ~0);
+ if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
+ qcrypto_ce_high_bw_req(sha_ctx->cp, true);
+
return 0;
};
@@ -473,6 +510,22 @@
return _qcrypto_cipher_cra_init(tfm);
};
+static void _qcrypto_cra_ablkcipher_exit(struct crypto_tfm *tfm)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (ctx->cp->platform_support.bus_scale_table != NULL)
+ qcrypto_ce_high_bw_req(ctx->cp, false);
+};
+
+static void _qcrypto_cra_aead_exit(struct crypto_tfm *tfm)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (ctx->cp->platform_support.bus_scale_table != NULL)
+ qcrypto_ce_high_bw_req(ctx->cp, false);
+};
+
static int _disp_stats(int id)
{
struct crypto_stat *pstat;
@@ -577,6 +630,9 @@
if (!cp)
return 0;
+ if (cp->platform_support.bus_scale_table != NULL)
+ msm_bus_scale_unregister_client(cp->bus_scale_handle);
+
list_for_each_entry_safe(q_alg, n, &cp->alg_list, entry) {
if (q_alg->alg_type == QCRYPTO_ALG_CIPHER)
crypto_unregister_alg(&q_alg->cipher_alg);
@@ -2676,6 +2732,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
@@ -2697,6 +2754,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.ivsize = AES_BLOCK_SIZE,
@@ -2719,6 +2777,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.ivsize = AES_BLOCK_SIZE,
@@ -2741,6 +2800,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.min_keysize = DES_KEY_SIZE,
@@ -2762,6 +2822,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.ivsize = DES_BLOCK_SIZE,
@@ -2784,6 +2845,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.min_keysize = DES3_EDE_KEY_SIZE,
@@ -2805,6 +2867,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.ivsize = DES3_EDE_BLOCK_SIZE,
@@ -2829,6 +2892,7 @@
.cra_type = &crypto_ablkcipher_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_ablkcipher_init,
+ .cra_exit = _qcrypto_cra_ablkcipher_exit,
.cra_u = {
.ablkcipher = {
.ivsize = AES_BLOCK_SIZE,
@@ -2853,6 +2917,7 @@
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
.cra_u = {
.aead = {
.ivsize = AES_BLOCK_SIZE,
@@ -2879,6 +2944,7 @@
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
.cra_u = {
.aead = {
.ivsize = AES_BLOCK_SIZE,
@@ -2904,6 +2970,7 @@
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
.cra_u = {
.aead = {
.ivsize = DES_BLOCK_SIZE,
@@ -2928,6 +2995,7 @@
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
.cra_u = {
.aead = {
.ivsize = DES3_EDE_BLOCK_SIZE,
@@ -2954,6 +3022,7 @@
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
.cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
.cra_u = {
.aead = {
.ivsize = AES_BLOCK_SIZE,
@@ -3011,12 +3080,28 @@
platform_support->shared_ce_resource;
cp->platform_support.hw_key_support =
platform_support->hw_key_support;
+ cp->platform_support.bus_scale_table =
+ platform_support->bus_scale_table;
+ cp->high_bw_req_count = 0;
cp->ce_lock_count = 0;
cp->platform_support.sha_hmac = platform_support->sha_hmac;
if (cp->platform_support.ce_shared)
INIT_WORK(&cp->unlock_ce_ws, qcrypto_unlock_ce);
+ if (cp->platform_support.bus_scale_table != NULL) {
+ cp->bus_scale_handle =
+ msm_bus_scale_register_client(
+ (struct msm_bus_scale_pdata *)
+ cp->platform_support.bus_scale_table);
+ if (!cp->bus_scale_handle) {
+ printk(KERN_ERR "%s not able to get bus scale\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err;
+ }
+ }
+
/* register crypto cipher algorithms the device supports */
for (i = 0; i < ARRAY_SIZE(_qcrypto_ablk_cipher_algos); i++) {
struct qcrypto_alg *q_alg;
@@ -3274,4 +3359,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm Crypto driver");
-MODULE_VERSION("1.19");
+MODULE_VERSION("1.20");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 385e9c7..8f3263e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -454,16 +454,6 @@
Select this option to enable GPIO driver for the TPS65910
chip family.
-config MPP_PMIC8901
- tristate "Qualcomm PMIC8901 MPP"
- depends on GPIOLIB && PMIC8901
- default y
- help
- Say yes here to support GPIO functionality on Qualcomm's
- PM8901 chip for MPP(Multi-Purpose Pin) pins. These pins
- work like GPIO pins when configured as digital input and/or
- output signals.
-
config GPIO_PM8XXX
tristate "Qualcomm PM8xxx GPIO support"
depends on MFD_PM8XXX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1b2c4b1..83972f1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -48,7 +48,6 @@
obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o
obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o
obj-$(CONFIG_GPIO_TPS65910) += tps65910-gpio.o
-obj-$(CONFIG_MPP_PMIC8901) += pmic8901-mpp.o
obj-$(CONFIG_GPIO_PM8XXX) += pm8xxx-gpio.o
obj-$(CONFIG_GPIO_PM8XXX_MPP) += pm8xxx-mpp.o
obj-$(CONFIG_GPIO_PM8XXX_RPC) += gpio-pm8xxx-rpc.o
diff --git a/drivers/gpio/pmic8901-mpp.c b/drivers/gpio/pmic8901-mpp.c
deleted file mode 100644
index 85e6539..0000000
--- a/drivers/gpio/pmic8901-mpp.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-/*
- * Qualcomm PMIC8901 MPP driver
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/mfd/pmic8901.h>
-#include <mach/mpp.h>
-#include <linux/seq_file.h>
-
-/* MPP Control Registers */
-#define SSBI_MPP_CNTRL_BASE 0x27
-#define SSBI_MPP_CNTRL(n) (SSBI_MPP_CNTRL_BASE + (n))
-
-/* MPP Type */
-#define PM8901_MPP_TYPE_MASK 0xE0
-#define PM8901_MPP_TYPE_SHIFT 5
-
-/* MPP Config Level */
-#define PM8901_MPP_CONFIG_LVL_MASK 0x1C
-#define PM8901_MPP_CONFIG_LVL_SHIFT 2
-
-/* MPP Config Control */
-#define PM8901_MPP_CONFIG_CTL_MASK 0x03
-
-struct pm8901_mpp_chip {
- struct gpio_chip chip;
- struct pm8901_chip *pm_chip;
- u8 ctrl[PM8901_MPPS];
-};
-
-static int pm8901_mpp_write(struct pm8901_chip *chip, u16 addr, u8 val,
- u8 mask, u8 *bak)
-{
- u8 reg = (*bak & ~mask) | (val & mask);
- int rc = pm8901_write(chip, addr, ®, 1);
- if (!rc)
- *bak = reg;
- return rc;
-}
-
-static int pm8901_mpp_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct pm8901_gpio_platform_data *pdata;
- pdata = chip->dev->platform_data;
- return pdata->irq_base + offset;
-}
-
-static int pm8901_mpp_get(struct gpio_chip *chip, unsigned offset)
-{
- struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
- int ret;
-
- if ((mpp_chip->ctrl[offset] & PM8901_MPP_TYPE_MASK) >>
- PM8901_MPP_TYPE_SHIFT == PM_MPP_TYPE_D_OUTPUT)
- ret = mpp_chip->ctrl[offset] & PM8901_MPP_CONFIG_CTL_MASK;
- else
- ret = pm8901_irq_get_rt_status(mpp_chip->pm_chip,
- pm8901_mpp_to_irq(chip, offset));
- return ret;
-}
-
-static void pm8901_mpp_set(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
- u8 reg = val ? PM_MPP_DOUT_CTL_HIGH : PM_MPP_DOUT_CTL_LOW;
- int rc;
-
- rc = pm8901_mpp_write(mpp_chip->pm_chip, SSBI_MPP_CNTRL(offset),
- reg, PM8901_MPP_CONFIG_CTL_MASK,
- &mpp_chip->ctrl[offset]);
- if (rc)
- pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
-}
-
-static int pm8901_mpp_dir_input(struct gpio_chip *chip, unsigned offset)
-{
- struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
- int rc = pm8901_mpp_write(mpp_chip->pm_chip,
- SSBI_MPP_CNTRL(offset),
- PM_MPP_TYPE_D_INPUT << PM8901_MPP_TYPE_SHIFT,
- PM8901_MPP_TYPE_MASK, &mpp_chip->ctrl[offset]);
- if (rc)
- pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
- return rc;
-}
-
-static int pm8901_mpp_dir_output(struct gpio_chip *chip,
- unsigned offset, int val)
-{
- struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
- u8 reg = (PM_MPP_TYPE_D_OUTPUT << PM8901_MPP_TYPE_SHIFT) |
- (val & PM8901_MPP_CONFIG_CTL_MASK);
- u8 mask = PM8901_MPP_TYPE_MASK | PM8901_MPP_CONFIG_CTL_MASK;
- int rc = pm8901_mpp_write(mpp_chip->pm_chip,
- SSBI_MPP_CNTRL(offset), reg, mask,
- &mpp_chip->ctrl[offset]);
- if (rc)
- pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
- return rc;
-}
-
-static void pm8901_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
- static const char *ctype[] = { "d_in", "d_out", "bi_dir", "a_in",
- "a_out", "sink", "dtest_sink", "dtest_out" };
- struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
- u8 type, state;
- const char *label;
- int i;
-
- for (i = 0; i < PM8901_MPPS; i++) {
- label = gpiochip_is_requested(chip, i);
- type = (mpp_chip->ctrl[i] & PM8901_MPP_TYPE_MASK) >>
- PM8901_MPP_TYPE_SHIFT;
- state = pm8901_mpp_get(chip, i);
- seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
- " %s 0x%02x\n",
- chip->base + i,
- label ? label : "--",
- ctype[type],
- state ? "hi" : "lo",
- mpp_chip->ctrl[i]);
- }
-}
-
-static struct pm8901_mpp_chip pm8901_mpp_chip = {
- .chip = {
- .label = "pm8901-mpp",
- .to_irq = pm8901_mpp_to_irq,
- .get = pm8901_mpp_get,
- .set = pm8901_mpp_set,
- .direction_input = pm8901_mpp_dir_input,
- .direction_output = pm8901_mpp_dir_output,
- .dbg_show = pm8901_mpp_dbg_show,
- .ngpio = PM8901_MPPS,
- },
-};
-
-int pm8901_mpp_config(unsigned mpp, unsigned type, unsigned level,
- unsigned control)
-{
- u8 config, mask;
- int rc;
-
- if (mpp >= PM8901_MPPS)
- return -EINVAL;
-
- mask = PM8901_MPP_TYPE_MASK | PM8901_MPP_CONFIG_LVL_MASK |
- PM8901_MPP_CONFIG_CTL_MASK;
- config = (type << PM8901_MPP_TYPE_SHIFT) & PM8901_MPP_TYPE_MASK;
- config |= (level << PM8901_MPP_CONFIG_LVL_SHIFT) &
- PM8901_MPP_CONFIG_LVL_MASK;
- config |= control & PM8901_MPP_CONFIG_CTL_MASK;
-
- rc = pm8901_mpp_write(pm8901_mpp_chip.pm_chip, SSBI_MPP_CNTRL(mpp),
- config, mask, &pm8901_mpp_chip.ctrl[mpp]);
- if (rc)
- pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8901_mpp_config);
-
-static int __devinit pm8901_mpp_probe(struct platform_device *pdev)
-{
- int ret, i;
- struct pm8901_gpio_platform_data *pdata = pdev->dev.platform_data;
-
- pm8901_mpp_chip.pm_chip = dev_get_drvdata(pdev->dev.parent);
- for (i = 0; i < PM8901_MPPS; i++) {
- ret = pm8901_read(pm8901_mpp_chip.pm_chip,
- SSBI_MPP_CNTRL(i), &pm8901_mpp_chip.ctrl[i], 1);
- if (ret)
- goto bail;
-
- }
- platform_set_drvdata(pdev, &pm8901_mpp_chip);
- pm8901_mpp_chip.chip.dev = &pdev->dev;
- pm8901_mpp_chip.chip.base = pdata->gpio_base;
- ret = gpiochip_add(&pm8901_mpp_chip.chip);
-
-bail:
- pr_info("%s: gpiochip_add(): rc=%d\n", __func__, ret);
- return ret;
-}
-
-static int __devexit pm8901_mpp_remove(struct platform_device *pdev)
-{
- return gpiochip_remove(&pm8901_mpp_chip.chip);
-}
-
-static struct platform_driver pm8901_mpp_driver = {
- .probe = pm8901_mpp_probe,
- .remove = __devexit_p(pm8901_mpp_remove),
- .driver = {
- .name = "pm8901-mpp",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8901_mpp_init(void)
-{
- return platform_driver_register(&pm8901_mpp_driver);
-}
-
-static void __exit pm8901_mpp_exit(void)
-{
- platform_driver_unregister(&pm8901_mpp_driver);
-}
-
-subsys_initcall(pm8901_mpp_init);
-module_exit(pm8901_mpp_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8901 MPP driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8901-mpp");
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 9cb338a..f1d40ef 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -36,8 +36,8 @@
ion_phys_addr_t base;
unsigned long allocated_bytes;
unsigned long total_size;
- void (*request_region)(void *);
- void (*release_region)(void *);
+ int (*request_region)(void *);
+ int (*release_region)(void *);
atomic_t map_count;
void *bus_id;
};
@@ -138,10 +138,17 @@
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
- if (atomic_inc_return(&carveout_heap->map_count) == 1)
- if (carveout_heap->request_region)
- carveout_heap->request_region(carveout_heap->bus_id);
-
+ if (atomic_inc_return(&carveout_heap->map_count) == 1) {
+ if (carveout_heap->request_region) {
+ int ret = carveout_heap->request_region(
+ carveout_heap->bus_id);
+ if (ret) {
+ pr_err("Unable to request SMI region");
+ atomic_dec(&carveout_heap->map_count);
+ return NULL;
+ }
+ }
+ }
if (ION_IS_CACHED(flags))
return ioremap_cached(buffer->priv_phys, buffer->size);
else
@@ -157,9 +164,14 @@
__arch_iounmap(buffer->vaddr);
buffer->vaddr = NULL;
- if (atomic_dec_and_test(&carveout_heap->map_count))
- if (carveout_heap->release_region)
- carveout_heap->release_region(carveout_heap->bus_id);
+ if (atomic_dec_and_test(&carveout_heap->map_count)) {
+ if (carveout_heap->release_region) {
+ int ret = carveout_heap->release_region(
+ carveout_heap->bus_id);
+ if (ret)
+ pr_err("Unable to release SMI region");
+ }
+ }
return;
}
@@ -170,9 +182,17 @@
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
- if (atomic_inc_return(&carveout_heap->map_count) == 1)
- if (carveout_heap->request_region)
- carveout_heap->request_region(carveout_heap->bus_id);
+ if (atomic_inc_return(&carveout_heap->map_count) == 1) {
+ if (carveout_heap->request_region) {
+ int ret = carveout_heap->request_region(
+ carveout_heap->bus_id);
+ if (ret) {
+ pr_err("Unable to request SMI region");
+ atomic_dec(&carveout_heap->map_count);
+ return -EINVAL;
+ }
+ }
+ }
if (ION_IS_CACHED(flags))
return remap_pfn_range(vma, vma->vm_start,
@@ -192,9 +212,14 @@
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
- if (atomic_dec_and_test(&carveout_heap->map_count))
- if (carveout_heap->release_region)
- carveout_heap->release_region(carveout_heap->bus_id);
+ if (atomic_dec_and_test(&carveout_heap->map_count)) {
+ if (carveout_heap->release_region) {
+ int ret = carveout_heap->release_region(
+ carveout_heap->bus_id);
+ if (ret)
+ pr_err("Unable to release SMI region");
+ }
+ }
}
int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d2e4e4b..a8a0e59 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -194,7 +194,7 @@
if (device->requested_state == KGSL_STATE_NONE) {
if (device->pwrctrl.nap_allowed == true) {
- device->requested_state = KGSL_STATE_NAP;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
queue_work(device->work_queue, &device->idle_check_ws);
} else if (device->pwrscale.policy != NULL) {
queue_work(device->work_queue, &device->idle_check_ws);
@@ -495,8 +495,7 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int init_reftimestamp = 0x7fffffff;
- device->state = KGSL_STATE_INIT;
- device->requested_state = KGSL_STATE_NONE;
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
/* Power up the device */
kgsl_pwrctrl_enable(device);
@@ -716,33 +715,27 @@
static int
adreno_dump_and_recover(struct kgsl_device *device)
{
- static int recovery;
int result = -ETIMEDOUT;
if (device->state == KGSL_STATE_HUNG)
goto done;
- if (device->state == KGSL_STATE_DUMP_AND_RECOVER && !recovery) {
+ if (device->state == KGSL_STATE_DUMP_AND_RECOVER) {
mutex_unlock(&device->mutex);
wait_for_completion(&device->recovery_gate);
mutex_lock(&device->mutex);
- if (!(device->state & KGSL_STATE_HUNG))
- /* recovery success */
+ if (device->state != KGSL_STATE_HUNG)
result = 0;
} else {
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_RECOVER);
INIT_COMPLETION(device->recovery_gate);
/* Detected a hang - trigger an automatic dump */
adreno_postmortem_dump(device, 0);
- if (!recovery) {
- recovery = 1;
- result = adreno_recover_hang(device);
- if (result)
- device->state = KGSL_STATE_HUNG;
- recovery = 0;
- complete_all(&device->recovery_gate);
- } else
- KGSL_DRV_ERR(device,
- "Cannot recover from another hang while "
- "recovering from a hang\n");
+ result = adreno_recover_hang(device);
+ if (result)
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
+ else
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ complete_all(&device->recovery_gate);
}
done:
return result;
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 9e49e6a..aafef21 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -21,6 +21,7 @@
#include "adreno_postmortem.h"
#include "adreno_debugfs.h"
#include "kgsl_cffdump.h"
+#include "kgsl_pwrctrl.h"
#include "a2xx_reg.h"
@@ -828,11 +829,9 @@
/* Disable the idle timer so we don't get interrupted */
del_timer_sync(&device->idle_timer);
-
mutex_unlock(&device->mutex);
flush_workqueue(device->work_queue);
mutex_lock(&device->mutex);
- adreno_dump(device);
/* Turn off napping to make sure we have the clocks full
attention through the following process */
@@ -845,15 +844,7 @@
/* Disable the irq */
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
- /* If this is not a manual trigger, then set up the
- state to try to recover */
-
- if (!manual) {
- device->state = KGSL_STATE_DUMP_AND_RECOVER;
- KGSL_PWR_WARN(device,
- "state -> DUMP_AND_RECOVER, device %d\n",
- device->id);
- }
+ adreno_dump(device);
/* Restore nap mode */
device->pwrctrl.nap_allowed = saved_nap;
@@ -867,7 +858,7 @@
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
/* try to go into a sleep mode until the next event */
- device->requested_state = KGSL_STATE_SLEEP;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
kgsl_pwrctrl_sleep(device);
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a0982006..7ace67a 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -393,7 +393,6 @@
if (rb->flags & KGSL_FLAGS_STARTED) {
/* ME_HALT */
adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
-
rb->flags &= ~KGSL_FLAGS_STARTED;
}
}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7a42dcd..3207040 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -302,7 +302,7 @@
if (device->pwrctrl.nap_allowed == true &&
device->state == KGSL_STATE_ACTIVE &&
device->requested_state == KGSL_STATE_NONE) {
- device->requested_state = KGSL_STATE_NAP;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
if (kgsl_pwrctrl_sleep(device) != 0)
mod_timer(&device->idle_timer,
jiffies +
@@ -395,7 +395,7 @@
device->pwrctrl.nap_allowed = false;
policy_saved = device->pwrscale.policy;
device->pwrscale.policy = NULL;
- device->requested_state = KGSL_STATE_SUSPEND;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
/* Make sure no user process is waiting for a timestamp *
* before supending */
if (device->active_cnt != 0) {
@@ -417,22 +417,18 @@
INIT_COMPLETION(device->hwaccess_gate);
device->ftbl->suspend_context(device);
device->ftbl->stop(device);
- device->state = KGSL_STATE_SUSPEND;
- KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n",
- device->id);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
break;
case KGSL_STATE_SLUMBER:
INIT_COMPLETION(device->hwaccess_gate);
- device->state = KGSL_STATE_SUSPEND;
- KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n",
- device->id);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
break;
default:
KGSL_PWR_ERR(device, "suspend fail, device %d\n",
device->id);
goto end;
}
- device->requested_state = KGSL_STATE_NONE;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
device->pwrctrl.nap_allowed = nap_allowed_saved;
device->pwrscale.policy = policy_saved;
status = 0;
@@ -453,14 +449,11 @@
KGSL_PWR_WARN(device, "resume start\n");
mutex_lock(&device->mutex);
if (device->state == KGSL_STATE_SUSPEND) {
- device->state = KGSL_STATE_SLUMBER;
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
status = 0;
- KGSL_PWR_WARN(device,
- "state -> SLUMBER, device %d\n",
- device->id);
complete_all(&device->hwaccess_gate);
}
- device->requested_state = KGSL_STATE_NONE;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
mutex_unlock(&device->mutex);
KGSL_PWR_WARN(device, "resume end\n");
@@ -505,7 +498,7 @@
struct kgsl_device, display_off);
KGSL_PWR_WARN(device, "early suspend start\n");
mutex_lock(&device->mutex);
- device->requested_state = KGSL_STATE_SLUMBER;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
kgsl_pwrctrl_sleep(device);
mutex_unlock(&device->mutex);
KGSL_PWR_WARN(device, "early suspend end\n");
@@ -535,6 +528,7 @@
mutex_lock(&device->mutex);
kgsl_pwrctrl_wake(device);
device->pwrctrl.restore_slumber = 0;
+ kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
mutex_unlock(&device->mutex);
kgsl_check_idle(device);
KGSL_PWR_WARN(device, "late resume end\n");
@@ -651,8 +645,7 @@
device->open_count--;
if (device->open_count == 0) {
result = device->ftbl->stop(device);
- device->state = KGSL_STATE_INIT;
- KGSL_PWR_WARN(device, "state -> INIT, device %d\n", device->id);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
}
/* clean up any to-be-freed entries that belong to this
* process and this device
@@ -720,9 +713,7 @@
mutex_unlock(&device->mutex);
goto err_putprocess;
}
- device->state = KGSL_STATE_ACTIVE;
- KGSL_PWR_WARN(device,
- "state -> ACTIVE, device %d\n", minor);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
}
device->open_count++;
mutex_unlock(&device->mutex);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 3ef11ce..f82b038 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -175,6 +175,7 @@
struct kobject pwrscale_kobj;
struct work_struct ts_expired_ws;
struct list_head events;
+ s64 on_time;
};
struct kgsl_context {
@@ -317,4 +318,6 @@
irqreturn_t (*dev_isr) (int, void*));
void kgsl_device_platform_remove(struct kgsl_device *device);
+const char *kgsl_pwrstate_to_str(unsigned int state);
+
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index dbbe4d5..f4abf99 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -18,6 +18,7 @@
#include "kgsl.h"
#include "kgsl_pwrscale.h"
#include "kgsl_device.h"
+#include "kgsl_trace.h"
#define KGSL_PWRFLAGS_POWER_ON 0
#define KGSL_PWRFLAGS_CLK_ON 1
@@ -62,24 +63,20 @@
if (new_level < (pwr->num_pwrlevels - 1) &&
new_level >= pwr->thermal_pwrlevel &&
new_level != pwr->active_pwrlevel) {
+ struct kgsl_pwrlevel *pwrlevel = &pwr->pwrlevels[new_level];
pwr->active_pwrlevel = new_level;
if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
(device->state == KGSL_STATE_NAP))
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->active_pwrlevel].
- gpu_freq);
+ clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq);
if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
if (pwr->pcl)
msm_bus_scale_client_update_request(pwr->pcl,
- pwr->pwrlevels[pwr->active_pwrlevel].
- bus_freq);
+ pwrlevel->bus_freq);
else if (pwr->ebi1_clk)
- clk_set_rate(pwr->ebi1_clk,
- pwr->pwrlevels[pwr->active_pwrlevel].
- bus_freq);
+ clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
}
- KGSL_PWR_WARN(device, "kgsl pwr level changed to %d\n",
- pwr->active_pwrlevel);
+ trace_kgsl_pwrlevel(device, pwr->active_pwrlevel,
+ pwrlevel->gpu_freq);
}
}
EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
@@ -335,8 +332,7 @@
if (state == KGSL_PWRFLAGS_OFF) {
if (test_and_clear_bit(KGSL_PWRFLAGS_CLK_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "clocks off, device %d\n", device->id);
+ trace_kgsl_clk(device, state);
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
if (pwr->grp_clks[i])
clk_disable(pwr->grp_clks[i]);
@@ -350,9 +346,7 @@
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "clocks on, device %d\n", device->id);
-
+ trace_kgsl_clk(device, state);
if ((pwr->pwrlevels[0].gpu_freq > 0) &&
(device->state != KGSL_STATE_NAP))
clk_set_rate(pwr->grp_clks[0],
@@ -376,8 +370,7 @@
if (state == KGSL_PWRFLAGS_OFF) {
if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "axi off, device %d\n", device->id);
+ trace_kgsl_bus(device, state);
if (pwr->ebi1_clk) {
clk_set_rate(pwr->ebi1_clk, 0);
clk_disable(pwr->ebi1_clk);
@@ -389,8 +382,7 @@
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "axi on, device %d\n", device->id);
+ trace_kgsl_bus(device, state);
if (pwr->ebi1_clk) {
clk_enable(pwr->ebi1_clk);
clk_set_rate(pwr->ebi1_clk,
@@ -412,16 +404,14 @@
if (state == KGSL_PWRFLAGS_OFF) {
if (test_and_clear_bit(KGSL_PWRFLAGS_POWER_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "power off, device %d\n", device->id);
+ trace_kgsl_rail(device, state);
if (pwr->gpu_reg)
regulator_disable(pwr->gpu_reg);
}
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_POWER_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "power on, device %d\n", device->id);
+ trace_kgsl_rail(device, state);
if (pwr->gpu_reg)
regulator_enable(pwr->gpu_reg);
}
@@ -435,16 +425,14 @@
if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_IRQ_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "irq on, device %d\n", device->id);
+ trace_kgsl_irq(device, state);
enable_irq(pwr->interrupt_num);
device->ftbl->irqctrl(device, 1);
}
} else if (state == KGSL_PWRFLAGS_OFF) {
if (test_and_clear_bit(KGSL_PWRFLAGS_IRQ_ON,
&pwr->power_flags)) {
- KGSL_PWR_INFO(device,
- "irq off, device %d\n", device->id);
+ trace_kgsl_irq(device, state);
device->ftbl->irqctrl(device, 0);
if (in_interrupt())
disable_irq_nosync(pwr->interrupt_num);
@@ -599,6 +587,9 @@
{
struct kgsl_device *device = container_of(work, struct kgsl_device,
idle_check_ws);
+ WARN_ON(device == NULL);
+ if (device == NULL)
+ return;
mutex_lock(&device->mutex);
if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
@@ -620,7 +611,7 @@
}
} else if (device->state & (KGSL_STATE_HUNG |
KGSL_STATE_DUMP_AND_RECOVER)) {
- device->requested_state = KGSL_STATE_NONE;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
}
mutex_unlock(&device->mutex);
@@ -632,7 +623,7 @@
KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
if (device->requested_state != KGSL_STATE_SUSPEND) {
- device->requested_state = KGSL_STATE_SLEEP;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
/* Have work run in a non-interrupt context. */
queue_work(device->work_queue, &device->idle_check_ws);
}
@@ -663,155 +654,182 @@
}
static int
-_slumber(struct kgsl_device *device)
+_nap(struct kgsl_device *device)
{
- int status = -EINVAL;
- if (!device)
- return -EINVAL;
- KGSL_PWR_WARN(device, "Slumber start\n");
-
- device->requested_state = KGSL_STATE_SLUMBER;
- del_timer(&device->idle_timer);
switch (device->state) {
case KGSL_STATE_ACTIVE:
- /* Wait for the device to become idle */
- device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
+ if (!device->ftbl->isidle(device)) {
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+ return -EBUSY;
+ }
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
+ if (device->idle_wakelock.name)
+ wake_unlock(&device->idle_wakelock);
case KGSL_STATE_NAP:
case KGSL_STATE_SLEEP:
- device->ftbl->suspend_context(device);
- device->ftbl->stop(device);
- device->state = KGSL_STATE_SLUMBER;
- device->pwrctrl.restore_slumber = 1;
- KGSL_PWR_WARN(device, "state -> SLUMBER, device %d\n",
- device->id);
+ case KGSL_STATE_SLUMBER:
break;
default:
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
break;
}
- status = 0;
- /* Don't set requested state to NONE
- It's done in kgsl_pwrctrl_sleep*/
- KGSL_PWR_WARN(device, "Done going to slumber\n");
- return status;
+ return 0;
+}
+
+static void
+_sleep_accounting(struct kgsl_device *device)
+{
+ kgsl_pwrctrl_busy_time(device, false);
+ device->pwrctrl.busy.start.tv_sec = 0;
+ device->pwrctrl.time = 0;
+ kgsl_pwrscale_sleep(device);
+}
+
+static int
+_sleep(struct kgsl_device *device)
+{
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ switch (device->state) {
+ case KGSL_STATE_ACTIVE:
+ if (!device->ftbl->isidle(device)) {
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+ return -EBUSY;
+ }
+ /* fall through */
+ case KGSL_STATE_NAP:
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
+ if (pwr->pwrlevels[0].gpu_freq > 0)
+ clk_set_rate(pwr->grp_clks[0],
+ pwr->pwrlevels[pwr->num_pwrlevels - 1].
+ gpu_freq);
+ _sleep_accounting(device);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
+ if (device->idle_wakelock.name)
+ wake_unlock(&device->idle_wakelock);
+ break;
+ case KGSL_STATE_SLEEP:
+ case KGSL_STATE_SLUMBER:
+ break;
+ default:
+ KGSL_PWR_WARN(device, "unhandled state %s\n",
+ kgsl_pwrstate_to_str(device->state));
+ break;
+ }
+ return 0;
+}
+
+static int
+_slumber(struct kgsl_device *device)
+{
+ switch (device->state) {
+ case KGSL_STATE_ACTIVE:
+ if (!device->ftbl->isidle(device)) {
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+ device->pwrctrl.restore_slumber = true;
+ return -EBUSY;
+ }
+ /* fall through */
+ case KGSL_STATE_NAP:
+ case KGSL_STATE_SLEEP:
+ del_timer_sync(&device->idle_timer);
+ kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
+ device->ftbl->suspend_context(device);
+ device->ftbl->stop(device);
+ device->pwrctrl.restore_slumber = true;
+ _sleep_accounting(device);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
+ if (device->idle_wakelock.name)
+ wake_unlock(&device->idle_wakelock);
+ break;
+ case KGSL_STATE_SLUMBER:
+ break;
+ default:
+ KGSL_PWR_WARN(device, "unhandled state %s\n",
+ kgsl_pwrstate_to_str(device->state));
+ break;
+ }
+ return 0;
}
/******************************************************************/
/* Caller must hold the device mutex. */
int kgsl_pwrctrl_sleep(struct kgsl_device *device)
{
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ int status = 0;
KGSL_PWR_INFO(device, "sleep device %d\n", device->id);
/* Work through the legal state transitions */
- if ((device->requested_state == KGSL_STATE_NAP)) {
+ switch (device->requested_state) {
+ case KGSL_STATE_NAP:
if (device->pwrctrl.restore_slumber) {
- device->requested_state = KGSL_STATE_NONE;
- return 0;
- } else if (device->ftbl->isidle(device))
- goto nap;
- } else if (device->requested_state == KGSL_STATE_SLEEP) {
- if (device->state == KGSL_STATE_NAP ||
- device->ftbl->isidle(device)) {
- if (!device->pwrctrl.restore_slumber)
- goto sleep;
- else
- goto slumber;
- }
- } else if (device->requested_state == KGSL_STATE_SLUMBER) {
- if (device->state == KGSL_STATE_INIT)
- return 0;
- if (device->ftbl->isidle(device))
- goto slumber;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+ break;
+ }
+ status = _nap(device);
+ break;
+ case KGSL_STATE_SLEEP:
+ if (device->pwrctrl.restore_slumber)
+ status = _slumber(device);
else
- device->pwrctrl.restore_slumber = true;
+ status = _sleep(device);
+ break;
+ case KGSL_STATE_SLUMBER:
+ status = _slumber(device);
+ break;
+ default:
+ KGSL_PWR_INFO(device, "bad state request 0x%x\n",
+ device->requested_state);
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+ status = -EINVAL;
+ break;
}
-
- device->requested_state = KGSL_STATE_NONE;
- return -EBUSY;
-
-
-slumber:
- _slumber(device);
-
-sleep:
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
- kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
- if (pwr->pwrlevels[0].gpu_freq > 0)
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->num_pwrlevels - 1].
- gpu_freq);
- kgsl_pwrctrl_busy_time(device, false);
- pwr->busy.start.tv_sec = 0;
- device->pwrctrl.time = 0;
-
- kgsl_pwrscale_sleep(device);
- goto clk_off;
-
-nap:
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-clk_off:
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
-
- device->state = device->requested_state;
- device->requested_state = KGSL_STATE_NONE;
- if (device->idle_wakelock.name)
- wake_unlock(&device->idle_wakelock);
- KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n",
- device->state, device->id);
-
- return 0;
-}
-EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
-
-static int
-_wake_from_slumber(struct kgsl_device *device)
-{
- int status = -EINVAL;
- if (!device)
- return -EINVAL;
-
- KGSL_PWR_WARN(device, "wake from slumber start\n");
-
- device->requested_state = KGSL_STATE_ACTIVE;
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
- status = device->ftbl->start(device, 0);
- device->requested_state = KGSL_STATE_NONE;
-
- KGSL_PWR_WARN(device, "Done waking from slumber\n");
return status;
}
+EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
/******************************************************************/
/* Caller must hold the device mutex. */
void kgsl_pwrctrl_wake(struct kgsl_device *device)
{
- if (device->state & (KGSL_STATE_SUSPEND | KGSL_STATE_INIT))
- return;
-
- if (device->state == KGSL_STATE_SLUMBER)
- _wake_from_slumber(device);
-
- if (device->state != KGSL_STATE_NAP) {
+ int status;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
+ switch (device->state) {
+ case KGSL_STATE_SLUMBER:
+ status = device->ftbl->start(device, 0);
+ if (status) {
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+ KGSL_DRV_ERR(device, "start failed %d\n", status);
+ break;
+ }
+ /* fall through */
+ case KGSL_STATE_SLEEP:
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
kgsl_pwrscale_wake(device);
- }
-
- /* Turn on the core clocks */
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
-
- /* Enable state before turning on irq */
- device->state = KGSL_STATE_ACTIVE;
- KGSL_PWR_WARN(device, "state -> ACTIVE, device %d\n", device->id);
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
-
- /* Re-enable HW access */
- mod_timer(&device->idle_timer,
+ /* fall through */
+ case KGSL_STATE_NAP:
+ /* Turn on the core clocks */
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+ /* Enable state before turning on irq */
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+ /* Re-enable HW access */
+ mod_timer(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
- if (device->idle_wakelock.name)
- wake_lock(&device->idle_wakelock);
-
- KGSL_PWR_INFO(device, "wake return for device %d\n", device->id);
+ if (device->idle_wakelock.name)
+ wake_lock(&device->idle_wakelock);
+ case KGSL_STATE_ACTIVE:
+ break;
+ default:
+ KGSL_PWR_WARN(device, "unhandled state %s\n",
+ kgsl_pwrstate_to_str(device->state));
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+ break;
+ }
}
EXPORT_SYMBOL(kgsl_pwrctrl_wake);
@@ -832,3 +850,48 @@
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
}
EXPORT_SYMBOL(kgsl_pwrctrl_disable);
+
+void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state)
+{
+ trace_kgsl_pwr_set_state(device, state);
+ device->state = state;
+ device->requested_state = KGSL_STATE_NONE;
+}
+EXPORT_SYMBOL(kgsl_pwrctrl_set_state);
+
+void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state)
+{
+ if (state != KGSL_STATE_NONE && state != device->requested_state)
+ trace_kgsl_pwr_request_state(device, state);
+ device->requested_state = state;
+}
+EXPORT_SYMBOL(kgsl_pwrctrl_request_state);
+
+const char *kgsl_pwrstate_to_str(unsigned int state)
+{
+ switch (state) {
+ case KGSL_STATE_NONE:
+ return "NONE";
+ case KGSL_STATE_INIT:
+ return "INIT";
+ case KGSL_STATE_ACTIVE:
+ return "ACTIVE";
+ case KGSL_STATE_NAP:
+ return "NAP";
+ case KGSL_STATE_SLEEP:
+ return "SLEEP";
+ case KGSL_STATE_SUSPEND:
+ return "SUSPEND";
+ case KGSL_STATE_HUNG:
+ return "HUNG";
+ case KGSL_STATE_DUMP_AND_RECOVER:
+ return "DNR";
+ case KGSL_STATE_SLUMBER:
+ return "SLUMBER";
+ default:
+ break;
+ }
+ return "UNKNOWN";
+}
+EXPORT_SYMBOL(kgsl_pwrstate_to_str);
+
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 8b33fcd..8ec41be 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -77,4 +77,6 @@
return (clk != NULL) ? clk_get_rate(clk) : 0;
}
+void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state);
+void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state);
#endif /* __KGSL_PWRCTRL_H */
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index f3e84e4..931ef48 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
#include <mach/socinfo.h>
#include <mach/scm.h>
@@ -29,6 +30,7 @@
unsigned int no_switch_cnt;
unsigned int skip_cnt;
};
+spinlock_t tz_lock;
#define SWITCH_OFF 200
#define SWITCH_OFF_RESET_TH 40
@@ -38,13 +40,17 @@
#ifdef CONFIG_MSM_SCM
/* Trap into the TrustZone, and call funcs there. */
-static int __secure_tz_entry(u32 cmd, u32 val)
+static int __secure_tz_entry(u32 cmd, u32 val, u32 id)
{
+ int ret;
+ spin_lock(&tz_lock);
__iowmb();
- return scm_call_atomic1(SCM_SVC_IO, cmd, val);
+ ret = scm_call_atomic2(SCM_SVC_IO, cmd, val, id);
+ spin_unlock(&tz_lock);
+ return ret;
}
#else
-static int __secure_tz_entry(u32 cmd, u32 val)
+static int __secure_tz_entry(u32 cmd, u32 val, u32 id)
{
return 0;
}
@@ -107,7 +113,8 @@
{
struct tz_priv *priv = pwrscale->priv;
if (device->state != KGSL_STATE_NAP &&
- priv->governor == TZ_GOVERNOR_ONDEMAND)
+ priv->governor == TZ_GOVERNOR_ONDEMAND &&
+ device->pwrctrl.restore_slumber == 0)
kgsl_pwrctrl_pwrlevel_change(device,
device->pwrctrl.thermal_pwrlevel);
}
@@ -117,7 +124,7 @@
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct tz_priv *priv = pwrscale->priv;
struct kgsl_power_stats stats;
- int val;
+ int val, idle;
/* In "performance" mode the clock speed always stays
the same */
@@ -145,19 +152,26 @@
priv->no_switch_cnt = 0;
}
- val = __secure_tz_entry(TZ_UPDATE_ID,
- stats.total_time - stats.busy_time);
+ idle = stats.total_time - stats.busy_time;
+ idle = (idle > 0) ? idle : 0;
+ val = __secure_tz_entry(TZ_UPDATE_ID, idle, device->id);
if (val)
kgsl_pwrctrl_pwrlevel_change(device,
pwr->active_pwrlevel + val);
}
+static void tz_busy(struct kgsl_device *device,
+ struct kgsl_pwrscale *pwrscale)
+{
+ device->on_time = ktime_to_us(ktime_get());
+}
+
static void tz_sleep(struct kgsl_device *device,
struct kgsl_pwrscale *pwrscale)
{
struct tz_priv *priv = pwrscale->priv;
- __secure_tz_entry(TZ_RESET_ID, 0);
+ __secure_tz_entry(TZ_RESET_ID, 0, device->id);
priv->no_switch_cnt = 0;
}
@@ -174,6 +188,7 @@
return -ENOMEM;
priv->governor = TZ_GOVERNOR_ONDEMAND;
+ spin_lock_init(&tz_lock);
kgsl_pwrscale_policy_add_files(device, pwrscale, &tz_attr_group);
return 0;
@@ -189,6 +204,7 @@
struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz = {
.name = "trustzone",
.init = tz_init,
+ .busy = tz_busy,
.idle = tz_idle,
.sleep = tz_sleep,
.wake = tz_wake,
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 7c14ac1..86a9adc 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -155,6 +155,108 @@
__entry->result
)
);
+
+DECLARE_EVENT_CLASS(kgsl_pwr_template,
+ TP_PROTO(struct kgsl_device *device, int on),
+
+ TP_ARGS(device, on),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(int, on)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->on = on;
+ ),
+
+ TP_printk(
+ "d_name=%s %s",
+ __get_str(device_name),
+ __entry->on ? "on" : "off"
+ )
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_clk,
+ TP_PROTO(struct kgsl_device *device, int on),
+ TP_ARGS(device, on)
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_irq,
+ TP_PROTO(struct kgsl_device *device, int on),
+ TP_ARGS(device, on)
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_bus,
+ TP_PROTO(struct kgsl_device *device, int on),
+ TP_ARGS(device, on)
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_rail,
+ TP_PROTO(struct kgsl_device *device, int on),
+ TP_ARGS(device, on)
+);
+
+TRACE_EVENT(kgsl_pwrlevel,
+
+ TP_PROTO(struct kgsl_device *device, unsigned int pwrlevel,
+ unsigned int freq),
+
+ TP_ARGS(device, pwrlevel, freq),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, pwrlevel)
+ __field(unsigned int, freq)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->pwrlevel = pwrlevel;
+ __entry->freq = freq;
+ ),
+
+ TP_printk(
+ "d_name=%s pwrlevel=%d freq=%d",
+ __get_str(device_name),
+ __entry->pwrlevel,
+ __entry->freq
+ )
+);
+
+DECLARE_EVENT_CLASS(kgsl_pwrstate_template,
+ TP_PROTO(struct kgsl_device *device, unsigned int state),
+
+ TP_ARGS(device, state),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, state)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->state = state;
+ ),
+
+ TP_printk(
+ "d_name=%s %s",
+ __get_str(device_name),
+ kgsl_pwrstate_to_str(__entry->state)
+ )
+);
+
+DEFINE_EVENT(kgsl_pwrstate_template, kgsl_pwr_set_state,
+ TP_PROTO(struct kgsl_device *device, unsigned int state),
+ TP_ARGS(device, state)
+);
+
+DEFINE_EVENT(kgsl_pwrstate_template, kgsl_pwr_request_state,
+ TP_PROTO(struct kgsl_device *device, unsigned int state),
+ TP_ARGS(device, state)
+);
+
#endif /* _KGSL_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index cf74e64..de7d1be 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -248,7 +248,7 @@
if ((device->pwrctrl.nap_allowed == true) &&
(device->requested_state == KGSL_STATE_NONE)) {
- device->requested_state = KGSL_STATE_NAP;
+ kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
queue_work(device->work_queue, &device->idle_check_ws);
}
mod_timer(&device->idle_timer,
@@ -460,6 +460,7 @@
z180_dev->ringbuffer.prevctx = context->id;
addcmd(&z180_dev->ringbuffer, index, cmd + ofs, cnt);
+ kgsl_pwrscale_busy(device);
/* Make sure the next ringbuffer entry has a marker */
addmarker(&z180_dev->ringbuffer, nextindex);
@@ -523,6 +524,7 @@
goto error_close_ringbuffer;
kgsl_pwrscale_init(device);
+ kgsl_pwrscale_attach_policy(device, Z180_DEFAULT_PWRSCALE_POLICY);
return status;
@@ -551,9 +553,7 @@
{
int status = 0;
- device->state = KGSL_STATE_INIT;
- device->requested_state = KGSL_STATE_NONE;
- KGSL_PWR_WARN(device, "state -> INIT, device %d\n", device->id);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
kgsl_pwrctrl_enable(device);
@@ -834,8 +834,7 @@
status = 0;
else if (timeout == 0) {
status = -ETIMEDOUT;
- device->state = KGSL_STATE_HUNG;
- KGSL_PWR_WARN(device, "state -> HUNG, device %d\n", device->id);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
} else
status = timeout;
@@ -861,17 +860,17 @@
struct kgsl_power_stats *stats)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ s64 tmp = ktime_to_us(ktime_get());
if (pwr->time == 0) {
- pwr->time = ktime_to_us(ktime_get());
+ pwr->time = tmp;
stats->total_time = 0;
stats->busy_time = 0;
} else {
- s64 tmp;
- tmp = ktime_to_us(ktime_get());
stats->total_time = tmp - pwr->time;
- stats->busy_time = tmp - pwr->time;
pwr->time = tmp;
+ stats->busy_time = tmp - device->on_time;
+ device->on_time = tmp;
}
}
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index 28b1cc6..e5c5ef3 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -19,6 +19,8 @@
#define DEVICE_2D0_NAME "kgsl-2d0"
#define DEVICE_2D1_NAME "kgsl-2d1"
+#define Z180_DEFAULT_PWRSCALE_POLICY NULL
+
struct z180_ringbuffer {
unsigned int prevctx;
struct kgsl_memdesc cmdbufdesc;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 3dbbf15..2d69256 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -29,6 +29,7 @@
#include <linux/timer.h>
#include <linux/slab.h>
#include <mach/board.h>
+#include <mach/gpiomux.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
@@ -110,6 +111,7 @@
enum {
I2C_STATUS_WR_BUFFER_FULL = 1U << 0,
I2C_STATUS_BUS_ACTIVE = 1U << 8,
+ I2C_STATUS_BUS_MASTER = 1U << 9,
I2C_STATUS_ERROR_MASK = 0x38000FC,
QUP_I2C_NACK_FLAG = 1U << 3,
QUP_IN_NOT_EMPTY = 1U << 5,
@@ -126,6 +128,12 @@
static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
+static struct gpiomux_setting recovery_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
struct qup_i2c_dev {
struct device *dev;
void __iomem *base; /* virtual */
@@ -639,6 +647,83 @@
return ret;
}
+
+static void qup_i2c_recover_bus_busy(struct qup_i2c_dev *dev)
+{
+ int i;
+ int gpio_clk;
+ int gpio_dat;
+ bool gpio_clk_status = false;
+ uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+ struct gpiomux_setting old_gpio_setting;
+
+ if (dev->pdata->msm_i2c_config_gpio)
+ return;
+
+ if (!(status & (I2C_STATUS_BUS_ACTIVE)) ||
+ (status & (I2C_STATUS_BUS_MASTER)))
+ return;
+
+ gpio_clk = dev->i2c_gpios[0];
+ gpio_dat = dev->i2c_gpios[1];
+
+ if ((gpio_clk == -1) && (gpio_dat == -1)) {
+ dev_err(dev->dev, "Recovery failed due to undefined GPIO's\n");
+ return;
+ }
+
+ disable_irq(dev->err_irq);
+ for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+ if (msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
+ &recovery_config, &old_gpio_setting)) {
+ dev_err(dev->dev, "GPIO pins have no active setting\n");
+ goto recovery_end;
+ }
+ }
+
+ dev_warn(dev->dev, "i2c_scl: %d, i2c_sda: %d\n",
+ gpio_get_value(gpio_clk), gpio_get_value(gpio_dat));
+
+ for (i = 0; i < 9; i++) {
+ if (gpio_get_value(gpio_dat) && gpio_clk_status)
+ break;
+ gpio_direction_output(gpio_clk, 0);
+ udelay(5);
+ gpio_direction_output(gpio_dat, 0);
+ udelay(5);
+ gpio_direction_input(gpio_clk);
+ udelay(5);
+ if (!gpio_get_value(gpio_clk))
+ udelay(20);
+ if (!gpio_get_value(gpio_clk))
+ usleep_range(10000, 10000);
+ gpio_clk_status = gpio_get_value(gpio_clk);
+ gpio_direction_input(gpio_dat);
+ udelay(5);
+ }
+
+ /* Configure ALT funciton to QUP I2C*/
+ for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+ msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
+ &old_gpio_setting, NULL);
+ }
+
+ udelay(10);
+
+ status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+ if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+ dev_info(dev->dev, "Bus busy cleared after %d clock cycles, "
+ "status %x\n",
+ i, status);
+ goto recovery_end;
+ }
+
+ dev_warn(dev->dev, "Bus still busy, status %x\n", status);
+
+recovery_end:
+ enable_irq(dev->err_irq);
+}
+
static int
qup_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
@@ -837,7 +922,8 @@
idx, rem, num, dev->mode);
qup_print_status(dev);
- timeout = wait_for_completion_timeout(&complete, HZ);
+ timeout = wait_for_completion_timeout(&complete,
+ msecs_to_jiffies(dev->out_fifo_sz));
if (!timeout) {
uint32_t istatus = readl_relaxed(dev->base +
QUP_I2C_STATUS);
@@ -846,7 +932,24 @@
uint32_t op_flgs = readl_relaxed(dev->base +
QUP_OPERATIONAL);
- dev_err(dev->dev, "Transaction timed out\n");
+ /*
+ * Dont wait for 1 sec if i2c sees the bus
+ * active and controller is not master.
+ * A slave has pulled line low. Try to recover
+ */
+ if (!(istatus & I2C_STATUS_BUS_ACTIVE) ||
+ (istatus & I2C_STATUS_BUS_MASTER)) {
+ timeout =
+ wait_for_completion_timeout(&complete,
+ HZ);
+ if (timeout)
+ goto timeout_err;
+ }
+ qup_i2c_recover_bus_busy(dev);
+ dev_err(dev->dev,
+ "Transaction timed out, SL-AD = 0x%x\n",
+ dev->msg->addr);
+
dev_err(dev->dev, "I2C Status: %x\n", istatus);
dev_err(dev->dev, "QUP Status: %x\n", qstatus);
dev_err(dev->dev, "OP Flags: %x\n", op_flgs);
@@ -858,17 +961,27 @@
ret = -ETIMEDOUT;
goto out_err;
}
+timeout_err:
if (dev->err) {
if (dev->err > 0 &&
- dev->err & QUP_I2C_NACK_FLAG)
+ dev->err & QUP_I2C_NACK_FLAG) {
dev_err(dev->dev,
"I2C slave addr:0x%x not connected\n",
dev->msg->addr);
- else if (dev->err < 0) {
+ dev->err = ENOTCONN;
+ } else if (dev->err < 0) {
dev_err(dev->dev,
"QUP data xfer error %d\n", dev->err);
ret = dev->err;
goto out_err;
+ } else if (dev->err > 0) {
+ /*
+ * ISR returns +ve error if error code
+ * is I2C related, e.g. unexpected start
+ * So you may call recover-bus-busy when
+ * this error happens
+ */
+ qup_i2c_recover_bus_busy(dev);
}
ret = -dev->err;
goto out_err;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 6db0da1..ec392c3 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -594,28 +594,6 @@
To compile this driver as a module, choose M here: the
module will be called w90p910_keypad.
-config KEYBOARD_PMIC8058
- tristate "Qualcomm PMIC8058 keypad"
- depends on PMIC8058
- default y
- help
- Say Y here if you want to enable the driver for the PMIC8058
- keypad provided as a reference design from Qualcomm. This is intended
- to support upto 18x8 matrix based keypad design.
-
- To compile this driver as a module, choose M here: the module will
- be called pmic8058-keypad.
endif
-config KEYBOARD_PMIC8058
- tristate "Qualcomm PMIC8058 keypad"
- depends on PMIC8058
- default y
- help
- Say Y here if you want to enable the driver for the PMIC8058
- keypad provided as a reference design from Qualcomm. This is intended
- to support upto 18x8 matrix based keypad design.
-
- To compile this driver as a module, choose M here: the module will
- be called pmic8058-keypad.
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index cf4c058..b22df06 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -34,7 +34,6 @@
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
-obj-$(CONFIG_KEYBOARD_PM8058) += pm8058-keypad.o
obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
diff --git a/drivers/input/keyboard/pmic8058-keypad.c b/drivers/input/keyboard/pmic8058-keypad.c
deleted file mode 100644
index 9c7588e..0000000
--- a/drivers/input/keyboard/pmic8058-keypad.c
+++ /dev/null
@@ -1,948 +0,0 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/bitops.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/input/pmic8058-keypad.h>
-
-#define PM8058_MAX_ROWS 18
-#define PM8058_MAX_COLS 8
-#define PM8058_ROW_SHIFT 3
-#define PM8058_MATRIX_MAX_SIZE (PM8058_MAX_ROWS * PM8058_MAX_COLS)
-
-#define PM8058_MIN_ROWS 5
-#define PM8058_MIN_COLS 5
-
-#define MAX_SCAN_DELAY 128
-#define MIN_SCAN_DELAY 1
-
-/* in nanoseconds */
-#define MAX_ROW_HOLD_DELAY 122000
-#define MIN_ROW_HOLD_DELAY 30500
-
-#define MAX_DEBOUNCE_B0_TIME 20
-#define MIN_DEBOUNCE_B0_TIME 5
-
-#define MAX_DEBOUNCE_A0_TIME 8
-#define MIN_DEBOUNCE_A0_TIME 1
-
-#define KEYP_CTRL 0x148
-
-#define KEYP_CTRL_EVNTS BIT(0)
-#define KEYP_CTRL_EVNTS_MASK 0x3
-
-#define KEYP_CTRL_SCAN_COLS_SHIFT 5
-#define KEYP_CTRL_SCAN_COLS_MIN 5
-#define KEYP_CTRL_SCAN_COLS_BITS 0x3
-
-#define KEYP_CTRL_SCAN_ROWS_SHIFT 2
-#define KEYP_CTRL_SCAN_ROWS_MIN 5
-#define KEYP_CTRL_SCAN_ROWS_BITS 0x7
-
-#define KEYP_CTRL_KEYP_EN BIT(7)
-
-#define KEYP_SCAN 0x149
-
-#define KEYP_SCAN_READ_STATE BIT(0)
-#define KEYP_SCAN_DBOUNCE_SHIFT 1
-#define KEYP_SCAN_PAUSE_SHIFT 3
-#define KEYP_SCAN_ROW_HOLD_SHIFT 6
-
-#define KEYP_TEST 0x14A
-
-#define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6)
-#define KEYP_TEST_CLEAR_OLD_SCAN BIT(5)
-#define KEYP_TEST_READ_RESET BIT(4)
-#define KEYP_TEST_DTEST_EN BIT(3)
-#define KEYP_TEST_ABORT_READ BIT(0)
-
-#define KEYP_TEST_DBG_SELECT_SHIFT 1
-
-/* bits of these register represent
- * '0' for key press
- * '1' for key release
- */
-#define KEYP_RECENT_DATA 0x14B
-#define KEYP_OLD_DATA 0x14C
-
-#define KEYP_CLOCK_FREQ 32768
-
-/* Internal flags */
-#define KEYF_FIX_LAST_ROW 0x01
-
-
-/* ---------------------------------------------------------------------*/
-struct pmic8058_kp {
- const struct pmic8058_keypad_data *pdata;
- struct input_dev *input;
- int key_sense_irq;
- int key_stuck_irq;
-
- unsigned short *keycodes;
-
- struct device *dev;
- u16 keystate[PM8058_MAX_ROWS];
- u16 stuckstate[PM8058_MAX_ROWS];
-
- u32 flags;
- struct pm8058_chip *pm_chip;
-
- /* protect read/write */
- struct mutex mutex;
- bool user_disabled;
- u32 disable_depth;
-
- u8 ctrl_reg;
-};
-
-static int pmic8058_kp_write_u8(struct pmic8058_kp *kp,
- u8 data, u16 reg)
-{
- int rc;
-
- rc = pm8058_write(kp->pm_chip, reg, &data, 1);
- if (rc < 0)
- dev_warn(kp->dev, "Error writing pmic8058: %X - ret %X\n",
- reg, rc);
- return rc;
-}
-
-static int pmic8058_kp_read(struct pmic8058_kp *kp,
- u8 *data, u16 reg, unsigned num_bytes)
-{
- int rc;
-
- rc = pm8058_read(kp->pm_chip, reg, data, num_bytes);
- if (rc < 0)
- dev_warn(kp->dev, "Error reading pmic8058: %X - ret %X\n",
- reg, rc);
-
- return rc;
-}
-
-static int pmic8058_kp_read_u8(struct pmic8058_kp *kp,
- u8 *data, u16 reg)
-{
- int rc;
-
- rc = pmic8058_kp_read(kp, data, reg, 1);
- if (rc < 0)
- dev_warn(kp->dev, "Error reading pmic8058: %X - ret %X\n",
- reg, rc);
- return rc;
-}
-
-static u8 pmic8058_col_state(struct pmic8058_kp *kp, u8 col)
-{
- /* all keys pressed on that particular row? */
- if (col == 0x00)
- return 1 << kp->pdata->num_cols;
- else
- return col & ((1 << kp->pdata->num_cols) - 1);
-}
-/* REVISIT: just for debugging, will be removed in final working version */
-static void __dump_kp_regs(struct pmic8058_kp *kp, char *msg)
-{
- u8 temp;
-
- dev_dbg(kp->dev, "%s\n", msg);
-
- pmic8058_kp_read_u8(kp, &temp, KEYP_CTRL);
- dev_dbg(kp->dev, "KEYP_CTRL - %X\n", temp);
- pmic8058_kp_read_u8(kp, &temp, KEYP_SCAN);
- dev_dbg(kp->dev, "KEYP_SCAN - %X\n", temp);
- pmic8058_kp_read_u8(kp, &temp, KEYP_TEST);
- dev_dbg(kp->dev, "KEYP_TEST - %X\n", temp);
-}
-
-/* H/W constraint:
- * One should read recent/old data registers equal to the
- * number of columns programmed in the keyp_control register,
- * otherwise h/w state machine may get stuck. In order to avoid this
- * situation one should check readstate bit in keypad scan
- * register to be '0' at the end of data read, to make sure
- * the keypad state machine is not in READ state.
- */
-static int pmic8058_chk_read_state(struct pmic8058_kp *kp, u16 data_reg)
-{
- u8 temp, scan_val;
- int retries = 10, rc;
-
- do {
- rc = pmic8058_kp_read_u8(kp, &scan_val, KEYP_SCAN);
- if (scan_val & 0x1)
- rc = pmic8058_kp_read_u8(kp, &temp, data_reg);
- } while ((scan_val & 0x1) && (--retries > 0));
-
- if (retries == 0)
- dev_dbg(kp->dev, "Unable to clear read state bit\n");
-
- return 0;
-}
-/*
- * Synchronous read protocol for RevB0 onwards:
- *
- * 1. Write '1' to ReadState bit in KEYP_SCAN register
- * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
- * synchronously
- * 3. Read rows in old array first if events are more than one
- * 4. Read rows in recent array
- * 5. Wait 4*32KHz clocks
- * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
- * synchronously exit read mode.
- */
-static int pmic8058_chk_sync_read(struct pmic8058_kp *kp)
-{
- int rc;
- u8 scan_val;
-
- rc = pmic8058_kp_read_u8(kp, &scan_val, KEYP_SCAN);
- scan_val |= 0x1;
- rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN);
-
- /* 2 * 32KHz clocks */
- udelay((2 * USEC_PER_SEC / KEYP_CLOCK_FREQ) + 1);
-
- return rc;
-}
-
-static int pmic8058_kp_read_data(struct pmic8058_kp *kp, u16 *state,
- u16 data_reg, int read_rows)
-{
- int rc, row;
- u8 new_data[PM8058_MAX_ROWS];
-
- rc = pmic8058_kp_read(kp, new_data, data_reg, read_rows);
-
- if (!rc) {
- if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
- pmic8058_chk_read_state(kp, data_reg);
- for (row = 0; row < kp->pdata->num_rows; row++) {
- dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
- new_data[row]);
- state[row] = pmic8058_col_state(kp, new_data[row]);
- }
- }
-
- return rc;
-}
-
-static int pmic8058_kp_read_matrix(struct pmic8058_kp *kp, u16 *new_state,
- u16 *old_state)
-{
- int rc, read_rows;
- u8 scan_val;
- static u8 rows[] = {
- 5, 6, 7, 8, 10, 10, 12, 12, 15, 15, 15, 18, 18, 18
- };
-
- if (kp->flags & KEYF_FIX_LAST_ROW &&
- (kp->pdata->num_rows != PM8058_MAX_ROWS))
- read_rows = rows[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN
- + 1];
- else
- read_rows = kp->pdata->num_rows;
-
- if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0)
- pmic8058_chk_sync_read(kp);
-
- if (old_state)
- rc = pmic8058_kp_read_data(kp, old_state, KEYP_OLD_DATA,
- read_rows);
-
- rc = pmic8058_kp_read_data(kp, new_state, KEYP_RECENT_DATA,
- read_rows);
-
- if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0) {
- /* 4 * 32KHz clocks */
- udelay((4 * USEC_PER_SEC / KEYP_CLOCK_FREQ) + 1);
-
- rc = pmic8058_kp_read(kp, &scan_val, KEYP_SCAN, 1);
- scan_val &= 0xFE;
- rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN);
- }
-
- return rc;
-}
-
-static int __pmic8058_kp_scan_matrix(struct pmic8058_kp *kp, u16 *new_state,
- u16 *old_state)
-{
- int row, col, code;
-
- for (row = 0; row < kp->pdata->num_rows; row++) {
- int bits_changed = new_state[row] ^ old_state[row];
-
- if (!bits_changed)
- continue;
-
- for (col = 0; col < kp->pdata->num_cols; col++) {
- if (!(bits_changed & (1 << col)))
- continue;
-
- dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col,
- !(new_state[row] & (1 << col)) ?
- "pressed" : "released");
-
- code = MATRIX_SCAN_CODE(row, col, PM8058_ROW_SHIFT);
- input_event(kp->input, EV_MSC, MSC_SCAN, code);
- input_report_key(kp->input,
- kp->keycodes[code],
- !(new_state[row] & (1 << col)));
-
- input_sync(kp->input);
- }
- }
-
- return 0;
-}
-
-static int pmic8058_detect_ghost_keys(struct pmic8058_kp *kp, u16 *new_state)
-{
- int row, found_first = -1;
- u16 check, row_state;
-
- check = 0;
- for (row = 0; row < kp->pdata->num_rows; row++) {
- row_state = (~new_state[row]) &
- ((1 << kp->pdata->num_cols) - 1);
-
- if (hweight16(row_state) > 1) {
- if (found_first == -1)
- found_first = row;
- if (check & row_state) {
- dev_dbg(kp->dev, "detected ghost key on row[%d]"
- "row[%d]\n", found_first, row);
- return 1;
- }
- }
- check |= row_state;
- }
- return 0;
-}
-
-static int pmic8058_kp_scan_matrix(struct pmic8058_kp *kp, unsigned int events)
-{
- u16 new_state[PM8058_MAX_ROWS];
- u16 old_state[PM8058_MAX_ROWS];
- int rc;
-
- switch (events) {
- case 0x1:
- rc = pmic8058_kp_read_matrix(kp, new_state, NULL);
- if (pmic8058_detect_ghost_keys(kp, new_state))
- return -EINVAL;
- __pmic8058_kp_scan_matrix(kp, new_state, kp->keystate);
- memcpy(kp->keystate, new_state, sizeof(new_state));
- break;
- case 0x3: /* two events - eventcounter is gray-coded */
- rc = pmic8058_kp_read_matrix(kp, new_state, old_state);
- __pmic8058_kp_scan_matrix(kp, old_state, kp->keystate);
- __pmic8058_kp_scan_matrix(kp, new_state, old_state);
- memcpy(kp->keystate, new_state, sizeof(new_state));
- break;
- case 0x2:
- dev_dbg(kp->dev, "Some key events are missed\n");
- rc = pmic8058_kp_read_matrix(kp, new_state, old_state);
- __pmic8058_kp_scan_matrix(kp, old_state, kp->keystate);
- __pmic8058_kp_scan_matrix(kp, new_state, old_state);
- memcpy(kp->keystate, new_state, sizeof(new_state));
- break;
- default:
- rc = -1;
- }
- return rc;
-}
-
-static inline int pmic8058_kp_disabled(struct pmic8058_kp *kp)
-{
- return kp->disable_depth != 0;
-}
-
-static void pmic8058_kp_enable(struct pmic8058_kp *kp)
-{
- if (!pmic8058_kp_disabled(kp))
- return;
-
- if (--kp->disable_depth == 0) {
-
- kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
- pmic8058_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
-
- enable_irq(kp->key_sense_irq);
- enable_irq(kp->key_stuck_irq);
- }
-}
-
-static void pmic8058_kp_disable(struct pmic8058_kp *kp)
-{
- if (kp->disable_depth++ == 0) {
- disable_irq(kp->key_sense_irq);
- disable_irq(kp->key_stuck_irq);
-
- kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
- pmic8058_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
- }
-}
-
-static ssize_t pmic8058_kp_disable_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct pmic8058_kp *kp = dev_get_drvdata(dev);
-
- return sprintf(buf, "%u\n", pmic8058_kp_disabled(kp));
-}
-
-static ssize_t pmic8058_kp_disable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct pmic8058_kp *kp = dev_get_drvdata(dev);
- long i = 0;
- int rc;
-
- rc = strict_strtoul(buf, 10, &i);
- if (rc)
- return -EINVAL;
-
- i = !!i;
-
- mutex_lock(&kp->mutex);
- if (i == kp->user_disabled) {
- mutex_unlock(&kp->mutex);
- return count;
- }
-
- kp->user_disabled = i;
-
- if (i)
- pmic8058_kp_disable(kp);
- else
- pmic8058_kp_enable(kp);
- mutex_unlock(&kp->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(disable_kp, 0664, pmic8058_kp_disable_show,
- pmic8058_kp_disable_store);
-
-
-/*
- * NOTE: We are reading recent and old data registers blindly
- * whenever key-stuck interrupt happens, because events counter doesn't
- * get updated when this interrupt happens due to key stuck doesn't get
- * considered as key state change.
- *
- * We are not using old data register contents after they are being read
- * because it might report the key which was pressed before the key being stuck
- * as stuck key because it's pressed status is stored in the old data
- * register.
- */
-static irqreturn_t pmic8058_kp_stuck_irq(int irq, void *data)
-{
- u16 new_state[PM8058_MAX_ROWS];
- u16 old_state[PM8058_MAX_ROWS];
- int rc;
- struct pmic8058_kp *kp = data;
-
- rc = pmic8058_kp_read_matrix(kp, new_state, old_state);
- __pmic8058_kp_scan_matrix(kp, new_state, kp->stuckstate);
-
- return IRQ_HANDLED;
-}
-
-/*
- * NOTE: Any row multiple interrupt issue - PMIC4 Rev A0
- *
- * If the S/W responds to the key-event interrupt too early and reads the
- * recent data, the keypad FSM will mistakenly go to the IDLE state, instead
- * of the scan pause state as it is supposed too. Since the key is still
- * pressed, the keypad scanner will go through the debounce, scan, and generate
- * another key event interrupt. The workaround for this issue is to add delay
- * of 1ms between servicing the key event interrupt and reading the recent data.
- */
-static irqreturn_t pmic8058_kp_irq(int irq, void *data)
-{
- struct pmic8058_kp *kp = data;
- u8 ctrl_val, events;
- int rc;
-
- if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
- mdelay(1);
-
- dev_dbg(kp->dev, "key sense irq\n");
- __dump_kp_regs(kp, "pmic8058_kp_irq");
-
- rc = pmic8058_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
- events = ctrl_val & KEYP_CTRL_EVNTS_MASK;
-
- rc = pmic8058_kp_scan_matrix(kp, events);
-
- return IRQ_HANDLED;
-}
-/*
- * NOTE: Last row multi-interrupt issue
- *
- * In PMIC Rev A0, if any key in the last row of the keypad matrix
- * is pressed and held, the H/W keeps on generating interrupts.
- * Software work-arounds it by programming the keypad controller next level
- * up rows (for 8x12 matrix it is 15 rows) so the keypad controller
- * thinks of more-rows than the actual ones, so the actual last-row
- * in the matrix won't generate multiple interrupts.
- */
-static int pmic8058_kpd_init(struct pmic8058_kp *kp)
-{
- int bits, rc, cycles;
- u8 scan_val = 0, ctrl_val = 0;
- static u8 row_bits[] = {
- 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
- };
-
- /* Find column bits */
- if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
- bits = 0;
- else
- bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
- ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
- KEYP_CTRL_SCAN_COLS_SHIFT;
-
- /* Find row bits */
- if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
- bits = 0;
- else if (kp->pdata->num_rows > PM8058_MAX_ROWS)
- bits = KEYP_CTRL_SCAN_ROWS_BITS;
- else
- bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
-
- /* Use max rows to fix last row problem if actual rows are less */
- if (kp->flags & KEYF_FIX_LAST_ROW &&
- (kp->pdata->num_rows != PM8058_MAX_ROWS))
- bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN
- + 1];
-
- ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
-
- rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
-
- if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
- bits = fls(kp->pdata->debounce_ms[0]) - 1;
- else
- bits = (kp->pdata->debounce_ms[1] / 5) - 1;
-
- scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
-
- bits = fls(kp->pdata->scan_delay_ms) - 1;
- scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
-
- /* Row hold time is a multiple of 32KHz cycles. */
- cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
-
- scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
-
- rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN);
-
- return rc;
-}
-
-static int pm8058_kp_config_drv(int gpio_start, int num_gpios)
-{
- int rc;
- struct pm8058_gpio kypd_drv = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN,
- .output_value = 0,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = 2,
- .out_strength = PM_GPIO_STRENGTH_LOW,
- .function = PM_GPIO_FUNC_1,
- .inv_int_pol = 1,
- };
-
- if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS)
- return -EINVAL;
-
- while (num_gpios--) {
- rc = pm8058_gpio_config(gpio_start++, &kypd_drv);
- if (rc) {
- pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n",
- __func__, rc);
- return rc;
- }
- }
-
- return 0;
-}
-
-static int pm8058_kp_config_sns(int gpio_start, int num_gpios)
-{
- int rc;
- struct pm8058_gpio kypd_sns = {
- .direction = PM_GPIO_DIR_IN,
- .pull = PM_GPIO_PULL_UP_31P5,
- .vin_sel = 2,
- .out_strength = PM_GPIO_STRENGTH_NO,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 1,
- };
-
- if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS)
- return -EINVAL;
-
- while (num_gpios--) {
- rc = pm8058_gpio_config(gpio_start++, &kypd_sns);
- if (rc) {
- pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n",
- __func__, rc);
- return rc;
- }
- }
-
- return 0;
-}
-
-/*
- * keypad controller should be initialized in the following sequence
- * only, otherwise it might get into FSM stuck state.
- *
- * - Initialize keypad control parameters, like no. of rows, columns,
- * timing values etc.,
- * - configure rows and column gpios pull up/down.
- * - set irq edge type.
- * - enable the keypad controller.
- */
-static int __devinit pmic8058_kp_probe(struct platform_device *pdev)
-{
- struct pmic8058_keypad_data *pdata = pdev->dev.platform_data;
- const struct matrix_keymap_data *keymap_data;
- struct pmic8058_kp *kp;
- int rc;
- unsigned short *keycodes;
- u8 ctrl_val;
- struct pm8058_chip *pm_chip;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- dev_err(&pdev->dev, "no parent data passed in\n");
- return -EFAULT;
- }
-
- if (!pdata || !pdata->num_cols || !pdata->num_rows ||
- pdata->num_cols > PM8058_MAX_COLS ||
- pdata->num_rows > PM8058_MAX_ROWS ||
- pdata->num_cols < PM8058_MIN_COLS ||
- pdata->num_rows < PM8058_MIN_ROWS) {
- dev_err(&pdev->dev, "invalid platform data\n");
- return -EINVAL;
- }
-
- if (pdata->rows_gpio_start < 0 || pdata->cols_gpio_start < 0) {
- dev_err(&pdev->dev, "invalid gpio_start platform data\n");
- return -EINVAL;
- }
-
- if (!pdata->scan_delay_ms || pdata->scan_delay_ms > MAX_SCAN_DELAY
- || pdata->scan_delay_ms < MIN_SCAN_DELAY ||
- !is_power_of_2(pdata->scan_delay_ms)) {
- dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
- return -EINVAL;
- }
-
- if (!pdata->row_hold_ns || pdata->row_hold_ns > MAX_ROW_HOLD_DELAY
- || pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
- ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
- dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
- return -EINVAL;
- }
-
- if (pm8058_rev(pm_chip) == PM_8058_REV_1p0) {
- if (!pdata->debounce_ms
- || !is_power_of_2(pdata->debounce_ms[0])
- || pdata->debounce_ms[0] > MAX_DEBOUNCE_A0_TIME
- || pdata->debounce_ms[0] < MIN_DEBOUNCE_A0_TIME) {
- dev_err(&pdev->dev, "invalid debounce time supplied\n");
- return -EINVAL;
- }
- } else {
- if (!pdata->debounce_ms
- || ((pdata->debounce_ms[1] % 5) != 0)
- || pdata->debounce_ms[1] > MAX_DEBOUNCE_B0_TIME
- || pdata->debounce_ms[1] < MIN_DEBOUNCE_B0_TIME) {
- dev_err(&pdev->dev, "invalid debounce time supplied\n");
- return -EINVAL;
- }
- }
-
- keymap_data = pdata->keymap_data;
- if (!keymap_data) {
- dev_err(&pdev->dev, "no keymap data supplied\n");
- return -EINVAL;
- }
-
- kp = kzalloc(sizeof(*kp), GFP_KERNEL);
- if (!kp)
- return -ENOMEM;
-
- keycodes = kzalloc(PM8058_MATRIX_MAX_SIZE * sizeof(*keycodes),
- GFP_KERNEL);
- if (!keycodes) {
- rc = -ENOMEM;
- goto err_alloc_mem;
- }
-
- platform_set_drvdata(pdev, kp);
- mutex_init(&kp->mutex);
-
- kp->pdata = pdata;
- kp->dev = &pdev->dev;
- kp->keycodes = keycodes;
- kp->pm_chip = pm_chip;
-
- if (pm8058_rev(pm_chip) == PM_8058_REV_1p0)
- kp->flags |= KEYF_FIX_LAST_ROW;
-
- kp->input = input_allocate_device();
- if (!kp->input) {
- dev_err(&pdev->dev, "unable to allocate input device\n");
- rc = -ENOMEM;
- goto err_alloc_device;
- }
-
- /* Enable runtime PM ops, start in ACTIVE mode */
- rc = pm_runtime_set_active(&pdev->dev);
- if (rc < 0)
- dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
- pm_runtime_enable(&pdev->dev);
-
- kp->key_sense_irq = platform_get_irq(pdev, 0);
- if (kp->key_sense_irq < 0) {
- dev_err(&pdev->dev, "unable to get keypad sense irq\n");
- rc = -ENXIO;
- goto err_get_irq;
- }
-
- kp->key_stuck_irq = platform_get_irq(pdev, 1);
- if (kp->key_stuck_irq < 0) {
- dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
- rc = -ENXIO;
- goto err_get_irq;
- }
-
- if (pdata->input_name)
- kp->input->name = pdata->input_name;
- else
- kp->input->name = "PMIC8058 keypad";
-
- if (pdata->input_phys_device)
- kp->input->phys = pdata->input_phys_device;
- else
- kp->input->phys = "pmic8058_keypad/input0";
-
- kp->input->dev.parent = &pdev->dev;
-
- kp->input->id.bustype = BUS_HOST;
- kp->input->id.version = 0x0001;
- kp->input->id.product = 0x0001;
- kp->input->id.vendor = 0x0001;
-
- kp->input->evbit[0] = BIT_MASK(EV_KEY);
-
- if (pdata->rep)
- __set_bit(EV_REP, kp->input->evbit);
-
- kp->input->keycode = keycodes;
- kp->input->keycodemax = PM8058_MATRIX_MAX_SIZE;
- kp->input->keycodesize = sizeof(*keycodes);
-
- matrix_keypad_build_keymap(keymap_data, PM8058_ROW_SHIFT,
- kp->input->keycode, kp->input->keybit);
-
- input_set_capability(kp->input, EV_MSC, MSC_SCAN);
- input_set_drvdata(kp->input, kp);
-
- rc = input_register_device(kp->input);
- if (rc < 0) {
- dev_err(&pdev->dev, "unable to register keypad input device\n");
- goto err_get_irq;
- }
-
- /* initialize keypad state */
- memset(kp->keystate, 0xff, sizeof(kp->keystate));
- memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
-
- rc = pmic8058_kpd_init(kp);
- if (rc < 0) {
- dev_err(&pdev->dev, "unable to initialize keypad controller\n");
- goto err_kpd_init;
- }
-
- rc = pm8058_kp_config_sns(pdata->cols_gpio_start,
- pdata->num_cols);
- if (rc < 0) {
- dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
- goto err_gpio_config;
- }
-
- rc = pm8058_kp_config_drv(pdata->rows_gpio_start,
- pdata->num_rows);
- if (rc < 0) {
- dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
- goto err_gpio_config;
- }
-
- rc = request_threaded_irq(kp->key_sense_irq, NULL, pmic8058_kp_irq,
- IRQF_TRIGGER_RISING, "pmic-keypad", kp);
- if (rc < 0) {
- dev_err(&pdev->dev, "failed to request keypad sense irq\n");
- goto err_req_sense_irq;
- }
-
- rc = request_threaded_irq(kp->key_stuck_irq, NULL,
- pmic8058_kp_stuck_irq, IRQF_TRIGGER_RISING,
- "pmic-keypad-stuck", kp);
- if (rc < 0) {
- dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
- goto err_req_stuck_irq;
- }
-
- rc = pmic8058_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
- ctrl_val |= KEYP_CTRL_KEYP_EN;
- rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
-
- kp->ctrl_reg = ctrl_val;
-
- __dump_kp_regs(kp, "probe");
-
- rc = device_create_file(&pdev->dev, &dev_attr_disable_kp);
- if (rc < 0)
- goto err_create_file;
-
- device_init_wakeup(&pdev->dev, pdata->wakeup);
-
- return 0;
-
-err_create_file:
- free_irq(kp->key_stuck_irq, NULL);
-err_req_stuck_irq:
- free_irq(kp->key_sense_irq, NULL);
-err_req_sense_irq:
-err_gpio_config:
-err_kpd_init:
- input_unregister_device(kp->input);
- kp->input = NULL;
-err_get_irq:
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- input_free_device(kp->input);
-err_alloc_device:
- kfree(keycodes);
-err_alloc_mem:
- kfree(kp);
- return rc;
-}
-
-static int __devexit pmic8058_kp_remove(struct platform_device *pdev)
-{
- struct pmic8058_kp *kp = platform_get_drvdata(pdev);
-
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- device_remove_file(&pdev->dev, &dev_attr_disable_kp);
- device_init_wakeup(&pdev->dev, 0);
- free_irq(kp->key_stuck_irq, NULL);
- free_irq(kp->key_sense_irq, NULL);
- input_unregister_device(kp->input);
- platform_set_drvdata(pdev, NULL);
- kfree(kp->input->keycode);
- kfree(kp);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_kp_suspend(struct device *dev)
-{
- struct pmic8058_kp *kp = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev) && !pmic8058_kp_disabled(kp)) {
- enable_irq_wake(kp->key_sense_irq);
- } else {
- mutex_lock(&kp->mutex);
- pmic8058_kp_disable(kp);
- mutex_unlock(&kp->mutex);
- }
-
- return 0;
-}
-
-static int pmic8058_kp_resume(struct device *dev)
-{
- struct pmic8058_kp *kp = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev) && !pmic8058_kp_disabled(kp)) {
- disable_irq_wake(kp->key_sense_irq);
- } else {
- mutex_lock(&kp->mutex);
- pmic8058_kp_enable(kp);
- mutex_unlock(&kp->mutex);
- }
-
- return 0;
-}
-
-static struct dev_pm_ops pm8058_kp_pm_ops = {
- .suspend = pmic8058_kp_suspend,
- .resume = pmic8058_kp_resume,
-};
-#endif
-
-static struct platform_driver pmic8058_kp_driver = {
- .probe = pmic8058_kp_probe,
- .remove = __devexit_p(pmic8058_kp_remove),
- .driver = {
- .name = "pm8058-keypad",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &pm8058_kp_pm_ops,
-#endif
- },
-};
-
-static int __init pmic8058_kp_init(void)
-{
- return platform_driver_register(&pmic8058_kp_driver);
-}
-module_init(pmic8058_kp_init);
-
-static void __exit pmic8058_kp_exit(void)
-{
- platform_driver_unregister(&pmic8058_kp_driver);
-}
-module_exit(pmic8058_kp_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 keypad driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058_keypad");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 9acebc0..d279a63 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -517,16 +517,6 @@
To compile this driver as a module, choose M here: the
module will be called xen-kbdfront.
-config PMIC8058_PWRKEY
- tristate "PMIC8058 power key support"
- default n
- depends on PMIC8058
- help
- Say Y here if you want support for the PMIC8058 power key.
-
- To compile this driver as a module, choose M here: the
- module will be called pmic8058-pwrkey.
-
config PMIC8058_OTHC
tristate "Qualcomm PMIC8058 OTHC support"
default n
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 770eb96..c5c4639 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -36,7 +36,6 @@
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
-obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
@@ -49,7 +48,6 @@
obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
-obj-$(CONFIG_PMIC8058_PWRKEY) += pmic8058-pwrkey.o
obj-$(CONFIG_PMIC8058_OTHC) += pmic8058-othc.o
obj-$(CONFIG_INPUT_PMIC8058_VIBRA_MEMLESS) += pmic8058-vib-memless.o
obj-$(CONFIG_BOSCH_BMA150) += bma150.o
diff --git a/drivers/input/misc/pmic8058-pwrkey.c b/drivers/input/misc/pmic8058-pwrkey.c
deleted file mode 100644
index a981013..0000000
--- a/drivers/input/misc/pmic8058-pwrkey.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pmic8058-pwrkey.h>
-#include <linux/log2.h>
-#include <linux/spinlock.h>
-#include <linux/hrtimer.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-#define PON_CNTL_1 0x1C
-#define PON_CNTL_PULL_UP BIT(7)
-#define PON_CNTL_TRIG_DELAY_MASK (0x7)
-
-struct pmic8058_pwrkey {
- struct input_dev *pwr;
- int key_press_irq;
- int key_release_irq;
- struct pm8058_chip *pm_chip;
- struct hrtimer timer;
- bool key_pressed;
- bool pressed_first;
- struct pmic8058_pwrkey_pdata *pdata;
- spinlock_t lock;
-};
-
-static enum hrtimer_restart pmic8058_pwrkey_timer(struct hrtimer *timer)
-{
- unsigned long flags;
- struct pmic8058_pwrkey *pwrkey = container_of(timer,
- struct pmic8058_pwrkey, timer);
-
- spin_lock_irqsave(&pwrkey->lock, flags);
- pwrkey->key_pressed = true;
-
- input_report_key(pwrkey->pwr, KEY_POWER, 1);
- input_sync(pwrkey->pwr);
- spin_unlock_irqrestore(&pwrkey->lock, flags);
-
- return HRTIMER_NORESTART;
-}
-
-static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
-{
- struct pmic8058_pwrkey *pwrkey = _pwrkey;
- struct pmic8058_pwrkey_pdata *pdata = pwrkey->pdata;
- unsigned long flags;
-
- spin_lock_irqsave(&pwrkey->lock, flags);
- if (pwrkey->pressed_first) {
- /*
- * If pressed_first flag is set already then release interrupt
- * has occured first. Events are handled in the release IRQ so
- * return.
- */
- pwrkey->pressed_first = false;
- spin_unlock_irqrestore(&pwrkey->lock, flags);
- return IRQ_HANDLED;
- } else {
- pwrkey->pressed_first = true;
- /*no pwrkey time duration, means no end key simulation*/
- if (!pwrkey->pdata->pwrkey_time_ms) {
- input_report_key(pwrkey->pwr, KEY_POWER, 1);
- input_sync(pwrkey->pwr);
- spin_unlock_irqrestore(&pwrkey->lock, flags);
- return IRQ_HANDLED;
- }
-
- input_report_key(pwrkey->pwr, KEY_END, 1);
- input_sync(pwrkey->pwr);
-
- hrtimer_start(&pwrkey->timer,
- ktime_set(pdata->pwrkey_time_ms / 1000,
- (pdata->pwrkey_time_ms % 1000) * 1000000),
- HRTIMER_MODE_REL);
- }
- spin_unlock_irqrestore(&pwrkey->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
-{
- struct pmic8058_pwrkey *pwrkey = _pwrkey;
- unsigned long flags;
-
- spin_lock_irqsave(&pwrkey->lock, flags);
- if (pwrkey->pressed_first) {
- pwrkey->pressed_first = false;
- /* no pwrkey time, means no delay in pwr key reporting */
- if (!pwrkey->pdata->pwrkey_time_ms) {
- input_report_key(pwrkey->pwr, KEY_POWER, 0);
- input_sync(pwrkey->pwr);
- spin_unlock_irqrestore(&pwrkey->lock, flags);
- return IRQ_HANDLED;
- }
-
- hrtimer_cancel(&pwrkey->timer);
-
- if (pwrkey->key_pressed) {
- pwrkey->key_pressed = false;
- input_report_key(pwrkey->pwr, KEY_POWER, 0);
- input_sync(pwrkey->pwr);
- }
-
- input_report_key(pwrkey->pwr, KEY_END, 0);
- input_sync(pwrkey->pwr);
- } else {
- /*
- * Set this flag true so that in the subsequent interrupt of
- * press we can know release interrupt came first
- */
- pwrkey->pressed_first = true;
- /* no pwrkey time, means no delay in pwr key reporting */
- if (!pwrkey->pdata->pwrkey_time_ms) {
- input_report_key(pwrkey->pwr, KEY_POWER, 1);
- input_sync(pwrkey->pwr);
- input_report_key(pwrkey->pwr, KEY_POWER, 0);
- input_sync(pwrkey->pwr);
- spin_unlock_irqrestore(&pwrkey->lock, flags);
- return IRQ_HANDLED;
- }
- input_report_key(pwrkey->pwr, KEY_END, 1);
- input_sync(pwrkey->pwr);
- input_report_key(pwrkey->pwr, KEY_END, 0);
- input_sync(pwrkey->pwr);
- }
- spin_unlock_irqrestore(&pwrkey->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_pwrkey_suspend(struct device *dev)
-{
- struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev)) {
- enable_irq_wake(pwrkey->key_press_irq);
- enable_irq_wake(pwrkey->key_release_irq);
- }
-
- return 0;
-}
-
-static int pmic8058_pwrkey_resume(struct device *dev)
-{
- struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev)) {
- disable_irq_wake(pwrkey->key_press_irq);
- disable_irq_wake(pwrkey->key_release_irq);
- }
-
- return 0;
-}
-
-static struct dev_pm_ops pm8058_pwr_key_pm_ops = {
- .suspend = pmic8058_pwrkey_suspend,
- .resume = pmic8058_pwrkey_resume,
-};
-#endif
-
-static int __devinit pmic8058_pwrkey_probe(struct platform_device *pdev)
-{
- struct input_dev *pwr;
- int key_release_irq = platform_get_irq(pdev, 0);
- int key_press_irq = platform_get_irq(pdev, 1);
- int err;
- unsigned int delay;
- u8 pon_cntl;
- struct pmic8058_pwrkey *pwrkey;
- struct pmic8058_pwrkey_pdata *pdata = pdev->dev.platform_data;
- struct pm8058_chip *pm_chip;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- dev_err(&pdev->dev, "no parent data passed in\n");
- return -EFAULT;
- }
-
- if (!pdata) {
- dev_err(&pdev->dev, "power key platform data not supplied\n");
- return -EINVAL;
- }
-
- if (pdata->kpd_trigger_delay_us > 62500) {
- dev_err(&pdev->dev, "invalid pwr key trigger delay\n");
- return -EINVAL;
- }
-
- if (pdata->pwrkey_time_ms &&
- (pdata->pwrkey_time_ms < 500 || pdata->pwrkey_time_ms > 1000)) {
- dev_err(&pdev->dev, "invalid pwr key time supplied\n");
- return -EINVAL;
- }
-
- pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
- if (!pwrkey)
- return -ENOMEM;
-
- pwrkey->pm_chip = pm_chip;
- pwrkey->pdata = pdata;
- pwrkey->pressed_first = false;
- /* Enable runtime PM ops, start in ACTIVE mode */
- err = pm_runtime_set_active(&pdev->dev);
- if (err < 0)
- dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
- pm_runtime_enable(&pdev->dev);
-
- pwr = input_allocate_device();
- if (!pwr) {
- dev_dbg(&pdev->dev, "Can't allocate power button\n");
- err = -ENOMEM;
- goto free_pwrkey;
- }
-
- input_set_capability(pwr, EV_KEY, KEY_POWER);
- input_set_capability(pwr, EV_KEY, KEY_END);
-
- pwr->name = "pmic8058_pwrkey";
- pwr->phys = "pmic8058_pwrkey/input0";
- pwr->dev.parent = &pdev->dev;
-
- delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
- delay = 1 + ilog2(delay);
-
- err = pm8058_read(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
- if (err < 0) {
- dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
- goto free_input_dev;
- }
-
-
- pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
- pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
- pon_cntl |= (pdata->pull_up ? PON_CNTL_PULL_UP : ~PON_CNTL_PULL_UP);
- err = pm8058_write(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
- if (err < 0) {
- dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
- goto free_input_dev;
- }
-
- hrtimer_init(&pwrkey->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- pwrkey->timer.function = pmic8058_pwrkey_timer;
-
- spin_lock_init(&pwrkey->lock);
-
- err = input_register_device(pwr);
- if (err) {
- dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
- goto free_input_dev;
- }
-
- pwrkey->key_press_irq = key_press_irq;
- pwrkey->key_release_irq = key_release_irq;
- pwrkey->pwr = pwr;
-
- platform_set_drvdata(pdev, pwrkey);
-
- /* Check if power-key is pressed at boot up */
- err = pm8058_irq_get_rt_status(pwrkey->pm_chip, key_press_irq);
- if (err < 0) {
- dev_err(&pdev->dev, "Key-press status at boot failed rc=%d\n",
- err);
- goto unreg_input_dev;
- }
- if (err) {
- if (!pwrkey->pdata->pwrkey_time_ms)
- input_report_key(pwrkey->pwr, KEY_POWER, 1);
- else
- input_report_key(pwrkey->pwr, KEY_END, 1);
- input_sync(pwrkey->pwr);
- pwrkey->pressed_first = true;
- }
-
- err = request_threaded_irq(key_press_irq, NULL, pwrkey_press_irq,
- IRQF_TRIGGER_RISING, "pmic8058_pwrkey_press", pwrkey);
- if (err < 0) {
- dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
- key_press_irq, err);
- goto unreg_input_dev;
- }
-
- err = request_threaded_irq(key_release_irq, NULL, pwrkey_release_irq,
- IRQF_TRIGGER_RISING, "pmic8058_pwrkey_release",
- pwrkey);
- if (err < 0) {
- dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
- key_release_irq, err);
-
- goto free_press_irq;
- }
-
- device_init_wakeup(&pdev->dev, pdata->wakeup);
-
- return 0;
-
-free_press_irq:
- free_irq(key_press_irq, NULL);
-unreg_input_dev:
- input_unregister_device(pwr);
- pwr = NULL;
-free_input_dev:
- input_free_device(pwr);
-free_pwrkey:
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- kfree(pwrkey);
- return err;
-}
-
-static int __devexit pmic8058_pwrkey_remove(struct platform_device *pdev)
-{
- struct pmic8058_pwrkey *pwrkey = platform_get_drvdata(pdev);
- int key_release_irq = platform_get_irq(pdev, 0);
- int key_press_irq = platform_get_irq(pdev, 1);
-
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- device_init_wakeup(&pdev->dev, 0);
-
- free_irq(key_press_irq, pwrkey);
- free_irq(key_release_irq, pwrkey);
- input_unregister_device(pwrkey->pwr);
- kfree(pwrkey);
-
- return 0;
-}
-
-static struct platform_driver pmic8058_pwrkey_driver = {
- .probe = pmic8058_pwrkey_probe,
- .remove = __devexit_p(pmic8058_pwrkey_remove),
- .driver = {
- .name = "pm8058-pwrkey",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &pm8058_pwr_key_pm_ops,
-#endif
- },
-};
-
-static int __init pmic8058_pwrkey_init(void)
-{
- return platform_driver_register(&pmic8058_pwrkey_driver);
-}
-module_init(pmic8058_pwrkey_init);
-
-static void __exit pmic8058_pwrkey_exit(void)
-{
- platform_driver_unregister(&pmic8058_pwrkey_driver);
-}
-module_exit(pmic8058_pwrkey_exit);
-
-MODULE_ALIAS("platform:pmic8058_pwrkey");
-MODULE_DESCRIPTION("PMIC8058 Power Key");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c
index e397774..cc18bc7 100644
--- a/drivers/input/touchscreen/atmel_maxtouch.c
+++ b/drivers/input/touchscreen/atmel_maxtouch.c
@@ -1832,16 +1832,14 @@
if (error < 0)
goto err_write_block;
- enable_irq(mxt->irq);
+ /* Make sure we just didn't miss a interrupt. */
+ if (mxt->read_chg() == 0)
+ schedule_delayed_work(&mxt->dwork, 0);
+ else
+ enable_irq(mxt->irq);
mxt->is_suspended = false;
- /* Make sure we just didn't miss a interrupt. */
- if (mxt->read_chg() == 0) {
- disable_irq(mxt->irq);
- schedule_delayed_work(&mxt->dwork, 0);
- }
-
return 0;
err_write_block:
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 790a9e1..5b594bc 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -21,6 +21,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
@@ -31,6 +32,7 @@
/* Family ID */
#define MXT224_ID 0x80
+#define MXT224E_ID 0x81
#define MXT1386_ID 0xA0
/* Version */
@@ -60,41 +62,47 @@
#define MXT_OBJECT_SIZE 6
/* Object types */
-#define MXT_DEBUG_DIAGNOSTIC 37
-#define MXT_GEN_MESSAGE 5
-#define MXT_GEN_COMMAND 6
-#define MXT_GEN_POWER 7
-#define MXT_GEN_ACQUIRE 8
-#define MXT_TOUCH_MULTI 9
-#define MXT_TOUCH_KEYARRAY 15
-#define MXT_TOUCH_PROXIMITY 23
-#define MXT_PROCI_GRIPFACE 20
-#define MXT_PROCG_NOISE 22
-#define MXT_PROCI_ONETOUCH 24
-#define MXT_PROCI_TWOTOUCH 27
-#define MXT_PROCI_GRIP 40
-#define MXT_PROCI_PALM 41
-#define MXT_SPT_COMMSCONFIG 18
-#define MXT_SPT_GPIOPWM 19
-#define MXT_SPT_SELFTEST 25
-#define MXT_SPT_CTECONFIG 28
-#define MXT_SPT_USERDATA 38
-#define MXT_SPT_DIGITIZER 43
-#define MXT_SPT_MESSAGECOUNT 44
+#define MXT_DEBUG_DIAGNOSTIC_T37 37
+#define MXT_GEN_MESSAGE_T5 5
+#define MXT_GEN_COMMAND_T6 6
+#define MXT_GEN_POWER_T7 7
+#define MXT_GEN_ACQUIRE_T8 8
+#define MXT_GEN_DATASOURCE_T53 53
+#define MXT_TOUCH_MULTI_T9 9
+#define MXT_TOUCH_KEYARRAY_T15 15
+#define MXT_TOUCH_PROXIMITY_T23 23
+#define MXT_TOUCH_PROXKEY_T52 52
+#define MXT_PROCI_GRIPFACE_T20 20
+#define MXT_PROCG_NOISE_T22 22
+#define MXT_PROCI_ONETOUCH_T24 24
+#define MXT_PROCI_TWOTOUCH_T27 27
+#define MXT_PROCI_GRIP_T40 40
+#define MXT_PROCI_PALM_T41 41
+#define MXT_PROCI_TOUCHSUPPRESSION_T42 42
+#define MXT_PROCI_STYLUS_T47 47
+#define MXT_PROCG_NOISESUPPRESSION_T48 48
+#define MXT_SPT_COMMSCONFIG_T18 18
+#define MXT_SPT_GPIOPWM_T19 19
+#define MXT_SPT_SELFTEST_T25 25
+#define MXT_SPT_CTECONFIG_T28 28
+#define MXT_SPT_USERDATA_T38 38
+#define MXT_SPT_DIGITIZER_T43 43
+#define MXT_SPT_MESSAGECOUNT_T44 44
+#define MXT_SPT_CTECONFIG_T46 46
-/* MXT_GEN_COMMAND field */
+/* MXT_GEN_COMMAND_T6 field */
#define MXT_COMMAND_RESET 0
#define MXT_COMMAND_BACKUPNV 1
#define MXT_COMMAND_CALIBRATE 2
#define MXT_COMMAND_REPORTALL 3
#define MXT_COMMAND_DIAGNOSTIC 5
-/* MXT_GEN_POWER field */
+/* MXT_GEN_POWER_T7 field */
#define MXT_POWER_IDLEACQINT 0
#define MXT_POWER_ACTVACQINT 1
#define MXT_POWER_ACTV2IDLETO 2
-/* MXT_GEN_ACQUIRE field */
+/* MXT_GEN_ACQUIRE_T8 field */
#define MXT_ACQUIRE_CHRGTIME 0
#define MXT_ACQUIRE_TCHDRIFT 2
#define MXT_ACQUIRE_DRIFTST 3
@@ -103,7 +111,7 @@
#define MXT_ACQUIRE_ATCHCALST 6
#define MXT_ACQUIRE_ATCHCALSTHR 7
-/* MXT_TOUCH_MULTI field */
+/* MXT_TOUCH_MULT_T9 field */
#define MXT_TOUCH_CTRL 0
#define MXT_TOUCH_XORIGIN 1
#define MXT_TOUCH_YORIGIN 2
@@ -133,7 +141,7 @@
#define MXT_TOUCH_YEDGEDIST 29
#define MXT_TOUCH_JUMPLIMIT 30
-/* MXT_PROCI_GRIPFACE field */
+/* MXT_PROCI_GRIPFACE_T20 field */
#define MXT_GRIPFACE_CTRL 0
#define MXT_GRIPFACE_XLOGRIP 1
#define MXT_GRIPFACE_XHIGRIP 2
@@ -163,11 +171,11 @@
#define MXT_NOISE_FREQ4 15
#define MXT_NOISE_IDLEGCAFVALID 16
-/* MXT_SPT_COMMSCONFIG */
+/* MXT_SPT_COMMSCONFIG_T18 */
#define MXT_COMMS_CTRL 0
#define MXT_COMMS_CMD 1
-/* MXT_SPT_CTECONFIG field */
+/* MXT_SPT_CTECONFIG_T28 field */
#define MXT_CTE_CTRL 0
#define MXT_CTE_CMD 1
#define MXT_CTE_MODE 2
@@ -178,21 +186,28 @@
#define MXT_VOLTAGE_DEFAULT 2700000
#define MXT_VOLTAGE_STEP 10000
+/* Analog voltage @2.7 V */
#define MXT_VTG_MIN_UV 2700000
#define MXT_VTG_MAX_UV 3300000
#define MXT_ACTIVE_LOAD_UA 15000
#define MXT_LPM_LOAD_UA 10
+/* Digital voltage @1.8 V */
+#define MXT_VTG_DIG_MIN_UV 1800000
+#define MXT_VTG_DIG_MAX_UV 1800000
+#define MXT_ACTIVE_LOAD_DIG_UA 10000
+#define MXT_LPM_LOAD_DIG_UA 10
#define MXT_I2C_VTG_MIN_UV 1800000
#define MXT_I2C_VTG_MAX_UV 1800000
#define MXT_I2C_LOAD_UA 10000
#define MXT_I2C_LPM_LOAD_UA 10
-/* Define for MXT_GEN_COMMAND */
+/* Define for MXT_GEN_COMMAND_T6 */
#define MXT_BOOT_VALUE 0xa5
#define MXT_BACKUP_VALUE 0x55
#define MXT_BACKUP_TIME 25 /* msec */
#define MXT224_RESET_TIME 65 /* msec */
+#define MXT224E_RESET_TIME 22 /* msec */
#define MXT1386_RESET_TIME 250 /* msec */
#define MXT_RESET_TIME 250 /* msec */
#define MXT_RESET_NOCHGREAD 400 /* msec */
@@ -269,6 +284,7 @@
int x;
int y;
int area;
+ int pressure;
};
/* Each client has this additional data */
@@ -280,7 +296,8 @@
struct mxt_info info;
struct mxt_finger finger[MXT_MAX_FINGER];
unsigned int irq;
- struct regulator *vcc;
+ struct regulator *vcc_ana;
+ struct regulator *vcc_dig;
struct regulator *vcc_i2c;
#if defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
@@ -294,25 +311,31 @@
static bool mxt_object_readable(unsigned int type)
{
switch (type) {
- case MXT_GEN_MESSAGE:
- case MXT_GEN_COMMAND:
- case MXT_GEN_POWER:
- case MXT_GEN_ACQUIRE:
- case MXT_TOUCH_MULTI:
- case MXT_TOUCH_KEYARRAY:
- case MXT_TOUCH_PROXIMITY:
- case MXT_PROCI_GRIPFACE:
- case MXT_PROCG_NOISE:
- case MXT_PROCI_ONETOUCH:
- case MXT_PROCI_TWOTOUCH:
- case MXT_PROCI_GRIP:
- case MXT_PROCI_PALM:
- case MXT_SPT_COMMSCONFIG:
- case MXT_SPT_GPIOPWM:
- case MXT_SPT_SELFTEST:
- case MXT_SPT_CTECONFIG:
- case MXT_SPT_USERDATA:
- case MXT_SPT_DIGITIZER:
+ case MXT_GEN_MESSAGE_T5:
+ case MXT_GEN_COMMAND_T6:
+ case MXT_GEN_POWER_T7:
+ case MXT_GEN_ACQUIRE_T8:
+ case MXT_GEN_DATASOURCE_T53:
+ case MXT_TOUCH_MULTI_T9:
+ case MXT_TOUCH_KEYARRAY_T15:
+ case MXT_TOUCH_PROXIMITY_T23:
+ case MXT_TOUCH_PROXKEY_T52:
+ case MXT_PROCI_GRIPFACE_T20:
+ case MXT_PROCG_NOISE_T22:
+ case MXT_PROCI_ONETOUCH_T24:
+ case MXT_PROCI_TWOTOUCH_T27:
+ case MXT_PROCI_GRIP_T40:
+ case MXT_PROCI_PALM_T41:
+ case MXT_PROCI_TOUCHSUPPRESSION_T42:
+ case MXT_PROCI_STYLUS_T47:
+ case MXT_PROCG_NOISESUPPRESSION_T48:
+ case MXT_SPT_COMMSCONFIG_T18:
+ case MXT_SPT_GPIOPWM_T19:
+ case MXT_SPT_SELFTEST_T25:
+ case MXT_SPT_CTECONFIG_T28:
+ case MXT_SPT_USERDATA_T38:
+ case MXT_SPT_DIGITIZER_T43:
+ case MXT_SPT_CTECONFIG_T46:
return true;
default:
return false;
@@ -322,23 +345,29 @@
static bool mxt_object_writable(unsigned int type)
{
switch (type) {
- case MXT_GEN_COMMAND:
- case MXT_GEN_POWER:
- case MXT_GEN_ACQUIRE:
- case MXT_TOUCH_MULTI:
- case MXT_TOUCH_KEYARRAY:
- case MXT_TOUCH_PROXIMITY:
- case MXT_PROCI_GRIPFACE:
- case MXT_PROCG_NOISE:
- case MXT_PROCI_ONETOUCH:
- case MXT_PROCI_TWOTOUCH:
- case MXT_PROCI_GRIP:
- case MXT_PROCI_PALM:
- case MXT_SPT_GPIOPWM:
- case MXT_SPT_SELFTEST:
- case MXT_SPT_CTECONFIG:
- case MXT_SPT_USERDATA:
- case MXT_SPT_DIGITIZER:
+ case MXT_GEN_COMMAND_T6:
+ case MXT_GEN_POWER_T7:
+ case MXT_GEN_ACQUIRE_T8:
+ case MXT_TOUCH_MULTI_T9:
+ case MXT_TOUCH_KEYARRAY_T15:
+ case MXT_TOUCH_PROXIMITY_T23:
+ case MXT_TOUCH_PROXKEY_T52:
+ case MXT_PROCI_GRIPFACE_T20:
+ case MXT_PROCG_NOISE_T22:
+ case MXT_PROCI_ONETOUCH_T24:
+ case MXT_PROCI_TWOTOUCH_T27:
+ case MXT_PROCI_GRIP_T40:
+ case MXT_PROCI_PALM_T41:
+ case MXT_PROCI_TOUCHSUPPRESSION_T42:
+ case MXT_PROCI_STYLUS_T47:
+ case MXT_PROCG_NOISESUPPRESSION_T48:
+ case MXT_SPT_COMMSCONFIG_T18:
+ case MXT_SPT_GPIOPWM_T19:
+ case MXT_SPT_SELFTEST_T25:
+ case MXT_SPT_CTECONFIG_T28:
+ case MXT_SPT_USERDATA_T38:
+ case MXT_SPT_DIGITIZER_T43:
+ case MXT_SPT_CTECONFIG_T46:
return true;
default:
return false;
@@ -512,7 +541,7 @@
struct mxt_object *object;
u16 reg;
- object = mxt_get_object(data, MXT_GEN_MESSAGE);
+ object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
if (!object)
return -EINVAL;
@@ -568,6 +597,8 @@
finger[id].x);
input_report_abs(input_dev, ABS_MT_POSITION_Y,
finger[id].y);
+ input_report_abs(input_dev, ABS_MT_PRESSURE,
+ finger[id].pressure);
input_mt_sync(input_dev);
if (finger[id].status == MXT_RELEASE)
@@ -581,6 +612,8 @@
if (status != MXT_RELEASE) {
input_report_abs(input_dev, ABS_X, finger[single_id].x);
input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+ input_report_abs(input_dev,
+ ABS_PRESSURE, finger[single_id].pressure);
}
input_sync(input_dev);
@@ -595,6 +628,7 @@
int x;
int y;
int area;
+ int pressure;
/* Check the touch is present on the screen */
if (!(status & MXT_DETECT)) {
@@ -619,6 +653,7 @@
y = y >> 2;
area = message->message[4];
+ pressure = message->message[5];
dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
status & MXT_MOVE ? "moved" : "pressed",
@@ -629,6 +664,7 @@
finger[id].x = x;
finger[id].y = y;
finger[id].area = area;
+ finger[id].pressure = pressure;
mxt_input_report(data, id);
}
@@ -649,14 +685,12 @@
dev_err(dev, "Failed to read message\n");
goto end;
}
-
reportid = message.reportid;
- /* whether reportid is thing of MXT_TOUCH_MULTI */
- object = mxt_get_object(data, MXT_TOUCH_MULTI);
+ /* whether reportid is thing of MXT_TOUCH_MULTI_T9 */
+ object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
if (!object)
goto end;
-
max_reportid = object->max_reportid;
min_reportid = max_reportid - object->num_report_ids + 1;
id = reportid - min_reportid;
@@ -802,6 +836,9 @@
case MXT224_ID:
msleep(MXT224_RESET_TIME);
break;
+ case MXT224E_ID:
+ msleep(MXT224E_RESET_TIME);
+ break;
case MXT1386_ID:
msleep(MXT1386_RESET_TIME);
break;
@@ -843,7 +880,7 @@
goto free_object_table;
/* Store T7 and T9 locally, used in suspend/resume operations */
- t7_object = mxt_get_object(data, MXT_GEN_POWER);
+ t7_object = mxt_get_object(data, MXT_GEN_POWER_T7);
if (!t7_object) {
dev_err(&client->dev, "Failed to get T7 object\n");
error = -EINVAL;
@@ -858,7 +895,7 @@
"Failed to save current power state\n");
goto free_object_table;
}
- error = mxt_read_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_CTRL,
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL,
&data->t9_ctrl);
if (error < 0) {
dev_err(&client->dev, "Failed to save current touch object\n");
@@ -866,12 +903,12 @@
}
/* Backup to memory */
- mxt_write_object(data, MXT_GEN_COMMAND,
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_BACKUPNV,
MXT_BACKUP_VALUE);
msleep(MXT_BACKUP_TIME);
do {
- error = mxt_read_object(data, MXT_GEN_COMMAND,
+ error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_BACKUPNV,
&command_register);
if (error)
@@ -886,7 +923,7 @@
/* Soft reset */
- mxt_write_object(data, MXT_GEN_COMMAND,
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, 1);
mxt_reset_delay(data);
@@ -982,7 +1019,7 @@
}
/* Change to the bootloader mode */
- mxt_write_object(data, MXT_GEN_COMMAND,
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
MXT_COMMAND_RESET, MXT_BOOT_VALUE);
mxt_reset_delay(data);
@@ -1099,7 +1136,7 @@
}
error = mxt_write_object(data,
- MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, data->t9_ctrl);
+ MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, data->t9_ctrl);
if (error < 0) {
dev_err(&data->client->dev, "failed to restore touch\n");
return error;
@@ -1114,7 +1151,7 @@
u8 t7_data[T7_DATA_SIZE] = {0};
/* disable touch and configure deep sleep mode */
- error = mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0);
+ error = mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
if (error < 0) {
dev_err(&data->client->dev, "failed to disable touch\n");
return error;
@@ -1163,32 +1200,50 @@
if (on == false)
goto power_off;
- rc = regulator_set_optimum_mode(data->vcc, MXT_ACTIVE_LOAD_UA);
+ rc = regulator_set_optimum_mode(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
if (rc < 0) {
- dev_err(&data->client->dev, "Regulator set_opt failed rc=%d\n",
- rc);
+ dev_err(&data->client->dev,
+ "Regulator vcc_ana set_opt failed rc=%d\n", rc);
return rc;
}
- rc = regulator_enable(data->vcc);
+ rc = regulator_enable(data->vcc_ana);
if (rc) {
- dev_err(&data->client->dev, "Regulator enable failed rc=%d\n",
- rc);
- goto error_reg_en_vcc;
+ dev_err(&data->client->dev,
+ "Regulator vcc_ana enable failed rc=%d\n", rc);
+ goto error_reg_en_vcc_ana;
+ }
+
+ if (data->pdata->digital_pwr_regulator) {
+ rc = regulator_set_optimum_mode(data->vcc_dig,
+ MXT_ACTIVE_LOAD_DIG_UA);
+ if (rc < 0) {
+ dev_err(&data->client->dev,
+ "Regulator vcc_dig set_opt failed rc=%d\n",
+ rc);
+ goto error_reg_opt_vcc_dig;
+ }
+
+ rc = regulator_enable(data->vcc_dig);
+ if (rc) {
+ dev_err(&data->client->dev,
+ "Regulator vcc_dig enable failed rc=%d\n", rc);
+ goto error_reg_en_vcc_dig;
+ }
}
if (data->pdata->i2c_pull_up) {
rc = regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LOAD_UA);
if (rc < 0) {
dev_err(&data->client->dev,
- "Regulator set_opt failed rc=%d\n", rc);
+ "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
goto error_reg_opt_i2c;
}
rc = regulator_enable(data->vcc_i2c);
if (rc) {
dev_err(&data->client->dev,
- "Regulator enable failed rc=%d\n", rc);
+ "Regulator vcc_i2c enable failed rc=%d\n", rc);
goto error_reg_en_vcc_i2c;
}
}
@@ -1201,14 +1256,24 @@
if (data->pdata->i2c_pull_up)
regulator_set_optimum_mode(data->vcc_i2c, 0);
error_reg_opt_i2c:
- regulator_disable(data->vcc);
-error_reg_en_vcc:
- regulator_set_optimum_mode(data->vcc, 0);
+ if (data->pdata->digital_pwr_regulator)
+ regulator_disable(data->vcc_dig);
+error_reg_en_vcc_dig:
+ if (data->pdata->digital_pwr_regulator)
+ regulator_set_optimum_mode(data->vcc_dig, 0);
+error_reg_opt_vcc_dig:
+ regulator_disable(data->vcc_ana);
+error_reg_en_vcc_ana:
+ regulator_set_optimum_mode(data->vcc_ana, 0);
return rc;
power_off:
- regulator_set_optimum_mode(data->vcc, 0);
- regulator_disable(data->vcc);
+ regulator_set_optimum_mode(data->vcc_ana, 0);
+ regulator_disable(data->vcc_ana);
+ if (data->pdata->digital_pwr_regulator) {
+ regulator_set_optimum_mode(data->vcc_dig, 0);
+ regulator_disable(data->vcc_dig);
+ }
if (data->pdata->i2c_pull_up) {
regulator_set_optimum_mode(data->vcc_i2c, 0);
regulator_disable(data->vcc_i2c);
@@ -1224,24 +1289,42 @@
if (on == false)
goto hw_shutdown;
- data->vcc = regulator_get(&data->client->dev, "vdd");
- if (IS_ERR(data->vcc)) {
- rc = PTR_ERR(data->vcc);
- dev_err(&data->client->dev, "Regulator get failed rc=%d\n",
- rc);
+ data->vcc_ana = regulator_get(&data->client->dev, "vdd_ana");
+ if (IS_ERR(data->vcc_ana)) {
+ rc = PTR_ERR(data->vcc_ana);
+ dev_err(&data->client->dev,
+ "Regulator get failed vcc_ana rc=%d\n", rc);
return rc;
}
- if (regulator_count_voltages(data->vcc) > 0) {
- rc = regulator_set_voltage(data->vcc, MXT_VTG_MIN_UV,
+ if (regulator_count_voltages(data->vcc_ana) > 0) {
+ rc = regulator_set_voltage(data->vcc_ana, MXT_VTG_MIN_UV,
MXT_VTG_MAX_UV);
if (rc) {
dev_err(&data->client->dev,
"regulator set_vtg failed rc=%d\n", rc);
- goto error_set_vtg_vcc;
+ goto error_set_vtg_vcc_ana;
}
}
+ if (data->pdata->digital_pwr_regulator) {
+ data->vcc_dig = regulator_get(&data->client->dev, "vdd_dig");
+ if (IS_ERR(data->vcc_dig)) {
+ rc = PTR_ERR(data->vcc_dig);
+ dev_err(&data->client->dev,
+ "Regulator get dig failed rc=%d\n", rc);
+ goto error_get_vtg_vcc_dig;
+ }
+ if (regulator_count_voltages(data->vcc_dig) > 0) {
+ rc = regulator_set_voltage(data->vcc_dig,
+ MXT_VTG_DIG_MIN_UV, MXT_VTG_DIG_MAX_UV);
+ if (rc) {
+ dev_err(&data->client->dev,
+ "regulator set_vtg failed rc=%d\n", rc);
+ goto error_set_vtg_vcc_dig;
+ }
+ }
+ }
if (data->pdata->i2c_pull_up) {
data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
if (IS_ERR(data->vcc_i2c)) {
@@ -1266,16 +1349,30 @@
error_set_vtg_i2c:
regulator_put(data->vcc_i2c);
error_get_vtg_i2c:
- if (regulator_count_voltages(data->vcc) > 0)
- regulator_set_voltage(data->vcc, 0, MXT_VTG_MAX_UV);
-error_set_vtg_vcc:
- regulator_put(data->vcc);
+ if (data->pdata->digital_pwr_regulator)
+ if (regulator_count_voltages(data->vcc_dig) > 0)
+ regulator_set_voltage(data->vcc_dig, 0,
+ MXT_VTG_DIG_MAX_UV);
+error_set_vtg_vcc_dig:
+ if (data->pdata->digital_pwr_regulator)
+ regulator_put(data->vcc_dig);
+error_get_vtg_vcc_dig:
+ if (regulator_count_voltages(data->vcc_ana) > 0)
+ regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
+error_set_vtg_vcc_ana:
+ regulator_put(data->vcc_ana);
return rc;
hw_shutdown:
- if (regulator_count_voltages(data->vcc) > 0)
- regulator_set_voltage(data->vcc, 0, MXT_VTG_MAX_UV);
- regulator_put(data->vcc);
+ if (regulator_count_voltages(data->vcc_ana) > 0)
+ regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
+ regulator_put(data->vcc_ana);
+ if (data->pdata->digital_pwr_regulator) {
+ if (regulator_count_voltages(data->vcc_dig) > 0)
+ regulator_set_voltage(data->vcc_dig, 0,
+ MXT_VTG_DIG_MAX_UV);
+ regulator_put(data->vcc_dig);
+ }
if (data->pdata->i2c_pull_up) {
if (regulator_count_voltages(data->vcc_i2c) > 0)
regulator_set_voltage(data->vcc_i2c, 0,
@@ -1294,19 +1391,29 @@
if (on == false)
goto regulator_hpm;
- rc = regulator_set_optimum_mode(data->vcc, MXT_LPM_LOAD_UA);
+ rc = regulator_set_optimum_mode(data->vcc_ana, MXT_LPM_LOAD_UA);
if (rc < 0) {
dev_err(&data->client->dev,
- "Regulator set_opt failed rc=%d\n", rc);
+ "Regulator vcc_ana set_opt failed rc=%d\n", rc);
goto fail_regulator_lpm;
}
+ if (data->pdata->digital_pwr_regulator) {
+ rc = regulator_set_optimum_mode(data->vcc_dig,
+ MXT_LPM_LOAD_DIG_UA);
+ if (rc < 0) {
+ dev_err(&data->client->dev,
+ "Regulator vcc_dig set_opt failed rc=%d\n", rc);
+ goto fail_regulator_lpm;
+ }
+ }
+
if (data->pdata->i2c_pull_up) {
rc = regulator_set_optimum_mode(data->vcc_i2c,
MXT_I2C_LPM_LOAD_UA);
if (rc < 0) {
dev_err(&data->client->dev,
- "Regulator set_opt failed rc=%d\n", rc);
+ "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
goto fail_regulator_lpm;
}
}
@@ -1315,18 +1422,28 @@
regulator_hpm:
- rc = regulator_set_optimum_mode(data->vcc, MXT_ACTIVE_LOAD_UA);
+ rc = regulator_set_optimum_mode(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
if (rc < 0) {
dev_err(&data->client->dev,
- "Regulator set_opt failed rc=%d\n", rc);
+ "Regulator vcc_ana set_opt failed rc=%d\n", rc);
goto fail_regulator_hpm;
}
+ if (data->pdata->digital_pwr_regulator) {
+ rc = regulator_set_optimum_mode(data->vcc_dig,
+ MXT_ACTIVE_LOAD_DIG_UA);
+ if (rc < 0) {
+ dev_err(&data->client->dev,
+ "Regulator vcc_dig set_opt failed rc=%d\n", rc);
+ goto fail_regulator_hpm;
+ }
+ }
+
if (data->pdata->i2c_pull_up) {
rc = regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LOAD_UA);
if (rc < 0) {
dev_err(&data->client->dev,
- "Regulator set_opt failed rc=%d\n", rc);
+ "Regulator vcc_i2c set_opt failed rc=%d\n", rc);
goto fail_regulator_hpm;
}
}
@@ -1334,14 +1451,19 @@
return 0;
fail_regulator_lpm:
- regulator_set_optimum_mode(data->vcc, MXT_ACTIVE_LOAD_UA);
+ regulator_set_optimum_mode(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
+ if (data->pdata->digital_pwr_regulator)
+ regulator_set_optimum_mode(data->vcc_dig,
+ MXT_ACTIVE_LOAD_DIG_UA);
if (data->pdata->i2c_pull_up)
regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LOAD_UA);
return rc;
fail_regulator_hpm:
- regulator_set_optimum_mode(data->vcc, MXT_LPM_LOAD_UA);
+ regulator_set_optimum_mode(data->vcc_ana, MXT_LPM_LOAD_UA);
+ if (data->pdata->digital_pwr_regulator)
+ regulator_set_optimum_mode(data->vcc_dig, MXT_LPM_LOAD_DIG_UA);
if (data->pdata->i2c_pull_up)
regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LPM_LOAD_UA);
@@ -1472,6 +1594,8 @@
0, data->pdata->x_size, 0, 0);
input_set_abs_params(input_dev, ABS_Y,
0, data->pdata->y_size, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, 255, 0, 0);
/* For multi touch */
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
@@ -1480,6 +1604,8 @@
0, data->pdata->x_size, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->pdata->y_size, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+ 0, 255, 0, 0);
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
@@ -1502,9 +1628,47 @@
goto err_regulator_on;
}
+ if (gpio_is_valid(pdata->irq_gpio)) {
+ /* configure touchscreen irq gpio */
+ error = gpio_request(pdata->irq_gpio,
+ "mxt_irq_gpio");
+ if (error) {
+ pr_err("%s: unable to request gpio [%d]\n", __func__,
+ pdata->irq_gpio);
+ goto err_power_on;
+ }
+ error = gpio_direction_input(pdata->irq_gpio);
+ if (error) {
+ pr_err("%s: unable to set_direction for gpio [%d]\n",
+ __func__, pdata->irq_gpio);
+ goto err_irq_gpio_req;
+ }
+ }
+
+ if (gpio_is_valid(pdata->reset_gpio)) {
+ /* configure touchscreen reset out gpio */
+ error = gpio_request(pdata->reset_gpio,
+ "mxt_reset_gpio");
+ if (error) {
+ pr_err("%s: unable to request reset gpio %d\n",
+ __func__, pdata->reset_gpio);
+ goto err_irq_gpio_req;
+ }
+
+ error = gpio_direction_output(
+ pdata->reset_gpio, 1);
+ if (error) {
+ pr_err("%s: unable to set direction for gpio %d\n",
+ __func__, pdata->reset_gpio);
+ goto err_reset_gpio_req;
+ }
+ }
+
+ mxt_reset_delay(data);
+
error = mxt_initialize(data);
if (error)
- goto err_power_on;
+ goto err_reset_gpio_req;
error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
pdata->irqflags, client->dev.driver->name, data);
@@ -1542,6 +1706,12 @@
free_irq(client->irq, data);
err_free_object:
kfree(data->object_table);
+err_reset_gpio_req:
+ if (gpio_is_valid(pdata->reset_gpio))
+ gpio_free(pdata->reset_gpio);
+err_irq_gpio_req:
+ if (gpio_is_valid(pdata->irq_gpio))
+ gpio_free(pdata->irq_gpio);
err_power_on:
if (pdata->power_on)
pdata->power_on(false);
diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
index 9df1189..bb02be6 100644
--- a/drivers/input/touchscreen/cyttsp-i2c.c
+++ b/drivers/input/touchscreen/cyttsp-i2c.c
@@ -1006,7 +1006,7 @@
/* wait for TTSP Device to complete reset back to bootloader */
tries = 0;
do {
- mdelay(1);
+ usleep_range(1000, 1000);
cyttsp_putbl(ts, 1, false, false, false);
} while (g_bl_data.bl_status != 0x10 &&
g_bl_data.bl_status != 0x11 &&
@@ -1024,7 +1024,7 @@
* switch to Operational mode */
tries = 0;
do {
- mdelay(100);
+ msleep(100);
cyttsp_putbl(ts, 2, false, false, false);
} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
tries++ < 100);
@@ -2001,7 +2001,7 @@
/* wait for TTSP Device to complete reset back to bootloader */
tries = 0;
do {
- mdelay(1);
+ usleep_range(1000, 1000);
cyttsp_putbl(ts, 3, false, false, false);
} while (g_bl_data.bl_status != 0x10 &&
g_bl_data.bl_status != 0x11 &&
@@ -2026,7 +2026,7 @@
i++;
tries = 0;
do {
- mdelay(100);
+ msleep(100);
cyttsp_putbl(ts, 4, false, false, false);
} while (g_bl_data.bl_status != 0x10 &&
g_bl_data.bl_status != 0x11 &&
@@ -2059,7 +2059,7 @@
!((g_bl_data.bl_status == 0x11) &&
(g_bl_data.bl_error == 0x20)) &&
(tries++ < 100)) {
- mdelay(1);
+ usleep_range(1000, 1000);
cyttsp_putbl(ts, 5, false, false, false);
}
}
@@ -2073,7 +2073,7 @@
i++;
tries = 0;
do {
- mdelay(100);
+ msleep(100);
cyttsp_putbl(ts, 6, true, false, false);
} while (g_bl_data.bl_status != 0x10 &&
g_bl_data.bl_status != 0x11 &&
@@ -2098,7 +2098,7 @@
/* wait for TTSP Device to complete reset back to bootloader */
tries = 0;
do {
- mdelay(1);
+ usleep_range(1000, 1000);
cyttsp_putbl(ts, 3, false, false, false);
} while (g_bl_data.bl_status != 0x10 &&
g_bl_data.bl_status != 0x11 &&
@@ -2132,7 +2132,7 @@
sizeof(host_reg), &host_reg);
tries = 0;
do {
- mdelay(1);
+ usleep_range(1000, 1000);
/* set arg2 to non-0 to activate */
retval = cyttsp_putbl(ts, 1, true, true, true);
@@ -2170,7 +2170,7 @@
sizeof(host_reg), &host_reg);
/* wait for TTSP Device to complete switch to
* Operational mode */
- mdelay(1000);
+ msleep(1000);
goto bypass;
}
}
@@ -2249,7 +2249,7 @@
* switch to Operational mode */
tries = 0;
do {
- mdelay(100);
+ msleep(100);
cyttsp_putbl(ts, 9, false, false, false);
} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
tries++ < 100);
@@ -2267,7 +2267,7 @@
retval = i2c_smbus_write_i2c_block_data(ts->client,
CY_REG_BASE, sizeof(host_reg), &host_reg);
/* wait for TTSP Device to complete switch to SysInfo mode */
- mdelay(100);
+ msleep(100);
if (!(retval < CY_OK)) {
retval = i2c_smbus_read_i2c_block_data(ts->client,
CY_REG_BASE,
@@ -2326,7 +2326,7 @@
ts->client,
CY_REG_ACT_INTRVL,
sizeof(intrvl_ray), intrvl_ray);
- mdelay(CY_DLY_SYSINFO);
+ msleep(CY_DLY_SYSINFO);
}
}
}
@@ -2339,7 +2339,7 @@
sizeof(host_reg), &host_reg);
/* wait for TTSP Device to complete
* switch to Operational mode */
- mdelay(100);
+ msleep(100);
}
}
/* init gesture setup;
@@ -2352,7 +2352,7 @@
retval = i2c_smbus_write_i2c_block_data(ts->client,
CY_REG_GEST_SET,
sizeof(gesture_setup), &gesture_setup);
- mdelay(CY_DLY_DFLT);
+ msleep(CY_DLY_DFLT);
}
if (!(retval < CY_OK))
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index fd5fcd2..59f915e 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2961,8 +2961,9 @@
retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
break;
case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
+ case V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH:
/*
- This private control is a place holder to keep the
+ These private controls are place holders to keep the
driver compatible with changes done in the frameworks
which are specific to TAVARUA.
*/
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index b73775c..393e30e 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1416,93 +1416,49 @@
adie_type_bahma = is_bahama();
/* Set freq band */
- switch (region) {
- case TAVARUA_REGION_US:
- case TAVARUA_REGION_EU:
+ if (region == TAVARUA_REGION_JAPAN)
+ SET_REG_FIELD(radio->registers[RDCTRL], 1,
+ RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
+ else
SET_REG_FIELD(radio->registers[RDCTRL], 0,
RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
- break;
- case TAVARUA_REGION_JAPAN_WIDE:
- case TAVARUA_REGION_JAPAN:
- default:
- retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
- if (retval < 0) {
- FMDERR("failed to get RADIO_CONFIG\n");
- return retval;
- }
- band_low = (radio->region_params.band_low -
- low_band_limit) / spacing;
- band_high = (radio->region_params.band_high -
- low_band_limit) / spacing;
- FMDBG("low_band: %x, high_band: %x\n", band_low, band_high);
- xfr_buf[0] = band_low >> 8;
- xfr_buf[1] = band_low & 0xFF;
- xfr_buf[2] = band_high >> 8;
- xfr_buf[3] = band_high & 0xFF;
- retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
- if (retval < 0) {
- FMDERR("Could not set regional settings\n");
- return retval;
- }
- break;
- }
/* Set De-emphasis and soft band range*/
- switch (region) {
- case TAVARUA_REGION_US:
- case TAVARUA_REGION_JAPAN:
- case TAVARUA_REGION_JAPAN_WIDE:
- value = EMP_75;
- break;
- case TAVARUA_REGION_EU:
- value = EMP_50;
- break;
- default:
- value = radio->region_params.emphasis;
- }
-
- SET_REG_FIELD(radio->registers[RDCTRL], value,
+ SET_REG_FIELD(radio->registers[RDCTRL], radio->region_params.emphasis,
RDCTRL_DEEMPHASIS_OFFSET, RDCTRL_DEEMPHASIS_MASK);
/* set RDS standard */
- switch (region) {
- default:
- value = radio->region_params.rds_std;
- break;
- case TAVARUA_REGION_US:
- value = RBDS_STD;
- break;
- case TAVARUA_REGION_EU:
- value = RDS_STD;
- break;
- }
- SET_REG_FIELD(radio->registers[RDSCTRL], value,
+ SET_REG_FIELD(radio->registers[RDSCTRL], radio->region_params.rds_std,
RDSCTRL_STANDARD_OFFSET, RDSCTRL_STANDARD_MASK);
FMDBG("RDSCTRLL %x\n", radio->registers[RDSCTRL]);
retval = tavarua_write_register(radio, RDSCTRL,
radio->registers[RDSCTRL]);
- if (retval < 0)
+ if (retval < 0) {
+ FMDERR("Failed to set RDS/RBDS standard\n");
return retval;
+ }
+ /* Set the lower and upper band limits*/
+ retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
+ if (retval < 0) {
+ FMDERR("failed to get RADIO_CONFIG\n");
+ return retval;
+ }
- /* setting soft band */
- switch (region) {
- case TAVARUA_REGION_US:
- case TAVARUA_REGION_EU:
- radio->region_params.band_low = 87.5 * FREQ_MUL;
- radio->region_params.band_high = 108 * FREQ_MUL;
- break;
- case TAVARUA_REGION_JAPAN:
- radio->region_params.band_low = 76 * FREQ_MUL;
- radio->region_params.band_high = 90 * FREQ_MUL;
- break;
- case TAVARUA_REGION_JAPAN_WIDE:
- radio->region_params.band_low = 90 * FREQ_MUL;
- radio->region_params.band_high = 108 * FREQ_MUL;
- break;
- default:
- break;
+ band_low = (radio->region_params.band_low -
+ low_band_limit) / spacing;
+ band_high = (radio->region_params.band_high -
+ low_band_limit) / spacing;
+
+ xfr_buf[0] = RSH_DATA(band_low, 8);
+ xfr_buf[1] = GET_ABS_VAL(band_low);
+ xfr_buf[2] = RSH_DATA(band_high, 8);
+ xfr_buf[3] = GET_ABS_VAL(band_high);
+ retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
+ if (retval < 0) {
+ FMDERR("Could not set regional settings\n");
+ return retval;
}
radio->region_params.region = region;
@@ -1555,8 +1511,7 @@
}
/* Set channel spacing */
- switch (region) {
- case TAVARUA_REGION_US:
+ if (region == TAVARUA_REGION_US) {
if (adie_type_bahma) {
FMDBG("Adie type : Bahama\n");
/*
@@ -1569,23 +1524,13 @@
FMDBG("Adie type : Marimba\n");
value = FM_CH_SPACE_200KHZ;
}
- break;
- case TAVARUA_REGION_JAPAN:
- value = FM_CH_SPACE_100KHZ;
- break;
- case TAVARUA_REGION_EU:
- case TAVARUA_REGION_JAPAN_WIDE:
- value = FM_CH_SPACE_50KHZ;
- break;
- default:
+ } else {
/*
Set the channel spacing as configured from
the upper layers.
*/
value = radio->region_params.spacing;
- break;
}
-
SET_REG_FIELD(radio->registers[RDCTRL], value,
RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 6f39576..5454763 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -5,6 +5,8 @@
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
+ EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+ EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
obj-$(CONFIG_MSM_CAMERA) += io/ sensors/ actuators/ csi/
else
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 579c4d5..8df6243 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -19,7 +19,7 @@
#include <linux/spinlock.h>
#include <linux/proc_fs.h>
#include "msm.h"
-
+#include "msm_sensor.h"
#define MSM_MAX_CAMERA_SENSORS 5
@@ -2294,10 +2294,11 @@
{
int rc = -ENOMEM;
struct video_device *pvdev = NULL;
+ struct i2c_client *client = v4l2_get_subdevdata(pcam->mctl.sensor_sdev);
D("%s\n", __func__);
/* first register the v4l2 device */
- pcam->v4l2_dev.dev = &pcam->pdev->dev;
+ pcam->v4l2_dev.dev = &client->dev;
rc = v4l2_device_register(pcam->v4l2_dev.dev, &pcam->v4l2_dev);
if (rc < 0)
return -EINVAL;
@@ -2314,11 +2315,11 @@
/* init video device's driver interface */
D("sensor name = %s, sizeof(pvdev->name)=%d\n",
- pcam->pdev->name, sizeof(pvdev->name));
+ pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
/* device info - strlcpy is safer than strncpy but
only if architecture supports*/
- strlcpy(pvdev->name, pcam->pdev->name, sizeof(pvdev->name));
+ strlcpy(pvdev->name, pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
pvdev->release = video_device_release;
pvdev->fops = &g_msm_fops;
@@ -2418,36 +2419,25 @@
struct platform_device *pdev)
{
int rc = 0;
-
- sync->sdata = pdev->dev.platform_data;
-
wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
-
- sync->pdev = pdev;
sync->opencnt = 0;
-
mutex_init(&sync->lock);
- D("%s: initialized %s\n", __func__, sync->sdata->sensor_name);
return rc;
}
/* register a msm sensor into the msm device, which will probe the
* sensor HW. if the HW exist then create a video device (/dev/videoX/)
* to represent this sensor */
-int msm_sensor_register(struct platform_device *pdev,
- int (*sensor_probe)(const struct msm_camera_sensor_info *,
- struct v4l2_subdev *, struct msm_sensor_ctrl *))
+int msm_sensor_register(struct v4l2_subdev *sensor_sd)
{
-
int rc = -EINVAL;
- struct msm_camera_sensor_info *sdata = pdev->dev.platform_data;
+ struct msm_camera_sensor_info *sdata;
struct msm_cam_v4l2_device *pcam;
- struct v4l2_subdev *sdev = NULL;
- struct msm_sensor_ctrl *sctrl = NULL;
+ struct msm_sensor_ctrl_t *s_ctrl;
struct v4l2_subdev *act_sdev = NULL;
struct msm_actuator_ctrl *actctrl = NULL;
- D("%s for %s\n", __func__, pdev->name);
+ D("%s for %s\n", __func__, sensor_sd->name);
/* allocate the memory for the camera device first */
pcam = kzalloc(sizeof(*pcam), GFP_KERNEL);
@@ -2457,44 +2447,15 @@
return -ENOMEM;
}
- pcam->mctl.sensor_sdev = kzalloc(sizeof(struct v4l2_subdev),
- GFP_KERNEL);
- if (!pcam->mctl.sensor_sdev) {
- pr_err("%s: could not allocate mem for sensor v4l2_subdev\n",
- __func__);
- kfree(pcam);
- return -ENOMEM;
- }
-
- sdev = pcam->mctl.sensor_sdev;
- snprintf(sdev->name, sizeof(sdev->name), "%s", pdev->name);
- sctrl = &pcam->mctl.sync.sctrl;
-
- /* come sensor probe logic */
- rc = msm_camio_probe_on(pdev);
- if (rc < 0) {
- kzfree(pcam);
- return rc;
- }
-
- rc = sensor_probe(sdata, sdev, sctrl);
- if (rc < 0) {
- pr_err("%s: failed to detect %s\n",
- __func__,
- sdata->sensor_name);
- msm_camio_probe_off(pdev);
- kzfree(sdev);
- kzfree(pcam);
- return rc;
- }
+ pcam->mctl.sensor_sdev = sensor_sd;
+ s_ctrl = get_sctrl(sensor_sd);
+ sdata = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
pcam->mctl.act_sdev = kzalloc(sizeof(struct v4l2_subdev),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!pcam->mctl.act_sdev) {
pr_err("%s: could not allocate mem for actuator v4l2_subdev\n",
- __func__);
- msm_camio_probe_off(pdev);
- kzfree(sdev);
+ __func__);
kfree(pcam);
return -ENOMEM;
}
@@ -2503,20 +2464,17 @@
actctrl = &pcam->mctl.sync.actctrl;
msm_actuator_probe(sdata->actuator_info,
- act_sdev, actctrl);
-
- msm_camio_probe_off(pdev);
+ act_sdev, actctrl);
/* setup a manager object*/
- rc = msm_sync_init(&pcam->mctl.sync, pdev);
+ rc = msm_sync_init(&pcam->mctl.sync, NULL);
if (rc < 0)
goto failure;
D("%s: pcam =0x%p\n", __func__, pcam);
D("%s: &pcam->mctl.sync =0x%p\n", __func__, &pcam->mctl.sync);
+ pcam->mctl.sync.sdata = sdata;
pcam->mctl.sync.pcam_sync = pcam;
- /* bind the driver device to the sensor device */
- pcam->pdev = pdev;
/* init the user count and lock*/
pcam->use_count = 0;
@@ -2527,7 +2485,6 @@
if (rc < 0)
goto failure;
- /* now initialize the camera device object */
rc = msm_cam_dev_init(pcam);
if (rc < 0)
goto failure;
@@ -2541,39 +2498,35 @@
g_server_dev.camera_info.s_mount_angle
[g_server_dev.camera_info.num_cameras]
- = sctrl->s_mount_angle;
+ = sdata->sensor_platform_info->mount_angle;
g_server_dev.camera_info.is_internal_cam
[g_server_dev.camera_info.num_cameras]
- = sctrl->s_camera_type;
+ = sdata->camera_type;
g_server_dev.camera_info.num_cameras++;
D("%s done, rc = %d\n", __func__, rc);
D("%s number of sensors connected is %d\n", __func__,
g_server_dev.camera_info.num_cameras);
-/*
- if (g_server_dev.camera_info.num_cameras == 1) {
- rc = add_axi_qos();
- if (rc < 0)
- goto failure;
- }
-*/
+
/* register the subdevice, must be done for callbacks */
- rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sdev);
+ rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sensor_sd);
if (rc < 0) {
D("%s sensor sub device register failed\n",
__func__);
goto failure;
}
+
if (sdata->actuator_info) {
rc = v4l2_device_register_subdev(&pcam->v4l2_dev, act_sdev);
if (rc < 0) {
D("%s actuator sub device register failed\n",
- __func__);
+ __func__);
goto failure;
}
}
+
pcam->vnode_id = vnode_count++;
return rc;
@@ -2581,9 +2534,7 @@
/* mutex_destroy not needed at this moment as the associated
implemenation of mutex_init is not consuming resources */
msm_sync_destroy(&pcam->mctl.sync);
- pcam->pdev = NULL;
kfree(act_sdev);
- kfree(sdev);
kzfree(pcam);
return rc;
}
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 3e3b9c8..5fc3e6ae 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -396,9 +396,7 @@
*/
int msm_isp_register(struct msm_cam_server_dev *psvr);
void msm_isp_unregister(struct msm_cam_server_dev *psvr);
-int msm_sensor_register(struct platform_device *pdev,
- int (*sensor_probe)(const struct msm_camera_sensor_info *,
- struct v4l2_subdev *, struct msm_sensor_ctrl *));
+int msm_sensor_register(struct v4l2_subdev *);
int msm_isp_init_module(int g_num_config_nodes);
int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam);
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index ec18a93..3168bb6 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -136,10 +136,10 @@
msm_io_dump(dest_addr, len);
}
-static int msm_camera_vreg_enable(struct platform_device *pdev)
+static int msm_camera_vreg_enable(struct device *dev)
{
if (mipi_csi_vdd == NULL) {
- mipi_csi_vdd = regulator_get(&pdev->dev, "mipi_csi_vdd");
+ mipi_csi_vdd = regulator_get(dev, "mipi_csi_vdd");
if (IS_ERR(mipi_csi_vdd)) {
CDBG("%s: VREG MIPI CSI VDD get failed\n", __func__);
mipi_csi_vdd = NULL;
@@ -164,7 +164,7 @@
}
}
if (cam_vana == NULL) {
- cam_vana = regulator_get(&pdev->dev, "cam_vana");
+ cam_vana = regulator_get(dev, "cam_vana");
if (IS_ERR(cam_vana)) {
CDBG("%s: VREG CAM VANA get failed\n", __func__);
cam_vana = NULL;
@@ -188,7 +188,7 @@
}
}
if (cam_vio == NULL) {
- cam_vio = regulator_get(&pdev->dev, "cam_vio");
+ cam_vio = regulator_get(dev, "cam_vio");
if (IS_ERR(cam_vio)) {
CDBG("%s: VREG VIO get failed\n", __func__);
cam_vio = NULL;
@@ -200,7 +200,7 @@
}
}
if (cam_vdig == NULL) {
- cam_vdig = regulator_get(&pdev->dev, "cam_vdig");
+ cam_vdig = regulator_get(dev, "cam_vdig");
if (IS_ERR(cam_vdig)) {
CDBG("%s: VREG CAM VDIG get failed\n", __func__);
cam_vdig = NULL;
@@ -224,7 +224,7 @@
}
}
if (cam_vaf == NULL) {
- cam_vaf = regulator_get(&pdev->dev, "cam_vaf");
+ cam_vaf = regulator_get(dev, "cam_vaf");
if (IS_ERR(cam_vaf)) {
CDBG("%s: VREG CAM VAF get failed\n", __func__);
cam_vaf = NULL;
@@ -456,9 +456,8 @@
return rc;
}
-static int config_gpio_table(int gpio_en)
+static int config_gpio_table(struct msm_camera_sensor_info *sinfo, int gpio_en)
{
- struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data;
struct msm_camera_gpio_conf *gpio_conf = sinfo->gpio_conf;
int rc = 0, i = 0;
@@ -567,73 +566,47 @@
.control = PM8XXX_MPP_CS_CTRL_DISABLE,
};
-int msm_camio_sensor_clk_on(struct platform_device *pdev)
+static struct msm_cam_clk_info cam_clk_info[] = {
+ {"cam_clk", 24000000},
+};
+
+int msm_sensor_probe_on(struct device *dev)
{
int rc = 0;
- struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+ struct msm_camera_sensor_info *sinfo = dev->platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
- camio_dev = pdev;
camio_clk = camdev->ioclk;
- msm_camera_vreg_enable(pdev);
+ rc = config_gpio_table(sinfo, 1);
+ if (rc < 0)
+ return rc;
+ msm_camera_vreg_enable(dev);
if (sinfo->sensor_platform_info->privacy_light) {
struct msm8960_privacy_light_cfg *privacy_light_config =
sinfo->sensor_platform_info->privacy_light_info;
pm8xxx_mpp_config(privacy_light_config->mpp,
&privacy_light_on_config);
}
- msleep(20);
- rc = config_gpio_table(1);
- if (rc < 0)
- return rc;
- return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+ return msm_cam_clk_enable(dev, cam_clk_info,
+ &camio_cam_clk, ARRAY_SIZE(cam_clk_info), 1);
}
-int msm_camio_sensor_clk_off(struct platform_device *pdev)
+int msm_sensor_probe_off(struct device *dev)
{
int rc = 0;
- struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
- msm_camera_vreg_disable();
+ struct msm_camera_sensor_info *sinfo = dev->platform_data;
if (sinfo->sensor_platform_info->privacy_light) {
struct msm8960_privacy_light_cfg *privacy_light_config =
sinfo->sensor_platform_info->privacy_light_info;
pm8xxx_mpp_config(privacy_light_config->mpp,
&privacy_light_off_config);
}
- rc = config_gpio_table(0);
- if (rc < 0)
- return rc;
- return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
-}
-
-void msm_camio_vfe_blk_reset(void)
-{
- return;
-}
-
-int msm_camio_probe_on(struct platform_device *pdev)
-{
- int rc = 0;
- struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
- struct msm_camera_device_platform_data *camdev = sinfo->pdata;
- camio_dev = pdev;
- camio_clk = camdev->ioclk;
-
- rc = config_gpio_table(1);
- if (rc < 0)
- return rc;
- msm_camera_vreg_enable(pdev);
- return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
-}
-
-int msm_camio_probe_off(struct platform_device *pdev)
-{
- int rc = 0;
msm_camera_vreg_disable();
- rc = config_gpio_table(0);
+ rc = config_gpio_table(sinfo, 0);
if (rc < 0)
return rc;
- return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+ return msm_cam_clk_enable(dev, cam_clk_info,
+ &camio_cam_clk, ARRAY_SIZE(cam_clk_info), 0);
}
void msm_camio_mode_config(enum msm_cam_mode mode)
@@ -653,16 +626,13 @@
}
}
-void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
+void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
+ enum msm_bus_perf_setting perf_setting)
{
static uint32_t bus_perf_client;
- struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data;
- struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-
int rc = 0;
switch (perf_setting) {
case S_INIT:
- cam_bus_scale_table = camdev->cam_bus_scale_table;
bus_perf_client =
msm_bus_scale_register_client(cam_bus_scale_table);
if (!bus_perf_client) {
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 689a614..759ac47 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -31,6 +31,7 @@
#include "msm_csid.h"
#include "msm_csiphy.h"
#include "msm_ispif.h"
+#include "msm_sensor.h"
#ifdef CONFIG_MSM_CAMERA_DEBUG
#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -151,7 +152,7 @@
return -EFAULT;
}
- sdata = sync->pdev->dev.platform_data;
+ sdata = sync->sdata;
D("%s: sensor_name %s\n", __func__, sdata->sensor_name);
memcpy(&info.name[0], sdata->sensor_name, MAX_SENSOR_NAME);
@@ -175,8 +176,9 @@
unsigned int notification, void *arg)
{
int rc = -EINVAL;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
struct msm_camera_sensor_info *sinfo =
- p_mctl->plat_dev->dev.platform_data;
+ (struct msm_camera_sensor_info *) s_ctrl->sensordata;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
uint8_t csid_core = camdev->csid_core;
switch (notification) {
@@ -258,7 +260,8 @@
break;
case MSM_CAM_IOCTL_SENSOR_IO_CFG:
- rc = p_mctl->sync.sctrl.s_config(argp);
+ rc = v4l2_subdev_call(p_mctl->sensor_sdev,
+ core, ioctl, VIDIOC_MSM_SENSOR_CFG, argp);
break;
case MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL: {
@@ -325,6 +328,19 @@
break;
}
+ case MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME: {
+ struct timeval timestamp;
+ if (copy_from_user(×tamp, argp, sizeof(timestamp))) {
+ ERR_COPY_FROM_USER();
+ rc = -EFAULT;
+ } else {
+ msm_mctl_gettimeofday(×tamp);
+ rc = copy_to_user((void *)argp,
+ ×tamp, sizeof(timestamp));
+ }
+ break;
+ }
+
case MSM_CAM_IOCTL_FLASH_CTRL: {
struct flash_ctrl_data flash_info;
if (copy_from_user(&flash_info, argp, sizeof(flash_info))) {
@@ -462,8 +478,10 @@
{
int rc = 0;
struct msm_sync *sync = NULL;
- struct msm_camera_sensor_info *sinfo;
- struct msm_camera_device_platform_data *camdev;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+ struct msm_camera_sensor_info *sinfo =
+ (struct msm_camera_sensor_info *) s_ctrl->sensordata;
+ struct msm_camera_device_platform_data *camdev = sinfo->pdata;
uint8_t csid_core;
D("%s\n", __func__);
if (!p_mctl) {
@@ -480,10 +498,6 @@
uint32_t csid_version;
wake_lock(&sync->wake_lock);
- sinfo = sync->pdev->dev.platform_data;
- sync->pdev->resource = sinfo->resource;
- sync->pdev->num_resources = sinfo->num_resources;
- camdev = sinfo->pdata;
csid_core = camdev->csid_core;
rc = msm_mctl_register_subdevs(p_mctl, csid_core);
if (rc < 0) {
@@ -492,14 +506,6 @@
goto msm_open_done;
}
- /* turn on clock */
- rc = msm_camio_sensor_clk_on(sync->pdev);
- if (rc < 0) {
- pr_err("%s: msm_camio_sensor_clk_on failed:%d\n",
- __func__, rc);
- goto msm_open_done;
- }
-
rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_INIT, NULL);
if (rc < 0) {
@@ -535,8 +541,7 @@
}
/* then sensor - move sub dev later*/
- if (sync->sctrl.s_init)
- rc = sync->sctrl.s_init(sync->sdata);
+ rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
if (rc < 0) {
pr_err("%s: isp init failed: %d\n", __func__, rc);
@@ -570,8 +575,6 @@
static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
{
int rc = 0;
- struct msm_sync *sync = &(p_mctl->sync);
-
v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
VIDIOC_MSM_ISPIF_RELEASE, NULL);
@@ -585,20 +588,16 @@
VIDIOC_MSM_CSIPHY_RELEASE, NULL);
if (p_mctl->sync.actctrl.a_power_down)
- p_mctl->sync.actctrl.a_power_down(sync->sdata->actuator_info);
+ p_mctl->sync.actctrl.a_power_down(
+ p_mctl->sync.sdata->actuator_info);
- if (p_mctl->sync.sctrl.s_release)
- p_mctl->sync.sctrl.s_release();
-
- rc = msm_camio_sensor_clk_off(sync->pdev);
- if (rc < 0)
- pr_err("%s: msm_camio_sensor_clk_off failed:%d\n",
- __func__, rc);
+ v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
pm_qos_update_request(&p_mctl->pm_qos_req_list,
PM_QOS_DEFAULT_VALUE);
pm_qos_remove_request(&p_mctl->pm_qos_req_list);
+ wake_unlock(&p_mctl->sync.wake_lock);
return rc;
}
@@ -679,7 +678,6 @@
pmctl->mctl_cmd = msm_mctl_cmd;
pmctl->mctl_notify = msm_mctl_notify;
pmctl->mctl_release = msm_mctl_release;
- pmctl->plat_dev = pcam->pdev;
/* init mctl buf */
msm_mctl_buf_init(pcam);
memset(&pmctl->pp_info, 0, sizeof(pmctl->pp_info));
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 77f963c..6a2c8aa 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -149,6 +149,8 @@
msm_mctl_gettimeofday(&div.frame.timestamp);
vb->vidbuf.v4l2_buf.timestamp = div.frame.timestamp;
div.do_pp = pp_type;
+ D("%s Diverting frame %x id %d to userspace ", __func__,
+ (int)div.frame.handle, div.frame.frame_id);
/* Get the cookie for 1st plane and store the path.
* Also use this to check the number of planes in
* this buffer.*/
@@ -187,7 +189,8 @@
}
if (!pp_type)
p_mctl->pp_info.div_frame[pcam_inst->image_mode].
- ch_paddr[0] = div.frame.mp[0].phy_addr;
+ ch_paddr[0] = div.frame.mp[0].phy_addr +
+ div.frame.mp[0].data_offset;
}
rc = msm_mctl_pp_buf_divert(p_mctl, pcam_inst, &div);
return rc;
@@ -823,6 +826,8 @@
rc = -EFAULT;
goto err;
}
+ D("%s Returning frame %x id %d to kernel ", __func__,
+ (int)frame.handle, frame.frame_id);
if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) {
memcpy(&buf,
&p_mctl->pp_info.div_frame[image_mode],
@@ -836,9 +841,10 @@
}
} else {
if (frame.num_planes > 1)
- buf.ch_paddr[0] = frame.mp[0].phy_addr;
+ buf.ch_paddr[0] = frame.mp[0].phy_addr +
+ frame.mp[0].data_offset;
else
- buf.ch_paddr[0] = frame.sp.phy_addr;
+ buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off;
}
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
/* here buf.addr is phy_addr */
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index d34d5b1..b04f07c 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -444,10 +444,11 @@
static int vfe32_config_axi(int mode, uint32_t *ao)
{
- int32_t *ch_info;
+ uint32_t *ch_info;
+ uint32_t *axi_cfg = ao+V32_AXI_BUS_FMT_OFF;
/* Update the corresponding write masters for each output*/
- ch_info = ao + V32_AXI_CFG_LEN;
+ ch_info = axi_cfg + V32_AXI_CFG_LEN;
vfe32_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
vfe32_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
vfe32_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
@@ -517,9 +518,12 @@
default:
break;
}
+ msm_io_w(*ao, vfe32_ctrl->vfebase +
+ VFE_BUS_IO_FORMAT_CFG);
msm_io_memcpy(vfe32_ctrl->vfebase +
- vfe32_cmd[VFE_CMD_AXI_OUT_CFG].offset, ao,
- vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length - V32_AXI_CH_INF_LEN);
+ vfe32_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+ vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length - V32_AXI_CH_INF_LEN
+ - V32_AXI_BUS_FMT_LEN);
return 0;
}
@@ -727,7 +731,9 @@
static int vfe32_start_recording(void)
{
- msm_camio_set_perf_lvl(S_VIDEO);
+ struct msm_sync *sync = vfe_syncdata;
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_VIDEO);
vfe32_ctrl->recording_state = VFE_REC_STATE_START_REQUESTED;
msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
return 0;
@@ -735,9 +741,11 @@
static int vfe32_stop_recording(void)
{
+ struct msm_sync *sync = vfe_syncdata;
vfe32_ctrl->recording_state = VFE_REC_STATE_STOP_REQUESTED;
msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- msm_camio_set_perf_lvl(S_PREVIEW);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
return 0;
}
@@ -749,6 +757,7 @@
static int vfe32_zsl(void)
{
+ struct msm_sync *sync = vfe_syncdata;
uint32_t irq_comp_mask = 0;
/* capture command is valid for both idle and active state. */
irq_comp_mask =
@@ -807,7 +816,8 @@
}
msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
vfe32_start_common();
- msm_camio_set_perf_lvl(S_ZSL);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_ZSL);
msm_io_w(1, vfe32_ctrl->vfebase + 0x18C);
msm_io_w(1, vfe32_ctrl->vfebase + 0x188);
@@ -861,13 +871,12 @@
(0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8));
msm_io_w(1, vfe32_ctrl->vfebase +
vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_io_w(0x1000, vfe32_ctrl->vfebase +
- VFE_BUS_IO_FORMAT_CFG);
}
}
msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
- msm_camio_set_perf_lvl(S_CAPTURE);
+ msm_camio_bus_scale_cfg(
+ p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
vfe32_start_common();
msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
/* for debug */
@@ -879,6 +888,7 @@
static int vfe32_start(void)
{
uint32_t irq_comp_mask = 0;
+ struct msm_sync *sync = vfe_syncdata;
/* start command now is only good for continuous mode. */
if ((vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_CONTINUOUS) &&
(vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_VIDEO))
@@ -918,7 +928,8 @@
msm_io_w(1, vfe32_ctrl->vfebase +
vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]);
}
- msm_camio_set_perf_lvl(S_PREVIEW);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
vfe32_start_common();
return 0;
}
@@ -3681,6 +3692,7 @@
struct platform_device *pdev)
{
int rc = 0;
+ struct msm_sync *sync = data;
v4l2_set_subdev_hostdata(sd, data);
vfe_syncdata = data;
@@ -3733,8 +3745,10 @@
if (rc < 0)
goto vfe_clk_enable_failed;
- msm_camio_set_perf_lvl(S_INIT);
- msm_camio_set_perf_lvl(S_PREVIEW);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_INIT);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
if (msm_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
VFE32_HW_NUMBER)
@@ -3757,6 +3771,7 @@
void msm_vfe_subdev_release(struct platform_device *pdev)
{
+ struct msm_sync *sync = vfe_syncdata;
msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info,
vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
if (vfe32_ctrl->fs_vfe) {
@@ -3772,7 +3787,8 @@
if (atomic_read(&irq_cnt))
pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
- msm_camio_set_perf_lvl(S_EXIT);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_EXIT);
vfe_syncdata = NULL;
}
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index ecb8608..ff42c28 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -226,9 +226,11 @@
#define V32_OPERATION_CFG_LEN 32
#define V32_AXI_OUT_OFF 0x00000038
-#define V32_AXI_OUT_LEN 212
+#define V32_AXI_OUT_LEN 216
#define V32_AXI_CH_INF_LEN 24
#define V32_AXI_CFG_LEN 47
+#define V32_AXI_BUS_FMT_OFF 1
+#define V32_AXI_BUS_FMT_LEN 4
#define V32_FRAME_SKIP_OFF 0x00000504
#define V32_FRAME_SKIP_LEN 32
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index f721441..c77cfc3 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -211,23 +211,8 @@
.vert_offset = 3,
};
-static int imx074_sensor_config(void __user *argp)
-{
- return msm_sensor_config(&imx074_s_ctrl, argp);
-}
-
static struct sensor_calib_data imx074_calib_data;
-static int imx074_sensor_open_init(const struct msm_camera_sensor_info *data)
-{
- return msm_sensor_open_init(&imx074_s_ctrl, data);
-}
-
-static int imx074_sensor_release(void)
-{
- return msm_sensor_release(&imx074_s_ctrl);
-}
-
static const struct i2c_device_id imx074_i2c_id[] = {
{SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl},
{ }
@@ -276,31 +261,16 @@
.data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
};
-static int imx074_sensor_v4l2_probe(const struct msm_camera_sensor_info *info,
- struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
-{
- return msm_sensor_v4l2_probe(&imx074_s_ctrl, info, sdev, s);
-}
-
-static int imx074_probe(struct platform_device *pdev)
-{
- return msm_sensor_register(pdev, imx074_sensor_v4l2_probe);
-}
-
-struct platform_driver imx074_driver = {
- .probe = imx074_probe,
- .driver = {
- .name = PLATFORM_DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
static int __init msm_sensor_init_module(void)
{
- return platform_driver_register(&imx074_driver);
+ return i2c_add_driver(&imx074_i2c_driver);
}
-static struct v4l2_subdev_core_ops imx074_subdev_core_ops;
+static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
+};
+
static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
};
@@ -322,12 +292,9 @@
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
- .sensor_config = imx074_sensor_config,
- .sensor_open_init = imx074_sensor_open_init,
- .sensor_release = imx074_sensor_release,
+ .sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_probe = msm_sensor_probe,
};
static struct msm_sensor_reg_t imx074_regs = {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index e67f9cd..d31de14 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -177,7 +177,7 @@
{
int32_t rc = 0;
- v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
PIX0, ISPIF_OFF_IMMEDIATELY));
s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
@@ -190,23 +190,23 @@
msm_sensor_write_res_settings(s_ctrl, res);
if (s_ctrl->curr_csi_params != s_ctrl->csi_params[res]) {
s_ctrl->curr_csi_params = s_ctrl->csi_params[res];
- v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_CSID_CFG,
&s_ctrl->curr_csi_params->csid_params);
- v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_CID_CHANGE, NULL);
mb();
- v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_CSIPHY_CFG,
&s_ctrl->curr_csi_params->csiphy_params);
mb();
msleep(20);
}
- v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_PCLK_CHANGE, &s_ctrl->msm_sensor_reg->
output_settings[res].op_pixel_clk);
- v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
PIX0, ISPIF_ON_FRAME_BOUNDARY));
s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
@@ -269,6 +269,19 @@
return rc;
}
+long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+ void __user *argp = (void __user *)arg;
+ switch (cmd) {
+ case VIDIOC_MSM_SENSOR_CFG:
+ return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp)
{
struct sensor_cfg_data cdata;
@@ -396,10 +409,12 @@
return rc;
}
-int32_t msm_sensor_power_up(const struct msm_camera_sensor_info *data)
+int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
+ struct msm_camera_sensor_info *data = s_ctrl->sensordata;
CDBG("%s: %d\n", __func__, __LINE__);
+ msm_sensor_probe_on(&s_ctrl->sensor_i2c_client->client->dev);
msm_camio_clk_rate_set(MSM_SENSOR_MCLK_24HZ);
rc = gpio_request(data->sensor_platform_info->sensor_reset,
"SENSOR_NAME");
@@ -417,9 +432,11 @@
return rc;
}
-int32_t msm_sensor_power_down(const struct msm_camera_sensor_info *data)
+int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
{
+ struct msm_camera_sensor_info *data = s_ctrl->sensordata;
CDBG("%s\n", __func__);
+ msm_sensor_probe_off(&s_ctrl->sensor_i2c_client->client->dev);
gpio_set_value_cansleep(data->sensor_platform_info->sensor_reset, 0);
usleep_range(1000, 2000);
gpio_free(data->sensor_platform_info->sensor_reset);
@@ -448,64 +465,37 @@
return rc;
}
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct msm_sensor_ctrl_t, sensor_v4l2_subdev);
+}
+
int32_t msm_sensor_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
- struct msm_sensor_ctrl_t *this_ctrl;
+ struct msm_sensor_ctrl_t *s_ctrl;
CDBG("%s_i2c_probe called\n", client->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
CDBG("i2c_check_functionality failed\n");
rc = -EFAULT;
- goto probe_failure;
+ return rc;
}
- this_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
- if (this_ctrl->sensor_i2c_client != NULL) {
- this_ctrl->sensor_i2c_client->client = client;
- if (this_ctrl->sensor_i2c_addr != 0)
- this_ctrl->sensor_i2c_client->client->addr =
- this_ctrl->sensor_i2c_addr;
+ s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+ if (s_ctrl->sensor_i2c_client != NULL) {
+ s_ctrl->sensor_i2c_client->client = client;
+ if (s_ctrl->sensor_i2c_addr != 0)
+ s_ctrl->sensor_i2c_client->client->addr =
+ s_ctrl->sensor_i2c_addr;
} else {
rc = -EFAULT;
+ return rc;
}
-probe_failure:
- CDBG("%s_i2c_probe failed\n", client->name);
- return rc;
-}
+ s_ctrl->sensordata = client->dev.platform_data;
-int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl)
-{
- mutex_lock(s_ctrl->msm_sensor_mutex);
- s_ctrl->func_tbl->sensor_power_down(s_ctrl->sensordata);
- mutex_unlock(s_ctrl->msm_sensor_mutex);
- CDBG("%s completed\n", __func__);
- return 0;
-}
-
-int32_t msm_sensor_open_init(struct msm_sensor_ctrl_t *s_ctrl,
- const struct msm_camera_sensor_info *data)
-{
- if (data)
- s_ctrl->sensordata = data;
-
- return s_ctrl->func_tbl->sensor_power_up(data);
-}
-
-int32_t msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl,
- const struct msm_camera_sensor_info *info,
- struct msm_sensor_ctrl *s)
-{
- int rc = 0;
- rc = i2c_add_driver(s_ctrl->sensor_i2c_driver);
- if (rc < 0 || s_ctrl->sensor_i2c_client->client == NULL) {
- rc = -ENOTSUPP;
- CDBG("I2C add driver failed");
- goto probe_fail;
- }
-
- rc = s_ctrl->func_tbl->sensor_power_up(info);
+ rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0)
goto probe_fail;
@@ -532,45 +522,38 @@
}
}
- s->s_init = s_ctrl->func_tbl->sensor_open_init;
- s->s_release = s_ctrl->func_tbl->sensor_release;
- s->s_config = s_ctrl->func_tbl->sensor_config;
- s->s_camera_type = info->camera_type;
- if (info->sensor_platform_info != NULL)
- s->s_mount_angle = info->sensor_platform_info->mount_angle;
- else
- s->s_mount_angle = 0;
+ snprintf(s_ctrl->sensor_v4l2_subdev.name,
+ sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
+ v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
+ s_ctrl->sensor_v4l2_subdev_ops);
+ msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
goto power_down;
probe_fail:
- i2c_del_driver(s_ctrl->sensor_i2c_driver);
+ CDBG("%s_i2c_probe failed\n", client->name);
power_down:
- s_ctrl->func_tbl->sensor_power_down(info);
+ s_ctrl->func_tbl->sensor_power_down(s_ctrl);
return rc;
}
-int32_t msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl,
- const struct msm_camera_sensor_info *info,
- struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
+int32_t msm_sensor_power(struct v4l2_subdev *sd, int on)
{
- int32_t rc = 0;
- rc = s_ctrl->func_tbl->sensor_probe(s_ctrl, info, s);
- if (rc < 0)
- return rc;
-
- s_ctrl->sensor_v4l2_subdev = sdev;
- v4l2_i2c_subdev_init(s_ctrl->sensor_v4l2_subdev,
- s_ctrl->sensor_i2c_client->client,
- s_ctrl->sensor_v4l2_subdev_ops);
- s_ctrl->sensor_v4l2_subdev->dev_priv = (void *) s_ctrl;
+ int rc = 0;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+ mutex_lock(s_ctrl->msm_sensor_mutex);
+ if (on)
+ rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+ else
+ rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
}
int32_t msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- struct msm_sensor_ctrl_t *s_ctrl =
- (struct msm_sensor_ctrl_t *) sd->dev_priv;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+
if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size)
return -EINVAL;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index f1a15b2..e06f628 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -10,6 +10,9 @@
* GNU General Public License for more details.
*/
+#ifndef MSM_SENSOR_H
+#define MSM_SENSOR_H
+
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -22,7 +25,6 @@
#include <mach/gpio.h>
#include <media/msm_camera.h>
#include <media/v4l2-subdev.h>
-#include "msm.h"
#include "msm_camera_i2c.h"
#include "msm_camera_eeprom.h"
#define Q8 0x00000100
@@ -124,19 +126,14 @@
int, struct sensor_init_cfg *);
int32_t (*sensor_get_output_info) (struct msm_sensor_ctrl_t *,
struct sensor_output_info_t *);
- int (*sensor_config) (void __user *);
- int (*sensor_open_init) (const struct msm_camera_sensor_info *);
- int (*sensor_release) (void);
+ int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
int (*sensor_power_down)
- (const struct msm_camera_sensor_info *);
- int (*sensor_power_up) (const struct msm_camera_sensor_info *);
- int (*sensor_probe) (struct msm_sensor_ctrl_t *s_ctrl,
- const struct msm_camera_sensor_info *info,
- struct msm_sensor_ctrl *s);
+ (struct msm_sensor_ctrl_t *);
+ int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
};
struct msm_sensor_ctrl_t {
- const struct msm_camera_sensor_info *sensordata;
+ struct msm_camera_sensor_info *sensordata;
struct i2c_client *msm_sensor_client;
struct i2c_driver *sensor_i2c_driver;
struct msm_camera_i2c_client *sensor_i2c_client;
@@ -162,7 +159,7 @@
struct msm_camera_csi2_params *curr_csi_params;
struct msm_camera_csi2_params **csi_params;
- struct v4l2_subdev *sensor_v4l2_subdev;
+ struct v4l2_subdev sensor_v4l2_subdev;
struct v4l2_subdev_info *sensor_v4l2_subdev_info;
uint8_t sensor_v4l2_subdev_info_size;
struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
@@ -188,22 +185,13 @@
struct sensor_output_info_t *);
int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
void __user *argp);
-int32_t msm_sensor_power_up(const struct msm_camera_sensor_info *data);
-int32_t msm_sensor_power_down(const struct msm_camera_sensor_info *data);
+int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
+int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl);
int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl);
int msm_sensor_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id);
-int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl);
-int32_t msm_sensor_open_init(struct msm_sensor_ctrl_t *s_ctrl,
- const struct msm_camera_sensor_info *data);
-int msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl,
- const struct msm_camera_sensor_info *info,
- struct msm_sensor_ctrl *s);
-
-int msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl,
- const struct msm_camera_sensor_info *info,
- struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s);
+int32_t msm_sensor_power(struct v4l2_subdev *sd, int on);
int32_t msm_sensor_v4l2_s_ctrl(struct v4l2_subdev *sd,
struct v4l2_control *ctrl);
@@ -231,3 +219,13 @@
int update_type, int res);
int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
+
+long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg);
+
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
+
+#define VIDIOC_MSM_SENSOR_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
+
+#endif
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index fc45705..a1e56f7 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1221,21 +1221,6 @@
.sensor_id = 0x2481,
};
-static int mt9m114_sensor_config(void __user *argp)
-{
- return msm_sensor_config(&mt9m114_s_ctrl, argp);
-}
-
-static int mt9m114_sensor_open_init(const struct msm_camera_sensor_info *data)
-{
- return msm_sensor_open_init(&mt9m114_s_ctrl, data);
-}
-
-static int mt9m114_sensor_release(void)
-{
- return msm_sensor_release(&mt9m114_s_ctrl);
-}
-
static const struct i2c_device_id mt9m114_i2c_id[] = {
{SENSOR_NAME, (kernel_ulong_t)&mt9m114_s_ctrl},
{ }
@@ -1253,33 +1238,16 @@
.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
};
-static int mt9m114_sensor_v4l2_probe(const struct msm_camera_sensor_info *info,
- struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
-{
- return msm_sensor_v4l2_probe(&mt9m114_s_ctrl, info, sdev, s);
-}
-
-static int mt9m114_probe(struct platform_device *pdev)
-{
- return msm_sensor_register(pdev, mt9m114_sensor_v4l2_probe);
-}
-
-struct platform_driver mt9m114_driver = {
- .probe = mt9m114_probe,
- .driver = {
- .name = PLATFORM_DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
static int __init msm_sensor_init_module(void)
{
- return platform_driver_register(&mt9m114_driver);
+ return i2c_add_driver(&mt9m114_i2c_driver);
}
static struct v4l2_subdev_core_ops mt9m114_subdev_core_ops = {
.s_ctrl = msm_sensor_v4l2_s_ctrl,
.queryctrl = msm_sensor_v4l2_query_ctrl,
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
};
static struct v4l2_subdev_video_ops mt9m114_subdev_video_ops = {
@@ -1298,12 +1266,9 @@
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
- .sensor_config = mt9m114_sensor_config,
- .sensor_open_init = mt9m114_sensor_open_init,
- .sensor_release = mt9m114_sensor_release,
+ .sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_probe = msm_sensor_probe,
};
static struct msm_sensor_reg_t mt9m114_regs = {
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 5938406..6389498 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -406,21 +406,6 @@
return 0;
}
-static int ov2720_sensor_config(void __user *argp)
-{
- return msm_sensor_config(&ov2720_s_ctrl, argp);
-}
-
-static int ov2720_sensor_open_init(const struct msm_camera_sensor_info *data)
-{
- return msm_sensor_open_init(&ov2720_s_ctrl, data);
-}
-
-static int ov2720_sensor_release(void)
-{
- return msm_sensor_release(&ov2720_s_ctrl);
-}
-
static const struct i2c_device_id ov2720_i2c_id[] = {
{SENSOR_NAME, (kernel_ulong_t)&ov2720_s_ctrl},
{ }
@@ -438,31 +423,16 @@
.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
};
-static int ov2720_sensor_v4l2_probe(const struct msm_camera_sensor_info *info,
- struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
-{
- return msm_sensor_v4l2_probe(&ov2720_s_ctrl, info, sdev, s);
-}
-
-static int ov2720_probe(struct platform_device *pdev)
-{
- return msm_sensor_register(pdev, ov2720_sensor_v4l2_probe);
-}
-
-struct platform_driver ov2720_driver = {
- .probe = ov2720_probe,
- .driver = {
- .name = PLATFORM_DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
static int __init msm_sensor_init_module(void)
{
- return platform_driver_register(&ov2720_driver);
+ return i2c_add_driver(&ov2720_i2c_driver);
}
-static struct v4l2_subdev_core_ops ov2720_subdev_core_ops;
+static struct v4l2_subdev_core_ops ov2720_subdev_core_ops = {
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
+};
+
static struct v4l2_subdev_video_ops ov2720_subdev_video_ops = {
.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
};
@@ -484,12 +454,9 @@
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
- .sensor_config = ov2720_sensor_config,
- .sensor_open_init = ov2720_sensor_open_init,
- .sensor_release = ov2720_sensor_release,
+ .sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_probe = msm_sensor_probe,
};
static struct msm_sensor_reg_t ov2720_regs = {
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 9e9bb23..77ac845 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -158,7 +158,6 @@
depends on MSM_SSBI
select MFD_CORE
select MFD_PM8XXX
- select MSM_SHOW_RESUME_IRQ
help
Say yes here for Qualcomm PM8058 chip.
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index 8d89568..fc85a42 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -16,11 +16,13 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/err.h>
#include <linux/msm_ssbi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8018.h>
#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
#include <linux/leds-pm8xxx.h>
@@ -53,10 +55,11 @@
}
struct pm8018 {
- struct device *dev;
- struct pm_irq_chip *irq_chip;
- struct mfd_cell *mfd_regulators;
- u32 rev_registers;
+ struct device *dev;
+ struct pm_irq_chip *irq_chip;
+ struct mfd_cell *mfd_regulators;
+ struct pm8xxx_regulator_core_platform_data *regulator_cdata;
+ u32 rev_registers;
};
static int pm8018_readb(const struct device *dev, u16 addr, u8 *val)
@@ -227,14 +230,136 @@
.id = -1,
};
+static struct pm8xxx_vreg regulator_data[] = {
+ /* name pc_name ctrl test hpm_min */
+ PLDO("8018_l2", "8018_l2_pc", 0x0B0, 0x0B1, LDO_50),
+ PLDO("8018_l3", "8018_l3_pc", 0x0B2, 0x0B3, LDO_50),
+ PLDO("8018_l4", "8018_l4_pc", 0x0B4, 0x0B5, LDO_300),
+ PLDO("8018_l5", "8018_l5_pc", 0x0B6, 0x0B7, LDO_150),
+ PLDO("8018_l6", "8018_l6_pc", 0x0B8, 0x0B9, LDO_150),
+ PLDO("8018_l7", "8018_l7_pc", 0x0BA, 0x0BB, LDO_300),
+ NLDO("8018_l8", "8018_l8_pc", 0x0BC, 0x0BD, LDO_150),
+ NLDO1200("8018_l9", 0x0BE, 0x0BF, LDO_1200),
+ NLDO1200("8018_l10", 0x0C0, 0x0C1, LDO_1200),
+ NLDO1200("8018_l11", 0x0C2, 0x0C3, LDO_1200),
+ NLDO1200("8018_l12", 0x0C4, 0x0C5, LDO_1200),
+ PLDO("8018_l13", "8018_l13_pc", 0x0C8, 0x0C9, LDO_50),
+ PLDO("8018_l14", "8018_l14_pc", 0x0CA, 0x0CB, LDO_50),
+
+ /* name pc_name ctrl test2 clk sleep hpm_min */
+ SMPS("8018_s1", "8018_s1_pc", 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
+ SMPS("8018_s2", "8018_s2_pc", 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
+ SMPS("8018_s3", "8018_s3_pc", 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
+ SMPS("8018_s4", "8018_s4_pc", 0x1E8, 0x1ED, 0x00C, 0x1EA, SMPS_1500),
+ SMPS("8018_s5", "8018_s5_pc", 0x1F0, 0x1F5, 0x00D, 0x1F2, SMPS_1500),
+
+ /* name pc_name ctrl */
+ VS("8018_lvs1", "8018_lvs1_pc", 0x060),
+};
+
+#define MAX_NAME_COMPARISON_LEN 32
+
+static int __devinit match_regulator(
+ struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+{
+ int found = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
+ if (regulator_data[i].rdesc.name
+ && strncmp(regulator_data[i].rdesc.name, name,
+ MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = false;
+ core_data->vreg = ®ulator_data[i];
+ found = 1;
+ break;
+ } else if (regulator_data[i].rdesc_pc.name
+ && strncmp(regulator_data[i].rdesc_pc.name, name,
+ MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = true;
+ core_data->vreg = ®ulator_data[i];
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ pr_err("could not find a match for regulator: %s\n", name);
+
+ return found;
+}
+
+static int __devinit
+pm8018_add_regulators(const struct pm8018_platform_data *pdata,
+ struct pm8018 *pmic, int irq_base)
+{
+ int ret = 0;
+ struct mfd_cell *mfd_regulators;
+ struct pm8xxx_regulator_core_platform_data *cdata;
+ int i;
+
+ /* Add one device for each regulator used by the board. */
+ mfd_regulators = kzalloc(sizeof(struct mfd_cell)
+ * (pdata->num_regulators), GFP_KERNEL);
+ if (!mfd_regulators) {
+ pr_err("Cannot allocate %d bytes for pm8018 regulator "
+ "mfd cells\n", sizeof(struct mfd_cell)
+ * (pdata->num_regulators));
+ return -ENOMEM;
+ }
+ cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
+ * pdata->num_regulators, GFP_KERNEL);
+ if (!cdata) {
+ pr_err("Cannot allocate %d bytes for pm8018 regulator "
+ "core data\n", pdata->num_regulators
+ * sizeof(struct pm8xxx_regulator_core_platform_data));
+ kfree(mfd_regulators);
+ return -ENOMEM;
+ }
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_init(®ulator_data[i].pc_lock);
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
+ pr_err("name missing for regulator %d\n", i);
+ ret = -EINVAL;
+ goto bail;
+ }
+ if (!match_regulator(&cdata[i],
+ pdata->regulator_pdatas[i].init_data.constraints.name)) {
+ ret = -ENODEV;
+ goto bail;
+ }
+ cdata[i].pdata = &(pdata->regulator_pdatas[i]);
+ mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
+ mfd_regulators[i].id = cdata[i].pdata->id;
+ mfd_regulators[i].platform_data = &cdata[i];
+ mfd_regulators[i].pdata_size =
+ sizeof(struct pm8xxx_regulator_core_platform_data);
+ }
+ ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
+ pdata->num_regulators, NULL, irq_base);
+ if (ret)
+ goto bail;
+
+ pmic->mfd_regulators = mfd_regulators;
+ pmic->regulator_cdata = cdata;
+ return ret;
+
+bail:
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_destroy(®ulator_data[i].pc_lock);
+ kfree(mfd_regulators);
+ kfree(cdata);
+ return ret;
+}
+
static int __devinit
pm8018_add_subdevices(const struct pm8018_platform_data *pdata,
struct pm8018 *pmic)
{
int ret = 0, irq_base = 0;
struct pm_irq_chip *irq_chip;
- static struct mfd_cell *mfd_regulators;
- int i;
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8018_NR_IRQS;
@@ -341,36 +466,16 @@
goto bail;
}
- /* Add one device for each regulator used by the board. */
if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
- mfd_regulators = kzalloc(sizeof(struct mfd_cell)
- * (pdata->num_regulators), GFP_KERNEL);
- if (!mfd_regulators) {
- pr_err("Cannot allocate %d bytes for pm8018 regulator "
- "mfd cells\n", sizeof(struct mfd_cell)
- * (pdata->num_regulators));
- ret = -ENOMEM;
- goto bail;
- }
- for (i = 0; i < pdata->num_regulators; i++) {
- mfd_regulators[i].name = PM8018_REGULATOR_DEV_NAME;
- mfd_regulators[i].id = pdata->regulator_pdatas[i].id;
- mfd_regulators[i].platform_data =
- &(pdata->regulator_pdatas[i]);
- mfd_regulators[i].pdata_size =
- sizeof(struct pm8018_regulator_platform_data);
- }
- ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
- pdata->num_regulators, NULL, irq_base);
+ ret = pm8018_add_regulators(pdata, pmic, irq_base);
if (ret) {
pr_err("Failed to add regulator subdevices ret=%d\n",
ret);
- kfree(mfd_regulators);
goto bail;
}
- pmic->mfd_regulators = mfd_regulators;
}
+
return 0;
bail:
if (pmic->irq_chip) {
@@ -475,6 +580,8 @@
err:
mfd_remove_devices(pmic->dev);
platform_set_drvdata(pdev, NULL);
+ kfree(pmic->mfd_regulators);
+ kfree(pmic->regulator_cdata);
err_read_rev:
kfree(pmic);
return rc;
@@ -484,19 +591,27 @@
{
struct pm8xxx_drvdata *drvdata;
struct pm8018 *pmic = NULL;
+ int i;
drvdata = platform_get_drvdata(pdev);
if (drvdata)
pmic = drvdata->pm_chip_data;
- if (pmic)
- mfd_remove_devices(pmic->dev);
- if (pmic->irq_chip) {
- pm8xxx_irq_exit(pmic->irq_chip);
- pmic->irq_chip = NULL;
+ if (pmic) {
+ if (pmic->dev)
+ mfd_remove_devices(pmic->dev);
+ if (pmic->irq_chip) {
+ pm8xxx_irq_exit(pmic->irq_chip);
+ pmic->irq_chip = NULL;
+ }
+ if (pmic->mfd_regulators) {
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_destroy(®ulator_data[i].pc_lock);
+ }
+ kfree(pmic->mfd_regulators);
+ kfree(pmic->regulator_cdata);
+ kfree(pmic);
}
platform_set_drvdata(pdev, NULL);
- kfree(pmic->mfd_regulators);
- kfree(pmic);
return 0;
}
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index 9123067..f433456 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -17,10 +17,12 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/string.h>
#include <linux/msm_ssbi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8038.h>
#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
#define REG_HWREV 0x002 /* PMIC4 revision */
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
@@ -45,9 +47,11 @@
}
struct pm8038 {
- struct device *dev;
- struct pm_irq_chip *irq_chip;
- u32 rev_registers;
+ struct device *dev;
+ struct pm_irq_chip *irq_chip;
+ struct mfd_cell *mfd_regulators;
+ struct pm8xxx_regulator_core_platform_data *regulator_cdata;
+ u32 rev_registers;
};
static int pm8038_readb(const struct device *dev, u16 addr, u8 *val)
@@ -200,6 +204,145 @@
.pdata_size = sizeof("pm8038-dbg"),
};
+static struct pm8xxx_vreg regulator_data[] = {
+ /* name pc_name ctrl test hpm_min */
+ NLDO1200("8038_l1", 0x0AE, 0x0AF, LDO_1200),
+ NLDO("8038_l2", "8038_l2_pc", 0x0B0, 0x0B1, LDO_150),
+ PLDO("8038_l3", "8038_l3_pc", 0x0B2, 0x0B3, LDO_50),
+ PLDO("8038_l4", "8038_l4_pc", 0x0B4, 0x0B5, LDO_50),
+ PLDO("8038_l5", "8038_l5_pc", 0x0B6, 0x0B7, LDO_600),
+ PLDO("8038_l6", "8038_l6_pc", 0x0B8, 0x0B9, LDO_600),
+ PLDO("8038_l7", "8038_l7_pc", 0x0BA, 0x0BB, LDO_600),
+ PLDO("8038_l8", "8038_l8_pc", 0x0BC, 0x0BD, LDO_300),
+ PLDO("8038_l9", "8038_l9_pc", 0x0BE, 0x0BF, LDO_300),
+ PLDO("8038_l10", "8038_l10_pc", 0x0C0, 0x0C1, LDO_600),
+ PLDO("8038_l11", "8038_l11_pc", 0x0C2, 0x0C3, LDO_600),
+ NLDO("8038_l12", "8038_l12_pc", 0x0C4, 0x0C5, LDO_300),
+ PLDO("8038_l14", "8038_l14_pc", 0x0C8, 0x0C9, LDO_50),
+ PLDO("8038_l15", "8038_l15_pc", 0x0CA, 0x0CB, LDO_150),
+ NLDO1200("8038_l16", 0x0CC, 0x0CD, LDO_1200),
+ PLDO("8038_l17", "8038_l17_pc", 0x0CE, 0x0CF, LDO_150),
+ PLDO("8038_l18", "8038_l18_pc", 0x0D0, 0x0D1, LDO_50),
+ NLDO1200("8038_l19", 0x0D2, 0x0D3, LDO_1200),
+ NLDO1200("8038_l20", 0x0D4, 0x0D5, LDO_1200),
+ PLDO("8038_l21", "8038_l21_pc", 0x0D6, 0x0D7, LDO_150),
+ PLDO("8038_l22", "8038_l22_pc", 0x0D8, 0x0D9, LDO_50),
+ PLDO("8038_l23", "8038_l23_pc", 0x0DA, 0x0DB, LDO_50),
+ NLDO1200("8038_l24", 0x0DC, 0x0DD, LDO_1200),
+ NLDO("8038_l26", "8038_l26_pc", 0x0E0, 0x0E1, LDO_150),
+ NLDO1200("8038_l27", 0x0E2, 0x0E3, LDO_1200),
+
+ /* name pc_name ctrl test2 clk sleep hpm_min */
+ SMPS("8038_s1", "8038_s1_pc", 0x1E0, 0x1E5, 0x009, 0x1E2, SMPS_1500),
+ SMPS("8038_s2", "8038_s2_pc", 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
+ SMPS("8038_s3", "8038_s3_pc", 0x1D0, 0x1D5, 0x00B, 0x1D2, SMPS_1500),
+ SMPS("8038_s4", "8038_s4_pc", 0x1E8, 0x1ED, 0x00C, 0x1EA, SMPS_1500),
+
+ /* name ctrl fts_cnfg1 pfm pwr_cnfg hpm_min */
+ FTSMPS("8038_s5", 0x025, 0x02E, 0x026, 0x032, SMPS_2000),
+ FTSMPS("8038_s6", 0x036, 0x03F, 0x037, 0x043, SMPS_2000),
+
+ /* name pc_name ctrl */
+ VS("8038_lvs1", "8038_lvs1_pc", 0x060),
+ VS("8038_lvs2", "8038_lvs2_pc", 0x062),
+};
+
+#define MAX_NAME_COMPARISON_LEN 32
+
+static int __devinit match_regulator(
+ struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+{
+ int found = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
+ if (regulator_data[i].rdesc.name
+ && strncmp(regulator_data[i].rdesc.name, name,
+ MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = false;
+ core_data->vreg = ®ulator_data[i];
+ found = 1;
+ break;
+ } else if (regulator_data[i].rdesc_pc.name
+ && strncmp(regulator_data[i].rdesc_pc.name, name,
+ MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = true;
+ core_data->vreg = ®ulator_data[i];
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ pr_err("could not find a match for regulator: %s\n", name);
+
+ return found;
+}
+
+static int __devinit
+pm8038_add_regulators(const struct pm8038_platform_data *pdata,
+ struct pm8038 *pmic, int irq_base)
+{
+ int ret = 0;
+ struct mfd_cell *mfd_regulators;
+ struct pm8xxx_regulator_core_platform_data *cdata;
+ int i;
+
+ /* Add one device for each regulator used by the board. */
+ mfd_regulators = kzalloc(sizeof(struct mfd_cell)
+ * (pdata->num_regulators), GFP_KERNEL);
+ if (!mfd_regulators) {
+ pr_err("Cannot allocate %d bytes for pm8038 regulator "
+ "mfd cells\n", sizeof(struct mfd_cell)
+ * (pdata->num_regulators));
+ return -ENOMEM;
+ }
+ cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
+ * pdata->num_regulators, GFP_KERNEL);
+ if (!cdata) {
+ pr_err("Cannot allocate %d bytes for pm8038 regulator "
+ "core data\n", pdata->num_regulators
+ * sizeof(struct pm8xxx_regulator_core_platform_data));
+ kfree(mfd_regulators);
+ return -ENOMEM;
+ }
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_init(®ulator_data[i].pc_lock);
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
+ pr_err("name missing for regulator %d\n", i);
+ ret = -EINVAL;
+ goto bail;
+ }
+ if (!match_regulator(&cdata[i],
+ pdata->regulator_pdatas[i].init_data.constraints.name)) {
+ ret = -ENODEV;
+ goto bail;
+ }
+ cdata[i].pdata = &(pdata->regulator_pdatas[i]);
+ mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
+ mfd_regulators[i].id = cdata[i].pdata->id;
+ mfd_regulators[i].platform_data = &cdata[i];
+ mfd_regulators[i].pdata_size =
+ sizeof(struct pm8xxx_regulator_core_platform_data);
+ }
+ ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
+ pdata->num_regulators, NULL, irq_base);
+ if (ret)
+ goto bail;
+
+ pmic->mfd_regulators = mfd_regulators;
+ pmic->regulator_cdata = cdata;
+ return ret;
+
+bail:
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_destroy(®ulator_data[i].pc_lock);
+ kfree(mfd_regulators);
+ kfree(cdata);
+ return ret;
+}
static int __devinit
pm8038_add_subdevices(const struct pm8038_platform_data *pdata,
@@ -287,6 +430,15 @@
}
}
+ if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
+ ret = pm8038_add_regulators(pdata, pmic, irq_base);
+ if (ret) {
+ pr_err("Failed to add regulator subdevices ret=%d\n",
+ ret);
+ goto bail;
+ }
+ }
+
ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
if (ret) {
pr_err("Failed to add debugfs subdevice ret=%d\n", ret);
@@ -395,6 +547,8 @@
err:
mfd_remove_devices(pmic->dev);
platform_set_drvdata(pdev, NULL);
+ kfree(pmic->mfd_regulators);
+ kfree(pmic->regulator_cdata);
err_read_rev:
kfree(pmic);
return rc;
@@ -404,6 +558,7 @@
{
struct pm8xxx_drvdata *drvdata;
struct pm8038 *pmic = NULL;
+ int i;
drvdata = platform_get_drvdata(pdev);
@@ -418,7 +573,12 @@
pm8xxx_irq_exit(pmic->irq_chip);
pmic->irq_chip = NULL;
}
-
+ if (pmic->mfd_regulators) {
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_destroy(®ulator_data[i].pc_lock);
+ }
+ kfree(pmic->mfd_regulators);
+ kfree(pmic->regulator_cdata);
kfree(pmic);
}
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 373aaf7..3c4686f 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -16,11 +16,13 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/err.h>
#include <linux/msm_ssbi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
#include <linux/leds-pm8xxx.h>
#define REG_HWREV 0x002 /* PMIC4 revision */
@@ -55,10 +57,11 @@
}
struct pm8921 {
- struct device *dev;
- struct pm_irq_chip *irq_chip;
- struct mfd_cell *mfd_regulators;
- u32 rev_registers;
+ struct device *dev;
+ struct pm_irq_chip *irq_chip;
+ struct mfd_cell *mfd_regulators;
+ struct pm8xxx_regulator_core_platform_data *regulator_cdata;
+ u32 rev_registers;
};
static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
@@ -363,15 +366,168 @@
.id = -1,
};
+static struct pm8xxx_vreg regulator_data[] = {
+ /* name pc_name ctrl test hpm_min */
+ NLDO("8921_l1", "8921_l1_pc", 0x0AE, 0x0AF, LDO_150),
+ NLDO("8921_l2", "8921_l2_pc", 0x0B0, 0x0B1, LDO_150),
+ PLDO("8921_l3", "8921_l3_pc", 0x0B2, 0x0B3, LDO_150),
+ PLDO("8921_l4", "8921_l4_pc", 0x0B4, 0x0B5, LDO_50),
+ PLDO("8921_l5", "8921_l5_pc", 0x0B6, 0x0B7, LDO_300),
+ PLDO("8921_l6", "8921_l6_pc", 0x0B8, 0x0B9, LDO_600),
+ PLDO("8921_l7", "8921_l7_pc", 0x0BA, 0x0BB, LDO_150),
+ PLDO("8921_l8", "8921_l8_pc", 0x0BC, 0x0BD, LDO_300),
+ PLDO("8921_l9", "8921_l9_pc", 0x0BE, 0x0BF, LDO_300),
+ PLDO("8921_l10", "8921_l10_pc", 0x0C0, 0x0C1, LDO_600),
+ PLDO("8921_l11", "8921_l11_pc", 0x0C2, 0x0C3, LDO_150),
+ NLDO("8921_l12", "8921_l12_pc", 0x0C4, 0x0C5, LDO_150),
+ PLDO("8921_l14", "8921_l14_pc", 0x0C8, 0x0C9, LDO_50),
+ PLDO("8921_l15", "8921_l15_pc", 0x0CA, 0x0CB, LDO_150),
+ PLDO("8921_l16", "8921_l16_pc", 0x0CC, 0x0CD, LDO_300),
+ PLDO("8921_l17", "8921_l17_pc", 0x0CE, 0x0CF, LDO_150),
+ NLDO("8921_l18", "8921_l18_pc", 0x0D0, 0x0D1, LDO_150),
+ PLDO("8921_l21", "8921_l21_pc", 0x0D6, 0x0D7, LDO_150),
+ PLDO("8921_l22", "8921_l22_pc", 0x0D8, 0x0D9, LDO_150),
+ PLDO("8921_l23", "8921_l23_pc", 0x0DA, 0x0DB, LDO_150),
+ NLDO1200("8921_l24", 0x0DC, 0x0DD, LDO_1200),
+ NLDO1200("8921_l25", 0x0DE, 0x0DF, LDO_1200),
+ NLDO1200("8921_l26", 0x0E0, 0x0E1, LDO_1200),
+ NLDO1200("8921_l27", 0x0E2, 0x0E3, LDO_1200),
+ NLDO1200("8921_l28", 0x0E4, 0x0E5, LDO_1200),
+ PLDO("8921_l29", "8921_l29_pc", 0x0E6, 0x0E7, LDO_150),
+
+ /* name pc_name ctrl test2 clk sleep hpm_min */
+ SMPS("8921_s1", "8921_s1_pc", 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
+ SMPS("8921_s2", "8921_s2_pc", 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
+ SMPS("8921_s3", "8921_s3_pc", 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
+ SMPS("8921_s4", "8921_s4_pc", 0x1E8, 0x1ED, 0x011, 0x1EA, SMPS_1500),
+
+ /* name ctrl fts_cnfg1 pfm pwr_cnfg hpm_min */
+ FTSMPS("8921_s5", 0x025, 0x02E, 0x026, 0x032, SMPS_2000),
+ FTSMPS("8921_s6", 0x036, 0x03F, 0x037, 0x043, SMPS_2000),
+
+ /* name pc_name ctrl test2 clk sleep hpm_min */
+ SMPS("8921_s7", "8921_s7_pc", 0x1F0, 0x1F5, 0x012, 0x1F2, SMPS_1500),
+ SMPS("8921_s8", "8921_s8_pc", 0x1F8, 0x1FD, 0x013, 0x1FA, SMPS_1500),
+
+ /* name pc_name ctrl */
+ VS("8921_lvs1", "8921_lvs1_pc", 0x060),
+ VS300("8921_lvs2", 0x062),
+ VS("8921_lvs3", "8921_lvs3_pc", 0x064),
+ VS("8921_lvs4", "8921_lvs4_pc", 0x066),
+ VS("8921_lvs5", "8921_lvs5_pc", 0x068),
+ VS("8921_lvs6", "8921_lvs6_pc", 0x06A),
+ VS("8921_lvs7", "8921_lvs7_pc", 0x06C),
+ VS300("8921_usb_otg", 0x06E),
+ VS300("8921_hdmi_mvs", 0x070),
+
+ /* name ctrl */
+ NCP("8921_ncp", 0x090),
+};
+
+#define MAX_NAME_COMPARISON_LEN 32
+
+static int __devinit match_regulator(
+ struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+{
+ int found = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
+ if (regulator_data[i].rdesc.name
+ && strncmp(regulator_data[i].rdesc.name, name,
+ MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = false;
+ core_data->vreg = ®ulator_data[i];
+ found = 1;
+ break;
+ } else if (regulator_data[i].rdesc_pc.name
+ && strncmp(regulator_data[i].rdesc_pc.name, name,
+ MAX_NAME_COMPARISON_LEN) == 0) {
+ core_data->is_pin_controlled = true;
+ core_data->vreg = ®ulator_data[i];
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ pr_err("could not find a match for regulator: %s\n", name);
+
+ return found;
+}
+
+static int __devinit
+pm8921_add_regulators(const struct pm8921_platform_data *pdata,
+ struct pm8921 *pmic, int irq_base)
+{
+ int ret = 0;
+ struct mfd_cell *mfd_regulators;
+ struct pm8xxx_regulator_core_platform_data *cdata;
+ int i;
+
+ /* Add one device for each regulator used by the board. */
+ mfd_regulators = kzalloc(sizeof(struct mfd_cell)
+ * (pdata->num_regulators), GFP_KERNEL);
+ if (!mfd_regulators) {
+ pr_err("Cannot allocate %d bytes for pm8921 regulator "
+ "mfd cells\n", sizeof(struct mfd_cell)
+ * (pdata->num_regulators));
+ return -ENOMEM;
+ }
+ cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
+ * pdata->num_regulators, GFP_KERNEL);
+ if (!cdata) {
+ pr_err("Cannot allocate %d bytes for pm8921 regulator "
+ "core data\n", pdata->num_regulators
+ * sizeof(struct pm8xxx_regulator_core_platform_data));
+ kfree(mfd_regulators);
+ return -ENOMEM;
+ }
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_init(®ulator_data[i].pc_lock);
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
+ pr_err("name missing for regulator %d\n", i);
+ ret = -EINVAL;
+ goto bail;
+ }
+ if (!match_regulator(&cdata[i],
+ pdata->regulator_pdatas[i].init_data.constraints.name)) {
+ ret = -ENODEV;
+ goto bail;
+ }
+ cdata[i].pdata = &(pdata->regulator_pdatas[i]);
+ mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
+ mfd_regulators[i].id = cdata[i].pdata->id;
+ mfd_regulators[i].platform_data = &cdata[i];
+ mfd_regulators[i].pdata_size =
+ sizeof(struct pm8xxx_regulator_core_platform_data);
+ }
+ ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
+ pdata->num_regulators, NULL, irq_base);
+ if (ret)
+ goto bail;
+
+ pmic->mfd_regulators = mfd_regulators;
+ pmic->regulator_cdata = cdata;
+ return ret;
+
+bail:
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_destroy(®ulator_data[i].pc_lock);
+ kfree(mfd_regulators);
+ kfree(cdata);
+ return ret;
+}
+
static int __devinit
pm8921_add_subdevices(const struct pm8921_platform_data *pdata,
struct pm8921 *pmic)
{
int ret = 0, irq_base = 0;
struct pm_irq_chip *irq_chip;
- static struct mfd_cell *mfd_regulators;
enum pm8xxx_version version;
- int i;
version = pm8xxx_get_version(pmic->dev);
@@ -495,34 +651,13 @@
}
}
- /* Add one device for each regulator used by the board. */
if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
- mfd_regulators = kzalloc(sizeof(struct mfd_cell)
- * (pdata->num_regulators), GFP_KERNEL);
- if (!mfd_regulators) {
- pr_err("Cannot allocate %d bytes for pm8921 regulator "
- "mfd cells\n", sizeof(struct mfd_cell)
- * (pdata->num_regulators));
- ret = -ENOMEM;
- goto bail;
- }
- for (i = 0; i < pdata->num_regulators; i++) {
- mfd_regulators[i].name = PM8921_REGULATOR_DEV_NAME;
- mfd_regulators[i].id = pdata->regulator_pdatas[i].id;
- mfd_regulators[i].platform_data =
- &(pdata->regulator_pdatas[i]);
- mfd_regulators[i].pdata_size =
- sizeof(struct pm8921_regulator_platform_data);
- }
- ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
- pdata->num_regulators, NULL, irq_base);
+ ret = pm8921_add_regulators(pdata, pmic, irq_base);
if (ret) {
pr_err("Failed to add regulator subdevices ret=%d\n",
ret);
- kfree(mfd_regulators);
goto bail;
}
- pmic->mfd_regulators = mfd_regulators;
}
ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
@@ -725,6 +860,8 @@
err:
mfd_remove_devices(pmic->dev);
platform_set_drvdata(pdev, NULL);
+ kfree(pmic->mfd_regulators);
+ kfree(pmic->regulator_cdata);
err_read_rev:
kfree(pmic);
return rc;
@@ -734,6 +871,7 @@
{
struct pm8xxx_drvdata *drvdata;
struct pm8921 *pmic = NULL;
+ int i;
drvdata = platform_get_drvdata(pdev);
if (drvdata)
@@ -743,7 +881,12 @@
mfd_remove_devices(pmic->dev);
if (pmic->irq_chip)
pm8xxx_irq_exit(pmic->irq_chip);
+ if (pmic->mfd_regulators) {
+ for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+ mutex_destroy(®ulator_data[i].pc_lock);
+ }
kfree(pmic->mfd_regulators);
+ kfree(pmic->regulator_cdata);
kfree(pmic);
}
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index 7c56dd6..814b59c 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -73,119 +73,8 @@
struct mfd_cell *mfd_regulators, *mfd_xo_buffers;
u8 revision;
-
- struct mutex pm_lock;
};
-static struct pm8058_chip *pmic_chip;
-
-static inline int
-ssbi_read(struct device *dev, u16 addr, u8 *buf, size_t len)
-{
- return msm_ssbi_read(dev->parent, addr, buf, len);
-}
-
-static inline int
-ssbi_write(struct device *dev, u16 addr, u8 *buf, size_t len)
-{
- return msm_ssbi_write(dev->parent, addr, buf, len);
-}
-
-/**
- * pm8058_stay_on - enables stay_on feature
- *
- * PMIC stay-on feature allows PMIC to ignore MSM PS_HOLD=low
- * signal so that some special functions like debugging could be
- * performed.
- *
- * This feature should not be used in any product release.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_stay_on(void)
-{
- u8 ctrl = 0x92;
- int rc;
-
- rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_GP_TEST_1, &ctrl, 1);
- pr_info("%s: set stay-on: rc = %d\n", __func__, rc);
- return rc;
-}
-EXPORT_SYMBOL(pm8058_stay_on);
-
-/*
- power on hard reset configuration
- config = DISABLE_HARD_RESET to disable hard reset
- = SHUTDOWN_ON_HARD_RESET to turn off the system on hard reset
- = RESTART_ON_HARD_RESET to restart the system on hard reset
- */
-int pm8058_hard_reset_config(enum pon_config config)
-{
- int rc, ret;
- u8 pon, pon_5;
-
- if (config >= MAX_PON_CONFIG)
- return -EINVAL;
-
- if (pmic_chip == NULL)
- return -ENODEV;
-
- mutex_lock(&pmic_chip->pm_lock);
-
- rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
- __func__, SSBI_REG_ADDR_PON_CNTL_5, rc);
- mutex_unlock(&pmic_chip->pm_lock);
- return rc;
- }
-
- pon_5 = pon;
- (config != DISABLE_HARD_RESET) ? (pon |= PM8058_HARD_RESET_EN_MASK) :
- (pon &= ~PM8058_HARD_RESET_EN_MASK);
-
- rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
- __func__, SSBI_REG_ADDR_PON_CNTL_5, pon, rc);
- mutex_unlock(&pmic_chip->pm_lock);
- return rc;
- }
-
- if (config == DISABLE_HARD_RESET) {
- mutex_unlock(&pmic_chip->pm_lock);
- return 0;
- }
-
- rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_4, &pon, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
- __func__, SSBI_REG_ADDR_PON_CNTL_4, rc);
- goto err_restore_pon_5;
- }
-
- (config == RESTART_ON_HARD_RESET) ? (pon |= PM8058_PON_RESET_EN_MASK) :
- (pon &= ~PM8058_PON_RESET_EN_MASK);
-
- rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_4, &pon, 1);
- if (rc) {
- pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
- __func__, SSBI_REG_ADDR_PON_CNTL_4, pon, rc);
- goto err_restore_pon_5;
- }
- mutex_unlock(&pmic_chip->pm_lock);
- return 0;
-
-err_restore_pon_5:
- ret = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon_5, 1);
- if (ret)
- pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
- __func__, SSBI_REG_ADDR_PON_CNTL_5, pon, ret);
- mutex_unlock(&pmic_chip->pm_lock);
- return rc;
-}
-EXPORT_SYMBOL(pm8058_hard_reset_config);
-
static int pm8058_readb(const struct device *dev, u16 addr, u8 *val)
{
const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
@@ -823,9 +712,6 @@
pm8058_drvdata.pm_chip_data = pmic;
platform_set_drvdata(pdev, &pm8058_drvdata);
- mutex_init(&pmic->pm_lock);
- pmic_chip = pmic;
-
/* Read PMIC chip revision */
rc = pm8058_readb(pmic->dev, PM8058_REG_REV, &pmic->revision);
if (rc)
@@ -843,7 +729,7 @@
goto err;
}
- rc = pm8058_hard_reset_config(SHUTDOWN_ON_HARD_RESET);
+ rc = pm8xxx_hard_reset_config(PM8XXX_SHUTDOWN_ON_HARD_RESET);
if (rc < 0)
pr_err("%s: failed to config shutdown on hard reset: %d\n",
__func__, rc);
@@ -870,7 +756,6 @@
mfd_remove_devices(pmic->dev);
if (pmic->irq_chip)
pm8xxx_irq_exit(pmic->irq_chip);
- mutex_destroy(&pmic->pm_lock);
kfree(pmic->mfd_regulators);
kfree(pmic);
}
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
index aabc2cc..4b81e99 100644
--- a/drivers/mfd/wcd9310-core.c
+++ b/drivers/mfd/wcd9310-core.c
@@ -27,6 +27,7 @@
#define TABLA_SLIM_GLA_MAX_RETRIES 5
#define TABLA_REGISTER_START_OFFSET 0x800
+#define TABLA_SLIM_RW_MAX_TRIES 3
#define MAX_TABLA_DEVICE 4
#define TABLA_I2C_MODE 0x03
@@ -183,21 +184,25 @@
{
int ret;
struct slim_ele_access msg;
+ int slim_read_tries = TABLA_SLIM_RW_MAX_TRIES;
msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
msg.num_bytes = bytes;
msg.comp = NULL;
- mutex_lock(&tabla->xfer_lock);
- if (interface)
- ret = slim_request_val_element(tabla->slim_slave, &msg, dest,
- bytes);
- else
- ret = slim_request_val_element(tabla->slim, &msg, dest, bytes);
+ while (1) {
+ mutex_lock(&tabla->xfer_lock);
+ ret = slim_request_val_element(interface ?
+ tabla->slim_slave : tabla->slim,
+ &msg, dest, bytes);
+ mutex_unlock(&tabla->xfer_lock);
+ if (likely(ret == 0) || (--slim_read_tries == 0))
+ break;
+ usleep_range(5000, 5000);
+ }
if (ret)
- pr_err("%s: Error, Tabla read failed\n", __func__);
+ pr_err("%s: Error, Tabla read failed (%d)\n", __func__, ret);
- mutex_unlock(&tabla->xfer_lock);
return ret;
}
/* Interface specifies whether the write is to the interface or general
@@ -208,20 +213,25 @@
{
int ret;
struct slim_ele_access msg;
+ int slim_write_tries = TABLA_SLIM_RW_MAX_TRIES;
msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
msg.num_bytes = bytes;
msg.comp = NULL;
- mutex_lock(&tabla->xfer_lock);
- if (interface)
- ret = slim_change_val_element(tabla->slim_slave, &msg, src,
- bytes);
- else
- ret = slim_change_val_element(tabla->slim, &msg, src, bytes);
- if (ret)
- pr_err("%s: Error, Tabla write failed\n", __func__);
+ while (1) {
+ mutex_lock(&tabla->xfer_lock);
+ ret = slim_change_val_element(interface ?
+ tabla->slim_slave : tabla->slim,
+ &msg, src, bytes);
+ mutex_unlock(&tabla->xfer_lock);
+ if (likely(ret == 0) || (--slim_write_tries == 0))
+ break;
+ usleep_range(5000, 5000);
+ }
- mutex_unlock(&tabla->xfer_lock);
+ if (ret)
+ pr_err("%s: Error, Tabla write failed (%d)\n", __func__, ret);
+
return ret;
}
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
index 9cc4761..fef1323 100644
--- a/drivers/mfd/wcd9310-irq.c
+++ b/drivers/mfd/wcd9310-irq.c
@@ -189,17 +189,37 @@
ret = request_threaded_irq(tabla->irq, NULL, tabla_irq_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"tabla", tabla);
-
- if (ret != 0) {
+ if (ret != 0)
dev_err(tabla->dev, "Failed to request IRQ %d: %d\n",
tabla->irq, ret);
- return ret;
+ else {
+ ret = enable_irq_wake(tabla->irq);
+ if (ret == 0) {
+ ret = device_init_wakeup(tabla->dev, 1);
+ if (ret) {
+ dev_err(tabla->dev, "Failed to init device"
+ "wakeup : %d\n", ret);
+ disable_irq_wake(tabla->irq);
+ }
+ } else
+ dev_err(tabla->dev, "Failed to set wake interrupt on"
+ " IRQ %d: %d\n", tabla->irq, ret);
+ if (ret)
+ free_irq(tabla->irq, tabla);
}
- return 0;
+
+ if (ret)
+ mutex_destroy(&tabla->irq_lock);
+
+ return ret;
}
+
void tabla_irq_exit(struct tabla *tabla)
{
- if (tabla->irq)
+ if (tabla->irq) {
+ disable_irq_wake(tabla->irq);
free_irq(tabla->irq, tabla);
+ device_init_wakeup(tabla->dev, 0);
+ }
mutex_destroy(&tabla->irq_lock);
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0c579e2..43eb169 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -561,6 +561,14 @@
---help---
This turns on debugging information for the tsif driver
+config TSPP
+ depends on ARCH_MSM
+ tristate "TSPP (Transport Stream Packet Processor) Support"
+ ---help---
+ Transport Stream Packet Processor is used to offload the
+ processing of MPEG transport streams from the main processor.
+ This can also be compiled as a loadable module.
+
config HAPTIC_ISA1200
tristate "ISA1200 haptic support"
depends on I2C
@@ -578,14 +586,6 @@
purposes including software controlled brightness of backlight,
motor control, and waveform generation.
-config PMIC8058_VIBRATOR
- tristate "Qualcomm PM8058 vibrator support"
- depends on PMIC8058 && ANDROID_TIMED_OUTPUT
- default n
- help
- This option enables device driver support for the vibrator
- on Qualcomm PM8058 chip.
-
config PMIC8XXX_VIBRATOR
tristate "Qualcomm Vibrator support for PMIC8XXX"
depends on MFD_PM8XXX && ANDROID_TIMED_OUTPUT
@@ -619,23 +619,6 @@
PMIC8058. Driver interface to program registers of the ADC over
AMUX channels, devices on programmable MPP's and xotherm.
-config PMIC8058_MISC
- tristate "Qualcomm PM8058 Misc Device driver"
- depends on PMIC8058
- default n
- help
- Provides functionality for various small drivers utilizing the
- Qualcomm PM8058 chip. Examples include: signalling when the 32kHz
- oscillator malfunctions.
-
-config PMIC8058_BATTALARM
- tristate "Qualcomm PM8058 Battery Alarm Device driver"
- depends on PMIC8058
- help
- This option enables support for the battery alarm module on the
- Qualcomm PM8058 PMIC chip. This support allows for configuration of
- the alarm module as well as interrupt handling.
-
config TZCOM
tristate "Trustzone Communicator driver"
default n
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 385f8ff..6b5fdcc 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,16 +54,14 @@
obj-$(CONFIG_TSIF) += msm_tsif.o
msm_tsif-objs := tsif.o
obj-$(CONFIG_TSIF_CHRDEV) += tsif_chrdev.o
+obj-$(CONFIG_TSPP) += tspp.o
obj-$(CONFIG_HAPTIC_ISA1200) += isa1200.o
obj-$(CONFIG_PMIC8058_PWM) += pmic8058-pwm.o
-obj-$(CONFIG_PMIC8058_VIBRATOR) += pmic8058-vibrator.o
obj-$(CONFIG_PMIC8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_PMIC8XXX_NFC) += pm8xxx-nfc.o
obj-$(CONFIG_PMIC8XXX_UPL) += pm8xxx-upl.o
obj-$(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN) \
+= msm_migrate_pages.o
obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
-obj-$(CONFIG_PMIC8058_MISC) += pmic8058-misc.o
-obj-$(CONFIG_PMIC8058_BATTALARM) += pmic8058-batt-alarm.o
obj-$(CONFIG_TZCOM) += tzcom.o
obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
index 692849a..7ee7c11 100644
--- a/drivers/misc/pmem.c
+++ b/drivers/misc/pmem.c
@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/file.h>
+#include <linux/fmem.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <linux/debugfs.h>
@@ -229,12 +230,12 @@
* request function for a region when the allocation count goes
* from 0 -> 1
*/
- void (*mem_request)(void *);
+ int (*mem_request)(void *);
/*
* release function for a region when the allocation count goes
* from 1 -> 0
*/
- void (*mem_release)(void *);
+ int (*mem_release)(void *);
/*
* private data for the request/release callback
*/
@@ -243,6 +244,10 @@
* map and unmap as needed
*/
int map_on_demand;
+ /*
+ * memory will be reused through fmem
+ */
+ int reusable;
};
#define to_pmem_info_id(a) (container_of(a, struct pmem_info, kobj)->id)
@@ -582,8 +587,13 @@
atomic_inc(&pmem[id].allocation_cnt);
if (!pmem[id].vbase) {
DLOG("PMEMDEBUG: mapping for %s", pmem[id].name);
- if (pmem[id].mem_request)
- pmem[id].mem_request(pmem[id].region_data);
+ if (pmem[id].mem_request) {
+ int ret = pmem[id].mem_request(pmem[id].region_data);
+ if (ret) {
+ atomic_dec(&pmem[id].allocation_cnt);
+ return 1;
+ }
+ }
ioremap_pmem(id);
}
@@ -610,8 +620,11 @@
unmap_kernel_range((unsigned long)pmem[id].vbase,
pmem[id].size);
pmem[id].vbase = NULL;
- if (pmem[id].mem_release)
- pmem[id].mem_release(pmem[id].region_data);
+ if (pmem[id].mem_release) {
+ int ret = pmem[id].mem_release(
+ pmem[id].region_data);
+ WARN(ret, "mem_release failed");
+ }
}
}
@@ -2785,19 +2798,26 @@
pr_info("allocating %lu bytes at %p (%lx physical) for %s\n",
pmem[id].size, pmem[id].vbase, pmem[id].base, pmem[id].name);
- pmem[id].map_on_demand = pdata->map_on_demand;
+ pmem[id].reusable = pdata->reusable;
+ /* reusable pmem requires map on demand */
+ pmem[id].map_on_demand = pdata->map_on_demand || pdata->reusable;
if (pmem[id].map_on_demand) {
- pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
- if (!pmem_vma) {
- pr_err("pmem: Failed to allocate virtual space for "
+ if (pmem[id].reusable) {
+ const struct fmem_data *fmem_info = fmem_get_info();
+ pmem[id].area = fmem_info->area;
+ } else {
+ pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
+ if (!pmem_vma) {
+ pr_err("pmem: Failed to allocate virtual space for "
"%s\n", pdata->name);
- goto out_put_kobj;
- }
- pr_err("pmem: Reserving virtual address range %lx - %lx for"
+ goto out_put_kobj;
+ }
+ pr_err("pmem: Reserving virtual address range %lx - %lx for"
" %s\n", (unsigned long) pmem_vma->addr,
(unsigned long) pmem_vma->addr + pmem[id].size,
pdata->name);
- pmem[id].area = pmem_vma;
+ pmem[id].area = pmem_vma;
+ }
} else
pmem[id].area = NULL;
diff --git a/drivers/misc/pmic8058-batt-alarm.c b/drivers/misc/pmic8058-batt-alarm.c
deleted file mode 100644
index bff0720..0000000
--- a/drivers/misc/pmic8058-batt-alarm.c
+++ /dev/null
@@ -1,753 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-/*
- * Qualcomm PMIC 8058 Battery Alarm Device driver
- *
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/pmic8058-batt-alarm.h>
-#include <linux/mfd/pmic8058.h>
-
-/* PMIC 8058 Battery Alarm SSBI registers */
-#define REG_THRESHOLD 0x023
-#define REG_CTRL1 0x024
-#define REG_CTRL2 0x0AA
-#define REG_PWM_CTRL 0x0A3
-
-/* Available voltage threshold values */
-#define THRESHOLD_MIN_MV 2500
-#define THRESHOLD_MAX_MV 5675
-#define THRESHOLD_STEP_MV 25
-
-/* Register bit definitions */
-
-/* Threshold register */
-#define THRESHOLD_UPPER_MASK 0xF0
-#define THRESHOLD_LOWER_MASK 0x0F
-#define THRESHOLD_UPPER_SHIFT 4
-#define THRESHOLD_LOWER_SHIFT 0
-
-/* CTRL 1 register */
-#define CTRL1_BATT_ALARM_EN_MASK 0x80
-#define CTRL1_HOLD_TIME_MASK 0x70
-#define CTRL1_STATUS_UPPER_MASK 0x02
-#define CTRL1_STATUS_LOWER_MASK 0x01
-#define CTRL1_HOLD_TIME_SHIFT 4
-#define CTRL1_HOLD_TIME_MIN 0
-#define CTRL1_HOLD_TIME_MAX 7
-
-/* CTRL 2 register */
-#define CTRL2_COMP_UPPER_DISABLE_MASK 0x80
-#define CTRL2_COMP_LOWER_DISABLE_MASK 0x40
-#define CTRL2_FINE_STEP_UPPER_MASK 0x30
-#define CTRL2_RANGE_EXT_UPPER_MASK 0x08
-#define CTRL2_FINE_STEP_LOWER_MASK 0x06
-#define CTRL2_RANGE_EXT_LOWER_MASK 0x01
-#define CTRL2_FINE_STEP_UPPER_SHIFT 4
-#define CTRL2_FINE_STEP_LOWER_SHIFT 1
-
-/* PWM control register */
-#define PWM_CTRL_ALARM_EN_MASK 0xC0
-#define PWM_CTRL_ALARM_EN_NEVER 0x00
-#define PWM_CTRL_ALARM_EN_TCXO 0x40
-#define PWM_CTRL_ALARM_EN_PWM 0x80
-#define PWM_CTRL_ALARM_EN_ALWAYS 0xC0
-#define PWM_CTRL_PRE_MASK 0x38
-#define PWM_CTRL_DIV_MASK 0x07
-#define PWM_CTRL_PRE_SHIFT 3
-#define PWM_CTRL_DIV_SHIFT 0
-#define PWM_CTRL_PRE_MIN 0
-#define PWM_CTRL_PRE_MAX 7
-#define PWM_CTRL_DIV_MIN 1
-#define PWM_CTRL_DIV_MAX 7
-
-/* PWM control input range */
-#define PWM_CTRL_PRE_INPUT_MIN 2
-#define PWM_CTRL_PRE_INPUT_MAX 9
-#define PWM_CTRL_DIV_INPUT_MIN 2
-#define PWM_CTRL_DIV_INPUT_MAX 8
-
-/* Available voltage threshold values */
-#define THRESHOLD_BASIC_MIN_MV 2800
-#define THRESHOLD_EXT_MIN_MV 4400
-
-/*
- * Default values used during initialization:
- * Slowest PWM rate to ensure minimal status jittering when crossing thresholds.
- * Largest hold time also helps reduce status value jittering. Comparators
- * are disabled by default and must be turned on by calling
- * pm8058_batt_alarm_state_set.
- */
-#define DEFAULT_THRESHOLD_LOWER 3200
-#define DEFAULT_THRESHOLD_UPPER 4300
-#define DEFAULT_HOLD_TIME PM8058_BATT_ALARM_HOLD_TIME_16_MS
-#define DEFAULT_USE_PWM 1
-#define DEFAULT_PWM_SCALER 9
-#define DEFAULT_PWM_DIVIDER 8
-#define DEFAULT_LOWER_ENABLE 0
-#define DEFAULT_UPPER_ENABLE 0
-
-struct pm8058_batt_alarm_device {
- struct srcu_notifier_head irq_notifier_list;
- struct pm8058_chip *pm_chip;
- struct mutex batt_mutex;
- unsigned int irq;
- int notifier_count;
- u8 reg_threshold;
- u8 reg_ctrl1;
- u8 reg_ctrl2;
- u8 reg_pwm_ctrl;
-};
-static struct pm8058_batt_alarm_device *the_battalarm;
-
-static int pm8058_reg_write(struct pm8058_chip *chip, u16 addr, u8 val, u8 mask,
- u8 *reg_save)
-{
- int rc = 0;
- u8 reg;
-
- reg = (*reg_save & ~mask) | (val & mask);
- if (reg != *reg_save)
- rc = pm8058_write(chip, addr, ®, 1);
- if (rc)
- pr_err("pm8058_write failed; addr=%03X, rc=%d\n", addr, rc);
- else
- *reg_save = reg;
- return rc;
-}
-
-/**
- * pm8058_batt_alarm_state_set - enable or disable the threshold comparators
- * @enable_lower_comparator: 1 = enable comparator, 0 = disable comparator
- * @enable_upper_comparator: 1 = enable comparator, 0 = disable comparator
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_state_set(int enable_lower_comparator,
- int enable_upper_comparator)
-{
- struct pm8058_batt_alarm_device *battdev = the_battalarm;
- int rc;
- u8 reg_ctrl1 = 0, reg_ctrl2 = 0;
-
- if (!battdev) {
- pr_err("no battery alarm device found.\n");
- return -ENXIO;
- }
-
- if (!enable_lower_comparator)
- reg_ctrl2 |= CTRL2_COMP_LOWER_DISABLE_MASK;
- if (!enable_upper_comparator)
- reg_ctrl2 |= CTRL2_COMP_UPPER_DISABLE_MASK;
-
- if (enable_lower_comparator || enable_upper_comparator)
- reg_ctrl1 = CTRL1_BATT_ALARM_EN_MASK;
-
- mutex_lock(&battdev->batt_mutex);
- rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL1, reg_ctrl1,
- CTRL1_BATT_ALARM_EN_MASK, &battdev->reg_ctrl1);
- if (rc)
- goto bail;
-
- rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL2, reg_ctrl2,
- CTRL2_COMP_LOWER_DISABLE_MASK | CTRL2_COMP_UPPER_DISABLE_MASK,
- &battdev->reg_ctrl2);
-
-bail:
- mutex_unlock(&battdev->batt_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_state_set);
-
-/**
- * pm8058_batt_alarm_threshold_set - set the lower and upper alarm thresholds
- * @lower_threshold_mV: battery undervoltage threshold in millivolts
- * @upper_threshold_mV: battery overvoltage threshold in millivolts
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_threshold_set(int lower_threshold_mV,
- int upper_threshold_mV)
-{
- struct pm8058_batt_alarm_device *battdev = the_battalarm;
- int step, fine_step, rc;
- u8 reg_threshold = 0, reg_ctrl2 = 0;
-
- if (!battdev) {
- pr_err("no battery alarm device found.\n");
- return -ENXIO;
- }
-
- if (lower_threshold_mV < THRESHOLD_MIN_MV
- || lower_threshold_mV > THRESHOLD_MAX_MV) {
- pr_err("lower threshold value, %d mV, is outside of allowable "
- "range: [%d, %d] mV\n", lower_threshold_mV,
- THRESHOLD_MIN_MV, THRESHOLD_MAX_MV);
- return -EINVAL;
- }
-
- if (upper_threshold_mV < THRESHOLD_MIN_MV
- || upper_threshold_mV > THRESHOLD_MAX_MV) {
- pr_err("upper threshold value, %d mV, is outside of allowable "
- "range: [%d, %d] mV\n", upper_threshold_mV,
- THRESHOLD_MIN_MV, THRESHOLD_MAX_MV);
- return -EINVAL;
- }
-
- if (upper_threshold_mV < lower_threshold_mV) {
- pr_err("lower threshold value, %d mV, must be <= upper "
- "threshold value, %d mV\n", lower_threshold_mV,
- upper_threshold_mV);
- return -EINVAL;
- }
-
- /* Determine register settings for lower threshold. */
- if (lower_threshold_mV < THRESHOLD_BASIC_MIN_MV) {
- /* Extended low range */
- reg_ctrl2 |= CTRL2_RANGE_EXT_LOWER_MASK;
-
- step = (lower_threshold_mV - THRESHOLD_MIN_MV)
- / THRESHOLD_STEP_MV;
-
- fine_step = step & 0x3;
- /* Extended low range is for steps 0 to 2 */
- step >>= 2;
-
- reg_threshold |= (step << THRESHOLD_LOWER_SHIFT)
- & THRESHOLD_LOWER_MASK;
- reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_LOWER_SHIFT)
- & CTRL2_FINE_STEP_LOWER_MASK;
- } else if (lower_threshold_mV >= THRESHOLD_EXT_MIN_MV) {
- /* Extended high range */
- reg_ctrl2 |= CTRL2_RANGE_EXT_LOWER_MASK;
-
- step = (lower_threshold_mV - THRESHOLD_EXT_MIN_MV)
- / THRESHOLD_STEP_MV;
-
- fine_step = step & 0x3;
- /* Extended high range is for steps 3 to 15 */
- step = (step >> 2) + 3;
-
- reg_threshold |= (step << THRESHOLD_LOWER_SHIFT)
- & THRESHOLD_LOWER_MASK;
- reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_LOWER_SHIFT)
- & CTRL2_FINE_STEP_LOWER_MASK;
- } else {
- /* Basic range */
- step = (lower_threshold_mV - THRESHOLD_BASIC_MIN_MV)
- / THRESHOLD_STEP_MV;
-
- fine_step = step & 0x3;
- step >>= 2;
-
- reg_threshold |= (step << THRESHOLD_LOWER_SHIFT)
- & THRESHOLD_LOWER_MASK;
- reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_LOWER_SHIFT)
- & CTRL2_FINE_STEP_LOWER_MASK;
- }
-
- /* Determine register settings for upper threshold. */
- if (upper_threshold_mV < THRESHOLD_BASIC_MIN_MV) {
- /* Extended low range */
- reg_ctrl2 |= CTRL2_RANGE_EXT_UPPER_MASK;
-
- step = (upper_threshold_mV - THRESHOLD_MIN_MV)
- / THRESHOLD_STEP_MV;
-
- fine_step = step & 0x3;
- /* Extended low range is for steps 0 to 2 */
- step >>= 2;
-
- reg_threshold |= (step << THRESHOLD_UPPER_SHIFT)
- & THRESHOLD_UPPER_MASK;
- reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_UPPER_SHIFT)
- & CTRL2_FINE_STEP_UPPER_MASK;
- } else if (upper_threshold_mV >= THRESHOLD_EXT_MIN_MV) {
- /* Extended high range */
- reg_ctrl2 |= CTRL2_RANGE_EXT_UPPER_MASK;
-
- step = (upper_threshold_mV - THRESHOLD_EXT_MIN_MV)
- / THRESHOLD_STEP_MV;
-
- fine_step = step & 0x3;
- /* Extended high range is for steps 3 to 15 */
- step = (step >> 2) + 3;
-
- reg_threshold |= (step << THRESHOLD_UPPER_SHIFT)
- & THRESHOLD_UPPER_MASK;
- reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_UPPER_SHIFT)
- & CTRL2_FINE_STEP_UPPER_MASK;
- } else {
- /* Basic range */
- step = (upper_threshold_mV - THRESHOLD_BASIC_MIN_MV)
- / THRESHOLD_STEP_MV;
-
- fine_step = step & 0x3;
- step >>= 2;
-
- reg_threshold |= (step << THRESHOLD_UPPER_SHIFT)
- & THRESHOLD_UPPER_MASK;
- reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_UPPER_SHIFT)
- & CTRL2_FINE_STEP_UPPER_MASK;
- }
-
- mutex_lock(&battdev->batt_mutex);
- rc = pm8058_reg_write(battdev->pm_chip, REG_THRESHOLD, reg_threshold,
- THRESHOLD_LOWER_MASK | THRESHOLD_UPPER_MASK,
- &battdev->reg_threshold);
- if (rc)
- goto bail;
-
- rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL2, reg_ctrl2,
- CTRL2_FINE_STEP_LOWER_MASK | CTRL2_FINE_STEP_UPPER_MASK
- | CTRL2_RANGE_EXT_LOWER_MASK | CTRL2_RANGE_EXT_UPPER_MASK,
- &battdev->reg_ctrl2);
-
-bail:
- mutex_unlock(&battdev->batt_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_threshold_set);
-
-/**
- * pm8058_batt_alarm_status_read - get status of both threshold comparators
- *
- * RETURNS: < 0 = error
- * 0 = battery voltage ok
- * BIT(0) set = battery voltage below lower threshold
- * BIT(1) set = battery voltage above upper threshold
- */
-int pm8058_batt_alarm_status_read(void)
-{
- struct pm8058_batt_alarm_device *battdev = the_battalarm;
- int status, rc;
-
- if (!battdev) {
- pr_err("no battery alarm device found.\n");
- return -ENXIO;
- }
-
- mutex_lock(&battdev->batt_mutex);
- rc = pm8058_read(battdev->pm_chip, REG_CTRL1, &battdev->reg_ctrl1, 1);
-
- status = ((battdev->reg_ctrl1 & CTRL1_STATUS_LOWER_MASK)
- ? PM8058_BATT_ALARM_STATUS_BELOW_LOWER : 0)
- | ((battdev->reg_ctrl1 & CTRL1_STATUS_UPPER_MASK)
- ? PM8058_BATT_ALARM_STATUS_ABOVE_UPPER : 0);
- mutex_unlock(&battdev->batt_mutex);
-
- if (rc) {
- pr_err("pm8058_read failed, rc=%d\n", rc);
- return rc;
- }
-
- return status;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_status_read);
-
-/**
- * pm8058_batt_alarm_hold_time_set - set hold time of interrupt output *
- * @hold_time: amount of time that battery voltage must remain outside of the
- * threshold range before the battery alarm interrupt triggers
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_hold_time_set(enum pm8058_batt_alarm_hold_time hold_time)
-{
- struct pm8058_batt_alarm_device *battdev = the_battalarm;
- int rc;
- u8 reg_ctrl1 = 0;
-
- if (!battdev) {
- pr_err("no battery alarm device found.\n");
- return -ENXIO;
- }
-
- if (hold_time < CTRL1_HOLD_TIME_MIN
- || hold_time > CTRL1_HOLD_TIME_MAX) {
-
- pr_err("hold time, %d, is outside of allowable range: "
- "[%d, %d]\n", hold_time, CTRL1_HOLD_TIME_MIN,
- CTRL1_HOLD_TIME_MAX);
- return -EINVAL;
- }
-
- reg_ctrl1 = hold_time << CTRL1_HOLD_TIME_SHIFT;
-
- mutex_lock(&battdev->batt_mutex);
- rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL1, reg_ctrl1,
- CTRL1_HOLD_TIME_MASK, &battdev->reg_ctrl1);
- mutex_unlock(&battdev->batt_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_hold_time_set);
-
-/**
- * pm8058_batt_alarm_pwm_rate_set - set battery alarm update rate *
- * @use_pwm: 1 = use PWM update rate, 0 = comparators always active
- * @clock_scaler: PWM clock scaler = 2 to 9
- * @clock_divider: PWM clock divider = 2 to 8
- *
- * This function sets the rate at which the battery alarm module enables
- * the threshold comparators. The rate is determined by the following equation:
- *
- * f_update = (1024 Hz) / (clock_divider * (2 ^ clock_scaler))
- *
- * Thus, the update rate can range from 0.25 Hz to 128 Hz.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_pwm_rate_set(int use_pwm, int clock_scaler,
- int clock_divider)
-{
- struct pm8058_batt_alarm_device *battdev = the_battalarm;
- int rc;
- u8 reg_pwm_ctrl = 0, mask = 0;
-
- if (!battdev) {
- pr_err("no battery alarm device found.\n");
- return -ENXIO;
- }
-
- if (use_pwm && (clock_scaler < PWM_CTRL_PRE_INPUT_MIN
- || clock_scaler > PWM_CTRL_PRE_INPUT_MAX)) {
- pr_err("PWM clock scaler, %d, is outside of allowable range: "
- "[%d, %d]\n", clock_scaler, PWM_CTRL_PRE_INPUT_MIN,
- PWM_CTRL_PRE_INPUT_MAX);
- return -EINVAL;
- }
-
- if (use_pwm && (clock_divider < PWM_CTRL_DIV_INPUT_MIN
- || clock_divider > PWM_CTRL_DIV_INPUT_MAX)) {
- pr_err("PWM clock divider, %d, is outside of allowable range: "
- "[%d, %d]\n", clock_divider, PWM_CTRL_DIV_INPUT_MIN,
- PWM_CTRL_DIV_INPUT_MAX);
- return -EINVAL;
- }
-
- if (!use_pwm) {
- /* Turn off PWM control and always enable. */
- reg_pwm_ctrl = PWM_CTRL_ALARM_EN_ALWAYS;
- mask = PWM_CTRL_ALARM_EN_MASK;
- } else {
- /* Use PWM control. */
- reg_pwm_ctrl = PWM_CTRL_ALARM_EN_PWM;
- mask = PWM_CTRL_ALARM_EN_MASK | PWM_CTRL_PRE_MASK
- | PWM_CTRL_DIV_MASK;
-
- clock_scaler -= PWM_CTRL_PRE_INPUT_MIN - PWM_CTRL_PRE_MIN;
- clock_divider -= PWM_CTRL_DIV_INPUT_MIN - PWM_CTRL_DIV_MIN;
-
- reg_pwm_ctrl |= (clock_scaler << PWM_CTRL_PRE_SHIFT)
- & PWM_CTRL_PRE_MASK;
- reg_pwm_ctrl |= (clock_divider << PWM_CTRL_DIV_SHIFT)
- & PWM_CTRL_DIV_MASK;
- }
-
- mutex_lock(&battdev->batt_mutex);
- rc = pm8058_reg_write(battdev->pm_chip, REG_PWM_CTRL, reg_pwm_ctrl,
- mask, &battdev->reg_pwm_ctrl);
- mutex_unlock(&battdev->batt_mutex);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_pwm_rate_set);
-
-/*
- * Handle the BATT_ALARM interrupt:
- * Battery voltage is above or below threshold range.
- */
-static irqreturn_t pm8058_batt_alarm_isr(int irq, void *data)
-{
- struct pm8058_batt_alarm_device *battdev = data;
- int status;
-
- if (battdev) {
- status = pm8058_batt_alarm_status_read();
-
- if (status < 0)
- pr_err("failed to read status, rc=%d\n", status);
- else
- srcu_notifier_call_chain(&battdev->irq_notifier_list,
- status, NULL);
- }
-
- return IRQ_HANDLED;
-}
-
-/**
- * pm8058_batt_alarm_register_notifier - register a notifier to run when a
- * battery voltage change interrupt fires
- * @nb: notifier block containing callback function to register
- *
- * nb->notifier_call must point to a function of this form -
- * int (*notifier_call)(struct notifier_block *nb, unsigned long status,
- * void *unused);
- * "status" will receive the battery alarm status; "unused" will be NULL.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_register_notifier(struct notifier_block *nb)
-{
- int rc;
-
- if (!the_battalarm) {
- pr_err("no battery alarm device found.\n");
- return -ENXIO;
- }
-
- rc = srcu_notifier_chain_register(&the_battalarm->irq_notifier_list,
- nb);
- mutex_lock(&the_battalarm->batt_mutex);
- if (rc == 0) {
- if (the_battalarm->notifier_count == 0) {
- /* request the irq */
- rc = request_threaded_irq(the_battalarm->irq, NULL,
- pm8058_batt_alarm_isr,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "pm8058-batt_alarm-irq", the_battalarm);
- if (rc < 0) {
- pr_err("request_irq(%d) failed, rc=%d\n",
- the_battalarm->irq, rc);
- goto done;
- }
-
- rc = irq_set_irq_wake(the_battalarm->irq, 1);
- if (rc < 0) {
- pr_err("irq_set_irq_wake(%d,1) failed, rc=%d\n",
- the_battalarm->irq, rc);
- goto done;
- }
- }
-
- the_battalarm->notifier_count++;
- }
-done:
- mutex_unlock(&the_battalarm->batt_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_register_notifier);
-
-/**
- * pm8058_batt_alarm_unregister_notifier - unregister a notifier that is run
- * when a battery voltage change interrupt fires
- * @nb: notifier block containing callback function to unregister
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_unregister_notifier(struct notifier_block *nb)
-{
- int rc;
-
- if (!the_battalarm) {
- pr_err("no battery alarm device found.\n");
- return -ENXIO;
- }
-
- rc = srcu_notifier_chain_unregister(&the_battalarm->irq_notifier_list,
- nb);
- if (rc == 0) {
- mutex_lock(&the_battalarm->batt_mutex);
-
- the_battalarm->notifier_count--;
-
- if (the_battalarm->notifier_count == 0)
- free_irq(the_battalarm->irq, the_battalarm);
-
- WARN_ON(the_battalarm->notifier_count < 0);
-
- mutex_unlock(&the_battalarm->batt_mutex);
- }
-
-
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_unregister_notifier);
-
-static int pm8058_batt_alarm_reg_init(struct pm8058_batt_alarm_device *battdev)
-{
- int rc = 0;
-
- /* save the current register states */
- rc = pm8058_read(battdev->pm_chip, REG_THRESHOLD,
- &battdev->reg_threshold, 1);
- if (rc)
- goto bail;
-
- rc = pm8058_read(battdev->pm_chip, REG_CTRL1,
- &battdev->reg_ctrl1, 1);
- if (rc)
- goto bail;
-
- rc = pm8058_read(battdev->pm_chip, REG_CTRL2,
- &battdev->reg_ctrl2, 1);
- if (rc)
- goto bail;
-
- rc = pm8058_read(battdev->pm_chip, REG_PWM_CTRL,
- &battdev->reg_pwm_ctrl, 1);
- if (rc)
- goto bail;
-
-bail:
- if (rc)
- pr_err("pm8058_read failed; initial register states "
- "unknown, rc=%d\n", rc);
- return rc;
-}
-
-static int pm8058_batt_alarm_config(void)
-{
- int rc = 0;
-
- /* Use default values when no platform data is provided. */
- rc = pm8058_batt_alarm_threshold_set(DEFAULT_THRESHOLD_LOWER,
- DEFAULT_THRESHOLD_UPPER);
- if (rc) {
- pr_err("threshold_set failed, rc=%d\n", rc);
- goto done;
- }
-
- rc = pm8058_batt_alarm_hold_time_set(DEFAULT_HOLD_TIME);
- if (rc) {
- pr_err("hold_time_set failed, rc=%d\n", rc);
- goto done;
- }
-
- rc = pm8058_batt_alarm_pwm_rate_set(DEFAULT_USE_PWM,
- DEFAULT_PWM_SCALER, DEFAULT_PWM_DIVIDER);
- if (rc) {
- pr_err("pwm_rate_set failed, rc=%d\n", rc);
- goto done;
- }
-
- rc = pm8058_batt_alarm_state_set(DEFAULT_LOWER_ENABLE,
- DEFAULT_UPPER_ENABLE);
- if (rc) {
- pr_err("state_set failed, rc=%d\n", rc);
- goto done;
- }
-
-done:
- return rc;
-}
-
-static int __devinit pm8058_batt_alarm_probe(struct platform_device *pdev)
-{
- struct pm8058_batt_alarm_device *battdev;
- struct pm8058_chip *pm_chip;
- unsigned int irq;
- int rc;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("no driver data passed in.\n");
- rc = -EFAULT;
- goto exit_input;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (!irq) {
- pr_err("no IRQ passed in.\n");
- rc = -EFAULT;
- goto exit_input;
- }
-
- battdev = kzalloc(sizeof *battdev, GFP_KERNEL);
- if (battdev == NULL) {
- pr_err("kzalloc() failed.\n");
- rc = -ENOMEM;
- goto exit_input;
- }
-
- battdev->pm_chip = pm_chip;
- platform_set_drvdata(pdev, battdev);
-
- srcu_init_notifier_head(&battdev->irq_notifier_list);
-
- battdev->irq = irq;
- battdev->notifier_count = 0;
- mutex_init(&battdev->batt_mutex);
-
- rc = pm8058_batt_alarm_reg_init(battdev);
- if (rc)
- goto exit_free_dev;
-
- the_battalarm = battdev;
-
- rc = pm8058_batt_alarm_config();
- if (rc)
- goto exit_free_dev;
-
- pr_notice("OK\n");
- return 0;
-
-exit_free_dev:
- mutex_destroy(&battdev->batt_mutex);
- srcu_cleanup_notifier_head(&battdev->irq_notifier_list);
- platform_set_drvdata(pdev, battdev->pm_chip);
- kfree(battdev);
-exit_input:
- return rc;
-}
-
-static int __devexit pm8058_batt_alarm_remove(struct platform_device *pdev)
-{
- struct pm8058_batt_alarm_device *battdev = platform_get_drvdata(pdev);
-
- mutex_destroy(&battdev->batt_mutex);
- srcu_cleanup_notifier_head(&battdev->irq_notifier_list);
- platform_set_drvdata(pdev, battdev->pm_chip);
- free_irq(battdev->irq, battdev);
- kfree(battdev);
-
- the_battalarm = NULL;
-
- return 0;
-}
-
-static struct platform_driver pm8058_batt_alarm_driver = {
- .probe = pm8058_batt_alarm_probe,
- .remove = __devexit_p(pm8058_batt_alarm_remove),
- .driver = {
- .name = "pm8058-batt-alarm",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8058_batt_alarm_init(void)
-{
- return platform_driver_register(&pm8058_batt_alarm_driver);
-}
-
-static void __exit pm8058_batt_alarm_exit(void)
-{
- platform_driver_unregister(&pm8058_batt_alarm_driver);
-}
-
-module_init(pm8058_batt_alarm_init);
-module_exit(pm8058_batt_alarm_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 Battery Alarm Device driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8058-batt-alarm");
diff --git a/drivers/misc/pmic8058-misc.c b/drivers/misc/pmic8058-misc.c
deleted file mode 100644
index 77a2f47..0000000
--- a/drivers/misc/pmic8058-misc.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-/*
- * Qualcomm PMIC8058 Misc Device driver
- *
- */
-
-#include <linux/debugfs.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pmic8058-misc.h>
-
-/* VIB_DRV register */
-#define SSBI_REG_ADDR_DRV_VIB 0x4A
-
-#define PM8058_VIB_DRIVE_SHIFT 3
-#define PM8058_VIB_LOGIC_SHIFT 2
-#define PM8058_VIB_MIN_LEVEL_mV 1200
-#define PM8058_VIB_MAX_LEVEL_mV 3100
-
-/* COINCELL_CHG register */
-#define SSBI_REG_ADDR_COINCELL_CHG (0x2F)
-#define PM8058_COINCELL_RESISTOR_SHIFT (2)
-
-/* Resource offsets. */
-enum PM8058_MISC_IRQ {
- PM8058_MISC_IRQ_OSC_HALT = 0
-};
-
-struct pm8058_misc_device {
- struct pm8058_chip *pm_chip;
- struct dentry *dgb_dir;
- unsigned int osc_halt_irq;
- u64 osc_halt_count;
-};
-
-static struct pm8058_misc_device *misc_dev;
-
-int pm8058_vibrator_config(struct pm8058_vib_config *vib_config)
-{
- u8 reg = 0;
- int rc;
-
- if (misc_dev == NULL) {
- pr_info("misc_device is NULL\n");
- return -EINVAL;
- }
-
- if (vib_config->drive_mV) {
- if (vib_config->drive_mV < PM8058_VIB_MIN_LEVEL_mV ||
- vib_config->drive_mV > PM8058_VIB_MAX_LEVEL_mV) {
- pr_err("Invalid vibrator drive strength\n");
- return -EINVAL;
- }
- }
-
- reg = (vib_config->drive_mV / 100) << PM8058_VIB_DRIVE_SHIFT;
-
- reg |= (!!vib_config->active_low) << PM8058_VIB_LOGIC_SHIFT;
-
- reg |= vib_config->enable_mode;
-
- rc = pm8058_write(misc_dev->pm_chip, SSBI_REG_ADDR_DRV_VIB, ®, 1);
- if (rc)
- pr_err("%s: pm8058 write failed: rc=%d\n", __func__, rc);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8058_vibrator_config);
-
-/**
- * pm8058_coincell_chg_config - Disables or enables the coincell charger, and
- * configures its voltage and resistor settings.
- * @chg_config: Holds both voltage and resistor values, and a
- * switch to change the state of charger.
- * If state is to disable the charger then
- * both voltage and resistor are disregarded.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_coincell_chg_config(struct pm8058_coincell_chg_config *chg_config)
-{
- u8 reg, voltage, resistor;
- int rc;
-
- reg = 0;
- voltage = 0;
- resistor = 0;
- rc = 0;
-
- if (misc_dev == NULL) {
- pr_err("misc_device is NULL\n");
- return -EINVAL;
- }
-
- if (chg_config == NULL) {
- pr_err("chg_config is NULL\n");
- return -EINVAL;
- }
-
- if (chg_config->state == PM8058_COINCELL_CHG_DISABLE) {
- rc = pm8058_write(misc_dev->pm_chip,
- SSBI_REG_ADDR_COINCELL_CHG, ®, 1);
- if (rc)
- pr_err("%s: pm8058 write failed: rc=%d\n",
- __func__, rc);
- return rc;
- }
-
- voltage = chg_config->voltage;
- resistor = chg_config->resistor;
-
- if (voltage < PM8058_COINCELL_VOLTAGE_3p2V ||
- (voltage > PM8058_COINCELL_VOLTAGE_3p0V &&
- voltage != PM8058_COINCELL_VOLTAGE_2p5V)) {
- pr_err("Invalid voltage value provided\n");
- return -EINVAL;
- }
-
- if (resistor < PM8058_COINCELL_RESISTOR_2100_OHMS ||
- resistor > PM8058_COINCELL_RESISTOR_800_OHMS) {
- pr_err("Invalid resistor value provided\n");
- return -EINVAL;
- }
-
- reg |= voltage;
-
- reg |= (resistor << PM8058_COINCELL_RESISTOR_SHIFT);
-
- rc = pm8058_write(misc_dev->pm_chip,
- SSBI_REG_ADDR_COINCELL_CHG, ®, 1);
-
- if (rc)
- pr_err("%s: pm8058 write failed: rc=%d\n", __func__, rc);
-
- return rc;
-}
-EXPORT_SYMBOL(pm8058_coincell_chg_config);
-
-/* Handle the OSC_HALT interrupt: 32 kHz XTAL oscillator has stopped. */
-static irqreturn_t pm8058_osc_halt_isr(int irq, void *data)
-{
- struct pm8058_misc_device *miscdev = data;
- u64 count = 0;
-
- if (miscdev) {
- miscdev->osc_halt_count++;
- count = miscdev->osc_halt_count;
- }
-
- pr_crit("%s: OSC_HALT interrupt has triggered, 32 kHz XTAL oscillator"
- " has halted (%llu)!\n", __func__, count);
-
- return IRQ_HANDLED;
-}
-
-#if defined(CONFIG_DEBUG_FS)
-
-static int osc_halt_count_get(void *data, u64 *val)
-{
- struct pm8058_misc_device *miscdev = data;
-
- if (miscdev == NULL) {
- pr_err("%s: null pointer input.\n", __func__);
- return -EINVAL;
- }
-
- *val = miscdev->osc_halt_count;
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(dbg_osc_halt_fops, osc_halt_count_get, NULL, "%llu\n");
-
-static int __devinit pmic8058_misc_dbg_probe(struct pm8058_misc_device *miscdev)
-{
- struct dentry *dent;
- struct dentry *temp;
-
- if (miscdev == NULL) {
- pr_err("%s: no parent data passed in.\n", __func__);
- return -EINVAL;
- }
-
- dent = debugfs_create_dir("pm8058-misc", NULL);
- if (dent == NULL || IS_ERR(dent)) {
- pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
- __func__, (unsigned)dent);
- return -ENOMEM;
- }
-
- temp = debugfs_create_file("osc_halt_count", S_IRUSR, dent,
- miscdev, &dbg_osc_halt_fops);
- if (temp == NULL || IS_ERR(temp)) {
- pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
- __func__, (unsigned)temp);
- goto debug_error;
- }
-
- miscdev->dgb_dir = dent;
- return 0;
-
-debug_error:
- debugfs_remove_recursive(dent);
- return -ENOMEM;
-}
-
-static int __devexit pmic8058_misc_dbg_remove(
- struct pm8058_misc_device *miscdev)
-{
- if (miscdev->dgb_dir)
- debugfs_remove_recursive(miscdev->dgb_dir);
-
- return 0;
-}
-
-#else
-
-static int __devinit pmic8058_misc_dbg_probe(struct pm8058_misc_device *miscdev)
-{
- return 0;
-}
-
-static int __devexit pmic8058_misc_dbg_remove(
- struct pm8058_misc_device *miscdev)
-{
- return 0;
-}
-
-#endif
-
-
-static int __devinit pmic8058_misc_probe(struct platform_device *pdev)
-{
- struct pm8058_misc_device *miscdev;
- struct pm8058_chip *pm_chip;
- unsigned int irq;
- int rc;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("%s: no driver data passed in.\n", __func__);
- return -EFAULT;
- }
-
- irq = platform_get_irq(pdev, PM8058_MISC_IRQ_OSC_HALT);
- if (!irq) {
- pr_err("%s: no IRQ passed in.\n", __func__);
- return -EFAULT;
- }
-
- miscdev = kzalloc(sizeof *miscdev, GFP_KERNEL);
- if (miscdev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
- return -ENOMEM;
- }
-
- miscdev->pm_chip = pm_chip;
- platform_set_drvdata(pdev, miscdev);
-
- rc = request_threaded_irq(irq, NULL, pm8058_osc_halt_isr,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
- "pm8058-osc_halt-irq", miscdev);
- if (rc < 0) {
- pr_err("%s: request_irq(%d) FAIL: %d\n", __func__, irq, rc);
- platform_set_drvdata(pdev, miscdev->pm_chip);
- kfree(miscdev);
- return rc;
- }
- miscdev->osc_halt_irq = irq;
- miscdev->osc_halt_count = 0;
-
- rc = pmic8058_misc_dbg_probe(miscdev);
- if (rc)
- return rc;
-
- misc_dev = miscdev;
-
- pr_notice("%s: OK\n", __func__);
- return 0;
-}
-
-static int __devexit pmic8058_misc_remove(struct platform_device *pdev)
-{
- struct pm8058_misc_device *miscdev = platform_get_drvdata(pdev);
-
- pmic8058_misc_dbg_remove(miscdev);
-
- platform_set_drvdata(pdev, miscdev->pm_chip);
- free_irq(miscdev->osc_halt_irq, miscdev);
- kfree(miscdev);
-
- return 0;
-}
-
-static struct platform_driver pmic8058_misc_driver = {
- .probe = pmic8058_misc_probe,
- .remove = __devexit_p(pmic8058_misc_remove),
- .driver = {
- .name = "pm8058-misc",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8058_misc_init(void)
-{
- return platform_driver_register(&pmic8058_misc_driver);
-}
-
-static void __exit pm8058_misc_exit(void)
-{
- platform_driver_unregister(&pmic8058_misc_driver);
-}
-
-module_init(pm8058_misc_init);
-module_exit(pm8058_misc_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 Misc Device driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058-misc");
diff --git a/drivers/misc/pmic8058-vibrator.c b/drivers/misc/pmic8058-vibrator.c
deleted file mode 100644
index f6284ee..0000000
--- a/drivers/misc/pmic8058-vibrator.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/pmic8058-vibrator.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-
-#include "../staging/android/timed_output.h"
-
-#define VIB_DRV 0x4A
-
-#define VIB_DRV_SEL_MASK 0xf8
-#define VIB_DRV_SEL_SHIFT 0x03
-#define VIB_DRV_EN_MANUAL_MASK 0xfc
-
-#define VIB_MAX_LEVEL_mV 3100
-#define VIB_MIN_LEVEL_mV 1200
-
-struct pmic8058_vib {
- struct hrtimer vib_timer;
- struct timed_output_dev timed_dev;
- spinlock_t lock;
- struct work_struct work;
-
- struct device *dev;
- struct pmic8058_vibrator_pdata *pdata;
- int state;
- int level;
- u8 reg_vib_drv;
-
- struct pm8058_chip *pm_chip;
-};
-
-/* REVISIT: just for debugging, will be removed in final working version */
-static void __dump_vib_regs(struct pmic8058_vib *vib, char *msg)
-{
- u8 temp;
-
- dev_dbg(vib->dev, "%s\n", msg);
-
- pm8058_read(vib->pm_chip, VIB_DRV, &temp, 1);
- dev_dbg(vib->dev, "VIB_DRV - %X\n", temp);
-}
-
-static int pmic8058_vib_read_u8(struct pmic8058_vib *vib,
- u8 *data, u16 reg)
-{
- int rc;
-
- rc = pm8058_read(vib->pm_chip, reg, data, 1);
- if (rc < 0)
- dev_warn(vib->dev, "Error reading pmic8058: %X - ret %X\n",
- reg, rc);
-
- return rc;
-}
-
-static int pmic8058_vib_write_u8(struct pmic8058_vib *vib,
- u8 data, u16 reg)
-{
- int rc;
-
- rc = pm8058_write(vib->pm_chip, reg, &data, 1);
- if (rc < 0)
- dev_warn(vib->dev, "Error writing pmic8058: %X - ret %X\n",
- reg, rc);
- return rc;
-}
-
-static int pmic8058_vib_set(struct pmic8058_vib *vib, int on)
-{
- int rc;
- u8 val;
-
- if (on) {
- rc = pm_runtime_resume(vib->dev);
- if (rc < 0)
- dev_dbg(vib->dev, "pm_runtime_resume failed\n");
-
- val = vib->reg_vib_drv;
- val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK);
- rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
- if (rc < 0)
- return rc;
- vib->reg_vib_drv = val;
- } else {
- val = vib->reg_vib_drv;
- val &= ~VIB_DRV_SEL_MASK;
- rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
- if (rc < 0)
- return rc;
- vib->reg_vib_drv = val;
-
- rc = pm_runtime_suspend(vib->dev);
- if (rc < 0)
- dev_dbg(vib->dev, "pm_runtime_suspend failed\n");
- }
- __dump_vib_regs(vib, "vib_set_end");
-
- return rc;
-}
-
-static void pmic8058_vib_enable(struct timed_output_dev *dev, int value)
-{
- struct pmic8058_vib *vib = container_of(dev, struct pmic8058_vib,
- timed_dev);
- unsigned long flags;
-
-retry:
- spin_lock_irqsave(&vib->lock, flags);
- if (hrtimer_try_to_cancel(&vib->vib_timer) < 0) {
- spin_unlock_irqrestore(&vib->lock, flags);
- cpu_relax();
- goto retry;
- }
-
- if (value == 0)
- vib->state = 0;
- else {
- value = (value > vib->pdata->max_timeout_ms ?
- vib->pdata->max_timeout_ms : value);
- vib->state = 1;
- hrtimer_start(&vib->vib_timer,
- ktime_set(value / 1000, (value % 1000) * 1000000),
- HRTIMER_MODE_REL);
- }
- spin_unlock_irqrestore(&vib->lock, flags);
- schedule_work(&vib->work);
-}
-
-static void pmic8058_vib_update(struct work_struct *work)
-{
- struct pmic8058_vib *vib = container_of(work, struct pmic8058_vib,
- work);
-
- pmic8058_vib_set(vib, vib->state);
-}
-
-static int pmic8058_vib_get_time(struct timed_output_dev *dev)
-{
- struct pmic8058_vib *vib = container_of(dev, struct pmic8058_vib,
- timed_dev);
-
- if (hrtimer_active(&vib->vib_timer)) {
- ktime_t r = hrtimer_get_remaining(&vib->vib_timer);
- return (int) ktime_to_us(r);
- } else
- return 0;
-}
-
-static enum hrtimer_restart pmic8058_vib_timer_func(struct hrtimer *timer)
-{
- struct pmic8058_vib *vib = container_of(timer, struct pmic8058_vib,
- vib_timer);
- vib->state = 0;
- schedule_work(&vib->work);
- return HRTIMER_NORESTART;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_vib_suspend(struct device *dev)
-{
- struct pmic8058_vib *vib = dev_get_drvdata(dev);
-
- hrtimer_cancel(&vib->vib_timer);
- cancel_work_sync(&vib->work);
- /* turn-off vibrator */
- pmic8058_vib_set(vib, 0);
- return 0;
-}
-
-static struct dev_pm_ops pmic8058_vib_pm_ops = {
- .suspend = pmic8058_vib_suspend,
-};
-#endif
-
-static int __devinit pmic8058_vib_probe(struct platform_device *pdev)
-
-{
- struct pmic8058_vibrator_pdata *pdata = pdev->dev.platform_data;
- struct pmic8058_vib *vib;
- u8 val;
- int rc;
-
- struct pm8058_chip *pm_chip;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- dev_err(&pdev->dev, "no parent data passed in\n");
- return -EFAULT;
- }
-
- if (!pdata)
- return -EINVAL;
-
- if (pdata->level_mV < VIB_MIN_LEVEL_mV ||
- pdata->level_mV > VIB_MAX_LEVEL_mV)
- return -EINVAL;
-
- vib = kzalloc(sizeof(*vib), GFP_KERNEL);
- if (!vib)
- return -ENOMEM;
-
- /* Enable runtime PM ops, start in ACTIVE mode */
- rc = pm_runtime_set_active(&pdev->dev);
- if (rc < 0)
- dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
- pm_runtime_enable(&pdev->dev);
-
- vib->pm_chip = pm_chip;
- vib->pdata = pdata;
- vib->level = pdata->level_mV / 100;
- vib->dev = &pdev->dev;
-
- spin_lock_init(&vib->lock);
- INIT_WORK(&vib->work, pmic8058_vib_update);
-
- hrtimer_init(&vib->vib_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- vib->vib_timer.function = pmic8058_vib_timer_func;
-
- vib->timed_dev.name = "vibrator";
- vib->timed_dev.get_time = pmic8058_vib_get_time;
- vib->timed_dev.enable = pmic8058_vib_enable;
-
- __dump_vib_regs(vib, "boot_vib_default");
-
- /* operate in manual mode */
- rc = pmic8058_vib_read_u8(vib, &val, VIB_DRV);
- if (rc < 0)
- goto err_read_vib;
- val &= ~VIB_DRV_EN_MANUAL_MASK;
- rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
- if (rc < 0)
- goto err_read_vib;
-
- vib->reg_vib_drv = val;
-
- rc = timed_output_dev_register(&vib->timed_dev);
- if (rc < 0)
- goto err_read_vib;
-
- pmic8058_vib_enable(&vib->timed_dev, pdata->initial_vibrate_ms);
-
- platform_set_drvdata(pdev, vib);
-
- pm_runtime_set_suspended(&pdev->dev);
- return 0;
-
-err_read_vib:
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- kfree(vib);
- return rc;
-}
-
-static int __devexit pmic8058_vib_remove(struct platform_device *pdev)
-{
- struct pmic8058_vib *vib = platform_get_drvdata(pdev);
-
- pm_runtime_disable(&pdev->dev);
- cancel_work_sync(&vib->work);
- hrtimer_cancel(&vib->vib_timer);
- timed_output_dev_unregister(&vib->timed_dev);
- kfree(vib);
-
- return 0;
-}
-
-static struct platform_driver pmic8058_vib_driver = {
- .probe = pmic8058_vib_probe,
- .remove = __devexit_p(pmic8058_vib_remove),
- .driver = {
- .name = "pm8058-vib",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &pmic8058_vib_pm_ops,
-#endif
- },
-};
-
-static int __init pmic8058_vib_init(void)
-{
- return platform_driver_register(&pmic8058_vib_driver);
-}
-module_init(pmic8058_vib_init);
-
-static void __exit pmic8058_vib_exit(void)
-{
- platform_driver_unregister(&pmic8058_vib_driver);
-}
-module_exit(pmic8058_vib_exit);
-
-MODULE_ALIAS("platform:pmic8058_vib");
-MODULE_DESCRIPTION("PMIC8058 vibrator driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1ee8538..48f3f2d 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -549,6 +549,7 @@
return err;
}
+#define ERR_NOMEDIUM 3
#define ERR_RETRY 2
#define ERR_ABORT 1
#define ERR_CONTINUE 0
@@ -620,6 +621,9 @@
u32 status, stop_status = 0;
int err, retry;
+ if (mmc_card_removed(card))
+ return ERR_NOMEDIUM;
+
/*
* Try to get card status which indicates both the card state
* and why there was no response. If the first attempt fails,
@@ -636,8 +640,12 @@
}
/* We couldn't get a response from the card. Give up. */
- if (err)
+ if (err) {
+ /* Check if the card is removed */
+ if (mmc_detect_card_removed(card->host))
+ return ERR_NOMEDIUM;
return ERR_ABORT;
+ }
/*
* Check the current card state. If it is in some data transfer
@@ -969,6 +977,7 @@
if (retry++ < 5)
continue;
case ERR_ABORT:
+ case ERR_NOMEDIUM:
goto cmd_abort;
case ERR_CONTINUE:
break;
@@ -1075,6 +1084,8 @@
cmd_abort:
spin_lock_irq(&md->lock);
+ if (mmc_card_removed(card))
+ req->cmd_flags |= REQ_QUIET;
while (ret)
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
spin_unlock_irq(&md->lock);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 9b64847..b2fb161 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -29,6 +29,8 @@
*/
static int mmc_prep_request(struct request_queue *q, struct request *req)
{
+ struct mmc_queue *mq = q->queuedata;
+
/*
* We only like normal block requests and discards.
*/
@@ -37,6 +39,9 @@
return BLKPREP_KILL;
}
+ if (mq && mmc_card_removed(mq->card))
+ return BLKPREP_KILL;
+
req->cmd_flags |= REQ_DONTPREP;
return BLKPREP_OK;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 2c7c0a5..51434b6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -105,7 +105,7 @@
cmd->retries = 0;
}
- if (err && cmd->retries) {
+ if (err && cmd->retries && !mmc_card_removed(host->card)) {
pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host), cmd->opcode, err);
@@ -238,6 +238,10 @@
mrq->done_data = &complete;
mrq->done = mmc_wait_done;
+ if (mmc_card_removed(host->card)) {
+ mrq->cmd->error = -ENOMEDIUM;
+ return;
+ }
mmc_start_request(host, mrq);
@@ -502,13 +506,6 @@
might_sleep();
add_wait_queue(&host->wq, &wait);
-#ifdef CONFIG_PM_RUNTIME
- while (mmc_dev(host)->power.runtime_status == RPM_SUSPENDING) {
- if (host->suspend_task == current)
- break;
- msleep(15);
- }
-#endif
spin_lock_irqsave(&host->lock, flags);
while (1) {
@@ -1257,6 +1254,7 @@
#endif
wake_lock(&host->detect_wake_lock);
+ host->detect_change = 1;
mmc_schedule_delayed_work(&host->detect, delay);
}
@@ -1665,6 +1663,43 @@
return -EIO;
}
+int _mmc_detect_card_removed(struct mmc_host *host)
+{
+ int ret;
+
+ if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+ return 0;
+
+ if (!host->card || mmc_card_removed(host->card))
+ return 1;
+
+ ret = host->bus_ops->alive(host);
+ if (ret) {
+ mmc_card_set_removed(host->card);
+ pr_debug("%s: card remove detected\n", mmc_hostname(host));
+ }
+
+ return ret;
+}
+
+int mmc_detect_card_removed(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+
+ WARN_ON(!host->claimed);
+ /*
+ * The card will be considered unchanged unless we have been asked to
+ * detect a change or host requires polling to provide card detection.
+ */
+ if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
+ return mmc_card_removed(card);
+
+ host->detect_change = 0;
+
+ return _mmc_detect_card_removed(host);
+}
+EXPORT_SYMBOL(mmc_detect_card_removed);
+
void mmc_rescan(struct work_struct *work)
{
struct mmc_host *host =
@@ -1690,6 +1725,8 @@
if (host->bus_dead)
extend_wakelock = 1;
+ host->detect_change = 0;
+
/*
* Let mmc_bus_put() free the bus/bus_ops if we've found that
* the card is no longer present.
@@ -1873,20 +1910,43 @@
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
- if (host->bus_ops->suspend)
- err = host->bus_ops->suspend(host);
- if (err == -ENOSYS || !host->bus_ops->resume) {
- /*
- * We simply "remove" the card in this case.
- * It will be redetected on resume.
- */
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_release_host(host);
- host->pm_flags = 0;
- err = 0;
+
+ /*
+ * A long response time is not acceptable for device drivers
+ * when doing suspend. Prevent mmc_claim_host in the suspend
+ * sequence, to potentially wait "forever" by trying to
+ * pre-claim the host.
+ *
+ * Skip try claim host for SDIO cards, doing so fixes deadlock
+ * conditions. The function driver suspend may again call into
+ * SDIO driver within a different context for enabling power
+ * save mode in the card and hence wait in mmc_claim_host
+ * causing deadlock.
+ */
+ if (!(host->card && mmc_card_sdio(host->card)))
+ if (!mmc_try_claim_host(host))
+ err = -EBUSY;
+
+ if (!err) {
+ if (host->bus_ops->suspend)
+ err = host->bus_ops->suspend(host);
+ if (!(host->card && mmc_card_sdio(host->card)))
+ mmc_do_release_host(host);
+
+ if (err == -ENOSYS || !host->bus_ops->resume) {
+ /*
+ * We simply "remove" the card in this case.
+ * It will be redetected on resume.
+ */
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_power_off(host);
+ mmc_release_host(host);
+ host->pm_flags = 0;
+ err = 0;
+ }
}
}
mmc_bus_put(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index a4edb24..49684f6 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -24,6 +24,7 @@
int (*resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
+ int (*alive)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -60,6 +61,8 @@
void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);
+int _mmc_detect_card_removed(struct mmc_host *host);
+
int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 918fc9e..79d6e97 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -874,6 +874,14 @@
}
/*
+ * Card detection - card is alive.
+ */
+static int mmc_alive(struct mmc_host *host)
+{
+ return mmc_send_status(host->card, NULL);
+}
+
+/*
* Card detection callback from host.
*/
static void mmc_detect(struct mmc_host *host)
@@ -888,7 +896,7 @@
/*
* Just check if our card has been removed.
*/
- err = mmc_send_status(host->card, NULL);
+ err = _mmc_detect_card_removed(host);
mmc_release_host(host);
@@ -992,6 +1000,7 @@
.suspend = NULL,
.resume = NULL,
.power_restore = mmc_power_restore,
+ .alive = mmc_alive,
};
static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -1002,6 +1011,7 @@
.suspend = mmc_suspend,
.resume = mmc_resume,
.power_restore = mmc_power_restore,
+ .alive = mmc_alive,
};
static void mmc_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 71518f6..6522efb 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1044,6 +1044,14 @@
}
/*
+ * Card detection - card is alive.
+ */
+static int mmc_sd_alive(struct mmc_host *host)
+{
+ return mmc_send_status(host->card, NULL);
+}
+
+/*
* Card detection callback from host.
*/
static void mmc_sd_detect(struct mmc_host *host)
@@ -1063,7 +1071,7 @@
*/
#ifdef CONFIG_MMC_PARANOID_SD_INIT
while(retries) {
- err = mmc_send_status(host->card, NULL);
+ err = _mmc_detect_card_removed(host);
if (err) {
retries--;
udelay(5);
@@ -1076,7 +1084,7 @@
__func__, mmc_hostname(host), err);
}
#else
- err = mmc_send_status(host->card, NULL);
+ err = _mmc_detect_card_removed(host);
#endif
mmc_release_host(host);
@@ -1163,6 +1171,7 @@
.suspend = NULL,
.resume = NULL,
.power_restore = mmc_sd_power_restore,
+ .alive = mmc_sd_alive,
};
static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -1171,6 +1180,7 @@
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
.power_restore = mmc_sd_power_restore,
+ .alive = mmc_sd_alive,
};
static void mmc_sd_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 3237742..8ac2e59 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -582,6 +582,14 @@
}
/*
+ * Card detection - card is alive.
+ */
+static int mmc_sdio_alive(struct mmc_host *host)
+{
+ return mmc_select_card(host->card);
+}
+
+/*
* Card detection callback from host.
*/
static void mmc_sdio_detect(struct mmc_host *host)
@@ -603,7 +611,7 @@
/*
* Just check if our card has been removed.
*/
- err = mmc_select_card(host->card);
+ err = _mmc_detect_card_removed(host);
mmc_release_host(host);
@@ -783,6 +791,7 @@
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
.power_restore = mmc_sdio_power_restore,
+ .alive = mmc_sdio_alive,
};
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0410473..e853699 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -132,6 +132,7 @@
msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
u32 c);
static inline void msmsdcc_delay(struct msmsdcc_host *host);
+static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
{
@@ -476,7 +477,11 @@
goto out;
}
msmsdcc_stop_data(host);
- if (!mrq->data->stop || mrq->cmd->error ||
+
+ if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+ || !mrq->sbc)) {
+ msmsdcc_start_command(host, mrq->data->stop, 0);
+ } else if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -486,9 +491,6 @@
mmc_request_done(host->mmc, mrq);
return;
- } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
- || !mrq->sbc)) {
- msmsdcc_start_command(host, mrq->data->stop, 0);
}
}
@@ -633,7 +635,10 @@
return;
}
msmsdcc_stop_data(host);
- if (!mrq->data->stop || mrq->cmd->error ||
+ if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+ || !mrq->sbc)) {
+ msmsdcc_start_command(host, mrq->data->stop, 0);
+ } else if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -643,9 +648,6 @@
mmc_request_done(host->mmc, mrq);
return;
- } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
- || !mrq->sbc)) {
- msmsdcc_start_command(host, mrq->data->stop, 0);
}
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -696,7 +698,7 @@
static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
-static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
+static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
static void
msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
@@ -942,7 +944,7 @@
msmsdcc_start_command_deferred(struct msmsdcc_host *host,
struct mmc_command *cmd, u32 *c)
{
- DBG(host, "op %02x arg %08x flags %08x\n",
+ DBG(host, "op %d arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags);
*c |= (cmd->opcode | MCI_CPSM_ENABLE);
@@ -1149,9 +1151,11 @@
*/
if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
- pr_err("%s: Data timeout\n",
- mmc_hostname(host->mmc));
+ pr_err("%s: CMD%d: Data timeout\n",
+ mmc_hostname(host->mmc),
+ data->mrq->cmd->opcode);
data->error = -ETIMEDOUT;
+ msmsdcc_dump_sdcc_state(host);
}
} else if (status & MCI_RXOVERRUN) {
pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
@@ -1262,6 +1266,9 @@
len = msmsdcc_pio_read(host, buffer, remain);
if (status & MCI_TXACTIVE)
len = msmsdcc_pio_write(host, buffer, remain);
+ /* len might have aligned to 32bits above */
+ if (len > remain)
+ len = remain;
/* Unmap the buffer */
kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
@@ -1362,11 +1369,14 @@
cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
- pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
+ pr_debug("%s: CMD%d: Command timeout\n",
+ mmc_hostname(host->mmc), cmd->opcode);
cmd->error = -ETIMEDOUT;
} else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
!host->cmd19_tuning_in_progress) {
- pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
+ pr_err("%s: CMD%d: Command CRC error\n",
+ mmc_hostname(host->mmc), cmd->opcode);
+ msmsdcc_dump_sdcc_state(host);
cmd->error = -EILSEQ;
}
@@ -1383,9 +1393,16 @@
else if (host->curr.data) { /* Non DMA */
msmsdcc_reset_and_restore(host);
msmsdcc_stop_data(host);
- msmsdcc_request_end(host, cmd->mrq);
+ if (cmd->data && cmd->data->stop)
+ msmsdcc_start_command(host,
+ cmd->data->stop, 0);
+ else
+ msmsdcc_request_end(host, cmd->mrq);
} else { /* host->data == NULL */
- if (!cmd->error && host->prog_enable) {
+ if (cmd->data && cmd->data->stop) {
+ msmsdcc_start_command(host,
+ cmd->data->stop, 0);
+ } else if (!cmd->error && host->prog_enable) {
if (status & MCI_PROGDONE) {
host->prog_enable = 0;
msmsdcc_request_end(host, cmd->mrq);
@@ -2221,7 +2238,7 @@
if (clock != host->clk_rate) {
rc = clk_set_rate(host->clk, clock);
if (rc < 0)
- pr_debug("%s: failed to set clk rate %u\n",
+ pr_err("%s: failed to set clk rate %u\n",
mmc_hostname(mmc), clock);
host->clk_rate = clock;
host->reg_write_delay =
@@ -2254,8 +2271,7 @@
* Select the controller timing mode according
* to current bus speed mode
*/
- if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
- (ios->timing == MMC_TIMING_UHS_SDR50)) {
+ if (ios->timing == MMC_TIMING_UHS_SDR104) {
clk |= (4 << 14);
host->tuning_needed = 1;
} else if (ios->timing == MMC_TIMING_UHS_DDR50) {
@@ -2357,6 +2373,11 @@
msmsdcc_setup_clocks(host, false);
host->clks_on = 0;
}
+
+ if (host->cmd19_tuning_in_progress)
+ WARN(!host->clks_on,
+ "cmd19_tuning_in_progress but SDCC clocks are OFF\n");
+
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -2603,97 +2624,9 @@
return rc;
}
-static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
- u8 phase);
-/* Initialize the DLL (Programmable Delay Line ) */
-static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
+static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
{
- int rc = 0;
- u32 wait_timeout;
-
- /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
-
- /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
-
- msmsdcc_delay(host);
-
- /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
-
- /* Initialize the phase to 0 */
- rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
- if (rc)
- goto out;
-
- wait_timeout = 1000;
- /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
- while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
- /* max. wait for 1 sec for LOCK bit to be set */
- if (--wait_timeout == 0) {
- pr_err("%s: %s: DLL failed to lock at phase: %d",
- mmc_hostname(host->mmc), __func__, 0);
- rc = -1;
- goto out;
- }
- /* wait for 1ms */
- usleep_range(1000, 1500);
- }
-out:
- return rc;
-}
-
-/*
- * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
- * calibration sequence. This function should be called before
- * enabling AUTO_CMD19 bit in MCI_CMD register for block read
- * commands (CMD17/CMD18).
- */
-static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
-{
- /* Set CDR_EN bit to 1. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
- MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
-
- /* Set CDR_EXT_EN bit to 0. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- & ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
-
- /* Set CK_OUT_EN bit to 0. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
- /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
- while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
- ;
-
- /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
- /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
- while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
- ;
-}
-
-static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
- u8 phase)
-{
- int rc = 0;
u32 mclk_freq = 0;
- u32 wait_timeout;
-
- /* Set CDR_EN bit to 0. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- & ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
-
- /* Set CDR_EXT_EN bit to 1. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- | MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
/* Program the MCLK value to MCLK_FREQ bit field */
if (host->clk_rate <= 112000000)
@@ -2716,73 +2649,16 @@
writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
& ~(7 << 24)) | (mclk_freq << 24)),
host->base + MCI_DLL_CONFIG);
-
- /* Set CK_OUT_EN bit to 0. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- & ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
- /* Set DLL_EN bit to 1. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
-
- wait_timeout = 1000;
- /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
- while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
- /* max. wait for 1 sec for LOCK bit for be set */
- if (--wait_timeout == 0) {
- pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
- mmc_hostname(host->mmc), __func__, phase);
- rc = -1;
- goto out;
- }
- /* wait for 1ms */
- usleep_range(1000, 1500);
- }
-
- /*
- * Write the selected DLL clock output phase (0 ... 15)
- * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
- */
- writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
- & ~(0xF << 20)) | (phase << 20)),
- host->base + MCI_DLL_CONFIG);
-
- /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
- writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
- | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
- wait_timeout = 1000;
- /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
- while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
- /* max. wait for 1 sec for LOCK bit for be set */
- if (--wait_timeout == 0) {
- pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
- mmc_hostname(host->mmc), __func__, phase);
- rc = -1;
- goto out;
- }
- /* wait for 1ms */
- usleep_range(1000, 1500);
- }
-out:
- return rc;
}
-static int msmsdcc_execute_tuning(struct mmc_host *mmc)
+/* Initialize the DLL (Programmable Delay Line ) */
+static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
{
- struct msmsdcc_host *host = mmc_priv(mmc);
- u8 phase;
- u8 *data_buf;
- u8 tuned_phases[16], tuned_phase_cnt = 0;
int rc = 0;
+ unsigned long flags;
+ u32 wait_cnt;
- /* Tuning is only required for SDR50 & SDR104 modes */
- if (!host->tuning_needed) {
- rc = 0;
- goto out;
- }
-
- host->cmd19_tuning_in_progress = 1;
+ spin_lock_irqsave(&host->lock, flags);
/*
* Make sure that clock is always enabled when DLL
* tuning is in progress. Keeping PWRSAVE ON may
@@ -2791,7 +2667,248 @@
*/
writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
& ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+
+ /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ | MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
+
+ /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ | MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
+
+ msmsdcc_cm_sdc4_dll_set_freq(host);
+
+ /* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ & ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
+
+ /* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ & ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
+
+ /* Set DLL_EN bit to 1. */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ | MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
+
+ /* Set CK_OUT_EN bit to 1. */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
+
+ wait_cnt = 50;
+ /* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
+ while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
+ /* max. wait for 50us sec for LOCK bit to be set */
+ if (--wait_cnt == 0) {
+ pr_err("%s: %s: DLL failed to LOCK\n",
+ mmc_hostname(host->mmc), __func__);
+ rc = -ETIMEDOUT;
+ goto out;
+ }
+ /* wait for 1us before polling again */
+ udelay(1);
+ }
+
+out:
+ /* re-enable PWRSAVE */
+ writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
+ MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return rc;
+}
+
+static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
+ u8 poll)
+{
+ int rc = 0;
+ u32 wait_cnt = 50;
+ u8 ck_out_en = 0;
+
+ /* poll for MCI_CK_OUT_EN bit. max. poll time = 50us */
+ ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
+ MCI_CK_OUT_EN);
+
+ while (ck_out_en != poll) {
+ if (--wait_cnt == 0) {
+ pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
+ mmc_hostname(host->mmc), __func__, poll);
+ rc = -ETIMEDOUT;
+ goto out;
+ }
+ udelay(1);
+
+ ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
+ MCI_CK_OUT_EN);
+ }
+out:
+ return rc;
+}
+
+/*
+ * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
+ * calibration sequence. This function should be called before
+ * enabling AUTO_CMD19 bit in MCI_CMD register for block read
+ * commands (CMD17/CMD18).
+ *
+ * This function gets called when host spinlock acquired.
+ */
+static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
+{
+ int rc = 0;
+ u32 config;
+
+ config = readl_relaxed(host->base + MCI_DLL_CONFIG);
+ config |= MCI_CDR_EN;
+ config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
+ writel_relaxed(config, host->base + MCI_DLL_CONFIG);
+
+ /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
+ rc = msmsdcc_dll_poll_ck_out_en(host, 0);
+ if (rc)
+ goto err_out;
+
+ /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
+
+ /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
+ rc = msmsdcc_dll_poll_ck_out_en(host, 1);
+ if (rc)
+ goto err_out;
+
+ goto out;
+
+err_out:
+ pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
+out:
+ return rc;
+}
+
+static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
+ u8 phase)
+{
+ int rc = 0;
+ u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6,
+ 0x7, 0x5, 0x4, 0x8, 0x9,
+ 0xB, 0xA, 0xE, 0xF, 0xD,
+ 0xC};
+ unsigned long flags;
+ u32 config;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ config = readl_relaxed(host->base + MCI_DLL_CONFIG);
+ config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
+ config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
+ writel_relaxed(config, host->base + MCI_DLL_CONFIG);
+
+ /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
+ rc = msmsdcc_dll_poll_ck_out_en(host, 0);
+ if (rc)
+ goto err_out;
+
+ /*
+ * Write the selected DLL clock output phase (0 ... 15)
+ * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
+ */
+ writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ & ~(0xF << 20))
+ | (grey_coded_phase_table[phase] << 20)),
+ host->base + MCI_DLL_CONFIG);
+
+ /* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
+ writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+ | MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
+
+ /* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
+ rc = msmsdcc_dll_poll_ck_out_en(host, 1);
+ if (rc)
+ goto err_out;
+
+ config = readl_relaxed(host->base + MCI_DLL_CONFIG);
+ config |= MCI_CDR_EN;
+ config &= ~MCI_CDR_EXT_EN;
+ writel_relaxed(config, host->base + MCI_DLL_CONFIG);
+ goto out;
+
+err_out:
+ pr_err("%s: %s: Failed to set DLL phase: %d\n",
+ mmc_hostname(host->mmc), __func__, phase);
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+ return rc;
+}
+
+/*
+ * Find out the greatest range of consecuitive selected
+ * DLL clock output phases that can be used as sampling
+ * setting for SD3.0 UHS-I card read operation (in SDR104
+ * timing mode) or for eMMC4.5 card read operation (in HS200
+ * timing mode).
+ * Select the 3/4 of the range and configure the DLL with the
+ * selected DLL clock output phase.
+*/
+
+static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
+ u8 *phase_table, u8 total_phases)
+{
+ u8 ret, temp;
+ u8 ranges[16][16] = { {0}, {0} };
+ u8 phases_per_row[16] = {0};
+ int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
+ int cnt;
+
+ for (cnt = 0; cnt <= total_phases; cnt++) {
+ ranges[row_index][col_index] = phase_table[cnt];
+ phases_per_row[row_index] += 1;
+ col_index++;
+
+ if ((cnt + 1) > total_phases) {
+ continue;
+ /* check if next phase in phase_table is consecutive or not */
+ } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
+ row_index++;
+ col_index = 0;
+ }
+ }
+
+ for (cnt = 0; cnt <= total_phases; cnt++) {
+ if (phases_per_row[cnt] > curr_max) {
+ curr_max = phases_per_row[cnt];
+ selected_row_index = cnt;
+ }
+ }
+
+ temp = ((curr_max * 3) / 4);
+ ret = ranges[selected_row_index][temp];
+
+ return ret;
+}
+
+static int msmsdcc_execute_tuning(struct mmc_host *mmc)
+{
+ int rc = 0;
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+
+ /* Tuning is only required for SDR104 modes */
+ if (!host->tuning_needed) {
+ rc = 0;
+ goto exit;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ WARN(!host->pwr, "SDCC power is turned off\n");
+ WARN(!host->clks_on, "SDCC clocks are turned off\n");
+ WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
+
+ host->cmd19_tuning_in_progress = 1;
msmsdcc_delay(host);
+ spin_unlock_irqrestore(&host->lock, flags);
+
/* first of all reset the tuning block */
rc = msmsdcc_init_cm_sdc4_dll(host);
if (rc)
@@ -2839,35 +2956,36 @@
}
} while (++phase < 16);
- kfree(data_buf);
-
if (tuned_phase_cnt) {
tuned_phase_cnt--;
- tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
- phase = tuned_phases[tuned_phase_cnt];
+ phase = find_most_appropriate_phase(host, tuned_phases,
+ tuned_phase_cnt);
/*
* Finally set the selected phase in delay
* line hw block.
*/
rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
if (rc)
- goto out;
+ goto kfree;
+ pr_debug("%s: %s: finally setting the tuning phase to %d\n",
+ mmc_hostname(mmc), __func__, phase);
} else {
/* tuning failed */
- rc = -EAGAIN;
- pr_err("%s: %s: no tuning point found",
+ pr_err("%s: %s: no tuning point found\n",
mmc_hostname(mmc), __func__);
+ msmsdcc_dump_sdcc_state(host);
+ rc = -EAGAIN;
}
- goto out;
kfree:
kfree(data_buf);
out:
- /* re-enable PWESAVE */
- writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
- MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+ spin_lock_irqsave(&host->lock, flags);
msmsdcc_delay(host);
host->cmd19_tuning_in_progress = 0;
+ spin_unlock_irqrestore(&host->lock, flags);
+exit:
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
return rc;
}
@@ -2897,7 +3015,7 @@
} else {
status = gpio_direction_input(gpio_no);
if (!status)
- status = !gpio_get_value_cansleep(gpio_no);
+ status = gpio_get_value_cansleep(gpio_no);
gpio_free(gpio_no);
}
return status;
@@ -2910,15 +3028,36 @@
unsigned int status;
if (host->plat->status || host->plat->status_gpio) {
- if (host->plat->status)
+ if (host->plat->status) {
status = host->plat->status(mmc_dev(host->mmc));
- else
+ host->eject = !status;
+ } else {
status = msmsdcc_slot_status(host);
- host->eject = !status;
+ if (host->plat->is_status_gpio_active_low)
+ host->eject = status;
+ else
+ host->eject = !status;
+ }
+
if (status ^ host->oldstat) {
- pr_info("%s: Slot status change detected (%d -> %d)\n",
- mmc_hostname(host->mmc), host->oldstat, status);
+ if (host->plat->status)
+ pr_info("%s: Slot status change detected "
+ "(%d -> %d)\n",
+ mmc_hostname(host->mmc),
+ host->oldstat, status);
+ else if (host->plat->is_status_gpio_active_low)
+ pr_info("%s: Slot status change detected "
+ "(%d -> %d) and the card detect GPIO"
+ " is ACTIVE_LOW\n",
+ mmc_hostname(host->mmc),
+ host->oldstat, status);
+ else
+ pr_info("%s: Slot status change detected "
+ "(%d -> %d) and the card detect GPIO"
+ " is ACTIVE_HIGH\n",
+ mmc_hostname(host->mmc),
+ host->oldstat, status);
mmc_detect_change(host->mmc, 0);
}
host->oldstat = status;
@@ -4049,11 +4188,17 @@
*/
if (plat->status || plat->status_gpio) {
- if (plat->status)
+ if (plat->status) {
host->oldstat = plat->status(mmc_dev(host->mmc));
- else
+ host->eject = !host->oldstat;
+ } else {
host->oldstat = msmsdcc_slot_status(host);
- host->eject = !host->oldstat;
+
+ if (host->plat->is_status_gpio_active_low)
+ host->eject = host->oldstat;
+ else
+ host->eject = !host->oldstat;
+ }
}
if (plat->status_irq) {
@@ -4376,7 +4521,6 @@
if (host->plat->is_sdio_al_client)
return 0;
-
pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
if (mmc) {
host->sdcc_suspending = 1;
@@ -4411,7 +4555,11 @@
* simple become pm usage counter increment operations.
*/
pm_runtime_get_noresume(dev);
- rc = mmc_suspend_host(mmc);
+ /* If there is pending detect work abort runtime suspend */
+ if (unlikely(work_busy(&mmc->detect.work)))
+ rc = -EAGAIN;
+ else
+ rc = mmc_suspend_host(mmc);
pm_runtime_put_noidle(dev);
if (!rc) {
@@ -4442,7 +4590,7 @@
if (rc && wake_lock_active(&host->sdio_suspend_wlock))
wake_unlock(&host->sdio_suspend_wlock);
}
- pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
+ pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
return rc;
}
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 84d4608..4e40468 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -458,4 +458,14 @@
http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
+config MSM_RMNET_USB
+ tristate "RMNET USB Driver"
+ depends on USB_USBNET
+ help
+ Select this if you have a Qualcomm modem device connected via USB
+ supporting RMNET network interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called rmnet_usb. If unsure, choose N.
+
endmenu
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index c203fa2..84228c1 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -29,4 +29,5 @@
obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o
obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o
obj-$(CONFIG_USB_VL600) += lg-vl600.o
-
+rmnet_usb-y := rmnet_usb_ctrl.o rmnet_usb_data.o
+obj-$(CONFIG_MSM_RMNET_USB) += rmnet_usb.o
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
new file mode 100644
index 0000000..b693b18
--- /dev/null
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -0,0 +1,1071 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/termios.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include "rmnet_usb_ctrl.h"
+
+#define DEVICE_NAME "hsicctl"
+#define NUM_CTRL_CHANNELS 4
+#define DEFAULT_READ_URB_LENGTH 0x1000
+
+/*Output control lines.*/
+#define ACM_CTRL_DTR BIT(0)
+#define ACM_CTRL_RTS BIT(1)
+
+
+/*Input control lines.*/
+#define ACM_CTRL_DSR BIT(0)
+#define ACM_CTRL_CTS BIT(1)
+#define ACM_CTRL_RI BIT(2)
+#define ACM_CTRL_CD BIT(3)
+
+/* polling interval for Interrupt ep */
+#define HS_INTERVAL 7
+#define FS_LS_INTERVAL 3
+
+/*echo modem_wait > /sys/class/hsicctl/hsicctlx/modem_wait*/
+static ssize_t modem_wait_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned int mdm_wait;
+ struct rmnet_ctrl_dev *dev = dev_get_drvdata(d);
+
+ if (!dev)
+ return -ENODEV;
+
+ sscanf(buf, "%u", &mdm_wait);
+
+ dev->mdm_wait_timeout = mdm_wait;
+
+ return n;
+}
+
+static ssize_t modem_wait_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct rmnet_ctrl_dev *dev = dev_get_drvdata(d);
+
+ if (!dev)
+ return -ENODEV;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", dev->mdm_wait_timeout);
+}
+
+static DEVICE_ATTR(modem_wait, 0666, modem_wait_show, modem_wait_store);
+
+static int ctl_msg_dbg_mask;
+module_param_named(dump_ctrl_msg, ctl_msg_dbg_mask, int,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+
+enum {
+ MSM_USB_CTL_DEBUG = 1U << 0,
+ MSM_USB_CTL_DUMP_BUFFER = 1U << 1,
+};
+
+#define DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+ if (ctl_msg_dbg_mask & MSM_USB_CTL_DUMP_BUFFER) \
+ print_hex_dump(KERN_INFO, prestr, DUMP_PREFIX_NONE, \
+ 16, 1, buf, cnt, false); \
+} while (0)
+
+#define DBG(x...) \
+ do { \
+ if (ctl_msg_dbg_mask & MSM_USB_CTL_DEBUG) \
+ pr_info(x); \
+ } while (0)
+
+struct rmnet_ctrl_dev *ctrl_dev[NUM_CTRL_CHANNELS];
+struct class *ctrldev_classp;
+static dev_t ctrldev_num;
+
+struct ctrl_pkt {
+ size_t data_size;
+ void *data;
+};
+
+struct ctrl_pkt_list_elem {
+ struct list_head list;
+ struct ctrl_pkt cpkt;
+};
+
+static void resp_avail_cb(struct urb *);
+
+static int is_dev_connected(struct rmnet_ctrl_dev *dev)
+{
+ if (dev) {
+ mutex_lock(&dev->dev_lock);
+ if (!dev->intf) {
+ mutex_unlock(&dev->dev_lock);
+ return 0;
+ }
+ mutex_unlock(&dev->dev_lock);
+ return 1;
+ }
+ return 0;
+}
+
+static void notification_available_cb(struct urb *urb)
+{
+ int status;
+ struct usb_cdc_notification *ctrl;
+ struct usb_device *udev;
+ struct rmnet_ctrl_dev *dev = urb->context;
+
+ udev = interface_to_usbdev(dev->intf);
+
+ switch (urb->status) {
+ case 0:
+ /*success*/
+ break;
+
+ /*do not resubmit*/
+ case -ESHUTDOWN:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPROTO:
+ return;
+ case -EPIPE:
+ pr_err_ratelimited("%s: Stall on int endpoint\n", __func__);
+ /* TBD : halt to be cleared in work */
+ return;
+
+ /*resubmit*/
+ case -EOVERFLOW:
+ pr_err_ratelimited("%s: Babble error happened\n", __func__);
+ default:
+ pr_debug_ratelimited("%s: Non zero urb status = %d\n",
+ __func__, urb->status);
+ goto resubmit_int_urb;
+ }
+
+ ctrl = urb->transfer_buffer;
+
+ switch (ctrl->bNotificationType) {
+ case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
+ dev->resp_avail_cnt++;
+ usb_fill_control_urb(dev->rcvurb, udev,
+ usb_rcvctrlpipe(udev, 0),
+ (unsigned char *)dev->in_ctlreq,
+ dev->rcvbuf,
+ DEFAULT_READ_URB_LENGTH,
+ resp_avail_cb, dev);
+
+ status = usb_submit_urb(dev->rcvurb, GFP_ATOMIC);
+ if (status) {
+ dev_err(dev->devicep,
+ "%s: Error submitting Read URB %d\n", __func__, status);
+ goto resubmit_int_urb;
+ }
+
+ if (!dev->resp_available) {
+ dev->resp_available = true;
+ wake_up(&dev->open_wait_queue);
+ }
+
+ return;
+ default:
+ dev_err(dev->devicep,
+ "%s:Command not implemented\n", __func__);
+ }
+
+resubmit_int_urb:
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status)
+ dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
+
+ return;
+}
+
+static void resp_avail_cb(struct urb *urb)
+{
+ struct usb_device *udev;
+ struct ctrl_pkt_list_elem *list_elem = NULL;
+ struct rmnet_ctrl_dev *dev = urb->context;
+ void *cpkt;
+ int status = 0;
+ size_t cpkt_size = 0;
+
+ udev = interface_to_usbdev(dev->intf);
+
+ switch (urb->status) {
+ case 0:
+ /*success*/
+ dev->get_encap_resp_cnt++;
+ break;
+
+ /*do not resubmit*/
+ case -ESHUTDOWN:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPROTO:
+ return;
+
+ /*resubmit*/
+ case -EOVERFLOW:
+ pr_err_ratelimited("%s: Babble error happened\n", __func__);
+ default:
+ pr_debug_ratelimited("%s: Non zero urb status = %d\n",
+ __func__, urb->status);
+ goto resubmit_int_urb;
+ }
+
+ dev_dbg(dev->devicep, "Read %d bytes for %s\n",
+ urb->actual_length, dev->name);
+
+ cpkt = urb->transfer_buffer;
+ cpkt_size = urb->actual_length;
+
+ list_elem = kmalloc(sizeof(struct ctrl_pkt_list_elem), GFP_ATOMIC);
+ if (!list_elem) {
+ dev_err(dev->devicep, "%s: list_elem alloc failed\n", __func__);
+ return;
+ }
+ list_elem->cpkt.data = kmalloc(cpkt_size, GFP_ATOMIC);
+ if (!list_elem->cpkt.data) {
+ dev_err(dev->devicep, "%s: list_elem->data alloc failed\n",
+ __func__);
+ kfree(list_elem);
+ return;
+ }
+ memcpy(list_elem->cpkt.data, cpkt, cpkt_size);
+ list_elem->cpkt.data_size = cpkt_size;
+ spin_lock(&dev->rx_lock);
+ list_add_tail(&list_elem->list, &dev->rx_list);
+ spin_unlock(&dev->rx_lock);
+
+ wake_up(&dev->read_wait_queue);
+
+resubmit_int_urb:
+ /*re-submit int urb to check response available*/
+ status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
+ if (status)
+ dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+ __func__, status);
+}
+
+static int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
+{
+ int retval = 0;
+
+ retval = usb_autopm_get_interface(dev->intf);
+ if (retval < 0) {
+ dev_err(dev->devicep, "%s Resumption fail\n", __func__);
+ goto done_nopm;
+ }
+
+ retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
+ if (retval < 0)
+ dev_err(dev->devicep, "%s Intr submit %d\n", __func__, retval);
+
+ usb_autopm_put_interface(dev->intf);
+
+done_nopm:
+ return retval;
+}
+
+int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *dev)
+{
+ if (!is_dev_connected(dev)) {
+ dev_dbg(dev->devicep, "%s: Ctrl device disconnected\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ dev_dbg(dev->devicep, "%s\n", __func__);
+
+ usb_kill_urb(dev->rcvurb);
+ usb_kill_urb(dev->inturb);
+
+ return 0;
+}
+
+int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *dev)
+{
+ int status = 0;
+
+ mutex_lock(&dev->dev_lock);
+ if (dev->is_opened)
+ status = rmnet_usb_ctrl_start_rx(dev);
+ mutex_unlock(&dev->dev_lock);
+
+ return status;
+}
+
+static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev)
+{
+ int retval = -ENOMEM;
+
+ dev->rcvurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->rcvurb) {
+ pr_err("%s: Error allocating read urb\n", __func__);
+ goto nomem;
+ }
+
+ dev->rcvbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL);
+ if (!dev->rcvbuf) {
+ pr_err("%s: Error allocating read buffer\n", __func__);
+ goto nomem;
+ }
+
+ dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL);
+ if (!dev->in_ctlreq) {
+ pr_err("%s: Error allocating setup packet buffer\n", __func__);
+ goto nomem;
+ }
+
+ return 0;
+
+nomem:
+ usb_free_urb(dev->rcvurb);
+ kfree(dev->rcvbuf);
+ kfree(dev->in_ctlreq);
+
+ return retval;
+
+}
+static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev)
+{
+ int retval = 0;
+ struct usb_device *udev;
+
+ if (!is_dev_connected(dev))
+ return -ENODEV;
+
+ udev = interface_to_usbdev(dev->intf);
+ retval = usb_autopm_get_interface(dev->intf);
+ if (retval < 0) {
+ dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+ __func__, retval);
+
+ /*
+ * Revisit if (retval == -EPERM)
+ * rmnet_usb_suspend(dev->intf, PMSG_SUSPEND);
+ */
+
+ return retval;
+ }
+ dev->set_ctrl_line_state_cnt++;
+ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_CDC_REQ_SET_CONTROL_LINE_STATE,
+ (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
+ dev->cbits_tomdm,
+ dev->intf->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ usb_autopm_put_interface(dev->intf);
+
+ return retval;
+}
+
+static void ctrl_write_callback(struct urb *urb)
+{
+ struct rmnet_ctrl_dev *dev = urb->context;
+
+ if (urb->status) {
+ dev->tx_ctrl_err_cnt++;
+ pr_debug_ratelimited("Write status/size %d/%d\n",
+ urb->status, urb->actual_length);
+ }
+
+ kfree(urb->setup_packet);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ usb_autopm_put_interface_async(dev->intf);
+}
+
+static int rmnet_usb_ctrl_write(struct rmnet_ctrl_dev *dev, char *buf,
+ size_t size)
+{
+ int result;
+ struct urb *sndurb;
+ struct usb_ctrlrequest *out_ctlreq;
+ struct usb_device *udev;
+
+ if (!is_dev_connected(dev))
+ return -ENETRESET;
+
+ udev = interface_to_usbdev(dev->intf);
+
+ sndurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!sndurb) {
+ dev_err(dev->devicep, "Error allocating read urb\n");
+ return -ENOMEM;
+ }
+
+ out_ctlreq = kmalloc(sizeof(*out_ctlreq), GFP_KERNEL);
+ if (!out_ctlreq) {
+ usb_free_urb(sndurb);
+ dev_err(dev->devicep, "Error allocating setup packet buffer\n");
+ return -ENOMEM;
+ }
+
+ /* CDC Send Encapsulated Request packet */
+ out_ctlreq->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE);
+ out_ctlreq->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
+ out_ctlreq->wValue = 0;
+ out_ctlreq->wIndex = dev->intf->cur_altsetting->desc.bInterfaceNumber;
+ out_ctlreq->wLength = cpu_to_le16(size);
+
+ usb_fill_control_urb(sndurb, udev,
+ usb_sndctrlpipe(udev, 0),
+ (unsigned char *)out_ctlreq, (void *)buf, size,
+ ctrl_write_callback, dev);
+
+ result = usb_autopm_get_interface_async(dev->intf);
+ if (result < 0) {
+ dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+ __func__, result);
+
+ /*
+ * Revisit: if (result == -EPERM)
+ * rmnet_usb_suspend(dev->intf, PMSG_SUSPEND);
+ */
+
+ usb_free_urb(sndurb);
+ kfree(out_ctlreq);
+ return result;
+ }
+
+ usb_anchor_urb(sndurb, &dev->tx_submitted);
+ dev->snd_encap_cmd_cnt++;
+ result = usb_submit_urb(sndurb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev->devicep, "%s: Submit URB error %d\n",
+ __func__, result);
+ dev->snd_encap_cmd_cnt--;
+ usb_autopm_put_interface_async(dev->intf);
+ usb_unanchor_urb(sndurb);
+ usb_free_urb(sndurb);
+ kfree(out_ctlreq);
+ return result;
+ }
+
+ return size;
+}
+
+static int rmnet_ctl_open(struct inode *inode, struct file *file)
+{
+ int retval = 0;
+ struct rmnet_ctrl_dev *dev =
+ container_of(inode->i_cdev, struct rmnet_ctrl_dev, cdev);
+
+ if (!dev)
+ return -ENODEV;
+
+ if (dev->is_opened)
+ goto already_opened;
+
+ctrl_open:
+ if (!is_dev_connected(dev)) {
+ dev_dbg(dev->devicep, "%s: Device not connected\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ /*block open to get first response available from mdm*/
+ if (dev->mdm_wait_timeout && !dev->resp_available) {
+ retval = wait_event_interruptible_timeout(
+ dev->open_wait_queue,
+ dev->resp_available ||
+ !is_dev_connected(dev),
+ msecs_to_jiffies(dev->mdm_wait_timeout *
+ 1000));
+ if (retval == 0) {
+ dev_err(dev->devicep, "%s: Timeout opening %s\n",
+ __func__, dev->name);
+ return -ETIMEDOUT;
+ } else if (retval < 0) {
+ dev_err(dev->devicep, "%s: Error waiting for %s\n",
+ __func__, dev->name);
+ return retval;
+ }
+
+ goto ctrl_open;
+ }
+
+ if (!dev->resp_available) {
+ dev_dbg(dev->devicep, "%s: Connection timedout opening %s\n",
+ __func__, dev->name);
+ return -ETIMEDOUT;
+ }
+
+ mutex_lock(&dev->dev_lock);
+ dev->is_opened = 1;
+ mutex_unlock(&dev->dev_lock);
+
+ file->private_data = dev;
+
+already_opened:
+ DBG("%s: Open called for %s\n", __func__, dev->name);
+
+ return 0;
+}
+
+static int rmnet_ctl_release(struct inode *inode, struct file *file)
+{
+ struct ctrl_pkt_list_elem *list_elem = NULL;
+ struct rmnet_ctrl_dev *dev;
+ unsigned long flag;
+
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ DBG("%s Called on %s device\n", __func__, dev->name);
+
+ spin_lock_irqsave(&dev->rx_lock, flag);
+ while (!list_empty(&dev->rx_list)) {
+ list_elem = list_first_entry(
+ &dev->rx_list,
+ struct ctrl_pkt_list_elem,
+ list);
+ list_del(&list_elem->list);
+ kfree(list_elem->cpkt.data);
+ kfree(list_elem);
+ }
+ spin_unlock_irqrestore(&dev->rx_lock, flag);
+
+ mutex_lock(&dev->dev_lock);
+ dev->is_opened = 0;
+ mutex_unlock(&dev->dev_lock);
+
+ rmnet_usb_ctrl_stop_rx(dev);
+
+ if (is_dev_connected(dev))
+ usb_kill_anchored_urbs(&dev->tx_submitted);
+
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ int retval = 0;
+ int bytes_to_read;
+ struct rmnet_ctrl_dev *dev;
+ struct ctrl_pkt_list_elem *list_elem = NULL;
+ unsigned long flags;
+
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ DBG("%s: Read from %s\n", __func__, dev->name);
+
+ctrl_read:
+ if (!is_dev_connected(dev)) {
+ dev_err(dev->devicep, "%s: Device not connected\n",
+ __func__);
+ return -ENETRESET;
+ }
+ spin_lock_irqsave(&dev->rx_lock, flags);
+ if (list_empty(&dev->rx_list)) {
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+ retval = wait_event_interruptible(dev->read_wait_queue,
+ !list_empty(&dev->rx_list) ||
+ !is_dev_connected(dev));
+ if (retval < 0)
+ return retval;
+
+ goto ctrl_read;
+ }
+
+ list_elem = list_first_entry(&dev->rx_list,
+ struct ctrl_pkt_list_elem, list);
+ bytes_to_read = (uint32_t)(list_elem->cpkt.data_size);
+ if (bytes_to_read > count) {
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+ dev_err(dev->devicep, "%s: Packet size %d > buf size %d\n",
+ __func__, bytes_to_read, count);
+ return -ENOMEM;
+ }
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+ if (copy_to_user(buf, list_elem->cpkt.data, bytes_to_read)) {
+ dev_err(dev->devicep,
+ "%s: copy_to_user failed for %s\n",
+ __func__, dev->name);
+ return -EFAULT;
+ }
+ spin_lock_irqsave(&dev->rx_lock, flags);
+ list_del(&list_elem->list);
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+ kfree(list_elem->cpkt.data);
+ kfree(list_elem);
+ DBG("%s: Returning %d bytes to %s\n", __func__, bytes_to_read,
+ dev->name);
+ DUMP_BUFFER("Read: ", bytes_to_read, buf);
+
+ return bytes_to_read;
+}
+
+static ssize_t rmnet_ctl_write(struct file *file, const char __user * buf,
+ size_t size, loff_t *pos)
+{
+ int status;
+ void *wbuf;
+ struct rmnet_ctrl_dev *dev = file->private_data;
+
+ if (!dev)
+ return -ENODEV;
+
+ if (size <= 0)
+ return -EINVAL;
+
+ if (!is_dev_connected(dev))
+ return -ENETRESET;
+
+ DBG("%s: Writing %i bytes on %s\n", __func__, size, dev->name);
+
+ wbuf = kmalloc(size , GFP_KERNEL);
+ if (!wbuf)
+ return -ENOMEM;
+
+ status = copy_from_user(wbuf , buf, size);
+ if (status) {
+ dev_err(dev->devicep,
+ "%s: Unable to copy data from userspace %d\n",
+ __func__, status);
+ kfree(wbuf);
+ return status;
+ }
+ DUMP_BUFFER("Write: ", size, buf);
+
+ status = rmnet_usb_ctrl_write(dev, wbuf, size);
+ if (status == size)
+ return size;
+
+ return status;
+}
+
+static int rmnet_ctrl_tiocmset(struct rmnet_ctrl_dev *dev, unsigned int set,
+ unsigned int clear)
+{
+ mutex_lock(&dev->dev_lock);
+ if (set & TIOCM_DTR)
+ dev->cbits_tomdm |= ACM_CTRL_DTR;
+
+ /*
+ * TBD if (set & TIOCM_RTS)
+ * dev->cbits_tomdm |= ACM_CTRL_RTS;
+ */
+
+ if (clear & TIOCM_DTR)
+ dev->cbits_tomdm &= ~ACM_CTRL_DTR;
+
+ /*
+ * (clear & TIOCM_RTS)
+ * dev->cbits_tomdm &= ~ACM_CTRL_RTS;
+ */
+
+ mutex_unlock(&dev->dev_lock);
+
+ return rmnet_usb_ctrl_write_cmd(dev);
+}
+
+static int rmnet_ctrl_tiocmget(struct rmnet_ctrl_dev *dev)
+{
+ int ret;
+
+ mutex_lock(&dev->dev_lock);
+ ret =
+ /*
+ * TBD(dev->cbits_tolocal & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
+ * (dev->cbits_tolocal & ACM_CTRL_CTS ? TIOCM_CTS : 0) |
+ */
+ (dev->cbits_tolocal & ACM_CTRL_CD ? TIOCM_CD : 0) |
+ /*
+ * TBD (dev->cbits_tolocal & ACM_CTRL_RI ? TIOCM_RI : 0) |
+ *(dev->cbits_tomdm & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
+ */
+ (dev->cbits_tomdm & ACM_CTRL_DTR ? TIOCM_DTR : 0);
+ mutex_unlock(&dev->dev_lock);
+
+ return ret;
+}
+
+static long rmnet_ctrl_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+ struct rmnet_ctrl_dev *dev;
+
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ switch (cmd) {
+ case TIOCMGET:
+
+ ret = rmnet_ctrl_tiocmget(dev);
+ break;
+ case TIOCMSET:
+ ret = rmnet_ctrl_tiocmset(dev, arg, ~arg);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct file_operations ctrldev_fops = {
+ .owner = THIS_MODULE,
+ .read = rmnet_ctl_read,
+ .write = rmnet_ctl_write,
+ .unlocked_ioctl = rmnet_ctrl_ioctl,
+ .open = rmnet_ctl_open,
+ .release = rmnet_ctl_release,
+};
+
+int rmnet_usb_ctrl_probe(struct usb_interface *intf,
+ struct usb_host_endpoint *int_in, struct rmnet_ctrl_dev *dev)
+{
+ u16 wMaxPacketSize;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_device *udev;
+ int interval;
+ int ret = 0;
+
+ udev = interface_to_usbdev(intf);
+
+ if (!dev) {
+ pr_err("%s: Ctrl device not found\n", __func__);
+ return -ENODEV;
+ }
+ dev->int_pipe = usb_rcvintpipe(udev,
+ int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+ mutex_lock(&dev->dev_lock);
+ dev->intf = intf;
+
+ /*TBD: for now just update CD status*/
+ dev->cbits_tolocal = ACM_CTRL_CD;
+
+ /*send DTR high to modem*/
+ dev->cbits_tomdm = ACM_CTRL_DTR;
+ mutex_unlock(&dev->dev_lock);
+
+ dev->resp_available = false;
+ dev->snd_encap_cmd_cnt = 0;
+ dev->get_encap_resp_cnt = 0;
+ dev->resp_avail_cnt = 0;
+ dev->tx_ctrl_err_cnt = 0;
+ dev->set_ctrl_line_state_cnt = 0;
+
+ dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->inturb) {
+ dev_err(dev->devicep, "Error allocating int urb\n");
+ return -ENOMEM;
+ }
+
+ /*use max pkt size from ep desc*/
+ ep = &dev->intf->cur_altsetting->endpoint[0].desc;
+ wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+
+ dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL);
+ if (!dev->intbuf) {
+ usb_free_urb(dev->inturb);
+ dev_err(dev->devicep, "Error allocating int buffer\n");
+ return -ENOMEM;
+ }
+
+ dev->in_ctlreq->bRequestType =
+ (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+ dev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+ dev->in_ctlreq->wValue = 0;
+ dev->in_ctlreq->wIndex =
+ dev->intf->cur_altsetting->desc.bInterfaceNumber;
+ dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
+
+ interval =
+ max((int)int_in->desc.bInterval,
+ (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL);
+
+ usb_fill_int_urb(dev->inturb, udev,
+ dev->int_pipe,
+ dev->intbuf, wMaxPacketSize,
+ notification_available_cb, dev, interval);
+
+ ret = rmnet_usb_ctrl_write_cmd(dev);
+ if (ret < 0)
+ return ret;
+
+ return rmnet_usb_ctrl_start_rx(dev);
+}
+
+void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev)
+{
+ rmnet_usb_ctrl_stop_rx(dev);
+
+ mutex_lock(&dev->dev_lock);
+
+ /*TBD: for now just update CD status*/
+ dev->cbits_tolocal = ~ACM_CTRL_CD;
+
+ dev->cbits_tomdm = ~ACM_CTRL_DTR;
+ dev->intf = NULL;
+ mutex_unlock(&dev->dev_lock);
+
+ usb_free_urb(dev->inturb);
+ dev->inturb = NULL;
+
+ kfree(dev->intbuf);
+ dev->intbuf = NULL;
+
+ usb_kill_anchored_urbs(&dev->tx_submitted);
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE 1024
+static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct rmnet_ctrl_dev *dev;
+ char *buf;
+ int ret;
+ int i;
+ int temp = 0;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < NUM_CTRL_CHANNELS; i++) {
+ dev = ctrl_dev[i];
+ if (!dev)
+ continue;
+
+ temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+ "\n#ctrl_dev: %p Name: %s#\n"
+ "snd encap cmd cnt %u\n"
+ "resp avail cnt: %u\n"
+ "get encap resp cnt: %u\n"
+ "set ctrl line state cnt: %u\n"
+ "tx_err_cnt: %u\n"
+ "cbits_tolocal: %d\n"
+ "cbits_tomdm: %d\n"
+ "mdm_wait_timeout: %u\n"
+ "dev opened: %s\n",
+ dev, dev->name,
+ dev->snd_encap_cmd_cnt,
+ dev->resp_avail_cnt,
+ dev->get_encap_resp_cnt,
+ dev->set_ctrl_line_state_cnt,
+ dev->tx_ctrl_err_cnt,
+ dev->cbits_tolocal,
+ dev->cbits_tomdm,
+ dev->mdm_wait_timeout,
+ dev->is_opened ? "OPEN" : "CLOSE");
+
+ }
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static ssize_t rmnet_usb_ctrl_reset_stats(struct file *file, const char __user *
+ buf, size_t count, loff_t *ppos)
+{
+ struct rmnet_ctrl_dev *dev;
+ int i;
+
+ for (i = 0; i < NUM_CTRL_CHANNELS; i++) {
+ dev = ctrl_dev[i];
+ if (!dev)
+ continue;
+
+ dev->snd_encap_cmd_cnt = 0;
+ dev->resp_avail_cnt = 0;
+ dev->get_encap_resp_cnt = 0;
+ dev->set_ctrl_line_state_cnt = 0;
+ dev->tx_ctrl_err_cnt = 0;
+ }
+ return count;
+}
+
+const struct file_operations rmnet_usb_ctrl_stats_ops = {
+ .read = rmnet_usb_ctrl_read_stats,
+ .write = rmnet_usb_ctrl_reset_stats,
+};
+
+struct dentry *usb_ctrl_dent;
+struct dentry *usb_ctrl_dfile;
+static void rmnet_usb_ctrl_debugfs_init(void)
+{
+ usb_ctrl_dent = debugfs_create_dir("rmnet_usb_ctrl", 0);
+ if (IS_ERR(usb_ctrl_dent))
+ return;
+
+ usb_ctrl_dfile = debugfs_create_file("status", 0644, usb_ctrl_dent, 0,
+ &rmnet_usb_ctrl_stats_ops);
+ if (!usb_ctrl_dfile || IS_ERR(usb_ctrl_dfile))
+ debugfs_remove(usb_ctrl_dent);
+}
+
+static void rmnet_usb_ctrl_debugfs_exit(void)
+{
+ debugfs_remove(usb_ctrl_dfile);
+ debugfs_remove(usb_ctrl_dent);
+}
+
+#else
+static void rmnet_usb_ctrl_debugfs_init(void) { }
+static void rmnet_usb_ctrl_debugfs_exit(void) { }
+#endif
+
+int rmnet_usb_ctrl_init(void)
+{
+ struct rmnet_ctrl_dev *dev;
+ int n;
+ int status;
+
+ for (n = 0; n < NUM_CTRL_CHANNELS; ++n) {
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ status = -ENOMEM;
+ goto error0;
+ }
+ /*for debug purpose*/
+ snprintf(dev->name, CTRL_DEV_MAX_LEN, "hsicctl%d", n);
+
+ mutex_init(&dev->dev_lock);
+ spin_lock_init(&dev->rx_lock);
+ init_waitqueue_head(&dev->read_wait_queue);
+ init_waitqueue_head(&dev->open_wait_queue);
+ INIT_LIST_HEAD(&dev->rx_list);
+ init_usb_anchor(&dev->tx_submitted);
+
+ status = rmnet_usb_ctrl_alloc_rx(dev);
+ if (status < 0) {
+ kfree(dev);
+ goto error0;
+ }
+
+ ctrl_dev[n] = dev;
+ }
+
+ status = alloc_chrdev_region(&ctrldev_num, 0, NUM_CTRL_CHANNELS,
+ DEVICE_NAME);
+ if (IS_ERR_VALUE(status)) {
+ pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n",
+ __func__, status);
+ goto error0;
+ }
+
+ ctrldev_classp = class_create(THIS_MODULE, DEVICE_NAME);
+ if (IS_ERR(ctrldev_classp)) {
+ pr_err("ERROR:%s: class_create() ENOMEM\n", __func__);
+ status = -ENOMEM;
+ goto error1;
+ }
+ for (n = 0; n < NUM_CTRL_CHANNELS; ++n) {
+ cdev_init(&ctrl_dev[n]->cdev, &ctrldev_fops);
+ ctrl_dev[n]->cdev.owner = THIS_MODULE;
+
+ status = cdev_add(&ctrl_dev[n]->cdev, (ctrldev_num + n), 1);
+
+ if (IS_ERR_VALUE(status)) {
+ pr_err("%s: cdev_add() ret %i\n", __func__, status);
+ kfree(ctrl_dev[n]);
+ goto error2;
+ }
+
+ ctrl_dev[n]->devicep =
+ device_create(ctrldev_classp, NULL,
+ (ctrldev_num + n), NULL,
+ DEVICE_NAME "%d", n);
+
+ if (IS_ERR(ctrl_dev[n]->devicep)) {
+ pr_err("%s: device_create() ENOMEM\n", __func__);
+ status = -ENOMEM;
+ cdev_del(&ctrl_dev[n]->cdev);
+ kfree(ctrl_dev[n]);
+ goto error2;
+ }
+ /*create /sys/class/hsicctl/hsicctlx/modem_wait*/
+ status = device_create_file(ctrl_dev[n]->devicep,
+ &dev_attr_modem_wait);
+ if (status) {
+ device_destroy(ctrldev_classp,
+ MKDEV(MAJOR(ctrldev_num), n));
+ cdev_del(&ctrl_dev[n]->cdev);
+ kfree(ctrl_dev[n]);
+ goto error2;
+ }
+ dev_set_drvdata(ctrl_dev[n]->devicep, ctrl_dev[n]);
+ }
+
+ rmnet_usb_ctrl_debugfs_init();
+ pr_info("rmnet usb ctrl Initialized.\n");
+ return 0;
+
+error2:
+ while (--n >= 0) {
+ cdev_del(&ctrl_dev[n]->cdev);
+ device_destroy(ctrldev_classp,
+ MKDEV(MAJOR(ctrldev_num), n));
+ }
+
+ class_destroy(ctrldev_classp);
+ n = NUM_CTRL_CHANNELS;
+error1:
+ unregister_chrdev_region(MAJOR(ctrldev_num), NUM_CTRL_CHANNELS);
+error0:
+ while (--n >= 0)
+ kfree(ctrl_dev[n]);
+
+ return status;
+}
+
+void rmnet_usb_ctrl_exit(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_CTRL_CHANNELS; ++i) {
+ if (!ctrl_dev[i])
+ return;
+
+ kfree(ctrl_dev[i]->in_ctlreq);
+ kfree(ctrl_dev[i]->rcvbuf);
+ kfree(ctrl_dev[i]->intbuf);
+ usb_free_urb(ctrl_dev[i]->rcvurb);
+ usb_free_urb(ctrl_dev[i]->inturb);
+#if defined(DEBUG)
+ device_remove_file(ctrl_dev[i]->devicep, &dev_attr_modem_wait);
+#endif
+ cdev_del(&ctrl_dev[i]->cdev);
+ kfree(ctrl_dev[i]);
+ ctrl_dev[i] = NULL;
+ device_destroy(ctrldev_classp, MKDEV(MAJOR(ctrldev_num), i));
+ }
+
+ class_destroy(ctrldev_classp);
+ unregister_chrdev_region(MAJOR(ctrldev_num), NUM_CTRL_CHANNELS);
+ rmnet_usb_ctrl_debugfs_exit();
+}
diff --git a/drivers/net/usb/rmnet_usb_ctrl.h b/drivers/net/usb/rmnet_usb_ctrl.h
new file mode 100644
index 0000000..f6e5876
--- /dev/null
+++ b/drivers/net/usb/rmnet_usb_ctrl.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __RMNET_USB_CTRL_H
+#define __RMNET_USB_CTRL_H
+
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/cdev.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+
+#define CTRL_DEV_MAX_LEN 10
+
+struct rmnet_ctrl_dev {
+
+ /*for debugging purpose*/
+ char name[CTRL_DEV_MAX_LEN];
+
+ struct cdev cdev;
+ struct device *devicep;
+
+ struct usb_interface *intf;
+ unsigned int int_pipe;
+ struct urb *rcvurb;
+ struct urb *inturb;
+ struct usb_anchor tx_submitted;
+ void *rcvbuf;
+ void *intbuf;
+ struct usb_ctrlrequest *in_ctlreq;
+
+ spinlock_t rx_lock;
+ struct mutex dev_lock;
+ struct list_head rx_list;
+ wait_queue_head_t read_wait_queue;
+ wait_queue_head_t open_wait_queue;
+
+ unsigned is_opened;
+
+ /*input control lines (DSR, CTS, CD, RI)*/
+ unsigned int cbits_tolocal;
+
+ /*output control lines (DTR, RTS)*/
+ unsigned int cbits_tomdm;
+
+ /*
+ * track first resp available from mdm when it boots up
+ * to avoid bigger timeout value used by qmuxd
+ */
+ bool resp_available;
+
+ unsigned int mdm_wait_timeout;
+
+ /*counters*/
+ unsigned int snd_encap_cmd_cnt;
+ unsigned int get_encap_resp_cnt;
+ unsigned int resp_avail_cnt;
+ unsigned int set_ctrl_line_state_cnt;
+ unsigned int tx_ctrl_err_cnt;
+};
+
+extern struct rmnet_ctrl_dev *ctrl_dev[];
+
+extern int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *);
+extern int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *);
+extern int rmnet_usb_ctrl_init(void);
+extern void rmnet_usb_ctrl_exit(void);
+extern int rmnet_usb_ctrl_probe(struct usb_interface *intf,
+ struct usb_host_endpoint *status,
+ struct rmnet_ctrl_dev *dev);
+extern void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *);
+
+#endif /* __RMNET_USB_H*/
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
new file mode 100644
index 0000000..fa0cd82
--- /dev/null
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -0,0 +1,564 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mii.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/usb/usbnet.h>
+#include <linux/msm_rmnet.h>
+
+#include "rmnet_usb_ctrl.h"
+
+#define RMNET_DATA_LEN 2000
+#define HEADROOM_FOR_QOS 8
+
+#define FIRST_RMNET_USB_INTERFACE 5
+#define NUM_EMBEDDED_RMNET_IFACE 4
+
+static int data_msg_dbg_mask;
+
+enum {
+ DEBUG_MASK_LVL0 = 1U << 0,
+ DEBUG_MASK_LVL1 = 1U << 1,
+ DEBUG_MASK_LVL2 = 1U << 2,
+};
+
+#define DBG(m, x...) do { \
+ if (data_msg_dbg_mask & m) \
+ pr_info(x); \
+} while (0)
+
+/*echo dbg_mask > /sys/class/net/rmnet_usbx/dbg_mask*/
+static ssize_t dbg_mask_store(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned int dbg_mask;
+ struct net_device *dev = to_net_dev(d);
+ struct usbnet *unet = netdev_priv(dev);
+
+ if (!dev)
+ return -ENODEV;
+
+ sscanf(buf, "%u", &dbg_mask);
+ /*enable dbg msgs for data driver*/
+ data_msg_dbg_mask = dbg_mask;
+
+ /*set default msg level*/
+ unet->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK;
+
+ /*enable netif_xxx msgs*/
+ if (dbg_mask & DEBUG_MASK_LVL0)
+ unet->msg_enable |= NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+ if (dbg_mask & DEBUG_MASK_LVL1)
+ unet->msg_enable |= NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
+ | NETIF_MSG_TX_QUEUED | NETIF_MSG_TX_DONE
+ | NETIF_MSG_RX_STATUS;
+
+ return n;
+}
+
+static ssize_t dbg_mask_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", data_msg_dbg_mask);
+}
+
+static DEVICE_ATTR(dbg_mask, 0644, dbg_mask_show, dbg_mask_store);
+
+#define DBG0(x...) DBG(DEBUG_MASK_LVL0, x)
+#define DBG1(x...) DBG(DEBUG_MASK_LVL1, x)
+#define DBG2(x...) DBG(DEBUG_MASK_LVL2, x)
+
+static void rmnet_usb_setup(struct net_device *);
+static int rmnet_ioctl(struct net_device *, struct ifreq *, int);
+
+static int rmnet_usb_suspend(struct usb_interface *iface, pm_message_t message)
+{
+ struct usbnet *unet;
+ struct rmnet_ctrl_dev *dev;
+ int time = 0;
+ int retval = 0;
+
+ unet = usb_get_intfdata(iface);
+ if (!unet) {
+ pr_err("%s:data device not found\n", __func__);
+ retval = -ENODEV;
+ goto fail;
+ }
+
+ dev = (struct rmnet_ctrl_dev *)unet->data[1];
+ if (!dev) {
+ dev_err(&unet->udev->dev, "%s: ctrl device not found\n",
+ __func__);
+ retval = -ENODEV;
+ goto fail;
+ }
+
+ retval = usbnet_suspend(iface, message);
+ if (!retval) {
+ if (message.event & PM_EVENT_SUSPEND) {
+ time = usb_wait_anchor_empty_timeout(&dev->tx_submitted,
+ 1000);
+ if (!time)
+ usb_kill_anchored_urbs(&dev->tx_submitted);
+
+ retval = rmnet_usb_ctrl_stop_rx(dev);
+ iface->dev.power.power_state.event = message.event;
+ }
+ /* TBD : do we need to set/clear usbnet->udev->reset_resume*/
+ } else
+ dev_dbg(&unet->udev->dev,
+ "%s: device is busy can not suspend\n", __func__);
+
+fail:
+ return retval;
+}
+
+static int rmnet_usb_resume(struct usb_interface *iface)
+{
+ int retval = 0;
+ int oldstate;
+ struct usbnet *unet;
+ struct rmnet_ctrl_dev *dev;
+
+ unet = usb_get_intfdata(iface);
+ if (!unet) {
+ pr_err("%s:data device not found\n", __func__);
+ retval = -ENODEV;
+ goto fail;
+ }
+
+ dev = (struct rmnet_ctrl_dev *)unet->data[1];
+ if (!dev) {
+ dev_err(&unet->udev->dev, "%s: ctrl device not found\n",
+ __func__);
+ retval = -ENODEV;
+ goto fail;
+ }
+ oldstate = iface->dev.power.power_state.event;
+ iface->dev.power.power_state.event = PM_EVENT_ON;
+
+ retval = usbnet_resume(iface);
+ if (!retval) {
+
+ if (oldstate & PM_EVENT_SUSPEND)
+ retval = rmnet_usb_ctrl_start(dev);
+ }
+fail:
+ return retval;
+}
+
+static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface)
+{
+ struct usb_host_endpoint *endpoint = NULL;
+ struct usb_host_endpoint *bulk_in = NULL;
+ struct usb_host_endpoint *bulk_out = NULL;
+ struct usb_host_endpoint *int_in = NULL;
+ struct usb_device *udev;
+ int status = 0;
+ int i;
+ int numends;
+
+ udev = interface_to_usbdev(iface);
+ numends = iface->cur_altsetting->desc.bNumEndpoints;
+ for (i = 0; i < numends; i++) {
+ endpoint = iface->cur_altsetting->endpoint + i;
+ if (!endpoint) {
+ dev_err(&udev->dev, "%s: invalid endpoint %u\n",
+ __func__, i);
+ status = -EINVAL;
+ goto out;
+ }
+ if (usb_endpoint_is_bulk_in(&endpoint->desc))
+ bulk_in = endpoint;
+ else if (usb_endpoint_is_bulk_out(&endpoint->desc))
+ bulk_out = endpoint;
+ else if (usb_endpoint_is_int_in(&endpoint->desc))
+ int_in = endpoint;
+ }
+
+ if (!bulk_in || !bulk_out || !int_in) {
+ dev_err(&udev->dev, "%s: invalid endpoints\n", __func__);
+ status = -EINVAL;
+ goto out;
+ }
+ usbnet->in = usb_rcvbulkpipe(usbnet->udev,
+ bulk_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usbnet->out = usb_sndbulkpipe(usbnet->udev,
+ bulk_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usbnet->status = int_in;
+
+ /*change name of net device to rmnet_usbx here*/
+ strlcpy(usbnet->net->name, "rmnet_usb%d", IFNAMSIZ);
+
+ /*TBD: update rx_urb_size, curently set to eth frame len by usbnet*/
+out:
+ return status;
+}
+
+static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev,
+ struct sk_buff *skb, gfp_t flags)
+{
+ struct QMI_QOS_HDR_S *qmih;
+
+ if (test_bit(RMNET_MODE_QOS, &dev->data[0])) {
+ qmih = (struct QMI_QOS_HDR_S *)
+ skb_push(skb, sizeof(struct QMI_QOS_HDR_S));
+ qmih->version = 1;
+ qmih->flags = 0;
+ qmih->flow_id = skb->mark;
+ }
+
+ DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+ dev->net->name, dev->net->stats.tx_packets, skb->len, skb->mark);
+
+ return skb;
+}
+
+static __be16 rmnet_ip_type_trans(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ __be16 protocol = 0;
+
+ skb->dev = dev;
+
+ switch (skb->data[0] & 0xf0) {
+ case 0x40:
+ protocol = htons(ETH_P_IP);
+ break;
+ case 0x60:
+ protocol = htons(ETH_P_IPV6);
+ break;
+ default:
+ pr_err("[%s] rmnet_recv() L3 protocol decode error: 0x%02x",
+ dev->name, skb->data[0] & 0xf0);
+ }
+
+ return protocol;
+}
+
+static int rmnet_usb_rx_fixup(struct usbnet *dev,
+ struct sk_buff *skb)
+{
+
+ if (test_bit(RMNET_MODE_LLP_IP, &dev->data[0]))
+ skb->protocol = rmnet_ip_type_trans(skb, dev->net);
+ else /*set zero for eth mode*/
+ skb->protocol = 0;
+
+ DBG1("[%s] Rx packet #%lu len=%d\n",
+ dev->net->name, dev->net->stats.rx_packets, skb->len);
+
+ return 1;
+}
+
+static int rmnet_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (0 > new_mtu || RMNET_DATA_LEN < new_mtu)
+ return -EINVAL;
+
+ DBG0("[%s] MTU change: old=%d new=%d\n", dev->name, dev->mtu, new_mtu);
+
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+static struct net_device_stats *rmnet_get_stats(struct net_device *dev)
+{
+ return &dev->stats;
+}
+
+static const struct net_device_ops rmnet_usb_ops_ether = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_get_stats = rmnet_get_stats,
+ /*.ndo_set_multicast_list = rmnet_set_multicast_list,*/
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_do_ioctl = rmnet_ioctl,
+ .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static const struct net_device_ops rmnet_usb_ops_ip = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_get_stats = rmnet_get_stats,
+ /*.ndo_set_multicast_list = rmnet_set_multicast_list,*/
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_do_ioctl = rmnet_ioctl,
+ .ndo_change_mtu = rmnet_change_mtu,
+ .ndo_set_mac_address = 0,
+ .ndo_validate_addr = 0,
+};
+
+
+static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct usbnet *unet = netdev_priv(dev);
+ u32 old_opmode;
+ int prev_mtu = dev->mtu;
+ int rc = 0;
+
+ old_opmode = unet->data[0]; /*data[0] saves operation mode*/
+ /* Process IOCTL command */
+ switch (cmd) {
+ case RMNET_IOCTL_SET_LLP_ETHERNET: /*Set Ethernet protocol*/
+ /* Perform Ethernet config only if in IP mode currently*/
+ if (test_bit(RMNET_MODE_LLP_IP, &unet->data[0])) {
+ ether_setup(dev);
+ random_ether_addr(dev->dev_addr);
+ dev->mtu = prev_mtu;
+ dev->netdev_ops = &rmnet_usb_ops_ether;
+ clear_bit(RMNET_MODE_LLP_IP, &unet->data[0]);
+ set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
+ DBG0("[%s] rmnet_ioctl(): set Ethernet protocol mode\n",
+ dev->name);
+ }
+ break;
+
+ case RMNET_IOCTL_SET_LLP_IP: /* Set RAWIP protocol*/
+ /* Perform IP config only if in Ethernet mode currently*/
+ if (test_bit(RMNET_MODE_LLP_ETH, &unet->data[0])) {
+
+ /* Undo config done in ether_setup() */
+ dev->header_ops = 0; /* No header */
+ dev->type = ARPHRD_RAWIP;
+ dev->hard_header_len = 0;
+ dev->mtu = prev_mtu;
+ dev->addr_len = 0;
+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+ dev->needed_headroom = HEADROOM_FOR_QOS;
+ dev->netdev_ops = &rmnet_usb_ops_ip;
+ clear_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
+ set_bit(RMNET_MODE_LLP_IP, &unet->data[0]);
+ DBG0("[%s] rmnet_ioctl(): set IP protocol mode\n",
+ dev->name);
+ }
+ break;
+
+ case RMNET_IOCTL_GET_LLP: /* Get link protocol state */
+ ifr->ifr_ifru.ifru_data = (void *)(unet->data[0]
+ & (RMNET_MODE_LLP_ETH
+ | RMNET_MODE_LLP_IP));
+ break;
+
+ case RMNET_IOCTL_SET_QOS_ENABLE: /* Set QoS header enabled*/
+ set_bit(RMNET_MODE_QOS, &unet->data[0]);
+ DBG0("[%s] rmnet_ioctl(): set QMI QOS header enable\n",
+ dev->name);
+ break;
+
+ case RMNET_IOCTL_SET_QOS_DISABLE: /* Set QoS header disabled */
+ clear_bit(RMNET_MODE_QOS, &unet->data[0]);
+ DBG0("[%s] rmnet_ioctl(): set QMI QOS header disable\n",
+ dev->name);
+ break;
+
+ case RMNET_IOCTL_GET_QOS: /* Get QoS header state */
+ ifr->ifr_ifru.ifru_data = (void *)(unet->data[0]
+ & RMNET_MODE_QOS);
+ break;
+
+ case RMNET_IOCTL_GET_OPMODE: /* Get operation mode*/
+ ifr->ifr_ifru.ifru_data = (void *)unet->data[0];
+ break;
+
+ case RMNET_IOCTL_OPEN: /* Open transport port */
+ rc = usbnet_open(dev);
+ DBG0("[%s] rmnet_ioctl(): open transport port\n", dev->name);
+ break;
+
+ case RMNET_IOCTL_CLOSE: /* Close transport port*/
+ rc = usbnet_stop(dev);
+ DBG0("[%s] rmnet_ioctl(): close transport port\n", dev->name);
+ break;
+
+ default:
+ dev_err(&unet->udev->dev, "[%s] error: "
+ "rmnet_ioct called for unsupported cmd[%d]",
+ dev->name, cmd);
+ return -EINVAL;
+ }
+
+ DBG2("[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08lx\n",
+ dev->name, __func__, cmd, old_opmode, unet->data[0]);
+
+ return rc;
+}
+
+static void rmnet_usb_setup(struct net_device *dev)
+{
+ /* Using Ethernet mode by default */
+ dev->netdev_ops = &rmnet_usb_ops_ether;
+
+ /* set this after calling ether_setup */
+ dev->mtu = RMNET_DATA_LEN;
+
+ dev->needed_headroom = HEADROOM_FOR_QOS;
+ random_ether_addr(dev->dev_addr);
+ dev->watchdog_timeo = 1000; /* 10 seconds? */
+}
+
+static int rmnet_usb_probe(struct usb_interface *iface,
+ const struct usb_device_id *prod)
+{
+ struct usbnet *unet;
+ struct usb_device *udev;
+ int iface_num;
+ int last_rmnet_iface_num;
+ int status = -ENODEV;
+
+ udev = interface_to_usbdev(iface);
+ iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+ if (iface->num_altsetting != 1) {
+ dev_err(&udev->dev, "%s invalid num_altsetting %u\n",
+ __func__, iface->num_altsetting);
+ status = -EINVAL;
+ goto out;
+ }
+
+ last_rmnet_iface_num = (FIRST_RMNET_USB_INTERFACE +
+ NUM_EMBEDDED_RMNET_IFACE - 1);
+
+ if (iface_num >= FIRST_RMNET_USB_INTERFACE &&
+ iface_num <= last_rmnet_iface_num) {
+ status = usbnet_probe(iface, prod);
+ if (status < 0) {
+ dev_err(&udev->dev, "usbnet_probe failed %d\n",
+ status);
+ goto out;
+ }
+ unet = usb_get_intfdata(iface);
+
+ /*set rmnet operation mode to eth by default*/
+ set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
+
+ /*update net device*/
+ rmnet_usb_setup(unet->net);
+
+ /*create /sys/class/net/rmnet_usbx/dbg_mask*/
+ status = device_create_file(&unet->net->dev,
+ &dev_attr_dbg_mask);
+ if (status)
+ goto out;
+
+ /*save control device intstance */
+ unet->data[1] = (unsigned long)ctrl_dev \
+ [iface_num - FIRST_RMNET_USB_INTERFACE];
+
+ status = rmnet_usb_ctrl_probe(iface, unet->status,
+ (struct rmnet_ctrl_dev *)unet->data[1]);
+ }
+out:
+ return status;
+}
+
+static void rmnet_usb_disconnect(struct usb_interface *intf)
+{
+ struct usbnet *unet;
+ struct usb_device *udev;
+ struct rmnet_ctrl_dev *dev;
+ int iface_num;
+ int last_rmnet_iface_num;
+
+ udev = interface_to_usbdev(intf);
+ iface_num = intf->cur_altsetting->desc.bInterfaceNumber;
+
+ last_rmnet_iface_num = (FIRST_RMNET_USB_INTERFACE +
+ NUM_EMBEDDED_RMNET_IFACE - 1);
+
+ if (iface_num >= FIRST_RMNET_USB_INTERFACE &&
+ iface_num <= last_rmnet_iface_num) {
+ unet = usb_get_intfdata(intf);
+ if (!unet) {
+ dev_err(&udev->dev, "%s:data device not found\n",
+ __func__);
+ return;
+ }
+ dev = (struct rmnet_ctrl_dev *)unet->data[1];
+ if (!dev) {
+ dev_err(&udev->dev, "%s:ctrl device not found\n",
+ __func__);
+ return;
+ }
+ unet->data[0] = 0;
+ unet->data[1] = 0;
+ rmnet_usb_ctrl_disconnect(dev);
+ device_remove_file(&unet->net->dev, &dev_attr_dbg_mask);
+ usbnet_disconnect(intf);
+ }
+}
+
+static const struct driver_info rmnet_info = {
+ .description = "RmNET net device",
+ .bind = rmnet_usb_bind,
+ .tx_fixup = rmnet_usb_tx_fixup,
+ .rx_fixup = rmnet_usb_rx_fixup,
+ .data = 0,
+};
+
+static const struct usb_device_id vidpids[] = {
+ {
+ USB_DEVICE(0x05c6, 0x9048), /* MDM9x15*/
+ .driver_info = (unsigned long)&rmnet_info,
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(usb, vidpids);
+
+static struct usb_driver rmnet_usb = {
+ .name = "rmnet_usb",
+ .id_table = vidpids,
+ .probe = rmnet_usb_probe,
+ .disconnect = rmnet_usb_disconnect,
+ .suspend = rmnet_usb_suspend,
+ .resume = rmnet_usb_resume,
+ .supports_autosuspend = true,
+};
+
+static int __init rmnet_usb_init(void)
+{
+ int retval;
+
+ retval = usb_register(&rmnet_usb);
+ if (retval) {
+ err("usb_register failed: %d", retval);
+ return retval;
+ }
+ /* initialize rmnet ctrl device here*/
+ retval = rmnet_usb_ctrl_init();
+ if (retval) {
+ usb_deregister(&rmnet_usb);
+ err("rmnet_usb_cmux_init failed: %d", retval);
+ return retval;
+ }
+
+ return 0;
+}
+module_init(rmnet_usb_init);
+
+static void __exit rmnet_usb_exit(void)
+{
+ rmnet_usb_ctrl_exit();
+ usb_deregister(&rmnet_usb);
+}
+module_exit(rmnet_usb_exit);
+
+MODULE_DESCRIPTION("msm rmnet usb device");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ce395fe..dce8d6d 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -231,6 +231,9 @@
return;
}
+ if (!skb->protocol)
+ skb->protocol = eth_type_trans(skb, dev->net);
+
skb->protocol = eth_type_trans (skb, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index df2d556..0af181b 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1063,12 +1063,6 @@
soc = 100;
pr_debug("SOC = %u%%\n", soc);
- if (bms_fake_battery) {
- soc = BATTERY_POWER_SUPPLY_SOC;
- pr_debug("setting SOC = %u%% bms_fake_battery = %d\n", soc,
- bms_fake_battery);
- }
-
if (soc < 0) {
pr_err("bad rem_usb_chg = %d rem_chg %d,"
"cc_mah %d, unusb_chg %d\n",
@@ -1085,7 +1079,7 @@
if (last_soc == -EINVAL || soc <= last_soc) {
last_soc = update_userspace ? soc : last_soc;
- return soc;
+ return bms_fake_battery ? BATTERY_POWER_SUPPLY_SOC : soc;
}
/*
@@ -1093,27 +1087,14 @@
* the device must be charging for reporting a higher soc, if not ignore
* this soc and continue reporting the last_soc
*/
- if (the_chip->start_percent != 0) {
+ if (the_chip->start_percent != -EINVAL) {
last_soc = soc;
} else {
pr_debug("soc = %d reporting last_soc = %d\n", soc, last_soc);
soc = last_soc;
}
- return soc;
-}
-
-#define XOADC_MAX_1P25V 1312500
-#define XOADC_MIN_1P25V 1187500
-#define XOADC_MAX_0P625V 656250
-#define XOADC_MIN_0P625V 593750
-
-#define HKADC_V_PER_BIT_MUL_FACTOR 977
-#define HKADC_V_PER_BIT_DIV_FACTOR 10
-static int calib_hkadc_convert_microvolt(unsigned int phy)
-{
- return (phy - 0x6000) *
- HKADC_V_PER_BIT_MUL_FACTOR / HKADC_V_PER_BIT_DIV_FACTOR;
+ return bms_fake_battery ? BATTERY_POWER_SUPPLY_SOC : soc;
}
static void calib_hkadc(struct pm8921_bms_chip *chip)
@@ -1126,16 +1107,11 @@
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
return;
}
- voltage = calib_hkadc_convert_microvolt(result.adc_code);
+ voltage = xoadc_reading_to_microvolt(result.adc_code);
pr_debug("result 1.25v = 0x%x, voltage = %duV adc_meas = %lld\n",
result.adc_code, voltage, result.measurement);
- /* check for valid range */
- if (voltage > XOADC_MAX_1P25V)
- voltage = XOADC_MAX_1P25V;
- else if (voltage < XOADC_MIN_1P25V)
- voltage = XOADC_MIN_1P25V;
chip->xoadc_v125 = voltage;
rc = pm8xxx_adc_read(the_chip->ref625mv_channel, &result);
@@ -1143,14 +1119,9 @@
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
return;
}
- voltage = calib_hkadc_convert_microvolt(result.adc_code);
+ voltage = xoadc_reading_to_microvolt(result.adc_code);
pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld\n",
result.adc_code, voltage, result.measurement);
- /* check for valid range */
- if (voltage > XOADC_MAX_0P625V)
- voltage = XOADC_MAX_0P625V;
- else if (voltage < XOADC_MIN_0P625V)
- voltage = XOADC_MIN_0P625V;
chip->xoadc_v0625 = voltage;
}
@@ -1369,8 +1340,8 @@
the_chip->end_percent,
last_charge_increase,
last_chargecycles);
- the_chip->start_percent = 0;
- the_chip->end_percent = 0;
+ the_chip->start_percent = -EINVAL;
+ the_chip->end_percent = -EINVAL;
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
@@ -1854,6 +1825,8 @@
chip->v_failure = pdata->v_failure;
chip->calib_delay_ms = pdata->calib_delay_ms;
chip->max_voltage_uv = pdata->max_voltage_uv;
+ chip->start_percent = -EINVAL;
+ chip->end_percent = -EINVAL;
rc = set_battery_data(chip);
if (rc) {
pr_err("%s bad battery data %d\n", __func__, rc);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index ef97389..ea50ae9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1334,6 +1334,69 @@
return pm_chg_vinmin_set(the_chip, voltage);
}
+#define USB_OV_THRESHOLD_MASK 0x60
+#define USB_OV_THRESHOLD_SHIFT 5
+int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
+{
+ u8 temp;
+
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+
+ if (ov > PM_USB_OV_7V) {
+ pr_err("limiting to over voltage threshold to 7volts\n");
+ ov = PM_USB_OV_7V;
+ }
+
+ temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
+
+ return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
+ USB_OV_THRESHOLD_MASK, temp);
+}
+EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
+
+#define USB_DEBOUNCE_TIME_MASK 0x06
+#define USB_DEBOUNCE_TIME_SHIFT 1
+int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
+{
+ u8 temp;
+
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+
+ if (ms > PM_USB_DEBOUNCE_80P5MS) {
+ pr_err("limiting debounce to 80.5ms\n");
+ ms = PM_USB_DEBOUNCE_80P5MS;
+ }
+
+ temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
+
+ return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
+ USB_DEBOUNCE_TIME_MASK, temp);
+}
+EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
+
+#define USB_OVP_DISABLE_MASK 0x80
+int pm8921_usb_ovp_disable(int disable)
+{
+ u8 temp = 0;
+
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+
+ if (disable)
+ temp = USB_OVP_DISABLE_MASK;
+
+ return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
+ USB_OVP_DISABLE_MASK, temp);
+}
+
bool pm8921_is_battery_charging(int *source)
{
int fsm_state, is_charging, dc_present, usb_present;
@@ -1975,7 +2038,7 @@
if (chip->is_bat_warm)
chg_current = min(chg_current, chip->warm_bat_chg_current);
- if (thermal_mitigation != 0 && !chip->thermal_mitigation)
+ if (thermal_mitigation != 0 && chip->thermal_mitigation)
chg_current = min(chg_current,
chip->thermal_mitigation[thermal_mitigation]);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8eb443f..49e0d0e9 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -317,15 +317,14 @@
help
Say Y here to support the voltage regulators on PMIC8901
-config REGULATOR_PM8921
- tristate "Qualcomm PM8921 PMIC Power regulators"
- depends on MFD_PM8921_CORE
- default y if MFD_PM8921_CORE
+config REGULATOR_PM8XXX
+ tristate "Qualcomm PM8XXX PMIC Voltage regulators"
+ depends on MFD_PM8XXX
help
- This driver supports voltage regulators in the Qualcomm PM8921 PMIC
- chip. The PM8921 provides several different varieties of LDO and
- switching regulators. It also provides a negative charge pump and
- voltage switches.
+ This driver supports voltage regulators in Qualcomm PM8XXX PMIC chips.
+ PM8XXX chips provide several different varieties of LDO and switching
+ regulators. They also provide negative charge pumps and voltage
+ switches.
config REGULATOR_GPIO
tristate "GPIO regulator"
@@ -345,14 +344,5 @@
chip. It is only supposed to be used when Linux on application
processor is the master in control of XO buffers.
-config REGULATOR_PM8018
- tristate "Qualcomm PM8018 PMIC Power regulators"
- depends on MFD_PM8018_CORE
- default y if MFD_PM8018_CORE
- help
- This driver supports voltage regulators in the Qualcomm PM8018 PMIC
- chip. The PM8018 provides several different varieties of LDO and
- switching regulators. It also provides a voltage switch.
-
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4e5fd66..5318cff 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -45,9 +45,8 @@
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_PMIC8058) += pmic8058-regulator.o
obj-$(CONFIG_REGULATOR_PMIC8901) += pmic8901-regulator.o
-obj-$(CONFIG_REGULATOR_PM8921) += pm8921-regulator.o
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_PM8058_XO) += pm8058-xo.o
-obj-$(CONFIG_REGULATOR_PM8018) += pm8018-regulator.o
+obj-$(CONFIG_REGULATOR_PM8XXX) += pm8xxx-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/pm8018-regulator.c b/drivers/regulator/pm8018-regulator.c
deleted file mode 100644
index 2f31cbb..0000000
--- a/drivers/regulator/pm8018-regulator.c
+++ /dev/null
@@ -1,2590 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/pm8018-regulator.h>
-#include <linux/mfd/pm8xxx/core.h>
-
-/* Debug Flag Definitions */
-enum {
- PM8018_VREG_DEBUG_REQUEST = BIT(0),
- PM8018_VREG_DEBUG_DUPLICATE = BIT(1),
- PM8018_VREG_DEBUG_INIT = BIT(2),
- PM8018_VREG_DEBUG_WRITES = BIT(3), /* SSBI writes */
-};
-
-static int pm8018_vreg_debug_mask;
-module_param_named(
- debug_mask, pm8018_vreg_debug_mask, int, S_IRUSR | S_IWUSR
-);
-
-#define REGULATOR_TYPE_PLDO 0
-#define REGULATOR_TYPE_NLDO 1
-#define REGULATOR_TYPE_NLDO1200 2
-#define REGULATOR_TYPE_SMPS 3
-#define REGULATOR_TYPE_VS 4
-
-/* Common Masks */
-#define REGULATOR_ENABLE_MASK 0x80
-#define REGULATOR_ENABLE 0x80
-#define REGULATOR_DISABLE 0x00
-
-#define REGULATOR_BANK_MASK 0xF0
-#define REGULATOR_BANK_SEL(n) ((n) << 4)
-#define REGULATOR_BANK_WRITE 0x80
-
-#define LDO_TEST_BANKS 7
-#define NLDO1200_TEST_BANKS 5
-#define SMPS_TEST_BANKS 8
-#define REGULATOR_TEST_BANKS_MAX SMPS_TEST_BANKS
-
-/*
- * This voltage in uV is returned by get_voltage functions when there is no way
- * to determine the current voltage level. It is needed because the regulator
- * framework treats a 0 uV voltage as an error.
- */
-#define VOLTAGE_UNKNOWN 1
-
-/* LDO masks and values */
-
-/* CTRL register */
-#define LDO_ENABLE_MASK 0x80
-#define LDO_DISABLE 0x00
-#define LDO_ENABLE 0x80
-#define LDO_PULL_DOWN_ENABLE_MASK 0x40
-#define LDO_PULL_DOWN_ENABLE 0x40
-
-#define LDO_CTRL_PM_MASK 0x20
-#define LDO_CTRL_PM_HPM 0x00
-#define LDO_CTRL_PM_LPM 0x20
-
-#define LDO_CTRL_VPROG_MASK 0x1F
-
-/* TEST register bank 0 */
-#define LDO_TEST_LPM_MASK 0x40
-#define LDO_TEST_LPM_SEL_CTRL 0x00
-#define LDO_TEST_LPM_SEL_TCXO 0x40
-
-/* TEST register bank 2 */
-#define LDO_TEST_VPROG_UPDATE_MASK 0x08
-#define LDO_TEST_RANGE_SEL_MASK 0x04
-#define LDO_TEST_FINE_STEP_MASK 0x02
-#define LDO_TEST_FINE_STEP_SHIFT 1
-
-/* TEST register bank 4 */
-#define LDO_TEST_RANGE_EXT_MASK 0x01
-
-/* TEST register bank 5 */
-#define LDO_TEST_PIN_CTRL_MASK 0x0F
-#define LDO_TEST_PIN_CTRL_EN3 0x08
-#define LDO_TEST_PIN_CTRL_EN2 0x04
-#define LDO_TEST_PIN_CTRL_EN1 0x02
-#define LDO_TEST_PIN_CTRL_EN0 0x01
-
-/* TEST register bank 6 */
-#define LDO_TEST_PIN_CTRL_LPM_MASK 0x0F
-
-/*
- * If a given voltage could be output by two ranges, then the preferred one must
- * be determined by the range limits. Specified voltage ranges should must
- * not overlap.
- *
- * Allowable voltage ranges:
- */
-#define PLDO_LOW_UV_MIN 750000
-#define PLDO_LOW_UV_MAX 1487500
-#define PLDO_LOW_UV_FINE_STEP 12500
-
-#define PLDO_NORM_UV_MIN 1500000
-#define PLDO_NORM_UV_MAX 3075000
-#define PLDO_NORM_UV_FINE_STEP 25000
-
-#define PLDO_HIGH_UV_MIN 1750000
-#define PLDO_HIGH_UV_SET_POINT_MIN 3100000
-#define PLDO_HIGH_UV_MAX 4900000
-#define PLDO_HIGH_UV_FINE_STEP 50000
-
-#define PLDO_LOW_SET_POINTS ((PLDO_LOW_UV_MAX - PLDO_LOW_UV_MIN) \
- / PLDO_LOW_UV_FINE_STEP + 1)
-#define PLDO_NORM_SET_POINTS ((PLDO_NORM_UV_MAX - PLDO_NORM_UV_MIN) \
- / PLDO_NORM_UV_FINE_STEP + 1)
-#define PLDO_HIGH_SET_POINTS ((PLDO_HIGH_UV_MAX \
- - PLDO_HIGH_UV_SET_POINT_MIN) \
- / PLDO_HIGH_UV_FINE_STEP + 1)
-#define PLDO_SET_POINTS (PLDO_LOW_SET_POINTS \
- + PLDO_NORM_SET_POINTS \
- + PLDO_HIGH_SET_POINTS)
-
-#define NLDO_UV_MIN 750000
-#define NLDO_UV_MAX 1537500
-#define NLDO_UV_FINE_STEP 12500
-
-#define NLDO_SET_POINTS ((NLDO_UV_MAX - NLDO_UV_MIN) \
- / NLDO_UV_FINE_STEP + 1)
-
-/* NLDO1200 masks and values */
-
-/* CTRL register */
-#define NLDO1200_ENABLE_MASK 0x80
-#define NLDO1200_DISABLE 0x00
-#define NLDO1200_ENABLE 0x80
-
-/* Legacy mode */
-#define NLDO1200_LEGACY_PM_MASK 0x20
-#define NLDO1200_LEGACY_PM_HPM 0x00
-#define NLDO1200_LEGACY_PM_LPM 0x20
-
-/* Advanced mode */
-#define NLDO1200_CTRL_RANGE_MASK 0x40
-#define NLDO1200_CTRL_RANGE_HIGH 0x00
-#define NLDO1200_CTRL_RANGE_LOW 0x40
-#define NLDO1200_CTRL_VPROG_MASK 0x3F
-
-#define NLDO1200_LOW_UV_MIN 375000
-#define NLDO1200_LOW_UV_MAX 743750
-#define NLDO1200_LOW_UV_STEP 6250
-
-#define NLDO1200_HIGH_UV_MIN 750000
-#define NLDO1200_HIGH_UV_MAX 1537500
-#define NLDO1200_HIGH_UV_STEP 12500
-
-#define NLDO1200_LOW_SET_POINTS ((NLDO1200_LOW_UV_MAX \
- - NLDO1200_LOW_UV_MIN) \
- / NLDO1200_LOW_UV_STEP + 1)
-#define NLDO1200_HIGH_SET_POINTS ((NLDO1200_HIGH_UV_MAX \
- - NLDO1200_HIGH_UV_MIN) \
- / NLDO1200_HIGH_UV_STEP + 1)
-#define NLDO1200_SET_POINTS (NLDO1200_LOW_SET_POINTS \
- + NLDO1200_HIGH_SET_POINTS)
-
-/* TEST register bank 0 */
-#define NLDO1200_TEST_LPM_MASK 0x04
-#define NLDO1200_TEST_LPM_SEL_CTRL 0x00
-#define NLDO1200_TEST_LPM_SEL_TCXO 0x04
-
-/* TEST register bank 1 */
-#define NLDO1200_PULL_DOWN_ENABLE_MASK 0x02
-#define NLDO1200_PULL_DOWN_ENABLE 0x02
-
-/* TEST register bank 2 */
-#define NLDO1200_ADVANCED_MODE_MASK 0x08
-#define NLDO1200_ADVANCED_MODE 0x00
-#define NLDO1200_LEGACY_MODE 0x08
-
-/* Advanced mode power mode control */
-#define NLDO1200_ADVANCED_PM_MASK 0x02
-#define NLDO1200_ADVANCED_PM_HPM 0x00
-#define NLDO1200_ADVANCED_PM_LPM 0x02
-
-#define NLDO1200_IN_ADVANCED_MODE(vreg) \
- ((vreg->test_reg[2] & NLDO1200_ADVANCED_MODE_MASK) \
- == NLDO1200_ADVANCED_MODE)
-
-/* SMPS masks and values */
-
-/* CTRL register */
-
-/* Legacy mode */
-#define SMPS_LEGACY_ENABLE_MASK 0x80
-#define SMPS_LEGACY_DISABLE 0x00
-#define SMPS_LEGACY_ENABLE 0x80
-#define SMPS_LEGACY_PULL_DOWN_ENABLE 0x40
-#define SMPS_LEGACY_VREF_SEL_MASK 0x20
-#define SMPS_LEGACY_VPROG_MASK 0x1F
-
-/* Advanced mode */
-#define SMPS_ADVANCED_BAND_MASK 0xC0
-#define SMPS_ADVANCED_BAND_OFF 0x00
-#define SMPS_ADVANCED_BAND_1 0x40
-#define SMPS_ADVANCED_BAND_2 0x80
-#define SMPS_ADVANCED_BAND_3 0xC0
-#define SMPS_ADVANCED_VPROG_MASK 0x3F
-
-/* Legacy mode voltage ranges */
-#define SMPS_MODE3_UV_MIN 375000
-#define SMPS_MODE3_UV_MAX 725000
-#define SMPS_MODE3_UV_STEP 25000
-
-#define SMPS_MODE2_UV_MIN 750000
-#define SMPS_MODE2_UV_MAX 1475000
-#define SMPS_MODE2_UV_STEP 25000
-
-#define SMPS_MODE1_UV_MIN 1500000
-#define SMPS_MODE1_UV_MAX 3050000
-#define SMPS_MODE1_UV_STEP 50000
-
-#define SMPS_MODE3_SET_POINTS ((SMPS_MODE3_UV_MAX \
- - SMPS_MODE3_UV_MIN) \
- / SMPS_MODE3_UV_STEP + 1)
-#define SMPS_MODE2_SET_POINTS ((SMPS_MODE2_UV_MAX \
- - SMPS_MODE2_UV_MIN) \
- / SMPS_MODE2_UV_STEP + 1)
-#define SMPS_MODE1_SET_POINTS ((SMPS_MODE1_UV_MAX \
- - SMPS_MODE1_UV_MIN) \
- / SMPS_MODE1_UV_STEP + 1)
-#define SMPS_LEGACY_SET_POINTS (SMPS_MODE3_SET_POINTS \
- + SMPS_MODE2_SET_POINTS \
- + SMPS_MODE1_SET_POINTS)
-
-/* Advanced mode voltage ranges */
-#define SMPS_BAND1_UV_MIN 375000
-#define SMPS_BAND1_UV_MAX 737500
-#define SMPS_BAND1_UV_STEP 12500
-
-#define SMPS_BAND2_UV_MIN 750000
-#define SMPS_BAND2_UV_MAX 1487500
-#define SMPS_BAND2_UV_STEP 12500
-
-#define SMPS_BAND3_UV_MIN 1500000
-#define SMPS_BAND3_UV_MAX 3075000
-#define SMPS_BAND3_UV_STEP 25000
-
-#define SMPS_BAND1_SET_POINTS ((SMPS_BAND1_UV_MAX \
- - SMPS_BAND1_UV_MIN) \
- / SMPS_BAND1_UV_STEP + 1)
-#define SMPS_BAND2_SET_POINTS ((SMPS_BAND2_UV_MAX \
- - SMPS_BAND2_UV_MIN) \
- / SMPS_BAND2_UV_STEP + 1)
-#define SMPS_BAND3_SET_POINTS ((SMPS_BAND3_UV_MAX \
- - SMPS_BAND3_UV_MIN) \
- / SMPS_BAND3_UV_STEP + 1)
-#define SMPS_ADVANCED_SET_POINTS (SMPS_BAND1_SET_POINTS \
- + SMPS_BAND2_SET_POINTS \
- + SMPS_BAND3_SET_POINTS)
-
-/* Test2 register bank 1 */
-#define SMPS_LEGACY_VLOW_SEL_MASK 0x01
-
-/* Test2 register bank 6 */
-#define SMPS_ADVANCED_PULL_DOWN_ENABLE 0x08
-
-/* Test2 register bank 7 */
-#define SMPS_ADVANCED_MODE_MASK 0x02
-#define SMPS_ADVANCED_MODE 0x02
-#define SMPS_LEGACY_MODE 0x00
-
-#define SMPS_IN_ADVANCED_MODE(vreg) \
- ((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
-
-/* BUCK_SLEEP_CNTRL register */
-#define SMPS_PIN_CTRL_MASK 0xF0
-#define SMPS_PIN_CTRL_EN3 0x80
-#define SMPS_PIN_CTRL_EN2 0x40
-#define SMPS_PIN_CTRL_EN1 0x20
-#define SMPS_PIN_CTRL_EN0 0x10
-
-#define SMPS_PIN_CTRL_LPM_MASK 0x0F
-#define SMPS_PIN_CTRL_LPM_EN3 0x08
-#define SMPS_PIN_CTRL_LPM_EN2 0x04
-#define SMPS_PIN_CTRL_LPM_EN1 0x02
-#define SMPS_PIN_CTRL_LPM_EN0 0x01
-
-/* BUCK_CLOCK_CNTRL register */
-#define SMPS_CLK_DIVIDE2 0x40
-
-#define SMPS_CLK_CTRL_MASK 0x30
-#define SMPS_CLK_CTRL_FOLLOW_TCXO 0x00
-#define SMPS_CLK_CTRL_PWM 0x10
-#define SMPS_CLK_CTRL_PFM 0x20
-
-/* VS masks and values */
-
-/* CTRL register */
-#define VS_ENABLE_MASK 0x80
-#define VS_DISABLE 0x00
-#define VS_ENABLE 0x80
-#define VS_PULL_DOWN_ENABLE_MASK 0x40
-#define VS_PULL_DOWN_ENABLE 0x40
-
-#define VS_PIN_CTRL_MASK 0x0F
-#define VS_PIN_CTRL_EN0 0x08
-#define VS_PIN_CTRL_EN1 0x04
-#define VS_PIN_CTRL_EN2 0x02
-#define VS_PIN_CTRL_EN3 0x01
-
-#define IS_REAL_REGULATOR(id) ((id) >= 0 && \
- (id) < PM8018_VREG_ID_L2_PC)
-
-struct pm8018_vreg {
- /* Configuration data */
- struct regulator_dev *rdev;
- struct regulator_dev *rdev_pc;
- struct device *dev;
- struct device *dev_pc;
- const char *name;
- struct pm8018_regulator_platform_data pdata;
- const int hpm_min_load;
- const u16 ctrl_addr;
- const u16 test_addr;
- const u16 clk_ctrl_addr;
- const u16 sleep_ctrl_addr;
- const u8 type;
- /* State data */
- struct mutex pc_lock;
- int save_uV;
- int mode;
- u32 write_count;
- u32 prev_write_count;
- bool is_enabled;
- bool is_enabled_pc;
- u8 test_reg[REGULATOR_TEST_BANKS_MAX];
- u8 ctrl_reg;
- u8 clk_ctrl_reg;
- u8 sleep_ctrl_reg;
-};
-
-#define vreg_err(vreg, fmt, ...) \
- pr_err("%s: " fmt, vreg->name, ##__VA_ARGS__)
-
-#define PLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
- [PM8018_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_PLDO, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .hpm_min_load = PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define NLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
- [PM8018_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_NLDO, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .hpm_min_load = PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define NLDO1200(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
- [PM8018_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_NLDO1200, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .hpm_min_load = PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define SMPS(_id, _ctrl_addr, _test_addr, _clk_ctrl_addr, _sleep_ctrl_addr, \
- _hpm_min_load) \
- [PM8018_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_SMPS, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .clk_ctrl_addr = _clk_ctrl_addr, \
- .sleep_ctrl_addr = _sleep_ctrl_addr, \
- .hpm_min_load = PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define VS(_id, _ctrl_addr) \
- [PM8018_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_VS, \
- .ctrl_addr = _ctrl_addr, \
- }
-
-static struct pm8018_vreg pm8018_vreg[] = {
- /* id ctrl test hpm_min */
- PLDO(L2, 0x0B0, 0x0B1, LDO_50),
- PLDO(L3, 0x0B2, 0x0B3, LDO_50),
- PLDO(L4, 0x0B4, 0x0B5, LDO_300),
- PLDO(L5, 0x0B6, 0x0B7, LDO_150),
- PLDO(L6, 0x0B8, 0x0B9, LDO_150),
- PLDO(L7, 0x0BA, 0x0BB, LDO_300),
- NLDO(L8, 0x0BC, 0x0BD, LDO_150),
- NLDO1200(L9, 0x0BE, 0x0BF, LDO_1200),
- NLDO1200(L10, 0x0C0, 0x0C1, LDO_1200),
- NLDO1200(L11, 0x0C2, 0x0C3, LDO_1200),
- NLDO1200(L12, 0x0C4, 0x0C5, LDO_1200),
- PLDO(L13, 0x0C8, 0x0C9, LDO_50),
- PLDO(L14, 0x0CA, 0x0CB, LDO_50),
-
- /* id ctrl test2 clk sleep hpm_min */
- SMPS(S1, 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
- SMPS(S2, 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
- SMPS(S3, 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
- SMPS(S4, 0x1E8, 0x1ED, 0x00C, 0x1EA, SMPS_1500),
- SMPS(S5, 0x1F0, 0x1F5, 0x00D, 0x1F2, SMPS_1500),
-
- /* id ctrl */
- VS(LVS1, 0x060),
-};
-
-/* Determines which label to add to the print. */
-enum pm8018_regulator_action {
- PM8018_REGULATOR_ACTION_INIT,
- PM8018_REGULATOR_ACTION_ENABLE,
- PM8018_REGULATOR_ACTION_DISABLE,
- PM8018_REGULATOR_ACTION_VOLTAGE,
- PM8018_REGULATOR_ACTION_MODE,
- PM8018_REGULATOR_ACTION_PIN_CTRL,
-};
-
-/* Debug state printing */
-static void pm8018_vreg_show_state(struct regulator_dev *rdev,
- enum pm8018_regulator_action action);
-
-/*
- * Perform a masked write to a PMIC register only if the new value differs
- * from the last value written to the register. This removes redundant
- * register writing.
- *
- * No locking is required because registers are not shared between regulators.
- */
-static int pm8018_vreg_masked_write(struct pm8018_vreg *vreg, u16 addr, u8 val,
- u8 mask, u8 *reg_save)
-{
- int rc = 0;
- u8 reg;
-
- reg = (*reg_save & ~mask) | (val & mask);
- if (reg != *reg_save) {
- rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
- if (rc) {
- pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
- vreg->name, addr, rc);
- } else {
- *reg_save = reg;
- vreg->write_count++;
- if (pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_WRITES)
- pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
- addr, reg);
- }
- }
-
- return rc;
-}
-
-/*
- * Perform a masked write to a PMIC register without checking the previously
- * written value. This is needed for registers that must be rewritten even if
- * the value hasn't changed in order for changes in other registers to take
- * effect.
- */
-static int pm8018_vreg_masked_write_forced(struct pm8018_vreg *vreg, u16 addr,
- u8 val, u8 mask, u8 *reg_save)
-{
- int rc = 0;
- u8 reg;
-
- reg = (*reg_save & ~mask) | (val & mask);
- rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
- if (rc) {
- pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
- vreg->name, addr, rc);
- } else {
- *reg_save = reg;
- vreg->write_count++;
- if (pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_WRITES)
- pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
- addr, reg);
- }
-
- return rc;
-}
-
-static int pm8018_vreg_is_pin_controlled(struct pm8018_vreg *vreg)
-{
- int ret = 0;
-
- switch (vreg->type) {
- case REGULATOR_TYPE_PLDO:
- case REGULATOR_TYPE_NLDO:
- ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
- | (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
- break;
- case REGULATOR_TYPE_SMPS:
- ret = vreg->sleep_ctrl_reg
- & (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
- break;
- case REGULATOR_TYPE_VS:
- ret = vreg->ctrl_reg & VS_PIN_CTRL_MASK;
- break;
- }
-
- return ret;
-}
-
-/*
- * Returns the logical pin control enable state because the pin control options
- * present in the hardware out of restart could be different from those desired
- * by the consumer.
- */
-static int pm8018_vreg_pin_control_is_enabled(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int enabled;
-
- mutex_lock(&vreg->pc_lock);
- enabled = vreg->is_enabled_pc;
- mutex_unlock(&vreg->pc_lock);
-
- return enabled;
-}
-
-/* Returns the physical enable state of the regulator. */
-static int _pm8018_vreg_is_enabled(struct pm8018_vreg *vreg)
-{
- int rc = 0;
-
- /*
- * All regulator types except advanced mode SMPS have enable bit in
- * bit 7 of the control register.
- */
-
- if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg)) {
- if ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
- != SMPS_ADVANCED_BAND_OFF)
- rc = 1;
- } else {
- if ((vreg->ctrl_reg & REGULATOR_ENABLE_MASK)
- == REGULATOR_ENABLE)
- rc = 1;
- }
-
- return rc;
-}
-
-/*
- * Returns the logical enable state of the regulator which may be different from
- * the physical enable state thanks to HPM/LPM pin control.
- */
-static int pm8018_vreg_is_enabled(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int enabled;
-
- if (vreg->type == REGULATOR_TYPE_PLDO
- || vreg->type == REGULATOR_TYPE_NLDO
- || vreg->type == REGULATOR_TYPE_SMPS
- || vreg->type == REGULATOR_TYPE_VS) {
- /* Pin controllable */
- mutex_lock(&vreg->pc_lock);
- enabled = vreg->is_enabled;
- mutex_unlock(&vreg->pc_lock);
- } else {
- /* Not pin controlable */
- enabled = _pm8018_vreg_is_enabled(vreg);
- }
-
- return enabled;
-}
-
-static int pm8018_pldo_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int vmin, fine_step;
- u8 range_ext, range_sel, vprog, fine_step_reg;
-
- mutex_lock(&vreg->pc_lock);
-
- fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
- range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
- range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
- vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
- mutex_unlock(&vreg->pc_lock);
-
- vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
- if (range_sel) {
- /* low range mode */
- fine_step = PLDO_LOW_UV_FINE_STEP;
- vmin = PLDO_LOW_UV_MIN;
- } else if (!range_ext) {
- /* normal mode */
- fine_step = PLDO_NORM_UV_FINE_STEP;
- vmin = PLDO_NORM_UV_MIN;
- } else {
- /* high range mode */
- fine_step = PLDO_HIGH_UV_FINE_STEP;
- vmin = PLDO_HIGH_UV_MIN;
- }
-
- return fine_step * vprog + vmin;
-}
-
-static int pm8018_pldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int uV;
-
- if (selector >= PLDO_SET_POINTS)
- return 0;
-
- if (selector < PLDO_LOW_SET_POINTS)
- uV = selector * PLDO_LOW_UV_FINE_STEP + PLDO_LOW_UV_MIN;
- else if (selector < (PLDO_LOW_SET_POINTS + PLDO_NORM_SET_POINTS))
- uV = (selector - PLDO_LOW_SET_POINTS) * PLDO_NORM_UV_FINE_STEP
- + PLDO_NORM_UV_MIN;
- else
- uV = (selector - PLDO_LOW_SET_POINTS - PLDO_NORM_SET_POINTS)
- * PLDO_HIGH_UV_FINE_STEP
- + PLDO_HIGH_UV_SET_POINT_MIN;
-
- return uV;
-}
-
-static int pm8018_pldo_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0, uV = min_uV;
- int vmin;
- unsigned vprog, fine_step;
- u8 range_ext, range_sel, fine_step_reg, prev_reg;
- bool reg_changed = false;
-
- if (uV < PLDO_LOW_UV_MIN && max_uV >= PLDO_LOW_UV_MIN)
- uV = PLDO_LOW_UV_MIN;
-
- if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, PLDO_LOW_UV_MIN, PLDO_HIGH_UV_MAX);
- return -EINVAL;
- }
-
- if (uV > PLDO_NORM_UV_MAX) {
- vmin = PLDO_HIGH_UV_MIN;
- fine_step = PLDO_HIGH_UV_FINE_STEP;
- range_ext = LDO_TEST_RANGE_EXT_MASK;
- range_sel = 0;
- } else if (uV > PLDO_LOW_UV_MAX) {
- vmin = PLDO_NORM_UV_MIN;
- fine_step = PLDO_NORM_UV_FINE_STEP;
- range_ext = 0;
- range_sel = 0;
- } else {
- vmin = PLDO_LOW_UV_MIN;
- fine_step = PLDO_LOW_UV_FINE_STEP;
- range_ext = 0;
- range_sel = LDO_TEST_RANGE_SEL_MASK;
- }
-
- vprog = (uV - vmin + fine_step - 1) / fine_step;
- uV = vprog * fine_step + vmin;
- fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
- vprog >>= 1;
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- /* Write fine step, range select and program voltage update. */
- prev_reg = vreg->test_reg[2];
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
- | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
- LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
- | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
- &vreg->test_reg[2]);
- if (rc)
- goto bail;
- if (prev_reg != vreg->test_reg[2])
- reg_changed = true;
-
- /* Write range extension. */
- prev_reg = vreg->test_reg[4];
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- range_ext | REGULATOR_BANK_SEL(4)
- | REGULATOR_BANK_WRITE,
- LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[4]);
- if (rc)
- goto bail;
- if (prev_reg != vreg->test_reg[4])
- reg_changed = true;
-
- /* Write new voltage. */
- if (reg_changed) {
- /*
- * Force a CTRL register write even if the value hasn't changed.
- * This is neccessary because range select, range extension, and
- * fine step will not update until a value is written into the
- * control register.
- */
- rc = pm8018_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
- vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- } else {
- /* Only write to control register if new value is different. */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
- LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- }
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int pm8018_nldo_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- u8 vprog, fine_step_reg;
-
- mutex_lock(&vreg->pc_lock);
-
- fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
- vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
- mutex_unlock(&vreg->pc_lock);
-
- vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
- return NLDO_UV_FINE_STEP * vprog + NLDO_UV_MIN;
-}
-
-static int pm8018_nldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector >= NLDO_SET_POINTS)
- return 0;
-
- return selector * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
-}
-
-static int pm8018_nldo_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned vprog, fine_step_reg, prev_reg;
- int rc;
- int uV = min_uV;
-
- if (uV < NLDO_UV_MIN && max_uV >= NLDO_UV_MIN)
- uV = NLDO_UV_MIN;
-
- if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
- return -EINVAL;
- }
-
- vprog = (uV - NLDO_UV_MIN + NLDO_UV_FINE_STEP - 1) / NLDO_UV_FINE_STEP;
- uV = vprog * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
- fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
- vprog >>= 1;
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- /* Write fine step. */
- prev_reg = vreg->test_reg[2];
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- fine_step_reg | REGULATOR_BANK_SEL(2)
- | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
- LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
- | LDO_TEST_VPROG_UPDATE_MASK,
- &vreg->test_reg[2]);
- if (rc)
- goto bail;
-
- /* Write new voltage. */
- if (prev_reg != vreg->test_reg[2]) {
- /*
- * Force a CTRL register write even if the value hasn't changed.
- * This is neccessary because fine step will not update until a
- * value is written into the control register.
- */
- rc = pm8018_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
- vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- } else {
- /* Only write to control register if new value is different. */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
- LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- }
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int _pm8018_nldo1200_get_voltage(struct pm8018_vreg *vreg)
-{
- int uV = 0;
- int vprog;
-
- if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
- pr_warn("%s: currently in legacy mode; voltage unknown.\n",
- vreg->name);
- return vreg->save_uV;
- }
-
- vprog = vreg->ctrl_reg & NLDO1200_CTRL_VPROG_MASK;
-
- if ((vreg->ctrl_reg & NLDO1200_CTRL_RANGE_MASK)
- == NLDO1200_CTRL_RANGE_LOW)
- uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
- else
- uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
-
- return uV;
-}
-
-static int pm8018_nldo1200_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-
- return _pm8018_nldo1200_get_voltage(vreg);
-}
-
-static int pm8018_nldo1200_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int uV;
-
- if (selector >= NLDO1200_SET_POINTS)
- return 0;
-
- if (selector < NLDO1200_LOW_SET_POINTS)
- uV = selector * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
- else
- uV = (selector - NLDO1200_LOW_SET_POINTS)
- * NLDO1200_HIGH_UV_STEP
- + NLDO1200_HIGH_UV_MIN;
-
- return uV;
-}
-
-static int _pm8018_nldo1200_set_voltage(struct pm8018_vreg *vreg, int min_uV,
- int max_uV)
-{
- u8 vprog, range;
- int rc;
- int uV = min_uV;
-
- if (uV < NLDO1200_LOW_UV_MIN && max_uV >= NLDO1200_LOW_UV_MIN)
- uV = NLDO1200_LOW_UV_MIN;
-
- if (uV < NLDO1200_LOW_UV_MIN || uV > NLDO1200_HIGH_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
- return -EINVAL;
- }
-
- if (uV > NLDO1200_LOW_UV_MAX) {
- vprog = (uV - NLDO1200_HIGH_UV_MIN + NLDO1200_HIGH_UV_STEP - 1)
- / NLDO1200_HIGH_UV_STEP;
- uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
- vprog &= NLDO1200_CTRL_VPROG_MASK;
- range = NLDO1200_CTRL_RANGE_HIGH;
- } else {
- vprog = (uV - NLDO1200_LOW_UV_MIN + NLDO1200_LOW_UV_STEP - 1)
- / NLDO1200_LOW_UV_STEP;
- uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
- vprog &= NLDO1200_CTRL_VPROG_MASK;
- range = NLDO1200_CTRL_RANGE_LOW;
- }
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /* Set to advanced mode */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- NLDO1200_ADVANCED_MODE | REGULATOR_BANK_SEL(2)
- | REGULATOR_BANK_WRITE, NLDO1200_ADVANCED_MODE_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
- if (rc)
- goto bail;
-
- /* Set voltage and range selection. */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, vprog | range,
- NLDO1200_CTRL_VPROG_MASK | NLDO1200_CTRL_RANGE_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- vreg->save_uV = uV;
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8018_nldo1200_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = _pm8018_nldo1200_set_voltage(vreg, min_uV, max_uV);
-
- if (!rc)
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int pm8018_smps_get_voltage_advanced(struct pm8018_vreg *vreg)
-{
- u8 vprog, band;
- int uV = 0;
-
- vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
- band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
-
- if (band == SMPS_ADVANCED_BAND_1)
- uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
- else if (band == SMPS_ADVANCED_BAND_2)
- uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
- else if (band == SMPS_ADVANCED_BAND_3)
- uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
- else if (vreg->save_uV > 0)
- uV = vreg->save_uV;
- else
- uV = VOLTAGE_UNKNOWN;
-
- return uV;
-}
-
-static int pm8018_smps_get_voltage_legacy(struct pm8018_vreg *vreg)
-{
- u8 vlow, vref, vprog;
- int uV;
-
- vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
- vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
- vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
-
- if (vlow && vref) {
- /* mode 3 */
- uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
- } else if (vref) {
- /* mode 2 */
- uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
- } else {
- /* mode 1 */
- uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
- }
-
- return uV;
-}
-
-static int _pm8018_smps_get_voltage(struct pm8018_vreg *vreg)
-{
- if (SMPS_IN_ADVANCED_MODE(vreg))
- return pm8018_smps_get_voltage_advanced(vreg);
-
- return pm8018_smps_get_voltage_legacy(vreg);
-}
-
-static int pm8018_smps_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int uV;
-
- if (selector >= SMPS_ADVANCED_SET_POINTS)
- return 0;
-
- if (selector < SMPS_BAND1_SET_POINTS)
- uV = selector * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
- else if (selector < (SMPS_BAND1_SET_POINTS + SMPS_BAND2_SET_POINTS))
- uV = (selector - SMPS_BAND1_SET_POINTS) * SMPS_BAND2_UV_STEP
- + SMPS_BAND2_UV_MIN;
- else
- uV = (selector - SMPS_BAND1_SET_POINTS - SMPS_BAND2_SET_POINTS)
- * SMPS_BAND3_UV_STEP
- + SMPS_BAND3_UV_MIN;
-
- return uV;
-}
-
-static int pm8018_smps_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int uV;
-
- mutex_lock(&vreg->pc_lock);
- uV = _pm8018_smps_get_voltage(vreg);
- mutex_unlock(&vreg->pc_lock);
-
- return uV;
-}
-
-static int pm8018_smps_set_voltage_advanced(struct pm8018_vreg *vreg,
- int min_uV, int max_uV, int force_on)
-{
- u8 vprog, band;
- int rc;
- int uV = min_uV;
-
- if (uV < SMPS_BAND1_UV_MIN && max_uV >= SMPS_BAND1_UV_MIN)
- uV = SMPS_BAND1_UV_MIN;
-
- if (uV < SMPS_BAND1_UV_MIN || uV > SMPS_BAND3_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, SMPS_BAND1_UV_MIN, SMPS_BAND3_UV_MAX);
- return -EINVAL;
- }
-
- if (uV > SMPS_BAND2_UV_MAX) {
- vprog = (uV - SMPS_BAND3_UV_MIN + SMPS_BAND3_UV_STEP - 1)
- / SMPS_BAND3_UV_STEP;
- band = SMPS_ADVANCED_BAND_3;
- uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
- } else if (uV > SMPS_BAND1_UV_MAX) {
- vprog = (uV - SMPS_BAND2_UV_MIN + SMPS_BAND2_UV_STEP - 1)
- / SMPS_BAND2_UV_STEP;
- band = SMPS_ADVANCED_BAND_2;
- uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
- } else {
- vprog = (uV - SMPS_BAND1_UV_MIN + SMPS_BAND1_UV_STEP - 1)
- / SMPS_BAND1_UV_STEP;
- band = SMPS_ADVANCED_BAND_1;
- uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
- }
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /* Do not set band if regulator currently disabled. */
- if (!_pm8018_vreg_is_enabled(vreg) && !force_on)
- band = SMPS_ADVANCED_BAND_OFF;
-
- /* Set advanced mode bit to 1. */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
- | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
- SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[7]);
- if (rc)
- goto bail;
-
- /* Set voltage and voltage band. */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, band | vprog,
- SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- vreg->save_uV = uV;
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8018_smps_set_voltage_legacy(struct pm8018_vreg *vreg, int min_uV,
- int max_uV)
-{
- u8 vlow, vref, vprog, pd, en;
- int rc;
- int uV = min_uV;
-
-
- if (uV < SMPS_MODE3_UV_MIN && max_uV >= SMPS_MODE3_UV_MIN)
- uV = SMPS_MODE3_UV_MIN;
-
- if (uV < SMPS_MODE3_UV_MIN || uV > SMPS_MODE1_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, SMPS_MODE3_UV_MIN, SMPS_MODE1_UV_MAX);
- return -EINVAL;
- }
-
- if (uV > SMPS_MODE2_UV_MAX) {
- vprog = (uV - SMPS_MODE1_UV_MIN + SMPS_MODE1_UV_STEP - 1)
- / SMPS_MODE1_UV_STEP;
- vref = 0;
- vlow = 0;
- uV = SMPS_MODE1_UV_MIN + vprog * SMPS_MODE1_UV_STEP;
- } else if (uV > SMPS_MODE3_UV_MAX) {
- vprog = (uV - SMPS_MODE2_UV_MIN + SMPS_MODE2_UV_STEP - 1)
- / SMPS_MODE2_UV_STEP;
- vref = SMPS_LEGACY_VREF_SEL_MASK;
- vlow = 0;
- uV = SMPS_MODE2_UV_MIN + vprog * SMPS_MODE2_UV_STEP;
- } else {
- vprog = (uV - SMPS_MODE3_UV_MIN + SMPS_MODE3_UV_STEP - 1)
- / SMPS_MODE3_UV_STEP;
- vref = SMPS_LEGACY_VREF_SEL_MASK;
- vlow = SMPS_LEGACY_VLOW_SEL_MASK;
- uV = SMPS_MODE3_UV_MIN + vprog * SMPS_MODE3_UV_STEP;
- }
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /* set vlow bit for ultra low voltage mode */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
- REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
- &vreg->test_reg[1]);
- if (rc)
- goto bail;
-
- /* Set advanced mode bit to 0. */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
- | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
- SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[7]);
- if (rc)
- goto bail;
-
- en = (_pm8018_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
- pd = (vreg->pdata.pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
-
- /* Set voltage (and the rest of the control register). */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- en | pd | vref | vprog,
- SMPS_LEGACY_ENABLE_MASK | SMPS_LEGACY_PULL_DOWN_ENABLE
- | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
- &vreg->ctrl_reg);
-
- vreg->save_uV = uV;
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8018_smps_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- mutex_lock(&vreg->pc_lock);
-
- if (SMPS_IN_ADVANCED_MODE(vreg) || !pm8018_vreg_is_pin_controlled(vreg))
- rc = pm8018_smps_set_voltage_advanced(vreg, min_uV, max_uV, 0);
- else
- rc = pm8018_smps_set_voltage_legacy(vreg, min_uV, max_uV);
-
- mutex_unlock(&vreg->pc_lock);
-
- if (!rc)
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static unsigned int pm8018_ldo_get_mode(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode = 0;
-
- mutex_lock(&vreg->pc_lock);
- mode = vreg->mode;
- mutex_unlock(&vreg->pc_lock);
-
- return mode;
-}
-
-static int pm8018_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
- vreg_err(vreg, "invalid mode: %u\n", mode);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- if (mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE)) {
- /* HPM */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_HPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- } else {
- /* LPM */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0),
- LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[0]);
- }
-
-bail:
- if (!rc)
- vreg->mode = mode;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_MODE);
-
- return rc;
-}
-
-static unsigned int pm8018_nldo1200_get_mode(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode = 0;
-
- if (NLDO1200_IN_ADVANCED_MODE(vreg)) {
- /* Advanced mode */
- if ((vreg->test_reg[2] & NLDO1200_ADVANCED_PM_MASK)
- == NLDO1200_ADVANCED_PM_LPM)
- mode = REGULATOR_MODE_IDLE;
- else
- mode = REGULATOR_MODE_NORMAL;
- } else {
- /* Legacy mode */
- if ((vreg->ctrl_reg & NLDO1200_LEGACY_PM_MASK)
- == NLDO1200_LEGACY_PM_LPM)
- mode = REGULATOR_MODE_IDLE;
- else
- mode = REGULATOR_MODE_NORMAL;
- }
-
- return mode;
-}
-
-static int pm8018_nldo1200_set_mode(struct regulator_dev *rdev,
- unsigned int mode)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
- vreg_err(vreg, "invalid mode: %u\n", mode);
- return -EINVAL;
- }
-
- /*
- * Make sure that advanced mode is in use. If it isn't, then set it
- * and update the voltage accordingly.
- */
- if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
- rc = _pm8018_nldo1200_set_voltage(vreg, vreg->save_uV,
- vreg->save_uV);
- if (rc)
- goto bail;
- }
-
- if (mode == REGULATOR_MODE_NORMAL) {
- /* HPM */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- NLDO1200_ADVANCED_PM_HPM | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
- } else {
- /* LPM */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- NLDO1200_ADVANCED_PM_LPM | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
- }
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_MODE);
-
- return rc;
-}
-
-static unsigned int pm8018_smps_get_mode(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode = 0;
-
- mutex_lock(&vreg->pc_lock);
- mode = vreg->mode;
- mutex_unlock(&vreg->pc_lock);
-
- return mode;
-}
-
-static int pm8018_smps_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
- vreg_err(vreg, "invalid mode: %u\n", mode);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- if (mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE)) {
- /* HPM */
- rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PWM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
- } else {
- /* LPM */
- rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
- }
-
- if (!rc)
- vreg->mode = mode;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_MODE);
-
- return rc;
-}
-
-static unsigned int pm8018_vreg_get_optimum_mode(struct regulator_dev *rdev,
- int input_uV, int output_uV, int load_uA)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode;
-
- if (load_uA + vreg->pdata.system_uA >= vreg->hpm_min_load)
- mode = REGULATOR_MODE_NORMAL;
- else
- mode = REGULATOR_MODE_IDLE;
-
- return mode;
-}
-
-static int pm8018_ldo_enable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc, val;
-
- mutex_lock(&vreg->pc_lock);
-
- /*
- * Choose HPM if previously set to HPM or if pin control is enabled in
- * on/off mode.
- */
- val = LDO_CTRL_PM_LPM;
- if (vreg->mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE))
- val = LDO_CTRL_PM_HPM;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val | LDO_ENABLE,
- LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8018_ldo_disable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- /*
- * Only disable the regulator if it isn't still required for HPM/LPM
- * pin control.
- */
- if (!vreg->is_enabled_pc
- || vreg->pdata.pin_fn != PM8018_VREG_PIN_FN_MODE) {
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if HPM/LPM pin control is enabled. */
- if (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_MODE) {
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0),
- LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[0]);
- }
-
- if (!rc)
- vreg->is_enabled = false;
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8018_nldo1200_enable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_ENABLE,
- NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8018_nldo1200_disable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_DISABLE,
- NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8018_smps_enable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
- int val;
-
- mutex_lock(&vreg->pc_lock);
-
- if (SMPS_IN_ADVANCED_MODE(vreg)
- || !pm8018_vreg_is_pin_controlled(vreg)) {
- /* Enable in advanced mode if not using pin control. */
- rc = pm8018_smps_set_voltage_advanced(vreg, vreg->save_uV,
- vreg->save_uV, 1);
- } else {
- rc = pm8018_smps_set_voltage_legacy(vreg, vreg->save_uV,
- vreg->save_uV);
- if (rc)
- goto bail;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- SMPS_LEGACY_ENABLE, SMPS_LEGACY_ENABLE_MASK,
- &vreg->ctrl_reg);
- }
-
- /*
- * Choose HPM if previously set to HPM or if pin control is enabled in
- * on/off mode.
- */
- val = SMPS_CLK_CTRL_PFM;
- if (vreg->mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE))
- val = SMPS_CLK_CTRL_PWM;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr, val,
- SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = true;
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8018_smps_disable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- if (SMPS_IN_ADVANCED_MODE(vreg)) {
- /* Change SMPS to legacy mode before disabling. */
- rc = pm8018_smps_set_voltage_legacy(vreg, vreg->save_uV,
- vreg->save_uV);
- if (rc)
- goto bail;
- }
-
- /*
- * Only disable the regulator if it isn't still required for HPM/LPM
- * pin control.
- */
- if (!vreg->is_enabled_pc
- || vreg->pdata.pin_fn != PM8018_VREG_PIN_FN_MODE) {
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if HPM/LPM pin control is enabled. */
- if (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_MODE)
- rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = false;
-
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8018_vs_enable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, VS_ENABLE,
- VS_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8018_vs_disable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, VS_DISABLE,
- VS_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8018_ldo_pin_control_enable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
- int bank;
- u8 val = 0;
- u8 mask;
-
- mutex_lock(&vreg->pc_lock);
-
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
- val |= LDO_TEST_PIN_CTRL_EN0;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
- val |= LDO_TEST_PIN_CTRL_EN1;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
- val |= LDO_TEST_PIN_CTRL_EN2;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
- val |= LDO_TEST_PIN_CTRL_EN3;
-
- bank = (vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE ? 5 : 6);
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- val | REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[bank]);
- if (rc)
- goto bail;
-
- /* Unset pin control bits in unused bank. */
- bank = (bank == 5 ? 6 : 5);
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[bank]);
- if (rc)
- goto bail;
-
- val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0);
- mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr, val, mask,
- &vreg->test_reg[0]);
- if (rc)
- goto bail;
-
- if (vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE) {
- /* Pin control ON/OFF */
- val = LDO_CTRL_PM_HPM;
- /* Leave physically enabled if already enabled. */
- val |= (vreg->is_enabled ? LDO_ENABLE : LDO_DISABLE);
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val,
- LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- } else {
- /* Pin control LPM/HPM */
- val = LDO_ENABLE;
- /* Leave in HPM if already enabled in HPM. */
- val |= (vreg->is_enabled && vreg->mode == REGULATOR_MODE_NORMAL
- ? LDO_CTRL_PM_HPM : LDO_CTRL_PM_LPM);
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val,
- LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8018_ldo_pin_control_disable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[5]);
- if (rc)
- goto bail;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[6]);
-
- /*
- * Physically disable the regulator if it was enabled in HPM/LPM pin
- * control mode previously and it logically should not be enabled.
- */
- if ((vreg->ctrl_reg & LDO_ENABLE_MASK) == LDO_ENABLE
- && !vreg->is_enabled) {
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if LPM was enabled. */
- if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0),
- LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[0]);
- if (rc)
- goto bail;
- }
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8018_smps_pin_control_enable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
- u8 val = 0;
-
- mutex_lock(&vreg->pc_lock);
-
- if (vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE) {
- /* Pin control ON/OFF */
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
- val |= SMPS_PIN_CTRL_EN0;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
- val |= SMPS_PIN_CTRL_EN1;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
- val |= SMPS_PIN_CTRL_EN2;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
- val |= SMPS_PIN_CTRL_EN3;
- } else {
- /* Pin control LPM/HPM */
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
- val |= SMPS_PIN_CTRL_LPM_EN0;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
- val |= SMPS_PIN_CTRL_LPM_EN1;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
- val |= SMPS_PIN_CTRL_LPM_EN2;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
- val |= SMPS_PIN_CTRL_LPM_EN3;
- }
-
- rc = pm8018_smps_set_voltage_legacy(vreg, vreg->save_uV, vreg->save_uV);
- if (rc)
- goto bail;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, val,
- SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
- &vreg->sleep_ctrl_reg);
- if (rc)
- goto bail;
-
- /*
- * Physically enable the regulator if using HPM/LPM pin control mode or
- * if the regulator should be logically left on.
- */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- ((vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_MODE
- || vreg->is_enabled) ?
- SMPS_LEGACY_ENABLE : SMPS_LEGACY_DISABLE),
- SMPS_LEGACY_ENABLE_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /*
- * Set regulator to HPM if using on/off pin control or if the regulator
- * is already enabled in HPM. Otherwise, set it to LPM.
- */
- rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- (vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE
- || (vreg->is_enabled
- && vreg->mode == REGULATOR_MODE_NORMAL)
- ? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
- SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8018_smps_pin_control_disable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8018_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, 0,
- SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
- &vreg->sleep_ctrl_reg);
- if (rc)
- goto bail;
-
- /*
- * Physically disable the regulator if it was enabled in HPM/LPM pin
- * control mode previously and it logically should not be enabled.
- */
- if ((vreg->ctrl_reg & SMPS_LEGACY_ENABLE_MASK) == SMPS_LEGACY_ENABLE
- && vreg->is_enabled == false) {
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if LPM was enabled. */
- if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
- rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
- if (rc)
- goto bail;
- }
-
- rc = pm8018_smps_set_voltage_advanced(vreg, vreg->save_uV,
- vreg->save_uV, 0);
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8018_vs_pin_control_enable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
- u8 val = 0;
-
- mutex_lock(&vreg->pc_lock);
-
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
- val |= VS_PIN_CTRL_EN0;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
- val |= VS_PIN_CTRL_EN1;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
- val |= VS_PIN_CTRL_EN2;
- if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
- val |= VS_PIN_CTRL_EN3;
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val,
- VS_PIN_CTRL_MASK | VS_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled_pc = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8018_vs_pin_control_disable(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, 0,
- VS_PIN_CTRL_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled_pc = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8018_enable_time(struct regulator_dev *rdev)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-
- return vreg->pdata.enable_time;
-}
-
-static const char const *pm8018_print_actions[] = {
- [PM8018_REGULATOR_ACTION_INIT] = "initial ",
- [PM8018_REGULATOR_ACTION_ENABLE] = "enable ",
- [PM8018_REGULATOR_ACTION_DISABLE] = "disable ",
- [PM8018_REGULATOR_ACTION_VOLTAGE] = "set voltage",
- [PM8018_REGULATOR_ACTION_MODE] = "set mode ",
- [PM8018_REGULATOR_ACTION_PIN_CTRL] = "pin control",
-};
-
-static void pm8018_vreg_show_state(struct regulator_dev *rdev,
- enum pm8018_regulator_action action)
-{
- struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
- int uV, pc;
- unsigned int mode;
- const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
- const char *pc_total = "";
- const char *action_label = pm8018_print_actions[action];
- const char *enable_label;
-
- mutex_lock(&vreg->pc_lock);
-
- /*
- * Do not print unless REQUEST is specified and SSBI writes have taken
- * place, or DUPLICATE is specified.
- */
- if (!((pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_DUPLICATE)
- || ((pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_REQUEST)
- && (vreg->write_count != vreg->prev_write_count)))) {
- mutex_unlock(&vreg->pc_lock);
- return;
- }
-
- vreg->prev_write_count = vreg->write_count;
-
- pc = vreg->pdata.pin_ctrl;
- if (vreg->is_enabled_pc) {
- if (pc & PM8018_VREG_PIN_CTRL_D1)
- pc_en0 = " D1";
- if (pc & PM8018_VREG_PIN_CTRL_A0)
- pc_en1 = " A0";
- if (pc & PM8018_VREG_PIN_CTRL_A1)
- pc_en2 = " A1";
- if (pc & PM8018_VREG_PIN_CTRL_A2)
- pc_en3 = " A2";
- if (pc == PM8018_VREG_PIN_CTRL_NONE)
- pc_total = " none";
- } else {
- pc_total = " none";
- }
-
- mutex_unlock(&vreg->pc_lock);
-
- enable_label = pm8018_vreg_is_enabled(rdev) ? "on " : "off";
-
- switch (vreg->type) {
- case REGULATOR_TYPE_PLDO:
- uV = pm8018_pldo_get_voltage(rdev);
- mode = pm8018_ldo_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- case REGULATOR_TYPE_NLDO:
- uV = pm8018_nldo_get_voltage(rdev);
- mode = pm8018_ldo_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- case REGULATOR_TYPE_NLDO1200:
- uV = pm8018_nldo1200_get_voltage(rdev);
- mode = pm8018_nldo1200_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
- break;
- case REGULATOR_TYPE_SMPS:
- uV = pm8018_smps_get_voltage(rdev);
- mode = pm8018_smps_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- case REGULATOR_TYPE_VS:
- pr_info("%s %-9s: %s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label,
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- default:
- break;
- }
-}
-
-/* Real regulator operations. */
-static struct regulator_ops pm8018_pldo_ops = {
- .enable = pm8018_ldo_enable,
- .disable = pm8018_ldo_disable,
- .is_enabled = pm8018_vreg_is_enabled,
- .set_voltage = pm8018_pldo_set_voltage,
- .get_voltage = pm8018_pldo_get_voltage,
- .list_voltage = pm8018_pldo_list_voltage,
- .set_mode = pm8018_ldo_set_mode,
- .get_mode = pm8018_ldo_get_mode,
- .get_optimum_mode = pm8018_vreg_get_optimum_mode,
- .enable_time = pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_nldo_ops = {
- .enable = pm8018_ldo_enable,
- .disable = pm8018_ldo_disable,
- .is_enabled = pm8018_vreg_is_enabled,
- .set_voltage = pm8018_nldo_set_voltage,
- .get_voltage = pm8018_nldo_get_voltage,
- .list_voltage = pm8018_nldo_list_voltage,
- .set_mode = pm8018_ldo_set_mode,
- .get_mode = pm8018_ldo_get_mode,
- .get_optimum_mode = pm8018_vreg_get_optimum_mode,
- .enable_time = pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_nldo1200_ops = {
- .enable = pm8018_nldo1200_enable,
- .disable = pm8018_nldo1200_disable,
- .is_enabled = pm8018_vreg_is_enabled,
- .set_voltage = pm8018_nldo1200_set_voltage,
- .get_voltage = pm8018_nldo1200_get_voltage,
- .list_voltage = pm8018_nldo1200_list_voltage,
- .set_mode = pm8018_nldo1200_set_mode,
- .get_mode = pm8018_nldo1200_get_mode,
- .get_optimum_mode = pm8018_vreg_get_optimum_mode,
- .enable_time = pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_smps_ops = {
- .enable = pm8018_smps_enable,
- .disable = pm8018_smps_disable,
- .is_enabled = pm8018_vreg_is_enabled,
- .set_voltage = pm8018_smps_set_voltage,
- .get_voltage = pm8018_smps_get_voltage,
- .list_voltage = pm8018_smps_list_voltage,
- .set_mode = pm8018_smps_set_mode,
- .get_mode = pm8018_smps_get_mode,
- .get_optimum_mode = pm8018_vreg_get_optimum_mode,
- .enable_time = pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_vs_ops = {
- .enable = pm8018_vs_enable,
- .disable = pm8018_vs_disable,
- .is_enabled = pm8018_vreg_is_enabled,
- .enable_time = pm8018_enable_time,
-};
-
-/* Pin control regulator operations. */
-static struct regulator_ops pm8018_ldo_pc_ops = {
- .enable = pm8018_ldo_pin_control_enable,
- .disable = pm8018_ldo_pin_control_disable,
- .is_enabled = pm8018_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8018_smps_pc_ops = {
- .enable = pm8018_smps_pin_control_enable,
- .disable = pm8018_smps_pin_control_disable,
- .is_enabled = pm8018_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8018_vs_pc_ops = {
- .enable = pm8018_vs_pin_control_enable,
- .disable = pm8018_vs_pin_control_disable,
- .is_enabled = pm8018_vreg_pin_control_is_enabled,
-};
-
-#define VREG_DESC(_id, _name, _ops, _n_voltages) \
- [PM8018_VREG_ID_##_id] = { \
- .id = PM8018_VREG_ID_##_id, \
- .name = _name, \
- .n_voltages = _n_voltages, \
- .ops = _ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- }
-
-static struct regulator_desc pm8018_vreg_description[] = {
- VREG_DESC(L2, "8018_l2", &pm8018_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L3, "8018_l3", &pm8018_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L4, "8018_l4", &pm8018_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L5, "8018_l5", &pm8018_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L6, "8018_l6", &pm8018_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L7, "8018_l7", &pm8018_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L8, "8018_l8", &pm8018_nldo_ops, NLDO_SET_POINTS),
- VREG_DESC(L9, "8018_l9", &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L10, "8018_l10", &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L11, "8018_l11", &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L12, "8018_l12", &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L13, "8018_l13", &pm8018_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L14, "8018_l14", &pm8018_pldo_ops, PLDO_SET_POINTS),
-
- VREG_DESC(S1, "8018_s1", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S2, "8018_s2", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S3, "8018_s3", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S4, "8018_s4", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S5, "8018_s5", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
-
- VREG_DESC(LVS1, "8018_lvs1", &pm8018_vs_ops, 0),
-
- VREG_DESC(L2_PC, "8018_l2_pc", &pm8018_ldo_pc_ops, 0),
- VREG_DESC(L3_PC, "8018_l3_pc", &pm8018_ldo_pc_ops, 0),
- VREG_DESC(L4_PC, "8018_l4_pc", &pm8018_ldo_pc_ops, 0),
- VREG_DESC(L5_PC, "8018_l5_pc", &pm8018_ldo_pc_ops, 0),
- VREG_DESC(L6_PC, "8018_l6_pc", &pm8018_ldo_pc_ops, 0),
- VREG_DESC(L7_PC, "8018_l7_pc", &pm8018_ldo_pc_ops, 0),
- VREG_DESC(L8_PC, "8018_l8_pc", &pm8018_ldo_pc_ops, 0),
-
- VREG_DESC(L13_PC, "8018_l13_pc", &pm8018_ldo_pc_ops, 0),
- VREG_DESC(L14_PC, "8018_l14_pc", &pm8018_ldo_pc_ops, 0),
-
- VREG_DESC(S1_PC, "8018_s1_pc", &pm8018_smps_pc_ops, 0),
- VREG_DESC(S2_PC, "8018_s2_pc", &pm8018_smps_pc_ops, 0),
- VREG_DESC(S3_PC, "8018_s3_pc", &pm8018_smps_pc_ops, 0),
- VREG_DESC(S4_PC, "8018_s4_pc", &pm8018_smps_pc_ops, 0),
- VREG_DESC(S5_PC, "8018_s5_pc", &pm8018_smps_pc_ops, 0),
-
- VREG_DESC(LVS1_PC, "8018_lvs1_pc", &pm8018_vs_pc_ops, 0),
-};
-
-static int pm8018_init_ldo(struct pm8018_vreg *vreg, bool is_real)
-{
- int rc = 0;
- int i;
- u8 bank;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current test register state. */
- for (i = 0; i < LDO_TEST_BANKS; i++) {
- bank = REGULATOR_BANK_SEL(i);
- rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
- &vreg->test_reg[i]);
- if (rc)
- goto bail;
- vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
- }
-
- if (is_real) {
- /* Set pull down enable based on platform data. */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- (vreg->pdata.pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
- LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
- vreg->is_enabled = !!_pm8018_vreg_is_enabled(vreg);
-
- vreg->mode = ((vreg->ctrl_reg & LDO_CTRL_PM_MASK)
- == LDO_CTRL_PM_LPM ?
- REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
- }
-bail:
- if (rc)
- vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8018_init_nldo1200(struct pm8018_vreg *vreg)
-{
- int rc = 0;
- int i;
- u8 bank;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current test register state. */
- for (i = 0; i < LDO_TEST_BANKS; i++) {
- bank = REGULATOR_BANK_SEL(i);
- rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
- &vreg->test_reg[i]);
- if (rc)
- goto bail;
- vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
- }
-
- vreg->save_uV = _pm8018_nldo1200_get_voltage(vreg);
-
- /* Set pull down enable based on platform data. */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- (vreg->pdata.pull_down_enable ? NLDO1200_PULL_DOWN_ENABLE : 0)
- | REGULATOR_BANK_SEL(1) | REGULATOR_BANK_WRITE,
- NLDO1200_PULL_DOWN_ENABLE_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[1]);
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8018_init_smps(struct pm8018_vreg *vreg, bool is_real)
-{
- int rc = 0;
- int i;
- u8 bank;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current test2 register state. */
- for (i = 0; i < SMPS_TEST_BANKS; i++) {
- bank = REGULATOR_BANK_SEL(i);
- rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
- &vreg->test_reg[i]);
- if (rc)
- goto bail;
- vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
- }
-
- /* Save the current clock control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
- &vreg->clk_ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current sleep control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
- &vreg->sleep_ctrl_reg);
- if (rc)
- goto bail;
-
- vreg->save_uV = _pm8018_smps_get_voltage(vreg);
-
- if (is_real) {
- /* Set advanced mode pull down enable based on platform data. */
- rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
- (vreg->pdata.pull_down_enable
- ? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
- | REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
- REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
- &vreg->test_reg[6]);
- if (rc)
- goto bail;
-
- vreg->is_enabled = !!_pm8018_vreg_is_enabled(vreg);
-
- vreg->mode = ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
- == SMPS_CLK_CTRL_PFM ?
- REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
- }
-
- if (!SMPS_IN_ADVANCED_MODE(vreg) && is_real) {
- /* Set legacy mode pull down enable based on platform data. */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- (vreg->pdata.pull_down_enable
- ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
- SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8018_init_vs(struct pm8018_vreg *vreg, bool is_real)
-{
- int rc = 0;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc) {
- vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
- return rc;
- }
-
- if (is_real) {
- /* Set pull down enable based on platform data. */
- rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
- (vreg->pdata.pull_down_enable ? VS_PULL_DOWN_ENABLE : 0),
- VS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg,
- "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
- vreg->is_enabled = !!_pm8018_vreg_is_enabled(vreg);
- }
-
- return rc;
-}
-
-int pc_id_to_real_id(int id)
-{
- int real_id;
-
- if (id >= PM8018_VREG_ID_L2_PC && id <= PM8018_VREG_ID_L8_PC)
- real_id = id - PM8018_VREG_ID_L2_PC + PM8018_VREG_ID_L2;
- else
- real_id = id - PM8018_VREG_ID_L13_PC + PM8018_VREG_ID_L13;
-
- return real_id;
-}
-
-static int __devinit pm8018_vreg_probe(struct platform_device *pdev)
-{
- const struct pm8018_regulator_platform_data *pdata;
- enum pm8018_vreg_pin_function pin_fn;
- struct regulator_desc *rdesc;
- struct pm8018_vreg *vreg;
- const char *reg_name = "";
- unsigned pin_ctrl;
- int rc = 0, id = pdev->id;
-
- if (pdev == NULL)
- return -EINVAL;
-
- if (pdev->id >= 0 && pdev->id < PM8018_VREG_ID_MAX) {
- pdata = pdev->dev.platform_data;
- rdesc = &pm8018_vreg_description[pdev->id];
- if (!IS_REAL_REGULATOR(pdev->id))
- id = pc_id_to_real_id(pdev->id);
- vreg = &pm8018_vreg[id];
- reg_name = pm8018_vreg_description[pdev->id].name;
- if (!pdata) {
- pr_err("%s requires platform data\n", reg_name);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- if (IS_REAL_REGULATOR(pdev->id)) {
- /* Do not modify pin control and pin function values. */
- pin_ctrl = vreg->pdata.pin_ctrl;
- pin_fn = vreg->pdata.pin_fn;
- memcpy(&(vreg->pdata), pdata,
- sizeof(struct pm8018_regulator_platform_data));
- vreg->pdata.pin_ctrl = pin_ctrl;
- vreg->pdata.pin_fn = pin_fn;
- vreg->dev = &pdev->dev;
- vreg->name = reg_name;
- } else {
- /* Pin control regulator */
- if ((pdata->pin_ctrl &
- (PM8018_VREG_PIN_CTRL_D1 | PM8018_VREG_PIN_CTRL_A0
- | PM8018_VREG_PIN_CTRL_A1 | PM8018_VREG_PIN_CTRL_A2))
- == PM8018_VREG_PIN_CTRL_NONE) {
- pr_err("%s: no pin control input specified\n",
- reg_name);
- mutex_unlock(&vreg->pc_lock);
- return -EINVAL;
- }
- vreg->pdata.pin_ctrl = pdata->pin_ctrl;
- vreg->pdata.pin_fn = pdata->pin_fn;
- vreg->dev_pc = &pdev->dev;
- if (!vreg->dev)
- vreg->dev = &pdev->dev;
- if (!vreg->name)
- vreg->name = reg_name;
- }
-
- /* Initialize register values. */
- switch (vreg->type) {
- case REGULATOR_TYPE_PLDO:
- case REGULATOR_TYPE_NLDO:
- rc = pm8018_init_ldo(vreg, IS_REAL_REGULATOR(pdev->id));
- break;
- case REGULATOR_TYPE_NLDO1200:
- rc = pm8018_init_nldo1200(vreg);
- break;
- case REGULATOR_TYPE_SMPS:
- rc = pm8018_init_smps(vreg,
- IS_REAL_REGULATOR(pdev->id));
- break;
- case REGULATOR_TYPE_VS:
- rc = pm8018_init_vs(vreg, IS_REAL_REGULATOR(pdev->id));
- break;
- }
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- goto bail;
-
- if (IS_REAL_REGULATOR(pdev->id)) {
- vreg->rdev = regulator_register(rdesc, &pdev->dev,
- &(pdata->init_data), vreg);
- if (IS_ERR(vreg->rdev)) {
- rc = PTR_ERR(vreg->rdev);
- vreg->rdev = NULL;
- pr_err("regulator_register failed: %s, rc=%d\n",
- reg_name, rc);
- }
- } else {
- vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
- &(pdata->init_data), vreg);
- if (IS_ERR(vreg->rdev_pc)) {
- rc = PTR_ERR(vreg->rdev_pc);
- vreg->rdev_pc = NULL;
- pr_err("regulator_register failed: %s, rc=%d\n",
- reg_name, rc);
- }
- }
- if ((pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_INIT) && !rc
- && vreg->rdev)
- pm8018_vreg_show_state(vreg->rdev,
- PM8018_REGULATOR_ACTION_INIT);
- } else {
- rc = -ENODEV;
- }
-
-bail:
- if (rc)
- pr_err("error for %s, rc=%d\n", reg_name, rc);
-
- return rc;
-}
-
-static int __devexit pm8018_vreg_remove(struct platform_device *pdev)
-{
- if (IS_REAL_REGULATOR(pdev->id))
- regulator_unregister(pm8018_vreg[pdev->id].rdev);
- else
- regulator_unregister(
- pm8018_vreg[pc_id_to_real_id(pdev->id)].rdev_pc);
-
- return 0;
-}
-
-static struct platform_driver pm8018_vreg_driver = {
- .probe = pm8018_vreg_probe,
- .remove = __devexit_p(pm8018_vreg_remove),
- .driver = {
- .name = PM8018_REGULATOR_DEV_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8018_vreg_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pm8018_vreg); i++) {
- mutex_init(&pm8018_vreg[i].pc_lock);
- pm8018_vreg[i].write_count = 0;
- pm8018_vreg[i].prev_write_count = -1;
- }
-
- return platform_driver_register(&pm8018_vreg_driver);
-}
-postcore_initcall(pm8018_vreg_init);
-
-static void __exit pm8018_vreg_exit(void)
-{
- int i;
-
- platform_driver_unregister(&pm8018_vreg_driver);
-
- for (i = 0; i < ARRAY_SIZE(pm8018_vreg); i++)
- mutex_destroy(&pm8018_vreg[i].pc_lock);
-}
-module_exit(pm8018_vreg_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8018 regulator driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:" PM8018_REGULATOR_DEV_NAME);
diff --git a/drivers/regulator/pm8921-regulator.c b/drivers/regulator/pm8921-regulator.c
deleted file mode 100644
index 69a1318..0000000
--- a/drivers/regulator/pm8921-regulator.c
+++ /dev/null
@@ -1,3303 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/pm8921-regulator.h>
-#include <linux/mfd/pm8xxx/core.h>
-
-/* Debug Flag Definitions */
-enum {
- PM8921_VREG_DEBUG_REQUEST = BIT(0),
- PM8921_VREG_DEBUG_DUPLICATE = BIT(1),
- PM8921_VREG_DEBUG_INIT = BIT(2),
- PM8921_VREG_DEBUG_WRITES = BIT(3), /* SSBI writes */
-};
-
-static int pm8921_vreg_debug_mask;
-module_param_named(
- debug_mask, pm8921_vreg_debug_mask, int, S_IRUSR | S_IWUSR
-);
-
-#define REGULATOR_TYPE_PLDO 0
-#define REGULATOR_TYPE_NLDO 1
-#define REGULATOR_TYPE_NLDO1200 2
-#define REGULATOR_TYPE_SMPS 3
-#define REGULATOR_TYPE_FTSMPS 4
-#define REGULATOR_TYPE_VS 5
-#define REGULATOR_TYPE_VS300 6
-#define REGULATOR_TYPE_NCP 7
-
-/* Common Masks */
-#define REGULATOR_ENABLE_MASK 0x80
-#define REGULATOR_ENABLE 0x80
-#define REGULATOR_DISABLE 0x00
-
-#define REGULATOR_BANK_MASK 0xF0
-#define REGULATOR_BANK_SEL(n) ((n) << 4)
-#define REGULATOR_BANK_WRITE 0x80
-
-#define LDO_TEST_BANKS 7
-#define NLDO1200_TEST_BANKS 5
-#define SMPS_TEST_BANKS 8
-#define REGULATOR_TEST_BANKS_MAX SMPS_TEST_BANKS
-
-/*
- * This voltage in uV is returned by get_voltage functions when there is no way
- * to determine the current voltage level. It is needed because the regulator
- * framework treats a 0 uV voltage as an error.
- */
-#define VOLTAGE_UNKNOWN 1
-
-/* LDO masks and values */
-
-/* CTRL register */
-#define LDO_ENABLE_MASK 0x80
-#define LDO_DISABLE 0x00
-#define LDO_ENABLE 0x80
-#define LDO_PULL_DOWN_ENABLE_MASK 0x40
-#define LDO_PULL_DOWN_ENABLE 0x40
-
-#define LDO_CTRL_PM_MASK 0x20
-#define LDO_CTRL_PM_HPM 0x00
-#define LDO_CTRL_PM_LPM 0x20
-
-#define LDO_CTRL_VPROG_MASK 0x1F
-
-/* TEST register bank 0 */
-#define LDO_TEST_LPM_MASK 0x04
-#define LDO_TEST_LPM_SEL_CTRL 0x00
-#define LDO_TEST_LPM_SEL_TCXO 0x04
-
-/* TEST register bank 2 */
-#define LDO_TEST_VPROG_UPDATE_MASK 0x08
-#define LDO_TEST_RANGE_SEL_MASK 0x04
-#define LDO_TEST_FINE_STEP_MASK 0x02
-#define LDO_TEST_FINE_STEP_SHIFT 1
-
-/* TEST register bank 4 */
-#define LDO_TEST_RANGE_EXT_MASK 0x01
-
-/* TEST register bank 5 */
-#define LDO_TEST_PIN_CTRL_MASK 0x0F
-#define LDO_TEST_PIN_CTRL_EN3 0x08
-#define LDO_TEST_PIN_CTRL_EN2 0x04
-#define LDO_TEST_PIN_CTRL_EN1 0x02
-#define LDO_TEST_PIN_CTRL_EN0 0x01
-
-/* TEST register bank 6 */
-#define LDO_TEST_PIN_CTRL_LPM_MASK 0x0F
-
-
-/*
- * If a given voltage could be output by two ranges, then the preferred one must
- * be determined by the range limits. Specified voltage ranges should must
- * not overlap.
- *
- * Allowable voltage ranges:
- */
-#define PLDO_LOW_UV_MIN 750000
-#define PLDO_LOW_UV_MAX 1487500
-#define PLDO_LOW_UV_FINE_STEP 12500
-
-#define PLDO_NORM_UV_MIN 1500000
-#define PLDO_NORM_UV_MAX 3075000
-#define PLDO_NORM_UV_FINE_STEP 25000
-
-#define PLDO_HIGH_UV_MIN 1750000
-#define PLDO_HIGH_UV_SET_POINT_MIN 3100000
-#define PLDO_HIGH_UV_MAX 4900000
-#define PLDO_HIGH_UV_FINE_STEP 50000
-
-#define PLDO_LOW_SET_POINTS ((PLDO_LOW_UV_MAX - PLDO_LOW_UV_MIN) \
- / PLDO_LOW_UV_FINE_STEP + 1)
-#define PLDO_NORM_SET_POINTS ((PLDO_NORM_UV_MAX - PLDO_NORM_UV_MIN) \
- / PLDO_NORM_UV_FINE_STEP + 1)
-#define PLDO_HIGH_SET_POINTS ((PLDO_HIGH_UV_MAX \
- - PLDO_HIGH_UV_SET_POINT_MIN) \
- / PLDO_HIGH_UV_FINE_STEP + 1)
-#define PLDO_SET_POINTS (PLDO_LOW_SET_POINTS \
- + PLDO_NORM_SET_POINTS \
- + PLDO_HIGH_SET_POINTS)
-
-#define NLDO_UV_MIN 750000
-#define NLDO_UV_MAX 1537500
-#define NLDO_UV_FINE_STEP 12500
-
-#define NLDO_SET_POINTS ((NLDO_UV_MAX - NLDO_UV_MIN) \
- / NLDO_UV_FINE_STEP + 1)
-
-/* NLDO1200 masks and values */
-
-/* CTRL register */
-#define NLDO1200_ENABLE_MASK 0x80
-#define NLDO1200_DISABLE 0x00
-#define NLDO1200_ENABLE 0x80
-
-/* Legacy mode */
-#define NLDO1200_LEGACY_PM_MASK 0x20
-#define NLDO1200_LEGACY_PM_HPM 0x00
-#define NLDO1200_LEGACY_PM_LPM 0x20
-
-/* Advanced mode */
-#define NLDO1200_CTRL_RANGE_MASK 0x40
-#define NLDO1200_CTRL_RANGE_HIGH 0x00
-#define NLDO1200_CTRL_RANGE_LOW 0x40
-#define NLDO1200_CTRL_VPROG_MASK 0x3F
-
-#define NLDO1200_LOW_UV_MIN 375000
-#define NLDO1200_LOW_UV_MAX 743750
-#define NLDO1200_LOW_UV_STEP 6250
-
-#define NLDO1200_HIGH_UV_MIN 750000
-#define NLDO1200_HIGH_UV_MAX 1537500
-#define NLDO1200_HIGH_UV_STEP 12500
-
-#define NLDO1200_LOW_SET_POINTS ((NLDO1200_LOW_UV_MAX \
- - NLDO1200_LOW_UV_MIN) \
- / NLDO1200_LOW_UV_STEP + 1)
-#define NLDO1200_HIGH_SET_POINTS ((NLDO1200_HIGH_UV_MAX \
- - NLDO1200_HIGH_UV_MIN) \
- / NLDO1200_HIGH_UV_STEP + 1)
-#define NLDO1200_SET_POINTS (NLDO1200_LOW_SET_POINTS \
- + NLDO1200_HIGH_SET_POINTS)
-
-/* TEST register bank 0 */
-#define NLDO1200_TEST_LPM_MASK 0x04
-#define NLDO1200_TEST_LPM_SEL_CTRL 0x00
-#define NLDO1200_TEST_LPM_SEL_TCXO 0x04
-
-/* TEST register bank 1 */
-#define NLDO1200_PULL_DOWN_ENABLE_MASK 0x02
-#define NLDO1200_PULL_DOWN_ENABLE 0x02
-
-/* TEST register bank 2 */
-#define NLDO1200_ADVANCED_MODE_MASK 0x08
-#define NLDO1200_ADVANCED_MODE 0x00
-#define NLDO1200_LEGACY_MODE 0x08
-
-/* Advanced mode power mode control */
-#define NLDO1200_ADVANCED_PM_MASK 0x02
-#define NLDO1200_ADVANCED_PM_HPM 0x00
-#define NLDO1200_ADVANCED_PM_LPM 0x02
-
-#define NLDO1200_IN_ADVANCED_MODE(vreg) \
- ((vreg->test_reg[2] & NLDO1200_ADVANCED_MODE_MASK) \
- == NLDO1200_ADVANCED_MODE)
-
-/* SMPS masks and values */
-
-/* CTRL register */
-
-/* Legacy mode */
-#define SMPS_LEGACY_ENABLE_MASK 0x80
-#define SMPS_LEGACY_DISABLE 0x00
-#define SMPS_LEGACY_ENABLE 0x80
-#define SMPS_LEGACY_PULL_DOWN_ENABLE 0x40
-#define SMPS_LEGACY_VREF_SEL_MASK 0x20
-#define SMPS_LEGACY_VPROG_MASK 0x1F
-
-/* Advanced mode */
-#define SMPS_ADVANCED_BAND_MASK 0xC0
-#define SMPS_ADVANCED_BAND_OFF 0x00
-#define SMPS_ADVANCED_BAND_1 0x40
-#define SMPS_ADVANCED_BAND_2 0x80
-#define SMPS_ADVANCED_BAND_3 0xC0
-#define SMPS_ADVANCED_VPROG_MASK 0x3F
-
-/* Legacy mode voltage ranges */
-#define SMPS_MODE3_UV_MIN 375000
-#define SMPS_MODE3_UV_MAX 725000
-#define SMPS_MODE3_UV_STEP 25000
-
-#define SMPS_MODE2_UV_MIN 750000
-#define SMPS_MODE2_UV_MAX 1475000
-#define SMPS_MODE2_UV_STEP 25000
-
-#define SMPS_MODE1_UV_MIN 1500000
-#define SMPS_MODE1_UV_MAX 3050000
-#define SMPS_MODE1_UV_STEP 50000
-
-#define SMPS_MODE3_SET_POINTS ((SMPS_MODE3_UV_MAX \
- - SMPS_MODE3_UV_MIN) \
- / SMPS_MODE3_UV_STEP + 1)
-#define SMPS_MODE2_SET_POINTS ((SMPS_MODE2_UV_MAX \
- - SMPS_MODE2_UV_MIN) \
- / SMPS_MODE2_UV_STEP + 1)
-#define SMPS_MODE1_SET_POINTS ((SMPS_MODE1_UV_MAX \
- - SMPS_MODE1_UV_MIN) \
- / SMPS_MODE1_UV_STEP + 1)
-#define SMPS_LEGACY_SET_POINTS (SMPS_MODE3_SET_POINTS \
- + SMPS_MODE2_SET_POINTS \
- + SMPS_MODE1_SET_POINTS)
-
-/* Advanced mode voltage ranges */
-#define SMPS_BAND1_UV_MIN 375000
-#define SMPS_BAND1_UV_MAX 737500
-#define SMPS_BAND1_UV_STEP 12500
-
-#define SMPS_BAND2_UV_MIN 750000
-#define SMPS_BAND2_UV_MAX 1487500
-#define SMPS_BAND2_UV_STEP 12500
-
-#define SMPS_BAND3_UV_MIN 1500000
-#define SMPS_BAND3_UV_MAX 3075000
-#define SMPS_BAND3_UV_STEP 25000
-
-#define SMPS_BAND1_SET_POINTS ((SMPS_BAND1_UV_MAX \
- - SMPS_BAND1_UV_MIN) \
- / SMPS_BAND1_UV_STEP + 1)
-#define SMPS_BAND2_SET_POINTS ((SMPS_BAND2_UV_MAX \
- - SMPS_BAND2_UV_MIN) \
- / SMPS_BAND2_UV_STEP + 1)
-#define SMPS_BAND3_SET_POINTS ((SMPS_BAND3_UV_MAX \
- - SMPS_BAND3_UV_MIN) \
- / SMPS_BAND3_UV_STEP + 1)
-#define SMPS_ADVANCED_SET_POINTS (SMPS_BAND1_SET_POINTS \
- + SMPS_BAND2_SET_POINTS \
- + SMPS_BAND3_SET_POINTS)
-
-/* Test2 register bank 1 */
-#define SMPS_LEGACY_VLOW_SEL_MASK 0x01
-
-/* Test2 register bank 6 */
-#define SMPS_ADVANCED_PULL_DOWN_ENABLE 0x08
-
-/* Test2 register bank 7 */
-#define SMPS_ADVANCED_MODE_MASK 0x02
-#define SMPS_ADVANCED_MODE 0x02
-#define SMPS_LEGACY_MODE 0x00
-
-#define SMPS_IN_ADVANCED_MODE(vreg) \
- ((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
-
-/* BUCK_SLEEP_CNTRL register */
-#define SMPS_PIN_CTRL_MASK 0xF0
-#define SMPS_PIN_CTRL_EN3 0x80
-#define SMPS_PIN_CTRL_EN2 0x40
-#define SMPS_PIN_CTRL_EN1 0x20
-#define SMPS_PIN_CTRL_EN0 0x10
-
-#define SMPS_PIN_CTRL_LPM_MASK 0x0F
-#define SMPS_PIN_CTRL_LPM_EN3 0x08
-#define SMPS_PIN_CTRL_LPM_EN2 0x04
-#define SMPS_PIN_CTRL_LPM_EN1 0x02
-#define SMPS_PIN_CTRL_LPM_EN0 0x01
-
-/* BUCK_CLOCK_CNTRL register */
-#define SMPS_CLK_DIVIDE2 0x40
-
-#define SMPS_CLK_CTRL_MASK 0x30
-#define SMPS_CLK_CTRL_FOLLOW_TCXO 0x00
-#define SMPS_CLK_CTRL_PWM 0x10
-#define SMPS_CLK_CTRL_PFM 0x20
-
-/* FTSMPS masks and values */
-
-/* CTRL register */
-#define FTSMPS_VCTRL_BAND_MASK 0xC0
-#define FTSMPS_VCTRL_BAND_OFF 0x00
-#define FTSMPS_VCTRL_BAND_1 0x40
-#define FTSMPS_VCTRL_BAND_2 0x80
-#define FTSMPS_VCTRL_BAND_3 0xC0
-#define FTSMPS_VCTRL_VPROG_MASK 0x3F
-
-#define FTSMPS_BAND1_UV_MIN 350000
-#define FTSMPS_BAND1_UV_MAX 650000
-/* 3 LSB's of program voltage must be 0 in band 1. */
-/* Logical step size */
-#define FTSMPS_BAND1_UV_LOG_STEP 50000
-/* Physical step size */
-#define FTSMPS_BAND1_UV_PHYS_STEP 6250
-
-#define FTSMPS_BAND2_UV_MIN 700000
-#define FTSMPS_BAND2_UV_MAX 1400000
-#define FTSMPS_BAND2_UV_STEP 12500
-
-#define FTSMPS_BAND3_UV_MIN 1400000
-#define FTSMPS_BAND3_UV_SET_POINT_MIN 1500000
-#define FTSMPS_BAND3_UV_MAX 3300000
-#define FTSMPS_BAND3_UV_STEP 50000
-
-#define FTSMPS_BAND1_SET_POINTS ((FTSMPS_BAND1_UV_MAX \
- - FTSMPS_BAND1_UV_MIN) \
- / FTSMPS_BAND1_UV_LOG_STEP + 1)
-#define FTSMPS_BAND2_SET_POINTS ((FTSMPS_BAND2_UV_MAX \
- - FTSMPS_BAND2_UV_MIN) \
- / FTSMPS_BAND2_UV_STEP + 1)
-#define FTSMPS_BAND3_SET_POINTS ((FTSMPS_BAND3_UV_MAX \
- - FTSMPS_BAND3_UV_SET_POINT_MIN) \
- / FTSMPS_BAND3_UV_STEP + 1)
-#define FTSMPS_SET_POINTS (FTSMPS_BAND1_SET_POINTS \
- + FTSMPS_BAND2_SET_POINTS \
- + FTSMPS_BAND3_SET_POINTS)
-
-/* FTS_CNFG1 register bank 0 */
-#define FTSMPS_CNFG1_PM_MASK 0x0C
-#define FTSMPS_CNFG1_PM_PWM 0x00
-#define FTSMPS_CNFG1_PM_PFM 0x08
-
-/* PWR_CNFG register */
-#define FTSMPS_PULL_DOWN_ENABLE_MASK 0x40
-#define FTSMPS_PULL_DOWN_ENABLE 0x40
-
-/* VS masks and values */
-
-/* CTRL register */
-#define VS_ENABLE_MASK 0x80
-#define VS_DISABLE 0x00
-#define VS_ENABLE 0x80
-#define VS_PULL_DOWN_ENABLE_MASK 0x40
-#define VS_PULL_DOWN_DISABLE 0x40
-#define VS_PULL_DOWN_ENABLE 0x00
-
-#define VS_PIN_CTRL_MASK 0x0F
-#define VS_PIN_CTRL_EN0 0x08
-#define VS_PIN_CTRL_EN1 0x04
-#define VS_PIN_CTRL_EN2 0x02
-#define VS_PIN_CTRL_EN3 0x01
-
-/* VS300 masks and values */
-
-/* CTRL register */
-#define VS300_CTRL_ENABLE_MASK 0xC0
-#define VS300_CTRL_DISABLE 0x00
-#define VS300_CTRL_ENABLE 0x40
-
-#define VS300_PULL_DOWN_ENABLE_MASK 0x20
-#define VS300_PULL_DOWN_ENABLE 0x20
-
-/* NCP masks and values */
-
-/* CTRL register */
-#define NCP_ENABLE_MASK 0x80
-#define NCP_DISABLE 0x00
-#define NCP_ENABLE 0x80
-#define NCP_VPROG_MASK 0x1F
-
-#define NCP_UV_MIN 1500000
-#define NCP_UV_MAX 3050000
-#define NCP_UV_STEP 50000
-
-#define NCP_SET_POINTS ((NCP_UV_MAX - NCP_UV_MIN) \
- / NCP_UV_STEP + 1)
-
-#define IS_REAL_REGULATOR(id) ((id) >= 0 && \
- (id) < PM8921_VREG_ID_L1_PC)
-
-struct pm8921_vreg {
- /* Configuration data */
- struct regulator_dev *rdev;
- struct regulator_dev *rdev_pc;
- struct device *dev;
- struct device *dev_pc;
- const char *name;
- struct pm8921_regulator_platform_data pdata;
- const int hpm_min_load;
- const u16 ctrl_addr;
- const u16 test_addr;
- const u16 clk_ctrl_addr;
- const u16 sleep_ctrl_addr;
- const u16 pfm_ctrl_addr;
- const u16 pwr_cnfg_addr;
- const u8 type;
- /* State data */
- struct mutex pc_lock;
- int save_uV;
- int mode;
- u32 write_count;
- u32 prev_write_count;
- bool is_enabled;
- bool is_enabled_pc;
- u8 test_reg[REGULATOR_TEST_BANKS_MAX];
- u8 ctrl_reg;
- u8 clk_ctrl_reg;
- u8 sleep_ctrl_reg;
- u8 pfm_ctrl_reg;
- u8 pwr_cnfg_reg;
-};
-
-#define vreg_err(vreg, fmt, ...) \
- pr_err("%s: " fmt, vreg->name, ##__VA_ARGS__)
-
-#define PLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_PLDO, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .hpm_min_load = PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define NLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_NLDO, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .hpm_min_load = PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define NLDO1200(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_NLDO1200, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .hpm_min_load = PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define SMPS(_id, _ctrl_addr, _test_addr, _clk_ctrl_addr, _sleep_ctrl_addr, \
- _hpm_min_load) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_SMPS, \
- .ctrl_addr = _ctrl_addr, \
- .test_addr = _test_addr, \
- .clk_ctrl_addr = _clk_ctrl_addr, \
- .sleep_ctrl_addr = _sleep_ctrl_addr, \
- .hpm_min_load = PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define FTSMPS(_id, _pwm_ctrl_addr, _fts_cnfg1_addr, _pfm_ctrl_addr, \
- _pwr_cnfg_addr, _hpm_min_load) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_FTSMPS, \
- .ctrl_addr = _pwm_ctrl_addr, \
- .test_addr = _fts_cnfg1_addr, \
- .pfm_ctrl_addr = _pfm_ctrl_addr, \
- .pwr_cnfg_addr = _pwr_cnfg_addr, \
- .hpm_min_load = PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- }
-
-#define VS(_id, _ctrl_addr) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_VS, \
- .ctrl_addr = _ctrl_addr, \
- }
-
-#define VS300(_id, _ctrl_addr) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_VS300, \
- .ctrl_addr = _ctrl_addr, \
- }
-
-#define NCP(_id, _ctrl_addr) \
- [PM8921_VREG_ID_##_id] = { \
- .type = REGULATOR_TYPE_NCP, \
- .ctrl_addr = _ctrl_addr, \
- }
-
-static struct pm8921_vreg pm8921_vreg[] = {
- /* id ctrl test hpm_min */
- NLDO(L1, 0x0AE, 0x0AF, LDO_150),
- NLDO(L2, 0x0B0, 0x0B1, LDO_150),
- PLDO(L3, 0x0B2, 0x0B3, LDO_150),
- PLDO(L4, 0x0B4, 0x0B5, LDO_50),
- PLDO(L5, 0x0B6, 0x0B7, LDO_300),
- PLDO(L6, 0x0B8, 0x0B9, LDO_600),
- PLDO(L7, 0x0BA, 0x0BB, LDO_150),
- PLDO(L8, 0x0BC, 0x0BD, LDO_300),
- PLDO(L9, 0x0BE, 0x0BF, LDO_300),
- PLDO(L10, 0x0C0, 0x0C1, LDO_600),
- PLDO(L11, 0x0C2, 0x0C3, LDO_150),
- NLDO(L12, 0x0C4, 0x0C5, LDO_150),
- PLDO(L14, 0x0C8, 0x0C9, LDO_50),
- PLDO(L15, 0x0CA, 0x0CB, LDO_150),
- PLDO(L16, 0x0CC, 0x0CD, LDO_300),
- PLDO(L17, 0x0CE, 0x0CF, LDO_150),
- NLDO(L18, 0x0D0, 0x0D1, LDO_150),
- PLDO(L21, 0x0D6, 0x0D7, LDO_150),
- PLDO(L22, 0x0D8, 0x0D9, LDO_150),
- PLDO(L23, 0x0DA, 0x0DB, LDO_150),
-
- /* id ctrl test hpm_min */
- NLDO1200(L24, 0x0DC, 0x0DD, LDO_1200),
- NLDO1200(L25, 0x0DE, 0x0DF, LDO_1200),
- NLDO1200(L26, 0x0E0, 0x0E1, LDO_1200),
- NLDO1200(L27, 0x0E2, 0x0E3, LDO_1200),
- NLDO1200(L28, 0x0E4, 0x0E5, LDO_1200),
-
- /* id ctrl test hpm_min */
- PLDO(L29, 0x0E6, 0x0E7, LDO_150),
-
- /* id ctrl test2 clk sleep hpm_min */
- SMPS(S1, 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
- SMPS(S2, 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
- SMPS(S3, 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
- SMPS(S4, 0x1E8, 0x1ED, 0x011, 0x1EA, SMPS_1500),
-
- /* id ctrl fts_cnfg1 pfm pwr_cnfg hpm_min */
- FTSMPS(S5, 0x025, 0x02E, 0x026, 0x032, SMPS_2000),
- FTSMPS(S6, 0x036, 0x03F, 0x037, 0x043, SMPS_2000),
-
- /* id ctrl test2 clk sleep hpm_min */
- SMPS(S7, 0x1F0, 0x1F5, 0x012, 0x1F2, SMPS_1500),
- SMPS(S8, 0x1F8, 0x1FD, 0x013, 0x1FA, SMPS_1500),
-
- /* id ctrl */
- VS(LVS1, 0x060),
- VS300(LVS2, 0x062),
- VS(LVS3, 0x064),
- VS(LVS4, 0x066),
- VS(LVS5, 0x068),
- VS(LVS6, 0x06A),
- VS(LVS7, 0x06C),
- VS300(USB_OTG, 0x06E),
- VS300(HDMI_MVS, 0x070),
-
- /* id ctrl */
- NCP(NCP, 0x090),
-};
-
-/* Determines which label to add to the print. */
-enum pm8921_regulator_action {
- PM8921_REGULATOR_ACTION_INIT,
- PM8921_REGULATOR_ACTION_ENABLE,
- PM8921_REGULATOR_ACTION_DISABLE,
- PM8921_REGULATOR_ACTION_VOLTAGE,
- PM8921_REGULATOR_ACTION_MODE,
- PM8921_REGULATOR_ACTION_PIN_CTRL,
-};
-
-/* Debug state printing */
-static void pm8921_vreg_show_state(struct regulator_dev *rdev,
- enum pm8921_regulator_action action);
-
-/*
- * Perform a masked write to a PMIC register only if the new value differs
- * from the last value written to the register. This removes redundant
- * register writing.
- *
- * No locking is required because registers are not shared between regulators.
- */
-static int pm8921_vreg_masked_write(struct pm8921_vreg *vreg, u16 addr, u8 val,
- u8 mask, u8 *reg_save)
-{
- int rc = 0;
- u8 reg;
-
- reg = (*reg_save & ~mask) | (val & mask);
- if (reg != *reg_save) {
- rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
- if (rc) {
- pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
- vreg->name, addr, rc);
- } else {
- *reg_save = reg;
- vreg->write_count++;
- if (pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_WRITES)
- pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
- addr, reg);
- }
- }
-
- return rc;
-}
-
-/*
- * Perform a masked write to a PMIC register without checking the previously
- * written value. This is needed for registers that must be rewritten even if
- * the value hasn't changed in order for changes in other registers to take
- * effect.
- */
-static int pm8921_vreg_masked_write_forced(struct pm8921_vreg *vreg, u16 addr,
- u8 val, u8 mask, u8 *reg_save)
-{
- int rc = 0;
- u8 reg;
-
- reg = (*reg_save & ~mask) | (val & mask);
- rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
- if (rc) {
- pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
- vreg->name, addr, rc);
- } else {
- *reg_save = reg;
- vreg->write_count++;
- if (pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_WRITES)
- pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
- addr, reg);
- }
-
- return rc;
-}
-
-static int pm8921_vreg_is_pin_controlled(struct pm8921_vreg *vreg)
-{
- int ret = 0;
-
- switch (vreg->type) {
- case REGULATOR_TYPE_PLDO:
- case REGULATOR_TYPE_NLDO:
- ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
- | (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
- break;
- case REGULATOR_TYPE_SMPS:
- ret = vreg->sleep_ctrl_reg
- & (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
- break;
- case REGULATOR_TYPE_VS:
- ret = vreg->ctrl_reg & VS_PIN_CTRL_MASK;
- break;
- }
-
- return ret;
-}
-
-/*
- * Returns the logical pin control enable state because the pin control options
- * present in the hardware out of restart could be different from those desired
- * by the consumer.
- */
-static int pm8921_vreg_pin_control_is_enabled(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int enabled;
-
- mutex_lock(&vreg->pc_lock);
- enabled = vreg->is_enabled_pc;
- mutex_unlock(&vreg->pc_lock);
-
- return enabled;
-}
-
-/* Returns the physical enable state of the regulator. */
-static int _pm8921_vreg_is_enabled(struct pm8921_vreg *vreg)
-{
- int rc = 0;
-
- /*
- * All regulator types except advanced mode SMPS, FTSMPS, and VS300 have
- * enable bit in bit 7 of the control register.
- */
- switch (vreg->type) {
- case REGULATOR_TYPE_FTSMPS:
- if ((vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK)
- != FTSMPS_VCTRL_BAND_OFF)
- rc = 1;
- break;
- case REGULATOR_TYPE_VS300:
- if ((vreg->ctrl_reg & VS300_CTRL_ENABLE_MASK)
- != VS300_CTRL_DISABLE)
- rc = 1;
- break;
- case REGULATOR_TYPE_SMPS:
- if (SMPS_IN_ADVANCED_MODE(vreg)) {
- if ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
- != SMPS_ADVANCED_BAND_OFF)
- rc = 1;
- break;
- }
- /* Fall through for legacy mode SMPS. */
- default:
- if ((vreg->ctrl_reg & REGULATOR_ENABLE_MASK)
- == REGULATOR_ENABLE)
- rc = 1;
- }
-
- return rc;
-}
-
-/*
- * Returns the logical enable state of the regulator which may be different from
- * the physical enable state thanks to HPM/LPM pin control.
- */
-static int pm8921_vreg_is_enabled(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int enabled;
-
- if (vreg->type == REGULATOR_TYPE_PLDO
- || vreg->type == REGULATOR_TYPE_NLDO
- || vreg->type == REGULATOR_TYPE_SMPS
- || vreg->type == REGULATOR_TYPE_VS) {
- /* Pin controllable */
- mutex_lock(&vreg->pc_lock);
- enabled = vreg->is_enabled;
- mutex_unlock(&vreg->pc_lock);
- } else {
- /* Not pin controlable */
- enabled = _pm8921_vreg_is_enabled(vreg);
- }
-
- return enabled;
-}
-
-static int pm8921_pldo_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int vmin, fine_step;
- u8 range_ext, range_sel, vprog, fine_step_reg;
-
- mutex_lock(&vreg->pc_lock);
-
- fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
- range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
- range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
- vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
- mutex_unlock(&vreg->pc_lock);
-
- vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
- if (range_sel) {
- /* low range mode */
- fine_step = PLDO_LOW_UV_FINE_STEP;
- vmin = PLDO_LOW_UV_MIN;
- } else if (!range_ext) {
- /* normal mode */
- fine_step = PLDO_NORM_UV_FINE_STEP;
- vmin = PLDO_NORM_UV_MIN;
- } else {
- /* high range mode */
- fine_step = PLDO_HIGH_UV_FINE_STEP;
- vmin = PLDO_HIGH_UV_MIN;
- }
-
- return fine_step * vprog + vmin;
-}
-
-static int pm8921_pldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int uV;
-
- if (selector >= PLDO_SET_POINTS)
- return 0;
-
- if (selector < PLDO_LOW_SET_POINTS)
- uV = selector * PLDO_LOW_UV_FINE_STEP + PLDO_LOW_UV_MIN;
- else if (selector < (PLDO_LOW_SET_POINTS + PLDO_NORM_SET_POINTS))
- uV = (selector - PLDO_LOW_SET_POINTS) * PLDO_NORM_UV_FINE_STEP
- + PLDO_NORM_UV_MIN;
- else
- uV = (selector - PLDO_LOW_SET_POINTS - PLDO_NORM_SET_POINTS)
- * PLDO_HIGH_UV_FINE_STEP
- + PLDO_HIGH_UV_SET_POINT_MIN;
-
- return uV;
-}
-
-static int pm8921_pldo_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0, uV = min_uV;
- int vmin;
- unsigned vprog, fine_step;
- u8 range_ext, range_sel, fine_step_reg, prev_reg;
- bool reg_changed = false;
-
- if (uV < PLDO_LOW_UV_MIN && max_uV >= PLDO_LOW_UV_MIN)
- uV = PLDO_LOW_UV_MIN;
-
- if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, PLDO_LOW_UV_MIN, PLDO_HIGH_UV_MAX);
- return -EINVAL;
- }
-
- /*
- * This is a temporary hack to boost LDO 4 voltage from 1.8 V to 2.0 V
- * for old PMIC revisions which have register read back issues when
- * LDO 4 is set to 1.8 V.
- */
- if (vreg->pdata.id == PM8921_VREG_ID_L4
- && pm8xxx_get_revision(vreg->dev->parent)
- <= PM8XXX_REVISION_8921_1p1) {
- uV = 2000000;
- max_uV = 2000000;
- }
-
- if (uV > PLDO_NORM_UV_MAX) {
- vmin = PLDO_HIGH_UV_MIN;
- fine_step = PLDO_HIGH_UV_FINE_STEP;
- range_ext = LDO_TEST_RANGE_EXT_MASK;
- range_sel = 0;
- } else if (uV > PLDO_LOW_UV_MAX) {
- vmin = PLDO_NORM_UV_MIN;
- fine_step = PLDO_NORM_UV_FINE_STEP;
- range_ext = 0;
- range_sel = 0;
- } else {
- vmin = PLDO_LOW_UV_MIN;
- fine_step = PLDO_LOW_UV_FINE_STEP;
- range_ext = 0;
- range_sel = LDO_TEST_RANGE_SEL_MASK;
- }
-
- vprog = (uV - vmin + fine_step - 1) / fine_step;
- uV = vprog * fine_step + vmin;
- fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
- vprog >>= 1;
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- /* Write fine step, range select and program voltage update. */
- prev_reg = vreg->test_reg[2];
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
- | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
- LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
- | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
- &vreg->test_reg[2]);
- if (rc)
- goto bail;
- if (prev_reg != vreg->test_reg[2])
- reg_changed = true;
-
- /* Write range extension. */
- prev_reg = vreg->test_reg[4];
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- range_ext | REGULATOR_BANK_SEL(4)
- | REGULATOR_BANK_WRITE,
- LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[4]);
- if (rc)
- goto bail;
- if (prev_reg != vreg->test_reg[4])
- reg_changed = true;
-
- /* Write new voltage. */
- if (reg_changed) {
- /*
- * Force a CTRL register write even if the value hasn't changed.
- * This is neccessary because range select, range extension, and
- * fine step will not update until a value is written into the
- * control register.
- */
- rc = pm8921_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
- vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- } else {
- /* Only write to control register if new value is different. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
- LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- }
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int pm8921_nldo_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- u8 vprog, fine_step_reg;
-
- mutex_lock(&vreg->pc_lock);
-
- fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
- vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
- mutex_unlock(&vreg->pc_lock);
-
- vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
- return NLDO_UV_FINE_STEP * vprog + NLDO_UV_MIN;
-}
-
-static int pm8921_nldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector >= NLDO_SET_POINTS)
- return 0;
-
- return selector * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
-}
-
-static int pm8921_nldo_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned vprog, fine_step_reg, prev_reg;
- int rc;
- int uV = min_uV;
-
- if (uV < NLDO_UV_MIN && max_uV >= NLDO_UV_MIN)
- uV = NLDO_UV_MIN;
-
- if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
- return -EINVAL;
- }
-
- vprog = (uV - NLDO_UV_MIN + NLDO_UV_FINE_STEP - 1) / NLDO_UV_FINE_STEP;
- uV = vprog * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
- fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
- vprog >>= 1;
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- /* Write fine step. */
- prev_reg = vreg->test_reg[2];
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- fine_step_reg | REGULATOR_BANK_SEL(2)
- | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
- LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
- | LDO_TEST_VPROG_UPDATE_MASK,
- &vreg->test_reg[2]);
- if (rc)
- goto bail;
-
- /* Write new voltage. */
- if (prev_reg != vreg->test_reg[2]) {
- /*
- * Force a CTRL register write even if the value hasn't changed.
- * This is neccessary because fine step will not update until a
- * value is written into the control register.
- */
- rc = pm8921_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
- vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- } else {
- /* Only write to control register if new value is different. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
- LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
- }
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int _pm8921_nldo1200_get_voltage(struct pm8921_vreg *vreg)
-{
- int uV = 0;
- int vprog;
-
- if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
- pr_warn("%s: currently in legacy mode; voltage unknown.\n",
- vreg->name);
- return vreg->save_uV;
- }
-
- vprog = vreg->ctrl_reg & NLDO1200_CTRL_VPROG_MASK;
-
- if ((vreg->ctrl_reg & NLDO1200_CTRL_RANGE_MASK)
- == NLDO1200_CTRL_RANGE_LOW)
- uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
- else
- uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
-
- return uV;
-}
-
-static int pm8921_nldo1200_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-
- return _pm8921_nldo1200_get_voltage(vreg);
-}
-
-static int pm8921_nldo1200_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int uV;
-
- if (selector >= NLDO1200_SET_POINTS)
- return 0;
-
- if (selector < NLDO1200_LOW_SET_POINTS)
- uV = selector * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
- else
- uV = (selector - NLDO1200_LOW_SET_POINTS)
- * NLDO1200_HIGH_UV_STEP
- + NLDO1200_HIGH_UV_MIN;
-
- return uV;
-}
-
-static int _pm8921_nldo1200_set_voltage(struct pm8921_vreg *vreg, int min_uV,
- int max_uV)
-{
- u8 vprog, range;
- int rc;
- int uV = min_uV;
-
- if (uV < NLDO1200_LOW_UV_MIN && max_uV >= NLDO1200_LOW_UV_MIN)
- uV = NLDO1200_LOW_UV_MIN;
-
- if (uV < NLDO1200_LOW_UV_MIN || uV > NLDO1200_HIGH_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
- return -EINVAL;
- }
-
- if (uV > NLDO1200_LOW_UV_MAX) {
- vprog = (uV - NLDO1200_HIGH_UV_MIN + NLDO1200_HIGH_UV_STEP - 1)
- / NLDO1200_HIGH_UV_STEP;
- uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
- vprog &= NLDO1200_CTRL_VPROG_MASK;
- range = NLDO1200_CTRL_RANGE_HIGH;
- } else {
- vprog = (uV - NLDO1200_LOW_UV_MIN + NLDO1200_LOW_UV_STEP - 1)
- / NLDO1200_LOW_UV_STEP;
- uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
- vprog &= NLDO1200_CTRL_VPROG_MASK;
- range = NLDO1200_CTRL_RANGE_LOW;
- }
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /* Set to advanced mode */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- NLDO1200_ADVANCED_MODE | REGULATOR_BANK_SEL(2)
- | REGULATOR_BANK_WRITE, NLDO1200_ADVANCED_MODE_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
- if (rc)
- goto bail;
-
- /* Set voltage and range selection. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, vprog | range,
- NLDO1200_CTRL_VPROG_MASK | NLDO1200_CTRL_RANGE_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- vreg->save_uV = uV;
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_nldo1200_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = _pm8921_nldo1200_set_voltage(vreg, min_uV, max_uV);
-
- if (!rc)
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int pm8921_smps_get_voltage_advanced(struct pm8921_vreg *vreg)
-{
- u8 vprog, band;
- int uV = 0;
-
- vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
- band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
-
- if (band == SMPS_ADVANCED_BAND_1)
- uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
- else if (band == SMPS_ADVANCED_BAND_2)
- uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
- else if (band == SMPS_ADVANCED_BAND_3)
- uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
- else if (vreg->save_uV > 0)
- uV = vreg->save_uV;
- else
- uV = VOLTAGE_UNKNOWN;
-
- return uV;
-}
-
-static int pm8921_smps_get_voltage_legacy(struct pm8921_vreg *vreg)
-{
- u8 vlow, vref, vprog;
- int uV;
-
- vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
- vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
- vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
-
- if (vlow && vref) {
- /* mode 3 */
- uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
- } else if (vref) {
- /* mode 2 */
- uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
- } else {
- /* mode 1 */
- uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
- }
-
- return uV;
-}
-
-static int _pm8921_smps_get_voltage(struct pm8921_vreg *vreg)
-{
- if (SMPS_IN_ADVANCED_MODE(vreg))
- return pm8921_smps_get_voltage_advanced(vreg);
-
- return pm8921_smps_get_voltage_legacy(vreg);
-}
-
-static int pm8921_smps_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int uV;
-
- if (selector >= SMPS_ADVANCED_SET_POINTS)
- return 0;
-
- if (selector < SMPS_BAND1_SET_POINTS)
- uV = selector * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
- else if (selector < (SMPS_BAND1_SET_POINTS + SMPS_BAND2_SET_POINTS))
- uV = (selector - SMPS_BAND1_SET_POINTS) * SMPS_BAND2_UV_STEP
- + SMPS_BAND2_UV_MIN;
- else
- uV = (selector - SMPS_BAND1_SET_POINTS - SMPS_BAND2_SET_POINTS)
- * SMPS_BAND3_UV_STEP
- + SMPS_BAND3_UV_MIN;
-
- return uV;
-}
-
-static int pm8921_smps_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int uV;
-
- mutex_lock(&vreg->pc_lock);
- uV = _pm8921_smps_get_voltage(vreg);
- mutex_unlock(&vreg->pc_lock);
-
- return uV;
-}
-
-static int pm8921_smps_set_voltage_advanced(struct pm8921_vreg *vreg,
- int min_uV, int max_uV, int force_on)
-{
- u8 vprog, band;
- int rc;
- int uV = min_uV;
-
- if (uV < SMPS_BAND1_UV_MIN && max_uV >= SMPS_BAND1_UV_MIN)
- uV = SMPS_BAND1_UV_MIN;
-
- if (uV < SMPS_BAND1_UV_MIN || uV > SMPS_BAND3_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, SMPS_BAND1_UV_MIN, SMPS_BAND3_UV_MAX);
- return -EINVAL;
- }
-
- if (uV > SMPS_BAND2_UV_MAX) {
- vprog = (uV - SMPS_BAND3_UV_MIN + SMPS_BAND3_UV_STEP - 1)
- / SMPS_BAND3_UV_STEP;
- band = SMPS_ADVANCED_BAND_3;
- uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
- } else if (uV > SMPS_BAND1_UV_MAX) {
- vprog = (uV - SMPS_BAND2_UV_MIN + SMPS_BAND2_UV_STEP - 1)
- / SMPS_BAND2_UV_STEP;
- band = SMPS_ADVANCED_BAND_2;
- uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
- } else {
- vprog = (uV - SMPS_BAND1_UV_MIN + SMPS_BAND1_UV_STEP - 1)
- / SMPS_BAND1_UV_STEP;
- band = SMPS_ADVANCED_BAND_1;
- uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
- }
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /* Do not set band if regulator currently disabled. */
- if (!_pm8921_vreg_is_enabled(vreg) && !force_on)
- band = SMPS_ADVANCED_BAND_OFF;
-
- /* Set advanced mode bit to 1. */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
- | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
- SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[7]);
- if (rc)
- goto bail;
-
- /* Set voltage and voltage band. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, band | vprog,
- SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- vreg->save_uV = uV;
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_smps_set_voltage_legacy(struct pm8921_vreg *vreg, int min_uV,
- int max_uV)
-{
- u8 vlow, vref, vprog, pd, en;
- int rc;
- int uV = min_uV;
-
-
- if (uV < SMPS_MODE3_UV_MIN && max_uV >= SMPS_MODE3_UV_MIN)
- uV = SMPS_MODE3_UV_MIN;
-
- if (uV < SMPS_MODE3_UV_MIN || uV > SMPS_MODE1_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, SMPS_MODE3_UV_MIN, SMPS_MODE1_UV_MAX);
- return -EINVAL;
- }
-
- if (uV > SMPS_MODE2_UV_MAX) {
- vprog = (uV - SMPS_MODE1_UV_MIN + SMPS_MODE1_UV_STEP - 1)
- / SMPS_MODE1_UV_STEP;
- vref = 0;
- vlow = 0;
- uV = SMPS_MODE1_UV_MIN + vprog * SMPS_MODE1_UV_STEP;
- } else if (uV > SMPS_MODE3_UV_MAX) {
- vprog = (uV - SMPS_MODE2_UV_MIN + SMPS_MODE2_UV_STEP - 1)
- / SMPS_MODE2_UV_STEP;
- vref = SMPS_LEGACY_VREF_SEL_MASK;
- vlow = 0;
- uV = SMPS_MODE2_UV_MIN + vprog * SMPS_MODE2_UV_STEP;
- } else {
- vprog = (uV - SMPS_MODE3_UV_MIN + SMPS_MODE3_UV_STEP - 1)
- / SMPS_MODE3_UV_STEP;
- vref = SMPS_LEGACY_VREF_SEL_MASK;
- vlow = SMPS_LEGACY_VLOW_SEL_MASK;
- uV = SMPS_MODE3_UV_MIN + vprog * SMPS_MODE3_UV_STEP;
- }
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /* set vlow bit for ultra low voltage mode */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
- REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
- &vreg->test_reg[1]);
- if (rc)
- goto bail;
-
- /* Set advanced mode bit to 0. */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
- | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
- SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[7]);
- if (rc)
- goto bail;
-
- en = (_pm8921_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
- pd = (vreg->pdata.pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
-
- /* Set voltage (and the rest of the control register). */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- en | pd | vref | vprog,
- SMPS_LEGACY_ENABLE_MASK | SMPS_LEGACY_PULL_DOWN_ENABLE
- | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
- &vreg->ctrl_reg);
-
- vreg->save_uV = uV;
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_smps_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- mutex_lock(&vreg->pc_lock);
-
- if (SMPS_IN_ADVANCED_MODE(vreg) || !pm8921_vreg_is_pin_controlled(vreg))
- rc = pm8921_smps_set_voltage_advanced(vreg, min_uV, max_uV, 0);
- else
- rc = pm8921_smps_set_voltage_legacy(vreg, min_uV, max_uV);
-
- mutex_unlock(&vreg->pc_lock);
-
- if (!rc)
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int _pm8921_ftsmps_get_voltage(struct pm8921_vreg *vreg)
-{
- u8 vprog, band;
- int uV = 0;
-
- if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM) {
- vprog = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
- band = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
- if (band == FTSMPS_VCTRL_BAND_OFF && vprog == 0) {
- /* PWM_VCTRL overrides PFM_VCTRL */
- vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
- band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
- }
- } else {
- vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
- band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
- }
-
- if (band == FTSMPS_VCTRL_BAND_1)
- uV = vprog * FTSMPS_BAND1_UV_PHYS_STEP + FTSMPS_BAND1_UV_MIN;
- else if (band == FTSMPS_VCTRL_BAND_2)
- uV = vprog * FTSMPS_BAND2_UV_STEP + FTSMPS_BAND2_UV_MIN;
- else if (band == FTSMPS_VCTRL_BAND_3)
- uV = vprog * FTSMPS_BAND3_UV_STEP + FTSMPS_BAND3_UV_MIN;
- else if (vreg->save_uV > 0)
- uV = vreg->save_uV;
- else
- uV = VOLTAGE_UNKNOWN;
-
- return uV;
-}
-
-static int pm8921_ftsmps_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-
- return _pm8921_ftsmps_get_voltage(vreg);
-}
-
-static int pm8921_ftsmps_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int uV;
-
- if (selector >= FTSMPS_SET_POINTS)
- return 0;
-
- if (selector < FTSMPS_BAND1_SET_POINTS)
- uV = selector * FTSMPS_BAND1_UV_LOG_STEP + FTSMPS_BAND1_UV_MIN;
- else if (selector < (FTSMPS_BAND1_SET_POINTS + FTSMPS_BAND2_SET_POINTS))
- uV = (selector - FTSMPS_BAND1_SET_POINTS) * FTSMPS_BAND2_UV_STEP
- + FTSMPS_BAND2_UV_MIN;
- else
- uV = (selector - FTSMPS_BAND1_SET_POINTS
- - FTSMPS_BAND2_SET_POINTS)
- * FTSMPS_BAND3_UV_STEP
- + FTSMPS_BAND3_UV_SET_POINT_MIN;
-
- return uV;
-}
-
-static int _pm8921_ftsmps_set_voltage(struct pm8921_vreg *vreg, int min_uV,
- int max_uV, int force_on)
-{
- int rc = 0;
- u8 vprog, band;
- int uV = min_uV;
-
- if (uV < FTSMPS_BAND1_UV_MIN && max_uV >= FTSMPS_BAND1_UV_MIN)
- uV = FTSMPS_BAND1_UV_MIN;
-
- if (uV < FTSMPS_BAND1_UV_MIN || uV > FTSMPS_BAND3_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, FTSMPS_BAND1_UV_MIN,
- FTSMPS_BAND3_UV_MAX);
- return -EINVAL;
- }
-
- /* Round up for set points in the gaps between bands. */
- if (uV > FTSMPS_BAND1_UV_MAX && uV < FTSMPS_BAND2_UV_MIN)
- uV = FTSMPS_BAND2_UV_MIN;
- else if (uV > FTSMPS_BAND2_UV_MAX
- && uV < FTSMPS_BAND3_UV_SET_POINT_MIN)
- uV = FTSMPS_BAND3_UV_SET_POINT_MIN;
-
- if (uV > FTSMPS_BAND2_UV_MAX) {
- vprog = (uV - FTSMPS_BAND3_UV_MIN + FTSMPS_BAND3_UV_STEP - 1)
- / FTSMPS_BAND3_UV_STEP;
- band = FTSMPS_VCTRL_BAND_3;
- uV = FTSMPS_BAND3_UV_MIN + vprog * FTSMPS_BAND3_UV_STEP;
- } else if (uV > FTSMPS_BAND1_UV_MAX) {
- vprog = (uV - FTSMPS_BAND2_UV_MIN + FTSMPS_BAND2_UV_STEP - 1)
- / FTSMPS_BAND2_UV_STEP;
- band = FTSMPS_VCTRL_BAND_2;
- uV = FTSMPS_BAND2_UV_MIN + vprog * FTSMPS_BAND2_UV_STEP;
- } else {
- vprog = (uV - FTSMPS_BAND1_UV_MIN
- + FTSMPS_BAND1_UV_LOG_STEP - 1)
- / FTSMPS_BAND1_UV_LOG_STEP;
- uV = FTSMPS_BAND1_UV_MIN + vprog * FTSMPS_BAND1_UV_LOG_STEP;
- vprog *= FTSMPS_BAND1_UV_LOG_STEP / FTSMPS_BAND1_UV_PHYS_STEP;
- band = FTSMPS_VCTRL_BAND_1;
- }
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /*
- * Do not set voltage if regulator is currently disabled because doing
- * so will enable it.
- */
- if (_pm8921_vreg_is_enabled(vreg) || force_on) {
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- band | vprog,
- FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Program PFM_VCTRL as 0x00 so that PWM_VCTRL overrides it. */
- rc = pm8921_vreg_masked_write(vreg, vreg->pfm_ctrl_addr, 0x00,
- FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
- &vreg->pfm_ctrl_reg);
- if (rc)
- goto bail;
- }
-
- vreg->save_uV = uV;
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_ftsmps_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = _pm8921_ftsmps_set_voltage(vreg, min_uV, max_uV, 0);
-
- if (!rc)
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static int pm8921_ncp_get_voltage(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- u8 vprog;
-
- vprog = vreg->ctrl_reg & NCP_VPROG_MASK;
-
- return NCP_UV_MIN + vprog * NCP_UV_STEP;
-}
-
-static int pm8921_ncp_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector >= NCP_SET_POINTS)
- return 0;
-
- return selector * NCP_UV_STEP + NCP_UV_MIN;
-}
-
-static int pm8921_ncp_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
- int uV = min_uV;
- u8 val;
-
- if (uV < NCP_UV_MIN && max_uV >= NCP_UV_MIN)
- uV = NCP_UV_MIN;
-
- if (uV < NCP_UV_MIN || uV > NCP_UV_MAX) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, NCP_UV_MIN, NCP_UV_MAX);
- return -EINVAL;
- }
-
- val = (uV - NCP_UV_MIN + NCP_UV_STEP - 1) / NCP_UV_STEP;
- uV = val * NCP_UV_STEP + NCP_UV_MIN;
-
- if (uV > max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] cannot be met by any set point\n",
- min_uV, max_uV);
- return -EINVAL;
- }
-
- /* voltage setting */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
- NCP_VPROG_MASK, &vreg->ctrl_reg);
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
- return rc;
-}
-
-static unsigned int pm8921_ldo_get_mode(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode = 0;
-
- mutex_lock(&vreg->pc_lock);
- mode = vreg->mode;
- mutex_unlock(&vreg->pc_lock);
-
- return mode;
-}
-
-static int pm8921_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
- vreg_err(vreg, "invalid mode: %u\n", mode);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- if (mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE)) {
- /* HPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_HPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- } else {
- /* LPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0),
- LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[0]);
- }
-
-bail:
- if (!rc)
- vreg->mode = mode;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
- return rc;
-}
-
-static unsigned int pm8921_nldo1200_get_mode(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode = 0;
-
- if (NLDO1200_IN_ADVANCED_MODE(vreg)) {
- /* Advanced mode */
- if ((vreg->test_reg[2] & NLDO1200_ADVANCED_PM_MASK)
- == NLDO1200_ADVANCED_PM_LPM)
- mode = REGULATOR_MODE_IDLE;
- else
- mode = REGULATOR_MODE_NORMAL;
- } else {
- /* Legacy mode */
- if ((vreg->ctrl_reg & NLDO1200_LEGACY_PM_MASK)
- == NLDO1200_LEGACY_PM_LPM)
- mode = REGULATOR_MODE_IDLE;
- else
- mode = REGULATOR_MODE_NORMAL;
- }
-
- return mode;
-}
-
-static int pm8921_nldo1200_set_mode(struct regulator_dev *rdev,
- unsigned int mode)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
- vreg_err(vreg, "invalid mode: %u\n", mode);
- return -EINVAL;
- }
-
- /*
- * Make sure that advanced mode is in use. If it isn't, then set it
- * and update the voltage accordingly.
- */
- if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
- rc = _pm8921_nldo1200_set_voltage(vreg, vreg->save_uV,
- vreg->save_uV);
- if (rc)
- goto bail;
- }
-
- if (mode == REGULATOR_MODE_NORMAL) {
- /* HPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- NLDO1200_ADVANCED_PM_HPM | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
- } else {
- /* LPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- NLDO1200_ADVANCED_PM_LPM | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
- }
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
- return rc;
-}
-
-static unsigned int pm8921_smps_get_mode(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode = 0;
-
- mutex_lock(&vreg->pc_lock);
- mode = vreg->mode;
- mutex_unlock(&vreg->pc_lock);
-
- return mode;
-}
-
-static int pm8921_smps_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
- vreg_err(vreg, "invalid mode: %u\n", mode);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- if (mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE)) {
- /* HPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PWM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
- } else {
- /* LPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
- }
-
- if (!rc)
- vreg->mode = mode;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
- return rc;
-}
-
-static unsigned int pm8921_ftsmps_get_mode(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode = 0;
-
- if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM)
- mode = REGULATOR_MODE_IDLE;
- else
- mode = REGULATOR_MODE_NORMAL;
-
- return mode;
-}
-
-static int pm8921_ftsmps_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
-
- if (mode == REGULATOR_MODE_NORMAL) {
- /* HPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- FTSMPS_CNFG1_PM_PWM | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[0]);
- } else if (mode == REGULATOR_MODE_IDLE) {
- /* LPM */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- FTSMPS_CNFG1_PM_PFM | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
- | REGULATOR_BANK_MASK, &vreg->test_reg[0]);
- } else {
- vreg_err(vreg, "invalid mode: %u\n", mode);
- return -EINVAL;
- }
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
- return rc;
-}
-
-static unsigned int pm8921_vreg_get_optimum_mode(struct regulator_dev *rdev,
- int input_uV, int output_uV, int load_uA)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode;
-
- if (load_uA + vreg->pdata.system_uA >= vreg->hpm_min_load)
- mode = REGULATOR_MODE_NORMAL;
- else
- mode = REGULATOR_MODE_IDLE;
-
- return mode;
-}
-
-static int pm8921_ldo_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc, val;
-
- mutex_lock(&vreg->pc_lock);
-
- /*
- * Choose HPM if previously set to HPM or if pin control is enabled in
- * on/off mode.
- */
- val = LDO_CTRL_PM_LPM;
- if (vreg->mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE))
- val = LDO_CTRL_PM_HPM;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val | LDO_ENABLE,
- LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8921_ldo_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- /*
- * Only disable the regulator if it isn't still required for HPM/LPM
- * pin control.
- */
- if (!vreg->is_enabled_pc
- || vreg->pdata.pin_fn != PM8921_VREG_PIN_FN_MODE) {
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if HPM/LPM pin control is enabled. */
- if (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_MODE) {
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0),
- LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[0]);
- }
-
- if (!rc)
- vreg->is_enabled = false;
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8921_nldo1200_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_ENABLE,
- NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8921_nldo1200_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_DISABLE,
- NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8921_smps_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
- int val;
-
- mutex_lock(&vreg->pc_lock);
-
- if (SMPS_IN_ADVANCED_MODE(vreg)
- || !pm8921_vreg_is_pin_controlled(vreg)) {
- /* Enable in advanced mode if not using pin control. */
- rc = pm8921_smps_set_voltage_advanced(vreg, vreg->save_uV,
- vreg->save_uV, 1);
- } else {
- rc = pm8921_smps_set_voltage_legacy(vreg, vreg->save_uV,
- vreg->save_uV);
- if (rc)
- goto bail;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- SMPS_LEGACY_ENABLE, SMPS_LEGACY_ENABLE_MASK,
- &vreg->ctrl_reg);
- }
-
- /*
- * Choose HPM if previously set to HPM or if pin control is enabled in
- * on/off mode.
- */
- val = SMPS_CLK_CTRL_PFM;
- if (vreg->mode == REGULATOR_MODE_NORMAL
- || (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE))
- val = SMPS_CLK_CTRL_PWM;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr, val,
- SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = true;
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8921_smps_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- if (SMPS_IN_ADVANCED_MODE(vreg)) {
- /* Change SMPS to legacy mode before disabling. */
- rc = pm8921_smps_set_voltage_legacy(vreg, vreg->save_uV,
- vreg->save_uV);
- if (rc)
- goto bail;
- }
-
- /*
- * Only disable the regulator if it isn't still required for HPM/LPM
- * pin control.
- */
- if (!vreg->is_enabled_pc
- || vreg->pdata.pin_fn != PM8921_VREG_PIN_FN_MODE) {
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if HPM/LPM pin control is enabled. */
- if (vreg->is_enabled_pc
- && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_MODE)
- rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = false;
-
-bail:
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8921_ftsmps_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = _pm8921_ftsmps_set_voltage(vreg, vreg->save_uV, vreg->save_uV, 1);
-
- if (rc)
- vreg_err(vreg, "set voltage failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8921_ftsmps_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->pfm_ctrl_addr,
- FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK,
- &vreg->pfm_ctrl_reg);
-bail:
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8921_vs_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS_ENABLE,
- VS_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8921_vs_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS_DISABLE,
- VS_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8921_vs300_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_ENABLE,
- VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8921_vs300_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_DISABLE,
- VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8921_ncp_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_ENABLE,
- NCP_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
- return rc;
-}
-
-static int pm8921_ncp_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_DISABLE,
- NCP_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
- return rc;
-}
-
-static int pm8921_ldo_pin_control_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
- int bank;
- u8 val = 0;
- u8 mask;
-
- mutex_lock(&vreg->pc_lock);
-
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
- val |= LDO_TEST_PIN_CTRL_EN0;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
- val |= LDO_TEST_PIN_CTRL_EN1;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
- val |= LDO_TEST_PIN_CTRL_EN2;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
- val |= LDO_TEST_PIN_CTRL_EN3;
-
- bank = (vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE ? 5 : 6);
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- val | REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[bank]);
- if (rc)
- goto bail;
-
- /* Unset pin control bits in unused bank. */
- bank = (bank == 5 ? 6 : 5);
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[bank]);
- if (rc)
- goto bail;
-
- val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0);
- mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr, val, mask,
- &vreg->test_reg[0]);
- if (rc)
- goto bail;
-
- if (vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE) {
- /* Pin control ON/OFF */
- val = LDO_CTRL_PM_HPM;
- /* Leave physically enabled if already enabled. */
- val |= (vreg->is_enabled ? LDO_ENABLE : LDO_DISABLE);
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
- LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- } else {
- /* Pin control LPM/HPM */
- val = LDO_ENABLE;
- /* Leave in HPM if already enabled in HPM. */
- val |= (vreg->is_enabled && vreg->mode == REGULATOR_MODE_NORMAL
- ? LDO_CTRL_PM_HPM : LDO_CTRL_PM_LPM);
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
- LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8921_ldo_pin_control_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[5]);
- if (rc)
- goto bail;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
- LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[6]);
-
- /*
- * Physically disable the regulator if it was enabled in HPM/LPM pin
- * control mode previously and it logically should not be enabled.
- */
- if ((vreg->ctrl_reg & LDO_ENABLE_MASK) == LDO_ENABLE
- && !vreg->is_enabled) {
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if LPM was enabled. */
- if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
- | REGULATOR_BANK_SEL(0),
- LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[0]);
- if (rc)
- goto bail;
- }
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8921_smps_pin_control_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc = 0;
- u8 val = 0;
-
- mutex_lock(&vreg->pc_lock);
-
- if (vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE) {
- /* Pin control ON/OFF */
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
- val |= SMPS_PIN_CTRL_EN0;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
- val |= SMPS_PIN_CTRL_EN1;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
- val |= SMPS_PIN_CTRL_EN2;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
- val |= SMPS_PIN_CTRL_EN3;
- } else {
- /* Pin control LPM/HPM */
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
- val |= SMPS_PIN_CTRL_LPM_EN0;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
- val |= SMPS_PIN_CTRL_LPM_EN1;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
- val |= SMPS_PIN_CTRL_LPM_EN2;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
- val |= SMPS_PIN_CTRL_LPM_EN3;
- }
-
- rc = pm8921_smps_set_voltage_legacy(vreg, vreg->save_uV, vreg->save_uV);
- if (rc)
- goto bail;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, val,
- SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
- &vreg->sleep_ctrl_reg);
- if (rc)
- goto bail;
-
- /*
- * Physically enable the regulator if using HPM/LPM pin control mode or
- * if the regulator should be logically left on.
- */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- ((vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_MODE
- || vreg->is_enabled) ?
- SMPS_LEGACY_ENABLE : SMPS_LEGACY_DISABLE),
- SMPS_LEGACY_ENABLE_MASK, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /*
- * Set regulator to HPM if using on/off pin control or if the regulator
- * is already enabled in HPM. Otherwise, set it to LPM.
- */
- rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- (vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE
- || (vreg->is_enabled
- && vreg->mode == REGULATOR_MODE_NORMAL)
- ? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
- SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8921_smps_pin_control_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8921_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, 0,
- SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
- &vreg->sleep_ctrl_reg);
- if (rc)
- goto bail;
-
- /*
- * Physically disable the regulator if it was enabled in HPM/LPM pin
- * control mode previously and it logically should not be enabled.
- */
- if ((vreg->ctrl_reg & SMPS_LEGACY_ENABLE_MASK) == SMPS_LEGACY_ENABLE
- && vreg->is_enabled == false) {
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
- &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
- /* Change to LPM if LPM was enabled. */
- if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
- rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
- SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
- &vreg->clk_ctrl_reg);
- if (rc)
- goto bail;
- }
-
- rc = pm8921_smps_set_voltage_advanced(vreg, vreg->save_uV,
- vreg->save_uV, 0);
-
-bail:
- if (!rc)
- vreg->is_enabled_pc = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8921_vs_pin_control_enable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
- u8 val = 0;
-
- mutex_lock(&vreg->pc_lock);
-
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
- val |= VS_PIN_CTRL_EN0;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
- val |= VS_PIN_CTRL_EN1;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
- val |= VS_PIN_CTRL_EN2;
- if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
- val |= VS_PIN_CTRL_EN3;
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
- VS_PIN_CTRL_MASK | VS_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled_pc = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8921_vs_pin_control_disable(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, 0,
- VS_PIN_CTRL_MASK, &vreg->ctrl_reg);
-
- if (!rc)
- vreg->is_enabled_pc = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
- else
- pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
- return rc;
-}
-
-static int pm8921_enable_time(struct regulator_dev *rdev)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-
- return vreg->pdata.enable_time;
-}
-
-static const char const *pm8921_print_actions[] = {
- [PM8921_REGULATOR_ACTION_INIT] = "initial ",
- [PM8921_REGULATOR_ACTION_ENABLE] = "enable ",
- [PM8921_REGULATOR_ACTION_DISABLE] = "disable ",
- [PM8921_REGULATOR_ACTION_VOLTAGE] = "set voltage",
- [PM8921_REGULATOR_ACTION_MODE] = "set mode ",
- [PM8921_REGULATOR_ACTION_PIN_CTRL] = "pin control",
-};
-
-static void pm8921_vreg_show_state(struct regulator_dev *rdev,
- enum pm8921_regulator_action action)
-{
- struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
- int uV, pc;
- unsigned int mode;
- const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
- const char *pc_total = "";
- const char *action_label = pm8921_print_actions[action];
- const char *enable_label;
-
- mutex_lock(&vreg->pc_lock);
-
- /*
- * Do not print unless REQUEST is specified and SSBI writes have taken
- * place, or DUPLICATE is specified.
- */
- if (!((pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_DUPLICATE)
- || ((pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_REQUEST)
- && (vreg->write_count != vreg->prev_write_count)))) {
- mutex_unlock(&vreg->pc_lock);
- return;
- }
-
- vreg->prev_write_count = vreg->write_count;
-
- pc = vreg->pdata.pin_ctrl;
- if (vreg->is_enabled_pc) {
- if (pc & PM8921_VREG_PIN_CTRL_D1)
- pc_en0 = " D1";
- if (pc & PM8921_VREG_PIN_CTRL_A0)
- pc_en1 = " A0";
- if (pc & PM8921_VREG_PIN_CTRL_A1)
- pc_en2 = " A1";
- if (pc & PM8921_VREG_PIN_CTRL_A2)
- pc_en3 = " A2";
- if (pc == PM8921_VREG_PIN_CTRL_NONE)
- pc_total = " none";
- } else {
- pc_total = " none";
- }
-
- mutex_unlock(&vreg->pc_lock);
-
- enable_label = pm8921_vreg_is_enabled(rdev) ? "on " : "off";
-
- switch (vreg->type) {
- case REGULATOR_TYPE_PLDO:
- uV = pm8921_pldo_get_voltage(rdev);
- mode = pm8921_ldo_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- case REGULATOR_TYPE_NLDO:
- uV = pm8921_nldo_get_voltage(rdev);
- mode = pm8921_ldo_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- case REGULATOR_TYPE_NLDO1200:
- uV = pm8921_nldo1200_get_voltage(rdev);
- mode = pm8921_nldo1200_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
- break;
- case REGULATOR_TYPE_SMPS:
- uV = pm8921_smps_get_voltage(rdev);
- mode = pm8921_smps_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- case REGULATOR_TYPE_FTSMPS:
- uV = pm8921_ftsmps_get_voltage(rdev);
- mode = pm8921_ftsmps_get_mode(rdev);
- pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
- action_label, vreg->name, enable_label, uV,
- (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
- break;
- case REGULATOR_TYPE_VS:
- pr_info("%s %-9s: %s, pc=%s%s%s%s%s\n",
- action_label, vreg->name, enable_label,
- pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
- break;
- case REGULATOR_TYPE_VS300:
- pr_info("%s %-9s: %s\n",
- action_label, vreg->name, enable_label);
- break;
- case REGULATOR_TYPE_NCP:
- uV = pm8921_ncp_get_voltage(rdev);
- pr_info("%s %-9s: %s, v=%7d uV\n",
- action_label, vreg->name, enable_label, uV);
- break;
- default:
- break;
- }
-}
-
-
-/* Real regulator operations. */
-static struct regulator_ops pm8921_pldo_ops = {
- .enable = pm8921_ldo_enable,
- .disable = pm8921_ldo_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .set_voltage = pm8921_pldo_set_voltage,
- .get_voltage = pm8921_pldo_get_voltage,
- .list_voltage = pm8921_pldo_list_voltage,
- .set_mode = pm8921_ldo_set_mode,
- .get_mode = pm8921_ldo_get_mode,
- .get_optimum_mode = pm8921_vreg_get_optimum_mode,
- .enable_time = pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_nldo_ops = {
- .enable = pm8921_ldo_enable,
- .disable = pm8921_ldo_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .set_voltage = pm8921_nldo_set_voltage,
- .get_voltage = pm8921_nldo_get_voltage,
- .list_voltage = pm8921_nldo_list_voltage,
- .set_mode = pm8921_ldo_set_mode,
- .get_mode = pm8921_ldo_get_mode,
- .get_optimum_mode = pm8921_vreg_get_optimum_mode,
- .enable_time = pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_nldo1200_ops = {
- .enable = pm8921_nldo1200_enable,
- .disable = pm8921_nldo1200_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .set_voltage = pm8921_nldo1200_set_voltage,
- .get_voltage = pm8921_nldo1200_get_voltage,
- .list_voltage = pm8921_nldo1200_list_voltage,
- .set_mode = pm8921_nldo1200_set_mode,
- .get_mode = pm8921_nldo1200_get_mode,
- .get_optimum_mode = pm8921_vreg_get_optimum_mode,
- .enable_time = pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_smps_ops = {
- .enable = pm8921_smps_enable,
- .disable = pm8921_smps_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .set_voltage = pm8921_smps_set_voltage,
- .get_voltage = pm8921_smps_get_voltage,
- .list_voltage = pm8921_smps_list_voltage,
- .set_mode = pm8921_smps_set_mode,
- .get_mode = pm8921_smps_get_mode,
- .get_optimum_mode = pm8921_vreg_get_optimum_mode,
- .enable_time = pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_ftsmps_ops = {
- .enable = pm8921_ftsmps_enable,
- .disable = pm8921_ftsmps_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .set_voltage = pm8921_ftsmps_set_voltage,
- .get_voltage = pm8921_ftsmps_get_voltage,
- .list_voltage = pm8921_ftsmps_list_voltage,
- .set_mode = pm8921_ftsmps_set_mode,
- .get_mode = pm8921_ftsmps_get_mode,
- .get_optimum_mode = pm8921_vreg_get_optimum_mode,
- .enable_time = pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_vs_ops = {
- .enable = pm8921_vs_enable,
- .disable = pm8921_vs_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .enable_time = pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_vs300_ops = {
- .enable = pm8921_vs300_enable,
- .disable = pm8921_vs300_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .enable_time = pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_ncp_ops = {
- .enable = pm8921_ncp_enable,
- .disable = pm8921_ncp_disable,
- .is_enabled = pm8921_vreg_is_enabled,
- .set_voltage = pm8921_ncp_set_voltage,
- .get_voltage = pm8921_ncp_get_voltage,
- .list_voltage = pm8921_ncp_list_voltage,
- .enable_time = pm8921_enable_time,
-};
-
-/* Pin control regulator operations. */
-static struct regulator_ops pm8921_ldo_pc_ops = {
- .enable = pm8921_ldo_pin_control_enable,
- .disable = pm8921_ldo_pin_control_disable,
- .is_enabled = pm8921_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8921_smps_pc_ops = {
- .enable = pm8921_smps_pin_control_enable,
- .disable = pm8921_smps_pin_control_disable,
- .is_enabled = pm8921_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8921_vs_pc_ops = {
- .enable = pm8921_vs_pin_control_enable,
- .disable = pm8921_vs_pin_control_disable,
- .is_enabled = pm8921_vreg_pin_control_is_enabled,
-};
-
-#define VREG_DESC(_id, _name, _ops, _n_voltages) \
- [PM8921_VREG_ID_##_id] = { \
- .id = PM8921_VREG_ID_##_id, \
- .name = _name, \
- .n_voltages = _n_voltages, \
- .ops = _ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- }
-
-static struct regulator_desc pm8921_vreg_description[] = {
- VREG_DESC(L1, "8921_l1", &pm8921_nldo_ops, NLDO_SET_POINTS),
- VREG_DESC(L2, "8921_l2", &pm8921_nldo_ops, NLDO_SET_POINTS),
- VREG_DESC(L3, "8921_l3", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L4, "8921_l4", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L5, "8921_l5", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L6, "8921_l6", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L7, "8921_l7", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L8, "8921_l8", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L9, "8921_l9", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L10, "8921_l10", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L11, "8921_l11", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L12, "8921_l12", &pm8921_nldo_ops, NLDO_SET_POINTS),
- VREG_DESC(L14, "8921_l14", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L15, "8921_l15", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L16, "8921_l16", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L17, "8921_l17", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L18, "8921_l18", &pm8921_nldo_ops, NLDO_SET_POINTS),
- VREG_DESC(L21, "8921_l21", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L22, "8921_l22", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L23, "8921_l23", &pm8921_pldo_ops, PLDO_SET_POINTS),
- VREG_DESC(L24, "8921_l24", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L25, "8921_l25", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L26, "8921_l26", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L27, "8921_l27", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L28, "8921_l28", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
- VREG_DESC(L29, "8921_l29", &pm8921_pldo_ops, PLDO_SET_POINTS),
-
- VREG_DESC(S1, "8921_s1", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S2, "8921_s2", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S3, "8921_s3", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S4, "8921_s4", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S5, "8921_s5", &pm8921_ftsmps_ops, FTSMPS_SET_POINTS),
- VREG_DESC(S6, "8921_s6", &pm8921_ftsmps_ops, FTSMPS_SET_POINTS),
- VREG_DESC(S7, "8921_s7", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
- VREG_DESC(S8, "8921_s8", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
-
- VREG_DESC(LVS1, "8921_lvs1", &pm8921_vs_ops, 0),
- VREG_DESC(LVS2, "8921_lvs2", &pm8921_vs300_ops, 0),
- VREG_DESC(LVS3, "8921_lvs3", &pm8921_vs_ops, 0),
- VREG_DESC(LVS4, "8921_lvs4", &pm8921_vs_ops, 0),
- VREG_DESC(LVS5, "8921_lvs5", &pm8921_vs_ops, 0),
- VREG_DESC(LVS6, "8921_lvs6", &pm8921_vs_ops, 0),
- VREG_DESC(LVS7, "8921_lvs7", &pm8921_vs_ops, 0),
-
- VREG_DESC(USB_OTG, "8921_usb_otg", &pm8921_vs300_ops, 0),
- VREG_DESC(HDMI_MVS, "8921_hdmi_mvs", &pm8921_vs300_ops, 0),
- VREG_DESC(NCP, "8921_ncp", &pm8921_ncp_ops, NCP_SET_POINTS),
-
- VREG_DESC(L1_PC, "8921_l1_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L2_PC, "8921_l2_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L3_PC, "8921_l3_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L4_PC, "8921_l4_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L5_PC, "8921_l5_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L6_PC, "8921_l6_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L7_PC, "8921_l7_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L8_PC, "8921_l8_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L9_PC, "8921_l9_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L10_PC, "8921_l10_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L11_PC, "8921_l11_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L12_PC, "8921_l12_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L14_PC, "8921_l14_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L15_PC, "8921_l15_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L16_PC, "8921_l16_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L17_PC, "8921_l17_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L18_PC, "8921_l18_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L21_PC, "8921_l21_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L22_PC, "8921_l22_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L23_PC, "8921_l23_pc", &pm8921_ldo_pc_ops, 0),
- VREG_DESC(L29_PC, "8921_l29_pc", &pm8921_ldo_pc_ops, 0),
-
- VREG_DESC(S1_PC, "8921_s1_pc", &pm8921_smps_pc_ops, 0),
- VREG_DESC(S2_PC, "8921_s2_pc", &pm8921_smps_pc_ops, 0),
- VREG_DESC(S3_PC, "8921_s3_pc", &pm8921_smps_pc_ops, 0),
- VREG_DESC(S4_PC, "8921_s4_pc", &pm8921_smps_pc_ops, 0),
- VREG_DESC(S7_PC, "8921_s7_pc", &pm8921_smps_pc_ops, 0),
- VREG_DESC(S8_PC, "8921_s8_pc", &pm8921_smps_pc_ops, 0),
-
- VREG_DESC(LVS1_PC, "8921_lvs1_pc", &pm8921_vs_pc_ops, 0),
- VREG_DESC(LVS3_PC, "8921_lvs3_pc", &pm8921_vs_pc_ops, 0),
- VREG_DESC(LVS4_PC, "8921_lvs4_pc", &pm8921_vs_pc_ops, 0),
- VREG_DESC(LVS5_PC, "8921_lvs5_pc", &pm8921_vs_pc_ops, 0),
- VREG_DESC(LVS6_PC, "8921_lvs6_pc", &pm8921_vs_pc_ops, 0),
- VREG_DESC(LVS7_PC, "8921_lvs7_pc", &pm8921_vs_pc_ops, 0),
-};
-
-static int pm8921_init_ldo(struct pm8921_vreg *vreg, bool is_real)
-{
- int rc = 0;
- int i;
- u8 bank;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current test register state. */
- for (i = 0; i < LDO_TEST_BANKS; i++) {
- bank = REGULATOR_BANK_SEL(i);
- rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
- &vreg->test_reg[i]);
- if (rc)
- goto bail;
- vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
- }
-
- if (is_real) {
- /* Set pull down enable based on platform data. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- (vreg->pdata.pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
- LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
- vreg->is_enabled = !!_pm8921_vreg_is_enabled(vreg);
-
- vreg->mode = ((vreg->ctrl_reg & LDO_CTRL_PM_MASK)
- == LDO_CTRL_PM_LPM ?
- REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
- }
-bail:
- if (rc)
- vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_init_nldo1200(struct pm8921_vreg *vreg)
-{
- int rc = 0;
- int i;
- u8 bank;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current test register state. */
- for (i = 0; i < LDO_TEST_BANKS; i++) {
- bank = REGULATOR_BANK_SEL(i);
- rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
- &vreg->test_reg[i]);
- if (rc)
- goto bail;
- vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
- }
-
- vreg->save_uV = _pm8921_nldo1200_get_voltage(vreg);
-
- /* Set pull down enable based on platform data. */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- (vreg->pdata.pull_down_enable ? NLDO1200_PULL_DOWN_ENABLE : 0)
- | REGULATOR_BANK_SEL(1) | REGULATOR_BANK_WRITE,
- NLDO1200_PULL_DOWN_ENABLE_MASK | REGULATOR_BANK_MASK,
- &vreg->test_reg[1]);
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_init_smps(struct pm8921_vreg *vreg, bool is_real)
-{
- int rc = 0;
- int i;
- u8 bank;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current test2 register state. */
- for (i = 0; i < SMPS_TEST_BANKS; i++) {
- bank = REGULATOR_BANK_SEL(i);
- rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
- &vreg->test_reg[i]);
- if (rc)
- goto bail;
- vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
- }
-
- /* Save the current clock control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
- &vreg->clk_ctrl_reg);
- if (rc)
- goto bail;
-
- /* Save the current sleep control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
- &vreg->sleep_ctrl_reg);
- if (rc)
- goto bail;
-
- vreg->save_uV = _pm8921_smps_get_voltage(vreg);
-
- if (is_real) {
- /* Set advanced mode pull down enable based on platform data. */
- rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
- (vreg->pdata.pull_down_enable
- ? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
- | REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
- REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
- &vreg->test_reg[6]);
- if (rc)
- goto bail;
-
- vreg->is_enabled = !!_pm8921_vreg_is_enabled(vreg);
-
- vreg->mode = ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
- == SMPS_CLK_CTRL_PFM ?
- REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
- }
-
- if (!SMPS_IN_ADVANCED_MODE(vreg) && is_real) {
- /* Set legacy mode pull down enable based on platform data. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- (vreg->pdata.pull_down_enable
- ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
- SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
- if (rc)
- goto bail;
- }
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_init_ftsmps(struct pm8921_vreg *vreg)
-{
- int rc, i;
- u8 bank;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc)
- goto bail;
-
- /* Store current regulator register values. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->pfm_ctrl_addr,
- &vreg->pfm_ctrl_reg);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->pwr_cnfg_addr,
- &vreg->pwr_cnfg_reg);
- if (rc)
- goto bail;
-
- /* Save the current fts_cnfg1 register state (uses 'test' member). */
- for (i = 0; i < SMPS_TEST_BANKS; i++) {
- bank = REGULATOR_BANK_SEL(i);
- rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
- if (rc)
- goto bail;
-
- rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
- &vreg->test_reg[i]);
- if (rc)
- goto bail;
- vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
- }
-
- vreg->save_uV = _pm8921_ftsmps_get_voltage(vreg);
-
- /* Set pull down enable based on platform data. */
- rc = pm8921_vreg_masked_write(vreg, vreg->pwr_cnfg_addr,
- (vreg->pdata.pull_down_enable ? FTSMPS_PULL_DOWN_ENABLE : 0),
- FTSMPS_PULL_DOWN_ENABLE_MASK, &vreg->pwr_cnfg_reg);
-
-bail:
- if (rc)
- vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_init_vs(struct pm8921_vreg *vreg, bool is_real)
-{
- int rc = 0;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc) {
- vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
- return rc;
- }
-
- if (is_real) {
- /* Set pull down enable based on platform data. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- (vreg->pdata.pull_down_enable ? VS_PULL_DOWN_ENABLE
- : VS_PULL_DOWN_DISABLE),
- VS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg,
- "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
- vreg->is_enabled = !!_pm8921_vreg_is_enabled(vreg);
- }
-
- return rc;
-}
-
-static int pm8921_init_vs300(struct pm8921_vreg *vreg)
-{
- int rc;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc) {
- vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
- return rc;
- }
-
- /* Set pull down enable based on platform data. */
- rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
- (vreg->pdata.pull_down_enable ? VS300_PULL_DOWN_ENABLE : 0),
- VS300_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
- if (rc)
- vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int pm8921_init_ncp(struct pm8921_vreg *vreg)
-{
- int rc;
-
- /* Save the current control register state. */
- rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
- if (rc) {
- vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
- return rc;
- }
-
- return rc;
-}
-
-int pc_id_to_real_id(int id)
-{
- int real_id;
-
- if (id >= PM8921_VREG_ID_L1_PC && id <= PM8921_VREG_ID_L23_PC)
- real_id = id - PM8921_VREG_ID_L1_PC;
- else if (id >= PM8921_VREG_ID_L29_PC && id <= PM8921_VREG_ID_S4_PC)
- real_id = id - PM8921_VREG_ID_L29_PC + PM8921_VREG_ID_L29;
- else if (id >= PM8921_VREG_ID_S7_PC && id <= PM8921_VREG_ID_LVS1_PC)
- real_id = id - PM8921_VREG_ID_S7_PC + PM8921_VREG_ID_S7;
- else
- real_id = id - PM8921_VREG_ID_LVS3_PC + PM8921_VREG_ID_LVS3;
-
- return real_id;
-}
-
-static int __devinit pm8921_vreg_probe(struct platform_device *pdev)
-{
- const struct pm8921_regulator_platform_data *pdata;
- enum pm8921_vreg_pin_function pin_fn;
- struct regulator_desc *rdesc;
- struct pm8921_vreg *vreg;
- const char *reg_name = "";
- unsigned pin_ctrl;
- int rc = 0, id = pdev->id;
-
- if (pdev == NULL)
- return -EINVAL;
-
- if (pdev->id >= 0 && pdev->id < PM8921_VREG_ID_MAX) {
- pdata = pdev->dev.platform_data;
- rdesc = &pm8921_vreg_description[pdev->id];
- if (!IS_REAL_REGULATOR(pdev->id))
- id = pc_id_to_real_id(pdev->id);
- vreg = &pm8921_vreg[id];
- reg_name = pm8921_vreg_description[pdev->id].name;
- if (!pdata) {
- pr_err("%s requires platform data\n", reg_name);
- return -EINVAL;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- if (IS_REAL_REGULATOR(pdev->id)) {
- /* Do not modify pin control and pin function values. */
- pin_ctrl = vreg->pdata.pin_ctrl;
- pin_fn = vreg->pdata.pin_fn;
- memcpy(&(vreg->pdata), pdata,
- sizeof(struct pm8921_regulator_platform_data));
- vreg->pdata.pin_ctrl = pin_ctrl;
- vreg->pdata.pin_fn = pin_fn;
- vreg->dev = &pdev->dev;
- vreg->name = reg_name;
- } else {
- /* Pin control regulator */
- if ((pdata->pin_ctrl &
- (PM8921_VREG_PIN_CTRL_D1 | PM8921_VREG_PIN_CTRL_A0
- | PM8921_VREG_PIN_CTRL_A1 | PM8921_VREG_PIN_CTRL_A2))
- == PM8921_VREG_PIN_CTRL_NONE) {
- pr_err("%s: no pin control input specified\n",
- reg_name);
- mutex_unlock(&vreg->pc_lock);
- return -EINVAL;
- }
- vreg->pdata.pin_ctrl = pdata->pin_ctrl;
- vreg->pdata.pin_fn = pdata->pin_fn;
- vreg->dev_pc = &pdev->dev;
- if (!vreg->dev)
- vreg->dev = &pdev->dev;
- if (!vreg->name)
- vreg->name = reg_name;
- }
-
- /* Initialize register values. */
- switch (vreg->type) {
- case REGULATOR_TYPE_PLDO:
- case REGULATOR_TYPE_NLDO:
- rc = pm8921_init_ldo(vreg, IS_REAL_REGULATOR(pdev->id));
- break;
- case REGULATOR_TYPE_NLDO1200:
- rc = pm8921_init_nldo1200(vreg);
- break;
- case REGULATOR_TYPE_SMPS:
- rc = pm8921_init_smps(vreg,
- IS_REAL_REGULATOR(pdev->id));
- break;
- case REGULATOR_TYPE_FTSMPS:
- rc = pm8921_init_ftsmps(vreg);
- break;
- case REGULATOR_TYPE_VS:
- rc = pm8921_init_vs(vreg, IS_REAL_REGULATOR(pdev->id));
- break;
- case REGULATOR_TYPE_VS300:
- rc = pm8921_init_vs300(vreg);
- break;
- case REGULATOR_TYPE_NCP:
- rc = pm8921_init_ncp(vreg);
- break;
- }
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- goto bail;
-
- if (IS_REAL_REGULATOR(pdev->id)) {
- vreg->rdev = regulator_register(rdesc, &pdev->dev,
- &(pdata->init_data), vreg);
- if (IS_ERR(vreg->rdev)) {
- rc = PTR_ERR(vreg->rdev);
- vreg->rdev = NULL;
- pr_err("regulator_register failed: %s, rc=%d\n",
- reg_name, rc);
- }
- } else {
- vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
- &(pdata->init_data), vreg);
- if (IS_ERR(vreg->rdev_pc)) {
- rc = PTR_ERR(vreg->rdev_pc);
- vreg->rdev_pc = NULL;
- pr_err("regulator_register failed: %s, rc=%d\n",
- reg_name, rc);
- }
- }
- if ((pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_INIT) && !rc
- && vreg->rdev)
- pm8921_vreg_show_state(vreg->rdev,
- PM8921_REGULATOR_ACTION_INIT);
- } else {
- rc = -ENODEV;
- }
-
-bail:
- if (rc)
- pr_err("error for %s, rc=%d\n", reg_name, rc);
-
- return rc;
-}
-
-static int __devexit pm8921_vreg_remove(struct platform_device *pdev)
-{
- if (IS_REAL_REGULATOR(pdev->id))
- regulator_unregister(pm8921_vreg[pdev->id].rdev);
- else
- regulator_unregister(
- pm8921_vreg[pc_id_to_real_id(pdev->id)].rdev_pc);
-
- return 0;
-}
-
-static struct platform_driver pm8921_vreg_driver = {
- .probe = pm8921_vreg_probe,
- .remove = __devexit_p(pm8921_vreg_remove),
- .driver = {
- .name = PM8921_REGULATOR_DEV_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pm8921_vreg_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pm8921_vreg); i++) {
- mutex_init(&pm8921_vreg[i].pc_lock);
- pm8921_vreg[i].write_count = 0;
- pm8921_vreg[i].prev_write_count = -1;
- }
-
- return platform_driver_register(&pm8921_vreg_driver);
-}
-postcore_initcall(pm8921_vreg_init);
-
-static void __exit pm8921_vreg_exit(void)
-{
- int i;
-
- platform_driver_unregister(&pm8921_vreg_driver);
-
- for (i = 0; i < ARRAY_SIZE(pm8921_vreg); i++)
- mutex_destroy(&pm8921_vreg[i].pc_lock);
-}
-module_exit(pm8921_vreg_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8921 regulator driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:" PM8921_REGULATOR_DEV_NAME);
diff --git a/drivers/regulator/pm8xxx-regulator.c b/drivers/regulator/pm8xxx-regulator.c
new file mode 100644
index 0000000..15a9cb1
--- /dev/null
+++ b/drivers/regulator/pm8xxx-regulator.c
@@ -0,0 +1,3065 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
+
+/* Debug Flag Definitions */
+enum {
+ PM8XXX_VREG_DEBUG_REQUEST = BIT(0),
+ PM8XXX_VREG_DEBUG_DUPLICATE = BIT(1),
+ PM8XXX_VREG_DEBUG_INIT = BIT(2),
+ PM8XXX_VREG_DEBUG_WRITES = BIT(3), /* SSBI writes */
+};
+
+static int pm8xxx_vreg_debug_mask;
+module_param_named(
+ debug_mask, pm8xxx_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+/* Common Masks */
+#define REGULATOR_ENABLE_MASK 0x80
+#define REGULATOR_ENABLE 0x80
+#define REGULATOR_DISABLE 0x00
+
+#define REGULATOR_BANK_MASK 0xF0
+#define REGULATOR_BANK_SEL(n) ((n) << 4)
+#define REGULATOR_BANK_WRITE 0x80
+
+#define LDO_TEST_BANKS 7
+#define NLDO1200_TEST_BANKS 5
+#define SMPS_TEST_BANKS 8
+
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level. It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN 1
+
+/* LDO masks and values */
+
+/* CTRL register */
+#define LDO_ENABLE_MASK 0x80
+#define LDO_DISABLE 0x00
+#define LDO_ENABLE 0x80
+#define LDO_PULL_DOWN_ENABLE_MASK 0x40
+#define LDO_PULL_DOWN_ENABLE 0x40
+
+#define LDO_CTRL_PM_MASK 0x20
+#define LDO_CTRL_PM_HPM 0x00
+#define LDO_CTRL_PM_LPM 0x20
+
+#define LDO_CTRL_VPROG_MASK 0x1F
+
+/* TEST register bank 0 */
+#define LDO_TEST_LPM_MASK 0x04
+#define LDO_TEST_LPM_SEL_CTRL 0x00
+#define LDO_TEST_LPM_SEL_TCXO 0x04
+
+/* TEST register bank 2 */
+#define LDO_TEST_VPROG_UPDATE_MASK 0x08
+#define LDO_TEST_RANGE_SEL_MASK 0x04
+#define LDO_TEST_FINE_STEP_MASK 0x02
+#define LDO_TEST_FINE_STEP_SHIFT 1
+
+/* TEST register bank 4 */
+#define LDO_TEST_RANGE_EXT_MASK 0x01
+
+/* TEST register bank 5 */
+#define LDO_TEST_PIN_CTRL_MASK 0x0F
+#define LDO_TEST_PIN_CTRL_EN3 0x08
+#define LDO_TEST_PIN_CTRL_EN2 0x04
+#define LDO_TEST_PIN_CTRL_EN1 0x02
+#define LDO_TEST_PIN_CTRL_EN0 0x01
+
+/* TEST register bank 6 */
+#define LDO_TEST_PIN_CTRL_LPM_MASK 0x0F
+
+/*
+ * If a given voltage could be output by two ranges, then the preferred one must
+ * be determined by the range limits. Specified voltage ranges should must
+ * not overlap.
+ *
+ * Allowable voltage ranges:
+ */
+#define PLDO_LOW_UV_MIN 750000
+#define PLDO_LOW_UV_MAX 1487500
+#define PLDO_LOW_UV_FINE_STEP 12500
+
+#define PLDO_NORM_UV_MIN 1500000
+#define PLDO_NORM_UV_MAX 3075000
+#define PLDO_NORM_UV_FINE_STEP 25000
+
+#define PLDO_HIGH_UV_MIN 1750000
+#define PLDO_HIGH_UV_SET_POINT_MIN 3100000
+#define PLDO_HIGH_UV_MAX 4900000
+#define PLDO_HIGH_UV_FINE_STEP 50000
+
+#define PLDO_LOW_SET_POINTS ((PLDO_LOW_UV_MAX - PLDO_LOW_UV_MIN) \
+ / PLDO_LOW_UV_FINE_STEP + 1)
+#define PLDO_NORM_SET_POINTS ((PLDO_NORM_UV_MAX - PLDO_NORM_UV_MIN) \
+ / PLDO_NORM_UV_FINE_STEP + 1)
+#define PLDO_HIGH_SET_POINTS ((PLDO_HIGH_UV_MAX \
+ - PLDO_HIGH_UV_SET_POINT_MIN) \
+ / PLDO_HIGH_UV_FINE_STEP + 1)
+#define PLDO_SET_POINTS (PLDO_LOW_SET_POINTS \
+ + PLDO_NORM_SET_POINTS \
+ + PLDO_HIGH_SET_POINTS)
+
+#define NLDO_UV_MIN 750000
+#define NLDO_UV_MAX 1537500
+#define NLDO_UV_FINE_STEP 12500
+
+#define NLDO_SET_POINTS ((NLDO_UV_MAX - NLDO_UV_MIN) \
+ / NLDO_UV_FINE_STEP + 1)
+
+/* NLDO1200 masks and values */
+
+/* CTRL register */
+#define NLDO1200_ENABLE_MASK 0x80
+#define NLDO1200_DISABLE 0x00
+#define NLDO1200_ENABLE 0x80
+
+/* Legacy mode */
+#define NLDO1200_LEGACY_PM_MASK 0x20
+#define NLDO1200_LEGACY_PM_HPM 0x00
+#define NLDO1200_LEGACY_PM_LPM 0x20
+
+/* Advanced mode */
+#define NLDO1200_CTRL_RANGE_MASK 0x40
+#define NLDO1200_CTRL_RANGE_HIGH 0x00
+#define NLDO1200_CTRL_RANGE_LOW 0x40
+#define NLDO1200_CTRL_VPROG_MASK 0x3F
+
+#define NLDO1200_LOW_UV_MIN 375000
+#define NLDO1200_LOW_UV_MAX 743750
+#define NLDO1200_LOW_UV_STEP 6250
+
+#define NLDO1200_HIGH_UV_MIN 750000
+#define NLDO1200_HIGH_UV_MAX 1537500
+#define NLDO1200_HIGH_UV_STEP 12500
+
+#define NLDO1200_LOW_SET_POINTS ((NLDO1200_LOW_UV_MAX \
+ - NLDO1200_LOW_UV_MIN) \
+ / NLDO1200_LOW_UV_STEP + 1)
+#define NLDO1200_HIGH_SET_POINTS ((NLDO1200_HIGH_UV_MAX \
+ - NLDO1200_HIGH_UV_MIN) \
+ / NLDO1200_HIGH_UV_STEP + 1)
+#define NLDO1200_SET_POINTS (NLDO1200_LOW_SET_POINTS \
+ + NLDO1200_HIGH_SET_POINTS)
+
+/* TEST register bank 0 */
+#define NLDO1200_TEST_LPM_MASK 0x04
+#define NLDO1200_TEST_LPM_SEL_CTRL 0x00
+#define NLDO1200_TEST_LPM_SEL_TCXO 0x04
+
+/* TEST register bank 1 */
+#define NLDO1200_PULL_DOWN_ENABLE_MASK 0x02
+#define NLDO1200_PULL_DOWN_ENABLE 0x02
+
+/* TEST register bank 2 */
+#define NLDO1200_ADVANCED_MODE_MASK 0x08
+#define NLDO1200_ADVANCED_MODE 0x00
+#define NLDO1200_LEGACY_MODE 0x08
+
+/* Advanced mode power mode control */
+#define NLDO1200_ADVANCED_PM_MASK 0x02
+#define NLDO1200_ADVANCED_PM_HPM 0x00
+#define NLDO1200_ADVANCED_PM_LPM 0x02
+
+#define NLDO1200_IN_ADVANCED_MODE(vreg) \
+ ((vreg->test_reg[2] & NLDO1200_ADVANCED_MODE_MASK) \
+ == NLDO1200_ADVANCED_MODE)
+
+/* SMPS masks and values */
+
+/* CTRL register */
+
+/* Legacy mode */
+#define SMPS_LEGACY_ENABLE_MASK 0x80
+#define SMPS_LEGACY_DISABLE 0x00
+#define SMPS_LEGACY_ENABLE 0x80
+#define SMPS_LEGACY_PULL_DOWN_ENABLE 0x40
+#define SMPS_LEGACY_VREF_SEL_MASK 0x20
+#define SMPS_LEGACY_VPROG_MASK 0x1F
+
+/* Advanced mode */
+#define SMPS_ADVANCED_BAND_MASK 0xC0
+#define SMPS_ADVANCED_BAND_OFF 0x00
+#define SMPS_ADVANCED_BAND_1 0x40
+#define SMPS_ADVANCED_BAND_2 0x80
+#define SMPS_ADVANCED_BAND_3 0xC0
+#define SMPS_ADVANCED_VPROG_MASK 0x3F
+
+/* Legacy mode voltage ranges */
+#define SMPS_MODE3_UV_MIN 375000
+#define SMPS_MODE3_UV_MAX 725000
+#define SMPS_MODE3_UV_STEP 25000
+
+#define SMPS_MODE2_UV_MIN 750000
+#define SMPS_MODE2_UV_MAX 1475000
+#define SMPS_MODE2_UV_STEP 25000
+
+#define SMPS_MODE1_UV_MIN 1500000
+#define SMPS_MODE1_UV_MAX 3050000
+#define SMPS_MODE1_UV_STEP 50000
+
+#define SMPS_MODE3_SET_POINTS ((SMPS_MODE3_UV_MAX \
+ - SMPS_MODE3_UV_MIN) \
+ / SMPS_MODE3_UV_STEP + 1)
+#define SMPS_MODE2_SET_POINTS ((SMPS_MODE2_UV_MAX \
+ - SMPS_MODE2_UV_MIN) \
+ / SMPS_MODE2_UV_STEP + 1)
+#define SMPS_MODE1_SET_POINTS ((SMPS_MODE1_UV_MAX \
+ - SMPS_MODE1_UV_MIN) \
+ / SMPS_MODE1_UV_STEP + 1)
+#define SMPS_LEGACY_SET_POINTS (SMPS_MODE3_SET_POINTS \
+ + SMPS_MODE2_SET_POINTS \
+ + SMPS_MODE1_SET_POINTS)
+
+/* Advanced mode voltage ranges */
+#define SMPS_BAND1_UV_MIN 375000
+#define SMPS_BAND1_UV_MAX 737500
+#define SMPS_BAND1_UV_STEP 12500
+
+#define SMPS_BAND2_UV_MIN 750000
+#define SMPS_BAND2_UV_MAX 1487500
+#define SMPS_BAND2_UV_STEP 12500
+
+#define SMPS_BAND3_UV_MIN 1500000
+#define SMPS_BAND3_UV_MAX 3075000
+#define SMPS_BAND3_UV_STEP 25000
+
+#define SMPS_BAND1_SET_POINTS ((SMPS_BAND1_UV_MAX \
+ - SMPS_BAND1_UV_MIN) \
+ / SMPS_BAND1_UV_STEP + 1)
+#define SMPS_BAND2_SET_POINTS ((SMPS_BAND2_UV_MAX \
+ - SMPS_BAND2_UV_MIN) \
+ / SMPS_BAND2_UV_STEP + 1)
+#define SMPS_BAND3_SET_POINTS ((SMPS_BAND3_UV_MAX \
+ - SMPS_BAND3_UV_MIN) \
+ / SMPS_BAND3_UV_STEP + 1)
+#define SMPS_ADVANCED_SET_POINTS (SMPS_BAND1_SET_POINTS \
+ + SMPS_BAND2_SET_POINTS \
+ + SMPS_BAND3_SET_POINTS)
+
+/* Test2 register bank 1 */
+#define SMPS_LEGACY_VLOW_SEL_MASK 0x01
+
+/* Test2 register bank 6 */
+#define SMPS_ADVANCED_PULL_DOWN_ENABLE 0x08
+
+/* Test2 register bank 7 */
+#define SMPS_ADVANCED_MODE_MASK 0x02
+#define SMPS_ADVANCED_MODE 0x02
+#define SMPS_LEGACY_MODE 0x00
+
+#define SMPS_IN_ADVANCED_MODE(vreg) \
+ ((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
+
+/* BUCK_SLEEP_CNTRL register */
+#define SMPS_PIN_CTRL_MASK 0xF0
+#define SMPS_PIN_CTRL_EN3 0x80
+#define SMPS_PIN_CTRL_EN2 0x40
+#define SMPS_PIN_CTRL_EN1 0x20
+#define SMPS_PIN_CTRL_EN0 0x10
+
+#define SMPS_PIN_CTRL_LPM_MASK 0x0F
+#define SMPS_PIN_CTRL_LPM_EN3 0x08
+#define SMPS_PIN_CTRL_LPM_EN2 0x04
+#define SMPS_PIN_CTRL_LPM_EN1 0x02
+#define SMPS_PIN_CTRL_LPM_EN0 0x01
+
+/* BUCK_CLOCK_CNTRL register */
+#define SMPS_CLK_DIVIDE2 0x40
+
+#define SMPS_CLK_CTRL_MASK 0x30
+#define SMPS_CLK_CTRL_FOLLOW_TCXO 0x00
+#define SMPS_CLK_CTRL_PWM 0x10
+#define SMPS_CLK_CTRL_PFM 0x20
+
+/* FTSMPS masks and values */
+
+/* CTRL register */
+#define FTSMPS_VCTRL_BAND_MASK 0xC0
+#define FTSMPS_VCTRL_BAND_OFF 0x00
+#define FTSMPS_VCTRL_BAND_1 0x40
+#define FTSMPS_VCTRL_BAND_2 0x80
+#define FTSMPS_VCTRL_BAND_3 0xC0
+#define FTSMPS_VCTRL_VPROG_MASK 0x3F
+
+#define FTSMPS_BAND1_UV_MIN 350000
+#define FTSMPS_BAND1_UV_MAX 650000
+/* 3 LSB's of program voltage must be 0 in band 1. */
+/* Logical step size */
+#define FTSMPS_BAND1_UV_LOG_STEP 50000
+/* Physical step size */
+#define FTSMPS_BAND1_UV_PHYS_STEP 6250
+
+#define FTSMPS_BAND2_UV_MIN 700000
+#define FTSMPS_BAND2_UV_MAX 1400000
+#define FTSMPS_BAND2_UV_STEP 12500
+
+#define FTSMPS_BAND3_UV_MIN 1400000
+#define FTSMPS_BAND3_UV_SET_POINT_MIN 1500000
+#define FTSMPS_BAND3_UV_MAX 3300000
+#define FTSMPS_BAND3_UV_STEP 50000
+
+#define FTSMPS_BAND1_SET_POINTS ((FTSMPS_BAND1_UV_MAX \
+ - FTSMPS_BAND1_UV_MIN) \
+ / FTSMPS_BAND1_UV_LOG_STEP + 1)
+#define FTSMPS_BAND2_SET_POINTS ((FTSMPS_BAND2_UV_MAX \
+ - FTSMPS_BAND2_UV_MIN) \
+ / FTSMPS_BAND2_UV_STEP + 1)
+#define FTSMPS_BAND3_SET_POINTS ((FTSMPS_BAND3_UV_MAX \
+ - FTSMPS_BAND3_UV_SET_POINT_MIN) \
+ / FTSMPS_BAND3_UV_STEP + 1)
+#define FTSMPS_SET_POINTS (FTSMPS_BAND1_SET_POINTS \
+ + FTSMPS_BAND2_SET_POINTS \
+ + FTSMPS_BAND3_SET_POINTS)
+
+/* FTS_CNFG1 register bank 0 */
+#define FTSMPS_CNFG1_PM_MASK 0x0C
+#define FTSMPS_CNFG1_PM_PWM 0x00
+#define FTSMPS_CNFG1_PM_PFM 0x08
+
+/* PWR_CNFG register */
+#define FTSMPS_PULL_DOWN_ENABLE_MASK 0x40
+#define FTSMPS_PULL_DOWN_ENABLE 0x40
+
+/* VS masks and values */
+
+/* CTRL register */
+#define VS_ENABLE_MASK 0x80
+#define VS_DISABLE 0x00
+#define VS_ENABLE 0x80
+#define VS_PULL_DOWN_ENABLE_MASK 0x40
+#define VS_PULL_DOWN_DISABLE 0x40
+#define VS_PULL_DOWN_ENABLE 0x00
+
+#define VS_PIN_CTRL_MASK 0x0F
+#define VS_PIN_CTRL_EN0 0x08
+#define VS_PIN_CTRL_EN1 0x04
+#define VS_PIN_CTRL_EN2 0x02
+#define VS_PIN_CTRL_EN3 0x01
+
+/* VS300 masks and values */
+
+/* CTRL register */
+#define VS300_CTRL_ENABLE_MASK 0xC0
+#define VS300_CTRL_DISABLE 0x00
+#define VS300_CTRL_ENABLE 0x40
+
+#define VS300_PULL_DOWN_ENABLE_MASK 0x20
+#define VS300_PULL_DOWN_ENABLE 0x20
+
+/* NCP masks and values */
+
+/* CTRL register */
+#define NCP_ENABLE_MASK 0x80
+#define NCP_DISABLE 0x00
+#define NCP_ENABLE 0x80
+#define NCP_VPROG_MASK 0x1F
+
+#define NCP_UV_MIN 1500000
+#define NCP_UV_MAX 3050000
+#define NCP_UV_STEP 50000
+
+#define NCP_SET_POINTS ((NCP_UV_MAX - NCP_UV_MIN) \
+ / NCP_UV_STEP + 1)
+
+#define vreg_err(vreg, fmt, ...) \
+ pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
+
+/* Determines which label to add to the print. */
+enum pm8xxx_regulator_action {
+ PM8XXX_REGULATOR_ACTION_INIT,
+ PM8XXX_REGULATOR_ACTION_ENABLE,
+ PM8XXX_REGULATOR_ACTION_DISABLE,
+ PM8XXX_REGULATOR_ACTION_VOLTAGE,
+ PM8XXX_REGULATOR_ACTION_MODE,
+ PM8XXX_REGULATOR_ACTION_PIN_CTRL,
+};
+
+/* Debug state printing */
+static void pm8xxx_vreg_show_state(struct regulator_dev *rdev,
+ enum pm8xxx_regulator_action action);
+
+/*
+ * Perform a masked write to a PMIC register only if the new value differs
+ * from the last value written to the register. This removes redundant
+ * register writing.
+ *
+ * No locking is required because registers are not shared between regulators.
+ */
+static int pm8xxx_vreg_masked_write(struct pm8xxx_vreg *vreg, u16 addr, u8 val,
+ u8 mask, u8 *reg_save)
+{
+ int rc = 0;
+ u8 reg;
+
+ reg = (*reg_save & ~mask) | (val & mask);
+ if (reg != *reg_save) {
+ rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
+
+ if (rc) {
+ pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
+ vreg->rdesc.name, addr, rc);
+ } else {
+ *reg_save = reg;
+ vreg->write_count++;
+ if (pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_WRITES)
+ pr_info("%s: write(0x%03X)=0x%02X\n",
+ vreg->rdesc.name, addr, reg);
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Perform a masked write to a PMIC register without checking the previously
+ * written value. This is needed for registers that must be rewritten even if
+ * the value hasn't changed in order for changes in other registers to take
+ * effect.
+ */
+static int pm8xxx_vreg_masked_write_forced(struct pm8xxx_vreg *vreg, u16 addr,
+ u8 val, u8 mask, u8 *reg_save)
+{
+ int rc = 0;
+ u8 reg;
+
+ reg = (*reg_save & ~mask) | (val & mask);
+ rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
+
+ if (rc) {
+ pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
+ vreg->rdesc.name, addr, rc);
+ } else {
+ *reg_save = reg;
+ vreg->write_count++;
+ if (pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_WRITES)
+ pr_info("%s: write(0x%03X)=0x%02X\n", vreg->rdesc.name,
+ addr, reg);
+ }
+
+ return rc;
+}
+
+static int pm8xxx_vreg_is_pin_controlled(struct pm8xxx_vreg *vreg)
+{
+ int ret = 0;
+
+ switch (vreg->type) {
+ case PM8XXX_REGULATOR_TYPE_PLDO:
+ case PM8XXX_REGULATOR_TYPE_NLDO:
+ ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
+ | (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
+ break;
+ case PM8XXX_REGULATOR_TYPE_SMPS:
+ ret = vreg->sleep_ctrl_reg
+ & (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
+ break;
+ case PM8XXX_REGULATOR_TYPE_VS:
+ ret = vreg->ctrl_reg & VS_PIN_CTRL_MASK;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Returns the logical pin control enable state because the pin control options
+ * present in the hardware out of restart could be different from those desired
+ * by the consumer.
+ */
+static int pm8xxx_vreg_pin_control_is_enabled(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int enabled;
+
+ mutex_lock(&vreg->pc_lock);
+ enabled = vreg->is_enabled_pc;
+ mutex_unlock(&vreg->pc_lock);
+
+ return enabled;
+}
+
+/* Returns the physical enable state of the regulator. */
+static int _pm8xxx_vreg_is_enabled(struct pm8xxx_vreg *vreg)
+{
+ int rc = 0;
+
+ /*
+ * All regulator types except advanced mode SMPS, FTSMPS, and VS300 have
+ * enable bit in bit 7 of the control register.
+ */
+ switch (vreg->type) {
+ case PM8XXX_REGULATOR_TYPE_FTSMPS:
+ if ((vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK)
+ != FTSMPS_VCTRL_BAND_OFF)
+ rc = 1;
+ break;
+ case PM8XXX_REGULATOR_TYPE_VS300:
+ if ((vreg->ctrl_reg & VS300_CTRL_ENABLE_MASK)
+ != VS300_CTRL_DISABLE)
+ rc = 1;
+ break;
+ case PM8XXX_REGULATOR_TYPE_SMPS:
+ if (SMPS_IN_ADVANCED_MODE(vreg)) {
+ if ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
+ != SMPS_ADVANCED_BAND_OFF)
+ rc = 1;
+ break;
+ }
+ /* Fall through for legacy mode SMPS. */
+ default:
+ if ((vreg->ctrl_reg & REGULATOR_ENABLE_MASK)
+ == REGULATOR_ENABLE)
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/*
+ * Returns the logical enable state of the regulator which may be different from
+ * the physical enable state thanks to HPM/LPM pin control.
+ */
+static int pm8xxx_vreg_is_enabled(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int enabled;
+
+ if (vreg->type == PM8XXX_REGULATOR_TYPE_PLDO
+ || vreg->type == PM8XXX_REGULATOR_TYPE_NLDO
+ || vreg->type == PM8XXX_REGULATOR_TYPE_SMPS
+ || vreg->type == PM8XXX_REGULATOR_TYPE_VS) {
+ /* Pin controllable */
+ mutex_lock(&vreg->pc_lock);
+ enabled = vreg->is_enabled;
+ mutex_unlock(&vreg->pc_lock);
+ } else {
+ /* Not pin controlable */
+ enabled = _pm8xxx_vreg_is_enabled(vreg);
+ }
+
+ return enabled;
+}
+
+static int pm8xxx_pldo_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int vmin, fine_step;
+ u8 range_ext, range_sel, vprog, fine_step_reg;
+
+ mutex_lock(&vreg->pc_lock);
+
+ fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
+ range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
+ range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
+ vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
+
+ if (range_sel) {
+ /* low range mode */
+ fine_step = PLDO_LOW_UV_FINE_STEP;
+ vmin = PLDO_LOW_UV_MIN;
+ } else if (!range_ext) {
+ /* normal mode */
+ fine_step = PLDO_NORM_UV_FINE_STEP;
+ vmin = PLDO_NORM_UV_MIN;
+ } else {
+ /* high range mode */
+ fine_step = PLDO_HIGH_UV_FINE_STEP;
+ vmin = PLDO_HIGH_UV_MIN;
+ }
+
+ return fine_step * vprog + vmin;
+}
+
+static int pm8xxx_pldo_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ int uV;
+
+ if (selector >= PLDO_SET_POINTS)
+ return 0;
+
+ if (selector < PLDO_LOW_SET_POINTS)
+ uV = selector * PLDO_LOW_UV_FINE_STEP + PLDO_LOW_UV_MIN;
+ else if (selector < (PLDO_LOW_SET_POINTS + PLDO_NORM_SET_POINTS))
+ uV = (selector - PLDO_LOW_SET_POINTS) * PLDO_NORM_UV_FINE_STEP
+ + PLDO_NORM_UV_MIN;
+ else
+ uV = (selector - PLDO_LOW_SET_POINTS - PLDO_NORM_SET_POINTS)
+ * PLDO_HIGH_UV_FINE_STEP
+ + PLDO_HIGH_UV_SET_POINT_MIN;
+
+ return uV;
+}
+
+static int pm8xxx_pldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0, uV = min_uV;
+ int vmin;
+ unsigned vprog, fine_step;
+ u8 range_ext, range_sel, fine_step_reg, prev_reg;
+ bool reg_changed = false;
+
+ if (uV < PLDO_LOW_UV_MIN && max_uV >= PLDO_LOW_UV_MIN)
+ uV = PLDO_LOW_UV_MIN;
+
+ if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, PLDO_LOW_UV_MIN, PLDO_HIGH_UV_MAX);
+ return -EINVAL;
+ }
+
+ if (uV > PLDO_NORM_UV_MAX) {
+ vmin = PLDO_HIGH_UV_MIN;
+ fine_step = PLDO_HIGH_UV_FINE_STEP;
+ range_ext = LDO_TEST_RANGE_EXT_MASK;
+ range_sel = 0;
+ } else if (uV > PLDO_LOW_UV_MAX) {
+ vmin = PLDO_NORM_UV_MIN;
+ fine_step = PLDO_NORM_UV_FINE_STEP;
+ range_ext = 0;
+ range_sel = 0;
+ } else {
+ vmin = PLDO_LOW_UV_MIN;
+ fine_step = PLDO_LOW_UV_FINE_STEP;
+ range_ext = 0;
+ range_sel = LDO_TEST_RANGE_SEL_MASK;
+ }
+
+ vprog = (uV - vmin + fine_step - 1) / fine_step;
+ uV = vprog * fine_step + vmin;
+ fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
+ vprog >>= 1;
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vreg->pc_lock);
+
+ /* Write fine step, range select and program voltage update. */
+ prev_reg = vreg->test_reg[2];
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
+ | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
+ LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
+ | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
+ &vreg->test_reg[2]);
+ if (rc)
+ goto bail;
+ if (prev_reg != vreg->test_reg[2])
+ reg_changed = true;
+
+ /* Write range extension. */
+ prev_reg = vreg->test_reg[4];
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ range_ext | REGULATOR_BANK_SEL(4)
+ | REGULATOR_BANK_WRITE,
+ LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[4]);
+ if (rc)
+ goto bail;
+ if (prev_reg != vreg->test_reg[4])
+ reg_changed = true;
+
+ /* Write new voltage. */
+ if (reg_changed) {
+ /*
+ * Force a CTRL register write even if the value hasn't changed.
+ * This is neccessary because range select, range extension, and
+ * fine step will not update until a value is written into the
+ * control register.
+ */
+ rc = pm8xxx_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
+ vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+ } else {
+ /* Only write to control register if new value is different. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
+ LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+ }
+bail:
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+ return rc;
+}
+
+static int pm8xxx_nldo_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ u8 vprog, fine_step_reg;
+
+ mutex_lock(&vreg->pc_lock);
+
+ fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
+ vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
+
+ return NLDO_UV_FINE_STEP * vprog + NLDO_UV_MIN;
+}
+
+static int pm8xxx_nldo_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector >= NLDO_SET_POINTS)
+ return 0;
+
+ return selector * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
+}
+
+static int pm8xxx_nldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned vprog, fine_step_reg, prev_reg;
+ int rc;
+ int uV = min_uV;
+
+ if (uV < NLDO_UV_MIN && max_uV >= NLDO_UV_MIN)
+ uV = NLDO_UV_MIN;
+
+ if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
+ return -EINVAL;
+ }
+
+ vprog = (uV - NLDO_UV_MIN + NLDO_UV_FINE_STEP - 1) / NLDO_UV_FINE_STEP;
+ uV = vprog * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
+ fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
+ vprog >>= 1;
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vreg->pc_lock);
+
+ /* Write fine step. */
+ prev_reg = vreg->test_reg[2];
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ fine_step_reg | REGULATOR_BANK_SEL(2)
+ | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
+ LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
+ | LDO_TEST_VPROG_UPDATE_MASK,
+ &vreg->test_reg[2]);
+ if (rc)
+ goto bail;
+
+ /* Write new voltage. */
+ if (prev_reg != vreg->test_reg[2]) {
+ /*
+ * Force a CTRL register write even if the value hasn't changed.
+ * This is neccessary because fine step will not update until a
+ * value is written into the control register.
+ */
+ rc = pm8xxx_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
+ vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+ } else {
+ /* Only write to control register if new value is different. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
+ LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+ }
+bail:
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+ return rc;
+}
+
+static int _pm8xxx_nldo1200_get_voltage(struct pm8xxx_vreg *vreg)
+{
+ int uV = 0;
+ int vprog;
+
+ if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
+ pr_warn("%s: currently in legacy mode; voltage unknown.\n",
+ vreg->rdesc.name);
+ return vreg->save_uV;
+ }
+
+ vprog = vreg->ctrl_reg & NLDO1200_CTRL_VPROG_MASK;
+
+ if ((vreg->ctrl_reg & NLDO1200_CTRL_RANGE_MASK)
+ == NLDO1200_CTRL_RANGE_LOW)
+ uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
+ else
+ uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
+
+ return uV;
+}
+
+static int pm8xxx_nldo1200_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return _pm8xxx_nldo1200_get_voltage(vreg);
+}
+
+static int pm8xxx_nldo1200_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ int uV;
+
+ if (selector >= NLDO1200_SET_POINTS)
+ return 0;
+
+ if (selector < NLDO1200_LOW_SET_POINTS)
+ uV = selector * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
+ else
+ uV = (selector - NLDO1200_LOW_SET_POINTS)
+ * NLDO1200_HIGH_UV_STEP
+ + NLDO1200_HIGH_UV_MIN;
+
+ return uV;
+}
+
+static int _pm8xxx_nldo1200_set_voltage(struct pm8xxx_vreg *vreg, int min_uV,
+ int max_uV)
+{
+ u8 vprog, range;
+ int rc;
+ int uV = min_uV;
+
+ if (uV < NLDO1200_LOW_UV_MIN && max_uV >= NLDO1200_LOW_UV_MIN)
+ uV = NLDO1200_LOW_UV_MIN;
+
+ if (uV < NLDO1200_LOW_UV_MIN || uV > NLDO1200_HIGH_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
+ return -EINVAL;
+ }
+
+ if (uV > NLDO1200_LOW_UV_MAX) {
+ vprog = (uV - NLDO1200_HIGH_UV_MIN + NLDO1200_HIGH_UV_STEP - 1)
+ / NLDO1200_HIGH_UV_STEP;
+ uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
+ vprog &= NLDO1200_CTRL_VPROG_MASK;
+ range = NLDO1200_CTRL_RANGE_HIGH;
+ } else {
+ vprog = (uV - NLDO1200_LOW_UV_MIN + NLDO1200_LOW_UV_STEP - 1)
+ / NLDO1200_LOW_UV_STEP;
+ uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
+ vprog &= NLDO1200_CTRL_VPROG_MASK;
+ range = NLDO1200_CTRL_RANGE_LOW;
+ }
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ /* Set to advanced mode */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ NLDO1200_ADVANCED_MODE | REGULATOR_BANK_SEL(2)
+ | REGULATOR_BANK_WRITE, NLDO1200_ADVANCED_MODE_MASK
+ | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
+ if (rc)
+ goto bail;
+
+ /* Set voltage and range selection. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, vprog | range,
+ NLDO1200_CTRL_VPROG_MASK | NLDO1200_CTRL_RANGE_MASK,
+ &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ vreg->save_uV = uV;
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_nldo1200_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = _pm8xxx_nldo1200_set_voltage(vreg, min_uV, max_uV);
+
+ if (!rc)
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+ return rc;
+}
+
+static int pm8xxx_smps_get_voltage_advanced(struct pm8xxx_vreg *vreg)
+{
+ u8 vprog, band;
+ int uV = 0;
+
+ vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
+ band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
+
+ if (band == SMPS_ADVANCED_BAND_1)
+ uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
+ else if (band == SMPS_ADVANCED_BAND_2)
+ uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
+ else if (band == SMPS_ADVANCED_BAND_3)
+ uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
+ else if (vreg->save_uV > 0)
+ uV = vreg->save_uV;
+ else
+ uV = VOLTAGE_UNKNOWN;
+
+ return uV;
+}
+
+static int pm8xxx_smps_get_voltage_legacy(struct pm8xxx_vreg *vreg)
+{
+ u8 vlow, vref, vprog;
+ int uV;
+
+ vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
+ vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
+ vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
+
+ if (vlow && vref) {
+ /* mode 3 */
+ uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
+ } else if (vref) {
+ /* mode 2 */
+ uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
+ } else {
+ /* mode 1 */
+ uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
+ }
+
+ return uV;
+}
+
+static int _pm8xxx_smps_get_voltage(struct pm8xxx_vreg *vreg)
+{
+ if (SMPS_IN_ADVANCED_MODE(vreg))
+ return pm8xxx_smps_get_voltage_advanced(vreg);
+
+ return pm8xxx_smps_get_voltage_legacy(vreg);
+}
+
+static int pm8xxx_smps_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ int uV;
+
+ if (selector >= SMPS_ADVANCED_SET_POINTS)
+ return 0;
+
+ if (selector < SMPS_BAND1_SET_POINTS)
+ uV = selector * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
+ else if (selector < (SMPS_BAND1_SET_POINTS + SMPS_BAND2_SET_POINTS))
+ uV = (selector - SMPS_BAND1_SET_POINTS) * SMPS_BAND2_UV_STEP
+ + SMPS_BAND2_UV_MIN;
+ else
+ uV = (selector - SMPS_BAND1_SET_POINTS - SMPS_BAND2_SET_POINTS)
+ * SMPS_BAND3_UV_STEP
+ + SMPS_BAND3_UV_MIN;
+
+ return uV;
+}
+
+static int pm8xxx_smps_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int uV;
+
+ mutex_lock(&vreg->pc_lock);
+ uV = _pm8xxx_smps_get_voltage(vreg);
+ mutex_unlock(&vreg->pc_lock);
+
+ return uV;
+}
+
+static int pm8xxx_smps_set_voltage_advanced(struct pm8xxx_vreg *vreg,
+ int min_uV, int max_uV, int force_on)
+{
+ u8 vprog, band;
+ int rc;
+ int uV = min_uV;
+
+ if (uV < SMPS_BAND1_UV_MIN && max_uV >= SMPS_BAND1_UV_MIN)
+ uV = SMPS_BAND1_UV_MIN;
+
+ if (uV < SMPS_BAND1_UV_MIN || uV > SMPS_BAND3_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, SMPS_BAND1_UV_MIN, SMPS_BAND3_UV_MAX);
+ return -EINVAL;
+ }
+
+ if (uV > SMPS_BAND2_UV_MAX) {
+ vprog = (uV - SMPS_BAND3_UV_MIN + SMPS_BAND3_UV_STEP - 1)
+ / SMPS_BAND3_UV_STEP;
+ band = SMPS_ADVANCED_BAND_3;
+ uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
+ } else if (uV > SMPS_BAND1_UV_MAX) {
+ vprog = (uV - SMPS_BAND2_UV_MIN + SMPS_BAND2_UV_STEP - 1)
+ / SMPS_BAND2_UV_STEP;
+ band = SMPS_ADVANCED_BAND_2;
+ uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
+ } else {
+ vprog = (uV - SMPS_BAND1_UV_MIN + SMPS_BAND1_UV_STEP - 1)
+ / SMPS_BAND1_UV_STEP;
+ band = SMPS_ADVANCED_BAND_1;
+ uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
+ }
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ /* Do not set band if regulator currently disabled. */
+ if (!_pm8xxx_vreg_is_enabled(vreg) && !force_on)
+ band = SMPS_ADVANCED_BAND_OFF;
+
+ /* Set advanced mode bit to 1. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
+ | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
+ SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[7]);
+ if (rc)
+ goto bail;
+
+ /* Set voltage and voltage band. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, band | vprog,
+ SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
+ &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ vreg->save_uV = uV;
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_smps_set_voltage_legacy(struct pm8xxx_vreg *vreg, int min_uV,
+ int max_uV)
+{
+ u8 vlow, vref, vprog, pd, en;
+ int rc;
+ int uV = min_uV;
+
+ if (uV < SMPS_MODE3_UV_MIN && max_uV >= SMPS_MODE3_UV_MIN)
+ uV = SMPS_MODE3_UV_MIN;
+
+ if (uV < SMPS_MODE3_UV_MIN || uV > SMPS_MODE1_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, SMPS_MODE3_UV_MIN, SMPS_MODE1_UV_MAX);
+ return -EINVAL;
+ }
+
+ if (uV > SMPS_MODE2_UV_MAX) {
+ vprog = (uV - SMPS_MODE1_UV_MIN + SMPS_MODE1_UV_STEP - 1)
+ / SMPS_MODE1_UV_STEP;
+ vref = 0;
+ vlow = 0;
+ uV = SMPS_MODE1_UV_MIN + vprog * SMPS_MODE1_UV_STEP;
+ } else if (uV > SMPS_MODE3_UV_MAX) {
+ vprog = (uV - SMPS_MODE2_UV_MIN + SMPS_MODE2_UV_STEP - 1)
+ / SMPS_MODE2_UV_STEP;
+ vref = SMPS_LEGACY_VREF_SEL_MASK;
+ vlow = 0;
+ uV = SMPS_MODE2_UV_MIN + vprog * SMPS_MODE2_UV_STEP;
+ } else {
+ vprog = (uV - SMPS_MODE3_UV_MIN + SMPS_MODE3_UV_STEP - 1)
+ / SMPS_MODE3_UV_STEP;
+ vref = SMPS_LEGACY_VREF_SEL_MASK;
+ vlow = SMPS_LEGACY_VLOW_SEL_MASK;
+ uV = SMPS_MODE3_UV_MIN + vprog * SMPS_MODE3_UV_STEP;
+ }
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ /* set vlow bit for ultra low voltage mode */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
+ REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
+ &vreg->test_reg[1]);
+ if (rc)
+ goto bail;
+
+ /* Set advanced mode bit to 0. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
+ | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
+ SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[7]);
+ if (rc)
+ goto bail;
+
+ en = (_pm8xxx_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
+ pd = (vreg->pdata.pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
+
+ /* Set voltage (and the rest of the control register). */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ en | pd | vref | vprog,
+ SMPS_LEGACY_ENABLE_MASK | SMPS_LEGACY_PULL_DOWN_ENABLE
+ | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
+ &vreg->ctrl_reg);
+
+ vreg->save_uV = uV;
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_smps_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (SMPS_IN_ADVANCED_MODE(vreg) || !pm8xxx_vreg_is_pin_controlled(vreg))
+ rc = pm8xxx_smps_set_voltage_advanced(vreg, min_uV, max_uV, 0);
+ else
+ rc = pm8xxx_smps_set_voltage_legacy(vreg, min_uV, max_uV);
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (!rc)
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+ return rc;
+}
+
+static int _pm8xxx_ftsmps_get_voltage(struct pm8xxx_vreg *vreg)
+{
+ u8 vprog, band;
+ int uV = 0;
+
+ if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM) {
+ vprog = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
+ band = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
+ if (band == FTSMPS_VCTRL_BAND_OFF && vprog == 0) {
+ /* PWM_VCTRL overrides PFM_VCTRL */
+ vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
+ band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
+ }
+ } else {
+ vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
+ band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
+ }
+
+ if (band == FTSMPS_VCTRL_BAND_1)
+ uV = vprog * FTSMPS_BAND1_UV_PHYS_STEP + FTSMPS_BAND1_UV_MIN;
+ else if (band == FTSMPS_VCTRL_BAND_2)
+ uV = vprog * FTSMPS_BAND2_UV_STEP + FTSMPS_BAND2_UV_MIN;
+ else if (band == FTSMPS_VCTRL_BAND_3)
+ uV = vprog * FTSMPS_BAND3_UV_STEP + FTSMPS_BAND3_UV_MIN;
+ else if (vreg->save_uV > 0)
+ uV = vreg->save_uV;
+ else
+ uV = VOLTAGE_UNKNOWN;
+
+ return uV;
+}
+
+static int pm8xxx_ftsmps_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return _pm8xxx_ftsmps_get_voltage(vreg);
+}
+
+static int pm8xxx_ftsmps_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ int uV;
+
+ if (selector >= FTSMPS_SET_POINTS)
+ return 0;
+
+ if (selector < FTSMPS_BAND1_SET_POINTS)
+ uV = selector * FTSMPS_BAND1_UV_LOG_STEP + FTSMPS_BAND1_UV_MIN;
+ else if (selector < (FTSMPS_BAND1_SET_POINTS + FTSMPS_BAND2_SET_POINTS))
+ uV = (selector - FTSMPS_BAND1_SET_POINTS) * FTSMPS_BAND2_UV_STEP
+ + FTSMPS_BAND2_UV_MIN;
+ else
+ uV = (selector - FTSMPS_BAND1_SET_POINTS
+ - FTSMPS_BAND2_SET_POINTS)
+ * FTSMPS_BAND3_UV_STEP
+ + FTSMPS_BAND3_UV_SET_POINT_MIN;
+
+ return uV;
+}
+
+static int _pm8xxx_ftsmps_set_voltage(struct pm8xxx_vreg *vreg, int min_uV,
+ int max_uV, int force_on)
+{
+ int rc = 0;
+ u8 vprog, band;
+ int uV = min_uV;
+
+ if (uV < FTSMPS_BAND1_UV_MIN && max_uV >= FTSMPS_BAND1_UV_MIN)
+ uV = FTSMPS_BAND1_UV_MIN;
+
+ if (uV < FTSMPS_BAND1_UV_MIN || uV > FTSMPS_BAND3_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, FTSMPS_BAND1_UV_MIN,
+ FTSMPS_BAND3_UV_MAX);
+ return -EINVAL;
+ }
+
+ /* Round up for set points in the gaps between bands. */
+ if (uV > FTSMPS_BAND1_UV_MAX && uV < FTSMPS_BAND2_UV_MIN)
+ uV = FTSMPS_BAND2_UV_MIN;
+ else if (uV > FTSMPS_BAND2_UV_MAX
+ && uV < FTSMPS_BAND3_UV_SET_POINT_MIN)
+ uV = FTSMPS_BAND3_UV_SET_POINT_MIN;
+
+ if (uV > FTSMPS_BAND2_UV_MAX) {
+ vprog = (uV - FTSMPS_BAND3_UV_MIN + FTSMPS_BAND3_UV_STEP - 1)
+ / FTSMPS_BAND3_UV_STEP;
+ band = FTSMPS_VCTRL_BAND_3;
+ uV = FTSMPS_BAND3_UV_MIN + vprog * FTSMPS_BAND3_UV_STEP;
+ } else if (uV > FTSMPS_BAND1_UV_MAX) {
+ vprog = (uV - FTSMPS_BAND2_UV_MIN + FTSMPS_BAND2_UV_STEP - 1)
+ / FTSMPS_BAND2_UV_STEP;
+ band = FTSMPS_VCTRL_BAND_2;
+ uV = FTSMPS_BAND2_UV_MIN + vprog * FTSMPS_BAND2_UV_STEP;
+ } else {
+ vprog = (uV - FTSMPS_BAND1_UV_MIN
+ + FTSMPS_BAND1_UV_LOG_STEP - 1)
+ / FTSMPS_BAND1_UV_LOG_STEP;
+ uV = FTSMPS_BAND1_UV_MIN + vprog * FTSMPS_BAND1_UV_LOG_STEP;
+ vprog *= FTSMPS_BAND1_UV_LOG_STEP / FTSMPS_BAND1_UV_PHYS_STEP;
+ band = FTSMPS_VCTRL_BAND_1;
+ }
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ /*
+ * Do not set voltage if regulator is currently disabled because doing
+ * so will enable it.
+ */
+ if (_pm8xxx_vreg_is_enabled(vreg) || force_on) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ band | vprog,
+ FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
+ &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /* Program PFM_VCTRL as 0x00 so that PWM_VCTRL overrides it. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->pfm_ctrl_addr, 0x00,
+ FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
+ &vreg->pfm_ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+ vreg->save_uV = uV;
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_ftsmps_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = _pm8xxx_ftsmps_set_voltage(vreg, min_uV, max_uV, 0);
+
+ if (!rc)
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+ return rc;
+}
+
+static int pm8xxx_ncp_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ u8 vprog;
+
+ vprog = vreg->ctrl_reg & NCP_VPROG_MASK;
+
+ return NCP_UV_MIN + vprog * NCP_UV_STEP;
+}
+
+static int pm8xxx_ncp_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector >= NCP_SET_POINTS)
+ return 0;
+
+ return selector * NCP_UV_STEP + NCP_UV_MIN;
+}
+
+static int pm8xxx_ncp_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+ int uV = min_uV;
+ u8 val;
+
+ if (uV < NCP_UV_MIN && max_uV >= NCP_UV_MIN)
+ uV = NCP_UV_MIN;
+
+ if (uV < NCP_UV_MIN || uV > NCP_UV_MAX) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, NCP_UV_MIN, NCP_UV_MAX);
+ return -EINVAL;
+ }
+
+ val = (uV - NCP_UV_MIN + NCP_UV_STEP - 1) / NCP_UV_STEP;
+ uV = val * NCP_UV_STEP + NCP_UV_MIN;
+
+ if (uV > max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] cannot be met by any set point\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ /* voltage setting */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+ NCP_VPROG_MASK, &vreg->ctrl_reg);
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+ return rc;
+}
+
+static unsigned int pm8xxx_ldo_get_mode(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode = 0;
+
+ mutex_lock(&vreg->pc_lock);
+ mode = vreg->mode;
+ mutex_unlock(&vreg->pc_lock);
+
+ return mode;
+}
+
+static int pm8xxx_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+
+ if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+ vreg_err(vreg, "invalid mode: %u\n", mode);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (mode == REGULATOR_MODE_NORMAL
+ || (vreg->is_enabled_pc
+ && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE)) {
+ /* HPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ LDO_CTRL_PM_HPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+ } else {
+ /* LPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(0),
+ LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[0]);
+ }
+
+bail:
+ if (!rc)
+ vreg->mode = mode;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+ return rc;
+}
+
+static unsigned int pm8xxx_nldo1200_get_mode(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode = 0;
+
+ if (NLDO1200_IN_ADVANCED_MODE(vreg)) {
+ /* Advanced mode */
+ if ((vreg->test_reg[2] & NLDO1200_ADVANCED_PM_MASK)
+ == NLDO1200_ADVANCED_PM_LPM)
+ mode = REGULATOR_MODE_IDLE;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+ } else {
+ /* Legacy mode */
+ if ((vreg->ctrl_reg & NLDO1200_LEGACY_PM_MASK)
+ == NLDO1200_LEGACY_PM_LPM)
+ mode = REGULATOR_MODE_IDLE;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+ }
+
+ return mode;
+}
+
+static int pm8xxx_nldo1200_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+
+ if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+ vreg_err(vreg, "invalid mode: %u\n", mode);
+ return -EINVAL;
+ }
+
+ /*
+ * Make sure that advanced mode is in use. If it isn't, then set it
+ * and update the voltage accordingly.
+ */
+ if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
+ rc = _pm8xxx_nldo1200_set_voltage(vreg, vreg->save_uV,
+ vreg->save_uV);
+ if (rc)
+ goto bail;
+ }
+
+ if (mode == REGULATOR_MODE_NORMAL) {
+ /* HPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ NLDO1200_ADVANCED_PM_HPM | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
+ | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
+ } else {
+ /* LPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ NLDO1200_ADVANCED_PM_LPM | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
+ | REGULATOR_BANK_MASK, &vreg->test_reg[2]);
+ }
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+ return rc;
+}
+
+static unsigned int pm8xxx_smps_get_mode(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode = 0;
+
+ mutex_lock(&vreg->pc_lock);
+ mode = vreg->mode;
+ mutex_unlock(&vreg->pc_lock);
+
+ return mode;
+}
+
+static int pm8xxx_smps_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+
+ if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+ vreg_err(vreg, "invalid mode: %u\n", mode);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (mode == REGULATOR_MODE_NORMAL
+ || (vreg->is_enabled_pc
+ && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE)) {
+ /* HPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+ SMPS_CLK_CTRL_PWM, SMPS_CLK_CTRL_MASK,
+ &vreg->clk_ctrl_reg);
+ } else {
+ /* LPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+ SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
+ &vreg->clk_ctrl_reg);
+ }
+
+ if (!rc)
+ vreg->mode = mode;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+ return rc;
+}
+
+static unsigned int pm8xxx_ftsmps_get_mode(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode = 0;
+
+ if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM)
+ mode = REGULATOR_MODE_IDLE;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+
+ return mode;
+}
+
+static int pm8xxx_ftsmps_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+
+ if (mode == REGULATOR_MODE_NORMAL) {
+ /* HPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ FTSMPS_CNFG1_PM_PWM | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
+ | REGULATOR_BANK_MASK, &vreg->test_reg[0]);
+ } else if (mode == REGULATOR_MODE_IDLE) {
+ /* LPM */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ FTSMPS_CNFG1_PM_PFM | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
+ | REGULATOR_BANK_MASK, &vreg->test_reg[0]);
+ } else {
+ vreg_err(vreg, "invalid mode: %u\n", mode);
+ return -EINVAL;
+ }
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+ return rc;
+}
+
+static unsigned int pm8xxx_vreg_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV, int load_uA)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode;
+
+ if (load_uA + vreg->pdata.system_uA >= vreg->hpm_min_load)
+ mode = REGULATOR_MODE_NORMAL;
+ else
+ mode = REGULATOR_MODE_IDLE;
+
+ return mode;
+}
+
+static int pm8xxx_ldo_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc, val;
+
+ mutex_lock(&vreg->pc_lock);
+
+ /*
+ * Choose HPM if previously set to HPM or if pin control is enabled in
+ * on/off mode.
+ */
+ val = LDO_CTRL_PM_LPM;
+ if (vreg->mode == REGULATOR_MODE_NORMAL
+ || (vreg->is_enabled_pc
+ && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE))
+ val = LDO_CTRL_PM_HPM;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val | LDO_ENABLE,
+ LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+
+ if (!rc)
+ vreg->is_enabled = true;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_ldo_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ mutex_lock(&vreg->pc_lock);
+
+ /*
+ * Only disable the regulator if it isn't still required for HPM/LPM
+ * pin control.
+ */
+ if (!vreg->is_enabled_pc
+ || vreg->pdata.pin_fn != PM8XXX_VREG_PIN_FN_MODE) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+ /* Change to LPM if HPM/LPM pin control is enabled. */
+ if (vreg->is_enabled_pc
+ && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_MODE) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(0),
+ LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[0]);
+ }
+
+ if (!rc)
+ vreg->is_enabled = false;
+bail:
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
+static int pm8xxx_nldo1200_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_ENABLE,
+ NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_nldo1200_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_DISABLE,
+ NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
+static int pm8xxx_smps_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+ int val;
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (SMPS_IN_ADVANCED_MODE(vreg)
+ || !pm8xxx_vreg_is_pin_controlled(vreg)) {
+ /* Enable in advanced mode if not using pin control. */
+ rc = pm8xxx_smps_set_voltage_advanced(vreg, vreg->save_uV,
+ vreg->save_uV, 1);
+ } else {
+ rc = pm8xxx_smps_set_voltage_legacy(vreg, vreg->save_uV,
+ vreg->save_uV);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ SMPS_LEGACY_ENABLE, SMPS_LEGACY_ENABLE_MASK,
+ &vreg->ctrl_reg);
+ }
+
+ /*
+ * Choose HPM if previously set to HPM or if pin control is enabled in
+ * on/off mode.
+ */
+ val = SMPS_CLK_CTRL_PFM;
+ if (vreg->mode == REGULATOR_MODE_NORMAL
+ || (vreg->is_enabled_pc
+ && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE))
+ val = SMPS_CLK_CTRL_PWM;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr, val,
+ SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
+
+ if (!rc)
+ vreg->is_enabled = true;
+bail:
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_smps_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (SMPS_IN_ADVANCED_MODE(vreg)) {
+ /* Change SMPS to legacy mode before disabling. */
+ rc = pm8xxx_smps_set_voltage_legacy(vreg, vreg->save_uV,
+ vreg->save_uV);
+ if (rc)
+ goto bail;
+ }
+
+ /*
+ * Only disable the regulator if it isn't still required for HPM/LPM
+ * pin control.
+ */
+ if (!vreg->is_enabled_pc
+ || vreg->pdata.pin_fn != PM8XXX_VREG_PIN_FN_MODE) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
+ &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+ /* Change to LPM if HPM/LPM pin control is enabled. */
+ if (vreg->is_enabled_pc
+ && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_MODE)
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+ SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
+ &vreg->clk_ctrl_reg);
+
+ if (!rc)
+ vreg->is_enabled = false;
+
+bail:
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
+static int pm8xxx_ftsmps_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = _pm8xxx_ftsmps_set_voltage(vreg, vreg->save_uV, vreg->save_uV, 1);
+
+ if (rc)
+ vreg_err(vreg, "set voltage failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_ftsmps_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->pfm_ctrl_addr,
+ FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK,
+ &vreg->pfm_ctrl_reg);
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
+static int pm8xxx_vs_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ mutex_lock(&vreg->pc_lock);
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS_ENABLE,
+ VS_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (!rc)
+ vreg->is_enabled = true;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_vs_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ mutex_lock(&vreg->pc_lock);
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS_DISABLE,
+ VS_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (!rc)
+ vreg->is_enabled = false;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
+static int pm8xxx_vs300_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_ENABLE,
+ VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_vs300_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_DISABLE,
+ VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
+static int pm8xxx_ncp_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_ENABLE,
+ NCP_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+ return rc;
+}
+
+static int pm8xxx_ncp_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_DISABLE,
+ NCP_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+ return rc;
+}
+
+static int pm8xxx_ldo_pin_control_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+ int bank;
+ u8 val = 0;
+ u8 mask;
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+ val |= LDO_TEST_PIN_CTRL_EN0;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+ val |= LDO_TEST_PIN_CTRL_EN1;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+ val |= LDO_TEST_PIN_CTRL_EN2;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+ val |= LDO_TEST_PIN_CTRL_EN3;
+
+ bank = (vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE ? 5 : 6);
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ val | REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
+ LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[bank]);
+ if (rc)
+ goto bail;
+
+ /* Unset pin control bits in unused bank. */
+ bank = (bank == 5 ? 6 : 5);
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
+ LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[bank]);
+ if (rc)
+ goto bail;
+
+ val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(0);
+ mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr, val, mask,
+ &vreg->test_reg[0]);
+ if (rc)
+ goto bail;
+
+ if (vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE) {
+ /* Pin control ON/OFF */
+ val = LDO_CTRL_PM_HPM;
+ /* Leave physically enabled if already enabled. */
+ val |= (vreg->is_enabled ? LDO_ENABLE : LDO_DISABLE);
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+ LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+ } else {
+ /* Pin control LPM/HPM */
+ val = LDO_ENABLE;
+ /* Leave in HPM if already enabled in HPM. */
+ val |= (vreg->is_enabled && vreg->mode == REGULATOR_MODE_NORMAL
+ ? LDO_CTRL_PM_HPM : LDO_CTRL_PM_LPM);
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+ LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+bail:
+ if (!rc)
+ vreg->is_enabled_pc = true;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+ return rc;
+}
+
+static int pm8xxx_ldo_pin_control_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ mutex_lock(&vreg->pc_lock);
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
+ LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[5]);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
+ LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[6]);
+
+ /*
+ * Physically disable the regulator if it was enabled in HPM/LPM pin
+ * control mode previously and it logically should not be enabled.
+ */
+ if ((vreg->ctrl_reg & LDO_ENABLE_MASK) == LDO_ENABLE
+ && !vreg->is_enabled) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+ /* Change to LPM if LPM was enabled. */
+ if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+ | REGULATOR_BANK_SEL(0),
+ LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[0]);
+ if (rc)
+ goto bail;
+ }
+
+bail:
+ if (!rc)
+ vreg->is_enabled_pc = false;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+ return rc;
+}
+
+static int pm8xxx_smps_pin_control_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc = 0;
+ u8 val = 0;
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE) {
+ /* Pin control ON/OFF */
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+ val |= SMPS_PIN_CTRL_EN0;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+ val |= SMPS_PIN_CTRL_EN1;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+ val |= SMPS_PIN_CTRL_EN2;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+ val |= SMPS_PIN_CTRL_EN3;
+ } else {
+ /* Pin control LPM/HPM */
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+ val |= SMPS_PIN_CTRL_LPM_EN0;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+ val |= SMPS_PIN_CTRL_LPM_EN1;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+ val |= SMPS_PIN_CTRL_LPM_EN2;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+ val |= SMPS_PIN_CTRL_LPM_EN3;
+ }
+
+ rc = pm8xxx_smps_set_voltage_legacy(vreg, vreg->save_uV, vreg->save_uV);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, val,
+ SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
+ &vreg->sleep_ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /*
+ * Physically enable the regulator if using HPM/LPM pin control mode or
+ * if the regulator should be logically left on.
+ */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ ((vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_MODE
+ || vreg->is_enabled) ?
+ SMPS_LEGACY_ENABLE : SMPS_LEGACY_DISABLE),
+ SMPS_LEGACY_ENABLE_MASK, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /*
+ * Set regulator to HPM if using on/off pin control or if the regulator
+ * is already enabled in HPM. Otherwise, set it to LPM.
+ */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+ (vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE
+ || (vreg->is_enabled
+ && vreg->mode == REGULATOR_MODE_NORMAL)
+ ? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
+ SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
+
+bail:
+ if (!rc)
+ vreg->is_enabled_pc = true;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+ return rc;
+}
+
+static int pm8xxx_smps_pin_control_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ mutex_lock(&vreg->pc_lock);
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, 0,
+ SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
+ &vreg->sleep_ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /*
+ * Physically disable the regulator if it was enabled in HPM/LPM pin
+ * control mode previously and it logically should not be enabled.
+ */
+ if ((vreg->ctrl_reg & SMPS_LEGACY_ENABLE_MASK) == SMPS_LEGACY_ENABLE
+ && vreg->is_enabled == false) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
+ &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+ /* Change to LPM if LPM was enabled. */
+ if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+ SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
+ &vreg->clk_ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+ rc = pm8xxx_smps_set_voltage_advanced(vreg, vreg->save_uV,
+ vreg->save_uV, 0);
+
+bail:
+ if (!rc)
+ vreg->is_enabled_pc = false;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+ return rc;
+}
+
+static int pm8xxx_vs_pin_control_enable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+ u8 val = 0;
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+ val |= VS_PIN_CTRL_EN0;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+ val |= VS_PIN_CTRL_EN1;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+ val |= VS_PIN_CTRL_EN2;
+ if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+ val |= VS_PIN_CTRL_EN3;
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+ VS_PIN_CTRL_MASK | VS_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (!rc)
+ vreg->is_enabled_pc = true;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+ return rc;
+}
+
+static int pm8xxx_vs_pin_control_disable(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ mutex_lock(&vreg->pc_lock);
+
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, 0,
+ VS_PIN_CTRL_MASK, &vreg->ctrl_reg);
+
+ if (!rc)
+ vreg->is_enabled_pc = false;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+ else
+ pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+ return rc;
+}
+
+static int pm8xxx_enable_time(struct regulator_dev *rdev)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->pdata.enable_time;
+}
+
+static const char const *pm8xxx_print_actions[] = {
+ [PM8XXX_REGULATOR_ACTION_INIT] = "initial ",
+ [PM8XXX_REGULATOR_ACTION_ENABLE] = "enable ",
+ [PM8XXX_REGULATOR_ACTION_DISABLE] = "disable ",
+ [PM8XXX_REGULATOR_ACTION_VOLTAGE] = "set voltage",
+ [PM8XXX_REGULATOR_ACTION_MODE] = "set mode ",
+ [PM8XXX_REGULATOR_ACTION_PIN_CTRL] = "pin control",
+};
+
+static void pm8xxx_vreg_show_state(struct regulator_dev *rdev,
+ enum pm8xxx_regulator_action action)
+{
+ struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+ int uV, pc;
+ unsigned int mode;
+ const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
+ const char *pc_total = "";
+ const char *action_label = pm8xxx_print_actions[action];
+ const char *enable_label;
+
+ mutex_lock(&vreg->pc_lock);
+
+ /*
+ * Do not print unless REQUEST is specified and SSBI writes have taken
+ * place, or DUPLICATE is specified.
+ */
+ if (!((pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_DUPLICATE)
+ || ((pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_REQUEST)
+ && (vreg->write_count != vreg->prev_write_count)))) {
+ mutex_unlock(&vreg->pc_lock);
+ return;
+ }
+
+ vreg->prev_write_count = vreg->write_count;
+
+ pc = vreg->pdata.pin_ctrl;
+ if (vreg->is_enabled_pc) {
+ if (pc & PM8XXX_VREG_PIN_CTRL_EN0)
+ pc_en0 = " EN0";
+ if (pc & PM8XXX_VREG_PIN_CTRL_EN1)
+ pc_en1 = " EN1";
+ if (pc & PM8XXX_VREG_PIN_CTRL_EN2)
+ pc_en2 = " EN2";
+ if (pc & PM8XXX_VREG_PIN_CTRL_EN3)
+ pc_en3 = " EN3";
+ if (pc == PM8XXX_VREG_PIN_CTRL_NONE)
+ pc_total = " none";
+ } else {
+ pc_total = " none";
+ }
+
+ mutex_unlock(&vreg->pc_lock);
+
+ enable_label = pm8xxx_vreg_is_enabled(rdev) ? "on " : "off";
+
+ switch (vreg->type) {
+ case PM8XXX_REGULATOR_TYPE_PLDO:
+ uV = pm8xxx_pldo_get_voltage(rdev);
+ mode = pm8xxx_ldo_get_mode(rdev);
+ pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
+ action_label, vreg->rdesc.name, enable_label, uV,
+ (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
+ pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+ break;
+ case PM8XXX_REGULATOR_TYPE_NLDO:
+ uV = pm8xxx_nldo_get_voltage(rdev);
+ mode = pm8xxx_ldo_get_mode(rdev);
+ pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
+ action_label, vreg->rdesc.name, enable_label, uV,
+ (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
+ pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+ break;
+ case PM8XXX_REGULATOR_TYPE_NLDO1200:
+ uV = pm8xxx_nldo1200_get_voltage(rdev);
+ mode = pm8xxx_nldo1200_get_mode(rdev);
+ pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
+ action_label, vreg->rdesc.name, enable_label, uV,
+ (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
+ break;
+ case PM8XXX_REGULATOR_TYPE_SMPS:
+ uV = pm8xxx_smps_get_voltage(rdev);
+ mode = pm8xxx_smps_get_mode(rdev);
+ pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
+ action_label, vreg->rdesc.name, enable_label, uV,
+ (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
+ pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+ break;
+ case PM8XXX_REGULATOR_TYPE_FTSMPS:
+ uV = pm8xxx_ftsmps_get_voltage(rdev);
+ mode = pm8xxx_ftsmps_get_mode(rdev);
+ pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
+ action_label, vreg->rdesc.name, enable_label, uV,
+ (mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
+ break;
+ case PM8XXX_REGULATOR_TYPE_VS:
+ pr_info("%s %-9s: %s, pc=%s%s%s%s%s\n",
+ action_label, vreg->rdesc.name, enable_label,
+ pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+ break;
+ case PM8XXX_REGULATOR_TYPE_VS300:
+ pr_info("%s %-9s: %s\n",
+ action_label, vreg->rdesc.name, enable_label);
+ break;
+ case PM8XXX_REGULATOR_TYPE_NCP:
+ uV = pm8xxx_ncp_get_voltage(rdev);
+ pr_info("%s %-9s: %s, v=%7d uV\n",
+ action_label, vreg->rdesc.name, enable_label, uV);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Real regulator operations. */
+static struct regulator_ops pm8xxx_pldo_ops = {
+ .enable = pm8xxx_ldo_enable,
+ .disable = pm8xxx_ldo_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .set_voltage = pm8xxx_pldo_set_voltage,
+ .get_voltage = pm8xxx_pldo_get_voltage,
+ .list_voltage = pm8xxx_pldo_list_voltage,
+ .set_mode = pm8xxx_ldo_set_mode,
+ .get_mode = pm8xxx_ldo_get_mode,
+ .get_optimum_mode = pm8xxx_vreg_get_optimum_mode,
+ .enable_time = pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_nldo_ops = {
+ .enable = pm8xxx_ldo_enable,
+ .disable = pm8xxx_ldo_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .set_voltage = pm8xxx_nldo_set_voltage,
+ .get_voltage = pm8xxx_nldo_get_voltage,
+ .list_voltage = pm8xxx_nldo_list_voltage,
+ .set_mode = pm8xxx_ldo_set_mode,
+ .get_mode = pm8xxx_ldo_get_mode,
+ .get_optimum_mode = pm8xxx_vreg_get_optimum_mode,
+ .enable_time = pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_nldo1200_ops = {
+ .enable = pm8xxx_nldo1200_enable,
+ .disable = pm8xxx_nldo1200_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .set_voltage = pm8xxx_nldo1200_set_voltage,
+ .get_voltage = pm8xxx_nldo1200_get_voltage,
+ .list_voltage = pm8xxx_nldo1200_list_voltage,
+ .set_mode = pm8xxx_nldo1200_set_mode,
+ .get_mode = pm8xxx_nldo1200_get_mode,
+ .get_optimum_mode = pm8xxx_vreg_get_optimum_mode,
+ .enable_time = pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_smps_ops = {
+ .enable = pm8xxx_smps_enable,
+ .disable = pm8xxx_smps_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .set_voltage = pm8xxx_smps_set_voltage,
+ .get_voltage = pm8xxx_smps_get_voltage,
+ .list_voltage = pm8xxx_smps_list_voltage,
+ .set_mode = pm8xxx_smps_set_mode,
+ .get_mode = pm8xxx_smps_get_mode,
+ .get_optimum_mode = pm8xxx_vreg_get_optimum_mode,
+ .enable_time = pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_ftsmps_ops = {
+ .enable = pm8xxx_ftsmps_enable,
+ .disable = pm8xxx_ftsmps_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .set_voltage = pm8xxx_ftsmps_set_voltage,
+ .get_voltage = pm8xxx_ftsmps_get_voltage,
+ .list_voltage = pm8xxx_ftsmps_list_voltage,
+ .set_mode = pm8xxx_ftsmps_set_mode,
+ .get_mode = pm8xxx_ftsmps_get_mode,
+ .get_optimum_mode = pm8xxx_vreg_get_optimum_mode,
+ .enable_time = pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_vs_ops = {
+ .enable = pm8xxx_vs_enable,
+ .disable = pm8xxx_vs_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .enable_time = pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_vs300_ops = {
+ .enable = pm8xxx_vs300_enable,
+ .disable = pm8xxx_vs300_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .enable_time = pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_ncp_ops = {
+ .enable = pm8xxx_ncp_enable,
+ .disable = pm8xxx_ncp_disable,
+ .is_enabled = pm8xxx_vreg_is_enabled,
+ .set_voltage = pm8xxx_ncp_set_voltage,
+ .get_voltage = pm8xxx_ncp_get_voltage,
+ .list_voltage = pm8xxx_ncp_list_voltage,
+ .enable_time = pm8xxx_enable_time,
+};
+
+/* Pin control regulator operations. */
+static struct regulator_ops pm8xxx_ldo_pc_ops = {
+ .enable = pm8xxx_ldo_pin_control_enable,
+ .disable = pm8xxx_ldo_pin_control_disable,
+ .is_enabled = pm8xxx_vreg_pin_control_is_enabled,
+};
+
+static struct regulator_ops pm8xxx_smps_pc_ops = {
+ .enable = pm8xxx_smps_pin_control_enable,
+ .disable = pm8xxx_smps_pin_control_disable,
+ .is_enabled = pm8xxx_vreg_pin_control_is_enabled,
+};
+
+static struct regulator_ops pm8xxx_vs_pc_ops = {
+ .enable = pm8xxx_vs_pin_control_enable,
+ .disable = pm8xxx_vs_pin_control_disable,
+ .is_enabled = pm8xxx_vreg_pin_control_is_enabled,
+};
+
+static struct regulator_ops *pm8xxx_reg_ops[PM8XXX_REGULATOR_TYPE_MAX] = {
+ [PM8XXX_REGULATOR_TYPE_PLDO] = &pm8xxx_pldo_ops,
+ [PM8XXX_REGULATOR_TYPE_NLDO] = &pm8xxx_nldo_ops,
+ [PM8XXX_REGULATOR_TYPE_NLDO1200] = &pm8xxx_nldo1200_ops,
+ [PM8XXX_REGULATOR_TYPE_SMPS] = &pm8xxx_smps_ops,
+ [PM8XXX_REGULATOR_TYPE_FTSMPS] = &pm8xxx_ftsmps_ops,
+ [PM8XXX_REGULATOR_TYPE_VS] = &pm8xxx_vs_ops,
+ [PM8XXX_REGULATOR_TYPE_VS300] = &pm8xxx_vs300_ops,
+ [PM8XXX_REGULATOR_TYPE_NCP] = &pm8xxx_ncp_ops,
+};
+
+static struct regulator_ops *pm8xxx_reg_pc_ops[PM8XXX_REGULATOR_TYPE_MAX] = {
+ [PM8XXX_REGULATOR_TYPE_PLDO] = &pm8xxx_ldo_pc_ops,
+ [PM8XXX_REGULATOR_TYPE_NLDO] = &pm8xxx_ldo_pc_ops,
+ [PM8XXX_REGULATOR_TYPE_SMPS] = &pm8xxx_smps_pc_ops,
+ [PM8XXX_REGULATOR_TYPE_VS] = &pm8xxx_vs_pc_ops,
+};
+
+static unsigned pm8xxx_n_voltages[PM8XXX_REGULATOR_TYPE_MAX] = {
+ [PM8XXX_REGULATOR_TYPE_PLDO] = PLDO_SET_POINTS,
+ [PM8XXX_REGULATOR_TYPE_NLDO] = NLDO_SET_POINTS,
+ [PM8XXX_REGULATOR_TYPE_NLDO1200] = NLDO1200_SET_POINTS,
+ [PM8XXX_REGULATOR_TYPE_SMPS] = SMPS_ADVANCED_SET_POINTS,
+ [PM8XXX_REGULATOR_TYPE_FTSMPS] = FTSMPS_SET_POINTS,
+ [PM8XXX_REGULATOR_TYPE_VS] = 0,
+ [PM8XXX_REGULATOR_TYPE_VS300] = 0,
+ [PM8XXX_REGULATOR_TYPE_NCP] = NCP_SET_POINTS,
+};
+
+static int pm8xxx_init_ldo(struct pm8xxx_vreg *vreg, bool is_real)
+{
+ int rc = 0;
+ int i;
+ u8 bank;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /* Save the current test register state. */
+ for (i = 0; i < LDO_TEST_BANKS; i++) {
+ bank = REGULATOR_BANK_SEL(i);
+ rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+ &vreg->test_reg[i]);
+ if (rc)
+ goto bail;
+ vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+ }
+
+ if (is_real) {
+ /* Set pull down enable based on platform data. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ (vreg->pdata.pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
+ LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
+
+ vreg->is_enabled = !!_pm8xxx_vreg_is_enabled(vreg);
+
+ vreg->mode = ((vreg->ctrl_reg & LDO_CTRL_PM_MASK)
+ == LDO_CTRL_PM_LPM ?
+ REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
+ }
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_init_nldo1200(struct pm8xxx_vreg *vreg)
+{
+ int rc = 0;
+ int i;
+ u8 bank;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /* Save the current test register state. */
+ for (i = 0; i < LDO_TEST_BANKS; i++) {
+ bank = REGULATOR_BANK_SEL(i);
+ rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+ &vreg->test_reg[i]);
+ if (rc)
+ goto bail;
+ vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+ }
+
+ vreg->save_uV = _pm8xxx_nldo1200_get_voltage(vreg);
+
+ /* Set pull down enable based on platform data. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ (vreg->pdata.pull_down_enable ? NLDO1200_PULL_DOWN_ENABLE : 0)
+ | REGULATOR_BANK_SEL(1) | REGULATOR_BANK_WRITE,
+ NLDO1200_PULL_DOWN_ENABLE_MASK | REGULATOR_BANK_MASK,
+ &vreg->test_reg[1]);
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_init_smps(struct pm8xxx_vreg *vreg, bool is_real)
+{
+ int rc = 0;
+ int i;
+ u8 bank;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /* Save the current test2 register state. */
+ for (i = 0; i < SMPS_TEST_BANKS; i++) {
+ bank = REGULATOR_BANK_SEL(i);
+ rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+ &vreg->test_reg[i]);
+ if (rc)
+ goto bail;
+ vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+ }
+
+ /* Save the current clock control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
+ &vreg->clk_ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /* Save the current sleep control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
+ &vreg->sleep_ctrl_reg);
+ if (rc)
+ goto bail;
+
+ vreg->save_uV = _pm8xxx_smps_get_voltage(vreg);
+
+ if (is_real) {
+ /* Set advanced mode pull down enable based on platform data. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+ (vreg->pdata.pull_down_enable
+ ? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
+ | REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
+ REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
+ &vreg->test_reg[6]);
+ if (rc)
+ goto bail;
+
+ vreg->is_enabled = !!_pm8xxx_vreg_is_enabled(vreg);
+
+ vreg->mode = ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
+ == SMPS_CLK_CTRL_PFM ?
+ REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
+ }
+
+ if (!SMPS_IN_ADVANCED_MODE(vreg) && is_real) {
+ /* Set legacy mode pull down enable based on platform data. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ (vreg->pdata.pull_down_enable
+ ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
+ SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+ }
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_init_ftsmps(struct pm8xxx_vreg *vreg)
+{
+ int rc, i;
+ u8 bank;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc)
+ goto bail;
+
+ /* Store current regulator register values. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->pfm_ctrl_addr,
+ &vreg->pfm_ctrl_reg);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->pwr_cnfg_addr,
+ &vreg->pwr_cnfg_reg);
+ if (rc)
+ goto bail;
+
+ /* Save the current fts_cnfg1 register state (uses 'test' member). */
+ for (i = 0; i < SMPS_TEST_BANKS; i++) {
+ bank = REGULATOR_BANK_SEL(i);
+ rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+ if (rc)
+ goto bail;
+
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+ &vreg->test_reg[i]);
+ if (rc)
+ goto bail;
+ vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+ }
+
+ vreg->save_uV = _pm8xxx_ftsmps_get_voltage(vreg);
+
+ /* Set pull down enable based on platform data. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->pwr_cnfg_addr,
+ (vreg->pdata.pull_down_enable ? FTSMPS_PULL_DOWN_ENABLE : 0),
+ FTSMPS_PULL_DOWN_ENABLE_MASK, &vreg->pwr_cnfg_reg);
+
+bail:
+ if (rc)
+ vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_init_vs(struct pm8xxx_vreg *vreg, bool is_real)
+{
+ int rc = 0;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc) {
+ vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (is_real) {
+ /* Set pull down enable based on platform data. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ (vreg->pdata.pull_down_enable ? VS_PULL_DOWN_ENABLE
+ : VS_PULL_DOWN_DISABLE),
+ VS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg,
+ "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+ vreg->is_enabled = !!_pm8xxx_vreg_is_enabled(vreg);
+ }
+
+ return rc;
+}
+
+static int pm8xxx_init_vs300(struct pm8xxx_vreg *vreg)
+{
+ int rc;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc) {
+ vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Set pull down enable based on platform data. */
+ rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+ (vreg->pdata.pull_down_enable ? VS300_PULL_DOWN_ENABLE : 0),
+ VS300_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
+
+ if (rc)
+ vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pm8xxx_init_ncp(struct pm8xxx_vreg *vreg)
+{
+ int rc;
+
+ /* Save the current control register state. */
+ rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+ if (rc) {
+ vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static int __devinit pm8xxx_vreg_probe(struct platform_device *pdev)
+{
+ struct pm8xxx_regulator_core_platform_data *core_data;
+ const struct pm8xxx_regulator_platform_data *pdata;
+ enum pm8xxx_vreg_pin_function pin_fn;
+ struct regulator_desc *rdesc;
+ struct pm8xxx_vreg *vreg;
+ unsigned pin_ctrl;
+ int rc = 0;
+
+ if (pdev == NULL) {
+ pr_err("no platform device specified\n");
+ return -EINVAL;
+ }
+
+ core_data = pdev->dev.platform_data;
+ if (core_data == NULL) {
+ pr_err("no core data specified\n");
+ return -EINVAL;
+ }
+
+ pdata = core_data->pdata;
+ vreg = core_data->vreg;
+ if (pdata == NULL) {
+ pr_err("no pdata specified\n");
+ return -EINVAL;
+ } else if (vreg == NULL) {
+ pr_err("no vreg specified\n");
+ return -EINVAL;
+ }
+
+ if (vreg->rdesc.name == NULL) {
+ pr_err("regulator name missing\n");
+ return -EINVAL;
+ } else if (vreg->type < 0 || vreg->type > PM8XXX_REGULATOR_TYPE_MAX) {
+ pr_err("%s: regulator type=%d is invalid\n", vreg->rdesc.name,
+ vreg->type);
+ return -EINVAL;
+ } else if (core_data->is_pin_controlled
+ && pm8xxx_reg_pc_ops[vreg->type] == NULL) {
+ pr_err("%s: regulator type=%d does not support pin control\n",
+ vreg->rdesc.name, vreg->type);
+ return -EINVAL;
+ } else if (core_data->is_pin_controlled
+ && vreg->rdesc_pc.name == NULL) {
+ pr_err("%s: regulator pin control name missing\n",
+ vreg->rdesc.name);
+ return -EINVAL;
+ }
+
+ if (core_data->is_pin_controlled)
+ rdesc = &vreg->rdesc_pc;
+ else
+ rdesc = &vreg->rdesc;
+ if (!pdata) {
+ pr_err("%s requires platform data\n", vreg->rdesc.name);
+ return -EINVAL;
+ }
+
+ rdesc->id = pdev->id;
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+ if (core_data->is_pin_controlled) {
+ rdesc->ops = pm8xxx_reg_pc_ops[vreg->type];
+ rdesc->n_voltages = 0;
+ } else {
+ rdesc->ops = pm8xxx_reg_ops[vreg->type];
+ rdesc->n_voltages = pm8xxx_n_voltages[vreg->type];
+ }
+
+ mutex_lock(&vreg->pc_lock);
+
+ if (!core_data->is_pin_controlled) {
+ /* Do not modify pin control and pin function values. */
+ pin_ctrl = vreg->pdata.pin_ctrl;
+ pin_fn = vreg->pdata.pin_fn;
+ memcpy(&(vreg->pdata), pdata,
+ sizeof(struct pm8xxx_regulator_platform_data));
+ vreg->pdata.pin_ctrl = pin_ctrl;
+ vreg->pdata.pin_fn = pin_fn;
+ vreg->dev = &pdev->dev;
+ } else {
+ /* Pin control regulator */
+ if ((pdata->pin_ctrl & PM8XXX_VREG_PIN_CTRL_ALL)
+ == PM8XXX_VREG_PIN_CTRL_NONE) {
+ pr_err("%s: no pin control input specified\n",
+ vreg->rdesc.name);
+ mutex_unlock(&vreg->pc_lock);
+ return -EINVAL;
+ }
+ vreg->pdata.pin_ctrl = pdata->pin_ctrl;
+ vreg->pdata.pin_fn = pdata->pin_fn;
+ vreg->dev_pc = &pdev->dev;
+ if (!vreg->dev)
+ vreg->dev = &pdev->dev;
+ }
+
+ /* Initialize register values. */
+ switch (vreg->type) {
+ case PM8XXX_REGULATOR_TYPE_PLDO:
+ case PM8XXX_REGULATOR_TYPE_NLDO:
+ rc = pm8xxx_init_ldo(vreg, !core_data->is_pin_controlled);
+ break;
+ case PM8XXX_REGULATOR_TYPE_NLDO1200:
+ rc = pm8xxx_init_nldo1200(vreg);
+ break;
+ case PM8XXX_REGULATOR_TYPE_SMPS:
+ rc = pm8xxx_init_smps(vreg, !core_data->is_pin_controlled);
+ break;
+ case PM8XXX_REGULATOR_TYPE_FTSMPS:
+ rc = pm8xxx_init_ftsmps(vreg);
+ break;
+ case PM8XXX_REGULATOR_TYPE_VS:
+ rc = pm8xxx_init_vs(vreg, !core_data->is_pin_controlled);
+ break;
+ case PM8XXX_REGULATOR_TYPE_VS300:
+ rc = pm8xxx_init_vs300(vreg);
+ break;
+ case PM8XXX_REGULATOR_TYPE_NCP:
+ rc = pm8xxx_init_ncp(vreg);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ goto bail;
+
+ if (!core_data->is_pin_controlled) {
+ vreg->rdev = regulator_register(rdesc, &pdev->dev,
+ &(pdata->init_data), vreg);
+ if (IS_ERR(vreg->rdev)) {
+ rc = PTR_ERR(vreg->rdev);
+ vreg->rdev = NULL;
+ pr_err("regulator_register failed: %s, rc=%d\n",
+ vreg->rdesc.name, rc);
+ }
+ } else {
+ vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
+ &(pdata->init_data), vreg);
+ if (IS_ERR(vreg->rdev_pc)) {
+ rc = PTR_ERR(vreg->rdev_pc);
+ vreg->rdev_pc = NULL;
+ pr_err("regulator_register failed: %s, rc=%d\n",
+ vreg->rdesc.name, rc);
+ }
+ }
+ if ((pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_INIT) && !rc
+ && vreg->rdev)
+ pm8xxx_vreg_show_state(vreg->rdev,
+ PM8XXX_REGULATOR_ACTION_INIT);
+
+ platform_set_drvdata(pdev, core_data);
+
+bail:
+ if (rc)
+ pr_err("error for %s, rc=%d\n", vreg->rdesc.name, rc);
+
+ return rc;
+}
+
+static int __devexit pm8xxx_vreg_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_regulator_core_platform_data *core_data;
+
+ core_data = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+
+ if (core_data) {
+ if (core_data->is_pin_controlled)
+ regulator_unregister(core_data->vreg->rdev_pc);
+ else
+ regulator_unregister(core_data->vreg->rdev);
+ }
+
+ return 0;
+}
+
+static struct platform_driver pm8xxx_vreg_driver = {
+ .probe = pm8xxx_vreg_probe,
+ .remove = __devexit_p(pm8xxx_vreg_remove),
+ .driver = {
+ .name = PM8XXX_REGULATOR_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8xxx_vreg_init(void)
+{
+ return platform_driver_register(&pm8xxx_vreg_driver);
+}
+postcore_initcall(pm8xxx_vreg_init);
+
+static void __exit pm8xxx_vreg_exit(void)
+{
+ platform_driver_unregister(&pm8xxx_vreg_driver);
+}
+module_exit(pm8xxx_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC PM8XXX regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_REGULATOR_DEV_NAME);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 93feb81..67179e5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1133,26 +1133,6 @@
This drive can also be built as a module. If so, the module
will be called rtc-puv3.
-config RTC_PM8058
- tristate "PMIC8058 RTC support"
- default n
- depends on PMIC8058
- help
- Say Y here if you want support for the PMIC8058 RTC.
-
- To compile this driver as a module, choose M here: the
- module will be called pmic8058-rtc.
-
-config RTC_PM8058_WRITE_ENABLE
- bool "PM8058 RTC write enable"
- default n
- depends on RTC_PM8058
- help
- Say Y here if you want to support the write operation for
- PMIC8058 RTC.
-
- By default the write operation is not supported.
-
config RTC_DRV_PM8XXX
tristate "Qualcomm PMIC8XXX RTC"
depends on MFD_PM8XXX
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 9e41297..bd149ed 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -113,4 +113,3 @@
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
-obj-$(CONFIG_RTC_PM8058) += rtc-pm8058.o
diff --git a/drivers/rtc/rtc-pm8058.c b/drivers/rtc/rtc-pm8058.c
deleted file mode 100644
index 0376c64..0000000
--- a/drivers/rtc/rtc-pm8058.c
+++ /dev/null
@@ -1,603 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/rtc.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/rtc/rtc-pm8058.h>
-#include <linux/pm_runtime.h>
-
-#define PM8058_RTC_CTRL 0x1E8
- #define PM8058_RTC_ENABLE BIT(7)
- #define PM8058_RTC_ALARM_ENABLE BIT(1)
- #define PM8058_RTC_ABORT_ENABLE BIT(0)
-#define PM8058_RTC_ALARM_CTRL 0x1E9
- #define PM8058_RTC_ALARM_CLEAR BIT(0)
-#define PM8058_RTC_TEST 0x1F6
-#define PM8058_RTC_READ_BASE 0x1EE
-#define PM8058_RTC_WRITE_BASE 0x1EA
-#define PM8058_RTC_ALARM_BASE 0x1F2
-
-struct pm8058_rtc {
- struct rtc_device *rtc0;
- u8 rtc_ctrl_reg;
- int rtc_irq;
- int rtc_alarm_irq;
- struct pm8058_chip *pm_chip;
-};
-
-static int
-pm8058_rtc_read_bytes(struct pm8058_rtc *rtc_dd, u8 *rtc_val, int base)
-{
- int i, rc;
-
- /*
- * Read the 32-bit RTC/Alarm Value.
- * These values have to be read 8-bit at a time.
- */
- for (i = 0; i < 4; i++) {
- rc = pm8058_read(rtc_dd->pm_chip, base + i, &rtc_val[i], 1);
- if (rc < 0) {
- pr_err("%s: PM8058 read failed\n", __func__);
- return rc;
- }
- }
-
- return 0;
-}
-
-static int
-pm8058_rtc_write_bytes(struct pm8058_rtc *rtc_dd, u8 *rtc_val, int base)
-{
- int i, rc;
-
- /*
- * Write the 32-bit Value.
- * These values have to be written 8-bit at a time.
- */
- for (i = 0; i < 4; i++) {
- rc = pm8058_write(rtc_dd->pm_chip, base + i, &rtc_val[i], 1);
- if (rc < 0) {
- pr_err("%s: PM8058 read failed\n", __func__);
- return rc;
- }
- }
-
- return 0;
-}
-
-/*
- * Steps to write the RTC registers.
- * 1. Disable alarm if enabled.
- * 2. Write 0x00 to LSB.
- * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
- * 4. Enable alarm if disabled earlier.
- */
-#ifdef CONFIG_RTC_PM8058_WRITE_ENABLE
-static int
-pm8058_rtc0_set_time(struct device *dev, struct rtc_time *tm)
-{
- int rc;
- unsigned long secs = 0;
- u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg = 0, i;
- struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
- ctrl_reg = rtc_dd->rtc_ctrl_reg;
-
- rtc_tm_to_time(tm, &secs);
-
- value[0] = secs & 0xFF;
- value[1] = (secs >> 8) & 0xFF;
- value[2] = (secs >> 16) & 0xFF;
- value[3] = (secs >> 24) & 0xFF;
-
- pr_debug("%s: Seconds value to be written to RTC = %lu\n", __func__,
- secs);
- /* Disable alarm before updating RTC */
- if (ctrl_reg & PM8058_RTC_ALARM_ENABLE) {
- alarm_enabled = 1;
- ctrl_reg &= ~PM8058_RTC_ALARM_ENABLE;
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL,
- &ctrl_reg, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return rc;
- }
- }
-
- /* Write Byte[1], Byte[2], Byte[3], Byte[0] */
- reg = 0;
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_WRITE_BASE, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return rc;
- }
-
- for (i = 1; i < 4; i++) {
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_WRITE_BASE + i,
- &value[i], 1);
- if (rc < 0) {
- pr_err("%s:Write to RTC registers failed\n", __func__);
- return rc;
- }
- }
-
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_WRITE_BASE,
- &value[0], 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return rc;
- }
-
- if (alarm_enabled) {
- ctrl_reg |= PM8058_RTC_ALARM_ENABLE;
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL,
- &ctrl_reg, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return rc;
- }
- }
-
- rtc_dd->rtc_ctrl_reg = ctrl_reg;
-
- return 0;
-}
-#endif
-
-static int
-pm8058_rtc0_read_time(struct device *dev, struct rtc_time *tm)
-{
- int rc;
- u8 value[4], reg;
- unsigned long secs = 0;
- struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
- rc = pm8058_rtc_read_bytes(rtc_dd, value, PM8058_RTC_READ_BASE);
- if (rc < 0) {
- pr_err("%s: RTC time read failed\n", __func__);
- return rc;
- }
-
- /*
- * Read the LSB again and check if there has been a carry over.
- * If there is, redo the read operation.
- */
- rc = pm8058_read(rtc_dd->pm_chip, PM8058_RTC_READ_BASE, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 read failed\n", __func__);
- return rc;
- }
-
- if (unlikely(reg < value[0])) {
- rc = pm8058_rtc_read_bytes(rtc_dd, value,
- PM8058_RTC_READ_BASE);
- if (rc < 0) {
- pr_err("%s: RTC time read failed\n", __func__);
- return rc;
- }
- }
-
- secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
-
- rtc_time_to_tm(secs, tm);
-
- rc = rtc_valid_tm(tm);
- if (rc < 0) {
- pr_err("%s: Invalid time read from PMIC8058\n", __func__);
- return rc;
- }
-
- pr_debug("%s: secs = %lu, h::m:s == %d::%d::%d, d/m/y = %d/%d/%d\n",
- __func__, secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
- tm->tm_mday, tm->tm_mon, tm->tm_year);
-
- return 0;
-}
-
-static int
-pm8058_rtc0_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-{
- int rc;
- u8 value[4], reg;
- struct rtc_time rtc_tm;
- unsigned long secs_alarm, secs_rtc;
- struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
- reg = rtc_dd->rtc_ctrl_reg;
-
- /* Check if the alarm is valid */
- rc = rtc_valid_tm(&alarm->time);
- if (rc < 0) {
- pr_err("%s: Alarm time invalid\n", __func__);
- return -EINVAL;
- }
-
- rtc_tm_to_time(&alarm->time, &secs_alarm);
-
- /*
- * Read the current RTC time and verify if the alarm time is in the
- * past. If yes, return invalid.
- */
- rc = pm8058_rtc0_read_time(dev, &rtc_tm);
- if (rc) {
- pr_err("%s: Unable to read RTC time\n", __func__);
- return -EINVAL;
- }
- rtc_tm_to_time(&rtc_tm, &secs_rtc);
-
- if (secs_alarm < secs_rtc) {
- pr_err("%s: Trying to set alarm in the past\n", __func__);
- return -EINVAL;
- }
-
- value[0] = secs_alarm & 0xFF;
- value[1] = (secs_alarm >> 8) & 0xFF;
- value[2] = (secs_alarm >> 16) & 0xFF;
- value[3] = (secs_alarm >> 24) & 0xFF;
-
- rc = pm8058_rtc_write_bytes(rtc_dd, value, PM8058_RTC_ALARM_BASE);
- if (rc < 0) {
- pr_err("%s: Alarm could not be set\n", __func__);
- return rc;
- }
-
- reg = (alarm->enabled) ? (reg | PM8058_RTC_ALARM_ENABLE) :
- (reg & ~PM8058_RTC_ALARM_ENABLE);
-
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return rc;
- }
-
- rtc_dd->rtc_ctrl_reg = reg;
-
- pr_debug("%s: Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
- __func__, alarm->time.tm_hour, alarm->time.tm_min,
- alarm->time.tm_sec, alarm->time.tm_mday,
- alarm->time.tm_mon, alarm->time.tm_year);
-
- return 0;
-}
-
-static int
-pm8058_rtc0_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-{
- int rc;
- u8 value[4], reg;
- unsigned long secs = 0;
- struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
- reg = rtc_dd->rtc_ctrl_reg;
-
- alarm->enabled = !!(reg & PM8058_RTC_ALARM_ENABLE);
-
- rc = pm8058_rtc_read_bytes(rtc_dd, value,
- PM8058_RTC_ALARM_BASE);
- if (rc < 0) {
- pr_err("%s: RTC alarm time read failed\n", __func__);
- return rc;
- }
-
- secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
-
- rtc_time_to_tm(secs, &alarm->time);
-
- rc = rtc_valid_tm(&alarm->time);
- if (rc < 0) {
- pr_err("%s: Invalid time read from PMIC8058\n", __func__);
- return rc;
- }
-
- pr_debug("%s: Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
- __func__, alarm->time.tm_hour, alarm->time.tm_min,
- alarm->time.tm_sec, alarm->time.tm_mday,
- alarm->time.tm_mon, alarm->time.tm_year);
-
- return 0;
-}
-
-
-static int
-pm8058_rtc0_alarm_irq_enable(struct device *dev, unsigned int enable)
-{
- int rc;
- struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
- u8 reg;
-
- reg = rtc_dd->rtc_ctrl_reg;
- reg = (enable) ? (reg | PM8058_RTC_ALARM_ENABLE) :
- (reg & ~PM8058_RTC_ALARM_ENABLE);
-
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return rc;
- }
-
- rtc_dd->rtc_ctrl_reg = reg;
-
- return rc;
-}
-
-static struct rtc_class_ops pm8058_rtc0_ops = {
- .read_time = pm8058_rtc0_read_time,
- .set_alarm = pm8058_rtc0_set_alarm,
- .read_alarm = pm8058_rtc0_read_alarm,
- .alarm_irq_enable = pm8058_rtc0_alarm_irq_enable,
-};
-
-static irqreturn_t pm8058_alarm_trigger(int irq, void *dev_id)
-{
- u8 reg;
- int rc;
- unsigned long events = 0;
- struct pm8058_rtc *rtc_dd = dev_id;
-
- events = RTC_IRQF | RTC_AF;
- rtc_update_irq(rtc_dd->rtc0, 1, events);
-
- pr_debug("%s: Alarm Triggered !!\n", __func__);
-
- /* Clear the alarm enable bit */
- reg = rtc_dd->rtc_ctrl_reg;
-
- reg &= ~PM8058_RTC_ALARM_ENABLE;
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL,
- ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- goto rtc_alarm_handled;
- }
-
- rtc_dd->rtc_ctrl_reg = reg;
-
- /* Clear RTC alarm register */
- rc = pm8058_read(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 read failed\n", __func__);
- goto rtc_alarm_handled;
- }
-
- reg &= ~PM8058_RTC_ALARM_CLEAR;
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- goto rtc_alarm_handled;
- }
-
-rtc_alarm_handled:
- return IRQ_HANDLED;
-}
-
-static int __devinit pm8058_rtc_probe(struct platform_device *pdev)
-{
- int rc;
- u8 reg, reg_alarm;
- struct pm8058_rtc *rtc_dd;
- struct pm8058_chip *pm_chip;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("%s: Invalid driver information\n", __func__);
- return -ENXIO;
- }
-
- rtc_dd = kzalloc(sizeof(*rtc_dd), GFP_KERNEL);
- if (rtc_dd == NULL) {
- pr_err("%s: Unable to allocate memory\n", __func__);
- return -ENOMEM;
- }
-
- /* Enable runtime PM ops, start in ACTIVE mode */
- rc = pm_runtime_set_active(&pdev->dev);
- if (rc < 0)
- dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
- pm_runtime_enable(&pdev->dev);
-
- rtc_dd->rtc_irq = platform_get_irq(pdev, 0);
- rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 1);
- if (!rtc_dd->rtc_alarm_irq || !rtc_dd->rtc_irq) {
- pr_err("%s: RTC Alarm IRQ absent\n", __func__);
- rc = -ENXIO;
- goto fail_rtc_enable;
- }
-
- rtc_dd->pm_chip = pm_chip;
-
- rc = pm8058_read(pm_chip, PM8058_RTC_CTRL, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 read failed\n", __func__);
- goto fail_rtc_enable;
- }
-
- /* Enable RTC, ABORT enable and disable alarm */
- reg |= ((PM8058_RTC_ENABLE | PM8058_RTC_ABORT_ENABLE) &
- ~PM8058_RTC_ALARM_ENABLE);
-
- rc = pm8058_write(pm_chip, PM8058_RTC_CTRL, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- goto fail_rtc_enable;
- }
-
- /* Clear RTC alarm control register */
- rc = pm8058_read(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL,
- ®_alarm, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 read failed\n", __func__);
- goto fail_rtc_enable;
- }
-
- reg_alarm &= ~PM8058_RTC_ALARM_CLEAR;
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL,
- ®_alarm, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- goto fail_rtc_enable;
- }
-
- rtc_dd->rtc_ctrl_reg = reg;
-
-#ifdef CONFIG_RTC_PM8058_WRITE_ENABLE
- pm8058_rtc0_ops.set_time = pm8058_rtc0_set_time;
-#endif
-
- platform_set_drvdata(pdev, rtc_dd);
-
- /* Register the RTC device */
- rtc_dd->rtc0 = rtc_device_register("pm8058_rtc0", &pdev->dev,
- &pm8058_rtc0_ops, THIS_MODULE);
- if (IS_ERR(rtc_dd->rtc0)) {
- pr_err("%s: RTC device registration failed (%ld)\n",
- __func__, PTR_ERR(rtc_dd->rtc0));
- rc = PTR_ERR(rtc_dd->rtc0);
- goto fail_rtc_enable;
- }
-
- /* Request the alarm IRQ */
- rc = request_threaded_irq(rtc_dd->rtc_alarm_irq, NULL,
- pm8058_alarm_trigger, IRQF_TRIGGER_RISING,
- "pm8058_rtc_alarm", rtc_dd);
- if (rc < 0) {
- pr_err("%s: Request IRQ failed (%d)\n", __func__, rc);
- goto fail_req_irq;
- }
-
- device_init_wakeup(&pdev->dev, 1);
-
- pr_debug("%s: Probe success !!\n", __func__);
-
- return 0;
-
-fail_req_irq:
- rtc_device_unregister(rtc_dd->rtc0);
-fail_rtc_enable:
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- kfree(rtc_dd);
- return rc;
-}
-
-#ifdef CONFIG_PM
-static int pm8058_rtc_resume(struct device *dev)
-{
- struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev))
- disable_irq_wake(rtc_dd->rtc_alarm_irq);
-
- return 0;
-}
-
-static int pm8058_rtc_suspend(struct device *dev)
-{
- struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev))
- enable_irq_wake(rtc_dd->rtc_alarm_irq);
-
- return 0;
-}
-
-static struct dev_pm_ops pm8058_rtc_pm_ops = {
- .suspend = pm8058_rtc_suspend,
- .resume = pm8058_rtc_resume,
-};
-#endif
-
-static int __devexit pm8058_rtc_remove(struct platform_device *pdev)
-{
- struct pm8058_rtc *rtc_dd = platform_get_drvdata(pdev);
-
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
- device_init_wakeup(&pdev->dev, 0);
- free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
- rtc_device_unregister(rtc_dd->rtc0);
- kfree(rtc_dd);
-
- return 0;
-}
-
-static void pm8058_rtc_shutdown(struct platform_device *pdev)
-{
- u8 reg;
- int rc, i;
- bool rtc_alarm_powerup = false;
- struct pm8058_rtc *rtc_dd = platform_get_drvdata(pdev);
- struct pm8058_rtc_platform_data *pdata = pdev->dev.platform_data;
-
- if (pdata != NULL)
- rtc_alarm_powerup = pdata->rtc_alarm_powerup;
-
- if (!rtc_alarm_powerup) {
-
- dev_dbg(&pdev->dev, "Disabling alarm interrupts\n");
-
- /* Disable RTC alarms */
- reg = rtc_dd->rtc_ctrl_reg;
- reg &= ~PM8058_RTC_ALARM_ENABLE;
- rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return;
- }
-
- /* Clear Alarm register */
- reg = 0x0;
- for (i = 0; i < 4; i++) {
- rc = pm8058_write(rtc_dd->pm_chip,
- PM8058_RTC_ALARM_BASE + i, ®, 1);
- if (rc < 0) {
- pr_err("%s: PM8058 write failed\n", __func__);
- return;
- }
- }
-
- }
-}
-
-static struct platform_driver pm8058_rtc_driver = {
- .probe = pm8058_rtc_probe,
- .remove = __devexit_p(pm8058_rtc_remove),
- .shutdown = pm8058_rtc_shutdown,
- .driver = {
- .name = "pm8058-rtc",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &pm8058_rtc_pm_ops,
-#endif
- },
-};
-
-static int __init pm8058_rtc_init(void)
-{
- return platform_driver_register(&pm8058_rtc_driver);
-}
-
-static void __exit pm8058_rtc_exit(void)
-{
- platform_driver_unregister(&pm8058_rtc_driver);
-}
-
-module_init(pm8058_rtc_init);
-module_exit(pm8058_rtc_exit);
-
-MODULE_ALIAS("platform:pm8058-rtc");
-MODULE_DESCRIPTION("PMIC8058 RTC driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
index 9ab21da..489d27a 100644
--- a/drivers/staging/qcache/fmem.c
+++ b/drivers/staging/qcache/fmem.c
@@ -17,11 +17,36 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include "tmem.h"
+#include <asm/mach/map.h>
struct fmem_data fmem_data;
enum fmem_state fmem_state;
static spinlock_t fmem_state_lock;
+void *fmem_map_virtual_area(int cacheability)
+{
+ unsigned long addr;
+ const struct mem_type *type;
+ int ret;
+
+ addr = (unsigned long) fmem_data.area->addr;
+ type = get_mem_type(cacheability);
+ ret = ioremap_page_range(addr, addr + fmem_data.size,
+ fmem_data.phys, __pgprot(type->prot_pte));
+ if (ret)
+ return ERR_PTR(ret);
+
+ fmem_data.virt = fmem_data.area->addr;
+
+ return fmem_data.virt;
+}
+
+void fmem_unmap_virtual_area(void)
+{
+ unmap_kernel_range((unsigned long)fmem_data.virt, fmem_data.size);
+ fmem_data.virt = NULL;
+}
+
static int fmem_probe(struct platform_device *pdev)
{
struct fmem_platform_data *pdata = pdev->dev.platform_data;
@@ -29,13 +54,16 @@
if (!pdata->size)
return -ENODEV;
- fmem_data.virt = ioremap_cached(pdata->phys, pdata->size);
- if (!fmem_data.virt)
- return -ENOMEM;
-
fmem_data.phys = pdata->phys;
fmem_data.size = pdata->size;
+ fmem_data.area = get_vm_area(pdata->size, VM_IOREMAP);
+ if (!fmem_data.area)
+ return -ENOMEM;
+ if (!fmem_map_virtual_area(MT_DEVICE_CACHED)) {
+ remove_vm_area(fmem_data.area->addr);
+ return -ENOMEM;
+ }
pr_info("fmem phys %lx virt %p size %lx\n",
fmem_data.phys, fmem_data.virt, fmem_data.size);
@@ -159,10 +187,18 @@
}
}
- if (new_state == FMEM_T_STATE)
+ if (new_state == FMEM_T_STATE) {
+ void *v;
+ v = fmem_map_virtual_area(MT_DEVICE_CACHED);
+ if (IS_ERR_OR_NULL(v)) {
+ ret = PTR_ERR(v);
+ goto out;
+ }
tmem_enable(true);
- else
+ } else {
tmem_disable();
+ fmem_unmap_virtual_area();
+ }
out_set:
fmem_state = new_state;
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index c44c245..794775a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -23,31 +23,6 @@
Say Y if your user-space is new enough.
-config THERMAL_PM8901
- tristate "Qualcomm PM8901 Temperature Alarm"
- depends on PMIC8901
- depends on THERMAL
- default n
- help
- This enables a thermal Sysfs driver for the PMIC 8901 device. It
- shows up in Sysfs as a thermal zone with multiple trip points.
- Enabling the thermal zone device via the mode file results in
- shifting over temperature shutdown control of the PMIC from hardware
- to software.
-
-config THERMAL_PM8058
- tristate "Qualcomm PM8058 Temperature Alarm"
- depends on PMIC8058
- depends on THERMAL
- depends on SENSORS_MSM_ADC
- default n
- help
- This enables a thermal Sysfs driver for the PMIC 8058 device. It
- shows up in Sysfs as a thermal zone with multiple trip points.
- Enabling the thermal zone device via the mode file results in
- shifting over temperature shutdown control of the PMIC from hardware
- to software.
-
config THERMAL_MSM_POPMEM
tristate "Qualcomm MSM POP memory temperature sensor"
depends on THERMAL
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index c5d792c..31b5c3f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,8 +3,6 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
-obj-$(CONFIG_THERMAL_PM8901) += pmic8901-tm.o
-obj-$(CONFIG_THERMAL_PM8058) += pmic8058-tm.o
obj-$(CONFIG_THERMAL_MSM_POPMEM) += msm_popmem-tm.o
obj-$(CONFIG_THERMAL_TSENS) += msm_tsens.o
obj-$(CONFIG_THERMAL_TSENS8960) += msm8960_tsens.o
diff --git a/drivers/thermal/pmic8058-tm.c b/drivers/thermal/pmic8058-tm.c
deleted file mode 100644
index 2589494..0000000
--- a/drivers/thermal/pmic8058-tm.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-/*
- * Qualcomm PMIC8058 Thermal Manager driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/thermal.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/completion.h>
-
-#include <linux/msm_adc.h>
-
-/* PMIC8058 TEMP_ALRM registers */
-#define SSBI_REG_TEMP_ALRM_CTRL 0x1B
-#define SSBI_REG_TEMP_ALRM_PWM 0x9B
-#define SSBI_REG_TEMP_ALRM_TEST1 0x7A
-#define SSBI_REG_TEMP_ALRM_TEST2 0xAB
-
-/* TEMP_ALRM_CTRL */
-#define PM8058_TEMP_ST3_SD 0x80
-#define PM8058_TEMP_ST2_SD 0x40
-#define PM8058_TEMP_STATUS_MASK 0x30
-#define PM8058_TEMP_STATUS_SHIFT 4
-#define PM8058_TEMP_THRESH_MASK 0x0C
-#define PM8058_TEMP_THRESH_SHIFT 2
-#define PM8058_TEMP_OVRD_ST3 0x02
-#define PM8058_TEMP_OVRD_ST2 0x01
-#define PM8058_TEMP_OVRD_MASK 0x03
-
-#define PM8058_TEMP_STAGE_STEP 20000 /* Stage step: 20 C */
-#define PM8058_TEMP_STAGE_HYSTERESIS 2000
-
-#define PM8058_TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */
-#define PM8058_TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
-
-/* TEMP_ALRM_PWM */
-#define PM8058_TEMP_PWM_EN_MASK 0xC0
-#define PM8058_TEMP_PWM_EN_SHIFT 6
-#define PM8058_TEMP_PWM_PER_PRE_MASK 0x38
-#define PM8058_TEMP_PWM_PER_PRE_SHIFT 3
-#define PM8058_TEMP_PWM_PER_DIV_MASK 0x07
-#define PM8058_TEMP_PWM_PER_DIV_SHIFT 0
-
-/* Trips: from critical to less critical */
-#define PM8058_TRIP_STAGE3 0
-#define PM8058_TRIP_STAGE2 1
-#define PM8058_TRIP_STAGE1 2
-#define PM8058_TRIP_NUM 3
-
-#define PM8058_TEMP_ADC_CH CHANNEL_ADC_DIE_TEMP
-
-struct pm8058_tm_device {
- struct pm8058_chip *pm_chip;
- struct thermal_zone_device *tz_dev;
- unsigned long temp;
- enum thermal_device_mode mode;
- unsigned int thresh;
- unsigned int stage;
- unsigned int irq;
- void *adc_handle;
-};
-
-enum pmic_thermal_override_mode {
- SOFTWARE_OVERRIDE_DISABLED = 0,
- SOFTWARE_OVERRIDE_ENABLED,
-};
-
-static inline int pm8058_tm_read_ctrl(struct pm8058_chip *chip, u8 *reg)
-{
- int rc;
-
- rc = pm8058_read(chip, SSBI_REG_TEMP_ALRM_CTRL, reg, 1);
- if (rc)
- pr_err("%s: pm8058_read FAIL: rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static inline int pm8058_tm_write_ctrl(struct pm8058_chip *chip, u8 reg)
-{
- int rc;
-
- rc = pm8058_write(chip, SSBI_REG_TEMP_ALRM_CTRL, ®, 1);
- if (rc)
- pr_err("%s: pm8058_write FAIL: rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static inline int pm8058_tm_write_pwm(struct pm8058_chip *chip, u8 reg)
-{
- int rc;
-
- rc = pm8058_write(chip, SSBI_REG_TEMP_ALRM_PWM, ®, 1);
- if (rc)
- pr_err("%s: pm8058_write FAIL: rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static inline int
-pm8058_tm_shutdown_override(struct pm8058_chip *chip,
- enum pmic_thermal_override_mode mode)
-{
- int rc;
- u8 reg;
-
- rc = pm8058_tm_read_ctrl(chip, ®);
- if (rc < 0)
- return rc;
-
- reg &= ~(PM8058_TEMP_OVRD_MASK | PM8058_TEMP_STATUS_MASK);
- if (mode == SOFTWARE_OVERRIDE_ENABLED)
- reg |= (PM8058_TEMP_OVRD_ST3 | PM8058_TEMP_OVRD_ST2) &
- PM8058_TEMP_OVRD_MASK;
-
- rc = pm8058_tm_write_ctrl(chip, reg);
-
- return rc;
-}
-
-static int pm8058_tz_get_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- struct pm8058_tm_device *tm = thermal->devdata;
- DECLARE_COMPLETION_ONSTACK(wait);
- struct adc_chan_result adc_result = {
- .physical = 0lu,
- };
- int rc;
-
- if (!tm || !temp)
- return -EINVAL;
-
- *temp = tm->temp;
-
- rc = adc_channel_request_conv(tm->adc_handle, &wait);
- if (rc < 0) {
- pr_err("%s: adc_channel_request_conv() failed, rc = %d\n",
- __func__, rc);
- return rc;
- }
-
- wait_for_completion(&wait);
-
- rc = adc_channel_read_result(tm->adc_handle, &adc_result);
- if (rc < 0) {
- pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
- __func__, rc);
- return rc;
- }
-
- *temp = adc_result.physical;
- tm->temp = adc_result.physical;
-
- return 0;
-}
-
-static int pm8058_tz_get_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode *mode)
-{
- struct pm8058_tm_device *tm = thermal->devdata;
-
- if (!tm || !mode)
- return -EINVAL;
-
- *mode = tm->mode;
-
- return 0;
-}
-
-static int pm8058_tz_set_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode mode)
-{
- struct pm8058_tm_device *tm = thermal->devdata;
-
- if (!tm)
- return -EINVAL;
-
- if (mode != tm->mode) {
- if (mode == THERMAL_DEVICE_ENABLED)
- pm8058_tm_shutdown_override(tm->pm_chip,
- SOFTWARE_OVERRIDE_ENABLED);
- else
- pm8058_tm_shutdown_override(tm->pm_chip,
- SOFTWARE_OVERRIDE_DISABLED);
- }
- tm->mode = mode;
-
- return 0;
-}
-
-static int pm8058_tz_get_trip_type(struct thermal_zone_device *thermal,
- int trip, enum thermal_trip_type *type)
-{
- struct pm8058_tm_device *tm = thermal->devdata;
-
- if (!tm || trip < 0 || !type)
- return -EINVAL;
-
- switch (trip) {
- case PM8058_TRIP_STAGE3:
- *type = THERMAL_TRIP_CRITICAL;
- break;
- case PM8058_TRIP_STAGE2:
- *type = THERMAL_TRIP_HOT;
- break;
- case PM8058_TRIP_STAGE1:
- *type = THERMAL_TRIP_HOT;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int pm8058_tz_get_trip_temp(struct thermal_zone_device *thermal,
- int trip, unsigned long *temp)
-{
- struct pm8058_tm_device *tm = thermal->devdata;
- int thresh_temp;
-
- if (!tm || trip < 0 || !temp)
- return -EINVAL;
-
- thresh_temp = tm->thresh * PM8058_TEMP_THRESH_STEP +
- PM8058_TEMP_THRESH_MIN;
-
- switch (trip) {
- case PM8058_TRIP_STAGE3:
- thresh_temp += 2 * PM8058_TEMP_STAGE_STEP;
- break;
- case PM8058_TRIP_STAGE2:
- thresh_temp += PM8058_TEMP_STAGE_STEP;
- break;
- case PM8058_TRIP_STAGE1:
- break;
- default:
- return -EINVAL;
- }
-
- *temp = thresh_temp;
-
- return 0;
-}
-
-static int pm8058_tz_get_crit_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- struct pm8058_tm_device *tm = thermal->devdata;
-
- if (!tm || !temp)
- return -EINVAL;
-
- *temp = tm->thresh * PM8058_TEMP_THRESH_STEP + PM8058_TEMP_THRESH_MIN +
- 2 * PM8058_TEMP_STAGE_STEP;
-
- return 0;
-}
-
-static struct thermal_zone_device_ops pm8058_thermal_zone_ops = {
- .get_temp = pm8058_tz_get_temp,
- .get_mode = pm8058_tz_get_mode,
- .set_mode = pm8058_tz_set_mode,
- .get_trip_type = pm8058_tz_get_trip_type,
- .get_trip_temp = pm8058_tz_get_trip_temp,
- .get_crit_temp = pm8058_tz_get_crit_temp,
-};
-
-static irqreturn_t pm8058_tm_isr(int irq, void *data)
-{
- struct pm8058_tm_device *tm = data;
- int rc;
- u8 reg;
-
- rc = pm8058_tm_read_ctrl(tm->pm_chip, ®);
- if (rc < 0)
- goto isr_handled;
-
- tm->stage = (reg & PM8058_TEMP_STATUS_MASK) >> PM8058_TEMP_STATUS_SHIFT;
- tm->thresh = (reg & PM8058_TEMP_THRESH_MASK) >>
- PM8058_TEMP_THRESH_SHIFT;
-
- if (reg & (PM8058_TEMP_ST2_SD | PM8058_TEMP_ST3_SD)) {
- reg &= ~(PM8058_TEMP_ST2_SD | PM8058_TEMP_ST3_SD |
- PM8058_TEMP_STATUS_MASK);
- pm8058_tm_write_ctrl(tm->pm_chip, reg);
- }
-
- thermal_zone_device_update(tm->tz_dev);
-
- /* Notify user space */
- if (tm->mode == THERMAL_DEVICE_ENABLED)
- kobject_uevent(&tm->tz_dev->device.kobj, KOBJ_CHANGE);
-
-isr_handled:
- return IRQ_HANDLED;
-}
-
-static int pm8058_tm_init_reg(struct pm8058_tm_device *tm)
-{
- int rc;
- u8 reg;
-
- rc = pm8058_tm_read_ctrl(tm->pm_chip, ®);
- if (rc < 0)
- return rc;
-
- tm->stage = (reg & PM8058_TEMP_STATUS_MASK) >> PM8058_TEMP_STATUS_SHIFT;
- tm->temp = 0;
-
- /* Use temperature threshold set 0: (105, 125, 145) */
- tm->thresh = 0;
- reg = (tm->thresh << PM8058_TEMP_THRESH_SHIFT) &
- PM8058_TEMP_THRESH_MASK;
- rc = pm8058_tm_write_ctrl(tm->pm_chip, reg);
- if (rc < 0)
- return rc;
-
- /*
- * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
- * helps cut down on the number of unnecessary interrupts fired when
- * changing between thermal stages. Also, Enable the over temperature
- * PWM whenever the PMIC is enabled.
- */
- reg = 1 << PM8058_TEMP_PWM_EN_SHIFT |
- 3 << PM8058_TEMP_PWM_PER_PRE_SHIFT |
- 3 << PM8058_TEMP_PWM_PER_DIV_SHIFT;
-
- rc = pm8058_tm_write_pwm(tm->pm_chip, reg);
-
- return rc;
-}
-
-static int __devinit pmic8058_tm_probe(struct platform_device *pdev)
-{
- struct pm8058_tm_device *tmdev;
- struct pm8058_chip *pm_chip;
- unsigned int irq;
- int rc;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("%s: no driver data passed in.\n", __func__);
- return -EFAULT;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (!irq) {
- pr_err("%s: no IRQ passed in.\n", __func__);
- return -EFAULT;
- }
-
- tmdev = kzalloc(sizeof *tmdev, GFP_KERNEL);
- if (tmdev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
- return -ENOMEM;
- }
-
- rc = adc_channel_open(PM8058_TEMP_ADC_CH, &(tmdev->adc_handle));
- if (rc < 0) {
- pr_err("%s: adc_channel_open() failed.\n", __func__);
- kfree(tmdev);
- return rc;
- }
-
- tmdev->pm_chip = pm_chip;
- tmdev->tz_dev = thermal_zone_device_register("pm8058_tz",
- PM8058_TRIP_NUM, tmdev,
- &pm8058_thermal_zone_ops,
- 0, 0, 0, 0);
- if (tmdev->tz_dev == NULL) {
- pr_err("%s: thermal_zone_device_register() failed.\n",
- __func__);
- adc_channel_close(tmdev->adc_handle);
- kfree(tmdev);
- return -ENODEV;
- }
-
- rc = pm8058_tm_init_reg(tmdev);
- pm8058_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
- if (rc < 0) {
- thermal_zone_device_unregister(tmdev->tz_dev);
- adc_channel_close(tmdev->adc_handle);
- kfree(tmdev);
- return rc;
- }
-
- /* start in HW control, switch to SW control when user changes mode */
- tmdev->mode = THERMAL_DEVICE_DISABLED;
- thermal_zone_device_update(tmdev->tz_dev);
-
- platform_set_drvdata(pdev, tmdev);
-
- rc = request_threaded_irq(irq, NULL, pm8058_tm_isr,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
- "pm8058-tm-irq", tmdev);
- if (rc < 0) {
- pr_err("%s: request_irq(%d) FAIL: %d\n", __func__, irq, rc);
- thermal_zone_device_unregister(tmdev->tz_dev);
- platform_set_drvdata(pdev, tmdev->pm_chip);
- adc_channel_close(tmdev->adc_handle);
- kfree(tmdev);
- return rc;
- }
- tmdev->irq = irq;
-
- pr_notice("%s: OK\n", __func__);
- return 0;
-}
-
-static int __devexit pmic8058_tm_remove(struct platform_device *pdev)
-{
- struct pm8058_tm_device *tmdev = platform_get_drvdata(pdev);
-
- thermal_zone_device_unregister(tmdev->tz_dev);
- platform_set_drvdata(pdev, tmdev->pm_chip);
- pm8058_tm_shutdown_override(tmdev->pm_chip, THERMAL_DEVICE_DISABLED);
- adc_channel_close(tmdev->adc_handle);
- free_irq(tmdev->irq, tmdev);
- kfree(tmdev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_tm_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pm8058_tm_device *tm = platform_get_drvdata(pdev);
-
- /* Clear override bits in suspend to allow hardware control */
- pm8058_tm_shutdown_override(tm->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
-
- return 0;
-}
-
-static int pmic8058_tm_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pm8058_tm_device *tm = platform_get_drvdata(pdev);
-
- /* Override hardware actions so software can control */
- if (tm->mode == THERMAL_DEVICE_ENABLED)
- pm8058_tm_shutdown_override(tm->pm_chip,
- SOFTWARE_OVERRIDE_ENABLED);
-
- return 0;
-}
-
-static const struct dev_pm_ops pmic8058_tm_pm_ops = {
- .suspend = pmic8058_tm_suspend,
- .resume = pmic8058_tm_resume,
-};
-
-#define PM8058_TM_PM_OPS (&pmic8058_tm_pm_ops)
-#else
-#define PM8058_TM_PM_OPS NULL
-#endif
-
-static struct platform_driver pmic8058_tm_driver = {
- .probe = pmic8058_tm_probe,
- .remove = __devexit_p(pmic8058_tm_remove),
- .driver = {
- .name = "pm8058-tm",
- .owner = THIS_MODULE,
- .pm = PM8058_TM_PM_OPS,
- },
-};
-
-static int __init pm8058_tm_init(void)
-{
- return platform_driver_register(&pmic8058_tm_driver);
-}
-
-static void __exit pm8058_tm_exit(void)
-{
- platform_driver_unregister(&pmic8058_tm_driver);
-}
-
-module_init(pm8058_tm_init);
-module_exit(pm8058_tm_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 Thermal Manager driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058-tm");
diff --git a/drivers/thermal/pmic8901-tm.c b/drivers/thermal/pmic8901-tm.c
deleted file mode 100644
index 0ff5788..0000000
--- a/drivers/thermal/pmic8901-tm.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-/*
- * Qualcomm PMIC8901 Thermal Manager driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/thermal.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/mfd/pmic8901.h>
-
-/* PMIC8901 TEMP_ALRM registers */
-#define SSBI_REG_TEMP_ALRM_CTRL 0x23
-#define SSBI_REG_TEMP_ALRM_PWM 0x24
-
-/* TEMP_ALRM_CTRL */
-#define PM8901_TEMP_ST3_SD 0x80
-#define PM8901_TEMP_ST2_SD 0x40
-#define PM8901_TEMP_STATUS_MASK 0x30
-#define PM8901_TEMP_STATUS_SHIFT 4
-#define PM8901_TEMP_THRESH_MASK 0x0C
-#define PM8901_TEMP_THRESH_SHIFT 2
-#define PM8901_TEMP_OVRD_ST3 0x02
-#define PM8901_TEMP_OVRD_ST2 0x01
-#define PM8901_TEMP_OVRD_MASK 0x03
-
-#define PM8901_TEMP_STAGE_STEP 20000 /* Stage step: 20 C */
-#define PM8901_TEMP_STAGE_HYSTERESIS 2000
-
-#define PM8901_TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */
-#define PM8901_TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
-
-/* TEMP_ALRM_PWM */
-#define PM8901_TEMP_PWM_EN_MASK 0xC0
-#define PM8901_TEMP_PWM_EN_SHIFT 6
-#define PM8901_TEMP_PWM_PER_PRE_MASK 0x38
-#define PM8901_TEMP_PWM_PER_PRE_SHIFT 3
-#define PM8901_TEMP_PWM_PER_DIV_MASK 0x07
-#define PM8901_TEMP_PWM_PER_DIV_SHIFT 0
-
-/* Trips: from critical to less critical */
-#define PM8901_TRIP_STAGE3 0
-#define PM8901_TRIP_STAGE2 1
-#define PM8901_TRIP_STAGE1 2
-#define PM8901_TRIP_NUM 3
-
-/* Used because there is no means to read the die temperature */
-#define DEFAULT_NO_ADC_TEMP 37000
-
-struct pm8901_tm_device {
- struct pm8901_chip *pm_chip;
- struct thermal_zone_device *tz_dev;
- unsigned long temp;
- enum thermal_device_mode mode;
- unsigned int thresh;
- unsigned int stage;
- unsigned int irq;
- unsigned int hi_irq;
-};
-
-enum pmic_thermal_override_mode {
- SOFTWARE_OVERRIDE_DISABLED = 0,
- SOFTWARE_OVERRIDE_ENABLED,
-};
-
-static inline int pm8901_tm_read_ctrl(struct pm8901_chip *chip, u8 *reg)
-{
- int rc;
-
- rc = pm8901_read(chip, SSBI_REG_TEMP_ALRM_CTRL, reg, 1);
- if (rc)
- pr_err("%s: pm8901_read FAIL: rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static inline int pm8901_tm_write_ctrl(struct pm8901_chip *chip, u8 reg)
-{
- int rc;
-
- rc = pm8901_write(chip, SSBI_REG_TEMP_ALRM_CTRL, ®, 1);
- if (rc)
- pr_err("%s: pm8901_write FAIL: rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static inline int pm8901_tm_read_pwm(struct pm8901_chip *chip, u8 *reg)
-{
- int rc;
-
- rc = pm8901_read(chip, SSBI_REG_TEMP_ALRM_PWM, reg, 1);
- if (rc)
- pr_err("%s: pm8901_read FAIL: rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static inline int pm8901_tm_write_pwm(struct pm8901_chip *chip, u8 reg)
-{
- int rc;
-
- rc = pm8901_write(chip, SSBI_REG_TEMP_ALRM_PWM, ®, 1);
- if (rc)
- pr_err("%s: pm8901_write FAIL: rc=%d\n", __func__, rc);
-
- return rc;
-}
-
-static inline int
-pm8901_tm_shutdown_override(struct pm8901_chip *chip,
- enum pmic_thermal_override_mode mode)
-{
- int rc;
- u8 reg;
-
- rc = pm8901_tm_read_ctrl(chip, ®);
- if (rc < 0)
- return rc;
-
- reg &= ~(PM8901_TEMP_OVRD_MASK | PM8901_TEMP_STATUS_MASK);
- if (mode == SOFTWARE_OVERRIDE_ENABLED)
- reg |= (PM8901_TEMP_OVRD_ST3 | PM8901_TEMP_OVRD_ST2) &
- PM8901_TEMP_OVRD_MASK;
-
- rc = pm8901_tm_write_ctrl(chip, reg);
-
- return rc;
-}
-
-/*
- * This function initializes the internal temperature value based on only the
- * current thermal stage and threshold.
- */
-static int pm8901_tm_init_temp(struct pm8901_tm_device *tm)
-{
- int rc;
- u8 reg;
-
- rc = pm8901_tm_read_ctrl(tm->pm_chip, ®);
- if (rc < 0)
- return rc;
-
- tm->stage = (reg & PM8901_TEMP_STATUS_MASK) >> PM8901_TEMP_STATUS_SHIFT;
- tm->thresh = (reg & PM8901_TEMP_THRESH_MASK) >>
- PM8901_TEMP_THRESH_SHIFT;
-
- if (tm->stage) {
- tm->temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
- (tm->stage - 1) * PM8901_TEMP_STAGE_STEP +
- PM8901_TEMP_THRESH_MIN;
- } else
- tm->temp = DEFAULT_NO_ADC_TEMP;
-
- return 0;
-}
-
-/*
- * This function updates the internal temperature value based on the
- * current thermal stage and threshold as well as the previous stage
- */
-static int pm8901_tm_update_temp(struct pm8901_tm_device *tm)
-{
- unsigned int stage;
- int rc;
- u8 reg;
-
- rc = pm8901_tm_read_ctrl(tm->pm_chip, ®);
- if (rc < 0)
- return rc;
-
- stage = (reg & PM8901_TEMP_STATUS_MASK) >> PM8901_TEMP_STATUS_SHIFT;
- tm->thresh = (reg & PM8901_TEMP_THRESH_MASK) >>
- PM8901_TEMP_THRESH_SHIFT;
-
- if (stage > tm->stage) {
- /* increasing stage, use lower bound */
- tm->temp = (stage-1) * PM8901_TEMP_STAGE_STEP +
- tm->thresh * PM8901_TEMP_THRESH_STEP +
- PM8901_TEMP_STAGE_HYSTERESIS +
- PM8901_TEMP_THRESH_MIN;
- } else if (stage < tm->stage) {
- /* decreasing stage, use upper bound */
- tm->temp = stage * PM8901_TEMP_STAGE_STEP +
- tm->thresh * PM8901_TEMP_THRESH_STEP -
- PM8901_TEMP_STAGE_HYSTERESIS +
- PM8901_TEMP_THRESH_MIN;
- }
-
- tm->stage = stage;
-
- return 0;
-}
-
-static int pm8901_tz_get_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- struct pm8901_tm_device *tm = thermal->devdata;
- int rc;
-
- if (!tm || !temp)
- return -EINVAL;
-
- rc = pm8901_tm_update_temp(tm);
- if (rc < 0)
- return rc;
-
- *temp = tm->temp;
-
- return 0;
-}
-
-static int pm8901_tz_get_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode *mode)
-{
- struct pm8901_tm_device *tm = thermal->devdata;
-
- if (!tm || !mode)
- return -EINVAL;
-
- *mode = tm->mode;
-
- return 0;
-}
-
-static int pm8901_tz_set_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode mode)
-{
- struct pm8901_tm_device *tm = thermal->devdata;
-
- if (!tm)
- return -EINVAL;
-
- if (mode != tm->mode) {
- pr_info("%s: mode: %d --> %d\n", __func__, tm->mode, mode);
-
- if (mode == THERMAL_DEVICE_ENABLED)
- pm8901_tm_shutdown_override(tm->pm_chip,
- SOFTWARE_OVERRIDE_ENABLED);
- else
- pm8901_tm_shutdown_override(tm->pm_chip,
- SOFTWARE_OVERRIDE_DISABLED);
- }
- tm->mode = mode;
-
- return 0;
-}
-
-static int pm8901_tz_get_trip_type(struct thermal_zone_device *thermal,
- int trip, enum thermal_trip_type *type)
-{
- struct pm8901_tm_device *tm = thermal->devdata;
-
- if (!tm || trip < 0 || !type)
- return -EINVAL;
-
- switch (trip) {
- case PM8901_TRIP_STAGE3:
- *type = THERMAL_TRIP_CRITICAL;
- break;
- case PM8901_TRIP_STAGE2:
- *type = THERMAL_TRIP_HOT;
- break;
- case PM8901_TRIP_STAGE1:
- *type = THERMAL_TRIP_HOT;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int pm8901_tz_get_trip_temp(struct thermal_zone_device *thermal,
- int trip, unsigned long *temp)
-{
- struct pm8901_tm_device *tm = thermal->devdata;
- int thresh_temp;
-
- if (!tm || trip < 0 || !temp)
- return -EINVAL;
-
- thresh_temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
- PM8901_TEMP_THRESH_MIN;
-
- switch (trip) {
- case PM8901_TRIP_STAGE3:
- thresh_temp += 2 * PM8901_TEMP_STAGE_STEP;
- break;
- case PM8901_TRIP_STAGE2:
- thresh_temp += PM8901_TEMP_STAGE_STEP;
- break;
- case PM8901_TRIP_STAGE1:
- break;
- default:
- return -EINVAL;
- }
- *temp = thresh_temp;
-
- return 0;
-}
-
-static int pm8901_tz_get_crit_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- struct pm8901_tm_device *tm = thermal->devdata;
-
- if (!tm || !temp)
- return -EINVAL;
-
- *temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
- PM8901_TEMP_THRESH_MIN + 2 * PM8901_TEMP_STAGE_STEP;
-
- return 0;
-}
-
-static struct thermal_zone_device_ops pm8901_thermal_zone_ops = {
- .get_temp = pm8901_tz_get_temp,
- .get_mode = pm8901_tz_get_mode,
- .set_mode = pm8901_tz_set_mode,
- .get_trip_type = pm8901_tz_get_trip_type,
- .get_trip_temp = pm8901_tz_get_trip_temp,
- .get_crit_temp = pm8901_tz_get_crit_temp,
-};
-
-static irqreturn_t pm8901_tm_isr(int irq, void *data)
-{
- struct pm8901_tm_device *tm = data;
- int rc;
- u8 reg;
-
- rc = pm8901_tm_update_temp(tm);
- if (rc < 0)
- goto isr_handled;
-
- rc = pm8901_tm_read_ctrl(tm->pm_chip, ®);
- if (rc < 0)
- goto isr_handled;
-
- pr_info("%s: Temp Alarm - stage=%u, threshold=%u, temp=%lu\n",
- __func__, tm->stage, tm->thresh, tm->temp);
-
- if (reg & (PM8901_TEMP_ST2_SD | PM8901_TEMP_ST3_SD)) {
- reg &= ~(PM8901_TEMP_ST2_SD | PM8901_TEMP_ST3_SD |
- PM8901_TEMP_STATUS_MASK);
-
- pm8901_tm_write_ctrl(tm->pm_chip, reg);
- }
-
- thermal_zone_device_update(tm->tz_dev);
-
- /* Notify user space */
- if (tm->mode == THERMAL_DEVICE_ENABLED)
- kobject_uevent(&tm->tz_dev->device.kobj, KOBJ_CHANGE);
-
-isr_handled:
- return IRQ_HANDLED;
-}
-
-static irqreturn_t pm8901_tm_isr1(int irq, void *data)
-{
- struct pm8901_tm_device *tm = data;
- irqreturn_t rc;
-
- disable_irq(tm->hi_irq);
- rc = pm8901_tm_isr(irq, data);
- enable_irq(tm->hi_irq);
-
- return rc;
-}
-
-static irqreturn_t pm8901_tm_isr2(int irq, void *data)
-{
- struct pm8901_tm_device *tm = data;
- irqreturn_t rc;
-
- disable_irq(tm->irq);
- rc = pm8901_tm_isr(irq, data);
- enable_irq(tm->irq);
-
- return rc;
-}
-
-static int pm8901_tm_init_reg(struct pm8901_tm_device *tm)
-{
- int rc;
- u8 reg;
-
- rc = pm8901_tm_init_temp(tm);
- if (rc < 0)
- return rc;
-
- /* Use temperature threshold set 0: (105, 125, 145) */
- tm->thresh = 0;
- reg = (tm->thresh << PM8901_TEMP_THRESH_SHIFT) &
- PM8901_TEMP_THRESH_MASK;
- rc = pm8901_tm_write_ctrl(tm->pm_chip, reg);
- if (rc < 0)
- return rc;
-
- /*
- * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
- * helps cut down on the number of unnecessary interrupts fired when
- * changing between thermal stages. Also, Enable the over temperature
- * PWM whenever the PMIC is enabled.
- */
- reg = 1 << PM8901_TEMP_PWM_EN_SHIFT |
- 3 << PM8901_TEMP_PWM_PER_PRE_SHIFT |
- 3 << PM8901_TEMP_PWM_PER_DIV_SHIFT;
-
- rc = pm8901_tm_write_pwm(tm->pm_chip, reg);
-
- return rc;
-}
-
-static int __devinit pmic8901_tm_probe(struct platform_device *pdev)
-{
- struct pm8901_tm_device *tmdev;
- struct pm8901_chip *pm_chip;
- unsigned int irq, hi_irq;
- int rc;
-
- pm_chip = dev_get_drvdata(pdev->dev.parent);
- if (pm_chip == NULL) {
- pr_err("%s: no driver data passed in.\n", __func__);
- return -EFAULT;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (!irq) {
- pr_err("%s: no IRQ passed in.\n", __func__);
- return -EFAULT;
- }
- hi_irq = platform_get_irq(pdev, 1);
- if (!hi_irq) {
- pr_err("%s: no HI IRQ passed in.\n", __func__);
- return -EFAULT;
- }
-
- tmdev = kzalloc(sizeof *tmdev, GFP_KERNEL);
- if (tmdev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
- return -ENOMEM;
- }
-
- tmdev->pm_chip = pm_chip;
- tmdev->tz_dev = thermal_zone_device_register("pm8901_tz",
- PM8901_TRIP_NUM, tmdev,
- &pm8901_thermal_zone_ops,
- 0, 0, 0, 0);
- if (tmdev->tz_dev == NULL) {
- pr_err("%s: thermal_zone_device_register() failed.\n",
- __func__);
- kfree(tmdev);
- return -ENODEV;
- }
-
- rc = pm8901_tm_init_reg(tmdev);
- pm8901_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
- if (rc < 0) {
- thermal_zone_device_unregister(tmdev->tz_dev);
- kfree(tmdev);
- return rc;
- }
-
- /* start in HW control, switch to SW control when user changes mode */
- tmdev->mode = THERMAL_DEVICE_DISABLED;
- thermal_zone_device_update(tmdev->tz_dev);
-
- platform_set_drvdata(pdev, tmdev);
-
- rc = request_threaded_irq(irq, pm8901_tm_isr1, NULL,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
- "pm8901-tm-irq", tmdev);
- if (rc < 0) {
- pr_err("%s: request_threaded_irq(%d) FAIL: %d\n",
- __func__, irq, rc);
-
- thermal_zone_device_unregister(tmdev->tz_dev);
- platform_set_drvdata(pdev, tmdev->pm_chip);
- kfree(tmdev);
- return -ENODEV;
- }
- tmdev->irq = irq;
-
- rc = request_threaded_irq(hi_irq, pm8901_tm_isr2, NULL,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
- "pm8901-tm-irq2", tmdev);
- if (rc < 0) {
- pr_err("%s: request_threaded_irq(%d) FAIL: %d\n",
- __func__, hi_irq, rc);
-
- free_irq(irq, tmdev);
- thermal_zone_device_unregister(tmdev->tz_dev);
- platform_set_drvdata(pdev, tmdev->pm_chip);
- kfree(tmdev);
- return -ENODEV;
- }
- tmdev->hi_irq = hi_irq;
-
- pr_notice("%s: OK\n", __func__);
- return 0;
-}
-
-static int __devexit pmic8901_tm_remove(struct platform_device *pdev)
-{
- struct pm8901_tm_device *tmdev = platform_get_drvdata(pdev);
-
- free_irq(tmdev->hi_irq, tmdev);
- free_irq(tmdev->irq, tmdev);
- thermal_zone_device_unregister(tmdev->tz_dev);
- platform_set_drvdata(pdev, tmdev->pm_chip);
- pm8901_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
- kfree(tmdev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int pmic8901_tm_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pm8901_tm_device *tm = platform_get_drvdata(pdev);
-
- pm8901_tm_shutdown_override(tm->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
-
- return 0;
-}
-
-static int pmic8901_tm_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pm8901_tm_device *tm = platform_get_drvdata(pdev);
-
- pm8901_tm_init_temp(tm);
-
- if (tm->mode == THERMAL_DEVICE_ENABLED)
- pm8901_tm_shutdown_override(tm->pm_chip,
- SOFTWARE_OVERRIDE_ENABLED);
-
- return 0;
-}
-
-static const struct dev_pm_ops pmic8901_tm_pm_ops = {
- .suspend = pmic8901_tm_suspend,
- .resume = pmic8901_tm_resume,
-};
-
-#define PM8901_TM_PM_OPS (&pmic8901_tm_pm_ops)
-#else
-#define PM8901_TM_PM_OPS NULL
-#endif
-
-static struct platform_driver pmic8901_tm_driver = {
- .probe = pmic8901_tm_probe,
- .remove = __devexit_p(pmic8901_tm_remove),
- .driver = {
- .name = "pm8901-tm",
- .owner = THIS_MODULE,
- .pm = PM8901_TM_PM_OPS,
- },
-};
-
-static int __init pm8901_tm_init(void)
-{
- return platform_driver_register(&pmic8901_tm_driver);
-}
-
-static void __exit pm8901_tm_exit(void)
-{
- platform_driver_unregister(&pmic8901_tm_driver);
-}
-
-module_init(pm8901_tm_init);
-module_exit(pm8901_tm_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8901 Thermal Manager driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8901-tm");
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 047df1a..9dc4044 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -2,6 +2,7 @@
* Gadget Driver for Android
*
* Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Author: Mike Lockwood <lockwood@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -60,7 +61,7 @@
#include "u_ctrl_hsic.c"
#include "u_data_hsic.c"
#include "f_serial.c"
-//#include "f_acm.c"
+#include "f_acm.c"
#include "f_adb.c"
#include "f_ccid.c"
#include "f_mtp.c"
@@ -476,6 +477,77 @@
.attributes = serial_function_attributes,
};
+/* ACM */
+static char acm_transports[32]; /*enabled ACM ports - "tty[,sdio]"*/
+static ssize_t acm_transports_store(
+ struct device *device, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ strlcpy(acm_transports, buff, sizeof(acm_transports));
+
+ return size;
+}
+
+static DEVICE_ATTR(acm_transports, S_IWUSR, NULL, acm_transports_store);
+static struct device_attribute *acm_function_attributes[] = {
+ &dev_attr_acm_transports, NULL };
+
+static void acm_function_cleanup(struct android_usb_function *f)
+{
+ gserial_cleanup();
+}
+
+static int acm_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ char *name;
+ char buf[32], *b;
+ int err = -1, i;
+ static int acm_initialized, ports;
+
+ if (acm_initialized)
+ goto bind_config;
+
+ acm_initialized = 1;
+ strlcpy(buf, acm_transports, sizeof(buf));
+ b = strim(buf);
+
+ while (b) {
+ name = strsep(&b, ",");
+
+ if (name) {
+ err = acm_init_port(ports, name);
+ if (err) {
+ pr_err("acm: Cannot open port '%s'", name);
+ goto out;
+ }
+ ports++;
+ }
+ }
+ err = acm_port_setup(c);
+ if (err) {
+ pr_err("acm: Cannot setup transports");
+ goto out;
+ }
+
+bind_config:
+ for (i = 0; i < ports; i++) {
+ err = acm_bind_config(c, i);
+ if (err) {
+ pr_err("acm: bind_config failed for port %d", i);
+ goto out;
+ }
+ }
+
+out:
+ return err;
+}
+static struct android_usb_function acm_function = {
+ .name = "acm",
+ .cleanup = acm_function_cleanup,
+ .bind_config = acm_function_bind_config,
+ .attributes = acm_function_attributes,
+};
/* ADB */
static int adb_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
@@ -525,79 +597,6 @@
.bind_config = ccid_function_bind_config,
};
-#if 0
-#define MAX_ACM_INSTANCES 4
-struct acm_function_config {
- int instances;
-};
-
-static int acm_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
-{
- f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
- if (!f->config)
- return -ENOMEM;
-
- return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES);
-}
-
-static void acm_function_cleanup(struct android_usb_function *f)
-{
- gserial_cleanup();
- kfree(f->config);
- f->config = NULL;
-}
-
-static int acm_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
-{
- int i;
- int ret = 0;
- struct acm_function_config *config = f->config;
-
- for (i = 0; i < config->instances; i++) {
- ret = acm_bind_config(c, i);
- if (ret) {
- pr_err("Could not bind acm%u config\n", i);
- break;
- }
- }
-
- return ret;
-}
-
-static ssize_t acm_instances_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct android_usb_function *f = dev_get_drvdata(dev);
- struct acm_function_config *config = f->config;
- return sprintf(buf, "%d\n", config->instances);
-}
-
-static ssize_t acm_instances_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct android_usb_function *f = dev_get_drvdata(dev);
- struct acm_function_config *config = f->config;
- int value;
-
- sscanf(buf, "%d", &value);
- if (value > MAX_ACM_INSTANCES)
- value = MAX_ACM_INSTANCES;
- config->instances = value;
- return size;
-}
-
-static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show, acm_instances_store);
-static struct device_attribute *acm_function_attributes[] = { &dev_attr_instances, NULL };
-
-static struct android_usb_function acm_function = {
- .name = "acm",
- .init = acm_function_init,
- .cleanup = acm_function_cleanup,
- .bind_config = acm_function_bind_config,
- .attributes = acm_function_attributes,
-};
-#endif
-
static int mtp_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
{
return mtp_setup();
@@ -969,7 +968,7 @@
&serial_function,
&adb_function,
&ccid_function,
-// &acm_function,
+ &acm_function,
&mtp_function,
&ptp_function,
&rndis_function,
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 6282389..703494a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1844,6 +1844,14 @@
}
mReq->req.status = -ESHUTDOWN;
+ if (mReq->map) {
+ dma_unmap_single(mEp->device, mReq->req.dma,
+ mReq->req.length,
+ mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mReq->req.dma = 0;
+ mReq->map = 0;
+ }
+
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 7299dff..69a36af 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/usb/android_composite.h>
+#include <mach/usb_gadget_xport.h>
#include "u_serial.h"
#include "gadget_chips.h"
@@ -86,12 +87,12 @@
#define ACM_CTRL_DCD (1 << 0)
};
-static unsigned int no_tty_ports;
-static unsigned int no_sdio_ports;
-static unsigned int no_smd_ports;
-static unsigned int nr_ports;
+static unsigned int no_acm_tty_ports;
+static unsigned int no_acm_sdio_ports;
+static unsigned int no_acm_smd_ports;
+static unsigned int nr_acm_ports;
-static struct port_info {
+static struct acm_port_info {
enum transport_type transport;
unsigned port_num;
unsigned client_port_num;
@@ -107,24 +108,25 @@
return container_of(p, struct f_acm, port);
}
-static int gport_setup(struct usb_configuration *c)
+static int acm_port_setup(struct usb_configuration *c)
{
int ret = 0;
- pr_debug("%s: no_tty_ports:%u no_sdio_ports: %u nr_ports:%u\n",
- __func__, no_tty_ports, no_sdio_ports, nr_ports);
+ pr_debug("%s: no_acm_tty_ports:%u no_acm_sdio_ports: %u nr_acm_ports:%u\n",
+ __func__, no_acm_tty_ports, no_acm_sdio_ports,
+ nr_acm_ports);
- if (no_tty_ports)
- ret = gserial_setup(c->cdev->gadget, no_tty_ports);
- if (no_sdio_ports)
- ret = gsdio_setup(c->cdev->gadget, no_sdio_ports);
- if (no_smd_ports)
- ret = gsmd_setup(c->cdev->gadget, no_smd_ports);
+ if (no_acm_tty_ports)
+ ret = gserial_setup(c->cdev->gadget, no_acm_tty_ports);
+ if (no_acm_sdio_ports)
+ ret = gsdio_setup(c->cdev->gadget, no_acm_sdio_ports);
+ if (no_acm_smd_ports)
+ ret = gsmd_setup(c->cdev->gadget, no_acm_smd_ports);
return ret;
}
-static int gport_connect(struct f_acm *acm)
+static int acm_port_connect(struct f_acm *acm)
{
unsigned port_num;
@@ -136,13 +138,13 @@
acm, &acm->port, acm->port_num, port_num);
switch (acm->transport) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
+ case USB_GADGET_XPORT_TTY:
gserial_connect(&acm->port, port_num);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
+ case USB_GADGET_XPORT_SDIO:
gsdio_connect(&acm->port, port_num);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
+ case USB_GADGET_XPORT_SMD:
gsmd_connect(&acm->port, port_num);
break;
default:
@@ -154,7 +156,7 @@
return 0;
}
-static int gport_disconnect(struct f_acm *acm)
+static int acm_port_disconnect(struct f_acm *acm)
{
unsigned port_num;
@@ -165,13 +167,13 @@
acm, &acm->port, acm->port_num, port_num);
switch (acm->transport) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
+ case USB_GADGET_XPORT_TTY:
gserial_disconnect(&acm->port);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
+ case USB_GADGET_XPORT_SDIO:
gsdio_disconnect(&acm->port, port_num);
break;
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
+ case USB_GADGET_XPORT_SMD:
gsmd_disconnect(&acm->port, port_num);
break;
default:
@@ -504,7 +506,7 @@
} else if (intf == acm->data_id) {
if (acm->port.in->driver_data) {
DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
- gport_disconnect(acm);
+ acm_port_disconnect(acm);
} else {
DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
}
@@ -512,7 +514,7 @@
acm->hs.in, acm->fs.in);
acm->port.out_desc = ep_choose(cdev->gadget,
acm->hs.out, acm->fs.out);
- gport_connect(acm);
+ acm_port_connect(acm);
} else
return -EINVAL;
@@ -526,7 +528,7 @@
struct usb_composite_dev *cdev = f->config->cdev;
DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
- gport_disconnect(acm);
+ acm_port_disconnect(acm);
usb_ep_disable(acm->notify);
acm->notify->driver_data = NULL;
}
@@ -888,116 +890,43 @@
return status;
}
-#ifdef CONFIG_USB_ANDROID_ACM
-#include <linux/platform_device.h>
-
-static struct acm_platform_data *acm_pdata;
-
-static int acm_probe(struct platform_device *pdev)
+/**
+ * acm_init_port - bind a acm_port to its transport
+ */
+static int acm_init_port(int port_num, const char *name)
{
- acm_pdata = pdev->dev.platform_data;
- return 0;
-}
+ enum transport_type transport;
-static struct platform_driver acm_platform_driver = {
- .driver = { .name = "acm", },
- .probe = acm_probe,
-};
+ if (port_num >= GSERIAL_NO_PORTS)
+ return -ENODEV;
-int acm1_function_bind_config(struct usb_configuration *c)
-{
- int ret = acm_bind_config(c, 0);
- if (ret == 0)
- gport_setup(c);
- return ret;
-}
+ transport = str_to_xport(name);
+ pr_debug("%s, port:%d, transport:%s\n", __func__,
+ port_num, xport_to_str(transport));
-int acm2_function_bind_config(struct usb_configuration *c)
-{
- int ret = acm_bind_config(c, 1);
+ gacm_ports[port_num].transport = transport;
+ gacm_ports[port_num].port_num = port_num;
- return ret;
-}
-
-static struct android_usb_function acm1_function = {
- .name = "acm1",
- .bind_config = acm1_function_bind_config,
-};
-
-static struct android_usb_function acm2_function = {
- .name = "acm2",
- .bind_config = acm2_function_bind_config,
-};
-
-static int facm_remove(struct platform_device *pdev)
-{
- gserial_cleanup();
-
- return 0;
-}
-
-static struct platform_driver usb_facm = {
- .remove = facm_remove,
- .driver = {
- .name = "usb_facm",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init facm_probe(struct platform_device *pdev)
-{
- struct usb_gadget_facm_pdata *pdata = pdev->dev.platform_data;
- int i;
-
- dev_dbg(&pdev->dev, "%s: probe\n", __func__);
-
- if (!pdata)
- goto probe_android_register;
-
- for (i = 0; i < GSERIAL_NO_PORTS; i++) {
- gacm_ports[i].transport = pdata->transport[i];
- gacm_ports[i].port_num = i;
-
- switch (gacm_ports[i].transport) {
- case USB_GADGET_FSERIAL_TRANSPORT_TTY:
- gacm_ports[i].client_port_num = no_tty_ports;
- no_tty_ports++;
- break;
- case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
- gacm_ports[i].client_port_num = no_sdio_ports;
- no_sdio_ports++;
- break;
- case USB_GADGET_FSERIAL_TRANSPORT_SMD:
- gacm_ports[i].client_port_num = no_smd_ports;
- no_smd_ports++;
- break;
- default:
- pr_err("%s: Un-supported transport transport: %u\n",
- __func__, gacm_ports[i].transport);
- return -ENODEV;
- }
-
- nr_ports++;
+ switch (transport) {
+ case USB_GADGET_XPORT_TTY:
+ gacm_ports[port_num].client_port_num = no_acm_tty_ports;
+ no_acm_tty_ports++;
+ break;
+ case USB_GADGET_XPORT_SDIO:
+ gacm_ports[port_num].client_port_num = no_acm_sdio_ports;
+ no_acm_sdio_ports++;
+ break;
+ case USB_GADGET_XPORT_SMD:
+ gacm_ports[port_num].client_port_num = no_acm_smd_ports;
+ no_acm_smd_ports++;
+ break;
+ default:
+ pr_err("%s: Un-supported transport transport: %u\n",
+ __func__, gacm_ports[port_num].transport);
+ return -ENODEV;
}
- pr_info("%s:gport:tty_ports:%u sdio_ports:%u "
- "smd_ports:%u nr_ports:%u\n",
- __func__, no_tty_ports, no_sdio_ports,
- no_smd_ports, nr_ports);
-
-probe_android_register:
- android_register_function(&acm1_function);
- android_register_function(&acm2_function);
+ nr_acm_ports++;
return 0;
}
-
-static int __init init(void)
-{
- printk(KERN_INFO "f_acm init\n");
-
- return platform_driver_probe(&usb_facm, facm_probe);
-}
-module_init(init);
-
-#endif /* CONFIG_USB_ANDROID_ACM */
diff --git a/drivers/usb/gadget/f_rmnet_smd_sdio.c b/drivers/usb/gadget/f_rmnet_smd_sdio.c
index f974b8a..e39125d 100644
--- a/drivers/usb/gadget/f_rmnet_smd_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_smd_sdio.c
@@ -1395,9 +1395,7 @@
struct device *device, struct device_attribute *attr,
const char *buf, size_t size)
{
- struct usb_function *f = dev_get_drvdata(device);
- struct rmnet_mux_dev *dev = container_of(f, struct rmnet_mux_dev,
- function);
+ struct rmnet_mux_dev *dev = rmux_dev;
int value;
enum transport_type given_xport;
enum transport_type t;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ec303b9..eb0b203 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -35,6 +35,7 @@
#include <mach/clk.h>
#include <mach/msm_iomap.h>
#include <mach/msm_xo.h>
+#include <linux/spinlock.h>
#define MSM_USB_BASE (hcd->regs)
@@ -51,6 +52,7 @@
atomic_t in_lpm;
struct msm_xo_voter *xo_handle;
struct wake_lock wlock;
+ int peripheral_status_irq;
};
static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
@@ -227,15 +229,18 @@
{
int rc = 0;
struct msm_hsic_host_platform_data *pdata;
+ static int gpio_status;
pdata = mehci->dev->platform_data;
- /*
- * In future versions, dedicated lines might be used for HSIC
- * strobe and data instead of gpios. Hence returning zero value.
- */
+
if (!pdata->strobe || !pdata->data)
return rc;
+ if (gpio_status == gpio_en)
+ return 0;
+
+ gpio_status = gpio_en;
+
if (!gpio_en)
goto free_gpio;
@@ -697,6 +702,18 @@
return ret;
}
+static irqreturn_t hsic_peripheral_status_change(int irq, void *dev_id)
+{
+ struct msm_hsic_hcd *mehci = dev_id;
+
+ pr_debug("%s: mechi:%p dev_id:%p\n", __func__, mehci, dev_id);
+
+ if (mehci)
+ msm_hsic_config_gpios(mehci, 0);
+
+ return IRQ_HANDLED;
+}
+
static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -740,6 +757,12 @@
mehci = hcd_to_hsic(hcd);
mehci->dev = &pdev->dev;
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ,
+ "peripheral_status_irq");
+ if (res)
+ mehci->peripheral_status_irq = res->start;
+
ret = msm_hsic_init_clocks(mehci, 1);
if (ret) {
dev_err(&pdev->dev, "unable to initialize clocks\n");
@@ -793,6 +816,18 @@
device_init_wakeup(&pdev->dev, 1);
wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
wake_lock(&mehci->wlock);
+
+ if (mehci->peripheral_status_irq) {
+ ret = request_threaded_irq(mehci->peripheral_status_irq,
+ NULL, hsic_peripheral_status_change,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_SHARED,
+ "hsic_peripheral_status", mehci);
+ if (ret)
+ dev_err(&pdev->dev, "%s:request_irq:%d failed:%d",
+ __func__, mehci->peripheral_status_irq, ret);
+ }
+
/*
* This pdev->dev is assigned parent of root-hub by USB core,
* hence, runtime framework automatically calls this driver's
@@ -828,6 +863,9 @@
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
struct msm_hsic_host_platform_data *pdata;
+ if (mehci->peripheral_status_irq)
+ free_irq(mehci->peripheral_status_irq, mehci);
+
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 00b2ec1..88a5993 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -31,6 +31,7 @@
struct usb_anchor submitted;
__u8 in_epAddr;
__u8 out_epAddr;
+ int err;
struct kref kref;
struct diag_bridge_ops *ops;
struct platform_device *pdev;
@@ -47,6 +48,7 @@
}
dev->ops = ops;
+ dev->err = 0;
return 0;
}
@@ -72,13 +74,19 @@
dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
urb->status, urb->actual_length);
+ if (urb->status == -EPROTO) {
+ /* save error so that subsequent read/write returns ESHUTDOWN */
+ dev->err = urb->status;
+ return;
+ }
+
cbs->read_complete_cb(cbs->ctxt,
urb->transfer_buffer,
urb->transfer_buffer_length,
urb->status < 0 ? urb->status : urb->actual_length);
}
-int diag_bridge_read(char *data, size_t size)
+int diag_bridge_read(char *data, int size)
{
struct urb *urb = NULL;
unsigned int pipe;
@@ -97,6 +105,10 @@
return -ENODEV;
}
+ /* if there was a previous unrecoverable error, just quit */
+ if (dev->err)
+ return -ESHUTDOWN;
+
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_err(&dev->udev->dev, "unable to allocate urb\n");
@@ -129,13 +141,19 @@
dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ if (urb->status == -EPROTO) {
+ /* save error so that subsequent read/write returns ESHUTDOWN */
+ dev->err = urb->status;
+ return;
+ }
+
cbs->write_complete_cb(cbs->ctxt,
urb->transfer_buffer,
urb->transfer_buffer_length,
urb->status < 0 ? urb->status : urb->actual_length);
}
-int diag_bridge_write(char *data, size_t size)
+int diag_bridge_write(char *data, int size)
{
struct urb *urb = NULL;
unsigned int pipe;
@@ -154,6 +172,10 @@
return -ENODEV;
}
+ /* if there was a previous unrecoverable error, just quit */
+ if (dev->err)
+ return -ESHUTDOWN;
+
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
err("unable to allocate urb");
@@ -271,7 +293,7 @@
#define VALID_INTERFACE_NUM 0
static const struct usb_device_id diag_bridge_ids[] = {
- { USB_DEVICE(0x5c6, 0x9001),
+ { USB_DEVICE(0x5c6, 0x9048),
.driver_info = VALID_INTERFACE_NUM, },
{} /* terminating entry */
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 6fe5b1d..89b8e5a 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -24,7 +24,7 @@
#define MAX_RX_URBS 50
#define RMNET_RX_BUFSIZE 2048
-#define STOP_SUBMIT_URB_LIMIT 400
+#define STOP_SUBMIT_URB_LIMIT 500
#define FLOW_CTRL_EN_THRESHOLD 500
#define FLOW_CTRL_DISABLE 300
#define FLOW_CTRL_SUPPORT 1
@@ -157,12 +157,9 @@
}
spin_lock_irqsave(&dev->rx_done.lock, flags);
- if (dev->rx_done.qlen > stop_submit_urb_limit && rx_throttled(brdg)) {
- spin_unlock_irqrestore(&dev->rx_done.lock, flags);
- return;
- }
-
while (!list_empty(&dev->rx_idle)) {
+ if (dev->rx_done.qlen > stop_submit_urb_limit)
+ break;
rx_idle = list_first_entry(&dev->rx_idle, struct urb, urb_list);
list_del(&rx_idle->urb_list);
@@ -448,6 +445,8 @@
return -ENODEV;
brdg = dev->brdg;
+ if (!brdg)
+ return -ENODEV;
dev_dbg(&dev->udev->dev, "%s: write (%d bytes)\n", __func__, skb->len);
@@ -754,6 +753,9 @@
static void data_bridge_debugfs_exit(void) { }
#endif
+#define DUN_IFACE_NUM 3
+#define TETHERED_RMNET_IFACE_NUM 4
+
static int __devinit
bridge_probe(struct usb_interface *iface, const struct usb_device_id *id)
{
@@ -872,7 +874,7 @@
}
static const struct usb_device_id bridge_ids[] = {
- { USB_DEVICE(0x5c6, 0x9001) },
+ { USB_DEVICE(0x5c6, 0x9048) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index dc3ff26..d756dd8 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -61,6 +61,7 @@
#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
+static DECLARE_COMPLETION(pmic_vbus_init);
static struct msm_otg *the_msm_otg;
static bool debug_aca_enabled;
@@ -86,7 +87,9 @@
static struct regulator *hsusb_3p3;
static struct regulator *hsusb_1p8;
static struct regulator *hsusb_vddcx;
+static struct regulator *vbus_otg;
+static bool aca_id_turned_on;
static inline bool aca_enabled(void)
{
#ifdef CONFIG_USB_MSM_ACA
@@ -527,6 +530,7 @@
return ret;
}
+ aca_id_turned_on = false;
ret = msm_otg_link_reset(motg);
if (ret) {
dev_err(otg->dev, "link reset failed\n");
@@ -541,17 +545,19 @@
clk_disable(motg->clk);
- val = readl_relaxed(USB_OTGSC);
- if (pdata->mode == USB_OTG) {
- ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
- val |= OTGSC_IDIE | OTGSC_BSVIE;
- } else if (pdata->mode == USB_PERIPHERAL) {
- ulpi_val = ULPI_INT_SESS_VALID;
- val |= OTGSC_BSVIE;
+ if (pdata->otg_control == OTG_PHY_CONTROL) {
+ val = readl_relaxed(USB_OTGSC);
+ if (pdata->mode == USB_OTG) {
+ ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
+ val |= OTGSC_IDIE | OTGSC_BSVIE;
+ } else if (pdata->mode == USB_PERIPHERAL) {
+ ulpi_val = ULPI_INT_SESS_VALID;
+ val |= OTGSC_BSVIE;
+ }
+ writel_relaxed(val, USB_OTGSC);
+ ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
+ ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
}
- writel_relaxed(val, USB_OTGSC);
- ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
- ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
return 0;
}
@@ -588,16 +594,16 @@
struct usb_bus *bus = otg->host;
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
- bool session_active;
- u32 phy_ctrl_val = 0;
+ bool host_bus_suspend;
+ u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
+ u32 portsc;
if (atomic_read(&motg->in_lpm))
return 0;
disable_irq(motg->irq);
- session_active = (otg->host && !test_bit(ID, &motg->inputs)) ||
- test_bit(B_SESS_VLD, &motg->inputs);
+ host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
/*
* Chipidea 45-nm PHY suspend sequence:
*
@@ -626,23 +632,27 @@
* Turn off the OTG comparators, if depends on PMIC for
* VBUS and ID notifications.
*/
- if ((motg->caps & ALLOW_PHY_COMP_DISABLE) && !session_active) {
+ if ((motg->caps & ALLOW_PHY_COMP_DISABLE) && !host_bus_suspend) {
ulpi_write(otg, OTG_COMP_DISABLE,
ULPI_SET(ULPI_PWR_CLK_MNG_REG));
motg->lpm_flags |= PHY_OTG_COMP_DISABLED;
}
- /*
+ /* Set the PHCD bit, only if it is not set by the controller.
* PHY may take some time or even fail to enter into low power
* mode (LPM). Hence poll for 500 msec and reset the PHY and link
* in failure case.
*/
- writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
- while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
- if (readl(USB_PORTSC) & PORTSC_PHCD)
- break;
- udelay(1);
- cnt++;
+ portsc = readl_relaxed(USB_PORTSC);
+ if (!(portsc & PORTSC_PHCD)) {
+ writel_relaxed(portsc | PORTSC_PHCD,
+ USB_PORTSC);
+ while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+ if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
+ break;
+ udelay(1);
+ cnt++;
+ }
}
if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
@@ -659,9 +669,14 @@
* in USBCMD register. Assert STP (ULPI interface STOP signal) to
* block data communication from PHY.
*/
- writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
+ cmd_val = readl_relaxed(USB_USBCMD);
+ if (host_bus_suspend)
+ cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
+ else
+ cmd_val |= ULPI_STP_CTRL;
+ writel_relaxed(cmd_val, USB_USBCMD);
- if (motg->caps & ALLOW_PHY_RETENTION && !session_active) {
+ if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend) {
phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
if (motg->pdata->otg_control == OTG_PHY_CONTROL)
/* Enable PHY HV interrupts to wake MPM/Link */
@@ -690,7 +705,7 @@
dev_err(otg->dev, "%s failed to devote for "
"TCXO D0 buffer%d\n", __func__, ret);
- if (motg->caps & ALLOW_PHY_POWER_COLLAPSE && !session_active) {
+ if (motg->caps & ALLOW_PHY_POWER_COLLAPSE && !host_bus_suspend) {
msm_hsusb_ldo_enable(motg, 0);
motg->lpm_flags |= PHY_PWR_COLLAPSED;
}
@@ -813,11 +828,6 @@
atomic_set(&motg->in_lpm, 0);
- if (aca_enabled() && !irq_read_line(motg->pdata->pmic_id_irq)) {
- clear_bit(ID, &motg->inputs);
- schedule_work(&motg->sm_work);
- }
-
if (motg->async_int) {
motg->async_int = 0;
enable_irq(motg->irq);
@@ -943,6 +953,41 @@
return NOTIFY_OK;
}
+static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
+{
+ int ret;
+ static bool vbus_is_on;
+
+ if (vbus_is_on == on)
+ return;
+
+ if (motg->pdata->vbus_power) {
+ motg->pdata->vbus_power(on);
+ return;
+ }
+
+ if (!vbus_otg) {
+ pr_err("vbus_otg is NULL.");
+ return;
+ }
+
+ if (on) {
+ ret = regulator_enable(vbus_otg);
+ if (ret) {
+ pr_err("unable to enable vbus_otg\n");
+ return;
+ }
+ vbus_is_on = true;
+ } else {
+ ret = regulator_disable(vbus_otg);
+ if (ret) {
+ pr_err("unable to disable vbus_otg\n");
+ return;
+ }
+ vbus_is_on = false;
+ }
+}
+
static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
{
struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
@@ -957,13 +1002,20 @@
return -ENODEV;
}
+ if (!motg->pdata->vbus_power && host) {
+ vbus_otg = regulator_get(motg->otg.dev, "vbus_otg");
+ if (IS_ERR(vbus_otg)) {
+ pr_err("Unable to get vbus_otg\n");
+ return -ENODEV;
+ }
+ }
+
if (!host) {
if (otg->state == OTG_STATE_A_HOST) {
pm_runtime_get_sync(otg->dev);
usb_unregister_notify(&motg->usbdev_nb);
msm_otg_start_host(otg, 0);
- if (motg->pdata->vbus_power)
- motg->pdata->vbus_power(0);
+ msm_hsusb_vbus_power(motg, 0);
otg->host = NULL;
otg->state = OTG_STATE_UNDEFINED;
schedule_work(&motg->sm_work);
@@ -971,6 +1023,9 @@
otg->host = NULL;
}
+ if (vbus_otg)
+ regulator_put(vbus_otg);
+
return 0;
}
@@ -1159,6 +1214,7 @@
ulpi_write(otg, 0x10, 0x12);
/* Enable ACA ID detection */
ulpi_write(otg, 0x20, 0x85);
+ aca_id_turned_on = true;
break;
default:
break;
@@ -1606,24 +1662,26 @@
set_bit(ID, &motg->inputs);
clear_bit(B_SESS_VLD, &motg->inputs);
}
- } else {
- if (aca_enabled()) {
- if (irq_read_line(motg->pdata->pmic_id_irq))
- set_bit(ID, &motg->inputs);
- else
- clear_bit(ID, &motg->inputs);
-
- } else {
- if (otgsc & OTGSC_ID)
- set_bit(ID, &motg->inputs);
- else
- clear_bit(ID, &motg->inputs);
- }
-
+ } else if (pdata->otg_control == OTG_PHY_CONTROL) {
+ if (otgsc & OTGSC_ID)
+ set_bit(ID, &motg->inputs);
+ else
+ clear_bit(ID, &motg->inputs);
if (otgsc & OTGSC_BSV)
set_bit(B_SESS_VLD, &motg->inputs);
else
clear_bit(B_SESS_VLD, &motg->inputs);
+ } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+ if (irq_read_line(motg->pdata->pmic_id_irq))
+ set_bit(ID, &motg->inputs);
+ else
+ clear_bit(ID, &motg->inputs);
+
+ /*
+ * VBUS initial state is reported after PMIC
+ * driver initialization. Wait for it.
+ */
+ wait_for_completion(&pmic_vbus_init);
}
break;
case USB_HOST:
@@ -1670,8 +1728,8 @@
else if (test_bit(ID_A, &motg->inputs))
msm_otg_notify_charger(motg,
IDEV_ACA_CHG_MAX - IUNIT);
- else if (motg->pdata->vbus_power)
- motg->pdata->vbus_power(1);
+ else
+ msm_hsusb_vbus_power(motg, 1);
msm_otg_start_host(otg, 1);
/*
* Link can not generate PHY_ALT interrupt
@@ -1757,10 +1815,8 @@
if (test_bit(ID, &motg->inputs) &&
!test_bit(ID_A, &motg->inputs)) {
msm_otg_start_host(otg, 0);
- if (motg->pdata->vbus_power) {
- motg->pdata->vbus_power(0);
- msleep(100); /* TA_WAIT_VFALL */
- }
+ msm_hsusb_vbus_power(motg, 0);
+ msleep(100); /* TA_WAIT_VFALL */
/*
* Exit point of host mode.
*
@@ -1782,14 +1838,12 @@
otg->state = OTG_STATE_B_IDLE;
schedule_work(w);
} else if (test_bit(ID_A, &motg->inputs)) {
- if (motg->pdata->vbus_power)
- motg->pdata->vbus_power(0);
+ msm_hsusb_vbus_power(motg, 0);
msm_otg_notify_charger(motg,
IDEV_ACA_CHG_MAX - motg->mA_port);
} else if (!test_bit(ID, &motg->inputs)) {
msm_otg_notify_charger(motg, 0);
- if (motg->pdata->vbus_power)
- motg->pdata->vbus_power(1);
+ msm_hsusb_vbus_power(motg, 1);
}
break;
default:
@@ -1804,6 +1858,7 @@
u32 otgsc = 0, usbsts;
if (atomic_read(&motg->in_lpm)) {
+ pr_debug("OTG IRQ: in LPM\n");
disable_irq_nosync(irq);
motg->async_int = 1;
pm_request_resume(otg->dev);
@@ -1853,25 +1908,44 @@
static void msm_otg_set_vbus_state(int online)
{
+ static bool init;
struct msm_otg *motg = the_msm_otg;
- /* We depend on PMIC for only VBUS ON interrupt */
- if (!atomic_read(&motg->in_lpm) || !online || motg->async_int)
- return;
+ if (online) {
+ pr_debug("PMIC: BSV set\n");
+ set_bit(B_SESS_VLD, &motg->inputs);
+ } else {
+ pr_debug("PMIC: BSV clear\n");
+ clear_bit(B_SESS_VLD, &motg->inputs);
+ }
- /*
- * Let interrupt handler take care of resuming
- * the hardware.
- */
- msm_otg_irq(motg->irq, (void *) motg);
+ if (!init) {
+ init = true;
+ complete(&pmic_vbus_init);
+ pr_debug("PMIC: BSV init complete\n");
+ return;
+ }
+
+ schedule_work(&motg->sm_work);
}
static irqreturn_t msm_pmic_id_irq(int irq, void *data)
{
struct msm_otg *motg = data;
- if (atomic_read(&motg->in_lpm) && !motg->async_int)
- msm_otg_irq(motg->irq, motg);
+ if (aca_id_turned_on)
+ return IRQ_HANDLED;
+
+ if (irq_read_line(motg->pdata->pmic_id_irq)) {
+ pr_debug("PMIC: ID set\n");
+ set_bit(ID, &motg->inputs);
+ } else {
+ pr_debug("PMIC: ID clear\n");
+ clear_bit(ID, &motg->inputs);
+ }
+
+ if (motg->otg.state != OTG_STATE_UNDEFINED)
+ schedule_work(&motg->sm_work);
return IRQ_HANDLED;
}
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 6bc70ba..b29a974 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -82,10 +82,13 @@
{USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */
{USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */
{USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */
+ {USB_DEVICE(0x05c6, 0x9048)},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
+#define EFS_SYNC_IFC_NUM 2
+
static struct usb_driver qcdriver = {
.name = "qcserial",
.probe = usb_serial_probe,
@@ -197,6 +200,14 @@
}
break;
+ case 9:
+ if (ifnum != EFS_SYNC_IFC_NUM) {
+ kfree(data);
+ break;
+ }
+
+ retval = 0;
+ break;
default:
dev_err(&serial->dev->dev,
"unknown number of interfaces: %d\n", nintf);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 64fc6ea..fcf4b08 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -407,8 +407,8 @@
intfdata = serial->private;
/* explicitly set the driver mode to raw */
- tty->raw = 0;
- tty->real_raw = 0;
+ tty->raw = 1;
+ tty->real_raw = 1;
dbg("%s", __func__);
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 35d1714..de6bf1a 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -628,6 +628,15 @@
Support for HDMI CEC Feature
Choose to enable CEC
+config FB_MSM_HDMI_MHL
+ depends on FB_MSM_HDMI_MSM_PANEL
+ bool 'HDMI to MHL support'
+ default n
+ ---help---
+ Support the HDMI to MHL conversion.
+ MHL (Mobile High-Definition Link) technology
+ uses USB connector to output HDMI content
+
choice
depends on (FB_MSM_MDP22 || FB_MSM_MDP31 || FB_MSM_MDP40)
prompt "TVOut Region"
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 5d9795a..7fd4c56 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -21,6 +21,7 @@
#include "msm_fb.h"
#include "hdmi_msm.h"
#include "external_common.h"
+#include "mhl_api.h"
struct external_common_state_type *external_common_state;
EXPORT_SYMBOL(external_common_state);
@@ -224,6 +225,70 @@
};
EXPORT_SYMBOL(hdmi_common_supported_video_mode_lut);
+struct hdmi_disp_mode_timing_type
+ hdmi_mhl_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
+ HDMI_SETTINGS_640x480p60_4_3,
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9),
+ HDMI_SETTINGS_1280x720p60_16_9,
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9),
+ HDMI_SETTINGS_1920x1080p24_16_9,
+ HDMI_SETTINGS_1920x1080p25_16_9,
+ HDMI_SETTINGS_1920x1080p30_16_9,
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9),
+};
+EXPORT_SYMBOL(hdmi_mhl_supported_video_mode_lut);
+
static ssize_t hdmi_common_rda_edid_modes(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -537,6 +602,7 @@
mutex_unlock(&external_common_state_hpd_mutex);
video_mode = atoi(buf)-1;
+ DEV_INFO("%s: video_mode is %d\n", __func__, video_mode);
kobject_uevent(external_common_state->uevent_kobj, KOBJ_OFFLINE);
#ifdef CONFIG_FB_MSM_HDMI_COMMON
disp_mode = hdmi_common_get_supported_mode(video_mode);
@@ -569,11 +635,27 @@
return ret;
}
+static ssize_t external_common_rda_hdmi_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ external_common_state->hdmi_sink);
+
+ DEV_DBG("%s: '%d'\n", __func__,
+ external_common_state->hdmi_sink);
+
+ return ret;
+}
+
+
static DEVICE_ATTR(video_mode, S_IRUGO | S_IWUGO,
external_common_rda_video_mode, external_common_wta_video_mode);
static DEVICE_ATTR(video_mode_str, S_IRUGO, external_common_rda_video_mode_str,
NULL);
static DEVICE_ATTR(connected, S_IRUGO, external_common_rda_connected, NULL);
+static DEVICE_ATTR(hdmi_mode, S_IRUGO, external_common_rda_hdmi_mode, NULL);
#ifdef CONFIG_FB_MSM_HDMI_COMMON
static DEVICE_ATTR(edid_modes, S_IRUGO, hdmi_common_rda_edid_modes, NULL);
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUGO, hdmi_common_rda_hpd,
@@ -591,6 +673,7 @@
&dev_attr_video_mode.attr,
&dev_attr_video_mode_str.attr,
&dev_attr_connected.attr,
+ &dev_attr_hdmi_mode.attr,
#ifdef CONFIG_FB_MSM_HDMI_COMMON
&dev_attr_edid_modes.attr,
&dev_attr_hdcp.attr,
@@ -1002,7 +1085,11 @@
img_size_v = (((uint32)data_buf[0xE] & 0xF) << 8)
| data_buf[0xD];
- aspect_ratio_4_3 = (img_size_h * 3 == img_size_v * 4);
+ /*
+ * aspect ratio as 4:3 if within specificed range , rathaer than being
+ * absolute value
+ */
+ aspect_ratio_4_3 = (abs(img_size_h * 3 - img_size_v * 4) < 5) ? 1 : 0;
max_num_of_elements = sizeof(hdmi_edid_disp_mode_lut)
/ sizeof(*hdmi_edid_disp_mode_lut);
@@ -1061,9 +1148,21 @@
DEV_DBG("EDID: format: %d [%s], %s\n",
video_format, video_format_2string(video_format),
supported ? "Supported" : "Not-Supported");
- if (supported)
- disp_mode_list->disp_mode_list[
+ if (supported) {
+ if (mhl_is_connected()) {
+ const struct hdmi_disp_mode_timing_type *mhl_timing =
+ hdmi_mhl_get_supported_mode(video_format);
+ boolean mhl_supported = mhl_timing != NULL;
+ DEV_DBG("EDID: format: %d [%s], %s by MHL\n",
+ video_format, video_format_2string(video_format),
+ mhl_supported ? "Supported" : "Not-Supported");
+ if (mhl_supported)
+ disp_mode_list->disp_mode_list[
disp_mode_list->num_of_elements++] = video_format;
+ } else
+ disp_mode_list->disp_mode_list[
+ disp_mode_list->num_of_elements++] = video_format;
+ }
}
static void hdmi_edid_get_display_mode(const uint8 *data_buf,
@@ -1352,6 +1451,7 @@
if (var->reserved[3]) {
format = var->reserved[3]-1;
+ DEV_DBG("reserved format is %d\n", format);
} else {
DEV_DBG("detecting resolution from %dx%d use var->reserved[3]"
" to specify mode", mfd->var_xres, mfd->var_yres);
@@ -1413,6 +1513,27 @@
}
EXPORT_SYMBOL(hdmi_common_get_supported_mode);
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_mode(uint32 mode)
+{
+ if (mode >= HDMI_VFRMT_MAX)
+ return NULL;
+
+ return &hdmi_mhl_supported_video_mode_lut[mode];
+}
+EXPORT_SYMBOL(hdmi_mhl_get_mode);
+
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_supported_mode(
+ uint32 mode)
+{
+ const struct hdmi_disp_mode_timing_type *ret
+ = hdmi_mhl_get_mode(mode);
+
+ if (ret == NULL || !ret->supported)
+ return NULL;
+ return ret;
+}
+EXPORT_SYMBOL(hdmi_mhl_get_supported_mode);
+
void hdmi_common_init_panel_info(struct msm_panel_info *pinfo)
{
const struct hdmi_disp_mode_timing_type *timing =
diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h
index f629d0f..3d23522 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -243,6 +243,9 @@
const struct hdmi_disp_mode_timing_type *hdmi_common_get_mode(uint32 mode);
const struct hdmi_disp_mode_timing_type *hdmi_common_get_supported_mode(
uint32 mode);
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_mode(uint32 mode);
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_supported_mode(
+ uint32 mode);
void hdmi_common_init_panel_info(struct msm_panel_info *pinfo);
#endif
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index c87119f..a449fc7 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -2301,8 +2301,8 @@
aksv[4] = qfprom_aksv_1 & 0xFF;
/* check there are 20 ones in AKSV */
if (hdmi_msm_count_one(aksv, 5) != 20) {
- DEV_ERR("HDCP: AKSV read from QFPROM doesn't have\
- 20 1's and 20 0's, FAIL (AKSV=%02x%08x)\n",
+ DEV_ERR("HDCP: AKSV read from QFPROM doesn't have "
+ "20 1's and 20 0's, FAIL (AKSV=%02x%08x)\n",
qfprom_aksv_1, qfprom_aksv_0);
ret = -EINVAL;
goto error;
@@ -2332,9 +2332,9 @@
}
/* check there are 20 ones in BKSV */
if (hdmi_msm_count_one(bksv, 5) != 20) {
- DEV_ERR("HDCP: BKSV read from Sink doesn't have\
- 20 1's and 20 0's, FAIL (BKSV=\
- %02x%02x%02x%02x%02x)\n",
+ DEV_ERR("HDCP: BKSV read from Sink doesn't have "
+ "20 1's and 20 0's, FAIL (BKSV="
+ "%02x%02x%02x%02x%02x)\n",
bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
ret = -EINVAL;
goto error;
@@ -2507,8 +2507,8 @@
hpd_int_status = HDMI_INP_ND(0x0250);
/* HDMI_HPD_INT_CTRL[0x0254] */
hpd_int_ctrl = HDMI_INP_ND(0x0254);
- DEV_DBG("[SR-DEUG]: HPD_INTR_CTRL=[%u] HPD_INTR_STATUS=[%u]\
- before reading R0'\n", hpd_int_ctrl, hpd_int_status);
+ DEV_DBG("[SR-DEUG]: HPD_INTR_CTRL=[%u] HPD_INTR_STATUS=[%u] "
+ "before reading R0'\n", hpd_int_ctrl, hpd_int_status);
/*
* HDCP Compliace Test case 1B-01:
@@ -2525,12 +2525,12 @@
goto error;
}
+ DEV_DBG("HDCP: R0'=%02x%02x\n", buf[1], buf[0]);
+ INIT_COMPLETION(hdmi_msm_state->hdcp_success_done);
/* 0x013C HDCP_RCVPORT_DATA2_0
[15:0] LINK0_RI */
HDMI_OUTP(0x013C, (((uint32)buf[1]) << 8) | buf[0]);
- DEV_DBG("HDCP: R0'=%02x%02x\n", buf[1], buf[0]);
- INIT_COMPLETION(hdmi_msm_state->hdcp_success_done);
timeout_count = wait_for_completion_interruptible_timeout(
&hdmi_msm_state->hdcp_success_done, HZ*2);
@@ -2968,8 +2968,8 @@
hdmi_msm_state->hdcp_activating = FALSE;
mutex_unlock(&hdmi_msm_state_mutex);
if (hdmi_msm_state->hpd_during_auth) {
- DEV_WARN("Calling Deauthentication: HPD occured during\
- authentication from [%s]\n", __func__);
+ DEV_WARN("Calling Deauthentication: HPD occured during "
+ "authentication from [%s]\n", __func__);
hdcp_deauthenticate();
mutex_lock(&hdcp_auth_state_mutex);
hdmi_msm_state->hpd_during_auth = FALSE;
@@ -3479,9 +3479,11 @@
{
msm_hdmi_sample_rate = rate;
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
if (hdmi_msm_has_hdcp())
hdcp_deauthenticate();
else
+#endif
hdmi_msm_turn_on();
}
EXPORT_SYMBOL(hdmi_msm_audio_sample_rate_reset);
@@ -3987,7 +3989,6 @@
phy_reset_done = 1;
}
- hdmi_msm_init_phy(external_common_state->video_resolution);
/* HDMI_USEC_REFTIMER[0x0208] */
HDMI_OUTP(0x0208, 0x0001001B);
@@ -4275,9 +4276,13 @@
if (rc)
goto error;
- if (hdmi_msm_has_hdcp())
+ if (hdmi_msm_has_hdcp()) {
+ /* Don't Set Encryption in case of non HDCP builds */
+ external_common_state->present_hdcp = FALSE;
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
external_common_state->present_hdcp = TRUE;
- else {
+#endif
+ } else {
external_common_state->present_hdcp = FALSE;
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
/*
diff --git a/drivers/video/msm/mddi_toshiba_wvga_pt.c b/drivers/video/msm/mddi_toshiba_wvga_pt.c
index edf739d..7a9fb2d 100644
--- a/drivers/video/msm/mddi_toshiba_wvga_pt.c
+++ b/drivers/video/msm/mddi_toshiba_wvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -44,10 +44,10 @@
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.lcd.vsync_enable = TRUE;
- pinfo.lcd.refx100 = 6096; /* adjust refx100 to prevent tearing */
- pinfo.lcd.v_back_porch = 2; /* vsw=1 + vbp = 2 */
- pinfo.lcd.v_front_porch = 3;
- pinfo.lcd.v_pulse_width = 1;
+ pinfo.lcd.refx100 = 6102; /* adjust refx100 to prevent tearing */
+ pinfo.lcd.v_back_porch = 8; /* vsw=10 + vbp = 8 */
+ pinfo.lcd.v_front_porch = 2;
+ pinfo.lcd.v_pulse_width = 10;
pinfo.lcd.hw_vsync_mode = FALSE;
pinfo.lcd.vsync_notifier_period = (1 * HZ);
pinfo.bl_max = 15;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 462ede1..9380257 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -31,7 +31,7 @@
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
-
+#include <linux/memory_alloc.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
@@ -52,6 +52,7 @@
int mdp_rev;
static struct regulator *footswitch;
+static unsigned int mdp_footswitch_on;
struct completion mdp_ppp_comp;
struct semaphore mdp_ppp_mutex;
@@ -104,6 +105,11 @@
static struct mdp_dma_data dma_e_data;
#endif
#endif
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+struct mdp_dma_data dma_wb_data;
+#endif
+
static struct mdp_dma_data dma3_data;
extern ktime_t mdp_dma2_last_update_time;
@@ -600,6 +606,10 @@
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_lut_enable();
outpdw(MDP_BASE + 0x0008, 0);
+ } else if (term == MDP_OVERLAY2_TERM) {
+ mdp_pipe_ctrl(MDP_OVERLAY2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_lut_enable();
+ outpdw(MDP_BASE + 0x00D0, 0);
}
#else
} else if (term == MDP_DMA_S_TERM) {
@@ -958,6 +968,14 @@
init_completion(&dma_e_data.comp);
mutex_init(&dma_e_data.ov_mutex);
#endif
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+ dma_wb_data.busy = FALSE;
+ dma_wb_data.waiting = FALSE;
+ init_completion(&dma_wb_data.comp);
+ mutex_init(&dma_wb_data.ov_mutex);
+#endif
+
+
#ifndef CONFIG_FB_MSM_MDP22
init_completion(&mdp_hist_comp);
@@ -1122,18 +1140,6 @@
__func__, mdp_hw_revision);
}
-int mdp4_writeback_offset(void)
-{
- int off = 0;
-
- if (mdp_pdata->writeback_offset)
- off = mdp_pdata->writeback_offset();
-
- pr_debug("%s: writeback_offset=%d %x\n", __func__, off, off);
-
- return off;
-}
-
#ifdef CONFIG_FB_MSM_MDP40
static void configure_mdp_core_clk_table(uint32 min_clk_rate)
{
@@ -1251,8 +1257,10 @@
footswitch = regulator_get(NULL, "fs_mdp");
if (IS_ERR(footswitch))
footswitch = NULL;
- else
+ else {
regulator_enable(footswitch);
+ mdp_footswitch_on = 1;
+ }
mdp_clk = clk_get(NULL, "mdp_clk");
if (IS_ERR(mdp_clk)) {
@@ -1312,6 +1320,7 @@
#endif
if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+
mdp_pdata = pdev->dev.platform_data;
size = resource_size(&pdev->resource[0]);
@@ -1349,6 +1358,28 @@
#endif
mdp_resource_initialized = 1;
+
+ if (!mdp_pdata)
+ return 0;
+
+ size = mdp_pdata->mdp_writeback_size_ov0 +
+ mdp_pdata->mdp_writeback_size_ov1;
+ if (size) {
+ mdp_pdata->mdp_writeback_phys =
+ (void *)allocate_contiguous_memory_nomap
+ (size,
+ mdp_pdata->mdp_writeback_memtype,
+ 4); /* align to word size */
+ if (mdp_pdata->mdp_writeback_phys) {
+ pr_info("allocating %d bytes at %p for mdp writeback\n",
+ size, mdp_pdata->mdp_writeback_phys);
+ } else {
+ pr_err("%s cannot allocate memory for mdp writeback!\n",
+ __func__);
+ }
+ } else {
+ mdp_pdata->mdp_writeback_phys = 0;
+ }
return 0;
}
@@ -1588,11 +1619,25 @@
#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
case WRITEBACK_PANEL:
- pdata->on = mdp4_overlay_writeback_on;
- pdata->off = mdp4_overlay_writeback_off;
- mfd->dma_fnc = mdp4_writeback_overlay;
- mfd->dma = &dma_e_data;
- mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF);
+ {
+ unsigned int mdp_version;
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
+ FALSE);
+ mdp_version = inpdw(MDP_BASE + 0x0);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
+ FALSE);
+ if (mdp_version < 0x04030303) {
+ pr_err("%s: writeback panel not supprted\n",
+ __func__);
+ rc = -ENODEV;
+ goto mdp_probe_err;
+ }
+ pdata->on = mdp4_overlay_writeback_on;
+ pdata->off = mdp4_overlay_writeback_off;
+ mfd->dma_fnc = mdp4_writeback_overlay;
+ mfd->dma = &dma_wb_data;
+ mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF);
+ }
break;
#endif
default:
@@ -1619,6 +1664,20 @@
}
}
#endif
+
+ if (mdp_pdata && mdp_pdata->mdp_writeback_phys) {
+ mfd->writeback_overlay0_phys =
+ (mdp_pdata->mdp_writeback_size_ov0) ?
+ mdp_pdata->mdp_writeback_phys : 0;
+ mfd->writeback_overlay1_phys =
+ (mdp_pdata->mdp_writeback_size_ov1) ?
+ (mdp_pdata->mdp_writeback_phys +
+ mdp_pdata->mdp_writeback_size_ov0) : 0;
+ } else {
+ mfd->writeback_overlay0_phys = 0;
+ mfd->writeback_overlay1_phys = 0;
+ }
+
/* set driver data */
platform_set_drvdata(msm_fb_dev, mfd);
@@ -1644,6 +1703,28 @@
return rc;
}
+void mdp_footswitch_ctrl(boolean on)
+{
+ mutex_lock(&mdp_suspend_mutex);
+ if (!mdp_suspended || mdp4_extn_disp || !footswitch ||
+ mdp_rev <= MDP_REV_41) {
+ mutex_unlock(&mdp_suspend_mutex);
+ return;
+ }
+
+ if (on && !mdp_footswitch_on) {
+ pr_debug("Enable MDP FS\n");
+ regulator_enable(footswitch);
+ mdp_footswitch_on = 1;
+ } else if (!on && mdp_footswitch_on) {
+ pr_debug("Disable MDP FS\n");
+ regulator_disable(footswitch);
+ mdp_footswitch_on = 0;
+ }
+
+ mutex_unlock(&mdp_suspend_mutex);
+}
+
#ifdef CONFIG_PM
static void mdp_suspend_sub(void)
{
@@ -1688,15 +1769,12 @@
#ifdef CONFIG_FB_MSM_DTV
mdp4_dtv_set_black_screen();
#endif
- if (footswitch && mdp_rev > MDP_REV_42)
- regulator_disable(footswitch);
+ mdp_footswitch_ctrl(FALSE);
}
static void mdp_early_resume(struct early_suspend *h)
{
- if (footswitch && mdp_rev > MDP_REV_42)
- regulator_enable(footswitch);
-
+ mdp_footswitch_ctrl(TRUE);
mutex_lock(&mdp_suspend_mutex);
mdp_suspended = FALSE;
mutex_unlock(&mdp_suspend_mutex);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 8817213..ceb133b 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -123,6 +123,7 @@
MDP_DMA_S_BLOCK,
MDP_DMA_E_BLOCK,
MDP_OVERLAY1_BLOCK,
+ MDP_OVERLAY2_BLOCK,
MDP_MAX_BLOCK
} MDP_BLOCK_TYPE;
@@ -223,6 +224,7 @@
#define MDP_OVERLAY1_TERM 0x40
#endif
#define MDP_HISTOGRAM_TERM 0x80
+#define MDP_OVERLAY2_TERM 0x100
#define ACTIVE_START_X_EN BIT(31)
#define ACTIVE_START_Y_EN BIT(31)
@@ -722,6 +724,7 @@
int mdp_start_histogram(struct fb_info *info);
int mdp_stop_histogram(struct fb_info *info);
int mdp_histogram_ctrl(boolean en);
+void mdp_footswitch_ctrl(boolean on);
#ifdef CONFIG_FB_MSM_MDP303
static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 2bcac9c..798cf47 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
extern struct mdp_dma_data dma2_data;
extern struct mdp_dma_data dma_s_data;
extern struct mdp_dma_data dma_e_data;
+extern struct mdp_dma_data dma_wb_data;
extern unsigned int mdp_hist_frame_cnt;
extern struct completion mdp_hist_comp;
extern boolean mdp_is_hist_start;
@@ -28,6 +29,7 @@
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
+#define MDP4_OVERLAYPROC2_BASE 0x88000
#define MDP4_VIDEO_BASE 0x20000
#define MDP4_VIDEO_OFF 0x10000
@@ -125,6 +127,7 @@
#define INTR_EXTERNAL_INTF_UDERRUN BIT(10)
#define INTR_PRIMARY_READ_PTR BIT(11)
#define INTR_DMA_P_HISTOGRAM BIT(17)
+#define INTR_OVERLAY2_DONE BIT(30)
#ifdef CONFIG_FB_MSM_OVERLAY
#define MDP4_ANY_INTR_MASK (INTR_OVERLAY0_DONE|INTR_DMA_S_DONE | \
@@ -141,6 +144,7 @@
OVERLAY_PIPE_VG2,
OVERLAY_PIPE_RGB3,
OVERLAY_PIPE_VG3,
+ OVERLAY_PIPE_VG4,
OVERLAY_PIPE_MAX
};
@@ -153,6 +157,7 @@
enum {
MDP4_MIXER0,
MDP4_MIXER1,
+ MDP4_MIXER2,
MDP4_MIXER_MAX
};
@@ -219,6 +224,7 @@
#define MDP4_OP_SCALEX_FIR (0 << 2)
#define MDP4_OP_SCALEX_MN_PHASE (1 << 2)
#define MDP4_OP_SCALEX_PIXEL_RPT (2 << 2)
+#define MDP4_OP_SCALE_RGB_ENHANCED (1 << 4)
#define MDP4_OP_SCALE_RGB_PIXEL_RPT (0 << 3)
#define MDP4_OP_SCALE_RGB_BILINEAR (1 << 3)
#define MDP4_OP_SCALE_ALPHA_PIXEL_RPT (0 << 2)
@@ -327,6 +333,7 @@
ulong intr_dma_e;
ulong intr_overlay0;
ulong intr_overlay1;
+ ulong intr_overlay2;
ulong intr_vsync_p; /* Primary interface */
ulong intr_underrun_p; /* Primary interface */
ulong intr_vsync_e; /* external interface */
@@ -388,7 +395,7 @@
void mdp4_mixer_blend_init(int mixer_num);
void mdp4_vg_qseed_init(int vg_num);
void mdp4_vg_csc_setup(int vp_num);
-void mdp4_mixer1_csc_setup(void);
+void mdp4_mixer_csc_setup(uint32 mixer);
void mdp4_vg_csc_update(struct mdp_csc *p);
irqreturn_t mdp4_isr(int irq, void *ptr);
void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
@@ -421,7 +428,9 @@
static inline int mdp4_overlay_borderfill_supported(void)
{
unsigned int mdp_hw_version;
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return (mdp_hw_version >= 0x0402030b);
}
@@ -635,7 +644,6 @@
struct msmfb_overlay_3d *r3d);
int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info);
-int mdp4_writeback_offset(void);
void mdp_dmap_vsync_set(int enable);
int mdp_dmap_vsync_get(void);
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index a44f7c0..ba774b9 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -109,6 +109,7 @@
clk_disable(ebi1_clk);
#endif
mdp4_extn_disp = 0;
+ mdp_footswitch_ctrl(FALSE);
return ret;
}
@@ -126,6 +127,7 @@
pm_qos_rate = panel_pixclock_freq / 1000 ;
else
pm_qos_rate = 58000;
+ mdp_footswitch_ctrl(TRUE);
mdp4_extn_disp = 1;
#ifdef CONFIG_MSM_BUS_SCALING
if (dtv_bus_scale_handle > 0)
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index a06eef8..543d21a 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -48,6 +48,7 @@
uint32 panel_mode;
uint32 mixer0_played;
uint32 mixer1_played;
+ uint32 mixer2_played;
} mdp4_overlay_db = {
.cs_controller = CS_CONTROLLER_0,
.plist = {
@@ -83,6 +84,12 @@
.pipe_ndx = 6,
.mixer_num = MDP4_MIXER1,
},
+ {
+ .pipe_type = OVERLAY_TYPE_BF,
+ .pipe_num = OVERLAY_PIPE_VG4,
+ .pipe_ndx = 7,
+ .mixer_num = MDP4_MIXER2,
+ },
},
};
@@ -104,7 +111,9 @@
int mdp4_overlay_mixer_play(int mixer_num)
{
- if (mixer_num == MDP4_MIXER1)
+ if (mixer_num == MDP4_MIXER2)
+ return ctrl->mixer2_played;
+ else if (mixer_num == MDP4_MIXER1)
return ctrl->mixer1_played;
else
return ctrl->mixer0_played;
@@ -365,15 +374,16 @@
pipe->op_mode |= MDP4_OP_SCALEY_EN;
if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {
- if (pipe->alpha_enable)
+ if (pipe->alpha_enable && pipe->dst_h > pipe->src_h)
pipe->op_mode |= MDP4_OP_SCALEY_PIXEL_RPT;
else if (pipe->dst_h <= (pipe->src_h / 4))
pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE;
else
pipe->op_mode |= MDP4_OP_SCALEY_FIR;
} else { /* RGB pipe */
- pipe->op_mode |= MDP4_OP_SCALE_RGB_BILINEAR;
- pipe->op_mode |= MDP4_OP_SCALE_ALPHA_BILINEAR;
+ pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED |
+ MDP4_OP_SCALE_RGB_BILINEAR |
+ MDP4_OP_SCALE_ALPHA_BILINEAR;
}
pipe->phasey_step = mdp4_scale_phase_step(29,
@@ -386,15 +396,16 @@
pipe->op_mode |= MDP4_OP_SCALEX_EN;
if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {
- if (pipe->alpha_enable)
+ if (pipe->alpha_enable && pipe->dst_w > pipe->src_w)
pipe->op_mode |= MDP4_OP_SCALEX_PIXEL_RPT;
else if (pipe->dst_w <= (pipe->src_w / 4))
pipe->op_mode |= MDP4_OP_SCALEX_MN_PHASE;
else
pipe->op_mode |= MDP4_OP_SCALEX_FIR;
} else { /* RGB pipe */
- pipe->op_mode |= MDP4_OP_SCALE_RGB_BILINEAR;
- pipe->op_mode |= MDP4_OP_SCALE_ALPHA_BILINEAR;
+ pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED |
+ MDP4_OP_SCALE_RGB_BILINEAR |
+ MDP4_OP_SCALE_ALPHA_BILINEAR;
}
pipe->phasex_step = mdp4_scale_phase_step(29,
@@ -1071,7 +1082,9 @@
char *overlay_base;
intf = 0;
- if (pipe->mixer_num == MDP4_MIXER1) {
+ if (pipe->mixer_num == MDP4_MIXER2)
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;
+ else if (pipe->mixer_num == MDP4_MIXER1) {
overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
intf = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */
intf >>= 4;
@@ -1112,10 +1125,10 @@
#else
outpdw(overlay_base + 0x0014, 0x0); /* RGB888 */
#endif
- } else {
+ } else if (pipe->mixer_num == MDP4_MIXER2) {
if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
off = 0;
- bpp = 2;
+ bpp = 1;
if (pipe->ov_cnt & 0x01)
off = pipe->src_height *
pipe->src_width * bpp;
@@ -1124,12 +1137,22 @@
pipe->blt_addr + off);
/* overlay ouput is RGB888 */
outpdw(overlay_base + 0x0010,
- pipe->src_width * bpp);
+ ((pipe->src_width << 16) |
+ pipe->src_width));
outpdw(overlay_base + 0x001c,
pipe->blt_addr + off);
+ off = pipe->src_height * pipe->src_width;
+ /* align chroma to 2k address */
+ off = (off + 2047) & ~2047;
+ /* UV plane adress */
+ outpdw(overlay_base + 0x0020,
+ pipe->blt_addr + off);
/* MDDI - BLT + on demand */
outpdw(overlay_base + 0x0004, 0x08);
- outpdw(overlay_base + 0x0014, 0x1); /* RGB565 */
+ /* pseudo planar + writeback */
+ outpdw(overlay_base + 0x0014, 0x012);
+ /* rgb->yuv */
+ outpdw(overlay_base + 0x0200, 0x05);
}
}
} else {
@@ -1160,11 +1183,16 @@
int mdp4_overlay_pipe_staged(int mixer)
{
- uint32 data, mask, i;
+ uint32 data, mask, i, off;
int p1, p2;
+ if (mixer == MDP4_MIXER2)
+ off = 0x100F0;
+ else
+ off = 0x10100;
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- data = inpdw(MDP_BASE + 0x10100);
+ data = inpdw(MDP_BASE + off);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
p1 = 0;
p2 = 0;
@@ -1214,7 +1242,7 @@
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
{
- uint32 data, mask, snum, stage, mixer, pnum;
+ uint32 data, mask, snum, stage, mixer, pnum, off;
struct mdp4_overlay_pipe *spipe;
spipe = mdp4_overlay_stage_pipe(pipe->mixer_num, pipe->mixer_stage);
@@ -1230,10 +1258,15 @@
mixer = pipe->mixer_num;
pnum = pipe->pipe_num;
- /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */
- data = inpdw(MDP_BASE + 0x10100);
+ if (mixer == MDP4_MIXER2)
+ off = 0x100F0;
+ else
+ off = 0x10100;
- if (mixer == MDP4_MIXER1)
+ /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */
+ data = inpdw(MDP_BASE + off);
+
+ if (mixer >= MDP4_MIXER1)
stage += 8;
if (pipe->pipe_type == OVERLAY_TYPE_BF) {
@@ -1254,9 +1287,9 @@
data |= stage;
- outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */
+ outpdw(MDP_BASE + off, data); /* MDP_LAYERMIXER_IN_CFG */
- data = inpdw(MDP_BASE + 0x10100);
+ data = inpdw(MDP_BASE + off);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -1265,7 +1298,7 @@
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
{
- uint32 data, mask, snum, stage, mixer, pnum;
+ uint32 data, mask, snum, stage, mixer, pnum, off;
stage = pipe->mixer_stage;
mixer = pipe->mixer_num;
@@ -1276,10 +1309,15 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */
- data = inpdw(MDP_BASE + 0x10100);
+ if (mixer == MDP4_MIXER2)
+ off = 0x100F0;
+ else
+ off = 0x10100;
- if (mixer == MDP4_MIXER1)
+ /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */
+ data = inpdw(MDP_BASE + off);
+
+ if (mixer >= MDP4_MIXER1)
stage += 8;
if (pipe->pipe_type == OVERLAY_TYPE_BF) {
@@ -1297,9 +1335,9 @@
mask <<= snum;
data &= ~mask; /* clear old bits */
- outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */
+ outpdw(MDP_BASE + off, data); /* MDP_LAYERMIXER_IN_CFG */
- data = inpdw(MDP_BASE + 0x10100);
+ data = inpdw(MDP_BASE + off);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -1311,13 +1349,16 @@
struct mdp4_overlay_pipe *bg_pipe;
unsigned char *overlay_base, *rgb_base;
uint32 c0, c1, c2, blend_op, constant_color = 0, rgb_src_format;
- uint32 fg_color3_out;
+ uint32 fg_color3_out, fg_alpha = 0, bg_alpha = 0;
int off;
if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE)
return;
- if (pipe->mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */
+ /* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */
+ if (pipe->mixer_num == MDP4_MIXER2)
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */
+ else if (pipe->mixer_num == MDP4_MIXER1)
overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
else
overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
@@ -1332,17 +1373,48 @@
return;
}
+ if (bg_pipe->pipe_type == OVERLAY_TYPE_BF &&
+ pipe->mixer_stage > MDP4_MIXER_STAGE0) {
+ bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
+ MDP4_MIXER_STAGE0);
+ }
+
+ if (pipe->alpha_enable) {
+ /* alpha channel is lost on VG pipe when downscaling */
+ if (pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
+ (pipe->dst_w < pipe->src_w || pipe->dst_h < pipe->src_h))
+ fg_alpha = 0;
+ else
+ fg_alpha = 1;
+ }
+
+ if (!fg_alpha && bg_pipe && bg_pipe->alpha_enable) {
+ struct mdp4_overlay_pipe *tmp;
+ int stage;
+
+ bg_alpha = 1;
+ /* check all bg layers are opaque to propagate bg alpha */
+ stage = bg_pipe->mixer_stage + 1;
+ for (; stage < pipe->mixer_stage; stage++) {
+ tmp = mdp4_overlay_stage_pipe(pipe->mixer_num, stage);
+ if (!tmp || tmp->alpha_enable || tmp->is_fg) {
+ bg_alpha = 0;
+ break;
+ }
+ }
+ }
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
blend_op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
MDP4_BLEND_BG_ALPHA_BG_CONST);
outpdw(overlay_base + off + 0x108, pipe->alpha);
outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
- fg_color3_out = 0; /* keep bg alpha by default */
+ fg_color3_out = 1; /* keep fg alpha by default */
if (pipe->is_fg) {
if (pipe->alpha == 0xff &&
- bg_pipe->pipe_num <= OVERLAY_PIPE_RGB2) {
+ bg_pipe && bg_pipe->pipe_num <= OVERLAY_PIPE_RGB2) {
rgb_base = MDP_BASE + MDP4_RGB_BASE;
rgb_base += MDP4_RGB_OFF * bg_pipe->pipe_num;
rgb_src_format = inpdw(rgb_base + 0x50);
@@ -1350,14 +1422,11 @@
outpdw(rgb_base + 0x50, rgb_src_format);
outpdw(rgb_base + 0x1008, constant_color);
}
- } else if (pipe->alpha_enable) {
- /* pick fg alpha */
+ } else if (fg_alpha) {
blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
- MDP4_BLEND_FG_ALPHA_FG_PIXEL |
MDP4_BLEND_BG_INV_ALPHA);
fg_color3_out = 1; /* keep fg alpha */
- } else if (bg_pipe->alpha_enable) {
- /* pick bg alpha */
+ } else if (bg_alpha) {
blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
MDP4_BLEND_FG_ALPHA_BG_PIXEL |
MDP4_BLEND_FG_INV_ALPHA);
@@ -1378,7 +1447,7 @@
outpdw(overlay_base + off + 0x118,
(c1 << 16 | c0));
outpdw(overlay_base + off + 0x11c, c2);
- } else {
+ } else if (bg_pipe) {
transp_color_key(bg_pipe->src_format,
pipe->transp, &c0, &c1, &c2);
/* bg blocked */
@@ -1960,16 +2029,16 @@
if (req->flags & MDP_DEINTERLACE)
return OVERLAY_PERF_LEVEL1;
+ if (ctrl->plist[OVERLAY_PIPE_VG1].pipe_used &&
+ ctrl->plist[OVERLAY_PIPE_VG2].pipe_used)
+ return OVERLAY_PERF_LEVEL1;
+
if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
return OVERLAY_PERF_LEVEL4;
else if (mdp4_overlay_is_rgb_type(req->src.format))
return OVERLAY_PERF_LEVEL1;
- if (ctrl->plist[OVERLAY_PIPE_VG1].pipe_used &&
- ctrl->plist[OVERLAY_PIPE_VG2].pipe_used)
- return OVERLAY_PERF_LEVEL1;
-
if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE)
return OVERLAY_PERF_LEVEL3;
else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE)
@@ -2184,7 +2253,9 @@
return -ENODEV;
}
- if (pipe->mixer_num == MDP4_MIXER1)
+ if (pipe->mixer_num == MDP4_MIXER2)
+ ctrl->mixer2_played = 0;
+ else if (pipe->mixer_num == MDP4_MIXER1)
ctrl->mixer1_played = 0;
else {
/* mixer 0 */
@@ -2483,7 +2554,15 @@
mdp4_mixer_blend_setup(pipe);
mdp4_mixer_stage_up(pipe);
- if (pipe->mixer_num == MDP4_MIXER1) {
+ if (pipe->mixer_num == MDP4_MIXER2) {
+ ctrl->mixer2_played++;
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+ if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
+ mdp4_writeback_dma_busy_wait(mfd);
+ mdp4_writeback_kickoff_video(mfd, pipe);
+ }
+#endif
+ } else if (pipe->mixer_num == MDP4_MIXER1) {
ctrl->mixer1_played++;
/* enternal interface */
if (ctrl->panel_mode & MDP4_PANEL_DTV)
@@ -2494,12 +2573,6 @@
#endif
else if (ctrl->panel_mode & MDP4_PANEL_ATV)
mdp4_overlay_reg_flush(pipe, 1);
-#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
- else if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
- mdp4_writeback_dma_busy_wait(mfd);
- mdp4_writeback_kickoff_video(mfd, pipe);
- }
-#endif
} else {
/* primary interface */
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 4479ece..484ed7d 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -45,8 +45,6 @@
struct timer_list dsi_clock_timer;
-static int writeback_offset;
-
void mdp4_overlay_dsi_state_set(int state)
{
unsigned long flag;
@@ -119,7 +117,6 @@
void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
- struct fb_info *fbi = mfd->fbi;
uint8 *src;
int ptype;
struct mdp4_overlay_pipe *pipe;
@@ -159,14 +156,9 @@
dsi_pipe = pipe; /* keep it */
- writeback_offset = mdp4_writeback_offset();
+ pipe->blt_base = (ulong) mfd->writeback_overlay0_phys;
+ pipe->blt_addr = 0;
- if (writeback_offset > 0) {
- pipe->blt_base = (ulong)fbi->fix.smem_start;
- pipe->blt_base += writeback_offset;
- } else {
- pipe->blt_base = 0;
- }
} else {
pipe = dsi_pipe;
}
@@ -351,7 +343,7 @@
int mdp4_dsi_overlay_blt_offset(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req)
{
- req->offset = writeback_offset;
+ req->offset = 0;
req->width = dsi_pipe->src_width;
req->height = dsi_pipe->src_height;
req->bpp = dsi_pipe->bpp;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 938d7c6..d68396a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -37,8 +37,6 @@
static int first_pixel_start_x;
static int first_pixel_start_y;
-static int writeback_offset;
-
static struct mdp4_overlay_pipe *dsi_pipe;
static struct completion dsi_video_comp;
@@ -141,14 +139,9 @@
dsi_pipe = pipe; /* keep it */
init_completion(&dsi_video_comp);
- writeback_offset = mdp4_writeback_offset();
+ pipe->blt_base = (ulong) mfd->writeback_overlay0_phys;
+ pipe->blt_addr = 0;
- if (writeback_offset > 0) {
- pipe->blt_base = (ulong)fbi->fix.smem_start;
- pipe->blt_base += writeback_offset;
- } else {
- pipe->blt_base = 0;
- }
} else {
pipe = dsi_pipe;
}
@@ -634,7 +627,7 @@
int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req)
{
- req->offset = writeback_offset;
+ req->offset = 0;
req->width = dsi_pipe->src_width;
req->height = dsi_pipe->src_height;
req->bpp = dsi_pipe->bpp;
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index c8135d4..08eb948 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -333,8 +333,6 @@
MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
(0x0 & 0xFFF)); /* 12-bit R */
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
- pipe->src_format = MDP_ARGB_8888;
} else {
switch (mfd->ibuf.bpp) {
case 2:
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index f318691..1dbbf94 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -42,8 +42,6 @@
int first_pixel_start_x;
int first_pixel_start_y;
-static int writeback_offset;
-
static struct mdp4_overlay_pipe *lcdc_pipe;
static struct completion lcdc_comp;
@@ -128,14 +126,9 @@
lcdc_pipe = pipe; /* keep it */
init_completion(&lcdc_comp);
- writeback_offset = mdp4_writeback_offset();
+ pipe->blt_base = (ulong) mfd->writeback_overlay0_phys;
+ pipe->blt_addr = 0;
- if (writeback_offset > 0) {
- pipe->blt_base = (ulong)fbi->fix.smem_start;
- pipe->blt_base += writeback_offset;
- } else {
- pipe->blt_base = 0;
- }
} else {
pipe = lcdc_pipe;
}
@@ -507,7 +500,7 @@
int mdp4_lcdc_overlay_blt_offset(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req)
{
- req->offset = writeback_offset;
+ req->offset = 0;
req->width = lcdc_pipe->src_width;
req->height = lcdc_pipe->src_height;
req->bpp = lcdc_pipe->bpp;
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index cd027e9..8f68e11 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -48,11 +48,10 @@
struct msm_fb_data_type *mfd;
struct fb_info *fbi;
uint8 *buf;
- int ptype;
struct mdp4_overlay_pipe *pipe;
int bpp;
int ret;
- uint32 format;
+ uint32 data;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
@@ -71,27 +70,17 @@
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
- if (bpp == 2)
- format = MDP_RGB_565;
- else if (bpp == 3)
- format = MDP_RGB_888;
- else
- format = MDP_ARGB_8888;
-
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
if (writeback_pipe == NULL) {
- ptype = mdp4_overlay_format2type(format);
- if (ptype < 0)
- pr_err("%s: format2type failed\n", __func__);
- pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1);
+ pipe = mdp4_overlay_pipe_alloc(OVERLAY_TYPE_BF, MDP4_MIXER2);
if (pipe == NULL)
pr_info("%s: pipe_alloc failed\n", __func__);
pipe->pipe_used++;
pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
- pipe->mixer_num = MDP4_MIXER1;
- pipe->src_format = format;
+ pipe->mixer_num = MDP4_MIXER2;
+ pipe->src_format = MDP_ARGB_8888;
mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_WRITEBACK);
ret = mdp4_overlay_format2pipe(pipe);
if (ret < 0)
@@ -103,6 +92,18 @@
pipe = writeback_pipe;
}
ret = panel_next_on(pdev);
+ /* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */
+ data = inpdw(MDP_BASE + 0x100F4);
+ data &= ~0x02; /* clear the mixer1 mux bit */
+ data |= 0x02;
+ outpdw(MDP_BASE + 0x100F4, data);
+ MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004,
+ ((0x0 & 0xFFF) << 16) | /* 12-bit B */
+ (0x0 & 0xFFF)); /* 12-bit G */
+ /* MSP_BORDER_COLOR */
+ MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
+ (0x0 & 0xFFF)); /* 12-bit R */
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return ret;
}
@@ -110,14 +111,24 @@
int mdp4_overlay_writeback_off(struct platform_device *pdev)
{
int ret;
+ uint32 data;
struct msm_fb_data_type *mfd =
(struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (mfd && writeback_pipe) {
mdp4_writeback_dma_busy_wait(mfd);
mdp4_overlay_pipe_free(writeback_pipe);
+ mdp4_overlay_panel_mode_unset(writeback_pipe->mixer_num,
+ MDP4_PANEL_WRITEBACK);
writeback_pipe = NULL;
}
ret = panel_next_off(pdev);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ /* MDP_LAYERMIXER_WB_MUX_SEL to restore
+ * mixer1 axi for mixer1 writeback */
+ data = inpdw(MDP_BASE + 0x100F4);
+ data &= ~0x02; /* clear the mixer1 mux bit */
+ outpdw(MDP_BASE + 0x100F4, data);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return ret;
}
int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd)
@@ -159,8 +170,6 @@
pipe->srcp0_addr = (uint32)buf;
- mdp4_overlay_rgb_setup(pipe);
-
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -202,7 +211,7 @@
if (busy_wait_cnt)
busy_wait_cnt--;
- mdp_disable_irq_nosync(MDP_OVERLAY1_TERM);
+ mdp_disable_irq_nosync(MDP_OVERLAY2_TERM);
pr_debug("%s ovdone interrupt\n", __func__);
}
@@ -211,17 +220,17 @@
{
unsigned long flag;
spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_enable_irq(MDP_OVERLAY1_TERM);
+ mdp_enable_irq(MDP_OVERLAY2_TERM);
INIT_COMPLETION(writeback_pipe->comp);
mfd->dma->busy = TRUE;
- outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE);
- mdp_intr_mask |= INTR_OVERLAY1_DONE;
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY2_DONE);
+ mdp_intr_mask |= INTR_OVERLAY2_DONE;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
wmb(); /* make sure all registers updated */
spin_unlock_irqrestore(&mdp_spin_lock, flag);
/* start OVERLAY pipe */
- mdp_pipe_kickoff(MDP_OVERLAY1_TERM, mfd);
+ mdp_pipe_kickoff(MDP_OVERLAY2_TERM, mfd);
wmb();
pr_debug("%s: before ov done interrupt\n", __func__);
wait_for_completion_killable(&mfd->dma->comp);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index f51427c..f9edf07 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -79,7 +79,7 @@
if (overlayer == MDP4_MIXER0)
outpdw(MDP_BASE + 0x10004, bits); /* MDP_OVERLAY0_CFG */
- else
+ else if (overlayer == MDP4_MIXER1)
outpdw(MDP_BASE + 0x18004, bits); /* MDP_OVERLAY1_CFG */
MSM_FB_DEBUG("mdp4_overlay_cfg: 0x%x\n",
@@ -273,7 +273,8 @@
mdp4_vg_csc_setup(0);
mdp4_vg_csc_setup(1);
- mdp4_mixer1_csc_setup();
+ mdp4_mixer_csc_setup(1);
+ mdp4_mixer_csc_setup(2);
if (mdp_rev <= MDP_REV_41) {
mdp4_mixer_gc_lut_setup(0);
@@ -473,11 +474,21 @@
if (panel & MDP4_PANEL_ATV)
mdp4_overlay1_done_atv();
#endif
+ }
#if defined(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL)
+ if (isr & INTR_OVERLAY2_DONE) {
+ mdp4_stat.intr_overlay2++;
+ /* disable DTV interrupt */
+ dma = &dma_wb_data;
+ spin_lock(&mdp_spin_lock);
+ mdp_intr_mask &= ~INTR_OVERLAY2_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ dma->waiting = FALSE;
+ spin_unlock(&mdp_spin_lock);
if (panel & MDP4_PANEL_WRITEBACK)
mdp4_overlay1_done_writeback(dma);
-#endif
}
+#endif
#endif /* OVERLAY */
if (isr & INTR_DMA_P_DONE) {
@@ -1416,12 +1427,15 @@
0x00f0, 0x0010, 0x00f0
};
-void mdp4_mixer1_csc_mv_setup(void)
+void mdp4_mixer_csc_mv_setup(uint32 mixer)
{
uint32 *off;
int i;
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400);
+ if (mixer == MDP4_MIXER1)
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400);
+ else
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2400);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
for (i = 0; i < 9; i++) {
@@ -1431,12 +1445,15 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
-void mdp4_mixer1_csc_pre_bv_setup(void)
+void mdp4_mixer_csc_pre_bv_setup(uint32 mixer)
{
uint32 *off;
int i;
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500);
+ if (mixer == MDP4_MIXER1)
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500);
+ else
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2500);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
for (i = 0; i < 3; i++) {
@@ -1446,12 +1463,15 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
-void mdp4_mixer1_csc_post_bv_setup(void)
+void mdp4_mixer_csc_post_bv_setup(uint32 mixer)
{
uint32 *off;
int i;
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580);
+ if (mixer == MDP4_MIXER1)
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580);
+ else
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2580);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
for (i = 0; i < 3; i++) {
@@ -1461,12 +1481,15 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
-void mdp4_mixer1_csc_pre_lv_setup(void)
+void mdp4_mixer_csc_pre_lv_setup(uint32 mixer)
{
uint32 *off;
int i;
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600);
+ if (mixer == MDP4_MIXER1)
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600);
+ else
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2600);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
for (i = 0; i < 6; i++) {
@@ -1476,12 +1499,15 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
-void mdp4_mixer1_csc_post_lv_setup(void)
+void mdp4_mixer_csc_post_lv_setup(uint32 mixer)
{
uint32 *off;
int i;
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680);
+ if (mixer == MDP4_MIXER1)
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680);
+ else
+ off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2680);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
for (i = 0; i < 6; i++) {
@@ -1491,14 +1517,16 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
-void mdp4_mixer1_csc_setup(void)
+void mdp4_mixer_csc_setup(uint32 mixer)
{
+ if (mixer >= MDP4_MIXER1) {
/* rgb2yuv */
- mdp4_mixer1_csc_mv_setup();
- mdp4_mixer1_csc_pre_bv_setup();
- mdp4_mixer1_csc_post_bv_setup();
- mdp4_mixer1_csc_pre_lv_setup();
- mdp4_mixer1_csc_post_lv_setup();
+ mdp4_mixer_csc_mv_setup(mixer);
+ mdp4_mixer_csc_pre_bv_setup(mixer);
+ mdp4_mixer_csc_post_bv_setup(mixer);
+ mdp4_mixer_csc_pre_lv_setup(mixer);
+ mdp4_mixer_csc_post_lv_setup(mixer);
+ }
}
char gc_lut[] = {
diff --git a/drivers/video/msm/mdp4_wfd_writeback_panel.c b/drivers/video/msm/mdp4_wfd_writeback_panel.c
index 77f714c..32b0669 100644
--- a/drivers/video/msm/mdp4_wfd_writeback_panel.c
+++ b/drivers/video/msm/mdp4_wfd_writeback_panel.c
@@ -39,7 +39,7 @@
.type = WRITEBACK_PANEL,
.xres = 800,
.yres = 480,
- .pdest = DISPLAY_2,
+ .pdest = DISPLAY_3,
.wait_cycle = 0,
.bpp = 24,
.fb_num = 1,
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 9ae1d9c5..2eb9257 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -297,6 +297,10 @@
mdp4_stat.intr_overlay1);
bp += len;
dlen -= len;
+ len = snprintf(bp, dlen, "int_overlay1: %08lu\n",
+ mdp4_stat.intr_overlay2);
+ bp += len;
+ dlen -= len;
len = snprintf(bp, dlen, "int_dmap: %08lu\t",
mdp4_stat.intr_dma_p);
diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h
index 3f70dac..627f802 100644
--- a/drivers/video/msm/mhl_api.h
+++ b/drivers/video/msm/mhl_api.h
@@ -14,7 +14,7 @@
#ifndef __MHL_API_H__
#define __MHL_API_H__
-#ifdef CONFIG_MHL
+#ifdef CONFIG_FB_MSM_HDMI_MHL
bool mhl_is_connected(void);
#else
static bool mhl_is_connected(void)
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index 5e2e515..caa4114 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -432,11 +432,8 @@
static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
{
struct mipi_panel_info *mipi;
- static int bl_level_old;
mipi = &mfd->panel_info.mipi;
- if (bl_level_old == mfd->bl_level)
- return;
mutex_lock(&mfd->dma->ov_mutex);
if (mdp4_overlay_dsi_state_get() <= ST_DSI_SUSPEND) {
@@ -451,7 +448,6 @@
led_pwm1[1] = (unsigned char)(mfd->bl_level);
mipi_dsi_cmds_tx(mfd, &novatek_tx_buf, novatek_cmd_backlight_cmds,
ARRAY_SIZE(novatek_cmd_backlight_cmds));
- bl_level_old = mfd->bl_level;
mutex_unlock(&mfd->dma->ov_mutex);
return;
}
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 59c2afe..ab91e41 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -665,16 +665,31 @@
}
#endif
+static int unset_bl_level, bl_updated;
+static int bl_level_old;
+
void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl)
{
struct msm_fb_panel_data *pdata;
+ if (!mfd->panel_power_on || !bl_updated) {
+ unset_bl_level = bkl_lvl;
+ return;
+ } else {
+ unset_bl_level = 0;
+ }
+
pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if ((pdata) && (pdata->set_backlight)) {
down(&mfd->sem);
+ if (bl_level_old == bkl_lvl) {
+ up(&mfd->sem);
+ return;
+ }
mfd->bl_level = bkl_lvl;
pdata->set_backlight(mfd);
+ bl_level_old = mfd->bl_level;
up(&mfd->sem);
}
}
@@ -728,6 +743,7 @@
mfd->op_enable = FALSE;
curr_pwr_state = mfd->panel_power_on;
mfd->panel_power_on = FALSE;
+ bl_updated = 0;
msleep(16);
ret = pdata->off(mfd->pdev);
@@ -1393,6 +1409,7 @@
struct mdp_dirty_region dirty;
struct mdp_dirty_region *dirtyPtr = NULL;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msm_fb_panel_data *pdata;
if ((!mfd->op_enable) || (!mfd->panel_power_on))
return -EPERM;
@@ -1459,6 +1476,19 @@
mdp_dma_pan_update(info);
up(&msm_fb_pan_sem);
+ if (unset_bl_level && !bl_updated) {
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->
+ dev.platform_data;
+ if ((pdata) && (pdata->set_backlight)) {
+ down(&mfd->sem);
+ mfd->bl_level = unset_bl_level;
+ pdata->set_backlight(mfd);
+ bl_level_old = unset_bl_level;
+ up(&mfd->sem);
+ }
+ bl_updated = 1;
+ }
+
++mfd->panel_info.frame_count;
return 0;
}
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index de2734d..9ee8972 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -166,6 +166,8 @@
struct completion msmfb_update_notify;
struct completion msmfb_no_update_notify;
u32 ov_start, ov_end;
+ void *writeback_overlay0_phys;
+ void *writeback_overlay1_phys;
struct mutex writeback_mutex;
struct mutex unregister_mutex;
struct list_head writeback_busy_queue;
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 82ac915..d66d802 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -51,6 +51,7 @@
typedef enum {
DISPLAY_1 = 0, /* attached as first device */
DISPLAY_2, /* attached on second device */
+ DISPLAY_3, /* attached on third writeback device */
MAX_PHYS_TARGET_NUM,
} DISP_TARGET_PHYS;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 1144166..051d32dc 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -253,6 +253,7 @@
u32 mb_info_enable;
u32 ext_enc_control_val;
u32 num_references_for_p_frame;
+ u32 closed_gop;
};
struct ddl_decoder_data {
struct ddl_codec_data_hdr hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index f10abc5..6078821 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -237,7 +237,6 @@
struct ddl_frame_data_tag *frame;
u32 luma[DDL_MAX_BUFFER_COUNT], chroma[DDL_MAX_BUFFER_COUNT];
u32 mv[DDL_MAX_BUFFER_COUNT], luma_size, i, dpb;
-
frame = &decoder->dp_buf.dec_pic_buffers[0];
luma_size = ddl_get_yuv_buf_size(decoder->frame_size.width,
decoder->frame_size.height, DDL_YUV_BUF_TYPE_TILE);
@@ -248,9 +247,16 @@
dpb = DDL_MAX_BUFFER_COUNT;
for (i = 0; i < dpb; i++) {
if (frame[i].vcd_frm.virtual) {
- memset(frame[i].vcd_frm.virtual, 0x10101010, luma_size);
- memset(frame[i].vcd_frm.virtual + luma_size, 0x80808080,
+ if (luma_size <= frame[i].vcd_frm.alloc_len) {
+ memset(frame[i].vcd_frm.virtual,
+ 0x10101010, luma_size);
+ memset(frame[i].vcd_frm.virtual + luma_size,
+ 0x80808080,
frame[i].vcd_frm.alloc_len - luma_size);
+ } else {
+ DDL_MSG_ERROR("luma size error");
+ return VCD_ERR_FAIL;
+ }
}
luma[i] = DDL_OFFSET(ddl_context->dram_base_a.
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 5485335..d2969b6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1540,6 +1540,8 @@
encoder->hdr_ext_control = 0;
encoder->mb_info_enable = false;
encoder->num_references_for_p_frame = DDL_MIN_NUM_REF_FOR_P_FRAME;
+ if (encoder->codec.codec == VCD_CODEC_MPEG4)
+ encoder->closed_gop = true;
ddl_set_default_metadata_flag(ddl);
ddl_set_default_encoder_buffer_req(encoder);
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index ac05364..f8977e9 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -204,6 +204,9 @@
#define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_BMSK 0x00000001
#define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_SHFT 0
+#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK 0x40
+#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT 6
+
#define DDL_MEM_WRITE_32(base, offset, val) ddl_mem_write_32(\
(u32 *) ((u8 *) (base)->align_virtual_addr + (offset)), (val))
#define DDL_MEM_READ_32(base, offset) ddl_mem_read_32(\
@@ -348,7 +351,8 @@
void vidc_sm_set_extended_encoder_control(struct ddl_buf_addr
*shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode,
- u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable)
+ u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
+ u32 closed_gop_enable)
{
u32 enc_ctrl;
@@ -366,7 +370,10 @@
VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK) |
VIDC_SETFIELD((cpcfc_enable) ? 1 : 0,
VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT,
- VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK);
+ VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK) |
+ VIDC_SETFIELD(closed_gop_enable,
+ VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
+ VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK);
DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 8a4b598..78bfee5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -100,7 +100,7 @@
void vidc_sm_set_extended_encoder_control(
struct ddl_buf_addr *shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode, u32 seq_hdr_in_band,
- u32 vbv_buffer_size, u32 cpcfc_enable);
+ u32 vbv_buffer_size, u32 cpcfc_enable, u32 closed_gop_enable);
void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 521e3b6..43aba2e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -126,12 +126,13 @@
if (addr->alloc_handle) {
ion_free(ddl_context->video_ion_client,
addr->alloc_handle);
+ addr->alloc_handle = NULL;
}
- } else
+ } else {
free_contiguous_memory_by_paddr(
(unsigned long)addr->alloced_phys_addr);
- addr->alloc_handle = NULL;
- addr->alloced_phys_addr = (phys_addr_t)NULL;
+ addr->alloced_phys_addr = (phys_addr_t)NULL;
+ }
bail_out:
return NULL;
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 5ae8d09..ab50258 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -541,7 +541,7 @@
vidc_sm_set_extended_encoder_control(&ddl->shared_mem
[ddl->command_channel], hdr_ext_control,
r_cframe_skip, false, 0,
- h263_cpfc_enable);
+ h263_cpfc_enable, encoder->closed_gop);
vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
[ddl->command_channel],
encoder->target_bit_rate.target_bitrate);
@@ -818,7 +818,8 @@
if (vidc_msg_timing)
ddl_set_core_start_time(__func__, DEC_OP_TIME);
ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_INIT);
- ddl_decoder_dpb_init(ddl);
+ if (ddl_decoder_dpb_init(ddl) == VCD_ERR_FAIL)
+ return VCD_ERR_FAIL;
DDL_MSG_LOW("ddl_state_transition: %s ~~> DDL_CLIENT_WAIT_FOR_DPBDONE",
ddl_get_state_string(ddl->client_state));
ddl->client_state = DDL_CLIENT_WAIT_FOR_DPBDONE;
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
index d27b354..7c68d63 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
@@ -474,8 +474,7 @@
}
if (!input_frame ||
!input_frame->vcd_frm.physical ||
- ddl->codec_data.encoder.input_buf_req.sz !=
- input_frame->vcd_frm.data_len) {
+ !input_frame->vcd_frm.data_len) {
VIDC_LOGERR_STRING("ddl_enc_frame:Bad_input_params");
return VCD_ERR_ILLEGAL_PARM;
}
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
index d1b1952..6d3c666 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
@@ -840,6 +840,11 @@
ddl, property_hdr, property_value);
break;
}
+ case VCD_I_META_BUFFER_MODE:
+ {
+ vcd_status = VCD_S_SUCCESS;
+ break;
+ }
default:
{
vcd_status = VCD_ERR_ILLEGAL_OP;
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index ee38098..47f2db5 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -597,6 +597,9 @@
case VEN_LEVEL_H264_3p1:
level.level = VCD_LEVEL_H264_3p1;
break;
+ case VEN_LEVEL_H264_3p2:
+ level.level = VCD_LEVEL_H264_3p2;
+ break;
case VEN_LEVEL_H264_4:
level.level = VCD_LEVEL_H264_4;
break;
@@ -700,7 +703,7 @@
profile_level->level = VEN_LEVEL_H264_3p1;
break;
case VCD_LEVEL_H264_3p2:
- status = false;
+ profile_level->level = VEN_LEVEL_H264_3p2;
break;
case VCD_LEVEL_H264_4:
profile_level->level = VEN_LEVEL_H264_4;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 1217f1f..05df44f 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -450,7 +450,7 @@
unsigned long length)
{
unsigned long len, phys_addr;
- struct file *file;
+ struct file *file = NULL;
u32 *num_of_buffers = NULL;
u32 i, flags;
struct buf_addr_table *buf_addr_table;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 4900e9c..9c43f56 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -368,6 +368,7 @@
header-y += tipc.h
header-y += tipc_config.h
header-y += toshiba.h
+header-y += tspp.h
header-y += tty.h
header-y += types.h
header-y += udf_fs_i.h
diff --git a/include/linux/android_pmem.h b/include/linux/android_pmem.h
index c0291969..ab96379 100644
--- a/include/linux/android_pmem.h
+++ b/include/linux/android_pmem.h
@@ -157,12 +157,12 @@
* function to be called when the number of allocations goes from
* 0 -> 1
*/
- void (*request_region)(void *);
+ int (*request_region)(void *);
/*
* function to be called when the number of allocations goes from
* 1 -> 0
*/
- void (*release_region)(void *);
+ int (*release_region)(void *);
/*
* function to be called upon pmem registration
*/
@@ -171,6 +171,10 @@
* indicates that this region should be mapped/unmaped as needed
*/
int map_on_demand;
+ /*
+ * indicates this pmem may be reused via fmem
+ */
+ int reusable;
};
int pmem_setup(struct android_pmem_platform_data *pdata,
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 5c94a3c..bdbaffd 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -41,9 +41,16 @@
#define AO8960_MACHINE_ID 87
#define MSM8660_MACHINE_ID 71
#define APQ8064_MACHINE_ID 109
+#define MSM8930_MACHINE_ID 116
+#define MSM8630_MACHINE_ID 117
+#define MSM8230_MACHINE_ID 118
+#define APQ8030_MACHINE_ID 119
+#define MSM8627_MACHINE_ID 120
+#define MSM8227_MACHINE_ID 121
#define APQ8060_TOOLS_ID 4062
#define AO8960_TOOLS_ID 4064
#define APQ8064_TOOLS_ID 4072
+#define MSM8930_TOOLS_ID 4072
#define MSG_MASK_0 (0x00000001)
#define MSG_MASK_1 (0x00000002)
diff --git a/include/linux/export.h b/include/linux/export.h
new file mode 100644
index 0000000..696c0f4
--- /dev/null
+++ b/include/linux/export.h
@@ -0,0 +1,89 @@
+#ifndef _LINUX_EXPORT_H
+#define _LINUX_EXPORT_H
+/*
+ * Export symbols from the kernel to modules. Forked from module.h
+ * to reduce the amount of pointless cruft we feed to gcc when only
+ * exporting a simple symbol or two.
+ *
+ * If you feel the need to add #include <linux/foo.h> to this file
+ * then you are doing something wrong and should go away silently.
+ */
+
+/* Some toolchains use a `_' prefix for all user symbols. */
+#ifdef CONFIG_SYMBOL_PREFIX
+#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX
+#else
+#define MODULE_SYMBOL_PREFIX ""
+#endif
+
+struct kernel_symbol
+{
+ unsigned long value;
+ const char *name;
+};
+
+#ifdef MODULE
+extern struct module __this_module;
+#define THIS_MODULE (&__this_module)
+#else
+#define THIS_MODULE ((struct module *)0)
+#endif
+
+#ifdef CONFIG_MODULES
+
+#ifndef __GENKSYMS__
+#ifdef CONFIG_MODVERSIONS
+/* Mark the CRC weak since genksyms apparently decides not to
+ * generate a checksums for some symbols */
+#define __CRC_SYMBOL(sym, sec) \
+ extern void *__crc_##sym __attribute__((weak)); \
+ static const unsigned long __kcrctab_##sym \
+ __used \
+ __attribute__((section("___kcrctab" sec "+" #sym), unused)) \
+ = (unsigned long) &__crc_##sym;
+#else
+#define __CRC_SYMBOL(sym, sec)
+#endif
+
+/* For every exported symbol, place a struct in the __ksymtab section */
+#define __EXPORT_SYMBOL(sym, sec) \
+ extern typeof(sym) sym; \
+ __CRC_SYMBOL(sym, sec) \
+ static const char __kstrtab_##sym[] \
+ __attribute__((section("__ksymtab_strings"), aligned(1))) \
+ = MODULE_SYMBOL_PREFIX #sym; \
+ static const struct kernel_symbol __ksymtab_##sym \
+ __used \
+ __attribute__((section("___ksymtab" sec "+" #sym), unused)) \
+ = { (unsigned long)&sym, __kstrtab_##sym }
+
+#define EXPORT_SYMBOL(sym) \
+ __EXPORT_SYMBOL(sym, "")
+
+#define EXPORT_SYMBOL_GPL(sym) \
+ __EXPORT_SYMBOL(sym, "_gpl")
+
+#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
+ __EXPORT_SYMBOL(sym, "_gpl_future")
+
+#ifdef CONFIG_UNUSED_SYMBOLS
+#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
+#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
+#else
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
+#endif
+
+#endif /* __GENKSYMS__ */
+
+#else /* !CONFIG_MODULES... */
+
+#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
+
+#endif /* CONFIG_MODULES */
+
+#endif /* _LINUX_EXPORT_H */
diff --git a/include/linux/fmem.h b/include/linux/fmem.h
index d4d5cc7..c9e36b5 100644
--- a/include/linux/fmem.h
+++ b/include/linux/fmem.h
@@ -15,6 +15,8 @@
#ifndef _FMEM_H_
#define _FMEM_H_
+#include <linux/vmalloc.h>
+
struct fmem_platform_data {
unsigned long phys;
unsigned long size;
@@ -23,6 +25,7 @@
struct fmem_data {
unsigned long phys;
void *virt;
+ struct vm_struct *area;
unsigned long size;
};
@@ -33,9 +36,22 @@
FMEM_O_STATE,
};
+#ifdef CONFIG_QCACHE
struct fmem_data *fmem_get_info(void);
int fmem_set_state(enum fmem_state);
void lock_fmem_state(void);
void unlock_fmem_state(void);
+void *fmem_map_virtual_area(int cacheability);
+void fmem_unmap_virtual_area(void);
+#else
+static inline struct fmem_data *fmem_get_info(void) { return NULL; }
+static inline int fmem_set_state(enum fmem_state f) { return -ENODEV; }
+static inline void lock_fmem_state(void) { return; }
+static inline void unlock_fmem_state(void) { return; }
+static inline void *fmem_map_virtual_area(int cacheability) { return NULL; }
+static inline void fmem_unmap_virtual_area(void) { return; }
+#endif
+int request_fmem_c_region(void *unused);
+int release_fmem_c_region(void *unused);
#endif
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index c425343..d61b934 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -35,6 +35,9 @@
unsigned int y_size;
unsigned long irqflags;
bool i2c_pull_up;
+ bool digital_pwr_regulator;
+ int reset_gpio;
+ int irq_gpio;
u8(*read_chg) (void);
int (*init_hw) (bool);
diff --git a/include/linux/input/pmic8058-keypad.h b/include/linux/input/pmic8058-keypad.h
deleted file mode 100644
index a2fd6ac..0000000
--- a/include/linux/input/pmic8058-keypad.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __PMIC8058_KEYPAD_H__
-#define __PMIC8058_KEYPAD_H__
-
-#include <linux/input/matrix_keypad.h>
-
-/*
- * NOTE: Assumption of maximum of five revisions
- * of PMIC8058 chip.
- */
-#define MAX_PM8058_REVS 0x5
-
-struct pmic8058_keypad_data {
- const struct matrix_keymap_data *keymap_data;
-
- const char *input_name;
- const char *input_phys_device;
-
- unsigned int num_cols;
- unsigned int num_rows;
-
- unsigned int rows_gpio_start;
- unsigned int cols_gpio_start;
-
- unsigned int debounce_ms[MAX_PM8058_REVS];
- unsigned int scan_delay_ms;
- unsigned int row_hold_ns;
-
- int keymap_size;
- const unsigned int *keymap;
-
- unsigned int wakeup;
- unsigned int rep;
-};
-
-#endif /*__PMIC8058_KEYPAD_H__ */
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index d042e2a..ed1f112 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -53,6 +53,7 @@
unsigned long iova);
int (*domain_has_cap)(struct iommu_domain *domain,
unsigned long cap);
+ phys_addr_t (*get_pt_base_addr)(struct iommu_domain *domain);
};
#ifdef CONFIG_IOMMU_API
@@ -77,6 +78,7 @@
unsigned long iova);
extern int iommu_domain_has_cap(struct iommu_domain *domain,
unsigned long cap);
+extern phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain);
#else /* CONFIG_IOMMU_API */
@@ -146,6 +148,10 @@
return 0;
}
+static inline phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain)
+{
+ return 0;
+}
#endif /* CONFIG_IOMMU_API */
#endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index b396369..2cced6d 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -27,8 +27,8 @@
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
* @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
* @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
- * carveout heap, allocations are physically
- * contiguous
+ * carveout heap, allocations are physically
+ * contiguous
* @ION_HEAP_END: helper for iterating over heaps
*/
enum ion_heap_type {
@@ -97,8 +97,8 @@
/**
* struct ion_platform_heap - defines a heap in the given platform
* @type: type of the heap from ion_heap_type enum
- * @id: unique identifier for heap. When allocating (lower numbers
- * will be allocated from first)
+ * @id: unique identifier for heap. When allocating (lower numbers
+ * will be allocated from first)
* @name: used for debug purposes
* @base: base address of heap in physical memory if applicable
* @size: size of the heap in bytes if applicable
@@ -117,8 +117,8 @@
ion_phys_addr_t base;
size_t size;
enum ion_memory_types memory_type;
- void (*request_region)(void *);
- void (*release_region)(void *);
+ int (*request_region)(void *);
+ int (*release_region)(void *);
void *(*setup_region)(void);
};
@@ -136,8 +136,8 @@
*/
struct ion_platform_data {
int nr;
- void (*request_region)(void *);
- void (*release_region)(void *);
+ int (*request_region)(void *);
+ int (*release_region)(void *);
void *(*setup_region)(void);
struct ion_platform_heap heaps[];
};
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index e807ad6..99834e58 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -47,6 +47,7 @@
* of the irq_domain is responsible for allocating the array of
* irq_desc structures.
* @nr_irq: Number of irqs managed by the irq domain
+ * @hwirq_base: Starting number for hwirqs managed by the irq domain
* @ops: pointer to irq_domain methods
* @priv: private data pointer for use by owner. Not touched by irq_domain
* core code.
@@ -57,6 +58,7 @@
struct list_head list;
unsigned int irq_base;
unsigned int nr_irq;
+ unsigned int hwirq_base;
const struct irq_domain_ops *ops;
void *priv;
struct device_node *of_node;
@@ -72,14 +74,27 @@
static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
unsigned long hwirq)
{
- return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq;
+ if (d->ops->to_irq)
+ return d->ops->to_irq(d, hwirq);
+ if (WARN_ON(hwirq < d->hwirq_base))
+ return 0;
+ return d->irq_base + hwirq - d->hwirq_base;
}
+#define irq_domain_for_each_hwirq(d, hw) \
+ for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++)
+
+#define irq_domain_for_each_irq(d, hw, irq) \
+ for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
+ hw < d->hwirq_base + d->nr_irq; \
+ hw++, irq = irq_domain_to_irq(d, hw))
+
extern void irq_domain_add(struct irq_domain *domain);
extern void irq_domain_del(struct irq_domain *domain);
#endif /* CONFIG_IRQ_DOMAIN */
#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
+extern struct irq_domain_ops irq_domain_simple_ops;
extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
extern void irq_domain_generate_simple(const struct of_device_id *match,
u64 phys_base, unsigned int irq_start);
diff --git a/include/linux/lglock.h b/include/linux/lglock.h
index f549056..87f402c 100644
--- a/include/linux/lglock.h
+++ b/include/linux/lglock.h
@@ -22,6 +22,7 @@
#include <linux/spinlock.h>
#include <linux/lockdep.h>
#include <linux/percpu.h>
+#include <linux/cpu.h>
/* can make br locks by using local lock for read side, global lock for write */
#define br_lock_init(name) name##_lock_init()
@@ -72,9 +73,31 @@
#define DEFINE_LGLOCK(name) \
\
+ DEFINE_SPINLOCK(name##_cpu_lock); \
+ cpumask_t name##_cpus __read_mostly; \
DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \
DEFINE_LGLOCK_LOCKDEP(name); \
\
+ static int \
+ name##_lg_cpu_callback(struct notifier_block *nb, \
+ unsigned long action, void *hcpu) \
+ { \
+ switch (action & ~CPU_TASKS_FROZEN) { \
+ case CPU_UP_PREPARE: \
+ spin_lock(&name##_cpu_lock); \
+ cpu_set((unsigned long)hcpu, name##_cpus); \
+ spin_unlock(&name##_cpu_lock); \
+ break; \
+ case CPU_UP_CANCELED: case CPU_DEAD: \
+ spin_lock(&name##_cpu_lock); \
+ cpu_clear((unsigned long)hcpu, name##_cpus); \
+ spin_unlock(&name##_cpu_lock); \
+ } \
+ return NOTIFY_OK; \
+ } \
+ static struct notifier_block name##_lg_cpu_notifier = { \
+ .notifier_call = name##_lg_cpu_callback, \
+ }; \
void name##_lock_init(void) { \
int i; \
LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \
@@ -83,6 +106,11 @@
lock = &per_cpu(name##_lock, i); \
*lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \
} \
+ register_hotcpu_notifier(&name##_lg_cpu_notifier); \
+ get_online_cpus(); \
+ for_each_online_cpu(i) \
+ cpu_set(i, name##_cpus); \
+ put_online_cpus(); \
} \
EXPORT_SYMBOL(name##_lock_init); \
\
@@ -124,9 +152,9 @@
\
void name##_global_lock_online(void) { \
int i; \
- preempt_disable(); \
+ spin_lock(&name##_cpu_lock); \
rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \
- for_each_online_cpu(i) { \
+ for_each_cpu(i, &name##_cpus) { \
arch_spinlock_t *lock; \
lock = &per_cpu(name##_lock, i); \
arch_spin_lock(lock); \
@@ -137,12 +165,12 @@
void name##_global_unlock_online(void) { \
int i; \
rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \
- for_each_online_cpu(i) { \
+ for_each_cpu(i, &name##_cpus) { \
arch_spinlock_t *lock; \
lock = &per_cpu(name##_lock, i); \
arch_spin_unlock(lock); \
} \
- preempt_enable(); \
+ spin_unlock(&name##_cpu_lock); \
} \
EXPORT_SYMBOL(name##_global_unlock_online); \
\
diff --git a/include/linux/mfd/pm8xxx/pm8018.h b/include/linux/mfd/pm8xxx/pm8018.h
index 1093409..e0ec0b4 100644
--- a/include/linux/mfd/pm8xxx/pm8018.h
+++ b/include/linux/mfd/pm8xxx/pm8018.h
@@ -25,7 +25,7 @@
#include <linux/mfd/pm8xxx/rtc.h>
#include <linux/input/pmic8xxx-pwrkey.h>
#include <linux/mfd/pm8xxx/misc.h>
-#include <linux/regulator/pm8018-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/mfd/pm8xxx/pwm.h>
#include <linux/leds-pm8xxx.h>
@@ -64,7 +64,7 @@
struct pm8xxx_rtc_platform_data *rtc_pdata;
struct pm8xxx_pwrkey_platform_data *pwrkey_pdata;
struct pm8xxx_misc_platform_data *misc_pdata;
- struct pm8018_regulator_platform_data *regulator_pdatas;
+ struct pm8xxx_regulator_platform_data *regulator_pdatas;
struct pm8xxx_adc_platform_data *adc_pdata;
int num_regulators;
struct pm8xxx_led_platform_data *leds_pdata;
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 2c2bb09..caed75c 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -26,6 +26,7 @@
#include <linux/mfd/pm8xxx/rtc.h>
#include <linux/input/pmic8xxx-pwrkey.h>
#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/regulator/pm8xxx-regulator.h>
#define PM8038_CORE_DEV_NAME "pm8038-core"
@@ -62,6 +63,8 @@
struct pm8xxx_rtc_platform_data *rtc_pdata;
struct pm8xxx_pwrkey_platform_data *pwrkey_pdata;
struct pm8xxx_misc_platform_data *misc_pdata;
+ struct pm8xxx_regulator_platform_data *regulator_pdatas;
+ int num_regulators;
};
#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 31fa537..eb1005c 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -33,6 +33,20 @@
PM_SMBC_BATT_TEMP_HOT_THR__HIGH
};
+enum pm8921_usb_ov_threshold {
+ PM_USB_OV_5P5V,
+ PM_USB_OV_6V,
+ PM_USB_OV_6P5V,
+ PM_USB_OV_7V,
+};
+
+enum pm8921_usb_debounce_time {
+ PM_USB_BYPASS_DEBOUNCER,
+ PM_USB_DEBOUNCE_20P5MS,
+ PM_USB_DEBOUNCE_40P5MS,
+ PM_USB_DEBOUNCE_80P5MS,
+};
+
/**
* struct pm8921_charger_platform_data -
* @safety_time: max charging time in minutes incl. fast and trkl
@@ -247,6 +261,31 @@
*/
void unregister_external_dc_charger(struct ext_chg_pm8921 *ext);
+/**
+ * pm8921_usb_ovp_set_threshold -
+ * Set the usb threshold as defined in by
+ * enum usb_ov_threshold
+ */
+int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov);
+
+/**
+ * pm8921_usb_ovp_set_hystersis -
+ * @ms: the debounce time enum
+ *
+ * Sets the debounce time for usb insertion/removal detection
+ *
+ */
+int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms);
+
+/**
+ * pm8921_usb_ovp_disable -
+ *
+ * when disabled there is no over voltage protection. The usb voltage is
+ * fed to the pmic as is. This should be disabled only when there is
+ * over voltage protection circuitry present outside the pmic chip.
+ *
+ */
+int pm8921_usb_ovp_disable(int disable);
#else
static inline void pm8921_charger_vbus_draw(unsigned int mA)
{
@@ -308,6 +347,18 @@
{
pr_err("%s.not implemented.\n", __func__);
}
+static inline int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
+{
+ return -ENXIO;
+}
+static inline int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
+{
+ return -ENXIO;
+}
+static inline int pm8921_usb_ovp_disable(int disable)
+{
+ return -ENXIO;
+}
#endif
#endif
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index d4cdc3c..35792d5 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -29,7 +29,7 @@
#include <linux/mfd/pm8xxx/batt-alarm.h>
#include <linux/input/pmic8xxx-pwrkey.h>
#include <linux/input/pmic8xxx-keypad.h>
-#include <linux/regulator/pm8921-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/mfd/pm8xxx/pm8921-bms.h>
@@ -124,7 +124,7 @@
struct pm8921_charger_platform_data *charger_pdata;
struct pm8921_bms_platform_data *bms_pdata;
struct pm8xxx_misc_platform_data *misc_pdata;
- struct pm8921_regulator_platform_data *regulator_pdatas;
+ struct pm8xxx_regulator_platform_data *regulator_pdatas;
int num_regulators;
struct pm8xxx_adc_platform_data *adc_pdata;
struct pm8xxx_led_platform_data *leds_pdata;
diff --git a/include/linux/mfd/pm8xxx/regulator.h b/include/linux/mfd/pm8xxx/regulator.h
new file mode 100644
index 0000000..38700cb
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/regulator.h
@@ -0,0 +1,258 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MFD_PM8XXX_REGULATOR_H__
+#define __MFD_PM8XXX_REGULATOR_H__
+
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/pm8xxx-regulator.h>
+
+/**
+ * enum pm8xxx_regulator_type - possible PM8XXX voltage regulator types
+ * %PM8XXX_REGULATOR_TYPE_PLDO: PMOS low drop-out linear regulator
+ * %PM8XXX_REGULATOR_TYPE_NLDO: NMOS low drop-out linear regulator
+ * %PM8XXX_REGULATOR_TYPE_NLDO1200: NMOS low drop-out linear regulator
+ * capable of supplying up to 1200 mA
+ * %PM8XXX_REGULATOR_TYPE_SMPS: switched-mode power supply (buck)
+ * %PM8XXX_REGULATOR_TYPE_FTSMPS: fast transient switched-mode power
+ * supply (buck)
+ * %PM8XXX_REGULATOR_TYPE_VS: voltage switch capable of sourcing 100mA
+ * %PM8XXX_REGULATOR_TYPE_VS300: voltage switch capable of sourcing 300mA
+ * %PM8XXX_REGULATOR_TYPE_NCP: negative charge pump
+ * %PM8XXX_REGULATOR_TYPE_MAX: used internally for error checking; not
+ * a valid regulator type.
+ *
+ * Each of these has a different register control interface.
+ */
+enum pm8xxx_regulator_type {
+ PM8XXX_REGULATOR_TYPE_PLDO,
+ PM8XXX_REGULATOR_TYPE_NLDO,
+ PM8XXX_REGULATOR_TYPE_NLDO1200,
+ PM8XXX_REGULATOR_TYPE_SMPS,
+ PM8XXX_REGULATOR_TYPE_FTSMPS,
+ PM8XXX_REGULATOR_TYPE_VS,
+ PM8XXX_REGULATOR_TYPE_VS300,
+ PM8XXX_REGULATOR_TYPE_NCP,
+ PM8XXX_REGULATOR_TYPE_MAX,
+};
+
+/**
+ * struct pm8xxx_vreg - regulator configuration and state data used by the
+ * pm8xxx-regulator driver
+ * @rdesc: regulator description
+ * @rdesc_pc: pin control regulator description. rdesc_pc.name == NULL
+ * implies that there is no pin control version of this
+ * regulator.
+ * @type: regulator type
+ * @hpm_min_load: minimum load in uA that will result in the regulator
+ * being set to high power mode
+ * @ctrl_addr: control register SSBI address
+ * @test_addr: test register SSBI address (not needed for all types)
+ * @clk_ctrl_addr: clock control register SSBI address (only used by SMPS
+ * type regulators)
+ * @sleep_ctrl_addr: sleep control register SSBI address (only used by SMPS
+ * type regulators)
+ * @pfm_ctrl_addr: pulse-frequency modulation control register SSBI address
+ * (only used by FTSMPS type regulators)
+ * @pwr_cnfg_addr: power configuration register SSBI address (only used by
+ * FTSMPS type regulators)
+ * @pdata: this platform data struct is filled based using the
+ * platform data pointed to in a core platform data struct
+ * @rdev: pointer to regulator device which is created with
+ * regulator_register
+ * @rdev_pc: pointer to pin controlled regulator device which is
+ * created with regulator_register
+ * @dev: pointer to pm8xxx-regulator device
+ * @dev_pc: pointer to pin control pm8xxx-regulator device
+ * @pc_lock: mutex lock to handle sharing between pin controlled and
+ * non-pin controlled versions of a given regulator. Note,
+ * this lock must be initialized in the PMIC core driver.)
+ * @save_uV: current regulator voltage in uV
+ * @mode: current mode of the regulator
+ * @write_count: number of SSBI writes that have taken place for this
+ * regulator. This is used for debug printing to determine
+ * if a given operation is redundant.
+ * @prev_write_count: number of SSBI writes that have taken place for this
+ * regulator at the start of an operation. This is used for
+ * debug printing to determine if a given operation is
+ * redundant.
+ * @is_enabled: true if the regulator is currently enabled, false if not
+ * @is_enabled_pc: true if the pin controlled version of the regulator is
+ * currently enabled (i.e. pin control is active), false if
+ * not
+ * @test_reg: last value read from or written to each of the banks of
+ * the test register
+ * @ctrl_reg: last value read from or written to the control register
+ * @clk_ctrl_reg: last value read from or written to the clock control
+ * register
+ * @sleep_ctrl_reg: last value read from or written to the sleep control
+ * register
+ * @pfm_ctrl_reg: last value read from or written to the PFM control
+ * register
+ * @pwr_cnfg_reg: last value read from or written to the power
+ * configuration register
+ *
+ * This data structure should only need to be instantiated in a PMIC core driver
+ * It is used to specify PMIC specific as opposed to board specific
+ * configuration data. It is also used to hold all state variables needed by
+ * the pm8xxx-regulator driver as these variables need to be shared between
+ * pin controlled and non-pin controlled versions of a given regulator, which
+ * are probed separately.
+ */
+struct pm8xxx_vreg {
+ /* Configuration data */
+ struct regulator_desc rdesc;
+ struct regulator_desc rdesc_pc;
+ enum pm8xxx_regulator_type type;
+ const int hpm_min_load;
+ const u16 ctrl_addr;
+ const u16 test_addr;
+ const u16 clk_ctrl_addr;
+ const u16 sleep_ctrl_addr;
+ const u16 pfm_ctrl_addr;
+ const u16 pwr_cnfg_addr;
+ /* State data */
+ struct pm8xxx_regulator_platform_data pdata;
+ struct regulator_dev *rdev;
+ struct regulator_dev *rdev_pc;
+ struct device *dev;
+ struct device *dev_pc;
+ struct mutex pc_lock;
+ int save_uV;
+ int mode;
+ u32 write_count;
+ u32 prev_write_count;
+ bool is_enabled;
+ bool is_enabled_pc;
+ u8 test_reg[REGULATOR_TEST_BANKS_MAX];
+ u8 ctrl_reg;
+ u8 clk_ctrl_reg;
+ u8 sleep_ctrl_reg;
+ u8 pfm_ctrl_reg;
+ u8 pwr_cnfg_reg;
+};
+
+/**
+ * struct pm8xxx_regulator_core_platform_data - platform data specified in a
+ * PMIC core driver and utilized in the pm8xxx-regulator driver
+* @vreg: pointer to pm8xxx_vreg data structure that may be shared
+* between pin controlled and non-pin controlled versions
+* of a given regulator. Note that this data must persist
+* as long as the regulator device is in use.
+* @pdata: pointer to platform data passed in from a board file
+* @is_pin_controlled: true if the regulator driver represents the pin control
+* portion of a regulator, false if not.
+*
+* This data structure should only be needed in a PMIC core driver.
+*/
+struct pm8xxx_regulator_core_platform_data {
+ struct pm8xxx_vreg *vreg;
+ struct pm8xxx_regulator_platform_data *pdata;
+ bool is_pin_controlled;
+};
+
+/* Helper macros */
+#define PLDO(_name, _pc_name, _ctrl_addr, _test_addr, _hpm_min_load) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_PLDO, \
+ .ctrl_addr = _ctrl_addr, \
+ .test_addr = _test_addr, \
+ .hpm_min_load = PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _pc_name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#define NLDO(_name, _pc_name, _ctrl_addr, _test_addr, _hpm_min_load) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_NLDO, \
+ .ctrl_addr = _ctrl_addr, \
+ .test_addr = _test_addr, \
+ .hpm_min_load = PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _pc_name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#define NLDO1200(_name, _ctrl_addr, _test_addr, _hpm_min_load) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_NLDO1200, \
+ .ctrl_addr = _ctrl_addr, \
+ .test_addr = _test_addr, \
+ .hpm_min_load = PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .rdesc.name = _name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#define SMPS(_name, _pc_name, _ctrl_addr, _test_addr, _clk_ctrl_addr, \
+ _sleep_ctrl_addr, _hpm_min_load) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_SMPS, \
+ .ctrl_addr = _ctrl_addr, \
+ .test_addr = _test_addr, \
+ .clk_ctrl_addr = _clk_ctrl_addr, \
+ .sleep_ctrl_addr = _sleep_ctrl_addr, \
+ .hpm_min_load = PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _pc_name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#define FTSMPS(_name, _pwm_ctrl_addr, _fts_cnfg1_addr, _pfm_ctrl_addr, \
+ _pwr_cnfg_addr, _hpm_min_load) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_FTSMPS, \
+ .ctrl_addr = _pwm_ctrl_addr, \
+ .test_addr = _fts_cnfg1_addr, \
+ .pfm_ctrl_addr = _pfm_ctrl_addr, \
+ .pwr_cnfg_addr = _pwr_cnfg_addr, \
+ .hpm_min_load = PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .rdesc.name = _name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#define VS(_name, _pc_name, _ctrl_addr) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_VS, \
+ .ctrl_addr = _ctrl_addr, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _pc_name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#define VS300(_name, _ctrl_addr) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_VS300, \
+ .ctrl_addr = _ctrl_addr, \
+ .rdesc.name = _name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#define NCP(_name, _ctrl_addr) \
+ { \
+ .type = PM8XXX_REGULATOR_TYPE_NCP, \
+ .ctrl_addr = _ctrl_addr, \
+ .rdesc.name = _name, \
+ .write_count = 0, \
+ .prev_write_count = -1, \
+ }
+
+#endif
diff --git a/include/linux/mfd/pmic8058.h b/include/linux/mfd/pmic8058.h
index 0699c46..ff7a329 100644
--- a/include/linux/mfd/pmic8058.h
+++ b/include/linux/mfd/pmic8058.h
@@ -108,20 +108,6 @@
bool charger_data_valid;
};
-enum pon_config{
- DISABLE_HARD_RESET = 0,
- SHUTDOWN_ON_HARD_RESET,
- RESTART_ON_HARD_RESET,
- MAX_PON_CONFIG,
-};
-
-enum pm8058_smpl_delay {
- PM8058_SMPL_DELAY_0p5,
- PM8058_SMPL_DELAY_1p0,
- PM8058_SMPL_DELAY_1p5,
- PM8058_SMPL_DELAY_2p0,
-};
-
struct pm8058_platform_data {
struct pm8xxx_mpp_platform_data *mpp_pdata;
struct pm8xxx_keypad_platform_data *keypad_pdata;
@@ -144,19 +130,4 @@
struct pmic8058_charger_data *charger_pdata;
};
-int pm8058_hard_reset_config(enum pon_config config);
-
-/**
- * pm8058_stay_on - enables stay_on feature
- *
- * PMIC stay-on feature allows PMIC to ignore MSM PS_HOLD=low
- * signal so that some special functions like debugging could be
- * performed.
- *
- * This feature should not be used in any product release.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_stay_on(void);
-
#endif /* __MFD_PMIC8058_H__ */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 29f5a63..9e82abf8 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -177,6 +177,7 @@
#define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */
#define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */
#define MMC_CARD_SDXC (1<<6) /* card is SDXC */
+#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -314,6 +315,7 @@
#define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
+#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -322,6 +324,7 @@
#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
/*
* Quirk add/remove for MMC products.
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index b6718e5..279c023 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -166,6 +166,8 @@
extern void mmc_do_release_host(struct mmc_host *host);
extern int mmc_try_claim_host(struct mmc_host *host);
+extern int mmc_detect_card_removed(struct mmc_host *host);
+
/**
* mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d1f478b..d90c779 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -266,6 +266,7 @@
struct delayed_work detect;
struct wake_lock detect_wake_lock;
+ int detect_change; /* card detect flag */
const struct mmc_bus_ops *bus_ops; /* current bus driver */
unsigned int bus_refs; /* reference counter */
diff --git a/include/linux/module.h b/include/linux/module.h
index d9ca2d5..e91cc65 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -16,6 +16,7 @@
#include <linux/kobject.h>
#include <linux/moduleparam.h>
#include <linux/tracepoint.h>
+#include <linux/export.h>
#include <linux/percpu.h>
#include <asm/module.h>
@@ -25,21 +26,8 @@
/* Not Yet Implemented */
#define MODULE_SUPPORTED_DEVICE(name)
-/* Some toolchains use a `_' prefix for all user symbols. */
-#ifdef CONFIG_SYMBOL_PREFIX
-#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX
-#else
-#define MODULE_SYMBOL_PREFIX ""
-#endif
-
#define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN
-struct kernel_symbol
-{
- unsigned long value;
- const char *name;
-};
-
struct modversion_info
{
unsigned long crc;
@@ -96,11 +84,8 @@
extern const struct gtype##_id __mod_##gtype##_table \
__attribute__ ((unused, alias(__stringify(name))))
-extern struct module __this_module;
-#define THIS_MODULE (&__this_module)
#else /* !MODULE */
#define MODULE_GENERIC_TABLE(gtype,name)
-#define THIS_MODULE ((struct module *)0)
#endif
/* Generic info of form tag = "info" */
@@ -216,52 +201,6 @@
struct module *source, *target;
};
-#ifndef __GENKSYMS__
-#ifdef CONFIG_MODVERSIONS
-/* Mark the CRC weak since genksyms apparently decides not to
- * generate a checksums for some symbols */
-#define __CRC_SYMBOL(sym, sec) \
- extern void *__crc_##sym __attribute__((weak)); \
- static const unsigned long __kcrctab_##sym \
- __used \
- __attribute__((section("___kcrctab" sec "+" #sym), unused)) \
- = (unsigned long) &__crc_##sym;
-#else
-#define __CRC_SYMBOL(sym, sec)
-#endif
-
-/* For every exported symbol, place a struct in the __ksymtab section */
-#define __EXPORT_SYMBOL(sym, sec) \
- extern typeof(sym) sym; \
- __CRC_SYMBOL(sym, sec) \
- static const char __kstrtab_##sym[] \
- __attribute__((section("__ksymtab_strings"), aligned(1))) \
- = MODULE_SYMBOL_PREFIX #sym; \
- static const struct kernel_symbol __ksymtab_##sym \
- __used \
- __attribute__((section("___ksymtab" sec "+" #sym), unused)) \
- = { (unsigned long)&sym, __kstrtab_##sym }
-
-#define EXPORT_SYMBOL(sym) \
- __EXPORT_SYMBOL(sym, "")
-
-#define EXPORT_SYMBOL_GPL(sym) \
- __EXPORT_SYMBOL(sym, "_gpl")
-
-#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
- __EXPORT_SYMBOL(sym, "_gpl_future")
-
-
-#ifdef CONFIG_UNUSED_SYMBOLS
-#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
-#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
-#else
-#define EXPORT_UNUSED_SYMBOL(sym)
-#define EXPORT_UNUSED_SYMBOL_GPL(sym)
-#endif
-
-#endif
-
enum module_state
{
MODULE_STATE_LIVE,
@@ -582,11 +521,6 @@
extern int module_get_iter_tracepoints(struct tracepoint_iter *iter);
#else /* !CONFIG_MODULES... */
-#define EXPORT_SYMBOL(sym)
-#define EXPORT_SYMBOL_GPL(sym)
-#define EXPORT_SYMBOL_GPL_FUTURE(sym)
-#define EXPORT_UNUSED_SYMBOL(sym)
-#define EXPORT_UNUSED_SYMBOL_GPL(sym)
/* Given an address, look for it in the exception tables. */
static inline const struct exception_table_entry *
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 611d7b4..72809cf 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -30,6 +30,7 @@
unsigned int dst_y;
unsigned char rotations;
int enable;
+ unsigned int downscale_ratio;
};
struct msm_rotator_data_info {
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index 45199cb..1f264e9 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -92,16 +92,17 @@
#define VEN_LEVEL_H264_2p2 0x10/* H.264 Level 2.2 */
#define VEN_LEVEL_H264_3 0x11/* H.264 Level 3 */
#define VEN_LEVEL_H264_3p1 0x12/* H.264 Level 3.1 */
-#define VEN_LEVEL_H264_4 0x13/* H.264 Level 4 */
+#define VEN_LEVEL_H264_3p2 0x13/* H.264 Level 3.2 */
+#define VEN_LEVEL_H264_4 0x14/* H.264 Level 4 */
-#define VEN_LEVEL_H263_10 0x14/* H.263 Level 10 */
-#define VEN_LEVEL_H263_20 0x15/* H.263 Level 20 */
-#define VEN_LEVEL_H263_30 0x16/* H.263 Level 30 */
-#define VEN_LEVEL_H263_40 0x17/* H.263 Level 40 */
-#define VEN_LEVEL_H263_45 0x18/* H.263 Level 45 */
-#define VEN_LEVEL_H263_50 0x19/* H.263 Level 50 */
-#define VEN_LEVEL_H263_60 0x1A/* H.263 Level 60 */
-#define VEN_LEVEL_H263_70 0x1B/* H.263 Level 70 */
+#define VEN_LEVEL_H263_10 0x15/* H.263 Level 10 */
+#define VEN_LEVEL_H263_20 0x16/* H.263 Level 20 */
+#define VEN_LEVEL_H263_30 0x17/* H.263 Level 30 */
+#define VEN_LEVEL_H263_40 0x18/* H.263 Level 40 */
+#define VEN_LEVEL_H263_45 0x19/* H.263 Level 45 */
+#define VEN_LEVEL_H263_50 0x1A/* H.263 Level 50 */
+#define VEN_LEVEL_H263_60 0x1B/* H.263 Level 60 */
+#define VEN_LEVEL_H263_70 0x1C/* H.263 Level 70 */
/*Entropy coding model selection for H.264 encoder.*/
#define VEN_ENTROPY_MODEL_CAVLC 1
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index c7ccaae..70fe6cab 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -161,6 +161,13 @@
* @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
* using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
* %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ * Following attributes are provided for drivers that generate full Beacon
+ * and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
+ * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
+ * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
+ * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
+ * %NL80211_ATTR_IE_ASSOC_RESP.
* @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
* parameters are like for %NL80211_CMD_SET_BEACON.
* @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
@@ -745,8 +752,12 @@
*
* @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
* a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can
+ * scan with a single scheduled scan request, a wiphy attribute.
* @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
* that can be added to a scan request
+ * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
+ * elements that can be added to a scheduled scan request
*
* @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
* @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -827,18 +838,20 @@
* @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
* event (u16)
* @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- * that protected APs should be used.
+ * that protected APs should be used. This is also used with NEW_BEACON to
+ * indicate that the BSS is to use protection.
*
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- * indicate which unicast key ciphers will be used with the connection
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ * to indicate which unicast key ciphers will be used with the connection
* (an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- * which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- * which WPA version(s) the AP we want to associate with is using
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which group key cipher will be used with the connection (a
+ * u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which WPA version(s) the AP we want to associate with is using
* (a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- * which key management algorithm(s) to use (an array of u32).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which key management algorithm(s) to use (an array of u32).
*
* @NL80211_ATTR_REQ_IE: (Re)association request information elements as
* sent out by the card, for ROAM and successful CONNECT events.
@@ -996,6 +1009,29 @@
* are managed in software: interfaces of these types aren't subject to
* any restrictions in their number or combinations.
*
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
+ * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in
+ * scan, nested array attribute containing an entry for each band, with
+ * the entry being a list of supported rates as defined by IEEE 802.11
+ * 7.3.2.2 but without the length restriction
+ * (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ * and Probe Response (when response to wildcard Probe Request); see
+ * &enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ * This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ * provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ * driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ * Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ * %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ * (Re)Association Response frames when the driver (or firmware) replies to
+ * (Re)Association Request frames.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1194,6 +1230,18 @@
NL80211_ATTR_INTERFACE_COMBINATIONS,
NL80211_ATTR_SOFTWARE_IFTYPES,
+ NL80211_ATTR_REKEY_DATA,
+
+ NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+ NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+
+ NL80211_ATTR_SCAN_SUPP_RATES,
+
+ NL80211_ATTR_HIDDEN_SSID,
+
+ NL80211_ATTR_IE_PROBE_RESP,
+ NL80211_ATTR_IE_ASSOC_RESP,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2361,4 +2409,19 @@
MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
};
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ * Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ * in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ * element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+ NL80211_HIDDEN_SSID_NOT_IN_USE,
+ NL80211_HIDDEN_SSID_ZERO_LEN,
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/platform_data/qcom_crypto_device.h b/include/linux/platform_data/qcom_crypto_device.h
index c6ef40a..08aa784 100644
--- a/include/linux/platform_data/qcom_crypto_device.h
+++ b/include/linux/platform_data/qcom_crypto_device.h
@@ -18,6 +18,7 @@
uint32_t shared_ce_resource;
uint32_t hw_key_support;
uint32_t sha_hmac;
+ void *bus_scale_table;
};
#endif /* __QCOM_CRYPTO_DEVICE__H */
diff --git a/include/linux/pmic8058-batt-alarm.h b/include/linux/pmic8058-batt-alarm.h
deleted file mode 100644
index 0a0ac78..0000000
--- a/include/linux/pmic8058-batt-alarm.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-/*
- * Qualcomm PMIC 8058 Battery Alarm Device driver
- *
- */
-#ifndef __PMIC8058_BATT_ALARM_H__
-#define __PMIC8058_BATT_ALARM_H__
-
-#include <linux/bitops.h>
-
-/**
- * enum pm8058_batt_alarm_hold_time - hold time required for out of range
- * battery voltage needed to trigger a status change. Enum names denote
- * hold time in milliseconds.
- */
-enum pm8058_batt_alarm_hold_time {
- PM8058_BATT_ALARM_HOLD_TIME_0p125_MS = 0,
- PM8058_BATT_ALARM_HOLD_TIME_0p25_MS,
- PM8058_BATT_ALARM_HOLD_TIME_0p5_MS,
- PM8058_BATT_ALARM_HOLD_TIME_1_MS,
- PM8058_BATT_ALARM_HOLD_TIME_2_MS,
- PM8058_BATT_ALARM_HOLD_TIME_4_MS,
- PM8058_BATT_ALARM_HOLD_TIME_8_MS,
- PM8058_BATT_ALARM_HOLD_TIME_16_MS,
-};
-
-/*
- * Bits that are set in the return value of pm8058_batt_alarm_status_read
- * to indicate crossing of the upper or lower threshold.
- */
-#define PM8058_BATT_ALARM_STATUS_BELOW_LOWER BIT(0)
-#define PM8058_BATT_ALARM_STATUS_ABOVE_UPPER BIT(1)
-
-/**
- * pm8058_batt_alarm_state_set - enable or disable the threshold comparators
- * @enable_lower_comparator: 1 = enable comparator, 0 = disable comparator
- * @enable_upper_comparator: 1 = enable comparator, 0 = disable comparator
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_state_set(int enable_lower_comparator,
- int enable_upper_comparator);
-
-/**
- * pm8058_batt_alarm_threshold_set - set the lower and upper alarm thresholds
- * @lower_threshold_mV: battery undervoltage threshold in millivolts
- * @upper_threshold_mV: battery overvoltage threshold in millivolts
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_threshold_set(int lower_threshold_mV,
- int upper_threshold_mV);
-
-/**
- * pm8058_batt_alarm_status_read - get status of both threshold comparators
- *
- * RETURNS: < 0 = error
- * 0 = battery voltage ok
- * BIT(0) set = battery voltage below lower threshold
- * BIT(1) set = battery voltage above upper threshold
- */
-int pm8058_batt_alarm_status_read(void);
-
-/**
- * pm8058_batt_alarm_register_notifier - register a notifier to run when a
- * battery voltage change interrupt fires
- * @nb: notifier block containing callback function to register
- *
- * nb->notifier_call must point to a function of this form -
- * int (*notifier_call)(struct notifier_block *nb, unsigned long status,
- * void *unused);
- * "status" will receive the battery alarm status; "unused" will be NULL.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_register_notifier(struct notifier_block *nb);
-
-/**
- * pm8058_batt_alarm_unregister_notifier - unregister a notifier that is run
- * when a battery voltage change interrupt fires
- * @nb: notifier block containing callback function to unregister
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_unregister_notifier(struct notifier_block *nb);
-
-/**
- * pm8058_batt_alarm_hold_time_set - set hold time of interrupt output *
- * @hold_time: amount of time that battery voltage must remain outside of the
- * threshold range before the battery alarm interrupt triggers
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_hold_time_set(enum pm8058_batt_alarm_hold_time hold_time);
-
-/**
- * pm8058_batt_alarm_pwm_rate_set - set battery alarm update rate *
- * @use_pwm: 1 = use PWM update rate, 0 = comparators always active
- * @clock_scaler: PWM clock scaler = 2 to 9
- * @clock_divider: PWM clock divider = 2 to 8
- *
- * This function sets the rate at which the battery alarm module enables
- * the threshold comparators. The rate is determined by the following equation:
- *
- * f_update = (1024 Hz) / (clock_divider * (2 ^ clock_scaler))
- *
- * Thus, the update rate can range from 0.25 Hz to 128 Hz.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_pwm_rate_set(int use_pwm, int clock_scaler,
- int clock_divider);
-
-#endif /* __PMIC8058_BATT_ALARM_H__ */
diff --git a/include/linux/pmic8058-misc.h b/include/linux/pmic8058-misc.h
deleted file mode 100644
index 5675a93..0000000
--- a/include/linux/pmic8058-misc.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-
-#ifndef __PMIC8058_MISC_H__
-#define __PMIC8058_MISC_H__
-
-enum pm8058_vib_en_mode {
- PM8058_VIB_MANUAL,
- PM8058_VIB_DTEST1,
- PM8058_VIB_DTEST2,
- PM8058_VIB_DTEST3
-};
-
-enum pm8058_coincell_chg_voltage {
- PM8058_COINCELL_VOLTAGE_3p2V = 1,
- PM8058_COINCELL_VOLTAGE_3p1V,
- PM8058_COINCELL_VOLTAGE_3p0V,
- PM8058_COINCELL_VOLTAGE_2p5V = 16
-};
-
-enum pm8058_coincell_chg_resistor {
- PM8058_COINCELL_RESISTOR_2100_OHMS,
- PM8058_COINCELL_RESISTOR_1700_OHMS,
- PM8058_COINCELL_RESISTOR_1200_OHMS,
- PM8058_COINCELL_RESISTOR_800_OHMS
-};
-
-enum pm8058_coincell_chg_state {
- PM8058_COINCELL_CHG_DISABLE,
- PM8058_COINCELL_CHG_ENABLE
-};
-
-struct pm8058_vib_config {
- u16 drive_mV;
- u8 active_low;
- enum pm8058_vib_en_mode enable_mode;
-};
-
-struct pm8058_coincell_chg_config {
- enum pm8058_coincell_chg_state state;
- enum pm8058_coincell_chg_voltage voltage;
- enum pm8058_coincell_chg_resistor resistor;
-};
-
-int pm8058_vibrator_config(struct pm8058_vib_config *vib_config);
-int pm8058_coincell_chg_config(struct pm8058_coincell_chg_config *chg_config);
-
-#endif /* __PMIC8058_MISC_H__ */
diff --git a/include/linux/pmic8058-pwrkey.h b/include/linux/pmic8058-pwrkey.h
deleted file mode 100644
index 6953872..0000000
--- a/include/linux/pmic8058-pwrkey.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __PMIC8058_PWRKEY_H__
-#define __PMIC8058_PWRKEY_H__
-
-struct pmic8058_pwrkey_pdata {
- bool pull_up;
- /* time after which pwr key event should be generated, if key is
- * released before that then end key event is reported
- */
- u16 pwrkey_time_ms;
- /* time delay for pwr-key state change
- * interrupt triggering.
- */
- u32 kpd_trigger_delay_us;
- u32 wakeup;
-};
-
-#endif /* __PMIC8058_PWRKEY_H__ */
diff --git a/include/linux/pmic8058-vibrator.h b/include/linux/pmic8058-vibrator.h
deleted file mode 100644
index e539058..0000000
--- a/include/linux/pmic8058-vibrator.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#ifndef __PMIC8058_VIBRATOR_H__
-#define __PMIC8058_VIBRATOR_H__
-
-struct pmic8058_vibrator_pdata {
- int initial_vibrate_ms;
- int max_timeout_ms;
-
- int level_mV;
-};
-
-#endif /* __PMIC8058_VIBRATOR_H__ */
diff --git a/include/linux/regulator/pm8018-regulator.h b/include/linux/regulator/pm8018-regulator.h
deleted file mode 100644
index 54515fa..0000000
--- a/include/linux/regulator/pm8018-regulator.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __PM8018_REGULATOR_H__
-#define __PM8018_REGULATOR_H__
-
-#include <linux/regulator/machine.h>
-
-#define PM8018_REGULATOR_DEV_NAME "pm8018-regulator"
-
-/**
- * enum pm8018_vreg_id - PMIC 8018 regulator ID numbers
- */
-enum pm8018_vreg_id {
- PM8018_VREG_ID_L2,
- PM8018_VREG_ID_L3,
- PM8018_VREG_ID_L4,
- PM8018_VREG_ID_L5,
- PM8018_VREG_ID_L6,
- PM8018_VREG_ID_L7,
- PM8018_VREG_ID_L8,
- PM8018_VREG_ID_L9,
- PM8018_VREG_ID_L10,
- PM8018_VREG_ID_L11,
- PM8018_VREG_ID_L12,
- PM8018_VREG_ID_L13,
- PM8018_VREG_ID_L14,
- PM8018_VREG_ID_S1,
- PM8018_VREG_ID_S2,
- PM8018_VREG_ID_S3,
- PM8018_VREG_ID_S4,
- PM8018_VREG_ID_S5,
- PM8018_VREG_ID_LVS1,
-
- /* The following are IDs for regulator devices to enable pin control. */
- PM8018_VREG_ID_L2_PC,
- PM8018_VREG_ID_L3_PC,
- PM8018_VREG_ID_L4_PC,
- PM8018_VREG_ID_L5_PC,
- PM8018_VREG_ID_L6_PC,
- PM8018_VREG_ID_L7_PC,
- PM8018_VREG_ID_L8_PC,
-
- PM8018_VREG_ID_L13_PC,
- PM8018_VREG_ID_L14_PC,
- PM8018_VREG_ID_S1_PC,
- PM8018_VREG_ID_S2_PC,
- PM8018_VREG_ID_S3_PC,
- PM8018_VREG_ID_S4_PC,
- PM8018_VREG_ID_S5_PC,
- PM8018_VREG_ID_LVS1_PC,
-
- PM8018_VREG_ID_MAX,
-};
-
-/* Pin control input pins. */
-#define PM8018_VREG_PIN_CTRL_NONE 0x00
-#define PM8018_VREG_PIN_CTRL_D1 0x01
-#define PM8018_VREG_PIN_CTRL_A0 0x02
-#define PM8018_VREG_PIN_CTRL_A1 0x04
-#define PM8018_VREG_PIN_CTRL_A2 0x08
-
-/* Minimum high power mode loads in uA. */
-#define PM8018_VREG_LDO_50_HPM_MIN_LOAD 5000
-#define PM8018_VREG_LDO_150_HPM_MIN_LOAD 10000
-#define PM8018_VREG_LDO_300_HPM_MIN_LOAD 10000
-#define PM8018_VREG_LDO_1200_HPM_MIN_LOAD 10000
-#define PM8018_VREG_SMPS_1500_HPM_MIN_LOAD 100000
-
-/**
- * enum pm8018_vreg_pin_function - action to perform when pin control is active
- * %PM8018_VREG_PIN_FN_ENABLE: pin control enables the regulator
- * %PM8018_VREG_PIN_FN_MODE: pin control changes mode from LPM to HPM
- */
-enum pm8018_vreg_pin_function {
- PM8018_VREG_PIN_FN_ENABLE = 0,
- PM8018_VREG_PIN_FN_MODE,
-};
-
-/**
- * struct pm8018_regulator_platform_data - PMIC 8018 regulator platform data
- * @init_data: regulator constraints
- * @id: regulator id; from enum pm8018_vreg_id
- * @pull_down_enable: 0 = no pulldown, 1 = pulldown when regulator disabled
- * @pin_ctrl: pin control inputs to use for the regulator; should be
- * a combination of PM8018_VREG_PIN_CTRL_* values
- * @pin_fn: action to perform when pin control pin is active
- * @system_uA: current drawn from regulator not accounted for by any
- * regulator framework consumer
- * @enable_time: time in us taken to enable a regulator to the maximum
- * allowed voltage for the system. This is dependent upon
- * the load and capacitance for a regulator on the board.
- */
-struct pm8018_regulator_platform_data {
- struct regulator_init_data init_data;
- enum pm8018_vreg_id id;
- unsigned pull_down_enable;
- unsigned pin_ctrl;
- enum pm8018_vreg_pin_function pin_fn;
- int system_uA;
- int enable_time;
-};
-
-#endif
diff --git a/include/linux/regulator/pm8921-regulator.h b/include/linux/regulator/pm8921-regulator.h
deleted file mode 100644
index 2eac548..0000000
--- a/include/linux/regulator/pm8921-regulator.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __PM8921_REGULATOR_H__
-#define __PM8921_REGULATOR_H__
-
-#include <linux/regulator/machine.h>
-
-#define PM8921_REGULATOR_DEV_NAME "pm8921-regulator"
-
-/**
- * enum pm8921_vreg_id - PMIC 8921 regulator ID numbers
- */
-enum pm8921_vreg_id {
- PM8921_VREG_ID_L1 = 0,
- PM8921_VREG_ID_L2,
- PM8921_VREG_ID_L3,
- PM8921_VREG_ID_L4,
- PM8921_VREG_ID_L5,
- PM8921_VREG_ID_L6,
- PM8921_VREG_ID_L7,
- PM8921_VREG_ID_L8,
- PM8921_VREG_ID_L9,
- PM8921_VREG_ID_L10,
- PM8921_VREG_ID_L11,
- PM8921_VREG_ID_L12,
- PM8921_VREG_ID_L14,
- PM8921_VREG_ID_L15,
- PM8921_VREG_ID_L16,
- PM8921_VREG_ID_L17,
- PM8921_VREG_ID_L18,
- PM8921_VREG_ID_L21,
- PM8921_VREG_ID_L22,
- PM8921_VREG_ID_L23,
- PM8921_VREG_ID_L24,
- PM8921_VREG_ID_L25,
- PM8921_VREG_ID_L26,
- PM8921_VREG_ID_L27,
- PM8921_VREG_ID_L28,
- PM8921_VREG_ID_L29,
- PM8921_VREG_ID_S1,
- PM8921_VREG_ID_S2,
- PM8921_VREG_ID_S3,
- PM8921_VREG_ID_S4,
- PM8921_VREG_ID_S5,
- PM8921_VREG_ID_S6,
- PM8921_VREG_ID_S7,
- PM8921_VREG_ID_S8,
- PM8921_VREG_ID_LVS1,
- PM8921_VREG_ID_LVS2,
- PM8921_VREG_ID_LVS3,
- PM8921_VREG_ID_LVS4,
- PM8921_VREG_ID_LVS5,
- PM8921_VREG_ID_LVS6,
- PM8921_VREG_ID_LVS7,
- PM8921_VREG_ID_USB_OTG,
- PM8921_VREG_ID_HDMI_MVS,
- PM8921_VREG_ID_NCP,
- /* The following are IDs for regulator devices to enable pin control. */
- PM8921_VREG_ID_L1_PC,
- PM8921_VREG_ID_L2_PC,
- PM8921_VREG_ID_L3_PC,
- PM8921_VREG_ID_L4_PC,
- PM8921_VREG_ID_L5_PC,
- PM8921_VREG_ID_L6_PC,
- PM8921_VREG_ID_L7_PC,
- PM8921_VREG_ID_L8_PC,
- PM8921_VREG_ID_L9_PC,
- PM8921_VREG_ID_L10_PC,
- PM8921_VREG_ID_L11_PC,
- PM8921_VREG_ID_L12_PC,
- PM8921_VREG_ID_L14_PC,
- PM8921_VREG_ID_L15_PC,
- PM8921_VREG_ID_L16_PC,
- PM8921_VREG_ID_L17_PC,
- PM8921_VREG_ID_L18_PC,
- PM8921_VREG_ID_L21_PC,
- PM8921_VREG_ID_L22_PC,
- PM8921_VREG_ID_L23_PC,
-
- PM8921_VREG_ID_L29_PC,
- PM8921_VREG_ID_S1_PC,
- PM8921_VREG_ID_S2_PC,
- PM8921_VREG_ID_S3_PC,
- PM8921_VREG_ID_S4_PC,
-
- PM8921_VREG_ID_S7_PC,
- PM8921_VREG_ID_S8_PC,
- PM8921_VREG_ID_LVS1_PC,
-
- PM8921_VREG_ID_LVS3_PC,
- PM8921_VREG_ID_LVS4_PC,
- PM8921_VREG_ID_LVS5_PC,
- PM8921_VREG_ID_LVS6_PC,
- PM8921_VREG_ID_LVS7_PC,
-
- PM8921_VREG_ID_MAX,
-};
-
-/* Pin control input pins. */
-#define PM8921_VREG_PIN_CTRL_NONE 0x00
-#define PM8921_VREG_PIN_CTRL_D1 0x01
-#define PM8921_VREG_PIN_CTRL_A0 0x02
-#define PM8921_VREG_PIN_CTRL_A1 0x04
-#define PM8921_VREG_PIN_CTRL_A2 0x08
-
-/* Minimum high power mode loads in uA. */
-#define PM8921_VREG_LDO_50_HPM_MIN_LOAD 5000
-#define PM8921_VREG_LDO_150_HPM_MIN_LOAD 10000
-#define PM8921_VREG_LDO_300_HPM_MIN_LOAD 10000
-#define PM8921_VREG_LDO_600_HPM_MIN_LOAD 10000
-#define PM8921_VREG_LDO_1200_HPM_MIN_LOAD 10000
-#define PM8921_VREG_SMPS_1500_HPM_MIN_LOAD 100000
-#define PM8921_VREG_SMPS_2000_HPM_MIN_LOAD 100000
-
-/**
- * enum pm8921_vreg_pin_function - action to perform when pin control is active
- * %PM8921_VREG_PIN_FN_ENABLE: pin control enables the regulator
- * %PM8921_VREG_PIN_FN_MODE: pin control changes mode from LPM to HPM
- */
-enum pm8921_vreg_pin_function {
- PM8921_VREG_PIN_FN_ENABLE = 0,
- PM8921_VREG_PIN_FN_MODE,
-};
-
-/**
- * struct pm8921_regulator_platform_data - PMIC 8921 regulator platform data
- * @init_data: regulator constraints
- * @id: regulator id; from enum pm8921_vreg_id
- * @pull_down_enable: 0 = no pulldown, 1 = pulldown when regulator disabled
- * @pin_ctrl: pin control inputs to use for the regulator; should be
- * a combination of PM8921_VREG_PIN_CTRL_* values
- * @pin_fn: action to perform when pin control pin is active
- * @system_uA: current drawn from regulator not accounted for by any
- * regulator framework consumer
- * @enable_time: time in us taken to enable a regulator to the maximum
- * allowed voltage for the system. This is dependent upon
- * the load and capacitance for a regulator on the board.
- */
-struct pm8921_regulator_platform_data {
- struct regulator_init_data init_data;
- enum pm8921_vreg_id id;
- unsigned pull_down_enable;
- unsigned pin_ctrl;
- enum pm8921_vreg_pin_function pin_fn;
- int system_uA;
- int enable_time;
-};
-
-#endif
diff --git a/include/linux/regulator/pm8xxx-regulator.h b/include/linux/regulator/pm8xxx-regulator.h
new file mode 100644
index 0000000..7c8d778
--- /dev/null
+++ b/include/linux/regulator/pm8xxx-regulator.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __REGULATOR_PM8XXX_REGULATOR_H__
+#define __REGULATOR_PM8XXX_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+#define PM8XXX_REGULATOR_DEV_NAME "pm8xxx-regulator"
+
+/* Pin control input pins. */
+#define PM8XXX_VREG_PIN_CTRL_NONE 0x00
+#define PM8XXX_VREG_PIN_CTRL_EN0 0x01
+#define PM8XXX_VREG_PIN_CTRL_EN1 0x02
+#define PM8XXX_VREG_PIN_CTRL_EN2 0x04
+#define PM8XXX_VREG_PIN_CTRL_EN3 0x08
+#define PM8XXX_VREG_PIN_CTRL_ALL 0x0F
+
+#define PM8921_VREG_PIN_CTRL_NONE PM8XXX_VREG_PIN_CTRL_NONE
+#define PM8921_VREG_PIN_CTRL_D1 PM8XXX_VREG_PIN_CTRL_EN0
+#define PM8921_VREG_PIN_CTRL_A0 PM8XXX_VREG_PIN_CTRL_EN1
+#define PM8921_VREG_PIN_CTRL_A1 PM8XXX_VREG_PIN_CTRL_EN2
+#define PM8921_VREG_PIN_CTRL_A2 PM8XXX_VREG_PIN_CTRL_EN3
+
+/* Minimum high power mode loads in uA. */
+#define PM8XXX_VREG_LDO_50_HPM_MIN_LOAD 5000
+#define PM8XXX_VREG_LDO_150_HPM_MIN_LOAD 10000
+#define PM8XXX_VREG_LDO_300_HPM_MIN_LOAD 10000
+#define PM8XXX_VREG_LDO_600_HPM_MIN_LOAD 10000
+#define PM8XXX_VREG_LDO_1200_HPM_MIN_LOAD 10000
+#define PM8XXX_VREG_SMPS_1500_HPM_MIN_LOAD 100000
+#define PM8XXX_VREG_SMPS_2000_HPM_MIN_LOAD 100000
+
+#define REGULATOR_TEST_BANKS_MAX 8
+
+/**
+ * enum pm8xxx_vreg_pin_function - action to perform when pin control is active
+ * %PM8XXX_VREG_PIN_FN_ENABLE: pin control enables the regulator
+ * %PM8XXX_VREG_PIN_FN_MODE: pin control changes mode from LPM to HPM
+ */
+enum pm8xxx_vreg_pin_function {
+ PM8XXX_VREG_PIN_FN_ENABLE = 0,
+ PM8XXX_VREG_PIN_FN_MODE,
+};
+
+/**
+ * struct pm8xxx_regulator_platform_data - PMIC 8921 regulator platform data
+ * @init_data: regulator constraints
+ * @id: regulator id. Any value unique among pm8xxx_regulator
+ * devices is acceptable.
+ * @pull_down_enable: 0 = no pulldown, 1 = pulldown when regulator disabled
+ * @pin_ctrl: pin control inputs to use for the regulator; should be
+ * a combination of PM8XXX_VREG_PIN_CTRL_* values
+ * @pin_fn: action to perform when pin control pin is active
+ * @system_uA: current drawn from regulator not accounted for by any
+ * regulator framework consumer
+ * @enable_time: time in us taken to enable a regulator to the maximum
+ * allowed voltage for the system. This is dependent upon
+ * the load and capacitance for a regulator on the board.
+ */
+struct pm8xxx_regulator_platform_data {
+ struct regulator_init_data init_data;
+ int id;
+ unsigned pull_down_enable;
+ unsigned pin_ctrl;
+ enum pm8xxx_vreg_pin_function pin_fn;
+ int system_uA;
+ int enable_time;
+};
+
+#endif
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index a8b04df..423a849 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -165,6 +165,9 @@
#define MSM_CAM_IOCTL_SENSOR_V4l2_QUERY_CTRL \
_IOR(MSM_CAM_IOCTL_MAGIC, 49, struct v4l2_queryctrl)
+#define MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 50, struct timeval *)
+
struct msm_mctl_pp_cmd {
int32_t id;
uint16_t length;
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index b7380bc..bedfc7c 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -348,6 +348,8 @@
#define SET_REG_FIELD(reg, val, offset, mask) \
(reg = (reg & ~mask) | (((val) << offset) & mask))
#define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset)
+#define RSH_DATA(val, offset) ((val) >> (offset))
+#define GET_ABS_VAL(val) ((val) & (0xFF))
enum radio_state_t {
FM_OFF,
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ca15ed0..5339785 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1041,6 +1041,7 @@
/* LE SMP Management interface */
int le_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, void *cp);
+int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3]);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 2d3028d..de61c32 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -342,3 +342,8 @@
} __packed;
+#define MGMT_EV_REMOTE_CLASS 0x0017
+struct mgmt_ev_remote_class {
+ bdaddr_t bdaddr;
+ __u8 dev_class[3];
+} __packed;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 396e8fc..8be88bb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -339,6 +339,36 @@
};
/**
+ * struct cfg80211_crypto_settings - Crypto settings
+ * @wpa_versions: indicates which, if any, WPA versions are enabled
+ * (from enum nl80211_wpa_versions)
+ * @cipher_group: group key cipher suite (or 0 if unset)
+ * @n_ciphers_pairwise: number of AP supported unicast ciphers
+ * @ciphers_pairwise: unicast key cipher suites
+ * @n_akm_suites: number of AKM suites
+ * @akm_suites: AKM suites
+ * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
+ * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ * required to assume that the port is unauthorized until authorized by
+ * user space. Otherwise, port is marked authorized by default.
+ * @control_port_ethertype: the control port protocol that should be
+ * allowed through even on unauthorized ports
+ * @control_port_no_encrypt: TRUE to prevent encryption of control port
+ * protocol frames.
+ */
+struct cfg80211_crypto_settings {
+ u32 wpa_versions;
+ u32 cipher_group;
+ int n_ciphers_pairwise;
+ u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
+ int n_akm_suites;
+ u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
+ bool control_port;
+ __be16 control_port_ethertype;
+ bool control_port_no_encrypt;
+};
+
+/**
* struct beacon_parameters - beacon parameters
*
* Used to configure the beacon for an interface.
@@ -351,11 +381,38 @@
* @dtim_period: DTIM period or zero if not changed
* @head_len: length of @head
* @tail_len: length of @tail
+ * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
+ * user space)
+ * @ssid_len: length of @ssid
+ * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
+ * @crypto: crypto settings
+ * @privacy: the BSS uses privacy
+ * @auth_type: Authentication type (algorithm)
+ * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL
+ * @beacon_ies_len: length of beacon_ies in octets
+ * @proberesp_ies: extra information element(s) to add into Probe Response
+ * frames or %NULL
+ * @proberesp_ies_len: length of proberesp_ies in octets
+ * @assocresp_ies: extra information element(s) to add into (Re)Association
+ * Response frames or %NULL
+ * @assocresp_ies_len: length of assocresp_ies in octets
*/
struct beacon_parameters {
u8 *head, *tail;
int interval, dtim_period;
int head_len, tail_len;
+ const u8 *ssid;
+ size_t ssid_len;
+ enum nl80211_hidden_ssid hidden_ssid;
+ struct cfg80211_crypto_settings crypto;
+ bool privacy;
+ enum nl80211_auth_type auth_type;
+ const u8 *beacon_ies;
+ size_t beacon_ies_len;
+ const u8 *proberesp_ies;
+ size_t proberesp_ies_len;
+ const u8 *assocresp_ies;
+ size_t assocresp_ies_len;
};
/**
@@ -536,6 +593,11 @@
* This number should increase every time the list of stations
* changes, i.e. when a station is added or removed, so that
* userspace can tell whether it got a consistent snapshot.
+ * @assoc_req_ies: IEs from (Re)Association Request.
+ * This is used only when in AP mode with drivers that do not use
+ * user space MLME/SME implementation. The information is provided for
+ * the cfg80211_new_sta() calls to notify user space of the IEs.
+ * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets.
*/
struct station_info {
u32 filled;
@@ -558,6 +620,14 @@
struct sta_bss_parameters bss_param;
int generation;
+
+ const u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+
+ /*
+ * Note: Add a new enum station_info_flags value for each new field and
+ * use it to check which fields are initialized.
+ */
};
/**
@@ -893,36 +963,6 @@
/**
- * struct cfg80211_crypto_settings - Crypto settings
- * @wpa_versions: indicates which, if any, WPA versions are enabled
- * (from enum nl80211_wpa_versions)
- * @cipher_group: group key cipher suite (or 0 if unset)
- * @n_ciphers_pairwise: number of AP supported unicast ciphers
- * @ciphers_pairwise: unicast key cipher suites
- * @n_akm_suites: number of AKM suites
- * @akm_suites: AKM suites
- * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
- * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
- * required to assume that the port is unauthorized until authorized by
- * user space. Otherwise, port is marked authorized by default.
- * @control_port_ethertype: the control port protocol that should be
- * allowed through even on unauthorized ports
- * @control_port_no_encrypt: TRUE to prevent encryption of control port
- * protocol frames.
- */
-struct cfg80211_crypto_settings {
- u32 wpa_versions;
- u32 cipher_group;
- int n_ciphers_pairwise;
- u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
- int n_akm_suites;
- u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
- bool control_port;
- __be16 control_port_ethertype;
- bool control_port_no_encrypt;
-};
-
-/**
* struct cfg80211_auth_request - Authentication request data
*
* This structure provides information needed to complete IEEE 802.11
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 9126bbb..798ed89 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -519,6 +519,7 @@
#define DEFAULT_POPP_TOPOLOGY 0x00010be4
#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
+#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
#define ASM_MAX_EQ_BANDS 12
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index e913e15..4be1abe 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -93,4 +93,6 @@
*/
int afe_convert_virtual_to_portid(u16 port_id);
+int afe_pseudo_port_start_nowait(u16 port_id);
+int afe_pseudo_port_stop_nowait(u16 port_id);
#endif /* __Q6AFE_H__ */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index d5828da..200ce83 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -20,16 +20,20 @@
void irq_domain_add(struct irq_domain *domain)
{
struct irq_data *d;
- int hwirq;
+ int hwirq, irq;
/*
* This assumes that the irq_domain owner has already allocated
* the irq_descs. This block will be removed when support for dynamic
* allocation of irq_descs is added to irq_domain.
*/
- for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
- d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
- if (d || d->domain) {
+ irq_domain_for_each_irq(domain, hwirq, irq) {
+ d = irq_get_irq_data(irq);
+ if (!d) {
+ WARN(1, "error: assigning domain to non existant irq_desc");
+ return;
+ }
+ if (d->domain) {
/* things are broken; just report, don't clean up */
WARN(1, "error: irq_desc already assigned to a domain");
return;
@@ -50,15 +54,15 @@
void irq_domain_del(struct irq_domain *domain)
{
struct irq_data *d;
- int hwirq;
+ int hwirq, irq;
mutex_lock(&irq_domain_mutex);
list_del(&domain->list);
mutex_unlock(&irq_domain_mutex);
/* Clear the irq_domain assignments */
- for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
- d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+ irq_domain_for_each_irq(domain, hwirq, irq) {
+ d = irq_get_irq_data(irq);
d->domain = NULL;
}
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6a9e368..75b5d6b 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1079,7 +1079,7 @@
depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
depends on !X86_64
select STACKTRACE
- select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE
+ select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
help
Provide stacktrace filter for fault-injection capabilities
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 25b80df..78d1c61 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -366,6 +366,7 @@
switch (type) {
case ACL_LINK:
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
+ conn->link_policy = hdev->link_policy;
break;
case SCO_LINK:
if (!pkt_type)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e1a90f8..dd1d6e8 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -639,6 +639,12 @@
hci_notify(hdev, HCI_DEV_DOWN);
+ if (hdev->dev_type == HCI_BREDR) {
+ hci_dev_lock_bh(hdev);
+ mgmt_powered(hdev->id, 0);
+ hci_dev_unlock_bh(hdev);
+ }
+
if (hdev->flush)
hdev->flush(hdev);
@@ -671,12 +677,6 @@
* and no tasks are scheduled. */
hdev->close(hdev);
- if (hdev->dev_type == HCI_BREDR) {
- hci_dev_lock_bh(hdev);
- mgmt_powered(hdev->id, 0);
- hci_dev_unlock_bh(hdev);
- }
-
/* Clear only non-persistent flags */
if (test_bit(HCI_MGMT, &hdev->flags))
set_bit(HCI_MGMT, &keepflags);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 45aa228..be0f55c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1678,6 +1678,8 @@
}
memcpy(conn->dev_class, ev->dev_class, 3);
+ /* For incoming connection update remote class to userspace */
+ mgmt_remote_class(hdev->id, &ev->bdaddr, ev->dev_class);
conn->state = BT_CONNECT;
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a3f3563..7e17a28 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -569,6 +569,7 @@
} else
sk->sk_state_change(sk);
+ sk->sk_send_head = NULL;
skb_queue_purge(TX_QUEUE(sk));
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
@@ -782,6 +783,7 @@
if (!conn)
return;
+ sk->sk_send_head = NULL;
skb_queue_purge(TX_QUEUE(sk));
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
@@ -1452,10 +1454,6 @@
tx_skb->destructor = l2cap_skb_destructor;
atomic_inc(&pi->ertm_queued);
- l2cap_do_send(sk, tx_skb);
-
- BT_DBG("Sent txseq %d", (int)control->txseq);
-
l2cap_ertm_start_retrans_timer(pi);
pi->next_tx_seq = __next_seq(pi->next_tx_seq, pi);
@@ -1467,6 +1465,9 @@
sk->sk_send_head = NULL;
else
sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
+
+ l2cap_do_send(sk, tx_skb);
+ BT_DBG("Sent txseq %d", (int)control->txseq);
}
BT_DBG("Sent %d, %d unacked, %d in ERTM queue, %d in HCI queue", sent,
@@ -4515,6 +4516,7 @@
if (sk->sk_state != BT_DISCONN) {
sk->sk_shutdown = SHUTDOWN_MASK;
+ sk->sk_send_head = NULL;
skb_queue_purge(TX_QUEUE(sk));
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b413a9c..7f2cff8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2905,3 +2905,14 @@
NULL);
}
+int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
+{
+ struct mgmt_ev_remote_class ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ bacpy(&ev.bdaddr, bdaddr);
+ memcpy(ev.dev_class, dev_class, 3);
+
+ return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
+}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ca7bf10..3ff633e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -334,6 +334,7 @@
ieee80211_sta_debugfs_add(sta);
rate_control_add_sta_debugfs(sta);
+ memset(&sinfo, 0, sizeof(sinfo));
sinfo.filled = 0;
sinfo.generation = local->sta_generation;
cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 584a7cd..0fc46b3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -23,6 +23,12 @@
#include "nl80211.h"
#include "reg.h"
+static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type);
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+ struct genl_info *info,
+ struct cfg80211_crypto_settings *settings,
+ int cipher_limit);
+
static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info);
static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
@@ -176,6 +182,11 @@
[NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
+ [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
+ [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
};
/* policy for the key attributes */
@@ -1957,7 +1968,10 @@
struct beacon_parameters params;
int haveinfo = 0, err;
- if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
+ !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
+ !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
+ !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
return -EINVAL;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
@@ -1983,6 +1997,49 @@
if (err)
return err;
+ /*
+ * In theory, some of these attributes could be required for
+ * NEW_BEACON, but since they were not used when the command was
+ * originally added, keep them optional for old user space
+ * programs to work with drivers that do not need the additional
+ * information.
+ */
+ if (info->attrs[NL80211_ATTR_SSID]) {
+ params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ params.ssid_len =
+ nla_len(info->attrs[NL80211_ATTR_SSID]);
+ if (params.ssid_len == 0 ||
+ params.ssid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
+ params.hidden_ssid = nla_get_u32(
+ info->attrs[NL80211_ATTR_HIDDEN_SSID]);
+ if (params.hidden_ssid !=
+ NL80211_HIDDEN_SSID_NOT_IN_USE &&
+ params.hidden_ssid !=
+ NL80211_HIDDEN_SSID_ZERO_LEN &&
+ params.hidden_ssid !=
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS)
+ return -EINVAL;
+ }
+
+ params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+ if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+ params.auth_type = nla_get_u32(
+ info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(params.auth_type))
+ return -EINVAL;
+ } else
+ params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+ err = nl80211_crypto_settings(rdev, info, ¶ms.crypto,
+ NL80211_MAX_NR_CIPHER_SUITES);
+ if (err)
+ return err;
+
call = rdev->ops->add_beacon;
break;
case NL80211_CMD_SET_BEACON:
@@ -2013,6 +2070,25 @@
if (!haveinfo)
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_IE]) {
+ params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+ params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
+ params.proberesp_ies =
+ nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+ params.proberesp_ies_len =
+ nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+ }
+
+ if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
+ params.assocresp_ies =
+ nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+ params.assocresp_ies_len =
+ nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+ }
+
err = call(&rdev->wiphy, dev, ¶ms);
if (!err && params.interval)
wdev->beacon_interval = params.interval;
@@ -2209,6 +2285,10 @@
}
nla_nest_end(msg, sinfoattr);
+ if (sinfo->assoc_req_ies)
+ NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
+ sinfo->assoc_req_ies);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -2236,6 +2316,7 @@
}
while (1) {
+ memset(&sinfo, 0, sizeof(sinfo));
err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
mac_addr, &sinfo);
if (err == -ENOENT)
diff --git a/scripts/build-all.py b/scripts/build-all.py
index dbf7b80..296d9ad 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -83,7 +83,7 @@
def scan_configs():
"""Get the full list of defconfigs appropriate for this tree."""
names = {}
- for n in glob.glob('arch/arm/configs/[fm]sm[0-9]*_defconfig'):
+ for n in glob.glob('arch/arm/configs/[fm]sm[0-9-]*_defconfig'):
names[os.path.basename(n)[:-10]] = n
for n in glob.glob('arch/arm/configs/qsd*_defconfig'):
names[os.path.basename(n)[:-10]] = n
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 5003ab5..33afdc9d 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -46,6 +46,8 @@
#define TABLA_I2S_MASTER_MODE_MASK 0x08
+#define TABLA_OCP_ATTEMPT 1
+
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -81,6 +83,16 @@
BAND_MAX,
};
+/* Flags to track of PA and DAC state.
+ * PA and DAC should be tracked separately as AUXPGA loopback requires
+ * only PA to be turned on without DAC being on. */
+enum tabla_priv_ack_flags {
+ TABLA_HPHL_PA_OFF_ACK = 0,
+ TABLA_HPHR_PA_OFF_ACK,
+ TABLA_HPHL_DAC_OFF_ACK,
+ TABLA_HPHR_DAC_OFF_ACK
+};
+
struct tabla_priv {
struct snd_soc_codec *codec;
u32 adc_count;
@@ -112,6 +124,9 @@
u8 cfilt_k_value;
bool mbhc_micbias_switched;
+ /* track PA/DAC state */
+ unsigned long hph_pa_dac_state;
+
/*track tabla interface type*/
u8 intf_type;
@@ -122,6 +137,14 @@
*/
struct work_struct hphlocp_work; /* reporting left hph ocp off */
struct work_struct hphrocp_work; /* reporting right hph ocp off */
+
+ /* pm_cnt holds number of sleep lock holders + 1
+ * so if pm_cnt is 1 system is sleep-able. */
+ atomic_t pm_cnt;
+ wait_queue_head_t pm_wq;
+
+ u8 hphlocp_cnt; /* headphone left ocp retry */
+ u8 hphrocp_cnt; /* headphone right ocp retry */
};
#ifdef CONFIG_DEBUG_FS
@@ -945,6 +968,7 @@
{
struct snd_soc_codec *codec = w->codec;
u16 adc_reg;
+ u8 init_bit_shift;
pr_debug("%s %d\n", __func__, event);
@@ -959,16 +983,28 @@
return -EINVAL;
}
+ if (w->shift == 3)
+ init_bit_shift = 6;
+ else if (w->shift == 7)
+ init_bit_shift = 7;
+ else {
+ pr_err("%s: Error, invalid init bit postion adc register\n",
+ __func__);
+ return -EINVAL;
+ }
+
+
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
tabla_codec_enable_adc_block(codec, 1);
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+ 1 << init_bit_shift);
break;
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
- 1 << w->shift);
- usleep_range(1000, 1000);
- snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
- usleep_range(1000, 1000);
+
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
break;
case SND_SOC_DAPM_POST_PMD:
tabla_codec_enable_adc_block(codec, 0);
@@ -1012,9 +1048,9 @@
snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
break;
case SND_SOC_DAPM_POST_PMU:
- pr_debug("%s: sleeping 40 ms after %s PA turn on\n",
+ pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
__func__, w->name);
- usleep_range(40000, 40000);
+ usleep_range(16000, 16000);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
@@ -1348,6 +1384,19 @@
return (hph_reg_val & 0x30) ? true : false;
}
+static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
+{
+ u8 hph_reg_val = 0;
+ if (left)
+ hph_reg_val = snd_soc_read(codec,
+ TABLA_A_RX_HPH_L_DAC_CTL);
+ else
+ hph_reg_val = snd_soc_read(codec,
+ TABLA_A_RX_HPH_R_DAC_CTL);
+
+ return (hph_reg_val & 0xC0) ? true : false;
+}
+
static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
int vddio_switch)
{
@@ -1603,6 +1652,14 @@
return 0;
}
+static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
+ struct snd_soc_jack *jack, int status,
+ int mask)
+{
+ /* XXX: wake_lock_timeout()? */
+ snd_soc_jack_report(jack, status, mask);
+}
+
static void hphocp_off_report(struct tabla_priv *tabla,
u32 jack_status, int irq)
{
@@ -1613,12 +1670,20 @@
codec = tabla->codec;
tabla->hph_status &= ~jack_status;
if (tabla->headset_jack)
- snd_soc_jack_report(tabla->headset_jack,
- tabla->hph_status, TABLA_JACK_MASK);
+ tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
+ tabla->hph_status,
+ TABLA_JACK_MASK);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
0x00);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
0x10);
+ /* reset retry counter as PA is turned off signifying
+ * start of new OCP detection session
+ */
+ if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
+ tabla->hphlocp_cnt = 0;
+ else
+ tabla->hphrocp_cnt = 0;
tabla_enable_irq(codec->control_data, irq);
} else {
pr_err("%s: Bad tabla private data\n", __func__);
@@ -1664,12 +1729,22 @@
* would have been locked while snd_soc_jack_report also
* attempts to acquire same lock.
*/
- if ((tabla->hph_status & SND_JACK_OC_HPHL) &&
- strnstr(w->name, "HPHL", 4))
- schedule_work(&tabla->hphlocp_work);
- else if ((tabla->hph_status & SND_JACK_OC_HPHR) &&
- strnstr(w->name, "HPHR", 4))
- schedule_work(&tabla->hphrocp_work);
+ if (w->shift == 5) {
+ clear_bit(TABLA_HPHL_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ if (tabla->hph_status & SND_JACK_OC_HPHL)
+ schedule_work(&tabla->hphlocp_work);
+ } else if (w->shift == 4) {
+ clear_bit(TABLA_HPHR_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ if (tabla->hph_status & SND_JACK_OC_HPHR)
+ schedule_work(&tabla->hphrocp_work);
+ }
+
if (tabla->mbhc_micbias_switched)
tabla_codec_switch_micbias(codec, 0);
@@ -1717,6 +1792,7 @@
default:
/* Should never reach here */
pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
+ return;
}
micbias_regs->cfilt_sel = cfilt;
@@ -3069,6 +3145,24 @@
return 0;
}
+static void tabla_lock_sleep(struct tabla_priv *tabla)
+{
+ int ret;
+ while (!(ret = wait_event_timeout(tabla->pm_wq,
+ atomic_inc_not_zero(&tabla->pm_cnt),
+ 2 * HZ))) {
+ pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
+ __func__, ret, atomic_read(&tabla->pm_cnt));
+ WARN_ON_ONCE(1);
+ }
+}
+
+static void tabla_unlock_sleep(struct tabla_priv *tabla)
+{
+ atomic_dec(&tabla->pm_cnt);
+ wake_up(&tabla->pm_wq);
+}
+
static void btn0_lpress_fn(struct work_struct *work)
{
struct delayed_work *delayed_work;
@@ -3083,13 +3177,15 @@
if (tabla->button_jack) {
pr_debug("%s: Reporting long button press event\n",
__func__);
- snd_soc_jack_report(tabla->button_jack, SND_JACK_BTN_0,
- SND_JACK_BTN_0);
+ tabla_snd_soc_jack_report(tabla, tabla->button_jack,
+ SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
}
} else {
pr_err("%s: Bad tabla private data\n", __func__);
}
+ tabla_unlock_sleep(tabla);
}
int tabla_hs_detect(struct snd_soc_codec *codec,
@@ -3139,6 +3235,7 @@
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ tabla_lock_sleep(priv);
bias_value = tabla_codec_read_dce_result(codec);
pr_debug("%s: button press interrupt, bias value(DCE Read)=%d\n",
@@ -3155,7 +3252,11 @@
msleep(100);
- schedule_delayed_work(&priv->btn0_dwork, msecs_to_jiffies(400));
+ if (schedule_delayed_work(&priv->btn0_dwork,
+ msecs_to_jiffies(400)) == 0) {
+ WARN(1, "Button pressed twice without release event\n");
+ tabla_unlock_sleep(priv);
+ }
return IRQ_HANDLED;
}
@@ -3168,6 +3269,7 @@
pr_debug("%s\n", __func__);
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+ tabla_lock_sleep(priv);
mic_voltage = tabla_codec_read_dce_result(codec);
pr_debug("%s: Microphone Voltage on release(DCE Read) = %d\n",
@@ -3181,12 +3283,15 @@
pr_debug("%s: Reporting long button release event\n",
__func__);
if (priv->button_jack) {
- snd_soc_jack_report(priv->button_jack, 0,
- SND_JACK_BTN_0);
+ tabla_snd_soc_jack_report(priv,
+ priv->button_jack, 0,
+ SND_JACK_BTN_0);
}
} else {
-
+ /* if scheduled btn0_dwork is canceled from here,
+ * we have to unlock from here instead btn0_work */
+ tabla_unlock_sleep(priv);
mic_voltage =
tabla_codec_measure_micbias_voltage(codec, 0);
pr_debug("%s: Mic Voltage on release(new STA) = %d\n",
@@ -3201,10 +3306,12 @@
pr_debug("%s:reporting short button press and release\n",
__func__);
- snd_soc_jack_report(priv->button_jack,
+ tabla_snd_soc_jack_report(priv,
+ priv->button_jack,
SND_JACK_BTN_0, SND_JACK_BTN_0);
- snd_soc_jack_report(priv->button_jack,
- 0, SND_JACK_BTN_0);
+ tabla_snd_soc_jack_report(priv,
+ priv->button_jack,
+ 0, SND_JACK_BTN_0);
}
}
}
@@ -3213,7 +3320,7 @@
}
tabla_codec_start_hs_polling(codec);
-
+ tabla_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3264,12 +3371,22 @@
if (tabla) {
codec = tabla->codec;
- tabla_disable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
- tabla->hph_status |= SND_JACK_OC_HPHL;
- if (tabla->headset_jack) {
- snd_soc_jack_report(tabla->headset_jack,
- tabla->hph_status, TABLA_JACK_MASK);
+ if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
+ pr_info("%s: retry\n", __func__);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ } else {
+ tabla_disable_irq(codec->control_data,
+ TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ tabla->hphlocp_cnt = 0;
+ tabla->hph_status |= SND_JACK_OC_HPHL;
+ if (tabla->headset_jack)
+ tabla_snd_soc_jack_report(tabla,
+ tabla->headset_jack,
+ tabla->hph_status,
+ TABLA_JACK_MASK);
}
} else {
pr_err("%s: Bad tabla private data\n", __func__);
@@ -3287,12 +3404,22 @@
if (tabla) {
codec = tabla->codec;
- tabla_disable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
- tabla->hph_status |= SND_JACK_OC_HPHR;
- if (tabla->headset_jack) {
- snd_soc_jack_report(tabla->headset_jack,
- tabla->hph_status, TABLA_JACK_MASK);
+ if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
+ pr_info("%s: retry\n", __func__);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ } else {
+ tabla_disable_irq(codec->control_data,
+ TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ tabla->hphrocp_cnt = 0;
+ tabla->hph_status |= SND_JACK_OC_HPHR;
+ if (tabla->headset_jack)
+ tabla_snd_soc_jack_report(tabla,
+ tabla->headset_jack,
+ tabla->hph_status,
+ TABLA_JACK_MASK);
}
} else {
pr_err("%s: Bad tabla private data\n", __func__);
@@ -3301,6 +3428,35 @@
return IRQ_HANDLED;
}
+static void tabla_sync_hph_state(struct tabla_priv *tabla)
+{
+ if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state)) {
+ pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
+ 1 << 4);
+ }
+ if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state)) {
+ pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
+ 1 << 5);
+ }
+
+ if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state)) {
+ pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+ if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state)) {
+ pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+}
+
static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
{
struct tabla_priv *priv = data;
@@ -3311,9 +3467,10 @@
short threshold_fake_insert = 0xFD30;
u8 is_removal;
-
pr_debug("%s\n", __func__);
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ tabla_lock_sleep(priv);
+
is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
@@ -3359,13 +3516,30 @@
if (priv->mbhc_micbias_switched)
tabla_codec_switch_micbias(codec, 0);
priv->hph_status &= ~SND_JACK_HEADPHONE;
+
+ /* If headphone PA is on, check if userspace receives
+ * removal event to sync-up PA's state */
+ if (tabla_is_hph_pa_on(codec)) {
+ set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
+ set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
+ }
+
+ if (tabla_is_hph_dac_on(codec, 1))
+ set_bit(TABLA_HPHL_DAC_OFF_ACK,
+ &priv->hph_pa_dac_state);
+ if (tabla_is_hph_dac_on(codec, 0))
+ set_bit(TABLA_HPHR_DAC_OFF_ACK,
+ &priv->hph_pa_dac_state);
+
if (priv->headset_jack) {
pr_debug("%s: Reporting removal\n", __func__);
- snd_soc_jack_report(priv->headset_jack,
- priv->hph_status, TABLA_JACK_MASK);
+ tabla_snd_soc_jack_report(priv, priv->headset_jack,
+ priv->hph_status,
+ TABLA_JACK_MASK);
}
tabla_codec_shutdown_hs_removal_detect(codec);
tabla_codec_enable_hs_detect(codec, 1);
+ tabla_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3400,12 +3574,13 @@
if (priv->headset_jack) {
pr_debug("%s: Reporting insertion %d\n", __func__,
SND_JACK_HEADPHONE);
- snd_soc_jack_report(priv->headset_jack,
- priv->hph_status, TABLA_JACK_MASK);
+ tabla_snd_soc_jack_report(priv, priv->headset_jack,
+ priv->hph_status,
+ TABLA_JACK_MASK);
}
tabla_codec_shutdown_hs_polling(codec);
tabla_codec_enable_hs_detect(codec, 0);
-
+ tabla_sync_hph_state(priv);
} else {
pr_debug("%s: Headset detected, mic_voltage = %x\n",
__func__, mic_voltage);
@@ -3413,12 +3588,15 @@
if (priv->headset_jack) {
pr_debug("%s: Reporting insertion %d\n", __func__,
SND_JACK_HEADSET);
- snd_soc_jack_report(priv->headset_jack,
- priv->hph_status, TABLA_JACK_MASK);
+ tabla_snd_soc_jack_report(priv, priv->headset_jack,
+ priv->hph_status,
+ TABLA_JACK_MASK);
}
tabla_codec_start_hs_polling(codec);
+ tabla_sync_hph_state(priv);
}
+ tabla_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3431,6 +3609,7 @@
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+ tabla_lock_sleep(priv);
usleep_range(priv->calibration->shutdown_plug_removal,
priv->calibration->shutdown_plug_removal);
@@ -3452,13 +3631,15 @@
priv->hph_status &= ~SND_JACK_HEADSET;
if (priv->headset_jack) {
pr_debug("%s: Reporting removal\n", __func__);
- snd_soc_jack_report(priv->headset_jack, 0,
- TABLA_JACK_MASK);
+ tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
+ TABLA_JACK_MASK);
}
tabla_codec_shutdown_hs_polling(codec);
tabla_codec_enable_hs_detect(codec, 1);
}
+
+ tabla_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3471,6 +3652,8 @@
int i, j;
u8 val;
+ tabla_lock_sleep(priv);
+
for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
slimbus_value = tabla_interface_reg_read(codec->control_data,
TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
@@ -3488,6 +3671,7 @@
TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
}
+ tabla_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3667,8 +3851,11 @@
}
static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
- /* Initialize current threshold to 350MA */
+ /* Initialize current threshold to 350MA
+ * number of wait and run cycles to 4096
+ */
{TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
+ {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
{TABLA_A_QFUSE_CTL, 0xFF, 0x03},
@@ -3765,6 +3952,8 @@
tabla->codec = codec;
tabla->pdata = dev_get_platdata(codec->dev->parent);
tabla->intf_type = tabla_get_intf_type();
+ atomic_set(&tabla->pm_cnt, 1);
+ init_waitqueue_head(&tabla->pm_wq);
tabla_update_reg_defaults(codec);
tabla_codec_init_reg(codec);
@@ -3869,6 +4058,7 @@
TABLA_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
+ tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
ret = tabla_request_irq(codec->control_data,
TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
@@ -3878,6 +4068,7 @@
TABLA_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
+ tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
#ifdef CONFIG_DEBUG_FS
debug_tabla_priv = tabla;
@@ -3966,6 +4157,64 @@
};
#endif
+#ifdef CONFIG_PM
+static int tabla_suspend(struct device *dev)
+{
+ int ret = 0, cnt;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
+ cnt = atomic_read(&tabla->pm_cnt);
+ if (cnt > 0) {
+ if (wait_event_timeout(tabla->pm_wq,
+ (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
+ == 1), 5 * HZ)) {
+ dev_dbg(dev, "system suspend pm_cnt %d\n",
+ atomic_read(&tabla->pm_cnt));
+ } else {
+ dev_err(dev, "%s timed out pm_cnt = %d\n",
+ __func__, atomic_read(&tabla->pm_cnt));
+ WARN_ON_ONCE(1);
+ ret = -EBUSY;
+ }
+ } else if (cnt == 0)
+ dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
+ atomic_read(&tabla->pm_cnt));
+ else {
+ WARN(1, "unexpected pm_cnt %d\n", cnt);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static int tabla_resume(struct device *dev)
+{
+ int ret = 0, cnt;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
+ cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
+ if (cnt == 0) {
+ dev_dbg(dev, "system resume, pm_cnt %d\n",
+ atomic_read(&tabla->pm_cnt));
+ wake_up_all(&tabla->pm_wq);
+ } else if (cnt > 0)
+ dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
+ else {
+ WARN(1, "unexpected pm_cnt %d\n", cnt);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static const struct dev_pm_ops tabla_pm_ops = {
+ .suspend = tabla_suspend,
+ .resume = tabla_resume,
+};
+#endif
+
static int __devinit tabla_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -3997,6 +4246,9 @@
.driver = {
.name = "tabla_codec",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &tabla_pm_ops,
+#endif
},
};
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 5e02797..4af4f06 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -300,6 +300,11 @@
case RT_PROXY_DAI_002_RX:
rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
break;
+ case VOICE_PLAYBACK_TX:
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ rc = 0;
+ break;
default:
dev_err(dai->dev, "invalid AFE port ID\n");
rc = -EINVAL;
@@ -343,7 +348,18 @@
int rc = 0;
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- rc = afe_close(dai->id); /* can block */
+ switch (dai->id) {
+ case VOICE_PLAYBACK_TX:
+ case VOICE_RECORD_TX:
+ case VOICE_RECORD_RX:
+ pr_debug("%s, stop pseudo port:%d\n",
+ __func__, dai->id);
+ rc = afe_stop_pseudo_port(dai->id);
+ break;
+ default:
+ rc = afe_close(dai->id); /* can block */
+ break;
+ }
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close AFE port\n");
pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
@@ -478,8 +494,17 @@
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- afe_port_start_nowait(dai->id, &dai_data->port_config,
- dai_data->rate);
+ switch (dai->id) {
+ case VOICE_PLAYBACK_TX:
+ case VOICE_RECORD_TX:
+ case VOICE_RECORD_RX:
+ afe_pseudo_port_start_nowait(dai->id);
+ break;
+ default:
+ afe_port_start_nowait(dai->id,
+ &dai_data->port_config, dai_data->rate);
+ break;
+ }
set_bit(STATUS_PORT_STARTED,
dai_data->status_mask);
}
@@ -488,7 +513,16 @@
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- afe_port_stop_nowait(dai->id);
+ switch (dai->id) {
+ case VOICE_PLAYBACK_TX:
+ case VOICE_RECORD_TX:
+ case VOICE_RECORD_RX:
+ afe_pseudo_port_stop_nowait(dai->id);
+ break;
+ default:
+ afe_port_stop_nowait(dai->id);
+ break;
+ }
clear_bit(STATUS_PORT_STARTED,
dai_data->status_mask);
}
@@ -586,7 +620,17 @@
/* If AFE port is still up, close it */
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
- rc = afe_close(dai->id); /* can block */
+ switch (dai->id) {
+ case VOICE_PLAYBACK_TX:
+ case VOICE_RECORD_TX:
+ case VOICE_RECORD_RX:
+ pr_debug("%s, stop pseudo port:%d\n",
+ __func__, dai->id);
+ rc = afe_stop_pseudo_port(dai->id);
+ break;
+ default:
+ rc = afe_close(dai->id); /* can block */
+ }
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close AFE port\n");
clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
@@ -705,6 +749,21 @@
.remove = msm_dai_q6_dai_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -735,6 +794,21 @@
.remove = msm_dai_q6_dai_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
@@ -872,6 +946,15 @@
case RT_PROXY_DAI_002_TX:
rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
break;
+ case VOICE_PLAYBACK_TX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_voice_playback_tx_dai);
+ break;
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_incall_record_dai);
+ break;
default:
rc = -ENODEV;
break;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 9a076d6..453bce4 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -114,6 +114,9 @@
{ RT_PROXY_PORT_001_TX, 0, NULL, 0, 0},
{ PCM_RX, 0, NULL, 0, 0},
{ PCM_TX, 0, NULL, 0, 0},
+ { VOICE_PLAYBACK_TX, 0, NULL, 0, 0},
+ { VOICE_RECORD_RX, 0, NULL, 0, 0},
+ { VOICE_RECORD_TX, 0, NULL, 0, 0},
};
@@ -259,6 +262,10 @@
mutex_lock(&routing_lock);
if (set) {
+ if (!test_bit(val, &msm_bedais[reg].fe_sessions) &&
+ (msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
+ voc_start_playback(set);
+
set_bit(val, &msm_bedais[reg].fe_sessions);
if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
INVALID_SESSION) {
@@ -270,6 +277,9 @@
fe_dai_map[val][session_type], path_type);
}
} else {
+ if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
+ (msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
+ voc_start_playback(set);
clear_bit(val, &msm_bedais[reg].fe_sessions);
if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
INVALID_SESSION) {
@@ -278,6 +288,9 @@
fe_dai_map[val][session_type], path_type);
}
}
+ if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
+ || (msm_bedais[reg].port_id == VOICE_RECORD_TX))
+ voc_start_record(msm_bedais[reg].port_id, set);
mutex_unlock(&routing_lock);
}
@@ -683,6 +696,15 @@
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
+ /* incall music delivery mixer */
+static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_SCO_RX,
@@ -763,6 +785,12 @@
SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
@@ -1103,6 +1131,13 @@
SND_SOC_DAPM_AIF_OUT("PCM_RX", "AFE Playback",
0, 0, 0 , 0),
SND_SOC_DAPM_AIF_IN("PCM_TX", "AFE Capture",
+ 0, 0, 0 , 0),
+ /* incall */
+ SND_SOC_DAPM_AIF_OUT("VOICE_PLAYBACK_TX", "Voice Farend Playback",
+ 0, 0, 0 , 0),
+ SND_SOC_DAPM_AIF_IN("INCALL_RECORD_TX", "Voice Uplink Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INCALL_RECORD_RX", "Voice Downlink Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
@@ -1122,6 +1157,10 @@
mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
+ /* incall */
+ SND_SOC_DAPM_MIXER("Incall_Music Audio Mixer", SND_SOC_NOPM, 0, 0,
+ incall_music_delivery_mixer_controls,
+ ARRAY_SIZE(incall_music_delivery_mixer_controls)),
/* Voice Mixer */
SND_SOC_DAPM_MIXER("PRI_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0, pri_rx_voice_mixer_controls,
@@ -1182,6 +1221,14 @@
{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
{"HDMI", NULL, "HDMI Mixer"},
+ /* incall */
+ {"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"VOICE_PLAYBACK_TX", NULL, "Incall_Music Audio Mixer"},
+
+ {"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+ {"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index b3a8210..2020939 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -26,6 +26,10 @@
#define LPASS_BE_AFE_PCM_TX "(Backend) RT_PROXY_DAI_002_TX"
#define LPASS_BE_AUXPCM_RX "(Backend) AUX_PCM_RX"
#define LPASS_BE_AUXPCM_TX "(Backend) AUX_PCM_TX"
+#define LPASS_BE_VOICE_PLAYBACK_TX "(Backend) VOICE_PLAYBACK_TX"
+#define LPASS_BE_INCALL_RECORD_RX "(Backend) INCALL_RECORD_TX"
+#define LPASS_BE_INCALL_RECORD_TX "(Backend) INCALL_RECORD_RX"
+
/* For multimedia front-ends, asm session is allocated dynamically.
* Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -62,6 +66,9 @@
MSM_BACKEND_DAI_AFE_PCM_TX,
MSM_BACKEND_DAI_AUXPCM_RX,
MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_BACKEND_DAI_INCALL_RECORD_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index d3f02a9..2e98627 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1061,6 +1061,45 @@
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
},
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm8960_be_hw_params_fixup,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm8960_be_hw_params_fixup,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .no_codec = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm8960_be_hw_params_fixup,
+ },
};
struct snd_soc_card snd_soc_card_msm8960 = {
@@ -1126,7 +1165,7 @@
{
int ret;
- if (!cpu_is_msm8960()) {
+ if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
pr_err("%s: Not the right machine type\n", __func__);
return -ENODEV ;
}
@@ -1156,7 +1195,7 @@
static void __exit msm8960_audio_exit(void)
{
- if (!cpu_is_msm8960()) {
+ if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
pr_err("%s: Not the right machine type\n", __func__);
return ;
}
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index ee6116a..68cb2b4 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -130,16 +130,18 @@
return 0;
}
-void send_cal(int port_id, struct acdb_cal_block *aud_cal)
+int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
{
- s32 result;
+ s32 result = 0;
struct adm_set_params_command adm_params;
int index = afe_get_port_index(port_id);
pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
if (!aud_cal || aud_cal->cal_size == 0) {
- pr_err("%s: No calibration data to send!\n", __func__);
+ pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+ __func__, port_id);
+ result = -EINVAL;
goto done;
}
@@ -165,17 +167,23 @@
if (result < 0) {
pr_err("%s: Set params failed port = %d payload = 0x%x\n",
__func__, port_id, aud_cal->cal_paddr);
+ result = -EINVAL;
goto done;
}
/* Wait for the callback */
result = wait_event_timeout(this_adm.wait,
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
- if (!result)
+ if (!result) {
pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
__func__, port_id, aud_cal->cal_paddr);
+ result = -EINVAL;
+ goto done;
+ }
+
+ result = 0;
done:
- return;
+ return result;
}
void send_adm_cal(int port_id, int path)
@@ -187,22 +195,24 @@
/* Maps audio_dev_ctrl path definition to ACDB definition */
acdb_path = path - 1;
- if ((acdb_path >= NUM_AUDPROC_BUFFERS) ||
- (acdb_path < 0)) {
- pr_err("%s: Path is not RX or TX, path = %d\n",
- __func__, path);
- goto done;
- }
pr_debug("%s: Sending audproc cal\n", __func__);
get_audproc_cal(acdb_path, &aud_cal);
- send_cal(port_id, &aud_cal);
+ if (!send_adm_cal_block(port_id, &aud_cal))
+ pr_info("%s: Audproc cal sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+ else
+ pr_info("%s: Audproc cal not sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
pr_debug("%s: Sending audvol cal\n", __func__);
get_audvol_cal(acdb_path, &aud_cal);
- send_cal(port_id, &aud_cal);
-done:
- return;
+ if (!send_adm_cal_block(port_id, &aud_cal))
+ pr_info("%s: Audvol cal sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+ else
+ pr_info("%s: Audvol cal not sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
}
int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
@@ -263,7 +273,9 @@
if ((open.topology_id ==
VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
(open.topology_id ==
- VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+ VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+ (open.topology_id ==
+ VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY))
rate = 16000;
}
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 017c1b6..21bbcf2 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -677,6 +677,39 @@
fail_cmd:
return ret;
}
+
+int afe_pseudo_port_start_nowait(u16 port_id)
+{
+ int ret = 0;
+ struct afe_pseudoport_start_command start;
+
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE APR is not registered\n", __func__);
+ return -ENODEV;
+ }
+
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = 0;
+ start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+ start.port_id = port_id;
+ start.timing = 1;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port %d failed %d\n",
+ __func__, port_id, ret);
+ return -EINVAL;
+ }
+ return 0;
+}
+
int afe_start_pseudo_port(u16 port_id)
{
int ret = 0;
@@ -703,8 +736,7 @@
if (ret < 0) {
pr_err("%s: AFE enable for port %d failed %d\n",
__func__, port_id, ret);
- ret = -EINVAL;
- return ret;
+ return -EINVAL;
}
ret = wait_event_timeout(this_afe.wait,
@@ -712,24 +744,22 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- return ret;
+ return -EINVAL;
}
return 0;
}
-int afe_stop_pseudo_port(u16 port_id)
+int afe_pseudo_port_stop_nowait(u16 port_id)
{
int ret = 0;
struct afe_pseudoport_stop_command stop;
- pr_info("%s: port_id=%d\n", __func__, port_id);
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
if (this_afe.apr == NULL) {
pr_err("%s: AFE is already closed\n", __func__);
- ret = -EINVAL;
- return ret;
+ return -EINVAL;
}
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -746,8 +776,40 @@
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
if (ret < 0) {
pr_err("%s: AFE close failed %d\n", __func__, ret);
- ret = -EINVAL;
- return ret;
+ return -EINVAL;
+ }
+
+ return 0;
+
+}
+
+int afe_stop_pseudo_port(u16 port_id)
+{
+ int ret = 0;
+ struct afe_pseudoport_stop_command stop;
+
+ pr_info("%s: port_id=%d\n", __func__, port_id);
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE is already closed\n", __func__);
+ return -EINVAL;
+ }
+
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = 0;
+ stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+ stop.port_id = port_id;
+ stop.reserved = 0;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+ if (ret < 0) {
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
+ return -EINVAL;
}
ret = wait_event_timeout(this_afe.wait,
@@ -755,8 +817,7 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- return ret;
+ return -EINVAL;
}
return 0;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index c899b2a..de63fa0 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -54,6 +54,10 @@
static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
static int voice_send_set_slowtalk_enable_cmd(struct voice_data *v);
+static int voice_cvs_stop_playback(struct voice_data *v);
+static int voice_cvs_start_playback(struct voice_data *v);
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
+static int voice_cvs_stop_record(struct voice_data *v);
static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv);
static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
@@ -1919,6 +1923,14 @@
if (is_voip_session(v->session_id))
voice_send_netid_timing_cmd(v);
+ /* Start in-call music delivery if this feature is enabled */
+ if (v->music_info.play_enable)
+ voice_cvs_start_playback(v);
+
+ /* Start in-call recording if this feature is enabled */
+ if (v->rec_info.rec_enable)
+ voice_cvs_start_record(v, v->rec_info.rec_mode);
+
rtac_add_voice(voice_get_cvs_handle(v),
voice_get_cvp_handle(v),
v->dev_rx.port_id, v->dev_tx.port_id,
@@ -2150,6 +2162,10 @@
mvm_handle = voice_get_mvm_handle(v);
cvp_handle = voice_get_cvp_handle(v);
+ /* stop playback or recording */
+ v->music_info.force = 1;
+ voice_cvs_stop_playback(v);
+ voice_cvs_stop_record(v);
/* send stop voice cmd */
voice_send_stop_voice_cmd(v);
@@ -2322,6 +2338,423 @@
return 0;
}
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ struct cvs_start_record_cmd cvs_start_record;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (!v->rec_info.recording) {
+ cvs_start_record.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_start_record.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_start_record) - APR_HDR_SIZE);
+ cvs_start_record.hdr.src_port = v->session_id;
+ cvs_start_record.hdr.dest_port = cvs_handle;
+ cvs_start_record.hdr.token = 0;
+ cvs_start_record.hdr.opcode = VSS_ISTREAM_CMD_START_RECORD;
+
+ if (rec_mode == VOC_REC_UPLINK) {
+ cvs_start_record.rec_mode.rx_tap_point =
+ VSS_TAP_POINT_NONE;
+ cvs_start_record.rec_mode.tx_tap_point =
+ VSS_TAP_POINT_STREAM_END;
+ } else if (rec_mode == VOC_REC_DOWNLINK) {
+ cvs_start_record.rec_mode.rx_tap_point =
+ VSS_TAP_POINT_STREAM_END;
+ cvs_start_record.rec_mode.tx_tap_point =
+ VSS_TAP_POINT_NONE;
+ } else if (rec_mode == VOC_REC_BOTH) {
+ cvs_start_record.rec_mode.rx_tap_point =
+ VSS_TAP_POINT_STREAM_END;
+ cvs_start_record.rec_mode.tx_tap_point =
+ VSS_TAP_POINT_STREAM_END;
+ } else {
+ pr_err("%s: Invalid in-call rec_mode %d\n", __func__,
+ rec_mode);
+
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_record);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending START_RECORD\n", __func__,
+ ret);
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ v->rec_info.recording = 1;
+ } else {
+ pr_debug("%s: Start record already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_cvs_stop_record(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct apr_hdr cvs_stop_record;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (v->rec_info.recording) {
+ cvs_stop_record.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvs_stop_record.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_stop_record) - APR_HDR_SIZE);
+ cvs_stop_record.src_port = v->session_id;
+ cvs_stop_record.dest_port = cvs_handle;
+ cvs_stop_record.token = 0;
+ cvs_stop_record.opcode = VSS_ISTREAM_CMD_STOP_RECORD;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_record);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending STOP_RECORD\n",
+ __func__, ret);
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ v->rec_info.recording = 0;
+ } else {
+ pr_debug("%s: Stop record already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+
+ return ret;
+}
+
+int voc_start_record(uint32_t port_id, uint32_t set)
+{
+ int ret = 0;
+ int rec_mode = 0;
+ u16 cvs_handle;
+ int i, rec_set = 0;
+
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ struct voice_data *v = &common.voice[i];
+ pr_debug("%s: i:%d port_id: %d, set: %d\n",
+ __func__, i, port_id, set);
+
+ mutex_lock(&v->lock);
+ rec_mode = v->rec_info.rec_mode;
+ rec_set = set;
+ if (set) {
+ if ((v->rec_route_state.ul_flag != 0) &&
+ (v->rec_route_state.dl_flag != 0)) {
+ pr_debug("%s: i=%d, rec mode already set.\n",
+ __func__, i);
+ mutex_unlock(&v->lock);
+ if (i < MAX_VOC_SESSIONS)
+ continue;
+ else
+ return 0;
+ }
+
+ if (port_id == VOICE_RECORD_TX) {
+ if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ rec_mode = VOC_REC_UPLINK;
+ v->rec_route_state.ul_flag = 1;
+ } else if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ voice_cvs_stop_record(v);
+ rec_mode = VOC_REC_BOTH;
+ v->rec_route_state.ul_flag = 1;
+ }
+ } else if (port_id == VOICE_RECORD_RX) {
+ if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ rec_mode = VOC_REC_DOWNLINK;
+ v->rec_route_state.dl_flag = 1;
+ } else if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ voice_cvs_stop_record(v);
+ rec_mode = VOC_REC_BOTH;
+ v->rec_route_state.dl_flag = 1;
+ }
+ }
+ rec_set = 1;
+ } else {
+ if ((v->rec_route_state.ul_flag == 0) &&
+ (v->rec_route_state.dl_flag == 0)) {
+ pr_debug("%s: i=%d, rec already stops.\n",
+ __func__, i);
+ mutex_unlock(&v->lock);
+ if (i < MAX_VOC_SESSIONS)
+ continue;
+ else
+ return 0;
+ }
+
+ if (port_id == VOICE_RECORD_TX) {
+ if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag == 0)) {
+ v->rec_route_state.ul_flag = 0;
+ rec_set = 0;
+ } else if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ voice_cvs_stop_record(v);
+ v->rec_route_state.ul_flag = 0;
+ rec_mode = VOC_REC_DOWNLINK;
+ rec_set = 1;
+ }
+ } else if (port_id == VOICE_RECORD_RX) {
+ if ((v->rec_route_state.ul_flag == 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ v->rec_route_state.dl_flag = 0;
+ rec_set = 0;
+ } else if ((v->rec_route_state.ul_flag != 0)
+ && (v->rec_route_state.dl_flag != 0)) {
+ voice_cvs_stop_record(v);
+ v->rec_route_state.dl_flag = 0;
+ rec_mode = VOC_REC_UPLINK;
+ rec_set = 1;
+ }
+ }
+ }
+ pr_debug("%s: i=%d, mode =%d, set =%d\n", __func__,
+ i, rec_mode, rec_set);
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (cvs_handle != 0) {
+ if (rec_set)
+ ret = voice_cvs_start_record(v, rec_mode);
+ else
+ ret = voice_cvs_stop_record(v);
+ }
+
+ /* Cache the value */
+ v->rec_info.rec_enable = rec_set;
+ v->rec_info.rec_mode = rec_mode;
+
+ mutex_unlock(&v->lock);
+ }
+
+ return ret;
+}
+
+static int voice_cvs_start_playback(struct voice_data *v)
+{
+ int ret = 0;
+ struct apr_hdr cvs_start_playback;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (!v->music_info.playing && v->music_info.count) {
+ cvs_start_playback.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_start_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_start_playback) - APR_HDR_SIZE);
+ cvs_start_playback.src_port = v->session_id;
+ cvs_start_playback.dest_port = cvs_handle;
+ cvs_start_playback.token = 0;
+ cvs_start_playback.opcode = VSS_ISTREAM_CMD_START_PLAYBACK;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_playback);
+
+ if (ret < 0) {
+ pr_err("%s: Error %d sending START_PLAYBACK\n",
+ __func__, ret);
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+
+ v->music_info.playing = 1;
+ } else {
+ pr_debug("%s: Start playback already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int voice_cvs_stop_playback(struct voice_data *v)
+{
+ int ret = 0;
+ struct apr_hdr cvs_stop_playback;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ if (v->music_info.playing && ((!v->music_info.count) ||
+ (v->music_info.force))) {
+ cvs_stop_playback.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cvs_stop_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_stop_playback) - APR_HDR_SIZE);
+ cvs_stop_playback.src_port = v->session_id;
+ cvs_stop_playback.dest_port = cvs_handle;
+ cvs_stop_playback.token = 0;
+
+ cvs_stop_playback.opcode = VSS_ISTREAM_CMD_STOP_PLAYBACK;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_playback);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending STOP_PLAYBACK\n",
+ __func__, ret);
+
+
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+
+ v->music_info.playing = 0;
+ v->music_info.force = 0;
+ } else {
+ pr_debug("%s: Stop playback already sent\n", __func__);
+ }
+
+ return 0;
+
+fail:
+ return ret;
+}
+
+int voc_start_playback(uint32_t set)
+{
+ int ret = 0;
+ u16 cvs_handle;
+ int i;
+
+
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ struct voice_data *v = &common.voice[i];
+
+ mutex_lock(&v->lock);
+ v->music_info.play_enable = set;
+ if (set)
+ v->music_info.count++;
+ else
+ v->music_info.count--;
+ pr_debug("%s: music_info count =%d\n", __func__,
+ v->music_info.count);
+
+ cvs_handle = voice_get_cvs_handle(v);
+ if (cvs_handle != 0) {
+ if (set)
+ ret = voice_cvs_start_playback(v);
+ else
+ ret = voice_cvs_stop_playback(v);
+ }
+
+ mutex_unlock(&v->lock);
+ }
+
+ return ret;
+}
+
int voc_disable_cvp(uint16_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
@@ -2937,6 +3370,10 @@
case VSS_ICOMMON_CMD_MAP_MEMORY:
case VSS_ICOMMON_CMD_UNMAP_MEMORY:
case VSS_ICOMMON_CMD_SET_UI_PROPERTY:
+ case VSS_ISTREAM_CMD_START_PLAYBACK:
+ case VSS_ISTREAM_CMD_STOP_PLAYBACK:
+ case VSS_ISTREAM_CMD_START_RECORD:
+ case VSS_ISTREAM_CMD_STOP_RECORD:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->cvs_state = CMD_STATUS_SUCCESS;
wake_up(&v->cvs_wait);
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index edde0aa..d330ada 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -17,6 +17,10 @@
#define MAX_VOC_PKT_SIZE 642
#define SESSION_NAME_LEN 20
+#define VOC_REC_UPLINK 0x00
+#define VOC_REC_DOWNLINK 0x01
+#define VOC_REC_BOTH 0x02
+
struct voice_header {
uint32_t id;
uint32_t data_len;
@@ -43,6 +47,11 @@
u16 tx_route_flag;
};
+struct voice_rec_route_state {
+ u16 ul_flag;
+ u16 dl_flag;
+};
+
enum {
VOC_INIT = 0,
VOC_RUN,
@@ -318,6 +327,36 @@
#define VOICE_PARAM_MOD_ENABLE 0x00010E00
#define MOD_ENABLE_PARAM_LEN 4
+#define VSS_ISTREAM_CMD_START_PLAYBACK 0x00011238
+/* Start in-call music delivery on the Tx voice path. */
+
+#define VSS_ISTREAM_CMD_STOP_PLAYBACK 0x00011239
+/* Stop the in-call music delivery on the Tx voice path. */
+
+#define VSS_ISTREAM_CMD_START_RECORD 0x00011236
+/* Start in-call conversation recording. */
+#define VSS_ISTREAM_CMD_STOP_RECORD 0x00011237
+/* Stop in-call conversation recording. */
+
+#define VSS_TAP_POINT_NONE 0x00010F78
+/* Indicates no tapping for specified path. */
+
+#define VSS_TAP_POINT_STREAM_END 0x00010F79
+/* Indicates that specified path should be tapped at the end of the stream. */
+
+struct vss_istream_cmd_start_record_t {
+ uint32_t rx_tap_point;
+ /* Tap point to use on the Rx path. Supported values are:
+ * VSS_TAP_POINT_NONE : Do not record Rx path.
+ * VSS_TAP_POINT_STREAM_END : Rx tap point is at the end of the stream.
+ */
+ uint32_t tx_tap_point;
+ /* Tap point to use on the Tx path. Supported values are:
+ * VSS_TAP_POINT_NONE : Do not record tx path.
+ * VSS_TAP_POINT_STREAM_END : Tx tap point is at the end of the stream.
+ */
+} __packed;
+
struct vss_istream_cmd_create_passive_control_session_t {
char name[SESSION_NAME_LEN];
/**<
@@ -538,6 +577,10 @@
struct apr_hdr hdr;
struct vss_icommon_cmd_set_ui_property_st_enable_t vss_set_st;
} __packed;
+struct cvs_start_record_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_start_record_t rec_mode;
+} __packed;
/* TO CVP commands */
@@ -747,13 +790,16 @@
};
struct incall_rec_info {
- uint32_t pending;
+ uint32_t rec_enable;
uint32_t rec_mode;
+ uint32_t recording;
};
struct incall_music_info {
- uint32_t pending;
+ uint32_t play_enable;
uint32_t playing;
+ int count;
+ int force;
};
struct voice_data {
@@ -790,6 +836,12 @@
struct voice_dev_route_state voc_route_state;
u16 session_id;
+
+ struct incall_rec_info rec_info;
+
+ struct incall_music_info music_info;
+
+ struct voice_rec_route_state rec_route_state;
};
#define MAX_VOC_SESSIONS 2
@@ -856,4 +908,6 @@
#define VOIP_SESSION_NAME "VoIP session"
uint16_t voc_get_session_id(char *name);
+int voc_start_playback(uint32_t set);
+int voc_start_record(uint32_t port_id, uint32_t set);
#endif