Port USB Fastcharge : originally ported by showp1984

         https://github.com/showp1984/bricked-pyramid-3.0/commit/9074f71ce46a984ad790e1b6ffb2ff4221d7afd1
         https://github.com/showp1984/bricked-pyramid-3.0/commit/515dedcf5fa3268942b282f0ecbb36533d4245da

        USB forced fast charge v2

        Use sysfs interface to change behaviour :

         * /sys/kernel/fast_charge/force_fast_charge (rw)
         *
         *   0 - disabled (default)
         *   1 - substitute AC to USB charging always
         *   2 - substitute AC to USB charging only if no USB peripheral is detected

        For informational purposes I've also added a read-only sysfs file that indicates the current USB state :

         * /sys/kernel/fast_charge/USB_peripheral_detected (ro)
         *
         * The state will be returned in clear text (Yes/No).

        For informational purposes I've also added a read-only sysfs file that indicates the detected USB port type :

         * /sys/kernel/fast_charge/USB_porttype_detected (ro)
         *
         * The port type will be returned in clear text.

Change-Id: Iccd151e5bcd07af74859f5fe177312a12fb891c7
diff --git a/arch/arm/configs/pyramid_defconfig b/arch/arm/configs/pyramid_defconfig
index 46cf943..c1f1c31 100644
--- a/arch/arm/configs/pyramid_defconfig
+++ b/arch/arm/configs/pyramid_defconfig
@@ -409,6 +409,7 @@
 CONFIG_HTC_HEADSET_GPIO=y
 CONFIG_HTC_HEADSET_8X60=y
 CONFIG_HTC_WAKE_ON_VOL=y
+CONFIG_FORCE_FAST_CHARGE=y
 
 #
 # HP Board Selection
diff --git a/arch/arm/mach-msm/htc/Kconfig b/arch/arm/mach-msm/htc/Kconfig
index 1030a1c..2115bc2 100644
--- a/arch/arm/mach-msm/htc/Kconfig
+++ b/arch/arm/mach-msm/htc/Kconfig
@@ -76,4 +76,12 @@
 	help
 	  Provides support for HTC GPIO headset detection.
 
+config FORCE_FAST_CHARGE
+	bool "Force AC charge mode at will"
+	depends on ARCH_MSM8X60
+	default n
+	help
+	  A simple sysfs interface to force adapters that
+	  are detected as USB to charge as AC.
+
 endmenu
diff --git a/arch/arm/mach-msm/htc/Makefile b/arch/arm/mach-msm/htc/Makefile
index dbd31e0..647a51c 100644
--- a/arch/arm/mach-msm/htc/Makefile
+++ b/arch/arm/mach-msm/htc/Makefile
@@ -23,6 +23,7 @@
 obj-$(CONFIG_HTC_BATT_CORE) += htc_battery_core.o
 obj-$(CONFIG_HTC_BATT_8x60) += htc_battery_8x60.o
 obj-$(CONFIG_HTC_BATT_8960) += htc_battery_8960.o htc_battery_cell.o
+obj-$(CONFIG_FORCE_FAST_CHARGE) += fastchg.o
 obj-$(CONFIG_MSM_NATIVE_RESTART) += htc_restart_handler.o
 
 obj-$(CONFIG_HTC_HEADSET_MGR) += htc_headset_mgr.o
