blob: bda10933d4eef84c511a02ca3941a0813211b7b9 [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>
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +053037#include <linux/usb/msm_ext_chg.h>
Manu Gautam60e01352012-05-29 09:00:34 +053038#include <linux/regulator/consumer.h>
Jack Pham924cbe872013-07-10 16:40:55 -070039#include <linux/pm_wakeup.h>
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +053040#include <linux/power_supply.h>
Jack Pham0fc12332012-11-19 13:14:22 -080041#include <linux/qpnp/qpnp-adc.h>
Pavankumar Kondeti08693e72013-05-03 11:55:48 +053042#include <linux/cdev.h>
43#include <linux/completion.h>
Manu Gautam60e01352012-05-29 09:00:34 +053044
45#include <mach/rpm-regulator.h>
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +053046#include <mach/rpm-regulator-smd.h>
Manu Gautam2617deb2012-08-31 17:50:06 -070047#include <mach/msm_bus.h>
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +053048#include <mach/clk.h>
Ido Shayevitz9fb83452012-04-01 17:45:58 +030049
Manu Gautam8c642812012-06-07 10:35:10 +053050#include "dwc3_otg.h"
Ido Shayevitz9fb83452012-04-01 17:45:58 +030051#include "core.h"
52#include "gadget.h"
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +053053#include "debug.h"
Ido Shayevitz9fb83452012-04-01 17:45:58 +030054
Jack Pham0fc12332012-11-19 13:14:22 -080055/* ADC threshold values */
56static int adc_low_threshold = 700;
57module_param(adc_low_threshold, int, S_IRUGO | S_IWUSR);
58MODULE_PARM_DESC(adc_low_threshold, "ADC ID Low voltage threshold");
59
60static int adc_high_threshold = 950;
61module_param(adc_high_threshold, int, S_IRUGO | S_IWUSR);
62MODULE_PARM_DESC(adc_high_threshold, "ADC ID High voltage threshold");
63
64static int adc_meas_interval = ADC_MEAS1_INTERVAL_1S;
65module_param(adc_meas_interval, int, S_IRUGO | S_IWUSR);
66MODULE_PARM_DESC(adc_meas_interval, "ADC ID polling period");
67
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +053068static int override_phy_init;
69module_param(override_phy_init, int, S_IRUGO|S_IWUSR);
70MODULE_PARM_DESC(override_phy_init, "Override HSPHY Init Seq");
71
Vijayavardhan Vennapusa9f74b1b2013-09-23 19:22:17 +053072static int ss_phy_override_deemphasis;
73module_param(ss_phy_override_deemphasis, int, S_IRUGO|S_IWUSR);
74MODULE_PARM_DESC(ss_phy_override_deemphasis, "Override SSPHY demphasis value");
75
Jack Pham9b4606b2013-04-02 17:32:25 -070076/* Enable Proprietary charger detection */
77static bool prop_chg_detect;
78module_param(prop_chg_detect, bool, S_IRUGO | S_IWUSR);
79MODULE_PARM_DESC(prop_chg_detect, "Enable Proprietary charger detection");
80
Ido Shayevitz9fb83452012-04-01 17:45:58 +030081/**
82 * USB DBM Hardware registers.
83 *
84 */
Shimrit Malichia00d7322012-08-05 13:56:28 +030085#define DBM_BASE 0x000F8000
86#define DBM_EP_CFG(n) (DBM_BASE + (0x00 + 4 * (n)))
87#define DBM_DATA_FIFO(n) (DBM_BASE + (0x10 + 4 * (n)))
88#define DBM_DATA_FIFO_SIZE(n) (DBM_BASE + (0x20 + 4 * (n)))
89#define DBM_DATA_FIFO_EN (DBM_BASE + (0x30))
90#define DBM_GEVNTADR (DBM_BASE + (0x34))
91#define DBM_GEVNTSIZ (DBM_BASE + (0x38))
92#define DBM_DBG_CNFG (DBM_BASE + (0x3C))
93#define DBM_HW_TRB0_EP(n) (DBM_BASE + (0x40 + 4 * (n)))
94#define DBM_HW_TRB1_EP(n) (DBM_BASE + (0x50 + 4 * (n)))
95#define DBM_HW_TRB2_EP(n) (DBM_BASE + (0x60 + 4 * (n)))
96#define DBM_HW_TRB3_EP(n) (DBM_BASE + (0x70 + 4 * (n)))
97#define DBM_PIPE_CFG (DBM_BASE + (0x80))
98#define DBM_SOFT_RESET (DBM_BASE + (0x84))
99#define DBM_GEN_CFG (DBM_BASE + (0x88))
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300100
101/**
102 * USB DBM Hardware registers bitmask.
103 *
104 */
105/* DBM_EP_CFG */
Shimrit Malichia00d7322012-08-05 13:56:28 +0300106#define DBM_EN_EP 0x00000001
107#define USB3_EPNUM 0x0000003E
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300108#define DBM_BAM_PIPE_NUM 0x000000C0
109#define DBM_PRODUCER 0x00000100
110#define DBM_DISABLE_WB 0x00000200
111#define DBM_INT_RAM_ACC 0x00000400
112
113/* DBM_DATA_FIFO_SIZE */
114#define DBM_DATA_FIFO_SIZE_MASK 0x0000ffff
115
116/* DBM_GEVNTSIZ */
117#define DBM_GEVNTSIZ_MASK 0x0000ffff
118
119/* DBM_DBG_CNFG */
120#define DBM_ENABLE_IOC_MASK 0x0000000f
121
122/* DBM_SOFT_RESET */
123#define DBM_SFT_RST_EP0 0x00000001
124#define DBM_SFT_RST_EP1 0x00000002
125#define DBM_SFT_RST_EP2 0x00000004
126#define DBM_SFT_RST_EP3 0x00000008
Shimrit Malichia00d7322012-08-05 13:56:28 +0300127#define DBM_SFT_RST_EPS_MASK 0x0000000F
128#define DBM_SFT_RST_MASK 0x80000000
129#define DBM_EN_MASK 0x00000002
Ido Shayevitzef72ddd2012-03-28 18:55:55 +0200130
131#define DBM_MAX_EPS 4
132
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300133/* DBM TRB configurations */
134#define DBM_TRB_BIT 0x80000000
135#define DBM_TRB_DATA_SRC 0x40000000
136#define DBM_TRB_DMA 0x20000000
137#define DBM_TRB_EP_NUM(ep) (ep<<24)
Shimrit Malichia00d7322012-08-05 13:56:28 +0300138
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +0530139#define USB3_PORTSC (0x430)
140#define PORT_PE (0x1 << 1)
Manu Gautam8c642812012-06-07 10:35:10 +0530141/**
142 * USB QSCRATCH Hardware registers
143 *
144 */
145#define QSCRATCH_REG_OFFSET (0x000F8800)
Pavankumar Kondeti08693e72013-05-03 11:55:48 +0530146#define QSCRATCH_CTRL_REG (QSCRATCH_REG_OFFSET + 0x04)
Shimrit Malichia00d7322012-08-05 13:56:28 +0300147#define QSCRATCH_GENERAL_CFG (QSCRATCH_REG_OFFSET + 0x08)
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +0530148#define QSCRATCH_RAM1_REG (QSCRATCH_REG_OFFSET + 0x0C)
Manu Gautambd0e5782012-08-30 10:39:01 -0700149#define HS_PHY_CTRL_REG (QSCRATCH_REG_OFFSET + 0x10)
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +0530150#define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
Manu Gautam8c642812012-06-07 10:35:10 +0530151#define CHARGING_DET_CTRL_REG (QSCRATCH_REG_OFFSET + 0x18)
152#define CHARGING_DET_OUTPUT_REG (QSCRATCH_REG_OFFSET + 0x1C)
153#define ALT_INTERRUPT_EN_REG (QSCRATCH_REG_OFFSET + 0x20)
154#define HS_PHY_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x24)
Manu Gautamd4108b72012-12-14 17:35:18 +0530155#define CGCTL_REG (QSCRATCH_REG_OFFSET + 0x28)
Manu Gautambd0e5782012-08-30 10:39:01 -0700156#define SS_PHY_CTRL_REG (QSCRATCH_REG_OFFSET + 0x30)
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +0530157#define SS_PHY_PARAM_CTRL_1 (QSCRATCH_REG_OFFSET + 0x34)
158#define SS_PHY_PARAM_CTRL_2 (QSCRATCH_REG_OFFSET + 0x38)
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530159#define SS_CR_PROTOCOL_DATA_IN_REG (QSCRATCH_REG_OFFSET + 0x3C)
160#define SS_CR_PROTOCOL_DATA_OUT_REG (QSCRATCH_REG_OFFSET + 0x40)
161#define SS_CR_PROTOCOL_CAP_ADDR_REG (QSCRATCH_REG_OFFSET + 0x44)
162#define SS_CR_PROTOCOL_CAP_DATA_REG (QSCRATCH_REG_OFFSET + 0x48)
163#define SS_CR_PROTOCOL_READ_REG (QSCRATCH_REG_OFFSET + 0x4C)
164#define SS_CR_PROTOCOL_WRITE_REG (QSCRATCH_REG_OFFSET + 0x50)
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +0530165#define PWR_EVNT_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x58)
166#define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C)
Manu Gautam8c642812012-06-07 10:35:10 +0530167
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300168struct dwc3_msm_req_complete {
169 struct list_head list_item;
170 struct usb_request *req;
171 void (*orig_complete)(struct usb_ep *ep,
172 struct usb_request *req);
173};
174
Ido Shayevitzef72ddd2012-03-28 18:55:55 +0200175struct dwc3_msm {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +0200176 struct device *dev;
177 void __iomem *base;
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +0530178 struct resource *io_res;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +0200179 int dbm_num_eps;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300180 u8 ep_num_mapping[DBM_MAX_EPS];
181 const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
182 struct list_head req_complete_list;
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +0530183 struct clk *xo_clk;
Manu Gautam3e9ad352012-08-16 14:44:47 -0700184 struct clk *ref_clk;
Manu Gautam1742db22012-06-19 13:33:24 +0530185 struct clk *core_clk;
Manu Gautam3e9ad352012-08-16 14:44:47 -0700186 struct clk *iface_clk;
187 struct clk *sleep_clk;
188 struct clk *hsphy_sleep_clk;
Jack Pham22698b82013-02-13 17:45:06 -0800189 struct clk *utmi_clk;
Manu Gautam60e01352012-05-29 09:00:34 +0530190 struct regulator *hsusb_3p3;
191 struct regulator *hsusb_1p8;
192 struct regulator *hsusb_vddcx;
193 struct regulator *ssusb_1p8;
194 struct regulator *ssusb_vddcx;
Hemant Kumar086bf6b2013-06-10 19:29:27 -0700195 struct regulator *dwc3_gdsc;
Manu Gautambb825d72013-03-12 16:25:42 +0530196
197 /* VBUS regulator if no OTG and running in host only mode */
198 struct regulator *vbus_otg;
Manu Gautamb5067272012-07-02 09:53:41 +0530199 struct dwc3_ext_xceiv ext_xceiv;
200 bool resume_pending;
201 atomic_t pm_suspended;
202 atomic_t in_lpm;
Manu Gautam377821c2012-09-28 16:53:24 +0530203 int hs_phy_irq;
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +0530204 int hsphy_init_seq;
Vijayavardhan Vennapusa9f74b1b2013-09-23 19:22:17 +0530205 int deemphasis_val;
Manu Gautam377821c2012-09-28 16:53:24 +0530206 bool lpm_irq_seen;
Manu Gautamb5067272012-07-02 09:53:41 +0530207 struct delayed_work resume_work;
Manu Gautam6eb13e32013-02-01 15:19:15 +0530208 struct work_struct restart_usb_work;
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +0530209 struct work_struct usb_block_reset_work;
Manu Gautam8c642812012-06-07 10:35:10 +0530210 struct dwc3_charger charger;
211 struct usb_phy *otg_xceiv;
212 struct delayed_work chg_work;
213 enum usb_chg_state chg_state;
Jack Pham0cca9412013-03-08 13:22:42 -0800214 int pmic_id_irq;
215 struct work_struct id_work;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800216 struct qpnp_adc_tm_btm_param adc_param;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700217 struct qpnp_adc_tm_chip *adc_tm_dev;
Jack Pham0fc12332012-11-19 13:14:22 -0800218 struct delayed_work init_adc_work;
219 bool id_adc_detect;
Manu Gautam8c642812012-06-07 10:35:10 +0530220 u8 dcd_retries;
Manu Gautam2617deb2012-08-31 17:50:06 -0700221 u32 bus_perf_client;
222 struct msm_bus_scale_pdata *bus_scale_table;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +0530223 struct power_supply usb_psy;
Jack Pham9354c6a2012-12-20 19:19:32 -0800224 struct power_supply *ext_vbus_psy;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +0530225 unsigned int online;
226 unsigned int host_mode;
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +0530227 unsigned int voltage_max;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +0530228 unsigned int current_max;
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +0530229 unsigned int vdd_no_vol_level;
230 unsigned int vdd_low_vol_level;
231 unsigned int vdd_high_vol_level;
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +0530232 unsigned int tx_fifo_size;
233 unsigned int qdss_tx_fifo_size;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +0530234 bool vbus_active;
Jack Phamfadd6432012-12-07 19:03:41 -0800235 bool ext_inuse;
Jack Phamf12b7e12012-12-28 14:27:26 -0800236 enum dwc3_id_state id_state;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +0530237 unsigned long lpm_flags;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +0530238#define MDWC3_PHY_REF_AND_CORECLK_OFF BIT(0)
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +0530239#define MDWC3_TCXO_SHUTDOWN BIT(1)
Pavankumar Kondeti08693e72013-05-03 11:55:48 +0530240
241 u32 qscratch_ctl_val;
242 dev_t ext_chg_dev;
243 struct cdev ext_chg_cdev;
244 struct class *ext_chg_class;
245 struct device *ext_chg_device;
246 bool ext_chg_opened;
247 bool ext_chg_active;
248 struct completion ext_chg_wait;
Manu Gautam60e01352012-05-29 09:00:34 +0530249};
250
251#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
252#define USB_HSPHY_3P3_VOL_MAX 3300000 /* uV */
253#define USB_HSPHY_3P3_HPM_LOAD 16000 /* uA */
254
255#define USB_HSPHY_1P8_VOL_MIN 1800000 /* uV */
256#define USB_HSPHY_1P8_VOL_MAX 1800000 /* uV */
257#define USB_HSPHY_1P8_HPM_LOAD 19000 /* uA */
258
259#define USB_SSPHY_1P8_VOL_MIN 1800000 /* uV */
260#define USB_SSPHY_1P8_VOL_MAX 1800000 /* uV */
261#define USB_SSPHY_1P8_HPM_LOAD 23000 /* uA */
262
Jack Phamfadd6432012-12-07 19:03:41 -0800263static struct usb_ext_notification *usb_ext;
264
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300265/**
266 *
267 * Read register with debug info.
268 *
269 * @base - DWC3 base virtual address.
270 * @offset - register offset.
271 *
272 * @return u32
273 */
274static inline u32 dwc3_msm_read_reg(void *base, u32 offset)
275{
276 u32 val = ioread32(base + offset);
277 return val;
278}
279
280/**
281 * Read register masked field with debug info.
282 *
283 * @base - DWC3 base virtual address.
284 * @offset - register offset.
285 * @mask - register bitmask.
286 *
287 * @return u32
288 */
289static inline u32 dwc3_msm_read_reg_field(void *base,
290 u32 offset,
291 const u32 mask)
292{
293 u32 shift = find_first_bit((void *)&mask, 32);
294 u32 val = ioread32(base + offset);
295 val &= mask; /* clear other bits */
296 val >>= shift;
297 return val;
298}
299
300/**
301 *
302 * Write register with debug info.
303 *
304 * @base - DWC3 base virtual address.
305 * @offset - register offset.
306 * @val - value to write.
307 *
308 */
309static inline void dwc3_msm_write_reg(void *base, u32 offset, u32 val)
310{
311 iowrite32(val, base + offset);
312}
313
314/**
315 * Write register masked field with debug info.
316 *
317 * @base - DWC3 base virtual address.
318 * @offset - register offset.
319 * @mask - register bitmask.
320 * @val - value to write.
321 *
322 */
323static inline void dwc3_msm_write_reg_field(void *base, u32 offset,
324 const u32 mask, u32 val)
325{
326 u32 shift = find_first_bit((void *)&mask, 32);
327 u32 tmp = ioread32(base + offset);
328
329 tmp &= ~mask; /* clear written bits */
330 val = tmp | (val << shift);
331 iowrite32(val, base + offset);
332}
333
334/**
Manu Gautam8c642812012-06-07 10:35:10 +0530335 * Write register and read back masked value to confirm it is written
336 *
337 * @base - DWC3 base virtual address.
338 * @offset - register offset.
339 * @mask - register bitmask specifying what should be updated
340 * @val - value to write.
341 *
342 */
343static inline void dwc3_msm_write_readback(void *base, u32 offset,
344 const u32 mask, u32 val)
345{
346 u32 write_val, tmp = ioread32(base + offset);
347
348 tmp &= ~mask; /* retain other bits */
349 write_val = tmp | val;
350
351 iowrite32(write_val, base + offset);
352
353 /* Read back to see if val was written */
354 tmp = ioread32(base + offset);
355 tmp &= mask; /* clear other bits */
356
357 if (tmp != val)
Jack Pham4b00e702013-07-03 17:10:36 -0700358 pr_err("%s: write: %x to QSCRATCH: %x FAILED\n",
359 __func__, val, offset);
Manu Gautam8c642812012-06-07 10:35:10 +0530360}
361
362/**
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530363 *
364 * Write SSPHY register with debug info.
365 *
366 * @base - DWC3 base virtual address.
367 * @addr - SSPHY address to write.
368 * @val - value to write.
369 *
370 */
371static void dwc3_msm_ssusb_write_phycreg(void *base, u32 addr, u32 val)
372{
373 iowrite32(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
374 iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
375 while (ioread32(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
376 cpu_relax();
377
378 iowrite32(val, base + SS_CR_PROTOCOL_DATA_IN_REG);
379 iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_DATA_REG);
380 while (ioread32(base + SS_CR_PROTOCOL_CAP_DATA_REG))
381 cpu_relax();
382
383 iowrite32(0x1, base + SS_CR_PROTOCOL_WRITE_REG);
384 while (ioread32(base + SS_CR_PROTOCOL_WRITE_REG))
385 cpu_relax();
386}
387
388/**
389 *
390 * Read SSPHY register with debug info.
391 *
392 * @base - DWC3 base virtual address.
393 * @addr - SSPHY address to read.
394 *
395 */
396static u32 dwc3_msm_ssusb_read_phycreg(void *base, u32 addr)
397{
Vijayavardhan Vennapusa96201212013-06-12 19:59:27 +0530398 bool first_read = true;
399
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530400 iowrite32(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
401 iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
402 while (ioread32(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
403 cpu_relax();
404
Vijayavardhan Vennapusa96201212013-06-12 19:59:27 +0530405 /*
406 * Due to hardware bug, first read of SSPHY register might be
407 * incorrect. Hence as workaround, SW should perform SSPHY register
408 * read twice, but use only second read and ignore first read.
409 */
410retry:
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530411 iowrite32(0x1, base + SS_CR_PROTOCOL_READ_REG);
412 while (ioread32(base + SS_CR_PROTOCOL_READ_REG))
413 cpu_relax();
414
Vijayavardhan Vennapusa96201212013-06-12 19:59:27 +0530415 if (first_read) {
416 ioread32(base + SS_CR_PROTOCOL_DATA_OUT_REG);
417 first_read = false;
418 goto retry;
419 }
420
Vijayavardhan Vennapusad81aed32012-12-05 17:30:40 +0530421 return ioread32(base + SS_CR_PROTOCOL_DATA_OUT_REG);
422}
423
424/**
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +0530425 * Dump all QSCRATCH registers.
426 *
427 */
428static void dwc3_msm_dump_phy_info(struct dwc3_msm *mdwc)
429{
430
431 dbg_print_reg("SSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
432 SS_PHY_CTRL_REG));
433 dbg_print_reg("HSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
434 HS_PHY_CTRL_REG));
435 dbg_print_reg("QSCRATCH_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
436 QSCRATCH_CTRL_REG));
437 dbg_print_reg("QSCRATCH_GENERAL_CFG", dwc3_msm_read_reg(mdwc->base,
438 QSCRATCH_GENERAL_CFG));
439 dbg_print_reg("PARAMETER_OVERRIDE_X_REG", dwc3_msm_read_reg(mdwc->base,
440 PARAMETER_OVERRIDE_X_REG));
441 dbg_print_reg("HS_PHY_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
442 HS_PHY_IRQ_STAT_REG));
443 dbg_print_reg("SS_PHY_PARAM_CTRL_1", dwc3_msm_read_reg(mdwc->base,
444 SS_PHY_PARAM_CTRL_1));
445 dbg_print_reg("SS_PHY_PARAM_CTRL_2", dwc3_msm_read_reg(mdwc->base,
446 SS_PHY_PARAM_CTRL_2));
447 dbg_print_reg("QSCRATCH_RAM1_REG", dwc3_msm_read_reg(mdwc->base,
448 QSCRATCH_RAM1_REG));
449 dbg_print_reg("PWR_EVNT_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
450 PWR_EVNT_IRQ_STAT_REG));
451 dbg_print_reg("PWR_EVNT_IRQ_MASK_REG", dwc3_msm_read_reg(mdwc->base,
452 PWR_EVNT_IRQ_MASK_REG));
453}
454
455/**
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300456 * Return DBM EP number according to usb endpoint number.
457 *
458 */
Jack Pham62c19a42013-07-09 17:55:09 -0700459static int dwc3_msm_find_matching_dbm_ep(struct dwc3_msm *mdwc, u8 usb_ep)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300460{
461 int i;
462
Jack Pham62c19a42013-07-09 17:55:09 -0700463 for (i = 0; i < mdwc->dbm_num_eps; i++)
464 if (mdwc->ep_num_mapping[i] == usb_ep)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300465 return i;
466
467 return -ENODEV; /* Not found */
468}
469
470/**
471 * Return number of configured DBM endpoints.
472 *
473 */
Jack Pham62c19a42013-07-09 17:55:09 -0700474static int dwc3_msm_configured_dbm_ep_num(struct dwc3_msm *mdwc)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300475{
476 int i;
477 int count = 0;
478
Jack Pham62c19a42013-07-09 17:55:09 -0700479 for (i = 0; i < mdwc->dbm_num_eps; i++)
480 if (mdwc->ep_num_mapping[i])
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300481 count++;
482
483 return count;
484}
485
486/**
487 * Configure the DBM with the USB3 core event buffer.
488 * This function is called by the SNPS UDC upon initialization.
489 *
490 * @addr - address of the event buffer.
491 * @size - size of the event buffer.
492 *
493 */
Jack Pham62c19a42013-07-09 17:55:09 -0700494static int dwc3_msm_event_buffer_config(struct dwc3_msm *mdwc,
495 u32 addr, u16 size)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300496{
Jack Pham62c19a42013-07-09 17:55:09 -0700497 dev_dbg(mdwc->dev, "%s\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300498
Jack Pham62c19a42013-07-09 17:55:09 -0700499 dwc3_msm_write_reg(mdwc->base, DBM_GEVNTADR, addr);
500 dwc3_msm_write_reg_field(mdwc->base, DBM_GEVNTSIZ,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300501 DBM_GEVNTSIZ_MASK, size);
502
503 return 0;
504}
505
506/**
507 * Reset the DBM registers upon initialization.
508 *
509 */
Jack Pham62c19a42013-07-09 17:55:09 -0700510static int dwc3_msm_dbm_soft_reset(struct dwc3_msm *mdwc, int enter_reset)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300511{
Jack Pham62c19a42013-07-09 17:55:09 -0700512 dev_dbg(mdwc->dev, "%s\n", __func__);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300513 if (enter_reset) {
Jack Pham62c19a42013-07-09 17:55:09 -0700514 dev_dbg(mdwc->dev, "enter DBM reset\n");
515 dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300516 DBM_SFT_RST_MASK, 1);
517 } else {
Jack Pham62c19a42013-07-09 17:55:09 -0700518 dev_dbg(mdwc->dev, "exit DBM reset\n");
519 dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300520 DBM_SFT_RST_MASK, 0);
521 /*enable DBM*/
Jack Pham62c19a42013-07-09 17:55:09 -0700522 dwc3_msm_write_reg_field(mdwc->base, QSCRATCH_GENERAL_CFG,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300523 DBM_EN_MASK, 0x1);
524 }
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300525
526 return 0;
527}
528
529/**
530 * Soft reset specific DBM ep.
531 * This function is called by the function driver upon events
532 * such as transfer aborting, USB re-enumeration and USB
533 * disconnection.
534 *
535 * @dbm_ep - DBM ep number.
536 * @enter_reset - should we enter a reset state or get out of it.
537 *
538 */
Jack Pham62c19a42013-07-09 17:55:09 -0700539static int dwc3_msm_dbm_ep_soft_reset(struct dwc3_msm *mdwc,
540 u8 dbm_ep, bool enter_reset)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300541{
Jack Pham62c19a42013-07-09 17:55:09 -0700542 dev_dbg(mdwc->dev, "%s\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300543
Jack Pham62c19a42013-07-09 17:55:09 -0700544 if (dbm_ep >= mdwc->dbm_num_eps) {
545 dev_err(mdwc->dev, "%s: Invalid DBM ep index\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300546 return -ENODEV;
547 }
548
549 if (enter_reset) {
Jack Pham62c19a42013-07-09 17:55:09 -0700550 dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300551 DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 1);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300552 } else {
Jack Pham62c19a42013-07-09 17:55:09 -0700553 dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300554 DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 0);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300555 }
556
557 return 0;
558}
559
560/**
561 * Configure a USB DBM ep to work in BAM mode.
562 *
563 *
564 * @usb_ep - USB physical EP number.
565 * @producer - producer/consumer.
566 * @disable_wb - disable write back to system memory.
567 * @internal_mem - use internal USB memory for data fifo.
568 * @ioc - enable interrupt on completion.
569 *
570 * @return int - DBM ep number.
571 */
Jack Pham62c19a42013-07-09 17:55:09 -0700572static int dwc3_msm_dbm_ep_config(struct dwc3_msm *mdwc, u8 usb_ep, u8 bam_pipe,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300573 bool producer, bool disable_wb,
574 bool internal_mem, bool ioc)
575{
576 u8 dbm_ep;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300577 u32 ep_cfg;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300578
Jack Pham62c19a42013-07-09 17:55:09 -0700579 dev_dbg(mdwc->dev, "%s\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300580
Jack Pham62c19a42013-07-09 17:55:09 -0700581 dbm_ep = dwc3_msm_find_matching_dbm_ep(mdwc, usb_ep);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300582
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300583 if (dbm_ep < 0) {
Jack Pham62c19a42013-07-09 17:55:09 -0700584 dev_err(mdwc->dev,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300585 "%s: Invalid usb ep index\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300586 return -ENODEV;
587 }
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300588 /* First, reset the dbm endpoint */
Jack Pham62c19a42013-07-09 17:55:09 -0700589 dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, 0);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300590
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300591 /* Set ioc bit for dbm_ep if needed */
Jack Pham62c19a42013-07-09 17:55:09 -0700592 dwc3_msm_write_reg_field(mdwc->base, DBM_DBG_CNFG,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300593 DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300594
Shimrit Malichia00d7322012-08-05 13:56:28 +0300595 ep_cfg = (producer ? DBM_PRODUCER : 0) |
596 (disable_wb ? DBM_DISABLE_WB : 0) |
597 (internal_mem ? DBM_INT_RAM_ACC : 0);
598
Jack Pham62c19a42013-07-09 17:55:09 -0700599 dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep),
Shimrit Malichia00d7322012-08-05 13:56:28 +0300600 DBM_PRODUCER | DBM_DISABLE_WB | DBM_INT_RAM_ACC, ep_cfg >> 8);
601
Jack Pham62c19a42013-07-09 17:55:09 -0700602 dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300603 usb_ep);
Jack Pham62c19a42013-07-09 17:55:09 -0700604 dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep),
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300605 DBM_BAM_PIPE_NUM, bam_pipe);
Jack Pham62c19a42013-07-09 17:55:09 -0700606 dwc3_msm_write_reg_field(mdwc->base, DBM_PIPE_CFG, 0x000000ff,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300607 0xe4);
Jack Pham62c19a42013-07-09 17:55:09 -0700608 dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
Shimrit Malichia00d7322012-08-05 13:56:28 +0300609 1);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300610
611 return dbm_ep;
612}
613
614/**
615 * Configure a USB DBM ep to work in normal mode.
616 *
617 * @usb_ep - USB ep number.
618 *
619 */
Jack Pham62c19a42013-07-09 17:55:09 -0700620static int dwc3_msm_dbm_ep_unconfig(struct dwc3_msm *mdwc, u8 usb_ep)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300621{
622 u8 dbm_ep;
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530623 u32 data;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300624
Jack Pham62c19a42013-07-09 17:55:09 -0700625 dev_dbg(mdwc->dev, "%s\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300626
Jack Pham62c19a42013-07-09 17:55:09 -0700627 dbm_ep = dwc3_msm_find_matching_dbm_ep(mdwc, usb_ep);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300628
629 if (dbm_ep < 0) {
Jack Pham62c19a42013-07-09 17:55:09 -0700630 dev_err(mdwc->dev, "%s: Invalid usb ep index\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300631 return -ENODEV;
632 }
633
Jack Pham62c19a42013-07-09 17:55:09 -0700634 mdwc->ep_num_mapping[dbm_ep] = 0;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300635
Jack Pham62c19a42013-07-09 17:55:09 -0700636 data = dwc3_msm_read_reg(mdwc->base, DBM_EP_CFG(dbm_ep));
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530637 data &= (~0x1);
Jack Pham62c19a42013-07-09 17:55:09 -0700638 dwc3_msm_write_reg(mdwc->base, DBM_EP_CFG(dbm_ep), data);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300639
640 /* Reset the dbm endpoint */
Jack Pham62c19a42013-07-09 17:55:09 -0700641 dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, true);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530642 /*
643 * 10 usec delay is required before deasserting DBM endpoint reset
644 * according to hardware programming guide.
645 */
646 udelay(10);
Jack Pham62c19a42013-07-09 17:55:09 -0700647 dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, false);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300648
649 return 0;
650}
651
652/**
653 * Configure the DBM with the BAM's data fifo.
654 * This function is called by the USB BAM Driver
655 * upon initialization.
656 *
657 * @ep - pointer to usb endpoint.
658 * @addr - address of data fifo.
659 * @size - size of data fifo.
660 *
661 */
Shimrit Malichia00d7322012-08-05 13:56:28 +0300662int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size, u8 dst_pipe_idx)
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300663{
664 u8 dbm_ep;
665 struct dwc3_ep *dep = to_dwc3_ep(ep);
Jack Pham62c19a42013-07-09 17:55:09 -0700666 struct dwc3 *dwc = dep->dwc;
667 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300668 u8 bam_pipe = dst_pipe_idx;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300669
Jack Pham62c19a42013-07-09 17:55:09 -0700670 dev_dbg(mdwc->dev, "%s\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300671
Shimrit Malichia00d7322012-08-05 13:56:28 +0300672 dbm_ep = bam_pipe;
Jack Pham62c19a42013-07-09 17:55:09 -0700673 mdwc->ep_num_mapping[dbm_ep] = dep->number;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300674
Jack Pham62c19a42013-07-09 17:55:09 -0700675 dwc3_msm_write_reg(mdwc->base, DBM_DATA_FIFO(dbm_ep), addr);
676 dwc3_msm_write_reg_field(mdwc->base, DBM_DATA_FIFO_SIZE(dbm_ep),
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300677 DBM_DATA_FIFO_SIZE_MASK, size);
678
679 return 0;
680}
681
682/**
683* Cleanups for msm endpoint on request complete.
684*
685* Also call original request complete.
686*
687* @usb_ep - pointer to usb_ep instance.
688* @request - pointer to usb_request instance.
689*
690* @return int - 0 on success, negetive on error.
691*/
692static void dwc3_msm_req_complete_func(struct usb_ep *ep,
693 struct usb_request *request)
694{
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300695 struct dwc3_ep *dep = to_dwc3_ep(ep);
Jack Pham62c19a42013-07-09 17:55:09 -0700696 struct dwc3 *dwc = dep->dwc;
697 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300698 struct dwc3_msm_req_complete *req_complete = NULL;
699
700 /* Find original request complete function and remove it from list */
Jack Pham62c19a42013-07-09 17:55:09 -0700701 list_for_each_entry(req_complete, &mdwc->req_complete_list, list_item) {
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300702 if (req_complete->req == request)
703 break;
704 }
705 if (!req_complete || req_complete->req != request) {
706 dev_err(dep->dwc->dev, "%s: could not find the request\n",
707 __func__);
708 return;
709 }
710 list_del(&req_complete->list_item);
711
712 /*
713 * Release another one TRB to the pool since DBM queue took 2 TRBs
714 * (normal and link), and the dwc3/gadget.c :: dwc3_gadget_giveback
715 * released only one.
716 */
Manu Gautam55d34222012-12-19 16:49:47 +0530717 dep->busy_slot++;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300718
719 /* Unconfigure dbm ep */
Jack Pham62c19a42013-07-09 17:55:09 -0700720 dwc3_msm_dbm_ep_unconfig(mdwc, dep->number);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300721
722 /*
723 * If this is the last endpoint we unconfigured, than reset also
724 * the event buffers.
725 */
Jack Pham62c19a42013-07-09 17:55:09 -0700726 if (0 == dwc3_msm_configured_dbm_ep_num(mdwc))
727 dwc3_msm_event_buffer_config(mdwc, 0, 0);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300728
729 /*
730 * Call original complete function, notice that dwc->lock is already
731 * taken by the caller of this function (dwc3_gadget_giveback()).
732 */
733 request->complete = req_complete->orig_complete;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300734 if (request->complete)
735 request->complete(ep, request);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300736
737 kfree(req_complete);
738}
739
740/**
741* Helper function.
742* See the header of the dwc3_msm_ep_queue function.
743*
744* @dwc3_ep - pointer to dwc3_ep instance.
745* @req - pointer to dwc3_request instance.
746*
747* @return int - 0 on success, negetive on error.
748*/
749static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
750{
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300751 struct dwc3_trb *trb;
752 struct dwc3_trb *trb_link;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300753 struct dwc3_gadget_ep_cmd_params params;
754 u32 cmd;
755 int ret = 0;
756
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300757 /* We push the request to the dep->req_queued list to indicate that
758 * this request is issued with start transfer. The request will be out
759 * from this list in 2 cases. The first is that the transfer will be
760 * completed (not if the transfer is endless using a circular TRBs with
761 * with link TRB). The second case is an option to do stop stransfer,
762 * this can be initiated by the function driver when calling dequeue.
763 */
764 req->queued = true;
765 list_add_tail(&req->list, &dep->req_queued);
766
767 /* First, prepare a normal TRB, point to the fake buffer */
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300768 trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300769 dep->free_slot++;
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300770 memset(trb, 0, sizeof(*trb));
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300771
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300772 req->trb = trb;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300773 trb->bph = DBM_TRB_BIT | DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300774 trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
775 trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300776 req->trb_dma = dwc3_trb_dma_offset(dep, trb);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300777
778 /* Second, prepare a Link TRB that points to the first TRB*/
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300779 trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300780 dep->free_slot++;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300781 memset(trb_link, 0, sizeof *trb_link);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300782
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300783 trb_link->bpl = lower_32_bits(req->trb_dma);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300784 trb_link->bph = DBM_TRB_BIT |
Ido Shayevitzfa65a582012-06-06 14:39:54 +0300785 DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
786 trb_link->size = 0;
787 trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300788
789 /*
790 * Now start the transfer
791 */
792 memset(&params, 0, sizeof(params));
Shimrit Malichia00d7322012-08-05 13:56:28 +0300793 params.param0 = 0; /* TDAddr High */
794 params.param1 = lower_32_bits(req->trb_dma); /* DAddr Low */
795
Manu Gautam5b2bf9a2012-10-18 10:52:50 +0530796 /* DBM requires IOC to be set */
797 cmd = DWC3_DEPCMD_STARTTRANSFER | DWC3_DEPCMD_CMDIOC;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300798 ret = dwc3_send_gadget_ep_cmd(dep->dwc, dep->number, cmd, &params);
799 if (ret < 0) {
800 dev_dbg(dep->dwc->dev,
801 "%s: failed to send STARTTRANSFER command\n",
802 __func__);
803
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300804 list_del(&req->list);
805 return ret;
806 }
Manu Gautam4a51a062012-12-07 11:24:39 +0530807 dep->flags |= DWC3_EP_BUSY;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300808
809 return ret;
810}
811
812/**
813* Queue a usb request to the DBM endpoint.
814* This function should be called after the endpoint
815* was enabled by the ep_enable.
816*
817* This function prepares special structure of TRBs which
818* is familier with the DBM HW, so it will possible to use
819* this endpoint in DBM mode.
820*
821* The TRBs prepared by this function, is one normal TRB
822* which point to a fake buffer, followed by a link TRB
823* that points to the first TRB.
824*
825* The API of this function follow the regular API of
826* usb_ep_queue (see usb_ep_ops in include/linuk/usb/gadget.h).
827*
828* @usb_ep - pointer to usb_ep instance.
829* @request - pointer to usb_request instance.
830* @gfp_flags - possible flags.
831*
832* @return int - 0 on success, negetive on error.
833*/
834static int dwc3_msm_ep_queue(struct usb_ep *ep,
835 struct usb_request *request, gfp_t gfp_flags)
836{
837 struct dwc3_request *req = to_dwc3_request(request);
838 struct dwc3_ep *dep = to_dwc3_ep(ep);
839 struct dwc3 *dwc = dep->dwc;
Jack Pham62c19a42013-07-09 17:55:09 -0700840 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300841 struct dwc3_msm_req_complete *req_complete;
842 unsigned long flags;
843 int ret = 0;
844 u8 bam_pipe;
845 bool producer;
846 bool disable_wb;
847 bool internal_mem;
848 bool ioc;
Shimrit Malichia00d7322012-08-05 13:56:28 +0300849 u8 speed;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300850
851 if (!(request->udc_priv & MSM_SPS_MODE)) {
852 /* Not SPS mode, call original queue */
Jack Pham62c19a42013-07-09 17:55:09 -0700853 dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n",
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300854 __func__);
855
Jack Pham62c19a42013-07-09 17:55:09 -0700856 return (mdwc->original_ep_ops[dep->number])->queue(ep,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300857 request,
858 gfp_flags);
859 }
860
861 if (!dep->endpoint.desc) {
Jack Pham62c19a42013-07-09 17:55:09 -0700862 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300863 "%s: trying to queue request %p to disabled ep %s\n",
864 __func__, request, ep->name);
865 return -EPERM;
866 }
867
868 if (dep->number == 0 || dep->number == 1) {
Jack Pham62c19a42013-07-09 17:55:09 -0700869 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300870 "%s: trying to queue dbm request %p to control ep %s\n",
871 __func__, request, ep->name);
872 return -EPERM;
873 }
874
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300875
Manu Gautam4a51a062012-12-07 11:24:39 +0530876 if (dep->busy_slot != dep->free_slot || !list_empty(&dep->request_list)
877 || !list_empty(&dep->req_queued)) {
Jack Pham62c19a42013-07-09 17:55:09 -0700878 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300879 "%s: trying to queue dbm request %p tp ep %s\n",
880 __func__, request, ep->name);
881 return -EPERM;
Manu Gautam4a51a062012-12-07 11:24:39 +0530882 } else {
883 dep->busy_slot = 0;
884 dep->free_slot = 0;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300885 }
886
887 /*
888 * Override req->complete function, but before doing that,
889 * store it's original pointer in the req_complete_list.
890 */
891 req_complete = kzalloc(sizeof(*req_complete), GFP_KERNEL);
892 if (!req_complete) {
Jack Pham62c19a42013-07-09 17:55:09 -0700893 dev_err(mdwc->dev, "%s: not enough memory\n", __func__);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300894 return -ENOMEM;
895 }
896 req_complete->req = request;
897 req_complete->orig_complete = request->complete;
Jack Pham62c19a42013-07-09 17:55:09 -0700898 list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300899 request->complete = dwc3_msm_req_complete_func;
900
901 /*
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300902 * Configure the DBM endpoint
903 */
Shimrit Malichia00d7322012-08-05 13:56:28 +0300904 bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300905 producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
906 disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
907 internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
908 ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
909
Jack Pham62c19a42013-07-09 17:55:09 -0700910 ret = dwc3_msm_dbm_ep_config(mdwc, dep->number,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300911 bam_pipe, producer,
912 disable_wb, internal_mem, ioc);
913 if (ret < 0) {
Jack Pham62c19a42013-07-09 17:55:09 -0700914 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300915 "error %d after calling dwc3_msm_dbm_ep_config\n",
916 ret);
917 return ret;
918 }
919
920 dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
921 __func__, request, ep->name, request->length);
922
923 /*
924 * We must obtain the lock of the dwc3 core driver,
925 * including disabling interrupts, so we will be sure
926 * that we are the only ones that configure the HW device
927 * core and ensure that we queuing the request will finish
928 * as soon as possible so we will release back the lock.
929 */
930 spin_lock_irqsave(&dwc->lock, flags);
931 ret = __dwc3_msm_ep_queue(dep, req);
932 spin_unlock_irqrestore(&dwc->lock, flags);
933 if (ret < 0) {
Jack Pham62c19a42013-07-09 17:55:09 -0700934 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300935 "error %d after calling __dwc3_msm_ep_queue\n", ret);
936 return ret;
937 }
938
Shimrit Malichia00d7322012-08-05 13:56:28 +0300939 speed = dwc3_readl(dwc->regs, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD;
Jack Pham62c19a42013-07-09 17:55:09 -0700940 dwc3_msm_write_reg(mdwc->base, DBM_GEN_CFG, speed >> 2);
Shimrit Malichia00d7322012-08-05 13:56:28 +0300941
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300942 return 0;
943}
944
945/**
946 * Configure MSM endpoint.
947 * This function do specific configurations
948 * to an endpoint which need specific implementaion
949 * in the MSM architecture.
950 *
951 * This function should be called by usb function/class
952 * layer which need a support from the specific MSM HW
953 * which wrap the USB3 core. (like DBM specific endpoints)
954 *
955 * @ep - a pointer to some usb_ep instance
956 *
957 * @return int - 0 on success, negetive on error.
958 */
959int msm_ep_config(struct usb_ep *ep)
960{
961 struct dwc3_ep *dep = to_dwc3_ep(ep);
Jack Pham62c19a42013-07-09 17:55:09 -0700962 struct dwc3 *dwc = dep->dwc;
963 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300964 struct usb_ep_ops *new_ep_ops;
965
Jack Pham62c19a42013-07-09 17:55:09 -0700966 dwc3_msm_event_buffer_config(mdwc,
967 dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
968 dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0)));
Manu Gautama302f612012-12-18 17:33:06 +0530969
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300970 /* Save original ep ops for future restore*/
Jack Pham62c19a42013-07-09 17:55:09 -0700971 if (mdwc->original_ep_ops[dep->number]) {
972 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300973 "ep [%s,%d] already configured as msm endpoint\n",
974 ep->name, dep->number);
975 return -EPERM;
976 }
Jack Pham62c19a42013-07-09 17:55:09 -0700977 mdwc->original_ep_ops[dep->number] = ep->ops;
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300978
979 /* Set new usb ops as we like */
980 new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_KERNEL);
981 if (!new_ep_ops) {
Jack Pham62c19a42013-07-09 17:55:09 -0700982 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300983 "%s: unable to allocate mem for new usb ep ops\n",
984 __func__);
985 return -ENOMEM;
986 }
987 (*new_ep_ops) = (*ep->ops);
988 new_ep_ops->queue = dwc3_msm_ep_queue;
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +0530989 new_ep_ops->disable = ep->ops->disable;
990
Ido Shayevitz9fb83452012-04-01 17:45:58 +0300991 ep->ops = new_ep_ops;
992
993 /*
994 * Do HERE more usb endpoint configurations
995 * which are specific to MSM.
996 */
997
998 return 0;
999}
1000EXPORT_SYMBOL(msm_ep_config);
1001
1002/**
1003 * Un-configure MSM endpoint.
1004 * Tear down configurations done in the
1005 * dwc3_msm_ep_config function.
1006 *
1007 * @ep - a pointer to some usb_ep instance
1008 *
1009 * @return int - 0 on success, negetive on error.
1010 */
1011int msm_ep_unconfig(struct usb_ep *ep)
1012{
1013 struct dwc3_ep *dep = to_dwc3_ep(ep);
Jack Pham62c19a42013-07-09 17:55:09 -07001014 struct dwc3 *dwc = dep->dwc;
1015 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
Ido Shayevitz9fb83452012-04-01 17:45:58 +03001016 struct usb_ep_ops *old_ep_ops;
1017
1018 /* Restore original ep ops */
Jack Pham62c19a42013-07-09 17:55:09 -07001019 if (!mdwc->original_ep_ops[dep->number]) {
1020 dev_err(mdwc->dev,
Ido Shayevitz9fb83452012-04-01 17:45:58 +03001021 "ep [%s,%d] was not configured as msm endpoint\n",
1022 ep->name, dep->number);
1023 return -EINVAL;
1024 }
1025 old_ep_ops = (struct usb_ep_ops *)ep->ops;
Jack Pham62c19a42013-07-09 17:55:09 -07001026 ep->ops = mdwc->original_ep_ops[dep->number];
1027 mdwc->original_ep_ops[dep->number] = NULL;
Ido Shayevitz9fb83452012-04-01 17:45:58 +03001028 kfree(old_ep_ops);
1029
1030 /*
1031 * Do HERE more usb endpoint un-configurations
1032 * which are specific to MSM.
1033 */
1034
1035 return 0;
1036}
1037EXPORT_SYMBOL(msm_ep_unconfig);
1038
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05301039void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enabled)
1040{
1041 struct dwc3_ep *dep = to_dwc3_ep(ep);
1042 struct dwc3 *dwc = dep->dwc;
1043 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
1044
1045 if (qdss_enabled)
1046 dwc->tx_fifo_size = mdwc->qdss_tx_fifo_size;
1047 else
1048 dwc->tx_fifo_size = mdwc->tx_fifo_size;
1049}
1050EXPORT_SYMBOL(dwc3_tx_fifo_resize_request);
1051
Manu Gautam6eb13e32013-02-01 15:19:15 +05301052static void dwc3_restart_usb_work(struct work_struct *w)
1053{
1054 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
1055 restart_usb_work);
1056
1057 dev_dbg(mdwc->dev, "%s\n", __func__);
1058
1059 if (atomic_read(&mdwc->in_lpm) || !mdwc->otg_xceiv) {
1060 dev_err(mdwc->dev, "%s failed!!!\n", __func__);
1061 return;
1062 }
1063
1064 if (!mdwc->ext_xceiv.bsv) {
1065 dev_dbg(mdwc->dev, "%s bailing out in disconnect\n", __func__);
1066 return;
1067 }
1068
1069 /* Reset active USB connection */
1070 mdwc->ext_xceiv.bsv = false;
1071 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
1072 /* Make sure disconnect is processed before sending connect */
1073 flush_delayed_work(&mdwc->resume_work);
1074
1075 mdwc->ext_xceiv.bsv = true;
1076 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
1077}
1078
1079/**
1080 * Reset USB peripheral connection
1081 * Inform OTG for Vbus LOW followed by Vbus HIGH notification.
1082 * This performs full hardware reset and re-initialization which
1083 * might be required by some DBM client driver during uninit/cleanup.
1084 */
Jack Pham62c19a42013-07-09 17:55:09 -07001085void msm_dwc3_restart_usb_session(struct usb_gadget *gadget)
Manu Gautam6eb13e32013-02-01 15:19:15 +05301086{
Jack Pham62c19a42013-07-09 17:55:09 -07001087 struct dwc3 *dwc = container_of(gadget, struct dwc3, gadget);
1088 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
1089
1090 if (mdwc)
1091 return;
Manu Gautam6eb13e32013-02-01 15:19:15 +05301092
1093 dev_dbg(mdwc->dev, "%s\n", __func__);
1094 queue_work(system_nrt_wq, &mdwc->restart_usb_work);
Manu Gautam6eb13e32013-02-01 15:19:15 +05301095}
1096EXPORT_SYMBOL(msm_dwc3_restart_usb_session);
1097
Jack Phamfadd6432012-12-07 19:03:41 -08001098/**
1099 * msm_register_usb_ext_notification: register for event notification
1100 * @info: pointer to client usb_ext_notification structure. May be NULL.
1101 *
1102 * @return int - 0 on success, negative on error
1103 */
1104int msm_register_usb_ext_notification(struct usb_ext_notification *info)
1105{
1106 pr_debug("%s usb_ext: %p\n", __func__, info);
1107
1108 if (info) {
1109 if (usb_ext) {
1110 pr_err("%s: already registered\n", __func__);
1111 return -EEXIST;
1112 }
1113
1114 if (!info->notify) {
1115 pr_err("%s: notify is NULL\n", __func__);
1116 return -EINVAL;
1117 }
1118 }
1119
1120 usb_ext = info;
1121 return 0;
1122}
1123EXPORT_SYMBOL(msm_register_usb_ext_notification);
1124
Manu Gautam60e01352012-05-29 09:00:34 +05301125/* HSPHY */
Jack Pham4b00e702013-07-03 17:10:36 -07001126static int dwc3_hsusb_config_vddcx(struct dwc3_msm *dwc, int high)
Manu Gautam60e01352012-05-29 09:00:34 +05301127{
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301128 int min_vol, max_vol, ret;
Manu Gautam60e01352012-05-29 09:00:34 +05301129
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301130 max_vol = dwc->vdd_high_vol_level;
1131 min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
Manu Gautam60e01352012-05-29 09:00:34 +05301132 ret = regulator_set_voltage(dwc->hsusb_vddcx, min_vol, max_vol);
1133 if (ret) {
1134 dev_err(dwc->dev, "unable to set voltage for HSUSB_VDDCX\n");
1135 return ret;
1136 }
1137
1138 dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
1139 min_vol, max_vol);
1140
1141 return ret;
1142}
1143
Jack Pham4b00e702013-07-03 17:10:36 -07001144static int dwc3_hsusb_ldo_init(struct dwc3_msm *dwc, int init)
Manu Gautam60e01352012-05-29 09:00:34 +05301145{
1146 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301147
1148 if (!init) {
1149 regulator_set_voltage(dwc->hsusb_1p8, 0, USB_HSPHY_1P8_VOL_MAX);
1150 regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
1151 return 0;
1152 }
1153
1154 dwc->hsusb_3p3 = devm_regulator_get(dwc->dev, "HSUSB_3p3");
1155 if (IS_ERR(dwc->hsusb_3p3)) {
1156 dev_err(dwc->dev, "unable to get hsusb 3p3\n");
1157 return PTR_ERR(dwc->hsusb_3p3);
1158 }
1159
1160 rc = regulator_set_voltage(dwc->hsusb_3p3,
1161 USB_HSPHY_3P3_VOL_MIN, USB_HSPHY_3P3_VOL_MAX);
1162 if (rc) {
1163 dev_err(dwc->dev, "unable to set voltage for hsusb 3p3\n");
1164 return rc;
1165 }
1166 dwc->hsusb_1p8 = devm_regulator_get(dwc->dev, "HSUSB_1p8");
1167 if (IS_ERR(dwc->hsusb_1p8)) {
1168 dev_err(dwc->dev, "unable to get hsusb 1p8\n");
1169 rc = PTR_ERR(dwc->hsusb_1p8);
1170 goto devote_3p3;
1171 }
1172 rc = regulator_set_voltage(dwc->hsusb_1p8,
1173 USB_HSPHY_1P8_VOL_MIN, USB_HSPHY_1P8_VOL_MAX);
1174 if (rc) {
1175 dev_err(dwc->dev, "unable to set voltage for hsusb 1p8\n");
1176 goto devote_3p3;
1177 }
1178
1179 return 0;
1180
1181devote_3p3:
1182 regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
1183
1184 return rc;
1185}
1186
Jack Pham4b00e702013-07-03 17:10:36 -07001187static int dwc3_hsusb_ldo_enable(struct dwc3_msm *dwc, int on)
Manu Gautam60e01352012-05-29 09:00:34 +05301188{
1189 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301190
1191 dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
1192
1193 if (!on)
1194 goto disable_regulators;
1195
1196
1197 rc = regulator_set_optimum_mode(dwc->hsusb_1p8, USB_HSPHY_1P8_HPM_LOAD);
1198 if (rc < 0) {
1199 dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_1p8\n");
1200 return rc;
1201 }
1202
1203 rc = regulator_enable(dwc->hsusb_1p8);
1204 if (rc) {
1205 dev_err(dwc->dev, "Unable to enable HSUSB_1p8\n");
1206 goto put_1p8_lpm;
1207 }
1208
1209 rc = regulator_set_optimum_mode(dwc->hsusb_3p3, USB_HSPHY_3P3_HPM_LOAD);
1210 if (rc < 0) {
1211 dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_3p3\n");
1212 goto disable_1p8;
1213 }
1214
1215 rc = regulator_enable(dwc->hsusb_3p3);
1216 if (rc) {
1217 dev_err(dwc->dev, "Unable to enable HSUSB_3p3\n");
1218 goto put_3p3_lpm;
1219 }
1220
1221 return 0;
1222
1223disable_regulators:
1224 rc = regulator_disable(dwc->hsusb_3p3);
1225 if (rc)
1226 dev_err(dwc->dev, "Unable to disable HSUSB_3p3\n");
1227
1228put_3p3_lpm:
1229 rc = regulator_set_optimum_mode(dwc->hsusb_3p3, 0);
1230 if (rc < 0)
1231 dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_3p3\n");
1232
1233disable_1p8:
1234 rc = regulator_disable(dwc->hsusb_1p8);
1235 if (rc)
1236 dev_err(dwc->dev, "Unable to disable HSUSB_1p8\n");
1237
1238put_1p8_lpm:
1239 rc = regulator_set_optimum_mode(dwc->hsusb_1p8, 0);
1240 if (rc < 0)
1241 dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_1p8\n");
1242
1243 return rc < 0 ? rc : 0;
1244}
1245
1246/* SSPHY */
Jack Pham4b00e702013-07-03 17:10:36 -07001247static int dwc3_ssusb_config_vddcx(struct dwc3_msm *dwc, int high)
Manu Gautam60e01352012-05-29 09:00:34 +05301248{
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301249 int min_vol, max_vol, ret;
Manu Gautam60e01352012-05-29 09:00:34 +05301250
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301251 max_vol = dwc->vdd_high_vol_level;
1252 min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
Manu Gautam60e01352012-05-29 09:00:34 +05301253 ret = regulator_set_voltage(dwc->ssusb_vddcx, min_vol, max_vol);
1254 if (ret) {
1255 dev_err(dwc->dev, "unable to set voltage for SSUSB_VDDCX\n");
1256 return ret;
1257 }
1258
1259 dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
1260 min_vol, max_vol);
1261 return ret;
1262}
1263
1264/* 3.3v supply not needed for SS PHY */
Jack Pham4b00e702013-07-03 17:10:36 -07001265static int dwc3_ssusb_ldo_init(struct dwc3_msm *dwc, int init)
Manu Gautam60e01352012-05-29 09:00:34 +05301266{
1267 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301268
1269 if (!init) {
1270 regulator_set_voltage(dwc->ssusb_1p8, 0, USB_SSPHY_1P8_VOL_MAX);
1271 return 0;
1272 }
1273
1274 dwc->ssusb_1p8 = devm_regulator_get(dwc->dev, "SSUSB_1p8");
1275 if (IS_ERR(dwc->ssusb_1p8)) {
1276 dev_err(dwc->dev, "unable to get ssusb 1p8\n");
1277 return PTR_ERR(dwc->ssusb_1p8);
1278 }
1279 rc = regulator_set_voltage(dwc->ssusb_1p8,
1280 USB_SSPHY_1P8_VOL_MIN, USB_SSPHY_1P8_VOL_MAX);
1281 if (rc)
1282 dev_err(dwc->dev, "unable to set voltage for ssusb 1p8\n");
1283
1284 return rc;
1285}
1286
Jack Pham4b00e702013-07-03 17:10:36 -07001287static int dwc3_ssusb_ldo_enable(struct dwc3_msm *dwc, int on)
Manu Gautam60e01352012-05-29 09:00:34 +05301288{
1289 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301290
Jack Pham4b00e702013-07-03 17:10:36 -07001291 dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
Manu Gautam60e01352012-05-29 09:00:34 +05301292
1293 if (!on)
1294 goto disable_regulators;
1295
1296
1297 rc = regulator_set_optimum_mode(dwc->ssusb_1p8, USB_SSPHY_1P8_HPM_LOAD);
1298 if (rc < 0) {
1299 dev_err(dwc->dev, "Unable to set HPM of SSUSB_1p8\n");
1300 return rc;
1301 }
1302
1303 rc = regulator_enable(dwc->ssusb_1p8);
1304 if (rc) {
1305 dev_err(dwc->dev, "Unable to enable SSUSB_1p8\n");
1306 goto put_1p8_lpm;
1307 }
1308
1309 return 0;
1310
1311disable_regulators:
1312 rc = regulator_disable(dwc->ssusb_1p8);
1313 if (rc)
1314 dev_err(dwc->dev, "Unable to disable SSUSB_1p8\n");
1315
1316put_1p8_lpm:
1317 rc = regulator_set_optimum_mode(dwc->ssusb_1p8, 0);
1318 if (rc < 0)
1319 dev_err(dwc->dev, "Unable to set LPM of SSUSB_1p8\n");
1320
1321 return rc < 0 ? rc : 0;
1322}
1323
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001324/*
1325 * Config Global Distributed Switch Controller (GDSC)
1326 * to support controller power collapse
1327 */
Jack Pham80162462013-07-10 11:59:01 -07001328static int dwc3_msm_config_gdsc(struct dwc3_msm *mdwc, int on)
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001329{
1330 int ret = 0;
1331
Jack Pham80162462013-07-10 11:59:01 -07001332 if (IS_ERR(mdwc->dwc3_gdsc))
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001333 return 0;
1334
Jack Pham80162462013-07-10 11:59:01 -07001335 if (!mdwc->dwc3_gdsc) {
1336 mdwc->dwc3_gdsc = devm_regulator_get(mdwc->dev,
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001337 "USB3_GDSC");
Jack Pham80162462013-07-10 11:59:01 -07001338 if (IS_ERR(mdwc->dwc3_gdsc))
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001339 return 0;
1340 }
1341
1342 if (on) {
Jack Pham80162462013-07-10 11:59:01 -07001343 ret = regulator_enable(mdwc->dwc3_gdsc);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001344 if (ret) {
Jack Pham80162462013-07-10 11:59:01 -07001345 dev_err(mdwc->dev, "unable to enable usb3 gdsc\n");
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001346 return ret;
1347 }
1348 } else {
Jack Pham80162462013-07-10 11:59:01 -07001349 regulator_disable(mdwc->dwc3_gdsc);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001350 }
1351
1352 return 0;
1353}
1354
Jack Pham4b00e702013-07-03 17:10:36 -07001355static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301356{
1357 int ret = 0;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301358
1359 if (assert) {
1360 /* Using asynchronous block reset to the hardware */
1361 dev_dbg(mdwc->dev, "block_reset ASSERT\n");
1362 clk_disable_unprepare(mdwc->ref_clk);
1363 clk_disable_unprepare(mdwc->iface_clk);
1364 clk_disable_unprepare(mdwc->core_clk);
1365 ret = clk_reset(mdwc->core_clk, CLK_RESET_ASSERT);
1366 if (ret)
1367 dev_err(mdwc->dev, "dwc3 core_clk assert failed\n");
1368 } else {
1369 dev_dbg(mdwc->dev, "block_reset DEASSERT\n");
1370 ret = clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT);
1371 ndelay(200);
1372 clk_prepare_enable(mdwc->core_clk);
1373 clk_prepare_enable(mdwc->ref_clk);
1374 clk_prepare_enable(mdwc->iface_clk);
1375 if (ret)
1376 dev_err(mdwc->dev, "dwc3 core_clk deassert failed\n");
1377 }
1378
1379 return ret;
1380}
1381
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301382/* Reinitialize SSPHY parameters by overriding using QSCRATCH CR interface */
Jack Pham80162462013-07-10 11:59:01 -07001383static void dwc3_msm_ss_phy_reg_init(struct dwc3_msm *mdwc)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301384{
1385 u32 data = 0;
1386
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301387 /*
1388 * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
1389 * in HS mode instead of SS mode. Workaround it by asserting
1390 * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
1391 */
Jack Pham80162462013-07-10 11:59:01 -07001392 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x102D);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301393 data |= (1 << 7);
Jack Pham80162462013-07-10 11:59:01 -07001394 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x102D, data);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301395
Jack Pham80162462013-07-10 11:59:01 -07001396 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1010);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301397 data &= ~0xFF0;
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301398 data |= 0x20;
Jack Pham80162462013-07-10 11:59:01 -07001399 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1010, data);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301400
1401 /*
1402 * Fix RX Equalization setting as follows
1403 * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
1404 * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
1405 * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
1406 * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
1407 */
Jack Pham80162462013-07-10 11:59:01 -07001408 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1006);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301409 data &= ~(1 << 6);
1410 data |= (1 << 7);
1411 data &= ~(0x7 << 8);
1412 data |= (0x3 << 8);
1413 data |= (0x1 << 11);
Jack Pham80162462013-07-10 11:59:01 -07001414 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1006, data);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301415
1416 /*
1417 * Set EQ and TX launch amplitudes as follows
1418 * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
1419 * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
1420 * LANE0.TX_OVRD_DRV_LO.EN set to 1.
1421 */
Jack Pham80162462013-07-10 11:59:01 -07001422 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1002);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301423 data &= ~0x3F80;
Vijayavardhan Vennapusa9f74b1b2013-09-23 19:22:17 +05301424 if (ss_phy_override_deemphasis)
1425 mdwc->deemphasis_val = ss_phy_override_deemphasis;
1426 if (mdwc->deemphasis_val)
1427 data |= (mdwc->deemphasis_val << 7);
1428 else
1429 data |= (0x16 << 7);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301430 data &= ~0x7F;
1431 data |= (0x7F | (1 << 14));
Jack Pham80162462013-07-10 11:59:01 -07001432 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1002, data);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301433
Jack Pham63c8c702013-04-24 19:21:33 -07001434 /*
1435 * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
1436 * TX_FULL_SWING [26:20] amplitude to 127
1437 * TX_DEEMPH_3_5DB [13:8] to 22
1438 * LOS_BIAS [2:0] to 0x5
1439 */
Jack Pham80162462013-07-10 11:59:01 -07001440 dwc3_msm_write_readback(mdwc->base, SS_PHY_PARAM_CTRL_1,
Jack Pham63c8c702013-04-24 19:21:33 -07001441 0x07f03f07, 0x07f01605);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301442}
1443
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301444/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301445static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc,
1446 unsigned event_status)
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301447{
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301448 if (event_status == DWC3_CONTROLLER_POST_RESET_EVENT) {
1449 dwc3_msm_ss_phy_reg_init(mdwc);
1450 return;
1451 }
1452
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301453 /* SSPHY Initialization: Use ref_clk from pads and set its parameters */
Jack Pham80162462013-07-10 11:59:01 -07001454 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301455 msleep(30);
1456 /* Assert SSPHY reset */
Jack Pham80162462013-07-10 11:59:01 -07001457 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210082);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301458 usleep_range(2000, 2200);
1459 /* De-assert SSPHY reset - power and ref_clock must be ON */
Jack Pham80162462013-07-10 11:59:01 -07001460 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301461 usleep_range(2000, 2200);
1462 /* Ref clock must be stable now, enable ref clock for HS mode */
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301463 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x11210102);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301464 usleep_range(2000, 2200);
1465 /*
1466 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
1467 * and disable RETENTION (power-on default is ENABLED)
1468 */
Jack Pham80162462013-07-10 11:59:01 -07001469 dwc3_msm_write_reg(mdwc->base, HS_PHY_CTRL_REG, 0x5220bb2);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301470 usleep_range(2000, 2200);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301471 /* Set XHCI_REV bit (2) to 1 - XHCI version 1.0 */
1472 dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x4);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301473 /*
1474 * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
1475 * VBUS valid threshold, disconnect valid threshold, DC voltage level,
1476 * preempasis and rise/fall time.
1477 */
1478 if (override_phy_init)
Jack Pham80162462013-07-10 11:59:01 -07001479 mdwc->hsphy_init_seq = override_phy_init;
1480 if (mdwc->hsphy_init_seq)
1481 dwc3_msm_write_readback(mdwc->base,
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301482 PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
Jack Pham80162462013-07-10 11:59:01 -07001483 mdwc->hsphy_init_seq & 0x03FFFFFF);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301484
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301485 /*
1486 * Enable master clock for RAMs to allow BAM to access RAMs when
1487 * RAM clock gating is enabled via DWC3's GCTL. Otherwise issues
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301488 * are seen where RAM clocks get turned OFF in SS mode
1489 */
Jack Pham80162462013-07-10 11:59:01 -07001490 dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
1491 dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301492
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301493 /*
1494 * This is required to restore the POR value after userspace
1495 * is done with charger detection.
1496 */
Jack Pham80162462013-07-10 11:59:01 -07001497 mdwc->qscratch_ctl_val =
1498 dwc3_msm_read_reg(mdwc->base, QSCRATCH_CTRL_REG);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301499}
1500
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05301501static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
1502{
1503 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
1504
1505 switch (event) {
1506 case DWC3_CONTROLLER_ERROR_EVENT:
1507 dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
1508 dwc3_msm_dump_phy_info(mdwc);
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05301509 /*
1510 * schedule work for doing block reset for recovery from erratic
1511 * error event.
1512 */
1513 queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05301514 break;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301515 case DWC3_CONTROLLER_RESET_EVENT:
1516 dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
1517 dwc3_msm_qscratch_reg_init(mdwc, DWC3_CONTROLLER_RESET_EVENT);
1518 break;
1519 case DWC3_CONTROLLER_POST_RESET_EVENT:
1520 dev_dbg(mdwc->dev,
1521 "DWC3_CONTROLLER_POST_RESET_EVENT received\n");
1522 dwc3_msm_qscratch_reg_init(mdwc,
1523 DWC3_CONTROLLER_POST_RESET_EVENT);
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05301524 dwc->tx_fifo_size = mdwc->tx_fifo_size;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301525 break;
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05301526 default:
1527 dev_dbg(mdwc->dev, "unknown dwc3 event\n");
1528 break;
1529 }
1530}
1531
Jack Pham4b00e702013-07-03 17:10:36 -07001532static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301533{
Jack Pham4b00e702013-07-03 17:10:36 -07001534 struct dwc3_msm *mdwc = container_of(xceiv, struct dwc3_msm, ext_xceiv);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301535 int ret = 0;
1536
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301537 if (core_reset) {
Jack Pham4b00e702013-07-03 17:10:36 -07001538 ret = dwc3_msm_link_clk_reset(mdwc, 1);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301539 if (ret)
1540 return;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301541
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301542 usleep_range(1000, 1200);
Jack Pham4b00e702013-07-03 17:10:36 -07001543 ret = dwc3_msm_link_clk_reset(mdwc, 0);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301544 if (ret)
1545 return;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301546
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301547 usleep_range(10000, 12000);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301548 }
Manu Gautama302f612012-12-18 17:33:06 +05301549
1550 /* Reset the DBM */
Jack Pham62c19a42013-07-09 17:55:09 -07001551 dwc3_msm_dbm_soft_reset(mdwc, 1);
Manu Gautama302f612012-12-18 17:33:06 +05301552 usleep_range(1000, 1200);
Jack Pham62c19a42013-07-09 17:55:09 -07001553 dwc3_msm_dbm_soft_reset(mdwc, 0);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301554}
1555
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05301556static void dwc3_block_reset_usb_work(struct work_struct *w)
1557{
1558 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
1559 usb_block_reset_work);
1560
1561 dev_dbg(mdwc->dev, "%s\n", __func__);
1562
1563 dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
1564}
1565
Manu Gautam8c642812012-06-07 10:35:10 +05301566static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
1567{
1568 u32 chg_ctrl;
1569
1570 /* Turn off VDP_SRC */
1571 dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
1572 msleep(20);
1573
1574 /* Before proceeding make sure VDP_SRC is OFF */
1575 chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
1576 if (chg_ctrl & 0x3F)
1577 dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
1578 __func__, chg_ctrl);
1579 /*
1580 * Configure DM as current source, DP as current sink
1581 * and enable battery charging comparators.
1582 */
1583 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x34);
1584}
1585
Manu Gautama1e331d2013-02-07 14:55:05 +05301586static bool dwc3_chg_det_check_linestate(struct dwc3_msm *mdwc)
1587{
1588 u32 chg_det;
Jack Pham9b4606b2013-04-02 17:32:25 -07001589
1590 if (!prop_chg_detect)
1591 return false;
Manu Gautama1e331d2013-02-07 14:55:05 +05301592
1593 chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
Jack Pham9b4606b2013-04-02 17:32:25 -07001594 return chg_det & (3 << 8);
Manu Gautama1e331d2013-02-07 14:55:05 +05301595}
1596
Manu Gautam8c642812012-06-07 10:35:10 +05301597static bool dwc3_chg_det_check_output(struct dwc3_msm *mdwc)
1598{
1599 u32 chg_det;
1600 bool ret = false;
1601
1602 chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
1603 ret = chg_det & 1;
1604
1605 return ret;
1606}
1607
1608static void dwc3_chg_enable_primary_det(struct dwc3_msm *mdwc)
1609{
1610 /*
1611 * Configure DP as current source, DM as current sink
1612 * and enable battery charging comparators.
1613 */
1614 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x30);
1615}
1616
1617static inline bool dwc3_chg_check_dcd(struct dwc3_msm *mdwc)
1618{
1619 u32 chg_state;
1620 bool ret = false;
1621
1622 chg_state = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
1623 ret = chg_state & 2;
1624
1625 return ret;
1626}
1627
1628static inline void dwc3_chg_disable_dcd(struct dwc3_msm *mdwc)
1629{
1630 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x0);
1631}
1632
1633static inline void dwc3_chg_enable_dcd(struct dwc3_msm *mdwc)
1634{
1635 /* Data contact detection enable, DCDENB */
1636 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x2);
1637}
1638
1639static void dwc3_chg_block_reset(struct dwc3_msm *mdwc)
1640{
1641 u32 chg_ctrl;
1642
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301643 dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
1644 mdwc->qscratch_ctl_val);
Manu Gautam8c642812012-06-07 10:35:10 +05301645 /* Clear charger detecting control bits */
1646 dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
1647
1648 /* Clear alt interrupt latch and enable bits */
1649 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1650 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x0);
1651
1652 udelay(100);
1653
1654 /* Before proceeding make sure charger block is RESET */
1655 chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
1656 if (chg_ctrl & 0x3F)
1657 dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
1658 __func__, chg_ctrl);
1659}
1660
1661static const char *chg_to_string(enum dwc3_chg_type chg_type)
1662{
1663 switch (chg_type) {
Manu Gautama1e331d2013-02-07 14:55:05 +05301664 case DWC3_SDP_CHARGER: return "USB_SDP_CHARGER";
1665 case DWC3_DCP_CHARGER: return "USB_DCP_CHARGER";
1666 case DWC3_CDP_CHARGER: return "USB_CDP_CHARGER";
1667 case DWC3_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301668 case DWC3_FLOATED_CHARGER: return "USB_FLOATED_CHARGER";
Vijayavardhan Vennapusaa04e0c92013-06-04 12:37:10 +05301669 default: return "UNKNOWN_CHARGER";
Manu Gautam8c642812012-06-07 10:35:10 +05301670 }
1671}
1672
1673#define DWC3_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1674#define DWC3_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1675#define DWC3_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
1676#define DWC3_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
1677
1678static void dwc3_chg_detect_work(struct work_struct *w)
1679{
1680 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, chg_work.work);
1681 bool is_dcd = false, tmout, vout;
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301682 static bool dcd;
Manu Gautam8c642812012-06-07 10:35:10 +05301683 unsigned long delay;
1684
1685 dev_dbg(mdwc->dev, "chg detection work\n");
1686 switch (mdwc->chg_state) {
1687 case USB_CHG_STATE_UNDEFINED:
1688 dwc3_chg_block_reset(mdwc);
1689 dwc3_chg_enable_dcd(mdwc);
1690 mdwc->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1691 mdwc->dcd_retries = 0;
1692 delay = DWC3_CHG_DCD_POLL_TIME;
1693 break;
1694 case USB_CHG_STATE_WAIT_FOR_DCD:
1695 is_dcd = dwc3_chg_check_dcd(mdwc);
1696 tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES;
1697 if (is_dcd || tmout) {
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301698 if (is_dcd)
1699 dcd = true;
1700 else
1701 dcd = false;
Manu Gautam8c642812012-06-07 10:35:10 +05301702 dwc3_chg_disable_dcd(mdwc);
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301703 usleep_range(1000, 1200);
Manu Gautama1e331d2013-02-07 14:55:05 +05301704 if (dwc3_chg_det_check_linestate(mdwc)) {
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301705 mdwc->charger.chg_type =
Manu Gautama1e331d2013-02-07 14:55:05 +05301706 DWC3_PROPRIETARY_CHARGER;
1707 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1708 delay = 0;
1709 break;
1710 }
Manu Gautam8c642812012-06-07 10:35:10 +05301711 dwc3_chg_enable_primary_det(mdwc);
1712 delay = DWC3_CHG_PRIMARY_DET_TIME;
1713 mdwc->chg_state = USB_CHG_STATE_DCD_DONE;
1714 } else {
1715 delay = DWC3_CHG_DCD_POLL_TIME;
1716 }
1717 break;
1718 case USB_CHG_STATE_DCD_DONE:
1719 vout = dwc3_chg_det_check_output(mdwc);
1720 if (vout) {
1721 dwc3_chg_enable_secondary_det(mdwc);
1722 delay = DWC3_CHG_SECONDARY_DET_TIME;
1723 mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1724 } else {
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301725 /*
1726 * Detect floating charger only if propreitary
1727 * charger detection is enabled.
1728 */
1729 if (!dcd && prop_chg_detect)
1730 mdwc->charger.chg_type =
1731 DWC3_FLOATED_CHARGER;
1732 else
1733 mdwc->charger.chg_type = DWC3_SDP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301734 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1735 delay = 0;
1736 }
1737 break;
1738 case USB_CHG_STATE_PRIMARY_DONE:
1739 vout = dwc3_chg_det_check_output(mdwc);
1740 if (vout)
Manu Gautama1e331d2013-02-07 14:55:05 +05301741 mdwc->charger.chg_type = DWC3_DCP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301742 else
Manu Gautama1e331d2013-02-07 14:55:05 +05301743 mdwc->charger.chg_type = DWC3_CDP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301744 mdwc->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1745 /* fall through */
1746 case USB_CHG_STATE_SECONDARY_DONE:
1747 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1748 /* fall through */
1749 case USB_CHG_STATE_DETECTED:
1750 dwc3_chg_block_reset(mdwc);
Manu Gautama48296e2012-12-05 17:37:56 +05301751 /* Enable VDP_SRC */
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301752 if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
Manu Gautama48296e2012-12-05 17:37:56 +05301753 dwc3_msm_write_readback(mdwc->base,
1754 CHARGING_DET_CTRL_REG, 0x1F, 0x10);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301755 if (mdwc->ext_chg_opened) {
1756 init_completion(&mdwc->ext_chg_wait);
1757 mdwc->ext_chg_active = true;
1758 }
1759 }
Manu Gautam8c642812012-06-07 10:35:10 +05301760 dev_dbg(mdwc->dev, "chg_type = %s\n",
1761 chg_to_string(mdwc->charger.chg_type));
1762 mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
1763 &mdwc->charger);
1764 return;
1765 default:
1766 return;
1767 }
1768
1769 queue_delayed_work(system_nrt_wq, &mdwc->chg_work, delay);
1770}
1771
1772static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)
1773{
Jack Phamea382b72013-07-09 17:50:20 -07001774 struct dwc3_msm *mdwc = container_of(charger, struct dwc3_msm, charger);
Manu Gautam8c642812012-06-07 10:35:10 +05301775
1776 if (start == false) {
Jack Pham9354c6a2012-12-20 19:19:32 -08001777 dev_dbg(mdwc->dev, "canceling charging detection work\n");
Manu Gautam8c642812012-06-07 10:35:10 +05301778 cancel_delayed_work_sync(&mdwc->chg_work);
1779 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1780 charger->chg_type = DWC3_INVALID_CHARGER;
1781 return;
1782 }
1783
1784 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1785 charger->chg_type = DWC3_INVALID_CHARGER;
1786 queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
1787}
1788
Manu Gautamb5067272012-07-02 09:53:41 +05301789static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
1790{
Manu Gautam2617deb2012-08-31 17:50:06 -07001791 int ret;
Manu Gautama48296e2012-12-05 17:37:56 +05301792 bool dcp;
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301793 bool host_bus_suspend;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301794 bool host_ss_active;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301795 bool host_ss_suspend;
Manu Gautam2617deb2012-08-31 17:50:06 -07001796
Manu Gautamb5067272012-07-02 09:53:41 +05301797 dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
1798
1799 if (atomic_read(&mdwc->in_lpm)) {
1800 dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
1801 return 0;
1802 }
1803
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301804 host_ss_active = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC) & PORT_PE;
Manu Gautama48296e2012-12-05 17:37:56 +05301805 if (mdwc->hs_phy_irq)
1806 disable_irq(mdwc->hs_phy_irq);
1807
Manu Gautam98013c22012-11-20 17:42:42 +05301808 if (cancel_delayed_work_sync(&mdwc->chg_work))
1809 dev_dbg(mdwc->dev, "%s: chg_work was pending\n", __func__);
1810 if (mdwc->chg_state != USB_CHG_STATE_DETECTED) {
1811 /* charger detection wasn't complete; re-init flags */
1812 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1813 mdwc->charger.chg_type = DWC3_INVALID_CHARGER;
Manu Gautama48296e2012-12-05 17:37:56 +05301814 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG,
1815 0x37, 0x0);
Manu Gautam98013c22012-11-20 17:42:42 +05301816 }
1817
Manu Gautam840f4fe2013-04-16 16:50:30 +05301818 dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
Vijayavardhan Vennapusac4974862013-07-23 17:36:37 +05301819 (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
1820 (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301821 host_bus_suspend = mdwc->host_mode == 1;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301822 host_ss_suspend = host_bus_suspend && host_ss_active;
Manu Gautam377821c2012-09-28 16:53:24 +05301823
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301824 if (!dcp && !host_bus_suspend)
1825 dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
1826 mdwc->qscratch_ctl_val);
1827
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05301828 /* Sequence to put SSPHY in low power state:
1829 * 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
1830 * 2. Clear REF_USE_PAD in SS_PHY_CTRL_REG
1831 * 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
1832 * 4. Disable SSPHY ref clk
1833 */
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301834 if (!host_ss_suspend) {
1835 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
1836 0x0);
1837 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
1838 0x0);
1839 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05301840 (1 << 26));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301841 }
Manu Gautam377821c2012-09-28 16:53:24 +05301842 usleep_range(1000, 1200);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301843 if (!host_ss_suspend)
1844 clk_disable_unprepare(mdwc->ref_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05301845
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301846 if (host_bus_suspend) {
1847 /* Sequence for host bus suspend case:
1848 * 1. Set suspend and sleep bits in GUSB2PHYCONFIG reg
1849 * 2. Clear interrupt latch register and enable BSV, ID HV intr
1850 * 3. Enable DP and DM HV interrupts in ALT_INTERRUPT_EN_REG
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301851 */
1852 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
1853 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
1854 0x00000140);
1855 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1856 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1857 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1858 0x18000, 0x18000);
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301859 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0xFC0);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301860 udelay(5);
1861 } else {
1862 /* Sequence to put hardware in low power state:
1863 * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
1864 * 2. Clear charger detection control fields (performed above)
1865 * 3. SUSPEND PHY and turn OFF core clock after some delay
1866 * 4. Clear interrupt latch register and enable BSV, ID HV intr
1867 * 5. Enable PHY retention
1868 */
1869 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000,
1870 0x1000);
1871 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1872 0xC00000, 0x800000);
1873 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1874 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1875 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1876 0x18000, 0x18000);
1877 if (!dcp)
1878 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1879 0x2, 0x0);
1880 }
Manu Gautam377821c2012-09-28 16:53:24 +05301881
1882 /* make sure above writes are completed before turning off clocks */
1883 wmb();
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001884
1885 /* remove vote for controller power collapse */
1886 if (!host_bus_suspend)
1887 dwc3_msm_config_gdsc(mdwc, 0);
1888
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301889 if (!host_ss_suspend) {
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301890 clk_disable_unprepare(mdwc->core_clk);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301891 mdwc->lpm_flags |= MDWC3_PHY_REF_AND_CORECLK_OFF;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301892 }
Manu Gautam377821c2012-09-28 16:53:24 +05301893 clk_disable_unprepare(mdwc->iface_clk);
1894
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301895 if (!host_bus_suspend)
Jack Pham22698b82013-02-13 17:45:06 -08001896 clk_disable_unprepare(mdwc->utmi_clk);
1897
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301898 if (!host_bus_suspend) {
Jack Pham22698b82013-02-13 17:45:06 -08001899 /* USB PHY no more requires TCXO */
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05301900 clk_disable_unprepare(mdwc->xo_clk);
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301901 mdwc->lpm_flags |= MDWC3_TCXO_SHUTDOWN;
Jack Pham22698b82013-02-13 17:45:06 -08001902 }
Manu Gautamb5067272012-07-02 09:53:41 +05301903
Manu Gautam2617deb2012-08-31 17:50:06 -07001904 if (mdwc->bus_perf_client) {
1905 ret = msm_bus_scale_client_update_request(
1906 mdwc->bus_perf_client, 0);
1907 if (ret)
1908 dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
1909 }
1910
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301911 if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
1912 !host_bus_suspend)
Jack Pham4b00e702013-07-03 17:10:36 -07001913 dwc3_hsusb_ldo_enable(mdwc, 0);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05301914
Jack Pham4b00e702013-07-03 17:10:36 -07001915 dwc3_ssusb_ldo_enable(mdwc, 0);
1916 dwc3_ssusb_config_vddcx(mdwc, 0);
Manu Gautam840f4fe2013-04-16 16:50:30 +05301917 if (!host_bus_suspend && !dcp)
Jack Pham4b00e702013-07-03 17:10:36 -07001918 dwc3_hsusb_config_vddcx(mdwc, 0);
Jack Pham924cbe872013-07-10 16:40:55 -07001919 pm_relax(mdwc->dev);
Manu Gautamb5067272012-07-02 09:53:41 +05301920 atomic_set(&mdwc->in_lpm, 1);
Manu Gautam377821c2012-09-28 16:53:24 +05301921
Manu Gautamb5067272012-07-02 09:53:41 +05301922 dev_info(mdwc->dev, "DWC3 in low power mode\n");
1923
Manu Gautam840f4fe2013-04-16 16:50:30 +05301924 if (mdwc->hs_phy_irq) {
Manu Gautama48296e2012-12-05 17:37:56 +05301925 enable_irq(mdwc->hs_phy_irq);
Manu Gautam840f4fe2013-04-16 16:50:30 +05301926 /* with DCP we dont require wakeup using HS_PHY_IRQ */
1927 if (dcp)
1928 disable_irq_wake(mdwc->hs_phy_irq);
1929 }
Manu Gautama48296e2012-12-05 17:37:56 +05301930
Manu Gautamb5067272012-07-02 09:53:41 +05301931 return 0;
1932}
1933
1934static int dwc3_msm_resume(struct dwc3_msm *mdwc)
1935{
Manu Gautam2617deb2012-08-31 17:50:06 -07001936 int ret;
Manu Gautama48296e2012-12-05 17:37:56 +05301937 bool dcp;
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301938 bool host_bus_suspend;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301939 bool resume_from_core_clk_off = false;
Manu Gautam2617deb2012-08-31 17:50:06 -07001940
Manu Gautamb5067272012-07-02 09:53:41 +05301941 dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
1942
1943 if (!atomic_read(&mdwc->in_lpm)) {
1944 dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__);
1945 return 0;
1946 }
1947
Jack Pham924cbe872013-07-10 16:40:55 -07001948 pm_stay_awake(mdwc->dev);
Manu Gautam377821c2012-09-28 16:53:24 +05301949
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301950 if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
1951 resume_from_core_clk_off = true;
1952
Manu Gautam2617deb2012-08-31 17:50:06 -07001953 if (mdwc->bus_perf_client) {
1954 ret = msm_bus_scale_client_update_request(
1955 mdwc->bus_perf_client, 1);
1956 if (ret)
1957 dev_err(mdwc->dev, "Failed to vote for bus scaling\n");
1958 }
1959
Manu Gautam840f4fe2013-04-16 16:50:30 +05301960 dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
Vijayavardhan Vennapusac4974862013-07-23 17:36:37 +05301961 (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
1962 (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301963 host_bus_suspend = mdwc->host_mode == 1;
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301964
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301965 if (mdwc->lpm_flags & MDWC3_TCXO_SHUTDOWN) {
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301966 /* Vote for TCXO while waking up USB HSPHY */
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05301967 ret = clk_prepare_enable(mdwc->xo_clk);
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301968 if (ret)
1969 dev_err(mdwc->dev, "%s failed to vote TCXO buffer%d\n",
1970 __func__, ret);
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301971 mdwc->lpm_flags &= ~MDWC3_TCXO_SHUTDOWN;
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301972 }
1973
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001974 /* add vote for controller power collapse */
1975 if (!host_bus_suspend)
1976 dwc3_msm_config_gdsc(mdwc, 1);
1977
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301978 if (!host_bus_suspend)
1979 clk_prepare_enable(mdwc->utmi_clk);
1980
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301981 if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
1982 !host_bus_suspend)
Jack Pham4b00e702013-07-03 17:10:36 -07001983 dwc3_hsusb_ldo_enable(mdwc, 1);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05301984
Jack Pham4b00e702013-07-03 17:10:36 -07001985 dwc3_ssusb_ldo_enable(mdwc, 1);
1986 dwc3_ssusb_config_vddcx(mdwc, 1);
Jack Pham22698b82013-02-13 17:45:06 -08001987
Manu Gautam840f4fe2013-04-16 16:50:30 +05301988 if (!host_bus_suspend && !dcp)
Jack Pham4b00e702013-07-03 17:10:36 -07001989 dwc3_hsusb_config_vddcx(mdwc, 1);
Jack Pham22698b82013-02-13 17:45:06 -08001990
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301991 if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
1992 clk_prepare_enable(mdwc->ref_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05301993 usleep_range(1000, 1200);
1994
Manu Gautam3e9ad352012-08-16 14:44:47 -07001995 clk_prepare_enable(mdwc->iface_clk);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301996 if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF) {
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301997 clk_prepare_enable(mdwc->core_clk);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301998 mdwc->lpm_flags &= ~MDWC3_PHY_REF_AND_CORECLK_OFF;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301999 }
Manu Gautam377821c2012-09-28 16:53:24 +05302000
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302001 if (host_bus_suspend) {
2002 /* Disable HV interrupt */
2003 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
2004 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
2005 0x18000, 0x0);
2006 /* Clear interrupt latch register */
2007 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0x000);
Manu Gautam377821c2012-09-28 16:53:24 +05302008
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302009 /* Disable DP and DM HV interrupt */
2010 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302011 } else {
2012 /* Disable HV interrupt */
2013 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
2014 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
2015 0x18000, 0x0);
2016 /* Disable Retention */
2017 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
2018
2019 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
2020 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
2021 0xF0000000);
2022 /* 10usec delay required before de-asserting PHY RESET */
2023 udelay(10);
2024 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
2025 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) &
2026 0x7FFFFFFF);
2027
2028 /* Bring PHY out of suspend */
2029 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000,
2030 0x0);
2031
2032 }
Manu Gautamb5067272012-07-02 09:53:41 +05302033
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302034 if (resume_from_core_clk_off) {
2035 /* Assert SS PHY RESET */
2036 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302037 (1 << 7));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302038 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302039 (1 << 28));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302040 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302041 (1 << 8));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302042 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
2043 0x0);
2044 /* 10usec delay required before de-asserting SS PHY RESET */
2045 udelay(10);
2046 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
2047 0x0);
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302048
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302049 /*
2050 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
2051 * the internal registers to default values.
2052 */
2053 dwc3_msm_ss_phy_reg_init(mdwc);
2054 }
Manu Gautamb5067272012-07-02 09:53:41 +05302055 atomic_set(&mdwc->in_lpm, 0);
Manu Gautam377821c2012-09-28 16:53:24 +05302056
2057 /* match disable_irq call from isr */
2058 if (mdwc->lpm_irq_seen && mdwc->hs_phy_irq) {
2059 enable_irq(mdwc->hs_phy_irq);
2060 mdwc->lpm_irq_seen = false;
2061 }
Manu Gautam840f4fe2013-04-16 16:50:30 +05302062 /* it must DCP disconnect, re-enable HS_PHY wakeup IRQ */
2063 if (mdwc->hs_phy_irq && dcp)
2064 enable_irq_wake(mdwc->hs_phy_irq);
Manu Gautam377821c2012-09-28 16:53:24 +05302065
Manu Gautamb5067272012-07-02 09:53:41 +05302066 dev_info(mdwc->dev, "DWC3 exited from low power mode\n");
2067
2068 return 0;
2069}
2070
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302071static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc)
2072{
2073 unsigned long t;
2074
2075 /*
2076 * Defer next cable connect event till external charger
2077 * detection is completed.
2078 */
2079
2080 if (mdwc->ext_chg_active && (mdwc->ext_xceiv.bsv ||
2081 !mdwc->ext_xceiv.id)) {
2082
2083 dev_dbg(mdwc->dev, "before ext chg wait\n");
2084
2085 t = wait_for_completion_timeout(&mdwc->ext_chg_wait,
2086 msecs_to_jiffies(3000));
2087 if (!t)
2088 dev_err(mdwc->dev, "ext chg wait timeout\n");
2089 else
2090 dev_dbg(mdwc->dev, "ext chg wait done\n");
2091 }
2092
2093}
2094
Manu Gautamb5067272012-07-02 09:53:41 +05302095static void dwc3_resume_work(struct work_struct *w)
2096{
2097 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
2098 resume_work.work);
2099
2100 dev_dbg(mdwc->dev, "%s: dwc3 resume work\n", __func__);
2101 /* handle any event that was queued while work was already running */
2102 if (!atomic_read(&mdwc->in_lpm)) {
2103 dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302104 if (mdwc->otg_xceiv) {
2105 dwc3_wait_for_ext_chg_done(mdwc);
Manu Gautamb5067272012-07-02 09:53:41 +05302106 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2107 DWC3_EVENT_XCEIV_STATE);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302108 }
Manu Gautamb5067272012-07-02 09:53:41 +05302109 return;
2110 }
2111
2112 /* bail out if system resume in process, else initiate RESUME */
2113 if (atomic_read(&mdwc->pm_suspended)) {
2114 mdwc->resume_pending = true;
2115 } else {
2116 pm_runtime_get_sync(mdwc->dev);
2117 if (mdwc->otg_xceiv)
2118 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2119 DWC3_EVENT_PHY_RESUME);
Manu Gautambb825d72013-03-12 16:25:42 +05302120 pm_runtime_put_noidle(mdwc->dev);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302121 if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability)) {
2122 dwc3_wait_for_ext_chg_done(mdwc);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302123 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2124 DWC3_EVENT_XCEIV_STATE);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302125 }
Manu Gautamb5067272012-07-02 09:53:41 +05302126 }
2127}
2128
Jack Pham0fc12332012-11-19 13:14:22 -08002129static u32 debug_id = true, debug_bsv, debug_connect;
Manu Gautamb5067272012-07-02 09:53:41 +05302130
2131static int dwc3_connect_show(struct seq_file *s, void *unused)
2132{
2133 if (debug_connect)
2134 seq_printf(s, "true\n");
2135 else
2136 seq_printf(s, "false\n");
2137
2138 return 0;
2139}
2140
2141static int dwc3_connect_open(struct inode *inode, struct file *file)
2142{
2143 return single_open(file, dwc3_connect_show, inode->i_private);
2144}
2145
2146static ssize_t dwc3_connect_write(struct file *file, const char __user *ubuf,
2147 size_t count, loff_t *ppos)
2148{
2149 struct seq_file *s = file->private_data;
2150 struct dwc3_msm *mdwc = s->private;
2151 char buf[8];
2152
2153 memset(buf, 0x00, sizeof(buf));
2154
2155 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
2156 return -EFAULT;
2157
2158 if (!strncmp(buf, "enable", 6) || !strncmp(buf, "true", 4)) {
2159 debug_connect = true;
2160 } else {
2161 debug_connect = debug_bsv = false;
2162 debug_id = true;
2163 }
2164
2165 mdwc->ext_xceiv.bsv = debug_bsv;
2166 mdwc->ext_xceiv.id = debug_id ? DWC3_ID_FLOAT : DWC3_ID_GROUND;
2167
2168 if (atomic_read(&mdwc->in_lpm)) {
2169 dev_dbg(mdwc->dev, "%s: calling resume_work\n", __func__);
2170 dwc3_resume_work(&mdwc->resume_work.work);
2171 } else {
2172 dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
2173 if (mdwc->otg_xceiv)
2174 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2175 DWC3_EVENT_XCEIV_STATE);
2176 }
2177
2178 return count;
2179}
2180
2181const struct file_operations dwc3_connect_fops = {
2182 .open = dwc3_connect_open,
2183 .read = seq_read,
2184 .write = dwc3_connect_write,
2185 .llseek = seq_lseek,
2186 .release = single_release,
2187};
2188
2189static struct dentry *dwc3_debugfs_root;
2190
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05302191static void dwc3_msm_debugfs_init(struct dwc3_msm *mdwc)
Manu Gautamb5067272012-07-02 09:53:41 +05302192{
2193 dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
2194
2195 if (!dwc3_debugfs_root || IS_ERR(dwc3_debugfs_root))
2196 return;
2197
2198 if (!debugfs_create_bool("id", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
Vijayavardhan Vennapusa54be1d62012-10-06 18:32:06 +05302199 &debug_id))
Manu Gautamb5067272012-07-02 09:53:41 +05302200 goto error;
2201
2202 if (!debugfs_create_bool("bsv", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
Vijayavardhan Vennapusa54be1d62012-10-06 18:32:06 +05302203 &debug_bsv))
Manu Gautamb5067272012-07-02 09:53:41 +05302204 goto error;
2205
2206 if (!debugfs_create_file("connect", S_IRUGO | S_IWUSR,
2207 dwc3_debugfs_root, mdwc, &dwc3_connect_fops))
2208 goto error;
2209
2210 return;
2211
2212error:
2213 debugfs_remove_recursive(dwc3_debugfs_root);
2214}
Manu Gautam8c642812012-06-07 10:35:10 +05302215
Manu Gautam377821c2012-09-28 16:53:24 +05302216static irqreturn_t msm_dwc3_irq(int irq, void *data)
2217{
2218 struct dwc3_msm *mdwc = data;
2219
2220 if (atomic_read(&mdwc->in_lpm)) {
2221 dev_dbg(mdwc->dev, "%s received in LPM\n", __func__);
2222 mdwc->lpm_irq_seen = true;
2223 disable_irq_nosync(irq);
2224 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
2225 } else {
2226 pr_info_ratelimited("%s: IRQ outside LPM\n", __func__);
2227 }
2228
2229 return IRQ_HANDLED;
2230}
2231
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302232static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
2233 enum power_supply_property psp,
2234 union power_supply_propval *val)
2235{
2236 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
2237 usb_psy);
2238 switch (psp) {
2239 case POWER_SUPPLY_PROP_SCOPE:
2240 val->intval = mdwc->host_mode;
2241 break;
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302242 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2243 val->intval = mdwc->voltage_max;
2244 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302245 case POWER_SUPPLY_PROP_CURRENT_MAX:
2246 val->intval = mdwc->current_max;
2247 break;
2248 case POWER_SUPPLY_PROP_PRESENT:
2249 val->intval = mdwc->vbus_active;
2250 break;
2251 case POWER_SUPPLY_PROP_ONLINE:
2252 val->intval = mdwc->online;
2253 break;
Manu Gautamfa40cae2013-03-01 16:37:12 +05302254 case POWER_SUPPLY_PROP_TYPE:
2255 val->intval = psy->type;
2256 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302257 default:
2258 return -EINVAL;
2259 }
2260 return 0;
2261}
2262
2263static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
2264 enum power_supply_property psp,
2265 const union power_supply_propval *val)
2266{
2267 static bool init;
2268 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
2269 usb_psy);
2270
2271 switch (psp) {
2272 case POWER_SUPPLY_PROP_SCOPE:
2273 mdwc->host_mode = val->intval;
2274 break;
2275 /* Process PMIC notification in PRESENT prop */
2276 case POWER_SUPPLY_PROP_PRESENT:
2277 dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
Jack Pham9354c6a2012-12-20 19:19:32 -08002278 if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
2279 (mdwc->ext_xceiv.otg_capability || !init)) {
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302280 mdwc->ext_xceiv.bsv = val->intval;
Manu Gautamf71d9cb2013-02-07 13:52:12 +05302281 queue_delayed_work(system_nrt_wq,
Jack Pham4d91aab2013-03-08 10:02:16 -08002282 &mdwc->resume_work, 20);
Jack Pham9354c6a2012-12-20 19:19:32 -08002283
2284 if (!init)
2285 init = true;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302286 }
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302287 mdwc->vbus_active = val->intval;
2288 break;
2289 case POWER_SUPPLY_PROP_ONLINE:
2290 mdwc->online = val->intval;
2291 break;
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302292 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2293 mdwc->voltage_max = val->intval;
2294 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302295 case POWER_SUPPLY_PROP_CURRENT_MAX:
2296 mdwc->current_max = val->intval;
2297 break;
Manu Gautamfa40cae2013-03-01 16:37:12 +05302298 case POWER_SUPPLY_PROP_TYPE:
2299 psy->type = val->intval;
2300 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302301 default:
2302 return -EINVAL;
2303 }
2304
2305 power_supply_changed(&mdwc->usb_psy);
2306 return 0;
2307}
2308
Jack Pham9354c6a2012-12-20 19:19:32 -08002309static void dwc3_msm_external_power_changed(struct power_supply *psy)
2310{
2311 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm, usb_psy);
2312 union power_supply_propval ret = {0,};
2313
2314 if (!mdwc->ext_vbus_psy)
2315 mdwc->ext_vbus_psy = power_supply_get_by_name("ext-vbus");
2316
2317 if (!mdwc->ext_vbus_psy) {
2318 pr_err("%s: Unable to get ext_vbus power_supply\n", __func__);
2319 return;
2320 }
2321
2322 mdwc->ext_vbus_psy->get_property(mdwc->ext_vbus_psy,
2323 POWER_SUPPLY_PROP_ONLINE, &ret);
2324 if (ret.intval) {
2325 dwc3_start_chg_det(&mdwc->charger, false);
2326 mdwc->ext_vbus_psy->get_property(mdwc->ext_vbus_psy,
2327 POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
2328 power_supply_set_current_limit(&mdwc->usb_psy, ret.intval);
2329 }
2330
2331 power_supply_set_online(&mdwc->usb_psy, ret.intval);
2332 power_supply_changed(&mdwc->usb_psy);
2333}
2334
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302335static int
2336dwc3_msm_property_is_writeable(struct power_supply *psy,
2337 enum power_supply_property psp)
2338{
2339 switch (psp) {
2340 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2341 return 1;
2342 default:
2343 break;
2344 }
2345
2346 return 0;
2347}
2348
Jack Pham9354c6a2012-12-20 19:19:32 -08002349
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302350static char *dwc3_msm_pm_power_supplied_to[] = {
2351 "battery",
2352};
2353
2354static enum power_supply_property dwc3_msm_pm_power_props_usb[] = {
2355 POWER_SUPPLY_PROP_PRESENT,
2356 POWER_SUPPLY_PROP_ONLINE,
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302357 POWER_SUPPLY_PROP_VOLTAGE_MAX,
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302358 POWER_SUPPLY_PROP_CURRENT_MAX,
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302359 POWER_SUPPLY_PROP_TYPE,
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302360 POWER_SUPPLY_PROP_SCOPE,
2361};
2362
Jack Phamfadd6432012-12-07 19:03:41 -08002363static void dwc3_init_adc_work(struct work_struct *w);
2364
Jack Phamb7209152013-07-03 17:04:53 -07002365static void dwc3_ext_notify_online(void *ctx, int on)
Jack Phamfadd6432012-12-07 19:03:41 -08002366{
Jack Phamb7209152013-07-03 17:04:53 -07002367 struct dwc3_msm *mdwc = ctx;
Jack Phamf12b7e12012-12-28 14:27:26 -08002368 bool notify_otg = false;
Jack Phamfadd6432012-12-07 19:03:41 -08002369
2370 if (!mdwc) {
2371 pr_err("%s: DWC3 driver already removed\n", __func__);
2372 return;
2373 }
2374
2375 dev_dbg(mdwc->dev, "notify %s%s\n", on ? "" : "dis", "connected");
2376
Jack Pham9354c6a2012-12-20 19:19:32 -08002377 if (!mdwc->ext_vbus_psy)
2378 mdwc->ext_vbus_psy = power_supply_get_by_name("ext-vbus");
2379
2380 mdwc->ext_inuse = on;
Jack Phamf12b7e12012-12-28 14:27:26 -08002381 if (on) {
2382 /* force OTG to exit B-peripheral state */
2383 mdwc->ext_xceiv.bsv = false;
2384 notify_otg = true;
Jack Pham9354c6a2012-12-20 19:19:32 -08002385 dwc3_start_chg_det(&mdwc->charger, false);
Jack Phamf12b7e12012-12-28 14:27:26 -08002386 } else {
2387 /* external client offline; tell OTG about cached ID/BSV */
2388 if (mdwc->ext_xceiv.id != mdwc->id_state) {
2389 mdwc->ext_xceiv.id = mdwc->id_state;
2390 notify_otg = true;
2391 }
2392
2393 mdwc->ext_xceiv.bsv = mdwc->vbus_active;
2394 notify_otg |= mdwc->vbus_active;
2395 }
Jack Pham9354c6a2012-12-20 19:19:32 -08002396
2397 if (mdwc->ext_vbus_psy)
2398 power_supply_set_present(mdwc->ext_vbus_psy, on);
Jack Phamf12b7e12012-12-28 14:27:26 -08002399
2400 if (notify_otg)
2401 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
Jack Phamfadd6432012-12-07 19:03:41 -08002402}
2403
Jack Pham0cca9412013-03-08 13:22:42 -08002404static void dwc3_id_work(struct work_struct *w)
Jack Phamfadd6432012-12-07 19:03:41 -08002405{
Jack Pham0cca9412013-03-08 13:22:42 -08002406 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, id_work);
Jack Pham5c585062013-03-25 18:39:12 -07002407 int ret;
Jack Phamfadd6432012-12-07 19:03:41 -08002408
Jack Pham0cca9412013-03-08 13:22:42 -08002409 /* Give external client a chance to handle */
Jack Pham5c585062013-03-25 18:39:12 -07002410 if (!mdwc->ext_inuse && usb_ext) {
2411 if (mdwc->pmic_id_irq)
2412 disable_irq(mdwc->pmic_id_irq);
2413
2414 ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
Jack Phamb7209152013-07-03 17:04:53 -07002415 dwc3_ext_notify_online, mdwc);
Jack Pham5c585062013-03-25 18:39:12 -07002416 dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
2417 __func__, ret);
2418
2419 if (mdwc->pmic_id_irq) {
Vijayavardhan Vennapusa242eaf02013-07-01 12:39:31 +05302420 unsigned long flags;
2421 local_irq_save(flags);
Jack Pham5c585062013-03-25 18:39:12 -07002422 /* ID may have changed while IRQ disabled; update it */
2423 mdwc->id_state = !!irq_read_line(mdwc->pmic_id_irq);
Vijayavardhan Vennapusa242eaf02013-07-01 12:39:31 +05302424 local_irq_restore(flags);
Jack Pham5c585062013-03-25 18:39:12 -07002425 enable_irq(mdwc->pmic_id_irq);
Jack Pham0cca9412013-03-08 13:22:42 -08002426 }
Jack Pham5c585062013-03-25 18:39:12 -07002427
2428 mdwc->ext_inuse = (ret == 0);
Jack Pham0cca9412013-03-08 13:22:42 -08002429 }
Jack Phamfadd6432012-12-07 19:03:41 -08002430
Jack Pham0cca9412013-03-08 13:22:42 -08002431 if (!mdwc->ext_inuse) { /* notify OTG */
2432 mdwc->ext_xceiv.id = mdwc->id_state;
2433 dwc3_resume_work(&mdwc->resume_work.work);
2434 }
2435}
2436
2437static irqreturn_t dwc3_pmic_id_irq(int irq, void *data)
2438{
2439 struct dwc3_msm *mdwc = data;
Jack Pham5c585062013-03-25 18:39:12 -07002440 enum dwc3_id_state id;
Jack Pham0cca9412013-03-08 13:22:42 -08002441
2442 /* If we can't read ID line state for some reason, treat it as float */
Jack Pham5c585062013-03-25 18:39:12 -07002443 id = !!irq_read_line(irq);
2444 if (mdwc->id_state != id) {
2445 mdwc->id_state = id;
2446 queue_work(system_nrt_wq, &mdwc->id_work);
2447 }
Jack Pham0cca9412013-03-08 13:22:42 -08002448
2449 return IRQ_HANDLED;
Jack Phamfadd6432012-12-07 19:03:41 -08002450}
2451
Jack Pham0fc12332012-11-19 13:14:22 -08002452static void dwc3_adc_notification(enum qpnp_tm_state state, void *ctx)
2453{
2454 struct dwc3_msm *mdwc = ctx;
2455
2456 if (state >= ADC_TM_STATE_NUM) {
2457 pr_err("%s: invalid notification %d\n", __func__, state);
2458 return;
2459 }
2460
2461 dev_dbg(mdwc->dev, "%s: state = %s\n", __func__,
2462 state == ADC_TM_HIGH_STATE ? "high" : "low");
2463
Jack Phamf12b7e12012-12-28 14:27:26 -08002464 /* save ID state, but don't necessarily notify OTG */
Jack Pham0fc12332012-11-19 13:14:22 -08002465 if (state == ADC_TM_HIGH_STATE) {
Jack Phamf12b7e12012-12-28 14:27:26 -08002466 mdwc->id_state = DWC3_ID_FLOAT;
Jack Pham0fc12332012-11-19 13:14:22 -08002467 mdwc->adc_param.state_request = ADC_TM_LOW_THR_ENABLE;
2468 } else {
Jack Phamf12b7e12012-12-28 14:27:26 -08002469 mdwc->id_state = DWC3_ID_GROUND;
Jack Pham0fc12332012-11-19 13:14:22 -08002470 mdwc->adc_param.state_request = ADC_TM_HIGH_THR_ENABLE;
2471 }
2472
Jack Pham0cca9412013-03-08 13:22:42 -08002473 dwc3_id_work(&mdwc->id_work);
2474
Jack Phamfadd6432012-12-07 19:03:41 -08002475 /* re-arm ADC interrupt */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002476 qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
Jack Pham0fc12332012-11-19 13:14:22 -08002477}
2478
2479static void dwc3_init_adc_work(struct work_struct *w)
2480{
2481 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
2482 init_adc_work.work);
2483 int ret;
2484
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002485 mdwc->adc_tm_dev = qpnp_get_adc_tm(mdwc->dev, "dwc_usb3-adc_tm");
2486 if (IS_ERR(mdwc->adc_tm_dev)) {
2487 if (PTR_ERR(mdwc->adc_tm_dev) == -EPROBE_DEFER)
2488 queue_delayed_work(system_nrt_wq, to_delayed_work(w),
Jack Pham90b4d122012-12-13 11:46:22 -08002489 msecs_to_jiffies(100));
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002490 else
2491 mdwc->adc_tm_dev = NULL;
2492
Jack Pham0fc12332012-11-19 13:14:22 -08002493 return;
2494 }
2495
2496 mdwc->adc_param.low_thr = adc_low_threshold;
2497 mdwc->adc_param.high_thr = adc_high_threshold;
2498 mdwc->adc_param.timer_interval = adc_meas_interval;
2499 mdwc->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08002500 mdwc->adc_param.btm_ctx = mdwc;
Jack Pham0fc12332012-11-19 13:14:22 -08002501 mdwc->adc_param.threshold_notification = dwc3_adc_notification;
2502
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002503 ret = qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
Jack Pham0fc12332012-11-19 13:14:22 -08002504 if (ret) {
2505 dev_err(mdwc->dev, "%s: request ADC error %d\n", __func__, ret);
2506 return;
2507 }
2508
2509 mdwc->id_adc_detect = true;
2510}
2511
2512static ssize_t adc_enable_show(struct device *dev,
2513 struct device_attribute *attr, char *buf)
2514{
Jack Pham84fc1ac2013-07-09 17:51:41 -07002515 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
2516
2517 if (!mdwc)
2518 return -EINVAL;
2519
2520 return snprintf(buf, PAGE_SIZE, "%s\n", mdwc->id_adc_detect ?
Jack Pham0fc12332012-11-19 13:14:22 -08002521 "enabled" : "disabled");
2522}
2523
2524static ssize_t adc_enable_store(struct device *dev,
2525 struct device_attribute *attr, const char
2526 *buf, size_t size)
2527{
Jack Pham84fc1ac2013-07-09 17:51:41 -07002528 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
2529
2530 if (!mdwc)
2531 return -EINVAL;
2532
Jack Pham0fc12332012-11-19 13:14:22 -08002533 if (!strnicmp(buf, "enable", 6)) {
Jack Pham84fc1ac2013-07-09 17:51:41 -07002534 if (!mdwc->id_adc_detect)
2535 dwc3_init_adc_work(&mdwc->init_adc_work.work);
Jack Pham0fc12332012-11-19 13:14:22 -08002536 return size;
2537 } else if (!strnicmp(buf, "disable", 7)) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002538 qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
Jack Pham84fc1ac2013-07-09 17:51:41 -07002539 mdwc->id_adc_detect = false;
Jack Pham0fc12332012-11-19 13:14:22 -08002540 return size;
2541 }
2542
2543 return -EINVAL;
2544}
2545
2546static DEVICE_ATTR(adc_enable, S_IRUGO | S_IWUSR, adc_enable_show,
2547 adc_enable_store);
2548
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302549static int dwc3_msm_ext_chg_open(struct inode *inode, struct file *file)
2550{
Jack Phamea382b72013-07-09 17:50:20 -07002551 struct dwc3_msm *mdwc =
2552 container_of(inode->i_cdev, struct dwc3_msm, ext_chg_cdev);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302553
2554 pr_debug("dwc3-msm ext chg open\n");
Jack Phamea382b72013-07-09 17:50:20 -07002555 file->private_data = mdwc;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302556 mdwc->ext_chg_opened = true;
Jack Phamea382b72013-07-09 17:50:20 -07002557
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302558 return 0;
2559}
2560
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302561static long
2562dwc3_msm_ext_chg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302563{
Jack Phamea382b72013-07-09 17:50:20 -07002564 struct dwc3_msm *mdwc = file->private_data;
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302565 struct msm_usb_chg_info info = {0};
2566 int ret = 0, val;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302567
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302568 switch (cmd) {
2569 case MSM_USB_EXT_CHG_INFO:
2570 info.chg_block_type = USB_CHG_BLOCK_QSCRATCH;
Jack Phamea382b72013-07-09 17:50:20 -07002571 info.page_offset = (mdwc->io_res->start +
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302572 QSCRATCH_REG_OFFSET) & ~PAGE_MASK;
2573 /*
2574 * The charger block register address space is only
2575 * 512 bytes. But mmap() works on PAGE granularity.
2576 */
2577 info.length = PAGE_SIZE;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302578
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302579 if (copy_to_user((void __user *)arg, &info, sizeof(info))) {
2580 pr_err("%s: copy to user failed\n\n", __func__);
2581 ret = -EFAULT;
2582 }
2583 break;
2584 case MSM_USB_EXT_CHG_BLOCK_LPM:
2585 if (get_user(val, (int __user *)arg)) {
2586 pr_err("%s: get_user failed\n\n", __func__);
2587 ret = -EFAULT;
2588 break;
2589 }
2590 pr_debug("%s: LPM block request %d\n", __func__, val);
2591 if (val) { /* block LPM */
2592 if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
2593 pm_runtime_get_sync(mdwc->dev);
2594 } else {
2595 mdwc->ext_chg_active = false;
2596 complete(&mdwc->ext_chg_wait);
2597 ret = -ENODEV;
2598 }
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302599 } else {
2600 mdwc->ext_chg_active = false;
2601 complete(&mdwc->ext_chg_wait);
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302602 pm_runtime_put(mdwc->dev);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302603 }
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302604 break;
2605 default:
2606 ret = -EINVAL;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302607 }
2608
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302609 return ret;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302610}
2611
2612static int dwc3_msm_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
2613{
Jack Phamea382b72013-07-09 17:50:20 -07002614 struct dwc3_msm *mdwc = file->private_data;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302615 unsigned long vsize = vma->vm_end - vma->vm_start;
2616 int ret;
2617
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302618 if (vma->vm_pgoff != 0 || vsize > PAGE_SIZE)
2619 return -EINVAL;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302620
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302621 vma->vm_pgoff = __phys_to_pfn(mdwc->io_res->start +
2622 QSCRATCH_REG_OFFSET);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302623 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
2624
2625 ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
2626 vsize, vma->vm_page_prot);
2627 if (ret < 0)
2628 pr_err("%s: failed with return val %d\n", __func__, ret);
2629
2630 return ret;
2631}
2632
2633static int dwc3_msm_ext_chg_release(struct inode *inode, struct file *file)
2634{
Jack Phamea382b72013-07-09 17:50:20 -07002635 struct dwc3_msm *mdwc = file->private_data;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302636
2637 pr_debug("dwc3-msm ext chg release\n");
2638
2639 mdwc->ext_chg_opened = false;
2640
2641 return 0;
2642}
2643
2644static const struct file_operations dwc3_msm_ext_chg_fops = {
2645 .owner = THIS_MODULE,
2646 .open = dwc3_msm_ext_chg_open,
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302647 .unlocked_ioctl = dwc3_msm_ext_chg_ioctl,
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302648 .mmap = dwc3_msm_ext_chg_mmap,
2649 .release = dwc3_msm_ext_chg_release,
2650};
2651
2652static int dwc3_msm_setup_cdev(struct dwc3_msm *mdwc)
2653{
2654 int ret;
2655
2656 ret = alloc_chrdev_region(&mdwc->ext_chg_dev, 0, 1, "usb_ext_chg");
2657 if (ret < 0) {
2658 pr_err("Fail to allocate usb ext char dev region\n");
2659 return ret;
2660 }
2661 mdwc->ext_chg_class = class_create(THIS_MODULE, "dwc_ext_chg");
2662 if (ret < 0) {
2663 pr_err("Fail to create usb ext chg class\n");
2664 goto unreg_chrdev;
2665 }
2666 cdev_init(&mdwc->ext_chg_cdev, &dwc3_msm_ext_chg_fops);
2667 mdwc->ext_chg_cdev.owner = THIS_MODULE;
2668
2669 ret = cdev_add(&mdwc->ext_chg_cdev, mdwc->ext_chg_dev, 1);
2670 if (ret < 0) {
2671 pr_err("Fail to add usb ext chg cdev\n");
2672 goto destroy_class;
2673 }
2674 mdwc->ext_chg_device = device_create(mdwc->ext_chg_class,
2675 NULL, mdwc->ext_chg_dev, NULL,
2676 "usb_ext_chg");
2677 if (IS_ERR(mdwc->ext_chg_device)) {
2678 pr_err("Fail to create usb ext chg device\n");
2679 ret = PTR_ERR(mdwc->ext_chg_device);
2680 mdwc->ext_chg_device = NULL;
2681 goto del_cdev;
2682 }
2683
2684 pr_debug("dwc3 msm ext chg cdev setup success\n");
2685 return 0;
2686
2687del_cdev:
2688 cdev_del(&mdwc->ext_chg_cdev);
2689destroy_class:
2690 class_destroy(mdwc->ext_chg_class);
2691unreg_chrdev:
2692 unregister_chrdev_region(mdwc->ext_chg_dev, 1);
2693
2694 return ret;
2695}
2696
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002697static int __devinit dwc3_msm_probe(struct platform_device *pdev)
2698{
2699 struct device_node *node = pdev->dev.of_node;
Jack Pham80162462013-07-10 11:59:01 -07002700 struct dwc3_msm *mdwc;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002701 struct resource *res;
Ido Shayevitz7ad8ded2012-08-28 04:30:58 +03002702 void __iomem *tcsr;
Manu Gautamf08f7b62013-04-02 16:09:42 +05302703 unsigned long flags;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002704 int ret = 0;
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302705 int len = 0;
2706 u32 tmp[3];
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002707
Jack Pham80162462013-07-10 11:59:01 -07002708 mdwc = devm_kzalloc(&pdev->dev, sizeof(*mdwc), GFP_KERNEL);
2709 if (!mdwc) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002710 dev_err(&pdev->dev, "not enough memory\n");
2711 return -ENOMEM;
2712 }
2713
Jack Pham80162462013-07-10 11:59:01 -07002714 platform_set_drvdata(pdev, mdwc);
2715 mdwc->dev = &pdev->dev;
Ido Shayevitz9fb83452012-04-01 17:45:58 +03002716
Jack Pham80162462013-07-10 11:59:01 -07002717 INIT_LIST_HEAD(&mdwc->req_complete_list);
2718 INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
2719 INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
2720 INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05302721 INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
Jack Pham80162462013-07-10 11:59:01 -07002722 INIT_WORK(&mdwc->id_work, dwc3_id_work);
2723 INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
2724 init_completion(&mdwc->ext_chg_wait);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002725
Jack Pham80162462013-07-10 11:59:01 -07002726 ret = dwc3_msm_config_gdsc(mdwc, 1);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07002727 if (ret) {
2728 dev_err(&pdev->dev, "unable to configure usb3 gdsc\n");
2729 return ret;
2730 }
2731
Jack Pham80162462013-07-10 11:59:01 -07002732 mdwc->xo_clk = clk_get(&pdev->dev, "xo");
2733 if (IS_ERR(mdwc->xo_clk)) {
Manu Gautam377821c2012-09-28 16:53:24 +05302734 dev_err(&pdev->dev, "%s unable to get TCXO buffer handle\n",
2735 __func__);
Jack Pham80162462013-07-10 11:59:01 -07002736 ret = PTR_ERR(mdwc->xo_clk);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07002737 goto disable_dwc3_gdsc;
Manu Gautam377821c2012-09-28 16:53:24 +05302738 }
2739
Jack Pham80162462013-07-10 11:59:01 -07002740 ret = clk_prepare_enable(mdwc->xo_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05302741 if (ret) {
2742 dev_err(&pdev->dev, "%s failed to vote for TCXO buffer%d\n",
2743 __func__, ret);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302744 goto put_xo;
Manu Gautam377821c2012-09-28 16:53:24 +05302745 }
2746
Manu Gautam1742db22012-06-19 13:33:24 +05302747 /*
2748 * DWC3 Core requires its CORE CLK (aka master / bus clk) to
2749 * run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
2750 */
Jack Pham80162462013-07-10 11:59:01 -07002751 mdwc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
2752 if (IS_ERR(mdwc->core_clk)) {
Manu Gautam1742db22012-06-19 13:33:24 +05302753 dev_err(&pdev->dev, "failed to get core_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002754 ret = PTR_ERR(mdwc->core_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302755 goto disable_xo;
Manu Gautam1742db22012-06-19 13:33:24 +05302756 }
Jack Pham80162462013-07-10 11:59:01 -07002757 clk_set_rate(mdwc->core_clk, 125000000);
2758 clk_prepare_enable(mdwc->core_clk);
Manu Gautam1742db22012-06-19 13:33:24 +05302759
Jack Pham80162462013-07-10 11:59:01 -07002760 mdwc->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
2761 if (IS_ERR(mdwc->iface_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002762 dev_err(&pdev->dev, "failed to get iface_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002763 ret = PTR_ERR(mdwc->iface_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002764 goto disable_core_clk;
2765 }
Jack Pham80162462013-07-10 11:59:01 -07002766 clk_prepare_enable(mdwc->iface_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002767
Jack Pham80162462013-07-10 11:59:01 -07002768 mdwc->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
2769 if (IS_ERR(mdwc->sleep_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002770 dev_err(&pdev->dev, "failed to get sleep_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002771 ret = PTR_ERR(mdwc->sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002772 goto disable_iface_clk;
2773 }
Jack Pham80162462013-07-10 11:59:01 -07002774 clk_prepare_enable(mdwc->sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002775
Jack Pham80162462013-07-10 11:59:01 -07002776 mdwc->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
2777 if (IS_ERR(mdwc->hsphy_sleep_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002778 dev_err(&pdev->dev, "failed to get sleep_a_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002779 ret = PTR_ERR(mdwc->hsphy_sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002780 goto disable_sleep_clk;
2781 }
Jack Pham80162462013-07-10 11:59:01 -07002782 clk_prepare_enable(mdwc->hsphy_sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002783
Jack Pham80162462013-07-10 11:59:01 -07002784 mdwc->utmi_clk = devm_clk_get(&pdev->dev, "utmi_clk");
2785 if (IS_ERR(mdwc->utmi_clk)) {
Jack Pham22698b82013-02-13 17:45:06 -08002786 dev_err(&pdev->dev, "failed to get utmi_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002787 ret = PTR_ERR(mdwc->utmi_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002788 goto disable_sleep_a_clk;
2789 }
Jack Pham80162462013-07-10 11:59:01 -07002790 clk_prepare_enable(mdwc->utmi_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002791
Jack Pham80162462013-07-10 11:59:01 -07002792 mdwc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
2793 if (IS_ERR(mdwc->ref_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002794 dev_err(&pdev->dev, "failed to get ref_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002795 ret = PTR_ERR(mdwc->ref_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002796 goto disable_utmi_clk;
Manu Gautam3e9ad352012-08-16 14:44:47 -07002797 }
Jack Pham80162462013-07-10 11:59:01 -07002798 clk_prepare_enable(mdwc->ref_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002799
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302800 of_get_property(node, "qcom,vdd-voltage-level", &len);
2801 if (len == sizeof(tmp)) {
2802 of_property_read_u32_array(node, "qcom,vdd-voltage-level",
2803 tmp, len/sizeof(*tmp));
Jack Pham80162462013-07-10 11:59:01 -07002804 mdwc->vdd_no_vol_level = tmp[0];
2805 mdwc->vdd_low_vol_level = tmp[1];
2806 mdwc->vdd_high_vol_level = tmp[2];
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302807 } else {
2808 dev_err(&pdev->dev, "no qcom,vdd-voltage-level property\n");
2809 ret = -EINVAL;
2810 goto disable_ref_clk;
2811 }
2812
Manu Gautam60e01352012-05-29 09:00:34 +05302813 /* SS PHY */
Jack Pham80162462013-07-10 11:59:01 -07002814 mdwc->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
2815 if (IS_ERR(mdwc->ssusb_vddcx)) {
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302816 dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
Jack Pham80162462013-07-10 11:59:01 -07002817 ret = PTR_ERR(mdwc->ssusb_vddcx);
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302818 goto disable_ref_clk;
Manu Gautam60e01352012-05-29 09:00:34 +05302819 }
2820
Jack Pham80162462013-07-10 11:59:01 -07002821 ret = dwc3_ssusb_config_vddcx(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302822 if (ret) {
2823 dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
Manu Gautam3e9ad352012-08-16 14:44:47 -07002824 goto disable_ref_clk;
Manu Gautam60e01352012-05-29 09:00:34 +05302825 }
2826
Jack Pham80162462013-07-10 11:59:01 -07002827 ret = regulator_enable(mdwc->ssusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05302828 if (ret) {
2829 dev_err(&pdev->dev, "unable to enable the ssusb vddcx\n");
2830 goto unconfig_ss_vddcx;
2831 }
2832
Jack Pham80162462013-07-10 11:59:01 -07002833 ret = dwc3_ssusb_ldo_init(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302834 if (ret) {
2835 dev_err(&pdev->dev, "ssusb vreg configuration failed\n");
2836 goto disable_ss_vddcx;
2837 }
2838
Jack Pham80162462013-07-10 11:59:01 -07002839 ret = dwc3_ssusb_ldo_enable(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302840 if (ret) {
2841 dev_err(&pdev->dev, "ssusb vreg enable failed\n");
2842 goto free_ss_ldo_init;
2843 }
2844
2845 /* HS PHY */
Jack Pham80162462013-07-10 11:59:01 -07002846 mdwc->hsusb_vddcx = devm_regulator_get(&pdev->dev, "hsusb_vdd_dig");
2847 if (IS_ERR(mdwc->hsusb_vddcx)) {
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302848 dev_err(&pdev->dev, "unable to get hsusb vddcx\n");
Jack Pham80162462013-07-10 11:59:01 -07002849 ret = PTR_ERR(mdwc->hsusb_vddcx);
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302850 goto disable_ss_ldo;
Manu Gautam60e01352012-05-29 09:00:34 +05302851 }
2852
Jack Pham80162462013-07-10 11:59:01 -07002853 ret = dwc3_hsusb_config_vddcx(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302854 if (ret) {
2855 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
2856 goto disable_ss_ldo;
2857 }
2858
Jack Pham80162462013-07-10 11:59:01 -07002859 ret = regulator_enable(mdwc->hsusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05302860 if (ret) {
2861 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
2862 goto unconfig_hs_vddcx;
2863 }
2864
Jack Pham80162462013-07-10 11:59:01 -07002865 ret = dwc3_hsusb_ldo_init(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302866 if (ret) {
2867 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
2868 goto disable_hs_vddcx;
2869 }
2870
Jack Pham80162462013-07-10 11:59:01 -07002871 ret = dwc3_hsusb_ldo_enable(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302872 if (ret) {
2873 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
2874 goto free_hs_ldo_init;
2875 }
2876
Jack Pham80162462013-07-10 11:59:01 -07002877 mdwc->id_state = mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
2878 mdwc->ext_xceiv.otg_capability = of_property_read_bool(node,
Manu Gautam6c0ff032012-11-02 14:55:35 +05302879 "qcom,otg-capability");
Jack Pham80162462013-07-10 11:59:01 -07002880 mdwc->charger.charging_disabled = of_property_read_bool(node,
Manu Gautam6c0ff032012-11-02 14:55:35 +05302881 "qcom,charging-disabled");
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302882
Jack Pham80162462013-07-10 11:59:01 -07002883 mdwc->charger.skip_chg_detect = of_property_read_bool(node,
Hemant Kumar6d7b7242013-04-18 16:44:38 -07002884 "qcom,skip-charger-detection");
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302885 /*
2886 * DWC3 has separate IRQ line for OTG events (ID/BSV) and for
2887 * DP and DM linestate transitions during low power mode.
2888 */
Jack Pham80162462013-07-10 11:59:01 -07002889 mdwc->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
2890 if (mdwc->hs_phy_irq < 0) {
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302891 dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
Jack Pham80162462013-07-10 11:59:01 -07002892 mdwc->hs_phy_irq = 0;
Jack Pham0fc12332012-11-19 13:14:22 -08002893 } else {
Jack Pham80162462013-07-10 11:59:01 -07002894 ret = devm_request_irq(&pdev->dev, mdwc->hs_phy_irq,
Jack Pham56a0a632013-03-08 13:18:42 -08002895 msm_dwc3_irq, IRQF_TRIGGER_RISING,
Jack Pham80162462013-07-10 11:59:01 -07002896 "msm_dwc3", mdwc);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302897 if (ret) {
2898 dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
2899 goto disable_hs_ldo;
2900 }
Jack Pham80162462013-07-10 11:59:01 -07002901 enable_irq_wake(mdwc->hs_phy_irq);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302902 }
Jack Pham0cca9412013-03-08 13:22:42 -08002903
Jack Pham80162462013-07-10 11:59:01 -07002904 if (mdwc->ext_xceiv.otg_capability) {
2905 mdwc->pmic_id_irq =
2906 platform_get_irq_byname(pdev, "pmic_id_irq");
2907 if (mdwc->pmic_id_irq > 0) {
David Keitelad4a0282013-03-19 18:04:27 -07002908 /* check if PMIC ID IRQ is supported */
2909 ret = qpnp_misc_irqs_available(&pdev->dev);
2910
2911 if (ret == -EPROBE_DEFER) {
2912 /* qpnp hasn't probed yet; defer dwc probe */
Jack Pham0cca9412013-03-08 13:22:42 -08002913 goto disable_hs_ldo;
David Keitelad4a0282013-03-19 18:04:27 -07002914 } else if (ret == 0) {
Jack Pham80162462013-07-10 11:59:01 -07002915 mdwc->pmic_id_irq = 0;
David Keitelad4a0282013-03-19 18:04:27 -07002916 } else {
2917 ret = devm_request_irq(&pdev->dev,
Jack Pham80162462013-07-10 11:59:01 -07002918 mdwc->pmic_id_irq,
David Keitelad4a0282013-03-19 18:04:27 -07002919 dwc3_pmic_id_irq,
2920 IRQF_TRIGGER_RISING |
2921 IRQF_TRIGGER_FALLING,
Jack Pham80162462013-07-10 11:59:01 -07002922 "dwc3_msm_pmic_id",
2923 mdwc);
David Keitelad4a0282013-03-19 18:04:27 -07002924 if (ret) {
2925 dev_err(&pdev->dev, "irqreq IDINT failed\n");
2926 goto disable_hs_ldo;
2927 }
Jack Pham9198d9f2013-04-09 17:54:54 -07002928
Manu Gautamf08f7b62013-04-02 16:09:42 +05302929 local_irq_save(flags);
2930 /* Update initial ID state */
Jack Pham80162462013-07-10 11:59:01 -07002931 mdwc->id_state =
2932 !!irq_read_line(mdwc->pmic_id_irq);
2933 if (mdwc->id_state == DWC3_ID_GROUND)
Jack Pham9198d9f2013-04-09 17:54:54 -07002934 queue_work(system_nrt_wq,
Jack Pham80162462013-07-10 11:59:01 -07002935 &mdwc->id_work);
Manu Gautamf08f7b62013-04-02 16:09:42 +05302936 local_irq_restore(flags);
Jack Pham80162462013-07-10 11:59:01 -07002937 enable_irq_wake(mdwc->pmic_id_irq);
Jack Pham0cca9412013-03-08 13:22:42 -08002938 }
David Keitelad4a0282013-03-19 18:04:27 -07002939 }
2940
Jack Pham80162462013-07-10 11:59:01 -07002941 if (mdwc->pmic_id_irq <= 0) {
Jack Pham0cca9412013-03-08 13:22:42 -08002942 /* If no PMIC ID IRQ, use ADC for ID pin detection */
Jack Pham80162462013-07-10 11:59:01 -07002943 queue_work(system_nrt_wq, &mdwc->init_adc_work.work);
Jack Pham0cca9412013-03-08 13:22:42 -08002944 device_create_file(&pdev->dev, &dev_attr_adc_enable);
Jack Pham80162462013-07-10 11:59:01 -07002945 mdwc->pmic_id_irq = 0;
Jack Pham0cca9412013-03-08 13:22:42 -08002946 }
Manu Gautam377821c2012-09-28 16:53:24 +05302947 }
2948
Ido Shayevitz7ad8ded2012-08-28 04:30:58 +03002949 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2950 if (!res) {
2951 dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
2952 } else {
2953 tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
2954 resource_size(res));
2955 if (!tcsr) {
2956 dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
2957 } else {
2958 /* Enable USB3 on the primary USB port. */
2959 writel_relaxed(0x1, tcsr);
2960 /*
2961 * Ensure that TCSR write is completed before
2962 * USB registers initialization.
2963 */
2964 mb();
2965 }
2966 }
2967
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002968 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2969 if (!res) {
2970 dev_err(&pdev->dev, "missing memory base resource\n");
Manu Gautam60e01352012-05-29 09:00:34 +05302971 ret = -ENODEV;
Jack Pham56a0a632013-03-08 13:18:42 -08002972 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002973 }
2974
Jack Pham80162462013-07-10 11:59:01 -07002975 mdwc->base = devm_ioremap_nocache(&pdev->dev, res->start,
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002976 resource_size(res));
Jack Pham80162462013-07-10 11:59:01 -07002977 if (!mdwc->base) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002978 dev_err(&pdev->dev, "ioremap failed\n");
Manu Gautam60e01352012-05-29 09:00:34 +05302979 ret = -ENODEV;
Jack Pham56a0a632013-03-08 13:18:42 -08002980 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002981 }
2982
Jack Pham80162462013-07-10 11:59:01 -07002983 mdwc->io_res = res; /* used to calculate chg block offset */
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002984
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +05302985 if (of_property_read_u32(node, "qcom,dwc-hsphy-init",
Jack Pham80162462013-07-10 11:59:01 -07002986 &mdwc->hsphy_init_seq))
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +05302987 dev_dbg(&pdev->dev, "unable to read hsphy init seq\n");
Jack Pham80162462013-07-10 11:59:01 -07002988 else if (!mdwc->hsphy_init_seq)
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +05302989 dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
2990
Vijayavardhan Vennapusa9f74b1b2013-09-23 19:22:17 +05302991 if (of_property_read_u32(node, "qcom,dwc-ssphy-deemphasis-value",
2992 &mdwc->deemphasis_val))
2993 dev_dbg(&pdev->dev, "unable to read ssphy deemphasis value\n");
2994
Jack Pham80162462013-07-10 11:59:01 -07002995 pm_runtime_set_active(mdwc->dev);
2996 pm_runtime_enable(mdwc->dev);
Manu Gautamb5067272012-07-02 09:53:41 +05302997
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002998 if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
Jack Pham80162462013-07-10 11:59:01 -07002999 &mdwc->dbm_num_eps)) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003000 dev_err(&pdev->dev,
3001 "unable to read platform data num of dbm eps\n");
Jack Pham80162462013-07-10 11:59:01 -07003002 mdwc->dbm_num_eps = DBM_MAX_EPS;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003003 }
3004
Jack Pham80162462013-07-10 11:59:01 -07003005 if (mdwc->dbm_num_eps > DBM_MAX_EPS) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003006 dev_err(&pdev->dev,
3007 "Driver doesn't support number of DBM EPs. "
3008 "max: %d, dbm_num_eps: %d\n",
Jack Pham80162462013-07-10 11:59:01 -07003009 DBM_MAX_EPS, mdwc->dbm_num_eps);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003010 ret = -ENODEV;
Vijayavardhan Vennapusa8eb68732013-03-26 13:05:38 +05303011 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003012 }
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05303013
3014 if (of_property_read_u32(node, "qcom,dwc-usb3-msm-tx-fifo-size",
3015 &mdwc->tx_fifo_size))
3016 dev_err(&pdev->dev,
3017 "unable to read platform data tx fifo size\n");
3018
3019 if (of_property_read_u32(node, "qcom,dwc-usb3-msm-qdss-tx-fifo-size",
3020 &mdwc->qdss_tx_fifo_size))
3021 dev_err(&pdev->dev,
3022 "unable to read platform data qdss tx fifo size\n");
3023
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05303024 dwc3_set_notifier(&dwc3_msm_notify_event);
Manu Gautambb825d72013-03-12 16:25:42 +05303025 /* usb_psy required only for vbus_notifications or charging support */
Jack Pham80162462013-07-10 11:59:01 -07003026 if (mdwc->ext_xceiv.otg_capability ||
3027 !mdwc->charger.charging_disabled) {
3028 mdwc->usb_psy.name = "usb";
3029 mdwc->usb_psy.type = POWER_SUPPLY_TYPE_USB;
3030 mdwc->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
3031 mdwc->usb_psy.num_supplicants = ARRAY_SIZE(
Manu Gautambb825d72013-03-12 16:25:42 +05303032 dwc3_msm_pm_power_supplied_to);
Jack Pham80162462013-07-10 11:59:01 -07003033 mdwc->usb_psy.properties = dwc3_msm_pm_power_props_usb;
3034 mdwc->usb_psy.num_properties =
Manu Gautambb825d72013-03-12 16:25:42 +05303035 ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
Jack Pham80162462013-07-10 11:59:01 -07003036 mdwc->usb_psy.get_property = dwc3_msm_power_get_property_usb;
3037 mdwc->usb_psy.set_property = dwc3_msm_power_set_property_usb;
3038 mdwc->usb_psy.external_power_changed =
Manu Gautambb825d72013-03-12 16:25:42 +05303039 dwc3_msm_external_power_changed;
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05303040 mdwc->usb_psy.property_is_writeable =
3041 dwc3_msm_property_is_writeable;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303042
Jack Pham80162462013-07-10 11:59:01 -07003043 ret = power_supply_register(&pdev->dev, &mdwc->usb_psy);
Manu Gautambb825d72013-03-12 16:25:42 +05303044 if (ret < 0) {
3045 dev_err(&pdev->dev,
3046 "%s:power_supply_register usb failed\n",
3047 __func__);
3048 goto disable_hs_ldo;
3049 }
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303050 }
3051
Vijayavardhan Vennapusa8eb68732013-03-26 13:05:38 +05303052 if (node) {
3053 ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
3054 if (ret) {
3055 dev_err(&pdev->dev,
3056 "failed to add create dwc3 core\n");
3057 goto put_psupply;
3058 }
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003059 }
3060
Jack Pham80162462013-07-10 11:59:01 -07003061 mdwc->bus_scale_table = msm_bus_cl_get_pdata(pdev);
3062 if (!mdwc->bus_scale_table) {
Manu Gautam2617deb2012-08-31 17:50:06 -07003063 dev_err(&pdev->dev, "bus scaling is disabled\n");
3064 } else {
Jack Pham80162462013-07-10 11:59:01 -07003065 mdwc->bus_perf_client =
3066 msm_bus_scale_register_client(mdwc->bus_scale_table);
Manu Gautam2617deb2012-08-31 17:50:06 -07003067 ret = msm_bus_scale_client_update_request(
Jack Pham80162462013-07-10 11:59:01 -07003068 mdwc->bus_perf_client, 1);
Manu Gautam2617deb2012-08-31 17:50:06 -07003069 if (ret)
3070 dev_err(&pdev->dev, "Failed to vote for bus scaling\n");
3071 }
3072
Jack Pham80162462013-07-10 11:59:01 -07003073 mdwc->otg_xceiv = usb_get_transceiver();
Manu Gautambb825d72013-03-12 16:25:42 +05303074 /* Register with OTG if present, ignore USB2 OTG using other PHY */
Jack Pham80162462013-07-10 11:59:01 -07003075 if (mdwc->otg_xceiv &&
3076 !(mdwc->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
Hemant Kumar6d7b7242013-04-18 16:44:38 -07003077 /* Skip charger detection for simulator targets */
Jack Pham80162462013-07-10 11:59:01 -07003078 if (!mdwc->charger.skip_chg_detect) {
3079 mdwc->charger.start_detection = dwc3_start_chg_det;
3080 ret = dwc3_set_charger(mdwc->otg_xceiv->otg,
3081 &mdwc->charger);
3082 if (ret || !mdwc->charger.notify_detection_complete) {
Hemant Kumar6d7b7242013-04-18 16:44:38 -07003083 dev_err(&pdev->dev,
3084 "failed to register charger: %d\n",
3085 ret);
3086 goto put_xcvr;
3087 }
Manu Gautam8c642812012-06-07 10:35:10 +05303088 }
Manu Gautamb5067272012-07-02 09:53:41 +05303089
Jack Pham80162462013-07-10 11:59:01 -07003090 if (mdwc->ext_xceiv.otg_capability)
3091 mdwc->ext_xceiv.ext_block_reset = dwc3_msm_block_reset;
3092 ret = dwc3_set_ext_xceiv(mdwc->otg_xceiv->otg,
3093 &mdwc->ext_xceiv);
3094 if (ret || !mdwc->ext_xceiv.notify_ext_events) {
Manu Gautamb5067272012-07-02 09:53:41 +05303095 dev_err(&pdev->dev, "failed to register xceiver: %d\n",
3096 ret);
3097 goto put_xcvr;
3098 }
Manu Gautam8c642812012-06-07 10:35:10 +05303099 } else {
Manu Gautambb825d72013-03-12 16:25:42 +05303100 dev_dbg(&pdev->dev, "No OTG, DWC3 running in host only mode\n");
Jack Pham80162462013-07-10 11:59:01 -07003101 mdwc->host_mode = 1;
3102 mdwc->vbus_otg = devm_regulator_get(&pdev->dev, "vbus_dwc3");
3103 if (IS_ERR(mdwc->vbus_otg)) {
Manu Gautambb825d72013-03-12 16:25:42 +05303104 dev_dbg(&pdev->dev, "Failed to get vbus regulator\n");
Jack Pham80162462013-07-10 11:59:01 -07003105 mdwc->vbus_otg = 0;
Manu Gautambb825d72013-03-12 16:25:42 +05303106 } else {
Jack Pham80162462013-07-10 11:59:01 -07003107 ret = regulator_enable(mdwc->vbus_otg);
Manu Gautambb825d72013-03-12 16:25:42 +05303108 if (ret) {
Jack Pham80162462013-07-10 11:59:01 -07003109 mdwc->vbus_otg = 0;
Manu Gautambb825d72013-03-12 16:25:42 +05303110 dev_err(&pdev->dev, "Failed to enable vbus_otg\n");
3111 }
3112 }
Jack Pham80162462013-07-10 11:59:01 -07003113 mdwc->otg_xceiv = NULL;
Manu Gautam8c642812012-06-07 10:35:10 +05303114 }
Jack Pham80162462013-07-10 11:59:01 -07003115 if (mdwc->ext_xceiv.otg_capability && mdwc->charger.start_detection) {
3116 ret = dwc3_msm_setup_cdev(mdwc);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303117 if (ret)
3118 dev_err(&pdev->dev, "Fail to setup dwc3 setup cdev\n");
3119 }
Manu Gautam8c642812012-06-07 10:35:10 +05303120
Jack Pham80162462013-07-10 11:59:01 -07003121 device_init_wakeup(mdwc->dev, 1);
3122 pm_stay_awake(mdwc->dev);
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05303123 dwc3_msm_debugfs_init(mdwc);
Manu Gautamb5067272012-07-02 09:53:41 +05303124
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003125 return 0;
3126
Manu Gautam8c642812012-06-07 10:35:10 +05303127put_xcvr:
Jack Pham80162462013-07-10 11:59:01 -07003128 usb_put_transceiver(mdwc->otg_xceiv);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303129put_psupply:
Jack Pham80162462013-07-10 11:59:01 -07003130 if (mdwc->usb_psy.dev)
3131 power_supply_unregister(&mdwc->usb_psy);
Manu Gautam60e01352012-05-29 09:00:34 +05303132disable_hs_ldo:
Jack Pham80162462013-07-10 11:59:01 -07003133 dwc3_hsusb_ldo_enable(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303134free_hs_ldo_init:
Jack Pham80162462013-07-10 11:59:01 -07003135 dwc3_hsusb_ldo_init(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303136disable_hs_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003137 regulator_disable(mdwc->hsusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05303138unconfig_hs_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003139 dwc3_hsusb_config_vddcx(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303140disable_ss_ldo:
Jack Pham80162462013-07-10 11:59:01 -07003141 dwc3_ssusb_ldo_enable(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303142free_ss_ldo_init:
Jack Pham80162462013-07-10 11:59:01 -07003143 dwc3_ssusb_ldo_init(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303144disable_ss_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003145 regulator_disable(mdwc->ssusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05303146unconfig_ss_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003147 dwc3_ssusb_config_vddcx(mdwc, 0);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003148disable_ref_clk:
Jack Pham80162462013-07-10 11:59:01 -07003149 clk_disable_unprepare(mdwc->ref_clk);
Jack Pham22698b82013-02-13 17:45:06 -08003150disable_utmi_clk:
Jack Pham80162462013-07-10 11:59:01 -07003151 clk_disable_unprepare(mdwc->utmi_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003152disable_sleep_a_clk:
Jack Pham80162462013-07-10 11:59:01 -07003153 clk_disable_unprepare(mdwc->hsphy_sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003154disable_sleep_clk:
Jack Pham80162462013-07-10 11:59:01 -07003155 clk_disable_unprepare(mdwc->sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003156disable_iface_clk:
Jack Pham80162462013-07-10 11:59:01 -07003157 clk_disable_unprepare(mdwc->iface_clk);
Manu Gautam1742db22012-06-19 13:33:24 +05303158disable_core_clk:
Jack Pham80162462013-07-10 11:59:01 -07003159 clk_disable_unprepare(mdwc->core_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05303160disable_xo:
Jack Pham80162462013-07-10 11:59:01 -07003161 clk_disable_unprepare(mdwc->xo_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05303162put_xo:
Jack Pham80162462013-07-10 11:59:01 -07003163 clk_put(mdwc->xo_clk);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07003164disable_dwc3_gdsc:
Jack Pham80162462013-07-10 11:59:01 -07003165 dwc3_msm_config_gdsc(mdwc, 0);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003166
3167 return ret;
3168}
3169
3170static int __devexit dwc3_msm_remove(struct platform_device *pdev)
3171{
Jack Pham80162462013-07-10 11:59:01 -07003172 struct dwc3_msm *mdwc = platform_get_drvdata(pdev);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003173
Jack Pham80162462013-07-10 11:59:01 -07003174 if (!mdwc->ext_chg_device) {
3175 device_destroy(mdwc->ext_chg_class, mdwc->ext_chg_dev);
3176 cdev_del(&mdwc->ext_chg_cdev);
3177 class_destroy(mdwc->ext_chg_class);
3178 unregister_chrdev_region(mdwc->ext_chg_dev, 1);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303179 }
3180
Jack Pham80162462013-07-10 11:59:01 -07003181 if (mdwc->id_adc_detect)
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07003182 qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
Manu Gautamb5067272012-07-02 09:53:41 +05303183 if (dwc3_debugfs_root)
3184 debugfs_remove_recursive(dwc3_debugfs_root);
Jack Pham80162462013-07-10 11:59:01 -07003185 if (mdwc->otg_xceiv) {
3186 dwc3_start_chg_det(&mdwc->charger, false);
3187 usb_put_transceiver(mdwc->otg_xceiv);
Manu Gautam8c642812012-06-07 10:35:10 +05303188 }
Jack Pham80162462013-07-10 11:59:01 -07003189 if (mdwc->usb_psy.dev)
3190 power_supply_unregister(&mdwc->usb_psy);
3191 if (mdwc->vbus_otg)
3192 regulator_disable(mdwc->vbus_otg);
Jack Pham0fc12332012-11-19 13:14:22 -08003193
Jack Pham80162462013-07-10 11:59:01 -07003194 pm_runtime_disable(mdwc->dev);
3195 device_init_wakeup(mdwc->dev, 0);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003196
Jack Pham80162462013-07-10 11:59:01 -07003197 dwc3_hsusb_ldo_enable(mdwc, 0);
3198 dwc3_hsusb_ldo_init(mdwc, 0);
3199 regulator_disable(mdwc->hsusb_vddcx);
3200 dwc3_hsusb_config_vddcx(mdwc, 0);
3201 dwc3_ssusb_ldo_enable(mdwc, 0);
3202 dwc3_ssusb_ldo_init(mdwc, 0);
3203 regulator_disable(mdwc->ssusb_vddcx);
3204 dwc3_ssusb_config_vddcx(mdwc, 0);
3205 clk_disable_unprepare(mdwc->core_clk);
3206 clk_disable_unprepare(mdwc->iface_clk);
3207 clk_disable_unprepare(mdwc->sleep_clk);
3208 clk_disable_unprepare(mdwc->hsphy_sleep_clk);
3209 clk_disable_unprepare(mdwc->ref_clk);
3210 clk_disable_unprepare(mdwc->xo_clk);
3211 clk_put(mdwc->xo_clk);
Manu Gautam60e01352012-05-29 09:00:34 +05303212
Jack Pham80162462013-07-10 11:59:01 -07003213 dwc3_msm_config_gdsc(mdwc, 0);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07003214
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003215 return 0;
3216}
3217
Manu Gautamb5067272012-07-02 09:53:41 +05303218static int dwc3_msm_pm_suspend(struct device *dev)
3219{
3220 int ret = 0;
3221 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3222
3223 dev_dbg(dev, "dwc3-msm PM suspend\n");
3224
Manu Gautam8d98a572013-01-21 16:34:50 +05303225 flush_delayed_work_sync(&mdwc->resume_work);
3226 if (!atomic_read(&mdwc->in_lpm)) {
3227 dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n");
3228 return -EBUSY;
3229 }
3230
Manu Gautamb5067272012-07-02 09:53:41 +05303231 ret = dwc3_msm_suspend(mdwc);
3232 if (!ret)
3233 atomic_set(&mdwc->pm_suspended, 1);
3234
3235 return ret;
3236}
3237
3238static int dwc3_msm_pm_resume(struct device *dev)
3239{
3240 int ret = 0;
3241 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3242
3243 dev_dbg(dev, "dwc3-msm PM resume\n");
3244
3245 atomic_set(&mdwc->pm_suspended, 0);
3246 if (mdwc->resume_pending) {
3247 mdwc->resume_pending = false;
3248
3249 ret = dwc3_msm_resume(mdwc);
3250 /* Update runtime PM status */
3251 pm_runtime_disable(dev);
3252 pm_runtime_set_active(dev);
3253 pm_runtime_enable(dev);
3254
3255 /* Let OTG know about resume event and update pm_count */
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303256 if (mdwc->otg_xceiv) {
Manu Gautamb5067272012-07-02 09:53:41 +05303257 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
3258 DWC3_EVENT_PHY_RESUME);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303259 if (mdwc->ext_xceiv.otg_capability)
3260 mdwc->ext_xceiv.notify_ext_events(
3261 mdwc->otg_xceiv->otg,
3262 DWC3_EVENT_XCEIV_STATE);
3263 }
Manu Gautamb5067272012-07-02 09:53:41 +05303264 }
3265
3266 return ret;
3267}
3268
3269static int dwc3_msm_runtime_idle(struct device *dev)
3270{
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303271 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3272
Manu Gautamb5067272012-07-02 09:53:41 +05303273 dev_dbg(dev, "DWC3-msm runtime idle\n");
3274
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303275 if (mdwc->ext_chg_active) {
3276 dev_dbg(dev, "Deferring LPM\n");
3277 /*
3278 * Charger detection may happen in user space.
3279 * Delay entering LPM by 3 sec. Otherwise we
3280 * have to exit LPM when user space begins
3281 * charger detection.
3282 *
3283 * This timer will be canceled when user space
3284 * votes against LPM by incrementing PM usage
3285 * counter. We enter low power mode when
3286 * PM usage counter is decremented.
3287 */
3288 pm_schedule_suspend(dev, 3000);
3289 return -EAGAIN;
3290 }
3291
Manu Gautamb5067272012-07-02 09:53:41 +05303292 return 0;
3293}
3294
3295static int dwc3_msm_runtime_suspend(struct device *dev)
3296{
3297 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3298
3299 dev_dbg(dev, "DWC3-msm runtime suspend\n");
3300
3301 return dwc3_msm_suspend(mdwc);
3302}
3303
3304static int dwc3_msm_runtime_resume(struct device *dev)
3305{
3306 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3307
3308 dev_dbg(dev, "DWC3-msm runtime resume\n");
3309
3310 return dwc3_msm_resume(mdwc);
3311}
3312
3313static const struct dev_pm_ops dwc3_msm_dev_pm_ops = {
3314 SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume)
3315 SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume,
3316 dwc3_msm_runtime_idle)
3317};
3318
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003319static const struct of_device_id of_dwc3_matach[] = {
3320 {
3321 .compatible = "qcom,dwc-usb3-msm",
3322 },
3323 { },
3324};
3325MODULE_DEVICE_TABLE(of, of_dwc3_matach);
3326
3327static struct platform_driver dwc3_msm_driver = {
3328 .probe = dwc3_msm_probe,
3329 .remove = __devexit_p(dwc3_msm_remove),
3330 .driver = {
3331 .name = "msm-dwc3",
Manu Gautamb5067272012-07-02 09:53:41 +05303332 .pm = &dwc3_msm_dev_pm_ops,
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003333 .of_match_table = of_dwc3_matach,
3334 },
3335};
3336
Manu Gautam377821c2012-09-28 16:53:24 +05303337MODULE_LICENSE("GPL v2");
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003338MODULE_DESCRIPTION("DesignWare USB3 MSM Glue Layer");
3339
3340static int __devinit dwc3_msm_init(void)
3341{
3342 return platform_driver_register(&dwc3_msm_driver);
3343}
3344module_init(dwc3_msm_init);
3345
3346static void __exit dwc3_msm_exit(void)
3347{
3348 platform_driver_unregister(&dwc3_msm_driver);
3349}
3350module_exit(dwc3_msm_exit);