2 * Copyright (C) 2013-2014 ROCKCHIP, Inc.
3 * Author: LIYUNZHI <lyz@rock-chips.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include "usbdev_rk.h"
19 char *bc_string[USB_BC_TYPE_MAX] = {"DISCONNECT",
20 "Stander Downstream Port",
21 "Dedicated Charging Port",
22 "Charging Downstream Port",
25 /****** GET and SET REGISTER FIELDS IN GRF UOC ******/
26 #define BC_GET(x) grf_uoc_get_field(&pBC_UOC_FIELDS[x])
27 #define BC_SET(x, v) grf_uoc_set_field(&pBC_UOC_FIELDS[x], v)
29 uoc_field_t *pBC_UOC_FIELDS;
30 static void *pGRF_BASE;
31 static void *pGRF_REGMAP;
32 static struct mutex bc_mutex;
34 static enum bc_port_type usb_charger_status = USB_BC_TYPE_DISCNT;
36 /****** GET REGISTER FIELD INFO FROM Device Tree ******/
38 static inline void *get_grf_base(struct device_node *np)
40 void *grf_base = of_iomap(of_get_parent(np), 0);
42 if (of_machine_is_compatible("rockchip,rk3188"))
44 else if (of_machine_is_compatible("rockchip,rk3288"))
50 static inline struct regmap *get_grf_regmap(struct device_node *np)
54 grf = syscon_regmap_lookup_by_phandle(of_get_parent(np),
61 void grf_uoc_set_field(uoc_field_t *field, u32 value)
63 if (!uoc_field_valid(field))
67 grf_uoc_set(pGRF_BASE, field->b.offset, field->b.bitmap,
68 field->b.mask, value);
69 } else if (pGRF_REGMAP) {
70 regmap_grf_uoc_set(pGRF_REGMAP, field->b.offset,
72 field->b.mask, value);
76 u32 grf_uoc_get_field(uoc_field_t *field)
79 return grf_uoc_get(pGRF_BASE, field->b.offset, field->b.bitmap,
81 } else if (pGRF_REGMAP) {
82 return regmap_grf_uoc_get(pGRF_REGMAP, field->b.offset,
83 field->b.bitmap, field->b.mask);
89 static inline int uoc_init_field(struct device_node *np, const char *name,
92 of_property_read_u32_array(np, name, f->array, 3);
93 /* printk("usb battery charger detect: uoc_init_field: 0x%08x %d %d \n",
94 * f->b.offset,f->b.bitmap,f->b.mask);*/
98 static inline void uoc_init_synop(struct device_node *np)
101 (uoc_field_t *) kzalloc(SYNOP_BC_MAX * sizeof(uoc_field_t),
104 uoc_init_field(np, "rk_usb,bvalid", &pBC_UOC_FIELDS[SYNOP_BC_BVALID]);
105 uoc_init_field(np, "rk_usb,iddig", &pBC_UOC_FIELDS[SYNOP_BC_IDDIG]);
106 uoc_init_field(np, "rk_usb,dcdenb", &pBC_UOC_FIELDS[SYNOP_BC_DCDENB]);
107 uoc_init_field(np, "rk_usb,vdatsrcenb",
108 &pBC_UOC_FIELDS[SYNOP_BC_VDATSRCENB]);
109 uoc_init_field(np, "rk_usb,vdatdetenb",
110 &pBC_UOC_FIELDS[SYNOP_BC_VDATDETENB]);
111 uoc_init_field(np, "rk_usb,chrgsel", &pBC_UOC_FIELDS[SYNOP_BC_CHRGSEL]);
112 uoc_init_field(np, "rk_usb,chgdet", &pBC_UOC_FIELDS[SYNOP_BC_CHGDET]);
113 uoc_init_field(np, "rk_usb,fsvplus", &pBC_UOC_FIELDS[SYNOP_BC_FSVPLUS]);
114 uoc_init_field(np, "rk_usb,fsvminus",
115 &pBC_UOC_FIELDS[SYNOP_BC_FSVMINUS]);
118 static inline void uoc_init_rk(struct device_node *np)
121 (uoc_field_t *) kzalloc(RK_BC_MAX * sizeof(uoc_field_t),
124 uoc_init_field(np, "rk_usb,bvalid", &pBC_UOC_FIELDS[RK_BC_BVALID]);
125 uoc_init_field(np, "rk_usb,iddig", &pBC_UOC_FIELDS[RK_BC_IDDIG]);
126 uoc_init_field(np, "rk_usb,line", &pBC_UOC_FIELDS[RK_BC_LINESTATE]);
127 uoc_init_field(np, "rk_usb,softctrl", &pBC_UOC_FIELDS[RK_BC_SOFTCTRL]);
128 uoc_init_field(np, "rk_usb,opmode", &pBC_UOC_FIELDS[RK_BC_OPMODE]);
129 uoc_init_field(np, "rk_usb,xcvrsel", &pBC_UOC_FIELDS[RK_BC_XCVRSELECT]);
130 uoc_init_field(np, "rk_usb,termsel", &pBC_UOC_FIELDS[RK_BC_TERMSELECT]);
133 static inline void uoc_init_inno(struct device_node *np)
135 pBC_UOC_FIELDS = (uoc_field_t *)
136 kzalloc(INNO_BC_MAX * sizeof(uoc_field_t), GFP_ATOMIC);
138 uoc_init_field(np, "rk_usb,bvalid",
139 &pBC_UOC_FIELDS[INNO_BC_BVALID]);
140 uoc_init_field(np, "rk_usb,iddig",
141 &pBC_UOC_FIELDS[INNO_BC_IDDIG]);
142 uoc_init_field(np, "rk_usb,vdmsrcen",
143 &pBC_UOC_FIELDS[INNO_BC_VDMSRCEN]);
144 uoc_init_field(np, "rk_usb,vdpsrcen",
145 &pBC_UOC_FIELDS[INNO_BC_VDPSRCEN]);
146 uoc_init_field(np, "rk_usb,rdmpden",
147 &pBC_UOC_FIELDS[INNO_BC_RDMPDEN]);
148 uoc_init_field(np, "rk_usb,idpsrcen",
149 &pBC_UOC_FIELDS[INNO_BC_IDPSRCEN]);
150 uoc_init_field(np, "rk_usb,idmsinken",
151 &pBC_UOC_FIELDS[INNO_BC_IDMSINKEN]);
152 uoc_init_field(np, "rk_usb,idpsinken",
153 &pBC_UOC_FIELDS[INNO_BC_IDPSINKEN]);
154 uoc_init_field(np, "rk_usb,dpattach",
155 &pBC_UOC_FIELDS[INNO_BC_DPATTACH]);
156 uoc_init_field(np, "rk_usb,cpdet",
157 &pBC_UOC_FIELDS[INNO_BC_CPDET]);
158 uoc_init_field(np, "rk_usb,dcpattach",
159 &pBC_UOC_FIELDS[INNO_BC_DCPATTACH]);
162 /****** BATTERY CHARGER DETECT FUNCTIONS ******/
163 bool is_connected(void)
165 if (!pGRF_BASE && !pGRF_REGMAP)
167 if (BC_GET(BC_BVALID) && BC_GET(BC_IDDIG))
172 enum bc_port_type usb_battery_charger_detect_rk(bool wait)
175 enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
177 if (BC_GET(RK_BC_BVALID) &&
178 BC_GET(RK_BC_IDDIG)) {
180 BC_SET(RK_BC_SOFTCTRL, 1);
181 BC_SET(RK_BC_OPMODE, 0);
182 BC_SET(RK_BC_XCVRSELECT, 1);
183 BC_SET(RK_BC_TERMSELECT, 1);
186 switch (BC_GET(RK_BC_LINESTATE)) {
188 port_type = USB_BC_TYPE_SDP;
192 port_type = USB_BC_TYPE_DCP;
196 port_type = USB_BC_TYPE_SDP;
197 /* printk("%s linestate = %d bad status\n",
198 * __func__, BC_GET(RK_BC_LINESTATE)); */
202 BC_SET(RK_BC_SOFTCTRL, 0);
204 /* printk("%s , battery_charger_detect %d\n",
205 * __func__, port_type); */
209 enum bc_port_type usb_battery_charger_detect_inno(bool wait)
211 enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
212 int dcd_state = DCD_POSITIVE;
213 int timeout = 0, i = 0, filted_cpdet = 0;
215 /* VBUS Valid detect */
216 if (BC_GET(INNO_BC_BVALID) &&
217 BC_GET(INNO_BC_IDDIG)) {
220 dcd_state = DCD_TIMEOUT;
221 BC_SET(INNO_BC_RDMPDEN, 1);
222 BC_SET(INNO_BC_IDPSRCEN, 1);
223 timeout = T_DCD_TIMEOUT;
225 if (BC_GET(INNO_BC_DPATTACH))
228 /* It is a filter here to assure data
229 * lines contacted for at least 3ms */
230 dcd_state = DCD_POSITIVE;
235 BC_SET(INNO_BC_RDMPDEN, 0);
236 BC_SET(INNO_BC_IDPSRCEN, 0);
238 dcd_state = DCD_PASSED;
240 if (dcd_state == DCD_TIMEOUT) {
241 port_type = USB_BC_TYPE_UNKNOW;
246 /* Primary Detection */
247 BC_SET(INNO_BC_VDPSRCEN, 1);
248 BC_SET(INNO_BC_IDMSINKEN, 1);
249 udelay(T_BC_CHGDET_VALID);
252 * Filter for Primary Detection,
253 * double check CPDET field
255 timeout = T_BC_CHGDET_VALID;
258 * In rapidly hotplug case, it's more likely to
259 * distinguish SDP as DCP/CDP because of line
262 filted_cpdet += (BC_GET(INNO_BC_CPDET) ? 1 : -2);
265 /* SDP and CDP/DCP distinguish */
266 if (filted_cpdet > 0) {
267 /* Turn off VDPSRC */
268 BC_SET(INNO_BC_VDPSRCEN, 0);
269 BC_SET(INNO_BC_IDMSINKEN, 0);
271 udelay(T_BC_CHGDET_VALID);
274 BC_SET(INNO_BC_VDMSRCEN, 1);
275 BC_SET(INNO_BC_IDPSINKEN, 1);
276 udelay(T_BC_CHGDET_VALID);
277 if (BC_GET(INNO_BC_DCPATTACH))
278 port_type = USB_BC_TYPE_DCP;
280 port_type = USB_BC_TYPE_CDP;
282 port_type = USB_BC_TYPE_SDP;
285 BC_SET(INNO_BC_VDPSRCEN, 0);
286 BC_SET(INNO_BC_IDMSINKEN, 0);
287 BC_SET(INNO_BC_VDMSRCEN, 0);
288 BC_SET(INNO_BC_IDPSINKEN, 0);
293 printk("%s, Charger type %s, %s DCD, dcd_state = %d\n", __func__,
294 bc_string[port_type], wait ? "wait" : "pass", dcd_state);
300 /* When do BC detect PCD pull-up register should be disabled */
301 /* wait wait for dcd timeout 900ms */
302 enum bc_port_type usb_battery_charger_detect_synop(bool wait)
304 enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
305 int dcd_state = DCD_POSITIVE;
306 int timeout = 0, i = 0;
308 /* VBUS Valid detect */
309 if (BC_GET(SYNOP_BC_BVALID) &&
310 BC_GET(SYNOP_BC_IDDIG)) {
313 dcd_state = DCD_TIMEOUT;
314 BC_SET(SYNOP_BC_DCDENB, 1);
315 timeout = T_DCD_TIMEOUT;
317 if (!BC_GET(SYNOP_BC_FSVPLUS))
320 /* It is a filter here to assure data
321 * lines contacted for at least 3ms */
322 dcd_state = DCD_POSITIVE;
328 BC_SET(SYNOP_BC_DCDENB, 0);
330 dcd_state = DCD_PASSED;
332 if (dcd_state == DCD_TIMEOUT) {
333 port_type = USB_BC_TYPE_UNKNOW;
338 /* Primary Detection */
339 BC_SET(SYNOP_BC_VDATSRCENB, 1);
340 BC_SET(SYNOP_BC_VDATDETENB, 1);
341 BC_SET(SYNOP_BC_CHRGSEL, 0);
343 udelay(T_BC_CHGDET_VALID);
345 /* SDP and CDP/DCP distinguish */
346 if (BC_GET(SYNOP_BC_CHGDET)) {
347 /* Turn off VDPSRC */
348 BC_SET(SYNOP_BC_VDATSRCENB, 0);
349 BC_SET(SYNOP_BC_VDATDETENB, 0);
351 udelay(T_BC_CHGDET_VALID);
354 BC_SET(SYNOP_BC_VDATSRCENB, 1);
355 BC_SET(SYNOP_BC_VDATDETENB, 1);
356 BC_SET(SYNOP_BC_CHRGSEL, 1);
357 udelay(T_BC_CHGDET_VALID);
358 if (BC_GET(SYNOP_BC_CHGDET))
359 port_type = USB_BC_TYPE_DCP;
361 port_type = USB_BC_TYPE_CDP;
363 port_type = USB_BC_TYPE_SDP;
365 BC_SET(SYNOP_BC_VDATSRCENB, 0);
366 BC_SET(SYNOP_BC_VDATDETENB, 0);
367 BC_SET(SYNOP_BC_CHRGSEL, 0);
372 printk("%s, Charger type %s, %s DCD, dcd_state = %d\n", __func__,
373 bc_string[port_type], wait ? "wait" : "pass", dcd_state);
378 enum bc_port_type usb_battery_charger_detect(bool wait)
380 static struct device_node *np;
381 enum bc_port_type ret = USB_BC_TYPE_DISCNT;
386 np = of_find_node_by_name(NULL, "usb_bc");
389 if (!pGRF_BASE && !pGRF_REGMAP) {
390 pGRF_BASE = get_grf_base(np);
391 pGRF_REGMAP = get_grf_regmap(np);
392 mutex_init(&bc_mutex);
395 mutex_lock(&bc_mutex);
396 if (of_device_is_compatible(np, "rockchip,ctrl")) {
399 ret = usb_battery_charger_detect_rk(wait);
402 else if (of_device_is_compatible(np, "synopsys,phy")) {
405 ret = usb_battery_charger_detect_synop(wait);
408 else if (of_device_is_compatible(np, "inno,phy")) {
411 ret = usb_battery_charger_detect_inno(wait);
413 if (ret == USB_BC_TYPE_UNKNOW)
414 ret = USB_BC_TYPE_DCP;
415 mutex_unlock(&bc_mutex);
416 rk_battery_charger_detect_cb(ret);
420 int dwc_otg_check_dpdm(bool wait)
422 return (is_connected() ? usb_charger_status : USB_BC_TYPE_DISCNT);
424 EXPORT_SYMBOL(dwc_otg_check_dpdm);
426 /* Call back function for USB charger type changed */
427 static ATOMIC_NOTIFIER_HEAD(rk_bc_notifier);
429 int rk_bc_detect_notifier_register(struct notifier_block *nb,
432 *type = (int)usb_battery_charger_detect(0);
433 return atomic_notifier_chain_register(&rk_bc_notifier, nb);
435 EXPORT_SYMBOL(rk_bc_detect_notifier_register);
437 int rk_bc_detect_notifier_unregister(struct notifier_block *nb)
439 return atomic_notifier_chain_unregister(&rk_bc_notifier, nb);
441 EXPORT_SYMBOL(rk_bc_detect_notifier_unregister);
443 void rk_bc_detect_notifier_callback(int bc_mode)
445 atomic_notifier_call_chain(&rk_bc_notifier,bc_mode, NULL);
448 void rk_battery_charger_detect_cb(int new_type)
452 if (usb_charger_status != new_type) {
453 printk("%s , battery_charger_detect %d\n", __func__, new_type);
454 atomic_notifier_call_chain(&rk_bc_notifier, new_type, NULL);
456 mutex_lock(&bc_mutex);
457 usb_charger_status = new_type;
458 mutex_unlock(&bc_mutex);