diff --git a/arch/arm/mach-msm/htc/fastchg.c b/arch/arm/mach-msm/htc/fastchg.c
new file mode 100644
index 0000000..9b8f1f9
--- /dev/null
+++ b/arch/arm/mach-msm/htc/fastchg.c
@@ -0,0 +1,180 @@
+/*
+ * Author: Chad Froebel <chadfroebel@gmail.com>
+ *
+ * Ported to Sensation and extended : Jean-Pierre Rasquin <yank555.lu@gmail.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.
+ *
+ */
+
+/*
+ * Possible values for "force_fast_charge" are :
+ *
+ *   0 - disabled (default)
+ *   1 - substitute AC to USB unconditional
+ *   2 - substitute AC to USB only if no USB peripheral is detected
+ *
+ * Possible values for "USB_peripheral_detected" are :
+ *
+ *   0 - No USB accessory currently attached (default)
+ *   1 - USB accessory currently attached
+ *
+ * Possible values for "USB_porttype_detected" are :
+ *
+ *   0 - invalid USB port
+ *   1 - standard downstream port
+ *   2 - dedicated charging port
+ *   3 - charging downstream port
+ *   4 - accessory charger adapter A
+ *   5 - accessory charger adapter B
+ *   6 - accessory charger adapter C
+ *   7 - accessory charger adapter dock
+ *  10 - nothing attached (default)
+ */
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/fastchg.h>
+
+int force_fast_charge;
+int USB_peripheral_detected;
+int USB_porttype_detected;
+
+/* sysfs interface for "force_fast_charge" */
+static ssize_t force_fast_charge_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+return sprintf(buf, "%d\n", force_fast_charge);
+}
+
+static ssize_t force_fast_charge_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+
+int new_force_fast_charge;
+
+sscanf(buf, "%du", &new_force_fast_charge);
+
+if (new_force_fast_charge >= FAST_CHARGE_DISABLED && new_force_fast_charge <= FAST_CHARGE_FORCE_AC_IF_NO_USB) {
+
+	/* update only if valid value provided */
+	force_fast_charge = new_force_fast_charge;
+
+}
+
+return count;
+}
+
+static struct kobj_attribute force_fast_charge_attribute =
+__ATTR(force_fast_charge, 0666, force_fast_charge_show, force_fast_charge_store);
+
+static struct attribute *force_fast_charge_attrs[] = {
+&force_fast_charge_attribute.attr,
+NULL,
+};
+
+static struct attribute_group force_fast_charge_attr_group = {
+.attrs = force_fast_charge_attrs,
+};
+
+/* sysfs interface for "USB_peripheral_detected" */
+static ssize_t USB_peripheral_detected_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	switch (USB_peripheral_detected) {
+		case USB_ACC_NOT_DETECTED:	return sprintf(buf, "No\n");
+		case USB_ACC_DETECTED:		return sprintf(buf, "Yes\n");
+		default:			return sprintf(buf, "something went wrong\n");
+	}
+}
+
+static ssize_t USB_peripheral_detected_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+/* no user change allowed */
+return count;
+}
+
+static struct kobj_attribute USB_peripheral_detected_attribute =
+__ATTR(USB_peripheral_detected, 0444, USB_peripheral_detected_show, USB_peripheral_detected_store);
+
+static struct attribute *USB_peripheral_detected_attrs[] = {
+&USB_peripheral_detected_attribute.attr,
+NULL,
+};
+
+static struct attribute_group USB_peripheral_detected_attr_group = {
+.attrs = USB_peripheral_detected_attrs,
+};
+
+/* sysfs interface for "USB_porttype_detected" */
+static ssize_t USB_porttype_detected_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	switch (USB_porttype_detected) {
+		case USB_INVALID_DETECTED:	return sprintf(buf, "Invalid Port\n");
+		case USB_SDP_DETECTED:		return sprintf(buf, "Standard Downstream Port\n");
+		case USB_DCP_DETECTED:		return sprintf(buf, "Dedicated Charging Port\n");
+		case USB_CDP_DETECTED:		return sprintf(buf, "Charging Downstream Port\n");
+		case USB_ACA_A_DETECTED:	return sprintf(buf, "Accessory Charger Adapter A\n");
+		case USB_ACA_B_DETECTED:	return sprintf(buf, "Accessory Charger Adapter B\n");
+		case USB_ACA_C_DETECTED:	return sprintf(buf, "Accessory Charger Adapter C\n");
+		case USB_ACA_DOCK_DETECTED:	return sprintf(buf, "Accessory Charger Adapter Dock\n");
+		case NO_USB_DETECTED:		return sprintf(buf, "No Port\n");
+		default:			return sprintf(buf, "something went wrong\n");
+	}
+}
+
+static ssize_t USB_porttype_detected_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+/* no user change allowed */
+return count;
+}
+
+static struct kobj_attribute USB_porttype_detected_attribute =
+__ATTR(USB_porttype_detected, 0444, USB_porttype_detected_show, USB_porttype_detected_store);
+
+static struct attribute *USB_porttype_detected_attrs[] = {
+&USB_porttype_detected_attribute.attr,
+NULL,
+};
+
+static struct attribute_group USB_porttype_detected_attr_group = {
+.attrs = USB_porttype_detected_attrs,
+};
+
+/* Initialize fast charge sysfs folder */
+static struct kobject *force_fast_charge_kobj;
+
+int force_fast_charge_init(void)
+{
+	int force_fast_charge_retval;
+	int USB_peripheral_detected_retval;
+	int USB_porttype_detected_retval;
+
+	force_fast_charge = FAST_CHARGE_DISABLED; /* Forced fast charge disabled by default */
+	USB_peripheral_detected = USB_ACC_NOT_DETECTED; /* Consider no USB accessory detected so far */
+	USB_porttype_detected = NO_USB_DETECTED; /* Consider no USB port is yet detected */
+
+        force_fast_charge_kobj = kobject_create_and_add("fast_charge", kernel_kobj);
+        if (!force_fast_charge_kobj) {
+                return -ENOMEM;
+        }
+        force_fast_charge_retval = sysfs_create_group(force_fast_charge_kobj, &force_fast_charge_attr_group);
+        USB_peripheral_detected_retval = sysfs_create_group(force_fast_charge_kobj, &USB_peripheral_detected_attr_group);
+        USB_porttype_detected_retval = sysfs_create_group(force_fast_charge_kobj, &USB_porttype_detected_attr_group);
+        if (force_fast_charge_retval && USB_peripheral_detected_retval && USB_porttype_detected_retval)
+                kobject_put(force_fast_charge_kobj);
+        return (force_fast_charge_retval && USB_peripheral_detected_retval && USB_porttype_detected_retval);
+}
+/* end sysfs interface */
+
+void force_fast_charge_exit(void)
+{
+	kobject_put(force_fast_charge_kobj);
+}
+
+module_init(force_fast_charge_init);
+module_exit(force_fast_charge_exit);
diff --git a/arch/arm/mach-msm/htc/htc_battery_8x60.c b/arch/arm/mach-msm/htc/htc_battery_8x60.c
index 9cbd4db..a9e1303 100644
--- a/arch/arm/mach-msm/htc/htc_battery_8x60.c
+++ b/arch/arm/mach-msm/htc/htc_battery_8x60.c
@@ -39,6 +39,10 @@
 #include <linux/earlysuspend.h>
 #include <mach/rpm.h>
 
