]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
usb: phy: tegra: support apple charger detection
authorJosh Kuo <joshk@nvidia.com>
Wed, 30 Oct 2013 11:37:12 +0000 (19:37 +0800)
committerJon Mayo <jmayo@nvidia.com>
Mon, 18 Nov 2013 17:19:05 +0000 (09:19 -0800)
Adding the support to detect apple charger (500/1000/2000mA)

Bug 1383500

Change-Id: I1a8a91bec5642365f46383a8e7333ee4ef161d45
Signed-off-by: Josh Kuo <joshk@nvidia.com>
Reviewed-on: http://git-master/r/309593
Reviewed-by: Rakesh Babu Bodla <rbodla@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Reviewed-by: Greg Lo <glo@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/phy/tegra11x_usb_phy.c
drivers/usb/phy/tegra_usb_phy.h
include/linux/usb/tegra_usb_phy.h

index d2fbd6ff160d42cd716bfe0d6bfb507c00449f46..39769de6bdc35cd85f415b304860a22c163c4b3e 100644 (file)
@@ -604,6 +604,36 @@ bool tegra_usb_phy_nv_charger_detected(struct tegra_usb_phy *phy)
        return status;
 }
 
+bool tegra_usb_phy_apple_1000ma_charger_detected(struct tegra_usb_phy *phy)
+{
+       bool status = 0;
+       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+       if (phy->ops && phy->ops->apple_charger_1000ma_detect)
+               status = phy->ops->apple_charger_1000ma_detect(phy);
+
+       return status;
+}
+
+bool tegra_usb_phy_apple_2000ma_charger_detected(struct tegra_usb_phy *phy)
+{
+       bool status = 0;
+       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+       if (phy->ops && phy->ops->apple_charger_2000ma_detect)
+               status = phy->ops->apple_charger_2000ma_detect(phy);
+
+       return status;
+}
+
+bool tegra_usb_phy_apple_500ma_charger_detected(struct tegra_usb_phy *phy)
+{
+       bool status = 0;
+       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+       if (phy->ops && phy->ops->apple_charger_500ma_detect)
+               status = phy->ops->apple_charger_500ma_detect(phy);
+
+       return status;
+}
+
 bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy)
 {
        if (!phy->hw_accessible)
index 6f78a201fde61a4507705d688534bc545b525338..6833e06fec3e67d8f613a7e5c9a25bb24f3f5304 100644 (file)
 #define   UHSIC_PHY_ENABLE             (1 << 19)
 
 #define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define   DIV_DET_EN           (1 << 31)
 #define   VDCD_DET_STS         (1 << 26)
 #define   VDCD_DET_CHG_DET     (1 << 25)
+#define   VOP_DIV2P7_DET       (1 << 23)
+#define   VOP_DIV2P0_DET       (1 << 22)
+#define   VON_DIV2P7_DET       (1 << 15)
+#define   VON_DIV2P0_DET       (1 << 14)
 #define   VDAT_DET_INT_EN      (1 << 16)
 #define   VDAT_DET_CHG_DET     (1 << 17)
 #define   VDAT_DET_STS         (1 << 18)
@@ -1446,6 +1451,114 @@ static bool utmi_phy_nv_charger_detect(struct tegra_usb_phy *phy)
        return ret;
 }
 
