blob: f31481f5423262d1f1e24f647728f2a3bfa8cd17 [file] [log] [blame]
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/platform_device.h>
18#include <linux/dma-mapping.h>
Manu Gautamb5067272012-07-02 09:53:41 +053019#include <linux/pm_runtime.h>
Manu Gautam377821c2012-09-28 16:53:24 +053020#include <linux/ratelimit.h>
Manu Gautamb5067272012-07-02 09:53:41 +053021#include <linux/interrupt.h>
Ido Shayevitzef72ddd2012-03-28 18:55:55 +020022#include <linux/ioport.h>
Manu Gautam1742db22012-06-19 13:33:24 +053023#include <linux/clk.h>
Ido Shayevitzef72ddd2012-03-28 18:55:55 +020024#include <linux/io.h>
25#include <linux/module.h>
26#include <linux/types.h>
Ido Shayevitzef72ddd2012-03-28 18:55:55 +020027#include <linux/delay.h>
28#include <linux/of.h>
Vijayavardhan Vennapusa8eb68732013-03-26 13:05:38 +053029#include <linux/of_platform.h>
Ido Shayevitz9fb83452012-04-01 17:45:58 +030030#include <linux/list.h>
Manu Gautamb5067272012-07-02 09:53:41 +053031#include <linux/debugfs.h>
32#include <linux/uaccess.h>
Ido Shayevitz9fb83452012-04-01 17:45:58 +030033#include <linux/usb/ch9.h>
34#include <linux/usb/gadget.h>
David Keitelad4a0282013-03-19 18:04:27 -070035#include <linux/qpnp-misc.h>
Ido Shayevitz9fb83452012-04-01 17:45:58 +030036#include <linux/usb/msm_hsusb.h>
Manu Gautam60e01352012-05-29 09:00:34 +053037#include <linux/regulator/consumer.h>
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +053038#include <linux/power_supply.h>
Jack Pham0fc12332012-11-19 13:14:22 -080039#include <linux/qpnp/qpnp-adc.h>
Pavankumar Kondeti08693e72013-05-03 11:55:48 +053040#include <linux/cdev.h>
41#include <linux/completion.h>
Manu Gautam60e01352012-05-29 09:00:34 +053042
43#include <mach/rpm-regulator.h>
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +053044#include <mach/rpm-regulator-smd.h>
Manu Gautam2617deb2012-08-31 17:50:06 -070045#include <mach/msm_bus.h>
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +053046#include <mach/clk.h>
Ido Shayevitz9fb83452012-04-01 17:45:58 +030047
Manu Gautam8c642812012-06-07 10:35:10 +053048#include "dwc3_otg.h"
Ido Shayevitz9fb83452012-04-01 17:45:58 +030049#include "core.h"
50#include "gadget.h"
51
Jack Pham0fc12332012-11-19 13:14:22 -080052/* ADC threshold values */
53static int adc_low_threshold = 700;
54module_param(adc_low_threshold, int, S_IRUGO | S_IWUSR);
55MODULE_PARM_DESC(adc_low_threshold, "ADC ID Low voltage threshold");
56
57static int adc_high_threshold = 950;
58module_param(adc_high_threshold, int, S_IRUGO | S_IWUSR);
59MODULE_PARM_DESC(adc_high_threshold, "ADC ID High voltage threshold");
60
61static int adc_meas_interval = ADC_MEAS1_INTERVAL_1S;
62module_param(adc_meas_interval, int, S_IRUGO | S_IWUSR);
63MODULE_PARM_DESC(adc_meas_interval, "ADC ID polling period");
64
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +053065static int override_phy_init;
66module_param(override_phy_init, int, S_IRUGO|S_IWUSR);
67MODULE_PARM_DESC(override_phy_init, "Override HSPHY Init Seq");
68
Jack Pham9b4606b2013-04-02 17:32:25 -070069/* Enable Proprietary charger detection */
70static bool prop_chg_detect;
71module_param(prop_chg_detect, bool, S_IRUGO | S_IWUSR);
72MODULE_PARM_DESC(prop_chg_detect, "Enable Proprietary charger detection");
73
Ido Shayevitz9fb83452012-04-01 17:45:58 +030074/**
75 * USB DBM Hardware registers.
76 *
77 */
Shimrit Malichia00d7322012-08-05 13:56:28 +030078#define DBM_BASE 0x000F8000
79#define DBM_EP_CFG(n) (DBM_BASE + (0x00 + 4 * (n)))
80#define DBM_DATA_FIFO(n) (DBM_BASE + (0x10 + 4 * (n)))
81#define DBM_DATA_FIFO_SIZE(n) (DBM_BASE + (0x20 + 4 * (n)))
82#define DBM_DATA_FIFO_EN (DBM_BASE + (0x30))
83#define DBM_GEVNTADR (DBM_BASE + (0x34))
84#define DBM_GEVNTSIZ (DBM_BASE + (0x38))
85#define DBM_DBG_CNFG (DBM_BASE + (0x3C))
86#define DBM_HW_TRB0_EP(n) (DBM_BASE + (0x40 + 4 * (n)))
87#define DBM_HW_TRB1_EP(n) (DBM_BASE + (0x50 + 4 * (n)))
88#define DBM_HW_TRB2_EP(n) (DBM_BASE + (0x60 + 4 * (n)))
89#define DBM_HW_TRB3_EP(n) (DBM_BASE + (0x70 + 4 * (n)))
90#define DBM_PIPE_CFG (DBM_BASE + (0x80))
91#define DBM_SOFT_RESET (DBM_BASE + (0x84))
92#define DBM_GEN_CFG (DBM_BASE + (0x88))
Ido Shayevitz9fb83452012-04-01 17:45:58 +030093
94/**
95 * USB DBM Hardware registers bitmask.
96 *
97 */
98/* DBM_EP_CFG */
Shimrit Malichia00d7322012-08-05 13:56:28 +030099#define DBM_EN_EP 0x00000001
100#define USB3_EPNUM 0x0000003E
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300101#define DBM_BAM_PIPE_NUM 0x000000C0
102#define DBM_PRODUCER 0x00000100
103#define DBM_DISABLE_WB 0x00000200
104#define DBM_INT_RAM_ACC 0x00000400
105
106/* DBM_DATA_FIFO_SIZE */
107#define DBM_DATA_FIFO_SIZE_MASK 0x0000ffff
108
109/* DBM_GEVNTSIZ */
110#define DBM_GEVNTSIZ_MASK 0x0000ffff
111
112/* DBM_DBG_CNFG */
113#define DBM_ENABLE_IOC_MASK 0x0000000f
114
115/* DBM_SOFT_RESET */
116#define DBM_SFT_RST_EP0 0x00000001
117#define DBM_SFT_RST_EP1 0x00000002
118#define DBM_SFT_RST_EP2 0x00000004
119#define DBM_SFT_RST_EP3 0x00000008
Shimrit Malichia00d7322012-08-05 13:56:28 +0300120#define DBM_SFT_RST_EPS_MASK 0x0000000F
121#define DBM_SFT_RST_MASK 0x80000000
122#define DBM_EN_MASK 0x00000002
Ido Shayevitzef72ddd2012-03-28 18:55:55 +0200123
124#define DBM_MAX_EPS 4
125
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300126/* DBM TRB configurations */
127#define DBM_TRB_BIT 0x80000000
128#define DBM_TRB_DATA_SRC 0x40000000
129#define DBM_TRB_DMA 0x20000000
130#define DBM_TRB_EP_NUM(ep) (ep<<24)
Shimrit Malichia00d7322012-08-05 13:56:28 +0300131
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +0530132#define USB3_PORTSC (0x430)
133#define PORT_PE (0x1 << 1)
Manu Gautam8c642812012-06-07 10:35:10 +0530134/**
135 * USB QSCRATCH Hardware registers
136 *
137 */
138#define QSCRATCH_REG_OFFSET (0x000F8800)
Pavankumar Kondeti08693e72013-05-03 11:55:48 +0530139#define QSCRATCH_CTRL_REG (QSCRATCH_REG_OFFSET + 0x04)
Shimrit Malichia00d7322012-08-05 13:56:28 +0300140#define QSCRATCH_GENERAL_CFG (QSCRATCH_REG_OFFSET + 0x08)
Manu Gautambd0e5782012-08-30 10:39:01 -0700141#define HS_PHY_CTRL_REG (QSCRATCH_REG_OFFSET + 0x10)
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +0530142#define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
Manu Gautam8c642812012-06-07 10:35:10 +0530143#define CHARGING_DET_CTRL_REG (QSCRATCH_REG_OFFSET + 0x18)
144#define CHARGING_DET_OUTPUT_REG (QSCRATCH_REG_OFFSET + 0x1C)
145#define ALT_INTERRUPT_EN_REG (QSCRATCH_REG_OFFSET + 0x20)
146#define HS_PHY_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x24)
Manu Gautamd4108b72012-12-14 17:35:18 +0530147#define CGCTL_REG (QSCRATCH_REG_OFFSET + 0x28)
Manu Gautambd0e5782012-08-30 10:39:01 -0700148#define SS_PHY_CTRL_REG (QSCRATCH_REG_OFFSET + 0x30)
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +0530149#define SS_PHY_PARAM_CTRL_1 (QSCRATCH_REG_OFFSET + 0x34)
150#define SS_PHY_PARAM_CTRL_2 (QSCRATCH_REG_OFFSET + 0x38)
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530151#define SS_CR_PROTOCOL_DATA_IN_REG (QSCRATCH_REG_OFFSET + 0x3C)
152#define SS_CR_PROTOCOL_DATA_OUT_REG (QSCRATCH_REG_OFFSET + 0x40)
153#define SS_CR_PROTOCOL_CAP_ADDR_REG (QSCRATCH_REG_OFFSET + 0x44)
154#define SS_CR_PROTOCOL_CAP_DATA_REG (QSCRATCH_REG_OFFSET + 0x48)
155#define SS_CR_PROTOCOL_READ_REG (QSCRATCH_REG_OFFSET + 0x4C)
156#define SS_CR_PROTOCOL_WRITE_REG (QSCRATCH_REG_OFFSET + 0x50)
Manu Gautam8c642812012-06-07 10:35:10 +0530157
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300158struct dwc3_msm_req_complete {
159 struct list_head list_item;
160 struct usb_request *req;
161 void (*orig_complete)(struct usb_ep *ep,
162 struct usb_request *req);
163};
164
Ido Shayevitzef72ddd2012-03-28 18:55:55 +0200165struct dwc3_msm {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +0200166 struct device *dev;
167 void __iomem *base;
168 u32 resource_size;
169 int dbm_num_eps;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300170 u8 ep_num_mapping[DBM_MAX_EPS];
171 const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
172 struct list_head req_complete_list;
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +0530173 struct clk *xo_clk;
Manu Gautam3e9ad352012-08-16 14:44:47 -0700174 struct clk *ref_clk;
Manu Gautam1742db22012-06-19 13:33:24 +0530175 struct clk *core_clk;
Manu Gautam3e9ad352012-08-16 14:44:47 -0700176 struct clk *iface_clk;
177 struct clk *sleep_clk;
178 struct clk *hsphy_sleep_clk;
Jack Pham22698b82013-02-13 17:45:06 -0800179 struct clk *utmi_clk;
Manu Gautam60e01352012-05-29 09:00:34 +0530180 struct regulator *hsusb_3p3;
181 struct regulator *hsusb_1p8;
182 struct regulator *hsusb_vddcx;
183 struct regulator *ssusb_1p8;
184 struct regulator *ssusb_vddcx;
Manu Gautambb825d72013-03-12 16:25:42 +0530185
186 /* VBUS regulator if no OTG and running in host only mode */
187 struct regulator *vbus_otg;
Manu Gautamb5067272012-07-02 09:53:41 +0530188 struct dwc3_ext_xceiv ext_xceiv;
189 bool resume_pending;
190 atomic_t pm_suspended;
191 atomic_t in_lpm;
Manu Gautam377821c2012-09-28 16:53:24 +0530192 int hs_phy_irq;
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +0530193 int hsphy_init_seq;
Manu Gautam377821c2012-09-28 16:53:24 +0530194 bool lpm_irq_seen;
Manu Gautamb5067272012-07-02 09:53:41 +0530195 struct delayed_work resume_work;
Manu Gautam6eb13e32013-02-01 15:19:15 +0530196 struct work_struct restart_usb_work;
Manu Gautamb5067272012-07-02 09:53:41 +0530197 struct wake_lock wlock;
Manu Gautam8c642812012-06-07 10:35:10 +0530198 struct dwc3_charger charger;
199 struct usb_phy *otg_xceiv;
200 struct delayed_work chg_work;
201 enum usb_chg_state chg_state;
Jack Pham0cca9412013-03-08 13:22:42 -0800202 int pmic_id_irq;
203 struct work_struct id_work;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800204 struct qpnp_adc_tm_btm_param adc_param;
Jack Pham0fc12332012-11-19 13:14:22 -0800205 struct delayed_work init_adc_work;
206 bool id_adc_detect;
Manu Gautam8c642812012-06-07 10:35:10 +0530207 u8 dcd_retries;
Manu Gautam2617deb2012-08-31 17:50:06 -0700208 u32 bus_perf_client;
209 struct msm_bus_scale_pdata *bus_scale_table;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +0530210 struct power_supply usb_psy;
Jack Pham9354c6a2012-12-20 19:19:32 -0800211 struct power_supply *ext_vbus_psy;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +0530212 unsigned int online;
213 unsigned int host_mode;
214 unsigned int current_max;
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +0530215 unsigned int vdd_no_vol_level;
216 unsigned int vdd_low_vol_level;
217 unsigned int vdd_high_vol_level;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +0530218 bool vbus_active;
Jack Phamfadd6432012-12-07 19:03:41 -0800219 bool ext_inuse;
Jack Phamf12b7e12012-12-28 14:27:26 -0800220 enum dwc3_id_state id_state;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +0530221 unsigned long lpm_flags;
222#define MDWC3_CORECLK_OFF BIT(0)
223#define MDWC3_TCXO_SHUTDOWN BIT(1)
Pavankumar Kondeti08693e72013-05-03 11:55:48 +0530224
225 u32 qscratch_ctl_val;
226 dev_t ext_chg_dev;
227 struct cdev ext_chg_cdev;
228 struct class *ext_chg_class;
229 struct device *ext_chg_device;
230 bool ext_chg_opened;
231 bool ext_chg_active;
232 struct completion ext_chg_wait;
Manu Gautam60e01352012-05-29 09:00:34 +0530233};
234
235#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
236#define USB_HSPHY_3P3_VOL_MAX 3300000 /* uV */
237#define USB_HSPHY_3P3_HPM_LOAD 16000 /* uA */
238
239#define USB_HSPHY_1P8_VOL_MIN 1800000 /* uV */
240#define USB_HSPHY_1P8_VOL_MAX 1800000 /* uV */
241#define USB_HSPHY_1P8_HPM_LOAD 19000 /* uA */
242
243#define USB_SSPHY_1P8_VOL_MIN 1800000 /* uV */
244#define USB_SSPHY_1P8_VOL_MAX 1800000 /* uV */
245#define USB_SSPHY_1P8_HPM_LOAD 23000 /* uA */
246
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300247static struct dwc3_msm *context;
248
Jack Phamfadd6432012-12-07 19:03:41 -0800249static struct usb_ext_notification *usb_ext;
250
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300251/**
252 *
253 * Read register with debug info.
254 *
255 * @base - DWC3 base virtual address.
256 * @offset - register offset.
257 *
258 * @return u32
259 */
260static inline u32 dwc3_msm_read_reg(void *base, u32 offset)
261{
262 u32 val = ioread32(base + offset);
263 return val;
264}
265
266/**
267 * Read register masked field with debug info.
268 *
269 * @base - DWC3 base virtual address.
270 * @offset - register offset.
271 * @mask - register bitmask.
272 *
273 * @return u32
274 */
275static inline u32 dwc3_msm_read_reg_field(void *base,
276 u32 offset,
277 const u32 mask)
278{
279 u32 shift = find_first_bit((void *)&mask, 32);
280 u32 val = ioread32(base + offset);
281 val &= mask; /* clear other bits */
282 val >>= shift;
283 return val;
284}
285
286/**
287 *
288 * Write register with debug info.
289 *
290 * @base - DWC3 base virtual address.
291 * @offset - register offset.
292 * @val - value to write.
293 *
294 */
295static inline void dwc3_msm_write_reg(void *base, u32 offset, u32 val)
296{
297 iowrite32(val, base + offset);
298}
299
300/**
301 * Write register masked field with debug info.
302 *
303 * @base - DWC3 base virtual address.
304 * @offset - register offset.
305 * @mask - register bitmask.
306 * @val - value to write.
307 *
308 */
309static inline void dwc3_msm_write_reg_field(void *base, u32 offset,
310 const u32 mask, u32 val)
311{
312 u32 shift = find_first_bit((void *)&mask, 32);
313 u32 tmp = ioread32(base + offset);
314
315 tmp &= ~mask; /* clear written bits */
316 val = tmp | (val << shift);
317 iowrite32(val, base + offset);
318}
319
320/**
Manu Gautam8c642812012-06-07 10:35:10 +0530321 * Write register and read back masked value to confirm it is written
322 *
323 * @base - DWC3 base virtual address.
324 * @offset - register offset.
325 * @mask - register bitmask specifying what should be updated
326 * @val - value to write.
327 *
328 */
329static inline void dwc3_msm_write_readback(void *base, u32 offset,
330 const u32 mask, u32 val)
331{
332 u32 write_val, tmp = ioread32(base + offset);
333
334 tmp &= ~mask; /* retain other bits */
335 write_val = tmp | val;
336
337 iowrite32(write_val, base + offset);
338
339 /* Read back to see if val was written */
340 tmp = ioread32(base + offset);
341 tmp &= mask; /* clear other bits */
342
343 if (tmp != val)
344 dev_err(context->dev, "%s: write: %x to QSCRATCH: %x FAILED\n",
345 __func__, val, offset);
346}
347
348/**
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530349 *
350 * Write SSPHY register with debug info.
351 *
352 * @base - DWC3 base virtual address.
353 * @addr - SSPHY address to write.
354 * @val - value to write.
355 *
356 */
357static void dwc3_msm_ssusb_write_phycreg(void *base, u32 addr, u32 val)
358{
359 iowrite32(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
360 iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
361 while (ioread32(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
362 cpu_relax();
363
364 iowrite32(val, base + SS_CR_PROTOCOL_DATA_IN_REG);
365 iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_DATA_REG);
366 while (ioread32(base + SS_CR_PROTOCOL_CAP_DATA_REG))
367 cpu_relax();
368
369 iowrite32(0x1, base + SS_CR_PROTOCOL_WRITE_REG);
370 while (ioread32(base + SS_CR_PROTOCOL_WRITE_REG))
371 cpu_relax();
372}
373
374/**
375 *
376 * Read SSPHY register with debug info.
377 *
378 * @base - DWC3 base virtual address.
379 * @addr - SSPHY address to read.
380 *
381 */
382static u32 dwc3_msm_ssusb_read_phycreg(void *base, u32 addr)
383{
Vijayavardhan Vennapusa96201212013-06-12 19:59:27 +0530384 bool first_read = true;
385
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530386 iowrite32(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
387 iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
388 while (ioread32(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
389 cpu_relax();
390
Vijayavardhan Vennapusa96201212013-06-12 19:59:27 +0530391 /*
392 * Due to hardware bug, first read of SSPHY register might be
393 * incorrect. Hence as workaround, SW should perform SSPHY register
394 * read twice, but use only second read and ignore first read.
395 */
396retry:
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530397 iowrite32(0x1, base + SS_CR_PROTOCOL_READ_REG);
398 while (ioread32(base + SS_CR_PROTOCOL_READ_REG))
399 cpu_relax();
400
Vijayavardhan Vennapusa96201212013-06-12 19:59:27 +0530401 if (first_read) {
402 ioread32(base + SS_CR_PROTOCOL_DATA_OUT_REG);
403 first_read = false;
404 goto retry;
405 }
406
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530407 return ioread32(base + SS_CR_PROTOCOL_DATA_OUT_REG);
408}
409
410/**
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300411 * Return DBM EP number according to usb endpoint number.
412 *
413 */
414static int dwc3_msm_find_matching_dbm_ep(u8 usb_ep)
415{
416 int i;
417
418 for (i = 0; i < context->dbm_num_eps; i++)
419 if (context->ep_num_mapping[i] == usb_ep)
420 return i;
421
422 return -ENODEV; /* Not found */
423}
424
425/**
426 * Return number of configured DBM endpoints.
427 *
428 */
429static int dwc3_msm_configured_dbm_ep_num(void)
430{
431 int i;
432 int count = 0;
433
434 for (i = 0; i < context->dbm_num_eps; i++)
435 if (context->ep_num_mapping[i])
436 count++;
437
438 return count;
439}
440
441/**
442 * Configure the DBM with the USB3 core event buffer.
443 * This function is called by the SNPS UDC upon initialization.
444 *
445 * @addr - address of the event buffer.
446 * @size - size of the event buffer.
447 *
448 */
449static int dwc3_msm_event_buffer_config(u32 addr, u16 size)
450{
451 dev_dbg(context->dev, "%s\n", __func__);
452
453 dwc3_msm_write_reg(context->base, DBM_GEVNTADR, addr);
454 dwc3_msm_write_reg_field(context->base, DBM_GEVNTSIZ,
455 DBM_GEVNTSIZ_MASK, size);
456
457 return 0;
458}
459
460/**
461 * Reset the DBM registers upon initialization.
462 *
463 */
Shimrit Malichia00d7322012-08-05 13:56:28 +0300464static int dwc3_msm_dbm_soft_reset(int enter_reset)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300465{
466 dev_dbg(context->dev, "%s\n", __func__);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300467 if (enter_reset) {
468 dev_dbg(context->dev, "enter DBM reset\n");
469 dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
470 DBM_SFT_RST_MASK, 1);
471 } else {
472 dev_dbg(context->dev, "exit DBM reset\n");
473 dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
474 DBM_SFT_RST_MASK, 0);
475 /*enable DBM*/
476 dwc3_msm_write_reg_field(context->base, QSCRATCH_GENERAL_CFG,
477 DBM_EN_MASK, 0x1);
478 }
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300479
480 return 0;
481}
482
483/**
484 * Soft reset specific DBM ep.
485 * This function is called by the function driver upon events
486 * such as transfer aborting, USB re-enumeration and USB
487 * disconnection.
488 *
489 * @dbm_ep - DBM ep number.
490 * @enter_reset - should we enter a reset state or get out of it.
491 *
492 */
493static int dwc3_msm_dbm_ep_soft_reset(u8 dbm_ep, bool enter_reset)
494{
495 dev_dbg(context->dev, "%s\n", __func__);
496
497 if (dbm_ep >= context->dbm_num_eps) {
498 dev_err(context->dev,
499 "%s: Invalid DBM ep index\n", __func__);
500 return -ENODEV;
501 }
502
503 if (enter_reset) {
504 dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300505 DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 1);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300506 } else {
507 dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300508 DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 0);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300509 }
510
511 return 0;
512}
513
514/**
515 * Configure a USB DBM ep to work in BAM mode.
516 *
517 *
518 * @usb_ep - USB physical EP number.
519 * @producer - producer/consumer.
520 * @disable_wb - disable write back to system memory.
521 * @internal_mem - use internal USB memory for data fifo.
522 * @ioc - enable interrupt on completion.
523 *
524 * @return int - DBM ep number.
525 */
526static int dwc3_msm_dbm_ep_config(u8 usb_ep, u8 bam_pipe,
527 bool producer, bool disable_wb,
528 bool internal_mem, bool ioc)
529{
530 u8 dbm_ep;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300531 u32 ep_cfg;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300532
533 dev_dbg(context->dev, "%s\n", __func__);
534
Shimrit Malichia00d7322012-08-05 13:56:28 +0300535 dbm_ep = dwc3_msm_find_matching_dbm_ep(usb_ep);
536
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300537 if (dbm_ep < 0) {
Shimrit Malichia00d7322012-08-05 13:56:28 +0300538 dev_err(context->dev,
539 "%s: Invalid usb ep index\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300540 return -ENODEV;
541 }
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300542 /* First, reset the dbm endpoint */
Shimrit Malichia00d7322012-08-05 13:56:28 +0300543 dwc3_msm_dbm_ep_soft_reset(dbm_ep, 0);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300544
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300545 /* Set ioc bit for dbm_ep if needed */
546 dwc3_msm_write_reg_field(context->base, DBM_DBG_CNFG,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300547 DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300548
Shimrit Malichia00d7322012-08-05 13:56:28 +0300549 ep_cfg = (producer ? DBM_PRODUCER : 0) |
550 (disable_wb ? DBM_DISABLE_WB : 0) |
551 (internal_mem ? DBM_INT_RAM_ACC : 0);
552
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300553 dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
Shimrit Malichia00d7322012-08-05 13:56:28 +0300554 DBM_PRODUCER | DBM_DISABLE_WB | DBM_INT_RAM_ACC, ep_cfg >> 8);
555
556 dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
557 usb_ep);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300558 dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
559 DBM_BAM_PIPE_NUM, bam_pipe);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300560 dwc3_msm_write_reg_field(context->base, DBM_PIPE_CFG, 0x000000ff,
561 0xe4);
562 dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
563 1);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300564
565 return dbm_ep;
566}
567
568/**
569 * Configure a USB DBM ep to work in normal mode.
570 *
571 * @usb_ep - USB ep number.
572 *
573 */
574static int dwc3_msm_dbm_ep_unconfig(u8 usb_ep)
575{
576 u8 dbm_ep;
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530577 u32 data;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300578
579 dev_dbg(context->dev, "%s\n", __func__);
580
581 dbm_ep = dwc3_msm_find_matching_dbm_ep(usb_ep);
582
583 if (dbm_ep < 0) {
584 dev_err(context->dev,
585 "%s: Invalid usb ep index\n", __func__);
586 return -ENODEV;
587 }
588
589 context->ep_num_mapping[dbm_ep] = 0;
590
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530591 data = dwc3_msm_read_reg(context->base, DBM_EP_CFG(dbm_ep));
592 data &= (~0x1);
593 dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep), data);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300594
595 /* Reset the dbm endpoint */
596 dwc3_msm_dbm_ep_soft_reset(dbm_ep, true);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530597 /*
598 * 10 usec delay is required before deasserting DBM endpoint reset
599 * according to hardware programming guide.
600 */
601 udelay(10);
602 dwc3_msm_dbm_ep_soft_reset(dbm_ep, false);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300603
604 return 0;
605}
606
607/**
608 * Configure the DBM with the BAM's data fifo.
609 * This function is called by the USB BAM Driver
610 * upon initialization.
611 *
612 * @ep - pointer to usb endpoint.
613 * @addr - address of data fifo.
614 * @size - size of data fifo.
615 *
616 */
Shimrit Malichia00d7322012-08-05 13:56:28 +0300617int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size, u8 dst_pipe_idx)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300618{
619 u8 dbm_ep;
620 struct dwc3_ep *dep = to_dwc3_ep(ep);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300621 u8 bam_pipe = dst_pipe_idx;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300622
623 dev_dbg(context->dev, "%s\n", __func__);
624
Shimrit Malichia00d7322012-08-05 13:56:28 +0300625 dbm_ep = bam_pipe;
626 context->ep_num_mapping[dbm_ep] = dep->number;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300627
628 dwc3_msm_write_reg(context->base, DBM_DATA_FIFO(dbm_ep), addr);
629 dwc3_msm_write_reg_field(context->base, DBM_DATA_FIFO_SIZE(dbm_ep),
630 DBM_DATA_FIFO_SIZE_MASK, size);
631
632 return 0;
633}
634
635/**
636* Cleanups for msm endpoint on request complete.
637*
638* Also call original request complete.
639*
640* @usb_ep - pointer to usb_ep instance.
641* @request - pointer to usb_request instance.
642*
643* @return int - 0 on success, negetive on error.
644*/
645static void dwc3_msm_req_complete_func(struct usb_ep *ep,
646 struct usb_request *request)
647{
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300648 struct dwc3_ep *dep = to_dwc3_ep(ep);
649 struct dwc3_msm_req_complete *req_complete = NULL;
650
651 /* Find original request complete function and remove it from list */
652 list_for_each_entry(req_complete,
653 &context->req_complete_list,
654 list_item) {
655 if (req_complete->req == request)
656 break;
657 }
658 if (!req_complete || req_complete->req != request) {
659 dev_err(dep->dwc->dev, "%s: could not find the request\n",
660 __func__);
661 return;
662 }
663 list_del(&req_complete->list_item);
664
665 /*
666 * Release another one TRB to the pool since DBM queue took 2 TRBs
667 * (normal and link), and the dwc3/gadget.c :: dwc3_gadget_giveback
668 * released only one.
669 */
Manu Gautam55d34222012-12-19 16:49:47 +0530670 dep->busy_slot++;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300671
672 /* Unconfigure dbm ep */
673 dwc3_msm_dbm_ep_unconfig(dep->number);
674
675 /*
676 * If this is the last endpoint we unconfigured, than reset also
677 * the event buffers.
678 */
679 if (0 == dwc3_msm_configured_dbm_ep_num())
680 dwc3_msm_event_buffer_config(0, 0);
681
682 /*
683 * Call original complete function, notice that dwc->lock is already
684 * taken by the caller of this function (dwc3_gadget_giveback()).
685 */
686 request->complete = req_complete->orig_complete;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300687 if (request->complete)
688 request->complete(ep, request);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300689
690 kfree(req_complete);
691}
692
693/**
694* Helper function.
695* See the header of the dwc3_msm_ep_queue function.
696*
697* @dwc3_ep - pointer to dwc3_ep instance.
698* @req - pointer to dwc3_request instance.
699*
700* @return int - 0 on success, negetive on error.
701*/
702static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
703{
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300704 struct dwc3_trb *trb;
705 struct dwc3_trb *trb_link;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300706 struct dwc3_gadget_ep_cmd_params params;
707 u32 cmd;
708 int ret = 0;
709
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300710 /* We push the request to the dep->req_queued list to indicate that
711 * this request is issued with start transfer. The request will be out
712 * from this list in 2 cases. The first is that the transfer will be
713 * completed (not if the transfer is endless using a circular TRBs with
714 * with link TRB). The second case is an option to do stop stransfer,
715 * this can be initiated by the function driver when calling dequeue.
716 */
717 req->queued = true;
718 list_add_tail(&req->list, &dep->req_queued);
719
720 /* First, prepare a normal TRB, point to the fake buffer */
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300721 trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300722 dep->free_slot++;
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300723 memset(trb, 0, sizeof(*trb));
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300724
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300725 req->trb = trb;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300726 trb->bph = DBM_TRB_BIT | DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300727 trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
728 trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300729 req->trb_dma = dwc3_trb_dma_offset(dep, trb);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300730
731 /* Second, prepare a Link TRB that points to the first TRB*/
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300732 trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300733 dep->free_slot++;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300734 memset(trb_link, 0, sizeof *trb_link);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300735
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300736 trb_link->bpl = lower_32_bits(req->trb_dma);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300737 trb_link->bph = DBM_TRB_BIT |
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300738 DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
739 trb_link->size = 0;
740 trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300741
742 /*
743 * Now start the transfer
744 */
745 memset(&params, 0, sizeof(params));
Shimrit Malichia00d7322012-08-05 13:56:28 +0300746 params.param0 = 0; /* TDAddr High */
747 params.param1 = lower_32_bits(req->trb_dma); /* DAddr Low */
748
Manu Gautam5b2bf9a2012-10-18 10:52:50 +0530749 /* DBM requires IOC to be set */
750 cmd = DWC3_DEPCMD_STARTTRANSFER | DWC3_DEPCMD_CMDIOC;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300751 ret = dwc3_send_gadget_ep_cmd(dep->dwc, dep->number, cmd, &params);
752 if (ret < 0) {
753 dev_dbg(dep->dwc->dev,
754 "%s: failed to send STARTTRANSFER command\n",
755 __func__);
756
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300757 list_del(&req->list);
758 return ret;
759 }
Manu Gautam4a51a062012-12-07 11:24:39 +0530760 dep->flags |= DWC3_EP_BUSY;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300761
762 return ret;
763}
764
765/**
766* Queue a usb request to the DBM endpoint.
767* This function should be called after the endpoint
768* was enabled by the ep_enable.
769*
770* This function prepares special structure of TRBs which
771* is familier with the DBM HW, so it will possible to use
772* this endpoint in DBM mode.
773*
774* The TRBs prepared by this function, is one normal TRB
775* which point to a fake buffer, followed by a link TRB
776* that points to the first TRB.
777*
778* The API of this function follow the regular API of
779* usb_ep_queue (see usb_ep_ops in include/linuk/usb/gadget.h).
780*
781* @usb_ep - pointer to usb_ep instance.
782* @request - pointer to usb_request instance.
783* @gfp_flags - possible flags.
784*
785* @return int - 0 on success, negetive on error.
786*/
787static int dwc3_msm_ep_queue(struct usb_ep *ep,
788 struct usb_request *request, gfp_t gfp_flags)
789{
790 struct dwc3_request *req = to_dwc3_request(request);
791 struct dwc3_ep *dep = to_dwc3_ep(ep);
792 struct dwc3 *dwc = dep->dwc;
793 struct dwc3_msm_req_complete *req_complete;
794 unsigned long flags;
795 int ret = 0;
796 u8 bam_pipe;
797 bool producer;
798 bool disable_wb;
799 bool internal_mem;
800 bool ioc;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300801 u8 speed;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300802
803 if (!(request->udc_priv & MSM_SPS_MODE)) {
804 /* Not SPS mode, call original queue */
805 dev_vdbg(dwc->dev, "%s: not sps mode, use regular queue\n",
806 __func__);
807
808 return (context->original_ep_ops[dep->number])->queue(ep,
809 request,
810 gfp_flags);
811 }
812
813 if (!dep->endpoint.desc) {
814 dev_err(dwc->dev,
815 "%s: trying to queue request %p to disabled ep %s\n",
816 __func__, request, ep->name);
817 return -EPERM;
818 }
819
820 if (dep->number == 0 || dep->number == 1) {
821 dev_err(dwc->dev,
822 "%s: trying to queue dbm request %p to control ep %s\n",
823 __func__, request, ep->name);
824 return -EPERM;
825 }
826
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300827
Manu Gautam4a51a062012-12-07 11:24:39 +0530828 if (dep->busy_slot != dep->free_slot || !list_empty(&dep->request_list)
829 || !list_empty(&dep->req_queued)) {
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300830 dev_err(dwc->dev,
831 "%s: trying to queue dbm request %p tp ep %s\n",
832 __func__, request, ep->name);
833 return -EPERM;
Manu Gautam4a51a062012-12-07 11:24:39 +0530834 } else {
835 dep->busy_slot = 0;
836 dep->free_slot = 0;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300837 }
838
839 /*
840 * Override req->complete function, but before doing that,
841 * store it's original pointer in the req_complete_list.
842 */
843 req_complete = kzalloc(sizeof(*req_complete), GFP_KERNEL);
844 if (!req_complete) {
845 dev_err(dep->dwc->dev, "%s: not enough memory\n", __func__);
846 return -ENOMEM;
847 }
848 req_complete->req = request;
849 req_complete->orig_complete = request->complete;
850 list_add_tail(&req_complete->list_item, &context->req_complete_list);
851 request->complete = dwc3_msm_req_complete_func;
852
853 /*
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300854 * Configure the DBM endpoint
855 */
Shimrit Malichia00d7322012-08-05 13:56:28 +0300856 bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300857 producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
858 disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
859 internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
860 ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
861
862 ret = dwc3_msm_dbm_ep_config(dep->number,
863 bam_pipe, producer,
864 disable_wb, internal_mem, ioc);
865 if (ret < 0) {
866 dev_err(context->dev,
867 "error %d after calling dwc3_msm_dbm_ep_config\n",
868 ret);
869 return ret;
870 }
871
872 dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
873 __func__, request, ep->name, request->length);
874
875 /*
876 * We must obtain the lock of the dwc3 core driver,
877 * including disabling interrupts, so we will be sure
878 * that we are the only ones that configure the HW device
879 * core and ensure that we queuing the request will finish
880 * as soon as possible so we will release back the lock.
881 */
882 spin_lock_irqsave(&dwc->lock, flags);
883 ret = __dwc3_msm_ep_queue(dep, req);
884 spin_unlock_irqrestore(&dwc->lock, flags);
885 if (ret < 0) {
886 dev_err(context->dev,
887 "error %d after calling __dwc3_msm_ep_queue\n", ret);
888 return ret;
889 }
890
Shimrit Malichia00d7322012-08-05 13:56:28 +0300891 speed = dwc3_readl(dwc->regs, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD;
892 dwc3_msm_write_reg(context->base, DBM_GEN_CFG, speed >> 2);
893
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300894 return 0;
895}
896
897/**
898 * Configure MSM endpoint.
899 * This function do specific configurations
900 * to an endpoint which need specific implementaion
901 * in the MSM architecture.
902 *
903 * This function should be called by usb function/class
904 * layer which need a support from the specific MSM HW
905 * which wrap the USB3 core. (like DBM specific endpoints)
906 *
907 * @ep - a pointer to some usb_ep instance
908 *
909 * @return int - 0 on success, negetive on error.
910 */
911int msm_ep_config(struct usb_ep *ep)
912{
913 struct dwc3_ep *dep = to_dwc3_ep(ep);
914 struct usb_ep_ops *new_ep_ops;
915
Manu Gautama302f612012-12-18 17:33:06 +0530916 dwc3_msm_event_buffer_config(dwc3_msm_read_reg(context->base,
917 DWC3_GEVNTADRLO(0)),
918 dwc3_msm_read_reg(context->base, DWC3_GEVNTSIZ(0)));
919
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300920 /* Save original ep ops for future restore*/
921 if (context->original_ep_ops[dep->number]) {
922 dev_err(context->dev,
923 "ep [%s,%d] already configured as msm endpoint\n",
924 ep->name, dep->number);
925 return -EPERM;
926 }
927 context->original_ep_ops[dep->number] = ep->ops;
928
929 /* Set new usb ops as we like */
930 new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_KERNEL);
931 if (!new_ep_ops) {
932 dev_err(context->dev,
933 "%s: unable to allocate mem for new usb ep ops\n",
934 __func__);
935 return -ENOMEM;
936 }
937 (*new_ep_ops) = (*ep->ops);
938 new_ep_ops->queue = dwc3_msm_ep_queue;
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530939 new_ep_ops->disable = ep->ops->disable;
940
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300941 ep->ops = new_ep_ops;
942
943 /*
944 * Do HERE more usb endpoint configurations
945 * which are specific to MSM.
946 */
947
948 return 0;
949}
950EXPORT_SYMBOL(msm_ep_config);
951
952/**
953 * Un-configure MSM endpoint.
954 * Tear down configurations done in the
955 * dwc3_msm_ep_config function.
956 *
957 * @ep - a pointer to some usb_ep instance
958 *
959 * @return int - 0 on success, negetive on error.
960 */
961int msm_ep_unconfig(struct usb_ep *ep)
962{
963 struct dwc3_ep *dep = to_dwc3_ep(ep);
964 struct usb_ep_ops *old_ep_ops;
965
966 /* Restore original ep ops */
967 if (!context->original_ep_ops[dep->number]) {
968 dev_err(context->dev,
969 "ep [%s,%d] was not configured as msm endpoint\n",
970 ep->name, dep->number);
971 return -EINVAL;
972 }
973 old_ep_ops = (struct usb_ep_ops *)ep->ops;
974 ep->ops = context->original_ep_ops[dep->number];
975 context->original_ep_ops[dep->number] = NULL;
976 kfree(old_ep_ops);
977
978 /*
979 * Do HERE more usb endpoint un-configurations
980 * which are specific to MSM.
981 */
982
983 return 0;
984}
985EXPORT_SYMBOL(msm_ep_unconfig);
986
Manu Gautam6eb13e32013-02-01 15:19:15 +0530987static void dwc3_restart_usb_work(struct work_struct *w)
988{
989 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
990 restart_usb_work);
991
992 dev_dbg(mdwc->dev, "%s\n", __func__);
993
994 if (atomic_read(&mdwc->in_lpm) || !mdwc->otg_xceiv) {
995 dev_err(mdwc->dev, "%s failed!!!\n", __func__);
996 return;
997 }
998
999 if (!mdwc->ext_xceiv.bsv) {
1000 dev_dbg(mdwc->dev, "%s bailing out in disconnect\n", __func__);
1001 return;
1002 }
1003
1004 /* Reset active USB connection */
1005 mdwc->ext_xceiv.bsv = false;
1006 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
1007 /* Make sure disconnect is processed before sending connect */
1008 flush_delayed_work(&mdwc->resume_work);
1009
1010 mdwc->ext_xceiv.bsv = true;
1011 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
1012}
1013
1014/**
1015 * Reset USB peripheral connection
1016 * Inform OTG for Vbus LOW followed by Vbus HIGH notification.
1017 * This performs full hardware reset and re-initialization which
1018 * might be required by some DBM client driver during uninit/cleanup.
1019 */
1020void msm_dwc3_restart_usb_session(void)
1021{
1022 struct dwc3_msm *mdwc = context;
1023
1024 dev_dbg(mdwc->dev, "%s\n", __func__);
1025 queue_work(system_nrt_wq, &mdwc->restart_usb_work);
1026
1027 return;
1028}
1029EXPORT_SYMBOL(msm_dwc3_restart_usb_session);
1030
Jack Phamfadd6432012-12-07 19:03:41 -08001031/**
1032 * msm_register_usb_ext_notification: register for event notification
1033 * @info: pointer to client usb_ext_notification structure. May be NULL.
1034 *
1035 * @return int - 0 on success, negative on error
1036 */
1037int msm_register_usb_ext_notification(struct usb_ext_notification *info)
1038{
1039 pr_debug("%s usb_ext: %p\n", __func__, info);
1040
1041 if (info) {
1042 if (usb_ext) {
1043 pr_err("%s: already registered\n", __func__);
1044 return -EEXIST;
1045 }
1046
1047 if (!info->notify) {
1048 pr_err("%s: notify is NULL\n", __func__);
1049 return -EINVAL;
1050 }
1051 }
1052
1053 usb_ext = info;
1054 return 0;
1055}
1056EXPORT_SYMBOL(msm_register_usb_ext_notification);
1057
Manu Gautam60e01352012-05-29 09:00:34 +05301058/* HSPHY */
1059static int dwc3_hsusb_config_vddcx(int high)
1060{
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301061 int min_vol, max_vol, ret;
Manu Gautam60e01352012-05-29 09:00:34 +05301062 struct dwc3_msm *dwc = context;
Manu Gautam60e01352012-05-29 09:00:34 +05301063
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301064 max_vol = dwc->vdd_high_vol_level;
1065 min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
Manu Gautam60e01352012-05-29 09:00:34 +05301066 ret = regulator_set_voltage(dwc->hsusb_vddcx, min_vol, max_vol);
1067 if (ret) {
1068 dev_err(dwc->dev, "unable to set voltage for HSUSB_VDDCX\n");
1069 return ret;
1070 }
1071
1072 dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
1073 min_vol, max_vol);
1074
1075 return ret;
1076}
1077
1078static int dwc3_hsusb_ldo_init(int init)
1079{
1080 int rc = 0;
1081 struct dwc3_msm *dwc = context;
1082
1083 if (!init) {
1084 regulator_set_voltage(dwc->hsusb_1p8, 0, USB_HSPHY_1P8_VOL_MAX);
1085 regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
1086 return 0;
1087 }
1088
1089 dwc->hsusb_3p3 = devm_regulator_get(dwc->dev, "HSUSB_3p3");
1090 if (IS_ERR(dwc->hsusb_3p3)) {
1091 dev_err(dwc->dev, "unable to get hsusb 3p3\n");
1092 return PTR_ERR(dwc->hsusb_3p3);
1093 }
1094
1095 rc = regulator_set_voltage(dwc->hsusb_3p3,
1096 USB_HSPHY_3P3_VOL_MIN, USB_HSPHY_3P3_VOL_MAX);
1097 if (rc) {
1098 dev_err(dwc->dev, "unable to set voltage for hsusb 3p3\n");
1099 return rc;
1100 }
1101 dwc->hsusb_1p8 = devm_regulator_get(dwc->dev, "HSUSB_1p8");
1102 if (IS_ERR(dwc->hsusb_1p8)) {
1103 dev_err(dwc->dev, "unable to get hsusb 1p8\n");
1104 rc = PTR_ERR(dwc->hsusb_1p8);
1105 goto devote_3p3;
1106 }
1107 rc = regulator_set_voltage(dwc->hsusb_1p8,
1108 USB_HSPHY_1P8_VOL_MIN, USB_HSPHY_1P8_VOL_MAX);
1109 if (rc) {
1110 dev_err(dwc->dev, "unable to set voltage for hsusb 1p8\n");
1111 goto devote_3p3;
1112 }
1113
1114 return 0;
1115
1116devote_3p3:
1117 regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
1118
1119 return rc;
1120}
1121
1122static int dwc3_hsusb_ldo_enable(int on)
1123{
1124 int rc = 0;
1125 struct dwc3_msm *dwc = context;
1126
1127 dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
1128
1129 if (!on)
1130 goto disable_regulators;
1131
1132
1133 rc = regulator_set_optimum_mode(dwc->hsusb_1p8, USB_HSPHY_1P8_HPM_LOAD);
1134 if (rc < 0) {
1135 dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_1p8\n");
1136 return rc;
1137 }
1138
1139 rc = regulator_enable(dwc->hsusb_1p8);
1140 if (rc) {
1141 dev_err(dwc->dev, "Unable to enable HSUSB_1p8\n");
1142 goto put_1p8_lpm;
1143 }
1144
1145 rc = regulator_set_optimum_mode(dwc->hsusb_3p3, USB_HSPHY_3P3_HPM_LOAD);
1146 if (rc < 0) {
1147 dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_3p3\n");
1148 goto disable_1p8;
1149 }
1150
1151 rc = regulator_enable(dwc->hsusb_3p3);
1152 if (rc) {
1153 dev_err(dwc->dev, "Unable to enable HSUSB_3p3\n");
1154 goto put_3p3_lpm;
1155 }
1156
1157 return 0;
1158
1159disable_regulators:
1160 rc = regulator_disable(dwc->hsusb_3p3);
1161 if (rc)
1162 dev_err(dwc->dev, "Unable to disable HSUSB_3p3\n");
1163
1164put_3p3_lpm:
1165 rc = regulator_set_optimum_mode(dwc->hsusb_3p3, 0);
1166 if (rc < 0)
1167 dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_3p3\n");
1168
1169disable_1p8:
1170 rc = regulator_disable(dwc->hsusb_1p8);
1171 if (rc)
1172 dev_err(dwc->dev, "Unable to disable HSUSB_1p8\n");
1173
1174put_1p8_lpm:
1175 rc = regulator_set_optimum_mode(dwc->hsusb_1p8, 0);
1176 if (rc < 0)
1177 dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_1p8\n");
1178
1179 return rc < 0 ? rc : 0;
1180}
1181
1182/* SSPHY */
1183static int dwc3_ssusb_config_vddcx(int high)
1184{
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301185 int min_vol, max_vol, ret;
Manu Gautam60e01352012-05-29 09:00:34 +05301186 struct dwc3_msm *dwc = context;
Manu Gautam60e01352012-05-29 09:00:34 +05301187
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301188 max_vol = dwc->vdd_high_vol_level;
1189 min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
Manu Gautam60e01352012-05-29 09:00:34 +05301190 ret = regulator_set_voltage(dwc->ssusb_vddcx, min_vol, max_vol);
1191 if (ret) {
1192 dev_err(dwc->dev, "unable to set voltage for SSUSB_VDDCX\n");
1193 return ret;
1194 }
1195
1196 dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
1197 min_vol, max_vol);
1198 return ret;
1199}
1200
1201/* 3.3v supply not needed for SS PHY */
1202static int dwc3_ssusb_ldo_init(int init)
1203{
1204 int rc = 0;
1205 struct dwc3_msm *dwc = context;
1206
1207 if (!init) {
1208 regulator_set_voltage(dwc->ssusb_1p8, 0, USB_SSPHY_1P8_VOL_MAX);
1209 return 0;
1210 }
1211
1212 dwc->ssusb_1p8 = devm_regulator_get(dwc->dev, "SSUSB_1p8");
1213 if (IS_ERR(dwc->ssusb_1p8)) {
1214 dev_err(dwc->dev, "unable to get ssusb 1p8\n");
1215 return PTR_ERR(dwc->ssusb_1p8);
1216 }
1217 rc = regulator_set_voltage(dwc->ssusb_1p8,
1218 USB_SSPHY_1P8_VOL_MIN, USB_SSPHY_1P8_VOL_MAX);
1219 if (rc)
1220 dev_err(dwc->dev, "unable to set voltage for ssusb 1p8\n");
1221
1222 return rc;
1223}
1224
1225static int dwc3_ssusb_ldo_enable(int on)
1226{
1227 int rc = 0;
1228 struct dwc3_msm *dwc = context;
1229
1230 dev_dbg(context->dev, "reg (%s)\n", on ? "HPM" : "LPM");
1231
1232 if (!on)
1233 goto disable_regulators;
1234
1235
1236 rc = regulator_set_optimum_mode(dwc->ssusb_1p8, USB_SSPHY_1P8_HPM_LOAD);
1237 if (rc < 0) {
1238 dev_err(dwc->dev, "Unable to set HPM of SSUSB_1p8\n");
1239 return rc;
1240 }
1241
1242 rc = regulator_enable(dwc->ssusb_1p8);
1243 if (rc) {
1244 dev_err(dwc->dev, "Unable to enable SSUSB_1p8\n");
1245 goto put_1p8_lpm;
1246 }
1247
1248 return 0;
1249
1250disable_regulators:
1251 rc = regulator_disable(dwc->ssusb_1p8);
1252 if (rc)
1253 dev_err(dwc->dev, "Unable to disable SSUSB_1p8\n");
1254
1255put_1p8_lpm:
1256 rc = regulator_set_optimum_mode(dwc->ssusb_1p8, 0);
1257 if (rc < 0)
1258 dev_err(dwc->dev, "Unable to set LPM of SSUSB_1p8\n");
1259
1260 return rc < 0 ? rc : 0;
1261}
1262
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301263static int dwc3_msm_link_clk_reset(bool assert)
1264{
1265 int ret = 0;
1266 struct dwc3_msm *mdwc = context;
1267
1268 if (assert) {
1269 /* Using asynchronous block reset to the hardware */
1270 dev_dbg(mdwc->dev, "block_reset ASSERT\n");
1271 clk_disable_unprepare(mdwc->ref_clk);
1272 clk_disable_unprepare(mdwc->iface_clk);
1273 clk_disable_unprepare(mdwc->core_clk);
1274 ret = clk_reset(mdwc->core_clk, CLK_RESET_ASSERT);
1275 if (ret)
1276 dev_err(mdwc->dev, "dwc3 core_clk assert failed\n");
1277 } else {
1278 dev_dbg(mdwc->dev, "block_reset DEASSERT\n");
1279 ret = clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT);
1280 ndelay(200);
1281 clk_prepare_enable(mdwc->core_clk);
1282 clk_prepare_enable(mdwc->ref_clk);
1283 clk_prepare_enable(mdwc->iface_clk);
1284 if (ret)
1285 dev_err(mdwc->dev, "dwc3 core_clk deassert failed\n");
1286 }
1287
1288 return ret;
1289}
1290
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301291/* Reinitialize SSPHY parameters by overriding using QSCRATCH CR interface */
1292static void dwc3_msm_ss_phy_reg_init(struct dwc3_msm *msm)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301293{
1294 u32 data = 0;
1295
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301296 /*
1297 * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
1298 * in HS mode instead of SS mode. Workaround it by asserting
1299 * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
1300 */
1301 data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x102D);
1302 data |= (1 << 7);
1303 dwc3_msm_ssusb_write_phycreg(msm->base, 0x102D, data);
1304
1305 data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1010);
1306 data &= ~0xFF0;
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301307 data |= 0x20;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301308 dwc3_msm_ssusb_write_phycreg(msm->base, 0x1010, data);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301309
1310 /*
1311 * Fix RX Equalization setting as follows
1312 * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
1313 * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
1314 * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
1315 * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
1316 */
1317 data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1006);
1318 data &= ~(1 << 6);
1319 data |= (1 << 7);
1320 data &= ~(0x7 << 8);
1321 data |= (0x3 << 8);
1322 data |= (0x1 << 11);
1323 dwc3_msm_ssusb_write_phycreg(msm->base, 0x1006, data);
1324
1325 /*
1326 * Set EQ and TX launch amplitudes as follows
1327 * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
1328 * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
1329 * LANE0.TX_OVRD_DRV_LO.EN set to 1.
1330 */
1331 data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1002);
1332 data &= ~0x3F80;
1333 data |= (0x16 << 7);
1334 data &= ~0x7F;
1335 data |= (0x7F | (1 << 14));
1336 dwc3_msm_ssusb_write_phycreg(msm->base, 0x1002, data);
1337
Jack Pham63c8c702013-04-24 19:21:33 -07001338 /*
1339 * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
1340 * TX_FULL_SWING [26:20] amplitude to 127
1341 * TX_DEEMPH_3_5DB [13:8] to 22
1342 * LOS_BIAS [2:0] to 0x5
1343 */
1344 dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1,
1345 0x07f03f07, 0x07f01605);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301346}
1347
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301348/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
1349static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *msm)
1350{
1351 /* SSPHY Initialization: Use ref_clk from pads and set its parameters */
1352 dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
1353 msleep(30);
1354 /* Assert SSPHY reset */
1355 dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
1356 usleep_range(2000, 2200);
1357 /* De-assert SSPHY reset - power and ref_clock must be ON */
1358 dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
1359 usleep_range(2000, 2200);
1360 /* Ref clock must be stable now, enable ref clock for HS mode */
1361 dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
1362 usleep_range(2000, 2200);
1363 /*
1364 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
1365 * and disable RETENTION (power-on default is ENABLED)
1366 */
1367 dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
1368 usleep_range(2000, 2200);
1369 /* Disable (bypass) VBUS and ID filters */
1370 dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
1371 /*
1372 * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
1373 * VBUS valid threshold, disconnect valid threshold, DC voltage level,
1374 * preempasis and rise/fall time.
1375 */
1376 if (override_phy_init)
1377 msm->hsphy_init_seq = override_phy_init;
1378 if (msm->hsphy_init_seq)
1379 dwc3_msm_write_readback(msm->base,
1380 PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
1381 msm->hsphy_init_seq & 0x03FFFFFF);
1382
1383 /* Enable master clock for RAMs to allow BAM to access RAMs when
1384 * RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
1385 * are seen where RAM clocks get turned OFF in SS mode
1386 */
1387 dwc3_msm_write_reg(msm->base, CGCTL_REG,
1388 dwc3_msm_read_reg(msm->base, CGCTL_REG) | 0x18);
1389
1390 dwc3_msm_ss_phy_reg_init(msm);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301391 /*
1392 * This is required to restore the POR value after userspace
1393 * is done with charger detection.
1394 */
1395 msm->qscratch_ctl_val = dwc3_msm_read_reg(msm->base, QSCRATCH_CTRL_REG);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301396}
1397
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301398static void dwc3_msm_block_reset(bool core_reset)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301399{
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301400
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301401 struct dwc3_msm *mdwc = context;
1402 int ret = 0;
1403
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301404 if (core_reset) {
1405 ret = dwc3_msm_link_clk_reset(1);
1406 if (ret)
1407 return;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301408
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301409 usleep_range(1000, 1200);
1410 ret = dwc3_msm_link_clk_reset(0);
1411 if (ret)
1412 return;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301413
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301414 usleep_range(10000, 12000);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301415
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301416 /* Reinitialize QSCRATCH registers after block reset */
1417 dwc3_msm_qscratch_reg_init(mdwc);
1418 }
Manu Gautama302f612012-12-18 17:33:06 +05301419
1420 /* Reset the DBM */
1421 dwc3_msm_dbm_soft_reset(1);
1422 usleep_range(1000, 1200);
1423 dwc3_msm_dbm_soft_reset(0);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301424}
1425
Manu Gautam8c642812012-06-07 10:35:10 +05301426static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
1427{
1428 u32 chg_ctrl;
1429
1430 /* Turn off VDP_SRC */
1431 dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
1432 msleep(20);
1433
1434 /* Before proceeding make sure VDP_SRC is OFF */
1435 chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
1436 if (chg_ctrl & 0x3F)
1437 dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
1438 __func__, chg_ctrl);
1439 /*
1440 * Configure DM as current source, DP as current sink
1441 * and enable battery charging comparators.
1442 */
1443 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x34);
1444}
1445
Manu Gautama1e331d2013-02-07 14:55:05 +05301446static bool dwc3_chg_det_check_linestate(struct dwc3_msm *mdwc)
1447{
1448 u32 chg_det;
Jack Pham9b4606b2013-04-02 17:32:25 -07001449
1450 if (!prop_chg_detect)
1451 return false;
Manu Gautama1e331d2013-02-07 14:55:05 +05301452
1453 chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
Jack Pham9b4606b2013-04-02 17:32:25 -07001454 return chg_det & (3 << 8);
Manu Gautama1e331d2013-02-07 14:55:05 +05301455}
1456
Manu Gautam8c642812012-06-07 10:35:10 +05301457static bool dwc3_chg_det_check_output(struct dwc3_msm *mdwc)
1458{
1459 u32 chg_det;
1460 bool ret = false;
1461
1462 chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
1463 ret = chg_det & 1;
1464
1465 return ret;
1466}
1467
1468static void dwc3_chg_enable_primary_det(struct dwc3_msm *mdwc)
1469{
1470 /*
1471 * Configure DP as current source, DM as current sink
1472 * and enable battery charging comparators.
1473 */
1474 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x30);
1475}
1476
1477static inline bool dwc3_chg_check_dcd(struct dwc3_msm *mdwc)
1478{
1479 u32 chg_state;
1480 bool ret = false;
1481
1482 chg_state = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
1483 ret = chg_state & 2;
1484
1485 return ret;
1486}
1487
1488static inline void dwc3_chg_disable_dcd(struct dwc3_msm *mdwc)
1489{
1490 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x0);
1491}
1492
1493static inline void dwc3_chg_enable_dcd(struct dwc3_msm *mdwc)
1494{
1495 /* Data contact detection enable, DCDENB */
1496 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x2);
1497}
1498
1499static void dwc3_chg_block_reset(struct dwc3_msm *mdwc)
1500{
1501 u32 chg_ctrl;
1502
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301503 dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
1504 mdwc->qscratch_ctl_val);
Manu Gautam8c642812012-06-07 10:35:10 +05301505 /* Clear charger detecting control bits */
1506 dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
1507
1508 /* Clear alt interrupt latch and enable bits */
1509 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1510 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x0);
1511
1512 udelay(100);
1513
1514 /* Before proceeding make sure charger block is RESET */
1515 chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
1516 if (chg_ctrl & 0x3F)
1517 dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
1518 __func__, chg_ctrl);
1519}
1520
1521static const char *chg_to_string(enum dwc3_chg_type chg_type)
1522{
1523 switch (chg_type) {
Manu Gautama1e331d2013-02-07 14:55:05 +05301524 case DWC3_SDP_CHARGER: return "USB_SDP_CHARGER";
1525 case DWC3_DCP_CHARGER: return "USB_DCP_CHARGER";
1526 case DWC3_CDP_CHARGER: return "USB_CDP_CHARGER";
1527 case DWC3_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Manu Gautam8c642812012-06-07 10:35:10 +05301528 default: return "INVALID_CHARGER";
1529 }
1530}
1531
1532#define DWC3_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1533#define DWC3_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1534#define DWC3_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
1535#define DWC3_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
1536
1537static void dwc3_chg_detect_work(struct work_struct *w)
1538{
1539 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, chg_work.work);
1540 bool is_dcd = false, tmout, vout;
1541 unsigned long delay;
1542
1543 dev_dbg(mdwc->dev, "chg detection work\n");
1544 switch (mdwc->chg_state) {
1545 case USB_CHG_STATE_UNDEFINED:
1546 dwc3_chg_block_reset(mdwc);
1547 dwc3_chg_enable_dcd(mdwc);
1548 mdwc->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1549 mdwc->dcd_retries = 0;
1550 delay = DWC3_CHG_DCD_POLL_TIME;
1551 break;
1552 case USB_CHG_STATE_WAIT_FOR_DCD:
1553 is_dcd = dwc3_chg_check_dcd(mdwc);
1554 tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES;
1555 if (is_dcd || tmout) {
1556 dwc3_chg_disable_dcd(mdwc);
Manu Gautama1e331d2013-02-07 14:55:05 +05301557 if (dwc3_chg_det_check_linestate(mdwc)) {
1558 dev_dbg(mdwc->dev, "proprietary charger\n");
1559 mdwc->charger.chg_type =
1560 DWC3_PROPRIETARY_CHARGER;
1561 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1562 delay = 0;
1563 break;
1564 }
Manu Gautam8c642812012-06-07 10:35:10 +05301565 dwc3_chg_enable_primary_det(mdwc);
1566 delay = DWC3_CHG_PRIMARY_DET_TIME;
1567 mdwc->chg_state = USB_CHG_STATE_DCD_DONE;
1568 } else {
1569 delay = DWC3_CHG_DCD_POLL_TIME;
1570 }
1571 break;
1572 case USB_CHG_STATE_DCD_DONE:
1573 vout = dwc3_chg_det_check_output(mdwc);
1574 if (vout) {
1575 dwc3_chg_enable_secondary_det(mdwc);
1576 delay = DWC3_CHG_SECONDARY_DET_TIME;
1577 mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1578 } else {
Manu Gautama1e331d2013-02-07 14:55:05 +05301579 mdwc->charger.chg_type = DWC3_SDP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301580 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1581 delay = 0;
1582 }
1583 break;
1584 case USB_CHG_STATE_PRIMARY_DONE:
1585 vout = dwc3_chg_det_check_output(mdwc);
1586 if (vout)
Manu Gautama1e331d2013-02-07 14:55:05 +05301587 mdwc->charger.chg_type = DWC3_DCP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301588 else
Manu Gautama1e331d2013-02-07 14:55:05 +05301589 mdwc->charger.chg_type = DWC3_CDP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301590 mdwc->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1591 /* fall through */
1592 case USB_CHG_STATE_SECONDARY_DONE:
1593 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1594 /* fall through */
1595 case USB_CHG_STATE_DETECTED:
1596 dwc3_chg_block_reset(mdwc);
Manu Gautama48296e2012-12-05 17:37:56 +05301597 /* Enable VDP_SRC */
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301598 if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
Manu Gautama48296e2012-12-05 17:37:56 +05301599 dwc3_msm_write_readback(mdwc->base,
1600 CHARGING_DET_CTRL_REG, 0x1F, 0x10);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301601 if (mdwc->ext_chg_opened) {
1602 init_completion(&mdwc->ext_chg_wait);
1603 mdwc->ext_chg_active = true;
1604 }
1605 }
Manu Gautam8c642812012-06-07 10:35:10 +05301606 dev_dbg(mdwc->dev, "chg_type = %s\n",
1607 chg_to_string(mdwc->charger.chg_type));
1608 mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
1609 &mdwc->charger);
1610 return;
1611 default:
1612 return;
1613 }
1614
1615 queue_delayed_work(system_nrt_wq, &mdwc->chg_work, delay);
1616}
1617
1618static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)
1619{
1620 struct dwc3_msm *mdwc = context;
1621
1622 if (start == false) {
Jack Pham9354c6a2012-12-20 19:19:32 -08001623 dev_dbg(mdwc->dev, "canceling charging detection work\n");
Manu Gautam8c642812012-06-07 10:35:10 +05301624 cancel_delayed_work_sync(&mdwc->chg_work);
1625 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1626 charger->chg_type = DWC3_INVALID_CHARGER;
1627 return;
1628 }
1629
1630 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1631 charger->chg_type = DWC3_INVALID_CHARGER;
1632 queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
1633}
1634
Manu Gautamb5067272012-07-02 09:53:41 +05301635static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
1636{
Manu Gautam2617deb2012-08-31 17:50:06 -07001637 int ret;
Manu Gautama48296e2012-12-05 17:37:56 +05301638 bool dcp;
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301639 bool host_bus_suspend;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301640 bool host_ss_active;
Manu Gautam2617deb2012-08-31 17:50:06 -07001641
Manu Gautamb5067272012-07-02 09:53:41 +05301642 dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
1643
1644 if (atomic_read(&mdwc->in_lpm)) {
1645 dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
1646 return 0;
1647 }
1648
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301649 host_ss_active = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC) & PORT_PE;
Manu Gautama48296e2012-12-05 17:37:56 +05301650 if (mdwc->hs_phy_irq)
1651 disable_irq(mdwc->hs_phy_irq);
1652
Manu Gautam98013c22012-11-20 17:42:42 +05301653 if (cancel_delayed_work_sync(&mdwc->chg_work))
1654 dev_dbg(mdwc->dev, "%s: chg_work was pending\n", __func__);
1655 if (mdwc->chg_state != USB_CHG_STATE_DETECTED) {
1656 /* charger detection wasn't complete; re-init flags */
1657 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1658 mdwc->charger.chg_type = DWC3_INVALID_CHARGER;
Manu Gautama48296e2012-12-05 17:37:56 +05301659 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG,
1660 0x37, 0x0);
Manu Gautam98013c22012-11-20 17:42:42 +05301661 }
1662
Manu Gautam840f4fe2013-04-16 16:50:30 +05301663 dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
1664 (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301665 host_bus_suspend = mdwc->host_mode == 1;
Manu Gautam377821c2012-09-28 16:53:24 +05301666
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301667 if (!dcp && !host_bus_suspend)
1668 dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
1669 mdwc->qscratch_ctl_val);
1670
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05301671 /* Sequence to put SSPHY in low power state:
1672 * 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
1673 * 2. Clear REF_USE_PAD in SS_PHY_CTRL_REG
1674 * 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
1675 * 4. Disable SSPHY ref clk
1676 */
1677 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8), 0x0);
1678 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28), 0x0);
1679 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
1680 (1 << 26));
1681
Manu Gautam377821c2012-09-28 16:53:24 +05301682 usleep_range(1000, 1200);
Manu Gautam3e9ad352012-08-16 14:44:47 -07001683 clk_disable_unprepare(mdwc->ref_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05301684
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301685 if (host_bus_suspend) {
1686 /* Sequence for host bus suspend case:
1687 * 1. Set suspend and sleep bits in GUSB2PHYCONFIG reg
1688 * 2. Clear interrupt latch register and enable BSV, ID HV intr
1689 * 3. Enable DP and DM HV interrupts in ALT_INTERRUPT_EN_REG
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301690 */
1691 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
1692 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
1693 0x00000140);
1694 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1695 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1696 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1697 0x18000, 0x18000);
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301698 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0xFC0);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301699 udelay(5);
1700 } else {
1701 /* Sequence to put hardware in low power state:
1702 * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
1703 * 2. Clear charger detection control fields (performed above)
1704 * 3. SUSPEND PHY and turn OFF core clock after some delay
1705 * 4. Clear interrupt latch register and enable BSV, ID HV intr
1706 * 5. Enable PHY retention
1707 */
1708 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000,
1709 0x1000);
1710 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1711 0xC00000, 0x800000);
1712 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1713 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1714 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1715 0x18000, 0x18000);
1716 if (!dcp)
1717 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1718 0x2, 0x0);
1719 }
Manu Gautam377821c2012-09-28 16:53:24 +05301720
1721 /* make sure above writes are completed before turning off clocks */
1722 wmb();
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301723 if (!host_bus_suspend || !host_ss_active) {
1724 clk_disable_unprepare(mdwc->core_clk);
1725 mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
1726 }
Manu Gautam377821c2012-09-28 16:53:24 +05301727 clk_disable_unprepare(mdwc->iface_clk);
1728
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301729 if (!host_bus_suspend)
Jack Pham22698b82013-02-13 17:45:06 -08001730 clk_disable_unprepare(mdwc->utmi_clk);
1731
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301732 if (!host_bus_suspend) {
Jack Pham22698b82013-02-13 17:45:06 -08001733 /* USB PHY no more requires TCXO */
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05301734 clk_disable_unprepare(mdwc->xo_clk);
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301735 mdwc->lpm_flags |= MDWC3_TCXO_SHUTDOWN;
Jack Pham22698b82013-02-13 17:45:06 -08001736 }
Manu Gautamb5067272012-07-02 09:53:41 +05301737
Manu Gautam2617deb2012-08-31 17:50:06 -07001738 if (mdwc->bus_perf_client) {
1739 ret = msm_bus_scale_client_update_request(
1740 mdwc->bus_perf_client, 0);
1741 if (ret)
1742 dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
1743 }
1744
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301745 if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
1746 !host_bus_suspend)
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05301747 dwc3_hsusb_ldo_enable(0);
1748
Vijayavardhan Vennapusa6bc06962012-10-31 13:23:38 +05301749 dwc3_ssusb_ldo_enable(0);
1750 dwc3_ssusb_config_vddcx(0);
Manu Gautam840f4fe2013-04-16 16:50:30 +05301751 if (!host_bus_suspend && !dcp)
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301752 dwc3_hsusb_config_vddcx(0);
Manu Gautam377821c2012-09-28 16:53:24 +05301753 wake_unlock(&mdwc->wlock);
Manu Gautamb5067272012-07-02 09:53:41 +05301754 atomic_set(&mdwc->in_lpm, 1);
Manu Gautam377821c2012-09-28 16:53:24 +05301755
Manu Gautamb5067272012-07-02 09:53:41 +05301756 dev_info(mdwc->dev, "DWC3 in low power mode\n");
1757
Manu Gautam840f4fe2013-04-16 16:50:30 +05301758 if (mdwc->hs_phy_irq) {
Manu Gautama48296e2012-12-05 17:37:56 +05301759 enable_irq(mdwc->hs_phy_irq);
Manu Gautam840f4fe2013-04-16 16:50:30 +05301760 /* with DCP we dont require wakeup using HS_PHY_IRQ */
1761 if (dcp)
1762 disable_irq_wake(mdwc->hs_phy_irq);
1763 }
Manu Gautama48296e2012-12-05 17:37:56 +05301764
Manu Gautamb5067272012-07-02 09:53:41 +05301765 return 0;
1766}
1767
1768static int dwc3_msm_resume(struct dwc3_msm *mdwc)
1769{
Manu Gautam2617deb2012-08-31 17:50:06 -07001770 int ret;
Manu Gautama48296e2012-12-05 17:37:56 +05301771 bool dcp;
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301772 bool host_bus_suspend;
Manu Gautam2617deb2012-08-31 17:50:06 -07001773
Manu Gautamb5067272012-07-02 09:53:41 +05301774 dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
1775
1776 if (!atomic_read(&mdwc->in_lpm)) {
1777 dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__);
1778 return 0;
1779 }
1780
Manu Gautam377821c2012-09-28 16:53:24 +05301781 wake_lock(&mdwc->wlock);
1782
Manu Gautam2617deb2012-08-31 17:50:06 -07001783 if (mdwc->bus_perf_client) {
1784 ret = msm_bus_scale_client_update_request(
1785 mdwc->bus_perf_client, 1);
1786 if (ret)
1787 dev_err(mdwc->dev, "Failed to vote for bus scaling\n");
1788 }
1789
Manu Gautam840f4fe2013-04-16 16:50:30 +05301790 dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
1791 (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301792 host_bus_suspend = mdwc->host_mode == 1;
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301793
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301794 if (mdwc->lpm_flags & MDWC3_TCXO_SHUTDOWN) {
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301795 /* Vote for TCXO while waking up USB HSPHY */
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05301796 ret = clk_prepare_enable(mdwc->xo_clk);
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301797 if (ret)
1798 dev_err(mdwc->dev, "%s failed to vote TCXO buffer%d\n",
1799 __func__, ret);
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301800 mdwc->lpm_flags &= ~MDWC3_TCXO_SHUTDOWN;
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301801 }
1802
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301803 if (!host_bus_suspend)
1804 clk_prepare_enable(mdwc->utmi_clk);
1805
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301806 if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
1807 !host_bus_suspend)
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05301808 dwc3_hsusb_ldo_enable(1);
1809
Vijayavardhan Vennapusa6bc06962012-10-31 13:23:38 +05301810 dwc3_ssusb_ldo_enable(1);
1811 dwc3_ssusb_config_vddcx(1);
Jack Pham22698b82013-02-13 17:45:06 -08001812
Manu Gautam840f4fe2013-04-16 16:50:30 +05301813 if (!host_bus_suspend && !dcp)
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301814 dwc3_hsusb_config_vddcx(1);
Jack Pham22698b82013-02-13 17:45:06 -08001815
Manu Gautam3e9ad352012-08-16 14:44:47 -07001816 clk_prepare_enable(mdwc->ref_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05301817 usleep_range(1000, 1200);
1818
Manu Gautam3e9ad352012-08-16 14:44:47 -07001819 clk_prepare_enable(mdwc->iface_clk);
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301820 if (mdwc->lpm_flags & MDWC3_CORECLK_OFF) {
1821 clk_prepare_enable(mdwc->core_clk);
1822 mdwc->lpm_flags &= ~MDWC3_CORECLK_OFF;
1823 }
Manu Gautam377821c2012-09-28 16:53:24 +05301824
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301825 if (host_bus_suspend) {
1826 /* Disable HV interrupt */
1827 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1828 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1829 0x18000, 0x0);
1830 /* Clear interrupt latch register */
1831 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0x000);
Manu Gautam377821c2012-09-28 16:53:24 +05301832
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301833 /* Disable DP and DM HV interrupt */
1834 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
Manu Gautam377821c2012-09-28 16:53:24 +05301835
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301836 /* Clear suspend bit in GUSB2PHYCONFIG register */
1837 dwc3_msm_write_readback(mdwc->base, DWC3_GUSB2PHYCFG(0),
1838 0x40, 0x0);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301839 } else {
1840 /* Disable HV interrupt */
1841 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1842 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1843 0x18000, 0x0);
1844 /* Disable Retention */
1845 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
1846
1847 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
1848 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
1849 0xF0000000);
1850 /* 10usec delay required before de-asserting PHY RESET */
1851 udelay(10);
1852 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
1853 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) &
1854 0x7FFFFFFF);
1855
1856 /* Bring PHY out of suspend */
1857 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000,
1858 0x0);
1859
1860 }
Manu Gautamb5067272012-07-02 09:53:41 +05301861
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05301862 /* Assert SS PHY RESET */
1863 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
1864 (1 << 7));
1865 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
1866 (1 << 28));
1867 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
1868 (1 << 8));
1869 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26), 0x0);
1870 /* 10usec delay required before de-asserting SS PHY RESET */
1871 udelay(10);
1872 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7), 0x0);
1873
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301874 /*
1875 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
1876 * the internal registers to default values.
1877 */
1878 dwc3_msm_ss_phy_reg_init(mdwc);
Manu Gautamb5067272012-07-02 09:53:41 +05301879 atomic_set(&mdwc->in_lpm, 0);
Manu Gautam377821c2012-09-28 16:53:24 +05301880
1881 /* match disable_irq call from isr */
1882 if (mdwc->lpm_irq_seen && mdwc->hs_phy_irq) {
1883 enable_irq(mdwc->hs_phy_irq);
1884 mdwc->lpm_irq_seen = false;
1885 }
Manu Gautam840f4fe2013-04-16 16:50:30 +05301886 /* it must DCP disconnect, re-enable HS_PHY wakeup IRQ */
1887 if (mdwc->hs_phy_irq && dcp)
1888 enable_irq_wake(mdwc->hs_phy_irq);
Manu Gautam377821c2012-09-28 16:53:24 +05301889
Manu Gautamb5067272012-07-02 09:53:41 +05301890 dev_info(mdwc->dev, "DWC3 exited from low power mode\n");
1891
1892 return 0;
1893}
1894
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301895static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc)
1896{
1897 unsigned long t;
1898
1899 /*
1900 * Defer next cable connect event till external charger
1901 * detection is completed.
1902 */
1903
1904 if (mdwc->ext_chg_active && (mdwc->ext_xceiv.bsv ||
1905 !mdwc->ext_xceiv.id)) {
1906
1907 dev_dbg(mdwc->dev, "before ext chg wait\n");
1908
1909 t = wait_for_completion_timeout(&mdwc->ext_chg_wait,
1910 msecs_to_jiffies(3000));
1911 if (!t)
1912 dev_err(mdwc->dev, "ext chg wait timeout\n");
1913 else
1914 dev_dbg(mdwc->dev, "ext chg wait done\n");
1915 }
1916
1917}
1918
Manu Gautamb5067272012-07-02 09:53:41 +05301919static void dwc3_resume_work(struct work_struct *w)
1920{
1921 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
1922 resume_work.work);
1923
1924 dev_dbg(mdwc->dev, "%s: dwc3 resume work\n", __func__);
1925 /* handle any event that was queued while work was already running */
1926 if (!atomic_read(&mdwc->in_lpm)) {
1927 dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301928 if (mdwc->otg_xceiv) {
1929 dwc3_wait_for_ext_chg_done(mdwc);
Manu Gautamb5067272012-07-02 09:53:41 +05301930 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
1931 DWC3_EVENT_XCEIV_STATE);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301932 }
Manu Gautamb5067272012-07-02 09:53:41 +05301933 return;
1934 }
1935
1936 /* bail out if system resume in process, else initiate RESUME */
1937 if (atomic_read(&mdwc->pm_suspended)) {
1938 mdwc->resume_pending = true;
1939 } else {
1940 pm_runtime_get_sync(mdwc->dev);
1941 if (mdwc->otg_xceiv)
1942 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
1943 DWC3_EVENT_PHY_RESUME);
Manu Gautambb825d72013-03-12 16:25:42 +05301944 pm_runtime_put_noidle(mdwc->dev);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301945 if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability)) {
1946 dwc3_wait_for_ext_chg_done(mdwc);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05301947 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
1948 DWC3_EVENT_XCEIV_STATE);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301949 }
Manu Gautamb5067272012-07-02 09:53:41 +05301950 }
1951}
1952
Jack Pham0fc12332012-11-19 13:14:22 -08001953static u32 debug_id = true, debug_bsv, debug_connect;
Manu Gautamb5067272012-07-02 09:53:41 +05301954
1955static int dwc3_connect_show(struct seq_file *s, void *unused)
1956{
1957 if (debug_connect)
1958 seq_printf(s, "true\n");
1959 else
1960 seq_printf(s, "false\n");
1961
1962 return 0;
1963}
1964
1965static int dwc3_connect_open(struct inode *inode, struct file *file)
1966{
1967 return single_open(file, dwc3_connect_show, inode->i_private);
1968}
1969
1970static ssize_t dwc3_connect_write(struct file *file, const char __user *ubuf,
1971 size_t count, loff_t *ppos)
1972{
1973 struct seq_file *s = file->private_data;
1974 struct dwc3_msm *mdwc = s->private;
1975 char buf[8];
1976
1977 memset(buf, 0x00, sizeof(buf));
1978
1979 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
1980 return -EFAULT;
1981
1982 if (!strncmp(buf, "enable", 6) || !strncmp(buf, "true", 4)) {
1983 debug_connect = true;
1984 } else {
1985 debug_connect = debug_bsv = false;
1986 debug_id = true;
1987 }
1988
1989 mdwc->ext_xceiv.bsv = debug_bsv;
1990 mdwc->ext_xceiv.id = debug_id ? DWC3_ID_FLOAT : DWC3_ID_GROUND;
1991
1992 if (atomic_read(&mdwc->in_lpm)) {
1993 dev_dbg(mdwc->dev, "%s: calling resume_work\n", __func__);
1994 dwc3_resume_work(&mdwc->resume_work.work);
1995 } else {
1996 dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
1997 if (mdwc->otg_xceiv)
1998 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
1999 DWC3_EVENT_XCEIV_STATE);
2000 }
2001
2002 return count;
2003}
2004
2005const struct file_operations dwc3_connect_fops = {
2006 .open = dwc3_connect_open,
2007 .read = seq_read,
2008 .write = dwc3_connect_write,
2009 .llseek = seq_lseek,
2010 .release = single_release,
2011};
2012
2013static struct dentry *dwc3_debugfs_root;
2014
2015static void dwc3_debugfs_init(struct dwc3_msm *mdwc)
2016{
2017 dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
2018
2019 if (!dwc3_debugfs_root || IS_ERR(dwc3_debugfs_root))
2020 return;
2021
2022 if (!debugfs_create_bool("id", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
Vijayavardhan Vennapusa54be1d62012-10-06 18:32:06 +05302023 &debug_id))
Manu Gautamb5067272012-07-02 09:53:41 +05302024 goto error;
2025
2026 if (!debugfs_create_bool("bsv", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
Vijayavardhan Vennapusa54be1d62012-10-06 18:32:06 +05302027 &debug_bsv))
Manu Gautamb5067272012-07-02 09:53:41 +05302028 goto error;
2029
2030 if (!debugfs_create_file("connect", S_IRUGO | S_IWUSR,
2031 dwc3_debugfs_root, mdwc, &dwc3_connect_fops))
2032 goto error;
2033
2034 return;
2035
2036error:
2037 debugfs_remove_recursive(dwc3_debugfs_root);
2038}
Manu Gautam8c642812012-06-07 10:35:10 +05302039
Manu Gautam377821c2012-09-28 16:53:24 +05302040static irqreturn_t msm_dwc3_irq(int irq, void *data)
2041{
2042 struct dwc3_msm *mdwc = data;
2043
2044 if (atomic_read(&mdwc->in_lpm)) {
2045 dev_dbg(mdwc->dev, "%s received in LPM\n", __func__);
2046 mdwc->lpm_irq_seen = true;
2047 disable_irq_nosync(irq);
2048 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
2049 } else {
2050 pr_info_ratelimited("%s: IRQ outside LPM\n", __func__);
2051 }
2052
2053 return IRQ_HANDLED;
2054}
2055
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302056static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
2057 enum power_supply_property psp,
2058 union power_supply_propval *val)
2059{
2060 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
2061 usb_psy);
2062 switch (psp) {
2063 case POWER_SUPPLY_PROP_SCOPE:
2064 val->intval = mdwc->host_mode;
2065 break;
2066 case POWER_SUPPLY_PROP_CURRENT_MAX:
2067 val->intval = mdwc->current_max;
2068 break;
2069 case POWER_SUPPLY_PROP_PRESENT:
2070 val->intval = mdwc->vbus_active;
2071 break;
2072 case POWER_SUPPLY_PROP_ONLINE:
2073 val->intval = mdwc->online;
2074 break;
Manu Gautamfa40cae2013-03-01 16:37:12 +05302075 case POWER_SUPPLY_PROP_TYPE:
2076 val->intval = psy->type;
2077 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302078 default:
2079 return -EINVAL;
2080 }
2081 return 0;
2082}
2083
2084static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
2085 enum power_supply_property psp,
2086 const union power_supply_propval *val)
2087{
2088 static bool init;
2089 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
2090 usb_psy);
2091
2092 switch (psp) {
2093 case POWER_SUPPLY_PROP_SCOPE:
2094 mdwc->host_mode = val->intval;
2095 break;
2096 /* Process PMIC notification in PRESENT prop */
2097 case POWER_SUPPLY_PROP_PRESENT:
2098 dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
Jack Pham9354c6a2012-12-20 19:19:32 -08002099 if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
2100 (mdwc->ext_xceiv.otg_capability || !init)) {
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302101 mdwc->ext_xceiv.bsv = val->intval;
Manu Gautamf71d9cb2013-02-07 13:52:12 +05302102 queue_delayed_work(system_nrt_wq,
Jack Pham4d91aab2013-03-08 10:02:16 -08002103 &mdwc->resume_work, 20);
Jack Pham9354c6a2012-12-20 19:19:32 -08002104
2105 if (!init)
2106 init = true;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302107 }
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302108 mdwc->vbus_active = val->intval;
2109 break;
2110 case POWER_SUPPLY_PROP_ONLINE:
2111 mdwc->online = val->intval;
2112 break;
2113 case POWER_SUPPLY_PROP_CURRENT_MAX:
2114 mdwc->current_max = val->intval;
2115 break;
Manu Gautamfa40cae2013-03-01 16:37:12 +05302116 case POWER_SUPPLY_PROP_TYPE:
2117 psy->type = val->intval;
2118 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302119 default:
2120 return -EINVAL;
2121 }
2122
2123 power_supply_changed(&mdwc->usb_psy);
2124 return 0;
2125}
2126
Jack Pham9354c6a2012-12-20 19:19:32 -08002127static void dwc3_msm_external_power_changed(struct power_supply *psy)
2128{
2129 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm, usb_psy);
2130 union power_supply_propval ret = {0,};
2131
2132 if (!mdwc->ext_vbus_psy)
2133 mdwc->ext_vbus_psy = power_supply_get_by_name("ext-vbus");
2134
2135 if (!mdwc->ext_vbus_psy) {
2136 pr_err("%s: Unable to get ext_vbus power_supply\n", __func__);
2137 return;
2138 }
2139
2140 mdwc->ext_vbus_psy->get_property(mdwc->ext_vbus_psy,
2141 POWER_SUPPLY_PROP_ONLINE, &ret);
2142 if (ret.intval) {
2143 dwc3_start_chg_det(&mdwc->charger, false);
2144 mdwc->ext_vbus_psy->get_property(mdwc->ext_vbus_psy,
2145 POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
2146 power_supply_set_current_limit(&mdwc->usb_psy, ret.intval);
2147 }
2148
2149 power_supply_set_online(&mdwc->usb_psy, ret.intval);
2150 power_supply_changed(&mdwc->usb_psy);
2151}
2152
2153
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302154static char *dwc3_msm_pm_power_supplied_to[] = {
2155 "battery",
2156};
2157
2158static enum power_supply_property dwc3_msm_pm_power_props_usb[] = {
2159 POWER_SUPPLY_PROP_PRESENT,
2160 POWER_SUPPLY_PROP_ONLINE,
2161 POWER_SUPPLY_PROP_CURRENT_MAX,
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302162 POWER_SUPPLY_PROP_TYPE,
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302163 POWER_SUPPLY_PROP_SCOPE,
2164};
2165
Jack Phamfadd6432012-12-07 19:03:41 -08002166static void dwc3_init_adc_work(struct work_struct *w);
2167
2168static void dwc3_ext_notify_online(int on)
2169{
2170 struct dwc3_msm *mdwc = context;
Jack Phamf12b7e12012-12-28 14:27:26 -08002171 bool notify_otg = false;
Jack Phamfadd6432012-12-07 19:03:41 -08002172
2173 if (!mdwc) {
2174 pr_err("%s: DWC3 driver already removed\n", __func__);
2175 return;
2176 }
2177
2178 dev_dbg(mdwc->dev, "notify %s%s\n", on ? "" : "dis", "connected");
2179
Jack Pham9354c6a2012-12-20 19:19:32 -08002180 if (!mdwc->ext_vbus_psy)
2181 mdwc->ext_vbus_psy = power_supply_get_by_name("ext-vbus");
2182
2183 mdwc->ext_inuse = on;
Jack Phamf12b7e12012-12-28 14:27:26 -08002184 if (on) {
2185 /* force OTG to exit B-peripheral state */
2186 mdwc->ext_xceiv.bsv = false;
2187 notify_otg = true;
Jack Pham9354c6a2012-12-20 19:19:32 -08002188 dwc3_start_chg_det(&mdwc->charger, false);
Jack Phamf12b7e12012-12-28 14:27:26 -08002189 } else {
2190 /* external client offline; tell OTG about cached ID/BSV */
2191 if (mdwc->ext_xceiv.id != mdwc->id_state) {
2192 mdwc->ext_xceiv.id = mdwc->id_state;
2193 notify_otg = true;
2194 }
2195
2196 mdwc->ext_xceiv.bsv = mdwc->vbus_active;
2197 notify_otg |= mdwc->vbus_active;
2198 }
Jack Pham9354c6a2012-12-20 19:19:32 -08002199
2200 if (mdwc->ext_vbus_psy)
2201 power_supply_set_present(mdwc->ext_vbus_psy, on);
Jack Phamf12b7e12012-12-28 14:27:26 -08002202
2203 if (notify_otg)
2204 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
Jack Phamfadd6432012-12-07 19:03:41 -08002205}
2206
Jack Pham0cca9412013-03-08 13:22:42 -08002207static void dwc3_id_work(struct work_struct *w)
Jack Phamfadd6432012-12-07 19:03:41 -08002208{
Jack Pham0cca9412013-03-08 13:22:42 -08002209 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, id_work);
Jack Pham5c585062013-03-25 18:39:12 -07002210 int ret;
Jack Phamfadd6432012-12-07 19:03:41 -08002211
Jack Pham0cca9412013-03-08 13:22:42 -08002212 /* Give external client a chance to handle */
Jack Pham5c585062013-03-25 18:39:12 -07002213 if (!mdwc->ext_inuse && usb_ext) {
2214 if (mdwc->pmic_id_irq)
2215 disable_irq(mdwc->pmic_id_irq);
2216
2217 ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
2218 dwc3_ext_notify_online);
2219 dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
2220 __func__, ret);
2221
2222 if (mdwc->pmic_id_irq) {
2223 /* ID may have changed while IRQ disabled; update it */
2224 mdwc->id_state = !!irq_read_line(mdwc->pmic_id_irq);
2225 enable_irq(mdwc->pmic_id_irq);
Jack Pham0cca9412013-03-08 13:22:42 -08002226 }
Jack Pham5c585062013-03-25 18:39:12 -07002227
2228 mdwc->ext_inuse = (ret == 0);
Jack Pham0cca9412013-03-08 13:22:42 -08002229 }
Jack Phamfadd6432012-12-07 19:03:41 -08002230
Jack Pham0cca9412013-03-08 13:22:42 -08002231 if (!mdwc->ext_inuse) { /* notify OTG */
2232 mdwc->ext_xceiv.id = mdwc->id_state;
2233 dwc3_resume_work(&mdwc->resume_work.work);
2234 }
2235}
2236
2237static irqreturn_t dwc3_pmic_id_irq(int irq, void *data)
2238{
2239 struct dwc3_msm *mdwc = data;
Jack Pham5c585062013-03-25 18:39:12 -07002240 enum dwc3_id_state id;
Jack Pham0cca9412013-03-08 13:22:42 -08002241
2242 /* If we can't read ID line state for some reason, treat it as float */
Jack Pham5c585062013-03-25 18:39:12 -07002243 id = !!irq_read_line(irq);
2244 if (mdwc->id_state != id) {
2245 mdwc->id_state = id;
2246 queue_work(system_nrt_wq, &mdwc->id_work);
2247 }
Jack Pham0cca9412013-03-08 13:22:42 -08002248
2249 return IRQ_HANDLED;
Jack Phamfadd6432012-12-07 19:03:41 -08002250}
2251
Jack Pham0fc12332012-11-19 13:14:22 -08002252static void dwc3_adc_notification(enum qpnp_tm_state state, void *ctx)
2253{
2254 struct dwc3_msm *mdwc = ctx;
2255
2256 if (state >= ADC_TM_STATE_NUM) {
2257 pr_err("%s: invalid notification %d\n", __func__, state);
2258 return;
2259 }
2260
2261 dev_dbg(mdwc->dev, "%s: state = %s\n", __func__,
2262 state == ADC_TM_HIGH_STATE ? "high" : "low");
2263
Jack Phamf12b7e12012-12-28 14:27:26 -08002264 /* save ID state, but don't necessarily notify OTG */
Jack Pham0fc12332012-11-19 13:14:22 -08002265 if (state == ADC_TM_HIGH_STATE) {
Jack Phamf12b7e12012-12-28 14:27:26 -08002266 mdwc->id_state = DWC3_ID_FLOAT;
Jack Pham0fc12332012-11-19 13:14:22 -08002267 mdwc->adc_param.state_request = ADC_TM_LOW_THR_ENABLE;
2268 } else {
Jack Phamf12b7e12012-12-28 14:27:26 -08002269 mdwc->id_state = DWC3_ID_GROUND;
Jack Pham0fc12332012-11-19 13:14:22 -08002270 mdwc->adc_param.state_request = ADC_TM_HIGH_THR_ENABLE;
2271 }
2272
Jack Pham0cca9412013-03-08 13:22:42 -08002273 dwc3_id_work(&mdwc->id_work);
2274
Jack Phamfadd6432012-12-07 19:03:41 -08002275 /* re-arm ADC interrupt */
Jack Pham0fc12332012-11-19 13:14:22 -08002276 qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
2277}
2278
2279static void dwc3_init_adc_work(struct work_struct *w)
2280{
2281 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
2282 init_adc_work.work);
2283 int ret;
2284
2285 ret = qpnp_adc_tm_is_ready();
2286 if (ret == -EPROBE_DEFER) {
Jack Pham90b4d122012-12-13 11:46:22 -08002287 queue_delayed_work(system_nrt_wq, to_delayed_work(w),
2288 msecs_to_jiffies(100));
Jack Pham0fc12332012-11-19 13:14:22 -08002289 return;
2290 }
2291
2292 mdwc->adc_param.low_thr = adc_low_threshold;
2293 mdwc->adc_param.high_thr = adc_high_threshold;
2294 mdwc->adc_param.timer_interval = adc_meas_interval;
2295 mdwc->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08002296 mdwc->adc_param.btm_ctx = mdwc;
Jack Pham0fc12332012-11-19 13:14:22 -08002297 mdwc->adc_param.threshold_notification = dwc3_adc_notification;
2298
2299 ret = qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
2300 if (ret) {
2301 dev_err(mdwc->dev, "%s: request ADC error %d\n", __func__, ret);
2302 return;
2303 }
2304
2305 mdwc->id_adc_detect = true;
2306}
2307
2308static ssize_t adc_enable_show(struct device *dev,
2309 struct device_attribute *attr, char *buf)
2310{
2311 return snprintf(buf, PAGE_SIZE, "%s\n", context->id_adc_detect ?
2312 "enabled" : "disabled");
2313}
2314
2315static ssize_t adc_enable_store(struct device *dev,
2316 struct device_attribute *attr, const char
2317 *buf, size_t size)
2318{
2319 if (!strnicmp(buf, "enable", 6)) {
2320 if (!context->id_adc_detect)
2321 dwc3_init_adc_work(&context->init_adc_work.work);
2322 return size;
2323 } else if (!strnicmp(buf, "disable", 7)) {
2324 qpnp_adc_tm_usbid_end();
2325 context->id_adc_detect = false;
2326 return size;
2327 }
2328
2329 return -EINVAL;
2330}
2331
2332static DEVICE_ATTR(adc_enable, S_IRUGO | S_IWUSR, adc_enable_show,
2333 adc_enable_store);
2334
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302335static int dwc3_msm_ext_chg_open(struct inode *inode, struct file *file)
2336{
2337 struct dwc3_msm *mdwc = context;
2338
2339 pr_debug("dwc3-msm ext chg open\n");
2340
2341 mdwc->ext_chg_opened = true;
2342 return 0;
2343}
2344
2345static ssize_t
2346dwc3_msm_ext_chg_write(struct file *file, const char __user *ubuf,
2347 size_t size, loff_t *pos)
2348{
2349 struct dwc3_msm *mdwc = context;
2350 char kbuf[16];
2351
2352 memset(kbuf, 0x00, sizeof(kbuf));
2353 if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, size)))
2354 return -EFAULT;
2355
2356 pr_debug("%s: buf = %s\n", __func__, kbuf);
2357
2358 if (!strncmp(kbuf, "enable", 6)) {
2359 pr_info("%s: on\n", __func__);
2360 if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
2361 pm_runtime_get_sync(mdwc->dev);
2362 } else {
2363 mdwc->ext_chg_active = false;
2364 complete(&mdwc->ext_chg_wait);
2365 return -ENODEV;
2366 }
2367 } else if (!strncmp(kbuf, "disable", 7)) {
2368 pr_info("%s: off\n", __func__);
2369 mdwc->ext_chg_active = false;
2370 complete(&mdwc->ext_chg_wait);
2371 pm_runtime_put(mdwc->dev);
2372 } else {
2373 return -EINVAL;
2374 }
2375
2376 return size;
2377}
2378
2379static int dwc3_msm_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
2380{
2381 unsigned long vsize = vma->vm_end - vma->vm_start;
2382 int ret;
2383
2384 pr_debug("%s: size = %lu %x\n", __func__, vsize, (int) vma->vm_pgoff);
2385
2386 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
2387
2388 ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
2389 vsize, vma->vm_page_prot);
2390 if (ret < 0)
2391 pr_err("%s: failed with return val %d\n", __func__, ret);
2392
2393 return ret;
2394}
2395
2396static int dwc3_msm_ext_chg_release(struct inode *inode, struct file *file)
2397{
2398 struct dwc3_msm *mdwc = context;
2399
2400 pr_debug("dwc3-msm ext chg release\n");
2401
2402 mdwc->ext_chg_opened = false;
2403
2404 return 0;
2405}
2406
2407static const struct file_operations dwc3_msm_ext_chg_fops = {
2408 .owner = THIS_MODULE,
2409 .open = dwc3_msm_ext_chg_open,
2410 .write = dwc3_msm_ext_chg_write,
2411 .mmap = dwc3_msm_ext_chg_mmap,
2412 .release = dwc3_msm_ext_chg_release,
2413};
2414
2415static int dwc3_msm_setup_cdev(struct dwc3_msm *mdwc)
2416{
2417 int ret;
2418
2419 ret = alloc_chrdev_region(&mdwc->ext_chg_dev, 0, 1, "usb_ext_chg");
2420 if (ret < 0) {
2421 pr_err("Fail to allocate usb ext char dev region\n");
2422 return ret;
2423 }
2424 mdwc->ext_chg_class = class_create(THIS_MODULE, "dwc_ext_chg");
2425 if (ret < 0) {
2426 pr_err("Fail to create usb ext chg class\n");
2427 goto unreg_chrdev;
2428 }
2429 cdev_init(&mdwc->ext_chg_cdev, &dwc3_msm_ext_chg_fops);
2430 mdwc->ext_chg_cdev.owner = THIS_MODULE;
2431
2432 ret = cdev_add(&mdwc->ext_chg_cdev, mdwc->ext_chg_dev, 1);
2433 if (ret < 0) {
2434 pr_err("Fail to add usb ext chg cdev\n");
2435 goto destroy_class;
2436 }
2437 mdwc->ext_chg_device = device_create(mdwc->ext_chg_class,
2438 NULL, mdwc->ext_chg_dev, NULL,
2439 "usb_ext_chg");
2440 if (IS_ERR(mdwc->ext_chg_device)) {
2441 pr_err("Fail to create usb ext chg device\n");
2442 ret = PTR_ERR(mdwc->ext_chg_device);
2443 mdwc->ext_chg_device = NULL;
2444 goto del_cdev;
2445 }
2446
2447 pr_debug("dwc3 msm ext chg cdev setup success\n");
2448 return 0;
2449
2450del_cdev:
2451 cdev_del(&mdwc->ext_chg_cdev);
2452destroy_class:
2453 class_destroy(mdwc->ext_chg_class);
2454unreg_chrdev:
2455 unregister_chrdev_region(mdwc->ext_chg_dev, 1);
2456
2457 return ret;
2458}
2459
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002460static int __devinit dwc3_msm_probe(struct platform_device *pdev)
2461{
2462 struct device_node *node = pdev->dev.of_node;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002463 struct dwc3_msm *msm;
2464 struct resource *res;
Ido Shayevitz7ad8ded2012-08-28 04:30:58 +03002465 void __iomem *tcsr;
Manu Gautamf08f7b62013-04-02 16:09:42 +05302466 unsigned long flags;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002467 int ret = 0;
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302468 int len = 0;
2469 u32 tmp[3];
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002470
2471 msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
2472 if (!msm) {
2473 dev_err(&pdev->dev, "not enough memory\n");
2474 return -ENOMEM;
2475 }
2476
2477 platform_set_drvdata(pdev, msm);
Ido Shayevitz9fb83452012-04-01 17:45:58 +03002478 context = msm;
Manu Gautam60e01352012-05-29 09:00:34 +05302479 msm->dev = &pdev->dev;
Ido Shayevitz9fb83452012-04-01 17:45:58 +03002480
2481 INIT_LIST_HEAD(&msm->req_complete_list);
Manu Gautam8c642812012-06-07 10:35:10 +05302482 INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
Manu Gautamb5067272012-07-02 09:53:41 +05302483 INIT_DELAYED_WORK(&msm->resume_work, dwc3_resume_work);
Manu Gautam6eb13e32013-02-01 15:19:15 +05302484 INIT_WORK(&msm->restart_usb_work, dwc3_restart_usb_work);
Jack Pham0cca9412013-03-08 13:22:42 -08002485 INIT_WORK(&msm->id_work, dwc3_id_work);
Jack Pham0fc12332012-11-19 13:14:22 -08002486 INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302487 init_completion(&msm->ext_chg_wait);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002488
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302489 msm->xo_clk = clk_get(&pdev->dev, "xo");
2490 if (IS_ERR(msm->xo_clk)) {
Manu Gautam377821c2012-09-28 16:53:24 +05302491 dev_err(&pdev->dev, "%s unable to get TCXO buffer handle\n",
2492 __func__);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302493 return PTR_ERR(msm->xo_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05302494 }
2495
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302496 ret = clk_prepare_enable(msm->xo_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05302497 if (ret) {
2498 dev_err(&pdev->dev, "%s failed to vote for TCXO buffer%d\n",
2499 __func__, ret);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302500 goto put_xo;
Manu Gautam377821c2012-09-28 16:53:24 +05302501 }
2502
Manu Gautam1742db22012-06-19 13:33:24 +05302503 /*
2504 * DWC3 Core requires its CORE CLK (aka master / bus clk) to
2505 * run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
2506 */
2507 msm->core_clk = devm_clk_get(&pdev->dev, "core_clk");
2508 if (IS_ERR(msm->core_clk)) {
2509 dev_err(&pdev->dev, "failed to get core_clk\n");
Manu Gautam377821c2012-09-28 16:53:24 +05302510 ret = PTR_ERR(msm->core_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302511 goto disable_xo;
Manu Gautam1742db22012-06-19 13:33:24 +05302512 }
2513 clk_set_rate(msm->core_clk, 125000000);
2514 clk_prepare_enable(msm->core_clk);
2515
Manu Gautam3e9ad352012-08-16 14:44:47 -07002516 msm->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
2517 if (IS_ERR(msm->iface_clk)) {
2518 dev_err(&pdev->dev, "failed to get iface_clk\n");
2519 ret = PTR_ERR(msm->iface_clk);
2520 goto disable_core_clk;
2521 }
2522 clk_prepare_enable(msm->iface_clk);
2523
2524 msm->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
2525 if (IS_ERR(msm->sleep_clk)) {
2526 dev_err(&pdev->dev, "failed to get sleep_clk\n");
2527 ret = PTR_ERR(msm->sleep_clk);
2528 goto disable_iface_clk;
2529 }
2530 clk_prepare_enable(msm->sleep_clk);
2531
2532 msm->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
2533 if (IS_ERR(msm->hsphy_sleep_clk)) {
2534 dev_err(&pdev->dev, "failed to get sleep_a_clk\n");
2535 ret = PTR_ERR(msm->hsphy_sleep_clk);
2536 goto disable_sleep_clk;
2537 }
2538 clk_prepare_enable(msm->hsphy_sleep_clk);
2539
Jack Pham22698b82013-02-13 17:45:06 -08002540 msm->utmi_clk = devm_clk_get(&pdev->dev, "utmi_clk");
2541 if (IS_ERR(msm->utmi_clk)) {
2542 dev_err(&pdev->dev, "failed to get utmi_clk\n");
2543 ret = PTR_ERR(msm->utmi_clk);
2544 goto disable_sleep_a_clk;
2545 }
2546 clk_prepare_enable(msm->utmi_clk);
2547
Manu Gautam3e9ad352012-08-16 14:44:47 -07002548 msm->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
2549 if (IS_ERR(msm->ref_clk)) {
2550 dev_err(&pdev->dev, "failed to get ref_clk\n");
2551 ret = PTR_ERR(msm->ref_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002552 goto disable_utmi_clk;
Manu Gautam3e9ad352012-08-16 14:44:47 -07002553 }
2554 clk_prepare_enable(msm->ref_clk);
2555
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302556 of_get_property(node, "qcom,vdd-voltage-level", &len);
2557 if (len == sizeof(tmp)) {
2558 of_property_read_u32_array(node, "qcom,vdd-voltage-level",
2559 tmp, len/sizeof(*tmp));
2560 msm->vdd_no_vol_level = tmp[0];
2561 msm->vdd_low_vol_level = tmp[1];
2562 msm->vdd_high_vol_level = tmp[2];
2563 } else {
2564 dev_err(&pdev->dev, "no qcom,vdd-voltage-level property\n");
2565 ret = -EINVAL;
2566 goto disable_ref_clk;
2567 }
2568
Manu Gautam60e01352012-05-29 09:00:34 +05302569 /* SS PHY */
Manu Gautam60e01352012-05-29 09:00:34 +05302570 msm->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
2571 if (IS_ERR(msm->ssusb_vddcx)) {
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302572 dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
2573 ret = PTR_ERR(msm->ssusb_vddcx);
2574 goto disable_ref_clk;
Manu Gautam60e01352012-05-29 09:00:34 +05302575 }
2576
2577 ret = dwc3_ssusb_config_vddcx(1);
2578 if (ret) {
2579 dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
Manu Gautam3e9ad352012-08-16 14:44:47 -07002580 goto disable_ref_clk;
Manu Gautam60e01352012-05-29 09:00:34 +05302581 }
2582
2583 ret = regulator_enable(context->ssusb_vddcx);
2584 if (ret) {
2585 dev_err(&pdev->dev, "unable to enable the ssusb vddcx\n");
2586 goto unconfig_ss_vddcx;
2587 }
2588
2589 ret = dwc3_ssusb_ldo_init(1);
2590 if (ret) {
2591 dev_err(&pdev->dev, "ssusb vreg configuration failed\n");
2592 goto disable_ss_vddcx;
2593 }
2594
2595 ret = dwc3_ssusb_ldo_enable(1);
2596 if (ret) {
2597 dev_err(&pdev->dev, "ssusb vreg enable failed\n");
2598 goto free_ss_ldo_init;
2599 }
2600
2601 /* HS PHY */
Manu Gautam60e01352012-05-29 09:00:34 +05302602 msm->hsusb_vddcx = devm_regulator_get(&pdev->dev, "hsusb_vdd_dig");
2603 if (IS_ERR(msm->hsusb_vddcx)) {
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302604 dev_err(&pdev->dev, "unable to get hsusb vddcx\n");
2605 ret = PTR_ERR(msm->hsusb_vddcx);
2606 goto disable_ss_ldo;
Manu Gautam60e01352012-05-29 09:00:34 +05302607 }
2608
2609 ret = dwc3_hsusb_config_vddcx(1);
2610 if (ret) {
2611 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
2612 goto disable_ss_ldo;
2613 }
2614
2615 ret = regulator_enable(context->hsusb_vddcx);
2616 if (ret) {
2617 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
2618 goto unconfig_hs_vddcx;
2619 }
2620
2621 ret = dwc3_hsusb_ldo_init(1);
2622 if (ret) {
2623 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
2624 goto disable_hs_vddcx;
2625 }
2626
2627 ret = dwc3_hsusb_ldo_enable(1);
2628 if (ret) {
2629 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
2630 goto free_hs_ldo_init;
2631 }
2632
Jack Pham5c585062013-03-25 18:39:12 -07002633 msm->id_state = msm->ext_xceiv.id = DWC3_ID_FLOAT;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302634 msm->ext_xceiv.otg_capability = of_property_read_bool(node,
Manu Gautam6c0ff032012-11-02 14:55:35 +05302635 "qcom,otg-capability");
2636 msm->charger.charging_disabled = of_property_read_bool(node,
2637 "qcom,charging-disabled");
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302638
Hemant Kumar6d7b7242013-04-18 16:44:38 -07002639 msm->charger.skip_chg_detect = of_property_read_bool(node,
2640 "qcom,skip-charger-detection");
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302641 /*
2642 * DWC3 has separate IRQ line for OTG events (ID/BSV) and for
2643 * DP and DM linestate transitions during low power mode.
2644 */
2645 msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
2646 if (msm->hs_phy_irq < 0) {
2647 dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
2648 msm->hs_phy_irq = 0;
Jack Pham0fc12332012-11-19 13:14:22 -08002649 } else {
Jack Pham56a0a632013-03-08 13:18:42 -08002650 ret = devm_request_irq(&pdev->dev, msm->hs_phy_irq,
2651 msm_dwc3_irq, IRQF_TRIGGER_RISING,
2652 "msm_dwc3", msm);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302653 if (ret) {
2654 dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
2655 goto disable_hs_ldo;
2656 }
2657 enable_irq_wake(msm->hs_phy_irq);
2658 }
Jack Pham0cca9412013-03-08 13:22:42 -08002659
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302660 if (msm->ext_xceiv.otg_capability) {
Jack Pham0cca9412013-03-08 13:22:42 -08002661 msm->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
2662 if (msm->pmic_id_irq > 0) {
David Keitelad4a0282013-03-19 18:04:27 -07002663 /* check if PMIC ID IRQ is supported */
2664 ret = qpnp_misc_irqs_available(&pdev->dev);
2665
2666 if (ret == -EPROBE_DEFER) {
2667 /* qpnp hasn't probed yet; defer dwc probe */
Jack Pham0cca9412013-03-08 13:22:42 -08002668 goto disable_hs_ldo;
David Keitelad4a0282013-03-19 18:04:27 -07002669 } else if (ret == 0) {
2670 msm->pmic_id_irq = 0;
2671 } else {
2672 ret = devm_request_irq(&pdev->dev,
2673 msm->pmic_id_irq,
2674 dwc3_pmic_id_irq,
2675 IRQF_TRIGGER_RISING |
2676 IRQF_TRIGGER_FALLING,
2677 "dwc3_msm_pmic_id", msm);
2678 if (ret) {
2679 dev_err(&pdev->dev, "irqreq IDINT failed\n");
2680 goto disable_hs_ldo;
2681 }
Jack Pham9198d9f2013-04-09 17:54:54 -07002682
Manu Gautamf08f7b62013-04-02 16:09:42 +05302683 local_irq_save(flags);
2684 /* Update initial ID state */
Jack Pham9198d9f2013-04-09 17:54:54 -07002685 msm->id_state =
Manu Gautamf08f7b62013-04-02 16:09:42 +05302686 !!irq_read_line(msm->pmic_id_irq);
Jack Pham9198d9f2013-04-09 17:54:54 -07002687 if (msm->id_state == DWC3_ID_GROUND)
2688 queue_work(system_nrt_wq,
2689 &msm->id_work);
Manu Gautamf08f7b62013-04-02 16:09:42 +05302690 local_irq_restore(flags);
David Keitelad4a0282013-03-19 18:04:27 -07002691 enable_irq_wake(msm->pmic_id_irq);
Jack Pham0cca9412013-03-08 13:22:42 -08002692 }
David Keitelad4a0282013-03-19 18:04:27 -07002693 }
2694
2695 if (msm->pmic_id_irq <= 0) {
Jack Pham0cca9412013-03-08 13:22:42 -08002696 /* If no PMIC ID IRQ, use ADC for ID pin detection */
2697 queue_work(system_nrt_wq, &msm->init_adc_work.work);
2698 device_create_file(&pdev->dev, &dev_attr_adc_enable);
2699 msm->pmic_id_irq = 0;
2700 }
Manu Gautam377821c2012-09-28 16:53:24 +05302701 }
2702
Ido Shayevitz7ad8ded2012-08-28 04:30:58 +03002703 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2704 if (!res) {
2705 dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
2706 } else {
2707 tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
2708 resource_size(res));
2709 if (!tcsr) {
2710 dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
2711 } else {
2712 /* Enable USB3 on the primary USB port. */
2713 writel_relaxed(0x1, tcsr);
2714 /*
2715 * Ensure that TCSR write is completed before
2716 * USB registers initialization.
2717 */
2718 mb();
2719 }
2720 }
2721
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002722 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2723 if (!res) {
2724 dev_err(&pdev->dev, "missing memory base resource\n");
Manu Gautam60e01352012-05-29 09:00:34 +05302725 ret = -ENODEV;
Jack Pham56a0a632013-03-08 13:18:42 -08002726 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002727 }
2728
2729 msm->base = devm_ioremap_nocache(&pdev->dev, res->start,
2730 resource_size(res));
2731 if (!msm->base) {
2732 dev_err(&pdev->dev, "ioremap failed\n");
Manu Gautam60e01352012-05-29 09:00:34 +05302733 ret = -ENODEV;
Jack Pham56a0a632013-03-08 13:18:42 -08002734 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002735 }
2736
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002737 msm->resource_size = resource_size(res);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002738
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +05302739 if (of_property_read_u32(node, "qcom,dwc-hsphy-init",
2740 &msm->hsphy_init_seq))
2741 dev_dbg(&pdev->dev, "unable to read hsphy init seq\n");
2742 else if (!msm->hsphy_init_seq)
2743 dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
2744
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05302745 dwc3_msm_qscratch_reg_init(msm);
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +05302746
Manu Gautamb5067272012-07-02 09:53:41 +05302747 pm_runtime_set_active(msm->dev);
Manu Gautam377821c2012-09-28 16:53:24 +05302748 pm_runtime_enable(msm->dev);
Manu Gautamb5067272012-07-02 09:53:41 +05302749
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002750 if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
2751 &msm->dbm_num_eps)) {
2752 dev_err(&pdev->dev,
2753 "unable to read platform data num of dbm eps\n");
2754 msm->dbm_num_eps = DBM_MAX_EPS;
2755 }
2756
2757 if (msm->dbm_num_eps > DBM_MAX_EPS) {
2758 dev_err(&pdev->dev,
2759 "Driver doesn't support number of DBM EPs. "
2760 "max: %d, dbm_num_eps: %d\n",
2761 DBM_MAX_EPS, msm->dbm_num_eps);
2762 ret = -ENODEV;
Vijayavardhan Vennapusa8eb68732013-03-26 13:05:38 +05302763 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002764 }
2765
Manu Gautambb825d72013-03-12 16:25:42 +05302766 /* usb_psy required only for vbus_notifications or charging support */
2767 if (msm->ext_xceiv.otg_capability || !msm->charger.charging_disabled) {
2768 msm->usb_psy.name = "usb";
2769 msm->usb_psy.type = POWER_SUPPLY_TYPE_USB;
2770 msm->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
2771 msm->usb_psy.num_supplicants = ARRAY_SIZE(
2772 dwc3_msm_pm_power_supplied_to);
2773 msm->usb_psy.properties = dwc3_msm_pm_power_props_usb;
2774 msm->usb_psy.num_properties =
2775 ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
2776 msm->usb_psy.get_property = dwc3_msm_power_get_property_usb;
2777 msm->usb_psy.set_property = dwc3_msm_power_set_property_usb;
2778 msm->usb_psy.external_power_changed =
2779 dwc3_msm_external_power_changed;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302780
Manu Gautambb825d72013-03-12 16:25:42 +05302781 ret = power_supply_register(&pdev->dev, &msm->usb_psy);
2782 if (ret < 0) {
2783 dev_err(&pdev->dev,
2784 "%s:power_supply_register usb failed\n",
2785 __func__);
2786 goto disable_hs_ldo;
2787 }
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302788 }
2789
Vijayavardhan Vennapusa8eb68732013-03-26 13:05:38 +05302790 if (node) {
2791 ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
2792 if (ret) {
2793 dev_err(&pdev->dev,
2794 "failed to add create dwc3 core\n");
2795 goto put_psupply;
2796 }
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002797 }
2798
Manu Gautam2617deb2012-08-31 17:50:06 -07002799 msm->bus_scale_table = msm_bus_cl_get_pdata(pdev);
2800 if (!msm->bus_scale_table) {
2801 dev_err(&pdev->dev, "bus scaling is disabled\n");
2802 } else {
2803 msm->bus_perf_client =
2804 msm_bus_scale_register_client(msm->bus_scale_table);
2805 ret = msm_bus_scale_client_update_request(
2806 msm->bus_perf_client, 1);
2807 if (ret)
2808 dev_err(&pdev->dev, "Failed to vote for bus scaling\n");
2809 }
2810
Manu Gautam8c642812012-06-07 10:35:10 +05302811 msm->otg_xceiv = usb_get_transceiver();
Manu Gautambb825d72013-03-12 16:25:42 +05302812 /* Register with OTG if present, ignore USB2 OTG using other PHY */
2813 if (msm->otg_xceiv && !(msm->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
Hemant Kumar6d7b7242013-04-18 16:44:38 -07002814 /* Skip charger detection for simulator targets */
2815 if (!msm->charger.skip_chg_detect) {
2816 msm->charger.start_detection = dwc3_start_chg_det;
2817 ret = dwc3_set_charger(msm->otg_xceiv->otg,
2818 &msm->charger);
2819 if (ret || !msm->charger.notify_detection_complete) {
2820 dev_err(&pdev->dev,
2821 "failed to register charger: %d\n",
2822 ret);
2823 goto put_xcvr;
2824 }
Manu Gautam8c642812012-06-07 10:35:10 +05302825 }
Manu Gautamb5067272012-07-02 09:53:41 +05302826
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05302827 if (msm->ext_xceiv.otg_capability)
2828 msm->ext_xceiv.ext_block_reset = dwc3_msm_block_reset;
Manu Gautamb5067272012-07-02 09:53:41 +05302829 ret = dwc3_set_ext_xceiv(msm->otg_xceiv->otg, &msm->ext_xceiv);
2830 if (ret || !msm->ext_xceiv.notify_ext_events) {
2831 dev_err(&pdev->dev, "failed to register xceiver: %d\n",
2832 ret);
2833 goto put_xcvr;
2834 }
Manu Gautam8c642812012-06-07 10:35:10 +05302835 } else {
Manu Gautambb825d72013-03-12 16:25:42 +05302836 dev_dbg(&pdev->dev, "No OTG, DWC3 running in host only mode\n");
2837 msm->host_mode = 1;
2838 msm->vbus_otg = devm_regulator_get(&pdev->dev, "vbus_dwc3");
2839 if (IS_ERR(msm->vbus_otg)) {
2840 dev_dbg(&pdev->dev, "Failed to get vbus regulator\n");
2841 msm->vbus_otg = 0;
2842 } else {
2843 ret = regulator_enable(msm->vbus_otg);
2844 if (ret) {
2845 msm->vbus_otg = 0;
2846 dev_err(&pdev->dev, "Failed to enable vbus_otg\n");
2847 }
2848 }
2849 msm->otg_xceiv = NULL;
Manu Gautam8c642812012-06-07 10:35:10 +05302850 }
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302851 if (msm->ext_xceiv.otg_capability && msm->charger.start_detection) {
2852 ret = dwc3_msm_setup_cdev(msm);
2853 if (ret)
2854 dev_err(&pdev->dev, "Fail to setup dwc3 setup cdev\n");
2855 }
Manu Gautam8c642812012-06-07 10:35:10 +05302856
Manu Gautamb5067272012-07-02 09:53:41 +05302857 wake_lock_init(&msm->wlock, WAKE_LOCK_SUSPEND, "msm_dwc3");
2858 wake_lock(&msm->wlock);
2859 dwc3_debugfs_init(msm);
2860
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002861 return 0;
2862
Manu Gautam8c642812012-06-07 10:35:10 +05302863put_xcvr:
2864 usb_put_transceiver(msm->otg_xceiv);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302865put_psupply:
Manu Gautambb825d72013-03-12 16:25:42 +05302866 if (msm->usb_psy.dev)
2867 power_supply_unregister(&msm->usb_psy);
Manu Gautam60e01352012-05-29 09:00:34 +05302868disable_hs_ldo:
2869 dwc3_hsusb_ldo_enable(0);
2870free_hs_ldo_init:
2871 dwc3_hsusb_ldo_init(0);
2872disable_hs_vddcx:
2873 regulator_disable(context->hsusb_vddcx);
2874unconfig_hs_vddcx:
2875 dwc3_hsusb_config_vddcx(0);
2876disable_ss_ldo:
2877 dwc3_ssusb_ldo_enable(0);
2878free_ss_ldo_init:
2879 dwc3_ssusb_ldo_init(0);
2880disable_ss_vddcx:
2881 regulator_disable(context->ssusb_vddcx);
2882unconfig_ss_vddcx:
2883 dwc3_ssusb_config_vddcx(0);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002884disable_ref_clk:
2885 clk_disable_unprepare(msm->ref_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002886disable_utmi_clk:
2887 clk_disable_unprepare(msm->utmi_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002888disable_sleep_a_clk:
2889 clk_disable_unprepare(msm->hsphy_sleep_clk);
2890disable_sleep_clk:
2891 clk_disable_unprepare(msm->sleep_clk);
2892disable_iface_clk:
2893 clk_disable_unprepare(msm->iface_clk);
Manu Gautam1742db22012-06-19 13:33:24 +05302894disable_core_clk:
2895 clk_disable_unprepare(msm->core_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302896disable_xo:
2897 clk_disable_unprepare(msm->xo_clk);
2898put_xo:
2899 clk_put(msm->xo_clk);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002900
2901 return ret;
2902}
2903
2904static int __devexit dwc3_msm_remove(struct platform_device *pdev)
2905{
2906 struct dwc3_msm *msm = platform_get_drvdata(pdev);
2907
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302908 if (!msm->ext_chg_device) {
2909 device_destroy(msm->ext_chg_class, msm->ext_chg_dev);
2910 cdev_del(&msm->ext_chg_cdev);
2911 class_destroy(msm->ext_chg_class);
2912 unregister_chrdev_region(msm->ext_chg_dev, 1);
2913 }
2914
Jack Pham0fc12332012-11-19 13:14:22 -08002915 if (msm->id_adc_detect)
2916 qpnp_adc_tm_usbid_end();
Manu Gautamb5067272012-07-02 09:53:41 +05302917 if (dwc3_debugfs_root)
2918 debugfs_remove_recursive(dwc3_debugfs_root);
Manu Gautam8c642812012-06-07 10:35:10 +05302919 if (msm->otg_xceiv) {
2920 dwc3_start_chg_det(&msm->charger, false);
2921 usb_put_transceiver(msm->otg_xceiv);
2922 }
Manu Gautambb825d72013-03-12 16:25:42 +05302923 if (msm->usb_psy.dev)
2924 power_supply_unregister(&msm->usb_psy);
2925 if (msm->vbus_otg)
2926 regulator_disable(msm->vbus_otg);
Jack Pham0fc12332012-11-19 13:14:22 -08002927
Manu Gautamb5067272012-07-02 09:53:41 +05302928 pm_runtime_disable(msm->dev);
Manu Gautamb5067272012-07-02 09:53:41 +05302929 wake_lock_destroy(&msm->wlock);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002930
Manu Gautam60e01352012-05-29 09:00:34 +05302931 dwc3_hsusb_ldo_enable(0);
2932 dwc3_hsusb_ldo_init(0);
2933 regulator_disable(msm->hsusb_vddcx);
2934 dwc3_hsusb_config_vddcx(0);
2935 dwc3_ssusb_ldo_enable(0);
2936 dwc3_ssusb_ldo_init(0);
2937 regulator_disable(msm->ssusb_vddcx);
2938 dwc3_ssusb_config_vddcx(0);
Manu Gautam1742db22012-06-19 13:33:24 +05302939 clk_disable_unprepare(msm->core_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002940 clk_disable_unprepare(msm->iface_clk);
2941 clk_disable_unprepare(msm->sleep_clk);
2942 clk_disable_unprepare(msm->hsphy_sleep_clk);
2943 clk_disable_unprepare(msm->ref_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302944 clk_disable_unprepare(msm->xo_clk);
2945 clk_put(msm->xo_clk);
Manu Gautam60e01352012-05-29 09:00:34 +05302946
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002947 return 0;
2948}
2949
Manu Gautamb5067272012-07-02 09:53:41 +05302950static int dwc3_msm_pm_suspend(struct device *dev)
2951{
2952 int ret = 0;
2953 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
2954
2955 dev_dbg(dev, "dwc3-msm PM suspend\n");
2956
Manu Gautam8d98a572013-01-21 16:34:50 +05302957 flush_delayed_work_sync(&mdwc->resume_work);
2958 if (!atomic_read(&mdwc->in_lpm)) {
2959 dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n");
2960 return -EBUSY;
2961 }
2962
Manu Gautamb5067272012-07-02 09:53:41 +05302963 ret = dwc3_msm_suspend(mdwc);
2964 if (!ret)
2965 atomic_set(&mdwc->pm_suspended, 1);
2966
2967 return ret;
2968}
2969
2970static int dwc3_msm_pm_resume(struct device *dev)
2971{
2972 int ret = 0;
2973 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
2974
2975 dev_dbg(dev, "dwc3-msm PM resume\n");
2976
2977 atomic_set(&mdwc->pm_suspended, 0);
2978 if (mdwc->resume_pending) {
2979 mdwc->resume_pending = false;
2980
2981 ret = dwc3_msm_resume(mdwc);
2982 /* Update runtime PM status */
2983 pm_runtime_disable(dev);
2984 pm_runtime_set_active(dev);
2985 pm_runtime_enable(dev);
2986
2987 /* Let OTG know about resume event and update pm_count */
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302988 if (mdwc->otg_xceiv) {
Manu Gautamb5067272012-07-02 09:53:41 +05302989 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2990 DWC3_EVENT_PHY_RESUME);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302991 if (mdwc->ext_xceiv.otg_capability)
2992 mdwc->ext_xceiv.notify_ext_events(
2993 mdwc->otg_xceiv->otg,
2994 DWC3_EVENT_XCEIV_STATE);
2995 }
Manu Gautamb5067272012-07-02 09:53:41 +05302996 }
2997
2998 return ret;
2999}
3000
3001static int dwc3_msm_runtime_idle(struct device *dev)
3002{
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303003 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3004
Manu Gautamb5067272012-07-02 09:53:41 +05303005 dev_dbg(dev, "DWC3-msm runtime idle\n");
3006
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303007 if (mdwc->ext_chg_active) {
3008 dev_dbg(dev, "Deferring LPM\n");
3009 /*
3010 * Charger detection may happen in user space.
3011 * Delay entering LPM by 3 sec. Otherwise we
3012 * have to exit LPM when user space begins
3013 * charger detection.
3014 *
3015 * This timer will be canceled when user space
3016 * votes against LPM by incrementing PM usage
3017 * counter. We enter low power mode when
3018 * PM usage counter is decremented.
3019 */
3020 pm_schedule_suspend(dev, 3000);
3021 return -EAGAIN;
3022 }
3023
Manu Gautamb5067272012-07-02 09:53:41 +05303024 return 0;
3025}
3026
3027static int dwc3_msm_runtime_suspend(struct device *dev)
3028{
3029 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3030
3031 dev_dbg(dev, "DWC3-msm runtime suspend\n");
3032
3033 return dwc3_msm_suspend(mdwc);
3034}
3035
3036static int dwc3_msm_runtime_resume(struct device *dev)
3037{
3038 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3039
3040 dev_dbg(dev, "DWC3-msm runtime resume\n");
3041
3042 return dwc3_msm_resume(mdwc);
3043}
3044
3045static const struct dev_pm_ops dwc3_msm_dev_pm_ops = {
3046 SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume)
3047 SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume,
3048 dwc3_msm_runtime_idle)
3049};
3050
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003051static const struct of_device_id of_dwc3_matach[] = {
3052 {
3053 .compatible = "qcom,dwc-usb3-msm",
3054 },
3055 { },
3056};
3057MODULE_DEVICE_TABLE(of, of_dwc3_matach);
3058
3059static struct platform_driver dwc3_msm_driver = {
3060 .probe = dwc3_msm_probe,
3061 .remove = __devexit_p(dwc3_msm_remove),
3062 .driver = {
3063 .name = "msm-dwc3",
Manu Gautamb5067272012-07-02 09:53:41 +05303064 .pm = &dwc3_msm_dev_pm_ops,
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003065 .of_match_table = of_dwc3_matach,
3066 },
3067};
3068
Manu Gautam377821c2012-09-28 16:53:24 +05303069MODULE_LICENSE("GPL v2");
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003070MODULE_DESCRIPTION("DesignWare USB3 MSM Glue Layer");
3071
3072static int __devinit dwc3_msm_init(void)
3073{
3074 return platform_driver_register(&dwc3_msm_driver);
3075}
3076module_init(dwc3_msm_init);
3077
3078static void __exit dwc3_msm_exit(void)
3079{
3080 platform_driver_unregister(&dwc3_msm_driver);
3081}
3082module_exit(dwc3_msm_exit);