forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f9004dbfff8a3fbbd7e2a88c8a4327c7f2f8e5b2
kernel/drivers/extcon/extcon-intel-cht-wc.c
....@@ -1,18 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
23 * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
34 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
45 *
56 * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
67 * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
7
- *
8
- * This program is free software; you can redistribute it and/or modify it
9
- * under the terms and conditions of the GNU General Public License,
10
- * version 2, as published by the Free Software Foundation.
11
- *
12
- * This program is distributed in the hope it will be useful, but WITHOUT
13
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
- * more details.
168 */
179
1810 #include <linux/extcon-provider.h>
....@@ -25,6 +17,8 @@
2517 #include <linux/regmap.h>
2618 #include <linux/slab.h>
2719
20
+#include "extcon-intel.h"
21
+
2822 #define CHT_WC_PHYCTRL 0x5e07
2923
3024 #define CHT_WC_CHGRCTRL0 0x5e16
....@@ -32,12 +26,20 @@
3226 #define CHT_WC_CHGRCTRL0_EMRGCHREN BIT(1)
3327 #define CHT_WC_CHGRCTRL0_EXTCHRDIS BIT(2)
3428 #define CHT_WC_CHGRCTRL0_SWCONTROL BIT(3)
35
-#define CHT_WC_CHGRCTRL0_TTLCK_MASK BIT(4)
36
-#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK BIT(5)
37
-#define CHT_WC_CHGRCTRL0_DBPOFF_MASK BIT(6)
38
-#define CHT_WC_CHGRCTRL0_WDT_NOKICK BIT(7)
29
+#define CHT_WC_CHGRCTRL0_TTLCK BIT(4)
30
+#define CHT_WC_CHGRCTRL0_CCSM_OFF BIT(5)
31
+#define CHT_WC_CHGRCTRL0_DBPOFF BIT(6)
32
+#define CHT_WC_CHGRCTRL0_CHR_WDT_NOKICK BIT(7)
3933
40
-#define CHT_WC_CHGRCTRL1 0x5e17
34
+#define CHT_WC_CHGRCTRL1 0x5e17
35
+#define CHT_WC_CHGRCTRL1_FUSB_INLMT_100 BIT(0)
36
+#define CHT_WC_CHGRCTRL1_FUSB_INLMT_150 BIT(1)
37
+#define CHT_WC_CHGRCTRL1_FUSB_INLMT_500 BIT(2)
38
+#define CHT_WC_CHGRCTRL1_FUSB_INLMT_900 BIT(3)
39
+#define CHT_WC_CHGRCTRL1_FUSB_INLMT_1500 BIT(4)
40
+#define CHT_WC_CHGRCTRL1_FTEMP_EVENT BIT(5)
41
+#define CHT_WC_CHGRCTRL1_OTGMODE BIT(6)
42
+#define CHT_WC_CHGRCTRL1_DBPEN BIT(7)
4143
4244 #define CHT_WC_USBSRC 0x5e29
4345 #define CHT_WC_USBSRC_STS_MASK GENMASK(1, 0)
....@@ -52,32 +54,33 @@
5254 #define CHT_WC_USBSRC_TYPE_ACA 4
5355 #define CHT_WC_USBSRC_TYPE_SE1 5
5456 #define CHT_WC_USBSRC_TYPE_MHL 6
55
-#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN 7
57
+#define CHT_WC_USBSRC_TYPE_FLOATING 7
5658 #define CHT_WC_USBSRC_TYPE_OTHER 8
5759 #define CHT_WC_USBSRC_TYPE_DCP_EXTPHY 9
60
+
61
+#define CHT_WC_CHGDISCTRL 0x5e2f
62
+#define CHT_WC_CHGDISCTRL_OUT BIT(0)
63
+/* 0 - open drain, 1 - regular push-pull output */
64
+#define CHT_WC_CHGDISCTRL_DRV BIT(4)
65
+/* 0 - pin is controlled by SW, 1 - by HW */
66
+#define CHT_WC_CHGDISCTRL_FN BIT(6)
5867
5968 #define CHT_WC_PWRSRC_IRQ 0x6e03
6069 #define CHT_WC_PWRSRC_IRQ_MASK 0x6e0f
6170 #define CHT_WC_PWRSRC_STS 0x6e1e
6271 #define CHT_WC_PWRSRC_VBUS BIT(0)
6372 #define CHT_WC_PWRSRC_DC BIT(1)
64
-#define CHT_WC_PWRSRC_BAT BIT(2)
65
-#define CHT_WC_PWRSRC_ID_GND BIT(3)
66
-#define CHT_WC_PWRSRC_ID_FLOAT BIT(4)
73
+#define CHT_WC_PWRSRC_BATT BIT(2)
74
+#define CHT_WC_PWRSRC_USBID_MASK GENMASK(4, 3)
75
+#define CHT_WC_PWRSRC_USBID_SHIFT 3
76
+#define CHT_WC_PWRSRC_RID_ACA 0
77
+#define CHT_WC_PWRSRC_RID_GND 1
78
+#define CHT_WC_PWRSRC_RID_FLOAT 2
6779
6880 #define CHT_WC_VBUS_GPIO_CTLO 0x6e2d
6981 #define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0)
7082 #define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4)
7183 #define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5)
72
-
73
-enum cht_wc_usb_id {
74
- USB_ID_OTG,
75
- USB_ID_GND,
76
- USB_ID_FLOAT,
77
- USB_RID_A,
78
- USB_RID_B,
79
- USB_RID_C,
80
-};
8184
8285 enum cht_wc_mux_select {
8386 MUX_SEL_PMIC = 0,
....@@ -104,16 +107,20 @@
104107
105108 static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
106109 {
107
- if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
108
- return USB_ID_GND;
109
- if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
110
- return USB_ID_FLOAT;
111
-
112
- /*
113
- * Once we have iio support for the gpadc we should read the USBID
114
- * gpadc channel here and determine ACA role based on that.
115
- */
116
- return USB_ID_FLOAT;
110
+ switch ((pwrsrc_sts & CHT_WC_PWRSRC_USBID_MASK) >> CHT_WC_PWRSRC_USBID_SHIFT) {
111
+ case CHT_WC_PWRSRC_RID_GND:
112
+ return INTEL_USB_ID_GND;
113
+ case CHT_WC_PWRSRC_RID_FLOAT:
114
+ return INTEL_USB_ID_FLOAT;
115
+ case CHT_WC_PWRSRC_RID_ACA:
116
+ default:
117
+ /*
118
+ * Once we have IIO support for the GPADC we should read
119
+ * the USBID GPADC channel here and determine ACA role
120
+ * based on that.
121
+ */
122
+ return INTEL_USB_ID_FLOAT;
123
+ }
117124 }
118125
119126 static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
....@@ -158,7 +165,7 @@
158165 ret);
159166 return EXTCON_CHG_USB_SDP;
160167 case CHT_WC_USBSRC_TYPE_SDP:
161
- case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
168
+ case CHT_WC_USBSRC_TYPE_FLOATING:
162169 case CHT_WC_USBSRC_TYPE_OTHER:
163170 return EXTCON_CHG_USB_SDP;
164171 case CHT_WC_USBSRC_TYPE_CDP:
....@@ -199,6 +206,30 @@
199206 dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret);
200207 }
201208
209
+static void cht_wc_extcon_set_otgmode(struct cht_wc_extcon_data *ext,
210
+ bool enable)
211
+{
212
+ unsigned int val = enable ? CHT_WC_CHGRCTRL1_OTGMODE : 0;
213
+ int ret;
214
+
215
+ ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL1,
216
+ CHT_WC_CHGRCTRL1_OTGMODE, val);
217
+ if (ret)
218
+ dev_err(ext->dev, "Error updating CHGRCTRL1 reg: %d\n", ret);
219
+}
220
+
221
+static void cht_wc_extcon_enable_charging(struct cht_wc_extcon_data *ext,
222
+ bool enable)
223
+{
224
+ unsigned int val = enable ? 0 : CHT_WC_CHGDISCTRL_OUT;
225
+ int ret;
226
+
227
+ ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL,
228
+ CHT_WC_CHGDISCTRL_OUT, val);
229
+ if (ret)
230
+ dev_err(ext->dev, "Error updating CHGDISCTRL reg: %d\n", ret);
231
+}
232
+
202233 /* Small helper to sync EXTCON_CHG_USB_SDP and EXTCON_USB state */
203234 static void cht_wc_extcon_set_state(struct cht_wc_extcon_data *ext,
204235 unsigned int cable, bool state)
....@@ -222,10 +253,16 @@
222253 }
223254
224255 id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
225
- if (id == USB_ID_GND) {
256
+ if (id == INTEL_USB_ID_GND) {
257
+ cht_wc_extcon_enable_charging(ext, false);
258
+ cht_wc_extcon_set_otgmode(ext, true);
259
+
226260 /* The 5v boost causes a false VBUS / SDP detect, skip */
227261 goto charger_det_done;
228262 }
263
+
264
+ cht_wc_extcon_set_otgmode(ext, false);
265
+ cht_wc_extcon_enable_charging(ext, true);
229266
230267 /* Plugged into a host/charger or not connected? */
231268 if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) {
....@@ -249,7 +286,7 @@
249286 ext->previous_cable = cable;
250287 }
251288
252
- ext->usb_host = ((id == USB_ID_GND) || (id == USB_RID_A));
289
+ ext->usb_host = ((id == INTEL_USB_ID_GND) || (id == INTEL_USB_RID_A));
253290 extcon_set_state_sync(ext->edev, EXTCON_USB_HOST, ext->usb_host);
254291 }
255292
....@@ -279,7 +316,15 @@
279316 {
280317 int ret, mask, val;
281318
282
- mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK;
319
+ val = enable ? 0 : CHT_WC_CHGDISCTRL_FN;
320
+ ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL,
321
+ CHT_WC_CHGDISCTRL_FN, val);
322
+ if (ret)
323
+ dev_err(ext->dev,
324
+ "Error setting sw control for CHGDIS pin: %d\n",
325
+ ret);
326
+
327
+ mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF;
283328 val = enable ? mask : 0;
284329 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val);
285330 if (ret)
....@@ -292,6 +337,8 @@
292337 {
293338 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
294339 struct cht_wc_extcon_data *ext;
340
+ unsigned long mask = ~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_USBID_MASK);
341
+ int pwrsrc_sts, id;
295342 int irq, ret;
296343
297344 irq = platform_get_irq(pdev, 0);
....@@ -329,7 +376,10 @@
329376 /* Enable sw control */
330377 ret = cht_wc_extcon_sw_control(ext, true);
331378 if (ret)
332
- return ret;
379
+ goto disable_sw_control;
380
+
381
+ /* Disable charging by external battery charger */
382
+ cht_wc_extcon_enable_charging(ext, false);
333383
334384 /* Register extcon device */
335385 ret = devm_extcon_dev_register(ext->dev, ext->edev);
....@@ -338,8 +388,19 @@
338388 goto disable_sw_control;
339389 }
340390
341
- /* Route D+ and D- to PMIC for initial charger detection */
342
- cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
391
+ ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
392
+ if (ret) {
393
+ dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
394
+ goto disable_sw_control;
395
+ }
396
+
397
+ /*
398
+ * If no USB host or device connected, route D+ and D- to PMIC for
399
+ * initial charger detection
400
+ */
401
+ id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
402
+ if (id != INTEL_USB_ID_GND)
403
+ cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
343404
344405 /* Get initial state */
345406 cht_wc_extcon_pwrsrc_event(ext);
....@@ -352,9 +413,7 @@
352413 }
353414
354415 /* Unmask irqs */
355
- ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
356
- (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
357
- CHT_WC_PWRSRC_ID_FLOAT));
416
+ ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, mask);
358417 if (ret) {
359418 dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);
360419 goto disable_sw_control;