+static bool utmi_phy_apple_charger_1000ma_detect(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       bool ret;
+       void __iomem *base = phy->regs;
+       unsigned long org_flags;
+
+       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+       ret = false;
+
+       org_flags = utmi_phy_set_dp_dm_pull_up_down(phy,
+                               FORCE_PULLUP_DP | FORCE_PULLUP_DM |
+                               DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+       usleep_range(20000, 30000);
+       utmi_phy_set_dp_dm_pull_up_down(phy,
+                               DISABLE_PULLUP_DP | DISABLE_PULLUP_DM |
+                               DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+
+       val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+       val |= DIV_DET_EN;
+       writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+       usleep_range(10000, 20000);
+
+       val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+       val &= ~DIV_DET_EN;
+       writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+       if ((val & VOP_DIV2P0_DET) && (val & VON_DIV2P7_DET))
+               ret = true;
+
+       utmi_phy_set_dp_dm_pull_up_down(phy, org_flags);
+
+       return ret;
+}
+
+static bool utmi_phy_apple_charger_2000ma_detect(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       bool ret;
+       void __iomem *base = phy->regs;
+       unsigned long org_flags;
+
+       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+       ret = false;
+
+       org_flags = utmi_phy_set_dp_dm_pull_up_down(phy,
+                               FORCE_PULLUP_DP | FORCE_PULLUP_DM |
+                               DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+       usleep_range(20000, 30000);
+       utmi_phy_set_dp_dm_pull_up_down(phy,
+                               DISABLE_PULLUP_DP | DISABLE_PULLUP_DM |
+                               DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+
+       val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+       val |= DIV_DET_EN;
+       writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+       usleep_range(10000, 20000);
+
+       val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+       val &= ~DIV_DET_EN;
+       writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+       if ((val & VOP_DIV2P7_DET) && (val & VON_DIV2P0_DET))
+               ret = true;
+
+       utmi_phy_set_dp_dm_pull_up_down(phy, org_flags);
+
+       return ret;
+}
+
+static bool utmi_phy_apple_charger_500ma_detect(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       bool ret;
+       void __iomem *base = phy->regs;
+       unsigned long org_flags;
+
+       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+       ret = false;
+
+       org_flags = utmi_phy_set_dp_dm_pull_up_down(phy,
+                               FORCE_PULLUP_DP | FORCE_PULLUP_DM |
+                               DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+       usleep_range(20000, 30000);
+       utmi_phy_set_dp_dm_pull_up_down(phy,
+                               DISABLE_PULLUP_DP | DISABLE_PULLUP_DM |
+                               DISABLE_PULLDN_DP | DISABLE_PULLDN_DM);
+
+       val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+       val |= DIV_DET_EN;
+       writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+       usleep_range(10000, 20000);
+
+       val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+       val &= ~DIV_DET_EN;
+       writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+       if ((val & VOP_DIV2P0_DET) && (val & VON_DIV2P0_DET))
+               ret = true;
+
+       utmi_phy_set_dp_dm_pull_up_down(phy, org_flags);
+
+       return ret;
+}
+
 static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
 {
        void __iomem *base = phy->regs;
@@ -2005,6 +2118,9 @@ static struct tegra_usb_phy_ops utmi_phy_ops = {
        .resume = utmi_phy_resume,
        .charger_detect = utmi_phy_charger_detect,
        .nv_charger_detect = utmi_phy_nv_charger_detect,
+       .apple_charger_1000ma_detect = utmi_phy_apple_charger_1000ma_detect,
+       .apple_charger_2000ma_detect = utmi_phy_apple_charger_2000ma_detect,
+       .apple_charger_500ma_detect = utmi_phy_apple_charger_500ma_detect,
        .pmc_disable = utmi_phy_pmc_disable,
 };
 
index 4893c91b00c203a558167b481d7bd62e338602a8..9057d2dbfd38ff673266898d771e4ce75b9b5818 100644 (file)
@@ -68,6 +68,9 @@ struct tegra_usb_phy_ops {
        int (*power_on)(struct tegra_usb_phy *phy);
        bool (*charger_detect)(struct tegra_usb_phy *phy);
        bool (*nv_charger_detect)(struct tegra_usb_phy *phy);
+       bool (*apple_charger_1000ma_detect)(struct tegra_usb_phy *phy);
+       bool (*apple_charger_2000ma_detect)(struct tegra_usb_phy *phy);
+       bool (*apple_charger_500ma_detect)(struct tegra_usb_phy *phy);
        void (*pmc_disable) (struct tegra_usb_phy *phy);
 };
 
index 2feb79658129f298a0bd6347d9664028f572c173..cdab5a1b261156af7463e8560f7212a49e4d2096 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2011 NVIDIA Corporation.
+ * Copyright (c) 2010 Google, Inc.
+ * Copyright (c) 2011-2013, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -100,6 +100,24 @@ bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy);
  */
 bool tegra_usb_phy_nv_charger_detected(struct tegra_usb_phy *phy);
 
+/**
+ * Indicates whether apple 1A charger is connected or not
+ * if apple 1A charger is detected then returns true else false
+ */
+bool tegra_usb_phy_apple_1000ma_charger_detected(struct tegra_usb_phy *phy);
+
+/**
+ * Indicates whether apple 2A charger is connected or not
+ * if apple 2A charger is detected then returns true else false
+ */
+bool tegra_usb_phy_apple_2000ma_charger_detected(struct tegra_usb_phy *phy);
+
+/**
+ * Indicates whether apple 0.5A charger is connected or not
+ * if apple 0.5A charger is detected then returns true else false
+ */
+bool tegra_usb_phy_apple_500ma_charger_detected(struct tegra_usb_phy *phy);
+
 /**
  * Indicates whether phy resumed due to the pmc remote/hotplug wake event
  *  or not, returns true if remote/hotplug wake is detected.