2 * Copyright (C) 2013 Freescale Semiconductor, Inc. All Rights Reserved.
4 * The code contained herein is licensed under the GNU General Public
5 * License. You may obtain a copy of the GNU General Public License
6 * Version 2 or later at the following locations:
8 * http://www.opensource.org/licenses/gpl-license.html
9 * http://www.gnu.org/copyleft/gpl.html
12 #include <linux/delay.h>
13 #include <linux/device.h>
14 #include <linux/power/imx6_usb_charger.h>
15 #include <linux/regmap.h>
17 #define HW_ANADIG_REG_3P0_SET (0x00000124)
18 #define HW_ANADIG_REG_3P0_CLR (0x00000128)
19 #define BM_ANADIG_REG_3P0_ENABLE_ILIMIT 0x00000004
20 #define BM_ANADIG_REG_3P0_ENABLE_LINREG 0x00000001
22 #define HW_ANADIG_USB1_CHRG_DETECT_SET (0x000001b4)
23 #define HW_ANADIG_USB1_CHRG_DETECT_CLR (0x000001b8)
25 #define BM_ANADIG_USB1_CHRG_DETECT_EN_B 0x00100000
26 #define BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B 0x00080000
27 #define BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT 0x00040000
29 #define HW_ANADIG_USB1_VBUS_DET_STAT (0x000001c0)
31 #define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID 0x00000008
33 #define HW_ANADIG_USB1_CHRG_DET_STAT (0x000001d0)
35 #define BM_ANADIG_USB1_CHRG_DET_STAT_DM_STATE 0x00000004
36 #define BM_ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED 0x00000002
37 #define BM_ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT 0x00000001
39 static char *imx6_usb_charger_supplied_to[] = {
43 static enum power_supply_property imx6_usb_charger_power_props[] = {
44 POWER_SUPPLY_PROP_PRESENT, /* Charger detected */
45 POWER_SUPPLY_PROP_ONLINE, /* VBUS online */
46 POWER_SUPPLY_PROP_CURRENT_MAX, /* Maximum current in mA */
49 static int imx6_usb_charger_get_property(struct power_supply *psy,
50 enum power_supply_property psp,
51 union power_supply_propval *val)
53 struct usb_charger *charger =
54 container_of(psy, struct usb_charger, psy);
57 case POWER_SUPPLY_PROP_PRESENT:
58 val->intval = charger->present;
60 case POWER_SUPPLY_PROP_ONLINE:
61 val->intval = charger->online;
63 case POWER_SUPPLY_PROP_CURRENT_MAX:
64 val->intval = charger->max_current;
72 static void disable_charger_detector(struct regmap *regmap)
74 regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_SET,
75 BM_ANADIG_USB1_CHRG_DETECT_EN_B |
76 BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
79 static void disable_current_limiter(struct regmap *regmap)
81 /* Disable the vdd3p0 current limiter */
82 regmap_write(regmap, HW_ANADIG_REG_3P0_CLR,
83 BM_ANADIG_REG_3P0_ENABLE_ILIMIT);
86 /* Return value if the charger is present */
87 static int imx6_usb_charger_detect(struct usb_charger *charger)
89 struct regmap *regmap = charger->anatop;
91 int i, data_pin_contact_count = 0;
93 /* Enable the vdd3p0 curret limiter */
94 regmap_write(regmap, HW_ANADIG_REG_3P0_SET,
95 BM_ANADIG_REG_3P0_ENABLE_LINREG |
96 BM_ANADIG_REG_3P0_ENABLE_ILIMIT);
98 /* check if vbus is valid */
99 regmap_read(regmap, HW_ANADIG_USB1_VBUS_DET_STAT, &val);
100 if (!(val & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)) {
101 dev_err(charger->dev, "vbus is error\n");
102 disable_current_limiter(regmap);
106 /* Enable charger detector */
107 regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_CLR,
108 BM_ANADIG_USB1_CHRG_DETECT_EN_B);
110 * - Do not check whether a charger is connected to the USB port
111 * - Check whether the USB plug has been in contact with each other
113 regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_SET,
114 BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
115 BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
117 /* Check if plug is connected */
118 for (i = 0; i < 100; i = i + 1) {
119 regmap_read(regmap, HW_ANADIG_USB1_CHRG_DET_STAT, &val);
120 if (val & BM_ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT) {
121 if (data_pin_contact_count++ > 5)
122 /* Data pin makes contact */
130 dev_err(charger->dev,
131 "VBUS is coming from a dedicated power supply.\n");
132 disable_current_limiter(regmap);
133 disable_charger_detector(regmap);
138 * - Do check whether a charger is connected to the USB port
139 * - Do not Check whether the USB plug has been in contact with
142 regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_CLR,
143 BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
144 BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
147 /* Check if it is a charger */
148 regmap_read(regmap, HW_ANADIG_USB1_CHRG_DET_STAT, &val);
149 if (!(val & BM_ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
150 dev_dbg(charger->dev, "It is a stardard downstream port\n");
151 charger->psy.type = POWER_SUPPLY_TYPE_USB;
152 charger->max_current = 500;
153 disable_charger_detector(regmap);
155 /* It is a charger */
156 disable_charger_detector(regmap);
160 disable_current_limiter(regmap);
166 * imx6_usb_vbus_connect - inform about VBUS connection
167 * @charger: the usb charger
169 * Inform the charger VBUS is connected, vbus detect supplier should call it.
170 * Besides, the USB device controller is expected to keep the dataline
173 int imx6_usb_vbus_connect(struct usb_charger *charger)
179 mutex_lock(&charger->lock);
181 /* Start the 1st period charger detection. */
182 ret = imx6_usb_charger_detect(charger);
184 dev_err(charger->dev,
185 "Error occurs during detection: %d\n",
188 charger->present = 1;
190 mutex_unlock(&charger->lock);
194 EXPORT_SYMBOL(imx6_usb_vbus_connect);
197 * It must be called after dp is pulled up (from USB controller driver),
198 * That is used to differentiate DCP and CDP
200 int imx6_usb_charger_detect_post(struct usb_charger *charger)
202 struct regmap *regmap = charger->anatop;
205 mutex_lock(&charger->lock);
209 regmap_read(regmap, HW_ANADIG_USB1_CHRG_DET_STAT, &val);
210 if (val & BM_ANADIG_USB1_CHRG_DET_STAT_DM_STATE) {
211 dev_dbg(charger->dev, "It is a dedicate charging port\n");
212 charger->psy.type = POWER_SUPPLY_TYPE_USB_DCP;
213 charger->max_current = 1500;
215 dev_dbg(charger->dev, "It is a charging downstream port\n");
216 charger->psy.type = POWER_SUPPLY_TYPE_USB_CDP;
217 charger->max_current = 900;
220 power_supply_changed(&charger->psy);
222 mutex_unlock(&charger->lock);
226 EXPORT_SYMBOL(imx6_usb_charger_detect_post);
229 * imx6_usb_vbus_disconnect - inform about VBUS disconnection
230 * @charger: the usb charger
232 * Inform the charger that VBUS is disconnected. The charging will be
233 * stopped and the charger properties cleared.
235 int imx6_usb_vbus_disconnect(struct usb_charger *charger)
238 charger->present = 0;
239 charger->max_current = 0;
240 charger->psy.type = POWER_SUPPLY_TYPE_MAINS;
242 power_supply_changed(&charger->psy);
246 EXPORT_SYMBOL(imx6_usb_vbus_disconnect);
249 * imx6_usb_create_charger - create a USB charger
250 * @charger: the charger to be initialized
251 * @name: name for the power supply
253 * Registers a power supply for the charger. The USB Controller
254 * driver will call this after filling struct usb_charger.
256 int imx6_usb_create_charger(struct usb_charger *charger,
259 struct power_supply *psy = &charger->psy;
267 psy->name = "imx6_usb_charger";
269 charger->bc = BATTERY_CHARGING_SPEC_1_2;
270 mutex_init(&charger->lock);
272 psy->type = POWER_SUPPLY_TYPE_MAINS;
273 psy->properties = imx6_usb_charger_power_props;
274 psy->num_properties = ARRAY_SIZE(imx6_usb_charger_power_props);
275 psy->get_property = imx6_usb_charger_get_property;
276 psy->supplied_to = imx6_usb_charger_supplied_to;
277 psy->num_supplicants = sizeof(imx6_usb_charger_supplied_to)
280 return power_supply_register(charger->dev, psy);
282 EXPORT_SYMBOL(imx6_usb_create_charger);
285 * imx6_usb_remove_charger - remove a USB charger
286 * @charger: the charger to be removed
288 * Unregister the chargers power supply.
290 void imx6_usb_remove_charger(struct usb_charger *charger)
292 power_supply_unregister(&charger->psy);
294 EXPORT_SYMBOL(imx6_usb_remove_charger);