Merge "msm: kgsl: Remove wakelock and pm_qos requirements" into msm-3.0
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 604989d..e4f88ec 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -149,7 +149,7 @@
obj-$(CONFIG_ARCH_MSM7X01A) += pm.o
obj-y += pm-boot.o
else
- obj-y += no-pm.o
+ obj-y += no-pm.o hotplug.o
endif
obj-$(CONFIG_MSM_SPM_V1) += spm.o
diff --git a/arch/arm/mach-msm/board-apq8064.c b/arch/arm/mach-msm/board-apq8064.c
index b131989..6662751 100644
--- a/arch/arm/mach-msm/board-apq8064.c
+++ b/arch/arm/mach-msm/board-apq8064.c
@@ -18,6 +18,8 @@
#include <linux/slimbus/slimbus.h>
#include <linux/msm_ssbi.h>
#include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -37,6 +39,7 @@
#include <mach/msm_memtypes.h>
#include <linux/bootmem.h>
#include <asm/setup.h>
+#include <mach/dma.h>
#include "msm_watchdog.h"
#include "board-apq8064.h"
@@ -443,6 +446,118 @@
apq8064_add_sdcc(3, apq8064_sdc3_pdata);
}
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE 0x10000
+#define QCE_0_BASE 0x11000000
+
+#define QCE_HW_KEY_SUPPORT 0
+#define QCE_SHA_HMAC_SUPPORT 1
+#define QCE_SHARE_CE_RESOURCE 3
+#define QCE_CE_SHARED 0
+
+static struct resource qcrypto_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV8064_CE_IN_CHAN,
+ .end = DMOV8064_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV8064_CE_IN_CRCI,
+ .end = DMOV8064_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV8064_CE_OUT_CRCI,
+ .end = DMOV8064_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource qcedev_resources[] = {
+ [0] = {
+ .start = QCE_0_BASE,
+ .end = QCE_0_BASE + QCE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "crypto_channels",
+ .start = DMOV8064_CE_IN_CHAN,
+ .end = DMOV8064_CE_OUT_CHAN,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .name = "crypto_crci_in",
+ .start = DMOV8064_CE_IN_CRCI,
+ .end = DMOV8064_CE_IN_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .name = "crypto_crci_out",
+ .start = DMOV8064_CE_OUT_CRCI,
+ .end = DMOV8064_CE_OUT_CRCI,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcrypto_device = {
+ .name = "qcrypto",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcrypto_resources),
+ .resource = qcrypto_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcrypto_ce_hw_suppport,
+ },
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+ .ce_shared = QCE_CE_SHARED,
+ .shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+ .hw_key_support = QCE_HW_KEY_SUPPORT,
+ .sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+ .name = "qce",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(qcedev_resources),
+ .resource = qcedev_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &qcedev_ce_hw_suppport,
+ },
+};
+#endif
+
+
#define MSM_SHARED_RAM_PHYS 0x80000000
static void __init apq8064_map_io(void)
{
@@ -526,6 +641,15 @@
&msm8064_device_saw_regulator_core1,
&msm8064_device_saw_regulator_core2,
&msm8064_device_saw_regulator_core3,
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+ defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+ &qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+ defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+ &qcedev_device,
+#endif
};
static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 9813715..22767cec 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -4288,7 +4288,7 @@
.update_time = 60000,
.max_voltage = 4200,
.min_voltage = 3200,
- .resume_voltage = 4100,
+ .resume_voltage_delta = 100,
.term_current = 100,
.cool_temp = 10,
.warm_temp = 40,
@@ -4378,6 +4378,10 @@
.num_configs = ARRAY_SIZE(pm8921_led_configs),
};
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+ .r_sense = 10,
+};
+
static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
.irq_pdata = &pm8xxx_irq_pdata,
.gpio_pdata = &pm8xxx_gpio_pdata,
@@ -4391,6 +4395,7 @@
.bms_pdata = &pm8921_bms_pdata,
.adc_pdata = &pm8921_adc_pdata,
.leds_pdata = &pm8xxx_leds_pdata,
+ .ccadc_pdata = &pm8xxx_ccadc_pdata,
};
static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index aaf6c83..c16c2ee 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5158,8 +5158,14 @@
CLK_LOOKUP("usb_fs_sys_clk", usb_fs1_sys_clk.c, NULL),
CLK_LOOKUP("iface_clk", ce1_p_clk.c, NULL),
CLK_LOOKUP("core_clk", ce1_core_clk.c, NULL),
- CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, NULL),
+ CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, NULL),
CLK_LOOKUP("cfg_clk", sata_phy_cfg_clk.c, NULL),
+ CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qce.0"),
+ CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qcrypto.0"),
+ CLK_LOOKUP("core_clk", ce3_core_clk.c, "qce.0"),
+ CLK_LOOKUP("core_clk", ce3_core_clk.c, "qcrypto.0"),
+ CLK_LOOKUP("ce3_core_src_clk", ce3_src_clk.c, "qce.0"),
+ CLK_LOOKUP("ce3_core_src_clk", ce3_src_clk.c, "qcrypto.0"),
CLK_LOOKUP("dma_bam_pclk", dma_bam_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gsbi1_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gsbi2_p_clk.c, NULL),
@@ -5178,9 +5184,6 @@
CLK_LOOKUP("iface_clk", sdc3_p_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", sdc4_p_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("iface_clk", pcie_p_clk.c, NULL),
- CLK_LOOKUP("core_src_clk", ce3_src_clk.c, NULL),
- CLK_LOOKUP("core_clk", ce3_core_clk.c, NULL),
- CLK_LOOKUP("iface_clk", ce3_p_clk.c, NULL),
CLK_LOOKUP("core_clk", adm0_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", adm0_p_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", pmic_arb0_p_clk.c, NULL),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 9b8d5ac..afc2649 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -761,6 +761,12 @@
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
CLK_DUMMY("mem_clk", EBI1_ADM_CLK, "msm_dmov", 0),
+ CLK_DUMMY("ce3_core_src_clk", CE3_SRC_CLK, "qce.0", OFF),
+ CLK_DUMMY("ce3_core_src_clk", CE3_SRC_CLK, "qcrypto.0", OFF),
+ CLK_DUMMY("core_clk", CE3_CORE_CLK, "qce.0", OFF),
+ CLK_DUMMY("core_clk", CE3_CORE_CLK, "qcrypto.0", OFF),
+ CLK_DUMMY("iface_clk", CE3_P_CLK, "qce0.0", OFF),
+ CLK_DUMMY("iface_clk", CE3_P_CLK, "qcrypto.0", OFF),
};
struct clock_init_data apq8064_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 5a31f70..e8aa38e 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -12,6 +12,7 @@
#include <asm/cacheflush.h>
+#ifdef CONFIG_SMP
extern volatile int pen_release;
static inline void cpu_enter_lowpower(void)
@@ -55,6 +56,7 @@
pr_debug("CPU%u: spurious wakeup call\n", cpu);
}
}
+#endif
int platform_cpu_kill(unsigned int cpu)
{
@@ -68,6 +70,7 @@
*/
void platform_cpu_die(unsigned int cpu)
{
+#ifdef CONFIG_SMP
/*
* we're ready for shutdown now, so do it
*/
@@ -79,6 +82,7 @@
* coherency, and then restore interrupts
*/
cpu_leave_lowpower();
+#endif
}
int platform_cpu_disable(unsigned int cpu)
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 1474fcb..3cb79b7 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -245,6 +245,13 @@
#define DMOV_HSUART2_RX_CRCI 15
#endif
+/* channels for APQ8064 */
+#define DMOV8064_CE_IN_CHAN 2
+#define DMOV8064_CE_IN_CRCI 14
+
+#define DMOV8064_CE_OUT_CHAN 3
+#define DMOV8064_CE_OUT_CRCI 15
+
/* no client rate control ifc (eg, ram) */
#define DMOV_NONE_CRCI 0
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index e34abb1..d6cdbe7 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -25,16 +25,3 @@
void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-
-int platform_cpu_disable(unsigned int cpu)
-{
- return -ENOSYS;
-}
-
-int platform_cpu_kill(unsigned int cpu)
-{
- return -ENOSYS;
-}
-
-void platform_cpu_die(unsigned int cpu)
-{ }
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index e2f7271..bddc80f 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -125,14 +125,6 @@
#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-static int get_loadavg(void)
-{
- unsigned long this = this_cpu_load();
-
-
- return LOAD_INT(this) * 10 + LOAD_FRAC(this) / 10;
-}
-
static inline int which_bucket(unsigned int duration)
{
int bucket = 0;
@@ -170,15 +162,6 @@
{
int mult = 1;
- /* for higher loadavg, we are more reluctant */
-
- /*
- * this doesn't work as intended - it is almost always 0, but can
- * sometimes, depending on workload, spike very high into the hundreds
- * even when the average cpu load is under 10%.
- */
- /* mult += 2 * get_loadavg(); */
-
/* for IO wait tasks (per cpu!) we add 5x each */
mult += 10 * nr_iowait_cpu(smp_processor_id());
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 893933b..60a5aff 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -58,8 +58,9 @@
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
- struct clk *ce_core_clk; /* Handle to CE clk */
- struct clk *ce_clk; /* Handle to CE clk */
+ struct clk *ce_core_src_clk; /* Handle to CE src clk*/
+ struct clk *ce_core_clk; /* Handle to CE clk */
+ struct clk *ce_clk; /* Handle to CE clk */
qce_comp_func_ptr_t qce_cb; /* qce callback function pointer */
@@ -2391,6 +2392,8 @@
struct resource *resource;
struct clk *ce_core_clk;
struct clk *ce_clk;
+ struct clk *ce_core_src_clk;
+ int ret = 0;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -2461,10 +2464,26 @@
goto err;
}
+ /* Get CE3 src core clk. */
+ ce_core_src_clk = clk_get(pce_dev->pdev, "ce3_core_src_clk");
+ if (!IS_ERR(ce_core_src_clk)) {
+ pce_dev->ce_core_src_clk = ce_core_src_clk;
+
+ /* Set the core src clk @100Mhz */
+ ret = clk_set_rate(pce_dev->ce_core_src_clk, 100000000);
+ if (ret) {
+ clk_put(pce_dev->ce_core_src_clk);
+ goto err;
+ }
+ } else
+ pce_dev->ce_core_src_clk = NULL;
+
/* Get CE core clk */
ce_core_clk = clk_get(pce_dev->pdev, "core_clk");
if (IS_ERR(ce_core_clk)) {
*rc = PTR_ERR(ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
goto err;
}
pce_dev->ce_core_clk = ce_core_clk;
@@ -2472,6 +2491,8 @@
ce_clk = clk_get(pce_dev->pdev, "iface_clk");
if (IS_ERR(ce_clk)) {
*rc = PTR_ERR(ce_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
goto err;
}
@@ -2480,6 +2501,8 @@
/* Enable CE core clk */
*rc = clk_enable(pce_dev->ce_core_clk);
if (*rc) {
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
clk_put(pce_dev->ce_clk);
goto err;
@@ -2488,6 +2511,8 @@
*rc = clk_enable(pce_dev->ce_clk);
if (*rc) {
clk_disable(pce_dev->ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
clk_put(pce_dev->ce_core_clk);
clk_put(pce_dev->ce_clk);
goto err;
@@ -2539,6 +2564,9 @@
clk_disable(pce_dev->ce_clk);
clk_disable(pce_dev->ce_core_clk);
+ if (pce_dev->ce_core_src_clk != NULL)
+ clk_put(pce_dev->ce_core_src_clk);
+
clk_put(pce_dev->ce_clk);
clk_put(pce_dev->ce_core_clk);
@@ -2571,4 +2599,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.13");
+MODULE_VERSION("2.14");
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 742d8dd..b72ceb3 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -270,7 +270,6 @@
SINGLE_IRQ_RESOURCE("PM8921_BMS_OCV_FOR_R", PM8921_BMS_OCV_FOR_R),
SINGLE_IRQ_RESOURCE("PM8921_BMS_GOOD_OCV", PM8921_BMS_GOOD_OCV),
SINGLE_IRQ_RESOURCE("PM8921_BMS_VSENSE_AVG", PM8921_BMS_VSENSE_AVG),
- SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
};
static struct mfd_cell charger_cell __devinitdata = {
@@ -342,6 +341,17 @@
.pdata_size = sizeof(struct pm8xxx_batt_alarm_core_data),
};
+static const struct resource ccadc_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
+};
+
+static struct mfd_cell ccadc_cell __devinitdata = {
+ .name = PM8XXX_CCADC_DEV_NAME,
+ .id = -1,
+ .resources = ccadc_cell_resources,
+ .num_resources = ARRAY_SIZE(ccadc_cell_resources),
+};
+
static struct mfd_cell vibrator_cell __devinitdata = {
.name = PM8XXX_VIBRATOR_DEV_NAME,
.id = -1,
@@ -566,6 +576,19 @@
}
}
+ if (pdata->ccadc_pdata) {
+ ccadc_cell.platform_data = pdata->ccadc_pdata;
+ ccadc_cell.pdata_size =
+ sizeof(struct pm8xxx_ccadc_platform_data);
+
+ ret = mfd_add_devices(pmic->dev, 0, &ccadc_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add ccadc subdevice ret=%d\n", ret);
+ goto bail;
+ }
+ }
+
return 0;
bail:
if (pmic->irq_chip) {
diff --git a/drivers/net/msm_rmnet_bam.c b/drivers/net/msm_rmnet_bam.c
index 3b3758e..bb20a3f 100644
--- a/drivers/net/msm_rmnet_bam.c
+++ b/drivers/net/msm_rmnet_bam.c
@@ -308,6 +308,7 @@
}
dev->trans_start = jiffies;
+ /* if write() succeeds, skb access is unsafe in this process */
bam_ret = msm_bam_dmux_write(p->ch_id, skb);
if (bam_ret != 0) {
@@ -316,16 +317,6 @@
goto xmit_out;
}
- if (count_this_packet(skb->data, skb->len)) {
- p->stats.tx_packets++;
- p->stats.tx_bytes += skb->len;
-#ifdef CONFIG_MSM_RMNET_DEBUG
- p->wakeups_xmit += rmnet_cause_wakeup(p);
-#endif
- }
- DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
- dev->name, p->stats.tx_packets, skb->len, skb->mark);
-
return 0;
xmit_out:
/* data xmited, safe to release skb */
@@ -335,7 +326,21 @@
static void bam_write_done(void *dev, struct sk_buff *skb)
{
+ struct rmnet_private *p = netdev_priv(dev);
+ u32 opmode = p->operation_mode;
+
DBG1("%s: write complete\n", __func__);
+ if (RMNET_IS_MODE_IP(opmode) ||
+ count_this_packet(skb->data, skb->len)) {
+ p->stats.tx_packets++;
+ p->stats.tx_bytes += skb->len;
+#ifdef CONFIG_MSM_RMNET_DEBUG
+ p->wakeups_xmit += rmnet_cause_wakeup(p);
+#endif
+ }
+ DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+ ((struct net_device *)(dev))->name, p->stats.tx_packets,
+ skb->len, skb->mark);
dev_kfree_skb_any(skb);
netif_wake_queue(dev);
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3590e6d..7c8dfea 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -332,7 +332,14 @@
help
Say Y here to enable support for pm8921 chip charger subdevice
+config PM8XXX_CCADC
+ tristate "PM8XXX battery current adc driver"
+ depends on MFD_PM8921_CORE
+ help
+ Say Y here to enable support for pm8921 chip bms subdevice
+
config PM8921_BMS
+ select PM8XXX_CCADC
tristate "PM8921 Battery Monitoring System driver"
depends on MFD_PM8921_CORE
help
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index f61c88a..e168590 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -45,5 +45,6 @@
obj-$(CONFIG_BATTERY_BQ27520) += bq27520_fuelgauger.o
obj-$(CONFIG_BATTERY_BQ27541) += bq27541_fuelgauger.o
obj-$(CONFIG_SMB137B_CHARGER) += smb137b.o
+obj-$(CONFIG_PM8XXX_CCADC) += pm8xxx-ccadc.o
obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index d7cf3a8..143d9b5 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -19,6 +19,7 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
@@ -29,15 +30,6 @@
#define BMS_OUTPUT0 0x230
#define BMS_OUTPUT1 0x231
#define BMS_TEST1 0x237
-#define CCADC_ANA_PARAM 0x240
-#define CCADC_DIG_PARAM 0x241
-#define CCADC_RSV 0x242
-#define CCADC_DATA0 0x244
-#define CCADC_DATA1 0x245
-#define CCADC_OFFSET_TRIM1 0x34A
-#define CCADC_OFFSET_TRIM0 0x34B
-#define CCADC_FULLSCALE_TRIM1 0x34C
-#define CCADC_FULLSCALE_TRIM0 0x34D
#define ADC_ARB_SECP_CNTRL 0x190
#define ADC_ARB_SECP_AMUX_CNTRL 0x191
@@ -57,7 +49,6 @@
PM8921_BMS_OCV_FOR_R,
PM8921_BMS_GOOD_OCV,
PM8921_BMS_VSENSE_AVG,
- PM8921_BMS_CCADC_EOC,
PM_BMS_MAX_INTS,
};
@@ -75,8 +66,6 @@
struct work_struct calib_hkadc_work;
struct delayed_work calib_ccadc_work;
unsigned int calib_delay_ms;
- int ccadc_gain_uv;
- u16 ccadc_result_offset;
unsigned int revision;
unsigned int xoadc_v0625;
unsigned int xoadc_v125;
@@ -400,56 +389,6 @@
cc_to_microvolt_v2((s64)cc);
}
-#define CCADC_READING_RESOLUTION_N_V1 1085069
-#define CCADC_READING_RESOLUTION_D_V1 100000
-#define CCADC_READING_RESOLUTION_N_V2 542535
-#define CCADC_READING_RESOLUTION_D_V2 100000
-static s64 ccadc_reading_to_microvolt_v1(s64 cc)
-{
- return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
- CCADC_READING_RESOLUTION_D_V1);
-}
-
-static s64 ccadc_reading_to_microvolt_v2(s64 cc)
-{
- return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
- CCADC_READING_RESOLUTION_D_V2);
-}
-
-static s64 ccadc_reading_to_microvolt(struct pm8921_bms_chip *chip, s64 cc)
-{
- /*
- * resolution (the value of a single bit) was changed after revision 2.0
- * for more accurate readings
- */
- return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
- ccadc_reading_to_microvolt_v1((s64)cc) :
- ccadc_reading_to_microvolt_v2((s64)cc);
-}
-
-static s64 microvolt_to_ccadc_reading_v1(s64 uv)
-{
- return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
- CCADC_READING_RESOLUTION_N_V1);
-}
-
-static s64 microvolt_to_ccadc_reading_v2(s64 uv)
-{
- return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
- CCADC_READING_RESOLUTION_N_V2);
-}
-
-static s64 microvolt_to_ccadc_reading(struct pm8921_bms_chip *chip, s64 cc)
-{
- /*
- * resolution (the value of a single bit) was changed after revision 2.0
- * for more accurate readings
- */
- return (chip->revision < PM8XXX_REVISION_8921_2p0) ?
- microvolt_to_ccadc_reading_v1((s64)cc) :
- microvolt_to_ccadc_reading_v2((s64)cc);
-}
-
#define CC_READING_TICKS 55
#define SLEEP_CLK_HZ 32768
#define SECONDS_PER_HOUR 3600
@@ -459,19 +398,6 @@
SLEEP_CLK_HZ * SECONDS_PER_HOUR);
}
-#define GAIN_REFERENCE_UV 25000
-/*
- * gain compensation for ccadc readings - common for vsense based and
- * couloumb counter based readings
- */
-static s64 cc_adjust_for_gain(struct pm8921_bms_chip *chip, s64 cc)
-{
- if (chip->ccadc_gain_uv == 0)
- return cc;
-
- return div_s64(cc * GAIN_REFERENCE_UV, chip->ccadc_gain_uv);
-}
-
/* returns the signed value read from the hardware */
static int read_cc(struct pm8921_bms_chip *chip, int *result)
{
@@ -559,9 +485,9 @@
pr_err("fail to read VSENSE_FOR_RBATT rc = %d\n", rc);
return rc;
}
- *result = ccadc_reading_to_microvolt(chip, reading);
+ *result = pm8xxx_ccadc_reading_to_microvolt(chip->revision, reading);
pr_debug("raw = %04x vsense_for_r_uV = %u\n", reading, *result);
- *result = cc_adjust_for_gain(chip, *result);
+ *result = pm8xxx_cc_adjust_for_gain(*result);
pr_debug("after adj vsense_for_r_uV = %u\n", *result);
return 0;
}
@@ -593,9 +519,10 @@
pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
return rc;
}
- *result = ccadc_reading_to_microvolt(chip, reading);
+ *result = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ reading);
pr_debug("raw = %04x vsense = %d\n", reading, *result);
- *result = cc_adjust_for_gain(the_chip, (s64)*result);
+ *result = pm8xxx_cc_adjust_for_gain((s64)*result);
pr_debug("after adj vsense = %d\n", *result);
return 0;
}
@@ -976,7 +903,7 @@
rc = read_cc(the_chip, coulumb_counter);
cc_voltage_uv = (int64_t)*coulumb_counter;
cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
- cc_voltage_uv = cc_adjust_for_gain(chip, cc_voltage_uv);
+ cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
cc_uvh = ccmicrovolt_to_uvh(cc_voltage_uv);
pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh);
@@ -1224,386 +1151,12 @@
calib_hkadc(chip);
}
-#define START_CONV_BIT BIT(7)
-#define EOC_CONV_BIT BIT(6)
-#define SEL_CCADC_BIT BIT(1)
-#define EN_ARB_BIT BIT(0)
-
-#define CCADC_CALIB_DIG_PARAM 0xE3
-#define CCADC_CALIB_RSV_GND 0x40
-#define CCADC_CALIB_RSV_25MV 0x80
-#define CCADC_CALIB_ANA_PARAM 0x1B
-#define SAMPLE_COUNT 16
-#define ADC_WAIT_COUNT 10
-
-#define CCADC_MAX_25MV 30000
-#define CCADC_MIN_25MV 20000
-#define CCADC_MAX_0UV -4000
-#define CCADC_MIN_0UV -7000
-
-#define CCADC_INTRINSIC_OFFSET 0xC000
-
-#define REG_SBI_CONFIG 0x04F
-#define PAGE3_ENABLE_MASK 0x6
-
-static int calib_ccadc_enable_trim_access(struct pm8921_bms_chip *chip,
- u8 *sbi_config)
-{
- u8 reg;
- int rc;
-
- rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
- if (rc) {
- pr_err("error = %d reading sbi config reg\n", rc);
- return rc;
- }
-
- reg = *sbi_config | PAGE3_ENABLE_MASK;
- return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
-}
-
-static int calib_ccadc_restore_trim_access(struct pm8921_bms_chip *chip,
- u8 sbi_config)
-{
- return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
-}
-
-static int calib_ccadc_enable_arbiter(struct pm8921_bms_chip *chip)
-{
- int rc;
-
- /* enable Arbiter, must be sent twice */
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for offset\n", rc);
- return rc;
- }
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
- if (rc < 0) {
- pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
- return rc;
- }
- return 0;
-}
-
-static int calib_start_conv(struct pm8921_bms_chip *chip,
- u16 *result)
-{
- int rc, i;
- u8 data_msb, data_lsb, reg;
-
- /* Start conversion */
- rc = pm_bms_masked_write(chip, ADC_ARB_SECP_CNTRL,
- START_CONV_BIT, START_CONV_BIT);
- if (rc < 0) {
- pr_err("error = %d starting offset meas\n", rc);
- return rc;
- }
-
- /* Wait for End of conversion */
- for (i = 0; i < ADC_WAIT_COUNT; i++) {
- rc = pm8xxx_readb(chip->dev->parent,
- ADC_ARB_SECP_CNTRL, ®);
- if (rc < 0) {
- pr_err("error = %d read eoc for offset\n", rc);
- return rc;
- }
- if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
- msleep(60);
- else
- break;
- }
- if (i == ADC_WAIT_COUNT) {
- pr_err("waited too long for offset eoc\n");
- return rc;
- }
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
- if (rc < 0) {
- pr_err("error = %d reading offset lsb\n", rc);
- return rc;
- }
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
- if (rc < 0) {
- pr_err("error = %d reading offset msb\n", rc);
- return rc;
- }
-
- *result = (data_msb << 8) | data_lsb;
- return 0;
-}
-
-static int calib_ccadc_read_trim(struct pm8921_bms_chip *chip,
- int addr, u8 *data_msb, u8 *data_lsb)
-{
- int rc;
- u8 sbi_config;
-
- calib_ccadc_enable_trim_access(chip, &sbi_config);
- rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
- if (rc < 0) {
- pr_err("error = %d read msb\n", rc);
- return rc;
- }
- rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
- if (rc < 0) {
- pr_err("error = %d read lsb\n", rc);
- return rc;
- }
- calib_ccadc_restore_trim_access(chip, sbi_config);
- return 0;
-}
-
-static int calib_ccadc_read_gain_uv(struct pm8921_bms_chip *chip)
-{
- s8 data_msb;
- u8 data_lsb;
- int rc, gain, offset;
-
- rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
- &data_msb, &data_lsb);
- gain = (data_msb << 8) | data_lsb;
-
- rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
- &data_msb, &data_lsb);
- offset = (data_msb << 8) | data_lsb;
-
- pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", gain, offset);
- gain = ccadc_reading_to_microvolt(chip, (s64)gain - offset);
- return gain;
-}
-
-#define CCADC_PROGRAM_TRIM_COUNT 2
-#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
-#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
-#define BMS_CONV_IN_PROGRESS 0x2
-
-static int calib_ccadc_program_trim(struct pm8921_bms_chip *chip,
- int addr, u8 data_msb, u8 data_lsb,
- int wait)
-{
- int i, rc, loop;
- u8 cntrl, sbi_config;
- bool in_progress = 0;
-
- loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
-
- calib_ccadc_enable_trim_access(chip, &sbi_config);
-
- for (i = 0; i < loop; i++) {
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
- if (rc < 0) {
- pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
- return rc;
- }
-
- /* break if a ccadc conversion is not happening */
- in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
- & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
-
- if (!in_progress)
- break;
- }
-
- if (in_progress) {
- pr_debug("conv in progress cannot write trim,returing EBUSY\n");
- return -EBUSY;
- }
-
- rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
- if (rc < 0) {
- pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
- return rc;
- }
- rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
- if (rc < 0) {
- pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
- return rc;
- }
- calib_ccadc_restore_trim_access(chip, sbi_config);
- return 0;
-}
-
-static void calib_ccadc(struct pm8921_bms_chip *chip)
-{
- u8 data_msb, data_lsb, sec_cntrl;
- int result_offset, voltage_offset, result_gain;
- u16 result;
- int i, rc;
-
- rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_CNTRL, &sec_cntrl);
- if (rc < 0) {
- pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
- return;
- }
-
- rc = calib_ccadc_enable_arbiter(chip);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for offset\n", rc);
- goto bail;
- }
-
- /*
- * Set decimation ratio to 4k, lower ratio may be used in order to speed
- * up, pending verification through bench
- */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
- CCADC_CALIB_DIG_PARAM);
- if (rc < 0) {
- pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
- goto bail;
- }
-
- result_offset = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- /* Short analog inputs to CCADC internally to ground */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_RSV,
- CCADC_CALIB_RSV_GND);
- if (rc < 0) {
- pr_err("error = %d selecting gnd voltage\n", rc);
- goto bail;
- }
-
- /* Enable CCADC */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
- CCADC_CALIB_ANA_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling ccadc\n", rc);
- goto bail;
- }
-
- rc = calib_start_conv(chip, &result);
- if (rc < 0) {
- pr_err("error = %d for zero volt measurement\n", rc);
- goto bail;
- }
-
- result_offset += result;
- }
-
- result_offset = result_offset / SAMPLE_COUNT;
-
- voltage_offset = ccadc_reading_to_microvolt(chip,
- ((s64)result_offset - CCADC_INTRINSIC_OFFSET));
-
- pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
- result_offset, voltage_offset);
-
- /* Sanity Check */
- if (voltage_offset > CCADC_MAX_0UV) {
- pr_err("offset voltage = %d is huge limiting to %d\n",
- voltage_offset, CCADC_MAX_0UV);
- result_offset = CCADC_INTRINSIC_OFFSET
- + microvolt_to_ccadc_reading(chip, (s64)CCADC_MAX_0UV);
- } else if (voltage_offset < CCADC_MIN_0UV) {
- pr_err("offset voltage = %d is too low limiting to %d\n",
- voltage_offset, CCADC_MIN_0UV);
- result_offset = CCADC_INTRINSIC_OFFSET
- + microvolt_to_ccadc_reading(chip, (s64)CCADC_MIN_0UV);
- }
-
- chip->ccadc_result_offset = result_offset;
- data_msb = chip->ccadc_result_offset >> 8;
- data_lsb = chip->ccadc_result_offset;
-
- rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
- data_msb, data_lsb, 1);
- if (rc) {
- pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
- rc, data_msb, data_lsb);
- /* enable the interrupt and write it when it fires */
- pm8921_bms_enable_irq(chip, PM8921_BMS_CCADC_EOC);
- }
-
- rc = calib_ccadc_enable_arbiter(chip);
- if (rc < 0) {
- pr_err("error = %d enabling arbiter for gain\n", rc);
- goto bail;
- }
-
- /*
- * Set decimation ratio to 4k, lower ratio may be used in order to speed
- * up, pending verification through bench
- */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
- CCADC_CALIB_DIG_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling decimation ration for gain\n", rc);
- goto bail;
- }
-
- result_gain = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- rc = pm8xxx_writeb(chip->dev->parent,
- ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
- if (rc < 0) {
- pr_err("error = %d selecting 25mV for gain\n", rc);
- goto bail;
- }
-
- /* Enable CCADC */
- rc = pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_ANA_PARAM,
- CCADC_CALIB_ANA_PARAM);
- if (rc < 0) {
- pr_err("error = %d enabling ccadc\n", rc);
- goto bail;
- }
-
- rc = calib_start_conv(chip, &result);
- if (rc < 0) {
- pr_err("error = %d for adc reading 25mV\n", rc);
- goto bail;
- }
-
- result_gain += result;
- }
- result_gain = result_gain / SAMPLE_COUNT;
-
- /*
- * result_offset includes INTRINSIC OFFSET
- * chip->ccadc_gain_uv will be the actual voltage
- * measured for 25000UV
- */
- chip->ccadc_gain_uv = ccadc_reading_to_microvolt(chip,
- ((s64)result_gain - result_offset));
-
- pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
- result_gain,
- chip->ccadc_gain_uv);
- /* Sanity Check */
- if (chip->ccadc_gain_uv > CCADC_MAX_25MV) {
- pr_err("gain voltage = %d is huge limiting to %d\n",
- chip->ccadc_gain_uv, CCADC_MAX_25MV);
- chip->ccadc_gain_uv = CCADC_MAX_25MV;
- result_gain = result_offset +
- microvolt_to_ccadc_reading(chip, CCADC_MAX_25MV);
- } else if (chip->ccadc_gain_uv < CCADC_MIN_25MV) {
- pr_err("gain voltage = %d is too low limiting to %d\n",
- chip->ccadc_gain_uv, CCADC_MIN_25MV);
- chip->ccadc_gain_uv = CCADC_MIN_25MV;
- result_gain = result_offset +
- microvolt_to_ccadc_reading(chip, CCADC_MIN_25MV);
- }
-
- data_msb = result_gain >> 8;
- data_lsb = result_gain;
- rc = calib_ccadc_program_trim(chip, CCADC_FULLSCALE_TRIM1,
- data_msb, data_lsb, 0);
- if (rc)
- pr_debug("error = %d programming gain trim\n", rc);
-bail:
- pm8xxx_writeb(chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
-}
-
static void calibrate_ccadc_work(struct work_struct *work)
{
struct pm8921_bms_chip *chip = container_of(work,
struct pm8921_bms_chip, calib_ccadc_work.work);
- calib_ccadc(chip);
+ pm8xxx_calib_ccadc();
schedule_delayed_work(&chip->calib_ccadc_work,
round_jiffies_relative(msecs_to_jiffies
(chip->calib_delay_ms)));
@@ -1810,23 +1363,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
-{
- u8 data_msb, data_lsb;
- struct pm8921_bms_chip *chip = data;
- int rc;
-
- pr_debug("irq = %d triggered\n", irq);
- data_msb = chip->ccadc_result_offset >> 8;
- data_lsb = chip->ccadc_result_offset;
-
- rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
- data_msb, data_lsb, 0);
- pm8921_bms_disable_irq(chip, PM8921_BMS_CCADC_EOC);
-
- return IRQ_HANDLED;
-}
-
struct pm_bms_irq_init_data {
unsigned int irq_id;
char *name;
@@ -1857,8 +1393,6 @@
pm8921_bms_good_ocv_handler),
BMS_IRQ(PM8921_BMS_VSENSE_AVG, IRQF_TRIGGER_RISING,
pm8921_bms_vsense_avg_handler),
- BMS_IRQ(PM8921_BMS_CCADC_EOC, IRQF_TRIGGER_RISING,
- pm8921_bms_ccadc_eoc_handler),
};
static void free_irqs(struct pm8921_bms_chip *chip)
@@ -2076,7 +1610,7 @@
case CALIB_CCADC:
/* reading this will trigger calibration */
*val = 0;
- calib_ccadc(the_chip);
+ pm8xxx_calib_ccadc();
break;
default:
ret = -EINVAL;
@@ -2169,7 +1703,7 @@
{
int i;
- chip->dent = debugfs_create_dir("pm8921_bms", NULL);
+ chip->dent = debugfs_create_dir("pm8921-bms", NULL);
if (IS_ERR(chip->dent)) {
pr_err("pmic bms couldnt create debugfs dir\n");
@@ -2184,20 +1718,6 @@
(void *)BMS_OUTPUT1, ®_fops);
debugfs_create_file("BMS_TEST1", 0644, chip->dent,
(void *)BMS_TEST1, ®_fops);
- debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
- (void *)CCADC_ANA_PARAM, ®_fops);
- debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
- (void *)CCADC_DIG_PARAM, ®_fops);
- debugfs_create_file("CCADC_RSV", 0644, chip->dent,
- (void *)CCADC_RSV, ®_fops);
- debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
- (void *)CCADC_DATA0, ®_fops);
- debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
- (void *)CCADC_DATA1, ®_fops);
- debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
- (void *)CCADC_OFFSET_TRIM1, ®_fops);
- debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
- (void *)CCADC_OFFSET_TRIM0, ®_fops);
debugfs_create_file("test_batt_temp", 0644, chip->dent,
(void *)TEST_BATT_TEMP, &temp_fops);
@@ -2296,7 +1816,6 @@
create_debugfs_entries(chip);
check_initial_ocv(chip);
- chip->ccadc_gain_uv = calib_ccadc_read_gain_uv(chip);
INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
/* begin calibration only on chips > 2.0 */
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 148a5e5..af44f45 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -201,8 +201,8 @@
* @update_time: how frequently the userland needs to be updated
* @max_voltage: the max volts the batt should be charged up to
* @min_voltage: the min battery voltage before turning the FETon
- * @resume_voltage: the voltage at which the battery should resume
- * charging
+ * @resume_voltage_delta: the voltage delta from vdd max at which the
+ * battery should resume charging
* @term_current: The charging based term current
*
*/
@@ -225,7 +225,9 @@
unsigned int warm_bat_chg_current;
unsigned int cool_bat_voltage;
unsigned int warm_bat_voltage;
- unsigned int resume_voltage;
+ unsigned int is_bat_cool;
+ unsigned int is_bat_warm;
+ unsigned int resume_voltage_delta;
unsigned int term_current;
unsigned int vbat_channel;
unsigned int batt_temp_channel;
@@ -1898,11 +1900,17 @@
the_chip->cool_temp + TEMP_HYSTERISIS_DEGC;
pm_chg_ibatmax_set(the_chip, the_chip->cool_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->cool_bat_voltage
+ - the_chip->resume_voltage_delta);
} else {
btm_config.low_thr_temp = the_chip->cool_temp;
pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->max_voltage - the_chip->resume_voltage_delta);
}
+ the_chip->is_bat_cool = enter;
schedule_work(&btm_config_work);
}
@@ -1914,11 +1922,17 @@
the_chip->warm_temp - TEMP_HYSTERISIS_DEGC;
pm_chg_ibatmax_set(the_chip, the_chip->warm_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->warm_bat_voltage
+ - the_chip->resume_voltage_delta);
} else {
btm_config.high_thr_temp = the_chip->warm_temp;
pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ pm_chg_vbatdet_set(the_chip,
+ the_chip->max_voltage - the_chip->resume_voltage_delta);
}
+ the_chip->is_bat_warm = enter;
schedule_work(&btm_config_work);
}
@@ -2211,10 +2225,11 @@
chip->max_voltage, rc);
return rc;
}
- rc = pm_chg_vbatdet_set(chip, chip->resume_voltage);
+ rc = pm_chg_vbatdet_set(chip,
+ chip->max_voltage - chip->resume_voltage_delta);
if (rc) {
pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
- chip->resume_voltage, rc);
+ chip->max_voltage - chip->resume_voltage_delta, rc);
return rc;
}
@@ -2458,6 +2473,24 @@
}
DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+enum {
+ BAT_WARM_ZONE,
+ BAT_COOL_ZONE,
+};
+static int get_warm_cool(void *data, u64 * val)
+{
+ if (!the_chip) {
+ pr_err("%s called before init\n", __func__);
+ return -EINVAL;
+ }
+ if ((int)data == BAT_WARM_ZONE)
+ *val = the_chip->is_bat_warm;
+ if ((int)data == BAT_COOL_ZONE)
+ *val = the_chip->is_bat_cool;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
+
static void create_debugfs_entries(struct pm8921_chg_chip *chip)
{
int i;
@@ -2524,6 +2557,11 @@
debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
®_loop_fops);
+ debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
+ (void *)BAT_WARM_ZONE, &warm_cool_fops);
+ debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
+ (void *)BAT_COOL_ZONE, &warm_cool_fops);
+
for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
debugfs_create_file(chg_irq_data[i].name, 0444,
@@ -2558,7 +2596,7 @@
chip->update_time = pdata->update_time;
chip->max_voltage = pdata->max_voltage;
chip->min_voltage = pdata->min_voltage;
- chip->resume_voltage = pdata->resume_voltage;
+ chip->resume_voltage_delta = pdata->resume_voltage_delta;
chip->term_current = pdata->term_current;
chip->vbat_channel = pdata->charger_cdata.vbat_channel;
chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
new file mode 100644
index 0000000..1245045
--- /dev/null
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -0,0 +1,761 @@
+/* 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/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#define CCADC_ANA_PARAM 0x240
+#define CCADC_DIG_PARAM 0x241
+#define CCADC_RSV 0x242
+#define CCADC_DATA0 0x244
+#define CCADC_DATA1 0x245
+#define CCADC_OFFSET_TRIM1 0x34A
+#define CCADC_OFFSET_TRIM0 0x34B
+#define CCADC_FULLSCALE_TRIM1 0x34C
+#define CCADC_FULLSCALE_TRIM0 0x34D
+
+/* note : TRIM1 is the msb and TRIM0 is the lsb */
+#define ADC_ARB_SECP_CNTRL 0x190
+#define ADC_ARB_SECP_AMUX_CNTRL 0x191
+#define ADC_ARB_SECP_ANA_PARAM 0x192
+#define ADC_ARB_SECP_DIG_PARAM 0x193
+#define ADC_ARB_SECP_RSV 0x194
+#define ADC_ARB_SECP_DATA1 0x195
+#define ADC_ARB_SECP_DATA0 0x196
+
+#define ADC_ARB_BMS_CNTRL 0x18D
+
+#define START_CONV_BIT BIT(7)
+#define EOC_CONV_BIT BIT(6)
+#define SEL_CCADC_BIT BIT(1)
+#define EN_ARB_BIT BIT(0)
+
+#define CCADC_CALIB_DIG_PARAM 0xE3
+#define CCADC_CALIB_RSV_GND 0x40
+#define CCADC_CALIB_RSV_25MV 0x80
+#define CCADC_CALIB_ANA_PARAM 0x1B
+#define SAMPLE_COUNT 16
+#define ADC_WAIT_COUNT 10
+
+#define CCADC_MAX_25MV 30000
+#define CCADC_MIN_25MV 20000
+#define CCADC_MAX_0UV -4000
+#define CCADC_MIN_0UV -7000
+
+#define CCADC_INTRINSIC_OFFSET 0xC000
+
+struct pm8xxx_ccadc_chip {
+ struct device *dev;
+ struct dentry *dent;
+ u16 ccadc_offset;
+ int ccadc_gain_uv;
+ unsigned int revision;
+ int eoc_irq;
+ int r_sense;
+};
+
+static struct pm8xxx_ccadc_chip *the_chip;
+
+static s64 microvolt_to_ccadc_reading_v1(s64 uv)
+{
+ return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
+ CCADC_READING_RESOLUTION_N_V1);
+}
+
+static s64 microvolt_to_ccadc_reading_v2(s64 uv)
+{
+ return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
+ CCADC_READING_RESOLUTION_N_V2);
+}
+
+static s64 microvolt_to_ccadc_reading(struct pm8xxx_ccadc_chip *chip, s64 cc)
+{
+ /*
+ * resolution (the value of a single bit) was changed after revision 2.0
+ * for more accurate readings
+ */
+ return (the_chip->revision < PM8XXX_REVISION_8921_2p0) ?
+ microvolt_to_ccadc_reading_v1((s64)cc) :
+ microvolt_to_ccadc_reading_v2((s64)cc);
+}
+
+static int cc_adjust_for_offset(u16 raw)
+{
+ /* this has the intrinsic offset */
+ return (int)raw - the_chip->ccadc_offset;
+}
+
+#define GAIN_REFERENCE_UV 25000
+/*
+ * gain compensation for ccadc readings - common for vsense based and
+ * couloumb counter based readings
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+ if (the_chip == NULL || the_chip->ccadc_gain_uv == 0)
+ return uv;
+
+ return div_s64(uv * GAIN_REFERENCE_UV, the_chip->ccadc_gain_uv);
+}
+EXPORT_SYMBOL(pm8xxx_cc_adjust_for_gain);
+
+static int pm_ccadc_masked_write(struct pm8xxx_ccadc_chip *chip, u16 addr,
+ u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = pm8xxx_readb(chip->dev->parent, addr, ®);
+ if (rc) {
+ pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+ reg &= ~mask;
+ reg |= val & mask;
+ rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+ if (rc) {
+ pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+ return 0;
+}
+
+#define REG_SBI_CONFIG 0x04F
+#define PAGE3_ENABLE_MASK 0x6
+static int calib_ccadc_enable_trim_access(struct pm8xxx_ccadc_chip *chip,
+ u8 *sbi_config)
+{
+ u8 reg;
+ int rc;
+
+ rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+ if (rc) {
+ pr_err("error = %d reading sbi config reg\n", rc);
+ return rc;
+ }
+
+ reg = *sbi_config | PAGE3_ENABLE_MASK;
+ return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
+}
+
+static int calib_ccadc_restore_trim_access(struct pm8xxx_ccadc_chip *chip,
+ u8 sbi_config)
+{
+ return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+}
+
+static int calib_ccadc_enable_arbiter(struct pm8xxx_ccadc_chip *chip)
+{
+ int rc;
+
+ /* enable Arbiter, must be sent twice */
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ return rc;
+ }
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
+ return rc;
+ }
+ return 0;
+}
+
+static int calib_start_conv(struct pm8xxx_ccadc_chip *chip,
+ u16 *result)
+{
+ int rc, i;
+ u8 data_msb, data_lsb, reg;
+
+ /* Start conversion */
+ rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
+ START_CONV_BIT, START_CONV_BIT);
+ if (rc < 0) {
+ pr_err("error = %d starting offset meas\n", rc);
+ return rc;
+ }
+
+ /* Wait for End of conversion */
+ for (i = 0; i < ADC_WAIT_COUNT; i++) {
+ rc = pm8xxx_readb(chip->dev->parent,
+ ADC_ARB_SECP_CNTRL, ®);
+ if (rc < 0) {
+ pr_err("error = %d read eoc for offset\n", rc);
+ return rc;
+ }
+ if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
+ msleep(60);
+ else
+ break;
+ }
+ if (i == ADC_WAIT_COUNT) {
+ pr_err("waited too long for offset eoc\n");
+ return rc;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d reading offset lsb\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
+ if (rc < 0) {
+ pr_err("error = %d reading offset msb\n", rc);
+ return rc;
+ }
+
+ *result = (data_msb << 8) | data_lsb;
+ return 0;
+}
+
+static int calib_ccadc_read_trim(struct pm8xxx_ccadc_chip *chip,
+ int addr, u8 *data_msb, u8 *data_lsb)
+{
+ int rc;
+ u8 sbi_config;
+
+ calib_ccadc_enable_trim_access(chip, &sbi_config);
+ rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
+ if (rc < 0) {
+ pr_err("error = %d read msb\n", rc);
+ return rc;
+ }
+ rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d read lsb\n", rc);
+ return rc;
+ }
+ calib_ccadc_restore_trim_access(chip, sbi_config);
+ return 0;
+}
+
+static void calib_ccadc_read_offset_and_gain(struct pm8xxx_ccadc_chip *chip,
+ int *gain, u16 *offset)
+{
+ s8 data_msb;
+ u8 data_lsb;
+ int rc;
+
+ rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
+ &data_msb, &data_lsb);
+ *gain = (data_msb << 8) | data_lsb;
+
+ rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
+ &data_msb, &data_lsb);
+ *offset = (data_msb << 8) | data_lsb;
+
+ pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", *gain, *offset);
+ *gain = pm8xxx_ccadc_reading_to_microvolt(chip->revision,
+ (s64)*gain - *offset);
+ pr_debug("gain uv = %duV offset=0x%x\n", *gain, *offset);
+}
+
+#define CCADC_PROGRAM_TRIM_COUNT 2
+#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
+#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
+#define BMS_CONV_IN_PROGRESS 0x2
+
+static int calib_ccadc_program_trim(struct pm8xxx_ccadc_chip *chip,
+ int addr, u8 data_msb, u8 data_lsb,
+ int wait)
+{
+ int i, rc, loop;
+ u8 cntrl, sbi_config;
+ bool in_progress = 0;
+
+ loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
+
+ calib_ccadc_enable_trim_access(chip, &sbi_config);
+
+ for (i = 0; i < loop; i++) {
+ rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
+ if (rc < 0) {
+ pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
+ return rc;
+ }
+
+ /* break if a ccadc conversion is not happening */
+ in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
+ & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
+
+ if (!in_progress)
+ break;
+ }
+
+ if (in_progress) {
+ pr_debug("conv in progress cannot write trim,returing EBUSY\n");
+ return -EBUSY;
+ }
+
+ rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
+ if (rc < 0) {
+ pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
+ return rc;
+ }
+ rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
+ if (rc < 0) {
+ pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
+ return rc;
+ }
+ calib_ccadc_restore_trim_access(chip, sbi_config);
+ return 0;
+}
+
+void pm8xxx_calib_ccadc(void)
+{
+ u8 data_msb, data_lsb, sec_cntrl;
+ int result_offset, voltage_offset, result_gain;
+ u16 result;
+ int i, rc;
+
+ rc = pm8xxx_readb(the_chip->dev->parent,
+ ADC_ARB_SECP_CNTRL, &sec_cntrl);
+ if (rc < 0) {
+ pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
+ return;
+ }
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ goto bail;
+ }
+
+ /*
+ * Set decimation ratio to 4k, lower ratio may be used in order to speed
+ * up, pending verification through bench
+ */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_CALIB_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+ goto bail;
+ }
+
+ result_offset = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ /* Short analog inputs to CCADC internally to ground */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+ CCADC_CALIB_RSV_GND);
+ if (rc < 0) {
+ pr_err("error = %d selecting gnd voltage\n", rc);
+ goto bail;
+ }
+
+ /* Enable CCADC */
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ goto bail;
+ }
+
+ rc = calib_start_conv(the_chip, &result);
+ if (rc < 0) {
+ pr_err("error = %d for zero volt measurement\n", rc);
+ goto bail;
+ }
+
+ result_offset += result;
+ }
+
+ result_offset = result_offset / SAMPLE_COUNT;
+
+ voltage_offset = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ ((s64)result_offset - CCADC_INTRINSIC_OFFSET));
+
+ pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
+ result_offset, voltage_offset);
+
+ /* Sanity Check */
+ if (voltage_offset > CCADC_MAX_0UV) {
+ pr_err("offset voltage = %d is huge limiting to %d\n",
+ voltage_offset, CCADC_MAX_0UV);
+ result_offset = CCADC_INTRINSIC_OFFSET
+ + microvolt_to_ccadc_reading(the_chip,
+ (s64)CCADC_MAX_0UV);
+ } else if (voltage_offset < CCADC_MIN_0UV) {
+ pr_err("offset voltage = %d is too low limiting to %d\n",
+ voltage_offset, CCADC_MIN_0UV);
+ result_offset = CCADC_INTRINSIC_OFFSET
+ + microvolt_to_ccadc_reading(the_chip,
+ (s64)CCADC_MIN_0UV);
+ }
+
+ the_chip->ccadc_offset = result_offset;
+ data_msb = the_chip->ccadc_offset >> 8;
+ data_lsb = the_chip->ccadc_offset;
+
+ rc = calib_ccadc_program_trim(the_chip, CCADC_OFFSET_TRIM1,
+ data_msb, data_lsb, 1);
+ if (rc) {
+ pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
+ rc, data_msb, data_lsb);
+ /* enable the interrupt and write it when it fires */
+ enable_irq(the_chip->eoc_irq);
+ }
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for gain\n", rc);
+ goto bail;
+ }
+
+ /*
+ * Set decimation ratio to 4k, lower ratio may be used in order to speed
+ * up, pending verification through bench
+ */
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_CALIB_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling decimation ration for gain\n", rc);
+ goto bail;
+ }
+
+ result_gain = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
+ if (rc < 0) {
+ pr_err("error = %d selecting 25mV for gain\n", rc);
+ goto bail;
+ }
+
+ /* Enable CCADC */
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ goto bail;
+ }
+
+ rc = calib_start_conv(the_chip, &result);
+ if (rc < 0) {
+ pr_err("error = %d for adc reading 25mV\n", rc);
+ goto bail;
+ }
+
+ result_gain += result;
+ }
+ result_gain = result_gain / SAMPLE_COUNT;
+
+ /*
+ * result_offset includes INTRINSIC OFFSET
+ * the_chip->ccadc_gain_uv will be the actual voltage
+ * measured for 25000UV
+ */
+ the_chip->ccadc_gain_uv = pm8xxx_ccadc_reading_to_microvolt(
+ the_chip->revision,
+ ((s64)result_gain - result_offset));
+
+ pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
+ result_gain, the_chip->ccadc_gain_uv);
+ /* Sanity Check */
+ if (the_chip->ccadc_gain_uv > CCADC_MAX_25MV) {
+ pr_err("gain voltage = %d is huge limiting to %d\n",
+ the_chip->ccadc_gain_uv,
+ CCADC_MAX_25MV);
+ the_chip->ccadc_gain_uv = CCADC_MAX_25MV;
+ result_gain = result_offset +
+ microvolt_to_ccadc_reading(the_chip, CCADC_MAX_25MV);
+ } else if (the_chip->ccadc_gain_uv < CCADC_MIN_25MV) {
+ pr_err("gain voltage = %d is too low limiting to %d\n",
+ the_chip->ccadc_gain_uv,
+ CCADC_MIN_25MV);
+ the_chip->ccadc_gain_uv = CCADC_MIN_25MV;
+ result_gain = result_offset +
+ microvolt_to_ccadc_reading(the_chip, CCADC_MIN_25MV);
+ }
+
+ data_msb = result_gain >> 8;
+ data_lsb = result_gain;
+ rc = calib_ccadc_program_trim(the_chip, CCADC_FULLSCALE_TRIM1,
+ data_msb, data_lsb, 0);
+ if (rc)
+ pr_debug("error = %d programming gain trim\n", rc);
+bail:
+ pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
+}
+EXPORT_SYMBOL(pm8xxx_calib_ccadc);
+
+static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
+{
+ u8 data_msb, data_lsb;
+ struct pm8xxx_ccadc_chip *chip = data;
+ int rc;
+
+ pr_debug("irq = %d triggered\n", irq);
+ data_msb = chip->ccadc_offset >> 8;
+ data_lsb = chip->ccadc_offset;
+
+ rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
+ data_msb, data_lsb, 0);
+ disable_irq_nosync(chip->eoc_irq);
+
+ return IRQ_HANDLED;
+}
+
+#define CCADC_IBAT_DIG_PARAM 0xA3
+#define CCADC_IBAT_RSV 0x10
+#define CCADC_IBAT_ANA_PARAM 0x1A
+static int ccadc_get_rsense_voltage(int *voltage_uv)
+{
+ u16 raw;
+ int result;
+ int rc = 0;
+
+ rc = calib_ccadc_enable_arbiter(the_chip);
+ if (rc < 0) {
+ pr_err("error = %d enabling arbiter for offset\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
+ CCADC_IBAT_DIG_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
+ CCADC_IBAT_RSV);
+ if (rc < 0) {
+ pr_err("error = %d selecting rsense\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_writeb(the_chip->dev->parent,
+ ADC_ARB_SECP_ANA_PARAM, CCADC_IBAT_ANA_PARAM);
+ if (rc < 0) {
+ pr_err("error = %d enabling ccadc\n", rc);
+ return rc;
+ }
+
+ rc = calib_start_conv(the_chip, &raw);
+ if (rc < 0) {
+ pr_err("error = %d for zero volt measurement\n", rc);
+ return rc;
+ }
+
+ pr_debug("Vsense raw = 0x%x\n", raw);
+ result = cc_adjust_for_offset(raw);
+ pr_debug("Vsense after offset raw = 0x%x offset=0x%x\n",
+ result,
+ the_chip->ccadc_offset);
+ *voltage_uv = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
+ ((s64)result));
+ pr_debug("Vsense before gain = %d uV\n", *voltage_uv);
+ *voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
+
+ pr_debug("Vsense = %d uV\n", *voltage_uv);
+ return 0;
+}
+
+int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+ int voltage_uv, rc;
+
+ rc = ccadc_get_rsense_voltage(&voltage_uv);
+ if (rc) {
+ pr_err("cant get voltage across rsense rc = %d\n", rc);
+ return rc;
+ }
+
+ *bat_current = voltage_uv/the_chip->r_sense;
+ /*
+ * ccadc reads +ve current when the battery is charging
+ * We need to return -ve if the battery is charging
+ */
+ *bat_current = -1 * (*bat_current);
+ pr_debug("bat current = %d ma\n", *bat_current);
+ return 0;
+}
+EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
+
+static int get_reg(void *data, u64 * val)
+{
+ int addr = (int)data;
+ int ret;
+ u8 temp;
+
+ ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
+ if (ret) {
+ pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
+ addr, temp, ret);
+ return -EAGAIN;
+ }
+ *val = temp;
+ return 0;
+}
+
+static int set_reg(void *data, u64 val)
+{
+ int addr = (int)data;
+ int ret;
+ u8 temp;
+
+ temp = (u8) val;
+ ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
+ if (ret) {
+ pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
+ addr, temp, ret);
+ return -EAGAIN;
+ }
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
+
+static int get_calc(void *data, u64 * val)
+{
+ int ibat, rc;
+
+ rc = pm8xxx_ccadc_get_battery_current(&ibat);
+ *val = ibat;
+ return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%lld\n");
+
+static void create_debugfs_entries(struct pm8xxx_ccadc_chip *chip)
+{
+ chip->dent = debugfs_create_dir("pm8xxx-ccadc", NULL);
+
+ if (IS_ERR(chip->dent)) {
+ pr_err("ccadc couldnt create debugfs dir\n");
+ return;
+ }
+
+ debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
+ (void *)CCADC_ANA_PARAM, ®_fops);
+ debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
+ (void *)CCADC_DIG_PARAM, ®_fops);
+ debugfs_create_file("CCADC_RSV", 0644, chip->dent,
+ (void *)CCADC_RSV, ®_fops);
+ debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
+ (void *)CCADC_DATA0, ®_fops);
+ debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
+ (void *)CCADC_DATA1, ®_fops);
+ debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
+ (void *)CCADC_OFFSET_TRIM1, ®_fops);
+ debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
+ (void *)CCADC_OFFSET_TRIM0, ®_fops);
+ debugfs_create_file("CCADC_FULLSCALE_TRIM1", 0644, chip->dent,
+ (void *)CCADC_FULLSCALE_TRIM1, ®_fops);
+ debugfs_create_file("CCADC_FULLSCALE_TRIM0", 0644, chip->dent,
+ (void *)CCADC_FULLSCALE_TRIM0, ®_fops);
+
+ debugfs_create_file("show_ibatt", 0644, chip->dent,
+ (void *)0, &calc_fops);
+}
+
+static int __devinit pm8xxx_ccadc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct pm8xxx_ccadc_chip *chip;
+ struct resource *res;
+ const struct pm8xxx_ccadc_platform_data *pdata
+ = pdev->dev.platform_data;
+
+ if (!pdata) {
+ pr_err("missing platform data\n");
+ return -EINVAL;
+ }
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "PM8921_BMS_CCADC_EOC");
+ if (!res) {
+ pr_err("failed to get irq\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(struct pm8xxx_ccadc_chip), GFP_KERNEL);
+ if (!chip) {
+ pr_err("Cannot allocate pm_bms_chip\n");
+ return -ENOMEM;
+ }
+ chip->dev = &pdev->dev;
+ chip->revision = pm8xxx_get_revision(chip->dev->parent);
+ chip->eoc_irq = res->start;
+ chip->r_sense = pdata->r_sense;
+
+ rc = request_irq(chip->eoc_irq,
+ pm8921_bms_ccadc_eoc_handler, IRQF_TRIGGER_RISING,
+ "bms_eoc_ccadc", chip);
+ if (rc) {
+ pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
+ goto free_chip;
+ }
+
+ platform_set_drvdata(pdev, chip);
+ the_chip = chip;
+
+ create_debugfs_entries(chip);
+
+ calib_ccadc_read_offset_and_gain(chip,
+ &chip->ccadc_gain_uv,
+ &chip->ccadc_offset);
+ return 0;
+
+free_chip:
+ kfree(chip);
+ return rc;
+}
+
+static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_ccadc_chip *chip = platform_get_drvdata(pdev);
+
+ debugfs_remove_recursive(chip->dent);
+ the_chip = NULL;
+ kfree(chip);
+ return 0;
+}
+
+static struct platform_driver pm8xxx_ccadc_driver = {
+ .probe = pm8xxx_ccadc_probe,
+ .remove = __devexit_p(pm8xxx_ccadc_remove),
+ .driver = {
+ .name = PM8XXX_CCADC_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8xxx_ccadc_init(void)
+{
+ return platform_driver_register(&pm8xxx_ccadc_driver);
+}
+
+static void __exit pm8xxx_ccadc_exit(void)
+{
+ platform_driver_unregister(&pm8xxx_ccadc_driver);
+}
+
+module_init(pm8xxx_ccadc_init);
+module_exit(pm8xxx_ccadc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC8XXX ccadc driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_CCADC_DEV_NAME);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4622725..f8b320f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -567,6 +567,7 @@
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
bool session_active;
+ u32 phy_ctrl_val = 0;
if (atomic_read(&motg->in_lpm))
return 0;
@@ -638,8 +639,13 @@
writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
if (motg->caps & ALLOW_PHY_RETENTION && !session_active) {
- writel_relaxed(readl_relaxed(USB_PHY_CTRL) & ~PHY_RETEN,
- USB_PHY_CTRL);
+ phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ /* Enable PHY HV interrupts to wake MPM/Link */
+ phy_ctrl_val |=
+ (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+
+ writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
motg->lpm_flags |= PHY_RETENTIONED;
}
@@ -688,6 +694,7 @@
struct usb_bus *bus = otg->host;
int cnt = 0;
unsigned temp;
+ u32 phy_ctrl_val = 0;
if (!atomic_read(&motg->in_lpm))
return 0;
@@ -711,8 +718,13 @@
if (motg->lpm_flags & PHY_RETENTIONED) {
msm_hsusb_mhl_switch_enable(motg, 1);
msm_hsusb_config_vddcx(1);
- writel_relaxed(readl_relaxed(USB_PHY_CTRL) | PHY_RETEN,
- USB_PHY_CTRL);
+ phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
+ phy_ctrl_val |= PHY_RETEN;
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ /* Disable PHY HV interrupts */
+ phy_ctrl_val &=
+ ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+ writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
motg->lpm_flags &= ~PHY_RETENTIONED;
}
@@ -2362,13 +2374,17 @@
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
- if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
- motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+ if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
+ if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
motg->pdata->pmic_id_irq)
- motg->caps = ALLOW_PHY_POWER_COLLAPSE |
+ motg->caps = ALLOW_PHY_POWER_COLLAPSE |
ALLOW_PHY_RETENTION |
ALLOW_PHY_COMP_DISABLE;
+ if (motg->pdata->otg_control == OTG_PHY_CONTROL)
+ motg->caps = ALLOW_PHY_RETENTION;
+ }
+
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
new file mode 100644
index 0000000..6f6cb39
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -0,0 +1,100 @@
+/* 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.
+ */
+
+#ifndef __PMIC8XXX_CCADC_H__
+#define __PMIC8XXX_CCADC_H__
+
+#include <linux/mfd/pm8xxx/core.h>
+
+#define PM8XXX_CCADC_DEV_NAME "pm8xxx-ccadc"
+
+/**
+ * struct pm8xxx_ccadc_platform_data -
+ * @r_sense: sense resistor value in (mOhms)
+ */
+struct pm8xxx_ccadc_platform_data {
+ int r_sense;
+};
+
+#define CCADC_READING_RESOLUTION_N_V1 1085069
+#define CCADC_READING_RESOLUTION_D_V1 100000
+#define CCADC_READING_RESOLUTION_N_V2 542535
+#define CCADC_READING_RESOLUTION_D_V2 100000
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v1(s64 cc)
+{
+ return div_s64(cc * CCADC_READING_RESOLUTION_N_V1,
+ CCADC_READING_RESOLUTION_D_V1);
+}
+
+static s64 pm8xxx_ccadc_reading_to_microvolt_v2(s64 cc)
+{
+ return div_s64(cc * CCADC_READING_RESOLUTION_N_V2,
+ CCADC_READING_RESOLUTION_D_V2);
+}
+
+static inline s64 pm8xxx_ccadc_reading_to_microvolt(int revision, s64 cc)
+{
+ /*
+ * resolution (the value of a single bit) was changed after revision 2.0
+ * for more accurate readings
+ */
+ return (revision < PM8XXX_REVISION_8921_2p0) ?
+ pm8xxx_ccadc_reading_to_microvolt_v1((s64)cc) :
+ pm8xxx_ccadc_reading_to_microvolt_v2((s64)cc);
+}
+
+#if defined(CONFIG_PM8XXX_CCADC) || defined(CONFIG_PM8XXX_CCADC_MODULE)
+/**
+ * pm8xxx_cc_adjust_for_gain - the function to adjust the voltage read from
+ * ccadc for gain compensation
+ * @v: the voltage which needs to be gain compensated in microVolts
+ *
+ *
+ * RETURNS: gain compensated voltage
+ */
+s64 pm8xxx_cc_adjust_for_gain(s64 uv);
+
+/**
+ * pm8xxx_calib_ccadc - calibration for ccadc. This will calculate gain
+ * and offset and reprogram them in the appropriate
+ * registers
+ */
+void pm8xxx_calib_ccadc(void);
+
+/**
+ * pm8xxx_ccadc_get_battery_current - return the battery current based on vsense
+ * resitor in milliamperes
+ * @result: The pointer where the voltage will be updated. A -ve
+ * result means that the current is flowing in
+ * the battery - during battery charging
+ *
+ * RETURNS: Error code if there was a problem reading vsense, Zero otherwise
+ * The result won't be updated in case of an error.
+ *
+ */
+int pm8xxx_ccadc_get_battery_current(int *bat_current);
+#else
+static inline s64 pm8xxx_cc_adjust_for_gain(s64 uv)
+{
+ return -ENXIO;
+}
+static inline void pm8xxx_calib_ccadc(void)
+{
+}
+static inline int pm8xxx_ccadc_get_battery_current(int *bat_current)
+{
+ return -ENXIO;
+}
+#endif
+
+#endif /* __PMIC8XXX_CCADC_H__ */
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 73067b7..f39c00f 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -44,8 +44,8 @@
* @min_voltage: the voltage (mV) where charging method switches from
* trickle to fast. This is also the minimum voltage the
* system operates at
- * @resume_voltage: the voltage (mV) to wait for before resume charging
- * after the battery has been fully charged
+ * @resume_voltage_delta: the (mV) drop to wait for before resume charging
+ * after the battery has been fully charged
* @term_current: the charger current (mA) at which EOC happens
* @cool_temp: the temperature (degC) at which the battery is
* considered cool charging current and voltage is reduced
@@ -91,7 +91,7 @@
unsigned int update_time;
unsigned int max_voltage;
unsigned int min_voltage;
- unsigned int resume_voltage;
+ unsigned int resume_voltage_delta;
unsigned int term_current;
unsigned int cool_temp;
unsigned int warm_temp;
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 64bdab1..2c931b6 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -35,6 +35,7 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/leds-pm8xxx.h>
#include <linux/mfd/pm8xxx/vibrator.h>
+#include <linux/mfd/pm8xxx/ccadc.h>
#define PM8921_NR_IRQS 256
@@ -128,6 +129,7 @@
struct pm8921_adc_platform_data *adc_pdata;
struct pm8xxx_led_platform_data *leds_pdata;
struct pm8xxx_vibrator_platform_data *vibrator_pdata;
+ struct pm8xxx_ccadc_platform_data *ccadc_pdata;
};
#endif
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 9cb8356..fcd91da 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -51,6 +51,8 @@
#define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */
#define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */
#define PHY_RETEN (1 << 1) /* PHY retention enable/disable */
+#define PHY_IDHV_INTEN (1 << 8) /* PHY ID HV interrupt */
+#define PHY_OTGSESSVLDHV_INTEN (1 << 9) /* PHY Session Valid HV int. */
/* OTG definitions */
#define OTGSC_INTSTS_MASK (0x7f << 16)
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 97c08c0..cbe2eae 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -54,7 +54,6 @@
"inode.c:72",
"inode.c:73",
"inode.c:74",
- "menu.c:128",
"msm_sdcc.c:126",
"msm_sdcc.c:128",
"nf_conntrack_netlink.c:790",