+#ifdef CONFIG_FORCE_FAST_CHARGE
+#include <linux/fastchg.h>
+#endif
+
 #define BATT_SUSPEND_CHECK_TIME			3600
 #define BATT_SUSPEND_HIGHFREQ_CHECK_TIME	(300)
 #define BATT_TIMER_CHECK_TIME			360
@@ -308,9 +312,24 @@
 
 	switch (online) {
 	case CONNECT_TYPE_USB:
+#ifdef CONFIG_FORCE_FAST_CHARGE
+		/* If forced fast charge is enabled "always" or if no USB device detected, go AC */
+		if ((force_fast_charge == FAST_CHARGE_FORCE_AC) ||
+		    (force_fast_charge == FAST_CHARGE_FORCE_AC_IF_NO_USB &&
+                     USB_peripheral_detected == USB_ACC_NOT_DETECTED        )) {
+			BATT_LOG("cable USB forced to AC");
+			htc_batt_info.rep.charging_source = CHARGER_AC;
+			radio_set_cable_status(CHARGER_AC);
+		} else {
+			BATT_LOG("cable USB not forced to AC");
+			htc_batt_info.rep.charging_source = CHARGER_USB;
+			radio_set_cable_status(CHARGER_USB);
+		}
+#else
 		BATT_LOG("cable USB");
 		htc_batt_info.rep.charging_source = CHARGER_USB;
 		radio_set_cable_status(CHARGER_USB);
+#endif
 		break;
 	case CONNECT_TYPE_AC:
 	case CONNECT_TYPE_MHL_AC:
diff --git a/drivers/usb/otg/msm_otg_htc.c b/drivers/usb/otg/msm_otg_htc.c
index 6fc9595..8030220 100644
--- a/drivers/usb/otg/msm_otg_htc.c
+++ b/drivers/usb/otg/msm_otg_htc.c
@@ -50,6 +50,10 @@
 #include <mach/board.h>
 #include <mach/board_htc.h>
 
+#ifdef CONFIG_FORCE_FAST_CHARGE
+#include <linux/fastchg.h>
+#endif
+
 #define MSM_USB_BASE	(motg->regs)
 #define DRIVER_NAME	"msm_otg"
 
@@ -73,6 +77,15 @@
 
 	motg->connect_type_ready = 1;
 	USBH_INFO("send connect type %d\n", motg->connect_type);
+#ifdef CONFIG_FORCE_FAST_CHARGE
+	if (motg->connect_type == CONNECT_TYPE_USB) {
+		USB_peripheral_detected = USB_ACC_DETECTED; /* Inform forced fast charge that a USB accessory has been attached */
+		USBH_INFO("USB forced fast charge : USB device currently attached");
+	} else {
+		USB_peripheral_detected = USB_ACC_NOT_DETECTED; /* Inform forced fast charge that a USB accessory has not been attached */
+		USBH_INFO("USB forced fast charge : No USB device currently attached");
+	}
+#endif
 	mutex_lock(&notify_sem);
 	list_for_each_entry(notifier, &g_lh_usb_notifier_list, notifier_link) {
 		if (notifier->func != NULL) {
@@ -653,6 +666,10 @@
 	u32 ulpi_val = 0;
 	USBH_INFO("%s\n", __func__);
 
+#ifdef CONFIG_FORCE_FAST_CHARGE
+	USB_porttype_detected = NO_USB_DETECTED; /* No USB plugged, clear fast charge detected port value */
+#endif
+
 	/*
 	 * USB PHY and Link reset also reset the USB BAM.
 	 * Thus perform reset operation only once to avoid
@@ -2225,6 +2242,27 @@
 		msm_chg_enable_aca_intr(motg);
 		USBH_INFO("chg_type = %s\n",
 			chg_to_string(motg->chg_type));
+
+#ifdef CONFIG_FORCE_FAST_CHARGE
+		switch (motg->chg_type) {
+		case USB_SDP_CHARGER:		USB_porttype_detected = USB_SDP_DETECTED;
+						break;
+		case USB_DCP_CHARGER:		USB_porttype_detected = USB_DCP_DETECTED;
+						break;
+		case USB_CDP_CHARGER:		USB_porttype_detected = USB_CDP_DETECTED;
+						break;
+		case USB_ACA_A_CHARGER:		USB_porttype_detected = USB_ACA_A_DETECTED;
+						break;
+		case USB_ACA_B_CHARGER:		USB_porttype_detected = USB_ACA_B_DETECTED;
+						break;
+		case USB_ACA_C_CHARGER:		USB_porttype_detected = USB_ACA_C_DETECTED;
+						break;
+		case USB_ACA_DOCK_CHARGER:	USB_porttype_detected = USB_ACA_DOCK_DETECTED;
+						break;
+		default:			USB_porttype_detected = USB_INVALID_DETECTED;
+						break;
+		}
+#endif
 		queue_work(system_nrt_wq, &motg->sm_work);
 		queue_work(motg->usb_wq, &motg->notifier_work);
 		return;
diff --git a/include/linux/fastchg.h b/include/linux/fastchg.h
new file mode 100644
index 0000000..f300c4a
--- /dev/null
+++ b/include/linux/fastchg.h
@@ -0,0 +1,42 @@
+/*
+ * Author: Chad Froebel <chadfroebel@gmail.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.
+ *
+ */
+
+
+#ifndef _LINUX_FASTCHG_H
+#define _LINUX_FASTCHG_H
+
+extern int force_fast_charge;
+
+#define FAST_CHARGE_DISABLED 0	/* default */
+#define FAST_CHARGE_FORCE_AC 1
+#define FAST_CHARGE_FORCE_AC_IF_NO_USB 2
+
+extern int USB_peripheral_detected;
+
+#define USB_ACC_NOT_DETECTED 0	/* default */
+#define USB_ACC_DETECTED 1
+
+#define USB_INVALID_DETECTED 0
+#define USB_SDP_DETECTED 1
+#define USB_DCP_DETECTED 2
+#define USB_CDP_DETECTED 3
+#define USB_ACA_A_DETECTED 4
+#define USB_ACA_B_DETECTED 5
+#define USB_ACA_C_DETECTED 6
+#define USB_ACA_DOCK_DETECTED 7
+#define NO_USB_DETECTED 10	/* default */
+
+extern int USB_porttype_detected;
+
+#endif