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 struct mutex bc_mutex;
33 static enum bc_port_type usb_charger_status = USB_BC_TYPE_DISCNT;
35 /****** GET REGISTER FIELD INFO FROM Device Tree ******/
37 static inline void *get_grf_base(struct device_node *np)
39 void *grf_base = of_iomap(of_get_parent(np), 0);
41 if (of_machine_is_compatible("rockchip,rk3188"))
43 else if (of_machine_is_compatible("rockchip,rk3288"))
49 void grf_uoc_set_field(uoc_field_t *field, u32 value)
51 if (!uoc_field_valid(field))
53 grf_uoc_set(pGRF_BASE, field->b.offset, field->b.bitmap, field->b.mask,
57 u32 grf_uoc_get_field(uoc_field_t *field)
59 return grf_uoc_get(pGRF_BASE, field->b.offset, field->b.bitmap,
63 static inline int uoc_init_field(struct device_node *np, const char *name,
66 of_property_read_u32_array(np, name, f->array, 3);
67 /* printk("usb battery charger detect: uoc_init_field: 0x%08x %d %d \n",
68 * f->b.offset,f->b.bitmap,f->b.mask);*/
72 static inline void uoc_init_synop(struct device_node *np)
75 (uoc_field_t *) kzalloc(SYNOP_BC_MAX * sizeof(uoc_field_t),
78 uoc_init_field(np, "rk_usb,bvalid", &pBC_UOC_FIELDS[SYNOP_BC_BVALID]);
79 uoc_init_field(np, "rk_usb,iddig", &pBC_UOC_FIELDS[SYNOP_BC_IDDIG]);
80 uoc_init_field(np, "rk_usb,dcdenb", &pBC_UOC_FIELDS[SYNOP_BC_DCDENB]);
81 uoc_init_field(np, "rk_usb,vdatsrcenb",
82 &pBC_UOC_FIELDS[SYNOP_BC_VDATSRCENB]);
83 uoc_init_field(np, "rk_usb,vdatdetenb",
84 &pBC_UOC_FIELDS[SYNOP_BC_VDATDETENB]);
85 uoc_init_field(np, "rk_usb,chrgsel", &pBC_UOC_FIELDS[SYNOP_BC_CHRGSEL]);
86 uoc_init_field(np, "rk_usb,chgdet", &pBC_UOC_FIELDS[SYNOP_BC_CHGDET]);
87 uoc_init_field(np, "rk_usb,fsvplus", &pBC_UOC_FIELDS[SYNOP_BC_FSVPLUS]);
88 uoc_init_field(np, "rk_usb,fsvminus",
89 &pBC_UOC_FIELDS[SYNOP_BC_FSVMINUS]);
92 static inline void uoc_init_rk(struct device_node *np)
95 (uoc_field_t *) kzalloc(RK_BC_MAX * sizeof(uoc_field_t),
98 uoc_init_field(np, "rk_usb,bvalid", &pBC_UOC_FIELDS[RK_BC_BVALID]);
99 uoc_init_field(np, "rk_usb,iddig", &pBC_UOC_FIELDS[RK_BC_IDDIG]);
100 uoc_init_field(np, "rk_usb,line", &pBC_UOC_FIELDS[RK_BC_LINESTATE]);
101 uoc_init_field(np, "rk_usb,softctrl", &pBC_UOC_FIELDS[RK_BC_SOFTCTRL]);
102 uoc_init_field(np, "rk_usb,opmode", &pBC_UOC_FIELDS[RK_BC_OPMODE]);
103 uoc_init_field(np, "rk_usb,xcvrsel", &pBC_UOC_FIELDS[RK_BC_XCVRSELECT]);
104 uoc_init_field(np, "rk_usb,termsel", &pBC_UOC_FIELDS[RK_BC_TERMSELECT]);
107 static inline void uoc_init_inno(struct device_node *np)
109 pBC_UOC_FIELDS = (uoc_field_t *)
110 kzalloc(INNO_BC_MAX * sizeof(uoc_field_t), GFP_ATOMIC);
112 uoc_init_field(np, "rk_usb,bvalid",
113 &pBC_UOC_FIELDS[INNO_BC_BVALID]);
114 uoc_init_field(np, "rk_usb,iddig",
115 &pBC_UOC_FIELDS[INNO_BC_IDDIG]);
116 uoc_init_field(np, "rk_usb,vdmsrcen",
117 &pBC_UOC_FIELDS[INNO_BC_VDMSRCEN]);
118 uoc_init_field(np, "rk_usb,vdpsrcen",
119 &pBC_UOC_FIELDS[INNO_BC_VDPSRCEN]);
120 uoc_init_field(np, "rk_usb,rdmpden",
121 &pBC_UOC_FIELDS[INNO_BC_RDMPDEN]);
122 uoc_init_field(np, "rk_usb,idpsrcen",
123 &pBC_UOC_FIELDS[INNO_BC_IDPSRCEN]);
124 uoc_init_field(np, "rk_usb,idmsinken",
125 &pBC_UOC_FIELDS[INNO_BC_IDMSINKEN]);
126 uoc_init_field(np, "rk_usb,idpsinken",
127 &pBC_UOC_FIELDS[INNO_BC_IDPSINKEN]);
128 uoc_init_field(np, "rk_usb,dpattach",
129 &pBC_UOC_FIELDS[INNO_BC_DPATTACH]);
130 uoc_init_field(np, "rk_usb,cpdet",
131 &pBC_UOC_FIELDS[INNO_BC_CPDET]);
132 uoc_init_field(np, "rk_usb,dcpattach",
133 &pBC_UOC_FIELDS[INNO_BC_DCPATTACH]);
136 /****** BATTERY CHARGER DETECT FUNCTIONS ******/
137 bool is_connected(void)
141 if (BC_GET(BC_BVALID) && BC_GET(BC_IDDIG))
146 enum bc_port_type usb_battery_charger_detect_rk(bool wait)
149 enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
151 if (BC_GET(RK_BC_BVALID) &&
152 BC_GET(RK_BC_IDDIG)) {
154 BC_SET(RK_BC_SOFTCTRL, 1);
155 BC_SET(RK_BC_OPMODE, 0);
156 BC_SET(RK_BC_XCVRSELECT, 1);
157 BC_SET(RK_BC_TERMSELECT, 1);
160 switch (BC_GET(RK_BC_LINESTATE)) {
162 port_type = USB_BC_TYPE_SDP;
166 port_type = USB_BC_TYPE_DCP;
170 port_type = USB_BC_TYPE_SDP;
171 /* printk("%s linestate = %d bad status\n",
172 * __func__, BC_GET(RK_BC_LINESTATE)); */
176 BC_SET(RK_BC_SOFTCTRL, 0);
178 /* printk("%s , battery_charger_detect %d\n",
179 * __func__, port_type); */
183 enum bc_port_type usb_battery_charger_detect_inno(bool wait)
185 enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
186 int dcd_state = DCD_POSITIVE;
187 int timeout = 0, i = 0;
189 /* VBUS Valid detect */
190 if (BC_GET(INNO_BC_BVALID) &&
191 BC_GET(INNO_BC_IDDIG)) {
194 dcd_state = DCD_TIMEOUT;
195 BC_SET(INNO_BC_RDMPDEN, 1);
196 BC_SET(INNO_BC_IDPSRCEN, 1);
197 timeout = T_DCD_TIMEOUT;
199 if (BC_GET(INNO_BC_DPATTACH))
202 /* It is a filter here to assure data
203 * lines contacted for at least 3ms */
204 dcd_state = DCD_POSITIVE;
209 BC_SET(INNO_BC_RDMPDEN, 0);
210 BC_SET(INNO_BC_IDPSRCEN, 0);
212 dcd_state = DCD_PASSED;
214 if (dcd_state == DCD_TIMEOUT) {
215 port_type = USB_BC_TYPE_UNKNOW;
220 /* Primary Detection */
221 BC_SET(INNO_BC_VDPSRCEN, 1);
222 BC_SET(INNO_BC_IDMSINKEN, 1);
223 udelay(T_BC_CHGDET_VALID);
225 /* SDP and CDP/DCP distinguish */
226 if (BC_GET(INNO_BC_CPDET)) {
227 /* Turn off VDPSRC */
228 BC_SET(INNO_BC_VDPSRCEN, 0);
229 BC_SET(INNO_BC_IDMSINKEN, 0);
231 udelay(T_BC_CHGDET_VALID);
234 BC_SET(INNO_BC_VDMSRCEN, 1);
235 BC_SET(INNO_BC_IDPSINKEN, 1);
236 udelay(T_BC_CHGDET_VALID);
237 if (BC_GET(INNO_BC_DCPATTACH))
238 port_type = USB_BC_TYPE_DCP;
240 port_type = USB_BC_TYPE_CDP;
242 port_type = USB_BC_TYPE_SDP;
245 BC_SET(INNO_BC_VDPSRCEN, 0);
246 BC_SET(INNO_BC_IDMSINKEN, 0);
247 BC_SET(INNO_BC_VDMSRCEN, 0);
248 BC_SET(INNO_BC_IDPSINKEN, 0);
253 printk("%s, Charger type %s, %s DCD, dcd_state = %d\n", __func__,
254 bc_string[port_type], wait ? "wait" : "pass", dcd_state);
260 /* When do BC detect PCD pull-up register should be disabled */
261 /* wait wait for dcd timeout 900ms */
262 enum bc_port_type usb_battery_charger_detect_synop(bool wait)
264 enum bc_port_type port_type = USB_BC_TYPE_DISCNT;
265 int dcd_state = DCD_POSITIVE;
266 int timeout = 0, i = 0;
268 /* VBUS Valid detect */
269 if (BC_GET(SYNOP_BC_BVALID) &&
270 BC_GET(SYNOP_BC_IDDIG)) {
273 dcd_state = DCD_TIMEOUT;
274 BC_SET(SYNOP_BC_DCDENB, 1);
275 timeout = T_DCD_TIMEOUT;
277 if (!BC_GET(SYNOP_BC_FSVPLUS))
280 /* It is a filter here to assure data
281 * lines contacted for at least 3ms */
282 dcd_state = DCD_POSITIVE;
288 BC_SET(SYNOP_BC_DCDENB, 0);
290 dcd_state = DCD_PASSED;
292 if (dcd_state == DCD_TIMEOUT) {
293 port_type = USB_BC_TYPE_UNKNOW;
298 /* Primary Detection */
299 BC_SET(SYNOP_BC_VDATSRCENB, 1);
300 BC_SET(SYNOP_BC_VDATDETENB, 1);
301 BC_SET(SYNOP_BC_CHRGSEL, 0);
303 udelay(T_BC_CHGDET_VALID);
305 /* SDP and CDP/DCP distinguish */
306 if (BC_GET(SYNOP_BC_CHGDET)) {
307 /* Turn off VDPSRC */
308 BC_SET(SYNOP_BC_VDATSRCENB, 0);
309 BC_SET(SYNOP_BC_VDATDETENB, 0);
311 udelay(T_BC_CHGDET_VALID);
314 BC_SET(SYNOP_BC_VDATSRCENB, 1);
315 BC_SET(SYNOP_BC_VDATDETENB, 1);
316 BC_SET(SYNOP_BC_CHRGSEL, 1);
317 udelay(T_BC_CHGDET_VALID);
318 if (BC_GET(SYNOP_BC_CHGDET))
319 port_type = USB_BC_TYPE_DCP;
321 port_type = USB_BC_TYPE_CDP;
323 port_type = USB_BC_TYPE_SDP;
325 BC_SET(SYNOP_BC_VDATSRCENB, 0);
326 BC_SET(SYNOP_BC_VDATDETENB, 0);
327 BC_SET(SYNOP_BC_CHRGSEL, 0);
332 printk("%s, Charger type %s, %s DCD, dcd_state = %d\n", __func__,
333 bc_string[port_type], wait ? "wait" : "pass", dcd_state);
338 enum bc_port_type usb_battery_charger_detect(bool wait)
340 static struct device_node *np;
341 enum bc_port_type ret = USB_BC_TYPE_DISCNT;
346 np = of_find_node_by_name(NULL, "usb_bc");
350 pGRF_BASE = get_grf_base(np);
351 mutex_init(&bc_mutex);
354 mutex_lock(&bc_mutex);
355 if (of_device_is_compatible(np, "rockchip,ctrl")) {
358 ret = usb_battery_charger_detect_rk(wait);
361 else if (of_device_is_compatible(np, "synopsys,phy")) {
364 ret = usb_battery_charger_detect_synop(wait);
367 else if (of_device_is_compatible(np, "inno,phy")) {
370 ret = usb_battery_charger_detect_inno(wait);
372 if (ret == USB_BC_TYPE_UNKNOW)
373 ret = USB_BC_TYPE_DCP;
374 mutex_unlock(&bc_mutex);
375 rk_battery_charger_detect_cb(ret);
379 int dwc_otg_check_dpdm(bool wait)
381 return (is_connected() ? usb_charger_status : USB_BC_TYPE_DISCNT);
383 EXPORT_SYMBOL(dwc_otg_check_dpdm);
385 /* Call back function for USB charger type changed */
386 static ATOMIC_NOTIFIER_HEAD(rk_bc_notifier);
388 int rk_bc_detect_notifier_register(struct notifier_block *nb,
391 *type = (int)usb_battery_charger_detect(0);
392 return atomic_notifier_chain_register(&rk_bc_notifier, nb);
394 EXPORT_SYMBOL(rk_bc_detect_notifier_register);
396 int rk_bc_detect_notifier_unregister(struct notifier_block *nb)
398 return atomic_notifier_chain_unregister(&rk_bc_notifier, nb);
400 EXPORT_SYMBOL(rk_bc_detect_notifier_unregister);
402 void rk_bc_detect_notifier_callback(int bc_mode)
404 atomic_notifier_call_chain(&rk_bc_notifier,bc_mode, NULL);
407 void rk_battery_charger_detect_cb(int new_type)
411 if (usb_charger_status != new_type) {
412 printk("%s , battery_charger_detect %d\n", __func__, new_type);
413 atomic_notifier_call_chain(&rk_bc_notifier, new_type, NULL);
415 mutex_lock(&bc_mutex);
416 usb_charger_status = new_type;
417 mutex_unlock(&bc_mutex);